dhcp-4.2.4/000777 000765 000024 00000000000 11757514244 012405 5ustar00sarstaff000000 000000 dhcp-4.2.4/aclocal.m4000644 000765 000024 00000100723 11757500112 014231 0ustar00sarstaff000000 000000 # generated automatically by aclocal 1.10.1 -*- Autoconf -*- # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, # 2005, 2006, 2007, 2008 Free Software Foundation, Inc. # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl m4_if(AC_AUTOCONF_VERSION, [2.67],, [m4_warning([this file was generated for autoconf 2.67. You have another version of autoconf. It may work, but is not guaranteed to. If you have problems, you may need to regenerate the build system entirely. To do so, use the procedure documented by the package, typically `autoreconf'.])]) # Copyright (C) 2002, 2003, 2005, 2006, 2007 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_AUTOMAKE_VERSION(VERSION) # ---------------------------- # Automake X.Y traces this macro to ensure aclocal.m4 has been # generated from the m4 files accompanying Automake X.Y. # (This private macro should not be called outside this file.) AC_DEFUN([AM_AUTOMAKE_VERSION], [am__api_version='1.10' dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to dnl require some minimum version. Point them to the right macro. m4_if([$1], [1.10.1], [], [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl ]) # _AM_AUTOCONF_VERSION(VERSION) # ----------------------------- # aclocal traces this macro to find the Autoconf version. # This is a private macro too. Using m4_define simplifies # the logic in aclocal, which can simply ignore this definition. m4_define([_AM_AUTOCONF_VERSION], []) # AM_SET_CURRENT_AUTOMAKE_VERSION # ------------------------------- # Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. # This function is AC_REQUIREd by AC_INIT_AUTOMAKE. AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], [AM_AUTOMAKE_VERSION([1.10.1])dnl m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl _AM_AUTOCONF_VERSION(AC_AUTOCONF_VERSION)]) # AM_AUX_DIR_EXPAND -*- Autoconf -*- # Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets # $ac_aux_dir to `$srcdir/foo'. In other projects, it is set to # `$srcdir', `$srcdir/..', or `$srcdir/../..'. # # Of course, Automake must honor this variable whenever it calls a # tool from the auxiliary directory. The problem is that $srcdir (and # therefore $ac_aux_dir as well) can be either absolute or relative, # depending on how configure is run. This is pretty annoying, since # it makes $ac_aux_dir quite unusable in subdirectories: in the top # source directory, any form will work fine, but in subdirectories a # relative path needs to be adjusted first. # # $ac_aux_dir/missing # fails when called from a subdirectory if $ac_aux_dir is relative # $top_srcdir/$ac_aux_dir/missing # fails if $ac_aux_dir is absolute, # fails when called from a subdirectory in a VPATH build with # a relative $ac_aux_dir # # The reason of the latter failure is that $top_srcdir and $ac_aux_dir # are both prefixed by $srcdir. In an in-source build this is usually # harmless because $srcdir is `.', but things will broke when you # start a VPATH build or use an absolute $srcdir. # # So we could use something similar to $top_srcdir/$ac_aux_dir/missing, # iff we strip the leading $srcdir from $ac_aux_dir. That would be: # am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` # and then we would define $MISSING as # MISSING="\${SHELL} $am_aux_dir/missing" # This will work as long as MISSING is not called from configure, because # unfortunately $(top_srcdir) has no meaning in configure. # However there are other variables, like CC, which are often used in # configure, and could therefore not use this "fixed" $ac_aux_dir. # # Another solution, used here, is to always expand $ac_aux_dir to an # absolute PATH. The drawback is that using absolute paths prevent a # configured tree to be moved without reconfiguration. AC_DEFUN([AM_AUX_DIR_EXPAND], [dnl Rely on autoconf to set up CDPATH properly. AC_PREREQ([2.50])dnl # expand $ac_aux_dir to an absolute path am_aux_dir=`cd $ac_aux_dir && pwd` ]) # AM_CONDITIONAL -*- Autoconf -*- # Copyright (C) 1997, 2000, 2001, 2003, 2004, 2005, 2006 # Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 8 # AM_CONDITIONAL(NAME, SHELL-CONDITION) # ------------------------------------- # Define a conditional. AC_DEFUN([AM_CONDITIONAL], [AC_PREREQ(2.52)dnl ifelse([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl AC_SUBST([$1_TRUE])dnl AC_SUBST([$1_FALSE])dnl _AM_SUBST_NOTMAKE([$1_TRUE])dnl _AM_SUBST_NOTMAKE([$1_FALSE])dnl if $2; then $1_TRUE= $1_FALSE='#' else $1_TRUE='#' $1_FALSE= fi AC_CONFIG_COMMANDS_PRE( [if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then AC_MSG_ERROR([[conditional "$1" was never defined. Usually this means the macro was only invoked conditionally.]]) fi])]) # Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 # Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 9 # There are a few dirty hacks below to avoid letting `AC_PROG_CC' be # written in clear, in which case automake, when reading aclocal.m4, # will think it sees a *use*, and therefore will trigger all it's # C support machinery. Also note that it means that autoscan, seeing # CC etc. in the Makefile, will ask for an AC_PROG_CC use... # _AM_DEPENDENCIES(NAME) # ---------------------- # See how the compiler implements dependency checking. # NAME is "CC", "CXX", "GCJ", or "OBJC". # We try a few techniques and use that to set a single cache variable. # # We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was # modified to invoke _AM_DEPENDENCIES(CC); we would have a circular # dependency, and given that the user is not expected to run this macro, # just rely on AC_PROG_CC. AC_DEFUN([_AM_DEPENDENCIES], [AC_REQUIRE([AM_SET_DEPDIR])dnl AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl AC_REQUIRE([AM_MAKE_INCLUDE])dnl AC_REQUIRE([AM_DEP_TRACK])dnl ifelse([$1], CC, [depcc="$CC" am_compiler_list=], [$1], CXX, [depcc="$CXX" am_compiler_list=], [$1], OBJC, [depcc="$OBJC" am_compiler_list='gcc3 gcc'], [$1], UPC, [depcc="$UPC" am_compiler_list=], [$1], GCJ, [depcc="$GCJ" am_compiler_list='gcc3 gcc'], [depcc="$$1" am_compiler_list=]) AC_CACHE_CHECK([dependency style of $depcc], [am_cv_$1_dependencies_compiler_type], [if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named `D' -- because `-MD' means `put the output # in D'. mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_$1_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` fi for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with # Solaris 8's {/usr,}/bin/sh. touch sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf case $depmode in nosideeffect) # after this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; none) break ;; esac # We check with `-c' and `-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle `-M -o', and we need to detect this. if depmode=$depmode \ source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_$1_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_$1_dependencies_compiler_type=none fi ]) AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) AM_CONDITIONAL([am__fastdep$1], [ test "x$enable_dependency_tracking" != xno \ && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) ]) # AM_SET_DEPDIR # ------------- # Choose a directory name for dependency files. # This macro is AC_REQUIREd in _AM_DEPENDENCIES AC_DEFUN([AM_SET_DEPDIR], [AC_REQUIRE([AM_SET_LEADING_DOT])dnl AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl ]) # AM_DEP_TRACK # ------------ AC_DEFUN([AM_DEP_TRACK], [AC_ARG_ENABLE(dependency-tracking, [ --disable-dependency-tracking speeds up one-time build --enable-dependency-tracking do not reject slow dependency extractors]) if test "x$enable_dependency_tracking" != xno; then am_depcomp="$ac_aux_dir/depcomp" AMDEPBACKSLASH='\' fi AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) AC_SUBST([AMDEPBACKSLASH])dnl _AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl ]) # Generate code to set up dependency tracking. -*- Autoconf -*- # Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005 # Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. #serial 3 # _AM_OUTPUT_DEPENDENCY_COMMANDS # ------------------------------ AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], [for mf in $CONFIG_FILES; do # Strip MF so we end up with the name of the file. mf=`echo "$mf" | sed -e 's/:.*$//'` # Check whether this is an Automake generated Makefile or not. # We used to match only the files named `Makefile.in', but # some people rename them; so instead we look at the file content. # Grep'ing the first line is not enough: some people post-process # each Makefile.in and add a new line on top of each file to say so. # Grep'ing the whole file is not good either: AIX grep has a line # limit of 2048, but all sed's we know have understand at least 4000. if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then dirpart=`AS_DIRNAME("$mf")` else continue fi # Extract the definition of DEPDIR, am__include, and am__quote # from the Makefile without running `make'. DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` test -z "$DEPDIR" && continue am__include=`sed -n 's/^am__include = //p' < "$mf"` test -z "am__include" && continue am__quote=`sed -n 's/^am__quote = //p' < "$mf"` # When using ansi2knr, U may be empty or an underscore; expand it U=`sed -n 's/^U = //p' < "$mf"` # Find all dependency output files, they are included files with # $(DEPDIR) in their names. We invoke sed twice because it is the # simplest approach to changing $(DEPDIR) to its actual value in the # expansion. for file in `sed -n " s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do # Make sure the directory exists. test -f "$dirpart/$file" && continue fdir=`AS_DIRNAME(["$file"])` AS_MKDIR_P([$dirpart/$fdir]) # echo "creating $dirpart/$file" echo '# dummy' > "$dirpart/$file" done done ])# _AM_OUTPUT_DEPENDENCY_COMMANDS # AM_OUTPUT_DEPENDENCY_COMMANDS # ----------------------------- # This macro should only be invoked once -- use via AC_REQUIRE. # # This code is only required when automatic dependency tracking # is enabled. FIXME. This creates each `.P' file that we will # need in order to bootstrap the dependency handling code. AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], [AC_CONFIG_COMMANDS([depfiles], [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"]) ]) # Do all the work for Automake. -*- Autoconf -*- # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, # 2005, 2006, 2008 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 13 # This macro actually does too much. Some checks are only needed if # your package does certain things. But this isn't really a big deal. # AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) # AM_INIT_AUTOMAKE([OPTIONS]) # ----------------------------------------------- # The call with PACKAGE and VERSION arguments is the old style # call (pre autoconf-2.50), which is being phased out. PACKAGE # and VERSION should now be passed to AC_INIT and removed from # the call to AM_INIT_AUTOMAKE. # We support both call styles for the transition. After # the next Automake release, Autoconf can make the AC_INIT # arguments mandatory, and then we can depend on a new Autoconf # release and drop the old call support. AC_DEFUN([AM_INIT_AUTOMAKE], [AC_PREREQ([2.60])dnl dnl Autoconf wants to disallow AM_ names. We explicitly allow dnl the ones we care about. m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl AC_REQUIRE([AC_PROG_INSTALL])dnl if test "`cd $srcdir && pwd`" != "`pwd`"; then # Use -I$(srcdir) only when $(srcdir) != ., so that make's output # is not polluted with repeated "-I." AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl # test to see if srcdir already configured if test -f $srcdir/config.status; then AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) fi fi # test whether we have cygpath if test -z "$CYGPATH_W"; then if (cygpath --version) >/dev/null 2>/dev/null; then CYGPATH_W='cygpath -w' else CYGPATH_W=echo fi fi AC_SUBST([CYGPATH_W]) # Define the identity of the package. dnl Distinguish between old-style and new-style calls. m4_ifval([$2], [m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl AC_SUBST([PACKAGE], [$1])dnl AC_SUBST([VERSION], [$2])], [_AM_SET_OPTIONS([$1])dnl dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT. m4_if(m4_ifdef([AC_PACKAGE_NAME], 1)m4_ifdef([AC_PACKAGE_VERSION], 1), 11,, [m4_fatal([AC_INIT should be called with package and version arguments])])dnl AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl _AM_IF_OPTION([no-define],, [AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package]) AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])])dnl # Some tools Automake needs. AC_REQUIRE([AM_SANITY_CHECK])dnl AC_REQUIRE([AC_ARG_PROGRAM])dnl AM_MISSING_PROG(ACLOCAL, aclocal-${am__api_version}) AM_MISSING_PROG(AUTOCONF, autoconf) AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version}) AM_MISSING_PROG(AUTOHEADER, autoheader) AM_MISSING_PROG(MAKEINFO, makeinfo) AM_PROG_INSTALL_SH AM_PROG_INSTALL_STRIP AC_REQUIRE([AM_PROG_MKDIR_P])dnl # We need awk for the "check" target. The system "awk" is bad on # some platforms. AC_REQUIRE([AC_PROG_AWK])dnl AC_REQUIRE([AC_PROG_MAKE_SET])dnl AC_REQUIRE([AM_SET_LEADING_DOT])dnl _AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], [_AM_PROG_TAR([v7])])]) _AM_IF_OPTION([no-dependencies],, [AC_PROVIDE_IFELSE([AC_PROG_CC], [_AM_DEPENDENCIES(CC)], [define([AC_PROG_CC], defn([AC_PROG_CC])[_AM_DEPENDENCIES(CC)])])dnl AC_PROVIDE_IFELSE([AC_PROG_CXX], [_AM_DEPENDENCIES(CXX)], [define([AC_PROG_CXX], defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl AC_PROVIDE_IFELSE([AC_PROG_OBJC], [_AM_DEPENDENCIES(OBJC)], [define([AC_PROG_OBJC], defn([AC_PROG_OBJC])[_AM_DEPENDENCIES(OBJC)])])dnl ]) ]) # When config.status generates a header, we must update the stamp-h file. # This file resides in the same directory as the config header # that is generated. The stamp files are numbered to have different names. # Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the # loop where config.status creates the headers, so we can generate # our stamp files there. AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], [# Compute $1's index in $config_headers. _am_arg=$1 _am_stamp_count=1 for _am_header in $config_headers :; do case $_am_header in $_am_arg | $_am_arg:* ) break ;; * ) _am_stamp_count=`expr $_am_stamp_count + 1` ;; esac done echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) # Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_PROG_INSTALL_SH # ------------------ # Define $install_sh. AC_DEFUN([AM_PROG_INSTALL_SH], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl install_sh=${install_sh-"\$(SHELL) $am_aux_dir/install-sh"} AC_SUBST(install_sh)]) # Copyright (C) 2003, 2005 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 2 # Check whether the underlying file-system supports filenames # with a leading dot. For instance MS-DOS doesn't. AC_DEFUN([AM_SET_LEADING_DOT], [rm -rf .tst 2>/dev/null mkdir .tst 2>/dev/null if test -d .tst; then am__leading_dot=. else am__leading_dot=_ fi rmdir .tst 2>/dev/null AC_SUBST([am__leading_dot])]) # Add --enable-maintainer-mode option to configure. -*- Autoconf -*- # From Jim Meyering # Copyright (C) 1996, 1998, 2000, 2001, 2002, 2003, 2004, 2005 # Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 4 AC_DEFUN([AM_MAINTAINER_MODE], [AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles]) dnl maintainer-mode is disabled by default AC_ARG_ENABLE(maintainer-mode, [ --enable-maintainer-mode enable make rules and dependencies not useful (and sometimes confusing) to the casual installer], USE_MAINTAINER_MODE=$enableval, USE_MAINTAINER_MODE=no) AC_MSG_RESULT([$USE_MAINTAINER_MODE]) AM_CONDITIONAL(MAINTAINER_MODE, [test $USE_MAINTAINER_MODE = yes]) MAINT=$MAINTAINER_MODE_TRUE AC_SUBST(MAINT)dnl ] ) AU_DEFUN([jm_MAINTAINER_MODE], [AM_MAINTAINER_MODE]) # Check to see how 'make' treats includes. -*- Autoconf -*- # Copyright (C) 2001, 2002, 2003, 2005 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 3 # AM_MAKE_INCLUDE() # ----------------- # Check to see how make treats includes. AC_DEFUN([AM_MAKE_INCLUDE], [am_make=${MAKE-make} cat > confinc << 'END' am__doit: @echo done .PHONY: am__doit END # If we don't find an include directive, just comment out the code. AC_MSG_CHECKING([for style of include used by $am_make]) am__include="#" am__quote= _am_result=none # First try GNU make style include. echo "include confinc" > confmf # We grep out `Entering directory' and `Leaving directory' # messages which can occur if `w' ends up in MAKEFLAGS. # In particular we don't look at `^make:' because GNU make might # be invoked under some other name (usually "gmake"), in which # case it prints its new name instead of `make'. if test "`$am_make -s -f confmf 2> /dev/null | grep -v 'ing directory'`" = "done"; then am__include=include am__quote= _am_result=GNU fi # Now try BSD make style include. if test "$am__include" = "#"; then echo '.include "confinc"' > confmf if test "`$am_make -s -f confmf 2> /dev/null`" = "done"; then am__include=.include am__quote="\"" _am_result=BSD fi fi AC_SUBST([am__include]) AC_SUBST([am__quote]) AC_MSG_RESULT([$_am_result]) rm -f confinc confmf ]) # Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- # Copyright (C) 1997, 1999, 2000, 2001, 2003, 2004, 2005 # Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 5 # AM_MISSING_PROG(NAME, PROGRAM) # ------------------------------ AC_DEFUN([AM_MISSING_PROG], [AC_REQUIRE([AM_MISSING_HAS_RUN]) $1=${$1-"${am_missing_run}$2"} AC_SUBST($1)]) # AM_MISSING_HAS_RUN # ------------------ # Define MISSING if not defined so far and test if it supports --run. # If it does, set am_missing_run to use it, otherwise, to nothing. AC_DEFUN([AM_MISSING_HAS_RUN], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl AC_REQUIRE_AUX_FILE([missing])dnl test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing" # Use eval to expand $SHELL if eval "$MISSING --run true"; then am_missing_run="$MISSING --run " else am_missing_run= AC_MSG_WARN([`missing' script is too old or missing]) fi ]) # Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_PROG_MKDIR_P # --------------- # Check for `mkdir -p'. AC_DEFUN([AM_PROG_MKDIR_P], [AC_PREREQ([2.60])dnl AC_REQUIRE([AC_PROG_MKDIR_P])dnl dnl Automake 1.8 to 1.9.6 used to define mkdir_p. We now use MKDIR_P, dnl while keeping a definition of mkdir_p for backward compatibility. dnl @MKDIR_P@ is magic: AC_OUTPUT adjusts its value for each Makefile. dnl However we cannot define mkdir_p as $(MKDIR_P) for the sake of dnl Makefile.ins that do not define MKDIR_P, so we do our own dnl adjustment using top_builddir (which is defined more often than dnl MKDIR_P). AC_SUBST([mkdir_p], ["$MKDIR_P"])dnl case $mkdir_p in [[\\/$]]* | ?:[[\\/]]*) ;; */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;; esac ]) # Helper functions for option handling. -*- Autoconf -*- # Copyright (C) 2001, 2002, 2003, 2005 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 3 # _AM_MANGLE_OPTION(NAME) # ----------------------- AC_DEFUN([_AM_MANGLE_OPTION], [[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) # _AM_SET_OPTION(NAME) # ------------------------------ # Set option NAME. Presently that only means defining a flag for this option. AC_DEFUN([_AM_SET_OPTION], [m4_define(_AM_MANGLE_OPTION([$1]), 1)]) # _AM_SET_OPTIONS(OPTIONS) # ---------------------------------- # OPTIONS is a space-separated list of Automake options. AC_DEFUN([_AM_SET_OPTIONS], [AC_FOREACH([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) # _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) # ------------------------------------------- # Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. AC_DEFUN([_AM_IF_OPTION], [m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) # Check to make sure that the build environment is sane. -*- Autoconf -*- # Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005 # Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 4 # AM_SANITY_CHECK # --------------- AC_DEFUN([AM_SANITY_CHECK], [AC_MSG_CHECKING([whether build environment is sane]) # Just in case sleep 1 echo timestamp > conftest.file # Do `set' in a subshell so we don't clobber the current shell's # arguments. Must try -L first in case configure is actually a # symlink; some systems play weird games with the mod time of symlinks # (eg FreeBSD returns the mod time of the symlink's containing # directory). if ( set X `ls -Lt $srcdir/configure conftest.file 2> /dev/null` if test "$[*]" = "X"; then # -L didn't work. set X `ls -t $srcdir/configure conftest.file` fi rm -f conftest.file if test "$[*]" != "X $srcdir/configure conftest.file" \ && test "$[*]" != "X conftest.file $srcdir/configure"; then # If neither matched, then we have a broken ls. This can happen # if, for instance, CONFIG_SHELL is bash and it inherits a # broken ls alias from the environment. This has actually # happened. Such a system could not be considered "sane". AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken alias in your environment]) fi test "$[2]" = conftest.file ) then # Ok. : else AC_MSG_ERROR([newly created file is older than distributed files! Check your system clock]) fi AC_MSG_RESULT(yes)]) # Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_PROG_INSTALL_STRIP # --------------------- # One issue with vendor `install' (even GNU) is that you can't # specify the program used to strip binaries. This is especially # annoying in cross-compiling environments, where the build's strip # is unlikely to handle the host's binaries. # Fortunately install-sh will honor a STRIPPROG variable, so we # always use install-sh in `make install-strip', and initialize # STRIPPROG with the value of the STRIP variable (set by the user). AC_DEFUN([AM_PROG_INSTALL_STRIP], [AC_REQUIRE([AM_PROG_INSTALL_SH])dnl # Installed binaries are usually stripped using `strip' when the user # run `make install-strip'. However `strip' might not be the right # tool to use in cross-compilation environments, therefore Automake # will honor the `STRIP' environment variable to overrule this program. dnl Don't test for $cross_compiling = yes, because it might be `maybe'. if test "$cross_compiling" != no; then AC_CHECK_TOOL([STRIP], [strip], :) fi INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" AC_SUBST([INSTALL_STRIP_PROGRAM])]) # Copyright (C) 2006 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_SUBST_NOTMAKE(VARIABLE) # --------------------------- # Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in. # This macro is traced by Automake. AC_DEFUN([_AM_SUBST_NOTMAKE]) # Check how to create a tarball. -*- Autoconf -*- # Copyright (C) 2004, 2005 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 2 # _AM_PROG_TAR(FORMAT) # -------------------- # Check how to create a tarball in format FORMAT. # FORMAT should be one of `v7', `ustar', or `pax'. # # Substitute a variable $(am__tar) that is a command # writing to stdout a FORMAT-tarball containing the directory # $tardir. # tardir=directory && $(am__tar) > result.tar # # Substitute a variable $(am__untar) that extract such # a tarball read from stdin. # $(am__untar) < result.tar AC_DEFUN([_AM_PROG_TAR], [# Always define AMTAR for backward compatibility. AM_MISSING_PROG([AMTAR], [tar]) m4_if([$1], [v7], [am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'], [m4_case([$1], [ustar],, [pax],, [m4_fatal([Unknown tar format])]) AC_MSG_CHECKING([how to create a $1 tar archive]) # Loop over all known methods to create a tar archive until one works. _am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' _am_tools=${am_cv_prog_tar_$1-$_am_tools} # Do not fold the above two line into one, because Tru64 sh and # Solaris sh will not grok spaces in the rhs of `-'. for _am_tool in $_am_tools do case $_am_tool in gnutar) for _am_tar in tar gnutar gtar; do AM_RUN_LOG([$_am_tar --version]) && break done am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' am__untar="$_am_tar -xf -" ;; plaintar) # Must skip GNU tar: if it does not support --format= it doesn't create # ustar tarball either. (tar --version) >/dev/null 2>&1 && continue am__tar='tar chf - "$$tardir"' am__tar_='tar chf - "$tardir"' am__untar='tar xf -' ;; pax) am__tar='pax -L -x $1 -w "$$tardir"' am__tar_='pax -L -x $1 -w "$tardir"' am__untar='pax -r' ;; cpio) am__tar='find "$$tardir" -print | cpio -o -H $1 -L' am__tar_='find "$tardir" -print | cpio -o -H $1 -L' am__untar='cpio -i -H $1 -d' ;; none) am__tar=false am__tar_=false am__untar=false ;; esac # If the value was cached, stop now. We just wanted to have am__tar # and am__untar set. test -n "${am_cv_prog_tar_$1}" && break # tar/untar a dummy directory, and stop if the command works rm -rf conftest.dir mkdir conftest.dir echo GrepMe > conftest.dir/file AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) rm -rf conftest.dir if test -s conftest.tar; then AM_RUN_LOG([$am__untar /dev/null 2>&1 && break fi done rm -rf conftest.dir AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) AC_MSG_RESULT([$am_cv_prog_tar_$1])]) AC_SUBST([am__tar]) AC_SUBST([am__untar]) ]) # _AM_PROG_TAR dhcp-4.2.4/bind/000777 000765 000024 00000000000 11757514243 013320 5ustar00sarstaff000000 000000 dhcp-4.2.4/client/000777 000765 000024 00000000000 11757514244 013663 5ustar00sarstaff000000 000000 dhcp-4.2.4/common/000777 000765 000024 00000000000 11757514244 013675 5ustar00sarstaff000000 000000 dhcp-4.2.4/configure000755 000765 000024 00001040462 11757500162 014311 0ustar00sarstaff000000 000000 #! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.61 for DHCP 4.2.4. # # Report bugs to . # # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, # 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## --------------------- ## ## M4sh Initialization. ## ## --------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in *posix*) set -o posix ;; esac fi # PATH needs CR # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then echo "#! /bin/sh" >conf$$.sh echo "exit 0" >>conf$$.sh chmod +x conf$$.sh if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then PATH_SEPARATOR=';' else PATH_SEPARATOR=: fi rm -f conf$$.sh fi # Support unset when possible. if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then as_unset=unset else as_unset=false fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) as_nl=' ' IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. case $0 in *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 { (exit 1); exit 1; } fi # Work around bugs in pre-3.0 UWIN ksh. for as_var in ENV MAIL MAILPATH do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. for as_var in \ LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ LC_TELEPHONE LC_TIME do if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then eval $as_var=C; export $as_var else ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var fi done # Required to use basename. if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi # Name of the executable. as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # CDPATH. $as_unset CDPATH if test "x$CONFIG_SHELL" = x; then if (eval ":") 2>/dev/null; then as_have_required=yes else as_have_required=no fi if test $as_have_required = yes && (eval ": (as_func_return () { (exit \$1) } as_func_success () { as_func_return 0 } as_func_failure () { as_func_return 1 } as_func_ret_success () { return 0 } as_func_ret_failure () { return 1 } exitcode=0 if as_func_success; then : else exitcode=1 echo as_func_success failed. fi if as_func_failure; then exitcode=1 echo as_func_failure succeeded. fi if as_func_ret_success; then : else exitcode=1 echo as_func_ret_success failed. fi if as_func_ret_failure; then exitcode=1 echo as_func_ret_failure succeeded. fi if ( set x; as_func_ret_success y && test x = \"\$1\" ); then : else exitcode=1 echo positional parameters were not saved. fi test \$exitcode = 0) || { (exit 1); exit 1; } ( as_lineno_1=\$LINENO as_lineno_2=\$LINENO test \"x\$as_lineno_1\" != \"x\$as_lineno_2\" && test \"x\`expr \$as_lineno_1 + 1\`\" = \"x\$as_lineno_2\") || { (exit 1); exit 1; } ") 2> /dev/null; then : else as_candidate_shells= as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. case $as_dir in /*) for as_base in sh bash ksh sh5; do as_candidate_shells="$as_candidate_shells $as_dir/$as_base" done;; esac done IFS=$as_save_IFS for as_shell in $as_candidate_shells $SHELL; do # Try only shells that exist, to save several forks. if { test -f "$as_shell" || test -f "$as_shell.exe"; } && { ("$as_shell") 2> /dev/null <<\_ASEOF if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in *posix*) set -o posix ;; esac fi : _ASEOF }; then CONFIG_SHELL=$as_shell as_have_required=yes if { "$as_shell" 2> /dev/null <<\_ASEOF if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in *posix*) set -o posix ;; esac fi : (as_func_return () { (exit $1) } as_func_success () { as_func_return 0 } as_func_failure () { as_func_return 1 } as_func_ret_success () { return 0 } as_func_ret_failure () { return 1 } exitcode=0 if as_func_success; then : else exitcode=1 echo as_func_success failed. fi if as_func_failure; then exitcode=1 echo as_func_failure succeeded. fi if as_func_ret_success; then : else exitcode=1 echo as_func_ret_success failed. fi if as_func_ret_failure; then exitcode=1 echo as_func_ret_failure succeeded. fi if ( set x; as_func_ret_success y && test x = "$1" ); then : else exitcode=1 echo positional parameters were not saved. fi test $exitcode = 0) || { (exit 1); exit 1; } ( as_lineno_1=$LINENO as_lineno_2=$LINENO test "x$as_lineno_1" != "x$as_lineno_2" && test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2") || { (exit 1); exit 1; } _ASEOF }; then break fi fi done if test "x$CONFIG_SHELL" != x; then for as_var in BASH_ENV ENV do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var done export CONFIG_SHELL exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"} fi if test $as_have_required = no; then echo This script requires a shell more modern than all the echo shells that I found on your system. Please install a echo modern shell, or manually run the script under such a echo shell if you do have one. { (exit 1); exit 1; } fi fi fi (eval "as_func_return () { (exit \$1) } as_func_success () { as_func_return 0 } as_func_failure () { as_func_return 1 } as_func_ret_success () { return 0 } as_func_ret_failure () { return 1 } exitcode=0 if as_func_success; then : else exitcode=1 echo as_func_success failed. fi if as_func_failure; then exitcode=1 echo as_func_failure succeeded. fi if as_func_ret_success; then : else exitcode=1 echo as_func_ret_success failed. fi if as_func_ret_failure; then exitcode=1 echo as_func_ret_failure succeeded. fi if ( set x; as_func_ret_success y && test x = \"\$1\" ); then : else exitcode=1 echo positional parameters were not saved. fi test \$exitcode = 0") || { echo No shell found that supports shell functions. echo Please tell autoconf@gnu.org about your system, echo including any error possibly output before this echo message } as_lineno_1=$LINENO as_lineno_2=$LINENO test "x$as_lineno_1" != "x$as_lineno_2" && test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || { # Create $as_me.lineno as a copy of $as_myself, but with $LINENO # uniformly replaced by the line number. The first 'sed' inserts a # line-number line after each line using $LINENO; the second 'sed' # does the real work. The second script uses 'N' to pair each # line-number line with the line containing $LINENO, and appends # trailing '-' during substitution so that $LINENO is not a special # case at line end. # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the # scripts with optimization help from Paolo Bonzini. Blame Lee # E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 { (exit 1); exit 1; }; } # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in -n*) case `echo 'x\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. *) ECHO_C='\c';; esac;; *) ECHO_N='-n';; esac if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir fi echo >conf$$.file if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -p'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -p' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -p' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p=: else test -d ./-p && rmdir ./-p as_mkdir_p=false fi if test -x / >/dev/null 2>&1; then as_test_x='test -x' else if ls -dL / >/dev/null 2>&1; then as_ls_L_option=L else as_ls_L_option= fi as_test_x=' eval sh -c '\'' if test -d "$1"; then test -d "$1/."; else case $1 in -*)set "./$1";; esac; case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in ???[sx]*):;;*)false;;esac;fi '\'' sh ' fi as_executable_p=$as_test_x # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 7<&0 &1 # Name of the host. # hostname on some systems (SVR3.2, Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` # # Initializations. # ac_default_prefix=/usr/local ac_clean_files= ac_config_libobj_dir=. LIBOBJS= cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= SHELL=${CONFIG_SHELL-/bin/sh} # Identity of this package. PACKAGE_NAME='DHCP' PACKAGE_TARNAME='dhcp' PACKAGE_VERSION='4.2.4' PACKAGE_STRING='DHCP 4.2.4' PACKAGE_BUGREPORT='dhcp-users@isc.org' # Factoring default headers for most tests. ac_includes_default="\ #include #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef STDC_HEADERS # include # include #else # ifdef HAVE_STDLIB_H # include # endif #endif #ifdef HAVE_STRING_H # if !defined STDC_HEADERS && defined HAVE_MEMORY_H # include # endif # include #endif #ifdef HAVE_STRINGS_H # include #endif #ifdef HAVE_INTTYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif #ifdef HAVE_UNISTD_H # include #endif" ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datarootdir datadir sysconfdir sharedstatedir localstatedir includedir oldincludedir docdir infodir htmldir dvidir pdfdir psdir libdir localedir mandir DEFS ECHO_C ECHO_N ECHO_T LIBS build_alias host_alias target_alias INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA am__isrc CYGPATH_W PACKAGE VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO install_sh STRIP INSTALL_STRIP_PROGRAM mkdir_p AWK SET_MAKE am__leading_dot AMTAR am__tar am__untar MAINTAINER_MODE_TRUE MAINTAINER_MODE_FALSE MAINT CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT DEPDIR am__include am__quote AMDEP_TRUE AMDEP_FALSE AMDEPBACKSLASH CCDEPMODE am__fastdepCC_TRUE am__fastdepCC_FALSE CPP GREP EGREP RANLIB byte_order ac_prefix_program LDAP_CFLAGS LIBOBJS LTLIBOBJS' ac_subst_files='' ac_precious_vars='build_alias host_alias target_alias CC CFLAGS LDFLAGS LIBS CPPFLAGS CPP' # Initialize some variables set by options. ac_init_help= ac_init_version=false # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. # (The list follows the same order as the GNU Coding Standards.) bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' psdir='${docdir}' libdir='${exec_prefix}/lib' localedir='${datarootdir}/locale' mandir='${datarootdir}/man' ac_prev= ac_dashdash= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval $ac_prev=\$ac_option ac_prev= continue fi case $ac_option in *=*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; *) ac_optarg=yes ;; esac # Accept the important Cygnus configure options, so we can diagnose typos. case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=*) datadir=$ac_optarg ;; -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ | --dataroo | --dataro | --datar) ac_prev=datarootdir ;; -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) datarootdir=$ac_optarg ;; -disable-* | --disable-*) ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_feature" : ".*[^-._$as_cr_alnum]" >/dev/null && { echo "$as_me: error: invalid feature name: $ac_feature" >&2 { (exit 1); exit 1; }; } ac_feature=`echo $ac_feature | sed 's/[-.]/_/g'` eval enable_$ac_feature=no ;; -docdir | --docdir | --docdi | --doc | --do) ac_prev=docdir ;; -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) docdir=$ac_optarg ;; -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) ac_prev=dvidir ;; -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) dvidir=$ac_optarg ;; -enable-* | --enable-*) ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_feature" : ".*[^-._$as_cr_alnum]" >/dev/null && { echo "$as_me: error: invalid feature name: $ac_feature" >&2 { (exit 1); exit 1; }; } ac_feature=`echo $ac_feature | sed 's/[-.]/_/g'` eval enable_$ac_feature=\$ac_optarg ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) ac_prev=htmldir ;; -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ | --ht=*) htmldir=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localedir | --localedir | --localedi | --localed | --locale) ac_prev=localedir ;; -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) localedir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst | --locals) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) ac_prev=pdfdir ;; -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) pdfdir=$ac_optarg ;; -psdir | --psdir | --psdi | --psd | --ps) ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_package" : ".*[^-._$as_cr_alnum]" >/dev/null && { echo "$as_me: error: invalid package name: $ac_package" >&2 { (exit 1); exit 1; }; } ac_package=`echo $ac_package | sed 's/[-.]/_/g'` eval with_$ac_package=\$ac_optarg ;; -without-* | --without-*) ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_package" : ".*[^-._$as_cr_alnum]" >/dev/null && { echo "$as_me: error: invalid package name: $ac_package" >&2 { (exit 1); exit 1; }; } ac_package=`echo $ac_package | sed 's/[-.]/_/g'` eval with_$ac_package=no ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) { echo "$as_me: error: unrecognized option: $ac_option Try \`$0 --help' for more information." >&2 { (exit 1); exit 1; }; } ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null && { echo "$as_me: error: invalid variable name: $ac_envvar" >&2 { (exit 1); exit 1; }; } eval $ac_envvar=\$ac_optarg export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && echo "$as_me: WARNING: invalid host type: $ac_option" >&2 : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` { echo "$as_me: error: missing argument to $ac_option" >&2 { (exit 1); exit 1; }; } fi # Be sure to have absolute directory names. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ libdir localedir mandir do eval ac_val=\$$ac_var case $ac_val in [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 { (exit 1); exit 1; }; } done # There might be people who depend on the old broken behavior: `$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host. If a cross compiler is detected then cross compile mode will be used." >&2 elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || { echo "$as_me: error: Working directory cannot be determined" >&2 { (exit 1); exit 1; }; } test "X$ac_ls_di" = "X$ac_pwd_ls_di" || { echo "$as_me: error: pwd does not report name of working directory" >&2 { (exit 1); exit 1; }; } # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then the parent directory. ac_confdir=`$as_dirname -- "$0" || $as_expr X"$0" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$0" : 'X\(//\)[^/]' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || echo X"$0" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` srcdir=$ac_confdir if test ! -r "$srcdir/$ac_unique_file"; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." { echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2 { (exit 1); exit 1; }; } fi ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || { echo "$as_me: error: $ac_msg" >&2 { (exit 1); exit 1; }; } pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then srcdir=. fi # Remove unnecessary trailing slashes from srcdir. # Double slashes in file names in object file debugging info # mess up M-x gdb in Emacs. case $srcdir in */) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; esac for ac_var in $ac_precious_vars; do eval ac_env_${ac_var}_set=\${${ac_var}+set} eval ac_env_${ac_var}_value=\$${ac_var} eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} eval ac_cv_env_${ac_var}_value=\$${ac_var} done # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF \`configure' configures DHCP 4.2.4 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print \`checking...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or \`..'] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, \`make install' will install all the files in \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify an installation prefix other than \`$ac_default_prefix' using \`--prefix', for instance \`--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] --mandir=DIR man documentation [DATAROOTDIR/man] --docdir=DIR documentation root [DATAROOTDIR/doc/dhcp] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] --psdir=DIR ps documentation [DOCDIR] _ACEOF cat <<\_ACEOF Program names: --program-prefix=PREFIX prepend PREFIX to installed program names --program-suffix=SUFFIX append SUFFIX to installed program names --program-transform-name=PROGRAM run sed PROGRAM on installed program names _ACEOF fi if test -n "$ac_init_help"; then case $ac_init_help in short | recursive ) echo "Configuration of DHCP 4.2.4:";; esac cat <<\_ACEOF Optional Features: --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --enable-maintainer-mode enable make rules and dependencies not useful (and sometimes confusing) to the casual installer --disable-dependency-tracking speeds up one-time build --enable-dependency-tracking do not reject slow dependency extractors --enable-debug create a debug-only version of the software (default is no). --enable-failover enable support for failover (default is yes) --enable-execute enable support for execute() in config (default is yes) --enable-tracing enable support for server activity tracing (default is yes) --enable-delayed-ack queues multiple DHCPACK replies (default is no) --enable-dhcpv6 enable support for DHCPv6 (default is yes) --enable-paranoia enable support for chroot/setuid (default is no) --enable-early-chroot enable chrooting prior to configuration (default is no) --enable-ipv4-pktinfo enable use of pktinfo on IPv4 sockets (default is no) --enable-use-sockets use the standard BSD socket API (default is no) Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-srv-lease-file=PATH File for dhcpd leases (default is LOCALSTATEDIR/db/dhcpd.leases) --with-srv6-lease-file=PATH File for dhcpd6 leases (default is LOCALSTATEDIR/db/dhcpd6.leases) --with-cli-lease-file=PATH File for dhclient leases (default is LOCALSTATEDIR/db/dhclient.leases) --with-cli6-lease-file=PATH File for dhclient6 leases (default is LOCALSTATEDIR/db/dhclient6.leases) --with-srv-pid-file=PATH File for dhcpd process information (default is LOCALSTATEDIR/run/dhcpd.pid) --with-srv6-pid-file=PATH File for dhcpd6 process information (default is LOCALSTATEDIR/run/dhcpd6.pid) --with-cli-pid-file=PATH File for dhclient process information (default is LOCALSTATEDIR/run/dhclient.pid) --with-cli6-pid-file=PATH File for dhclient6 process information (default is LOCALSTATEDIR/run/dhclient6.pid) --with-relay-pid-file=PATH File for dhcrelay process information (default is LOCALSTATEDIR/run/dhcrelay.pid) --with-relay6-pid-file=PATH File for dhcrelay6 process information (default is LOCALSTATEDIR/run/dhcrelay6.pid) --with-libbind=PATH bind includes and libraries are in PATH (default is ./bind) --with-ldap enable OpenLDAP support in dhcpd (default is no) --with-ldapcrypto enable OpenLDAP crypto support in dhcpd (default is no) Some influential environment variables: CC C compiler command CFLAGS C compiler flags LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory LIBS libraries to pass to the linker, e.g. -l CPPFLAGS C/C++/Objective C preprocessor flags, e.g. -I if you have headers in a nonstandard directory CPP C preprocessor Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. Report bugs to . _ACEOF ac_status=$? fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d "$ac_dir" || continue ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,/..,g;s,/,,'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } # Check for guested configure. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive elif test -f "$ac_srcdir/configure"; then echo && $SHELL "$ac_srcdir/configure" --help=recursive else echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF DHCP configure 4.2.4 generated by GNU Autoconf 2.61 Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit fi cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by DHCP $as_me 4.2.4, which was generated by GNU Autoconf 2.61. Invocation command line was $ $0 $@ _ACEOF exec 5>>config.log { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` /usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. echo "PATH: $as_dir" done IFS=$as_save_IFS } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) ac_arg=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;; 2) ac_configure_args1="$ac_configure_args1 '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi ac_configure_args="$ac_configure_args '$ac_arg'" ;; esac done done $as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; } $as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; } # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? # Save into config.log some information that might help in debugging. { echo cat <<\_ASBOX ## ---------------- ## ## Cache variables. ## ## ---------------- ## _ASBOX echo # The following way of writing the cache mishandles newlines in values, ( for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { echo "$as_me:$LINENO: WARNING: Cache variable $ac_var contains a newline." >&5 echo "$as_me: WARNING: Cache variable $ac_var contains a newline." >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( *) $as_unset $ac_var ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( *${as_nl}ac_space=\ *) sed -n \ "s/'\''/'\''\\\\'\'''\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" ;; #( *) sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) echo cat <<\_ASBOX ## ----------------- ## ## Output variables. ## ## ----------------- ## _ASBOX echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac echo "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then cat <<\_ASBOX ## ------------------- ## ## File substitutions. ## ## ------------------- ## _ASBOX echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac echo "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then cat <<\_ASBOX ## ----------- ## ## confdefs.h. ## ## ----------- ## _ASBOX echo cat confdefs.h echo fi test "$ac_signal" != 0 && echo "$as_me: caught signal $ac_signal" echo "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h # Predefined preprocessor variables. cat >>confdefs.h <<_ACEOF #define PACKAGE_NAME "$PACKAGE_NAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_TARNAME "$PACKAGE_TARNAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_VERSION "$PACKAGE_VERSION" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_STRING "$PACKAGE_STRING" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" _ACEOF # Let the site file select an alternate cache file if it wants to. # Prefer explicitly selected file to automatically selected ones. if test -n "$CONFIG_SITE"; then set x "$CONFIG_SITE" elif test "x$prefix" != xNONE; then set x "$prefix/share/config.site" "$prefix/etc/config.site" else set x "$ac_default_prefix/share/config.site" \ "$ac_default_prefix/etc/config.site" fi shift for ac_site_file do if test -r "$ac_site_file"; then { echo "$as_me:$LINENO: loading site script $ac_site_file" >&5 echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special # files actually), so we avoid doing that. if test -f "$cache_file"; then { echo "$as_me:$LINENO: loading cache $cache_file" >&5 echo "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { echo "$as_me:$LINENO: creating cache $cache_file" >&5 echo "$as_me: creating cache $cache_file" >&6;} >$cache_file fi # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in $ac_precious_vars; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val=\$ac_cv_env_${ac_var}_value eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) { echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5 echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then { echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5 echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} { echo "$as_me:$LINENO: former value: $ac_old_val" >&5 echo "$as_me: former value: $ac_old_val" >&2;} { echo "$as_me:$LINENO: current value: $ac_new_val" >&5 echo "$as_me: current value: $ac_new_val" >&2;} ac_cache_corrupted=: fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *\'*) ac_arg=$ac_var=`echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) ac_configure_args="$ac_configure_args '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5 echo "$as_me: error: changes in the environment can compromise the build" >&2;} { { echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5 echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;} { (exit 1); exit 1; }; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu # we specify "foreign" to avoid having to have the GNU mandated files, # like AUTHORS, COPYING, and such am__api_version='1.10' ac_aux_dir= for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do if test -f "$ac_dir/install-sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install-sh -c" break elif test -f "$ac_dir/install.sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install.sh -c" break elif test -f "$ac_dir/shtool"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/shtool install -c" break fi done if test -z "$ac_aux_dir"; then { { echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" >&5 echo "$as_me: error: cannot find install-sh or install.sh in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" >&2;} { (exit 1); exit 1; }; } fi # These three variables are undocumented and unsupported, # and are intended to be withdrawn in a future Autoconf release. # They can cause serious problems if a builder's source tree is in a directory # whose full name contains unusual characters. ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: # SysV /etc/install, /usr/sbin/install # SunOS /usr/etc/install # IRIX /sbin/install # AIX /bin/install # AmigaOS /C/install, which installs bootblocks on floppy discs # AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag # AFS /usr/afsws/bin/install, which mishandles nonexistent args # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # OS/2's system install, which has a completely different semantic # ./install, which can be erroneously created by make from ./install.sh. { echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5 echo $ECHO_N "checking for a BSD-compatible install... $ECHO_C" >&6; } if test -z "$INSTALL"; then if test "${ac_cv_path_install+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. # Account for people who put trailing slashes in PATH elements. case $as_dir/ in ./ | .// | /cC/* | \ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ ?:\\/os2\\/install\\/* | ?:\\/OS2\\/INSTALL\\/* | \ /usr/ucb/* ) ;; *) # OSF1 and SCO ODT 3.0 have their own names for install. # Don't use installbsd from OSF since it installs stuff as root # by default. for ac_prog in ginstall scoinst install; do for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then if test $ac_prog = install && grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. : elif test $ac_prog = install && grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # program-specific install script used by HP pwplus--don't use. : else ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" break 3 fi fi done done ;; esac done IFS=$as_save_IFS fi if test "${ac_cv_path_install+set}" = set; then INSTALL=$ac_cv_path_install else # As a last resort, use the slow shell script. Don't cache a # value for INSTALL within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. INSTALL=$ac_install_sh fi fi { echo "$as_me:$LINENO: result: $INSTALL" >&5 echo "${ECHO_T}$INSTALL" >&6; } # Use test -z because SunOS4 sh mishandles braces in ${var-val}. # It thinks the first close brace ends the variable substitution. test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' { echo "$as_me:$LINENO: checking whether build environment is sane" >&5 echo $ECHO_N "checking whether build environment is sane... $ECHO_C" >&6; } # Just in case sleep 1 echo timestamp > conftest.file # Do `set' in a subshell so we don't clobber the current shell's # arguments. Must try -L first in case configure is actually a # symlink; some systems play weird games with the mod time of symlinks # (eg FreeBSD returns the mod time of the symlink's containing # directory). if ( set X `ls -Lt $srcdir/configure conftest.file 2> /dev/null` if test "$*" = "X"; then # -L didn't work. set X `ls -t $srcdir/configure conftest.file` fi rm -f conftest.file if test "$*" != "X $srcdir/configure conftest.file" \ && test "$*" != "X conftest.file $srcdir/configure"; then # If neither matched, then we have a broken ls. This can happen # if, for instance, CONFIG_SHELL is bash and it inherits a # broken ls alias from the environment. This has actually # happened. Such a system could not be considered "sane". { { echo "$as_me:$LINENO: error: ls -t appears to fail. Make sure there is not a broken alias in your environment" >&5 echo "$as_me: error: ls -t appears to fail. Make sure there is not a broken alias in your environment" >&2;} { (exit 1); exit 1; }; } fi test "$2" = conftest.file ) then # Ok. : else { { echo "$as_me:$LINENO: error: newly created file is older than distributed files! Check your system clock" >&5 echo "$as_me: error: newly created file is older than distributed files! Check your system clock" >&2;} { (exit 1); exit 1; }; } fi { echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6; } test "$program_prefix" != NONE && program_transform_name="s&^&$program_prefix&;$program_transform_name" # Use a double $ so make ignores it. test "$program_suffix" != NONE && program_transform_name="s&\$&$program_suffix&;$program_transform_name" # Double any \ or $. echo might interpret backslashes. # By default was `s,x,x', remove it if useless. cat <<\_ACEOF >conftest.sed s/[\\$]/&&/g;s/;s,x,x,$// _ACEOF program_transform_name=`echo $program_transform_name | sed -f conftest.sed` rm -f conftest.sed # expand $ac_aux_dir to an absolute path am_aux_dir=`cd $ac_aux_dir && pwd` test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing" # Use eval to expand $SHELL if eval "$MISSING --run true"; then am_missing_run="$MISSING --run " else am_missing_run= { echo "$as_me:$LINENO: WARNING: \`missing' script is too old or missing" >&5 echo "$as_me: WARNING: \`missing' script is too old or missing" >&2;} fi { echo "$as_me:$LINENO: checking for a thread-safe mkdir -p" >&5 echo $ECHO_N "checking for a thread-safe mkdir -p... $ECHO_C" >&6; } if test -z "$MKDIR_P"; then if test "${ac_cv_path_mkdir+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in mkdir gmkdir; do for ac_exec_ext in '' $ac_executable_extensions; do { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; } || continue case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #( 'mkdir (GNU coreutils) '* | \ 'mkdir (coreutils) '* | \ 'mkdir (fileutils) '4.1*) ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext break 3;; esac done done done IFS=$as_save_IFS fi if test "${ac_cv_path_mkdir+set}" = set; then MKDIR_P="$ac_cv_path_mkdir -p" else # As a last resort, use the slow shell script. Don't cache a # value for MKDIR_P within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. test -d ./--version && rmdir ./--version MKDIR_P="$ac_install_sh -d" fi fi { echo "$as_me:$LINENO: result: $MKDIR_P" >&5 echo "${ECHO_T}$MKDIR_P" >&6; } mkdir_p="$MKDIR_P" case $mkdir_p in [\\/$]* | ?:[\\/]*) ;; */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;; esac for ac_prog in gawk mawk nawk awk do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } if test "${ac_cv_prog_AWK+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$AWK"; then ac_cv_prog_AWK="$AWK" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_AWK="$ac_prog" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi AWK=$ac_cv_prog_AWK if test -n "$AWK"; then { echo "$as_me:$LINENO: result: $AWK" >&5 echo "${ECHO_T}$AWK" >&6; } else { echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6; } fi test -n "$AWK" && break done { echo "$as_me:$LINENO: checking whether ${MAKE-make} sets \$(MAKE)" >&5 echo $ECHO_N "checking whether ${MAKE-make} sets \$(MAKE)... $ECHO_C" >&6; } set x ${MAKE-make}; ac_make=`echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` if { as_var=ac_cv_prog_make_${ac_make}_set; eval "test \"\${$as_var+set}\" = set"; }; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.make <<\_ACEOF SHELL = /bin/sh all: @echo '@@@%%%=$(MAKE)=@@@%%%' _ACEOF # GNU make sometimes prints "make[1]: Entering...", which would confuse us. case `${MAKE-make} -f conftest.make 2>/dev/null` in *@@@%%%=?*=@@@%%%*) eval ac_cv_prog_make_${ac_make}_set=yes;; *) eval ac_cv_prog_make_${ac_make}_set=no;; esac rm -f conftest.make fi if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then { echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6; } SET_MAKE= else { echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6; } SET_MAKE="MAKE=${MAKE-make}" fi rm -rf .tst 2>/dev/null mkdir .tst 2>/dev/null if test -d .tst; then am__leading_dot=. else am__leading_dot=_ fi rmdir .tst 2>/dev/null if test "`cd $srcdir && pwd`" != "`pwd`"; then # Use -I$(srcdir) only when $(srcdir) != ., so that make's output # is not polluted with repeated "-I." am__isrc=' -I$(srcdir)' # test to see if srcdir already configured if test -f $srcdir/config.status; then { { echo "$as_me:$LINENO: error: source directory already configured; run \"make distclean\" there first" >&5 echo "$as_me: error: source directory already configured; run \"make distclean\" there first" >&2;} { (exit 1); exit 1; }; } fi fi # test whether we have cygpath if test -z "$CYGPATH_W"; then if (cygpath --version) >/dev/null 2>/dev/null; then CYGPATH_W='cygpath -w' else CYGPATH_W=echo fi fi # Define the identity of the package. PACKAGE='dhcp' VERSION='4.2.4' cat >>confdefs.h <<_ACEOF #define PACKAGE "$PACKAGE" _ACEOF cat >>confdefs.h <<_ACEOF #define VERSION "$VERSION" _ACEOF # Some tools Automake needs. ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"} AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"} AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"} AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"} MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} install_sh=${install_sh-"\$(SHELL) $am_aux_dir/install-sh"} # Installed binaries are usually stripped using `strip' when the user # run `make install-strip'. However `strip' might not be the right # tool to use in cross-compilation environments, therefore Automake # will honor the `STRIP' environment variable to overrule this program. if test "$cross_compiling" != no; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. set dummy ${ac_tool_prefix}strip; ac_word=$2 { echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } if test "${ac_cv_prog_STRIP+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$STRIP"; then ac_cv_prog_STRIP="$STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_STRIP="${ac_tool_prefix}strip" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi STRIP=$ac_cv_prog_STRIP if test -n "$STRIP"; then { echo "$as_me:$LINENO: result: $STRIP" >&5 echo "${ECHO_T}$STRIP" >&6; } else { echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6; } fi fi if test -z "$ac_cv_prog_STRIP"; then ac_ct_STRIP=$STRIP # Extract the first word of "strip", so it can be a program name with args. set dummy strip; ac_word=$2 { echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$ac_ct_STRIP"; then ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_STRIP="strip" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP if test -n "$ac_ct_STRIP"; then { echo "$as_me:$LINENO: result: $ac_ct_STRIP" >&5 echo "${ECHO_T}$ac_ct_STRIP" >&6; } else { echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6; } fi if test "x$ac_ct_STRIP" = x; then STRIP=":" else case $cross_compiling:$ac_tool_warned in yes:) { echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools whose name does not start with the host triplet. If you think this configuration is useful to you, please write to autoconf@gnu.org." >&5 echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools whose name does not start with the host triplet. If you think this configuration is useful to you, please write to autoconf@gnu.org." >&2;} ac_tool_warned=yes ;; esac STRIP=$ac_ct_STRIP fi else STRIP="$ac_cv_prog_STRIP" fi fi INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" # We need awk for the "check" target. The system "awk" is bad on # some platforms. # Always define AMTAR for backward compatibility. AMTAR=${AMTAR-"${am_missing_run}tar"} am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -' # we specify AM_MAINTAINER_MODE to avoid problems with rebuilding # the configure and makefiles. Without it users doing things that # change the timestamps on the code, like checking it into a cvs # tree, could trigger a rebuild of the infrastructure files which # might fail if they don't have the correct tools. { echo "$as_me:$LINENO: checking whether to enable maintainer-specific portions of Makefiles" >&5 echo $ECHO_N "checking whether to enable maintainer-specific portions of Makefiles... $ECHO_C" >&6; } # Check whether --enable-maintainer-mode was given. if test "${enable_maintainer_mode+set}" = set; then enableval=$enable_maintainer_mode; USE_MAINTAINER_MODE=$enableval else USE_MAINTAINER_MODE=no fi { echo "$as_me:$LINENO: result: $USE_MAINTAINER_MODE" >&5 echo "${ECHO_T}$USE_MAINTAINER_MODE" >&6; } if test $USE_MAINTAINER_MODE = yes; then MAINTAINER_MODE_TRUE= MAINTAINER_MODE_FALSE='#' else MAINTAINER_MODE_TRUE='#' MAINTAINER_MODE_FALSE= fi MAINT=$MAINTAINER_MODE_TRUE # We want to turn on warnings if we are using gcc and the user did # not specify CFLAGS. The autoconf check for the C compiler sets the # CFLAGS if gcc is used, so we will save it before we run that check. SAVE_CFLAGS="$CFLAGS" # Now find our C compiler. ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } if test "${ac_cv_prog_CC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_CC="${ac_tool_prefix}gcc" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { echo "$as_me:$LINENO: result: $CC" >&5 echo "${ECHO_T}$CC" >&6; } else { echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } if test "${ac_cv_prog_ac_ct_CC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_CC="gcc" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 echo "${ECHO_T}$ac_ct_CC" >&6; } else { echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools whose name does not start with the host triplet. If you think this configuration is useful to you, please write to autoconf@gnu.org." >&5 echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools whose name does not start with the host triplet. If you think this configuration is useful to you, please write to autoconf@gnu.org." >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } if test "${ac_cv_prog_CC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_CC="${ac_tool_prefix}cc" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { echo "$as_me:$LINENO: result: $CC" >&5 echo "${ECHO_T}$CC" >&6; } else { echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } if test "${ac_cv_prog_CC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { echo "$as_me:$LINENO: result: $CC" >&5 echo "${ECHO_T}$CC" >&6; } else { echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } if test "${ac_cv_prog_CC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { echo "$as_me:$LINENO: result: $CC" >&5 echo "${ECHO_T}$CC" >&6; } else { echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } if test "${ac_cv_prog_ac_ct_CC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_CC="$ac_prog" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 echo "${ECHO_T}$ac_ct_CC" >&6; } else { echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools whose name does not start with the host triplet. If you think this configuration is useful to you, please write to autoconf@gnu.org." >&5 echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools whose name does not start with the host triplet. If you think this configuration is useful to you, please write to autoconf@gnu.org." >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH See \`config.log' for more details." >&5 echo "$as_me: error: no acceptable C compiler found in \$PATH See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } # Provide some information about the compiler. echo "$as_me:$LINENO: checking for C compiler version" >&5 ac_compiler=`set X $ac_compile; echo $2` { (ac_try="$ac_compiler --version >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compiler --version >&5") 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } { (ac_try="$ac_compiler -v >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compiler -v >&5") 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } { (ac_try="$ac_compiler -V >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compiler -V >&5") 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. { echo "$as_me:$LINENO: checking for C compiler default output file name" >&5 echo $ECHO_N "checking for C compiler default output file name... $ECHO_C" >&6; } ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # # List of possible output files, starting from the most likely. # The algorithm is not robust to junk in `.', hence go to wildcards (a.*) # only as a last resort. b.out is created by i960 compilers. ac_files='a_out.exe a.exe conftest.exe a.out conftest a.* conftest.* b.out' # # The IRIX 6 linker writes into existing files which may not be # executable, retaining their permissions. Remove them first so a # subsequent execution test works. ac_rmfiles= for ac_file in $ac_files do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.o | *.obj ) ;; * ) ac_rmfiles="$ac_rmfiles $ac_file";; esac done rm -f $ac_rmfiles if { (ac_try="$ac_link_default" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_link_default") 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; then # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. # So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, # so that the user can short-circuit this test for compilers unknown to # Autoconf. for ac_file in $ac_files '' do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.o | *.obj ) ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi # We set ac_cv_exeext here because the later test for it is not # safe: cross compilers may not add the suffix if given an `-o' # argument, so we may need to know it at that point already. # Even if this section looks crufty: it has the advantage of # actually working. break;; * ) break;; esac done test "$ac_cv_exeext" = no && ac_cv_exeext= else ac_file='' fi { echo "$as_me:$LINENO: result: $ac_file" >&5 echo "${ECHO_T}$ac_file" >&6; } if test -z "$ac_file"; then echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { echo "$as_me:$LINENO: error: C compiler cannot create executables See \`config.log' for more details." >&5 echo "$as_me: error: C compiler cannot create executables See \`config.log' for more details." >&2;} { (exit 77); exit 77; }; } fi ac_exeext=$ac_cv_exeext # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. { echo "$as_me:$LINENO: checking whether the C compiler works" >&5 echo $ECHO_N "checking whether the C compiler works... $ECHO_C" >&6; } # FIXME: These cross compiler hacks should be removed for Autoconf 3.0 # If not cross compiling, check that we can run a simple program. if test "$cross_compiling" != yes; then if { ac_try='./$ac_file' { (case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_try") 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { echo "$as_me:$LINENO: error: cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details." >&5 echo "$as_me: error: cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } fi fi fi { echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6; } rm -f a.out a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. { echo "$as_me:$LINENO: checking whether we are cross compiling" >&5 echo $ECHO_N "checking whether we are cross compiling... $ECHO_C" >&6; } { echo "$as_me:$LINENO: result: $cross_compiling" >&5 echo "${ECHO_T}$cross_compiling" >&6; } { echo "$as_me:$LINENO: checking for suffix of executables" >&5 echo $ECHO_N "checking for suffix of executables... $ECHO_C" >&6; } if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_link") 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; then # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with # `rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` break;; * ) break;; esac done else { { echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link See \`config.log' for more details." >&5 echo "$as_me: error: cannot compute suffix of executables: cannot compile and link See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } fi rm -f conftest$ac_cv_exeext { echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5 echo "${ECHO_T}$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT { echo "$as_me:$LINENO: checking for suffix of object files" >&5 echo $ECHO_N "checking for suffix of object files... $ECHO_C" >&6; } if test "${ac_cv_objext+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; then for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile See \`config.log' for more details." >&5 echo "$as_me: error: cannot compute suffix of object files: cannot compile See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi { echo "$as_me:$LINENO: result: $ac_cv_objext" >&5 echo "${ECHO_T}$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT { echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5 echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6; } if test "${ac_cv_c_compiler_gnu+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_compiler_gnu=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5 echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6; } GCC=`test $ac_compiler_gnu = yes && echo yes` ac_test_CFLAGS=${CFLAGS+set} ac_save_CFLAGS=$CFLAGS { echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5 echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6; } if test "${ac_cv_prog_cc_g+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_cv_prog_cc_g=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 CFLAGS="" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_cv_prog_cc_g=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5 echo "${ECHO_T}$ac_cv_prog_cc_g" >&6; } if test "$ac_test_CFLAGS" = set; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi { echo "$as_me:$LINENO: checking for $CC option to accept ISO C89" >&5 echo $ECHO_N "checking for $CC option to accept ISO C89... $ECHO_C" >&6; } if test "${ac_cv_prog_cc_c89+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_cv_prog_cc_c89=no ac_save_CC=$CC cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #include #include #include /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not '\xHH' hex character constants. These don't provoke an error unfortunately, instead are silently treated as 'x'. The following induces an error, until -std is added to get proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an array size at least. It's necessary to write '\x00'==0 to get something that's true only with -std. */ int osf4_cc_array ['\x00' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) 'x' int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); int argc; char **argv; int main () { return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ; return 0; } _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_cv_prog_cc_c89=$ac_arg else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f core conftest.err conftest.$ac_objext test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi # AC_CACHE_VAL case "x$ac_cv_prog_cc_c89" in x) { echo "$as_me:$LINENO: result: none needed" >&5 echo "${ECHO_T}none needed" >&6; } ;; xno) { echo "$as_me:$LINENO: result: unsupported" >&5 echo "${ECHO_T}unsupported" >&6; } ;; *) CC="$CC $ac_cv_prog_cc_c89" { echo "$as_me:$LINENO: result: $ac_cv_prog_cc_c89" >&5 echo "${ECHO_T}$ac_cv_prog_cc_c89" >&6; } ;; esac ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu DEPDIR="${am__leading_dot}deps" ac_config_commands="$ac_config_commands depfiles" am_make=${MAKE-make} cat > confinc << 'END' am__doit: @echo done .PHONY: am__doit END # If we don't find an include directive, just comment out the code. { echo "$as_me:$LINENO: checking for style of include used by $am_make" >&5 echo $ECHO_N "checking for style of include used by $am_make... $ECHO_C" >&6; } am__include="#" am__quote= _am_result=none # First try GNU make style include. echo "include confinc" > confmf # We grep out `Entering directory' and `Leaving directory' # messages which can occur if `w' ends up in MAKEFLAGS. # In particular we don't look at `^make:' because GNU make might # be invoked under some other name (usually "gmake"), in which # case it prints its new name instead of `make'. if test "`$am_make -s -f confmf 2> /dev/null | grep -v 'ing directory'`" = "done"; then am__include=include am__quote= _am_result=GNU fi # Now try BSD make style include. if test "$am__include" = "#"; then echo '.include "confinc"' > confmf if test "`$am_make -s -f confmf 2> /dev/null`" = "done"; then am__include=.include am__quote="\"" _am_result=BSD fi fi { echo "$as_me:$LINENO: result: $_am_result" >&5 echo "${ECHO_T}$_am_result" >&6; } rm -f confinc confmf # Check whether --enable-dependency-tracking was given. if test "${enable_dependency_tracking+set}" = set; then enableval=$enable_dependency_tracking; fi if test "x$enable_dependency_tracking" != xno; then am_depcomp="$ac_aux_dir/depcomp" AMDEPBACKSLASH='\' fi if test "x$enable_dependency_tracking" != xno; then AMDEP_TRUE= AMDEP_FALSE='#' else AMDEP_TRUE='#' AMDEP_FALSE= fi depcc="$CC" am_compiler_list= { echo "$as_me:$LINENO: checking dependency style of $depcc" >&5 echo $ECHO_N "checking dependency style of $depcc... $ECHO_C" >&6; } if test "${am_cv_CC_dependencies_compiler_type+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named `D' -- because `-MD' means `put the output # in D'. mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_CC_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` fi for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with # Solaris 8's {/usr,}/bin/sh. touch sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf case $depmode in nosideeffect) # after this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; none) break ;; esac # We check with `-c' and `-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle `-M -o', and we need to detect this. if depmode=$depmode \ source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_CC_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_CC_dependencies_compiler_type=none fi fi { echo "$as_me:$LINENO: result: $am_cv_CC_dependencies_compiler_type" >&5 echo "${ECHO_T}$am_cv_CC_dependencies_compiler_type" >&6; } CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type if test "x$enable_dependency_tracking" != xno \ && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then am__fastdepCC_TRUE= am__fastdepCC_FALSE='#' else am__fastdepCC_TRUE='#' am__fastdepCC_FALSE= fi # Suppress warnings about --datarootdir # If we have gcc, and AC_PROG_CC changed the flags, then we know the # user did not specify any flags. Add warnings in this case. if test "$GCC" = "yes"; then if test "$CFLAGS" != "$SAVE_CFLAGS"; then STD_CWARNINGS="$STD_CWARNINGS -Wall -Werror -fno-strict-aliasing" fi fi # POSIX doesn't include the IPv6 Advanced Socket API and glibc hides # parts of the IPv6 Advanced Socket API as a result. This is stupid # as it breaks how the two halves (Basic and Advanced) of the IPv6 # Socket API were designed to be used but we have to live with it. # Use this to define _GNU_SOURCE to pull in the IPv6 Advanced Socket API. cat >>confdefs.h <<\_ACEOF #define _GNU_SOURCE 1 _ACEOF ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { echo "$as_me:$LINENO: checking how to run the C preprocessor" >&5 echo $ECHO_N "checking how to run the C preprocessor... $ECHO_C" >&6; } # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then if test "${ac_cv_prog_CPP+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else # Double quotes because CPP needs to be expanded for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" do ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if { (ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err }; then : else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 # Broken: fails on valid input. continue fi rm -f conftest.err conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if { (ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err }; then # Broken: success on invalid input. continue else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.err conftest.$ac_ext if $ac_preproc_ok; then break fi done ac_cv_prog_CPP=$CPP fi CPP=$ac_cv_prog_CPP else ac_cv_prog_CPP=$CPP fi { echo "$as_me:$LINENO: result: $CPP" >&5 echo "${ECHO_T}$CPP" >&6; } ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if { (ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err }; then : else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 # Broken: fails on valid input. continue fi rm -f conftest.err conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if { (ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err }; then # Broken: success on invalid input. continue else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.err conftest.$ac_ext if $ac_preproc_ok; then : else { { echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check See \`config.log' for more details." >&5 echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { echo "$as_me:$LINENO: checking for grep that handles long lines and -e" >&5 echo $ECHO_N "checking for grep that handles long lines and -e... $ECHO_C" >&6; } if test "${ac_cv_path_GREP+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else # Extract the first word of "grep ggrep" to use in msg output if test -z "$GREP"; then set dummy grep ggrep; ac_prog_name=$2 if test "${ac_cv_path_GREP+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_path_GREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in grep ggrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue # Check for GNU ac_path_GREP and select it if it is found. # Check for GNU $ac_path_GREP case `"$ac_path_GREP" --version 2>&1` in *GNU*) ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; *) ac_count=0 echo $ECHO_N "0123456789$ECHO_C" >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" echo 'GREP' >> "conftest.nl" "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break ac_count=`expr $ac_count + 1` if test $ac_count -gt ${ac_path_GREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_GREP_found && break 3 done done done IFS=$as_save_IFS fi GREP="$ac_cv_path_GREP" if test -z "$GREP"; then { { echo "$as_me:$LINENO: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&5 echo "$as_me: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&2;} { (exit 1); exit 1; }; } fi else ac_cv_path_GREP=$GREP fi fi { echo "$as_me:$LINENO: result: $ac_cv_path_GREP" >&5 echo "${ECHO_T}$ac_cv_path_GREP" >&6; } GREP="$ac_cv_path_GREP" { echo "$as_me:$LINENO: checking for egrep" >&5 echo $ECHO_N "checking for egrep... $ECHO_C" >&6; } if test "${ac_cv_path_EGREP+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 then ac_cv_path_EGREP="$GREP -E" else # Extract the first word of "egrep" to use in msg output if test -z "$EGREP"; then set dummy egrep; ac_prog_name=$2 if test "${ac_cv_path_EGREP+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_path_EGREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in egrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue # Check for GNU ac_path_EGREP and select it if it is found. # Check for GNU $ac_path_EGREP case `"$ac_path_EGREP" --version 2>&1` in *GNU*) ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; *) ac_count=0 echo $ECHO_N "0123456789$ECHO_C" >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" echo 'EGREP' >> "conftest.nl" "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break ac_count=`expr $ac_count + 1` if test $ac_count -gt ${ac_path_EGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_EGREP_found && break 3 done done done IFS=$as_save_IFS fi EGREP="$ac_cv_path_EGREP" if test -z "$EGREP"; then { { echo "$as_me:$LINENO: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&5 echo "$as_me: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&2;} { (exit 1); exit 1; }; } fi else ac_cv_path_EGREP=$EGREP fi fi fi { echo "$as_me:$LINENO: result: $ac_cv_path_EGREP" >&5 echo "${ECHO_T}$ac_cv_path_EGREP" >&6; } EGREP="$ac_cv_path_EGREP" { echo "$as_me:$LINENO: checking for AIX" >&5 echo $ECHO_N "checking for AIX... $ECHO_C" >&6; } cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #ifdef _AIX yes #endif _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "yes" >/dev/null 2>&1; then { echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6; } cat >>confdefs.h <<\_ACEOF #define _ALL_SOURCE 1 _ACEOF else { echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6; } fi rm -f conftest* { echo "$as_me:$LINENO: checking for ANSI C header files" >&5 echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6; } if test "${ac_cv_header_stdc+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #include #include #include int main () { ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_cv_header_stdc=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_header_stdc=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "memchr" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "free" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. if test "$cross_compiling" = yes; then : else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #include #if ((' ' & 0x0FF) == 0x020) # define ISLOWER(c) ('a' <= (c) && (c) <= 'z') # define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #else # define ISLOWER(c) \ (('a' <= (c) && (c) <= 'i') \ || ('j' <= (c) && (c) <= 'r') \ || ('s' <= (c) && (c) <= 'z')) # define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) #endif #define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int main () { int i; for (i = 0; i < 256; i++) if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) return 2; return 0; } _ACEOF rm -f conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_link") 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='./conftest$ac_exeext' { (case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_try") 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then : else echo "$as_me: program exited with status $ac_status" >&5 echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ( exit $ac_status ) ac_cv_header_stdc=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext fi fi fi { echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5 echo "${ECHO_T}$ac_cv_header_stdc" >&6; } if test $ac_cv_header_stdc = yes; then cat >>confdefs.h <<\_ACEOF #define STDC_HEADERS 1 _ACEOF fi # On IRIX 5.3, sys/types and inttypes.h are conflicting. for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ inttypes.h stdint.h unistd.h do as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` { echo "$as_me:$LINENO: checking for $ac_header" >&5 echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default #include <$ac_header> _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then eval "$as_ac_Header=yes" else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 eval "$as_ac_Header=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi ac_res=`eval echo '${'$as_ac_Header'}'` { echo "$as_me:$LINENO: result: $ac_res" >&5 echo "${ECHO_T}$ac_res" >&6; } if test `eval echo '${'$as_ac_Header'}'` = yes; then cat >>confdefs.h <<_ACEOF #define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done if test "${ac_cv_header_minix_config_h+set}" = set; then { echo "$as_me:$LINENO: checking for minix/config.h" >&5 echo $ECHO_N "checking for minix/config.h... $ECHO_C" >&6; } if test "${ac_cv_header_minix_config_h+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 fi { echo "$as_me:$LINENO: result: $ac_cv_header_minix_config_h" >&5 echo "${ECHO_T}$ac_cv_header_minix_config_h" >&6; } else # Is the header compilable? { echo "$as_me:$LINENO: checking minix/config.h usability" >&5 echo $ECHO_N "checking minix/config.h usability... $ECHO_C" >&6; } cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default #include _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_header_compiler=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_compiler=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 echo "${ECHO_T}$ac_header_compiler" >&6; } # Is the header present? { echo "$as_me:$LINENO: checking minix/config.h presence" >&5 echo $ECHO_N "checking minix/config.h presence... $ECHO_C" >&6; } cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if { (ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err }; then ac_header_preproc=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_preproc=no fi rm -f conftest.err conftest.$ac_ext { echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 echo "${ECHO_T}$ac_header_preproc" >&6; } # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in yes:no: ) { echo "$as_me:$LINENO: WARNING: minix/config.h: accepted by the compiler, rejected by the preprocessor!" >&5 echo "$as_me: WARNING: minix/config.h: accepted by the compiler, rejected by the preprocessor!" >&2;} { echo "$as_me:$LINENO: WARNING: minix/config.h: proceeding with the compiler's result" >&5 echo "$as_me: WARNING: minix/config.h: proceeding with the compiler's result" >&2;} ac_header_preproc=yes ;; no:yes:* ) { echo "$as_me:$LINENO: WARNING: minix/config.h: present but cannot be compiled" >&5 echo "$as_me: WARNING: minix/config.h: present but cannot be compiled" >&2;} { echo "$as_me:$LINENO: WARNING: minix/config.h: check for missing prerequisite headers?" >&5 echo "$as_me: WARNING: minix/config.h: check for missing prerequisite headers?" >&2;} { echo "$as_me:$LINENO: WARNING: minix/config.h: see the Autoconf documentation" >&5 echo "$as_me: WARNING: minix/config.h: see the Autoconf documentation" >&2;} { echo "$as_me:$LINENO: WARNING: minix/config.h: section \"Present But Cannot Be Compiled\"" >&5 echo "$as_me: WARNING: minix/config.h: section \"Present But Cannot Be Compiled\"" >&2;} { echo "$as_me:$LINENO: WARNING: minix/config.h: proceeding with the preprocessor's result" >&5 echo "$as_me: WARNING: minix/config.h: proceeding with the preprocessor's result" >&2;} { echo "$as_me:$LINENO: WARNING: minix/config.h: in the future, the compiler will take precedence" >&5 echo "$as_me: WARNING: minix/config.h: in the future, the compiler will take precedence" >&2;} ( cat <<\_ASBOX ## --------------------------------- ## ## Report this to dhcp-users@isc.org ## ## --------------------------------- ## _ASBOX ) | sed "s/^/$as_me: WARNING: /" >&2 ;; esac { echo "$as_me:$LINENO: checking for minix/config.h" >&5 echo $ECHO_N "checking for minix/config.h... $ECHO_C" >&6; } if test "${ac_cv_header_minix_config_h+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_cv_header_minix_config_h=$ac_header_preproc fi { echo "$as_me:$LINENO: result: $ac_cv_header_minix_config_h" >&5 echo "${ECHO_T}$ac_cv_header_minix_config_h" >&6; } fi if test $ac_cv_header_minix_config_h = yes; then MINIX=yes else MINIX= fi if test "$MINIX" = yes; then cat >>confdefs.h <<\_ACEOF #define _POSIX_SOURCE 1 _ACEOF cat >>confdefs.h <<\_ACEOF #define _POSIX_1_SOURCE 2 _ACEOF cat >>confdefs.h <<\_ACEOF #define _MINIX 1 _ACEOF fi { echo "$as_me:$LINENO: checking whether it is safe to define __EXTENSIONS__" >&5 echo $ECHO_N "checking whether it is safe to define __EXTENSIONS__... $ECHO_C" >&6; } if test "${ac_cv_safe_to_define___extensions__+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ # define __EXTENSIONS__ 1 $ac_includes_default int main () { ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_cv_safe_to_define___extensions__=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_safe_to_define___extensions__=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { echo "$as_me:$LINENO: result: $ac_cv_safe_to_define___extensions__" >&5 echo "${ECHO_T}$ac_cv_safe_to_define___extensions__" >&6; } test $ac_cv_safe_to_define___extensions__ = yes && cat >>confdefs.h <<\_ACEOF #define __EXTENSIONS__ 1 _ACEOF cat >>confdefs.h <<\_ACEOF #define _POSIX_PTHREAD_SEMANTICS 1 _ACEOF cat >>confdefs.h <<\_ACEOF #define _TANDEM_SOURCE 1 _ACEOF if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. set dummy ${ac_tool_prefix}ranlib; ac_word=$2 { echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } if test "${ac_cv_prog_RANLIB+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$RANLIB"; then ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi RANLIB=$ac_cv_prog_RANLIB if test -n "$RANLIB"; then { echo "$as_me:$LINENO: result: $RANLIB" >&5 echo "${ECHO_T}$RANLIB" >&6; } else { echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6; } fi fi if test -z "$ac_cv_prog_RANLIB"; then ac_ct_RANLIB=$RANLIB # Extract the first word of "ranlib", so it can be a program name with args. set dummy ranlib; ac_word=$2 { echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$ac_ct_RANLIB"; then ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_RANLIB="ranlib" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB if test -n "$ac_ct_RANLIB"; then { echo "$as_me:$LINENO: result: $ac_ct_RANLIB" >&5 echo "${ECHO_T}$ac_ct_RANLIB" >&6; } else { echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6; } fi if test "x$ac_ct_RANLIB" = x; then RANLIB=":" else case $cross_compiling:$ac_tool_warned in yes:) { echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools whose name does not start with the host triplet. If you think this configuration is useful to you, please write to autoconf@gnu.org." >&5 echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools whose name does not start with the host triplet. If you think this configuration is useful to you, please write to autoconf@gnu.org." >&2;} ac_tool_warned=yes ;; esac RANLIB=$ac_ct_RANLIB fi else RANLIB="$ac_cv_prog_RANLIB" fi ac_config_headers="$ac_config_headers includes/config.h" # we sometimes need to know byte order for building packets { echo "$as_me:$LINENO: checking whether byte ordering is bigendian" >&5 echo $ECHO_N "checking whether byte ordering is bigendian... $ECHO_C" >&6; } if test "${ac_cv_c_bigendian+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else # See if sys/param.h defines the BYTE_ORDER macro. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #include int main () { #if ! (defined BYTE_ORDER && defined BIG_ENDIAN && defined LITTLE_ENDIAN \ && BYTE_ORDER && BIG_ENDIAN && LITTLE_ENDIAN) bogus endian macros #endif ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then # It does; now see whether it defined to BIG_ENDIAN or not. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #include int main () { #if BYTE_ORDER != BIG_ENDIAN not big endian #endif ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_cv_c_bigendian=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_c_bigendian=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 # It does not; compile a test program. if test "$cross_compiling" = yes; then # try to guess the endianness by grepping values into an object file ac_cv_c_bigendian=unknown cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ short int ascii_mm[] = { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 }; short int ascii_ii[] = { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 }; void _ascii () { char *s = (char *) ascii_mm; s = (char *) ascii_ii; } short int ebcdic_ii[] = { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 }; short int ebcdic_mm[] = { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 }; void _ebcdic () { char *s = (char *) ebcdic_mm; s = (char *) ebcdic_ii; } int main () { _ascii (); _ebcdic (); ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then if grep BIGenDianSyS conftest.$ac_objext >/dev/null ; then ac_cv_c_bigendian=yes fi if grep LiTTleEnDian conftest.$ac_objext >/dev/null ; then if test "$ac_cv_c_bigendian" = unknown; then ac_cv_c_bigendian=no else # finding both strings is unlikely to happen, but who knows? ac_cv_c_bigendian=unknown fi fi else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default int main () { /* Are we little or big endian? From Harbison&Steele. */ union { long int l; char c[sizeof (long int)]; } u; u.l = 1; return u.c[sizeof (long int) - 1] == 1; ; return 0; } _ACEOF rm -f conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_link") 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='./conftest$ac_exeext' { (case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_try") 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_c_bigendian=no else echo "$as_me: program exited with status $ac_status" >&5 echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ( exit $ac_status ) ac_cv_c_bigendian=yes fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext fi fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { echo "$as_me:$LINENO: result: $ac_cv_c_bigendian" >&5 echo "${ECHO_T}$ac_cv_c_bigendian" >&6; } case $ac_cv_c_bigendian in yes) byte_order=BIG_ENDIAN ;; no) byte_order=LITTLE_ENDIAN ;; *) { { echo "$as_me:$LINENO: error: unknown endianness presetting ac_cv_c_bigendian=no (or yes) will help" >&5 echo "$as_me: error: unknown endianness presetting ac_cv_c_bigendian=no (or yes) will help" >&2;} { (exit 1); exit 1; }; } ;; esac cat >>confdefs.h <<_ACEOF #define DHCP_BYTE_ORDER $byte_order _ACEOF # Optional compile-time DEBUGging. # Check whether --enable-debug was given. if test "${enable_debug+set}" = set; then enableval=$enable_debug; fi # This is very much off by default. if test "$enable_debug" = "yes" ; then cat >>confdefs.h <<\_ACEOF #define DEBUG 1 _ACEOF # Just override CFLAGS to totally to remove optimization. CFLAGS="-g" fi # XXX: there are actually quite a lot more DEBUG_ features we could enable, # but I don't want to pollute the --help space. # #/* #define DEBUG_TOKENS */ #/* #define DEBUG_PACKET */ #/* #define DEBUG_EXPRESSIONS */ #/* #define DEBUG_FIND_LEASE */ #/* #define DEBUG_EXPRESSION_PARSE */ #/* #define DEBUG_CLASS_MATCHING */ #/* #define DEBUG_MEMORY_LEAKAGE */ #/* #define DEBUG_MALLOC_POOL */ #/* #define DEBUG_LEASE_STATE_TRANSITIONS */ #/* #define DEBUG_RC_HISTORY */ #/* #define DEBUG_RC_HISTORY_EXHAUSTIVELY */ #/* #define RC_HISTORY_MAX 10240 */ #/* #define POINTER_DEBUG */ #/* #define DEBUG_FAILOVER_MESSAGES */ #/* #define DEBUG_FAILOVER_TIMING */ #/* #define DEBUG_DUMP_ALL_LEASES */ # Failover optional compile-time feature. # Check whether --enable-failover was given. if test "${enable_failover+set}" = set; then enableval=$enable_failover; fi # Failover is on by default, so define if it is not explicitly disabled. if test "$enable_failover" != "no"; then cat >>confdefs.h <<\_ACEOF #define FAILOVER_PROTOCOL 1 _ACEOF fi # execute() support. # Check whether --enable-execute was given. if test "${enable_execute+set}" = set; then enableval=$enable_execute; fi # execute() is on by default, so define if it is not explicitly disabled. if test "$enable_execute" != "no" ; then cat >>confdefs.h <<\_ACEOF #define ENABLE_EXECUTE 1 _ACEOF fi # Server tracing support. # Check whether --enable-tracing was given. if test "${enable_tracing+set}" = set; then enableval=$enable_tracing; fi # tracing is on by default, so define if it is not explicitly disabled. if test "$enable_tracing" != "no" ; then cat >>confdefs.h <<\_ACEOF #define TRACING 1 _ACEOF fi # Delayed-ack feature support (experimental). # Check whether --enable-delayed_ack was given. if test "${enable_delayed_ack+set}" = set; then enableval=$enable_delayed_ack; fi if test "$enable_delayed_ack" = "yes"; then cat >>confdefs.h <<\_ACEOF #define DELAYED_ACK 1 _ACEOF fi # DHCPv6 optional compile-time feature. # Check whether --enable-dhcpv6 was given. if test "${enable_dhcpv6+set}" = set; then enableval=$enable_dhcpv6; fi # DHCPv6 is on by default, so define if it is not explicitly disabled. if test "$enable_dhcpv6" != "no"; then cat >>confdefs.h <<\_ACEOF #define DHCPv6 1 _ACEOF fi # PARANOIA is off by default (until we can test it with all features) # Check whether --enable-paranoia was given. if test "${enable_paranoia+set}" = set; then enableval=$enable_paranoia; fi # Check whether --enable-early_chroot was given. if test "${enable_early_chroot+set}" = set; then enableval=$enable_early_chroot; fi # If someone enables early chroot, but does not enable paranoia, do so for # them. if test "$enable_paranoia" != "yes" && \ test "$enable_early_chroot" = "yes" ; then enable_paranoia="yes" fi if test "$enable_paranoia" = "yes" ; then cat >>confdefs.h <<\_ACEOF #define PARANOIA 1 _ACEOF fi if test "$enable_early_chroot" = "yes" ; then cat >>confdefs.h <<\_ACEOF #define EARLY_CHROOT 1 _ACEOF fi # Check whether --enable-ipv4_pktinfo was given. if test "${enable_ipv4_pktinfo+set}" = set; then enableval=$enable_ipv4_pktinfo; fi if test "$enable_ipv4_pktinfo" = "yes"; then cat >>confdefs.h <<\_ACEOF #define USE_V4_PKTINFO 1 _ACEOF fi # Check whether --enable-use_sockets was given. if test "${enable_use_sockets+set}" = set; then enableval=$enable_use_sockets; fi if test "$enable_use_sockets" = "yes"; then cat >>confdefs.h <<\_ACEOF #define USE_SOCKETS 1 _ACEOF fi ### ### Path fun. Older versions of DHCP were installed in /usr/sbin, so we ### need to look there and potentially overwrite by default (but not if ### the user configures an alternate value). LOCALSTATEDIR is totally ### braindead. No one uses /usr/local/var/db/ nor /usr/local/var/run, and ### they would be insane for suggesting it. We need to look in /var/for ### 'db' and 'state/dhcp' for db files, and /var/run for pid files by ### default. ### if test "x$prefix" = xNONE; then echo $ECHO_N "checking for prefix by $ECHO_C" >&6 # Extract the first word of "dhcpd", so it can be a program name with args. set dummy dhcpd; ac_word=$2 { echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } if test "${ac_cv_path_ac_prefix_program+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else case $ac_prefix_program in [\\/]* | ?:[\\/]*) ac_cv_path_ac_prefix_program="$ac_prefix_program" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_path_ac_prefix_program="$as_dir/$ac_word$ac_exec_ext" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi ac_prefix_program=$ac_cv_path_ac_prefix_program if test -n "$ac_prefix_program"; then { echo "$as_me:$LINENO: result: $ac_prefix_program" >&5 echo "${ECHO_T}$ac_prefix_program" >&6; } else { echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6; } fi if test -n "$ac_prefix_program"; then prefix=`$as_dirname -- "$ac_prefix_program" || $as_expr X"$ac_prefix_program" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_prefix_program" : 'X\(//\)[^/]' \| \ X"$ac_prefix_program" : 'X\(//\)$' \| \ X"$ac_prefix_program" : 'X\(/\)' \| . 2>/dev/null || echo X"$ac_prefix_program" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` prefix=`$as_dirname -- "$prefix" || $as_expr X"$prefix" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$prefix" : 'X\(//\)[^/]' \| \ X"$prefix" : 'X\(//\)$' \| \ X"$prefix" : 'X\(/\)' \| . 2>/dev/null || echo X"$prefix" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` fi fi # XXX - isn't there SOME WAY to default autoconf to /var instead of # /usr/local/var/no/one/has/this/please/stop/trying? case "$localstatedir" in '${prefix}/var') localstatedir=/var ;; esac # Allow specification of alternate state files # Check whether --with-srv-lease-file was given. if test "${with_srv_lease_file+set}" = set; then withval=$with_srv_lease_file; cat >>confdefs.h <<_ACEOF #define _PATH_DHCPD_DB "$withval" _ACEOF fi echo -n "checking for dhcpd.leases location..." if [ "x$with_srv_lease_file" = "x" ] ; then if [ -d "${localstatedir}/db" ] ; then with_srv_lease_file="${localstatedir}/db/dhcpd.leases" elif [ -d "${localstatedir}/state" ] ; then if [ -d "${localstatedir}/state/dhcp" ] ; then with_srv_lease_file="${localstatedir}/state/dhcp/dhcpd.leases" else with_srv_lease_file="${localstatedir}/state/dhcpd.leases" fi elif [ -d "${localstatedir}/lib" ] ; then if [ -d "${localstatedir}/lib/dhcp" ] ; then with_srv_lease_file="${localstatedir}/lib/dhcp/dhcpd.leases" else with_srv_lease_file="${localstatedir}/lib/dhcpd.leases" fi elif [ -d "${localstatedir}/etc" ] ; then with_srv_lease_file="${localstatedir}/etc/dhcpd.leases" else with_srv_lease_file="/etc/dhcpd.leases" fi fi echo "$with_srv_lease_file" # Check whether --with-srv6-lease-file was given. if test "${with_srv6_lease_file+set}" = set; then withval=$with_srv6_lease_file; cat >>confdefs.h <<_ACEOF #define _PATH_DHCPD6_DB "$withval" _ACEOF fi echo -n "checking for dhcpd6.leases location..." if [ "x$with_srv6_lease_file" = "x" ] ; then if [ -d "${localstatedir}/db" ] ; then with_srv6_lease_file="${localstatedir}/db/dhcpd6.leases" elif [ -d "${localstatedir}/state" ] ; then if [ -d "${localstatedir}/state/dhcp" ] ; then with_srv6_lease_file="${localstatedir}/state/dhcp/dhcpd6.leases" else with_srv6_lease_file="${localstatedir}/state/dhcpd6.leases" fi elif [ -d "${localstatedir}/lib" ] ; then if [ -d "${localstatedir}/lib/dhcp" ] ; then with_srv6_lease_file="${localstatedir}/lib/dhcp/dhcpd6.leases" else with_srv6_lease_file="${localstatedir}/lib/dhcpd6.leases" fi elif [ -d "${localstatedir}/etc" ] ; then with_srv6_lease_file="${localstatedir}/etc/dhcpd6.leases" else with_srv6_lease_file="/etc/dhcpd6.leases" fi fi echo "$with_srv6_lease_file" # Check whether --with-cli-lease-file was given. if test "${with_cli_lease_file+set}" = set; then withval=$with_cli_lease_file; cat >>confdefs.h <<_ACEOF #define _PATH_DHCLIENT_DB "$withval" _ACEOF fi echo -n "checking for dhclient.leases location..." if [ "x$with_cli_lease_file" = "x" ] ; then if [ -d "${localstatedir}/db" ] ; then with_cli_lease_file="${localstatedir}/db/dhclient.leases" elif [ -d "${localstatedir}/state" ] ; then if [ -d "${localstatedir}/state/dhcp" ] ; then with_cli_lease_file="${localstatedir}/state/dhcp/dhclient.leases" else with_cli_lease_file="${localstatedir}/state/dhclient.leases" fi elif [ -d "${localstatedir}/lib" ] ; then if [ -d "${localstatedir}/lib/dhcp" ] ; then with_cli_lease_file="${localstatedir}/lib/dhcp/dhclient.leases" else with_cli_lease_file="${localstatedir}/lib/dhclient.leases" fi elif [ -d "${localstatedir}/etc" ] ; then with_cli_lease_file="${localstatedir}/etc/dhclient.leases" else with_cli_lease_file="/etc/dhclient.leases" fi fi echo "$with_cli_lease_file" # Check whether --with-cli6-lease-file was given. if test "${with_cli6_lease_file+set}" = set; then withval=$with_cli6_lease_file; cat >>confdefs.h <<_ACEOF #define _PATH_DHCLIENT6_DB "$withval" _ACEOF fi echo -n "checking for dhclient6.leases location..." if [ "x$with_cli6_lease_file" = "x" ] ; then if [ -d "${localstatedir}/db" ] ; then with_cli6_lease_file="${localstatedir}/db/dhclient6.leases" elif [ -d "${localstatedir}/state" ] ; then if [ -d "${localstatedir}/state/dhcp" ] ; then with_cli6_lease_file="${localstatedir}/state/dhcp/dhclient6.leases" else with_cli6_lease_file="${localstatedir}/state/dhclient6.leases" fi elif [ -d "${localstatedir}/lib" ] ; then if [ -d "${localstatedir}/lib/dhcp" ] ; then with_cli6_lease_file="${localstatedir}/lib/dhcp/dhclient6.leases" else with_cli6_lease_file="${localstatedir}/lib/dhclient6.leases" fi elif [ -d "${localstatedir}/etc" ] ; then with_cli6_lease_file="${localstatedir}/etc/dhclient6.leases" else with_cli6_lease_file="/etc/dhclient6.leases" fi fi echo "$with_cli6_lease_file" # Check whether --with-srv-pid-file was given. if test "${with_srv_pid_file+set}" = set; then withval=$with_srv_pid_file; cat >>confdefs.h <<_ACEOF #define _PATH_DHCPD_PID "$withval" _ACEOF fi # Check whether --with-srv6-pid-file was given. if test "${with_srv6_pid_file+set}" = set; then withval=$with_srv6_pid_file; cat >>confdefs.h <<_ACEOF #define _PATH_DHCPD6_PID "$withval" _ACEOF fi # Check whether --with-cli-pid-file was given. if test "${with_cli_pid_file+set}" = set; then withval=$with_cli_pid_file; cat >>confdefs.h <<_ACEOF #define _PATH_DHCLIENT_PID "$withval" _ACEOF fi # Check whether --with-cli6-pid-file was given. if test "${with_cli6_pid_file+set}" = set; then withval=$with_cli6_pid_file; cat >>confdefs.h <<_ACEOF #define _PATH_DHCLIENT6_PID "$withval" _ACEOF fi # Check whether --with-relay-pid-file was given. if test "${with_relay_pid_file+set}" = set; then withval=$with_relay_pid_file; cat >>confdefs.h <<_ACEOF #define _PATH_DHCRELAY_PID "$withval" _ACEOF fi # Check whether --with-relay6-pid-file was given. if test "${with_relay6_pid_file+set}" = set; then withval=$with_relay6_pid_file; cat >>confdefs.h <<_ACEOF #define _PATH_DHCRELAY6_PID "$withval" _ACEOF fi # Check basic types. { echo "$as_me:$LINENO: checking for int8_t" >&5 echo $ECHO_N "checking for int8_t... $ECHO_C" >&6; } if test "${ac_cv_c_int8_t+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_cv_c_int8_t=no for ac_type in 'int8_t' 'int' 'long int' \ 'long long int' 'short int' 'signed char'; do cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default int main () { static int test_array [1 - 2 * !(0 < ($ac_type) (((($ac_type) 1 << (8 - 2)) - 1) * 2 + 1))]; test_array [0] = 0 ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default int main () { static int test_array [1 - 2 * !(($ac_type) (((($ac_type) 1 << (8 - 2)) - 1) * 2 + 1) < ($ac_type) (((($ac_type) 1 << (8 - 2)) - 1) * 2 + 2))]; test_array [0] = 0 ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 case $ac_type in int8_t) ac_cv_c_int8_t=yes ;; *) ac_cv_c_int8_t=$ac_type ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext test "$ac_cv_c_int8_t" != no && break done fi { echo "$as_me:$LINENO: result: $ac_cv_c_int8_t" >&5 echo "${ECHO_T}$ac_cv_c_int8_t" >&6; } case $ac_cv_c_int8_t in #( no|yes) ;; #( *) cat >>confdefs.h <<_ACEOF #define int8_t $ac_cv_c_int8_t _ACEOF ;; esac { echo "$as_me:$LINENO: checking for int16_t" >&5 echo $ECHO_N "checking for int16_t... $ECHO_C" >&6; } if test "${ac_cv_c_int16_t+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_cv_c_int16_t=no for ac_type in 'int16_t' 'int' 'long int' \ 'long long int' 'short int' 'signed char'; do cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default int main () { static int test_array [1 - 2 * !(0 < ($ac_type) (((($ac_type) 1 << (16 - 2)) - 1) * 2 + 1))]; test_array [0] = 0 ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default int main () { static int test_array [1 - 2 * !(($ac_type) (((($ac_type) 1 << (16 - 2)) - 1) * 2 + 1) < ($ac_type) (((($ac_type) 1 << (16 - 2)) - 1) * 2 + 2))]; test_array [0] = 0 ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 case $ac_type in int16_t) ac_cv_c_int16_t=yes ;; *) ac_cv_c_int16_t=$ac_type ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext test "$ac_cv_c_int16_t" != no && break done fi { echo "$as_me:$LINENO: result: $ac_cv_c_int16_t" >&5 echo "${ECHO_T}$ac_cv_c_int16_t" >&6; } case $ac_cv_c_int16_t in #( no|yes) ;; #( *) cat >>confdefs.h <<_ACEOF #define int16_t $ac_cv_c_int16_t _ACEOF ;; esac { echo "$as_me:$LINENO: checking for int32_t" >&5 echo $ECHO_N "checking for int32_t... $ECHO_C" >&6; } if test "${ac_cv_c_int32_t+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_cv_c_int32_t=no for ac_type in 'int32_t' 'int' 'long int' \ 'long long int' 'short int' 'signed char'; do cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default int main () { static int test_array [1 - 2 * !(0 < ($ac_type) (((($ac_type) 1 << (32 - 2)) - 1) * 2 + 1))]; test_array [0] = 0 ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default int main () { static int test_array [1 - 2 * !(($ac_type) (((($ac_type) 1 << (32 - 2)) - 1) * 2 + 1) < ($ac_type) (((($ac_type) 1 << (32 - 2)) - 1) * 2 + 2))]; test_array [0] = 0 ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 case $ac_type in int32_t) ac_cv_c_int32_t=yes ;; *) ac_cv_c_int32_t=$ac_type ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext test "$ac_cv_c_int32_t" != no && break done fi { echo "$as_me:$LINENO: result: $ac_cv_c_int32_t" >&5 echo "${ECHO_T}$ac_cv_c_int32_t" >&6; } case $ac_cv_c_int32_t in #( no|yes) ;; #( *) cat >>confdefs.h <<_ACEOF #define int32_t $ac_cv_c_int32_t _ACEOF ;; esac { echo "$as_me:$LINENO: checking for int64_t" >&5 echo $ECHO_N "checking for int64_t... $ECHO_C" >&6; } if test "${ac_cv_c_int64_t+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_cv_c_int64_t=no for ac_type in 'int64_t' 'int' 'long int' \ 'long long int' 'short int' 'signed char'; do cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default int main () { static int test_array [1 - 2 * !(0 < ($ac_type) (((($ac_type) 1 << (64 - 2)) - 1) * 2 + 1))]; test_array [0] = 0 ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default int main () { static int test_array [1 - 2 * !(($ac_type) (((($ac_type) 1 << (64 - 2)) - 1) * 2 + 1) < ($ac_type) (((($ac_type) 1 << (64 - 2)) - 1) * 2 + 2))]; test_array [0] = 0 ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 case $ac_type in int64_t) ac_cv_c_int64_t=yes ;; *) ac_cv_c_int64_t=$ac_type ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext test "$ac_cv_c_int64_t" != no && break done fi { echo "$as_me:$LINENO: result: $ac_cv_c_int64_t" >&5 echo "${ECHO_T}$ac_cv_c_int64_t" >&6; } case $ac_cv_c_int64_t in #( no|yes) ;; #( *) cat >>confdefs.h <<_ACEOF #define int64_t $ac_cv_c_int64_t _ACEOF ;; esac # Some systems need the u_intX_t types defined across. { echo "$as_me:$LINENO: checking for u_int8_t" >&5 echo $ECHO_N "checking for u_int8_t... $ECHO_C" >&6; } if test "${ac_cv_type_u_int8_t+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default typedef u_int8_t ac__type_new_; int main () { if ((ac__type_new_ *) 0) return 0; if (sizeof (ac__type_new_)) return 0; ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_cv_type_u_int8_t=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_type_u_int8_t=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { echo "$as_me:$LINENO: result: $ac_cv_type_u_int8_t" >&5 echo "${ECHO_T}$ac_cv_type_u_int8_t" >&6; } if test $ac_cv_type_u_int8_t = yes; then : else { echo "$as_me:$LINENO: checking for uint8_t" >&5 echo $ECHO_N "checking for uint8_t... $ECHO_C" >&6; } if test "${ac_cv_c_uint8_t+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_cv_c_uint8_t=no for ac_type in 'uint8_t' 'unsigned int' 'unsigned long int' \ 'unsigned long long int' 'unsigned short int' 'unsigned char'; do cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default int main () { static int test_array [1 - 2 * !(($ac_type) -1 >> (8 - 1) == 1)]; test_array [0] = 0 ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then case $ac_type in uint8_t) ac_cv_c_uint8_t=yes ;; *) ac_cv_c_uint8_t=$ac_type ;; esac else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext test "$ac_cv_c_uint8_t" != no && break done fi { echo "$as_me:$LINENO: result: $ac_cv_c_uint8_t" >&5 echo "${ECHO_T}$ac_cv_c_uint8_t" >&6; } case $ac_cv_c_uint8_t in #( no|yes) ;; #( *) cat >>confdefs.h <<\_ACEOF #define _UINT8_T 1 _ACEOF cat >>confdefs.h <<_ACEOF #define uint8_t $ac_cv_c_uint8_t _ACEOF ;; esac cat >>confdefs.h <<\_ACEOF #define u_int8_t uint8_t _ACEOF fi { echo "$as_me:$LINENO: checking for u_int16_t" >&5 echo $ECHO_N "checking for u_int16_t... $ECHO_C" >&6; } if test "${ac_cv_type_u_int16_t+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default typedef u_int16_t ac__type_new_; int main () { if ((ac__type_new_ *) 0) return 0; if (sizeof (ac__type_new_)) return 0; ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_cv_type_u_int16_t=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_type_u_int16_t=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { echo "$as_me:$LINENO: result: $ac_cv_type_u_int16_t" >&5 echo "${ECHO_T}$ac_cv_type_u_int16_t" >&6; } if test $ac_cv_type_u_int16_t = yes; then : else { echo "$as_me:$LINENO: checking for uint16_t" >&5 echo $ECHO_N "checking for uint16_t... $ECHO_C" >&6; } if test "${ac_cv_c_uint16_t+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_cv_c_uint16_t=no for ac_type in 'uint16_t' 'unsigned int' 'unsigned long int' \ 'unsigned long long int' 'unsigned short int' 'unsigned char'; do cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default int main () { static int test_array [1 - 2 * !(($ac_type) -1 >> (16 - 1) == 1)]; test_array [0] = 0 ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then case $ac_type in uint16_t) ac_cv_c_uint16_t=yes ;; *) ac_cv_c_uint16_t=$ac_type ;; esac else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext test "$ac_cv_c_uint16_t" != no && break done fi { echo "$as_me:$LINENO: result: $ac_cv_c_uint16_t" >&5 echo "${ECHO_T}$ac_cv_c_uint16_t" >&6; } case $ac_cv_c_uint16_t in #( no|yes) ;; #( *) cat >>confdefs.h <<_ACEOF #define uint16_t $ac_cv_c_uint16_t _ACEOF ;; esac cat >>confdefs.h <<\_ACEOF #define u_int16_t uint16_t _ACEOF fi { echo "$as_me:$LINENO: checking for u_int32_t" >&5 echo $ECHO_N "checking for u_int32_t... $ECHO_C" >&6; } if test "${ac_cv_type_u_int32_t+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default typedef u_int32_t ac__type_new_; int main () { if ((ac__type_new_ *) 0) return 0; if (sizeof (ac__type_new_)) return 0; ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_cv_type_u_int32_t=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_type_u_int32_t=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { echo "$as_me:$LINENO: result: $ac_cv_type_u_int32_t" >&5 echo "${ECHO_T}$ac_cv_type_u_int32_t" >&6; } if test $ac_cv_type_u_int32_t = yes; then : else { echo "$as_me:$LINENO: checking for uint32_t" >&5 echo $ECHO_N "checking for uint32_t... $ECHO_C" >&6; } if test "${ac_cv_c_uint32_t+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_cv_c_uint32_t=no for ac_type in 'uint32_t' 'unsigned int' 'unsigned long int' \ 'unsigned long long int' 'unsigned short int' 'unsigned char'; do cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default int main () { static int test_array [1 - 2 * !(($ac_type) -1 >> (32 - 1) == 1)]; test_array [0] = 0 ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then case $ac_type in uint32_t) ac_cv_c_uint32_t=yes ;; *) ac_cv_c_uint32_t=$ac_type ;; esac else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext test "$ac_cv_c_uint32_t" != no && break done fi { echo "$as_me:$LINENO: result: $ac_cv_c_uint32_t" >&5 echo "${ECHO_T}$ac_cv_c_uint32_t" >&6; } case $ac_cv_c_uint32_t in #( no|yes) ;; #( *) cat >>confdefs.h <<\_ACEOF #define _UINT32_T 1 _ACEOF cat >>confdefs.h <<_ACEOF #define uint32_t $ac_cv_c_uint32_t _ACEOF ;; esac cat >>confdefs.h <<\_ACEOF #define u_int32_t uint32_t _ACEOF fi { echo "$as_me:$LINENO: checking for u_int64_t" >&5 echo $ECHO_N "checking for u_int64_t... $ECHO_C" >&6; } if test "${ac_cv_type_u_int64_t+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default typedef u_int64_t ac__type_new_; int main () { if ((ac__type_new_ *) 0) return 0; if (sizeof (ac__type_new_)) return 0; ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_cv_type_u_int64_t=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_type_u_int64_t=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { echo "$as_me:$LINENO: result: $ac_cv_type_u_int64_t" >&5 echo "${ECHO_T}$ac_cv_type_u_int64_t" >&6; } if test $ac_cv_type_u_int64_t = yes; then : else { echo "$as_me:$LINENO: checking for uint64_t" >&5 echo $ECHO_N "checking for uint64_t... $ECHO_C" >&6; } if test "${ac_cv_c_uint64_t+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_cv_c_uint64_t=no for ac_type in 'uint64_t' 'unsigned int' 'unsigned long int' \ 'unsigned long long int' 'unsigned short int' 'unsigned char'; do cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default int main () { static int test_array [1 - 2 * !(($ac_type) -1 >> (64 - 1) == 1)]; test_array [0] = 0 ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then case $ac_type in uint64_t) ac_cv_c_uint64_t=yes ;; *) ac_cv_c_uint64_t=$ac_type ;; esac else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext test "$ac_cv_c_uint64_t" != no && break done fi { echo "$as_me:$LINENO: result: $ac_cv_c_uint64_t" >&5 echo "${ECHO_T}$ac_cv_c_uint64_t" >&6; } case $ac_cv_c_uint64_t in #( no|yes) ;; #( *) cat >>confdefs.h <<\_ACEOF #define _UINT64_T 1 _ACEOF cat >>confdefs.h <<_ACEOF #define uint64_t $ac_cv_c_uint64_t _ACEOF ;; esac cat >>confdefs.h <<\_ACEOF #define u_int64_t uint64_t _ACEOF fi # see if ifaddrs.h is available for ac_header in ifaddrs.h do as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then { echo "$as_me:$LINENO: checking for $ac_header" >&5 echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then echo $ECHO_N "(cached) $ECHO_C" >&6 fi ac_res=`eval echo '${'$as_ac_Header'}'` { echo "$as_me:$LINENO: result: $ac_res" >&5 echo "${ECHO_T}$ac_res" >&6; } else # Is the header compilable? { echo "$as_me:$LINENO: checking $ac_header usability" >&5 echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6; } cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default #include <$ac_header> _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_header_compiler=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_compiler=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 echo "${ECHO_T}$ac_header_compiler" >&6; } # Is the header present? { echo "$as_me:$LINENO: checking $ac_header presence" >&5 echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6; } cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include <$ac_header> _ACEOF if { (ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err }; then ac_header_preproc=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_preproc=no fi rm -f conftest.err conftest.$ac_ext { echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 echo "${ECHO_T}$ac_header_preproc" >&6; } # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in yes:no: ) { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} ac_header_preproc=yes ;; no:yes:* ) { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} ( cat <<\_ASBOX ## --------------------------------- ## ## Report this to dhcp-users@isc.org ## ## --------------------------------- ## _ASBOX ) | sed "s/^/$as_me: WARNING: /" >&2 ;; esac { echo "$as_me:$LINENO: checking for $ac_header" >&5 echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then echo $ECHO_N "(cached) $ECHO_C" >&6 else eval "$as_ac_Header=\$ac_header_preproc" fi ac_res=`eval echo '${'$as_ac_Header'}'` { echo "$as_me:$LINENO: result: $ac_res" >&5 echo "${ECHO_T}$ac_res" >&6; } fi if test `eval echo '${'$as_ac_Header'}'` = yes; then cat >>confdefs.h <<_ACEOF #define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done # figure out what IPv4 interface code to use for ac_header in linux/types.h do as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then { echo "$as_me:$LINENO: checking for $ac_header" >&5 echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then echo $ECHO_N "(cached) $ECHO_C" >&6 fi ac_res=`eval echo '${'$as_ac_Header'}'` { echo "$as_me:$LINENO: result: $ac_res" >&5 echo "${ECHO_T}$ac_res" >&6; } else # Is the header compilable? { echo "$as_me:$LINENO: checking $ac_header usability" >&5 echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6; } cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default #include <$ac_header> _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_header_compiler=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_compiler=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 echo "${ECHO_T}$ac_header_compiler" >&6; } # Is the header present? { echo "$as_me:$LINENO: checking $ac_header presence" >&5 echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6; } cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include <$ac_header> _ACEOF if { (ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err }; then ac_header_preproc=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_preproc=no fi rm -f conftest.err conftest.$ac_ext { echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 echo "${ECHO_T}$ac_header_preproc" >&6; } # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in yes:no: ) { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} ac_header_preproc=yes ;; no:yes:* ) { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} ( cat <<\_ASBOX ## --------------------------------- ## ## Report this to dhcp-users@isc.org ## ## --------------------------------- ## _ASBOX ) | sed "s/^/$as_me: WARNING: /" >&2 ;; esac { echo "$as_me:$LINENO: checking for $ac_header" >&5 echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then echo $ECHO_N "(cached) $ECHO_C" >&6 else eval "$as_ac_Header=\$ac_header_preproc" fi ac_res=`eval echo '${'$as_ac_Header'}'` { echo "$as_me:$LINENO: result: $ac_res" >&5 echo "${ECHO_T}$ac_res" >&6; } fi if test `eval echo '${'$as_ac_Header'}'` = yes; then cat >>confdefs.h <<_ACEOF #define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done # needed for linux/filter.h on old systems { echo "$as_me:$LINENO: checking for linux/filter.h" >&5 echo $ECHO_N "checking for linux/filter.h... $ECHO_C" >&6; } if test "${ac_cv_header_linux_filter_h+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #ifdef HAVE_LINUX_TYPES_H #include #endif #include _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_cv_header_linux_filter_h=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_header_linux_filter_h=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { echo "$as_me:$LINENO: result: $ac_cv_header_linux_filter_h" >&5 echo "${ECHO_T}$ac_cv_header_linux_filter_h" >&6; } if test $ac_cv_header_linux_filter_h = yes; then DO_LPF=1 fi if test -n "$DO_LPF" then cat >>confdefs.h <<\_ACEOF #define HAVE_LPF 1 _ACEOF else if test "${ac_cv_header_sys_dlpi_h+set}" = set; then { echo "$as_me:$LINENO: checking for sys/dlpi.h" >&5 echo $ECHO_N "checking for sys/dlpi.h... $ECHO_C" >&6; } if test "${ac_cv_header_sys_dlpi_h+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 fi { echo "$as_me:$LINENO: result: $ac_cv_header_sys_dlpi_h" >&5 echo "${ECHO_T}$ac_cv_header_sys_dlpi_h" >&6; } else # Is the header compilable? { echo "$as_me:$LINENO: checking sys/dlpi.h usability" >&5 echo $ECHO_N "checking sys/dlpi.h usability... $ECHO_C" >&6; } cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default #include _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_header_compiler=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_compiler=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 echo "${ECHO_T}$ac_header_compiler" >&6; } # Is the header present? { echo "$as_me:$LINENO: checking sys/dlpi.h presence" >&5 echo $ECHO_N "checking sys/dlpi.h presence... $ECHO_C" >&6; } cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if { (ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err }; then ac_header_preproc=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_preproc=no fi rm -f conftest.err conftest.$ac_ext { echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 echo "${ECHO_T}$ac_header_preproc" >&6; } # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in yes:no: ) { echo "$as_me:$LINENO: WARNING: sys/dlpi.h: accepted by the compiler, rejected by the preprocessor!" >&5 echo "$as_me: WARNING: sys/dlpi.h: accepted by the compiler, rejected by the preprocessor!" >&2;} { echo "$as_me:$LINENO: WARNING: sys/dlpi.h: proceeding with the compiler's result" >&5 echo "$as_me: WARNING: sys/dlpi.h: proceeding with the compiler's result" >&2;} ac_header_preproc=yes ;; no:yes:* ) { echo "$as_me:$LINENO: WARNING: sys/dlpi.h: present but cannot be compiled" >&5 echo "$as_me: WARNING: sys/dlpi.h: present but cannot be compiled" >&2;} { echo "$as_me:$LINENO: WARNING: sys/dlpi.h: check for missing prerequisite headers?" >&5 echo "$as_me: WARNING: sys/dlpi.h: check for missing prerequisite headers?" >&2;} { echo "$as_me:$LINENO: WARNING: sys/dlpi.h: see the Autoconf documentation" >&5 echo "$as_me: WARNING: sys/dlpi.h: see the Autoconf documentation" >&2;} { echo "$as_me:$LINENO: WARNING: sys/dlpi.h: section \"Present But Cannot Be Compiled\"" >&5 echo "$as_me: WARNING: sys/dlpi.h: section \"Present But Cannot Be Compiled\"" >&2;} { echo "$as_me:$LINENO: WARNING: sys/dlpi.h: proceeding with the preprocessor's result" >&5 echo "$as_me: WARNING: sys/dlpi.h: proceeding with the preprocessor's result" >&2;} { echo "$as_me:$LINENO: WARNING: sys/dlpi.h: in the future, the compiler will take precedence" >&5 echo "$as_me: WARNING: sys/dlpi.h: in the future, the compiler will take precedence" >&2;} ( cat <<\_ASBOX ## --------------------------------- ## ## Report this to dhcp-users@isc.org ## ## --------------------------------- ## _ASBOX ) | sed "s/^/$as_me: WARNING: /" >&2 ;; esac { echo "$as_me:$LINENO: checking for sys/dlpi.h" >&5 echo $ECHO_N "checking for sys/dlpi.h... $ECHO_C" >&6; } if test "${ac_cv_header_sys_dlpi_h+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_cv_header_sys_dlpi_h=$ac_header_preproc fi { echo "$as_me:$LINENO: result: $ac_cv_header_sys_dlpi_h" >&5 echo "${ECHO_T}$ac_cv_header_sys_dlpi_h" >&6; } fi if test $ac_cv_header_sys_dlpi_h = yes; then DO_DLPI=1 fi if test -n "$DO_DLPI" then cat >>confdefs.h <<\_ACEOF #define HAVE_DLPI 1 _ACEOF else if test "${ac_cv_header_net_bpf_h+set}" = set; then { echo "$as_me:$LINENO: checking for net/bpf.h" >&5 echo $ECHO_N "checking for net/bpf.h... $ECHO_C" >&6; } if test "${ac_cv_header_net_bpf_h+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 fi { echo "$as_me:$LINENO: result: $ac_cv_header_net_bpf_h" >&5 echo "${ECHO_T}$ac_cv_header_net_bpf_h" >&6; } else # Is the header compilable? { echo "$as_me:$LINENO: checking net/bpf.h usability" >&5 echo $ECHO_N "checking net/bpf.h usability... $ECHO_C" >&6; } cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default #include _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_header_compiler=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_compiler=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 echo "${ECHO_T}$ac_header_compiler" >&6; } # Is the header present? { echo "$as_me:$LINENO: checking net/bpf.h presence" >&5 echo $ECHO_N "checking net/bpf.h presence... $ECHO_C" >&6; } cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if { (ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err }; then ac_header_preproc=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_preproc=no fi rm -f conftest.err conftest.$ac_ext { echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 echo "${ECHO_T}$ac_header_preproc" >&6; } # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in yes:no: ) { echo "$as_me:$LINENO: WARNING: net/bpf.h: accepted by the compiler, rejected by the preprocessor!" >&5 echo "$as_me: WARNING: net/bpf.h: accepted by the compiler, rejected by the preprocessor!" >&2;} { echo "$as_me:$LINENO: WARNING: net/bpf.h: proceeding with the compiler's result" >&5 echo "$as_me: WARNING: net/bpf.h: proceeding with the compiler's result" >&2;} ac_header_preproc=yes ;; no:yes:* ) { echo "$as_me:$LINENO: WARNING: net/bpf.h: present but cannot be compiled" >&5 echo "$as_me: WARNING: net/bpf.h: present but cannot be compiled" >&2;} { echo "$as_me:$LINENO: WARNING: net/bpf.h: check for missing prerequisite headers?" >&5 echo "$as_me: WARNING: net/bpf.h: check for missing prerequisite headers?" >&2;} { echo "$as_me:$LINENO: WARNING: net/bpf.h: see the Autoconf documentation" >&5 echo "$as_me: WARNING: net/bpf.h: see the Autoconf documentation" >&2;} { echo "$as_me:$LINENO: WARNING: net/bpf.h: section \"Present But Cannot Be Compiled\"" >&5 echo "$as_me: WARNING: net/bpf.h: section \"Present But Cannot Be Compiled\"" >&2;} { echo "$as_me:$LINENO: WARNING: net/bpf.h: proceeding with the preprocessor's result" >&5 echo "$as_me: WARNING: net/bpf.h: proceeding with the preprocessor's result" >&2;} { echo "$as_me:$LINENO: WARNING: net/bpf.h: in the future, the compiler will take precedence" >&5 echo "$as_me: WARNING: net/bpf.h: in the future, the compiler will take precedence" >&2;} ( cat <<\_ASBOX ## --------------------------------- ## ## Report this to dhcp-users@isc.org ## ## --------------------------------- ## _ASBOX ) | sed "s/^/$as_me: WARNING: /" >&2 ;; esac { echo "$as_me:$LINENO: checking for net/bpf.h" >&5 echo $ECHO_N "checking for net/bpf.h... $ECHO_C" >&6; } if test "${ac_cv_header_net_bpf_h+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_cv_header_net_bpf_h=$ac_header_preproc fi { echo "$as_me:$LINENO: result: $ac_cv_header_net_bpf_h" >&5 echo "${ECHO_T}$ac_cv_header_net_bpf_h" >&6; } fi if test $ac_cv_header_net_bpf_h = yes; then DO_BPF=1 fi if test -n "$DO_BPF" then cat >>confdefs.h <<\_ACEOF #define HAVE_BPF 1 _ACEOF fi fi fi # SIOCGLIFCONF uses some transport structures. Trick is not all platforms # use the same structures. We like to use 'struct lifconf' and 'struct # lifreq', but we'll use these other structures if they're present. HPUX # does not define 'struct lifnum', but does use SIOCGLIFNUM - they use an # int value. # { echo "$as_me:$LINENO: checking for struct lifnum" >&5 echo $ECHO_N "checking for struct lifnum... $ECHO_C" >&6; } cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #include #include int main () { struct lifnum a; ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then { echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6; } cat >>confdefs.h <<\_ACEOF #define ISC_PLATFORM_HAVELIFNUM 1 _ACEOF else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6; } fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { echo "$as_me:$LINENO: checking for struct if_laddrconf" >&5 echo $ECHO_N "checking for struct if_laddrconf... $ECHO_C" >&6; } cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #include int main () { struct if_laddrconf a; ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then { echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6; } cat >>confdefs.h <<\_ACEOF #define ISC_PLATFORM_HAVEIF_LADDRCONF 1 _ACEOF else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6; } fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { echo "$as_me:$LINENO: checking for struct if_laddrreq" >&5 echo $ECHO_N "checking for struct if_laddrreq... $ECHO_C" >&6; } cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #include int main () { struct if_laddrreq a; ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_link") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && $as_test_x conftest$ac_exeext; then { echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6; } cat >>confdefs.h <<\_ACEOF #define ISC_PLATFORM_HAVEIF_LADDRREQ 1 _ACEOF else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6; } fi rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ conftest$ac_exeext conftest.$ac_ext # # check for GCC noreturn attribute # { echo "$as_me:$LINENO: checking for GCC noreturn attribute" >&5 echo $ECHO_N "checking for GCC noreturn attribute... $ECHO_C" >&6; } cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { void foo() __attribute__((noreturn)); ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then { echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6; } cat >>confdefs.h <<\_ACEOF #define ISC_DHCP_NORETURN __attribute__((noreturn)) _ACEOF else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6; } cat >>confdefs.h <<\_ACEOF #define ISC_DHCP_NORETURN _ACEOF fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext # Look for optional headers. for ac_header in sys/socket.h net/if_dl.h net/if6.h regex.h do as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then { echo "$as_me:$LINENO: checking for $ac_header" >&5 echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then echo $ECHO_N "(cached) $ECHO_C" >&6 fi ac_res=`eval echo '${'$as_ac_Header'}'` { echo "$as_me:$LINENO: result: $ac_res" >&5 echo "${ECHO_T}$ac_res" >&6; } else # Is the header compilable? { echo "$as_me:$LINENO: checking $ac_header usability" >&5 echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6; } cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default #include <$ac_header> _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_header_compiler=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_compiler=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 echo "${ECHO_T}$ac_header_compiler" >&6; } # Is the header present? { echo "$as_me:$LINENO: checking $ac_header presence" >&5 echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6; } cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include <$ac_header> _ACEOF if { (ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err }; then ac_header_preproc=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_preproc=no fi rm -f conftest.err conftest.$ac_ext { echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 echo "${ECHO_T}$ac_header_preproc" >&6; } # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in yes:no: ) { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} ac_header_preproc=yes ;; no:yes:* ) { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} ( cat <<\_ASBOX ## --------------------------------- ## ## Report this to dhcp-users@isc.org ## ## --------------------------------- ## _ASBOX ) | sed "s/^/$as_me: WARNING: /" >&2 ;; esac { echo "$as_me:$LINENO: checking for $ac_header" >&5 echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then echo $ECHO_N "(cached) $ECHO_C" >&6 else eval "$as_ac_Header=\$ac_header_preproc" fi ac_res=`eval echo '${'$as_ac_Header'}'` { echo "$as_me:$LINENO: result: $ac_res" >&5 echo "${ECHO_T}$ac_res" >&6; } fi if test `eval echo '${'$as_ac_Header'}'` = yes; then cat >>confdefs.h <<_ACEOF #define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done # Solaris needs some libraries for functions { echo "$as_me:$LINENO: checking for library containing socket" >&5 echo $ECHO_N "checking for library containing socket... $ECHO_C" >&6; } if test "${ac_cv_search_socket+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_func_search_save_LIBS=$LIBS cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char socket (); int main () { return socket (); ; return 0; } _ACEOF for ac_lib in '' socket; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi rm -f conftest.$ac_objext conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_link") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && $as_test_x conftest$ac_exeext; then ac_cv_search_socket=$ac_res else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ conftest$ac_exeext if test "${ac_cv_search_socket+set}" = set; then break fi done if test "${ac_cv_search_socket+set}" = set; then : else ac_cv_search_socket=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { echo "$as_me:$LINENO: result: $ac_cv_search_socket" >&5 echo "${ECHO_T}$ac_cv_search_socket" >&6; } ac_res=$ac_cv_search_socket if test "$ac_res" != no; then test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi { echo "$as_me:$LINENO: checking for library containing inet_ntoa" >&5 echo $ECHO_N "checking for library containing inet_ntoa... $ECHO_C" >&6; } if test "${ac_cv_search_inet_ntoa+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_func_search_save_LIBS=$LIBS cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char inet_ntoa (); int main () { return inet_ntoa (); ; return 0; } _ACEOF for ac_lib in '' nsl; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi rm -f conftest.$ac_objext conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_link") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && $as_test_x conftest$ac_exeext; then ac_cv_search_inet_ntoa=$ac_res else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ conftest$ac_exeext if test "${ac_cv_search_inet_ntoa+set}" = set; then break fi done if test "${ac_cv_search_inet_ntoa+set}" = set; then : else ac_cv_search_inet_ntoa=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { echo "$as_me:$LINENO: result: $ac_cv_search_inet_ntoa" >&5 echo "${ECHO_T}$ac_cv_search_inet_ntoa" >&6; } ac_res=$ac_cv_search_inet_ntoa if test "$ac_res" != no; then test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi { echo "$as_me:$LINENO: checking for library containing inet_aton" >&5 echo $ECHO_N "checking for library containing inet_aton... $ECHO_C" >&6; } if test "${ac_cv_search_inet_aton+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_func_search_save_LIBS=$LIBS cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char inet_aton (); int main () { return inet_aton (); ; return 0; } _ACEOF for ac_lib in '' socket nsl; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi rm -f conftest.$ac_objext conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_link") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && $as_test_x conftest$ac_exeext; then ac_cv_search_inet_aton=$ac_res else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ conftest$ac_exeext if test "${ac_cv_search_inet_aton+set}" = set; then break fi done if test "${ac_cv_search_inet_aton+set}" = set; then : else ac_cv_search_inet_aton=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { echo "$as_me:$LINENO: result: $ac_cv_search_inet_aton" >&5 echo "${ECHO_T}$ac_cv_search_inet_aton" >&6; } ac_res=$ac_cv_search_inet_aton if test "$ac_res" != no; then test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" else cat >>confdefs.h <<\_ACEOF #define NEED_INET_ATON 1 _ACEOF fi # Check for a standalone regex library. { echo "$as_me:$LINENO: checking for library containing regcomp" >&5 echo $ECHO_N "checking for library containing regcomp... $ECHO_C" >&6; } if test "${ac_cv_search_regcomp+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_func_search_save_LIBS=$LIBS cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char regcomp (); int main () { return regcomp (); ; return 0; } _ACEOF for ac_lib in '' regex; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi rm -f conftest.$ac_objext conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_link") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && $as_test_x conftest$ac_exeext; then ac_cv_search_regcomp=$ac_res else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ conftest$ac_exeext if test "${ac_cv_search_regcomp+set}" = set; then break fi done if test "${ac_cv_search_regcomp+set}" = set; then : else ac_cv_search_regcomp=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { echo "$as_me:$LINENO: result: $ac_cv_search_regcomp" >&5 echo "${ECHO_T}$ac_cv_search_regcomp" >&6; } ac_res=$ac_cv_search_regcomp if test "$ac_res" != no; then test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi # For HP/UX we need -lipv6 for if_nametoindex, perhaps others. { echo "$as_me:$LINENO: checking for library containing if_nametoindex" >&5 echo $ECHO_N "checking for library containing if_nametoindex... $ECHO_C" >&6; } if test "${ac_cv_search_if_nametoindex+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_func_search_save_LIBS=$LIBS cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char if_nametoindex (); int main () { return if_nametoindex (); ; return 0; } _ACEOF for ac_lib in '' ipv6; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi rm -f conftest.$ac_objext conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_link") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && $as_test_x conftest$ac_exeext; then ac_cv_search_if_nametoindex=$ac_res else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ conftest$ac_exeext if test "${ac_cv_search_if_nametoindex+set}" = set; then break fi done if test "${ac_cv_search_if_nametoindex+set}" = set; then : else ac_cv_search_if_nametoindex=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { echo "$as_me:$LINENO: result: $ac_cv_search_if_nametoindex" >&5 echo "${ECHO_T}$ac_cv_search_if_nametoindex" >&6; } ac_res=$ac_cv_search_if_nametoindex if test "$ac_res" != no; then test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi # check for /dev/random (declares HAVE_DEV_RANDOM) { echo "$as_me:$LINENO: checking for /dev/random" >&5 echo $ECHO_N "checking for /dev/random... $ECHO_C" >&6; } if test "${ac_cv_file__dev_random+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else test "$cross_compiling" = yes && { { echo "$as_me:$LINENO: error: cannot check for file existence when cross compiling" >&5 echo "$as_me: error: cannot check for file existence when cross compiling" >&2;} { (exit 1); exit 1; }; } if test -r "/dev/random"; then ac_cv_file__dev_random=yes else ac_cv_file__dev_random=no fi fi { echo "$as_me:$LINENO: result: $ac_cv_file__dev_random" >&5 echo "${ECHO_T}$ac_cv_file__dev_random" >&6; } if test $ac_cv_file__dev_random = yes; then cat >>confdefs.h <<\_ACEOF #define HAVE_DEV_RANDOM 1 _ACEOF fi # see if there is a "sa_len" field in our interface information structure { echo "$as_me:$LINENO: checking for struct sockaddr.sa_len" >&5 echo $ECHO_N "checking for struct sockaddr.sa_len... $ECHO_C" >&6; } if test "${ac_cv_member_struct_sockaddr_sa_len+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include int main () { static struct sockaddr ac_aggr; if (ac_aggr.sa_len) return 0; ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_cv_member_struct_sockaddr_sa_len=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include int main () { static struct sockaddr ac_aggr; if (sizeof ac_aggr.sa_len) return 0; ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_cv_member_struct_sockaddr_sa_len=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_member_struct_sockaddr_sa_len=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { echo "$as_me:$LINENO: result: $ac_cv_member_struct_sockaddr_sa_len" >&5 echo "${ECHO_T}$ac_cv_member_struct_sockaddr_sa_len" >&6; } if test $ac_cv_member_struct_sockaddr_sa_len = yes; then cat >>confdefs.h <<\_ACEOF #define HAVE_SA_LEN _ACEOF fi # figure out pointer size { echo "$as_me:$LINENO: checking for struct iaddr *" >&5 echo $ECHO_N "checking for struct iaddr *... $ECHO_C" >&6; } if test "${ac_cv_type_struct_iaddr_p+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include "includes/inet.h" #include typedef struct iaddr * ac__type_new_; int main () { if ((ac__type_new_ *) 0) return 0; if (sizeof (ac__type_new_)) return 0; ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_cv_type_struct_iaddr_p=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_type_struct_iaddr_p=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { echo "$as_me:$LINENO: result: $ac_cv_type_struct_iaddr_p" >&5 echo "${ECHO_T}$ac_cv_type_struct_iaddr_p" >&6; } # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. { echo "$as_me:$LINENO: checking size of struct iaddr *" >&5 echo $ECHO_N "checking size of struct iaddr *... $ECHO_C" >&6; } if test "${ac_cv_sizeof_struct_iaddr_p+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test "$cross_compiling" = yes; then # Depending upon the size, compute the lo and hi bounds. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include "includes/inet.h" #include typedef struct iaddr * ac__type_sizeof_; int main () { static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) >= 0)]; test_array [0] = 0 ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_lo=0 ac_mid=0 while :; do cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include "includes/inet.h" #include typedef struct iaddr * ac__type_sizeof_; int main () { static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) <= $ac_mid)]; test_array [0] = 0 ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_hi=$ac_mid; break else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_lo=`expr $ac_mid + 1` if test $ac_lo -le $ac_mid; then ac_lo= ac_hi= break fi ac_mid=`expr 2 '*' $ac_mid + 1` fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext done else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include "includes/inet.h" #include typedef struct iaddr * ac__type_sizeof_; int main () { static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) < 0)]; test_array [0] = 0 ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_hi=-1 ac_mid=-1 while :; do cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include "includes/inet.h" #include typedef struct iaddr * ac__type_sizeof_; int main () { static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) >= $ac_mid)]; test_array [0] = 0 ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_lo=$ac_mid; break else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_hi=`expr '(' $ac_mid ')' - 1` if test $ac_mid -le $ac_hi; then ac_lo= ac_hi= break fi ac_mid=`expr 2 '*' $ac_mid` fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext done else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_lo= ac_hi= fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext # Binary search between lo and hi bounds. while test "x$ac_lo" != "x$ac_hi"; do ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo` cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include "includes/inet.h" #include typedef struct iaddr * ac__type_sizeof_; int main () { static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) <= $ac_mid)]; test_array [0] = 0 ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_hi=$ac_mid else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_lo=`expr '(' $ac_mid ')' + 1` fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext done case $ac_lo in ?*) ac_cv_sizeof_struct_iaddr_p=$ac_lo;; '') if test "$ac_cv_type_struct_iaddr_p" = yes; then { { echo "$as_me:$LINENO: error: cannot compute sizeof (struct iaddr *) See \`config.log' for more details." >&5 echo "$as_me: error: cannot compute sizeof (struct iaddr *) See \`config.log' for more details." >&2;} { (exit 77); exit 77; }; } else ac_cv_sizeof_struct_iaddr_p=0 fi ;; esac else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include "includes/inet.h" #include typedef struct iaddr * ac__type_sizeof_; static long int longval () { return (long int) (sizeof (ac__type_sizeof_)); } static unsigned long int ulongval () { return (long int) (sizeof (ac__type_sizeof_)); } #include #include int main () { FILE *f = fopen ("conftest.val", "w"); if (! f) return 1; if (((long int) (sizeof (ac__type_sizeof_))) < 0) { long int i = longval (); if (i != ((long int) (sizeof (ac__type_sizeof_)))) return 1; fprintf (f, "%ld\n", i); } else { unsigned long int i = ulongval (); if (i != ((long int) (sizeof (ac__type_sizeof_)))) return 1; fprintf (f, "%lu\n", i); } return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF rm -f conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_link") 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='./conftest$ac_exeext' { (case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_try") 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_sizeof_struct_iaddr_p=`cat conftest.val` else echo "$as_me: program exited with status $ac_status" >&5 echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ( exit $ac_status ) if test "$ac_cv_type_struct_iaddr_p" = yes; then { { echo "$as_me:$LINENO: error: cannot compute sizeof (struct iaddr *) See \`config.log' for more details." >&5 echo "$as_me: error: cannot compute sizeof (struct iaddr *) See \`config.log' for more details." >&2;} { (exit 77); exit 77; }; } else ac_cv_sizeof_struct_iaddr_p=0 fi fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext fi rm -f conftest.val fi { echo "$as_me:$LINENO: result: $ac_cv_sizeof_struct_iaddr_p" >&5 echo "${ECHO_T}$ac_cv_sizeof_struct_iaddr_p" >&6; } cat >>confdefs.h <<_ACEOF #define SIZEOF_STRUCT_IADDR_P $ac_cv_sizeof_struct_iaddr_p _ACEOF # Solaris does not have the msg_control or msg_controlen members # in the msghdr structure unless you define: # # _XOPEN_SOURCE, _XOPEN_SOURCE_EXTENDED, and __EXTENSIONS__ # # See the "standards" man page for details. # # We check for the msg_control member, and if it is not found, we check # again with the appropriate defines added to the CFLAGS. (In order to # do this we have to remove the check from the cache, which is what the # "unset" is for.) { echo "$as_me:$LINENO: checking for struct msghdr.msg_control" >&5 echo $ECHO_N "checking for struct msghdr.msg_control... $ECHO_C" >&6; } if test "${ac_cv_member_struct_msghdr_msg_control+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #include int main () { static struct msghdr ac_aggr; if (ac_aggr.msg_control) return 0; ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_cv_member_struct_msghdr_msg_control=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #include int main () { static struct msghdr ac_aggr; if (sizeof ac_aggr.msg_control) return 0; ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_cv_member_struct_msghdr_msg_control=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_member_struct_msghdr_msg_control=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { echo "$as_me:$LINENO: result: $ac_cv_member_struct_msghdr_msg_control" >&5 echo "${ECHO_T}$ac_cv_member_struct_msghdr_msg_control" >&6; } if test $ac_cv_member_struct_msghdr_msg_control = yes; then : else CFLAGS="$CFLAGS -D_XOPEN_SOURCE -D_XOPEN_SOURCE_EXTENDED=1" CFLAGS="$CFLAGS -D__EXTENSIONS__" unset ac_cv_member_struct_msghdr_msg_control { echo "$as_me:$LINENO: checking for struct msghdr.msg_control" >&5 echo $ECHO_N "checking for struct msghdr.msg_control... $ECHO_C" >&6; } if test "${ac_cv_member_struct_msghdr_msg_control+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #include int main () { static struct msghdr ac_aggr; if (ac_aggr.msg_control) return 0; ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_cv_member_struct_msghdr_msg_control=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #include int main () { static struct msghdr ac_aggr; if (sizeof ac_aggr.msg_control) return 0; ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_cv_member_struct_msghdr_msg_control=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_member_struct_msghdr_msg_control=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { echo "$as_me:$LINENO: result: $ac_cv_member_struct_msghdr_msg_control" >&5 echo "${ECHO_T}$ac_cv_member_struct_msghdr_msg_control" >&6; } if test $ac_cv_member_struct_msghdr_msg_control = yes; then : else { { echo "$as_me:$LINENO: error: Missing msg_control member in msg_control structure." >&5 echo "$as_me: error: Missing msg_control member in msg_control structure." >&2;} { (exit 1); exit 1; }; } fi fi libbind= # Check whether --with-libbind was given. if test "${with_libbind+set}" = set; then withval=$with_libbind; use_libbind="$withval" else use_libbind="no" fi case "$use_libbind" in yes) libbind="\${top_srcdir}/bind" ;; no) libbind="\${top_srcdir}/bind" ;; *) libbind="$use_libbind" ;; esac # OpenLDAP support. # Check whether --with-ldap was given. if test "${with_ldap+set}" = set; then withval=$with_ldap; ldap=$withval else ldap=no fi # OpenLDAP with SSL support. # Check whether --with-ldapcrypto was given. if test "${with_ldapcrypto+set}" = set; then withval=$with_ldapcrypto; ldapcrypto=$withval else ldapcrypto=no fi # OpenLDAP support is disabled by default, if enabled then SSL support is an # extra optional that is also disabled by default. Enabling LDAP SSL support # implies enabling LDAP support. if test x$ldap = xyes || test x$ldapcrypto = xyes ; then { echo "$as_me:$LINENO: checking for library containing ldap_initialize" >&5 echo $ECHO_N "checking for library containing ldap_initialize... $ECHO_C" >&6; } if test "${ac_cv_search_ldap_initialize+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_func_search_save_LIBS=$LIBS cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char ldap_initialize (); int main () { return ldap_initialize (); ; return 0; } _ACEOF for ac_lib in '' ldap; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi rm -f conftest.$ac_objext conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_link") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && $as_test_x conftest$ac_exeext; then ac_cv_search_ldap_initialize=$ac_res else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ conftest$ac_exeext if test "${ac_cv_search_ldap_initialize+set}" = set; then break fi done if test "${ac_cv_search_ldap_initialize+set}" = set; then : else ac_cv_search_ldap_initialize=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { echo "$as_me:$LINENO: result: $ac_cv_search_ldap_initialize" >&5 echo "${ECHO_T}$ac_cv_search_ldap_initialize" >&6; } ac_res=$ac_cv_search_ldap_initialize if test "$ac_res" != no; then test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" else { { echo "$as_me:$LINENO: error: *** Cannot find ldap_initialize with -lldap - do you need to install an OpenLDAP2 Devel package? See \`config.log' for more details." >&5 echo "$as_me: error: *** Cannot find ldap_initialize with -lldap - do you need to install an OpenLDAP2 Devel package? See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } fi { echo "$as_me:$LINENO: checking for library containing ber_pvt_opt_on" >&5 echo $ECHO_N "checking for library containing ber_pvt_opt_on... $ECHO_C" >&6; } if test "${ac_cv_search_ber_pvt_opt_on+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_func_search_save_LIBS=$LIBS cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char ber_pvt_opt_on (); int main () { return ber_pvt_opt_on (); ; return 0; } _ACEOF for ac_lib in '' lber; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi rm -f conftest.$ac_objext conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_link") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && $as_test_x conftest$ac_exeext; then ac_cv_search_ber_pvt_opt_on=$ac_res else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ conftest$ac_exeext if test "${ac_cv_search_ber_pvt_opt_on+set}" = set; then break fi done if test "${ac_cv_search_ber_pvt_opt_on+set}" = set; then : else ac_cv_search_ber_pvt_opt_on=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { echo "$as_me:$LINENO: result: $ac_cv_search_ber_pvt_opt_on" >&5 echo "${ECHO_T}$ac_cv_search_ber_pvt_opt_on" >&6; } ac_res=$ac_cv_search_ber_pvt_opt_on if test "$ac_res" != no; then test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" else { { echo "$as_me:$LINENO: error: *** Cannot find ber_pvt_opt_on with -llber - do you need to install an OpenLDAP2 Devel package? See \`config.log' for more details." >&5 echo "$as_me: error: *** Cannot find ber_pvt_opt_on with -llber - do you need to install an OpenLDAP2 Devel package? See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } fi if test x$ldapcrypto = xyes ; then LDAP_CFLAGS="-DLDAP_CONFIGURATION -DLDAP_USE_SSL" else LDAP_CFLAGS="-DLDAP_CONFIGURATION" fi fi # Append selected warning levels to CFLAGS before substitution (but after # AC_TRY_COMPILE & etc). CFLAGS="$CFLAGS $STD_CWARNINGS" # Try to add the bind include directory CFLAGS="$CFLAGS -I$libbind/include" { echo "$as_me:$LINENO: checking for flexible array members" >&5 echo $ECHO_N "checking for flexible array members... $ECHO_C" >&6; } if test "${ac_cv_c_flexmember+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #include #include struct s { int n; double d[]; }; int main () { int m = getchar (); struct s *p = malloc (offsetof (struct s, d) + m * sizeof (double)); p->d[0] = 0.0; return p->d != (double *) NULL; ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_cv_c_flexmember=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_c_flexmember=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { echo "$as_me:$LINENO: result: $ac_cv_c_flexmember" >&5 echo "${ECHO_T}$ac_cv_c_flexmember" >&6; } if test $ac_cv_c_flexmember = yes; then cat >>confdefs.h <<\_ACEOF #define FLEXIBLE_ARRAY_MEMBER _ACEOF else cat >>confdefs.h <<\_ACEOF #define FLEXIBLE_ARRAY_MEMBER 1 _ACEOF fi ac_config_files="$ac_config_files Makefile client/Makefile common/Makefile common/tests/Makefile dhcpctl/Makefile dst/Makefile includes/Makefile omapip/Makefile relay/Makefile server/Makefile tests/Makefile" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { echo "$as_me:$LINENO: WARNING: Cache variable $ac_var contains a newline." >&5 echo "$as_me: WARNING: Cache variable $ac_var contains a newline." >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( *) $as_unset $ac_var ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes (double-quote # substitution turns \\\\ into \\, and sed turns \\ into \). sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then test "x$cache_file" != "x/dev/null" && { echo "$as_me:$LINENO: updating cache $cache_file" >&5 echo "$as_me: updating cache $cache_file" >&6;} cat confcache >$cache_file else { echo "$as_me:$LINENO: not updating unwritable cache $cache_file" >&5 echo "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' DEFS=-DHAVE_CONFIG_H ac_libobjs= ac_ltlibobjs= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' ac_i=`echo "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. ac_libobjs="$ac_libobjs \${LIBOBJDIR}$ac_i\$U.$ac_objext" ac_ltlibobjs="$ac_ltlibobjs \${LIBOBJDIR}$ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs if test -z "${MAINTAINER_MODE_TRUE}" && test -z "${MAINTAINER_MODE_FALSE}"; then { { echo "$as_me:$LINENO: error: conditional \"MAINTAINER_MODE\" was never defined. Usually this means the macro was only invoked conditionally." >&5 echo "$as_me: error: conditional \"MAINTAINER_MODE\" was never defined. Usually this means the macro was only invoked conditionally." >&2;} { (exit 1); exit 1; }; } fi if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then { { echo "$as_me:$LINENO: error: conditional \"AMDEP\" was never defined. Usually this means the macro was only invoked conditionally." >&5 echo "$as_me: error: conditional \"AMDEP\" was never defined. Usually this means the macro was only invoked conditionally." >&2;} { (exit 1); exit 1; }; } fi if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then { { echo "$as_me:$LINENO: error: conditional \"am__fastdepCC\" was never defined. Usually this means the macro was only invoked conditionally." >&5 echo "$as_me: error: conditional \"am__fastdepCC\" was never defined. Usually this means the macro was only invoked conditionally." >&2;} { (exit 1); exit 1; }; } fi : ${CONFIG_STATUS=./config.status} ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5 echo "$as_me: creating $CONFIG_STATUS" >&6;} cat >$CONFIG_STATUS <<_ACEOF #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF ## --------------------- ## ## M4sh Initialization. ## ## --------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in *posix*) set -o posix ;; esac fi # PATH needs CR # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then echo "#! /bin/sh" >conf$$.sh echo "exit 0" >>conf$$.sh chmod +x conf$$.sh if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then PATH_SEPARATOR=';' else PATH_SEPARATOR=: fi rm -f conf$$.sh fi # Support unset when possible. if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then as_unset=unset else as_unset=false fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) as_nl=' ' IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. case $0 in *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 { (exit 1); exit 1; } fi # Work around bugs in pre-3.0 UWIN ksh. for as_var in ENV MAIL MAILPATH do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. for as_var in \ LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ LC_TELEPHONE LC_TIME do if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then eval $as_var=C; export $as_var else ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var fi done # Required to use basename. if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi # Name of the executable. as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # CDPATH. $as_unset CDPATH as_lineno_1=$LINENO as_lineno_2=$LINENO test "x$as_lineno_1" != "x$as_lineno_2" && test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || { # Create $as_me.lineno as a copy of $as_myself, but with $LINENO # uniformly replaced by the line number. The first 'sed' inserts a # line-number line after each line using $LINENO; the second 'sed' # does the real work. The second script uses 'N' to pair each # line-number line with the line containing $LINENO, and appends # trailing '-' during substitution so that $LINENO is not a special # case at line end. # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the # scripts with optimization help from Paolo Bonzini. Blame Lee # E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 { (exit 1); exit 1; }; } # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in -n*) case `echo 'x\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. *) ECHO_C='\c';; esac;; *) ECHO_N='-n';; esac if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir fi echo >conf$$.file if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -p'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -p' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -p' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p=: else test -d ./-p && rmdir ./-p as_mkdir_p=false fi if test -x / >/dev/null 2>&1; then as_test_x='test -x' else if ls -dL / >/dev/null 2>&1; then as_ls_L_option=L else as_ls_L_option= fi as_test_x=' eval sh -c '\'' if test -d "$1"; then test -d "$1/."; else case $1 in -*)set "./$1";; esac; case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in ???[sx]*):;;*)false;;esac;fi '\'' sh ' fi as_executable_p=$as_test_x # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 6>&1 # Save the log message, to keep $[0] and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by DHCP $as_me 4.2.4, which was generated by GNU Autoconf 2.61. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ on `(hostname || uname -n) 2>/dev/null | sed 1q` " _ACEOF cat >>$CONFIG_STATUS <<_ACEOF # Files that config.status was made for. config_files="$ac_config_files" config_headers="$ac_config_headers" config_commands="$ac_config_commands" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF ac_cs_usage="\ \`$as_me' instantiates files from templates according to the current configuration. Usage: $0 [OPTIONS] [FILE]... -h, --help print this help, then exit -V, --version print version number and configuration settings, then exit -q, --quiet do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE --header=FILE[:TEMPLATE] instantiate the configuration header FILE Configuration files: $config_files Configuration headers: $config_headers Configuration commands: $config_commands Report bugs to ." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF ac_cs_version="\\ DHCP config.status 4.2.4 configured by $0, generated by GNU Autoconf 2.61, with options \\"`echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\" Copyright (C) 2006 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' INSTALL='$INSTALL' MKDIR_P='$MKDIR_P' _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF # If no file are specified by the user, then we need to provide default # value. By we need to know if files were specified by the user. ac_need_defaults=: while test $# != 0 do case $1 in --*=*) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ac_shift=: ;; *) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; esac case $ac_option in # Handling of the options. -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) echo "$ac_cs_version"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift CONFIG_FILES="$CONFIG_FILES $ac_optarg" ac_need_defaults=false;; --header | --heade | --head | --hea ) $ac_shift CONFIG_HEADERS="$CONFIG_HEADERS $ac_optarg" ac_need_defaults=false;; --he | --h) # Conflict between --help and --header { echo "$as_me: error: ambiguous option: $1 Try \`$0 --help' for more information." >&2 { (exit 1); exit 1; }; };; --help | --hel | -h ) echo "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) { echo "$as_me: error: unrecognized option: $1 Try \`$0 --help' for more information." >&2 { (exit 1); exit 1; }; } ;; *) ac_config_targets="$ac_config_targets $1" ac_need_defaults=false ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF if \$ac_cs_recheck; then echo "running CONFIG_SHELL=$SHELL $SHELL $0 "$ac_configure_args \$ac_configure_extra_args " --no-create --no-recursion" >&6 CONFIG_SHELL=$SHELL export CONFIG_SHELL exec $SHELL "$0"$ac_configure_args \$ac_configure_extra_args --no-create --no-recursion fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX echo "$ac_log" } >&5 _ACEOF cat >>$CONFIG_STATUS <<_ACEOF # # INIT-COMMANDS # AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF # Handling of arguments. for ac_config_target in $ac_config_targets do case $ac_config_target in "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; "includes/config.h") CONFIG_HEADERS="$CONFIG_HEADERS includes/config.h" ;; "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; "client/Makefile") CONFIG_FILES="$CONFIG_FILES client/Makefile" ;; "common/Makefile") CONFIG_FILES="$CONFIG_FILES common/Makefile" ;; "common/tests/Makefile") CONFIG_FILES="$CONFIG_FILES common/tests/Makefile" ;; "dhcpctl/Makefile") CONFIG_FILES="$CONFIG_FILES dhcpctl/Makefile" ;; "dst/Makefile") CONFIG_FILES="$CONFIG_FILES dst/Makefile" ;; "includes/Makefile") CONFIG_FILES="$CONFIG_FILES includes/Makefile" ;; "omapip/Makefile") CONFIG_FILES="$CONFIG_FILES omapip/Makefile" ;; "relay/Makefile") CONFIG_FILES="$CONFIG_FILES relay/Makefile" ;; "server/Makefile") CONFIG_FILES="$CONFIG_FILES server/Makefile" ;; "tests/Makefile") CONFIG_FILES="$CONFIG_FILES tests/Makefile" ;; *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5 echo "$as_me: error: invalid argument: $ac_config_target" >&2;} { (exit 1); exit 1; }; };; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason against having it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: # after its creation but before its name has been assigned to `$tmp'. $debug || { tmp= trap 'exit_status=$? { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status ' 0 trap '{ (exit 1); exit 1; }' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || { echo "$me: cannot create a temporary directory in ." >&2 { (exit 1); exit 1; } } # # Set up the sed scripts for CONFIG_FILES section. # # No need to generate the scripts if there are no CONFIG_FILES. # This happens for instance when ./config.status config.h if test -n "$CONFIG_FILES"; then _ACEOF ac_delim='%!_!# ' for ac_last_try in false false false false false :; do cat >conf$$subs.sed <<_ACEOF SHELL!$SHELL$ac_delim PATH_SEPARATOR!$PATH_SEPARATOR$ac_delim PACKAGE_NAME!$PACKAGE_NAME$ac_delim PACKAGE_TARNAME!$PACKAGE_TARNAME$ac_delim PACKAGE_VERSION!$PACKAGE_VERSION$ac_delim PACKAGE_STRING!$PACKAGE_STRING$ac_delim PACKAGE_BUGREPORT!$PACKAGE_BUGREPORT$ac_delim exec_prefix!$exec_prefix$ac_delim prefix!$prefix$ac_delim program_transform_name!$program_transform_name$ac_delim bindir!$bindir$ac_delim sbindir!$sbindir$ac_delim libexecdir!$libexecdir$ac_delim datarootdir!$datarootdir$ac_delim datadir!$datadir$ac_delim sysconfdir!$sysconfdir$ac_delim sharedstatedir!$sharedstatedir$ac_delim localstatedir!$localstatedir$ac_delim includedir!$includedir$ac_delim oldincludedir!$oldincludedir$ac_delim docdir!$docdir$ac_delim infodir!$infodir$ac_delim htmldir!$htmldir$ac_delim dvidir!$dvidir$ac_delim pdfdir!$pdfdir$ac_delim psdir!$psdir$ac_delim libdir!$libdir$ac_delim localedir!$localedir$ac_delim mandir!$mandir$ac_delim DEFS!$DEFS$ac_delim ECHO_C!$ECHO_C$ac_delim ECHO_N!$ECHO_N$ac_delim ECHO_T!$ECHO_T$ac_delim LIBS!$LIBS$ac_delim build_alias!$build_alias$ac_delim host_alias!$host_alias$ac_delim target_alias!$target_alias$ac_delim INSTALL_PROGRAM!$INSTALL_PROGRAM$ac_delim INSTALL_SCRIPT!$INSTALL_SCRIPT$ac_delim INSTALL_DATA!$INSTALL_DATA$ac_delim am__isrc!$am__isrc$ac_delim CYGPATH_W!$CYGPATH_W$ac_delim PACKAGE!$PACKAGE$ac_delim VERSION!$VERSION$ac_delim ACLOCAL!$ACLOCAL$ac_delim AUTOCONF!$AUTOCONF$ac_delim AUTOMAKE!$AUTOMAKE$ac_delim AUTOHEADER!$AUTOHEADER$ac_delim MAKEINFO!$MAKEINFO$ac_delim install_sh!$install_sh$ac_delim STRIP!$STRIP$ac_delim INSTALL_STRIP_PROGRAM!$INSTALL_STRIP_PROGRAM$ac_delim mkdir_p!$mkdir_p$ac_delim AWK!$AWK$ac_delim SET_MAKE!$SET_MAKE$ac_delim am__leading_dot!$am__leading_dot$ac_delim AMTAR!$AMTAR$ac_delim am__tar!$am__tar$ac_delim am__untar!$am__untar$ac_delim MAINTAINER_MODE_TRUE!$MAINTAINER_MODE_TRUE$ac_delim MAINTAINER_MODE_FALSE!$MAINTAINER_MODE_FALSE$ac_delim MAINT!$MAINT$ac_delim CC!$CC$ac_delim CFLAGS!$CFLAGS$ac_delim LDFLAGS!$LDFLAGS$ac_delim CPPFLAGS!$CPPFLAGS$ac_delim ac_ct_CC!$ac_ct_CC$ac_delim EXEEXT!$EXEEXT$ac_delim OBJEXT!$OBJEXT$ac_delim DEPDIR!$DEPDIR$ac_delim am__include!$am__include$ac_delim am__quote!$am__quote$ac_delim AMDEP_TRUE!$AMDEP_TRUE$ac_delim AMDEP_FALSE!$AMDEP_FALSE$ac_delim AMDEPBACKSLASH!$AMDEPBACKSLASH$ac_delim CCDEPMODE!$CCDEPMODE$ac_delim am__fastdepCC_TRUE!$am__fastdepCC_TRUE$ac_delim am__fastdepCC_FALSE!$am__fastdepCC_FALSE$ac_delim CPP!$CPP$ac_delim GREP!$GREP$ac_delim EGREP!$EGREP$ac_delim RANLIB!$RANLIB$ac_delim byte_order!$byte_order$ac_delim ac_prefix_program!$ac_prefix_program$ac_delim LDAP_CFLAGS!$LDAP_CFLAGS$ac_delim LIBOBJS!$LIBOBJS$ac_delim LTLIBOBJS!$LTLIBOBJS$ac_delim _ACEOF if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 87; then break elif $ac_last_try; then { { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5 echo "$as_me: error: could not make $CONFIG_STATUS" >&2;} { (exit 1); exit 1; }; } else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done ac_eof=`sed -n '/^CEOF[0-9]*$/s/CEOF/0/p' conf$$subs.sed` if test -n "$ac_eof"; then ac_eof=`echo "$ac_eof" | sort -nru | sed 1q` ac_eof=`expr $ac_eof + 1` fi cat >>$CONFIG_STATUS <<_ACEOF cat >"\$tmp/subs-1.sed" <<\CEOF$ac_eof /@[a-zA-Z_][a-zA-Z_0-9]*@/!b end _ACEOF sed ' s/[,\\&]/\\&/g; s/@/@|#_!!_#|/g s/^/s,@/; s/!/@,|#_!!_#|/ :n t n s/'"$ac_delim"'$/,g/; t s/$/\\/; p N; s/^.*\n//; s/[,\\&]/\\&/g; s/@/@|#_!!_#|/g; b n ' >>$CONFIG_STATUS >$CONFIG_STATUS <<_ACEOF :end s/|#_!!_#|//g CEOF$ac_eof _ACEOF # VPATH may cause trouble with some makes, so we remove $(srcdir), # ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=/{ s/:*\$(srcdir):*/:/ s/:*\${srcdir}:*/:/ s/:*@srcdir@:*/:/ s/^\([^=]*=[ ]*\):*/\1/ s/:*$// s/^[^=]*=[ ]*$// }' fi cat >>$CONFIG_STATUS <<\_ACEOF fi # test -n "$CONFIG_FILES" for ac_tag in :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS do case $ac_tag in :[FHLC]) ac_mode=$ac_tag; continue;; esac case $ac_mode$ac_tag in :[FHL]*:*);; :L* | :C*:*) { { echo "$as_me:$LINENO: error: Invalid tag $ac_tag." >&5 echo "$as_me: error: Invalid tag $ac_tag." >&2;} { (exit 1); exit 1; }; };; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac ac_save_IFS=$IFS IFS=: set x $ac_tag IFS=$ac_save_IFS shift ac_file=$1 shift case $ac_mode in :L) ac_source=$1;; :[FH]) ac_file_inputs= for ac_f do case $ac_f in -) ac_f="$tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || { { echo "$as_me:$LINENO: error: cannot find input file: $ac_f" >&5 echo "$as_me: error: cannot find input file: $ac_f" >&2;} { (exit 1); exit 1; }; };; esac ac_file_inputs="$ac_file_inputs $ac_f" done # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input="Generated from "`IFS=: echo $* | sed 's|^[^:]*/||;s|:[^:]*/|, |g'`" by configure." if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { echo "$as_me:$LINENO: creating $ac_file" >&5 echo "$as_me: creating $ac_file" >&6;} fi case $ac_tag in *:-:* | *:-) cat >"$tmp/stdin";; esac ;; esac ac_dir=`$as_dirname -- "$ac_file" || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` { as_dir="$ac_dir" case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || { $as_mkdir_p && mkdir -p "$as_dir"; } || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || { { echo "$as_me:$LINENO: error: cannot create directory $as_dir" >&5 echo "$as_me: error: cannot create directory $as_dir" >&2;} { (exit 1); exit 1; }; }; } ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,/..,g;s,/,,'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix case $ac_mode in :F) # # CONFIG_FILE # case $INSTALL in [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; esac ac_MKDIR_P=$MKDIR_P case $MKDIR_P in [\\/$]* | ?:[\\/]* ) ;; */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;; esac _ACEOF # Neutralize VPATH when `$srcdir' = `.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? cat >>$CONFIG_STATUS <<_ACEOF sed "$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s&@configure_input@&$configure_input&;t t s&@top_builddir@&$ac_top_builddir_sub&;t t s&@srcdir@&$ac_srcdir&;t t s&@abs_srcdir@&$ac_abs_srcdir&;t t s&@top_srcdir@&$ac_top_srcdir&;t t s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t s&@builddir@&$ac_builddir&;t t s&@abs_builddir@&$ac_abs_builddir&;t t s&@abs_top_builddir@&$ac_abs_top_builddir&;t t s&@INSTALL@&$ac_INSTALL&;t t s&@MKDIR_P@&$ac_MKDIR_P&;t t " $ac_file_inputs | sed -f "$tmp/subs-1.sed" >$tmp/out rm -f "$tmp/stdin" case $ac_file in -) cat "$tmp/out"; rm -f "$tmp/out";; *) rm -f "$ac_file"; mv "$tmp/out" $ac_file;; esac ;; :H) # # CONFIG_HEADER # _ACEOF # Transform confdefs.h into a sed script `conftest.defines', that # substitutes the proper values into config.h.in to produce config.h. rm -f conftest.defines conftest.tail # First, append a space to every undef/define line, to ease matching. echo 's/$/ /' >conftest.defines # Then, protect against being on the right side of a sed subst, or in # an unquoted here document, in config.status. If some macros were # called several times there might be several #defines for the same # symbol, which is useless. But do not sort them, since the last # AC_DEFINE must be honored. ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* # These sed commands are passed to sed as "A NAME B PARAMS C VALUE D", where # NAME is the cpp macro being defined, VALUE is the value it is being given. # PARAMS is the parameter list in the macro definition--in most cases, it's # just an empty string. ac_dA='s,^\\([ #]*\\)[^ ]*\\([ ]*' ac_dB='\\)[ (].*,\\1define\\2' ac_dC=' ' ac_dD=' ,' uniq confdefs.h | sed -n ' t rset :rset s/^[ ]*#[ ]*define[ ][ ]*// t ok d :ok s/[\\&,]/\\&/g s/^\('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/ '"$ac_dA"'\1'"$ac_dB"'\2'"${ac_dC}"'\3'"$ac_dD"'/p s/^\('"$ac_word_re"'\)[ ]*\(.*\)/'"$ac_dA"'\1'"$ac_dB$ac_dC"'\2'"$ac_dD"'/p ' >>conftest.defines # Remove the space that was appended to ease matching. # Then replace #undef with comments. This is necessary, for # example, in the case of _POSIX_SOURCE, which is predefined and required # on some systems where configure will not decide to define it. # (The regexp can be short, since the line contains either #define or #undef.) echo 's/ $// s,^[ #]*u.*,/* & */,' >>conftest.defines # Break up conftest.defines: ac_max_sed_lines=50 # First sed command is: sed -f defines.sed $ac_file_inputs >"$tmp/out1" # Second one is: sed -f defines.sed "$tmp/out1" >"$tmp/out2" # Third one will be: sed -f defines.sed "$tmp/out2" >"$tmp/out1" # et cetera. ac_in='$ac_file_inputs' ac_out='"$tmp/out1"' ac_nxt='"$tmp/out2"' while : do # Write a here document: cat >>$CONFIG_STATUS <<_ACEOF # First, check the format of the line: cat >"\$tmp/defines.sed" <<\\CEOF /^[ ]*#[ ]*undef[ ][ ]*$ac_word_re[ ]*\$/b def /^[ ]*#[ ]*define[ ][ ]*$ac_word_re[( ]/b def b :def _ACEOF sed ${ac_max_sed_lines}q conftest.defines >>$CONFIG_STATUS echo 'CEOF sed -f "$tmp/defines.sed"' "$ac_in >$ac_out" >>$CONFIG_STATUS ac_in=$ac_out; ac_out=$ac_nxt; ac_nxt=$ac_in sed 1,${ac_max_sed_lines}d conftest.defines >conftest.tail grep . conftest.tail >/dev/null || break rm -f conftest.defines mv conftest.tail conftest.defines done rm -f conftest.defines conftest.tail echo "ac_result=$ac_in" >>$CONFIG_STATUS cat >>$CONFIG_STATUS <<\_ACEOF if test x"$ac_file" != x-; then echo "/* $configure_input */" >"$tmp/config.h" cat "$ac_result" >>"$tmp/config.h" if diff $ac_file "$tmp/config.h" >/dev/null 2>&1; then { echo "$as_me:$LINENO: $ac_file is unchanged" >&5 echo "$as_me: $ac_file is unchanged" >&6;} else rm -f $ac_file mv "$tmp/config.h" $ac_file fi else echo "/* $configure_input */" cat "$ac_result" fi rm -f "$tmp/out12" # Compute $ac_file's index in $config_headers. _am_arg=$ac_file _am_stamp_count=1 for _am_header in $config_headers :; do case $_am_header in $_am_arg | $_am_arg:* ) break ;; * ) _am_stamp_count=`expr $_am_stamp_count + 1` ;; esac done echo "timestamp for $_am_arg" >`$as_dirname -- "$_am_arg" || $as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$_am_arg" : 'X\(//\)[^/]' \| \ X"$_am_arg" : 'X\(//\)$' \| \ X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null || echo X"$_am_arg" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'`/stamp-h$_am_stamp_count ;; :C) { echo "$as_me:$LINENO: executing $ac_file commands" >&5 echo "$as_me: executing $ac_file commands" >&6;} ;; esac case $ac_file$ac_mode in "depfiles":C) test x"$AMDEP_TRUE" != x"" || for mf in $CONFIG_FILES; do # Strip MF so we end up with the name of the file. mf=`echo "$mf" | sed -e 's/:.*$//'` # Check whether this is an Automake generated Makefile or not. # We used to match only the files named `Makefile.in', but # some people rename them; so instead we look at the file content. # Grep'ing the first line is not enough: some people post-process # each Makefile.in and add a new line on top of each file to say so. # Grep'ing the whole file is not good either: AIX grep has a line # limit of 2048, but all sed's we know have understand at least 4000. if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then dirpart=`$as_dirname -- "$mf" || $as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$mf" : 'X\(//\)[^/]' \| \ X"$mf" : 'X\(//\)$' \| \ X"$mf" : 'X\(/\)' \| . 2>/dev/null || echo X"$mf" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` else continue fi # Extract the definition of DEPDIR, am__include, and am__quote # from the Makefile without running `make'. DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` test -z "$DEPDIR" && continue am__include=`sed -n 's/^am__include = //p' < "$mf"` test -z "am__include" && continue am__quote=`sed -n 's/^am__quote = //p' < "$mf"` # When using ansi2knr, U may be empty or an underscore; expand it U=`sed -n 's/^U = //p' < "$mf"` # Find all dependency output files, they are included files with # $(DEPDIR) in their names. We invoke sed twice because it is the # simplest approach to changing $(DEPDIR) to its actual value in the # expansion. for file in `sed -n " s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do # Make sure the directory exists. test -f "$dirpart/$file" && continue fdir=`$as_dirname -- "$file" || $as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$file" : 'X\(//\)[^/]' \| \ X"$file" : 'X\(//\)$' \| \ X"$file" : 'X\(/\)' \| . 2>/dev/null || echo X"$file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` { as_dir=$dirpart/$fdir case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || { $as_mkdir_p && mkdir -p "$as_dir"; } || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || { { echo "$as_me:$LINENO: error: cannot create directory $as_dir" >&5 echo "$as_me: error: cannot create directory $as_dir" >&2;} { (exit 1); exit 1; }; }; } # echo "creating $dirpart/$file" echo '# dummy' > "$dirpart/$file" done done ;; esac done # for ac_tag { (exit 0); exit 0; } _ACEOF chmod +x $CONFIG_STATUS ac_clean_files=$ac_clean_files_save # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || { (exit 1); exit 1; } fi sh util/bindvar.sh dhcp-4.2.4/configure.ac000644 000765 000024 00000046612 11757476456 014714 0ustar00sarstaff000000 000000 AC_INIT([DHCP], [4.2.4], [dhcp-users@isc.org]) # we specify "foreign" to avoid having to have the GNU mandated files, # like AUTHORS, COPYING, and such AM_INIT_AUTOMAKE([foreign]) # we specify AM_MAINTAINER_MODE to avoid problems with rebuilding # the configure and makefiles. Without it users doing things that # change the timestamps on the code, like checking it into a cvs # tree, could trigger a rebuild of the infrastructure files which # might fail if they don't have the correct tools. AM_MAINTAINER_MODE # We want to turn on warnings if we are using gcc and the user did # not specify CFLAGS. The autoconf check for the C compiler sets the # CFLAGS if gcc is used, so we will save it before we run that check. SAVE_CFLAGS="$CFLAGS" # Now find our C compiler. AC_PROG_CC # Suppress warnings about --datarootdir AC_DEFUN([AC_DATAROOTDIR_CHECKED]) # If we have gcc, and AC_PROG_CC changed the flags, then we know the # user did not specify any flags. Add warnings in this case. if test "$GCC" = "yes"; then if test "$CFLAGS" != "$SAVE_CFLAGS"; then STD_CWARNINGS="$STD_CWARNINGS -Wall -Werror -fno-strict-aliasing" fi fi # POSIX doesn't include the IPv6 Advanced Socket API and glibc hides # parts of the IPv6 Advanced Socket API as a result. This is stupid # as it breaks how the two halves (Basic and Advanced) of the IPv6 # Socket API were designed to be used but we have to live with it. # Use this to define _GNU_SOURCE to pull in the IPv6 Advanced Socket API. AC_USE_SYSTEM_EXTENSIONS AC_PROG_RANLIB AC_CONFIG_HEADERS([includes/config.h]) # we sometimes need to know byte order for building packets AC_C_BIGENDIAN(AC_SUBST(byte_order, BIG_ENDIAN), AC_SUBST(byte_order, LITTLE_ENDIAN)) AC_DEFINE_UNQUOTED([DHCP_BYTE_ORDER], [$byte_order], [Define to BIG_ENDIAN for MSB (Motorola or SPARC CPUs) or LITTLE_ENDIAN for LSB (Intel CPUs).]) # Optional compile-time DEBUGging. AC_ARG_ENABLE(debug, AC_HELP_STRING([--enable-debug], [create a debug-only version of the software (default is no).])) # This is very much off by default. if test "$enable_debug" = "yes" ; then AC_DEFINE([DEBUG], [1], [Define to compile debug-only DHCP software.]) # Just override CFLAGS to totally to remove optimization. CFLAGS="-g" fi # XXX: there are actually quite a lot more DEBUG_ features we could enable, # but I don't want to pollute the --help space. # #/* #define DEBUG_TOKENS */ #/* #define DEBUG_PACKET */ #/* #define DEBUG_EXPRESSIONS */ #/* #define DEBUG_FIND_LEASE */ #/* #define DEBUG_EXPRESSION_PARSE */ #/* #define DEBUG_CLASS_MATCHING */ #/* #define DEBUG_MEMORY_LEAKAGE */ #/* #define DEBUG_MALLOC_POOL */ #/* #define DEBUG_LEASE_STATE_TRANSITIONS */ #/* #define DEBUG_RC_HISTORY */ #/* #define DEBUG_RC_HISTORY_EXHAUSTIVELY */ #/* #define RC_HISTORY_MAX 10240 */ #/* #define POINTER_DEBUG */ #/* #define DEBUG_FAILOVER_MESSAGES */ #/* #define DEBUG_FAILOVER_TIMING */ #/* #define DEBUG_DUMP_ALL_LEASES */ # Failover optional compile-time feature. AC_ARG_ENABLE(failover, AC_HELP_STRING([--enable-failover], [enable support for failover (default is yes)])) # Failover is on by default, so define if it is not explicitly disabled. if test "$enable_failover" != "no"; then AC_DEFINE([FAILOVER_PROTOCOL], [1], [Define to include Failover Protocol support.]) fi # execute() support. AC_ARG_ENABLE(execute, AC_HELP_STRING([--enable-execute], [enable support for execute() in config (default is yes)])) # execute() is on by default, so define if it is not explicitly disabled. if test "$enable_execute" != "no" ; then AC_DEFINE([ENABLE_EXECUTE], [1], [Define to include execute() config language support.]) fi # Server tracing support. AC_ARG_ENABLE(tracing, AC_HELP_STRING([--enable-tracing], [enable support for server activity tracing (default is yes)])) # tracing is on by default, so define if it is not explicitly disabled. if test "$enable_tracing" != "no" ; then AC_DEFINE([TRACING], [1], [Define to include server activity tracing support.]) fi # Delayed-ack feature support (experimental). AC_ARG_ENABLE(delayed_ack, AC_HELP_STRING([--enable-delayed-ack], [queues multiple DHCPACK replies (default is no)])) if test "$enable_delayed_ack" = "yes"; then AC_DEFINE([DELAYED_ACK], [1], [Define to queue multiple DHCPACK replies per fsync.]) fi # DHCPv6 optional compile-time feature. AC_ARG_ENABLE(dhcpv6, AC_HELP_STRING([--enable-dhcpv6], [enable support for DHCPv6 (default is yes)])) # DHCPv6 is on by default, so define if it is not explicitly disabled. if test "$enable_dhcpv6" != "no"; then AC_DEFINE([DHCPv6], [1], [Define to 1 to include DHCPv6 support.]) fi # PARANOIA is off by default (until we can test it with all features) AC_ARG_ENABLE(paranoia, AC_HELP_STRING([--enable-paranoia], [enable support for chroot/setuid (default is no)])) AC_ARG_ENABLE(early_chroot, AC_HELP_STRING([--enable-early-chroot], [enable chrooting prior to configuration (default is no)])) # If someone enables early chroot, but does not enable paranoia, do so for # them. if test "$enable_paranoia" != "yes" && \ test "$enable_early_chroot" = "yes" ; then enable_paranoia="yes" fi if test "$enable_paranoia" = "yes" ; then AC_DEFINE([PARANOIA], [1], [Define to any value to include Ari's PARANOIA patch.]) fi if test "$enable_early_chroot" = "yes" ; then AC_DEFINE([EARLY_CHROOT], [1], [Define to any value to chroot() prior to loading config.]) fi AC_ARG_ENABLE(ipv4_pktinfo, AC_HELP_STRING([--enable-ipv4-pktinfo], [enable use of pktinfo on IPv4 sockets (default is no)])) if test "$enable_ipv4_pktinfo" = "yes"; then AC_DEFINE([USE_V4_PKTINFO], [1], [Define to 1 to enable IPv4 packet info support.]) fi AC_ARG_ENABLE(use_sockets, AC_HELP_STRING([--enable-use-sockets], [use the standard BSD socket API (default is no)])) if test "$enable_use_sockets" = "yes"; then AC_DEFINE([USE_SOCKETS], [1], [Define to 1 to use the standard BSD socket API.]) fi ### ### Path fun. Older versions of DHCP were installed in /usr/sbin, so we ### need to look there and potentially overwrite by default (but not if ### the user configures an alternate value). LOCALSTATEDIR is totally ### braindead. No one uses /usr/local/var/db/ nor /usr/local/var/run, and ### they would be insane for suggesting it. We need to look in /var/for ### 'db' and 'state/dhcp' for db files, and /var/run for pid files by ### default. ### AC_PREFIX_PROGRAM(dhcpd) # XXX - isn't there SOME WAY to default autoconf to /var instead of # /usr/local/var/no/one/has/this/please/stop/trying? case "$localstatedir" in '${prefix}/var') localstatedir=/var ;; esac # Allow specification of alternate state files AC_ARG_WITH(srv-lease-file, AC_HELP_STRING([--with-srv-lease-file=PATH], [File for dhcpd leases (default is LOCALSTATEDIR/db/dhcpd.leases)]), AC_DEFINE_UNQUOTED([_PATH_DHCPD_DB], ["$withval"], [File for dhcpd leases.])) echo -n "checking for dhcpd.leases location..." if [[ "x$with_srv_lease_file" = "x" ]] ; then if [[ -d "${localstatedir}/db" ]] ; then with_srv_lease_file="${localstatedir}/db/dhcpd.leases" elif [[ -d "${localstatedir}/state" ]] ; then if [[ -d "${localstatedir}/state/dhcp" ]] ; then with_srv_lease_file="${localstatedir}/state/dhcp/dhcpd.leases" else with_srv_lease_file="${localstatedir}/state/dhcpd.leases" fi elif [[ -d "${localstatedir}/lib" ]] ; then if [[ -d "${localstatedir}/lib/dhcp" ]] ; then with_srv_lease_file="${localstatedir}/lib/dhcp/dhcpd.leases" else with_srv_lease_file="${localstatedir}/lib/dhcpd.leases" fi elif [[ -d "${localstatedir}/etc" ]] ; then with_srv_lease_file="${localstatedir}/etc/dhcpd.leases" else with_srv_lease_file="/etc/dhcpd.leases" fi fi echo "$with_srv_lease_file" AC_ARG_WITH(srv6-lease-file, AC_HELP_STRING([--with-srv6-lease-file=PATH], [File for dhcpd6 leases (default is LOCALSTATEDIR/db/dhcpd6.leases)]), AC_DEFINE_UNQUOTED([_PATH_DHCPD6_DB], ["$withval"], [File for dhcpd6 leases.])) echo -n "checking for dhcpd6.leases location..." if [[ "x$with_srv6_lease_file" = "x" ]] ; then if [[ -d "${localstatedir}/db" ]] ; then with_srv6_lease_file="${localstatedir}/db/dhcpd6.leases" elif [[ -d "${localstatedir}/state" ]] ; then if [[ -d "${localstatedir}/state/dhcp" ]] ; then with_srv6_lease_file="${localstatedir}/state/dhcp/dhcpd6.leases" else with_srv6_lease_file="${localstatedir}/state/dhcpd6.leases" fi elif [[ -d "${localstatedir}/lib" ]] ; then if [[ -d "${localstatedir}/lib/dhcp" ]] ; then with_srv6_lease_file="${localstatedir}/lib/dhcp/dhcpd6.leases" else with_srv6_lease_file="${localstatedir}/lib/dhcpd6.leases" fi elif [[ -d "${localstatedir}/etc" ]] ; then with_srv6_lease_file="${localstatedir}/etc/dhcpd6.leases" else with_srv6_lease_file="/etc/dhcpd6.leases" fi fi echo "$with_srv6_lease_file" AC_ARG_WITH(cli-lease-file, AC_HELP_STRING([--with-cli-lease-file=PATH], [File for dhclient leases (default is LOCALSTATEDIR/db/dhclient.leases)]), AC_DEFINE_UNQUOTED([_PATH_DHCLIENT_DB], ["$withval"], [File for dhclient leases.])) echo -n "checking for dhclient.leases location..." if [[ "x$with_cli_lease_file" = "x" ]] ; then if [[ -d "${localstatedir}/db" ]] ; then with_cli_lease_file="${localstatedir}/db/dhclient.leases" elif [[ -d "${localstatedir}/state" ]] ; then if [[ -d "${localstatedir}/state/dhcp" ]] ; then with_cli_lease_file="${localstatedir}/state/dhcp/dhclient.leases" else with_cli_lease_file="${localstatedir}/state/dhclient.leases" fi elif [[ -d "${localstatedir}/lib" ]] ; then if [[ -d "${localstatedir}/lib/dhcp" ]] ; then with_cli_lease_file="${localstatedir}/lib/dhcp/dhclient.leases" else with_cli_lease_file="${localstatedir}/lib/dhclient.leases" fi elif [[ -d "${localstatedir}/etc" ]] ; then with_cli_lease_file="${localstatedir}/etc/dhclient.leases" else with_cli_lease_file="/etc/dhclient.leases" fi fi echo "$with_cli_lease_file" AC_ARG_WITH(cli6-lease-file, AC_HELP_STRING([--with-cli6-lease-file=PATH], [File for dhclient6 leases (default is LOCALSTATEDIR/db/dhclient6.leases)]), AC_DEFINE_UNQUOTED([_PATH_DHCLIENT6_DB], ["$withval"], [File for dhclient6 leases.])) echo -n "checking for dhclient6.leases location..." if [[ "x$with_cli6_lease_file" = "x" ]] ; then if [[ -d "${localstatedir}/db" ]] ; then with_cli6_lease_file="${localstatedir}/db/dhclient6.leases" elif [[ -d "${localstatedir}/state" ]] ; then if [[ -d "${localstatedir}/state/dhcp" ]] ; then with_cli6_lease_file="${localstatedir}/state/dhcp/dhclient6.leases" else with_cli6_lease_file="${localstatedir}/state/dhclient6.leases" fi elif [[ -d "${localstatedir}/lib" ]] ; then if [[ -d "${localstatedir}/lib/dhcp" ]] ; then with_cli6_lease_file="${localstatedir}/lib/dhcp/dhclient6.leases" else with_cli6_lease_file="${localstatedir}/lib/dhclient6.leases" fi elif [[ -d "${localstatedir}/etc" ]] ; then with_cli6_lease_file="${localstatedir}/etc/dhclient6.leases" else with_cli6_lease_file="/etc/dhclient6.leases" fi fi echo "$with_cli6_lease_file" AC_ARG_WITH(srv-pid-file, AC_HELP_STRING([--with-srv-pid-file=PATH], [File for dhcpd process information (default is LOCALSTATEDIR/run/dhcpd.pid)]), AC_DEFINE_UNQUOTED([_PATH_DHCPD_PID], ["$withval"], [File for dhcpd process information.])) AC_ARG_WITH(srv6-pid-file, AC_HELP_STRING([--with-srv6-pid-file=PATH], [File for dhcpd6 process information (default is LOCALSTATEDIR/run/dhcpd6.pid)]), AC_DEFINE_UNQUOTED([_PATH_DHCPD6_PID], ["$withval"], [File for dhcpd6 process information.])) AC_ARG_WITH(cli-pid-file, AC_HELP_STRING([--with-cli-pid-file=PATH], [File for dhclient process information (default is LOCALSTATEDIR/run/dhclient.pid)]), AC_DEFINE_UNQUOTED([_PATH_DHCLIENT_PID], ["$withval"], [File for dhclient process information.])) AC_ARG_WITH(cli6-pid-file, AC_HELP_STRING([--with-cli6-pid-file=PATH], [File for dhclient6 process information (default is LOCALSTATEDIR/run/dhclient6.pid)]), AC_DEFINE_UNQUOTED([_PATH_DHCLIENT6_PID], ["$withval"], [File for dhclient6 process information.])) AC_ARG_WITH(relay-pid-file, AC_HELP_STRING([--with-relay-pid-file=PATH], [File for dhcrelay process information (default is LOCALSTATEDIR/run/dhcrelay.pid)]), AC_DEFINE_UNQUOTED([_PATH_DHCRELAY_PID], ["$withval"], [File for dhcrelay process information.])) AC_ARG_WITH(relay6-pid-file, AC_HELP_STRING([--with-relay6-pid-file=PATH], [File for dhcrelay6 process information (default is LOCALSTATEDIR/run/dhcrelay6.pid)]), AC_DEFINE_UNQUOTED([_PATH_DHCRELAY6_PID], ["$withval"], [File for dhcrelay6 process information.])) # Check basic types. AC_TYPE_INT8_T AC_TYPE_INT16_T AC_TYPE_INT32_T AC_TYPE_INT64_T # Some systems need the u_intX_t types defined across. AC_CHECK_TYPE([u_int8_t], [], [ AC_TYPE_UINT8_T AC_DEFINE(u_int8_t, [uint8_t], [Define a type for 8-bit unsigned integers.]) ]) AC_CHECK_TYPE([u_int16_t], [], [ AC_TYPE_UINT16_T AC_DEFINE(u_int16_t, [uint16_t], [Define a type for 16-bit unsigned integers.]) ]) AC_CHECK_TYPE([u_int32_t], [], [ AC_TYPE_UINT32_T AC_DEFINE(u_int32_t, [uint32_t], [Define a type for 32-bit unsigned integers.]) ]) AC_CHECK_TYPE([u_int64_t], [], [ AC_TYPE_UINT64_T AC_DEFINE(u_int64_t, [uint64_t], [Define a type for 64-bit unsigned integers.]) ]) # see if ifaddrs.h is available AC_CHECK_HEADERS(ifaddrs.h) # figure out what IPv4 interface code to use AC_CHECK_HEADERS(linux/types.h) # needed for linux/filter.h on old systems AC_CHECK_HEADER(linux/filter.h, DO_LPF=1, , [ #ifdef HAVE_LINUX_TYPES_H #include #endif ]) if test -n "$DO_LPF" then AC_DEFINE([HAVE_LPF], [1], [Define to 1 to use the Linux Packet Filter interface code.]) else AC_CHECK_HEADER(sys/dlpi.h, DO_DLPI=1) if test -n "$DO_DLPI" then AC_DEFINE([HAVE_DLPI], [1], [Define to 1 to use DLPI interface code.]) else AC_CHECK_HEADER(net/bpf.h, DO_BPF=1) if test -n "$DO_BPF" then AC_DEFINE([HAVE_BPF], [1], [Define to 1 to use the Berkeley Packet Filter interface code.]) fi fi fi # SIOCGLIFCONF uses some transport structures. Trick is not all platforms # use the same structures. We like to use 'struct lifconf' and 'struct # lifreq', but we'll use these other structures if they're present. HPUX # does not define 'struct lifnum', but does use SIOCGLIFNUM - they use an # int value. # AC_MSG_CHECKING([for struct lifnum]) AC_TRY_COMPILE( [ #include #include #include ], [ struct lifnum a; ], [AC_MSG_RESULT(yes) AC_DEFINE([ISC_PLATFORM_HAVELIFNUM], [1], [Define to 1 if the system has 'struct lifnum'.])], [AC_MSG_RESULT(no)]) AC_MSG_CHECKING([for struct if_laddrconf]) AC_TRY_COMPILE( [ #include #include ], [ struct if_laddrconf a; ], [AC_MSG_RESULT(yes) AC_DEFINE([ISC_PLATFORM_HAVEIF_LADDRCONF], [1], [Define to 1 if the system has 'struct if_laddrconf'.])], [AC_MSG_RESULT(no)]) AC_MSG_CHECKING([for struct if_laddrreq]) AC_TRY_LINK( [#include #include ], [ struct if_laddrreq a; ], [AC_MSG_RESULT(yes) AC_DEFINE([ISC_PLATFORM_HAVEIF_LADDRREQ], [1], [Define to 1 if the system has 'struct if_laddrreq'.])], [AC_MSG_RESULT(no)]) # # check for GCC noreturn attribute # AC_MSG_CHECKING(for GCC noreturn attribute) AC_TRY_COMPILE([],[void foo() __attribute__((noreturn));], [AC_MSG_RESULT(yes) AC_DEFINE([ISC_DHCP_NORETURN], [__attribute__((noreturn))], [Define to the string for a noreturn attribute.])], [AC_MSG_RESULT(no) AC_DEFINE([ISC_DHCP_NORETURN], [], [Define to the string for a noreturn attribute.])]) # Look for optional headers. AC_CHECK_HEADERS(sys/socket.h net/if_dl.h net/if6.h regex.h) # Solaris needs some libraries for functions AC_SEARCH_LIBS(socket, [socket]) AC_SEARCH_LIBS(inet_ntoa, [nsl]) AC_SEARCH_LIBS(inet_aton, [socket nsl], , AC_DEFINE([NEED_INET_ATON], [1], [Define to 1 if the inet_aton() function is missing.])) # Check for a standalone regex library. AC_SEARCH_LIBS(regcomp, [regex]) # For HP/UX we need -lipv6 for if_nametoindex, perhaps others. AC_SEARCH_LIBS(if_nametoindex, [ipv6]) # check for /dev/random (declares HAVE_DEV_RANDOM) AC_CHECK_FILE(/dev/random, AC_DEFINE([HAVE_DEV_RANDOM], [1], [Define to 1 if you have the /dev/random file.])) # see if there is a "sa_len" field in our interface information structure AC_CHECK_MEMBER(struct sockaddr.sa_len, AC_DEFINE([HAVE_SA_LEN], [], [Define to 1 if the sockaddr structure has a length field.]), , [#include ]) # figure out pointer size AC_CHECK_SIZEOF(struct iaddr *, , [ #include "includes/inet.h" #include ]) # Solaris does not have the msg_control or msg_controlen members # in the msghdr structure unless you define: # # _XOPEN_SOURCE, _XOPEN_SOURCE_EXTENDED, and __EXTENSIONS__ # # See the "standards" man page for details. # # We check for the msg_control member, and if it is not found, we check # again with the appropriate defines added to the CFLAGS. (In order to # do this we have to remove the check from the cache, which is what the # "unset" is for.) AC_CHECK_MEMBER(struct msghdr.msg_control,, [CFLAGS="$CFLAGS -D_XOPEN_SOURCE -D_XOPEN_SOURCE_EXTENDED=1" CFLAGS="$CFLAGS -D__EXTENSIONS__" unset ac_cv_member_struct_msghdr_msg_control AC_CHECK_MEMBER(struct msghdr.msg_control,, [AC_MSG_ERROR([Missing msg_control member in msg_control structure.])], [ #include #include ]) ], [ #include #include ]) libbind= AC_ARG_WITH(libbind, AC_HELP_STRING([--with-libbind=PATH], [bind includes and libraries are in PATH (default is ./bind)]), use_libbind="$withval", use_libbind="no") case "$use_libbind" in yes) libbind="\${top_srcdir}/bind" ;; no) libbind="\${top_srcdir}/bind" ;; *) libbind="$use_libbind" ;; esac # OpenLDAP support. AC_ARG_WITH(ldap, AC_HELP_STRING([--with-ldap], [enable OpenLDAP support in dhcpd (default is no)]), [ldap=$withval], [ldap=no]) # OpenLDAP with SSL support. AC_ARG_WITH(ldapcrypto, AC_HELP_STRING([--with-ldapcrypto], [enable OpenLDAP crypto support in dhcpd (default is no)]), [ldapcrypto=$withval], [ldapcrypto=no]) # OpenLDAP support is disabled by default, if enabled then SSL support is an # extra optional that is also disabled by default. Enabling LDAP SSL support # implies enabling LDAP support. if test x$ldap = xyes || test x$ldapcrypto = xyes ; then AC_SEARCH_LIBS(ldap_initialize, [ldap], , AC_MSG_FAILURE([*** Cannot find ldap_initialize with -lldap - do you need to install an OpenLDAP2 Devel package?])) AC_SEARCH_LIBS(ber_pvt_opt_on, [lber], , AC_MSG_FAILURE([*** Cannot find ber_pvt_opt_on with -llber - do you need to install an OpenLDAP2 Devel package?])) if test x$ldapcrypto = xyes ; then AC_SUBST(LDAP_CFLAGS, ["-DLDAP_CONFIGURATION -DLDAP_USE_SSL"]) else AC_SUBST(LDAP_CFLAGS, ["-DLDAP_CONFIGURATION"]) fi fi # Append selected warning levels to CFLAGS before substitution (but after # AC_TRY_COMPILE & etc). CFLAGS="$CFLAGS $STD_CWARNINGS" # Try to add the bind include directory CFLAGS="$CFLAGS -I$libbind/include" AC_C_FLEXIBLE_ARRAY_MEMBER AC_OUTPUT([ Makefile client/Makefile common/Makefile common/tests/Makefile dhcpctl/Makefile dst/Makefile includes/Makefile omapip/Makefile relay/Makefile server/Makefile tests/Makefile ]) sh util/bindvar.sh dhcp-4.2.4/contrib/000777 000765 000024 00000000000 11757514243 014044 5ustar00sarstaff000000 000000 dhcp-4.2.4/depcomp000755 000765 000024 00000037100 11352520237 013745 0ustar00sarstaff000000 000000 #! /bin/sh # depcomp - compile a program generating dependencies as side-effects scriptversion=2005-07-09.11 # Copyright (C) 1999, 2000, 2003, 2004, 2005 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301, USA. # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Originally written by Alexandre Oliva . case $1 in '') echo "$0: No command. Try \`$0 --help' for more information." 1>&2 exit 1; ;; -h | --h*) cat <<\EOF Usage: depcomp [--help] [--version] PROGRAM [ARGS] Run PROGRAMS ARGS to compile a file, generating dependencies as side-effects. Environment variables: depmode Dependency tracking mode. source Source file read by `PROGRAMS ARGS'. object Object file output by `PROGRAMS ARGS'. DEPDIR directory where to store dependencies. depfile Dependency file to output. tmpdepfile Temporary file to use when outputing dependencies. libtool Whether libtool is used (yes/no). Report bugs to . EOF exit $? ;; -v | --v*) echo "depcomp $scriptversion" exit $? ;; esac if test -z "$depmode" || test -z "$source" || test -z "$object"; then echo "depcomp: Variables source, object and depmode must be set" 1>&2 exit 1 fi # Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po. depfile=${depfile-`echo "$object" | sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`} tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`} rm -f "$tmpdepfile" # Some modes work just like other modes, but use different flags. We # parameterize here, but still list the modes in the big case below, # to make depend.m4 easier to write. Note that we *cannot* use a case # here, because this file can only contain one case statement. if test "$depmode" = hp; then # HP compiler uses -M and no extra arg. gccflag=-M depmode=gcc fi if test "$depmode" = dashXmstdout; then # This is just like dashmstdout with a different argument. dashmflag=-xM depmode=dashmstdout fi case "$depmode" in gcc3) ## gcc 3 implements dependency tracking that does exactly what ## we want. Yay! Note: for some reason libtool 1.4 doesn't like ## it if -MD -MP comes after the -MF stuff. Hmm. "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile" exit $stat fi mv "$tmpdepfile" "$depfile" ;; gcc) ## There are various ways to get dependency output from gcc. Here's ## why we pick this rather obscure method: ## - Don't want to use -MD because we'd like the dependencies to end ## up in a subdir. Having to rename by hand is ugly. ## (We might end up doing this anyway to support other compilers.) ## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like ## -MM, not -M (despite what the docs say). ## - Using -M directly means running the compiler twice (even worse ## than renaming). if test -z "$gccflag"; then gccflag=-MD, fi "$@" -Wp,"$gccflag$tmpdepfile" stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" echo "$object : \\" > "$depfile" alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz ## The second -e expression handles DOS-style file names with drive letters. sed -e 's/^[^:]*: / /' \ -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile" ## This next piece of magic avoids the `deleted header file' problem. ## The problem is that when a header file which appears in a .P file ## is deleted, the dependency causes make to die (because there is ## typically no way to rebuild the header). We avoid this by adding ## dummy dependencies for each header file. Too bad gcc doesn't do ## this for us directly. tr ' ' ' ' < "$tmpdepfile" | ## Some versions of gcc put a space before the `:'. On the theory ## that the space means something, we add a space to the output as ## well. ## Some versions of the HPUX 10.20 sed can't process this invocation ## correctly. Breaking it into two sed invocations is a workaround. sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; hp) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; sgi) if test "$libtool" = yes; then "$@" "-Wp,-MDupdate,$tmpdepfile" else "$@" -MDupdate "$tmpdepfile" fi stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files echo "$object : \\" > "$depfile" # Clip off the initial element (the dependent). Don't try to be # clever and replace this with sed code, as IRIX sed won't handle # lines with more than a fixed number of characters (4096 in # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines; # the IRIX cc adds comments like `#:fec' to the end of the # dependency line. tr ' ' ' ' < "$tmpdepfile" \ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \ tr ' ' ' ' >> $depfile echo >> $depfile # The second pass generates a dummy entry for each header file. tr ' ' ' ' < "$tmpdepfile" \ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ >> $depfile else # The sourcefile does not contain any dependencies, so just # store a dummy comment line, to avoid errors with the Makefile # "include basename.Plo" scheme. echo "#dummy" > "$depfile" fi rm -f "$tmpdepfile" ;; aix) # The C for AIX Compiler uses -M and outputs the dependencies # in a .u file. In older versions, this file always lives in the # current directory. Also, the AIX compiler puts `$object:' at the # start of each line; $object doesn't have directory information. # Version 6 uses the directory in both cases. stripped=`echo "$object" | sed 's/\(.*\)\..*$/\1/'` tmpdepfile="$stripped.u" if test "$libtool" = yes; then "$@" -Wc,-M else "$@" -M fi stat=$? if test -f "$tmpdepfile"; then : else stripped=`echo "$stripped" | sed 's,^.*/,,'` tmpdepfile="$stripped.u" fi if test $stat -eq 0; then : else rm -f "$tmpdepfile" exit $stat fi if test -f "$tmpdepfile"; then outname="$stripped.o" # Each line is of the form `foo.o: dependent.h'. # Do two passes, one to just change these to # `$object: dependent.h' and one to simply `dependent.h:'. sed -e "s,^$outname:,$object :," < "$tmpdepfile" > "$depfile" sed -e "s,^$outname: \(.*\)$,\1:," < "$tmpdepfile" >> "$depfile" else # The sourcefile does not contain any dependencies, so just # store a dummy comment line, to avoid errors with the Makefile # "include basename.Plo" scheme. echo "#dummy" > "$depfile" fi rm -f "$tmpdepfile" ;; icc) # Intel's C compiler understands `-MD -MF file'. However on # icc -MD -MF foo.d -c -o sub/foo.o sub/foo.c # ICC 7.0 will fill foo.d with something like # foo.o: sub/foo.c # foo.o: sub/foo.h # which is wrong. We want: # sub/foo.o: sub/foo.c # sub/foo.o: sub/foo.h # sub/foo.c: # sub/foo.h: # ICC 7.1 will output # foo.o: sub/foo.c sub/foo.h # and will wrap long lines using \ : # foo.o: sub/foo.c ... \ # sub/foo.h ... \ # ... "$@" -MD -MF "$tmpdepfile" stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" # Each line is of the form `foo.o: dependent.h', # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'. # Do two passes, one to just change these to # `$object: dependent.h' and one to simply `dependent.h:'. sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile" # Some versions of the HPUX 10.20 sed can't process this invocation # correctly. Breaking it into two sed invocations is a workaround. sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; tru64) # The Tru64 compiler uses -MD to generate dependencies as a side # effect. `cc -MD -o foo.o ...' puts the dependencies into `foo.o.d'. # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put # dependencies in `foo.d' instead, so we check for that too. # Subdirectories are respected. dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` test "x$dir" = "x$object" && dir= base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` if test "$libtool" = yes; then # With Tru64 cc, shared objects can also be used to make a # static library. This mecanism is used in libtool 1.4 series to # handle both shared and static libraries in a single compilation. # With libtool 1.4, dependencies were output in $dir.libs/$base.lo.d. # # With libtool 1.5 this exception was removed, and libtool now # generates 2 separate objects for the 2 libraries. These two # compilations output dependencies in in $dir.libs/$base.o.d and # in $dir$base.o.d. We have to check for both files, because # one of the two compilations can be disabled. We should prefer # $dir$base.o.d over $dir.libs/$base.o.d because the latter is # automatically cleaned when .libs/ is deleted, while ignoring # the former would cause a distcleancheck panic. tmpdepfile1=$dir.libs/$base.lo.d # libtool 1.4 tmpdepfile2=$dir$base.o.d # libtool 1.5 tmpdepfile3=$dir.libs/$base.o.d # libtool 1.5 tmpdepfile4=$dir.libs/$base.d # Compaq CCC V6.2-504 "$@" -Wc,-MD else tmpdepfile1=$dir$base.o.d tmpdepfile2=$dir$base.d tmpdepfile3=$dir$base.d tmpdepfile4=$dir$base.d "$@" -MD fi stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" do test -f "$tmpdepfile" && break done if test -f "$tmpdepfile"; then sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile" # That's a tab and a space in the []. sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile" else echo "#dummy" > "$depfile" fi rm -f "$tmpdepfile" ;; #nosideeffect) # This comment above is used by automake to tell side-effect # dependency tracking mechanisms from slower ones. dashmstdout) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout, regardless of -o. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test $1 != '--mode=compile'; do shift done shift fi # Remove `-o $object'. IFS=" " for arg do case $arg in -o) shift ;; $object) shift ;; *) set fnord "$@" "$arg" shift # fnord shift # $arg ;; esac done test -z "$dashmflag" && dashmflag=-M # Require at least two characters before searching for `:' # in the target name. This is to cope with DOS-style filenames: # a dependency such as `c:/foo/bar' could be seen as target `c' otherwise. "$@" $dashmflag | sed 's:^[ ]*[^: ][^:][^:]*\:[ ]*:'"$object"'\: :' > "$tmpdepfile" rm -f "$depfile" cat < "$tmpdepfile" > "$depfile" tr ' ' ' ' < "$tmpdepfile" | \ ## Some versions of the HPUX 10.20 sed can't process this invocation ## correctly. Breaking it into two sed invocations is a workaround. sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; dashXmstdout) # This case only exists to satisfy depend.m4. It is never actually # run, as this mode is specially recognized in the preamble. exit 1 ;; makedepend) "$@" || exit $? # Remove any Libtool call if test "$libtool" = yes; then while test $1 != '--mode=compile'; do shift done shift fi # X makedepend shift cleared=no for arg in "$@"; do case $cleared in no) set ""; shift cleared=yes ;; esac case "$arg" in -D*|-I*) set fnord "$@" "$arg"; shift ;; # Strip any option that makedepend may not understand. Remove # the object too, otherwise makedepend will parse it as a source file. -*|$object) ;; *) set fnord "$@" "$arg"; shift ;; esac done obj_suffix="`echo $object | sed 's/^.*\././'`" touch "$tmpdepfile" ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@" rm -f "$depfile" cat < "$tmpdepfile" > "$depfile" sed '1,2d' "$tmpdepfile" | tr ' ' ' ' | \ ## Some versions of the HPUX 10.20 sed can't process this invocation ## correctly. Breaking it into two sed invocations is a workaround. sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" "$tmpdepfile".bak ;; cpp) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test $1 != '--mode=compile'; do shift done shift fi # Remove `-o $object'. IFS=" " for arg do case $arg in -o) shift ;; $object) shift ;; *) set fnord "$@" "$arg" shift # fnord shift # $arg ;; esac done "$@" -E | sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' | sed '$ s: \\$::' > "$tmpdepfile" rm -f "$depfile" echo "$object : \\" > "$depfile" cat < "$tmpdepfile" >> "$depfile" sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; msvisualcpp) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout, regardless of -o, # because we must use -o when running libtool. "$@" || exit $? IFS=" " for arg do case "$arg" in "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI") set fnord "$@" shift shift ;; *) set fnord "$@" "$arg" shift shift ;; esac done "$@" -E | sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::echo "`cygpath -u \\"\1\\"`":p' | sort | uniq > "$tmpdepfile" rm -f "$depfile" echo "$object : \\" > "$depfile" . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s:: \1 \\:p' >> "$depfile" echo " " >> "$depfile" . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s::\1\::p' >> "$depfile" rm -f "$tmpdepfile" ;; none) exec "$@" ;; *) echo "Unknown depmode $depmode" 1>&2 exit 1 ;; esac exit 0 # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-end: "$" # End: dhcp-4.2.4/dhcpctl/000777 000765 000024 00000000000 11757514244 014026 5ustar00sarstaff000000 000000 dhcp-4.2.4/doc/000777 000765 000024 00000000000 11757514243 013151 5ustar00sarstaff000000 000000 dhcp-4.2.4/dst/000777 000765 000024 00000000000 11757514244 013177 5ustar00sarstaff000000 000000 dhcp-4.2.4/includes/000777 000765 000024 00000000000 11757514243 014212 5ustar00sarstaff000000 000000 dhcp-4.2.4/install-sh000755 000765 000024 00000022021 11352520237 014370 0ustar00sarstaff000000 000000 #!/bin/sh # install - install a program, script, or datafile scriptversion=2005-05-14.22 # This originates from X11R5 (mit/util/scripts/install.sh), which was # later released in X11R6 (xc/config/util/install.sh) with the # following copyright and license. # # Copyright (C) 1994 X Consortium # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- # TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # # Except as contained in this notice, the name of the X Consortium shall not # be used in advertising or otherwise to promote the sale, use or other deal- # ings in this Software without prior written authorization from the X Consor- # tium. # # # FSF changes to this file are in the public domain. # # Calling this script install-sh is preferred over install.sh, to prevent # `make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. It can only install one file at a time, a restriction # shared with many OS's install programs. # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit="${DOITPROG-}" # put in absolute paths if you don't have them in your path; or use env. vars. mvprog="${MVPROG-mv}" cpprog="${CPPROG-cp}" chmodprog="${CHMODPROG-chmod}" chownprog="${CHOWNPROG-chown}" chgrpprog="${CHGRPPROG-chgrp}" stripprog="${STRIPPROG-strip}" rmprog="${RMPROG-rm}" mkdirprog="${MKDIRPROG-mkdir}" chmodcmd="$chmodprog 0755" chowncmd= chgrpcmd= stripcmd= rmcmd="$rmprog -f" mvcmd="$mvprog" src= dst= dir_arg= dstarg= no_target_directory= usage="Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE or: $0 [OPTION]... SRCFILES... DIRECTORY or: $0 [OPTION]... -t DIRECTORY SRCFILES... or: $0 [OPTION]... -d DIRECTORIES... In the 1st form, copy SRCFILE to DSTFILE. In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. In the 4th, create DIRECTORIES. Options: -c (ignored) -d create directories instead of installing files. -g GROUP $chgrpprog installed files to GROUP. -m MODE $chmodprog installed files to MODE. -o USER $chownprog installed files to USER. -s $stripprog installed files. -t DIRECTORY install into DIRECTORY. -T report an error if DSTFILE is a directory. --help display this help and exit. --version display version info and exit. Environment variables override the default commands: CHGRPPROG CHMODPROG CHOWNPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG " while test -n "$1"; do case $1 in -c) shift continue;; -d) dir_arg=true shift continue;; -g) chgrpcmd="$chgrpprog $2" shift shift continue;; --help) echo "$usage"; exit $?;; -m) chmodcmd="$chmodprog $2" shift shift continue;; -o) chowncmd="$chownprog $2" shift shift continue;; -s) stripcmd=$stripprog shift continue;; -t) dstarg=$2 shift shift continue;; -T) no_target_directory=true shift continue;; --version) echo "$0 $scriptversion"; exit $?;; *) # When -d is used, all remaining arguments are directories to create. # When -t is used, the destination is already specified. test -n "$dir_arg$dstarg" && break # Otherwise, the last argument is the destination. Remove it from $@. for arg do if test -n "$dstarg"; then # $@ is not empty: it contains at least $arg. set fnord "$@" "$dstarg" shift # fnord fi shift # arg dstarg=$arg done break;; esac done if test -z "$1"; then if test -z "$dir_arg"; then echo "$0: no input file specified." >&2 exit 1 fi # It's OK to call `install-sh -d' without argument. # This can happen when creating conditional directories. exit 0 fi for src do # Protect names starting with `-'. case $src in -*) src=./$src ;; esac if test -n "$dir_arg"; then dst=$src src= if test -d "$dst"; then mkdircmd=: chmodcmd= else mkdircmd=$mkdirprog fi else # Waiting for this to be detected by the "$cpprog $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if test ! -f "$src" && test ! -d "$src"; then echo "$0: $src does not exist." >&2 exit 1 fi if test -z "$dstarg"; then echo "$0: no destination specified." >&2 exit 1 fi dst=$dstarg # Protect names starting with `-'. case $dst in -*) dst=./$dst ;; esac # If destination is a directory, append the input filename; won't work # if double slashes aren't ignored. if test -d "$dst"; then if test -n "$no_target_directory"; then echo "$0: $dstarg: Is a directory" >&2 exit 1 fi dst=$dst/`basename "$src"` fi fi # This sed command emulates the dirname command. dstdir=`echo "$dst" | sed -e 's,/*$,,;s,[^/]*$,,;s,/*$,,;s,^$,.,'` # Make sure that the destination directory exists. # Skip lots of stat calls in the usual case. if test ! -d "$dstdir"; then defaultIFS=' ' IFS="${IFS-$defaultIFS}" oIFS=$IFS # Some sh's can't handle IFS=/ for some reason. IFS='%' set x `echo "$dstdir" | sed -e 's@/@%@g' -e 's@^%@/@'` shift IFS=$oIFS pathcomp= while test $# -ne 0 ; do pathcomp=$pathcomp$1 shift if test ! -d "$pathcomp"; then $mkdirprog "$pathcomp" # mkdir can fail with a `File exist' error in case several # install-sh are creating the directory concurrently. This # is OK. test -d "$pathcomp" || exit fi pathcomp=$pathcomp/ done fi if test -n "$dir_arg"; then $doit $mkdircmd "$dst" \ && { test -z "$chowncmd" || $doit $chowncmd "$dst"; } \ && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } \ && { test -z "$stripcmd" || $doit $stripcmd "$dst"; } \ && { test -z "$chmodcmd" || $doit $chmodcmd "$dst"; } else dstfile=`basename "$dst"` # Make a couple of temp file names in the proper directory. dsttmp=$dstdir/_inst.$$_ rmtmp=$dstdir/_rm.$$_ # Trap to clean up those temp files at exit. trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 trap '(exit $?); exit' 1 2 13 15 # Copy the file name to the temp name. $doit $cpprog "$src" "$dsttmp" && # and set any options; do chmod last to preserve setuid bits. # # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $cpprog $src $dsttmp" command. # { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } \ && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } \ && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } \ && { test -z "$chmodcmd" || $doit $chmodcmd "$dsttmp"; } && # Now rename the file to the real destination. { $doit $mvcmd -f "$dsttmp" "$dstdir/$dstfile" 2>/dev/null \ || { # The rename failed, perhaps because mv can't rename something else # to itself, or perhaps because mv is so ancient that it does not # support -f. # Now remove or move aside any old file at destination location. # We try this two ways since rm can't unlink itself on some # systems and the destination file might be busy for other # reasons. In this case, the final cleanup might fail but the new # file should still install successfully. { if test -f "$dstdir/$dstfile"; then $doit $rmcmd -f "$dstdir/$dstfile" 2>/dev/null \ || $doit $mvcmd -f "$dstdir/$dstfile" "$rmtmp" 2>/dev/null \ || { echo "$0: cannot unlink or rename $dstdir/$dstfile" >&2 (exit 1); exit 1 } else : fi } && # Now rename the file to the real destination. $doit $mvcmd "$dsttmp" "$dstdir/$dstfile" } } fi || { (exit 1); exit 1; } done # The final little trick to "correctly" pass the exit status to the exit trap. { (exit 0); exit 0 } # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-end: "$" # End: dhcp-4.2.4/LICENSE000644 000765 000024 00000001707 11741366353 013412 0ustar00sarstaff000000 000000 # Copyright (c) 2004-2012 by Internet Systems Consortium, Inc. ("ISC") # Copyright (c) 1995-2003 by Internet Software Consortium # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # # Internet Systems Consortium, Inc. # 950 Charter Street # Redwood City, CA 94063 # # https://www.isc.org/ dhcp-4.2.4/Makefile.am000644 000765 000024 00000002154 11352520236 014424 0ustar00sarstaff000000 000000 # # automake adds dependencies that we don't like, so we explicitly remove them # Makefile: # # We have a lot of files that we want shipped with the distribution. # EXTRA_DIST = RELNOTES LICENSE \ contrib/3.0b1-lease-convert contrib/dhclient-tz-exithook.sh \ contrib/dhcp.spec contrib/sethostname.sh contrib/solaris.init \ contrib/ms2isc/Registry.pm contrib/ms2isc/ms2isc.pl \ contrib/ms2isc/readme.txt contrib/ldap/dhcpd-conf-to-ldap \ contrib/ldap/dhcp.schema contrib/ldap/README.ldap \ doc/IANA-arp-parameters doc/Makefile doc/References.html \ doc/References.txt doc/References.xml doc/api+protocol \ doc/ja_JP.eucJP/dhclient-script.8 doc/ja_JP.eucJP/dhclient.8 \ doc/ja_JP.eucJP/dhclient.conf.5 doc/ja_JP.eucJP/dhclient.leases.5 \ doc/ja_JP.eucJP/dhcp-eval.5 doc/ja_JP.eucJP/dhcp-options.5 \ doc/examples/dhclient-dhcpv6.conf doc/examples/dhcpd-dhcpv6.conf \ util/bindvar.sh \ bind/Makefile bind/bind.tar.gz bind/version.tmp SUBDIRS = bind includes tests common dst omapip client dhcpctl relay server nobase_include_HEADERS = dhcpctl/dhcpctl.h dhcp-4.2.4/Makefile.in000644 000765 000024 00000050277 11757500152 014452 0ustar00sarstaff000000 000000 # Makefile.in generated by automake 1.10.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : subdir = . DIST_COMMON = README $(am__configure_deps) $(nobase_include_HEADERS) \ $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ $(top_srcdir)/configure depcomp install-sh missing ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ configure.lineno config.status.lineno mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/includes/config.h CONFIG_CLEAN_FILES = SOURCES = DIST_SOURCES = RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ html-recursive info-recursive install-data-recursive \ install-dvi-recursive install-exec-recursive \ install-html-recursive install-info-recursive \ install-pdf-recursive install-ps-recursive install-recursive \ installcheck-recursive installdirs-recursive pdf-recursive \ ps-recursive uninstall-recursive am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = `echo $$p | sed -e 's|^.*/||'`; am__installdirs = "$(DESTDIR)$(includedir)" nobase_includeHEADERS_INSTALL = $(install_sh_DATA) HEADERS = $(nobase_include_HEADERS) RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive ETAGS = etags CTAGS = ctags DIST_SUBDIRS = $(SUBDIRS) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) distdir = $(PACKAGE)-$(VERSION) top_distdir = $(distdir) am__remove_distdir = \ { test ! -d $(distdir) \ || { find $(distdir) -type d ! -perm -200 -exec chmod u+w {} ';' \ && rm -fr $(distdir); }; } DIST_ARCHIVES = $(distdir).tar.gz GZIP_ENV = --best distuninstallcheck_listfiles = find . -type f -print distcleancheck_listfiles = find . -type f -print ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ GREP = @GREP@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDAP_CFLAGS = @LDAP_CFLAGS@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_prefix_program = @ac_prefix_program@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build_alias = @build_alias@ builddir = @builddir@ byte_order = @byte_order@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host_alias = @host_alias@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ # # We have a lot of files that we want shipped with the distribution. # EXTRA_DIST = RELNOTES LICENSE \ contrib/3.0b1-lease-convert contrib/dhclient-tz-exithook.sh \ contrib/dhcp.spec contrib/sethostname.sh contrib/solaris.init \ contrib/ms2isc/Registry.pm contrib/ms2isc/ms2isc.pl \ contrib/ms2isc/readme.txt contrib/ldap/dhcpd-conf-to-ldap \ contrib/ldap/dhcp.schema contrib/ldap/README.ldap \ doc/IANA-arp-parameters doc/Makefile doc/References.html \ doc/References.txt doc/References.xml doc/api+protocol \ doc/ja_JP.eucJP/dhclient-script.8 doc/ja_JP.eucJP/dhclient.8 \ doc/ja_JP.eucJP/dhclient.conf.5 doc/ja_JP.eucJP/dhclient.leases.5 \ doc/ja_JP.eucJP/dhcp-eval.5 doc/ja_JP.eucJP/dhcp-options.5 \ doc/examples/dhclient-dhcpv6.conf doc/examples/dhcpd-dhcpv6.conf \ util/bindvar.sh \ bind/Makefile bind/bind.tar.gz bind/version.tmp SUBDIRS = bind includes tests common dst omapip client dhcpctl relay server nobase_include_HEADERS = dhcpctl/dhcpctl.h all: all-recursive .SUFFIXES: am--refresh: @: $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ echo ' cd $(srcdir) && $(AUTOMAKE) --foreign '; \ cd $(srcdir) && $(AUTOMAKE) --foreign \ && exit 0; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \ cd $(top_srcdir) && \ $(AUTOMAKE) --foreign Makefile .PRECIOUS: Makefile $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) $(SHELL) ./config.status --recheck $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(srcdir) && $(AUTOCONF) $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) install-nobase_includeHEADERS: $(nobase_include_HEADERS) @$(NORMAL_INSTALL) test -z "$(includedir)" || $(MKDIR_P) "$(DESTDIR)$(includedir)" @$(am__vpath_adj_setup) \ list='$(nobase_include_HEADERS)'; for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ $(am__vpath_adj) \ echo " $(nobase_includeHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(includedir)/$$f'"; \ $(nobase_includeHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(includedir)/$$f"; \ done uninstall-nobase_includeHEADERS: @$(NORMAL_UNINSTALL) @$(am__vpath_adj_setup) \ list='$(nobase_include_HEADERS)'; for p in $$list; do \ $(am__vpath_adj) \ echo " rm -f '$(DESTDIR)$(includedir)/$$f'"; \ rm -f "$(DESTDIR)$(includedir)/$$f"; \ done # This directory's subdirectories are mostly independent; you can cd # into them and run `make' without going through this Makefile. # To change the values of `make' variables: instead of editing Makefiles, # (1) if the variable is set in `config.status', edit `config.status' # (which will cause the Makefiles to be regenerated when you run `make'); # (2) otherwise, pass the desired values on the `make' command line. $(RECURSIVE_TARGETS): @failcom='exit 1'; \ for f in x $$MAKEFLAGS; do \ case $$f in \ *=* | --[!k]*);; \ *k*) failcom='fail=yes';; \ esac; \ done; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ list='$(SUBDIRS)'; for subdir in $$list; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ dot_seen=yes; \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" $(RECURSIVE_CLEAN_TARGETS): @failcom='exit 1'; \ for f in x $$MAKEFLAGS; do \ case $$f in \ *=* | --[!k]*);; \ *k*) failcom='fail=yes';; \ esac; \ done; \ dot_seen=no; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ rev=''; for subdir in $$list; do \ if test "$$subdir" = "."; then :; else \ rev="$$subdir $$rev"; \ fi; \ done; \ rev="$$rev ."; \ target=`echo $@ | sed s/-recursive//`; \ for subdir in $$rev; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done && test -z "$$fail" tags-recursive: list='$(SUBDIRS)'; for subdir in $$list; do \ test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ done ctags-recursive: list='$(SUBDIRS)'; for subdir in $$list; do \ test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ done ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) tags=; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ tags="$$tags $$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$tags $$unique; \ fi ctags: CTAGS CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) tags=; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$tags$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$tags $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && cd $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) $$here distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) $(am__remove_distdir) test -d $(distdir) || mkdir $(distdir) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ fi; \ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ else \ test -f $(distdir)/$$file \ || cp -p $$d/$$file $(distdir)/$$file \ || exit 1; \ fi; \ done list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ distdir=`$(am__cd) $(distdir) && pwd`; \ top_distdir=`$(am__cd) $(top_distdir) && pwd`; \ (cd $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$top_distdir" \ distdir="$$distdir/$$subdir" \ am__remove_distdir=: \ am__skip_length_check=: \ distdir) \ || exit 1; \ fi; \ done -find $(distdir) -type d ! -perm -777 -exec chmod a+rwx {} \; -o \ ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \ || chmod -R a+r $(distdir) dist-gzip: distdir tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz $(am__remove_distdir) dist-bzip2: distdir tardir=$(distdir) && $(am__tar) | bzip2 -9 -c >$(distdir).tar.bz2 $(am__remove_distdir) dist-lzma: distdir tardir=$(distdir) && $(am__tar) | lzma -9 -c >$(distdir).tar.lzma $(am__remove_distdir) dist-tarZ: distdir tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z $(am__remove_distdir) dist-shar: distdir shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz $(am__remove_distdir) dist-zip: distdir -rm -f $(distdir).zip zip -rq $(distdir).zip $(distdir) $(am__remove_distdir) dist dist-all: distdir tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz $(am__remove_distdir) # This target untars the dist file and tries a VPATH configuration. Then # it guarantees that the distribution is self-contained by making another # tarfile. distcheck: dist case '$(DIST_ARCHIVES)' in \ *.tar.gz*) \ GZIP=$(GZIP_ENV) gunzip -c $(distdir).tar.gz | $(am__untar) ;;\ *.tar.bz2*) \ bunzip2 -c $(distdir).tar.bz2 | $(am__untar) ;;\ *.tar.lzma*) \ unlzma -c $(distdir).tar.lzma | $(am__untar) ;;\ *.tar.Z*) \ uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ *.shar.gz*) \ GZIP=$(GZIP_ENV) gunzip -c $(distdir).shar.gz | unshar ;;\ *.zip*) \ unzip $(distdir).zip ;;\ esac chmod -R a-w $(distdir); chmod a+w $(distdir) mkdir $(distdir)/_build mkdir $(distdir)/_inst chmod a-w $(distdir) dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ && cd $(distdir)/_build \ && ../configure --srcdir=.. --prefix="$$dc_install_base" \ $(DISTCHECK_CONFIGURE_FLAGS) \ && $(MAKE) $(AM_MAKEFLAGS) \ && $(MAKE) $(AM_MAKEFLAGS) dvi \ && $(MAKE) $(AM_MAKEFLAGS) check \ && $(MAKE) $(AM_MAKEFLAGS) install \ && $(MAKE) $(AM_MAKEFLAGS) installcheck \ && $(MAKE) $(AM_MAKEFLAGS) uninstall \ && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ distuninstallcheck \ && chmod -R a-w "$$dc_install_base" \ && ({ \ (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ } || { rm -rf "$$dc_destdir"; exit 1; }) \ && rm -rf "$$dc_destdir" \ && $(MAKE) $(AM_MAKEFLAGS) dist \ && rm -rf $(DIST_ARCHIVES) \ && $(MAKE) $(AM_MAKEFLAGS) distcleancheck $(am__remove_distdir) @(echo "$(distdir) archives ready for distribution: "; \ list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x' distuninstallcheck: @cd $(distuninstallcheck_dir) \ && test `$(distuninstallcheck_listfiles) | wc -l` -le 1 \ || { echo "ERROR: files left after uninstall:" ; \ if test -n "$(DESTDIR)"; then \ echo " (check DESTDIR support)"; \ fi ; \ $(distuninstallcheck_listfiles) ; \ exit 1; } >&2 distcleancheck: distclean @if test '$(srcdir)' = . ; then \ echo "ERROR: distcleancheck can only run from a VPATH build" ; \ exit 1 ; \ fi @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ || { echo "ERROR: files left in build directory after distclean:" ; \ $(distcleancheck_listfiles) ; \ exit 1; } >&2 check-am: all-am check: check-recursive all-am: Makefile $(HEADERS) installdirs: installdirs-recursive installdirs-am: for dir in "$(DESTDIR)$(includedir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-recursive clean-am: clean-generic mostlyclean-am distclean: distclean-recursive -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -f Makefile distclean-am: clean-am distclean-generic distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive info: info-recursive info-am: install-data-am: install-nobase_includeHEADERS install-dvi: install-dvi-recursive install-exec-am: install-html: install-html-recursive install-info: install-info-recursive install-man: install-pdf: install-pdf-recursive install-ps: install-ps-recursive installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -rf $(top_srcdir)/autom4te.cache -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-generic pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: uninstall-nobase_includeHEADERS .MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) install-am \ install-strip .PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ all all-am am--refresh check check-am clean clean-generic \ ctags ctags-recursive dist dist-all dist-bzip2 dist-gzip \ dist-lzma dist-shar dist-tarZ dist-zip distcheck distclean \ distclean-generic distclean-tags distcleancheck distdir \ distuninstallcheck dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-nobase_includeHEADERS install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs installdirs-am maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-generic pdf \ pdf-am ps ps-am tags tags-recursive uninstall uninstall-am \ uninstall-nobase_includeHEADERS # # automake adds dependencies that we don't like, so we explicitly remove them # Makefile: # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: dhcp-4.2.4/missing000755 000765 000024 00000025406 11352520237 013775 0ustar00sarstaff000000 000000 #! /bin/sh # Common stub for a few missing GNU programs while installing. scriptversion=2005-06-08.21 # Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004, 2005 # Free Software Foundation, Inc. # Originally by Fran,cois Pinard , 1996. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301, USA. # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. if test $# -eq 0; then echo 1>&2 "Try \`$0 --help' for more information" exit 1 fi run=: # In the cases where this matters, `missing' is being run in the # srcdir already. if test -f configure.ac; then configure_ac=configure.ac else configure_ac=configure.in fi msg="missing on your system" case "$1" in --run) # Try to run requested program, and just exit if it succeeds. run= shift "$@" && exit 0 # Exit code 63 means version mismatch. This often happens # when the user try to use an ancient version of a tool on # a file that requires a minimum version. In this case we # we should proceed has if the program had been absent, or # if --run hadn't been passed. if test $? = 63; then run=: msg="probably too old" fi ;; -h|--h|--he|--hel|--help) echo "\ $0 [OPTION]... PROGRAM [ARGUMENT]... Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an error status if there is no known handling for PROGRAM. Options: -h, --help display this help and exit -v, --version output version information and exit --run try to run the given command, and emulate it if it fails Supported PROGRAM values: aclocal touch file \`aclocal.m4' autoconf touch file \`configure' autoheader touch file \`config.h.in' automake touch all \`Makefile.in' files bison create \`y.tab.[ch]', if possible, from existing .[ch] flex create \`lex.yy.c', if possible, from existing .c help2man touch the output file lex create \`lex.yy.c', if possible, from existing .c makeinfo touch the output file tar try tar, gnutar, gtar, then tar without non-portable flags yacc create \`y.tab.[ch]', if possible, from existing .[ch] Send bug reports to ." exit $? ;; -v|--v|--ve|--ver|--vers|--versi|--versio|--version) echo "missing $scriptversion (GNU Automake)" exit $? ;; -*) echo 1>&2 "$0: Unknown \`$1' option" echo 1>&2 "Try \`$0 --help' for more information" exit 1 ;; esac # Now exit if we have it, but it failed. Also exit now if we # don't have it and --version was passed (most likely to detect # the program). case "$1" in lex|yacc) # Not GNU programs, they don't have --version. ;; tar) if test -n "$run"; then echo 1>&2 "ERROR: \`tar' requires --run" exit 1 elif test "x$2" = "x--version" || test "x$2" = "x--help"; then exit 1 fi ;; *) if test -z "$run" && ($1 --version) > /dev/null 2>&1; then # We have it, but it failed. exit 1 elif test "x$2" = "x--version" || test "x$2" = "x--help"; then # Could not run --version or --help. This is probably someone # running `$TOOL --version' or `$TOOL --help' to check whether # $TOOL exists and not knowing $TOOL uses missing. exit 1 fi ;; esac # If it does not exist, or fails to run (possibly an outdated version), # try to emulate it. case "$1" in aclocal*) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified \`acinclude.m4' or \`${configure_ac}'. You might want to install the \`Automake' and \`Perl' packages. Grab them from any GNU archive site." touch aclocal.m4 ;; autoconf) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified \`${configure_ac}'. You might want to install the \`Autoconf' and \`GNU m4' packages. Grab them from any GNU archive site." touch configure ;; autoheader) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified \`acconfig.h' or \`${configure_ac}'. You might want to install the \`Autoconf' and \`GNU m4' packages. Grab them from any GNU archive site." files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}` test -z "$files" && files="config.h" touch_files= for f in $files; do case "$f" in *:*) touch_files="$touch_files "`echo "$f" | sed -e 's/^[^:]*://' -e 's/:.*//'`;; *) touch_files="$touch_files $f.in";; esac done touch $touch_files ;; automake*) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'. You might want to install the \`Automake' and \`Perl' packages. Grab them from any GNU archive site." find . -type f -name Makefile.am -print | sed 's/\.am$/.in/' | while read f; do touch "$f"; done ;; autom4te) echo 1>&2 "\ WARNING: \`$1' is needed, but is $msg. You might have modified some files without having the proper tools for further handling them. You can get \`$1' as part of \`Autoconf' from any GNU archive site." file=`echo "$*" | sed -n 's/.*--output[ =]*\([^ ]*\).*/\1/p'` test -z "$file" && file=`echo "$*" | sed -n 's/.*-o[ ]*\([^ ]*\).*/\1/p'` if test -f "$file"; then touch $file else test -z "$file" || exec >$file echo "#! /bin/sh" echo "# Created by GNU Automake missing as a replacement of" echo "# $ $@" echo "exit 0" chmod +x $file exit 1 fi ;; bison|yacc) echo 1>&2 "\ WARNING: \`$1' $msg. You should only need it if you modified a \`.y' file. You may need the \`Bison' package in order for those modifications to take effect. You can get \`Bison' from any GNU archive site." rm -f y.tab.c y.tab.h if [ $# -ne 1 ]; then eval LASTARG="\${$#}" case "$LASTARG" in *.y) SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'` if [ -f "$SRCFILE" ]; then cp "$SRCFILE" y.tab.c fi SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'` if [ -f "$SRCFILE" ]; then cp "$SRCFILE" y.tab.h fi ;; esac fi if [ ! -f y.tab.h ]; then echo >y.tab.h fi if [ ! -f y.tab.c ]; then echo 'main() { return 0; }' >y.tab.c fi ;; lex|flex) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified a \`.l' file. You may need the \`Flex' package in order for those modifications to take effect. You can get \`Flex' from any GNU archive site." rm -f lex.yy.c if [ $# -ne 1 ]; then eval LASTARG="\${$#}" case "$LASTARG" in *.l) SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'` if [ -f "$SRCFILE" ]; then cp "$SRCFILE" lex.yy.c fi ;; esac fi if [ ! -f lex.yy.c ]; then echo 'main() { return 0; }' >lex.yy.c fi ;; help2man) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified a dependency of a manual page. You may need the \`Help2man' package in order for those modifications to take effect. You can get \`Help2man' from any GNU archive site." file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'` if test -z "$file"; then file=`echo "$*" | sed -n 's/.*--output=\([^ ]*\).*/\1/p'` fi if [ -f "$file" ]; then touch $file else test -z "$file" || exec >$file echo ".ab help2man is required to generate this page" exit 1 fi ;; makeinfo) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified a \`.texi' or \`.texinfo' file, or any other file indirectly affecting the aspect of the manual. The spurious call might also be the consequence of using a buggy \`make' (AIX, DU, IRIX). You might want to install the \`Texinfo' package or the \`GNU make' package. Grab either from any GNU archive site." # The file to touch is that specified with -o ... file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'` if test -z "$file"; then # ... or it is the one specified with @setfilename ... infile=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'` file=`sed -n '/^@setfilename/ { s/.* \([^ ]*\) *$/\1/; p; q; }' $infile` # ... or it is derived from the source name (dir/f.texi becomes f.info) test -z "$file" && file=`echo "$infile" | sed 's,.*/,,;s,.[^.]*$,,'`.info fi # If the file does not exist, the user really needs makeinfo; # let's fail without touching anything. test -f $file || exit 1 touch $file ;; tar) shift # We have already tried tar in the generic part. # Look for gnutar/gtar before invocation to avoid ugly error # messages. if (gnutar --version > /dev/null 2>&1); then gnutar "$@" && exit 0 fi if (gtar --version > /dev/null 2>&1); then gtar "$@" && exit 0 fi firstarg="$1" if shift; then case "$firstarg" in *o*) firstarg=`echo "$firstarg" | sed s/o//` tar "$firstarg" "$@" && exit 0 ;; esac case "$firstarg" in *h*) firstarg=`echo "$firstarg" | sed s/h//` tar "$firstarg" "$@" && exit 0 ;; esac fi echo 1>&2 "\ WARNING: I can't seem to be able to run \`tar' with the given arguments. You may want to install GNU tar or Free paxutils, or check the command line arguments." exit 1 ;; *) echo 1>&2 "\ WARNING: \`$1' is needed, and is $msg. You might have modified some files without having the proper tools for further handling them. Check the \`README' file, it often tells you about the needed prerequisites for installing this package. You may also peek at any GNU archive site, in case some other package would contain this missing \`$1' program." exit 1 ;; esac exit 0 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-end: "$" # End: dhcp-4.2.4/omapip/000777 000765 000024 00000000000 11757514244 013672 5ustar00sarstaff000000 000000 dhcp-4.2.4/README000644 000765 000024 00000070151 11757476455 013300 0ustar00sarstaff000000 000000 Internet Systems Consortium DHCP Distribution Version 4.2.4 29 May 2012 README FILE You should read this file carefully before trying to install or use the ISC DHCP Distribution. TABLE OF CONTENTS 1 WHERE TO FIND DOCUMENTATION 2 RELEASE STATUS 3 BUILDING THE DHCP DISTRIBUTION 3.1 UNPACKING IT 3.2 CONFIGURING IT 3.2.1 DYNAMIC DNS UPDATES 3.2.2 LOCALLY DEFINED OPTIONS 3.3 BUILDING IT 4 INSTALLING THE DHCP DISTRIBUTION 5 USING THE DHCP DISTRIBUTION 5.1 FIREWALL RULES 5.2 LINUX 5.2.1 IF_TR.H NOT FOUND 5.2.2 SO_ATTACH_FILTER UNDECLARED 5.2.3 PROTOCOL NOT CONFIGURED 5.2.4 BROADCAST 5.2.6 IP BOOTP AGENT 5.2.7 MULTIPLE INTERFACES 5.3 SCO 5.4 HP-UX 5.5 ULTRIX 5.6 FreeBSD 5.7 NeXTSTEP 5.8 SOLARIS 5.8.1 Solaris 11 5.8.2 Other Solaris Items 5.9 AIX 5.10 MacOS X 6 SUPPORT 6.1 HOW TO REPORT BUGS WHERE TO FIND DOCUMENTATION Documentation for this software includes this README file, the RELNOTES file, and the manual pages, which are in the server, common, client and relay subdirectories. The README file (this file) includes late-breaking operational and system-specific information that you should read even if you don't want to read the manual pages, and that you should *certainly* read if you run into trouble. Internet standards relating to the DHCP protocol are listed in the References document that is available in html, txt and xml formats in doc/ subdirectory. You will have the best luck reading the manual pages if you build this software and then install it, although you can read them directly out of the distribution if you need to. DHCP server documentation is in the dhcpd man page. Information about the DHCP server lease database is in the dhcpd.leases man page. Server configuration documentation is in the dhcpd.conf man page as well as the dhcp-options man page. A sample DHCP server configuration is in the file server/dhcpd.conf. The source for the dhcpd, dhcpd.leases and dhcpd.conf man pages is in the server/ sub- directory in the distribution. The source for the dhcp-options.5 man page is in the common/ subdirectory. DHCP Client documentation is in the dhclient man page. DHCP client configuration documentation is in the dhclient.conf man page and the dhcp-options man page. The DHCP client configuration script is documented in the dhclient-script man page. The format of the DHCP client lease database is documented in the dhclient.leases man page. The source for all these man pages is in the client/ subdirectory in the distribution. In addition, the dhcp-options man page should be referred to for information about DHCP options. DHCP relay agent documentation is in the dhcrelay man page, the source for which is distributed in the relay/ subdirectory. To read installed manual pages, use the man command. Type "man page" where page is the name of the manual page. This will only work if you have installed the ISC DHCP distribution using the ``make install'' command (described later). If you want to read manual pages that aren't installed, you can type ``nroff -man page |more'' where page is the filename of the unformatted manual page. The filename of an unformatted manual page is the name of the manual page, followed by '.', followed by some number - 5 for documentation about files, and 8 for documentation about programs. For example, to read the dhcp-options man page, you would type ``nroff -man common/dhcp-options.5 |more'', assuming your current working directory is the top level directory of the ISC DHCP Distribution. Please note that the pathnames of files to which our manpages refer will not be correct for your operating system until after you iterate 'make install' (so if you're reading a manpage out of the source directory, it may not have up-to-date information). RELEASE STATUS This is ISC DHCP 4.2.4, a maintenance release containing patches. In this release, the DHCPv6 server should be fully functional on Linux, Solaris, or any BSD. The DHCPv6 client should be similarly functional except on Solaris. The DHCPv4 server, relay, and client, should be fully functional on Linux, Solaris, any BSD, HPUX, SCO, NextSTEP, and Irix. If you are running the DHCP distribution on a machine which is a firewall, or if there is a firewall between your DHCP server(s) and DHCP clients, please read the section on firewalls which appears later in this document. If you wish to run the DHCP Distribution on Linux, please see the Linux-specific notes later in this document. If you wish to run on an SCO release, please see the SCO-specific notes later in this document. You particularly need to read these notes if you intend to support Windows 95 clients. If you are running HP-UX or Ultrix, please read the notes for those operating systems below. If you are running NeXTSTEP, please see the notes on NeXTSTEP below. If you start dhcpd and get a message, "no free bpf", that means you need to configure the Berkeley Packet Filter into your operating system kernel. On NetBSD, FreeBSD and BSD/os, type ``man bpf'' for information. On Digital Unix, type ``man pfilt''. BUILDING THE DHCP DISTRIBUTION UNPACKING IT To build the DHCP Distribution, unpack the compressed tar file using the tar utility and the gzip command - type something like: gunzip dhcp-4.2.4.tar.gz tar xvf dhcp-4.2.4.tar CONFIGURING IT Now, cd to the dhcp-4.2.4 subdirectory that you've just created and configure the source tree by typing: ./configure If the configure utility can figure out what sort of system you're running on, it will create a custom Makefile for you for that system; otherwise, it will complain. If it can't figure out what system you are using, that system is not supported - you are on your own. DYNAMIC DNS UPDATES A fully-featured implementation of dynamic DNS updates is included in this release. It uses libraries from BIND and, to avoid issues with different versions, includes the necessary BIND version. The appropriate BIND libraries will be compiled and installed in the bind subdirectory as part of the make step. In order to build the necessary libraries you will need to have "gmake" available on your build system. There is documentation for the DDNS support in the dhcpd.conf manual page - see the beginning of this document for information on finding manual pages. LOCALLY DEFINED OPTIONS In previous versions of the DHCP server there was a mechanism whereby options that were not known by the server could be configured using a name made up of the option code number and an identifier: "option-nnn" This is no longer supported, because it is not future- proof. Instead, if you want to use an option that the server doesn't know about, you must explicitly define it using the method described in the dhcp-options man page under the DEFINING NEW OPTIONS heading. BUILDING IT Once you've run configure, just type ``make'', and after a while you should have a dhcp server. If you get compile errors on one of the supported systems mentioned earlier, please let us know. If you get warnings, it's not likely to be a problem - the DHCP server compiles completely warning-free on as many architectures as we can manage, but there are a few for which this is difficult. If you get errors on a system not mentioned above, you will need to do some programming or debugging on your own to get the DHCP Distribution working. INSTALLING THE DHCP DISTRIBUTION Once you have successfully gotten the DHCP Distribution to build, you can install it by typing ``make install''. If you already have an old version of the DHCP Distribution installed, you may want to save it before typing ``make install''. USING THE DHCP DISTRIBUTION FIREWALL RULES If you are running the DHCP server or client on a computer that's also acting as a firewall, you must be sure to allow DHCP packets through the firewall. In particular, your firewall rules _must_ allow packets from IP address 0.0.0.0 to IP address 255.255.255.255 from UDP port 68 to UDP port 67 through. They must also allow packets from your local firewall's IP address and UDP port 67 through to any address your DHCP server might serve on UDP port 68. Finally, packets from relay agents on port 67 to the DHCP server on port 67, and vice versa, must be permitted. We have noticed that on some systems where we are using a packet filter, if you set up a firewall that blocks UDP port 67 and 68 entirely, packets sent through the packet filter will not be blocked. However, unicast packets will be blocked. This can result in strange behaviour, particularly on DHCP clients, where the initial packet exchange is broadcast, but renewals are unicast - the client will appear to be unable to renew until it starts broadcasting its renewals, and then suddenly it'll work. The fix is to fix the firewall rules as described above. PARTIAL SERVERS If you have a server that is connected to two networks, and you only want to provide DHCP service on one of those networks (e.g., you are using a cable modem and have set up a NAT router), if you don't write any subnet declaration for the network you aren't supporting, the DHCP server will ignore input on that network interface if it can. If it can't, it will refuse to run - some operating systems do not have the capability of supporting DHCP on machines with more than one interface, and ironically this is the case even if you don't want to provide DHCP service on one of those interfaces. LINUX There are three big LINUX issues: the all-ones broadcast address, Linux 2.1 ip_bootp_agent enabling, and operations with more than one network interface. There are also two potential compilation/runtime problems for Linux 2.1/2.2: the "SO_ATTACH_FILTER undeclared" problem and the "protocol not configured" problem. LINUX: PROTOCOL NOT CONFIGURED If you get the following message, it's because your kernel doesn't have the linux packetfilter or raw packet socket configured: Make sure CONFIG_PACKET (Packet socket) and CONFIG_FILTER (Socket Filtering) are enabled in your kernel configuration If this happens, you need to configure your Linux kernel to support Socket Filtering and the Packet socket, or to select a kernel provided by your Linux distribution that has these enabled (virtually all modern ones do by default). LINUX: BROADCAST If you are running a recent version of Linux, this won't be a problem, but on older versions of Linux (kernel versions prior to 2.2), there is a potential problem with the broadcast address being sent incorrectly. In order for dhcpd to work correctly with picky DHCP clients (e.g., Windows 95), it must be able to send packets with an IP destination address of 255.255.255.255. Unfortunately, Linux changes an IP destination of 255.255.255.255 into the local subnet broadcast address (here, that's 192.5.5.223). This isn't generally a problem on Linux 2.2 and later kernels, since we completely bypass the Linux IP stack, but on old versions of Linux 2.1 and all versions of Linux prior to 2.1, it is a problem - pickier DHCP clients connected to the same network as the ISC DHCP server or ISC relay agent will not see messages from the DHCP server. It *is* possible to run into trouble with this on Linux 2.2 and later if you are running a verson of the DHCP server that was compiled on a Linux 2.0 system, though. It is possible to work around this problem on some versions of Linux by creating a host route from your network interface address to 255.255.255.255. The command you need to use to do this on Linux varies from version to version. The easiest version is: route add -host 255.255.255.255 dev eth0 On some older Linux systems, you will get an error if you try to do this. On those systems, try adding the following entry to your /etc/hosts file: 255.255.255.255 all-ones Then, try: route add -host all-ones dev eth0 Another route that has worked for some users is: route add -net 255.255.255.0 dev eth0 If you are not using eth0 as your network interface, you should specify the network interface you *are* using in your route command. LINUX: IP BOOTP AGENT Some versions of the Linux 2.1 kernel apparently prevent dhcpd from working unless you enable it by doing the following: echo 1 >/proc/sys/net/ipv4/ip_bootp_agent LINUX: MULTIPLE INTERFACES Very old versions of the Linux kernel do not provide a networking API that allows dhcpd to operate correctly if the system has more than one broadcast network interface. However, Linux 2.0 kernels with version numbers greater than or equal to 2.0.31 add an API feature: the SO_BINDTODEVICE socket option. If SO_BINDTODEVICE is present, it is possible for dhcpd to operate on Linux with more than one network interface. In order to take advantage of this, you must be running a 2.0.31 or greater kernel, and you must have 2.0.31 or later system headers installed *before* you build the DHCP Distribution. We have heard reports that you must still add routes to 255.255.255.255 in order for the all-ones broadcast to work, even on 2.0.31 kernels. In fact, you now need to add a route for each interface. Hopefully the Linux kernel gurus will get this straight eventually. Linux 2.1 and later kernels do not use SO_BINDTODEVICE or require the broadcast address hack, but do support multiple interfaces, using the Linux Packet Filter. LINUX: OpenWrt DHCP 4.1 has been tested on OpenWrt 7.09 and 8.09. In keeping with standard practice, client/scripts now includes a dhclient-script file for OpenWrt. However, this is not sufficient by itself to run dhcp on OpenWrt; a full OpenWrt package for DHCP is available at ftp://ftp.isc.org/isc/dhcp/dhcp-4.1.0-openwrt.tar.gz LINUX: 802.1q VLAN INTERFACES If you're using 802.1q vlan interfaces on Linux, it is necessary to vconfig the subinterface(s) to rewrite the 802.1q information out of packets received by the dhcpd daemon via LPF: vconfig set_flag eth1.523 1 1 Note that this may affect the performance of your system, since the Linux kernel must rewrite packets received via this interface. For more information, consult the vconfig man pages. SCO ISC DHCP will now work correctly on newer versions of SCO out of the box (tested on OpenServer 5.05b, assumed to work on UnixWare 7). Older versions of SCO have the same problem as Linux (described earlier). The thing is, SCO *really* doesn't want to let you add a host route to the all-ones broadcast address. You can try the following: ifconfig net0 xxx.xxx.xxx.xxx netmask 0xNNNNNNNN broadcast 255.255.255.255 If this doesn't work, you can also try the following strange hack: ifconfig net0 alias 10.1.1.1 netmask 8.0.0.0 Apparently this works because of an interaction between SCO's support for network classes and the weird netmask. The 10.* network is just a dummy that can generally be assumed to be safe. Don't ask why this works. Just try it. If it works for you, great. HP-UX HP-UX has the same problem with the all-ones broadcast address that SCO and Linux have. One user reported that adding the following to /etc/rc.config.d/netconf helped (you may have to modify this to suit your local configuration): INTERFACE_NAME[0]=lan0 IP_ADDRESS[0]=1.1.1.1 SUBNET_MASK[0]=255.255.255.0 BROADCAST_ADDRESS[0]="255.255.255.255" LANCONFIG_ARGS[0]="ether" DHCP_ENABLE[0]=0 ULTRIX Now that we have Ultrix packet filter support, the DHCP Distribution on Ultrix should be pretty trouble-free. However, one thing you do need to be aware of is that it now requires that the pfilt device be configured into your kernel and present in /dev. If you type ``man packetfilter'', you will get some information on how to configure your kernel for the packet filter (if it isn't already) and how to make an entry for it in /dev. FreeBSD Versions of FreeBSD prior to 2.2 have a bug in BPF support in that the ethernet driver swaps the ethertype field in the ethernet header downstream from BPF, which corrupts the output packet. If you are running a version of FreeBSD prior to 2.2, and you find that dhcpd can't communicate with its clients, you should #define BROKEN_FREEBSD_BPF in site.h and recompile. Modern versions of FreeBSD include the ISC DHCP 3.0 client as part of the base system, and the full distribution (for the DHCP server and relay agent) is available from the Ports Collection in /usr/ports/net/isc-dhcp3, or as a package on FreeBSD installation CDROMs. NeXTSTEP The NeXTSTEP support uses the NeXTSTEP Berkeley Packet Filter extension, which is not included in the base NextStep system. You must install this extension in order to get dhcpd or dhclient to work. SOLARIS There are two known issues seen when compiling using the Sun compiler. The first is that older Sun compilers generate an error on some of our uses of the flexible array option. Newer versions only generate a warning, which can be safely ignored. If you run into this error ("type of struct member "buf" can not be derived from structure with flexible array member"), upgrade your tools to Oracle Solaris Studio (previously Sun Studio) 12 or something newer. The second is the interaction between the configure script and the makefiles for the Bind libraries. Currently we don't pass all environment variables between the DHCP configure and the Bind configure. If you attempt to specify the compiler you wish to use like this: CC=/opt/SUNWspro/bin/cc ./configure "make" may not build the Bind libraries with that compiler. In order to use the same compiler for Bind and DHCP we suggest the following commands: CC=/opt/SUNWspro/bin/cc ./configure CC=/opt/SUNWspro/bin/cc make Solaris 11 We have integrated a patch from Oracle to use sockets instead of DLPI on Solaris 11. This functionality was written for use with Solaris Studio 12.2 and requires the system/header package. By default this code is disabled in order to minimize disruptions for current users. In order to enable this code you will need to enable both USE_SOCKETS and USE_V4_PKTINFO as part of the configuration step. The command line would be something like: ./configure --enable-use-sockets --enable-ipv4-pktinfo Other Solaris Items One problem which has been observed and is not fixed in this patchlevel has to do with using DLPI on Solaris machines. The symptom of this problem is that the DHCP server never receives any requests. This has been observed with Solaris 2.6 and Solaris 7 on Intel x86 systems, although it may occur with other systems as well. If you encounter this symptom, and you are running the DHCP server on a machine with a single broadcast network interface, you may wish to edit the includes/site.h file and uncomment the #define USE_SOCKETS line. Then type ``make clean; make''. As an alternative workaround, it has been reported that running 'snoop' will cause the dhcp server to start receiving packets. So the practice reported to us is to run snoop at dhcpd startup time, with arguments to cause it to receive one packet and exit. snoop -c 1 udp port 67 > /dev/null & The DHCP client on Solaris will only work with DLPI. If you run it and it just keeps saying it's sending DHCPREQUEST packets, but never gets a response, you may be having DLPI trouble as described above. If so, we have no solution to offer at this time, aside from the above workaround which should also work here. Also, because Solaris requires you to "plumb" an interface before it can be detected by the DHCP client, you must either specify the name(s) of the interface(s) you want to configure on the command line, or must plumb the interfaces prior to invoking the DHCP client. This can be done with ``ifconfig iface plumb'', where iface is the name of the interface (e.g., ``ifconfig hme0 plumb''). It should be noted that Solaris versions from 2.6 onward include a DHCP client that you can run with ``/sbin/ifconfig iface dhcp start'' rather than using the ISC DHCP client, including DHCPv6. Consequently, we don't believe there is a need for the client to run on Solaris, and have not engineered the needed DHCPv6 modifications for the dhclient-script. If you feel this is in error, or have a need, please contact us. AIX The AIX support uses the BSD socket API, which cannot differentiate on which network interface a broadcast packet was received; thus the DHCP server and relay will work only on a single interface. (They do work on multi-interface machines if configured to listen on only one of the interfaces.) We have reports of Windows XP clients having difficutly retrieving addresses from a server running on an AIX machine. This issue was traced to the client requiring messages be sent to the all ones broadcast address (255.255.255.255) while the AIX server was sending to 192.168.0.255. You may be able to solve this by including a relay between the client and server with the relay configured to use a broadcast of all-ones. A second option that worked for AIX 5.1 but doesn't seem to work for AIX 5.3 was to: create a host file entry for all-ones (255.255.255.255) and then add a route: route add -host all-ones -interface The ISC DHCP distribution does not include a dhclient-script for AIX-- AIX comes with a DHCP client. Contribution of a working dhclient-script for AIX would be welcome. MacOS X The MacOS X system uses a TCP/IP stack derived from FreeBSD with a user-friendly interface named the System Configuration Framework. As it includes a builtin DHCPv4 client (you are better just using that), this text is only about the DHCPv6 client (``dhclient -6 ...''). The DNS configuration (domain search list and name servers' addresses) is managed by a System Configuration agent, not by /etc/resolv.conf (which is a link to /var/run/resolv.conf, which itself only reflects the internal state; the System Configuration framework's Dynamic Store). This means that modifying resolv.conf directly doesn't have the intended effect, instead the macos script sample creates its own resolv.conf.dhclient6 in /var/run, and inserts the contents of this file into the Dynamic Store. When updating the address configuration the System Configuration framework expects the prefix and a default router along with the configured address. As this extra information is not available via the DHCPv6 protocol the System Configuration framework isn't usable for address configuration, instead ifconfig is used directly. Note the Dynamic Store (from which /var/run/resolv.conf is built) is recomputed from scratch when the current location/set is changed. Running the dhclient-script reinstalls the resolv.conf.dhclient6 configuration. SUPPORT The Internet Systems Consortium DHCP server is developed and distributed by ISC in the public trust, thanks to the generous donations of its sponsors. ISC now also offers commercial quality support contracts for ISC DHCP, more information about ISC Support Contracts can be found at the following URL: https://www.isc.org/services/support/ Please understand that we may not respond to support inquiries unless you have a support contract. ISC will continue its practice of always responding to critical items that effect the entire community, and responding to all other requests for support upon ISC's mailing lists on a best-effort basis. However, ISC DHCP has attracted a fairly sizable following on the Internet, which means that there are a lot of knowledgeable users who may be able to help you if you get stuck. These people generally read the dhcp-users@isc.org mailing list. Be sure to provide as much detail in your query as possible. If you are going to use ISC DHCP, you should probably subscribe to the dhcp-users or dhcp-announce mailing lists. WHERE TO SEND FEATURE REQUESTS: We like to hear your feedback. We may not respond to it all the time, but we do read it. If ISC DHCP doesn't work well for you, or you have an idea that would improve it for your use, please send your suggestion to dhcp-suggest@isc.org. This is also an excellent place to send patches that add new features. WHERE TO REPORT BUGS: If you want the act of sending in a bug report to result in you getting help in the form of a fixed piece of software, you are asking for help. Your bug report is helpful to us, but fundamentally you are making a support request, so please use the addresses described in the previous paragraphs. If you are _sure_ that your problem is a bug, and not user error, or if your bug report includes a patch, you can send it to our ticketing system at dhcp-bugs@isc.org. If you have not received a notice that the ticket has been resolved, then we're still working on it. PLEASE DO NOT REPORT BUGS IN OLD SOFTWARE RELEASES! Fetch the latest release and see if the bug is still in that version of the software, and if it is still present, _then_ report it. ISC release versions always have three numbers, for example: 1.2.3. The 'major release' is 1 here, the 'minor release' is 2, and the 'maintenance release' is 3. ISC will accept bug reports against the most recent two major.minor releases: for example, 1.0.0 and 0.9.0, but not 0.8.* or prior. PLEASE take a moment to determine where the ISC DHCP distribution that you're using came from. ISC DHCP is sometimes heavily modified by integrators in various operating systems - it's not that we feel that our software is perfect and incapable of having bugs, but rather that it is very frustrating to find out after many days trying to help someone that the sources you're looking at aren't what they're running. When in doubt, please retrieve the source distribution from ISC's web page and install it. HOW TO REPORT BUGS OR REQUEST HELP When you report bugs or ask for help, please provide us complete information. A list of information we need follows. Please read it carefully, and put all the information you can into your initial bug report. This will save us a great deal of time and more informative bug reports are more likely to get handled more quickly overall. 1. The specific operating system name and version of the machine on which the DHCP server or client is running. 2. The specific operating system name and version of the machine on which the client is running, if you are having trouble getting a client working with the server. 3. If you're running Linux, the version number we care about is the kernel version and maybe the library version, not the distribution version - e.g., while we don't mind knowing that you're running Redhat version mumble.foo, we must know what kernel version you're running, and it helps if you can tell us what version of the C library you're running, although if you don't know that off the top of your head it may be hard for you to figure it out, so don't go crazy trying. 4. The specific version of the DHCP distribution you're running, as reported by dhcpd -t. 5. Please explain the problem carefully, thinking through what you're saying to ensure that you don't assume we know something about your situation that we don't know. 6. Include your dhcpd.conf and dhcpd.leases file as MIME attachments if they're not over 100 kilobytes in size each. If they are this large, please make them available to us eg via a hidden http:// URL or FTP site. If you're not comfortable releasing this information due to sensitive contents, you may encrypt the file to our release signing key, available on our website. 7. Include a log of your server or client running until it encounters the problem - for example, if you are having trouble getting some client to get an address, restart the server with the -d flag and then restart the client, and send us what the server prints. Likewise, with the client, include the output of the client as it fails to get an address or otherwise does the wrong thing. Do not leave out parts of the output that you think aren't interesting. 8. If the client or server is dumping core, please run the debugger and get a stack trace, and include that in your bug report. For example, if your debugger is gdb, do the following: gdb dhcpd dhcpd.core (gdb) where [...] (gdb) quit This assumes that it's the dhcp server you're debugging, and that the core file is in dhcpd.core. Please see https://www.isc.org/software/dhcp/ for details on how to subscribe to the ISC DHCP mailing lists. dhcp-4.2.4/relay/000777 000765 000024 00000000000 11757514244 013521 5ustar00sarstaff000000 000000 dhcp-4.2.4/RELNOTES000644 000765 000024 00000412250 11757476455 013576 0ustar00sarstaff000000 000000 Internet Systems Consortium DHCP Distribution Version 4.2.4 29 May 2012 Release Notes NEW FEATURES ISC DHCP 4.2.x includes features that were not included in DHCP 4.1.x. These include: Processing the DHCP to DNS server transactions in an asynchronous fashion. The DHCP server or client can now continue with its processing while awaiting replies from the DNS server. There are a number of DHCPv6 limitations and features missing in this release, which will be addressed in the future: - Only Solaris, Linux, FreeBSD, NetBSD, and OpenBSD are supported. - DHCPv6 includes human-readable text in status code messages, in English. A method to reconfigure or support other languages would be preferable. - The "host-identifier" option is limited to a simple token. - The client and server can only operate DHCPv4 or DHCPv6 at a time, not both. To use both protocols simultaneously, two instances of the relevant daemon are required, one with the '-6' command line option. For information on how to install, configure and run this software, as well as how to find documentation and report bugs, please consult the README file. ISC DHCP uses standard GNU configure for installation. Please review the output of "./configure --help" to see what options are available. The system has only been tested on Linux, FreeBSD, and Solaris, and may not work on other platforms. Please report any problems and suggested fixes to . Changes since 4.2.4rc1 - Rotate the lease file when running in v6 mode. Thanks to Christoph Moench-Tegeder at Astaro for the report and the first version of the patch. [ISC-Bugs #24887] Changes since 4.2.4b1 - None Changes since 4.2.3 ! Add a check for a null pointer before calling the regexec function. Without this check we could, under some circumstances, pass a null pointer to the regexec function causing it to segfault. Thanks to a report from BlueCat Networks. [ISC-Bugs #26704]. CVE: CVE-2011-4539 ! Modify the DDNS handling code. In a previous patch we added logging code to the DDNS handling. This code included a bug that caused it to attempt to dereference a NULL pointer and eventually segfault. While reviewing the code as we addressed this problem, we determined that some of the updates to the lease structures would not work as planned since the structures being updated were in the process of being freed: these updates were removed. In addition we removed an incorrect call to the DDNS removal function that could cause a failure during the removal of DDNS information from the DNS server. Thanks to Jasper Jongmans for reporting this issue. [ISC-Bugs #27078] CVE: CVE-2011-4868 - Fixed the code that checks if an address the server is planning to hand out is in a reserved range. This would appear as the server being out of addresses in pools with particular ranges. [ISC-Bugs #26498] - In the DDNS code handle error conditions more gracefully and add more logging code. The major change is to handle unexpected cancel events from the DNS client code. [ISC-Bugs #26287] - Tidy up the receive calls and eliminate the need for found_pkt. [ISC-Bugs #25066] - Add support for Infiniband over sockets to the server and relay code. We've tested this on Solaris and hope to expand support for Infiniband in the future. This patch also corrects some issues we found in the socket code. [ISC-Bugs #24245] - Add a compile time check for the presence of the noreturn attribute and use it for log_fatal if it's available. This will help code checking programs to eliminate false positives. [ISC-Bugs #27539] - Fixed many compilation problems ("set, but not used" warnings) for gcc 4.6 that may affect Ubuntu 11.10 users. [ISC-Bugs #27588] - Modify the code that determines if an outstanding DDNS request should be cancelled. This patch results in cancelling the outstanding request less often. It fixes the problem caused by a client doing a release where the TXT and PTR records weren't removed from the DNS. [ISC-BUGS #27858] - Use offsetof() instead of sizeof() to get the sizes for dhcpv6_relay_packet and dhcpv6_packet in several more places. Thanks to a report from Bruno Verstuyft and Vincent Demaertelaere of Excentis. [ISC-Bugs #27941] - Remove outdated note in the description of the bootp keyword about the option not satisfying the requirement of failover peers for denying dynamic bootp clients. [ISC-bugs #28574] - Multiple items to clean up IPv6 address processing. When processing an IA that we've seen check to see if the addresses are usable (not in use by somebody else) before handing it out. When reading in leases from the file discard expired addresses. When picking an address for a client include the IA ID in addition to the client ID to generally pick different addresses for different IAs. [ISC-Bugs #23138] [ISC-Bugs #27945] [ISC-Bugs #25586] [ISC-Bugs #27684] - Remove unnecessary checks in the lease query code and clean up several compiler issues (some dereferences of NULL and treating an int as a boolean). [ISC-Bugs #26203] - Fix the NA and PD allocation code to handle the case where a client provides a preference and the server doesn't have any addresses or prefixes available. Previoulsy the server ignored the request with this patch it replies with a NoAddrsAvail or NoPrefixAvail response. By default the code performs according to the errata of August 2010 for RFC 3315 section 17.2.2; to enable the previous style see the section on RFC3315_PRE_ERRATA_2010_08 in includes/site.h. This option may be removed in the future. Thanks to Jiri Popelka at Red Hat for the patch. [ISC-Bugs #22676] - Fix up some issues found by static analysis. A potential memory leak and NULL dereference in omapi. The use of a boolean test instead of a bitwise test in dst. [ISC-Bugs #28941] Changes since 4.2.2 - Fix the code that checks for an existing DDNS transaction to cancel when removing DDNS information, so that we will continue with the processing if we have a lease even if it doesn't have an outstanding transaction. [ISC-Bugs #24682] - Add AM_MAINTAINER_MODE to configure.ac to avoid rebuilding configuration files. [ISC-Bugs #24107] - Add support for passing DDNS information to a DNS server over an IPv6 address. [ISC-Bugs #22647] - Enhanced patch for 23595 to handle IPv4 fixed addresses more cleanly. [ISC-Bugs #23595] Changes since 4.2.2rc1 ! Two packets were found that cause a server to halt. The code has been updated to properly process or reject the packets as appropriate. Thanks to David Zych at University of Illinois for reporting this issue. [ISC-Bugs #24960] One CVE number for each class of packet. CVE-2011-2748 CVE-2011-2749 Changes since 4.2.2b1 - Strict checks for content of domain-name DHCPv4 option can now be configured during compilation time. Even though RFC2132 does not allow to store more than one domain in domain-name option, such behavior is now enabled by default, but this may change some time in the future. See ACCEPT_LIST_IN_DOMAIN_NAME define in includes/site.h. [ISC-Bugs #24167] - DNS Update fix. A misconfigured server could crash during DNS update processing if the configuration included overlapping pools or multiple fixed-address entries for a single address. This issue affected both IPv4 and IPv6. The fix allows a server to detect such conditions, provides the user with extra information and recommended steps to fix the problem. If the user enables the appropriate option in site.h then server will be terminated [ISC-Bugs #23595] Changes since 4.2.1 ! In dhclient check the data for some string options for reasonableness before passing it along to the script that interfaces with the OS. [ISC-Bugs #23722] CVE: CVE-2011-0997 - DHCPv6 server now responds properly if client asks for a prefix that is already assigned to a different client. [ISC-Bugs #23948] - Add the option "--no-pid" to the client, relay and server code, to disable writing a pid file. Add the option "-pf pidfile" to the relay to allow the user to supply the pidfile name at runtime. Add the "with-relay6-pid-file" option to configure to allow the user to supply the pidfile name for the relay in v6 mode at configure time. [ISC-Bugs #23351] [ISC-Bugs #17541] - 'dhclient' no longer waits a random interval after first starting up to begin in the INIT state. This conforms to RFC 2131, but elects not to implement a 'SHOULD' direction in section 4.1. [ISC-Bugs #19660] - Added 'initial-delay' parameter that specifies maximum amount of time before client goes to the INIT state. The default value is 0. In previous versions of the code client could wait up to 5 seconds. The old behavior may be restored by using 'initial-delay 5;' in the client config file. [ISC-Bugs #19660] - ICMP ping-check should now sit closer to precisely the number of seconds configured (or default 1), due to making use of the new microsecond scale timer internally to dhcpd. This corrects a bug where the server may immediately timeout an ICMP ping-check if it was made late in the current second. [ISC-Bugs #19660] - The DHCP client will schedule renewal and rebinding events in microseconds if the DHCP server provided a lease-time that would result in sub-1-second timers. This corrects a bug where a 2-second or lower lease-time would cause the DHCP client to enter an infinite loop by scheduling renewal at zero seconds. [ISC-Bugs #19660] - Client lease records are recorded at most once every 15 seconds. This keeps the client from filling the lease database disk quickly on very small lease times. [ISC-Bugs #19660] - To defend against RFC 2131 non-compliant DHCP servers which fail to advertise a lease-time (either mangled, or zero in value) the DHCP client now adds the server to the reject list ACL and returns to INIT state to hopefully find an RFC 2131 compliant server (or retry in INIT forever). [ISC-Bugs #19660] - Parameters configured to evaluate from user defined function calls can now be correctly written to dhcpd.leases (as on 'on events' or dynamic host records inserted via OMAPI). [ISC-Bugs #22266] - If a 'next-server' parameter is configured in a dynamic host record via OMAPI as a domain name, the syntax written to disk is now correctly parsed upon restart. [ISC-Bugs #22266] - The DHCP server now responds to DHCPLEASEQUERY messages from agents using IP addresses not covered by a subnet in configuration. Whether or not to respond to such an agent is still governed by the 'allow leasequery;' configuration parameter, in the case of an agent not covered by a configured subnet the root configuration area is examined. Server now also returns vendor-class-id option, if client sent it. [ISC-Bugs #21094] - Documentation fixes [ISC-Bugs #17959] add text to AIX section describing how to have it send responses to the all-ones address. [ISC-Bugs #19615] update the includes in dhcpctl/dhcpctl.3 to be more correct [ISC-Bugs #20676] update dhcpd.conf.5 to include the RFC numbers for DDNS - Linux Packet Filter interface improvement. sockaddr_pkt structure is used, rather than sockaddr. Packet etherType is now forced to ETH_P_IP. [ISC-Bugs #18975] - Minor code cleanups - but note port change for #23196 [ISC-Bugs #23470] - Modify when an ignore return macro is defined to handle unsed error return warnings for more versions of gcc. [ISC-Bugs #23196] - Modify the reply handling in the server code to send to a specified port rather than to the source port for the incoming message. Sending to the source port was test code that should have been removed. The previous functionality may be restored by defining REPLY_TO_SOURCE_PORT in the includes/site.h file. We suggest you don't enable this except for testing purposes. [ISC-Bugs #22695] - Close a file descriptor in an error path. [ISC-Bugs #19368] - Tidy up variable types in validate_port. - Code cleanup [ISC-Bugs #13151] remove obsolete PROTO, KandR, INLINE and ANSI_DECL macros - Compilation problem with gcc4.5 and omshell.c resolved. [ISC-Bugs #23831] - Client Script fixes [ISC-Bugs #23045] Typos in client/scripts/openbsd [ISC-Bugs #23565] In the client scripts add a zone id (interface id) if the domain search address is link local. [ISC-Bugs #1277] In some of the client scripts add code to handle the case of the default router information being changed without the address being changed. - Documentation cleanup [ISC-Bugs #23326] Updated References document, several man page updates - Server no longer complains about NULL pointer when configured server-identifier expression fails to evaluate. [ISC-Bugs #24547] - Convert ISC_R_INPROGRESS status to ISC_R_SUCCESS when called from other than the dispatch handler. This fixes an issue where omshell, when run from the same platform as the server, would appear to fail to connect. This is a companion to #21839. [ISC-Bugs #23592] - Enlarge the buffer size used by the Omshell code and some of the print routines to allow for greater than 60 characters or, when printing as hex strings, 20 characters. [ISC-Bugs #22743] - In Solaris 11 switch to using sockets instead of DLPI, thanks to a patch form Oracle. [ISC-Bugs #24634]. Changes since 4.2.1rc1 - None Changes since 4.2.1b1 - Removed the restriction on using IPv6 addresses in IPv4 mode. This allows IPv4 options which contain IPv6 addresses to be specified. For example the 6rd option can be specified and used like this: [ISC-Bugs #23039] option 6rd code 212 = { integer 8, integer 8, ip6-address, array of ip-address }; option 6rd 16 10 2001:: 1.2.3.4, 5.6.7.8; - Handle some DDNS corner cases better. Maintain the DDNS transaction information when updating a lease and cancel any existing transactions when removing the ddns information. [ISC-Bugs #23103] - Some fixes for LDAP [ISC-Bugs #21783] - Include lber library when building ldap [ISC-Bugs #22888] - Enable the ldap code when buidling common The above fixes are from Jiri Popelka at Red Hat. - Modify the dlpi code to accept getmsg() returning a positive value. [ISC-Bugs #22824] Changes since 4.2.0 - 'get-host-names true;' now also works even if 'use-host-decl-names true;' was also configured. The nature of this repair also fixes another error; the host-name supplied by a client is no longer overridden by a reverse lookup of the lease address. Thanks to a patch from Wilco Baan Hofman supplied to us by the Debian package maintenance team. [ISC-Bugs #21691] {Debian Bug#509445} - The .TH tag for the dhcp-options manpage was typo repaired thanks to a report from jidanni and the Debian package maintenance team. [ISC-Bugs #21676] {Debian Bug#563613} - More documentation changes - primarily to put the options in the dhclient and dhcpd man pages into the standard form. Thanks in part to a patch from David Cantrell at Red Hat. [ISC-Bugs #20264] and parts of [ISC-Bugs #17744] dhclient.8 changes - Add code to clear the pointer to an object in an OMAPI handle when the object is freed due to a dereference. [ISC-Bugs #21306] - Fixed a bug that leaks host record references onto lease structures, causing the server to apply configuration intended for one host to any other innocent clients that come along later. [ISC-Bugs #22018] - Minor code fixes [ISC-Bugs #19566] When trying to find the zone for a name for ddns allow the name to be at the apex of the zone. [ISC-Bugs #19617] Restrict length of interface name read from command line in dhcpd - based on a patch from David Cantrell at Red Hat. [ISC-Bugs #20039] Correct some error messages in dhcpd.c [ISC-Bugs #20070] Better range check on values when creating a DHCID. [ISC-Bugs #20198] Avoid writing past the end of the field when adding overly long file or server names to a packet and add a log message if the configuration supplied overly long names for these fields. Thanks to Martin Pala. [ISC-Bugs #21497] Add a little more randomness to rng seed in client thanks to a patch from Jeremiah Jinno. - Correct error handling in DLPI [ISC-Bugs #20378] - Remove __sun__ and __hpux__ typedefs in osdep.h as they are now being checked in configure. [ISC-Bugs #20443] - Modify how the cmsg header is allocated the v6 send and received routines to compile on more compilers. [ISC-Bugs #20524] - When parsing a domain name free the memory for the name after we are done with it. [ISC-Bugs #20824] - Add an elapsed time option to the release message and refactor the code to move most of the common code to a single routine. [ISC-Bugs #21171]. - Parse date strings more properly - the code now handles semi-colons in date strings correctly. Thanks to a patch from Jiri Popelka at Red Hat. [ISC-Bugs #21501, #20598] - Fixes to lease input and output. [ISC-Bugs #20418] - Some systems don't support the "%s" argument to strftime, paste together the same string using mktime instead. [ISC-Bugs #19596] - When parsing iaid values accept printable characters. [ISC-Bugs #21585] - Always print time values in omshell as hex instead of ascii if the values happen to be printable characters. - Minor changes for scripts, configure.ac and Makefiles [ISC-Bugs #19147] Use domain-search instead of domain-name in manual and example conf file. Thanks to a patch from David Cantrell at Red Hat. [ISC-Bugs #19761] Restore address when doing a rebind in DHCPv6 [ISC-Bugs #19945] Properly close the quote on some arguments. [ISC-Bugs #20952] Add 64 bit types to configure.ac [ISC-Bugs #21308] Add "PATH=" to CLIENT_PATH envrionment variable - Update the code to parse dhcpv6 lease files to accept a semi-colon at the end of the max-life and preferred-life clauses. In order to be backwards compatible with older lease files not finding a semi-colon is also accepted. [ISC-Bugs #22303]. ! Handle a relay forward message with an unspecified address in the link address field. Previously such a message would cause the server to crash. Thanks to a report from John Gibbons. [ISC-Bugs #21992] CERT: VU#102047 CVE: CVE-2010-3611 - ./configure on longer searches for -lcrypto to explicitly link against. This fixes a bug where 'dhclient' would have shared library dependencies on '/usr/lib'. [ISC-Bugs #21967] - Handle pipe failures more gracefully. Some OSes pass a SIGPIPE signal to a process and will kill the process if the signal isn't caught. This patch adds code to turn off the SIGPIPE signal via a setsockopt() call. The signal is already being ignored as part of the ISC library. [ISC-Bugs #22269] - Restore printing of values in omshell to the style pre 21585. For 21585 we changed the print routines to always display time values as a hex list. This had a side effect of printing all data strings as a hex list. We shall investigate other ways of displaying time values more usefully. [ISC-Bugs #22626] ! Fix the handling of connection requests on the failover port. Previously a connection request from a source that wasn't listed as a failover peer would cause the server to become non-responsive. Thanks to a report from Brad Bendily, brad@bendily.com. [ISC-Bugs #22679] CERT: VU#159528 CVE: CVE-2010-3616 - Don't pass the ISC_R_INPROGRESS status to the omapi signal handlers. Passing it through to the handlers caused the omshell program to fail to connect to the server. [ISC-Bugs #21839] - Fix the paranthesis in the code to process configuration statements beginning with "auth". The previous arrangement caused "auto-partner-down" to be processed incorrectly. [ISC-Bugs #21854] - Limit the timeout period allowed in the dispatch code to 2^^32-1 seconds. Thanks to a report from Jiri Popelka at Red Hat. [ISC-Bugs #22033], [Red Hat Bug #628258] - When processing the format flags for a given option consume the flag indicating an optional value correctly. A symptom of this bug was an infinite loop when trying to parse the slp-service-scope option. Thanks to a patch from Marius Tomaschewski. [ISC-Bugs #22055] - Disable the use of kqueue in the ISC library. This avoids a problem between the fork and socket code that caused the dhcpd process to use all available cpu if the program daemonized itself. [ISC-Bugs #21911] ! When processing a request in the DHCPv6 server code that specifies an address that is tagged as abandoned (meaning we received a decline request for it previously) don't attempt to move it from the inactive to active pool as doing so can result in the server crashing on an assert failure. Also retag the lease as active and reset its timeout value. [ISC-Bugs #21921] - Relay no longer crashes, when DHCP packet is received over interface without any IPv4 address assigned. [ISC-Bugs #22409] Changes since 4.2.0rc1 - Documentation cleanup covering multiple tickets [ISC-Bugs #20265] [ISC-Bugs #20259] minor cleanup [ISC-Bugs #20263] add text describing some default values [ISC-Bugs #20193] single quotes at the start of a line indicate a control line to nroff, escape them if we actually want a quote. [ISC-Bugs #18916] sync the pointer to web pages amongst the different docs Changes since 4.2.0b2 - Add declaration for variable in debug code in alloc.c. [ISC-Bugs #21472] Changes since 4.2.0b1 - Prohibit including lease time information in a response to a DHCP INFORM. [ISC-Bugs #21092] ! Accept a client id of length 0 while hashing. Previously the server would exit if it attempted to hash a zero length client id, providing attackers with a simple denial of service attack. [ISC-Bugs #21253] CERT: VU#541921 - CVE: CVE-2010-2156 - A memory leak in ddns processing was closed. [ISC-Bugs #21377] - Modify the exception handling for initial context creation. Previously we would try and clean up before exiting. This could present problems when the cleanup required part of the context that wasn't available. It also didn't do much as we exited afterwards anyway. Now we simply log the error and exit. [ISC-Bugs #21093] - A bug was fixed that could cause the DHCPv6 server to advertise/assign a previously allocated (active) lease to a client that has changed subnets, despite being on different shared networks. Dynamic prefixes specifically allocated in shared networks also now are not offered if the client has moved. [ISC-Bugs #21152] - Add some debugging output for use with the DDNS code. [ISC-Bugs #20916] - Fix the trace code to handle timing events better and to truncate a file before using instead of overwriting it. [ISC-Bugs #20969] - Modify the determination of the default TTL to use for DDNS updates. The user may still configure the ttl via ddns-ttl. The default for both v4 and v6 is now 1/2 the (preferred) lease time with a limit. The previous defaults (1/2 lease time without a limit for v4 and a default value for v6) may be used by defining USE_OLD_DDNS_TTL in site.h [ISC-Bugs #21126] - libisc/libdns is now brought up to version 9.7.1rc1. This corrects three reported flaws in ISC DHCP; o DHCP processes (dhcpd, dhclient) fail to start if one of either the IPv4 or IPv6 address families is not present. [ISC-Bugs #21122] o Assertion failure when attempting to cancel a previously running DDNS update. [ISC-Bugs #21133] o Compilation failure of libisc/libdns due to the use of a flexible array member. [ISC-Bugs #21316] Changes since 4.2.0a2 - Update the fsync code to work with the changes to the DDNS code. It now uses a timer instead of noticing if there are no more packets to process. - When constructing the DNS name structure from a text string append the root to relative names. This satisfies a requirement in the DNS library that names be absolute instead of relative and prevents DHCP from crashing. [ISC-Bugs #21054] - "The LDAP Patch" that has been circulating for some time, written by Brian Masney and S.Kalyanasundraram and maintained for application to the DHCP-4 sources by David Cantrell has been included. Please be advised that these sources were contributed, and do not yet meet the high standards we place on production sources we include by default. As a result, the LDAP features are only included by using a compile-time option which defaults off, and if you enable it you do so under your own recognizance. We will be improving this software over time. [ISC-Bugs #17741] Changes since 4.2.0a1 - When using 'ignore client-updates;', the FQDN returned to the client is no longer truncated to one octet. - Cleaned up an unused hardware address variable in nak_lease(). - Manpage entries for the ia-pd and ia-prefix options were updated to reflect support for prefix delegation. - Cleaned up some compiler warnings - An optimization described in the failover protocol draft is now included, which permits a DHCP server operating in communications-interrupted state to 'rewind' a lease to the state most recently transmitted to its peer, greatly increasing a server's endurance in communications-interrupted. This is supported using a new 'rewind state' record on the dhcpd.leases entry for each lease. - Fix the trace code which was broken by the changes to the DDNS code. Changes since 4.1.0 (new features) - Failover port configuration can now be left to defaults (port 647) as described in the -12 revision of the Failover draft (and assigned by IANA). Thanks in part to a patch from David Cantrell at Red Hat. - If configured, dhclient may now transmit to an anycast MAC address, rather than using a broadcast address. Thanks to a patch from David Cantrell at Red Hat. - Added client support for setting interface MTU and metric, thanks to Roy "UberLord" Marples . - Added client -D option to specify DUID type to send. - A new failover configuration parameter has been introduced for those environments where DHCP servers can be reasonably guaranteed to be "down" when the failover TCP socket is severed, "auto-partner-down". This parameter is not generally safe, and by default is disabled, so please carefully review the documentation of this parameter in the dhcpd.conf(5) manpage before determining to use it yourself. - Added a configuration function, 'gethostname()', which calls the system function of the same name and presents the results as a data expression. This function can be used to incorporate the system level hostname of the system the DHCP software is operating on in responses or queries (such as including a failover partner's hostname in a dhcp message or binding scope, or having a DHCP client send any system hostname in the host-name or FQDN options by default). - The dhcp-renewal-time and dhcp-rebinding-time options may now be configured for DHCPv4 operation and used independently of the dhcp-lease-time calculations. Invalid renew and rebinding times (e.g., greater than the determined lease time) are omitted. - Processing the DHCP to DNS server transactions in an asyncrhonous fashion. The DHCP server or client can now continue with its processing while awaiting replies from the DNS server. - The 'hardware [ethernet|etc] ...;' parameter in host records has been extended to attempt to match DHCPv6 clients by the last octets of a DUID-LL or DUID-LLT provided by the client. Changes since 4.1.0 (bug fixes) - Remove infinite loop in token_print_indent_concat(). - Validate the argument to the -p option. - The notorious 'option ... larger than buffer' log line, which is seen in some malformed DHCP client packets, was modified. It now logs the universe name, and does not log the length values (which are bogus corruption read from the packet anyway). It also carries a hopefully more useful explanation. - Suppress spurious warnings from configure about --datarootdir - A bug was fixed that caused the server not to answer some valid Solicit and Request packets, if the dynamic range covering any requested addresses had been deleted from configuration. - Update the code to deal with GCC 4.3. This included two sets of changes. The first is to the configuration files to include the use of AC_USE_SYSTEM_EXTENSIONS. The second is to deal with return values that were being ignored. - The db-time-format option was documented in manpages. - Using reserved leases no longer results in 'lease with binding state free not on its queue' error messages, thanks to a patch from Frode Nordahl. - Fix a build error in dhcrelay, using older versions of gcc with dhcpv6 disabled. - Two uninitialized stack structures are now memset to zero, thanks to a patch from David Cantrell at Red Hat. - Fixed a cosmetic bug where pretty-printing valid domain-search options would result in an erroneous error log message ('garbage in format string'). - A bug in DLPI packet transmission (Solaris, HP/UX) that caused the server to stop receiving packets is fixed. The same fix also means that the MAC address will no longer appear 'bogus' on DLPI-based systems. - A bug in select handling was discovered where the results of one select() call were discarded, causing the server to process the next select() call and use more system calls than required. This has been repaired - the sockets will be handled after the first return from select(), resulting in fewer system calls. - The update-conflict-detection feature would leave an FQDN updated without a DHCID (still currently implemented as a TXT RR). This would cause later expiration or release events to fail to remove the domain name. The feature now also inserts the client's up to date DHCID record, so records may safely be removed at expiration or release time. Thanks to a patch submitted by Christof Chen. - Memory leak in the load_balance_mine() function is fixed. This would leak ~20-30 octets per DHCPDISCOVER packet while failover was in use and in normal state. - Various compilation fixes have been included for the memory related DEBUG #defines in includes/site.h. - Fixed Linux client script 'unary operator expected' errors with DHCPv6. - Fixed setting hostname in Linux hosts that require hostname argument to be double-quoted. Also allow server-provided hostname to override hostnames 'localhost' and '(none)'. - Fixed failover reconnection retry code to continue to retry to reconnect rather than restarting the listener. - Compilation on Solaris with USE_SOCKETS defined in includes/site.h has been repaired. Other USE_ overrides should work better. - A check for the local flavor of IFNAMSIZ had a broken 'else' condition, that probably still resulted in the correct behaviour (but wouldn't use a larger defined value provided by the host OS). - Fixed a bug where an OMAPI socket disconnection message would not result in scheduling a failover reconnection, if the link had not negotiated a failover connect yet (e.g.: connection refused, asynch socket connect() timeouts). - A bug was fixed that caused the 'conflict-done' state to fail to be parsed in failover state records. ! A stack overflow vulnerability was fixed in dhclient that could allow remote attackers to execute arbitrary commands as root on the system, or simply terminate the client, by providing an over-long subnet-mask option. CERT VU#410676 - CVE-2009-0692 - Fixed a bug where relay agent options would never be returned when processing a DHCPINFORM. - Versions 3.0.x syntax with multiple name->code option definitions is now supported. Note that, similarly to 3.0.x, for by-code lookups only the last option definition is used. - Fixed a bug where a time difference of greater than 60 seconds between a failover pair could cause the primary to crash on contact with the secondary. Thanks to a patch from Steinar Haug. - Don't look for IPv6 interfaces on Linux when running in DHCPv4 mode. Thanks to patches from Matthew Newton and David Cantrell. - Secondary servers in a failover pair will now perform ddns removals if they had performed ddns updates on a lease that is expiring, or was released through the primary. As part of the same fix, stale binding scopes will now be removed if a change in identity of a lease's active client is detected, rather than simply if a lease is noticed to have expired (which it may have expired without a failover server noticing in some situations). - A patch supplied by David Cantrell at RedHat was applied that detects invalid calling parameters given to the ns_name_ntop() function. Specifically, it detects if the caller passed a pointer and size pair that causes the pointer to integer-wrap past zero. ! Fixed a fenceposting bug when a client had two host records configured, one using 'uid' and the other using 'hardware ethernet'. CVE-2009-1892 - Fixed the check in the dhcp_interface_signal_handler routine to verify the existence of the linked signal handler before calling it. - Both host and subnet6 configuration groups are now included whether a fixed-address6 (DHCPv6) is in use or not. Host scoped configuration takes precedence. This fixes two bugs, one where host scoped configuration would not be included from a non-fixed-address6 host record, and the equal and opposite bug where subnet6 scoped configuration would not be used when over-riding values were not present in a matching fixed-address6 host configuration. - ./configure now checks to ensure the intX_t and u_intX_t types are defined, correcting a compilation failure when using Sun's compiler. - Modified the handling of a connection to avoid releasing the omapi io object for the connection while it is still in use. One symptom from this error was a segfault when a failover secondary attempted to connect to the failover primary if their clocks were not synchronized. - Clean up to allow compilation with gcc 2.95.4 on FreeBSD. Remove an extra semi-colon from common/dns.c and moved setting a variable to NULL in server/dhcpv6.c to allow the compiler to decide that the variable was always properly set. Changes since 4.1.0b1 - A missing "else" in dhcrelay.c could have caused an interface not to be recognized. Changes since 4.1.0a2 - A cosmetic bug in DHCPDECLINE processing was fixed which caused all successful DHCPDECLINEs to be logged as "not found" rather than "abandoned". - Added configuration file examples for DHCPv6. - Some failover debugging #defines have been better defined and some high frequency messages moved to a deeper debugging symbol. - The CLTT parameter in failover is now only updated by client activity, and not by failover binding updates (taking on the peer's CLTT). - Failover BNDUPD messages are now discarded if they conflict with an update that has been transmitted, but not acknowledged. - A bug cleaning up unknown-xxx temporary option definitions was fixed. - Delayed-ack is now a compile-time option, compiled out by default. This feature is simply too experimental for right now, and causes some problems to some failover installations. We will revisit this in future releases. - The !inet_pton() call in res_mkupdrec was adjusted to '<= 0' as inet_pton returns either 1, 0, or -1. - A dhclient-script for MacOS X has been included, which enables 'dhclient -6' support. - DDNS removal routines were updated so that the DHCID is not removed until the client has been deprived of all A and AAAA records (not only the last one of either of those). This resolves a bug where dual stack clients would not be able to regain their names after either expiration event. Changes since 4.1.0a1 - Corrected list of failover state values in dhcpd man page. - Fixed a bug that caused some request types to be logged incorrectly. - Clients that sent a parameter request list containing the routers option before the subnet mask option were receiving only the latter. Fixed. - The server wasn't always sending the FQDN option when it should. - A partner-down failover server no longer emits 'peer holds all free leases' if it is able to newly-allocate one of the peer's leases. - Fixed a coredump when adding a class via OMAPI. - Check whether files are zero length before trying to parse them. - Ari Edelkind's PARANOIA patch has been included and may be compiled in via two ./configure parameters, --enable-paranoia and --enable-early-chroot. - ./configure was extended to cover many optional build features, such as failover, server tracing, debugging, and the execute() command. - There is now a default 1/4 of a second scheduled delay between delayed fsync()'s, it can be configured by the max-ack-delay configuration parameter. - A bug was fixed where the length of a hostname was miscalculated, so that hosts were given odd-looking domain names ("foo.bar.ba.example.com"). - Shared network selection should be done from the innermost relay valid link-address field, rather than the outermost. - Prefix pools are attached to shared network scopes. - Merged IA_XX related structures. - Add DHCPv6 files in configure. - A memory leak when using omapi has been fixed. - DHCPv6 vendor-class options (VSIO) are now only sent when they appear on the DHCPv6 ORO. This resolves a bug where VSIO options were placed in IA_NA encapsulated options fields. - Integrated client with stateless, temporary address and prefix delegation support. - A double-dereference in dhclient transmission of DHCPDECLINEs was repaired. - Fix handling of format code 'Z'. - Support "-1" argument in DHCPv6. - Merge DHCPv6-only "dhcrelay6" into general-purpose "dhcrelay" (use "-6" option to select DHCPv6 mode). - Fix handling of -A and -a flags in dhcrelay; it was failing to expand packet size as needed to add relay agent options. - A bug in subnet6 parsing where options contained in subnet6 clauses would not be applied to clients addressed within that network was repaired. - When configuring a "subnet {}" or "subnet6 {}" without an explicit shared-network enclosing it, the DHCP software would synthesize a shared-network to contain the subnet. However, all configuration parameters within the subnet more intuitively belong "to any client on that interface", or rather the synthesized shared-network. So, when a shared-network is synthesized, it is used to contain the configuration present inside the subnet {} clause. This means that the configuration will be valid for all clients on that network, not just those addressed out of the stated subnet. If you intended the opposite, the workaround is to explicitly configure an empty shared-network. - A bug was fixed where Information-Request processing was not sourcing configured option values. - A warning was added since the DHCPv6 processing software does not yet support class statements. - Compliation warnings on GCC 4.3 relating to bootp source address selection were repaired. - The v6 BSD socket method was updated to use a single UDP BSD socket no matter how many interfaces are involved, differentiating the interfaces the packets were received on by the interface index supplied by the OS. - The relay agent no longer listens to the All DHCP Servers Multicast address. - A bug was fixed in data_string_sprintfa() where va_start was only called once for two invocations of vsprintf() variants. - ERO (RFC 4994) server support. - Basic and partial DHCPv6 leasequery support. - Reliable DHCPv6 release (previous behavior, send release and exit, is still available with dhclient -6 -1 -r). Changes since 4.0.0 (new features) - Added DHCPv6 rapid commit support. - Added explicit parser support for zero-length DHCP options, such as rapid-commit, via format code 'Z'. - It's now possible to update the "ends" field of a lease with OMAPI. This is useful if you want not only to release a lease, but also make it available for reuse right away. Hat tip to Christof Chen. - Fixed definition of the iaaddr hash functions to use the correct functions when referencing and dereferencing memory. - Some definitions not in phase with the IANA registry were updated. - Allocated interface IDs are better controlled ('u' bit set to zero, reserved IDs avoided). - Unicast options are taken into account only for RENEWs. - NoAddrsAvail answers to SOLICITs are always ADVERTISEs even when a SOLICIT carries a rapid-commit option. - Return in place of raise an impossible condition when one tries to release an empty active lease. - Timer granularity is now 1/100s in the DHCPv6 client. - The dhclient-script was updated to create a host route for the default gateway if the supplied subnet mask for an IPv4 address was a /32. This allows the client to work in 'captive' network environments, where the operator does not want clients to crosstalk directly. - MINUS tokens should be parseable again. - Multiple (up to "delayed-ack x;" maximum) DHCPv4 packets are now queued and released in bursts after single fsync() events when the upper limit is reached or if the receiving sockets go dry. The practical upshot is that fsync-coupled server performance is now multiplicitively increased. The default delayed ack limit is 28. Thanks entirely to a patch from Christof Chen. Changes since 4.0.0 (bug fixes) - DHCP now builds on AIX. - Exit with warning when DHCPv6-specific statements are used in the config file but -6 is not specified. - Fixed "--version" flag in dhcrelay - The 'min-secs' configuration parameter's log message has been updated to be more helpful. - The warning logged when an address range doesn't fit in the subnets they were declared has been updated to be more helpful and identify the typo in configuration that created the spanning addresses. - A bug in failover pool rebalancing that caused POOLREQ message ping-pongs was repaired. - A flaw in failover pool rebalancing that could cause POOLREQ messages to be sent outside of the min-balance/max-balance scheduled intervals has been repaired. - A cosmetic bug during potential-conflict recovery that caused the peer's 'conflict-done' state message to be logged as 'unknown-state' has been repaired. It is now logged correctly. - A bug was fixed where the 'giaddr' may be used to find the client's subnet rather than its own 'ciaddr'. - A log message was introduced to clarify the situation where a failover 'address' parameter (the server's local address) did not resolve to an IPv4 address. - The minimum site code value was set to 224 in 3.1.0 to track RFC3942. This broke a lot of legacy site local configurations. The new code in place will track site local space minimum option codes and logs a warning to encourage updates and exploration of site local code migration problems. Option codes less than 128 in site local spaces remain inaccessible. - A possible relay agent option bug was repaired where random server initialization state may have been used to signal the relay agent information options sub-option code for the 'END' of the option space. - Fixes to allow code to compile and run on Solaris 9. - Fixes to allow code to compile on Mac OS X Leopard (10.5). - When server is configured with options that it overrides, a warning is issued when the configuration file is read, rather than at the time the option is overridden. This was important, because the warning was given every time the option was overridden, which could create a lot of unnecessary logging. - Fixed a compilation problems on platforms that define a value for FDDI, which conflicts with a dhcp configuration syntax token by the same name. - When a failover server suspects it has encountered a peer running a version 3.0.x failover server, a warning that the failover wire protocol is incompatible is printed. - The failover server no longer issues a floating point error if it encounters a previously undefined option code. - Fix startup error messages to report a missing "subnet6 declaration", rather than a missing "subnet declaration", when running as a DHCPv6 server. - DHCPv6 client timestamp in DUID was based on the year 1970 rather than the year 2000. - Warn when attempting to use a hardware parameter in DHCPv6. - DHCPv6 released resources are now marked as released by the client. - 'Soft' bindings have no more side-effects. Changes since 4.0.0b3 - The reverse dns name for PTR updates on IPv6 addresses has been fixed to use ip6.arpa. rather than default to in-addr.arpa and require user configuration. - dhc6_lease_destroy() and dhc6_ia_destroy() now set lease and IA pointers to NULL after freeing, to prevent subsequent accesses to freed memory. - The DHCPv6 server would not send the preference option unless the client requested it, via the ORO. This has been fixed, so the DHCPv6 server will always send the preference value if it is configured. - When addresses were passed as hints to the server in an IA, they were incorrectly handled, sometimes being treated as an error. Now the server will treat these as hints and ignore them if it cannot supply a requested address. - If the client had multiple addresses, and one expired (was not renewed by the server), the client would continue to attempt to renew the same old address over and over. Now, the client will omit any expired addresses from future Confirm, Renew, or Rebind messages. - dhclient -6 will now select renew/rebind timers based upon the longest address expiration time rather than the shortest expiration time, in order to avoid cascading renewals in the event a server elects not to extend one of multiple IAADDR leases. - The server now limits clients that request multiple addresses to one address per IA by default, which can be adjusted through the "limit-addrs-per-ia" configuration option. - The DHCPv6 client now issues fresh transaction IDs on Renew and Rebind message exchanges, rather than using the most recent ID. - The DHCPv6 server now replies to Information-Request messages. - A bug was fixed in the dhclient-script for BSDs to correctly carry error codes through some conditions. - The parsing of some options in the dhclient lease file, in particular the success DHCPv6 status-code, was fixed. - A bug was fixed that caused the DHCPv6 ORO option to be corrupted with seemingly random values. - A reference overleak in DHCPv6 shared network processing was repaired. - ./configure now autodetects local database locations rather than trying to put dhcpd.leases and dhclient.leases in /usr/local/var/db, which no one ever has. - Regression fix for bug where server advertised a IPv6 address in response to a SOLICIT but would not return the address in response to a REQUEST. - A bug was fixed where the DHCPv6 server puts the NoAddrsAvail status code in the IA_NA was fixed. The status code now appears in the root level. Changes since 4.0.0b2 - Clarified error message when lease limit exceeded - Relative time may now be used as a qualifier for 'allow' and 'deny' access control lists. These directives may be used to assist in re-addressing address pools without having to constantly reconfigure the server. Please see 'man dhcpd.conf' for more information on allow/deny 'after time' syntax. Thanks to a patch from Christof Chen. - The server will now include multiple IA_NA's and multiple IAADDRs within them, if advertised by the client. It still only seeks to allocate one new address. Changes since 4.0.0b1 - Use different paths for PID and lease files when running in DHCPv4 or DHCPv6 mode, so that servers for both protcols can be run simultaneously on a single interface. - Fixed a buffer overflow error which could have allowed a denial of service under unusual server configurations - Eliminated a spurious error message from the client - A number of bugs with the internal handling of lease state on the server have been fixed. Some of these could cause server crashes. - The peer_wants_leases() changes pulled up from 3.1.0 were corrected, 'never used' leases will no longer consistently shift between servers on every pool rebalance run. - sendmsg()/recvmsg() control buffers are now declared in such a way to ensure they are correctly aligned on all (esp. 64-bit) architectures. - The client leasing subsystem was streamlined and corrected to account more closely for changes in client link attachment selection. Changes since 4.0.0a3 - The DHCP server no longer requires a "ddns-update-style" statement, and now defaults to "none", which means DNS updates are disabled. - Log messages when failover peer names mismatch have been improved to point out the problem. - Bug where server advertised a IPv6 address in response to a SOLICIT but would not return the address in response to a REQUEST. Thanks to Dennis Kou for finding the bug. - Fixed an error causing the server to lock up on lease expiration, reported independently by Jothilingam Vasu and Dennis Kou. - Fixed a ./configure bug where compile tests were failing due to "-Werror" (unused variable) rather than the actual test failure. Lead to inconsistent and unworkable auto-configurations. - Compilation with DLPI and -Werror has been repaired. - Error in decoding IA_NA option if multiple interfaces are present fixed by Marcus Goller. - DHCPv6 server Confirm message processing has been enhanced - it no longer replies only to clients with host {} records, it now replies as directed in RFC3315 section 18.2.2 - that is, to all clients regardless of the existence of bindings. - A core dump during expired lease cleanup has been repaired. - DDNS updates state information are now stored in 'binding scopes' that follow the leases through their lifecycles. This enables DDNS teardowns on leases that are assigned and expired inbetween a server restart (the state is recovered from dhcpd.leases). Arbitrary user-specified binding scopes ('set var = "value";') are not yet supported. - Additional compilation problems on HP/UX have been repaired. Changes since 4.0.0a2 - Fix for startup where there are no IPv4 addresses on an interface. Thanks to Marcus Goller for reporting the bug. - Fixed file descriptor leak on listen failure. Thanks to Tom Clark. - Bug in server configuration parser caused server to get stuck on startup for certain bad pool declarations. Thanks to Guillaume Knispel for the bug report and fix. - Code cleaned to remove warnings reported by "gcc -Wall". - DHCPv6 is now the default. You can disable DHCPv6 support using the "--disable-dhcpv6" flag when you run the configure script. - An internal database inconsistency bug was repaired where the server would segfault if a client attempted to renew a lease that had been loaded from persistent storage. - 'request' and 'also request' syntaxes have been added to accommodate the DHCPv6 client configuration. 'send dhcp6.oro' is no longer necessary. - Bug fixed where configuration file parsing did not work with zero-length options; this made it impossible to set the rapid-commit option. - Bogus messages about host records with IPv4 fixed-addresses being of non-128-bits in length were removed. Changes since 4.0.0a1 - Bug in octal parsing fixed. Thanks to Bernd Fuhrmann for the report and fix. - Autoconf now supplies proper flags for Solaris DHCPv6 builds. - Fix for parsing error on some IPv6 addresses. - Invalid CIDR representation for IPv6 subnets or ranges now checked for when loading configuration. - Compilation on HP/UX has been repaired. The changes should generally apply to any architecture that supplies SIOCGLIFCONF but does not use 'struct lifconf' structures to pass values. - Two new operators, ~= and ~~, have been integrated to implement boolean matches by regular expression (such as may be used in class matching statements). Thanks to a patch by Alexandr S. Agranovsky, which underwent slight modification. - Fix for icmp packets on 64-bit systems (bug introduced in 4.0). - A bug was fixed in interface discovery wherein an error identifying a server-configured interface with no IPv4 addresses would SEGV. - Fixed a bug in which write_lease() might report a failure incorrectly - Added support for DHCPv6 Release messages - Added -x option to dhclient, which triggers dhclient processes to exit gracefully without releasing leases first - All binaries (client, server, relay) now change directories to / before going into daemon mode, so as not to hold $CWD open - Fixed a bug parsing DHCPv6 client-id's in host-identifier statements - Fixed a bug with the 'ddns-updates' boolean server configuration parameter, which caused the server to fail. Changes since 4.0.0-20070413 - Old (expired) leases are now cleaned. - IPv6 subnets now have support for arbitrary allocation ranges via a new 'range6' configuration directive. - An obviated option code hash lookup to find D6O_CLIENTID was removed. - Corrected some situations where variables might be used without being initialized. - Silenced several other compiler warnings. - Include the more standard sys/uio.h rather than rely upon other header files to include it (fixes a BSD 4.2 compile failure). - Duplicate dhclient-script updates for DHCPv6 to all provided scripts. - DHCPv4 I/O methods that failed to sense hardware address were corrected. - DHCPv4 is now the default (as documented) rather than DHCPv6. The default was set to DHCPv6 to facilitate ease early development, and forgotten. - Corrected a segmentation violation in DHCPv4 socket processing. - dhclient will now fork() into the background once it binds to an IPv6 address, or immediately if the -n flag is supplied. - -q is now the default behaviour on dhclient, with -d or -v enabling non-quiet (stderr logging) mode. - Fix documentation of the domain-search atom (quoted, with commas). - Document DHCPv6 options presently in the default table. - Replaced ./configure shellscripting with GNU Autoconf. Changes since 3.1.0 (NEW FEATURES) - DHCPv6 Client and Server protocol support. Use '-6' to run the daemons as v6-only. Use '-4' to run the daemons as v4-only (default. There is no support currently for both. - Server support for multiple IA_NA options, containing at most one IAADDR option. - Client support for one IA_NA option, containing any number of IAADDR options. - Server support for the DHCPv6 Information-request message. - Inappropriate unicast DHCPv6 messages sent to the server are now discarded, and this has rearchitected the IO system slightly. - The DHCPv6 server DUID defaults to type 1, is persistently stored in the leases database, and can be over-ridden (either completely, or by specifying type 1 or type 2). - The server only uses Rapid-Commit if it has been configured with the Rapid-Commit option and the client requests it. - DDNS support. We now update AAAA records in the same place we would update A records, if we have an IPv6 address. We also generate IP6.ARPA style names for PTR records if we're dealing with an IPv6 address. Both A and AAAA updates are done using the same 'fqdn.' virtual option space (although the DHCPv4 FQDN and DHCPv6 FQDN options are formatted differently, they both use the same code here). - The Linux dhclient-script attempts to set and remove assigned addresses, and to configure /etc/resolv.conf from nameserver and domain name configurations. It can be extended to configure other parameters. - Initial DHCPv6 lease support. - The IO system now tracks all local IP addresses, so that the DHCP applications (particularly the dhcrelay) can discern between what frames were transmitted to it, and what frames are being carried through it which it should not intercept. Changes since 3.1.0 (Maintenance) - A bug was repaired where MAC Address Affinity for virgin leases always mapped to the primary. Virgin leases now have an interleaved preference between primary and secondary. - A bug was repaired where MAC Address Affinity for clients with no client identifier was sometimes mishashed to the peer. Load balancing during runtime and pool rebalancing were opposing. - An assertion in lease counting relating to reserved leases was repaired. - The subnet-mask option inclusion now conforms with RFC2132 section 3.3; it will only appear prior to the routers option if it is present on the Parameter-Request-List. The subnet-mask option will also only be included by default (if it is not on the PRL) in response to DISCOVER or REQUEST messages. - The FQDN option is only supplied if the client supplied an FQDN option or if the FQDN option was explicitly requested on the PRL. - Dynamic BOOTP leases are now load balanced in failover. Changes since 3.1.0rc1 - The parse warning that 'deny dyanmic bootp;' must be configured for failover protected subnets was removed. Changes since 3.1.0b2 - Failover rebalance events no longer play ping pong with round errors (moving leases between free and back to backup where there are an odd number of leases). - The 'pool' log line has been split into two messages, one before the rebalance run, and one after. - Any queued BNDACKs are transmitted before transmitting new BNDUPDs. This enforces the correct sequence of events for the remote server processing these messages. Changes since 3.1.0b1 - Fixed a bug that caused OMAPI clients to freeze when opening lease objects. - A new server config option "fqdn-reply" specifies whether the server should send out option 81 (FQDN). Defaults to "on". If set to "off", the FQDN option is not sent, even if the client requested it. This is needed because some clients misbehave otherwise. Thanks to Christof Chen at Allianz. - Allow trace output files (-tf option) to be overwritten, rather than crashing dhcpd if the file already exists - A bug was fixed that caused dhcpd to segfault if a pool was declared outside the scope of a subnet in dhcpd.conf. - Some uninitialized values were repaired in dhcpleasequery.c that caused the server to abort. - A new server config option, 'do-reverse-updates', has been added which causes the server to abstain from performing updates on PTR records. Thanks to a patch from Christof Chen at Allianz. - A bug was repaired in subencapsulation support, where spaces separated by empty spaces would not get included. - A bug in dhclient was repaired which caused it to send parameter request lists of 55 bytes in length no matter how long the declared PRL was. - 'dhcp.c(3953): non-null pointer' has been repaired. This fixes a flaw wherein the DHCPv4 server may ignore a configured server-identifier. - A flaw in failover startup sequences was repaired that sometimes left the primary DHCP server's pool rebalance schedules unscheduled. - Corrected a flaw that broke encapsulated spaces included due to presence on the parameter request list. Changes since 3.1.0a3 - Some spelling fixes. Changes since 3.1.0a2 - A bug was fixed where attempting to permit leasequeries results in a fatal internal error, "Unable to find server option 49". - A bug was fixed in dhclient rendering the textual output form of the domain-search option syntax. Changes since 3.1.0a1 - A bug in the FQDN universe that added FQDN codes to the NWIP universe's hash table was repaired. - The servers now try harder to transmit pending binding updates when entering normal state. - UPDREQ/UPDREQALL handling was optimized - it no longer dequeues and requeues all pending updates. This should reduce the number of spurious 'xid mismatch' log messages. - An option definition referencing leak was fixed, which resulted in early termination of dhclient upon the renewal event. - Some default hash table sizes were tweaked, some upwards, some downwards. 3.1.0a1's tables resulted in a reduction in default server memory use. The new selected values provide more of a zero sum (increasing the size of tables likely to be populated, decreasing the size of tables unlikely). - Lease structures appear in three separate hashes: by IP address, by UID, and by hardware address. One type of table was used for all three, and improvements to IP address hashing were applied to all three (so UID and hardware addresses were treated like 4-byte integers). There are now two types of tables, and the uid/hw hashes use functions more appropriate to their needs. - The max-lease-misbalance percentage no longer causes scheduled rebalance runs to be skipped: it still governs the schedule, but every scheduled run will attempt balance. - A segfault bug in recursive encapsulation support has been corrected. Changes since 3.0 (New Features) - A workaround for certain STSN servers that send a mangled domain-name option was introduced for dhclient. The client will now accept corrupted server responses, if they contain a valid DHCP_MESSAGE_TYPE (OFFER, ACK, or NAK). The server will continue to not accept corrupt client packets. - Support for 'reserved' (pseudo-static) and BOOTP leases via failover was introduced. - Support for adding, removing, and managing class and subclass statements via OMAPI. - The failover implementation was updated to comply with revision 12 of the protocol draft. - 'make install' now creates the initial zero-length dhcpd.leases file if one does not already exist on the system. - RFC3942 compliance, site-local option spaces start at 224 now, not 128. - The Load Balance Algorithm was misimplemented. The current implementation matches RFC 3074. - lcase() and ucase() configuration expressions have been added which adjust their arguments from upper to lower and lower to upper cases respectively. Thanks to a patch from Albert Herranz. - The dhclient 'reject ...;' statement, which rejects leases given by named server-identifiers, now permits address ranges to be specified in CIDR notation. Thanks to a patch from David Boyce. - The subnet-mask option is now supplied by default, but at lowest priority. This helps a small minority of clients that provide parameter request lists, but do not list the subnet-mask option because they were designed to interoperate with a server that behaves in this manner. - The FQDN option is similarly supplied even if it does not appear on the parameter request list, but not to the exclusion of options that do appear at the parameter request list. Up until now it had ultimate priority over the client's parameter request list. - Varying option space code and length bit widths (8/16/32) are now supported. This is a milestone in achieving RFC 3925 "VIVSO" and DHCPv6 support. - A new common (server or client) option, 'db-time-format local;', has been added which prints the local time in /var/db/dhcpd.leases rather than UTC. Thanks to a patch from Ken Lalonde. - Some patches to improve DHCP Server startup speed from Andrew Matheson have been incorporated. - Failover pairs now implement 'MAC Affinity' on leases moving from the active to free states. Leases that belonged to the failover secondary are moved to BACKUP state rather than FREE upon exiting EXPIRED state. If lease rebalancing must move leases, it tries first to move leases that belong to the peer in need. - The server no longer sends POOLREQ messages unless the pool is severely misbalanced in the peer's favor (see 'man dhcpd.conf' for more details). - Pool rebalance events no longer happen upon successfully allocating a lease. Instead, they happen on a schedule. See 'man dhcpd.conf' for the min-balance and max-balance statements for more information. - The DHCP Relay Agent Information Option / Link Selection Sub-Option is now supported. (See RFC3527 for details). - A new DDNS related server option, update-conflict-detection, has been added. If this option is enabled, dhcpd will perform normal DHCID conflict resolution (the default). If this option is disabled, it will instead trust the assigned name implicitly (removing any other bindings on that name). This option has not been made available in dhclient. - In those cases where the DHCP software manufactures an IP header (to transmit via bpf, lpf, etc), the IP TTL the software selects has been increased from 16 to 128. This is intended to match Microsoft Windows DHCP Client behaviour, to increase compatibility. - 'ignore client-updates;' now has behaviour that is different from 'deny client-updates;'. The client's request is not truly ignored, rather it is encouraged. Should this value be configured, the server updates DNS as though client-updates were set to 'deny'. That is, it enters into DNS whatever it is configured to do already, provided it is configured to. Then it sends a response to the client that lets the client believe it is performing client updates (which it will), probably for a different name. In essence, this lets the client do as it will, ignoring this aspect of their request. - Support for compressed 'domain name list' style DHCP option contents, and in particular the domain search option (#119) was added. - The DHCP LEASEQUERY protocol as defined in RFC4388 is now implemented. LEASEQUERY lets you query the DHCP server for information about a lease, using either an IP address, MAC address, or client identifier. Thanks to a patch from Justin Haddad. - DHCPD is now RFC2131 section 4.1 compliant (broadcast to all-ones ip and ethernet mac address) on the SCO platform specifically without any strange ifconfig hacks. Many thanks go to the Kroger Co. for donating the hardware and funding the development. - A new common configuration executable statement, execute(), has been added. This permits dhcpd or dhclient to execute a named external program with command line arguments specified from other configuration language. Thanks to a patch written by Mattias Ronnblom, gotten to us via Robin Breathe. - A new dhcp server option 'adaptive-lease-time-threshold' has been added which causes the server to substantially reduce lease-times if there are few (configured percentage) remaining leases. Thanks to a patch submitted from Christof Chen. - Encapsulated option spaces within encapsulated option spaces is now formally supported. Changes since 3.0.6rc1 - supersede_lease() now requeues leases in their respective hardware address hash bucket. This mirrors client identifier behaviour. Changes since 3.0.5 - Assorted fixes for broken network devices: Packet length is now determined from the IP header length field to finally calculate the UDP payload length, because some NIC drivers return more data than they actually received. - UDP packets are now stored in aligned data structures. - A logic error in omapi interface code was repaired that might result in incorrectly indicating 'up' state when any flags were set, rather than specifically the INTERFACE_REQUESTED flag. Thanks to a patch from Jochen Voss which got to us via Andrew Pollock at Debian. - A reference leak on binding scopes set by ddns updates was repaired. - A memory leak in the minires_nsendsigned() function call was repaired. Effectively, this leaked ~176 bytes per DDNS update. - In the case where an "L2" DHCP Relay Agent (one that does not set giaddr) was directly attached to the same broadcast domain as the DHCP server, the RFC3046 relay agent information option was not being returned to the relay in the server's replies. This was fixed; the dhcp server no longer requires the giaddr to reply with relay agent information. Note that this also improves compatibility with L2 devices that "intercept" DHCP packets and expect relay agent information even in unicast (renewal) replies. Thanks to a patch from Pekka Silvonen. - A bug was fixed where the BOOTP header 'sname' field had a value, the copy written to persistent storage was actually the contents of the 'file' field. - A bug was fixed where the nwip virtual option space was referencing the fqdn option's virtual option space's option cache. - Timestamp parsing errors that indicated missing "minutes" fields rather than the actually missing "seconds" fields have been repaired thanks to a patch from Kevin Steves. - A grammar error in the dhclient.8 manpage was repaired thanks to a patch from Chris Wagner. - Several spelling typos were repaired, and some cross-references to other relevant documents were included in the manpages, thanks to a patch by Andrew Pollock which got to us via Tomas Pospisek. - Some bugs were fixed in the 'emergency relay agent options hologram' which is used to retain relay agent option contents from when the client was in INIT or REBIND states. This should solve problems where relay agent options were not echoed from the server, even when giaddr was set. - dhclient now closes its descriptor to dhclient.leases prior to executing dhclient-script. Thanks to a patch from Tomas Pospisek. - The server's "by client-id" and "by hardware address" hash table lists are now sorted according to the preference to re-allocate that lease to returning clients. This should eliminate pool starvation problems arising when "INIT" clients were given new leases rather than presently active ones. Changes since 3.0.5rc1 - A bug was repaired in fixes to the dhclient, which sought to run the dhclient-script with the 'EXPIRE' state should it receive a NAK in response to a REQUEST. The client now iterates the PREINIT state after the EXPIRE state, so that interfaces that might be configured 'down' can be brought back 'up' and initialized. - DHCPINFORM handling for clients that properly set ciaddr and come to the server via a relay aget has been repaired. Changes since 3.0.4 - A warning that host statements declared within subnet or shared-network scopes are actually global has been added. - The default minimum lease time (if min-lease-time was not specified) was raised from 0 to 300. 0 is not thought to be sensible, and is known to be damaging. - Added additional fatal error sanity checks surrounding lease binding state count calculations (free/active counts used for failover pool balancing). - Some time value size fixes in 3.0.4 brought on from FreeBSD /usr/ports were misapplied to server values rather than client values. The server no longer advertises 8-byte lease-time options when on 64-bit platforms. - A bug where leases not in ACTIVE state would get billed to billed classes (classes with lease limitations) was fixed. Non-active leases OFFERed to clients are no longer billed (but billing is checked before offering). - The dhcpd.conf.5 manpage was updated in regard to the ddns-domainname configuration option - the default configuration and results should be more clear now. - If the dhclient were to receive a DHCPNAK while it was in the RENEW state (and consequently, had an active, 'bound' address and related configuration options), it would fail to 'tear down' this information before proceeding into INIT state. dhclient now iterates the dhclient- script with the 'EXPIRE' action to cause these teardowns prior to entering INIT state. Thanks to a patch from Chris Zimmerman. - The omapi.1 manpage had some formatting errors repaired thanks to a patch from Yoshihiko Sarumaru. - A few lines of code that were failover-specific were moved within #if defined() clauses so that compilation without failover could be made possible. - The log message emitted when the 'leased-address' value was not available in dhcpd.conf "executable statements" has been updated to be more helpful. Manpage information for this value has also been updated. - Abandoned or dissociated (err condition) leases now remove any related dynamic dns bindings. Thanks to a patch from Patrick Schoo. - Attempting to write a new lease file to replace a corrupt (due to encountering non-retryable errors during writing) lease file should no longer result in an infinite recursion. - Host declaration hardware addresses and client identifiers may only be configured once. dhcpd will now fail to load config files that specify multiple identifiers (previous versions would silently over-ride the value with the later configured value). - Several option codes that have been allocated since our last release have been named and documented. - Option names of the form "unknown-123" have been removed from the in- memory hash tables. In order to support options of these names that may appear in dhclient.leases or similar in previous versions, the parser will now find the new option code definition, or mock up a generic option code definition. This should result in a smooth transition from one name to the other, as the new name is used to write new output. Changes since 3.0.4rc1 - The dhcp-options.5 manpage was updated to correct indentation errors thanks to a patch from Jean Delvare. Changes since 3.0.4b3 - Some manual pages were clarified pursuant to discussion on the dhcp-server mailing list. Changes since 3.0.4b2 - Null-termination sensing for certain clients that unfortunately require it in DHCPINFORM processing was repaired. - The host-name option and a few others were moved from "X" format to "t" format to be compatible with new NULL handling functions. - DHCPINFORM processing is a little more careful about return addressing its responses, or if responding via a relay. The INFORM related messages also log the 'effective client ip address' rather than the client's supplied ciaddr (since some clients produce null ciaddrs). - The server was inappropriately sending leases to the RESET state in the event that multiple active leases were found to match a singly-identified client. This was changed to RELEASED (by accepting a different, ACTIVE binding, the client is implicitly releasing its lease). This repairs a bug wherein secondary servers in failover pairs detecting this condition move leases to RESET, and primaries refuse to accept that state transition (properly). - The memset-after-dmalloc() changes made in 3.0.4b1 have been backed out. Changes since 3.0.4b1 - Command line parsing in omshell was repaired - it no longer closes STDIN after reading one line. - The resolver library no longer closes the /etc/resolv.conf file descriptor it opened twice. - Changes to trailing NULL removal in 't' option-atoms has been rethought, it now includes 'd' (domain name) types, and tries hard not to rewind an option beyond the start of the text field it is un-terminating. Changes since 3.0.3 - A DDNS update handling function was misusing the DNS error codes, rather than the internal generic result enumeration. The result is a confusing syslog line, logging the wrong condition. - The DHCP Server was not checking pool balance in the case where it brought a non-ACTIVE lease out of storage for a client that was returning to use a lease it once had long ago, and had since expired. - Failover peers no longer bother to look for free leases to allocate when they already found the client's ACTIVE lease. DISCOVERs are load balanced whether freely-allocated or not, unless the server doubts the peer has leases to allocate. - Fixed a bug in dhcrelay agent addition code that suppressed trailing PAD options - it was suppressing only one trailing PAD option, rather than the entire block of them. ! Fixed some unlikely overlapping-region memcpy() bugs in dhcrelay agent option addition and stripping code. Added a few sanity checks. Although highly improbable, due to requiring the reception of a DHCP datagram well in excess of all known to be used physical MTU limitations, it is possible this may have been used in a stack overflow security vulnerability. Thanks to a patch from infamous42md. ! Added some sanity checks to OMAPI connection/authentication code. Although highly improbable, due to having to deliver in excess of 2^32 bytes of data via the OMAPI channel, not to mention requiring dhcpd to be able to malloc() a memory region 2^32 bytes in size, it was possible this might have resulted in a heap overflow security vulnerability. Thanks to a patch from infamous42md. - dmalloc() memset()'s the non-debug (data) portion of the allocated memory to zero. Code that memset()'s the result returned by dmalloc() to zero is redundant. These redundancies were removed. - Some type declaration corrections to u_int16_t were made in common/tr.c (Token Ring support) thanks to a patch from Jason Vas Dias at Red Hat. - A failover bug that was allowing leases that EXPIRED or were RELEASED where tsfp and tstp are identical timestamps to languish in these transitional states has been repaired. As a side effect, lease databases should be kept more consistent overall, not just for these transitional states. - If the lease db is deleted out from under the daemon, and it moves to rewrite the db, it will go ahead with the operation and move the new db into place once it detects the old db does not exist. - dhclient now ignores IRDA, SIT, and IEEE1394 network interfaces, as it is either nonsensical or (in the case of IEEE1394) is not known to support these interfaces. Thanks to Marius Gedminas and Andrew Pollock of Debian. - Some previously undocumented reasons for dhclient-script invoking has been documented in the dhclient-script.8 manpage. - Failover potential expiry calculations (TSTP) have been corrected. Results should be substantially more consistent, and proper given the constraints. - Adjusted lease state validation checks in potential-conflict, to account for possible clock skew similarly to normal state, and several previously illegal transitions were made legal (ex: active->released). - An impossible sanity check was removed from omapi/buffer.c, thanks to a patch from 'infamous42md'. - An OMAPI host/network byte order problem in lease time values has been repaired. - Several minor bugs, largely relating to treating 8-byte time values as 4-byte entities, have been repaired after careful review of the FreeBSD ports collection's patch set. Thanks to the nameless entities who have contributed to the FreeBSD ports. - When writing a trace file, the file is now created with permissions 0600, to help administrators avoid accidentally publicising sensitive config data. - The calculation of the maximum size of DHCP packets no longer includes Ethernet framing overhead. The result is that the 'Maximum Message Size' option advertised by clients, or the default value 576, is no longer reduced by 14 bytes, and instead directly reflects the IP level MTU (and the default, minimum allowed IP MTU of 576). - The special status of RELEASED/EXPIRED/RESET leases when a server is operating in partner-down was fixed. It no longer requires a lease be twice the MCLT beyond STOS to 'reallocate', and the expiry event to turn these into FREE leases without peer acknowledgement (after STOS+MCLT) has been repaired. - Compilation on older Solaris systems (lacking /usr/include/sys/int_types.h) has been repaired. - "append"ing a string onto the end of a "t" type option (such as the domain-name field) that had been improperly NULL-terminated by the DHCP server will no longer result in a truncated string containing only the option from the server, and not the expected appended value. Thanks to a patch from Jason Vas Dias at Red Hat. - File handlers on configuration state (config files and lease dbs) should be treated consistently, regardless of whether TRACING is defined or not. - The Linux build environment has had some minor improvements - better sensing of 64-bit pointer sizes (only used for establishing an icmp_id), and corrections to #if operators regarding LINUX_MAJOR should it ever move to 3.[01].x. - The server now tries harder to survive the condition where it is unable to open a new lease file to rewrite the lease state database. Changes since 3.0.3b3 - dhclient.conf documentation for interface {} was updated to reflect recent discussion on the dhcp-hackers mailing list. - In response to reports that the software does not compile on GCC 4.0.0, -Werror was removed from Makefile.conf for all platforms that used it. We will address the true problem in a future release; this is a temporary workaround. Changes since 3.0.3b2 - An error in code changes introduced in 3.0.3b2 was corrected, which caused static BOOTP clients to receive random addresses. Changes since 3.0.3b1 - A bug was fixed in BOOTPREQUEST handling code wherein stale references to host records would be left behind on leases that were not allocated to the client currently booting (eg in the case where the host was denied booting). - The dhcpd.conf.5 manpage was updated to be more clear in regards to multiple host declarations (thanks to Vincent McIntyre). 'Interim' style dynamic updates were also retouched. Changes since 3.0.2 - A bug was fixed where a server might load balance a DHCP REQUEST to its peer after already choosing not to load balance the preceding DISCOVER. The peer cannot allocate the originating server's lease. - In the case where a secondary server lost its stable storage while the primary was still in communications-interrupted, and came back online, the lease databases would not be fully transferred to the secondary. This was due to the secondary errantly sending an extra UPDREQ message when the primary made its state transition to PARTNER-DOWN known. - The package will now compile cleanly in gcc 3.3 and 3.4. As a side effect, lease structures will be 9 bytes smaller on all platforms. Thanks to Jason Vas Dias at Red Hat. - Interface discovery code in DISCOVER_UNCONFIGURED mode is now properly restricted to only detecting broadcast interfaces. Thanks to a patch from Jason Vas Dias at Red Hat. - decode_udp_ip_header was changed so that the IP address was copied out to a variable, rather than referenced by a pointer. This enforces 4-byte alignment of the 32-bit IP address value. Thanks to a patch from Dr. Peter Poeml. - An incorrect log message was corrected thanks to a patch from Dr. Peter Poeml. - A bug in DDNS was repaired, where if the server's first DDNS action was a DDNS removal rather than a DDNS update, the resolver library's retransmit timer and retry timer was set to the default, implying a 15 second timeout interval. Which is a little excessive in a synchronous, single-threaded system. In all cases, ISC DHCP should now hold fast to a 1-second timeout, trying only once. - The siaddr field was being improperly set to the server-identifier when responding to DHCP messages. RFC2131 clarified the siaddr field as meaning the 'next server in the bootstrap process', eg a tftp server. The siaddr field is now left zeroed unless next-server is configured. - mockup_lease() could have returned in an error condition (or in the condition where no fixed-address was found matching the shared network) with stale references to a host record. This is probably not a memory leak since host records generally never die anyway. - A bug was repaired where failover servers would let stale client identifiers persist on leases that were reallocated to new clients not sending an id. - Binding scopes ("set var = value;") are now removed from leases allocated by failover peers if the lease had expired. This should help reduce the number of stale binding scopes on leases. - A small memory leak was closed involving client identifiers larger than 7 bytes, and failover. - Configuring a subnet in dhcpd.conf with a subnet mask of 32 bits might cause an internal function to overflow heap. Thanks to Jason Vas Dias at Red Hat. - Some inconsistencies in treating numbers that the lexer parsed as 'NUMBER' or 'NUMBER_OR_NAME' was repaired. Hexadecimal parsing is affected, and should work better. - In several cases, parse warnings were being issued before the lexical token had been advanced to the token whose value was causing an error... causing parse warnings to claim the problem is on the wrong token. - Host declarations matching on client identifier for dynamic leases will no longer match fixed-address host declarations (this is now identical to behaviour for host records matching on hardware address). Changes since 3.0.2rc3 - A previously undocumented configuration directive, 'local-address', was documented in the dhcpd.conf manpage. Changes since 3.0.2rc2 - Two variables introduced in 3.0.2b1 were used without being initialized in the case where neither the FILE nor SNAME fields were available for overloading. This was repaired. - A heretofore believed to be impossible corner case of the option overloading implementation turned out to be possible ("Unable to sort overloaded options after 10 tries."). The implementation was reworked to consider the case of an option so large it would require more than three chunks to fit. - Many other instances of variables being used without being initialized were repaired. - An uninitialized variable in omapi_io_destroy() led to the discovery that this function may result in orphaned pointers (and hence, a memory leak). Changes since 3.0.2rc1 - allocate_lease() was rewritten to repair a bug in which the server would try to allocate an ABANDONED lease when FREE leases were available. Changes since 3.0.2b1 - Some dhcp-eval.5 manpage formatting was repaired. Changes since 3.0.1 - A bug was fixed in the server's 'option overloading' implementation, where options loaded into the 'file' and 'sname' packet fields were not aligned precisely as rfc2131 dictates. - The FreeBSD client script was changed to support the case where a domain name was not provided by the server. - A memory leak in 'omshell' per each command line parsed was repaired, thanks to a patch from Jarkko Torppa. - Log functions writing to stderr were adjusted to use the STDERR_FILENO system definition rather than '2'. This is a no-op for 90% of platforms. - One call to trace_write_packet_iov() counted the number of io vectors incorrectly, causing inconsistent tracefiles. This was fixed. - Some expression parse failure memory leaks were closed. - A host byte order problem in tracefiles was repaired. - Pools configured in DHCPD for failover possessing permission lists that previously were assumed to not include dyanmic bootp clients are now a little more pessimistic. The result is, dhcpd will nag you about just about most pools that possess a 'allow' statement with no 'deny' that would definitely match a dynamic bootp client. - The 'ddns-update-style' configuration warning bit now insists that the configuration be globally scoped. - Two memory leaks in dhclient were closed thanks to a patch from Felix Farkas. - Some minor but excellently pedantic documentation errors were fixed thanks to a patch from Thomas Klausner. - Bugs in operator precedence in executable statements have been repaired once again. More legal syntaxes should be parsed legally. - Failing to initialize a tracefile for any reason if a tracefile was specified is now a fatal error. Thanks to a patch from Albert Herranz. - Corrected a bug in which the number of leases transferred as calculated by the failover primary and sent to peers in POOLRESP responses may be incorrect. This value is not believed to be used by other failover implementations, excepting perhaps as logged information. - Corrected a bug in which 'dhcp_failover_send_poolresp()' was in fact sending POOLREQ messages instead of POOLRESP mesasges. This message was essentially ignored since failover secondaries effectively do not respond to POOLREQ messages. - Type definitions for various bitwidths of integers in the sunos5-5 build of ISC DHCP have been fixed. It should compile and run more easily when built in 64-bit for this platform. - "allow known-clients;" is now a legal syntax, to avoid confusion. - If one dhcp server chooses to 'load balance' a request to its failover peer, it first checks to see if it believes said peer has a free lease to allocate before ignoring the DISCOVER. - log() was logging a work buffer, rather than the value returned by executing the statements configured by the user. In some cases, the work buffer and the intended results were the same. In some other cases, they were not. This was fixed thanks to a patch from Gunnar Fjone and directconnect.no. - Compiler warnings for some string type conversions was fixed, thanks to Andreas Gustafsson. - The netbsd build environments were simplified to one, in which -Wconversion is not used, thanks to Andreas Gustafsson. - How randomness in the backoff-cutoff dhclient configuration variable is implemented was better documented in the manpage, and the behaviour of dhclient in REQUEST timeout handling was changed to match that of DISCOVER timeout handling. - Omapi was hardened against clients that pass in null values, thanks to a patch from Mark Jason Dominus. - A bug was fixed in dhclient that kept it from doing client-side ddns updates. Thanks to a patch from Andreas Gustafsson, which underwent some modification after review by Jason Vas Dias. - Failover implementations disconnected due to the network between them (rather than one of the two shutting down) will now try to re-establish the failover connection every 5 seconds, rather than to simply try once and give up until one of them is restarted. Thanks to a patch from Ulf Ekberg from Infoblox, and field testing by Greger V. Teigre which led to an enhancement to it. - A problem that kept DHCP Failover secondaries from tearing down ddns records was repaired. Thanks to a patch from Ulf Ekberg from Infoblox. - 64bit pointer sizes are detected properly on FreeBSD now. - A bug was repaired where the DHCP server would leave stale references to host records on leases it once thought about offering to certain clients. The result would be to apply host and 'known' scopes to the wrong clients (possibly denying booting). NOTE: The 'mis-host' patch that was being circulated as a workaround is not the way this bug was fixed. If you were a victim of this bug in 3.0.1, you are cautioned to proceed carefully and see if it fixes your problem. - A bug was repaired in the server's DHCPINFORM handling, where it tried to divine the client's address from the source packet and would get it wrong. Thanks to Anshuman Singh Rawat. - A log message was introduced to help illuminate the case where the server was unable to find a lease to assign to any BOOTP client. Thanks to Daniel Baker. - A minor dhcpd.conf.5 manpage error was fixed. Changes since 3.0.1rc14 - The global variable 'cur_time' was centralized and is now uniformly of a type #defined in system-dependent headers. It had previously been defined in one of many places as a 32-bit value, and this causes mayhem on 64-bit big endian systems. It probably wasn't too healthy on little endian systems either. - A printf format string error introduced in rc14 was repaired. - AIX system-dependent header file was altered to only define NO_SNPRINTF if the condition used to #ifdef in vsnprintf in AIX' header files is false. - The Alpha/OSF system-dependent header file was altered to define NO_SNPRINTF on OS revisions older than 4.0G. - omapip/test.c had string.h added to its includes. Changes since 3.0.1rc13 ! CAN-2004-0460 - CERT VU#317350: Five stack overflow exploits were closed in logging messages with excessively long hostnames provided by the clients. It is highly probable that these could have been used by attackers to gain arbitrary root access on systems using ISC DHCP 3.0.1 release candidates 12 or 13. Special thanks to Gregory Duchemin for both finding and solving the problem. ! CAN-2004-0461 - CERT VU#654390: Once the above was closed, an opening in log_*() functions was evidenced, on some specific platforms where vsnprintf() was not believed to be available and calls were wrapped to sprintf() instead. Again, credit goes to Gregory Duchemin for finding the problem. Calls to snprintf() are now linked to a distribution-local snprintf implementation, only in those cases where the architecture is not known to provide one (see includes/cf/[arch].h). If you experience linking problems with snprintf/vsnprintf or 'isc_print_' functions, this is where to look. This vulnerability did not exist in any previously published version of ISC DHCP. - Compilation on hpux 11.11 was repaired. - 'The cross-compile bug fix' was backed out. Changes since 3.0.1rc12 - Fixed a bug in omapi lease lookup function, to form the hardware address for the hash lookup correctly, thanks to a patch from Richard Hirst. - Fixed a bug where dhcrelay was sending relayed responses back to the broadcast address, but with the source's unicast mac address. Should now conform to rfc2131 section 4.1. - Cross-compile bug fix; use $(AR) instead of ar. Thanks to Morten Brorup. - Fixed a crash bug in dhclient where dhcpd servers that do not provide renewal times results in an FPE. As a side effect, dhclient can now properly handle 0xFFFFFFFF (-1) expiry times supplied by servers. Thanks to a patch from Burt Silverman. - The 'ping timeout' debugs from rc12 were removed to -DDEBUG only, and reformatted to correct a compilation error on Solaris platforms. - A patch was applied which fixes a case where leases read from the leases database do not properly over-ride previously read leases. - dhcpctl.3 manpage was tweaked. Changes since 3.0.1rc11 - A patch from Steve Campbell was applied with minor modifications to permit reverse dns PTR record updates with values containing spaces. - A patch from Florian Lohoff was applied with some modifications to dhcrelay. It now discards packets whose hop count exceeds 10 by default, and a command-line option (-c) can be used to set this threshold. - A failover bug relating to identifying peers by name length instead of by name was fixed. - Declaring failover configs within shared-network statements should no longer result in error. - The -nw command line option to dhclient now works. - Thanks to a patch from Michael Richardson: - Some problems with long option processing have been fixed. - Some fixes to minires so that updates of KEY records will work. - contrib/ms2isc was updated by Shu-Min Chang of the Intel Corporation. see contrib/ms2isc/readme.txt for revision notes. - Dhclient no longer uses shell commands to kill another instance of itself, it sends the signal directly. Thanks to a patch from Martin Blapp. - The FreeBSD dhclient-script was changed so that a failure to write to /etc/resolv.conf does not prematurely end the script. This keeps dhclient from looping infinitely when this is the case. Thanks to a patch from Martin Blapp. - A patch from Bill Stephens was applied which resolves a problem with lease expiry times in failover configurations. - A memory leak in configuration parsing was closed thanks to a patch from Steve G. - The function which discovers interfaces will now skip non-broadcast or point-to-point interfaces, thanks to a patch from David Brownlee. - Options not yet known by the dhcpd or dhclient have had their names changed such that they do not contain # symbols, in case they should ever appear in a lease file. An option that might have been named "#144" is now "unknown-144". - Another patch from Bill Stephens which allows the ping-check timeout to be configured as 'ping-timeout'. Defaults to 1. Changes since 3.0.1rc10 - Potential buffer overflows in minires repaired. - A change to the linux client script to use /bin/bash, since /bin/sh may not be bash. - Some missing va_end cleanups thanks to a patch from Thomas Klausner. - A correction of boolean parsing syntax validation - some illegal syntaxes that worked before are now detected and produce errs, some legal syntaxes that errored before will now work properly. - Some search-and-replace errors that caused some options to change their names was repaired. - Shu-min Chang of the Intel corporation has contributed a perl script and module that converts the MS NT4 DHCP configuration to a ISC DHCP3 configuration file. - Applied the remainder of the dhcpctl memory leak patch provided by Bill Squier at ReefEdge, Inc. (groo@reefedge.com). - Missing non-optional failover peer configurations will now result in a soft error rather than a null dereference. Changes since 3.0.1rc9 - A format string was corrected to fix compiler warnings. - A number of spelling corrections were made in the man pages. - The dhclient.conf.5 man page was changed to refer to do-forward-updates rather than a configuration option that doesn't exist. - A FreeBSD-specific bug in the interface removal handling was fixed. - A Linux-specific Token Ring detection problem was fixed. - Hashes removed from as-yet-unknown agent options, having those options appear in reality before we know about them will no longer produce self-corrupting lease databases. - dhclient will use the proper port numbers now when using the -g option. - A order-of-operations bug with 2 match clauses in 1 class statement is fixed thanks to a patch from Andrew Matheson. - Compilation problems on Solaris were fixed. - Compilation problems when built with DEBUG or DEBUG_PACKET were repaired. - A fix to the dhcp ack process which makes certain group options will be included in the first DHCPOFFER message was made thanks to a patch from Ling Gou. - A few memory leaks were repaired thanks to patches from Bill Squier at ReefEdge, Inc. (groo@reefedge.com). - A fix for shared-networks that sometimes give clients options for the wrong subnets (in particular, 'option routers') was applied, thanks to Ted Lemon for the patch. - Omshell's handling of dotted octets as values was changed such that dots one after the other produce zero values in the integer string. Changes since 3.0.1rc8 - Fix a format string vulnerability in the server that could lead to a remote root compromise (discovered by NGSEC Research Team, www.ngsec.com). - Add additional support for NetBSD/sparc64. - Fix a bug in the command-line parsing of the client. Also, resolve a memory leak. - Add better support for shells other than bash in the Linux client script. - Various build fixes for modern versions of FreeBSD and Linux. - Fix a bad bounds check when printing binding state names. - Clarify documentation about fixed-address and multiple addresses. - Fix a typo in the authoritative error message. - Make a log entry when we can't write a billing class. - Use conversion targets that are the right size on all architectures. - Increment the hop count when relaying. - Log a message when lease state is changed through OMAPI. - Don't rerun the shared_network when evaluating the pool. - Fix a reversed test in the parser. - Change the type of rbuf_max. - Make FTS_LAST a manifest constant to quiet warnings. Changes since 3.0.1rc7 - Fix two compiler warnings that are generated when compiling on Solaris with gcc. These stop the build, even though they weren't actually errors, because we prefer that our builds generate no warnings. Changes since 3.0.1rc6 - Don't allow a lease that's in the EXPIRED, RELEASED or RESET state to be renewed. - Implement lease stealing for cases where the primary has fewer leases than the secondary, as called for by the standard. - Add a fudge factor to the lease expiry acceptance code, (suggested by Kevin Miller of CMU). - Fix a bug in permit_list_match that made it much too willing to say that two permit lists matched. - Unless DEBUG_DNS_UPDATES is defined, print more user-friendly (and also more compact) messages about DNS updates. - Fix a bug in generating wire-format domain names for the FQDN option. - Fix a bug where the FQDN option would not be returned if the client requested it, contrary to the standard. - On Darwin, use the FreeBSD DHCP client script. - On NetBSD/sparc, don't check for casting warnings. - Add a flag in the DHCP client to disable updating the client's A record when sending an FQDN option indicating that the client is going to update its A record. - In the client, don't attempt a DNS update until one second after configuring the new IP address, and if the update times out, keep trying until a response, positive or negative, is received from the DNS server. - Fix an uninitialized memory bug in the DHCP client. - Apply some FreeBSD-specific bug fixes suggested by Murray Stokely. - Fix a bug in ns_parserr(), where it was returning the wrong sort of result code in some cases (suggested by Ben Harris of the NetBSD project). - Fix a bug in is_identifier(), where it was checking against EOF instead of the END_OF_FILE token (also suggested by Ben Harris). - Fix a bug where if an option universe contained no options, the DHCP server could dump core (Walter Steiner). - Fix a bug in the handling of encapsulated options. - Fix a bug that prevented NWIP suboptions from being processed. - Delete the FTS_BOOTP and FTS_RESERVED states and implement them as modifier flags to the FTS_ACTIVE state, as called for in the failover protocol standard. - Fix bugs in the pool merging code that resulted in references and dereferences of null pointers. This bug had no impact unless the POINTER_DEBUG flag was defined. - In the server, added a do-forward-updates flag that can be used to disable forward updates in all cases, so that sites that want the clients to take sole responsibility for updating their A record can do so. - Make it possible to disable optimization of PTR record updates. Changes since 3.0.1rc5 - Include some new documentation and changes provided by Karl Auer. - Add a workaround for some Lexmark printers that send a double-NUL- terminated host-name option, which would break DNS updates. - Fix an off-by-one error in the MAC-address checking code for DHCPRELEASE that was added in 3.0.1rc5. - Fix a bug where client-specific information was not being discarded from the lease when it expired or was released, resulting in problems if the lease was reallocated to a different client. - If more than one allocation pool is specified that has the same set of constraints as another allocation pool on the same shared network, merge the two pools. - Don't print an error in fallback_discard, since this just causes confusion and does not appear to be helping to encourage anyone to fix this bug. Changes since 3.0.1rc4 - Fix a bug that would cause the DHCP server to spin if asked to parse a certain kind of incorrect statement. - Fix a related bug that would prevent an error from being reported in the same case. - Additional documentation. - Make sure that the hardware address matches the lease when processing a DHCPRELEASE message. Changes since 3.0.1rc3 - A minor bug fix in the arguments to a logging function call. - Documentation update for dhcpd.conf. Changes since 3.0.1rc2 - Allow the primary to send a POOLREQ message. This isn't what the current failover draft says to do, so we may have to back it out if I can't get the authors to relent, but the scheme for balancing that's specified in the current draft seems needlessly hairy, so I'm floating a trial balloon. The rc1 code did not implement the method described in the draft either. Changes since 3.0.1rc1 - Treat NXDOMAIN and NXRRSET as success when we are trying to delete a domain or RRSET. This allows the DHCP server to forget about a name it added to the DNS once it's been removed, even if the DHCP server wasn't the one that removed it. - Install defaults for failover maximum outstanding updates and maximum silent time. This prevents problems that might occur if these values were not configured. - Don't do DDNS deletes if ddns-update-style is none. - Return relay agent information options in DHCPNAK. This prevents DHCPNAK messages from being dropped when the relay agent information option contains routing information. - Fix a problem where coming up in recover wouldn't result in an update request being sent. - Add some more chatty messages when we start a recovery update and when it's done. - Fix a possible problem where some state might have been left around after the peer lost contact and regained contact about how many updates were pending. - Don't nix a lease update because of a lease conflict. This test has never (as far as I know) prevented a mistake, and it appears to cause problems with failover. - Add support in rc history code for keeping a selective history, rather than a history of all references and dereferences. This code is only used when extensive additional debugging is enabled. Changes since 3.0 - Make allocators for hash tables. As a side effect, this fixes a memory smash in the subclass allocation code. - Fix a small bug in omshell where if you try to close an object when no object is open, it dumps core. - Fix an obscure coredump that could occur on shutdown. - Fix a bug in the recording of host declaration rubouts in the lease file. - Fix two potential spins in the host deletion code. - Fix a core dump that would happen if an application tried to update a host object attribute with a null value. Changes since 3.0 Release Candidate 12 - Fix a memory leak in the evaluation code. - Fix an obscure core dump. - Print a couple of new warnings when parsing the configuration file when crucial information is left out. - Log "no free leases" as an error. - Documentation updates. Changes since 3.0 Release Candidate 11 - Always return a subnet selection option if one is sent. - Fix a warning that was being printed because an automatic data structure wasn't zeroed. - Fix some failover state transitions that were being handled incorrectly. - When supersede_lease is called on a lease whose end time has already expired, but for which a state transition has not yet been done, do a state transition. This fixes the case where if the secondary allocated a lease to a client and the lease "expired" while the secondary was in partner-down, no expiry event would actually happen, so the lease would remain active until the primary was restarted. Changes since 3.0 Release Candidate 10 - Fix a bug that was preventing released leases from changing state in failover-enabled pools. - Fix a core dump in the client identifier finder code (for host declarations). - Finish fixing a bug where bogus data would sometimes get logged to the dhclient.leases file because it was opened as descriptor 2. - Fix the Linux dhclient-script according to suggestions made by several people on the dhcp-client mailing list. - Log successful DNS updates at LOG_INFO, not LOG_ERROR. - Print an error message and refuse to run if a failover peer is defined but not referenced by any pools. - Correct a confusing error message in failover. Changes since 3.0 Release Candidate 9 - Fix a bug in lease allocation for Dynamic BOOTP clients. Changes since 3.0 Release Candidate 8 Patchlevel 2 - Fix a bug that prevented update-static-leases from working. - Document failover-state OMAPI object. - Fix a compilation error on SunOS 4. Changes since 3.0 Release Candidate 8 Patchlevel 1 - Fix a parsing bug that broke dns updates (both interim and ad-hoc). This was introduced in rc8pl1 as an unintended result of the memory leakage fixes that were in pl1. - Fix a long-standing bug where the server would record that an update had been done for a client with no name, even though no update had been done, and then when the client's lease expired the deletion of that nonexistant record would time out because the name was the null string. - Clean up the omshell, dhcpctl and omapi man pages a bit. Changes since 3.0 Release Candidate 8 - Fix a bug that could cause the DHCP server to spin if one-lease-per-client was enabled. - Fix a bug that was causing core dumps on BSD/os in the presence of malformed packets. - In partner-down state, don't restrict lease lengths to MCLT. - On the failover secondary, record the MCLT received from the primary so that if we come up without a connection to the primary we don't wind up giving out zero-length leases. - Fix some compilation problems on BSD/os. - Fix a bunch of memory leaks. - Fix a couple of bugs in the option printer. - Fix an obscure error reporting bug in the dns update code, and also make the message clearer when a key algorithm isn't supported. - Fix a bug in the tracing code that prevented trace runs that used tcp connections from being played back. - Add some additional debugging capability for catching memory leaks on exit. - Make the client release the lease correctly on shutdown. - Add some configurability to the build system. - Install omshell manual page in man1, not man8. - Craig Gwydir sent in a patch that fixes a long-standing bug in the DHCP client that could cause core dumps, but that for some reason hadn't been noticed until now. Changes since 3.0 Release Candidate 7 - Fix a bug in failover where we weren't sending updates after a transition from communications-interrupted to normal. - Handle expired/released/reset -> free transition according to the protocol specification (this works - the other way not only wasn't conformant, but also didn't work). - Add a control object in both client and server that allows either daemon to be shut down cleanly. - When writing a lease, if we run out of disk space, shut down the output file and insist on writing a new one before proceeding. - In the server, if the OMAPI listener port is occupied, keep trying to get it, rather than simply giving up and exiting. - Support fetching variables from leases and also updating and adding variables to leases via OMAPI. - If two failover peers have wildly different clocks, refuse to start doing failover. - Fix a bug in the DNS update code that could cause core dumps when running on alpha processors. - Fixed a bug in ddns updates for static lease entries, thanks to a patch from Andrey M Linkevitch. - Add support for Darwin/MacOS X - Install omshell (including new documentation). - Support DNS updates in the client (this is a very obscure feature that most DHCP client users probably will not be able to use). - Somewhat cleaner status logging in the client. - Make OMAPI key naming syntax compatible with the way keys are actually named (key names are domain names). - Fix a bug in the lease file writer. - Install DHCP ISC headers in a different place than BIND 9 ISC headers, to avoid causing trouble in BIND 9 builds. - Don't send updates for attributes on an object when the attributes haven't changed. Support deleting attributes on remote objects. - Fix a number of bugs in omshell, and add the unset and refresh statements. - Handle disconnects in OMAPI a little bit more intelligently (so that the caller gets ECONNRESET instead of EINVAL). - Fix a bunch of bugs in the handling of clients that have existing leases when the try to renew their leases while failover is operating. Changes since 3.0 Release Candidate 6 - Fix a core dump that could happen when processing a DHCPREQUEST from a client that had a host declaration that contained both a fixed-address declaration and a dhcp-client-identifier option declaration, if the client identifier was longer than nine bytes. - Fix a memory leak that could happen in certain obscure cases when using omapi to manipulate leases. - Fix some bugs and omissions in omshell. Changes since 3.0 Release Candidate 5 - Fix a bug in omapi_object_dereference that prevented objects in chains from having their reference counts decreased on dereference. - Fix a bug in omapi_object_dereference that would prevent object chains from being freed upon removal of the last reference external to the chain. - Fix a number of other memory leaks in the OMAPI protocol subsystem. - Add code in the OMAPI protocol handler to trace memory leakage. - Clean up the memory allocation/reference history printer. - Support input of dotted quads and colon-separated hex lists as attribute values in omshell. - Fix a typo in the Linux interface discovery code. - Conditionalize a piece of trace code that wasn't conditional. Changes since 3.0 Release Candidate 4 - Fix a bug that would prevent leases from being abandoned properly on DHCPDECLINE. - Fix failover peer OMAPI support. - In failover, correctly handle expiration of leases. Previously, leases would never be reclaimed because they couldn't make the transition from EXPIRED to FREE. - Fix some broken failover state transitions. - Documentation fixes. - Take out an unnecessary check in DHCP relay agent information option stashing code that was preventing REBINDING clients from rebinding. - Prevent failover peers from allocating leases in DHCPREQUEST processing if the lease belongs to the other server. - Record server version in lease file introductory comment. - Correctly report connection errors in OMAPI and failover. - Make authentication signature algorithm name comparisons in OMAPI case-insensitive. - Fix compile problem on SunOS 4.x - If a signature algorithm is not terminated with '.', terminate it so that comparisons between fully-qualified names will work consistently. - Different SIOCGIFCONF probe code, may "fix" problem on some Linux systems with the probe not working correctly. - Don't allow user to type omapi key on command line of omshell. Changes since 3.0 Release Candidate 3 - Do lease billing on startup in a way that I *think* will finally do the billing correctly - the previous method could overbill as a result of duplicate leases. - Document OMAPI server objects. Changes since 3.0 Release Candidate 2 Patchlevel 1 - Fix some problems in the DDNS update code. Thanks to Albert Herranz for figuring out the main problem. - Fix some reference counting errors on host entries that were causing core dumps. - Fix a byte-swap bug in the token ring code, thanks to Jochen Friedrich. - Fix a bug in lease billing, thanks to Jonas Bulow. Changes since 3.0 Release Candidate 2 - Change the conditions under which a DHCPRELEASE is actually committed to be consistent with lease binding states rather than using the lease end time. This may fix some problems with the billing class code. - Fix a bug where lease updates would fail on Digital Unix (and maybe others) because malloc was called with a size of zero. - Fix a core dump that happens when the DHCP server can't create its trace file. Changes since 3.0 Release Candidate 1 Patchlevel 1 - Fix the dhcp_failover_put_message to not attempt to allocate a zero-length buffer. Some versions of malloc() fail if you try to allocate a zero-length buffer, and this was causing problems on, e.g., Digital Unix. - Fix a case where the failover code was printing an error message when no error had occurred. - Fix a problem where when a server went down and back up again, the peer would not see a state transition and so would stay in the non-communicating state. - Be smart about going into recover_wait. - Fix a problem in the failover implementation where peers would fail to come into sync if interrupted in the RECOVER state. This could have been the cause of some problems people have reported recently. - Fix a problem with billing classes where they would not be unbilled when the client lease expired. - If select fails, figure out which descriptor is bad, and cut it out of the I/O loop. This prevents a potentially nasty spin. I haven't heard any report it in a while, but it came up consistently in testing. - Fix a bug in the relay agent where if you specified interfaces on the command line, it would fail. - Fix a couple of small bugs in the omapi connection object (no known user impact). - Add the missing 3.0 Beta 1 lease conversion script. - Read dhcp client script hooks if they exist, rather than only if they're executable. Changes since 3.0 Release Candidate 1 - Fix a memory smash that happens when fixed-address leases are used. ANY SITE AT WHICH FIXED-ADDRESS STATEMENTS ARE BEING USED SHOULD UPGRADE IMMEDIATELY. This has been a long-standing bug - thanks to Alvise Nobile for discovering it and helping me to find it! - Fix a small bug in binary-to-ascii, thanks to H. Peter Anvin of Transmeta. - There is a known problem with the DHCP server doing failover on Compaq Alpha systems. This patchlevel is not a release candidate because of this bug. The bug should be straightforward to fix, so a new release candidate is expected shortly. - There is a known problem in the DDNS update code that is probably a bug, and is not, as far as we know, fixed in this patchlevel. Changes since 3.0 Beta 2 Patchlevel 24 - Went over problematic failover state transitions and made them all work, so that failover should now much less fragile. - Add some dhcpctl and omapi documentation - Fix compile errors when compiling with unusual predefines. - Make Token Ring work on Linux 2.4 - Fix the Digital Unix BPF_WORDALIGN bug. - Fix some dhcp client documentation errors. - Update some parts of the README file. - Support GCC on SCO. Changes since 3.0 Beta 2 Patchlevel 23 - Fix a bug in the DNS update code where a status code was not being checked. This may have been causing core dumps. - When parsing the lease file, if a lease declaration includes a billing class statement, and the lease already has a billing class, unbill the old class. - When processing failover transactions, where acks will be deferred, process the state transition immediately. - Don't try to use the new SIOCGIFCONF buffer size detection code on Linux 2.0, which doesn't provide this functionality. - Apply a patch suggested by Tuan Uong for a problem in dlpi.c. - Fix a problem in using the which command in the configure script. - Fix a parse error in the client when setting up an omapi listener. - Document the -n and -g flags to the client. - Make sure there is always a stdin and stdout on startup. This prevents shell scripts from accidentally writing error messages into configuration files that happen to be opened as stderr. - If an interface is removed, the client will now notice that it is gone rather than spinning. This has only been tested on NetBSD. - The client will attempt to get an address even if it can't create a lease file. - Don't overwrite tracefiles. - Fix some memory allocation bugs in failover. Changes since 3.0 Beta 2 Patchlevel 22 - Apply some patches suggested by Cyrille Lefevre, who is maintaining the FreeBSD ISC DHCP Distribution port. - Fix a core dump in DHCPRELEASE. Changes since 3.0 Beta 2 Patchlevel 21 - This time for sure: fix the spin described in the changes for pl20. Changes since 3.0 Beta 2 Patchlevel 20 - Fix a problem with Linux detecting large numbers of interfaces (Ben) - Fix a memory smash in the quotify code, which was introduced in pl19. - Actually fix the spin described in the changes for pl20. The previous fix only partially fixed the problem - enough to get it past the regression test. Changes since 3.0 Beta 2 Patchlevel 19 - Fix a bug that could cause the server to abort if compiled with POINTER_DEBUG enabled. - Fix a bug that could cause the server to spin when responding to a DHCPREQUEST. - Apply Joost Mulders' suggested patches for DLPI on x86. - Support NUL characters in quoted strings. - Install unformatted man pages on SunOS. Changes since 3.0 Beta 2 Patchlevel 18 - Allow the server to be placed in partner-down state using OMAPI. (Damien Neil) - Implement omshell, which can be used to do arbitrary things to the server (in theory). (Damien Neil) - Fix a case where if a client had two different leases the server could actually dereference the second one when it hadn't been referenced, leading to memory corruption and a core dump. (James Brister) - Fix a case where a client could request the address of another client's lease, but find_lease wouldn't detect that the other client had it, and would attempt to allocate it to the client, resulting in a lease conflict message. - Fix a case where a client with more than one client identifier could be given a lease where the hardware address was correct but the client identifier was not, resulting in a lease conflict message. - Fix a problem where the server could write out a colon-separated hex list as a value for a variable, which would then not parse. The fix is to always write strings as quoted strings, with any non-printable characters quoted as octal escape sequences. So a file written the old way still won't work, but new files written this way will work. - Fix documentation for sending non-standard options. - Use unparsable names for unknown options. WARNING: this will break any configuration files that use the option-nnn convention. If you want to continue to use this convention for some options, please be sure to write a definition, like this: option option-nnn code nnn = string; You can use a descriptive name instead of option-nnn if you like. - Fix a problem where we would see a DHCPDISCOVER/DHCPOFFER/ DHCPREQUEST/DHCPACK/DHCPREQUEST/DHCPNAK sequence. This was the result of a deceptively silly bug in supersede_lease. - Fix client script exit status check, according to a fix supplied by Hermann Lauer. - Fix an endianness bug in the tracefile support, regarding ICMP messages. - Fix a bug in the client where the medium would not work correctly if it contained quoted strings. ** there was no pl17 ** Changes since 3.0 Beta 2 Patchlevel 16 - Add support for transaction tracing. This allows the state of the DHCP server on startup, and all the subsequent transactions, to be recorded in a file which can then be played back to reproduce the behaviour of the DHCP server. This can be used to quickly reproduce bugs that cause core dumps or corruption, and also for tracking down memory leaks. - Incorporate some bug fixes provided by Joost Mulders for the DLPI package which should clear up problems people have been seeing on Solaris. - Fix bugs in the handling of options stored as linked lists (agent options, fqdn options and nwip options) that could cause memory corruption and core dumps. - Fix a bug in DHCPREQUEST handling that resulted in DHCPNAK messages not being send in some cases when they were needed. - Make the lease structure somewhat more compact. - Make initial failover startup *much* faster. This was researched and implemented by Damien Neil. - Add a --version flag to all executables, which prints the program name and version to standard output. - Don't rewrite the lease file every thousand leases. - A bug in nit.c for older SunOS machines was fixed by a patch sent in by Takeshi Hagiwara. - Fix a memory corruption bug in the DHCP client. - Lots of documentation updates. - Add a feature allowing environment variables to be passed to the DHCP client script on the DHCP client command line. - Fix client medium support, which had been broken for some time. - Fix a bug in the DHCP client initial startup backoff interval, which would cause two DHCPDISCOVERS to be sent back-to-back on startup. Changes since 3.0 Beta 2 Patchlevel 15 - Some documentation tweaks. - Maybe fix a problem in the DLPI code. - Fix some error code space inconsistencies in ddns update code. - Support relay agents that intercept unicast DHCP messages to stuff agent options into them. - Fix a small memory leak in the relay agent option support code. - Fix a core dump that would occur if a packet was sent with no options. Changes since 3.0 Beta 2 Patchlevel 14 - Finish fixing a long-standing bug in the agent options code. This was causing core dumps and failing to operate correctly - in particular, agent option stashing wasn't working. Agent option stashing should now be working, meaning that agent options can be used in class statements to control address allocation. - Fix up documentation. - Fix a couple of small memory leaks that would have added up significantly in a high-demand situation. - Add a log-facility configuration parameter. - Fix a compile error on some older operating systems. - Add the ability in the client to execute certain statements before transmitting packets to the server. Handy for debugging; not much practical use otherwise. - Don't send faked-out giaddr when renewing or bound - again, useful for debugging. Changes since 3.0 Beta 2 Patchlevel 13 - Fixed a problem where the fqdn decoder would sometimes try to store an option with an (unsigned) negative length, resulting in a core dump on some systems. - Work around the Win98 DHCP client, which NUL-terminates the FQDN option. - Work around Win98 and Win2k clients that will claim they want to do the update even when they don't have any way to do it. - Fix some log messages that can be printed when failover is operating that were not printing enough information. - It was possible for a DHCPDISCOVER to get an allocation even when the state machine said the server shouldn't be responding. - Don't load balance DHCPREQUESTs from clients in RENEWING and REBINDING, since in RENEWING, if we heard it, it's for us, and in REBINDING, the client wouldn't have got to REBINDING if its primary were answering. - When we get a bogus state lease binding state transition, don't do the transition. Changes since 3.0 Beta 2 Patchlevel 12 - Fixed a couple of silly compile errors. Changes since 3.0 Beta 2 Patchlevel 11 - Albert Herranz tracked down and fixed a subtle bug in the base64 decoder that would prevent any key with an 'x' in its base64 representation from working correctly. - Thanks to Chris Cheney and Michael Sanders, we have a fix for the hang that they both spotted in the DHCP server - when one-lease-per-client was set, the code to release the "other" lease could spin. - Fix a problem with alignment of the input buffer in bpf in cases where two packets arrive in the same bpf read. - Fix a problem where the relay agent would crash if you specified an interface name on the command line. - Add the ability to conditionalize client behaviour based on the client state. - Add support for the FQDN option, and added support for a new way of doing ddns updates (ddns update style interim) that allows more than one DHCP server to update the DNS for the same network(s). This was implemented by Damien Neil with some additional functionality added by Ted Lemon. - Damien added a "log" statement, so that the configuration file can be made to log debugging information and other information. - Fixed a bug that caused option buffers not to be terminated with an end option. - Fixed a long-standing bug in the support for option spaces where the options are stored as an ordered list rather than in a hash table, which could theoretically result in memory pool corruption. - Prevent hardware declarations with no actual hardware address from being written as something unparsable, and behave correctly in the face of a null hardware address on input. - Allow key names to be FQDNs, and qualify the algorithm name if it is specified unqualified. - Modify the DDNS update code so that it never prints the "resolver failed" message, but instead says *why* the resolver failed. - Officially support the subnet selection option, which now has an RFC. - Fix a build bug on MacOS X. - Allow administrator to disable ping checking. - Clean up dhcpd.conf documentation and add more information about how it works. Changes since 3.0 Beta 2 Patchlevel 10 - Fix a bug introduced during debugging (!) and accidentally committed to CVS. Changes since 3.0 Beta 2 Patchlevel 9 - Fix DHCP client handling of vendor encapsulated options. - Fix a bug in the handling of relay agent information options introduced in patchlevel 9. - Stash agent options on client leases by default, and use the stashed options at renewal time. - Add the ability to test the client's binding state in the client configuration language. - Fix a core dump in the DNS update code. - Fix some expression evaluation bugs that were causing updates to be done when no client hostname was received. - Fix expression evaluation debugging printfs. - Teach pretty_print_option to print options in option spaces other than the DHCP option space. - Add a warning message if the RHS of a not is not boolean. - Never select for more than a day, because some implementations of select will just fail if the timeout is too long (!). - Fix a case where a DHCPDISCOVER from an unknown network would be silently dropped. - Fix a bug where if a client requested an IP address for which a different client had the lease, the DHCP server would reallocate it anyway. - Fix the DNS update code so that if the client changes its name, the DNS will be correctly updated. Changes since 3.0 Beta 2 Patchlevel 8 - Oops, there was another subtle math error in the header-length bounds-checking. Changes since 3.0 Beta 2 Patchlevel 7 - Oops, forgot to byte-swap udp header length before bounds-checking it. Changes since 3.0 Beta 2 Patchlevel 6 - Fix a possible DoS attack where a client could cause the checksummer to dump core. This was a read, not a write, so it shouldn't be possible to exploit it any further than that. - Implement client- and server-side support for using the Client FQDN option. - Support for other option spaces in the client has been added. This means that it is now possible to define a vendor option space on the client, request options in that space from the server (which must define the same option space), and then use those options in the client. This also allows NWIP and Client FQDN options to be used meaningfully. - Add object initializer support. This means that objects can now be initialized to something other than all-zeros when allocated, which makes, e.g., the interface object support code a little more robust. - Fix an off-by-one bug in the host stuffer. This was causing host deletes not the work, and may also have been causing OMAPI connections to get dropped. Thanks to James Brister for tracking this one down! - Fixed a core dump in the interface discovery code that is triggered when there is no subnet declaration for an interface, but the server decides to continue running. Thanks to Shane Kerr for tracking down and fixing this problem. Changes since 3.0 Beta 2 Patchlevel 5 - Fix a bug in the recent enhancement to the interface discovery code to support arbitrary-length interface lists. - Support NUL-terminated DHCP options when initializing client-script environment. - Fix suffix operator. - Fix NetWare/IP option parsing. - Better error/status checking in dhcpctl initialization and omapi connection code. - Fix a potential memory smash in dhcpctl code. - Fix SunOS4 and (maybe) Ultrix builds. - Fix a bug where a certain sort of incoming packet could cause a core dump on Solaris (and probably elsewhere). - Add some more safety checks in error logging code. - Add support for ISC_R_INCOMPLETE in OMAPI protocol connection code. - Fix relay agent so that if an interface is specified on the command line, the relay agent does not dump core. - Fix class matching so that match if can be combined with match or spawn with. - Do not allow spurious leases in the lease database to introduce potentially bogus leases into the in-memory database. - Fix a byte-order problem in the client hardware address type code for OMAPI. - Be slightly less picky about what sort of hardware addresses OMAPI can install in host declarations. Changes since 3.0 Beta 2 Patchlevel 4 - Incorporated Peter Marschall's proposed change to array/record parsing, which allows things like the slp-agent option to be encoded correctly. Thanks very much to Peter for taking the initiative to do this, and for doing such a careful job of it (e.g., updating the comments)! - Added an encoding for the slp-agent option. :') - Fixed SunOS 4 build. Thanks to Robert Elz for responding to my request for help on this with patches! - Incorporated a change that should fix a problem reported by Philippe Jumelle where when the network connection between two servers is lost, they never reconnect. - Fix client script files other than that for NetBSD to actually use make_resolv_conf as documented in the manual page. - Fix a bug in the packet handling code that could result in a core dump. - Fix a bug in the bootp code where responses on the local net would be sent to the wrong MAC address. Thanks to Jerry Schave for catching this one. Changes since 3.0 Beta 2 Patchlevel 3 - In the DHCP client, execute client statements prior to using the values of options, so that the client configuration can overridden, e.g., the lease renewal time. - Fix a reference counting error that would result in very reproducible failures in updates, as well as occasional core dumps, if a zone was declared without a key. - Fix some Linux 2.0 compilation problems. - Fix a bug in scope evaluation during execution of "on" statements that caused values not to be recorded on leases. - If the dhcp-max-message-size option is specified in scope, and the client didn't send this option, use the one specified in scope to determine the maximum size of the response. Changes since 3.0 Beta 2 Patchlevel 2 - Fix a case where spawning subclasses were being allocated incorrectly, resulting in a core dump. - Fix a case where the DHCP server might inappropriately NAK a RENEWING client. - Fix a place dhcprequest() where static leases could leak. - Include memory.h in omapip_p.h so that we don't get warnings about using memcmp(). Changes since 3.0 Beta 2 Patchlevel 1 - Notice when SIOCFIGCONF returns more data than fit in the buffer - allocate a larger buffer, and retry. Thanks to Greg Fausak for pointing this out. - In the server, if no interfaces were configured, report an error and exit. - Don't ever record a state of 'startup'. - Don't try to evaluate the local failover binding address if none was specified. Thanks to Joseph Breu for finding this. dhcp-4.2.4/server/000777 000765 000024 00000000000 11757514244 013713 5ustar00sarstaff000000 000000 dhcp-4.2.4/tests/000777 000765 000024 00000000000 11757514244 013547 5ustar00sarstaff000000 000000 dhcp-4.2.4/util/000777 000765 000024 00000000000 11757514243 013361 5ustar00sarstaff000000 000000 dhcp-4.2.4/util/bindvar.sh000644 000765 000024 00000002242 11305565627 015337 0ustar00sarstaff000000 000000 #!/bin/sh # # Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") # # Permission to use, copy, modify, and/or distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH # REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY # AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, # INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM # LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR # PERFORMANCE OF THIS SOFTWARE. # $Id: bindvar.sh,v 1.2.2.1 2009-12-02 22:35:03 sar Exp $ # Create a file with the base directory and gmake pat for # use by the bind/Makefile, we do this to minimize portability # concerns. binddir=`pwd` gmake= for x in gmake gnumake make; do if $x --version 2>/dev/null | grep GNU > /dev/null; then gmake=$x break; fi done cat < bind/bindvar.tmp binddir=$binddir/bind GMAKE=$gmake EOF dhcp-4.2.4/tests/DHCPv6/000777 000765 000024 00000000000 11757514244 014541 5ustar00sarstaff000000 000000 dhcp-4.2.4/tests/failover/000777 000765 000024 00000000000 11757514244 015356 5ustar00sarstaff000000 000000 dhcp-4.2.4/tests/HOWTO-unit-test000644 000765 000024 00000006724 10717274454 016332 0ustar00sarstaff000000 000000 Introduction ------------ In DHCP, a unit test exercises a particular piece of code in isolation. There is a separate unit test per module or API. Each unit test lives in a directory beneath the code it is designed to exercise. So, we have: client/tests/ common/tests/ dhcpctl/tests/ And so on. Ideally each function would be invoked with every possible type of input, and each branch of every function would be checked. In practice we try to be a bit more pragmatic, and target the most basic operations, as well tricky code, and areas we have seen bugs in the past. Running Unit Tests ------------------ In order to run the unit tests for DHCP, use: $ make check This will run all of the unit tests. You can run a single test by going to the appropriate test directory and invoking the test directly: $ cd common/tests $ make test_alloc $ ./test_alloc There are also a number of options that you can use when running a test. To see these, use the "-u" flag on the program. Adding a New Unit Test ---------------------- To add an additional test to an existing test program, you must create a function for the new test in the C source file: static void mynewtest(void) { static const char *test_desc = "describe the test"; t_assert("mynewtest", 1, T_REQUIRED, test_desc); /* ... test code ... */ t_result(T_PASS); } Then add this function to the T_testlist[] array in the file: testspec_t T_testlist[] = { ... { mynewtest, "some new test" }, { NULL, NULL } }; Then you should be able to compile and run your new test. Adding a New Unit Test Program ------------------------------ To add a new program, such as when a new module is added, you can copy the "unit_test_sample.c" file (in this directory) to a new name, add the new file as a target in Makefile.am, and begin adding tests. Do not forget to add it to CVS via "cvs add". If there is no "tests" directory for a given subdirectory, then one must be created. This can be done by: 1. Creating the directory: $ mkdir $subdir/tests $ cvs add tests 2. Adding the subdirectory to the build system: Add to $subdir/Makefile.am: SUBDIRS = tests Add to the AC_OUTPUT macro in configure.ac: $subdir/tests/Makefile 3. Create a Makefile.am in the new directory, something like this: AM_CPPFLAGS = -I../.. check_PROGRAMS = test_foo TESTS = test_foo test_foo_SOURCES = test_foo.c test_foo_LDADD = ../../tests/libt_api.a # plus others... See existing Makefile.am for examples, and the Automake documentation: http://www.gnu.org/software/automake/manual/html_node/Tests.html Support Functions ----------------- Here are a few of the most useful functions defined in t_api that you can use in testing: void t_assert(const char *component, int anum, int class, const char *what, ...); The name of this function is slightly misleading. It actually just prints out an error message in the test output. void t_info(const char *format, ...); Prints out a message in the test output. You should include "\n" at the end. void t_result(int result); Prints out the result in the test output. You should use one of the constants for this: T_PASS T_FAIL T_UNRESOLVED T_UNSUPPORTED T_UNTESTED T_THREADONLY Additional Testing ------------------ Other static or runtime testing is always an option. For instance, you can use valgrind to check for memory leaks. $Id: HOWTO-unit-test,v 1.2 2007-11-16 11:04:12 shane Exp $ dhcp-4.2.4/tests/Makefile.am000644 000765 000024 00000002245 10717274454 015603 0ustar00sarstaff000000 000000 EXTRA_DIST = failover/dhcp-1.cf failover/dhcp-2.cf failover/new-failover \ DHCPv6/000-badmsgtype.pl \ DHCPv6/010-solicit-noclientid.pl \ DHCPv6/011-solicit-serverid.pl \ DHCPv6/020-advertise-mcast.pl \ DHCPv6/030-request-noclientid.pl \ DHCPv6/031-request-noserverid.pl \ DHCPv6/032-request-badduid.pl \ DHCPv6/110-information-request-ia_na.pl \ DHCPv6/111-information-request-ia_ta.pl \ DHCPv6/112-badduid.pl \ DHCPv6/210-solicit-nohost.pl \ DHCPv6/211-solicit-opt-in-na.pl \ DHCPv6/212-solicit-opt-in-na-norapidcommit.pl \ DHCPv6/280-release-nohost.pl \ DHCPv6/281-release-bad-address.pl \ DHCPv6/282-release-no-address.pl \ DHCPv6/283-release.pl \ DHCPv6/290-decline-nohost.pl \ DHCPv6/291-decline-bad-address.pl \ DHCPv6/292-decline-no-address.pl \ DHCPv6/293-decline.pl \ DHCPv6/README DHCPv6/dhcp_client.pm \ DHCPv6/stubcli-opt-in-na.pl DHCPv6/stubcli.pl \ DHCPv6/test-a.conf DHCPv6/test-b.conf \ HOWTO-unit-test \ unit_test_sample.c AM_CPPFLAGS = -I.. check_LIBRARIES = libt_api.a libt_api_a_SOURCES = t_api.c t_api_dhcp.c dhcp-4.2.4/tests/Makefile.in000644 000765 000024 00000031441 11757500142 015603 0ustar00sarstaff000000 000000 # Makefile.in generated by automake 1.10.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : subdir = tests DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/includes/config.h CONFIG_CLEAN_FILES = AR = ar ARFLAGS = cru libt_api_a_AR = $(AR) $(ARFLAGS) libt_api_a_LIBADD = am_libt_api_a_OBJECTS = t_api.$(OBJEXT) t_api_dhcp.$(OBJEXT) libt_api_a_OBJECTS = $(am_libt_api_a_OBJECTS) DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/includes depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) CCLD = $(CC) LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ SOURCES = $(libt_api_a_SOURCES) DIST_SOURCES = $(libt_api_a_SOURCES) ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ GREP = @GREP@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDAP_CFLAGS = @LDAP_CFLAGS@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_prefix_program = @ac_prefix_program@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build_alias = @build_alias@ builddir = @builddir@ byte_order = @byte_order@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host_alias = @host_alias@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ EXTRA_DIST = failover/dhcp-1.cf failover/dhcp-2.cf failover/new-failover \ DHCPv6/000-badmsgtype.pl \ DHCPv6/010-solicit-noclientid.pl \ DHCPv6/011-solicit-serverid.pl \ DHCPv6/020-advertise-mcast.pl \ DHCPv6/030-request-noclientid.pl \ DHCPv6/031-request-noserverid.pl \ DHCPv6/032-request-badduid.pl \ DHCPv6/110-information-request-ia_na.pl \ DHCPv6/111-information-request-ia_ta.pl \ DHCPv6/112-badduid.pl \ DHCPv6/210-solicit-nohost.pl \ DHCPv6/211-solicit-opt-in-na.pl \ DHCPv6/212-solicit-opt-in-na-norapidcommit.pl \ DHCPv6/280-release-nohost.pl \ DHCPv6/281-release-bad-address.pl \ DHCPv6/282-release-no-address.pl \ DHCPv6/283-release.pl \ DHCPv6/290-decline-nohost.pl \ DHCPv6/291-decline-bad-address.pl \ DHCPv6/292-decline-no-address.pl \ DHCPv6/293-decline.pl \ DHCPv6/README DHCPv6/dhcp_client.pm \ DHCPv6/stubcli-opt-in-na.pl DHCPv6/stubcli.pl \ DHCPv6/test-a.conf DHCPv6/test-b.conf \ HOWTO-unit-test \ unit_test_sample.c AM_CPPFLAGS = -I.. check_LIBRARIES = libt_api.a libt_api_a_SOURCES = t_api.c t_api_dhcp.c all: all-am .SUFFIXES: .SUFFIXES: .c .o .obj $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ && exit 0; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign tests/Makefile'; \ cd $(top_srcdir) && \ $(AUTOMAKE) --foreign tests/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh clean-checkLIBRARIES: -test -z "$(check_LIBRARIES)" || rm -f $(check_LIBRARIES) libt_api.a: $(libt_api_a_OBJECTS) $(libt_api_a_DEPENDENCIES) -rm -f libt_api.a $(libt_api_a_AR) libt_api.a $(libt_api_a_OBJECTS) $(libt_api_a_LIBADD) $(RANLIB) libt_api.a mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/t_api.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/t_api_dhcp.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) tags=; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$tags $$unique; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) tags=; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$tags$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$tags $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && cd $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) $$here distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ fi; \ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ else \ test -f $(distdir)/$$file \ || cp -p $$d/$$file $(distdir)/$$file \ || exit 1; \ fi; \ done check-am: all-am $(MAKE) $(AM_MAKEFLAGS) $(check_LIBRARIES) check: check-am all-am: Makefile installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-checkLIBRARIES clean-generic mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-exec-am: install-html: install-html-am install-info: install-info-am install-man: install-pdf: install-pdf-am install-ps: install-ps-am installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: install-am install-strip .PHONY: CTAGS GTAGS all all-am check check-am clean \ clean-checkLIBRARIES clean-generic ctags distclean \ distclean-compile distclean-generic distclean-tags distdir dvi \ dvi-am html html-am info info-am install install-am \ install-data install-data-am install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-info install-info-am install-man install-pdf \ install-pdf-am install-ps install-ps-am install-strip \ installcheck installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ uninstall-am # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: dhcp-4.2.4/tests/t_api.c000644 000765 000024 00000037772 11271742256 015020 0ustar00sarstaff000000 000000 /* * Copyright (C) 2004, 2005, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ /* $Id: t_api.c,v 1.4 2009-10-28 04:12:30 sar Exp $ */ /*! \file */ /* * This test API framework is taken from the BIND 9 code. It has been * modified to remove the DNS-specific parts, and the BIND-specific * parts. * * The DNS-specific parts are now wrapped with the DNS_SUPPORT macro, * and the BIND-specific parts are now wrapped with the BIND_SUPPORT * macro. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef DNS_SUPPORT #include #include #endif /* DNS_SUPPORT */ #ifndef BIND_SUPPORT #define isc_commandline_parse getopt #define isc_commandline_argument optarg #define isc_commandline_option optopt #endif /* BIND_SUPPORT */ #include "t_api.h" #include "cdefs.h" static const char *Usage = "\t-a : run all tests\n" "\t-b : chdir to dir before running tests" "\t-c : use specified config file\n" "\t-d : set debug level to debug_level\n" "\t-h : print test info\n" "\t-u : print usage info\n" "\t-n : run specified test name\n" "\t-t : run specified test number\n" "\t-x : don't execute tests in a subproc\n" "\t-q : use 'timeout' as the timeout value\n"; /*!< * -a --> run all tests * -b dir --> chdir to dir before running tests * -c config --> use config file 'config' * -d --> turn on api debugging * -h --> print out available test names * -u --> print usage info * -n name --> run test named name * -tn --> run test n * -x --> don't execute testcases in a subproc * -q timeout --> use 'timeout' as the timeout value */ #define T_MAXTESTS 256 /*% must be 0 mod 8 */ #define T_MAXENV 256 #define T_DEFAULT_CONFIG "t_config" #define T_BUFSIZ 256 #define T_BIGBUF 4096 #define T_TCTOUT 60 int T_debug; int T_timeout; pid_t T_pid; static const char * T_config; static char T_tvec[T_MAXTESTS / 8]; static char * T_env[T_MAXENV + 1]; static char T_buf[T_BIGBUF]; static char * T_dir; static int t_initconf(const char *path); static int t_dumpconf(const char *path); static int t_putinfo(const char *key, const char *info); static char * t_getdate(char *buf, size_t buflen); static void printhelp(void); static void printusage(void); static int T_int; static void t_sighandler(int sig) { T_int = sig; } int main(int argc, char **argv) { int c; int tnum; int subprocs; pid_t deadpid; int status; int len; isc_boolean_t first; testspec_t *pts; struct sigaction sa; #ifdef BIND_SUPPORT isc_mem_debugging = ISC_MEM_DEBUGRECORD; #endif /* BIND_SUPPORT */ first = ISC_TRUE; subprocs = 1; T_timeout = T_TCTOUT; /* * -a option is now default. */ memset(T_tvec, 0xffff, sizeof(T_tvec)); /* * Parse args. */ while ((c = isc_commandline_parse(argc, argv, ":at:c:d:n:huxq:b:")) != -1) { if (c == 'a') { /* * Flag all tests to be run. */ memset(T_tvec, 0xffff, sizeof(T_tvec)); } else if (c == 'b') { T_dir = isc_commandline_argument; } else if (c == 't') { tnum = atoi(isc_commandline_argument); if ((tnum > 0) && (tnum < T_MAXTESTS)) { if (first) { /* * Turn off effect of -a default * and allow multiple -t and -n * options. */ memset(T_tvec, 0, sizeof(T_tvec)); first = ISC_FALSE; } /* * Flag test tnum to be run. */ tnum -= 1; T_tvec[tnum / 8] |= (0x01 << (tnum % 8)); } } else if (c == 'c') { T_config = isc_commandline_argument; } else if (c == 'd') { T_debug = atoi(isc_commandline_argument); } else if (c == 'n') { pts = &T_testlist[0]; tnum = 0; while (pts->pfv != NULL) { if (! strcmp(pts->func_name, isc_commandline_argument)) { if (first) { memset(T_tvec, 0, sizeof(T_tvec)); first = ISC_FALSE; } T_tvec[tnum/8] |= (0x01 << (tnum%8)); break; } ++pts; ++tnum; } if (pts->pfv == NULL) { fprintf(stderr, "no such test %s\n", isc_commandline_argument); exit(1); } } else if (c == 'h') { printhelp(); exit(0); } else if (c == 'u') { printusage(); exit(0); } else if (c == 'x') { subprocs = 0; } else if (c == 'q') { T_timeout = atoi(isc_commandline_argument); } else if (c == ':') { fprintf(stderr, "Option -%c requires an argument\n", isc_commandline_option); exit(1); } else if (c == '?') { fprintf(stderr, "Unrecognized option -%c\n", isc_commandline_option); exit(1); } } /* * Set cwd. */ if (T_dir != NULL) IGNORE_RET (chdir(T_dir)); /* * We don't want buffered output. */ (void)setbuf(stdout, NULL); (void)setbuf(stderr, NULL); /* * Setup signals. */ sa.sa_flags = 0; sigfillset(&sa.sa_mask); #ifdef SIGCHLD /* * This is mostly here for NetBSD's pthread implementation, until * people catch up to the latest unproven-pthread package. */ sa.sa_handler = SIG_DFL; (void)sigaction(SIGCHLD, &sa, NULL); #endif sa.sa_handler = t_sighandler; (void)sigaction(SIGINT, &sa, NULL); (void)sigaction(SIGALRM, &sa, NULL); /* * Output start stanza to journal. */ snprintf(T_buf, sizeof(T_buf), "%s:", argv[0]); len = strlen(T_buf); (void) t_getdate(T_buf + len, T_BIGBUF - len); t_putinfo("S", T_buf); /* * Setup the test environment using the config file. */ if (T_config == NULL) T_config = T_DEFAULT_CONFIG; t_initconf(T_config); if (T_debug) t_dumpconf(T_config); /* * Now invoke all the test cases. */ tnum = 0; pts = &T_testlist[0]; while (*pts->pfv != NULL) { if (T_tvec[tnum / 8] & (0x01 << (tnum % 8))) { if (subprocs) { T_pid = fork(); if (T_pid == 0) { (*pts->pfv)(); exit(0); } else if (T_pid > 0) { T_int = 0; sa.sa_handler = t_sighandler; (void)sigaction(SIGALRM, &sa, NULL); alarm(T_timeout); deadpid = (pid_t) -1; while (deadpid != T_pid) { deadpid = waitpid(T_pid, &status, 0); if (deadpid == T_pid) { if (WIFSIGNALED(status)) { if (WTERMSIG(status) == SIGTERM) t_info( "the test case timed out\n"); else t_info( "the test case caused exception %d\n", WTERMSIG(status)); t_result(T_UNRESOLVED); } } else if ((deadpid == -1) && (errno == EINTR) && T_int) { kill(T_pid, SIGTERM); T_int = 0; } else if ((deadpid == -1) && ((errno == ECHILD) || (errno == ESRCH))) break; } alarm(0); sa.sa_handler = SIG_IGN; (void)sigaction(SIGALRM, &sa, NULL); } else { t_info("fork failed, errno == %d\n", errno); t_result(T_UNRESOLVED); } } else { (*pts->pfv)(); } } ++pts; ++tnum; } snprintf(T_buf, sizeof(T_buf), "%s:", argv[0]); len = strlen(T_buf); (void) t_getdate(T_buf + len, T_BIGBUF - len); t_putinfo("E", T_buf); return(0); } void t_assert(const char *component, int anum, int class, const char *what, ...) { va_list args; (void)printf("T:%s:%d:%s\n", component, anum, class == T_REQUIRED ? "A" : "C"); /* * Format text to a buffer. */ va_start(args, what); (void)vsnprintf(T_buf, sizeof(T_buf), what, args); va_end(args); (void)t_putinfo("A", T_buf); (void)printf("\n"); } void t_info(const char *format, ...) { va_list args; va_start(args, format); (void) vsnprintf(T_buf, sizeof(T_buf), format, args); va_end(args); (void) t_putinfo("I", T_buf); } void t_result(int result) { const char *p; switch (result) { case T_PASS: p = "PASS"; break; case T_FAIL: p = "FAIL"; break; case T_UNRESOLVED: p = "UNRESOLVED"; break; case T_UNSUPPORTED: p = "UNSUPPORTED"; break; case T_UNTESTED: p = "UNTESTED"; break; case T_THREADONLY: p = "THREADONLY"; break; default: p = "UNKNOWN"; break; } printf("R:%s\n", p); } char * t_getenv(const char *name) { char *n; char **p; size_t len; n = NULL; if (name && *name) { p = &T_env[0]; len = strlen(name); while (*p != NULL) { if (strncmp(*p, name, len) == 0) { if ( *(*p + len) == '=') { n = *p + len + 1; break; } } ++p; } } return(n); } /* * * Read in the config file at path, initializing T_env. * * note: no format checking for now ... * */ static int t_initconf(const char *path) { int n; int rval; char **p; FILE *fp; rval = -1; fp = fopen(path, "r"); if (fp != NULL) { n = 0; p = &T_env[0]; while (n < T_MAXENV) { *p = t_fgetbs(fp); if (*p == NULL) break; if ((**p == '#') || (strchr(*p, '=') == NULL)) { /* * Skip comments and other junk. */ (void)free(*p); continue; } ++p; ++n; } (void)fclose(fp); rval = 0; } return (rval); } /* * * Dump T_env to stdout. * */ static int t_dumpconf(const char *path) { int rval; char **p; FILE *fp; rval = -1; fp = fopen(path, "r"); if (fp != NULL) { p = &T_env[0]; while (*p != NULL) { printf("C:%s\n", *p); ++p; } (void) fclose(fp); rval = 0; } return(rval); } /* * * Read a newline or EOF terminated string from fp. * On success: * return a malloc'd buf containing the string with * the newline converted to a '\0'. * On error: * return NULL. * * Caller is responsible for freeing buf. * */ char * t_fgetbs(FILE *fp) { int c; size_t n; size_t size; char *buf; char *p; n = 0; size = T_BUFSIZ; buf = (char *) malloc(T_BUFSIZ * sizeof(char)); if (buf != NULL) { p = buf; while ((c = fgetc(fp)) != EOF) { if (c == '\n') break; *p++ = c; ++n; if ( n >= size ) { size += T_BUFSIZ; buf = (char *)realloc(buf, size * sizeof(char)); if (buf == NULL) break; p = buf + n; } } *p = '\0'; if (c == EOF && n == 0U) { free(buf); return (NULL); } return (buf); } else { fprintf(stderr, "malloc failed %d", errno); return(NULL); } } /* * * Put info to log, using key. * For now, just dump it out. * Later format into pretty lines. * */ static int t_putinfo(const char *key, const char *info) { int rval; /* * For now. */ rval = printf("%s:%s", key, info); return(rval); } static char * t_getdate(char *buf, size_t buflen) { size_t n; time_t t; struct tm *p; t = time(NULL); p = localtime(&t); n = strftime(buf, buflen - 1, "%A %d %B %H:%M:%S %Y\n", p); return(n != 0U ? buf : NULL); } /* * Some generally used utilities. */ #ifdef DNS_SUPPORT struct dns_errormap { isc_result_t result; const char *text; } dns_errormap[] = { { ISC_R_SUCCESS, "ISC_R_SUCCESS" }, { ISC_R_EXISTS, "ISC_R_EXISTS" }, { ISC_R_NOTFOUND, "ISC_R_NOTFOUND" }, { ISC_R_NOSPACE, "ISC_R_NOSPACE" }, { ISC_R_UNEXPECTED, "ISC_R_UNEXPECTED" }, { ISC_R_UNEXPECTEDEND, "ISC_R_UNEXPECTEDEND" }, { ISC_R_RANGE, "ISC_R_RANGE" }, { DNS_R_LABELTOOLONG, "DNS_R_LABELTOOLONG" }, { DNS_R_BADESCAPE, "DNS_R_BADESCAPE" }, /* { DNS_R_BADBITSTRING, "DNS_R_BADBITSTRING" }, */ /* { DNS_R_BITSTRINGTOOLONG, "DNS_R_BITSTRINGTOOLONG"}, */ { DNS_R_EMPTYLABEL, "DNS_R_EMPTYLABEL" }, { DNS_R_BADDOTTEDQUAD, "DNS_R_BADDOTTEDQUAD" }, { DNS_R_UNKNOWN, "DNS_R_UNKNOWN" }, { DNS_R_BADLABELTYPE, "DNS_R_BADLABELTYPE" }, { DNS_R_BADPOINTER, "DNS_R_BADPOINTER" }, { DNS_R_TOOMANYHOPS, "DNS_R_TOOMANYHOPS" }, { DNS_R_DISALLOWED, "DNS_R_DISALLOWED" }, { DNS_R_EXTRATOKEN, "DNS_R_EXTRATOKEN" }, { DNS_R_EXTRADATA, "DNS_R_EXTRADATA" }, { DNS_R_TEXTTOOLONG, "DNS_R_TEXTTOOLONG" }, { DNS_R_SYNTAX, "DNS_R_SYNTAX" }, { DNS_R_BADCKSUM, "DNS_R_BADCKSUM" }, { DNS_R_BADAAAA, "DNS_R_BADAAAA" }, { DNS_R_NOOWNER, "DNS_R_NOOWNER" }, { DNS_R_NOTTL, "DNS_R_NOTTL" }, { DNS_R_BADCLASS, "DNS_R_BADCLASS" }, { DNS_R_PARTIALMATCH, "DNS_R_PARTIALMATCH" }, { DNS_R_NEWORIGIN, "DNS_R_NEWORIGIN" }, { DNS_R_UNCHANGED, "DNS_R_UNCHANGED" }, { DNS_R_BADTTL, "DNS_R_BADTTL" }, { DNS_R_NOREDATA, "DNS_R_NOREDATA" }, { DNS_R_CONTINUE, "DNS_R_CONTINUE" }, { DNS_R_DELEGATION, "DNS_R_DELEGATION" }, { DNS_R_GLUE, "DNS_R_GLUE" }, { DNS_R_DNAME, "DNS_R_DNAME" }, { DNS_R_CNAME, "DNS_R_CNAME" }, { DNS_R_NXDOMAIN, "DNS_R_NXDOMAIN" }, { DNS_R_NXRRSET, "DNS_R_NXRRSET" }, { DNS_R_BADDB, "DNS_R_BADDB" }, { DNS_R_ZONECUT, "DNS_R_ZONECUT" }, { DNS_R_NOTZONETOP, "DNS_R_NOTZONETOP" }, { DNS_R_SEENINCLUDE, "DNS_R_SEENINCLUDE" }, { DNS_R_SINGLETON, "DNS_R_SINGLETON" }, { (isc_result_t)0, NULL } }; isc_result_t t_dns_result_fromtext(char *name) { isc_result_t result; struct dns_errormap *pmap; result = ISC_R_UNEXPECTED; pmap = dns_errormap; while (pmap->text != NULL) { if (strcmp(name, pmap->text) == 0) break; ++pmap; } if (pmap->text != NULL) result = pmap->result; return (result); } struct dc_method_map { unsigned int dc_method; const char *text; } dc_method_map[] = { { DNS_COMPRESS_NONE, "DNS_COMPRESS_NONE" }, { DNS_COMPRESS_GLOBAL14, "DNS_COMPRESS_GLOBAL14" }, { DNS_COMPRESS_ALL, "DNS_COMPRESS_ALL" }, { 0, NULL } }; unsigned int t_dc_method_fromtext(char *name) { unsigned int dc_method; struct dc_method_map *pmap; dc_method = DNS_COMPRESS_NONE; pmap = dc_method_map; while (pmap->text != NULL) { if (strcmp(name, pmap->text) == 0) break; ++pmap; } if (pmap->text != NULL) dc_method = pmap->dc_method; return(dc_method); } #endif /* DNS_SUPPORT */ int t_bustline(char *line, char **toks) { int cnt; char *p; cnt = 0; if (line && *line) { while ((p = strtok(line, "\t")) && (cnt < T_MAXTOKS)) { *toks++ = p; line = NULL; ++cnt; } } return(cnt); } static void printhelp(void) { int cnt; testspec_t *pts; cnt = 1; pts = &T_testlist[0]; printf("Available tests:\n"); while (pts->func_name) { printf("\t%d\t%s\n", cnt, pts->func_name); ++pts; ++cnt; } } static void printusage(void) { printf("Usage:\n%s\n", Usage); } int t_eval(const char *filename, int (*func)(char **), int nargs) { FILE *fp; char *p; int line; int cnt; int result; int nfails; int nprobs; int npass; char *tokens[T_MAXTOKS + 1]; npass = 0; nfails = 0; nprobs = 0; fp = fopen(filename, "r"); if (fp != NULL) { line = 0; while ((p = t_fgetbs(fp)) != NULL) { ++line; /* * Skip comment lines. */ if ((isspace((unsigned char)*p)) || (*p == '#')) { (void)free(p); continue; } cnt = t_bustline(p, tokens); if (cnt == nargs) { result = func(tokens); switch (result) { case T_PASS: ++npass; break; case T_FAIL: ++nfails; break; case T_UNTESTED: break; default: ++nprobs; break; } } else { t_info("bad format in %s at line %d\n", filename, line); ++nprobs; } (void)free(p); } (void)fclose(fp); } else { t_info("Missing datafile %s\n", filename); ++nprobs; } result = T_UNRESOLVED; if (nfails == 0 && nprobs == 0 && npass > 0) result = T_PASS; else if (nfails > 0) result = T_FAIL; else if (npass == 0) result = T_UNTESTED; return (result); } dhcp-4.2.4/tests/t_api_dhcp.c000644 000765 000024 00000001345 10717274454 016005 0ustar00sarstaff000000 000000 /* * We have to have a number of symbols defined in order to build a * DHCP program. */ #include #include "dhcpd.h" void bootp(struct packet *packet) { } void dhcp(struct packet *packet) { } void dhcpv6(struct packet *packet) { } isc_result_t dhcp_set_control_state(control_object_state_t old, control_object_state_t new) { return ISC_R_NOTIMPLEMENTED; } int check_collection(struct packet *p, struct lease *l, struct collection *c) { return 0; } void classify (struct packet *p, struct class *c) { } isc_result_t find_class(struct class **class, const char *c1, const char *c2, int i) { return ISC_R_NOTFOUND; } int parse_allow_deny(struct option_cache **oc, struct parse *p, int i) { return 0; } dhcp-4.2.4/tests/unit_test_sample.c000644 000765 000024 00000000646 10717274454 017275 0ustar00sarstaff000000 000000 #include "config.h" #include "t_api.h" static void foo(void); /* * T_testlist is a list of tests that are invoked. */ testspec_t T_testlist[] = { { foo, "sample test" }, { NULL, NULL } }; static void foo(void) { static const char *test_desc = "this is an example test, for no actual module"; t_assert("sample", 1, T_REQUIRED, test_desc); /* ... */ /* Test code would go here. */ t_result(T_PASS); } dhcp-4.2.4/tests/failover/dhcp-1.cf000644 000765 000024 00000007306 10216362541 016734 0ustar00sarstaff000000 000000 authoritative; class "even" { match if ((extract-int (suffix (pick-first-value (option dhcp-client-identifier, hardware), 1), 8) % 2) = 0); } class "odd" { match if ((extract-int (suffix (pick-first-value (option dhcp-client-identifier, hardware), 1), 8) % 2) = 1); } lease-file-name "dhcp-1.leases"; pid-file-name "dhcp-1.pid"; ddns-update-style none; local-port 50002; remote-port 50003; omapi-port 50004; omapi-key FOO; default-lease-time 600; max-lease-time 600; failover peer "foo" { primary; address 10.0.0.1; port 51000; peer address 10.0.0.1; peer port 51001; max-response-delay 60; max-unacked-updates 10; mclt 100; hba ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff: 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00; load balance max seconds 2; } option space SUNW; option SUNW.root-mount-options code 1 = text; option SUNW.root-server-ip-address code 2 = ip-address; option SUNW.root-server-hostname code 3 = text; option SUNW.root-path-name code 4 = text; option SUNW.swap-server-ip-address code 5 = ip-address; option SUNW.swap-file-path code 6 = text; option SUNW.boot-file-path code 7 = text; option SUNW.posix-timezone-string code 8 = text; option SUNW.boot-read-size code 9 = unsigned integer 16; option SUNW.install-server-ip-address code 10 = ip-address; option SUNW.install-server-hostname code 11 = text; option SUNW.install-path code 12 = text; option SUNW.sysid-config-file-server code 13 = text; option SUNW.JumpStart-server code 14 = text; option SUNW.terminal-name code 15 = text; class "solaris-i86pc" { match if option vendor-class-identifier = "SUNW.i86pc"; vendor-option-space SUNW; option SUNW.boot-file-path "/platform/i86pc/kernel/unix"; option SUNW.root-path-name "/export/root/i86pc"; } class "solaris-sun4u" { match if option vendor-class-identifier = "SUNW.Ultra-5_10"; vendor-option-space SUNW; option SUNW.install-path "/export/2/s581_sparc"; option SUNW.root-path-name "/export/2/s581_sparc/Solaris_8/Tools/Boot"; } option domain-name "connectathon.org."; option SUNW.root-server-ip-address 172.16.113.1; option SUNW.root-server-hostname "sundhcp-server17-1"; class "sniffer" { match if option host-name = "sniffer"; } key FOO { algorithm HMAC-MD5.SIG-ALG.REG.INT; secret ABCD; } zone BISBEE.FUGUE.COM. { primary 127.0.0.1; key FOO; } zone 17.127.10.in-addr.arpa. { primary 127.0.0.1; key FOO; } zone 0.0.10.in-addr.arpa. { primary 127.0.0.1; key FOO; } subnet 204.152.186.128 netmask 255.255.255.192 { not authoritative; } shared-network LOCAL { subnet 127.0.0.0 netmask 255.255.255.0 { } subnet 10.0.2.0 netmask 255.255.255.0 { pool { deny dynamic bootp clients; failover peer "foo"; range 10.0.2.100 10.0.2.200; } } } shared-network NET-187 { subnet 204.152.187.0 netmask 255.255.255.0 { } subnet 205.140.116.224 netmask 255.255.255.248 { } subnet 10.0.1.0 netmask 255.255.255.0 { pool { deny dynamic bootp clients; failover peer "foo"; range 10.0.1.10 10.0.1.200; } } } subnet 10.0.0.0 netmask 255.255.255.0 { pool { deny dynamic bootp clients; allow members of "even"; option impress-servers 10.0.0.0; failover peer "foo"; range 10.0.0.10 10.0.0.54; range 10.0.0.100 10.0.0.149; } pool { deny dynamic bootp clients; allow members of "odd"; failover peer "foo"; option impress-servers 10.0.0.1; range 10.0.0.55 10.0.0.99; range 10.0.0.150 10.0.0.200; } pool { deny dynamic bootp clients; allow members of "sniffer"; failover peer "foo"; range 10.0.0.9 10.0.0.9; } option routers 10.0.0.1; option domain-name "bisbee.fugue.com"; option domain-name-servers 10.0.0.1; } dhcp-4.2.4/tests/failover/dhcp-2.cf000644 000765 000024 00000007110 10216362541 016726 0ustar00sarstaff000000 000000 authoritative; class "even" { match if ((extract-int (suffix (pick-first-value (option dhcp-client-identifier, hardware), 1), 8) % 2) = 0); } class "odd" { match if ((extract-int (suffix (pick-first-value (option dhcp-client-identifier, hardware), 1), 8) % 2) = 1); } lease-file-name "dhcp-2.leases"; pid-file-name "dhcp-2.pid"; local-port 50000; remote-port 50001; omapi-port 50005; ddns-update-style none; default-lease-time 600; max-lease-time 600; failover peer "foo" { secondary; address 10.0.0.1; port 51001; peer address 10.0.0.1; peer port 51000; max-response-delay 60; max-unacked-updates 10; mclt 100; load balance max seconds 2; } option space SUNW; option SUNW.root-mount-options code 1 = text; option SUNW.root-server-ip-address code 2 = ip-address; option SUNW.root-server-hostname code 3 = text; option SUNW.root-path-name code 4 = text; option SUNW.swap-server-ip-address code 5 = ip-address; option SUNW.swap-file-path code 6 = text; option SUNW.boot-file-path code 7 = text; option SUNW.posix-timezone-string code 8 = text; option SUNW.boot-read-size code 9 = unsigned integer 16; option SUNW.install-server-ip-address code 10 = ip-address; option SUNW.install-server-hostname code 11 = text; option SUNW.install-path code 12 = text; option SUNW.sysid-config-file-server code 13 = text; option SUNW.JumpStart-server code 14 = text; option SUNW.terminal-name code 15 = text; class "solaris-i86pc" { match if option vendor-class-identifier = "SUNW.i86pc"; vendor-option-space SUNW; option SUNW.boot-file-path "/platform/i86pc/kernel/unix"; option SUNW.root-path-name "/export/root/i86pc"; } class "solaris-sun4u" { match if option vendor-class-identifier = "SUNW.Ultra-5_10"; vendor-option-space SUNW; option SUNW.install-path "/export/2/s581_sparc"; option SUNW.root-path-name "/export/2/s581_sparc/Solaris_8/Tools/Boot"; } option domain-name "connectathon.org."; option SUNW.root-server-ip-address 172.16.113.1; option SUNW.root-server-hostname "sundhcp-server17-1"; class "sniffer" { match if option host-name = "sniffer"; } key FOO { algorithm HMAC-MD5.SIG-ALG.REG.INT; secret ABCD; } zone BISBEE.FUGUE.COM. { primary 127.0.0.1; key FOO; } zone 17.127.10.in-addr.arpa. { primary 127.0.0.1; key FOO; } zone 0.0.10.in-addr.arpa. { primary 127.0.0.1; key FOO; } subnet 204.152.186.128 netmask 255.255.255.192 { not authoritative; } shared-network LOCAL { subnet 127.0.0.0 netmask 255.255.255.0 { } subnet 10.0.2.0 netmask 255.255.255.0 { pool { deny dynamic bootp clients; failover peer "foo"; range 10.0.2.100 10.0.2.200; } } } shared-network 187-NET { subnet 204.152.187.0 netmask 255.255.255.0 { } subnet 205.140.116.224 netmask 255.255.255.248 { } subnet 10.0.1.0 netmask 255.255.255.0 { pool { deny dynamic bootp clients; failover peer "foo"; range 10.0.1.10 10.0.1.200; } } } subnet 10.0.0.0 netmask 255.255.255.0 { pool { deny dynamic bootp clients; allow members of "even"; option impress-servers 10.0.0.0; failover peer "foo"; range 10.0.0.10 10.0.0.54; range 10.0.0.100 10.0.0.149; } pool { deny dynamic bootp clients; allow members of "odd"; failover peer "foo"; option impress-servers 10.0.0.1; range 10.0.0.55 10.0.0.99; range 10.0.0.150 10.0.0.200; } pool { deny dynamic bootp clients; allow members of "sniffer"; failover peer "foo"; range 10.0.0.9 10.0.0.9; } option routers 10.0.0.1; option domain-name "bisbee.fugue.com"; option domain-name-servers 10.0.0.1; } dhcp-4.2.4/tests/failover/new-failover000755 000765 000024 00000001031 07316224530 017661 0ustar00sarstaff000000 000000 #!/bin/sh foo=10 while [ $foo -lt 100 ]; do cat >>dhcp-1.leases <<~ lease 10.0.0.$foo { starts 4 2001/05/01 02:19:16; ends 5 2021/05/03 02:29:16; binding state active; next binding state free; hardware ethernet 08:00:46:06:6c:23; uid "test-$foo"; } ~ foo=`expr $foo + 1` cat >>dhcp-2.leases <<~ lease 10.0.0.$foo { starts 4 2001/04/19 02:19:16; ends 5 2021/04/21 02:29:16; binding state active; next binding state free; hardware ethernet 08:00:46:06:6c:23; uid "test-$foo"; } ~ foo=`expr $foo + 1` done dhcp-4.2.4/tests/DHCPv6/000-badmsgtype.pl000644 000765 000024 00000010361 11301372617 017516 0ustar00sarstaff000000 000000 #! /usr/bin/perl -w # Copyright (c) 2007,2009 by Internet Systems Consortium, Inc. ("ISC") # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # # Internet Systems Consortium, Inc. # 950 Charter Street # Redwood City, CA 94063 # # https://www.isc.org/ use strict; use English; use Time::HiRes qw( sleep ); use Socket; use Socket6; use IO::Select; use dhcp_client; # well-known addresses my $All_DHCP_Relay_Agents_and_Servers = "ff02::1:2"; my $All_DHCP_Servers = "ff05::1:3"; # ports my $client_port = 546; my $server_port = 547; # create a new Solicit message my $msg = dhcp_client::msg->new(255); # add the Client Identifier (required by DOCSIS and RFC 3315) $msg->add_option($OPT_CLIENTID, dhcp_client::duid()); # add Elapsed Time, set to 0 on first packet (required by RFC 3315) $msg->add_option($OPT_ELAPSED_TIME, "\x00\x00"); # add IA_NA for each interface (required by DOCSIS and RFC 3315) # XXX: should this be a single interface only? my $iaid = 0; foreach my $iface (dhcp_client::iface()) { my $option_data = pack("NNN", ++$iaid, 0, 0); $msg->add_option($OPT_IA_NA, $option_data); } # add Options Request (required by DOCSIS, recommended by RFC 3315) my @oro = ( ); $msg->add_option($OPT_ORO, pack("n*", @oro)); # timeout parameters my $IRT = $SOL_TIMEOUT; my $MRT = $SOL_MAX_RT; my $MRC = 1; # DOCSIS says 4, RFC 3315 says it SHOULD be 0 my $MRD = 0; # sleep a random amount of time between 0 and 1 second, required by RFC 3315 # XXX: this seems pretty stupid sleep(rand($SOL_MAX_DELAY)); my $RT; my $count = 0; my $mrd_end_time; if ($MRD != 0) { $mrd_end_time = time() + $MRD; } my $reply_msg; do { # create our socket, and send our bogus packet socket(SOCK, PF_INET6, SOCK_DGRAM, getprotobyname('udp')) || die; my $addr = inet_pton(AF_INET6, $All_DHCP_Servers); my $packet = $msg->packet(); my $send_ret = send(SOCK, $packet, 0, pack_sockaddr_in6($server_port, $addr)); if (not defined($send_ret)) { printf STDERR "Error \%d sending DHCPv6 message;\n\%s\n", 0+$ERRNO, $ERRNO; exit(1); } elsif ($send_ret != length($packet)) { print STDERR "Unable to send entire DHCPv6 message.\n"; exit(1); } $count++; my $RAND = rand(0.2) - 0.1; if (defined $RT) { $RT = 2*$RT + $RAND*$RT; if (($RT > $MRT) && ($MRT != 0)) { $RT = $MRT + $RAND*$RT; } } else { $RT = $IRT + $RAND*$IRT; } my $rt_end_time = time() + $RT; if (defined($mrd_end_time) && ($mrd_end_time > $rt_end_time)) { $rt_end_time = $mrd_end_time; } for (;;) { my $timeout = $rt_end_time - time(); if ($timeout < 0) { last; } my @ready = IO::Select->new(\*SOCK)->can_read($timeout); if (@ready) { my $reply; my $recv_ret; $recv_ret = recv(SOCK, $reply, 1500, 0); if (not defined $recv_ret) { printf STDERR "Error \%d receiving DHCPv6 " . "message;\n\%s\n", 0+$ERRNO, $ERRNO; exit(1); } $reply_msg = dhcp_client::msg::decode($reply); if (($reply_msg->{msg_type} == $MSG_ADVERTISE) || ($reply_msg->{msg_type} == $MSG_REPLY)) { last; } } } } until ($reply_msg || (($MRC != 0) && ($count > $MRC)) || (defined($mrd_end_time) && ($mrd_end_time > time()))); unless ($reply_msg) { if (($MRC != 0) && ($count >= $MRC)) { print STDERR "No reply after maximum retransmission count.\n"; } else { print STDERR "No reply after maximum retransmission duration.\n"; } } if ($reply_msg && ($reply_msg->{msg_type} == $MSG_REPLY)) { print "Got DHCPv6 Reply message.\n"; exit(0); } #$Data::Dumper::Useqq = 1; #print Dumper($msg), "\n"; #print Dumper($msg->packet()), "\n"; # #print "packet length: ", length($msg->packet()), "\n"; dhcp-4.2.4/tests/DHCPv6/010-solicit-noclientid.pl000644 000765 000024 00000013335 11301372617 021160 0ustar00sarstaff000000 000000 #! /usr/bin/perl -w # Copyright (c) 2007,2009 by Internet Systems Consortium, Inc. ("ISC") # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # # Internet Systems Consortium, Inc. # 950 Charter Street # Redwood City, CA 94063 # # https://www.isc.org/ use strict; use English; use Time::HiRes qw( sleep ); use Socket; use Socket6; use IO::Select; use dhcp_client; # XXX: for debugging use Data::Dumper; # not-yet-standard options my $OPT_TIME_SERVERS = 40; my $OPT_TIME_OFFSET = 41; # DOCSIS sub-options my $DOCSIS_OPT_ORO = 1; # 2 to 31 are reserved my $DOCSIS_OPT_TFTP_SERVERS = 32; my $DOCSIS_OPT_CONFIG_FILE_NAME = 33; my $DOCSIS_OPT_SYSLOG_SERVERS = 34; my $DOCSIS_OPT_TLV5 = 35; my $DOCSIS_OPT_DEVICE_ID = 36; my $DOCSIS_OPT_CCC = 37; my $DOCSIS_OPT_VERS = 38; # well-known addresses my $All_DHCP_Relay_Agents_and_Servers = "ff02::1:2"; my $All_DHCP_Servers = "ff05::1:3"; # ports my $client_port = 546; my $server_port = 547; # create a new Solicit message my $msg = dhcp_client::msg->new($MSG_SOLICIT); # do NOT add the Client Identifier (required by DOCSIS and RFC 3315) #$msg->add_option($OPT_CLIENTID, dhcp_client::duid()); # add Elapsed Time, set to 0 on first packet (required by RFC 3315) $msg->add_option($OPT_ELAPSED_TIME, "\x00\x00"); # add IA_NA for each interface (required by DOCSIS and RFC 3315) # XXX: should this be a single interface only? my $iaid = 0; foreach my $iface (dhcp_client::iface()) { my $option_data = pack("NNN", ++$iaid, 0, 0); $msg->add_option($OPT_IA_NA, $option_data); } # add Reconfigure Accept (required by DOCSIS) $msg->add_option($OPT_RECONF_ACCEPT, ""); # add Options Request (required by DOCSIS, recommended by RFC 3315) my @oro = ( $OPT_TIME_SERVERS, $OPT_TIME_OFFSET ); $msg->add_option($OPT_ORO, pack("n*", @oro)); # add Vendor Class option (required by DOCSIS) $msg->add_option($OPT_VENDOR_CLASS, pack("N", 4491) . "docsis3.0"); # add Vendor-specific Information Option option (required by DOCSIS) my $vsio = pack("N", 4491); # ORO (required by DOCSIS) my @docsis_oro = ( $DOCSIS_OPT_TFTP_SERVERS ); $vsio .= pack("nnC*", $DOCSIS_OPT_ORO, 0+@docsis_oro, @docsis_oro); # TLV5 data: CMTS DOCSIS version number 3.0 (required by DOCSIS) my $tlv5_data = "\x01\x02\x03\x0"; $vsio .= pack("nn", $DOCSIS_OPT_TLV5, length($tlv5_data)) . $tlv5_data; # DOCSIS Device (required by DOCSIS) my $docsis_device_id = dhcp_client::mac_addr_binary(); $vsio .= pack("nn", $DOCSIS_OPT_DEVICE_ID, length($docsis_device_id)); $vsio .= $docsis_device_id; $msg->add_option($OPT_VENDOR_OPTS, $vsio); # add Rapid Commit option (required by DOCSIS) $msg->add_option($OPT_RAPID_COMMIT, ""); # timeout parameters, from DOCSIS my $IRT = $SOL_TIMEOUT; my $MRT = $SOL_MAX_RT; my $MRC = 1; # DOCSIS says 4, RFC 3315 says it SHOULD be 0 my $MRD = 0; # sleep a random amount of time between 0 and 1 second, required by RFC 3315 # XXX: this seems pretty stupid sleep(rand($SOL_MAX_DELAY)); my $RT; my $count = 0; my $mrd_end_time; if ($MRD != 0) { $mrd_end_time = time() + $MRD; } my $reply_msg; do { # create our socket, and send our Solicit socket(SOCK, PF_INET6, SOCK_DGRAM, getprotobyname('udp')) || die; my $addr = inet_pton(AF_INET6, $All_DHCP_Servers); my $packet = $msg->packet(); my $send_ret = send(SOCK, $packet, 0, pack_sockaddr_in6($server_port, $addr)); if (not defined($send_ret)) { printf STDERR "Error \%d sending DHCPv6 Solicit message;\n\%s\n", 0+$ERRNO, $ERRNO; exit(1); } elsif ($send_ret != length($packet)) { print STDERR "Unable to send entire DHCPv6 Solicit message.\n"; exit(1); } $count++; my $RAND = rand(0.2) - 0.1; if (defined $RT) { $RT = 2*$RT + $RAND*$RT; if (($RT > $MRT) && ($MRT != 0)) { $RT = $MRT + $RAND*$RT; } } else { $RT = $IRT + $RAND*$IRT; } my $rt_end_time = time() + $RT; if (defined($mrd_end_time) && ($mrd_end_time > $rt_end_time)) { $rt_end_time = $mrd_end_time; } for (;;) { my $timeout = $rt_end_time - time(); if ($timeout < 0) { # print STDERR "Timeout waiting for DHCPv6 Advertise ", # "or Reply message.\n"; last; } my @ready = IO::Select->new(\*SOCK)->can_read($timeout); if (@ready) { my $reply; my $recv_ret; $recv_ret = recv(SOCK, $reply, 1500, 0); if (not defined $recv_ret) { printf STDERR "Error \%d receiving DHCPv6 " . "message;\n\%s\n", 0+$ERRNO, $ERRNO; exit(1); } $reply_msg = dhcp_client::msg::decode($reply); if (($reply_msg->{msg_type} == $MSG_ADVERTISE) || ($reply_msg->{msg_type} == $MSG_REPLY)) { last; } } } } until ($reply_msg || (($MRC != 0) && ($count > $MRC)) || (defined($mrd_end_time) && ($mrd_end_time > time()))); unless ($reply_msg) { if (($MRC != 0) && ($count >= $MRC)) { print STDERR "No reply after maximum retransmission count.\n"; } else { print STDERR "No reply after maximum retransmission duration.\n"; } } if ($reply_msg && ($reply_msg->{msg_type} == $MSG_REPLY)) { print "Got DHCPv6 Reply message.\n"; exit(0); } #$Data::Dumper::Useqq = 1; #print Dumper($msg), "\n"; #print Dumper($msg->packet()), "\n"; # #print "packet length: ", length($msg->packet()), "\n"; dhcp-4.2.4/tests/DHCPv6/011-solicit-serverid.pl000644 000765 000024 00000013515 11301372617 020654 0ustar00sarstaff000000 000000 #! /usr/bin/perl -w # Copyright (c) 2007,2009 by Internet Systems Consortium, Inc. ("ISC") # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # # Internet Systems Consortium, Inc. # 950 Charter Street # Redwood City, CA 94063 # # https://www.isc.org/ use strict; use English; use Time::HiRes qw( sleep ); use Socket; use Socket6; use IO::Select; use dhcp_client; # XXX: for debugging use Data::Dumper; # not-yet-standard options my $OPT_TIME_SERVERS = 40; my $OPT_TIME_OFFSET = 41; # DOCSIS sub-options my $DOCSIS_OPT_ORO = 1; # 2 to 31 are reserved my $DOCSIS_OPT_TFTP_SERVERS = 32; my $DOCSIS_OPT_CONFIG_FILE_NAME = 33; my $DOCSIS_OPT_SYSLOG_SERVERS = 34; my $DOCSIS_OPT_TLV5 = 35; my $DOCSIS_OPT_DEVICE_ID = 36; my $DOCSIS_OPT_CCC = 37; my $DOCSIS_OPT_VERS = 38; # well-known addresses my $All_DHCP_Relay_Agents_and_Servers = "ff02::1:2"; my $All_DHCP_Servers = "ff05::1:3"; # ports my $client_port = 546; my $server_port = 547; # create a new Solicit message my $msg = dhcp_client::msg->new($MSG_SOLICIT); # add the Client Identifier (required by DOCSIS and RFC 3315) $msg->add_option($OPT_CLIENTID, dhcp_client::duid()); # add the Server Identifier (NOT ALLOWED by DOCSIS and RFC 3315) $msg->add_option($OPT_SERVERID, dhcp_client::duid()); # add Elapsed Time, set to 0 on first packet (required by RFC 3315) $msg->add_option($OPT_ELAPSED_TIME, "\x00\x00"); # add IA_NA for each interface (required by DOCSIS and RFC 3315) # XXX: should this be a single interface only? my $iaid = 0; foreach my $iface (dhcp_client::iface()) { my $option_data = pack("NNN", ++$iaid, 0, 0); $msg->add_option($OPT_IA_NA, $option_data); } # add Reconfigure Accept (required by DOCSIS) $msg->add_option($OPT_RECONF_ACCEPT, ""); # add Options Request (required by DOCSIS, recommended by RFC 3315) my @oro = ( $OPT_TIME_SERVERS, $OPT_TIME_OFFSET ); $msg->add_option($OPT_ORO, pack("n*", @oro)); # add Vendor Class option (required by DOCSIS) $msg->add_option($OPT_VENDOR_CLASS, pack("N", 4491) . "docsis3.0"); # add Vendor-specific Information Option option (required by DOCSIS) my $vsio = pack("N", 4491); # ORO (required by DOCSIS) my @docsis_oro = ( $DOCSIS_OPT_TFTP_SERVERS ); $vsio .= pack("nnC*", $DOCSIS_OPT_ORO, 0+@docsis_oro, @docsis_oro); # TLV5 data: CMTS DOCSIS version number 3.0 (required by DOCSIS) my $tlv5_data = "\x01\x02\x03\x0"; $vsio .= pack("nn", $DOCSIS_OPT_TLV5, length($tlv5_data)) . $tlv5_data; # DOCSIS Device (required by DOCSIS) my $docsis_device_id = dhcp_client::mac_addr_binary(); $vsio .= pack("nn", $DOCSIS_OPT_DEVICE_ID, length($docsis_device_id)); $vsio .= $docsis_device_id; $msg->add_option($OPT_VENDOR_OPTS, $vsio); # add Rapid Commit option (required by DOCSIS) $msg->add_option($OPT_RAPID_COMMIT, ""); # timeout parameters, from DOCSIS my $IRT = $SOL_TIMEOUT; my $MRT = $SOL_MAX_RT; my $MRC = 1; # DOCSIS says 4, RFC 3315 says it SHOULD be 0 my $MRD = 0; # sleep a random amount of time between 0 and 1 second, required by RFC 3315 # XXX: this seems pretty stupid sleep(rand($SOL_MAX_DELAY)); my $RT; my $count = 0; my $mrd_end_time; if ($MRD != 0) { $mrd_end_time = time() + $MRD; } my $reply_msg; do { # create our socket, and send our Solicit socket(SOCK, PF_INET6, SOCK_DGRAM, getprotobyname('udp')) || die; my $addr = inet_pton(AF_INET6, $All_DHCP_Servers); my $packet = $msg->packet(); my $send_ret = send(SOCK, $packet, 0, pack_sockaddr_in6($server_port, $addr)); if (not defined($send_ret)) { printf STDERR "Error \%d sending DHCPv6 Solicit message;\n\%s\n", 0+$ERRNO, $ERRNO; exit(1); } elsif ($send_ret != length($packet)) { print STDERR "Unable to send entire DHCPv6 Solicit message.\n"; exit(1); } $count++; my $RAND = rand(0.2) - 0.1; if (defined $RT) { $RT = 2*$RT + $RAND*$RT; if (($RT > $MRT) && ($MRT != 0)) { $RT = $MRT + $RAND*$RT; } } else { $RT = $IRT + $RAND*$IRT; } my $rt_end_time = time() + $RT; if (defined($mrd_end_time) && ($mrd_end_time > $rt_end_time)) { $rt_end_time = $mrd_end_time; } for (;;) { my $timeout = $rt_end_time - time(); if ($timeout < 0) { # print STDERR "Timeout waiting for DHCPv6 Advertise ", # "or Reply message.\n"; last; } my @ready = IO::Select->new(\*SOCK)->can_read($timeout); if (@ready) { my $reply; my $recv_ret; $recv_ret = recv(SOCK, $reply, 1500, 0); if (not defined $recv_ret) { printf STDERR "Error \%d receiving DHCPv6 " . "message;\n\%s\n", 0+$ERRNO, $ERRNO; exit(1); } $reply_msg = dhcp_client::msg::decode($reply); if (($reply_msg->{msg_type} == $MSG_ADVERTISE) || ($reply_msg->{msg_type} == $MSG_REPLY)) { last; } } } } until ($reply_msg || (($MRC != 0) && ($count > $MRC)) || (defined($mrd_end_time) && ($mrd_end_time > time()))); unless ($reply_msg) { if (($MRC != 0) && ($count >= $MRC)) { print STDERR "No reply after maximum retransmission count.\n"; } else { print STDERR "No reply after maximum retransmission duration.\n"; } } if ($reply_msg && ($reply_msg->{msg_type} == $MSG_REPLY)) { print "Got DHCPv6 Reply message.\n"; exit(0); } #$Data::Dumper::Useqq = 1; #print Dumper($msg), "\n"; #print Dumper($msg->packet()), "\n"; # #print "packet length: ", length($msg->packet()), "\n"; dhcp-4.2.4/tests/DHCPv6/020-advertise-mcast.pl000644 000765 000024 00000010374 11301372617 020460 0ustar00sarstaff000000 000000 #! /usr/bin/perl -w # Copyright (c) 2007,2009 by Internet Systems Consortium, Inc. ("ISC") # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # # Internet Systems Consortium, Inc. # 950 Charter Street # Redwood City, CA 94063 # # https://www.isc.org/ use strict; use English; use Time::HiRes qw( sleep ); use Socket; use Socket6; use IO::Select; use dhcp_client; # well-known addresses my $All_DHCP_Relay_Agents_and_Servers = "ff02::1:2"; my $All_DHCP_Servers = "ff05::1:3"; # ports my $client_port = 546; my $server_port = 547; # create a new Solicit message my $msg = dhcp_client::msg->new($MSG_ADVERTISE); # add the Client Identifier (required by DOCSIS and RFC 3315) $msg->add_option($OPT_CLIENTID, dhcp_client::duid()); # add Elapsed Time, set to 0 on first packet (required by RFC 3315) $msg->add_option($OPT_ELAPSED_TIME, "\x00\x00"); # add IA_NA for each interface (required by DOCSIS and RFC 3315) # XXX: should this be a single interface only? my $iaid = 0; foreach my $iface (dhcp_client::iface()) { my $option_data = pack("NNN", ++$iaid, 0, 0); $msg->add_option($OPT_IA_NA, $option_data); } # add Options Request (required by DOCSIS, recommended by RFC 3315) my @oro = ( ); $msg->add_option($OPT_ORO, pack("n*", @oro)); # timeout parameters my $IRT = $SOL_TIMEOUT; my $MRT = $SOL_MAX_RT; my $MRC = 1; # DOCSIS says 4, RFC 3315 says it SHOULD be 0 my $MRD = 0; # sleep a random amount of time between 0 and 1 second, required by RFC 3315 # XXX: this seems pretty stupid sleep(rand($SOL_MAX_DELAY)); my $RT; my $count = 0; my $mrd_end_time; if ($MRD != 0) { $mrd_end_time = time() + $MRD; } my $reply_msg; do { # create our socket, and send our bogus packet socket(SOCK, PF_INET6, SOCK_DGRAM, getprotobyname('udp')) || die; my $addr = inet_pton(AF_INET6, $All_DHCP_Servers); my $packet = $msg->packet(); my $send_ret = send(SOCK, $packet, 0, pack_sockaddr_in6($server_port, $addr)); if (not defined($send_ret)) { printf STDERR "Error \%d sending DHCPv6 message;\n\%s\n", 0+$ERRNO, $ERRNO; exit(1); } elsif ($send_ret != length($packet)) { print STDERR "Unable to send entire DHCPv6 message.\n"; exit(1); } $count++; my $RAND = rand(0.2) - 0.1; if (defined $RT) { $RT = 2*$RT + $RAND*$RT; if (($RT > $MRT) && ($MRT != 0)) { $RT = $MRT + $RAND*$RT; } } else { $RT = $IRT + $RAND*$IRT; } my $rt_end_time = time() + $RT; if (defined($mrd_end_time) && ($mrd_end_time > $rt_end_time)) { $rt_end_time = $mrd_end_time; } for (;;) { my $timeout = $rt_end_time - time(); if ($timeout < 0) { last; } my @ready = IO::Select->new(\*SOCK)->can_read($timeout); if (@ready) { my $reply; my $recv_ret; $recv_ret = recv(SOCK, $reply, 1500, 0); if (not defined $recv_ret) { printf STDERR "Error \%d receiving DHCPv6 " . "message;\n\%s\n", 0+$ERRNO, $ERRNO; exit(1); } $reply_msg = dhcp_client::msg::decode($reply); if (($reply_msg->{msg_type} == $MSG_ADVERTISE) || ($reply_msg->{msg_type} == $MSG_REPLY)) { last; } } } } until ($reply_msg || (($MRC != 0) && ($count > $MRC)) || (defined($mrd_end_time) && ($mrd_end_time > time()))); unless ($reply_msg) { if (($MRC != 0) && ($count >= $MRC)) { print STDERR "No reply after maximum retransmission count.\n"; } else { print STDERR "No reply after maximum retransmission duration.\n"; } } if ($reply_msg && ($reply_msg->{msg_type} == $MSG_REPLY)) { print "Got DHCPv6 Reply message.\n"; exit(0); } #$Data::Dumper::Useqq = 1; #print Dumper($msg), "\n"; #print Dumper($msg->packet()), "\n"; # #print "packet length: ", length($msg->packet()), "\n"; dhcp-4.2.4/tests/DHCPv6/030-request-noclientid.pl000644 000765 000024 00000013332 11301372617 021201 0ustar00sarstaff000000 000000 #! /usr/bin/perl -w # Copyright (c) 2007,2009 by Internet Systems Consortium, Inc. ("ISC") # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # # Internet Systems Consortium, Inc. # 950 Charter Street # Redwood City, CA 94063 # # https://www.isc.org/ use strict; use English; use Time::HiRes qw( sleep ); use Socket; use Socket6; use IO::Select; use dhcp_client; # XXX: for debugging use Data::Dumper; # not-yet-standard options my $OPT_TIME_SERVERS = 40; my $OPT_TIME_OFFSET = 41; # DOCSIS sub-options my $DOCSIS_OPT_ORO = 1; # 2 to 31 are reserved my $DOCSIS_OPT_TFTP_SERVERS = 32; my $DOCSIS_OPT_CONFIG_FILE_NAME = 33; my $DOCSIS_OPT_SYSLOG_SERVERS = 34; my $DOCSIS_OPT_TLV5 = 35; my $DOCSIS_OPT_DEVICE_ID = 36; my $DOCSIS_OPT_CCC = 37; my $DOCSIS_OPT_VERS = 38; # well-known addresses my $All_DHCP_Relay_Agents_and_Servers = "ff02::1:2"; my $All_DHCP_Servers = "ff05::1:3"; # ports my $client_port = 546; my $server_port = 547; # create a new Solicit message my $msg = dhcp_client::msg->new($MSG_REQUEST); # NOT add the Client Identifier (required by DOCSIS and RFC 3315) #$msg->add_option($OPT_CLIENTID, dhcp_client::duid()); # add Elapsed Time, set to 0 on first packet (required by RFC 3315) $msg->add_option($OPT_ELAPSED_TIME, "\x00\x00"); # add IA_NA for each interface (required by DOCSIS and RFC 3315) # XXX: should this be a single interface only? my $iaid = 0; foreach my $iface (dhcp_client::iface()) { my $option_data = pack("NNN", ++$iaid, 0, 0); $msg->add_option($OPT_IA_NA, $option_data); } # add Reconfigure Accept (required by DOCSIS) $msg->add_option($OPT_RECONF_ACCEPT, ""); # add Options Request (required by DOCSIS, recommended by RFC 3315) my @oro = ( $OPT_TIME_SERVERS, $OPT_TIME_OFFSET ); $msg->add_option($OPT_ORO, pack("n*", @oro)); # add Vendor Class option (required by DOCSIS) $msg->add_option($OPT_VENDOR_CLASS, pack("N", 4491) . "docsis3.0"); # add Vendor-specific Information Option option (required by DOCSIS) my $vsio = pack("N", 4491); # ORO (required by DOCSIS) my @docsis_oro = ( $DOCSIS_OPT_TFTP_SERVERS ); $vsio .= pack("nnC*", $DOCSIS_OPT_ORO, 0+@docsis_oro, @docsis_oro); # TLV5 data: CMTS DOCSIS version number 3.0 (required by DOCSIS) my $tlv5_data = "\x01\x02\x03\x0"; $vsio .= pack("nn", $DOCSIS_OPT_TLV5, length($tlv5_data)) . $tlv5_data; # DOCSIS Device (required by DOCSIS) my $docsis_device_id = dhcp_client::mac_addr_binary(); $vsio .= pack("nn", $DOCSIS_OPT_DEVICE_ID, length($docsis_device_id)); $vsio .= $docsis_device_id; $msg->add_option($OPT_VENDOR_OPTS, $vsio); # add Rapid Commit option (required by DOCSIS) $msg->add_option($OPT_RAPID_COMMIT, ""); # timeout parameters, from DOCSIS my $IRT = $SOL_TIMEOUT; my $MRT = $SOL_MAX_RT; my $MRC = 1; # DOCSIS says 4, RFC 3315 says it SHOULD be 0 my $MRD = 0; # sleep a random amount of time between 0 and 1 second, required by RFC 3315 # XXX: this seems pretty stupid sleep(rand($SOL_MAX_DELAY)); my $RT; my $count = 0; my $mrd_end_time; if ($MRD != 0) { $mrd_end_time = time() + $MRD; } my $reply_msg; do { # create our socket, and send our Solicit socket(SOCK, PF_INET6, SOCK_DGRAM, getprotobyname('udp')) || die; my $addr = inet_pton(AF_INET6, $All_DHCP_Servers); my $packet = $msg->packet(); my $send_ret = send(SOCK, $packet, 0, pack_sockaddr_in6($server_port, $addr)); if (not defined($send_ret)) { printf STDERR "Error \%d sending DHCPv6 Solicit message;\n\%s\n", 0+$ERRNO, $ERRNO; exit(1); } elsif ($send_ret != length($packet)) { print STDERR "Unable to send entire DHCPv6 Solicit message.\n"; exit(1); } $count++; my $RAND = rand(0.2) - 0.1; if (defined $RT) { $RT = 2*$RT + $RAND*$RT; if (($RT > $MRT) && ($MRT != 0)) { $RT = $MRT + $RAND*$RT; } } else { $RT = $IRT + $RAND*$IRT; } my $rt_end_time = time() + $RT; if (defined($mrd_end_time) && ($mrd_end_time > $rt_end_time)) { $rt_end_time = $mrd_end_time; } for (;;) { my $timeout = $rt_end_time - time(); if ($timeout < 0) { # print STDERR "Timeout waiting for DHCPv6 Advertise ", # "or Reply message.\n"; last; } my @ready = IO::Select->new(\*SOCK)->can_read($timeout); if (@ready) { my $reply; my $recv_ret; $recv_ret = recv(SOCK, $reply, 1500, 0); if (not defined $recv_ret) { printf STDERR "Error \%d receiving DHCPv6 " . "message;\n\%s\n", 0+$ERRNO, $ERRNO; exit(1); } $reply_msg = dhcp_client::msg::decode($reply); if (($reply_msg->{msg_type} == $MSG_ADVERTISE) || ($reply_msg->{msg_type} == $MSG_REPLY)) { last; } } } } until ($reply_msg || (($MRC != 0) && ($count > $MRC)) || (defined($mrd_end_time) && ($mrd_end_time > time()))); unless ($reply_msg) { if (($MRC != 0) && ($count >= $MRC)) { print STDERR "No reply after maximum retransmission count.\n"; } else { print STDERR "No reply after maximum retransmission duration.\n"; } } if ($reply_msg && ($reply_msg->{msg_type} == $MSG_REPLY)) { print "Got DHCPv6 Reply message.\n"; exit(0); } #$Data::Dumper::Useqq = 1; #print Dumper($msg), "\n"; #print Dumper($msg->packet()), "\n"; # #print "packet length: ", length($msg->packet()), "\n"; dhcp-4.2.4/tests/DHCPv6/031-request-noserverid.pl000644 000765 000024 00000013325 11301372617 021234 0ustar00sarstaff000000 000000 #! /usr/bin/perl -w # Copyright (c) 2007,2009 by Internet Systems Consortium, Inc. ("ISC") # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # # Internet Systems Consortium, Inc. # 950 Charter Street # Redwood City, CA 94063 # # https://www.isc.org/ use strict; use English; use Time::HiRes qw( sleep ); use Socket; use Socket6; use IO::Select; use dhcp_client; # XXX: for debugging use Data::Dumper; # not-yet-standard options my $OPT_TIME_SERVERS = 40; my $OPT_TIME_OFFSET = 41; # DOCSIS sub-options my $DOCSIS_OPT_ORO = 1; # 2 to 31 are reserved my $DOCSIS_OPT_TFTP_SERVERS = 32; my $DOCSIS_OPT_CONFIG_FILE_NAME = 33; my $DOCSIS_OPT_SYSLOG_SERVERS = 34; my $DOCSIS_OPT_TLV5 = 35; my $DOCSIS_OPT_DEVICE_ID = 36; my $DOCSIS_OPT_CCC = 37; my $DOCSIS_OPT_VERS = 38; # well-known addresses my $All_DHCP_Relay_Agents_and_Servers = "ff02::1:2"; my $All_DHCP_Servers = "ff05::1:3"; # ports my $client_port = 546; my $server_port = 547; # create a new Solicit message my $msg = dhcp_client::msg->new($MSG_REQUEST); # add the Client Identifier (required by DOCSIS and RFC 3315) $msg->add_option($OPT_CLIENTID, dhcp_client::duid()); # add Elapsed Time, set to 0 on first packet (required by RFC 3315) $msg->add_option($OPT_ELAPSED_TIME, "\x00\x00"); # add IA_NA for each interface (required by DOCSIS and RFC 3315) # XXX: should this be a single interface only? my $iaid = 0; foreach my $iface (dhcp_client::iface()) { my $option_data = pack("NNN", ++$iaid, 0, 0); $msg->add_option($OPT_IA_NA, $option_data); } # add Reconfigure Accept (required by DOCSIS) $msg->add_option($OPT_RECONF_ACCEPT, ""); # add Options Request (required by DOCSIS, recommended by RFC 3315) my @oro = ( $OPT_TIME_SERVERS, $OPT_TIME_OFFSET ); $msg->add_option($OPT_ORO, pack("n*", @oro)); # add Vendor Class option (required by DOCSIS) $msg->add_option($OPT_VENDOR_CLASS, pack("N", 4491) . "docsis3.0"); # add Vendor-specific Information Option option (required by DOCSIS) my $vsio = pack("N", 4491); # ORO (required by DOCSIS) my @docsis_oro = ( $DOCSIS_OPT_TFTP_SERVERS ); $vsio .= pack("nnC*", $DOCSIS_OPT_ORO, 0+@docsis_oro, @docsis_oro); # TLV5 data: CMTS DOCSIS version number 3.0 (required by DOCSIS) my $tlv5_data = "\x01\x02\x03\x0"; $vsio .= pack("nn", $DOCSIS_OPT_TLV5, length($tlv5_data)) . $tlv5_data; # DOCSIS Device (required by DOCSIS) my $docsis_device_id = dhcp_client::mac_addr_binary(); $vsio .= pack("nn", $DOCSIS_OPT_DEVICE_ID, length($docsis_device_id)); $vsio .= $docsis_device_id; $msg->add_option($OPT_VENDOR_OPTS, $vsio); # add Rapid Commit option (required by DOCSIS) $msg->add_option($OPT_RAPID_COMMIT, ""); # timeout parameters, from DOCSIS my $IRT = $SOL_TIMEOUT; my $MRT = $SOL_MAX_RT; my $MRC = 1; # DOCSIS says 4, RFC 3315 says it SHOULD be 0 my $MRD = 0; # sleep a random amount of time between 0 and 1 second, required by RFC 3315 # XXX: this seems pretty stupid sleep(rand($SOL_MAX_DELAY)); my $RT; my $count = 0; my $mrd_end_time; if ($MRD != 0) { $mrd_end_time = time() + $MRD; } my $reply_msg; do { # create our socket, and send our Solicit socket(SOCK, PF_INET6, SOCK_DGRAM, getprotobyname('udp')) || die; my $addr = inet_pton(AF_INET6, $All_DHCP_Servers); my $packet = $msg->packet(); my $send_ret = send(SOCK, $packet, 0, pack_sockaddr_in6($server_port, $addr)); if (not defined($send_ret)) { printf STDERR "Error \%d sending DHCPv6 Solicit message;\n\%s\n", 0+$ERRNO, $ERRNO; exit(1); } elsif ($send_ret != length($packet)) { print STDERR "Unable to send entire DHCPv6 Solicit message.\n"; exit(1); } $count++; my $RAND = rand(0.2) - 0.1; if (defined $RT) { $RT = 2*$RT + $RAND*$RT; if (($RT > $MRT) && ($MRT != 0)) { $RT = $MRT + $RAND*$RT; } } else { $RT = $IRT + $RAND*$IRT; } my $rt_end_time = time() + $RT; if (defined($mrd_end_time) && ($mrd_end_time > $rt_end_time)) { $rt_end_time = $mrd_end_time; } for (;;) { my $timeout = $rt_end_time - time(); if ($timeout < 0) { # print STDERR "Timeout waiting for DHCPv6 Advertise ", # "or Reply message.\n"; last; } my @ready = IO::Select->new(\*SOCK)->can_read($timeout); if (@ready) { my $reply; my $recv_ret; $recv_ret = recv(SOCK, $reply, 1500, 0); if (not defined $recv_ret) { printf STDERR "Error \%d receiving DHCPv6 " . "message;\n\%s\n", 0+$ERRNO, $ERRNO; exit(1); } $reply_msg = dhcp_client::msg::decode($reply); if (($reply_msg->{msg_type} == $MSG_ADVERTISE) || ($reply_msg->{msg_type} == $MSG_REPLY)) { last; } } } } until ($reply_msg || (($MRC != 0) && ($count > $MRC)) || (defined($mrd_end_time) && ($mrd_end_time > time()))); unless ($reply_msg) { if (($MRC != 0) && ($count >= $MRC)) { print STDERR "No reply after maximum retransmission count.\n"; } else { print STDERR "No reply after maximum retransmission duration.\n"; } } if ($reply_msg && ($reply_msg->{msg_type} == $MSG_REPLY)) { print "Got DHCPv6 Reply message.\n"; exit(0); } #$Data::Dumper::Useqq = 1; #print Dumper($msg), "\n"; #print Dumper($msg->packet()), "\n"; # #print "packet length: ", length($msg->packet()), "\n"; dhcp-4.2.4/tests/DHCPv6/032-request-badduid.pl000644 000765 000024 00000013537 11301372617 020456 0ustar00sarstaff000000 000000 #! /usr/bin/perl -w # Copyright (c) 2007,2009 by Internet Systems Consortium, Inc. ("ISC") # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # # Internet Systems Consortium, Inc. # 950 Charter Street # Redwood City, CA 94063 # # https://www.isc.org/ use strict; use English; use Time::HiRes qw( sleep ); use Socket; use Socket6; use IO::Select; use dhcp_client; # XXX: for debugging use Data::Dumper; # not-yet-standard options my $OPT_TIME_SERVERS = 40; my $OPT_TIME_OFFSET = 41; # DOCSIS sub-options my $DOCSIS_OPT_ORO = 1; # 2 to 31 are reserved my $DOCSIS_OPT_TFTP_SERVERS = 32; my $DOCSIS_OPT_CONFIG_FILE_NAME = 33; my $DOCSIS_OPT_SYSLOG_SERVERS = 34; my $DOCSIS_OPT_TLV5 = 35; my $DOCSIS_OPT_DEVICE_ID = 36; my $DOCSIS_OPT_CCC = 37; my $DOCSIS_OPT_VERS = 38; # well-known addresses my $All_DHCP_Relay_Agents_and_Servers = "ff02::1:2"; my $All_DHCP_Servers = "ff05::1:3"; # ports my $client_port = 546; my $server_port = 547; # create a new Solicit message my $msg = dhcp_client::msg->new($MSG_REQUEST); # add the Client Identifier (required by DOCSIS and RFC 3315) $msg->add_option($OPT_CLIENTID, dhcp_client::duid()); # add the Server Identifier (required by DOCSIS and RFC 3315) # but use *our* DUID $msg->add_option($OPT_SERVERID, dhcp_client::duid()); # add Elapsed Time, set to 0 on first packet (required by RFC 3315) $msg->add_option($OPT_ELAPSED_TIME, "\x00\x00"); # add IA_NA for each interface (required by DOCSIS and RFC 3315) # XXX: should this be a single interface only? my $iaid = 0; foreach my $iface (dhcp_client::iface()) { my $option_data = pack("NNN", ++$iaid, 0, 0); $msg->add_option($OPT_IA_NA, $option_data); } # add Reconfigure Accept (required by DOCSIS) $msg->add_option($OPT_RECONF_ACCEPT, ""); # add Options Request (required by DOCSIS, recommended by RFC 3315) my @oro = ( $OPT_TIME_SERVERS, $OPT_TIME_OFFSET ); $msg->add_option($OPT_ORO, pack("n*", @oro)); # add Vendor Class option (required by DOCSIS) $msg->add_option($OPT_VENDOR_CLASS, pack("N", 4491) . "docsis3.0"); # add Vendor-specific Information Option option (required by DOCSIS) my $vsio = pack("N", 4491); # ORO (required by DOCSIS) my @docsis_oro = ( $DOCSIS_OPT_TFTP_SERVERS ); $vsio .= pack("nnC*", $DOCSIS_OPT_ORO, 0+@docsis_oro, @docsis_oro); # TLV5 data: CMTS DOCSIS version number 3.0 (required by DOCSIS) my $tlv5_data = "\x01\x02\x03\x0"; $vsio .= pack("nn", $DOCSIS_OPT_TLV5, length($tlv5_data)) . $tlv5_data; # DOCSIS Device (required by DOCSIS) my $docsis_device_id = dhcp_client::mac_addr_binary(); $vsio .= pack("nn", $DOCSIS_OPT_DEVICE_ID, length($docsis_device_id)); $vsio .= $docsis_device_id; $msg->add_option($OPT_VENDOR_OPTS, $vsio); # add Rapid Commit option (required by DOCSIS) $msg->add_option($OPT_RAPID_COMMIT, ""); # timeout parameters, from DOCSIS my $IRT = $SOL_TIMEOUT; my $MRT = $SOL_MAX_RT; my $MRC = 1; # DOCSIS says 4, RFC 3315 says it SHOULD be 0 my $MRD = 0; # sleep a random amount of time between 0 and 1 second, required by RFC 3315 # XXX: this seems pretty stupid sleep(rand($SOL_MAX_DELAY)); my $RT; my $count = 0; my $mrd_end_time; if ($MRD != 0) { $mrd_end_time = time() + $MRD; } my $reply_msg; do { # create our socket, and send our Solicit socket(SOCK, PF_INET6, SOCK_DGRAM, getprotobyname('udp')) || die; my $addr = inet_pton(AF_INET6, $All_DHCP_Servers); my $packet = $msg->packet(); my $send_ret = send(SOCK, $packet, 0, pack_sockaddr_in6($server_port, $addr)); if (not defined($send_ret)) { printf STDERR "Error \%d sending DHCPv6 Solicit message;\n\%s\n", 0+$ERRNO, $ERRNO; exit(1); } elsif ($send_ret != length($packet)) { print STDERR "Unable to send entire DHCPv6 Solicit message.\n"; exit(1); } $count++; my $RAND = rand(0.2) - 0.1; if (defined $RT) { $RT = 2*$RT + $RAND*$RT; if (($RT > $MRT) && ($MRT != 0)) { $RT = $MRT + $RAND*$RT; } } else { $RT = $IRT + $RAND*$IRT; } my $rt_end_time = time() + $RT; if (defined($mrd_end_time) && ($mrd_end_time > $rt_end_time)) { $rt_end_time = $mrd_end_time; } for (;;) { my $timeout = $rt_end_time - time(); if ($timeout < 0) { # print STDERR "Timeout waiting for DHCPv6 Advertise ", # "or Reply message.\n"; last; } my @ready = IO::Select->new(\*SOCK)->can_read($timeout); if (@ready) { my $reply; my $recv_ret; $recv_ret = recv(SOCK, $reply, 1500, 0); if (not defined $recv_ret) { printf STDERR "Error \%d receiving DHCPv6 " . "message;\n\%s\n", 0+$ERRNO, $ERRNO; exit(1); } $reply_msg = dhcp_client::msg::decode($reply); if (($reply_msg->{msg_type} == $MSG_ADVERTISE) || ($reply_msg->{msg_type} == $MSG_REPLY)) { last; } } } } until ($reply_msg || (($MRC != 0) && ($count > $MRC)) || (defined($mrd_end_time) && ($mrd_end_time > time()))); unless ($reply_msg) { if (($MRC != 0) && ($count >= $MRC)) { print STDERR "No reply after maximum retransmission count.\n"; } else { print STDERR "No reply after maximum retransmission duration.\n"; } } if ($reply_msg && ($reply_msg->{msg_type} == $MSG_REPLY)) { print "Got DHCPv6 Reply message.\n"; exit(0); } #$Data::Dumper::Useqq = 1; #print Dumper($msg), "\n"; #print Dumper($msg->packet()), "\n"; # #print "packet length: ", length($msg->packet()), "\n"; dhcp-4.2.4/tests/DHCPv6/110-information-request-ia_na.pl000644 000765 000024 00000013341 11301372617 022442 0ustar00sarstaff000000 000000 #! /usr/bin/perl -w # Copyright (c) 2007,2009 by Internet Systems Consortium, Inc. ("ISC") # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # # Internet Systems Consortium, Inc. # 950 Charter Street # Redwood City, CA 94063 # # https://www.isc.org/ use strict; use English; use Time::HiRes qw( sleep ); use Socket; use Socket6; use IO::Select; use dhcp_client; # XXX: for debugging use Data::Dumper; # not-yet-standard options my $OPT_TIME_SERVERS = 40; my $OPT_TIME_OFFSET = 41; # DOCSIS sub-options my $DOCSIS_OPT_ORO = 1; # 2 to 31 are reserved my $DOCSIS_OPT_TFTP_SERVERS = 32; my $DOCSIS_OPT_CONFIG_FILE_NAME = 33; my $DOCSIS_OPT_SYSLOG_SERVERS = 34; my $DOCSIS_OPT_TLV5 = 35; my $DOCSIS_OPT_DEVICE_ID = 36; my $DOCSIS_OPT_CCC = 37; my $DOCSIS_OPT_VERS = 38; # well-known addresses my $All_DHCP_Relay_Agents_and_Servers = "ff02::1:2"; my $All_DHCP_Servers = "ff05::1:3"; # ports my $client_port = 546; my $server_port = 547; # create a new Solicit message my $msg = dhcp_client::msg->new($MSG_INFORMATION_REQUEST); # add the Client Identifier (required by DOCSIS and RFC 3315) $msg->add_option($OPT_CLIENTID, dhcp_client::duid()); # add Elapsed Time, set to 0 on first packet (required by RFC 3315) $msg->add_option($OPT_ELAPSED_TIME, "\x00\x00"); # add IA_NA for each interface (required by DOCSIS and RFC 3315) # XXX: should this be a single interface only? my $iaid = 0; foreach my $iface (dhcp_client::iface()) { my $option_data = pack("NNN", ++$iaid, 0, 0); $msg->add_option($OPT_IA_NA, $option_data); } # add Reconfigure Accept (required by DOCSIS) $msg->add_option($OPT_RECONF_ACCEPT, ""); # add Options Request (required by DOCSIS, recommended by RFC 3315) my @oro = ( $OPT_TIME_SERVERS, $OPT_TIME_OFFSET ); $msg->add_option($OPT_ORO, pack("n*", @oro)); # add Vendor Class option (required by DOCSIS) $msg->add_option($OPT_VENDOR_CLASS, pack("N", 4491) . "docsis3.0"); # add Vendor-specific Information Option option (required by DOCSIS) my $vsio = pack("N", 4491); # ORO (required by DOCSIS) my @docsis_oro = ( $DOCSIS_OPT_TFTP_SERVERS ); $vsio .= pack("nnC*", $DOCSIS_OPT_ORO, 0+@docsis_oro, @docsis_oro); # TLV5 data: CMTS DOCSIS version number 3.0 (required by DOCSIS) my $tlv5_data = "\x01\x02\x03\x0"; $vsio .= pack("nn", $DOCSIS_OPT_TLV5, length($tlv5_data)) . $tlv5_data; # DOCSIS Device (required by DOCSIS) my $docsis_device_id = dhcp_client::mac_addr_binary(); $vsio .= pack("nn", $DOCSIS_OPT_DEVICE_ID, length($docsis_device_id)); $vsio .= $docsis_device_id; $msg->add_option($OPT_VENDOR_OPTS, $vsio); # add Rapid Commit option (required by DOCSIS) $msg->add_option($OPT_RAPID_COMMIT, ""); # timeout parameters, from DOCSIS my $IRT = $SOL_TIMEOUT; my $MRT = $SOL_MAX_RT; my $MRC = 1; # DOCSIS says 4, RFC 3315 says it SHOULD be 0 my $MRD = 0; # sleep a random amount of time between 0 and 1 second, required by RFC 3315 # XXX: this seems pretty stupid sleep(rand($SOL_MAX_DELAY)); my $RT; my $count = 0; my $mrd_end_time; if ($MRD != 0) { $mrd_end_time = time() + $MRD; } my $reply_msg; do { # create our socket, and send our Solicit socket(SOCK, PF_INET6, SOCK_DGRAM, getprotobyname('udp')) || die; my $addr = inet_pton(AF_INET6, $All_DHCP_Servers); my $packet = $msg->packet(); my $send_ret = send(SOCK, $packet, 0, pack_sockaddr_in6($server_port, $addr)); if (not defined($send_ret)) { printf STDERR "Error \%d sending DHCPv6 Solicit message;\n\%s\n", 0+$ERRNO, $ERRNO; exit(1); } elsif ($send_ret != length($packet)) { print STDERR "Unable to send entire DHCPv6 Solicit message.\n"; exit(1); } $count++; my $RAND = rand(0.2) - 0.1; if (defined $RT) { $RT = 2*$RT + $RAND*$RT; if (($RT > $MRT) && ($MRT != 0)) { $RT = $MRT + $RAND*$RT; } } else { $RT = $IRT + $RAND*$IRT; } my $rt_end_time = time() + $RT; if (defined($mrd_end_time) && ($mrd_end_time > $rt_end_time)) { $rt_end_time = $mrd_end_time; } for (;;) { my $timeout = $rt_end_time - time(); if ($timeout < 0) { # print STDERR "Timeout waiting for DHCPv6 Advertise ", # "or Reply message.\n"; last; } my @ready = IO::Select->new(\*SOCK)->can_read($timeout); if (@ready) { my $reply; my $recv_ret; $recv_ret = recv(SOCK, $reply, 1500, 0); if (not defined $recv_ret) { printf STDERR "Error \%d receiving DHCPv6 " . "message;\n\%s\n", 0+$ERRNO, $ERRNO; exit(1); } $reply_msg = dhcp_client::msg::decode($reply); if (($reply_msg->{msg_type} == $MSG_ADVERTISE) || ($reply_msg->{msg_type} == $MSG_REPLY)) { last; } } } } until ($reply_msg || (($MRC != 0) && ($count > $MRC)) || (defined($mrd_end_time) && ($mrd_end_time > time()))); unless ($reply_msg) { if (($MRC != 0) && ($count >= $MRC)) { print STDERR "No reply after maximum retransmission count.\n"; } else { print STDERR "No reply after maximum retransmission duration.\n"; } } if ($reply_msg && ($reply_msg->{msg_type} == $MSG_REPLY)) { print "Got DHCPv6 Reply message.\n"; exit(0); } #$Data::Dumper::Useqq = 1; #print Dumper($msg), "\n"; #print Dumper($msg->packet()), "\n"; # #print "packet length: ", length($msg->packet()), "\n"; dhcp-4.2.4/tests/DHCPv6/111-information-request-ia_ta.pl000644 000765 000024 00000013351 11301372617 022452 0ustar00sarstaff000000 000000 #! /usr/bin/perl -w # Copyright (c) 2007,2009 by Internet Systems Consortium, Inc. ("ISC") # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # # Internet Systems Consortium, Inc. # 950 Charter Street # Redwood City, CA 94063 # # https://www.isc.org/ use strict; use English; use Time::HiRes qw( sleep ); use Socket; use Socket6; use IO::Select; use dhcp_client; # XXX: for debugging use Data::Dumper; # not-yet-standard options my $OPT_TIME_SERVERS = 40; my $OPT_TIME_OFFSET = 41; # DOCSIS sub-options my $DOCSIS_OPT_ORO = 1; # 2 to 31 are reserved my $DOCSIS_OPT_TFTP_SERVERS = 32; my $DOCSIS_OPT_CONFIG_FILE_NAME = 33; my $DOCSIS_OPT_SYSLOG_SERVERS = 34; my $DOCSIS_OPT_TLV5 = 35; my $DOCSIS_OPT_DEVICE_ID = 36; my $DOCSIS_OPT_CCC = 37; my $DOCSIS_OPT_VERS = 38; # well-known addresses my $All_DHCP_Relay_Agents_and_Servers = "ff02::1:2"; my $All_DHCP_Servers = "ff05::1:3"; # ports my $client_port = 546; my $server_port = 547; # create a new Solicit message my $msg = dhcp_client::msg->new($MSG_INFORMATION_REQUEST); # add the Client Identifier (required by DOCSIS and RFC 3315) $msg->add_option($OPT_CLIENTID, dhcp_client::duid()); # add Elapsed Time, set to 0 on first packet (required by RFC 3315) $msg->add_option($OPT_ELAPSED_TIME, "\x00\x00"); # add IA_TA for each interface (should be IA_NA, by DOCSIS and RFC 3315) # XXX: should this be a single interface only? my $iaid = 0; foreach my $iface (dhcp_client::iface()) { my $option_data = pack("NNN", ++$iaid, 0, 0); $msg->add_option($OPT_IA_TA, $option_data); } # add Reconfigure Accept (required by DOCSIS) $msg->add_option($OPT_RECONF_ACCEPT, ""); # add Options Request (required by DOCSIS, recommended by RFC 3315) my @oro = ( $OPT_TIME_SERVERS, $OPT_TIME_OFFSET ); $msg->add_option($OPT_ORO, pack("n*", @oro)); # add Vendor Class option (required by DOCSIS) $msg->add_option($OPT_VENDOR_CLASS, pack("N", 4491) . "docsis3.0"); # add Vendor-specific Information Option option (required by DOCSIS) my $vsio = pack("N", 4491); # ORO (required by DOCSIS) my @docsis_oro = ( $DOCSIS_OPT_TFTP_SERVERS ); $vsio .= pack("nnC*", $DOCSIS_OPT_ORO, 0+@docsis_oro, @docsis_oro); # TLV5 data: CMTS DOCSIS version number 3.0 (required by DOCSIS) my $tlv5_data = "\x01\x02\x03\x0"; $vsio .= pack("nn", $DOCSIS_OPT_TLV5, length($tlv5_data)) . $tlv5_data; # DOCSIS Device (required by DOCSIS) my $docsis_device_id = dhcp_client::mac_addr_binary(); $vsio .= pack("nn", $DOCSIS_OPT_DEVICE_ID, length($docsis_device_id)); $vsio .= $docsis_device_id; $msg->add_option($OPT_VENDOR_OPTS, $vsio); # add Rapid Commit option (required by DOCSIS) $msg->add_option($OPT_RAPID_COMMIT, ""); # timeout parameters, from DOCSIS my $IRT = $SOL_TIMEOUT; my $MRT = $SOL_MAX_RT; my $MRC = 1; # DOCSIS says 4, RFC 3315 says it SHOULD be 0 my $MRD = 0; # sleep a random amount of time between 0 and 1 second, required by RFC 3315 # XXX: this seems pretty stupid sleep(rand($SOL_MAX_DELAY)); my $RT; my $count = 0; my $mrd_end_time; if ($MRD != 0) { $mrd_end_time = time() + $MRD; } my $reply_msg; do { # create our socket, and send our Solicit socket(SOCK, PF_INET6, SOCK_DGRAM, getprotobyname('udp')) || die; my $addr = inet_pton(AF_INET6, $All_DHCP_Servers); my $packet = $msg->packet(); my $send_ret = send(SOCK, $packet, 0, pack_sockaddr_in6($server_port, $addr)); if (not defined($send_ret)) { printf STDERR "Error \%d sending DHCPv6 Solicit message;\n\%s\n", 0+$ERRNO, $ERRNO; exit(1); } elsif ($send_ret != length($packet)) { print STDERR "Unable to send entire DHCPv6 Solicit message.\n"; exit(1); } $count++; my $RAND = rand(0.2) - 0.1; if (defined $RT) { $RT = 2*$RT + $RAND*$RT; if (($RT > $MRT) && ($MRT != 0)) { $RT = $MRT + $RAND*$RT; } } else { $RT = $IRT + $RAND*$IRT; } my $rt_end_time = time() + $RT; if (defined($mrd_end_time) && ($mrd_end_time > $rt_end_time)) { $rt_end_time = $mrd_end_time; } for (;;) { my $timeout = $rt_end_time - time(); if ($timeout < 0) { # print STDERR "Timeout waiting for DHCPv6 Advertise ", # "or Reply message.\n"; last; } my @ready = IO::Select->new(\*SOCK)->can_read($timeout); if (@ready) { my $reply; my $recv_ret; $recv_ret = recv(SOCK, $reply, 1500, 0); if (not defined $recv_ret) { printf STDERR "Error \%d receiving DHCPv6 " . "message;\n\%s\n", 0+$ERRNO, $ERRNO; exit(1); } $reply_msg = dhcp_client::msg::decode($reply); if (($reply_msg->{msg_type} == $MSG_ADVERTISE) || ($reply_msg->{msg_type} == $MSG_REPLY)) { last; } } } } until ($reply_msg || (($MRC != 0) && ($count > $MRC)) || (defined($mrd_end_time) && ($mrd_end_time > time()))); unless ($reply_msg) { if (($MRC != 0) && ($count >= $MRC)) { print STDERR "No reply after maximum retransmission count.\n"; } else { print STDERR "No reply after maximum retransmission duration.\n"; } } if ($reply_msg && ($reply_msg->{msg_type} == $MSG_REPLY)) { print "Got DHCPv6 Reply message.\n"; exit(0); } #$Data::Dumper::Useqq = 1; #print Dumper($msg), "\n"; #print Dumper($msg->packet()), "\n"; # #print "packet length: ", length($msg->packet()), "\n"; dhcp-4.2.4/tests/DHCPv6/112-badduid.pl000644 000765 000024 00000013143 11301372617 016760 0ustar00sarstaff000000 000000 #! /usr/bin/perl -w # Copyright (c) 2007,2009 by Internet Systems Consortium, Inc. ("ISC") # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # # Internet Systems Consortium, Inc. # 950 Charter Street # Redwood City, CA 94063 # # https://www.isc.org/ use strict; use English; use Time::HiRes qw( sleep ); use Socket; use Socket6; use IO::Select; use dhcp_client; # XXX: for debugging use Data::Dumper; # not-yet-standard options my $OPT_TIME_SERVERS = 40; my $OPT_TIME_OFFSET = 41; # DOCSIS sub-options my $DOCSIS_OPT_ORO = 1; # 2 to 31 are reserved my $DOCSIS_OPT_TFTP_SERVERS = 32; my $DOCSIS_OPT_CONFIG_FILE_NAME = 33; my $DOCSIS_OPT_SYSLOG_SERVERS = 34; my $DOCSIS_OPT_TLV5 = 35; my $DOCSIS_OPT_DEVICE_ID = 36; my $DOCSIS_OPT_CCC = 37; my $DOCSIS_OPT_VERS = 38; # well-known addresses my $All_DHCP_Relay_Agents_and_Servers = "ff02::1:2"; my $All_DHCP_Servers = "ff05::1:3"; # ports my $client_port = 546; my $server_port = 547; # create a new Solicit message my $msg = dhcp_client::msg->new($MSG_INFORMATION_REQUEST); # add the Client Identifier (required by DOCSIS and RFC 3315) $msg->add_option($OPT_CLIENTID, dhcp_client::duid()); # add the Server Identifier (required by DOCSIS and RFC 3315) # but use *our* DUID $msg->add_option($OPT_SERVERID, dhcp_client::duid()); # add Elapsed Time, set to 0 on first packet (required by RFC 3315) $msg->add_option($OPT_ELAPSED_TIME, "\x00\x00"); # add Reconfigure Accept (required by DOCSIS) $msg->add_option($OPT_RECONF_ACCEPT, ""); # add Options Request (required by DOCSIS, recommended by RFC 3315) my @oro = ( $OPT_TIME_SERVERS, $OPT_TIME_OFFSET ); $msg->add_option($OPT_ORO, pack("n*", @oro)); # add Vendor Class option (required by DOCSIS) $msg->add_option($OPT_VENDOR_CLASS, pack("N", 4491) . "docsis3.0"); # add Vendor-specific Information Option option (required by DOCSIS) my $vsio = pack("N", 4491); # ORO (required by DOCSIS) my @docsis_oro = ( $DOCSIS_OPT_TFTP_SERVERS ); $vsio .= pack("nnC*", $DOCSIS_OPT_ORO, 0+@docsis_oro, @docsis_oro); # TLV5 data: CMTS DOCSIS version number 3.0 (required by DOCSIS) my $tlv5_data = "\x01\x02\x03\x0"; $vsio .= pack("nn", $DOCSIS_OPT_TLV5, length($tlv5_data)) . $tlv5_data; # DOCSIS Device (required by DOCSIS) my $docsis_device_id = dhcp_client::mac_addr_binary(); $vsio .= pack("nn", $DOCSIS_OPT_DEVICE_ID, length($docsis_device_id)); $vsio .= $docsis_device_id; $msg->add_option($OPT_VENDOR_OPTS, $vsio); # add Rapid Commit option (required by DOCSIS) $msg->add_option($OPT_RAPID_COMMIT, ""); # timeout parameters, from DOCSIS my $IRT = $SOL_TIMEOUT; my $MRT = $SOL_MAX_RT; my $MRC = 1; # DOCSIS says 4, RFC 3315 says it SHOULD be 0 my $MRD = 0; # sleep a random amount of time between 0 and 1 second, required by RFC 3315 # XXX: this seems pretty stupid sleep(rand($SOL_MAX_DELAY)); my $RT; my $count = 0; my $mrd_end_time; if ($MRD != 0) { $mrd_end_time = time() + $MRD; } my $reply_msg; do { # create our socket, and send our Solicit socket(SOCK, PF_INET6, SOCK_DGRAM, getprotobyname('udp')) || die; my $addr = inet_pton(AF_INET6, $All_DHCP_Servers); my $packet = $msg->packet(); my $send_ret = send(SOCK, $packet, 0, pack_sockaddr_in6($server_port, $addr)); if (not defined($send_ret)) { printf STDERR "Error \%d sending DHCPv6 Solicit message;\n\%s\n", 0+$ERRNO, $ERRNO; exit(1); } elsif ($send_ret != length($packet)) { print STDERR "Unable to send entire DHCPv6 Solicit message.\n"; exit(1); } $count++; my $RAND = rand(0.2) - 0.1; if (defined $RT) { $RT = 2*$RT + $RAND*$RT; if (($RT > $MRT) && ($MRT != 0)) { $RT = $MRT + $RAND*$RT; } } else { $RT = $IRT + $RAND*$IRT; } my $rt_end_time = time() + $RT; if (defined($mrd_end_time) && ($mrd_end_time > $rt_end_time)) { $rt_end_time = $mrd_end_time; } for (;;) { my $timeout = $rt_end_time - time(); if ($timeout < 0) { # print STDERR "Timeout waiting for DHCPv6 Advertise ", # "or Reply message.\n"; last; } my @ready = IO::Select->new(\*SOCK)->can_read($timeout); if (@ready) { my $reply; my $recv_ret; $recv_ret = recv(SOCK, $reply, 1500, 0); if (not defined $recv_ret) { printf STDERR "Error \%d receiving DHCPv6 " . "message;\n\%s\n", 0+$ERRNO, $ERRNO; exit(1); } $reply_msg = dhcp_client::msg::decode($reply); if (($reply_msg->{msg_type} == $MSG_ADVERTISE) || ($reply_msg->{msg_type} == $MSG_REPLY)) { last; } } } } until ($reply_msg || (($MRC != 0) && ($count > $MRC)) || (defined($mrd_end_time) && ($mrd_end_time > time()))); unless ($reply_msg) { if (($MRC != 0) && ($count >= $MRC)) { print STDERR "No reply after maximum retransmission count.\n"; } else { print STDERR "No reply after maximum retransmission duration.\n"; } } if ($reply_msg && ($reply_msg->{msg_type} == $MSG_REPLY)) { print "Got DHCPv6 Reply message.\n"; exit(0); } #$Data::Dumper::Useqq = 1; #print Dumper($msg), "\n"; #print Dumper($msg->packet()), "\n"; # #print "packet length: ", length($msg->packet()), "\n"; dhcp-4.2.4/tests/DHCPv6/210-solicit-nohost.pl000644 000765 000024 00000013330 11301372617 020337 0ustar00sarstaff000000 000000 #! /usr/bin/perl -w # Copyright (c) 2007,2009 by Internet Systems Consortium, Inc. ("ISC") # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # # Internet Systems Consortium, Inc. # 950 Charter Street # Redwood City, CA 94063 # # https://www.isc.org/ use strict; use English; use Time::HiRes qw( sleep ); use Socket; use Socket6; use IO::Select; use dhcp_client; # XXX: for debugging use Data::Dumper; # not-yet-standard options my $OPT_TIME_SERVERS = 40; my $OPT_TIME_OFFSET = 41; # DOCSIS sub-options my $DOCSIS_OPT_ORO = 1; # 2 to 31 are reserved my $DOCSIS_OPT_TFTP_SERVERS = 32; my $DOCSIS_OPT_CONFIG_FILE_NAME = 33; my $DOCSIS_OPT_SYSLOG_SERVERS = 34; my $DOCSIS_OPT_TLV5 = 35; my $DOCSIS_OPT_DEVICE_ID = 36; my $DOCSIS_OPT_CCC = 37; my $DOCSIS_OPT_VERS = 38; # well-known addresses my $All_DHCP_Relay_Agents_and_Servers = "ff02::1:2"; my $All_DHCP_Servers = "ff05::1:3"; # ports my $client_port = 546; my $server_port = 547; # create a new Solicit message my $msg = dhcp_client::msg->new($MSG_SOLICIT); # add the Client Identifier (required by DOCSIS and RFC 3315) $msg->add_option($OPT_CLIENTID, dhcp_client::duid()); # add Elapsed Time, set to 0 on first packet (required by RFC 3315) $msg->add_option($OPT_ELAPSED_TIME, "\x00\x00"); # add IA_NA for each interface (required by DOCSIS and RFC 3315) # XXX: should this be a single interface only? my $iaid = 0; foreach my $iface (dhcp_client::iface()) { my $option_data = pack("NNN", ++$iaid, 0, 0); $msg->add_option($OPT_IA_NA, $option_data); } # add Reconfigure Accept (required by DOCSIS) $msg->add_option($OPT_RECONF_ACCEPT, ""); # add Options Request (required by DOCSIS, recommended by RFC 3315) my @oro = ( $OPT_TIME_SERVERS, $OPT_TIME_OFFSET ); $msg->add_option($OPT_ORO, pack("n*", @oro)); # add Vendor Class option (required by DOCSIS) $msg->add_option($OPT_VENDOR_CLASS, pack("N", 4491) . "docsis3.0"); # add Vendor-specific Information Option option (required by DOCSIS) my $vsio = pack("N", 4491); # ORO (required by DOCSIS) my @docsis_oro = ( $DOCSIS_OPT_TFTP_SERVERS ); $vsio .= pack("nnC*", $DOCSIS_OPT_ORO, 0+@docsis_oro, @docsis_oro); # TLV5 data: CMTS DOCSIS version number 3.0 (required by DOCSIS) my $tlv5_data = "\x01\x02\x03\x0"; $vsio .= pack("nn", $DOCSIS_OPT_TLV5, length($tlv5_data)) . $tlv5_data; # DOCSIS Device (required by DOCSIS) my $docsis_device_id = dhcp_client::mac_addr_binary(); $vsio .= pack("nn", $DOCSIS_OPT_DEVICE_ID, length($docsis_device_id)); $vsio .= $docsis_device_id; $msg->add_option($OPT_VENDOR_OPTS, $vsio); # add Rapid Commit option (required by DOCSIS) $msg->add_option($OPT_RAPID_COMMIT, ""); # timeout parameters, from DOCSIS my $IRT = $SOL_TIMEOUT; my $MRT = $SOL_MAX_RT; my $MRC = 4; # DOCSIS says 4, RFC 3315 says it SHOULD be 0 my $MRD = 0; # sleep a random amount of time between 0 and 1 second, required by RFC 3315 # XXX: this seems pretty stupid sleep(rand($SOL_MAX_DELAY)); my $RT; my $count = 0; my $mrd_end_time; if ($MRD != 0) { $mrd_end_time = time() + $MRD; } my $reply_msg; do { # create our socket, and send our Solicit socket(SOCK, PF_INET6, SOCK_DGRAM, getprotobyname('udp')) || die; my $addr = inet_pton(AF_INET6, $All_DHCP_Servers); my $packet = $msg->packet(); my $send_ret = send(SOCK, $packet, 0, pack_sockaddr_in6($server_port, $addr)); if (not defined($send_ret)) { printf STDERR "Error \%d sending DHCPv6 Solicit message;\n\%s\n", 0+$ERRNO, $ERRNO; exit(1); } elsif ($send_ret != length($packet)) { print STDERR "Unable to send entire DHCPv6 Solicit message.\n"; exit(1); } $count++; my $RAND = rand(0.2) - 0.1; if (defined $RT) { $RT = 2*$RT + $RAND*$RT; if (($RT > $MRT) && ($MRT != 0)) { $RT = $MRT + $RAND*$RT; } } else { $RT = $IRT + $RAND*$IRT; } my $rt_end_time = time() + $RT; if (defined($mrd_end_time) && ($mrd_end_time > $rt_end_time)) { $rt_end_time = $mrd_end_time; } for (;;) { my $timeout = $rt_end_time - time(); if ($timeout < 0) { # print STDERR "Timeout waiting for DHCPv6 Advertise ", # "or Reply message.\n"; last; } my @ready = IO::Select->new(\*SOCK)->can_read($timeout); if (@ready) { my $reply; my $recv_ret; $recv_ret = recv(SOCK, $reply, 1500, 0); if (not defined $recv_ret) { printf STDERR "Error \%d receiving DHCPv6 " . "message;\n\%s\n", 0+$ERRNO, $ERRNO; exit(1); } $reply_msg = dhcp_client::msg::decode($reply, 1); if (($reply_msg->{msg_type} == $MSG_ADVERTISE) || ($reply_msg->{msg_type} == $MSG_REPLY)) { last; } } } } until ($reply_msg || (($MRC != 0) && ($count > $MRC)) || (defined($mrd_end_time) && ($mrd_end_time > time()))); unless ($reply_msg) { if (($MRC != 0) && ($count >= $MRC)) { print STDERR "No reply after maximum retransmission count.\n"; } else { print STDERR "No reply after maximum retransmission duration.\n"; } } if ($reply_msg && ($reply_msg->{msg_type} == $MSG_REPLY)) { print "Got DHCPv6 Reply message.\n"; exit(0); } #$Data::Dumper::Useqq = 1; #print Dumper($msg), "\n"; #print Dumper($msg->packet()), "\n"; # #print "packet length: ", length($msg->packet()), "\n"; dhcp-4.2.4/tests/DHCPv6/211-solicit-opt-in-na.pl000644 000765 000024 00000014041 11301372617 020630 0ustar00sarstaff000000 000000 #! /usr/bin/perl -w # Copyright (c) 2007,2009 by Internet Systems Consortium, Inc. ("ISC") # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # # Internet Systems Consortium, Inc. # 950 Charter Street # Redwood City, CA 94063 # # https://www.isc.org/ use strict; use English; use Time::HiRes qw( sleep ); use Socket; use Socket6; use IO::Select; use dhcp_client; # XXX: for debugging use Data::Dumper; $Data::Dumper::Useqq = 1; # not-yet-standard options my $OPT_TIME_SERVERS = 40; my $OPT_TIME_OFFSET = 41; # DOCSIS sub-options my $DOCSIS_OPT_ORO = 1; # 2 to 31 are reserved my $DOCSIS_OPT_TFTP_SERVERS = 32; my $DOCSIS_OPT_CONFIG_FILE_NAME = 33; my $DOCSIS_OPT_SYSLOG_SERVERS = 34; my $DOCSIS_OPT_TLV5 = 35; my $DOCSIS_OPT_DEVICE_ID = 36; my $DOCSIS_OPT_CCC = 37; my $DOCSIS_OPT_VERS = 38; # well-known addresses my $All_DHCP_Relay_Agents_and_Servers = "ff02::1:2"; my $All_DHCP_Servers = "ff05::1:3"; # ports my $client_port = 546; my $server_port = 547; # create a new Solicit message my $msg = dhcp_client::msg->new($MSG_SOLICIT); # add the Client Identifier (required by DOCSIS and RFC 3315) my $client_id = "\x00\x01\x00\x01\x0c\x00\xa1\x41\x00\x06\x5b\x50\x99\xf6"; #my $client_id = dhcp_client::duid(3); $msg->add_option($OPT_CLIENTID, $client_id); #$msg->add_option($OPT_CLIENTID, dhcp_client::duid(3)); # add Elapsed Time, set to 0 on first packet (required by RFC 3315) $msg->add_option($OPT_ELAPSED_TIME, "\x00\x00"); # add IA_NA for each interface (required by DOCSIS and RFC 3315) # XXX: should this be a single interface only? my $iaid = 0; foreach my $iface (dhcp_client::iface()) { my $option_data = pack("NNN", ++$iaid, 0, 0); my $enc_opt = dhcp_client::msg->new(0); $enc_opt->add_option($OPT_CLIENTID, $client_id); $option_data .= $enc_opt->packed_options(); $msg->add_option($OPT_IA_NA, $option_data); } # add Reconfigure Accept (required by DOCSIS) $msg->add_option($OPT_RECONF_ACCEPT, ""); # add Options Request (required by DOCSIS, recommended by RFC 3315) my @oro = ( $OPT_TIME_SERVERS, $OPT_TIME_OFFSET ); $msg->add_option($OPT_ORO, pack("n*", @oro)); # add Vendor Class option (required by DOCSIS) $msg->add_option($OPT_VENDOR_CLASS, pack("N", 4491) . "docsis3.0"); # add Vendor-specific Information Option option (required by DOCSIS) my $vsio = pack("N", 4491); # ORO (required by DOCSIS) my @docsis_oro = ( $DOCSIS_OPT_TFTP_SERVERS ); $vsio .= pack("nnC*", $DOCSIS_OPT_ORO, 0+@docsis_oro, @docsis_oro); # TLV5 data: CMTS DOCSIS version number 3.0 (required by DOCSIS) my $tlv5_data = "\x01\x02\x03\x0"; $vsio .= pack("nn", $DOCSIS_OPT_TLV5, length($tlv5_data)) . $tlv5_data; # DOCSIS Device (required by DOCSIS) my $docsis_device_id = dhcp_client::mac_addr_binary(); $vsio .= pack("nn", $DOCSIS_OPT_DEVICE_ID, length($docsis_device_id)); $vsio .= $docsis_device_id; $msg->add_option($OPT_VENDOR_OPTS, $vsio); # add Rapid Commit option (required by DOCSIS) $msg->add_option($OPT_RAPID_COMMIT, ""); # timeout parameters, from DOCSIS my $IRT = $SOL_TIMEOUT; my $MRT = $SOL_MAX_RT; my $MRC = 4; # DOCSIS says 4, RFC 3315 says it SHOULD be 0 my $MRD = 0; # sleep a random amount of time between 0 and 1 second, required by RFC 3315 # XXX: this seems pretty stupid sleep(rand($SOL_MAX_DELAY)); my $RT; my $count = 0; my $mrd_end_time; if ($MRD != 0) { $mrd_end_time = time() + $MRD; } my $reply_msg; do { # create our socket, and send our Solicit socket(SOCK, PF_INET6, SOCK_DGRAM, getprotobyname('udp')) || die; my $addr = inet_pton(AF_INET6, $All_DHCP_Servers); my $packet = $msg->packet(); my $send_ret = send(SOCK, $packet, 0, pack_sockaddr_in6($server_port, $addr)); if (not defined($send_ret)) { printf STDERR "Error \%d sending DHCPv6 Solicit message;\n\%s\n", 0+$ERRNO, $ERRNO; exit(1); } elsif ($send_ret != length($packet)) { print STDERR "Unable to send entire DHCPv6 Solicit message.\n"; exit(1); } $count++; my $RAND = rand(0.2) - 0.1; if (defined $RT) { $RT = 2*$RT + $RAND*$RT; if (($RT > $MRT) && ($MRT != 0)) { $RT = $MRT + $RAND*$RT; } } else { $RT = $IRT + $RAND*$IRT; } my $rt_end_time = time() + $RT; if (defined($mrd_end_time) && ($mrd_end_time > $rt_end_time)) { $rt_end_time = $mrd_end_time; } for (;;) { my $timeout = $rt_end_time - time(); if ($timeout < 0) { # print STDERR "Timeout waiting for DHCPv6 Advertise ", # "or Reply message.\n"; last; } my @ready = IO::Select->new(\*SOCK)->can_read($timeout); if (@ready) { my $reply; my $recv_ret; $recv_ret = recv(SOCK, $reply, 1500, 0); if (not defined $recv_ret) { printf STDERR "Error \%d receiving DHCPv6 " . "message;\n\%s\n", 0+$ERRNO, $ERRNO; exit(1); } $reply_msg = dhcp_client::msg::decode($reply, 1); if (($reply_msg->{msg_type} == $MSG_ADVERTISE) || ($reply_msg->{msg_type} == $MSG_REPLY)) { last; } } } } until ($reply_msg || (($MRC != 0) && ($count > $MRC)) || (defined($mrd_end_time) && ($mrd_end_time > time()))); unless ($reply_msg) { if (($MRC != 0) && ($count >= $MRC)) { print STDERR "No reply after maximum retransmission count.\n"; } else { print STDERR "No reply after maximum retransmission duration.\n"; } } if ($reply_msg && ($reply_msg->{msg_type} == $MSG_REPLY)) { print "Got DHCPv6 Reply message.\n"; #print Dumper($reply_msg), "\n"; exit(0); } #print Dumper($msg), "\n"; #print Dumper($msg->packet()), "\n"; # #print "packet length: ", length($msg->packet()), "\n"; dhcp-4.2.4/tests/DHCPv6/212-solicit-opt-in-na-norapidcommit.pl000644 000765 000024 00000014042 11301372617 023475 0ustar00sarstaff000000 000000 #! /usr/bin/perl -w # Copyright (c) 2007,2009 by Internet Systems Consortium, Inc. ("ISC") # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # # Internet Systems Consortium, Inc. # 950 Charter Street # Redwood City, CA 94063 # # https://www.isc.org/ use strict; use English; use Time::HiRes qw( sleep ); use Socket; use Socket6; use IO::Select; use dhcp_client; # XXX: for debugging use Data::Dumper; $Data::Dumper::Useqq = 1; # not-yet-standard options my $OPT_TIME_SERVERS = 40; my $OPT_TIME_OFFSET = 41; # DOCSIS sub-options my $DOCSIS_OPT_ORO = 1; # 2 to 31 are reserved my $DOCSIS_OPT_TFTP_SERVERS = 32; my $DOCSIS_OPT_CONFIG_FILE_NAME = 33; my $DOCSIS_OPT_SYSLOG_SERVERS = 34; my $DOCSIS_OPT_TLV5 = 35; my $DOCSIS_OPT_DEVICE_ID = 36; my $DOCSIS_OPT_CCC = 37; my $DOCSIS_OPT_VERS = 38; # well-known addresses my $All_DHCP_Relay_Agents_and_Servers = "ff02::1:2"; my $All_DHCP_Servers = "ff05::1:3"; # ports my $client_port = 546; my $server_port = 547; # create a new Solicit message my $msg = dhcp_client::msg->new($MSG_SOLICIT); # add the Client Identifier (required by DOCSIS and RFC 3315) my $client_id = "\x00\x01\x00\x01\x0c\x00\xa1\x41\x00\x06\x5b\x50\x99\xf6"; #my $client_id = dhcp_client::duid(3); $msg->add_option($OPT_CLIENTID, $client_id); #$msg->add_option($OPT_CLIENTID, dhcp_client::duid(3)); # add Elapsed Time, set to 0 on first packet (required by RFC 3315) $msg->add_option($OPT_ELAPSED_TIME, "\x00\x00"); # add IA_NA for each interface (required by DOCSIS and RFC 3315) # XXX: should this be a single interface only? my $iaid = 0; foreach my $iface (dhcp_client::iface()) { my $option_data = pack("NNN", ++$iaid, 0, 0); my $enc_opt = dhcp_client::msg->new(0); $enc_opt->add_option($OPT_CLIENTID, $client_id); $option_data .= $enc_opt->packed_options(); $msg->add_option($OPT_IA_NA, $option_data); } # add Reconfigure Accept (required by DOCSIS) $msg->add_option($OPT_RECONF_ACCEPT, ""); # add Options Request (required by DOCSIS, recommended by RFC 3315) my @oro = ( $OPT_TIME_SERVERS, $OPT_TIME_OFFSET ); $msg->add_option($OPT_ORO, pack("n*", @oro)); # add Vendor Class option (required by DOCSIS) $msg->add_option($OPT_VENDOR_CLASS, pack("N", 4491) . "docsis3.0"); # add Vendor-specific Information Option option (required by DOCSIS) my $vsio = pack("N", 4491); # ORO (required by DOCSIS) my @docsis_oro = ( $DOCSIS_OPT_TFTP_SERVERS ); $vsio .= pack("nnC*", $DOCSIS_OPT_ORO, 0+@docsis_oro, @docsis_oro); # TLV5 data: CMTS DOCSIS version number 3.0 (required by DOCSIS) my $tlv5_data = "\x01\x02\x03\x0"; $vsio .= pack("nn", $DOCSIS_OPT_TLV5, length($tlv5_data)) . $tlv5_data; # DOCSIS Device (required by DOCSIS) my $docsis_device_id = dhcp_client::mac_addr_binary(); $vsio .= pack("nn", $DOCSIS_OPT_DEVICE_ID, length($docsis_device_id)); $vsio .= $docsis_device_id; $msg->add_option($OPT_VENDOR_OPTS, $vsio); # add Rapid Commit option (required by DOCSIS) #$msg->add_option($OPT_RAPID_COMMIT, ""); # timeout parameters, from DOCSIS my $IRT = $SOL_TIMEOUT; my $MRT = $SOL_MAX_RT; my $MRC = 4; # DOCSIS says 4, RFC 3315 says it SHOULD be 0 my $MRD = 0; # sleep a random amount of time between 0 and 1 second, required by RFC 3315 # XXX: this seems pretty stupid sleep(rand($SOL_MAX_DELAY)); my $RT; my $count = 0; my $mrd_end_time; if ($MRD != 0) { $mrd_end_time = time() + $MRD; } my $reply_msg; do { # create our socket, and send our Solicit socket(SOCK, PF_INET6, SOCK_DGRAM, getprotobyname('udp')) || die; my $addr = inet_pton(AF_INET6, $All_DHCP_Servers); my $packet = $msg->packet(); my $send_ret = send(SOCK, $packet, 0, pack_sockaddr_in6($server_port, $addr)); if (not defined($send_ret)) { printf STDERR "Error \%d sending DHCPv6 Solicit message;\n\%s\n", 0+$ERRNO, $ERRNO; exit(1); } elsif ($send_ret != length($packet)) { print STDERR "Unable to send entire DHCPv6 Solicit message.\n"; exit(1); } $count++; my $RAND = rand(0.2) - 0.1; if (defined $RT) { $RT = 2*$RT + $RAND*$RT; if (($RT > $MRT) && ($MRT != 0)) { $RT = $MRT + $RAND*$RT; } } else { $RT = $IRT + $RAND*$IRT; } my $rt_end_time = time() + $RT; if (defined($mrd_end_time) && ($mrd_end_time > $rt_end_time)) { $rt_end_time = $mrd_end_time; } for (;;) { my $timeout = $rt_end_time - time(); if ($timeout < 0) { # print STDERR "Timeout waiting for DHCPv6 Advertise ", # "or Reply message.\n"; last; } my @ready = IO::Select->new(\*SOCK)->can_read($timeout); if (@ready) { my $reply; my $recv_ret; $recv_ret = recv(SOCK, $reply, 1500, 0); if (not defined $recv_ret) { printf STDERR "Error \%d receiving DHCPv6 " . "message;\n\%s\n", 0+$ERRNO, $ERRNO; exit(1); } $reply_msg = dhcp_client::msg::decode($reply, 1); if (($reply_msg->{msg_type} == $MSG_ADVERTISE) || ($reply_msg->{msg_type} == $MSG_REPLY)) { last; } } } } until ($reply_msg || (($MRC != 0) && ($count > $MRC)) || (defined($mrd_end_time) && ($mrd_end_time > time()))); unless ($reply_msg) { if (($MRC != 0) && ($count >= $MRC)) { print STDERR "No reply after maximum retransmission count.\n"; } else { print STDERR "No reply after maximum retransmission duration.\n"; } } if ($reply_msg && ($reply_msg->{msg_type} == $MSG_REPLY)) { print "Got DHCPv6 Reply message.\n"; #print Dumper($reply_msg), "\n"; exit(0); } #print Dumper($msg), "\n"; #print Dumper($msg->packet()), "\n"; # #print "packet length: ", length($msg->packet()), "\n"; dhcp-4.2.4/tests/DHCPv6/280-release-nohost.pl000644 000765 000024 00000010707 11301372617 020325 0ustar00sarstaff000000 000000 #! /usr/bin/perl -w # Copyright (c) 2007,2009 by Internet Systems Consortium, Inc. ("ISC") # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # # Internet Systems Consortium, Inc. # 950 Charter Street # Redwood City, CA 94063 # # https://www.isc.org/ use strict; use English; use Time::HiRes qw( sleep ); use Socket; use Socket6; use IO::Select; use dhcp_client; # XXX: for debugging use Data::Dumper; # not-yet-standard options my $OPT_TIME_SERVERS = 40; my $OPT_TIME_OFFSET = 41; # DOCSIS sub-options my $DOCSIS_OPT_ORO = 1; # 2 to 31 are reserved my $DOCSIS_OPT_TFTP_SERVERS = 32; my $DOCSIS_OPT_CONFIG_FILE_NAME = 33; my $DOCSIS_OPT_SYSLOG_SERVERS = 34; my $DOCSIS_OPT_TLV5 = 35; my $DOCSIS_OPT_DEVICE_ID = 36; my $DOCSIS_OPT_CCC = 37; my $DOCSIS_OPT_VERS = 38; # well-known addresses my $All_DHCP_Relay_Agents_and_Servers = "ff02::1:2"; my $All_DHCP_Servers = "ff05::1:3"; # ports my $client_port = 546; my $server_port = 547; # create a new message my $msg = dhcp_client::msg->new($MSG_RELEASE); # add the Client Identifier (required by DOCSIS and RFC 3315) $msg->add_option($OPT_CLIENTID, dhcp_client::duid()); # add the Server identifier (required by RFC 3315) $msg->add_option($OPT_SERVERID, "InfiniteEntropy"); # add Elapsed Time, set to 0 on first packet (required by RFC 3315) $msg->add_option($OPT_ELAPSED_TIME, "\x00\x00"); # timeout parameters, from DOCSIS my $IRT = $SOL_TIMEOUT; my $MRT = $SOL_MAX_RT; my $MRC = 4; # DOCSIS says 4, RFC 3315 says it SHOULD be 0 my $MRD = 0; # sleep a random amount of time between 0 and 1 second, required by RFC 3315 # XXX: this seems pretty stupid sleep(rand($SOL_MAX_DELAY)); my $RT; my $count = 0; my $mrd_end_time; if ($MRD != 0) { $mrd_end_time = time() + $MRD; } my $reply_msg; do { # create our socket, and send our message socket(SOCK, PF_INET6, SOCK_DGRAM, getprotobyname('udp')) || die; my $addr = inet_pton(AF_INET6, $All_DHCP_Servers); my $packet = $msg->packet(); my $send_ret = send(SOCK, $packet, 0, pack_sockaddr_in6($server_port, $addr)); if (not defined($send_ret)) { printf STDERR "Error \%d sending DHCPv6 message;\n\%s\n", 0+$ERRNO, $ERRNO; exit(1); } elsif ($send_ret != length($packet)) { print STDERR "Unable to send entire DHCPv6 message.\n"; exit(1); } $count++; my $RAND = rand(0.2) - 0.1; if (defined $RT) { $RT = 2*$RT + $RAND*$RT; if (($RT > $MRT) && ($MRT != 0)) { $RT = $MRT + $RAND*$RT; } } else { $RT = $IRT + $RAND*$IRT; } my $rt_end_time = time() + $RT; if (defined($mrd_end_time) && ($mrd_end_time > $rt_end_time)) { $rt_end_time = $mrd_end_time; } for (;;) { my $timeout = $rt_end_time - time(); if ($timeout < 0) { # print STDERR "Timeout waiting for DHCPv6 Advertise ", # "or Reply message.\n"; last; } my @ready = IO::Select->new(\*SOCK)->can_read($timeout); if (@ready) { my $reply; my $recv_ret; $recv_ret = recv(SOCK, $reply, 1500, 0); if (not defined $recv_ret) { printf STDERR "Error \%d receiving DHCPv6 " . "message;\n\%s\n", 0+$ERRNO, $ERRNO; exit(1); } $reply_msg = dhcp_client::msg::decode($reply, 1); if (($reply_msg->{msg_type} == $MSG_ADVERTISE) || ($reply_msg->{msg_type} == $MSG_REPLY)) { last; } } } } until ($reply_msg || (($MRC != 0) && ($count > $MRC)) || (defined($mrd_end_time) && ($mrd_end_time > time()))); unless ($reply_msg) { if (($MRC != 0) && ($count >= $MRC)) { print STDERR "No reply after maximum retransmission count.\n"; } else { print STDERR "No reply after maximum retransmission duration.\n"; } } if ($reply_msg && ($reply_msg->{msg_type} == $MSG_REPLY)) { print "Got DHCPv6 Reply message.\n"; exit(0); } #$Data::Dumper::Useqq = 1; #print Dumper($msg), "\n"; #print Dumper($msg->packet()), "\n"; # #print "packet length: ", length($msg->packet()), "\n"; dhcp-4.2.4/tests/DHCPv6/281-release-bad-address.pl000644 000765 000024 00000011650 11301372617 021163 0ustar00sarstaff000000 000000 #! /usr/bin/perl -w # Copyright (c) 2007,2009 by Internet Systems Consortium, Inc. ("ISC") # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # # Internet Systems Consortium, Inc. # 950 Charter Street # Redwood City, CA 94063 # # https://www.isc.org/ use strict; use English; use Time::HiRes qw( sleep ); use Socket; use Socket6; use IO::Select; use dhcp_client; # XXX: for debugging use Data::Dumper; # not-yet-standard options my $OPT_TIME_SERVERS = 40; my $OPT_TIME_OFFSET = 41; # DOCSIS sub-options my $DOCSIS_OPT_ORO = 1; # 2 to 31 are reserved my $DOCSIS_OPT_TFTP_SERVERS = 32; my $DOCSIS_OPT_CONFIG_FILE_NAME = 33; my $DOCSIS_OPT_SYSLOG_SERVERS = 34; my $DOCSIS_OPT_TLV5 = 35; my $DOCSIS_OPT_DEVICE_ID = 36; my $DOCSIS_OPT_CCC = 37; my $DOCSIS_OPT_VERS = 38; # well-known addresses my $All_DHCP_Relay_Agents_and_Servers = "ff02::1:2"; my $All_DHCP_Servers = "ff05::1:3"; # ports my $client_port = 546; my $server_port = 547; # create a new Solicit message my $msg = dhcp_client::msg->new($MSG_RELEASE); # add the Client Identifier (required by DOCSIS and RFC 3315) $msg->add_option($OPT_CLIENTID, dhcp_client::duid()); # add the Server identifier (required by RFC 3315) $msg->add_option($OPT_SERVERID, "InfiniteEntropy"); # add Elapsed Time, set to 0 on first packet (required by RFC 3315) $msg->add_option($OPT_ELAPSED_TIME, "\x00\x00"); # add IA_NA for each interface (required by DOCSIS and RFC 3315) # XXX: should this be a single interface only? my $iaid = 0; foreach my $iface (dhcp_client::iface()) { my $iaaddr_option = inet_pton(AF_INET6, "1:2:3:4::"); $iaaddr_option .= pack("NN", 0, 0); my $option_data = pack("NNN", ++$iaid, 0, 0); $option_data .= pack("nn", $OPT_IAADDR, length($iaaddr_option)-8); $option_data .= $iaaddr_option; $msg->add_option($OPT_IA_NA, $option_data); } # timeout parameters, from DOCSIS my $IRT = $SOL_TIMEOUT; my $MRT = $SOL_MAX_RT; my $MRC = 4; # DOCSIS says 4, RFC 3315 says it SHOULD be 0 my $MRD = 0; # sleep a random amount of time between 0 and 1 second, required by RFC 3315 # XXX: this seems pretty stupid sleep(rand($SOL_MAX_DELAY)); my $RT; my $count = 0; my $mrd_end_time; if ($MRD != 0) { $mrd_end_time = time() + $MRD; } my $reply_msg; do { # create our socket, and send our Solicit socket(SOCK, PF_INET6, SOCK_DGRAM, getprotobyname('udp')) || die; my $addr = inet_pton(AF_INET6, $All_DHCP_Servers); my $packet = $msg->packet(); my $send_ret = send(SOCK, $packet, 0, pack_sockaddr_in6($server_port, $addr)); if (not defined($send_ret)) { printf STDERR "Error \%d sending DHCPv6 Solicit message;\n\%s\n", 0+$ERRNO, $ERRNO; exit(1); } elsif ($send_ret != length($packet)) { print STDERR "Unable to send entire DHCPv6 Solicit message.\n"; exit(1); } $count++; my $RAND = rand(0.2) - 0.1; if (defined $RT) { $RT = 2*$RT + $RAND*$RT; if (($RT > $MRT) && ($MRT != 0)) { $RT = $MRT + $RAND*$RT; } } else { $RT = $IRT + $RAND*$IRT; } my $rt_end_time = time() + $RT; if (defined($mrd_end_time) && ($mrd_end_time > $rt_end_time)) { $rt_end_time = $mrd_end_time; } for (;;) { my $timeout = $rt_end_time - time(); if ($timeout < 0) { # print STDERR "Timeout waiting for DHCPv6 Advertise ", # "or Reply message.\n"; last; } my @ready = IO::Select->new(\*SOCK)->can_read($timeout); if (@ready) { my $reply; my $recv_ret; $recv_ret = recv(SOCK, $reply, 1500, 0); if (not defined $recv_ret) { printf STDERR "Error \%d receiving DHCPv6 " . "message;\n\%s\n", 0+$ERRNO, $ERRNO; exit(1); } $reply_msg = dhcp_client::msg::decode($reply, 1); if (($reply_msg->{msg_type} == $MSG_ADVERTISE) || ($reply_msg->{msg_type} == $MSG_REPLY)) { last; } } } } until ($reply_msg || (($MRC != 0) && ($count > $MRC)) || (defined($mrd_end_time) && ($mrd_end_time > time()))); unless ($reply_msg) { if (($MRC != 0) && ($count >= $MRC)) { print STDERR "No reply after maximum retransmission count.\n"; } else { print STDERR "No reply after maximum retransmission duration.\n"; } } if ($reply_msg && ($reply_msg->{msg_type} == $MSG_REPLY)) { print "Got DHCPv6 Reply message.\n"; exit(0); } #$Data::Dumper::Useqq = 1; #print Dumper($msg), "\n"; #print Dumper($msg->packet()), "\n"; # #print "packet length: ", length($msg->packet()), "\n"; dhcp-4.2.4/tests/DHCPv6/282-release-no-address.pl000644 000765 000024 00000011347 11301372617 021055 0ustar00sarstaff000000 000000 #! /usr/bin/perl -w # Copyright (c) 2007,2009 by Internet Systems Consortium, Inc. ("ISC") # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # # Internet Systems Consortium, Inc. # 950 Charter Street # Redwood City, CA 94063 # # https://www.isc.org/ use strict; use English; use Time::HiRes qw( sleep ); use Socket; use Socket6; use IO::Select; use dhcp_client; # XXX: for debugging use Data::Dumper; # not-yet-standard options my $OPT_TIME_SERVERS = 40; my $OPT_TIME_OFFSET = 41; # DOCSIS sub-options my $DOCSIS_OPT_ORO = 1; # 2 to 31 are reserved my $DOCSIS_OPT_TFTP_SERVERS = 32; my $DOCSIS_OPT_CONFIG_FILE_NAME = 33; my $DOCSIS_OPT_SYSLOG_SERVERS = 34; my $DOCSIS_OPT_TLV5 = 35; my $DOCSIS_OPT_DEVICE_ID = 36; my $DOCSIS_OPT_CCC = 37; my $DOCSIS_OPT_VERS = 38; # well-known addresses my $All_DHCP_Relay_Agents_and_Servers = "ff02::1:2"; my $All_DHCP_Servers = "ff05::1:3"; # ports my $client_port = 546; my $server_port = 547; # create a new Solicit message my $msg = dhcp_client::msg->new($MSG_RELEASE); # add the Client Identifier (required by DOCSIS and RFC 3315) $msg->add_option($OPT_CLIENTID, dhcp_client::duid()); # add the Server identifier (required by RFC 3315) $msg->add_option($OPT_SERVERID, "InfiniteEntropy"); # add Elapsed Time, set to 0 on first packet (required by RFC 3315) $msg->add_option($OPT_ELAPSED_TIME, "\x00\x00"); # add IA_NA for each interface (required by DOCSIS and RFC 3315) # XXX: should this be a single interface only? my $iaid = 0; foreach my $iface (dhcp_client::iface()) { my $option_data = pack("NNN", ++$iaid, 0, 0); $msg->add_option($OPT_IA_NA, $option_data); } # timeout parameters, from DOCSIS my $IRT = $SOL_TIMEOUT; my $MRT = $SOL_MAX_RT; my $MRC = 4; # DOCSIS says 4, RFC 3315 says it SHOULD be 0 my $MRD = 0; # sleep a random amount of time between 0 and 1 second, required by RFC 3315 # XXX: this seems pretty stupid sleep(rand($SOL_MAX_DELAY)); my $RT; my $count = 0; my $mrd_end_time; if ($MRD != 0) { $mrd_end_time = time() + $MRD; } my $reply_msg; do { # create our socket, and send our Solicit socket(SOCK, PF_INET6, SOCK_DGRAM, getprotobyname('udp')) || die; my $addr = inet_pton(AF_INET6, $All_DHCP_Servers); my $packet = $msg->packet(); my $send_ret = send(SOCK, $packet, 0, pack_sockaddr_in6($server_port, $addr)); if (not defined($send_ret)) { printf STDERR "Error \%d sending DHCPv6 Solicit message;\n\%s\n", 0+$ERRNO, $ERRNO; exit(1); } elsif ($send_ret != length($packet)) { print STDERR "Unable to send entire DHCPv6 Solicit message.\n"; exit(1); } $count++; my $RAND = rand(0.2) - 0.1; if (defined $RT) { $RT = 2*$RT + $RAND*$RT; if (($RT > $MRT) && ($MRT != 0)) { $RT = $MRT + $RAND*$RT; } } else { $RT = $IRT + $RAND*$IRT; } my $rt_end_time = time() + $RT; if (defined($mrd_end_time) && ($mrd_end_time > $rt_end_time)) { $rt_end_time = $mrd_end_time; } for (;;) { my $timeout = $rt_end_time - time(); if ($timeout < 0) { # print STDERR "Timeout waiting for DHCPv6 Advertise ", # "or Reply message.\n"; last; } my @ready = IO::Select->new(\*SOCK)->can_read($timeout); if (@ready) { my $reply; my $recv_ret; $recv_ret = recv(SOCK, $reply, 1500, 0); if (not defined $recv_ret) { printf STDERR "Error \%d receiving DHCPv6 " . "message;\n\%s\n", 0+$ERRNO, $ERRNO; exit(1); } $reply_msg = dhcp_client::msg::decode($reply, 1); if (($reply_msg->{msg_type} == $MSG_ADVERTISE) || ($reply_msg->{msg_type} == $MSG_REPLY)) { last; } } } } until ($reply_msg || (($MRC != 0) && ($count > $MRC)) || (defined($mrd_end_time) && ($mrd_end_time > time()))); unless ($reply_msg) { if (($MRC != 0) && ($count >= $MRC)) { print STDERR "No reply after maximum retransmission count.\n"; } else { print STDERR "No reply after maximum retransmission duration.\n"; } } if ($reply_msg && ($reply_msg->{msg_type} == $MSG_REPLY)) { print "Got DHCPv6 Reply message.\n"; exit(0); } #$Data::Dumper::Useqq = 1; #print Dumper($msg), "\n"; #print Dumper($msg->packet()), "\n"; # #print "packet length: ", length($msg->packet()), "\n"; dhcp-4.2.4/tests/DHCPv6/283-release.pl000644 000765 000024 00000012135 11301372617 017015 0ustar00sarstaff000000 000000 #! /usr/bin/perl -w # Copyright (c) 2007,2009 by Internet Systems Consortium, Inc. ("ISC") # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # # Internet Systems Consortium, Inc. # 950 Charter Street # Redwood City, CA 94063 # # https://www.isc.org/ use strict; use English; use Time::HiRes qw( sleep ); use Socket; use Socket6; use IO::Select; use dhcp_client; # XXX: for debugging use Data::Dumper; # not-yet-standard options my $OPT_TIME_SERVERS = 40; my $OPT_TIME_OFFSET = 41; # DOCSIS sub-options my $DOCSIS_OPT_ORO = 1; # 2 to 31 are reserved my $DOCSIS_OPT_TFTP_SERVERS = 32; my $DOCSIS_OPT_CONFIG_FILE_NAME = 33; my $DOCSIS_OPT_SYSLOG_SERVERS = 34; my $DOCSIS_OPT_TLV5 = 35; my $DOCSIS_OPT_DEVICE_ID = 36; my $DOCSIS_OPT_CCC = 37; my $DOCSIS_OPT_VERS = 38; # well-known addresses my $All_DHCP_Relay_Agents_and_Servers = "ff02::1:2"; my $All_DHCP_Servers = "ff05::1:3"; # ports my $client_port = 546; my $server_port = 547; # create a new Solicit message my $msg = dhcp_client::msg->new($MSG_RELEASE); # add the Client Identifier (required by DOCSIS and RFC 3315) my $client_id = "\x00\x01\x00\x01\x0c\x00\xa1\x41\x00\x06\x5b\x50\x99\xf6"; $msg->add_option($OPT_CLIENTID, $client_id); #$msg->add_option($OPT_CLIENTID, dhcp_client::duid(3)); # add the Server identifier (required by RFC 3315) $msg->add_option($OPT_SERVERID, "InfiniteEntropy"); # add Elapsed Time, set to 0 on first packet (required by RFC 3315) $msg->add_option($OPT_ELAPSED_TIME, "\x00\x00"); # add IA_NA for each interface (required by DOCSIS and RFC 3315) # XXX: should this be a single interface only? my $iaid = 0; foreach my $iface (dhcp_client::iface()) { my $iaaddr_option = inet_pton(AF_INET6, "3ffe:aaaa:aaaa:aaaa::ffff"); $iaaddr_option .= pack("NN", 0, 0); my $option_data = pack("NNN", ++$iaid, 0, 0); $option_data .= pack("nn", $OPT_IAADDR, length($iaaddr_option)-8); $option_data .= $iaaddr_option; $msg->add_option($OPT_IA_NA, $option_data); } # timeout parameters, from DOCSIS my $IRT = $SOL_TIMEOUT; my $MRT = $SOL_MAX_RT; my $MRC = 4; # DOCSIS says 4, RFC 3315 says it SHOULD be 0 my $MRD = 0; # sleep a random amount of time between 0 and 1 second, required by RFC 3315 # XXX: this seems pretty stupid sleep(rand($SOL_MAX_DELAY)); my $RT; my $count = 0; my $mrd_end_time; if ($MRD != 0) { $mrd_end_time = time() + $MRD; } my $reply_msg; do { # create our socket, and send our Solicit socket(SOCK, PF_INET6, SOCK_DGRAM, getprotobyname('udp')) || die; my $addr = inet_pton(AF_INET6, $All_DHCP_Servers); my $packet = $msg->packet(); my $send_ret = send(SOCK, $packet, 0, pack_sockaddr_in6($server_port, $addr)); if (not defined($send_ret)) { printf STDERR "Error \%d sending DHCPv6 Solicit message;\n\%s\n", 0+$ERRNO, $ERRNO; exit(1); } elsif ($send_ret != length($packet)) { print STDERR "Unable to send entire DHCPv6 Solicit message.\n"; exit(1); } $count++; my $RAND = rand(0.2) - 0.1; if (defined $RT) { $RT = 2*$RT + $RAND*$RT; if (($RT > $MRT) && ($MRT != 0)) { $RT = $MRT + $RAND*$RT; } } else { $RT = $IRT + $RAND*$IRT; } my $rt_end_time = time() + $RT; if (defined($mrd_end_time) && ($mrd_end_time > $rt_end_time)) { $rt_end_time = $mrd_end_time; } for (;;) { my $timeout = $rt_end_time - time(); if ($timeout < 0) { # print STDERR "Timeout waiting for DHCPv6 Advertise ", # "or Reply message.\n"; last; } my @ready = IO::Select->new(\*SOCK)->can_read($timeout); if (@ready) { my $reply; my $recv_ret; $recv_ret = recv(SOCK, $reply, 1500, 0); if (not defined $recv_ret) { printf STDERR "Error \%d receiving DHCPv6 " . "message;\n\%s\n", 0+$ERRNO, $ERRNO; exit(1); } $reply_msg = dhcp_client::msg::decode($reply, 1); if (($reply_msg->{msg_type} == $MSG_ADVERTISE) || ($reply_msg->{msg_type} == $MSG_REPLY)) { last; } } } } until ($reply_msg || (($MRC != 0) && ($count > $MRC)) || (defined($mrd_end_time) && ($mrd_end_time > time()))); unless ($reply_msg) { if (($MRC != 0) && ($count >= $MRC)) { print STDERR "No reply after maximum retransmission count.\n"; } else { print STDERR "No reply after maximum retransmission duration.\n"; } } if ($reply_msg && ($reply_msg->{msg_type} == $MSG_REPLY)) { print "Got DHCPv6 Reply message.\n"; exit(0); } #$Data::Dumper::Useqq = 1; #print Dumper($msg), "\n"; #print Dumper($msg->packet()), "\n"; # #print "packet length: ", length($msg->packet()), "\n"; dhcp-4.2.4/tests/DHCPv6/290-decline-nohost.pl000644 000765 000024 00000010737 11301372617 020314 0ustar00sarstaff000000 000000 #! /usr/bin/perl -w # Copyright (c) 2007,2009 by Internet Systems Consortium, Inc. ("ISC") # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # # Internet Systems Consortium, Inc. # 950 Charter Street # Redwood City, CA 94063 # # https://www.isc.org/ use strict; use English; use Time::HiRes qw( sleep ); use Socket; use Socket6; use IO::Select; use dhcp_client; # XXX: for debugging use Data::Dumper; # not-yet-standard options my $OPT_TIME_SERVERS = 40; my $OPT_TIME_OFFSET = 41; # DOCSIS sub-options my $DOCSIS_OPT_ORO = 1; # 2 to 31 are reserved my $DOCSIS_OPT_TFTP_SERVERS = 32; my $DOCSIS_OPT_CONFIG_FILE_NAME = 33; my $DOCSIS_OPT_SYSLOG_SERVERS = 34; my $DOCSIS_OPT_TLV5 = 35; my $DOCSIS_OPT_DEVICE_ID = 36; my $DOCSIS_OPT_CCC = 37; my $DOCSIS_OPT_VERS = 38; # well-known addresses my $All_DHCP_Relay_Agents_and_Servers = "ff02::1:2"; my $All_DHCP_Servers = "ff05::1:3"; # ports my $client_port = 546; my $server_port = 547; # create a new Solicit message my $msg = dhcp_client::msg->new($MSG_DECLINE); # add the Client Identifier (required by DOCSIS and RFC 3315) $msg->add_option($OPT_CLIENTID, dhcp_client::duid()); # add the Server identifier (required by RFC 3315) $msg->add_option($OPT_SERVERID, "InfiniteEntropy"); # add Elapsed Time, set to 0 on first packet (required by RFC 3315) $msg->add_option($OPT_ELAPSED_TIME, "\x00\x00"); # timeout parameters, from DOCSIS my $IRT = $SOL_TIMEOUT; my $MRT = $SOL_MAX_RT; my $MRC = 4; # DOCSIS says 4, RFC 3315 says it SHOULD be 0 my $MRD = 0; # sleep a random amount of time between 0 and 1 second, required by RFC 3315 # XXX: this seems pretty stupid sleep(rand($SOL_MAX_DELAY)); my $RT; my $count = 0; my $mrd_end_time; if ($MRD != 0) { $mrd_end_time = time() + $MRD; } my $reply_msg; do { # create our socket, and send our Solicit socket(SOCK, PF_INET6, SOCK_DGRAM, getprotobyname('udp')) || die; my $addr = inet_pton(AF_INET6, $All_DHCP_Servers); my $packet = $msg->packet(); my $send_ret = send(SOCK, $packet, 0, pack_sockaddr_in6($server_port, $addr)); if (not defined($send_ret)) { printf STDERR "Error \%d sending DHCPv6 Solicit message;\n\%s\n", 0+$ERRNO, $ERRNO; exit(1); } elsif ($send_ret != length($packet)) { print STDERR "Unable to send entire DHCPv6 Solicit message.\n"; exit(1); } $count++; my $RAND = rand(0.2) - 0.1; if (defined $RT) { $RT = 2*$RT + $RAND*$RT; if (($RT > $MRT) && ($MRT != 0)) { $RT = $MRT + $RAND*$RT; } } else { $RT = $IRT + $RAND*$IRT; } my $rt_end_time = time() + $RT; if (defined($mrd_end_time) && ($mrd_end_time > $rt_end_time)) { $rt_end_time = $mrd_end_time; } for (;;) { my $timeout = $rt_end_time - time(); if ($timeout < 0) { # print STDERR "Timeout waiting for DHCPv6 Advertise ", # "or Reply message.\n"; last; } my @ready = IO::Select->new(\*SOCK)->can_read($timeout); if (@ready) { my $reply; my $recv_ret; $recv_ret = recv(SOCK, $reply, 1500, 0); if (not defined $recv_ret) { printf STDERR "Error \%d receiving DHCPv6 " . "message;\n\%s\n", 0+$ERRNO, $ERRNO; exit(1); } $reply_msg = dhcp_client::msg::decode($reply, 1); if (($reply_msg->{msg_type} == $MSG_ADVERTISE) || ($reply_msg->{msg_type} == $MSG_REPLY)) { last; } } } } until ($reply_msg || (($MRC != 0) && ($count > $MRC)) || (defined($mrd_end_time) && ($mrd_end_time > time()))); unless ($reply_msg) { if (($MRC != 0) && ($count >= $MRC)) { print STDERR "No reply after maximum retransmission count.\n"; } else { print STDERR "No reply after maximum retransmission duration.\n"; } } if ($reply_msg && ($reply_msg->{msg_type} == $MSG_REPLY)) { print "Got DHCPv6 Reply message.\n"; exit(0); } #$Data::Dumper::Useqq = 1; #print Dumper($msg), "\n"; #print Dumper($msg->packet()), "\n"; # #print "packet length: ", length($msg->packet()), "\n"; dhcp-4.2.4/tests/DHCPv6/291-decline-bad-address.pl000644 000765 000024 00000011650 11301372617 021147 0ustar00sarstaff000000 000000 #! /usr/bin/perl -w # Copyright (c) 2007,2009 by Internet Systems Consortium, Inc. ("ISC") # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # # Internet Systems Consortium, Inc. # 950 Charter Street # Redwood City, CA 94063 # # https://www.isc.org/ use strict; use English; use Time::HiRes qw( sleep ); use Socket; use Socket6; use IO::Select; use dhcp_client; # XXX: for debugging use Data::Dumper; # not-yet-standard options my $OPT_TIME_SERVERS = 40; my $OPT_TIME_OFFSET = 41; # DOCSIS sub-options my $DOCSIS_OPT_ORO = 1; # 2 to 31 are reserved my $DOCSIS_OPT_TFTP_SERVERS = 32; my $DOCSIS_OPT_CONFIG_FILE_NAME = 33; my $DOCSIS_OPT_SYSLOG_SERVERS = 34; my $DOCSIS_OPT_TLV5 = 35; my $DOCSIS_OPT_DEVICE_ID = 36; my $DOCSIS_OPT_CCC = 37; my $DOCSIS_OPT_VERS = 38; # well-known addresses my $All_DHCP_Relay_Agents_and_Servers = "ff02::1:2"; my $All_DHCP_Servers = "ff05::1:3"; # ports my $client_port = 546; my $server_port = 547; # create a new Solicit message my $msg = dhcp_client::msg->new($MSG_DECLINE); # add the Client Identifier (required by DOCSIS and RFC 3315) $msg->add_option($OPT_CLIENTID, dhcp_client::duid()); # add the Server identifier (required by RFC 3315) $msg->add_option($OPT_SERVERID, "InfiniteEntropy"); # add Elapsed Time, set to 0 on first packet (required by RFC 3315) $msg->add_option($OPT_ELAPSED_TIME, "\x00\x00"); # add IA_NA for each interface (required by DOCSIS and RFC 3315) # XXX: should this be a single interface only? my $iaid = 0; foreach my $iface (dhcp_client::iface()) { my $iaaddr_option = inet_pton(AF_INET6, "1:2:3:4::"); $iaaddr_option .= pack("NN", 0, 0); my $option_data = pack("NNN", ++$iaid, 0, 0); $option_data .= pack("nn", $OPT_IAADDR, length($iaaddr_option)-8); $option_data .= $iaaddr_option; $msg->add_option($OPT_IA_NA, $option_data); } # timeout parameters, from DOCSIS my $IRT = $SOL_TIMEOUT; my $MRT = $SOL_MAX_RT; my $MRC = 4; # DOCSIS says 4, RFC 3315 says it SHOULD be 0 my $MRD = 0; # sleep a random amount of time between 0 and 1 second, required by RFC 3315 # XXX: this seems pretty stupid sleep(rand($SOL_MAX_DELAY)); my $RT; my $count = 0; my $mrd_end_time; if ($MRD != 0) { $mrd_end_time = time() + $MRD; } my $reply_msg; do { # create our socket, and send our Solicit socket(SOCK, PF_INET6, SOCK_DGRAM, getprotobyname('udp')) || die; my $addr = inet_pton(AF_INET6, $All_DHCP_Servers); my $packet = $msg->packet(); my $send_ret = send(SOCK, $packet, 0, pack_sockaddr_in6($server_port, $addr)); if (not defined($send_ret)) { printf STDERR "Error \%d sending DHCPv6 Solicit message;\n\%s\n", 0+$ERRNO, $ERRNO; exit(1); } elsif ($send_ret != length($packet)) { print STDERR "Unable to send entire DHCPv6 Solicit message.\n"; exit(1); } $count++; my $RAND = rand(0.2) - 0.1; if (defined $RT) { $RT = 2*$RT + $RAND*$RT; if (($RT > $MRT) && ($MRT != 0)) { $RT = $MRT + $RAND*$RT; } } else { $RT = $IRT + $RAND*$IRT; } my $rt_end_time = time() + $RT; if (defined($mrd_end_time) && ($mrd_end_time > $rt_end_time)) { $rt_end_time = $mrd_end_time; } for (;;) { my $timeout = $rt_end_time - time(); if ($timeout < 0) { # print STDERR "Timeout waiting for DHCPv6 Advertise ", # "or Reply message.\n"; last; } my @ready = IO::Select->new(\*SOCK)->can_read($timeout); if (@ready) { my $reply; my $recv_ret; $recv_ret = recv(SOCK, $reply, 1500, 0); if (not defined $recv_ret) { printf STDERR "Error \%d receiving DHCPv6 " . "message;\n\%s\n", 0+$ERRNO, $ERRNO; exit(1); } $reply_msg = dhcp_client::msg::decode($reply, 1); if (($reply_msg->{msg_type} == $MSG_ADVERTISE) || ($reply_msg->{msg_type} == $MSG_REPLY)) { last; } } } } until ($reply_msg || (($MRC != 0) && ($count > $MRC)) || (defined($mrd_end_time) && ($mrd_end_time > time()))); unless ($reply_msg) { if (($MRC != 0) && ($count >= $MRC)) { print STDERR "No reply after maximum retransmission count.\n"; } else { print STDERR "No reply after maximum retransmission duration.\n"; } } if ($reply_msg && ($reply_msg->{msg_type} == $MSG_REPLY)) { print "Got DHCPv6 Reply message.\n"; exit(0); } #$Data::Dumper::Useqq = 1; #print Dumper($msg), "\n"; #print Dumper($msg->packet()), "\n"; # #print "packet length: ", length($msg->packet()), "\n"; dhcp-4.2.4/tests/DHCPv6/292-decline-no-address.pl000644 000765 000024 00000011347 11301372617 021041 0ustar00sarstaff000000 000000 #! /usr/bin/perl -w # Copyright (c) 2007,2009 by Internet Systems Consortium, Inc. ("ISC") # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # # Internet Systems Consortium, Inc. # 950 Charter Street # Redwood City, CA 94063 # # https://www.isc.org/ use strict; use English; use Time::HiRes qw( sleep ); use Socket; use Socket6; use IO::Select; use dhcp_client; # XXX: for debugging use Data::Dumper; # not-yet-standard options my $OPT_TIME_SERVERS = 40; my $OPT_TIME_OFFSET = 41; # DOCSIS sub-options my $DOCSIS_OPT_ORO = 1; # 2 to 31 are reserved my $DOCSIS_OPT_TFTP_SERVERS = 32; my $DOCSIS_OPT_CONFIG_FILE_NAME = 33; my $DOCSIS_OPT_SYSLOG_SERVERS = 34; my $DOCSIS_OPT_TLV5 = 35; my $DOCSIS_OPT_DEVICE_ID = 36; my $DOCSIS_OPT_CCC = 37; my $DOCSIS_OPT_VERS = 38; # well-known addresses my $All_DHCP_Relay_Agents_and_Servers = "ff02::1:2"; my $All_DHCP_Servers = "ff05::1:3"; # ports my $client_port = 546; my $server_port = 547; # create a new Solicit message my $msg = dhcp_client::msg->new($MSG_DECLINE); # add the Client Identifier (required by DOCSIS and RFC 3315) $msg->add_option($OPT_CLIENTID, dhcp_client::duid()); # add the Server identifier (required by RFC 3315) $msg->add_option($OPT_SERVERID, "InfiniteEntropy"); # add Elapsed Time, set to 0 on first packet (required by RFC 3315) $msg->add_option($OPT_ELAPSED_TIME, "\x00\x00"); # add IA_NA for each interface (required by DOCSIS and RFC 3315) # XXX: should this be a single interface only? my $iaid = 0; foreach my $iface (dhcp_client::iface()) { my $option_data = pack("NNN", ++$iaid, 0, 0); $msg->add_option($OPT_IA_NA, $option_data); } # timeout parameters, from DOCSIS my $IRT = $SOL_TIMEOUT; my $MRT = $SOL_MAX_RT; my $MRC = 4; # DOCSIS says 4, RFC 3315 says it SHOULD be 0 my $MRD = 0; # sleep a random amount of time between 0 and 1 second, required by RFC 3315 # XXX: this seems pretty stupid sleep(rand($SOL_MAX_DELAY)); my $RT; my $count = 0; my $mrd_end_time; if ($MRD != 0) { $mrd_end_time = time() + $MRD; } my $reply_msg; do { # create our socket, and send our Solicit socket(SOCK, PF_INET6, SOCK_DGRAM, getprotobyname('udp')) || die; my $addr = inet_pton(AF_INET6, $All_DHCP_Servers); my $packet = $msg->packet(); my $send_ret = send(SOCK, $packet, 0, pack_sockaddr_in6($server_port, $addr)); if (not defined($send_ret)) { printf STDERR "Error \%d sending DHCPv6 Solicit message;\n\%s\n", 0+$ERRNO, $ERRNO; exit(1); } elsif ($send_ret != length($packet)) { print STDERR "Unable to send entire DHCPv6 Solicit message.\n"; exit(1); } $count++; my $RAND = rand(0.2) - 0.1; if (defined $RT) { $RT = 2*$RT + $RAND*$RT; if (($RT > $MRT) && ($MRT != 0)) { $RT = $MRT + $RAND*$RT; } } else { $RT = $IRT + $RAND*$IRT; } my $rt_end_time = time() + $RT; if (defined($mrd_end_time) && ($mrd_end_time > $rt_end_time)) { $rt_end_time = $mrd_end_time; } for (;;) { my $timeout = $rt_end_time - time(); if ($timeout < 0) { # print STDERR "Timeout waiting for DHCPv6 Advertise ", # "or Reply message.\n"; last; } my @ready = IO::Select->new(\*SOCK)->can_read($timeout); if (@ready) { my $reply; my $recv_ret; $recv_ret = recv(SOCK, $reply, 1500, 0); if (not defined $recv_ret) { printf STDERR "Error \%d receiving DHCPv6 " . "message;\n\%s\n", 0+$ERRNO, $ERRNO; exit(1); } $reply_msg = dhcp_client::msg::decode($reply, 1); if (($reply_msg->{msg_type} == $MSG_ADVERTISE) || ($reply_msg->{msg_type} == $MSG_REPLY)) { last; } } } } until ($reply_msg || (($MRC != 0) && ($count > $MRC)) || (defined($mrd_end_time) && ($mrd_end_time > time()))); unless ($reply_msg) { if (($MRC != 0) && ($count >= $MRC)) { print STDERR "No reply after maximum retransmission count.\n"; } else { print STDERR "No reply after maximum retransmission duration.\n"; } } if ($reply_msg && ($reply_msg->{msg_type} == $MSG_REPLY)) { print "Got DHCPv6 Reply message.\n"; exit(0); } #$Data::Dumper::Useqq = 1; #print Dumper($msg), "\n"; #print Dumper($msg->packet()), "\n"; # #print "packet length: ", length($msg->packet()), "\n"; dhcp-4.2.4/tests/DHCPv6/293-decline.pl000644 000765 000024 00000012135 11301372617 017001 0ustar00sarstaff000000 000000 #! /usr/bin/perl -w # Copyright (c) 2007,2009 by Internet Systems Consortium, Inc. ("ISC") # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # # Internet Systems Consortium, Inc. # 950 Charter Street # Redwood City, CA 94063 # # https://www.isc.org/ use strict; use English; use Time::HiRes qw( sleep ); use Socket; use Socket6; use IO::Select; use dhcp_client; # XXX: for debugging use Data::Dumper; # not-yet-standard options my $OPT_TIME_SERVERS = 40; my $OPT_TIME_OFFSET = 41; # DOCSIS sub-options my $DOCSIS_OPT_ORO = 1; # 2 to 31 are reserved my $DOCSIS_OPT_TFTP_SERVERS = 32; my $DOCSIS_OPT_CONFIG_FILE_NAME = 33; my $DOCSIS_OPT_SYSLOG_SERVERS = 34; my $DOCSIS_OPT_TLV5 = 35; my $DOCSIS_OPT_DEVICE_ID = 36; my $DOCSIS_OPT_CCC = 37; my $DOCSIS_OPT_VERS = 38; # well-known addresses my $All_DHCP_Relay_Agents_and_Servers = "ff02::1:2"; my $All_DHCP_Servers = "ff05::1:3"; # ports my $client_port = 546; my $server_port = 547; # create a new Solicit message my $msg = dhcp_client::msg->new($MSG_DECLINE); # add the Client Identifier (required by DOCSIS and RFC 3315) my $client_id = "\x00\x01\x00\x01\x0c\x00\xa1\x41\x00\x06\x5b\x50\x99\xf6"; $msg->add_option($OPT_CLIENTID, $client_id); #$msg->add_option($OPT_CLIENTID, dhcp_client::duid(3)); # add the Server identifier (required by RFC 3315) $msg->add_option($OPT_SERVERID, "InfiniteEntropy"); # add Elapsed Time, set to 0 on first packet (required by RFC 3315) $msg->add_option($OPT_ELAPSED_TIME, "\x00\x00"); # add IA_NA for each interface (required by DOCSIS and RFC 3315) # XXX: should this be a single interface only? my $iaid = 0; foreach my $iface (dhcp_client::iface()) { my $iaaddr_option = inet_pton(AF_INET6, "3ffe:aaaa:aaaa:aaaa::ffff"); $iaaddr_option .= pack("NN", 0, 0); my $option_data = pack("NNN", ++$iaid, 0, 0); $option_data .= pack("nn", $OPT_IAADDR, length($iaaddr_option)-8); $option_data .= $iaaddr_option; $msg->add_option($OPT_IA_NA, $option_data); } # timeout parameters, from DOCSIS my $IRT = $SOL_TIMEOUT; my $MRT = $SOL_MAX_RT; my $MRC = 4; # DOCSIS says 4, RFC 3315 says it SHOULD be 0 my $MRD = 0; # sleep a random amount of time between 0 and 1 second, required by RFC 3315 # XXX: this seems pretty stupid sleep(rand($SOL_MAX_DELAY)); my $RT; my $count = 0; my $mrd_end_time; if ($MRD != 0) { $mrd_end_time = time() + $MRD; } my $reply_msg; do { # create our socket, and send our Solicit socket(SOCK, PF_INET6, SOCK_DGRAM, getprotobyname('udp')) || die; my $addr = inet_pton(AF_INET6, $All_DHCP_Servers); my $packet = $msg->packet(); my $send_ret = send(SOCK, $packet, 0, pack_sockaddr_in6($server_port, $addr)); if (not defined($send_ret)) { printf STDERR "Error \%d sending DHCPv6 Solicit message;\n\%s\n", 0+$ERRNO, $ERRNO; exit(1); } elsif ($send_ret != length($packet)) { print STDERR "Unable to send entire DHCPv6 Solicit message.\n"; exit(1); } $count++; my $RAND = rand(0.2) - 0.1; if (defined $RT) { $RT = 2*$RT + $RAND*$RT; if (($RT > $MRT) && ($MRT != 0)) { $RT = $MRT + $RAND*$RT; } } else { $RT = $IRT + $RAND*$IRT; } my $rt_end_time = time() + $RT; if (defined($mrd_end_time) && ($mrd_end_time > $rt_end_time)) { $rt_end_time = $mrd_end_time; } for (;;) { my $timeout = $rt_end_time - time(); if ($timeout < 0) { # print STDERR "Timeout waiting for DHCPv6 Advertise ", # "or Reply message.\n"; last; } my @ready = IO::Select->new(\*SOCK)->can_read($timeout); if (@ready) { my $reply; my $recv_ret; $recv_ret = recv(SOCK, $reply, 1500, 0); if (not defined $recv_ret) { printf STDERR "Error \%d receiving DHCPv6 " . "message;\n\%s\n", 0+$ERRNO, $ERRNO; exit(1); } $reply_msg = dhcp_client::msg::decode($reply, 1); if (($reply_msg->{msg_type} == $MSG_ADVERTISE) || ($reply_msg->{msg_type} == $MSG_REPLY)) { last; } } } } until ($reply_msg || (($MRC != 0) && ($count > $MRC)) || (defined($mrd_end_time) && ($mrd_end_time > time()))); unless ($reply_msg) { if (($MRC != 0) && ($count >= $MRC)) { print STDERR "No reply after maximum retransmission count.\n"; } else { print STDERR "No reply after maximum retransmission duration.\n"; } } if ($reply_msg && ($reply_msg->{msg_type} == $MSG_REPLY)) { print "Got DHCPv6 Reply message.\n"; exit(0); } #$Data::Dumper::Useqq = 1; #print Dumper($msg), "\n"; #print Dumper($msg->packet()), "\n"; # #print "packet length: ", length($msg->packet()), "\n"; dhcp-4.2.4/tests/DHCPv6/dhcp_client.pm000644 000765 000024 00000026327 11301372617 017350 0ustar00sarstaff000000 000000 #! /usr/bin/perl -w # Copyright (c) 2007,2009 by Internet Systems Consortium, Inc. ("ISC") # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # # Internet Systems Consortium, Inc. # 950 Charter Street # Redwood City, CA 94063 # # https://www.isc.org/ package dhcp_client; require Exporter; @ISA = qw(Exporter); # message types $MSG_SOLICIT = 1; $MSG_ADVERTISE = 2; $MSG_REQUEST = 3; $MSG_CONFIRM = 4; $MSG_RENEW = 5; $MSG_REBIND = 6; $MSG_REPLY = 7; $MSG_RELEASE = 8; $MSG_DECLINE = 9; $MSG_RECONFIGURE = 10; $MSG_INFORMATION_REQUEST = 11; $MSG_RELAY_FORW = 12; $MSG_RELAY_REPL = 13; # option numbers $OPT_CLIENTID = 1; $OPT_SERVERID = 2; $OPT_IA_NA = 3; $OPT_IA_TA = 4; $OPT_IAADDR = 5; $OPT_ORO = 6; $OPT_PREFERENCE = 7; $OPT_ELAPSED_TIME = 8; $OPT_RELAY_MSG = 9; $OPT_AUTH = 11; $OPT_UNICAST = 12; $OPT_STATUS_CODE = 13; $OPT_RAPID_COMMIT = 14; $OPT_USER_CLASS = 15; $OPT_VENDOR_CLASS = 16; $OPT_VENDOR_OPTS = 17; $OPT_INTERFACE_ID = 18; $OPT_RECONF_MSG = 19; $OPT_RECONF_ACCEPT = 20; # timeouts $SOL_MAX_DELAY = 1; $SOL_TIMEOUT = 1; $SOL_MAX_RT = 120; $REQ_TIMEOUT = 1; $REQ_MAX_RT = 30; $REQ_MAX_RC = 10; $CNF_MAX_DELAY = 1; $CNF_MAX_RT = 4; $CNF_MAX_RD = 10; $REN_TIMEOUT = 10; $REN_MAX_RT = 600; $REB_TIMEOUT = 10; $REB_MAX_RT = 600; $INF_MAX_DELAY = 1; $INF_TIMEOUT = 1; $INF_MAX_RT = 120; $REL_TIMEOUT = 1; $REL_MAX_RC = 5; $DEC_TIMEOUT = 1; $DEC_MAX_RC = 5; $REC_TIMEOUT = 2; $REC_MAX_RC = 8; $HOP_COUNT_LIMIT = 32; @EXPORT = qw( $MSG_SOLICIT $MSG_ADVERTISE $MSG_REQUEST $MSG_CONFIRM $MSG_RENEW $MSG_REBIND $MSG_REPLY $MSG_RELEASE $MSG_DECLINE $MSG_RECONFIGURE $MSG_INFORMATION_REQUEST $MSG_RELAY_FORW $MSG_RELAY_REPL $OPT_CLIENTID $OPT_SERVERID $OPT_IA_NA $OPT_IA_TA $OPT_IAADDR $OPT_ORO $OPT_PREFERENCE $OPT_ELAPSED_TIME $OPT_RELAY_MSG $OPT_AUTH $OPT_UNICAST $OPT_STATUS_CODE $OPT_RAPID_COMMIT $OPT_USER_CLASS $OPT_VENDOR_CLASS $OPT_VENDOR_OPTS $OPT_INTERFACE_ID $OPT_RECONF_MSG $OPT_RECONF_ACCEPT $SOL_MAX_DELAY $SOL_TIMEOUT $SOL_MAX_RT $REQ_TIMEOUT $REQ_MAX_RT $REQ_MAX_RC $CNF_MAX_DELAY $CNF_MAX_RT $CNF_MAX_RD $REN_TIMEOUT $REN_MAX_RT $REB_TIMEOUT $REB_MAX_RT $INF_MAX_DELAY $INF_TIMEOUT $INF_MAX_RT $REL_TIMEOUT $REL_MAX_RC $DEC_TIMEOUT $DEC_MAX_RC $REC_TIMEOUT $REC_MAX_RC $HOP_COUNT_LIMIT ); my %msg_type_num = ( MSG_SOLICIT => 1, MSG_ADVERTISE => 2, MSG_REQUEST => 3, MSG_CONFIRM => 4, MSG_RENEW => 5, MSG_REBIND => 6, MSG_REPLY => 7, MSG_RELEASE => 8, MSG_DECLINE => 9, MSG_RECONFIGURE => 10, MSG_INFORMATION_REQUEST => 11, MSG_RELAY_FORW => 12, MSG_RELAY_REPL => 13, ); my %msg_num_type = reverse(%msg_type_num); my %opt_type_num = ( OPT_CLIENTID => 1, OPT_SERVERID => 2, OPT_IA_NA => 3, OPT_IA_TA => 4, OPT_IAADDR => 5, OPT_ORO => 6, OPT_PREFERENCE => 7, OPT_ELAPSED_TIME => 8, OPT_RELAY_MSG => 9, OPT_AUTH => 11, OPT_UNICAST => 12, OPT_STATUS_CODE => 13, OPT_RAPID_COMMIT => 14, OPT_USER_CLASS => 15, OPT_VENDOR_CLASS => 16, OPT_VENDOR_OPTS => 17, OPT_INTERFACE_ID => 18, OPT_RECONF_MSG => 19, OPT_RECONF_ACCEPT => 20, ); my %opt_num_type = reverse(%opt_type_num); my %status_code_num = ( Success => 0, UnspecFail => 1, NoAddrsAvail => 2, NoBinding => 3, NotOnLink => 4, UseMulticast => 5, ); my %status_num_code = reverse(%status_code_num); my %docsis_type_num = ( CL_OPTION_ORO => 1, CL_OPTION_TFTP_SERVERS => 32, CL_OPTION_CONFIG_FILE_NAME => 33, CL_OPTION_SYSLOG_SERVERS => 34, CL_OPTION_TLV5 => 35, CL_OPTION_DEVICE_ID => 36, CL_OPTION_CCC => 37, CL_OPTION_DOCSIS_VERS => 38, ); my %docsis_num_type = reverse(%docsis_type_num); use strict; use English; use POSIX; # XXX: very Solaris-specific sub iface { my @ifaces; foreach my $fname (glob("/etc/hostname.*")) { $fname =~ s[^/etc/hostname.][]; push(@ifaces, $fname); } return wantarray() ? @ifaces : $ifaces[0]; } # XXX: very Solaris-specific sub mac_addr { my @ip_addrs; foreach my $iface (iface()) { if (`ifconfig $iface 2>/dev/null` =~ /\sinet (\S+)\s/) { push(@ip_addrs, $1); } } my @mac_addrs; foreach my $line (split(/\n/, `arp -an 2>/dev/null`)) { my @parts = split(/\s+/, $line); my $ip = $parts[1]; my $mac = $parts[-1]; if (grep { $ip eq $_ } @ip_addrs) { $mac =~ s/://g; push(@mac_addrs, $mac); } } return wantarray() ? @mac_addrs : $mac_addrs[0]; } sub mac_addr_binary { my @mac_addr = split(//, mac_addr()); my $mac_addr = join("", map { chr(hex($_)) } @mac_addr); return $mac_addr; } # DHCPv6 times start 2000-01-01 00:00:00 my $dhcp_time_base = 946684800; #{ # local $ENV{TZ} = "UTC"; # POSIX::tzset(); # $dhcp_time_base = POSIX::mktime(0, 0, 0, 1, 0, 100); #} sub dhcpv6_time { return time() - $dhcp_time_base; } sub duid { my ($type) = @_; $type = 1 unless (defined $type); if (($type == 1) || ($type == 3)) { my $mac_addr = mac_addr_binary(); if ($type == 1) { my $time = pack("N", dhcpv6_time()); return "\x00\x01\x00\x01${time}${mac_addr}"; } else { return "\x00\x03\x00\x01${mac_addr}"; } } else { die "Unknown DUID type $type requested"; } } package dhcp_client::msg; use Socket; use Socket6; sub new { my ($pkg, $msg_type, $trans_id) = @_; my $this = {}; bless $this; $this->{msg_type} = $msg_type+0; if (defined $trans_id) { $this->{trans_id} = $trans_id; } else { $this->{trans_id} = chr(rand(256)) . chr(rand(256)) . chr(rand(256)); } $this->{options} = [ ]; return $this; } sub add_option { my ($this, $num, $data) = @_; push(@{$this->{options}}, [ $num, $data ]); } sub get_option { my ($this, $num) = @_; my @options; foreach my $option (@{$this->{options}}) { if ($option->[0] == $num) { push(@options, $option->[1]); } } return wantarray() ? @options : $options[0]; } sub packed_options { my ($this) = @_; my $options = ""; foreach my $option (@{$this->{options}}) { $options .= pack("nn", $option->[0], length($option->[1])); $options .= $option->[1]; } return $options; } sub packet { my ($this) = @_; my $packet = ""; $packet .= chr($this->{msg_type}); $packet .= $this->{trans_id}; $packet .= $this->packed_options(); return $packet; } sub unpack_options { my ($options) = @_; my @parsed_options; my $p = 0; while ($p < length($options)) { my ($id, $len) = unpack("nn", substr($options, $p, 4)); push(@parsed_options, [ $id, substr($options, $p + 4, $len) ]); $p += 4 + $len; } return @parsed_options; } sub print_docsis_option { my ($num, $data, $indent) = @_; print "${indent}DOCSIS Option $num"; if ($docsis_num_type{$num}) { print " ($docsis_num_type{$num})"; } print ", length ", length($data), "\n"; return unless ($docsis_num_type{$num}); if ($docsis_num_type{$num} eq "CL_OPTION_ORO") { my $num_oro = length($data) / 2; for (my $i=0; $i<$num_oro; $i++) { my $oro_num = unpack("n", substr($data, $i*2, 2)); print "${indent} $oro_num"; if ($docsis_num_type{$oro_num}) { print " ($docsis_num_type{$oro_num})"; } print "\n"; } } elsif ($docsis_num_type{$num} eq "CL_OPTION_TFTP_SERVERS") { my $num_servers = length($data) / 16; for (my $i=0; $i<$num_servers; $i++) { my $srv = inet_ntop(AF_INET6, substr($data, $i*16, 16)); print "$indent TFTP server ", ($i+1), ": "; print uc($srv), "\n"; } } elsif ($docsis_num_type{$num} eq "CL_OPTION_CONFIG_FILE_NAME") { print "$indent Config file name: \"$data\"\n" } elsif ($docsis_num_type{$num} eq "CL_OPTION_SYSLOG_SERVERS") { my $num_servers = length($data) / 16; for (my $i=0; $i<$num_servers; $i++) { my $srv = inet_ntop(AF_INET6, substr($data, $i*16, 16)); print "$indent syslog server ", ($i+1), ": "; print uc($srv), "\n"; } } } sub print_option { my ($num, $data, $indent) = @_; print "${indent}Option $num"; if ($opt_num_type{$num}) { print " ($opt_num_type{$num})"; } print ", length ", length($data), "\n"; if ($num == $dhcp_client::OPT_ORO) { my $num_oro = length($data) / 2; for (my $i=0; $i<$num_oro; $i++) { my $oro_num = unpack("n", substr($data, $i*2, 2)); print "${indent} $oro_num"; if ($opt_num_type{$oro_num}) { print " ($opt_num_type{$oro_num})"; } print "\n"; } } elsif (($num == $dhcp_client::OPT_CLIENTID) || ($num == $dhcp_client::OPT_SERVERID)) { print $indent, " "; if (length($data) > 0) { printf '%02X', ord(substr($data, 0, 1)); for (my $i=1; $i 12) { printf "${indent} IA_NA encapsulated options:\n"; foreach my $option (unpack_options(substr($data, 12))) { print_option(@{$option}, $indent . " "); } } } elsif ($num == $dhcp_client::OPT_IAADDR) { printf "${indent} IPv6 address: \%s\n", uc(inet_ntop(AF_INET6, substr($data, 0, 16))); printf "${indent} Preferred lifetime: \%d\n", unpack("N", substr($data, 16, 4)); printf "${indent} Valid lifetime: \%d\n", unpack("N", substr($data, 20, 4)); if (length($data) > 24) { printf "${indent} IAADDR encapsulated options:\n"; foreach my $option (unpack_options(substr($data, 24))) { print_option(@{$option}, $indent . " "); } } } elsif ($num == $dhcp_client::OPT_VENDOR_OPTS) { my $enterprise_number = unpack("N", substr($data, 0, 4)); print "${indent} Enterprise number: $enterprise_number\n"; # DOCSIS if ($enterprise_number == 4491) { foreach my $option (unpack_options(substr($data, 4))) { print_docsis_option(@{$option}, $indent . " "); } } } elsif ($num == $dhcp_client::OPT_STATUS_CODE) { my $code = ord(substr($data, 0, 1)); my $msg = substr($data, 1); print "${indent} Code: $code"; if ($status_num_code{$code}) { print " ($status_num_code{$code})"; } print "\n"; print "${indent} Message: \"$msg\"\n"; } } # XXX: we aren't careful about packet boundaries and values... # DO NOT RUN ON PRODUCTION SYSTEMS!!! sub decode { my ($packet, $print) = @_; my $msg_type = ord(substr($packet, 0, 1)); my $trans_id = substr($packet, 1, 3); my $msg = dhcp_client::msg->new($msg_type, $trans_id); if ($print) { print "DHCPv6 packet\n"; print " Message type: $msg_num_type{$msg_type}\n"; printf " Transaction id: 0x\%02X\%02X\%02X\n", ord(substr($trans_id, 0, 1)), ord(substr($trans_id, 1, 1)), ord(substr($trans_id, 2, 1)); print " Options:\n"; } foreach my $option (unpack_options(substr($packet, 4))) { print_option(@{$option}, " ") if ($print); $msg->add_option(@{$option}); } return $msg; } dhcp-4.2.4/tests/DHCPv6/README000644 000765 000024 00000004332 10620201062 015372 0ustar00sarstaff000000 000000 In order to test the DHCPv6 server, we have a configuration file with known values, and some Perl scripts designed to send and receive DHCPv6 packets to check various code paths. It is not complete test converage by any means, but it should be fairly easy to add additional tests as needed. The scripts themselves are not very well written. There is a lot of copied code, poor error handling, and so on. These should be rewritten at some point. To use, the DHCPv6 server must be running in test mode to send back to the originating port. (The scripts can be changed to bind to the appropriate client port, but they don't now, and have to run as root to do this). In server/dhcpv6.c, look for this comment: /* For testing, we reply to the sending port, so we don't need a root */ /* client */ to_addr.sin6_port = remote_port; /* to_addr.sin6_port = packet->client_port;*/ And change the code to use the client_port value. You will need to modify one of the test configuration files to use one of the physical subnets that your machine uses, in the subnet6 statement. Then run the server as root, in debug mode: # touch /tmp/test.leases # dhcpd -cf test-a.conf -lf /tmp/test.leases -d You can invoke the scripts then: $ perl 000-badmsgtype.pl The expected results vary per script, depending on the behavior that is being tested. Notes about scripts: In order to manipulate IPv6 addresses, we need the Socket6 library, available from CPAN: http://search.cpan.org/~umemoto/Socket6-0.19/Socket6.pm The Perl that Sun issues for Solaris 10 is compiled with the Sun compiler. If you have the Sun compiler, then this will work fine. Otherwise you may need to install Perl from source. We need to get the hardware address in order to build DUID properly. The IO::Interface module reports hardware address, but not on Solaris 10 it seems. Rather than do this the "right way", we do it the "Perl way", and hack it. "ifconfig" does return the Ethernet address, but only to the root user. However, we can look for files of the name /etc/hostname.*, get the IP address from "ifconfig", and then check for those addresses in the ARP table. Client DUID is supposed to be an opaque value to the server, but we go ahead and make a "real" type 1 or type 3 DUID. dhcp-4.2.4/tests/DHCPv6/stubcli-opt-in-na.pl000644 000765 000024 00000013771 11301372617 020337 0ustar00sarstaff000000 000000 #! /usr/bin/perl -w # Copyright (c) 2007,2009 by Internet Systems Consortium, Inc. ("ISC") # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # # Internet Systems Consortium, Inc. # 950 Charter Street # Redwood City, CA 94063 # # https://www.isc.org/ use strict; use English; use Time::HiRes qw( sleep ); use Socket; use Socket6; use IO::Select; use dhcp_client; # XXX: for debugging use Data::Dumper; $Data::Dumper::Useqq = 1; # not-yet-standard options my $OPT_TIME_SERVERS = 40; my $OPT_TIME_OFFSET = 41; # DOCSIS sub-options my $DOCSIS_OPT_ORO = 1; # 2 to 31 are reserved my $DOCSIS_OPT_TFTP_SERVERS = 32; my $DOCSIS_OPT_CONFIG_FILE_NAME = 33; my $DOCSIS_OPT_SYSLOG_SERVERS = 34; my $DOCSIS_OPT_TLV5 = 35; my $DOCSIS_OPT_DEVICE_ID = 36; my $DOCSIS_OPT_CCC = 37; my $DOCSIS_OPT_VERS = 38; # well-known addresses my $All_DHCP_Relay_Agents_and_Servers = "ff02::1:2"; my $All_DHCP_Servers = "ff05::1:3"; # ports my $client_port = 546; my $server_port = 547; # create a new Solicit message my $msg = dhcp_client::msg->new($MSG_SOLICIT); # add the Client Identifier (required by DOCSIS and RFC 3315) my $client_id = "\x00\x01\x00\x01\x0c\x00\xa1\x41\x00\x06\x5b\x50\x99\xf6"; $msg->add_option($OPT_CLIENTID, $client_id); #$msg->add_option($OPT_CLIENTID, dhcp_client::duid()); # add Elapsed Time, set to 0 on first packet (required by RFC 3315) $msg->add_option($OPT_ELAPSED_TIME, "\x00\x00"); # add IA_NA for each interface (required by DOCSIS and RFC 3315) # XXX: should this be a single interface only? my $iaid = 0; foreach my $iface (dhcp_client::iface()) { my $option_data = pack("NNN", ++$iaid, 0, 0); my $enc_opt = dhcp_client::msg->new(0); $enc_opt->add_option($OPT_CLIENTID, $client_id); $option_data .= $enc_opt->packed_options(); $msg->add_option($OPT_IA_NA, $option_data); } # add Reconfigure Accept (required by DOCSIS) $msg->add_option($OPT_RECONF_ACCEPT, ""); # add Options Request (required by DOCSIS, recommended by RFC 3315) my @oro = ( $OPT_TIME_SERVERS, $OPT_TIME_OFFSET ); $msg->add_option($OPT_ORO, pack("n*", @oro)); # add Vendor Class option (required by DOCSIS) $msg->add_option($OPT_VENDOR_CLASS, pack("N", 4491) . "docsis3.0"); # add Vendor-specific Information Option option (required by DOCSIS) my $vsio = pack("N", 4491); # ORO (required by DOCSIS) my @docsis_oro = ( $DOCSIS_OPT_TFTP_SERVERS ); $vsio .= pack("nnC*", $DOCSIS_OPT_ORO, 0+@docsis_oro, @docsis_oro); # TLV5 data: CMTS DOCSIS version number 3.0 (required by DOCSIS) my $tlv5_data = "\x01\x02\x03\x0"; $vsio .= pack("nn", $DOCSIS_OPT_TLV5, length($tlv5_data)) . $tlv5_data; # DOCSIS Device (required by DOCSIS) my $docsis_device_id = dhcp_client::mac_addr_binary(); $vsio .= pack("nn", $DOCSIS_OPT_DEVICE_ID, length($docsis_device_id)); $vsio .= $docsis_device_id; $msg->add_option($OPT_VENDOR_OPTS, $vsio); # add Rapid Commit option (required by DOCSIS) $msg->add_option($OPT_RAPID_COMMIT, ""); # timeout parameters, from DOCSIS my $IRT = $SOL_TIMEOUT; my $MRT = $SOL_MAX_RT; my $MRC = 4; # DOCSIS says 4, RFC 3315 says it SHOULD be 0 my $MRD = 0; # sleep a random amount of time between 0 and 1 second, required by RFC 3315 # XXX: this seems pretty stupid sleep(rand($SOL_MAX_DELAY)); my $RT; my $count = 0; my $mrd_end_time; if ($MRD != 0) { $mrd_end_time = time() + $MRD; } my $reply_msg; do { # create our socket, and send our Solicit socket(SOCK, PF_INET6, SOCK_DGRAM, getprotobyname('udp')) || die; my $addr = inet_pton(AF_INET6, $All_DHCP_Servers); my $packet = $msg->packet(); my $send_ret = send(SOCK, $packet, 0, pack_sockaddr_in6($server_port, $addr)); if (not defined($send_ret)) { printf STDERR "Error \%d sending DHCPv6 Solicit message;\n\%s\n", 0+$ERRNO, $ERRNO; exit(1); } elsif ($send_ret != length($packet)) { print STDERR "Unable to send entire DHCPv6 Solicit message.\n"; exit(1); } $count++; my $RAND = rand(0.2) - 0.1; if (defined $RT) { $RT = 2*$RT + $RAND*$RT; if (($RT > $MRT) && ($MRT != 0)) { $RT = $MRT + $RAND*$RT; } } else { $RT = $IRT + $RAND*$IRT; } my $rt_end_time = time() + $RT; if (defined($mrd_end_time) && ($mrd_end_time > $rt_end_time)) { $rt_end_time = $mrd_end_time; } for (;;) { my $timeout = $rt_end_time - time(); if ($timeout < 0) { # print STDERR "Timeout waiting for DHCPv6 Advertise ", # "or Reply message.\n"; last; } my @ready = IO::Select->new(\*SOCK)->can_read($timeout); if (@ready) { my $reply; my $recv_ret; $recv_ret = recv(SOCK, $reply, 1500, 0); if (not defined $recv_ret) { printf STDERR "Error \%d receiving DHCPv6 " . "message;\n\%s\n", 0+$ERRNO, $ERRNO; exit(1); } $reply_msg = dhcp_client::msg::decode($reply, 1); if (($reply_msg->{msg_type} == $MSG_ADVERTISE) || ($reply_msg->{msg_type} == $MSG_REPLY)) { last; } } } } until ($reply_msg || (($MRC != 0) && ($count > $MRC)) || (defined($mrd_end_time) && ($mrd_end_time > time()))); unless ($reply_msg) { if (($MRC != 0) && ($count >= $MRC)) { print STDERR "No reply after maximum retransmission count.\n"; } else { print STDERR "No reply after maximum retransmission duration.\n"; } } if ($reply_msg && ($reply_msg->{msg_type} == $MSG_REPLY)) { print "Got DHCPv6 Reply message.\n"; #print Dumper($reply_msg), "\n"; exit(0); } #print Dumper($msg), "\n"; #print Dumper($msg->packet()), "\n"; # #print "packet length: ", length($msg->packet()), "\n"; dhcp-4.2.4/tests/DHCPv6/stubcli.pl000644 000765 000024 00000013330 11301372617 016526 0ustar00sarstaff000000 000000 #! /usr/bin/perl -w # Copyright (c) 2007,2009 by Internet Systems Consortium, Inc. ("ISC") # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # # Internet Systems Consortium, Inc. # 950 Charter Street # Redwood City, CA 94063 # # https://www.isc.org/ use strict; use English; use Time::HiRes qw( sleep ); use Socket; use Socket6; use IO::Select; use dhcp_client; # XXX: for debugging use Data::Dumper; # not-yet-standard options my $OPT_TIME_SERVERS = 40; my $OPT_TIME_OFFSET = 41; # DOCSIS sub-options my $DOCSIS_OPT_ORO = 1; # 2 to 31 are reserved my $DOCSIS_OPT_TFTP_SERVERS = 32; my $DOCSIS_OPT_CONFIG_FILE_NAME = 33; my $DOCSIS_OPT_SYSLOG_SERVERS = 34; my $DOCSIS_OPT_TLV5 = 35; my $DOCSIS_OPT_DEVICE_ID = 36; my $DOCSIS_OPT_CCC = 37; my $DOCSIS_OPT_VERS = 38; # well-known addresses my $All_DHCP_Relay_Agents_and_Servers = "ff02::1:2"; my $All_DHCP_Servers = "ff05::1:3"; # ports my $client_port = 546; my $server_port = 547; # create a new Solicit message my $msg = dhcp_client::msg->new($MSG_SOLICIT); # add the Client Identifier (required by DOCSIS and RFC 3315) $msg->add_option($OPT_CLIENTID, dhcp_client::duid()); # add Elapsed Time, set to 0 on first packet (required by RFC 3315) $msg->add_option($OPT_ELAPSED_TIME, "\x00\x00"); # add IA_NA for each interface (required by DOCSIS and RFC 3315) # XXX: should this be a single interface only? my $iaid = 0; foreach my $iface (dhcp_client::iface()) { my $option_data = pack("NNN", ++$iaid, 0, 0); $msg->add_option($OPT_IA_NA, $option_data); } # add Reconfigure Accept (required by DOCSIS) $msg->add_option($OPT_RECONF_ACCEPT, ""); # add Options Request (required by DOCSIS, recommended by RFC 3315) my @oro = ( $OPT_TIME_SERVERS, $OPT_TIME_OFFSET ); $msg->add_option($OPT_ORO, pack("n*", @oro)); # add Vendor Class option (required by DOCSIS) $msg->add_option($OPT_VENDOR_CLASS, pack("N", 4491) . "docsis3.0"); # add Vendor-specific Information Option option (required by DOCSIS) my $vsio = pack("N", 4491); # ORO (required by DOCSIS) my @docsis_oro = ( $DOCSIS_OPT_TFTP_SERVERS ); $vsio .= pack("nnC*", $DOCSIS_OPT_ORO, 0+@docsis_oro, @docsis_oro); # TLV5 data: CMTS DOCSIS version number 3.0 (required by DOCSIS) my $tlv5_data = "\x01\x02\x03\x0"; $vsio .= pack("nn", $DOCSIS_OPT_TLV5, length($tlv5_data)) . $tlv5_data; # DOCSIS Device (required by DOCSIS) my $docsis_device_id = dhcp_client::mac_addr_binary(); $vsio .= pack("nn", $DOCSIS_OPT_DEVICE_ID, length($docsis_device_id)); $vsio .= $docsis_device_id; $msg->add_option($OPT_VENDOR_OPTS, $vsio); # add Rapid Commit option (required by DOCSIS) $msg->add_option($OPT_RAPID_COMMIT, ""); # timeout parameters, from DOCSIS my $IRT = $SOL_TIMEOUT; my $MRT = $SOL_MAX_RT; my $MRC = 4; # DOCSIS says 4, RFC 3315 says it SHOULD be 0 my $MRD = 0; # sleep a random amount of time between 0 and 1 second, required by RFC 3315 # XXX: this seems pretty stupid sleep(rand($SOL_MAX_DELAY)); my $RT; my $count = 0; my $mrd_end_time; if ($MRD != 0) { $mrd_end_time = time() + $MRD; } my $reply_msg; do { # create our socket, and send our Solicit socket(SOCK, PF_INET6, SOCK_DGRAM, getprotobyname('udp')) || die; my $addr = inet_pton(AF_INET6, $All_DHCP_Servers); my $packet = $msg->packet(); my $send_ret = send(SOCK, $packet, 0, pack_sockaddr_in6($server_port, $addr)); if (not defined($send_ret)) { printf STDERR "Error \%d sending DHCPv6 Solicit message;\n\%s\n", 0+$ERRNO, $ERRNO; exit(1); } elsif ($send_ret != length($packet)) { print STDERR "Unable to send entire DHCPv6 Solicit message.\n"; exit(1); } $count++; my $RAND = rand(0.2) - 0.1; if (defined $RT) { $RT = 2*$RT + $RAND*$RT; if (($RT > $MRT) && ($MRT != 0)) { $RT = $MRT + $RAND*$RT; } } else { $RT = $IRT + $RAND*$IRT; } my $rt_end_time = time() + $RT; if (defined($mrd_end_time) && ($mrd_end_time > $rt_end_time)) { $rt_end_time = $mrd_end_time; } for (;;) { my $timeout = $rt_end_time - time(); if ($timeout < 0) { # print STDERR "Timeout waiting for DHCPv6 Advertise ", # "or Reply message.\n"; last; } my @ready = IO::Select->new(\*SOCK)->can_read($timeout); if (@ready) { my $reply; my $recv_ret; $recv_ret = recv(SOCK, $reply, 1500, 0); if (not defined $recv_ret) { printf STDERR "Error \%d receiving DHCPv6 " . "message;\n\%s\n", 0+$ERRNO, $ERRNO; exit(1); } $reply_msg = dhcp_client::msg::decode($reply, 1); if (($reply_msg->{msg_type} == $MSG_ADVERTISE) || ($reply_msg->{msg_type} == $MSG_REPLY)) { last; } } } } until ($reply_msg || (($MRC != 0) && ($count > $MRC)) || (defined($mrd_end_time) && ($mrd_end_time > time()))); unless ($reply_msg) { if (($MRC != 0) && ($count >= $MRC)) { print STDERR "No reply after maximum retransmission count.\n"; } else { print STDERR "No reply after maximum retransmission duration.\n"; } } if ($reply_msg && ($reply_msg->{msg_type} == $MSG_REPLY)) { print "Got DHCPv6 Reply message.\n"; exit(0); } #$Data::Dumper::Useqq = 1; #print Dumper($msg), "\n"; #print Dumper($msg->packet()), "\n"; # #print "packet length: ", length($msg->packet()), "\n"; dhcp-4.2.4/tests/DHCPv6/test-a.conf000644 000765 000024 00000003755 10620201062 016566 0ustar00sarstaff000000 000000 # # Define the DHCPv6 option space. # # Option numbers are assigned by IANA: # http://www.iana.org/assignments/dhcpv6-parameters # option dhcp6.time-servers code 40 = array of ip6-address; option dhcp6.time-offset code 41 = signed integer 32; # # Define the DOCSIS option space. # TODO: DOCSIS oro definition # option space docsis code width 2 length width 2; option vsio.docsis code 4491 = encapsulate docsis; option docsis.tftp-servers code 32 = array of ip6-address; option docsis.cablelabs-configuration-file code 33 = text; option docsis.cablelabs-syslog-servers code 34 = array of ip6-address; option docsis.device-id code 36 = string; # # Declare some options. # option dhcp6.time-servers 3ffe:bbbb:aaaa:aaaa::1, 3ffe:bbbb:aaaa:aaaa::2; option docsis.tftp-servers 3ffe:cccc:aaaa:aaaa::1, 3ffe:cccc:aaaa:aaaa::2; # # DNS server IP address to update dynamically # ddns-update-style interim; ddns-domainname "foo.com"; # # Per-host settings. # host cablemodem-1 { host-identifier option dhcp6.client-id 00:01:00:01:0c:00:a1:41:00:06:5b:50:99:f6; fixed-address6 3ffe:aaaa:aaaa:aaaa::ffff; ddns-domainname "bar.com"; option dhcp6.time-servers 3ffe:aaaa:aaaa:aaaa::1, 3ffe:aaaa:aaaa:aaaa::2; option docsis.tftp-servers 3ffe:aaaa:aaaa:aaaa::1, 3ffe:aaaa:aaaa:aaaa::2; option dhcp6.time-offset -14400; # -4 hours option docsis.cablelabs-configuration-file "bootfile.cfg"; option docsis.cablelabs-syslog-servers 3ffe:aaaa:aaaa:aaaa::1, 3ffe:aaaa:aaaa:aaaa::2; } #host cablemodem-2 { # host-identifier option docsis.device-id 00:06:5B:50:99:F6; # option dhcp6.time-servers 3ffe:dddd:aaaa:aaaa::1, # 3ffe:dddd:aaaa:aaaa::2; # option docsis.tftp-servers 3ffe:dddd:aaaa:aaaa::1, # 3ffe:dddd:aaaa:aaaa::2; # option dhcp6.time-offset -14400; # -4 hours # option docsis.cablelabs-configuration-file "bootfile.cfg"; # option docsis.cablelabs-syslog-servers 3ffe:aaaa:aaaa:aaaa::1, # 3ffe:aaaa:aaaa:aaaa::2; #} # XXX: for testing subnet6 fe80::20c:29ff:fe42:820/128 { } dhcp-4.2.4/tests/DHCPv6/test-b.conf000644 000765 000024 00000003473 10620201062 016564 0ustar00sarstaff000000 000000 # # Define the DHCPv6 option space. # # Option numbers are assigned by IANA: # http://www.iana.org/assignments/dhcpv6-parameters # option dhcpv6.time-servers code 40 = array of ip6-address; option dhcpv6.time-offset code 41 = signed integer 32; # # Define the DOCSIS option space. # option space docsis code width 2 length width 2; option docsis.tftp-servers code 32 = array of ip6-address; option docsis.cablelabs-configuration-file code 33 = text; option docsis.cablelabs-syslog-servers code 34 = array of ip6-address; option docsis.device-id code 36 = string; # # Declare some options. # option dhcpv6.time-servers 3ffe:bbbb:aaaa:aaaa::1, 3ffe:bbbb:aaaa:aaaa::2; option docsis.tftp-servers 3ffe:cccc:aaaa:aaaa::1, 3ffe:cccc:aaaa:aaaa::2; # # DNS server IP address to update dynamically # ddns-update-style interim; ddns-domainname "foo.com"; # # Per-host settings. # host cablemodem-1 { option dhcpv6.client-id 00:01:00:01:0c:00:a1:41:00:06:5b:50:99:f6; fixed-address6 3ffe:aaaa:aaaa:aaaa::ffff; ddns-domainname "bar.com"; option dhcpv6.time-servers 3ffe:aaaa:aaaa:aaaa::1, 3ffe:aaaa:aaaa:aaaa::2; option docsis.tftp-servers 3ffe:aaaa:aaaa:aaaa::1, 3ffe:aaaa:aaaa:aaaa::2; option dhcpv6.time-offset -14400; # -4 hours option docsis.cablelabs-configuration-file "bootfile.cfg"; option docsis.cablelabs-syslog-servers 3ffe:aaaa:aaaa:aaaa::1, 3ffe:aaaa:aaaa:aaaa::2; } host cablemodem-2 { option docsis.device-id 00:06:5B:50:99:F6; option dhcpv6.time-servers 3ffe:dddd:aaaa:aaaa::1, 3ffe:dddd:aaaa:aaaa::2; option docsis.tftp-servers 3ffe:dddd:aaaa:aaaa::1, 3ffe:dddd:aaaa:aaaa::2; option dhcpv6.time-offset -14400; # -4 hours option docsis.cablelabs-configuration-file "bootfile.cfg"; option docsis.cablelabs-syslog-servers 3ffe:aaaa:aaaa:aaaa::1, 3ffe:aaaa:aaaa:aaaa::2; } dhcp-4.2.4/server/bootp.c000644 000765 000024 00000032422 11741122652 015170 0ustar00sarstaff000000 000000 /* bootp.c BOOTP Protocol support. */ /* * Copyright (c) 2009,2012 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 2004,2005,2007 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1995-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ * * This software has been written for Internet Systems Consortium * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. * To learn more about Internet Systems Consortium, see * ``https://www.isc.org/''. To learn more about Vixie Enterprises, * see ``http://www.vix.com''. To learn more about Nominum, Inc., see * ``http://www.nominum.com''. */ #include "dhcpd.h" #include #if defined (TRACING) # define send_packet trace_packet_send #endif void bootp (packet) struct packet *packet; { int result; struct host_decl *hp = (struct host_decl *)0; struct host_decl *host = (struct host_decl *)0; struct packet outgoing; struct dhcp_packet raw; struct sockaddr_in to; struct in_addr from; struct hardware hto; struct option_state *options = (struct option_state *)0; struct lease *lease = (struct lease *)0; unsigned i; struct data_string d1; struct option_cache *oc; char msgbuf [1024]; int ignorep; int peer_has_leases = 0; if (packet -> raw -> op != BOOTREQUEST) return; /* %Audit% This is log output. %2004.06.17,Safe% * If we truncate we hope the user can get a hint from the log. */ snprintf (msgbuf, sizeof msgbuf, "BOOTREQUEST from %s via %s", print_hw_addr (packet -> raw -> htype, packet -> raw -> hlen, packet -> raw -> chaddr), packet -> raw -> giaddr.s_addr ? inet_ntoa (packet -> raw -> giaddr) : packet -> interface -> name); if (!locate_network (packet)) { log_info ("%s: network unknown", msgbuf); return; } find_lease (&lease, packet, packet -> shared_network, 0, 0, (struct lease *)0, MDL); if (lease && lease->host) host_reference(&hp, lease->host, MDL); if (!lease || ((lease->flags & STATIC_LEASE) == 0)) { struct host_decl *h; /* We didn't find an applicable fixed-address host declaration. Just in case we may be able to dynamically assign an address, see if there's a host declaration that doesn't have an ip address associated with it. */ if (!hp) find_hosts_by_haddr(&hp, packet->raw->htype, packet->raw->chaddr, packet->raw->hlen, MDL); for (h = hp; h; h = h -> n_ipaddr) { if (!h -> fixed_addr) { host_reference(&host, h, MDL); break; } } if (hp) host_dereference(&hp, MDL); if (host) { host_reference(&hp, host, MDL); host_dereference(&host, MDL); } /* Allocate a lease if we have not yet found one. */ if (!lease) allocate_lease (&lease, packet, packet -> shared_network -> pools, &peer_has_leases); if (lease == NULL) { log_info("%s: BOOTP from dynamic client and no " "dynamic leases", msgbuf); goto out; } #if defined(FAILOVER_PROTOCOL) if ((lease->pool != NULL) && (lease->pool->failover_peer != NULL)) { dhcp_failover_state_t *peer; peer = lease->pool->failover_peer; /* If we are in a failover state that bars us from * answering, do not do so. * If we are in a cooperative state, load balance * (all) responses. */ if ((peer->service_state == not_responding) || (peer->service_state == service_startup)) { log_info("%s: not responding%s", msgbuf, peer->nrr); goto out; } else if((peer->service_state == cooperating) && !load_balance_mine(packet, peer)) { log_info("%s: load balance to peer %s", msgbuf, peer->name); goto out; } } #endif ack_lease (packet, lease, 0, 0, msgbuf, 0, hp); goto out; } /* Run the executable statements to compute the client and server options. */ option_state_allocate (&options, MDL); /* Execute the subnet statements. */ execute_statements_in_scope ((struct binding_value **)0, packet, lease, (struct client_state *)0, packet -> options, options, &lease -> scope, lease -> subnet -> group, (struct group *)0); /* Execute statements from class scopes. */ for (i = packet -> class_count; i > 0; i--) { execute_statements_in_scope ((struct binding_value **)0, packet, lease, (struct client_state *)0, packet -> options, options, &lease -> scope, packet -> classes [i - 1] -> group, lease -> subnet -> group); } /* Execute the host statements. */ if (hp != NULL) { execute_statements_in_scope (NULL, packet, lease, NULL, packet->options, options, &lease->scope, hp->group, lease->subnet->group); } /* Drop the request if it's not allowed for this client. */ if ((oc = lookup_option (&server_universe, options, SV_ALLOW_BOOTP)) && !evaluate_boolean_option_cache (&ignorep, packet, lease, (struct client_state *)0, packet -> options, options, &lease -> scope, oc, MDL)) { if (!ignorep) log_info ("%s: bootp disallowed", msgbuf); goto out; } if ((oc = lookup_option (&server_universe, options, SV_ALLOW_BOOTING)) && !evaluate_boolean_option_cache (&ignorep, packet, lease, (struct client_state *)0, packet -> options, options, &lease -> scope, oc, MDL)) { if (!ignorep) log_info ("%s: booting disallowed", msgbuf); goto out; } /* Set up the outgoing packet... */ memset (&outgoing, 0, sizeof outgoing); memset (&raw, 0, sizeof raw); outgoing.raw = &raw; /* If we didn't get a known vendor magic number on the way in, just copy the input options to the output. */ if (!packet -> options_valid && !(evaluate_boolean_option_cache (&ignorep, packet, lease, (struct client_state *)0, packet -> options, options, &lease -> scope, lookup_option (&server_universe, options, SV_ALWAYS_REPLY_RFC1048), MDL))) { memcpy (outgoing.raw -> options, packet -> raw -> options, DHCP_MAX_OPTION_LEN); outgoing.packet_length = BOOTP_MIN_LEN; } else { /* Use the subnet mask from the subnet declaration if no other mask has been provided. */ oc = (struct option_cache *)0; i = DHO_SUBNET_MASK; if (!lookup_option (&dhcp_universe, options, i)) { if (option_cache_allocate (&oc, MDL)) { if (make_const_data (&oc -> expression, lease -> subnet -> netmask.iabuf, lease -> subnet -> netmask.len, 0, 0, MDL)) { option_code_hash_lookup(&oc->option, dhcp_universe.code_hash, &i, 0, MDL); save_option (&dhcp_universe, options, oc); } option_cache_dereference (&oc, MDL); } } /* Pack the options into the buffer. Unlike DHCP, we can't pack options into the filename and server name buffers. */ outgoing.packet_length = cons_options (packet, outgoing.raw, lease, (struct client_state *)0, 0, packet -> options, options, &lease -> scope, 0, 0, 1, (struct data_string *)0, (const char *)0); if (outgoing.packet_length < BOOTP_MIN_LEN) outgoing.packet_length = BOOTP_MIN_LEN; } /* Take the fields that we care about... */ raw.op = BOOTREPLY; raw.htype = packet -> raw -> htype; raw.hlen = packet -> raw -> hlen; memcpy (raw.chaddr, packet -> raw -> chaddr, sizeof raw.chaddr); raw.hops = packet -> raw -> hops; raw.xid = packet -> raw -> xid; raw.secs = packet -> raw -> secs; raw.flags = packet -> raw -> flags; raw.ciaddr = packet -> raw -> ciaddr; /* yiaddr is an ipv4 address, it must be 4 octets. */ memcpy (&raw.yiaddr, lease->ip_addr.iabuf, 4); /* If we're always supposed to broadcast to this client, set the broadcast bit in the bootp flags field. */ if ((oc = lookup_option (&server_universe, options, SV_ALWAYS_BROADCAST)) && evaluate_boolean_option_cache (&ignorep, packet, lease, (struct client_state *)0, packet -> options, options, &lease -> scope, oc, MDL)) raw.flags |= htons (BOOTP_BROADCAST); /* Figure out the address of the next server. */ memset (&d1, 0, sizeof d1); oc = lookup_option (&server_universe, options, SV_NEXT_SERVER); if (oc && evaluate_option_cache (&d1, packet, lease, (struct client_state *)0, packet -> options, options, &lease -> scope, oc, MDL)) { /* If there was more than one answer, take the first. */ if (d1.len >= 4 && d1.data) memcpy (&raw.siaddr, d1.data, 4); data_string_forget (&d1, MDL); } else { if ((lease->subnet->shared_network->interface != NULL) && lease->subnet->shared_network->interface->address_count) raw.siaddr = lease->subnet->shared_network->interface->addresses[0]; else if (packet->interface->address_count) raw.siaddr = packet->interface->addresses[0]; } raw.giaddr = packet -> raw -> giaddr; /* Figure out the filename. */ oc = lookup_option (&server_universe, options, SV_FILENAME); if (oc && evaluate_option_cache (&d1, packet, lease, (struct client_state *)0, packet -> options, options, &lease -> scope, oc, MDL)) { memcpy (raw.file, d1.data, d1.len > sizeof raw.file ? sizeof raw.file : d1.len); if (sizeof raw.file > d1.len) memset (&raw.file [d1.len], 0, (sizeof raw.file) - d1.len); data_string_forget (&d1, MDL); } else memcpy (raw.file, packet -> raw -> file, sizeof raw.file); /* Choose a server name as above. */ oc = lookup_option (&server_universe, options, SV_SERVER_NAME); if (oc && evaluate_option_cache (&d1, packet, lease, (struct client_state *)0, packet -> options, options, &lease -> scope, oc, MDL)) { memcpy (raw.sname, d1.data, d1.len > sizeof raw.sname ? sizeof raw.sname : d1.len); if (sizeof raw.sname > d1.len) memset (&raw.sname [d1.len], 0, (sizeof raw.sname) - d1.len); data_string_forget (&d1, MDL); } /* Execute the commit statements, if there are any. */ execute_statements ((struct binding_value **)0, packet, lease, (struct client_state *)0, packet -> options, options, &lease -> scope, lease -> on_commit); /* We're done with the option state. */ option_state_dereference (&options, MDL); /* Set up the hardware destination address... */ hto.hbuf [0] = packet -> raw -> htype; hto.hlen = packet -> raw -> hlen + 1; memcpy (&hto.hbuf [1], packet -> raw -> chaddr, packet -> raw -> hlen); if (packet->interface->address_count) { from = packet->interface->addresses[0]; } else { log_error("%s: Interface %s appears to have no IPv4 " "addresses, and so dhcpd cannot select a source " "address.", msgbuf, packet->interface->name); goto out; } /* Report what we're doing... */ log_info("%s", msgbuf); log_info("BOOTREPLY for %s to %s (%s) via %s", piaddr(lease->ip_addr), ((hp != NULL) && (hp->name != NULL)) ? hp -> name : "unknown", print_hw_addr (packet->raw->htype, packet->raw->hlen, packet->raw->chaddr), packet->raw->giaddr.s_addr ? inet_ntoa (packet->raw->giaddr) : packet->interface->name); /* Set up the parts of the address that are in common. */ to.sin_family = AF_INET; #ifdef HAVE_SA_LEN to.sin_len = sizeof to; #endif memset (to.sin_zero, 0, sizeof to.sin_zero); /* If this was gatewayed, send it back to the gateway... */ if (raw.giaddr.s_addr) { to.sin_addr = raw.giaddr; to.sin_port = local_port; if (fallback_interface) { result = send_packet (fallback_interface, NULL, &raw, outgoing.packet_length, from, &to, &hto); if (result < 0) { log_error ("%s:%d: Failed to send %d byte long " "packet over %s interface.", MDL, outgoing.packet_length, fallback_interface->name); } goto out; } /* If it comes from a client that already knows its address and is not requesting a broadcast response, and we can unicast to a client without using the ARP protocol, sent it directly to that client. */ } else if (!(raw.flags & htons (BOOTP_BROADCAST)) && can_unicast_without_arp (packet -> interface)) { to.sin_addr = raw.yiaddr; to.sin_port = remote_port; /* Otherwise, broadcast it on the local network. */ } else { to.sin_addr = limited_broadcast; to.sin_port = remote_port; /* XXX */ } errno = 0; result = send_packet(packet->interface, packet, &raw, outgoing.packet_length, from, &to, &hto); if (result < 0) { log_error ("%s:%d: Failed to send %d byte long packet over %s" " interface.", MDL, outgoing.packet_length, packet->interface->name); } out: if (options) option_state_dereference (&options, MDL); if (lease) lease_dereference (&lease, MDL); if (hp) host_dereference (&hp, MDL); if (host) host_dereference (&host, MDL); } dhcp-4.2.4/server/class.c000644 000765 000024 00000020713 11352504373 015154 0ustar00sarstaff000000 000000 /* class.c Handling for client classes. */ /* * Copyright (c) 2004,2007,2009 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1998-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ * * This software has been written for Internet Systems Consortium * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. * To learn more about Internet Systems Consortium, see * ``https://www.isc.org/''. To learn more about Vixie Enterprises, * see ``http://www.vix.com''. To learn more about Nominum, Inc., see * ``http://www.nominum.com''. */ #include "dhcpd.h" struct collection default_collection = { (struct collection *)0, "default", (struct class *)0, }; struct collection *collections = &default_collection; struct executable_statement *default_classification_rules; int have_billing_classes; /* Build the default classification rule tree. */ void classification_setup () { /* eval ... */ default_classification_rules = (struct executable_statement *)0; if (!executable_statement_allocate (&default_classification_rules, MDL)) log_fatal ("Can't allocate check of default collection"); default_classification_rules -> op = eval_statement; /* check-collection "default" */ if (!expression_allocate (&default_classification_rules -> data.eval, MDL)) log_fatal ("Can't allocate default check expression"); default_classification_rules -> data.eval -> op = expr_check; default_classification_rules -> data.eval -> data.check = &default_collection; } void classify_client (packet) struct packet *packet; { execute_statements ((struct binding_value **)0, packet, (struct lease *)0, (struct client_state *)0, packet -> options, (struct option_state *)0, &global_scope, default_classification_rules); } int check_collection (packet, lease, collection) struct packet *packet; struct lease *lease; struct collection *collection; { struct class *class, *nc; struct data_string data; int matched = 0; int status; int ignorep; int classfound; for (class = collection -> classes; class; class = class -> nic) { #if defined (DEBUG_CLASS_MATCHING) log_info ("checking against class %s...", class -> name); #endif memset (&data, 0, sizeof data); /* If there is a "match if" expression, check it. If we get a match, and there's no subclass expression, it's a match. If we get a match and there is a subclass expression, then we check the submatch. If it's not a match, that's final - we don't check the submatch. */ if (class -> expr) { status = (evaluate_boolean_expression_result (&ignorep, packet, lease, (struct client_state *)0, packet -> options, (struct option_state *)0, lease ? &lease -> scope : &global_scope, class -> expr)); if (status) { if (!class -> submatch) { matched = 1; #if defined (DEBUG_CLASS_MATCHING) log_info ("matches class."); #endif classify (packet, class); continue; } } else continue; } /* Check to see if the client matches an existing subclass. If it doesn't, and this is a spawning class, spawn a new subclass and put the client in it. */ if (class -> submatch) { status = (evaluate_data_expression (&data, packet, lease, (struct client_state *)0, packet -> options, (struct option_state *)0, lease ? &lease -> scope : &global_scope, class -> submatch, MDL)); if (status && data.len) { nc = (struct class *)0; classfound = class_hash_lookup (&nc, class -> hash, (const char *)data.data, data.len, MDL); #ifdef LDAP_CONFIGURATION if (!classfound && find_subclass_in_ldap (class, &nc, &data)) classfound = 1; #endif if (classfound) { #if defined (DEBUG_CLASS_MATCHING) log_info ("matches subclass %s.", print_hex_1 (data.len, data.data, 60)); #endif data_string_forget (&data, MDL); classify (packet, nc); matched = 1; class_dereference (&nc, MDL); continue; } if (!class -> spawning) { data_string_forget (&data, MDL); continue; } /* XXX Write out the spawned class? */ #if defined (DEBUG_CLASS_MATCHING) log_info ("spawning subclass %s.", print_hex_1 (data.len, data.data, 60)); #endif status = class_allocate (&nc, MDL); group_reference (&nc -> group, class -> group, MDL); class_reference (&nc -> superclass, class, MDL); nc -> lease_limit = class -> lease_limit; nc -> dirty = 1; if (nc -> lease_limit) { nc -> billed_leases = (dmalloc (nc -> lease_limit * sizeof (struct lease *), MDL)); if (!nc -> billed_leases) { log_error ("no memory for%s", " billing"); data_string_forget (&nc -> hash_string, MDL); class_dereference (&nc, MDL); data_string_forget (&data, MDL); continue; } memset (nc -> billed_leases, 0, (nc -> lease_limit * sizeof nc -> billed_leases)); } data_string_copy (&nc -> hash_string, &data, MDL); data_string_forget (&data, MDL); if (!class -> hash) class_new_hash(&class->hash, SCLASS_HASH_SIZE, MDL); class_hash_add (class -> hash, (const char *) nc -> hash_string.data, nc -> hash_string.len, nc, MDL); classify (packet, nc); class_dereference (&nc, MDL); } } } return matched; } void classify (packet, class) struct packet *packet; struct class *class; { if (packet -> class_count < PACKET_MAX_CLASSES) class_reference (&packet -> classes [packet -> class_count++], class, MDL); else log_error ("too many classes match %s", print_hw_addr (packet -> raw -> htype, packet -> raw -> hlen, packet -> raw -> chaddr)); } isc_result_t unlink_class(struct class **class) { struct collection *lp; struct class *cp, *pp; for (lp = collections; lp; lp = lp -> next) { for (pp = 0, cp = lp -> classes; cp; pp = cp, cp = cp -> nic) if (cp == *class) { if (pp == 0) { lp->classes = cp->nic; } else { pp->nic = cp->nic; } cp->nic = 0; class_dereference(class, MDL); return ISC_R_SUCCESS; } } return ISC_R_NOTFOUND; } isc_result_t find_class (struct class **class, const char *name, const char *file, int line) { struct collection *lp; struct class *cp; for (lp = collections; lp; lp = lp -> next) { for (cp = lp -> classes; cp; cp = cp -> nic) if (cp -> name && !strcmp (name, cp -> name)) { return class_reference (class, cp, file, line); } } return ISC_R_NOTFOUND; } int unbill_class (lease, class) struct lease *lease; struct class *class; { int i; for (i = 0; i < class -> lease_limit; i++) if (class -> billed_leases [i] == lease) break; if (i == class -> lease_limit) { log_error ("lease %s unbilled with no billing arrangement.", piaddr (lease -> ip_addr)); return 0; } class_dereference (&lease -> billing_class, MDL); lease_dereference (&class -> billed_leases [i], MDL); class -> leases_consumed--; return 1; } int bill_class (lease, class) struct lease *lease; struct class *class; { int i; if (lease -> billing_class) { log_error ("lease billed with existing billing arrangement."); unbill_class (lease, lease -> billing_class); } if (class -> leases_consumed == class -> lease_limit) return 0; for (i = 0; i < class -> lease_limit; i++) if (!class -> billed_leases [i]) break; if (i == class -> lease_limit) { log_error ("class billing consumption disagrees with leases."); return 0; } lease_reference (&class -> billed_leases [i], lease, MDL); class_reference (&lease -> billing_class, class, MDL); class -> leases_consumed++; return 1; } dhcp-4.2.4/server/confpars.c000644 000765 000024 00000423502 11741323273 015665 0ustar00sarstaff000000 000000 /* confpars.c Parser for dhcpd config file... */ /* * Copyright (c) 2004-2012 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1995-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ * * This software has been written for Internet Systems Consortium * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. * To learn more about Internet Systems Consortium, see * ``https://www.isc.org/''. To learn more about Vixie Enterprises, * see ``http://www.vix.com''. To learn more about Nominum, Inc., see * ``http://www.nominum.com''. */ #include "dhcpd.h" static unsigned char global_host_once = 1; static unsigned char dhcpv6_class_once = 1; static int parse_binding_value(struct parse *cfile, struct binding_value *value); #if defined (TRACING) trace_type_t *trace_readconf_type; trace_type_t *trace_readleases_type; void parse_trace_setup () { trace_readconf_type = trace_type_register ("readconf", (void *)0, trace_conf_input, trace_conf_stop, MDL); trace_readleases_type = trace_type_register ("readleases", (void *)0, trace_conf_input, trace_conf_stop, MDL); } #endif /* conf-file :== parameters declarations END_OF_FILE parameters :== | parameter | parameters parameter declarations :== | declaration | declarations declaration */ isc_result_t readconf () { isc_result_t res; res = read_conf_file (path_dhcpd_conf, root_group, ROOT_GROUP, 0); #if defined(LDAP_CONFIGURATION) if (res != ISC_R_SUCCESS) return (res); return ldap_read_config (); #else return (res); #endif } isc_result_t read_conf_file (const char *filename, struct group *group, int group_type, int leasep) { int file; struct parse *cfile; isc_result_t status; #if defined (TRACING) char *fbuf, *dbuf; off_t flen; int result; unsigned tflen, ulen; trace_type_t *ttype; if (leasep) ttype = trace_readleases_type; else ttype = trace_readconf_type; /* If we're in playback, we need to snarf the contents of the named file out of the playback file rather than trying to open and read it. */ if (trace_playback ()) { dbuf = (char *)0; tflen = 0; status = trace_get_file (ttype, filename, &tflen, &dbuf); if (status != ISC_R_SUCCESS) return status; ulen = tflen; /* What we get back is filename\0contents, where contents is terminated just by the length. So we figure out the length of the filename, and subtract that and the NUL from the total length to get the length of the contents of the file. We make fbuf a pointer to the contents of the file, and leave dbuf as it is so we can free it later. */ tflen = strlen (dbuf); ulen = ulen - tflen - 1; fbuf = dbuf + tflen + 1; goto memfile; } #endif if ((file = open (filename, O_RDONLY)) < 0) { if (leasep) { log_error ("Can't open lease database %s: %m --", path_dhcpd_db); log_error (" check for failed database %s!", "rewrite attempt"); log_error ("Please read the dhcpd.leases manual%s", " page if you"); log_fatal ("don't know what to do about this."); } else { log_fatal ("Can't open %s: %m", filename); } } cfile = (struct parse *)0; #if defined (TRACING) flen = lseek (file, (off_t)0, SEEK_END); if (flen < 0) { boom: log_fatal ("Can't lseek on %s: %m", filename); } if (lseek (file, (off_t)0, SEEK_SET) < 0) goto boom; /* Can't handle files greater than 2^31-1. */ if (flen > 0x7FFFFFFFUL) log_fatal ("%s: file is too long to buffer.", filename); ulen = flen; /* Allocate a buffer that will be what's written to the tracefile, and also will be what we parse from. */ tflen = strlen (filename); dbuf = dmalloc (ulen + tflen + 1, MDL); if (!dbuf) log_fatal ("No memory for %s (%d bytes)", filename, ulen); /* Copy the name into the beginning, nul-terminated. */ strcpy (dbuf, filename); /* Load the file in after the NUL. */ fbuf = dbuf + tflen + 1; result = read (file, fbuf, ulen); if (result < 0) log_fatal ("Can't read in %s: %m", filename); if (result != ulen) log_fatal ("%s: short read of %d bytes instead of %d.", filename, ulen, result); close (file); memfile: /* If we're recording, write out the filename and file contents. */ if (trace_record ()) trace_write_packet (ttype, ulen + tflen + 1, dbuf, MDL); status = new_parse(&cfile, -1, fbuf, ulen, filename, 0); /* XXX */ #else status = new_parse(&cfile, file, NULL, 0, filename, 0); #endif if (status != ISC_R_SUCCESS || cfile == NULL) return status; if (leasep) status = lease_file_subparse (cfile); else status = conf_file_subparse (cfile, group, group_type); end_parse (&cfile); #if defined (TRACING) dfree (dbuf, MDL); #endif return status; } #if defined (TRACING) void trace_conf_input (trace_type_t *ttype, unsigned len, char *data) { char *fbuf; unsigned flen; unsigned tflen; struct parse *cfile = (struct parse *)0; static int postconf_initialized; static int leaseconf_initialized; isc_result_t status; /* Do what's done above, except that we don't have to read in the data, because it's already been read for us. */ tflen = strlen (data); flen = len - tflen - 1; fbuf = data + tflen + 1; /* If we're recording, write out the filename and file contents. */ if (trace_record ()) trace_write_packet (ttype, len, data, MDL); status = new_parse(&cfile, -1, fbuf, flen, data, 0); if (status == ISC_R_SUCCESS || cfile != NULL) { if (ttype == trace_readleases_type) lease_file_subparse (cfile); else conf_file_subparse (cfile, root_group, ROOT_GROUP); end_parse (&cfile); } /* Postconfiguration needs to be done after the config file has been loaded. */ if (!postconf_initialized && ttype == trace_readconf_type) { postconf_initialization (0); postconf_initialized = 1; } if (!leaseconf_initialized && ttype == trace_readleases_type) { db_startup (0); leaseconf_initialized = 1; postdb_startup (); } } void trace_conf_stop (trace_type_t *ttype) { } #endif /* conf-file :== parameters declarations END_OF_FILE parameters :== | parameter | parameters parameter declarations :== | declaration | declarations declaration */ isc_result_t conf_file_subparse (struct parse *cfile, struct group *group, int group_type) { const char *val; enum dhcp_token token; int declaration = 0; int status; do { token = peek_token (&val, (unsigned *)0, cfile); if (token == END_OF_FILE) break; declaration = parse_statement (cfile, group, group_type, (struct host_decl *)0, declaration); } while (1); token = next_token (&val, (unsigned *)0, cfile); status = cfile->warnings_occurred ? DHCP_R_BADPARSE : ISC_R_SUCCESS; return status; } /* lease-file :== lease-declarations END_OF_FILE lease-statements :== | lease-declaration | lease-declarations lease-declaration */ isc_result_t lease_file_subparse (struct parse *cfile) { const char *val; enum dhcp_token token; isc_result_t status; do { token = next_token (&val, (unsigned *)0, cfile); if (token == END_OF_FILE) break; if (token == LEASE) { struct lease *lease = (struct lease *)0; if (parse_lease_declaration (&lease, cfile)) { enter_lease (lease); lease_dereference (&lease, MDL); } else parse_warn (cfile, "possibly corrupt lease file"); } else if (token == IA_NA) { parse_ia_na_declaration(cfile); } else if (token == IA_TA) { parse_ia_ta_declaration(cfile); } else if (token == IA_PD) { parse_ia_pd_declaration(cfile); } else if (token == CLASS) { parse_class_declaration(0, cfile, root_group, CLASS_TYPE_CLASS); } else if (token == SUBCLASS) { parse_class_declaration(0, cfile, root_group, CLASS_TYPE_SUBCLASS); } else if (token == HOST) { parse_host_declaration (cfile, root_group); } else if (token == GROUP) { parse_group_declaration (cfile, root_group); #if defined (FAILOVER_PROTOCOL) } else if (token == FAILOVER) { parse_failover_state_declaration (cfile, (dhcp_failover_state_t *)0); #endif #ifdef DHCPv6 } else if (token == SERVER_DUID) { parse_server_duid(cfile); #endif /* DHCPv6 */ } else { log_error ("Corrupt lease file - possible data loss!"); skip_to_semi (cfile); } } while (1); status = cfile->warnings_occurred ? DHCP_R_BADPARSE : ISC_R_SUCCESS; return status; } /* statement :== parameter | declaration parameter :== DEFAULT_LEASE_TIME lease_time | MAX_LEASE_TIME lease_time | DYNAMIC_BOOTP_LEASE_CUTOFF date | DYNAMIC_BOOTP_LEASE_LENGTH lease_time | BOOT_UNKNOWN_CLIENTS boolean | ONE_LEASE_PER_CLIENT boolean | GET_LEASE_HOSTNAMES boolean | USE_HOST_DECL_NAME boolean | NEXT_SERVER ip-addr-or-hostname SEMI | option_parameter | SERVER-IDENTIFIER ip-addr-or-hostname SEMI | FILENAME string-parameter | SERVER_NAME string-parameter | hardware-parameter | fixed-address-parameter | ALLOW allow-deny-keyword | DENY allow-deny-keyword | USE_LEASE_ADDR_FOR_DEFAULT_ROUTE boolean | AUTHORITATIVE | NOT AUTHORITATIVE declaration :== host-declaration | group-declaration | shared-network-declaration | subnet-declaration | VENDOR_CLASS class-declaration | USER_CLASS class-declaration | RANGE address-range-declaration */ int parse_statement (cfile, group, type, host_decl, declaration) struct parse *cfile; struct group *group; int type; struct host_decl *host_decl; int declaration; { enum dhcp_token token; const char *val; struct shared_network *share; char *n; struct hardware hardware; struct executable_statement *et, *ep; struct option *option = NULL; struct option_cache *cache; int lose; int known; isc_result_t status; unsigned code; token = peek_token (&val, (unsigned *)0, cfile); switch (token) { case INCLUDE: next_token (&val, (unsigned *)0, cfile); token = next_token (&val, (unsigned *)0, cfile); if (token != STRING) { parse_warn (cfile, "filename string expected."); skip_to_semi (cfile); } else { status = read_conf_file (val, group, type, 0); if (status != ISC_R_SUCCESS) parse_warn (cfile, "%s: bad parse.", val); parse_semi (cfile); } return 1; case HOST: next_token (&val, (unsigned *)0, cfile); if (type != HOST_DECL && type != CLASS_DECL) { if (global_host_once && (type == SUBNET_DECL || type == SHARED_NET_DECL)) { global_host_once = 0; log_error("WARNING: Host declarations are " "global. They are not limited to " "the scope you declared them in."); } parse_host_declaration (cfile, group); } else { parse_warn (cfile, "host declarations not allowed here."); skip_to_semi (cfile); } return 1; case GROUP: next_token (&val, (unsigned *)0, cfile); if (type != HOST_DECL && type != CLASS_DECL) parse_group_declaration (cfile, group); else { parse_warn (cfile, "group declarations not allowed here."); skip_to_semi (cfile); } return 1; case SHARED_NETWORK: next_token (&val, (unsigned *)0, cfile); if (type == SHARED_NET_DECL || type == HOST_DECL || type == SUBNET_DECL || type == CLASS_DECL) { parse_warn (cfile, "shared-network parameters not %s.", "allowed here"); skip_to_semi (cfile); break; } parse_shared_net_declaration (cfile, group); return 1; case SUBNET: case SUBNET6: next_token (&val, (unsigned *)0, cfile); if (type == HOST_DECL || type == SUBNET_DECL || type == CLASS_DECL) { parse_warn (cfile, "subnet declarations not allowed here."); skip_to_semi (cfile); return 1; } /* If we're in a subnet declaration, just do the parse. */ if (group->shared_network != NULL) { if (token == SUBNET) { parse_subnet_declaration(cfile, group->shared_network); } else { parse_subnet6_declaration(cfile, group->shared_network); } break; } /* * Otherwise, cons up a fake shared network structure * and populate it with the lone subnet...because the * intention most likely is to refer to the entire link * by shorthand, any configuration inside the subnet is * actually placed in the shared-network's group. */ share = NULL; status = shared_network_allocate (&share, MDL); if (status != ISC_R_SUCCESS) log_fatal ("Can't allocate shared subnet: %s", isc_result_totext (status)); if (!clone_group (&share -> group, group, MDL)) log_fatal ("Can't allocate group for shared net"); shared_network_reference (&share -> group -> shared_network, share, MDL); /* * This is an implicit shared network, not explicit in * the config. */ share->flags |= SHARED_IMPLICIT; if (token == SUBNET) { parse_subnet_declaration(cfile, share); } else { parse_subnet6_declaration(cfile, share); } /* share -> subnets is the subnet we just parsed. */ if (share->subnets) { interface_reference(&share->interface, share->subnets->interface, MDL); /* Make the shared network name from network number. */ if (token == SUBNET) { n = piaddrmask(&share->subnets->net, &share->subnets->netmask); } else { n = piaddrcidr(&share->subnets->net, share->subnets->prefix_len); } share->name = strdup(n); if (share->name == NULL) log_fatal("Out of memory allocating default " "shared network name (\"%s\").", n); /* Copy the authoritative parameter from the subnet, since there is no opportunity to declare it here. */ share->group->authoritative = share->subnets->group->authoritative; enter_shared_network(share); } shared_network_dereference(&share, MDL); return 1; case VENDOR_CLASS: next_token (&val, (unsigned *)0, cfile); if (type == CLASS_DECL) { parse_warn (cfile, "class declarations not allowed here."); skip_to_semi (cfile); break; } parse_class_declaration(NULL, cfile, group, CLASS_TYPE_VENDOR); return 1; case USER_CLASS: next_token (&val, (unsigned *)0, cfile); if (type == CLASS_DECL) { parse_warn (cfile, "class declarations not allowed here."); skip_to_semi (cfile); break; } parse_class_declaration(NULL, cfile, group, CLASS_TYPE_USER); return 1; case CLASS: next_token (&val, (unsigned *)0, cfile); if (type == CLASS_DECL) { parse_warn (cfile, "class declarations not allowed here."); skip_to_semi (cfile); break; } parse_class_declaration(NULL, cfile, group, CLASS_TYPE_CLASS); return 1; case SUBCLASS: next_token (&val, (unsigned *)0, cfile); if (type == CLASS_DECL) { parse_warn (cfile, "class declarations not allowed here."); skip_to_semi (cfile); break; } parse_class_declaration(NULL, cfile, group, CLASS_TYPE_SUBCLASS); return 1; case HARDWARE: next_token (&val, (unsigned *)0, cfile); memset (&hardware, 0, sizeof hardware); if (host_decl && memcmp(&hardware, &(host_decl->interface), sizeof(hardware)) != 0) { parse_warn(cfile, "Host %s hardware address already " "configured.", host_decl->name); break; } parse_hardware_param (cfile, &hardware); if (host_decl) host_decl -> interface = hardware; else parse_warn (cfile, "hardware address parameter %s", "not allowed here."); break; case FIXED_ADDR: case FIXED_ADDR6: next_token(&val, NULL, cfile); cache = NULL; if (parse_fixed_addr_param(&cache, cfile, token)) { if (host_decl) { if (host_decl->fixed_addr) { option_cache_dereference(&cache, MDL); parse_warn(cfile, "Only one fixed address " "declaration per host."); } else { host_decl->fixed_addr = cache; } } else { parse_warn(cfile, "fixed-address parameter not " "allowed here."); option_cache_dereference(&cache, MDL); } } break; case POOL: next_token (&val, (unsigned *)0, cfile); if (type == POOL_DECL) { parse_warn (cfile, "pool declared within pool."); skip_to_semi(cfile); } else if (type != SUBNET_DECL && type != SHARED_NET_DECL) { parse_warn (cfile, "pool declared outside of network"); skip_to_semi(cfile); } else parse_pool_statement (cfile, group, type); return declaration; case RANGE: next_token (&val, (unsigned *)0, cfile); if (type != SUBNET_DECL || !group -> subnet) { parse_warn (cfile, "range declaration not allowed here."); skip_to_semi (cfile); return declaration; } parse_address_range (cfile, group, type, (struct pool *)0, (struct lease **)0); return declaration; #ifdef DHCPv6 case RANGE6: next_token(NULL, NULL, cfile); if ((type != SUBNET_DECL) || (group->subnet == NULL)) { parse_warn (cfile, "range6 declaration not allowed here."); skip_to_semi(cfile); return declaration; } parse_address_range6(cfile, group); return declaration; case PREFIX6: next_token(NULL, NULL, cfile); if ((type != SUBNET_DECL) || (group->subnet == NULL)) { parse_warn (cfile, "prefix6 declaration not allowed here."); skip_to_semi(cfile); return declaration; } parse_prefix6(cfile, group); return declaration; case FIXED_PREFIX6: next_token(&val, NULL, cfile); if (!host_decl) { parse_warn (cfile, "fixed-prefix6 declaration not " "allowed here."); skip_to_semi(cfile); break; } parse_fixed_prefix6(cfile, host_decl); break; #endif /* DHCPv6 */ case TOKEN_NOT: token = next_token (&val, (unsigned *)0, cfile); token = next_token (&val, (unsigned *)0, cfile); switch (token) { case AUTHORITATIVE: group -> authoritative = 0; goto authoritative; default: parse_warn (cfile, "expecting assertion"); skip_to_semi (cfile); break; } break; case AUTHORITATIVE: token = next_token (&val, (unsigned *)0, cfile); group -> authoritative = 1; authoritative: if (type == HOST_DECL) parse_warn (cfile, "authority makes no sense here."); parse_semi (cfile); break; /* "server-identifier" is a special hack, equivalent to "option dhcp-server-identifier". */ case SERVER_IDENTIFIER: code = DHO_DHCP_SERVER_IDENTIFIER; if (!option_code_hash_lookup(&option, dhcp_universe.code_hash, &code, 0, MDL)) log_fatal("Server identifier not in hash (%s:%d).", MDL); token = next_token (&val, (unsigned *)0, cfile); goto finish_option; case OPTION: token = next_token (&val, (unsigned *)0, cfile); token = peek_token (&val, (unsigned *)0, cfile); if (token == SPACE) { if (type != ROOT_GROUP) { parse_warn (cfile, "option space definitions %s", "may not be scoped."); skip_to_semi (cfile); break; } parse_option_space_decl (cfile); return declaration; } known = 0; status = parse_option_name(cfile, 1, &known, &option); if (status == ISC_R_SUCCESS) { token = peek_token (&val, (unsigned *)0, cfile); if (token == CODE) { if (type != ROOT_GROUP) { parse_warn (cfile, "option definitions%s", " may not be scoped."); skip_to_semi (cfile); option_dereference(&option, MDL); break; } next_token (&val, (unsigned *)0, cfile); /* * If the option was known, remove it from the * code and name hashes before redefining it. */ if (known) { option_name_hash_delete( option->universe->name_hash, option->name, 0, MDL); option_code_hash_delete( option->universe->code_hash, &option->code, 0, MDL); } parse_option_code_definition(cfile, option); option_dereference(&option, MDL); return declaration; } /* If this wasn't an option code definition, don't allow an unknown option. */ if (!known) { parse_warn (cfile, "unknown option %s.%s", option -> universe -> name, option -> name); skip_to_semi (cfile); option_dereference(&option, MDL); return declaration; } finish_option: et = (struct executable_statement *)0; if (!parse_option_statement (&et, cfile, 1, option, supersede_option_statement)) return declaration; option_dereference(&option, MDL); goto insert_statement; } else return declaration; break; case FAILOVER: if (type != ROOT_GROUP && type != SHARED_NET_DECL) { parse_warn (cfile, "failover peers may only be %s", "defined in shared-network"); log_error ("declarations and the outer scope."); skip_to_semi (cfile); break; } token = next_token (&val, (unsigned *)0, cfile); #if defined (FAILOVER_PROTOCOL) parse_failover_peer (cfile, group, type); #else parse_warn (cfile, "No failover support."); skip_to_semi (cfile); #endif break; #ifdef DHCPv6 case SERVER_DUID: parse_server_duid_conf(cfile); break; #endif /* DHCPv6 */ default: et = (struct executable_statement *)0; lose = 0; if (!parse_executable_statement (&et, cfile, &lose, context_any)) { if (!lose) { if (declaration) parse_warn (cfile, "expecting a declaration"); else parse_warn (cfile, "expecting a parameter %s", "or declaration"); skip_to_semi (cfile); } return declaration; } if (!et) return declaration; insert_statement: if (group -> statements) { int multi = 0; /* If this set of statements is only referenced by this group, just add the current statement to the end of the chain. */ for (ep = group -> statements; ep -> next; ep = ep -> next) if (ep -> refcnt > 1) /* XXX */ multi = 1; if (!multi) { executable_statement_reference (&ep -> next, et, MDL); executable_statement_dereference (&et, MDL); return declaration; } /* Otherwise, make a parent chain, and put the current group statements first and the new statement in the next pointer. */ ep = (struct executable_statement *)0; if (!executable_statement_allocate (&ep, MDL)) log_fatal ("No memory for statements."); ep -> op = statements_statement; executable_statement_reference (&ep -> data.statements, group -> statements, MDL); executable_statement_reference (&ep -> next, et, MDL); executable_statement_dereference (&group -> statements, MDL); executable_statement_reference (&group -> statements, ep, MDL); executable_statement_dereference (&ep, MDL); } else { executable_statement_reference (&group -> statements, et, MDL); } executable_statement_dereference (&et, MDL); return declaration; } return 0; } #if defined (FAILOVER_PROTOCOL) void parse_failover_peer (cfile, group, type) struct parse *cfile; struct group *group; int type; { enum dhcp_token token; const char *val; dhcp_failover_state_t *peer; u_int32_t *tp; char *name; u_int32_t split; u_int8_t hba [32]; unsigned hba_len = sizeof hba; int i; struct expression *expr; isc_result_t status; dhcp_failover_config_t *cp; token = next_token (&val, (unsigned *)0, cfile); if (token != PEER) { parse_warn (cfile, "expecting \"peer\""); skip_to_semi (cfile); return; } token = next_token (&val, (unsigned *)0, cfile); if (is_identifier (token) || token == STRING) { name = dmalloc (strlen (val) + 1, MDL); if (!name) log_fatal ("no memory for peer name %s", name); strcpy (name, val); } else { parse_warn (cfile, "expecting failover peer name."); skip_to_semi (cfile); return; } /* See if there's a peer declaration by this name. */ peer = (dhcp_failover_state_t *)0; find_failover_peer (&peer, name, MDL); token = next_token (&val, (unsigned *)0, cfile); if (token == SEMI) { dfree (name, MDL); if (type != SHARED_NET_DECL) parse_warn (cfile, "failover peer reference not %s", "in shared-network declaration"); else { if (!peer) { parse_warn (cfile, "reference to unknown%s%s", " failover peer ", name); return; } dhcp_failover_state_reference (&group -> shared_network -> failover_peer, peer, MDL); } dhcp_failover_state_dereference (&peer, MDL); return; } else if (token == STATE) { if (!peer) { parse_warn (cfile, "state declaration for unknown%s%s", " failover peer ", name); return; } parse_failover_state_declaration (cfile, peer); dhcp_failover_state_dereference (&peer, MDL); return; } else if (token != LBRACE) { parse_warn (cfile, "expecting left brace"); skip_to_semi (cfile); } /* Make sure this isn't a redeclaration. */ if (peer) { parse_warn (cfile, "redeclaration of failover peer %s", name); skip_to_rbrace (cfile, 1); dhcp_failover_state_dereference (&peer, MDL); return; } status = dhcp_failover_state_allocate (&peer, MDL); if (status != ISC_R_SUCCESS) log_fatal ("Can't allocate failover peer %s: %s", name, isc_result_totext (status)); /* Save the name. */ peer -> name = name; do { cp = &peer -> me; peer: token = next_token (&val, (unsigned *)0, cfile); switch (token) { case RBRACE: break; case PRIMARY: peer -> i_am = primary; break; case SECONDARY: peer -> i_am = secondary; if (peer -> hba) parse_warn (cfile, "secondary may not define %s", "load balance settings."); break; case PEER: cp = &peer -> partner; goto peer; case ADDRESS: expr = (struct expression *)0; if (!parse_ip_addr_or_hostname (&expr, cfile, 0)) { skip_to_rbrace (cfile, 1); dhcp_failover_state_dereference (&peer, MDL); return; } option_cache (&cp -> address, (struct data_string *)0, expr, (struct option *)0, MDL); expression_dereference (&expr, MDL); break; case PORT: token = next_token (&val, (unsigned *)0, cfile); if (token != NUMBER) { parse_warn (cfile, "expecting number"); skip_to_rbrace (cfile, 1); } cp -> port = atoi (val); break; case MAX_LEASE_MISBALANCE: tp = &peer->max_lease_misbalance; goto parse_idle; case MAX_LEASE_OWNERSHIP: tp = &peer->max_lease_ownership; goto parse_idle; case MAX_BALANCE: tp = &peer->max_balance; goto parse_idle; case MIN_BALANCE: tp = &peer->min_balance; goto parse_idle; case AUTO_PARTNER_DOWN: tp = &peer->auto_partner_down; goto parse_idle; case MAX_RESPONSE_DELAY: tp = &cp -> max_response_delay; parse_idle: token = next_token (&val, (unsigned *)0, cfile); if (token != NUMBER) { parse_warn (cfile, "expecting number."); skip_to_rbrace (cfile, 1); dhcp_failover_state_dereference (&peer, MDL); return; } *tp = atoi (val); break; case MAX_UNACKED_UPDATES: tp = &cp -> max_flying_updates; goto parse_idle; case MCLT: tp = &peer -> mclt; goto parse_idle; case HBA: hba_len = 32; if (peer -> i_am == secondary) parse_warn (cfile, "secondary may not define %s", "load balance settings."); if (!parse_numeric_aggregate (cfile, hba, &hba_len, COLON, 16, 8)) { skip_to_rbrace (cfile, 1); dhcp_failover_state_dereference (&peer, MDL); return; } if (hba_len != 32) { parse_warn (cfile, "HBA must be exactly 32 bytes."); dfree (hba, MDL); break; } make_hba: peer -> hba = dmalloc (32, MDL); if (!peer -> hba) { dfree (peer -> name, MDL); dfree (peer, MDL); } memcpy (peer -> hba, hba, 32); break; case SPLIT: token = next_token (&val, (unsigned *)0, cfile); if (peer -> i_am == secondary) parse_warn (cfile, "secondary may not define %s", "load balance settings."); if (token != NUMBER) { parse_warn (cfile, "expecting number"); skip_to_rbrace (cfile, 1); dhcp_failover_state_dereference (&peer, MDL); return; } split = atoi (val); if (split > 255) { parse_warn (cfile, "split must be < 256"); } else { memset (hba, 0, sizeof hba); for (i = 0; i < split; i++) { if (i < split) hba [i / 8] |= (1 << (i & 7)); } goto make_hba; } break; case LOAD: token = next_token (&val, (unsigned *)0, cfile); if (token != BALANCE) { parse_warn (cfile, "expecting 'balance'"); badload: skip_to_rbrace (cfile, 1); break; } token = next_token (&val, (unsigned *)0, cfile); if (token != TOKEN_MAX) { parse_warn (cfile, "expecting 'max'"); goto badload; } token = next_token (&val, (unsigned *)0, cfile); if (token != SECONDS) { parse_warn (cfile, "expecting 'secs'"); goto badload; } token = next_token (&val, (unsigned *)0, cfile); if (token != NUMBER) { parse_warn (cfile, "expecting number"); goto badload; } peer -> load_balance_max_secs = atoi (val); break; default: parse_warn (cfile, "invalid statement in peer declaration"); skip_to_rbrace (cfile, 1); dhcp_failover_state_dereference (&peer, MDL); return; } if (token != RBRACE && !parse_semi (cfile)) { skip_to_rbrace (cfile, 1); dhcp_failover_state_dereference (&peer, MDL); return; } } while (token != RBRACE); /* me.address can be null; the failover link initiate code tries to * derive a reasonable address to use. */ if (!peer -> partner.address) parse_warn (cfile, "peer address may not be omitted"); if (!peer->me.port) peer->me.port = DEFAULT_FAILOVER_PORT; if (!peer->partner.port) peer->partner.port = DEFAULT_FAILOVER_PORT; if (peer -> i_am == primary) { if (!peer -> hba) { parse_warn (cfile, "primary failover server must have hba or split."); } else if (!peer -> mclt) { parse_warn (cfile, "primary failover server must have mclt."); } } if (!peer->max_lease_misbalance) peer->max_lease_misbalance = DEFAULT_MAX_LEASE_MISBALANCE; if (!peer->max_lease_ownership) peer->max_lease_ownership = DEFAULT_MAX_LEASE_OWNERSHIP; if (!peer->max_balance) peer->max_balance = DEFAULT_MAX_BALANCE_TIME; if (!peer->min_balance) peer->min_balance = DEFAULT_MIN_BALANCE_TIME; if (!peer->me.max_flying_updates) peer->me.max_flying_updates = DEFAULT_MAX_FLYING_UPDATES; if (!peer->me.max_response_delay) peer->me.max_response_delay = DEFAULT_MAX_RESPONSE_DELAY; if (type == SHARED_NET_DECL) group->shared_network->failover_peer = peer; /* Set the initial state. */ if (peer -> i_am == primary) { peer -> me.state = recover; peer -> me.stos = cur_time; peer -> partner.state = unknown_state; peer -> partner.stos = cur_time; } else { peer -> me.state = recover; peer -> me.stos = cur_time; peer -> partner.state = unknown_state; peer -> partner.stos = cur_time; } status = enter_failover_peer (peer); if (status != ISC_R_SUCCESS) parse_warn (cfile, "failover peer %s: %s", peer -> name, isc_result_totext (status)); dhcp_failover_state_dereference (&peer, MDL); } void parse_failover_state_declaration (struct parse *cfile, dhcp_failover_state_t *peer) { enum dhcp_token token; const char *val; char *name; dhcp_failover_state_t *state; dhcp_failover_config_t *cp; if (!peer) { token = next_token (&val, (unsigned *)0, cfile); if (token != PEER) { parse_warn (cfile, "expecting \"peer\""); skip_to_semi (cfile); return; } token = next_token (&val, (unsigned *)0, cfile); if (is_identifier (token) || token == STRING) { name = dmalloc (strlen (val) + 1, MDL); if (!name) log_fatal ("failover peer name %s: no memory", name); strcpy (name, val); } else { parse_warn (cfile, "expecting failover peer name."); skip_to_semi (cfile); return; } /* See if there's a peer declaration by this name. */ state = (dhcp_failover_state_t *)0; find_failover_peer (&state, name, MDL); if (!state) { parse_warn (cfile, "unknown failover peer: %s", name); skip_to_semi (cfile); return; } token = next_token (&val, (unsigned *)0, cfile); if (token != STATE) { parse_warn (cfile, "expecting 'state'"); if (token != SEMI) skip_to_semi (cfile); return; } } else { state = (dhcp_failover_state_t *)0; dhcp_failover_state_reference (&state, peer, MDL); } token = next_token (&val, (unsigned *)0, cfile); if (token != LBRACE) { parse_warn (cfile, "expecting left brace"); if (token != SEMI) skip_to_semi (cfile); dhcp_failover_state_dereference (&state, MDL); return; } do { token = next_token (&val, (unsigned *)0, cfile); switch (token) { case RBRACE: break; case MY: cp = &state -> me; do_state: token = next_token (&val, (unsigned *)0, cfile); if (token != STATE) { parse_warn (cfile, "expecting 'state'"); goto bogus; } parse_failover_state (cfile, &cp -> state, &cp -> stos); break; case PARTNER: cp = &state -> partner; goto do_state; case MCLT: if (state -> i_am == primary) { parse_warn (cfile, "mclt not valid for primary"); goto bogus; } token = next_token (&val, (unsigned *)0, cfile); if (token != NUMBER) { parse_warn (cfile, "expecting a number."); goto bogus; } state -> mclt = atoi (val); parse_semi (cfile); break; default: parse_warn (cfile, "expecting state setting."); bogus: skip_to_rbrace (cfile, 1); dhcp_failover_state_dereference (&state, MDL); return; } } while (token != RBRACE); dhcp_failover_state_dereference (&state, MDL); } void parse_failover_state (cfile, state, stos) struct parse *cfile; enum failover_state *state; TIME *stos; { enum dhcp_token token; const char *val; enum failover_state state_in; TIME stos_in; token = next_token (&val, (unsigned *)0, cfile); switch (token) { case UNKNOWN_STATE: state_in = unknown_state; break; case PARTNER_DOWN: state_in = partner_down; break; case NORMAL: state_in = normal; break; case COMMUNICATIONS_INTERRUPTED: state_in = communications_interrupted; break; case CONFLICT_DONE: state_in = conflict_done; break; case RESOLUTION_INTERRUPTED: state_in = resolution_interrupted; break; case POTENTIAL_CONFLICT: state_in = potential_conflict; break; case RECOVER: state_in = recover; break; case RECOVER_WAIT: state_in = recover_wait; break; case RECOVER_DONE: state_in = recover_done; break; case SHUTDOWN: state_in = shut_down; break; case PAUSED: state_in = paused; break; case STARTUP: state_in = startup; break; default: parse_warn (cfile, "unknown failover state"); skip_to_semi (cfile); return; } token = next_token (&val, (unsigned *)0, cfile); if (token == SEMI) { stos_in = cur_time; } else { if (token != AT) { parse_warn (cfile, "expecting \"at\""); skip_to_semi (cfile); return; } stos_in = parse_date (cfile); if (!stos_in) return; } /* Now that we've apparently gotten a clean parse, we can trust that this is a state that was fully committed to disk, so we can install it. */ *stos = stos_in; *state = state_in; } #endif /* defined (FAILOVER_PROTOCOL) */ /* Permit_list_match returns 1 if every element of the permit list in lhs also appears in rhs. Note that this doesn't by itself mean that the two lists are equal - to check for equality, permit_list_match has to return 1 with (list1, list2) and with (list2, list1). */ int permit_list_match (struct permit *lhs, struct permit *rhs) { struct permit *plp, *prp; int matched; if (!lhs) return 1; if (!rhs) return 0; for (plp = lhs; plp; plp = plp -> next) { matched = 0; for (prp = rhs; prp; prp = prp -> next) { if (prp -> type == plp -> type && (prp -> type != permit_class || prp -> class == plp -> class)) { matched = 1; break; } } if (!matched) return 0; } return 1; } void parse_pool_statement (cfile, group, type) struct parse *cfile; struct group *group; int type; { enum dhcp_token token; const char *val; int done = 0; struct pool *pool, **p, *pp; struct permit *permit; struct permit **permit_head; int declaration = 0; isc_result_t status; struct lease *lpchain = (struct lease *)0, *lp; TIME t; int is_allow = 0; pool = (struct pool *)0; status = pool_allocate (&pool, MDL); if (status != ISC_R_SUCCESS) log_fatal ("no memory for pool: %s", isc_result_totext (status)); if (type == SUBNET_DECL) shared_network_reference (&pool -> shared_network, group -> subnet -> shared_network, MDL); else if (type == SHARED_NET_DECL) shared_network_reference (&pool -> shared_network, group -> shared_network, MDL); else { parse_warn(cfile, "Dynamic pools are only valid inside " "subnet or shared-network statements."); skip_to_semi(cfile); return; } if (pool->shared_network == NULL || !clone_group(&pool->group, pool->shared_network->group, MDL)) log_fatal("can't clone pool group."); #if defined (FAILOVER_PROTOCOL) /* Inherit the failover peer from the shared network. */ if (pool -> shared_network -> failover_peer) dhcp_failover_state_reference (&pool -> failover_peer, pool -> shared_network -> failover_peer, MDL); #endif if (!parse_lbrace (cfile)) { pool_dereference (&pool, MDL); return; } do { token = peek_token (&val, (unsigned *)0, cfile); switch (token) { case TOKEN_NO: next_token (&val, (unsigned *)0, cfile); token = next_token (&val, (unsigned *)0, cfile); if (token != FAILOVER || (token = next_token (&val, (unsigned *)0, cfile)) != PEER) { parse_warn (cfile, "expecting \"failover peer\"."); skip_to_semi (cfile); continue; } #if defined (FAILOVER_PROTOCOL) if (pool -> failover_peer) dhcp_failover_state_dereference (&pool -> failover_peer, MDL); #endif break; #if defined (FAILOVER_PROTOCOL) case FAILOVER: next_token (&val, (unsigned *)0, cfile); token = next_token (&val, (unsigned *)0, cfile); if (token != PEER) { parse_warn (cfile, "expecting 'peer'."); skip_to_semi (cfile); break; } token = next_token (&val, (unsigned *)0, cfile); if (token != STRING) { parse_warn (cfile, "expecting string."); skip_to_semi (cfile); break; } if (pool -> failover_peer) dhcp_failover_state_dereference (&pool -> failover_peer, MDL); status = find_failover_peer (&pool -> failover_peer, val, MDL); if (status != ISC_R_SUCCESS) parse_warn (cfile, "failover peer %s: %s", val, isc_result_totext (status)); else pool -> failover_peer -> pool_count++; parse_semi (cfile); break; #endif case RANGE: next_token (&val, (unsigned *)0, cfile); parse_address_range (cfile, group, type, pool, &lpchain); break; case ALLOW: permit_head = &pool -> permit_list; /* remember the clause which leads to get_permit */ is_allow = 1; get_permit: permit = new_permit (MDL); if (!permit) log_fatal ("no memory for permit"); next_token (&val, (unsigned *)0, cfile); token = next_token (&val, (unsigned *)0, cfile); switch (token) { case UNKNOWN: permit -> type = permit_unknown_clients; get_clients: if (next_token (&val, (unsigned *)0, cfile) != CLIENTS) { parse_warn (cfile, "expecting \"clients\""); skip_to_semi (cfile); free_permit (permit, MDL); continue; } break; case KNOWN_CLIENTS: permit -> type = permit_known_clients; break; case UNKNOWN_CLIENTS: permit -> type = permit_unknown_clients; break; case KNOWN: permit -> type = permit_known_clients; goto get_clients; case AUTHENTICATED: permit -> type = permit_authenticated_clients; goto get_clients; case UNAUTHENTICATED: permit -> type = permit_unauthenticated_clients; goto get_clients; case ALL: permit -> type = permit_all_clients; goto get_clients; break; case DYNAMIC: permit -> type = permit_dynamic_bootp_clients; if (next_token (&val, (unsigned *)0, cfile) != TOKEN_BOOTP) { parse_warn (cfile, "expecting \"bootp\""); skip_to_semi (cfile); free_permit (permit, MDL); continue; } goto get_clients; case MEMBERS: if (next_token (&val, (unsigned *)0, cfile) != OF) { parse_warn (cfile, "expecting \"of\""); skip_to_semi (cfile); free_permit (permit, MDL); continue; } if (next_token (&val, (unsigned *)0, cfile) != STRING) { parse_warn (cfile, "expecting class name."); skip_to_semi (cfile); free_permit (permit, MDL); continue; } permit -> type = permit_class; permit -> class = (struct class *)0; find_class (&permit -> class, val, MDL); if (!permit -> class) parse_warn (cfile, "no such class: %s", val); break; case AFTER: if (pool->valid_from || pool->valid_until) { parse_warn(cfile, "duplicate \"after\" clause."); skip_to_semi(cfile); free_permit(permit, MDL); continue; } t = parse_date_core(cfile); permit->type = permit_after; permit->after = t; if (is_allow) { pool->valid_from = t; } else { pool->valid_until = t; } break; default: parse_warn (cfile, "expecting permit type."); skip_to_semi (cfile); break; } while (*permit_head) permit_head = &((*permit_head) -> next); *permit_head = permit; parse_semi (cfile); break; case DENY: permit_head = &pool -> prohibit_list; /* remember the clause which leads to get_permit */ is_allow = 0; goto get_permit; case RBRACE: next_token (&val, (unsigned *)0, cfile); done = 1; break; case END_OF_FILE: /* * We can get to END_OF_FILE if, for instance, * the parse_statement() reads all available tokens * and leaves us at the end. */ parse_warn(cfile, "unexpected end of file"); goto cleanup; default: declaration = parse_statement (cfile, pool -> group, POOL_DECL, (struct host_decl *)0, declaration); break; } } while (!done); /* See if there's already a pool into which we can merge this one. */ for (pp = pool -> shared_network -> pools; pp; pp = pp -> next) { if (pp -> group -> statements != pool -> group -> statements) continue; #if defined (FAILOVER_PROTOCOL) if (pool -> failover_peer != pp -> failover_peer) continue; #endif if (!permit_list_match (pp -> permit_list, pool -> permit_list) || !permit_list_match (pool -> permit_list, pp -> permit_list) || !permit_list_match (pp -> prohibit_list, pool -> prohibit_list) || !permit_list_match (pool -> prohibit_list, pp -> prohibit_list)) continue; /* Okay, we can merge these two pools. All we have to do is fix up the leases, which all point to their pool. */ for (lp = lpchain; lp; lp = lp -> next) { pool_dereference (&lp -> pool, MDL); pool_reference (&lp -> pool, pp, MDL); } break; } /* If we didn't succeed in merging this pool into another, put it on the list. */ if (!pp) { p = &pool -> shared_network -> pools; for (; *p; p = &((*p) -> next)) ; pool_reference (p, pool, MDL); } /* Don't allow a pool declaration with no addresses, since it is probably a configuration error. */ if (!lpchain) { parse_warn (cfile, "Pool declaration with no address range."); log_error ("Pool declarations must always contain at least"); log_error ("one range statement."); } cleanup: /* Dereference the lease chain. */ lp = (struct lease *)0; while (lpchain) { lease_reference (&lp, lpchain, MDL); lease_dereference (&lpchain, MDL); if (lp -> next) { lease_reference (&lpchain, lp -> next, MDL); lease_dereference (&lp -> next, MDL); lease_dereference (&lp, MDL); } } pool_dereference (&pool, MDL); } /* Expect a left brace; if there isn't one, skip over the rest of the statement and return zero; otherwise, return 1. */ int parse_lbrace (cfile) struct parse *cfile; { enum dhcp_token token; const char *val; token = next_token (&val, (unsigned *)0, cfile); if (token != LBRACE) { parse_warn (cfile, "expecting left brace."); skip_to_semi (cfile); return 0; } return 1; } /* host-declaration :== hostname RBRACE parameters declarations LBRACE */ void parse_host_declaration (cfile, group) struct parse *cfile; struct group *group; { const char *val; enum dhcp_token token; struct host_decl *host; char *name; int declaration = 0; int dynamicp = 0; int deleted = 0; isc_result_t status; int known; struct option *option; struct expression *expr = NULL; name = parse_host_name (cfile); if (!name) { parse_warn (cfile, "expecting a name for host declaration."); skip_to_semi (cfile); return; } host = (struct host_decl *)0; status = host_allocate (&host, MDL); if (status != ISC_R_SUCCESS) log_fatal ("can't allocate host decl struct %s: %s", name, isc_result_totext (status)); host -> name = name; if (!clone_group (&host -> group, group, MDL)) { log_fatal ("can't clone group for host %s", name); boom: host_dereference (&host, MDL); return; } if (!parse_lbrace (cfile)) goto boom; do { token = peek_token (&val, (unsigned *)0, cfile); if (token == RBRACE) { token = next_token (&val, (unsigned *)0, cfile); break; } if (token == END_OF_FILE) { token = next_token (&val, (unsigned *)0, cfile); parse_warn (cfile, "unexpected end of file"); break; } /* If the host declaration was created by the server, remember to save it. */ if (token == DYNAMIC) { dynamicp = 1; token = next_token (&val, (unsigned *)0, cfile); if (!parse_semi (cfile)) break; continue; } /* If the host declaration was created by the server, remember to save it. */ if (token == TOKEN_DELETED) { deleted = 1; token = next_token (&val, (unsigned *)0, cfile); if (!parse_semi (cfile)) break; continue; } if (token == GROUP) { struct group_object *go; token = next_token (&val, (unsigned *)0, cfile); token = next_token (&val, (unsigned *)0, cfile); if (token != STRING && !is_identifier (token)) { parse_warn (cfile, "expecting string or identifier."); skip_to_rbrace (cfile, 1); break; } go = (struct group_object *)0; if (!group_hash_lookup (&go, group_name_hash, val, strlen (val), MDL)) { parse_warn (cfile, "unknown group %s in host %s", val, host -> name); } else { if (host -> named_group) group_object_dereference (&host -> named_group, MDL); group_object_reference (&host -> named_group, go, MDL); group_object_dereference (&go, MDL); } if (!parse_semi (cfile)) break; continue; } if (token == UID) { const char *s; unsigned char *t = 0; unsigned len; token = next_token (&val, (unsigned *)0, cfile); data_string_forget (&host -> client_identifier, MDL); if (host->client_identifier.len != 0) { parse_warn(cfile, "Host %s already has a " "client identifier.", host->name); break; } /* See if it's a string or a cshl. */ token = peek_token (&val, (unsigned *)0, cfile); if (token == STRING) { token = next_token (&val, &len, cfile); s = val; host -> client_identifier.terminated = 1; } else { len = 0; t = parse_numeric_aggregate (cfile, (unsigned char *)0, &len, ':', 16, 8); if (!t) { parse_warn (cfile, "expecting hex list."); skip_to_semi (cfile); } s = (const char *)t; } if (!buffer_allocate (&host -> client_identifier.buffer, len + host -> client_identifier.terminated, MDL)) log_fatal ("no memory for uid for host %s.", host -> name); host -> client_identifier.data = host -> client_identifier.buffer -> data; host -> client_identifier.len = len; memcpy (host -> client_identifier.buffer -> data, s, len + host -> client_identifier.terminated); if (t) dfree (t, MDL); if (!parse_semi (cfile)) break; continue; } if (token == HOST_IDENTIFIER) { if (host->host_id_option != NULL) { parse_warn(cfile, "only one host-identifier allowed " "per host"); skip_to_rbrace(cfile, 1); break; } next_token(&val, NULL, cfile); token = next_token(&val, NULL, cfile); if (token != OPTION) { parse_warn(cfile, "host-identifier must be an option"); skip_to_rbrace(cfile, 1); break; } known = 0; option = NULL; status = parse_option_name(cfile, 1, &known, &option); if ((status != ISC_R_SUCCESS) || (option == NULL)) { break; } if (!known) { parse_warn(cfile, "unknown option %s.%s", option->universe->name, option->name); skip_to_rbrace(cfile, 1); break; } if (! parse_option_data(&expr, cfile, 1, option)) { skip_to_rbrace(cfile, 1); option_dereference(&option, MDL); break; } if (!parse_semi(cfile)) { skip_to_rbrace(cfile, 1); expression_dereference(&expr, MDL); option_dereference(&option, MDL); break; } option_reference(&host->host_id_option, option, MDL); option_dereference(&option, MDL); data_string_copy(&host->host_id, &expr->data.const_data, MDL); expression_dereference(&expr, MDL); continue; } declaration = parse_statement(cfile, host->group, HOST_DECL, host, declaration); } while (1); if (deleted) { struct host_decl *hp = (struct host_decl *)0; if (host_hash_lookup (&hp, host_name_hash, (unsigned char *)host -> name, strlen (host -> name), MDL)) { delete_host (hp, 0); host_dereference (&hp, MDL); } } else { if (host -> named_group && host -> named_group -> group) { if (host -> group -> statements || (host -> group -> authoritative != host -> named_group -> group -> authoritative)) { if (host -> group -> next) group_dereference (&host -> group -> next, MDL); group_reference (&host -> group -> next, host -> named_group -> group, MDL); } else { group_dereference (&host -> group, MDL); group_reference (&host -> group, host -> named_group -> group, MDL); } } if (dynamicp) host -> flags |= HOST_DECL_DYNAMIC; else host -> flags |= HOST_DECL_STATIC; status = enter_host (host, dynamicp, 0); if (status != ISC_R_SUCCESS) parse_warn (cfile, "host %s: %s", host -> name, isc_result_totext (status)); } host_dereference (&host, MDL); } /* class-declaration :== STRING LBRACE parameters declarations RBRACE */ int parse_class_declaration (cp, cfile, group, type) struct class **cp; struct parse *cfile; struct group *group; int type; { const char *val; enum dhcp_token token; struct class *class = (struct class *)0, *pc = (struct class *)0; int declaration = 0; int lose = 0; struct data_string data; char *name; const char *tname; struct executable_statement *stmt = (struct executable_statement *)0; int new = 1; isc_result_t status = ISC_R_FAILURE; int matchedonce = 0; int submatchedonce = 0; unsigned code; if (dhcpv6_class_once && local_family == AF_INET6) { dhcpv6_class_once = 0; log_error("WARNING: class declarations are not supported " "for DHCPv6."); } token = next_token (&val, (unsigned *)0, cfile); if (token != STRING) { parse_warn (cfile, "Expecting class name"); skip_to_semi (cfile); return 0; } /* See if there's already a class with the specified name. */ find_class (&pc, val, MDL); /* If it is a class, we're updating it. If it's any of the other * types (subclass, vendor or user class), the named class is a * reference to the parent class so its mandatory. */ if (pc && (type == CLASS_TYPE_CLASS)) { class_reference(&class, pc, MDL); new = 0; class_dereference(&pc, MDL); } else if (!pc && (type != CLASS_TYPE_CLASS)) { parse_warn(cfile, "no class named %s", val); skip_to_semi(cfile); return 0; } /* The old vendor-class and user-class declarations had an implicit match. We don't do the implicit match anymore. Instead, for backward compatibility, we have an implicit-vendor-class and an implicit-user-class. vendor-class and user-class declarations are turned into subclasses of the implicit classes, and the submatch expression of the implicit classes extracts the contents of the vendor class or user class. */ if ((type == CLASS_TYPE_VENDOR) || (type == CLASS_TYPE_USER)) { data.len = strlen (val); data.buffer = (struct buffer *)0; if (!buffer_allocate (&data.buffer, data.len + 1, MDL)) log_fatal ("no memory for class name."); data.data = &data.buffer -> data [0]; data.terminated = 1; tname = type ? "implicit-vendor-class" : "implicit-user-class"; } else if (type == CLASS_TYPE_CLASS) { tname = val; } else { tname = (const char *)0; } if (tname) { name = dmalloc (strlen (tname) + 1, MDL); if (!name) log_fatal ("No memory for class name %s.", tname); strcpy (name, val); } else name = (char *)0; /* If this is a straight subclass, parse the hash string. */ if (type == CLASS_TYPE_SUBCLASS) { token = peek_token (&val, (unsigned *)0, cfile); if (token == STRING) { token = next_token (&val, &data.len, cfile); data.buffer = (struct buffer *)0; if (!buffer_allocate (&data.buffer, data.len + 1, MDL)) { if (pc) class_dereference (&pc, MDL); return 0; } data.terminated = 1; data.data = &data.buffer -> data [0]; memcpy ((char *)data.buffer -> data, val, data.len + 1); } else if (token == NUMBER_OR_NAME || token == NUMBER) { memset (&data, 0, sizeof data); if (!parse_cshl (&data, cfile)) { if (pc) class_dereference (&pc, MDL); return 0; } } else { parse_warn (cfile, "Expecting string or hex list."); if (pc) class_dereference (&pc, MDL); return 0; } } /* See if there's already a class in the hash table matching the hash data. */ if (type != CLASS_TYPE_CLASS) class_hash_lookup (&class, pc -> hash, (const char *)data.data, data.len, MDL); /* If we didn't find an existing class, allocate a new one. */ if (!class) { /* Allocate the class structure... */ status = class_allocate (&class, MDL); if (pc) { group_reference (&class -> group, pc -> group, MDL); class_reference (&class -> superclass, pc, MDL); class -> lease_limit = pc -> lease_limit; if (class -> lease_limit) { class -> billed_leases = dmalloc (class -> lease_limit * sizeof (struct lease *), MDL); if (!class -> billed_leases) log_fatal ("no memory for billing"); memset (class -> billed_leases, 0, (class -> lease_limit * sizeof class -> billed_leases)); } data_string_copy (&class -> hash_string, &data, MDL); if (!pc -> hash && !class_new_hash (&pc->hash, SCLASS_HASH_SIZE, MDL)) log_fatal ("No memory for subclass hash."); class_hash_add (pc -> hash, (const char *)class -> hash_string.data, class -> hash_string.len, (void *)class, MDL); } else { if (class->group) group_dereference(&class->group, MDL); if (!clone_group (&class -> group, group, MDL)) log_fatal ("no memory to clone class group."); } /* If this is an implicit vendor or user class, add a statement that causes the vendor or user class ID to be sent back in the reply. */ if (type == CLASS_TYPE_VENDOR || type == CLASS_TYPE_USER) { stmt = (struct executable_statement *)0; if (!executable_statement_allocate (&stmt, MDL)) log_fatal ("no memory for class statement."); stmt -> op = supersede_option_statement; if (option_cache_allocate (&stmt -> data.option, MDL)) { stmt -> data.option -> data = data; code = (type == CLASS_TYPE_VENDOR) ? DHO_VENDOR_CLASS_IDENTIFIER : DHO_USER_CLASS; option_code_hash_lookup( &stmt->data.option->option, dhcp_universe.code_hash, &code, 0, MDL); } class -> statements = stmt; } /* Save the name, if there is one. */ if (class->name != NULL) dfree(class->name, MDL); class->name = name; } if (type != CLASS_TYPE_CLASS) data_string_forget(&data, MDL); /* Spawned classes don't have to have their own settings. */ if (class -> superclass) { token = peek_token (&val, (unsigned *)0, cfile); if (token == SEMI) { next_token (&val, (unsigned *)0, cfile); if (cp) status = class_reference (cp, class, MDL); class_dereference (&class, MDL); if (pc) class_dereference (&pc, MDL); return cp ? (status == ISC_R_SUCCESS) : 1; } /* Give the subclass its own group. */ if (!clone_group (&class -> group, class -> group, MDL)) log_fatal ("can't clone class group."); } if (!parse_lbrace (cfile)) { class_dereference (&class, MDL); if (pc) class_dereference (&pc, MDL); return 0; } do { token = peek_token (&val, (unsigned *)0, cfile); if (token == RBRACE) { token = next_token (&val, (unsigned *)0, cfile); break; } else if (token == END_OF_FILE) { token = next_token (&val, (unsigned *)0, cfile); parse_warn (cfile, "unexpected end of file"); break; } else if (token == DYNAMIC) { class->flags |= CLASS_DECL_DYNAMIC; token = next_token (&val, (unsigned *)0, cfile); if (!parse_semi (cfile)) break; continue; } else if (token == TOKEN_DELETED) { class->flags |= CLASS_DECL_DELETED; token = next_token (&val, (unsigned *)0, cfile); if (!parse_semi (cfile)) break; continue; } else if (token == MATCH) { if (pc) { parse_warn (cfile, "invalid match in subclass."); skip_to_semi (cfile); break; } token = next_token (&val, (unsigned *)0, cfile); token = peek_token (&val, (unsigned *)0, cfile); if (token != IF) goto submatch; token = next_token (&val, (unsigned *)0, cfile); if (matchedonce) { parse_warn(cfile, "A class may only have " "one 'match if' clause."); skip_to_semi(cfile); break; } matchedonce = 1; if (class->expr) expression_dereference(&class->expr, MDL); if (!parse_boolean_expression (&class->expr, cfile, &lose)) { if (!lose) { parse_warn (cfile, "expecting boolean expr."); skip_to_semi (cfile); } } else { #if defined (DEBUG_EXPRESSION_PARSE) print_expression ("class match", class -> expr); #endif parse_semi (cfile); } } else if (token == SPAWN) { token = next_token (&val, (unsigned *)0, cfile); if (pc) { parse_warn (cfile, "invalid spawn in subclass."); skip_to_semi (cfile); break; } class -> spawning = 1; token = next_token (&val, (unsigned *)0, cfile); if (token != WITH) { parse_warn (cfile, "expecting with after spawn"); skip_to_semi (cfile); break; } submatch: if (submatchedonce) { parse_warn (cfile, "can't override existing %s.", "submatch/spawn"); skip_to_semi (cfile); break; } submatchedonce = 1; if (class->submatch) expression_dereference(&class->submatch, MDL); if (!parse_data_expression (&class -> submatch, cfile, &lose)) { if (!lose) { parse_warn (cfile, "expecting data expr."); skip_to_semi (cfile); } } else { #if defined (DEBUG_EXPRESSION_PARSE) print_expression ("class submatch", class -> submatch); #endif parse_semi (cfile); } } else if (token == LEASE) { next_token (&val, (unsigned *)0, cfile); token = next_token (&val, (unsigned *)0, cfile); if (token != LIMIT) { parse_warn (cfile, "expecting \"limit\""); if (token != SEMI) skip_to_semi (cfile); break; } token = next_token (&val, (unsigned *)0, cfile); if (token != NUMBER) { parse_warn (cfile, "expecting a number"); if (token != SEMI) skip_to_semi (cfile); break; } class -> lease_limit = atoi (val); if (class->billed_leases) dfree(class->billed_leases, MDL); class -> billed_leases = dmalloc (class -> lease_limit * sizeof (struct lease *), MDL); if (!class -> billed_leases) log_fatal ("no memory for billed leases."); memset (class -> billed_leases, 0, (class -> lease_limit * sizeof class -> billed_leases)); have_billing_classes = 1; parse_semi (cfile); } else { declaration = parse_statement (cfile, class -> group, CLASS_DECL, (struct host_decl *)0, declaration); } } while (1); if (class->flags & CLASS_DECL_DELETED) { if (type == CLASS_TYPE_CLASS) { struct class *theclass = NULL; status = find_class(&theclass, class->name, MDL); if (status == ISC_R_SUCCESS) { delete_class(theclass, 0); class_dereference(&theclass, MDL); } } else { class_hash_delete(pc->hash, (char *)class->hash_string.data, class->hash_string.len, MDL); } } else if (type == CLASS_TYPE_CLASS && new) { if (!collections -> classes) class_reference (&collections -> classes, class, MDL); else { struct class *c; for (c = collections -> classes; c -> nic; c = c -> nic) ; class_reference (&c -> nic, class, MDL); } } if (cp) /* should always be 0??? */ status = class_reference (cp, class, MDL); class_dereference (&class, MDL); if (pc) class_dereference (&pc, MDL); return cp ? (status == ISC_R_SUCCESS) : 1; } /* shared-network-declaration :== hostname LBRACE declarations parameters RBRACE */ void parse_shared_net_declaration (cfile, group) struct parse *cfile; struct group *group; { const char *val; enum dhcp_token token; struct shared_network *share; char *name; int declaration = 0; isc_result_t status; share = (struct shared_network *)0; status = shared_network_allocate (&share, MDL); if (status != ISC_R_SUCCESS) log_fatal ("Can't allocate shared subnet: %s", isc_result_totext (status)); clone_group (&share -> group, group, MDL); shared_network_reference (&share -> group -> shared_network, share, MDL); /* Get the name of the shared network... */ token = peek_token (&val, (unsigned *)0, cfile); if (token == STRING) { token = next_token (&val, (unsigned *)0, cfile); if (val [0] == 0) { parse_warn (cfile, "zero-length shared network name"); val = ""; } name = dmalloc (strlen (val) + 1, MDL); if (!name) log_fatal ("no memory for shared network name"); strcpy (name, val); } else { name = parse_host_name (cfile); if (!name) { parse_warn (cfile, "expecting a name for shared-network"); skip_to_semi (cfile); shared_network_dereference (&share, MDL); return; } } share -> name = name; if (!parse_lbrace (cfile)) { shared_network_dereference (&share, MDL); return; } do { token = peek_token (&val, (unsigned *)0, cfile); if (token == RBRACE) { token = next_token (&val, (unsigned *)0, cfile); if (!share -> subnets) parse_warn (cfile, "empty shared-network decl"); else enter_shared_network (share); shared_network_dereference (&share, MDL); return; } else if (token == END_OF_FILE) { token = next_token (&val, (unsigned *)0, cfile); parse_warn (cfile, "unexpected end of file"); break; } else if (token == INTERFACE) { token = next_token (&val, (unsigned *)0, cfile); token = next_token (&val, (unsigned *)0, cfile); new_shared_network_interface (cfile, share, val); if (!parse_semi (cfile)) break; continue; } declaration = parse_statement (cfile, share -> group, SHARED_NET_DECL, (struct host_decl *)0, declaration); } while (1); shared_network_dereference (&share, MDL); } static int common_subnet_parsing(struct parse *cfile, struct shared_network *share, struct subnet *subnet) { enum dhcp_token token; struct subnet *t, *u; const char *val; int declaration = 0; enter_subnet(subnet); if (!parse_lbrace(cfile)) { subnet_dereference(&subnet, MDL); return 0; } do { token = peek_token(&val, NULL, cfile); if (token == RBRACE) { token = next_token(&val, NULL, cfile); break; } else if (token == END_OF_FILE) { token = next_token(&val, NULL, cfile); parse_warn (cfile, "unexpected end of file"); break; } else if (token == INTERFACE) { token = next_token(&val, NULL, cfile); token = next_token(&val, NULL, cfile); new_shared_network_interface(cfile, share, val); if (!parse_semi(cfile)) break; continue; } declaration = parse_statement(cfile, subnet->group, SUBNET_DECL, NULL, declaration); } while (1); /* Add the subnet to the list of subnets in this shared net. */ if (share->subnets == NULL) { subnet_reference(&share->subnets, subnet, MDL); } else { u = NULL; for (t = share->subnets; t->next_sibling; t = t->next_sibling) { if (subnet_inner_than(subnet, t, 0)) { subnet_reference(&subnet->next_sibling, t, MDL); if (u) { subnet_dereference(&u->next_sibling, MDL); subnet_reference(&u->next_sibling, subnet, MDL); } else { subnet_dereference(&share->subnets, MDL); subnet_reference(&share->subnets, subnet, MDL); } subnet_dereference(&subnet, MDL); return 1; } u = t; } subnet_reference(&t->next_sibling, subnet, MDL); } subnet_dereference(&subnet, MDL); return 1; } /* subnet-declaration :== net NETMASK netmask RBRACE parameters declarations LBRACE */ void parse_subnet_declaration (cfile, share) struct parse *cfile; struct shared_network *share; { const char *val; enum dhcp_token token; struct subnet *subnet; struct iaddr iaddr; unsigned char addr [4]; unsigned len = sizeof addr; isc_result_t status; subnet = (struct subnet *)0; status = subnet_allocate (&subnet, MDL); if (status != ISC_R_SUCCESS) log_fatal ("Allocation of new subnet failed: %s", isc_result_totext (status)); shared_network_reference (&subnet -> shared_network, share, MDL); /* * If our parent shared network was implicitly created by the software, * and not explicitly configured by the user, then we actually put all * configuration scope in the parent (the shared network and subnet * share the same {}-level scope). * * Otherwise, we clone the parent group and continue as normal. */ if (share->flags & SHARED_IMPLICIT) { group_reference(&subnet->group, share->group, MDL); } else { if (!clone_group(&subnet->group, share->group, MDL)) { log_fatal("Allocation of group for new subnet failed."); } } subnet_reference (&subnet -> group -> subnet, subnet, MDL); /* Get the network number... */ if (!parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8)) { subnet_dereference (&subnet, MDL); return; } memcpy (iaddr.iabuf, addr, len); iaddr.len = len; subnet -> net = iaddr; token = next_token (&val, (unsigned *)0, cfile); if (token != NETMASK) { parse_warn (cfile, "Expecting netmask"); skip_to_semi (cfile); return; } /* Get the netmask... */ if (!parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8)) { subnet_dereference (&subnet, MDL); return; } memcpy (iaddr.iabuf, addr, len); iaddr.len = len; subnet -> netmask = iaddr; /* Validate the network number/netmask pair. */ if (host_addr (subnet -> net, subnet -> netmask)) { char *maskstr; maskstr = strdup (piaddr (subnet -> netmask)); parse_warn (cfile, "subnet %s netmask %s: bad subnet number/mask combination.", piaddr (subnet -> net), maskstr); free(maskstr); subnet_dereference (&subnet, MDL); skip_to_semi (cfile); return; } common_subnet_parsing(cfile, share, subnet); } /* subnet6-declaration :== net / bits RBRACE parameters declarations LBRACE */ void parse_subnet6_declaration(struct parse *cfile, struct shared_network *share) { #if !defined(DHCPv6) parse_warn(cfile, "No DHCPv6 support."); skip_to_semi(cfile); #else /* defined(DHCPv6) */ struct subnet *subnet; isc_result_t status; enum dhcp_token token; const char *val; char *endp; int ofs; const static int mask[] = { 0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE }; struct iaddr iaddr; if (local_family != AF_INET6) { parse_warn(cfile, "subnet6 statement is only supported " "in DHCPv6 mode."); skip_to_semi(cfile); return; } subnet = NULL; status = subnet_allocate(&subnet, MDL); if (status != ISC_R_SUCCESS) { log_fatal("Allocation of new subnet failed: %s", isc_result_totext(status)); } shared_network_reference(&subnet->shared_network, share, MDL); /* * If our parent shared network was implicitly created by the software, * and not explicitly configured by the user, then we actually put all * configuration scope in the parent (the shared network and subnet * share the same {}-level scope). * * Otherwise, we clone the parent group and continue as normal. */ if (share->flags & SHARED_IMPLICIT) { group_reference(&subnet->group, share->group, MDL); } else { if (!clone_group(&subnet->group, share->group, MDL)) { log_fatal("Allocation of group for new subnet failed."); } } subnet_reference(&subnet->group->subnet, subnet, MDL); if (!parse_ip6_addr(cfile, &subnet->net)) { subnet_dereference(&subnet, MDL); return; } token = next_token(&val, NULL, cfile); if (token != SLASH) { parse_warn(cfile, "Expecting a '/'."); skip_to_semi(cfile); return; } token = next_token(&val, NULL, cfile); if (token != NUMBER) { parse_warn(cfile, "Expecting a number."); skip_to_semi(cfile); return; } subnet->prefix_len = strtol(val, &endp, 10); if ((subnet->prefix_len < 0) || (subnet->prefix_len > 128) || (*endp != '\0')) { parse_warn(cfile, "Expecting a number between 0 and 128."); skip_to_semi(cfile); return; } if (!is_cidr_mask_valid(&subnet->net, subnet->prefix_len)) { parse_warn(cfile, "New subnet mask too short."); skip_to_semi(cfile); return; } /* * Create a netmask. */ subnet->netmask.len = 16; ofs = subnet->prefix_len / 8; if (ofs < subnet->netmask.len) { subnet->netmask.iabuf[ofs] = mask[subnet->prefix_len % 8]; } while (--ofs >= 0) { subnet->netmask.iabuf[ofs] = 0xFF; } /* Validate the network number/netmask pair. */ iaddr = subnet_number(subnet->net, subnet->netmask); if (memcmp(&iaddr, &subnet->net, 16) != 0) { parse_warn(cfile, "subnet %s/%d: prefix not long enough for address.", piaddr(subnet->net), subnet->prefix_len); subnet_dereference(&subnet, MDL); skip_to_semi(cfile); return; } if (!common_subnet_parsing(cfile, share, subnet)) { return; } #endif /* defined(DHCPv6) */ } /* group-declaration :== RBRACE parameters declarations LBRACE */ void parse_group_declaration (cfile, group) struct parse *cfile; struct group *group; { const char *val; enum dhcp_token token; struct group *g; int declaration = 0; struct group_object *t = NULL; isc_result_t status; char *name = NULL; int deletedp = 0; int dynamicp = 0; int staticp = 0; g = NULL; if (!clone_group(&g, group, MDL)) log_fatal("no memory for explicit group."); token = peek_token(&val, NULL, cfile); if (is_identifier (token) || token == STRING) { next_token(&val, NULL, cfile); name = dmalloc(strlen(val) + 1, MDL); if (!name) log_fatal("no memory for group decl name %s", val); strcpy(name, val); } if (!parse_lbrace(cfile)) { group_dereference(&g, MDL); return; } do { token = peek_token(&val, NULL, cfile); if (token == RBRACE) { token = next_token(&val, NULL, cfile); break; } else if (token == END_OF_FILE) { token = next_token(&val, NULL, cfile); parse_warn(cfile, "unexpected end of file"); break; } else if (token == TOKEN_DELETED) { token = next_token(&val, NULL, cfile); parse_semi(cfile); deletedp = 1; } else if (token == DYNAMIC) { token = next_token(&val, NULL, cfile); parse_semi(cfile); dynamicp = 1; } else if (token == STATIC) { token = next_token(&val, NULL, cfile); parse_semi(cfile); staticp = 1; } declaration = parse_statement(cfile, g, GROUP_DECL, NULL, declaration); } while (1); if (name) { if (deletedp) { if (group_name_hash) { t = NULL; if (group_hash_lookup(&t, group_name_hash, name, strlen(name), MDL)) { delete_group(t, 0); } } } else { t = NULL; status = group_object_allocate(&t, MDL); if (status != ISC_R_SUCCESS) log_fatal("no memory for group decl %s: %s", val, isc_result_totext(status)); group_reference(&t->group, g, MDL); t->name = name; t->flags = ((staticp ? GROUP_OBJECT_STATIC : 0) | (dynamicp ? GROUP_OBJECT_DYNAMIC : 0) | (deletedp ? GROUP_OBJECT_DELETED : 0)); supersede_group(t, 0); } if (t != NULL) group_object_dereference(&t, MDL); } } /* fixed-addr-parameter :== ip-addrs-or-hostnames SEMI ip-addrs-or-hostnames :== ip-addr-or-hostname | ip-addrs-or-hostnames ip-addr-or-hostname */ int parse_fixed_addr_param(struct option_cache **oc, struct parse *cfile, enum dhcp_token type) { int parse_ok; const char *val; enum dhcp_token token; struct expression *expr = NULL; struct expression *tmp, *new; int status; do { tmp = NULL; if (type == FIXED_ADDR) { parse_ok = parse_ip_addr_or_hostname(&tmp, cfile, 1); } else { /* INSIST(type == FIXED_ADDR6); */ parse_ok = parse_ip6_addr_expr(&tmp, cfile); } if (parse_ok) { if (expr != NULL) { new = NULL; status = make_concat(&new, expr, tmp); expression_dereference(&expr, MDL); expression_dereference(&tmp, MDL); if (!status) { return 0; } expr = new; } else { expr = tmp; } } else { if (expr != NULL) { expression_dereference (&expr, MDL); } return 0; } token = peek_token(&val, NULL, cfile); if (token == COMMA) { token = next_token(&val, NULL, cfile); } } while (token == COMMA); if (!parse_semi(cfile)) { if (expr) { expression_dereference (&expr, MDL); } return 0; } status = option_cache(oc, NULL, expr, NULL, MDL); expression_dereference(&expr, MDL); return status; } /* lease_declaration :== LEASE ip_address LBRACE lease_parameters RBRACE lease_parameters :== | lease_parameter | lease_parameters lease_parameter lease_parameter :== STARTS date | ENDS date | TIMESTAMP date | HARDWARE hardware-parameter | UID hex_numbers SEMI | HOSTNAME hostname SEMI | CLIENT_HOSTNAME hostname SEMI | CLASS identifier SEMI | DYNAMIC_BOOTP SEMI */ int parse_lease_declaration (struct lease **lp, struct parse *cfile) { const char *val; enum dhcp_token token; unsigned char addr [4]; unsigned len = sizeof addr; int seenmask = 0; int seenbit; char tbuf [32]; struct lease *lease; struct executable_statement *on; int lose; TIME t; int noequal, newbinding; struct binding *binding; struct binding_value *nv; isc_result_t status; struct option_cache *oc; pair *p; binding_state_t new_state; unsigned buflen = 0; struct class *class; lease = (struct lease *)0; status = lease_allocate (&lease, MDL); if (status != ISC_R_SUCCESS) return 0; /* Get the address for which the lease has been issued. */ if (!parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8)) { lease_dereference (&lease, MDL); return 0; } memcpy (lease -> ip_addr.iabuf, addr, len); lease -> ip_addr.len = len; if (!parse_lbrace (cfile)) { lease_dereference (&lease, MDL); return 0; } do { token = next_token (&val, (unsigned *)0, cfile); if (token == RBRACE) break; else if (token == END_OF_FILE) { parse_warn (cfile, "unexpected end of file"); break; } strncpy (tbuf, val, sizeof tbuf); tbuf [(sizeof tbuf) - 1] = 0; /* Parse any of the times associated with the lease. */ switch (token) { case STARTS: case ENDS: case TIMESTAMP: case TSTP: case TSFP: case ATSFP: case CLTT: t = parse_date (cfile); switch (token) { case STARTS: seenbit = 1; lease -> starts = t; break; case ENDS: seenbit = 2; lease -> ends = t; break; case TSTP: seenbit = 65536; lease -> tstp = t; break; case TSFP: seenbit = 131072; lease -> tsfp = t; break; case ATSFP: seenbit = 262144; lease->atsfp = t; break; case CLTT: seenbit = 524288; lease -> cltt = t; break; default: /* for gcc, we'll never get here. */ log_fatal ("Impossible error at %s:%d.", MDL); return 0; } break; /* Colon-separated hexadecimal octets... */ case UID: seenbit = 8; token = peek_token (&val, (unsigned *)0, cfile); if (token == STRING) { unsigned char *tuid; token = next_token (&val, &buflen, cfile); if (buflen < sizeof lease -> uid_buf) { tuid = lease -> uid_buf; lease -> uid_max = sizeof lease -> uid_buf; } else { tuid = ((unsigned char *) dmalloc (buflen, MDL)); if (!tuid) { log_error ("no space for uid"); lease_dereference (&lease, MDL); return 0; } lease -> uid_max = buflen; } lease -> uid_len = buflen; memcpy (tuid, val, lease -> uid_len); lease -> uid = tuid; } else { buflen = 0; lease -> uid = (parse_numeric_aggregate (cfile, (unsigned char *)0, &buflen, ':', 16, 8)); if (!lease -> uid) { lease_dereference (&lease, MDL); return 0; } lease -> uid_len = buflen; lease -> uid_max = buflen; if (lease -> uid_len == 0) { lease -> uid = (unsigned char *)0; parse_warn (cfile, "zero-length uid"); seenbit = 0; parse_semi (cfile); break; } } parse_semi (cfile); if (!lease -> uid) { log_fatal ("No memory for lease uid"); } break; case CLASS: seenbit = 32; token = next_token (&val, (unsigned *)0, cfile); if (!is_identifier (token)) { if (token != SEMI) skip_to_rbrace (cfile, 1); lease_dereference (&lease, MDL); return 0; } parse_semi (cfile); /* for now, we aren't using this. */ break; case HARDWARE: seenbit = 64; parse_hardware_param (cfile, &lease -> hardware_addr); break; case TOKEN_RESERVED: seenbit = 0; lease->flags |= RESERVED_LEASE; parse_semi(cfile); break; case DYNAMIC_BOOTP: seenbit = 0; lease -> flags |= BOOTP_LEASE; parse_semi (cfile); break; /* XXX: Reverse compatibility? */ case TOKEN_ABANDONED: seenbit = 256; lease -> binding_state = FTS_ABANDONED; lease -> next_binding_state = FTS_ABANDONED; parse_semi (cfile); break; case TOKEN_NEXT: seenbit = 128; token = next_token (&val, (unsigned *)0, cfile); if (token != BINDING) { parse_warn (cfile, "expecting 'binding'"); skip_to_semi (cfile); break; } goto do_binding_state; case REWIND: seenbit = 512; token = next_token(&val, NULL, cfile); if (token != BINDING) { parse_warn(cfile, "expecting 'binding'"); skip_to_semi(cfile); break; } goto do_binding_state; case BINDING: seenbit = 256; do_binding_state: token = next_token (&val, (unsigned *)0, cfile); if (token != STATE) { parse_warn (cfile, "expecting 'state'"); skip_to_semi (cfile); break; } token = next_token (&val, (unsigned *)0, cfile); switch (token) { case TOKEN_ABANDONED: new_state = FTS_ABANDONED; break; case TOKEN_FREE: new_state = FTS_FREE; break; case TOKEN_ACTIVE: new_state = FTS_ACTIVE; break; case TOKEN_EXPIRED: new_state = FTS_EXPIRED; break; case TOKEN_RELEASED: new_state = FTS_RELEASED; break; case TOKEN_RESET: new_state = FTS_RESET; break; case TOKEN_BACKUP: new_state = FTS_BACKUP; break; /* RESERVED and BOOTP states preserved for * compatibleness with older versions. */ case TOKEN_RESERVED: new_state = FTS_ACTIVE; lease->flags |= RESERVED_LEASE; break; case TOKEN_BOOTP: new_state = FTS_ACTIVE; lease->flags |= BOOTP_LEASE; break; default: parse_warn (cfile, "%s: expecting a binding state.", val); skip_to_semi (cfile); return 0; } if (seenbit == 256) { lease -> binding_state = new_state; /* * Apply default/conservative next/rewind * binding states if they haven't been set * yet. These defaults will be over-ridden if * they are set later in parsing. */ if (!(seenmask & 128)) lease->next_binding_state = new_state; /* The most conservative rewind state. */ if (!(seenmask & 512)) lease->rewind_binding_state = new_state; } else if (seenbit == 128) lease -> next_binding_state = new_state; else if (seenbit == 512) lease->rewind_binding_state = new_state; else log_fatal("Impossible condition at %s:%d.", MDL); parse_semi (cfile); break; case CLIENT_HOSTNAME: seenbit = 1024; token = peek_token (&val, (unsigned *)0, cfile); if (token == STRING) { if (!parse_string (cfile, &lease -> client_hostname, (unsigned *)0)) { lease_dereference (&lease, MDL); return 0; } } else { lease -> client_hostname = parse_host_name (cfile); if (lease -> client_hostname) parse_semi (cfile); else { parse_warn (cfile, "expecting a hostname."); skip_to_semi (cfile); lease_dereference (&lease, MDL); return 0; } } break; case BILLING: seenbit = 2048; class = (struct class *)0; token = next_token (&val, (unsigned *)0, cfile); if (token == CLASS) { token = next_token (&val, (unsigned *)0, cfile); if (token != STRING) { parse_warn (cfile, "expecting string"); if (token != SEMI) skip_to_semi (cfile); token = BILLING; break; } if (lease -> billing_class) class_dereference (&lease -> billing_class, MDL); find_class (&class, val, MDL); if (!class) parse_warn (cfile, "unknown class %s", val); parse_semi (cfile); } else if (token == SUBCLASS) { if (lease -> billing_class) class_dereference (&lease -> billing_class, MDL); parse_class_declaration(&class, cfile, NULL, CLASS_TYPE_SUBCLASS); } else { parse_warn (cfile, "expecting \"class\""); if (token != SEMI) skip_to_semi (cfile); } if (class) { class_reference (&lease -> billing_class, class, MDL); class_dereference (&class, MDL); } break; case ON: on = (struct executable_statement *)0; lose = 0; if (!parse_on_statement (&on, cfile, &lose)) { skip_to_rbrace (cfile, 1); lease_dereference (&lease, MDL); return 0; } seenbit = 0; if ((on -> data.on.evtypes & ON_EXPIRY) && on -> data.on.statements) { seenbit |= 16384; executable_statement_reference (&lease -> on_expiry, on -> data.on.statements, MDL); } if ((on -> data.on.evtypes & ON_RELEASE) && on -> data.on.statements) { seenbit |= 32768; executable_statement_reference (&lease -> on_release, on -> data.on.statements, MDL); } executable_statement_dereference (&on, MDL); break; case OPTION: case SUPERSEDE: noequal = 0; seenbit = 0; oc = (struct option_cache *)0; if (parse_option_decl (&oc, cfile)) { if (oc -> option -> universe != &agent_universe) { parse_warn (cfile, "agent option expected."); option_cache_dereference (&oc, MDL); break; } if (!lease -> agent_options && !(option_chain_head_allocate (&lease -> agent_options, MDL))) { log_error ("no memory to stash agent option"); break; } for (p = &lease -> agent_options -> first; *p; p = &((*p) -> cdr)) ; *p = cons (0, 0); option_cache_reference (((struct option_cache **) &((*p) -> car)), oc, MDL); option_cache_dereference (&oc, MDL); } break; case TOKEN_SET: noequal = 0; token = next_token (&val, (unsigned *)0, cfile); if (token != NAME && token != NUMBER_OR_NAME) { parse_warn (cfile, "%s can't be a variable name", val); badset: skip_to_semi (cfile); lease_dereference (&lease, MDL); return 0; } seenbit = 0; special_set: if (lease -> scope) binding = find_binding (lease -> scope, val); else binding = (struct binding *)0; if (!binding) { if (!lease -> scope) if (!(binding_scope_allocate (&lease -> scope, MDL))) log_fatal ("no memory for scope"); binding = dmalloc (sizeof *binding, MDL); if (!binding) log_fatal ("No memory for lease %s.", "binding"); memset (binding, 0, sizeof *binding); binding -> name = dmalloc (strlen (val) + 1, MDL); if (!binding -> name) log_fatal ("No memory for binding %s.", "name"); strcpy (binding -> name, val); newbinding = 1; } else { newbinding = 0; } nv = NULL; if (!binding_value_allocate(&nv, MDL)) log_fatal("no memory for binding value."); if (!noequal) { token = next_token (&val, (unsigned *)0, cfile); if (token != EQUAL) { parse_warn (cfile, "expecting '=' in set statement."); goto badset; } } if (!parse_binding_value(cfile, nv)) { binding_value_dereference(&nv, MDL); lease_dereference(&lease, MDL); return 0; } if (newbinding) { binding_value_reference(&binding->value, nv, MDL); binding->next = lease->scope->bindings; lease->scope->bindings = binding; } else { binding_value_dereference(&binding->value, MDL); binding_value_reference(&binding->value, nv, MDL); } binding_value_dereference(&nv, MDL); parse_semi(cfile); break; /* case NAME: */ default: if (!strcasecmp (val, "ddns-fwd-name")) { seenbit = 4096; noequal = 1; goto special_set; } else if (!strcasecmp (val, "ddns-rev-name")) { seenbit = 8192; noequal = 1; goto special_set; } else parse_warn(cfile, "Unexpected configuration " "directive."); skip_to_semi (cfile); seenbit = 0; lease_dereference (&lease, MDL); return 0; } if (seenmask & seenbit) { parse_warn (cfile, "Too many %s parameters in lease %s\n", tbuf, piaddr (lease -> ip_addr)); } else seenmask |= seenbit; } while (1); /* If no binding state is specified, make one up. */ if (!(seenmask & 256)) { if (lease -> ends > cur_time || lease -> on_expiry || lease -> on_release) lease -> binding_state = FTS_ACTIVE; #if defined (FAILOVER_PROTOCOL) else if (lease -> pool && lease -> pool -> failover_peer) lease -> binding_state = FTS_EXPIRED; #endif else lease -> binding_state = FTS_FREE; if (lease -> binding_state == FTS_ACTIVE) { #if defined (FAILOVER_PROTOCOL) if (lease -> pool && lease -> pool -> failover_peer) lease -> next_binding_state = FTS_EXPIRED; else #endif lease -> next_binding_state = FTS_FREE; } else lease -> next_binding_state = lease -> binding_state; /* The most conservative rewind state implies no rewind. */ lease->rewind_binding_state = lease->binding_state; } if (!(seenmask & 65536)) lease -> tstp = lease -> ends; lease_reference (lp, lease, MDL); lease_dereference (&lease, MDL); return 1; } /* Parse the right side of a 'binding value'. * * set foo = "bar"; is a string * set foo = false; is a boolean * set foo = %31; is a numeric value. */ static int parse_binding_value(struct parse *cfile, struct binding_value *value) { struct data_string *data; unsigned char *s; const char *val; unsigned buflen; int token; if ((cfile == NULL) || (value == NULL)) log_fatal("Invalid arguments at %s:%d.", MDL); token = peek_token(&val, NULL, cfile); if (token == STRING) { token = next_token(&val, &buflen, cfile); value->type = binding_data; value->value.data.len = buflen; data = &value->value.data; if (!buffer_allocate(&data->buffer, buflen + 1, MDL)) log_fatal ("No memory for binding."); memcpy(data->buffer->data, val, buflen + 1); data->data = data->buffer->data; data->terminated = 1; } else if (token == NUMBER_OR_NAME) { value->type = binding_data; data = &value->value.data; s = parse_numeric_aggregate(cfile, NULL, &data->len, ':', 16, 8); if (s == NULL) { skip_to_semi(cfile); return 0; } if (data->len) { if (!buffer_allocate(&data->buffer, data->len + 1, MDL)) log_fatal("No memory for binding."); memcpy(data->buffer->data, s, data->len); data->data = data->buffer->data; dfree (s, MDL); } } else if (token == PERCENT) { token = next_token(&val, NULL, cfile); token = next_token(&val, NULL, cfile); if (token != NUMBER) { parse_warn(cfile, "expecting decimal number."); if (token != SEMI) skip_to_semi(cfile); return 0; } value->type = binding_numeric; value->value.intval = atol(val); } else if (token == NAME) { token = next_token(&val, NULL, cfile); value->type = binding_boolean; if (!strcasecmp(val, "true")) value->value.boolean = 1; else if (!strcasecmp(val, "false")) value->value.boolean = 0; else { parse_warn(cfile, "expecting true or false"); if (token != SEMI) skip_to_semi(cfile); return 0; } } else { parse_warn (cfile, "expecting a constant value."); if (token != SEMI) skip_to_semi (cfile); return 0; } return 1; } /* address-range-declaration :== ip-address ip-address SEMI | DYNAMIC_BOOTP ip-address ip-address SEMI */ void parse_address_range (cfile, group, type, inpool, lpchain) struct parse *cfile; struct group *group; int type; struct pool *inpool; struct lease **lpchain; { struct iaddr low, high, net; unsigned char addr [4]; unsigned len = sizeof addr; enum dhcp_token token; const char *val; int dynamic = 0; struct subnet *subnet; struct shared_network *share; struct pool *pool; isc_result_t status; if ((token = peek_token (&val, (unsigned *)0, cfile)) == DYNAMIC_BOOTP) { token = next_token (&val, (unsigned *)0, cfile); dynamic = 1; } /* Get the bottom address in the range... */ if (!parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8)) return; memcpy (low.iabuf, addr, len); low.len = len; /* Only one address? */ token = peek_token (&val, (unsigned *)0, cfile); if (token == SEMI) high = low; else { /* Get the top address in the range... */ if (!parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8)) return; memcpy (high.iabuf, addr, len); high.len = len; } token = next_token (&val, (unsigned *)0, cfile); if (token != SEMI) { parse_warn (cfile, "semicolon expected."); skip_to_semi (cfile); return; } if (type == SUBNET_DECL) { subnet = group -> subnet; share = subnet -> shared_network; } else { share = group -> shared_network; for (subnet = share -> subnets; subnet; subnet = subnet -> next_sibling) { net = subnet_number (low, subnet -> netmask); if (addr_eq (net, subnet -> net)) break; } if (!subnet) { parse_warn (cfile, "address range not on network %s", group -> shared_network -> name); log_error ("Be sure to place pool statement after %s", "related subnet declarations."); return; } } if (!inpool) { struct pool *last = (struct pool *)0; /* If we're permitting dynamic bootp for this range, then look for a pool with an empty prohibit list and a permit list with one entry that permits all clients. */ for (pool = share -> pools; pool; pool = pool -> next) { if ((!dynamic && !pool -> permit_list && pool -> prohibit_list && !pool -> prohibit_list -> next && (pool -> prohibit_list -> type == permit_dynamic_bootp_clients)) || (dynamic && !pool -> prohibit_list && pool -> permit_list && !pool -> permit_list -> next && (pool -> permit_list -> type == permit_all_clients))) { break; } last = pool; } /* If we didn't get a pool, make one. */ if (!pool) { struct permit *p; status = pool_allocate (&pool, MDL); if (status != ISC_R_SUCCESS) log_fatal ("no memory for ad-hoc pool: %s", isc_result_totext (status)); p = new_permit (MDL); if (!p) log_fatal ("no memory for ad-hoc permit."); /* Dynamic pools permit all clients. Otherwise we prohibit BOOTP clients. */ if (dynamic) { p -> type = permit_all_clients; pool -> permit_list = p; } else { p -> type = permit_dynamic_bootp_clients; pool -> prohibit_list = p; } if (share -> pools) pool_reference (&last -> next, pool, MDL); else pool_reference (&share -> pools, pool, MDL); shared_network_reference (&pool -> shared_network, share, MDL); if (!clone_group (&pool -> group, share -> group, MDL)) log_fatal ("no memory for anon pool group."); } else { pool = (struct pool *)0; if (last) pool_reference (&pool, last, MDL); else pool_reference (&pool, share -> pools, MDL); } } else { pool = (struct pool *)0; pool_reference (&pool, inpool, MDL); } #if defined (FAILOVER_PROTOCOL) if (pool -> failover_peer && dynamic) { /* Doctor, do you think I'm overly sensitive about getting bug reports I can't fix? */ parse_warn (cfile, "dynamic-bootp flag is %s", "not permitted for address"); log_error ("range declarations where there is a failover"); log_error ("peer in scope. If you wish to declare an"); log_error ("address range from which dynamic bootp leases"); log_error ("can be allocated, please declare it within a"); log_error ("pool declaration that also contains the \"no"); log_error ("failover\" statement. The failover protocol"); log_error ("itself does not permit dynamic bootp - this"); log_error ("is not a limitation specific to the ISC DHCP"); log_error ("server. Please don't ask me to defend this"); log_error ("until you have read and really tried %s", "to understand"); log_error ("the failover protocol specification."); /* We don't actually bomb at this point - instead, we let parse_lease_file notice the error and bomb at that point - it's easier. */ } #endif /* FAILOVER_PROTOCOL */ /* Create the new address range... */ new_address_range (cfile, low, high, subnet, pool, lpchain); pool_dereference (&pool, MDL); } #ifdef DHCPv6 static void add_ipv6_pool_to_subnet(struct subnet *subnet, u_int16_t type, struct iaddr *lo_addr, int bits, int units) { struct ipv6_pool *pool; struct shared_network *share; struct in6_addr tmp_in6_addr; int num_pools; struct ipv6_pool **tmp; share = subnet->shared_network; /* * Create our pool. */ if (lo_addr->len != sizeof(tmp_in6_addr)) { log_fatal("Internal error: Attempt to add non-IPv6 address " "to IPv6 shared network."); } memcpy(&tmp_in6_addr, lo_addr->iabuf, sizeof(tmp_in6_addr)); pool = NULL; if (ipv6_pool_allocate(&pool, type, &tmp_in6_addr, bits, units, MDL) != ISC_R_SUCCESS) { log_fatal("Out of memory"); } /* * Add to our global IPv6 pool set. */ if (add_ipv6_pool(pool) != ISC_R_SUCCESS) { log_fatal ("Out of memory"); } /* * Link the pool to its network. */ pool->subnet = NULL; subnet_reference(&pool->subnet, subnet, MDL); pool->shared_network = NULL; shared_network_reference(&pool->shared_network, share, MDL); /* * Increase our array size for ipv6_pools in the shared_network. */ if (share->ipv6_pools == NULL) { num_pools = 0; } else { num_pools = 0; while (share->ipv6_pools[num_pools] != NULL) { num_pools++; } } tmp = dmalloc(sizeof(struct ipv6_pool *) * (num_pools + 2), MDL); if (tmp == NULL) { log_fatal("Out of memory"); } if (num_pools > 0) { memcpy(tmp, share->ipv6_pools, sizeof(struct ipv6_pool *) * num_pools); } if (share->ipv6_pools != NULL) { dfree(share->ipv6_pools, MDL); } share->ipv6_pools = tmp; /* * Record this pool in our array of pools for this shared network. */ ipv6_pool_reference(&share->ipv6_pools[num_pools], pool, MDL); share->ipv6_pools[num_pools+1] = NULL; } /* address-range6-declaration :== ip-address6 ip-address6 SEMI | ip-address6 SLASH number SEMI | ip-address6 [SLASH number] TEMPORARY SEMI */ void parse_address_range6(struct parse *cfile, struct group *group) { struct iaddr lo, hi; int bits; enum dhcp_token token; const char *val; struct iaddrcidrnetlist *nets; struct iaddrcidrnetlist *p; u_int16_t type = D6O_IA_NA; if (local_family != AF_INET6) { parse_warn(cfile, "range6 statement is only supported " "in DHCPv6 mode."); skip_to_semi(cfile); return; } /* This is enforced by the caller, this is just a sanity check. */ if (group->subnet == NULL) log_fatal("Impossible condition at %s:%d.", MDL); /* * Read starting address. */ if (!parse_ip6_addr(cfile, &lo)) { return; } /* * See if we we're using range or CIDR notation or TEMPORARY */ token = peek_token(&val, NULL, cfile); if (token == SLASH) { /* * '/' means CIDR notation, so read the bits we want. */ next_token(NULL, NULL, cfile); token = next_token(&val, NULL, cfile); if (token != NUMBER) { parse_warn(cfile, "expecting number"); skip_to_semi(cfile); return; } bits = atoi(val); if ((bits < 0) || (bits > 128)) { parse_warn(cfile, "networks have 0 to 128 bits"); skip_to_semi(cfile); return; } if (!is_cidr_mask_valid(&lo, bits)) { parse_warn(cfile, "network mask too short"); skip_to_semi(cfile); return; } /* * can be temporary (RFC 4941 like) */ token = peek_token(&val, NULL, cfile); if (token == TEMPORARY) { if (bits < 64) parse_warn(cfile, "temporary mask too short"); if (bits == 128) parse_warn(cfile, "temporary singleton?"); token = next_token(NULL, NULL, cfile); type = D6O_IA_TA; } add_ipv6_pool_to_subnet(group->subnet, type, &lo, bits, 128); } else if (token == TEMPORARY) { /* * temporary (RFC 4941) */ type = D6O_IA_TA; next_token(NULL, NULL, cfile); bits = 64; if (!is_cidr_mask_valid(&lo, bits)) { parse_warn(cfile, "network mask too short"); skip_to_semi(cfile); return; } add_ipv6_pool_to_subnet(group->subnet, type, &lo, bits, 128); } else { /* * No '/', so we are looking for the end address of * the IPv6 pool. */ if (!parse_ip6_addr(cfile, &hi)) { return; } /* * Convert our range to a set of CIDR networks. */ nets = NULL; if (range2cidr(&nets, &lo, &hi) != ISC_R_SUCCESS) { log_fatal("Error converting range to CIDR networks"); } for (p=nets; p != NULL; p=p->next) { add_ipv6_pool_to_subnet(group->subnet, type, &p->cidrnet.lo_addr, p->cidrnet.bits, 128); } free_iaddrcidrnetlist(&nets); } token = next_token(NULL, NULL, cfile); if (token != SEMI) { parse_warn(cfile, "semicolon expected."); skip_to_semi(cfile); return; } } /* prefix6-declaration :== ip-address6 ip-address6 SLASH number SEMI */ void parse_prefix6(struct parse *cfile, struct group *group) { struct iaddr lo, hi; int bits; enum dhcp_token token; const char *val; struct iaddrcidrnetlist *nets; struct iaddrcidrnetlist *p; if (local_family != AF_INET6) { parse_warn(cfile, "prefix6 statement is only supported " "in DHCPv6 mode."); skip_to_semi(cfile); return; } /* This is enforced by the caller, so it's just a sanity check. */ if (group->subnet == NULL) log_fatal("Impossible condition at %s:%d.", MDL); /* * Read starting and ending address. */ if (!parse_ip6_addr(cfile, &lo)) { return; } if (!parse_ip6_addr(cfile, &hi)) { return; } /* * Next is '/' number ';'. */ token = next_token(NULL, NULL, cfile); if (token != SLASH) { parse_warn(cfile, "expecting '/'"); if (token != SEMI) skip_to_semi(cfile); return; } token = next_token(&val, NULL, cfile); if (token != NUMBER) { parse_warn(cfile, "expecting number"); if (token != SEMI) skip_to_semi(cfile); return; } bits = atoi(val); if ((bits <= 0) || (bits >= 128)) { parse_warn(cfile, "networks have 0 to 128 bits (exclusive)"); return; } if (!is_cidr_mask_valid(&lo, bits) || !is_cidr_mask_valid(&hi, bits)) { parse_warn(cfile, "network mask too short"); return; } token = next_token(NULL, NULL, cfile); if (token != SEMI) { parse_warn(cfile, "semicolon expected."); skip_to_semi(cfile); return; } /* * Convert our range to a set of CIDR networks. */ nets = NULL; if (range2cidr(&nets, &lo, &hi) != ISC_R_SUCCESS) { log_fatal("Error converting prefix to CIDR"); } for (p = nets; p != NULL; p = p->next) { /* Normalize and check. */ if (p->cidrnet.bits == 128) { p->cidrnet.bits = bits; } if (p->cidrnet.bits > bits) { parse_warn(cfile, "impossible mask length"); continue; } add_ipv6_pool_to_subnet(group->subnet, D6O_IA_PD, &p->cidrnet.lo_addr, p->cidrnet.bits, bits); } free_iaddrcidrnetlist(&nets); } /* fixed-prefix6 :== ip6-address SLASH number SEMI */ void parse_fixed_prefix6(struct parse *cfile, struct host_decl *host_decl) { struct iaddrcidrnetlist *ia, **h; enum dhcp_token token; const char *val; /* * Get the head of the fixed-prefix list. */ h = &host_decl->fixed_prefix; /* * Walk to the end. */ while (*h != NULL) { h = &((*h)->next); } /* * Allocate a new iaddrcidrnetlist structure. */ ia = dmalloc(sizeof(*ia), MDL); if (!ia) { log_fatal("Out of memory"); } /* * Parse it. */ if (!parse_ip6_addr(cfile, &ia->cidrnet.lo_addr)) { dfree(ia, MDL); return; } token = next_token(NULL, NULL, cfile); if (token != SLASH) { dfree(ia, MDL); parse_warn(cfile, "expecting '/'"); if (token != SEMI) skip_to_semi(cfile); return; } token = next_token(&val, NULL, cfile); if (token != NUMBER) { dfree(ia, MDL); parse_warn(cfile, "expecting number"); if (token != SEMI) skip_to_semi(cfile); return; } token = next_token(NULL, NULL, cfile); if (token != SEMI) { dfree(ia, MDL); parse_warn(cfile, "semicolon expected."); skip_to_semi(cfile); return; } /* * Fill it. */ ia->cidrnet.bits = atoi(val); if ((ia->cidrnet.bits < 0) || (ia->cidrnet.bits > 128)) { dfree(ia, MDL); parse_warn(cfile, "networks have 0 to 128 bits"); return; } if (!is_cidr_mask_valid(&ia->cidrnet.lo_addr, ia->cidrnet.bits)) { dfree(ia, MDL); parse_warn(cfile, "network mask too short"); return; } /* * Store it. */ *h = ia; return; } #endif /* DHCPv6 */ /* allow-deny-keyword :== BOOTP | BOOTING | DYNAMIC_BOOTP | UNKNOWN_CLIENTS */ int parse_allow_deny (oc, cfile, flag) struct option_cache **oc; struct parse *cfile; int flag; { enum dhcp_token token; const char *val; unsigned char rf = flag; unsigned code; struct option *option = NULL; struct expression *data = (struct expression *)0; int status; if (!make_const_data (&data, &rf, 1, 0, 1, MDL)) return 0; token = next_token (&val, (unsigned *)0, cfile); switch (token) { case TOKEN_BOOTP: code = SV_ALLOW_BOOTP; break; case BOOTING: code = SV_ALLOW_BOOTING; break; case DYNAMIC_BOOTP: code = SV_DYNAMIC_BOOTP; break; case UNKNOWN_CLIENTS: code = SV_BOOT_UNKNOWN_CLIENTS; break; case DUPLICATES: code = SV_DUPLICATES; break; case DECLINES: code= SV_DECLINES; break; case CLIENT_UPDATES: code = SV_CLIENT_UPDATES; break; case LEASEQUERY: code = SV_LEASEQUERY; break; default: parse_warn (cfile, "expecting allow/deny key"); skip_to_semi (cfile); return 0; } /* Reference on option is passed to option cache. */ if (!option_code_hash_lookup(&option, server_universe.code_hash, &code, 0, MDL)) log_fatal("Unable to find server option %u (%s:%d).", code, MDL); status = option_cache(oc, NULL, data, option, MDL); expression_dereference (&data, MDL); parse_semi (cfile); return status; } void parse_ia_na_declaration(struct parse *cfile) { #if !defined(DHCPv6) parse_warn(cfile, "No DHCPv6 support."); skip_to_semi(cfile); #else /* defined(DHCPv6) */ enum dhcp_token token; struct ia_xx *ia; const char *val; struct ia_xx *old_ia; unsigned int len; u_int32_t iaid; struct iaddr iaddr; binding_state_t state; u_int32_t prefer; u_int32_t valid; TIME end_time; struct iasubopt *iaaddr; struct ipv6_pool *pool; char addr_buf[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")]; isc_boolean_t newbinding; struct binding_scope *scope=NULL; struct binding *bnd; struct binding_value *nv=NULL; if (local_family != AF_INET6) { parse_warn(cfile, "IA_NA is only supported in DHCPv6 mode."); skip_to_semi(cfile); return; } token = next_token(&val, &len, cfile); if (token != STRING) { parse_warn(cfile, "corrupt lease file; " "expecting an iaid+ia_na string"); skip_to_semi(cfile); return; } if (len < 5) { parse_warn(cfile, "corrupt lease file; " "iaid+ia_na string too short"); skip_to_semi(cfile); return; } memcpy(&iaid, val, 4); ia = NULL; if (ia_allocate(&ia, iaid, val+4, len-4, MDL) != ISC_R_SUCCESS) { log_fatal("Out of memory."); } ia->ia_type = D6O_IA_NA; token = next_token(&val, NULL, cfile); if (token != LBRACE) { parse_warn(cfile, "corrupt lease file; expecting left brace"); skip_to_semi(cfile); return; } for (;;) { token = next_token(&val, NULL, cfile); if (token == RBRACE) break; if (token == CLTT) { ia->cltt = parse_date (cfile); continue; } if (token != IAADDR) { parse_warn(cfile, "corrupt lease file; " "expecting IAADDR or right brace"); skip_to_semi(cfile); return; } if (!parse_ip6_addr(cfile, &iaddr)) { parse_warn(cfile, "corrupt lease file; " "expecting IPv6 address"); skip_to_semi(cfile); return; } token = next_token(&val, NULL, cfile); if (token != LBRACE) { parse_warn(cfile, "corrupt lease file; " "expecting left brace"); skip_to_semi(cfile); return; } state = FTS_LAST+1; prefer = valid = 0; end_time = -1; for (;;) { token = next_token(&val, NULL, cfile); if (token == RBRACE) break; switch(token) { /* Lease binding state. */ case BINDING: token = next_token(&val, NULL, cfile); if (token != STATE) { parse_warn(cfile, "corrupt lease file; " "expecting state"); skip_to_semi(cfile); return; } token = next_token(&val, NULL, cfile); switch (token) { case TOKEN_ABANDONED: state = FTS_ABANDONED; break; case TOKEN_FREE: state = FTS_FREE; break; case TOKEN_ACTIVE: state = FTS_ACTIVE; break; case TOKEN_EXPIRED: state = FTS_EXPIRED; break; case TOKEN_RELEASED: state = FTS_RELEASED; break; default: parse_warn(cfile, "corrupt lease " "file; " "expecting a " "binding state."); skip_to_semi(cfile); return; } token = next_token(&val, NULL, cfile); if (token != SEMI) { parse_warn(cfile, "corrupt lease file; " "expecting " "semicolon."); } break; /* Lease preferred lifetime. */ case PREFERRED_LIFE: token = next_token(&val, NULL, cfile); if (token != NUMBER) { parse_warn(cfile, "%s is not a valid " "preferred time", val); skip_to_semi(cfile); continue; } prefer = atoi (val); /* * Currently we peek for the semi-colon to * allow processing of older lease files that * don't have the semi-colon. Eventually we * should remove the peeking code. */ token = peek_token(&val, NULL, cfile); if (token == SEMI) { token = next_token(&val, NULL, cfile); } else { parse_warn(cfile, "corrupt lease file; " "expecting semicolon."); } break; /* Lease valid lifetime. */ case MAX_LIFE: token = next_token(&val, NULL, cfile); if (token != NUMBER) { parse_warn(cfile, "%s is not a valid " "max time", val); skip_to_semi(cfile); continue; } valid = atoi (val); /* * Currently we peek for the semi-colon to * allow processing of older lease files that * don't have the semi-colon. Eventually we * should remove the peeking code. */ token = peek_token(&val, NULL, cfile); if (token == SEMI) { token = next_token(&val, NULL, cfile); } else { parse_warn(cfile, "corrupt lease file; " "expecting semicolon."); } break; /* Lease expiration time. */ case ENDS: end_time = parse_date(cfile); break; /* Lease binding scopes. */ case TOKEN_SET: token = next_token(&val, NULL, cfile); if ((token != NAME) && (token != NUMBER_OR_NAME)) { parse_warn(cfile, "%s is not a valid " "variable name", val); skip_to_semi(cfile); continue; } if (scope != NULL) bnd = find_binding(scope, val); else { if (!binding_scope_allocate(&scope, MDL)) { log_fatal("Out of memory for " "lease binding " "scope."); } bnd = NULL; } if (bnd == NULL) { bnd = dmalloc(sizeof(*bnd), MDL); if (bnd == NULL) { log_fatal("No memory for " "lease binding."); } bnd->name = dmalloc(strlen(val) + 1, MDL); if (bnd->name == NULL) { log_fatal("No memory for " "binding name."); } strcpy(bnd->name, val); newbinding = ISC_TRUE; } else { newbinding = ISC_FALSE; } if (!binding_value_allocate(&nv, MDL)) { log_fatal("no memory for binding " "value."); } token = next_token(NULL, NULL, cfile); if (token != EQUAL) { parse_warn(cfile, "expecting '=' in " "set statement."); goto binding_err; } if (!parse_binding_value(cfile, nv)) { binding_err: binding_value_dereference(&nv, MDL); binding_scope_dereference(&scope, MDL); return; } if (newbinding) { binding_value_reference(&bnd->value, nv, MDL); bnd->next = scope->bindings; scope->bindings = bnd; } else { binding_value_dereference(&bnd->value, MDL); binding_value_reference(&bnd->value, nv, MDL); } binding_value_dereference(&nv, MDL); parse_semi(cfile); break; default: parse_warn(cfile, "corrupt lease file; " "expecting ia_na contents, " "got '%s'", val); skip_to_semi(cfile); continue; } } if (state == FTS_LAST+1) { parse_warn(cfile, "corrupt lease file; " "missing state in iaaddr"); return; } if (end_time == -1) { parse_warn(cfile, "corrupt lease file; " "missing end time in iaaddr"); return; } iaaddr = NULL; if (iasubopt_allocate(&iaaddr, MDL) != ISC_R_SUCCESS) { log_fatal("Out of memory."); } memcpy(&iaaddr->addr, iaddr.iabuf, sizeof(iaaddr->addr)); iaaddr->plen = 0; iaaddr->state = state; iaaddr->prefer = prefer; iaaddr->valid = valid; if (iaaddr->state == FTS_RELEASED) iaaddr->hard_lifetime_end_time = end_time; if (scope != NULL) { binding_scope_reference(&iaaddr->scope, scope, MDL); binding_scope_dereference(&scope, MDL); } /* find the pool this address is in */ pool = NULL; if (find_ipv6_pool(&pool, D6O_IA_NA, &iaaddr->addr) != ISC_R_SUCCESS) { inet_ntop(AF_INET6, &iaaddr->addr, addr_buf, sizeof(addr_buf)); parse_warn(cfile, "no pool found for address %s", addr_buf); return; } /* remove old information */ if (cleanup_lease6(ia_na_active, pool, iaaddr, ia) != ISC_R_SUCCESS) { inet_ntop(AF_INET6, &iaaddr->addr, addr_buf, sizeof(addr_buf)); parse_warn(cfile, "duplicate na lease for address %s", addr_buf); } /* * if we like the lease we add it to our various structues * otherwise we leave it and it will get cleaned when we * do the iasubopt_dereference. */ if ((state == FTS_ACTIVE) || (state == FTS_ABANDONED)) { ia_add_iasubopt(ia, iaaddr, MDL); ia_reference(&iaaddr->ia, ia, MDL); add_lease6(pool, iaaddr, end_time); } iasubopt_dereference(&iaaddr, MDL); ipv6_pool_dereference(&pool, MDL); } /* * If we have an existing record for this IA_NA, remove it. */ old_ia = NULL; if (ia_hash_lookup(&old_ia, ia_na_active, (unsigned char *)ia->iaid_duid.data, ia->iaid_duid.len, MDL)) { ia_hash_delete(ia_na_active, (unsigned char *)ia->iaid_duid.data, ia->iaid_duid.len, MDL); ia_dereference(&old_ia, MDL); } /* * If we have addresses, add this, otherwise don't bother. */ if (ia->num_iasubopt > 0) { ia_hash_add(ia_na_active, (unsigned char *)ia->iaid_duid.data, ia->iaid_duid.len, ia, MDL); } ia_dereference(&ia, MDL); #endif /* defined(DHCPv6) */ } void parse_ia_ta_declaration(struct parse *cfile) { #if !defined(DHCPv6) parse_warn(cfile, "No DHCPv6 support."); skip_to_semi(cfile); #else /* defined(DHCPv6) */ enum dhcp_token token; struct ia_xx *ia; const char *val; struct ia_xx *old_ia; unsigned int len; u_int32_t iaid; struct iaddr iaddr; binding_state_t state; u_int32_t prefer; u_int32_t valid; TIME end_time; struct iasubopt *iaaddr; struct ipv6_pool *pool; char addr_buf[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")]; isc_boolean_t newbinding; struct binding_scope *scope=NULL; struct binding *bnd; struct binding_value *nv=NULL; if (local_family != AF_INET6) { parse_warn(cfile, "IA_TA is only supported in DHCPv6 mode."); skip_to_semi(cfile); return; } token = next_token(&val, &len, cfile); if (token != STRING) { parse_warn(cfile, "corrupt lease file; " "expecting an iaid+ia_ta string"); skip_to_semi(cfile); return; } if (len < 5) { parse_warn(cfile, "corrupt lease file; " "iaid+ia_ta string too short"); skip_to_semi(cfile); return; } memcpy(&iaid, val, 4); ia = NULL; if (ia_allocate(&ia, iaid, val+4, len-4, MDL) != ISC_R_SUCCESS) { log_fatal("Out of memory."); } ia->ia_type = D6O_IA_TA; token = next_token(&val, NULL, cfile); if (token != LBRACE) { parse_warn(cfile, "corrupt lease file; expecting left brace"); skip_to_semi(cfile); return; } for (;;) { token = next_token(&val, NULL, cfile); if (token == RBRACE) break; if (token == CLTT) { ia->cltt = parse_date (cfile); continue; } if (token != IAADDR) { parse_warn(cfile, "corrupt lease file; " "expecting IAADDR or right brace"); skip_to_semi(cfile); return; } if (!parse_ip6_addr(cfile, &iaddr)) { parse_warn(cfile, "corrupt lease file; " "expecting IPv6 address"); skip_to_semi(cfile); return; } token = next_token(&val, NULL, cfile); if (token != LBRACE) { parse_warn(cfile, "corrupt lease file; " "expecting left brace"); skip_to_semi(cfile); return; } state = FTS_LAST+1; prefer = valid = 0; end_time = -1; for (;;) { token = next_token(&val, NULL, cfile); if (token == RBRACE) break; switch(token) { /* Lease binding state. */ case BINDING: token = next_token(&val, NULL, cfile); if (token != STATE) { parse_warn(cfile, "corrupt lease file; " "expecting state"); skip_to_semi(cfile); return; } token = next_token(&val, NULL, cfile); switch (token) { case TOKEN_ABANDONED: state = FTS_ABANDONED; break; case TOKEN_FREE: state = FTS_FREE; break; case TOKEN_ACTIVE: state = FTS_ACTIVE; break; case TOKEN_EXPIRED: state = FTS_EXPIRED; break; case TOKEN_RELEASED: state = FTS_RELEASED; break; default: parse_warn(cfile, "corrupt lease " "file; " "expecting a " "binding state."); skip_to_semi(cfile); return; } token = next_token(&val, NULL, cfile); if (token != SEMI) { parse_warn(cfile, "corrupt lease file; " "expecting " "semicolon."); } break; /* Lease preferred lifetime. */ case PREFERRED_LIFE: token = next_token(&val, NULL, cfile); if (token != NUMBER) { parse_warn(cfile, "%s is not a valid " "preferred time", val); skip_to_semi(cfile); continue; } prefer = atoi (val); /* * Currently we peek for the semi-colon to * allow processing of older lease files that * don't have the semi-colon. Eventually we * should remove the peeking code. */ token = peek_token(&val, NULL, cfile); if (token == SEMI) { token = next_token(&val, NULL, cfile); } else { parse_warn(cfile, "corrupt lease file; " "expecting semicolon."); } break; /* Lease valid lifetime. */ case MAX_LIFE: token = next_token(&val, NULL, cfile); if (token != NUMBER) { parse_warn(cfile, "%s is not a valid " "max time", val); skip_to_semi(cfile); continue; } valid = atoi (val); /* * Currently we peek for the semi-colon to * allow processing of older lease files that * don't have the semi-colon. Eventually we * should remove the peeking code. */ token = peek_token(&val, NULL, cfile); if (token == SEMI) { token = next_token(&val, NULL, cfile); } else { parse_warn(cfile, "corrupt lease file; " "expecting semicolon."); } break; /* Lease expiration time. */ case ENDS: end_time = parse_date(cfile); break; /* Lease binding scopes. */ case TOKEN_SET: token = next_token(&val, NULL, cfile); if ((token != NAME) && (token != NUMBER_OR_NAME)) { parse_warn(cfile, "%s is not a valid " "variable name", val); skip_to_semi(cfile); continue; } if (scope != NULL) bnd = find_binding(scope, val); else { if (!binding_scope_allocate(&scope, MDL)) { log_fatal("Out of memory for " "lease binding " "scope."); } bnd = NULL; } if (bnd == NULL) { bnd = dmalloc(sizeof(*bnd), MDL); if (bnd == NULL) { log_fatal("No memory for " "lease binding."); } bnd->name = dmalloc(strlen(val) + 1, MDL); if (bnd->name == NULL) { log_fatal("No memory for " "binding name."); } strcpy(bnd->name, val); newbinding = ISC_TRUE; } else { newbinding = ISC_FALSE; } if (!binding_value_allocate(&nv, MDL)) { log_fatal("no memory for binding " "value."); } token = next_token(NULL, NULL, cfile); if (token != EQUAL) { parse_warn(cfile, "expecting '=' in " "set statement."); goto binding_err; } if (!parse_binding_value(cfile, nv)) { binding_err: binding_value_dereference(&nv, MDL); binding_scope_dereference(&scope, MDL); return; } if (newbinding) { binding_value_reference(&bnd->value, nv, MDL); bnd->next = scope->bindings; scope->bindings = bnd; } else { binding_value_dereference(&bnd->value, MDL); binding_value_reference(&bnd->value, nv, MDL); } binding_value_dereference(&nv, MDL); parse_semi(cfile); break; default: parse_warn(cfile, "corrupt lease file; " "expecting ia_ta contents, " "got '%s'", val); skip_to_semi(cfile); continue; } } if (state == FTS_LAST+1) { parse_warn(cfile, "corrupt lease file; " "missing state in iaaddr"); return; } if (end_time == -1) { parse_warn(cfile, "corrupt lease file; " "missing end time in iaaddr"); return; } iaaddr = NULL; if (iasubopt_allocate(&iaaddr, MDL) != ISC_R_SUCCESS) { log_fatal("Out of memory."); } memcpy(&iaaddr->addr, iaddr.iabuf, sizeof(iaaddr->addr)); iaaddr->plen = 0; iaaddr->state = state; iaaddr->prefer = prefer; iaaddr->valid = valid; if (iaaddr->state == FTS_RELEASED) iaaddr->hard_lifetime_end_time = end_time; if (scope != NULL) { binding_scope_reference(&iaaddr->scope, scope, MDL); binding_scope_dereference(&scope, MDL); } /* find the pool this address is in */ pool = NULL; if (find_ipv6_pool(&pool, D6O_IA_TA, &iaaddr->addr) != ISC_R_SUCCESS) { inet_ntop(AF_INET6, &iaaddr->addr, addr_buf, sizeof(addr_buf)); parse_warn(cfile, "no pool found for address %s", addr_buf); return; } /* remove old information */ if (cleanup_lease6(ia_ta_active, pool, iaaddr, ia) != ISC_R_SUCCESS) { inet_ntop(AF_INET6, &iaaddr->addr, addr_buf, sizeof(addr_buf)); parse_warn(cfile, "duplicate ta lease for address %s", addr_buf); } /* * if we like the lease we add it to our various structues * otherwise we leave it and it will get cleaned when we * do the iasubopt_dereference. */ if ((state == FTS_ACTIVE) || (state == FTS_ABANDONED)) { ia_add_iasubopt(ia, iaaddr, MDL); ia_reference(&iaaddr->ia, ia, MDL); add_lease6(pool, iaaddr, end_time); } ipv6_pool_dereference(&pool, MDL); iasubopt_dereference(&iaaddr, MDL); } /* * If we have an existing record for this IA_TA, remove it. */ old_ia = NULL; if (ia_hash_lookup(&old_ia, ia_ta_active, (unsigned char *)ia->iaid_duid.data, ia->iaid_duid.len, MDL)) { ia_hash_delete(ia_ta_active, (unsigned char *)ia->iaid_duid.data, ia->iaid_duid.len, MDL); ia_dereference(&old_ia, MDL); } /* * If we have addresses, add this, otherwise don't bother. */ if (ia->num_iasubopt > 0) { ia_hash_add(ia_ta_active, (unsigned char *)ia->iaid_duid.data, ia->iaid_duid.len, ia, MDL); } ia_dereference(&ia, MDL); #endif /* defined(DHCPv6) */ } void parse_ia_pd_declaration(struct parse *cfile) { #if !defined(DHCPv6) parse_warn(cfile, "No DHCPv6 support."); skip_to_semi(cfile); #else /* defined(DHCPv6) */ enum dhcp_token token; struct ia_xx *ia; const char *val; struct ia_xx *old_ia; unsigned int len; u_int32_t iaid; struct iaddr iaddr; u_int8_t plen; binding_state_t state; u_int32_t prefer; u_int32_t valid; TIME end_time; struct iasubopt *iapref; struct ipv6_pool *pool; char addr_buf[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")]; isc_boolean_t newbinding; struct binding_scope *scope=NULL; struct binding *bnd; struct binding_value *nv=NULL; if (local_family != AF_INET6) { parse_warn(cfile, "IA_PD is only supported in DHCPv6 mode."); skip_to_semi(cfile); return; } token = next_token(&val, &len, cfile); if (token != STRING) { parse_warn(cfile, "corrupt lease file; " "expecting an iaid+ia_pd string"); skip_to_semi(cfile); return; } if (len < 5) { parse_warn(cfile, "corrupt lease file; " "iaid+ia_pd string too short"); skip_to_semi(cfile); return; } memcpy(&iaid, val, 4); ia = NULL; if (ia_allocate(&ia, iaid, val+4, len-4, MDL) != ISC_R_SUCCESS) { log_fatal("Out of memory."); } ia->ia_type = D6O_IA_PD; token = next_token(&val, NULL, cfile); if (token != LBRACE) { parse_warn(cfile, "corrupt lease file; expecting left brace"); skip_to_semi(cfile); return; } for (;;) { token = next_token(&val, NULL, cfile); if (token == RBRACE) break; if (token == CLTT) { ia->cltt = parse_date (cfile); continue; } if (token != IAPREFIX) { parse_warn(cfile, "corrupt lease file; expecting " "IAPREFIX or right brace"); skip_to_semi(cfile); return; } if (!parse_ip6_prefix(cfile, &iaddr, &plen)) { parse_warn(cfile, "corrupt lease file; " "expecting IPv6 prefix"); skip_to_semi(cfile); return; } token = next_token(&val, NULL, cfile); if (token != LBRACE) { parse_warn(cfile, "corrupt lease file; " "expecting left brace"); skip_to_semi(cfile); return; } state = FTS_LAST+1; prefer = valid = 0; end_time = -1; for (;;) { token = next_token(&val, NULL, cfile); if (token == RBRACE) break; switch(token) { /* Prefix binding state. */ case BINDING: token = next_token(&val, NULL, cfile); if (token != STATE) { parse_warn(cfile, "corrupt lease file; " "expecting state"); skip_to_semi(cfile); return; } token = next_token(&val, NULL, cfile); switch (token) { case TOKEN_ABANDONED: state = FTS_ABANDONED; break; case TOKEN_FREE: state = FTS_FREE; break; case TOKEN_ACTIVE: state = FTS_ACTIVE; break; case TOKEN_EXPIRED: state = FTS_EXPIRED; break; case TOKEN_RELEASED: state = FTS_RELEASED; break; default: parse_warn(cfile, "corrupt lease " "file; " "expecting a " "binding state."); skip_to_semi(cfile); return; } token = next_token(&val, NULL, cfile); if (token != SEMI) { parse_warn(cfile, "corrupt lease file; " "expecting " "semicolon."); } break; /* Lease preferred lifetime. */ case PREFERRED_LIFE: token = next_token(&val, NULL, cfile); if (token != NUMBER) { parse_warn(cfile, "%s is not a valid " "preferred time", val); skip_to_semi(cfile); continue; } prefer = atoi (val); /* * Currently we peek for the semi-colon to * allow processing of older lease files that * don't have the semi-colon. Eventually we * should remove the peeking code. */ token = peek_token(&val, NULL, cfile); if (token == SEMI) { token = next_token(&val, NULL, cfile); } else { parse_warn(cfile, "corrupt lease file; " "expecting semicolon."); } break; /* Lease valid lifetime. */ case MAX_LIFE: token = next_token(&val, NULL, cfile); if (token != NUMBER) { parse_warn(cfile, "%s is not a valid " "max time", val); skip_to_semi(cfile); continue; } valid = atoi (val); /* * Currently we peek for the semi-colon to * allow processing of older lease files that * don't have the semi-colon. Eventually we * should remove the peeking code. */ token = peek_token(&val, NULL, cfile); if (token == SEMI) { token = next_token(&val, NULL, cfile); } else { parse_warn(cfile, "corrupt lease file; " "expecting semicolon."); } break; /* Prefix expiration time. */ case ENDS: end_time = parse_date(cfile); break; /* Prefix binding scopes. */ case TOKEN_SET: token = next_token(&val, NULL, cfile); if ((token != NAME) && (token != NUMBER_OR_NAME)) { parse_warn(cfile, "%s is not a valid " "variable name", val); skip_to_semi(cfile); continue; } if (scope != NULL) bnd = find_binding(scope, val); else { if (!binding_scope_allocate(&scope, MDL)) { log_fatal("Out of memory for " "lease binding " "scope."); } bnd = NULL; } if (bnd == NULL) { bnd = dmalloc(sizeof(*bnd), MDL); if (bnd == NULL) { log_fatal("No memory for " "prefix binding."); } bnd->name = dmalloc(strlen(val) + 1, MDL); if (bnd->name == NULL) { log_fatal("No memory for " "binding name."); } strcpy(bnd->name, val); newbinding = ISC_TRUE; } else { newbinding = ISC_FALSE; } if (!binding_value_allocate(&nv, MDL)) { log_fatal("no memory for binding " "value."); } token = next_token(NULL, NULL, cfile); if (token != EQUAL) { parse_warn(cfile, "expecting '=' in " "set statement."); goto binding_err; } if (!parse_binding_value(cfile, nv)) { binding_err: binding_value_dereference(&nv, MDL); binding_scope_dereference(&scope, MDL); return; } if (newbinding) { binding_value_reference(&bnd->value, nv, MDL); bnd->next = scope->bindings; scope->bindings = bnd; } else { binding_value_dereference(&bnd->value, MDL); binding_value_reference(&bnd->value, nv, MDL); } binding_value_dereference(&nv, MDL); parse_semi(cfile); break; default: parse_warn(cfile, "corrupt lease file; " "expecting ia_pd contents, " "got '%s'", val); skip_to_semi(cfile); continue; } } if (state == FTS_LAST+1) { parse_warn(cfile, "corrupt lease file; " "missing state in iaprefix"); return; } if (end_time == -1) { parse_warn(cfile, "corrupt lease file; " "missing end time in iaprefix"); return; } iapref = NULL; if (iasubopt_allocate(&iapref, MDL) != ISC_R_SUCCESS) { log_fatal("Out of memory."); } memcpy(&iapref->addr, iaddr.iabuf, sizeof(iapref->addr)); iapref->plen = plen; iapref->state = state; iapref->prefer = prefer; iapref->valid = valid; if (iapref->state == FTS_RELEASED) iapref->hard_lifetime_end_time = end_time; if (scope != NULL) { binding_scope_reference(&iapref->scope, scope, MDL); binding_scope_dereference(&scope, MDL); } /* find the pool this address is in */ pool = NULL; if (find_ipv6_pool(&pool, D6O_IA_PD, &iapref->addr) != ISC_R_SUCCESS) { inet_ntop(AF_INET6, &iapref->addr, addr_buf, sizeof(addr_buf)); parse_warn(cfile, "no pool found for address %s", addr_buf); return; } /* remove old information */ if (cleanup_lease6(ia_pd_active, pool, iapref, ia) != ISC_R_SUCCESS) { inet_ntop(AF_INET6, &iapref->addr, addr_buf, sizeof(addr_buf)); parse_warn(cfile, "duplicate pd lease for address %s", addr_buf); } /* * if we like the lease we add it to our various structues * otherwise we leave it and it will get cleaned when we * do the iasubopt_dereference. */ if ((state == FTS_ACTIVE) || (state == FTS_ABANDONED)) { ia_add_iasubopt(ia, iapref, MDL); ia_reference(&iapref->ia, ia, MDL); add_lease6(pool, iapref, end_time); } ipv6_pool_dereference(&pool, MDL); iasubopt_dereference(&iapref, MDL); } /* * If we have an existing record for this IA_PD, remove it. */ old_ia = NULL; if (ia_hash_lookup(&old_ia, ia_pd_active, (unsigned char *)ia->iaid_duid.data, ia->iaid_duid.len, MDL)) { ia_hash_delete(ia_pd_active, (unsigned char *)ia->iaid_duid.data, ia->iaid_duid.len, MDL); ia_dereference(&old_ia, MDL); } /* * If we have prefixes, add this, otherwise don't bother. */ if (ia->num_iasubopt > 0) { ia_hash_add(ia_pd_active, (unsigned char *)ia->iaid_duid.data, ia->iaid_duid.len, ia, MDL); } ia_dereference(&ia, MDL); #endif /* defined(DHCPv6) */ } #ifdef DHCPv6 /* * When we parse a server-duid statement in a lease file, we are * looking at the saved server DUID from a previous run. In this case * we expect it to be followed by the binary representation of the * DUID stored in a string: * * server-duid "\000\001\000\001\015\221\034JRT\000\0224Y"; */ void parse_server_duid(struct parse *cfile) { enum dhcp_token token; const char *val; unsigned int len; struct data_string duid; token = next_token(&val, &len, cfile); if (token != STRING) { parse_warn(cfile, "corrupt lease file; expecting a DUID"); skip_to_semi(cfile); return; } memset(&duid, 0, sizeof(duid)); duid.len = len; if (!buffer_allocate(&duid.buffer, duid.len, MDL)) { log_fatal("Out of memory storing DUID"); } duid.data = (unsigned char *)duid.buffer->data; memcpy(duid.buffer->data, val, len); set_server_duid(&duid); data_string_forget(&duid, MDL); token = next_token(&val, &len, cfile); if (token != SEMI) { parse_warn(cfile, "corrupt lease file; expecting a semicolon"); skip_to_semi(cfile); return; } } /* * When we parse a server-duid statement in a config file, we will * have the type of the server DUID to generate, and possibly the * actual value defined. * * server-duid llt; * server-duid llt ethernet|ieee802|fddi 213982198 00:16:6F:49:7D:9B; * server-duid ll; * server-duid ll ethernet|ieee802|fddi 00:16:6F:49:7D:9B; * server-duid en 2495 "enterprise-specific-identifier-1234"; */ void parse_server_duid_conf(struct parse *cfile) { enum dhcp_token token; const char *val; unsigned int len; u_int32_t enterprise_number; int ll_type; struct data_string ll_addr; u_int32_t llt_time; struct data_string duid; int duid_type_num; /* * Consume the SERVER_DUID token. */ token = next_token(NULL, NULL, cfile); /* * Obtain the DUID type. */ token = next_token(&val, NULL, cfile); /* * Enterprise is the easiest - enterprise number and raw data * are required. */ if (token == EN) { /* * Get enterprise number and identifier. */ token = next_token(&val, NULL, cfile); if (token != NUMBER) { parse_warn(cfile, "enterprise number expected"); skip_to_semi(cfile); return; } enterprise_number = atoi(val); token = next_token(&val, &len, cfile); if (token != STRING) { parse_warn(cfile, "identifier expected"); skip_to_semi(cfile); return; } /* * Save the DUID. */ memset(&duid, 0, sizeof(duid)); duid.len = 2 + 4 + len; if (!buffer_allocate(&duid.buffer, duid.len, MDL)) { log_fatal("Out of memory storing DUID"); } duid.data = (unsigned char *)duid.buffer->data; putUShort(duid.buffer->data, DUID_EN); putULong(duid.buffer->data + 2, enterprise_number); memcpy(duid.buffer->data + 6, val, len); set_server_duid(&duid); data_string_forget(&duid, MDL); } /* * Next easiest is the link-layer DUID. It consists only of * the LL directive, or optionally the specific value to use. * * If we have LL only, then we set the type. If we have the * value, then we set the actual DUID. */ else if (token == LL) { if (peek_token(NULL, NULL, cfile) == SEMI) { set_server_duid_type(DUID_LL); } else { /* * Get our hardware type and address. */ token = next_token(NULL, NULL, cfile); switch (token) { case ETHERNET: ll_type = HTYPE_ETHER; break; case TOKEN_RING: ll_type = HTYPE_IEEE802; break; case TOKEN_FDDI: ll_type = HTYPE_FDDI; break; default: parse_warn(cfile, "hardware type expected"); skip_to_semi(cfile); return; } memset(&ll_addr, 0, sizeof(ll_addr)); if (!parse_cshl(&ll_addr, cfile)) { return; } /* * Save the DUID. */ memset(&duid, 0, sizeof(duid)); duid.len = 2 + 2 + ll_addr.len; if (!buffer_allocate(&duid.buffer, duid.len, MDL)) { log_fatal("Out of memory storing DUID"); } duid.data = (unsigned char *)duid.buffer->data; putUShort(duid.buffer->data, DUID_LL); putULong(duid.buffer->data + 2, ll_type); memcpy(duid.buffer->data + 4, ll_addr.data, ll_addr.len); set_server_duid(&duid); data_string_forget(&duid, MDL); data_string_forget(&ll_addr, MDL); } } /* * Finally the link-layer DUID plus time. It consists only of * the LLT directive, or optionally the specific value to use. * * If we have LLT only, then we set the type. If we have the * value, then we set the actual DUID. */ else if (token == LLT) { if (peek_token(NULL, NULL, cfile) == SEMI) { set_server_duid_type(DUID_LLT); } else { /* * Get our hardware type, timestamp, and address. */ token = next_token(NULL, NULL, cfile); switch (token) { case ETHERNET: ll_type = HTYPE_ETHER; break; case TOKEN_RING: ll_type = HTYPE_IEEE802; break; case TOKEN_FDDI: ll_type = HTYPE_FDDI; break; default: parse_warn(cfile, "hardware type expected"); skip_to_semi(cfile); return; } token = next_token(&val, NULL, cfile); if (token != NUMBER) { parse_warn(cfile, "timestamp expected"); skip_to_semi(cfile); return; } llt_time = atoi(val); memset(&ll_addr, 0, sizeof(ll_addr)); if (!parse_cshl(&ll_addr, cfile)) { return; } /* * Save the DUID. */ memset(&duid, 0, sizeof(duid)); duid.len = 2 + 2 + 4 + ll_addr.len; if (!buffer_allocate(&duid.buffer, duid.len, MDL)) { log_fatal("Out of memory storing DUID"); } duid.data = (unsigned char *)duid.buffer->data; putUShort(duid.buffer->data, DUID_LLT); putULong(duid.buffer->data + 2, ll_type); putULong(duid.buffer->data + 4, llt_time); memcpy(duid.buffer->data + 8, ll_addr.data, ll_addr.len); set_server_duid(&duid); data_string_forget(&duid, MDL); data_string_forget(&ll_addr, MDL); } } /* * If users want they can use a number for DUID types. * This is useful for supporting future, not-yet-defined * DUID types. * * In this case, they have to put in the complete value. * * This also works for existing DUID types of course. */ else if (token == NUMBER) { duid_type_num = atoi(val); token = next_token(&val, &len, cfile); if (token != STRING) { parse_warn(cfile, "identifier expected"); skip_to_semi(cfile); return; } /* * Save the DUID. */ memset(&duid, 0, sizeof(duid)); duid.len = 2 + len; if (!buffer_allocate(&duid.buffer, duid.len, MDL)) { log_fatal("Out of memory storing DUID"); } duid.data = (unsigned char *)duid.buffer->data; putUShort(duid.buffer->data, duid_type_num); memcpy(duid.buffer->data + 2, val, len); set_server_duid(&duid); data_string_forget(&duid, MDL); } /* * Anything else is an error. */ else { parse_warn(cfile, "DUID type of LLT, EN, or LL expected"); skip_to_semi(cfile); return; } /* * Finally consume our trailing semicolon. */ token = next_token(NULL, NULL, cfile); if (token != SEMI) { parse_warn(cfile, "semicolon expected"); skip_to_semi(cfile); } } #endif /* DHCPv6 */ dhcp-4.2.4/server/db.c000644 000765 000024 00000071036 11754542635 014451 0ustar00sarstaff000000 000000 /* db.c Persistent database management routines for DHCPD... */ /* * Copyright (c) 2004-2010,2012 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1995-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ * * This software has been written for Internet Systems Consortium * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. * To learn more about Internet Systems Consortium, see * ``https://www.isc.org/''. To learn more about Vixie Enterprises, * see ``http://www.vix.com''. To learn more about Nominum, Inc., see * ``http://www.nominum.com''. */ #include "dhcpd.h" #include #include #define LEASE_REWRITE_PERIOD 3600 static isc_result_t write_binding_scope(FILE *db_file, struct binding *bnd, char *prepend); FILE *db_file; static int counting = 0; static int count = 0; TIME write_time; int lease_file_is_corrupt = 0; /* Write a single binding scope value in parsable format. */ static isc_result_t write_binding_scope(FILE *db_file, struct binding *bnd, char *prepend) { char *s; if ((db_file == NULL) || (bnd == NULL) || (prepend == NULL)) return DHCP_R_INVALIDARG; if (bnd->value->type == binding_data) { if (bnd->value->value.data.data != NULL) { s = quotify_buf(bnd->value->value.data.data, bnd->value->value.data.len, MDL); if (s != NULL) { errno = 0; fprintf(db_file, "%sset %s = \"%s\";", prepend, bnd->name, s); if (errno) return ISC_R_FAILURE; dfree(s, MDL); } else { return ISC_R_FAILURE; } } } else if (bnd->value->type == binding_numeric) { errno = 0; fprintf(db_file, "%sset %s = %%%ld;", prepend, bnd->name, bnd->value->value.intval); if (errno) return ISC_R_FAILURE; } else if (bnd->value->type == binding_boolean) { errno = 0; fprintf(db_file, "%sset %s = %s;", prepend, bnd->name, bnd->value->value.intval ? "true" : "false"); if (errno) return ISC_R_FAILURE; } else if (bnd->value->type == binding_dns) { log_error("%s: persistent dns values not supported.", bnd->name); } else if (bnd->value->type == binding_function) { log_error("%s: persistent functions not supported.", bnd->name); } else { log_fatal("%s: unknown binding type %d", bnd->name, bnd->value->type); } return ISC_R_SUCCESS; } /* Write the specified lease to the current lease database file. */ int write_lease (lease) struct lease *lease; { int errors = 0; struct binding *b; char *s; const char *tval; /* If the lease file is corrupt, don't try to write any more leases until we've written a good lease file. */ if (lease_file_is_corrupt) if (!new_lease_file ()) return 0; if (counting) ++count; errno = 0; fprintf (db_file, "lease %s {", piaddr (lease -> ip_addr)); if (errno) { ++errors; } if (lease->starts && ((tval = print_time(lease->starts)) == NULL || fprintf(db_file, "\n starts %s", tval) < 0)) ++errors; if (lease->ends && ((tval = print_time(lease->ends)) == NULL || fprintf(db_file, "\n ends %s", tval) < 0)) ++errors; if (lease->tstp && ((tval = print_time(lease->tstp)) == NULL || fprintf(db_file, "\n tstp %s", tval) < 0)) ++errors; if (lease->tsfp && ((tval = print_time(lease->tsfp)) == NULL || fprintf(db_file, "\n tsfp %s", tval) < 0)) ++errors; if (lease->atsfp && ((tval = print_time(lease->atsfp)) == NULL || fprintf(db_file, "\n atsfp %s", tval) < 0)) ++errors; if (lease->cltt && ((tval = print_time(lease->cltt)) == NULL || fprintf(db_file, "\n cltt %s", tval) < 0)) ++errors; if (fprintf (db_file, "\n binding state %s;", ((lease -> binding_state > 0 && lease -> binding_state <= FTS_LAST) ? binding_state_names [lease -> binding_state - 1] : "abandoned")) < 0) ++errors; if (lease -> binding_state != lease -> next_binding_state) if (fprintf (db_file, "\n next binding state %s;", ((lease -> next_binding_state > 0 && lease -> next_binding_state <= FTS_LAST) ? (binding_state_names [lease -> next_binding_state - 1]) : "abandoned")) < 0) ++errors; /* * In this case, if the rewind state is not present in the lease file, * the reader will use the current binding state as the most * conservative (safest) state. So if the in-memory rewind state is * for some reason invalid, the best thing to do is not to write a * state and let the reader take on a safe state. */ if ((lease->binding_state != lease->rewind_binding_state) && (lease->rewind_binding_state > 0) && (lease->rewind_binding_state <= FTS_LAST) && (fprintf(db_file, "\n rewind binding state %s;", binding_state_names[lease->rewind_binding_state-1])) < 0) ++errors; if (lease->flags & RESERVED_LEASE) if (fprintf(db_file, "\n reserved;") < 0) ++errors; if (lease->flags & BOOTP_LEASE) if (fprintf(db_file, "\n dynamic-bootp;") < 0) ++errors; /* If this lease is billed to a class and is still valid, write it out. */ if (lease -> billing_class && lease -> ends > cur_time) { if (!write_billing_class (lease -> billing_class)) { log_error ("unable to write class %s", lease -> billing_class -> name); ++errors; } } if (lease -> hardware_addr.hlen) { errno = 0; fprintf (db_file, "\n hardware %s %s;", hardware_types [lease -> hardware_addr.hbuf [0]], print_hw_addr (lease -> hardware_addr.hbuf [0], lease -> hardware_addr.hlen - 1, &lease -> hardware_addr.hbuf [1])); if (errno) ++errors; } if (lease -> uid_len) { s = quotify_buf (lease -> uid, lease -> uid_len, MDL); if (s) { errno = 0; fprintf (db_file, "\n uid \"%s\";", s); if (errno) ++errors; dfree (s, MDL); } else ++errors; } if (lease->scope != NULL) { for (b = lease->scope->bindings; b; b = b->next) { if (!b->value) continue; if (write_binding_scope(db_file, b, "\n ") != ISC_R_SUCCESS) ++errors; } } if (lease -> agent_options) { struct option_cache *oc; struct data_string ds; pair p; memset (&ds, 0, sizeof ds); for (p = lease -> agent_options -> first; p; p = p -> cdr) { oc = (struct option_cache *)p -> car; if (oc -> data.len) { errno = 0; fprintf (db_file, "\n option agent.%s %s;", oc -> option -> name, pretty_print_option (oc -> option, oc -> data.data, oc -> data.len, 1, 1)); if (errno) ++errors; } } } if (lease -> client_hostname && db_printable((unsigned char *)lease->client_hostname)) { s = quotify_string (lease -> client_hostname, MDL); if (s) { errno = 0; fprintf (db_file, "\n client-hostname \"%s\";", s); if (errno) ++errors; dfree (s, MDL); } else ++errors; } if (lease -> on_expiry) { errno = 0; fprintf (db_file, "\n on expiry%s {", lease -> on_expiry == lease -> on_release ? " or release" : ""); write_statements (db_file, lease -> on_expiry, 4); /* XXX */ fprintf (db_file, "\n }"); if (errno) ++errors; } if (lease -> on_release && lease -> on_release != lease -> on_expiry) { errno = 0; fprintf (db_file, "\n on release {"); write_statements (db_file, lease -> on_release, 4); /* XXX */ fprintf (db_file, "\n }"); if (errno) ++errors; } errno = 0; fputs ("\n}\n", db_file); if (errno) ++errors; if (errors) { log_info ("write_lease: unable to write lease %s", piaddr (lease -> ip_addr)); lease_file_is_corrupt = 1; } return !errors; } int write_host (host) struct host_decl *host; { int errors = 0; int i; struct data_string ip_addrs; /* If the lease file is corrupt, don't try to write any more leases until we've written a good lease file. */ if (lease_file_is_corrupt) if (!new_lease_file ()) return 0; if (!db_printable((unsigned char *)host->name)) return 0; if (counting) ++count; errno = 0; fprintf (db_file, "host %s {", host -> name); if (errno) ++errors; if (host -> flags & HOST_DECL_DYNAMIC) { errno = 0; fprintf (db_file, "\n dynamic;"); if (errno) ++errors; } if (host -> flags & HOST_DECL_DELETED) { errno = 0; fprintf (db_file, "\n deleted;"); if (errno) ++errors; } else { if (host -> interface.hlen) { errno = 0; fprintf (db_file, "\n hardware %s %s;", hardware_types [host -> interface.hbuf [0]], print_hw_addr (host -> interface.hbuf [0], host -> interface.hlen - 1, &host -> interface.hbuf [1])); if (errno) ++errors; } if (host -> client_identifier.len) { int i; errno = 0; if (db_printable_len (host -> client_identifier.data, host -> client_identifier.len)) { fprintf (db_file, "\n uid \"%.*s\";", (int)host -> client_identifier.len, host -> client_identifier.data); if (errno) ++errors; } else { fprintf (db_file, "\n uid %2.2x", host -> client_identifier.data [0]); if (errno) ++errors; for (i = 1; i < host -> client_identifier.len; i++) { errno = 0; fprintf (db_file, ":%2.2x", host -> client_identifier.data [i]); if (errno) ++errors; } errno = 0; fputc (';', db_file); if (errno) ++errors; } } memset (&ip_addrs, 0, sizeof ip_addrs); if (host -> fixed_addr && evaluate_option_cache (&ip_addrs, (struct packet *)0, (struct lease *)0, (struct client_state *)0, (struct option_state *)0, (struct option_state *)0, &global_scope, host -> fixed_addr, MDL)) { errno = 0; fprintf (db_file, "\n fixed-address "); if (errno) ++errors; for (i = 0; i < ip_addrs.len - 3; i += 4) { errno = 0; fprintf (db_file, "%u.%u.%u.%u%s", ip_addrs.data [i] & 0xff, ip_addrs.data [i + 1] & 0xff, ip_addrs.data [i + 2] & 0xff, ip_addrs.data [i + 3] & 0xff, i + 7 < ip_addrs.len ? "," : ""); if (errno) ++errors; } errno = 0; fputc (';', db_file); if (errno) ++errors; } if (host -> named_group) { errno = 0; fprintf (db_file, "\n group \"%s\";", host -> named_group -> name); if (errno) ++errors; } if (host -> group && (!host -> named_group || host -> group != host -> named_group -> group) && host -> group != root_group) { errno = 0; write_statements (db_file, host -> group -> statements, 8); if (errno) ++errors; } } errno = 0; fputs ("\n}\n", db_file); if (errno) ++errors; if (errors) { log_info ("write_host: unable to write host %s", host -> name); lease_file_is_corrupt = 1; } return !errors; } int write_group (group) struct group_object *group; { int errors = 0; /* If the lease file is corrupt, don't try to write any more leases until we've written a good lease file. */ if (lease_file_is_corrupt) if (!new_lease_file ()) return 0; if (!db_printable((unsigned char *)group->name)) return 0; if (counting) ++count; errno = 0; fprintf (db_file, "group %s {", group -> name); if (errno) ++errors; if (group -> flags & GROUP_OBJECT_DYNAMIC) { errno = 0; fprintf (db_file, "\n dynamic;"); if (errno) ++errors; } if (group -> flags & GROUP_OBJECT_STATIC) { errno = 0; fprintf (db_file, "\n static;"); if (errno) ++errors; } if (group -> flags & GROUP_OBJECT_DELETED) { errno = 0; fprintf (db_file, "\n deleted;"); if (errno) ++errors; } else { if (group -> group) { errno = 0; write_statements (db_file, group -> group -> statements, 8); if (errno) ++errors; } } errno = 0; fputs ("\n}\n", db_file); if (errno) ++errors; if (errors) { log_info ("write_group: unable to write group %s", group -> name); lease_file_is_corrupt = 1; } return !errors; } /* * Write an IA and the options it has. */ int write_ia(const struct ia_xx *ia) { struct iasubopt *iasubopt; struct binding *bnd; int i; char addr_buf[sizeof("ffff:ffff:ffff:ffff:ffff:ffff.255.255.255.255")]; const char *binding_state; const char *tval; char *s; int fprintf_ret; /* * If the lease file is corrupt, don't try to write any more * leases until we've written a good lease file. */ if (lease_file_is_corrupt) { if (!new_lease_file()) { return 0; } } if (counting) { ++count; } s = quotify_buf(ia->iaid_duid.data, ia->iaid_duid.len, MDL); if (s == NULL) { goto error_exit; } switch (ia->ia_type) { case D6O_IA_NA: fprintf_ret = fprintf(db_file, "ia-na \"%s\" {\n", s); break; case D6O_IA_TA: fprintf_ret = fprintf(db_file, "ia-ta \"%s\" {\n", s); break; case D6O_IA_PD: fprintf_ret = fprintf(db_file, "ia-pd \"%s\" {\n", s); break; default: log_error("Unknown ia type %u for \"%s\" at %s:%d", (unsigned)ia->ia_type, s, MDL); fprintf_ret = -1; } dfree(s, MDL); if (fprintf_ret < 0) { goto error_exit; } if (ia->cltt != MIN_TIME) { tval = print_time(ia->cltt); if (tval == NULL) { goto error_exit; } if (fprintf(db_file, " cltt %s\n", tval) < 0) { goto error_exit; } } for (i=0; inum_iasubopt; i++) { iasubopt = ia->iasubopt[i]; inet_ntop(AF_INET6, &iasubopt->addr, addr_buf, sizeof(addr_buf)); if ((ia->ia_type != D6O_IA_PD) && (fprintf(db_file, " iaaddr %s {\n", addr_buf) < 0)) { goto error_exit; } if ((ia->ia_type == D6O_IA_PD) && (fprintf(db_file, " iaprefix %s/%d {\n", addr_buf, (int)iasubopt->plen) < 0)) { goto error_exit; } if ((iasubopt->state <= 0) || (iasubopt->state > FTS_LAST)) { log_fatal("Unknown iasubopt state %d at %s:%d", iasubopt->state, MDL); } binding_state = binding_state_names[iasubopt->state-1]; if (fprintf(db_file, " binding state %s;\n", binding_state) < 0) { goto error_exit; } if (fprintf(db_file, " preferred-life %u;\n", (unsigned)iasubopt->prefer) < 0) { goto error_exit; } if (fprintf(db_file, " max-life %u;\n", (unsigned)iasubopt->valid) < 0) { goto error_exit; } /* Note that from here on out, the \n is prepended to the * next write, rather than appended to the current write. */ if ((iasubopt->state == FTS_ACTIVE) || (iasubopt->state == FTS_ABANDONED) || (iasubopt->hard_lifetime_end_time != 0)) { tval = print_time(iasubopt->hard_lifetime_end_time); } else { tval = print_time(iasubopt->soft_lifetime_end_time); } if (tval == NULL) { goto error_exit; } if (fprintf(db_file, " ends %s", tval) < 0) { goto error_exit; } /* Write out any binding scopes: note that 'ends' above does * not have \n on the end! We want that. */ if (iasubopt->scope != NULL) bnd = iasubopt->scope->bindings; else bnd = NULL; for (; bnd != NULL ; bnd = bnd->next) { if (bnd->value == NULL) continue; /* We don't do a regular error_exit because the * lease db is not corrupt in this case. */ if (write_binding_scope(db_file, bnd, "\n ") != ISC_R_SUCCESS) goto error_exit; } if (fprintf(db_file, "\n }\n") < 0) goto error_exit; } if (fprintf(db_file, "}\n\n") < 0) goto error_exit; fflush(db_file); return 1; error_exit: log_info("write_ia: unable to write ia"); lease_file_is_corrupt = 1; return 0; } #ifdef DHCPv6 /* * Put a copy of the server DUID in the leases file. */ int write_server_duid(void) { struct data_string server_duid; char *s; int fprintf_ret; /* * Only write the DUID if it's been set. */ if (!server_duid_isset()) { return 1; } /* * If the lease file is corrupt, don't try to write any more * leases until we've written a good lease file. */ if (lease_file_is_corrupt) { if (!new_lease_file()) { return 0; } } /* * Get a copy of our server DUID and convert to a quoted string. */ memset(&server_duid, 0, sizeof(server_duid)); copy_server_duid(&server_duid, MDL); s = quotify_buf(server_duid.data, server_duid.len, MDL); data_string_forget(&server_duid, MDL); if (s == NULL) { goto error_exit; } /* * Write to the leases file. */ fprintf_ret = fprintf(db_file, "server-duid \"%s\";\n\n", s); dfree(s, MDL); if (fprintf_ret < 0) { goto error_exit; } /* * Check if we actually managed to write. */ fflush(db_file); return 1; error_exit: log_info("write_server_duid: unable to write server-duid"); lease_file_is_corrupt = 1; return 0; } #endif /* DHCPv6 */ #if defined (FAILOVER_PROTOCOL) int write_failover_state (dhcp_failover_state_t *state) { int errors = 0; const char *tval; if (lease_file_is_corrupt) if (!new_lease_file ()) return 0; errno = 0; fprintf (db_file, "\nfailover peer \"%s\" state {", state -> name); if (errno) ++errors; tval = print_time(state->me.stos); if (tval == NULL || fprintf(db_file, "\n my state %s at %s", (state->me.state == startup) ? dhcp_failover_state_name_print(state->saved_state) : dhcp_failover_state_name_print(state->me.state), tval) < 0) ++errors; tval = print_time(state->partner.stos); if (tval == NULL || fprintf(db_file, "\n partner state %s at %s", dhcp_failover_state_name_print(state->partner.state), tval) < 0) ++errors; if (state -> i_am == secondary) { errno = 0; fprintf (db_file, "\n mclt %ld;", (unsigned long)state -> mclt); if (errno) ++errors; } errno = 0; fprintf (db_file, "\n}\n"); if (errno) ++errors; if (errors) { log_info ("write_failover_state: unable to write state %s", state -> name); lease_file_is_corrupt = 1; return 0; } return 1; } #endif int db_printable (s) const unsigned char *s; { int i; for (i = 0; s [i]; i++) if (!isascii (s [i]) || !isprint (s [i]) || s [i] == '"' || s [i] == '\\') return 0; return 1; } int db_printable_len (s, len) const unsigned char *s; unsigned len; { int i; for (i = 0; i < len; i++) if (!isascii (s [i]) || !isprint (s [i]) || s [i] == '"' || s [i] == '\\') return 0; return 1; } static int print_hash_string(FILE *fp, struct class *class) { int i; for (i = 0 ; i < class->hash_string.len ; i++) if (!isascii(class->hash_string.data[i]) || !isprint(class->hash_string.data[i])) break; if (i == class->hash_string.len) { if (fprintf(fp, " \"%.*s\"", (int)class->hash_string.len, class->hash_string.data) <= 0) { log_error("Failure writing hash string: %m"); return 0; } } else { if (fprintf(fp, " %2.2x", class->hash_string.data[0]) <= 0) { log_error("Failure writing hash string: %m"); return 0; } for (i = 1 ; i < class->hash_string.len ; i++) { if (fprintf(fp, ":%2.2x", class->hash_string.data[i]) <= 0) { log_error("Failure writing hash string: %m"); return 0; } } } return 1; } isc_result_t write_named_billing_class(const void *key, unsigned len, void *object) { const unsigned char *name = key; struct class *class = object; if (class->flags & CLASS_DECL_DYNAMIC) { numclasseswritten++; if (class->superclass == 0) { if (fprintf(db_file, "class \"%s\" {\n", name) <= 0) return ISC_R_IOERROR; } else { if (fprintf(db_file, "subclass \"%s\"", class->superclass->name) <= 0) return ISC_R_IOERROR; if (!print_hash_string(db_file, class)) return ISC_R_IOERROR; if (fprintf(db_file, " {\n") <= 0) return ISC_R_IOERROR; } if ((class->flags & CLASS_DECL_DELETED) != 0) { if (fprintf(db_file, " deleted;\n") <= 0) return ISC_R_IOERROR; } else { if (fprintf(db_file, " dynamic;\n") <= 0) return ISC_R_IOERROR; } if (class->lease_limit > 0) { if (fprintf(db_file, " lease limit %d;\n", class->lease_limit) <= 0) return ISC_R_IOERROR; } if (class->expr != 0) { if (fprintf(db_file, " match if ") <= 0) return ISC_R_IOERROR; errno = 0; write_expression(db_file, class->expr, 5, 5, 0); if (errno) return ISC_R_IOERROR; if (fprintf(db_file, ";\n") <= 0) return ISC_R_IOERROR; } if (class->submatch != 0) { if (class->spawning) { if (fprintf(db_file, " spawn ") <= 0) return ISC_R_IOERROR; } else { if (fprintf(db_file, " match ") <= 0) return ISC_R_IOERROR; } errno = 0; write_expression(db_file, class->submatch, 5, 5, 0); if (errno) return ISC_R_IOERROR; if (fprintf(db_file, ";\n") <= 0) return ISC_R_IOERROR; } if (class->statements != 0) { errno = 0; write_statements(db_file, class->statements, 8); if (errno) return ISC_R_IOERROR; } /* XXXJAB this isn't right, but classes read in off the leases file don't get the root group assigned to them (due to clone_group() call). */ if (class->group != 0 && class->group->authoritative != 0) { errno = 0; write_statements(db_file, class->group->statements, 8); if (errno) return ISC_R_IOERROR; } if (fprintf(db_file, "}\n\n") <= 0) return ISC_R_IOERROR; } if (class->hash != NULL) { /* yep. recursive. god help us. */ /* XXX - cannot check error status of this... * foo_hash_foreach returns a count of operations completed. */ class_hash_foreach(class->hash, write_named_billing_class); } return ISC_R_SUCCESS; } void write_billing_classes () { struct collection *lp; struct class *cp; for (lp = collections; lp; lp = lp -> next) { for (cp = lp -> classes; cp; cp = cp -> nic) { if (cp -> spawning && cp -> hash) { class_hash_foreach (cp -> hash, write_named_billing_class); } } } } /* Write a spawned class to the database file. */ int write_billing_class (class) struct class *class; { int errors = 0; if (lease_file_is_corrupt) if (!new_lease_file ()) return 0; if (!class -> superclass) { errno = 0; fprintf (db_file, "\n billing class \"%s\";", class -> name); return !errno; } if (fprintf(db_file, "\n billing subclass \"%s\"", class -> superclass -> name) < 0) ++errors; if (!print_hash_string(db_file, class)) ++errors; if (fprintf(db_file, ";") < 0) ++errors; class -> dirty = !errors; if (errors) lease_file_is_corrupt = 1; return !errors; } /* Commit leases after a timeout. */ void commit_leases_timeout (void *foo) { commit_leases (); } /* Commit any leases that have been written out... */ int commit_leases () { /* Commit any outstanding writes to the lease database file. We need to do this even if we're rewriting the file below, just in case the rewrite fails. */ if (fflush (db_file) == EOF) { log_info ("commit_leases: unable to commit: %m"); return 0; } if (fsync (fileno (db_file)) < 0) { log_info ("commit_leases: unable to commit: %m"); return 0; } /* send out all deferred ACKs now */ flush_ackqueue(NULL); /* If we haven't rewritten the lease database in over an hour, rewrite it now. (The length of time should probably be configurable. */ if (count && cur_time - write_time > LEASE_REWRITE_PERIOD) { count = 0; write_time = cur_time; new_lease_file (); } return 1; } /* * rewrite the lease file about once an hour * This is meant as a quick patch for ticket 24887. It allows * us to rotate the v6 lease file without adding too many fsync() * calls. In the future wes should revisit this area and add * something similar to the delayed ack code for v4. */ int commit_leases_timed() { if ((count != 0) && (cur_time - write_time > LEASE_REWRITE_PERIOD)) { return (commit_leases()); } return (1); } void db_startup (testp) int testp; { isc_result_t status; #if defined (TRACING) if (!trace_playback ()) { #endif /* Read in the existing lease file... */ status = read_conf_file (path_dhcpd_db, (struct group *)0, 0, 1); if (status != ISC_R_SUCCESS) { /* XXX ignore status? */ ; } #if defined (TRACING) } #endif #if defined (TRACING) /* If we're playing back, there is no lease file, so we can't append it, so we create one immediately (maybe this isn't the best solution... */ if (trace_playback ()) { new_lease_file (); } #endif if (!testp) { db_file = fopen (path_dhcpd_db, "a"); if (!db_file) log_fatal ("Can't open %s for append.", path_dhcpd_db); expire_all_pools (); #if defined (TRACING) if (trace_playback ()) write_time = cur_time; else #endif time(&write_time); new_lease_file (); } #if defined(REPORT_HASH_PERFORMANCE) log_info("Host HW hash: %s", host_hash_report(host_hw_addr_hash)); log_info("Host UID hash: %s", host_hash_report(host_uid_hash)); log_info("Lease IP hash: %s", lease_ip_hash_report(lease_ip_addr_hash)); log_info("Lease UID hash: %s", lease_id_hash_report(lease_uid_hash)); log_info("Lease HW hash: %s", lease_id_hash_report(lease_hw_addr_hash)); #endif } int new_lease_file () { char newfname [512]; char backfname [512]; TIME t; int db_fd; int db_validity; FILE *new_db_file; /* Make a temporary lease file... */ time(&t); db_validity = lease_file_is_corrupt; /* %Audit% Truncated filename causes panic. %2004.06.17,Safe% * This should never happen since the path is a configuration * variable from build-time or command-line. But if it should, * either by malice or ignorance, we panic, since the potential * for havoc is high. */ if (snprintf (newfname, sizeof newfname, "%s.%d", path_dhcpd_db, (int)t) >= sizeof newfname) log_fatal("new_lease_file: lease file path too long"); db_fd = open (newfname, O_WRONLY | O_TRUNC | O_CREAT, 0664); if (db_fd < 0) { log_error ("Can't create new lease file: %m"); return 0; } if ((new_db_file = fdopen(db_fd, "w")) == NULL) { log_error("Can't fdopen new lease file: %m"); close(db_fd); goto fdfail; } /* Close previous database, if any. */ if (db_file) fclose(db_file); db_file = new_db_file; errno = 0; fprintf (db_file, "# The format of this file is documented in the %s", "dhcpd.leases(5) manual page.\n"); if (errno) goto fail; fprintf (db_file, "# This lease file was written by isc-dhcp-%s\n\n", PACKAGE_VERSION); if (errno) goto fail; /* At this point we have a new lease file that, so far, could not * be described as either corrupt nor valid. */ lease_file_is_corrupt = 0; /* Write out all the leases that we know of... */ counting = 0; if (!write_leases ()) goto fail; #if defined (TRACING) if (!trace_playback ()) { #endif /* %Audit% Truncated filename causes panic. %2004.06.17,Safe% * This should never happen since the path is a configuration * variable from build-time or command-line. But if it should, * either by malice or ignorance, we panic, since the potential * for havoc is too high. */ if (snprintf (backfname, sizeof backfname, "%s~", path_dhcpd_db) >= sizeof backfname) log_fatal("new_lease_file: backup lease file path too long"); /* Get the old database out of the way... */ if (unlink (backfname) < 0 && errno != ENOENT) { log_error ("Can't remove old lease database backup %s: %m", backfname); goto fail; } if (link(path_dhcpd_db, backfname) < 0) { if (errno == ENOENT) { log_error("%s is missing - no lease db to backup.", path_dhcpd_db); } else { log_error("Can't backup lease database %s to %s: %m", path_dhcpd_db, backfname); goto fail; } } #if defined (TRACING) } #endif /* Move in the new file... */ if (rename (newfname, path_dhcpd_db) < 0) { log_error ("Can't install new lease database %s to %s: %m", newfname, path_dhcpd_db); goto fail; } counting = 1; return 1; fail: lease_file_is_corrupt = db_validity; fdfail: unlink (newfname); return 0; } int group_writer (struct group_object *group) { if (!write_group (group)) return 0; if (!commit_leases ()) return 0; return 1; } dhcp-4.2.4/server/ddns.c000644 000765 000024 00000162653 11731731535 015014 0ustar00sarstaff000000 000000 /* ddns.c Dynamic DNS updates. */ /* * Copyright (c) 2009-2012 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 2004-2007 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 2000-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ * * This software has been donated to Internet Systems Consortium * by Damien Neil of Nominum, Inc. * * To learn more about Internet Systems Consortium, see * ``https://www.isc.org/''. To learn more about Nominum, Inc., see * ``http://www.nominum.com''. */ #include "dhcpd.h" #include "dst/md5.h" #include #ifdef NSUPDATE static void ddns_fwd_srv_connector(struct lease *lease, struct iasubopt *lease6, struct binding_scope **inscope, dhcp_ddns_cb_t *ddns_cb, isc_result_t eresult); /* DN: No way of checking that there is enough space in a data_string's buffer. Be certain to allocate enough! TL: This is why the expression evaluation code allocates a *new* data_string. :') */ static void data_string_append (struct data_string *ds1, struct data_string *ds2) { memcpy (ds1 -> buffer -> data + ds1 -> len, ds2 -> data, ds2 -> len); ds1 -> len += ds2 -> len; } /* Determine what, if any, forward and reverse updates need to be * performed, and carry them through. */ int ddns_updates(struct packet *packet, struct lease *lease, struct lease *old, struct iasubopt *lease6, struct iasubopt *old6, struct option_state *options) { unsigned long ddns_ttl = DEFAULT_DDNS_TTL; struct data_string ddns_hostname; struct data_string ddns_domainname; struct data_string old_ddns_fwd_name; struct data_string ddns_fwd_name; //struct data_string ddns_rev_name; struct data_string ddns_dhcid; struct binding_scope **scope = NULL; //struct iaddr addr; struct data_string d1; struct option_cache *oc; int s1, s2; int result = 0; int server_updates_a = 1; //int server_updates_ptr = 1; struct buffer *bp = (struct buffer *)0; int ignorep = 0, client_ignorep = 0; int rev_name_len; int i; dhcp_ddns_cb_t *ddns_cb; int do_remove = 0; if (ddns_update_style != 2) return 0; /* * sigh, I want to cancel any previous udpates before we do anything * else but this means we need to deal with the lease vs lease6 * question twice. * If there is a ddns request already outstanding cancel it. */ if (lease != NULL) { if ((old != NULL) && (old->ddns_cb != NULL)) { ddns_cancel(old->ddns_cb, MDL); old->ddns_cb = NULL; } } else if (lease6 != NULL) { if ((old6 != NULL) && (old6->ddns_cb != NULL)) { ddns_cancel(old6->ddns_cb, MDL); old6->ddns_cb = NULL; } } else { log_fatal("Impossible condition at %s:%d.", MDL); /* Silence compiler warnings. */ result = 0; return(0); } /* allocate our control block */ ddns_cb = ddns_cb_alloc(MDL); if (ddns_cb == NULL) { return(0); } /* * Assume that we shall update both the A and ptr records and, * as this is an update, set the active flag */ ddns_cb->flags = DDNS_UPDATE_ADDR | DDNS_UPDATE_PTR | DDNS_ACTIVE_LEASE; /* * For v4 we flag static leases so we don't try * and manipulate the lease later. For v6 we don't * get static leases and don't need to flag them. */ if (lease != NULL) { scope = &(lease->scope); ddns_cb->address = lease->ip_addr; if (lease->flags & STATIC_LEASE) ddns_cb->flags |= DDNS_STATIC_LEASE; } else if (lease6 != NULL) { scope = &(lease6->scope); memcpy(ddns_cb->address.iabuf, lease6->addr.s6_addr, 16); ddns_cb->address.len = 16; } memset (&d1, 0, sizeof(d1)); memset (&ddns_hostname, 0, sizeof (ddns_hostname)); memset (&ddns_domainname, 0, sizeof (ddns_domainname)); memset (&old_ddns_fwd_name, 0, sizeof (ddns_fwd_name)); memset (&ddns_fwd_name, 0, sizeof (ddns_fwd_name)); //memset (&ddns_rev_name, 0, sizeof (ddns_rev_name)); memset (&ddns_dhcid, 0, sizeof (ddns_dhcid)); /* If we are allowed to accept the client's update of its own A record, see if the client wants to update its own A record. */ if (!(oc = lookup_option(&server_universe, options, SV_CLIENT_UPDATES)) || evaluate_boolean_option_cache(&client_ignorep, packet, lease, NULL, packet->options, options, scope, oc, MDL)) { /* If there's no fqdn.no-client-update or if it's nonzero, don't try to use the client-supplied XXX */ if (!(oc = lookup_option (&fqdn_universe, packet -> options, FQDN_SERVER_UPDATE)) || evaluate_boolean_option_cache(&ignorep, packet, lease, NULL, packet->options, options, scope, oc, MDL)) goto noclient; /* Win98 and Win2k will happily claim to be willing to update an unqualified domain name. */ if (!(oc = lookup_option (&fqdn_universe, packet -> options, FQDN_DOMAINNAME))) goto noclient; if (!(oc = lookup_option (&fqdn_universe, packet -> options, FQDN_FQDN)) || !evaluate_option_cache(&ddns_fwd_name, packet, lease, NULL, packet->options, options, scope, oc, MDL)) goto noclient; ddns_cb->flags &= ~DDNS_UPDATE_ADDR; server_updates_a = 0; goto client_updates; } noclient: /* If do-forward-updates is disabled, this basically means don't do an update unless the client is participating, so if we get here and do-forward-updates is disabled, we can stop. */ if ((oc = lookup_option (&server_universe, options, SV_DO_FORWARD_UPDATES)) && !evaluate_boolean_option_cache(&ignorep, packet, lease, NULL, packet->options, options, scope, oc, MDL)) { goto out; } /* If it's a static lease, then don't do the DNS update unless we're specifically configured to do so. If the client asked to do its own update and we allowed that, we don't do this test. */ /* XXX: note that we cannot detect static DHCPv6 leases. */ if ((lease != NULL) && (lease->flags & STATIC_LEASE)) { if (!(oc = lookup_option(&server_universe, options, SV_UPDATE_STATIC_LEASES)) || !evaluate_boolean_option_cache(&ignorep, packet, lease, NULL, packet->options, options, scope, oc, MDL)) goto out; } /* * Compute the name for the A record. */ oc = lookup_option(&server_universe, options, SV_DDNS_HOST_NAME); if (oc) s1 = evaluate_option_cache(&ddns_hostname, packet, lease, NULL, packet->options, options, scope, oc, MDL); else s1 = 0; oc = lookup_option(&server_universe, options, SV_DDNS_DOMAIN_NAME); if (oc) s2 = evaluate_option_cache(&ddns_domainname, packet, lease, NULL, packet->options, options, scope, oc, MDL); else s2 = 0; if (s1 && s2) { if (ddns_hostname.len + ddns_domainname.len > 253) { log_error ("ddns_update: host.domain name too long"); goto out; } buffer_allocate (&ddns_fwd_name.buffer, ddns_hostname.len + ddns_domainname.len + 2, MDL); if (ddns_fwd_name.buffer) { ddns_fwd_name.data = ddns_fwd_name.buffer->data; data_string_append (&ddns_fwd_name, &ddns_hostname); ddns_fwd_name.buffer->data[ddns_fwd_name.len] = '.'; ddns_fwd_name.len++; data_string_append (&ddns_fwd_name, &ddns_domainname); ddns_fwd_name.buffer->data[ddns_fwd_name.len] ='\0'; ddns_fwd_name.terminated = 1; } } client_updates: /* See if there's a name already stored on the lease. */ if (find_bound_string(&old_ddns_fwd_name, *scope, "ddns-fwd-name")) { /* If there is, see if it's different. */ if (old_ddns_fwd_name.len != ddns_fwd_name.len || memcmp (old_ddns_fwd_name.data, ddns_fwd_name.data, old_ddns_fwd_name.len)) { /* * If the name is different, mark the old record * for deletion and continue getting the new info. */ do_remove = 1; goto in; } /* See if there's a DHCID on the lease, and if not * then potentially look for 'on events' for ad-hoc ddns. */ if (!find_bound_string(&ddns_dhcid, *scope, "ddns-txt") && (old != NULL)) { /* If there's no DHCID, the update was probably done with the old-style ad-hoc DDNS updates. So if the expiry and release events look like they're the same, run them. This should delete the old DDNS data. */ if (old -> on_expiry == old -> on_release) { execute_statements(NULL, NULL, lease, NULL, NULL, NULL, scope, old->on_expiry); if (old -> on_expiry) executable_statement_dereference (&old -> on_expiry, MDL); if (old -> on_release) executable_statement_dereference (&old -> on_release, MDL); /* Now, install the DDNS data the new way. */ goto in; } } else data_string_forget(&ddns_dhcid, MDL); /* See if the administrator wants to do updates even in cases where the update already appears to have been done. */ if (!(oc = lookup_option(&server_universe, options, SV_UPDATE_OPTIMIZATION)) || evaluate_boolean_option_cache(&ignorep, packet, lease, NULL, packet->options, options, scope, oc, MDL)) { result = 1; goto noerror; } /* If there's no "ddns-fwd-name" on the lease record, see if * there's a ddns-client-fqdn indicating a previous client * update (if it changes, we need to adjust the PTR). */ } else if (find_bound_string(&old_ddns_fwd_name, *scope, "ddns-client-fqdn")) { /* If the name is not different, no need to update the PTR record. */ if (old_ddns_fwd_name.len == ddns_fwd_name.len && !memcmp (old_ddns_fwd_name.data, ddns_fwd_name.data, old_ddns_fwd_name.len) && (!(oc = lookup_option(&server_universe, options, SV_UPDATE_OPTIMIZATION)) || evaluate_boolean_option_cache(&ignorep, packet, lease, NULL, packet->options, options, scope, oc, MDL))) { goto noerror; } } in: /* If we don't have a name that the client has been assigned, we can just skip all this. */ if ((!ddns_fwd_name.len) || (ddns_fwd_name.len > 255)) { if (ddns_fwd_name.len > 255) { log_error ("client provided fqdn: too long"); } /* If desired do the removals */ if (do_remove != 0) { (void) ddns_removals(lease, lease6, NULL, ISC_TRUE); } goto out; } /* * Compute the RR TTL. * * We have two ways of computing the TTL. * The old behavior was to allow for the customer to set up * the option or to default things. For v4 this was 1/2 * of the lease time, for v6 this was DEFAULT_DDNS_TTL. * The new behavior continues to allow the customer to set * up an option but the defaults are a little different. * We now use 1/2 of the (preferred) lease time for both * v4 and v6 and cap them at a maximum value. * If the customer chooses to use an experession that references * part of the lease the v6 value will be the default as there * isn't a lease available for v6. */ ddns_ttl = DEFAULT_DDNS_TTL; if (lease != NULL) { if (lease->ends <= cur_time) { ddns_ttl = 0; } else { ddns_ttl = (lease->ends - cur_time)/2; } } #ifndef USE_OLD_DDNS_TTL else if (lease6 != NULL) { ddns_ttl = lease6->prefer/2; } if (ddns_ttl > MAX_DEFAULT_DDNS_TTL) { ddns_ttl = MAX_DEFAULT_DDNS_TTL; } #endif if ((oc = lookup_option(&server_universe, options, SV_DDNS_TTL))) { if (evaluate_option_cache(&d1, packet, lease, NULL, packet->options, options, scope, oc, MDL)) { if (d1.len == sizeof (u_int32_t)) ddns_ttl = getULong (d1.data); data_string_forget (&d1, MDL); } } ddns_cb->ttl = ddns_ttl; /* * Compute the reverse IP name, starting with the domain name. */ oc = lookup_option(&server_universe, options, SV_DDNS_REV_DOMAIN_NAME); if (oc) s1 = evaluate_option_cache(&d1, packet, lease, NULL, packet->options, options, scope, oc, MDL); else s1 = 0; /* * Figure out the length of the part of the name that depends * on the address. */ if (ddns_cb->address.len == 4) { char buf[17]; /* XXX: WOW this is gross. */ rev_name_len = snprintf(buf, sizeof(buf), "%u.%u.%u.%u.", ddns_cb->address.iabuf[3] & 0xff, ddns_cb->address.iabuf[2] & 0xff, ddns_cb->address.iabuf[1] & 0xff, ddns_cb->address.iabuf[0] & 0xff) + 1; if (s1) { rev_name_len += d1.len; if (rev_name_len > 255) { log_error("ddns_update: Calculated rev domain " "name too long."); s1 = 0; data_string_forget(&d1, MDL); } } } else if (ddns_cb->address.len == 16) { /* * IPv6 reverse names are always the same length, with * 32 hex characters separated by dots. */ rev_name_len = sizeof("0.1.2.3.4.5.6.7." "8.9.a.b.c.d.e.f." "0.1.2.3.4.5.6.7." "8.9.a.b.c.d.e.f." "ip6.arpa."); /* Set s1 to make sure we gate into updates. */ s1 = 1; } else { log_fatal("invalid address length %d", ddns_cb->address.len); /* Silence compiler warnings. */ return 0; } /* See if we are configured NOT to do reverse ptr updates */ if ((oc = lookup_option(&server_universe, options, SV_DO_REVERSE_UPDATES)) && !evaluate_boolean_option_cache(&ignorep, packet, lease, NULL, packet->options, options, scope, oc, MDL)) { ddns_cb->flags &= ~DDNS_UPDATE_PTR; } if (s1) { buffer_allocate(&ddns_cb->rev_name.buffer, rev_name_len, MDL); if (ddns_cb->rev_name.buffer != NULL) { struct data_string *rname = &ddns_cb->rev_name; rname->data = rname->buffer->data; if (ddns_cb->address.len == 4) { rname->len = sprintf((char *)rname->buffer->data, "%u.%u.%u.%u.", ddns_cb->address.iabuf[3] & 0xff, ddns_cb->address.iabuf[2] & 0xff, ddns_cb->address.iabuf[1] & 0xff, ddns_cb->address.iabuf[0] & 0xff); /* * d1.data may be opaque, garbage bytes, from * user (mis)configuration. */ data_string_append(rname, &d1); rname->buffer->data[rname->len] = '\0'; } else if (ddns_cb->address.len == 16) { char *p = (char *)&rname->buffer->data; unsigned char *a = ddns_cb->address.iabuf + 15; for (i=0; i<16; i++) { sprintf(p, "%x.%x.", (*a & 0xF), ((*a >> 4) & 0xF)); p += 4; a -= 1; } strcat(p, "ip6.arpa."); rname->len = strlen((const char *)rname->data); } rname->terminated = 1; } if (d1.data != NULL) data_string_forget(&d1, MDL); } /* * If we are updating the A record, compute the DHCID value. */ if ((ddns_cb->flags & DDNS_UPDATE_ADDR) != 0) { if (lease6 != NULL) result = get_dhcid(&ddns_cb->dhcid, 2, lease6->ia->iaid_duid.data, lease6->ia->iaid_duid.len); else if ((lease != NULL) && (lease->uid != NULL) && (lease->uid_len != 0)) result = get_dhcid (&ddns_cb->dhcid, DHO_DHCP_CLIENT_IDENTIFIER, lease -> uid, lease -> uid_len); else if (lease != NULL) result = get_dhcid (&ddns_cb->dhcid, 0, lease -> hardware_addr.hbuf, lease -> hardware_addr.hlen); else log_fatal("Impossible condition at %s:%d.", MDL); if (!result) goto badfqdn; } /* * Perform updates. */ data_string_copy(&ddns_cb->fwd_name, &ddns_fwd_name, MDL); if (ddns_cb->flags && DDNS_UPDATE_ADDR) { oc = lookup_option(&server_universe, options, SV_DDNS_CONFLICT_DETECT); if (oc && !evaluate_boolean_option_cache(&ignorep, packet, lease, NULL, packet->options, options, scope, oc, MDL)) ddns_cb->flags |= DDNS_CONFLICT_OVERRIDE; } /* * Previously if we failed during the removal operations * we skipped the fqdn option processing. I'm not sure * if we want to continue with that if we fail before sending * the ddns messages. Currently we don't. */ if (do_remove) { /* * We should log a more specific error closer to the actual * error if we want one. ddns_removal failure not logged here. */ (void) ddns_removals(lease, lease6, ddns_cb, ISC_TRUE); } else { ddns_fwd_srv_connector(lease, lease6, scope, ddns_cb, ISC_R_SUCCESS); } ddns_cb = NULL; noerror: /* * If fqdn-reply option is disabled in dhcpd.conf, then don't * send the client an FQDN option at all, even if one was requested. * (WinXP clients allegedly misbehave if the option is present, * refusing to handle PTR updates themselves). */ if ((oc = lookup_option (&server_universe, options, SV_FQDN_REPLY)) && !evaluate_boolean_option_cache(&ignorep, packet, lease, NULL, packet->options, options, scope, oc, MDL)) { goto badfqdn; /* If we're ignoring client updates, then we tell a sort of 'white * lie'. We've already updated the name the server wants (per the * config written by the server admin). Now let the client do as * it pleases with the name they supplied (if any). * * We only form an FQDN option this way if the client supplied an * FQDN option that had FQDN_SERVER_UPDATE set false. */ } else if (client_ignorep && (oc = lookup_option(&fqdn_universe, packet->options, FQDN_SERVER_UPDATE)) && !evaluate_boolean_option_cache(&ignorep, packet, lease, NULL, packet->options, options, scope, oc, MDL)) { oc = lookup_option(&fqdn_universe, packet->options, FQDN_FQDN); if (oc && evaluate_option_cache(&d1, packet, lease, NULL, packet->options, options, scope, oc, MDL)) { if (d1.len == 0 || !buffer_allocate(&bp, d1.len + 5, MDL)) goto badfqdn; /* Server pretends it is not updating. */ bp->data[0] = 0; if (!save_option_buffer(&fqdn_universe, options, bp, &bp->data[0], 1, FQDN_SERVER_UPDATE, 0)) goto badfqdn; /* Client is encouraged to update. */ bp->data[1] = 0; if (!save_option_buffer(&fqdn_universe, options, bp, &bp->data[1], 1, FQDN_NO_CLIENT_UPDATE, 0)) goto badfqdn; /* Use the encoding of client's FQDN option. */ oc = lookup_option(&fqdn_universe, packet->options, FQDN_ENCODED); if (oc && evaluate_boolean_option_cache(&ignorep, packet, lease, NULL, packet->options, options, scope, oc, MDL)) bp->data[2] = 1; /* FQDN is encoded. */ else bp->data[2] = 0; /* FQDN is not encoded. */ if (!save_option_buffer(&fqdn_universe, options, bp, &bp->data[2], 1, FQDN_ENCODED, 0)) goto badfqdn; /* Current FQDN drafts indicate 255 is mandatory. */ bp->data[3] = 255; if (!save_option_buffer(&fqdn_universe, options, bp, &bp->data[3], 1, FQDN_RCODE1, 0)) goto badfqdn; bp->data[4] = 255; if (!save_option_buffer(&fqdn_universe, options, bp, &bp->data[4], 1, FQDN_RCODE2, 0)) goto badfqdn; /* Copy in the FQDN supplied by the client. Note well * that the format of this option in the cache is going * to be in text format. If the fqdn supplied by the * client is encoded, it is decoded into the option * cache when parsed out of the packet. It will be * re-encoded when the option is assembled to be * transmitted if the client elects that encoding. */ memcpy(&bp->data[5], d1.data, d1.len); if (!save_option_buffer(&fqdn_universe, options, bp, &bp->data[5], d1.len, FQDN_FQDN, 0)) goto badfqdn; data_string_forget(&d1, MDL); } /* Set up the outgoing FQDN option if there was an incoming * FQDN option. If there's a valid FQDN option, there MUST * be an FQDN_SERVER_UPDATES suboption, it's part of the fixed * length head of the option contents, so we test the latter * to detect the presence of the former. */ } else if ((oc = lookup_option(&fqdn_universe, packet->options, FQDN_ENCODED)) && buffer_allocate(&bp, ddns_fwd_name.len + 5, MDL)) { bp -> data [0] = server_updates_a; if (!save_option_buffer(&fqdn_universe, options, bp, &bp->data [0], 1, FQDN_SERVER_UPDATE, 0)) goto badfqdn; bp -> data [1] = server_updates_a; if (!save_option_buffer(&fqdn_universe, options, bp, &bp->data [1], 1, FQDN_NO_CLIENT_UPDATE, 0)) goto badfqdn; /* Do the same encoding the client did. */ if (evaluate_boolean_option_cache(&ignorep, packet, lease, NULL, packet->options, options, scope, oc, MDL)) bp -> data [2] = 1; else bp -> data [2] = 0; if (!save_option_buffer(&fqdn_universe, options, bp, &bp->data [2], 1, FQDN_ENCODED, 0)) goto badfqdn; bp -> data [3] = 255;//isc_rcode_to_ns (rcode1); if (!save_option_buffer(&fqdn_universe, options, bp, &bp->data [3], 1, FQDN_RCODE1, 0)) goto badfqdn; bp -> data [4] = 255;//isc_rcode_to_ns (rcode2); if (!save_option_buffer(&fqdn_universe, options, bp, &bp->data [4], 1, FQDN_RCODE2, 0)) goto badfqdn; if (ddns_fwd_name.len) { memcpy (&bp -> data [5], ddns_fwd_name.data, ddns_fwd_name.len); if (!save_option_buffer(&fqdn_universe, options, bp, &bp->data [5], ddns_fwd_name.len, FQDN_FQDN, 0)) goto badfqdn; } } badfqdn: out: /* * Final cleanup. */ if (ddns_cb != NULL) { ddns_cb_free(ddns_cb, MDL); } data_string_forget(&d1, MDL); data_string_forget(&ddns_hostname, MDL); data_string_forget(&ddns_domainname, MDL); data_string_forget(&old_ddns_fwd_name, MDL); data_string_forget(&ddns_fwd_name, MDL); //data_string_forget(&ddns_rev_name, MDL); //data_string_forget(&ddns_dhcid, MDL); if (bp) buffer_dereference(&bp, MDL); return result; } /*%< * Utility function to update text strings within a lease. * * The first issue is to find the proper scope. Sometimes we shall be * called with a pointer to the scope in other cases we need to find * the proper lease and then get the scope. Once we have the scope we update * the proper strings, as indicated by the state value in the control block. * Lastly, if we needed to find the scope we write it out, if we used a * scope that was passed as an argument we don't write it, assuming that * our caller (or his ...) will do the write. * *\li ddns_cb - the control block for the DDNS request * *\li inscope - a pointer to the scope to update. This may be NULL * in which case we use the control block to find the lease and * then the scope. * * Returns *\li ISC_R_SUCCESS * *\li ISC_R_FAILURE - The routine was unable to find an expected scope. * In some cases (static and inactive leases) we don't expect a scope * and return success. */ isc_result_t ddns_update_lease_text(dhcp_ddns_cb_t *ddns_cb, struct binding_scope **inscope) { struct binding_scope **scope = NULL; struct lease *lease = NULL; struct iasubopt *lease6 = NULL; struct ipv6_pool *pool = NULL; struct in6_addr addr; struct data_string lease_dhcid; /* * If the lease was static (for a fixed address) * we don't need to do any work. */ if (ddns_cb->flags & DDNS_STATIC_LEASE) return (ISC_R_SUCCESS); /* * If we are processing an expired or released v6 lease * or some types of v4 leases we don't actually have a * scope to update */ if ((ddns_cb->flags & DDNS_ACTIVE_LEASE) == 0) return (ISC_R_SUCCESS); if (inscope != NULL) { scope = inscope; } else if (ddns_cb->address.len == 4) { if (find_lease_by_ip_addr(&lease, ddns_cb->address, MDL) != 0){ scope = &(lease->scope); } } else if (ddns_cb->address.len == 16) { memcpy(&addr, &ddns_cb->address.iabuf, 16); if ((find_ipv6_pool(&pool, D6O_IA_TA, &addr) == ISC_R_SUCCESS) || (find_ipv6_pool(&pool, D6O_IA_NA, &addr) == ISC_R_SUCCESS)) { if (iasubopt_hash_lookup(&lease6, pool->leases, &addr, 16, MDL)) { scope = &(lease6->scope); } ipv6_pool_dereference(&pool, MDL); } } else { log_fatal("Impossible condition at %s:%d.", MDL); } if (scope == NULL) { /* If necessary get rid of the lease */ if (lease) { lease_dereference(&lease, MDL); } else if (lease6) { iasubopt_dereference(&lease6, MDL); } return(ISC_R_FAILURE); } /* We now have a scope and can proceed to update it */ switch(ddns_cb->state) { case DDNS_STATE_REM_PTR: unset(*scope, "ddns-rev-name"); if ((ddns_cb->flags & DDNS_CLIENT_DID_UPDATE) != 0) { unset(*scope, "ddns-client-fqdn"); } break; case DDNS_STATE_ADD_PTR: case DDNS_STATE_CLEANUP: bind_ds_value(scope, "ddns-rev-name", &ddns_cb->rev_name); if ((ddns_cb->flags & DDNS_UPDATE_ADDR) == 0) { bind_ds_value(scope, "ddns-client-fqdn", &ddns_cb->fwd_name); } break; case DDNS_STATE_ADD_FW_YXDHCID: case DDNS_STATE_ADD_FW_NXDOMAIN: bind_ds_value(scope, "ddns-fwd-name", &ddns_cb->fwd_name); /* convert from dns version to lease version of dhcid */ memset(&lease_dhcid, 0, sizeof(lease_dhcid)); dhcid_tolease(&ddns_cb->dhcid, &lease_dhcid); bind_ds_value(scope, "ddns-txt", &lease_dhcid); data_string_forget(&lease_dhcid, MDL); break; case DDNS_STATE_REM_FW_NXRR: case DDNS_STATE_REM_FW_YXDHCID: unset(*scope, "ddns-fwd-name"); unset(*scope, "ddns-txt"); break; } /* If necessary write it out and get rid of the lease */ if (lease) { write_lease(lease); lease_dereference(&lease, MDL); } else if (lease6) { write_ia(lease6->ia); iasubopt_dereference(&lease6, MDL); } return(ISC_R_SUCCESS); } /* * This function should be called when update_lease_ptr function fails. * It does inform user about the condition, provides some hints how to * resolve this and dies gracefully. This can happend in at least three * cases (all are configuration mistakes): * a) IPv4: user have duplicate fixed-address entries (the same * address is defined twice). We may have found wrong lease. * b) IPv6: user have overlapping pools (we tried to find * a lease in a wrong pool) * c) IPv6: user have duplicate fixed-address6 entires (the same * address is defined twice). We may have found wrong lease. * * Comment: while it would be possible to recover from both cases * by forcibly searching for leases in *all* following pools, that would * only hide the real problem - a misconfiguration. Proper solution * is to log the problem, die and let the user fix his config file. */ void update_lease_failed(struct lease *lease, struct iasubopt *lease6, dhcp_ddns_cb_t *ddns_cb, dhcp_ddns_cb_t *ddns_cb_set, const char * file, int line) { char lease_address[MAX_ADDRESS_STRING_LEN + 64]; char reason[128]; /* likely reason */ sprintf(reason, "unknown"); sprintf(lease_address, "unknown"); /* * let's pretend that everything is ok, so we can continue for * information gathering purposes */ if (ddns_cb != NULL) { strncpy(lease_address, piaddr(ddns_cb->address), MAX_ADDRESS_STRING_LEN); if (ddns_cb->address.len == 4) { sprintf(reason, "duplicate IPv4 fixed-address entry"); } else if (ddns_cb->address.len == 16) { sprintf(reason, "duplicate IPv6 fixed-address6 entry " "or overlapping pools"); } else { /* * Should not happen. We have non-IPv4, non-IPv6 * address. Something is very wrong here. */ sprintf(reason, "corrupted ddns_cb structure (address " "length is %d)", ddns_cb->address.len); } } log_error("Failed to properly update internal lease structure with " "DDNS"); log_error("control block structures. Tried to update lease for" "%s address, ddns_cb=%p.", lease_address, ddns_cb); log_error("%s", ""); log_error("This condition can occur, if DHCP server configuration is " "inconsistent."); log_error("In particular, please do check that your configuration:"); log_error("a) does not have overlapping pools (especially containing"); log_error(" %s address).", lease_address); log_error("b) there are no duplicate fixed-address or fixed-address6"); log_error("entries for the %s address.", lease_address); log_error("%s", ""); log_error("Possible reason for this failure: %s", reason); log_fatal("%s(%d): Failed to update lease database with DDNS info for " "address %s. Lease database inconsistent. Unable to recover." " Terminating.", file, line, lease_address); } /* * utility function to update found lease. It does extra checks * that we are indeed updating the right lease. It may happen * that user have duplicate fixed-address entries, so we attempt * to update wrong lease. See also safe_lease6_update. */ void safe_lease_update(struct lease *lease, dhcp_ddns_cb_t *oldcb, dhcp_ddns_cb_t *newcb, const char *file, int line) { if (lease == NULL) { /* should never get here */ log_fatal("Impossible condition at %s:%d (called from %s:%d).", MDL, file, line); } if ( (lease->ddns_cb == NULL) && (newcb == NULL) ) { /* * Trying to clean up pointer that is already null. We * are most likely trying to update wrong lease here. */ /* * Previously this error message popped out during * DNS update for fixed leases. As we no longer * try to update the lease for a fixed (static) lease * this should not be a problem. */ log_error("%s(%d): Invalid lease update. Tried to " "clear already NULL DDNS control block " "pointer for lease %s.", file, line, piaddr(lease->ip_addr) ); #if defined (DNS_UPDATES_MEMORY_CHECKS) update_lease_failed(lease, NULL, oldcb, newcb, file, line); #endif /* * May not reach this: update_lease_failed calls * log_fatal. */ return; } if ( (lease->ddns_cb != NULL) && (lease->ddns_cb != oldcb) ) { /* * There is existing cb structure, but it differs from * what we expected to see there. Most likely we are * trying to update wrong lease. */ log_error("%s(%d): Failed to update internal lease " "structure with DDNS control block. Existing" " ddns_cb structure does not match " "expectations.IPv4=%s, old ddns_cb=%p, tried" "to update to new ddns_cb=%p", file, line, piaddr(lease->ip_addr), oldcb, newcb); #if defined (DNS_UPDATES_MEMORY_CHECKS) update_lease_failed(lease, NULL, oldcb, newcb, file, line); #endif /* * May not reach this: update_lease_failed calls * log_fatal. */ return; } /* additional IPv4 specific checks may be added here */ /* update the lease */ lease->ddns_cb = newcb; } void safe_lease6_update(struct iasubopt *lease6, dhcp_ddns_cb_t *oldcb, dhcp_ddns_cb_t *newcb, const char *file, int line) { char addrbuf[MAX_ADDRESS_STRING_LEN]; if (lease6 == NULL) { /* should never get here */ log_fatal("Impossible condition at %s:%d (called from %s:%d).", MDL, file, line); } if ( (lease6->ddns_cb == NULL) && (newcb == NULL) ) { inet_ntop(AF_INET6, &lease6->addr, addrbuf, MAX_ADDRESS_STRING_LEN); /* * Trying to clean up pointer that is already null. We * are most likely trying to update wrong lease here. */ log_error("%s(%d): Failed to update internal lease " "structure. Tried to clear already NULL " "DDNS control block pointer for lease %s.", file, line, addrbuf); #if defined (DNS_UPDATES_MEMORY_CHECKS) update_lease_failed(NULL, lease6, oldcb, newcb, file, line); #endif /* * May not reach this: update_lease_failed calls * log_fatal. */ return; } if ( (lease6->ddns_cb != NULL) && (lease6->ddns_cb != oldcb) ) { /* * there is existing cb structure, but it differs from * what we expected to see there. Most likely we are * trying to update wrong lease. */ inet_ntop(AF_INET6, &lease6->addr, addrbuf, MAX_ADDRESS_STRING_LEN); log_error("%s(%d): Failed to update internal lease " "structure with DDNS control block. Existing" " ddns_cb structure does not match " "expectations.IPv6=%s, old ddns_cb=%p, tried" "to update to new ddns_cb=%p", file, line, addrbuf, oldcb, newcb); #if defined (DNS_UPDATES_MEMORY_CHECKS) update_lease_failed(NULL, lease6, oldcb, newcb, file, line); #endif /* * May not reach this: update_lease_failed calls * log_fatal. */ return; } /* additional IPv6 specific checks may be added here */ /* update the lease */ lease6->ddns_cb = newcb; } /* * Utility function to update the pointer to the DDNS control block * in a lease. * SUCCESS - able to update the pointer * FAILURE - lease didn't exist or sanity checks failed * lease and lease6 may be empty in which case we attempt to find * the lease from the ddns_cb information. * ddns_cb is the control block to use if a lookup is necessary * ddns_cb_set is the pointer to insert into the lease and may be NULL * The last two arguments may look odd as they will be the same much of the * time, but I need an argument to tell me if I'm setting or clearing in * addition to the address information from the cb to look up the lease. * using the same value twice allows me more flexibility. */ isc_result_t ddns_update_lease_ptr(struct lease *lease, struct iasubopt *lease6, dhcp_ddns_cb_t *ddns_cb, dhcp_ddns_cb_t *ddns_cb_set, const char * file, int line) { char ddns_address[MAX_ADDRESS_STRING_LEN]; sprintf(ddns_address, "unknown"); if (ddns_cb) { strncpy(ddns_address, piaddr(ddns_cb->address), MAX_ADDRESS_STRING_LEN); } #if defined (DEBUG_DNS_UPDATES) log_info("%s(%d): Updating lease_ptr for ddns_cp=%p (addr=%s)", file, line, ddns_cb, ddns_address ); #endif /* * If the lease was static (for a fixed address) * we don't need to do any work. */ if (ddns_cb->flags & DDNS_STATIC_LEASE) { #if defined (DEBUG_DNS_UPDATES) log_info("lease is static, returning"); #endif return (ISC_R_SUCCESS); } /* * If we are processing an expired or released v6 lease * we don't actually have a lease to update */ if ((ddns_cb->address.len == 16) && ((ddns_cb->flags & DDNS_ACTIVE_LEASE) == 0)) { return (ISC_R_SUCCESS); } if (lease != NULL) { safe_lease_update(lease, ddns_cb, ddns_cb_set, file, line); } else if (lease6 != NULL) { safe_lease6_update(lease6, ddns_cb, ddns_cb_set, file, line); } else if (ddns_cb->address.len == 4) { struct lease *find_lease = NULL; if (find_lease_by_ip_addr(&find_lease, ddns_cb->address, MDL) != 0) { #if defined (DEBUG_DNS_UPDATES) log_info("%s(%d): find_lease_by_ip_addr(%s) successful:" "lease=%p", file, line, ddns_address, find_lease); #endif safe_lease_update(find_lease, ddns_cb, ddns_cb_set, file, line); lease_dereference(&find_lease, MDL); } else { log_error("%s(%d): ddns_update_lease_ptr failed. " "Lease for %s not found.", file, line, piaddr(ddns_cb->address)); #if defined (DNS_UPDATES_MEMORY_CHECKS) update_lease_failed(NULL, NULL, ddns_cb, ddns_cb_set, file, line); #endif /* * may not reach this. update_lease_failed * calls log_fatal. */ return(ISC_R_FAILURE); } } else if (ddns_cb->address.len == 16) { struct iasubopt *find_lease6 = NULL; struct ipv6_pool *pool = NULL; struct in6_addr addr; char addrbuf[MAX_ADDRESS_STRING_LEN]; memcpy(&addr, &ddns_cb->address.iabuf, 16); if ((find_ipv6_pool(&pool, D6O_IA_TA, &addr) != ISC_R_SUCCESS) && (find_ipv6_pool(&pool, D6O_IA_NA, &addr) != ISC_R_SUCCESS)) { inet_ntop(AF_INET6, &addr, addrbuf, MAX_ADDRESS_STRING_LEN); log_error("%s(%d): Pool for lease %s not found.", file, line, addrbuf); #if defined (DNS_UPDATES_MEMORY_CHECKS) update_lease_failed(NULL, NULL, ddns_cb, ddns_cb_set, file, line); #endif /* * never reached. update_lease_failed * calls log_fatal. */ return(ISC_R_FAILURE); } if (iasubopt_hash_lookup(&find_lease6, pool->leases, &addr, 16, MDL)) { find_lease6->ddns_cb = ddns_cb_set; iasubopt_dereference(&find_lease6, MDL); } else { inet_ntop(AF_INET6, &addr, addrbuf, MAX_ADDRESS_STRING_LEN); log_error("%s(%d): Lease %s not found within pool.", file, line, addrbuf); #if defined (DNS_UPDATES_MEMORY_CHECKS) update_lease_failed(NULL, NULL, ddns_cb, ddns_cb_set, file, line); #endif /* * never reached. update_lease_failed * calls log_fatal. */ return(ISC_R_FAILURE); } ipv6_pool_dereference(&pool, MDL); } else { /* shouldn't get here */ log_fatal("Impossible condition at %s:%d, called from %s:%d.", MDL, file, line); } return(ISC_R_SUCCESS); } void ddns_ptr_add(dhcp_ddns_cb_t *ddns_cb, isc_result_t eresult) { if (eresult == ISC_R_SUCCESS) { log_info("Added reverse map from %.*s to %.*s", (int)ddns_cb->rev_name.len, (const char *)ddns_cb->rev_name.data, (int)ddns_cb->fwd_name.len, (const char *)ddns_cb->fwd_name.data); ddns_update_lease_text(ddns_cb, NULL); } else { log_error("Unable to add reverse map from %.*s to %.*s: %s", (int)ddns_cb->rev_name.len, (const char *)ddns_cb->rev_name.data, (int)ddns_cb->fwd_name.len, (const char *)ddns_cb->fwd_name.data, isc_result_totext (eresult)); } ddns_update_lease_ptr(NULL, NULL, ddns_cb, NULL, MDL); ddns_cb_free(ddns_cb, MDL); /* * A single DDNS operation may require several calls depending on * the current state as the prerequisites for the first message * may not succeed requiring a second operation and potentially * a ptr operation after that. The commit_leases operation is * invoked at the end of this set of operations in order to require * a single write for all of the changes. We call commit_leases * here rather than immediately after the call to update the lease * text in order to save any previously written data. */ commit_leases(); return; } /* * action routine when trying to remove a pointer * this will be called after the ddns queries have completed * if we succeeded in removing the pointer we go to the next step (if any) * if not we cleanup and leave. */ void ddns_ptr_remove(dhcp_ddns_cb_t *ddns_cb, isc_result_t eresult) { isc_result_t result = eresult; switch(eresult) { case ISC_R_SUCCESS: log_info("Removed reverse map on %.*s", (int)ddns_cb->rev_name.len, (const char *)ddns_cb->rev_name.data); /* fall through */ case DNS_R_NXRRSET: case DNS_R_NXDOMAIN: /* No entry is the same as success. * Remove the information from the lease and * continue with any next step */ ddns_update_lease_text(ddns_cb, NULL); /* trigger any add operation */ result = ISC_R_SUCCESS; #if defined (DEBUG_DNS_UPDATES) log_info("DDNS: removed map or no reverse map to remove %.*s", (int)ddns_cb->rev_name.len, (const char *)ddns_cb->rev_name.data); #endif break; default: log_error("Can't remove reverse map on %.*s: %s", (int)ddns_cb->rev_name.len, (const char *)ddns_cb->rev_name.data, isc_result_totext (eresult)); break; } ddns_update_lease_ptr(NULL, NULL, ddns_cb, NULL, MDL); ddns_fwd_srv_connector(NULL, NULL, NULL, ddns_cb->next_op, result); ddns_cb_free(ddns_cb, MDL); return; } /* * If the first query succeeds, the updater can conclude that it * has added a new name whose only RRs are the A and DHCID RR records. * The A RR update is now complete (and a client updater is finished, * while a server might proceed to perform a PTR RR update). * -- "Interaction between DHCP and DNS" * * If the second query succeeds, the updater can conclude that the current * client was the last client associated with the domain name, and that * the name now contains the updated A RR. The A RR update is now * complete (and a client updater is finished, while a server would * then proceed to perform a PTR RR update). * -- "Interaction between DHCP and DNS" * * If the second query fails with NXRRSET, the updater must conclude * that the client's desired name is in use by another host. At this * juncture, the updater can decide (based on some administrative * configuration outside of the scope of this document) whether to let * the existing owner of the name keep that name, and to (possibly) * perform some name disambiguation operation on behalf of the current * client, or to replace the RRs on the name with RRs that represent * the current client. If the configured policy allows replacement of * existing records, the updater submits a query that deletes the * existing A RR and the existing DHCID RR, adding A and DHCID RRs that * represent the IP address and client-identity of the new client. * -- "Interaction between DHCP and DNS" */ void ddns_fwd_srv_add2(dhcp_ddns_cb_t *ddns_cb, isc_result_t eresult) { isc_result_t result; const char *logstr = NULL; char ddns_address[MAX_ADDRESS_STRING_LEN]; /* Construct a printable form of the address for logging */ strcpy(ddns_address, piaddr(ddns_cb->address)); switch(eresult) { case ISC_R_SUCCESS: log_info("Added new forward map from %.*s to %s", (int)ddns_cb->fwd_name.len, (const char *)ddns_cb->fwd_name.data, ddns_address); ddns_update_lease_text(ddns_cb, NULL); if ((ddns_cb->flags & DDNS_UPDATE_PTR) != 0) { /* if we have zone information get rid of it */ if (ddns_cb->zone != NULL) { ddns_cb_forget_zone(ddns_cb); } ddns_cb->state = DDNS_STATE_ADD_PTR; ddns_cb->cur_func = ddns_ptr_add; result = ddns_modify_ptr(ddns_cb, MDL); if (result == ISC_R_SUCCESS) { return; } } break; case DNS_R_YXRRSET: case DNS_R_YXDOMAIN: logstr = "DHCID mismatch, belongs to another client."; break; case DNS_R_NXRRSET: case DNS_R_NXDOMAIN: logstr = "Has an address record but no DHCID, not mine."; break; default: logstr = isc_result_totext(eresult); break; } if (logstr != NULL) { log_error("Forward map from %.*s to %s FAILED: %s", (int)ddns_cb->fwd_name.len, (const char *)ddns_cb->fwd_name.data, ddns_address, logstr); } ddns_update_lease_ptr(NULL, NULL, ddns_cb, NULL, MDL); ddns_cb_free(ddns_cb, MDL); /* * A single DDNS operation may require several calls depending on * the current state as the prerequisites for the first message * may not succeed requiring a second operation and potentially * a ptr operation after that. The commit_leases operation is * invoked at the end of this set of operations in order to require * a single write for all of the changes. We call commit_leases * here rather than immediately after the call to update the lease * text in order to save any previously written data. */ commit_leases(); return; } void ddns_fwd_srv_add1(dhcp_ddns_cb_t *ddns_cb, isc_result_t eresult) { isc_result_t result; char ddns_address[MAX_ADDRESS_STRING_LEN]; /* Construct a printable form of the address for logging */ strcpy(ddns_address, piaddr(ddns_cb->address)); switch(eresult) { case ISC_R_SUCCESS: log_info ("Added new forward map from %.*s to %s", (int)ddns_cb->fwd_name.len, (const char *)ddns_cb->fwd_name.data, ddns_address); ddns_update_lease_text(ddns_cb, NULL); if ((ddns_cb->flags & DDNS_UPDATE_PTR) != 0) { /* if we have zone information get rid of it */ if (ddns_cb->zone != NULL) { ddns_cb_forget_zone(ddns_cb); } ddns_cb->state = DDNS_STATE_ADD_PTR; ddns_cb->cur_func = ddns_ptr_add; result = ddns_modify_ptr(ddns_cb, MDL); if (result == ISC_R_SUCCESS) { return; } } break; case DNS_R_YXDOMAIN: /* we can reuse the zone information */ ddns_cb->state = DDNS_STATE_ADD_FW_YXDHCID; ddns_cb->cur_func = ddns_fwd_srv_add2; result = ddns_modify_fwd(ddns_cb, MDL); if (result == ISC_R_SUCCESS) { return; } break; default: log_error ("Unable to add forward map from %.*s to %s: %s", (int)ddns_cb->fwd_name.len, (const char *)ddns_cb->fwd_name.data, ddns_address, isc_result_totext (eresult)); break; } ddns_update_lease_ptr(NULL, NULL, ddns_cb, NULL, MDL); ddns_cb_free(ddns_cb, MDL); /* * A single DDNS operation may require several calls depending on * the current state as the prerequisites for the first message * may not succeed requiring a second operation and potentially * a ptr operation after that. The commit_leases operation is * invoked at the end of this set of operations in order to require * a single write for all of the changes. We call commit_leases * here rather than immediately after the call to update the lease * text in order to save any previously written data. */ commit_leases(); return; } static void ddns_fwd_srv_connector(struct lease *lease, struct iasubopt *lease6, struct binding_scope **inscope, dhcp_ddns_cb_t *ddns_cb, isc_result_t eresult) { isc_result_t result = ISC_R_FAILURE; if (ddns_cb == NULL) { /* nothing to do */ return; } if (eresult == ISC_R_SUCCESS) { /* * If we have updates dispatch as appropriate, * if not do FQDN binding if desired. */ if (ddns_cb->flags & DDNS_UPDATE_ADDR) { ddns_cb->state = DDNS_STATE_ADD_FW_NXDOMAIN; ddns_cb->cur_func = ddns_fwd_srv_add1; result = ddns_modify_fwd(ddns_cb, MDL); } else if ((ddns_cb->flags & DDNS_UPDATE_PTR) && (ddns_cb->rev_name.len != 0)) { ddns_cb->state = DDNS_STATE_ADD_PTR; ddns_cb->cur_func = ddns_ptr_add; result = ddns_modify_ptr(ddns_cb, MDL); } else { ddns_update_lease_text(ddns_cb, inscope); } } if (result == ISC_R_SUCCESS) { ddns_update_lease_ptr(lease, lease6, ddns_cb, ddns_cb, MDL); } else { ddns_cb_free(ddns_cb, MDL); } return; } /* * If the first query fails, the updater MUST NOT delete the DNS name. It * may be that the host whose lease on the server has expired has moved * to another network and obtained a lease from a different server, * which has caused the client's A RR to be replaced. It may also be * that some other client has been configured with a name that matches * the name of the DHCP client, and the policy was that the last client * to specify the name would get the name. In this case, the DHCID RR * will no longer match the updater's notion of the client-identity of * the host pointed to by the DNS name. * -- "Interaction between DHCP and DNS" */ void ddns_fwd_srv_rem2(dhcp_ddns_cb_t *ddns_cb, isc_result_t eresult) { if (eresult == ISC_R_SUCCESS) { ddns_update_lease_text(ddns_cb, NULL); /* Do the next operation */ if ((ddns_cb->flags & DDNS_UPDATE_PTR) != 0) { /* if we have zone information get rid of it */ if (ddns_cb->zone != NULL) { ddns_cb_forget_zone(ddns_cb); } ddns_cb->state = DDNS_STATE_REM_PTR; ddns_cb->cur_func = ddns_ptr_remove; eresult = ddns_modify_ptr(ddns_cb, MDL); if (eresult == ISC_R_SUCCESS) { return; } } } ddns_update_lease_ptr(NULL, NULL, ddns_cb, NULL, MDL); ddns_fwd_srv_connector(NULL, NULL, NULL, ddns_cb->next_op, eresult); ddns_cb_free(ddns_cb, MDL); return; } /* * First action routine when trying to remove a fwd * this will be called after the ddns queries have completed * if we succeeded in removing the fwd we go to the next step (if any) * if not we cleanup and leave. */ void ddns_fwd_srv_rem1(dhcp_ddns_cb_t *ddns_cb, isc_result_t eresult) { isc_result_t result = eresult; char ddns_address[MAX_ADDRESS_STRING_LEN]; switch(eresult) { case ISC_R_SUCCESS: /* Construct a printable form of the address for logging */ strcpy(ddns_address, piaddr(ddns_cb->address)); log_info("Removed forward map from %.*s to %s", (int)ddns_cb->fwd_name.len, (const char*)ddns_cb->fwd_name.data, ddns_address); /* Do the second step of the FWD removal */ ddns_cb->state = DDNS_STATE_REM_FW_NXRR; ddns_cb->cur_func = ddns_fwd_srv_rem2; result = ddns_modify_fwd(ddns_cb, MDL); if (result == ISC_R_SUCCESS) { return; } break; case DNS_R_NXRRSET: case DNS_R_NXDOMAIN: ddns_update_lease_text(ddns_cb, NULL); #if defined (DEBUG_DNS_UPDATES) log_info("DDNS: no forward map to remove. %p", ddns_cb); #endif /* Do the next operation */ if ((ddns_cb->flags & DDNS_UPDATE_PTR) != 0) { /* if we have zone information get rid of it */ if (ddns_cb->zone != NULL) { ddns_cb_forget_zone(ddns_cb); } ddns_cb->state = DDNS_STATE_REM_PTR; ddns_cb->cur_func = ddns_ptr_remove; result = ddns_modify_ptr(ddns_cb, MDL); if (result == ISC_R_SUCCESS) { return; } } else { /* Trigger the add operation */ eresult = ISC_R_SUCCESS; } break; default: break; } ddns_update_lease_ptr(NULL, NULL, ddns_cb, NULL, MDL); ddns_fwd_srv_connector(NULL, NULL, NULL, ddns_cb->next_op, eresult); ddns_cb_free(ddns_cb, MDL); } /*%< * Remove relevant entries from DNS. * * \li lease - lease to start with if this is for v4 * * \li lease6 - lease to start with if this is for v6 * * \li add_ddns_cb - control block for additional DDNS work. This * is used when the code is going to add a DDNS entry after removing * the current entry. * * \li active - indication about the status of the lease. It is * ISC_TRUE if the lease is still active, and FALSE if the lease * is inactive. This is used to indicate if the lease is inactive or going * to inactive so we can avoid trying to update the lease with cb pointers * and text information if it isn't useful. * * Returns * \li #ISC_R_FAILURE - badness occurred and we weren't able to do what was wanted * \li #ISC_R_SUCCESS - we were able to do stuff but it's in progress * * in both cases any additional block has been passed on to it's handler */ isc_result_t ddns_removals(struct lease *lease, struct iasubopt *lease6, dhcp_ddns_cb_t *add_ddns_cb, isc_boolean_t active) { isc_result_t rcode, execute_add = ISC_R_FAILURE; struct binding_scope **scope = NULL; isc_result_t result = ISC_R_FAILURE; dhcp_ddns_cb_t *ddns_cb = NULL; struct data_string leaseid; /* * See if we need to cancel an outstanding request. Mostly this is * used to handle the case where this routine is called twice for * the same release or abandon event. * * When called from the dns code as part of an update request * (add_ddns_cb != NULL) any outstanding requests will have already * been cancelled. * * If the new request is just a removal and we have an outstanding * request we have several options: * * - we are doing an update or we are doing a removal and the active * flag has changed from TRUE to FALSE. In these cases we need to * cancel the old request and start the new one. * * - other wise we are doing a removal with the active flag unchanged. * In this case we can let the current removal continue and do not need * to start a new one. If the old request included an update to be * done after the removal we need to kill the update part of the * request. */ if (add_ddns_cb == NULL) { if ((lease != NULL) && (lease->ddns_cb != NULL)) { ddns_cb = lease->ddns_cb; /* * Is the old request an update or did the * the active flag change? */ if (((ddns_cb->state == DDNS_STATE_ADD_PTR) || (ddns_cb->state == DDNS_STATE_ADD_FW_NXDOMAIN) || (ddns_cb->state == DDNS_STATE_ADD_FW_YXDHCID)) || ((active == ISC_FALSE) && ((ddns_cb->flags & DDNS_ACTIVE_LEASE) != 0))) { /* Cancel the current request */ ddns_cancel(lease->ddns_cb, MDL); lease->ddns_cb = NULL; } else { /* Remvoval, check and remove updates */ if (ddns_cb->next_op != NULL) { ddns_cb_free(ddns_cb->next_op, MDL); ddns_cb->next_op = NULL; } #if defined (DEBUG_DNS_UPDATES) log_info("DDNS %s(%d): removal already in " "progress new ddns_cb=%p", MDL, ddns_cb); #endif return (ISC_R_SUCCESS); } } else if ((lease6 != NULL) && (lease6->ddns_cb != NULL)) { ddns_cb = lease6->ddns_cb; /* * Is the old request an update or did the * the active flag change? */ if (((ddns_cb->state == DDNS_STATE_ADD_PTR) || (ddns_cb->state == DDNS_STATE_ADD_FW_NXDOMAIN) || (ddns_cb->state == DDNS_STATE_ADD_FW_YXDHCID)) || ((active == ISC_FALSE) && ((ddns_cb->flags & DDNS_ACTIVE_LEASE) != 0))) { /* Cancel the current request */ ddns_cancel(lease6->ddns_cb, MDL); lease6->ddns_cb = NULL; } else { /* Remvoval, check and remove updates */ if (ddns_cb->next_op != NULL) { ddns_cb_free(ddns_cb->next_op, MDL); ddns_cb->next_op = NULL; } #if defined (DEBUG_DNS_UPDATES) log_info("DDNS %s(%d): removal already in " "progress new ddns_cb=%p", MDL, ddns_cb); #endif return (ISC_R_SUCCESS); } } ddns_cb = NULL; } /* allocate our control block */ ddns_cb = ddns_cb_alloc(MDL); if (ddns_cb == NULL) { goto cleanup; } /* * For v4 we flag static leases so we don't try * and manipulate the lease later. For v6 we don't * get static leases and don't need to flag them. */ if (lease != NULL) { scope = &(lease->scope); ddns_cb->address = lease->ip_addr; if (lease->flags & STATIC_LEASE) ddns_cb->flags |= DDNS_STATIC_LEASE; } else if (lease6 != NULL) { scope = &(lease6->scope); memcpy(&ddns_cb->address.iabuf, lease6->addr.s6_addr, 16); ddns_cb->address.len = 16; } else goto cleanup; /* * Set the flag bit if the lease is active, that is it isn't * expired or released. This is used to determine if we need * to update the scope information for both v4 and v6 and * the lease information for v6 when the response * from the DNS code is processed. */ if (active == ISC_TRUE) { ddns_cb->flags |= DDNS_ACTIVE_LEASE; } /* No scope implies that DDNS has not been performed for this lease. */ if (*scope == NULL) goto cleanup; if (ddns_update_style != 2) goto cleanup; /* Assume that we are removing both records */ ddns_cb->flags |= DDNS_UPDATE_ADDR | DDNS_UPDATE_PTR; /* and that we want to do the add call */ execute_add = ISC_R_SUCCESS; /* * Look up stored names. */ /* * Find the fwd name and copy it to the control block. If we don't * have it we can't delete the fwd record but we can still try to * remove the ptr record and cleanup the lease information if the * client did the fwd update. */ if (!find_bound_string(&ddns_cb->fwd_name, *scope, "ddns-fwd-name")) { /* don't try and delete the A, or do the add */ ddns_cb->flags &= ~DDNS_UPDATE_ADDR; execute_add = ISC_R_FAILURE; /* Check if client did update */ if (find_bound_string(&ddns_cb->fwd_name, *scope, "ddns-client-fqdn")) { ddns_cb->flags |= DDNS_CLIENT_DID_UPDATE; } } /* * Find the ptr name and copy it to the control block. If we don't * have it this isn't an interim or rfc3??? record so we can't delete * the A record using this mechanism but we can delete the ptr record. * In this case we will attempt to do any requested next step. */ memset(&leaseid, 0, sizeof(leaseid)); if (!find_bound_string (&leaseid, *scope, "ddns-txt")) { ddns_cb->flags &= ~DDNS_UPDATE_ADDR; } else { if (dhcid_fromlease(&ddns_cb->dhcid, &leaseid) != ISC_R_SUCCESS) { /* We couldn't convert the dhcid from the lease * version to the dns version. We can't delete * the A record but can continue to the ptr */ ddns_cb->flags &= ~DDNS_UPDATE_ADDR; } data_string_forget(&leaseid, MDL); } /* * Find the rev name and copy it to the control block. If we don't * have it we can't get rid of it but we can try to remove the fwd * pointer if desired. */ if (!find_bound_string(&ddns_cb->rev_name, *scope, "ddns-rev-name")) { ddns_cb->flags &= ~DDNS_UPDATE_PTR; } /* * If we have a second control block for doing an add * after the remove finished attach it to our control block. */ ddns_cb->next_op = add_ddns_cb; /* * Now that we've collected the information we can try to process it. * If necessary we call an appropriate routine to send a message and * provide it with an action routine to run on the control block given * the results of the message. We have three entry points from here, * one for removing the A record, the next for removing the PTR and * the third for doing any requested add. */ if ((ddns_cb->flags & DDNS_UPDATE_ADDR) != 0) { if (ddns_cb->fwd_name.len != 0) { ddns_cb->state = DDNS_STATE_REM_FW_YXDHCID; ddns_cb->cur_func = ddns_fwd_srv_rem1; rcode = ddns_modify_fwd(ddns_cb, MDL); if (rcode == ISC_R_SUCCESS) { ddns_update_lease_ptr(lease, lease6, ddns_cb, ddns_cb, MDL); return (ISC_R_SUCCESS); } /* * We weren't able to process the request tag the * add so we won't execute it. */ execute_add = ISC_R_FAILURE; goto cleanup; } else { /*remove info from scope */ unset(*scope, "ddns-fwd-name"); unset(*scope, "ddns-txt"); } } if ((ddns_cb->flags & DDNS_UPDATE_PTR) != 0) { ddns_cb->state = DDNS_STATE_REM_PTR; ddns_cb->cur_func = ddns_ptr_remove; /* * if execute add isn't success remove the control block so * it won't be processed when the remove completes. We * also arrange to clean it up and get rid of it. */ if (execute_add != ISC_R_SUCCESS) { ddns_cb->next_op = NULL; ddns_fwd_srv_connector(lease, lease6, scope, add_ddns_cb, execute_add); add_ddns_cb = NULL; } else { result = ISC_R_SUCCESS; } rcode = ddns_modify_ptr(ddns_cb, MDL); if (rcode == ISC_R_SUCCESS) { ddns_update_lease_ptr(lease, lease6, ddns_cb, ddns_cb, MDL); return (result); } /* We weren't able to process the request tag the * add so we won't execute it */ execute_add = ISC_R_FAILURE; goto cleanup; } cleanup: /* * We've gotten here because we didn't need to send a message or * we failed when trying to do so. We send the additional cb * off to handle sending and/or cleanup and cleanup anything * we allocated here. */ ddns_fwd_srv_connector(lease, lease6, scope, add_ddns_cb, execute_add); if (ddns_cb != NULL) ddns_cb_free(ddns_cb, MDL); return (result); } #endif /* NSUPDATE */ dhcp-4.2.4/server/dhcp.c000644 000765 000024 00000423660 11726364514 015003 0ustar00sarstaff000000 000000 /* dhcp.c DHCP Protocol engine. */ /* * Copyright (c) 2004-2012 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1995-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ * * This software has been written for Internet Systems Consortium * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. * To learn more about Internet Systems Consortium, see * ``https://www.isc.org/''. To learn more about Vixie Enterprises, * see ``http://www.vix.com''. To learn more about Nominum, Inc., see * ``http://www.nominum.com''. */ #include "dhcpd.h" #include #include #include static void commit_leases_ackout(void *foo); static void maybe_return_agent_options(struct packet *packet, struct option_state *options); int outstanding_pings; struct leasequeue *ackqueue_head, *ackqueue_tail; static struct leasequeue *free_ackqueue; static struct timeval max_fsync; int outstanding_acks; int max_outstanding_acks = DEFAULT_DELAYED_ACK; int max_ack_delay_secs = DEFAULT_ACK_DELAY_SECS; int max_ack_delay_usecs = DEFAULT_ACK_DELAY_USECS; int min_ack_delay_usecs = DEFAULT_MIN_ACK_DELAY_USECS; static char dhcp_message [256]; static int site_code_min; static int find_min_site_code(struct universe *); static isc_result_t lowest_site_code(const void *, unsigned, void *); static const char *dhcp_type_names [] = { "DHCPDISCOVER", "DHCPOFFER", "DHCPREQUEST", "DHCPDECLINE", "DHCPACK", "DHCPNAK", "DHCPRELEASE", "DHCPINFORM", "type 9", "DHCPLEASEQUERY", "DHCPLEASEUNASSIGNED", "DHCPLEASEUNKNOWN", "DHCPLEASEACTIVE" }; const int dhcp_type_name_max = ((sizeof dhcp_type_names) / sizeof (char *)); #if defined (TRACING) # define send_packet trace_packet_send #endif void dhcp (struct packet *packet) { int ms_nulltp = 0; struct option_cache *oc; struct lease *lease = NULL; const char *errmsg; struct data_string data; if (!locate_network(packet) && packet->packet_type != DHCPREQUEST && packet->packet_type != DHCPINFORM && packet->packet_type != DHCPLEASEQUERY) { const char *s; char typebuf[32]; errmsg = "unknown network segment"; bad_packet: if (packet->packet_type > 0 && packet->packet_type <= dhcp_type_name_max) { s = dhcp_type_names[packet->packet_type - 1]; } else { /* %Audit% Cannot exceed 28 bytes. %2004.06.17,Safe% */ sprintf(typebuf, "type %d", packet->packet_type); s = typebuf; } log_info("%s from %s via %s: %s", s, (packet->raw->htype ? print_hw_addr(packet->raw->htype, packet->raw->hlen, packet->raw->chaddr) : ""), packet->raw->giaddr.s_addr ? inet_ntoa(packet->raw->giaddr) : packet->interface->name, errmsg); goto out; } /* There is a problem with the relay agent information option, * which is that in order for a normal relay agent to append * this option, the relay agent has to have been involved in * getting the packet from the client to the server. Note * that this is the software entity known as the relay agent, * _not_ the hardware entity known as a router in which the * relay agent may be running, so the fact that a router has * forwarded a packet does not mean that the relay agent in * the router was involved. * * So when the client broadcasts (DHCPDISCOVER, or giaddr is set), * we can be sure that there are either agent options in the * packet, or there aren't supposed to be. When the giaddr is not * set, it's still possible that the client is on a directly * attached subnet, and agent options are being appended by an l2 * device that has no address, and so sets no giaddr. * * But in either case it's possible that the packets we receive * from the client in RENEW state may not include the agent options, * so if they are not in the packet we must "pretend" the last values * we observed were provided. */ if (packet->packet_type == DHCPREQUEST && packet->raw->ciaddr.s_addr && !packet->raw->giaddr.s_addr && (packet->options->universe_count <= agent_universe.index || packet->options->universes[agent_universe.index] == NULL)) { struct iaddr cip; cip.len = sizeof packet -> raw -> ciaddr; memcpy (cip.iabuf, &packet -> raw -> ciaddr, sizeof packet -> raw -> ciaddr); if (!find_lease_by_ip_addr (&lease, cip, MDL)) goto nolease; /* If there are no agent options on the lease, it's not interesting. */ if (!lease -> agent_options) goto nolease; /* The client should not be unicasting a renewal if its lease has expired, so make it go through the process of getting its agent options legally. */ if (lease -> ends < cur_time) goto nolease; if (lease -> uid_len) { oc = lookup_option (&dhcp_universe, packet -> options, DHO_DHCP_CLIENT_IDENTIFIER); if (!oc) goto nolease; memset (&data, 0, sizeof data); if (!evaluate_option_cache (&data, packet, (struct lease *)0, (struct client_state *)0, packet -> options, (struct option_state *)0, &global_scope, oc, MDL)) goto nolease; if (lease -> uid_len != data.len || memcmp (lease -> uid, data.data, data.len)) { data_string_forget (&data, MDL); goto nolease; } data_string_forget (&data, MDL); } else if ((lease -> hardware_addr.hbuf [0] != packet -> raw -> htype) || (lease -> hardware_addr.hlen - 1 != packet -> raw -> hlen) || memcmp (&lease -> hardware_addr.hbuf [1], packet -> raw -> chaddr, packet -> raw -> hlen)) goto nolease; /* Okay, so we found a lease that matches the client. */ option_chain_head_reference ((struct option_chain_head **) &(packet -> options -> universes [agent_universe.index]), lease -> agent_options, MDL); if (packet->options->universe_count <= agent_universe.index) packet->options->universe_count = agent_universe.index + 1; packet->agent_options_stashed = ISC_TRUE; } nolease: /* If a client null terminates options it sends, it probably * expects the server to reciprocate. */ if ((oc = lookup_option (&dhcp_universe, packet -> options, DHO_HOST_NAME))) { if (!oc -> expression) ms_nulltp = oc->flags & OPTION_HAD_NULLS; } /* Classify the client. */ classify_client (packet); switch (packet -> packet_type) { case DHCPDISCOVER: dhcpdiscover (packet, ms_nulltp); break; case DHCPREQUEST: dhcprequest (packet, ms_nulltp, lease); break; case DHCPRELEASE: dhcprelease (packet, ms_nulltp); break; case DHCPDECLINE: dhcpdecline (packet, ms_nulltp); break; case DHCPINFORM: dhcpinform (packet, ms_nulltp); break; case DHCPLEASEQUERY: dhcpleasequery(packet, ms_nulltp); break; case DHCPACK: case DHCPOFFER: case DHCPNAK: case DHCPLEASEUNASSIGNED: case DHCPLEASEUNKNOWN: case DHCPLEASEACTIVE: break; default: errmsg = "unknown packet type"; goto bad_packet; } out: if (lease) lease_dereference (&lease, MDL); } void dhcpdiscover (packet, ms_nulltp) struct packet *packet; int ms_nulltp; { struct lease *lease = (struct lease *)0; char msgbuf [1024]; /* XXX */ TIME when; const char *s; int peer_has_leases = 0; #if defined (FAILOVER_PROTOCOL) dhcp_failover_state_t *peer; #endif find_lease (&lease, packet, packet -> shared_network, 0, &peer_has_leases, (struct lease *)0, MDL); if (lease && lease -> client_hostname) { if ((strlen (lease -> client_hostname) <= 64) && db_printable((unsigned char *)lease->client_hostname)) s = lease -> client_hostname; else s = "Hostname Unsuitable for Printing"; } else s = (char *)0; /* %Audit% This is log output. %2004.06.17,Safe% * If we truncate we hope the user can get a hint from the log. */ snprintf (msgbuf, sizeof msgbuf, "DHCPDISCOVER from %s %s%s%svia %s", (packet -> raw -> htype ? print_hw_addr (packet -> raw -> htype, packet -> raw -> hlen, packet -> raw -> chaddr) : (lease ? print_hex_1(lease->uid_len, lease->uid, 60) : "")), s ? "(" : "", s ? s : "", s ? ") " : "", packet -> raw -> giaddr.s_addr ? inet_ntoa (packet -> raw -> giaddr) : packet -> interface -> name); /* Sourceless packets don't make sense here. */ if (!packet -> shared_network) { log_info ("Packet from unknown subnet: %s", inet_ntoa (packet -> raw -> giaddr)); goto out; } #if defined (FAILOVER_PROTOCOL) if (lease && lease -> pool && lease -> pool -> failover_peer) { peer = lease -> pool -> failover_peer; /* * If the lease is ours to (re)allocate, then allocate it. * * If the lease is active, it belongs to the client. This * is the right lease, if we are to offer one. We decide * whether or not to offer later on. * * If the lease was last active, and we've reached this * point, then it was last active with the same client. We * can safely re-activate the lease with this client. */ if (lease->binding_state == FTS_ACTIVE || lease->rewind_binding_state == FTS_ACTIVE || lease_mine_to_reallocate(lease)) { ; /* This space intentionally left blank. */ /* Otherwise, we can't let the client have this lease. */ } else { #if defined (DEBUG_FIND_LEASE) log_debug ("discarding %s - %s", piaddr (lease -> ip_addr), binding_state_print (lease -> binding_state)); #endif lease_dereference (&lease, MDL); } } #endif /* If we didn't find a lease, try to allocate one... */ if (!lease) { if (!allocate_lease (&lease, packet, packet -> shared_network -> pools, &peer_has_leases)) { if (peer_has_leases) log_error ("%s: peer holds all free leases", msgbuf); else log_error ("%s: network %s: no free leases", msgbuf, packet -> shared_network -> name); return; } } #if defined (FAILOVER_PROTOCOL) if (lease && lease -> pool && lease -> pool -> failover_peer) { peer = lease -> pool -> failover_peer; if (peer -> service_state == not_responding || peer -> service_state == service_startup) { log_info ("%s: not responding%s", msgbuf, peer -> nrr); goto out; } } else peer = (dhcp_failover_state_t *)0; /* Do load balancing if configured. */ if (peer && (peer -> service_state == cooperating) && !load_balance_mine (packet, peer)) { if (peer_has_leases) { log_debug ("%s: load balance to peer %s", msgbuf, peer -> name); goto out; } else { log_debug ("%s: cancel load balance to peer %s - %s", msgbuf, peer -> name, "no free leases"); } } #endif /* If it's an expired lease, get rid of any bindings. */ if (lease -> ends < cur_time && lease -> scope) binding_scope_dereference (&lease -> scope, MDL); /* Set the lease to really expire in 2 minutes, unless it has not yet expired, in which case leave its expiry time alone. */ when = cur_time + 120; if (when < lease -> ends) when = lease -> ends; ack_lease (packet, lease, DHCPOFFER, when, msgbuf, ms_nulltp, (struct host_decl *)0); out: if (lease) lease_dereference (&lease, MDL); } void dhcprequest (packet, ms_nulltp, ip_lease) struct packet *packet; int ms_nulltp; struct lease *ip_lease; { struct lease *lease; struct iaddr cip; struct iaddr sip; struct subnet *subnet; int ours = 0; struct option_cache *oc; struct data_string data; char msgbuf [1024]; /* XXX */ const char *s; char smbuf [19]; #if defined (FAILOVER_PROTOCOL) dhcp_failover_state_t *peer; #endif int have_requested_addr = 0; oc = lookup_option (&dhcp_universe, packet -> options, DHO_DHCP_REQUESTED_ADDRESS); memset (&data, 0, sizeof data); if (oc && evaluate_option_cache (&data, packet, (struct lease *)0, (struct client_state *)0, packet -> options, (struct option_state *)0, &global_scope, oc, MDL)) { cip.len = 4; memcpy (cip.iabuf, data.data, 4); data_string_forget (&data, MDL); have_requested_addr = 1; } else { oc = (struct option_cache *)0; cip.len = 4; memcpy (cip.iabuf, &packet -> raw -> ciaddr.s_addr, 4); } /* Find the lease that matches the address requested by the client. */ subnet = (struct subnet *)0; lease = (struct lease *)0; if (find_subnet (&subnet, cip, MDL)) find_lease (&lease, packet, subnet -> shared_network, &ours, 0, ip_lease, MDL); if (lease && lease -> client_hostname) { if ((strlen (lease -> client_hostname) <= 64) && db_printable((unsigned char *)lease->client_hostname)) s = lease -> client_hostname; else s = "Hostname Unsuitable for Printing"; } else s = (char *)0; oc = lookup_option (&dhcp_universe, packet -> options, DHO_DHCP_SERVER_IDENTIFIER); memset (&data, 0, sizeof data); if (oc && evaluate_option_cache (&data, packet, (struct lease *)0, (struct client_state *)0, packet -> options, (struct option_state *)0, &global_scope, oc, MDL)) { sip.len = 4; memcpy (sip.iabuf, data.data, 4); data_string_forget (&data, MDL); /* piaddr() should not return more than a 15 byte string. * safe. */ sprintf (smbuf, " (%s)", piaddr (sip)); } else smbuf [0] = 0; /* %Audit% This is log output. %2004.06.17,Safe% * If we truncate we hope the user can get a hint from the log. */ snprintf (msgbuf, sizeof msgbuf, "DHCPREQUEST for %s%s from %s %s%s%svia %s", piaddr (cip), smbuf, (packet -> raw -> htype ? print_hw_addr (packet -> raw -> htype, packet -> raw -> hlen, packet -> raw -> chaddr) : (lease ? print_hex_1(lease->uid_len, lease->uid, 60) : "")), s ? "(" : "", s ? s : "", s ? ") " : "", packet -> raw -> giaddr.s_addr ? inet_ntoa (packet -> raw -> giaddr) : packet -> interface -> name); #if defined (FAILOVER_PROTOCOL) if (lease && lease -> pool && lease -> pool -> failover_peer) { peer = lease -> pool -> failover_peer; if (peer -> service_state == not_responding || peer -> service_state == service_startup) { log_info ("%s: not responding%s", msgbuf, peer -> nrr); goto out; } /* "load balance to peer" - is not done at all for request. * * If it's RENEWING, we are the only server to hear it, so * we have to serve it. If it's REBINDING, it's out of * communication with the other server, so there's no point * in waiting to serve it. However, if the lease we're * offering is not a free lease, then we may be the only * server that can offer it, so we can't load balance if * the lease isn't in the free or backup state. If it is * in the free or backup state, then that state is what * mandates one server or the other should perform the * allocation, not the LBA...we know the peer cannot * allocate a request for an address in our free state. * * So our only compass is lease_mine_to_reallocate(). This * effects both load balancing, and a sanity-check that we * are not going to try to allocate a lease that isn't ours. */ if ((lease -> binding_state == FTS_FREE || lease -> binding_state == FTS_BACKUP) && !lease_mine_to_reallocate (lease)) { log_debug ("%s: lease owned by peer", msgbuf); goto out; } /* * If the lease is in a transitional state, we can't * renew it unless we can rewind it to a non-transitional * state (active, free, or backup). lease_mine_to_reallocate() * checks for free/backup, so we only need to check for active. */ if ((lease->binding_state == FTS_RELEASED || lease->binding_state == FTS_EXPIRED) && lease->rewind_binding_state != FTS_ACTIVE && !lease_mine_to_reallocate(lease)) { log_debug("%s: lease in transition state %s", msgbuf, (lease->binding_state == FTS_RELEASED) ? "released" : "expired"); goto out; } /* It's actually very unlikely that we'll ever get here, but if we do, tell the client to stop using the lease, because the administrator reset it. */ if (lease -> binding_state == FTS_RESET && !lease_mine_to_reallocate (lease)) { log_debug ("%s: lease reset by administrator", msgbuf); nak_lease (packet, &cip); goto out; } /* At this point it's possible that we will get a broadcast DHCPREQUEST for a lease that we didn't offer, because both we and the peer are in a position to offer it. In that case, we probably shouldn't answer. In order to not answer, we would have to compare the server identifier sent by the client with the list of possible server identifiers we can send, and if the client's identifier isn't on the list, drop the DHCPREQUEST. We aren't currently doing that for two reasons - first, it's not clear that all clients do the right thing with respect to sending the client identifier, which could mean that we might simply not respond to a client that is depending on us to respond. Secondly, we allow the user to specify the server identifier to send, and we don't enforce that the server identifier should be one of our IP addresses. This is probably not a big deal, but it's theoretically an issue. The reason we care about this is that if both servers send a DHCPACK to the DHCPREQUEST, they are then going to send dueling BNDUPD messages, which could cause trouble. I think it causes no harm, but it seems wrong. */ } else peer = (dhcp_failover_state_t *)0; #endif /* If a client on a given network REQUESTs a lease on an address on a different network, NAK it. If the Requested Address option was used, the protocol says that it must have been broadcast, so we can trust the source network information. If ciaddr was specified and Requested Address was not, then we really only know for sure what network a packet came from if it came through a BOOTP gateway - if it came through an IP router, we'll just have to assume that it's cool. If we don't think we know where the packet came from, it came through a gateway from an unknown network, so it's not from a RENEWING client. If we recognize the network it *thinks* it's on, we can NAK it even though we don't recognize the network it's *actually* on; otherwise we just have to ignore it. We don't currently try to take advantage of access to the raw packet, because it's not available on all platforms. So a packet that was unicast to us through a router from a RENEWING client is going to look exactly like a packet that was broadcast to us from an INIT-REBOOT client. Since we can't tell the difference between these two kinds of packets, if the packet appears to have come in off the local wire, we have to treat it as if it's a RENEWING client. This means that we can't NAK a RENEWING client on the local wire that has a bogus address. The good news is that we won't ACK it either, so it should revert to INIT state and send us a DHCPDISCOVER, which we *can* work with. Because we can't detect that a RENEWING client is on the wrong wire, it's going to sit there trying to renew until it gets to the REBIND state, when we *can* NAK it because the packet will get to us through a BOOTP gateway. We shouldn't actually see DHCPREQUEST packets from RENEWING clients on the wrong wire anyway, since their idea of their local router will be wrong. In any case, the protocol doesn't really allow us to NAK a DHCPREQUEST from a RENEWING client, so we can punt on this issue. */ if (!packet -> shared_network || (packet -> raw -> ciaddr.s_addr && packet -> raw -> giaddr.s_addr) || (have_requested_addr && !packet -> raw -> ciaddr.s_addr)) { /* If we don't know where it came from but we do know where it claims to have come from, it didn't come from there. */ if (!packet -> shared_network) { if (subnet && subnet -> group -> authoritative) { log_info ("%s: wrong network.", msgbuf); nak_lease (packet, &cip); goto out; } /* Otherwise, ignore it. */ log_info ("%s: ignored (%s).", msgbuf, (subnet ? "not authoritative" : "unknown subnet")); goto out; } /* If we do know where it came from and it asked for an address that is not on that shared network, nak it. */ if (subnet) subnet_dereference (&subnet, MDL); if (!find_grouped_subnet (&subnet, packet -> shared_network, cip, MDL)) { if (packet -> shared_network -> group -> authoritative) { log_info ("%s: wrong network.", msgbuf); nak_lease (packet, &cip); goto out; } log_info ("%s: ignored (not authoritative).", msgbuf); return; } } /* If the address the client asked for is ours, but it wasn't available for the client, NAK it. */ if (!lease && ours) { log_info ("%s: lease %s unavailable.", msgbuf, piaddr (cip)); nak_lease (packet, &cip); goto out; } /* Otherwise, send the lease to the client if we found one. */ if (lease) { ack_lease (packet, lease, DHCPACK, 0, msgbuf, ms_nulltp, (struct host_decl *)0); } else log_info ("%s: unknown lease %s.", msgbuf, piaddr (cip)); out: if (subnet) subnet_dereference (&subnet, MDL); if (lease) lease_dereference (&lease, MDL); return; } void dhcprelease (packet, ms_nulltp) struct packet *packet; int ms_nulltp; { struct lease *lease = (struct lease *)0, *next = (struct lease *)0; struct iaddr cip; struct option_cache *oc; struct data_string data; const char *s; char msgbuf [1024], cstr[16]; /* XXX */ /* DHCPRELEASE must not specify address in requested-address option, but old protocol specs weren't explicit about this, so let it go. */ if ((oc = lookup_option (&dhcp_universe, packet -> options, DHO_DHCP_REQUESTED_ADDRESS))) { log_info ("DHCPRELEASE from %s specified requested-address.", print_hw_addr (packet -> raw -> htype, packet -> raw -> hlen, packet -> raw -> chaddr)); } oc = lookup_option (&dhcp_universe, packet -> options, DHO_DHCP_CLIENT_IDENTIFIER); memset (&data, 0, sizeof data); if (oc && evaluate_option_cache (&data, packet, (struct lease *)0, (struct client_state *)0, packet -> options, (struct option_state *)0, &global_scope, oc, MDL)) { find_lease_by_uid (&lease, data.data, data.len, MDL); data_string_forget (&data, MDL); /* See if we can find a lease that matches the IP address the client is claiming. */ while (lease) { if (lease -> n_uid) lease_reference (&next, lease -> n_uid, MDL); if (!memcmp (&packet -> raw -> ciaddr, lease -> ip_addr.iabuf, 4)) { break; } lease_dereference (&lease, MDL); if (next) { lease_reference (&lease, next, MDL); lease_dereference (&next, MDL); } } if (next) lease_dereference (&next, MDL); } /* The client is supposed to pass a valid client-identifier, but the spec on this has changed historically, so try the IP address in ciaddr if the client-identifier fails. */ if (!lease) { cip.len = 4; memcpy (cip.iabuf, &packet -> raw -> ciaddr, 4); find_lease_by_ip_addr (&lease, cip, MDL); } /* If the hardware address doesn't match, don't do the release. */ if (lease && (lease -> hardware_addr.hlen != packet -> raw -> hlen + 1 || lease -> hardware_addr.hbuf [0] != packet -> raw -> htype || memcmp (&lease -> hardware_addr.hbuf [1], packet -> raw -> chaddr, packet -> raw -> hlen))) lease_dereference (&lease, MDL); if (lease && lease -> client_hostname) { if ((strlen (lease -> client_hostname) <= 64) && db_printable((unsigned char *)lease->client_hostname)) s = lease -> client_hostname; else s = "Hostname Unsuitable for Printing"; } else s = (char *)0; /* %Audit% Cannot exceed 16 bytes. %2004.06.17,Safe% * We copy this out to stack because we actually want to log two * inet_ntoa()'s in this message. */ strncpy(cstr, inet_ntoa (packet -> raw -> ciaddr), 15); cstr[15] = '\0'; /* %Audit% This is log output. %2004.06.17,Safe% * If we truncate we hope the user can get a hint from the log. */ snprintf (msgbuf, sizeof msgbuf, "DHCPRELEASE of %s from %s %s%s%svia %s (%sfound)", cstr, (packet -> raw -> htype ? print_hw_addr (packet -> raw -> htype, packet -> raw -> hlen, packet -> raw -> chaddr) : (lease ? print_hex_1(lease->uid_len, lease->uid, 60) : "")), s ? "(" : "", s ? s : "", s ? ") " : "", packet -> raw -> giaddr.s_addr ? inet_ntoa (packet -> raw -> giaddr) : packet -> interface -> name, lease ? "" : "not "); #if defined (FAILOVER_PROTOCOL) if (lease && lease -> pool && lease -> pool -> failover_peer) { dhcp_failover_state_t *peer = lease -> pool -> failover_peer; if (peer -> service_state == not_responding || peer -> service_state == service_startup) { log_info ("%s: ignored%s", peer -> name, peer -> nrr); goto out; } /* DHCPRELEASE messages are unicast, so if the client sent the DHCPRELEASE to us, it's not going to send it to the peer. Not sure why this would happen, and if it does happen I think we still have to change the lease state, so that's what we're doing. XXX See what it says in the draft about this. */ } #endif /* If we found a lease, release it. */ if (lease && lease -> ends > cur_time) { release_lease (lease, packet); } log_info ("%s", msgbuf); #if defined(FAILOVER_PROTOCOL) out: #endif if (lease) lease_dereference (&lease, MDL); } void dhcpdecline (packet, ms_nulltp) struct packet *packet; int ms_nulltp; { struct lease *lease = (struct lease *)0; struct option_state *options = (struct option_state *)0; int ignorep = 0; int i; const char *status; const char *s; char msgbuf [1024]; /* XXX */ struct iaddr cip; struct option_cache *oc; struct data_string data; /* DHCPDECLINE must specify address. */ if (!(oc = lookup_option (&dhcp_universe, packet -> options, DHO_DHCP_REQUESTED_ADDRESS))) return; memset (&data, 0, sizeof data); if (!evaluate_option_cache (&data, packet, (struct lease *)0, (struct client_state *)0, packet -> options, (struct option_state *)0, &global_scope, oc, MDL)) return; cip.len = 4; memcpy (cip.iabuf, data.data, 4); data_string_forget (&data, MDL); find_lease_by_ip_addr (&lease, cip, MDL); if (lease && lease -> client_hostname) { if ((strlen (lease -> client_hostname) <= 64) && db_printable((unsigned char *)lease->client_hostname)) s = lease -> client_hostname; else s = "Hostname Unsuitable for Printing"; } else s = (char *)0; /* %Audit% This is log output. %2004.06.17,Safe% * If we truncate we hope the user can get a hint from the log. */ snprintf (msgbuf, sizeof msgbuf, "DHCPDECLINE of %s from %s %s%s%svia %s", piaddr (cip), (packet -> raw -> htype ? print_hw_addr (packet -> raw -> htype, packet -> raw -> hlen, packet -> raw -> chaddr) : (lease ? print_hex_1(lease->uid_len, lease->uid, 60) : "")), s ? "(" : "", s ? s : "", s ? ") " : "", packet -> raw -> giaddr.s_addr ? inet_ntoa (packet -> raw -> giaddr) : packet -> interface -> name); option_state_allocate (&options, MDL); /* Execute statements in scope starting with the subnet scope. */ if (lease) execute_statements_in_scope ((struct binding_value **)0, packet, (struct lease *)0, (struct client_state *)0, packet -> options, options, &global_scope, lease -> subnet -> group, (struct group *)0); /* Execute statements in the class scopes. */ for (i = packet -> class_count; i > 0; i--) { execute_statements_in_scope ((struct binding_value **)0, packet, (struct lease *)0, (struct client_state *)0, packet -> options, options, &global_scope, packet -> classes [i - 1] -> group, lease ? lease -> subnet -> group : (struct group *)0); } /* Drop the request if dhcpdeclines are being ignored. */ oc = lookup_option (&server_universe, options, SV_DECLINES); if (!oc || evaluate_boolean_option_cache (&ignorep, packet, lease, (struct client_state *)0, packet -> options, options, &lease -> scope, oc, MDL)) { /* If we found a lease, mark it as unusable and complain. */ if (lease) { #if defined (FAILOVER_PROTOCOL) if (lease -> pool && lease -> pool -> failover_peer) { dhcp_failover_state_t *peer = lease -> pool -> failover_peer; if (peer -> service_state == not_responding || peer -> service_state == service_startup) { if (!ignorep) log_info ("%s: ignored%s", peer -> name, peer -> nrr); goto out; } /* DHCPDECLINE messages are broadcast, so we can safely ignore the DHCPDECLINE if the peer has the lease. XXX Of course, at this point that information has been lost. */ } #endif abandon_lease (lease, "declined."); status = "abandoned"; } else { status = "not found"; } } else status = "ignored"; if (!ignorep) log_info ("%s: %s", msgbuf, status); #if defined(FAILOVER_PROTOCOL) out: #endif if (options) option_state_dereference (&options, MDL); if (lease) lease_dereference (&lease, MDL); } void dhcpinform (packet, ms_nulltp) struct packet *packet; int ms_nulltp; { char msgbuf [1024]; struct data_string d1, prl; struct option_cache *oc; struct option_state *options = (struct option_state *)0; struct dhcp_packet raw; struct packet outgoing; unsigned char dhcpack = DHCPACK; struct subnet *subnet = NULL; struct iaddr cip, gip; unsigned i; int nulltp; struct sockaddr_in to; struct in_addr from; isc_boolean_t zeroed_ciaddr; struct interface_info *interface; int result; /* The client should set ciaddr to its IP address, but apparently it's common for clients not to do this, so we'll use their IP source address if they didn't set ciaddr. */ if (!packet -> raw -> ciaddr.s_addr) { zeroed_ciaddr = ISC_TRUE; cip.len = 4; memcpy (cip.iabuf, &packet -> client_addr.iabuf, 4); } else { zeroed_ciaddr = ISC_FALSE; cip.len = 4; memcpy (cip.iabuf, &packet -> raw -> ciaddr, 4); } if (packet->raw->giaddr.s_addr) { gip.len = 4; memcpy(gip.iabuf, &packet->raw->giaddr, 4); } else gip.len = 0; /* %Audit% This is log output. %2004.06.17,Safe% * If we truncate we hope the user can get a hint from the log. */ snprintf (msgbuf, sizeof msgbuf, "DHCPINFORM from %s via %s", piaddr (cip), packet->raw->giaddr.s_addr ? inet_ntoa(packet->raw->giaddr) : packet -> interface -> name); /* If the IP source address is zero, don't respond. */ if (!memcmp (cip.iabuf, "\0\0\0", 4)) { log_info ("%s: ignored (null source address).", msgbuf); return; } /* Find the subnet that the client is on. */ if (zeroed_ciaddr && (gip.len != 0)) { /* XXX - do subnet selection relay agent suboption here */ find_subnet(&subnet, gip, MDL); if (subnet == NULL) { log_info("%s: unknown subnet for relay address %s", msgbuf, piaddr(gip)); return; } } else { /* XXX - do subnet selection (not relay agent) option here */ find_subnet(&subnet, cip, MDL); if (subnet == NULL) { log_info("%s: unknown subnet for %s address %s", msgbuf, zeroed_ciaddr ? "source" : "client", piaddr(cip)); return; } } /* We don't respond to DHCPINFORM packets if we're not authoritative. It would be nice if a per-host value could override this, but there's overhead involved in checking this, so let's see how people react first. */ if (subnet && !subnet -> group -> authoritative) { static int eso = 0; log_info ("%s: not authoritative for subnet %s", msgbuf, piaddr (subnet -> net)); if (!eso) { log_info ("If this DHCP server is authoritative for%s", " that subnet,"); log_info ("please write an `authoritative;' directi%s", "ve either in the"); log_info ("subnet declaration or in some scope that%s", " encloses the"); log_info ("subnet declaration - for example, write %s", "it at the top"); log_info ("of the dhcpd.conf file."); } if (eso++ == 100) eso = 0; subnet_dereference (&subnet, MDL); return; } option_state_allocate (&options, MDL); memset (&outgoing, 0, sizeof outgoing); memset (&raw, 0, sizeof raw); outgoing.raw = &raw; maybe_return_agent_options(packet, options); /* Execute statements in scope starting with the subnet scope. */ if (subnet) execute_statements_in_scope ((struct binding_value **)0, packet, (struct lease *)0, (struct client_state *)0, packet -> options, options, &global_scope, subnet -> group, (struct group *)0); /* Execute statements in the class scopes. */ for (i = packet -> class_count; i > 0; i--) { execute_statements_in_scope ((struct binding_value **)0, packet, (struct lease *)0, (struct client_state *)0, packet -> options, options, &global_scope, packet -> classes [i - 1] -> group, subnet ? subnet -> group : (struct group *)0); } /* Figure out the filename. */ memset (&d1, 0, sizeof d1); oc = lookup_option (&server_universe, options, SV_FILENAME); if (oc && evaluate_option_cache (&d1, packet, (struct lease *)0, (struct client_state *)0, packet -> options, (struct option_state *)0, &global_scope, oc, MDL)) { i = d1.len; if (i >= sizeof(raw.file)) { log_info("file name longer than packet field " "truncated - field: %lu name: %d %.*s", (unsigned long)sizeof(raw.file), i, i, d1.data); i = sizeof(raw.file); } else raw.file[i] = 0; memcpy (raw.file, d1.data, i); data_string_forget (&d1, MDL); } /* Choose a server name as above. */ oc = lookup_option (&server_universe, options, SV_SERVER_NAME); if (oc && evaluate_option_cache (&d1, packet, (struct lease *)0, (struct client_state *)0, packet -> options, (struct option_state *)0, &global_scope, oc, MDL)) { i = d1.len; if (i >= sizeof(raw.sname)) { log_info("server name longer than packet field " "truncated - field: %lu name: %d %.*s", (unsigned long)sizeof(raw.sname), i, i, d1.data); i = sizeof(raw.sname); } else raw.sname[i] = 0; memcpy (raw.sname, d1.data, i); data_string_forget (&d1, MDL); } /* Set a flag if this client is a lame Microsoft client that NUL terminates string options and expects us to do likewise. */ nulltp = 0; if ((oc = lookup_option (&dhcp_universe, packet -> options, DHO_HOST_NAME))) { if (!oc->expression) nulltp = oc->flags & OPTION_HAD_NULLS; } /* Put in DHCP-specific options. */ i = DHO_DHCP_MESSAGE_TYPE; oc = (struct option_cache *)0; if (option_cache_allocate (&oc, MDL)) { if (make_const_data (&oc -> expression, &dhcpack, 1, 0, 0, MDL)) { option_code_hash_lookup(&oc->option, dhcp_universe.code_hash, &i, 0, MDL); save_option (&dhcp_universe, options, oc); } option_cache_dereference (&oc, MDL); } get_server_source_address(&from, options, packet); /* Use the subnet mask from the subnet declaration if no other mask has been provided. */ i = DHO_SUBNET_MASK; if (subnet && !lookup_option (&dhcp_universe, options, i)) { oc = (struct option_cache *)0; if (option_cache_allocate (&oc, MDL)) { if (make_const_data (&oc -> expression, subnet -> netmask.iabuf, subnet -> netmask.len, 0, 0, MDL)) { option_code_hash_lookup(&oc->option, dhcp_universe.code_hash, &i, 0, MDL); save_option (&dhcp_universe, options, oc); } option_cache_dereference (&oc, MDL); } } /* If a site option space has been specified, use that for site option codes. */ i = SV_SITE_OPTION_SPACE; if ((oc = lookup_option (&server_universe, options, i)) && evaluate_option_cache (&d1, packet, (struct lease *)0, (struct client_state *)0, packet -> options, options, &global_scope, oc, MDL)) { struct universe *u = (struct universe *)0; if (!universe_hash_lookup (&u, universe_hash, (const char *)d1.data, d1.len, MDL)) { log_error ("unknown option space %s.", d1.data); option_state_dereference (&options, MDL); if (subnet) subnet_dereference (&subnet, MDL); return; } options -> site_universe = u -> index; options->site_code_min = find_min_site_code(u); data_string_forget (&d1, MDL); } else { options -> site_universe = dhcp_universe.index; options -> site_code_min = 0; /* Trust me, it works. */ } memset (&prl, 0, sizeof prl); /* Use the parameter list from the scope if there is one. */ oc = lookup_option (&dhcp_universe, options, DHO_DHCP_PARAMETER_REQUEST_LIST); /* Otherwise, if the client has provided a list of options that it wishes returned, use it to prioritize. Otherwise, prioritize based on the default priority list. */ if (!oc) oc = lookup_option (&dhcp_universe, packet -> options, DHO_DHCP_PARAMETER_REQUEST_LIST); if (oc) evaluate_option_cache (&prl, packet, (struct lease *)0, (struct client_state *)0, packet -> options, options, &global_scope, oc, MDL); #ifdef DEBUG_PACKET dump_packet (packet); dump_raw ((unsigned char *)packet -> raw, packet -> packet_length); #endif log_info ("%s", msgbuf); /* Figure out the address of the boot file server. */ if ((oc = lookup_option (&server_universe, options, SV_NEXT_SERVER))) { if (evaluate_option_cache (&d1, packet, (struct lease *)0, (struct client_state *)0, packet -> options, options, &global_scope, oc, MDL)) { /* If there was more than one answer, take the first. */ if (d1.len >= 4 && d1.data) memcpy (&raw.siaddr, d1.data, 4); data_string_forget (&d1, MDL); } } /* * Remove any time options, per section 3.4 RFC 2131 */ delete_option(&dhcp_universe, options, DHO_DHCP_LEASE_TIME); delete_option(&dhcp_universe, options, DHO_DHCP_RENEWAL_TIME); delete_option(&dhcp_universe, options, DHO_DHCP_REBINDING_TIME); /* Set up the option buffer... */ outgoing.packet_length = cons_options (packet, outgoing.raw, (struct lease *)0, (struct client_state *)0, 0, packet -> options, options, &global_scope, 0, nulltp, 0, prl.len ? &prl : (struct data_string *)0, (char *)0); option_state_dereference (&options, MDL); data_string_forget (&prl, MDL); /* Make sure that the packet is at least as big as a BOOTP packet. */ if (outgoing.packet_length < BOOTP_MIN_LEN) outgoing.packet_length = BOOTP_MIN_LEN; raw.giaddr = packet -> raw -> giaddr; raw.ciaddr = packet -> raw -> ciaddr; memcpy (raw.chaddr, packet -> raw -> chaddr, sizeof raw.chaddr); raw.hlen = packet -> raw -> hlen; raw.htype = packet -> raw -> htype; raw.xid = packet -> raw -> xid; raw.secs = packet -> raw -> secs; raw.flags = packet -> raw -> flags; raw.hops = packet -> raw -> hops; raw.op = BOOTREPLY; #ifdef DEBUG_PACKET dump_packet (&outgoing); dump_raw ((unsigned char *)&raw, outgoing.packet_length); #endif /* Set up the common stuff... */ to.sin_family = AF_INET; #ifdef HAVE_SA_LEN to.sin_len = sizeof to; #endif memset (to.sin_zero, 0, sizeof to.sin_zero); /* RFC2131 states the server SHOULD unciast to ciaddr. * There are two wrinkles - relays, and when ciaddr is zero. * There's actually no mention of relays at all in rfc2131 in * regard to DHCPINFORM, except to say we might get packets from * clients via them. Note: relays unicast to clients to the * "yiaddr" address, which servers are forbidden to set when * answering an inform. * * The solution: If ciaddr is zero, and giaddr is set, go via the * relay with the broadcast flag set to help the relay (with no * yiaddr and very likely no chaddr, it will have no idea where to * send the packet). * * If the ciaddr is zero and giaddr is not set, go via the source * IP address (but you are permitted to barf on their shoes). * * If ciaddr is not zero, send the packet there always. */ if (!raw.ciaddr.s_addr && gip.len) { memcpy(&to.sin_addr, gip.iabuf, 4); to.sin_port = local_port; raw.flags |= htons(BOOTP_BROADCAST); } else { gip.len = 0; memcpy(&to.sin_addr, cip.iabuf, 4); to.sin_port = remote_port; } /* Report what we're sending. */ snprintf(msgbuf, sizeof msgbuf, "DHCPACK to %s (%s) via", piaddr(cip), (packet->raw->htype && packet->raw->hlen) ? print_hw_addr(packet->raw->htype, packet->raw->hlen, packet->raw->chaddr) : ""); log_info("%s %s", msgbuf, gip.len ? piaddr(gip) : packet->interface->name); errno = 0; interface = (fallback_interface ? fallback_interface : packet -> interface); result = send_packet(interface, &outgoing, &raw, outgoing.packet_length, from, &to, NULL); if (result < 0) { log_error ("%s:%d: Failed to send %d byte long packet over %s " "interface.", MDL, outgoing.packet_length, interface->name); } if (subnet) subnet_dereference (&subnet, MDL); } void nak_lease (packet, cip) struct packet *packet; struct iaddr *cip; { struct sockaddr_in to; struct in_addr from; int result; struct dhcp_packet raw; unsigned char nak = DHCPNAK; struct packet outgoing; unsigned i; struct option_state *options = (struct option_state *)0; struct option_cache *oc = (struct option_cache *)0; option_state_allocate (&options, MDL); memset (&outgoing, 0, sizeof outgoing); memset (&raw, 0, sizeof raw); outgoing.raw = &raw; /* Set DHCP_MESSAGE_TYPE to DHCPNAK */ if (!option_cache_allocate (&oc, MDL)) { log_error ("No memory for DHCPNAK message type."); option_state_dereference (&options, MDL); return; } if (!make_const_data (&oc -> expression, &nak, sizeof nak, 0, 0, MDL)) { log_error ("No memory for expr_const expression."); option_cache_dereference (&oc, MDL); option_state_dereference (&options, MDL); return; } i = DHO_DHCP_MESSAGE_TYPE; option_code_hash_lookup(&oc->option, dhcp_universe.code_hash, &i, 0, MDL); save_option (&dhcp_universe, options, oc); option_cache_dereference (&oc, MDL); /* Set DHCP_MESSAGE to whatever the message is */ if (!option_cache_allocate (&oc, MDL)) { log_error ("No memory for DHCPNAK message type."); option_state_dereference (&options, MDL); return; } if (!make_const_data (&oc -> expression, (unsigned char *)dhcp_message, strlen (dhcp_message), 1, 0, MDL)) { log_error ("No memory for expr_const expression."); option_cache_dereference (&oc, MDL); option_state_dereference (&options, MDL); return; } i = DHO_DHCP_MESSAGE; option_code_hash_lookup(&oc->option, dhcp_universe.code_hash, &i, 0, MDL); save_option (&dhcp_universe, options, oc); option_cache_dereference (&oc, MDL); get_server_source_address(&from, options, packet); /* If there were agent options in the incoming packet, return * them. We do not check giaddr to detect the presence of a * relay, as this excludes "l2" relay agents which have no * giaddr to set. */ if (packet->options->universe_count > agent_universe.index && packet->options->universes [agent_universe.index]) { option_chain_head_reference ((struct option_chain_head **) &(options -> universes [agent_universe.index]), (struct option_chain_head *) packet -> options -> universes [agent_universe.index], MDL); } /* Do not use the client's requested parameter list. */ delete_option (&dhcp_universe, packet -> options, DHO_DHCP_PARAMETER_REQUEST_LIST); /* Set up the option buffer... */ outgoing.packet_length = cons_options (packet, outgoing.raw, (struct lease *)0, (struct client_state *)0, 0, packet -> options, options, &global_scope, 0, 0, 0, (struct data_string *)0, (char *)0); option_state_dereference (&options, MDL); /* memset (&raw.ciaddr, 0, sizeof raw.ciaddr);*/ if (packet->interface->address_count) raw.siaddr = packet->interface->addresses[0]; raw.giaddr = packet -> raw -> giaddr; memcpy (raw.chaddr, packet -> raw -> chaddr, sizeof raw.chaddr); raw.hlen = packet -> raw -> hlen; raw.htype = packet -> raw -> htype; raw.xid = packet -> raw -> xid; raw.secs = packet -> raw -> secs; raw.flags = packet -> raw -> flags | htons (BOOTP_BROADCAST); raw.hops = packet -> raw -> hops; raw.op = BOOTREPLY; /* Report what we're sending... */ log_info ("DHCPNAK on %s to %s via %s", piaddr (*cip), print_hw_addr (packet -> raw -> htype, packet -> raw -> hlen, packet -> raw -> chaddr), packet -> raw -> giaddr.s_addr ? inet_ntoa (packet -> raw -> giaddr) : packet -> interface -> name); #ifdef DEBUG_PACKET dump_packet (packet); dump_raw ((unsigned char *)packet -> raw, packet -> packet_length); dump_packet (&outgoing); dump_raw ((unsigned char *)&raw, outgoing.packet_length); #endif /* Set up the common stuff... */ to.sin_family = AF_INET; #ifdef HAVE_SA_LEN to.sin_len = sizeof to; #endif memset (to.sin_zero, 0, sizeof to.sin_zero); /* Make sure that the packet is at least as big as a BOOTP packet. */ if (outgoing.packet_length < BOOTP_MIN_LEN) outgoing.packet_length = BOOTP_MIN_LEN; /* If this was gatewayed, send it back to the gateway. Otherwise, broadcast it on the local network. */ if (raw.giaddr.s_addr) { to.sin_addr = raw.giaddr; if (raw.giaddr.s_addr != htonl (INADDR_LOOPBACK)) to.sin_port = local_port; else to.sin_port = remote_port; /* for testing. */ if (fallback_interface) { result = send_packet(fallback_interface, packet, &raw, outgoing.packet_length, from, &to, NULL); if (result < 0) { log_error ("%s:%d: Failed to send %d byte long " "packet over %s interface.", MDL, outgoing.packet_length, fallback_interface->name); } return; } } else { to.sin_addr = limited_broadcast; to.sin_port = remote_port; } errno = 0; result = send_packet(packet->interface, packet, &raw, outgoing.packet_length, from, &to, NULL); if (result < 0) { log_error ("%s:%d: Failed to send %d byte long packet over %s " "interface.", MDL, outgoing.packet_length, packet->interface->name); } } void ack_lease (packet, lease, offer, when, msg, ms_nulltp, hp) struct packet *packet; struct lease *lease; unsigned int offer; TIME when; char *msg; int ms_nulltp; struct host_decl *hp; { struct lease *lt; struct lease_state *state; struct lease *next; struct host_decl *host = (struct host_decl *)0; TIME lease_time; TIME offered_lease_time; struct data_string d1; TIME min_lease_time; TIME max_lease_time; TIME default_lease_time; struct option_cache *oc; isc_result_t result; TIME ping_timeout; TIME lease_cltt; struct in_addr from; TIME remaining_time; struct iaddr cip; #if defined(DELAYED_ACK) isc_boolean_t enqueue = ISC_TRUE; #endif unsigned i, j; int s1; int ignorep; struct timeval tv; /* If we're already acking this lease, don't do it again. */ if (lease -> state) return; /* Save original cltt for comparison later. */ lease_cltt = lease->cltt; /* If the lease carries a host record, remember it. */ if (hp) host_reference (&host, hp, MDL); else if (lease -> host) host_reference (&host, lease -> host, MDL); /* Allocate a lease state structure... */ state = new_lease_state (MDL); if (!state) log_fatal ("unable to allocate lease state!"); state -> got_requested_address = packet -> got_requested_address; shared_network_reference (&state -> shared_network, packet -> interface -> shared_network, MDL); /* See if we got a server identifier option. */ if (lookup_option (&dhcp_universe, packet -> options, DHO_DHCP_SERVER_IDENTIFIER)) state -> got_server_identifier = 1; maybe_return_agent_options(packet, state->options); /* If we are offering a lease that is still currently valid, preserve the events. We need to do this because if the client does not REQUEST our offer, it will expire in 2 minutes, overriding the expire time in the currently in force lease. We want the expire events to be executed at that point. */ if (lease -> ends <= cur_time && offer != DHCPOFFER) { /* Get rid of any old expiry or release statements - by executing the statements below, we will be inserting new ones if there are any to insert. */ if (lease -> on_expiry) executable_statement_dereference (&lease -> on_expiry, MDL); if (lease -> on_commit) executable_statement_dereference (&lease -> on_commit, MDL); if (lease -> on_release) executable_statement_dereference (&lease -> on_release, MDL); } /* Execute statements in scope starting with the subnet scope. */ execute_statements_in_scope ((struct binding_value **)0, packet, lease, (struct client_state *)0, packet -> options, state -> options, &lease -> scope, lease -> subnet -> group, (struct group *)0); /* If the lease is from a pool, run the pool scope. */ if (lease -> pool) (execute_statements_in_scope ((struct binding_value **)0, packet, lease, (struct client_state *)0, packet -> options, state -> options, &lease -> scope, lease -> pool -> group, lease -> pool -> shared_network -> group)); /* Execute statements from class scopes. */ for (i = packet -> class_count; i > 0; i--) { execute_statements_in_scope ((struct binding_value **)0, packet, lease, (struct client_state *)0, packet -> options, state -> options, &lease -> scope, packet -> classes [i - 1] -> group, (lease -> pool ? lease -> pool -> group : lease -> subnet -> group)); } /* See if the client is only supposed to have one lease at a time, and if so, find its other leases and release them. We can only do this on DHCPREQUEST. It's a little weird to do this before looking at permissions, because the client might not actually _get_ a lease after we've done the permission check, but the assumption for this option is that the client has exactly one network interface, and will only ever remember one lease. So if it sends a DHCPREQUEST, and doesn't get the lease, it's already forgotten about its old lease, so we can too. */ if (packet -> packet_type == DHCPREQUEST && (oc = lookup_option (&server_universe, state -> options, SV_ONE_LEASE_PER_CLIENT)) && evaluate_boolean_option_cache (&ignorep, packet, lease, (struct client_state *)0, packet -> options, state -> options, &lease -> scope, oc, MDL)) { struct lease *seek; if (lease -> uid_len) { do { seek = (struct lease *)0; find_lease_by_uid (&seek, lease -> uid, lease -> uid_len, MDL); if (!seek) break; if (seek == lease && !seek -> n_uid) { lease_dereference (&seek, MDL); break; } next = (struct lease *)0; /* Don't release expired leases, and don't release the lease we're going to assign. */ next = (struct lease *)0; while (seek) { if (seek -> n_uid) lease_reference (&next, seek -> n_uid, MDL); if (seek != lease && seek -> binding_state != FTS_RELEASED && seek -> binding_state != FTS_EXPIRED && seek -> binding_state != FTS_RESET && seek -> binding_state != FTS_FREE && seek -> binding_state != FTS_BACKUP) break; lease_dereference (&seek, MDL); if (next) { lease_reference (&seek, next, MDL); lease_dereference (&next, MDL); } } if (next) lease_dereference (&next, MDL); if (seek) { release_lease (seek, packet); lease_dereference (&seek, MDL); } else break; } while (1); } if (!lease -> uid_len || (host && !host -> client_identifier.len && (oc = lookup_option (&server_universe, state -> options, SV_DUPLICATES)) && !evaluate_boolean_option_cache (&ignorep, packet, lease, (struct client_state *)0, packet -> options, state -> options, &lease -> scope, oc, MDL))) { do { seek = (struct lease *)0; find_lease_by_hw_addr (&seek, lease -> hardware_addr.hbuf, lease -> hardware_addr.hlen, MDL); if (!seek) break; if (seek == lease && !seek -> n_hw) { lease_dereference (&seek, MDL); break; } next = (struct lease *)0; while (seek) { if (seek -> n_hw) lease_reference (&next, seek -> n_hw, MDL); if (seek != lease && seek -> binding_state != FTS_RELEASED && seek -> binding_state != FTS_EXPIRED && seek -> binding_state != FTS_RESET && seek -> binding_state != FTS_FREE && seek -> binding_state != FTS_BACKUP) break; lease_dereference (&seek, MDL); if (next) { lease_reference (&seek, next, MDL); lease_dereference (&next, MDL); } } if (next) lease_dereference (&next, MDL); if (seek) { release_lease (seek, packet); lease_dereference (&seek, MDL); } else break; } while (1); } } /* Make sure this packet satisfies the configured minimum number of seconds. */ memset (&d1, 0, sizeof d1); if (offer == DHCPOFFER && (oc = lookup_option (&server_universe, state -> options, SV_MIN_SECS))) { if (evaluate_option_cache (&d1, packet, lease, (struct client_state *)0, packet -> options, state -> options, &lease -> scope, oc, MDL)) { if (d1.len && ntohs (packet -> raw -> secs) < d1.data [0]) { log_info("%s: configured min-secs value (%d) " "is greater than secs field (%d). " "message dropped.", msg, d1.data[0], ntohs(packet->raw->secs)); data_string_forget (&d1, MDL); free_lease_state (state, MDL); if (host) host_dereference (&host, MDL); return; } data_string_forget (&d1, MDL); } } /* Try to find a matching host declaration for this lease. */ if (!host) { struct host_decl *hp = (struct host_decl *)0; struct host_decl *h; /* Try to find a host_decl that matches the client identifier or hardware address on the packet, and has no fixed IP address. If there is one, hang it off the lease so that its option definitions can be used. */ oc = lookup_option (&dhcp_universe, packet -> options, DHO_DHCP_CLIENT_IDENTIFIER); if (oc && evaluate_option_cache (&d1, packet, lease, (struct client_state *)0, packet -> options, state -> options, &lease -> scope, oc, MDL)) { find_hosts_by_uid (&hp, d1.data, d1.len, MDL); data_string_forget (&d1, MDL); for (h = hp; h; h = h -> n_ipaddr) { if (!h -> fixed_addr) break; } if (h) host_reference (&host, h, MDL); if (hp != NULL) host_dereference(&hp, MDL); } if (!host) { find_hosts_by_haddr (&hp, packet -> raw -> htype, packet -> raw -> chaddr, packet -> raw -> hlen, MDL); for (h = hp; h; h = h -> n_ipaddr) { if (!h -> fixed_addr) break; } if (h) host_reference (&host, h, MDL); if (hp != NULL) host_dereference(&hp, MDL); } if (!host) { find_hosts_by_option(&hp, packet, packet->options, MDL); for (h = hp; h; h = h -> n_ipaddr) { if (!h -> fixed_addr) break; } if (h) host_reference (&host, h, MDL); if (hp != NULL) host_dereference(&hp, MDL); } } /* If we have a host_decl structure, run the options associated with its group. Whether the host decl struct is old or not. */ if (host) execute_statements_in_scope ((struct binding_value **)0, packet, lease, (struct client_state *)0, packet -> options, state -> options, &lease -> scope, host -> group, (lease -> pool ? lease -> pool -> group : lease -> subnet -> group)); /* Drop the request if it's not allowed for this client. By default, unknown clients are allowed. */ if (!host && (oc = lookup_option (&server_universe, state -> options, SV_BOOT_UNKNOWN_CLIENTS)) && !evaluate_boolean_option_cache (&ignorep, packet, lease, (struct client_state *)0, packet -> options, state -> options, &lease -> scope, oc, MDL)) { if (!ignorep) log_info ("%s: unknown client", msg); free_lease_state (state, MDL); if (host) host_dereference (&host, MDL); return; } /* Drop the request if it's not allowed for this client. */ if (!offer && (oc = lookup_option (&server_universe, state -> options, SV_ALLOW_BOOTP)) && !evaluate_boolean_option_cache (&ignorep, packet, lease, (struct client_state *)0, packet -> options, state -> options, &lease -> scope, oc, MDL)) { if (!ignorep) log_info ("%s: bootp disallowed", msg); free_lease_state (state, MDL); if (host) host_dereference (&host, MDL); return; } /* Drop the request if booting is specifically denied. */ oc = lookup_option (&server_universe, state -> options, SV_ALLOW_BOOTING); if (oc && !evaluate_boolean_option_cache (&ignorep, packet, lease, (struct client_state *)0, packet -> options, state -> options, &lease -> scope, oc, MDL)) { if (!ignorep) log_info ("%s: booting disallowed", msg); free_lease_state (state, MDL); if (host) host_dereference (&host, MDL); return; } /* If we are configured to do per-class billing, do it. */ if (have_billing_classes && !(lease -> flags & STATIC_LEASE)) { /* See if the lease is currently being billed to a class, and if so, whether or not it can continue to be billed to that class. */ if (lease -> billing_class) { for (i = 0; i < packet -> class_count; i++) if (packet -> classes [i] == lease -> billing_class) break; if (i == packet -> class_count) unbill_class (lease, lease -> billing_class); } /* If we don't have an active billing, see if we need one, and if we do, try to do so. */ if (lease->billing_class == NULL) { int bill = 0; for (i = 0; i < packet->class_count; i++) { if (packet->classes[i]->lease_limit) { bill++; if (bill_class(lease, packet->classes[i])) break; } } if (bill != 0 && i == packet->class_count) { log_info("%s: no available billing: lease " "limit reached in all matching " "classes", msg); free_lease_state(state, MDL); if (host) host_dereference(&host, MDL); return; } /* If this is an offer, undo the billing. We go * through all the steps above to bill a class so * we can hit the 'no available billing' mark and * abort without offering. But it just doesn't make * sense to permanently bill a class for a non-active * lease. This means on REQUEST, we will bill this * lease again (if there is a REQUEST). */ if (offer == DHCPOFFER && lease->billing_class != NULL && lease->binding_state != FTS_ACTIVE) unbill_class(lease, lease->billing_class); } } /* Figure out the filename. */ oc = lookup_option (&server_universe, state -> options, SV_FILENAME); if (oc) evaluate_option_cache (&state -> filename, packet, lease, (struct client_state *)0, packet -> options, state -> options, &lease -> scope, oc, MDL); /* Choose a server name as above. */ oc = lookup_option (&server_universe, state -> options, SV_SERVER_NAME); if (oc) evaluate_option_cache (&state -> server_name, packet, lease, (struct client_state *)0, packet -> options, state -> options, &lease -> scope, oc, MDL); /* At this point, we have a lease that we can offer the client. Now we construct a lease structure that contains what we want, and call supersede_lease to do the right thing with it. */ lt = (struct lease *)0; result = lease_allocate (<, MDL); if (result != ISC_R_SUCCESS) { log_info ("%s: can't allocate temporary lease structure: %s", msg, isc_result_totext (result)); free_lease_state (state, MDL); if (host) host_dereference (&host, MDL); return; } /* Use the ip address of the lease that we finally found in the database. */ lt -> ip_addr = lease -> ip_addr; /* Start now. */ lt -> starts = cur_time; /* Figure out how long a lease to assign. If this is a dynamic BOOTP lease, its duration must be infinite. */ if (offer) { lt->flags &= ~BOOTP_LEASE; default_lease_time = DEFAULT_DEFAULT_LEASE_TIME; if ((oc = lookup_option (&server_universe, state -> options, SV_DEFAULT_LEASE_TIME))) { if (evaluate_option_cache (&d1, packet, lease, (struct client_state *)0, packet -> options, state -> options, &lease -> scope, oc, MDL)) { if (d1.len == sizeof (u_int32_t)) default_lease_time = getULong (d1.data); data_string_forget (&d1, MDL); } } if ((oc = lookup_option (&dhcp_universe, packet -> options, DHO_DHCP_LEASE_TIME))) s1 = evaluate_option_cache (&d1, packet, lease, (struct client_state *)0, packet -> options, state -> options, &lease -> scope, oc, MDL); else s1 = 0; if (s1 && (d1.len == 4)) { u_int32_t ones = 0xffffffff; /* One potential use of reserved leases is to allow * clients to signal reservation of their lease. They * can kinda sorta do this, if you squint hard enough, * by supplying an 'infinite' requested-lease-time * option. This is generally bad practice...you want * clients to return to the server on at least some * period (days, months, years) to get up-to-date * config state. So; * * 1) A client requests 0xffffffff lease-time. * 2) The server reserves the lease, and assigns a * <= max_lease_time lease-time to the client, which * we presume is much smaller than 0xffffffff. * 3) The client ultimately fails to renew its lease * (all clients go offline at some point). * 4) The server retains the reservation, although * the lease expires and passes through those states * as normal, it's placed in the 'reserved' queue, * and is under no circumstances allocated to any * clients. * * Whether the client knows its reserving its lease or * not, this can be a handy tool for a sysadmin. */ if ((memcmp(d1.data, &ones, 4) == 0) && (oc = lookup_option(&server_universe, state->options, SV_RESERVE_INFINITE)) && evaluate_boolean_option_cache(&ignorep, packet, lease, NULL, packet->options, state->options, &lease->scope, oc, MDL)) { lt->flags |= RESERVED_LEASE; if (!ignorep) log_info("Infinite-leasetime " "reservation made on %s.", piaddr(lt->ip_addr)); } lease_time = getULong (d1.data); } else lease_time = default_lease_time; if (s1) data_string_forget(&d1, MDL); /* See if there's a maximum lease time. */ max_lease_time = DEFAULT_MAX_LEASE_TIME; if ((oc = lookup_option (&server_universe, state -> options, SV_MAX_LEASE_TIME))) { if (evaluate_option_cache (&d1, packet, lease, (struct client_state *)0, packet -> options, state -> options, &lease -> scope, oc, MDL)) { if (d1.len == sizeof (u_int32_t)) max_lease_time = getULong (d1.data); data_string_forget (&d1, MDL); } } /* Enforce the maximum lease length. */ if (lease_time < 0 /* XXX */ || lease_time > max_lease_time) lease_time = max_lease_time; min_lease_time = DEFAULT_MIN_LEASE_TIME; if (min_lease_time > max_lease_time) min_lease_time = max_lease_time; if ((oc = lookup_option (&server_universe, state -> options, SV_MIN_LEASE_TIME))) { if (evaluate_option_cache (&d1, packet, lease, (struct client_state *)0, packet -> options, state -> options, &lease -> scope, oc, MDL)) { if (d1.len == sizeof (u_int32_t)) min_lease_time = getULong (d1.data); data_string_forget (&d1, MDL); } } /* CC: If there are less than adaptive-lease-time-threshold % free leases, hand out only short term leases */ memset(&d1, 0, sizeof(d1)); if (lease->pool && (oc = lookup_option(&server_universe, state->options, SV_ADAPTIVE_LEASE_TIME_THRESHOLD)) && evaluate_option_cache(&d1, packet, lease, NULL, packet->options, state->options, &lease->scope, oc, MDL)) { if (d1.len == 1 && d1.data[0] > 0 && d1.data[0] < 100) { TIME adaptive_time; int poolfilled, total, count; if (min_lease_time) adaptive_time = min_lease_time; else adaptive_time = DEFAULT_MIN_LEASE_TIME; /* Allow the client to keep its lease. */ if (lease->ends - cur_time > adaptive_time) adaptive_time = lease->ends - cur_time; count = lease->pool->lease_count; total = count - (lease->pool->free_leases + lease->pool->backup_leases); poolfilled = (total > (INT_MAX / 100)) ? total / (count / 100) : (total * 100) / count; log_debug("Adap-lease: Total: %d, Free: %d, " "Ends: %d, Adaptive: %d, Fill: %d, " "Threshold: %d", lease->pool->lease_count, lease->pool->free_leases, (int)(lease->ends - cur_time), (int)adaptive_time, poolfilled, d1.data[0]); if (poolfilled >= d1.data[0] && lease_time > adaptive_time) { log_info("Pool over threshold, time " "for %s reduced from %d to " "%d.", piaddr(lease->ip_addr), (int)lease_time, (int)adaptive_time); lease_time = adaptive_time; } } data_string_forget(&d1, MDL); } /* a client requests an address which is not yet active*/ if (lease->pool && lease->pool->valid_from && cur_time < lease->pool->valid_from) { /* NAK leases before pool activation date */ cip.len = 4; memcpy (cip.iabuf, <->ip_addr.iabuf, 4); nak_lease(packet, &cip); free_lease_state (state, MDL); lease_dereference (<, MDL); if (host) host_dereference (&host, MDL); return; } /* CC: a) NAK current lease if past the expiration date b) extend lease only up to the expiration date, but not below min-lease-time Setting min-lease-time is essential for this to work! The value of min-lease-time determines the lenght of the transition window: A client renewing a second before the deadline will get a min-lease-time lease. Since the current ip might not be routable after the deadline, the client will be offline until it DISCOVERS again. Otherwise it will receive a NAK at T/2. A min-lease-time of 6 seconds effectively switches over all clients in this pool very quickly. */ if (lease->pool && lease->pool->valid_until) { if (cur_time >= lease->pool->valid_until) { /* NAK leases after pool expiration date */ cip.len = 4; memcpy (cip.iabuf, <->ip_addr.iabuf, 4); nak_lease(packet, &cip); free_lease_state (state, MDL); lease_dereference (<, MDL); if (host) host_dereference (&host, MDL); return; } remaining_time = lease->pool->valid_until - cur_time; if (lease_time > remaining_time) lease_time = remaining_time; } if (lease_time < min_lease_time) { if (min_lease_time) lease_time = min_lease_time; else lease_time = default_lease_time; } #if defined (FAILOVER_PROTOCOL) /* Okay, we know the lease duration. Now check the failover state, if any. */ if (lease -> pool && lease -> pool -> failover_peer) { TIME new_lease_time = lease_time; dhcp_failover_state_t *peer = lease -> pool -> failover_peer; /* Copy previous lease failover ack-state. */ lt->tsfp = lease->tsfp; lt->atsfp = lease->atsfp; /* cltt set below */ /* Lease times less than MCLT are not a concern. */ if (lease_time > peer->mclt) { /* Each server can only offer a lease time * that is either equal to MCLT (at least), * or up to TSFP+MCLT. Only if the desired * lease time falls within TSFP+MCLT, can * the server allow it. */ if (lt->tsfp <= cur_time) new_lease_time = peer->mclt; else if ((cur_time + lease_time) > (lt->tsfp + peer->mclt)) new_lease_time = (lt->tsfp - cur_time) + peer->mclt; } /* Update potential expiry. Allow for the desired * lease time plus one half the actual (whether * modified downward or not) lease time, which is * actually an estimate of when the client will * renew. This way, the client will be able to get * the desired lease time upon renewal. */ if (offer == DHCPACK) { lt->tstp = cur_time + lease_time + (new_lease_time / 2); /* If we reduced the potential expiry time, * make sure we don't offer an old-expiry-time * lease for this lease before the change is * ack'd. */ if (lt->tstp < lt->tsfp) lt->tsfp = lt->tstp; } else lt->tstp = lease->tstp; /* Use failover-modified lease time. */ lease_time = new_lease_time; } #endif /* FAILOVER_PROTOCOL */ /* If the lease duration causes the time value to wrap, use the maximum expiry time. */ if (cur_time + lease_time < cur_time) state -> offered_expiry = MAX_TIME - 1; else state -> offered_expiry = cur_time + lease_time; if (when) lt -> ends = when; else lt -> ends = state -> offered_expiry; /* Don't make lease active until we actually get a DHCPREQUEST. */ if (offer == DHCPACK) lt -> next_binding_state = FTS_ACTIVE; else lt -> next_binding_state = lease -> binding_state; } else { lt->flags |= BOOTP_LEASE; lease_time = MAX_TIME - cur_time; if ((oc = lookup_option (&server_universe, state -> options, SV_BOOTP_LEASE_LENGTH))) { if (evaluate_option_cache (&d1, packet, lease, (struct client_state *)0, packet -> options, state -> options, &lease -> scope, oc, MDL)) { if (d1.len == sizeof (u_int32_t)) lease_time = getULong (d1.data); data_string_forget (&d1, MDL); } } if ((oc = lookup_option (&server_universe, state -> options, SV_BOOTP_LEASE_CUTOFF))) { if (evaluate_option_cache (&d1, packet, lease, (struct client_state *)0, packet -> options, state -> options, &lease -> scope, oc, MDL)) { if (d1.len == sizeof (u_int32_t)) lease_time = (getULong (d1.data) - cur_time); data_string_forget (&d1, MDL); } } lt -> ends = state -> offered_expiry = cur_time + lease_time; lt -> next_binding_state = FTS_ACTIVE; } /* Update Client Last Transaction Time. */ lt->cltt = cur_time; /* Record the uid, if given... */ oc = lookup_option (&dhcp_universe, packet -> options, DHO_DHCP_CLIENT_IDENTIFIER); if (oc && evaluate_option_cache (&d1, packet, lease, (struct client_state *)0, packet -> options, state -> options, &lease -> scope, oc, MDL)) { if (d1.len <= sizeof lt -> uid_buf) { memcpy (lt -> uid_buf, d1.data, d1.len); lt -> uid = lt -> uid_buf; lt -> uid_max = sizeof lt -> uid_buf; lt -> uid_len = d1.len; } else { unsigned char *tuid; lt -> uid_max = d1.len; lt -> uid_len = d1.len; tuid = (unsigned char *)dmalloc (lt -> uid_max, MDL); /* XXX inelegant */ if (!tuid) log_fatal ("no memory for large uid."); memcpy (tuid, d1.data, lt -> uid_len); lt -> uid = tuid; } data_string_forget (&d1, MDL); } if (host) { host_reference (< -> host, host, MDL); host_dereference (&host, MDL); } if (lease -> subnet) subnet_reference (< -> subnet, lease -> subnet, MDL); if (lease -> billing_class) class_reference (< -> billing_class, lease -> billing_class, MDL); /* Set a flag if this client is a broken client that NUL terminates string options and expects us to do likewise. */ if (ms_nulltp) lease -> flags |= MS_NULL_TERMINATION; else lease -> flags &= ~MS_NULL_TERMINATION; /* Save any bindings. */ if (lease -> scope) { binding_scope_reference (< -> scope, lease -> scope, MDL); binding_scope_dereference (&lease -> scope, MDL); } if (lease -> agent_options) option_chain_head_reference (< -> agent_options, lease -> agent_options, MDL); /* Save the vendor-class-identifier for DHCPLEASEQUERY. */ oc = lookup_option(&dhcp_universe, packet->options, DHO_VENDOR_CLASS_IDENTIFIER); if (oc != NULL && evaluate_option_cache(&d1, packet, NULL, NULL, packet->options, NULL, &lease->scope, oc, MDL)) { if (d1.len != 0) { bind_ds_value(&lease->scope, "vendor-class-identifier", &d1); } data_string_forget(&d1, MDL); } /* If we got relay agent information options from the packet, then * cache them for renewal in case the relay agent can't supply them * when the client unicasts. The options may be from an addressed * "l3" relay, or from an unaddressed "l2" relay which does not set * giaddr. */ if (!packet->agent_options_stashed && (packet->options != NULL) && packet->options->universe_count > agent_universe.index && packet->options->universes[agent_universe.index] != NULL) { oc = lookup_option (&server_universe, state -> options, SV_STASH_AGENT_OPTIONS); if (!oc || evaluate_boolean_option_cache (&ignorep, packet, lease, (struct client_state *)0, packet -> options, state -> options, &lease -> scope, oc, MDL)) { if (lt -> agent_options) option_chain_head_dereference (< -> agent_options, MDL); option_chain_head_reference (< -> agent_options, (struct option_chain_head *) packet -> options -> universes [agent_universe.index], MDL); } } /* Replace the old lease hostname with the new one, if it's changed. */ oc = lookup_option (&dhcp_universe, packet -> options, DHO_HOST_NAME); if (oc) s1 = evaluate_option_cache (&d1, packet, (struct lease *)0, (struct client_state *)0, packet -> options, (struct option_state *)0, &global_scope, oc, MDL); else s1 = 0; if (oc && s1 && lease -> client_hostname && strlen (lease -> client_hostname) == d1.len && !memcmp (lease -> client_hostname, d1.data, d1.len)) { /* Hasn't changed. */ data_string_forget (&d1, MDL); lt -> client_hostname = lease -> client_hostname; lease -> client_hostname = (char *)0; } else if (oc && s1) { lt -> client_hostname = dmalloc (d1.len + 1, MDL); if (!lt -> client_hostname) log_error ("no memory for client hostname."); else { memcpy (lt -> client_hostname, d1.data, d1.len); lt -> client_hostname [d1.len] = 0; } data_string_forget (&d1, MDL); } /* Record the hardware address, if given... */ lt -> hardware_addr.hlen = packet -> raw -> hlen + 1; lt -> hardware_addr.hbuf [0] = packet -> raw -> htype; memcpy (< -> hardware_addr.hbuf [1], packet -> raw -> chaddr, sizeof packet -> raw -> chaddr); lt -> flags = lease -> flags & ~PERSISTENT_FLAGS; /* If there are statements to execute when the lease is committed, execute them. */ if (lease -> on_commit && (!offer || offer == DHCPACK)) { execute_statements ((struct binding_value **)0, packet, lt, (struct client_state *)0, packet -> options, state -> options, < -> scope, lease -> on_commit); if (lease -> on_commit) executable_statement_dereference (&lease -> on_commit, MDL); } #ifdef NSUPDATE /* Perform DDNS updates, if configured to. */ if ((!offer || offer == DHCPACK) && (!(oc = lookup_option (&server_universe, state -> options, SV_DDNS_UPDATES)) || evaluate_boolean_option_cache (&ignorep, packet, lt, (struct client_state *)0, packet -> options, state -> options, < -> scope, oc, MDL))) { ddns_updates(packet, lt, lease, NULL, NULL, state->options); } #endif /* NSUPDATE */ /* Don't call supersede_lease on a mocked-up lease. */ if (lease -> flags & STATIC_LEASE) { /* Copy the hardware address into the static lease structure. */ lease -> hardware_addr.hlen = packet -> raw -> hlen + 1; lease -> hardware_addr.hbuf [0] = packet -> raw -> htype; memcpy (&lease -> hardware_addr.hbuf [1], packet -> raw -> chaddr, sizeof packet -> raw -> chaddr); /* XXX */ } else { #if !defined(DELAYED_ACK) /* Install the new information on 'lt' onto the lease at * 'lease'. If this is a DHCPOFFER, it is a 'soft' promise, * if it is a DHCPACK, it is a 'hard' binding, so it needs * to be recorded and propogated immediately. If the update * fails, don't ACK it (or BOOTREPLY) either; we may give * the same lease to another client later, and that would be * a conflict. */ if (!supersede_lease(lease, lt, !offer || (offer == DHCPACK), offer == DHCPACK, offer == DHCPACK)) { #else /* defined(DELAYED_ACK) */ /* Install the new information on 'lt' onto the lease at * 'lease'.  We will not 'commit' this information to disk * yet (fsync()), we will 'propogate' the information if * this is BOOTP or a DHCPACK, but we will not 'pimmediate'ly * transmit failover binding updates (this is delayed until * after the fsync()). If the update fails, don't ACK it (or * BOOTREPLY either); we may give the same lease out to a * different client, and that would be a conflict. */ if (!supersede_lease(lease, lt, 0, !offer || offer == DHCPACK, 0)) { #endif log_info ("%s: database update failed", msg); free_lease_state (state, MDL); lease_dereference (<, MDL); return; } } lease_dereference (<, MDL); /* Remember the interface on which the packet arrived. */ state -> ip = packet -> interface; /* Remember the giaddr, xid, secs, flags and hops. */ state -> giaddr = packet -> raw -> giaddr; state -> ciaddr = packet -> raw -> ciaddr; state -> xid = packet -> raw -> xid; state -> secs = packet -> raw -> secs; state -> bootp_flags = packet -> raw -> flags; state -> hops = packet -> raw -> hops; state -> offer = offer; /* If we're always supposed to broadcast to this client, set the broadcast bit in the bootp flags field. */ if ((oc = lookup_option (&server_universe, state -> options, SV_ALWAYS_BROADCAST)) && evaluate_boolean_option_cache (&ignorep, packet, lease, (struct client_state *)0, packet -> options, state -> options, &lease -> scope, oc, MDL)) state -> bootp_flags |= htons (BOOTP_BROADCAST); /* Get the Maximum Message Size option from the packet, if one was sent. */ oc = lookup_option (&dhcp_universe, packet -> options, DHO_DHCP_MAX_MESSAGE_SIZE); if (oc && evaluate_option_cache (&d1, packet, lease, (struct client_state *)0, packet -> options, state -> options, &lease -> scope, oc, MDL)) { if (d1.len == sizeof (u_int16_t)) state -> max_message_size = getUShort (d1.data); data_string_forget (&d1, MDL); } else { oc = lookup_option (&dhcp_universe, state -> options, DHO_DHCP_MAX_MESSAGE_SIZE); if (oc && evaluate_option_cache (&d1, packet, lease, (struct client_state *)0, packet -> options, state -> options, &lease -> scope, oc, MDL)) { if (d1.len == sizeof (u_int16_t)) state -> max_message_size = getUShort (d1.data); data_string_forget (&d1, MDL); } } /* Get the Subnet Selection option from the packet, if one was sent. */ if ((oc = lookup_option (&dhcp_universe, packet -> options, DHO_SUBNET_SELECTION))) { /* Make a copy of the data. */ struct option_cache *noc = (struct option_cache *)0; if (option_cache_allocate (&noc, MDL)) { if (oc -> data.len) data_string_copy (&noc -> data, &oc -> data, MDL); if (oc -> expression) expression_reference (&noc -> expression, oc -> expression, MDL); if (oc -> option) option_reference(&(noc->option), oc->option, MDL); } save_option (&dhcp_universe, state -> options, noc); option_cache_dereference (&noc, MDL); } /* Now, if appropriate, put in DHCP-specific options that override those. */ if (state -> offer) { i = DHO_DHCP_MESSAGE_TYPE; oc = (struct option_cache *)0; if (option_cache_allocate (&oc, MDL)) { if (make_const_data (&oc -> expression, &state -> offer, 1, 0, 0, MDL)) { option_code_hash_lookup(&oc->option, dhcp_universe.code_hash, &i, 0, MDL); save_option (&dhcp_universe, state -> options, oc); } option_cache_dereference (&oc, MDL); } get_server_source_address(&from, state->options, packet); memcpy(state->from.iabuf, &from, sizeof(from)); state->from.len = sizeof(from); offered_lease_time = state -> offered_expiry - cur_time; putULong(state->expiry, (u_int32_t)offered_lease_time); i = DHO_DHCP_LEASE_TIME; oc = (struct option_cache *)0; if (option_cache_allocate (&oc, MDL)) { if (make_const_data(&oc->expression, state->expiry, 4, 0, 0, MDL)) { option_code_hash_lookup(&oc->option, dhcp_universe.code_hash, &i, 0, MDL); save_option (&dhcp_universe, state -> options, oc); } option_cache_dereference (&oc, MDL); } /* * Validate any configured renew or rebinding times against * the determined lease time. Do rebinding first so that * the renew time can be validated against the rebind time. */ if ((oc = lookup_option(&dhcp_universe, state->options, DHO_DHCP_REBINDING_TIME)) != NULL && evaluate_option_cache(&d1, packet, lease, NULL, packet->options, state->options, &lease->scope, oc, MDL)) { TIME rebind_time = getULong(d1.data); /* Drop the configured (invalid) rebinding time. */ if (rebind_time >= offered_lease_time) delete_option(&dhcp_universe, state->options, DHO_DHCP_REBINDING_TIME); else /* XXX: variable is reused. */ offered_lease_time = rebind_time; data_string_forget(&d1, MDL); } if ((oc = lookup_option(&dhcp_universe, state->options, DHO_DHCP_RENEWAL_TIME)) != NULL && evaluate_option_cache(&d1, packet, lease, NULL, packet->options, state->options, &lease->scope, oc, MDL)) { if (getULong(d1.data) >= offered_lease_time) delete_option(&dhcp_universe, state->options, DHO_DHCP_RENEWAL_TIME); data_string_forget(&d1, MDL); } } else { /* XXXSK: should we use get_server_source_address() here? */ if (state -> ip -> address_count) { state -> from.len = sizeof state -> ip -> addresses [0]; memcpy (state -> from.iabuf, &state -> ip -> addresses [0], state -> from.len); } } /* Figure out the address of the boot file server. */ memset (&state -> siaddr, 0, sizeof state -> siaddr); if ((oc = lookup_option (&server_universe, state -> options, SV_NEXT_SERVER))) { if (evaluate_option_cache (&d1, packet, lease, (struct client_state *)0, packet -> options, state -> options, &lease -> scope, oc, MDL)) { /* If there was more than one answer, take the first. */ if (d1.len >= 4 && d1.data) memcpy (&state -> siaddr, d1.data, 4); data_string_forget (&d1, MDL); } } /* Use the subnet mask from the subnet declaration if no other mask has been provided. */ i = DHO_SUBNET_MASK; if (!lookup_option (&dhcp_universe, state -> options, i)) { oc = (struct option_cache *)0; if (option_cache_allocate (&oc, MDL)) { if (make_const_data (&oc -> expression, lease -> subnet -> netmask.iabuf, lease -> subnet -> netmask.len, 0, 0, MDL)) { option_code_hash_lookup(&oc->option, dhcp_universe.code_hash, &i, 0, MDL); save_option (&dhcp_universe, state -> options, oc); } option_cache_dereference (&oc, MDL); } } /* Use the hostname from the host declaration if there is one and no hostname has otherwise been provided, and if the use-host-decl-name flag is set. */ i = DHO_HOST_NAME; j = SV_USE_HOST_DECL_NAMES; if (!lookup_option (&dhcp_universe, state -> options, i) && lease -> host && lease -> host -> name && (evaluate_boolean_option_cache (&ignorep, packet, lease, (struct client_state *)0, packet -> options, state -> options, &lease -> scope, lookup_option (&server_universe, state -> options, j), MDL))) { oc = (struct option_cache *)0; if (option_cache_allocate (&oc, MDL)) { if (make_const_data (&oc -> expression, ((unsigned char *) lease -> host -> name), strlen (lease -> host -> name), 1, 0, MDL)) { option_code_hash_lookup(&oc->option, dhcp_universe.code_hash, &i, 0, MDL); save_option (&dhcp_universe, state -> options, oc); } option_cache_dereference (&oc, MDL); } } /* If we don't have a hostname yet, and we've been asked to do a reverse lookup to find the hostname, do it. */ i = DHO_HOST_NAME; j = SV_GET_LEASE_HOSTNAMES; if (!lookup_option(&dhcp_universe, state->options, i) && evaluate_boolean_option_cache (&ignorep, packet, lease, NULL, packet->options, state->options, &lease->scope, lookup_option (&server_universe, state->options, j), MDL)) { struct in_addr ia; struct hostent *h; memcpy (&ia, lease -> ip_addr.iabuf, 4); h = gethostbyaddr ((char *)&ia, sizeof ia, AF_INET); if (!h) log_error ("No hostname for %s", inet_ntoa (ia)); else { oc = (struct option_cache *)0; if (option_cache_allocate (&oc, MDL)) { if (make_const_data (&oc -> expression, ((unsigned char *) h -> h_name), strlen (h -> h_name) + 1, 1, 1, MDL)) { option_code_hash_lookup(&oc->option, dhcp_universe.code_hash, &i, 0, MDL); save_option (&dhcp_universe, state -> options, oc); } option_cache_dereference (&oc, MDL); } } } /* If so directed, use the leased IP address as the router address. This supposedly makes Win95 machines ARP for all IP addresses, so if the local router does proxy arp, you win. */ if (evaluate_boolean_option_cache (&ignorep, packet, lease, (struct client_state *)0, packet -> options, state -> options, &lease -> scope, lookup_option (&server_universe, state -> options, SV_USE_LEASE_ADDR_FOR_DEFAULT_ROUTE), MDL)) { i = DHO_ROUTERS; oc = lookup_option (&dhcp_universe, state -> options, i); if (!oc) { oc = (struct option_cache *)0; if (option_cache_allocate (&oc, MDL)) { if (make_const_data (&oc -> expression, lease -> ip_addr.iabuf, lease -> ip_addr.len, 0, 0, MDL)) { option_code_hash_lookup(&oc->option, dhcp_universe.code_hash, &i, 0, MDL); save_option (&dhcp_universe, state -> options, oc); } option_cache_dereference (&oc, MDL); } } } /* If a site option space has been specified, use that for site option codes. */ i = SV_SITE_OPTION_SPACE; if ((oc = lookup_option (&server_universe, state -> options, i)) && evaluate_option_cache (&d1, packet, lease, (struct client_state *)0, packet -> options, state -> options, &lease -> scope, oc, MDL)) { struct universe *u = (struct universe *)0; if (!universe_hash_lookup (&u, universe_hash, (const char *)d1.data, d1.len, MDL)) { log_error ("unknown option space %s.", d1.data); return; } state -> options -> site_universe = u -> index; state->options->site_code_min = find_min_site_code(u); data_string_forget (&d1, MDL); } else { state -> options -> site_code_min = 0; state -> options -> site_universe = dhcp_universe.index; } /* If the client has provided a list of options that it wishes returned, use it to prioritize. If there's a parameter request list in scope, use that in preference. Otherwise use the default priority list. */ oc = lookup_option (&dhcp_universe, state -> options, DHO_DHCP_PARAMETER_REQUEST_LIST); if (!oc) oc = lookup_option (&dhcp_universe, packet -> options, DHO_DHCP_PARAMETER_REQUEST_LIST); if (oc) evaluate_option_cache (&state -> parameter_request_list, packet, lease, (struct client_state *)0, packet -> options, state -> options, &lease -> scope, oc, MDL); #ifdef DEBUG_PACKET dump_packet (packet); dump_raw ((unsigned char *)packet -> raw, packet -> packet_length); #endif lease -> state = state; log_info ("%s", msg); /* Hang the packet off the lease state. */ packet_reference (&lease -> state -> packet, packet, MDL); /* If this is a DHCPOFFER, ping the lease address before actually sending the offer. */ if (offer == DHCPOFFER && !(lease -> flags & STATIC_LEASE) && ((cur_time - lease_cltt) > 60) && (!(oc = lookup_option (&server_universe, state -> options, SV_PING_CHECKS)) || evaluate_boolean_option_cache (&ignorep, packet, lease, (struct client_state *)0, packet -> options, state -> options, &lease -> scope, oc, MDL))) { icmp_echorequest (&lease -> ip_addr); /* Determine whether to use configured or default ping timeout. */ if ((oc = lookup_option (&server_universe, state -> options, SV_PING_TIMEOUT)) && evaluate_option_cache (&d1, packet, lease, NULL, packet -> options, state -> options, &lease -> scope, oc, MDL)) { if (d1.len == sizeof (u_int32_t)) ping_timeout = getULong (d1.data); else ping_timeout = DEFAULT_PING_TIMEOUT; data_string_forget (&d1, MDL); } else ping_timeout = DEFAULT_PING_TIMEOUT; #ifdef DEBUG log_debug ("Ping timeout: %ld", (long)ping_timeout); #endif /* * Set a timeout for 'ping-timeout' seconds from NOW, including * current microseconds. As ping-timeout defaults to 1, the * exclusion of current microseconds causes a value somewhere * /between/ zero and one. */ tv.tv_sec = cur_tv.tv_sec + ping_timeout; tv.tv_usec = cur_tv.tv_usec; add_timeout (&tv, lease_ping_timeout, lease, (tvref_t)lease_reference, (tvunref_t)lease_dereference); ++outstanding_pings; } else { lease->cltt = cur_time; #if defined(DELAYED_ACK) if (!(lease->flags & STATIC_LEASE) && (!offer || (offer == DHCPACK))) delayed_ack_enqueue(lease); else #endif dhcp_reply(lease); } } /* * CC: queue single ACK: * - write the lease (but do not fsync it yet) * - add to double linked list * - commit if more than xx ACKs pending * - if necessary set the max timer and bump the next timer * but only up to the max timer value. */ void delayed_ack_enqueue(struct lease *lease) { struct leasequeue *q; if (!write_lease(lease)) return; if (free_ackqueue) { q = free_ackqueue; free_ackqueue = q->next; } else { q = ((struct leasequeue *) dmalloc(sizeof(struct leasequeue), MDL)); if (!q) log_fatal("delayed_ack_enqueue: no memory!"); } memset(q, 0, sizeof *q); /* prepend to ackqueue*/ lease_reference(&q->lease, lease, MDL); q->next = ackqueue_head; ackqueue_head = q; if (!ackqueue_tail) ackqueue_tail = q; else q->next->prev = q; outstanding_acks++; if (outstanding_acks > max_outstanding_acks) { commit_leases(); /* Reset max_fsync and cancel any pending timeout. */ memset(&max_fsync, 0, sizeof(max_fsync)); cancel_timeout(commit_leases_ackout, NULL); } else { struct timeval next_fsync; if (max_fsync.tv_sec == 0 && max_fsync.tv_usec == 0) { /* set the maximum time we'll wait */ max_fsync.tv_sec = cur_tv.tv_sec + max_ack_delay_secs; max_fsync.tv_usec = cur_tv.tv_usec + max_ack_delay_usecs; if (max_fsync.tv_usec >= 1000000) { max_fsync.tv_sec++; max_fsync.tv_usec -= 1000000; } } /* Set the timeout */ next_fsync.tv_sec = cur_tv.tv_sec; next_fsync.tv_usec = cur_tv.tv_usec + min_ack_delay_usecs; if (next_fsync.tv_usec >= 1000000) { next_fsync.tv_sec++; next_fsync.tv_usec -= 1000000; } /* but not more than the max */ if ((next_fsync.tv_sec > max_fsync.tv_sec) || ((next_fsync.tv_sec == max_fsync.tv_sec) && (next_fsync.tv_usec > max_fsync.tv_usec))) { next_fsync.tv_sec = max_fsync.tv_sec; next_fsync.tv_usec = max_fsync.tv_usec; } add_timeout(&next_fsync, commit_leases_ackout, NULL, (tvref_t) NULL, (tvunref_t) NULL); } } static void commit_leases_ackout(void *foo) { if (outstanding_acks) { commit_leases(); memset(&max_fsync, 0, sizeof(max_fsync)); } } /* CC: process the delayed ACK responses: - send out the ACK packets - move the queue slots to the free list */ void flush_ackqueue(void *foo) { struct leasequeue *ack, *p; /* process from bottom to retain packet order */ for (ack = ackqueue_tail ; ack ; ack = p) { p = ack->prev; /* dhcp_reply() requires that the reply state still be valid */ if (ack->lease->state == NULL) log_error("delayed ack for %s has gone stale", piaddr(ack->lease->ip_addr)); else dhcp_reply(ack->lease); lease_dereference(&ack->lease, MDL); ack->next = free_ackqueue; free_ackqueue = ack; } ackqueue_head = NULL; ackqueue_tail = NULL; outstanding_acks = 0; } #if defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT) void relinquish_ackqueue(void) { struct leasequeue *q, *n; for (q = ackqueue_head ; q ; q = n) { n = q->next; dfree(q, MDL); } for (q = free_ackqueue ; q ; q = n) { n = q->next; dfree(q, MDL); } } #endif void dhcp_reply (lease) struct lease *lease; { int bufs = 0; unsigned packet_length; struct dhcp_packet raw; struct sockaddr_in to; struct in_addr from; struct hardware hto; int result; struct lease_state *state = lease -> state; int nulltp, bootpp, unicastp = 1; struct data_string d1; const char *s; if (!state) log_fatal ("dhcp_reply was supplied lease with no state!"); /* Compose a response for the client... */ memset (&raw, 0, sizeof raw); memset (&d1, 0, sizeof d1); /* Copy in the filename if given; otherwise, flag the filename buffer as available for options. */ if (state -> filename.len && state -> filename.data) { memcpy (raw.file, state -> filename.data, state -> filename.len > sizeof raw.file ? sizeof raw.file : state -> filename.len); if (sizeof raw.file > state -> filename.len) memset (&raw.file [state -> filename.len], 0, (sizeof raw.file) - state -> filename.len); else log_info("file name longer than packet field " "truncated - field: %lu name: %d %.*s", (unsigned long)sizeof(raw.file), state->filename.len, state->filename.len, state->filename.data); } else bufs |= 1; /* Copy in the server name if given; otherwise, flag the server_name buffer as available for options. */ if (state -> server_name.len && state -> server_name.data) { memcpy (raw.sname, state -> server_name.data, state -> server_name.len > sizeof raw.sname ? sizeof raw.sname : state -> server_name.len); if (sizeof raw.sname > state -> server_name.len) memset (&raw.sname [state -> server_name.len], 0, (sizeof raw.sname) - state -> server_name.len); else log_info("server name longer than packet field " "truncated - field: %lu name: %d %.*s", (unsigned long)sizeof(raw.sname), state->server_name.len, state->server_name.len, state->server_name.data); } else bufs |= 2; /* XXX */ memcpy (raw.chaddr, &lease -> hardware_addr.hbuf [1], sizeof raw.chaddr); raw.hlen = lease -> hardware_addr.hlen - 1; raw.htype = lease -> hardware_addr.hbuf [0]; /* See if this is a Microsoft client that NUL-terminates its strings and expects us to do likewise... */ if (lease -> flags & MS_NULL_TERMINATION) nulltp = 1; else nulltp = 0; /* See if this is a bootp client... */ if (state -> offer) bootpp = 0; else bootpp = 1; /* Insert such options as will fit into the buffer. */ packet_length = cons_options (state -> packet, &raw, lease, (struct client_state *)0, state -> max_message_size, state -> packet -> options, state -> options, &global_scope, bufs, nulltp, bootpp, &state -> parameter_request_list, (char *)0); memcpy (&raw.ciaddr, &state -> ciaddr, sizeof raw.ciaddr); memcpy (&raw.yiaddr, lease -> ip_addr.iabuf, 4); raw.siaddr = state -> siaddr; raw.giaddr = state -> giaddr; raw.xid = state -> xid; raw.secs = state -> secs; raw.flags = state -> bootp_flags; raw.hops = state -> hops; raw.op = BOOTREPLY; if (lease -> client_hostname) { if ((strlen (lease -> client_hostname) <= 64) && db_printable((unsigned char *)lease->client_hostname)) s = lease -> client_hostname; else s = "Hostname Unsuitable for Printing"; } else s = (char *)0; /* Say what we're doing... */ log_info ("%s on %s to %s %s%s%svia %s", (state -> offer ? (state -> offer == DHCPACK ? "DHCPACK" : "DHCPOFFER") : "BOOTREPLY"), piaddr (lease -> ip_addr), (lease -> hardware_addr.hlen ? print_hw_addr (lease -> hardware_addr.hbuf [0], lease -> hardware_addr.hlen - 1, &lease -> hardware_addr.hbuf [1]) : print_hex_1(lease->uid_len, lease->uid, 60)), s ? "(" : "", s ? s : "", s ? ") " : "", (state -> giaddr.s_addr ? inet_ntoa (state -> giaddr) : state -> ip -> name)); /* Set up the hardware address... */ hto.hlen = lease -> hardware_addr.hlen; memcpy (hto.hbuf, lease -> hardware_addr.hbuf, hto.hlen); to.sin_family = AF_INET; #ifdef HAVE_SA_LEN to.sin_len = sizeof to; #endif memset (to.sin_zero, 0, sizeof to.sin_zero); #ifdef DEBUG_PACKET dump_raw ((unsigned char *)&raw, packet_length); #endif /* Make sure outgoing packets are at least as big as a BOOTP packet. */ if (packet_length < BOOTP_MIN_LEN) packet_length = BOOTP_MIN_LEN; /* If this was gatewayed, send it back to the gateway... */ if (raw.giaddr.s_addr) { to.sin_addr = raw.giaddr; if (raw.giaddr.s_addr != htonl (INADDR_LOOPBACK)) to.sin_port = local_port; else to.sin_port = remote_port; /* For debugging. */ if (fallback_interface) { result = send_packet(fallback_interface, NULL, &raw, packet_length, raw.siaddr, &to, NULL); if (result < 0) { log_error ("%s:%d: Failed to send %d byte long " "packet over %s interface.", MDL, packet_length, fallback_interface->name); } free_lease_state (state, MDL); lease -> state = (struct lease_state *)0; return; } /* If the client is RENEWING, unicast to the client using the regular IP stack. Some clients, particularly those that follow RFC1541, are buggy, and send both ciaddr and server identifier. We deal with this situation by assuming that if we got both dhcp-server-identifier and ciaddr, and giaddr was not set, then the client is on the local network, and we can therefore unicast or broadcast to it successfully. A client in REQUESTING state on another network that's making this mistake will have set giaddr, and will therefore get a relayed response from the above code. */ } else if (raw.ciaddr.s_addr && !((state -> got_server_identifier || (raw.flags & htons (BOOTP_BROADCAST))) && /* XXX This won't work if giaddr isn't zero, but it is: */ (state -> shared_network == lease -> subnet -> shared_network)) && state -> offer == DHCPACK) { to.sin_addr = raw.ciaddr; to.sin_port = remote_port; if (fallback_interface) { result = send_packet(fallback_interface, NULL, &raw, packet_length, raw.siaddr, &to, NULL); if (result < 0) { log_error("%s:%d: Failed to send %d byte long" " packet over %s interface.", MDL, packet_length, fallback_interface->name); } free_lease_state (state, MDL); lease -> state = (struct lease_state *)0; return; } /* If it comes from a client that already knows its address and is not requesting a broadcast response, and we can unicast to a client without using the ARP protocol, sent it directly to that client. */ } else if (!(raw.flags & htons (BOOTP_BROADCAST)) && can_unicast_without_arp (state -> ip)) { to.sin_addr = raw.yiaddr; to.sin_port = remote_port; /* Otherwise, broadcast it on the local network. */ } else { to.sin_addr = limited_broadcast; to.sin_port = remote_port; if (!(lease -> flags & UNICAST_BROADCAST_HACK)) unicastp = 0; } memcpy (&from, state -> from.iabuf, sizeof from); result = send_packet(state->ip, NULL, &raw, packet_length, from, &to, unicastp ? &hto : NULL); if (result < 0) { log_error ("%s:%d: Failed to send %d byte long " "packet over %s interface.", MDL, packet_length, state->ip->name); } /* Free all of the entries in the option_state structure now that we're done with them. */ free_lease_state (state, MDL); lease -> state = (struct lease_state *)0; } int find_lease (struct lease **lp, struct packet *packet, struct shared_network *share, int *ours, int *peer_has_leases, struct lease *ip_lease_in, const char *file, int line) { struct lease *uid_lease = (struct lease *)0; struct lease *ip_lease = (struct lease *)0; struct lease *hw_lease = (struct lease *)0; struct lease *lease = (struct lease *)0; struct iaddr cip; struct host_decl *hp = (struct host_decl *)0; struct host_decl *host = (struct host_decl *)0; struct lease *fixed_lease = (struct lease *)0; struct lease *next = (struct lease *)0; struct option_cache *oc; struct data_string d1; int have_client_identifier = 0; struct data_string client_identifier; struct hardware h; #if defined(FAILOVER_PROTOCOL) /* Quick check to see if the peer has leases. */ if (peer_has_leases) { struct pool *pool; for (pool = share->pools ; pool ; pool = pool->next) { dhcp_failover_state_t *peer = pool->failover_peer; if (peer && ((peer->i_am == primary && pool->backup_leases) || (peer->i_am == secondary && pool->free_leases))) { *peer_has_leases = 1; break; } } } #endif /* FAILOVER_PROTOCOL */ if (packet -> raw -> ciaddr.s_addr) { cip.len = 4; memcpy (cip.iabuf, &packet -> raw -> ciaddr, 4); } else { /* Look up the requested address. */ oc = lookup_option (&dhcp_universe, packet -> options, DHO_DHCP_REQUESTED_ADDRESS); memset (&d1, 0, sizeof d1); if (oc && evaluate_option_cache (&d1, packet, (struct lease *)0, (struct client_state *)0, packet -> options, (struct option_state *)0, &global_scope, oc, MDL)) { packet -> got_requested_address = 1; cip.len = 4; memcpy (cip.iabuf, d1.data, cip.len); data_string_forget (&d1, MDL); } else cip.len = 0; } /* Try to find a host or lease that's been assigned to the specified unique client identifier. */ oc = lookup_option (&dhcp_universe, packet -> options, DHO_DHCP_CLIENT_IDENTIFIER); memset (&client_identifier, 0, sizeof client_identifier); if (oc && evaluate_option_cache (&client_identifier, packet, (struct lease *)0, (struct client_state *)0, packet -> options, (struct option_state *)0, &global_scope, oc, MDL)) { /* Remember this for later. */ have_client_identifier = 1; /* First, try to find a fixed host entry for the specified client identifier... */ if (find_hosts_by_uid (&hp, client_identifier.data, client_identifier.len, MDL)) { /* Remember if we know of this client. */ packet -> known = 1; mockup_lease (&fixed_lease, packet, share, hp); } #if defined (DEBUG_FIND_LEASE) if (fixed_lease) { log_info ("Found host for client identifier: %s.", piaddr (fixed_lease -> ip_addr)); } #endif if (hp) { if (!fixed_lease) /* Save the host if we found one. */ host_reference (&host, hp, MDL); host_dereference (&hp, MDL); } find_lease_by_uid (&uid_lease, client_identifier.data, client_identifier.len, MDL); } /* If we didn't find a fixed lease using the uid, try doing it with the hardware address... */ if (!fixed_lease && !host) { if (find_hosts_by_haddr (&hp, packet -> raw -> htype, packet -> raw -> chaddr, packet -> raw -> hlen, MDL)) { /* Remember if we know of this client. */ packet -> known = 1; if (host) host_dereference (&host, MDL); host_reference (&host, hp, MDL); host_dereference (&hp, MDL); mockup_lease (&fixed_lease, packet, share, host); #if defined (DEBUG_FIND_LEASE) if (fixed_lease) { log_info ("Found host for link address: %s.", piaddr (fixed_lease -> ip_addr)); } #endif } } /* Finally, if we haven't found anything yet try again with the * host-identifier option ... */ if (!fixed_lease && !host) { if (find_hosts_by_option(&hp, packet, packet->options, MDL) == 1) { packet->known = 1; if (host) host_dereference(&host, MDL); host_reference(&host, hp, MDL); host_dereference(&hp, MDL); mockup_lease (&fixed_lease, packet, share, host); #if defined (DEBUG_FIND_LEASE) if (fixed_lease) { log_info ("Found host via host-identifier"); } #endif } } /* If fixed_lease is present but does not match the requested IP address, and this is a DHCPREQUEST, then we can't return any other lease, so we might as well return now. */ if (packet -> packet_type == DHCPREQUEST && fixed_lease && (fixed_lease -> ip_addr.len != cip.len || memcmp (fixed_lease -> ip_addr.iabuf, cip.iabuf, cip.len))) { if (ours) *ours = 1; strcpy (dhcp_message, "requested address is incorrect"); #if defined (DEBUG_FIND_LEASE) log_info ("Client's fixed-address %s doesn't match %s%s", piaddr (fixed_lease -> ip_addr), "request ", print_dotted_quads (cip.len, cip.iabuf)); #endif goto out; } /* * If we found leases matching the client identifier, loop through * the n_uid pointer looking for one that's actually valid. We * can't do this until we get here because we depend on * packet -> known, which may be set by either the uid host * lookup or the haddr host lookup. * * Note that the n_uid lease chain is sorted in order of * preference, so the first one is the best one. */ while (uid_lease) { #if defined (DEBUG_FIND_LEASE) log_info ("trying next lease matching client id: %s", piaddr (uid_lease -> ip_addr)); #endif #if defined (FAILOVER_PROTOCOL) /* * When we lookup a lease by uid, we know the client identifier * matches the lease's record. If it is active, or was last * active with the same client, we can trivially extend it. * If is not or was not active, we can allocate it to this * client if it matches the usual free/backup criteria (which * is contained in lease_mine_to_reallocate()). */ if (uid_lease->binding_state != FTS_ACTIVE && uid_lease->rewind_binding_state != FTS_ACTIVE && !lease_mine_to_reallocate(uid_lease)) { #if defined (DEBUG_FIND_LEASE) log_info("not active or not mine to allocate: %s", piaddr(uid_lease->ip_addr)); #endif goto n_uid; } #endif if (uid_lease -> subnet -> shared_network != share) { #if defined (DEBUG_FIND_LEASE) log_info ("wrong network segment: %s", piaddr (uid_lease -> ip_addr)); #endif goto n_uid; } if ((uid_lease -> pool -> prohibit_list && permitted (packet, uid_lease -> pool -> prohibit_list)) || (uid_lease -> pool -> permit_list && !permitted (packet, uid_lease -> pool -> permit_list))) { #if defined (DEBUG_FIND_LEASE) log_info ("not permitted: %s", piaddr (uid_lease -> ip_addr)); #endif n_uid: if (uid_lease -> n_uid) lease_reference (&next, uid_lease -> n_uid, MDL); if (!packet -> raw -> ciaddr.s_addr) release_lease (uid_lease, packet); lease_dereference (&uid_lease, MDL); if (next) { lease_reference (&uid_lease, next, MDL); lease_dereference (&next, MDL); } continue; } break; } #if defined (DEBUG_FIND_LEASE) if (uid_lease) log_info ("Found lease for client id: %s.", piaddr (uid_lease -> ip_addr)); #endif /* Find a lease whose hardware address matches, whose client * identifier matches (or equally doesn't have one), that's * permitted, and that's on the correct subnet. * * Note that the n_hw chain is sorted in order of preference, so * the first one found is the best one. */ h.hlen = packet -> raw -> hlen + 1; h.hbuf [0] = packet -> raw -> htype; memcpy (&h.hbuf [1], packet -> raw -> chaddr, packet -> raw -> hlen); find_lease_by_hw_addr (&hw_lease, h.hbuf, h.hlen, MDL); while (hw_lease) { #if defined (DEBUG_FIND_LEASE) log_info ("trying next lease matching hw addr: %s", piaddr (hw_lease -> ip_addr)); #endif #if defined (FAILOVER_PROTOCOL) /* * When we lookup a lease by chaddr, we know the MAC address * matches the lease record (we will check if the lease has a * client-id the client does not next). If the lease is * currently active or was last active with this client, we can * trivially extend it. Otherwise, there are a set of rules * that govern if we can reallocate this lease to any client * ("lease_mine_to_reallocate()") including this one. */ if (hw_lease->binding_state != FTS_ACTIVE && hw_lease->rewind_binding_state != FTS_ACTIVE && !lease_mine_to_reallocate(hw_lease)) { #if defined (DEBUG_FIND_LEASE) log_info("not active or not mine to allocate: %s", piaddr(hw_lease->ip_addr)); #endif goto n_hw; } #endif /* * This conditional skips "potentially active" leases (leases * we think are expired may be extended by the peer, etc) that * may be assigned to a differently /client-identified/ client * with the same MAC address. */ if (hw_lease -> binding_state != FTS_FREE && hw_lease -> binding_state != FTS_BACKUP && hw_lease -> uid && (!have_client_identifier || hw_lease -> uid_len != client_identifier.len || memcmp (hw_lease -> uid, client_identifier.data, hw_lease -> uid_len))) { #if defined (DEBUG_FIND_LEASE) log_info ("wrong client identifier: %s", piaddr (hw_lease -> ip_addr)); #endif goto n_hw; } if (hw_lease -> subnet -> shared_network != share) { #if defined (DEBUG_FIND_LEASE) log_info ("wrong network segment: %s", piaddr (hw_lease -> ip_addr)); #endif goto n_hw; } if ((hw_lease -> pool -> prohibit_list && permitted (packet, hw_lease -> pool -> prohibit_list)) || (hw_lease -> pool -> permit_list && !permitted (packet, hw_lease -> pool -> permit_list))) { #if defined (DEBUG_FIND_LEASE) log_info ("not permitted: %s", piaddr (hw_lease -> ip_addr)); #endif if (!packet -> raw -> ciaddr.s_addr) release_lease (hw_lease, packet); n_hw: if (hw_lease -> n_hw) lease_reference (&next, hw_lease -> n_hw, MDL); lease_dereference (&hw_lease, MDL); if (next) { lease_reference (&hw_lease, next, MDL); lease_dereference (&next, MDL); } continue; } break; } #if defined (DEBUG_FIND_LEASE) if (hw_lease) log_info ("Found lease for hardware address: %s.", piaddr (hw_lease -> ip_addr)); #endif /* Try to find a lease that's been allocated to the client's IP address. */ if (ip_lease_in) lease_reference (&ip_lease, ip_lease_in, MDL); else if (cip.len) find_lease_by_ip_addr (&ip_lease, cip, MDL); #if defined (DEBUG_FIND_LEASE) if (ip_lease) log_info ("Found lease for requested address: %s.", piaddr (ip_lease -> ip_addr)); #endif /* If ip_lease is valid at this point, set ours to one, so that even if we choose a different lease, we know that the address the client was requesting was ours, and thus we can NAK it. */ if (ip_lease && ours) *ours = 1; /* If the requested IP address isn't on the network the packet came from, don't use it. Allow abandoned leases to be matched here - if the client is requesting it, there's a decent chance that it's because the lease database got trashed and a client that thought it had this lease answered an ARP or PING, causing the lease to be abandoned. If so, this request probably came from that client. */ if (ip_lease && (ip_lease -> subnet -> shared_network != share)) { if (ours) *ours = 1; #if defined (DEBUG_FIND_LEASE) log_info ("...but it was on the wrong shared network."); #endif strcpy (dhcp_message, "requested address on bad subnet"); lease_dereference (&ip_lease, MDL); } /* * If the requested address is in use (or potentially in use) by * a different client, it can't be granted. * * This first conditional only detects if the lease is currently * identified to a different client (client-id and/or chaddr * mismatch). In this case we may not want to give the client the * lease, if doing so may potentially be an addressing conflict. */ if (ip_lease && (ip_lease -> uid ? (!have_client_identifier || ip_lease -> uid_len != client_identifier.len || memcmp (ip_lease -> uid, client_identifier.data, ip_lease -> uid_len)) : (ip_lease -> hardware_addr.hbuf [0] != packet -> raw -> htype || ip_lease -> hardware_addr.hlen != packet -> raw -> hlen + 1 || memcmp (&ip_lease -> hardware_addr.hbuf [1], packet -> raw -> chaddr, (unsigned)(ip_lease -> hardware_addr.hlen - 1))))) { /* * A lease is unavailable for allocation to a new client if * it is not in the FREE or BACKUP state. There may be * leases that are in the expired state with a rewinding * state that is free or backup, but these will be processed * into the free or backup states by expiration processes, so * checking for them here is superfluous. */ if (ip_lease -> binding_state != FTS_FREE && ip_lease -> binding_state != FTS_BACKUP) { #if defined (DEBUG_FIND_LEASE) log_info ("rejecting lease for requested address."); #endif /* If we're rejecting it because the peer has it, don't set "ours", because we shouldn't NAK. */ if (ours && ip_lease -> binding_state != FTS_ACTIVE) *ours = 0; lease_dereference (&ip_lease, MDL); } } /* * If we got an ip_lease and a uid_lease or hw_lease, and ip_lease * is/was not active, and is not ours to reallocate, forget about it. */ if (ip_lease && (uid_lease || hw_lease) && ip_lease->binding_state != FTS_ACTIVE && ip_lease->rewind_binding_state != FTS_ACTIVE && #if defined(FAILOVER_PROTOCOL) !lease_mine_to_reallocate(ip_lease) && #endif packet->packet_type == DHCPDISCOVER) { #if defined (DEBUG_FIND_LEASE) log_info("ip lease not active or not ours to offer."); #endif lease_dereference(&ip_lease, MDL); } /* If for some reason the client has more than one lease on the subnet that matches its uid, pick the one that it asked for and (if we can) free the other. */ if (ip_lease && ip_lease->binding_state == FTS_ACTIVE && ip_lease->uid && ip_lease != uid_lease) { if (have_client_identifier && (ip_lease -> uid_len == client_identifier.len) && !memcmp (client_identifier.data, ip_lease -> uid, ip_lease -> uid_len)) { if (uid_lease) { if (uid_lease->binding_state == FTS_ACTIVE) { log_error ("client %s has duplicate%s on %s", (print_hw_addr (packet -> raw -> htype, packet -> raw -> hlen, packet -> raw -> chaddr)), " leases", (ip_lease -> subnet -> shared_network -> name)); /* If the client is REQUESTing the lease, it shouldn't still be using the old one, so we can free it for allocation. */ if (uid_lease && uid_lease->binding_state == FTS_ACTIVE && !packet -> raw -> ciaddr.s_addr && (share == uid_lease -> subnet -> shared_network) && packet -> packet_type == DHCPREQUEST) release_lease (uid_lease, packet); } lease_dereference (&uid_lease, MDL); lease_reference (&uid_lease, ip_lease, MDL); } } /* If we get to here and fixed_lease is not null, that means that there are both a dynamic lease and a fixed-address declaration for the same IP address. */ if (packet -> packet_type == DHCPREQUEST && fixed_lease) { lease_dereference (&fixed_lease, MDL); db_conflict: log_error ("Dynamic and static leases present for %s.", piaddr (cip)); log_error ("Remove host declaration %s or remove %s", (fixed_lease && fixed_lease -> host ? (fixed_lease -> host -> name ? fixed_lease -> host -> name : piaddr (cip)) : piaddr (cip)), piaddr (cip)); log_error ("from the dynamic address pool for %s", ip_lease -> subnet -> shared_network -> name ); if (fixed_lease) lease_dereference (&ip_lease, MDL); strcpy (dhcp_message, "database conflict - call for help!"); } if (ip_lease && ip_lease != uid_lease) { #if defined (DEBUG_FIND_LEASE) log_info ("requested address not available."); #endif lease_dereference (&ip_lease, MDL); } } /* If we get to here with both fixed_lease and ip_lease not null, then we have a configuration file bug. */ if (packet -> packet_type == DHCPREQUEST && fixed_lease && ip_lease) goto db_conflict; /* Toss extra pointers to the same lease... */ if (hw_lease && hw_lease == uid_lease) { #if defined (DEBUG_FIND_LEASE) log_info ("hardware lease and uid lease are identical."); #endif lease_dereference (&hw_lease, MDL); } if (ip_lease && ip_lease == hw_lease) { lease_dereference (&hw_lease, MDL); #if defined (DEBUG_FIND_LEASE) log_info ("hardware lease and ip lease are identical."); #endif } if (ip_lease && ip_lease == uid_lease) { lease_dereference (&uid_lease, MDL); #if defined (DEBUG_FIND_LEASE) log_info ("uid lease and ip lease are identical."); #endif } /* Make sure the client is permitted to use the requested lease. */ if (ip_lease && ((ip_lease -> pool -> prohibit_list && permitted (packet, ip_lease -> pool -> prohibit_list)) || (ip_lease -> pool -> permit_list && !permitted (packet, ip_lease -> pool -> permit_list)))) { if (!packet->raw->ciaddr.s_addr && (ip_lease->binding_state == FTS_ACTIVE)) release_lease (ip_lease, packet); lease_dereference (&ip_lease, MDL); } if (uid_lease && ((uid_lease -> pool -> prohibit_list && permitted (packet, uid_lease -> pool -> prohibit_list)) || (uid_lease -> pool -> permit_list && !permitted (packet, uid_lease -> pool -> permit_list)))) { if (!packet -> raw -> ciaddr.s_addr) release_lease (uid_lease, packet); lease_dereference (&uid_lease, MDL); } if (hw_lease && ((hw_lease -> pool -> prohibit_list && permitted (packet, hw_lease -> pool -> prohibit_list)) || (hw_lease -> pool -> permit_list && !permitted (packet, hw_lease -> pool -> permit_list)))) { if (!packet -> raw -> ciaddr.s_addr) release_lease (hw_lease, packet); lease_dereference (&hw_lease, MDL); } /* If we've already eliminated the lease, it wasn't there to begin with. If we have come up with a matching lease, set the message to bad network in case we have to throw it out. */ if (!ip_lease) { strcpy (dhcp_message, "requested address not available"); } /* If this is a DHCPREQUEST, make sure the lease we're going to return matches the requested IP address. If it doesn't, don't return a lease at all. */ if (packet -> packet_type == DHCPREQUEST && !ip_lease && !fixed_lease) { #if defined (DEBUG_FIND_LEASE) log_info ("no applicable lease found for DHCPREQUEST."); #endif goto out; } /* At this point, if fixed_lease is nonzero, we can assign it to this client. */ if (fixed_lease) { lease_reference (&lease, fixed_lease, MDL); lease_dereference (&fixed_lease, MDL); #if defined (DEBUG_FIND_LEASE) log_info ("choosing fixed address."); #endif } /* If we got a lease that matched the ip address and don't have a better offer, use that; otherwise, release it. */ if (ip_lease) { if (lease) { if (!packet -> raw -> ciaddr.s_addr) release_lease (ip_lease, packet); #if defined (DEBUG_FIND_LEASE) log_info ("not choosing requested address (!)."); #endif } else { #if defined (DEBUG_FIND_LEASE) log_info ("choosing lease on requested address."); #endif lease_reference (&lease, ip_lease, MDL); if (lease -> host) host_dereference (&lease -> host, MDL); } lease_dereference (&ip_lease, MDL); } /* If we got a lease that matched the client identifier, we may want to use it, but if we already have a lease we like, we must free the lease that matched the client identifier. */ if (uid_lease) { if (lease) { log_error("uid lease %s for client %s is duplicate " "on %s", piaddr(uid_lease->ip_addr), print_hw_addr(packet->raw->htype, packet->raw->hlen, packet->raw->chaddr), uid_lease->subnet->shared_network->name); if (!packet -> raw -> ciaddr.s_addr && packet -> packet_type == DHCPREQUEST && uid_lease -> binding_state == FTS_ACTIVE) release_lease(uid_lease, packet); #if defined (DEBUG_FIND_LEASE) log_info ("not choosing uid lease."); #endif } else { lease_reference (&lease, uid_lease, MDL); if (lease -> host) host_dereference (&lease -> host, MDL); #if defined (DEBUG_FIND_LEASE) log_info ("choosing uid lease."); #endif } lease_dereference (&uid_lease, MDL); } /* The lease that matched the hardware address is treated likewise. */ if (hw_lease) { if (lease) { #if defined (DEBUG_FIND_LEASE) log_info ("not choosing hardware lease."); #endif } else { /* We're a little lax here - if the client didn't send a client identifier and it's a bootp client, but the lease has a client identifier, we still let the client have a lease. */ if (!hw_lease -> uid_len || (have_client_identifier ? (hw_lease -> uid_len == client_identifier.len && !memcmp (hw_lease -> uid, client_identifier.data, client_identifier.len)) : packet -> packet_type == 0)) { lease_reference (&lease, hw_lease, MDL); if (lease -> host) host_dereference (&lease -> host, MDL); #if defined (DEBUG_FIND_LEASE) log_info ("choosing hardware lease."); #endif } else { #if defined (DEBUG_FIND_LEASE) log_info ("not choosing hardware lease: %s.", "uid mismatch"); #endif } } lease_dereference (&hw_lease, MDL); } /* * If we found a host_decl but no matching address, try to * find a host_decl that has no address, and if there is one, * hang it off the lease so that we can use the supplied * options. */ if (lease && host && !lease->host) { struct host_decl *p = NULL; struct host_decl *n = NULL; host_reference(&p, host, MDL); while (p != NULL) { if (!p->fixed_addr) { /* * If the lease is currently active, then it * must be allocated to the present client. * We store a reference to the host record on * the lease to save a lookup later (in * ack_lease()). We mustn't refer to the host * record on non-active leases because the * client may be denied later. * * XXX: Not having this reference (such as in * DHCPDISCOVER/INIT) means ack_lease will have * to perform this lookup a second time. This * hopefully isn't a problem as DHCPREQUEST is * more common than DHCPDISCOVER. */ if (lease->binding_state == FTS_ACTIVE) host_reference(&lease->host, p, MDL); host_dereference(&p, MDL); break; } if (p->n_ipaddr != NULL) host_reference(&n, p->n_ipaddr, MDL); host_dereference(&p, MDL); if (n != NULL) { host_reference(&p, n, MDL); host_dereference(&n, MDL); } } } /* If we find an abandoned lease, but it's the one the client requested, we assume that previous bugginess on the part of the client, or a server database loss, caused the lease to be abandoned, so we reclaim it and let the client have it. */ if (lease && (lease -> binding_state == FTS_ABANDONED) && lease == ip_lease && packet -> packet_type == DHCPREQUEST) { log_error ("Reclaiming REQUESTed abandoned IP address %s.", piaddr (lease -> ip_addr)); } else if (lease && (lease -> binding_state == FTS_ABANDONED)) { /* Otherwise, if it's not the one the client requested, we do not return it - instead, we claim it's ours, causing a DHCPNAK to be sent if this lookup is for a DHCPREQUEST, and force the client to go back through the allocation process. */ if (ours) *ours = 1; lease_dereference (&lease, MDL); } out: if (have_client_identifier) data_string_forget (&client_identifier, MDL); if (fixed_lease) lease_dereference (&fixed_lease, MDL); if (hw_lease) lease_dereference (&hw_lease, MDL); if (uid_lease) lease_dereference (&uid_lease, MDL); if (ip_lease) lease_dereference (&ip_lease, MDL); if (host) host_dereference (&host, MDL); if (lease) { #if defined (DEBUG_FIND_LEASE) log_info ("Returning lease: %s.", piaddr (lease -> ip_addr)); #endif lease_reference (lp, lease, file, line); lease_dereference (&lease, MDL); return 1; } #if defined (DEBUG_FIND_LEASE) log_info ("Not returning a lease."); #endif return 0; } /* Search the provided host_decl structure list for an address that's on the specified shared network. If one is found, mock up and return a lease structure for it; otherwise return the null pointer. */ int mockup_lease (struct lease **lp, struct packet *packet, struct shared_network *share, struct host_decl *hp) { struct lease *lease = (struct lease *)0; struct host_decl *rhp = (struct host_decl *)0; if (lease_allocate (&lease, MDL) != ISC_R_SUCCESS) return 0; if (host_reference (&rhp, hp, MDL) != ISC_R_SUCCESS) { lease_dereference (&lease, MDL); return 0; } if (!find_host_for_network (&lease -> subnet, &rhp, &lease -> ip_addr, share)) { lease_dereference (&lease, MDL); host_dereference (&rhp, MDL); return 0; } host_reference (&lease -> host, rhp, MDL); if (rhp -> client_identifier.len > sizeof lease -> uid_buf) lease -> uid = dmalloc (rhp -> client_identifier.len, MDL); else lease -> uid = lease -> uid_buf; if (!lease -> uid) { lease_dereference (&lease, MDL); host_dereference (&rhp, MDL); return 0; } memcpy (lease -> uid, rhp -> client_identifier.data, rhp -> client_identifier.len); lease -> uid_len = rhp -> client_identifier.len; lease -> hardware_addr = rhp -> interface; lease -> starts = lease -> cltt = lease -> ends = MIN_TIME; lease -> flags = STATIC_LEASE; lease -> binding_state = FTS_FREE; lease_reference (lp, lease, MDL); lease_dereference (&lease, MDL); host_dereference (&rhp, MDL); return 1; } /* Look through all the pools in a list starting with the specified pool for a free lease. We try to find a virgin lease if we can. If we don't find a virgin lease, we try to find a non-virgin lease that's free. If we can't find one of those, we try to reclaim an abandoned lease. If all of these possibilities fail to pan out, we don't return a lease at all. */ int allocate_lease (struct lease **lp, struct packet *packet, struct pool *pool, int *peer_has_leases) { struct lease *lease = (struct lease *)0; struct lease *candl = (struct lease *)0; for (; pool ; pool = pool -> next) { if ((pool -> prohibit_list && permitted (packet, pool -> prohibit_list)) || (pool -> permit_list && !permitted (packet, pool -> permit_list))) continue; #if defined (FAILOVER_PROTOCOL) /* Peer_has_leases just says that we found at least one free lease. If no free lease is returned, the caller can deduce that this means the peer is hogging all the free leases, so we can print a better error message. */ /* XXX Do we need code here to ignore PEER_IS_OWNER and * XXX just check tstp if we're in, e.g., PARTNER_DOWN? * XXX Where do we deal with CONFLICT_DETECTED, et al? */ /* XXX This should be handled by the lease binding "state * XXX machine" - that is, when we get here, if a lease * XXX could be allocated, it will have the correct * XXX binding state so that the following code will * XXX result in its being allocated. */ /* Skip to the most expired lease in the pool that is not * owned by a failover peer. */ if (pool->failover_peer != NULL) { if (pool->failover_peer->i_am == primary) { candl = pool->free; /* * In normal operation, we never want to touch * the peer's leases. In partner-down * operation, we need to be able to pick up * the peer's leases after STOS+MCLT. */ if (pool->backup != NULL) { if (((candl == NULL) || (candl->ends > pool->backup->ends)) && lease_mine_to_reallocate( pool->backup)) { candl = pool->backup; } else { *peer_has_leases = 1; } } } else { candl = pool->backup; if (pool->free != NULL) { if (((candl == NULL) || (candl->ends > pool->free->ends)) && lease_mine_to_reallocate( pool->free)) { candl = pool->free; } else { *peer_has_leases = 1; } } } /* Try abandoned leases as a last resort. */ if ((candl == NULL) && (pool->abandoned != NULL) && lease_mine_to_reallocate(pool->abandoned)) candl = pool->abandoned; } else #endif { if (pool -> free) candl = pool -> free; else candl = pool -> abandoned; } /* * XXX: This may not match with documented expectation. * It's expected that when we OFFER a lease, we set its * ends time forward 2 minutes so that it gets sorted to * the end of its free list (avoiding a similar allocation * to another client). It is not expected that we issue a * "no free leases" error when the last lease has been * offered, but it's not exactly broken either. */ if (!candl || (candl -> ends > cur_time)) continue; if (!lease) { lease = candl; continue; } /* * There are tiers of lease state preference, listed here in * reverse order (least to most preferential): * * ABANDONED * FREE/BACKUP * * If the selected lease and candidate are both of the same * state, select the oldest (longest ago) expiration time * between the two. If the candidate lease is of a higher * preferred grade over the selected lease, use it. */ if ((lease -> binding_state == FTS_ABANDONED) && ((candl -> binding_state != FTS_ABANDONED) || (candl -> ends < lease -> ends))) { lease = candl; continue; } else if (candl -> binding_state == FTS_ABANDONED) continue; if ((lease -> uid_len || lease -> hardware_addr.hlen) && ((!candl -> uid_len && !candl -> hardware_addr.hlen) || (candl -> ends < lease -> ends))) { lease = candl; continue; } else if (candl -> uid_len || candl -> hardware_addr.hlen) continue; if (candl -> ends < lease -> ends) lease = candl; } if (lease != NULL) { if (lease->binding_state == FTS_ABANDONED) log_error("Reclaiming abandoned lease %s.", piaddr(lease->ip_addr)); /* * XXX: For reliability, we go ahead and remove the host * record and try to move on. For correctness, if there * are any other stale host vectors, we want to find them. */ if (lease->host != NULL) { log_debug("soft impossible condition (%s:%d): stale " "host \"%s\" found on lease %s", MDL, lease->host->name, piaddr(lease->ip_addr)); host_dereference(&lease->host, MDL); } lease_reference (lp, lease, MDL); return 1; } return 0; } /* Determine whether or not a permit exists on a particular permit list that matches the specified packet, returning nonzero if so, zero if not. */ int permitted (packet, permit_list) struct packet *packet; struct permit *permit_list; { struct permit *p; int i; for (p = permit_list; p; p = p -> next) { switch (p -> type) { case permit_unknown_clients: if (!packet -> known) return 1; break; case permit_known_clients: if (packet -> known) return 1; break; case permit_authenticated_clients: if (packet -> authenticated) return 1; break; case permit_unauthenticated_clients: if (!packet -> authenticated) return 1; break; case permit_all_clients: return 1; case permit_dynamic_bootp_clients: if (!packet -> options_valid || !packet -> packet_type) return 1; break; case permit_class: for (i = 0; i < packet -> class_count; i++) { if (p -> class == packet -> classes [i]) return 1; if (packet -> classes [i] && packet -> classes [i] -> superclass && (packet -> classes [i] -> superclass == p -> class)) return 1; } break; case permit_after: if (cur_time > p->after) return 1; break; } } return 0; } int locate_network (packet) struct packet *packet; { struct iaddr ia; struct data_string data; struct subnet *subnet = (struct subnet *)0; struct option_cache *oc; /* See if there's a Relay Agent Link Selection Option, or a * Subnet Selection Option. The Link-Select and Subnet-Select * are formatted and used precisely the same, but we must prefer * the link-select over the subnet-select. */ if ((oc = lookup_option(&agent_universe, packet->options, RAI_LINK_SELECT)) == NULL) oc = lookup_option(&dhcp_universe, packet->options, DHO_SUBNET_SELECTION); /* If there's no SSO and no giaddr, then use the shared_network from the interface, if there is one. If not, fail. */ if (!oc && !packet -> raw -> giaddr.s_addr) { if (packet -> interface -> shared_network) { shared_network_reference (&packet -> shared_network, packet -> interface -> shared_network, MDL); return 1; } return 0; } /* If there's an option indicating link connection, and it's valid, * use it to figure out the subnet. If it's not valid, fail. */ if (oc) { memset (&data, 0, sizeof data); if (!evaluate_option_cache (&data, packet, (struct lease *)0, (struct client_state *)0, packet -> options, (struct option_state *)0, &global_scope, oc, MDL)) { return 0; } if (data.len != 4) { return 0; } ia.len = 4; memcpy (ia.iabuf, data.data, 4); data_string_forget (&data, MDL); } else { ia.len = 4; memcpy (ia.iabuf, &packet -> raw -> giaddr, 4); } /* If we know the subnet on which the IP address lives, use it. */ if (find_subnet (&subnet, ia, MDL)) { shared_network_reference (&packet -> shared_network, subnet -> shared_network, MDL); subnet_dereference (&subnet, MDL); return 1; } /* Otherwise, fail. */ return 0; } /* * Try to figure out the source address to send packets from. * * If the packet we received specified the server address, then we * will use that. * * Otherwise, use the first address from the interface. If we do * this, we also save this into the option cache as the server * address. */ void get_server_source_address(struct in_addr *from, struct option_state *options, struct packet *packet) { unsigned option_num; struct option_cache *oc; struct data_string d; struct in_addr *a; memset(&d, 0, sizeof(d)); option_num = DHO_DHCP_SERVER_IDENTIFIER; oc = lookup_option(&dhcp_universe, options, option_num); if (oc != NULL) { if (evaluate_option_cache(&d, packet, NULL, NULL, packet->options, options, &global_scope, oc, MDL)) { if (d.len == sizeof(*from)) { memcpy(from, d.data, sizeof(*from)); data_string_forget(&d, MDL); return; } data_string_forget(&d, MDL); } oc = NULL; } if (packet->interface->address_count > 0) { if (option_cache_allocate(&oc, MDL)) { a = &packet->interface->addresses[0]; if (make_const_data(&oc->expression, (unsigned char *)a, sizeof(*a), 0, 0, MDL)) { option_code_hash_lookup(&oc->option, dhcp_universe.code_hash, &option_num, 0, MDL); save_option(&dhcp_universe, options, oc); } option_cache_dereference(&oc, MDL); } *from = packet->interface->addresses[0]; } else { memset(from, 0, sizeof(*from)); } } /* * Look for the lowest numbered site code number and * apply a log warning if it is less than 224. Do not * permit site codes less than 128 (old code never did). * * Note that we could search option codes 224 down to 128 * on the hash table, but the table is (probably) smaller * than that if it was declared as a standalone table with * defaults. So we traverse the option code hash. */ static int find_min_site_code(struct universe *u) { if (u->site_code_min) return u->site_code_min; /* * Note that site_code_min has to be global as we can't pass an * argument through hash_foreach(). The value 224 is taken from * RFC 3942. */ site_code_min = 224; option_code_hash_foreach(u->code_hash, lowest_site_code); if (site_code_min < 224) { log_error("WARNING: site-local option codes less than 224 have " "been deprecated by RFC3942. You have options " "listed in site local space %s that number as low as " "%d. Please investigate if these should be declared " "as regular options rather than site-local options, " "or migrated up past 224.", u->name, site_code_min); } /* * don't even bother logging, this is just silly, and never worked * on any old version of software. */ if (site_code_min < 128) site_code_min = 128; /* * Cache the determined minimum site code on the universe structure. * Note that due to the < 128 check above, a value of zero is * impossible. */ u->site_code_min = site_code_min; return site_code_min; } static isc_result_t lowest_site_code(const void *key, unsigned len, void *object) { struct option *option = object; if (option->code < site_code_min) site_code_min = option->code; return ISC_R_SUCCESS; } static void maybe_return_agent_options(struct packet *packet, struct option_state *options) { /* If there were agent options in the incoming packet, return * them. Do not return the agent options if they were stashed * on the lease. We do not check giaddr to detect the presence of * a relay, as this excludes "l2" relay agents which have no giaddr * to set. * * XXX: If the user configures options for the relay agent information * (state->options->universes[agent_universe.index] is not NULL), * we're still required to duplicate other values provided by the * relay agent. So we need to merge the old values not configured * by the user into the new state, not just give up. */ if (!packet->agent_options_stashed && (packet->options != NULL) && packet->options->universe_count > agent_universe.index && packet->options->universes[agent_universe.index] != NULL && (options->universe_count <= agent_universe.index || options->universes[agent_universe.index] == NULL)) { option_chain_head_reference ((struct option_chain_head **) &(options->universes[agent_universe.index]), (struct option_chain_head *) packet->options->universes[agent_universe.index], MDL); if (options->universe_count <= agent_universe.index) options->universe_count = agent_universe.index + 1; } } dhcp-4.2.4/server/dhcpd.8000644 000765 000024 00000063763 11565475670 015107 0ustar00sarstaff000000 000000 .\" dhcpd.8 .\" .\" Copyright (c) 2009-2011 by Internet Systems Consortium, Inc. ("ISC") .\" Copyright (c) 2004-2007 by Internet Systems Consortium, Inc. ("ISC") .\" Copyright (c) 1996-2003 by Internet Software Consortium .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above .\" copyright notice and this permission notice appear in all copies. .\" .\" THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES .\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR .\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES .\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT .\" OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" .\" Internet Systems Consortium, Inc. .\" 950 Charter Street .\" Redwood City, CA 94063 .\" .\" https://www.isc.org/ .\" .\" This software has been written for Internet Systems Consortium .\" by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. .\" .\" Support and other services are available for ISC products - see .\" https://www.isc.org for more information or to learn more about ISC. .\" .\" $Id: dhcpd.8,v 1.30.24.5 2011-05-20 14:33:28 tomasz Exp $ .\" .TH dhcpd 8 .SH NAME dhcpd - Dynamic Host Configuration Protocol Server .SH SYNOPSIS .B dhcpd [ .B -p .I port ] [ .B -f ] [ .B -d ] [ .B -q ] [ .B -t | .B -T ] [ .B -4 | .B -6 ] [ .B -s .I server ] [ .B -cf .I config-file ] [ .B -lf .I lease-file ] [ .B -pf .I pid-file ] [ .B --no-pid ] [ .B -tf .I trace-output-file ] [ .B -play .I trace-playback-file ] [ .I if0 [ .I ...ifN ] ] .B dhcpd --version .SH DESCRIPTION The Internet Systems Consortium DHCP Server, dhcpd, implements the Dynamic Host Configuration Protocol (DHCP) and the Internet Bootstrap Protocol (BOOTP). DHCP allows hosts on a TCP/IP network to request and be assigned IP addresses, and also to discover information about the network to which they are attached. BOOTP provides similar functionality, with certain restrictions. .SH OPERATION .PP The DHCP protocol allows a host which is unknown to the network administrator to be automatically assigned a new IP address out of a pool of IP addresses for its network. In order for this to work, the network administrator allocates address pools in each subnet and enters them into the dhcpd.conf(5) file. .PP There are two versions of the DHCP protocol DHCPv4 and DHCPv6. At startup the server may be started for one or the other via the .B -4 or .B -6 arguments. .PP On startup, dhcpd reads the .IR dhcpd.conf file and stores a list of available addresses on each subnet in memory. When a client requests an address using the DHCP protocol, dhcpd allocates an address for it. Each client is assigned a lease, which expires after an amount of time chosen by the administrator (by default, one day). Before leases expire, the clients to which leases are assigned are expected to renew them in order to continue to use the addresses. Once a lease has expired, the client to which that lease was assigned is no longer permitted to use the leased IP address. .PP In order to keep track of leases across system reboots and server restarts, dhcpd keeps a list of leases it has assigned in the dhcpd.leases(5) file. Before dhcpd grants a lease to a host, it records the lease in this file and makes sure that the contents of the file are flushed to disk. This ensures that even in the event of a system crash, dhcpd will not forget about a lease that it has assigned. On startup, after reading the dhcpd.conf file, dhcpd reads the dhcpd.leases file to refresh its memory about what leases have been assigned. .PP New leases are appended to the end of the dhcpd.leases file. In order to prevent the file from becoming arbitrarily large, from time to time dhcpd creates a new dhcpd.leases file from its in-core lease database. Once this file has been written to disk, the old file is renamed .IR dhcpd.leases~ , and the new file is renamed dhcpd.leases. If the system crashes in the middle of this process, whichever dhcpd.leases file remains will contain all the lease information, so there is no need for a special crash recovery process. .PP BOOTP support is also provided by this server. Unlike DHCP, the BOOTP protocol does not provide a protocol for recovering dynamically-assigned addresses once they are no longer needed. It is still possible to dynamically assign addresses to BOOTP clients, but some administrative process for reclaiming addresses is required. By default, leases are granted to BOOTP clients in perpetuity, although the network administrator may set an earlier cutoff date or a shorter lease length for BOOTP leases if that makes sense. .PP BOOTP clients may also be served in the old standard way, which is to simply provide a declaration in the dhcpd.conf file for each BOOTP client, permanently assigning an address to each client. .PP Whenever changes are made to the dhcpd.conf file, dhcpd must be restarted. To restart dhcpd, send a SIGTERM (signal 15) to the process ID contained in .IR RUNDIR/dhcpd.pid , and then re-invoke dhcpd. Because the DHCP server database is not as lightweight as a BOOTP database, dhcpd does not automatically restart itself when it sees a change to the dhcpd.conf file. .PP Note: We get a lot of complaints about this. We realize that it would be nice if one could send a SIGHUP to the server and have it reload the database. This is not technically impossible, but it would require a great deal of work, our resources are extremely limited, and they can be better spent elsewhere. So please don't complain about this on the mailing list unless you're prepared to fund a project to implement this feature, or prepared to do it yourself. .SH COMMAND LINE .PP The names of the network interfaces on which dhcpd should listen for broadcasts may be specified on the command line. This should be done on systems where dhcpd is unable to identify non-broadcast interfaces, but should not be required on other systems. If no interface names are specified on the command line dhcpd will identify all network interfaces which are up, eliminating non-broadcast interfaces if possible, and listen for DHCP broadcasts on each interface. .PP .SH COMMAND LINE OPTIONS .TP .BI \-4 Run as a DHCP server. This is the default and cannot be combined with \fB\-6\fR. .TP .BI \-6 Run as a DHCPv6 server. This cannot be combined with \fB\-4\fR. .TP .BI \-p \ port The udp port number on which .B dhcpd should listen. If unspecified .B dhcpd uses the default port of 67. This is mostly useful for debugging purposes. .TP .BI \-s \ address Specify an address or host name to which .B dhcpd should send replies rather than the broadcast address (255.255.255.255). This option is only supported in IPv4. .TP .BI \-f Force .B dhcpd to run as a foreground process instead of as a daemon in the background. This is useful when running .B dhcpd under a debugger, or when running it out of inittab on System V systems. .TP .BI \-d Send log messages to the standard error descriptor. This can be useful for debugging, and also at sites where a complete log of all dhcp activity must be kept but syslogd is not reliable or otherwise cannot be used. Normally, .B dhcpd will log all output using the \fBsyslog(3)\fR function with the log facility set to LOG_DAEMON. Note that \fB\-d\fR implies \fB\-f\fR (the daemon will not fork itself into the background). .TP .BI \-q Be quiet at startup. This suppresses the printing of the entire copyright message during startup. This might be desirable when starting .B dhcpd from a system startup script (e.g., /etc/rc). .TP .BI \-t Test the configuration file. The server tests the configuration file for correct syntax, but will not attempt to perform any network operations. This can be used to test a new configuration file automatically before installing it. .TP .BI \-T Test the lease file. The server tests the lease file for correct syntax, but will not attempt to perform any network operations. This can be used to test a new leaes file automatically before installing it. .TP .BI \-tf \ tracefile Specify a file into which the entire startup state of the server and all the transactions it processes are logged. This can be useful in submitting bug reports - if you are getting a core dump every so often, you can start the server with the \fB-tf\fR option and then, when the server dumps core, the trace file will contain all the transactions that led up to it dumping core, so that the problem can be easily debugged with \fB-play\fR. .TP .BI \-play \ playfile Specify a file from which the entire startup state of the server and all the transactions it processed are read. The \fB-play\fR option must be specified with an alternate lease file, using the \fB-lf\fR switch, so that the DHCP server doesn't wipe out your existing lease file with its test data. The DHCP server will refuse to operate in playback mode unless you specify an alternate lease file. .TP .BI --version Print version number and exit. .PP .I Modifying default file locations: The following options can be used to modify the locations .B dhcpd uses for it's files. Because of the importance of using the same lease database at all times when running dhcpd in production, these options should be used \fBonly\fR for testing lease files or database files in a non-production environment. .TP .BI \-cf \ config-file Path to alternate configuration file. .TP .BI \-lf \ lease-file Path to alternate lease file. .TP .BI \-pf \ pid-file Path to alternate pid file. .TP .BI \--no-pid Option to disable writing pid files. By default the program will write a pid file. If the program is invoked with this option it will not check for an existing server process. .PP .SH CONFIGURATION The syntax of the dhcpd.conf(5) file is discussed separately. This section should be used as an overview of the configuration process, and the dhcpd.conf(5) documentation should be consulted for detailed reference information. .PP .SH Subnets dhcpd needs to know the subnet numbers and netmasks of all subnets for which it will be providing service. In addition, in order to dynamically allocate addresses, it must be assigned one or more ranges of addresses on each subnet which it can in turn assign to client hosts as they boot. Thus, a very simple configuration providing DHCP support might look like this: .nf .sp 1 subnet 239.252.197.0 netmask 255.255.255.0 { range 239.252.197.10 239.252.197.250; } .fi .PP Multiple address ranges may be specified like this: .nf .sp 1 subnet 239.252.197.0 netmask 255.255.255.0 { range 239.252.197.10 239.252.197.107; range 239.252.197.113 239.252.197.250; } .fi .PP If a subnet will only be provided with BOOTP service and no dynamic address assignment, the range clause can be left out entirely, but the subnet statement must appear. .PP .SH Lease Lengths DHCP leases can be assigned almost any length from zero seconds to infinity. What lease length makes sense for any given subnet, or for any given installation, will vary depending on the kinds of hosts being served. .PP For example, in an office environment where systems are added from time to time and removed from time to time, but move relatively infrequently, it might make sense to allow lease times of a month or more. In a final test environment on a manufacturing floor, it may make more sense to assign a maximum lease length of 30 minutes - enough time to go through a simple test procedure on a network appliance before packaging it up for delivery. .PP It is possible to specify two lease lengths: the default length that will be assigned if a client doesn't ask for any particular lease length, and a maximum lease length. These are specified as clauses to the subnet command: .nf .sp 1 subnet 239.252.197.0 netmask 255.255.255.0 { range 239.252.197.10 239.252.197.107; default-lease-time 600; max-lease-time 7200; } .fi .PP This particular subnet declaration specifies a default lease time of 600 seconds (ten minutes), and a maximum lease time of 7200 seconds (two hours). Other common values would be 86400 (one day), 604800 (one week) and 2592000 (30 days). .PP Each subnet need not have the same lease\(emin the case of an office environment and a manufacturing environment served by the same DHCP server, it might make sense to have widely disparate values for default and maximum lease times on each subnet. .SH BOOTP Support Each BOOTP client must be explicitly declared in the dhcpd.conf file. A very basic client declaration will specify the client network interface's hardware address and the IP address to assign to that client. If the client needs to be able to load a boot file from the server, that file's name must be specified. A simple bootp client declaration might look like this: .nf .sp 1 host haagen { hardware ethernet 08:00:2b:4c:59:23; fixed-address 239.252.197.9; filename "/tftpboot/haagen.boot"; } .fi .SH Options DHCP (and also BOOTP with Vendor Extensions) provide a mechanism whereby the server can provide the client with information about how to configure its network interface (e.g., subnet mask), and also how the client can access various network services (e.g., DNS, IP routers, and so on). .PP These options can be specified on a per-subnet basis, and, for BOOTP clients, also on a per-client basis. In the event that a BOOTP client declaration specifies options that are also specified in its subnet declaration, the options specified in the client declaration take precedence. A reasonably complete DHCP configuration might look something like this: .nf .sp 1 subnet 239.252.197.0 netmask 255.255.255.0 { range 239.252.197.10 239.252.197.250; default-lease-time 600 max-lease-time 7200; option subnet-mask 255.255.255.0; option broadcast-address 239.252.197.255; option routers 239.252.197.1; option domain-name-servers 239.252.197.2, 239.252.197.3; option domain-name "isc.org"; } .fi .PP A bootp host on that subnet that needs to be in a different domain and use a different name server might be declared as follows: .nf .sp 1 host haagen { hardware ethernet 08:00:2b:4c:59:23; fixed-address 239.252.197.9; filename "/tftpboot/haagen.boot"; option domain-name-servers 192.5.5.1; option domain-name "vix.com"; } .fi .PP A more complete description of the dhcpd.conf file syntax is provided in dhcpd.conf(5). .SH OMAPI The DHCP server provides the capability to modify some of its configuration while it is running, without stopping it, modifying its database files, and restarting it. This capability is currently provided using OMAPI - an API for manipulating remote objects. OMAPI clients connect to the server using TCP/IP, authenticate, and can then examine the server's current status and make changes to it. .PP Rather than implementing the underlying OMAPI protocol directly, user programs should use the dhcpctl API or OMAPI itself. Dhcpctl is a wrapper that handles some of the housekeeping chores that OMAPI does not do automatically. Dhcpctl and OMAPI are documented in \fBdhcpctl(3)\fR and \fBomapi(3)\fR. .PP OMAPI exports objects, which can then be examined and modified. The DHCP server exports the following objects: lease, host, failover-state and group. Each object has a number of methods that are provided: lookup, create, and destroy. In addition, it is possible to look at attributes that are stored on objects, and in some cases to modify those attributes. .SH THE LEASE OBJECT Leases can't currently be created or destroyed, but they can be looked up to examine and modify their state. .PP Leases have the following attributes: .PP .B state \fIinteger\fR lookup, examine .RS 0.5i .nf 1 = free 2 = active 3 = expired 4 = released 5 = abandoned 6 = reset 7 = backup 8 = reserved 9 = bootp .fi .RE .PP .B ip-address \fIdata\fR lookup, examine .RS 0.5i The IP address of the lease. .RE .PP .B dhcp-client-identifier \fIdata\fR lookup, examine, update .RS 0.5i The client identifier that the client used when it acquired the lease. Not all clients send client identifiers, so this may be empty. .RE .PP .B client-hostname \fIdata\fR examine, update .RS 0.5i The value the client sent in the host-name option. .RE .PP .B host \fIhandle\fR examine .RS 0.5i the host declaration associated with this lease, if any. .RE .PP .B subnet \fIhandle\fR examine .RS 0.5i the subnet object associated with this lease (the subnet object is not currently supported). .RE .PP .B pool \fIhandle\fR examine .RS 0.5i the pool object associated with this lease (the pool object is not currently supported). .RE .PP .B billing-class \fIhandle\fR examine .RS 0.5i the handle to the class to which this lease is currently billed, if any (the class object is not currently supported). .RE .PP .B hardware-address \fIdata\fR examine, update .RS 0.5i the hardware address (chaddr) field sent by the client when it acquired its lease. .RE .PP .B hardware-type \fIinteger\fR examine, update .RS 0.5i the type of the network interface that the client reported when it acquired its lease. .RE .PP .B ends \fItime\fR examine .RS 0.5i the time when the lease's current state ends, as understood by the client. .RE .PP .B tstp \fItime\fR examine .RS 0.5i the time when the lease's current state ends, as understood by the server. .RE .B tsfp \fItime\fR examine .RS 0.5i the adjusted time when the lease's current state ends, as understood by the failover peer (if there is no failover peer, this value is undefined). Generally this value is only adjusted for expired, released, or reset leases while the server is operating in partner-down state, and otherwise is simply the value supplied by the peer. .RE .B atsfp \fItime\fR examine .RS 0.5i the actual tsfp value sent from the peer. This value is forgotten when a lease binding state change is made, to facilitate retransmission logic. .RE .PP .B cltt \fItime\fR examine .RS 0.5i The time of the last transaction with the client on this lease. .RE .SH THE HOST OBJECT Hosts can be created, destroyed, looked up, examined and modified. If a host declaration is created or deleted using OMAPI, that information will be recorded in the dhcpd.leases file. It is permissible to delete host declarations that are declared in the dhcpd.conf file. .PP Hosts have the following attributes: .PP .B name \fIdata\fR lookup, examine, modify .RS 0.5i the name of the host declaration. This name must be unique among all host declarations. .RE .PP .B group \fIhandle\fR examine, modify .RS 0.5i the named group associated with the host declaration, if there is one. .RE .PP .B hardware-address \fIdata\fR lookup, examine, modify .RS 0.5i the link-layer address that will be used to match the client, if any. Only valid if hardware-type is also present. .RE .PP .B hardware-type \fIinteger\fR lookup, examine, modify .RS 0.5i the type of the network interface that will be used to match the client, if any. Only valid if hardware-address is also present. .RE .PP .B dhcp-client-identifier \fIdata\fR lookup, examine, modify .RS 0.5i the dhcp-client-identifier option that will be used to match the client, if any. .RE .PP .B ip-address \fIdata\fR examine, modify .RS 0.5i a fixed IP address which is reserved for a DHCP client that matches this host declaration. The IP address will only be assigned to the client if it is valid for the network segment to which the client is connected. .RE .PP .B statements \fIdata\fR modify .RS 0.5i a list of statements in the format of the dhcpd.conf file that will be executed whenever a message from the client is being processed. .RE .PP .B known \fIinteger\fR examine, modify .RS 0.5i if nonzero, indicates that a client matching this host declaration will be treated as \fIknown\fR in pool permit lists. If zero, the client will not be treated as known. .RE .SH THE GROUP OBJECT Named groups can be created, destroyed, looked up, examined and modified. If a group declaration is created or deleted using OMAPI, that information will be recorded in the dhcpd.leases file. It is permissible to delete group declarations that are declared in the dhcpd.conf file. .PP Named groups currently can only be associated with hosts - this allows one set of statements to be efficiently attached to more than one host declaration. .PP Groups have the following attributes: .PP .B name \fIdata\fR .RS 0.5i the name of the group. All groups that are created using OMAPI must have names, and the names must be unique among all groups. .RE .PP .B statements \fIdata\fR .RS 0.5i a list of statements in the format of the dhcpd.conf file that will be executed whenever a message from a client whose host declaration references this group is processed. .RE .SH THE CONTROL OBJECT The control object allows you to shut the server down. If the server is doing failover with another peer, it will make a clean transition into the shutdown state and notify its peer, so that the peer can go into partner down, and then record the "recover" state in the lease file so that when the server is restarted, it will automatically resynchronize with its peer. .PP On shutdown the server will also attempt to cleanly shut down all OMAPI connections. If these connections do not go down cleanly after five seconds, they are shut down preemptively. It can take as much as 25 seconds from the beginning of the shutdown process to the time that the server actually exits. .PP To shut the server down, open its control object and set the state attribute to 2. .SH THE FAILOVER-STATE OBJECT The failover-state object is the object that tracks the state of the failover protocol as it is being managed for a given failover peer. The failover object has the following attributes (please see .B dhcpd.conf (5) for explanations about what these attributes mean): .PP .B name \fIdata\fR examine .RS 0.5i Indicates the name of the failover peer relationship, as described in the server's \fBdhcpd.conf\fR file. .RE .PP .B partner-address \fIdata\fR examine .RS 0.5i Indicates the failover partner's IP address. .RE .PP .B local-address \fIdata\fR examine .RS 0.5i Indicates the IP address that is being used by the DHCP server for this failover pair. .RE .PP .B partner-port \fIdata\fR examine .RS 0.5i Indicates the TCP port on which the failover partner is listening for failover protocol connections. .RE .PP .B local-port \fIdata\fR examine .RS 0.5i Indicates the TCP port on which the DHCP server is listening for failover protocol connections for this failover pair. .RE .PP .B max-outstanding-updates \fIinteger\fR examine .RS 0.5i Indicates the number of updates that can be outstanding and unacknowledged at any given time, in this failover relationship. .RE .PP .B mclt \fIinteger\fR examine .RS 0.5i Indicates the maximum client lead time in this failover relationship. .RE .PP .B load-balance-max-secs \fIinteger\fR examine .RS 0.5i Indicates the maximum value for the secs field in a client request before load balancing is bypassed. .RE .PP .B load-balance-hba \fIdata\fR examine .RS 0.5i Indicates the load balancing hash bucket array for this failover relationship. .RE .PP .B local-state \fIinteger\fR examine, modify .RS 0.5i Indicates the present state of the DHCP server in this failover relationship. Possible values for state are: .RE .RS 1i .PP .nf 1 - startup 2 - normal 3 - communications interrupted 4 - partner down 5 - potential conflict 6 - recover 7 - paused 8 - shutdown 9 - recover done 10 - resolution interrupted 11 - conflict done 254 - recover wait .fi .RE .PP .RS 0.5i (Note that some of the above values have changed since DHCP 3.0.x.) .RE .PP .RS 0.5i In general it is not a good idea to make changes to this state. However, in the case that the failover partner is known to be down, it can be useful to set the DHCP server's failover state to partner down. At this point the DHCP server will take over service of the failover partner's leases as soon as possible, and will give out normal leases, not leases that are restricted by MCLT. If you do put the DHCP server into the partner-down when the other DHCP server is not in the partner-down state, but is not reachable, IP address assignment conflicts are possible, even likely. Once a server has been put into partner-down mode, its failover partner must not be brought back online until communication is possible between the two servers. .RE .PP .B partner-state \fIinteger\fR examine .RS 0.5i Indicates the present state of the failover partner. .RE .PP .B local-stos \fIinteger\fR examine .RS 0.5i Indicates the time at which the DHCP server entered its present state in this failover relationship. .RE .PP .B partner-stos \fIinteger\fR examine .RS 0.5i Indicates the time at which the failover partner entered its present state. .RE .PP .B hierarchy \fIinteger\fR examine .RS 0.5i Indicates whether the DHCP server is primary (0) or secondary (1) in this failover relationship. .RE .PP .B last-packet-sent \fIinteger\fR examine .RS 0.5i Indicates the time at which the most recent failover packet was sent by this DHCP server to its failover partner. .RE .PP .B last-timestamp-received \fIinteger\fR examine .RS 0.5i Indicates the timestamp that was on the failover message most recently received from the failover partner. .RE .PP .B skew \fIinteger\fR examine .RS 0.5i Indicates the skew between the failover partner's clock and this DHCP server's clock .RE .PP .B max-response-delay \fIinteger\fR examine .RS 0.5i Indicates the time in seconds after which, if no message is received from the failover partner, the partner is assumed to be out of communication. .RE .PP .B cur-unacked-updates \fIinteger\fR examine .RS 0.5i Indicates the number of update messages that have been received from the failover partner but not yet processed. .RE .SH FILES .B ETCDIR/dhcpd.conf, DBDIR/dhcpd.leases, RUNDIR/dhcpd.pid, .B DBDIR/dhcpd.leases~. .SH SEE ALSO dhclient(8), dhcrelay(8), dhcpd.conf(5), dhcpd.leases(5) .SH AUTHOR .B dhcpd(8) was originally written by Ted Lemon under a contract with Vixie Labs. Funding for this project was provided by Internet Systems Consortium. Version 3 of the DHCP server was funded by Nominum, Inc. Information about Internet Systems Consortium is available at .B https://www.isc.org/\fR. dhcp-4.2.4/server/dhcpd.c000644 000765 000024 00000124137 11741366355 015146 0ustar00sarstaff000000 000000 /* dhcpd.c DHCP Server Daemon. */ /* * Copyright (c) 2004-2012 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1996-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ * * This software has been written for Internet Systems Consortium * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. * To learn more about Internet Systems Consortium, see * ``https://www.isc.org/''. To learn more about Vixie Enterprises, * see ``http://www.vix.com''. To learn more about Nominum, Inc., see * ``http://www.nominum.com''. */ static const char copyright[] = "Copyright 2004-2012 Internet Systems Consortium."; static const char arr [] = "All rights reserved."; static const char message [] = "Internet Systems Consortium DHCP Server"; static const char url [] = "For info, please visit https://www.isc.org/software/dhcp/"; #include "dhcpd.h" #include #include #include #include #include #include #include #if defined (PARANOIA) # include # include # include /* get around the ISC declaration of group */ # define group real_group # include # undef group #endif /* PARANOIA */ static void usage(void); struct iaddr server_identifier; int server_identifier_matched; #if defined (NSUPDATE) /* This stuff is always executed to figure the default values for certain ddns variables. */ char std_nsupdate [] = " \n\ option server.ddns-hostname = \n\ pick (option fqdn.hostname, option host-name); \n\ option server.ddns-domainname = config-option domain-name; \n\ option server.ddns-rev-domainname = \"in-addr.arpa.\";"; /* This is the old-style name service updater that is executed whenever a lease is committed. It does not follow the DHCP-DNS draft at all. */ char old_nsupdate [] = " \n\ on commit { \n\ if (not static and \n\ ((config-option server.ddns-updates = null) or \n\ (config-option server.ddns-updates != 0))) { \n\ set new-ddns-fwd-name = \n\ concat (pick (config-option server.ddns-hostname, \n\ option host-name), \".\", \n\ pick (config-option server.ddns-domainname, \n\ config-option domain-name)); \n\ if (defined (ddns-fwd-name) and ddns-fwd-name != new-ddns-fwd-name) { \n\ switch (ns-update (delete (IN, A, ddns-fwd-name, leased-address))) { \n\ case NOERROR: \n\ unset ddns-fwd-name; \n\ on expiry or release { \n\ } \n\ } \n\ } \n\ \n\ if (not defined (ddns-fwd-name)) { \n\ set ddns-fwd-name = new-ddns-fwd-name; \n\ if defined (ddns-fwd-name) { \n\ switch (ns-update (not exists (IN, A, ddns-fwd-name, null), \n\ add (IN, A, ddns-fwd-name, leased-address, \n\ lease-time / 2))) { \n\ default: \n\ unset ddns-fwd-name; \n\ break; \n\ \n\ case NOERROR: \n\ set ddns-rev-name = \n\ concat (binary-to-ascii (10, 8, \".\", \n\ reverse (1, \n\ leased-address)), \".\", \n\ pick (config-option server.ddns-rev-domainname, \n\ \"in-addr.arpa.\")); \n\ switch (ns-update (delete (IN, PTR, ddns-rev-name, null), \n\ add (IN, PTR, ddns-rev-name, ddns-fwd-name, \n\ lease-time / 2))) \n\ { \n\ default: \n\ unset ddns-rev-name; \n\ on release or expiry { \n\ switch (ns-update (delete (IN, A, ddns-fwd-name, \n\ leased-address))) { \n\ case NOERROR: \n\ unset ddns-fwd-name; \n\ break; \n\ } \n\ on release or expiry; \n\ } \n\ break; \n\ \n\ case NOERROR: \n\ on release or expiry { \n\ switch (ns-update (delete (IN, PTR, ddns-rev-name, null))) {\n\ case NOERROR: \n\ unset ddns-rev-name; \n\ break; \n\ } \n\ switch (ns-update (delete (IN, A, ddns-fwd-name, \n\ leased-address))) { \n\ case NOERROR: \n\ unset ddns-fwd-name; \n\ break; \n\ } \n\ on release or expiry; \n\ } \n\ } \n\ } \n\ } \n\ } \n\ unset new-ddns-fwd-name; \n\ } \n\ }"; #endif /* NSUPDATE */ int ddns_update_style; const char *path_dhcpd_conf = _PATH_DHCPD_CONF; const char *path_dhcpd_db = _PATH_DHCPD_DB; const char *path_dhcpd_pid = _PATH_DHCPD_PID; /* False (default) => we write and use a pid file */ isc_boolean_t no_pid_file = ISC_FALSE; int dhcp_max_agent_option_packet_length = DHCP_MTU_MAX; static omapi_auth_key_t *omapi_key = (omapi_auth_key_t *)0; int omapi_port; #if defined (TRACING) trace_type_t *trace_srandom; #endif static isc_result_t verify_addr (omapi_object_t *l, omapi_addr_t *addr) { return ISC_R_SUCCESS; } static isc_result_t verify_auth (omapi_object_t *p, omapi_auth_key_t *a) { if (a != omapi_key) return DHCP_R_INVALIDKEY; return ISC_R_SUCCESS; } static void omapi_listener_start (void *foo) { omapi_object_t *listener; isc_result_t result; struct timeval tv; listener = (omapi_object_t *)0; result = omapi_generic_new (&listener, MDL); if (result != ISC_R_SUCCESS) log_fatal ("Can't allocate new generic object: %s", isc_result_totext (result)); result = omapi_protocol_listen (listener, (unsigned)omapi_port, 1); if (result == ISC_R_SUCCESS && omapi_key) result = omapi_protocol_configure_security (listener, verify_addr, verify_auth); if (result != ISC_R_SUCCESS) { log_error ("Can't start OMAPI protocol: %s", isc_result_totext (result)); tv.tv_sec = cur_tv.tv_sec + 5; tv.tv_usec = cur_tv.tv_usec; add_timeout (&tv, omapi_listener_start, 0, 0, 0); } omapi_object_dereference (&listener, MDL); } #if defined (PARANOIA) /* to be used in one of two possible scenarios */ static void setup_chroot (char *chroot_dir) { if (geteuid()) log_fatal ("you must be root to use chroot"); if (chroot(chroot_dir)) { log_fatal ("chroot(\"%s\"): %m", chroot_dir); } if (chdir ("/")) { /* probably permission denied */ log_fatal ("chdir(\"/\"): %m"); } } #endif /* PARANOIA */ #ifndef UNIT_TEST int main(int argc, char **argv) { int fd; int i, status; struct servent *ent; char *s; int cftest = 0; int lftest = 0; #ifndef DEBUG int pid; char pbuf [20]; int daemon = 1; #endif int quiet = 0; char *server = (char *)0; isc_result_t result; unsigned seed; struct interface_info *ip; #if defined (NSUPDATE) struct parse *parse; int lose; #endif int no_dhcpd_conf = 0; int no_dhcpd_db = 0; int no_dhcpd_pid = 0; #ifdef DHCPv6 int local_family_set = 0; #endif /* DHCPv6 */ #if defined (TRACING) char *traceinfile = (char *)0; char *traceoutfile = (char *)0; #endif #if defined (PARANOIA) char *set_user = 0; char *set_group = 0; char *set_chroot = 0; uid_t set_uid = 0; gid_t set_gid = 0; #endif /* PARANOIA */ /* Make sure that file descriptors 0 (stdin), 1, (stdout), and 2 (stderr) are open. To do this, we assume that when we open a file the lowest available file descriptor is used. */ fd = open("/dev/null", O_RDWR); if (fd == 0) fd = open("/dev/null", O_RDWR); if (fd == 1) fd = open("/dev/null", O_RDWR); if (fd == 2) log_perror = 0; /* No sense logging to /dev/null. */ else if (fd != -1) close(fd); /* Set up the isc and dns library managers */ status = dhcp_context_create(); if (status != ISC_R_SUCCESS) log_fatal("Can't initialize context: %s", isc_result_totext(status)); /* Set up the client classification system. */ classification_setup (); /* Initialize the omapi system. */ result = omapi_init (); if (result != ISC_R_SUCCESS) log_fatal ("Can't initialize OMAPI: %s", isc_result_totext (result)); /* Set up the OMAPI wrappers for common objects. */ dhcp_db_objects_setup (); /* Set up the OMAPI wrappers for various server database internal objects. */ dhcp_common_objects_setup (); /* Initially, log errors to stderr as well as to syslogd. */ openlog ("dhcpd", LOG_NDELAY, DHCPD_LOG_FACILITY); for (i = 1; i < argc; i++) { if (!strcmp (argv [i], "-p")) { if (++i == argc) usage (); local_port = validate_port (argv [i]); log_debug ("binding to user-specified port %d", ntohs (local_port)); } else if (!strcmp (argv [i], "-f")) { #ifndef DEBUG daemon = 0; #endif } else if (!strcmp (argv [i], "-d")) { #ifndef DEBUG daemon = 0; #endif log_perror = -1; } else if (!strcmp (argv [i], "-s")) { if (++i == argc) usage (); server = argv [i]; #if defined (PARANOIA) } else if (!strcmp (argv [i], "-user")) { if (++i == argc) usage (); set_user = argv [i]; } else if (!strcmp (argv [i], "-group")) { if (++i == argc) usage (); set_group = argv [i]; } else if (!strcmp (argv [i], "-chroot")) { if (++i == argc) usage (); set_chroot = argv [i]; #endif /* PARANOIA */ } else if (!strcmp (argv [i], "-cf")) { if (++i == argc) usage (); path_dhcpd_conf = argv [i]; no_dhcpd_conf = 1; } else if (!strcmp (argv [i], "-lf")) { if (++i == argc) usage (); path_dhcpd_db = argv [i]; no_dhcpd_db = 1; } else if (!strcmp (argv [i], "-pf")) { if (++i == argc) usage (); path_dhcpd_pid = argv [i]; no_dhcpd_pid = 1; } else if (!strcmp(argv[i], "--no-pid")) { no_pid_file = ISC_TRUE; } else if (!strcmp (argv [i], "-t")) { /* test configurations only */ #ifndef DEBUG daemon = 0; #endif cftest = 1; log_perror = -1; } else if (!strcmp (argv [i], "-T")) { /* test configurations and lease file only */ #ifndef DEBUG daemon = 0; #endif cftest = 1; lftest = 1; log_perror = -1; } else if (!strcmp (argv [i], "-q")) { quiet = 1; quiet_interface_discovery = 1; #ifdef DHCPv6 } else if (!strcmp(argv[i], "-4")) { if (local_family_set && (local_family != AF_INET)) { log_fatal("Server cannot run in both IPv4 and " "IPv6 mode at the same time."); } local_family = AF_INET; local_family_set = 1; } else if (!strcmp(argv[i], "-6")) { if (local_family_set && (local_family != AF_INET6)) { log_fatal("Server cannot run in both IPv4 and " "IPv6 mode at the same time."); } local_family = AF_INET6; local_family_set = 1; #endif /* DHCPv6 */ } else if (!strcmp (argv [i], "--version")) { log_info("isc-dhcpd-%s", PACKAGE_VERSION); exit (0); #if defined (TRACING) } else if (!strcmp (argv [i], "-tf")) { if (++i == argc) usage (); traceoutfile = argv [i]; } else if (!strcmp (argv [i], "-play")) { if (++i == argc) usage (); traceinfile = argv [i]; trace_replay_init (); #endif /* TRACING */ } else if (argv [i][0] == '-') { usage (); } else { struct interface_info *tmp = (struct interface_info *)0; if (strlen(argv[i]) >= sizeof(tmp->name)) log_fatal("%s: interface name too long " "(is %ld)", argv[i], (long)strlen(argv[i])); result = interface_allocate (&tmp, MDL); if (result != ISC_R_SUCCESS) log_fatal ("Insufficient memory to %s %s: %s", "record interface", argv [i], isc_result_totext (result)); strcpy (tmp -> name, argv [i]); if (interfaces) { interface_reference (&tmp -> next, interfaces, MDL); interface_dereference (&interfaces, MDL); } interface_reference (&interfaces, tmp, MDL); tmp -> flags = INTERFACE_REQUESTED; } } if (!no_dhcpd_conf && (s = getenv ("PATH_DHCPD_CONF"))) { path_dhcpd_conf = s; } #ifdef DHCPv6 if (local_family == AF_INET6) { /* DHCPv6: override DHCPv4 lease and pid filenames */ if (!no_dhcpd_db) { if ((s = getenv ("PATH_DHCPD6_DB"))) path_dhcpd_db = s; else path_dhcpd_db = _PATH_DHCPD6_DB; } if (!no_dhcpd_pid) { if ((s = getenv ("PATH_DHCPD6_PID"))) path_dhcpd_pid = s; else path_dhcpd_pid = _PATH_DHCPD6_PID; } } else #else /* !DHCPv6 */ { if (!no_dhcpd_db && (s = getenv ("PATH_DHCPD_DB"))) { path_dhcpd_db = s; } if (!no_dhcpd_pid && (s = getenv ("PATH_DHCPD_PID"))) { path_dhcpd_pid = s; } } #endif /* DHCPv6 */ /* * convert relative path names to absolute, for files that need * to be reopened after chdir() has been called */ if (path_dhcpd_db[0] != '/') { char *path = dmalloc(PATH_MAX, MDL); if (path == NULL) log_fatal("No memory for filename\n"); path_dhcpd_db = realpath(path_dhcpd_db, path); if (path_dhcpd_db == NULL) log_fatal("%s: %s", path, strerror(errno)); } if (!quiet) { log_info("%s %s", message, PACKAGE_VERSION); log_info (copyright); log_info (arr); log_info (url); } else { quiet = 0; log_perror = 0; } #if defined (TRACING) trace_init (set_time, MDL); if (traceoutfile) { result = trace_begin (traceoutfile, MDL); if (result != ISC_R_SUCCESS) log_fatal ("Unable to begin trace: %s", isc_result_totext (result)); } interface_trace_setup (); parse_trace_setup (); trace_srandom = trace_type_register ("random-seed", (void *)0, trace_seed_input, trace_seed_stop, MDL); trace_ddns_init(); #endif #if defined (PARANOIA) /* get user and group info if those options were given */ if (set_user) { struct passwd *tmp_pwd; if (geteuid()) log_fatal ("you must be root to set user"); if (!(tmp_pwd = getpwnam(set_user))) log_fatal ("no such user: %s", set_user); set_uid = tmp_pwd->pw_uid; /* use the user's group as the default gid */ if (!set_group) set_gid = tmp_pwd->pw_gid; } if (set_group) { /* get around the ISC declaration of group */ #define group real_group struct group *tmp_grp; if (geteuid()) log_fatal ("you must be root to set group"); if (!(tmp_grp = getgrnam(set_group))) log_fatal ("no such group: %s", set_group); set_gid = tmp_grp->gr_gid; #undef group } # if defined (EARLY_CHROOT) if (set_chroot) setup_chroot (set_chroot); # endif /* EARLY_CHROOT */ #endif /* PARANOIA */ /* Default to the DHCP/BOOTP port. */ if (!local_port) { if ((s = getenv ("DHCPD_PORT"))) { local_port = validate_port (s); log_debug ("binding to environment-specified port %d", ntohs (local_port)); } else { if (local_family == AF_INET) { ent = getservbyname("dhcp", "udp"); if (ent == NULL) { local_port = htons(67); } else { local_port = ent->s_port; } } else { /* INSIST(local_family == AF_INET6); */ ent = getservbyname("dhcpv6-server", "udp"); if (ent == NULL) { local_port = htons(547); } else { local_port = ent->s_port; } } #ifndef __CYGWIN32__ /* XXX */ endservent (); #endif } } if (local_family == AF_INET) { remote_port = htons(ntohs(local_port) + 1); } else { /* INSIST(local_family == AF_INET6); */ ent = getservbyname("dhcpv6-client", "udp"); if (ent == NULL) { remote_port = htons(546); } else { remote_port = ent->s_port; } } if (server) { if (local_family != AF_INET) { log_fatal("You can only specify address to send " "replies to when running an IPv4 server."); } if (!inet_aton (server, &limited_broadcast)) { struct hostent *he; he = gethostbyname (server); if (he) { memcpy (&limited_broadcast, he -> h_addr_list [0], sizeof limited_broadcast); } else limited_broadcast.s_addr = INADDR_BROADCAST; } } else { limited_broadcast.s_addr = INADDR_BROADCAST; } /* Get the current time... */ gettimeofday(&cur_tv, NULL); /* Set up the initial dhcp option universe. */ initialize_common_option_spaces (); initialize_server_option_spaces (); /* Add the ddns update style enumeration prior to parsing. */ add_enumeration (&ddns_styles); add_enumeration (&syslog_enum); #if defined (LDAP_CONFIGURATION) add_enumeration (&ldap_methods); #if defined (LDAP_USE_SSL) add_enumeration (&ldap_ssl_usage_enum); add_enumeration (&ldap_tls_reqcert_enum); add_enumeration (&ldap_tls_crlcheck_enum); #endif #endif if (!group_allocate (&root_group, MDL)) log_fatal ("Can't allocate root group!"); root_group -> authoritative = 0; /* Set up various hooks. */ dhcp_interface_setup_hook = dhcpd_interface_setup_hook; bootp_packet_handler = do_packet; #ifdef DHCPv6 dhcpv6_packet_handler = do_packet6; #endif /* DHCPv6 */ #if defined (NSUPDATE) /* Set up the standard name service updater routine. */ parse = NULL; status = new_parse(&parse, -1, std_nsupdate, sizeof(std_nsupdate) - 1, "standard name service update routine", 0); if (status != ISC_R_SUCCESS) log_fatal ("can't begin parsing name service updater!"); if (parse != NULL) { lose = 0; if (!(parse_executable_statements(&root_group->statements, parse, &lose, context_any))) { end_parse(&parse); log_fatal("can't parse standard name service updater!"); } end_parse(&parse); } #endif /* Initialize icmp support... */ if (!cftest && !lftest) icmp_startup (1, lease_pinged); #if defined (TRACING) if (traceinfile) { if (!no_dhcpd_db) { log_error ("%s", ""); log_error ("** You must specify a lease file with -lf."); log_error (" Dhcpd will not overwrite your default"); log_fatal (" lease file when playing back a trace. **"); } trace_file_replay (traceinfile); #if defined (DEBUG_MEMORY_LEAKAGE) && \ defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT) free_everything (); omapi_print_dmalloc_usage_by_caller (); #endif exit (0); } #endif #ifdef DHCPv6 /* set up DHCPv6 hashes */ if (!ia_new_hash(&ia_na_active, DEFAULT_HASH_SIZE, MDL)) { log_fatal("Out of memory creating hash for active IA_NA."); } if (!ia_new_hash(&ia_ta_active, DEFAULT_HASH_SIZE, MDL)) { log_fatal("Out of memory creating hash for active IA_TA."); } if (!ia_new_hash(&ia_pd_active, DEFAULT_HASH_SIZE, MDL)) { log_fatal("Out of memory creating hash for active IA_PD."); } #endif /* DHCPv6 */ /* Read the dhcpd.conf file... */ if (readconf () != ISC_R_SUCCESS) log_fatal ("Configuration file errors encountered -- exiting"); postconf_initialization (quiet); #if defined (PARANOIA) && !defined (EARLY_CHROOT) if (set_chroot) setup_chroot (set_chroot); #endif /* PARANOIA && !EARLY_CHROOT */ /* test option should cause an early exit */ if (cftest && !lftest) exit(0); group_write_hook = group_writer; /* Start up the database... */ db_startup (lftest); if (lftest) exit (0); /* Discover all the network interfaces and initialize them. */ discover_interfaces(DISCOVER_SERVER); #ifdef DHCPv6 /* * Remove addresses from our pools that we should not issue * to clients. * * We currently have no support for this in IPv4. It is not * as important in IPv4, as making pools with ranges that * leave out interfaces and hosts is fairly straightforward * using range notation, but not so handy with CIDR notation. */ if (local_family == AF_INET6) { mark_hosts_unavailable(); mark_phosts_unavailable(); mark_interfaces_unavailable(); } #endif /* DHCPv6 */ /* Make up a seed for the random number generator from current time plus the sum of the last four bytes of each interface's hardware address interpreted as an integer. Not much entropy, but we're booting, so we're not likely to find anything better. */ seed = 0; for (ip = interfaces; ip; ip = ip -> next) { int junk; memcpy (&junk, &ip -> hw_address.hbuf [ip -> hw_address.hlen - sizeof seed], sizeof seed); seed += junk; } srandom (seed + cur_time); #if defined (TRACING) trace_seed_stash (trace_srandom, seed + cur_time); #endif postdb_startup (); #ifdef DHCPv6 /* * Set server DHCPv6 identifier. * See dhcpv6.c for discussion of setting DUID. */ if (set_server_duid_from_option() == ISC_R_SUCCESS) { write_server_duid(); } else { if (!server_duid_isset()) { if (generate_new_server_duid() != ISC_R_SUCCESS) { log_fatal("Unable to set server identifier."); } write_server_duid(); } } #endif /* DHCPv6 */ #ifndef DEBUG if (daemon) { /* First part of becoming a daemon... */ if ((pid = fork ()) < 0) log_fatal ("Can't fork daemon: %m"); else if (pid) exit (0); } #if defined (PARANOIA) /* change uid to the specified one */ if (set_gid) { if (setgroups (0, (void *)0)) log_fatal ("setgroups: %m"); if (setgid (set_gid)) log_fatal ("setgid(%d): %m", (int) set_gid); } if (set_uid) { if (setuid (set_uid)) log_fatal ("setuid(%d): %m", (int) set_uid); } #endif /* PARANOIA */ /* * Deal with pid files. If the user told us * not to write a file we don't read one either */ if (no_pid_file == ISC_FALSE) { /*Read previous pid file. */ if ((i = open (path_dhcpd_pid, O_RDONLY)) >= 0) { status = read(i, pbuf, (sizeof pbuf) - 1); close (i); if (status > 0) { pbuf[status] = 0; pid = atoi(pbuf); /* * If there was a previous server process and * it is still running, abort */ if (!pid || (pid != getpid() && kill(pid, 0) == 0)) log_fatal("There's already a " "DHCP server running."); } } /* Write new pid file. */ i = open(path_dhcpd_pid, O_WRONLY|O_CREAT|O_TRUNC, 0644); if (i >= 0) { sprintf(pbuf, "%d\n", (int) getpid()); IGNORE_RET (write(i, pbuf, strlen(pbuf))); close(i); } else { log_error("Can't create PID file %s: %m.", path_dhcpd_pid); } } /* If we were requested to log to stdout on the command line, keep doing so; otherwise, stop. */ if (log_perror == -1) log_perror = 1; else log_perror = 0; if (daemon) { /* Become session leader and get pid... */ pid = setsid(); /* Close standard I/O descriptors. */ close(0); close(1); close(2); /* Reopen them on /dev/null. */ open("/dev/null", O_RDWR); open("/dev/null", O_RDWR); open("/dev/null", O_RDWR); log_perror = 0; /* No sense logging to /dev/null. */ IGNORE_RET (chdir("/")); } #endif /* !DEBUG */ #if defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL) || \ defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT) dmalloc_cutoff_generation = dmalloc_generation; dmalloc_longterm = dmalloc_outstanding; dmalloc_outstanding = 0; #endif omapi_set_int_value ((omapi_object_t *)dhcp_control_object, (omapi_object_t *)0, "state", server_running); /* Receive packets and dispatch them... */ dispatch (); /* Not reached */ return 0; } #endif /* !UNIT_TEST */ void postconf_initialization (int quiet) { struct option_state *options = (struct option_state *)0; struct data_string db; struct option_cache *oc; char *s; isc_result_t result; #if defined (NSUPDATE) struct parse *parse; #endif int tmp; /* Now try to get the lease file name. */ option_state_allocate (&options, MDL); execute_statements_in_scope ((struct binding_value **)0, (struct packet *)0, (struct lease *)0, (struct client_state *)0, (struct option_state *)0, options, &global_scope, root_group, (struct group *)0); memset (&db, 0, sizeof db); oc = lookup_option (&server_universe, options, SV_LEASE_FILE_NAME); if (oc && evaluate_option_cache (&db, (struct packet *)0, (struct lease *)0, (struct client_state *)0, options, (struct option_state *)0, &global_scope, oc, MDL)) { s = dmalloc (db.len + 1, MDL); if (!s) log_fatal ("no memory for lease db filename."); memcpy (s, db.data, db.len); s [db.len] = 0; data_string_forget (&db, MDL); path_dhcpd_db = s; } oc = lookup_option (&server_universe, options, SV_PID_FILE_NAME); if (oc && evaluate_option_cache (&db, (struct packet *)0, (struct lease *)0, (struct client_state *)0, options, (struct option_state *)0, &global_scope, oc, MDL)) { s = dmalloc (db.len + 1, MDL); if (!s) log_fatal ("no memory for pid filename."); memcpy (s, db.data, db.len); s [db.len] = 0; data_string_forget (&db, MDL); path_dhcpd_pid = s; } #ifdef DHCPv6 if (local_family == AF_INET6) { /* * Override lease file name with dhcpv6 lease file name, * if it was set; then, do the same with the pid file name */ oc = lookup_option(&server_universe, options, SV_DHCPV6_LEASE_FILE_NAME); if (oc && evaluate_option_cache(&db, NULL, NULL, NULL, options, NULL, &global_scope, oc, MDL)) { s = dmalloc (db.len + 1, MDL); if (!s) log_fatal ("no memory for lease db filename."); memcpy (s, db.data, db.len); s [db.len] = 0; data_string_forget (&db, MDL); path_dhcpd_db = s; } oc = lookup_option(&server_universe, options, SV_DHCPV6_PID_FILE_NAME); if (oc && evaluate_option_cache(&db, NULL, NULL, NULL, options, NULL, &global_scope, oc, MDL)) { s = dmalloc (db.len + 1, MDL); if (!s) log_fatal ("no memory for pid filename."); memcpy (s, db.data, db.len); s [db.len] = 0; data_string_forget (&db, MDL); path_dhcpd_pid = s; } } #endif /* DHCPv6 */ omapi_port = -1; oc = lookup_option (&server_universe, options, SV_OMAPI_PORT); if (oc && evaluate_option_cache (&db, (struct packet *)0, (struct lease *)0, (struct client_state *)0, options, (struct option_state *)0, &global_scope, oc, MDL)) { if (db.len == 2) { omapi_port = getUShort (db.data); } else log_fatal ("invalid omapi port data length"); data_string_forget (&db, MDL); } oc = lookup_option (&server_universe, options, SV_OMAPI_KEY); if (oc && evaluate_option_cache (&db, (struct packet *)0, (struct lease *)0, (struct client_state *)0, options, (struct option_state *)0, &global_scope, oc, MDL)) { s = dmalloc (db.len + 1, MDL); if (!s) log_fatal ("no memory for OMAPI key filename."); memcpy (s, db.data, db.len); s [db.len] = 0; data_string_forget (&db, MDL); result = omapi_auth_key_lookup_name (&omapi_key, s); dfree (s, MDL); if (result != ISC_R_SUCCESS) log_fatal ("OMAPI key %s: %s", s, isc_result_totext (result)); } oc = lookup_option (&server_universe, options, SV_LOCAL_PORT); if (oc && evaluate_option_cache (&db, (struct packet *)0, (struct lease *)0, (struct client_state *)0, options, (struct option_state *)0, &global_scope, oc, MDL)) { if (db.len == 2) { local_port = htons (getUShort (db.data)); } else log_fatal ("invalid local port data length"); data_string_forget (&db, MDL); } oc = lookup_option (&server_universe, options, SV_REMOTE_PORT); if (oc && evaluate_option_cache (&db, (struct packet *)0, (struct lease *)0, (struct client_state *)0, options, (struct option_state *)0, &global_scope, oc, MDL)) { if (db.len == 2) { remote_port = htons (getUShort (db.data)); } else log_fatal ("invalid remote port data length"); data_string_forget (&db, MDL); } oc = lookup_option (&server_universe, options, SV_LIMITED_BROADCAST_ADDRESS); if (oc && evaluate_option_cache (&db, (struct packet *)0, (struct lease *)0, (struct client_state *)0, options, (struct option_state *)0, &global_scope, oc, MDL)) { if (db.len == 4) { memcpy (&limited_broadcast, db.data, 4); } else log_fatal ("invalid broadcast address data length"); data_string_forget (&db, MDL); } oc = lookup_option (&server_universe, options, SV_LOCAL_ADDRESS); if (oc && evaluate_option_cache (&db, (struct packet *)0, (struct lease *)0, (struct client_state *)0, options, (struct option_state *)0, &global_scope, oc, MDL)) { if (db.len == 4) { memcpy (&local_address, db.data, 4); } else log_fatal ("invalid local address data length"); data_string_forget (&db, MDL); } oc = lookup_option (&server_universe, options, SV_DDNS_UPDATE_STYLE); if (oc) { if (evaluate_option_cache (&db, (struct packet *)0, (struct lease *)0, (struct client_state *)0, options, (struct option_state *)0, &global_scope, oc, MDL)) { if (db.len == 1) { ddns_update_style = db.data [0]; } else log_fatal ("invalid dns update type"); data_string_forget (&db, MDL); } } else { ddns_update_style = DDNS_UPDATE_STYLE_NONE; } #if defined (NSUPDATE) /* We no longer support ad_hoc, tell the user */ if (ddns_update_style == DDNS_UPDATE_STYLE_AD_HOC) { log_fatal("ddns-update-style ad_hoc no longer supported"); } #else /* If we don't have support for updates compiled in tell the user */ if (ddns_update_style != DDNS_UPDATE_STYLE_NONE) { log_fatal("Support for ddns-update-style not compiled in"); } #endif oc = lookup_option (&server_universe, options, SV_LOG_FACILITY); if (oc) { if (evaluate_option_cache (&db, (struct packet *)0, (struct lease *)0, (struct client_state *)0, options, (struct option_state *)0, &global_scope, oc, MDL)) { if (db.len == 1) { closelog (); openlog ("dhcpd", LOG_NDELAY, db.data[0]); /* Log the startup banner into the new log file. */ if (!quiet) { /* Don't log to stderr twice. */ tmp = log_perror; log_perror = 0; log_info("%s %s", message, PACKAGE_VERSION); log_info (copyright); log_info (arr); log_info (url); log_perror = tmp; } } else log_fatal ("invalid log facility"); data_string_forget (&db, MDL); } } oc = lookup_option(&server_universe, options, SV_DELAYED_ACK); if (oc && evaluate_option_cache(&db, NULL, NULL, NULL, options, NULL, &global_scope, oc, MDL)) { if (db.len == 2) { max_outstanding_acks = htons(getUShort(db.data)); } else { log_fatal("invalid max delayed ACK count "); } data_string_forget(&db, MDL); } oc = lookup_option(&server_universe, options, SV_MAX_ACK_DELAY); if (oc && evaluate_option_cache(&db, NULL, NULL, NULL, options, NULL, &global_scope, oc, MDL)) { u_int32_t timeval; if (db.len != 4) log_fatal("invalid max ack delay configuration"); timeval = getULong(db.data); max_ack_delay_secs = timeval / 1000000; max_ack_delay_usecs = timeval % 1000000; data_string_forget(&db, MDL); } /* Don't need the options anymore. */ option_state_dereference (&options, MDL); #if defined (NSUPDATE) /* If old-style ddns updates have been requested, parse the old-style ddns updater. */ if (ddns_update_style == 1) { struct executable_statement **e, *s; if (root_group -> statements) { s = (struct executable_statement *)0; if (!executable_statement_allocate (&s, MDL)) log_fatal ("no memory for ddns updater"); executable_statement_reference (&s -> next, root_group -> statements, MDL); executable_statement_dereference (&root_group -> statements, MDL); executable_statement_reference (&root_group -> statements, s, MDL); s -> op = statements_statement; e = &s -> data.statements; executable_statement_dereference (&s, MDL); } else { e = &root_group -> statements; } /* Set up the standard name service updater routine. */ parse = NULL; result = new_parse(&parse, -1, old_nsupdate, sizeof(old_nsupdate) - 1, "old name service update routine", 0); if (result != ISC_R_SUCCESS) log_fatal ("can't begin parsing old ddns updater!"); if (parse != NULL) { tmp = 0; if (!(parse_executable_statements(e, parse, &tmp, context_any))) { end_parse(&parse); log_fatal("can't parse standard ddns updater!"); } } end_parse(&parse); } #endif } void postdb_startup (void) { /* Initialize the omapi listener state. */ if (omapi_port != -1) { omapi_listener_start (0); } #if defined (FAILOVER_PROTOCOL) /* Initialize the failover listener state. */ dhcp_failover_startup (); #endif /* * Begin our lease timeout background task. */ schedule_all_ipv6_lease_timeouts(); } /* Print usage message. */ static void usage(void) { log_info("%s %s", message, PACKAGE_VERSION); log_info(copyright); log_info(arr); log_fatal("Usage: dhcpd [-p ] [-f] [-d] [-q] [-t|-T]\n" #ifdef DHCPv6 " [-4|-6] [-cf config-file] [-lf lease-file]\n" #else /* !DHCPv6 */ " [-cf config-file] [-lf lease-file]\n" #endif /* DHCPv6 */ #if defined (PARANOIA) /* meld into the following string */ " [-user user] [-group group] [-chroot dir]\n" #endif /* PARANOIA */ #if defined (TRACING) " [-tf trace-output-file]\n" " [-play trace-input-file]\n" #endif /* TRACING */ " [-pf pid-file] [--no-pid] [-s server]\n" " [if0 [...ifN]]"); } void lease_pinged (from, packet, length) struct iaddr from; u_int8_t *packet; int length; { struct lease *lp; /* Don't try to look up a pinged lease if we aren't trying to ping one - otherwise somebody could easily make us churn by just forging repeated ICMP EchoReply packets for us to look up. */ if (!outstanding_pings) return; lp = (struct lease *)0; if (!find_lease_by_ip_addr (&lp, from, MDL)) { log_debug ("unexpected ICMP Echo Reply from %s", piaddr (from)); return; } if (!lp -> state) { #if defined (FAILOVER_PROTOCOL) if (!lp -> pool || !lp -> pool -> failover_peer) #endif log_debug ("ICMP Echo Reply for %s late or spurious.", piaddr (from)); goto out; } if (lp -> ends > cur_time) { log_debug ("ICMP Echo reply while lease %s valid.", piaddr (from)); } /* At this point it looks like we pinged a lease and got a response, which shouldn't have happened. */ data_string_forget (&lp -> state -> parameter_request_list, MDL); free_lease_state (lp -> state, MDL); lp -> state = (struct lease_state *)0; abandon_lease (lp, "pinged before offer"); cancel_timeout (lease_ping_timeout, lp); --outstanding_pings; out: lease_dereference (&lp, MDL); } void lease_ping_timeout (vlp) void *vlp; { struct lease *lp = vlp; #if defined (DEBUG_MEMORY_LEAKAGE) unsigned long previous_outstanding = dmalloc_outstanding; #endif --outstanding_pings; dhcp_reply (lp); #if defined (DEBUG_MEMORY_LEAKAGE) log_info ("generation %ld: %ld new, %ld outstanding, %ld long-term", dmalloc_generation, dmalloc_outstanding - previous_outstanding, dmalloc_outstanding, dmalloc_longterm); #endif #if defined (DEBUG_MEMORY_LEAKAGE) dmalloc_dump_outstanding (); #endif } int dhcpd_interface_setup_hook (struct interface_info *ip, struct iaddr *ia) { struct subnet *subnet; struct shared_network *share; isc_result_t status; /* Special case for fallback network - not sure why this is necessary. */ if (!ia) { const char *fnn = "fallback-net"; status = shared_network_allocate (&ip -> shared_network, MDL); if (status != ISC_R_SUCCESS) log_fatal ("No memory for shared subnet: %s", isc_result_totext (status)); ip -> shared_network -> name = dmalloc (strlen (fnn) + 1, MDL); strcpy (ip -> shared_network -> name, fnn); return 1; } /* If there's a registered subnet for this address, connect it together... */ subnet = (struct subnet *)0; if (find_subnet (&subnet, *ia, MDL)) { /* If this interface has multiple aliases on the same subnet, ignore all but the first we encounter. */ if (!subnet -> interface) { interface_reference (&subnet -> interface, ip, MDL); subnet -> interface_address = *ia; } else if (subnet -> interface != ip) { log_error ("Multiple interfaces match the %s: %s %s", "same subnet", subnet -> interface -> name, ip -> name); } share = subnet -> shared_network; if (ip -> shared_network && ip -> shared_network != share) { log_fatal ("Interface %s matches multiple shared %s", ip -> name, "networks"); } else { if (!ip -> shared_network) shared_network_reference (&ip -> shared_network, share, MDL); } if (!share -> interface) { interface_reference (&share -> interface, ip, MDL); } else if (share -> interface != ip) { log_error ("Multiple interfaces match the %s: %s %s", "same shared network", share -> interface -> name, ip -> name); } subnet_dereference (&subnet, MDL); } return 1; } static TIME shutdown_time; static int omapi_connection_count; enum dhcp_shutdown_state shutdown_state; isc_result_t dhcp_io_shutdown (omapi_object_t *obj, void *foo) { /* Shut down all listeners. */ if (shutdown_state == shutdown_listeners && obj -> type == omapi_type_listener && obj -> inner && obj -> inner -> type == omapi_type_protocol_listener) { omapi_listener_destroy (obj, MDL); return ISC_R_SUCCESS; } /* Shut down all existing omapi connections. */ if (obj -> type == omapi_type_connection && obj -> inner && obj -> inner -> type == omapi_type_protocol) { if (shutdown_state == shutdown_drop_omapi_connections) { omapi_disconnect (obj, 1); } omapi_connection_count++; if (shutdown_state == shutdown_omapi_connections) { omapi_disconnect (obj, 0); return ISC_R_SUCCESS; } } /* Shutdown all DHCP interfaces. */ if (obj -> type == dhcp_type_interface && shutdown_state == shutdown_dhcp) { dhcp_interface_remove (obj, (omapi_object_t *)0); return ISC_R_SUCCESS; } return ISC_R_SUCCESS; } static isc_result_t dhcp_io_shutdown_countdown (void *vlp) { #if defined (FAILOVER_PROTOCOL) dhcp_failover_state_t *state; int failover_connection_count = 0; #endif struct timeval tv; oncemore: if (shutdown_state == shutdown_listeners || shutdown_state == shutdown_omapi_connections || shutdown_state == shutdown_drop_omapi_connections || shutdown_state == shutdown_dhcp) { omapi_connection_count = 0; omapi_io_state_foreach (dhcp_io_shutdown, 0); } if ((shutdown_state == shutdown_listeners || shutdown_state == shutdown_omapi_connections || shutdown_state == shutdown_drop_omapi_connections) && omapi_connection_count == 0) { shutdown_state = shutdown_dhcp; shutdown_time = cur_time; goto oncemore; } else if (shutdown_state == shutdown_listeners && cur_time - shutdown_time > 4) { shutdown_state = shutdown_omapi_connections; shutdown_time = cur_time; } else if (shutdown_state == shutdown_omapi_connections && cur_time - shutdown_time > 4) { shutdown_state = shutdown_drop_omapi_connections; shutdown_time = cur_time; } else if (shutdown_state == shutdown_drop_omapi_connections && cur_time - shutdown_time > 4) { shutdown_state = shutdown_dhcp; shutdown_time = cur_time; goto oncemore; } else if (shutdown_state == shutdown_dhcp && cur_time - shutdown_time > 4) { shutdown_state = shutdown_done; shutdown_time = cur_time; } #if defined (FAILOVER_PROTOCOL) /* Set all failover peers into the shutdown state. */ if (shutdown_state == shutdown_dhcp) { for (state = failover_states; state; state = state -> next) { if (state -> me.state == normal) { dhcp_failover_set_state (state, shut_down); failover_connection_count++; } if (state -> me.state == shut_down && state -> partner.state != partner_down) failover_connection_count++; } } if (shutdown_state == shutdown_done) { for (state = failover_states; state; state = state -> next) { if (state -> me.state == shut_down) { if (state -> link_to_peer) dhcp_failover_link_dereference (&state -> link_to_peer, MDL); dhcp_failover_set_state (state, recover); } } #if defined (DEBUG_MEMORY_LEAKAGE) && \ defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT) free_everything (); omapi_print_dmalloc_usage_by_caller (); #endif exit (0); } #else if (shutdown_state == shutdown_done) { #if defined (DEBUG_MEMORY_LEAKAGE) && \ defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT) free_everything (); omapi_print_dmalloc_usage_by_caller (); #endif exit (0); } #endif if (shutdown_state == shutdown_dhcp && #if defined(FAILOVER_PROTOCOL) !failover_connection_count && #endif ISC_TRUE) { shutdown_state = shutdown_done; shutdown_time = cur_time; goto oncemore; } tv.tv_sec = cur_tv.tv_sec + 1; tv.tv_usec = cur_tv.tv_usec; add_timeout (&tv, (void (*)(void *))dhcp_io_shutdown_countdown, 0, 0, 0); return ISC_R_SUCCESS; } isc_result_t dhcp_set_control_state (control_object_state_t oldstate, control_object_state_t newstate) { if (newstate == server_shutdown) { shutdown_time = cur_time; shutdown_state = shutdown_listeners; dhcp_io_shutdown_countdown (0); return ISC_R_SUCCESS; } return DHCP_R_INVALIDARG; } dhcp-4.2.4/server/dhcpd.conf000644 000765 000024 00000006276 07526054365 015655 0ustar00sarstaff000000 000000 # dhcpd.conf # # Sample configuration file for ISC dhcpd # # option definitions common to all supported networks... option domain-name "example.org"; option domain-name-servers ns1.example.org, ns2.example.org; default-lease-time 600; max-lease-time 7200; # Use this to enble / disable dynamic dns updates globally. #ddns-update-style none; # If this DHCP server is the official DHCP server for the local # network, the authoritative directive should be uncommented. #authoritative; # Use this to send dhcp log messages to a different log file (you also # have to hack syslog.conf to complete the redirection). log-facility local7; # No service will be given on this subnet, but declaring it helps the # DHCP server to understand the network topology. subnet 10.152.187.0 netmask 255.255.255.0 { } # This is a very basic subnet declaration. subnet 10.254.239.0 netmask 255.255.255.224 { range 10.254.239.10 10.254.239.20; option routers rtr-239-0-1.example.org, rtr-239-0-2.example.org; } # This declaration allows BOOTP clients to get dynamic addresses, # which we don't really recommend. subnet 10.254.239.32 netmask 255.255.255.224 { range dynamic-bootp 10.254.239.40 10.254.239.60; option broadcast-address 10.254.239.31; option routers rtr-239-32-1.example.org; } # A slightly different configuration for an internal subnet. subnet 10.5.5.0 netmask 255.255.255.224 { range 10.5.5.26 10.5.5.30; option domain-name-servers ns1.internal.example.org; option domain-name "internal.example.org"; option routers 10.5.5.1; option broadcast-address 10.5.5.31; default-lease-time 600; max-lease-time 7200; } # Hosts which require special configuration options can be listed in # host statements. If no address is specified, the address will be # allocated dynamically (if possible), but the host-specific information # will still come from the host declaration. host passacaglia { hardware ethernet 0:0:c0:5d:bd:95; filename "vmunix.passacaglia"; server-name "toccata.fugue.com"; } # Fixed IP addresses can also be specified for hosts. These addresses # should not also be listed as being available for dynamic assignment. # Hosts for which fixed IP addresses have been specified can boot using # BOOTP or DHCP. Hosts for which no fixed address is specified can only # be booted with DHCP, unless there is an address range on the subnet # to which a BOOTP client is connected which has the dynamic-bootp flag # set. host fantasia { hardware ethernet 08:00:07:26:c0:a5; fixed-address fantasia.fugue.com; } # You can declare a class of clients and then do address allocation # based on that. The example below shows a case where all clients # in a certain class get addresses on the 10.17.224/24 subnet, and all # other clients get addresses on the 10.0.29/24 subnet. class "foo" { match if substring (option vendor-class-identifier, 0, 4) = "SUNW"; } shared-network 224-29 { subnet 10.17.224.0 netmask 255.255.255.0 { option routers rtr-224.example.org; } subnet 10.0.29.0 netmask 255.255.255.0 { option routers rtr-29.example.org; } pool { allow members of "foo"; range 10.17.224.10 10.17.224.250; } pool { deny members of "foo"; range 10.0.29.10 10.0.29.230; } } dhcp-4.2.4/server/dhcpd.conf.5000644 000765 000024 00000343731 11736426526 016020 0ustar00sarstaff000000 000000 .\" dhcpd.conf.5 .\" .\" Copyright (c) 2004-2012 by Internet Systems Consortium, Inc. ("ISC") .\" Copyright (c) 1996-2003 by Internet Software Consortium .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above .\" copyright notice and this permission notice appear in all copies. .\" .\" THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES .\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR .\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES .\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT .\" OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" .\" Internet Systems Consortium, Inc. .\" 950 Charter Street .\" Redwood City, CA 94063 .\" .\" https://www.isc.org/ .\" .\" This software has been written for Internet Systems Consortium .\" by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. .\" .\" Support and other services are available for ISC products - see .\" https://www.isc.org for more information or to learn more about ISC. .\" .\" $Id: dhcpd.conf.5,v 1.106.18.8 2012-04-02 22:51:02 sar Exp $ .\" .TH dhcpd.conf 5 .SH NAME dhcpd.conf - dhcpd configuration file .SH DESCRIPTION The dhcpd.conf file contains configuration information for .IR dhcpd, the Internet Systems Consortium DHCP Server. .PP The dhcpd.conf file is a free-form ASCII text file. It is parsed by the recursive-descent parser built into dhcpd. The file may contain extra tabs and newlines for formatting purposes. Keywords in the file are case-insensitive. Comments may be placed anywhere within the file (except within quotes). Comments begin with the # character and end at the end of the line. .PP The file essentially consists of a list of statements. Statements fall into two broad categories - parameters and declarations. .PP Parameter statements either say how to do something (e.g., how long a lease to offer), whether to do something (e.g., should dhcpd provide addresses to unknown clients), or what parameters to provide to the client (e.g., use gateway 220.177.244.7). .PP Declarations are used to describe the topology of the network, to describe clients on the network, to provide addresses that can be assigned to clients, or to apply a group of parameters to a group of declarations. In any group of parameters and declarations, all parameters must be specified before any declarations which depend on those parameters may be specified. .PP Declarations about network topology include the \fIshared-network\fR and the \fIsubnet\fR declarations. If clients on a subnet are to be assigned addresses dynamically, a \fIrange\fR declaration must appear within the \fIsubnet\fR declaration. For clients with statically assigned addresses, or for installations where only known clients will be served, each such client must have a \fIhost\fR declaration. If parameters are to be applied to a group of declarations which are not related strictly on a per-subnet basis, the \fIgroup\fR declaration can be used. .PP For every subnet which will be served, and for every subnet to which the dhcp server is connected, there must be one \fIsubnet\fR declaration, which tells dhcpd how to recognize that an address is on that subnet. A \fIsubnet\fR declaration is required for each subnet even if no addresses will be dynamically allocated on that subnet. .PP Some installations have physical networks on which more than one IP subnet operates. For example, if there is a site-wide requirement that 8-bit subnet masks be used, but a department with a single physical ethernet network expands to the point where it has more than 254 nodes, it may be necessary to run two 8-bit subnets on the same ethernet until such time as a new physical network can be added. In this case, the \fIsubnet\fR declarations for these two networks must be enclosed in a \fIshared-network\fR declaration. .PP Note that even when the \fIshared-network\fR declaration is absent, an empty one is created by the server to contain the \fIsubnet\fR (and any scoped parameters included in the \fIsubnet\fR). For practical purposes, this means that "stateless" DHCP clients, which are not tied to addresses (and therefore subnets) will receive the same configuration as stateful ones. .PP Some sites may have departments which have clients on more than one subnet, but it may be desirable to offer those clients a uniform set of parameters which are different than what would be offered to clients from other departments on the same subnet. For clients which will be declared explicitly with \fIhost\fR declarations, these declarations can be enclosed in a \fIgroup\fR declaration along with the parameters which are common to that department. For clients whose addresses will be dynamically assigned, class declarations and conditional declarations may be used to group parameter assignments based on information the client sends. .PP When a client is to be booted, its boot parameters are determined by consulting that client's \fIhost\fR declaration (if any), and then consulting any \fIclass\fR declarations matching the client, followed by the \fIpool\fR, \fIsubnet\fR and \fIshared-network\fR declarations for the IP address assigned to the client. Each of these declarations itself appears within a lexical scope, and all declarations at less specific lexical scopes are also consulted for client option declarations. Scopes are never considered twice, and if parameters are declared in more than one scope, the parameter declared in the most specific scope is the one that is used. .PP When dhcpd tries to find a \fIhost\fR declaration for a client, it first looks for a \fIhost\fR declaration which has a \fIfixed-address\fR declaration that lists an IP address that is valid for the subnet or shared network on which the client is booting. If it doesn't find any such entry, it tries to find an entry which has no \fIfixed-address\fR declaration. .SH EXAMPLES .PP A typical dhcpd.conf file will look something like this: .nf .I global parameters... subnet 204.254.239.0 netmask 255.255.255.224 { \fIsubnet-specific parameters...\fR range 204.254.239.10 204.254.239.30; } subnet 204.254.239.32 netmask 255.255.255.224 { \fIsubnet-specific parameters...\fR range 204.254.239.42 204.254.239.62; } subnet 204.254.239.64 netmask 255.255.255.224 { \fIsubnet-specific parameters...\fR range 204.254.239.74 204.254.239.94; } group { \fIgroup-specific parameters...\fR host zappo.test.isc.org { \fIhost-specific parameters...\fR } host beppo.test.isc.org { \fIhost-specific parameters...\fR } host harpo.test.isc.org { \fIhost-specific parameters...\fR } } .ce 1 Figure 1 .fi .PP Notice that at the beginning of the file, there's a place for global parameters. These might be things like the organization's domain name, the addresses of the name servers (if they are common to the entire organization), and so on. So, for example: .nf option domain-name "isc.org"; option domain-name-servers ns1.isc.org, ns2.isc.org; .ce 1 Figure 2 .fi .PP As you can see in Figure 2, you can specify host addresses in parameters using their domain names rather than their numeric IP addresses. If a given hostname resolves to more than one IP address (for example, if that host has two ethernet interfaces), then where possible, both addresses are supplied to the client. .PP The most obvious reason for having subnet-specific parameters as shown in Figure 1 is that each subnet, of necessity, has its own router. So for the first subnet, for example, there should be something like: .nf option routers 204.254.239.1; .fi .PP Note that the address here is specified numerically. This is not required - if you have a different domain name for each interface on your router, it's perfectly legitimate to use the domain name for that interface instead of the numeric address. However, in many cases there may be only one domain name for all of a router's IP addresses, and it would not be appropriate to use that name here. .PP In Figure 1 there is also a \fIgroup\fR statement, which provides common parameters for a set of three hosts - zappo, beppo and harpo. As you can see, these hosts are all in the test.isc.org domain, so it might make sense for a group-specific parameter to override the domain name supplied to these hosts: .nf option domain-name "test.isc.org"; .fi .PP Also, given the domain they're in, these are probably test machines. If we wanted to test the DHCP leasing mechanism, we might set the lease timeout somewhat shorter than the default: .nf max-lease-time 120; default-lease-time 120; .fi .PP You may have noticed that while some parameters start with the \fIoption\fR keyword, some do not. Parameters starting with the \fIoption\fR keyword correspond to actual DHCP options, while parameters that do not start with the option keyword either control the behavior of the DHCP server (e.g., how long a lease dhcpd will give out), or specify client parameters that are not optional in the DHCP protocol (for example, server-name and filename). .PP In Figure 1, each host had \fIhost-specific parameters\fR. These could include such things as the \fIhostname\fR option, the name of a file to upload (the \fIfilename\fR parameter) and the address of the server from which to upload the file (the \fInext-server\fR parameter). In general, any parameter can appear anywhere that parameters are allowed, and will be applied according to the scope in which the parameter appears. .PP Imagine that you have a site with a lot of NCD X-Terminals. These terminals come in a variety of models, and you want to specify the boot files for each model. One way to do this would be to have host declarations for each server and group them by model: .nf group { filename "Xncd19r"; next-server ncd-booter; host ncd1 { hardware ethernet 0:c0:c3:49:2b:57; } host ncd4 { hardware ethernet 0:c0:c3:80:fc:32; } host ncd8 { hardware ethernet 0:c0:c3:22:46:81; } } group { filename "Xncd19c"; next-server ncd-booter; host ncd2 { hardware ethernet 0:c0:c3:88:2d:81; } host ncd3 { hardware ethernet 0:c0:c3:00:14:11; } } group { filename "XncdHMX"; next-server ncd-booter; host ncd1 { hardware ethernet 0:c0:c3:11:90:23; } host ncd4 { hardware ethernet 0:c0:c3:91:a7:8; } host ncd8 { hardware ethernet 0:c0:c3:cc:a:8f; } } .fi .SH ADDRESS POOLS .PP The .B pool declaration can be used to specify a pool of addresses that will be treated differently than another pool of addresses, even on the same network segment or subnet. For example, you may want to provide a large set of addresses that can be assigned to DHCP clients that are registered to your DHCP server, while providing a smaller set of addresses, possibly with short lease times, that are available for unknown clients. If you have a firewall, you may be able to arrange for addresses from one pool to be allowed access to the Internet, while addresses in another pool are not, thus encouraging users to register their DHCP clients. To do this, you would set up a pair of pool declarations: .PP .nf subnet 10.0.0.0 netmask 255.255.255.0 { option routers 10.0.0.254; # Unknown clients get this pool. pool { option domain-name-servers bogus.example.com; max-lease-time 300; range 10.0.0.200 10.0.0.253; allow unknown-clients; } # Known clients get this pool. pool { option domain-name-servers ns1.example.com, ns2.example.com; max-lease-time 28800; range 10.0.0.5 10.0.0.199; deny unknown-clients; } } .fi .PP It is also possible to set up entirely different subnets for known and unknown clients - address pools exist at the level of shared networks, so address ranges within pool declarations can be on different subnets. .PP As you can see in the preceding example, pools can have permit lists that control which clients are allowed access to the pool and which aren't. Each entry in a pool's permit list is introduced with the .I allow or \fIdeny\fR keyword. If a pool has a permit list, then only those clients that match specific entries on the permit list will be eligible to be assigned addresses from the pool. If a pool has a deny list, then only those clients that do not match any entries on the deny list will be eligible. If both permit and deny lists exist for a pool, then only clients that match the permit list and do not match the deny list will be allowed access. .SH DYNAMIC ADDRESS ALLOCATION Address allocation is actually only done when a client is in the INIT state and has sent a DHCPDISCOVER message. If the client thinks it has a valid lease and sends a DHCPREQUEST to initiate or renew that lease, the server has only three choices - it can ignore the DHCPREQUEST, send a DHCPNAK to tell the client it should stop using the address, or send a DHCPACK, telling the client to go ahead and use the address for a while. .PP If the server finds the address the client is requesting, and that address is available to the client, the server will send a DHCPACK. If the address is no longer available, or the client isn't permitted to have it, the server will send a DHCPNAK. If the server knows nothing about the address, it will remain silent, unless the address is incorrect for the network segment to which the client has been attached and the server is authoritative for that network segment, in which case the server will send a DHCPNAK even though it doesn't know about the address. .PP There may be a host declaration matching the client's identification. If that host declaration contains a fixed-address declaration that lists an IP address that is valid for the network segment to which the client is connected. In this case, the DHCP server will never do dynamic address allocation. In this case, the client is \fIrequired\fR to take the address specified in the host declaration. If the client sends a DHCPREQUEST for some other address, the server will respond with a DHCPNAK. .PP When the DHCP server allocates a new address for a client (remember, this only happens if the client has sent a DHCPDISCOVER), it first looks to see if the client already has a valid lease on an IP address, or if there is an old IP address the client had before that hasn't yet been reassigned. In that case, the server will take that address and check it to see if the client is still permitted to use it. If the client is no longer permitted to use it, the lease is freed if the server thought it was still in use - the fact that the client has sent a DHCPDISCOVER proves to the server that the client is no longer using the lease. .PP If no existing lease is found, or if the client is forbidden to receive the existing lease, then the server will look in the list of address pools for the network segment to which the client is attached for a lease that is not in use and that the client is permitted to have. It looks through each pool declaration in sequence (all .I range declarations that appear outside of pool declarations are grouped into a single pool with no permit list). If the permit list for the pool allows the client to be allocated an address from that pool, the pool is examined to see if there is an address available. If so, then the client is tentatively assigned that address. Otherwise, the next pool is tested. If no addresses are found that can be assigned to the client, no response is sent to the client. .PP If an address is found that the client is permitted to have, and that has never been assigned to any client before, the address is immediately allocated to the client. If the address is available for allocation but has been previously assigned to a different client, the server will keep looking in hopes of finding an address that has never before been assigned to a client. .PP The DHCP server generates the list of available IP addresses from a hash table. This means that the addresses are not sorted in any particular order, and so it is not possible to predict the order in which the DHCP server will allocate IP addresses. Users of previous versions of the ISC DHCP server may have become accustomed to the DHCP server allocating IP addresses in ascending order, but this is no longer possible, and there is no way to configure this behavior with version 3 of the ISC DHCP server. .SH IP ADDRESS CONFLICT PREVENTION The DHCP server checks IP addresses to see if they are in use before allocating them to clients. It does this by sending an ICMP Echo request message to the IP address being allocated. If no ICMP Echo reply is received within a second, the address is assumed to be free. This is only done for leases that have been specified in range statements, and only when the lease is thought by the DHCP server to be free - i.e., the DHCP server or its failover peer has not listed the lease as in use. .PP If a response is received to an ICMP Echo request, the DHCP server assumes that there is a configuration error - the IP address is in use by some host on the network that is not a DHCP client. It marks the address as abandoned, and will not assign it to clients. .PP If a DHCP client tries to get an IP address, but none are available, but there are abandoned IP addresses, then the DHCP server will attempt to reclaim an abandoned IP address. It marks one IP address as free, and then does the same ICMP Echo request check described previously. If there is no answer to the ICMP Echo request, the address is assigned to the client. .PP The DHCP server does not cycle through abandoned IP addresses if the first IP address it tries to reclaim is free. Rather, when the next DHCPDISCOVER comes in from the client, it will attempt a new allocation using the same method described here, and will typically try a new IP address. .SH DHCP FAILOVER This version of the ISC DHCP server supports the DHCP failover protocol as documented in draft-ietf-dhc-failover-12.txt. This is not a final protocol document, and we have not done interoperability testing with other vendors' implementations of this protocol, so you must not assume that this implementation conforms to the standard. If you wish to use the failover protocol, make sure that both failover peers are running the same version of the ISC DHCP server. .PP The failover protocol allows two DHCP servers (and no more than two) to share a common address pool. Each server will have about half of the available IP addresses in the pool at any given time for allocation. If one server fails, the other server will continue to renew leases out of the pool, and will allocate new addresses out of the roughly half of available addresses that it had when communications with the other server were lost. .PP It is possible during a prolonged failure to tell the remaining server that the other server is down, in which case the remaining server will (over time) reclaim all the addresses the other server had available for allocation, and begin to reuse them. This is called putting the server into the PARTNER-DOWN state. .PP You can put the server into the PARTNER-DOWN state either by using the .B omshell (1) command or by stopping the server, editing the last failover state declaration in the lease file, and restarting the server. If you use this last method, change the "my state" line to: .PP .nf .B failover peer "\fIname\fB" state { .B my state partner-down; .B peer state \fIstate\fB at \fIdate\fB; .B } .fi .PP It is only required to change "my state" as shown above. .PP When the other server comes back online, it should automatically detect that it has been offline and request a complete update from the server that was running in the PARTNER-DOWN state, and then both servers will resume processing together. .PP It is possible to get into a dangerous situation: if you put one server into the PARTNER-DOWN state, and then *that* server goes down, and the other server comes back up, the other server will not know that the first server was in the PARTNER-DOWN state, and may issue addresses previously issued by the other server to different clients, resulting in IP address conflicts. Before putting a server into PARTNER-DOWN state, therefore, make .I sure that the other server will not restart automatically. .PP The failover protocol defines a primary server role and a secondary server role. There are some differences in how primaries and secondaries act, but most of the differences simply have to do with providing a way for each peer to behave in the opposite way from the other. So one server must be configured as primary, and the other must be configured as secondary, and it doesn't matter too much which one is which. .SH FAILOVER STARTUP When a server starts that has not previously communicated with its failover peer, it must establish communications with its failover peer and synchronize with it before it can serve clients. This can happen either because you have just configured your DHCP servers to perform failover for the first time, or because one of your failover servers has failed catastrophically and lost its database. .PP The initial recovery process is designed to ensure that when one failover peer loses its database and then resynchronizes, any leases that the failed server gave out before it failed will be honored. When the failed server starts up, it notices that it has no saved failover state, and attempts to contact its peer. .PP When it has established contact, it asks the peer for a complete copy its peer's lease database. The peer then sends its complete database, and sends a message indicating that it is done. The failed server then waits until MCLT has passed, and once MCLT has passed both servers make the transition back into normal operation. This waiting period ensures that any leases the failed server may have given out while out of contact with its partner will have expired. .PP While the failed server is recovering, its partner remains in the partner-down state, which means that it is serving all clients. The failed server provides no service at all to DHCP clients until it has made the transition into normal operation. .PP In the case where both servers detect that they have never before communicated with their partner, they both come up in this recovery state and follow the procedure we have just described. In this case, no service will be provided to DHCP clients until MCLT has expired. .SH CONFIGURING FAILOVER In order to configure failover, you need to write a peer declaration that configures the failover protocol, and you need to write peer references in each pool declaration for which you want to do failover. You do not have to do failover for all pools on a given network segment. You must not tell one server it's doing failover on a particular address pool and tell the other it is not. You must not have any common address pools on which you are not doing failover. A pool declaration that utilizes failover would look like this: .PP .nf pool { failover peer "foo"; \fIpool specific parameters\fR }; .fi .PP The server currently does very little sanity checking, so if you configure it wrong, it will just fail in odd ways. I would recommend therefore that you either do failover or don't do failover, but don't do any mixed pools. Also, use the same master configuration file for both servers, and have a separate file that contains the peer declaration and includes the master file. This will help you to avoid configuration mismatches. As our implementation evolves, this will become less of a problem. A basic sample dhcpd.conf file for a primary server might look like this: .PP .nf failover peer "foo" { primary; address anthrax.rc.vix.com; port 519; peer address trantor.rc.vix.com; peer port 520; max-response-delay 60; max-unacked-updates 10; mclt 3600; split 128; load balance max seconds 3; } include "/etc/dhcpd.master"; .fi .PP The statements in the peer declaration are as follows: .PP The .I primary and .I secondary statements .RS 0.25i .PP [ \fBprimary\fR | \fBsecondary\fR ]\fB;\fR .PP This determines whether the server is primary or secondary, as described earlier under DHCP FAILOVER. .RE .PP The .I address statement .RS 0.25i .PP .B address \fIaddress\fR\fB;\fR .PP The \fBaddress\fR statement declares the IP address or DNS name on which the server should listen for connections from its failover peer, and also the value to use for the DHCP Failover Protocol server identifier. Because this value is used as an identifier, it may not be omitted. .RE .PP The .I peer address statement .RS 0.25i .PP .B peer address \fIaddress\fR\fB;\fR .PP The \fBpeer address\fR statement declares the IP address or DNS name to which the server should connect to reach its failover peer for failover messages. .RE .PP The .I port statement .RS 0.25i .PP .B port \fIport-number\fR\fB;\fR .PP The \fBport\fR statement declares the TCP port on which the server should listen for connections from its failover peer. This statement may be omitted, in which case the IANA assigned port number 647 will be used by default. .RE .PP The .I peer port statement .RS 0.25i .PP .B peer port \fIport-number\fR\fB;\fR .PP The \fBpeer port\fR statement declares the TCP port to which the server should connect to reach its failover peer for failover messages. This statement may be omitted, in which case the IANA assigned port number 647 will be used by default. .RE .PP The .I max-response-delay statement .RS 0.25i .PP .B max-response-delay \fIseconds\fR\fB;\fR .PP The \fBmax-response-delay\fR statement tells the DHCP server how many seconds may pass without receiving a message from its failover peer before it assumes that connection has failed. This number should be small enough that a transient network failure that breaks the connection will not result in the servers being out of communication for a long time, but large enough that the server isn't constantly making and breaking connections. This parameter must be specified. .RE .PP The .I max-unacked-updates statement .RS 0.25i .PP .B max-unacked-updates \fIcount\fR\fB;\fR .PP The \fBmax-unacked-updates\fR statement tells the remote DHCP server how many BNDUPD messages it can send before it receives a BNDACK from the local system. We don't have enough operational experience to say what a good value for this is, but 10 seems to work. This parameter must be specified. .RE .PP The .I mclt statement .RS 0.25i .PP .B mclt \fIseconds\fR\fB;\fR .PP The \fBmclt\fR statement defines the Maximum Client Lead Time. It must be specified on the primary, and may not be specified on the secondary. This is the length of time for which a lease may be renewed by either failover peer without contacting the other. The longer you set this, the longer it will take for the running server to recover IP addresses after moving into PARTNER-DOWN state. The shorter you set it, the more load your servers will experience when they are not communicating. A value of something like 3600 is probably reasonable, but again bear in mind that we have no real operational experience with this. .RE .PP The .I split statement .RS 0.25i .PP .B split \fIindex\fR\fB;\fR .PP The split statement specifies the split between the primary and secondary for the purposes of load balancing. Whenever a client makes a DHCP request, the DHCP server runs a hash on the client identification, resulting in value from 0 to 255. This is used as an index into a 256 bit field. If the bit at that index is set, the primary is responsible. If the bit at that index is not set, the secondary is responsible. The \fBsplit\fR value determines how many of the leading bits are set to one. So, in practice, higher split values will cause the primary to serve more clients than the secondary. Lower split values, the converse. Legal values are between 0 and 255, of which the most reasonable is 128. .RE .PP The .I hba statement .RS 0.25i .PP .B hba \fIcolon-separated-hex-list\fB;\fR .PP The hba statement specifies the split between the primary and secondary as a bitmap rather than a cutoff, which theoretically allows for finer-grained control. In practice, there is probably no need for such fine-grained control, however. An example hba statement: .PP .nf hba ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff: 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00; .fi .PP This is equivalent to a \fBsplit 128;\fR statement, and identical. The following two examples are also equivalent to a \fBsplit\fR of 128, but are not identical: .PP .nf hba aa:aa:aa:aa:aa:aa:aa:aa:aa:aa:aa:aa:aa:aa:aa:aa: aa:aa:aa:aa:aa:aa:aa:aa:aa:aa:aa:aa:aa:aa:aa:aa; hba 55:55:55:55:55:55:55:55:55:55:55:55:55:55:55:55: 55:55:55:55:55:55:55:55:55:55:55:55:55:55:55:55; .fi .PP They are equivalent, because half the bits are set to 0, half are set to 1 (0xa and 0x5 are 1010 and 0101 binary respectively) and consequently this would roughly divide the clients equally between the servers. They are not identical, because the actual peers this would load balance to each server are different for each example. .PP You must only have \fBsplit\fR or \fBhba\fR defined, never both. For most cases, the fine-grained control that \fBhba\fR offers isn't necessary, and \fBsplit\fR should be used. .RE .PP The .I load balance max seconds statement .RS 0.25i .PP .B load balance max seconds \fIseconds\fR\fB;\fR .PP This statement allows you to configure a cutoff after which load balancing is disabled. The cutoff is based on the number of seconds since the client sent its first DHCPDISCOVER or DHCPREQUEST message, and only works with clients that correctly implement the \fIsecs\fR field - fortunately most clients do. We recommend setting this to something like 3 or 5. The effect of this is that if one of the failover peers gets into a state where it is responding to failover messages but not responding to some client requests, the other failover peer will take over its client load automatically as the clients retry. .RE .PP The .I auto-partner-down statement .RS 0.25i .PP .B auto-partner-down \fIseconds\fR\fB;\fR .PP This statement instructs the server to initiate a timed delay upon entering the communications-interrupted state (any situation of being out-of-contact with the remote failover peer). At the conclusion of the timer, the server will automatically enter the partner-down state. This permits the server to allocate leases from the partner's free lease pool after an STOS+MCLT timer expires, which can be dangerous if the partner is in fact operating at the time (the two servers will give conflicting bindings). .PP Think very carefully before enabling this feature. The partner-down and communications-interrupted states are intentionally segregated because there do exist situations where a failover server can fail to communicate with its peer, but still has the ability to receive and reply to requests from DHCP clients. In general, this feature should only be used in those deployments where the failover servers are directly connected to one another, such as by a dedicated hardwired link ("a heartbeat cable"). .PP A zero value disables the auto-partner-down feature (also the default), and any positive value indicates the time in seconds to wait before automatically entering partner-down. .RE .PP The Failover pool balance statements. .RS 0.25i .PP \fBmax-lease-misbalance \fIpercentage\fR\fB;\fR \fBmax-lease-ownership \fIpercentage\fR\fB;\fR \fBmin-balance \fIseconds\fR\fB;\fR \fBmax-balance \fIseconds\fR\fB;\fR .PP This version of the DHCP Server evaluates pool balance on a schedule, rather than on demand as leases are allocated. The latter approach proved to be slightly klunky when pool misbalanced reach total saturation...when any server ran out of leases to assign, it also lost its ability to notice it had run dry. .PP In order to understand pool balance, some elements of its operation first need to be defined. First, there are \'free\' and \'backup\' leases. Both of these are referred to as \'free state leases\'. \'free\' and \'backup\' are \'the free states\' for the purpose of this document. The difference is that only the primary may allocate from \'free\' leases unless under special circumstances, and only the secondary may allocate \'backup\' leases. .PP When pool balance is performed, the only plausible expectation is to provide a 50/50 split of the free state leases between the two servers. This is because no one can predict which server will fail, regardless of the relative load placed upon the two servers, so giving each server half the leases gives both servers the same amount of \'failure endurance\'. Therefore, there is no way to configure any different behaviour, outside of some very small windows we will describe shortly. .PP The first thing calculated on any pool balance run is a value referred to as \'lts\', or "Leases To Send". This, simply, is the difference in the count of free and backup leases, divided by two. For the secondary, it is the difference in the backup and free leases, divided by two. The resulting value is signed: if it is positive, the local server is expected to hand out leases to retain a 50/50 balance. If it is negative, the remote server would need to send leases to balance the pool. Once the lts value reaches zero, the pool is perfectly balanced (give or take one lease in the case of an odd number of total free state leases). .PP The current approach is still something of a hybrid of the old approach, marked by the presence of the \fBmax-lease-misbalance\fR statement. This parameter configures what used to be a 10% fixed value in previous versions: if lts is less than free+backup * \fBmax-lease-misbalance\fR percent, then the server will skip balancing a given pool (it won't bother moving any leases, even if some leases "should" be moved). The meaning of this value is also somewhat overloaded, however, in that it also governs the estimation of when to attempt to balance the pool (which may then also be skipped over). The oldest leases in the free and backup states are examined. The time they have resided in their respective queues is used as an estimate to indicate how much time it is probable it would take before the leases at the top of the list would be consumed (and thus, how long it would take to use all leases in that state). This percentage is directly multiplied by this time, and fit into the schedule if it falls within the \fBmin-balance\fR and \fBmax-balance\fR configured values. The scheduled pool check time is only moved in a downwards direction, it is never increased. Lastly, if the lts is more than double this number in the negative direction, the local server will \'panic\' and transmit a Failover protocol POOLREQ message, in the hopes that the remote system will be woken up into action. .PP Once the lts value exceeds the \fBmax-lease-misbalance\fR percentage of total free state leases as described above, leases are moved to the remote server. This is done in two passes. .PP In the first pass, only leases whose most recent bound client would have been served by the remote server - according to the Load Balance Algorithm (see above \fBsplit\fR and \fBhba\fR configuration statements) - are given away to the peer. This first pass will happily continue to give away leases, decrementing the lts value by one for each, until the lts value has reached the negative of the total number of leases multiplied by the \fBmax-lease-ownership\fR percentage. So it is through this value that you can permit a small misbalance of the lease pools - for the purpose of giving the peer more than a 50/50 share of leases in the hopes that their clients might some day return and be allocated by the peer (operating normally). This process is referred to as \'MAC Address Affinity\', but this is somewhat misnamed: it applies equally to DHCP Client Identifier options. Note also that affinity is applied to leases when they enter the state \'free\' from \'expired\' or \'released\'. In this case also, leases will not be moved from free to backup if the secondary already has more than its share. .PP The second pass is only entered into if the first pass fails to reduce the lts underneath the total number of free state leases multiplied by the \fBmax-lease-ownership\fR percentage. In this pass, the oldest leases are given over to the peer without second thought about the Load Balance Algorithm, and this continues until the lts falls under this value. In this way, the local server will also happily keep a small percentage of the leases that would normally load balance to itself. .PP So, the \fBmax-lease-misbalance\fR value acts as a behavioural gate. Smaller values will cause more leases to transition states to balance the pools over time, higher values will decrease the amount of change (but may lead to pool starvation if there's a run on leases). .PP The \fBmax-lease-ownership\fR value permits a small (percentage) skew in the lease balance of a percentage of the total number of free state leases. .PP Finally, the \fBmin-balance\fR and \fBmax-balance\fR make certain that a scheduled rebalance event happens within a reasonable timeframe (not to be thrown off by, for example, a 7 year old free lease). .PP Plausible values for the percentages lie between 0 and 100, inclusive, but values over 50 are indistinguishable from one another (once lts exceeds 50% of the free state leases, one server must therefore have 100% of the leases in its respective free state). It is recommended to select a \fBmax-lease-ownership\fR value that is lower than the value selected for the \fBmax-lease-misbalance\fR value. \fBmax-lease-ownership\fR defaults to 10, and \fBmax-lease-misbalance\fR defaults to 15. .PP Plausible values for the \fBmin-balance\fR and \fBmax-balance\fR times also range from 0 to (2^32)-1 (or the limit of your local time_t value), but default to values 60 and 3600 respectively (to place balance events between 1 minute and 1 hour). .RE .SH CLIENT CLASSING Clients can be separated into classes, and treated differently depending on what class they are in. This separation can be done either with a conditional statement, or with a match statement within the class declaration. It is possible to specify a limit on the total number of clients within a particular class or subclass that may hold leases at one time, and it is possible to specify automatic subclassing based on the contents of the client packet. .PP To add clients to classes based on conditional evaluation, you can specify a matching expression in the class statement: .PP .nf class "ras-clients" { match if substring (option dhcp-client-identifier, 1, 3) = "RAS"; } .fi .PP Note that whether you use matching expressions or add statements (or both) to classify clients, you must always write a class declaration for any class that you use. If there will be no match statement and no in-scope statements for a class, the declaration should look like this: .PP .nf class "ras-clients" { } .fi .SH SUBCLASSES .PP In addition to classes, it is possible to declare subclasses. A subclass is a class with the same name as a regular class, but with a specific submatch expression which is hashed for quick matching. This is essentially a speed hack - the main difference between five classes with match expressions and one class with five subclasses is that it will be quicker to find the subclasses. Subclasses work as follows: .PP .nf class "allocation-class-1" { match pick-first-value (option dhcp-client-identifier, hardware); } class "allocation-class-2" { match pick-first-value (option dhcp-client-identifier, hardware); } subclass "allocation-class-1" 1:8:0:2b:4c:39:ad; subclass "allocation-class-2" 1:8:0:2b:a9:cc:e3; subclass "allocation-class-1" 1:0:0:c4:aa:29:44; subnet 10.0.0.0 netmask 255.255.255.0 { pool { allow members of "allocation-class-1"; range 10.0.0.11 10.0.0.50; } pool { allow members of "allocation-class-2"; range 10.0.0.51 10.0.0.100; } } .fi .PP The data following the class name in the subclass declaration is a constant value to use in matching the match expression for the class. When class matching is done, the server will evaluate the match expression and then look the result up in the hash table. If it finds a match, the client is considered a member of both the class and the subclass. .PP Subclasses can be declared with or without scope. In the above example, the sole purpose of the subclass is to allow some clients access to one address pool, while other clients are given access to the other pool, so these subclasses are declared without scopes. If part of the purpose of the subclass were to define different parameter values for some clients, you might want to declare some subclasses with scopes. .PP In the above example, if you had a single client that needed some configuration parameters, while most didn't, you might write the following subclass declaration for that client: .PP .nf subclass "allocation-class-2" 1:08:00:2b:a1:11:31 { option root-path "samsara:/var/diskless/alphapc"; filename "/tftpboot/netbsd.alphapc-diskless"; } .fi .PP In this example, we've used subclassing as a way to control address allocation on a per-client basis. However, it's also possible to use subclassing in ways that are not specific to clients - for example, to use the value of the vendor-class-identifier option to determine what values to send in the vendor-encapsulated-options option. An example of this is shown under the VENDOR ENCAPSULATED OPTIONS head in the .B dhcp-options(5) manual page. .SH PER-CLASS LIMITS ON DYNAMIC ADDRESS ALLOCATION .PP You may specify a limit to the number of clients in a class that can be assigned leases. The effect of this will be to make it difficult for a new client in a class to get an address. Once a class with such a limit has reached its limit, the only way a new client in that class can get a lease is for an existing client to relinquish its lease, either by letting it expire, or by sending a DHCPRELEASE packet. Classes with lease limits are specified as follows: .PP .nf class "limited-1" { lease limit 4; } .fi .PP This will produce a class in which a maximum of four members may hold a lease at one time. .SH SPAWNING CLASSES .PP It is possible to declare a .I spawning class\fR. A spawning class is a class that automatically produces subclasses based on what the client sends. The reason that spawning classes were created was to make it possible to create lease-limited classes on the fly. The envisioned application is a cable-modem environment where the ISP wishes to provide clients at a particular site with more than one IP address, but does not wish to provide such clients with their own subnet, nor give them an unlimited number of IP addresses from the network segment to which they are connected. .PP Many cable modem head-end systems can be configured to add a Relay Agent Information option to DHCP packets when relaying them to the DHCP server. These systems typically add a circuit ID or remote ID option that uniquely identifies the customer site. To take advantage of this, you can write a class declaration as follows: .PP .nf class "customer" { spawn with option agent.circuit-id; lease limit 4; } .fi .PP Now whenever a request comes in from a customer site, the circuit ID option will be checked against the class's hash table. If a subclass is found that matches the circuit ID, the client will be classified in that subclass and treated accordingly. If no subclass is found matching the circuit ID, a new one will be created and logged in the .B dhcpd.leases file, and the client will be classified in this new class. Once the client has been classified, it will be treated according to the rules of the class, including, in this case, being subject to the per-site limit of four leases. .PP The use of the subclass spawning mechanism is not restricted to relay agent options - this particular example is given only because it is a fairly straightforward one. .SH COMBINING MATCH, MATCH IF AND SPAWN WITH .PP In some cases, it may be useful to use one expression to assign a client to a particular class, and a second expression to put it into a subclass of that class. This can be done by combining the \fBmatch if\fR and \fBspawn with\fR statements, or the \fBmatch if\fR and \fBmatch\fR statements. For example: .PP .nf class "jr-cable-modems" { match if option dhcp-vendor-identifier = "jrcm"; spawn with option agent.circuit-id; lease limit 4; } class "dv-dsl-modems" { match if option dhcp-vendor-identifier = "dvdsl"; spawn with option agent.circuit-id; lease limit 16; } .fi .PP This allows you to have two classes that both have the same \fBspawn with\fR expression without getting the clients in the two classes confused with each other. .SH DYNAMIC DNS UPDATES .PP The DHCP server has the ability to dynamically update the Domain Name System. Within the configuration files, you can define how you want the Domain Name System to be updated. These updates are RFC 2136 compliant so any DNS server supporting RFC 2136 should be able to accept updates from the DHCP server. .PP Two DNS update schemes are currently implemented, and another is planned. The two that are currently implemented are the ad-hoc DNS update mode and the interim DHCP-DNS interaction draft update mode. In the future we plan to add a third mode which will be the standard DNS update method based on the RFCS for DHCP-DNS interaction and DHCID The DHCP server must be configured to use one of the two currently-supported methods, or not to do dns updates. This can be done with the .I ddns-update-style configuration parameter. .SH THE AD-HOC DNS UPDATE SCHEME The ad-hoc Dynamic DNS update scheme is .B now deprecated and .B does not work. In future releases of the ISC DHCP server, this scheme will not likely be available. The interim scheme works, allows for failover, and should now be used. The following description is left here for informational purposes only. .PP The ad-hoc Dynamic DNS update scheme implemented in this version of the ISC DHCP server is a prototype design, which does not have much to do with the standard update method that is being standardized in the IETF DHC working group, but rather implements some very basic, yet useful, update capabilities. This mode .B does not work with the .I failover protocol because it does not account for the possibility of two different DHCP servers updating the same set of DNS records. .PP For the ad-hoc DNS update method, the client's FQDN is derived in two parts. First, the hostname is determined. Then, the domain name is determined, and appended to the hostname. .PP The DHCP server determines the client's hostname by first looking for a \fIddns-hostname\fR configuration option, and using that if it is present. If no such option is present, the server looks for a valid hostname in the FQDN option sent by the client. If one is found, it is used; otherwise, if the client sent a host-name option, that is used. Otherwise, if there is a host declaration that applies to the client, the name from that declaration will be used. If none of these applies, the server will not have a hostname for the client, and will not be able to do a DNS update. .PP The domain name is determined from the .I ddns-domainname configuration option. The default configuration for this option is: .nf .sp 1 option server.ddns-domainname = config-option domain-name; .fi So if this configuration option is not configured to a different value (over-riding the above default), or if a domain-name option has not been configured for the client's scope, then the server will not attempt to perform a DNS update. .PP The client's fully-qualified domain name, derived as we have described, is used as the name on which an "A" record will be stored. The A record will contain the IP address that the client was assigned in its lease. If there is already an A record with the same name in the DNS server, no update of either the A or PTR records will occur - this prevents a client from claiming that its hostname is the name of some network server. For example, if you have a fileserver called "fs.sneedville.edu", and the client claims its hostname is "fs", no DNS update will be done for that client, and an error message will be logged. .PP If the A record update succeeds, a PTR record update for the assigned IP address will be done, pointing to the A record. This update is unconditional - it will be done even if another PTR record of the same name exists. Since the IP address has been assigned to the DHCP server, this should be safe. .PP Please note that the current implementation assumes clients only have a single network interface. A client with two network interfaces will see unpredictable behavior. This is considered a bug, and will be fixed in a later release. It may be helpful to enable the .I one-lease-per-client parameter so that roaming clients do not trigger this same behavior. .PP The DHCP protocol normally involves a four-packet exchange - first the client sends a DHCPDISCOVER message, then the server sends a DHCPOFFER, then the client sends a DHCPREQUEST, then the server sends a DHCPACK. In the current version of the server, the server will do a DNS update after it has received the DHCPREQUEST, and before it has sent the DHCPACK. It only sends the DNS update if it has not sent one for the client's address before, in order to minimize the impact on the DHCP server. .PP When the client's lease expires, the DHCP server (if it is operating at the time, or when next it operates) will remove the client's A and PTR records from the DNS database. If the client releases its lease by sending a DHCPRELEASE message, the server will likewise remove the A and PTR records. .SH THE INTERIM DNS UPDATE SCHEME The interim DNS update scheme operates mostly according to several drafts considered by the IETF. While the drafts have since become RFCs the code was written before they were finalized and there are some differences between our code and the final RFCs. We plan to update our code, probably adding a standard DNS update option, at some time. The basic framework is similar with the main material difference being that a DHCID RR was assigned in the RFCs whereas our code continues to use an experimental TXT record. The format of the TXT record bears a resemblance to the DHCID RR but it is not equivalent (MD5 vs SHA1, field length differences etc). The standard RFCs are: .PP .nf .ce 3 RFC 4701 (updated by RF5494) RFC 4702 RFC 4703 .fi .PP And the corresponding drafts were: .PP .nf .ce 3 draft-ietf-dnsext-dhcid-rr-??.txt draft-ietf-dhc-fqdn-option-??.txt draft-ietf-dhc-ddns-resolution-??.txt .fi .PP Because our implementation is slightly different than the standard, we will briefly document the operation of this update style here. .PP The first point to understand about this style of DNS update is that unlike the ad-hoc style, the DHCP server does not necessarily always update both the A and the PTR records. The FQDN option includes a flag which, when sent by the client, indicates that the client wishes to update its own A record. In that case, the server can be configured either to honor the client's intentions or ignore them. This is done with the statement \fIallow client-updates;\fR or the statement \fIignore client-updates;\fR. By default, client updates are allowed. .PP If the server is configured to allow client updates, then if the client sends a fully-qualified domain name in the FQDN option, the server will use that name the client sent in the FQDN option to update the PTR record. For example, let us say that the client is a visitor from the "radish.org" domain, whose hostname is "jschmoe". The server is for the "example.org" domain. The DHCP client indicates in the FQDN option that its FQDN is "jschmoe.radish.org.". It also indicates that it wants to update its own A record. The DHCP server therefore does not attempt to set up an A record for the client, but does set up a PTR record for the IP address that it assigns the client, pointing at jschmoe.radish.org. Once the DHCP client has an IP address, it can update its own A record, assuming that the "radish.org" DNS server will allow it to do so. .PP If the server is configured not to allow client updates, or if the client doesn't want to do its own update, the server will simply choose a name for the client from either the fqdn option (if present) or the hostname option (if present). It will use its own domain name for the client, just as in the ad-hoc update scheme. It will then update both the A and PTR record, using the name that it chose for the client. If the client sends a fully-qualified domain name in the fqdn option, the server uses only the leftmost part of the domain name - in the example above, "jschmoe" instead of "jschmoe.radish.org". .PP Further, if the \fIignore client-updates;\fR directive is used, then the server will in addition send a response in the DHCP packet, using the FQDN Option, that implies to the client that it should perform its own updates if it chooses to do so. With \fIdeny client-updates;\fR, a response is sent which indicates the client may not perform updates. .PP Also, if the .I use-host-decl-names configuration option is enabled, then the host declaration's .I hostname will be used in place of the .I hostname option, and the same rules will apply as described above. .PP The other difference between the ad-hoc scheme and the interim scheme is that with the interim scheme, a method is used that allows more than one DHCP server to update the DNS database without accidentally deleting A records that shouldn't be deleted nor failing to add A records that should be added. The scheme works as follows: .PP When the DHCP server issues a client a new lease, it creates a text string that is an MD5 hash over the DHCP client's identification (see draft-ietf-dnsext-dhcid-rr-??.txt for details). The update adds an A record with the name the server chose and a TXT record containing the hashed identifier string (hashid). If this update succeeds, the server is done. .PP If the update fails because the A record already exists, then the DHCP server attempts to add the A record with the prerequisite that there must be a TXT record in the same name as the new A record, and that TXT record's contents must be equal to hashid. If this update succeeds, then the client has its A record and PTR record. If it fails, then the name the client has been assigned (or requested) is in use, and can't be used by the client. At this point the DHCP server gives up trying to do a DNS update for the client until the client chooses a new name. .PP The interim DNS update scheme is called interim for two reasons. First, it does not quite follow the RFCs. The RFCs call for a new DHCID RRtype while he interim DNS update scheme uses a TXT record. The ddns-resolution draft called for the DHCP server to put a DHCID RR on the PTR record, but the \fIinterim\fR update method does not do this. In the final RFC this requirement was relaxed such that a server may add a DHCID RR to the PTR record. .PP In addition to these differences, the server also does not update very aggressively. Because each DNS update involves a round trip to the DNS server, there is a cost associated with doing updates even if they do not actually modify the DNS database. So the DHCP server tracks whether or not it has updated the record in the past (this information is stored on the lease) and does not attempt to update records that it thinks it has already updated. .PP This can lead to cases where the DHCP server adds a record, and then the record is deleted through some other mechanism, but the server never again updates the DNS because it thinks the data is already there. In this case the data can be removed from the lease through operator intervention, and once this has been done, the DNS will be updated the next time the client renews. .SH DYNAMIC DNS UPDATE SECURITY .PP When you set your DNS server up to allow updates from the DHCP server, you may be exposing it to unauthorized updates. To avoid this, you should use TSIG signatures - a method of cryptographically signing updates using a shared secret key. As long as you protect the secrecy of this key, your updates should also be secure. Note, however, that the DHCP protocol itself provides no security, and that clients can therefore provide information to the DHCP server which the DHCP server will then use in its updates, with the constraints described previously. .PP The DNS server must be configured to allow updates for any zone that the DHCP server will be updating. For example, let us say that clients in the sneedville.edu domain will be assigned addresses on the 10.10.17.0/24 subnet. In that case, you will need a key declaration for the TSIG key you will be using, and also two zone declarations - one for the zone containing A records that will be updates and one for the zone containing PTR records - for ISC BIND, something like this: .PP .nf key DHCP_UPDATER { algorithm HMAC-MD5.SIG-ALG.REG.INT; secret pRP5FapFoJ95JEL06sv4PQ==; }; zone "example.org" { type master; file "example.org.db"; allow-update { key DHCP_UPDATER; }; }; zone "17.10.10.in-addr.arpa" { type master; file "10.10.17.db"; allow-update { key DHCP_UPDATER; }; }; .fi .PP You will also have to configure your DHCP server to do updates to these zones. To do so, you need to add something like this to your dhcpd.conf file: .PP .nf key DHCP_UPDATER { algorithm HMAC-MD5.SIG-ALG.REG.INT; secret pRP5FapFoJ95JEL06sv4PQ==; }; zone EXAMPLE.ORG. { primary 127.0.0.1; key DHCP_UPDATER; } zone 17.127.10.in-addr.arpa. { primary 127.0.0.1; key DHCP_UPDATER; } .fi .PP The \fIprimary\fR statement specifies the IP address of the name server whose zone information is to be updated. In addition to the \fIprimary\fR statement there are also the \fIprimary6\fR , \fIsecondary\fR and \fIsecondary6\fR statements. The \fIprimary6\fR statement specifies an IPv6 address for the name server. The secondaries provide for additional addresses for name servers to be used if the primary does not respond. The number of name servers the DDNS code will attempt to use before giving up is limited and is currently set to three. .PP Note that the zone declarations have to correspond to authority records in your name server - in the above example, there must be an SOA record for "example.org." and for "17.10.10.in-addr.arpa.". For example, if there were a subdomain "foo.example.org" with no separate SOA, you could not write a zone declaration for "foo.example.org." Also keep in mind that zone names in your DHCP configuration should end in a "."; this is the preferred syntax. If you do not end your zone name in a ".", the DHCP server will figure it out. Also note that in the DHCP configuration, zone names are not encapsulated in quotes where there are in the DNS configuration. .PP You should choose your own secret key, of course. The ISC BIND 8 and 9 distributions come with a program for generating secret keys called dnssec-keygen. The version that comes with BIND 9 is likely to produce a substantially more random key, so we recommend you use that one even if you are not using BIND 9 as your DNS server. If you are using BIND 9's dnssec-keygen, the above key would be created as follows: .PP .nf dnssec-keygen -a HMAC-MD5 -b 128 -n USER DHCP_UPDATER .fi .PP If you are using the BIND 8 dnskeygen program, the following command will generate a key as seen above: .PP .nf dnskeygen -H 128 -u -c -n DHCP_UPDATER .fi .PP You may wish to enable logging of DNS updates on your DNS server. To do so, you might write a logging statement like the following: .PP .nf logging { channel update_debug { file "/var/log/update-debug.log"; severity debug 3; print-category yes; print-severity yes; print-time yes; }; channel security_info { file "/var/log/named-auth.info"; severity info; print-category yes; print-severity yes; print-time yes; }; category update { update_debug; }; category security { security_info; }; }; .fi .PP You must create the /var/log/named-auth.info and /var/log/update-debug.log files before starting the name server. For more information on configuring ISC BIND, consult the documentation that accompanies it. .SH REFERENCE: EVENTS .PP There are three kinds of events that can happen regarding a lease, and it is possible to declare statements that occur when any of these events happen. These events are the commit event, when the server has made a commitment of a certain lease to a client, the release event, when the client has released the server from its commitment, and the expiry event, when the commitment expires. .PP To declare a set of statements to execute when an event happens, you must use the \fBon\fR statement, followed by the name of the event, followed by a series of statements to execute when the event happens, enclosed in braces. Events are used to implement DNS updates, so you should not define your own event handlers if you are using the built-in DNS update mechanism. .PP The built-in version of the DNS update mechanism is in a text string towards the top of server/dhcpd.c. If you want to use events for things other than DNS updates, and you also want DNS updates, you will have to start out by copying this code into your dhcpd.conf file and modifying it. .SH REFERENCE: DECLARATIONS .PP .B The .I include .B statement .PP .nf \fBinclude\fR \fI"filename"\fR\fB;\fR .fi .PP The \fIinclude\fR statement is used to read in a named file, and process the contents of that file as though it were entered in place of the include statement. .PP .B The .I shared-network .B statement .PP .nf \fBshared-network\fR \fIname\fR \fB{\fR [ \fIparameters\fR ] [ \fIdeclarations\fR ] \fB}\fR .fi .PP The \fIshared-network\fR statement is used to inform the DHCP server that some IP subnets actually share the same physical network. Any subnets in a shared network should be declared within a \fIshared-network\fR statement. Parameters specified in the \fIshared-network\fR statement will be used when booting clients on those subnets unless parameters provided at the subnet or host level override them. If any subnet in a shared network has addresses available for dynamic allocation, those addresses are collected into a common pool for that shared network and assigned to clients as needed. There is no way to distinguish on which subnet of a shared network a client should boot. .PP .I Name should be the name of the shared network. This name is used when printing debugging messages, so it should be descriptive for the shared network. The name may have the syntax of a valid domain name (although it will never be used as such), or it may be any arbitrary name, enclosed in quotes. .PP .B The .I subnet .B statement .PP .nf \fBsubnet\fR \fIsubnet-number\fR \fBnetmask\fR \fInetmask\fR \fB{\fR [ \fIparameters\fR ] [ \fIdeclarations\fR ] \fB}\fR .fi .PP The \fIsubnet\fR statement is used to provide dhcpd with enough information to tell whether or not an IP address is on that subnet. It may also be used to provide subnet-specific parameters and to specify what addresses may be dynamically allocated to clients booting on that subnet. Such addresses are specified using the \fIrange\fR declaration. .PP The .I subnet-number should be an IP address or domain name which resolves to the subnet number of the subnet being described. The .I netmask should be an IP address or domain name which resolves to the subnet mask of the subnet being described. The subnet number, together with the netmask, are sufficient to determine whether any given IP address is on the specified subnet. .PP Although a netmask must be given with every subnet declaration, it is recommended that if there is any variance in subnet masks at a site, a subnet-mask option statement be used in each subnet declaration to set the desired subnet mask, since any subnet-mask option statement will override the subnet mask declared in the subnet statement. .PP .B The .I subnet6 .B statement .PP .nf \fBsubnet6\fR \fIsubnet6-number\fR \fB{\fR [ \fIparameters\fR ] [ \fIdeclarations\fR ] \fB}\fR .fi .PP The \fIsubnet6\fR statement is used to provide dhcpd with enough information to tell whether or not an IPv6 address is on that subnet6. It may also be used to provide subnet-specific parameters and to specify what addresses may be dynamically allocated to clients booting on that subnet. .PP The .I subnet6-number should be an IPv6 network identifier, specified as ip6-address/bits. .PP .B The .I range .B statement .PP .nf .B range\fR [ \fBdynamic-bootp\fR ] \fIlow-address\fR [ \fIhigh-address\fR]\fB;\fR .fi .PP For any subnet on which addresses will be assigned dynamically, there must be at least one \fIrange\fR statement. The range statement gives the lowest and highest IP addresses in a range. All IP addresses in the range should be in the subnet in which the \fIrange\fR statement is declared. The \fIdynamic-bootp\fR flag may be specified if addresses in the specified range may be dynamically assigned to BOOTP clients as well as DHCP clients. When specifying a single address, \fIhigh-address\fR can be omitted. .PP .B The .I range6 .B statement .PP .nf .B range6\fR \fIlow-address\fR \fIhigh-address\fR\fB;\fR .B range6\fR \fIsubnet6-number\fR\fB;\fR .B range6\fR \fIsubnet6-number\fR \fBtemporary\fR\fB;\fR .B range6\fR \fIaddress\fR \fBtemporary\fR\fB;\fR .fi .PP For any IPv6 subnet6 on which addresses will be assigned dynamically, there must be at least one \fIrange6\fR statement. The \fIrange6\fR statement can either be the lowest and highest IPv6 addresses in a \fIrange6\fR, or use CIDR notation, specified as ip6-address/bits. All IP addresses in the \fIrange6\fR should be in the subnet6 in which the \fIrange6\fR statement is declared. .PP The \fItemporary\fR variant makes the prefix (by default on 64 bits) available for temporary (RFC 4941) addresses. A new address per prefix in the shared network is computed at each request with an IA_TA option. Release and Confirm ignores temporary addresses. .PP Any IPv6 addresses given to hosts with \fIfixed-address6\fR are excluded from the \fIrange6\fR, as are IPv6 addresses on the server itself. .PP .PP .B The .I prefix6 .B statement .PP .nf .B prefix6\fR \fIlow-address\fR \fIhigh-address\fR \fB/\fR \fIbits\fR\fB;\fR .fi .PP The \fIprefix6\fR is the \fIrange6\fR equivalent for Prefix Delegation (RFC 3633). Prefixes of \fIbits\fR length are assigned between \fIlow-address\fR and \fIhigh-address\fR. .PP Any IPv6 prefixes given to static entries (hosts) with \fIfixed-prefix6\fR are excluded from the \fIprefix6\fR. .PP This statement is currently global but it should have a shared-network scope. .PP .B The .I host .B statement .PP .nf \fBhost\fR \fIhostname\fR { [ \fIparameters\fR ] [ \fIdeclarations\fR ] \fB}\fR .fi .PP The .B host declaration provides a scope in which to provide configuration information about a specific client, and also provides a way to assign a client a fixed address. The host declaration provides a way for the DHCP server to identify a DHCP or BOOTP client, and also a way to assign the client a static IP address. .PP If it is desirable to be able to boot a DHCP or BOOTP client on more than one subnet with fixed addresses, more than one address may be specified in the .I fixed-address declaration, or more than one .B host statement may be specified matching the same client. .PP If client-specific boot parameters must change based on the network to which the client is attached, then multiple .B host declarations should be used. The .B host declarations will only match a client if one of their .I fixed-address statements is viable on the subnet (or shared network) where the client is attached. Conversely, for a .B host declaration to match a client being allocated a dynamic address, it must not have any .I fixed-address statements. You may therefore need a mixture of .B host declarations for any given client...some having .I fixed-address statements, others without. .PP .I hostname should be a name identifying the host. If a \fIhostname\fR option is not specified for the host, \fIhostname\fR is used. .PP \fIHost\fR declarations are matched to actual DHCP or BOOTP clients by matching the \fRdhcp-client-identifier\fR option specified in the \fIhost\fR declaration to the one supplied by the client, or, if the \fIhost\fR declaration or the client does not provide a \fRdhcp-client-identifier\fR option, by matching the \fIhardware\fR parameter in the \fIhost\fR declaration to the network hardware address supplied by the client. BOOTP clients do not normally provide a \fIdhcp-client-identifier\fR, so the hardware address must be used for all clients that may boot using the BOOTP protocol. .PP DHCPv6 servers can use the \fIhost-identifier option\fR parameter in the \fIhost\fR declaration, and specify any option with a fixed value to identify hosts. .PP Please be aware that .B only the \fIdhcp-client-identifier\fR option and the hardware address can be used to match a host declaration, or the \fIhost-identifier option\fR parameter for DHCPv6 servers. For example, it is not possible to match a host declaration to a \fIhost-name\fR option. This is because the host-name option cannot be guaranteed to be unique for any given client, whereas both the hardware address and \fIdhcp-client-identifier\fR option are at least theoretically guaranteed to be unique to a given client. .PP .B The .I group .B statement .PP .nf \fBgroup\fR { [ \fIparameters\fR ] [ \fIdeclarations\fR ] \fB}\fR .fi .PP The group statement is used simply to apply one or more parameters to a group of declarations. It can be used to group hosts, shared networks, subnets, or even other groups. .SH REFERENCE: ALLOW AND DENY The .I allow and .I deny statements can be used to control the response of the DHCP server to various sorts of requests. The allow and deny keywords actually have different meanings depending on the context. In a pool context, these keywords can be used to set up access lists for address allocation pools. In other contexts, the keywords simply control general server behavior with respect to clients based on scope. In a non-pool context, the .I ignore keyword can be used in place of the .I deny keyword to prevent logging of denied requests. .PP .SH ALLOW DENY AND IGNORE IN SCOPE The following usages of allow and deny will work in any scope, although it is not recommended that they be used in pool declarations. .PP .B The .I unknown-clients .B keyword .PP \fBallow unknown-clients;\fR \fBdeny unknown-clients;\fR \fBignore unknown-clients;\fR .PP The \fBunknown-clients\fR flag is used to tell dhcpd whether or not to dynamically assign addresses to unknown clients. Dynamic address assignment to unknown clients is \fBallow\fRed by default. An unknown client is simply a client that has no host declaration. .PP The use of this option is now \fIdeprecated\fR. If you are trying to restrict access on your network to known clients, you should use \fBdeny unknown-clients;\fR inside of your address pool, as described under the heading ALLOW AND DENY WITHIN POOL DECLARATIONS. .PP .B The .I bootp .B keyword .PP \fBallow bootp;\fR \fBdeny bootp;\fR \fBignore bootp;\fR .PP The \fBbootp\fR flag is used to tell dhcpd whether or not to respond to bootp queries. Bootp queries are \fBallow\fRed by default. .PP .B The .I booting .B keyword .PP \fBallow booting;\fR \fBdeny booting;\fR \fBignore booting;\fR .PP The \fBbooting\fR flag is used to tell dhcpd whether or not to respond to queries from a particular client. This keyword only has meaning when it appears in a host declaration. By default, booting is \fBallow\fRed, but if it is disabled for a particular client, then that client will not be able to get an address from the DHCP server. .PP .B The .I duplicates .B keyword .PP \fBallow duplicates;\fR \fBdeny duplicates;\fR .PP Host declarations can match client messages based on the DHCP Client Identifier option or based on the client's network hardware type and MAC address. If the MAC address is used, the host declaration will match any client with that MAC address - even clients with different client identifiers. This doesn't normally happen, but is possible when one computer has more than one operating system installed on it - for example, Microsoft Windows and NetBSD or Linux. .PP The \fBduplicates\fR flag tells the DHCP server that if a request is received from a client that matches the MAC address of a host declaration, any other leases matching that MAC address should be discarded by the server, even if the UID is not the same. This is a violation of the DHCP protocol, but can prevent clients whose client identifiers change regularly from holding many leases at the same time. By default, duplicates are \fBallow\fRed. .PP .B The .I declines .B keyword .PP \fBallow declines;\fR \fBdeny declines;\fR \fBignore declines;\fR .PP The DHCPDECLINE message is used by DHCP clients to indicate that the lease the server has offered is not valid. When the server receives a DHCPDECLINE for a particular address, it normally abandons that address, assuming that some unauthorized system is using it. Unfortunately, a malicious or buggy client can, using DHCPDECLINE messages, completely exhaust the DHCP server's allocation pool. The server will reclaim these leases, but while the client is running through the pool, it may cause serious thrashing in the DNS, and it will also cause the DHCP server to forget old DHCP client address allocations. .PP The \fBdeclines\fR flag tells the DHCP server whether or not to honor DHCPDECLINE messages. If it is set to \fBdeny\fR or \fBignore\fR in a particular scope, the DHCP server will not respond to DHCPDECLINE messages. .PP .B The .I client-updates .B keyword .PP \fBallow client-updates;\fR \fBdeny client-updates;\fR .PP The \fBclient-updates\fR flag tells the DHCP server whether or not to honor the client's intention to do its own update of its A record. This is only relevant when doing \fIinterim\fR DNS updates. See the documentation under the heading THE INTERIM DNS UPDATE SCHEME for details. .PP .B The .I leasequery .B keyword .PP \fBallow leasequery;\fR \fBdeny leasequery;\fR .PP The \fBleasequery\fR flag tells the DHCP server whether or not to answer DHCPLEASEQUERY packets. The answer to a DHCPLEASEQUERY packet includes information about a specific lease, such as when it was issued and when it will expire. By default, the server will not respond to these packets. .SH ALLOW AND DENY WITHIN POOL DECLARATIONS .PP The uses of the allow and deny keywords shown in the previous section work pretty much the same way whether the client is sending a DHCPDISCOVER or a DHCPREQUEST message - an address will be allocated to the client (either the old address it's requesting, or a new address) and then that address will be tested to see if it's okay to let the client have it. If the client requested it, and it's not okay, the server will send a DHCPNAK message. Otherwise, the server will simply not respond to the client. If it is okay to give the address to the client, the server will send a DHCPACK message. .PP The primary motivation behind pool declarations is to have address allocation pools whose allocation policies are different. A client may be denied access to one pool, but allowed access to another pool on the same network segment. In order for this to work, access control has to be done during address allocation, not after address allocation is done. .PP When a DHCPREQUEST message is processed, address allocation simply consists of looking up the address the client is requesting and seeing if it's still available for the client. If it is, then the DHCP server checks both the address pool permit lists and the relevant in-scope allow and deny statements to see if it's okay to give the lease to the client. In the case of a DHCPDISCOVER message, the allocation process is done as described previously in the ADDRESS ALLOCATION section. .PP When declaring permit lists for address allocation pools, the following syntaxes are recognized following the allow or deny keywords: .PP \fBknown-clients;\fR .PP If specified, this statement either allows or prevents allocation from this pool to any client that has a host declaration (i.e., is known). A client is known if it has a host declaration in \fIany\fR scope, not just the current scope. .PP \fBunknown-clients;\fR .PP If specified, this statement either allows or prevents allocation from this pool to any client that has no host declaration (i.e., is not known). .PP \fBmembers of "\fRclass\fB";\fR .PP If specified, this statement either allows or prevents allocation from this pool to any client that is a member of the named class. .PP \fBdynamic bootp clients;\fR .PP If specified, this statement either allows or prevents allocation from this pool to any bootp client. .PP \fBauthenticated clients;\fR .PP If specified, this statement either allows or prevents allocation from this pool to any client that has been authenticated using the DHCP authentication protocol. This is not yet supported. .PP \fBunauthenticated clients;\fR .PP If specified, this statement either allows or prevents allocation from this pool to any client that has not been authenticated using the DHCP authentication protocol. This is not yet supported. .PP \fBall clients;\fR .PP If specified, this statement either allows or prevents allocation from this pool to all clients. This can be used when you want to write a pool declaration for some reason, but hold it in reserve, or when you want to renumber your network quickly, and thus want the server to force all clients that have been allocated addresses from this pool to obtain new addresses immediately when they next renew. .PP \fBafter \fItime\fR\fB;\fR .PP If specified, this statement either allows or prevents allocation from this pool after a given date. This can be used when you want to move clients from one pool to another. The server adjusts the regular lease time so that the latest expiry time is at the given time+min-lease-time. A short min-lease-time enforces a step change, whereas a longer min-lease-time allows for a gradual change. \fItime\fR is either second since epoch, or a UTC time string e.g. 4 2007/08/24 09:14:32 or a string with time zone offset in seconds e.g. 4 2007/08/24 11:14:32 -7200 .SH REFERENCE: PARAMETERS The .I adaptive-lease-time-threshold statement .RS 0.25i .PP .B adaptive-lease-time-threshold \fIpercentage\fR\fB;\fR .PP When the number of allocated leases within a pool rises above the \fIpercentage\fR given in this statement, the DHCP server decreases the lease length for new clients within this pool to \fImin-lease-time\fR seconds. Clients renewing an already valid (long) leases get at least the remaining time from the current lease. Since the leases expire faster, the server may either recover more quickly or avoid pool exhaustion entirely. Once the number of allocated leases drop below the threshold, the server reverts back to normal lease times. Valid percentages are between 1 and 99. .RE .PP The .I always-broadcast statement .RS 0.25i .PP .B always-broadcast \fIflag\fR\fB;\fR .PP The DHCP and BOOTP protocols both require DHCP and BOOTP clients to set the broadcast bit in the flags field of the BOOTP message header. Unfortunately, some DHCP and BOOTP clients do not do this, and therefore may not receive responses from the DHCP server. The DHCP server can be made to always broadcast its responses to clients by setting this flag to \'on\' for the relevant scope; relevant scopes would be inside a conditional statement, as a parameter for a class, or as a parameter for a host declaration. To avoid creating excess broadcast traffic on your network, we recommend that you restrict the use of this option to as few clients as possible. For example, the Microsoft DHCP client is known not to have this problem, as are the OpenTransport and ISC DHCP clients. .RE .PP The .I always-reply-rfc1048 statement .RS 0.25i .PP .B always-reply-rfc1048 \fIflag\fR\fB;\fR .PP Some BOOTP clients expect RFC1048-style responses, but do not follow RFC1048 when sending their requests. You can tell that a client is having this problem if it is not getting the options you have configured for it and if you see in the server log the message "(non-rfc1048)" printed with each BOOTREQUEST that is logged. .PP If you want to send rfc1048 options to such a client, you can set the .B always-reply-rfc1048 option in that client's host declaration, and the DHCP server will respond with an RFC-1048-style vendor options field. This flag can be set in any scope, and will affect all clients covered by that scope. .RE .PP The .I authoritative statement .RS 0.25i .PP .B authoritative; .PP .B not authoritative; .PP The DHCP server will normally assume that the configuration information about a given network segment is not known to be correct and is not authoritative. This is so that if a naive user installs a DHCP server not fully understanding how to configure it, it does not send spurious DHCPNAK messages to clients that have obtained addresses from a legitimate DHCP server on the network. .PP Network administrators setting up authoritative DHCP servers for their networks should always write \fBauthoritative;\fR at the top of their configuration file to indicate that the DHCP server \fIshould\fR send DHCPNAK messages to misconfigured clients. If this is not done, clients will be unable to get a correct IP address after changing subnets until their old lease has expired, which could take quite a long time. .PP Usually, writing \fBauthoritative;\fR at the top level of the file should be sufficient. However, if a DHCP server is to be set up so that it is aware of some networks for which it is authoritative and some networks for which it is not, it may be more appropriate to declare authority on a per-network-segment basis. .PP Note that the most specific scope for which the concept of authority makes any sense is the physical network segment - either a shared-network statement or a subnet statement that is not contained within a shared-network statement. It is not meaningful to specify that the server is authoritative for some subnets within a shared network, but not authoritative for others, nor is it meaningful to specify that the server is authoritative for some host declarations and not others. .RE .PP The \fIboot-unknown-clients\fR statement .RS 0.25i .PP .B boot-unknown-clients \fIflag\fB;\fR .PP If the \fIboot-unknown-clients\fR statement is present and has a value of \fIfalse\fR or \fIoff\fR, then clients for which there is no .I host declaration will not be allowed to obtain IP addresses. If this statement is not present or has a value of \fItrue\fR or \fIon\fR, then clients without host declarations will be allowed to obtain IP addresses, as long as those addresses are not restricted by .I allow and \fIdeny\fR statements within their \fIpool\fR declarations. .RE .PP The \fIdb-time-format\fR statement .RS 0.25i .PP .B db-time-format \fR[ \fIdefault\fR | \fIlocal\fR ] \fB;\fR .PP The DHCP server software outputs several timestamps when writing leases to persistent storage. This configuration parameter selects one of two output formats. The \fIdefault\fR format prints the day, date, and time in UTC, while the \fIlocal\fR format prints the system seconds-since-epoch, and helpfully provides the day and time in the system timezone in a comment. The time formats are described in detail in the dhcpd.leases(5) manpage. .RE .PP The \fIddns-hostname\fR statement .RS 0.25i .PP .B ddns-hostname \fIname\fB;\fR .PP The \fIname\fR parameter should be the hostname that will be used in setting up the client's A and PTR records. If no ddns-hostname is specified in scope, then the server will derive the hostname automatically, using an algorithm that varies for each of the different update methods. .RE .PP The \fIddns-domainname\fR statement .RS 0.25i .PP .B ddns-domainname \fIname\fB;\fR .PP The \fIname\fR parameter should be the domain name that will be appended to the client's hostname to form a fully-qualified domain-name (FQDN). .RE .PP The \fIddns-rev-domainname\fR statement .RS 0.25i .PP .B ddns-rev-domainname \fIname\fB;\fR The \fIname\fR parameter should be the domain name that will be appended to the client's reversed IP address to produce a name for use in the client's PTR record. By default, this is "in-addr.arpa.", but the default can be overridden here. .PP The reversed IP address to which this domain name is appended is always the IP address of the client, in dotted quad notation, reversed - for example, if the IP address assigned to the client is 10.17.92.74, then the reversed IP address is 74.92.17.10. So a client with that IP address would, by default, be given a PTR record of 10.17.92.74.in-addr.arpa. .RE .PP The \fIddns-update-style\fR parameter .RS 0.25i .PP .B ddns-update-style \fIstyle\fB;\fR .PP The .I style parameter must be one of \fBad-hoc\fR, \fBinterim\fR or \fBnone\fR. The \fIddns-update-style\fR statement is only meaningful in the outer scope - it is evaluated once after reading the dhcpd.conf file, rather than each time a client is assigned an IP address, so there is no way to use different DNS update styles for different clients. The default is \fBnone\fR. .RE .PP .B The .I ddns-updates .B statement .RS 0.25i .PP \fBddns-updates \fIflag\fR\fB;\fR .PP The \fIddns-updates\fR parameter controls whether or not the server will attempt to do a DNS update when a lease is confirmed. Set this to \fIoff\fR if the server should not attempt to do updates within a certain scope. The \fIddns-updates\fR parameter is on by default. To disable DNS updates in all scopes, it is preferable to use the \fIddns-update-style\fR statement, setting the style to \fInone\fR. .RE .PP The .I default-lease-time statement .RS 0.25i .PP .B default-lease-time \fItime\fR\fB;\fR .PP .I Time should be the length in seconds that will be assigned to a lease if the client requesting the lease does not ask for a specific expiration time. This is used for both DHCPv4 and DHCPv6 leases (it is also known as the "valid lifetime" in DHCPv6). The default is 43200 seconds. .RE .PP The .I delayed-ack and .I max-ack-delay statements .RS 0.25i .PP .B delayed-ack \fIcount\fR\fB;\fR .B max-ack-delay \fImicroseconds\fR\fB;\fR .PP .I Count should be an integer value from zero to 2^16-1, and defaults to 28. The count represents how many DHCPv4 replies maximum will be queued pending transmission until after a database commit event. If this number is reached, a database commit event (commonly resulting in fsync() and representing a performance penalty) will be made, and the reply packets will be transmitted in a batch afterwards. This preserves the RFC2131 direction that "stable storage" be updated prior to replying to clients. Should the DHCPv4 sockets "go dry" (select() returns immediately with no read sockets), the commit is made and any queued packets are transmitted. .PP Similarly, \fImicroseconds\fR indicates how many microseconds are permitted to pass inbetween queuing a packet pending an fsync, and performing the fsync. Valid values range from 0 to 2^32-1, and defaults to 250,000 (1/4 of a second). .PP Please note that as delayed-ack is currently experimental, the delayed-ack feature is not compiled in by default, but must be enabled at compile time with \'./configure --enable-delayed-ack\'. .RE .PP The .I do-forward-updates statement .RS 0.25i .PP .B do-forward-updates \fIflag\fB;\fR .PP The \fIdo-forward-updates\fR statement instructs the DHCP server as to whether it should attempt to update a DHCP client's A record when the client acquires or renews a lease. This statement has no effect unless DNS updates are enabled and \fBddns-update-style\fR is set to \fBinterim\fR. Forward updates are enabled by default. If this statement is used to disable forward updates, the DHCP server will never attempt to update the client's A record, and will only ever attempt to update the client's PTR record if the client supplies an FQDN that should be placed in the PTR record using the fqdn option. If forward updates are enabled, the DHCP server will still honor the setting of the \fBclient-updates\fR flag. .RE .PP The .I dynamic-bootp-lease-cutoff statement .RS 0.25i .PP .B dynamic-bootp-lease-cutoff \fIdate\fB;\fR .PP The \fIdynamic-bootp-lease-cutoff\fR statement sets the ending time for all leases assigned dynamically to BOOTP clients. Because BOOTP clients do not have any way of renewing leases, and don't know that their leases could expire, by default dhcpd assigns infinite leases to all BOOTP clients. However, it may make sense in some situations to set a cutoff date for all BOOTP leases - for example, the end of a school term, or the time at night when a facility is closed and all machines are required to be powered off. .PP .I Date should be the date on which all assigned BOOTP leases will end. The date is specified in the form: .PP .ce 1 W YYYY/MM/DD HH:MM:SS .PP W is the day of the week expressed as a number from zero (Sunday) to six (Saturday). YYYY is the year, including the century. MM is the month expressed as a number from 1 to 12. DD is the day of the month, counting from 1. HH is the hour, from zero to 23. MM is the minute and SS is the second. The time is always in Coordinated Universal Time (UTC), not local time. .RE .PP The .I dynamic-bootp-lease-length statement .RS 0.25i .PP .B dynamic-bootp-lease-length\fR \fIlength\fR\fB;\fR .PP The \fIdynamic-bootp-lease-length\fR statement is used to set the length of leases dynamically assigned to BOOTP clients. At some sites, it may be possible to assume that a lease is no longer in use if its holder has not used BOOTP or DHCP to get its address within a certain time period. The period is specified in \fIlength\fR as a number of seconds. If a client reboots using BOOTP during the timeout period, the lease duration is reset to \fIlength\fR, so a BOOTP client that boots frequently enough will never lose its lease. Needless to say, this parameter should be adjusted with extreme caution. .RE .PP The .I filename statement .RS 0.25i .PP .B filename\fR \fB"\fR\fIfilename\fR\fB";\fR .PP The \fIfilename\fR statement can be used to specify the name of the initial boot file which is to be loaded by a client. The .I filename should be a filename recognizable to whatever file transfer protocol the client can be expected to use to load the file. .RE .PP The .I fixed-address declaration .RS 0.25i .PP .B fixed-address address\fR [\fB,\fR \fIaddress\fR ... ]\fB;\fR .PP The \fIfixed-address\fR declaration is used to assign one or more fixed IP addresses to a client. It should only appear in a \fIhost\fR declaration. If more than one address is supplied, then when the client boots, it will be assigned the address that corresponds to the network on which it is booting. If none of the addresses in the \fIfixed-address\fR statement are valid for the network to which the client is connected, that client will not match the \fIhost\fR declaration containing that \fIfixed-address\fR declaration. Each \fIaddress\fR in the \fIfixed-address\fR declaration should be either an IP address or a domain name that resolves to one or more IP addresses. .RE .PP The .I fixed-address6 declaration .RS 0.25i .PP .B fixed-address6 ip6-address\fR ;\fR .PP The \fIfixed-address6\fR declaration is used to assign a fixed IPv6 addresses to a client. It should only appear in a \fIhost\fR declaration. .RE .PP The .I get-lease-hostnames statement .RS 0.25i .PP .B get-lease-hostnames\fR \fIflag\fR\fB;\fR .PP The \fIget-lease-hostnames\fR statement is used to tell dhcpd whether or not to look up the domain name corresponding to the IP address of each address in the lease pool and use that address for the DHCP \fIhostname\fR option. If \fIflag\fR is true, then this lookup is done for all addresses in the current scope. By default, or if \fIflag\fR is false, no lookups are done. .RE .PP The .I hardware statement .RS 0.25i .PP .B hardware \fIhardware-type hardware-address\fB;\fR .PP In order for a BOOTP client to be recognized, its network hardware address must be declared using a \fIhardware\fR clause in the .I host statement. .I hardware-type must be the name of a physical hardware interface type. Currently, only the .B ethernet and .B token-ring types are recognized, although support for a .B fddi hardware type (and others) would also be desirable. The .I hardware-address should be a set of hexadecimal octets (numbers from 0 through ff) separated by colons. The \fIhardware\fR statement may also be used for DHCP clients. .RE .PP The .I host-identifier option statement .RS 0.25i .PP .B host-identifier option \fIoption-name option-data\fB;\fR .PP This identifies a DHCPv6 client in a .I host statement. .I option-name is any option, and .I option-data is the value for the option that the client will send. The .I option-data must be a constant value. .RE .PP The .I infinite-is-reserved statement .RS 0.25i .PP .B infinite-is-reserved \fIflag\fB;\fR .PP ISC DHCP now supports \'reserved\' leases. See the section on RESERVED LEASES below. If this \fIflag\fR is on, the server will automatically reserve leases allocated to clients which requested an infinite (0xffffffff) lease-time. .PP The default is off. .RE .PP The .I lease-file-name statement .RS 0.25i .PP .B lease-file-name \fIname\fB;\fR .PP .I Name should be the name of the DHCP server's lease file. By default, this is DBDIR/dhcpd.leases. This statement \fBmust\fR appear in the outer scope of the configuration file - if it appears in some other scope, it will have no effect. Furthermore, it has no effect if overridden by the .B -lf flag or the .B PATH_DHCPD_DB environment variable. .RE .PP The .I limit-addrs-per-ia statement .RS 0.25i .PP .B limit-addrs-per-ia \fInumber\fB;\fR .PP By default, the DHCPv6 server will limit clients to one IAADDR per IA option, meaning one address. If you wish to permit clients to hang onto multiple addresses at a time, configure a larger \fInumber\fR here. .PP Note that there is no present method to configure the server to forcibly configure the client with one IP address per each subnet on a shared network. This is left to future work. .RE .PP The .I dhcpv6-lease-file-name statement .RS 0.25i .PP .B dhcpv6-lease-file-name \fIname\fB;\fR .PP .I Name is the name of the lease file to use if and only if the server is running in DHCPv6 mode. By default, this is DBDIR/dhcpd6.leases. This statement, like .I lease-file-name, \fBmust\fR appear in the outer scope of the configuration file. It has no effect if overridden by the .B -lf flag or the .B PATH_DHCPD6_DB environment variable. If .I dhcpv6-lease-file-name is not specified, but .I lease-file-name is, the latter value will be used. .RE .PP The .I local-port statement .RS 0.25i .PP .B local-port \fIport\fB;\fR .PP This statement causes the DHCP server to listen for DHCP requests on the UDP port specified in \fIport\fR, rather than on port 67. .RE .PP The .I local-address statement .RS 0.25i .PP .B local-address \fIaddress\fB;\fR .PP This statement causes the DHCP server to listen for DHCP requests sent to the specified \fIaddress\fR, rather than requests sent to all addresses. Since serving directly attached DHCP clients implies that the server must respond to requests sent to the all-ones IP address, this option cannot be used if clients are on directly attached networks...it is only realistically useful for a server whose only clients are reached via unicasts, such as via DHCP relay agents. .PP Note: This statement is only effective if the server was compiled using the USE_SOCKETS #define statement, which is default on a small number of operating systems, and must be explicitly chosen at compile-time for all others. You can be sure if your server is compiled with USE_SOCKETS if you see lines of this format at startup: .PP Listening on Socket/eth0 .PP Note also that since this bind()s all DHCP sockets to the specified address, that only one address may be supported in a daemon at a given time. .RE .PP The .I log-facility statement .RS 0.25i .PP .B log-facility \fIfacility\fB;\fR .PP This statement causes the DHCP server to do all of its logging on the specified log facility once the dhcpd.conf file has been read. By default the DHCP server logs to the daemon facility. Possible log facilities include auth, authpriv, cron, daemon, ftp, kern, lpr, mail, mark, news, ntp, security, syslog, user, uucp, and local0 through local7. Not all of these facilities are available on all systems, and there may be other facilities available on other systems. .PP In addition to setting this value, you may need to modify your .I syslog.conf file to configure logging of the DHCP server. For example, you might add a line like this: .PP .nf local7.debug /var/log/dhcpd.log .fi .PP The syntax of the \fIsyslog.conf\fR file may be different on some operating systems - consult the \fIsyslog.conf\fR manual page to be sure. To get syslog to start logging to the new file, you must first create the file with correct ownership and permissions (usually, the same owner and permissions of your /var/log/messages or /usr/adm/messages file should be fine) and send a SIGHUP to syslogd. Some systems support log rollover using a shell script or program called newsyslog or logrotate, and you may be able to configure this as well so that your log file doesn't grow uncontrollably. .PP Because the \fIlog-facility\fR setting is controlled by the dhcpd.conf file, log messages printed while parsing the dhcpd.conf file or before parsing it are logged to the default log facility. To prevent this, see the README file included with this distribution, which describes how to change the default log facility. When this parameter is used, the DHCP server prints its startup message a second time after parsing the configuration file, so that the log will be as complete as possible. .RE .PP The .I max-lease-time statement .RS 0.25i .PP .B max-lease-time \fItime\fR\fB;\fR .PP .I Time should be the maximum length in seconds that will be assigned to a lease. If not defined, the default maximum lease time is 86400. The only exception to this is that Dynamic BOOTP lease lengths, which are not specified by the client, are not limited by this maximum. .RE .PP The .I min-lease-time statement .RS 0.25i .PP .B min-lease-time \fItime\fR\fB;\fR .PP .I Time should be the minimum length in seconds that will be assigned to a lease. The default is the minimum of 300 seconds or \fBmax-lease-time\fR. .RE .PP The .I min-secs statement .RS 0.25i .PP .B min-secs \fIseconds\fR\fB;\fR .PP .I Seconds should be the minimum number of seconds since a client began trying to acquire a new lease before the DHCP server will respond to its request. The number of seconds is based on what the client reports, and the maximum value that the client can report is 255 seconds. Generally, setting this to one will result in the DHCP server not responding to the client's first request, but always responding to its second request. .PP This can be used to set up a secondary DHCP server which never offers an address to a client until the primary server has been given a chance to do so. If the primary server is down, the client will bind to the secondary server, but otherwise clients should always bind to the primary. Note that this does not, by itself, permit a primary server and a secondary server to share a pool of dynamically-allocatable addresses. .RE .PP The .I next-server statement .RS 0.25i .PP .B next-server\fR \fIserver-name\fR\fB;\fR .PP The \fInext-server\fR statement is used to specify the host address of the server from which the initial boot file (specified in the \fIfilename\fR statement) is to be loaded. \fIServer-name\fR should be a numeric IP address or a domain name. .RE .PP The .I omapi-port statement .RS 0.25i .PP .B omapi-port\fR \fIport\fR\fB;\fR .PP The \fIomapi-port\fR statement causes the DHCP server to listen for OMAPI connections on the specified port. This statement is required to enable the OMAPI protocol, which is used to examine and modify the state of the DHCP server as it is running. .RE .PP The .I one-lease-per-client statement .RS 0.25i .PP .B one-lease-per-client \fIflag\fR\fB;\fR .PP If this flag is enabled, whenever a client sends a DHCPREQUEST for a particular lease, the server will automatically free any other leases the client holds. This presumes that when the client sends a DHCPREQUEST, it has forgotten any lease not mentioned in the DHCPREQUEST - i.e., the client has only a single network interface .I and it does not remember leases it's holding on networks to which it is not currently attached. Neither of these assumptions are guaranteed or provable, so we urge caution in the use of this statement. .RE .PP The .I pid-file-name statement .RS 0.25i .PP .B pid-file-name .I name\fR\fB;\fR .PP .I Name should be the name of the DHCP server's process ID file. This is the file in which the DHCP server's process ID is stored when the server starts. By default, this is RUNDIR/dhcpd.pid. Like the .I lease-file-name statement, this statement must appear in the outer scope of the configuration file. It has no effect if overridden by the .B -pf flag or the .B PATH_DHCPD_PID environment variable. .PP The .I dhcpv6-pid-file-name statement .RS 0.25i .PP .B dhcpv6-pid-file-name \fIname\fB;\fR .PP .I Name is the name of the pid file to use if and only if the server is running in DHCPv6 mode. By default, this is DBDIR/dhcpd6.pid. This statement, like .I pid-file-name, \fBmust\fR appear in the outer scope of the configuration file. It has no effect if overridden by the .B -pf flag or the .B PATH_DHCPD6_PID environment variable. If .I dhcpv6-pid-file-name is not specified, but .I pid-file-name is, the latter value will be used. .RE .PP The .I ping-check statement .RS 0.25i .PP .B ping-check .I flag\fR\fB;\fR .PP When the DHCP server is considering dynamically allocating an IP address to a client, it first sends an ICMP Echo request (a \fIping\fR) to the address being assigned. It waits for a second, and if no ICMP Echo response has been heard, it assigns the address. If a response \fIis\fR heard, the lease is abandoned, and the server does not respond to the client. .PP This \fIping check\fR introduces a default one-second delay in responding to DHCPDISCOVER messages, which can be a problem for some clients. The default delay of one second may be configured using the ping-timeout parameter. The ping-check configuration parameter can be used to control checking - if its value is false, no ping check is done. .RE .PP The .I ping-timeout statement .RS 0.25i .PP .B ping-timeout .I seconds\fR\fB;\fR .PP If the DHCP server determined it should send an ICMP echo request (a \fIping\fR) because the ping-check statement is true, ping-timeout allows you to configure how many seconds the DHCP server should wait for an ICMP Echo response to be heard, if no ICMP Echo response has been received before the timeout expires, it assigns the address. If a response \fIis\fR heard, the lease is abandoned, and the server does not respond to the client. If no value is set, ping-timeout defaults to 1 second. .RE .PP The .I preferred-lifetime statement .RS 0.25i .PP .B preferred-lifetime .I seconds\fR\fB;\fR .PP IPv6 addresses have \'valid\' and \'preferred\' lifetimes. The valid lifetime determines at what point at lease might be said to have expired, and is no longer useable. A preferred lifetime is an advisory condition to help applications move off of the address and onto currently valid addresses (should there still be any open TCP sockets or similar). .PP The preferred lifetime defaults to the renew+rebind timers, or 3/4 the default lease time if none were specified. .RE .PP The .I remote-port statement .RS 0.25i .PP .B remote-port \fIport\fB;\fR .PP This statement causes the DHCP server to transmit DHCP responses to DHCP clients upon the UDP port specified in \fIport\fR, rather than on port 68. In the event that the UDP response is transmitted to a DHCP Relay, the server generally uses the \fBlocal-port\fR configuration value. Should the DHCP Relay happen to be addressed as 127.0.0.1, however, the DHCP Server transmits its response to the \fBremote-port\fR configuration value. This is generally only useful for testing purposes, and this configuration value should generally not be used. .RE .PP The .I server-identifier statement .RS 0.25i .PP .B server-identifier \fIhostname\fR\fB;\fR .PP The server-identifier statement can be used to define the value that is sent in the DHCP Server Identifier option for a given scope. The value specified \fBmust\fR be an IP address for the DHCP server, and must be reachable by all clients served by a particular scope. .PP The use of the server-identifier statement is not recommended - the only reason to use it is to force a value other than the default value to be sent on occasions where the default value would be incorrect. The default value is the first IP address associated with the physical network interface on which the request arrived. .PP The usual case where the \fIserver-identifier\fR statement needs to be sent is when a physical interface has more than one IP address, and the one being sent by default isn't appropriate for some or all clients served by that interface. Another common case is when an alias is defined for the purpose of having a consistent IP address for the DHCP server, and it is desired that the clients use this IP address when contacting the server. .PP Supplying a value for the dhcp-server-identifier option is equivalent to using the server-identifier statement. .RE .PP The .I server-duid statement .RS 0.25i .PP .B server-duid \fILLT\fR [ \fIhardware-type\fR \fItimestamp\fR \fIhardware-address\fR ] \fB;\fR .B server-duid \fIEN\fR \fIenterprise-number\fR \fIenterprise-identifier\fR \fB;\fR .B server-duid \fILL\fR [ \fIhardware-type\fR \fIhardware-address\fR ] \fB;\fR .PP The server-duid statement configures the server DUID. You may pick either LLT (link local address plus time), EN (enterprise), or LL (link local). .PP If you choose LLT or LL, you may specify the exact contents of the DUID. Otherwise the server will generate a DUID of the specified type. .PP If you choose EN, you must include the enterprise number and the enterprise-identifier. .PP The default server-duid type is LLT. .RE .PP The .I server-name statement .RS 0.25i .PP .B server-name "\fIname\fB";\fR .PP The \fIserver-name\fR statement can be used to inform the client of the name of the server from which it is booting. \fIName\fR should be the name that will be provided to the client. .RE .PP The .I site-option-space statement .RS 0.25i .PP .B site-option-space "\fIname\fB";\fR .PP The \fIsite-option-space\fR statement can be used to determine from what option space site-local options will be taken. This can be used in much the same way as the \fIvendor-option-space\fR statement. Site-local options in DHCP are those options whose numeric codes are greater than 224. These options are intended for site-specific uses, but are frequently used by vendors of embedded hardware that contains DHCP clients. Because site-specific options are allocated on an ad hoc basis, it is quite possible that one vendor's DHCP client might use the same option code that another vendor's client uses, for different purposes. The \fIsite-option-space\fR option can be used to assign a different set of site-specific options for each such vendor, using conditional evaluation (see \fBdhcp-eval (5)\fR for details). .RE .PP The .I stash-agent-options statement .RS 0.25i .PP .B stash-agent-options \fIflag\fB;\fR .PP If the \fIstash-agent-options\fR parameter is true for a given client, the server will record the relay agent information options sent during the client's initial DHCPREQUEST message when the client was in the SELECTING state and behave as if those options are included in all subsequent DHCPREQUEST messages sent in the RENEWING state. This works around a problem with relay agent information options, which is that they usually not appear in DHCPREQUEST messages sent by the client in the RENEWING state, because such messages are unicast directly to the server and not sent through a relay agent. .RE .PP The .I update-conflict-detection statement .RS 0.25i .PP .B update-conflict-detection \fIflag\fB;\fR .PP If the \fIupdate-conflict-detection\fR parameter is true, the server will perform standard DHCID multiple-client, one-name conflict detection. If the parameter has been set false, the server will skip this check and instead simply tear down any previous bindings to install the new binding without question. The default is true. .RE .PP The .I update-optimization statement .RS 0.25i .PP .B update-optimization \fIflag\fB;\fR .PP If the \fIupdate-optimization\fR parameter is false for a given client, the server will attempt a DNS update for that client each time the client renews its lease, rather than only attempting an update when it appears to be necessary. This will allow the DNS to heal from database inconsistencies more easily, but the cost is that the DHCP server must do many more DNS updates. We recommend leaving this option enabled, which is the default. This option only affects the behavior of the interim DNS update scheme, and has no effect on the ad-hoc DNS update scheme. If this parameter is not specified, or is true, the DHCP server will only update when the client information changes, the client gets a different lease, or the client's lease expires. .RE .PP The .I update-static-leases statement .RS 0.25i .PP .B update-static-leases \fIflag\fB;\fR .PP The \fIupdate-static-leases\fR flag, if enabled, causes the DHCP server to do DNS updates for clients even if those clients are being assigned their IP address using a \fIfixed-address\fR statement - that is, the client is being given a static assignment. This can only work with the \fIinterim\fR DNS update scheme. It is not recommended because the DHCP server has no way to tell that the update has been done, and therefore will not delete the record when it is not in use. Also, the server must attempt the update each time the client renews its lease, which could have a significant performance impact in environments that place heavy demands on the DHCP server. .RE .PP The .I use-host-decl-names statement .RS 0.25i .PP .B use-host-decl-names \fIflag\fB;\fR .PP If the \fIuse-host-decl-names\fR parameter is true in a given scope, then for every host declaration within that scope, the name provided for the host declaration will be supplied to the client as its hostname. So, for example, .PP .nf group { use-host-decl-names on; host joe { hardware ethernet 08:00:2b:4c:29:32; fixed-address joe.fugue.com; } } is equivalent to host joe { hardware ethernet 08:00:2b:4c:29:32; fixed-address joe.fugue.com; option host-name "joe"; } .fi .PP An \fIoption host-name\fR statement within a host declaration will override the use of the name in the host declaration. .PP It should be noted here that most DHCP clients completely ignore the host-name option sent by the DHCP server, and there is no way to configure them not to do this. So you generally have a choice of either not having any hostname to client IP address mapping that the client will recognize, or doing DNS updates. It is beyond the scope of this document to describe how to make this determination. .RE .PP The .I use-lease-addr-for-default-route statement .RS 0.25i .PP .B use-lease-addr-for-default-route \fIflag\fR\fB;\fR .PP If the \fIuse-lease-addr-for-default-route\fR parameter is true in a given scope, then instead of sending the value specified in the routers option (or sending no value at all), the IP address of the lease being assigned is sent to the client. This supposedly causes Win95 machines to ARP for all IP addresses, which can be helpful if your router is configured for proxy ARP. The use of this feature is not recommended, because it won't work for many DHCP clients. .RE .PP The .I vendor-option-space statement .RS 0.25i .PP .B vendor-option-space \fIstring\fR\fB;\fR .PP The \fIvendor-option-space\fR parameter determines from what option space vendor options are taken. The use of this configuration parameter is illustrated in the \fBdhcp-options(5)\fR manual page, in the \fIVENDOR ENCAPSULATED OPTIONS\fR section. .RE .SH SETTING PARAMETER VALUES USING EXPRESSIONS Sometimes it's helpful to be able to set the value of a DHCP server parameter based on some value that the client has sent. To do this, you can use expression evaluation. The .B dhcp-eval(5) manual page describes how to write expressions. To assign the result of an evaluation to an option, define the option as follows: .nf .sp 1 \fImy-parameter \fB= \fIexpression \fB;\fR .fi .PP For example: .nf .sp 1 ddns-hostname = binary-to-ascii (16, 8, "-", substring (hardware, 1, 6)); .fi .RE .SH RESERVED LEASES It's often useful to allocate a single address to a single client, in approximate perpetuity. Host statements with \fBfixed-address\fR clauses exist to a certain extent to serve this purpose, but because host statements are intended to approximate \'static configuration\', they suffer from not being referenced in a littany of other Server Services, such as dynamic DNS, failover, \'on events\' and so forth. .PP If a standard dynamic lease, as from any range statement, is marked \'reserved\', then the server will only allocate this lease to the client it is identified by (be that by client identifier or hardware address). .PP In practice, this means that the lease follows the normal state engine, enters ACTIVE state when the client is bound to it, expires, or is released, and any events or services that would normally be supplied during these events are processed normally, as with any other dynamic lease. The only difference is that failover servers treat reserved leases as special when they enter the FREE or BACKUP states - each server applies the lease into the state it may allocate from - and the leases are not placed on the queue for allocation to other clients. Instead they may only be \'found\' by client identity. The result is that the lease is only offered to the returning client. .PP Care should probably be taken to ensure that the client only has one lease within a given subnet that it is identified by. .PP Leases may be set \'reserved\' either through OMAPI, or through the \'infinite-is-reserved\' configuration option (if this is applicable to your environment and mixture of clients). .PP It should also be noted that leases marked \'reserved\' are effectively treated the same as leases marked \'bootp\'. .RE .SH REFERENCE: OPTION STATEMENTS DHCP option statements are documented in the .B dhcp-options(5) manual page. .SH REFERENCE: EXPRESSIONS Expressions used in DHCP option statements and elsewhere are documented in the .B dhcp-eval(5) manual page. .SH SEE ALSO dhcpd(8), dhcpd.leases(5), dhcp-options(5), dhcp-eval(5), RFC2132, RFC2131. .SH AUTHOR .B dhcpd.conf(5) was written by Ted Lemon under a contract with Vixie Labs. Funding for this project was provided by Internet Systems Consortium. Information about Internet Systems Consortium can be found at .B https://www.isc.org. dhcp-4.2.4/server/dhcpd.leases.5000644 000765 000024 00000031145 11635505666 016341 0ustar00sarstaff000000 000000 .\" dhcpd.leases.5 .\" .\" Copyright (c) 2004,2009 by Internet Systems Consortium, Inc. ("ISC") .\" Copyright (c) 1996-2003 by Internet Software Consortium .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above .\" copyright notice and this permission notice appear in all copies. .\" .\" THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES .\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR .\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES .\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT .\" OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" .\" Internet Systems Consortium, Inc. .\" 950 Charter Street .\" Redwood City, CA 94063 .\" .\" https://www.isc.org/ .\" .\" This software has been written for Internet Systems Consortium .\" by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. .\" To learn more about Internet Systems Consortium, see .\" ``https://www.isc.org/''. To learn more about Vixie Enterprises, .\" see ``http://www.vix.com''. To learn more about Nominum, Inc., see .\" ``http://www.nominum.com''. .\" .\" $Id: dhcpd.leases.5,v 1.14.24.3 2011-09-19 00:24:22 sar Exp $ .\" .TH dhcpd.leases 5 .SH NAME dhcpd.leases - DHCP client lease database .SH DESCRIPTION The Internet Systems Consortium DHCP Server keeps a persistent database of leases that it has assigned. This database is a free-form ASCII file containing a series of lease declarations. Every time a lease is acquired, renewed or released, its new value is recorded at the end of the lease file. So if more than one declaration appears for a given lease, the last one in the file is the current one. .PP When dhcpd is first installed, there is no lease database. However, dhcpd requires that a lease database be present before it will start. To make the initial lease database, just create an empty file called DBDIR/dhcpd.leases. You can do this with: .PP .nf touch DBDIR/dhcpd.leases .fi .PP In order to prevent the lease database from growing without bound, the file is rewritten from time to time. First, a temporary lease database is created and all known leases are dumped to it. Then, the old lease database is renamed DBDIR/dhcpd.leases~. Finally, the newly written lease database is moved into place. .SH FORMAT Lease descriptions are stored in a format that is parsed by the same recursive descent parser used to read the .B dhcpd.conf(5) and .B dhclient.conf(5) files. Lease files can contain lease declarations, and also group and subgroup declarations, host declarations and failover state declarations. Group, subgroup and host declarations are used to record objects created using the OMAPI protocol. .PP The lease file is a log-structured file - whenever a lease changes, the contents of that lease are written to the end of the file. This means that it is entirely possible and quite reasonable for there to be two or more declarations of the same lease in the lease file at the same time. In that case, the instance of that particular lease that appears last in the file is the one that is in effect. .PP Group, subgroup and host declarations in the lease file are handled in the same manner, except that if any of these objects are deleted, a \fIrubout\fR is written to the lease file. This is just the same declaration, with \fB{ deleted; }\fR in the scope of the declaration. When the lease file is rewritten, any such rubouts that can be eliminated are eliminated. It is possible to delete a declaration in the \fBdhcpd.conf\fR file; in this case, the rubout can never be eliminated from the \fBdhcpd.leases\fR file. .SH THE LEASE DECLARATION .PP .B lease \fIip-address\fB { \fIstatements...\fB } .PP Each lease declaration includes the single IP address that has been leased to the client. The statements within the braces define the duration of the lease and to whom it is assigned. .PP .nf .B starts \fIdate\fB;\fR .B ends \fIdate\fB;\fR .B tstp \fIdate\fB;\fR .B tsfp \fIdate\fB;\fR .B atsfp \fIdate\fB;\fR .B cltt \fIdate\fB;\fR .fi .PP The start and end time of a lease are recorded using the \fBstarts\fR and \fBends\fR statements. The \fBtstp\fR statement is specified if the failover protocol is being used, and indicates what time the peer has been told the lease expires. The \fBtsfp\fR statement is also specified if the failover protocol is being used, and indicates the lease expiry time that the peer has acknowledged. The \fBatsfp\fR statement is the actual time sent from the failover partner. The \fBcltt\fR statement is the client's last transaction time. .PP The \fIdate\fR is specified in two ways, depending on the configuration value for the \fBdb-time-format\fR parameter. If it was set to \fIdefault\fR, then the \fIdate\fR fields appear as follows: .PP .I weekday year\fB/\fImonth\fB/\fIday hour\fB:\fIminute\fB:\fIsecond\fR .PP The weekday is present to make it easy for a human to tell when a lease expires - it's specified as a number from zero to six, with zero being Sunday. The day of week is ignored on input. The year is specified with the century, so it should generally be four digits except for really long leases. The month is specified as a number starting with 1 for January. The day of the month is likewise specified starting with 1. The hour is a number between 0 and 23, the minute a number between 0 and 59, and the second also a number between 0 and 59. .PP Lease times are specified in Universal Coordinated Time (UTC), not in the local time zone. There is probably nowhere in the world where the times recorded on a lease are always the same as wall clock times. On most unix machines, you can display the current time in UTC by typing \fBdate -u\fR. .PP If the \fBdb-time-format\fR was configured to \fIlocal\fR, then the \fIdate\fR fields appear as follows: .PP \fBepoch\fR \fI\fR\fB; #\fR \fI \fR\fB:\fR\fI\fR\fB:\fR\fI \fR .PP The \fIseconds-since-epoch\fR is as according to the system's local clock (often referred to as "unix time"). The \fB#\fR symbol supplies a comment that describes what actual time this is as according to the system's configured timezone, at the time the value was written. It is provided only for human inspection. .PP If a lease will never expire, \fIdate\fR is \fBnever\fR instead of an actual date. .PP .B hardware \fIhardware-type mac-address\fB;\fR .PP The hardware statement records the MAC address of the network interface on which the lease will be used. It is specified as a series of hexadecimal octets, separated by colons. .PP .B uid \fIclient-identifier\fB;\fR .PP The \fBuid\fR statement records the client identifier used by the client to acquire the lease. Clients are not required to send client identifiers, and this statement only appears if the client did in fact send one. Client identifiers are normally an ARP type (1 for ethernet) followed by the MAC address, just like in the \fBhardware\fI statement, but this is not required. .PP The client identifier is recorded as a colon-separated hexadecimal list or as a quoted string. If it is recorded as a quoted string and it contains one or more non-printable characters, those characters are represented as octal escapes - a backslash character followed by three octal digits. .PP .B client-hostname "\fIhostname\fB";\fR .PP Most DHCP clients will send their hostname in the \fIhost-name\fR option. If a client sends its hostname in this way, the hostname is recorded on the lease with a \fBclient-hostname\fR statement. This is not required by the protocol, however, so many specialized DHCP clients do not send a host-name option. .PP .B abandoned; .PP The \fBabandoned\fR statement indicates that the DHCP server has abandoned the lease. In that case, the \fBabandoned\fR statement will be used to indicate that the lease should not be reassigned. Please see the \fBdhcpd.conf(5)\fR manual page for information about abandoned leases. .PP .B binding state \fIstate\fB; .B next binding state \fIstate\fB; .PP The \fBbinding state\fR statement declares the lease's binding state. When the DHCP server is not configured to use the failover protocol, a lease's binding state will be either \fBactive\fR or \fBfree\fR. The failover protocol adds some additional transitional states, as well as the \fBbackup\fR state, which indicates that the lease is available for allocation by the failover secondary. .PP The \fBnext binding state\fR statement indicates what state the lease will move to when the current state expires. The time when the current state expires is specified in the \fIends\fR statement. .PP .B option agent.circuit-id \fIstring\fR; .B option agent.remote-id \fIstring\fR; .PP The \fBoption agent.circuit-id\fR and \fBoption agent.remote-id\fR statements are used to record the circuit ID and remote ID options send by the relay agent, if the relay agent uses the \fIrelay agent information option\fR. This allows these options to be used consistently in conditional evaluations even when the client is contacting the server directly rather than through its relay agent. .PP .B set \fIvariable\fB = \fIvalue\fB; .PP The \fBset\fR statement sets the value of a variable on the lease. For general information on variables, see the \fBdhcp-eval(5)\fR manual page. .PP .B The \fIddns-text\fB variable .PP The \fIddns-text\fR variable is used to record the value of the client's TXT identification record when the interim ddns update style has been used to update the DNS for a particular lease. .PP .B The \fIddns-fwd-name\fB variable .PP The \fIddns-fwd-name\fB variable records the value of the name used in updating the client's A record if a DDNS update has been successfully done by the server. The server may also have used this name to update the client's PTR record. .PP .B The \fIddns-client-fqdn\fB variable .PP If the server is configured to use the interim ddns update style, and is also configured to allow clients to update their own fqdns, and the client did in fact update its own fqdn, then the \fIddns-client-fqdn\fR variable records the name that the client has indicated it is using. This is the name that the server will have used to update the client's PTR record in this case. .PP .B The \fIddns-rev-name\fB variable .PP If the server successfully updates the client's PTR record, this variable will record the name that the DHCP server used for the PTR record. The name to which the PTR record points will be either the \fIddns-fwd-name\fR or the \fIddns-client-fqdn\fR. .PP .B The \fIvendor-class-identifier\fB variable .PP The server retains the client-supplied Vendor Class Identifier option for informational purposes, and to render them in DHCPLEASEQUERY responses. .PP .B on \fIevents\fB { \fIstatements...\fB } The \fBon\fI statement records a list of statements to execute if a certain event occurs. The possible events that can occur for an active lease are \fBrelease\fR and \fBexpiry\fR. More than one event can be specified - if so, the events are separated by '|' characters. .PP .B bootp; .B reserved; These two statements are effectively flags. If present, they indicate that the BOOTP and RESERVED failover flags, respectively, should be set. BOOTP and RESERVED dynamic leases are treated differently than normal dynamic leases, as they may only be used by the client to which they are currently allocated. .RE .SH THE FAILOVER PEER STATE DECLARATION The state of any failover peering arrangements is also recorded in the lease file, using the \fBfailover peer\fR statement: .PP .nf .B failover peer "\fIname\fB" state { .B my state \fIstate\fB at \fIdate\fB; .B peer state \fIstate\fB at \fIdate\fB; .B } .fi .PP The states of the peer named \fIname\fR is being recorded. Both the state of the running server (\fBmy state\fR) and the other failover partner (\fIpeer state\fR) are recorded. The following states are possible: \fBunknown-state\fR, \fBpartner-down\fR, \fBnormal\fR, \fBcommunications-interrupted\fR, \fBresolution-interrupted\fR, \fBpotential-conflict\fR, \fBrecover\fR, \fBrecover-done\fR, \fBshutdown\fR, \fBpaused\fR, and \fBstartup\fR. .RE .SH FILES .B DBDIR/dhcpd.leases DBDIR/dhcpd.leases~ .SH SEE ALSO dhcpd(8), dhcp-options(5), dhcp-eval(5), dhcpd.conf(5), RFC2132, RFC2131. .SH AUTHOR .B dhcpd(8) was written by Ted Lemon under a contract with Vixie Labs. Funding for this project was provided by Internet Systems Consortium. Information about Internet Systems Consortium can be found at: .B https://www.isc.org/ dhcp-4.2.4/server/dhcpleasequery.c000644 000765 000024 00000075607 11741122653 017100 0ustar00sarstaff000000 000000 /* * Copyright (C) 2011-2012 by Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2006-2007,2009 by Internet Systems Consortium, Inc. ("ISC") * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #include "dhcpd.h" /* * TODO: RFC4388 specifies that the server SHOULD return the same * options it would for a DHCREQUEST message, if no Parameter * Request List option (option 55) is passed. We do not do that. * * TODO: RFC4388 specifies the creation of a "non-sensitive options" * configuration list, and that these SHOULD be returned. We * have no such list. * * TODO: RFC4388 says the server SHOULD use RFC3118, "Authentication * for DHCP Messages". * * TODO: RFC4388 specifies that you SHOULD insure that you cannot be * DoS'ed by DHCPLEASEQUERY message. */ /* * If you query by hardware address or by client ID, then you may have * more than one IP address for your query argument. We need to do two * things: * * 1. Find the most recent lease. * 2. Find all additional IP addresses for the query argument. * * We do this by looking through all of the leases associated with a * given hardware address or client ID. We use the cltt (client last * transaction time) of the lease, which only has a resolution of one * second, so we might not actually give the very latest IP. */ static struct lease* next_hw(const struct lease *lease) { /* INSIST(lease != NULL); */ return lease->n_hw; } static struct lease* next_uid(const struct lease *lease) { /* INSIST(lease != NULL); */ return lease->n_uid; } void get_newest_lease(struct lease **retval, struct lease *lease, struct lease *(*next)(const struct lease *)) { struct lease *p; struct lease *newest; /* INSIST(newest != NULL); */ /* INSIST(next != NULL); */ *retval = NULL; if (lease == NULL) { return; } newest = lease; for (p=next(lease); p != NULL; p=next(p)) { if (newest->binding_state == FTS_ACTIVE) { if ((p->binding_state == FTS_ACTIVE) && (p->cltt > newest->cltt)) { newest = p; } } else { if (p->ends > newest->ends) { newest = p; } } } lease_reference(retval, newest, MDL); } static int get_associated_ips(const struct lease *lease, struct lease *(*next)(const struct lease *), const struct lease *newest, u_int32_t *associated_ips, unsigned int associated_ips_size) { const struct lease *p; int cnt; /* INSIST(next != NULL); */ /* INSIST(associated_ips != NULL); */ if (lease == NULL) { return 0; } cnt = 0; for (p=lease; p != NULL; p=next(p)) { if ((p->binding_state == FTS_ACTIVE) && (p != newest)) { if (cnt < associated_ips_size) { memcpy(&associated_ips[cnt], p->ip_addr.iabuf, sizeof(associated_ips[cnt])); } cnt++; } } return cnt; } void dhcpleasequery(struct packet *packet, int ms_nulltp) { char msgbuf[256]; char dbg_info[128]; struct iaddr cip; struct iaddr gip; struct data_string uid; struct hardware h; struct lease *tmp_lease; struct lease *lease; int want_associated_ip; int assoc_ip_cnt; u_int32_t assoc_ips[40]; /* XXXSK: arbitrary maximum number of IPs */ const int nassoc_ips = sizeof(assoc_ips) / sizeof(assoc_ips[0]); unsigned char dhcpMsgType; const char *dhcp_msg_type_name; struct subnet *subnet; struct group *relay_group; struct option_state *options; struct option_cache *oc; int allow_leasequery; int ignorep; u_int32_t lease_duration; u_int32_t time_renewal; u_int32_t time_rebinding; u_int32_t time_expiry; u_int32_t client_last_transaction_time; struct sockaddr_in to; struct in_addr siaddr; struct data_string prl; struct data_string *prl_ptr; int i; struct interface_info *interface; /* INSIST(packet != NULL); */ /* * Prepare log information. */ snprintf(msgbuf, sizeof(msgbuf), "DHCPLEASEQUERY from %s", inet_ntoa(packet->raw->giaddr)); /* * We can't reply if there is no giaddr field. */ if (!packet->raw->giaddr.s_addr) { log_info("%s: missing giaddr, ciaddr is %s, no reply sent", msgbuf, inet_ntoa(packet->raw->ciaddr)); return; } /* * Initially we use the 'giaddr' subnet options scope to determine if * the giaddr-identified relay agent is permitted to perform a * leasequery. The subnet is not required, and may be omitted, in * which case we are essentially interrogating the root options class * to find a globally permit. */ gip.len = sizeof(packet->raw->giaddr); memcpy(gip.iabuf, &packet->raw->giaddr, sizeof(packet->raw->giaddr)); subnet = NULL; find_subnet(&subnet, gip, MDL); if (subnet != NULL) relay_group = subnet->group; else relay_group = root_group; subnet_dereference(&subnet, MDL); options = NULL; if (!option_state_allocate(&options, MDL)) { log_error("No memory for option state."); log_info("%s: out of memory, no reply sent", msgbuf); return; } execute_statements_in_scope(NULL, packet, NULL, NULL, packet->options, options, &global_scope, relay_group, NULL); for (i=packet->class_count-1; i>=0; i--) { execute_statements_in_scope(NULL, packet, NULL, NULL, packet->options, options, &global_scope, packet->classes[i]->group, relay_group); } /* * Because LEASEQUERY has some privacy concerns, default to deny. */ allow_leasequery = 0; /* * See if we are authorized to do LEASEQUERY. */ oc = lookup_option(&server_universe, options, SV_LEASEQUERY); if (oc != NULL) { allow_leasequery = evaluate_boolean_option_cache(&ignorep, packet, NULL, NULL, packet->options, options, &global_scope, oc, MDL); } if (!allow_leasequery) { log_info("%s: LEASEQUERY not allowed, query ignored", msgbuf); option_state_dereference(&options, MDL); return; } /* * Copy out the client IP address. */ cip.len = sizeof(packet->raw->ciaddr); memcpy(cip.iabuf, &packet->raw->ciaddr, sizeof(packet->raw->ciaddr)); /* * If the client IP address is valid (not all zero), then we * are looking for information about that IP address. */ assoc_ip_cnt = 0; lease = tmp_lease = NULL; if (memcmp(cip.iabuf, "\0\0\0", 4)) { want_associated_ip = 0; snprintf(dbg_info, sizeof(dbg_info), "IP %s", piaddr(cip)); find_lease_by_ip_addr(&lease, cip, MDL); } else { want_associated_ip = 1; /* * If the client IP address is all zero, then we will * either look up by the client identifier (if we have * one), or by the MAC address. */ memset(&uid, 0, sizeof(uid)); if (get_option(&uid, &dhcp_universe, packet, NULL, NULL, packet->options, NULL, packet->options, &global_scope, DHO_DHCP_CLIENT_IDENTIFIER, MDL)) { snprintf(dbg_info, sizeof(dbg_info), "client-id %s", print_hex_1(uid.len, uid.data, 60)); find_lease_by_uid(&tmp_lease, uid.data, uid.len, MDL); data_string_forget(&uid, MDL); get_newest_lease(&lease, tmp_lease, next_uid); assoc_ip_cnt = get_associated_ips(tmp_lease, next_uid, lease, assoc_ips, nassoc_ips); } else { if (packet->raw->hlen+1 > sizeof(h.hbuf)) { log_info("%s: hardware length too long, " "no reply sent", msgbuf); option_state_dereference(&options, MDL); return; } h.hlen = packet->raw->hlen + 1; h.hbuf[0] = packet->raw->htype; memcpy(&h.hbuf[1], packet->raw->chaddr, packet->raw->hlen); snprintf(dbg_info, sizeof(dbg_info), "MAC address %s", print_hw_addr(h.hbuf[0], h.hlen - 1, &h.hbuf[1])); find_lease_by_hw_addr(&tmp_lease, h.hbuf, h.hlen, MDL); get_newest_lease(&lease, tmp_lease, next_hw); assoc_ip_cnt = get_associated_ips(tmp_lease, next_hw, lease, assoc_ips, nassoc_ips); } lease_dereference(&tmp_lease, MDL); if (lease != NULL) { memcpy(&packet->raw->ciaddr, lease->ip_addr.iabuf, sizeof(packet->raw->ciaddr)); } /* * Log if we have too many IP addresses associated * with this client. */ if (want_associated_ip && (assoc_ip_cnt > nassoc_ips)) { log_info("%d IP addresses associated with %s, " "only %d sent in reply.", assoc_ip_cnt, dbg_info, nassoc_ips); } } /* * We now know the query target too, so can report this in * our log message. */ snprintf(msgbuf, sizeof(msgbuf), "DHCPLEASEQUERY from %s for %s", inet_ntoa(packet->raw->giaddr), dbg_info); /* * Figure our our return type. */ if (lease == NULL) { dhcpMsgType = DHCPLEASEUNKNOWN; dhcp_msg_type_name = "DHCPLEASEUNKNOWN"; } else { if (lease->binding_state == FTS_ACTIVE) { dhcpMsgType = DHCPLEASEACTIVE; dhcp_msg_type_name = "DHCPLEASEACTIVE"; } else { dhcpMsgType = DHCPLEASEUNASSIGNED; dhcp_msg_type_name = "DHCPLEASEUNASSIGNED"; } } /* * Set options that only make sense if we have an active lease. */ if (dhcpMsgType == DHCPLEASEACTIVE) { /* * RFC 4388 uses the PRL to request options for the agent to * receive that are "about" the client. It is confusing * because in some cases it wants to know what was sent to * the client (lease times, adjusted), and in others it wants * to know information the client sent. You're supposed to * know this on a case-by-case basis. * * "Name servers", "domain name", and the like from the relay * agent's scope seems less than useful. Our options are to * restart the option cache from the lease's best point of view * (execute statements from the lease pool's group), or to * simply restart the option cache from empty. * * I think restarting the option cache from empty best * approaches RFC 4388's intent; specific options are included. */ option_state_dereference(&options, MDL); if (!option_state_allocate(&options, MDL)) { log_error("%s: out of memory, no reply sent", msgbuf); lease_dereference(&lease, MDL); return; } /* * Set the hardware address fields. */ packet->raw->hlen = lease->hardware_addr.hlen - 1; packet->raw->htype = lease->hardware_addr.hbuf[0]; memcpy(packet->raw->chaddr, &lease->hardware_addr.hbuf[1], sizeof(packet->raw->chaddr)); /* * Set client identifier option. */ if (lease->uid_len > 0) { if (!add_option(options, DHO_DHCP_CLIENT_IDENTIFIER, lease->uid, lease->uid_len)) { option_state_dereference(&options, MDL); lease_dereference(&lease, MDL); log_info("%s: out of memory, no reply sent", msgbuf); return; } } /* * Calculate T1 and T2, the times when the client * tries to extend its lease on its networking * address. * These seem to be hard-coded in ISC DHCP, to 0.5 and * 0.875 of the lease time. */ lease_duration = lease->ends - lease->starts; time_renewal = lease->starts + (lease_duration / 2); time_rebinding = lease->starts + (lease_duration / 2) + (lease_duration / 4) + (lease_duration / 8); if (time_renewal > cur_time) { time_renewal = htonl(time_renewal - cur_time); if (!add_option(options, DHO_DHCP_RENEWAL_TIME, &time_renewal, sizeof(time_renewal))) { option_state_dereference(&options, MDL); lease_dereference(&lease, MDL); log_info("%s: out of memory, no reply sent", msgbuf); return; } } if (time_rebinding > cur_time) { time_rebinding = htonl(time_rebinding - cur_time); if (!add_option(options, DHO_DHCP_REBINDING_TIME, &time_rebinding, sizeof(time_rebinding))) { option_state_dereference(&options, MDL); lease_dereference(&lease, MDL); log_info("%s: out of memory, no reply sent", msgbuf); return; } } if (lease->ends > cur_time) { time_expiry = htonl(lease->ends - cur_time); if (!add_option(options, DHO_DHCP_LEASE_TIME, &time_expiry, sizeof(time_expiry))) { option_state_dereference(&options, MDL); lease_dereference(&lease, MDL); log_info("%s: out of memory, no reply sent", msgbuf); return; } } /* Supply the Vendor-Class-Identifier. */ if (lease->scope != NULL) { struct data_string vendor_class; memset(&vendor_class, 0, sizeof(vendor_class)); if (find_bound_string(&vendor_class, lease->scope, "vendor-class-identifier")) { if (!add_option(options, DHO_VENDOR_CLASS_IDENTIFIER, (void *)vendor_class.data, vendor_class.len)) { option_state_dereference(&options, MDL); lease_dereference(&lease, MDL); log_error("%s: error adding vendor " "class identifier, no reply " "sent", msgbuf); data_string_forget(&vendor_class, MDL); return; } data_string_forget(&vendor_class, MDL); } } /* * Set the relay agent info. * * Note that because agent info is appended without regard * to the PRL in cons_options(), this will be sent as the * last option in the packet whether it is listed on PRL or * not. */ if (lease->agent_options != NULL) { int idx = agent_universe.index; struct option_chain_head **tmp1 = (struct option_chain_head **) &(options->universes[idx]); struct option_chain_head *tmp2 = (struct option_chain_head *) lease->agent_options; option_chain_head_reference(tmp1, tmp2, MDL); } /* * Set the client last transaction time. * We check to make sure we have a timestamp. For * lease files that were saved before running a * timestamp-aware version of the server, this may * not be set. */ if (lease->cltt != MIN_TIME) { if (cur_time > lease->cltt) { client_last_transaction_time = htonl(cur_time - lease->cltt); } else { client_last_transaction_time = htonl(0); } if (!add_option(options, DHO_CLIENT_LAST_TRANSACTION_TIME, &client_last_transaction_time, sizeof(client_last_transaction_time))) { option_state_dereference(&options, MDL); lease_dereference(&lease, MDL); log_info("%s: out of memory, no reply sent", msgbuf); return; } } /* * Set associated IPs, if requested and there are some. */ if (want_associated_ip && (assoc_ip_cnt > 0)) { if (!add_option(options, DHO_ASSOCIATED_IP, assoc_ips, assoc_ip_cnt * sizeof(assoc_ips[0]))) { option_state_dereference(&options, MDL); lease_dereference(&lease, MDL); log_info("%s: out of memory, no reply sent", msgbuf); return; } } } /* * Set the message type. */ packet->raw->op = BOOTREPLY; /* * Set DHCP message type. */ if (!add_option(options, DHO_DHCP_MESSAGE_TYPE, &dhcpMsgType, sizeof(dhcpMsgType))) { option_state_dereference(&options, MDL); lease_dereference(&lease, MDL); log_info("%s: error adding option, no reply sent", msgbuf); return; } /* * Log the message we've received. */ log_info("%s", msgbuf); /* * Figure out which address to use to send from. */ get_server_source_address(&siaddr, options, packet); /* * Set up the option buffer. */ memset(&prl, 0, sizeof(prl)); oc = lookup_option(&dhcp_universe, options, DHO_DHCP_PARAMETER_REQUEST_LIST); if (oc != NULL) { evaluate_option_cache(&prl, packet, NULL, NULL, packet->options, options, &global_scope, oc, MDL); } if (prl.len > 0) { prl_ptr = &prl; } else { prl_ptr = NULL; } packet->packet_length = cons_options(packet, packet->raw, lease, NULL, 0, packet->options, options, &global_scope, 0, 0, 0, prl_ptr, NULL); data_string_forget(&prl, MDL); /* SK: safe, even if empty */ option_state_dereference(&options, MDL); lease_dereference(&lease, MDL); to.sin_family = AF_INET; #ifdef HAVE_SA_LEN to.sin_len = sizeof(to); #endif memset(to.sin_zero, 0, sizeof(to.sin_zero)); /* * Leasequery packets are be sent to the gateway address. */ to.sin_addr = packet->raw->giaddr; if (packet->raw->giaddr.s_addr != htonl(INADDR_LOOPBACK)) { to.sin_port = local_port; } else { to.sin_port = remote_port; /* XXXSK: For debugging. */ } /* * The fallback_interface lets us send with a real IP * address. The packet interface sends from all-zeros. */ if (fallback_interface != NULL) { interface = fallback_interface; } else { interface = packet->interface; } /* * Report what we're sending. */ log_info("%s to %s for %s (%d associated IPs)", dhcp_msg_type_name, inet_ntoa(to.sin_addr), dbg_info, assoc_ip_cnt); send_packet(interface, NULL, packet->raw, packet->packet_length, siaddr, &to, NULL); } #ifdef DHCPv6 /* * TODO: RFC5007 query-by-clientid. * * TODO: RFC5007 look at the pools according to the link-address. * * TODO: get fixed leases too. * * TODO: RFC5007 ORO in query-options. * * TODO: RFC5007 lq-relay-data. * * TODO: RFC5007 lq-client-link. * * Note: the code is still nearly compliant and usable for the target * case with these missing features! */ /* * The structure to handle a leasequery. */ struct lq6_state { struct packet *packet; struct data_string client_id; struct data_string server_id; struct data_string lq_query; uint8_t query_type; struct in6_addr link_addr; struct option_state *query_opts; struct option_state *reply_opts; unsigned cursor; union reply_buffer { unsigned char data[65536]; struct dhcpv6_packet reply; } buf; }; /* * Options that we want to send. */ static const int required_opts_lq[] = { D6O_CLIENTID, D6O_SERVERID, D6O_STATUS_CODE, D6O_CLIENT_DATA, D6O_LQ_RELAY_DATA, D6O_LQ_CLIENT_LINK, 0 }; static const int required_opt_CLIENT_DATA[] = { D6O_CLIENTID, D6O_IAADDR, D6O_IAPREFIX, D6O_CLT_TIME, 0 }; /* * Get the lq-query option from the packet. */ static isc_result_t get_lq_query(struct lq6_state *lq) { struct data_string *lq_query = &lq->lq_query; struct packet *packet = lq->packet; struct option_cache *oc; /* * Verify our lq_query structure is empty. */ if ((lq_query->data != NULL) || (lq_query->len != 0)) { return DHCP_R_INVALIDARG; } oc = lookup_option(&dhcpv6_universe, packet->options, D6O_LQ_QUERY); if (oc == NULL) { return ISC_R_NOTFOUND; } if (!evaluate_option_cache(lq_query, packet, NULL, NULL, packet->options, NULL, &global_scope, oc, MDL)) { return ISC_R_FAILURE; } return ISC_R_SUCCESS; } /* * Message validation, RFC 5007 section 4.2.1: * dhcpv6.c:valid_client_msg() - unicast + lq-query option. */ static int valid_query_msg(struct lq6_state *lq) { struct packet *packet = lq->packet; int ret_val = 0; struct option_cache *oc; /* INSIST((lq != NULL) || (packet != NULL)); */ switch (get_client_id(packet, &lq->client_id)) { case ISC_R_SUCCESS: break; case ISC_R_NOTFOUND: log_debug("Discarding %s from %s; " "client identifier missing", dhcpv6_type_names[packet->dhcpv6_msg_type], piaddr(packet->client_addr)); goto exit; default: log_error("Error processing %s from %s; " "unable to evaluate Client Identifier", dhcpv6_type_names[packet->dhcpv6_msg_type], piaddr(packet->client_addr)); goto exit; } oc = lookup_option(&dhcpv6_universe, packet->options, D6O_SERVERID); if (oc != NULL) { if (evaluate_option_cache(&lq->server_id, packet, NULL, NULL, packet->options, NULL, &global_scope, oc, MDL)) { log_debug("Discarding %s from %s; " "server identifier found " "(CLIENTID %s, SERVERID %s)", dhcpv6_type_names[packet->dhcpv6_msg_type], piaddr(packet->client_addr), print_hex_1(lq->client_id.len, lq->client_id.data, 60), print_hex_2(lq->server_id.len, lq->server_id.data, 60)); } else { log_debug("Discarding %s from %s; " "server identifier found " "(CLIENTID %s)", dhcpv6_type_names[packet->dhcpv6_msg_type], print_hex_1(lq->client_id.len, lq->client_id.data, 60), piaddr(packet->client_addr)); } goto exit; } switch (get_lq_query(lq)) { case ISC_R_SUCCESS: break; case ISC_R_NOTFOUND: log_debug("Discarding %s from %s; lq-query missing", dhcpv6_type_names[packet->dhcpv6_msg_type], piaddr(packet->client_addr)); goto exit; default: log_error("Error processing %s from %s; " "unable to evaluate LQ-Query", dhcpv6_type_names[packet->dhcpv6_msg_type], piaddr(packet->client_addr)); goto exit; } /* looks good */ ret_val = 1; exit: if (!ret_val) { if (lq->client_id.len > 0) { data_string_forget(&lq->client_id, MDL); } if (lq->server_id.len > 0) { data_string_forget(&lq->server_id, MDL); } if (lq->lq_query.len > 0) { data_string_forget(&lq->lq_query, MDL); } } return ret_val; } /* * Set an error in a status-code option (from set_status_code). */ static int set_error(struct lq6_state *lq, u_int16_t code, const char *message) { struct data_string d; int ret_val; memset(&d, 0, sizeof(d)); d.len = sizeof(code) + strlen(message); if (!buffer_allocate(&d.buffer, d.len, MDL)) { log_fatal("set_error: no memory for status code."); } d.data = d.buffer->data; putUShort(d.buffer->data, code); memcpy(d.buffer->data + sizeof(code), message, d.len - sizeof(code)); if (!save_option_buffer(&dhcpv6_universe, lq->reply_opts, d.buffer, (unsigned char *)d.data, d.len, D6O_STATUS_CODE, 0)) { log_error("set_error: error saving status code."); ret_val = 0; } else { ret_val = 1; } data_string_forget(&d, MDL); return ret_val; } /* * Process a by-address lease query. */ static int process_lq_by_address(struct lq6_state *lq) { struct packet *packet = lq->packet; struct option_cache *oc; struct ipv6_pool *pool = NULL; struct data_string data; struct in6_addr addr; struct iasubopt *iaaddr = NULL; struct option_state *opt_state = NULL; u_int32_t lifetime; unsigned opt_cursor; int ret_val = 0; /* * Get the IAADDR. */ oc = lookup_option(&dhcpv6_universe, lq->query_opts, D6O_IAADDR); if (oc == NULL) { if (!set_error(lq, STATUS_MalformedQuery, "No OPTION_IAADDR.")) { log_error("process_lq_by_address: unable " "to set MalformedQuery status code."); return 0; } return 1; } memset(&data, 0, sizeof(data)); if (!evaluate_option_cache(&data, packet, NULL, NULL, lq->query_opts, NULL, &global_scope, oc, MDL) || (data.len < IAADDR_OFFSET)) { log_error("process_lq_by_address: error evaluating IAADDR."); goto exit; } memcpy(&addr, data.data, sizeof(addr)); data_string_forget(&data, MDL); /* * Find the lease. * Note the RFC 5007 says to use the link-address to find the link * or the ia-aadr when it is :: but in any case the ia-addr has * to be on the link, so we ignore the link-address here. */ if (find_ipv6_pool(&pool, D6O_IA_NA, &addr) != ISC_R_SUCCESS) { if (!set_error(lq, STATUS_NotConfigured, "Address not in a pool.")) { log_error("process_lq_by_address: unable " "to set NotConfigured status code."); goto exit; } ret_val = 1; goto exit; } if (iasubopt_hash_lookup(&iaaddr, pool->leases, &addr, sizeof(addr), MDL) == 0) { ret_val = 1; goto exit; } if ((iaaddr == NULL) || (iaaddr->state != FTS_ACTIVE) || (iaaddr->ia == NULL) || (iaaddr->ia->iaid_duid.len <= 4)) { ret_val = 1; goto exit; } /* * Build the client-data option (with client-id, ia-addr and clt-time). */ if (!option_state_allocate(&opt_state, MDL)) { log_error("process_lq_by_address: " "no memory for option state."); goto exit; } data_string_copy(&data, &iaaddr->ia->iaid_duid, MDL); data.data += 4; data.len -= 4; if (!save_option_buffer(&dhcpv6_universe, opt_state, NULL, (unsigned char *)data.data, data.len, D6O_CLIENTID, 0)) { log_error("process_lq_by_address: error saving client ID."); goto exit; } data_string_forget(&data, MDL); data.len = IAADDR_OFFSET; if (!buffer_allocate(&data.buffer, data.len, MDL)) { log_error("process_lq_by_address: no memory for ia-addr."); goto exit; } data.data = data.buffer->data; memcpy(data.buffer->data, &iaaddr->addr, 16); lifetime = iaaddr->prefer; putULong(data.buffer->data + 16, lifetime); lifetime = iaaddr->valid; putULong(data.buffer->data + 20, lifetime); if (!save_option_buffer(&dhcpv6_universe, opt_state, NULL, (unsigned char *)data.data, data.len, D6O_IAADDR, 0)) { log_error("process_lq_by_address: error saving ia-addr."); goto exit; } data_string_forget(&data, MDL); lifetime = htonl(iaaddr->ia->cltt); if (!save_option_buffer(&dhcpv6_universe, opt_state, NULL, (unsigned char *)&lifetime, 4, D6O_CLT_TIME, 0)) { log_error("process_lq_by_address: error saving clt time."); goto exit; } /* * Store the client-data option. */ opt_cursor = lq->cursor; putUShort(lq->buf.data + lq->cursor, (unsigned)D6O_CLIENT_DATA); lq->cursor += 2; /* Skip option length. */ lq->cursor += 2; lq->cursor += store_options6((char *)lq->buf.data + lq->cursor, sizeof(lq->buf) - lq->cursor, opt_state, lq->packet, required_opt_CLIENT_DATA, NULL); /* Reset the length. */ putUShort(lq->buf.data + opt_cursor + 2, lq->cursor - (opt_cursor + 4)); /* Done. */ ret_val = 1; exit: if (data.data != NULL) data_string_forget(&data, MDL); if (pool != NULL) ipv6_pool_dereference(&pool, MDL); if (iaaddr != NULL) iasubopt_dereference(&iaaddr, MDL); if (opt_state != NULL) option_state_dereference(&opt_state, MDL); return ret_val; } /* * Process a lease query. */ void dhcpv6_leasequery(struct data_string *reply_ret, struct packet *packet) { static struct lq6_state lq; struct option_cache *oc; int allow_lq; /* * Initialize the lease query state. */ lq.packet = NULL; memset(&lq.client_id, 0, sizeof(lq.client_id)); memset(&lq.server_id, 0, sizeof(lq.server_id)); memset(&lq.lq_query, 0, sizeof(lq.lq_query)); lq.query_opts = NULL; lq.reply_opts = NULL; packet_reference(&lq.packet, packet, MDL); /* * Validate our input. */ if (!valid_query_msg(&lq)) { goto exit; } /* * Prepare our reply. */ if (!option_state_allocate(&lq.reply_opts, MDL)) { log_error("dhcpv6_leasequery: no memory for option state."); goto exit; } execute_statements_in_scope(NULL, lq.packet, NULL, NULL, lq.packet->options, lq.reply_opts, &global_scope, root_group, NULL); lq.buf.reply.msg_type = DHCPV6_LEASEQUERY_REPLY; memcpy(lq.buf.reply.transaction_id, lq.packet->dhcpv6_transaction_id, sizeof(lq.buf.reply.transaction_id)); /* * Because LEASEQUERY has some privacy concerns, default to deny. */ allow_lq = 0; /* * See if we are authorized to do LEASEQUERY. */ oc = lookup_option(&server_universe, lq.reply_opts, SV_LEASEQUERY); if (oc != NULL) { allow_lq = evaluate_boolean_option_cache(NULL, lq.packet, NULL, NULL, lq.packet->options, lq.reply_opts, &global_scope, oc, MDL); } if (!allow_lq) { log_info("dhcpv6_leasequery: not allowed, query ignored."); goto exit; } /* * Same than transmission of REPLY message in RFC 3315: * server-id * client-id */ oc = lookup_option(&dhcpv6_universe, lq.reply_opts, D6O_SERVERID); if (oc == NULL) { /* If not already in options, get from query then global. */ if (lq.server_id.data == NULL) copy_server_duid(&lq.server_id, MDL); if (!save_option_buffer(&dhcpv6_universe, lq.reply_opts, NULL, (unsigned char *)lq.server_id.data, lq.server_id.len, D6O_SERVERID, 0)) { log_error("dhcpv6_leasequery: " "error saving server identifier."); goto exit; } } if (!save_option_buffer(&dhcpv6_universe, lq.reply_opts, lq.client_id.buffer, (unsigned char *)lq.client_id.data, lq.client_id.len, D6O_CLIENTID, 0)) { log_error("dhcpv6_leasequery: " "error saving client identifier."); goto exit; } lq.cursor = 4; /* * Decode the lq-query option. */ if (lq.lq_query.len <= LQ_QUERY_OFFSET) { if (!set_error(&lq, STATUS_MalformedQuery, "OPTION_LQ_QUERY too short.")) { log_error("dhcpv6_leasequery: unable " "to set MalformedQuery status code."); goto exit; } goto done; } lq.query_type = lq.lq_query.data [0]; memcpy(&lq.link_addr, lq.lq_query.data + 1, sizeof(lq.link_addr)); switch (lq.query_type) { case LQ6QT_BY_ADDRESS: break; case LQ6QT_BY_CLIENTID: if (!set_error(&lq, STATUS_UnknownQueryType, "QUERY_BY_CLIENTID not supported.")) { log_error("dhcpv6_leasequery: unable to " "set UnknownQueryType status code."); goto exit; } goto done; default: if (!set_error(&lq, STATUS_UnknownQueryType, "Unknown query-type.")) { log_error("dhcpv6_leasequery: unable to " "set UnknownQueryType status code."); goto exit; } goto done; } if (!option_state_allocate(&lq.query_opts, MDL)) { log_error("dhcpv6_leasequery: no memory for option state."); goto exit; } if (!parse_option_buffer(lq.query_opts, lq.lq_query.data + LQ_QUERY_OFFSET, lq.lq_query.len - LQ_QUERY_OFFSET, &dhcpv6_universe)) { log_error("dhcpv6_leasequery: error parsing query-options."); if (!set_error(&lq, STATUS_MalformedQuery, "Bad query-options.")) { log_error("dhcpv6_leasequery: unable " "to set MalformedQuery status code."); goto exit; } goto done; } /* Do it. */ if (!process_lq_by_address(&lq)) goto exit; done: /* Store the options. */ lq.cursor += store_options6((char *)lq.buf.data + lq.cursor, sizeof(lq.buf) - lq.cursor, lq.reply_opts, lq.packet, required_opts_lq, NULL); /* Return our reply to the caller. */ reply_ret->len = lq.cursor; reply_ret->buffer = NULL; if (!buffer_allocate(&reply_ret->buffer, lq.cursor, MDL)) { log_fatal("dhcpv6_leasequery: no memory to store Reply."); } memcpy(reply_ret->buffer->data, lq.buf.data, lq.cursor); reply_ret->data = reply_ret->buffer->data; exit: /* Cleanup. */ if (lq.packet != NULL) packet_dereference(&lq.packet, MDL); if (lq.client_id.data != NULL) data_string_forget(&lq.client_id, MDL); if (lq.server_id.data != NULL) data_string_forget(&lq.server_id, MDL); if (lq.lq_query.data != NULL) data_string_forget(&lq.lq_query, MDL); if (lq.query_opts != NULL) option_state_dereference(&lq.query_opts, MDL); if (lq.reply_opts != NULL) option_state_dereference(&lq.reply_opts, MDL); } #endif /* DHCPv6 */ dhcp-4.2.4/server/dhcpv6.c000644 000765 000024 00000512055 11754542635 015257 0ustar00sarstaff000000 000000 /* * Copyright (C) 2006-2012 by Internet Systems Consortium, Inc. ("ISC") * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #include "dhcpd.h" #ifdef DHCPv6 /* * We use print_hex_1() to output DUID values. We could actually output * the DUID with more information... MAC address if using type 1 or 3, * and so on. However, RFC 3315 contains Grave Warnings against actually * attempting to understand a DUID. */ /* * TODO: gettext() or other method of localization for the messages * for status codes (and probably for log formats eventually) * TODO: refactoring (simplify, simplify, simplify) * TODO: support multiple shared_networks on each interface (this * will allow the server to issue multiple IPv6 addresses to * a single interface) */ /* * DHCPv6 Reply workflow assist. A Reply packet is built by various * different functions; this gives us one location where we keep state * regarding a reply. */ struct reply_state { /* root level persistent state */ struct shared_network *shared; struct host_decl *host; struct subnet *subnet; /* Used to match fixed-addrs to subnet scopes. */ struct option_state *opt_state; struct packet *packet; struct data_string client_id; /* IA level persistent state */ unsigned ia_count; unsigned pd_count; unsigned client_resources; isc_boolean_t resources_included; isc_boolean_t static_lease; unsigned static_prefixes; struct ia_xx *ia; struct ia_xx *old_ia; struct option_state *reply_ia; struct data_string fixed; /* IAADDR/PREFIX level persistent state */ struct iasubopt *lease; /* * "t1", "t2", preferred, and valid lifetimes records for calculating * t1 and t2 (min/max). */ u_int32_t renew, rebind, prefer, valid; /* Client-requested valid and preferred lifetimes. */ u_int32_t client_valid, client_prefer; /* Chosen values to transmit for valid and preferred lifetimes. */ u_int32_t send_valid, send_prefer; /* Preferred prefix length (-1 is any). */ int preflen; /* Index into the data field that has been consumed. */ unsigned cursor; union reply_buffer { unsigned char data[65536]; struct dhcpv6_packet reply; } buf; }; /* * Prototypes local to this file. */ static int get_encapsulated_IA_state(struct option_state **enc_opt_state, struct data_string *enc_opt_data, struct packet *packet, struct option_cache *oc, int offset); static void build_dhcpv6_reply(struct data_string *, struct packet *); static isc_result_t shared_network_from_packet6(struct shared_network **shared, struct packet *packet); static void seek_shared_host(struct host_decl **hp, struct shared_network *shared); static isc_boolean_t fixed_matches_shared(struct host_decl *host, struct shared_network *shared); static isc_result_t reply_process_ia_na(struct reply_state *reply, struct option_cache *ia); static isc_result_t reply_process_ia_ta(struct reply_state *reply, struct option_cache *ia); static isc_result_t reply_process_addr(struct reply_state *reply, struct option_cache *addr); static isc_boolean_t address_is_owned(struct reply_state *reply, struct iaddr *addr); static isc_boolean_t temporary_is_available(struct reply_state *reply, struct iaddr *addr); static isc_result_t find_client_temporaries(struct reply_state *reply); static isc_result_t reply_process_try_addr(struct reply_state *reply, struct iaddr *addr); static isc_result_t find_client_address(struct reply_state *reply); static isc_result_t reply_process_is_addressed(struct reply_state *reply, struct binding_scope **scope, struct group *group); static isc_result_t reply_process_send_addr(struct reply_state *reply, struct iaddr *addr); static struct iasubopt *lease_compare(struct iasubopt *alpha, struct iasubopt *beta); static isc_result_t reply_process_ia_pd(struct reply_state *reply, struct option_cache *ia_pd); static isc_result_t reply_process_prefix(struct reply_state *reply, struct option_cache *pref); static isc_boolean_t prefix_is_owned(struct reply_state *reply, struct iaddrcidrnet *pref); static isc_result_t find_client_prefix(struct reply_state *reply); static isc_result_t reply_process_try_prefix(struct reply_state *reply, struct iaddrcidrnet *pref); static isc_result_t reply_process_is_prefixed(struct reply_state *reply, struct binding_scope **scope, struct group *group); static isc_result_t reply_process_send_prefix(struct reply_state *reply, struct iaddrcidrnet *pref); static struct iasubopt *prefix_compare(struct reply_state *reply, struct iasubopt *alpha, struct iasubopt *beta); static int find_hosts_by_duid_chaddr(struct host_decl **host, const struct data_string *client_id); /* * This function returns the time since DUID time start for the * given time_t value. */ static u_int32_t duid_time(time_t when) { /* * This time is modulo 2^32. */ while ((when - DUID_TIME_EPOCH) > 4294967295u) { /* use 2^31 to avoid spurious compiler warnings */ when -= 2147483648u; when -= 2147483648u; } return when - DUID_TIME_EPOCH; } /* * Server DUID. * * This must remain the same for the lifetime of this server, because * clients return the server DUID that we sent them in Request packets. * * We pick the server DUID like this: * * 1. Check dhcpd.conf - any value the administrator has configured * overrides any possible values. * 2. Check the leases.txt - we want to use the previous value if * possible. * 3. Check if dhcpd.conf specifies a type of server DUID to use, * and generate that type. * 4. Generate a type 1 (time + hardware address) DUID. */ static struct data_string server_duid; /* * Check if the server_duid has been set. */ isc_boolean_t server_duid_isset(void) { return (server_duid.data != NULL); } /* * Return the server_duid. */ void copy_server_duid(struct data_string *ds, const char *file, int line) { data_string_copy(ds, &server_duid, file, line); } /* * Set the server DUID to a specified value. This is used when * the server DUID is stored in persistent memory (basically the * leases.txt file). */ void set_server_duid(struct data_string *new_duid) { /* INSIST(new_duid != NULL); */ /* INSIST(new_duid->data != NULL); */ if (server_duid_isset()) { data_string_forget(&server_duid, MDL); } data_string_copy(&server_duid, new_duid, MDL); } /* * Set the server DUID based on the D6O_SERVERID option. This handles * the case where the administrator explicitly put it in the dhcpd.conf * file. */ isc_result_t set_server_duid_from_option(void) { struct option_state *opt_state; struct option_cache *oc; struct data_string option_duid; isc_result_t ret_val; opt_state = NULL; if (!option_state_allocate(&opt_state, MDL)) { log_fatal("No memory for server DUID."); } execute_statements_in_scope(NULL, NULL, NULL, NULL, NULL, opt_state, &global_scope, root_group, NULL); oc = lookup_option(&dhcpv6_universe, opt_state, D6O_SERVERID); if (oc == NULL) { ret_val = ISC_R_NOTFOUND; } else { memset(&option_duid, 0, sizeof(option_duid)); if (!evaluate_option_cache(&option_duid, NULL, NULL, NULL, opt_state, NULL, &global_scope, oc, MDL)) { ret_val = ISC_R_UNEXPECTED; } else { set_server_duid(&option_duid); data_string_forget(&option_duid, MDL); ret_val = ISC_R_SUCCESS; } } option_state_dereference(&opt_state, MDL); return ret_val; } /* * DUID layout, as defined in RFC 3315, section 9. * * We support type 1 (hardware address plus time) and type 3 (hardware * address). * * We can support type 2 for specific vendors in the future, if they * publish the specification. And of course there may be additional * types later. */ static int server_duid_type = DUID_LLT; /* * Set the DUID type. */ void set_server_duid_type(int type) { server_duid_type = type; } /* * Generate a new server DUID. This is done if there was no DUID in * the leases.txt or in the dhcpd.conf file. */ isc_result_t generate_new_server_duid(void) { struct interface_info *p; u_int32_t time_val; struct data_string generated_duid; /* * Verify we have a type that we support. */ if ((server_duid_type != DUID_LL) && (server_duid_type != DUID_LLT)) { log_error("Invalid DUID type %d specified, " "only LL and LLT types supported", server_duid_type); return DHCP_R_INVALIDARG; } /* * Find an interface with a hardware address. * Any will do. :) */ for (p = interfaces; p != NULL; p = p->next) { if (p->hw_address.hlen > 0) { break; } } if (p == NULL) { return ISC_R_UNEXPECTED; } /* * Build our DUID. */ memset(&generated_duid, 0, sizeof(generated_duid)); if (server_duid_type == DUID_LLT) { time_val = duid_time(time(NULL)); generated_duid.len = 8 + p->hw_address.hlen - 1; if (!buffer_allocate(&generated_duid.buffer, generated_duid.len, MDL)) { log_fatal("No memory for server DUID."); } generated_duid.data = generated_duid.buffer->data; putUShort(generated_duid.buffer->data, DUID_LLT); putUShort(generated_duid.buffer->data + 2, p->hw_address.hbuf[0]); putULong(generated_duid.buffer->data + 4, time_val); memcpy(generated_duid.buffer->data + 8, p->hw_address.hbuf+1, p->hw_address.hlen-1); } else if (server_duid_type == DUID_LL) { generated_duid.len = 4 + p->hw_address.hlen - 1; if (!buffer_allocate(&generated_duid.buffer, generated_duid.len, MDL)) { log_fatal("No memory for server DUID."); } generated_duid.data = generated_duid.buffer->data; putUShort(generated_duid.buffer->data, DUID_LL); putUShort(generated_duid.buffer->data + 2, p->hw_address.hbuf[0]); memcpy(generated_duid.buffer->data + 4, p->hw_address.hbuf+1, p->hw_address.hlen-1); } else { log_fatal("Unsupported server DUID type %d.", server_duid_type); } set_server_duid(&generated_duid); data_string_forget(&generated_duid, MDL); return ISC_R_SUCCESS; } /* * Get the client identifier from the packet. */ isc_result_t get_client_id(struct packet *packet, struct data_string *client_id) { struct option_cache *oc; /* * Verify our client_id structure is empty. */ if ((client_id->data != NULL) || (client_id->len != 0)) { return DHCP_R_INVALIDARG; } oc = lookup_option(&dhcpv6_universe, packet->options, D6O_CLIENTID); if (oc == NULL) { return ISC_R_NOTFOUND; } if (!evaluate_option_cache(client_id, packet, NULL, NULL, packet->options, NULL, &global_scope, oc, MDL)) { return ISC_R_FAILURE; } return ISC_R_SUCCESS; } /* * Message validation, defined in RFC 3315, sections 15.2, 15.5, 15.7: * * Servers MUST discard any Solicit messages that do not include a * Client Identifier option or that do include a Server Identifier * option. */ int valid_client_msg(struct packet *packet, struct data_string *client_id) { int ret_val; struct option_cache *oc; struct data_string data; ret_val = 0; memset(client_id, 0, sizeof(*client_id)); memset(&data, 0, sizeof(data)); switch (get_client_id(packet, client_id)) { case ISC_R_SUCCESS: break; case ISC_R_NOTFOUND: log_debug("Discarding %s from %s; " "client identifier missing", dhcpv6_type_names[packet->dhcpv6_msg_type], piaddr(packet->client_addr)); goto exit; default: log_error("Error processing %s from %s; " "unable to evaluate Client Identifier", dhcpv6_type_names[packet->dhcpv6_msg_type], piaddr(packet->client_addr)); goto exit; } /* * Required by RFC 3315, section 15. */ if (packet->unicast) { log_debug("Discarding %s from %s; packet sent unicast " "(CLIENTID %s)", dhcpv6_type_names[packet->dhcpv6_msg_type], piaddr(packet->client_addr), print_hex_1(client_id->len, client_id->data, 60)); goto exit; } oc = lookup_option(&dhcpv6_universe, packet->options, D6O_SERVERID); if (oc != NULL) { if (evaluate_option_cache(&data, packet, NULL, NULL, packet->options, NULL, &global_scope, oc, MDL)) { log_debug("Discarding %s from %s; " "server identifier found " "(CLIENTID %s, SERVERID %s)", dhcpv6_type_names[packet->dhcpv6_msg_type], piaddr(packet->client_addr), print_hex_1(client_id->len, client_id->data, 60), print_hex_2(data.len, data.data, 60)); } else { log_debug("Discarding %s from %s; " "server identifier found " "(CLIENTID %s)", dhcpv6_type_names[packet->dhcpv6_msg_type], print_hex_1(client_id->len, client_id->data, 60), piaddr(packet->client_addr)); } goto exit; } /* looks good */ ret_val = 1; exit: if (data.len > 0) { data_string_forget(&data, MDL); } if (!ret_val) { if (client_id->len > 0) { data_string_forget(client_id, MDL); } } return ret_val; } /* * Response validation, defined in RFC 3315, sections 15.4, 15.6, 15.8, * 15.9 (slightly different wording, but same meaning): * * Servers MUST discard any received Request message that meet any of * the following conditions: * * - the message does not include a Server Identifier option. * - the contents of the Server Identifier option do not match the * server's DUID. * - the message does not include a Client Identifier option. */ int valid_client_resp(struct packet *packet, struct data_string *client_id, struct data_string *server_id) { int ret_val; struct option_cache *oc; /* INSIST((duid.data != NULL) && (duid.len > 0)); */ ret_val = 0; memset(client_id, 0, sizeof(*client_id)); memset(server_id, 0, sizeof(*server_id)); switch (get_client_id(packet, client_id)) { case ISC_R_SUCCESS: break; case ISC_R_NOTFOUND: log_debug("Discarding %s from %s; " "client identifier missing", dhcpv6_type_names[packet->dhcpv6_msg_type], piaddr(packet->client_addr)); goto exit; default: log_error("Error processing %s from %s; " "unable to evaluate Client Identifier", dhcpv6_type_names[packet->dhcpv6_msg_type], piaddr(packet->client_addr)); goto exit; } oc = lookup_option(&dhcpv6_universe, packet->options, D6O_SERVERID); if (oc == NULL) { log_debug("Discarding %s from %s: " "server identifier missing (CLIENTID %s)", dhcpv6_type_names[packet->dhcpv6_msg_type], piaddr(packet->client_addr), print_hex_1(client_id->len, client_id->data, 60)); goto exit; } if (!evaluate_option_cache(server_id, packet, NULL, NULL, packet->options, NULL, &global_scope, oc, MDL)) { log_error("Error processing %s from %s; " "unable to evaluate Server Identifier (CLIENTID %s)", dhcpv6_type_names[packet->dhcpv6_msg_type], piaddr(packet->client_addr), print_hex_1(client_id->len, client_id->data, 60)); goto exit; } if ((server_duid.len != server_id->len) || (memcmp(server_duid.data, server_id->data, server_duid.len) != 0)) { log_debug("Discarding %s from %s; " "not our server identifier " "(CLIENTID %s, SERVERID %s, server DUID %s)", dhcpv6_type_names[packet->dhcpv6_msg_type], piaddr(packet->client_addr), print_hex_1(client_id->len, client_id->data, 60), print_hex_2(server_id->len, server_id->data, 60), print_hex_3(server_duid.len, server_duid.data, 60)); goto exit; } /* looks good */ ret_val = 1; exit: if (!ret_val) { if (server_id->len > 0) { data_string_forget(server_id, MDL); } if (client_id->len > 0) { data_string_forget(client_id, MDL); } } return ret_val; } /* * Information request validation, defined in RFC 3315, section 15.12: * * Servers MUST discard any received Information-request message that * meets any of the following conditions: * * - The message includes a Server Identifier option and the DUID in * the option does not match the server's DUID. * * - The message includes an IA option. */ int valid_client_info_req(struct packet *packet, struct data_string *server_id) { int ret_val; struct option_cache *oc; struct data_string client_id; char client_id_str[80]; /* print_hex_1() uses maximum 60 characters, plus a few more for extra information */ ret_val = 0; memset(server_id, 0, sizeof(*server_id)); /* * Make a string that we can print out to give more * information about the client if we need to. * * By RFC 3315, Section 18.1.5 clients SHOULD have a * client-id on an Information-request packet, but it * is not strictly necessary. */ if (get_client_id(packet, &client_id) == ISC_R_SUCCESS) { snprintf(client_id_str, sizeof(client_id_str), " (CLIENTID %s)", print_hex_1(client_id.len, client_id.data, 60)); data_string_forget(&client_id, MDL); } else { client_id_str[0] = '\0'; } /* * Required by RFC 3315, section 15. */ if (packet->unicast) { log_debug("Discarding %s from %s; packet sent unicast%s", dhcpv6_type_names[packet->dhcpv6_msg_type], piaddr(packet->client_addr), client_id_str); goto exit; } oc = lookup_option(&dhcpv6_universe, packet->options, D6O_IA_NA); if (oc != NULL) { log_debug("Discarding %s from %s; " "IA_NA option present%s", dhcpv6_type_names[packet->dhcpv6_msg_type], piaddr(packet->client_addr), client_id_str); goto exit; } oc = lookup_option(&dhcpv6_universe, packet->options, D6O_IA_TA); if (oc != NULL) { log_debug("Discarding %s from %s; " "IA_TA option present%s", dhcpv6_type_names[packet->dhcpv6_msg_type], piaddr(packet->client_addr), client_id_str); goto exit; } oc = lookup_option(&dhcpv6_universe, packet->options, D6O_IA_PD); if (oc != NULL) { log_debug("Discarding %s from %s; " "IA_PD option present%s", dhcpv6_type_names[packet->dhcpv6_msg_type], piaddr(packet->client_addr), client_id_str); goto exit; } oc = lookup_option(&dhcpv6_universe, packet->options, D6O_SERVERID); if (oc != NULL) { if (!evaluate_option_cache(server_id, packet, NULL, NULL, packet->options, NULL, &global_scope, oc, MDL)) { log_error("Error processing %s from %s; " "unable to evaluate Server Identifier%s", dhcpv6_type_names[packet->dhcpv6_msg_type], piaddr(packet->client_addr), client_id_str); goto exit; } if ((server_duid.len != server_id->len) || (memcmp(server_duid.data, server_id->data, server_duid.len) != 0)) { log_debug("Discarding %s from %s; " "not our server identifier " "(SERVERID %s, server DUID %s)%s", dhcpv6_type_names[packet->dhcpv6_msg_type], piaddr(packet->client_addr), print_hex_1(server_id->len, server_id->data, 60), print_hex_2(server_duid.len, server_duid.data, 60), client_id_str); goto exit; } } /* looks good */ ret_val = 1; exit: if (!ret_val) { if (server_id->len > 0) { data_string_forget(server_id, MDL); } } return ret_val; } /* * Options that we want to send, in addition to what was requested * via the ORO. */ static const int required_opts[] = { D6O_CLIENTID, D6O_SERVERID, D6O_STATUS_CODE, D6O_PREFERENCE, 0 }; static const int required_opts_NAA[] = { D6O_CLIENTID, D6O_SERVERID, D6O_STATUS_CODE, 0 }; static const int required_opts_solicit[] = { D6O_CLIENTID, D6O_SERVERID, D6O_IA_NA, D6O_IA_TA, D6O_IA_PD, D6O_RAPID_COMMIT, D6O_STATUS_CODE, D6O_RECONF_ACCEPT, D6O_PREFERENCE, 0 }; static const int required_opts_agent[] = { D6O_INTERFACE_ID, D6O_RELAY_MSG, 0 }; static const int required_opts_IA[] = { D6O_IAADDR, D6O_STATUS_CODE, 0 }; static const int required_opts_IA_PD[] = { D6O_IAPREFIX, D6O_STATUS_CODE, 0 }; static const int required_opts_STATUS_CODE[] = { D6O_STATUS_CODE, 0 }; /* * Extracts from packet contents an IA_* option, storing the IA structure * in its entirety in enc_opt_data, and storing any decoded DHCPv6 options * in enc_opt_state for later lookup and evaluation. The 'offset' indicates * where in the IA_* the DHCPv6 options commence. */ static int get_encapsulated_IA_state(struct option_state **enc_opt_state, struct data_string *enc_opt_data, struct packet *packet, struct option_cache *oc, int offset) { /* * Get the raw data for the encapsulated options. */ memset(enc_opt_data, 0, sizeof(*enc_opt_data)); if (!evaluate_option_cache(enc_opt_data, packet, NULL, NULL, packet->options, NULL, &global_scope, oc, MDL)) { log_error("get_encapsulated_IA_state: " "error evaluating raw option."); return 0; } if (enc_opt_data->len < offset) { log_error("get_encapsulated_IA_state: raw option too small."); data_string_forget(enc_opt_data, MDL); return 0; } /* * Now create the option state structure, and pass it to the * function that parses options. */ *enc_opt_state = NULL; if (!option_state_allocate(enc_opt_state, MDL)) { log_error("get_encapsulated_IA_state: no memory for options."); data_string_forget(enc_opt_data, MDL); return 0; } if (!parse_option_buffer(*enc_opt_state, enc_opt_data->data + offset, enc_opt_data->len - offset, &dhcpv6_universe)) { log_error("get_encapsulated_IA_state: error parsing options."); option_state_dereference(enc_opt_state, MDL); data_string_forget(enc_opt_data, MDL); return 0; } return 1; } static int set_status_code(u_int16_t status_code, const char *status_message, struct option_state *opt_state) { struct data_string d; int ret_val; memset(&d, 0, sizeof(d)); d.len = sizeof(status_code) + strlen(status_message); if (!buffer_allocate(&d.buffer, d.len, MDL)) { log_fatal("set_status_code: no memory for status code."); } d.data = d.buffer->data; putUShort(d.buffer->data, status_code); memcpy(d.buffer->data + sizeof(status_code), status_message, d.len - sizeof(status_code)); if (!save_option_buffer(&dhcpv6_universe, opt_state, d.buffer, (unsigned char *)d.data, d.len, D6O_STATUS_CODE, 0)) { log_error("set_status_code: error saving status code."); ret_val = 0; } else { ret_val = 1; } data_string_forget(&d, MDL); return ret_val; } /* * We have a set of operations we do to set up the reply packet, which * is the same for many message types. */ static int start_reply(struct packet *packet, const struct data_string *client_id, const struct data_string *server_id, struct option_state **opt_state, struct dhcpv6_packet *reply) { struct option_cache *oc; const unsigned char *server_id_data; int server_id_len; /* * Build our option state for reply. */ *opt_state = NULL; if (!option_state_allocate(opt_state, MDL)) { log_error("start_reply: no memory for option_state."); return 0; } execute_statements_in_scope(NULL, packet, NULL, NULL, packet->options, *opt_state, &global_scope, root_group, NULL); /* * A small bit of special handling for Solicit messages. * * We could move the logic into a flag, but for now just check * explicitly. */ if (packet->dhcpv6_msg_type == DHCPV6_SOLICIT) { reply->msg_type = DHCPV6_ADVERTISE; /* * If: * - this message type supports rapid commit (Solicit), and * - the server is configured to supply a rapid commit, and * - the client requests a rapid commit, * Then we add a rapid commit option, and send Reply (instead * of an Advertise). */ oc = lookup_option(&dhcpv6_universe, *opt_state, D6O_RAPID_COMMIT); if (oc != NULL) { oc = lookup_option(&dhcpv6_universe, packet->options, D6O_RAPID_COMMIT); if (oc != NULL) { /* Rapid-commit in action. */ reply->msg_type = DHCPV6_REPLY; } else { /* Don't want a rapid-commit in advertise. */ delete_option(&dhcpv6_universe, *opt_state, D6O_RAPID_COMMIT); } } } else { reply->msg_type = DHCPV6_REPLY; /* Delete the rapid-commit from the sent options. */ oc = lookup_option(&dhcpv6_universe, *opt_state, D6O_RAPID_COMMIT); if (oc != NULL) { delete_option(&dhcpv6_universe, *opt_state, D6O_RAPID_COMMIT); } } /* * Use the client's transaction identifier for the reply. */ memcpy(reply->transaction_id, packet->dhcpv6_transaction_id, sizeof(reply->transaction_id)); /* * RFC 3315, section 18.2 says we need server identifier and * client identifier. * * If the server ID is defined via the configuration file, then * it will already be present in the option state at this point, * so we don't need to set it. * * If we have a server ID passed in from the caller, * use that, otherwise use the global DUID. */ oc = lookup_option(&dhcpv6_universe, *opt_state, D6O_SERVERID); if (oc == NULL) { if (server_id == NULL) { server_id_data = server_duid.data; server_id_len = server_duid.len; } else { server_id_data = server_id->data; server_id_len = server_id->len; } if (!save_option_buffer(&dhcpv6_universe, *opt_state, NULL, (unsigned char *)server_id_data, server_id_len, D6O_SERVERID, 0)) { log_error("start_reply: " "error saving server identifier."); return 0; } } if (client_id->buffer != NULL) { if (!save_option_buffer(&dhcpv6_universe, *opt_state, client_id->buffer, (unsigned char *)client_id->data, client_id->len, D6O_CLIENTID, 0)) { log_error("start_reply: error saving " "client identifier."); return 0; } } /* * If the client accepts reconfiguration, let it know that we * will send them. * * Note: we don't actually do this yet, but DOCSIS requires we * claim to. */ oc = lookup_option(&dhcpv6_universe, packet->options, D6O_RECONF_ACCEPT); if (oc != NULL) { if (!save_option_buffer(&dhcpv6_universe, *opt_state, NULL, (unsigned char *)"", 0, D6O_RECONF_ACCEPT, 0)) { log_error("start_reply: " "error saving RECONF_ACCEPT option."); option_state_dereference(opt_state, MDL); return 0; } } return 1; } /* * Try to get the IPv6 address the client asked for from the * pool. * * addr is the result (should be a pointer to NULL on entry) * pool is the pool to search in * requested_addr is the address the client wants */ static isc_result_t try_client_v6_address(struct iasubopt **addr, struct ipv6_pool *pool, const struct data_string *requested_addr) { struct in6_addr tmp_addr; isc_result_t result; if (requested_addr->len < sizeof(tmp_addr)) { return DHCP_R_INVALIDARG; } memcpy(&tmp_addr, requested_addr->data, sizeof(tmp_addr)); if (IN6_IS_ADDR_UNSPECIFIED(&tmp_addr)) { return ISC_R_FAILURE; } /* * The address is not covered by this (or possibly any) dynamic * range. */ if (!ipv6_in_pool(&tmp_addr, pool)) { return ISC_R_ADDRNOTAVAIL; } if (lease6_exists(pool, &tmp_addr)) { return ISC_R_ADDRINUSE; } result = iasubopt_allocate(addr, MDL); if (result != ISC_R_SUCCESS) { return result; } (*addr)->addr = tmp_addr; (*addr)->plen = 0; /* Default is soft binding for 2 minutes. */ result = add_lease6(pool, *addr, cur_time + 120); if (result != ISC_R_SUCCESS) { iasubopt_dereference(addr, MDL); } return result; } /* * Get an IPv6 address for the client. * * addr is the result (should be a pointer to NULL on entry) * packet is the information about the packet from the client * requested_iaaddr is a hint from the client * client_id is the DUID for the client */ static isc_result_t pick_v6_address(struct iasubopt **addr, struct shared_network *shared_network, const struct data_string *client_id) { struct ipv6_pool *p; int i; int start_pool; unsigned int attempts; char tmp_buf[INET6_ADDRSTRLEN]; /* * No address pools, we're done. */ if (shared_network->ipv6_pools == NULL) { log_debug("Unable to pick client address: " "no IPv6 pools on this shared network"); return ISC_R_NORESOURCES; } for (i = 0;; i++) { p = shared_network->ipv6_pools[i]; if (p == NULL) { log_debug("Unable to pick client address: " "no IPv6 address pools " "on this shared network"); return ISC_R_NORESOURCES; } if (p->pool_type == D6O_IA_NA) { break; } } /* * Otherwise try to get a lease from the first subnet possible. * * We start looking at the last pool we allocated from, unless * it had a collision trying to allocate an address. This will * tend to move us into less-filled pools. */ start_pool = shared_network->last_ipv6_pool; i = start_pool; do { p = shared_network->ipv6_pools[i]; if ((p->pool_type == D6O_IA_NA) && (create_lease6(p, addr, &attempts, client_id, cur_time + 120) == ISC_R_SUCCESS)) { /* * Record the pool used (or next one if there * was a collision). */ if (attempts > 1) { i++; if (shared_network->ipv6_pools[i] == NULL) { i = 0; } } shared_network->last_ipv6_pool = i; log_debug("Picking pool address %s", inet_ntop(AF_INET6, &((*addr)->addr), tmp_buf, sizeof(tmp_buf))); return ISC_R_SUCCESS; } i++; if (shared_network->ipv6_pools[i] == NULL) { i = 0; } } while (i != start_pool); /* * If we failed to pick an IPv6 address from any of the subnets. * Presumably that means we have no addresses for the client. */ log_debug("Unable to pick client address: no addresses available"); return ISC_R_NORESOURCES; } /* * Try to get the IPv6 prefix the client asked for from the * prefix pool. * * pref is the result (should be a pointer to NULL on entry) * pool is the prefix pool to search in * requested_pref is the address the client wants */ static isc_result_t try_client_v6_prefix(struct iasubopt **pref, struct ipv6_pool *pool, const struct data_string *requested_pref) { u_int8_t tmp_plen; struct in6_addr tmp_pref; struct iaddr ia; isc_result_t result; if (requested_pref->len < sizeof(tmp_plen) + sizeof(tmp_pref)) { return DHCP_R_INVALIDARG; } tmp_plen = (int) requested_pref->data[0]; if ((tmp_plen < 3) || (tmp_plen > 128) || ((int)tmp_plen != pool->units)) { return ISC_R_FAILURE; } memcpy(&tmp_pref, requested_pref->data + 1, sizeof(tmp_pref)); if (IN6_IS_ADDR_UNSPECIFIED(&tmp_pref)) { return ISC_R_FAILURE; } ia.len = 16; memcpy(&ia.iabuf, &tmp_pref, 16); if (!is_cidr_mask_valid(&ia, (int) tmp_plen)) { return ISC_R_FAILURE; } if (!ipv6_in_pool(&tmp_pref, pool)) { return ISC_R_ADDRNOTAVAIL; } if (prefix6_exists(pool, &tmp_pref, tmp_plen)) { return ISC_R_ADDRINUSE; } result = iasubopt_allocate(pref, MDL); if (result != ISC_R_SUCCESS) { return result; } (*pref)->addr = tmp_pref; (*pref)->plen = tmp_plen; /* Default is soft binding for 2 minutes. */ result = add_lease6(pool, *pref, cur_time + 120); if (result != ISC_R_SUCCESS) { iasubopt_dereference(pref, MDL); } return result; } /* * Get an IPv6 prefix for the client. * * pref is the result (should be a pointer to NULL on entry) * packet is the information about the packet from the client * requested_iaprefix is a hint from the client * plen is -1 or the requested prefix length * client_id is the DUID for the client */ static isc_result_t pick_v6_prefix(struct iasubopt **pref, int plen, struct shared_network *shared_network, const struct data_string *client_id) { struct ipv6_pool *p; int i; unsigned int attempts; char tmp_buf[INET6_ADDRSTRLEN]; /* * No prefix pools, we're done. */ if (shared_network->ipv6_pools == NULL) { log_debug("Unable to pick client prefix: " "no IPv6 pools on this shared network"); return ISC_R_NORESOURCES; } for (i = 0;; i++) { p = shared_network->ipv6_pools[i]; if (p == NULL) { log_debug("Unable to pick client prefix: " "no IPv6 prefix pools " "on this shared network"); return ISC_R_NORESOURCES; } if (p->pool_type == D6O_IA_PD) { break; } } /* * Otherwise try to get a prefix. */ for (i = 0;; i++) { p = shared_network->ipv6_pools[i]; if (p == NULL) { break; } if (p->pool_type != D6O_IA_PD) { continue; } /* * Try only pools with the requested prefix length if any. */ if ((plen >= 0) && (p->units != plen)) { continue; } if (create_prefix6(p, pref, &attempts, client_id, cur_time + 120) == ISC_R_SUCCESS) { log_debug("Picking pool prefix %s/%u", inet_ntop(AF_INET6, &((*pref)->addr), tmp_buf, sizeof(tmp_buf)), (unsigned) (*pref)->plen); return ISC_R_SUCCESS; } } /* * If we failed to pick an IPv6 prefix * Presumably that means we have no prefixes for the client. */ log_debug("Unable to pick client prefix: no prefixes available"); return ISC_R_NORESOURCES; } /* *! \file server/dhcpv6.c * * \brief construct a reply containing information about a client's lease * * lease_to_client() is called from several messages to construct a * reply that contains all that we know about the client's correct lease * (or projected lease). * * Solicit - "Soft" binding, ignore unknown addresses or bindings, just * send what we "may" give them on a request. * * Request - "Hard" binding, but ignore supplied addresses (just provide what * the client should really use). * * Renew - "Hard" binding, but client-supplied addresses are 'real'. Error * Rebind out any "wrong" addresses the client sends. This means we send * an empty IA_NA with a status code of NoBinding or NotOnLink or * possibly send the address with zeroed lifetimes. * * Information-Request - No binding. * * The basic structure is to traverse the client-supplied data first, and * validate and echo back any contents that can be. If the client-supplied * data does not error out (on renew/rebind as above), but we did not send * any addresses, attempt to allocate one. * * At the end of the this function we call commit_leases_timed() to * fsync and rotate the file as necessary. commit_leases_timed() will * check that we have written at least one lease to the file and that * some time has passed before doing any fsync or file rewrite so we * don't bother tracking if we did a write_ia during this function. */ /* TODO: look at client hints for lease times */ static void lease_to_client(struct data_string *reply_ret, struct packet *packet, const struct data_string *client_id, const struct data_string *server_id) { static struct reply_state reply; struct option_cache *oc; struct data_string packet_oro; #if defined (RFC3315_PRE_ERRATA_2010_08) isc_boolean_t no_resources_avail = ISC_FALSE; #endif /* Locate the client. */ if (shared_network_from_packet6(&reply.shared, packet) != ISC_R_SUCCESS) goto exit; /* * Initialize the reply. */ packet_reference(&reply.packet, packet, MDL); data_string_copy(&reply.client_id, client_id, MDL); if (!start_reply(packet, client_id, server_id, &reply.opt_state, &reply.buf.reply)) goto exit; /* Set the write cursor to just past the reply header. */ reply.cursor = REPLY_OPTIONS_INDEX; /* * Get the ORO from the packet, if any. */ oc = lookup_option(&dhcpv6_universe, packet->options, D6O_ORO); memset(&packet_oro, 0, sizeof(packet_oro)); if (oc != NULL) { if (!evaluate_option_cache(&packet_oro, packet, NULL, NULL, packet->options, NULL, &global_scope, oc, MDL)) { log_error("lease_to_client: error evaluating ORO."); goto exit; } } /* * Find a host record that matches from the packet, if any, and is * valid for the shared network the client is on. */ if (find_hosts_by_uid(&reply.host, client_id->data, client_id->len, MDL)) seek_shared_host(&reply.host, reply.shared); if ((reply.host == NULL) && find_hosts_by_option(&reply.host, packet, packet->options, MDL)) seek_shared_host(&reply.host, reply.shared); /* * Check for 'hardware' matches last, as some of the synthesis methods * are not considered to be as reliable. */ if ((reply.host == NULL) && find_hosts_by_duid_chaddr(&reply.host, client_id)) seek_shared_host(&reply.host, reply.shared); /* Process the client supplied IA's onto the reply buffer. */ reply.ia_count = 0; oc = lookup_option(&dhcpv6_universe, packet->options, D6O_IA_NA); for (; oc != NULL ; oc = oc->next) { isc_result_t status; /* Start counting resources (addresses) offered. */ reply.client_resources = 0; reply.resources_included = ISC_FALSE; status = reply_process_ia_na(&reply, oc); /* * We continue to try other IA's whether we can address * this one or not. Any other result is an immediate fail. */ if ((status != ISC_R_SUCCESS) && (status != ISC_R_NORESOURCES)) goto exit; #if defined (RFC3315_PRE_ERRATA_2010_08) /* * If any address cannot be given to any IA, then set the * NoAddrsAvail status code. */ if (reply.client_resources == 0) no_resources_avail = ISC_TRUE; #endif } oc = lookup_option(&dhcpv6_universe, packet->options, D6O_IA_TA); for (; oc != NULL ; oc = oc->next) { isc_result_t status; /* Start counting resources (addresses) offered. */ reply.client_resources = 0; reply.resources_included = ISC_FALSE; status = reply_process_ia_ta(&reply, oc); /* * We continue to try other IA's whether we can address * this one or not. Any other result is an immediate fail. */ if ((status != ISC_R_SUCCESS) && (status != ISC_R_NORESOURCES)) goto exit; #if defined (RFC3315_PRE_ERRATA_2010_08) /* * If any address cannot be given to any IA, then set the * NoAddrsAvail status code. */ if (reply.client_resources == 0) no_resources_avail = ISC_TRUE; #endif } /* Same for IA_PD's. */ reply.pd_count = 0; oc = lookup_option(&dhcpv6_universe, packet->options, D6O_IA_PD); for (; oc != NULL ; oc = oc->next) { isc_result_t status; /* Start counting resources (prefixes) offered. */ reply.client_resources = 0; reply.resources_included = ISC_FALSE; status = reply_process_ia_pd(&reply, oc); /* * We continue to try other IA_PD's whether we can address * this one or not. Any other result is an immediate fail. */ if ((status != ISC_R_SUCCESS) && (status != ISC_R_NORESOURCES)) goto exit; } /* * Make no reply if we gave no resources and is not * for Information-Request. */ if ((reply.ia_count == 0) && (reply.pd_count == 0)) { if (reply.packet->dhcpv6_msg_type != DHCPV6_INFORMATION_REQUEST) goto exit; /* * Because we only execute statements on a per-IA basis, * we need to execute statements in any non-IA reply to * source configuration. */ execute_statements_in_scope(NULL, reply.packet, NULL, NULL, reply.packet->options, reply.opt_state, &global_scope, reply.shared->group, root_group); /* Bring in any configuration from a host record. */ if (reply.host != NULL) execute_statements_in_scope(NULL, reply.packet, NULL, NULL, reply.packet->options, reply.opt_state, &global_scope, reply.host->group, reply.shared->group); } /* * RFC3315 section 17.2.2 (Solicit): * * If the server will not assign any addresses to any IAs in a * subsequent Request from the client, the server MUST send an * Advertise message to the client that includes only a Status * Code option with code NoAddrsAvail and a status message for * the user, a Server Identifier option with the server's DUID, * and a Client Identifier option with the client's DUID. * * Section 18.2.1 (Request): * * If the server cannot assign any addresses to an IA in the * message from the client, the server MUST include the IA in * the Reply message with no addresses in the IA and a Status * Code option in the IA containing status code NoAddrsAvail. * * Section 18.1.8 (Client Behavior): * * Leave unchanged any information about addresses the client has * recorded in the IA but that were not included in the IA from * the server. * Sends a Renew/Rebind if the IA is not in the Reply message. */ #if defined (RFC3315_PRE_ERRATA_2010_08) if (no_resources_avail && (reply.ia_count != 0) && (reply.packet->dhcpv6_msg_type == DHCPV6_SOLICIT)) { /* Set the NoAddrsAvail status code. */ if (!set_status_code(STATUS_NoAddrsAvail, "No addresses available for this " "interface.", reply.opt_state)) { log_error("lease_to_client: Unable to set " "NoAddrsAvail status code."); goto exit; } /* Rewind the cursor to the start. */ reply.cursor = REPLY_OPTIONS_INDEX; /* * Produce an advertise that includes only: * * Status code. * Server DUID. * Client DUID. */ reply.buf.reply.msg_type = DHCPV6_ADVERTISE; reply.cursor += store_options6((char *)reply.buf.data + reply.cursor, sizeof(reply.buf) - reply.cursor, reply.opt_state, reply.packet, required_opts_NAA, NULL); } else { /* * Having stored the client's IA's, store any options that * will fit in the remaining space. */ reply.cursor += store_options6((char *)reply.buf.data + reply.cursor, sizeof(reply.buf) - reply.cursor, reply.opt_state, reply.packet, required_opts_solicit, &packet_oro); } #else /* defined (RFC3315_PRE_ERRATA_2010_08) */ /* * Having stored the client's IA's, store any options that * will fit in the remaining space. */ reply.cursor += store_options6((char *)reply.buf.data + reply.cursor, sizeof(reply.buf) - reply.cursor, reply.opt_state, reply.packet, required_opts_solicit, &packet_oro); #endif /* defined (RFC3315_PRE_ERRATA_2010_08) */ /* Return our reply to the caller. */ reply_ret->len = reply.cursor; reply_ret->buffer = NULL; if (!buffer_allocate(&reply_ret->buffer, reply.cursor, MDL)) { log_fatal("No memory to store Reply."); } memcpy(reply_ret->buffer->data, reply.buf.data, reply.cursor); reply_ret->data = reply_ret->buffer->data; /* If appropriate commit and rotate the lease file */ (void) commit_leases_timed(); exit: /* Cleanup. */ if (reply.shared != NULL) shared_network_dereference(&reply.shared, MDL); if (reply.host != NULL) host_dereference(&reply.host, MDL); if (reply.opt_state != NULL) option_state_dereference(&reply.opt_state, MDL); if (reply.packet != NULL) packet_dereference(&reply.packet, MDL); if (reply.client_id.data != NULL) data_string_forget(&reply.client_id, MDL); reply.renew = reply.rebind = reply.prefer = reply.valid = 0; reply.cursor = 0; } /* Process a client-supplied IA_NA. This may append options to the tail of * the reply packet being built in the reply_state structure. */ static isc_result_t reply_process_ia_na(struct reply_state *reply, struct option_cache *ia) { isc_result_t status = ISC_R_SUCCESS; u_int32_t iaid; unsigned ia_cursor; struct option_state *packet_ia; struct option_cache *oc; struct data_string ia_data, data; /* Initialize values that will get cleaned up on return. */ packet_ia = NULL; memset(&ia_data, 0, sizeof(ia_data)); memset(&data, 0, sizeof(data)); /* * Note that find_client_address() may set reply->lease. */ /* Make sure there is at least room for the header. */ if ((reply->cursor + IA_NA_OFFSET + 4) > sizeof(reply->buf)) { log_error("reply_process_ia_na: Reply too long for IA."); return ISC_R_NOSPACE; } /* Fetch the IA_NA contents. */ if (!get_encapsulated_IA_state(&packet_ia, &ia_data, reply->packet, ia, IA_NA_OFFSET)) { log_error("reply_process_ia_na: error evaluating ia"); status = ISC_R_FAILURE; goto cleanup; } /* Extract IA_NA header contents. */ iaid = getULong(ia_data.data); reply->renew = getULong(ia_data.data + 4); reply->rebind = getULong(ia_data.data + 8); /* Create an IA_NA structure. */ if (ia_allocate(&reply->ia, iaid, (char *)reply->client_id.data, reply->client_id.len, MDL) != ISC_R_SUCCESS) { log_error("reply_process_ia_na: no memory for ia."); status = ISC_R_NOMEMORY; goto cleanup; } reply->ia->ia_type = D6O_IA_NA; /* Cache pre-existing IA, if any. */ ia_hash_lookup(&reply->old_ia, ia_na_active, (unsigned char *)reply->ia->iaid_duid.data, reply->ia->iaid_duid.len, MDL); /* * Create an option cache to carry the IA_NA option contents, and * execute any user-supplied values into it. */ if (!option_state_allocate(&reply->reply_ia, MDL)) { status = ISC_R_NOMEMORY; goto cleanup; } /* Check & cache the fixed host record. */ if ((reply->host != NULL) && (reply->host->fixed_addr != NULL)) { struct iaddr tmp_addr; if (!evaluate_option_cache(&reply->fixed, NULL, NULL, NULL, NULL, NULL, &global_scope, reply->host->fixed_addr, MDL)) { log_error("reply_process_ia_na: unable to evaluate " "fixed address."); status = ISC_R_FAILURE; goto cleanup; } if (reply->fixed.len < 16) { log_error("reply_process_ia_na: invalid fixed address."); status = DHCP_R_INVALIDARG; goto cleanup; } /* Find the static lease's subnet. */ tmp_addr.len = 16; memcpy(tmp_addr.iabuf, reply->fixed.data, 16); if (find_grouped_subnet(&reply->subnet, reply->shared, tmp_addr, MDL) == 0) log_fatal("Impossible condition at %s:%d.", MDL); reply->static_lease = ISC_TRUE; } else reply->static_lease = ISC_FALSE; /* * Save the cursor position at the start of the IA, so we can * set length and adjust t1/t2 values later. We write a temporary * header out now just in case we decide to adjust the packet * within sub-process functions. */ ia_cursor = reply->cursor; /* Initialize the IA_NA header. First the code. */ putUShort(reply->buf.data + reply->cursor, (unsigned)D6O_IA_NA); reply->cursor += 2; /* Then option length. */ putUShort(reply->buf.data + reply->cursor, 0x0Cu); reply->cursor += 2; /* Then IA_NA header contents; IAID. */ putULong(reply->buf.data + reply->cursor, iaid); reply->cursor += 4; /* We store the client's t1 for now, and may over-ride it later. */ putULong(reply->buf.data + reply->cursor, reply->renew); reply->cursor += 4; /* We store the client's t2 for now, and may over-ride it later. */ putULong(reply->buf.data + reply->cursor, reply->rebind); reply->cursor += 4; /* * For each address in this IA_NA, decide what to do about it. * * Guidelines: * * The client leaves unchanged any infomation about addresses * it has recorded but are not included ("cancel/break" below). * A not included IA ("cleanup" below) could give a Renew/Rebind. */ oc = lookup_option(&dhcpv6_universe, packet_ia, D6O_IAADDR); reply->valid = reply->prefer = 0xffffffff; reply->client_valid = reply->client_prefer = 0; for (; oc != NULL ; oc = oc->next) { status = reply_process_addr(reply, oc); /* * Canceled means we did not allocate addresses to the * client, but we're "done" with this IA - we set a status * code. So transmit this reply, e.g., move on to the next * IA. */ if (status == ISC_R_CANCELED) break; if ((status != ISC_R_SUCCESS) && (status != ISC_R_ADDRINUSE) && (status != ISC_R_ADDRNOTAVAIL)) goto cleanup; } reply->ia_count++; /* * If we fell through the above and never gave the client * an address, give it one now. */ if ((status != ISC_R_CANCELED) && (reply->client_resources == 0)) { status = find_client_address(reply); if (status == ISC_R_NORESOURCES) { switch (reply->packet->dhcpv6_msg_type) { case DHCPV6_SOLICIT: /* * No address for any IA is handled * by the caller. */ /* FALL THROUGH */ case DHCPV6_REQUEST: /* Section 18.2.1 (Request): * * If the server cannot assign any addresses to * an IA in the message from the client, the * server MUST include the IA in the Reply * message with no addresses in the IA and a * Status Code option in the IA containing * status code NoAddrsAvail. */ option_state_dereference(&reply->reply_ia, MDL); if (!option_state_allocate(&reply->reply_ia, MDL)) { log_error("reply_process_ia_na: No " "memory for option state " "wipe."); status = ISC_R_NOMEMORY; goto cleanup; } if (!set_status_code(STATUS_NoAddrsAvail, "No addresses available " "for this interface.", reply->reply_ia)) { log_error("reply_process_ia_na: Unable " "to set NoAddrsAvail status " "code."); status = ISC_R_FAILURE; goto cleanup; } status = ISC_R_SUCCESS; break; default: /* * RFC 3315 does not tell us to emit a status * code in this condition, or anything else. * * If we included non-allocated addresses * (zeroed lifetimes) in an IA, then the client * will deconfigure them. * * So we want to include the IA even if we * can't give it a new address if it includes * zeroed lifetime addresses. * * We don't want to include the IA if we * provide zero addresses including zeroed * lifetimes. */ if (reply->resources_included) status = ISC_R_SUCCESS; else goto cleanup; break; } } if (status != ISC_R_SUCCESS) goto cleanup; } reply->cursor += store_options6((char *)reply->buf.data + reply->cursor, sizeof(reply->buf) - reply->cursor, reply->reply_ia, reply->packet, required_opts_IA, NULL); /* Reset the length of this IA to match what was just written. */ putUShort(reply->buf.data + ia_cursor + 2, reply->cursor - (ia_cursor + 4)); /* * T1/T2 time selection is kind of weird. We actually use DHCP * (v4) scoped options as handy existing places where these might * be configured by an administrator. A value of zero tells the * client it may choose its own renewal time. */ reply->renew = 0; oc = lookup_option(&dhcp_universe, reply->opt_state, DHO_DHCP_RENEWAL_TIME); if (oc != NULL) { if (!evaluate_option_cache(&data, reply->packet, NULL, NULL, reply->packet->options, reply->opt_state, &global_scope, oc, MDL) || (data.len != 4)) { log_error("Invalid renewal time."); } else { reply->renew = getULong(data.data); } if (data.data != NULL) data_string_forget(&data, MDL); } putULong(reply->buf.data + ia_cursor + 8, reply->renew); /* Now T2. */ reply->rebind = 0; oc = lookup_option(&dhcp_universe, reply->opt_state, DHO_DHCP_REBINDING_TIME); if (oc != NULL) { if (!evaluate_option_cache(&data, reply->packet, NULL, NULL, reply->packet->options, reply->opt_state, &global_scope, oc, MDL) || (data.len != 4)) { log_error("Invalid rebinding time."); } else { reply->rebind = getULong(data.data); } if (data.data != NULL) data_string_forget(&data, MDL); } putULong(reply->buf.data + ia_cursor + 12, reply->rebind); /* * If this is not a 'soft' binding, consume the new changes into * the database (if any have been attached to the ia_na). * * Loop through the assigned dynamic addresses, referencing the * leases onto this IA_NA rather than any old ones, and updating * pool timers for each (if any). */ if ((status != ISC_R_CANCELED) && !reply->static_lease && (reply->buf.reply.msg_type == DHCPV6_REPLY) && (reply->ia->num_iasubopt != 0)) { struct iasubopt *tmp; struct data_string *ia_id; int i; for (i = 0 ; i < reply->ia->num_iasubopt ; i++) { tmp = reply->ia->iasubopt[i]; if (tmp->ia != NULL) ia_dereference(&tmp->ia, MDL); ia_reference(&tmp->ia, reply->ia, MDL); /* Commit 'hard' bindings. */ tmp->hard_lifetime_end_time = tmp->soft_lifetime_end_time; tmp->soft_lifetime_end_time = 0; renew_lease6(tmp->ipv6_pool, tmp); schedule_lease_timeout(tmp->ipv6_pool); #if defined (NSUPDATE) /* * Perform ddns updates. */ oc = lookup_option(&server_universe, reply->opt_state, SV_DDNS_UPDATES); if ((oc == NULL) || evaluate_boolean_option_cache(NULL, reply->packet, NULL, NULL, reply->packet->options, reply->opt_state, &tmp->scope, oc, MDL)) { ddns_updates(reply->packet, NULL, NULL, tmp, NULL, reply->opt_state); } #endif } /* Remove any old ia from the hash. */ if (reply->old_ia != NULL) { ia_id = &reply->old_ia->iaid_duid; ia_hash_delete(ia_na_active, (unsigned char *)ia_id->data, ia_id->len, MDL); ia_dereference(&reply->old_ia, MDL); } /* Put new ia into the hash. */ reply->ia->cltt = cur_time; ia_id = &reply->ia->iaid_duid; ia_hash_add(ia_na_active, (unsigned char *)ia_id->data, ia_id->len, reply->ia, MDL); write_ia(reply->ia); } cleanup: if (packet_ia != NULL) option_state_dereference(&packet_ia, MDL); if (reply->reply_ia != NULL) option_state_dereference(&reply->reply_ia, MDL); if (ia_data.data != NULL) data_string_forget(&ia_data, MDL); if (data.data != NULL) data_string_forget(&data, MDL); if (reply->ia != NULL) ia_dereference(&reply->ia, MDL); if (reply->old_ia != NULL) ia_dereference(&reply->old_ia, MDL); if (reply->lease != NULL) iasubopt_dereference(&reply->lease, MDL); if (reply->fixed.data != NULL) data_string_forget(&reply->fixed, MDL); if (reply->subnet != NULL) subnet_dereference(&reply->subnet, MDL); /* * ISC_R_CANCELED is a status code used by the addr processing to * indicate we're replying with a status code. This is still a * success at higher layers. */ return((status == ISC_R_CANCELED) ? ISC_R_SUCCESS : status); } /* * Process an IAADDR within a given IA_xA, storing any IAADDR reply contents * into the reply's current ia-scoped option cache. Returns ISC_R_CANCELED * in the event we are replying with a status code and do not wish to process * more IAADDRs within this IA. */ static isc_result_t reply_process_addr(struct reply_state *reply, struct option_cache *addr) { u_int32_t pref_life, valid_life; struct binding_scope **scope; struct group *group; struct subnet *subnet; struct iaddr tmp_addr; struct option_cache *oc; struct data_string iaaddr, data; isc_result_t status = ISC_R_SUCCESS; /* Initializes values that will be cleaned up. */ memset(&iaaddr, 0, sizeof(iaaddr)); memset(&data, 0, sizeof(data)); /* Note that reply->lease may be set by address_is_owned() */ /* * There is no point trying to process an incoming address if there * is no room for an outgoing address. */ if ((reply->cursor + 28) > sizeof(reply->buf)) { log_error("reply_process_addr: Out of room for address."); return ISC_R_NOSPACE; } /* Extract this IAADDR option. */ if (!evaluate_option_cache(&iaaddr, reply->packet, NULL, NULL, reply->packet->options, NULL, &global_scope, addr, MDL) || (iaaddr.len < IAADDR_OFFSET)) { log_error("reply_process_addr: error evaluating IAADDR."); status = ISC_R_FAILURE; goto cleanup; } /* The first 16 bytes are the IPv6 address. */ pref_life = getULong(iaaddr.data + 16); valid_life = getULong(iaaddr.data + 20); if ((reply->client_valid == 0) || (reply->client_valid > valid_life)) reply->client_valid = valid_life; if ((reply->client_prefer == 0) || (reply->client_prefer > pref_life)) reply->client_prefer = pref_life; /* * Clients may choose to send :: as an address, with the idea to give * hints about preferred-lifetime or valid-lifetime. */ tmp_addr.len = 16; memset(tmp_addr.iabuf, 0, 16); if (!memcmp(iaaddr.data, tmp_addr.iabuf, 16)) { /* Status remains success; we just ignore this one. */ goto cleanup; } /* tmp_addr len remains 16 */ memcpy(tmp_addr.iabuf, iaaddr.data, 16); /* * Verify that this address is on the client's network. */ for (subnet = reply->shared->subnets ; subnet != NULL ; subnet = subnet->next_sibling) { if (addr_eq(subnet_number(tmp_addr, subnet->netmask), subnet->net)) break; } /* Address not found on shared network. */ if (subnet == NULL) { /* Ignore this address on 'soft' bindings. */ if (reply->packet->dhcpv6_msg_type == DHCPV6_SOLICIT) { /* disable rapid commit */ reply->buf.reply.msg_type = DHCPV6_ADVERTISE; delete_option(&dhcpv6_universe, reply->opt_state, D6O_RAPID_COMMIT); /* status remains success */ goto cleanup; } /* * RFC3315 section 18.2.1: * * If the server finds that the prefix on one or more IP * addresses in any IA in the message from the client is not * appropriate for the link to which the client is connected, * the server MUST return the IA to the client with a Status * Code option with the value NotOnLink. */ if (reply->packet->dhcpv6_msg_type == DHCPV6_REQUEST) { /* Rewind the IA_NA to empty. */ option_state_dereference(&reply->reply_ia, MDL); if (!option_state_allocate(&reply->reply_ia, MDL)) { log_error("reply_process_addr: No memory for " "option state wipe."); status = ISC_R_NOMEMORY; goto cleanup; } /* Append a NotOnLink status code. */ if (!set_status_code(STATUS_NotOnLink, "Address not for use on this " "link.", reply->reply_ia)) { log_error("reply_process_addr: Failure " "setting status code."); status = ISC_R_FAILURE; goto cleanup; } /* Fin (no more IAADDRs). */ status = ISC_R_CANCELED; goto cleanup; } /* * RFC3315 sections 18.2.3 and 18.2.4 have identical language: * * If the server finds that any of the addresses are not * appropriate for the link to which the client is attached, * the server returns the address to the client with lifetimes * of 0. */ if ((reply->packet->dhcpv6_msg_type != DHCPV6_RENEW) && (reply->packet->dhcpv6_msg_type != DHCPV6_REBIND)) { log_error("It is impossible to lease a client that is " "not sending a solicit, request, renew, or " "rebind."); status = ISC_R_FAILURE; goto cleanup; } reply->send_prefer = reply->send_valid = 0; goto send_addr; } /* Verify the address belongs to the client. */ if (!address_is_owned(reply, &tmp_addr)) { /* * For solicit and request, any addresses included are * 'requested' addresses. For rebind, we actually have * no direction on what to do from 3315 section 18.2.4! * So I think the best bet is to try and give it out, and if * we can't, zero lifetimes. */ if ((reply->packet->dhcpv6_msg_type == DHCPV6_SOLICIT) || (reply->packet->dhcpv6_msg_type == DHCPV6_REQUEST) || (reply->packet->dhcpv6_msg_type == DHCPV6_REBIND)) { status = reply_process_try_addr(reply, &tmp_addr); /* * If the address is in use, or isn't in any dynamic * range, continue as normal. If any other error was * found, error out. */ if ((status != ISC_R_SUCCESS) && (status != ISC_R_ADDRINUSE) && (status != ISC_R_ADDRNOTAVAIL)) goto cleanup; /* * If we didn't honor this lease, for solicit and * request we simply omit it from our answer. For * rebind, we send it with zeroed lifetimes. */ if (reply->lease == NULL) { if (reply->packet->dhcpv6_msg_type == DHCPV6_REBIND) { reply->send_prefer = 0; reply->send_valid = 0; goto send_addr; } /* status remains success - ignore */ goto cleanup; } /* * RFC3315 section 18.2.3: * * If the server cannot find a client entry for the IA the * server returns the IA containing no addresses with a Status * Code option set to NoBinding in the Reply message. * * On mismatch we (ab)use this pretending we have not the IA * as soon as we have not an address. */ } else if (reply->packet->dhcpv6_msg_type == DHCPV6_RENEW) { /* Rewind the IA_NA to empty. */ option_state_dereference(&reply->reply_ia, MDL); if (!option_state_allocate(&reply->reply_ia, MDL)) { log_error("reply_process_addr: No memory for " "option state wipe."); status = ISC_R_NOMEMORY; goto cleanup; } /* Append a NoBinding status code. */ if (!set_status_code(STATUS_NoBinding, "Address not bound to this " "interface.", reply->reply_ia)) { log_error("reply_process_addr: Unable to " "attach status code."); status = ISC_R_FAILURE; goto cleanup; } /* Fin (no more IAADDRs). */ status = ISC_R_CANCELED; goto cleanup; } else { log_error("It is impossible to lease a client that is " "not sending a solicit, request, renew, or " "rebind message."); status = ISC_R_FAILURE; goto cleanup; } } if (reply->static_lease) { if (reply->host == NULL) log_fatal("Impossible condition at %s:%d.", MDL); scope = &global_scope; group = reply->subnet->group; } else { if (reply->lease == NULL) log_fatal("Impossible condition at %s:%d.", MDL); scope = &reply->lease->scope; group = reply->lease->ipv6_pool->subnet->group; } /* * If client_resources is nonzero, then the reply_process_is_addressed * function has executed configuration state into the reply option * cache. We will use that valid cache to derive configuration for * whether or not to engage in additional addresses, and similar. */ if (reply->client_resources != 0) { unsigned limit = 1; /* * Does this client have "enough" addresses already? Default * to one. Everybody gets one, and one should be enough for * anybody. */ oc = lookup_option(&server_universe, reply->opt_state, SV_LIMIT_ADDRS_PER_IA); if (oc != NULL) { if (!evaluate_option_cache(&data, reply->packet, NULL, NULL, reply->packet->options, reply->opt_state, scope, oc, MDL) || (data.len != 4)) { log_error("reply_process_addr: unable to " "evaluate addrs-per-ia value."); status = ISC_R_FAILURE; goto cleanup; } limit = getULong(data.data); data_string_forget(&data, MDL); } /* * If we wish to limit the client to a certain number of * addresses, then omit the address from the reply. */ if (reply->client_resources >= limit) goto cleanup; } status = reply_process_is_addressed(reply, scope, group); if (status != ISC_R_SUCCESS) goto cleanup; send_addr: status = reply_process_send_addr(reply, &tmp_addr); cleanup: if (iaaddr.data != NULL) data_string_forget(&iaaddr, MDL); if (data.data != NULL) data_string_forget(&data, MDL); if (reply->lease != NULL) iasubopt_dereference(&reply->lease, MDL); return status; } /* * Verify the address belongs to the client. If we've got a host * record with a fixed address, it has to be the assigned address * (fault out all else). Otherwise it's a dynamic address, so lookup * that address and make sure it belongs to this DUID:IAID pair. */ static isc_boolean_t address_is_owned(struct reply_state *reply, struct iaddr *addr) { int i; /* * This faults out addresses that don't match fixed addresses. */ if (reply->static_lease) { if (reply->fixed.data == NULL) log_fatal("Impossible condition at %s:%d.", MDL); if (memcmp(addr->iabuf, reply->fixed.data, 16) == 0) return (ISC_TRUE); return (ISC_FALSE); } if ((reply->old_ia == NULL) || (reply->old_ia->num_iasubopt == 0)) return (ISC_FALSE); for (i = 0 ; i < reply->old_ia->num_iasubopt ; i++) { struct iasubopt *tmp; tmp = reply->old_ia->iasubopt[i]; if (memcmp(addr->iabuf, &tmp->addr, 16) == 0) { if (lease6_usable(tmp) == ISC_FALSE) { return (ISC_FALSE); } iasubopt_reference(&reply->lease, tmp, MDL); return (ISC_TRUE); } } return (ISC_FALSE); } /* Process a client-supplied IA_TA. This may append options to the tail of * the reply packet being built in the reply_state structure. */ static isc_result_t reply_process_ia_ta(struct reply_state *reply, struct option_cache *ia) { isc_result_t status = ISC_R_SUCCESS; u_int32_t iaid; unsigned ia_cursor; struct option_state *packet_ia; struct option_cache *oc; struct data_string ia_data, data; struct data_string iaaddr; u_int32_t pref_life, valid_life; struct iaddr tmp_addr; /* Initialize values that will get cleaned up on return. */ packet_ia = NULL; memset(&ia_data, 0, sizeof(ia_data)); memset(&data, 0, sizeof(data)); memset(&iaaddr, 0, sizeof(iaaddr)); /* Make sure there is at least room for the header. */ if ((reply->cursor + IA_TA_OFFSET + 4) > sizeof(reply->buf)) { log_error("reply_process_ia_ta: Reply too long for IA."); return ISC_R_NOSPACE; } /* Fetch the IA_TA contents. */ if (!get_encapsulated_IA_state(&packet_ia, &ia_data, reply->packet, ia, IA_TA_OFFSET)) { log_error("reply_process_ia_ta: error evaluating ia"); status = ISC_R_FAILURE; goto cleanup; } /* Extract IA_TA header contents. */ iaid = getULong(ia_data.data); /* Create an IA_TA structure. */ if (ia_allocate(&reply->ia, iaid, (char *)reply->client_id.data, reply->client_id.len, MDL) != ISC_R_SUCCESS) { log_error("reply_process_ia_ta: no memory for ia."); status = ISC_R_NOMEMORY; goto cleanup; } reply->ia->ia_type = D6O_IA_TA; /* Cache pre-existing IA, if any. */ ia_hash_lookup(&reply->old_ia, ia_ta_active, (unsigned char *)reply->ia->iaid_duid.data, reply->ia->iaid_duid.len, MDL); /* * Create an option cache to carry the IA_TA option contents, and * execute any user-supplied values into it. */ if (!option_state_allocate(&reply->reply_ia, MDL)) { status = ISC_R_NOMEMORY; goto cleanup; } /* * Temporary leases are dynamic by definition. */ reply->static_lease = ISC_FALSE; /* * Save the cursor position at the start of the IA, so we can * set length later. We write a temporary * header out now just in case we decide to adjust the packet * within sub-process functions. */ ia_cursor = reply->cursor; /* Initialize the IA_TA header. First the code. */ putUShort(reply->buf.data + reply->cursor, (unsigned)D6O_IA_TA); reply->cursor += 2; /* Then option length. */ putUShort(reply->buf.data + reply->cursor, 0x04u); reply->cursor += 2; /* Then IA_TA header contents; IAID. */ putULong(reply->buf.data + reply->cursor, iaid); reply->cursor += 4; /* * Deal with an IAADDR for lifetimes. * For all or none, process IAADDRs as hints. */ reply->valid = reply->prefer = 0xffffffff; reply->client_valid = reply->client_prefer = 0; oc = lookup_option(&dhcpv6_universe, packet_ia, D6O_IAADDR); for (; oc != NULL; oc = oc->next) { memset(&iaaddr, 0, sizeof(iaaddr)); if (!evaluate_option_cache(&iaaddr, reply->packet, NULL, NULL, reply->packet->options, NULL, &global_scope, oc, MDL) || (iaaddr.len < IAADDR_OFFSET)) { log_error("reply_process_ia_ta: error " "evaluating IAADDR."); status = ISC_R_FAILURE; goto cleanup; } /* The first 16 bytes are the IPv6 address. */ pref_life = getULong(iaaddr.data + 16); valid_life = getULong(iaaddr.data + 20); if ((reply->client_valid == 0) || (reply->client_valid > valid_life)) reply->client_valid = valid_life; if ((reply->client_prefer == 0) || (reply->client_prefer > pref_life)) reply->client_prefer = pref_life; /* Nothing more if something has failed. */ if (status == ISC_R_CANCELED) continue; tmp_addr.len = 16; memcpy(tmp_addr.iabuf, iaaddr.data, 16); if (!temporary_is_available(reply, &tmp_addr)) goto bad_temp; status = reply_process_is_addressed(reply, &reply->lease->scope, reply->shared->group); if (status != ISC_R_SUCCESS) goto bad_temp; status = reply_process_send_addr(reply, &tmp_addr); if (status != ISC_R_SUCCESS) goto bad_temp; if (reply->lease != NULL) iasubopt_dereference(&reply->lease, MDL); continue; bad_temp: /* Rewind the IA_TA to empty. */ option_state_dereference(&reply->reply_ia, MDL); if (!option_state_allocate(&reply->reply_ia, MDL)) { status = ISC_R_NOMEMORY; goto cleanup; } status = ISC_R_CANCELED; reply->client_resources = 0; reply->resources_included = ISC_FALSE; if (reply->lease != NULL) iasubopt_dereference(&reply->lease, MDL); } reply->ia_count++; /* * Give the client temporary addresses. */ if (reply->client_resources != 0) goto store; status = find_client_temporaries(reply); if (status == ISC_R_NORESOURCES) { switch (reply->packet->dhcpv6_msg_type) { case DHCPV6_SOLICIT: /* * No address for any IA is handled * by the caller. */ /* FALL THROUGH */ case DHCPV6_REQUEST: /* Section 18.2.1 (Request): * * If the server cannot assign any addresses to * an IA in the message from the client, the * server MUST include the IA in the Reply * message with no addresses in the IA and a * Status Code option in the IA containing * status code NoAddrsAvail. */ option_state_dereference(&reply->reply_ia, MDL); if (!option_state_allocate(&reply->reply_ia, MDL)) { log_error("reply_process_ia_ta: No " "memory for option state wipe."); status = ISC_R_NOMEMORY; goto cleanup; } if (!set_status_code(STATUS_NoAddrsAvail, "No addresses available " "for this interface.", reply->reply_ia)) { log_error("reply_process_ia_ta: Unable " "to set NoAddrsAvail status code."); status = ISC_R_FAILURE; goto cleanup; } status = ISC_R_SUCCESS; break; default: /* * We don't want to include the IA if we * provide zero addresses including zeroed * lifetimes. */ if (reply->resources_included) status = ISC_R_SUCCESS; else goto cleanup; break; } } else if (status != ISC_R_SUCCESS) goto cleanup; store: reply->cursor += store_options6((char *)reply->buf.data + reply->cursor, sizeof(reply->buf) - reply->cursor, reply->reply_ia, reply->packet, required_opts_IA, NULL); /* Reset the length of this IA to match what was just written. */ putUShort(reply->buf.data + ia_cursor + 2, reply->cursor - (ia_cursor + 4)); /* * Consume the new changes into the database (if any have been * attached to the ia_ta). * * Loop through the assigned dynamic addresses, referencing the * leases onto this IA_TA rather than any old ones, and updating * pool timers for each (if any). */ if ((status != ISC_R_CANCELED) && (reply->buf.reply.msg_type == DHCPV6_REPLY) && (reply->ia->num_iasubopt != 0)) { struct iasubopt *tmp; struct data_string *ia_id; int i; for (i = 0 ; i < reply->ia->num_iasubopt ; i++) { tmp = reply->ia->iasubopt[i]; if (tmp->ia != NULL) ia_dereference(&tmp->ia, MDL); ia_reference(&tmp->ia, reply->ia, MDL); /* Commit 'hard' bindings. */ tmp->hard_lifetime_end_time = tmp->soft_lifetime_end_time; tmp->soft_lifetime_end_time = 0; renew_lease6(tmp->ipv6_pool, tmp); schedule_lease_timeout(tmp->ipv6_pool); #if defined (NSUPDATE) /* * Perform ddns updates. */ oc = lookup_option(&server_universe, reply->opt_state, SV_DDNS_UPDATES); if ((oc == NULL) || evaluate_boolean_option_cache(NULL, reply->packet, NULL, NULL, reply->packet->options, reply->opt_state, &tmp->scope, oc, MDL)) { ddns_updates(reply->packet, NULL, NULL, tmp, NULL, reply->opt_state); } #endif } /* Remove any old ia from the hash. */ if (reply->old_ia != NULL) { ia_id = &reply->old_ia->iaid_duid; ia_hash_delete(ia_ta_active, (unsigned char *)ia_id->data, ia_id->len, MDL); ia_dereference(&reply->old_ia, MDL); } /* Put new ia into the hash. */ reply->ia->cltt = cur_time; ia_id = &reply->ia->iaid_duid; ia_hash_add(ia_ta_active, (unsigned char *)ia_id->data, ia_id->len, reply->ia, MDL); write_ia(reply->ia); } cleanup: if (packet_ia != NULL) option_state_dereference(&packet_ia, MDL); if (iaaddr.data != NULL) data_string_forget(&iaaddr, MDL); if (reply->reply_ia != NULL) option_state_dereference(&reply->reply_ia, MDL); if (ia_data.data != NULL) data_string_forget(&ia_data, MDL); if (data.data != NULL) data_string_forget(&data, MDL); if (reply->ia != NULL) ia_dereference(&reply->ia, MDL); if (reply->old_ia != NULL) ia_dereference(&reply->old_ia, MDL); if (reply->lease != NULL) iasubopt_dereference(&reply->lease, MDL); /* * ISC_R_CANCELED is a status code used by the addr processing to * indicate we're replying with other addresses. This is still a * success at higher layers. */ return((status == ISC_R_CANCELED) ? ISC_R_SUCCESS : status); } /* * Verify the temporary address is available. */ static isc_boolean_t temporary_is_available(struct reply_state *reply, struct iaddr *addr) { struct in6_addr tmp_addr; struct subnet *subnet; struct ipv6_pool *pool; int i; memcpy(&tmp_addr, addr->iabuf, sizeof(tmp_addr)); /* * Clients may choose to send :: as an address, with the idea to give * hints about preferred-lifetime or valid-lifetime. * So this is not a request for this address. */ if (IN6_IS_ADDR_UNSPECIFIED(&tmp_addr)) return ISC_FALSE; /* * Verify that this address is on the client's network. */ for (subnet = reply->shared->subnets ; subnet != NULL ; subnet = subnet->next_sibling) { if (addr_eq(subnet_number(*addr, subnet->netmask), subnet->net)) break; } /* Address not found on shared network. */ if (subnet == NULL) return ISC_FALSE; /* * Check if this address is owned (must be before next step). */ if (address_is_owned(reply, addr)) return ISC_TRUE; /* * Verify that this address is in a temporary pool and try to get it. */ if (reply->shared->ipv6_pools == NULL) return ISC_FALSE; for (i = 0 ; (pool = reply->shared->ipv6_pools[i]) != NULL ; i++) { if (pool->pool_type != D6O_IA_TA) continue; if (ipv6_in_pool(&tmp_addr, pool)) break; } if (pool == NULL) return ISC_FALSE; if (lease6_exists(pool, &tmp_addr)) return ISC_FALSE; if (iasubopt_allocate(&reply->lease, MDL) != ISC_R_SUCCESS) return ISC_FALSE; reply->lease->addr = tmp_addr; reply->lease->plen = 0; /* Default is soft binding for 2 minutes. */ if (add_lease6(pool, reply->lease, cur_time + 120) != ISC_R_SUCCESS) return ISC_FALSE; return ISC_TRUE; } /* * Get a temporary address per prefix. */ static isc_result_t find_client_temporaries(struct reply_state *reply) { struct shared_network *shared; int i; struct ipv6_pool *p; isc_result_t status; unsigned int attempts; struct iaddr send_addr; /* * No pools, we're done. */ shared = reply->shared; if (shared->ipv6_pools == NULL) { log_debug("Unable to get client addresses: " "no IPv6 pools on this shared network"); return ISC_R_NORESOURCES; } status = ISC_R_NORESOURCES; for (i = 0;; i++) { p = shared->ipv6_pools[i]; if (p == NULL) { break; } if (p->pool_type != D6O_IA_TA) { continue; } /* * Get an address in this temporary pool. */ status = create_lease6(p, &reply->lease, &attempts, &reply->client_id, cur_time + 120); if (status != ISC_R_SUCCESS) { log_debug("Unable to get a temporary address."); goto cleanup; } status = reply_process_is_addressed(reply, &reply->lease->scope, reply->lease->ipv6_pool->subnet->group); if (status != ISC_R_SUCCESS) { goto cleanup; } send_addr.len = 16; memcpy(send_addr.iabuf, &reply->lease->addr, 16); status = reply_process_send_addr(reply, &send_addr); if (status != ISC_R_SUCCESS) { goto cleanup; } if (reply->lease != NULL) { iasubopt_dereference(&reply->lease, MDL); } } cleanup: if (reply->lease != NULL) { iasubopt_dereference(&reply->lease, MDL); } return status; } /* * This function only returns failure on 'hard' failures. If it succeeds, * it will leave a lease structure behind. */ static isc_result_t reply_process_try_addr(struct reply_state *reply, struct iaddr *addr) { isc_result_t status = ISC_R_ADDRNOTAVAIL; struct ipv6_pool *pool; int i; struct data_string data_addr; if ((reply == NULL) || (reply->shared == NULL) || (addr == NULL) || (reply->lease != NULL)) return (DHCP_R_INVALIDARG); if (reply->shared->ipv6_pools == NULL) return (ISC_R_ADDRNOTAVAIL); memset(&data_addr, 0, sizeof(data_addr)); data_addr.len = addr->len; data_addr.data = addr->iabuf; for (i = 0 ; (pool = reply->shared->ipv6_pools[i]) != NULL ; i++) { if (pool->pool_type != D6O_IA_NA) continue; status = try_client_v6_address(&reply->lease, pool, &data_addr); if (status == ISC_R_SUCCESS) break; } /* Note that this is just pedantry. There is no allocation to free. */ data_string_forget(&data_addr, MDL); /* Return just the most recent status... */ return (status); } /* Look around for an address to give the client. First, look through the * old IA for addresses we can extend. Second, try to allocate a new address. * Finally, actually add that address into the current reply IA. */ static isc_result_t find_client_address(struct reply_state *reply) { struct iaddr send_addr; isc_result_t status = ISC_R_NORESOURCES; struct iasubopt *lease, *best_lease = NULL; struct binding_scope **scope; struct group *group; int i; if (reply->static_lease) { if (reply->host == NULL) return DHCP_R_INVALIDARG; send_addr.len = 16; memcpy(send_addr.iabuf, reply->fixed.data, 16); status = ISC_R_SUCCESS; scope = &global_scope; group = reply->subnet->group; goto send_addr; } if (reply->old_ia != NULL) { for (i = 0 ; i < reply->old_ia->num_iasubopt ; i++) { struct shared_network *candidate_shared; lease = reply->old_ia->iasubopt[i]; candidate_shared = lease->ipv6_pool->shared_network; /* * Look for the best lease on the client's shared * network. */ if ((candidate_shared == reply->shared) && (lease6_usable(lease) == ISC_TRUE)) { best_lease = lease_compare(lease, best_lease); } } } /* Try to pick a new address if we didn't find one, or if we found an * abandoned lease. */ if ((best_lease == NULL) || (best_lease->state == FTS_ABANDONED)) { status = pick_v6_address(&reply->lease, reply->shared, &reply->ia->iaid_duid); } else if (best_lease != NULL) { iasubopt_reference(&reply->lease, best_lease, MDL); status = ISC_R_SUCCESS; } /* Pick the abandoned lease as a last resort. */ if ((status == ISC_R_NORESOURCES) && (best_lease != NULL)) { /* I don't see how this is supposed to be done right now. */ log_error("Reclaiming abandoned addresses is not yet " "supported. Treating this as an out of space " "condition."); /* iasubopt_reference(&reply->lease, best_lease, MDL); */ } /* Give up now if we didn't find a lease. */ if (status != ISC_R_SUCCESS) return status; if (reply->lease == NULL) log_fatal("Impossible condition at %s:%d.", MDL); /* Draw binding scopes from the lease's binding scope, and config * from the lease's containing subnet and higher. Note that it may * be desirable to place the group attachment directly in the pool. */ scope = &reply->lease->scope; group = reply->lease->ipv6_pool->subnet->group; send_addr.len = 16; memcpy(send_addr.iabuf, &reply->lease->addr, 16); send_addr: status = reply_process_is_addressed(reply, scope, group); if (status != ISC_R_SUCCESS) return status; status = reply_process_send_addr(reply, &send_addr); return status; } /* Once an address is found for a client, perform several common functions; * Calculate and store valid and preferred lease times, draw client options * into the option state. */ static isc_result_t reply_process_is_addressed(struct reply_state *reply, struct binding_scope **scope, struct group *group) { isc_result_t status = ISC_R_SUCCESS; struct data_string data; struct option_cache *oc; /* Initialize values we will cleanup. */ memset(&data, 0, sizeof(data)); /* * Bring configured options into the root packet level cache - start * with the lease's closest enclosing group (passed in by the caller * as 'group'). */ execute_statements_in_scope(NULL, reply->packet, NULL, NULL, reply->packet->options, reply->opt_state, scope, group, root_group); /* * If there is a host record, over-ride with values configured there, * without re-evaluating configuration from the previously executed * group or its common enclosers. */ if (reply->host != NULL) execute_statements_in_scope(NULL, reply->packet, NULL, NULL, reply->packet->options, reply->opt_state, scope, reply->host->group, group); /* Determine valid lifetime. */ if (reply->client_valid == 0) reply->send_valid = DEFAULT_DEFAULT_LEASE_TIME; else reply->send_valid = reply->client_valid; oc = lookup_option(&server_universe, reply->opt_state, SV_DEFAULT_LEASE_TIME); if (oc != NULL) { if (!evaluate_option_cache(&data, reply->packet, NULL, NULL, reply->packet->options, reply->opt_state, scope, oc, MDL) || (data.len != 4)) { log_error("reply_process_is_addressed: unable to " "evaluate default lease time"); status = ISC_R_FAILURE; goto cleanup; } reply->send_valid = getULong(data.data); data_string_forget(&data, MDL); } if (reply->client_prefer == 0) reply->send_prefer = reply->send_valid; else reply->send_prefer = reply->client_prefer; if (reply->send_prefer >= reply->send_valid) reply->send_prefer = (reply->send_valid / 2) + (reply->send_valid / 8); oc = lookup_option(&server_universe, reply->opt_state, SV_PREFER_LIFETIME); if (oc != NULL) { if (!evaluate_option_cache(&data, reply->packet, NULL, NULL, reply->packet->options, reply->opt_state, scope, oc, MDL) || (data.len != 4)) { log_error("reply_process_is_addressed: unable to " "evaluate preferred lease time"); status = ISC_R_FAILURE; goto cleanup; } reply->send_prefer = getULong(data.data); data_string_forget(&data, MDL); } /* Note lowest values for later calculation of renew/rebind times. */ if (reply->prefer > reply->send_prefer) reply->prefer = reply->send_prefer; if (reply->valid > reply->send_valid) reply->valid = reply->send_valid; #if 0 /* * XXX: Old 4.0.0 alpha code would change the host {} record * XXX: uid upon lease assignment. This was intended to cover the * XXX: case where a client first identifies itself using vendor * XXX: options in a solicit, or request, but later neglects to include * XXX: these options in a Renew or Rebind. It is not clear that this * XXX: is required, and has some startling ramifications (such as * XXX: how to recover this dynamic host {} state across restarts). */ if (reply->host != NULL) change_host_uid(host, reply->client_id->data, reply->client_id->len); #endif /* 0 */ /* Perform dynamic lease related update work. */ if (reply->lease != NULL) { /* Cached lifetimes */ reply->lease->prefer = reply->send_prefer; reply->lease->valid = reply->send_valid; /* Advance (or rewind) the valid lifetime. */ if (reply->buf.reply.msg_type == DHCPV6_REPLY) { reply->lease->soft_lifetime_end_time = cur_time + reply->send_valid; /* Wait before renew! */ } status = ia_add_iasubopt(reply->ia, reply->lease, MDL); if (status != ISC_R_SUCCESS) { log_fatal("reply_process_is_addressed: Unable to " "attach lease to new IA: %s", isc_result_totext(status)); } /* * If this is a new lease, make sure it is attached somewhere. */ if (reply->lease->ia == NULL) { ia_reference(&reply->lease->ia, reply->ia, MDL); } } /* Bring a copy of the relevant options into the IA scope. */ execute_statements_in_scope(NULL, reply->packet, NULL, NULL, reply->packet->options, reply->reply_ia, scope, group, root_group); /* * And bring in host record configuration, if any, but not to overlap * the previous group or its common enclosers. */ if (reply->host != NULL) execute_statements_in_scope(NULL, reply->packet, NULL, NULL, reply->packet->options, reply->reply_ia, scope, reply->host->group, group); cleanup: if (data.data != NULL) data_string_forget(&data, MDL); if (status == ISC_R_SUCCESS) reply->client_resources++; return status; } /* Simply send an IAADDR within the IA scope as described. */ static isc_result_t reply_process_send_addr(struct reply_state *reply, struct iaddr *addr) { isc_result_t status = ISC_R_SUCCESS; struct data_string data; memset(&data, 0, sizeof(data)); /* Now append the lease. */ data.len = IAADDR_OFFSET; if (!buffer_allocate(&data.buffer, data.len, MDL)) { log_error("reply_process_send_addr: out of memory" "allocating new IAADDR buffer."); status = ISC_R_NOMEMORY; goto cleanup; } data.data = data.buffer->data; memcpy(data.buffer->data, addr->iabuf, 16); putULong(data.buffer->data + 16, reply->send_prefer); putULong(data.buffer->data + 20, reply->send_valid); if (!append_option_buffer(&dhcpv6_universe, reply->reply_ia, data.buffer, data.buffer->data, data.len, D6O_IAADDR, 0)) { log_error("reply_process_send_addr: unable " "to save IAADDR option"); status = ISC_R_FAILURE; goto cleanup; } reply->resources_included = ISC_TRUE; cleanup: if (data.data != NULL) data_string_forget(&data, MDL); return status; } /* Choose the better of two leases. */ static struct iasubopt * lease_compare(struct iasubopt *alpha, struct iasubopt *beta) { if (alpha == NULL) return beta; if (beta == NULL) return alpha; switch(alpha->state) { case FTS_ACTIVE: switch(beta->state) { case FTS_ACTIVE: /* Choose the lease with the longest lifetime (most * likely the most recently allocated). */ if (alpha->hard_lifetime_end_time < beta->hard_lifetime_end_time) return beta; else return alpha; case FTS_EXPIRED: case FTS_ABANDONED: return alpha; default: log_fatal("Impossible condition at %s:%d.", MDL); } break; case FTS_EXPIRED: switch (beta->state) { case FTS_ACTIVE: return beta; case FTS_EXPIRED: /* Choose the most recently expired lease. */ if (alpha->hard_lifetime_end_time < beta->hard_lifetime_end_time) return beta; else if ((alpha->hard_lifetime_end_time == beta->hard_lifetime_end_time) && (alpha->soft_lifetime_end_time < beta->soft_lifetime_end_time)) return beta; else return alpha; case FTS_ABANDONED: return alpha; default: log_fatal("Impossible condition at %s:%d.", MDL); } break; case FTS_ABANDONED: switch (beta->state) { case FTS_ACTIVE: case FTS_EXPIRED: return alpha; case FTS_ABANDONED: /* Choose the lease that was abandoned longest ago. */ if (alpha->hard_lifetime_end_time < beta->hard_lifetime_end_time) return alpha; default: log_fatal("Impossible condition at %s:%d.", MDL); } break; default: log_fatal("Impossible condition at %s:%d.", MDL); } log_fatal("Triple impossible condition at %s:%d.", MDL); return NULL; } /* Process a client-supplied IA_PD. This may append options to the tail of * the reply packet being built in the reply_state structure. */ static isc_result_t reply_process_ia_pd(struct reply_state *reply, struct option_cache *ia) { isc_result_t status = ISC_R_SUCCESS; u_int32_t iaid; unsigned ia_cursor; struct option_state *packet_ia; struct option_cache *oc; struct data_string ia_data, data; /* Initialize values that will get cleaned up on return. */ packet_ia = NULL; memset(&ia_data, 0, sizeof(ia_data)); memset(&data, 0, sizeof(data)); /* * Note that find_client_prefix() may set reply->lease. */ /* Make sure there is at least room for the header. */ if ((reply->cursor + IA_PD_OFFSET + 4) > sizeof(reply->buf)) { log_error("reply_process_ia_pd: Reply too long for IA."); return ISC_R_NOSPACE; } /* Fetch the IA_PD contents. */ if (!get_encapsulated_IA_state(&packet_ia, &ia_data, reply->packet, ia, IA_PD_OFFSET)) { log_error("reply_process_ia_pd: error evaluating ia"); status = ISC_R_FAILURE; goto cleanup; } /* Extract IA_PD header contents. */ iaid = getULong(ia_data.data); reply->renew = getULong(ia_data.data + 4); reply->rebind = getULong(ia_data.data + 8); /* Create an IA_PD structure. */ if (ia_allocate(&reply->ia, iaid, (char *)reply->client_id.data, reply->client_id.len, MDL) != ISC_R_SUCCESS) { log_error("reply_process_ia_pd: no memory for ia."); status = ISC_R_NOMEMORY; goto cleanup; } reply->ia->ia_type = D6O_IA_PD; /* Cache pre-existing IA_PD, if any. */ ia_hash_lookup(&reply->old_ia, ia_pd_active, (unsigned char *)reply->ia->iaid_duid.data, reply->ia->iaid_duid.len, MDL); /* * Create an option cache to carry the IA_PD option contents, and * execute any user-supplied values into it. */ if (!option_state_allocate(&reply->reply_ia, MDL)) { status = ISC_R_NOMEMORY; goto cleanup; } /* Check & count the fixed prefix host records. */ reply->static_prefixes = 0; if ((reply->host != NULL) && (reply->host->fixed_prefix != NULL)) { struct iaddrcidrnetlist *fp; for (fp = reply->host->fixed_prefix; fp != NULL; fp = fp->next) { reply->static_prefixes += 1; } } /* * Save the cursor position at the start of the IA_PD, so we can * set length and adjust t1/t2 values later. We write a temporary * header out now just in case we decide to adjust the packet * within sub-process functions. */ ia_cursor = reply->cursor; /* Initialize the IA_PD header. First the code. */ putUShort(reply->buf.data + reply->cursor, (unsigned)D6O_IA_PD); reply->cursor += 2; /* Then option length. */ putUShort(reply->buf.data + reply->cursor, 0x0Cu); reply->cursor += 2; /* Then IA_PD header contents; IAID. */ putULong(reply->buf.data + reply->cursor, iaid); reply->cursor += 4; /* We store the client's t1 for now, and may over-ride it later. */ putULong(reply->buf.data + reply->cursor, reply->renew); reply->cursor += 4; /* We store the client's t2 for now, and may over-ride it later. */ putULong(reply->buf.data + reply->cursor, reply->rebind); reply->cursor += 4; /* * For each prefix in this IA_PD, decide what to do about it. */ oc = lookup_option(&dhcpv6_universe, packet_ia, D6O_IAPREFIX); reply->valid = reply->prefer = 0xffffffff; reply->client_valid = reply->client_prefer = 0; reply->preflen = -1; for (; oc != NULL ; oc = oc->next) { status = reply_process_prefix(reply, oc); /* * Canceled means we did not allocate prefixes to the * client, but we're "done" with this IA - we set a status * code. So transmit this reply, e.g., move on to the next * IA. */ if (status == ISC_R_CANCELED) break; if ((status != ISC_R_SUCCESS) && (status != ISC_R_ADDRINUSE) && (status != ISC_R_ADDRNOTAVAIL)) goto cleanup; } reply->pd_count++; /* * If we fell through the above and never gave the client * a prefix, give it one now. */ if ((status != ISC_R_CANCELED) && (reply->client_resources == 0)) { status = find_client_prefix(reply); if (status == ISC_R_NORESOURCES) { switch (reply->packet->dhcpv6_msg_type) { case DHCPV6_SOLICIT: /* * No prefix for any IA is handled * by the caller. */ /* FALL THROUGH */ case DHCPV6_REQUEST: /* Same than for addresses. */ option_state_dereference(&reply->reply_ia, MDL); if (!option_state_allocate(&reply->reply_ia, MDL)) { log_error("reply_process_ia_pd: No " "memory for option state " "wipe."); status = ISC_R_NOMEMORY; goto cleanup; } if (!set_status_code(STATUS_NoPrefixAvail, "No prefixes available " "for this interface.", reply->reply_ia)) { log_error("reply_process_ia_pd: " "Unable to set " "NoPrefixAvail status " "code."); status = ISC_R_FAILURE; goto cleanup; } status = ISC_R_SUCCESS; break; default: if (reply->resources_included) status = ISC_R_SUCCESS; else goto cleanup; break; } } if (status != ISC_R_SUCCESS) goto cleanup; } reply->cursor += store_options6((char *)reply->buf.data + reply->cursor, sizeof(reply->buf) - reply->cursor, reply->reply_ia, reply->packet, required_opts_IA_PD, NULL); /* Reset the length of this IA_PD to match what was just written. */ putUShort(reply->buf.data + ia_cursor + 2, reply->cursor - (ia_cursor + 4)); /* * T1/T2 time selection is kind of weird. We actually use DHCP * (v4) scoped options as handy existing places where these might * be configured by an administrator. A value of zero tells the * client it may choose its own renewal time. */ reply->renew = 0; oc = lookup_option(&dhcp_universe, reply->opt_state, DHO_DHCP_RENEWAL_TIME); if (oc != NULL) { if (!evaluate_option_cache(&data, reply->packet, NULL, NULL, reply->packet->options, reply->opt_state, &global_scope, oc, MDL) || (data.len != 4)) { log_error("Invalid renewal time."); } else { reply->renew = getULong(data.data); } if (data.data != NULL) data_string_forget(&data, MDL); } putULong(reply->buf.data + ia_cursor + 8, reply->renew); /* Now T2. */ reply->rebind = 0; oc = lookup_option(&dhcp_universe, reply->opt_state, DHO_DHCP_REBINDING_TIME); if (oc != NULL) { if (!evaluate_option_cache(&data, reply->packet, NULL, NULL, reply->packet->options, reply->opt_state, &global_scope, oc, MDL) || (data.len != 4)) { log_error("Invalid rebinding time."); } else { reply->rebind = getULong(data.data); } if (data.data != NULL) data_string_forget(&data, MDL); } putULong(reply->buf.data + ia_cursor + 12, reply->rebind); /* * If this is not a 'soft' binding, consume the new changes into * the database (if any have been attached to the ia_pd). * * Loop through the assigned dynamic prefixes, referencing the * prefixes onto this IA_PD rather than any old ones, and updating * prefix pool timers for each (if any). */ if ((status != ISC_R_CANCELED) && (reply->static_prefixes == 0) && (reply->buf.reply.msg_type == DHCPV6_REPLY) && (reply->ia->num_iasubopt != 0)) { struct iasubopt *tmp; struct data_string *ia_id; int i; for (i = 0 ; i < reply->ia->num_iasubopt ; i++) { tmp = reply->ia->iasubopt[i]; if (tmp->ia != NULL) ia_dereference(&tmp->ia, MDL); ia_reference(&tmp->ia, reply->ia, MDL); /* Commit 'hard' bindings. */ tmp->hard_lifetime_end_time = tmp->soft_lifetime_end_time; tmp->soft_lifetime_end_time = 0; renew_lease6(tmp->ipv6_pool, tmp); schedule_lease_timeout(tmp->ipv6_pool); } /* Remove any old ia from the hash. */ if (reply->old_ia != NULL) { ia_id = &reply->old_ia->iaid_duid; ia_hash_delete(ia_pd_active, (unsigned char *)ia_id->data, ia_id->len, MDL); ia_dereference(&reply->old_ia, MDL); } /* Put new ia into the hash. */ reply->ia->cltt = cur_time; ia_id = &reply->ia->iaid_duid; ia_hash_add(ia_pd_active, (unsigned char *)ia_id->data, ia_id->len, reply->ia, MDL); write_ia(reply->ia); } cleanup: if (packet_ia != NULL) option_state_dereference(&packet_ia, MDL); if (reply->reply_ia != NULL) option_state_dereference(&reply->reply_ia, MDL); if (ia_data.data != NULL) data_string_forget(&ia_data, MDL); if (data.data != NULL) data_string_forget(&data, MDL); if (reply->ia != NULL) ia_dereference(&reply->ia, MDL); if (reply->old_ia != NULL) ia_dereference(&reply->old_ia, MDL); if (reply->lease != NULL) iasubopt_dereference(&reply->lease, MDL); /* * ISC_R_CANCELED is a status code used by the prefix processing to * indicate we're replying with a status code. This is still a * success at higher layers. */ return((status == ISC_R_CANCELED) ? ISC_R_SUCCESS : status); } /* * Process an IAPREFIX within a given IA_PD, storing any IAPREFIX reply * contents into the reply's current ia_pd-scoped option cache. Returns * ISC_R_CANCELED in the event we are replying with a status code and do * not wish to process more IAPREFIXes within this IA_PD. */ static isc_result_t reply_process_prefix(struct reply_state *reply, struct option_cache *pref) { u_int32_t pref_life, valid_life; struct binding_scope **scope; struct iaddrcidrnet tmp_pref; struct option_cache *oc; struct data_string iapref, data; isc_result_t status = ISC_R_SUCCESS; /* Initializes values that will be cleaned up. */ memset(&iapref, 0, sizeof(iapref)); memset(&data, 0, sizeof(data)); /* Note that reply->lease may be set by prefix_is_owned() */ /* * There is no point trying to process an incoming prefix if there * is no room for an outgoing prefix. */ if ((reply->cursor + 29) > sizeof(reply->buf)) { log_error("reply_process_prefix: Out of room for prefix."); return ISC_R_NOSPACE; } /* Extract this IAPREFIX option. */ if (!evaluate_option_cache(&iapref, reply->packet, NULL, NULL, reply->packet->options, NULL, &global_scope, pref, MDL) || (iapref.len < IAPREFIX_OFFSET)) { log_error("reply_process_prefix: error evaluating IAPREFIX."); status = ISC_R_FAILURE; goto cleanup; } /* * Layout: preferred and valid lifetimes followed by the prefix * length and the IPv6 address. */ pref_life = getULong(iapref.data); valid_life = getULong(iapref.data + 4); if ((reply->client_valid == 0) || (reply->client_valid > valid_life)) reply->client_valid = valid_life; if ((reply->client_prefer == 0) || (reply->client_prefer > pref_life)) reply->client_prefer = pref_life; /* * Clients may choose to send ::/0 as a prefix, with the idea to give * hints about preferred-lifetime or valid-lifetime. */ tmp_pref.lo_addr.len = 16; memset(tmp_pref.lo_addr.iabuf, 0, 16); if ((iapref.data[8] == 0) && (memcmp(iapref.data + 9, tmp_pref.lo_addr.iabuf, 16) == 0)) { /* Status remains success; we just ignore this one. */ goto cleanup; } /* * Clients may choose to send ::/X as a prefix to specify a * preferred/requested prefix length. Note X is never zero here. */ tmp_pref.bits = (int) iapref.data[8]; if (reply->preflen < 0) { /* Cache the first preferred prefix length. */ reply->preflen = tmp_pref.bits; } if (memcmp(iapref.data + 9, tmp_pref.lo_addr.iabuf, 16) == 0) { goto cleanup; } memcpy(tmp_pref.lo_addr.iabuf, iapref.data + 9, 16); /* Verify the prefix belongs to the client. */ if (!prefix_is_owned(reply, &tmp_pref)) { /* Same than for addresses. */ if ((reply->packet->dhcpv6_msg_type == DHCPV6_SOLICIT) || (reply->packet->dhcpv6_msg_type == DHCPV6_REQUEST) || (reply->packet->dhcpv6_msg_type == DHCPV6_REBIND)) { status = reply_process_try_prefix(reply, &tmp_pref); /* Either error out or skip this prefix. */ if ((status != ISC_R_SUCCESS) && (status != ISC_R_ADDRINUSE) && (status != ISC_R_ADDRNOTAVAIL)) goto cleanup; if (reply->lease == NULL) { if (reply->packet->dhcpv6_msg_type == DHCPV6_REBIND) { reply->send_prefer = 0; reply->send_valid = 0; goto send_pref; } /* status remains success - ignore */ goto cleanup; } /* * RFC3633 section 18.2.3: * * If the delegating router cannot find a binding * for the requesting router's IA_PD the delegating * router returns the IA_PD containing no prefixes * with a Status Code option set to NoBinding in the * Reply message. * * On mismatch we (ab)use this pretending we have not the IA * as soon as we have not a prefix. */ } else if (reply->packet->dhcpv6_msg_type == DHCPV6_RENEW) { /* Rewind the IA_PD to empty. */ option_state_dereference(&reply->reply_ia, MDL); if (!option_state_allocate(&reply->reply_ia, MDL)) { log_error("reply_process_prefix: No memory " "for option state wipe."); status = ISC_R_NOMEMORY; goto cleanup; } /* Append a NoBinding status code. */ if (!set_status_code(STATUS_NoBinding, "Prefix not bound to this " "interface.", reply->reply_ia)) { log_error("reply_process_prefix: Unable to " "attach status code."); status = ISC_R_FAILURE; goto cleanup; } /* Fin (no more IAPREFIXes). */ status = ISC_R_CANCELED; goto cleanup; } else { log_error("It is impossible to lease a client that is " "not sending a solicit, request, renew, or " "rebind message."); status = ISC_R_FAILURE; goto cleanup; } } if (reply->static_prefixes > 0) { if (reply->host == NULL) log_fatal("Impossible condition at %s:%d.", MDL); scope = &global_scope; } else { if (reply->lease == NULL) log_fatal("Impossible condition at %s:%d.", MDL); scope = &reply->lease->scope; } /* * If client_resources is nonzero, then the reply_process_is_prefixed * function has executed configuration state into the reply option * cache. We will use that valid cache to derive configuration for * whether or not to engage in additional prefixes, and similar. */ if (reply->client_resources != 0) { unsigned limit = 1; /* * Does this client have "enough" prefixes already? Default * to one. Everybody gets one, and one should be enough for * anybody. */ oc = lookup_option(&server_universe, reply->opt_state, SV_LIMIT_PREFS_PER_IA); if (oc != NULL) { if (!evaluate_option_cache(&data, reply->packet, NULL, NULL, reply->packet->options, reply->opt_state, scope, oc, MDL) || (data.len != 4)) { log_error("reply_process_prefix: unable to " "evaluate prefs-per-ia value."); status = ISC_R_FAILURE; goto cleanup; } limit = getULong(data.data); data_string_forget(&data, MDL); } /* * If we wish to limit the client to a certain number of * prefixes, then omit the prefix from the reply. */ if (reply->client_resources >= limit) goto cleanup; } status = reply_process_is_prefixed(reply, scope, reply->shared->group); if (status != ISC_R_SUCCESS) goto cleanup; send_pref: status = reply_process_send_prefix(reply, &tmp_pref); cleanup: if (iapref.data != NULL) data_string_forget(&iapref, MDL); if (data.data != NULL) data_string_forget(&data, MDL); if (reply->lease != NULL) iasubopt_dereference(&reply->lease, MDL); return status; } /* * Verify the prefix belongs to the client. If we've got a host * record with fixed prefixes, it has to be an assigned prefix * (fault out all else). Otherwise it's a dynamic prefix, so lookup * that prefix and make sure it belongs to this DUID:IAID pair. */ static isc_boolean_t prefix_is_owned(struct reply_state *reply, struct iaddrcidrnet *pref) { struct iaddrcidrnetlist *l; int i; /* * This faults out prefixes that don't match fixed prefixes. */ if (reply->static_prefixes > 0) { for (l = reply->host->fixed_prefix; l != NULL; l = l->next) { if ((pref->bits == l->cidrnet.bits) && (memcmp(pref->lo_addr.iabuf, l->cidrnet.lo_addr.iabuf, 16) == 0)) return (ISC_TRUE); } return (ISC_FALSE); } if ((reply->old_ia == NULL) || (reply->old_ia->num_iasubopt == 0)) return (ISC_FALSE); for (i = 0 ; i < reply->old_ia->num_iasubopt ; i++) { struct iasubopt *tmp; tmp = reply->old_ia->iasubopt[i]; if ((pref->bits == (int) tmp->plen) && (memcmp(pref->lo_addr.iabuf, &tmp->addr, 16) == 0)) { if (lease6_usable(tmp) == ISC_FALSE) { return (ISC_FALSE); } iasubopt_reference(&reply->lease, tmp, MDL); return (ISC_TRUE); } } return (ISC_FALSE); } /* * This function only returns failure on 'hard' failures. If it succeeds, * it will leave a prefix structure behind. */ static isc_result_t reply_process_try_prefix(struct reply_state *reply, struct iaddrcidrnet *pref) { isc_result_t status = ISC_R_ADDRNOTAVAIL; struct ipv6_pool *pool; int i; struct data_string data_pref; if ((reply == NULL) || (reply->shared == NULL) || (pref == NULL) || (reply->lease != NULL)) return (DHCP_R_INVALIDARG); if (reply->shared->ipv6_pools == NULL) return (ISC_R_ADDRNOTAVAIL); memset(&data_pref, 0, sizeof(data_pref)); data_pref.len = 17; if (!buffer_allocate(&data_pref.buffer, data_pref.len, MDL)) { log_error("reply_process_try_prefix: out of memory."); return (ISC_R_NOMEMORY); } data_pref.data = data_pref.buffer->data; data_pref.buffer->data[0] = (u_int8_t) pref->bits; memcpy(data_pref.buffer->data + 1, pref->lo_addr.iabuf, 16); for (i = 0 ; (pool = reply->shared->ipv6_pools[i]) != NULL ; i++) { if (pool->pool_type != D6O_IA_PD) continue; status = try_client_v6_prefix(&reply->lease, pool, &data_pref); /* If we found it in this pool (either in use or available), there is no need to look further. */ if ( (status == ISC_R_SUCCESS) || (status == ISC_R_ADDRINUSE) ) break; } data_string_forget(&data_pref, MDL); /* Return just the most recent status... */ return (status); } /* Look around for a prefix to give the client. First, look through the old * IA_PD for prefixes we can extend. Second, try to allocate a new prefix. * Finally, actually add that prefix into the current reply IA_PD. */ static isc_result_t find_client_prefix(struct reply_state *reply) { struct iaddrcidrnet send_pref; isc_result_t status = ISC_R_NORESOURCES; struct iasubopt *prefix, *best_prefix = NULL; struct binding_scope **scope; int i; if (reply->static_prefixes > 0) { struct iaddrcidrnetlist *l; if (reply->host == NULL) return DHCP_R_INVALIDARG; for (l = reply->host->fixed_prefix; l != NULL; l = l->next) { if (l->cidrnet.bits == reply->preflen) break; } if (l == NULL) { /* * If no fixed prefix has the preferred length, * get the first one. */ l = reply->host->fixed_prefix; } memcpy(&send_pref, &l->cidrnet, sizeof(send_pref)); status = ISC_R_SUCCESS; scope = &global_scope; goto send_pref; } if (reply->old_ia != NULL) { for (i = 0 ; i < reply->old_ia->num_iasubopt ; i++) { struct shared_network *candidate_shared; prefix = reply->old_ia->iasubopt[i]; candidate_shared = prefix->ipv6_pool->shared_network; /* * Consider this prefix if it is in a global pool or * if it is scoped in a pool under the client's shared * network. */ if (((candidate_shared == NULL) || (candidate_shared == reply->shared)) && (lease6_usable(prefix) == ISC_TRUE)) { best_prefix = prefix_compare(reply, prefix, best_prefix); } } } /* Try to pick a new prefix if we didn't find one, or if we found an * abandoned prefix. */ if ((best_prefix == NULL) || (best_prefix->state == FTS_ABANDONED)) { status = pick_v6_prefix(&reply->lease, reply->preflen, reply->shared, &reply->client_id); } else if (best_prefix != NULL) { iasubopt_reference(&reply->lease, best_prefix, MDL); status = ISC_R_SUCCESS; } /* Pick the abandoned prefix as a last resort. */ if ((status == ISC_R_NORESOURCES) && (best_prefix != NULL)) { /* I don't see how this is supposed to be done right now. */ log_error("Reclaiming abandoned prefixes is not yet " "supported. Treating this as an out of space " "condition."); /* iasubopt_reference(&reply->lease, best_prefix, MDL); */ } /* Give up now if we didn't find a prefix. */ if (status != ISC_R_SUCCESS) return status; if (reply->lease == NULL) log_fatal("Impossible condition at %s:%d.", MDL); scope = &reply->lease->scope; send_pref.lo_addr.len = 16; memcpy(send_pref.lo_addr.iabuf, &reply->lease->addr, 16); send_pref.bits = (int) reply->lease->plen; send_pref: status = reply_process_is_prefixed(reply, scope, reply->shared->group); if (status != ISC_R_SUCCESS) return status; status = reply_process_send_prefix(reply, &send_pref); return status; } /* Once a prefix is found for a client, perform several common functions; * Calculate and store valid and preferred prefix times, draw client options * into the option state. */ static isc_result_t reply_process_is_prefixed(struct reply_state *reply, struct binding_scope **scope, struct group *group) { isc_result_t status = ISC_R_SUCCESS; struct data_string data; struct option_cache *oc; /* Initialize values we will cleanup. */ memset(&data, 0, sizeof(data)); /* * Bring configured options into the root packet level cache - start * with the lease's closest enclosing group (passed in by the caller * as 'group'). */ execute_statements_in_scope(NULL, reply->packet, NULL, NULL, reply->packet->options, reply->opt_state, scope, group, root_group); /* * If there is a host record, over-ride with values configured there, * without re-evaluating configuration from the previously executed * group or its common enclosers. */ if (reply->host != NULL) execute_statements_in_scope(NULL, reply->packet, NULL, NULL, reply->packet->options, reply->opt_state, scope, reply->host->group, group); /* Determine valid lifetime. */ if (reply->client_valid == 0) reply->send_valid = DEFAULT_DEFAULT_LEASE_TIME; else reply->send_valid = reply->client_valid; oc = lookup_option(&server_universe, reply->opt_state, SV_DEFAULT_LEASE_TIME); if (oc != NULL) { if (!evaluate_option_cache(&data, reply->packet, NULL, NULL, reply->packet->options, reply->opt_state, scope, oc, MDL) || (data.len != 4)) { log_error("reply_process_is_prefixed: unable to " "evaluate default prefix time"); status = ISC_R_FAILURE; goto cleanup; } reply->send_valid = getULong(data.data); data_string_forget(&data, MDL); } if (reply->client_prefer == 0) reply->send_prefer = reply->send_valid; else reply->send_prefer = reply->client_prefer; if (reply->send_prefer >= reply->send_valid) reply->send_prefer = (reply->send_valid / 2) + (reply->send_valid / 8); oc = lookup_option(&server_universe, reply->opt_state, SV_PREFER_LIFETIME); if (oc != NULL) { if (!evaluate_option_cache(&data, reply->packet, NULL, NULL, reply->packet->options, reply->opt_state, scope, oc, MDL) || (data.len != 4)) { log_error("reply_process_is_prefixed: unable to " "evaluate preferred prefix time"); status = ISC_R_FAILURE; goto cleanup; } reply->send_prefer = getULong(data.data); data_string_forget(&data, MDL); } /* Note lowest values for later calculation of renew/rebind times. */ if (reply->prefer > reply->send_prefer) reply->prefer = reply->send_prefer; if (reply->valid > reply->send_valid) reply->valid = reply->send_valid; /* Perform dynamic prefix related update work. */ if (reply->lease != NULL) { /* Cached lifetimes */ reply->lease->prefer = reply->send_prefer; reply->lease->valid = reply->send_valid; /* Advance (or rewind) the valid lifetime. */ if (reply->buf.reply.msg_type == DHCPV6_REPLY) { reply->lease->soft_lifetime_end_time = cur_time + reply->send_valid; /* Wait before renew! */ } status = ia_add_iasubopt(reply->ia, reply->lease, MDL); if (status != ISC_R_SUCCESS) { log_fatal("reply_process_is_prefixed: Unable to " "attach prefix to new IA_PD: %s", isc_result_totext(status)); } /* * If this is a new prefix, make sure it is attached somewhere. */ if (reply->lease->ia == NULL) { ia_reference(&reply->lease->ia, reply->ia, MDL); } } /* Bring a copy of the relevant options into the IA_PD scope. */ execute_statements_in_scope(NULL, reply->packet, NULL, NULL, reply->packet->options, reply->reply_ia, scope, group, root_group); /* * And bring in host record configuration, if any, but not to overlap * the previous group or its common enclosers. */ if (reply->host != NULL) execute_statements_in_scope(NULL, reply->packet, NULL, NULL, reply->packet->options, reply->reply_ia, scope, reply->host->group, group); cleanup: if (data.data != NULL) data_string_forget(&data, MDL); if (status == ISC_R_SUCCESS) reply->client_resources++; return status; } /* Simply send an IAPREFIX within the IA_PD scope as described. */ static isc_result_t reply_process_send_prefix(struct reply_state *reply, struct iaddrcidrnet *pref) { isc_result_t status = ISC_R_SUCCESS; struct data_string data; memset(&data, 0, sizeof(data)); /* Now append the prefix. */ data.len = IAPREFIX_OFFSET; if (!buffer_allocate(&data.buffer, data.len, MDL)) { log_error("reply_process_send_prefix: out of memory" "allocating new IAPREFIX buffer."); status = ISC_R_NOMEMORY; goto cleanup; } data.data = data.buffer->data; putULong(data.buffer->data, reply->send_prefer); putULong(data.buffer->data + 4, reply->send_valid); data.buffer->data[8] = pref->bits; memcpy(data.buffer->data + 9, pref->lo_addr.iabuf, 16); if (!append_option_buffer(&dhcpv6_universe, reply->reply_ia, data.buffer, data.buffer->data, data.len, D6O_IAPREFIX, 0)) { log_error("reply_process_send_prefix: unable " "to save IAPREFIX option"); status = ISC_R_FAILURE; goto cleanup; } reply->resources_included = ISC_TRUE; cleanup: if (data.data != NULL) data_string_forget(&data, MDL); return status; } /* Choose the better of two prefixes. */ static struct iasubopt * prefix_compare(struct reply_state *reply, struct iasubopt *alpha, struct iasubopt *beta) { if (alpha == NULL) return beta; if (beta == NULL) return alpha; if (reply->preflen >= 0) { if ((alpha->plen == reply->preflen) && (beta->plen != reply->preflen)) return alpha; if ((beta->plen == reply->preflen) && (alpha->plen != reply->preflen)) return beta; } switch(alpha->state) { case FTS_ACTIVE: switch(beta->state) { case FTS_ACTIVE: /* Choose the prefix with the longest lifetime (most * likely the most recently allocated). */ if (alpha->hard_lifetime_end_time < beta->hard_lifetime_end_time) return beta; else return alpha; case FTS_EXPIRED: case FTS_ABANDONED: return alpha; default: log_fatal("Impossible condition at %s:%d.", MDL); } break; case FTS_EXPIRED: switch (beta->state) { case FTS_ACTIVE: return beta; case FTS_EXPIRED: /* Choose the most recently expired prefix. */ if (alpha->hard_lifetime_end_time < beta->hard_lifetime_end_time) return beta; else if ((alpha->hard_lifetime_end_time == beta->hard_lifetime_end_time) && (alpha->soft_lifetime_end_time < beta->soft_lifetime_end_time)) return beta; else return alpha; case FTS_ABANDONED: return alpha; default: log_fatal("Impossible condition at %s:%d.", MDL); } break; case FTS_ABANDONED: switch (beta->state) { case FTS_ACTIVE: case FTS_EXPIRED: return alpha; case FTS_ABANDONED: /* Choose the prefix that was abandoned longest ago. */ if (alpha->hard_lifetime_end_time < beta->hard_lifetime_end_time) return alpha; default: log_fatal("Impossible condition at %s:%d.", MDL); } break; default: log_fatal("Impossible condition at %s:%d.", MDL); } log_fatal("Triple impossible condition at %s:%d.", MDL); return NULL; } /* * Solicit is how a client starts requesting addresses. * * If the client asks for rapid commit, and we support it, we will * allocate the addresses and reply. * * Otherwise we will send an advertise message. */ static void dhcpv6_solicit(struct data_string *reply_ret, struct packet *packet) { struct data_string client_id; /* * Validate our input. */ if (!valid_client_msg(packet, &client_id)) { return; } lease_to_client(reply_ret, packet, &client_id, NULL); /* * Clean up. */ data_string_forget(&client_id, MDL); } /* * Request is how a client actually requests addresses. * * Very similar to Solicit handling, except the server DUID is required. */ /* TODO: reject unicast messages, unless we set unicast option */ static void dhcpv6_request(struct data_string *reply_ret, struct packet *packet) { struct data_string client_id; struct data_string server_id; /* * Validate our input. */ if (!valid_client_resp(packet, &client_id, &server_id)) { return; } /* * Issue our lease. */ lease_to_client(reply_ret, packet, &client_id, &server_id); /* * Cleanup. */ data_string_forget(&client_id, MDL); data_string_forget(&server_id, MDL); } /* Find a DHCPv6 packet's shared network from hints in the packet. */ static isc_result_t shared_network_from_packet6(struct shared_network **shared, struct packet *packet) { const struct packet *chk_packet; const struct in6_addr *link_addr, *first_link_addr; struct iaddr tmp_addr; struct subnet *subnet; isc_result_t status; if ((shared == NULL) || (*shared != NULL) || (packet == NULL)) return DHCP_R_INVALIDARG; /* * First, find the link address where the packet from the client * first appeared (if this packet was relayed). */ first_link_addr = NULL; chk_packet = packet->dhcpv6_container_packet; while (chk_packet != NULL) { link_addr = &chk_packet->dhcpv6_link_address; if (!IN6_IS_ADDR_UNSPECIFIED(link_addr) && !IN6_IS_ADDR_LINKLOCAL(link_addr)) { first_link_addr = link_addr; break; } chk_packet = chk_packet->dhcpv6_container_packet; } /* * If there is a relayed link address, find the subnet associated * with that, and use that to get the appropriate * shared_network. */ if (first_link_addr != NULL) { tmp_addr.len = sizeof(*first_link_addr); memcpy(tmp_addr.iabuf, first_link_addr, sizeof(*first_link_addr)); subnet = NULL; if (!find_subnet(&subnet, tmp_addr, MDL)) { log_debug("No subnet found for link-address %s.", piaddr(tmp_addr)); return ISC_R_NOTFOUND; } status = shared_network_reference(shared, subnet->shared_network, MDL); subnet_dereference(&subnet, MDL); /* * If there is no link address, we will use the interface * that this packet came in on to pick the shared_network. */ } else if (packet->interface != NULL) { status = shared_network_reference(shared, packet->interface->shared_network, MDL); if (packet->dhcpv6_container_packet != NULL) { log_info("[L2 Relay] No link address in relay packet " "assuming L2 relay and using receiving " "interface"); } } else { /* * We shouldn't be able to get here but if there is no link * address and no interface we don't know where to get the * pool from log an error and return an error. */ log_error("No interface and no link address " "can't determine pool"); status = DHCP_R_INVALIDARG; } return status; } /* * When a client thinks it might be on a new link, it sends a * Confirm message. * * From RFC3315 section 18.2.2: * * When the server receives a Confirm message, the server determines * whether the addresses in the Confirm message are appropriate for the * link to which the client is attached. If all of the addresses in the * Confirm message pass this test, the server returns a status of * Success. If any of the addresses do not pass this test, the server * returns a status of NotOnLink. If the server is unable to perform * this test (for example, the server does not have information about * prefixes on the link to which the client is connected), or there were * no addresses in any of the IAs sent by the client, the server MUST * NOT send a reply to the client. */ static void dhcpv6_confirm(struct data_string *reply_ret, struct packet *packet) { struct shared_network *shared; struct subnet *subnet; struct option_cache *ia, *ta, *oc; struct data_string cli_enc_opt_data, iaaddr, client_id, packet_oro; struct option_state *cli_enc_opt_state, *opt_state; struct iaddr cli_addr; int pass; isc_boolean_t inappropriate, has_addrs; char reply_data[65536]; struct dhcpv6_packet *reply = (struct dhcpv6_packet *)reply_data; int reply_ofs = (int)(offsetof(struct dhcpv6_packet, options)); /* * Basic client message validation. */ memset(&client_id, 0, sizeof(client_id)); if (!valid_client_msg(packet, &client_id)) { return; } /* * Do not process Confirms that do not have IA's we do not recognize. */ ia = lookup_option(&dhcpv6_universe, packet->options, D6O_IA_NA); ta = lookup_option(&dhcpv6_universe, packet->options, D6O_IA_TA); if ((ia == NULL) && (ta == NULL)) return; /* * IA_PD's are simply ignored. */ delete_option(&dhcpv6_universe, packet->options, D6O_IA_PD); /* * Bit of variable initialization. */ opt_state = cli_enc_opt_state = NULL; memset(&cli_enc_opt_data, 0, sizeof(cli_enc_opt_data)); memset(&iaaddr, 0, sizeof(iaaddr)); memset(&packet_oro, 0, sizeof(packet_oro)); /* Determine what shared network the client is connected to. We * must not respond if we don't have any information about the * network the client is on. */ shared = NULL; if ((shared_network_from_packet6(&shared, packet) != ISC_R_SUCCESS) || (shared == NULL)) goto exit; /* If there are no recorded subnets, then we have no * information about this subnet - ignore Confirms. */ subnet = shared->subnets; if (subnet == NULL) goto exit; /* Are the addresses in all the IA's appropriate for that link? */ has_addrs = inappropriate = ISC_FALSE; pass = D6O_IA_NA; while(!inappropriate) { /* If we've reached the end of the IA_NA pass, move to the * IA_TA pass. */ if ((pass == D6O_IA_NA) && (ia == NULL)) { pass = D6O_IA_TA; ia = ta; } /* If we've reached the end of all passes, we're done. */ if (ia == NULL) break; if (((pass == D6O_IA_NA) && !get_encapsulated_IA_state(&cli_enc_opt_state, &cli_enc_opt_data, packet, ia, IA_NA_OFFSET)) || ((pass == D6O_IA_TA) && !get_encapsulated_IA_state(&cli_enc_opt_state, &cli_enc_opt_data, packet, ia, IA_TA_OFFSET))) { goto exit; } oc = lookup_option(&dhcpv6_universe, cli_enc_opt_state, D6O_IAADDR); for ( ; oc != NULL ; oc = oc->next) { if (!evaluate_option_cache(&iaaddr, packet, NULL, NULL, packet->options, NULL, &global_scope, oc, MDL) || (iaaddr.len < IAADDR_OFFSET)) { log_error("dhcpv6_confirm: " "error evaluating IAADDR."); goto exit; } /* Copy out the IPv6 address for processing. */ cli_addr.len = 16; memcpy(cli_addr.iabuf, iaaddr.data, 16); data_string_forget(&iaaddr, MDL); /* Record that we've processed at least one address. */ has_addrs = ISC_TRUE; /* Find out if any subnets cover this address. */ for (subnet = shared->subnets ; subnet != NULL ; subnet = subnet->next_sibling) { if (addr_eq(subnet_number(cli_addr, subnet->netmask), subnet->net)) break; } /* If we reach the end of the subnet list, and no * subnet matches the client address, then it must * be inappropriate to the link (so far as our * configuration says). Once we've found one * inappropriate address, there is no reason to * continue searching. */ if (subnet == NULL) { inappropriate = ISC_TRUE; break; } } option_state_dereference(&cli_enc_opt_state, MDL); data_string_forget(&cli_enc_opt_data, MDL); /* Advance to the next IA_*. */ ia = ia->next; } /* If the client supplied no addresses, do not reply. */ if (!has_addrs) goto exit; /* * Set up reply. */ if (!start_reply(packet, &client_id, NULL, &opt_state, reply)) { goto exit; } /* * Set our status. */ if (inappropriate) { if (!set_status_code(STATUS_NotOnLink, "Some of the addresses are not on link.", opt_state)) { goto exit; } } else { if (!set_status_code(STATUS_Success, "All addresses still on link.", opt_state)) { goto exit; } } /* * Only one option: add it. */ reply_ofs += store_options6(reply_data+reply_ofs, sizeof(reply_data)-reply_ofs, opt_state, packet, required_opts, &packet_oro); /* * Return our reply to the caller. */ reply_ret->len = reply_ofs; reply_ret->buffer = NULL; if (!buffer_allocate(&reply_ret->buffer, reply_ofs, MDL)) { log_fatal("No memory to store reply."); } reply_ret->data = reply_ret->buffer->data; memcpy(reply_ret->buffer->data, reply, reply_ofs); exit: /* Cleanup any stale data strings. */ if (cli_enc_opt_data.buffer != NULL) data_string_forget(&cli_enc_opt_data, MDL); if (iaaddr.buffer != NULL) data_string_forget(&iaaddr, MDL); if (client_id.buffer != NULL) data_string_forget(&client_id, MDL); if (packet_oro.buffer != NULL) data_string_forget(&packet_oro, MDL); /* Release any stale option states. */ if (cli_enc_opt_state != NULL) option_state_dereference(&cli_enc_opt_state, MDL); if (opt_state != NULL) option_state_dereference(&opt_state, MDL); } /* * Renew is when a client wants to extend its lease/prefix, at time T1. * * We handle this the same as if the client wants a new lease/prefix, * except for the error code of when addresses don't match. */ /* TODO: reject unicast messages, unless we set unicast option */ static void dhcpv6_renew(struct data_string *reply, struct packet *packet) { struct data_string client_id; struct data_string server_id; /* * Validate the request. */ if (!valid_client_resp(packet, &client_id, &server_id)) { return; } /* * Renew our lease. */ lease_to_client(reply, packet, &client_id, &server_id); /* * Cleanup. */ data_string_forget(&server_id, MDL); data_string_forget(&client_id, MDL); } /* * Rebind is when a client wants to extend its lease, at time T2. * * We handle this the same as if the client wants a new lease, except * for the error code of when addresses don't match. */ static void dhcpv6_rebind(struct data_string *reply, struct packet *packet) { struct data_string client_id; if (!valid_client_msg(packet, &client_id)) { return; } lease_to_client(reply, packet, &client_id, NULL); data_string_forget(&client_id, MDL); } static void ia_na_match_decline(const struct data_string *client_id, const struct data_string *iaaddr, struct iasubopt *lease) { char tmp_addr[INET6_ADDRSTRLEN]; log_error("Client %s reports address %s is " "already in use by another host!", print_hex_1(client_id->len, client_id->data, 60), inet_ntop(AF_INET6, iaaddr->data, tmp_addr, sizeof(tmp_addr))); if (lease != NULL) { decline_lease6(lease->ipv6_pool, lease); lease->ia->cltt = cur_time; write_ia(lease->ia); } } static void ia_na_nomatch_decline(const struct data_string *client_id, const struct data_string *iaaddr, u_int32_t *ia_na_id, struct packet *packet, char *reply_data, int *reply_ofs, int reply_len) { char tmp_addr[INET6_ADDRSTRLEN]; struct option_state *host_opt_state; int len; log_info("Client %s declines address %s, which is not offered to it.", print_hex_1(client_id->len, client_id->data, 60), inet_ntop(AF_INET6, iaaddr->data, tmp_addr, sizeof(tmp_addr))); /* * Create state for this IA_NA. */ host_opt_state = NULL; if (!option_state_allocate(&host_opt_state, MDL)) { log_error("ia_na_nomatch_decline: out of memory " "allocating option_state."); goto exit; } if (!set_status_code(STATUS_NoBinding, "Decline for unknown address.", host_opt_state)) { goto exit; } /* * Insure we have enough space */ if (reply_len < (*reply_ofs + 16)) { log_error("ia_na_nomatch_decline: " "out of space for reply packet."); goto exit; } /* * Put our status code into the reply packet. */ len = store_options6(reply_data+(*reply_ofs)+16, reply_len-(*reply_ofs)-16, host_opt_state, packet, required_opts_STATUS_CODE, NULL); /* * Store the non-encapsulated option data for this * IA_NA into our reply packet. Defined in RFC 3315, * section 22.4. */ /* option number */ putUShort((unsigned char *)reply_data+(*reply_ofs), D6O_IA_NA); /* option length */ putUShort((unsigned char *)reply_data+(*reply_ofs)+2, len + 12); /* IA_NA, copied from the client */ memcpy(reply_data+(*reply_ofs)+4, ia_na_id, 4); /* t1 and t2, odd that we need them, but here it is */ putULong((unsigned char *)reply_data+(*reply_ofs)+8, 0); putULong((unsigned char *)reply_data+(*reply_ofs)+12, 0); /* * Get ready for next IA_NA. */ *reply_ofs += (len + 16); exit: option_state_dereference(&host_opt_state, MDL); } static void iterate_over_ia_na(struct data_string *reply_ret, struct packet *packet, const struct data_string *client_id, const struct data_string *server_id, const char *packet_type, void (*ia_na_match)(), void (*ia_na_nomatch)()) { struct option_state *opt_state; struct host_decl *packet_host; struct option_cache *ia; struct option_cache *oc; /* cli_enc_... variables come from the IA_NA/IA_TA options */ struct data_string cli_enc_opt_data; struct option_state *cli_enc_opt_state; struct host_decl *host; struct option_state *host_opt_state; struct data_string iaaddr; struct data_string fixed_addr; char reply_data[65536]; struct dhcpv6_packet *reply = (struct dhcpv6_packet *)reply_data; int reply_ofs = (int)(offsetof(struct dhcpv6_packet, options)); char status_msg[32]; struct iasubopt *lease; struct ia_xx *existing_ia_na; int i; struct data_string key; u_int32_t iaid; /* * Initialize to empty values, in case we have to exit early. */ opt_state = NULL; memset(&cli_enc_opt_data, 0, sizeof(cli_enc_opt_data)); cli_enc_opt_state = NULL; memset(&iaaddr, 0, sizeof(iaaddr)); memset(&fixed_addr, 0, sizeof(fixed_addr)); host_opt_state = NULL; lease = NULL; /* * Find the host record that matches from the packet, if any. */ packet_host = NULL; if (!find_hosts_by_uid(&packet_host, client_id->data, client_id->len, MDL)) { packet_host = NULL; /* * Note: In general, we don't expect a client to provide * enough information to match by option for these * types of messages, but if we don't have a UID * match we can check anyway. */ if (!find_hosts_by_option(&packet_host, packet, packet->options, MDL)) { packet_host = NULL; if (!find_hosts_by_duid_chaddr(&packet_host, client_id)) packet_host = NULL; } } /* * Set our reply information. */ reply->msg_type = DHCPV6_REPLY; memcpy(reply->transaction_id, packet->dhcpv6_transaction_id, sizeof(reply->transaction_id)); /* * Build our option state for reply. */ opt_state = NULL; if (!option_state_allocate(&opt_state, MDL)) { log_error("iterate_over_ia_na: no memory for option_state."); goto exit; } execute_statements_in_scope(NULL, packet, NULL, NULL, packet->options, opt_state, &global_scope, root_group, NULL); /* * RFC 3315, section 18.2.7 tells us which options to include. */ oc = lookup_option(&dhcpv6_universe, opt_state, D6O_SERVERID); if (oc == NULL) { if (!save_option_buffer(&dhcpv6_universe, opt_state, NULL, (unsigned char *)server_duid.data, server_duid.len, D6O_SERVERID, 0)) { log_error("iterate_over_ia_na: " "error saving server identifier."); goto exit; } } if (!save_option_buffer(&dhcpv6_universe, opt_state, client_id->buffer, (unsigned char *)client_id->data, client_id->len, D6O_CLIENTID, 0)) { log_error("iterate_over_ia_na: " "error saving client identifier."); goto exit; } snprintf(status_msg, sizeof(status_msg), "%s received.", packet_type); if (!set_status_code(STATUS_Success, status_msg, opt_state)) { goto exit; } /* * Add our options that are not associated with any IA_NA or IA_TA. */ reply_ofs += store_options6(reply_data+reply_ofs, sizeof(reply_data)-reply_ofs, opt_state, packet, required_opts, NULL); /* * Loop through the IA_NA reported by the client, and deal with * addresses reported as already in use. */ for (ia = lookup_option(&dhcpv6_universe, packet->options, D6O_IA_NA); ia != NULL; ia = ia->next) { if (!get_encapsulated_IA_state(&cli_enc_opt_state, &cli_enc_opt_data, packet, ia, IA_NA_OFFSET)) { goto exit; } iaid = getULong(cli_enc_opt_data.data); /* * XXX: It is possible that we can get multiple addresses * sent by the client. We don't send multiple * addresses, so this indicates a client error. * We should check for multiple IAADDR options, log * if found, and set as an error. */ oc = lookup_option(&dhcpv6_universe, cli_enc_opt_state, D6O_IAADDR); if (oc == NULL) { /* no address given for this IA, ignore */ option_state_dereference(&cli_enc_opt_state, MDL); data_string_forget(&cli_enc_opt_data, MDL); continue; } memset(&iaaddr, 0, sizeof(iaaddr)); if (!evaluate_option_cache(&iaaddr, packet, NULL, NULL, packet->options, NULL, &global_scope, oc, MDL)) { log_error("iterate_over_ia_na: " "error evaluating IAADDR."); goto exit; } /* * Now we need to figure out which host record matches * this IA_NA and IAADDR (encapsulated option contents * matching a host record by option). * * XXX: We don't currently track IA_NA separately, but * we will need to do this! */ host = NULL; if (!find_hosts_by_option(&host, packet, cli_enc_opt_state, MDL)) { if (packet_host != NULL) { host = packet_host; } else { host = NULL; } } while (host != NULL) { if (host->fixed_addr != NULL) { if (!evaluate_option_cache(&fixed_addr, NULL, NULL, NULL, NULL, NULL, &global_scope, host->fixed_addr, MDL)) { log_error("iterate_over_ia_na: error " "evaluating host address."); goto exit; } if ((iaaddr.len >= 16) && !memcmp(fixed_addr.data, iaaddr.data, 16)) { data_string_forget(&fixed_addr, MDL); break; } data_string_forget(&fixed_addr, MDL); } host = host->n_ipaddr; } if ((host == NULL) && (iaaddr.len >= IAADDR_OFFSET)) { /* * Find existing IA_NA. */ if (ia_make_key(&key, iaid, (char *)client_id->data, client_id->len, MDL) != ISC_R_SUCCESS) { log_fatal("iterate_over_ia_na: no memory for " "key."); } existing_ia_na = NULL; if (ia_hash_lookup(&existing_ia_na, ia_na_active, (unsigned char *)key.data, key.len, MDL)) { /* * Make sure this address is in the IA_NA. */ for (i=0; inum_iasubopt; i++) { struct iasubopt *tmp; struct in6_addr *in6_addr; tmp = existing_ia_na->iasubopt[i]; in6_addr = &tmp->addr; if (memcmp(in6_addr, iaaddr.data, 16) == 0) { iasubopt_reference(&lease, tmp, MDL); break; } } } data_string_forget(&key, MDL); } if ((host != NULL) || (lease != NULL)) { ia_na_match(client_id, &iaaddr, lease); } else { ia_na_nomatch(client_id, &iaaddr, (u_int32_t *)cli_enc_opt_data.data, packet, reply_data, &reply_ofs, sizeof(reply_data)); } if (lease != NULL) { iasubopt_dereference(&lease, MDL); } data_string_forget(&iaaddr, MDL); option_state_dereference(&cli_enc_opt_state, MDL); data_string_forget(&cli_enc_opt_data, MDL); } /* * Return our reply to the caller. */ reply_ret->len = reply_ofs; reply_ret->buffer = NULL; if (!buffer_allocate(&reply_ret->buffer, reply_ofs, MDL)) { log_fatal("No memory to store reply."); } reply_ret->data = reply_ret->buffer->data; memcpy(reply_ret->buffer->data, reply, reply_ofs); exit: if (lease != NULL) { iasubopt_dereference(&lease, MDL); } if (host_opt_state != NULL) { option_state_dereference(&host_opt_state, MDL); } if (fixed_addr.buffer != NULL) { data_string_forget(&fixed_addr, MDL); } if (iaaddr.buffer != NULL) { data_string_forget(&iaaddr, MDL); } if (cli_enc_opt_state != NULL) { option_state_dereference(&cli_enc_opt_state, MDL); } if (cli_enc_opt_data.buffer != NULL) { data_string_forget(&cli_enc_opt_data, MDL); } if (opt_state != NULL) { option_state_dereference(&opt_state, MDL); } } /* * Decline means a client has detected that something else is using an * address we gave it. * * Since we're only dealing with fixed leases for now, there's not * much we can do, other that log the occurrence. * * When we start issuing addresses from pools, then we will have to * record our declined addresses and issue another. In general with * IPv6 there is no worry about DoS by clients exhausting space, but * we still need to be aware of this possibility. */ /* TODO: reject unicast messages, unless we set unicast option */ /* TODO: IA_TA */ static void dhcpv6_decline(struct data_string *reply, struct packet *packet) { struct data_string client_id; struct data_string server_id; /* * Validate our input. */ if (!valid_client_resp(packet, &client_id, &server_id)) { return; } /* * Undefined for IA_PD. */ delete_option(&dhcpv6_universe, packet->options, D6O_IA_PD); /* * And operate on each IA_NA in this packet. */ iterate_over_ia_na(reply, packet, &client_id, &server_id, "Decline", ia_na_match_decline, ia_na_nomatch_decline); data_string_forget(&server_id, MDL); data_string_forget(&client_id, MDL); } static void ia_na_match_release(const struct data_string *client_id, const struct data_string *iaaddr, struct iasubopt *lease) { char tmp_addr[INET6_ADDRSTRLEN]; log_info("Client %s releases address %s", print_hex_1(client_id->len, client_id->data, 60), inet_ntop(AF_INET6, iaaddr->data, tmp_addr, sizeof(tmp_addr))); if (lease != NULL) { release_lease6(lease->ipv6_pool, lease); lease->ia->cltt = cur_time; write_ia(lease->ia); } } static void ia_na_nomatch_release(const struct data_string *client_id, const struct data_string *iaaddr, u_int32_t *ia_na_id, struct packet *packet, char *reply_data, int *reply_ofs, int reply_len) { char tmp_addr[INET6_ADDRSTRLEN]; struct option_state *host_opt_state; int len; log_info("Client %s releases address %s, which is not leased to it.", print_hex_1(client_id->len, client_id->data, 60), inet_ntop(AF_INET6, iaaddr->data, tmp_addr, sizeof(tmp_addr))); /* * Create state for this IA_NA. */ host_opt_state = NULL; if (!option_state_allocate(&host_opt_state, MDL)) { log_error("ia_na_nomatch_release: out of memory " "allocating option_state."); goto exit; } if (!set_status_code(STATUS_NoBinding, "Release for non-leased address.", host_opt_state)) { goto exit; } /* * Insure we have enough space */ if (reply_len < (*reply_ofs + 16)) { log_error("ia_na_nomatch_release: " "out of space for reply packet."); goto exit; } /* * Put our status code into the reply packet. */ len = store_options6(reply_data+(*reply_ofs)+16, reply_len-(*reply_ofs)-16, host_opt_state, packet, required_opts_STATUS_CODE, NULL); /* * Store the non-encapsulated option data for this * IA_NA into our reply packet. Defined in RFC 3315, * section 22.4. */ /* option number */ putUShort((unsigned char *)reply_data+(*reply_ofs), D6O_IA_NA); /* option length */ putUShort((unsigned char *)reply_data+(*reply_ofs)+2, len + 12); /* IA_NA, copied from the client */ memcpy(reply_data+(*reply_ofs)+4, ia_na_id, 4); /* t1 and t2, odd that we need them, but here it is */ putULong((unsigned char *)reply_data+(*reply_ofs)+8, 0); putULong((unsigned char *)reply_data+(*reply_ofs)+12, 0); /* * Get ready for next IA_NA. */ *reply_ofs += (len + 16); exit: option_state_dereference(&host_opt_state, MDL); } static void ia_pd_match_release(const struct data_string *client_id, const struct data_string *iapref, struct iasubopt *prefix) { char tmp_addr[INET6_ADDRSTRLEN]; log_info("Client %s releases prefix %s/%u", print_hex_1(client_id->len, client_id->data, 60), inet_ntop(AF_INET6, iapref->data + 9, tmp_addr, sizeof(tmp_addr)), (unsigned) getUChar(iapref->data + 8)); if (prefix != NULL) { release_lease6(prefix->ipv6_pool, prefix); prefix->ia->cltt = cur_time; write_ia(prefix->ia); } } static void ia_pd_nomatch_release(const struct data_string *client_id, const struct data_string *iapref, u_int32_t *ia_pd_id, struct packet *packet, char *reply_data, int *reply_ofs, int reply_len) { char tmp_addr[INET6_ADDRSTRLEN]; struct option_state *host_opt_state; int len; log_info("Client %s releases prefix %s/%u, which is not leased to it.", print_hex_1(client_id->len, client_id->data, 60), inet_ntop(AF_INET6, iapref->data + 9, tmp_addr, sizeof(tmp_addr)), (unsigned) getUChar(iapref->data + 8)); /* * Create state for this IA_PD. */ host_opt_state = NULL; if (!option_state_allocate(&host_opt_state, MDL)) { log_error("ia_pd_nomatch_release: out of memory " "allocating option_state."); goto exit; } if (!set_status_code(STATUS_NoBinding, "Release for non-leased prefix.", host_opt_state)) { goto exit; } /* * Insure we have enough space */ if (reply_len < (*reply_ofs + 16)) { log_error("ia_pd_nomatch_release: " "out of space for reply packet."); goto exit; } /* * Put our status code into the reply packet. */ len = store_options6(reply_data+(*reply_ofs)+16, reply_len-(*reply_ofs)-16, host_opt_state, packet, required_opts_STATUS_CODE, NULL); /* * Store the non-encapsulated option data for this * IA_PD into our reply packet. Defined in RFC 3315, * section 22.4. */ /* option number */ putUShort((unsigned char *)reply_data+(*reply_ofs), D6O_IA_PD); /* option length */ putUShort((unsigned char *)reply_data+(*reply_ofs)+2, len + 12); /* IA_PD, copied from the client */ memcpy(reply_data+(*reply_ofs)+4, ia_pd_id, 4); /* t1 and t2, odd that we need them, but here it is */ putULong((unsigned char *)reply_data+(*reply_ofs)+8, 0); putULong((unsigned char *)reply_data+(*reply_ofs)+12, 0); /* * Get ready for next IA_PD. */ *reply_ofs += (len + 16); exit: option_state_dereference(&host_opt_state, MDL); } static void iterate_over_ia_pd(struct data_string *reply_ret, struct packet *packet, const struct data_string *client_id, const struct data_string *server_id, const char *packet_type, void (*ia_pd_match)(), void (*ia_pd_nomatch)()) { struct data_string reply_new; int reply_len; struct option_state *opt_state; struct host_decl *packet_host; struct option_cache *ia; struct option_cache *oc; /* cli_enc_... variables come from the IA_PD options */ struct data_string cli_enc_opt_data; struct option_state *cli_enc_opt_state; struct host_decl *host; struct option_state *host_opt_state; struct data_string iaprefix; char reply_data[65536]; int reply_ofs; struct iasubopt *prefix; struct ia_xx *existing_ia_pd; int i; struct data_string key; u_int32_t iaid; /* * Initialize to empty values, in case we have to exit early. */ memset(&reply_new, 0, sizeof(reply_new)); opt_state = NULL; memset(&cli_enc_opt_data, 0, sizeof(cli_enc_opt_data)); cli_enc_opt_state = NULL; memset(&iaprefix, 0, sizeof(iaprefix)); host_opt_state = NULL; prefix = NULL; /* * Compute the available length for the reply. */ reply_len = sizeof(reply_data) - reply_ret->len; reply_ofs = 0; /* * Find the host record that matches from the packet, if any. */ packet_host = NULL; if (!find_hosts_by_uid(&packet_host, client_id->data, client_id->len, MDL)) { packet_host = NULL; /* * Note: In general, we don't expect a client to provide * enough information to match by option for these * types of messages, but if we don't have a UID * match we can check anyway. */ if (!find_hosts_by_option(&packet_host, packet, packet->options, MDL)) { packet_host = NULL; if (!find_hosts_by_duid_chaddr(&packet_host, client_id)) packet_host = NULL; } } /* * Build our option state for reply. */ opt_state = NULL; if (!option_state_allocate(&opt_state, MDL)) { log_error("iterate_over_ia_pd: no memory for option_state."); goto exit; } execute_statements_in_scope(NULL, packet, NULL, NULL, packet->options, opt_state, &global_scope, root_group, NULL); /* * Loop through the IA_PD reported by the client, and deal with * prefixes reported as already in use. */ for (ia = lookup_option(&dhcpv6_universe, packet->options, D6O_IA_PD); ia != NULL; ia = ia->next) { if (!get_encapsulated_IA_state(&cli_enc_opt_state, &cli_enc_opt_data, packet, ia, IA_PD_OFFSET)) { goto exit; } iaid = getULong(cli_enc_opt_data.data); oc = lookup_option(&dhcpv6_universe, cli_enc_opt_state, D6O_IAPREFIX); if (oc == NULL) { /* no prefix given for this IA_PD, ignore */ option_state_dereference(&cli_enc_opt_state, MDL); data_string_forget(&cli_enc_opt_data, MDL); continue; } for (; oc != NULL; oc = oc->next) { memset(&iaprefix, 0, sizeof(iaprefix)); if (!evaluate_option_cache(&iaprefix, packet, NULL, NULL, packet->options, NULL, &global_scope, oc, MDL)) { log_error("iterate_over_ia_pd: " "error evaluating IAPREFIX."); goto exit; } /* * Now we need to figure out which host record matches * this IA_PD and IAPREFIX (encapsulated option contents * matching a host record by option). * * XXX: We don't currently track IA_PD separately, but * we will need to do this! */ host = NULL; if (!find_hosts_by_option(&host, packet, cli_enc_opt_state, MDL)) { if (packet_host != NULL) { host = packet_host; } else { host = NULL; } } while (host != NULL) { if (host->fixed_prefix != NULL) { struct iaddrcidrnetlist *l; int plen = (int) getUChar(iaprefix.data + 8); for (l = host->fixed_prefix; l != NULL; l = l->next) { if (plen != l->cidrnet.bits) continue; if (memcmp(iaprefix.data + 9, l->cidrnet.lo_addr.iabuf, 16) == 0) break; } if ((l != NULL) && (iaprefix.len >= 17)) break; } host = host->n_ipaddr; } if ((host == NULL) && (iaprefix.len >= IAPREFIX_OFFSET)) { /* * Find existing IA_PD. */ if (ia_make_key(&key, iaid, (char *)client_id->data, client_id->len, MDL) != ISC_R_SUCCESS) { log_fatal("iterate_over_ia_pd: no memory for " "key."); } existing_ia_pd = NULL; if (ia_hash_lookup(&existing_ia_pd, ia_pd_active, (unsigned char *)key.data, key.len, MDL)) { /* * Make sure this prefix is in the IA_PD. */ for (i = 0; i < existing_ia_pd->num_iasubopt; i++) { struct iasubopt *tmp; u_int8_t plen; plen = getUChar(iaprefix.data + 8); tmp = existing_ia_pd->iasubopt[i]; if ((tmp->plen == plen) && (memcmp(&tmp->addr, iaprefix.data + 9, 16) == 0)) { iasubopt_reference(&prefix, tmp, MDL); break; } } } data_string_forget(&key, MDL); } if ((host != NULL) || (prefix != NULL)) { ia_pd_match(client_id, &iaprefix, prefix); } else { ia_pd_nomatch(client_id, &iaprefix, (u_int32_t *)cli_enc_opt_data.data, packet, reply_data, &reply_ofs, reply_len - reply_ofs); } if (prefix != NULL) { iasubopt_dereference(&prefix, MDL); } data_string_forget(&iaprefix, MDL); } option_state_dereference(&cli_enc_opt_state, MDL); data_string_forget(&cli_enc_opt_data, MDL); } /* * Return our reply to the caller. * The IA_NA routine has already filled at least the header. */ reply_new.len = reply_ret->len + reply_ofs; if (!buffer_allocate(&reply_new.buffer, reply_new.len, MDL)) { log_fatal("No memory to store reply."); } reply_new.data = reply_new.buffer->data; memcpy(reply_new.buffer->data, reply_ret->buffer->data, reply_ret->len); memcpy(reply_new.buffer->data + reply_ret->len, reply_data, reply_ofs); data_string_forget(reply_ret, MDL); data_string_copy(reply_ret, &reply_new, MDL); data_string_forget(&reply_new, MDL); exit: if (prefix != NULL) { iasubopt_dereference(&prefix, MDL); } if (host_opt_state != NULL) { option_state_dereference(&host_opt_state, MDL); } if (iaprefix.buffer != NULL) { data_string_forget(&iaprefix, MDL); } if (cli_enc_opt_state != NULL) { option_state_dereference(&cli_enc_opt_state, MDL); } if (cli_enc_opt_data.buffer != NULL) { data_string_forget(&cli_enc_opt_data, MDL); } if (opt_state != NULL) { option_state_dereference(&opt_state, MDL); } } /* * Release means a client is done with the leases. */ /* TODO: reject unicast messages, unless we set unicast option */ static void dhcpv6_release(struct data_string *reply, struct packet *packet) { struct data_string client_id; struct data_string server_id; /* * Validate our input. */ if (!valid_client_resp(packet, &client_id, &server_id)) { return; } /* * And operate on each IA_NA in this packet. */ iterate_over_ia_na(reply, packet, &client_id, &server_id, "Release", ia_na_match_release, ia_na_nomatch_release); /* * And operate on each IA_PD in this packet. */ iterate_over_ia_pd(reply, packet, &client_id, &server_id, "Release", ia_pd_match_release, ia_pd_nomatch_release); data_string_forget(&server_id, MDL); data_string_forget(&client_id, MDL); } /* * Information-Request is used by clients who have obtained an address * from other means, but want configuration information from the server. */ static void dhcpv6_information_request(struct data_string *reply, struct packet *packet) { struct data_string client_id; struct data_string server_id; /* * Validate our input. */ if (!valid_client_info_req(packet, &server_id)) { return; } /* * Get our client ID, if there is one. */ memset(&client_id, 0, sizeof(client_id)); if (get_client_id(packet, &client_id) != ISC_R_SUCCESS) { data_string_forget(&client_id, MDL); } /* * Use the lease_to_client() function. This will work fine, * because the valid_client_info_req() insures that we * don't have any IA that would cause us to allocate * resources to the client. */ lease_to_client(reply, packet, &client_id, server_id.data != NULL ? &server_id : NULL); /* * Cleanup. */ if (client_id.data != NULL) { data_string_forget(&client_id, MDL); } data_string_forget(&server_id, MDL); } /* * The Relay-forw message is sent by relays. It typically contains a * single option, which encapsulates an entire packet. * * We need to build an encapsulated reply. */ /* XXX: this is very, very similar to do_packet6(), and should probably be combined in a clever way */ static void dhcpv6_relay_forw(struct data_string *reply_ret, struct packet *packet) { struct option_cache *oc; struct data_string enc_opt_data; struct packet *enc_packet; unsigned char msg_type; const struct dhcpv6_packet *msg; const struct dhcpv6_relay_packet *relay; struct data_string enc_reply; char link_addr[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")]; char peer_addr[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")]; struct data_string a_opt, packet_ero; struct option_state *opt_state; static char reply_data[65536]; struct dhcpv6_relay_packet *reply; int reply_ofs; /* * Initialize variables for early exit. */ opt_state = NULL; memset(&a_opt, 0, sizeof(a_opt)); memset(&packet_ero, 0, sizeof(packet_ero)); memset(&enc_reply, 0, sizeof(enc_reply)); memset(&enc_opt_data, 0, sizeof(enc_opt_data)); enc_packet = NULL; /* * Get our encapsulated relay message. */ oc = lookup_option(&dhcpv6_universe, packet->options, D6O_RELAY_MSG); if (oc == NULL) { inet_ntop(AF_INET6, &packet->dhcpv6_link_address, link_addr, sizeof(link_addr)); inet_ntop(AF_INET6, &packet->dhcpv6_peer_address, peer_addr, sizeof(peer_addr)); log_info("Relay-forward from %s with link address=%s and " "peer address=%s missing Relay Message option.", piaddr(packet->client_addr), link_addr, peer_addr); goto exit; } if (!evaluate_option_cache(&enc_opt_data, NULL, NULL, NULL, NULL, NULL, &global_scope, oc, MDL)) { log_error("dhcpv6_forw_relay: error evaluating " "relayed message."); goto exit; } if (!packet6_len_okay((char *)enc_opt_data.data, enc_opt_data.len)) { log_error("dhcpv6_forw_relay: encapsulated packet too short."); goto exit; } /* * Build a packet structure from this encapsulated packet. */ enc_packet = NULL; if (!packet_allocate(&enc_packet, MDL)) { log_error("dhcpv6_forw_relay: " "no memory for encapsulated packet."); goto exit; } if (!option_state_allocate(&enc_packet->options, MDL)) { log_error("dhcpv6_forw_relay: " "no memory for encapsulated packet's options."); goto exit; } enc_packet->client_port = packet->client_port; enc_packet->client_addr = packet->client_addr; interface_reference(&enc_packet->interface, packet->interface, MDL); enc_packet->dhcpv6_container_packet = packet; msg_type = enc_opt_data.data[0]; if ((msg_type == DHCPV6_RELAY_FORW) || (msg_type == DHCPV6_RELAY_REPL)) { int relaylen = (int)(offsetof(struct dhcpv6_relay_packet, options)); relay = (struct dhcpv6_relay_packet *)enc_opt_data.data; enc_packet->dhcpv6_msg_type = relay->msg_type; /* relay-specific data */ enc_packet->dhcpv6_hop_count = relay->hop_count; memcpy(&enc_packet->dhcpv6_link_address, relay->link_address, sizeof(relay->link_address)); memcpy(&enc_packet->dhcpv6_peer_address, relay->peer_address, sizeof(relay->peer_address)); if (!parse_option_buffer(enc_packet->options, relay->options, enc_opt_data.len - relaylen, &dhcpv6_universe)) { /* no logging here, as parse_option_buffer() logs all cases where it fails */ goto exit; } } else { int msglen = (int)(offsetof(struct dhcpv6_packet, options)); msg = (struct dhcpv6_packet *)enc_opt_data.data; enc_packet->dhcpv6_msg_type = msg->msg_type; /* message-specific data */ memcpy(enc_packet->dhcpv6_transaction_id, msg->transaction_id, sizeof(enc_packet->dhcpv6_transaction_id)); if (!parse_option_buffer(enc_packet->options, msg->options, enc_opt_data.len - msglen, &dhcpv6_universe)) { /* no logging here, as parse_option_buffer() logs all cases where it fails */ goto exit; } } /* * This is recursive. It is possible to exceed maximum packet size. * XXX: This will cause the packet send to fail. */ build_dhcpv6_reply(&enc_reply, enc_packet); /* * If we got no encapsulated data, then it is discarded, and * our reply-forw is also discarded. */ if (enc_reply.data == NULL) { goto exit; } /* * Now we can use the reply_data buffer. * Packet header stuff all comes from the forward message. */ reply = (struct dhcpv6_relay_packet *)reply_data; reply->msg_type = DHCPV6_RELAY_REPL; reply->hop_count = packet->dhcpv6_hop_count; memcpy(reply->link_address, &packet->dhcpv6_link_address, sizeof(reply->link_address)); memcpy(reply->peer_address, &packet->dhcpv6_peer_address, sizeof(reply->peer_address)); reply_ofs = (int)(offsetof(struct dhcpv6_relay_packet, options)); /* * Get the reply option state. */ opt_state = NULL; if (!option_state_allocate(&opt_state, MDL)) { log_error("dhcpv6_relay_forw: no memory for option state."); goto exit; } /* * Append the interface-id if present. */ oc = lookup_option(&dhcpv6_universe, packet->options, D6O_INTERFACE_ID); if (oc != NULL) { if (!evaluate_option_cache(&a_opt, packet, NULL, NULL, packet->options, NULL, &global_scope, oc, MDL)) { log_error("dhcpv6_relay_forw: error evaluating " "Interface ID."); goto exit; } if (!save_option_buffer(&dhcpv6_universe, opt_state, NULL, (unsigned char *)a_opt.data, a_opt.len, D6O_INTERFACE_ID, 0)) { log_error("dhcpv6_relay_forw: error saving " "Interface ID."); goto exit; } data_string_forget(&a_opt, MDL); } /* * Append our encapsulated stuff for caller. */ if (!save_option_buffer(&dhcpv6_universe, opt_state, NULL, (unsigned char *)enc_reply.data, enc_reply.len, D6O_RELAY_MSG, 0)) { log_error("dhcpv6_relay_forw: error saving Relay MSG."); goto exit; } /* * Get the ERO if any. */ oc = lookup_option(&dhcpv6_universe, packet->options, D6O_ERO); if (oc != NULL) { unsigned req; int i; if (!evaluate_option_cache(&packet_ero, packet, NULL, NULL, packet->options, NULL, &global_scope, oc, MDL) || (packet_ero.len & 1)) { log_error("dhcpv6_relay_forw: error evaluating ERO."); goto exit; } /* Decode and apply the ERO. */ for (i = 0; i < packet_ero.len; i += 2) { req = getUShort(packet_ero.data + i); /* Already in the reply? */ oc = lookup_option(&dhcpv6_universe, opt_state, req); if (oc != NULL) continue; /* Get it from the packet if present. */ oc = lookup_option(&dhcpv6_universe, packet->options, req); if (oc == NULL) continue; if (!evaluate_option_cache(&a_opt, packet, NULL, NULL, packet->options, NULL, &global_scope, oc, MDL)) { log_error("dhcpv6_relay_forw: error " "evaluating option %u.", req); goto exit; } if (!save_option_buffer(&dhcpv6_universe, opt_state, NULL, (unsigned char *)a_opt.data, a_opt.len, req, 0)) { log_error("dhcpv6_relay_forw: error saving " "option %u.", req); goto exit; } data_string_forget(&a_opt, MDL); } } reply_ofs += store_options6(reply_data + reply_ofs, sizeof(reply_data) - reply_ofs, opt_state, packet, required_opts_agent, &packet_ero); /* * Return our reply to the caller. */ reply_ret->len = reply_ofs; reply_ret->buffer = NULL; if (!buffer_allocate(&reply_ret->buffer, reply_ret->len, MDL)) { log_fatal("No memory to store reply."); } reply_ret->data = reply_ret->buffer->data; memcpy(reply_ret->buffer->data, reply_data, reply_ofs); exit: if (opt_state != NULL) option_state_dereference(&opt_state, MDL); if (a_opt.data != NULL) { data_string_forget(&a_opt, MDL); } if (packet_ero.data != NULL) { data_string_forget(&packet_ero, MDL); } if (enc_reply.data != NULL) { data_string_forget(&enc_reply, MDL); } if (enc_opt_data.data != NULL) { data_string_forget(&enc_opt_data, MDL); } if (enc_packet != NULL) { packet_dereference(&enc_packet, MDL); } } static void dhcpv6_discard(struct packet *packet) { /* INSIST(packet->msg_type > 0); */ /* INSIST(packet->msg_type < dhcpv6_type_name_max); */ log_debug("Discarding %s from %s; message type not handled by server", dhcpv6_type_names[packet->dhcpv6_msg_type], piaddr(packet->client_addr)); } static void build_dhcpv6_reply(struct data_string *reply, struct packet *packet) { memset(reply, 0, sizeof(*reply)); switch (packet->dhcpv6_msg_type) { case DHCPV6_SOLICIT: dhcpv6_solicit(reply, packet); break; case DHCPV6_ADVERTISE: dhcpv6_discard(packet); break; case DHCPV6_REQUEST: dhcpv6_request(reply, packet); break; case DHCPV6_CONFIRM: dhcpv6_confirm(reply, packet); break; case DHCPV6_RENEW: dhcpv6_renew(reply, packet); break; case DHCPV6_REBIND: dhcpv6_rebind(reply, packet); break; case DHCPV6_REPLY: dhcpv6_discard(packet); break; case DHCPV6_RELEASE: dhcpv6_release(reply, packet); break; case DHCPV6_DECLINE: dhcpv6_decline(reply, packet); break; case DHCPV6_RECONFIGURE: dhcpv6_discard(packet); break; case DHCPV6_INFORMATION_REQUEST: dhcpv6_information_request(reply, packet); break; case DHCPV6_RELAY_FORW: dhcpv6_relay_forw(reply, packet); break; case DHCPV6_RELAY_REPL: dhcpv6_discard(packet); break; case DHCPV6_LEASEQUERY: dhcpv6_leasequery(reply, packet); break; case DHCPV6_LEASEQUERY_REPLY: dhcpv6_discard(packet); break; default: /* XXX: would be nice if we had "notice" level, as syslog, for this */ log_info("Discarding unknown DHCPv6 message type %d " "from %s", packet->dhcpv6_msg_type, piaddr(packet->client_addr)); } } static void log_packet_in(const struct packet *packet) { struct data_string s; u_int32_t tid; char tmp_addr[INET6_ADDRSTRLEN]; const void *addr; memset(&s, 0, sizeof(s)); if (packet->dhcpv6_msg_type < dhcpv6_type_name_max) { data_string_sprintfa(&s, "%s message from %s port %d", dhcpv6_type_names[packet->dhcpv6_msg_type], piaddr(packet->client_addr), ntohs(packet->client_port)); } else { data_string_sprintfa(&s, "Unknown message type %d from %s port %d", packet->dhcpv6_msg_type, piaddr(packet->client_addr), ntohs(packet->client_port)); } if ((packet->dhcpv6_msg_type == DHCPV6_RELAY_FORW) || (packet->dhcpv6_msg_type == DHCPV6_RELAY_REPL)) { addr = &packet->dhcpv6_link_address; data_string_sprintfa(&s, ", link address %s", inet_ntop(AF_INET6, addr, tmp_addr, sizeof(tmp_addr))); addr = &packet->dhcpv6_peer_address; data_string_sprintfa(&s, ", peer address %s", inet_ntop(AF_INET6, addr, tmp_addr, sizeof(tmp_addr))); } else { tid = 0; memcpy(((char *)&tid)+1, packet->dhcpv6_transaction_id, 3); data_string_sprintfa(&s, ", transaction ID 0x%06X", tid); /* oc = lookup_option(&dhcpv6_universe, packet->options, D6O_CLIENTID); if (oc != NULL) { memset(&tmp_ds, 0, sizeof(tmp_ds_)); if (!evaluate_option_cache(&tmp_ds, packet, NULL, NULL, packet->options, NULL, &global_scope, oc, MDL)) { log_error("Error evaluating Client Identifier"); } else { data_strint_sprintf(&s, ", client ID %s", data_string_forget(&tmp_ds, MDL); } } */ } log_info("%s", s.data); data_string_forget(&s, MDL); } void dhcpv6(struct packet *packet) { struct data_string reply; struct sockaddr_in6 to_addr; int send_ret; /* * Log a message that we received this packet. */ log_packet_in(packet); /* * Build our reply packet. */ build_dhcpv6_reply(&reply, packet); if (reply.data != NULL) { /* * Send our reply, if we have one. */ memset(&to_addr, 0, sizeof(to_addr)); to_addr.sin6_family = AF_INET6; if ((packet->dhcpv6_msg_type == DHCPV6_RELAY_FORW) || (packet->dhcpv6_msg_type == DHCPV6_RELAY_REPL)) { to_addr.sin6_port = local_port; } else { to_addr.sin6_port = remote_port; } #if defined (REPLY_TO_SOURCE_PORT) /* * This appears to have been included for testing so we would * not need a root client, but was accidently left in the * final code. We continue to include it in case * some users have come to rely upon it, but leave * it off by default as it's a bad idea. */ to_addr.sin6_port = packet->client_port; #endif memcpy(&to_addr.sin6_addr, packet->client_addr.iabuf, sizeof(to_addr.sin6_addr)); log_info("Sending %s to %s port %d", dhcpv6_type_names[reply.data[0]], piaddr(packet->client_addr), ntohs(to_addr.sin6_port)); send_ret = send_packet6(packet->interface, reply.data, reply.len, &to_addr); if (send_ret != reply.len) { log_error("dhcpv6: send_packet6() sent %d of %d bytes", send_ret, reply.len); } data_string_forget(&reply, MDL); } } static void seek_shared_host(struct host_decl **hp, struct shared_network *shared) { struct host_decl *nofixed = NULL; struct host_decl *seek, *hold = NULL; /* * Seek forward through fixed addresses for the right link. * * Note: how to do this for fixed prefixes??? */ host_reference(&hold, *hp, MDL); host_dereference(hp, MDL); seek = hold; while (seek != NULL) { if (seek->fixed_addr == NULL) nofixed = seek; else if (fixed_matches_shared(seek, shared)) break; seek = seek->n_ipaddr; } if ((seek == NULL) && (nofixed != NULL)) seek = nofixed; if (seek != NULL) host_reference(hp, seek, MDL); } static isc_boolean_t fixed_matches_shared(struct host_decl *host, struct shared_network *shared) { struct subnet *subnet; struct data_string addr; isc_boolean_t matched; struct iaddr fixed; if (host->fixed_addr == NULL) return ISC_FALSE; memset(&addr, 0, sizeof(addr)); if (!evaluate_option_cache(&addr, NULL, NULL, NULL, NULL, NULL, &global_scope, host->fixed_addr, MDL)) return ISC_FALSE; if (addr.len < 16) { data_string_forget(&addr, MDL); return ISC_FALSE; } fixed.len = 16; memcpy(fixed.iabuf, addr.data, 16); matched = ISC_FALSE; for (subnet = shared->subnets ; subnet != NULL ; subnet = subnet->next_sibling) { if (addr_eq(subnet_number(fixed, subnet->netmask), subnet->net)) { matched = ISC_TRUE; break; } } data_string_forget(&addr, MDL); return matched; } /* * find_host_by_duid_chaddr() synthesizes a DHCPv4-like 'hardware' * parameter from a DHCPv6 supplied DUID (client-identifier option), * and may seek to use client or relay supplied hardware addresses. */ static int find_hosts_by_duid_chaddr(struct host_decl **host, const struct data_string *client_id) { static int once_htype; int htype, hlen; const unsigned char *chaddr; /* * The DUID-LL and DUID-LLT must have a 2-byte DUID type and 2-byte * htype. */ if (client_id->len < 4) return 0; /* * The third and fourth octets of the DUID-LL and DUID-LLT * is the hardware type, but in 16 bits. */ htype = getUShort(client_id->data + 2); hlen = 0; chaddr = NULL; /* The first two octets of the DUID identify the type. */ switch(getUShort(client_id->data)) { case DUID_LLT: if (client_id->len > 8) { hlen = client_id->len - 8; chaddr = client_id->data + 8; } break; case DUID_LL: /* * Note that client_id->len must be greater than or equal * to four to get to this point in the function. */ hlen = client_id->len - 4; chaddr = client_id->data + 4; break; default: break; } if (hlen == 0) return 0; /* * XXX: DHCPv6 gives a 16-bit field for the htype. DHCPv4 gives an * 8-bit field. To change the semantics of the generic 'hardware' * structure, we would have to adjust many DHCPv4 sources (from * interface to DHCPv4 lease code), and we would have to update the * 'hardware' config directive (probably being reverse compatible and * providing a new upgrade/replacement primitive). This is a little * too much to change for now. Hopefully we will revisit this before * hardware types exceeding 8 bits are assigned. */ if ((htype & 0xFF00) && !once_htype) { once_htype = 1; log_error("Attention: At least one client advertises a " "hardware type of %d, which exceeds the software " "limitation of 255.", htype); } return find_hosts_by_haddr(host, htype, chaddr, hlen, MDL); } #endif /* DHCPv6 */ dhcp-4.2.4/server/failover.c000644 000765 000024 00000554340 11731731535 015671 0ustar00sarstaff000000 000000 /* failover.c Failover protocol support code... */ /* * Copyright (c) 2004-2012 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1999-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ * * This software has been written for Internet Systems Consortium * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. * To learn more about Internet Systems Consortium, see * ``https://www.isc.org/''. To learn more about Vixie Enterprises, * see ``http://www.vix.com''. To learn more about Nominum, Inc., see * ``http://www.nominum.com''. */ #include "cdefs.h" #include "dhcpd.h" #include #if defined (FAILOVER_PROTOCOL) dhcp_failover_state_t *failover_states; static isc_result_t do_a_failover_option (omapi_object_t *, dhcp_failover_link_t *); dhcp_failover_listener_t *failover_listeners; static isc_result_t failover_message_reference (failover_message_t **, failover_message_t *, const char *file, int line); static isc_result_t failover_message_dereference (failover_message_t **, const char *file, int line); static void dhcp_failover_pool_balance(dhcp_failover_state_t *state); static void dhcp_failover_pool_reqbalance(dhcp_failover_state_t *state); static int dhcp_failover_pool_dobalance(dhcp_failover_state_t *state, isc_boolean_t *sendreq); static inline int secondary_not_hoarding(dhcp_failover_state_t *state, struct pool *p); void dhcp_failover_startup () { dhcp_failover_state_t *state; isc_result_t status; struct timeval tv; for (state = failover_states; state; state = state -> next) { dhcp_failover_state_transition (state, "startup"); if (state -> pool_count == 0) { log_error ("failover peer declaration with no %s", "referring pools."); log_error ("In order to use failover, you MUST %s", "refer to your main failover declaration"); log_error ("in each pool declaration. You MUST %s", "NOT use range declarations outside"); log_fatal ("of pool declarations."); } /* In case the peer is already running, immediately try to establish a connection with it. */ status = dhcp_failover_link_initiate ((omapi_object_t *)state); if (status != ISC_R_SUCCESS && status != DHCP_R_INCOMPLETE) { #if defined (DEBUG_FAILOVER_TIMING) log_info ("add_timeout +90 dhcp_failover_reconnect"); #endif tv . tv_sec = cur_time + 90; tv . tv_usec = 0; add_timeout (&tv, dhcp_failover_reconnect, state, (tvref_t) dhcp_failover_state_reference, (tvunref_t) dhcp_failover_state_dereference); log_error ("failover peer %s: %s", state -> name, isc_result_totext (status)); } status = (dhcp_failover_listen ((omapi_object_t *)state)); if (status != ISC_R_SUCCESS) { #if defined (DEBUG_FAILOVER_TIMING) log_info ("add_timeout +90 %s", "dhcp_failover_listener_restart"); #endif tv . tv_sec = cur_time + 90; tv . tv_usec = 0; add_timeout (&tv, dhcp_failover_listener_restart, state, (tvref_t)omapi_object_reference, (tvunref_t)omapi_object_dereference); } } } int dhcp_failover_write_all_states () { dhcp_failover_state_t *state; for (state = failover_states; state; state = state -> next) { if (!write_failover_state (state)) return 0; } return 1; } isc_result_t enter_failover_peer (peer) dhcp_failover_state_t *peer; { dhcp_failover_state_t *dup = (dhcp_failover_state_t *)0; isc_result_t status; status = find_failover_peer (&dup, peer -> name, MDL); if (status == ISC_R_NOTFOUND) { if (failover_states) { dhcp_failover_state_reference (&peer -> next, failover_states, MDL); dhcp_failover_state_dereference (&failover_states, MDL); } dhcp_failover_state_reference (&failover_states, peer, MDL); return ISC_R_SUCCESS; } dhcp_failover_state_dereference (&dup, MDL); if (status == ISC_R_SUCCESS) return ISC_R_EXISTS; return status; } isc_result_t find_failover_peer (peer, name, file, line) dhcp_failover_state_t **peer; const char *name; const char *file; int line; { dhcp_failover_state_t *p; for (p = failover_states; p; p = p -> next) if (!strcmp (name, p -> name)) break; if (p) return dhcp_failover_state_reference (peer, p, file, line); return ISC_R_NOTFOUND; } /* The failover protocol has three objects associated with it. For each failover partner declaration in the dhcpd.conf file, primary or secondary, there is a failover_state object. For any primary or secondary state object that has a connection to its peer, there is also a failover_link object, which has its own input state separate from the failover protocol state for managing the actual bytes coming in off the wire. Finally, there will be one listener object for every distinct port number associated with a secondary failover_state object. Normally all secondary failover_state objects are expected to listen on the same port number, so there need be only one listener object, but if different port numbers are specified for each failover object, there could be as many as one listener object for each secondary failover_state object. */ /* This, then, is the implementation of the failover link object. */ isc_result_t dhcp_failover_link_initiate (omapi_object_t *h) { isc_result_t status; dhcp_failover_link_t *obj; dhcp_failover_state_t *state; omapi_object_t *o; int i; struct data_string ds; omapi_addr_list_t *addrs = (omapi_addr_list_t *)0; omapi_addr_t local_addr; /* Find the failover state in the object chain. */ for (o = h; o -> outer; o = o -> outer) ; for (; o; o = o -> inner) { if (o -> type == dhcp_type_failover_state) break; } if (!o) return DHCP_R_INVALIDARG; state = (dhcp_failover_state_t *)o; obj = (dhcp_failover_link_t *)0; status = dhcp_failover_link_allocate (&obj, MDL); if (status != ISC_R_SUCCESS) return status; option_cache_reference (&obj -> peer_address, state -> partner.address, MDL); obj -> peer_port = state -> partner.port; dhcp_failover_state_reference (&obj -> state_object, state, MDL); memset (&ds, 0, sizeof ds); if (!evaluate_option_cache (&ds, (struct packet *)0, (struct lease *)0, (struct client_state *)0, (struct option_state *)0, (struct option_state *)0, &global_scope, obj -> peer_address, MDL)) { dhcp_failover_link_dereference (&obj, MDL); return ISC_R_UNEXPECTED; } /* Make an omapi address list out of a buffer containing zero or more IPv4 addresses. */ status = omapi_addr_list_new (&addrs, ds.len / 4, MDL); if (status != ISC_R_SUCCESS) { dhcp_failover_link_dereference (&obj, MDL); return status; } for (i = 0; i < addrs -> count; i++) { addrs -> addresses [i].addrtype = AF_INET; addrs -> addresses [i].addrlen = sizeof (struct in_addr); memcpy (addrs -> addresses [i].address, &ds.data [i * 4], sizeof (struct in_addr)); addrs -> addresses [i].port = obj -> peer_port; } data_string_forget (&ds, MDL); /* Now figure out the local address that we're supposed to use. */ if (!state -> me.address || !evaluate_option_cache (&ds, (struct packet *)0, (struct lease *)0, (struct client_state *)0, (struct option_state *)0, (struct option_state *)0, &global_scope, state -> me.address, MDL)) { memset (&local_addr, 0, sizeof local_addr); local_addr.addrtype = AF_INET; local_addr.addrlen = sizeof (struct in_addr); if (!state -> server_identifier.len) { log_fatal ("failover peer %s: no local address.", state -> name); } } else { if (ds.len != sizeof (struct in_addr)) { log_error("failover peer %s: 'address' parameter " "fails to resolve to an IPv4 address", state->name); data_string_forget (&ds, MDL); dhcp_failover_link_dereference (&obj, MDL); omapi_addr_list_dereference (&addrs, MDL); return DHCP_R_INVALIDARG; } local_addr.addrtype = AF_INET; local_addr.addrlen = ds.len; memcpy (local_addr.address, ds.data, ds.len); if (!state -> server_identifier.len) data_string_copy (&state -> server_identifier, &ds, MDL); data_string_forget (&ds, MDL); local_addr.port = 0; /* Let the O.S. choose. */ } status = omapi_connect_list ((omapi_object_t *)obj, addrs, &local_addr); omapi_addr_list_dereference (&addrs, MDL); dhcp_failover_link_dereference (&obj, MDL); return status; } isc_result_t dhcp_failover_link_signal (omapi_object_t *h, const char *name, va_list ap) { isc_result_t status; dhcp_failover_link_t *link; omapi_object_t *c; dhcp_failover_state_t *s, *state = (dhcp_failover_state_t *)0; char *sname; int slen; struct timeval tv; if (h -> type != dhcp_type_failover_link) { /* XXX shouldn't happen. Put an assert here? */ return ISC_R_UNEXPECTED; } link = (dhcp_failover_link_t *)h; if (!strcmp (name, "connect")) { if (link -> state_object -> i_am == primary) { status = dhcp_failover_send_connect (h); if (status != ISC_R_SUCCESS) { log_info ("dhcp_failover_send_connect: %s", isc_result_totext (status)); omapi_disconnect (h -> outer, 1); } } else status = ISC_R_SUCCESS; /* Allow the peer fifteen seconds to send us a startup message. */ #if defined (DEBUG_FAILOVER_TIMING) log_info ("add_timeout +15 %s", "dhcp_failover_link_startup_timeout"); #endif tv . tv_sec = cur_time + 15; tv . tv_usec = 0; add_timeout (&tv, dhcp_failover_link_startup_timeout, link, (tvref_t)dhcp_failover_link_reference, (tvunref_t)dhcp_failover_link_dereference); return status; } if (!strcmp (name, "disconnect")) { if (link -> state_object) { dhcp_failover_state_reference (&state, link -> state_object, MDL); link -> state = dhcp_flink_disconnected; /* Make the transition. */ if (state->link_to_peer == link) dhcp_failover_state_transition(link->state_object, name); /* Schedule an attempt to reconnect. */ #if defined (DEBUG_FAILOVER_TIMING) log_info("add_timeout +5 dhcp_failover_reconnect"); #endif tv.tv_sec = cur_time + 5; tv.tv_usec = cur_tv.tv_usec; add_timeout(&tv, dhcp_failover_reconnect, state, (tvref_t)dhcp_failover_state_reference, (tvunref_t)dhcp_failover_state_dereference); dhcp_failover_state_dereference (&state, MDL); } return ISC_R_SUCCESS; } if (!strcmp (name, "status")) { if (link -> state_object) { isc_result_t status; status = va_arg(ap, isc_result_t); if ((status == ISC_R_HOSTUNREACH) || (status == ISC_R_TIMEDOUT)) { dhcp_failover_state_reference (&state, link -> state_object, MDL); link -> state = dhcp_flink_disconnected; /* Make the transition. */ dhcp_failover_state_transition (link -> state_object, "disconnect"); /* Start trying to reconnect. */ #if defined (DEBUG_FAILOVER_TIMING) log_info ("add_timeout +5 %s", "dhcp_failover_reconnect"); #endif tv . tv_sec = cur_time + 5; tv . tv_usec = 0; add_timeout (&tv, dhcp_failover_reconnect, state, (tvref_t)dhcp_failover_state_reference, (tvunref_t)dhcp_failover_state_dereference); } dhcp_failover_state_dereference (&state, MDL); } return ISC_R_SUCCESS; } /* Not a signal we recognize? */ if (strcmp (name, "ready")) { if (h -> inner && h -> inner -> type -> signal_handler) return (*(h -> inner -> type -> signal_handler)) (h -> inner, name, ap); return ISC_R_NOTFOUND; } if (!h -> outer || h -> outer -> type != omapi_type_connection) return DHCP_R_INVALIDARG; c = h -> outer; /* We get here because we requested that we be woken up after some number of bytes were read, and that number of bytes has in fact been read. */ switch (link -> state) { case dhcp_flink_start: link -> state = dhcp_flink_message_length_wait; if ((omapi_connection_require (c, 2)) != ISC_R_SUCCESS) break; case dhcp_flink_message_length_wait: next_message: link -> state = dhcp_flink_message_wait; link -> imsg = dmalloc (sizeof (failover_message_t), MDL); if (!link -> imsg) { status = ISC_R_NOMEMORY; dhcp_flink_fail: if (link -> imsg) { failover_message_dereference (&link->imsg, MDL); } link -> state = dhcp_flink_disconnected; log_info ("message length wait: %s", isc_result_totext (status)); omapi_disconnect (c, 1); /* XXX just blow away the protocol state now? XXX or will disconnect blow it away? */ return ISC_R_UNEXPECTED; } memset (link -> imsg, 0, sizeof (failover_message_t)); link -> imsg -> refcnt = 1; /* Get the length: */ omapi_connection_get_uint16 (c, &link -> imsg_len); link -> imsg_count = 0; /* Bytes read. */ /* Ensure the message is of valid length. */ if (link->imsg_len < DHCP_FAILOVER_MIN_MESSAGE_SIZE || link->imsg_len > DHCP_FAILOVER_MAX_MESSAGE_SIZE) { status = ISC_R_UNEXPECTED; goto dhcp_flink_fail; } if ((omapi_connection_require (c, link -> imsg_len - 2U)) != ISC_R_SUCCESS) break; case dhcp_flink_message_wait: /* Read in the message. At this point we have the entire message in the input buffer. For each incoming value ID, set a bit in the bitmask indicating that we've gotten it. Maybe flag an error message if the bit is already set. Once we're done reading, we can check the bitmask to make sure that the required fields for each message have been included. */ link -> imsg_count += 2; /* Count the length as read. */ /* Get message type. */ omapi_connection_copyout (&link -> imsg -> type, c, 1); link -> imsg_count++; /* Get message payload offset. */ omapi_connection_copyout (&link -> imsg_payoff, c, 1); link -> imsg_count++; /* Get message time. */ omapi_connection_get_uint32 (c, &link -> imsg -> time); link -> imsg_count += 4; /* Get transaction ID. */ omapi_connection_get_uint32 (c, &link -> imsg -> xid); link -> imsg_count += 4; #if defined (DEBUG_FAILOVER_MESSAGES) # if !defined(DEBUG_FAILOVER_CONTACT_MESSAGES) if (link->imsg->type == FTM_CONTACT) goto skip_contact; # endif log_info ("link: message %s payoff %d time %ld xid %ld", dhcp_failover_message_name (link -> imsg -> type), link -> imsg_payoff, (unsigned long)link -> imsg -> time, (unsigned long)link -> imsg -> xid); # if !defined(DEBUG_FAILOVER_CONTACT_MESSAGES) skip_contact: # endif #endif /* Skip over any portions of the message header that we don't understand. */ if (link -> imsg_payoff - link -> imsg_count) { omapi_connection_copyout ((unsigned char *)0, c, (link -> imsg_payoff - link -> imsg_count)); link -> imsg_count = link -> imsg_payoff; } /* Now start sucking options off the wire. */ while (link -> imsg_count < link -> imsg_len) { status = do_a_failover_option (c, link); if (status != ISC_R_SUCCESS) goto dhcp_flink_fail; } /* If it's a connect message, try to associate it with a state object. */ /* XXX this should be authenticated! */ if (link -> imsg -> type == FTM_CONNECT) { const char *errmsg; int reason; if (!(link->imsg->options_present & FTB_RELATIONSHIP_NAME)) { errmsg = "missing relationship-name"; reason = FTR_INVALID_PARTNER; goto badconnect; } /* See if we can find a failover_state object that matches this connection. This message should only be received by a secondary from a primary. */ for (s = failover_states; s; s = s -> next) { if (dhcp_failover_state_match_by_name(s, &link->imsg->relationship_name)) state = s; } /* If we can't find a failover protocol state for this remote host, drop the connection */ if (!state) { errmsg = "unknown failover relationship name"; reason = FTR_INVALID_PARTNER; badconnect: /* XXX Send a refusal message first? XXX Look in protocol spec for guidance. */ if (state != NULL) { sname = state->name; slen = strlen(sname); } else if (link->imsg->options_present & FTB_RELATIONSHIP_NAME) { sname = (char *)link->imsg-> relationship_name.data; slen = link->imsg->relationship_name.count; } else { sname = "unknown"; slen = strlen(sname); } log_error("Failover CONNECT from %.*s: %s", slen, sname, errmsg); dhcp_failover_send_connectack ((omapi_object_t *)link, state, reason, errmsg); log_info ("failover: disconnect: %s", errmsg); omapi_disconnect (c, 0); link -> state = dhcp_flink_disconnected; return ISC_R_SUCCESS; } if ((cur_time > link -> imsg -> time && cur_time - link -> imsg -> time > 60) || (cur_time < link -> imsg -> time && link -> imsg -> time - cur_time > 60)) { errmsg = "time offset too large"; reason = FTR_TIMEMISMATCH; goto badconnect; } if (!(link -> imsg -> options_present & FTB_HBA) || link -> imsg -> hba.count != 32) { errmsg = "invalid HBA"; reason = FTR_HBA_CONFLICT; /* XXX */ goto badconnect; } if (state -> hba) dfree (state -> hba, MDL); state -> hba = dmalloc (32, MDL); if (!state -> hba) { errmsg = "no memory"; reason = FTR_MISC_REJECT; goto badconnect; } memcpy (state -> hba, link -> imsg -> hba.data, 32); if (!link -> state_object) dhcp_failover_state_reference (&link -> state_object, state, MDL); if (!link -> peer_address) option_cache_reference (&link -> peer_address, state -> partner.address, MDL); } /* If we don't have a state object at this point, it's some kind of bogus situation, so just drop the connection. */ if (!link -> state_object) { log_info ("failover: connect: no matching state."); omapi_disconnect (c, 1); link -> state = dhcp_flink_disconnected; return DHCP_R_INVALIDARG; } /* Once we have the entire message, and we've validated it as best we can here, pass it to the parent. */ omapi_signal ((omapi_object_t *)link -> state_object, "message", link); link -> state = dhcp_flink_message_length_wait; if (link -> imsg) failover_message_dereference (&link -> imsg, MDL); /* XXX This is dangerous because we could get into a tight XXX loop reading input without servicing any other stuff. XXX There needs to be a way to relinquish control but XXX get it back immediately if there's no other work to XXX do. */ if ((omapi_connection_require (c, 2)) == ISC_R_SUCCESS) goto next_message; break; default: log_fatal("Impossible case at %s:%d.", MDL); break; } return ISC_R_SUCCESS; } static isc_result_t do_a_failover_option (c, link) omapi_object_t *c; dhcp_failover_link_t *link; { u_int16_t option_code; u_int16_t option_len; unsigned char *op; unsigned op_size; unsigned op_count; int i; if (link -> imsg_count + 2 > link -> imsg_len) { log_error ("FAILOVER: message overflow at option code."); return DHCP_R_PROTOCOLERROR; } /* Get option code. */ omapi_connection_get_uint16 (c, &option_code); link -> imsg_count += 2; if (link -> imsg_count + 2 > link -> imsg_len) { log_error ("FAILOVER: message overflow at length."); return DHCP_R_PROTOCOLERROR; } /* Get option length. */ omapi_connection_get_uint16 (c, &option_len); link -> imsg_count += 2; if (link -> imsg_count + option_len > link -> imsg_len) { log_error ("FAILOVER: message overflow at data."); return DHCP_R_PROTOCOLERROR; } /* If it's an unknown code, skip over it. */ if ((option_code > FTO_MAX) || (ft_options[option_code].type == FT_UNDEF)) { #if defined (DEBUG_FAILOVER_MESSAGES) log_debug (" option code %d (%s) len %d (not recognized)", option_code, dhcp_failover_option_name (option_code), option_len); #endif omapi_connection_copyout ((unsigned char *)0, c, option_len); link -> imsg_count += option_len; return ISC_R_SUCCESS; } /* If it's the digest, do it now. */ if (ft_options [option_code].type == FT_DIGEST) { link -> imsg_count += option_len; if (link -> imsg_count != link -> imsg_len) { log_error ("FAILOVER: digest not at end of message"); return DHCP_R_PROTOCOLERROR; } #if defined (DEBUG_FAILOVER_MESSAGES) log_debug (" option %s len %d", ft_options [option_code].name, option_len); #endif /* For now, just dump it. */ omapi_connection_copyout ((unsigned char *)0, c, option_len); return ISC_R_SUCCESS; } /* Only accept an option once. */ if (link -> imsg -> options_present & ft_options [option_code].bit) { log_error ("FAILOVER: duplicate option %s", ft_options [option_code].name); return DHCP_R_PROTOCOLERROR; } /* Make sure the option is appropriate for this type of message. Really, any option is generally allowed for any message, and the cases where this is not true are too complicated to represent in this way - what this code is doing is to just avoid saving the value of an option we don't have any way to use, which allows us to make the failover_message structure smaller. */ if (ft_options [option_code].bit && !(fto_allowed [link -> imsg -> type] & ft_options [option_code].bit)) { omapi_connection_copyout ((unsigned char *)0, c, option_len); link -> imsg_count += option_len; return ISC_R_SUCCESS; } /* Figure out how many elements, how big they are, and where to store them. */ if (ft_options [option_code].num_present) { /* If this option takes a fixed number of elements, we expect the space for them to be preallocated, and we can just read the data in. */ op = ((unsigned char *)link -> imsg) + ft_options [option_code].offset; op_size = ft_sizes [ft_options [option_code].type]; op_count = ft_options [option_code].num_present; if (option_len != op_size * op_count) { log_error ("FAILOVER: option size (%d:%d), option %s", option_len, (ft_sizes [ft_options [option_code].type] * ft_options [option_code].num_present), ft_options [option_code].name); return DHCP_R_PROTOCOLERROR; } } else { failover_option_t *fo; /* FT_DDNS* are special - one or two bytes of status followed by the client FQDN. */ if (ft_options [option_code].type == FT_DDNS1 || ft_options [option_code].type == FT_DDNS1) { ddns_fqdn_t *ddns = ((ddns_fqdn_t *) (((char *)link -> imsg) + ft_options [option_code].offset)); op_count = (ft_options [option_code].type == FT_DDNS1 ? 1 : 2); omapi_connection_copyout (&ddns -> codes [0], c, op_count); link -> imsg_count += op_count; if (op_count == 1) ddns -> codes [1] = 0; op_size = 1; op_count = option_len - op_count; ddns -> length = op_count; ddns -> data = dmalloc (op_count, MDL); if (!ddns -> data) { log_error ("FAILOVER: no memory getting%s(%d)", " DNS data ", op_count); /* Actually, NO_MEMORY, but if we lose here we have to drop the connection. */ return DHCP_R_PROTOCOLERROR; } omapi_connection_copyout (ddns -> data, c, op_count); goto out; } /* A zero for num_present means that any number of elements can appear, so we have to figure out how many we got from the length of the option, and then fill out a failover_option structure describing the data. */ op_size = ft_sizes [ft_options [option_code].type]; /* Make sure that option data length is a multiple of the size of the data type being sent. */ if (op_size > 1 && option_len % op_size) { log_error ("FAILOVER: option_len %d not %s%d", option_len, "multiple of ", op_size); return DHCP_R_PROTOCOLERROR; } op_count = option_len / op_size; fo = ((failover_option_t *) (((char *)link -> imsg) + ft_options [option_code].offset)); fo -> count = op_count; fo -> data = dmalloc (option_len, MDL); if (!fo -> data) { log_error ("FAILOVER: no memory getting %s (%d)", "option data", op_count); return DHCP_R_PROTOCOLERROR; } op = fo -> data; } /* For single-byte message values and multi-byte values that don't need swapping, just read them in all at once. */ if (op_size == 1 || ft_options [option_code].type == FT_IPADDR) { omapi_connection_copyout ((unsigned char *)op, c, option_len); link -> imsg_count += option_len; /* * As of 3.1.0, many option codes were changed to conform to * draft revision 12 (which alphabetized, then renumbered all * the option codes without preserving the version option code * nor bumping its value). As it turns out, the message codes * for CONNECT and CONNECTACK turn out the same, so it tries * its darndest to connect, and falls short (when TLS_REQUEST * comes up size 2 rather than size 1 as draft revision 12 also * mandates). * * The VENDOR_CLASS code in 3.0.x was 11, which is now the HBA * code. Both work out to be arbitrarily long text-or-byte * strings, so they pass parsing. * * Note that it is possible (or intentional), if highly * improbable, for the HBA bit array to exactly match * isc-V3.0.x. Warning here is not an issue; if it really is * 3.0.x, there will be a protocol error later on. If it isn't * actually 3.0.x, then I guess the lucky user will have to * live with a weird warning. */ if ((option_code == 11) && (option_len > 9) && (strncmp((const char *)op, "isc-V3.0.", 9) == 0)) { log_error("WARNING: failover as of versions 3.1.0 and " "on are not reverse compatible with " "versions 3.0.x."); } goto out; } /* For values that require swapping, read them in one at a time using routines that swap bytes. */ for (i = 0; i < op_count; i++) { switch (ft_options [option_code].type) { case FT_UINT32: omapi_connection_get_uint32 (c, (u_int32_t *)op); op += 4; link -> imsg_count += 4; break; case FT_UINT16: omapi_connection_get_uint16 (c, (u_int16_t *)op); op += 2; link -> imsg_count += 2; break; default: /* Everything else should have been handled already. */ log_error ("FAILOVER: option %s: bad type %d", ft_options [option_code].name, ft_options [option_code].type); return DHCP_R_PROTOCOLERROR; } } out: /* Remember that we got this option. */ link -> imsg -> options_present |= ft_options [option_code].bit; return ISC_R_SUCCESS; } isc_result_t dhcp_failover_link_set_value (omapi_object_t *h, omapi_object_t *id, omapi_data_string_t *name, omapi_typed_data_t *value) { if (h -> type != omapi_type_protocol) return DHCP_R_INVALIDARG; /* Never valid to set these. */ if (!omapi_ds_strcmp (name, "link-port") || !omapi_ds_strcmp (name, "link-name") || !omapi_ds_strcmp (name, "link-state")) return ISC_R_NOPERM; if (h -> inner && h -> inner -> type -> set_value) return (*(h -> inner -> type -> set_value)) (h -> inner, id, name, value); return ISC_R_NOTFOUND; } isc_result_t dhcp_failover_link_get_value (omapi_object_t *h, omapi_object_t *id, omapi_data_string_t *name, omapi_value_t **value) { dhcp_failover_link_t *link; if (h -> type != omapi_type_protocol) return DHCP_R_INVALIDARG; link = (dhcp_failover_link_t *)h; if (!omapi_ds_strcmp (name, "link-port")) { return omapi_make_int_value (value, name, (int)link -> peer_port, MDL); } else if (!omapi_ds_strcmp (name, "link-state")) { if (link -> state < 0 || link -> state >= dhcp_flink_state_max) return omapi_make_string_value (value, name, "invalid link state", MDL); return omapi_make_string_value (value, name, dhcp_flink_state_names [link -> state], MDL); } if (h -> inner && h -> inner -> type -> get_value) return (*(h -> inner -> type -> get_value)) (h -> inner, id, name, value); return ISC_R_NOTFOUND; } isc_result_t dhcp_failover_link_destroy (omapi_object_t *h, const char *file, int line) { dhcp_failover_link_t *link; if (h -> type != dhcp_type_failover_link) return DHCP_R_INVALIDARG; link = (dhcp_failover_link_t *)h; if (link -> peer_address) option_cache_dereference (&link -> peer_address, file, line); if (link -> imsg) failover_message_dereference (&link -> imsg, file, line); if (link -> state_object) dhcp_failover_state_dereference (&link -> state_object, file, line); return ISC_R_SUCCESS; } /* Write all the published values associated with the object through the specified connection. */ isc_result_t dhcp_failover_link_stuff_values (omapi_object_t *c, omapi_object_t *id, omapi_object_t *l) { dhcp_failover_link_t *link; isc_result_t status; if (l -> type != dhcp_type_failover_link) return DHCP_R_INVALIDARG; link = (dhcp_failover_link_t *)l; status = omapi_connection_put_name (c, "link-port"); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_put_uint32 (c, sizeof (int)); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_put_uint32 (c, link -> peer_port); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_put_name (c, "link-state"); if (status != ISC_R_SUCCESS) return status; if (link -> state < 0 || link -> state >= dhcp_flink_state_max) status = omapi_connection_put_string (c, "invalid link state"); else status = (omapi_connection_put_string (c, dhcp_flink_state_names [link -> state])); if (status != ISC_R_SUCCESS) return status; if (link -> inner && link -> inner -> type -> stuff_values) return (*(link -> inner -> type -> stuff_values)) (c, id, link -> inner); return ISC_R_SUCCESS; } /* Set up a listener for the omapi protocol. The handle stored points to a listener object, not a protocol object. */ isc_result_t dhcp_failover_listen (omapi_object_t *h) { isc_result_t status; dhcp_failover_listener_t *obj, *l; omapi_value_t *value = (omapi_value_t *)0; omapi_addr_t local_addr; unsigned long port; status = omapi_get_value_str (h, (omapi_object_t *)0, "local-port", &value); if (status != ISC_R_SUCCESS) return status; if (!value -> value) { omapi_value_dereference (&value, MDL); return DHCP_R_INVALIDARG; } status = omapi_get_int_value (&port, value -> value); omapi_value_dereference (&value, MDL); if (status != ISC_R_SUCCESS) return status; local_addr.port = port; status = omapi_get_value_str (h, (omapi_object_t *)0, "local-address", &value); if (status != ISC_R_SUCCESS) return status; if (!value -> value) { nogood: omapi_value_dereference (&value, MDL); return DHCP_R_INVALIDARG; } if (value -> value -> type != omapi_datatype_data || value -> value -> u.buffer.len != sizeof (struct in_addr)) goto nogood; memcpy (local_addr.address, value -> value -> u.buffer.value, value -> value -> u.buffer.len); local_addr.addrlen = value -> value -> u.buffer.len; local_addr.addrtype = AF_INET; omapi_value_dereference (&value, MDL); /* Are we already listening on this port and address? */ for (l = failover_listeners; l; l = l -> next) { if (l -> address.port == local_addr.port && l -> address.addrtype == local_addr.addrtype && l -> address.addrlen == local_addr.addrlen && !memcmp (l -> address.address, local_addr.address, local_addr.addrlen)) break; } /* Already listening. */ if (l) return ISC_R_SUCCESS; obj = (dhcp_failover_listener_t *)0; status = dhcp_failover_listener_allocate (&obj, MDL); if (status != ISC_R_SUCCESS) return status; obj -> address = local_addr; status = omapi_listen_addr ((omapi_object_t *)obj, &obj -> address, 1); if (status != ISC_R_SUCCESS) return status; status = omapi_object_reference (&h -> outer, (omapi_object_t *)obj, MDL); if (status != ISC_R_SUCCESS) { dhcp_failover_listener_dereference (&obj, MDL); return status; } status = omapi_object_reference (&obj -> inner, h, MDL); if (status != ISC_R_SUCCESS) { dhcp_failover_listener_dereference (&obj, MDL); return status; } /* Put this listener on the list. */ if (failover_listeners) { dhcp_failover_listener_reference (&obj -> next, failover_listeners, MDL); dhcp_failover_listener_dereference (&failover_listeners, MDL); } dhcp_failover_listener_reference (&failover_listeners, obj, MDL); return dhcp_failover_listener_dereference (&obj, MDL); } /* Signal handler for protocol listener - if we get a connect signal, create a new protocol connection, otherwise pass the signal down. */ isc_result_t dhcp_failover_listener_signal (omapi_object_t *o, const char *name, va_list ap) { isc_result_t status; omapi_connection_object_t *c; dhcp_failover_link_t *obj; dhcp_failover_listener_t *p; dhcp_failover_state_t *s, *state = (dhcp_failover_state_t *)0; if (!o || o -> type != dhcp_type_failover_listener) return DHCP_R_INVALIDARG; p = (dhcp_failover_listener_t *)o; /* Not a signal we recognize? */ if (strcmp (name, "connect")) { if (p -> inner && p -> inner -> type -> signal_handler) return (*(p -> inner -> type -> signal_handler)) (p -> inner, name, ap); return ISC_R_NOTFOUND; } c = va_arg (ap, omapi_connection_object_t *); if (!c || c -> type != omapi_type_connection) return DHCP_R_INVALIDARG; /* See if we can find a failover_state object that matches this connection. */ for (s = failover_states; s; s = s -> next) { if (dhcp_failover_state_match (s, (u_int8_t *)&c -> remote_addr.sin_addr, sizeof c -> remote_addr.sin_addr)) { state = s; break; } } if (!state) { log_info ("failover: listener: no matching state"); omapi_disconnect ((omapi_object_t *)c, 1); return(ISC_R_NOTFOUND); } obj = (dhcp_failover_link_t *)0; status = dhcp_failover_link_allocate (&obj, MDL); if (status != ISC_R_SUCCESS) return status; obj -> peer_port = ntohs (c -> remote_addr.sin_port); status = omapi_object_reference (&obj -> outer, (omapi_object_t *)c, MDL); if (status != ISC_R_SUCCESS) { lose: dhcp_failover_link_dereference (&obj, MDL); log_info ("failover: listener: picayune failure."); omapi_disconnect ((omapi_object_t *)c, 1); return status; } status = omapi_object_reference (&c -> inner, (omapi_object_t *)obj, MDL); if (status != ISC_R_SUCCESS) goto lose; status = dhcp_failover_state_reference (&obj -> state_object, state, MDL); if (status != ISC_R_SUCCESS) goto lose; omapi_signal_in ((omapi_object_t *)obj, "connect"); return dhcp_failover_link_dereference (&obj, MDL); } isc_result_t dhcp_failover_listener_set_value (omapi_object_t *h, omapi_object_t *id, omapi_data_string_t *name, omapi_typed_data_t *value) { if (h -> type != dhcp_type_failover_listener) return DHCP_R_INVALIDARG; if (h -> inner && h -> inner -> type -> set_value) return (*(h -> inner -> type -> set_value)) (h -> inner, id, name, value); return ISC_R_NOTFOUND; } isc_result_t dhcp_failover_listener_get_value (omapi_object_t *h, omapi_object_t *id, omapi_data_string_t *name, omapi_value_t **value) { if (h -> type != dhcp_type_failover_listener) return DHCP_R_INVALIDARG; if (h -> inner && h -> inner -> type -> get_value) return (*(h -> inner -> type -> get_value)) (h -> inner, id, name, value); return ISC_R_NOTFOUND; } isc_result_t dhcp_failover_listener_destroy (omapi_object_t *h, const char *file, int line) { dhcp_failover_listener_t *l; if (h -> type != dhcp_type_failover_listener) return DHCP_R_INVALIDARG; l = (dhcp_failover_listener_t *)h; if (l -> next) dhcp_failover_listener_dereference (&l -> next, file, line); return ISC_R_SUCCESS; } /* Write all the published values associated with the object through the specified connection. */ isc_result_t dhcp_failover_listener_stuff (omapi_object_t *c, omapi_object_t *id, omapi_object_t *p) { if (p -> type != dhcp_type_failover_listener) return DHCP_R_INVALIDARG; if (p -> inner && p -> inner -> type -> stuff_values) return (*(p -> inner -> type -> stuff_values)) (c, id, p -> inner); return ISC_R_SUCCESS; } /* Set up master state machine for the failover protocol. */ isc_result_t dhcp_failover_register (omapi_object_t *h) { isc_result_t status; dhcp_failover_state_t *obj; unsigned long port; omapi_value_t *value = (omapi_value_t *)0; status = omapi_get_value_str (h, (omapi_object_t *)0, "local-port", &value); if (status != ISC_R_SUCCESS) return status; if (!value -> value) { omapi_value_dereference (&value, MDL); return DHCP_R_INVALIDARG; } status = omapi_get_int_value (&port, value -> value); omapi_value_dereference (&value, MDL); if (status != ISC_R_SUCCESS) return status; obj = (dhcp_failover_state_t *)0; dhcp_failover_state_allocate (&obj, MDL); obj -> me.port = port; status = omapi_listen ((omapi_object_t *)obj, port, 1); if (status != ISC_R_SUCCESS) { dhcp_failover_state_dereference (&obj, MDL); return status; } status = omapi_object_reference (&h -> outer, (omapi_object_t *)obj, MDL); if (status != ISC_R_SUCCESS) { dhcp_failover_state_dereference (&obj, MDL); return status; } status = omapi_object_reference (&obj -> inner, h, MDL); dhcp_failover_state_dereference (&obj, MDL); return status; } /* Signal handler for protocol state machine. */ isc_result_t dhcp_failover_state_signal (omapi_object_t *o, const char *name, va_list ap) { isc_result_t status; dhcp_failover_state_t *state; dhcp_failover_link_t *link; struct timeval tv; if (!o || o -> type != dhcp_type_failover_state) return DHCP_R_INVALIDARG; state = (dhcp_failover_state_t *)o; /* Not a signal we recognize? */ if (strcmp (name, "disconnect") && strcmp (name, "message")) { if (state -> inner && state -> inner -> type -> signal_handler) return (*(state -> inner -> type -> signal_handler)) (state -> inner, name, ap); return ISC_R_NOTFOUND; } /* Handle connect signals by seeing what state we're in and potentially doing a state transition. */ if (!strcmp (name, "disconnect")) { link = va_arg (ap, dhcp_failover_link_t *); dhcp_failover_link_dereference (&state -> link_to_peer, MDL); dhcp_failover_state_transition (state, "disconnect"); if (state -> i_am == primary) { #if defined (DEBUG_FAILOVER_TIMING) log_info ("add_timeout +90 %s", "dhcp_failover_reconnect"); #endif tv . tv_sec = cur_time + 90; tv . tv_usec = 0; add_timeout (&tv, dhcp_failover_reconnect, state, (tvref_t)dhcp_failover_state_reference, (tvunref_t) dhcp_failover_state_dereference); } } else if (!strcmp (name, "message")) { link = va_arg (ap, dhcp_failover_link_t *); if (link -> imsg -> type == FTM_CONNECT) { /* If we already have a link to the peer, it must be dead, so drop it. XXX Is this the right thing to do? XXX Probably not - what if both peers start at XXX the same time? */ if (state -> link_to_peer) { dhcp_failover_send_connectack ((omapi_object_t *)link, state, FTR_DUP_CONNECTION, "already connected"); omapi_disconnect (link -> outer, 1); return ISC_R_SUCCESS; } if (!(link -> imsg -> options_present & FTB_MCLT)) { dhcp_failover_send_connectack ((omapi_object_t *)link, state, FTR_INVALID_MCLT, "no MCLT provided"); omapi_disconnect (link -> outer, 1); return ISC_R_SUCCESS; } dhcp_failover_link_reference (&state -> link_to_peer, link, MDL); status = (dhcp_failover_send_connectack ((omapi_object_t *)link, state, 0, 0)); if (status != ISC_R_SUCCESS) { dhcp_failover_link_dereference (&state -> link_to_peer, MDL); log_info ("dhcp_failover_send_connectack: %s", isc_result_totext (status)); omapi_disconnect (link -> outer, 1); return ISC_R_SUCCESS; } if (link -> imsg -> options_present & FTB_MAX_UNACKED) state -> partner.max_flying_updates = link -> imsg -> max_unacked; if (link -> imsg -> options_present & FTB_RECEIVE_TIMER) state -> partner.max_response_delay = link -> imsg -> receive_timer; state -> mclt = link -> imsg -> mclt; dhcp_failover_send_state (state); cancel_timeout (dhcp_failover_link_startup_timeout, link); } else if (link -> imsg -> type == FTM_CONNECTACK) { const char *errmsg; char errbuf[1024]; int reason; cancel_timeout (dhcp_failover_link_startup_timeout, link); if (!(link->imsg->options_present & FTB_RELATIONSHIP_NAME)) { errmsg = "missing relationship-name"; reason = FTR_INVALID_PARTNER; goto badconnectack; } if (link->imsg->options_present & FTB_REJECT_REASON) { /* XXX: add message option to text output. */ log_error ("Failover CONNECT to %s rejected: %s", state ? state->name : "unknown", (dhcp_failover_reject_reason_print (link -> imsg -> reject_reason))); /* XXX print message from peer if peer sent message. */ omapi_disconnect (link -> outer, 1); return ISC_R_SUCCESS; } if (!dhcp_failover_state_match_by_name(state, &link->imsg->relationship_name)) { /* XXX: Overflow results in log truncation, safe. */ snprintf(errbuf, sizeof(errbuf), "remote failover " "relationship name %.*s does not match", (int)link->imsg->relationship_name.count, link->imsg->relationship_name.data); errmsg = errbuf; reason = FTR_INVALID_PARTNER; badconnectack: log_error("Failover CONNECTACK from %s: %s", state->name, errmsg); dhcp_failover_send_disconnect ((omapi_object_t *)link, reason, errmsg); omapi_disconnect (link -> outer, 0); return ISC_R_SUCCESS; } if (state -> link_to_peer) { errmsg = "already connected"; reason = FTR_DUP_CONNECTION; goto badconnectack; } if ((cur_time > link -> imsg -> time && cur_time - link -> imsg -> time > 60) || (cur_time < link -> imsg -> time && link -> imsg -> time - cur_time > 60)) { errmsg = "time offset too large"; reason = FTR_TIMEMISMATCH; goto badconnectack; } dhcp_failover_link_reference (&state -> link_to_peer, link, MDL); #if 0 /* XXX This is probably the right thing to do, but XXX for release three, to make the smallest possible XXX change, we are doing this when the peer state XXX changes instead. */ if (state -> me.state == startup) dhcp_failover_set_state (state, state -> saved_state); else #endif dhcp_failover_send_state (state); if (link -> imsg -> options_present & FTB_MAX_UNACKED) state -> partner.max_flying_updates = link -> imsg -> max_unacked; if (link -> imsg -> options_present & FTB_RECEIVE_TIMER) state -> partner.max_response_delay = link -> imsg -> receive_timer; #if defined (DEBUG_FAILOVER_CONTACT_TIMING) log_info ("add_timeout +%d %s", (int)state -> partner.max_response_delay / 3, "dhcp_failover_send_contact"); #endif tv . tv_sec = cur_time + (int)state -> partner.max_response_delay / 3; tv . tv_usec = 0; add_timeout (&tv, dhcp_failover_send_contact, state, (tvref_t)dhcp_failover_state_reference, (tvunref_t)dhcp_failover_state_dereference); #if defined (DEBUG_FAILOVER_CONTACT_TIMING) log_info ("add_timeout +%d %s", (int)state -> me.max_response_delay, "dhcp_failover_timeout"); #endif tv . tv_sec = cur_time + (int)state -> me.max_response_delay; tv . tv_usec = 0; add_timeout (&tv, dhcp_failover_timeout, state, (tvref_t)dhcp_failover_state_reference, (tvunref_t)dhcp_failover_state_dereference); } else if (link -> imsg -> type == FTM_DISCONNECT) { if (link -> imsg -> reject_reason) { log_error ("Failover DISCONNECT from %s: %s", state ? state->name : "unknown", (dhcp_failover_reject_reason_print (link -> imsg -> reject_reason))); } omapi_disconnect (link -> outer, 1); } else if (link -> imsg -> type == FTM_BNDUPD) { dhcp_failover_process_bind_update (state, link -> imsg); } else if (link -> imsg -> type == FTM_BNDACK) { dhcp_failover_process_bind_ack (state, link -> imsg); } else if (link -> imsg -> type == FTM_UPDREQ) { dhcp_failover_process_update_request (state, link -> imsg); } else if (link -> imsg -> type == FTM_UPDREQALL) { dhcp_failover_process_update_request_all (state, link -> imsg); } else if (link -> imsg -> type == FTM_UPDDONE) { dhcp_failover_process_update_done (state, link -> imsg); } else if (link -> imsg -> type == FTM_POOLREQ) { dhcp_failover_pool_reqbalance(state); } else if (link -> imsg -> type == FTM_POOLRESP) { log_info ("pool response: %ld leases", (unsigned long) link -> imsg -> addresses_transferred); } else if (link -> imsg -> type == FTM_STATE) { dhcp_failover_peer_state_changed (state, link -> imsg); } /* Add a timeout so that if the partner doesn't send another message for the maximum transmit idle time plus a grace of one second, we close the connection. */ if (state -> link_to_peer && state -> link_to_peer == link && state -> link_to_peer -> state != dhcp_flink_disconnected) { #if defined (DEBUG_FAILOVER_CONTACT_TIMING) log_info ("add_timeout +%d %s", (int)state -> me.max_response_delay, "dhcp_failover_timeout"); #endif tv . tv_sec = cur_time + (int)state -> me.max_response_delay; tv . tv_usec = 0; add_timeout (&tv, dhcp_failover_timeout, state, (tvref_t)dhcp_failover_state_reference, (tvunref_t)dhcp_failover_state_dereference); } } /* Handle all the events we care about... */ return ISC_R_SUCCESS; } isc_result_t dhcp_failover_state_transition (dhcp_failover_state_t *state, const char *name) { isc_result_t status; /* XXX Check these state transitions against the spec! */ if (!strcmp (name, "disconnect")) { if (state -> link_to_peer) { log_info ("peer %s: disconnected", state -> name); if (state -> link_to_peer -> state_object) dhcp_failover_state_dereference (&state -> link_to_peer -> state_object, MDL); dhcp_failover_link_dereference (&state -> link_to_peer, MDL); } cancel_timeout (dhcp_failover_send_contact, state); cancel_timeout (dhcp_failover_timeout, state); cancel_timeout (dhcp_failover_startup_timeout, state); switch (state -> me.state == startup ? state -> saved_state : state -> me.state) { /* In these situations, we remain in the current * state, or if in startup enter those states. */ case communications_interrupted: case conflict_done: case partner_down: case paused: case recover: case recover_done: case recover_wait: case resolution_interrupted: case shut_down: /* Already in the right state? */ if (state -> me.state == startup) return (dhcp_failover_set_state (state, state -> saved_state)); return ISC_R_SUCCESS; case potential_conflict: return dhcp_failover_set_state (state, resolution_interrupted); case normal: return dhcp_failover_set_state (state, communications_interrupted); case unknown_state: return dhcp_failover_set_state (state, resolution_interrupted); default: log_fatal("Impossible case at %s:%d.", MDL); break; /* can't happen. */ } } else if (!strcmp (name, "connect")) { switch (state -> me.state) { case communications_interrupted: status = dhcp_failover_set_state (state, normal); dhcp_failover_send_updates (state); return status; case resolution_interrupted: return dhcp_failover_set_state (state, potential_conflict); case conflict_done: case partner_down: case potential_conflict: case normal: case recover: case shut_down: case paused: case unknown_state: case recover_done: case startup: case recover_wait: return dhcp_failover_send_state (state); default: log_fatal("Impossible case at %s:%d.", MDL); break; } } else if (!strcmp (name, "startup")) { dhcp_failover_set_state (state, startup); return ISC_R_SUCCESS; } else if (!strcmp (name, "connect-timeout")) { switch (state -> me.state) { case communications_interrupted: case partner_down: case resolution_interrupted: case paused: case startup: case shut_down: case conflict_done: return ISC_R_SUCCESS; case normal: case recover: case recover_wait: case recover_done: case unknown_state: return dhcp_failover_set_state (state, communications_interrupted); case potential_conflict: return dhcp_failover_set_state (state, resolution_interrupted); default: log_fatal("Impossible case at %s:%d.", MDL); break; } } return DHCP_R_INVALIDARG; } isc_result_t dhcp_failover_set_service_state (dhcp_failover_state_t *state) { switch (state -> me.state) { case unknown_state: state -> service_state = not_responding; state -> nrr = " (my state unknown)"; break; case partner_down: state -> service_state = service_partner_down; state -> nrr = ""; break; case normal: state -> service_state = cooperating; state -> nrr = ""; break; case communications_interrupted: state -> service_state = not_cooperating; state -> nrr = ""; break; case resolution_interrupted: case potential_conflict: case conflict_done: state -> service_state = not_responding; state -> nrr = " (resolving conflicts)"; break; case recover: state -> service_state = not_responding; state -> nrr = " (recovering)"; break; case shut_down: state -> service_state = not_responding; state -> nrr = " (shut down)"; break; case paused: state -> service_state = not_responding; state -> nrr = " (paused)"; break; case recover_wait: state -> service_state = not_responding; state -> nrr = " (recover wait)"; break; case recover_done: state -> service_state = not_responding; state -> nrr = " (recover done)"; break; case startup: state -> service_state = service_startup; state -> nrr = " (startup)"; break; default: log_fatal("Impossible case at %s:%d.\n", MDL); break; } /* Some peer states can require us not to respond, even if our state doesn't. */ /* XXX hm. I suspect this isn't true anymore. */ if (state -> service_state != not_responding) { switch (state -> partner.state) { case partner_down: state -> service_state = not_responding; state -> nrr = " (peer demands: recovering)"; break; case potential_conflict: case conflict_done: case resolution_interrupted: state -> service_state = not_responding; state -> nrr = " (peer demands: resolving conflicts)"; break; /* Other peer states don't affect our behaviour. */ default: break; } } return ISC_R_SUCCESS; } isc_result_t dhcp_failover_set_state (dhcp_failover_state_t *state, enum failover_state new_state) { enum failover_state saved_state; TIME saved_stos; struct pool *p; struct shared_network *s; struct lease *l; struct timeval tv; /* If we're in certain states where we're sending updates, and the peer * state changes, we need to re-schedule any pending updates just to * be on the safe side. This results in retransmission. */ switch (state -> me.state) { case normal: case potential_conflict: case partner_down: if (state -> ack_queue_tail) { struct lease *lp; /* Zap the flags. */ for (lp = state -> ack_queue_head; lp; lp = lp -> next_pending) lp -> flags = ((lp -> flags & ~ON_ACK_QUEUE) | ON_UPDATE_QUEUE); /* Now hook the ack queue to the beginning of the update queue. */ if (state -> update_queue_head) { lease_reference (&state -> ack_queue_tail -> next_pending, state -> update_queue_head, MDL); lease_dereference (&state -> update_queue_head, MDL); } lease_reference (&state -> update_queue_head, state -> ack_queue_head, MDL); if (!state -> update_queue_tail) { #if defined (POINTER_DEBUG) if (state -> ack_queue_tail -> next_pending) { log_error ("next pending on ack queue tail."); abort (); } #endif lease_reference (&state -> update_queue_tail, state -> ack_queue_tail, MDL); } lease_dereference (&state -> ack_queue_tail, MDL); lease_dereference (&state -> ack_queue_head, MDL); state -> cur_unacked_updates = 0; } /* We will re-queue a timeout later, if applicable. */ cancel_timeout (dhcp_failover_keepalive, state); break; default: break; } /* Tentatively make the transition. */ saved_state = state -> me.state; saved_stos = state -> me.stos; /* Keep the old stos if we're going into recover_wait or if we're coming into or out of startup. */ if (new_state != recover_wait && new_state != startup && saved_state != startup) state -> me.stos = cur_time; /* If we're in shutdown, peer is in partner_down, and we're moving to recover, we can skip waiting for MCLT to expire. This happens when a server is moved administratively into shutdown prior to actually shutting down. Of course, if there are any updates pending we can't actually do this. */ if (new_state == recover && saved_state == shut_down && state -> partner.state == partner_down && !state -> update_queue_head && !state -> ack_queue_head) state -> me.stos = cur_time - state -> mclt; state -> me.state = new_state; if (new_state == startup && saved_state != startup) state -> saved_state = saved_state; /* If we can't record the new state, we can't make a state transition. */ if (!write_failover_state (state) || !commit_leases ()) { log_error ("Unable to record current failover state for %s", state -> name); state -> me.state = saved_state; state -> me.stos = saved_stos; return ISC_R_IOERROR; } log_info ("failover peer %s: I move from %s to %s", state -> name, dhcp_failover_state_name_print (saved_state), dhcp_failover_state_name_print (state -> me.state)); /* If we were in startup and we just left it, cancel the timeout. */ if (new_state != startup && saved_state == startup) cancel_timeout (dhcp_failover_startup_timeout, state); /* * If the state changes for any reason, cancel 'delayed auto state * changes' (currently there is just the one). */ cancel_timeout(dhcp_failover_auto_partner_down, state); /* Set our service state. */ dhcp_failover_set_service_state (state); /* Tell the peer about it. */ if (state -> link_to_peer) dhcp_failover_send_state (state); switch (new_state) { case communications_interrupted: /* * There is an optional feature to automatically enter partner * down after a timer expires, upon entering comms-interrupted. * This feature is generally not safe except in specific * circumstances. * * A zero value (also the default) disables it. */ if (state->auto_partner_down == 0) break; #if defined (DEBUG_FAILOVER_TIMING) log_info("add_timeout +%lu dhcp_failover_auto_partner_down", (unsigned long)state->auto_partner_down); #endif tv.tv_sec = cur_time + state->auto_partner_down; tv.tv_usec = 0; add_timeout(&tv, dhcp_failover_auto_partner_down, state, (tvref_t)omapi_object_reference, (tvunref_t)omapi_object_dereference); break; case normal: /* Upon entering normal state, the server is expected to retransmit * all pending binding updates. This is a good opportunity to * rebalance the pool (potentially making new pending updates), * which also schedules the next pool rebalance. */ dhcp_failover_pool_balance(state); dhcp_failover_generate_update_queue(state, 0); if (state->update_queue_tail != NULL) { dhcp_failover_send_updates(state); log_info("Sending updates to %s.", state->name); } break; case potential_conflict: if (state -> i_am == primary) dhcp_failover_send_update_request (state); break; case startup: #if defined (DEBUG_FAILOVER_TIMING) log_info ("add_timeout +15 %s", "dhcp_failover_startup_timeout"); #endif tv . tv_sec = cur_time + 15; tv . tv_usec = 0; add_timeout (&tv, dhcp_failover_startup_timeout, state, (tvref_t)omapi_object_reference, (tvunref_t) omapi_object_dereference); break; /* If we come back in recover_wait and there's still waiting to do, set a timeout. */ case recover_wait: if (state -> me.stos + state -> mclt > cur_time) { #if defined (DEBUG_FAILOVER_TIMING) log_info ("add_timeout +%d %s", (int)(cur_time - state -> me.stos + state -> mclt), "dhcp_failover_startup_timeout"); #endif tv . tv_sec = (int)(state -> me.stos + state -> mclt); tv . tv_usec = 0; add_timeout (&tv, dhcp_failover_recover_done, state, (tvref_t)omapi_object_reference, (tvunref_t) omapi_object_dereference); } else dhcp_failover_recover_done (state); break; case recover: /* XXX: We're supposed to calculate if updreq or updreqall is * needed. In theory, we should only have to updreqall if we * are positive we lost our stable storage. */ if (state -> link_to_peer) dhcp_failover_send_update_request_all (state); break; case partner_down: /* For every expired lease, set a timeout for it to become free. */ for (s = shared_networks; s; s = s -> next) { for (p = s -> pools; p; p = p -> next) { if (p -> failover_peer == state) { for (l = p->expired ; l ; l = l->next) { l->tsfp = state->me.stos + state->mclt; l->sort_time = (l->tsfp > l->ends) ? l->tsfp : l->ends; } if (p->expired && (p->expired->sort_time < p->next_event_time)) { p->next_event_time = p->expired->sort_time; #if defined (DEBUG_FAILOVER_TIMING) log_info ("add_timeout +%d %s", (int)(cur_time - p->next_event_time), "pool_timer"); #endif tv.tv_sec = p->next_event_time; tv.tv_usec = 0; add_timeout(&tv, pool_timer, p, (tvref_t)pool_reference, (tvunref_t)pool_dereference); } } } } break; default: break; } return ISC_R_SUCCESS; } isc_result_t dhcp_failover_peer_state_changed (dhcp_failover_state_t *state, failover_message_t *msg) { enum failover_state previous_state = state -> partner.state; enum failover_state new_state; int startupp; new_state = msg -> server_state; startupp = (msg -> server_flags & FTF_SERVER_STARTUP) ? 1 : 0; if (state -> partner.state == new_state && state -> me.state) { switch (state -> me.state) { case startup: dhcp_failover_set_state (state, state -> saved_state); return ISC_R_SUCCESS; case unknown_state: case normal: case potential_conflict: case recover_done: case shut_down: case paused: case recover_wait: return ISC_R_SUCCESS; /* If we get a peer state change when we're disconnected, we always process it. */ case partner_down: case communications_interrupted: case resolution_interrupted: case recover: case conflict_done: break; default: log_fatal("Impossible case at %s:%d.", MDL); break; } } state -> partner.state = new_state; log_info ("failover peer %s: peer moves from %s to %s", state -> name, dhcp_failover_state_name_print (previous_state), dhcp_failover_state_name_print (state -> partner.state)); if (!write_failover_state (state) || !commit_leases ()) { /* This is bad, but it's not fatal. Of course, if we can't write to the lease database, we're not going to get much done anyway. */ log_error ("Unable to record current failover state for %s", state -> name); } /* Quickly validate the new state as being one of the 13 known * states. */ switch (new_state) { case unknown_state: case startup: case normal: case communications_interrupted: case partner_down: case potential_conflict: case recover: case paused: case shut_down: case recover_done: case resolution_interrupted: case conflict_done: case recover_wait: break; default: log_error("failover peer %s: Invalid state: %d", state->name, new_state); dhcp_failover_set_state(state, shut_down); return ISC_R_SUCCESS; } /* Do any state transitions that are required as a result of the peer's state transition. */ switch (state -> me.state == startup ? state -> saved_state : state -> me.state) { case normal: switch (new_state) { case normal: dhcp_failover_state_pool_check (state); break; case partner_down: if (state -> me.state == startup) dhcp_failover_set_state (state, recover); else dhcp_failover_set_state (state, potential_conflict); break; case potential_conflict: case resolution_interrupted: case conflict_done: /* None of these transitions should ever occur. */ log_error("Peer %s: Invalid state transition %s " "to %s.", state->name, dhcp_failover_state_name_print(previous_state), dhcp_failover_state_name_print(new_state)); dhcp_failover_set_state (state, shut_down); break; case recover: case shut_down: dhcp_failover_set_state (state, partner_down); break; case paused: dhcp_failover_set_state (state, communications_interrupted); break; default: /* recover_wait, recover_done, unknown_state, startup, * communications_interrupted */ break; } break; case recover: switch (new_state) { case recover: log_info ("failover peer %s: requesting %s", state -> name, "full update from peer"); /* Don't send updreqall if we're really in the startup state, because that will result in two being sent. */ if (state -> me.state == recover) dhcp_failover_send_update_request_all (state); break; case potential_conflict: case resolution_interrupted: case conflict_done: case normal: dhcp_failover_set_state (state, potential_conflict); break; case partner_down: case communications_interrupted: /* We're supposed to send an update request at this point. */ /* XXX we don't currently have code here to do any XXX clever detection of when we should send an XXX UPDREQALL message rather than an UPDREQ XXX message. What to do, what to do? */ /* Currently when we enter recover state, no matter * the reason, we send an UPDREQALL. So, it makes * the most sense to stick to that until something * better is done. * Furthermore, we only want to send the update * request if we are not in startup state. */ if (state -> me.state == recover) dhcp_failover_send_update_request_all (state); break; case shut_down: /* XXX We're not explicitly told what to do in this XXX case, but this transition is consistent with XXX what is elsewhere in the draft. */ dhcp_failover_set_state (state, partner_down); break; /* We can't really do anything in this case. */ default: /* paused, recover_done, recover_wait, unknown_state, * startup. */ break; } break; case potential_conflict: switch (new_state) { case normal: /* This is an illegal transition. */ log_error("Peer %s moves to normal during conflict " "resolution - panic, shutting down.", state->name); dhcp_failover_set_state(state, shut_down); break; case conflict_done: if (previous_state == potential_conflict) dhcp_failover_send_update_request (state); else log_error("Peer %s: Unexpected move to " "conflict-done.", state->name); break; case recover_done: case recover_wait: case potential_conflict: case partner_down: case communications_interrupted: case resolution_interrupted: case paused: break; case recover: dhcp_failover_set_state (state, recover); break; case shut_down: dhcp_failover_set_state (state, partner_down); break; default: /* unknown_state, startup */ break; } break; case conflict_done: switch (new_state) { case normal: case shut_down: dhcp_failover_set_state(state, new_state); break; default: log_fatal("Peer %s: Invalid attempt to move from %s " "to %s while local state is conflict-done.", state->name, dhcp_failover_state_name_print(previous_state), dhcp_failover_state_name_print(new_state)); } break; case partner_down: /* Take no action if other server is starting up. */ if (startupp) break; switch (new_state) { /* This is where we should be. */ case recover: case recover_wait: break; case recover_done: dhcp_failover_set_state (state, normal); break; case normal: case potential_conflict: case partner_down: case communications_interrupted: case resolution_interrupted: case conflict_done: dhcp_failover_set_state (state, potential_conflict); break; default: /* shut_down, paused, unknown_state, startup */ break; } break; case communications_interrupted: switch (new_state) { case paused: /* Stick with the status quo. */ break; /* If we're in communications-interrupted and an amnesic peer connects, go to the partner_down state immediately. */ case recover: dhcp_failover_set_state (state, partner_down); break; case normal: case communications_interrupted: case recover_done: case recover_wait: /* XXX so we don't need to do this specially in XXX the CONNECT and CONNECTACK handlers. */ dhcp_failover_send_updates (state); dhcp_failover_set_state (state, normal); break; case potential_conflict: case partner_down: case resolution_interrupted: case conflict_done: dhcp_failover_set_state (state, potential_conflict); break; case shut_down: dhcp_failover_set_state (state, partner_down); break; default: /* unknown_state, startup */ break; } break; case resolution_interrupted: switch (new_state) { case normal: case recover: case potential_conflict: case partner_down: case communications_interrupted: case resolution_interrupted: case conflict_done: case recover_done: case recover_wait: dhcp_failover_set_state (state, potential_conflict); break; case shut_down: dhcp_failover_set_state (state, partner_down); break; default: /* paused, unknown_state, startup */ break; } break; /* Make no transitions while in recover_wait...just wait. */ case recover_wait: break; case recover_done: switch (new_state) { case recover_done: log_error("Both servers have entered recover-done!"); case normal: dhcp_failover_set_state (state, normal); break; case shut_down: dhcp_failover_set_state (state, partner_down); break; default: /* potential_conflict, partner_down, * communications_interrupted, resolution_interrupted, * paused, recover, recover_wait, unknown_state, * startup. */ break; } break; /* We are essentially dead in the water when we're in either shut_down or paused states, and do not do any automatic state transitions. */ case shut_down: case paused: break; /* XXX: Shouldn't this be a fatal condition? */ case unknown_state: break; default: log_fatal("Impossible condition at %s:%d.", MDL); break; } /* If we didn't make a transition out of startup as a result of the peer's state change, do it now as a result of the fact that we got a state change from the peer. */ if (state -> me.state == startup && state -> saved_state != startup) dhcp_failover_set_state (state, state -> saved_state); /* For now, just set the service state based on the peer's state if necessary. */ dhcp_failover_set_service_state (state); return ISC_R_SUCCESS; } /* * Balance operation manual entry; startup, entrance to normal state. No * sense sending a POOLREQ at this stage; the peer is likely about to schedule * their own rebalance event upon entering normal themselves. */ static void dhcp_failover_pool_balance(dhcp_failover_state_t *state) { /* Cancel pending event. */ cancel_timeout(dhcp_failover_pool_rebalance, state); state->sched_balance = 0; dhcp_failover_pool_dobalance(state, NULL); } /* * Balance operation entry from timer event. Once per timer interval is * the only time we want to emit POOLREQs (asserting an interrupt in our * peer). */ void dhcp_failover_pool_rebalance(void *failover_state) { dhcp_failover_state_t *state; isc_boolean_t sendreq = ISC_FALSE; state = (dhcp_failover_state_t *)failover_state; /* Clear scheduled event indicator. */ state->sched_balance = 0; if (dhcp_failover_pool_dobalance(state, &sendreq)) dhcp_failover_send_updates(state); if (sendreq) dhcp_failover_send_poolreq(state); } /* * Balance operation entry from POOLREQ protocol message. Do not permit a * POOLREQ to send back a POOLREQ. Ping pong. */ static void dhcp_failover_pool_reqbalance(dhcp_failover_state_t *state) { int queued; /* Cancel pending event. */ cancel_timeout(dhcp_failover_pool_rebalance, state); state->sched_balance = 0; queued = dhcp_failover_pool_dobalance(state, NULL); dhcp_failover_send_poolresp(state, queued); if (queued) dhcp_failover_send_updates(state); else log_info("peer %s: Got POOLREQ, answering negatively! " "Peer may be out of leases or database inconsistent.", state->name); } /* * Do the meat of the work common to all forms of pool rebalance. If the * caller deems it appropriate to transmit POOLREQ messages, it can use the * sendreq pointer to pass in the address of a FALSE value which this function * will conditionally turn TRUE if a POOLREQ is determined to be necessary. * A NULL value may be passed, in which case no action is taken. */ static int dhcp_failover_pool_dobalance(dhcp_failover_state_t *state, isc_boolean_t *sendreq) { int lts, total, thresh, hold, panic, pass; int leases_queued = 0; struct lease *lp = (struct lease *)0; struct lease *next = (struct lease *)0; struct shared_network *s; struct pool *p; binding_state_t peer_lease_state; /* binding_state_t my_lease_state; */ /* XXX Why is this my_lease_state never used? */ struct lease **lq; int (*log_func)(const char *, ...); const char *result, *reqlog; if (state -> me.state != normal) return 0; state->last_balance = cur_time; for (s = shared_networks ; s ; s = s->next) { for (p = s->pools ; p ; p = p->next) { if (p->failover_peer != state) continue; /* Right now we're giving the peer half of the free leases. If we have more leases than the peer (i.e., more than half), then the number of leases we have, less the number of leases the peer has, will be how many more leases we have than the peer has. So if we send half that number to the peer, we should be even. */ if (p->failover_peer->i_am == primary) { lts = (p->free_leases - p->backup_leases) / 2; peer_lease_state = FTS_BACKUP; /* my_lease_state = FTS_FREE; */ lq = &p->free; } else { lts = (p->backup_leases - p->free_leases) / 2; peer_lease_state = FTS_FREE; /* my_lease_state = FTS_BACKUP; */ lq = &p->backup; } total = p->backup_leases + p->free_leases; thresh = ((total * state->max_lease_misbalance) + 50) / 100; hold = ((total * state->max_lease_ownership) + 50) / 100; /* * If we need leases (so lts is negative) more than negative * double the thresh%, panic and send poolreq to hopefully wake * up the peer (but more likely the db is inconsistent). But, * if this comes out zero, switch to -1 so that the POOLREQ is * sent on lts == -2 rather than right away at -1. * * Note that we do not subtract -1 from panic all the time * because thresh% and hold% may come out to the same number, * and that is correct operation...where thresh% and hold% are * both -1, we want to send poolreq when lts reaches -3. So, * "-3 < -2", lts < panic. */ panic = thresh * -2; if (panic == 0) panic = -1; if ((sendreq != NULL) && (lts < panic)) { reqlog = " (requesting peer rebalance!)"; *sendreq = ISC_TRUE; } else reqlog = ""; log_info("balancing pool %lx %s total %d free %d " "backup %d lts %d max-own (+/-)%d%s", (unsigned long)p, (p->shared_network ? p->shared_network->name : ""), p->lease_count, p->free_leases, p->backup_leases, lts, hold, reqlog); /* In the first pass, try to allocate leases to the * peer which it would normally be responsible for (if * the lease has a hardware address or client-identifier, * and the load-balance-algorithm chooses the peer to * answer that address), up to a hold% excess in the peer's * favor. In the second pass, just send the oldest (first * on the list) leases up to a hold% excess in our favor. * * This could make for additional pool rebalance * events, but preserving MAC possession should be * worth it. */ pass = 0; lease_reference(&lp, *lq, MDL); while (lp) { if (next) lease_dereference(&next, MDL); if (lp->next) lease_reference(&next, lp->next, MDL); /* * Stop if the pool is 'balanced enough.' * * The pool is balanced enough if: * * 1) We're on the first run through and the peer has * its fair share of leases already (lts reaches * -hold). * 2) We're on the second run through, we are shifting * never-used leases, and there is a perfectly even * balance (lts reaches zero). * 3) Second run through, we are shifting previously * used leases, and the local system has its fair * share but no more (lts reaches hold). * * Note that this is implemented below in 3,2,1 order. */ if (pass) { if (lp->ends) { if (lts <= hold) break; } else { if (lts <= 0) break; } } else if (lts <= -hold) break; if (pass || peer_wants_lease(lp)) { --lts; ++leases_queued; lp->next_binding_state = peer_lease_state; lp->tstp = cur_time; lp->starts = cur_time; if (!supersede_lease(lp, NULL, 0, 1, 0) || !write_lease(lp)) log_error("can't commit lease %s on " "giveaway", piaddr(lp->ip_addr)); } lease_dereference(&lp, MDL); if (next) lease_reference(&lp, next, MDL); else if (!pass) { pass = 1; lease_reference(&lp, *lq, MDL); } } if (next) lease_dereference(&next, MDL); if (lp) lease_dereference(&lp, MDL); if (lts > thresh) { result = "IMBALANCED"; log_func = log_error; } else { result = "balanced"; log_func = log_info; } log_func("%s pool %lx %s total %d free %d backup %d " "lts %d max-misbal %d", result, (unsigned long)p, (p->shared_network ? p->shared_network->name : ""), p->lease_count, p->free_leases, p->backup_leases, lts, thresh); /* Recalculate next rebalance event timer. */ dhcp_failover_pool_check(p); } } if (leases_queued) commit_leases(); return leases_queued; } /* dhcp_failover_pool_check: Called whenever FREE or BACKUP leases change * states, on both servers. Check the scheduled time to rebalance the pool * and lower it if applicable. */ void dhcp_failover_pool_check(struct pool *pool) { dhcp_failover_state_t *peer; TIME est1, est2; struct timeval tv; peer = pool->failover_peer; if(!peer || peer->me.state != normal) return; /* Estimate the time left until lease exhaustion. * The first lease on the backup or free lists is also the oldest * lease. It is reasonable to guess that it will take at least * as much time for a pool to run out of leases, as the present * age of the oldest lease (seconds since it expired). * * Note that this isn't so sane of an assumption if the oldest * lease is a virgin (ends = 0), we wind up sending this against * the max_balance bounds check. */ if(pool->free && pool->free->ends < cur_time) est1 = cur_time - pool->free->ends; else est1 = 0; if(pool->backup && pool->backup->ends < cur_time) est2 = cur_time - pool->backup->ends; else est2 = 0; /* We don't want to schedule rebalance for when we think we'll run * out of leases, we want to schedule the rebalance for when we think * the disparity will be 'large enough' to warrant action. */ est1 = ((est1 * peer->max_lease_misbalance) + 50) / 100; est2 = ((est2 * peer->max_lease_misbalance) + 50) / 100; /* Guess when the local system will begin issuing POOLREQ panic * attacks because "max_lease_misbalance*2" has been exceeded. */ if(peer->i_am == primary) est1 *= 2; else est2 *= 2; /* Select the smallest time. */ if(est1 > est2) est1 = est2; /* Bounded by the maximum configured value. */ if(est1 > peer->max_balance) est1 = peer->max_balance; /* Project this time into the future. */ est1 += cur_time; /* Do not move the time down under the minimum. */ est2 = peer->last_balance + peer->min_balance; if(peer->last_balance && (est1 < est2)) est1 = est2; /* Introduce a random delay. */ est1 += random() % 5; /* Do not move the time forward, or reset to the same time. */ if(peer->sched_balance) { if (est1 >= peer->sched_balance) return; /* We are about to schedule the time down, cancel the * current timeout. */ cancel_timeout(dhcp_failover_pool_rebalance, peer); } /* The time is different, and lower, use it. */ peer->sched_balance = est1; #if defined(DEBUG_FAILOVER_TIMING) log_info("add_timeout +%d dhcp_failover_pool_rebalance", (int)(est1 - cur_time)); #endif tv.tv_sec = est1; tv.tv_usec = 0; add_timeout(&tv, dhcp_failover_pool_rebalance, peer, (tvref_t)dhcp_failover_state_reference, (tvunref_t)dhcp_failover_state_dereference); } int dhcp_failover_state_pool_check (dhcp_failover_state_t *state) { struct shared_network *s; struct pool *p; for (s = shared_networks; s; s = s -> next) { for (p = s -> pools; p; p = p -> next) { if (p -> failover_peer != state) continue; dhcp_failover_pool_check (p); } } return 0; } isc_result_t dhcp_failover_send_updates (dhcp_failover_state_t *state) { struct lease *lp = (struct lease *)0; isc_result_t status; /* Can't update peer if we're not talking to it! */ if (!state -> link_to_peer) return ISC_R_SUCCESS; /* If there are acks pending, transmit them prior to potentially * sending new updates for the same lease. */ if (state->toack_queue_head != NULL) dhcp_failover_send_acks(state); while ((state -> partner.max_flying_updates > state -> cur_unacked_updates) && state -> update_queue_head) { /* Grab the head of the update queue. */ lease_reference (&lp, state -> update_queue_head, MDL); /* Send the update to the peer. */ status = dhcp_failover_send_bind_update (state, lp); if (status != ISC_R_SUCCESS) { lease_dereference (&lp, MDL); return status; } lp -> flags &= ~ON_UPDATE_QUEUE; /* Take it off the head of the update queue and put the next item in the update queue at the head. */ lease_dereference (&state -> update_queue_head, MDL); if (lp -> next_pending) { lease_reference (&state -> update_queue_head, lp -> next_pending, MDL); lease_dereference (&lp -> next_pending, MDL); } else { lease_dereference (&state -> update_queue_tail, MDL); } if (state -> ack_queue_head) { lease_reference (&state -> ack_queue_tail -> next_pending, lp, MDL); lease_dereference (&state -> ack_queue_tail, MDL); } else { lease_reference (&state -> ack_queue_head, lp, MDL); } #if defined (POINTER_DEBUG) if (lp -> next_pending) { log_error ("ack_queue_tail: lp -> next_pending"); abort (); } #endif lease_reference (&state -> ack_queue_tail, lp, MDL); lp -> flags |= ON_ACK_QUEUE; lease_dereference (&lp, MDL); /* Count the object as an unacked update. */ state -> cur_unacked_updates++; } return ISC_R_SUCCESS; } /* Queue an update for a lease. Always returns 1 at this point - it's not an error for this to be called on a lease for which there's no failover peer. */ int dhcp_failover_queue_update (struct lease *lease, int immediate) { dhcp_failover_state_t *state; if (!lease -> pool || !lease -> pool -> failover_peer) return 1; /* If it's already on the update queue, leave it there. */ if (lease -> flags & ON_UPDATE_QUEUE) return 1; /* Get the failover state structure for this lease. */ state = lease -> pool -> failover_peer; /* If it's on the ack queue, take it off. */ if (lease -> flags & ON_ACK_QUEUE) dhcp_failover_ack_queue_remove (state, lease); if (state -> update_queue_head) { lease_reference (&state -> update_queue_tail -> next_pending, lease, MDL); lease_dereference (&state -> update_queue_tail, MDL); } else { lease_reference (&state -> update_queue_head, lease, MDL); } #if defined (POINTER_DEBUG) if (lease -> next_pending) { log_error ("next pending on update queue lease."); #if defined (DEBUG_RC_HISTORY) dump_rc_history (lease); #endif abort (); } #endif lease_reference (&state -> update_queue_tail, lease, MDL); lease -> flags |= ON_UPDATE_QUEUE; if (immediate) dhcp_failover_send_updates (state); return 1; } int dhcp_failover_send_acks (dhcp_failover_state_t *state) { failover_message_t *msg = (failover_message_t *)0; /* Must commit all leases prior to acking them. */ if (!commit_leases ()) return 0; while (state -> toack_queue_head) { failover_message_reference (&msg, state -> toack_queue_head, MDL); failover_message_dereference (&state -> toack_queue_head, MDL); if (msg -> next) { failover_message_reference (&state -> toack_queue_head, msg -> next, MDL); } dhcp_failover_send_bind_ack (state, msg, 0, (const char *)0); failover_message_dereference (&msg, MDL); } if (state -> toack_queue_tail) failover_message_dereference (&state -> toack_queue_tail, MDL); state -> pending_acks = 0; return 1; } void dhcp_failover_toack_queue_timeout (void *vs) { dhcp_failover_state_t *state = vs; #if defined (DEBUG_FAILOVER_TIMING) log_info ("dhcp_failover_toack_queue_timeout"); #endif dhcp_failover_send_acks (state); } /* Queue an ack for a message. There is currently no way to queue a negative ack -- these need to be sent directly. */ int dhcp_failover_queue_ack (dhcp_failover_state_t *state, failover_message_t *msg) { struct timeval tv; if (state -> toack_queue_head) { failover_message_reference (&state -> toack_queue_tail -> next, msg, MDL); failover_message_dereference (&state -> toack_queue_tail, MDL); } else { failover_message_reference (&state -> toack_queue_head, msg, MDL); } failover_message_reference (&state -> toack_queue_tail, msg, MDL); state -> pending_acks++; /* Flush the toack queue whenever we exceed half the number of allowed unacked updates. */ if (state -> pending_acks >= state -> partner.max_flying_updates / 2) { dhcp_failover_send_acks (state); } /* Schedule a timeout to flush the ack queue. */ if (state -> pending_acks > 0) { #if defined (DEBUG_FAILOVER_TIMING) log_info ("add_timeout +2 %s", "dhcp_failover_toack_queue_timeout"); #endif tv . tv_sec = cur_time + 2; tv . tv_usec = 0; add_timeout (&tv, dhcp_failover_toack_queue_timeout, state, (tvref_t)dhcp_failover_state_reference, (tvunref_t)dhcp_failover_state_dereference); } return 1; } void dhcp_failover_ack_queue_remove (dhcp_failover_state_t *state, struct lease *lease) { struct lease *lp; if (!(lease -> flags & ON_ACK_QUEUE)) return; if (state -> ack_queue_head == lease) { lease_dereference (&state -> ack_queue_head, MDL); if (lease -> next_pending) { lease_reference (&state -> ack_queue_head, lease -> next_pending, MDL); lease_dereference (&lease -> next_pending, MDL); } else { lease_dereference (&state -> ack_queue_tail, MDL); } } else { for (lp = state -> ack_queue_head; lp && lp -> next_pending != lease; lp = lp -> next_pending) ; if (!lp) return; lease_dereference (&lp -> next_pending, MDL); if (lease -> next_pending) { lease_reference (&lp -> next_pending, lease -> next_pending, MDL); lease_dereference (&lease -> next_pending, MDL); } else { lease_dereference (&state -> ack_queue_tail, MDL); if (lp -> next_pending) { log_error ("state -> ack_queue_tail"); abort (); } lease_reference (&state -> ack_queue_tail, lp, MDL); } } lease -> flags &= ~ON_ACK_QUEUE; /* Multiple acks on one XID is an error and may cause badness. */ lease->last_xid = 0; /* XXX: this violates draft-failover. We can't send another * update just because we forgot about an old one that hasn't * been acked yet. */ state -> cur_unacked_updates--; /* * When updating leases as a result of an ack, we defer the commit * for performance reasons. When there are no more acks pending, * do a commit. */ if (state -> cur_unacked_updates == 0) { commit_leases(); } } isc_result_t dhcp_failover_state_set_value (omapi_object_t *h, omapi_object_t *id, omapi_data_string_t *name, omapi_typed_data_t *value) { isc_result_t status; if (h -> type != dhcp_type_failover_state) return DHCP_R_INVALIDARG; /* This list of successful returns is completely wrong, but the fastest way to make dhcpctl do something vaguely sane when you try to change the local state. */ if (!omapi_ds_strcmp (name, "name")) { return ISC_R_SUCCESS; } else if (!omapi_ds_strcmp (name, "partner-address")) { return ISC_R_SUCCESS; } else if (!omapi_ds_strcmp (name, "local-address")) { return ISC_R_SUCCESS; } else if (!omapi_ds_strcmp (name, "partner-port")) { return ISC_R_SUCCESS; } else if (!omapi_ds_strcmp (name, "local-port")) { return ISC_R_SUCCESS; } else if (!omapi_ds_strcmp (name, "max-outstanding-updates")) { return ISC_R_SUCCESS; } else if (!omapi_ds_strcmp (name, "mclt")) { return ISC_R_SUCCESS; } else if (!omapi_ds_strcmp (name, "load-balance-max-secs")) { return ISC_R_SUCCESS; } else if (!omapi_ds_strcmp (name, "load-balance-hba")) { return ISC_R_SUCCESS; } else if (!omapi_ds_strcmp (name, "partner-state")) { return ISC_R_SUCCESS; } else if (!omapi_ds_strcmp (name, "local-state")) { unsigned long l; status = omapi_get_int_value (&l, value); if (status != ISC_R_SUCCESS) return status; return dhcp_failover_set_state ((dhcp_failover_state_t *)h, l); } else if (!omapi_ds_strcmp (name, "partner-stos")) { return ISC_R_SUCCESS; } else if (!omapi_ds_strcmp (name, "local-stos")) { return ISC_R_SUCCESS; } else if (!omapi_ds_strcmp (name, "hierarchy")) { return ISC_R_SUCCESS; } else if (!omapi_ds_strcmp (name, "last-packet-sent")) { return ISC_R_SUCCESS; } else if (!omapi_ds_strcmp (name, "last-timestamp-received")) { return ISC_R_SUCCESS; } else if (!omapi_ds_strcmp (name, "skew")) { return ISC_R_SUCCESS; } else if (!omapi_ds_strcmp (name, "max-response-delay")) { return ISC_R_SUCCESS; } else if (!omapi_ds_strcmp (name, "cur-unacked-updates")) { return ISC_R_SUCCESS; } if (h -> inner && h -> inner -> type -> set_value) return (*(h -> inner -> type -> set_value)) (h -> inner, id, name, value); return ISC_R_NOTFOUND; } void dhcp_failover_keepalive (void *vs) { } void dhcp_failover_reconnect (void *vs) { dhcp_failover_state_t *state = vs; isc_result_t status; struct timeval tv; #if defined (DEBUG_FAILOVER_TIMING) log_info ("dhcp_failover_reconnect"); #endif /* If we already connected the other way, let the connection recovery code initiate any retry that may be required. */ if (state -> link_to_peer) return; status = dhcp_failover_link_initiate ((omapi_object_t *)state); if (status != ISC_R_SUCCESS && status != DHCP_R_INCOMPLETE) { log_info ("failover peer %s: %s", state -> name, isc_result_totext (status)); #if defined (DEBUG_FAILOVER_TIMING) log_info("add_timeout +90 dhcp_failover_reconnect"); #endif tv . tv_sec = cur_time + 90; tv . tv_usec = 0; add_timeout(&tv, dhcp_failover_reconnect, state, (tvref_t)dhcp_failover_state_reference, (tvunref_t)dhcp_failover_state_dereference); } } void dhcp_failover_startup_timeout (void *vs) { dhcp_failover_state_t *state = vs; #if defined (DEBUG_FAILOVER_TIMING) log_info ("dhcp_failover_startup_timeout"); #endif dhcp_failover_state_transition (state, "disconnect"); } void dhcp_failover_link_startup_timeout (void *vl) { dhcp_failover_link_t *link = vl; omapi_object_t *p; for (p = (omapi_object_t *)link; p -> inner; p = p -> inner) ; for (; p; p = p -> outer) if (p -> type == omapi_type_connection) break; if (p) { log_info ("failover: link startup timeout"); omapi_disconnect (p, 1); } } void dhcp_failover_listener_restart (void *vs) { dhcp_failover_state_t *state = vs; isc_result_t status; struct timeval tv; #if defined (DEBUG_FAILOVER_TIMING) log_info ("dhcp_failover_listener_restart"); #endif status = dhcp_failover_listen ((omapi_object_t *)state); if (status != ISC_R_SUCCESS) { log_info ("failover peer %s: %s", state -> name, isc_result_totext (status)); #if defined (DEBUG_FAILOVER_TIMING) log_info ("add_timeout +90 %s", "dhcp_failover_listener_restart"); #endif tv . tv_sec = cur_time + 90; tv . tv_usec = 0; add_timeout (&tv, dhcp_failover_listener_restart, state, (tvref_t)dhcp_failover_state_reference, (tvunref_t)dhcp_failover_state_dereference); } } void dhcp_failover_auto_partner_down(void *vs) { dhcp_failover_state_t *state = vs; #if defined (DEBUG_FAILOVER_TIMING) log_info("dhcp_failover_auto_partner_down"); #endif dhcp_failover_set_state(state, partner_down); } isc_result_t dhcp_failover_state_get_value (omapi_object_t *h, omapi_object_t *id, omapi_data_string_t *name, omapi_value_t **value) { dhcp_failover_state_t *s; struct option_cache *oc; struct data_string ds; isc_result_t status; if (h -> type != dhcp_type_failover_state) return DHCP_R_INVALIDARG; s = (dhcp_failover_state_t *)h; if (!omapi_ds_strcmp (name, "name")) { if (s -> name) return omapi_make_string_value (value, name, s -> name, MDL); return ISC_R_NOTFOUND; } else if (!omapi_ds_strcmp (name, "partner-address")) { oc = s -> partner.address; getaddr: memset (&ds, 0, sizeof ds); if (!evaluate_option_cache (&ds, (struct packet *)0, (struct lease *)0, (struct client_state *)0, (struct option_state *)0, (struct option_state *)0, &global_scope, oc, MDL)) { return ISC_R_NOTFOUND; } status = omapi_make_const_value (value, name, ds.data, ds.len, MDL); /* Disgusting kludge: */ if (oc == s -> me.address && !s -> server_identifier.len) data_string_copy (&s -> server_identifier, &ds, MDL); data_string_forget (&ds, MDL); return status; } else if (!omapi_ds_strcmp (name, "local-address")) { oc = s -> me.address; goto getaddr; } else if (!omapi_ds_strcmp (name, "partner-port")) { return omapi_make_int_value (value, name, s -> partner.port, MDL); } else if (!omapi_ds_strcmp (name, "local-port")) { return omapi_make_int_value (value, name, s -> me.port, MDL); } else if (!omapi_ds_strcmp (name, "max-outstanding-updates")) { return omapi_make_uint_value (value, name, s -> me.max_flying_updates, MDL); } else if (!omapi_ds_strcmp (name, "mclt")) { return omapi_make_uint_value (value, name, s -> mclt, MDL); } else if (!omapi_ds_strcmp (name, "load-balance-max-secs")) { return omapi_make_int_value (value, name, s -> load_balance_max_secs, MDL); } else if (!omapi_ds_strcmp (name, "load-balance-hba")) { if (s -> hba) return omapi_make_const_value (value, name, s -> hba, 32, MDL); return ISC_R_NOTFOUND; } else if (!omapi_ds_strcmp (name, "partner-state")) { return omapi_make_uint_value (value, name, s -> partner.state, MDL); } else if (!omapi_ds_strcmp (name, "local-state")) { return omapi_make_uint_value (value, name, s -> me.state, MDL); } else if (!omapi_ds_strcmp (name, "partner-stos")) { return omapi_make_int_value (value, name, s -> partner.stos, MDL); } else if (!omapi_ds_strcmp (name, "local-stos")) { return omapi_make_int_value (value, name, s -> me.stos, MDL); } else if (!omapi_ds_strcmp (name, "hierarchy")) { return omapi_make_uint_value (value, name, s -> i_am, MDL); } else if (!omapi_ds_strcmp (name, "last-packet-sent")) { return omapi_make_int_value (value, name, s -> last_packet_sent, MDL); } else if (!omapi_ds_strcmp (name, "last-timestamp-received")) { return omapi_make_int_value (value, name, s -> last_timestamp_received, MDL); } else if (!omapi_ds_strcmp (name, "skew")) { return omapi_make_int_value (value, name, s -> skew, MDL); } else if (!omapi_ds_strcmp (name, "max-response-delay")) { return omapi_make_uint_value (value, name, s -> me.max_response_delay, MDL); } else if (!omapi_ds_strcmp (name, "cur-unacked-updates")) { return omapi_make_int_value (value, name, s -> cur_unacked_updates, MDL); } if (h -> inner && h -> inner -> type -> get_value) return (*(h -> inner -> type -> get_value)) (h -> inner, id, name, value); return ISC_R_NOTFOUND; } isc_result_t dhcp_failover_state_destroy (omapi_object_t *h, const char *file, int line) { dhcp_failover_state_t *s; if (h -> type != dhcp_type_failover_state) return DHCP_R_INVALIDARG; s = (dhcp_failover_state_t *)h; if (s -> link_to_peer) dhcp_failover_link_dereference (&s -> link_to_peer, file, line); if (s -> name) { dfree (s -> name, MDL); s -> name = (char *)0; } if (s -> partner.address) option_cache_dereference (&s -> partner.address, file, line); if (s -> me.address) option_cache_dereference (&s -> me.address, file, line); if (s -> hba) { dfree (s -> hba, file, line); s -> hba = (u_int8_t *)0; } if (s -> update_queue_head) lease_dereference (&s -> update_queue_head, file, line); if (s -> update_queue_tail) lease_dereference (&s -> update_queue_tail, file, line); if (s -> ack_queue_head) lease_dereference (&s -> ack_queue_head, file, line); if (s -> ack_queue_tail) lease_dereference (&s -> ack_queue_tail, file, line); if (s -> send_update_done) lease_dereference (&s -> send_update_done, file, line); if (s -> toack_queue_head) failover_message_dereference (&s -> toack_queue_head, file, line); if (s -> toack_queue_tail) failover_message_dereference (&s -> toack_queue_tail, file, line); return ISC_R_SUCCESS; } /* Write all the published values associated with the object through the specified connection. */ isc_result_t dhcp_failover_state_stuff (omapi_object_t *c, omapi_object_t *id, omapi_object_t *h) { /* In this function c should be a (omapi_connection_object_t *) */ dhcp_failover_state_t *s; isc_result_t status; if (c -> type != omapi_type_connection) return DHCP_R_INVALIDARG; if (h -> type != dhcp_type_failover_state) return DHCP_R_INVALIDARG; s = (dhcp_failover_state_t *)h; status = omapi_connection_put_name (c, "name"); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_put_string (c, s -> name); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_put_name (c, "partner-address"); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_put_uint32 (c, sizeof s -> partner.address); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_copyin (c, (u_int8_t *)&s -> partner.address, sizeof s -> partner.address); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_put_name (c, "partner-port"); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_put_uint32 (c, sizeof (u_int32_t)); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_put_uint32 (c, (u_int32_t)s -> partner.port); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_put_name (c, "local-address"); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_put_uint32 (c, sizeof s -> me.address); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_copyin (c, (u_int8_t *)&s -> me.address, sizeof s -> me.address); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_put_name (c, "local-port"); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_put_uint32 (c, sizeof (u_int32_t)); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_put_uint32 (c, (u_int32_t)s -> me.port); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_put_name (c, "max-outstanding-updates"); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_put_uint32 (c, sizeof (u_int32_t)); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_put_uint32 (c, s -> me.max_flying_updates); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_put_name (c, "mclt"); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_put_uint32 (c, sizeof (u_int32_t)); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_put_uint32 (c, s -> mclt); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_put_name (c, "load-balance-max-secs"); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_put_uint32 (c, sizeof (u_int32_t)); if (status != ISC_R_SUCCESS) return status; status = (omapi_connection_put_uint32 (c, (u_int32_t)s -> load_balance_max_secs)); if (status != ISC_R_SUCCESS) return status; if (s -> hba) { status = omapi_connection_put_name (c, "load-balance-hba"); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_put_uint32 (c, 32); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_copyin (c, s -> hba, 32); if (status != ISC_R_SUCCESS) return status; } status = omapi_connection_put_name (c, "partner-state"); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_put_uint32 (c, sizeof (u_int32_t)); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_put_uint32 (c, s -> partner.state); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_put_name (c, "local-state"); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_put_uint32 (c, sizeof (u_int32_t)); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_put_uint32 (c, s -> me.state); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_put_name (c, "partner-stos"); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_put_uint32 (c, sizeof (u_int32_t)); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_put_uint32 (c, (u_int32_t)s -> partner.stos); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_put_name (c, "local-stos"); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_put_uint32 (c, sizeof (u_int32_t)); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_put_uint32 (c, (u_int32_t)s -> me.stos); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_put_name (c, "hierarchy"); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_put_uint32 (c, sizeof (u_int32_t)); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_put_uint32 (c, s -> i_am); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_put_name (c, "last-packet-sent"); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_put_uint32 (c, sizeof (u_int32_t)); if (status != ISC_R_SUCCESS) return status; status = (omapi_connection_put_uint32 (c, (u_int32_t)s -> last_packet_sent)); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_put_name (c, "last-timestamp-received"); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_put_uint32 (c, sizeof (u_int32_t)); if (status != ISC_R_SUCCESS) return status; status = (omapi_connection_put_uint32 (c, (u_int32_t)s -> last_timestamp_received)); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_put_name (c, "skew"); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_put_uint32 (c, sizeof (u_int32_t)); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_put_uint32 (c, (u_int32_t)s -> skew); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_put_name (c, "max-response-delay"); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_put_uint32 (c, sizeof (u_int32_t)); if (status != ISC_R_SUCCESS) return status; status = (omapi_connection_put_uint32 (c, (u_int32_t)s -> me.max_response_delay)); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_put_name (c, "cur-unacked-updates"); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_put_uint32 (c, sizeof (u_int32_t)); if (status != ISC_R_SUCCESS) return status; status = (omapi_connection_put_uint32 (c, (u_int32_t)s -> cur_unacked_updates)); if (status != ISC_R_SUCCESS) return status; if (h -> inner && h -> inner -> type -> stuff_values) return (*(h -> inner -> type -> stuff_values)) (c, id, h -> inner); return ISC_R_SUCCESS; } isc_result_t dhcp_failover_state_lookup (omapi_object_t **sp, omapi_object_t *id, omapi_object_t *ref) { omapi_value_t *tv = (omapi_value_t *)0; isc_result_t status; dhcp_failover_state_t *s; if (!ref) return DHCP_R_NOKEYS; /* First see if we were sent a handle. */ status = omapi_get_value_str (ref, id, "handle", &tv); if (status == ISC_R_SUCCESS) { status = omapi_handle_td_lookup (sp, tv -> value); omapi_value_dereference (&tv, MDL); if (status != ISC_R_SUCCESS) return status; /* Don't return the object if the type is wrong. */ if ((*sp) -> type != dhcp_type_failover_state) { omapi_object_dereference (sp, MDL); return DHCP_R_INVALIDARG; } } /* Look the failover state up by peer name. */ status = omapi_get_value_str (ref, id, "name", &tv); if (status == ISC_R_SUCCESS) { for (s = failover_states; s; s = s -> next) { unsigned l = strlen (s -> name); if (l == tv -> value -> u.buffer.len && !memcmp (s -> name, tv -> value -> u.buffer.value, l)) break; } omapi_value_dereference (&tv, MDL); /* If we already have a lease, and it's not the same one, then the query was invalid. */ if (*sp && *sp != (omapi_object_t *)s) { omapi_object_dereference (sp, MDL); return DHCP_R_KEYCONFLICT; } else if (!s) { if (*sp) omapi_object_dereference (sp, MDL); return ISC_R_NOTFOUND; } else if (!*sp) /* XXX fix so that hash lookup itself creates XXX the reference. */ omapi_object_reference (sp, (omapi_object_t *)s, MDL); } /* If we get to here without finding a lease, no valid key was specified. */ if (!*sp) return DHCP_R_NOKEYS; return ISC_R_SUCCESS; } isc_result_t dhcp_failover_state_create (omapi_object_t **sp, omapi_object_t *id) { return ISC_R_NOTIMPLEMENTED; } isc_result_t dhcp_failover_state_remove (omapi_object_t *sp, omapi_object_t *id) { return ISC_R_NOTIMPLEMENTED; } int dhcp_failover_state_match (dhcp_failover_state_t *state, u_int8_t *addr, unsigned addrlen) { struct data_string ds; int i; memset (&ds, 0, sizeof ds); if (evaluate_option_cache (&ds, (struct packet *)0, (struct lease *)0, (struct client_state *)0, (struct option_state *)0, (struct option_state *)0, &global_scope, state -> partner.address, MDL)) { for (i = 0; i + addrlen - 1 < ds.len; i += addrlen) { if (!memcmp (&ds.data [i], addr, addrlen)) { data_string_forget (&ds, MDL); return 1; } } data_string_forget (&ds, MDL); } return 0; } int dhcp_failover_state_match_by_name(state, name) dhcp_failover_state_t *state; failover_option_t *name; { if ((strlen(state->name) == name->count) && (memcmp(state->name, name->data, name->count) == 0)) return 1; return 0; } const char *dhcp_failover_reject_reason_print (int reason) { static char resbuf[sizeof("Undefined-255: This reason code is not defined " "in the protocol standard.")]; if ((reason > 0xff) || (reason < 0)) return "Reason code out of range."; switch (reason) { case FTR_ILLEGAL_IP_ADDR: return "Illegal IP address (not part of any address pool)."; case FTR_FATAL_CONFLICT: return "Fatal conflict exists: address in use by other client."; case FTR_MISSING_BINDINFO: return "Missing binding information."; case FTR_TIMEMISMATCH: return "Connection rejected, time mismatch too great."; case FTR_INVALID_MCLT: return "Connection rejected, invalid MCLT."; case FTR_MISC_REJECT: return "Connection rejected, unknown reason."; case FTR_DUP_CONNECTION: return "Connection rejected, duplicate connection."; case FTR_INVALID_PARTNER: return "Connection rejected, invalid failover partner."; case FTR_TLS_UNSUPPORTED: return "TLS not supported."; case FTR_TLS_UNCONFIGURED: return "TLS supported but not configured."; case FTR_TLS_REQUIRED: return "TLS required but not supported by partner."; case FTR_DIGEST_UNSUPPORTED: return "Message digest not supported."; case FTR_DIGEST_UNCONFIGURED: return "Message digest not configured."; case FTR_VERSION_MISMATCH: return "Protocol version mismatch."; case FTR_OUTDATED_BIND_INFO: return "Outdated binding information."; case FTR_LESS_CRIT_BIND_INFO: return "Less critical binding information."; case FTR_NO_TRAFFIC: return "No traffic within sufficient time."; case FTR_HBA_CONFLICT: return "Hash bucket assignment conflict."; case FTR_IP_NOT_RESERVED: return "IP not reserved on this server."; case FTR_IP_DIGEST_FAILURE: return "Message digest failed to compare."; case FTR_IP_MISSING_DIGEST: return "Missing message digest."; case FTR_UNKNOWN: return "Unknown Error."; default: sprintf(resbuf, "Undefined-%d: This reason code is not defined in the " "protocol standard.", reason); return resbuf; } } const char *dhcp_failover_state_name_print (enum failover_state state) { switch (state) { default: case unknown_state: return "unknown-state"; case partner_down: return "partner-down"; case normal: return "normal"; case conflict_done: return "conflict-done"; case communications_interrupted: return "communications-interrupted"; case resolution_interrupted: return "resolution-interrupted"; case potential_conflict: return "potential-conflict"; case recover: return "recover"; case recover_done: return "recover-done"; case recover_wait: return "recover-wait"; case shut_down: return "shutdown"; case paused: return "paused"; case startup: return "startup"; } } const char *dhcp_failover_message_name (unsigned type) { static char messbuf[sizeof("unknown-message-255")]; if (type > 0xff) return "invalid-message"; switch (type) { case FTM_POOLREQ: return "pool-request"; case FTM_POOLRESP: return "pool-response"; case FTM_BNDUPD: return "bind-update"; case FTM_BNDACK: return "bind-ack"; case FTM_CONNECT: return "connect"; case FTM_CONNECTACK: return "connect-ack"; case FTM_UPDREQ: return "update-request"; case FTM_UPDDONE: return "update-done"; case FTM_UPDREQALL: return "update-request-all"; case FTM_STATE: return "state"; case FTM_CONTACT: return "contact"; case FTM_DISCONNECT: return "disconnect"; default: sprintf(messbuf, "unknown-message-%u", type); return messbuf; } } const char *dhcp_failover_option_name (unsigned type) { static char optbuf[sizeof("unknown-option-65535")]; if (type > 0xffff) return "invalid-option"; switch (type) { case FTO_ADDRESSES_TRANSFERRED: return "addresses-transferred"; case FTO_ASSIGNED_IP_ADDRESS: return "assigned-ip-address"; case FTO_BINDING_STATUS: return "binding-status"; case FTO_CLIENT_IDENTIFIER: return "client-identifier"; case FTO_CHADDR: return "chaddr"; case FTO_CLTT: return "cltt"; case FTO_DDNS: return "ddns"; case FTO_DELAYED_SERVICE: return "delayed-service"; case FTO_HBA: return "hba"; case FTO_IP_FLAGS: return "ip-flags"; case FTO_LEASE_EXPIRY: return "lease-expiry"; case FTO_MAX_UNACKED: return "max-unacked"; case FTO_MCLT: return "mclt"; case FTO_MESSAGE: return "message"; case FTO_MESSAGE_DIGEST: return "message-digest"; case FTO_POTENTIAL_EXPIRY: return "potential-expiry"; case FTO_PROTOCOL_VERSION: return "protocol-version"; case FTO_RECEIVE_TIMER: return "receive-timer"; case FTO_REJECT_REASON: return "reject-reason"; case FTO_RELATIONSHIP_NAME: return "relationship-name"; case FTO_REPLY_OPTIONS: return "reply-options"; case FTO_REQUEST_OPTIONS: return "request-options"; case FTO_SERVER_FLAGS: return "server-flags"; case FTO_SERVER_STATE: return "server-state"; case FTO_STOS: return "stos"; case FTO_TLS_REPLY: return "tls-reply"; case FTO_TLS_REQUEST: return "tls-request"; case FTO_VENDOR_CLASS: return "vendor-class"; case FTO_VENDOR_OPTIONS: return "vendor-options"; default: sprintf(optbuf, "unknown-option-%u", type); return optbuf; } } failover_option_t *dhcp_failover_option_printf (unsigned code, char *obuf, unsigned *obufix, unsigned obufmax, const char *fmt, ...) { va_list va; char tbuf [256]; /* %Audit% Truncation causes panic. %2004.06.17,Revisit% * It is unclear what the effects of truncation here are, or * how that condition should be handled. It seems that this * function is used for formatting messages in the failover * command channel. For now the safest thing is for * overflow-truncation to cause a fatal log. */ va_start (va, fmt); if (vsnprintf (tbuf, sizeof tbuf, fmt, va) >= sizeof tbuf) log_fatal ("%s: vsnprintf would truncate", "dhcp_failover_make_option"); va_end (va); return dhcp_failover_make_option (code, obuf, obufix, obufmax, strlen (tbuf), tbuf); } failover_option_t *dhcp_failover_make_option (unsigned code, char *obuf, unsigned *obufix, unsigned obufmax, ...) { va_list va; struct failover_option_info *info; int i; unsigned size, count; unsigned val; u_int8_t *iaddr; unsigned ilen = 0; u_int8_t *bval; char *txt = NULL; #if defined (DEBUG_FAILOVER_MESSAGES) char tbuf [256]; #endif /* Note that the failover_option structure is used differently on input than on output - on input, count is an element count, and on output it's the number of bytes total in the option, including the option code and option length. */ failover_option_t option, *op; /* Bogus option code? */ if (code < 1 || code > FTO_MAX || ft_options [code].type == FT_UNDEF) { return &null_failover_option; } info = &ft_options [code]; va_start (va, obufmax); /* Get the number of elements and the size of the buffer we need to allocate. */ if (info -> type == FT_DDNS || info -> type == FT_DDNS1) { count = info -> type == FT_DDNS ? 1 : 2; size = va_arg (va, int) + count; } else { /* Find out how many items in this list. */ if (info -> num_present) count = info -> num_present; else count = va_arg (va, int); /* Figure out size. */ switch (info -> type) { case FT_UINT8: case FT_BYTES: case FT_DIGEST: size = count; break; case FT_TEXT_OR_BYTES: case FT_TEXT: txt = va_arg (va, char *); size = count; break; case FT_IPADDR: ilen = va_arg (va, unsigned); size = count * ilen; break; case FT_UINT32: size = count * 4; break; case FT_UINT16: size = count * 2; break; default: /* shouldn't get here. */ log_fatal ("bogus type in failover_make_option: %d", info -> type); return &null_failover_option; } } size += 4; /* Allocate a buffer for the option. */ option.count = size; option.data = dmalloc (option.count, MDL); if (!option.data) { va_end (va); return &null_failover_option; } /* Put in the option code and option length. */ putUShort (option.data, code); putUShort (&option.data [2], size - 4); #if defined (DEBUG_FAILOVER_MESSAGES) /* %Audit% Truncation causes panic. %2004.06.17,Revisit% * It is unclear what the effects of truncation here are, or * how that condition should be handled. It seems that this * message may be sent over the failover command channel. * For now the safest thing is for overflow-truncation to cause * a fatal log. */ if (snprintf (tbuf, sizeof tbuf, " (%s<%d>", info -> name, option.count) >= sizeof tbuf) log_fatal ("dhcp_failover_make_option: tbuf overflow"); failover_print (obuf, obufix, obufmax, tbuf); #endif /* Now put in the data. */ switch (info -> type) { case FT_UINT8: for (i = 0; i < count; i++) { val = va_arg (va, unsigned); #if defined (DEBUG_FAILOVER_MESSAGES) /* %Audit% Cannot exceed 24 bytes. %2004.06.17,Safe% */ sprintf (tbuf, " %d", val); failover_print (obuf, obufix, obufmax, tbuf); #endif option.data [i + 4] = val; } break; case FT_IPADDR: for (i = 0; i < count; i++) { iaddr = va_arg (va, u_int8_t *); if (ilen != 4) { dfree (option.data, MDL); log_error ("IP addrlen=%d, should be 4.", ilen); va_end (va); return &null_failover_option; } #if defined (DEBUG_FAILOVER_MESSAGES) /*%Audit% Cannot exceed 17 bytes. %2004.06.17,Safe%*/ sprintf (tbuf, " %u.%u.%u.%u", iaddr [0], iaddr [1], iaddr [2], iaddr [3]); failover_print (obuf, obufix, obufmax, tbuf); #endif memcpy (&option.data [4 + i * ilen], iaddr, ilen); } break; case FT_UINT32: for (i = 0; i < count; i++) { val = va_arg (va, unsigned); #if defined (DEBUG_FAILOVER_MESSAGES) /*%Audit% Cannot exceed 24 bytes. %2004.06.17,Safe%*/ sprintf (tbuf, " %d", val); failover_print (obuf, obufix, obufmax, tbuf); #endif putULong (&option.data [4 + i * 4], val); } break; case FT_BYTES: case FT_DIGEST: bval = va_arg (va, u_int8_t *); #if defined (DEBUG_FAILOVER_MESSAGES) for (i = 0; i < count; i++) { /* 23 bytes plus nul, safe. */ sprintf (tbuf, " %d", bval [i]); failover_print (obuf, obufix, obufmax, tbuf); } #endif memcpy (&option.data [4], bval, count); break; /* On output, TEXT_OR_BYTES is _always_ text, and always NUL terminated. Note that the caller should be careful not to provide a format and data that amount to more than 256 bytes of data, since it will cause a fatal error. */ case FT_TEXT_OR_BYTES: case FT_TEXT: #if defined (DEBUG_FAILOVER_MESSAGES) /* %Audit% Truncation causes panic. %2004.06.17,Revisit% * It is unclear what the effects of truncation here are, or * how that condition should be handled. It seems that this * function is used for formatting messages in the failover * command channel. For now the safest thing is for * overflow-truncation to cause a fatal log. */ if (snprintf (tbuf, sizeof tbuf, "\"%s\"", txt) >= sizeof tbuf) log_fatal ("dhcp_failover_make_option: tbuf overflow"); failover_print (obuf, obufix, obufmax, tbuf); #endif memcpy (&option.data [4], txt, count); break; case FT_DDNS: case FT_DDNS1: option.data [4] = va_arg (va, unsigned); if (count == 2) option.data [5] = va_arg (va, unsigned); bval = va_arg (va, u_int8_t *); memcpy (&option.data [4 + count], bval, size - count - 4); #if defined (DEBUG_FAILOVER_MESSAGES) for (i = 4; i < size; i++) { /*%Audit% Cannot exceed 24 bytes. %2004.06.17,Safe%*/ sprintf (tbuf, " %d", option.data [i]); failover_print (obuf, obufix, obufmax, tbuf); } #endif break; case FT_UINT16: for (i = 0; i < count; i++) { val = va_arg (va, u_int32_t); #if defined (DEBUG_FAILOVER_MESSAGES) /*%Audit% Cannot exceed 24 bytes. %2004.06.17,Safe%*/ sprintf (tbuf, " %d", val); failover_print (obuf, obufix, obufmax, tbuf); #endif putUShort (&option.data [4 + i * 2], val); } break; case FT_UNDEF: default: break; } #if defined DEBUG_FAILOVER_MESSAGES failover_print (obuf, obufix, obufmax, ")"); #endif va_end (va); /* Now allocate a place to store what we just set up. */ op = dmalloc (sizeof (failover_option_t), MDL); if (!op) { dfree (option.data, MDL); return &null_failover_option; } *op = option; return op; } /* Send a failover message header. */ isc_result_t dhcp_failover_put_message (dhcp_failover_link_t *link, omapi_object_t *connection, int msg_type, u_int32_t xid, ...) { unsigned size = 0; int bad_option = 0; int opix = 0; va_list list; failover_option_t *option; unsigned char *opbuf; isc_result_t status = ISC_R_SUCCESS; unsigned char cbuf; struct timeval tv; /* Run through the argument list once to compute the length of the option portion of the message. */ va_start (list, xid); while ((option = va_arg (list, failover_option_t *))) { if (option != &skip_failover_option) size += option -> count; if (option == &null_failover_option) bad_option = 1; } va_end (list); /* Allocate an option buffer, unless we got an error. */ if (!bad_option && size) { opbuf = dmalloc (size, MDL); if (!opbuf) status = ISC_R_NOMEMORY; } else opbuf = (unsigned char *)0; va_start (list, xid); while ((option = va_arg (list, failover_option_t *))) { if (option == &skip_failover_option) continue; if (!bad_option && opbuf) memcpy (&opbuf [opix], option -> data, option -> count); if (option != &null_failover_option && option != &skip_failover_option) { opix += option -> count; dfree (option -> data, MDL); dfree (option, MDL); } } va_end(list); if (bad_option) return DHCP_R_INVALIDARG; /* Now send the message header. */ /* Message length. */ status = omapi_connection_put_uint16 (connection, size + 12); if (status != ISC_R_SUCCESS) goto err; /* Message type. */ cbuf = msg_type; status = omapi_connection_copyin (connection, &cbuf, 1); if (status != ISC_R_SUCCESS) goto err; /* Payload offset. */ cbuf = 12; status = omapi_connection_copyin (connection, &cbuf, 1); if (status != ISC_R_SUCCESS) goto err; /* Current time. */ status = omapi_connection_put_uint32 (connection, (u_int32_t)cur_time); if (status != ISC_R_SUCCESS) goto err; /* Transaction ID. */ status = omapi_connection_put_uint32(connection, xid); if (status != ISC_R_SUCCESS) goto err; /* Payload. */ if (opbuf) { status = omapi_connection_copyin (connection, opbuf, size); if (status != ISC_R_SUCCESS) goto err; dfree (opbuf, MDL); } if (link -> state_object && link -> state_object -> link_to_peer == link) { #if defined (DEBUG_FAILOVER_CONTACT_TIMING) log_info ("add_timeout +%d %s", (int)(link -> state_object -> partner.max_response_delay) / 3, "dhcp_failover_send_contact"); #endif tv . tv_sec = cur_time + (int)(link -> state_object -> partner.max_response_delay) / 3; tv . tv_usec = 0; add_timeout (&tv, dhcp_failover_send_contact, link -> state_object, (tvref_t)dhcp_failover_state_reference, (tvunref_t)dhcp_failover_state_dereference); } return status; err: if (opbuf) dfree (opbuf, MDL); log_info ("dhcp_failover_put_message: something went wrong."); omapi_disconnect (connection, 1); return status; } void dhcp_failover_timeout (void *vstate) { dhcp_failover_state_t *state = vstate; dhcp_failover_link_t *link; #if defined (DEBUG_FAILOVER_TIMING) log_info ("dhcp_failover_timeout"); #endif if (!state || state -> type != dhcp_type_failover_state) return; link = state -> link_to_peer; if (!link || !link -> outer || link -> outer -> type != omapi_type_connection) return; log_error ("timeout waiting for failover peer %s", state -> name); /* If we haven't gotten a timely response, blow away the connection. This will cause the state to change automatically. */ omapi_disconnect (link -> outer, 1); } void dhcp_failover_send_contact (void *vstate) { dhcp_failover_state_t *state = vstate; dhcp_failover_link_t *link; isc_result_t status; #if defined(DEBUG_FAILOVER_MESSAGES) && \ defined(DEBUG_FAILOVER_CONTACT_MESSAGES) char obuf [64]; unsigned obufix = 0; failover_print(obuf, &obufix, sizeof(obuf), "(contact"); #endif #if defined (DEBUG_FAILOVER_CONTACT_TIMING) log_info ("dhcp_failover_send_contact"); #endif if (!state || state -> type != dhcp_type_failover_state) return; link = state -> link_to_peer; if (!link || !link -> outer || link -> outer -> type != omapi_type_connection) return; status = (dhcp_failover_put_message (link, link -> outer, FTM_CONTACT, link->xid++, (failover_option_t *)0)); #if defined(DEBUG_FAILOVER_MESSAGES) && \ defined(DEBUG_FAILOVER_CONTACT_MESSAGES) if (status != ISC_R_SUCCESS) failover_print(obuf, &obufix, sizeof(obuf), " (failed)"); failover_print(obuf, &obufix, sizeof(obuf), ")"); if (obufix) { log_debug ("%s", obuf); } #else IGNORE_UNUSED(status); #endif return; } isc_result_t dhcp_failover_send_state (dhcp_failover_state_t *state) { dhcp_failover_link_t *link; isc_result_t status; #if defined (DEBUG_FAILOVER_MESSAGES) char obuf [64]; unsigned obufix = 0; # define FMA obuf, &obufix, sizeof obuf failover_print (FMA, "(state"); #else # define FMA (char *)0, (unsigned *)0, 0 #endif if (!state || state -> type != dhcp_type_failover_state) return DHCP_R_INVALIDARG; link = state -> link_to_peer; if (!link || !link -> outer || link -> outer -> type != omapi_type_connection) return DHCP_R_INVALIDARG; status = (dhcp_failover_put_message (link, link -> outer, FTM_STATE, link->xid++, dhcp_failover_make_option (FTO_SERVER_STATE, FMA, (state -> me.state == startup ? state -> saved_state : state -> me.state)), dhcp_failover_make_option (FTO_SERVER_FLAGS, FMA, (state -> service_state == service_startup ? FTF_SERVER_STARTUP : 0)), dhcp_failover_make_option (FTO_STOS, FMA, state -> me.stos), (failover_option_t *)0)); #if defined (DEBUG_FAILOVER_MESSAGES) if (status != ISC_R_SUCCESS) failover_print (FMA, " (failed)"); failover_print (FMA, ")"); if (obufix) { log_debug ("%s", obuf); } #else IGNORE_UNUSED(status); #endif return ISC_R_SUCCESS; } /* Send a connect message. */ isc_result_t dhcp_failover_send_connect (omapi_object_t *l) { dhcp_failover_link_t *link; dhcp_failover_state_t *state; isc_result_t status; #if defined (DEBUG_FAILOVER_MESSAGES) char obuf [64]; unsigned obufix = 0; # define FMA obuf, &obufix, sizeof obuf failover_print (FMA, "(connect"); #else # define FMA (char *)0, (unsigned *)0, 0 #endif if (!l || l -> type != dhcp_type_failover_link) return DHCP_R_INVALIDARG; link = (dhcp_failover_link_t *)l; state = link -> state_object; if (!l -> outer || l -> outer -> type != omapi_type_connection) return DHCP_R_INVALIDARG; status = (dhcp_failover_put_message (link, l -> outer, FTM_CONNECT, link->xid++, dhcp_failover_make_option(FTO_RELATIONSHIP_NAME, FMA, strlen(state->name), state->name), dhcp_failover_make_option (FTO_MAX_UNACKED, FMA, state -> me.max_flying_updates), dhcp_failover_make_option (FTO_RECEIVE_TIMER, FMA, state -> me.max_response_delay), dhcp_failover_option_printf(FTO_VENDOR_CLASS, FMA, "isc-%s", PACKAGE_VERSION), dhcp_failover_make_option (FTO_PROTOCOL_VERSION, FMA, DHCP_FAILOVER_VERSION), dhcp_failover_make_option (FTO_TLS_REQUEST, FMA, 0, 0), dhcp_failover_make_option (FTO_MCLT, FMA, state -> mclt), (state -> hba ? dhcp_failover_make_option (FTO_HBA, FMA, 32, state -> hba) : &skip_failover_option), (failover_option_t *)0)); #if defined (DEBUG_FAILOVER_MESSAGES) if (status != ISC_R_SUCCESS) failover_print (FMA, " (failed)"); failover_print (FMA, ")"); if (obufix) { log_debug ("%s", obuf); } #endif return status; } isc_result_t dhcp_failover_send_connectack (omapi_object_t *l, dhcp_failover_state_t *state, int reason, const char *errmsg) { dhcp_failover_link_t *link; isc_result_t status; #if defined (DEBUG_FAILOVER_MESSAGES) char obuf [64]; unsigned obufix = 0; # define FMA obuf, &obufix, sizeof obuf failover_print (FMA, "(connectack"); #else # define FMA (char *)0, (unsigned *)0, 0 #endif if (!l || l -> type != dhcp_type_failover_link) return DHCP_R_INVALIDARG; link = (dhcp_failover_link_t *)l; if (!l -> outer || l -> outer -> type != omapi_type_connection) return DHCP_R_INVALIDARG; status = (dhcp_failover_put_message (link, l -> outer, FTM_CONNECTACK, link->imsg->xid, state ? dhcp_failover_make_option(FTO_RELATIONSHIP_NAME, FMA, strlen(state->name), state->name) : (link->imsg->options_present & FTB_RELATIONSHIP_NAME) ? &link->imsg->relationship_name : &skip_failover_option, state ? dhcp_failover_make_option (FTO_MAX_UNACKED, FMA, state -> me.max_flying_updates) : &skip_failover_option, state ? dhcp_failover_make_option (FTO_RECEIVE_TIMER, FMA, state -> me.max_response_delay) : &skip_failover_option, dhcp_failover_option_printf(FTO_VENDOR_CLASS, FMA, "isc-%s", PACKAGE_VERSION), dhcp_failover_make_option (FTO_PROTOCOL_VERSION, FMA, DHCP_FAILOVER_VERSION), (link->imsg->options_present & FTB_TLS_REQUEST) ? dhcp_failover_make_option(FTO_TLS_REPLY, FMA, 0, 0) : &skip_failover_option, reason ? dhcp_failover_make_option (FTO_REJECT_REASON, FMA, reason) : &skip_failover_option, (reason && errmsg) ? dhcp_failover_make_option (FTO_MESSAGE, FMA, strlen (errmsg), errmsg) : &skip_failover_option, (failover_option_t *)0)); #if defined (DEBUG_FAILOVER_MESSAGES) if (status != ISC_R_SUCCESS) failover_print (FMA, " (failed)"); failover_print (FMA, ")"); if (obufix) { log_debug ("%s", obuf); } #endif return status; } isc_result_t dhcp_failover_send_disconnect (omapi_object_t *l, int reason, const char *message) { dhcp_failover_link_t *link; isc_result_t status; #if defined (DEBUG_FAILOVER_MESSAGES) char obuf [64]; unsigned obufix = 0; # define FMA obuf, &obufix, sizeof obuf failover_print (FMA, "(disconnect"); #else # define FMA (char *)0, (unsigned *)0, 0 #endif if (!l || l -> type != dhcp_type_failover_link) return DHCP_R_INVALIDARG; link = (dhcp_failover_link_t *)l; if (!l -> outer || l -> outer -> type != omapi_type_connection) return DHCP_R_INVALIDARG; if (!message && reason) message = dhcp_failover_reject_reason_print (reason); status = (dhcp_failover_put_message (link, l -> outer, FTM_DISCONNECT, link->xid++, dhcp_failover_make_option (FTO_REJECT_REASON, FMA, reason), (message ? dhcp_failover_make_option (FTO_MESSAGE, FMA, strlen (message), message) : &skip_failover_option), (failover_option_t *)0)); #if defined (DEBUG_FAILOVER_MESSAGES) if (status != ISC_R_SUCCESS) failover_print (FMA, " (failed)"); failover_print (FMA, ")"); if (obufix) { log_debug ("%s", obuf); } #endif return status; } /* Send a Bind Update message. */ isc_result_t dhcp_failover_send_bind_update (dhcp_failover_state_t *state, struct lease *lease) { dhcp_failover_link_t *link; isc_result_t status; int flags = 0; binding_state_t transmit_state; #if defined (DEBUG_FAILOVER_MESSAGES) char obuf [64]; unsigned obufix = 0; # define FMA obuf, &obufix, sizeof obuf failover_print (FMA, "(bndupd"); #else # define FMA (char *)0, (unsigned *)0, 0 #endif if (!state -> link_to_peer || state -> link_to_peer -> type != dhcp_type_failover_link) return DHCP_R_INVALIDARG; link = (dhcp_failover_link_t *)state -> link_to_peer; if (!link -> outer || link -> outer -> type != omapi_type_connection) return DHCP_R_INVALIDARG; transmit_state = lease->desired_binding_state; if (lease->flags & RESERVED_LEASE) { /* If we are listing an allocable (not yet ACTIVE etc) lease * as reserved, toggle to the peer's 'free state', per the * draft. This gives the peer permission to alloc it to the * chaddr/uid-named client. */ if ((state->i_am == primary) && (transmit_state == FTS_FREE)) transmit_state = FTS_BACKUP; else if ((state->i_am == secondary) && (transmit_state == FTS_BACKUP)) transmit_state = FTS_FREE; flags |= FTF_IP_FLAG_RESERVE; } if (lease->flags & BOOTP_LEASE) flags |= FTF_IP_FLAG_BOOTP; /* last_xid == 0 is illegal, seek past zero if we hit it. */ if (link->xid == 0) link->xid = 1; lease->last_xid = link->xid++; /* * Our very next action is to transmit a binding update relating to * this lease over the wire, and although there is a BNDACK, there is * no BNDACKACK or BNDACKACKACK...the basic issue as we send a BNDUPD, * we may not receive a BNDACK. This non-reception does not imply the * peer did not receive and process the BNDUPD. So at this point, we * must divest any state that would be dangerous to retain under the * impression the peer has been updated. Normally state changes like * this are processed in supersede_lease(), but in this case we need a * very late binding. * * In failover rules, a server is permitted to work forward in certain * directions from a given lease's state; active leases may be * extended, so forth. There is an 'optimization' in the failover * draft that permits a server to 'rewind' any work they have not * informed the peer. Since we can't know if the peer received our * update but was unable to acknowledge it, we make this change on * transmit rather than upon receiving the acknowledgement. * * XXX: Frequent lease commits are undesirable. This should hopefully * only trigger when a server is sending a lease /state change/, and * not merely an update such as with a renewal. */ if (lease->rewind_binding_state != lease->binding_state) { lease->rewind_binding_state = lease->binding_state; write_lease(lease); commit_leases(); } /* Send the update. */ status = (dhcp_failover_put_message (link, link -> outer, FTM_BNDUPD, lease->last_xid, dhcp_failover_make_option (FTO_ASSIGNED_IP_ADDRESS, FMA, lease -> ip_addr.len, lease -> ip_addr.iabuf), dhcp_failover_make_option (FTO_BINDING_STATUS, FMA, lease -> desired_binding_state), lease -> uid_len ? dhcp_failover_make_option (FTO_CLIENT_IDENTIFIER, FMA, lease -> uid_len, lease -> uid) : &skip_failover_option, lease -> hardware_addr.hlen ? dhcp_failover_make_option (FTO_CHADDR, FMA, lease -> hardware_addr.hlen, lease -> hardware_addr.hbuf) : &skip_failover_option, dhcp_failover_make_option (FTO_LEASE_EXPIRY, FMA, lease -> ends), dhcp_failover_make_option (FTO_POTENTIAL_EXPIRY, FMA, lease -> tstp), dhcp_failover_make_option (FTO_STOS, FMA, lease -> starts), (lease->cltt != 0) ? dhcp_failover_make_option(FTO_CLTT, FMA, lease->cltt) : &skip_failover_option, /* No CLTT */ flags ? dhcp_failover_make_option(FTO_IP_FLAGS, FMA, flags) : &skip_failover_option, /* No IP_FLAGS */ &skip_failover_option, /* XXX DDNS */ &skip_failover_option, /* XXX request options */ &skip_failover_option, /* XXX reply options */ (failover_option_t *)0)); #if defined (DEBUG_FAILOVER_MESSAGES) if (status != ISC_R_SUCCESS) failover_print (FMA, " (failed)"); failover_print (FMA, ")"); if (obufix) { log_debug ("%s", obuf); } #endif return status; } /* Send a Bind ACK message. */ isc_result_t dhcp_failover_send_bind_ack (dhcp_failover_state_t *state, failover_message_t *msg, int reason, const char *message) { dhcp_failover_link_t *link; isc_result_t status; #if defined (DEBUG_FAILOVER_MESSAGES) char obuf [64]; unsigned obufix = 0; # define FMA obuf, &obufix, sizeof obuf failover_print (FMA, "(bndack"); #else # define FMA (char *)0, (unsigned *)0, 0 #endif if (!state -> link_to_peer || state -> link_to_peer -> type != dhcp_type_failover_link) return DHCP_R_INVALIDARG; link = (dhcp_failover_link_t *)state -> link_to_peer; if (!link -> outer || link -> outer -> type != omapi_type_connection) return DHCP_R_INVALIDARG; if (!message && reason) message = dhcp_failover_reject_reason_print (reason); /* Send the update. */ status = (dhcp_failover_put_message (link, link -> outer, FTM_BNDACK, msg->xid, dhcp_failover_make_option (FTO_ASSIGNED_IP_ADDRESS, FMA, sizeof msg -> assigned_addr, &msg -> assigned_addr), #ifdef DO_BNDACK_SHOULD_NOT dhcp_failover_make_option (FTO_BINDING_STATUS, FMA, msg -> binding_status), (msg -> options_present & FTB_CLIENT_IDENTIFIER) ? dhcp_failover_make_option (FTO_CLIENT_IDENTIFIER, FMA, msg -> client_identifier.count, msg -> client_identifier.data) : &skip_failover_option, (msg -> options_present & FTB_CHADDR) ? dhcp_failover_make_option (FTO_CHADDR, FMA, msg -> chaddr.count, msg -> chaddr.data) : &skip_failover_option, dhcp_failover_make_option (FTO_LEASE_EXPIRY, FMA, msg -> expiry), dhcp_failover_make_option (FTO_POTENTIAL_EXPIRY, FMA, msg -> potential_expiry), dhcp_failover_make_option (FTO_STOS, FMA, msg -> stos), (msg->options_present & FTB_CLTT) ? dhcp_failover_make_option(FTO_CLTT, FMA, msg->cltt) : &skip_failover_option, /* No CLTT in the msg to ack. */ ((msg->options_present & FTB_IP_FLAGS) && msg->ip_flags) ? dhcp_failover_make_option(FTO_IP_FLAGS, FMA, msg->ip_flags) : &skip_failover_option, #endif /* DO_BNDACK_SHOULD_NOT */ reason ? dhcp_failover_make_option(FTO_REJECT_REASON, FMA, reason) : &skip_failover_option, (reason && message) ? dhcp_failover_make_option (FTO_MESSAGE, FMA, strlen (message), message) : &skip_failover_option, #ifdef DO_BNDACK_SHOULD_NOT &skip_failover_option, /* XXX DDNS */ &skip_failover_option, /* XXX request options */ &skip_failover_option, /* XXX reply options */ #endif /* DO_BNDACK_SHOULD_NOT */ (failover_option_t *)0)); #if defined (DEBUG_FAILOVER_MESSAGES) if (status != ISC_R_SUCCESS) failover_print (FMA, " (failed)"); failover_print (FMA, ")"); if (obufix) { log_debug ("%s", obuf); } #endif return status; } isc_result_t dhcp_failover_send_poolreq (dhcp_failover_state_t *state) { dhcp_failover_link_t *link; isc_result_t status; #if defined (DEBUG_FAILOVER_MESSAGES) char obuf [64]; unsigned obufix = 0; # define FMA obuf, &obufix, sizeof obuf failover_print (FMA, "(poolreq"); #else # define FMA (char *)0, (unsigned *)0, 0 #endif if (!state -> link_to_peer || state -> link_to_peer -> type != dhcp_type_failover_link) return DHCP_R_INVALIDARG; link = (dhcp_failover_link_t *)state -> link_to_peer; if (!link -> outer || link -> outer -> type != omapi_type_connection) return DHCP_R_INVALIDARG; status = (dhcp_failover_put_message (link, link -> outer, FTM_POOLREQ, link->xid++, (failover_option_t *)0)); #if defined (DEBUG_FAILOVER_MESSAGES) if (status != ISC_R_SUCCESS) failover_print (FMA, " (failed)"); failover_print (FMA, ")"); if (obufix) { log_debug ("%s", obuf); } #endif return status; } isc_result_t dhcp_failover_send_poolresp (dhcp_failover_state_t *state, int leases) { dhcp_failover_link_t *link; isc_result_t status; #if defined (DEBUG_FAILOVER_MESSAGES) char obuf [64]; unsigned obufix = 0; # define FMA obuf, &obufix, sizeof obuf failover_print (FMA, "(poolresp"); #else # define FMA (char *)0, (unsigned *)0, 0 #endif if (!state -> link_to_peer || state -> link_to_peer -> type != dhcp_type_failover_link) return DHCP_R_INVALIDARG; link = (dhcp_failover_link_t *)state -> link_to_peer; if (!link -> outer || link -> outer -> type != omapi_type_connection) return DHCP_R_INVALIDARG; status = (dhcp_failover_put_message (link, link -> outer, FTM_POOLRESP, link->imsg->xid, dhcp_failover_make_option (FTO_ADDRESSES_TRANSFERRED, FMA, leases), (failover_option_t *)0)); #if defined (DEBUG_FAILOVER_MESSAGES) if (status != ISC_R_SUCCESS) failover_print (FMA, " (failed)"); failover_print (FMA, ")"); if (obufix) { log_debug ("%s", obuf); } #endif return status; } isc_result_t dhcp_failover_send_update_request (dhcp_failover_state_t *state) { dhcp_failover_link_t *link; isc_result_t status; #if defined (DEBUG_FAILOVER_MESSAGES) char obuf [64]; unsigned obufix = 0; # define FMA obuf, &obufix, sizeof obuf failover_print (FMA, "(updreq"); #else # define FMA (char *)0, (unsigned *)0, 0 #endif if (!state -> link_to_peer || state -> link_to_peer -> type != dhcp_type_failover_link) return DHCP_R_INVALIDARG; link = (dhcp_failover_link_t *)state -> link_to_peer; if (!link -> outer || link -> outer -> type != omapi_type_connection) return DHCP_R_INVALIDARG; if (state -> curUPD) return ISC_R_ALREADYRUNNING; status = (dhcp_failover_put_message (link, link -> outer, FTM_UPDREQ, link->xid++, (failover_option_t *)0)); if (status == ISC_R_SUCCESS) state -> curUPD = FTM_UPDREQ; #if defined (DEBUG_FAILOVER_MESSAGES) if (status != ISC_R_SUCCESS) failover_print (FMA, " (failed)"); failover_print (FMA, ")"); if (obufix) { log_debug ("%s", obuf); } #endif log_info ("Sent update request message to %s", state -> name); return status; } isc_result_t dhcp_failover_send_update_request_all (dhcp_failover_state_t *state) { dhcp_failover_link_t *link; isc_result_t status; #if defined (DEBUG_FAILOVER_MESSAGES) char obuf [64]; unsigned obufix = 0; # define FMA obuf, &obufix, sizeof obuf failover_print (FMA, "(updreqall"); #else # define FMA (char *)0, (unsigned *)0, 0 #endif if (!state -> link_to_peer || state -> link_to_peer -> type != dhcp_type_failover_link) return DHCP_R_INVALIDARG; link = (dhcp_failover_link_t *)state -> link_to_peer; if (!link -> outer || link -> outer -> type != omapi_type_connection) return DHCP_R_INVALIDARG; /* If there is an UPDREQ in progress, then upgrade to UPDREQALL. */ if (state -> curUPD && (state -> curUPD != FTM_UPDREQ)) return ISC_R_ALREADYRUNNING; status = (dhcp_failover_put_message (link, link -> outer, FTM_UPDREQALL, link->xid++, (failover_option_t *)0)); if (status == ISC_R_SUCCESS) state -> curUPD = FTM_UPDREQALL; #if defined (DEBUG_FAILOVER_MESSAGES) if (status != ISC_R_SUCCESS) failover_print (FMA, " (failed)"); failover_print (FMA, ")"); if (obufix) { log_debug ("%s", obuf); } #endif log_info ("Sent update request all message to %s", state -> name); return status; } isc_result_t dhcp_failover_send_update_done (dhcp_failover_state_t *state) { dhcp_failover_link_t *link; isc_result_t status; #if defined (DEBUG_FAILOVER_MESSAGES) char obuf [64]; unsigned obufix = 0; # define FMA obuf, &obufix, sizeof obuf failover_print (FMA, "(upddone"); #else # define FMA (char *)0, (unsigned *)0, 0 #endif if (!state -> link_to_peer || state -> link_to_peer -> type != dhcp_type_failover_link) return DHCP_R_INVALIDARG; link = (dhcp_failover_link_t *)state -> link_to_peer; if (!link -> outer || link -> outer -> type != omapi_type_connection) return DHCP_R_INVALIDARG; status = (dhcp_failover_put_message (link, link -> outer, FTM_UPDDONE, state->updxid, (failover_option_t *)0)); #if defined (DEBUG_FAILOVER_MESSAGES) if (status != ISC_R_SUCCESS) failover_print (FMA, " (failed)"); failover_print (FMA, ")"); if (obufix) { log_debug ("%s", obuf); } #endif log_info ("Sent update done message to %s", state -> name); state->updxid--; /* Paranoia, just so it mismatches. */ /* There may be uncommitted leases at this point (since dhcp_failover_process_bind_ack() doesn't commit leases); commit the lease file. */ commit_leases(); return status; } /* * failover_lease_is_better() compares the binding update in 'msg' with * the current lease in 'lease'. If the determination is that the binding * update shouldn't be allowed to update/crush more critical binding info * on the lease, the lease is preferred. A value of true is returned if the * local lease is preferred, or false if the remote binding update is * preferred. * * For now this function is hopefully simplistic and trivial. It may be that * a more detailed system of preferences is required, so this is something we * should monitor as we gain experience with these dueling events. */ static isc_boolean_t failover_lease_is_better(dhcp_failover_state_t *state, struct lease *lease, failover_message_t *msg) { binding_state_t local_state; TIME msg_cltt; if (lease->binding_state != lease->desired_binding_state) local_state = lease->desired_binding_state; else local_state = lease->binding_state; if ((msg->options_present & FTB_CLTT) != 0) msg_cltt = msg->cltt; else msg_cltt = 0; switch(local_state) { case FTS_ACTIVE: if (msg->binding_status == FTS_ACTIVE) { if (msg_cltt < lease->cltt) return ISC_TRUE; else if (msg_cltt > lease->cltt) return ISC_FALSE; else if (state->i_am == primary) return ISC_TRUE; else return ISC_FALSE; } else if (msg->binding_status == FTS_EXPIRED) { return ISC_FALSE; } /* FALL THROUGH */ case FTS_FREE: case FTS_BACKUP: case FTS_EXPIRED: case FTS_RELEASED: case FTS_ABANDONED: case FTS_RESET: if (msg->binding_status == FTS_ACTIVE) return ISC_FALSE; else if (state->i_am == primary) return ISC_TRUE; else return ISC_FALSE; /* FALL THROUGH to impossible condition */ default: log_fatal("Impossible condition at %s:%d.", MDL); } log_fatal("Impossible condition at %s:%d.", MDL); /* Silence compiler warning. */ return ISC_FALSE; } isc_result_t dhcp_failover_process_bind_update (dhcp_failover_state_t *state, failover_message_t *msg) { struct lease *lt, *lease; struct iaddr ia; int reason = FTR_MISC_REJECT; const char *message; int new_binding_state; int send_to_backup = 0; int required_options; isc_boolean_t chaddr_changed = ISC_FALSE; isc_boolean_t ident_changed = ISC_FALSE; /* Validate the binding update. */ required_options = FTB_ASSIGNED_IP_ADDRESS | FTB_BINDING_STATUS; if ((msg->options_present & required_options) != required_options) { message = "binding update lacks required options"; reason = FTR_MISSING_BINDINFO; goto bad; } ia.len = sizeof msg -> assigned_addr; memcpy (ia.iabuf, &msg -> assigned_addr, ia.len); lease = (struct lease *)0; lt = (struct lease *)0; if (!find_lease_by_ip_addr (&lease, ia, MDL)) { message = "unknown IP address"; reason = FTR_ILLEGAL_IP_ADDR; goto bad; } /* * If this lease is covered by a different failover peering * relationship, assert an error. */ if ((lease->pool == NULL) || (lease->pool->failover_peer == NULL) || (lease->pool->failover_peer != state)) { message = "IP address is covered by a different failover " "relationship state"; reason = FTR_ILLEGAL_IP_ADDR; goto bad; } /* * Dueling updates: This happens when both servers send a BNDUPD * at the same time. We want the best update to win, which means * we reject if we think ours is better, or cancel if we think the * peer's is better. We only assert a problem if the lease is on * the ACK queue, not on the UPDATE queue. This means that after * accepting this server's BNDUPD, we will send our own BNDUPD * /after/ sending the BNDACK (this order was recently enforced in * queue processing). */ if ((lease->flags & ON_ACK_QUEUE) != 0) { if (failover_lease_is_better(state, lease, msg)) { message = "incoming update is less critical than " "outgoing update"; reason = FTR_LESS_CRIT_BIND_INFO; goto bad; } else { /* This makes it so we ignore any spurious ACKs. */ dhcp_failover_ack_queue_remove(state, lease); } } /* Install the new info. Start by taking a copy to markup. */ if (!lease_copy (<, lease, MDL)) { message = "no memory"; goto bad; } if (msg -> options_present & FTB_CHADDR) { if (msg->binding_status == FTS_ABANDONED) { message = "BNDUPD to ABANDONED with a CHADDR"; goto bad; } if (msg -> chaddr.count > sizeof lt -> hardware_addr.hbuf) { message = "chaddr too long"; goto bad; } if ((lt->hardware_addr.hlen != msg->chaddr.count) || (memcmp(lt->hardware_addr.hbuf, msg->chaddr.data, msg->chaddr.count) != 0)) chaddr_changed = ISC_TRUE; lt -> hardware_addr.hlen = msg -> chaddr.count; memcpy (lt -> hardware_addr.hbuf, msg -> chaddr.data, msg -> chaddr.count); } else if (msg->binding_status == FTS_ACTIVE || msg->binding_status == FTS_EXPIRED || msg->binding_status == FTS_RELEASED) { message = "BNDUPD without CHADDR"; reason = FTR_MISSING_BINDINFO; goto bad; } else if (msg->binding_status == FTS_ABANDONED) { chaddr_changed = ISC_TRUE; lt->hardware_addr.hlen = 0; if (lt->scope) binding_scope_dereference(<->scope, MDL); } /* There is no explicit message content to indicate that the client * supplied no client-identifier. So if we don't hear of a value, * we discard the last one. */ if (msg->options_present & FTB_CLIENT_IDENTIFIER) { if (msg->binding_status == FTS_ABANDONED) { message = "BNDUPD to ABANDONED with client-id"; goto bad; } if ((lt->uid_len != msg->client_identifier.count) || (lt->uid == NULL) || /* Sanity; should never happen. */ (memcmp(lt->uid, msg->client_identifier.data, lt->uid_len) != 0)) ident_changed = ISC_TRUE; lt->uid_len = msg->client_identifier.count; /* Allocate the lt->uid buffer if we haven't already, or * re-allocate the lt-uid buffer if we have one that is not * large enough. Otherwise, just use the extant buffer. */ if (!lt->uid || lt->uid == lt->uid_buf || lt->uid_len > lt->uid_max) { if (lt->uid && lt->uid != lt->uid_buf) dfree(lt->uid, MDL); if (lt->uid_len > sizeof(lt->uid_buf)) { lt->uid_max = lt->uid_len; lt->uid = dmalloc(lt->uid_len, MDL); if (!lt->uid) { message = "no memory"; goto bad; } } else { lt->uid_max = sizeof(lt->uid_buf); lt->uid = lt->uid_buf; } } memcpy (lt -> uid, msg -> client_identifier.data, lt -> uid_len); } else if (lt->uid && msg->binding_status != FTS_RESET && msg->binding_status != FTS_FREE && msg->binding_status != FTS_BACKUP) { ident_changed = ISC_TRUE; if (lt->uid != lt->uid_buf) dfree (lt->uid, MDL); lt->uid = NULL; lt->uid_max = lt->uid_len = 0; } /* * A server's configuration can assign a 'binding scope'; * * set var = "value"; * * The problem with these binding scopes is that they are refreshed * when the server processes a client's DHCP packet. A local binding * scope is trash, then, when the lease has been assigned by the * partner server. There is no real way to detect this, a peer may * be updating us (as through potential conflict) with a binding we * sent them, but we can trivially detect the /problematic/ case; * * lease is free. * primary allocates lease to client A, assigns ddns name A. * primary fails. * secondary enters partner down. * lease expires, and is set free. * lease is allocated to client B and given ddns name B. * primary recovers. * * The binding update in this case will be active->active, but the * client identification on the lease will have changed. The ddns * update on client A will have leaked if we just remove the binding * scope blindly. */ if (msg->binding_status == FTS_ACTIVE && (chaddr_changed || ident_changed)) { (void) ddns_removals(lease, NULL, NULL, ISC_FALSE); if (lease->scope != NULL) binding_scope_dereference(&lease->scope, MDL); } /* XXX Times may need to be adjusted based on clock skew! */ if (msg -> options_present & FTB_STOS) { lt -> starts = msg -> stos; } if (msg -> options_present & FTB_LEASE_EXPIRY) { lt -> ends = msg -> expiry; } if (msg->options_present & FTB_POTENTIAL_EXPIRY) { lt->atsfp = lt->tsfp = msg->potential_expiry; } if (msg->options_present & FTB_IP_FLAGS) { if (msg->ip_flags & FTF_IP_FLAG_RESERVE) { if ((((state->i_am == primary) && (lease->binding_state == FTS_FREE)) || ((state->i_am == secondary) && (lease->binding_state == FTS_BACKUP))) && !(lease->flags & RESERVED_LEASE)) { message = "Address is not reserved."; reason = FTR_IP_NOT_RESERVED; goto bad; } lt->flags |= RESERVED_LEASE; } else lt->flags &= ~RESERVED_LEASE; if (msg->ip_flags & FTF_IP_FLAG_BOOTP) { if ((((state->i_am == primary) && (lease->binding_state == FTS_FREE)) || ((state->i_am == secondary) && (lease->binding_state == FTS_BACKUP))) && !(lease->flags & BOOTP_LEASE)) { message = "Address is not allocated to BOOTP."; goto bad; } lt->flags |= BOOTP_LEASE; } else lt->flags &= ~BOOTP_LEASE; if (msg->ip_flags & ~(FTF_IP_FLAG_RESERVE | FTF_IP_FLAG_BOOTP)) log_info("Unknown IP-flags set in BNDUPD (0x%x).", msg->ip_flags); } else /* Flags may only not appear if the values are zero. */ lt->flags &= ~(RESERVED_LEASE | BOOTP_LEASE); #if defined (DEBUG_LEASE_STATE_TRANSITIONS) log_info ("processing state transition for %s: %s to %s", piaddr (lease -> ip_addr), binding_state_print (lease -> binding_state), binding_state_print (msg -> binding_status)); #endif /* If we're in normal state, make sure the state transition we got is valid. */ if (state -> me.state == normal) { new_binding_state = (normal_binding_state_transition_check (lease, state, msg -> binding_status, msg -> potential_expiry)); /* XXX if the transition the peer asked for isn't XXX allowed, maybe we should make the transition XXX into potential-conflict at this point. */ } else { new_binding_state = (conflict_binding_state_transition_check (lease, state, msg -> binding_status, msg -> potential_expiry)); } if (new_binding_state != msg -> binding_status) { char outbuf [100]; if (snprintf (outbuf, sizeof outbuf, "%s: invalid state transition: %s to %s", piaddr (lease -> ip_addr), binding_state_print (lease -> binding_state), binding_state_print (msg -> binding_status)) >= sizeof outbuf) log_fatal ("%s: impossible outbuf overflow", "dhcp_failover_process_bind_update"); dhcp_failover_send_bind_ack (state, msg, FTR_FATAL_CONFLICT, outbuf); goto out; } if (new_binding_state == FTS_EXPIRED || new_binding_state == FTS_RELEASED || new_binding_state == FTS_RESET) { lt -> next_binding_state = FTS_FREE; /* Mac address affinity. Assign the lease to * BACKUP state if we are the primary and the * peer is more likely to reallocate this lease * to a returning client. */ if ((state->i_am == primary) && !(lt->flags & (RESERVED_LEASE | BOOTP_LEASE))) send_to_backup = peer_wants_lease(lt); } else { lt -> next_binding_state = new_binding_state; } msg -> binding_status = lt -> next_binding_state; /* * If we accept a peer's binding update, then we can't rewind a * lease behind the peer's state. */ lease->rewind_binding_state = lt->next_binding_state; /* Try to install the new information. */ if (!supersede_lease (lease, lt, 0, 0, 0) || !write_lease (lease)) { message = "database update failed"; bad: dhcp_failover_send_bind_ack (state, msg, reason, message); goto out; } else { dhcp_failover_queue_ack (state, msg); } /* If it is probably wise, assign lease to backup state if the peer * is not already hoarding leases. */ if (send_to_backup && secondary_not_hoarding(state, lease->pool)) { lease->next_binding_state = FTS_BACKUP; lease->tstp = cur_time; lease->starts = cur_time; if (!supersede_lease(lease, NULL, 0, 1, 0) || !write_lease(lease)) log_error("can't commit lease %s for mac addr " "affinity", piaddr(lease->ip_addr)); dhcp_failover_send_updates(state); } out: if (lt) lease_dereference (<, MDL); if (lease) lease_dereference (&lease, MDL); return ISC_R_SUCCESS; } /* This was hairy enough I didn't want to do it all in an if statement. * * Returns: Truth is the secondary is allowed to get more leases based upon * MAC address affinity. False otherwise. */ static inline int secondary_not_hoarding(dhcp_failover_state_t *state, struct pool *p) { int total; int hold; int lts; total = p->free_leases + p->backup_leases; /* How many leases is one side or the other allowed to "hold"? */ hold = ((total * state->max_lease_ownership) + 50) / 100; /* If we were to send leases (or if the secondary were to send us * leases in the negative direction), how many would that be? */ lts = (p->free_leases - p->backup_leases) / 2; /* The peer is not hoarding leases if we would send them more leases * (or they would take fewer leases) than the maximum they are allowed * to hold (the negative hold). */ return(lts > -hold); } isc_result_t dhcp_failover_process_bind_ack (dhcp_failover_state_t *state, failover_message_t *msg) { struct lease *lt = (struct lease *)0; struct lease *lease = (struct lease *)0; struct iaddr ia; const char *message = "no memory"; u_int32_t pot_expire; int send_to_backup = ISC_FALSE; struct timeval tv; ia.len = sizeof msg -> assigned_addr; memcpy (ia.iabuf, &msg -> assigned_addr, ia.len); if (!find_lease_by_ip_addr (&lease, ia, MDL)) { message = "no such lease"; goto bad; } /* XXX check for conflicts. */ if (msg -> options_present & FTB_REJECT_REASON) { log_error ("bind update on %s from %s rejected: %.*s", piaddr (ia), state -> name, (int)((msg -> options_present & FTB_MESSAGE) ? msg -> message.count : strlen (dhcp_failover_reject_reason_print (msg -> reject_reason))), (msg -> options_present & FTB_MESSAGE) ? (const char *)(msg -> message.data) : (dhcp_failover_reject_reason_print (msg -> reject_reason))); goto unqueue; } /* Silently discard acks for leases we did not update (or multiple * acks). */ if (!lease->last_xid) goto unqueue; if (lease->last_xid != msg->xid) { message = "xid mismatch"; goto bad; } /* XXX Times may need to be adjusted based on clock skew! */ if (msg->options_present & FTO_POTENTIAL_EXPIRY) pot_expire = msg->potential_expiry; else pot_expire = lease->tstp; /* If the lease was desired to enter a binding state, we set * such a value upon transmitting a bndupd. We do not clear it * if we receive a bndupd in the meantime (or change the state * of the lease again ourselves), but we do set binding_state * if we get a bndupd. * * So desired_binding_state tells us what we sent a bndupd for, * and binding_state tells us what we have since determined in * the meantime. */ if (lease->desired_binding_state == FTS_EXPIRED || lease->desired_binding_state == FTS_RESET || lease->desired_binding_state == FTS_RELEASED) { /* It is not a problem to do this directly as we call * supersede_lease immediately after: the lease is requeued * even if its sort order (tsfp) has changed. */ lease->atsfp = lease->tsfp = pot_expire; if ((state->i_am == secondary) && (lease->flags & RESERVED_LEASE)) lease->next_binding_state = FTS_BACKUP; else lease->next_binding_state = FTS_FREE; /* Clear this condition for the next go-round. */ lease->desired_binding_state = lease->next_binding_state; /* The peer will have made this state change, so set rewind. */ lease->rewind_binding_state = lease->next_binding_state; supersede_lease(lease, (struct lease *)0, 0, 0, 0); write_lease(lease); /* Lease has returned to FREE state from the * transitional states. If the lease 'belongs' * to a client that would be served by the * peer, process a binding update now to send * the lease to backup state. But not if we * think we already have. */ if (state->i_am == primary && !(lease->flags & (RESERVED_LEASE | BOOTP_LEASE)) && peer_wants_lease(lease)) send_to_backup = ISC_TRUE; if (!send_to_backup && state->me.state == normal) commit_leases(); } else { /* XXX It could be a problem to do this directly if the lease * XXX is sorted by tsfp. */ lease->atsfp = lease->tsfp = pot_expire; if (lease->desired_binding_state != lease->binding_state) { lease->next_binding_state = lease->desired_binding_state; supersede_lease(lease, (struct lease *)0, 0, 0, 0); } write_lease(lease); /* Commit the lease only after a two-second timeout, so that if we get a bunch of acks in quick succession (e.g., when stealing leases from the secondary), we do not do an immediate commit for each one. */ tv.tv_sec = cur_time + 2; tv.tv_usec = 0; add_timeout(&tv, commit_leases_timeout, (void *)0, 0, 0); } unqueue: dhcp_failover_ack_queue_remove (state, lease); /* If we are supposed to send an update done after we send this lease, go ahead and send it. */ if (state -> send_update_done == lease) { lease_dereference (&state -> send_update_done, MDL); dhcp_failover_send_update_done (state); } /* Now that the lease is off the ack queue, consider putting it * back on the update queue for mac address affinity. */ if (send_to_backup && secondary_not_hoarding(state, lease->pool)) { lease->next_binding_state = FTS_BACKUP; lease->tstp = lease->starts = cur_time; if (!supersede_lease(lease, NULL, 0, 1, 0) || !write_lease(lease)) log_error("can't commit lease %s for " "client affinity", piaddr(lease->ip_addr)); if (state->me.state == normal) commit_leases(); } /* If there are updates pending, we've created space to send at least one. */ dhcp_failover_send_updates (state); out: lease_dereference (&lease, MDL); if (lt) lease_dereference (<, MDL); return ISC_R_SUCCESS; bad: log_info ("bind update on %s got ack from %s: %s.", piaddr (ia), state -> name, message); goto out; } isc_result_t dhcp_failover_generate_update_queue (dhcp_failover_state_t *state, int everythingp) { struct shared_network *s; struct pool *p; struct lease *l; int i; #define FREE_LEASES 0 #define ACTIVE_LEASES 1 #define EXPIRED_LEASES 2 #define ABANDONED_LEASES 3 #define BACKUP_LEASES 4 #define RESERVED_LEASES 5 struct lease **lptr[RESERVED_LEASES+1]; /* Loop through each pool in each shared network and call the expiry routine on the pool. */ for (s = shared_networks; s; s = s -> next) { for (p = s -> pools; p; p = p -> next) { if (p->failover_peer != state) continue; lptr[FREE_LEASES] = &p->free; lptr[ACTIVE_LEASES] = &p->active; lptr[EXPIRED_LEASES] = &p->expired; lptr[ABANDONED_LEASES] = &p->abandoned; lptr[BACKUP_LEASES] = &p->backup; lptr[RESERVED_LEASES] = &p->reserved; for (i = FREE_LEASES; i <= RESERVED_LEASES; i++) { for (l = *(lptr [i]); l; l = l -> next) { if ((l->flags & ON_QUEUE) == 0 && (everythingp || (l->tstp > l->atsfp) || (i == EXPIRED_LEASES))) { l -> desired_binding_state = l -> binding_state; dhcp_failover_queue_update (l, 0); } } } } } return ISC_R_SUCCESS; } isc_result_t dhcp_failover_process_update_request (dhcp_failover_state_t *state, failover_message_t *msg) { if (state->send_update_done) { log_info("Received update request while old update still " "flying! Silently discarding old request."); lease_dereference(&state->send_update_done, MDL); } /* Generate a fresh update queue. */ dhcp_failover_generate_update_queue (state, 0); state->updxid = msg->xid; /* If there's anything on the update queue (there shouldn't be anything on the ack queue), trigger an update done message when we get an ack for that lease. */ if (state -> update_queue_tail) { lease_reference (&state -> send_update_done, state -> update_queue_tail, MDL); dhcp_failover_send_updates (state); log_info ("Update request from %s: sending update", state -> name); } else { /* Otherwise, there are no updates to send, so we can just send an UPDDONE message immediately. */ dhcp_failover_send_update_done (state); log_info ("Update request from %s: nothing pending", state -> name); } return ISC_R_SUCCESS; } isc_result_t dhcp_failover_process_update_request_all (dhcp_failover_state_t *state, failover_message_t *msg) { if (state->send_update_done) { log_info("Received update request while old update still " "flying! Silently discarding old request."); lease_dereference(&state->send_update_done, MDL); } /* Generate a fresh update queue that includes every lease. */ dhcp_failover_generate_update_queue (state, 1); state->updxid = msg->xid; if (state -> update_queue_tail) { lease_reference (&state -> send_update_done, state -> update_queue_tail, MDL); dhcp_failover_send_updates (state); log_info ("Update request all from %s: sending update", state -> name); } else { /* This should really never happen, but it could happen on a server that currently has no leases configured. */ dhcp_failover_send_update_done (state); log_info ("Update request all from %s: nothing pending", state -> name); } return ISC_R_SUCCESS; } isc_result_t dhcp_failover_process_update_done (dhcp_failover_state_t *state, failover_message_t *msg) { struct timeval tv; log_info ("failover peer %s: peer update completed.", state -> name); state -> curUPD = 0; switch (state -> me.state) { case unknown_state: case partner_down: case normal: case communications_interrupted: case resolution_interrupted: case shut_down: case paused: case recover_done: case startup: case recover_wait: break; /* shouldn't happen. */ /* We got the UPDDONE, so we can go into normal state! */ case potential_conflict: if (state->partner.state == conflict_done) { if (state->i_am == secondary) { dhcp_failover_set_state (state, normal); } else { log_error("Secondary is in conflict_done " "state after conflict resolution, " "this is illegal."); dhcp_failover_set_state (state, shut_down); } } else { if (state->i_am == primary) dhcp_failover_set_state (state, conflict_done); else log_error("Spurious update-done message."); } break; case conflict_done: log_error("Spurious update-done message."); break; case recover: /* Wait for MCLT to expire before moving to recover_done, except that if both peers come up in recover, there is no point in waiting for MCLT to expire - this probably indicates the initial startup of a newly-configured failover pair. */ if (state -> me.stos + state -> mclt > cur_time && state -> partner.state != recover && state -> partner.state != recover_done) { dhcp_failover_set_state (state, recover_wait); #if defined (DEBUG_FAILOVER_TIMING) log_info ("add_timeout +%d %s", (int)(cur_time - state -> me.stos + state -> mclt), "dhcp_failover_recover_done"); #endif tv . tv_sec = (int)(state -> me.stos + state -> mclt); tv . tv_usec = 0; add_timeout (&tv, dhcp_failover_recover_done, state, (tvref_t)omapi_object_reference, (tvunref_t) omapi_object_dereference); } else dhcp_failover_recover_done (state); } return ISC_R_SUCCESS; } void dhcp_failover_recover_done (void *sp) { dhcp_failover_state_t *state = sp; #if defined (DEBUG_FAILOVER_TIMING) log_info ("dhcp_failover_recover_done"); #endif dhcp_failover_set_state (state, recover_done); } #if defined (DEBUG_FAILOVER_MESSAGES) /* Print hunks of failover messages, doing line breaks as appropriate. Note that this assumes syslog is being used, rather than, e.g., the Windows NT logging facility, where just dumping the whole message in one hunk would be more appropriate. */ void failover_print (char *obuf, unsigned *obufix, unsigned obufmax, const char *s) { int len = strlen (s); while (len + *obufix + 1 >= obufmax) { log_debug ("%s", obuf); if (!*obufix) { log_debug ("%s", s); *obufix = 0; return; } *obufix = 0; } strcpy (&obuf [*obufix], s); *obufix += len; } #endif /* defined (DEBUG_FAILOVER_MESSAGES) */ /* Taken from draft-ietf-dhc-loadb-01.txt: */ /* A "mixing table" of 256 distinct values, in pseudo-random order. */ unsigned char loadb_mx_tbl[256] = { 251, 175, 119, 215, 81, 14, 79, 191, 103, 49, 181, 143, 186, 157, 0, 232, 31, 32, 55, 60, 152, 58, 17, 237, 174, 70, 160, 144, 220, 90, 57, 223, 59, 3, 18, 140, 111, 166, 203, 196, 134, 243, 124, 95, 222, 179, 197, 65, 180, 48, 36, 15, 107, 46, 233, 130, 165, 30, 123, 161, 209, 23, 97, 16, 40, 91, 219, 61, 100, 10, 210, 109, 250, 127, 22, 138, 29, 108, 244, 67, 207, 9, 178, 204, 74, 98, 126, 249, 167, 116, 34, 77, 193, 200, 121, 5, 20, 113, 71, 35, 128, 13, 182, 94, 25, 226, 227, 199, 75, 27, 41, 245, 230, 224, 43, 225, 177, 26, 155, 150, 212, 142, 218, 115, 241, 73, 88, 105, 39, 114, 62, 255, 192, 201, 145, 214, 168, 158, 221, 148, 154, 122, 12, 84, 82, 163, 44, 139, 228, 236, 205, 242, 217, 11, 187, 146, 159, 64, 86, 239, 195, 42, 106, 198, 118, 112, 184, 172, 87, 2, 173, 117, 176, 229, 247, 253, 137, 185, 99, 164, 102, 147, 45, 66, 231, 52, 141, 211, 194, 206, 246, 238, 56, 110, 78, 248, 63, 240, 189, 93, 92, 51, 53, 183, 19, 171, 72, 50, 33, 104, 101, 69, 8, 252, 83, 120, 76, 135, 85, 54, 202, 125, 188, 213, 96, 235, 136, 208, 162, 129, 190, 132, 156, 38, 47, 1, 7, 254, 24, 4, 216, 131, 89, 21, 28, 133, 37, 153, 149, 80, 170, 68, 6, 169, 234, 151 }; static unsigned char loadb_p_hash (const unsigned char *, unsigned); static unsigned char loadb_p_hash (const unsigned char *key, unsigned len) { unsigned char hash = len; int i; for(i = len; i > 0; ) hash = loadb_mx_tbl [hash ^ (key [--i])]; return hash; } int load_balance_mine (struct packet *packet, dhcp_failover_state_t *state) { struct option_cache *oc; struct data_string ds; unsigned char hbaix; int hm; if (state -> load_balance_max_secs < ntohs (packet -> raw -> secs)) { return 1; } /* If we don't have a hash bucket array, we can't tell if this one's ours, so we assume it's not. */ if (!state -> hba) return 0; oc = lookup_option (&dhcp_universe, packet -> options, DHO_DHCP_CLIENT_IDENTIFIER); memset (&ds, 0, sizeof ds); if (oc && evaluate_option_cache (&ds, packet, (struct lease *)0, (struct client_state *)0, packet -> options, (struct option_state *)0, &global_scope, oc, MDL)) { hbaix = loadb_p_hash (ds.data, ds.len); data_string_forget(&ds, MDL); } else { hbaix = loadb_p_hash (packet -> raw -> chaddr, packet -> raw -> hlen); } hm = state->hba[(hbaix >> 3) & 0x1F] & (1 << (hbaix & 0x07)); if (state -> i_am == primary) return hm; else return !hm; } /* The inverse of load_balance_mine ("load balance theirs"). We can't * use the regular load_balance_mine() and invert it because of the case * where there might not be an HBA, and we want to indicate false here * in this case only. */ int peer_wants_lease(struct lease *lp) { dhcp_failover_state_t *state; unsigned char hbaix; int hm; if (!lp->pool) return 0; state = lp->pool->failover_peer; if (!state || !state->hba) return 0; if (lp->uid_len) hbaix = loadb_p_hash(lp->uid, lp->uid_len); else if (lp->hardware_addr.hlen > 1) /* Skip the first byte, which is the hardware type, and is * not included during actual load balancing checks above * since it is separate from the packet header chaddr field. * The remainder of the hardware address should be identical * to the chaddr contents. */ hbaix = loadb_p_hash(lp->hardware_addr.hbuf + 1, lp->hardware_addr.hlen - 1); else /* impossible to categorize into LBA */ return 0; hm = state->hba[(hbaix >> 3) & 0x1F] & (1 << (hbaix & 0x07)); if (state->i_am == primary) return !hm; else return hm; } /* This deals with what to do with bind updates when we're in the normal state Note that tsfp had better be set from the latest bind update _before_ this function is called! */ binding_state_t normal_binding_state_transition_check (struct lease *lease, dhcp_failover_state_t *state, binding_state_t binding_state, u_int32_t tsfp) { binding_state_t new_state; /* If there is no transition, it's no problem. */ if (binding_state == lease -> binding_state) return binding_state; switch (lease -> binding_state) { case FTS_FREE: case FTS_ABANDONED: switch (binding_state) { case FTS_ACTIVE: case FTS_ABANDONED: case FTS_BACKUP: case FTS_EXPIRED: case FTS_RELEASED: case FTS_RESET: /* If the lease was free, and our peer is primary, then it can make it active, or abandoned, or backup. Abandoned is treated like free in this case. */ if (state -> i_am == secondary) return binding_state; /* Otherwise, it can't legitimately do any sort of state transition. Because the lease was free, and the error has already been made, we allow the peer to change its state anyway, but log a warning message in hopes that the error will be fixed. */ case FTS_FREE: /* for compiler */ new_state = binding_state; goto out; default: log_fatal ("Impossible case at %s:%d.", MDL); return FTS_RESET; } case FTS_ACTIVE: /* The secondary can't change the state of an active lease. */ if (state -> i_am == primary) { /* Except that the client may send the DHCPRELEASE to the secondary, and we have to accept that. */ if (binding_state == FTS_RELEASED) return binding_state; new_state = lease -> binding_state; goto out; } /* So this is only for transitions made by the primary: */ switch (binding_state) { case FTS_FREE: case FTS_BACKUP: /* Can't set a lease to free or backup until the peer agrees that it's expired. */ if (tsfp > cur_time) { new_state = lease -> binding_state; goto out; } return binding_state; case FTS_EXPIRED: /* XXX 65 should be the clock skew between the peers XXX plus a fudge factor. This code will result XXX in problems if MCLT is really short or the XXX max-lease-time is really short (less than the XXX fudge factor. */ if (lease -> ends - 65 > cur_time) { new_state = lease -> binding_state; goto out; } case FTS_RELEASED: case FTS_ABANDONED: case FTS_RESET: case FTS_ACTIVE: return binding_state; default: log_fatal ("Impossible case at %s:%d.", MDL); return FTS_RESET; } break; case FTS_EXPIRED: switch (binding_state) { case FTS_BACKUP: case FTS_FREE: /* Can't set a lease to free or backup until the peer agrees that it's expired. */ if (tsfp > cur_time) { new_state = lease -> binding_state; goto out; } return binding_state; case FTS_ACTIVE: case FTS_RELEASED: case FTS_ABANDONED: case FTS_RESET: case FTS_EXPIRED: return binding_state; default: log_fatal ("Impossible case at %s:%d.", MDL); return FTS_RESET; } case FTS_RELEASED: switch (binding_state) { case FTS_FREE: case FTS_BACKUP: /* These are invalid state transitions - should we prevent them? */ case FTS_EXPIRED: case FTS_ABANDONED: case FTS_RESET: case FTS_ACTIVE: case FTS_RELEASED: return binding_state; default: log_fatal ("Impossible case at %s:%d.", MDL); return FTS_RESET; } case FTS_RESET: switch (binding_state) { case FTS_FREE: case FTS_BACKUP: /* Can't set a lease to free or backup until the peer agrees that it's expired. */ if (tsfp > cur_time) { new_state = lease -> binding_state; goto out; } return binding_state; case FTS_ACTIVE: case FTS_EXPIRED: case FTS_RELEASED: case FTS_ABANDONED: case FTS_RESET: return binding_state; default: log_fatal ("Impossible case at %s:%d.", MDL); return FTS_RESET; } case FTS_BACKUP: switch (binding_state) { case FTS_ACTIVE: case FTS_ABANDONED: case FTS_EXPIRED: case FTS_RELEASED: case FTS_RESET: /* If the lease was in backup, and our peer is secondary, then it can make it active or abandoned. */ if (state -> i_am == primary) return binding_state; /* Either the primary or the secondary can reasonably move a lease from the backup state to the free state. */ case FTS_FREE: return binding_state; case FTS_BACKUP: new_state = lease -> binding_state; goto out; default: log_fatal ("Impossible case at %s:%d.", MDL); return FTS_RESET; } default: log_fatal ("Impossible case at %s:%d.", MDL); return FTS_RESET; } out: return new_state; } /* Determine whether the state transition is okay when we're potentially in conflict with the peer. */ binding_state_t conflict_binding_state_transition_check (struct lease *lease, dhcp_failover_state_t *state, binding_state_t binding_state, u_int32_t tsfp) { binding_state_t new_state; /* If there is no transition, it's no problem. */ if (binding_state == lease -> binding_state) new_state = binding_state; else { switch (lease -> binding_state) { /* If we think the lease is not in use, then the state into which the partner put it is just fine, whatever it is. */ case FTS_FREE: case FTS_ABANDONED: case FTS_EXPIRED: case FTS_RELEASED: case FTS_RESET: case FTS_BACKUP: new_state = binding_state; break; /* If we think the lease *is* in use, then we're not going to take the partner's change if the partner thinks it's free. */ case FTS_ACTIVE: switch (binding_state) { case FTS_FREE: case FTS_BACKUP: new_state = lease -> binding_state; break; case FTS_EXPIRED: /* If we don't agree about expiry, it's * invalid. 65 should allow for max * clock skew (60) plus some fudge. * XXX: should we refetch cur_time? */ if ((lease->ends - 65) > cur_time) new_state = lease->binding_state; else new_state = binding_state; break; /* RELEASED, RESET, and ABANDONED indicate * that our partner has information about * this lease that we did not witness. Our * partner wins. */ case FTS_RELEASED: case FTS_RESET: case FTS_ABANDONED: new_state = binding_state; break; default: log_fatal ("Impossible case at %s:%d.", MDL); return FTS_RESET; } break; default: log_fatal ("Impossible case at %s:%d.", MDL); return FTS_RESET; } } return new_state; } /* We can reallocate a lease under the following circumstances: (1) It belongs to us - it's FTS_FREE, and we're primary, or it's FTS_BACKUP, and we're secondary. (2) We're in partner_down, and the lease is not active, and we can be sure that the other server didn't make it active. We can only be sure that the server didn't make it active when we are in the partner_down state and one of the following two conditions holds: (a) in the case that the time sent from the peer is earlier than the time we entered the partner_down state, at least MCLT has gone by since we entered partner_down, or (b) in the case that the time sent from the peer is later than the time when we entered partner_down, the current time is later than the time sent from the peer by at least MCLT. */ int lease_mine_to_reallocate (struct lease *lease) { dhcp_failover_state_t *peer; if (lease && lease->pool && (peer = lease->pool->failover_peer)) { /* * In addition to the normal rules governing wether a server * is allowed to operate changes on a lease, the server is * allowed to operate on a lease from the standpoint of the * most conservative guess of the peer's state for this lease. */ switch (lease->binding_state) { case FTS_ACTIVE: /* ACTIVE leases may not be reallocated. */ return 0; case FTS_FREE: case FTS_ABANDONED: /* FREE leases may only be allocated by the primary, * unless the secondary is acting in partner_down * state and stos+mclt or tsfp+mclt has expired, * whichever is greater. * * ABANDONED are treated the same as FREE for all * purposes here. Note that servers will only try * for ABANDONED leases as a last resort anyway. */ if (peer -> i_am == primary) return 1; return(peer->service_state == service_partner_down && ((lease->tsfp < peer->me.stos) ? (peer->me.stos + peer->mclt < cur_time) : (lease->tsfp + peer->mclt < cur_time))); case FTS_RELEASED: case FTS_EXPIRED: /* * These leases are generally untouchable until the * peer acknowledges their state change. However, as * this is impossible if the peer is offline, the * failover protocol permits an 'optimization' to * rewind the lease to a previous state that the server * is allowed to operate on, if that was the state that * was last acknowledged by the peer. * * So if a lease was free, was allocated by this * server, and expired without ever being transmitted * to the peer, it can be returned to free and given * to any new client legally. */ if ((peer->i_am == primary) && (lease->rewind_binding_state == FTS_FREE)) return 1; if ((peer->i_am == secondary) && (lease->rewind_binding_state == FTS_BACKUP)) return 1; /* FALL THROUGH (released, expired, reset) */ case FTS_RESET: /* * Released, expired, and reset leases go onto the * 'expired' queue all together. Upon entry into * partner-down state, this queue of leases has their * tsfp values modified to equal stos+mclt, the point * at which the server is allowed to remove them from * these transitional states. * * Note that although tsfp has been possibly extended * past the actual tsfp we received from the peer, we * don't have to take any special action. Since tsfp * will be equal to the current time when the lease * transitions to free, tsfp will not be used to grant * lease-times longer than the MCLT to clients, which * is the only danger for this sort of modification. */ return((peer->service_state == service_partner_down) && (lease->tsfp < cur_time)); case FTS_BACKUP: /* Only the secondary may allocate BACKUP leases, * unless in partner_down state in which case at * least TSFP+MCLT or STOS+MCLT must have expired, * whichever is greater. */ if (peer->i_am == secondary) return 1; return((peer->service_state == service_partner_down) && ((lease->tsfp < peer->me.stos) ? (peer->me.stos + peer->mclt < cur_time) : (lease->tsfp + peer->mclt < cur_time))); default: /* All lease states appear above. */ log_fatal("Impossible case at %s:%d.", MDL); break; } return 0; } if (lease) return(lease->binding_state == FTS_FREE || lease->binding_state == FTS_BACKUP); else return 0; } static isc_result_t failover_message_reference (failover_message_t **mp, failover_message_t *m, const char *file, int line) { *mp = m; m -> refcnt++; return ISC_R_SUCCESS; } static isc_result_t failover_message_dereference (failover_message_t **mp, const char *file, int line) { failover_message_t *m; m = (*mp); m -> refcnt--; if (m -> refcnt == 0) { if (m -> next) failover_message_dereference (&m -> next, file, line); if (m -> chaddr.data) dfree (m -> chaddr.data, file, line); if (m -> client_identifier.data) dfree (m -> client_identifier.data, file, line); if (m -> hba.data) dfree (m -> hba.data, file, line); if (m -> message.data) dfree (m -> message.data, file, line); if (m -> reply_options.data) dfree (m -> reply_options.data, file, line); if (m -> request_options.data) dfree (m -> request_options.data, file, line); if (m -> vendor_class.data) dfree (m -> vendor_class.data, file, line); if (m -> vendor_options.data) dfree (m -> vendor_options.data, file, line); if (m -> ddns.data) dfree (m -> ddns.data, file, line); dfree (*mp, file, line); } *mp = 0; return ISC_R_SUCCESS; } OMAPI_OBJECT_ALLOC (dhcp_failover_state, dhcp_failover_state_t, dhcp_type_failover_state) OMAPI_OBJECT_ALLOC (dhcp_failover_listener, dhcp_failover_listener_t, dhcp_type_failover_listener) OMAPI_OBJECT_ALLOC (dhcp_failover_link, dhcp_failover_link_t, dhcp_type_failover_link) #endif /* defined (FAILOVER_PROTOCOL) */ const char *binding_state_print (enum failover_state state) { switch (state) { case FTS_FREE: return "free"; break; case FTS_ACTIVE: return "active"; break; case FTS_EXPIRED: return "expired"; break; case FTS_RELEASED: return "released"; break; case FTS_ABANDONED: return "abandoned"; break; case FTS_RESET: return "reset"; break; case FTS_BACKUP: return "backup"; break; default: return "unknown"; break; } } dhcp-4.2.4/server/ldap.c000644 000765 000024 00000155345 11352700302 014767 0ustar00sarstaff000000 000000 /* ldap.c Routines for reading the configuration from LDAP */ /* * Copyright (c) 2003-2006 Ntelos, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of The Internet Software Consortium nor the names * of its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * This LDAP module was written by Brian Masney . Its * development was sponsored by Ntelos, Inc. (www.ntelos.com). */ #include "dhcpd.h" #include #include #if defined(LDAP_CONFIGURATION) #if defined(LDAP_CASA_AUTH) #include "ldap_casa.h" #endif static LDAP * ld = NULL; static char *ldap_server = NULL, *ldap_username = NULL, *ldap_password = NULL, *ldap_base_dn = NULL, *ldap_dhcp_server_cn = NULL, *ldap_debug_file = NULL; static int ldap_port = LDAP_PORT, ldap_method = LDAP_METHOD_DYNAMIC, ldap_referrals = -1, ldap_debug_fd = -1; #if defined (LDAP_USE_SSL) static int ldap_use_ssl = -1, /* try TLS if possible */ ldap_tls_reqcert = -1, ldap_tls_crlcheck = -1; static char *ldap_tls_ca_file = NULL, *ldap_tls_ca_dir = NULL, *ldap_tls_cert = NULL, *ldap_tls_key = NULL, *ldap_tls_ciphers = NULL, *ldap_tls_randfile = NULL; #endif static struct ldap_config_stack *ldap_stack = NULL; typedef struct ldap_dn_node { struct ldap_dn_node *next; size_t refs; char *dn; } ldap_dn_node; static ldap_dn_node *ldap_service_dn_head = NULL; static ldap_dn_node *ldap_service_dn_tail = NULL; static char * x_strncat(char *dst, const char *src, size_t dst_size) { size_t len = strlen(dst); return strncat(dst, src, dst_size > len ? dst_size - len - 1: 0); } static void ldap_parse_class (struct ldap_config_stack *item, struct parse *cfile) { struct berval **tempbv; if ((tempbv = ldap_get_values_len (ld, item->ldent, "cn")) == NULL || tempbv[0] == NULL) { if (tempbv != NULL) ldap_value_free_len (tempbv); return; } x_strncat (cfile->inbuf, "class \"", LDAP_BUFFER_SIZE); x_strncat (cfile->inbuf, tempbv[0]->bv_val, LDAP_BUFFER_SIZE); x_strncat (cfile->inbuf, "\" {\n", LDAP_BUFFER_SIZE); item->close_brace = 1; ldap_value_free_len (tempbv); } static void ldap_parse_subclass (struct ldap_config_stack *item, struct parse *cfile) { struct berval **tempbv, **classdata; if ((tempbv = ldap_get_values_len (ld, item->ldent, "cn")) == NULL || tempbv[0] == NULL) { if (tempbv != NULL) ldap_value_free_len (tempbv); return; } if ((classdata = ldap_get_values_len (ld, item->ldent, "dhcpClassData")) == NULL || classdata[0] == NULL) { if (classdata != NULL) ldap_value_free_len (classdata); ldap_value_free_len (tempbv); return; } x_strncat (cfile->inbuf, "subclass ", LDAP_BUFFER_SIZE); x_strncat (cfile->inbuf, classdata[0]->bv_val, LDAP_BUFFER_SIZE); x_strncat (cfile->inbuf, " ", LDAP_BUFFER_SIZE); x_strncat (cfile->inbuf, tempbv[0]->bv_val, LDAP_BUFFER_SIZE); x_strncat (cfile->inbuf, " {\n", LDAP_BUFFER_SIZE); item->close_brace = 1; ldap_value_free_len (tempbv); ldap_value_free_len (classdata); } static void ldap_parse_host (struct ldap_config_stack *item, struct parse *cfile) { struct berval **tempbv, **hwaddr; if ((tempbv = ldap_get_values_len (ld, item->ldent, "cn")) == NULL || tempbv[0] == NULL) { if (tempbv != NULL) ldap_value_free_len (tempbv); return; } hwaddr = ldap_get_values_len (ld, item->ldent, "dhcpHWAddress"); x_strncat (cfile->inbuf, "host ", LDAP_BUFFER_SIZE); x_strncat (cfile->inbuf, tempbv[0]->bv_val, LDAP_BUFFER_SIZE); if (hwaddr != NULL && hwaddr[0] != NULL) { x_strncat (cfile->inbuf, " {\nhardware ", LDAP_BUFFER_SIZE); x_strncat (cfile->inbuf, hwaddr[0]->bv_val, LDAP_BUFFER_SIZE); x_strncat (cfile->inbuf, ";\n", LDAP_BUFFER_SIZE); ldap_value_free_len (hwaddr); } item->close_brace = 1; ldap_value_free_len (tempbv); } static void ldap_parse_shared_network (struct ldap_config_stack *item, struct parse *cfile) { struct berval **tempbv; if ((tempbv = ldap_get_values_len (ld, item->ldent, "cn")) == NULL || tempbv[0] == NULL) { if (tempbv != NULL) ldap_value_free_len (tempbv); return; } x_strncat (cfile->inbuf, "shared-network \"", LDAP_BUFFER_SIZE); x_strncat (cfile->inbuf, tempbv[0]->bv_val, LDAP_BUFFER_SIZE); x_strncat (cfile->inbuf, "\" {\n", LDAP_BUFFER_SIZE); item->close_brace = 1; ldap_value_free_len (tempbv); } static void parse_netmask (int netmask, char *netmaskbuf) { unsigned long nm; int i; nm = 0; for (i=1; i <= netmask; i++) { nm |= 1 << (32 - i); } sprintf (netmaskbuf, "%d.%d.%d.%d", (int) (nm >> 24) & 0xff, (int) (nm >> 16) & 0xff, (int) (nm >> 8) & 0xff, (int) nm & 0xff); } static void ldap_parse_subnet (struct ldap_config_stack *item, struct parse *cfile) { struct berval **tempbv, **netmaskstr; char netmaskbuf[sizeof("255.255.255.255")]; int i; if ((tempbv = ldap_get_values_len (ld, item->ldent, "cn")) == NULL || tempbv[0] == NULL) { if (tempbv != NULL) ldap_value_free_len (tempbv); return; } if ((netmaskstr = ldap_get_values_len (ld, item->ldent, "dhcpNetmask")) == NULL || netmaskstr[0] == NULL) { if (netmaskstr != NULL) ldap_value_free_len (netmaskstr); ldap_value_free_len (tempbv); return; } x_strncat (cfile->inbuf, "subnet ", LDAP_BUFFER_SIZE); x_strncat (cfile->inbuf, tempbv[0]->bv_val, LDAP_BUFFER_SIZE); x_strncat (cfile->inbuf, " netmask ", LDAP_BUFFER_SIZE); parse_netmask (strtol (netmaskstr[0]->bv_val, NULL, 10), netmaskbuf); x_strncat (cfile->inbuf, netmaskbuf, LDAP_BUFFER_SIZE); x_strncat (cfile->inbuf, " {\n", LDAP_BUFFER_SIZE); ldap_value_free_len (tempbv); ldap_value_free_len (netmaskstr); if ((tempbv = ldap_get_values_len (ld, item->ldent, "dhcpRange")) != NULL) { for (i=0; tempbv[i] != NULL; i++) { x_strncat (cfile->inbuf, "range", LDAP_BUFFER_SIZE); x_strncat (cfile->inbuf, " ", LDAP_BUFFER_SIZE); x_strncat (cfile->inbuf, tempbv[i]->bv_val, LDAP_BUFFER_SIZE); x_strncat (cfile->inbuf, ";\n", LDAP_BUFFER_SIZE); } } item->close_brace = 1; } static void ldap_parse_pool (struct ldap_config_stack *item, struct parse *cfile) { struct berval **tempbv; int i; x_strncat (cfile->inbuf, "pool {\n", LDAP_BUFFER_SIZE); if ((tempbv = ldap_get_values_len (ld, item->ldent, "dhcpRange")) != NULL) { x_strncat (cfile->inbuf, "range", LDAP_BUFFER_SIZE); for (i=0; tempbv[i] != NULL; i++) { x_strncat (cfile->inbuf, " ", LDAP_BUFFER_SIZE); x_strncat (cfile->inbuf, tempbv[i]->bv_val, LDAP_BUFFER_SIZE); } x_strncat (cfile->inbuf, ";\n", LDAP_BUFFER_SIZE); ldap_value_free_len (tempbv); } if ((tempbv = ldap_get_values_len (ld, item->ldent, "dhcpPermitList")) != NULL) { for (i=0; tempbv[i] != NULL; i++) { x_strncat (cfile->inbuf, tempbv[i]->bv_val, LDAP_BUFFER_SIZE); x_strncat (cfile->inbuf, ";\n", LDAP_BUFFER_SIZE); } ldap_value_free_len (tempbv); } item->close_brace = 1; } static void ldap_parse_group (struct ldap_config_stack *item, struct parse *cfile) { x_strncat (cfile->inbuf, "group {\n", LDAP_BUFFER_SIZE); item->close_brace = 1; } static void ldap_parse_key (struct ldap_config_stack *item, struct parse *cfile) { struct berval **tempbv; if ((tempbv = ldap_get_values_len (ld, item->ldent, "cn")) != NULL) { x_strncat (cfile->inbuf, "key ", LDAP_BUFFER_SIZE); x_strncat (cfile->inbuf, tempbv[0]->bv_val, LDAP_BUFFER_SIZE); x_strncat (cfile->inbuf, " {\n", LDAP_BUFFER_SIZE); ldap_value_free_len (tempbv); } if ((tempbv = ldap_get_values_len (ld, item->ldent, "dhcpKeyAlgorithm")) != NULL) { x_strncat (cfile->inbuf, "algorithm ", LDAP_BUFFER_SIZE); x_strncat (cfile->inbuf, tempbv[0]->bv_val, LDAP_BUFFER_SIZE); x_strncat (cfile->inbuf, ";\n", LDAP_BUFFER_SIZE); ldap_value_free_len (tempbv); } if ((tempbv = ldap_get_values_len (ld, item->ldent, "dhcpKeySecret")) != NULL) { x_strncat (cfile->inbuf, "secret ", LDAP_BUFFER_SIZE); x_strncat (cfile->inbuf, tempbv[0]->bv_val, LDAP_BUFFER_SIZE); x_strncat (cfile->inbuf, ";\n", LDAP_BUFFER_SIZE); ldap_value_free_len (tempbv); } item->close_brace = 1; } static void ldap_parse_zone (struct ldap_config_stack *item, struct parse *cfile) { char *cnFindStart, *cnFindEnd; struct berval **tempbv; char *keyCn; size_t len; if ((tempbv = ldap_get_values_len (ld, item->ldent, "cn")) != NULL) { x_strncat (cfile->inbuf, "zone ", LDAP_BUFFER_SIZE); x_strncat (cfile->inbuf, tempbv[0]->bv_val, LDAP_BUFFER_SIZE); x_strncat (cfile->inbuf, " {\n", LDAP_BUFFER_SIZE); ldap_value_free_len (tempbv); } if ((tempbv = ldap_get_values_len (ld, item->ldent, "dhcpDnsZoneServer")) != NULL) { x_strncat (cfile->inbuf, "primary ", LDAP_BUFFER_SIZE); x_strncat (cfile->inbuf, tempbv[0]->bv_val, LDAP_BUFFER_SIZE); x_strncat (cfile->inbuf, ";\n", LDAP_BUFFER_SIZE); ldap_value_free_len (tempbv); } if ((tempbv = ldap_get_values_len (ld, item->ldent, "dhcpKeyDN")) != NULL) { cnFindStart = strchr(tempbv[0]->bv_val,'='); if (cnFindStart != NULL) cnFindEnd = strchr(++cnFindStart,','); else cnFindEnd = NULL; if (cnFindEnd != NULL && cnFindEnd > cnFindStart) { len = cnFindEnd - cnFindStart; keyCn = dmalloc (len + 1, MDL); } else { len = 0; keyCn = NULL; } if (keyCn != NULL) { strncpy (keyCn, cnFindStart, len); keyCn[len] = '\0'; x_strncat (cfile->inbuf, "key ", LDAP_BUFFER_SIZE); x_strncat (cfile->inbuf, keyCn, LDAP_BUFFER_SIZE); x_strncat (cfile->inbuf, ";\n", LDAP_BUFFER_SIZE); dfree (keyCn, MDL); } ldap_value_free_len (tempbv); } item->close_brace = 1; } static void add_to_config_stack (LDAPMessage * res, LDAPMessage * ent) { struct ldap_config_stack *ns; ns = dmalloc (sizeof (*ns), MDL); ns->res = res; ns->ldent = ent; ns->close_brace = 0; ns->processed = 0; ns->next = ldap_stack; ldap_stack = ns; } static void ldap_stop() { struct sigaction old, new; if (ld == NULL) return; /* ** ldap_unbind after a LDAP_SERVER_DOWN result ** causes a SIGPIPE and dhcpd gets terminated, ** since it doesn't handle it... */ new.sa_flags = 0; new.sa_handler = SIG_IGN; sigemptyset (&new.sa_mask); sigaction (SIGPIPE, &new, &old); ldap_unbind_ext_s (ld, NULL, NULL); ld = NULL; sigaction (SIGPIPE, &old, &new); } static char * _do_lookup_dhcp_string_option (struct option_state *options, int option_name) { struct option_cache *oc; struct data_string db; char *ret; memset (&db, 0, sizeof (db)); oc = lookup_option (&server_universe, options, option_name); if (oc && evaluate_option_cache (&db, (struct packet*) NULL, (struct lease *) NULL, (struct client_state *) NULL, options, (struct option_state *) NULL, &global_scope, oc, MDL) && db.data != NULL && *db.data != '\0') { ret = dmalloc (db.len + 1, MDL); if (ret == NULL) log_fatal ("no memory for ldap option %d value", option_name); memcpy (ret, db.data, db.len); ret[db.len] = 0; data_string_forget (&db, MDL); } else ret = NULL; return (ret); } static int _do_lookup_dhcp_int_option (struct option_state *options, int option_name) { struct option_cache *oc; struct data_string db; int ret; memset (&db, 0, sizeof (db)); oc = lookup_option (&server_universe, options, option_name); if (oc && evaluate_option_cache (&db, (struct packet*) NULL, (struct lease *) NULL, (struct client_state *) NULL, options, (struct option_state *) NULL, &global_scope, oc, MDL) && db.data != NULL && *db.data != '\0') { ret = strtol ((const char *) db.data, NULL, 10); data_string_forget (&db, MDL); } else ret = 0; return (ret); } static int _do_lookup_dhcp_enum_option (struct option_state *options, int option_name) { struct option_cache *oc; struct data_string db; int ret = -1; memset (&db, 0, sizeof (db)); oc = lookup_option (&server_universe, options, option_name); if (oc && evaluate_option_cache (&db, (struct packet*) NULL, (struct lease *) NULL, (struct client_state *) NULL, options, (struct option_state *) NULL, &global_scope, oc, MDL) && db.data != NULL && *db.data != '\0') { if (db.len == 1) ret = db.data [0]; else log_fatal ("invalid option name %d", option_name); data_string_forget (&db, MDL); } else ret = 0; return (ret); } int ldap_rebind_cb (LDAP *ld, LDAP_CONST char *url, ber_tag_t request, ber_int_t msgid, void *parms) { int ret; LDAPURLDesc *ldapurl = NULL; char *who = NULL; struct berval creds; log_info("LDAP rebind to '%s'", url); if ((ret = ldap_url_parse(url, &ldapurl)) != LDAP_SUCCESS) { log_error ("Error: Can not parse ldap rebind url '%s': %s", url, ldap_err2string(ret)); return ret; } #if defined (LDAP_USE_SSL) if (strcasecmp(ldapurl->lud_scheme, "ldaps") == 0) { int opt = LDAP_OPT_X_TLS_HARD; if ((ret = ldap_set_option (ld, LDAP_OPT_X_TLS, &opt)) != LDAP_SUCCESS) { log_error ("Error: Cannot init LDAPS session to %s:%d: %s", ldapurl->lud_host, ldapurl->lud_port, ldap_err2string (ret)); return ret; } else { log_info ("LDAPS session successfully enabled to %s", ldap_server); } } else if (strcasecmp(ldapurl->lud_scheme, "ldap") == 0 && ldap_use_ssl != LDAP_SSL_OFF) { if ((ret = ldap_start_tls_s (ld, NULL, NULL)) != LDAP_SUCCESS) { log_error ("Error: Cannot start TLS session to %s:%d: %s", ldapurl->lud_host, ldapurl->lud_port, ldap_err2string (ret)); return ret; } else { log_info ("TLS session successfully started to %s:%d", ldapurl->lud_host, ldapurl->lud_port); } } #endif if (ldap_username != NULL || *ldap_username != '\0') { who = ldap_username; creds.bv_val = strdup(ldap_password); creds.bv_len = strlen(ldap_password); } if ((ret = ldap_sasl_bind_s (ld, who, LDAP_SASL_SIMPLE, &creds, NULL, NULL, NULL)) != LDAP_SUCCESS) { log_error ("Error: Cannot login into ldap server %s:%d: %s", ldapurl->lud_host, ldapurl->lud_port, ldap_err2string (ret)); } return ret; } static void ldap_start (void) { struct option_state *options; int ret, version; char *uri = NULL; struct berval creds; if (ld != NULL) return; if (ldap_server == NULL) { options = NULL; option_state_allocate (&options, MDL); execute_statements_in_scope ((struct binding_value **) NULL, (struct packet *) NULL, (struct lease *) NULL, (struct client_state *) NULL, (struct option_state *) NULL, options, &global_scope, root_group, (struct group *) NULL); ldap_server = _do_lookup_dhcp_string_option (options, SV_LDAP_SERVER); ldap_dhcp_server_cn = _do_lookup_dhcp_string_option (options, SV_LDAP_DHCP_SERVER_CN); ldap_port = _do_lookup_dhcp_int_option (options, SV_LDAP_PORT); ldap_base_dn = _do_lookup_dhcp_string_option (options, SV_LDAP_BASE_DN); ldap_method = _do_lookup_dhcp_enum_option (options, SV_LDAP_METHOD); ldap_debug_file = _do_lookup_dhcp_string_option (options, SV_LDAP_DEBUG_FILE); ldap_referrals = _do_lookup_dhcp_enum_option (options, SV_LDAP_REFERRALS); #if defined (LDAP_USE_SSL) ldap_use_ssl = _do_lookup_dhcp_enum_option (options, SV_LDAP_SSL); if( ldap_use_ssl != LDAP_SSL_OFF) { ldap_tls_reqcert = _do_lookup_dhcp_enum_option (options, SV_LDAP_TLS_REQCERT); ldap_tls_ca_file = _do_lookup_dhcp_string_option (options, SV_LDAP_TLS_CA_FILE); ldap_tls_ca_dir = _do_lookup_dhcp_string_option (options, SV_LDAP_TLS_CA_DIR); ldap_tls_cert = _do_lookup_dhcp_string_option (options, SV_LDAP_TLS_CERT); ldap_tls_key = _do_lookup_dhcp_string_option (options, SV_LDAP_TLS_KEY); ldap_tls_crlcheck = _do_lookup_dhcp_enum_option (options, SV_LDAP_TLS_CRLCHECK); ldap_tls_ciphers = _do_lookup_dhcp_string_option (options, SV_LDAP_TLS_CIPHERS); ldap_tls_randfile = _do_lookup_dhcp_string_option (options, SV_LDAP_TLS_RANDFILE); } #endif #if defined (LDAP_CASA_AUTH) if (!load_uname_pwd_from_miCASA(&ldap_username,&ldap_password)) { #if defined (DEBUG_LDAP) log_info ("Authentication credential taken from file"); #endif #endif ldap_username = _do_lookup_dhcp_string_option (options, SV_LDAP_USERNAME); ldap_password = _do_lookup_dhcp_string_option (options, SV_LDAP_PASSWORD); #if defined (LDAP_CASA_AUTH) } #endif option_state_dereference (&options, MDL); } if (ldap_server == NULL || ldap_base_dn == NULL) { log_info ("Not searching LDAP since ldap-server, ldap-port and ldap-base-dn were not specified in the config file"); ldap_method = LDAP_METHOD_STATIC; return; } if (ldap_debug_file != NULL && ldap_debug_fd == -1) { if ((ldap_debug_fd = open (ldap_debug_file, O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR)) < 0) log_error ("Error opening debug LDAP log file %s: %s", ldap_debug_file, strerror (errno)); } #if defined (DEBUG_LDAP) log_info ("Connecting to LDAP server %s:%d", ldap_server, ldap_port); #endif #if defined (LDAP_USE_SSL) if (ldap_use_ssl == -1) { /* ** There was no "ldap-ssl" option in dhcpd.conf (also not "off"). ** Let's try, if we can use an anonymous TLS session without to ** verify the server certificate -- if not continue without TLS. */ int opt = LDAP_OPT_X_TLS_ALLOW; if ((ret = ldap_set_option (NULL, LDAP_OPT_X_TLS_REQUIRE_CERT, &opt)) != LDAP_SUCCESS) { log_error ("Warning: Cannot set LDAP TLS require cert option to 'allow': %s", ldap_err2string (ret)); } } if (ldap_use_ssl != LDAP_SSL_OFF) { if (ldap_tls_reqcert != -1) { if ((ret = ldap_set_option (NULL, LDAP_OPT_X_TLS_REQUIRE_CERT, &ldap_tls_reqcert)) != LDAP_SUCCESS) { log_error ("Cannot set LDAP TLS require cert option: %s", ldap_err2string (ret)); } } if( ldap_tls_ca_file != NULL) { if ((ret = ldap_set_option (NULL, LDAP_OPT_X_TLS_CACERTFILE, ldap_tls_ca_file)) != LDAP_SUCCESS) { log_error ("Cannot set LDAP TLS CA certificate file %s: %s", ldap_tls_ca_file, ldap_err2string (ret)); } } if( ldap_tls_ca_dir != NULL) { if ((ret = ldap_set_option (NULL, LDAP_OPT_X_TLS_CACERTDIR, ldap_tls_ca_dir)) != LDAP_SUCCESS) { log_error ("Cannot set LDAP TLS CA certificate dir %s: %s", ldap_tls_ca_dir, ldap_err2string (ret)); } } if( ldap_tls_cert != NULL) { if ((ret = ldap_set_option (NULL, LDAP_OPT_X_TLS_CERTFILE, ldap_tls_cert)) != LDAP_SUCCESS) { log_error ("Cannot set LDAP TLS client certificate file %s: %s", ldap_tls_cert, ldap_err2string (ret)); } } if( ldap_tls_key != NULL) { if ((ret = ldap_set_option (NULL, LDAP_OPT_X_TLS_KEYFILE, ldap_tls_key)) != LDAP_SUCCESS) { log_error ("Cannot set LDAP TLS certificate key file %s: %s", ldap_tls_key, ldap_err2string (ret)); } } if( ldap_tls_crlcheck != -1) { int opt = ldap_tls_crlcheck; if ((ret = ldap_set_option (NULL, LDAP_OPT_X_TLS_CRLCHECK, &opt)) != LDAP_SUCCESS) { log_error ("Cannot set LDAP TLS crl check option: %s", ldap_err2string (ret)); } } if( ldap_tls_ciphers != NULL) { if ((ret = ldap_set_option (NULL, LDAP_OPT_X_TLS_CIPHER_SUITE, ldap_tls_ciphers)) != LDAP_SUCCESS) { log_error ("Cannot set LDAP TLS cipher suite %s: %s", ldap_tls_ciphers, ldap_err2string (ret)); } } if( ldap_tls_randfile != NULL) { if ((ret = ldap_set_option (NULL, LDAP_OPT_X_TLS_RANDOM_FILE, ldap_tls_randfile)) != LDAP_SUCCESS) { log_error ("Cannot set LDAP TLS random file %s: %s", ldap_tls_randfile, ldap_err2string (ret)); } } } #endif /* enough for 'ldap://+ + hostname + ':' + port number */ uri = malloc(strlen(ldap_server) + 16); if (uri == NULL) { log_error ("Cannot build ldap init URI %s:%d", ldap_server, ldap_port); return; } sprintf(uri, "ldap://%s:%d", ldap_server, ldap_port); ldap_initialize(&ld, uri); if (ld == NULL) { log_error ("Cannot init ldap session to %s:%d", ldap_server, ldap_port); return; } free(uri); version = LDAP_VERSION3; if ((ret = ldap_set_option (ld, LDAP_OPT_PROTOCOL_VERSION, &version)) != LDAP_OPT_SUCCESS) { log_error ("Cannot set LDAP version to %d: %s", version, ldap_err2string (ret)); } if (ldap_referrals != -1) { if ((ret = ldap_set_option (ld, LDAP_OPT_REFERRALS, ldap_referrals ? LDAP_OPT_ON : LDAP_OPT_OFF)) != LDAP_OPT_SUCCESS) { log_error ("Cannot %s LDAP referrals option: %s", (ldap_referrals ? "enable" : "disable"), ldap_err2string (ret)); } } if ((ret = ldap_set_rebind_proc(ld, ldap_rebind_cb, NULL)) != LDAP_SUCCESS) { log_error ("Warning: Cannot set ldap rebind procedure: %s", ldap_err2string (ret)); } #if defined (LDAP_USE_SSL) if (ldap_use_ssl == LDAP_SSL_LDAPS || (ldap_use_ssl == LDAP_SSL_ON && ldap_port == LDAPS_PORT)) { int opt = LDAP_OPT_X_TLS_HARD; if ((ret = ldap_set_option (ld, LDAP_OPT_X_TLS, &opt)) != LDAP_SUCCESS) { log_error ("Error: Cannot init LDAPS session to %s:%d: %s", ldap_server, ldap_port, ldap_err2string (ret)); ldap_stop(); return; } else { log_info ("LDAPS session successfully enabled to %s:%d", ldap_server, ldap_port); } } else if (ldap_use_ssl != LDAP_SSL_OFF) { if ((ret = ldap_start_tls_s (ld, NULL, NULL)) != LDAP_SUCCESS) { log_error ("Error: Cannot start TLS session to %s:%d: %s", ldap_server, ldap_port, ldap_err2string (ret)); ldap_stop(); return; } else { log_info ("TLS session successfully started to %s:%d", ldap_server, ldap_port); } } #endif if (ldap_username != NULL && *ldap_username != '\0') { creds.bv_val = strdup(ldap_password); creds.bv_len = strlen(ldap_password); if ((ret = ldap_sasl_bind_s (ld, ldap_username, LDAP_SASL_SIMPLE, &creds, NULL, NULL, NULL)) != LDAP_SUCCESS) { log_error ("Error: Cannot login into ldap server %s:%d: %s", ldap_server, ldap_port, ldap_err2string (ret)); ldap_stop(); return; } } #if defined (DEBUG_LDAP) log_info ("Successfully logged into LDAP server %s", ldap_server); #endif } static void parse_external_dns (LDAPMessage * ent) { char *search[] = {"dhcpOptionsDN", "dhcpSharedNetworkDN", "dhcpSubnetDN", "dhcpGroupDN", "dhcpHostDN", "dhcpClassesDN", "dhcpPoolDN", NULL}; LDAPMessage * newres, * newent; struct berval **tempbv; int i, j, ret; #if defined (DEBUG_LDAP) char *dn; dn = ldap_get_dn (ld, ent); if (dn != NULL) { log_info ("Parsing external DNs for '%s'", dn); ldap_memfree (dn); } #endif if (ld == NULL) ldap_start (); if (ld == NULL) return; for (i=0; search[i] != NULL; i++) { if ((tempbv = ldap_get_values_len (ld, ent, search[i])) == NULL) continue; for (j=0; tempbv[j] != NULL; j++) { if (*tempbv[j]->bv_val == '\0') continue; if ((ret = ldap_search_ext_s(ld, tempbv[j]->bv_val, LDAP_SCOPE_BASE, "objectClass=*", NULL, 0, NULL, NULL, NULL, 0, &newres)) != LDAP_SUCCESS) { ldap_value_free_len (tempbv); ldap_stop(); return; } #if defined (DEBUG_LDAP) log_info ("Adding contents of subtree '%s' to config stack from '%s' reference", tempbv[j], search[i]); #endif for (newent = ldap_first_entry (ld, newres); newent != NULL; newent = ldap_next_entry (ld, newent)) { #if defined (DEBUG_LDAP) dn = ldap_get_dn (ld, newent); if (dn != NULL) { log_info ("Adding LDAP result set starting with '%s' to config stack", dn); ldap_memfree (dn); } #endif add_to_config_stack (newres, newent); /* don't free newres here */ } } ldap_value_free_len (tempbv); } } static void free_stack_entry (struct ldap_config_stack *item) { struct ldap_config_stack *look_ahead_pointer = item; int may_free_msg = 1; while (look_ahead_pointer->next != NULL) { look_ahead_pointer = look_ahead_pointer->next; if (look_ahead_pointer->res == item->res) { may_free_msg = 0; break; } } if (may_free_msg) ldap_msgfree (item->res); dfree (item, MDL); } static void next_ldap_entry (struct parse *cfile) { struct ldap_config_stack *temp_stack; if (ldap_stack != NULL && ldap_stack->close_brace) { x_strncat (cfile->inbuf, "}\n", LDAP_BUFFER_SIZE); ldap_stack->close_brace = 0; } while (ldap_stack != NULL && (ldap_stack->ldent == NULL || (ldap_stack->ldent = ldap_next_entry (ld, ldap_stack->ldent)) == NULL)) { if (ldap_stack->close_brace) { x_strncat (cfile->inbuf, "}\n", LDAP_BUFFER_SIZE); ldap_stack->close_brace = 0; } temp_stack = ldap_stack; ldap_stack = ldap_stack->next; free_stack_entry (temp_stack); } if (ldap_stack != NULL && ldap_stack->close_brace) { x_strncat (cfile->inbuf, "}\n", LDAP_BUFFER_SIZE); ldap_stack->close_brace = 0; } } static char check_statement_end (const char *statement) { char *ptr; if (statement == NULL || *statement == '\0') return ('\0'); /* ** check if it ends with "}", e.g.: ** "zone my.domain. { ... }" ** optionally followed by spaces */ ptr = strrchr (statement, '}'); if (ptr != NULL) { /* skip following white-spaces */ for (++ptr; isspace ((int)*ptr); ptr++); /* check if we reached the end */ if (*ptr == '\0') return ('}'); /* yes, block end */ else return (*ptr); } /* ** this should not happen, but... ** check if it ends with ";", e.g.: ** "authoritative;" ** optionally followed by spaces */ ptr = strrchr (statement, ';'); if (ptr != NULL) { /* skip following white-spaces */ for (++ptr; isspace ((int)*ptr); ptr++); /* check if we reached the end */ if (*ptr == '\0') return (';'); /* ends with a ; */ else return (*ptr); } return ('\0'); } static isc_result_t ldap_parse_entry_options (LDAPMessage *ent, char *buffer, size_t size, int *lease_limit) { struct berval **tempbv; int i; if (ent == NULL || buffer == NULL || size == 0) return (ISC_R_FAILURE); if ((tempbv = ldap_get_values_len (ld, ent, "dhcpStatements")) != NULL) { for (i=0; tempbv[i] != NULL; i++) { if (lease_limit != NULL && strncasecmp ("lease limit ", tempbv[i]->bv_val, 12) == 0) { *lease_limit = (int) strtol ((tempbv[i]->bv_val) + 12, NULL, 10); continue; } x_strncat (buffer, tempbv[i]->bv_val, size); switch((int) check_statement_end (tempbv[i]->bv_val)) { case '}': case ';': x_strncat (buffer, "\n", size); break; default: x_strncat (buffer, ";\n", size); break; } } ldap_value_free_len (tempbv); } if ((tempbv = ldap_get_values_len (ld, ent, "dhcpOption")) != NULL) { for (i=0; tempbv[i] != NULL; i++) { x_strncat (buffer, "option ", size); x_strncat (buffer, tempbv[i]->bv_val, size); switch ((int) check_statement_end (tempbv[i]->bv_val)) { case ';': x_strncat (buffer, "\n", size); break; default: x_strncat (buffer, ";\n", size); break; } } ldap_value_free_len (tempbv); } return (ISC_R_SUCCESS); } static void ldap_generate_config_string (struct parse *cfile) { struct berval **objectClass; char *dn; struct ldap_config_stack *entry; LDAPMessage * ent, * res; int i, ignore, found; int ret; if (ld == NULL) ldap_start (); if (ld == NULL) return; entry = ldap_stack; if ((objectClass = ldap_get_values_len (ld, entry->ldent, "objectClass")) == NULL) return; ignore = 0; found = 1; for (i=0; objectClass[i] != NULL; i++) { if (strcasecmp (objectClass[i]->bv_val, "dhcpSharedNetwork") == 0) ldap_parse_shared_network (entry, cfile); else if (strcasecmp (objectClass[i]->bv_val, "dhcpClass") == 0) ldap_parse_class (entry, cfile); else if (strcasecmp (objectClass[i]->bv_val, "dhcpSubnet") == 0) ldap_parse_subnet (entry, cfile); else if (strcasecmp (objectClass[i]->bv_val, "dhcpPool") == 0) ldap_parse_pool (entry, cfile); else if (strcasecmp (objectClass[i]->bv_val, "dhcpGroup") == 0) ldap_parse_group (entry, cfile); else if (strcasecmp (objectClass[i]->bv_val, "dhcpTSigKey") == 0) ldap_parse_key (entry, cfile); else if (strcasecmp (objectClass[i]->bv_val, "dhcpDnsZone") == 0) ldap_parse_zone (entry, cfile); else if (strcasecmp (objectClass[i]->bv_val, "dhcpHost") == 0) { if (ldap_method == LDAP_METHOD_STATIC) ldap_parse_host (entry, cfile); else { ignore = 1; break; } } else if (strcasecmp (objectClass[i]->bv_val, "dhcpSubClass") == 0) { if (ldap_method == LDAP_METHOD_STATIC) ldap_parse_subclass (entry, cfile); else { ignore = 1; break; } } else found = 0; if (found && cfile->inbuf[0] == '\0') { ignore = 1; break; } } ldap_value_free_len (objectClass); if (ignore) { next_ldap_entry (cfile); return; } ldap_parse_entry_options(entry->ldent, cfile->inbuf, LDAP_BUFFER_SIZE-1, NULL); dn = ldap_get_dn (ld, entry->ldent); #if defined(DEBUG_LDAP) if (dn != NULL) log_info ("Found LDAP entry '%s'", dn); #endif if (dn == NULL || (ret = ldap_search_ext_s (ld, dn, LDAP_SCOPE_ONELEVEL, "objectClass=*", NULL, 0, NULL, NULL, NULL, 0, &res)) != LDAP_SUCCESS) { if (dn) ldap_memfree (dn); ldap_stop(); return; } ldap_memfree (dn); if ((ent = ldap_first_entry (ld, res)) != NULL) { add_to_config_stack (res, ent); parse_external_dns (entry->ldent); } else { ldap_msgfree (res); parse_external_dns (entry->ldent); next_ldap_entry (cfile); } } static void ldap_close_debug_fd() { if (ldap_debug_fd != -1) { close (ldap_debug_fd); ldap_debug_fd = -1; } } static void ldap_write_debug (const void *buff, size_t size) { if (ldap_debug_fd != -1) { if (write (ldap_debug_fd, buff, size) < 0) { log_error ("Error writing to LDAP debug file %s: %s." " Disabling log file.", ldap_debug_file, strerror (errno)); ldap_close_debug_fd(); } } } static int ldap_read_function (struct parse *cfile) { cfile->inbuf[0] = '\0'; cfile->buflen = 0; while (ldap_stack != NULL && *cfile->inbuf == '\0') ldap_generate_config_string (cfile); if (ldap_stack == NULL && *cfile->inbuf == '\0') return (EOF); cfile->bufix = 1; cfile->buflen = strlen (cfile->inbuf) - 1; if (cfile->buflen > 0) ldap_write_debug (cfile->inbuf, cfile->buflen); #if defined (DEBUG_LDAP) log_info ("Sending config line '%s'", cfile->inbuf); #endif return (cfile->inbuf[0]); } static char * ldap_get_host_name (LDAPMessage * ent) { struct berval **name; char *ret; ret = NULL; if ((name = ldap_get_values_len (ld, ent, "cn")) == NULL || name[0] == NULL) { if (name != NULL) ldap_value_free_len (name); #if defined (DEBUG_LDAP) ret = ldap_get_dn (ld, ent); if (ret != NULL) { log_info ("Cannot get cn attribute for LDAP entry %s", ret); ldap_memfree(ret); } #endif return (NULL); } ret = dmalloc (strlen (name[0]->bv_val) + 1, MDL); strcpy (ret, name[0]->bv_val); ldap_value_free_len (name); return (ret); } static int getfqhostname(char *fqhost, size_t size) { #if defined(MAXHOSTNAMELEN) char hname[MAXHOSTNAMELEN]; #else char hname[65]; #endif struct hostent *hp; if(NULL == fqhost || 1 >= size) return -1; memset(hname, 0, sizeof(hname)); if( gethostname(hname, sizeof(hname)-1)) return -1; if(NULL == (hp = gethostbyname(hname))) return -1; strncpy(fqhost, hp->h_name, size-1); fqhost[size-1] = '\0'; return 0; } isc_result_t ldap_read_config (void) { LDAPMessage * ldres, * hostres, * ent, * hostent; char hfilter[1024], sfilter[1024], fqdn[257]; char *buffer, *hostdn; ldap_dn_node *curr = NULL; struct parse *cfile; struct utsname unme; isc_result_t res; size_t length; int ret, cnt; struct berval **tempbv = NULL; if (ld == NULL) ldap_start (); if (ld == NULL) return (ldap_server == NULL ? ISC_R_SUCCESS : ISC_R_FAILURE); buffer = dmalloc (LDAP_BUFFER_SIZE+1, MDL); if (buffer == NULL) return (ISC_R_FAILURE); cfile = (struct parse *) NULL; res = new_parse (&cfile, -1, buffer, LDAP_BUFFER_SIZE, "LDAP", 0); if (res != ISC_R_SUCCESS) return (res); uname (&unme); if (ldap_dhcp_server_cn != NULL) { snprintf (hfilter, sizeof (hfilter), "(&(objectClass=dhcpServer)(cn=%s))", ldap_dhcp_server_cn); } else { if(0 == getfqhostname(fqdn, sizeof(fqdn))) { snprintf (hfilter, sizeof (hfilter), "(&(objectClass=dhcpServer)(|(cn=%s)(cn=%s)))", unme.nodename, fqdn); } else { snprintf (hfilter, sizeof (hfilter), "(&(objectClass=dhcpServer)(cn=%s))", unme.nodename); } } hostres = NULL; if ((ret = ldap_search_ext_s (ld, ldap_base_dn, LDAP_SCOPE_SUBTREE, hfilter, NULL, 0, NULL, NULL, NULL, 0, &hostres)) != LDAP_SUCCESS) { log_error ("Cannot find host LDAP entry %s %s", ((ldap_dhcp_server_cn == NULL)?(unme.nodename):(ldap_dhcp_server_cn)), hfilter); if(NULL != hostres) ldap_msgfree (hostres); ldap_stop(); return (ISC_R_FAILURE); } if ((hostent = ldap_first_entry (ld, hostres)) == NULL) { log_error ("Error: Cannot find LDAP entry matching %s", hfilter); ldap_msgfree (hostres); ldap_stop(); return (ISC_R_FAILURE); } hostdn = ldap_get_dn (ld, hostent); #if defined(DEBUG_LDAP) if (hostdn != NULL) log_info ("Found dhcpServer LDAP entry '%s'", hostdn); #endif if (hostdn == NULL || (tempbv = ldap_get_values_len (ld, hostent, "dhcpServiceDN")) == NULL || tempbv[0] == NULL) { log_error ("Error: Cannot find LDAP entry matching %s", hfilter); if (tempbv != NULL) ldap_value_free_len (tempbv); if (hostdn) ldap_memfree (hostdn); ldap_msgfree (hostres); ldap_stop(); return (ISC_R_FAILURE); } #if defined(DEBUG_LDAP) log_info ("LDAP: Parsing dhcpServer options '%s' ...", hostdn); #endif cfile->inbuf[0] = '\0'; ldap_parse_entry_options(hostent, cfile->inbuf, LDAP_BUFFER_SIZE, NULL); cfile->buflen = strlen (cfile->inbuf); if(cfile->buflen > 0) { ldap_write_debug (cfile->inbuf, cfile->buflen); res = conf_file_subparse (cfile, root_group, ROOT_GROUP); if (res != ISC_R_SUCCESS) { log_error ("LDAP: cannot parse dhcpServer entry '%s'", hostdn); ldap_memfree (hostdn); ldap_stop(); return res; } cfile->inbuf[0] = '\0'; } ldap_msgfree (hostres); /* ** attach ldap (tree) read function now */ cfile->bufix = cfile->buflen = 0; cfile->read_function = ldap_read_function; res = ISC_R_SUCCESS; for (cnt=0; tempbv[cnt] != NULL; cnt++) { snprintf(sfilter, sizeof(sfilter), "(&(objectClass=dhcpService)" "(|(dhcpPrimaryDN=%s)(dhcpSecondaryDN=%s)))", hostdn, hostdn); ldres = NULL; if ((ret = ldap_search_ext_s (ld, tempbv[cnt]->bv_val, LDAP_SCOPE_BASE, sfilter, NULL, 0, NULL, NULL, NULL, 0, &ldres)) != LDAP_SUCCESS) { log_error ("Error searching for dhcpServiceDN '%s': %s. Please update the LDAP entry '%s'", tempbv[cnt]->bv_val, ldap_err2string (ret), hostdn); if(NULL != ldres) ldap_msgfree(ldres); res = ISC_R_FAILURE; break; } if ((ent = ldap_first_entry (ld, ldres)) == NULL) { log_error ("Error: Cannot find dhcpService DN '%s' with primary or secondary server reference. Please update the LDAP server entry '%s'", tempbv[cnt]->bv_val, hostdn); ldap_msgfree(ldres); res = ISC_R_FAILURE; break; } /* ** FIXME: how to free the remembered dn's on exit? ** This should be OK if dmalloc registers the ** memory it allocated and frees it on exit.. */ curr = dmalloc (sizeof (*curr), MDL); if (curr != NULL) { length = strlen (tempbv[cnt]->bv_val); curr->dn = dmalloc (length + 1, MDL); if (curr->dn == NULL) { dfree (curr, MDL); curr = NULL; } else strcpy (curr->dn, tempbv[cnt]->bv_val); } if (curr != NULL) { curr->refs++; /* append to service-dn list */ if (ldap_service_dn_tail != NULL) ldap_service_dn_tail->next = curr; else ldap_service_dn_head = curr; ldap_service_dn_tail = curr; } else log_fatal ("no memory to remember ldap service dn"); #if defined (DEBUG_LDAP) log_info ("LDAP: Parsing dhcpService DN '%s' ...", tempbv[cnt]); #endif add_to_config_stack (ldres, ent); res = conf_file_subparse (cfile, root_group, ROOT_GROUP); if (res != ISC_R_SUCCESS) { log_error ("LDAP: cannot parse dhcpService entry '%s'", tempbv[cnt]->bv_val); break; } } end_parse (&cfile); ldap_close_debug_fd(); ldap_memfree (hostdn); ldap_value_free_len (tempbv); if (res != ISC_R_SUCCESS) { struct ldap_config_stack *temp_stack; while ((curr = ldap_service_dn_head) != NULL) { ldap_service_dn_head = curr->next; dfree (curr->dn, MDL); dfree (curr, MDL); } ldap_service_dn_tail = NULL; while ((temp_stack = ldap_stack) != NULL) { ldap_stack = temp_stack->next; free_stack_entry (temp_stack); } ldap_stop(); } /* Unbind from ldap immediately after reading config in static mode. */ if (ldap_method == LDAP_METHOD_STATIC) ldap_stop(); return (res); } /* This function will parse the dhcpOption and dhcpStatements field in the LDAP entry if it exists. Right now, type will be either HOST_DECL or CLASS_DECL. If we are parsing a HOST_DECL, this always returns 0. If we are parsing a CLASS_DECL, this will return what the current lease limit is in LDAP. If there is no lease limit specified, we return 0 */ static int ldap_parse_options (LDAPMessage * ent, struct group *group, int type, struct host_decl *host, struct class **class) { int declaration, lease_limit; char option_buffer[8192]; enum dhcp_token token; struct parse *cfile; isc_result_t res; const char *val; lease_limit = 0; *option_buffer = '\0'; /* This block of code will try to find the parent of the host, and if it is a group object, fetch the options and apply to the host. */ if (type == HOST_DECL) { char *hostdn, *basedn, *temp1, *temp2, filter[1024]; LDAPMessage *groupdn, *entry; int ret; hostdn = ldap_get_dn (ld, ent); if( hostdn != NULL) { basedn = NULL; temp1 = strchr (hostdn, '='); if (temp1 != NULL) temp1 = strchr (++temp1, '='); if (temp1 != NULL) temp2 = strchr (++temp1, ','); else temp2 = NULL; if (temp2 != NULL) { snprintf (filter, sizeof(filter), "(&(cn=%.*s)(objectClass=dhcpGroup))", (int)(temp2 - temp1), temp1); basedn = strchr (temp1, ','); if (basedn != NULL) ++basedn; } if (basedn != NULL && *basedn != '\0') { ret = ldap_search_ext_s (ld, basedn, LDAP_SCOPE_SUBTREE, filter, NULL, 0, NULL, NULL, NULL, 0, &groupdn); if (ret == LDAP_SUCCESS) { if ((entry = ldap_first_entry (ld, groupdn)) != NULL) { res = ldap_parse_entry_options (entry, option_buffer, sizeof(option_buffer) - 1, &lease_limit); if (res != ISC_R_SUCCESS) { /* reset option buffer discarding any results */ *option_buffer = '\0'; lease_limit = 0; } } ldap_msgfree( groupdn); } } ldap_memfree( hostdn); } } res = ldap_parse_entry_options (ent, option_buffer, sizeof(option_buffer) - 1, &lease_limit); if (res != ISC_R_SUCCESS) return (lease_limit); option_buffer[sizeof(option_buffer) - 1] = '\0'; if (*option_buffer == '\0') return (lease_limit); cfile = (struct parse *) NULL; res = new_parse (&cfile, -1, option_buffer, strlen (option_buffer), type == HOST_DECL ? "LDAP-HOST" : "LDAP-SUBCLASS", 0); if (res != ISC_R_SUCCESS) return (lease_limit); #if defined (DEBUG_LDAP) log_info ("Sending the following options: '%s'", option_buffer); #endif declaration = 0; do { token = peek_token (&val, NULL, cfile); if (token == END_OF_FILE) break; declaration = parse_statement (cfile, group, type, host, declaration); } while (1); end_parse (&cfile); return (lease_limit); } int find_haddr_in_ldap (struct host_decl **hp, int htype, unsigned hlen, const unsigned char *haddr, const char *file, int line) { char buf[128], *type_str; LDAPMessage * res, *ent; struct host_decl * host; isc_result_t status; ldap_dn_node *curr; int ret; if (ldap_method == LDAP_METHOD_STATIC) return (0); if (ld == NULL) ldap_start (); if (ld == NULL) return (0); switch (htype) { case HTYPE_ETHER: type_str = "ethernet"; break; case HTYPE_IEEE802: type_str = "token-ring"; break; case HTYPE_FDDI: type_str = "fddi"; break; default: log_info ("Ignoring unknown type %d", htype); return (0); } /* ** FIXME: It is not guaranteed, that the dhcpHWAddress attribute ** contains _exactly_ "type addr" with one space between! */ snprintf (buf, sizeof (buf), "(&(objectClass=dhcpHost)(dhcpHWAddress=%s %s))", type_str, print_hw_addr (htype, hlen, haddr)); res = ent = NULL; for (curr = ldap_service_dn_head; curr != NULL && *curr->dn != '\0'; curr = curr->next) { #if defined (DEBUG_LDAP) log_info ("Searching for %s in LDAP tree %s", buf, curr->dn); #endif ret = ldap_search_ext_s (ld, curr->dn, LDAP_SCOPE_SUBTREE, buf, NULL, 0, NULL, NULL, NULL, 0, &res); if(ret == LDAP_SERVER_DOWN) { log_info ("LDAP server was down, trying to reconnect..."); ldap_stop(); ldap_start(); if(ld == NULL) { log_info ("LDAP reconnect failed - try again later..."); return (0); } ret = ldap_search_ext_s (ld, curr->dn, LDAP_SCOPE_SUBTREE, buf, NULL, 0, NULL, NULL, NULL, 0, &res); } if (ret == LDAP_SUCCESS) { if( (ent = ldap_first_entry (ld, res)) != NULL) break; /* search OK and have entry */ #if defined (DEBUG_LDAP) log_info ("No host entry for %s in LDAP tree %s", buf, curr->dn); #endif if(res) { ldap_msgfree (res); res = NULL; } } else { if(res) { ldap_msgfree (res); res = NULL; } if (ret != LDAP_NO_SUCH_OBJECT && ret != LDAP_SUCCESS) { log_error ("Cannot search for %s in LDAP tree %s: %s", buf, curr->dn, ldap_err2string (ret)); ldap_stop(); return (0); } #if defined (DEBUG_LDAP) else { log_info ("ldap_search_ext_s returned %s when searching for %s in %s", ldap_err2string (ret), buf, curr->dn); } #endif } } if (res && ent) { #if defined (DEBUG_LDAP) char *dn = ldap_get_dn (ld, ent); if (dn != NULL) { log_info ("Found dhcpHWAddress LDAP entry %s", dn); ldap_memfree(dn); } #endif host = (struct host_decl *)0; status = host_allocate (&host, MDL); if (status != ISC_R_SUCCESS) { log_fatal ("can't allocate host decl struct: %s", isc_result_totext (status)); ldap_msgfree (res); return (0); } host->name = ldap_get_host_name (ent); if (host->name == NULL) { host_dereference (&host, MDL); ldap_msgfree (res); return (0); } if (!clone_group (&host->group, root_group, MDL)) { log_fatal ("can't clone group for host %s", host->name); host_dereference (&host, MDL); ldap_msgfree (res); return (0); } ldap_parse_options (ent, host->group, HOST_DECL, host, NULL); *hp = host; ldap_msgfree (res); return (1); } if(res) ldap_msgfree (res); return (0); } int find_subclass_in_ldap (struct class *class, struct class **newclass, struct data_string *data) { LDAPMessage * res, * ent; int ret, lease_limit; isc_result_t status; ldap_dn_node *curr; char buf[1024]; if (ldap_method == LDAP_METHOD_STATIC) return (0); if (ld == NULL) ldap_start (); if (ld == NULL) return (0); snprintf (buf, sizeof (buf), "(&(objectClass=dhcpSubClass)(cn=%s)(dhcpClassData=%s))", print_hex_1 (data->len, data->data, 60), print_hex_2 (strlen (class->name), (u_int8_t *) class->name, 60)); #if defined (DEBUG_LDAP) log_info ("Searching LDAP for %s", buf); #endif res = ent = NULL; for (curr = ldap_service_dn_head; curr != NULL && *curr->dn != '\0'; curr = curr->next) { #if defined (DEBUG_LDAP) log_info ("Searching for %s in LDAP tree %s", buf, curr->dn); #endif ret = ldap_search_ext_s (ld, curr->dn, LDAP_SCOPE_SUBTREE, buf, NULL, 0, NULL, NULL, NULL, 0, &res); if(ret == LDAP_SERVER_DOWN) { log_info ("LDAP server was down, trying to reconnect..."); ldap_stop(); ldap_start(); if(ld == NULL) { log_info ("LDAP reconnect failed - try again later..."); return (0); } ret = ldap_search_ext_s (ld, curr->dn, LDAP_SCOPE_SUBTREE, buf, NULL, 0, NULL, NULL, NULL, 0, &res); } if (ret == LDAP_SUCCESS) { if( (ent = ldap_first_entry (ld, res)) != NULL) break; /* search OK and have entry */ #if defined (DEBUG_LDAP) log_info ("No subclass entry for %s in LDAP tree %s", buf, curr->dn); #endif if(res) { ldap_msgfree (res); res = NULL; } } else { if(res) { ldap_msgfree (res); res = NULL; } if (ret != LDAP_NO_SUCH_OBJECT && ret != LDAP_SUCCESS) { log_error ("Cannot search for %s in LDAP tree %s: %s", buf, curr->dn, ldap_err2string (ret)); ldap_stop(); return (0); } #if defined (DEBUG_LDAP) else { log_info ("ldap_search_ext_s returned %s when searching for %s in %s", ldap_err2string (ret), buf, curr->dn); } #endif } } if (res && ent) { #if defined (DEBUG_LDAP) char *dn = ldap_get_dn (ld, ent); if (dn != NULL) { log_info ("Found subclass LDAP entry %s", dn); ldap_memfree(dn); } #endif status = class_allocate (newclass, MDL); if (status != ISC_R_SUCCESS) { log_error ("Cannot allocate memory for a new class"); ldap_msgfree (res); return (0); } group_reference (&(*newclass)->group, class->group, MDL); class_reference (&(*newclass)->superclass, class, MDL); lease_limit = ldap_parse_options (ent, (*newclass)->group, CLASS_DECL, NULL, newclass); if (lease_limit == 0) (*newclass)->lease_limit = class->lease_limit; else class->lease_limit = lease_limit; if ((*newclass)->lease_limit) { (*newclass)->billed_leases = dmalloc ((*newclass)->lease_limit * sizeof (struct lease *), MDL); if (!(*newclass)->billed_leases) { log_error ("no memory for billing"); class_dereference (newclass, MDL); ldap_msgfree (res); return (0); } memset ((*newclass)->billed_leases, 0, ((*newclass)->lease_limit * sizeof (*newclass)->billed_leases)); } data_string_copy (&(*newclass)->hash_string, data, MDL); ldap_msgfree (res); return (1); } if(res) ldap_msgfree (res); return (0); } #endif dhcp-4.2.4/server/ldap_casa.c000644 000765 000024 00000012531 11352700302 015743 0ustar00sarstaff000000 000000 /* ldap_casa.c CASA routines for DHCPD... */ /* Copyright (c) 2006 Novell, Inc. * All rights reserved. * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * 1.Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2.Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3.Neither the name of ISC, ISC DHCP, nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * THIS SOFTWARE IS PROVIDED BY INTERNET SYSTEMS CONSORTIUM AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ISC OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * This file was written by S Kalyanasundaram */ /* * Copyright (c) 2004-2010 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1995-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ */ #if defined(LDAP_CASA_AUTH) #include "ldap_casa.h" #include "dhcpd.h" int load_casa (void) { if( !(casaIDK = dlopen(MICASA_LIB,RTLD_LAZY))) return 0; p_miCASAGetCredential = (CASA_GetCredential_T) dlsym(casaIDK, "miCASAGetCredential"); p_miCASASetCredential = (CASA_SetCredential_T) dlsym(casaIDK, "miCASASetCredential"); p_miCASARemoveCredential = (CASA_RemoveCredential_T) dlsym(casaIDK, "miCASARemoveCredential"); if((p_miCASAGetCredential == NULL) || (p_miCASASetCredential == NULL) || (p_miCASARemoveCredential == NULL)) { if(casaIDK) dlclose(casaIDK); casaIDK = NULL; p_miCASAGetCredential = NULL; p_miCASASetCredential = NULL; p_miCASARemoveCredential = NULL; return 0; } else return 1; } static void release_casa(void) { if(casaIDK) { dlclose(casaIDK); casaIDK = NULL; } p_miCASAGetCredential = NULL; p_miCASASetCredential = NULL; p_miCASARemoveCredential = NULL; } int load_uname_pwd_from_miCASA (char **ldap_username, char **ldap_password) { int result = 0; uint32_t credentialtype = SSCS_CRED_TYPE_SERVER_F; SSCS_BASIC_CREDENTIAL credential; SSCS_SECRET_ID_T applicationSecretId; char *tempVar = NULL; const char applicationName[10] = "dhcp-ldap"; if ( load_casa() ) { memset(&credential, 0, sizeof(SSCS_BASIC_CREDENTIAL)); memset(&applicationSecretId, 0, sizeof(SSCS_SECRET_ID_T)); applicationSecretId.len = strlen(applicationName) + 1; memcpy (applicationSecretId.id, applicationName, applicationSecretId.len); credential.unFlags = USERNAME_TYPE_CN_F; result = p_miCASAGetCredential (0, &applicationSecretId,NULL,&credentialtype, &credential,NULL); if(credential.unLen) { tempVar = dmalloc (credential.unLen + 1, MDL); if (!tempVar) log_fatal ("no memory for ldap_username"); memcpy(tempVar , credential.username, credential.unLen); *ldap_username = tempVar; tempVar = dmalloc (credential.pwordLen + 1, MDL); if (!tempVar) log_fatal ("no memory for ldap_password"); memcpy(tempVar, credential.password, credential.pwordLen); *ldap_password = tempVar; #if defined (DEBUG_LDAP) log_info ("Authentication credential taken from CASA"); #endif release_casa(); return 1; } else { release_casa(); return 0; } } else return 0; //casa libraries not loaded } #endif /* LDAP_CASA_AUTH */ dhcp-4.2.4/server/Makefile.am000644 000765 000024 00000001017 11352504373 015733 0ustar00sarstaff000000 000000 AM_CPPFLAGS = -I.. -DLOCALSTATEDIR='"@localstatedir@"' dist_sysconf_DATA = dhcpd.conf sbin_PROGRAMS = dhcpd dhcpd_SOURCES = dhcpd.c dhcp.c bootp.c confpars.c db.c class.c failover.c \ omapi.c mdb.c stables.c salloc.c ddns.c dhcpleasequery.c \ dhcpv6.c mdb6.c ldap.c ldap_casa.c dhcpd_CFLAGS = $(LDAP_CFLAGS) dhcpd_LDADD = ../common/libdhcp.a ../omapip/libomapi.a \ ../dhcpctl/libdhcpctl.a ../bind/lib/libdns.a \ ../bind/lib/libisc.a man_MANS = dhcpd.8 dhcpd.conf.5 dhcpd.leases.5 EXTRA_DIST = $(man_MANS) dhcp-4.2.4/server/Makefile.in000644 000765 000024 00000132636 11757500142 015757 0ustar00sarstaff000000 000000 # Makefile.in generated by automake 1.10.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : sbin_PROGRAMS = dhcpd$(EXEEXT) subdir = server DIST_COMMON = $(dist_sysconf_DATA) $(srcdir)/Makefile.am \ $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/includes/config.h CONFIG_CLEAN_FILES = am__installdirs = "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(man5dir)" \ "$(DESTDIR)$(man8dir)" "$(DESTDIR)$(sysconfdir)" sbinPROGRAMS_INSTALL = $(INSTALL_PROGRAM) PROGRAMS = $(sbin_PROGRAMS) am_dhcpd_OBJECTS = dhcpd-dhcpd.$(OBJEXT) dhcpd-dhcp.$(OBJEXT) \ dhcpd-bootp.$(OBJEXT) dhcpd-confpars.$(OBJEXT) \ dhcpd-db.$(OBJEXT) dhcpd-class.$(OBJEXT) \ dhcpd-failover.$(OBJEXT) dhcpd-omapi.$(OBJEXT) \ dhcpd-mdb.$(OBJEXT) dhcpd-stables.$(OBJEXT) \ dhcpd-salloc.$(OBJEXT) dhcpd-ddns.$(OBJEXT) \ dhcpd-dhcpleasequery.$(OBJEXT) dhcpd-dhcpv6.$(OBJEXT) \ dhcpd-mdb6.$(OBJEXT) dhcpd-ldap.$(OBJEXT) \ dhcpd-ldap_casa.$(OBJEXT) dhcpd_OBJECTS = $(am_dhcpd_OBJECTS) dhcpd_DEPENDENCIES = ../common/libdhcp.a ../omapip/libomapi.a \ ../dhcpctl/libdhcpctl.a ../bind/lib/libdns.a \ ../bind/lib/libisc.a dhcpd_LINK = $(CCLD) $(dhcpd_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/includes depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) CCLD = $(CC) LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ SOURCES = $(dhcpd_SOURCES) DIST_SOURCES = $(dhcpd_SOURCES) man5dir = $(mandir)/man5 man8dir = $(mandir)/man8 NROFF = nroff MANS = $(man_MANS) am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = `echo $$p | sed -e 's|^.*/||'`; dist_sysconfDATA_INSTALL = $(INSTALL_DATA) DATA = $(dist_sysconf_DATA) ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ GREP = @GREP@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDAP_CFLAGS = @LDAP_CFLAGS@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_prefix_program = @ac_prefix_program@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build_alias = @build_alias@ builddir = @builddir@ byte_order = @byte_order@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host_alias = @host_alias@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AM_CPPFLAGS = -I.. -DLOCALSTATEDIR='"@localstatedir@"' dist_sysconf_DATA = dhcpd.conf dhcpd_SOURCES = dhcpd.c dhcp.c bootp.c confpars.c db.c class.c failover.c \ omapi.c mdb.c stables.c salloc.c ddns.c dhcpleasequery.c \ dhcpv6.c mdb6.c ldap.c ldap_casa.c dhcpd_CFLAGS = $(LDAP_CFLAGS) dhcpd_LDADD = ../common/libdhcp.a ../omapip/libomapi.a \ ../dhcpctl/libdhcpctl.a ../bind/lib/libdns.a \ ../bind/lib/libisc.a man_MANS = dhcpd.8 dhcpd.conf.5 dhcpd.leases.5 EXTRA_DIST = $(man_MANS) all: all-am .SUFFIXES: .SUFFIXES: .c .o .obj $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ && exit 0; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign server/Makefile'; \ cd $(top_srcdir) && \ $(AUTOMAKE) --foreign server/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh install-sbinPROGRAMS: $(sbin_PROGRAMS) @$(NORMAL_INSTALL) test -z "$(sbindir)" || $(MKDIR_P) "$(DESTDIR)$(sbindir)" @list='$(sbin_PROGRAMS)'; for p in $$list; do \ p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ if test -f $$p \ ; then \ f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \ echo " $(INSTALL_PROGRAM_ENV) $(sbinPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(sbindir)/$$f'"; \ $(INSTALL_PROGRAM_ENV) $(sbinPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(sbindir)/$$f" || exit 1; \ else :; fi; \ done uninstall-sbinPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(sbin_PROGRAMS)'; for p in $$list; do \ f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ echo " rm -f '$(DESTDIR)$(sbindir)/$$f'"; \ rm -f "$(DESTDIR)$(sbindir)/$$f"; \ done clean-sbinPROGRAMS: -test -z "$(sbin_PROGRAMS)" || rm -f $(sbin_PROGRAMS) dhcpd$(EXEEXT): $(dhcpd_OBJECTS) $(dhcpd_DEPENDENCIES) @rm -f dhcpd$(EXEEXT) $(dhcpd_LINK) $(dhcpd_OBJECTS) $(dhcpd_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dhcpd-bootp.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dhcpd-class.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dhcpd-confpars.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dhcpd-db.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dhcpd-ddns.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dhcpd-dhcp.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dhcpd-dhcpd.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dhcpd-dhcpleasequery.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dhcpd-dhcpv6.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dhcpd-failover.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dhcpd-ldap.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dhcpd-ldap_casa.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dhcpd-mdb.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dhcpd-mdb6.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dhcpd-omapi.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dhcpd-salloc.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dhcpd-stables.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` dhcpd-dhcpd.o: dhcpd.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(dhcpd_CFLAGS) $(CFLAGS) -MT dhcpd-dhcpd.o -MD -MP -MF $(DEPDIR)/dhcpd-dhcpd.Tpo -c -o dhcpd-dhcpd.o `test -f 'dhcpd.c' || echo '$(srcdir)/'`dhcpd.c @am__fastdepCC_TRUE@ mv -f $(DEPDIR)/dhcpd-dhcpd.Tpo $(DEPDIR)/dhcpd-dhcpd.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='dhcpd.c' object='dhcpd-dhcpd.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(dhcpd_CFLAGS) $(CFLAGS) -c -o dhcpd-dhcpd.o `test -f 'dhcpd.c' || echo '$(srcdir)/'`dhcpd.c dhcpd-dhcpd.obj: dhcpd.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(dhcpd_CFLAGS) $(CFLAGS) -MT dhcpd-dhcpd.obj -MD -MP -MF $(DEPDIR)/dhcpd-dhcpd.Tpo -c -o dhcpd-dhcpd.obj `if test -f 'dhcpd.c'; then $(CYGPATH_W) 'dhcpd.c'; else $(CYGPATH_W) '$(srcdir)/dhcpd.c'; fi` @am__fastdepCC_TRUE@ mv -f $(DEPDIR)/dhcpd-dhcpd.Tpo $(DEPDIR)/dhcpd-dhcpd.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='dhcpd.c' object='dhcpd-dhcpd.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(dhcpd_CFLAGS) $(CFLAGS) -c -o dhcpd-dhcpd.obj `if test -f 'dhcpd.c'; then $(CYGPATH_W) 'dhcpd.c'; else $(CYGPATH_W) '$(srcdir)/dhcpd.c'; fi` dhcpd-dhcp.o: dhcp.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(dhcpd_CFLAGS) $(CFLAGS) -MT dhcpd-dhcp.o -MD -MP -MF $(DEPDIR)/dhcpd-dhcp.Tpo -c -o dhcpd-dhcp.o `test -f 'dhcp.c' || echo '$(srcdir)/'`dhcp.c @am__fastdepCC_TRUE@ mv -f $(DEPDIR)/dhcpd-dhcp.Tpo $(DEPDIR)/dhcpd-dhcp.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='dhcp.c' object='dhcpd-dhcp.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(dhcpd_CFLAGS) $(CFLAGS) -c -o dhcpd-dhcp.o `test -f 'dhcp.c' || echo '$(srcdir)/'`dhcp.c dhcpd-dhcp.obj: dhcp.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(dhcpd_CFLAGS) $(CFLAGS) -MT dhcpd-dhcp.obj -MD -MP -MF $(DEPDIR)/dhcpd-dhcp.Tpo -c -o dhcpd-dhcp.obj `if test -f 'dhcp.c'; then $(CYGPATH_W) 'dhcp.c'; else $(CYGPATH_W) '$(srcdir)/dhcp.c'; fi` @am__fastdepCC_TRUE@ mv -f $(DEPDIR)/dhcpd-dhcp.Tpo $(DEPDIR)/dhcpd-dhcp.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='dhcp.c' object='dhcpd-dhcp.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(dhcpd_CFLAGS) $(CFLAGS) -c -o dhcpd-dhcp.obj `if test -f 'dhcp.c'; then $(CYGPATH_W) 'dhcp.c'; else $(CYGPATH_W) '$(srcdir)/dhcp.c'; fi` dhcpd-bootp.o: bootp.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(dhcpd_CFLAGS) $(CFLAGS) -MT dhcpd-bootp.o -MD -MP -MF $(DEPDIR)/dhcpd-bootp.Tpo -c -o dhcpd-bootp.o `test -f 'bootp.c' || echo '$(srcdir)/'`bootp.c @am__fastdepCC_TRUE@ mv -f $(DEPDIR)/dhcpd-bootp.Tpo $(DEPDIR)/dhcpd-bootp.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='bootp.c' object='dhcpd-bootp.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(dhcpd_CFLAGS) $(CFLAGS) -c -o dhcpd-bootp.o `test -f 'bootp.c' || echo '$(srcdir)/'`bootp.c dhcpd-bootp.obj: bootp.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(dhcpd_CFLAGS) $(CFLAGS) -MT dhcpd-bootp.obj -MD -MP -MF $(DEPDIR)/dhcpd-bootp.Tpo -c -o dhcpd-bootp.obj `if test -f 'bootp.c'; then $(CYGPATH_W) 'bootp.c'; else $(CYGPATH_W) '$(srcdir)/bootp.c'; fi` @am__fastdepCC_TRUE@ mv -f $(DEPDIR)/dhcpd-bootp.Tpo $(DEPDIR)/dhcpd-bootp.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='bootp.c' object='dhcpd-bootp.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(dhcpd_CFLAGS) $(CFLAGS) -c -o dhcpd-bootp.obj `if test -f 'bootp.c'; then $(CYGPATH_W) 'bootp.c'; else $(CYGPATH_W) '$(srcdir)/bootp.c'; fi` dhcpd-confpars.o: confpars.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(dhcpd_CFLAGS) $(CFLAGS) -MT dhcpd-confpars.o -MD -MP -MF $(DEPDIR)/dhcpd-confpars.Tpo -c -o dhcpd-confpars.o `test -f 'confpars.c' || echo '$(srcdir)/'`confpars.c @am__fastdepCC_TRUE@ mv -f $(DEPDIR)/dhcpd-confpars.Tpo $(DEPDIR)/dhcpd-confpars.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='confpars.c' object='dhcpd-confpars.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(dhcpd_CFLAGS) $(CFLAGS) -c -o dhcpd-confpars.o `test -f 'confpars.c' || echo '$(srcdir)/'`confpars.c dhcpd-confpars.obj: confpars.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(dhcpd_CFLAGS) $(CFLAGS) -MT dhcpd-confpars.obj -MD -MP -MF $(DEPDIR)/dhcpd-confpars.Tpo -c -o dhcpd-confpars.obj `if test -f 'confpars.c'; then $(CYGPATH_W) 'confpars.c'; else $(CYGPATH_W) '$(srcdir)/confpars.c'; fi` @am__fastdepCC_TRUE@ mv -f $(DEPDIR)/dhcpd-confpars.Tpo $(DEPDIR)/dhcpd-confpars.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='confpars.c' object='dhcpd-confpars.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(dhcpd_CFLAGS) $(CFLAGS) -c -o dhcpd-confpars.obj `if test -f 'confpars.c'; then $(CYGPATH_W) 'confpars.c'; else $(CYGPATH_W) '$(srcdir)/confpars.c'; fi` dhcpd-db.o: db.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(dhcpd_CFLAGS) $(CFLAGS) -MT dhcpd-db.o -MD -MP -MF $(DEPDIR)/dhcpd-db.Tpo -c -o dhcpd-db.o `test -f 'db.c' || echo '$(srcdir)/'`db.c @am__fastdepCC_TRUE@ mv -f $(DEPDIR)/dhcpd-db.Tpo $(DEPDIR)/dhcpd-db.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='db.c' object='dhcpd-db.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(dhcpd_CFLAGS) $(CFLAGS) -c -o dhcpd-db.o `test -f 'db.c' || echo '$(srcdir)/'`db.c dhcpd-db.obj: db.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(dhcpd_CFLAGS) $(CFLAGS) -MT dhcpd-db.obj -MD -MP -MF $(DEPDIR)/dhcpd-db.Tpo -c -o dhcpd-db.obj `if test -f 'db.c'; then $(CYGPATH_W) 'db.c'; else $(CYGPATH_W) '$(srcdir)/db.c'; fi` @am__fastdepCC_TRUE@ mv -f $(DEPDIR)/dhcpd-db.Tpo $(DEPDIR)/dhcpd-db.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='db.c' object='dhcpd-db.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(dhcpd_CFLAGS) $(CFLAGS) -c -o dhcpd-db.obj `if test -f 'db.c'; then $(CYGPATH_W) 'db.c'; else $(CYGPATH_W) '$(srcdir)/db.c'; fi` dhcpd-class.o: class.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(dhcpd_CFLAGS) $(CFLAGS) -MT dhcpd-class.o -MD -MP -MF $(DEPDIR)/dhcpd-class.Tpo -c -o dhcpd-class.o `test -f 'class.c' || echo '$(srcdir)/'`class.c @am__fastdepCC_TRUE@ mv -f $(DEPDIR)/dhcpd-class.Tpo $(DEPDIR)/dhcpd-class.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='class.c' object='dhcpd-class.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(dhcpd_CFLAGS) $(CFLAGS) -c -o dhcpd-class.o `test -f 'class.c' || echo '$(srcdir)/'`class.c dhcpd-class.obj: class.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(dhcpd_CFLAGS) $(CFLAGS) -MT dhcpd-class.obj -MD -MP -MF $(DEPDIR)/dhcpd-class.Tpo -c -o dhcpd-class.obj `if test -f 'class.c'; then $(CYGPATH_W) 'class.c'; else $(CYGPATH_W) '$(srcdir)/class.c'; fi` @am__fastdepCC_TRUE@ mv -f $(DEPDIR)/dhcpd-class.Tpo $(DEPDIR)/dhcpd-class.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='class.c' object='dhcpd-class.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(dhcpd_CFLAGS) $(CFLAGS) -c -o dhcpd-class.obj `if test -f 'class.c'; then $(CYGPATH_W) 'class.c'; else $(CYGPATH_W) '$(srcdir)/class.c'; fi` dhcpd-failover.o: failover.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(dhcpd_CFLAGS) $(CFLAGS) -MT dhcpd-failover.o -MD -MP -MF $(DEPDIR)/dhcpd-failover.Tpo -c -o dhcpd-failover.o `test -f 'failover.c' || echo '$(srcdir)/'`failover.c @am__fastdepCC_TRUE@ mv -f $(DEPDIR)/dhcpd-failover.Tpo $(DEPDIR)/dhcpd-failover.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='failover.c' object='dhcpd-failover.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(dhcpd_CFLAGS) $(CFLAGS) -c -o dhcpd-failover.o `test -f 'failover.c' || echo '$(srcdir)/'`failover.c dhcpd-failover.obj: failover.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(dhcpd_CFLAGS) $(CFLAGS) -MT dhcpd-failover.obj -MD -MP -MF $(DEPDIR)/dhcpd-failover.Tpo -c -o dhcpd-failover.obj `if test -f 'failover.c'; then $(CYGPATH_W) 'failover.c'; else $(CYGPATH_W) '$(srcdir)/failover.c'; fi` @am__fastdepCC_TRUE@ mv -f $(DEPDIR)/dhcpd-failover.Tpo $(DEPDIR)/dhcpd-failover.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='failover.c' object='dhcpd-failover.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(dhcpd_CFLAGS) $(CFLAGS) -c -o dhcpd-failover.obj `if test -f 'failover.c'; then $(CYGPATH_W) 'failover.c'; else $(CYGPATH_W) '$(srcdir)/failover.c'; fi` dhcpd-omapi.o: omapi.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(dhcpd_CFLAGS) $(CFLAGS) -MT dhcpd-omapi.o -MD -MP -MF $(DEPDIR)/dhcpd-omapi.Tpo -c -o dhcpd-omapi.o `test -f 'omapi.c' || echo '$(srcdir)/'`omapi.c @am__fastdepCC_TRUE@ mv -f $(DEPDIR)/dhcpd-omapi.Tpo $(DEPDIR)/dhcpd-omapi.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='omapi.c' object='dhcpd-omapi.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(dhcpd_CFLAGS) $(CFLAGS) -c -o dhcpd-omapi.o `test -f 'omapi.c' || echo '$(srcdir)/'`omapi.c dhcpd-omapi.obj: omapi.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(dhcpd_CFLAGS) $(CFLAGS) -MT dhcpd-omapi.obj -MD -MP -MF $(DEPDIR)/dhcpd-omapi.Tpo -c -o dhcpd-omapi.obj `if test -f 'omapi.c'; then $(CYGPATH_W) 'omapi.c'; else $(CYGPATH_W) '$(srcdir)/omapi.c'; fi` @am__fastdepCC_TRUE@ mv -f $(DEPDIR)/dhcpd-omapi.Tpo $(DEPDIR)/dhcpd-omapi.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='omapi.c' object='dhcpd-omapi.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(dhcpd_CFLAGS) $(CFLAGS) -c -o dhcpd-omapi.obj `if test -f 'omapi.c'; then $(CYGPATH_W) 'omapi.c'; else $(CYGPATH_W) '$(srcdir)/omapi.c'; fi` dhcpd-mdb.o: mdb.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(dhcpd_CFLAGS) $(CFLAGS) -MT dhcpd-mdb.o -MD -MP -MF $(DEPDIR)/dhcpd-mdb.Tpo -c -o dhcpd-mdb.o `test -f 'mdb.c' || echo '$(srcdir)/'`mdb.c @am__fastdepCC_TRUE@ mv -f $(DEPDIR)/dhcpd-mdb.Tpo $(DEPDIR)/dhcpd-mdb.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='mdb.c' object='dhcpd-mdb.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(dhcpd_CFLAGS) $(CFLAGS) -c -o dhcpd-mdb.o `test -f 'mdb.c' || echo '$(srcdir)/'`mdb.c dhcpd-mdb.obj: mdb.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(dhcpd_CFLAGS) $(CFLAGS) -MT dhcpd-mdb.obj -MD -MP -MF $(DEPDIR)/dhcpd-mdb.Tpo -c -o dhcpd-mdb.obj `if test -f 'mdb.c'; then $(CYGPATH_W) 'mdb.c'; else $(CYGPATH_W) '$(srcdir)/mdb.c'; fi` @am__fastdepCC_TRUE@ mv -f $(DEPDIR)/dhcpd-mdb.Tpo $(DEPDIR)/dhcpd-mdb.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='mdb.c' object='dhcpd-mdb.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(dhcpd_CFLAGS) $(CFLAGS) -c -o dhcpd-mdb.obj `if test -f 'mdb.c'; then $(CYGPATH_W) 'mdb.c'; else $(CYGPATH_W) '$(srcdir)/mdb.c'; fi` dhcpd-stables.o: stables.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(dhcpd_CFLAGS) $(CFLAGS) -MT dhcpd-stables.o -MD -MP -MF $(DEPDIR)/dhcpd-stables.Tpo -c -o dhcpd-stables.o `test -f 'stables.c' || echo '$(srcdir)/'`stables.c @am__fastdepCC_TRUE@ mv -f $(DEPDIR)/dhcpd-stables.Tpo $(DEPDIR)/dhcpd-stables.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='stables.c' object='dhcpd-stables.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(dhcpd_CFLAGS) $(CFLAGS) -c -o dhcpd-stables.o `test -f 'stables.c' || echo '$(srcdir)/'`stables.c dhcpd-stables.obj: stables.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(dhcpd_CFLAGS) $(CFLAGS) -MT dhcpd-stables.obj -MD -MP -MF $(DEPDIR)/dhcpd-stables.Tpo -c -o dhcpd-stables.obj `if test -f 'stables.c'; then $(CYGPATH_W) 'stables.c'; else $(CYGPATH_W) '$(srcdir)/stables.c'; fi` @am__fastdepCC_TRUE@ mv -f $(DEPDIR)/dhcpd-stables.Tpo $(DEPDIR)/dhcpd-stables.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='stables.c' object='dhcpd-stables.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(dhcpd_CFLAGS) $(CFLAGS) -c -o dhcpd-stables.obj `if test -f 'stables.c'; then $(CYGPATH_W) 'stables.c'; else $(CYGPATH_W) '$(srcdir)/stables.c'; fi` dhcpd-salloc.o: salloc.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(dhcpd_CFLAGS) $(CFLAGS) -MT dhcpd-salloc.o -MD -MP -MF $(DEPDIR)/dhcpd-salloc.Tpo -c -o dhcpd-salloc.o `test -f 'salloc.c' || echo '$(srcdir)/'`salloc.c @am__fastdepCC_TRUE@ mv -f $(DEPDIR)/dhcpd-salloc.Tpo $(DEPDIR)/dhcpd-salloc.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='salloc.c' object='dhcpd-salloc.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(dhcpd_CFLAGS) $(CFLAGS) -c -o dhcpd-salloc.o `test -f 'salloc.c' || echo '$(srcdir)/'`salloc.c dhcpd-salloc.obj: salloc.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(dhcpd_CFLAGS) $(CFLAGS) -MT dhcpd-salloc.obj -MD -MP -MF $(DEPDIR)/dhcpd-salloc.Tpo -c -o dhcpd-salloc.obj `if test -f 'salloc.c'; then $(CYGPATH_W) 'salloc.c'; else $(CYGPATH_W) '$(srcdir)/salloc.c'; fi` @am__fastdepCC_TRUE@ mv -f $(DEPDIR)/dhcpd-salloc.Tpo $(DEPDIR)/dhcpd-salloc.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='salloc.c' object='dhcpd-salloc.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(dhcpd_CFLAGS) $(CFLAGS) -c -o dhcpd-salloc.obj `if test -f 'salloc.c'; then $(CYGPATH_W) 'salloc.c'; else $(CYGPATH_W) '$(srcdir)/salloc.c'; fi` dhcpd-ddns.o: ddns.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(dhcpd_CFLAGS) $(CFLAGS) -MT dhcpd-ddns.o -MD -MP -MF $(DEPDIR)/dhcpd-ddns.Tpo -c -o dhcpd-ddns.o `test -f 'ddns.c' || echo '$(srcdir)/'`ddns.c @am__fastdepCC_TRUE@ mv -f $(DEPDIR)/dhcpd-ddns.Tpo $(DEPDIR)/dhcpd-ddns.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='ddns.c' object='dhcpd-ddns.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(dhcpd_CFLAGS) $(CFLAGS) -c -o dhcpd-ddns.o `test -f 'ddns.c' || echo '$(srcdir)/'`ddns.c dhcpd-ddns.obj: ddns.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(dhcpd_CFLAGS) $(CFLAGS) -MT dhcpd-ddns.obj -MD -MP -MF $(DEPDIR)/dhcpd-ddns.Tpo -c -o dhcpd-ddns.obj `if test -f 'ddns.c'; then $(CYGPATH_W) 'ddns.c'; else $(CYGPATH_W) '$(srcdir)/ddns.c'; fi` @am__fastdepCC_TRUE@ mv -f $(DEPDIR)/dhcpd-ddns.Tpo $(DEPDIR)/dhcpd-ddns.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='ddns.c' object='dhcpd-ddns.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(dhcpd_CFLAGS) $(CFLAGS) -c -o dhcpd-ddns.obj `if test -f 'ddns.c'; then $(CYGPATH_W) 'ddns.c'; else $(CYGPATH_W) '$(srcdir)/ddns.c'; fi` dhcpd-dhcpleasequery.o: dhcpleasequery.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(dhcpd_CFLAGS) $(CFLAGS) -MT dhcpd-dhcpleasequery.o -MD -MP -MF $(DEPDIR)/dhcpd-dhcpleasequery.Tpo -c -o dhcpd-dhcpleasequery.o `test -f 'dhcpleasequery.c' || echo '$(srcdir)/'`dhcpleasequery.c @am__fastdepCC_TRUE@ mv -f $(DEPDIR)/dhcpd-dhcpleasequery.Tpo $(DEPDIR)/dhcpd-dhcpleasequery.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='dhcpleasequery.c' object='dhcpd-dhcpleasequery.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(dhcpd_CFLAGS) $(CFLAGS) -c -o dhcpd-dhcpleasequery.o `test -f 'dhcpleasequery.c' || echo '$(srcdir)/'`dhcpleasequery.c dhcpd-dhcpleasequery.obj: dhcpleasequery.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(dhcpd_CFLAGS) $(CFLAGS) -MT dhcpd-dhcpleasequery.obj -MD -MP -MF $(DEPDIR)/dhcpd-dhcpleasequery.Tpo -c -o dhcpd-dhcpleasequery.obj `if test -f 'dhcpleasequery.c'; then $(CYGPATH_W) 'dhcpleasequery.c'; else $(CYGPATH_W) '$(srcdir)/dhcpleasequery.c'; fi` @am__fastdepCC_TRUE@ mv -f $(DEPDIR)/dhcpd-dhcpleasequery.Tpo $(DEPDIR)/dhcpd-dhcpleasequery.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='dhcpleasequery.c' object='dhcpd-dhcpleasequery.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(dhcpd_CFLAGS) $(CFLAGS) -c -o dhcpd-dhcpleasequery.obj `if test -f 'dhcpleasequery.c'; then $(CYGPATH_W) 'dhcpleasequery.c'; else $(CYGPATH_W) '$(srcdir)/dhcpleasequery.c'; fi` dhcpd-dhcpv6.o: dhcpv6.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(dhcpd_CFLAGS) $(CFLAGS) -MT dhcpd-dhcpv6.o -MD -MP -MF $(DEPDIR)/dhcpd-dhcpv6.Tpo -c -o dhcpd-dhcpv6.o `test -f 'dhcpv6.c' || echo '$(srcdir)/'`dhcpv6.c @am__fastdepCC_TRUE@ mv -f $(DEPDIR)/dhcpd-dhcpv6.Tpo $(DEPDIR)/dhcpd-dhcpv6.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='dhcpv6.c' object='dhcpd-dhcpv6.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(dhcpd_CFLAGS) $(CFLAGS) -c -o dhcpd-dhcpv6.o `test -f 'dhcpv6.c' || echo '$(srcdir)/'`dhcpv6.c dhcpd-dhcpv6.obj: dhcpv6.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(dhcpd_CFLAGS) $(CFLAGS) -MT dhcpd-dhcpv6.obj -MD -MP -MF $(DEPDIR)/dhcpd-dhcpv6.Tpo -c -o dhcpd-dhcpv6.obj `if test -f 'dhcpv6.c'; then $(CYGPATH_W) 'dhcpv6.c'; else $(CYGPATH_W) '$(srcdir)/dhcpv6.c'; fi` @am__fastdepCC_TRUE@ mv -f $(DEPDIR)/dhcpd-dhcpv6.Tpo $(DEPDIR)/dhcpd-dhcpv6.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='dhcpv6.c' object='dhcpd-dhcpv6.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(dhcpd_CFLAGS) $(CFLAGS) -c -o dhcpd-dhcpv6.obj `if test -f 'dhcpv6.c'; then $(CYGPATH_W) 'dhcpv6.c'; else $(CYGPATH_W) '$(srcdir)/dhcpv6.c'; fi` dhcpd-mdb6.o: mdb6.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(dhcpd_CFLAGS) $(CFLAGS) -MT dhcpd-mdb6.o -MD -MP -MF $(DEPDIR)/dhcpd-mdb6.Tpo -c -o dhcpd-mdb6.o `test -f 'mdb6.c' || echo '$(srcdir)/'`mdb6.c @am__fastdepCC_TRUE@ mv -f $(DEPDIR)/dhcpd-mdb6.Tpo $(DEPDIR)/dhcpd-mdb6.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='mdb6.c' object='dhcpd-mdb6.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(dhcpd_CFLAGS) $(CFLAGS) -c -o dhcpd-mdb6.o `test -f 'mdb6.c' || echo '$(srcdir)/'`mdb6.c dhcpd-mdb6.obj: mdb6.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(dhcpd_CFLAGS) $(CFLAGS) -MT dhcpd-mdb6.obj -MD -MP -MF $(DEPDIR)/dhcpd-mdb6.Tpo -c -o dhcpd-mdb6.obj `if test -f 'mdb6.c'; then $(CYGPATH_W) 'mdb6.c'; else $(CYGPATH_W) '$(srcdir)/mdb6.c'; fi` @am__fastdepCC_TRUE@ mv -f $(DEPDIR)/dhcpd-mdb6.Tpo $(DEPDIR)/dhcpd-mdb6.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='mdb6.c' object='dhcpd-mdb6.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(dhcpd_CFLAGS) $(CFLAGS) -c -o dhcpd-mdb6.obj `if test -f 'mdb6.c'; then $(CYGPATH_W) 'mdb6.c'; else $(CYGPATH_W) '$(srcdir)/mdb6.c'; fi` dhcpd-ldap.o: ldap.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(dhcpd_CFLAGS) $(CFLAGS) -MT dhcpd-ldap.o -MD -MP -MF $(DEPDIR)/dhcpd-ldap.Tpo -c -o dhcpd-ldap.o `test -f 'ldap.c' || echo '$(srcdir)/'`ldap.c @am__fastdepCC_TRUE@ mv -f $(DEPDIR)/dhcpd-ldap.Tpo $(DEPDIR)/dhcpd-ldap.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='ldap.c' object='dhcpd-ldap.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(dhcpd_CFLAGS) $(CFLAGS) -c -o dhcpd-ldap.o `test -f 'ldap.c' || echo '$(srcdir)/'`ldap.c dhcpd-ldap.obj: ldap.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(dhcpd_CFLAGS) $(CFLAGS) -MT dhcpd-ldap.obj -MD -MP -MF $(DEPDIR)/dhcpd-ldap.Tpo -c -o dhcpd-ldap.obj `if test -f 'ldap.c'; then $(CYGPATH_W) 'ldap.c'; else $(CYGPATH_W) '$(srcdir)/ldap.c'; fi` @am__fastdepCC_TRUE@ mv -f $(DEPDIR)/dhcpd-ldap.Tpo $(DEPDIR)/dhcpd-ldap.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='ldap.c' object='dhcpd-ldap.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(dhcpd_CFLAGS) $(CFLAGS) -c -o dhcpd-ldap.obj `if test -f 'ldap.c'; then $(CYGPATH_W) 'ldap.c'; else $(CYGPATH_W) '$(srcdir)/ldap.c'; fi` dhcpd-ldap_casa.o: ldap_casa.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(dhcpd_CFLAGS) $(CFLAGS) -MT dhcpd-ldap_casa.o -MD -MP -MF $(DEPDIR)/dhcpd-ldap_casa.Tpo -c -o dhcpd-ldap_casa.o `test -f 'ldap_casa.c' || echo '$(srcdir)/'`ldap_casa.c @am__fastdepCC_TRUE@ mv -f $(DEPDIR)/dhcpd-ldap_casa.Tpo $(DEPDIR)/dhcpd-ldap_casa.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='ldap_casa.c' object='dhcpd-ldap_casa.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(dhcpd_CFLAGS) $(CFLAGS) -c -o dhcpd-ldap_casa.o `test -f 'ldap_casa.c' || echo '$(srcdir)/'`ldap_casa.c dhcpd-ldap_casa.obj: ldap_casa.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(dhcpd_CFLAGS) $(CFLAGS) -MT dhcpd-ldap_casa.obj -MD -MP -MF $(DEPDIR)/dhcpd-ldap_casa.Tpo -c -o dhcpd-ldap_casa.obj `if test -f 'ldap_casa.c'; then $(CYGPATH_W) 'ldap_casa.c'; else $(CYGPATH_W) '$(srcdir)/ldap_casa.c'; fi` @am__fastdepCC_TRUE@ mv -f $(DEPDIR)/dhcpd-ldap_casa.Tpo $(DEPDIR)/dhcpd-ldap_casa.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='ldap_casa.c' object='dhcpd-ldap_casa.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(dhcpd_CFLAGS) $(CFLAGS) -c -o dhcpd-ldap_casa.obj `if test -f 'ldap_casa.c'; then $(CYGPATH_W) 'ldap_casa.c'; else $(CYGPATH_W) '$(srcdir)/ldap_casa.c'; fi` install-man5: $(man5_MANS) $(man_MANS) @$(NORMAL_INSTALL) test -z "$(man5dir)" || $(MKDIR_P) "$(DESTDIR)$(man5dir)" @list='$(man5_MANS) $(dist_man5_MANS) $(nodist_man5_MANS)'; \ l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ for i in $$l2; do \ case "$$i" in \ *.5*) list="$$list $$i" ;; \ esac; \ done; \ for i in $$list; do \ if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \ else file=$$i; fi; \ ext=`echo $$i | sed -e 's/^.*\\.//'`; \ case "$$ext" in \ 5*) ;; \ *) ext='5' ;; \ esac; \ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ inst=`echo $$inst | sed -e 's/^.*\///'`; \ inst=`echo $$inst | sed '$(transform)'`.$$ext; \ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man5dir)/$$inst'"; \ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man5dir)/$$inst"; \ done uninstall-man5: @$(NORMAL_UNINSTALL) @list='$(man5_MANS) $(dist_man5_MANS) $(nodist_man5_MANS)'; \ l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ for i in $$l2; do \ case "$$i" in \ *.5*) list="$$list $$i" ;; \ esac; \ done; \ for i in $$list; do \ ext=`echo $$i | sed -e 's/^.*\\.//'`; \ case "$$ext" in \ 5*) ;; \ *) ext='5' ;; \ esac; \ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ inst=`echo $$inst | sed -e 's/^.*\///'`; \ inst=`echo $$inst | sed '$(transform)'`.$$ext; \ echo " rm -f '$(DESTDIR)$(man5dir)/$$inst'"; \ rm -f "$(DESTDIR)$(man5dir)/$$inst"; \ done install-man8: $(man8_MANS) $(man_MANS) @$(NORMAL_INSTALL) test -z "$(man8dir)" || $(MKDIR_P) "$(DESTDIR)$(man8dir)" @list='$(man8_MANS) $(dist_man8_MANS) $(nodist_man8_MANS)'; \ l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ for i in $$l2; do \ case "$$i" in \ *.8*) list="$$list $$i" ;; \ esac; \ done; \ for i in $$list; do \ if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \ else file=$$i; fi; \ ext=`echo $$i | sed -e 's/^.*\\.//'`; \ case "$$ext" in \ 8*) ;; \ *) ext='8' ;; \ esac; \ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ inst=`echo $$inst | sed -e 's/^.*\///'`; \ inst=`echo $$inst | sed '$(transform)'`.$$ext; \ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man8dir)/$$inst'"; \ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man8dir)/$$inst"; \ done uninstall-man8: @$(NORMAL_UNINSTALL) @list='$(man8_MANS) $(dist_man8_MANS) $(nodist_man8_MANS)'; \ l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ for i in $$l2; do \ case "$$i" in \ *.8*) list="$$list $$i" ;; \ esac; \ done; \ for i in $$list; do \ ext=`echo $$i | sed -e 's/^.*\\.//'`; \ case "$$ext" in \ 8*) ;; \ *) ext='8' ;; \ esac; \ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ inst=`echo $$inst | sed -e 's/^.*\///'`; \ inst=`echo $$inst | sed '$(transform)'`.$$ext; \ echo " rm -f '$(DESTDIR)$(man8dir)/$$inst'"; \ rm -f "$(DESTDIR)$(man8dir)/$$inst"; \ done install-dist_sysconfDATA: $(dist_sysconf_DATA) @$(NORMAL_INSTALL) test -z "$(sysconfdir)" || $(MKDIR_P) "$(DESTDIR)$(sysconfdir)" @list='$(dist_sysconf_DATA)'; for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ f=$(am__strip_dir) \ echo " $(dist_sysconfDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(sysconfdir)/$$f'"; \ $(dist_sysconfDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(sysconfdir)/$$f"; \ done uninstall-dist_sysconfDATA: @$(NORMAL_UNINSTALL) @list='$(dist_sysconf_DATA)'; for p in $$list; do \ f=$(am__strip_dir) \ echo " rm -f '$(DESTDIR)$(sysconfdir)/$$f'"; \ rm -f "$(DESTDIR)$(sysconfdir)/$$f"; \ done ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) tags=; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$tags $$unique; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) tags=; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$tags$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$tags $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && cd $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) $$here distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ fi; \ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ else \ test -f $(distdir)/$$file \ || cp -p $$d/$$file $(distdir)/$$file \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(PROGRAMS) $(MANS) $(DATA) installdirs: for dir in "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(man5dir)" "$(DESTDIR)$(man8dir)" "$(DESTDIR)$(sysconfdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-sbinPROGRAMS mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am info: info-am info-am: install-data-am: install-man install-dvi: install-dvi-am install-exec-am: install-dist_sysconfDATA install-sbinPROGRAMS install-html: install-html-am install-info: install-info-am install-man: install-man5 install-man8 install-pdf: install-pdf-am install-ps: install-ps-am installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-dist_sysconfDATA uninstall-man \ uninstall-sbinPROGRAMS uninstall-man: uninstall-man5 uninstall-man8 .MAKE: install-am install-strip .PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ clean-sbinPROGRAMS ctags distclean distclean-compile \ distclean-generic distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dist_sysconfDATA install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-man5 install-man8 install-pdf install-pdf-am \ install-ps install-ps-am install-sbinPROGRAMS install-strip \ installcheck installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ uninstall-am uninstall-dist_sysconfDATA uninstall-man \ uninstall-man5 uninstall-man8 uninstall-sbinPROGRAMS # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: dhcp-4.2.4/server/mdb.c000644 000765 000024 00000254213 11731731535 014620 0ustar00sarstaff000000 000000 /* mdb.c Server-specific in-memory database support. */ /* * Copyright (c) 2004-2012 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1996-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ * * This software has been written for Internet Systems Consortium * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. * To learn more about Internet Systems Consortium, see * ``https://www.isc.org/''. To learn more about Vixie Enterprises, * see ``http://www.vix.com''. To learn more about Nominum, Inc., see * ``http://www.nominum.com''. */ #include "dhcpd.h" #include "omapip/hash.h" struct subnet *subnets; struct shared_network *shared_networks; host_hash_t *host_hw_addr_hash; host_hash_t *host_uid_hash; host_hash_t *host_name_hash; lease_id_hash_t *lease_uid_hash; lease_ip_hash_t *lease_ip_addr_hash; lease_id_hash_t *lease_hw_addr_hash; /* * We allow users to specify any option as a host identifier. * * Any host is uniquely identified by the combination of * option type & option data. * * We expect people will only use a few types of options as host * identifier. Because of this, we store a list with an entry for * each option type. Each of these has a hash table, which contains * hash of the option data. */ typedef struct host_id_info { struct option *option; host_hash_t *values_hash; struct host_id_info *next; } host_id_info_t; static host_id_info_t *host_id_info = NULL; int numclasseswritten; omapi_object_type_t *dhcp_type_host; isc_result_t enter_class(cd, dynamicp, commit) struct class *cd; int dynamicp; int commit; { if (!collections -> classes) { /* A subclass with no parent is invalid. */ if (cd->name == NULL) return DHCP_R_INVALIDARG; class_reference (&collections -> classes, cd, MDL); } else if (cd->name != NULL) { /* regular class */ struct class *c = 0; if (find_class(&c, cd->name, MDL) != ISC_R_NOTFOUND) { class_dereference(&c, MDL); return ISC_R_EXISTS; } /* Find the tail. */ for (c = collections -> classes; c -> nic; c = c -> nic) /* nothing */ ; class_reference (&c -> nic, cd, MDL); } if (dynamicp && commit) { const char *name = cd->name; if (name == NULL) { name = cd->superclass->name; } write_named_billing_class ((const unsigned char *)name, 0, cd); if (!commit_leases ()) return ISC_R_IOERROR; } return ISC_R_SUCCESS; } /* Variable to check if we're starting the server. The server will init as * starting - but just to be safe start out as false to avoid triggering new * special-case code * XXX: There is actually a server_startup state...which is never entered... */ #define SS_NOSYNC 1 #define SS_QFOLLOW 2 static int server_starting = 0; static int find_uid_statement (struct executable_statement *esp, void *vp, int condp) { struct executable_statement **evp = vp; if (esp -> op == supersede_option_statement && esp -> data.option && (esp -> data.option -> option -> universe == &dhcp_universe) && (esp -> data.option -> option -> code == DHO_DHCP_CLIENT_IDENTIFIER)) { if (condp) { log_error ("dhcp client identifier may not be %s", "specified conditionally."); } else if (!(*evp)) { executable_statement_reference (evp, esp, MDL); return 1; } else { log_error ("only one dhcp client identifier may be %s", "specified"); } } return 0; } static host_id_info_t * find_host_id_info(unsigned int option_code) { host_id_info_t *p; for (p=host_id_info; p != NULL; p = p->next) { if (p->option->code == option_code) { break; } } return p; } /* Debugging code */ #if 0 isc_result_t print_host(const void *name, unsigned len, void *value) { struct host_decl *h; printf("--------------\n"); printf("name:'%s'\n", print_hex_1(len, name, 60)); printf("len:%d\n", len); h = (struct host_decl *)value; printf("host @%p is '%s'\n", h, h->name); return ISC_R_SUCCESS; } void hash_print_hosts(struct hash_table *h) { hash_foreach(h, print_host); printf("--------------\n"); } #endif /* 0 */ void change_host_uid(struct host_decl *host, const char *uid, int len) { /* XXX: should consolidate this type of code throughout */ if (host_uid_hash == NULL) { if (!host_new_hash(&host_uid_hash, HOST_HASH_SIZE, MDL)) { log_fatal("Can't allocate host/uid hash"); } } /* * Remove the old entry, if one exists. */ if (host->client_identifier.data != NULL) { host_hash_delete(host_uid_hash, host->client_identifier.data, host->client_identifier.len, MDL); data_string_forget(&host->client_identifier, MDL); } /* * Set our new value. */ memset(&host->client_identifier, 0, sizeof(host->client_identifier)); host->client_identifier.len = len; if (!buffer_allocate(&host->client_identifier.buffer, len, MDL)) { log_fatal("Can't allocate uid buffer"); } host->client_identifier.data = host->client_identifier.buffer->data; memcpy((char *)host->client_identifier.data, uid, len); /* * And add to hash. */ host_hash_add(host_uid_hash, host->client_identifier.data, host->client_identifier.len, host, MDL); } isc_result_t enter_host (hd, dynamicp, commit) struct host_decl *hd; int dynamicp; int commit; { struct host_decl *hp = (struct host_decl *)0; struct host_decl *np = (struct host_decl *)0; struct executable_statement *esp; host_id_info_t *h_id_info; if (!host_name_hash) { if (!host_new_hash(&host_name_hash, HOST_HASH_SIZE, MDL)) log_fatal ("Can't allocate host name hash"); host_hash_add (host_name_hash, (unsigned char *)hd -> name, strlen (hd -> name), hd, MDL); } else { host_hash_lookup (&hp, host_name_hash, (unsigned char *)hd -> name, strlen (hd -> name), MDL); /* If it's deleted, we can supersede it. */ if (hp && (hp -> flags & HOST_DECL_DELETED)) { host_hash_delete (host_name_hash, (unsigned char *)hd -> name, strlen (hd -> name), MDL); /* If the old entry wasn't dynamic, then we always have to keep the deletion. */ if (hp -> flags & HOST_DECL_STATIC) { hd -> flags |= HOST_DECL_STATIC; } host_dereference (&hp, MDL); } /* If we are updating an existing host declaration, we can just delete it and add it again. */ if (hp && hp == hd) { host_dereference (&hp, MDL); delete_host (hd, 0); if (!write_host (hd)) return ISC_R_IOERROR; hd -> flags &= ~HOST_DECL_DELETED; } /* If there isn't already a host decl matching this address, add it to the hash table. */ if (!hp) { host_hash_add (host_name_hash, (unsigned char *)hd -> name, strlen (hd -> name), hd, MDL); } else { /* XXX actually, we have to delete the old one XXX carefully and replace it. Not done yet. */ host_dereference (&hp, MDL); return ISC_R_EXISTS; } } if (hd -> n_ipaddr) host_dereference (&hd -> n_ipaddr, MDL); if (!hd -> type) hd -> type = dhcp_type_host; if (hd -> interface.hlen) { if (!host_hw_addr_hash) { if (!host_new_hash(&host_hw_addr_hash, HOST_HASH_SIZE, MDL)) log_fatal ("Can't allocate host/hw hash"); } else { /* If there isn't already a host decl matching this address, add it to the hash table. */ host_hash_lookup (&hp, host_hw_addr_hash, hd -> interface.hbuf, hd -> interface.hlen, MDL); } if (!hp) host_hash_add (host_hw_addr_hash, hd -> interface.hbuf, hd -> interface.hlen, hd, MDL); else { /* If there was already a host declaration for this hardware address, add this one to the end of the list. */ for (np = hp; np -> n_ipaddr; np = np -> n_ipaddr) ; host_reference (&np -> n_ipaddr, hd, MDL); host_dereference (&hp, MDL); } } /* See if there's a statement that sets the client identifier. This is a kludge - the client identifier really shouldn't be set with an executable statement. */ esp = (struct executable_statement *)0; if (executable_statement_foreach (hd -> group -> statements, find_uid_statement, &esp, 0)) { evaluate_option_cache (&hd -> client_identifier, (struct packet *)0, (struct lease *)0, (struct client_state *)0, (struct option_state *)0, (struct option_state *)0, &global_scope, esp -> data.option, MDL); } /* If we got a client identifier, hash this entry by client identifier. */ if (hd -> client_identifier.len) { /* If there's no uid hash, make one; otherwise, see if there's already an entry in the hash for this host. */ if (!host_uid_hash) { if (!host_new_hash(&host_uid_hash, HOST_HASH_SIZE, MDL)) log_fatal ("Can't allocate host/uid hash"); host_hash_add (host_uid_hash, hd -> client_identifier.data, hd -> client_identifier.len, hd, MDL); } else { /* If there's already a host declaration for this client identifier, add this one to the end of the list. Otherwise, add it to the hash table. */ if (host_hash_lookup (&hp, host_uid_hash, hd -> client_identifier.data, hd -> client_identifier.len, MDL)) { /* Don't link it in twice... */ if (!np) { for (np = hp; np -> n_ipaddr; np = np -> n_ipaddr) { if (hd == np) break; } if (hd != np) host_reference (&np -> n_ipaddr, hd, MDL); } host_dereference (&hp, MDL); } else { host_hash_add (host_uid_hash, hd -> client_identifier.data, hd -> client_identifier.len, hd, MDL); } } } /* * If we use an option as our host identifier, record it here. */ if (hd->host_id_option != NULL) { /* * Look for the host identifier information for this option, * and create a new entry if there is none. */ h_id_info = find_host_id_info(hd->host_id_option->code); if (h_id_info == NULL) { h_id_info = dmalloc(sizeof(*h_id_info), MDL); if (h_id_info == NULL) { log_fatal("No memory for host-identifier " "option information."); } option_reference(&h_id_info->option, hd->host_id_option, MDL); if (!host_new_hash(&h_id_info->values_hash, HOST_HASH_SIZE, MDL)) { log_fatal("No memory for host-identifier " "option hash."); } h_id_info->next = host_id_info; host_id_info = h_id_info; } if (host_hash_lookup(&hp, h_id_info->values_hash, hd->host_id.data, hd->host_id.len, MDL)) { /* * If this option is already present, then add * this host to the list in n_ipaddr, unless * we have already done so previously. * * XXXSK: This seems scary to me, but I don't * fully understand how these are used. * Shouldn't there be multiple lists, or * maybe we should just forbid duplicates? */ if (np == NULL) { np = hp; while (np->n_ipaddr != NULL) { np = np->n_ipaddr; } if (hd != np) { host_reference(&np->n_ipaddr, hd, MDL); } } host_dereference(&hp, MDL); } else { host_hash_add(h_id_info->values_hash, hd->host_id.data, hd->host_id.len, hd, MDL); } } if (dynamicp && commit) { if (!write_host (hd)) return ISC_R_IOERROR; if (!commit_leases ()) return ISC_R_IOERROR; } return ISC_R_SUCCESS; } isc_result_t delete_class (cp, commit) struct class *cp; int commit; { cp->flags |= CLASS_DECL_DELETED; /* do the write first as we won't be leaving it in any data structures, unlike the host objects */ if (commit) { write_named_billing_class ((unsigned char *)cp->name, 0, cp); if (!commit_leases ()) return ISC_R_IOERROR; } unlink_class(&cp); /* remove from collections */ class_dereference(&cp, MDL); return ISC_R_SUCCESS; } isc_result_t delete_host (hd, commit) struct host_decl *hd; int commit; { struct host_decl *hp = (struct host_decl *)0; struct host_decl *np = (struct host_decl *)0; struct host_decl *foo; int hw_head = 0, uid_head = 1; /* Don't need to do it twice. */ if (hd -> flags & HOST_DECL_DELETED) return ISC_R_SUCCESS; /* But we do need to do it once! :') */ hd -> flags |= HOST_DECL_DELETED; if (hd -> interface.hlen) { if (host_hw_addr_hash) { if (host_hash_lookup (&hp, host_hw_addr_hash, hd -> interface.hbuf, hd -> interface.hlen, MDL)) { if (hp == hd) { host_hash_delete (host_hw_addr_hash, hd -> interface.hbuf, hd -> interface.hlen, MDL); hw_head = 1; } else { np = (struct host_decl *)0; foo = (struct host_decl *)0; host_reference (&foo, hp, MDL); while (foo) { if (foo == hd) break; if (np) host_dereference (&np, MDL); host_reference (&np, foo, MDL); host_dereference (&foo, MDL); if (np -> n_ipaddr) host_reference (&foo, np -> n_ipaddr, MDL); } if (foo) { host_dereference (&np -> n_ipaddr, MDL); if (hd -> n_ipaddr) host_reference (&np -> n_ipaddr, hd -> n_ipaddr, MDL); host_dereference (&foo, MDL); } if (np) host_dereference (&np, MDL); } host_dereference (&hp, MDL); } } } /* If we got a client identifier, hash this entry by client identifier. */ if (hd -> client_identifier.len) { if (host_uid_hash) { if (host_hash_lookup (&hp, host_uid_hash, hd -> client_identifier.data, hd -> client_identifier.len, MDL)) { if (hp == hd) { host_hash_delete (host_uid_hash, hd -> client_identifier.data, hd -> client_identifier.len, MDL); uid_head = 1; } else { np = (struct host_decl *)0; foo = (struct host_decl *)0; host_reference (&foo, hp, MDL); while (foo) { if (foo == hd) break; if (np) host_dereference (&np, MDL); host_reference (&np, foo, MDL); host_dereference (&foo, MDL); if (np -> n_ipaddr) host_reference (&foo, np -> n_ipaddr, MDL); } if (foo) { host_dereference (&np -> n_ipaddr, MDL); if (hd -> n_ipaddr) host_reference (&np -> n_ipaddr, hd -> n_ipaddr, MDL); host_dereference (&foo, MDL); } if (np) host_dereference (&np, MDL); } host_dereference (&hp, MDL); } } } if (hd->host_id_option != NULL) { option_dereference(&hd->host_id_option, MDL); data_string_forget(&hd->host_id, MDL); } if (hd -> n_ipaddr) { if (uid_head && hd -> n_ipaddr -> client_identifier.len) { host_hash_add (host_uid_hash, hd -> n_ipaddr -> client_identifier.data, hd -> n_ipaddr -> client_identifier.len, hd -> n_ipaddr, MDL); } if (hw_head && hd -> n_ipaddr -> interface.hlen) { host_hash_add (host_hw_addr_hash, hd -> n_ipaddr -> interface.hbuf, hd -> n_ipaddr -> interface.hlen, hd -> n_ipaddr, MDL); } host_dereference (&hd -> n_ipaddr, MDL); } if (host_name_hash) { if (host_hash_lookup (&hp, host_name_hash, (unsigned char *)hd -> name, strlen (hd -> name), MDL)) { if (hp == hd && !(hp -> flags & HOST_DECL_STATIC)) { host_hash_delete (host_name_hash, (unsigned char *)hd -> name, strlen (hd -> name), MDL); } host_dereference (&hp, MDL); } } if (commit) { if (!write_host (hd)) return ISC_R_IOERROR; if (!commit_leases ()) return ISC_R_IOERROR; } return ISC_R_SUCCESS; } int find_hosts_by_haddr (struct host_decl **hp, int htype, const unsigned char *haddr, unsigned hlen, const char *file, int line) { struct hardware h; #if defined(LDAP_CONFIGURATION) int ret; if ((ret = find_haddr_in_ldap (hp, htype, hlen, haddr, file, line))) return ret; #endif h.hlen = hlen + 1; h.hbuf [0] = htype; memcpy (&h.hbuf [1], haddr, hlen); return host_hash_lookup (hp, host_hw_addr_hash, h.hbuf, h.hlen, file, line); } int find_hosts_by_uid (struct host_decl **hp, const unsigned char *data, unsigned len, const char *file, int line) { return host_hash_lookup (hp, host_uid_hash, data, len, file, line); } int find_hosts_by_option(struct host_decl **hp, struct packet *packet, struct option_state *opt_state, const char *file, int line) { host_id_info_t *p; struct option_cache *oc; struct data_string data; int found; for (p = host_id_info; p != NULL; p = p->next) { oc = lookup_option(p->option->universe, opt_state, p->option->code); if (oc != NULL) { memset(&data, 0, sizeof(data)); if (!evaluate_option_cache(&data, packet, NULL, NULL, opt_state, NULL, &global_scope, oc, MDL)) { log_error("Error evaluating option cache"); return 0; } found = host_hash_lookup(hp, p->values_hash, data.data, data.len, file, line); data_string_forget(&data, MDL); if (found) { return 1; } } } return 0; } /* More than one host_decl can be returned by find_hosts_by_haddr or find_hosts_by_uid, and each host_decl can have multiple addresses. Loop through the list of hosts, and then for each host, through the list of addresses, looking for an address that's in the same shared network as the one specified. Store the matching address through the addr pointer, update the host pointer to point at the host_decl that matched, and return the subnet that matched. */ int find_host_for_network (struct subnet **sp, struct host_decl **host, struct iaddr *addr, struct shared_network *share) { int i; struct iaddr ip_address; struct host_decl *hp; struct data_string fixed_addr; memset (&fixed_addr, 0, sizeof fixed_addr); for (hp = *host; hp; hp = hp -> n_ipaddr) { if (!hp -> fixed_addr) continue; if (!evaluate_option_cache (&fixed_addr, (struct packet *)0, (struct lease *)0, (struct client_state *)0, (struct option_state *)0, (struct option_state *)0, &global_scope, hp -> fixed_addr, MDL)) continue; for (i = 0; i < fixed_addr.len; i += 4) { ip_address.len = 4; memcpy (ip_address.iabuf, fixed_addr.data + i, 4); if (find_grouped_subnet (sp, share, ip_address, MDL)) { struct host_decl *tmp = (struct host_decl *)0; *addr = ip_address; /* This is probably not necessary, but just in case *host is the only reference to that host declaration, make a temporary reference so that dereferencing it doesn't dereference hp out from under us. */ host_reference (&tmp, *host, MDL); host_dereference (host, MDL); host_reference (host, hp, MDL); host_dereference (&tmp, MDL); data_string_forget (&fixed_addr, MDL); return 1; } } data_string_forget (&fixed_addr, MDL); } return 0; } void new_address_range (cfile, low, high, subnet, pool, lpchain) struct parse *cfile; struct iaddr low, high; struct subnet *subnet; struct pool *pool; struct lease **lpchain; { #if defined(COMPACT_LEASES) struct lease *address_range; #endif unsigned min, max, i; char lowbuf [16], highbuf [16], netbuf [16]; struct shared_network *share = subnet -> shared_network; struct lease *lt = (struct lease *)0; #if !defined(COMPACT_LEASES) isc_result_t status; #endif /* All subnets should have attached shared network structures. */ if (!share) { strcpy (netbuf, piaddr (subnet -> net)); log_fatal ("No shared network for network %s (%s)", netbuf, piaddr (subnet -> netmask)); } /* Initialize the hash table if it hasn't been done yet. */ if (!lease_uid_hash) { if (!lease_id_new_hash(&lease_uid_hash, LEASE_HASH_SIZE, MDL)) log_fatal ("Can't allocate lease/uid hash"); } if (!lease_ip_addr_hash) { if (!lease_ip_new_hash(&lease_ip_addr_hash, LEASE_HASH_SIZE, MDL)) log_fatal ("Can't allocate lease/ip hash"); } if (!lease_hw_addr_hash) { if (!lease_id_new_hash(&lease_hw_addr_hash, LEASE_HASH_SIZE, MDL)) log_fatal ("Can't allocate lease/hw hash"); } /* Make sure that high and low addresses are in this subnet. */ if (!addr_eq(subnet->net, subnet_number(low, subnet->netmask))) { strcpy(lowbuf, piaddr(low)); strcpy(netbuf, piaddr(subnet->net)); log_fatal("bad range, address %s not in subnet %s netmask %s", lowbuf, netbuf, piaddr(subnet->netmask)); } if (!addr_eq(subnet->net, subnet_number(high, subnet->netmask))) { strcpy(highbuf, piaddr(high)); strcpy(netbuf, piaddr(subnet->net)); log_fatal("bad range, address %s not in subnet %s netmask %s", highbuf, netbuf, piaddr(subnet->netmask)); } /* Get the high and low host addresses... */ max = host_addr (high, subnet -> netmask); min = host_addr (low, subnet -> netmask); /* Allow range to be specified high-to-low as well as low-to-high. */ if (min > max) { max = min; min = host_addr (high, subnet -> netmask); } /* Get a lease structure for each address in the range. */ #if defined (COMPACT_LEASES) address_range = new_leases (max - min + 1, MDL); if (!address_range) { strcpy (lowbuf, piaddr (low)); strcpy (highbuf, piaddr (high)); log_fatal ("No memory for address range %s-%s.", lowbuf, highbuf); } #endif /* Fill out the lease structures with some minimal information. */ for (i = 0; i < max - min + 1; i++) { struct lease *lp = (struct lease *)0; #if defined (COMPACT_LEASES) omapi_object_initialize ((omapi_object_t *)&address_range [i], dhcp_type_lease, 0, sizeof (struct lease), MDL); lease_reference (&lp, &address_range [i], MDL); #else status = lease_allocate (&lp, MDL); if (status != ISC_R_SUCCESS) log_fatal ("No memory for lease %s: %s", piaddr (ip_addr (subnet -> net, subnet -> netmask, i + min)), isc_result_totext (status)); #endif lp->ip_addr = ip_addr(subnet->net, subnet->netmask, i + min); lp->starts = MIN_TIME; lp->ends = MIN_TIME; subnet_reference(&lp->subnet, subnet, MDL); pool_reference(&lp->pool, pool, MDL); lp->binding_state = FTS_FREE; lp->next_binding_state = FTS_FREE; lp->rewind_binding_state = FTS_FREE; lp->flags = 0; /* Remember the lease in the IP address hash. */ if (find_lease_by_ip_addr (<, lp -> ip_addr, MDL)) { if (lt -> pool) { parse_warn (cfile, "lease %s is declared twice!", piaddr (lp -> ip_addr)); } else pool_reference (< -> pool, pool, MDL); lease_dereference (<, MDL); } else lease_ip_hash_add(lease_ip_addr_hash, lp->ip_addr.iabuf, lp->ip_addr.len, lp, MDL); /* Put the lease on the chain for the caller. */ if (lpchain) { if (*lpchain) { lease_reference (&lp -> next, *lpchain, MDL); lease_dereference (lpchain, MDL); } lease_reference (lpchain, lp, MDL); } lease_dereference (&lp, MDL); } } int find_subnet (struct subnet **sp, struct iaddr addr, const char *file, int line) { struct subnet *rv; for (rv = subnets; rv; rv = rv -> next_subnet) { if (addr_eq (subnet_number (addr, rv -> netmask), rv -> net)) { if (subnet_reference (sp, rv, file, line) != ISC_R_SUCCESS) return 0; return 1; } } return 0; } int find_grouped_subnet (struct subnet **sp, struct shared_network *share, struct iaddr addr, const char *file, int line) { struct subnet *rv; for (rv = share -> subnets; rv; rv = rv -> next_sibling) { if (addr_eq (subnet_number (addr, rv -> netmask), rv -> net)) { if (subnet_reference (sp, rv, file, line) != ISC_R_SUCCESS) return 0; return 1; } } return 0; } /* XXX: could speed up if everyone had a prefix length */ int subnet_inner_than(const struct subnet *subnet, const struct subnet *scan, int warnp) { if (addr_eq(subnet_number(subnet->net, scan->netmask), scan->net) || addr_eq(subnet_number(scan->net, subnet->netmask), subnet->net)) { char n1buf[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255")]; int i, j; for (i = 0; i < 128; i++) if (subnet->netmask.iabuf[3 - (i >> 3)] & (1 << (i & 7))) break; for (j = 0; j < 128; j++) if (scan->netmask.iabuf[3 - (j >> 3)] & (1 << (j & 7))) break; if (warnp) { strcpy(n1buf, piaddr(subnet->net)); log_error("Warning: subnet %s/%d overlaps subnet %s/%d", n1buf, 32 - i, piaddr(scan->net), 32 - j); } if (i < j) return 1; } return 0; } /* Enter a new subnet into the subnet list. */ void enter_subnet (subnet) struct subnet *subnet; { struct subnet *scan = (struct subnet *)0; struct subnet *next = (struct subnet *)0; struct subnet *prev = (struct subnet *)0; /* Check for duplicates... */ if (subnets) subnet_reference (&next, subnets, MDL); while (next) { subnet_reference (&scan, next, MDL); subnet_dereference (&next, MDL); /* When we find a conflict, make sure that the subnet with the narrowest subnet mask comes first. */ if (subnet_inner_than (subnet, scan, 1)) { if (prev) { if (prev -> next_subnet) subnet_dereference (&prev -> next_subnet, MDL); subnet_reference (&prev -> next_subnet, subnet, MDL); subnet_dereference (&prev, MDL); } else { subnet_dereference (&subnets, MDL); subnet_reference (&subnets, subnet, MDL); } subnet_reference (&subnet -> next_subnet, scan, MDL); subnet_dereference (&scan, MDL); return; } subnet_reference (&prev, scan, MDL); subnet_dereference (&scan, MDL); } if (prev) subnet_dereference (&prev, MDL); /* XXX use the BSD radix tree code instead of a linked list. */ if (subnets) { subnet_reference (&subnet -> next_subnet, subnets, MDL); subnet_dereference (&subnets, MDL); } subnet_reference (&subnets, subnet, MDL); } /* Enter a new shared network into the shared network list. */ void enter_shared_network (share) struct shared_network *share; { if (shared_networks) { shared_network_reference (&share -> next, shared_networks, MDL); shared_network_dereference (&shared_networks, MDL); } shared_network_reference (&shared_networks, share, MDL); } void new_shared_network_interface (cfile, share, name) struct parse *cfile; struct shared_network *share; const char *name; { struct interface_info *ip; isc_result_t status; if (share -> interface) { parse_warn (cfile, "A subnet or shared network can't be connected %s", "to two interfaces."); return; } for (ip = interfaces; ip; ip = ip -> next) if (!strcmp (ip -> name, name)) break; if (!ip) { status = interface_allocate (&ip, MDL); if (status != ISC_R_SUCCESS) log_fatal ("new_shared_network_interface %s: %s", name, isc_result_totext (status)); if (strlen (name) > sizeof ip -> name) { memcpy (ip -> name, name, (sizeof ip -> name) - 1); ip -> name [(sizeof ip -> name) - 1] = 0; } else strcpy (ip -> name, name); if (interfaces) { interface_reference (&ip -> next, interfaces, MDL); interface_dereference (&interfaces, MDL); } interface_reference (&interfaces, ip, MDL); ip -> flags = INTERFACE_REQUESTED; /* XXX this is a reference loop. */ shared_network_reference (&ip -> shared_network, share, MDL); interface_reference (&share -> interface, ip, MDL); } } /* Enter a lease into the system. This is called by the parser each time it reads in a new lease. If the subnet for that lease has already been read in (usually the case), just update that lease; otherwise, allocate temporary storage for the lease and keep it around until we're done reading in the config file. */ void enter_lease (lease) struct lease *lease; { struct lease *comp = (struct lease *)0; if (find_lease_by_ip_addr (&comp, lease -> ip_addr, MDL)) { if (!comp -> pool) { log_error ("undeclared lease found in database: %s", piaddr (lease -> ip_addr)); } else pool_reference (&lease -> pool, comp -> pool, MDL); if (comp -> subnet) subnet_reference (&lease -> subnet, comp -> subnet, MDL); lease_ip_hash_delete(lease_ip_addr_hash, lease->ip_addr.iabuf, lease->ip_addr.len, MDL); lease_dereference (&comp, MDL); } /* The only way a lease can get here without a subnet is if it's in the lease file, but not in the dhcpd.conf file. In this case, we *should* keep it around until it's expired, but never reallocate it or renew it. Currently, to maintain consistency, we are not doing this. XXX fix this so that the lease is kept around until it expires. XXX this will be important in IPv6 with addresses that become XXX non-renewable as a result of a renumbering event. */ if (!lease -> subnet) { log_error ("lease %s: no subnet.", piaddr (lease -> ip_addr)); return; } lease_ip_hash_add(lease_ip_addr_hash, lease->ip_addr.iabuf, lease->ip_addr.len, lease, MDL); } /* Replace the data in an existing lease with the data in a new lease; adjust hash tables to suit, and insertion sort the lease into the list of leases by expiry time so that we can always find the oldest lease. */ int supersede_lease (comp, lease, commit, propogate, pimmediate) struct lease *comp, *lease; int commit; int propogate; int pimmediate; { struct lease *lp, **lq, *prev; struct timeval tv; #if defined (FAILOVER_PROTOCOL) int do_pool_check = 0; /* We must commit leases before sending updates regarding them to failover peers. It is, therefore, an error to set pimmediate and not commit. */ if (pimmediate && !commit) return 0; #endif /* If there is no sample lease, just do the move. */ if (!lease) goto just_move_it; /* Static leases are not currently kept in the database... */ if (lease -> flags & STATIC_LEASE) return 1; /* If the existing lease hasn't expired and has a different unique identifier or, if it doesn't have a unique identifier, a different hardware address, then the two leases are in conflict. If the existing lease has a uid and the new one doesn't, but they both have the same hardware address, and dynamic bootp is allowed on this lease, then we allow that, in case a dynamic BOOTP lease is requested *after* a DHCP lease has been assigned. */ if (lease -> binding_state != FTS_ABANDONED && lease -> next_binding_state != FTS_ABANDONED && comp -> binding_state == FTS_ACTIVE && (((comp -> uid && lease -> uid) && (comp -> uid_len != lease -> uid_len || memcmp (comp -> uid, lease -> uid, comp -> uid_len))) || (!comp -> uid && ((comp -> hardware_addr.hlen != lease -> hardware_addr.hlen) || memcmp (comp -> hardware_addr.hbuf, lease -> hardware_addr.hbuf, comp -> hardware_addr.hlen))))) { log_error ("Lease conflict at %s", piaddr (comp -> ip_addr)); } /* If there's a Unique ID, dissociate it from the hash table and free it if necessary. */ if (comp->uid) { uid_hash_delete(comp); if (comp->uid != comp->uid_buf) { dfree(comp->uid, MDL); comp->uid_max = 0; comp->uid_len = 0; } comp -> uid = (unsigned char *)0; } /* If there's a hardware address, remove the lease from its * old position in the hash bucket's ordered list. */ if (comp->hardware_addr.hlen) hw_hash_delete(comp); /* If the lease has been billed to a class, remove the billing. */ if (comp -> billing_class != lease -> billing_class) { if (comp -> billing_class) unbill_class (comp, comp -> billing_class); if (lease -> billing_class) bill_class (comp, lease -> billing_class); } /* Copy the data files, but not the linkages. */ comp -> starts = lease -> starts; if (lease -> uid) { if (lease -> uid_len <= sizeof (lease -> uid_buf)) { memcpy (comp -> uid_buf, lease -> uid, lease -> uid_len); comp -> uid = &comp -> uid_buf [0]; comp -> uid_max = sizeof comp -> uid_buf; comp -> uid_len = lease -> uid_len; } else if (lease -> uid != &lease -> uid_buf [0]) { comp -> uid = lease -> uid; comp -> uid_max = lease -> uid_max; lease -> uid = (unsigned char *)0; lease -> uid_max = 0; comp -> uid_len = lease -> uid_len; lease -> uid_len = 0; } else { log_fatal ("corrupt lease uid."); /* XXX */ } } else { comp -> uid = (unsigned char *)0; comp -> uid_len = comp -> uid_max = 0; } if (comp -> host) host_dereference (&comp -> host, MDL); host_reference (&comp -> host, lease -> host, MDL); comp -> hardware_addr = lease -> hardware_addr; comp -> flags = ((lease -> flags & ~PERSISTENT_FLAGS) | (comp -> flags & ~EPHEMERAL_FLAGS)); if (comp -> scope) binding_scope_dereference (&comp -> scope, MDL); if (lease -> scope) { binding_scope_reference (&comp -> scope, lease -> scope, MDL); binding_scope_dereference (&lease -> scope, MDL); } if (comp -> agent_options) option_chain_head_dereference (&comp -> agent_options, MDL); if (lease -> agent_options) { /* Only retain the agent options if the lease is still affirmatively associated with a client. */ if (lease -> next_binding_state == FTS_ACTIVE || lease -> next_binding_state == FTS_EXPIRED) option_chain_head_reference (&comp -> agent_options, lease -> agent_options, MDL); option_chain_head_dereference (&lease -> agent_options, MDL); } /* Record the hostname information in the lease. */ if (comp -> client_hostname) dfree (comp -> client_hostname, MDL); comp -> client_hostname = lease -> client_hostname; lease -> client_hostname = (char *)0; if (lease -> on_expiry) { if (comp -> on_expiry) executable_statement_dereference (&comp -> on_expiry, MDL); executable_statement_reference (&comp -> on_expiry, lease -> on_expiry, MDL); } if (lease -> on_commit) { if (comp -> on_commit) executable_statement_dereference (&comp -> on_commit, MDL); executable_statement_reference (&comp -> on_commit, lease -> on_commit, MDL); } if (lease -> on_release) { if (comp -> on_release) executable_statement_dereference (&comp -> on_release, MDL); executable_statement_reference (&comp -> on_release, lease -> on_release, MDL); } /* Record the lease in the uid hash if necessary. */ if (comp->uid) uid_hash_add(comp); /* Record it in the hardware address hash if necessary. */ if (comp->hardware_addr.hlen) hw_hash_add(comp); comp->cltt = lease->cltt; #if defined (FAILOVER_PROTOCOL) comp->tstp = lease->tstp; comp->tsfp = lease->tsfp; comp->atsfp = lease->atsfp; #endif /* FAILOVER_PROTOCOL */ comp->ends = lease->ends; comp->next_binding_state = lease->next_binding_state; /* * If we have a control block pointer copy it in. * We don't zero out an older ponter as it is still * in use. We shouldn't need to overwrite an * old pointer with a new one as the old transaction * should have been cancelled before getting here. */ if (lease->ddns_cb != NULL) comp->ddns_cb = lease->ddns_cb; just_move_it: #if defined (FAILOVER_PROTOCOL) /* * Atsfp should be cleared upon any state change that implies * propagation whether supersede_lease was given a copy lease * structure or not (often from the pool_timer()). */ if (propogate) comp->atsfp = 0; #endif /* FAILOVER_PROTOCOL */ if (!comp -> pool) { log_error ("Supersede_lease: lease %s with no pool.", piaddr (comp -> ip_addr)); return 0; } /* Figure out which queue it's on. */ switch (comp -> binding_state) { case FTS_FREE: if (comp->flags & RESERVED_LEASE) lq = &comp->pool->reserved; else { lq = &comp->pool->free; comp->pool->free_leases--; } #if defined(FAILOVER_PROTOCOL) do_pool_check = 1; #endif break; case FTS_ACTIVE: lq = &comp -> pool -> active; break; case FTS_EXPIRED: case FTS_RELEASED: case FTS_RESET: lq = &comp -> pool -> expired; break; case FTS_ABANDONED: lq = &comp -> pool -> abandoned; break; case FTS_BACKUP: if (comp->flags & RESERVED_LEASE) lq = &comp->pool->reserved; else { lq = &comp->pool->backup; comp->pool->backup_leases--; } #if defined(FAILOVER_PROTOCOL) do_pool_check = 1; #endif break; default: log_error ("Lease with bogus binding state: %d", comp -> binding_state); #if defined (BINDING_STATE_DEBUG) abort (); #endif return 0; } /* Remove the lease from its current place in its current timer sequence. */ /* XXX this is horrid. */ prev = (struct lease *)0; for (lp = *lq; lp; lp = lp -> next) { if (lp == comp) break; prev = lp; } if (!lp) { log_fatal("Lease with binding state %s not on its queue.", (comp->binding_state < 1 || comp->binding_state > FTS_LAST) ? "unknown" : binding_state_names[comp->binding_state - 1]); } if (prev) { lease_dereference (&prev -> next, MDL); if (comp -> next) { lease_reference (&prev -> next, comp -> next, MDL); lease_dereference (&comp -> next, MDL); } } else { lease_dereference (lq, MDL); if (comp -> next) { lease_reference (lq, comp -> next, MDL); lease_dereference (&comp -> next, MDL); } } /* Make the state transition. */ if (commit || !pimmediate) make_binding_state_transition (comp); /* Put the lease back on the appropriate queue. If the lease is corrupt (as detected by lease_enqueue), don't go any farther. */ if (!lease_enqueue (comp)) return 0; /* If this is the next lease that will timeout on the pool, zap the old timeout and set the timeout on this pool to the time that the lease's next event will happen. We do not actually set the timeout unless commit is true - we don't want to thrash the timer queue when reading the lease database. Instead, the database code calls the expiry event on each pool after reading in the lease file, and the expiry code sets the timer if there's anything left to expire after it's run any outstanding expiry events on the pool. */ if ((commit || !pimmediate) && comp -> sort_time != MIN_TIME && comp -> sort_time > cur_time && (comp -> sort_time < comp -> pool -> next_event_time || comp -> pool -> next_event_time == MIN_TIME)) { comp -> pool -> next_event_time = comp -> sort_time; tv . tv_sec = comp -> pool -> next_event_time; tv . tv_usec = 0; add_timeout (&tv, pool_timer, comp -> pool, (tvref_t)pool_reference, (tvunref_t)pool_dereference); } if (commit) { #if defined(FAILOVER_PROTOCOL) /* * If commit and propogate are set, then we can save a * possible fsync later in BNDUPD socket transmission by * stepping the rewind state forward to the new state, in * case it has changed. This is only worth doing if the * failover connection is currently connected, as in this * case it is likely we will be transmitting to the peer very * shortly. */ if (propogate && (comp->pool->failover_peer != NULL) && ((comp->pool->failover_peer->service_state == cooperating) || (comp->pool->failover_peer->service_state == not_responding))) comp->rewind_binding_state = comp->binding_state; #endif if (!write_lease (comp)) return 0; if ((server_starting & SS_NOSYNC) == 0) { if (!commit_leases ()) return 0; } } #if defined (FAILOVER_PROTOCOL) if (propogate) { comp -> desired_binding_state = comp -> binding_state; if (!dhcp_failover_queue_update (comp, pimmediate)) return 0; } if (do_pool_check && comp->pool->failover_peer) dhcp_failover_pool_check(comp->pool); #endif /* If the current binding state has already expired, do an expiry event right now. */ /* XXX At some point we should optimize this so that we don't XXX write the lease twice, but this is a safe way to fix the XXX problem for 3.0 (I hope!). */ if ((commit || !pimmediate) && comp -> sort_time < cur_time && comp -> next_binding_state != comp -> binding_state) pool_timer (comp -> pool); return 1; } void make_binding_state_transition (struct lease *lease) { #if defined (FAILOVER_PROTOCOL) dhcp_failover_state_t *peer; if (lease && lease -> pool && lease -> pool -> failover_peer) peer = lease -> pool -> failover_peer; else peer = (dhcp_failover_state_t *)0; #endif /* If the lease was active and is now no longer active, but isn't released, then it just expired, so do the expiry event. */ if (lease -> next_binding_state != lease -> binding_state && (( #if defined (FAILOVER_PROTOCOL) peer && (lease->binding_state == FTS_EXPIRED || lease->binding_state == FTS_ACTIVE) && (lease->next_binding_state == FTS_FREE || lease->next_binding_state == FTS_BACKUP)) || (!peer && #endif lease -> binding_state == FTS_ACTIVE && lease -> next_binding_state != FTS_RELEASED))) { #if defined (NSUPDATE) (void) ddns_removals(lease, NULL, NULL, ISC_TRUE); #endif if (lease -> on_expiry) { execute_statements ((struct binding_value **)0, (struct packet *)0, lease, (struct client_state *)0, (struct option_state *)0, (struct option_state *)0, /* XXX */ &lease -> scope, lease -> on_expiry); if (lease -> on_expiry) executable_statement_dereference (&lease -> on_expiry, MDL); } /* No sense releasing a lease after it's expired. */ if (lease -> on_release) executable_statement_dereference (&lease -> on_release, MDL); /* Get rid of client-specific bindings that are only correct when the lease is active. */ if (lease -> billing_class) unbill_class (lease, lease -> billing_class); if (lease -> agent_options) option_chain_head_dereference (&lease -> agent_options, MDL); if (lease -> client_hostname) { dfree (lease -> client_hostname, MDL); lease -> client_hostname = (char *)0; } if (lease -> host) host_dereference (&lease -> host, MDL); /* Send the expiry time to the peer. */ lease -> tstp = lease -> ends; } /* If the lease was active and is now released, do the release event. */ if (lease -> next_binding_state != lease -> binding_state && (( #if defined (FAILOVER_PROTOCOL) peer && lease -> binding_state == FTS_RELEASED && (lease -> next_binding_state == FTS_FREE || lease -> next_binding_state == FTS_BACKUP)) || (!peer && #endif lease -> binding_state == FTS_ACTIVE && lease -> next_binding_state == FTS_RELEASED))) { #if defined (NSUPDATE) /* * Note: ddns_removals() is also iterated when the lease * enters state 'released' in 'release_lease()'. The below * is caught when a peer receives a BNDUPD from a failover * peer; it may not have received the client's release (it * may have been offline). * * We could remove the call from release_lease() because * it will also catch here on the originating server after the * peer acknowledges the state change. However, there could * be many hours inbetween, and in this case we /know/ the * client is no longer using the lease when we receive the * release message. This is not true of expiry, where the * peer may have extended the lease. */ (void) ddns_removals(lease, NULL, NULL, ISC_TRUE); #endif if (lease -> on_release) { execute_statements ((struct binding_value **)0, (struct packet *)0, lease, (struct client_state *)0, (struct option_state *)0, (struct option_state *)0, /* XXX */ &lease -> scope, lease -> on_release); executable_statement_dereference (&lease -> on_release, MDL); } /* A released lease can't expire. */ if (lease -> on_expiry) executable_statement_dereference (&lease -> on_expiry, MDL); /* Get rid of client-specific bindings that are only correct when the lease is active. */ if (lease -> billing_class) unbill_class (lease, lease -> billing_class); if (lease -> agent_options) option_chain_head_dereference (&lease -> agent_options, MDL); if (lease -> client_hostname) { dfree (lease -> client_hostname, MDL); lease -> client_hostname = (char *)0; } if (lease -> host) host_dereference (&lease -> host, MDL); /* Send the release time (should be == cur_time) to the peer. */ lease -> tstp = lease -> ends; } #if defined (DEBUG_LEASE_STATE_TRANSITIONS) log_debug ("lease %s moves from %s to %s", piaddr (lease -> ip_addr), binding_state_print (lease -> binding_state), binding_state_print (lease -> next_binding_state)); #endif lease -> binding_state = lease -> next_binding_state; switch (lease -> binding_state) { case FTS_ACTIVE: #if defined (FAILOVER_PROTOCOL) if (lease -> pool && lease -> pool -> failover_peer) lease -> next_binding_state = FTS_EXPIRED; else #endif lease -> next_binding_state = FTS_FREE; break; case FTS_EXPIRED: case FTS_RELEASED: case FTS_ABANDONED: case FTS_RESET: lease -> next_binding_state = FTS_FREE; #if defined(FAILOVER_PROTOCOL) /* If we are not in partner_down, leases don't go from EXPIRED to FREE on a timeout - only on an update. If we're in partner_down, they expire at mclt past the time we entered partner_down. */ if (lease -> pool -> failover_peer && lease -> pool -> failover_peer -> me.state == partner_down) lease -> tsfp = (lease -> pool -> failover_peer -> me.stos + lease -> pool -> failover_peer -> mclt); #endif /* FAILOVER_PROTOCOL */ break; case FTS_FREE: case FTS_BACKUP: lease -> next_binding_state = lease -> binding_state; break; } #if defined (DEBUG_LEASE_STATE_TRANSITIONS) log_debug ("lease %s: next binding state %s", piaddr (lease -> ip_addr), binding_state_print (lease -> next_binding_state)); #endif } /* Copy the contents of one lease into another, correctly maintaining reference counts. */ int lease_copy (struct lease **lp, struct lease *lease, const char *file, int line) { struct lease *lt = (struct lease *)0; isc_result_t status; status = lease_allocate (<, MDL); if (status != ISC_R_SUCCESS) return 0; lt -> ip_addr = lease -> ip_addr; lt -> starts = lease -> starts; lt -> ends = lease -> ends; lt -> uid_len = lease -> uid_len; lt -> uid_max = lease -> uid_max; if (lease -> uid == lease -> uid_buf) { lt -> uid = lt -> uid_buf; memcpy (lt -> uid_buf, lease -> uid_buf, sizeof lt -> uid_buf); } else if (!lease -> uid_max) { lt -> uid = (unsigned char *)0; } else { lt -> uid = dmalloc (lt -> uid_max, MDL); if (!lt -> uid) { lease_dereference (<, MDL); return 0; } memcpy (lt -> uid, lease -> uid, lease -> uid_max); } if (lease -> client_hostname) { lt -> client_hostname = dmalloc (strlen (lease -> client_hostname) + 1, MDL); if (!lt -> client_hostname) { lease_dereference (<, MDL); return 0; } strcpy (lt -> client_hostname, lease -> client_hostname); } if (lease -> scope) binding_scope_reference (< -> scope, lease -> scope, MDL); if (lease -> agent_options) option_chain_head_reference (< -> agent_options, lease -> agent_options, MDL); host_reference (< -> host, lease -> host, file, line); subnet_reference (< -> subnet, lease -> subnet, file, line); pool_reference (< -> pool, lease -> pool, file, line); class_reference (< -> billing_class, lease -> billing_class, file, line); lt -> hardware_addr = lease -> hardware_addr; if (lease -> on_expiry) executable_statement_reference (< -> on_expiry, lease -> on_expiry, file, line); if (lease -> on_commit) executable_statement_reference (< -> on_commit, lease -> on_commit, file, line); if (lease -> on_release) executable_statement_reference (< -> on_release, lease -> on_release, file, line); lt->flags = lease->flags; lt->tstp = lease->tstp; lt->tsfp = lease->tsfp; lt->atsfp = lease->atsfp; lt->cltt = lease -> cltt; lt->binding_state = lease->binding_state; lt->next_binding_state = lease->next_binding_state; lt->rewind_binding_state = lease->rewind_binding_state; status = lease_reference(lp, lt, file, line); lease_dereference(<, MDL); return status == ISC_R_SUCCESS; } /* Release the specified lease and re-hash it as appropriate. */ void release_lease (lease, packet) struct lease *lease; struct packet *packet; { /* If there are statements to execute when the lease is released, execute them. */ #if defined (NSUPDATE) (void) ddns_removals(lease, NULL, NULL, ISC_FALSE); #endif if (lease -> on_release) { execute_statements ((struct binding_value **)0, packet, lease, (struct client_state *)0, packet -> options, (struct option_state *)0, /* XXX */ &lease -> scope, lease -> on_release); if (lease -> on_release) executable_statement_dereference (&lease -> on_release, MDL); } /* We do either the on_release or the on_expiry events, but not both (it's possible that they could be the same, in any case). */ if (lease -> on_expiry) executable_statement_dereference (&lease -> on_expiry, MDL); if (lease -> binding_state != FTS_FREE && lease -> binding_state != FTS_BACKUP && lease -> binding_state != FTS_RELEASED && lease -> binding_state != FTS_EXPIRED && lease -> binding_state != FTS_RESET) { if (lease -> on_commit) executable_statement_dereference (&lease -> on_commit, MDL); /* Blow away any bindings. */ if (lease -> scope) binding_scope_dereference (&lease -> scope, MDL); /* Set sort times to the present. */ lease -> ends = cur_time; /* Lower layers of muckery set tstp to ->ends. But we send * protocol messages before this. So it is best to set * tstp now anyway. */ lease->tstp = cur_time; #if defined (FAILOVER_PROTOCOL) if (lease -> pool && lease -> pool -> failover_peer) { dhcp_failover_state_t *peer = NULL; if (lease->pool != NULL) peer = lease->pool->failover_peer; if ((peer->service_state == not_cooperating) && (((peer->i_am == primary) && (lease->rewind_binding_state == FTS_FREE)) || ((peer->i_am == secondary) && (lease->rewind_binding_state == FTS_BACKUP)))) { lease->next_binding_state = lease->rewind_binding_state; } else lease -> next_binding_state = FTS_RELEASED; } else { lease -> next_binding_state = FTS_FREE; } #else lease -> next_binding_state = FTS_FREE; #endif supersede_lease (lease, (struct lease *)0, 1, 1, 1); } } /* Abandon the specified lease (set its timeout to infinity and its particulars to zero, and re-hash it as appropriate. */ void abandon_lease (lease, message) struct lease *lease; const char *message; { struct lease *lt = (struct lease *)0; #if defined (NSUPDATE) (void) ddns_removals(lease, NULL, NULL, ISC_FALSE); #endif if (!lease_copy (<, lease, MDL)) return; if (lt->scope) binding_scope_dereference(<->scope, MDL); lt -> ends = cur_time; /* XXX */ lt -> next_binding_state = FTS_ABANDONED; log_error ("Abandoning IP address %s: %s", piaddr (lease -> ip_addr), message); lt -> hardware_addr.hlen = 0; if (lt -> uid && lt -> uid != lt -> uid_buf) dfree (lt -> uid, MDL); lt -> uid = (unsigned char *)0; lt -> uid_len = 0; lt -> uid_max = 0; supersede_lease (lease, lt, 1, 1, 1); lease_dereference (<, MDL); } #if 0 /* * This doesn't appear to be in use for anything anymore. * I'm ifdeffing it now and if there are no complaints in * the future it will be removed. * SAR */ /* Abandon the specified lease (set its timeout to infinity and its particulars to zero, and re-hash it as appropriate. */ void dissociate_lease (lease) struct lease *lease; { struct lease *lt = (struct lease *)0; #if defined (NSUPDATE) (void) ddns_removals(lease, NULL, NULL, ISC_FALSE); #endif if (!lease_copy (<, lease, MDL)) return; #if defined (FAILOVER_PROTOCOL) if (lease -> pool && lease -> pool -> failover_peer) { lt -> next_binding_state = FTS_RESET; } else { lt -> next_binding_state = FTS_FREE; } #else lt -> next_binding_state = FTS_FREE; #endif lt -> ends = cur_time; /* XXX */ lt -> hardware_addr.hlen = 0; if (lt -> uid && lt -> uid != lt -> uid_buf) dfree (lt -> uid, MDL); lt -> uid = (unsigned char *)0; lt -> uid_len = 0; lt -> uid_max = 0; supersede_lease (lease, lt, 1, 1, 1); lease_dereference (<, MDL); } #endif /* Timer called when a lease in a particular pool expires. */ void pool_timer (vpool) void *vpool; { struct pool *pool; struct lease *next = (struct lease *)0; struct lease *lease = (struct lease *)0; #define FREE_LEASES 0 #define ACTIVE_LEASES 1 #define EXPIRED_LEASES 2 #define ABANDONED_LEASES 3 #define BACKUP_LEASES 4 #define RESERVED_LEASES 5 struct lease **lptr[RESERVED_LEASES+1]; TIME next_expiry = MAX_TIME; int i; struct timeval tv; pool = (struct pool *)vpool; lptr [FREE_LEASES] = &pool -> free; lptr [ACTIVE_LEASES] = &pool -> active; lptr [EXPIRED_LEASES] = &pool -> expired; lptr [ABANDONED_LEASES] = &pool -> abandoned; lptr [BACKUP_LEASES] = &pool -> backup; lptr[RESERVED_LEASES] = &pool->reserved; for (i = FREE_LEASES; i <= RESERVED_LEASES; i++) { /* If there's nothing on the queue, skip it. */ if (!*(lptr [i])) continue; #if defined (FAILOVER_PROTOCOL) if (pool->failover_peer && pool->failover_peer->me.state != partner_down) { /* * Normally the secondary doesn't initiate expiration * events (unless in partner-down), but rather relies * on the primary to expire the lease. However, when * disconnected from its peer, the server is allowed to * rewind a lease to the previous state that the peer * would have recorded it. This means there may be * opportunities for active->free or active->backup * expirations while out of contact. * * Q: Should we limit this expiration to * comms-interrupt rather than not-normal? */ if ((i == ACTIVE_LEASES) && (pool->failover_peer->i_am == secondary) && (pool->failover_peer->me.state == normal)) continue; /* Leases in an expired state don't move to free because of a timeout unless we're in partner_down. */ if (i == EXPIRED_LEASES) continue; } #endif lease_reference (&lease, *(lptr [i]), MDL); while (lease) { /* Remember the next lease in the list. */ if (next) lease_dereference (&next, MDL); if (lease -> next) lease_reference (&next, lease -> next, MDL); /* If we've run out of things to expire on this list, stop. */ if (lease -> sort_time > cur_time) { if (lease -> sort_time < next_expiry) next_expiry = lease -> sort_time; break; } /* If there is a pending state change, and this lease has gotten to the time when the state change should happen, just call supersede_lease on it to make the change happen. */ if (lease->next_binding_state != lease->binding_state) { #if defined(FAILOVER_PROTOCOL) dhcp_failover_state_t *peer = NULL; if (lease->pool != NULL) peer = lease->pool->failover_peer; /* Can we rewind the lease to a free state? */ if (peer != NULL && peer->service_state == not_cooperating && lease->next_binding_state == FTS_EXPIRED && ((peer->i_am == primary && lease->rewind_binding_state == FTS_FREE) || (peer->i_am == secondary && lease->rewind_binding_state == FTS_BACKUP))) lease->next_binding_state = lease->rewind_binding_state; #endif supersede_lease(lease, NULL, 1, 1, 1); } lease_dereference (&lease, MDL); if (next) lease_reference (&lease, next, MDL); } if (next) lease_dereference (&next, MDL); if (lease) lease_dereference (&lease, MDL); } if (next_expiry != MAX_TIME) { pool -> next_event_time = next_expiry; tv . tv_sec = pool -> next_event_time; tv . tv_usec = 0; add_timeout (&tv, pool_timer, pool, (tvref_t)pool_reference, (tvunref_t)pool_dereference); } else pool -> next_event_time = MIN_TIME; } /* Locate the lease associated with a given IP address... */ int find_lease_by_ip_addr (struct lease **lp, struct iaddr addr, const char *file, int line) { return lease_ip_hash_lookup(lp, lease_ip_addr_hash, addr.iabuf, addr.len, file, line); } int find_lease_by_uid (struct lease **lp, const unsigned char *uid, unsigned len, const char *file, int line) { if (len == 0) return 0; return lease_id_hash_lookup (lp, lease_uid_hash, uid, len, file, line); } int find_lease_by_hw_addr (struct lease **lp, const unsigned char *hwaddr, unsigned hwlen, const char *file, int line) { if (hwlen == 0) return (0); /* * If it's an infiniband address don't bother * as we don't have a useful address to hash. */ if ((hwlen == 1) && (hwaddr[0] == HTYPE_INFINIBAND)) return (0); return (lease_id_hash_lookup(lp, lease_hw_addr_hash, hwaddr, hwlen, file, line)); } /* If the lease is preferred over the candidate, return truth. The * 'cand' and 'lease' names are retained to read more clearly against * the 'uid_hash_add' and 'hw_hash_add' functions (this is common logic * to those two functions). * * 1) ACTIVE leases are preferred. The active lease with * the longest lifetime is preferred over shortest. * 2) "transitional states" are next, this time with the * most recent CLTT. * 3) free/backup/etc states are next, again with CLTT. In truth we * should never see reset leases for this. * 4) Abandoned leases are always dead last. */ static isc_boolean_t client_lease_preferred(struct lease *cand, struct lease *lease) { if (cand->binding_state == FTS_ACTIVE) { if (lease->binding_state == FTS_ACTIVE && lease->ends >= cand->ends) return ISC_TRUE; } else if (cand->binding_state == FTS_EXPIRED || cand->binding_state == FTS_RELEASED) { if (lease->binding_state == FTS_ACTIVE) return ISC_TRUE; if ((lease->binding_state == FTS_EXPIRED || lease->binding_state == FTS_RELEASED) && lease->cltt >= cand->cltt) return ISC_TRUE; } else if (cand->binding_state != FTS_ABANDONED) { if (lease->binding_state == FTS_ACTIVE || lease->binding_state == FTS_EXPIRED || lease->binding_state == FTS_RELEASED) return ISC_TRUE; if (lease->binding_state != FTS_ABANDONED && lease->cltt >= cand->cltt) return ISC_TRUE; } else /* (cand->binding_state == FTS_ABANDONED) */ { if (lease->binding_state != FTS_ABANDONED || lease->cltt >= cand->cltt) return ISC_TRUE; } return ISC_FALSE; } /* Add the specified lease to the uid hash. */ void uid_hash_add(struct lease *lease) { struct lease *head = NULL; struct lease *cand = NULL; struct lease *prev = NULL; struct lease *next = NULL; /* If it's not in the hash, just add it. */ if (!find_lease_by_uid (&head, lease -> uid, lease -> uid_len, MDL)) lease_id_hash_add(lease_uid_hash, lease->uid, lease->uid_len, lease, MDL); else { /* Otherwise, insert it into the list in order of its * preference for "resuming allocation to the client." * * Because we don't have control of the hash bucket index * directly, we have to remove and re-insert the client * id into the hash if we're inserting onto the head. */ lease_reference(&cand, head, MDL); while (cand != NULL) { if (client_lease_preferred(cand, lease)) break; if (prev != NULL) lease_dereference(&prev, MDL); lease_reference(&prev, cand, MDL); if (cand->n_uid != NULL) lease_reference(&next, cand->n_uid, MDL); lease_dereference(&cand, MDL); if (next != NULL) { lease_reference(&cand, next, MDL); lease_dereference(&next, MDL); } } /* If we want to insert 'before cand', and prev is NULL, * then it was the head of the list. Assume that position. */ if (prev == NULL) { lease_reference(&lease->n_uid, head, MDL); lease_id_hash_delete(lease_uid_hash, lease->uid, lease->uid_len, MDL); lease_id_hash_add(lease_uid_hash, lease->uid, lease->uid_len, lease, MDL); } else /* (prev != NULL) */ { if(prev->n_uid != NULL) { lease_reference(&lease->n_uid, prev->n_uid, MDL); lease_dereference(&prev->n_uid, MDL); } lease_reference(&prev->n_uid, lease, MDL); lease_dereference(&prev, MDL); } if (cand != NULL) lease_dereference(&cand, MDL); lease_dereference(&head, MDL); } } /* Delete the specified lease from the uid hash. */ void uid_hash_delete (lease) struct lease *lease; { struct lease *head = (struct lease *)0; struct lease *scan; /* If it's not in the hash, we have no work to do. */ if (!find_lease_by_uid (&head, lease -> uid, lease -> uid_len, MDL)) { if (lease -> n_uid) lease_dereference (&lease -> n_uid, MDL); return; } /* If the lease we're freeing is at the head of the list, remove the hash table entry and add a new one with the next lease on the list (if there is one). */ if (head == lease) { lease_id_hash_delete(lease_uid_hash, lease->uid, lease->uid_len, MDL); if (lease -> n_uid) { lease_id_hash_add(lease_uid_hash, lease->n_uid->uid, lease->n_uid->uid_len, lease->n_uid, MDL); lease_dereference (&lease -> n_uid, MDL); } } else { /* Otherwise, look for the lease in the list of leases attached to the hash table entry, and remove it if we find it. */ for (scan = head; scan -> n_uid; scan = scan -> n_uid) { if (scan -> n_uid == lease) { lease_dereference (&scan -> n_uid, MDL); if (lease -> n_uid) { lease_reference (&scan -> n_uid, lease -> n_uid, MDL); lease_dereference (&lease -> n_uid, MDL); } break; } } } lease_dereference (&head, MDL); } /* Add the specified lease to the hardware address hash. */ /* We don't add leases with infiniband addresses to the * hash as there isn't any address to hash on. */ void hw_hash_add(struct lease *lease) { struct lease *head = NULL; struct lease *cand = NULL; struct lease *prev = NULL; struct lease *next = NULL; /* * If it's an infiniband address don't bother * as we don't have a useful address to hash. */ if ((lease->hardware_addr.hlen == 1) && (lease->hardware_addr.hbuf[0] == HTYPE_INFINIBAND)) return; /* If it's not in the hash, just add it. */ if (!find_lease_by_hw_addr (&head, lease -> hardware_addr.hbuf, lease -> hardware_addr.hlen, MDL)) lease_id_hash_add(lease_hw_addr_hash, lease->hardware_addr.hbuf, lease->hardware_addr.hlen, lease, MDL); else { /* Otherwise, insert it into the list in order of its * preference for "resuming allocation to the client." * * Because we don't have control of the hash bucket index * directly, we have to remove and re-insert the client * id into the hash if we're inserting onto the head. */ lease_reference(&cand, head, MDL); while (cand != NULL) { if (client_lease_preferred(cand, lease)) break; if (prev != NULL) lease_dereference(&prev, MDL); lease_reference(&prev, cand, MDL); if (cand->n_hw != NULL) lease_reference(&next, cand->n_hw, MDL); lease_dereference(&cand, MDL); if (next != NULL) { lease_reference(&cand, next, MDL); lease_dereference(&next, MDL); } } /* If we want to insert 'before cand', and prev is NULL, * then it was the head of the list. Assume that position. */ if (prev == NULL) { lease_reference(&lease->n_hw, head, MDL); lease_id_hash_delete(lease_hw_addr_hash, lease->hardware_addr.hbuf, lease->hardware_addr.hlen, MDL); lease_id_hash_add(lease_hw_addr_hash, lease->hardware_addr.hbuf, lease->hardware_addr.hlen, lease, MDL); } else /* (prev != NULL) */ { if(prev->n_hw != NULL) { lease_reference(&lease->n_hw, prev->n_hw, MDL); lease_dereference(&prev->n_hw, MDL); } lease_reference(&prev->n_hw, lease, MDL); lease_dereference(&prev, MDL); } if (cand != NULL) lease_dereference(&cand, MDL); lease_dereference(&head, MDL); } } /* Delete the specified lease from the hardware address hash. */ void hw_hash_delete (lease) struct lease *lease; { struct lease *head = (struct lease *)0; struct lease *next = (struct lease *)0; /* * If it's an infiniband address don't bother * as we don't have a useful address to hash. */ if ((lease->hardware_addr.hlen == 1) && (lease->hardware_addr.hbuf[0] == HTYPE_INFINIBAND)) return; /* If it's not in the hash, we have no work to do. */ if (!find_lease_by_hw_addr (&head, lease -> hardware_addr.hbuf, lease -> hardware_addr.hlen, MDL)) { if (lease -> n_hw) lease_dereference (&lease -> n_hw, MDL); return; } /* If the lease we're freeing is at the head of the list, remove the hash table entry and add a new one with the next lease on the list (if there is one). */ if (head == lease) { lease_id_hash_delete(lease_hw_addr_hash, lease->hardware_addr.hbuf, lease->hardware_addr.hlen, MDL); if (lease->n_hw) { lease_id_hash_add(lease_hw_addr_hash, lease->n_hw->hardware_addr.hbuf, lease->n_hw->hardware_addr.hlen, lease->n_hw, MDL); lease_dereference(&lease->n_hw, MDL); } } else { /* Otherwise, look for the lease in the list of leases attached to the hash table entry, and remove it if we find it. */ while (head -> n_hw) { if (head -> n_hw == lease) { lease_dereference (&head -> n_hw, MDL); if (lease -> n_hw) { lease_reference (&head -> n_hw, lease -> n_hw, MDL); lease_dereference (&lease -> n_hw, MDL); } break; } lease_reference (&next, head -> n_hw, MDL); lease_dereference (&head, MDL); lease_reference (&head, next, MDL); lease_dereference (&next, MDL); } } if (head) lease_dereference (&head, MDL); } /* Write all interesting leases to permanent storage. */ int write_leases () { struct lease *l; struct shared_network *s; struct pool *p; struct host_decl *hp; struct group_object *gp; struct hash_bucket *hb; struct class *cp; struct collection *colp; int i; int num_written; struct lease **lptr[RESERVED_LEASES+1]; /* write all the dynamically-created class declarations. */ if (collections->classes) { numclasseswritten = 0; for (colp = collections ; colp ; colp = colp->next) { for (cp = colp->classes ; cp ; cp = cp->nic) { write_named_billing_class( (unsigned char *)cp->name, 0, cp); } } /* XXXJAB this number doesn't include subclasses... */ log_info ("Wrote %d class decls to leases file.", numclasseswritten); } /* Write all the dynamically-created group declarations. */ if (group_name_hash) { num_written = 0; for (i = 0; i < group_name_hash -> hash_count; i++) { for (hb = group_name_hash -> buckets [i]; hb; hb = hb -> next) { gp = (struct group_object *)hb -> value; if ((gp -> flags & GROUP_OBJECT_DYNAMIC) || ((gp -> flags & GROUP_OBJECT_STATIC) && (gp -> flags & GROUP_OBJECT_DELETED))) { if (!write_group (gp)) return 0; ++num_written; } } } log_info ("Wrote %d group decls to leases file.", num_written); } /* Write all the deleted host declarations. */ if (host_name_hash) { num_written = 0; for (i = 0; i < host_name_hash -> hash_count; i++) { for (hb = host_name_hash -> buckets [i]; hb; hb = hb -> next) { hp = (struct host_decl *)hb -> value; if (((hp -> flags & HOST_DECL_STATIC) && (hp -> flags & HOST_DECL_DELETED))) { if (!write_host (hp)) return 0; ++num_written; } } } log_info ("Wrote %d deleted host decls to leases file.", num_written); } /* Write all the new, dynamic host declarations. */ if (host_name_hash) { num_written = 0; for (i = 0; i < host_name_hash -> hash_count; i++) { for (hb = host_name_hash -> buckets [i]; hb; hb = hb -> next) { hp = (struct host_decl *)hb -> value; if ((hp -> flags & HOST_DECL_DYNAMIC)) { if (!write_host (hp)) ++num_written; } } } log_info ("Wrote %d new dynamic host decls to leases file.", num_written); } #if defined (FAILOVER_PROTOCOL) /* Write all the failover states. */ if (!dhcp_failover_write_all_states ()) return 0; #endif /* Write all the leases. */ num_written = 0; for (s = shared_networks; s; s = s -> next) { for (p = s -> pools; p; p = p -> next) { lptr [FREE_LEASES] = &p -> free; lptr [ACTIVE_LEASES] = &p -> active; lptr [EXPIRED_LEASES] = &p -> expired; lptr [ABANDONED_LEASES] = &p -> abandoned; lptr [BACKUP_LEASES] = &p -> backup; lptr [RESERVED_LEASES] = &p->reserved; for (i = FREE_LEASES; i <= RESERVED_LEASES; i++) { for (l = *(lptr [i]); l; l = l -> next) { #if !defined (DEBUG_DUMP_ALL_LEASES) if (l->hardware_addr.hlen != 0 || l->uid_len != 0 || l->tsfp != 0 || l->binding_state != FTS_FREE) #endif { if (!write_lease (l)) return 0; num_written++; } } } } } log_info ("Wrote %d leases to leases file.", num_written); #ifdef DHCPv6 if (!write_leases6()) { return 0; } #endif /* DHCPv6 */ if (!commit_leases ()) return 0; return 1; } /* In addition to placing this lease upon a lease queue depending on its * state, it also keeps track of the number of FREE and BACKUP leases in * existence, and sets the sort_time on the lease. * * Sort_time is used in pool_timer() to determine when the lease will * bubble to the top of the list and be supersede_lease()'d into its next * state (possibly, if all goes well). Example, ACTIVE leases move to * EXPIRED state when the 'ends' value is reached, so that is its sort * time. Most queues are sorted by 'ends', since it is generally best * practice to re-use the oldest lease, to reduce address collision * chances. */ int lease_enqueue (struct lease *comp) { struct lease **lq, *prev, *lp; static struct lease **last_lq = NULL; static struct lease *last_insert_point = NULL; /* No queue to put it on? */ if (!comp -> pool) return 0; /* Figure out which queue it's going to. */ switch (comp -> binding_state) { case FTS_FREE: if (comp->flags & RESERVED_LEASE) { lq = &comp->pool->reserved; } else { lq = &comp->pool->free; comp->pool->free_leases++; } comp -> sort_time = comp -> ends; break; case FTS_ACTIVE: lq = &comp -> pool -> active; comp -> sort_time = comp -> ends; break; case FTS_EXPIRED: case FTS_RELEASED: case FTS_RESET: lq = &comp -> pool -> expired; #if defined(FAILOVER_PROTOCOL) /* In partner_down, tsfp is the time at which the lease * may be reallocated (stos+mclt). We can do that with * lease_mine_to_reallocate() anywhere between tsfp and * ends. But we prefer to wait until ends before doing it * automatically (choose the greater of the two). Note * that 'ends' is usually a historic timestamp in the * case of expired leases, is really only in the future * on released leases, and if we know a lease to be released * the peer might still know it to be active...in which case * it's possible the peer has renewed this lease, so avoid * doing that. */ if (comp->pool->failover_peer && comp->pool->failover_peer->me.state == partner_down) comp->sort_time = (comp->tsfp > comp->ends) ? comp->tsfp : comp->ends; else #endif comp->sort_time = comp->ends; break; case FTS_ABANDONED: lq = &comp -> pool -> abandoned; comp -> sort_time = comp -> ends; break; case FTS_BACKUP: if (comp->flags & RESERVED_LEASE) { lq = &comp->pool->reserved; } else { lq = &comp->pool->backup; comp->pool->backup_leases++; } comp -> sort_time = comp -> ends; break; default: log_error ("Lease with bogus binding state: %d", comp -> binding_state); #if defined (BINDING_STATE_DEBUG) abort (); #endif return 0; } /* This only works during server startup: during runtime, the last * lease may be dequeued in between calls. If the queue is the same * as was used previously, and the lease structure isn't (this is not * a re-queue), use that as a starting point for the insertion-sort. */ if ((server_starting & SS_QFOLLOW) && (lq == last_lq) && (comp != last_insert_point) && (last_insert_point->sort_time <= comp->sort_time)) { prev = last_insert_point; lp = prev->next; } else { prev = NULL; lp = *lq; } /* Insertion sort the lease onto the appropriate queue. */ for (; lp ; lp = lp->next) { if (lp -> sort_time >= comp -> sort_time) break; prev = lp; } if (prev) { if (prev -> next) { lease_reference (&comp -> next, prev -> next, MDL); lease_dereference (&prev -> next, MDL); } lease_reference (&prev -> next, comp, MDL); } else { if (*lq) { lease_reference (&comp -> next, *lq, MDL); lease_dereference (lq, MDL); } lease_reference (lq, comp, MDL); } last_insert_point = comp; last_lq = lq; return 1; } /* For a given lease, sort it onto the right list in its pool and put it in each appropriate hash, understanding that it's already by definition in lease_ip_addr_hash. */ isc_result_t lease_instantiate(const void *key, unsigned len, void *object) { struct lease *lease = object; struct class *class; /* XXX If the lease doesn't have a pool at this point, it's an XXX orphan, which we *should* keep around until it expires, XXX but which right now we just forget. */ if (!lease -> pool) { lease_ip_hash_delete(lease_ip_addr_hash, lease->ip_addr.iabuf, lease->ip_addr.len, MDL); return ISC_R_SUCCESS; } /* Put the lease on the right queue. Failure to queue is probably * due to a bogus binding state. In such a case, we claim success, * so that later leases in a hash_foreach are processed, but we * return early as we really don't want hw address hash entries or * other cruft to surround such a bogus entry. */ if (!lease_enqueue(lease)) return ISC_R_SUCCESS; /* Record the lease in the uid hash if possible. */ if (lease -> uid) { uid_hash_add (lease); } /* Record it in the hardware address hash if possible. */ if (lease -> hardware_addr.hlen) { hw_hash_add (lease); } /* If the lease has a billing class, set up the billing. */ if (lease -> billing_class) { class = (struct class *)0; class_reference (&class, lease -> billing_class, MDL); class_dereference (&lease -> billing_class, MDL); /* If the lease is available for allocation, the billing is invalid, so we don't keep it. */ if (lease -> binding_state == FTS_ACTIVE || lease -> binding_state == FTS_EXPIRED || lease -> binding_state == FTS_RELEASED || lease -> binding_state == FTS_RESET) bill_class (lease, class); class_dereference (&class, MDL); } return ISC_R_SUCCESS; } /* Run expiry events on every pool. This is called on startup so that any expiry events that occurred after the server stopped and before it was restarted can be run. At the same time, if failover support is compiled in, we compute the balance of leases for the pool. */ void expire_all_pools () { struct shared_network *s; struct pool *p; int i; struct lease *l; struct lease **lptr[RESERVED_LEASES+1]; /* Indicate that we are in the startup phase */ server_starting = SS_NOSYNC | SS_QFOLLOW; /* First, go over the hash list and actually put all the leases on the appropriate lists. */ lease_ip_hash_foreach(lease_ip_addr_hash, lease_instantiate); /* Loop through each pool in each shared network and call the * expiry routine on the pool. It is no longer safe to follow * the queue insertion point, as expiration of a lease can move * it between queues (and this may be the lease that function * points at). */ server_starting &= ~SS_QFOLLOW; for (s = shared_networks; s; s = s -> next) { for (p = s -> pools; p; p = p -> next) { pool_timer (p); p -> lease_count = 0; p -> free_leases = 0; p -> backup_leases = 0; lptr [FREE_LEASES] = &p -> free; lptr [ACTIVE_LEASES] = &p -> active; lptr [EXPIRED_LEASES] = &p -> expired; lptr [ABANDONED_LEASES] = &p -> abandoned; lptr [BACKUP_LEASES] = &p -> backup; lptr [RESERVED_LEASES] = &p->reserved; for (i = FREE_LEASES; i <= RESERVED_LEASES; i++) { for (l = *(lptr [i]); l; l = l -> next) { p -> lease_count++; if (l -> ends <= cur_time) { if (l->binding_state == FTS_FREE) { if (i == FREE_LEASES) p->free_leases++; else if (i != RESERVED_LEASES) log_fatal("Impossible case " "at %s:%d.", MDL); } else if (l->binding_state == FTS_BACKUP) { if (i == BACKUP_LEASES) p->backup_leases++; else if (i != RESERVED_LEASES) log_fatal("Impossible case " "at %s:%d.", MDL); } } #if defined (FAILOVER_PROTOCOL) if (p -> failover_peer && l -> tstp > l -> atsfp && !(l -> flags & ON_UPDATE_QUEUE)) { l -> desired_binding_state = l -> binding_state; dhcp_failover_queue_update (l, 1); } #endif } } } } /* turn off startup phase */ server_starting = 0; } void dump_subnets () { struct lease *l; struct shared_network *s; struct subnet *n; struct pool *p; struct lease **lptr[RESERVED_LEASES+1]; int i; log_info ("Subnets:"); for (n = subnets; n; n = n -> next_subnet) { log_debug (" Subnet %s", piaddr (n -> net)); log_debug (" netmask %s", piaddr (n -> netmask)); } log_info ("Shared networks:"); for (s = shared_networks; s; s = s -> next) { log_info (" %s", s -> name); for (p = s -> pools; p; p = p -> next) { lptr [FREE_LEASES] = &p -> free; lptr [ACTIVE_LEASES] = &p -> active; lptr [EXPIRED_LEASES] = &p -> expired; lptr [ABANDONED_LEASES] = &p -> abandoned; lptr [BACKUP_LEASES] = &p -> backup; lptr [RESERVED_LEASES] = &p->reserved; for (i = FREE_LEASES; i <= RESERVED_LEASES; i++) { for (l = *(lptr [i]); l; l = l -> next) { print_lease (l); } } } } } HASH_FUNCTIONS(lease_ip, const unsigned char *, struct lease, lease_ip_hash_t, lease_reference, lease_dereference, do_ip4_hash) HASH_FUNCTIONS(lease_id, const unsigned char *, struct lease, lease_id_hash_t, lease_reference, lease_dereference, do_id_hash) HASH_FUNCTIONS (host, const unsigned char *, struct host_decl, host_hash_t, host_reference, host_dereference, do_string_hash) HASH_FUNCTIONS (class, const char *, struct class, class_hash_t, class_reference, class_dereference, do_string_hash) #if defined (DEBUG_MEMORY_LEAKAGE) && \ defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT) extern struct hash_table *dns_zone_hash; extern struct interface_info **interface_vector; extern int interface_count; dhcp_control_object_t *dhcp_control_object; extern struct hash_table *auth_key_hash; struct hash_table *universe_hash; struct universe **universes; int universe_count, universe_max; #if 0 extern int end; #endif #if defined (COMPACT_LEASES) extern struct lease *lease_hunks; #endif void free_everything(void) { struct subnet *sc = (struct subnet *)0, *sn = (struct subnet *)0; struct shared_network *nc = (struct shared_network *)0, *nn = (struct shared_network *)0; struct pool *pc = (struct pool *)0, *pn = (struct pool *)0; struct lease *lc = (struct lease *)0, *ln = (struct lease *)0; struct interface_info *ic = (struct interface_info *)0, *in = (struct interface_info *)0; struct class *cc = (struct class *)0, *cn = (struct class *)0; struct collection *lp; int i; /* Get rid of all the hash tables. */ if (host_hw_addr_hash) host_free_hash_table (&host_hw_addr_hash, MDL); host_hw_addr_hash = 0; if (host_uid_hash) host_free_hash_table (&host_uid_hash, MDL); host_uid_hash = 0; if (lease_uid_hash) lease_id_free_hash_table (&lease_uid_hash, MDL); lease_uid_hash = 0; if (lease_ip_addr_hash) lease_ip_free_hash_table (&lease_ip_addr_hash, MDL); lease_ip_addr_hash = 0; if (lease_hw_addr_hash) lease_id_free_hash_table (&lease_hw_addr_hash, MDL); lease_hw_addr_hash = 0; if (host_name_hash) host_free_hash_table (&host_name_hash, MDL); host_name_hash = 0; if (dns_zone_hash) dns_zone_free_hash_table (&dns_zone_hash, MDL); dns_zone_hash = 0; while (host_id_info != NULL) { host_id_info_t *tmp; option_dereference(&host_id_info->option, MDL); host_free_hash_table(&host_id_info->values_hash, MDL); tmp = host_id_info->next; dfree(host_id_info, MDL); host_id_info = tmp; } #if 0 if (auth_key_hash) auth_key_free_hash_table (&auth_key_hash, MDL); #endif auth_key_hash = 0; omapi_object_dereference ((omapi_object_t **)&dhcp_control_object, MDL); for (lp = collections; lp; lp = lp -> next) { if (lp -> classes) { class_reference (&cn, lp -> classes, MDL); do { if (cn) { class_reference (&cc, cn, MDL); class_dereference (&cn, MDL); } if (cc -> nic) { class_reference (&cn, cc -> nic, MDL); class_dereference (&cc -> nic, MDL); } group_dereference (&cc -> group, MDL); if (cc -> hash) { class_free_hash_table (&cc -> hash, MDL); cc -> hash = (struct hash_table *)0; } class_dereference (&cc, MDL); } while (cn); class_dereference (&lp -> classes, MDL); } } if (interface_vector) { for (i = 0; i < interface_count; i++) { if (interface_vector [i]) interface_dereference (&interface_vector [i], MDL); } dfree (interface_vector, MDL); interface_vector = 0; } if (interfaces) { interface_reference (&in, interfaces, MDL); do { if (in) { interface_reference (&ic, in, MDL); interface_dereference (&in, MDL); } if (ic -> next) { interface_reference (&in, ic -> next, MDL); interface_dereference (&ic -> next, MDL); } omapi_unregister_io_object ((omapi_object_t *)ic); if (ic -> shared_network) { if (ic -> shared_network -> interface) interface_dereference (&ic -> shared_network -> interface, MDL); shared_network_dereference (&ic -> shared_network, MDL); } interface_dereference (&ic, MDL); } while (in); interface_dereference (&interfaces, MDL); } /* Subnets are complicated because of the extra links. */ if (subnets) { subnet_reference (&sn, subnets, MDL); do { if (sn) { subnet_reference (&sc, sn, MDL); subnet_dereference (&sn, MDL); } if (sc -> next_subnet) { subnet_reference (&sn, sc -> next_subnet, MDL); subnet_dereference (&sc -> next_subnet, MDL); } if (sc -> next_sibling) subnet_dereference (&sc -> next_sibling, MDL); if (sc -> shared_network) shared_network_dereference (&sc -> shared_network, MDL); group_dereference (&sc -> group, MDL); if (sc -> interface) interface_dereference (&sc -> interface, MDL); subnet_dereference (&sc, MDL); } while (sn); subnet_dereference (&subnets, MDL); } /* So are shared networks. */ /* XXX: this doesn't work presently, but i'm ok just filtering * it out of the noise (you get a bigger spike on the real leaks). * It would be good to fix this, but it is not a "real bug," so not * today. This hack is incomplete, it doesn't trim out sub-values. */ if (shared_networks) { shared_network_dereference (&shared_networks, MDL); /* This is the old method (tries to free memory twice, broken) */ } else if (0) { shared_network_reference (&nn, shared_networks, MDL); do { if (nn) { shared_network_reference (&nc, nn, MDL); shared_network_dereference (&nn, MDL); } if (nc -> next) { shared_network_reference (&nn, nc -> next, MDL); shared_network_dereference (&nc -> next, MDL); } /* As are pools. */ if (nc -> pools) { pool_reference (&pn, nc -> pools, MDL); do { struct lease **lptr[RESERVED_LEASES+1]; if (pn) { pool_reference (&pc, pn, MDL); pool_dereference (&pn, MDL); } if (pc -> next) { pool_reference (&pn, pc -> next, MDL); pool_dereference (&pc -> next, MDL); } lptr [FREE_LEASES] = &pc -> free; lptr [ACTIVE_LEASES] = &pc -> active; lptr [EXPIRED_LEASES] = &pc -> expired; lptr [ABANDONED_LEASES] = &pc -> abandoned; lptr [BACKUP_LEASES] = &pc -> backup; lptr [RESERVED_LEASES] = &pc->reserved; /* As (sigh) are leases. */ for (i = FREE_LEASES ; i <= RESERVED_LEASES ; i++) { if (*lptr [i]) { lease_reference (&ln, *lptr [i], MDL); do { if (ln) { lease_reference (&lc, ln, MDL); lease_dereference (&ln, MDL); } if (lc -> next) { lease_reference (&ln, lc -> next, MDL); lease_dereference (&lc -> next, MDL); } if (lc -> billing_class) class_dereference (&lc -> billing_class, MDL); if (lc -> state) free_lease_state (lc -> state, MDL); lc -> state = (struct lease_state *)0; if (lc -> n_hw) lease_dereference (&lc -> n_hw, MDL); if (lc -> n_uid) lease_dereference (&lc -> n_uid, MDL); lease_dereference (&lc, MDL); } while (ln); lease_dereference (lptr [i], MDL); } } if (pc -> group) group_dereference (&pc -> group, MDL); if (pc -> shared_network) shared_network_dereference (&pc -> shared_network, MDL); pool_dereference (&pc, MDL); } while (pn); pool_dereference (&nc -> pools, MDL); } /* Because of a circular reference, we need to nuke this manually. */ group_dereference (&nc -> group, MDL); shared_network_dereference (&nc, MDL); } while (nn); shared_network_dereference (&shared_networks, MDL); } cancel_all_timeouts (); relinquish_timeouts (); relinquish_ackqueue(); trace_free_all (); group_dereference (&root_group, MDL); executable_statement_dereference (&default_classification_rules, MDL); shutdown_state = shutdown_drop_omapi_connections; omapi_io_state_foreach (dhcp_io_shutdown, 0); shutdown_state = shutdown_listeners; omapi_io_state_foreach (dhcp_io_shutdown, 0); shutdown_state = shutdown_dhcp; omapi_io_state_foreach (dhcp_io_shutdown, 0); omapi_object_dereference ((omapi_object_t **)&icmp_state, MDL); universe_free_hash_table (&universe_hash, MDL); for (i = 0; i < universe_count; i++) { #if 0 union { const char *c; char *s; } foo; #endif if (universes [i]) { if (universes[i]->name_hash) option_name_free_hash_table( &universes[i]->name_hash, MDL); if (universes[i]->code_hash) option_code_free_hash_table( &universes[i]->code_hash, MDL); #if 0 if (universes [i] -> name > (char *)&end) { foo.c = universes [i] -> name; dfree (foo.s, MDL); } if (universes [i] > (struct universe *)&end) dfree (universes [i], MDL); #endif } } dfree (universes, MDL); relinquish_free_lease_states (); relinquish_free_pairs (); relinquish_free_expressions (); relinquish_free_binding_values (); relinquish_free_option_caches (); relinquish_free_packets (); #if defined(COMPACT_LEASES) relinquish_lease_hunks (); #endif relinquish_hash_bucket_hunks (); omapi_type_relinquish (); } #endif /* DEBUG_MEMORY_LEAKAGE_ON_EXIT */ dhcp-4.2.4/server/mdb6.c000644 000765 000024 00000221226 11754542635 014712 0ustar00sarstaff000000 000000 /* * Copyright (C) 2007-2012 by Internet Systems Consortium, Inc. ("ISC") * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ /*! * \todo assert() * \todo simplify functions, as pool is now in iaaddr */ /*! \file server/mdb6.c * * \page ipv6structures IPv6 Structures Overview * * A brief description of the IPv6 structures as reverse engineered. * * There are three major data strucutes involved in the database: * ipv6_pool - this contains information about a pool of addresses or prefixes * that the server is using. This includes a hash table that * tracks the active items and a pair of heap tables one for * active items and one for non-active items. The heap tables * are used to determine the next items to be modified due to * timing events (expire mostly). * ia_xx - this contains information about a single IA from a request * normally it will contain one pointer to a lease for the client * but it may contain more in some circumstances. There are 3 * hash tables to aid in accessing these one each for NA, TA and PD * iasubopt - the v6 lease structure. These are creaeted dynamically when * a client asks for something and will eventually be destroyed * if the client doesn't re-ask for that item. A lease has space * for backpointers to the IA and to the pool to which it belongs. * The pool backpointer is always filled, the IA pointer may not be * * In normal use we then have something like this: * * ia hash tables * ia_na_active +----------------+ * ia_ta_active +------------+ | pool | * ia_pd_active | iasubopt |<--| active hash | * +-----------------+ | aka lease |<--| active heap | * | ia_xx | | pool ptr |-->| | * | iasubopt array |<---| iaptr |<--| inactive heap | * | lease ptr |--->| | | | * +-----------------+ +------------+ +----------------+ * * For the pool either the inactive heap will have a pointer * or both the active heap and the active hash will have pointers. * * I think there are several major items to notice. The first is * that as a lease moves around it will be added to and removed * from the address hash table in the pool and between the active * and inactive hash tables. The hash table and the active heap * are used when the lease is either active or abandoned. The * inactive heap is used for all other states. In particular a * lease that has expired or been released will be cleaned * (DDNS removal etc) and then moved to the inactive heap. After * some time period (currently 1 hour) it will be freed. * * The second is that when a client requests specific addresses, * either because it previously owned them or if the server supplied * them as part of a solicit, the server will try to lookup the ia_xx * associated with the client and find the addresses there. If it * does find appropriate leases it moves them from the old IA to * a new IA and eventually replaces the old IA with the new IA * in the IA hash tables. * */ #include "config.h" #include #include #include #include #include "dhcpd.h" #include "omapip/omapip.h" #include "omapip/hash.h" #include HASH_FUNCTIONS(ia, unsigned char *, struct ia_xx, ia_hash_t, ia_reference, ia_dereference, do_string_hash) ia_hash_t *ia_na_active; ia_hash_t *ia_ta_active; ia_hash_t *ia_pd_active; HASH_FUNCTIONS(iasubopt, struct in6_addr *, struct iasubopt, iasubopt_hash_t, iasubopt_reference, iasubopt_dereference, do_string_hash) struct ipv6_pool **pools; int num_pools; /* * Create a new IAADDR/PREFIX structure. * * - iasubopt must be a pointer to a (struct iasubopt *) pointer previously * initialized to NULL */ isc_result_t iasubopt_allocate(struct iasubopt **iasubopt, const char *file, int line) { struct iasubopt *tmp; if (iasubopt == NULL) { log_error("%s(%d): NULL pointer reference", file, line); return DHCP_R_INVALIDARG; } if (*iasubopt != NULL) { log_error("%s(%d): non-NULL pointer", file, line); return DHCP_R_INVALIDARG; } tmp = dmalloc(sizeof(*tmp), file, line); if (tmp == NULL) { return ISC_R_NOMEMORY; } tmp->refcnt = 1; tmp->state = FTS_FREE; tmp->heap_index = -1; tmp->plen = 255; *iasubopt = tmp; return ISC_R_SUCCESS; } /* * Reference an IAADDR/PREFIX structure. * * - iasubopt must be a pointer to a (struct iasubopt *) pointer previously * initialized to NULL */ isc_result_t iasubopt_reference(struct iasubopt **iasubopt, struct iasubopt *src, const char *file, int line) { if (iasubopt == NULL) { log_error("%s(%d): NULL pointer reference", file, line); return DHCP_R_INVALIDARG; } if (*iasubopt != NULL) { log_error("%s(%d): non-NULL pointer", file, line); return DHCP_R_INVALIDARG; } if (src == NULL) { log_error("%s(%d): NULL pointer reference", file, line); return DHCP_R_INVALIDARG; } *iasubopt = src; src->refcnt++; return ISC_R_SUCCESS; } /* * Dereference an IAADDR/PREFIX structure. * * If it is the last reference, then the memory for the * structure is freed. */ isc_result_t iasubopt_dereference(struct iasubopt **iasubopt, const char *file, int line) { struct iasubopt *tmp; if ((iasubopt == NULL) || (*iasubopt == NULL)) { log_error("%s(%d): NULL pointer", file, line); return DHCP_R_INVALIDARG; } tmp = *iasubopt; *iasubopt = NULL; tmp->refcnt--; if (tmp->refcnt < 0) { log_error("%s(%d): negative refcnt", file, line); tmp->refcnt = 0; } if (tmp->refcnt == 0) { if (tmp->ia != NULL) { ia_dereference(&(tmp->ia), file, line); } if (tmp->ipv6_pool != NULL) { ipv6_pool_dereference(&(tmp->ipv6_pool), file, line); } if (tmp->scope != NULL) { binding_scope_dereference(&tmp->scope, file, line); } dfree(tmp, file, line); } return ISC_R_SUCCESS; } /* * Make the key that we use for IA. */ isc_result_t ia_make_key(struct data_string *key, u_int32_t iaid, const char *duid, unsigned int duid_len, const char *file, int line) { memset(key, 0, sizeof(*key)); key->len = duid_len + sizeof(iaid); if (!buffer_allocate(&(key->buffer), key->len, file, line)) { return ISC_R_NOMEMORY; } key->data = key->buffer->data; memcpy((char *)key->data, &iaid, sizeof(iaid)); memcpy((char *)key->data + sizeof(iaid), duid, duid_len); return ISC_R_SUCCESS; } /* * Create a new IA structure. * * - ia must be a pointer to a (struct ia_xx *) pointer previously * initialized to NULL * - iaid and duid are values from the client * * XXXsk: we don't concern ourself with the byte order of the IAID, * which might be a problem if we transfer this structure * between machines of different byte order */ isc_result_t ia_allocate(struct ia_xx **ia, u_int32_t iaid, const char *duid, unsigned int duid_len, const char *file, int line) { struct ia_xx *tmp; if (ia == NULL) { log_error("%s(%d): NULL pointer reference", file, line); return DHCP_R_INVALIDARG; } if (*ia != NULL) { log_error("%s(%d): non-NULL pointer", file, line); return DHCP_R_INVALIDARG; } tmp = dmalloc(sizeof(*tmp), file, line); if (tmp == NULL) { return ISC_R_NOMEMORY; } if (ia_make_key(&tmp->iaid_duid, iaid, duid, duid_len, file, line) != ISC_R_SUCCESS) { dfree(tmp, file, line); return ISC_R_NOMEMORY; } tmp->refcnt = 1; *ia = tmp; return ISC_R_SUCCESS; } /* * Reference an IA structure. * * - ia must be a pointer to a (struct ia_xx *) pointer previously * initialized to NULL */ isc_result_t ia_reference(struct ia_xx **ia, struct ia_xx *src, const char *file, int line) { if (ia == NULL) { log_error("%s(%d): NULL pointer reference", file, line); return DHCP_R_INVALIDARG; } if (*ia != NULL) { log_error("%s(%d): non-NULL pointer", file, line); return DHCP_R_INVALIDARG; } if (src == NULL) { log_error("%s(%d): NULL pointer reference", file, line); return DHCP_R_INVALIDARG; } *ia = src; src->refcnt++; return ISC_R_SUCCESS; } /* * Dereference an IA structure. * * If it is the last reference, then the memory for the * structure is freed. */ isc_result_t ia_dereference(struct ia_xx **ia, const char *file, int line) { struct ia_xx *tmp; int i; if ((ia == NULL) || (*ia == NULL)) { log_error("%s(%d): NULL pointer", file, line); return DHCP_R_INVALIDARG; } tmp = *ia; *ia = NULL; tmp->refcnt--; if (tmp->refcnt < 0) { log_error("%s(%d): negative refcnt", file, line); tmp->refcnt = 0; } if (tmp->refcnt == 0) { if (tmp->iasubopt != NULL) { for (i=0; inum_iasubopt; i++) { iasubopt_dereference(&(tmp->iasubopt[i]), file, line); } dfree(tmp->iasubopt, file, line); } data_string_forget(&(tmp->iaid_duid), file, line); dfree(tmp, file, line); } return ISC_R_SUCCESS; } /* * Add an IAADDR/PREFIX entry to an IA structure. */ isc_result_t ia_add_iasubopt(struct ia_xx *ia, struct iasubopt *iasubopt, const char *file, int line) { int max; struct iasubopt **new; /* * Grow our array if we need to. * * Note: we pick 4 as the increment, as that seems a reasonable * guess as to how many addresses/prefixes we might expect * on an interface. */ if (ia->max_iasubopt <= ia->num_iasubopt) { max = ia->max_iasubopt + 4; new = dmalloc(max * sizeof(struct iasubopt *), file, line); if (new == NULL) { return ISC_R_NOMEMORY; } memcpy(new, ia->iasubopt, ia->num_iasubopt * sizeof(struct iasubopt *)); ia->iasubopt = new; ia->max_iasubopt = max; } iasubopt_reference(&(ia->iasubopt[ia->num_iasubopt]), iasubopt, file, line); ia->num_iasubopt++; return ISC_R_SUCCESS; } /* * Remove an IAADDR/PREFIX entry to an IA structure. * * Note: if a suboption appears more than once, then only ONE will be removed. */ void ia_remove_iasubopt(struct ia_xx *ia, struct iasubopt *iasubopt, const char *file, int line) { int i, j; for (i=0; inum_iasubopt; i++) { if (ia->iasubopt[i] == iasubopt) { /* remove this sub option */ iasubopt_dereference(&(ia->iasubopt[i]), file, line); /* move remaining suboption pointers down one */ for (j=i+1; j < ia->num_iasubopt; j++) { ia->iasubopt[j-1] = ia->iasubopt[j]; } /* decrease our total count */ /* remove the back-reference in the suboption itself */ ia_dereference(&iasubopt->ia, file, line); ia->num_iasubopt--; return; } } log_error("%s(%d): IAADDR/PREFIX not in IA", file, line); } /* * Remove all addresses/prefixes from an IA. */ void ia_remove_all_lease(struct ia_xx *ia, const char *file, int line) { int i; for (i=0; inum_iasubopt; i++) { ia_dereference(&(ia->iasubopt[i]->ia), file, line); iasubopt_dereference(&(ia->iasubopt[i]), file, line); } ia->num_iasubopt = 0; } /* * Compare two IA. */ isc_boolean_t ia_equal(const struct ia_xx *a, const struct ia_xx *b) { isc_boolean_t found; int i, j; /* * Handle cases where one or both of the inputs is NULL. */ if (a == NULL) { if (b == NULL) { return ISC_TRUE; } else { return ISC_FALSE; } } /* * Check the type is the same. */ if (a->ia_type != b->ia_type) { return ISC_FALSE; } /* * Check the DUID is the same. */ if (a->iaid_duid.len != b->iaid_duid.len) { return ISC_FALSE; } if (memcmp(a->iaid_duid.data, b->iaid_duid.data, a->iaid_duid.len) != 0) { return ISC_FALSE; } /* * Make sure we have the same number of addresses/prefixes in each. */ if (a->num_iasubopt != b->num_iasubopt) { return ISC_FALSE; } /* * Check that each address/prefix is present in both. */ for (i=0; inum_iasubopt; i++) { found = ISC_FALSE; for (j=0; jnum_iasubopt; j++) { if (a->iasubopt[i]->plen != b->iasubopt[i]->plen) continue; if (memcmp(&(a->iasubopt[i]->addr), &(b->iasubopt[j]->addr), sizeof(struct in6_addr)) == 0) { found = ISC_TRUE; break; } } if (!found) { return ISC_FALSE; } } /* * These are the same in every way we care about. */ return ISC_TRUE; } /* * Helper function for lease heaps. * Makes the top of the heap the oldest lease. */ static isc_boolean_t lease_older(void *a, void *b) { struct iasubopt *la = (struct iasubopt *)a; struct iasubopt *lb = (struct iasubopt *)b; if (la->hard_lifetime_end_time == lb->hard_lifetime_end_time) { return difftime(la->soft_lifetime_end_time, lb->soft_lifetime_end_time) < 0; } else { return difftime(la->hard_lifetime_end_time, lb->hard_lifetime_end_time) < 0; } } /* * Helper function for lease address/prefix heaps. * Callback when an address's position in the heap changes. */ static void lease_index_changed(void *iasubopt, unsigned int new_heap_index) { ((struct iasubopt *)iasubopt)-> heap_index = new_heap_index; } /* * Create a new IPv6 lease pool structure. * * - pool must be a pointer to a (struct ipv6_pool *) pointer previously * initialized to NULL */ isc_result_t ipv6_pool_allocate(struct ipv6_pool **pool, u_int16_t type, const struct in6_addr *start_addr, int bits, int units, const char *file, int line) { struct ipv6_pool *tmp; if (pool == NULL) { log_error("%s(%d): NULL pointer reference", file, line); return DHCP_R_INVALIDARG; } if (*pool != NULL) { log_error("%s(%d): non-NULL pointer", file, line); return DHCP_R_INVALIDARG; } tmp = dmalloc(sizeof(*tmp), file, line); if (tmp == NULL) { return ISC_R_NOMEMORY; } tmp->refcnt = 1; tmp->pool_type = type; tmp->start_addr = *start_addr; tmp->bits = bits; tmp->units = units; if (!iasubopt_new_hash(&tmp->leases, DEFAULT_HASH_SIZE, file, line)) { dfree(tmp, file, line); return ISC_R_NOMEMORY; } if (isc_heap_create(dhcp_gbl_ctx.mctx, lease_older, lease_index_changed, 0, &(tmp->active_timeouts)) != ISC_R_SUCCESS) { iasubopt_free_hash_table(&(tmp->leases), file, line); dfree(tmp, file, line); return ISC_R_NOMEMORY; } if (isc_heap_create(dhcp_gbl_ctx.mctx, lease_older, lease_index_changed, 0, &(tmp->inactive_timeouts)) != ISC_R_SUCCESS) { isc_heap_destroy(&(tmp->active_timeouts)); iasubopt_free_hash_table(&(tmp->leases), file, line); dfree(tmp, file, line); return ISC_R_NOMEMORY; } *pool = tmp; return ISC_R_SUCCESS; } /* * Reference an IPv6 pool structure. * * - pool must be a pointer to a (struct pool *) pointer previously * initialized to NULL */ isc_result_t ipv6_pool_reference(struct ipv6_pool **pool, struct ipv6_pool *src, const char *file, int line) { if (pool == NULL) { log_error("%s(%d): NULL pointer reference", file, line); return DHCP_R_INVALIDARG; } if (*pool != NULL) { log_error("%s(%d): non-NULL pointer", file, line); return DHCP_R_INVALIDARG; } if (src == NULL) { log_error("%s(%d): NULL pointer reference", file, line); return DHCP_R_INVALIDARG; } *pool = src; src->refcnt++; return ISC_R_SUCCESS; } /* * Note: Each IAADDR/PREFIX in a pool is referenced by the pool. This is needed * to prevent the lease from being garbage collected out from under the * pool. * * The references are made from the hash and from the heap. The following * helper functions dereference these when a pool is destroyed. */ /* * Helper function for pool cleanup. * Dereference each of the hash entries in a pool. */ static isc_result_t dereference_hash_entry(const void *name, unsigned len, void *value) { struct iasubopt *iasubopt = (struct iasubopt *)value; iasubopt_dereference(&iasubopt, MDL); return ISC_R_SUCCESS; } /* * Helper function for pool cleanup. * Dereference each of the heap entries in a pool. */ static void dereference_heap_entry(void *value, void *dummy) { struct iasubopt *iasubopt = (struct iasubopt *)value; iasubopt_dereference(&iasubopt, MDL); } /* * Dereference an IPv6 pool structure. * * If it is the last reference, then the memory for the * structure is freed. */ isc_result_t ipv6_pool_dereference(struct ipv6_pool **pool, const char *file, int line) { struct ipv6_pool *tmp; if ((pool == NULL) || (*pool == NULL)) { log_error("%s(%d): NULL pointer", file, line); return DHCP_R_INVALIDARG; } tmp = *pool; *pool = NULL; tmp->refcnt--; if (tmp->refcnt < 0) { log_error("%s(%d): negative refcnt", file, line); tmp->refcnt = 0; } if (tmp->refcnt == 0) { iasubopt_hash_foreach(tmp->leases, dereference_hash_entry); iasubopt_free_hash_table(&(tmp->leases), file, line); isc_heap_foreach(tmp->active_timeouts, dereference_heap_entry, NULL); isc_heap_destroy(&(tmp->active_timeouts)); isc_heap_foreach(tmp->inactive_timeouts, dereference_heap_entry, NULL); isc_heap_destroy(&(tmp->inactive_timeouts)); dfree(tmp, file, line); } return ISC_R_SUCCESS; } /* * Create an address by hashing the input, and using that for * the non-network part. */ static void build_address6(struct in6_addr *addr, const struct in6_addr *net_start_addr, int net_bits, const struct data_string *input) { isc_md5_t ctx; int net_bytes; int i; char *str; const char *net_str; /* * Use MD5 to get a nice 128 bit hash of the input. * Yes, we know MD5 isn't cryptographically sound. * No, we don't care. */ isc_md5_init(&ctx); isc_md5_update(&ctx, input->data, input->len); isc_md5_final(&ctx, (unsigned char *)addr); /* * Copy the [0..128] network bits over. */ str = (char *)addr; net_str = (const char *)net_start_addr; net_bytes = net_bits / 8; for (i = 0; i < net_bytes; i++) { str[i] = net_str[i]; } switch (net_bits % 8) { case 1: str[i] = (str[i] & 0x7F) | (net_str[i] & 0x80); break; case 2: str[i] = (str[i] & 0x3F) | (net_str[i] & 0xC0); break; case 3: str[i] = (str[i] & 0x1F) | (net_str[i] & 0xE0); break; case 4: str[i] = (str[i] & 0x0F) | (net_str[i] & 0xF0); break; case 5: str[i] = (str[i] & 0x07) | (net_str[i] & 0xF8); break; case 6: str[i] = (str[i] & 0x03) | (net_str[i] & 0xFC); break; case 7: str[i] = (str[i] & 0x01) | (net_str[i] & 0xFE); break; } /* * Set the universal/local bit ("u bit") to zero for /64s. The * individual/group bit ("g bit") is unchanged, because the g-bit * has no meaning when the u-bit is cleared. */ if (net_bits == 64) str[8] &= ~0x02; } /* * Create a temporary address by a variant of RFC 4941 algo. * Note: this should not be used for prefixes shorter than 64 bits. */ static void build_temporary6(struct in6_addr *addr, const struct in6_addr *net_start_addr, int net_bits, const struct data_string *input) { static u_int32_t history[2]; static u_int32_t counter = 0; isc_md5_t ctx; unsigned char md[16]; /* * First time/time to reseed. * Please use a good pseudo-random generator here! */ if (counter == 0) { isc_random_get(&history[0]); isc_random_get(&history[1]); } /* * Use MD5 as recommended by RFC 4941. */ isc_md5_init(&ctx); isc_md5_update(&ctx, (unsigned char *)&history[0], 8UL); isc_md5_update(&ctx, input->data, input->len); isc_md5_final(&ctx, md); /* * Build the address. */ if (net_bits == 64) { memcpy(&addr->s6_addr[0], &net_start_addr->s6_addr[0], 8); memcpy(&addr->s6_addr[8], md, 8); addr->s6_addr[8] &= ~0x02; } else { int net_bytes; int i; char *str; const char *net_str; /* * Copy the [0..128] network bits over. */ str = (char *)addr; net_str = (const char *)net_start_addr; net_bytes = net_bits / 8; for (i = 0; i < net_bytes; i++) { str[i] = net_str[i]; } memcpy(str + net_bytes, md, 16 - net_bytes); switch (net_bits % 8) { case 1: str[i] = (str[i] & 0x7F) | (net_str[i] & 0x80); break; case 2: str[i] = (str[i] & 0x3F) | (net_str[i] & 0xC0); break; case 3: str[i] = (str[i] & 0x1F) | (net_str[i] & 0xE0); break; case 4: str[i] = (str[i] & 0x0F) | (net_str[i] & 0xF0); break; case 5: str[i] = (str[i] & 0x07) | (net_str[i] & 0xF8); break; case 6: str[i] = (str[i] & 0x03) | (net_str[i] & 0xFC); break; case 7: str[i] = (str[i] & 0x01) | (net_str[i] & 0xFE); break; } } /* * Save history for the next call. */ memcpy((unsigned char *)&history[0], md + 8, 8); counter++; } /* Reserved Subnet Router Anycast ::0:0:0:0. */ static struct in6_addr rtany; /* Reserved Subnet Anycasts ::fdff:ffff:ffff:ff80-::fdff:ffff:ffff:ffff. */ static struct in6_addr resany; /* * Create a lease for the given address and client duid. * * - pool must be a pointer to a (struct pool *) pointer previously * initialized to NULL * * Right now we simply hash the DUID, and if we get a collision, we hash * again until we find a free address. We try this a fixed number of times, * to avoid getting stuck in a loop (this is important on small pools * where we can run out of space). * * We return the number of attempts that it took to find an available * lease. This tells callers when a pool is are filling up, as * well as an indication of how full the pool is; statistically the * more full a pool is the more attempts must be made before finding * a free lease. Realistically this will only happen in very full * pools. * * We probably want different algorithms depending on the network size, in * the long term. */ isc_result_t create_lease6(struct ipv6_pool *pool, struct iasubopt **addr, unsigned int *attempts, const struct data_string *uid, time_t soft_lifetime_end_time) { struct data_string ds; struct in6_addr tmp; struct iasubopt *test_iaaddr; struct data_string new_ds; struct iasubopt *iaaddr; isc_result_t result; isc_boolean_t reserved_iid; static isc_boolean_t init_resiid = ISC_FALSE; /* * Fill the reserved IIDs. */ if (!init_resiid) { memset(&rtany, 0, 16); memset(&resany, 0, 8); resany.s6_addr[8] = 0xfd; memset(&resany.s6_addr[9], 0xff, 6); init_resiid = ISC_TRUE; } /* * Use the UID as our initial seed for the hash */ memset(&ds, 0, sizeof(ds)); data_string_copy(&ds, (struct data_string *)uid, MDL); *attempts = 0; for (;;) { /* * Give up at some point. */ if (++(*attempts) > 100) { data_string_forget(&ds, MDL); return ISC_R_NORESOURCES; } /* * Build a resource. */ switch (pool->pool_type) { case D6O_IA_NA: /* address */ build_address6(&tmp, &pool->start_addr, pool->bits, &ds); break; case D6O_IA_TA: /* temporary address */ build_temporary6(&tmp, &pool->start_addr, pool->bits, &ds); break; case D6O_IA_PD: /* prefix */ log_error("create_lease6: prefix pool."); return DHCP_R_INVALIDARG; default: log_error("create_lease6: untyped pool."); return DHCP_R_INVALIDARG; } /* * Avoid reserved interface IDs. (cf. RFC 5453) */ reserved_iid = ISC_FALSE; if (memcmp(&tmp.s6_addr[8], &rtany.s6_addr[8], 8) == 0) { reserved_iid = ISC_TRUE; } if (!reserved_iid && (memcmp(&tmp.s6_addr[8], &resany.s6_addr[8], 7) == 0) && ((tmp.s6_addr[15] & 0x80) == 0x80)) { reserved_iid = ISC_TRUE; } /* * If this address is not in use, we're happy with it */ test_iaaddr = NULL; if (!reserved_iid && (iasubopt_hash_lookup(&test_iaaddr, pool->leases, &tmp, sizeof(tmp), MDL) == 0)) { break; } if (test_iaaddr != NULL) iasubopt_dereference(&test_iaaddr, MDL); /* * Otherwise, we create a new input, adding the address */ memset(&new_ds, 0, sizeof(new_ds)); new_ds.len = ds.len + sizeof(tmp); if (!buffer_allocate(&new_ds.buffer, new_ds.len, MDL)) { data_string_forget(&ds, MDL); return ISC_R_NOMEMORY; } new_ds.data = new_ds.buffer->data; memcpy(new_ds.buffer->data, ds.data, ds.len); memcpy(new_ds.buffer->data + ds.len, &tmp, sizeof(tmp)); data_string_forget(&ds, MDL); data_string_copy(&ds, &new_ds, MDL); data_string_forget(&new_ds, MDL); } data_string_forget(&ds, MDL); /* * We're happy with the address, create an IAADDR * to hold it. */ iaaddr = NULL; result = iasubopt_allocate(&iaaddr, MDL); if (result != ISC_R_SUCCESS) { return result; } iaaddr->plen = 0; memcpy(&iaaddr->addr, &tmp, sizeof(iaaddr->addr)); /* * Add the lease to the pool (note state is free, not active?!). */ result = add_lease6(pool, iaaddr, soft_lifetime_end_time); if (result == ISC_R_SUCCESS) { iasubopt_reference(addr, iaaddr, MDL); } iasubopt_dereference(&iaaddr, MDL); return result; } /*! \file server/mdb6.c * * \brief Cleans up leases when reading from a lease file * * This function is only expected to be run when reading leases in from a file. * It checks to see if a lease already exists for the new leases's address. * We don't add expired leases to the structures when reading a lease file * which limits what can happen. We have two variables the owners of the leases * being the same or different and the new lease being active or non-active: * Owners active * same no remove old lease and its connections * same yes nothing to do, other code will update the structures. * diff no nothing to do * diff yes this combination shouldn't happen, we should only have a * single active lease per address at a time and that lease * should move to non-active before any other lease can * become active for that address. * Currently we delete the previous lease and pass an error * to the caller who should log an error. * * When we remove a lease we remove it from the hash table and active heap * (remember only active leases are in the structures at this time) for the * pool, and from the IA's array. If, after we've removed the pointer from * IA's array to the lease, the IA has no more pointers we remove it from * the appropriate hash table as well. * * \param[in] ia_table = the hash table for the IA * \param[in] pool = the pool to update * \param[in] lease = the new lease we want to add * \param[in] ia = the new ia we are building * * \return * ISC_R_SUCCESS = the incoming lease and any previous lease were in * an expected state - one of the first 3 options above. * If necessary the old lease was removed. * ISC_R_FAILURE = there is already an active lease for the address in * the incoming lease. This shouldn't happen if it does * flag an error for the caller to log. */ isc_result_t cleanup_lease6(ia_hash_t *ia_table, struct ipv6_pool *pool, struct iasubopt *lease, struct ia_xx *ia) { struct iasubopt *test_iasubopt, *tmp_iasubopt; struct ia_xx *old_ia; isc_result_t status = ISC_R_SUCCESS; test_iasubopt = NULL; old_ia = NULL; /* * Look up the address - if we don't find a lease * we don't need to do anything. */ if (iasubopt_hash_lookup(&test_iasubopt, pool->leases, &lease->addr, sizeof(lease->addr), MDL) == 0) { return (ISC_R_SUCCESS); } if (test_iasubopt->ia == NULL) { /* no old ia, no work to do */ iasubopt_dereference(&test_iasubopt, MDL); return (status); } ia_reference(&old_ia, test_iasubopt->ia, MDL); if ((old_ia->iaid_duid.len == ia->iaid_duid.len) && (memcmp((unsigned char *)ia->iaid_duid.data, (unsigned char *)old_ia->iaid_duid.data, ia->iaid_duid.len) == 0)) { /* same IA */ if ((lease->state == FTS_ACTIVE) || (lease->state == FTS_ABANDONED)) { /* still active, no need to delete */ goto cleanup; } } else { /* different IA */ if ((lease->state != FTS_ACTIVE) && (lease->state != FTS_ABANDONED)) { /* new lease isn't active, no work */ goto cleanup; } /* * We appear to have two active leases, this shouldn't happen. * Before a second lease can be set to active the first lease * should be set to inactive (released, expired etc). For now * delete the previous lease and indicate a failure to the * caller so it can generate a warning. * In the future we may try and determine which is the better * lease to keep. */ status = ISC_R_FAILURE; } /* * Remove the old lease from the active heap and from the hash table * then remove the lease from the IA and clean up the IA if necessary. */ isc_heap_delete(pool->active_timeouts, test_iasubopt->heap_index); pool->num_active--; iasubopt_hash_delete(pool->leases, &test_iasubopt->addr, sizeof(test_iasubopt->addr), MDL); ia_remove_iasubopt(old_ia, test_iasubopt, MDL); if (old_ia->num_iasubopt <= 0) { ia_hash_delete(ia_table, (unsigned char *)old_ia->iaid_duid.data, old_ia->iaid_duid.len, MDL); } /* * We derefenrece the subopt here as we've just removed it from * the hash table in the pool. We need to make a copy as we * need to derefernece it again later. */ tmp_iasubopt = test_iasubopt; iasubopt_dereference(&tmp_iasubopt, MDL); cleanup: ia_dereference(&old_ia, MDL); /* * Clean up the reference, this is in addition to the deference * above after removing the entry from the hash table */ iasubopt_dereference(&test_iasubopt, MDL); return (status); } /* * Put a lease in the pool directly. This is intended to be used when * loading leases from the file. */ isc_result_t add_lease6(struct ipv6_pool *pool, struct iasubopt *lease, time_t valid_lifetime_end_time) { isc_result_t insert_result; struct iasubopt *test_iasubopt; struct iasubopt *tmp_iasubopt; /* If a state was not assigned by the caller, assume active. */ if (lease->state == 0) lease->state = FTS_ACTIVE; ipv6_pool_reference(&lease->ipv6_pool, pool, MDL); /* * If this IAADDR/PREFIX is already in our structures, remove the * old one. */ test_iasubopt = NULL; if (iasubopt_hash_lookup(&test_iasubopt, pool->leases, &lease->addr, sizeof(lease->addr), MDL)) { /* XXX: we should probably ask the lease what heap it is on * (as a consistency check). * XXX: we should probably have one function to "put this lease * on its heap" rather than doing these if's everywhere. If * you add more states to this list, don't. */ if ((test_iasubopt->state == FTS_ACTIVE) || (test_iasubopt->state == FTS_ABANDONED)) { isc_heap_delete(pool->active_timeouts, test_iasubopt->heap_index); pool->num_active--; } else { isc_heap_delete(pool->inactive_timeouts, test_iasubopt->heap_index); pool->num_inactive--; } iasubopt_hash_delete(pool->leases, &test_iasubopt->addr, sizeof(test_iasubopt->addr), MDL); /* * We're going to do a bit of evil trickery here. * * We need to dereference the entry once to remove our * current reference (in test_iasubopt), and then one * more time to remove the reference left when the * address was added to the pool before. */ tmp_iasubopt = test_iasubopt; iasubopt_dereference(&test_iasubopt, MDL); iasubopt_dereference(&tmp_iasubopt, MDL); } /* * Add IAADDR/PREFIX to our structures. */ tmp_iasubopt = NULL; iasubopt_reference(&tmp_iasubopt, lease, MDL); if ((tmp_iasubopt->state == FTS_ACTIVE) || (tmp_iasubopt->state == FTS_ABANDONED)) { tmp_iasubopt->hard_lifetime_end_time = valid_lifetime_end_time; iasubopt_hash_add(pool->leases, &tmp_iasubopt->addr, sizeof(tmp_iasubopt->addr), lease, MDL); insert_result = isc_heap_insert(pool->active_timeouts, tmp_iasubopt); if (insert_result == ISC_R_SUCCESS) pool->num_active++; } else { tmp_iasubopt->soft_lifetime_end_time = valid_lifetime_end_time; insert_result = isc_heap_insert(pool->inactive_timeouts, tmp_iasubopt); if (insert_result == ISC_R_SUCCESS) pool->num_inactive++; } if (insert_result != ISC_R_SUCCESS) { iasubopt_hash_delete(pool->leases, &lease->addr, sizeof(lease->addr), MDL); iasubopt_dereference(&tmp_iasubopt, MDL); return insert_result; } /* * Note: we intentionally leave tmp_iasubopt referenced; there * is a reference in the heap/hash, after all. */ return ISC_R_SUCCESS; } /* * Determine if an address is present in a pool or not. */ isc_boolean_t lease6_exists(const struct ipv6_pool *pool, const struct in6_addr *addr) { struct iasubopt *test_iaaddr; test_iaaddr = NULL; if (iasubopt_hash_lookup(&test_iaaddr, pool->leases, (void *)addr, sizeof(*addr), MDL)) { iasubopt_dereference(&test_iaaddr, MDL); return ISC_TRUE; } else { return ISC_FALSE; } } /*! * * \brief Check if address is available to a lease * * Determine if the address in the lease is available to that * lease. Either the address isn't in use or it is in use * but by that lease. * * \param[in] lease = lease to check * * \return * ISC_TRUE = The lease is allowed to use that address * ISC_FALSE = The lease isn't allowed to use that address */ isc_boolean_t lease6_usable(struct iasubopt *lease) { struct iasubopt *test_iaaddr; isc_boolean_t status = ISC_TRUE; test_iaaddr = NULL; if (iasubopt_hash_lookup(&test_iaaddr, lease->ipv6_pool->leases, (void *)&lease->addr, sizeof(lease->addr), MDL)) { if (test_iaaddr != lease) { status = ISC_FALSE; } iasubopt_dereference(&test_iaaddr, MDL); } return (status); } /* * Put the lease on our active pool. */ static isc_result_t move_lease_to_active(struct ipv6_pool *pool, struct iasubopt *lease) { isc_result_t insert_result; int old_heap_index; old_heap_index = lease->heap_index; insert_result = isc_heap_insert(pool->active_timeouts, lease); if (insert_result == ISC_R_SUCCESS) { iasubopt_hash_add(pool->leases, &lease->addr, sizeof(lease->addr), lease, MDL); isc_heap_delete(pool->inactive_timeouts, old_heap_index); pool->num_active++; pool->num_inactive--; lease->state = FTS_ACTIVE; } return insert_result; } /* * Renew an lease in the pool. * * To do this, first set the new hard_lifetime_end_time for the resource, * and then invoke renew_lease6() on it. * * WARNING: lease times must only be extended, never reduced!!! */ isc_result_t renew_lease6(struct ipv6_pool *pool, struct iasubopt *lease) { /* * If we're already active, then we can just move our expiration * time down the heap. * * If we're abandoned then we are already on the active list * but we need to retag the lease and move our expiration * from infinite to the current value * * Otherwise, we have to move from the inactive heap to the * active heap. */ if (lease->state == FTS_ACTIVE) { isc_heap_decreased(pool->active_timeouts, lease->heap_index); return ISC_R_SUCCESS; } else if (lease->state == FTS_ABANDONED) { char tmp_addr[INET6_ADDRSTRLEN]; lease->state = FTS_ACTIVE; isc_heap_increased(pool->active_timeouts, lease->heap_index); log_info("Reclaiming previously abandoned address %s", inet_ntop(AF_INET6, &(lease->addr), tmp_addr, sizeof(tmp_addr))); return ISC_R_SUCCESS; } else { return move_lease_to_active(pool, lease); } } /* * Put the lease on our inactive pool, with the specified state. */ static isc_result_t move_lease_to_inactive(struct ipv6_pool *pool, struct iasubopt *lease, binding_state_t state) { isc_result_t insert_result; int old_heap_index; old_heap_index = lease->heap_index; insert_result = isc_heap_insert(pool->inactive_timeouts, lease); if (insert_result == ISC_R_SUCCESS) { #if defined (NSUPDATE) /* Process events upon expiration. */ if (pool->pool_type != D6O_IA_PD) { (void) ddns_removals(NULL, lease, NULL, ISC_FALSE); } #endif /* Binding scopes are no longer valid after expiry or * release. */ if (lease->scope != NULL) { binding_scope_dereference(&lease->scope, MDL); } iasubopt_hash_delete(pool->leases, &lease->addr, sizeof(lease->addr), MDL); isc_heap_delete(pool->active_timeouts, old_heap_index); lease->state = state; pool->num_active--; pool->num_inactive++; } return insert_result; } /* * Expire the oldest lease if it's lifetime_end_time is * older than the given time. * * - leasep must be a pointer to a (struct iasubopt *) pointer previously * initialized to NULL * * On return leasep has a reference to the removed entry. It is left * pointing to NULL if the oldest lease has not expired. */ isc_result_t expire_lease6(struct iasubopt **leasep, struct ipv6_pool *pool, time_t now) { struct iasubopt *tmp; isc_result_t result; if (leasep == NULL) { log_error("%s(%d): NULL pointer reference", MDL); return DHCP_R_INVALIDARG; } if (*leasep != NULL) { log_error("%s(%d): non-NULL pointer", MDL); return DHCP_R_INVALIDARG; } if (pool->num_active > 0) { tmp = (struct iasubopt *) isc_heap_element(pool->active_timeouts, 1); if (now > tmp->hard_lifetime_end_time) { result = move_lease_to_inactive(pool, tmp, FTS_EXPIRED); if (result == ISC_R_SUCCESS) { iasubopt_reference(leasep, tmp, MDL); } return result; } } return ISC_R_SUCCESS; } /* * For a declined lease, leave it on the "active" pool, but mark * it as declined. Give it an infinite (well, really long) life. */ isc_result_t decline_lease6(struct ipv6_pool *pool, struct iasubopt *lease) { isc_result_t result; if ((lease->state != FTS_ACTIVE) && (lease->state != FTS_ABANDONED)) { result = move_lease_to_active(pool, lease); if (result != ISC_R_SUCCESS) { return result; } } lease->state = FTS_ABANDONED; lease->hard_lifetime_end_time = MAX_TIME; isc_heap_decreased(pool->active_timeouts, lease->heap_index); return ISC_R_SUCCESS; } /* * Put the returned lease on our inactive pool. */ isc_result_t release_lease6(struct ipv6_pool *pool, struct iasubopt *lease) { if (lease->state == FTS_ACTIVE) { return move_lease_to_inactive(pool, lease, FTS_RELEASED); } else { return ISC_R_SUCCESS; } } /* * Create a prefix by hashing the input, and using that for * the part subject to allocation. */ static void build_prefix6(struct in6_addr *pref, const struct in6_addr *net_start_pref, int pool_bits, int pref_bits, const struct data_string *input) { isc_md5_t ctx; int net_bytes; int i; char *str; const char *net_str; /* * Use MD5 to get a nice 128 bit hash of the input. * Yes, we know MD5 isn't cryptographically sound. * No, we don't care. */ isc_md5_init(&ctx); isc_md5_update(&ctx, input->data, input->len); isc_md5_final(&ctx, (unsigned char *)pref); /* * Copy the network bits over. */ str = (char *)pref; net_str = (const char *)net_start_pref; net_bytes = pool_bits / 8; for (i = 0; i < net_bytes; i++) { str[i] = net_str[i]; } i = net_bytes; switch (pool_bits % 8) { case 1: str[i] = (str[i] & 0x7F) | (net_str[i] & 0x80); break; case 2: str[i] = (str[i] & 0x3F) | (net_str[i] & 0xC0); break; case 3: str[i] = (str[i] & 0x1F) | (net_str[i] & 0xE0); break; case 4: str[i] = (str[i] & 0x0F) | (net_str[i] & 0xF0); break; case 5: str[i] = (str[i] & 0x07) | (net_str[i] & 0xF8); break; case 6: str[i] = (str[i] & 0x03) | (net_str[i] & 0xFC); break; case 7: str[i] = (str[i] & 0x01) | (net_str[i] & 0xFE); break; } /* * Zero the remaining bits. */ net_bytes = pref_bits / 8; for (i=net_bytes+1; i<16; i++) { str[i] = 0; } i = net_bytes; switch (pref_bits % 8) { case 0: str[i] &= 0; break; case 1: str[i] &= 0x80; break; case 2: str[i] &= 0xC0; break; case 3: str[i] &= 0xE0; break; case 4: str[i] &= 0xF0; break; case 5: str[i] &= 0xF8; break; case 6: str[i] &= 0xFC; break; case 7: str[i] &= 0xFE; break; } } /* * Create a lease for the given prefix and client duid. * * - pool must be a pointer to a (struct pool *) pointer previously * initialized to NULL * * Right now we simply hash the DUID, and if we get a collision, we hash * again until we find a free prefix. We try this a fixed number of times, * to avoid getting stuck in a loop (this is important on small pools * where we can run out of space). * * We return the number of attempts that it took to find an available * prefix. This tells callers when a pool is are filling up, as * well as an indication of how full the pool is; statistically the * more full a pool is the more attempts must be made before finding * a free prefix. Realistically this will only happen in very full * pools. * * We probably want different algorithms depending on the network size, in * the long term. */ isc_result_t create_prefix6(struct ipv6_pool *pool, struct iasubopt **pref, unsigned int *attempts, const struct data_string *uid, time_t soft_lifetime_end_time) { struct data_string ds; struct in6_addr tmp; struct iasubopt *test_iapref; struct data_string new_ds; struct iasubopt *iapref; isc_result_t result; /* * Use the UID as our initial seed for the hash */ memset(&ds, 0, sizeof(ds)); data_string_copy(&ds, (struct data_string *)uid, MDL); *attempts = 0; for (;;) { /* * Give up at some point. */ if (++(*attempts) > 10) { data_string_forget(&ds, MDL); return ISC_R_NORESOURCES; } /* * Build a prefix */ build_prefix6(&tmp, &pool->start_addr, pool->bits, pool->units, &ds); /* * If this prefix is not in use, we're happy with it */ test_iapref = NULL; if (iasubopt_hash_lookup(&test_iapref, pool->leases, &tmp, sizeof(tmp), MDL) == 0) { break; } iasubopt_dereference(&test_iapref, MDL); /* * Otherwise, we create a new input, adding the prefix */ memset(&new_ds, 0, sizeof(new_ds)); new_ds.len = ds.len + sizeof(tmp); if (!buffer_allocate(&new_ds.buffer, new_ds.len, MDL)) { data_string_forget(&ds, MDL); return ISC_R_NOMEMORY; } new_ds.data = new_ds.buffer->data; memcpy(new_ds.buffer->data, ds.data, ds.len); memcpy(new_ds.buffer->data + ds.len, &tmp, sizeof(tmp)); data_string_forget(&ds, MDL); data_string_copy(&ds, &new_ds, MDL); data_string_forget(&new_ds, MDL); } data_string_forget(&ds, MDL); /* * We're happy with the prefix, create an IAPREFIX * to hold it. */ iapref = NULL; result = iasubopt_allocate(&iapref, MDL); if (result != ISC_R_SUCCESS) { return result; } iapref->plen = (u_int8_t)pool->units; memcpy(&iapref->addr, &tmp, sizeof(iapref->addr)); /* * Add the prefix to the pool (note state is free, not active?!). */ result = add_lease6(pool, iapref, soft_lifetime_end_time); if (result == ISC_R_SUCCESS) { iasubopt_reference(pref, iapref, MDL); } iasubopt_dereference(&iapref, MDL); return result; } /* * Determine if a prefix is present in a pool or not. */ isc_boolean_t prefix6_exists(const struct ipv6_pool *pool, const struct in6_addr *pref, u_int8_t plen) { struct iasubopt *test_iapref; if ((int)plen != pool->units) return ISC_FALSE; test_iapref = NULL; if (iasubopt_hash_lookup(&test_iapref, pool->leases, (void *)pref, sizeof(*pref), MDL)) { iasubopt_dereference(&test_iapref, MDL); return ISC_TRUE; } else { return ISC_FALSE; } } /* * Mark an IPv6 address/prefix as unavailable from a pool. * * This is used for host entries and the addresses of the server itself. */ isc_result_t mark_lease_unavailable(struct ipv6_pool *pool, const struct in6_addr *addr) { struct iasubopt *dummy_iasubopt; isc_result_t result; dummy_iasubopt = NULL; result = iasubopt_allocate(&dummy_iasubopt, MDL); if (result == ISC_R_SUCCESS) { dummy_iasubopt->addr = *addr; iasubopt_hash_add(pool->leases, &dummy_iasubopt->addr, sizeof(*addr), dummy_iasubopt, MDL); } return result; } /* * Add a pool. */ isc_result_t add_ipv6_pool(struct ipv6_pool *pool) { struct ipv6_pool **new_pools; new_pools = dmalloc(sizeof(struct ipv6_pool *) * (num_pools+1), MDL); if (new_pools == NULL) { return ISC_R_NOMEMORY; } if (num_pools > 0) { memcpy(new_pools, pools, sizeof(struct ipv6_pool *) * num_pools); dfree(pools, MDL); } pools = new_pools; pools[num_pools] = NULL; ipv6_pool_reference(&pools[num_pools], pool, MDL); num_pools++; return ISC_R_SUCCESS; } static void cleanup_old_expired(struct ipv6_pool *pool) { struct iasubopt *tmp; struct ia_xx *ia; struct ia_xx *ia_active; unsigned char *tmpd; time_t timeout; while (pool->num_inactive > 0) { tmp = (struct iasubopt *) isc_heap_element(pool->inactive_timeouts, 1); if (tmp->hard_lifetime_end_time != 0) { timeout = tmp->hard_lifetime_end_time; timeout += EXPIRED_IPV6_CLEANUP_TIME; } else { timeout = tmp->soft_lifetime_end_time; } if (cur_time < timeout) { break; } isc_heap_delete(pool->inactive_timeouts, tmp->heap_index); pool->num_inactive--; if (tmp->ia != NULL) { /* * Check to see if this IA is in an active list, * but has no remaining resources. If so, remove it * from the active list. */ ia = NULL; ia_reference(&ia, tmp->ia, MDL); ia_remove_iasubopt(ia, tmp, MDL); ia_active = NULL; tmpd = (unsigned char *)ia->iaid_duid.data; if ((ia->ia_type == D6O_IA_NA) && (ia->num_iasubopt <= 0) && (ia_hash_lookup(&ia_active, ia_na_active, tmpd, ia->iaid_duid.len, MDL) == 0) && (ia_active == ia)) { ia_hash_delete(ia_na_active, tmpd, ia->iaid_duid.len, MDL); } if ((ia->ia_type == D6O_IA_TA) && (ia->num_iasubopt <= 0) && (ia_hash_lookup(&ia_active, ia_ta_active, tmpd, ia->iaid_duid.len, MDL) == 0) && (ia_active == ia)) { ia_hash_delete(ia_ta_active, tmpd, ia->iaid_duid.len, MDL); } if ((ia->ia_type == D6O_IA_PD) && (ia->num_iasubopt <= 0) && (ia_hash_lookup(&ia_active, ia_pd_active, tmpd, ia->iaid_duid.len, MDL) == 0) && (ia_active == ia)) { ia_hash_delete(ia_pd_active, tmpd, ia->iaid_duid.len, MDL); } ia_dereference(&ia, MDL); } iasubopt_dereference(&tmp, MDL); } } static void lease_timeout_support(void *vpool) { struct ipv6_pool *pool; struct iasubopt *lease; pool = (struct ipv6_pool *)vpool; for (;;) { /* * Get the next lease scheduled to expire. * * Note that if there are no leases in the pool, * expire_lease6() will return ISC_R_SUCCESS with * a NULL lease. * * expire_lease6() will call move_lease_to_inactive() which * calls ddns_removals() do we want that on the standard * expiration timer or a special 'depref' timer? Original * query from DH, moved here by SAR. */ lease = NULL; if (expire_lease6(&lease, pool, cur_time) != ISC_R_SUCCESS) { break; } if (lease == NULL) { break; } write_ia(lease->ia); iasubopt_dereference(&lease, MDL); } /* * If appropriate commit and rotate the lease file * As commit_leases_timed() checks to see if we've done any writes * we don't bother tracking if this function called write _ia */ (void) commit_leases_timed(); /* * Do some cleanup of our expired leases. */ cleanup_old_expired(pool); /* * Schedule next round of expirations. */ schedule_lease_timeout(pool); } /* * For a given pool, add a timer that will remove the next * lease to expire. */ void schedule_lease_timeout(struct ipv6_pool *pool) { struct iasubopt *tmp; time_t timeout; time_t next_timeout; struct timeval tv; next_timeout = MAX_TIME; if (pool->num_active > 0) { tmp = (struct iasubopt *) isc_heap_element(pool->active_timeouts, 1); if (tmp->hard_lifetime_end_time < next_timeout) { next_timeout = tmp->hard_lifetime_end_time + 1; } } if (pool->num_inactive > 0) { tmp = (struct iasubopt *) isc_heap_element(pool->inactive_timeouts, 1); if (tmp->hard_lifetime_end_time != 0) { timeout = tmp->hard_lifetime_end_time; timeout += EXPIRED_IPV6_CLEANUP_TIME; } else { timeout = tmp->soft_lifetime_end_time + 1; } if (timeout < next_timeout) { next_timeout = timeout; } } if (next_timeout < MAX_TIME) { tv.tv_sec = next_timeout; tv.tv_usec = 0; add_timeout(&tv, lease_timeout_support, pool, (tvref_t)ipv6_pool_reference, (tvunref_t)ipv6_pool_dereference); } } /* * Schedule timeouts across all pools. */ void schedule_all_ipv6_lease_timeouts(void) { int i; for (i=0; i 128)) { log_fatal("ipv6_network_portion: bits %d not between 0 and 128", bits); } /* * Copy our address portion. */ *result = *addr; addrp = ((unsigned char *)result) + 15; /* * Zero out masked portion. */ mask_bits = 128 - bits; bytes = mask_bits / 8; extra_bits = mask_bits % 8; for (i=0; ibits); if (memcmp(&tmp, &pool->start_addr, sizeof(tmp)) == 0) { return ISC_TRUE; } else { return ISC_FALSE; } } /* * Find the pool that contains the given address. * * - pool must be a pointer to a (struct ipv6_pool *) pointer previously * initialized to NULL */ isc_result_t find_ipv6_pool(struct ipv6_pool **pool, u_int16_t type, const struct in6_addr *addr) { int i; if (pool == NULL) { log_error("%s(%d): NULL pointer reference", MDL); return DHCP_R_INVALIDARG; } if (*pool != NULL) { log_error("%s(%d): non-NULL pointer", MDL); return DHCP_R_INVALIDARG; } for (i=0; ipool_type != type) continue; if (ipv6_in_pool(addr, pools[i])) { ipv6_pool_reference(pool, pools[i], MDL); return ISC_R_SUCCESS; } } return ISC_R_NOTFOUND; } /* * Helper function for the various functions that act across all * pools. */ static isc_result_t change_leases(struct ia_xx *ia, isc_result_t (*change_func)(struct ipv6_pool *, struct iasubopt *)) { isc_result_t retval; isc_result_t renew_retval; struct ipv6_pool *pool; struct in6_addr *addr; int i; retval = ISC_R_SUCCESS; for (i=0; inum_iasubopt; i++) { pool = NULL; addr = &ia->iasubopt[i]->addr; if (find_ipv6_pool(&pool, ia->ia_type, addr) == ISC_R_SUCCESS) { renew_retval = change_func(pool, ia->iasubopt[i]); if (renew_retval != ISC_R_SUCCESS) { retval = renew_retval; } } /* XXXsk: should we warn if we don't find a pool? */ } return retval; } /* * Renew all leases in an IA from all pools. * * The new hard_lifetime_end_time should be updated for the addresses/prefixes. * * WARNING: lease times must only be extended, never reduced!!! */ isc_result_t renew_leases(struct ia_xx *ia) { return change_leases(ia, renew_lease6); } /* * Release all leases in an IA from all pools. */ isc_result_t release_leases(struct ia_xx *ia) { return change_leases(ia, release_lease6); } /* * Decline all leases in an IA from all pools. */ isc_result_t decline_leases(struct ia_xx *ia) { return change_leases(ia, decline_lease6); } #ifdef DHCPv6 /* * Helper function to output leases. */ static int write_error; static isc_result_t write_ia_leases(const void *name, unsigned len, void *value) { struct ia_xx *ia = (struct ia_xx *)value; if (!write_error) { if (!write_ia(ia)) { write_error = 1; } } return ISC_R_SUCCESS; } /* * Write all DHCPv6 information. */ int write_leases6(void) { write_error = 0; write_server_duid(); ia_hash_foreach(ia_na_active, write_ia_leases); if (write_error) { return 0; } ia_hash_foreach(ia_ta_active, write_ia_leases); if (write_error) { return 0; } ia_hash_foreach(ia_pd_active, write_ia_leases); if (write_error) { return 0; } return 1; } #endif /* DHCPv6 */ static isc_result_t mark_hosts_unavailable_support(const void *name, unsigned len, void *value) { struct host_decl *h; struct data_string fixed_addr; struct in6_addr addr; struct ipv6_pool *p; h = (struct host_decl *)value; /* * If the host has no address, we don't need to mark anything. */ if (h->fixed_addr == NULL) { return ISC_R_SUCCESS; } /* * Evaluate the fixed address. */ memset(&fixed_addr, 0, sizeof(fixed_addr)); if (!evaluate_option_cache(&fixed_addr, NULL, NULL, NULL, NULL, NULL, &global_scope, h->fixed_addr, MDL)) { log_error("mark_hosts_unavailable: " "error evaluating host address."); return ISC_R_SUCCESS; } if (fixed_addr.len != 16) { log_error("mark_hosts_unavailable: " "host address is not 128 bits."); return ISC_R_SUCCESS; } memcpy(&addr, fixed_addr.data, 16); data_string_forget(&fixed_addr, MDL); /* * Find the pool holding this host, and mark the address. * (I suppose it is arguably valid to have a host that does not * sit in any pool.) */ p = NULL; if (find_ipv6_pool(&p, D6O_IA_NA, &addr) == ISC_R_SUCCESS) { mark_lease_unavailable(p, &addr); ipv6_pool_dereference(&p, MDL); } if (find_ipv6_pool(&p, D6O_IA_TA, &addr) == ISC_R_SUCCESS) { mark_lease_unavailable(p, &addr); ipv6_pool_dereference(&p, MDL); } return ISC_R_SUCCESS; } void mark_hosts_unavailable(void) { hash_foreach(host_name_hash, mark_hosts_unavailable_support); } static isc_result_t mark_phosts_unavailable_support(const void *name, unsigned len, void *value) { struct host_decl *h; struct iaddrcidrnetlist *l; struct in6_addr pref; struct ipv6_pool *p; h = (struct host_decl *)value; /* * If the host has no prefix, we don't need to mark anything. */ if (h->fixed_prefix == NULL) { return ISC_R_SUCCESS; } /* * Get the fixed prefixes. */ for (l = h->fixed_prefix; l != NULL; l = l->next) { if (l->cidrnet.lo_addr.len != 16) { continue; } memcpy(&pref, l->cidrnet.lo_addr.iabuf, 16); /* * Find the pool holding this host, and mark the prefix. * (I suppose it is arguably valid to have a host that does not * sit in any pool.) */ p = NULL; if (find_ipv6_pool(&p, D6O_IA_PD, &pref) != ISC_R_SUCCESS) { continue; } if (l->cidrnet.bits != p->units) { ipv6_pool_dereference(&p, MDL); continue; } mark_lease_unavailable(p, &pref); ipv6_pool_dereference(&p, MDL); } return ISC_R_SUCCESS; } void mark_phosts_unavailable(void) { hash_foreach(host_name_hash, mark_phosts_unavailable_support); } void mark_interfaces_unavailable(void) { struct interface_info *ip; int i; struct ipv6_pool *p; ip = interfaces; while (ip != NULL) { for (i=0; iv6address_count; i++) { p = NULL; if (find_ipv6_pool(&p, D6O_IA_NA, &ip->v6addresses[i]) == ISC_R_SUCCESS) { mark_lease_unavailable(p, &ip->v6addresses[i]); ipv6_pool_dereference(&p, MDL); } if (find_ipv6_pool(&p, D6O_IA_TA, &ip->v6addresses[i]) == ISC_R_SUCCESS) { mark_lease_unavailable(p, &ip->v6addresses[i]); ipv6_pool_dereference(&p, MDL); } } ip = ip->next; } } #ifdef UNIT_TEST #include int main(int argc, char *argv[]) { struct iasubopt *iaaddr; struct iasubopt *iaaddr_copy; u_int32_t iaid; struct ia_xx *ia_na; struct ia_xx *ia_na_copy; int i; struct in6_addr addr; struct ipv6_pool *pool; struct ipv6_pool *pool_copy; char addr_buf[INET6_ADDRSTRLEN]; char *uid; struct data_string ds; struct iasubopt *expired_iaaddr; unsigned int attempts; /* * Test 0: Basic iaaddr manipulation. */ iaaddr = NULL; if (iasubopt_allocate(&iaaddr, MDL) != ISC_R_SUCCESS) { printf("ERROR: iasubopt_allocate() %s:%d\n", MDL); return 1; } if (iaaddr->state != FTS_FREE) { printf("ERROR: bad state %s:%d\n", MDL); return 1; } if (iaaddr->heap_index != -1) { printf("ERROR: bad heap_index %s:%d\n", MDL); return 1; } iaaddr_copy = NULL; if (iasubopt_reference(&iaaddr_copy, iaaddr, MDL) != ISC_R_SUCCESS) { printf("ERROR: iasubopt_reference() %s:%d\n", MDL); return 1; } if (iasubopt_dereference(&iaaddr, MDL) != ISC_R_SUCCESS) { printf("ERROR: iasubopt_reference() %s:%d\n", MDL); return 1; } if (iasubopt_dereference(&iaaddr_copy, MDL) != ISC_R_SUCCESS) { printf("ERROR: iasubopt_reference() %s:%d\n", MDL); return 1; } /* * Test 1: Error iaaddr manipulation. */ /* bogus allocate arguments */ if (iasubopt_allocate(NULL, MDL) != DHCP_R_INVALIDARG) { printf("ERROR: iasubopt_allocate() %s:%d\n", MDL); return 1; } iaaddr = (struct iasubopt *)1; if (iasubopt_allocate(&iaaddr, MDL) != DHCP_R_INVALIDARG) { printf("ERROR: iasubopt_allocate() %s:%d\n", MDL); return 1; } /* bogus reference arguments */ iaaddr = NULL; if (iasubopt_allocate(&iaaddr, MDL) != ISC_R_SUCCESS) { printf("ERROR: iasubopt_allocate() %s:%d\n", MDL); return 1; } if (iasubopt_reference(NULL, iaaddr, MDL) != DHCP_R_INVALIDARG) { printf("ERROR: iasubopt_reference() %s:%d\n", MDL); return 1; } iaaddr_copy = (struct iasubopt *)1; if (iasubopt_reference(&iaaddr_copy, iaaddr, MDL) != DHCP_R_INVALIDARG) { printf("ERROR: iasubopt_reference() %s:%d\n", MDL); return 1; } iaaddr_copy = NULL; if (iasubopt_reference(&iaaddr_copy, NULL, MDL) != DHCP_R_INVALIDARG) { printf("ERROR: iasubopt_reference() %s:%d\n", MDL); return 1; } if (iasubopt_dereference(&iaaddr, MDL) != ISC_R_SUCCESS) { printf("ERROR: iasubopt_reference() %s:%d\n", MDL); return 1; } /* bogus dereference arguments */ if (iasubopt_dereference(NULL, MDL) != DHCP_R_INVALIDARG) { printf("ERROR: iasubopt_dereference() %s:%d\n", MDL); return 1; } iaaddr = NULL; if (iasubopt_dereference(&iaaddr, MDL) != DHCP_R_INVALIDARG) { printf("ERROR: iasubopt_dereference() %s:%d\n", MDL); return 1; } /* * Test 2: Basic ia_na manipulation. */ iaid = 666; ia_na = NULL; if (ia_allocate(&ia_na, iaid, "TestDUID", 8, MDL) != ISC_R_SUCCESS) { printf("ERROR: ia_allocate() %s:%d\n", MDL); return 1; } if (memcmp(ia_na->iaid_duid.data, &iaid, sizeof(iaid)) != 0) { printf("ERROR: bad IAID_DUID %s:%d\n", MDL); return 1; } if (memcmp(ia_na->iaid_duid.data+sizeof(iaid), "TestDUID", 8) != 0) { printf("ERROR: bad IAID_DUID %s:%d\n", MDL); return 1; } if (ia_na->num_iasubopt != 0) { printf("ERROR: bad num_iasubopt %s:%d\n", MDL); return 1; } ia_na_copy = NULL; if (ia_reference(&ia_na_copy, ia_na, MDL) != ISC_R_SUCCESS) { printf("ERROR: ia_reference() %s:%d\n", MDL); return 1; } iaaddr = NULL; if (iasubopt_allocate(&iaaddr, MDL) != ISC_R_SUCCESS) { printf("ERROR: iasubopt_allocate() %s:%d\n", MDL); return 1; } if (ia_add_iasubopt(ia_na, iaaddr, MDL) != ISC_R_SUCCESS) { printf("ERROR: ia_add_iasubopt() %s:%d\n", MDL); return 1; } ia_remove_iasubopt(ia_na, iaaddr, MDL); if (iasubopt_dereference(&iaaddr, MDL) != ISC_R_SUCCESS) { printf("ERROR: iasubopt_reference() %s:%d\n", MDL); return 1; } if (ia_dereference(&ia_na, MDL) != ISC_R_SUCCESS) { printf("ERROR: ia_dereference() %s:%d\n", MDL); return 1; } if (ia_dereference(&ia_na_copy, MDL) != ISC_R_SUCCESS) { printf("ERROR: ia_dereference() %s:%d\n", MDL); return 1; } /* * Test 3: lots of iaaddr in our ia_na */ /* lots of iaaddr that we delete */ iaid = 666; ia_na = NULL; if (ia_allocate(&ia_na, iaid, "TestDUID", 8, MDL) != ISC_R_SUCCESS) { printf("ERROR: ia_allocate() %s:%d\n", MDL); return 1; } for (i=0; i<100; i++) { iaaddr = NULL; if (iasubopt_allocate(&iaaddr, MDL) != ISC_R_SUCCESS) { printf("ERROR: iasubopt_allocate() %s:%d\n", MDL); return 1; } if (ia_add_iasubopt(ia_na, iaaddr, MDL) != ISC_R_SUCCESS) { printf("ERROR: ia_add_iasubopt() %s:%d\n", MDL); return 1; } if (iasubopt_dereference(&iaaddr, MDL) != ISC_R_SUCCESS) { printf("ERROR: iasubopt_reference() %s:%d\n", MDL); return 1; } } for (i=0; i<100; i++) { iaaddr = ia_na->iasubopt[random() % ia_na->num_iasubopt]; ia_remove_iasubopt(ia_na, iaaddr, MDL); } if (ia_dereference(&ia_na, MDL) != ISC_R_SUCCESS) { printf("ERROR: ia_dereference() %s:%d\n", MDL); return 1; } /* lots of iaaddr, let dereference cleanup */ iaid = 666; ia_na = NULL; if (ia_allocate(&ia_na, iaid, "TestDUID", 8, MDL) != ISC_R_SUCCESS) { printf("ERROR: ia_allocate() %s:%d\n", MDL); return 1; } for (i=0; i<100; i++) { iaaddr = NULL; if (iasubopt_allocate(&iaaddr, MDL) != ISC_R_SUCCESS) { printf("ERROR: iasubopt_allocate() %s:%d\n", MDL); return 1; } if (ia_add_iasubopt(ia_na, iaaddr, MDL) != ISC_R_SUCCESS) { printf("ERROR: ia_add_iasubopt() %s:%d\n", MDL); return 1; } if (iasubopt_dereference(&iaaddr, MDL) != ISC_R_SUCCESS) { printf("ERROR: iasubopt_reference() %s:%d\n", MDL); return 1; } } if (ia_dereference(&ia_na, MDL) != ISC_R_SUCCESS) { printf("ERROR: ia_dereference() %s:%d\n", MDL); return 1; } /* * Test 4: Errors in ia_na. */ /* bogus allocate arguments */ if (ia_allocate(NULL, 123, "", 0, MDL) != DHCP_R_INVALIDARG) { printf("ERROR: ia_allocate() %s:%d\n", MDL); return 1; } ia_na = (struct ia_na *)1; if (ia_allocate(&ia_na, 456, "", 0, MDL) != DHCP_R_INVALIDARG) { printf("ERROR: ia_allocate() %s:%d\n", MDL); return 1; } /* bogus reference arguments */ iaid = 666; ia_na = NULL; if (ia_allocate(&ia_na, iaid, "TestDUID", 8, MDL) != ISC_R_SUCCESS) { printf("ERROR: ia_allocate() %s:%d\n", MDL); return 1; } if (ia_reference(NULL, ia_na, MDL) != DHCP_R_INVALIDARG) { printf("ERROR: ia_reference() %s:%d\n", MDL); return 1; } ia_na_copy = (struct ia_na *)1; if (ia_reference(&ia_na_copy, ia_na, MDL) != DHCP_R_INVALIDARG) { printf("ERROR: ia_reference() %s:%d\n", MDL); return 1; } ia_na_copy = NULL; if (ia_reference(&ia_na_copy, NULL, MDL) != DHCP_R_INVALIDARG) { printf("ERROR: ia_reference() %s:%d\n", MDL); return 1; } if (ia_dereference(&ia_na, MDL) != ISC_R_SUCCESS) { printf("ERROR: ia_dereference() %s:%d\n", MDL); return 1; } /* bogus dereference arguments */ if (ia_dereference(NULL, MDL) != DHCP_R_INVALIDARG) { printf("ERROR: ia_dereference() %s:%d\n", MDL); return 1; } /* bogus remove */ iaid = 666; ia_na = NULL; if (ia_allocate(&ia_na, iaid, "TestDUID", 8, MDL) != ISC_R_SUCCESS) { printf("ERROR: ia_allocate() %s:%d\n", MDL); return 1; } ia_remove_iasubopt(ia_na, NULL, MDL); if (ia_dereference(&ia_na, MDL) != ISC_R_SUCCESS) { printf("ERROR: ia_dereference() %s:%d\n", MDL); return 1; } /* * Test 5: Basic ipv6_pool manipulation. */ /* allocate, reference */ inet_pton(AF_INET6, "1:2:3:4::", &addr); pool = NULL; if (ipv6_pool_allocate(&pool, 0, &addr, 64, 128, MDL) != ISC_R_SUCCESS) { printf("ERROR: ipv6_pool_allocate() %s:%d\n", MDL); return 1; } if (pool->num_active != 0) { printf("ERROR: bad num_active %s:%d\n", MDL); return 1; } if (pool->bits != 64) { printf("ERROR: bad bits %s:%d\n", MDL); return 1; } inet_ntop(AF_INET6, &pool->start_addr, addr_buf, sizeof(addr_buf)); if (strcmp(inet_ntop(AF_INET6, &pool->start_addr, addr_buf, sizeof(addr_buf)), "1:2:3:4::") != 0) { printf("ERROR: bad start_addr %s:%d\n", MDL); return 1; } pool_copy = NULL; if (ipv6_pool_reference(&pool_copy, pool, MDL) != ISC_R_SUCCESS) { printf("ERROR: ipv6_pool_reference() %s:%d\n", MDL); return 1; } /* create_lease6, renew_lease6, expire_lease6 */ uid = "client0"; memset(&ds, 0, sizeof(ds)); ds.len = strlen(uid); if (!buffer_allocate(&ds.buffer, ds.len, MDL)) { printf("Out of memory\n"); return 1; } ds.data = ds.buffer->data; memcpy((char *)ds.data, uid, ds.len); if (create_lease6(pool, &iaaddr, &attempts, &ds, 1) != ISC_R_SUCCESS) { printf("ERROR: create_lease6() %s:%d\n", MDL); return 1; } if (pool->num_inactive != 1) { printf("ERROR: bad num_inactive %s:%d\n", MDL); return 1; } if (renew_lease6(pool, iaaddr) != ISC_R_SUCCESS) { printf("ERROR: renew_lease6() %s:%d\n", MDL); return 1; } if (pool->num_active != 1) { printf("ERROR: bad num_active %s:%d\n", MDL); return 1; } expired_iaaddr = NULL; if (expire_lease6(&expired_iaaddr, pool, 0) != ISC_R_SUCCESS) { printf("ERROR: expire_lease6() %s:%d\n", MDL); return 1; } if (expired_iaaddr != NULL) { printf("ERROR: should not have expired a lease %s:%d\n", MDL); return 1; } if (pool->num_active != 1) { printf("ERROR: bad num_active %s:%d\n", MDL); return 1; } if (expire_lease6(&expired_iaaddr, pool, 1000) != ISC_R_SUCCESS) { printf("ERROR: expire_lease6() %s:%d\n", MDL); return 1; } if (expired_iaaddr == NULL) { printf("ERROR: should have expired a lease %s:%d\n", MDL); return 1; } if (iasubopt_dereference(&expired_iaaddr, MDL) != ISC_R_SUCCESS) { printf("ERROR: iasubopt_dereference() %s:%d\n", MDL); return 1; } if (pool->num_active != 0) { printf("ERROR: bad num_active %s:%d\n", MDL); return 1; } if (iasubopt_dereference(&iaaddr, MDL) != ISC_R_SUCCESS) { printf("ERROR: iasubopt_dereference() %s:%d\n", MDL); return 1; } /* release_lease6, decline_lease6 */ if (create_lease6(pool, &iaaddr, &attempts, &ds, 1) != ISC_R_SUCCESS) { printf("ERROR: create_lease6() %s:%d\n", MDL); return 1; } if (renew_lease6(pool, iaaddr) != ISC_R_SUCCESS) { printf("ERROR: renew_lease6() %s:%d\n", MDL); return 1; } if (pool->num_active != 1) { printf("ERROR: bad num_active %s:%d\n", MDL); return 1; } if (release_lease6(pool, iaaddr) != ISC_R_SUCCESS) { printf("ERROR: decline_lease6() %s:%d\n", MDL); return 1; } if (pool->num_active != 0) { printf("ERROR: bad num_active %s:%d\n", MDL); return 1; } if (iasubopt_dereference(&iaaddr, MDL) != ISC_R_SUCCESS) { printf("ERROR: iasubopt_dereference() %s:%d\n", MDL); return 1; } if (create_lease6(pool, &iaaddr, &attempts, &ds, 1) != ISC_R_SUCCESS) { printf("ERROR: create_lease6() %s:%d\n", MDL); return 1; } if (renew_lease6(pool, iaaddr) != ISC_R_SUCCESS) { printf("ERROR: renew_lease6() %s:%d\n", MDL); return 1; } if (pool->num_active != 1) { printf("ERROR: bad num_active %s:%d\n", MDL); return 1; } if (decline_lease6(pool, iaaddr) != ISC_R_SUCCESS) { printf("ERROR: decline_lease6() %s:%d\n", MDL); return 1; } if (pool->num_active != 1) { printf("ERROR: bad num_active %s:%d\n", MDL); return 1; } if (iasubopt_dereference(&iaaddr, MDL) != ISC_R_SUCCESS) { printf("ERROR: iasubopt_dereference() %s:%d\n", MDL); return 1; } /* dereference */ if (ipv6_pool_dereference(&pool, MDL) != ISC_R_SUCCESS) { printf("ERROR: ipv6_pool_reference() %s:%d\n", MDL); return 1; } if (ipv6_pool_dereference(&pool_copy, MDL) != ISC_R_SUCCESS) { printf("ERROR: ipv6_pool_reference() %s:%d\n", MDL); return 1; } /* * Test 6: Error ipv6_pool manipulation */ if (ipv6_pool_allocate(NULL, 0, &addr, 64, 128, MDL) != DHCP_R_INVALIDARG) { printf("ERROR: ipv6_pool_allocate() %s:%d\n", MDL); return 1; } pool = (struct ipv6_pool *)1; if (ipv6_pool_allocate(&pool, 0, &addr, 64, 128, MDL) != DHCP_R_INVALIDARG) { printf("ERROR: ipv6_pool_allocate() %s:%d\n", MDL); return 1; } if (ipv6_pool_reference(NULL, pool, MDL) != DHCP_R_INVALIDARG) { printf("ERROR: ipv6_pool_reference() %s:%d\n", MDL); return 1; } pool_copy = (struct ipv6_pool *)1; if (ipv6_pool_reference(&pool_copy, pool, MDL) != DHCP_R_INVALIDARG) { printf("ERROR: ipv6_pool_reference() %s:%d\n", MDL); return 1; } pool_copy = NULL; if (ipv6_pool_reference(&pool_copy, NULL, MDL) != DHCP_R_INVALIDARG) { printf("ERROR: ipv6_pool_reference() %s:%d\n", MDL); return 1; } if (ipv6_pool_dereference(NULL, MDL) != DHCP_R_INVALIDARG) { printf("ERROR: ipv6_pool_dereference() %s:%d\n", MDL); return 1; } if (ipv6_pool_dereference(&pool_copy, MDL) != DHCP_R_INVALIDARG) { printf("ERROR: ipv6_pool_dereference() %s:%d\n", MDL); return 1; } /* * Test 7: order of expiration */ pool = NULL; if (ipv6_pool_allocate(&pool, 0, &addr, 64, 128, MDL) != ISC_R_SUCCESS) { printf("ERROR: ipv6_pool_allocate() %s:%d\n", MDL); return 1; } for (i=10; i<100; i+=10) { if (create_lease6(pool, &iaaddr, &attempts, &ds, i) != ISC_R_SUCCESS) { printf("ERROR: create_lease6() %s:%d\n", MDL); return 1; } if (renew_lease6(pool, iaaddr) != ISC_R_SUCCESS) { printf("ERROR: renew_lease6() %s:%d\n", MDL); return 1; } if (iasubopt_dereference(&iaaddr, MDL) != ISC_R_SUCCESS) { printf("ERROR: iasubopt_dereference() %s:%d\n", MDL); return 1; } if (pool->num_active != (i / 10)) { printf("ERROR: bad num_active %s:%d\n", MDL); return 1; } } if (pool->num_active != 9) { printf("ERROR: bad num_active %s:%d\n", MDL); return 1; } for (i=10; i<100; i+=10) { if (expire_lease6(&expired_iaaddr, pool, 1000) != ISC_R_SUCCESS) { printf("ERROR: expire_lease6() %s:%d\n", MDL); return 1; } if (expired_iaaddr == NULL) { printf("ERROR: should have expired a lease %s:%d\n", MDL); return 1; } if (pool->num_active != (9 - (i / 10))) { printf("ERROR: bad num_active %s:%d\n", MDL); return 1; } if (expired_iaaddr->hard_lifetime_end_time != i) { printf("ERROR: bad hard_lifetime_end_time %s:%d\n", MDL); return 1; } if (iasubopt_dereference(&expired_iaaddr, MDL) != ISC_R_SUCCESS) { printf("ERROR: iasubopt_dereference() %s:%d\n", MDL); return 1; } } if (pool->num_active != 0) { printf("ERROR: bad num_active %s:%d\n", MDL); return 1; } expired_iaaddr = NULL; if (expire_lease6(&expired_iaaddr, pool, 1000) != ISC_R_SUCCESS) { printf("ERROR: expire_lease6() %s:%d\n", MDL); return 1; } if (ipv6_pool_dereference(&pool, MDL) != ISC_R_SUCCESS) { printf("ERROR: ipv6_pool_dereference() %s:%d\n", MDL); return 1; } /* * Test 8: small pool */ pool = NULL; addr.s6_addr[14] = 0x81; if (ipv6_pool_allocate(&pool, 0, &addr, 127, 128, MDL) != ISC_R_SUCCESS) { printf("ERROR: ipv6_pool_allocate() %s:%d\n", MDL); return 1; } if (create_lease6(pool, &iaaddr, &attempts, &ds, 42) != ISC_R_SUCCESS) { printf("ERROR: create_lease6() %s:%d\n", MDL); return 1; } if (renew_lease6(pool, iaaddr) != ISC_R_SUCCESS) { printf("ERROR: renew_lease6() %s:%d\n", MDL); return 1; } if (iasubopt_dereference(&iaaddr, MDL) != ISC_R_SUCCESS) { printf("ERROR: iasubopt_dereference() %s:%d\n", MDL); return 1; } if (create_lease6(pool, &iaaddr, &attempts, &ds, 11) != ISC_R_SUCCESS) { printf("ERROR: create_lease6() %s:%d\n", MDL); return 1; } if (renew_lease6(pool, iaaddr) != ISC_R_SUCCESS) { printf("ERROR: renew_lease6() %s:%d\n", MDL); return 1; } if (iasubopt_dereference(&iaaddr, MDL) != ISC_R_SUCCESS) { printf("ERROR: iasubopt_dereference() %s:%d\n", MDL); return 1; } if (create_lease6(pool, &iaaddr, &attempts, &ds, 11) != ISC_R_NORESOURCES) { printf("ERROR: create_lease6() %s:%d\n", MDL); return 1; } if (ipv6_pool_dereference(&pool, MDL) != ISC_R_SUCCESS) { printf("ERROR: ipv6_pool_dereference() %s:%d\n", MDL); return 1; } addr.s6_addr[14] = 0; /* * Test 9: functions across all pools */ pool = NULL; if (ipv6_pool_allocate(&pool, 0, &addr, 64, 128, MDL) != ISC_R_SUCCESS) { printf("ERROR: ipv6_pool_allocate() %s:%d\n", MDL); return 1; } if (add_ipv6_pool(pool) != ISC_R_SUCCESS) { printf("ERROR: add_ipv6_pool() %s:%d\n", MDL); return 1; } if (ipv6_pool_dereference(&pool, MDL) != ISC_R_SUCCESS) { printf("ERROR: ipv6_pool_dereference() %s:%d\n", MDL); return 1; } pool = NULL; if (find_ipv6_pool(&pool, 0, &addr) != ISC_R_SUCCESS) { printf("ERROR: find_ipv6_pool() %s:%d\n", MDL); return 1; } if (ipv6_pool_dereference(&pool, MDL) != ISC_R_SUCCESS) { printf("ERROR: ipv6_pool_dereference() %s:%d\n", MDL); return 1; } inet_pton(AF_INET6, "1:2:3:4:ffff:ffff:ffff:ffff", &addr); pool = NULL; if (find_ipv6_pool(&pool, 0, &addr) != ISC_R_SUCCESS) { printf("ERROR: find_ipv6_pool() %s:%d\n", MDL); return 1; } if (ipv6_pool_dereference(&pool, MDL) != ISC_R_SUCCESS) { printf("ERROR: ipv6_pool_dereference() %s:%d\n", MDL); return 1; } inet_pton(AF_INET6, "1:2:3:5::", &addr); pool = NULL; if (find_ipv6_pool(&pool, 0, &addr) != ISC_R_NOTFOUND) { printf("ERROR: find_ipv6_pool() %s:%d\n", MDL); return 1; } inet_pton(AF_INET6, "1:2:3:3:ffff:ffff:ffff:ffff", &addr); pool = NULL; if (find_ipv6_pool(&pool, 0, &addr) != ISC_R_NOTFOUND) { printf("ERROR: find_ipv6_pool() %s:%d\n", MDL); return 1; } /* iaid = 666; ia_na = NULL; if (ia_allocate(&ia_na, iaid, "TestDUID", 8, MDL) != ISC_R_SUCCESS) { printf("ERROR: ia_allocate() %s:%d\n", MDL); return 1; }*/ { struct in6_addr r; struct data_string ds; u_char data[16]; char buf[64]; int i, j; memset(&ds, 0, sizeof(ds)); memset(data, 0xaa, sizeof(data)); ds.len = 16; ds.data = data; inet_pton(AF_INET6, "3ffe:501:ffff:100::", &addr); for (i = 32; i < 42; i++) for (j = i + 1; j < 49; j++) { memset(&r, 0, sizeof(r)); memset(buf, 0, 64); build_prefix6(&r, &addr, i, j, &ds); inet_ntop(AF_INET6, &r, buf, 64); printf("%d,%d-> %s/%d\n", i, j, buf, j); } } printf("SUCCESS: all tests passed (ignore any warning messages)\n"); return 0; } #endif dhcp-4.2.4/server/omapi.c000644 000765 000024 00000216146 11741122653 015162 0ustar00sarstaff000000 000000 /* omapi.c OMAPI object interfaces for the DHCP server. */ /* * Copyright (c) 2004-2010,2012 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1999-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ * * This software has been written for Internet Systems Consortium * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. * To learn more about Internet Systems Consortium, see * ``https://www.isc.org/''. To learn more about Vixie Enterprises, * see ``http://www.vix.com''. To learn more about Nominum, Inc., see * ``http://www.nominum.com''. */ /* Many, many thanks to Brian Murrell and BCtel for this code - BCtel provided the funding that resulted in this code and the entire OMAPI support library being written, and Brian helped brainstorm and refine the requirements. To the extent that this code is useful, you have Brian and BCtel to thank. Any limitations in the code are a result of mistakes on my part. -- Ted Lemon */ #include "dhcpd.h" #include static isc_result_t class_lookup (omapi_object_t **, omapi_object_t *, omapi_object_t *, omapi_object_type_t *); omapi_object_type_t *dhcp_type_lease; omapi_object_type_t *dhcp_type_pool; omapi_object_type_t *dhcp_type_class; omapi_object_type_t *dhcp_type_subclass; omapi_object_type_t *dhcp_type_host; #if defined (FAILOVER_PROTOCOL) omapi_object_type_t *dhcp_type_failover_state; omapi_object_type_t *dhcp_type_failover_link; omapi_object_type_t *dhcp_type_failover_listener; #endif void dhcp_db_objects_setup () { isc_result_t status; status = omapi_object_type_register (&dhcp_type_lease, "lease", dhcp_lease_set_value, dhcp_lease_get_value, dhcp_lease_destroy, dhcp_lease_signal_handler, dhcp_lease_stuff_values, dhcp_lease_lookup, dhcp_lease_create, dhcp_lease_remove, #if defined (COMPACT_LEASES) dhcp_lease_free, dhcp_lease_get, #else 0, 0, #endif 0, sizeof (struct lease), 0, RC_LEASE); if (status != ISC_R_SUCCESS) log_fatal ("Can't register lease object type: %s", isc_result_totext (status)); status = omapi_object_type_register (&dhcp_type_class, "class", dhcp_class_set_value, dhcp_class_get_value, dhcp_class_destroy, dhcp_class_signal_handler, dhcp_class_stuff_values, dhcp_class_lookup, dhcp_class_create, dhcp_class_remove, 0, 0, 0, sizeof (struct class), 0, RC_MISC); if (status != ISC_R_SUCCESS) log_fatal ("Can't register class object type: %s", isc_result_totext (status)); status = omapi_object_type_register (&dhcp_type_subclass, "subclass", dhcp_subclass_set_value, dhcp_subclass_get_value, dhcp_class_destroy, dhcp_subclass_signal_handler, dhcp_subclass_stuff_values, dhcp_subclass_lookup, dhcp_subclass_create, dhcp_subclass_remove, 0, 0, 0, sizeof (struct class), 0, RC_MISC); if (status != ISC_R_SUCCESS) log_fatal ("Can't register subclass object type: %s", isc_result_totext (status)); status = omapi_object_type_register (&dhcp_type_pool, "pool", dhcp_pool_set_value, dhcp_pool_get_value, dhcp_pool_destroy, dhcp_pool_signal_handler, dhcp_pool_stuff_values, dhcp_pool_lookup, dhcp_pool_create, dhcp_pool_remove, 0, 0, 0, sizeof (struct pool), 0, RC_MISC); if (status != ISC_R_SUCCESS) log_fatal ("Can't register pool object type: %s", isc_result_totext (status)); status = omapi_object_type_register (&dhcp_type_host, "host", dhcp_host_set_value, dhcp_host_get_value, dhcp_host_destroy, dhcp_host_signal_handler, dhcp_host_stuff_values, dhcp_host_lookup, dhcp_host_create, dhcp_host_remove, 0, 0, 0, sizeof (struct host_decl), 0, RC_MISC); if (status != ISC_R_SUCCESS) log_fatal ("Can't register host object type: %s", isc_result_totext (status)); #if defined (FAILOVER_PROTOCOL) status = omapi_object_type_register (&dhcp_type_failover_state, "failover-state", dhcp_failover_state_set_value, dhcp_failover_state_get_value, dhcp_failover_state_destroy, dhcp_failover_state_signal, dhcp_failover_state_stuff, dhcp_failover_state_lookup, dhcp_failover_state_create, dhcp_failover_state_remove, 0, 0, 0, sizeof (dhcp_failover_state_t), 0, RC_MISC); if (status != ISC_R_SUCCESS) log_fatal ("Can't register failover state object type: %s", isc_result_totext (status)); status = omapi_object_type_register (&dhcp_type_failover_link, "failover-link", dhcp_failover_link_set_value, dhcp_failover_link_get_value, dhcp_failover_link_destroy, dhcp_failover_link_signal, dhcp_failover_link_stuff_values, 0, 0, 0, 0, 0, 0, sizeof (dhcp_failover_link_t), 0, RC_MISC); if (status != ISC_R_SUCCESS) log_fatal ("Can't register failover link object type: %s", isc_result_totext (status)); status = omapi_object_type_register (&dhcp_type_failover_listener, "failover-listener", dhcp_failover_listener_set_value, dhcp_failover_listener_get_value, dhcp_failover_listener_destroy, dhcp_failover_listener_signal, dhcp_failover_listener_stuff, 0, 0, 0, 0, 0, 0, sizeof (dhcp_failover_listener_t), 0, RC_MISC); if (status != ISC_R_SUCCESS) log_fatal ("Can't register failover listener object type: %s", isc_result_totext (status)); #endif /* FAILOVER_PROTOCOL */ } isc_result_t dhcp_lease_set_value (omapi_object_t *h, omapi_object_t *id, omapi_data_string_t *name, omapi_typed_data_t *value) { struct lease *lease; isc_result_t status; if (h -> type != dhcp_type_lease) return DHCP_R_INVALIDARG; lease = (struct lease *)h; /* We're skipping a lot of things it might be interesting to set - for now, we just make it possible to whack the state. */ if (!omapi_ds_strcmp (name, "state")) { unsigned long bar; const char *ols, *nls; status = omapi_get_int_value (&bar, value); if (status != ISC_R_SUCCESS) return status; if (bar < 1 || bar > FTS_LAST) return DHCP_R_INVALIDARG; nls = binding_state_names [bar - 1]; if (lease -> binding_state >= 1 && lease -> binding_state <= FTS_LAST) ols = binding_state_names [lease -> binding_state - 1]; else ols = "unknown state"; if (lease -> binding_state != bar) { lease -> next_binding_state = bar; if (supersede_lease (lease, 0, 1, 1, 1)) { log_info ("lease %s state changed from %s to %s", piaddr(lease->ip_addr), ols, nls); return ISC_R_SUCCESS; } log_info ("lease %s state change from %s to %s failed.", piaddr (lease -> ip_addr), ols, nls); return ISC_R_IOERROR; } return DHCP_R_UNCHANGED; } else if (!omapi_ds_strcmp (name, "ip-address")) { return ISC_R_NOPERM; } else if (!omapi_ds_strcmp (name, "dhcp-client-identifier")) { return DHCP_R_UNCHANGED; /* XXX take change. */ } else if (!omapi_ds_strcmp (name, "hostname")) { return DHCP_R_UNCHANGED; /* XXX take change. */ } else if (!omapi_ds_strcmp (name, "client-hostname")) { return DHCP_R_UNCHANGED; /* XXX take change. */ } else if (!omapi_ds_strcmp (name, "host")) { return DHCP_R_UNCHANGED; /* XXX take change. */ } else if (!omapi_ds_strcmp (name, "subnet")) { return DHCP_R_INVALIDARG; } else if (!omapi_ds_strcmp (name, "pool")) { return ISC_R_NOPERM; } else if (!omapi_ds_strcmp (name, "starts")) { return ISC_R_NOPERM; } else if (!omapi_ds_strcmp (name, "ends")) { unsigned long lease_end, old_lease_end; status = omapi_get_int_value (&lease_end, value); if (status != ISC_R_SUCCESS) return status; old_lease_end = lease->ends; lease->ends = lease_end; if (supersede_lease (lease, 0, 1, 1, 1)) { log_info ("lease %s end changed from %lu to %lu", piaddr(lease->ip_addr), old_lease_end, lease_end); return ISC_R_SUCCESS; } log_info ("lease %s end change from %lu to %lu failed", piaddr(lease->ip_addr), old_lease_end, lease_end); return ISC_R_IOERROR; } else if (!omapi_ds_strcmp(name, "flags")) { u_int8_t oldflags; if (value->type != omapi_datatype_data) return DHCP_R_INVALIDARG; oldflags = lease->flags; lease->flags = (value->u.buffer.value[0] & EPHEMERAL_FLAGS) | (lease->flags & ~EPHEMERAL_FLAGS); if(oldflags == lease->flags) return ISC_R_SUCCESS; if (!supersede_lease(lease, NULL, 1, 1, 1)) { log_error("Failed to update flags for lease %s.", piaddr(lease->ip_addr)); return ISC_R_IOERROR; } return ISC_R_SUCCESS; } else if (!omapi_ds_strcmp (name, "billing-class")) { return DHCP_R_UNCHANGED; /* XXX carefully allow change. */ } else if (!omapi_ds_strcmp (name, "hardware-address")) { return DHCP_R_UNCHANGED; /* XXX take change. */ } else if (!omapi_ds_strcmp (name, "hardware-type")) { return DHCP_R_UNCHANGED; /* XXX take change. */ } else if (lease -> scope) { status = binding_scope_set_value (lease -> scope, 0, name, value); if (status == ISC_R_SUCCESS) { if (write_lease (lease) && commit_leases ()) return ISC_R_SUCCESS; return ISC_R_IOERROR; } } /* Try to find some inner object that can take the value. */ if (h -> inner && h -> inner -> type -> set_value) { status = ((*(h -> inner -> type -> set_value)) (h -> inner, id, name, value)); if (status == ISC_R_SUCCESS || status == DHCP_R_UNCHANGED) return status; } if (!lease -> scope) { if (!binding_scope_allocate (&lease -> scope, MDL)) return ISC_R_NOMEMORY; } status = binding_scope_set_value (lease -> scope, 1, name, value); if (status != ISC_R_SUCCESS) return status; if (write_lease (lease) && commit_leases ()) return ISC_R_SUCCESS; return ISC_R_IOERROR; } isc_result_t dhcp_lease_get_value (omapi_object_t *h, omapi_object_t *id, omapi_data_string_t *name, omapi_value_t **value) { struct lease *lease; isc_result_t status; if (h -> type != dhcp_type_lease) return DHCP_R_INVALIDARG; lease = (struct lease *)h; if (!omapi_ds_strcmp (name, "state")) return omapi_make_int_value (value, name, (int)lease -> binding_state, MDL); else if (!omapi_ds_strcmp (name, "ip-address")) return omapi_make_const_value (value, name, lease -> ip_addr.iabuf, lease -> ip_addr.len, MDL); else if (!omapi_ds_strcmp (name, "dhcp-client-identifier")) { return omapi_make_const_value (value, name, lease -> uid, lease -> uid_len, MDL); } else if (!omapi_ds_strcmp (name, "client-hostname")) { if (lease -> client_hostname) return omapi_make_string_value (value, name, lease -> client_hostname, MDL); return ISC_R_NOTFOUND; } else if (!omapi_ds_strcmp (name, "host")) { if (lease -> host) return omapi_make_handle_value (value, name, ((omapi_object_t *)lease -> host), MDL); } else if (!omapi_ds_strcmp (name, "subnet")) return omapi_make_handle_value (value, name, ((omapi_object_t *) lease -> subnet), MDL); else if (!omapi_ds_strcmp (name, "pool")) return omapi_make_handle_value (value, name, ((omapi_object_t *) lease -> pool), MDL); else if (!omapi_ds_strcmp (name, "billing-class")) { if (lease -> billing_class) return omapi_make_handle_value (value, name, ((omapi_object_t *)lease -> billing_class), MDL); return ISC_R_NOTFOUND; } else if (!omapi_ds_strcmp (name, "hardware-address")) { if (lease -> hardware_addr.hlen) return omapi_make_const_value (value, name, &lease -> hardware_addr.hbuf [1], (unsigned)(lease -> hardware_addr.hlen - 1), MDL); return ISC_R_NOTFOUND; } else if (!omapi_ds_strcmp (name, "hardware-type")) { if (lease -> hardware_addr.hlen) return omapi_make_int_value (value, name, lease -> hardware_addr.hbuf [0], MDL); return ISC_R_NOTFOUND; } else if (lease -> scope) { status = binding_scope_get_value (value, lease -> scope, name); if (status != ISC_R_NOTFOUND) return status; } /* Try to find some inner object that can take the value. */ if (h -> inner && h -> inner -> type -> get_value) { status = ((*(h -> inner -> type -> get_value)) (h -> inner, id, name, value)); if (status == ISC_R_SUCCESS) return status; } return DHCP_R_UNKNOWNATTRIBUTE; } isc_result_t dhcp_lease_destroy (omapi_object_t *h, const char *file, int line) { struct lease *lease; if (h -> type != dhcp_type_lease) return DHCP_R_INVALIDARG; lease = (struct lease *)h; if (lease -> uid) uid_hash_delete (lease); hw_hash_delete (lease); if (lease -> on_release) executable_statement_dereference (&lease -> on_release, file, line); if (lease -> on_expiry) executable_statement_dereference (&lease -> on_expiry, file, line); if (lease -> on_commit) executable_statement_dereference (&lease -> on_commit, file, line); if (lease -> scope) binding_scope_dereference (&lease -> scope, file, line); if (lease -> agent_options) option_chain_head_dereference (&lease -> agent_options, file, line); if (lease -> uid && lease -> uid != lease -> uid_buf) { dfree (lease -> uid, MDL); lease -> uid = &lease -> uid_buf [0]; lease -> uid_len = 0; } if (lease -> client_hostname) { dfree (lease -> client_hostname, MDL); lease -> client_hostname = (char *)0; } if (lease -> host) host_dereference (&lease -> host, file, line); if (lease -> subnet) subnet_dereference (&lease -> subnet, file, line); if (lease -> pool) pool_dereference (&lease -> pool, file, line); if (lease -> state) { free_lease_state (lease -> state, file, line); lease -> state = (struct lease_state *)0; cancel_timeout (lease_ping_timeout, lease); --outstanding_pings; /* XXX */ } if (lease -> billing_class) class_dereference (&lease -> billing_class, file, line); #if defined (DEBUG_MEMORY_LEAKAGE) || \ defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT) /* XXX we should never be destroying a lease with a next XXX pointer except on exit... */ if (lease -> next) lease_dereference (&lease -> next, file, line); if (lease -> n_hw) lease_dereference (&lease -> n_hw, file, line); if (lease -> n_uid) lease_dereference (&lease -> n_uid, file, line); if (lease -> next_pending) lease_dereference (&lease -> next_pending, file, line); #endif return ISC_R_SUCCESS; } isc_result_t dhcp_lease_signal_handler (omapi_object_t *h, const char *name, va_list ap) { /* h should point to (struct lease *) */ isc_result_t status; if (h -> type != dhcp_type_lease) return DHCP_R_INVALIDARG; if (!strcmp (name, "updated")) return ISC_R_SUCCESS; /* Try to find some inner object that can take the value. */ if (h -> inner && h -> inner -> type -> signal_handler) { status = ((*(h -> inner -> type -> signal_handler)) (h -> inner, name, ap)); if (status == ISC_R_SUCCESS) return status; } return ISC_R_NOTFOUND; } isc_result_t dhcp_lease_stuff_values (omapi_object_t *c, omapi_object_t *id, omapi_object_t *h) { u_int32_t bouncer; struct lease *lease; isc_result_t status; u_int8_t flagbuf; if (h -> type != dhcp_type_lease) return DHCP_R_INVALIDARG; lease = (struct lease *)h; /* Write out all the values. */ status = omapi_connection_put_name (c, "state"); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_put_uint32 (c, sizeof (int)); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_put_uint32 (c, lease -> binding_state); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_put_name (c, "ip-address"); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_put_uint32 (c, lease -> ip_addr.len); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_copyin (c, lease -> ip_addr.iabuf, lease -> ip_addr.len); if (status != ISC_R_SUCCESS) return status; if (lease -> uid_len) { status = omapi_connection_put_name (c, "dhcp-client-identifier"); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_put_uint32 (c, lease -> uid_len); if (status != ISC_R_SUCCESS) return status; if (lease -> uid_len) { status = omapi_connection_copyin (c, lease -> uid, lease -> uid_len); if (status != ISC_R_SUCCESS) return status; } } if (lease -> client_hostname) { status = omapi_connection_put_name (c, "client-hostname"); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_put_string (c, lease -> client_hostname); if (status != ISC_R_SUCCESS) return status; } if (lease -> host) { status = omapi_connection_put_name (c, "host"); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_put_handle (c, (omapi_object_t *) lease -> host); if (status != ISC_R_SUCCESS) return status; } status = omapi_connection_put_name (c, "subnet"); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_put_handle (c, (omapi_object_t *)lease -> subnet); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_put_name (c, "pool"); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_put_handle (c, (omapi_object_t *)lease -> pool); if (status != ISC_R_SUCCESS) return status; if (lease -> billing_class) { status = omapi_connection_put_name (c, "billing-class"); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_put_handle (c, (omapi_object_t *)lease -> billing_class); if (status != ISC_R_SUCCESS) return status; } if (lease -> hardware_addr.hlen) { status = omapi_connection_put_name (c, "hardware-address"); if (status != ISC_R_SUCCESS) return status; status = (omapi_connection_put_uint32 (c, (unsigned long)(lease -> hardware_addr.hlen - 1))); if (status != ISC_R_SUCCESS) return status; status = (omapi_connection_copyin (c, &lease -> hardware_addr.hbuf [1], (unsigned long)(lease -> hardware_addr.hlen - 1))); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_put_name (c, "hardware-type"); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_put_uint32 (c, sizeof (int)); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_put_uint32 (c, lease -> hardware_addr.hbuf [0]); if (status != ISC_R_SUCCESS) return status; } /* TIME values may be 64-bit, depending on system architecture. * OMAPI must be system independent, both in terms of transmitting * bytes on the wire in network byte order, and in terms of being * readable and usable by both systems. * * XXX: In a future feature release, a put_int64() should be made * to exist, and perhaps a put_time() wrapper that selects which * to use based upon sizeof(TIME). In the meantime, use existing, * 32-bit, code. */ bouncer = (u_int32_t)lease->ends; status = omapi_connection_put_name(c, "ends"); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_put_uint32(c, sizeof(bouncer)); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_put_uint32(c, bouncer); if (status != ISC_R_SUCCESS) return status; bouncer = (u_int32_t)lease->starts; status = omapi_connection_put_name(c, "starts"); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_put_uint32(c, sizeof(bouncer)); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_put_uint32(c, bouncer); if (status != ISC_R_SUCCESS) return status; bouncer = (u_int32_t)lease->tstp; status = omapi_connection_put_name(c, "tstp"); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_put_uint32(c, sizeof(bouncer)); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_put_uint32(c, bouncer); if (status != ISC_R_SUCCESS) return status; bouncer = (u_int32_t)lease->tsfp; status = omapi_connection_put_name(c, "tsfp"); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_put_uint32(c, sizeof(bouncer)); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_put_uint32(c, bouncer); if (status != ISC_R_SUCCESS) return status; bouncer = (u_int32_t)lease->atsfp; status = omapi_connection_put_name(c, "atsfp"); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_put_uint32(c, sizeof(bouncer)); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_put_uint32(c, bouncer); if (status != ISC_R_SUCCESS) return status; bouncer = (u_int32_t)lease->cltt; status = omapi_connection_put_name(c, "cltt"); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_put_uint32(c, sizeof(bouncer)); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_put_uint32(c, bouncer); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_put_name (c, "flags"); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_put_uint32(c, sizeof(flagbuf)); if (status != ISC_R_SUCCESS) return status; flagbuf = lease->flags & EPHEMERAL_FLAGS; status = omapi_connection_copyin(c, &flagbuf, sizeof(flagbuf)); if (status != ISC_R_SUCCESS) return status; if (lease -> scope) { status = binding_scope_stuff_values (c, lease -> scope); if (status != ISC_R_SUCCESS) return status; } /* Write out the inner object, if any. */ if (h -> inner && h -> inner -> type -> stuff_values) { status = ((*(h -> inner -> type -> stuff_values)) (c, id, h -> inner)); if (status == ISC_R_SUCCESS) return status; } return ISC_R_SUCCESS; } isc_result_t dhcp_lease_lookup (omapi_object_t **lp, omapi_object_t *id, omapi_object_t *ref) { omapi_value_t *tv = (omapi_value_t *)0; isc_result_t status; struct lease *lease; if (!ref) return DHCP_R_NOKEYS; /* First see if we were sent a handle. */ status = omapi_get_value_str (ref, id, "handle", &tv); if (status == ISC_R_SUCCESS) { status = omapi_handle_td_lookup (lp, tv -> value); omapi_value_dereference (&tv, MDL); if (status != ISC_R_SUCCESS) return status; /* Don't return the object if the type is wrong. */ if ((*lp) -> type != dhcp_type_lease) { omapi_object_dereference (lp, MDL); return DHCP_R_INVALIDARG; } } /* Now look for an IP address. */ status = omapi_get_value_str (ref, id, "ip-address", &tv); if (status == ISC_R_SUCCESS) { lease = (struct lease *)0; lease_ip_hash_lookup(&lease, lease_ip_addr_hash, tv->value->u.buffer.value, tv->value->u.buffer.len, MDL); omapi_value_dereference (&tv, MDL); /* If we already have a lease, and it's not the same one, then the query was invalid. */ if (*lp && *lp != (omapi_object_t *)lease) { omapi_object_dereference (lp, MDL); lease_dereference (&lease, MDL); return DHCP_R_KEYCONFLICT; } else if (!lease) { if (*lp) omapi_object_dereference (lp, MDL); return ISC_R_NOTFOUND; } else if (!*lp) { /* XXX fix so that hash lookup itself creates XXX the reference. */ omapi_object_reference (lp, (omapi_object_t *)lease, MDL); lease_dereference (&lease, MDL); } } /* Now look for a client identifier. */ status = omapi_get_value_str (ref, id, "dhcp-client-identifier", &tv); if (status == ISC_R_SUCCESS) { lease = (struct lease *)0; lease_id_hash_lookup(&lease, lease_uid_hash, tv->value->u.buffer.value, tv->value->u.buffer.len, MDL); omapi_value_dereference (&tv, MDL); if (*lp && *lp != (omapi_object_t *)lease) { omapi_object_dereference (lp, MDL); lease_dereference (&lease, MDL); return DHCP_R_KEYCONFLICT; } else if (!lease) { if (*lp) omapi_object_dereference (lp, MDL); return ISC_R_NOTFOUND; } else if (lease -> n_uid) { if (*lp) omapi_object_dereference (lp, MDL); return DHCP_R_MULTIPLE; } else if (!*lp) { /* XXX fix so that hash lookup itself creates XXX the reference. */ omapi_object_reference (lp, (omapi_object_t *)lease, MDL); lease_dereference (&lease, MDL); } } /* Now look for a hardware address. */ status = omapi_get_value_str (ref, id, "hardware-address", &tv); if (status == ISC_R_SUCCESS) { unsigned char *haddr; unsigned int len; len = tv -> value -> u.buffer.len + 1; haddr = dmalloc (len, MDL); if (!haddr) { omapi_value_dereference (&tv, MDL); return ISC_R_NOMEMORY; } memcpy (haddr + 1, tv -> value -> u.buffer.value, len - 1); omapi_value_dereference (&tv, MDL); status = omapi_get_value_str (ref, id, "hardware-type", &tv); if (status == ISC_R_SUCCESS) { if (tv -> value -> type == omapi_datatype_data) { if ((tv -> value -> u.buffer.len != 4) || (tv -> value -> u.buffer.value[0] != 0) || (tv -> value -> u.buffer.value[1] != 0) || (tv -> value -> u.buffer.value[2] != 0)) { omapi_value_dereference (&tv, MDL); dfree (haddr, MDL); return DHCP_R_INVALIDARG; } haddr[0] = tv -> value -> u.buffer.value[3]; } else if (tv -> value -> type == omapi_datatype_int) { haddr[0] = (unsigned char) tv -> value -> u.integer; } else { omapi_value_dereference (&tv, MDL); dfree (haddr, MDL); return DHCP_R_INVALIDARG; } omapi_value_dereference (&tv, MDL); } else { /* If no hardware-type is specified, default to ethernet. This may or may not be a good idea, but Telus is currently relying on this behavior. - DPN */ haddr[0] = HTYPE_ETHER; } lease = (struct lease *)0; lease_id_hash_lookup(&lease, lease_hw_addr_hash, haddr, len, MDL); dfree (haddr, MDL); if (*lp && *lp != (omapi_object_t *)lease) { omapi_object_dereference (lp, MDL); lease_dereference (&lease, MDL); return DHCP_R_KEYCONFLICT; } else if (!lease) { if (*lp) omapi_object_dereference (lp, MDL); return ISC_R_NOTFOUND; } else if (lease -> n_hw) { if (*lp) omapi_object_dereference (lp, MDL); lease_dereference (&lease, MDL); return DHCP_R_MULTIPLE; } else if (!*lp) { /* XXX fix so that hash lookup itself creates XXX the reference. */ omapi_object_reference (lp, (omapi_object_t *)lease, MDL); lease_dereference (&lease, MDL); } } /* If we get to here without finding a lease, no valid key was specified. */ if (!*lp) return DHCP_R_NOKEYS; return ISC_R_SUCCESS; } isc_result_t dhcp_lease_create (omapi_object_t **lp, omapi_object_t *id) { return ISC_R_NOTIMPLEMENTED; } isc_result_t dhcp_lease_remove (omapi_object_t *lp, omapi_object_t *id) { return ISC_R_NOTIMPLEMENTED; } isc_result_t dhcp_host_set_value (omapi_object_t *h, omapi_object_t *id, omapi_data_string_t *name, omapi_typed_data_t *value) { struct host_decl *host; isc_result_t status; if (h -> type != dhcp_type_host) return DHCP_R_INVALIDARG; host = (struct host_decl *)h; /* XXX For now, we can only set these values on new host objects. XXX Soon, we need to be able to update host objects. */ if (!omapi_ds_strcmp (name, "name")) { if (host -> name) return ISC_R_EXISTS; if (value && (value -> type == omapi_datatype_data || value -> type == omapi_datatype_string)) { host -> name = dmalloc (value -> u.buffer.len + 1, MDL); if (!host -> name) return ISC_R_NOMEMORY; memcpy (host -> name, value -> u.buffer.value, value -> u.buffer.len); host -> name [value -> u.buffer.len] = 0; } else return DHCP_R_INVALIDARG; return ISC_R_SUCCESS; } if (!omapi_ds_strcmp (name, "group")) { if (value && (value -> type == omapi_datatype_data || value -> type == omapi_datatype_string)) { struct group_object *group; group = (struct group_object *)0; group_hash_lookup (&group, group_name_hash, (char *)value -> u.buffer.value, value -> u.buffer.len, MDL); if (!group || (group -> flags & GROUP_OBJECT_DELETED)) return ISC_R_NOTFOUND; if (host -> group) group_dereference (&host -> group, MDL); group_reference (&host -> group, group -> group, MDL); if (host -> named_group) group_object_dereference (&host -> named_group, MDL); group_object_reference (&host -> named_group, group, MDL); group_object_dereference (&group, MDL); } else return DHCP_R_INVALIDARG; return ISC_R_SUCCESS; } if (!omapi_ds_strcmp (name, "hardware-address")) { if (host -> interface.hlen) return ISC_R_EXISTS; if (value && (value -> type == omapi_datatype_data || value -> type == omapi_datatype_string)) { if (value -> u.buffer.len > (sizeof host -> interface.hbuf) - 1) return DHCP_R_INVALIDARG; memcpy (&host -> interface.hbuf [1], value -> u.buffer.value, value -> u.buffer.len); host -> interface.hlen = value -> u.buffer.len + 1; } else return DHCP_R_INVALIDARG; return ISC_R_SUCCESS; } if (!omapi_ds_strcmp (name, "hardware-type")) { int type; if ((value != NULL) && ((value->type == omapi_datatype_data) && (value->u.buffer.len == sizeof(type)))) { if (value->u.buffer.len > sizeof(type)) return (DHCP_R_INVALIDARG); memcpy(&type, value->u.buffer.value, value->u.buffer.len); type = ntohl(type); } else if ((value != NULL) && (value->type == omapi_datatype_int)) type = value->u.integer; else return (DHCP_R_INVALIDARG); host->interface.hbuf[0] = type; return (ISC_R_SUCCESS); } if (!omapi_ds_strcmp (name, "dhcp-client-identifier")) { if (host -> client_identifier.data) return ISC_R_EXISTS; if (value && (value -> type == omapi_datatype_data || value -> type == omapi_datatype_string)) { if (!buffer_allocate (&host -> client_identifier.buffer, value -> u.buffer.len, MDL)) return ISC_R_NOMEMORY; host -> client_identifier.data = &host -> client_identifier.buffer -> data [0]; memcpy (host -> client_identifier.buffer -> data, value -> u.buffer.value, value -> u.buffer.len); host -> client_identifier.len = value -> u.buffer.len; } else return DHCP_R_INVALIDARG; return ISC_R_SUCCESS; } if (!omapi_ds_strcmp (name, "ip-address")) { if (host -> fixed_addr) option_cache_dereference (&host -> fixed_addr, MDL); if (!value) return ISC_R_SUCCESS; if (value && (value -> type == omapi_datatype_data || value -> type == omapi_datatype_string)) { struct data_string ds; memset (&ds, 0, sizeof ds); ds.len = value -> u.buffer.len; if (!buffer_allocate (&ds.buffer, ds.len, MDL)) return ISC_R_NOMEMORY; ds.data = (&ds.buffer -> data [0]); memcpy (ds.buffer -> data, value -> u.buffer.value, ds.len); if (!option_cache (&host -> fixed_addr, &ds, (struct expression *)0, (struct option *)0, MDL)) { data_string_forget (&ds, MDL); return ISC_R_NOMEMORY; } data_string_forget (&ds, MDL); } else return DHCP_R_INVALIDARG; return ISC_R_SUCCESS; } if (!omapi_ds_strcmp (name, "statements")) { if (!host -> group) { if (!clone_group (&host -> group, root_group, MDL)) return ISC_R_NOMEMORY; } else { if (host -> group -> statements && (!host -> named_group || host -> group != host -> named_group -> group) && host -> group != root_group) return ISC_R_EXISTS; if (!clone_group (&host -> group, host -> group, MDL)) return ISC_R_NOMEMORY; } if (!host -> group) return ISC_R_NOMEMORY; if (value && (value -> type == omapi_datatype_data || value -> type == omapi_datatype_string)) { struct parse *parse; int lose = 0; parse = (struct parse *)0; status = new_parse(&parse, -1, (char *) value->u.buffer.value, value->u.buffer.len, "network client", 0); if (status != ISC_R_SUCCESS || parse == NULL) return status; if (!(parse_executable_statements (&host -> group -> statements, parse, &lose, context_any))) { end_parse (&parse); return DHCP_R_BADPARSE; } end_parse (&parse); } else return DHCP_R_INVALIDARG; return ISC_R_SUCCESS; } /* The "known" flag isn't supported in the database yet, but it's legitimate. */ if (!omapi_ds_strcmp (name, "known")) { return ISC_R_SUCCESS; } /* Try to find some inner object that can take the value. */ if (h -> inner && h -> inner -> type -> set_value) { status = ((*(h -> inner -> type -> set_value)) (h -> inner, id, name, value)); if (status == ISC_R_SUCCESS || status == DHCP_R_UNCHANGED) return status; } return DHCP_R_UNKNOWNATTRIBUTE; } isc_result_t dhcp_host_get_value (omapi_object_t *h, omapi_object_t *id, omapi_data_string_t *name, omapi_value_t **value) { struct host_decl *host; isc_result_t status; struct data_string ip_addrs; if (h -> type != dhcp_type_host) return DHCP_R_INVALIDARG; host = (struct host_decl *)h; if (!omapi_ds_strcmp (name, "ip-addresses")) { memset (&ip_addrs, 0, sizeof ip_addrs); if (host -> fixed_addr && evaluate_option_cache (&ip_addrs, (struct packet *)0, (struct lease *)0, (struct client_state *)0, (struct option_state *)0, (struct option_state *)0, &global_scope, host -> fixed_addr, MDL)) { status = omapi_make_const_value (value, name, ip_addrs.data, ip_addrs.len, MDL); data_string_forget (&ip_addrs, MDL); return status; } return ISC_R_NOTFOUND; } if (!omapi_ds_strcmp (name, "dhcp-client-identifier")) { if (!host -> client_identifier.len) return ISC_R_NOTFOUND; return omapi_make_const_value (value, name, host -> client_identifier.data, host -> client_identifier.len, MDL); } if (!omapi_ds_strcmp (name, "name")) return omapi_make_string_value (value, name, host -> name, MDL); if (!omapi_ds_strcmp (name, "hardware-address")) { if (!host -> interface.hlen) return ISC_R_NOTFOUND; return (omapi_make_const_value (value, name, &host -> interface.hbuf [1], (unsigned long)(host -> interface.hlen - 1), MDL)); } if (!omapi_ds_strcmp (name, "hardware-type")) { if (!host -> interface.hlen) return ISC_R_NOTFOUND; return omapi_make_int_value (value, name, host -> interface.hbuf [0], MDL); } /* Try to find some inner object that can take the value. */ if (h -> inner && h -> inner -> type -> get_value) { status = ((*(h -> inner -> type -> get_value)) (h -> inner, id, name, value)); if (status == ISC_R_SUCCESS) return status; } return DHCP_R_UNKNOWNATTRIBUTE; } isc_result_t dhcp_host_destroy (omapi_object_t *h, const char *file, int line) { if (h -> type != dhcp_type_host) return DHCP_R_INVALIDARG; #if defined (DEBUG_MEMORY_LEAKAGE) || \ defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT) struct host_decl *host = (struct host_decl *)h; if (host -> n_ipaddr) host_dereference (&host -> n_ipaddr, file, line); if (host -> n_dynamic) host_dereference (&host -> n_dynamic, file, line); if (host -> name) { dfree (host -> name, file, line); host -> name = (char *)0; } data_string_forget (&host -> client_identifier, file, line); if (host -> fixed_addr) option_cache_dereference (&host -> fixed_addr, file, line); if (host -> group) group_dereference (&host -> group, file, line); if (host -> named_group) omapi_object_dereference ((omapi_object_t **) &host -> named_group, file, line); data_string_forget (&host -> auth_key_id, file, line); #endif return ISC_R_SUCCESS; } isc_result_t dhcp_host_signal_handler (omapi_object_t *h, const char *name, va_list ap) { struct host_decl *host; isc_result_t status; int updatep = 0; if (h -> type != dhcp_type_host) return DHCP_R_INVALIDARG; host = (struct host_decl *)h; if (!strcmp (name, "updated")) { /* There must be a client identifier of some sort. */ if (host -> interface.hlen == 0 && !host -> client_identifier.len) return DHCP_R_INVALIDARG; if (!host -> name) { char hnbuf [64]; sprintf (hnbuf, "nh%08lx%08lx", (unsigned long)cur_time, (unsigned long)host); host -> name = dmalloc (strlen (hnbuf) + 1, MDL); if (!host -> name) return ISC_R_NOMEMORY; strcpy (host -> name, hnbuf); } #ifdef DEBUG_OMAPI log_debug ("OMAPI added host %s", host -> name); #endif status = enter_host (host, 1, 1); if (status != ISC_R_SUCCESS) return status; updatep = 1; } /* Try to find some inner object that can take the value. */ if (h -> inner && h -> inner -> type -> signal_handler) { status = ((*(h -> inner -> type -> signal_handler)) (h -> inner, name, ap)); if (status == ISC_R_SUCCESS) return status; } if (updatep) return ISC_R_SUCCESS; return ISC_R_NOTFOUND; } isc_result_t dhcp_host_stuff_values (omapi_object_t *c, omapi_object_t *id, omapi_object_t *h) { struct host_decl *host; isc_result_t status; struct data_string ip_addrs; if (h -> type != dhcp_type_host) return DHCP_R_INVALIDARG; host = (struct host_decl *)h; /* Write out all the values. */ memset (&ip_addrs, 0, sizeof ip_addrs); if (host -> fixed_addr && evaluate_option_cache (&ip_addrs, (struct packet *)0, (struct lease *)0, (struct client_state *)0, (struct option_state *)0, (struct option_state *)0, &global_scope, host -> fixed_addr, MDL)) { status = omapi_connection_put_name (c, "ip-address"); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_put_uint32 (c, ip_addrs.len); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_copyin (c, ip_addrs.data, ip_addrs.len); if (status != ISC_R_SUCCESS) return status; } if (host -> client_identifier.len) { status = omapi_connection_put_name (c, "dhcp-client-identifier"); if (status != ISC_R_SUCCESS) return status; status = (omapi_connection_put_uint32 (c, host -> client_identifier.len)); if (status != ISC_R_SUCCESS) return status; status = (omapi_connection_copyin (c, host -> client_identifier.data, host -> client_identifier.len)); if (status != ISC_R_SUCCESS) return status; } if (host -> name) { status = omapi_connection_put_name (c, "name"); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_put_string (c, host -> name); if (status != ISC_R_SUCCESS) return status; } if (host -> interface.hlen) { status = omapi_connection_put_name (c, "hardware-address"); if (status != ISC_R_SUCCESS) return status; status = (omapi_connection_put_uint32 (c, (unsigned long)(host -> interface.hlen - 1))); if (status != ISC_R_SUCCESS) return status; status = (omapi_connection_copyin (c, &host -> interface.hbuf [1], (unsigned long)(host -> interface.hlen - 1))); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_put_name (c, "hardware-type"); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_put_uint32 (c, sizeof (int)); if (status != ISC_R_SUCCESS) return status; status = (omapi_connection_put_uint32 (c, host -> interface.hbuf [0])); if (status != ISC_R_SUCCESS) return status; } /* Write out the inner object, if any. */ if (h -> inner && h -> inner -> type -> stuff_values) { status = ((*(h -> inner -> type -> stuff_values)) (c, id, h -> inner)); if (status == ISC_R_SUCCESS) return status; } return ISC_R_SUCCESS; } isc_result_t dhcp_host_lookup (omapi_object_t **lp, omapi_object_t *id, omapi_object_t *ref) { omapi_value_t *tv = (omapi_value_t *)0; isc_result_t status; struct host_decl *host; if (!ref) return DHCP_R_NOKEYS; /* First see if we were sent a handle. */ status = omapi_get_value_str (ref, id, "handle", &tv); if (status == ISC_R_SUCCESS) { status = omapi_handle_td_lookup (lp, tv -> value); omapi_value_dereference (&tv, MDL); if (status != ISC_R_SUCCESS) return status; /* Don't return the object if the type is wrong. */ if ((*lp) -> type != dhcp_type_host) { omapi_object_dereference (lp, MDL); return DHCP_R_INVALIDARG; } if (((struct host_decl *)(*lp)) -> flags & HOST_DECL_DELETED) { omapi_object_dereference (lp, MDL); } } /* Now look for a client identifier. */ status = omapi_get_value_str (ref, id, "dhcp-client-identifier", &tv); if (status == ISC_R_SUCCESS) { host = (struct host_decl *)0; host_hash_lookup (&host, host_uid_hash, tv -> value -> u.buffer.value, tv -> value -> u.buffer.len, MDL); omapi_value_dereference (&tv, MDL); if (*lp && *lp != (omapi_object_t *)host) { omapi_object_dereference (lp, MDL); if (host) host_dereference (&host, MDL); return DHCP_R_KEYCONFLICT; } else if (!host || (host -> flags & HOST_DECL_DELETED)) { if (*lp) omapi_object_dereference (lp, MDL); if (host) host_dereference (&host, MDL); return ISC_R_NOTFOUND; } else if (!*lp) { /* XXX fix so that hash lookup itself creates XXX the reference. */ omapi_object_reference (lp, (omapi_object_t *)host, MDL); host_dereference (&host, MDL); } } /* Now look for a hardware address. */ status = omapi_get_value_str (ref, id, "hardware-address", &tv); if (status == ISC_R_SUCCESS) { unsigned char *haddr; unsigned int len; len = tv -> value -> u.buffer.len + 1; haddr = dmalloc (len, MDL); if (!haddr) { omapi_value_dereference (&tv, MDL); return ISC_R_NOMEMORY; } memcpy (haddr + 1, tv -> value -> u.buffer.value, len - 1); omapi_value_dereference (&tv, MDL); status = omapi_get_value_str (ref, id, "hardware-type", &tv); if (status == ISC_R_SUCCESS) { if (tv -> value -> type == omapi_datatype_data) { if ((tv -> value -> u.buffer.len != 4) || (tv -> value -> u.buffer.value[0] != 0) || (tv -> value -> u.buffer.value[1] != 0) || (tv -> value -> u.buffer.value[2] != 0)) { omapi_value_dereference (&tv, MDL); dfree (haddr, MDL); return DHCP_R_INVALIDARG; } haddr[0] = tv -> value -> u.buffer.value[3]; } else if (tv -> value -> type == omapi_datatype_int) { haddr[0] = (unsigned char) tv -> value -> u.integer; } else { omapi_value_dereference (&tv, MDL); dfree (haddr, MDL); return DHCP_R_INVALIDARG; } omapi_value_dereference (&tv, MDL); } else { /* If no hardware-type is specified, default to ethernet. This may or may not be a good idea, but Telus is currently relying on this behavior. - DPN */ haddr[0] = HTYPE_ETHER; } host = (struct host_decl *)0; host_hash_lookup (&host, host_hw_addr_hash, haddr, len, MDL); dfree (haddr, MDL); if (*lp && *lp != (omapi_object_t *)host) { omapi_object_dereference (lp, MDL); if (host) host_dereference (&host, MDL); return DHCP_R_KEYCONFLICT; } else if (!host || (host -> flags & HOST_DECL_DELETED)) { if (*lp) omapi_object_dereference (lp, MDL); if (host) host_dereference (&host, MDL); return ISC_R_NOTFOUND; } else if (!*lp) { /* XXX fix so that hash lookup itself creates XXX the reference. */ omapi_object_reference (lp, (omapi_object_t *)host, MDL); host_dereference (&host, MDL); } } /* Now look for an ip address. */ status = omapi_get_value_str (ref, id, "ip-address", &tv); if (status == ISC_R_SUCCESS) { struct lease *l; /* first find the lease for this ip address */ l = (struct lease *)0; lease_ip_hash_lookup(&l, lease_ip_addr_hash, tv->value->u.buffer.value, tv->value->u.buffer.len, MDL); omapi_value_dereference (&tv, MDL); if (!l && !*lp) return ISC_R_NOTFOUND; if (l) { /* now use that to get a host */ host = (struct host_decl *)0; host_hash_lookup (&host, host_hw_addr_hash, l -> hardware_addr.hbuf, l -> hardware_addr.hlen, MDL); if (host && *lp && *lp != (omapi_object_t *)host) { omapi_object_dereference (lp, MDL); if (host) host_dereference (&host, MDL); return DHCP_R_KEYCONFLICT; } else if (!host || (host -> flags & HOST_DECL_DELETED)) { if (host) host_dereference (&host, MDL); if (!*lp) return ISC_R_NOTFOUND; } else if (!*lp) { /* XXX fix so that hash lookup itself creates XXX the reference. */ omapi_object_reference (lp, (omapi_object_t *)host, MDL); host_dereference (&host, MDL); } lease_dereference (&l, MDL); } } /* Now look for a name. */ status = omapi_get_value_str (ref, id, "name", &tv); if (status == ISC_R_SUCCESS) { host = (struct host_decl *)0; host_hash_lookup (&host, host_name_hash, tv -> value -> u.buffer.value, tv -> value -> u.buffer.len, MDL); omapi_value_dereference (&tv, MDL); if (*lp && *lp != (omapi_object_t *)host) { omapi_object_dereference (lp, MDL); if (host) host_dereference (&host, MDL); return DHCP_R_KEYCONFLICT; } else if (!host || (host -> flags & HOST_DECL_DELETED)) { if (host) host_dereference (&host, MDL); return ISC_R_NOTFOUND; } else if (!*lp) { /* XXX fix so that hash lookup itself creates XXX the reference. */ omapi_object_reference (lp, (omapi_object_t *)host, MDL); host_dereference (&host, MDL); } } /* If we get to here without finding a host, no valid key was specified. */ if (!*lp) return DHCP_R_NOKEYS; return ISC_R_SUCCESS; } isc_result_t dhcp_host_create (omapi_object_t **lp, omapi_object_t *id) { struct host_decl *hp; isc_result_t status; hp = (struct host_decl *)0; status = host_allocate (&hp, MDL); if (status != ISC_R_SUCCESS) return status; group_reference (&hp -> group, root_group, MDL); hp -> flags = HOST_DECL_DYNAMIC; status = omapi_object_reference (lp, (omapi_object_t *)hp, MDL); host_dereference (&hp, MDL); return status; } isc_result_t dhcp_host_remove (omapi_object_t *lp, omapi_object_t *id) { struct host_decl *hp; if (lp -> type != dhcp_type_host) return DHCP_R_INVALIDARG; hp = (struct host_decl *)lp; #ifdef DEBUG_OMAPI log_debug ("OMAPI delete host %s", hp -> name); #endif delete_host (hp, 1); return ISC_R_SUCCESS; } isc_result_t dhcp_pool_set_value (omapi_object_t *h, omapi_object_t *id, omapi_data_string_t *name, omapi_typed_data_t *value) { /* h should point to (struct pool *) */ isc_result_t status; if (h -> type != dhcp_type_pool) return DHCP_R_INVALIDARG; /* No values to set yet. */ /* Try to find some inner object that can take the value. */ if (h -> inner && h -> inner -> type -> set_value) { status = ((*(h -> inner -> type -> set_value)) (h -> inner, id, name, value)); if (status == ISC_R_SUCCESS || status == DHCP_R_UNCHANGED) return status; } return DHCP_R_UNKNOWNATTRIBUTE; } isc_result_t dhcp_pool_get_value (omapi_object_t *h, omapi_object_t *id, omapi_data_string_t *name, omapi_value_t **value) { /* h should point to (struct pool *) */ isc_result_t status; if (h -> type != dhcp_type_pool) return DHCP_R_INVALIDARG; /* No values to get yet. */ /* Try to find some inner object that can provide the value. */ if (h -> inner && h -> inner -> type -> get_value) { status = ((*(h -> inner -> type -> get_value)) (h -> inner, id, name, value)); if (status == ISC_R_SUCCESS) return status; } return DHCP_R_UNKNOWNATTRIBUTE; } isc_result_t dhcp_pool_destroy (omapi_object_t *h, const char *file, int line) { #if defined (DEBUG_MEMORY_LEAKAGE) || \ defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT) struct permit *pc, *pn; #endif if (h -> type != dhcp_type_pool) return DHCP_R_INVALIDARG; #if defined (DEBUG_MEMORY_LEAKAGE) || \ defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT) struct pool *pool = (struct pool *)h; if (pool -> next) pool_dereference (&pool -> next, file, line); if (pool -> group) group_dereference (&pool -> group, file, line); if (pool -> shared_network) shared_network_dereference (&pool -> shared_network, file, line); if (pool -> active) lease_dereference (&pool -> active, file, line); if (pool -> expired) lease_dereference (&pool -> expired, file, line); if (pool -> free) lease_dereference (&pool -> free, file, line); if (pool -> backup) lease_dereference (&pool -> backup, file, line); if (pool -> abandoned) lease_dereference (&pool -> abandoned, file, line); #if defined (FAILOVER_PROTOCOL) if (pool -> failover_peer) dhcp_failover_state_dereference (&pool -> failover_peer, file, line); #endif for (pc = pool -> permit_list; pc; pc = pn) { pn = pc -> next; free_permit (pc, file, line); } pool -> permit_list = (struct permit *)0; for (pc = pool -> prohibit_list; pc; pc = pn) { pn = pc -> next; free_permit (pc, file, line); } pool -> prohibit_list = (struct permit *)0; #endif return ISC_R_SUCCESS; } isc_result_t dhcp_pool_signal_handler (omapi_object_t *h, const char *name, va_list ap) { /* h should point to (struct pool *) */ isc_result_t status; int updatep = 0; if (h -> type != dhcp_type_pool) return DHCP_R_INVALIDARG; /* Can't write pools yet. */ /* Try to find some inner object that can take the value. */ if (h -> inner && h -> inner -> type -> signal_handler) { status = ((*(h -> inner -> type -> signal_handler)) (h -> inner, name, ap)); if (status == ISC_R_SUCCESS) return status; } if (updatep) return ISC_R_SUCCESS; return ISC_R_NOTFOUND; } isc_result_t dhcp_pool_stuff_values (omapi_object_t *c, omapi_object_t *id, omapi_object_t *h) { /* h should point to (struct pool *) */ isc_result_t status; if (h -> type != dhcp_type_pool) return DHCP_R_INVALIDARG; /* Can't stuff pool values yet. */ /* Write out the inner object, if any. */ if (h -> inner && h -> inner -> type -> stuff_values) { status = ((*(h -> inner -> type -> stuff_values)) (c, id, h -> inner)); if (status == ISC_R_SUCCESS) return status; } return ISC_R_SUCCESS; } isc_result_t dhcp_pool_lookup (omapi_object_t **lp, omapi_object_t *id, omapi_object_t *ref) { /* Can't look up pools yet. */ /* If we get to here without finding a pool, no valid key was specified. */ if (!*lp) return DHCP_R_NOKEYS; return ISC_R_SUCCESS; } isc_result_t dhcp_pool_create (omapi_object_t **lp, omapi_object_t *id) { return ISC_R_NOTIMPLEMENTED; } isc_result_t dhcp_pool_remove (omapi_object_t *lp, omapi_object_t *id) { return ISC_R_NOTIMPLEMENTED; } static isc_result_t class_set_value (omapi_object_t *h, omapi_object_t *id, omapi_data_string_t *name, omapi_typed_data_t *value) { struct class *class; struct class *superclass = 0; isc_result_t status; int issubclass = (h -> type == dhcp_type_subclass); class = (struct class *)h; if (!omapi_ds_strcmp(name, "name")) { char *tname; if (class->name) return ISC_R_EXISTS; if ((tname = dmalloc(value->u.buffer.len + 1, MDL)) == NULL) { return ISC_R_NOMEMORY; } /* tname is null terminated from dmalloc() */ memcpy(tname, value->u.buffer.value, value->u.buffer.len); if (issubclass) { status = find_class(&superclass, tname, MDL); dfree(tname, MDL); if (status == ISC_R_NOTFOUND) return status; if (class->superclass != NULL) class_dereference(&class->superclass, MDL); class_reference(&class->superclass, superclass, MDL); } else if (value -> type == omapi_datatype_data || value -> type == omapi_datatype_string) { class->name = dmalloc(value->u.buffer.len + 1, MDL); if (!class->name) return ISC_R_NOMEMORY; /* class->name is null-terminated from dmalloc() */ memcpy(class->name, value->u.buffer.value, value->u.buffer.len); } else return DHCP_R_INVALIDARG; return ISC_R_SUCCESS; } if (issubclass && !omapi_ds_strcmp(name, "hashstring")) { if (class->hash_string.data) return ISC_R_EXISTS; if (value->type == omapi_datatype_data || value->type == omapi_datatype_string) { if (!buffer_allocate(&class->hash_string.buffer, value->u.buffer.len, MDL)) return ISC_R_NOMEMORY; class->hash_string.data = class->hash_string.buffer->data; memcpy(class->hash_string.buffer->data, value->u.buffer.value, value->u.buffer.len); class->hash_string.len = value->u.buffer.len; } else return DHCP_R_INVALIDARG; return ISC_R_SUCCESS; } if (!omapi_ds_strcmp(name, "group")) { if (value->type == omapi_datatype_data || value->type == omapi_datatype_string) { struct group_object *group = NULL; group_hash_lookup(&group, group_name_hash, (char *)value->u.buffer.value, value->u.buffer.len, MDL); if (!group || (group->flags & GROUP_OBJECT_DELETED)) return ISC_R_NOTFOUND; if (class->group) group_dereference(&class->group, MDL); group_reference(&class->group, group->group, MDL); group_object_dereference(&group, MDL); } else return DHCP_R_INVALIDARG; return ISC_R_SUCCESS; } /* note we do not support full expressions via omapi because the expressions parser needs to be re-done to support parsing from strings and not just files. */ if (!omapi_ds_strcmp(name, "match")) { if (value->type == omapi_datatype_data || value->type == omapi_datatype_string) { unsigned minlen = (value->u.buffer.len > 8 ? 8 : value->u.buffer.len); if (!strncmp("hardware", (char *)value->u.buffer.value, minlen)) { if (!expression_allocate(&class->submatch, MDL)) return ISC_R_NOMEMORY; class->submatch->op = expr_hardware; } else return DHCP_R_INVALIDARG; } else return DHCP_R_INVALIDARG; return ISC_R_SUCCESS; } if (!omapi_ds_strcmp(name, "option")) { if (value->type == omapi_datatype_data || value->type == omapi_datatype_string) { /* XXXJAB support 'options' here. */ /* XXXJAB specifically 'bootfile-name' */ return DHCP_R_INVALIDARG; /* XXX tmp */ } else return DHCP_R_INVALIDARG; /* * Currently no way to get here, if we update the above * code so that we do get here this return needs to be * uncommented. * return ISC_R_SUCCESS; */ } /* Try to find some inner object that can take the value. */ if (h->inner && h->inner->type->set_value) { status = ((*(h->inner->type->set_value)) (h->inner, id, name, value)); if (status == ISC_R_SUCCESS || status == DHCP_R_UNCHANGED) return status; } return DHCP_R_UNKNOWNATTRIBUTE; } isc_result_t dhcp_class_set_value (omapi_object_t *h, omapi_object_t *id, omapi_data_string_t *name, omapi_typed_data_t *value) { if (h -> type != dhcp_type_class) return DHCP_R_INVALIDARG; return class_set_value(h, id, name, value); } isc_result_t dhcp_class_get_value (omapi_object_t *h, omapi_object_t *id, omapi_data_string_t *name, omapi_value_t **value) { struct class *class; isc_result_t status; if (h -> type != dhcp_type_class) return DHCP_R_INVALIDARG; class = (struct class *)h; if (!omapi_ds_strcmp (name, "name")) return omapi_make_string_value (value, name, class -> name, MDL); /* Try to find some inner object that can provide the value. */ if (h -> inner && h -> inner -> type -> get_value) { status = ((*(h -> inner -> type -> get_value)) (h -> inner, id, name, value)); if (status == ISC_R_SUCCESS) return status; } return DHCP_R_UNKNOWNATTRIBUTE; } isc_result_t dhcp_class_destroy (omapi_object_t *h, const char *file, int line) { if (h -> type != dhcp_type_class && h -> type != dhcp_type_subclass) return DHCP_R_INVALIDARG; #if defined (DEBUG_MEMORY_LEAKAGE) || \ defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT) struct class *class = (struct class *)h; if (class -> nic) class_dereference (&class -> nic, file, line); if (class -> superclass) class_dereference (&class -> superclass, file, line); if (class -> name) { dfree (class -> name, file, line); class -> name = (char *)0; } if (class -> billed_leases) { int i; for (i = 0; i < class -> lease_limit; i++) { if (class -> billed_leases [i]) { lease_dereference (&class -> billed_leases [i], file, line); } } dfree (class -> billed_leases, file, line); class -> billed_leases = (struct lease **)0; } if (class -> hash) { class_free_hash_table (&class -> hash, file, line); class -> hash = (class_hash_t *)0; } data_string_forget (&class -> hash_string, file, line); if (class -> expr) expression_dereference (&class -> expr, file, line); if (class -> submatch) expression_dereference (&class -> submatch, file, line); if (class -> group) group_dereference (&class -> group, file, line); if (class -> statements) executable_statement_dereference (&class -> statements, file, line); if (class -> superclass) class_dereference (&class -> superclass, file, line); #endif return ISC_R_SUCCESS; } static isc_result_t class_signal_handler(omapi_object_t *h, const char *name, va_list ap) { struct class *class = (struct class *)h; isc_result_t status; int updatep = 0; int issubclass; issubclass = (h -> type == dhcp_type_subclass); if (!strcmp (name, "updated")) { if (!issubclass) { if (class -> name == 0 || strlen(class -> name) == 0) { return DHCP_R_INVALIDARG; } } else { if (class -> superclass == 0) { return DHCP_R_INVALIDARG; /* didn't give name */ } if (class -> hash_string.data == NULL) { return DHCP_R_INVALIDARG; } } if (issubclass) { if (!class -> superclass -> hash) class_new_hash(&class->superclass->hash, SCLASS_HASH_SIZE, MDL); add_hash (class -> superclass -> hash, class -> hash_string.data, class -> hash_string.len, (void *)class, MDL); } #ifdef DEBUG_OMAPI if (issubclass) { log_debug ("OMAPI added subclass %s", class -> superclass -> name); } else { log_debug ("OMAPI added class %s", class -> name); } #endif status = enter_class (class, 1, 1); if (status != ISC_R_SUCCESS) return status; updatep = 1; } /* Try to find some inner object that can take the value. */ if (h -> inner && h -> inner -> type -> signal_handler) { status = ((*(h -> inner -> type -> signal_handler)) (h -> inner, name, ap)); if (status == ISC_R_SUCCESS) return status; } if (updatep) return ISC_R_SUCCESS; return ISC_R_NOTFOUND; } isc_result_t dhcp_class_signal_handler (omapi_object_t *h, const char *name, va_list ap) { if (h -> type != dhcp_type_class) return DHCP_R_INVALIDARG; return class_signal_handler(h, name, ap); } isc_result_t dhcp_class_stuff_values (omapi_object_t *c, omapi_object_t *id, omapi_object_t *h) { /* h should point to (struct class *) */ isc_result_t status; if (h -> type != dhcp_type_class) return DHCP_R_INVALIDARG; /* Can't stuff class values yet. */ /* Write out the inner object, if any. */ if (h -> inner && h -> inner -> type -> stuff_values) { status = ((*(h -> inner -> type -> stuff_values)) (c, id, h -> inner)); if (status == ISC_R_SUCCESS) return status; } return ISC_R_SUCCESS; } static isc_result_t class_lookup (omapi_object_t **lp, omapi_object_t *id, omapi_object_t *ref, omapi_object_type_t *typewanted) { omapi_value_t *nv = (omapi_value_t *)0; omapi_value_t *hv = (omapi_value_t *)0; isc_result_t status; struct class *class = 0; struct class *subclass = 0; *lp = NULL; /* see if we have a name */ status = omapi_get_value_str (ref, id, "name", &nv); if (status == ISC_R_SUCCESS) { char *name = dmalloc(nv -> value -> u.buffer.len + 1, MDL); memcpy (name, nv -> value -> u.buffer.value, nv -> value -> u.buffer.len); omapi_value_dereference (&nv, MDL); find_class(&class, name, MDL); dfree(name, MDL); if (class == NULL) { return ISC_R_NOTFOUND; } if (typewanted == dhcp_type_subclass) { status = omapi_get_value_str (ref, id, "hashstring", &hv); if (status != ISC_R_SUCCESS) { class_dereference(&class, MDL); return DHCP_R_NOKEYS; } if (hv -> value -> type != omapi_datatype_data && hv -> value -> type != omapi_datatype_string) { class_dereference(&class, MDL); omapi_value_dereference (&hv, MDL); return DHCP_R_NOKEYS; } class_hash_lookup (&subclass, class -> hash, (const char *) hv -> value -> u.buffer.value, hv -> value -> u.buffer.len, MDL); omapi_value_dereference (&hv, MDL); class_dereference(&class, MDL); if (subclass == NULL) { return ISC_R_NOTFOUND; } class_reference(&class, subclass, MDL); class_dereference(&subclass, MDL); } /* Don't return the object if the type is wrong. */ if (class -> type != typewanted) { class_dereference (&class, MDL); return DHCP_R_INVALIDARG; } if (class -> flags & CLASS_DECL_DELETED) { class_dereference (&class, MDL); } omapi_object_reference(lp, (omapi_object_t *)class, MDL); return ISC_R_SUCCESS; } return DHCP_R_NOKEYS; } isc_result_t dhcp_class_lookup (omapi_object_t **lp, omapi_object_t *id, omapi_object_t *ref) { return class_lookup(lp, id, ref, dhcp_type_class); } isc_result_t dhcp_class_create (omapi_object_t **lp, omapi_object_t *id) { struct class *cp = 0; isc_result_t status; status = class_allocate(&cp, MDL); if (status != ISC_R_SUCCESS) return status; group_reference (&cp -> group, root_group, MDL); cp -> flags = CLASS_DECL_DYNAMIC; status = omapi_object_reference (lp, (omapi_object_t *)cp, MDL); class_dereference (&cp, MDL); return status; } isc_result_t dhcp_class_remove (omapi_object_t *lp, omapi_object_t *id) { struct class *cp; if (lp -> type != dhcp_type_class) return DHCP_R_INVALIDARG; cp = (struct class *)lp; #ifdef DEBUG_OMAPI log_debug ("OMAPI delete class %s", cp -> name); #endif delete_class (cp, 1); return ISC_R_SUCCESS; } isc_result_t dhcp_subclass_set_value (omapi_object_t *h, omapi_object_t *id, omapi_data_string_t *name, omapi_typed_data_t *value) { if (h -> type != dhcp_type_subclass) return DHCP_R_INVALIDARG; return class_set_value(h, id, name, value); } isc_result_t dhcp_subclass_get_value (omapi_object_t *h, omapi_object_t *id, omapi_data_string_t *name, omapi_value_t **value) { struct class *subclass; isc_result_t status; if (h -> type != dhcp_type_class) return DHCP_R_INVALIDARG; subclass = (struct class *)h; if (subclass -> name != 0) return DHCP_R_INVALIDARG; /* XXXJAB No values to get yet. */ /* Try to find some inner object that can provide the value. */ if (h -> inner && h -> inner -> type -> get_value) { status = ((*(h -> inner -> type -> get_value)) (h -> inner, id, name, value)); if (status == ISC_R_SUCCESS) return status; } return DHCP_R_UNKNOWNATTRIBUTE; } isc_result_t dhcp_subclass_signal_handler (omapi_object_t *h, const char *name, va_list ap) { if (h -> type != dhcp_type_subclass) return DHCP_R_INVALIDARG; return class_signal_handler(h, name, ap); } isc_result_t dhcp_subclass_stuff_values (omapi_object_t *c, omapi_object_t *id, omapi_object_t *h) { struct class *subclass; isc_result_t status; if (h -> type != dhcp_type_class) return DHCP_R_INVALIDARG; subclass = (struct class *)h; if (subclass -> name != 0) return DHCP_R_INVALIDARG; /* Can't stuff subclass values yet. */ /* Write out the inner object, if any. */ if (h -> inner && h -> inner -> type -> stuff_values) { status = ((*(h -> inner -> type -> stuff_values)) (c, id, h -> inner)); if (status == ISC_R_SUCCESS) return status; } return ISC_R_SUCCESS; } isc_result_t dhcp_subclass_lookup (omapi_object_t **lp, omapi_object_t *id, omapi_object_t *ref) { return class_lookup(lp, id, ref, dhcp_type_subclass); } isc_result_t dhcp_subclass_create (omapi_object_t **lp, omapi_object_t *id) { struct class *cp = 0; isc_result_t status; /* * XXX * NOTE: subclasses and classes have the same internal type, which makes it * difficult to tell them apart. Specifically, in this function we need to * create a class object (because there is no such thing as a subclass * object), but one field of the class object is the type (which has the * value dhcp_type_class), and it is from here that all the other omapi * functions are accessed. So, even though there's a whole suite of * subclass functions registered, they won't get used. Now we could change * the type pointer after creating the class object, but I'm not certain * that won't break something else. */ status = subclass_allocate(&cp, MDL); if (status != ISC_R_SUCCESS) return status; group_reference (&cp -> group, root_group, MDL); cp -> flags = CLASS_DECL_DYNAMIC; status = omapi_object_reference (lp, (omapi_object_t *)cp, MDL); subclass_dereference (&cp, MDL); return status; } isc_result_t dhcp_subclass_remove (omapi_object_t *lp, omapi_object_t *id) { #if 1 log_fatal("calling dhcp_subclass_set_value"); /* this should never be called see dhcp_subclass_create for why */ #else struct class *cp; if (lp -> type != dhcp_type_subclass) return DHCP_R_INVALIDARG; cp = (struct class *)lp; #ifdef DEBUG_OMAPI log_debug ("OMAPI delete subclass %s", cp -> name); #endif delete_class (cp, 1); #endif return ISC_R_SUCCESS; } isc_result_t binding_scope_set_value (struct binding_scope *scope, int createp, omapi_data_string_t *name, omapi_typed_data_t *value) { struct binding *bp; char *nname; struct binding_value *nv; nname = dmalloc (name -> len + 1, MDL); if (!nname) return ISC_R_NOMEMORY; memcpy (nname, name -> value, name -> len); nname [name -> len] = 0; bp = find_binding (scope, nname); if (!bp && !createp) { dfree (nname, MDL); return DHCP_R_UNKNOWNATTRIBUTE; } if (!value) { dfree (nname, MDL); if (!bp) return DHCP_R_UNKNOWNATTRIBUTE; binding_value_dereference (&bp -> value, MDL); return ISC_R_SUCCESS; } nv = (struct binding_value *)0; if (!binding_value_allocate (&nv, MDL)) { dfree (nname, MDL); return ISC_R_NOMEMORY; } switch (value -> type) { case omapi_datatype_int: nv -> type = binding_numeric; nv -> value.intval = value -> u.integer; break; case omapi_datatype_string: case omapi_datatype_data: if (!buffer_allocate (&nv -> value.data.buffer, value -> u.buffer.len, MDL)) { binding_value_dereference (&nv, MDL); dfree (nname, MDL); return ISC_R_NOMEMORY; } memcpy (&nv -> value.data.buffer -> data [1], value -> u.buffer.value, value -> u.buffer.len); nv -> value.data.len = value -> u.buffer.len; break; case omapi_datatype_object: binding_value_dereference (&nv, MDL); dfree (nname, MDL); return DHCP_R_INVALIDARG; } if (!bp) { bp = dmalloc (sizeof *bp, MDL); if (!bp) { binding_value_dereference (&nv, MDL); dfree (nname, MDL); return ISC_R_NOMEMORY; } memset (bp, 0, sizeof *bp); bp -> name = nname; nname = (char *)0; bp -> next = scope -> bindings; scope -> bindings = bp; } else { if (bp -> value) binding_value_dereference (&bp -> value, MDL); dfree (nname, MDL); } binding_value_reference (&bp -> value, nv, MDL); binding_value_dereference (&nv, MDL); return ISC_R_SUCCESS; } isc_result_t binding_scope_get_value (omapi_value_t **value, struct binding_scope *scope, omapi_data_string_t *name) { struct binding *bp; omapi_typed_data_t *td; isc_result_t status; char *nname; nname = dmalloc (name -> len + 1, MDL); if (!nname) return ISC_R_NOMEMORY; memcpy (nname, name -> value, name -> len); nname [name -> len] = 0; bp = find_binding (scope, nname); dfree (nname, MDL); if (!bp) return DHCP_R_UNKNOWNATTRIBUTE; if (!bp -> value) return DHCP_R_UNKNOWNATTRIBUTE; switch (bp -> value -> type) { case binding_boolean: td = (omapi_typed_data_t *)0; status = omapi_typed_data_new (MDL, &td, omapi_datatype_int, bp -> value -> value.boolean); break; case binding_numeric: td = (omapi_typed_data_t *)0; status = omapi_typed_data_new (MDL, &td, omapi_datatype_int, (int) bp -> value -> value.intval); break; case binding_data: td = (omapi_typed_data_t *)0; status = omapi_typed_data_new (MDL, &td, omapi_datatype_data, bp -> value -> value.data.len); if (status != ISC_R_SUCCESS) return status; memcpy (&td -> u.buffer.value [0], bp -> value -> value.data.data, bp -> value -> value.data.len); break; /* Can't return values for these two (yet?). */ case binding_dns: case binding_function: return DHCP_R_INVALIDARG; default: log_fatal ("Impossible case at %s:%d.", MDL); return ISC_R_FAILURE; } if (status != ISC_R_SUCCESS) return status; status = omapi_value_new (value, MDL); if (status != ISC_R_SUCCESS) { omapi_typed_data_dereference (&td, MDL); return status; } omapi_data_string_reference (&(*value) -> name, name, MDL); omapi_typed_data_reference (&(*value) -> value, td, MDL); omapi_typed_data_dereference (&td, MDL); return ISC_R_SUCCESS; } isc_result_t binding_scope_stuff_values (omapi_object_t *c, struct binding_scope *scope) { struct binding *bp; unsigned len; isc_result_t status; for (bp = scope -> bindings; bp; bp = bp -> next) { if (bp -> value) { if (bp -> value -> type == binding_dns || bp -> value -> type == binding_function) continue; /* Stuff the name. */ len = strlen (bp -> name); status = omapi_connection_put_uint16 (c, len); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_copyin (c, (unsigned char *)bp -> name, len); if (status != ISC_R_SUCCESS) return status; switch (bp -> value -> type) { case binding_boolean: status = omapi_connection_put_uint32 (c, sizeof (u_int32_t)); if (status != ISC_R_SUCCESS) return status; status = (omapi_connection_put_uint32 (c, ((u_int32_t)(bp -> value -> value.boolean)))); break; case binding_data: status = (omapi_connection_put_uint32 (c, bp -> value -> value.data.len)); if (status != ISC_R_SUCCESS) return status; if (bp -> value -> value.data.len) { status = (omapi_connection_copyin (c, bp -> value -> value.data.data, bp -> value -> value.data.len)); if (status != ISC_R_SUCCESS) return status; } break; case binding_numeric: status = (omapi_connection_put_uint32 (c, sizeof (u_int32_t))); if (status != ISC_R_SUCCESS) return status; status = (omapi_connection_put_uint32 (c, ((u_int32_t) (bp -> value -> value.intval)))); break; /* NOTREACHED */ case binding_dns: case binding_function: break; } } } return ISC_R_SUCCESS; } /* vim: set tabstop=8: */ dhcp-4.2.4/server/salloc.c000644 000765 000024 00000015241 11301372617 015322 0ustar00sarstaff000000 000000 /* salloc.c Memory allocation for the DHCP server... */ /* * Copyright (c) 2004-2007,2009 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1996-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ * * This software has been written for Internet Systems Consortium * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. * To learn more about Internet Systems Consortium, see * ``https://www.isc.org/''. To learn more about Vixie Enterprises, * see ``http://www.vix.com''. To learn more about Nominum, Inc., see * ``http://www.nominum.com''. */ #include "dhcpd.h" #include #if defined (COMPACT_LEASES) struct lease *free_leases; # if defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT) struct lease *lease_hunks; void relinquish_lease_hunks () { struct lease *c, *n, **p, *f; int i; /* Account for all the leases on the free list. */ for (n = lease_hunks; n; n = n -> next) { for (i = 1; i < n -> starts + 1; i++) { p = &free_leases; for (c = free_leases; c; c = c -> next) { if (c == &n [i]) { *p = c -> next; n -> ends++; break; } p = &c -> next; } if (!c) { log_info ("lease %s refcnt %d", piaddr (n [i].ip_addr), n [i].refcnt); dump_rc_history (&n [i]); } } } for (c = lease_hunks; c; c = n) { n = c -> next; if (c -> ends != c -> starts) { log_info ("lease hunk %lx leases %ld free %ld", (unsigned long)c, (unsigned long)c -> starts, (unsigned long)c -> ends); } dfree (c, MDL); } /* Free all the rogue leases. */ for (c = free_leases; c; c = n) { n = c -> next; dfree (c, MDL); } } #endif struct lease *new_leases (n, file, line) unsigned n; const char *file; int line; { struct lease *rval; #if defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT) rval = dmalloc ((n + 1) * sizeof (struct lease), file, line); memset (rval, 0, sizeof (struct lease)); rval -> starts = n; rval -> next = lease_hunks; lease_hunks = rval; rval++; #else rval = dmalloc (n * sizeof (struct lease), file, line); #endif return rval; } /* If we are allocating leases in aggregations, there's really no way to free one, although perhaps we can maintain a free list. */ isc_result_t dhcp_lease_free (omapi_object_t *lo, const char *file, int line) { struct lease *lease; if (lo -> type != dhcp_type_lease) return DHCP_R_INVALIDARG; lease = (struct lease *)lo; memset (lease, 0, sizeof (struct lease)); lease -> next = free_leases; free_leases = lease; return ISC_R_SUCCESS; } isc_result_t dhcp_lease_get (omapi_object_t **lp, const char *file, int line) { struct lease **lease = (struct lease **)lp; struct lease *lt; if (free_leases) { lt = free_leases; free_leases = lt -> next; *lease = lt; return ISC_R_SUCCESS; } return ISC_R_NOMEMORY; } #endif /* COMPACT_LEASES */ OMAPI_OBJECT_ALLOC (lease, struct lease, dhcp_type_lease) OMAPI_OBJECT_ALLOC (class, struct class, dhcp_type_class) OMAPI_OBJECT_ALLOC (subclass, struct class, dhcp_type_subclass) OMAPI_OBJECT_ALLOC (pool, struct pool, dhcp_type_pool) #if !defined (NO_HOST_FREES) /* Scary debugging mode - don't enable! */ OMAPI_OBJECT_ALLOC (host, struct host_decl, dhcp_type_host) #else isc_result_t host_allocate (struct host_decl **p, const char *file, int line) { return omapi_object_allocate ((omapi_object_t **)p, dhcp_type_host, 0, file, line); } isc_result_t host_reference (struct host_decl **pptr, struct host_decl *ptr, const char *file, int line) { return omapi_object_reference ((omapi_object_t **)pptr, (omapi_object_t *)ptr, file, line); } isc_result_t host_dereference (struct host_decl **ptr, const char *file, int line) { if ((*ptr) -> refcnt == 1) { log_error ("host dereferenced with refcnt == 1."); #if defined (DEBUG_RC_HISTORY) dump_rc_history (); #endif abort (); } return omapi_object_dereference ((omapi_object_t **)ptr, file, line); } #endif struct lease_state *free_lease_states; struct lease_state *new_lease_state (file, line) const char *file; int line; { struct lease_state *rval; if (free_lease_states) { rval = free_lease_states; free_lease_states = (struct lease_state *)(free_lease_states -> next); dmalloc_reuse (rval, file, line, 0); } else { rval = dmalloc (sizeof (struct lease_state), file, line); if (!rval) return rval; } memset (rval, 0, sizeof *rval); if (!option_state_allocate (&rval -> options, file, line)) { free_lease_state (rval, file, line); return (struct lease_state *)0; } return rval; } void free_lease_state (ptr, file, line) struct lease_state *ptr; const char *file; int line; { if (ptr -> options) option_state_dereference (&ptr -> options, file, line); if (ptr -> packet) packet_dereference (&ptr -> packet, file, line); if (ptr -> shared_network) shared_network_dereference (&ptr -> shared_network, file, line); data_string_forget (&ptr -> parameter_request_list, file, line); data_string_forget (&ptr -> filename, file, line); data_string_forget (&ptr -> server_name, file, line); ptr -> next = free_lease_states; free_lease_states = ptr; dmalloc_reuse (free_lease_states, (char *)0, 0, 0); } #if defined (DEBUG_MEMORY_LEAKAGE) || \ defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT) void relinquish_free_lease_states () { struct lease_state *cs, *ns; for (cs = free_lease_states; cs; cs = ns) { ns = cs -> next; dfree (cs, MDL); } free_lease_states = (struct lease_state *)0; } #endif struct permit *new_permit (file, line) const char *file; int line; { struct permit *permit = ((struct permit *) dmalloc (sizeof (struct permit), file, line)); if (!permit) return permit; memset (permit, 0, sizeof *permit); return permit; } void free_permit (permit, file, line) struct permit *permit; const char *file; int line; { if (permit -> type == permit_class) class_dereference (&permit -> class, MDL); dfree (permit, file, line); } dhcp-4.2.4/server/stables.c000644 000765 000024 00000044746 11646111134 015513 0ustar00sarstaff000000 000000 /* stables.c Tables of information only used by server... */ /* * Copyright (c) 2004-2011 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1995-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ * * This software has been written for Internet Systems Consortium * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. * To learn more about Internet Systems Consortium, see * ``https://www.isc.org/''. To learn more about Vixie Enterprises, * see ``http://www.vix.com''. To learn more about Nominum, Inc., see * ``http://www.nominum.com''. */ #include "dhcpd.h" #include #if defined (FAILOVER_PROTOCOL) /* This is used to indicate some kind of failure when generating a failover option. */ failover_option_t null_failover_option = { 0, 0 }; failover_option_t skip_failover_option = { 0, 0 }; /* Information about failover options, for printing, encoding and decoding. */ struct failover_option_info ft_options [] = { { 0, "unused", FT_UNDEF, 0, 0, 0 }, { FTO_ADDRESSES_TRANSFERRED, "addresses-transferred", FT_UINT32, 1, FM_OFFSET(addresses_transferred), FTB_ADDRESSES_TRANSFERRED }, { FTO_ASSIGNED_IP_ADDRESS, "assigned-IP-address", FT_IPADDR, 1, FM_OFFSET(assigned_addr), FTB_ASSIGNED_IP_ADDRESS }, { FTO_BINDING_STATUS, "binding-status", FT_UINT8, 1, FM_OFFSET(binding_status), FTB_BINDING_STATUS }, { FTO_CLIENT_IDENTIFIER, "client-identifier", FT_BYTES, 0, FM_OFFSET(client_identifier), FTB_CLIENT_IDENTIFIER }, { FTO_CHADDR, "client-hardware-address", FT_BYTES, 0, FM_OFFSET(chaddr), FTB_CHADDR }, { FTO_CLTT, "client-last-transaction-time", FT_UINT32, 1, FM_OFFSET(cltt), FTB_CLTT }, { FTO_REPLY_OPTIONS, "client-reply-options", FT_BYTES, 0, FM_OFFSET(reply_options), FTB_REPLY_OPTIONS }, { FTO_REQUEST_OPTIONS, "client-request-options", FT_BYTES, 0, FM_OFFSET(request_options), FTB_REQUEST_OPTIONS }, { FTO_DDNS, "DDNS", FT_DDNS, 1, FM_OFFSET(ddns), FTB_DDNS }, { FTO_DELAYED_SERVICE, "delayed-service", FT_UINT8, 1, FM_OFFSET(delayed_service), FTB_DELAYED_SERVICE }, { FTO_HBA, "hash-bucket-assignment", FT_BYTES, 0, FM_OFFSET(hba), FTB_HBA }, { FTO_IP_FLAGS, "IP-flags", FT_UINT16, 1, FM_OFFSET(ip_flags), FTB_IP_FLAGS }, { FTO_LEASE_EXPIRY, "lease-expiration-time", FT_UINT32, 1, FM_OFFSET(expiry), FTB_LEASE_EXPIRY }, { FTO_MAX_UNACKED, "max-unacked-bndupd", FT_UINT32, 1, FM_OFFSET(max_unacked), FTB_MAX_UNACKED }, { FTO_MCLT, "MCLT", FT_UINT32, 1, FM_OFFSET(mclt), FTB_MCLT }, { FTO_MESSAGE, "message", FT_TEXT, 0, FM_OFFSET(message), FTB_MESSAGE }, { FTO_MESSAGE_DIGEST, "message-digest", FT_BYTES, 0, FM_OFFSET(message_digest), FTB_MESSAGE_DIGEST }, { FTO_POTENTIAL_EXPIRY, "potential-expiration-time", FT_UINT32, 1, FM_OFFSET(potential_expiry), FTB_POTENTIAL_EXPIRY }, { FTO_RECEIVE_TIMER, "receive-timer", FT_UINT32, 1, FM_OFFSET(receive_timer), FTB_RECEIVE_TIMER }, { FTO_PROTOCOL_VERSION, "protocol-version", FT_UINT8, 1, FM_OFFSET(protocol_version), FTB_PROTOCOL_VERSION }, { FTO_REJECT_REASON, "reject-reason", FT_UINT8, 1, FM_OFFSET(reject_reason), FTB_REJECT_REASON }, { FTO_RELATIONSHIP_NAME, "relationship-name", FT_BYTES, 0, FM_OFFSET(relationship_name), FTB_RELATIONSHIP_NAME }, { FTO_SERVER_FLAGS, "server-flags", FT_UINT8, 1, FM_OFFSET(server_flags), FTB_SERVER_FLAGS }, { FTO_SERVER_STATE, "server-state", FT_UINT8, 1, FM_OFFSET(server_state), FTB_SERVER_STATE }, { FTO_STOS, "start-time-of-state", FT_UINT32, 1, FM_OFFSET(stos), FTB_STOS }, { FTO_TLS_REPLY, "TLS-reply", FT_UINT8, 1, FM_OFFSET(tls_reply), FTB_TLS_REPLY }, { FTO_TLS_REQUEST, "TLS-request", FT_UINT8, 1, FM_OFFSET(tls_request), FTB_TLS_REQUEST }, { FTO_VENDOR_CLASS, "vendor-class-identifier", FT_BYTES, 0, FM_OFFSET(vendor_class), FTB_VENDOR_CLASS }, { FTO_VENDOR_OPTIONS, "vendor-specific-options", FT_BYTES, 0, FM_OFFSET(vendor_options), FTB_VENDOR_OPTIONS } }; /* These are really options that make sense for a particular request - if some other option comes in, we're not going to use it, so we can just discard it. Note that the message-digest option is allowed for all message types, but is not saved - it's just used to validate the message and then discarded - so it's not mentioned here. */ u_int32_t fto_allowed [] = { 0, /* 0 unused */ 0, /* 1 POOLREQ */ FTB_ADDRESSES_TRANSFERRED, /* 2 POOLRESP */ (FTB_ASSIGNED_IP_ADDRESS | FTB_BINDING_STATUS | FTB_CLIENT_IDENTIFIER | FTB_CHADDR | FTB_DDNS | FTB_IP_FLAGS | FTB_LEASE_EXPIRY | FTB_POTENTIAL_EXPIRY | FTB_STOS | FTB_CLTT | FTB_REQUEST_OPTIONS | FTB_REPLY_OPTIONS), /* 3 BNDUPD */ (FTB_ASSIGNED_IP_ADDRESS | FTB_BINDING_STATUS | FTB_CLIENT_IDENTIFIER | FTB_CHADDR | FTB_DDNS | FTB_IP_FLAGS | FTB_LEASE_EXPIRY | FTB_POTENTIAL_EXPIRY | FTB_STOS | FTB_CLTT | FTB_REQUEST_OPTIONS | FTB_REPLY_OPTIONS | FTB_REJECT_REASON | FTB_MESSAGE), /* 4 BNDACK */ (FTB_RELATIONSHIP_NAME | FTB_MAX_UNACKED | FTB_RECEIVE_TIMER | FTB_VENDOR_CLASS | FTB_PROTOCOL_VERSION | FTB_TLS_REQUEST | FTB_MCLT | FTB_HBA), /* 5 CONNECT */ (FTB_RELATIONSHIP_NAME | FTB_MAX_UNACKED | FTB_RECEIVE_TIMER | FTB_VENDOR_CLASS | FTB_PROTOCOL_VERSION | FTB_TLS_REPLY | FTB_REJECT_REASON | FTB_MESSAGE), /* CONNECTACK */ 0, /* 7 UPDREQALL */ 0, /* 8 UPDDONE */ 0, /* 9 UPDREQ */ (FTB_SERVER_STATE | FTB_SERVER_FLAGS | FTB_STOS), /* 10 STATE */ 0, /* 11 CONTACT */ (FTB_REJECT_REASON | FTB_MESSAGE) /* 12 DISCONNECT */ }; /* Sizes of the various types. */ int ft_sizes [] = { 1, /* FT_UINT8 */ 4, /* FT_IPADDR */ 4, /* FT_UINT32 */ 1, /* FT_BYTES */ 1, /* FT_TEXT_OR_BYTES */ 0, /* FT_DDNS */ 0, /* FT_DDNS1 */ 2, /* FT_UINT16 */ 1, /* FT_TEXT */ 0, /* FT_UNDEF */ 0, /* FT_DIGEST */ }; /* Names of the various failover link states. */ const char *dhcp_flink_state_names [] = { "invalid state 0", "startup", "message length wait", "message wait", "disconnected" }; #endif /* FAILOVER_PROTOCOL */ /* Failover binding state names. These are used even if there is no failover protocol support. */ const char *binding_state_names [] = { "free", "active", "expired", "released", "abandoned", "reset", "backup" }; struct universe agent_universe; static struct option agent_options[] = { { "circuit-id", "X", &agent_universe, 1, 1 }, { "remote-id", "X", &agent_universe, 2, 1 }, { "agent-id", "I", &agent_universe, 3, 1 }, { "DOCSIS-device-class", "L", &agent_universe, 4, 1 }, { "link-selection", "I", &agent_universe, 5, 1 }, { NULL, NULL, NULL, 0, 0 } }; struct universe server_universe; static struct option server_options[] = { { "default-lease-time", "T", &server_universe, 1, 1 }, { "max-lease-time", "T", &server_universe, 2, 1 }, { "min-lease-time", "T", &server_universe, 3, 1 }, { "dynamic-bootp-lease-cutoff", "T", &server_universe, 4, 1 }, { "dynamic-bootp-lease-length", "L", &server_universe, 5, 1 }, { "boot-unknown-clients", "f", &server_universe, 6, 1 }, { "dynamic-bootp", "f", &server_universe, 7, 1 }, { "allow-bootp", "f", &server_universe, 8, 1 }, { "allow-booting", "f", &server_universe, 9, 1 }, { "one-lease-per-client", "f", &server_universe, 10, 1 }, { "get-lease-hostnames", "f", &server_universe, 11, 1 }, { "use-host-decl-names", "f", &server_universe, 12, 1 }, { "use-lease-addr-for-default-route", "f", &server_universe, 13, 1 }, { "min-secs", "B", &server_universe, 14, 1 }, { "filename", "t", &server_universe, 15, 1 }, { "server-name", "t", &server_universe, 16, 1 }, { "next-server", "I", &server_universe, 17, 1 }, { "authoritative", "f", &server_universe, 18, 1 }, { "vendor-option-space", "U", &server_universe, 19, 1 }, { "always-reply-rfc1048", "f", &server_universe, 20, 1 }, { "site-option-space", "X", &server_universe, 21, 1 }, { "always-broadcast", "f", &server_universe, 22, 1 }, { "ddns-domainname", "t", &server_universe, 23, 1 }, { "ddns-hostname", "t", &server_universe, 24, 1 }, { "ddns-rev-domainname", "t", &server_universe, 25, 1 }, { "lease-file-name", "t", &server_universe, 26, 1 }, { "pid-file-name", "t", &server_universe, 27, 1 }, { "duplicates", "f", &server_universe, 28, 1 }, { "declines", "f", &server_universe, 29, 1 }, { "ddns-updates", "f", &server_universe, 30, 1 }, { "omapi-port", "S", &server_universe, 31, 1 }, { "local-port", "S", &server_universe, 32, 1 }, { "limited-broadcast-address", "I", &server_universe, 33, 1 }, { "remote-port", "S", &server_universe, 34, 1 }, { "local-address", "I", &server_universe, 35, 1 }, { "omapi-key", "d", &server_universe, 36, 1 }, { "stash-agent-options", "f", &server_universe, 37, 1 }, { "ddns-ttl", "T", &server_universe, 38, 1 }, { "ddns-update-style", "Nddns-styles.", &server_universe, 39, 1 }, { "client-updates", "f", &server_universe, 40, 1 }, { "update-optimization", "f", &server_universe, 41, 1 }, { "ping-check", "f", &server_universe, 42, 1 }, { "update-static-leases", "f", &server_universe, 43, 1 }, { "log-facility", "Nsyslog-facilities.", &server_universe, 44, 1 }, { "do-forward-updates", "f", &server_universe, 45, 1 }, { "ping-timeout", "T", &server_universe, 46, 1 }, { "infinite-is-reserved", "f", &server_universe, 47, 1 }, { "update-conflict-detection", "f", &server_universe, 48, 1 }, { "leasequery", "f", &server_universe, 49, 1 }, { "adaptive-lease-time-threshold", "B", &server_universe, 50, 1 }, { "do-reverse-updates", "f", &server_universe, 51, 1 }, { "fqdn-reply", "f", &server_universe, 52, 1 }, { "preferred-lifetime", "T", &server_universe, 53, 1 }, { "dhcpv6-lease-file-name", "t", &server_universe, 54, 1 }, { "dhcpv6-pid-file-name", "t", &server_universe, 55, 1 }, { "limit-addrs-per-ia", "L", &server_universe, 56, 1 }, { "limit-prefs-per-ia", "L", &server_universe, 57, 1 }, /* Assert a configuration parsing error if delayed-ack isn't compiled in. */ #if defined(DELAYED_ACK) { "delayed-ack", "S", &server_universe, 58, 1 }, { "max-ack-delay", "L", &server_universe, 59, 1 }, #endif #if defined(LDAP_CONFIGURATION) { "ldap-server", "t", &server_universe, 60, 1 }, { "ldap-port", "d", &server_universe, 61, 1 }, { "ldap-username", "t", &server_universe, 62, 1 }, { "ldap-password", "t", &server_universe, 63, 1 }, { "ldap-base-dn", "t", &server_universe, 64, 1 }, { "ldap-method", "Nldap-methods.", &server_universe, 65, 1 }, { "ldap-debug-file", "t", &server_universe, 66, 1 }, { "ldap-dhcp-server-cn", "t", &server_universe, 67, 1 }, { "ldap-referrals", "f", &server_universe, 68, 1 }, #if defined(LDAP_USE_SSL) { "ldap-ssl", "Nldap-ssl-usage.", &server_universe, 69, 1 }, { "ldap-tls-reqcert", "Nldap-tls-reqcert.", &server_universe, 70, 1 }, { "ldap-tls-ca-file", "t", &server_universe, 71, 1 }, { "ldap-tls-ca-dir", "t", &server_universe, 72, 1 }, { "ldap-tls-cert", "t", &server_universe, 73, 1 }, { "ldap-tls-key", "t", &server_universe, 74, 1 }, { "ldap-tls-crlcheck", "Nldap-tls-crlcheck.", &server_universe, 75, 1 }, { "ldap-tls-ciphers", "t", &server_universe, 76, 1 }, { "ldap-tls-randfile", "t", &server_universe, 77, 1 }, #endif /* LDAP_USE_SSL */ #endif /* LDAP_CONFIGURATION */ { NULL, NULL, NULL, 0, 0 } }; #if defined(LDAP_CONFIGURATION) struct enumeration_value ldap_values [] = { { "static", LDAP_METHOD_STATIC }, { "dynamic", LDAP_METHOD_DYNAMIC }, { (char *) 0, 0 } }; struct enumeration ldap_methods = { (struct enumeration *)0, "ldap-methods", 1, ldap_values }; #if defined(LDAP_USE_SSL) struct enumeration_value ldap_ssl_usage_values [] = { { "off", LDAP_SSL_OFF }, { "on",LDAP_SSL_ON }, { "ldaps", LDAP_SSL_LDAPS }, { "start_tls", LDAP_SSL_TLS }, { (char *) 0, 0 } }; struct enumeration ldap_ssl_usage_enum = { (struct enumeration *)0, "ldap-ssl-usage", 1, ldap_ssl_usage_values }; struct enumeration_value ldap_tls_reqcert_values [] = { { "never", LDAP_OPT_X_TLS_NEVER }, { "hard", LDAP_OPT_X_TLS_HARD }, { "demand", LDAP_OPT_X_TLS_DEMAND}, { "allow", LDAP_OPT_X_TLS_ALLOW }, { "try", LDAP_OPT_X_TLS_TRY }, { (char *) 0, 0 } }; struct enumeration ldap_tls_reqcert_enum = { (struct enumeration *)0, "ldap-tls-reqcert", 1, ldap_tls_reqcert_values }; struct enumeration_value ldap_tls_crlcheck_values [] = { { "none", LDAP_OPT_X_TLS_CRL_NONE}, { "peer", LDAP_OPT_X_TLS_CRL_PEER}, { "all", LDAP_OPT_X_TLS_CRL_ALL }, { (char *) 0, 0 } }; struct enumeration ldap_tls_crlcheck_enum = { (struct enumeration *)0, "ldap-tls-crlcheck", 1, ldap_tls_crlcheck_values }; #endif #endif struct enumeration_value ddns_styles_values [] = { { "none", 0 }, { "ad-hoc", 1 }, { "interim", 2 }, { (char *)0, 0 } }; struct enumeration ddns_styles = { (struct enumeration *)0, "ddns-styles", 1, ddns_styles_values }; struct enumeration_value syslog_values [] = { #if defined (LOG_KERN) { "kern", LOG_KERN }, #endif #if defined (LOG_USER) { "user", LOG_USER }, #endif #if defined (LOG_MAIL) { "mail", LOG_MAIL }, #endif #if defined (LOG_DAEMON) { "daemon", LOG_DAEMON }, #endif #if defined (LOG_AUTH) { "auth", LOG_AUTH }, #endif #if defined (LOG_SYSLOG) { "syslog", LOG_SYSLOG }, #endif #if defined (LOG_LPR) { "lpr", LOG_LPR }, #endif #if defined (LOG_NEWS) { "news", LOG_NEWS }, #endif #if defined (LOG_UUCP) { "uucp", LOG_UUCP }, #endif #if defined (LOG_CRON) { "cron", LOG_CRON }, #endif #if defined (LOG_AUTHPRIV) { "authpriv", LOG_AUTHPRIV }, #endif #if defined (LOG_FTP) { "ftp", LOG_FTP }, #endif #if defined (LOG_LOCAL0) { "local0", LOG_LOCAL0 }, #endif #if defined (LOG_LOCAL1) { "local1", LOG_LOCAL1 }, #endif #if defined (LOG_LOCAL2) { "local2", LOG_LOCAL2 }, #endif #if defined (LOG_LOCAL3) { "local3", LOG_LOCAL3 }, #endif #if defined (LOG_LOCAL4) { "local4", LOG_LOCAL4 }, #endif #if defined (LOG_LOCAL5) { "local5", LOG_LOCAL5 }, #endif #if defined (LOG_LOCAL6) { "local6", LOG_LOCAL6 }, #endif #if defined (LOG_LOCAL7) { "local7", LOG_LOCAL7 }, #endif { (char *)0, 0 } }; struct enumeration syslog_enum = { (struct enumeration *)0, "syslog-facilities", 1, syslog_values }; void initialize_server_option_spaces() { int i; unsigned code; /* Set up the Relay Agent Information Option suboption space... */ agent_universe.name = "agent"; agent_universe.concat_duplicates = 0; agent_universe.option_state_dereference = linked_option_state_dereference; agent_universe.lookup_func = lookup_linked_option; agent_universe.save_func = save_linked_option; agent_universe.delete_func = delete_linked_option; agent_universe.encapsulate = linked_option_space_encapsulate; agent_universe.foreach = linked_option_space_foreach; agent_universe.decode = parse_option_buffer; agent_universe.index = universe_count++; agent_universe.length_size = 1; agent_universe.tag_size = 1; agent_universe.get_tag = getUChar; agent_universe.store_tag = putUChar; agent_universe.get_length = getUChar; agent_universe.store_length = putUChar; agent_universe.site_code_min = 0; agent_universe.end = 0; universes [agent_universe.index] = &agent_universe; if (!option_name_new_hash(&agent_universe.name_hash, AGENT_HASH_SIZE, MDL) || !option_code_new_hash(&agent_universe.code_hash, AGENT_HASH_SIZE, MDL)) log_fatal ("Can't allocate agent option hash table."); for (i = 0 ; agent_options[i].name ; i++) { option_code_hash_add(agent_universe.code_hash, &agent_options[i].code, 0, &agent_options[i], MDL); option_name_hash_add(agent_universe.name_hash, agent_options[i].name, 0, &agent_options[i], MDL); } #if defined(REPORT_HASH_PERFORMANCE) log_info("Relay Agent name hash: %s", option_name_hash_report(agent_universe.name_hash)); log_info("Relay Agent code hash: %s", option_code_hash_report(agent_universe.code_hash)); #endif code = DHO_DHCP_AGENT_OPTIONS; option_code_hash_lookup(&agent_universe.enc_opt, dhcp_universe.code_hash, &code, 0, MDL); /* Set up the server option universe... */ server_universe.name = "server"; server_universe.concat_duplicates = 0; server_universe.lookup_func = lookup_hashed_option; server_universe.option_state_dereference = hashed_option_state_dereference; server_universe.save_func = save_hashed_option; server_universe.delete_func = delete_hashed_option; server_universe.encapsulate = hashed_option_space_encapsulate; server_universe.foreach = hashed_option_space_foreach; server_universe.length_size = 1; /* Never used ... */ server_universe.tag_size = 4; server_universe.store_tag = putUChar; server_universe.store_length = putUChar; server_universe.site_code_min = 0; server_universe.end = 0; server_universe.index = universe_count++; universes [server_universe.index] = &server_universe; if (!option_name_new_hash(&server_universe.name_hash, SERVER_HASH_SIZE, MDL) || !option_code_new_hash(&server_universe.code_hash, SERVER_HASH_SIZE, MDL)) log_fatal ("Can't allocate server option hash table."); for (i = 0 ; server_options[i].name ; i++) { option_code_hash_add(server_universe.code_hash, &server_options[i].code, 0, &server_options[i], MDL); option_name_hash_add(server_universe.name_hash, server_options[i].name, 0, &server_options[i], MDL); } #if defined(REPORT_HASH_PERFORMANCE) log_info("Server-Config Option name hash: %s", option_name_hash_report(server_universe.name_hash)); log_info("Server-Config Option code hash: %s", option_code_hash_report(server_universe.code_hash)); #endif /* Add the server and agent option spaces to the option space hash. */ universe_hash_add (universe_hash, agent_universe.name, 0, &agent_universe, MDL); universe_hash_add (universe_hash, server_universe.name, 0, &server_universe, MDL); /* Make the server universe the configuration option universe. */ config_universe = &server_universe; code = SV_VENDOR_OPTION_SPACE; option_code_hash_lookup(&vendor_cfg_option, server_universe.code_hash, &code, 0, MDL); } dhcp-4.2.4/relay/dhcrelay.8000644 000765 000024 00000017515 11754311440 015400 0ustar00sarstaff000000 000000 .\" dhcrelay.8 .\" .\" Copyright (c) 2009-2011 by Internet Systems Consortium, Inc. ("ISC") .\" Copyright (c) 2004,2007 by Internet Systems Consortium, Inc. ("ISC") .\" Copyright (c) 1997-2003 by Internet Software Consortium .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above .\" copyright notice and this permission notice appear in all copies. .\" .\" THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES .\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR .\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES .\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT .\" OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" .\" Internet Systems Consortium, Inc. .\" 950 Charter Street .\" Redwood City, CA 94063 .\" .\" https://www.isc.org/ .\" .\" This software has been written for Internet Systems Consortium .\" by Ted Lemon in cooperation with Vixie Enterprises. .\" .\" Support and other services are available for ISC products - see .\" https://www.isc.org for more information or to learn more about ISC. .\" .\" $Id: dhcrelay.8,v 1.16.24.4 2012-05-14 23:20:00 sar Exp $ .\" .TH dhcrelay 8 .SH NAME dhcrelay - Dynamic Host Configuration Protocol Relay Agent .SH SYNOPSIS .B dhcrelay [ .B -4 ] [ .B -dqaD ] [ .B -p .I port ] [ .B -c .I count ] [ .B -A .I length ] [ .B -pf .I pid-file ] [ .B --no-pid ] [ .B -m .I append | .I replace | .I forward | .I discard ] [ .B -i .I interface0 [ .B ... .B -i .I interfaceN ] ] .I server0 [ .I ...serverN ] .PP .B dhcrelay -6 [ .B -dqI ] [ .B -p .I port ] [ .B -c .I count ] [ .B -pf .I pid-file ] [ .B --no-pid ] .B -l .I lower0 [ .B ... .B -l .I lowerN ] .B -u .I upper0 [ .B ... .B -u .I upperN ] .SH DESCRIPTION The Internet Systems Consortium DHCP Relay Agent, dhcrelay, provides a means for relaying DHCP and BOOTP requests from a subnet to which no DHCP server is directly connected to one or more DHCP servers on other subnets. It supports both DHCPv4/BOOTP and DHCPv6 protocols. .SH OPERATION .PP The DHCP Relay Agent listens for DHCPv4 or DHCPv6 queries from clients or other relay agents on one or more interfaces, passing them along to ``upstream'' servers or relay agents as specified on the command line. When a reply is received from upstream, it is multicast or unicast back downstream to the source of the original request. .SH COMMAND LINE .PP \fIProtocol selection options:\fR .TP -6 Run dhcrelay as a DHCPv6 relay agent. Incompatible with the \fB-4\fR option. .TP -4 Run dhcrelay as a DHCPv4/BOOTP relay agent. This is the default mode of operation, so the argument is not necessary, but may be specified for clarity. Incompatible with \fB-6\fR. .PP \fISpecifying DHCPv4/BOOTP servers\fR .PP In DHCPv4 mode, a list of one or more server addresses must be specified on the command line, to which DHCP/BOOTP queries should be relayed. .PP \fIOptions available for both DHCPv4 and DHCPv6:\fR .TP -c COUNT Maximum hop count. When forwarding packets, dhcrelay discards packets which have reached a hop count of COUNT. Default is 10. Maximum is 255. .TP -d Force dhcrelay to run as a foreground process. Useful when running dhcrelay under a debugger, or running out of inittab on System V systems. .TP -p PORT Listen and transmit on port PORT. This is mostly useful for debugging purposes. Default is port 67 for DHCPv4/BOOTP, or port 547 for DHCPv6. .TP -q Quiet mode. Prevents dhcrelay6 from printing its network configuration on startup. .TP -pf pid-file Path to alternate pid file. .TP --no-pid Option to disable writing pid files. By default the program will write a pid file. .PP \fIOptions available in DHCPv4 mode only:\fR .TP -a Append an agent option field to each request before forwarding it to the server. Agent option fields in responses sent from servers to clients will be stripped before forwarding such responses back to the client. The agent option field will contain two agent options: the Circuit ID suboption and the Remote ID suboption. Currently, the Circuit ID will be the printable name of the interface on which the client request was received. The client supports inclusion of a Remote ID suboption as well, but this is not used by default. .TP -A LENGTH Specify the maximum packet size to send to a DHCPv4/BOOTP server. This might be done to allow sufficient space for addition of relay agent options while still fitting into the Ethernet MTU size. .TP -D Drop packets from upstream servers if they contain Relay Agent Information options that indicate they were generated in response to a query that came via a different relay agent. If this option is not specified, such packets will be relayed anyway. .TP -i \fIifname\fR Listen for DHCPv4/BOOTP queries on interface \fIifname\fR. Multiple interfaces may be specified by using more than one \fB-i\fR option. If no interfaces are specified on the command line, dhcrelay will identify all network interfaces, eliminating non-broadcast interfaces if possible, and attempt to listen on all of them. .TP -m \fIappend\fR|\fIreplace\fR|\fIforward\fR|\fIdiscard\fR Control the handling of incoming DHCPv4 packets which already contain relay agent options. If such a packet does not have \fIgiaddr\fR set in its header, the DHCP standard requires that the packet be discarded. However, if \fIgiaddr\fR is set, the relay agent may handle the situation in four ways: It may \fIappend\fR its own set of relay options to the packet, leaving the supplied option field intact; it may \fIreplace\fR the existing agent option field; it may \fIforward\fR the packet unchanged; or, it may \fIdiscard\fR it. To use this option you must also enable the \fB-a\fR option. .PP \fIOptions available in DHCPv6 mode only:\fR .TP -I Force use of the DHCPv6 Interface-ID option. This option is automatically sent when there are two or more downstream interfaces in use, to disambiguate between them. The \fB-I\fR option causes dhcrelay to send the option even if there is only one downstream interface. .TP -l [\fIaddress%\fR]\fIifname\fR[\fI#index\fR] Specifies the ``lower'' network interface for DHCPv6 relay mode: the interface on which queries will be received from clients or from other relay agents. At least one \fB-l\fR option must be included in the command line when running in DHCPv6 mode. The interface name \fIifname\fR is a mandatory parameter. The link address can be specified by \fIaddress%\fR; if it isn't, dhcrelay will use the first non-link-local address configured on the interface. The optional \fI#index\fR parameter specifies the interface index. .TP -u [\fIaddress%\fR]\fIifname\fR Specifies the ``upper'' network interface for DHCPv6 relay mode: the interface to which queries from clients and other relay agents should be forwarded. At least one \fB-u\fR option must be included in the command line when running in DHCPv6 mode. The interface name \fIifname\fR is a mandatory parameter. The destination unicast or multicast address can be specified by \fIaddress%\fR; if not specified, the relay agent will forward to the DHCPv6 \fIAll_DHCP_Relay_Agents_and_Servers\fR multicast address. .PP It is possible to specify the same interface with different addresses more than once, and even, when the system supports it, to use the same interface as both upper and lower interfaces. .SH SEE ALSO dhclient(8), dhcpd(8), RFC3315, RFC2132, RFC2131. .SH BUGS .PP Using the same interface on both upper and lower sides may cause loops, so when running this way, the maximum hop count should be set to a low value. .PP The loopback interface is not (yet) recognized as a valid interface. .SH AUTHOR .B dhcrelay(8) To learn more about Internet Systems Consortium, see .B https://www.isc.org dhcp-4.2.4/relay/dhcrelay.c000644 000765 000024 00000125726 11741366354 015471 0ustar00sarstaff000000 000000 /* dhcrelay.c DHCP/BOOTP Relay Agent. */ /* * Copyright(c) 2004-2012 by Internet Systems Consortium, Inc.("ISC") * Copyright(c) 1997-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ * * This software has been written for Internet Systems Consortium * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. * To learn more about Internet Systems Consortium, see * ``https://www.isc.org/''. To learn more about Vixie Enterprises, * see ``http://www.vix.com''. To learn more about Nominum, Inc., see * ``http://www.nominum.com''. */ #include "dhcpd.h" #include #include TIME default_lease_time = 43200; /* 12 hours... */ TIME max_lease_time = 86400; /* 24 hours... */ struct tree_cache *global_options[256]; struct option *requested_opts[2]; /* Needed to prevent linking against conflex.c. */ int lexline; int lexchar; char *token_line; char *tlname; const char *path_dhcrelay_pid = _PATH_DHCRELAY_PID; isc_boolean_t no_dhcrelay_pid = ISC_FALSE; /* False (default) => we write and use a pid file */ isc_boolean_t no_pid_file = ISC_FALSE; int bogus_agent_drops = 0; /* Packets dropped because agent option field was specified and we're not relaying packets that already have an agent option specified. */ int bogus_giaddr_drops = 0; /* Packets sent to us to relay back to a client, but with a bogus giaddr. */ int client_packets_relayed = 0; /* Packets relayed from client to server. */ int server_packet_errors = 0; /* Errors sending packets to servers. */ int server_packets_relayed = 0; /* Packets relayed from server to client. */ int client_packet_errors = 0; /* Errors sending packets to clients. */ int add_agent_options = 0; /* If nonzero, add relay agent options. */ int agent_option_errors = 0; /* Number of packets forwarded without agent options because there was no room. */ int drop_agent_mismatches = 0; /* If nonzero, drop server replies that don't have matching circuit-id's. */ int corrupt_agent_options = 0; /* Number of packets dropped because relay agent information option was bad. */ int missing_agent_option = 0; /* Number of packets dropped because no RAI option matching our ID was found. */ int bad_circuit_id = 0; /* Circuit ID option in matching RAI option did not match any known circuit ID. */ int missing_circuit_id = 0; /* Circuit ID option in matching RAI option was missing. */ int max_hop_count = 10; /* Maximum hop count */ #ifdef DHCPv6 /* Force use of DHCPv6 interface-id option. */ isc_boolean_t use_if_id = ISC_FALSE; #endif /* Maximum size of a packet with agent options added. */ int dhcp_max_agent_option_packet_length = DHCP_MTU_MIN; /* What to do about packets we're asked to relay that already have a relay option: */ enum { forward_and_append, /* Forward and append our own relay option. */ forward_and_replace, /* Forward, but replace theirs with ours. */ forward_untouched, /* Forward without changes. */ discard } agent_relay_mode = forward_and_replace; u_int16_t local_port; u_int16_t remote_port; /* Relay agent server list. */ struct server_list { struct server_list *next; struct sockaddr_in to; } *servers; #ifdef DHCPv6 struct stream_list { struct stream_list *next; struct interface_info *ifp; struct sockaddr_in6 link; int id; } *downstreams, *upstreams; static struct stream_list *parse_downstream(char *); static struct stream_list *parse_upstream(char *); static void setup_streams(void); #endif static void do_relay4(struct interface_info *, struct dhcp_packet *, unsigned int, unsigned int, struct iaddr, struct hardware *); static int add_relay_agent_options(struct interface_info *, struct dhcp_packet *, unsigned, struct in_addr); static int find_interface_by_agent_option(struct dhcp_packet *, struct interface_info **, u_int8_t *, int); static int strip_relay_agent_options(struct interface_info *, struct interface_info **, struct dhcp_packet *, unsigned); static const char copyright[] = "Copyright 2004-2012 Internet Systems Consortium."; static const char arr[] = "All rights reserved."; static const char message[] = "Internet Systems Consortium DHCP Relay Agent"; static const char url[] = "For info, please visit https://www.isc.org/software/dhcp/"; #ifdef DHCPv6 #define DHCRELAY_USAGE \ "Usage: dhcrelay [-4] [-d] [-q] [-a] [-D]\n"\ " [-A ] [-c ] [-p ]\n" \ " [-pf ] [--no-pid]\n"\ " [-m append|replace|forward|discard]\n" \ " [-i interface0 [ ... -i interfaceN]\n" \ " server0 [ ... serverN]\n\n" \ " dhcrelay -6 [-d] [-q] [-I] [-c ] [-p ]\n" \ " [-pf ] [--no-pid]\n"\ " -l lower0 [ ... -l lowerN]\n" \ " -u upper0 [ ... -u upperN]\n" \ " lower (client link): [address%%]interface[#index]\n" \ " upper (server link): [address%%]interface" #else #define DHCRELAY_USAGE \ "Usage: dhcrelay [-d] [-q] [-a] [-D] [-A ] [-c ] [-p ]\n" \ " [-pf ] [--no-pid]\n"\ " [-m append|replace|forward|discard]\n" \ " [-i interface0 [ ... -i interfaceN]\n" \ " server0 [ ... serverN]\n\n" #endif static void usage() { log_fatal(DHCRELAY_USAGE); } int main(int argc, char **argv) { isc_result_t status; struct servent *ent; struct server_list *sp = NULL; struct interface_info *tmp = NULL; char *service_local = NULL, *service_remote = NULL; u_int16_t port_local = 0, port_remote = 0; int no_daemon = 0, quiet = 0; int fd; int i; #ifdef DHCPv6 struct stream_list *sl = NULL; int local_family_set = 0; #endif /* Make sure that file descriptors 0(stdin), 1,(stdout), and 2(stderr) are open. To do this, we assume that when we open a file the lowest available file descriptor is used. */ fd = open("/dev/null", O_RDWR); if (fd == 0) fd = open("/dev/null", O_RDWR); if (fd == 1) fd = open("/dev/null", O_RDWR); if (fd == 2) log_perror = 0; /* No sense logging to /dev/null. */ else if (fd != -1) close(fd); openlog("dhcrelay", LOG_NDELAY, LOG_DAEMON); #if !defined(DEBUG) setlogmask(LOG_UPTO(LOG_INFO)); #endif /* Set up the isc and dns library managers */ status = dhcp_context_create(); if (status != ISC_R_SUCCESS) log_fatal("Can't initialize context: %s", isc_result_totext(status)); /* Set up the OMAPI. */ status = omapi_init(); if (status != ISC_R_SUCCESS) log_fatal("Can't initialize OMAPI: %s", isc_result_totext(status)); /* Set up the OMAPI wrappers for the interface object. */ interface_setup(); for (i = 1; i < argc; i++) { if (!strcmp(argv[i], "-4")) { #ifdef DHCPv6 if (local_family_set && (local_family == AF_INET6)) { usage(); } local_family_set = 1; local_family = AF_INET; } else if (!strcmp(argv[i], "-6")) { if (local_family_set && (local_family == AF_INET)) { usage(); } local_family_set = 1; local_family = AF_INET6; #endif } else if (!strcmp(argv[i], "-d")) { no_daemon = 1; } else if (!strcmp(argv[i], "-q")) { quiet = 1; quiet_interface_discovery = 1; } else if (!strcmp(argv[i], "-p")) { if (++i == argc) usage(); local_port = validate_port(argv[i]); log_debug("binding to user-specified port %d", ntohs(local_port)); } else if (!strcmp(argv[i], "-c")) { int hcount; if (++i == argc) usage(); hcount = atoi(argv[i]); if (hcount <= 255) max_hop_count= hcount; else usage(); } else if (!strcmp(argv[i], "-i")) { #ifdef DHCPv6 if (local_family_set && (local_family == AF_INET6)) { usage(); } local_family_set = 1; local_family = AF_INET; #endif status = interface_allocate(&tmp, MDL); if (status != ISC_R_SUCCESS) log_fatal("%s: interface_allocate: %s", argv[i], isc_result_totext(status)); if (++i == argc) { usage(); } strcpy(tmp->name, argv[i]); interface_snorf(tmp, INTERFACE_REQUESTED); interface_dereference(&tmp, MDL); } else if (!strcmp(argv[i], "-a")) { #ifdef DHCPv6 if (local_family_set && (local_family == AF_INET6)) { usage(); } local_family_set = 1; local_family = AF_INET; #endif add_agent_options = 1; } else if (!strcmp(argv[i], "-A")) { #ifdef DHCPv6 if (local_family_set && (local_family == AF_INET6)) { usage(); } local_family_set = 1; local_family = AF_INET; #endif if (++i == argc) usage(); dhcp_max_agent_option_packet_length = atoi(argv[i]); if (dhcp_max_agent_option_packet_length > DHCP_MTU_MAX) log_fatal("%s: packet length exceeds " "longest possible MTU\n", argv[i]); } else if (!strcmp(argv[i], "-m")) { #ifdef DHCPv6 if (local_family_set && (local_family == AF_INET6)) { usage(); } local_family_set = 1; local_family = AF_INET; #endif if (++i == argc) usage(); if (!strcasecmp(argv[i], "append")) { agent_relay_mode = forward_and_append; } else if (!strcasecmp(argv[i], "replace")) { agent_relay_mode = forward_and_replace; } else if (!strcasecmp(argv[i], "forward")) { agent_relay_mode = forward_untouched; } else if (!strcasecmp(argv[i], "discard")) { agent_relay_mode = discard; } else usage(); } else if (!strcmp(argv[i], "-D")) { #ifdef DHCPv6 if (local_family_set && (local_family == AF_INET6)) { usage(); } local_family_set = 1; local_family = AF_INET; #endif drop_agent_mismatches = 1; #ifdef DHCPv6 } else if (!strcmp(argv[i], "-I")) { if (local_family_set && (local_family == AF_INET)) { usage(); } local_family_set = 1; local_family = AF_INET6; use_if_id = ISC_TRUE; } else if (!strcmp(argv[i], "-l")) { if (local_family_set && (local_family == AF_INET)) { usage(); } local_family_set = 1; local_family = AF_INET6; if (downstreams != NULL) use_if_id = ISC_TRUE; if (++i == argc) usage(); sl = parse_downstream(argv[i]); sl->next = downstreams; downstreams = sl; } else if (!strcmp(argv[i], "-u")) { if (local_family_set && (local_family == AF_INET)) { usage(); } local_family_set = 1; local_family = AF_INET6; if (++i == argc) usage(); sl = parse_upstream(argv[i]); sl->next = upstreams; upstreams = sl; #endif } else if (!strcmp(argv[i], "-pf")) { if (++i == argc) usage(); path_dhcrelay_pid = argv[i]; no_dhcrelay_pid = ISC_TRUE; } else if (!strcmp(argv[i], "--no-pid")) { no_pid_file = ISC_TRUE; } else if (!strcmp(argv[i], "--version")) { log_info("isc-dhcrelay-%s", PACKAGE_VERSION); exit(0); } else if (!strcmp(argv[i], "--help") || !strcmp(argv[i], "-h")) { log_info(DHCRELAY_USAGE); exit(0); } else if (argv[i][0] == '-') { usage(); } else { struct hostent *he; struct in_addr ia, *iap = NULL; #ifdef DHCPv6 if (local_family_set && (local_family == AF_INET6)) { usage(); } local_family_set = 1; local_family = AF_INET; #endif if (inet_aton(argv[i], &ia)) { iap = &ia; } else { he = gethostbyname(argv[i]); if (!he) { log_error("%s: host unknown", argv[i]); } else { iap = ((struct in_addr *) he->h_addr_list[0]); } } if (iap) { sp = ((struct server_list *) dmalloc(sizeof *sp, MDL)); if (!sp) log_fatal("no memory for server.\n"); sp->next = servers; servers = sp; memcpy(&sp->to.sin_addr, iap, sizeof *iap); } } } /* * If the user didn't specify a pid file directly * find one from environment variables or defaults */ if (no_dhcrelay_pid == ISC_FALSE) { if (local_family == AF_INET) { path_dhcrelay_pid = getenv("PATH_DHCRELAY_PID"); if (path_dhcrelay_pid == NULL) path_dhcrelay_pid = _PATH_DHCRELAY_PID; } #ifdef DHCPv6 else { path_dhcrelay_pid = getenv("PATH_DHCRELAY6_PID"); if (path_dhcrelay_pid == NULL) path_dhcrelay_pid = _PATH_DHCRELAY6_PID; } #endif } if (!quiet) { log_info("%s %s", message, PACKAGE_VERSION); log_info(copyright); log_info(arr); log_info(url); } else { quiet = 0; log_perror = 0; } /* Set default port */ if (local_family == AF_INET) { service_local = "bootps"; service_remote = "bootpc"; port_local = htons(67); port_remote = htons(68); } #ifdef DHCPv6 else { service_local = "dhcpv6-server"; service_remote = "dhcpv6-client"; port_local = htons(547); port_remote = htons(546); } #endif if (!local_port) { ent = getservbyname(service_local, "udp"); if (ent) local_port = ent->s_port; else local_port = port_local; ent = getservbyname(service_remote, "udp"); if (ent) remote_port = ent->s_port; else remote_port = port_remote; endservent(); } if (local_family == AF_INET) { /* We need at least one server */ if (servers == NULL) { log_fatal("No servers specified."); } /* Set up the server sockaddrs. */ for (sp = servers; sp; sp = sp->next) { sp->to.sin_port = local_port; sp->to.sin_family = AF_INET; #ifdef HAVE_SA_LEN sp->to.sin_len = sizeof sp->to; #endif } } #ifdef DHCPv6 else { unsigned code; /* We need at least one upstream and one downstream interface */ if (upstreams == NULL || downstreams == NULL) { log_info("Must specify at least one lower " "and one upper interface.\n"); usage(); } /* Set up the initial dhcp option universe. */ initialize_common_option_spaces(); /* Check requested options. */ code = D6O_RELAY_MSG; if (!option_code_hash_lookup(&requested_opts[0], dhcpv6_universe.code_hash, &code, 0, MDL)) log_fatal("Unable to find the RELAY_MSG " "option definition."); code = D6O_INTERFACE_ID; if (!option_code_hash_lookup(&requested_opts[1], dhcpv6_universe.code_hash, &code, 0, MDL)) log_fatal("Unable to find the INTERFACE_ID " "option definition."); } #endif /* Get the current time... */ gettimeofday(&cur_tv, NULL); /* Discover all the network interfaces. */ discover_interfaces(DISCOVER_RELAY); #ifdef DHCPv6 if (local_family == AF_INET6) setup_streams(); #endif /* Become a daemon... */ if (!no_daemon) { int pid; FILE *pf; int pfdesc; log_perror = 0; if ((pid = fork()) < 0) log_fatal("Can't fork daemon: %m"); else if (pid) exit(0); if (no_pid_file == ISC_FALSE) { pfdesc = open(path_dhcrelay_pid, O_CREAT | O_TRUNC | O_WRONLY, 0644); if (pfdesc < 0) { log_error("Can't create %s: %m", path_dhcrelay_pid); } else { pf = fdopen(pfdesc, "w"); if (!pf) log_error("Can't fdopen %s: %m", path_dhcrelay_pid); else { fprintf(pf, "%ld\n",(long)getpid()); fclose(pf); } } } close(0); close(1); close(2); pid = setsid(); IGNORE_RET (chdir("/")); } /* Set up the packet handler... */ if (local_family == AF_INET) bootp_packet_handler = do_relay4; #ifdef DHCPv6 else dhcpv6_packet_handler = do_packet6; #endif /* Start dispatching packets and timeouts... */ dispatch(); /* Not reached */ return (0); } static void do_relay4(struct interface_info *ip, struct dhcp_packet *packet, unsigned int length, unsigned int from_port, struct iaddr from, struct hardware *hfrom) { struct server_list *sp; struct sockaddr_in to; struct interface_info *out; struct hardware hto, *htop; if (packet->hlen > sizeof packet->chaddr) { log_info("Discarding packet with invalid hlen."); return; } if (ip->address_count < 1 || ip->addresses == NULL) { log_info("Discarding packet received on %s interface that " "has no IPv4 address assigned.", ip->name); return; } /* Find the interface that corresponds to the giaddr in the packet. */ if (packet->giaddr.s_addr) { for (out = interfaces; out; out = out->next) { int i; for (i = 0 ; i < out->address_count ; i++ ) { if (out->addresses[i].s_addr == packet->giaddr.s_addr) i = -1; break; } if (i == -1) break; } } else { out = NULL; } /* If it's a bootreply, forward it to the client. */ if (packet->op == BOOTREPLY) { if (!(packet->flags & htons(BOOTP_BROADCAST)) && can_unicast_without_arp(out)) { to.sin_addr = packet->yiaddr; to.sin_port = remote_port; /* and hardware address is not broadcast */ htop = &hto; } else { to.sin_addr.s_addr = htonl(INADDR_BROADCAST); to.sin_port = remote_port; /* hardware address is broadcast */ htop = NULL; } to.sin_family = AF_INET; #ifdef HAVE_SA_LEN to.sin_len = sizeof to; #endif memcpy(&hto.hbuf[1], packet->chaddr, packet->hlen); hto.hbuf[0] = packet->htype; hto.hlen = packet->hlen + 1; /* Wipe out the agent relay options and, if possible, figure out which interface to use based on the contents of the option that we put on the request to which the server is replying. */ if (!(length = strip_relay_agent_options(ip, &out, packet, length))) return; if (!out) { log_error("Packet to bogus giaddr %s.\n", inet_ntoa(packet->giaddr)); ++bogus_giaddr_drops; return; } if (send_packet(out, NULL, packet, length, out->addresses[0], &to, htop) < 0) { ++server_packet_errors; } else { log_debug("Forwarded BOOTREPLY for %s to %s", print_hw_addr(packet->htype, packet->hlen, packet->chaddr), inet_ntoa(to.sin_addr)); ++server_packets_relayed; } return; } /* If giaddr matches one of our addresses, ignore the packet - we just sent it. */ if (out) return; /* Add relay agent options if indicated. If something goes wrong, drop the packet. */ if (!(length = add_relay_agent_options(ip, packet, length, ip->addresses[0]))) return; /* If giaddr is not already set, Set it so the server can figure out what net it's from and so that we can later forward the response to the correct net. If it's already set, the response will be sent directly to the relay agent that set giaddr, so we won't see it. */ if (!packet->giaddr.s_addr) packet->giaddr = ip->addresses[0]; if (packet->hops < max_hop_count) packet->hops = packet->hops + 1; else return; /* Otherwise, it's a BOOTREQUEST, so forward it to all the servers. */ for (sp = servers; sp; sp = sp->next) { if (send_packet((fallback_interface ? fallback_interface : interfaces), NULL, packet, length, ip->addresses[0], &sp->to, NULL) < 0) { ++client_packet_errors; } else { log_debug("Forwarded BOOTREQUEST for %s to %s", print_hw_addr(packet->htype, packet->hlen, packet->chaddr), inet_ntoa(sp->to.sin_addr)); ++client_packets_relayed; } } } /* Strip any Relay Agent Information options from the DHCP packet option buffer. If there is a circuit ID suboption, look up the outgoing interface based upon it. */ static int strip_relay_agent_options(struct interface_info *in, struct interface_info **out, struct dhcp_packet *packet, unsigned length) { int is_dhcp = 0; u_int8_t *op, *nextop, *sp, *max; int good_agent_option = 0; int status; /* If we're not adding agent options to packets, we're not taking them out either. */ if (!add_agent_options) return (length); /* If there's no cookie, it's a bootp packet, so we should just forward it unchanged. */ if (memcmp(packet->options, DHCP_OPTIONS_COOKIE, 4)) return (length); max = ((u_int8_t *)packet) + length; sp = op = &packet->options[4]; while (op < max) { switch(*op) { /* Skip padding... */ case DHO_PAD: if (sp != op) *sp = *op; ++op; ++sp; continue; /* If we see a message type, it's a DHCP packet. */ case DHO_DHCP_MESSAGE_TYPE: is_dhcp = 1; goto skip; break; /* Quit immediately if we hit an End option. */ case DHO_END: if (sp != op) *sp++ = *op++; goto out; case DHO_DHCP_AGENT_OPTIONS: /* We shouldn't see a relay agent option in a packet before we've seen the DHCP packet type, but if we do, we have to leave it alone. */ if (!is_dhcp) goto skip; /* Do not process an agent option if it exceeds the * buffer. Fail this packet. */ nextop = op + op[1] + 2; if (nextop > max) return (0); status = find_interface_by_agent_option(packet, out, op + 2, op[1]); if (status == -1 && drop_agent_mismatches) return (0); if (status) good_agent_option = 1; op = nextop; break; skip: /* Skip over other options. */ default: /* Fail if processing this option will exceed the * buffer(op[1] is malformed). */ nextop = op + op[1] + 2; if (nextop > max) return (0); if (sp != op) { memmove(sp, op, op[1] + 2); sp += op[1] + 2; op = nextop; } else op = sp = nextop; break; } } out: /* If it's not a DHCP packet, we're not supposed to touch it. */ if (!is_dhcp) return (length); /* If none of the agent options we found matched, or if we didn't find any agent options, count this packet as not having any matching agent options, and if we're relying on agent options to determine the outgoing interface, drop the packet. */ if (!good_agent_option) { ++missing_agent_option; if (drop_agent_mismatches) return (0); } /* Adjust the length... */ if (sp != op) { length = sp -((u_int8_t *)packet); /* Make sure the packet isn't short(this is unlikely, but WTH) */ if (length < BOOTP_MIN_LEN) { memset(sp, DHO_PAD, BOOTP_MIN_LEN - length); length = BOOTP_MIN_LEN; } } return (length); } /* Find an interface that matches the circuit ID specified in the Relay Agent Information option. If one is found, store it through the pointer given; otherwise, leave the existing pointer alone. We actually deviate somewhat from the current specification here: if the option buffer is corrupt, we suggest that the caller not respond to this packet. If the circuit ID doesn't match any known interface, we suggest that the caller to drop the packet. Only if we find a circuit ID that matches an existing interface do we tell the caller to go ahead and process the packet. */ static int find_interface_by_agent_option(struct dhcp_packet *packet, struct interface_info **out, u_int8_t *buf, int len) { int i = 0; u_int8_t *circuit_id = 0; unsigned circuit_id_len = 0; struct interface_info *ip; while (i < len) { /* If the next agent option overflows the end of the packet, the agent option buffer is corrupt. */ if (i + 1 == len || i + buf[i + 1] + 2 > len) { ++corrupt_agent_options; return (-1); } switch(buf[i]) { /* Remember where the circuit ID is... */ case RAI_CIRCUIT_ID: circuit_id = &buf[i + 2]; circuit_id_len = buf[i + 1]; i += circuit_id_len + 2; continue; default: i += buf[i + 1] + 2; break; } } /* If there's no circuit ID, it's not really ours, tell the caller it's no good. */ if (!circuit_id) { ++missing_circuit_id; return (-1); } /* Scan the interface list looking for an interface whose name matches the one specified in circuit_id. */ for (ip = interfaces; ip; ip = ip->next) { if (ip->circuit_id && ip->circuit_id_len == circuit_id_len && !memcmp(ip->circuit_id, circuit_id, circuit_id_len)) break; } /* If we got a match, use it. */ if (ip) { *out = ip; return (1); } /* If we didn't get a match, the circuit ID was bogus. */ ++bad_circuit_id; return (-1); } /* * Examine a packet to see if it's a candidate to have a Relay * Agent Information option tacked onto its tail. If it is, tack * the option on. */ static int add_relay_agent_options(struct interface_info *ip, struct dhcp_packet *packet, unsigned length, struct in_addr giaddr) { int is_dhcp = 0, mms; unsigned optlen; u_int8_t *op, *nextop, *sp, *max, *end_pad = NULL; /* If we're not adding agent options to packets, we can skip this. */ if (!add_agent_options) return (length); /* If there's no cookie, it's a bootp packet, so we should just forward it unchanged. */ if (memcmp(packet->options, DHCP_OPTIONS_COOKIE, 4)) return (length); max = ((u_int8_t *)packet) + dhcp_max_agent_option_packet_length; /* Commence processing after the cookie. */ sp = op = &packet->options[4]; while (op < max) { switch(*op) { /* Skip padding... */ case DHO_PAD: /* Remember the first pad byte so we can commandeer * padded space. * * XXX: Is this really a good idea? Sure, we can * seemingly reduce the packet while we're looking, * but if the packet was signed by the client then * this padding is part of the checksum(RFC3118), * and its nonpresence would break authentication. */ if (end_pad == NULL) end_pad = sp; if (sp != op) *sp++ = *op++; else sp = ++op; continue; /* If we see a message type, it's a DHCP packet. */ case DHO_DHCP_MESSAGE_TYPE: is_dhcp = 1; goto skip; /* * If there's a maximum message size option, we * should pay attention to it */ case DHO_DHCP_MAX_MESSAGE_SIZE: mms = ntohs(*(op + 2)); if (mms < dhcp_max_agent_option_packet_length && mms >= DHCP_MTU_MIN) max = ((u_int8_t *)packet) + mms; goto skip; /* Quit immediately if we hit an End option. */ case DHO_END: goto out; case DHO_DHCP_AGENT_OPTIONS: /* We shouldn't see a relay agent option in a packet before we've seen the DHCP packet type, but if we do, we have to leave it alone. */ if (!is_dhcp) goto skip; end_pad = NULL; /* There's already a Relay Agent Information option in this packet. How embarrassing. Decide what to do based on the mode the user specified. */ switch(agent_relay_mode) { case forward_and_append: goto skip; case forward_untouched: return (length); case discard: return (0); case forward_and_replace: default: break; } /* Skip over the agent option and start copying if we aren't copying already. */ op += op[1] + 2; break; skip: /* Skip over other options. */ default: /* Fail if processing this option will exceed the * buffer(op[1] is malformed). */ nextop = op + op[1] + 2; if (nextop > max) return (0); end_pad = NULL; if (sp != op) { memmove(sp, op, op[1] + 2); sp += op[1] + 2; op = nextop; } else op = sp = nextop; break; } } out: /* If it's not a DHCP packet, we're not supposed to touch it. */ if (!is_dhcp) return (length); /* If the packet was padded out, we can store the agent option at the beginning of the padding. */ if (end_pad != NULL) sp = end_pad; /* Remember where the end of the packet was after parsing it. */ op = sp; /* Sanity check. Had better not ever happen. */ if ((ip->circuit_id_len > 255) ||(ip->circuit_id_len < 1)) log_fatal("Circuit ID length %d out of range [1-255] on " "%s\n", ip->circuit_id_len, ip->name); optlen = ip->circuit_id_len + 2; /* RAI_CIRCUIT_ID + len */ if (ip->remote_id) { if (ip->remote_id_len > 255 || ip->remote_id_len < 1) log_fatal("Remote ID length %d out of range [1-255] " "on %s\n", ip->circuit_id_len, ip->name); optlen += ip->remote_id_len + 2; /* RAI_REMOTE_ID + len */ } /* We do not support relay option fragmenting(multiple options to * support an option data exceeding 255 bytes). */ if ((optlen < 3) ||(optlen > 255)) log_fatal("Total agent option length(%u) out of range " "[3 - 255] on %s\n", optlen, ip->name); /* * Is there room for the option, its code+len, and DHO_END? * If not, forward without adding the option. */ if (max - sp >= optlen + 3) { log_debug("Adding %d-byte relay agent option", optlen + 3); /* Okay, cons up *our* Relay Agent Information option. */ *sp++ = DHO_DHCP_AGENT_OPTIONS; *sp++ = optlen; /* Copy in the circuit id... */ *sp++ = RAI_CIRCUIT_ID; *sp++ = ip->circuit_id_len; memcpy(sp, ip->circuit_id, ip->circuit_id_len); sp += ip->circuit_id_len; /* Copy in remote ID... */ if (ip->remote_id) { *sp++ = RAI_REMOTE_ID; *sp++ = ip->remote_id_len; memcpy(sp, ip->remote_id, ip->remote_id_len); sp += ip->remote_id_len; } } else { ++agent_option_errors; log_error("No room in packet (used %d of %d) " "for %d-byte relay agent option: omitted", (int) (sp - ((u_int8_t *) packet)), (int) (max - ((u_int8_t *) packet)), optlen + 3); } /* * Deposit an END option unless the packet is full (shouldn't * be possible). */ if (sp < max) *sp++ = DHO_END; /* Recalculate total packet length. */ length = sp -((u_int8_t *)packet); /* Make sure the packet isn't short(this is unlikely, but WTH) */ if (length < BOOTP_MIN_LEN) { memset(sp, DHO_PAD, BOOTP_MIN_LEN - length); return (BOOTP_MIN_LEN); } return (length); } #ifdef DHCPv6 /* * Parse a downstream argument: [address%]interface[#index]. */ static struct stream_list * parse_downstream(char *arg) { struct stream_list *dp, *up; struct interface_info *ifp = NULL; char *ifname, *addr, *iid; isc_result_t status; if (!supports_multiple_interfaces(ifp) && (downstreams != NULL)) log_fatal("No support for multiple interfaces."); /* Decode the argument. */ ifname = strchr(arg, '%'); if (ifname == NULL) { ifname = arg; addr = NULL; } else { *ifname++ = '\0'; addr = arg; } iid = strchr(ifname, '#'); if (iid != NULL) { *iid++ = '\0'; } if (strlen(ifname) >= sizeof(ifp->name)) { log_error("Interface name '%s' too long", ifname); usage(); } /* Don't declare twice. */ for (dp = downstreams; dp; dp = dp->next) { if (strcmp(ifname, dp->ifp->name) == 0) log_fatal("Down interface '%s' declared twice.", ifname); } /* Share with up side? */ for (up = upstreams; up; up = up->next) { if (strcmp(ifname, up->ifp->name) == 0) { log_info("Interface '%s' is both down and up.", ifname); ifp = up->ifp; break; } } /* New interface. */ if (ifp == NULL) { status = interface_allocate(&ifp, MDL); if (status != ISC_R_SUCCESS) log_fatal("%s: interface_allocate: %s", arg, isc_result_totext(status)); strcpy(ifp->name, ifname); if (interfaces) { interface_reference(&ifp->next, interfaces, MDL); interface_dereference(&interfaces, MDL); } interface_reference(&interfaces, ifp, MDL); ifp->flags |= INTERFACE_REQUESTED | INTERFACE_DOWNSTREAM; } /* New downstream. */ dp = (struct stream_list *) dmalloc(sizeof(*dp), MDL); if (!dp) log_fatal("No memory for downstream."); dp->ifp = ifp; if (iid != NULL) { dp->id = atoi(iid); } else { dp->id = -1; } /* !addr case handled by setup. */ if (addr && (inet_pton(AF_INET6, addr, &dp->link.sin6_addr) <= 0)) log_fatal("Bad link address '%s'", addr); return dp; } /* * Parse an upstream argument: [address]%interface. */ static struct stream_list * parse_upstream(char *arg) { struct stream_list *up, *dp; struct interface_info *ifp = NULL; char *ifname, *addr; isc_result_t status; /* Decode the argument. */ ifname = strchr(arg, '%'); if (ifname == NULL) { ifname = arg; addr = All_DHCP_Servers; } else { *ifname++ = '\0'; addr = arg; } if (strlen(ifname) >= sizeof(ifp->name)) { log_fatal("Interface name '%s' too long", ifname); } /* Shared up interface? */ for (up = upstreams; up; up = up->next) { if (strcmp(ifname, up->ifp->name) == 0) { ifp = up->ifp; break; } } for (dp = downstreams; dp; dp = dp->next) { if (strcmp(ifname, dp->ifp->name) == 0) { ifp = dp->ifp; break; } } /* New interface. */ if (ifp == NULL) { status = interface_allocate(&ifp, MDL); if (status != ISC_R_SUCCESS) log_fatal("%s: interface_allocate: %s", arg, isc_result_totext(status)); strcpy(ifp->name, ifname); if (interfaces) { interface_reference(&ifp->next, interfaces, MDL); interface_dereference(&interfaces, MDL); } interface_reference(&interfaces, ifp, MDL); ifp->flags |= INTERFACE_REQUESTED | INTERFACE_UPSTREAM; } /* New upstream. */ up = (struct stream_list *) dmalloc(sizeof(*up), MDL); if (up == NULL) log_fatal("No memory for upstream."); up->ifp = ifp; if (inet_pton(AF_INET6, addr, &up->link.sin6_addr) <= 0) log_fatal("Bad address %s", addr); return up; } /* * Setup downstream interfaces. */ static void setup_streams(void) { struct stream_list *dp, *up; int i; isc_boolean_t link_is_set; for (dp = downstreams; dp; dp = dp->next) { /* Check interface */ if (dp->ifp->v6address_count == 0) log_fatal("Interface '%s' has no IPv6 addresses.", dp->ifp->name); /* Check/set link. */ if (IN6_IS_ADDR_UNSPECIFIED(&dp->link.sin6_addr)) link_is_set = ISC_FALSE; else link_is_set = ISC_TRUE; for (i = 0; i < dp->ifp->v6address_count; i++) { if (IN6_IS_ADDR_LINKLOCAL(&dp->ifp->v6addresses[i])) continue; if (!link_is_set) break; if (!memcmp(&dp->ifp->v6addresses[i], &dp->link.sin6_addr, sizeof(dp->link.sin6_addr))) break; } if (i == dp->ifp->v6address_count) log_fatal("Can't find link address for interface '%s'.", dp->ifp->name); if (!link_is_set) memcpy(&dp->link.sin6_addr, &dp->ifp->v6addresses[i], sizeof(dp->link.sin6_addr)); /* Set interface-id. */ if (dp->id == -1) dp->id = dp->ifp->index; } for (up = upstreams; up; up = up->next) { up->link.sin6_port = local_port; up->link.sin6_family = AF_INET6; #ifdef HAVE_SA_LEN up->link.sin6_len = sizeof(up->link); #endif if (up->ifp->v6address_count == 0) log_fatal("Interface '%s' has no IPv6 addresses.", up->ifp->name); } } /* * Add DHCPv6 agent options here. */ static const int required_forw_opts[] = { D6O_INTERFACE_ID, D6O_RELAY_MSG, 0 }; /* * Process a packet upwards, i.e., from client to server. */ static void process_up6(struct packet *packet, struct stream_list *dp) { char forw_data[65535]; unsigned cursor; struct dhcpv6_relay_packet *relay; struct option_state *opts; struct stream_list *up; /* Check if the message should be relayed to the server. */ switch (packet->dhcpv6_msg_type) { case DHCPV6_SOLICIT: case DHCPV6_REQUEST: case DHCPV6_CONFIRM: case DHCPV6_RENEW: case DHCPV6_REBIND: case DHCPV6_RELEASE: case DHCPV6_DECLINE: case DHCPV6_INFORMATION_REQUEST: case DHCPV6_RELAY_FORW: case DHCPV6_LEASEQUERY: log_info("Relaying %s from %s port %d going up.", dhcpv6_type_names[packet->dhcpv6_msg_type], piaddr(packet->client_addr), ntohs(packet->client_port)); break; case DHCPV6_ADVERTISE: case DHCPV6_REPLY: case DHCPV6_RECONFIGURE: case DHCPV6_RELAY_REPL: case DHCPV6_LEASEQUERY_REPLY: log_info("Discarding %s from %s port %d going up.", dhcpv6_type_names[packet->dhcpv6_msg_type], piaddr(packet->client_addr), ntohs(packet->client_port)); return; default: log_info("Unknown %d type from %s port %d going up.", packet->dhcpv6_msg_type, piaddr(packet->client_addr), ntohs(packet->client_port)); return; } /* Build the relay-forward header. */ relay = (struct dhcpv6_relay_packet *) forw_data; cursor = offsetof(struct dhcpv6_relay_packet, options); relay->msg_type = DHCPV6_RELAY_FORW; if (packet->dhcpv6_msg_type == DHCPV6_RELAY_FORW) { if (packet->dhcpv6_hop_count >= max_hop_count) { log_info("Hop count exceeded,"); return; } relay->hop_count = packet->dhcpv6_hop_count + 1; if (dp) { memcpy(&relay->link_address, &dp->link.sin6_addr, 16); } else { /* On smart relay add: && !global. */ if (!use_if_id && downstreams->next) { log_info("Shan't get back the interface."); return; } memset(&relay->link_address, 0, 16); } } else { relay->hop_count = 0; if (!dp) return; memcpy(&relay->link_address, &dp->link.sin6_addr, 16); } memcpy(&relay->peer_address, packet->client_addr.iabuf, 16); /* Get an option state. */ opts = NULL; if (!option_state_allocate(&opts, MDL)) { log_fatal("No memory for upwards options."); } /* Add an interface-id (if used). */ if (use_if_id) { int if_id; if (dp) { if_id = dp->id; } else if (!downstreams->next) { if_id = downstreams->id; } else { log_info("Don't know the interface."); option_state_dereference(&opts, MDL); return; } if (!save_option_buffer(&dhcpv6_universe, opts, NULL, (unsigned char *) &if_id, sizeof(int), D6O_INTERFACE_ID, 0)) { log_error("Can't save interface-id."); option_state_dereference(&opts, MDL); return; } } /* Add the relay-msg carrying the packet. */ if (!save_option_buffer(&dhcpv6_universe, opts, NULL, (unsigned char *) packet->raw, packet->packet_length, D6O_RELAY_MSG, 0)) { log_error("Can't save relay-msg."); option_state_dereference(&opts, MDL); return; } /* Finish the relay-forward message. */ cursor += store_options6(forw_data + cursor, sizeof(forw_data) - cursor, opts, packet, required_forw_opts, NULL); option_state_dereference(&opts, MDL); /* Send it to all upstreams. */ for (up = upstreams; up; up = up->next) { send_packet6(up->ifp, (unsigned char *) forw_data, (size_t) cursor, &up->link); } } /* * Process a packet downwards, i.e., from server to client. */ static void process_down6(struct packet *packet) { struct stream_list *dp; struct option_cache *oc; struct data_string relay_msg; const struct dhcpv6_packet *msg; struct data_string if_id; struct sockaddr_in6 to; struct iaddr peer; /* The packet must be a relay-reply message. */ if (packet->dhcpv6_msg_type != DHCPV6_RELAY_REPL) { if (packet->dhcpv6_msg_type < dhcpv6_type_name_max) log_info("Discarding %s from %s port %d going down.", dhcpv6_type_names[packet->dhcpv6_msg_type], piaddr(packet->client_addr), ntohs(packet->client_port)); else log_info("Unknown %d type from %s port %d going down.", packet->dhcpv6_msg_type, piaddr(packet->client_addr), ntohs(packet->client_port)); return; } /* Inits. */ memset(&relay_msg, 0, sizeof(relay_msg)); memset(&if_id, 0, sizeof(if_id)); memset(&to, 0, sizeof(to)); to.sin6_family = AF_INET6; #ifdef HAVE_SA_LEN to.sin6_len = sizeof(to); #endif to.sin6_port = remote_port; peer.len = 16; /* Get the relay-msg option (carrying the message to relay). */ oc = lookup_option(&dhcpv6_universe, packet->options, D6O_RELAY_MSG); if (oc == NULL) { log_info("No relay-msg."); return; } if (!evaluate_option_cache(&relay_msg, packet, NULL, NULL, packet->options, NULL, &global_scope, oc, MDL) || (relay_msg.len < offsetof(struct dhcpv6_packet, options))) { log_error("Can't evaluate relay-msg."); return; } msg = (const struct dhcpv6_packet *) relay_msg.data; /* Get the interface-id (if exists) and the downstream. */ oc = lookup_option(&dhcpv6_universe, packet->options, D6O_INTERFACE_ID); if (oc != NULL) { int if_index; if (!evaluate_option_cache(&if_id, packet, NULL, NULL, packet->options, NULL, &global_scope, oc, MDL) || (if_id.len != sizeof(int))) { log_info("Can't evaluate interface-id."); goto cleanup; } memcpy(&if_index, if_id.data, sizeof(int)); for (dp = downstreams; dp; dp = dp->next) { if (dp->id == if_index) break; } } else { if (use_if_id) { /* Require an interface-id. */ log_info("No interface-id."); goto cleanup; } for (dp = downstreams; dp; dp = dp->next) { /* Get the first matching one. */ if (!memcmp(&dp->link.sin6_addr, &packet->dhcpv6_link_address, sizeof(struct in6_addr))) break; } } /* Why bother when there is no choice. */ if (!dp && !downstreams->next) dp = downstreams; if (!dp) { log_info("Can't find the down interface."); goto cleanup; } memcpy(peer.iabuf, &packet->dhcpv6_peer_address, peer.len); to.sin6_addr = packet->dhcpv6_peer_address; /* Check if we should relay the carried message. */ switch (msg->msg_type) { /* Relay-Reply of for another relay, not a client. */ case DHCPV6_RELAY_REPL: to.sin6_port = local_port; /* Fall into: */ case DHCPV6_ADVERTISE: case DHCPV6_REPLY: case DHCPV6_RECONFIGURE: case DHCPV6_RELAY_FORW: case DHCPV6_LEASEQUERY_REPLY: log_info("Relaying %s to %s port %d down.", dhcpv6_type_names[msg->msg_type], piaddr(peer), ntohs(to.sin6_port)); break; case DHCPV6_SOLICIT: case DHCPV6_REQUEST: case DHCPV6_CONFIRM: case DHCPV6_RENEW: case DHCPV6_REBIND: case DHCPV6_RELEASE: case DHCPV6_DECLINE: case DHCPV6_INFORMATION_REQUEST: case DHCPV6_LEASEQUERY: log_info("Discarding %s to %s port %d down.", dhcpv6_type_names[msg->msg_type], piaddr(peer), ntohs(to.sin6_port)); goto cleanup; default: log_info("Unknown %d type to %s port %d down.", msg->msg_type, piaddr(peer), ntohs(to.sin6_port)); goto cleanup; } /* Send the message to the downstream. */ send_packet6(dp->ifp, (unsigned char *) relay_msg.data, (size_t) relay_msg.len, &to); cleanup: if (relay_msg.data != NULL) data_string_forget(&relay_msg, MDL); if (if_id.data != NULL) data_string_forget(&if_id, MDL); } /* * Called by the dispatch packet handler with a decoded packet. */ void dhcpv6(struct packet *packet) { struct stream_list *dp; /* Try all relay-replies downwards. */ if (packet->dhcpv6_msg_type == DHCPV6_RELAY_REPL) { process_down6(packet); return; } /* Others are candidates to go up if they come from down. */ for (dp = downstreams; dp; dp = dp->next) { if (packet->interface != dp->ifp) continue; process_up6(packet, dp); return; } /* Relay-forward could work from an unknown interface. */ if (packet->dhcpv6_msg_type == DHCPV6_RELAY_FORW) { process_up6(packet, NULL); return; } log_info("Can't process packet from interface '%s'.", packet->interface->name); } #endif /* Stub routines needed for linking with DHCP libraries. */ void bootp(struct packet *packet) { return; } void dhcp(struct packet *packet) { return; } void classify(struct packet *p, struct class *c) { return; } int check_collection(struct packet *p, struct lease *l, struct collection *c) { return 0; } isc_result_t find_class(struct class **class, const char *c1, const char *c2, int i) { return ISC_R_NOTFOUND; } int parse_allow_deny(struct option_cache **oc, struct parse *p, int i) { return 0; } isc_result_t dhcp_set_control_state(control_object_state_t oldstate, control_object_state_t newstate) { return ISC_R_SUCCESS; } dhcp-4.2.4/relay/Makefile.am000644 000765 000024 00000000403 11271742256 015543 0ustar00sarstaff000000 000000 AM_CPPFLAGS = -DLOCALSTATEDIR='"@localstatedir@"' sbin_PROGRAMS = dhcrelay dhcrelay_SOURCES = dhcrelay.c dhcrelay_LDADD = ../common/libdhcp.a ../omapip/libomapi.a \ ../bind/lib/libdns.a ../bind/lib/libisc.a man_MANS = dhcrelay.8 EXTRA_DIST = $(man_MANS) dhcp-4.2.4/relay/Makefile.in000644 000765 000024 00000034735 11757500142 015566 0ustar00sarstaff000000 000000 # Makefile.in generated by automake 1.10.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : sbin_PROGRAMS = dhcrelay$(EXEEXT) subdir = relay DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/includes/config.h CONFIG_CLEAN_FILES = am__installdirs = "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(man8dir)" sbinPROGRAMS_INSTALL = $(INSTALL_PROGRAM) PROGRAMS = $(sbin_PROGRAMS) am_dhcrelay_OBJECTS = dhcrelay.$(OBJEXT) dhcrelay_OBJECTS = $(am_dhcrelay_OBJECTS) dhcrelay_DEPENDENCIES = ../common/libdhcp.a ../omapip/libomapi.a \ ../bind/lib/libdns.a ../bind/lib/libisc.a DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/includes depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) CCLD = $(CC) LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ SOURCES = $(dhcrelay_SOURCES) DIST_SOURCES = $(dhcrelay_SOURCES) man8dir = $(mandir)/man8 NROFF = nroff MANS = $(man_MANS) ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ GREP = @GREP@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDAP_CFLAGS = @LDAP_CFLAGS@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_prefix_program = @ac_prefix_program@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build_alias = @build_alias@ builddir = @builddir@ byte_order = @byte_order@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host_alias = @host_alias@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AM_CPPFLAGS = -DLOCALSTATEDIR='"@localstatedir@"' dhcrelay_SOURCES = dhcrelay.c dhcrelay_LDADD = ../common/libdhcp.a ../omapip/libomapi.a \ ../bind/lib/libdns.a ../bind/lib/libisc.a man_MANS = dhcrelay.8 EXTRA_DIST = $(man_MANS) all: all-am .SUFFIXES: .SUFFIXES: .c .o .obj $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ && exit 0; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign relay/Makefile'; \ cd $(top_srcdir) && \ $(AUTOMAKE) --foreign relay/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh install-sbinPROGRAMS: $(sbin_PROGRAMS) @$(NORMAL_INSTALL) test -z "$(sbindir)" || $(MKDIR_P) "$(DESTDIR)$(sbindir)" @list='$(sbin_PROGRAMS)'; for p in $$list; do \ p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ if test -f $$p \ ; then \ f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \ echo " $(INSTALL_PROGRAM_ENV) $(sbinPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(sbindir)/$$f'"; \ $(INSTALL_PROGRAM_ENV) $(sbinPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(sbindir)/$$f" || exit 1; \ else :; fi; \ done uninstall-sbinPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(sbin_PROGRAMS)'; for p in $$list; do \ f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ echo " rm -f '$(DESTDIR)$(sbindir)/$$f'"; \ rm -f "$(DESTDIR)$(sbindir)/$$f"; \ done clean-sbinPROGRAMS: -test -z "$(sbin_PROGRAMS)" || rm -f $(sbin_PROGRAMS) dhcrelay$(EXEEXT): $(dhcrelay_OBJECTS) $(dhcrelay_DEPENDENCIES) @rm -f dhcrelay$(EXEEXT) $(LINK) $(dhcrelay_OBJECTS) $(dhcrelay_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dhcrelay.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` install-man8: $(man8_MANS) $(man_MANS) @$(NORMAL_INSTALL) test -z "$(man8dir)" || $(MKDIR_P) "$(DESTDIR)$(man8dir)" @list='$(man8_MANS) $(dist_man8_MANS) $(nodist_man8_MANS)'; \ l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ for i in $$l2; do \ case "$$i" in \ *.8*) list="$$list $$i" ;; \ esac; \ done; \ for i in $$list; do \ if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \ else file=$$i; fi; \ ext=`echo $$i | sed -e 's/^.*\\.//'`; \ case "$$ext" in \ 8*) ;; \ *) ext='8' ;; \ esac; \ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ inst=`echo $$inst | sed -e 's/^.*\///'`; \ inst=`echo $$inst | sed '$(transform)'`.$$ext; \ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man8dir)/$$inst'"; \ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man8dir)/$$inst"; \ done uninstall-man8: @$(NORMAL_UNINSTALL) @list='$(man8_MANS) $(dist_man8_MANS) $(nodist_man8_MANS)'; \ l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ for i in $$l2; do \ case "$$i" in \ *.8*) list="$$list $$i" ;; \ esac; \ done; \ for i in $$list; do \ ext=`echo $$i | sed -e 's/^.*\\.//'`; \ case "$$ext" in \ 8*) ;; \ *) ext='8' ;; \ esac; \ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ inst=`echo $$inst | sed -e 's/^.*\///'`; \ inst=`echo $$inst | sed '$(transform)'`.$$ext; \ echo " rm -f '$(DESTDIR)$(man8dir)/$$inst'"; \ rm -f "$(DESTDIR)$(man8dir)/$$inst"; \ done ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) tags=; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$tags $$unique; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) tags=; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$tags$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$tags $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && cd $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) $$here distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ fi; \ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ else \ test -f $(distdir)/$$file \ || cp -p $$d/$$file $(distdir)/$$file \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(PROGRAMS) $(MANS) installdirs: for dir in "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(man8dir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-sbinPROGRAMS mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am info: info-am info-am: install-data-am: install-man install-dvi: install-dvi-am install-exec-am: install-sbinPROGRAMS install-html: install-html-am install-info: install-info-am install-man: install-man8 install-pdf: install-pdf-am install-ps: install-ps-am installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-man uninstall-sbinPROGRAMS uninstall-man: uninstall-man8 .MAKE: install-am install-strip .PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ clean-sbinPROGRAMS ctags distclean distclean-compile \ distclean-generic distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-man8 install-pdf \ install-pdf-am install-ps install-ps-am install-sbinPROGRAMS \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-compile mostlyclean-generic pdf pdf-am ps ps-am \ tags uninstall uninstall-am uninstall-man uninstall-man8 \ uninstall-sbinPROGRAMS # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: dhcp-4.2.4/omapip/alloc.c000644 000765 000024 00000070236 11441542650 015124 0ustar00sarstaff000000 000000 /* alloc.c Functions supporting memory allocation for the object management protocol... */ /* * Copyright (c) 2009-2010 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 2004-2007 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1999-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ * * This software has been written for Internet Systems Consortium * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. * To learn more about Internet Systems Consortium, see * ``https://www.isc.org/''. To learn more about Vixie Enterprises, * see ``http://www.vix.com''. To learn more about Nominum, Inc., see * ``http://www.nominum.com''. */ #include "dhcpd.h" #include #if defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL) || \ defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT) struct dmalloc_preamble *dmalloc_list; unsigned long dmalloc_outstanding; unsigned long dmalloc_longterm; unsigned long dmalloc_generation; unsigned long dmalloc_cutoff_generation; #endif #if defined (DEBUG_RC_HISTORY) struct rc_history_entry rc_history [RC_HISTORY_MAX]; int rc_history_index; int rc_history_count; #endif #if defined (DEBUG_RC_HISTORY) static void print_rc_hist_entry (int); #endif void * dmalloc(unsigned size, const char *file, int line) { unsigned char *foo; unsigned len; void **bar; #if defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL) || \ defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT) int i; struct dmalloc_preamble *dp; #endif len = size + DMDSIZE; if (len < size) return NULL; foo = malloc(len); if (!foo) return NULL; bar = (void *)(foo + DMDOFFSET); memset (bar, 0, size); #if defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL) || \ defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT) dp = (struct dmalloc_preamble *)foo; dp -> prev = dmalloc_list; if (dmalloc_list) dmalloc_list -> next = dp; dmalloc_list = dp; dp -> next = (struct dmalloc_preamble *)0; dp -> size = size; dp -> file = file; dp -> line = line; dp -> generation = dmalloc_generation++; dmalloc_outstanding += size; for (i = 0; i < DMLFSIZE; i++) dp -> low_fence [i] = (((unsigned long) (&dp -> low_fence [i])) % 143) + 113; for (i = DMDOFFSET; i < DMDSIZE; i++) foo [i + size] = (((unsigned long) (&foo [i + size])) % 143) + 113; #if defined (DEBUG_MALLOC_POOL_EXHAUSTIVELY) /* Check _every_ entry in the pool! Very expensive. */ for (dp = dmalloc_list; dp; dp = dp -> prev) { for (i = 0; i < DMLFSIZE; i++) { if (dp -> low_fence [i] != (((unsigned long) (&dp -> low_fence [i])) % 143) + 113) { log_error ("malloc fence modified: %s(%d)", dp -> file, dp -> line); abort (); } } foo = (unsigned char *)dp; for (i = DMDOFFSET; i < DMDSIZE; i++) { if (foo [i + dp -> size] != (((unsigned long) (&foo [i + dp -> size])) % 143) + 113) { log_error ("malloc fence modified: %s(%d)", dp -> file, dp -> line); abort (); } } } #endif #endif #ifdef DEBUG_REFCNT_DMALLOC_FREE rc_register (file, line, 0, foo + DMDOFFSET, 1, 0, RC_MALLOC); #endif return bar; } void dfree(void *ptr, const char *file, int line) { if (!ptr) { log_error ("dfree %s(%d): free on null pointer.", file, line); return; } #if defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL) || \ defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT) { unsigned char *bar = ptr; struct dmalloc_preamble *dp, *cur; int i; bar -= DMDOFFSET; cur = (struct dmalloc_preamble *)bar; for (dp = dmalloc_list; dp; dp = dp -> prev) if (dp == cur) break; if (!dp) { log_error ("%s(%d): freeing unknown memory: %lx", file, line, (unsigned long)cur); abort (); } if (dp -> prev) dp -> prev -> next = dp -> next; if (dp -> next) dp -> next -> prev = dp -> prev; if (dp == dmalloc_list) dmalloc_list = dp -> prev; if (dp -> generation >= dmalloc_cutoff_generation) dmalloc_outstanding -= dp -> size; else dmalloc_longterm -= dp -> size; for (i = 0; i < DMLFSIZE; i++) { if (dp -> low_fence [i] != (((unsigned long) (&dp -> low_fence [i])) % 143) + 113) { log_error ("malloc fence modified: %s(%d)", dp -> file, dp -> line); abort (); } } for (i = DMDOFFSET; i < DMDSIZE; i++) { if (bar [i + dp -> size] != (((unsigned long) (&bar [i + dp -> size])) % 143) + 113) { log_error ("malloc fence modified: %s(%d)", dp -> file, dp -> line); abort (); } } ptr = bar; } #endif #ifdef DEBUG_REFCNT_DMALLOC_FREE rc_register (file, line, 0, (unsigned char *)ptr + DMDOFFSET, 0, 1, RC_MALLOC); #endif free (ptr); } #if defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL) || \ defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT) /* For allocation functions that keep their own free lists, we want to account for the reuse of the memory. */ void dmalloc_reuse(void *foo, const char *file, int line, int justref) { struct dmalloc_preamble *dp; /* Get the pointer to the dmalloc header. */ dp = foo; dp--; /* If we just allocated this and are now referencing it, this function would almost be a no-op, except that it would increment the generation count needlessly. So just return in this case. */ if (dp -> generation == dmalloc_generation) return; /* If this is longterm data, and we just made reference to it, don't put it on the short-term list or change its name - we don't need to know about this. */ if (dp -> generation < dmalloc_cutoff_generation && justref) return; /* Take it out of the place in the allocated list where it was. */ if (dp -> prev) dp -> prev -> next = dp -> next; if (dp -> next) dp -> next -> prev = dp -> prev; if (dp == dmalloc_list) dmalloc_list = dp -> prev; /* Account for its removal. */ if (dp -> generation >= dmalloc_cutoff_generation) dmalloc_outstanding -= dp -> size; else dmalloc_longterm -= dp -> size; /* Now put it at the head of the list. */ dp -> prev = dmalloc_list; if (dmalloc_list) dmalloc_list -> next = dp; dmalloc_list = dp; dp -> next = (struct dmalloc_preamble *)0; /* Change the reference location information. */ dp -> file = file; dp -> line = line; /* Increment the generation. */ dp -> generation = dmalloc_generation++; /* Account for it. */ dmalloc_outstanding += dp -> size; } void dmalloc_dump_outstanding () { static unsigned long dmalloc_cutoff_point; struct dmalloc_preamble *dp; #if defined(DEBUG_MALLOC_POOL) unsigned char *foo; int i; #endif if (!dmalloc_cutoff_point) dmalloc_cutoff_point = dmalloc_cutoff_generation; for (dp = dmalloc_list; dp; dp = dp -> prev) { if (dp -> generation <= dmalloc_cutoff_point) break; #if defined (DEBUG_MALLOC_POOL) for (i = 0; i < DMLFSIZE; i++) { if (dp -> low_fence [i] != (((unsigned long) (&dp -> low_fence [i])) % 143) + 113) { log_error ("malloc fence modified: %s(%d)", dp -> file, dp -> line); abort (); } } foo = (unsigned char *)dp; for (i = DMDOFFSET; i < DMDSIZE; i++) { if (foo [i + dp -> size] != (((unsigned long) (&foo [i + dp -> size])) % 143) + 113) { log_error ("malloc fence modified: %s(%d)", dp -> file, dp -> line); abort (); } } #endif #if defined (DEBUG_MEMORY_LEAKAGE) || \ defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT) /* Don't count data that's actually on a free list somewhere. */ if (dp -> file) { #if defined (DEBUG_RC_HISTORY) int i, count, inhistory = 0, noted = 0; /* If we have the info, see if this is actually new garbage. */ if (rc_history_count < RC_HISTORY_MAX) { count = rc_history_count; } else count = RC_HISTORY_MAX; i = rc_history_index - 1; if (i < 0) i += RC_HISTORY_MAX; do { if (rc_history [i].addr == dp + 1) { inhistory = 1; if (!noted) { log_info (" %s(%d): %ld", dp -> file, dp -> line, dp -> size); noted = 1; } print_rc_hist_entry (i); if (!rc_history [i].refcnt) break; } if (--i < 0) i = RC_HISTORY_MAX - 1; } while (count--); if (!inhistory) #endif log_info (" %s(%d): %ld", dp -> file, dp -> line, dp -> size); } #endif } if (dmalloc_list) dmalloc_cutoff_point = dmalloc_list -> generation; } #endif /* DEBUG_MEMORY_LEAKAGE || DEBUG_MALLOC_POOL */ #if defined (DEBUG_RC_HISTORY) static void print_rc_hist_entry (int i) { log_info (" referenced by %s(%d)[%lx]: addr = %lx refcnt = %x", rc_history [i].file, rc_history [i].line, (unsigned long)rc_history [i].reference, (unsigned long)rc_history [i].addr, rc_history [i].refcnt); } void dump_rc_history (void *addr) { int i; i = rc_history_index; if (!rc_history [i].file) i = 0; else if (rc_history_count < RC_HISTORY_MAX) { i -= rc_history_count; if (i < 0) i += RC_HISTORY_MAX; } rc_history_count = 0; while (rc_history [i].file) { if (!addr || addr == rc_history [i].addr) print_rc_hist_entry (i); ++i; if (i == RC_HISTORY_MAX) i = 0; if (i == rc_history_index) break; } } void rc_history_next (int d) { #if defined (RC_HISTORY_COMPRESSION) int i, j = 0, m, n = 0; void *ap, *rp; /* If we are decreasing the reference count, try to find the entry where the reference was made and eliminate it; then we can also eliminate this reference. */ if (d) { m = rc_history_index - 1000; if (m < -1) m = -1; ap = rc_history [rc_history_index].addr; rp = rc_history [rc_history_index].reference; for (i = rc_history_index - 1; i > m; i--) { if (rc_history [i].addr == ap) { if (rc_history [i].reference == rp) { if (n > 10) { for (n = i; n <= rc_history_index; n++) print_rc_hist_entry (n); n = 11; } memmove (&rc_history [i], &rc_history [i + 1], (unsigned)((rc_history_index - i) * sizeof (struct rc_history_entry))); --rc_history_count; --rc_history_index; for (j = i; j < rc_history_count; j++) { if (rc_history [j].addr == ap) --rc_history [j].refcnt; } if (n > 10) { for (n = i; n <= rc_history_index; n++) print_rc_hist_entry (n); n = 11; exit (0); } return; } } } } #endif if (++rc_history_index == RC_HISTORY_MAX) rc_history_index = 0; ++rc_history_count; } #endif /* DEBUG_RC_HISTORY */ #if defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL) || \ defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT) struct caller { struct dmalloc_preamble *dp; int count; }; static int dmalloc_find_entry (struct dmalloc_preamble *dp, struct caller *array, int min, int max) { int middle; middle = (min + max) / 2; if (middle == min) return middle; if (array [middle].dp -> file == dp -> file) { if (array [middle].dp -> line == dp -> line) return middle; else if (array [middle].dp -> line < dp -> line) return dmalloc_find_entry (dp, array, middle, max); else return dmalloc_find_entry (dp, array, 0, middle); } else if (array [middle].dp -> file < dp -> file) return dmalloc_find_entry (dp, array, middle, max); else return dmalloc_find_entry (dp, array, 0, middle); } void omapi_print_dmalloc_usage_by_caller () { struct dmalloc_preamble *dp; int ccur, cmax, i; struct caller cp [1024]; cmax = 1024; ccur = 0; memset (cp, 0, sizeof cp); for (dp = dmalloc_list; dp; dp = dp -> prev) { i = dmalloc_find_entry (dp, cp, 0, ccur); if ((i == ccur || cp [i].dp -> file != dp -> file || cp [i].dp -> line != dp -> line) && ccur == cmax) { log_error ("no space for memory usage summary."); return; } if (i == ccur) { cp [ccur++].dp = dp; cp [i].count = 1; } else if (cp [i].dp -> file < dp -> file || (cp [i].dp -> file == dp -> file && cp [i].dp -> line < dp -> line)) { if (i + 1 != ccur) memmove (cp + i + 2, cp + i + 1, (ccur - i) * sizeof *cp); cp [i + 1].dp = dp; cp [i + 1].count = 1; ccur++; } else if (cp [i].dp -> file != dp -> file || cp [i].dp -> line != dp -> line) { memmove (cp + i + 1, cp + i, (ccur - i) * sizeof *cp); cp [i].dp = dp; cp [i].count = 1; ccur++; } else cp [i].count++; #if 0 printf ("%d\t%s:%d\n", i, dp -> file, dp -> line); dump_rc_history (dp + 1); #endif } for (i = 0; i < ccur; i++) { printf ("%d\t%s:%d\t%d\n", i, cp [i].dp -> file, cp [i].dp -> line, cp [i].count); #if defined(DUMP_RC_HISTORY) dump_rc_history (cp [i].dp + 1); #endif } } #endif /* DEBUG_MEMORY_LEAKAGE || DEBUG_MALLOC_POOL */ isc_result_t omapi_object_allocate (omapi_object_t **o, omapi_object_type_t *type, size_t size, const char *file, int line) { size_t tsize; omapi_object_t *foo; isc_result_t status; if (type -> allocator) { foo = (omapi_object_t *)0; status = (*type -> allocator) (&foo, file, line); tsize = type -> size; } else { status = ISC_R_NOMEMORY; tsize = 0; } if (status == ISC_R_NOMEMORY) { if (type -> sizer) tsize = (*type -> sizer) (size); else tsize = type -> size; /* Sanity check. */ if (tsize < sizeof (omapi_object_t)) return DHCP_R_INVALIDARG; foo = dmalloc (tsize, file, line); if (!foo) return ISC_R_NOMEMORY; } status = omapi_object_initialize (foo, type, size, tsize, file, line); if (status != ISC_R_SUCCESS) { if (type -> freer) (*type -> freer) (foo, file, line); else dfree (foo, file, line); return status; } return omapi_object_reference (o, foo, file, line); } isc_result_t omapi_object_initialize (omapi_object_t *o, omapi_object_type_t *type, size_t usize, size_t psize, const char *file, int line) { memset (o, 0, psize); o -> type = type; if (type -> initialize) (*type -> initialize) (o, file, line); return ISC_R_SUCCESS; } isc_result_t omapi_object_reference (omapi_object_t **r, omapi_object_t *h, const char *file, int line) { if (!h || !r) return DHCP_R_INVALIDARG; if (*r) { #if defined (POINTER_DEBUG) log_error ("%s(%d): reference store into non-null pointer!", file, line); abort (); #else return DHCP_R_INVALIDARG; #endif } *r = h; h -> refcnt++; rc_register (file, line, r, h, h -> refcnt, 0, h -> type -> rc_flag); return ISC_R_SUCCESS; } isc_result_t omapi_object_dereference (omapi_object_t **h, const char *file, int line) { int outer_reference = 0; int inner_reference = 0; int handle_reference = 0; int extra_references; omapi_object_t *p, *hp; if (!h) return DHCP_R_INVALIDARG; if (!*h) { #if defined (POINTER_DEBUG) log_error ("%s(%d): dereference of null pointer!", file, line); abort (); #else return DHCP_R_INVALIDARG; #endif } if ((*h) -> refcnt <= 0) { #if defined (POINTER_DEBUG) log_error ("%s(%d): dereference of pointer with refcnt of zero!", file, line); #if defined (DEBUG_RC_HISTORY) dump_rc_history (*h); #endif abort (); #else *h = 0; return DHCP_R_INVALIDARG; #endif } /* See if this object's inner object refers to it, but don't count this as a reference if we're being asked to free the reference from the inner object. */ if ((*h) -> inner && (*h) -> inner -> outer && h != &((*h) -> inner -> outer)) inner_reference = 1; /* Ditto for the outer object. */ if ((*h) -> outer && (*h) -> outer -> inner && h != &((*h) -> outer -> inner)) outer_reference = 1; /* Ditto for the outer object. The code below assumes that the only reason we'd get a dereference from the handle table is if this function does it - otherwise we'd have to traverse the handle table to find the address where the reference is stored and compare against that, and we don't want to do that if we can avoid it. */ if ((*h) -> handle) handle_reference = 1; /* If we are getting rid of the last reference other than references to inner and outer objects, or from the handle table, then we must examine all the objects in either direction to see if they hold any non-inner, non-outer, non-handle-table references. If not, we need to free the entire chain of objects. */ if ((*h) -> refcnt == inner_reference + outer_reference + handle_reference + 1) { if (inner_reference || outer_reference || handle_reference) { /* XXX we could check for a reference from the handle table here. */ extra_references = 0; for (p = (*h) -> inner; p && !extra_references; p = p -> inner) { extra_references += p -> refcnt; if (p -> inner && p -> inner -> outer == p) --extra_references; if (p -> outer) --extra_references; if (p -> handle) --extra_references; } for (p = (*h) -> outer; p && !extra_references; p = p -> outer) { extra_references += p -> refcnt; if (p -> outer && p -> outer -> inner == p) --extra_references; if (p -> inner) --extra_references; if (p -> handle) --extra_references; } } else extra_references = 0; if (!extra_references) { hp = *h; *h = 0; hp -> refcnt--; if (inner_reference) omapi_object_dereference (&hp -> inner, file, line); if (outer_reference) omapi_object_dereference (&hp -> outer, file, line); /* if (!hp -> type -> freer) */ rc_register (file, line, h, hp, 0, 1, hp -> type -> rc_flag); if (handle_reference) { if (omapi_handle_clear(hp->handle) != ISC_R_SUCCESS) { log_debug("Attempt to clear null " "handle pointer"); } } if (hp -> type -> destroy) (*(hp -> type -> destroy)) (hp, file, line); if (hp -> type -> freer) (hp -> type -> freer (hp, file, line)); else dfree (hp, file, line); } else { (*h) -> refcnt--; /* if (!(*h) -> type -> freer) */ rc_register (file, line, h, *h, (*h) -> refcnt, 1, (*h) -> type -> rc_flag); } } else { (*h) -> refcnt--; /* if (!(*h) -> type -> freer) */ rc_register (file, line, h, *h, (*h) -> refcnt, 1, (*h) -> type -> rc_flag); } *h = 0; return ISC_R_SUCCESS; } isc_result_t omapi_buffer_new (omapi_buffer_t **h, const char *file, int line) { omapi_buffer_t *t; isc_result_t status; t = (omapi_buffer_t *)dmalloc (sizeof *t, file, line); if (!t) return ISC_R_NOMEMORY; memset (t, 0, sizeof *t); status = omapi_buffer_reference (h, t, file, line); if (status != ISC_R_SUCCESS) dfree (t, file, line); (*h) -> head = sizeof ((*h) -> buf) - 1; return status; } isc_result_t omapi_buffer_reference (omapi_buffer_t **r, omapi_buffer_t *h, const char *file, int line) { if (!h || !r) return DHCP_R_INVALIDARG; if (*r) { #if defined (POINTER_DEBUG) log_error ("%s(%d): reference store into non-null pointer!", file, line); abort (); #else return DHCP_R_INVALIDARG; #endif } *r = h; h -> refcnt++; rc_register (file, line, r, h, h -> refcnt, 0, RC_MISC); return ISC_R_SUCCESS; } isc_result_t omapi_buffer_dereference (omapi_buffer_t **h, const char *file, int line) { if (!h) return DHCP_R_INVALIDARG; if (!*h) { #if defined (POINTER_DEBUG) log_error ("%s(%d): dereference of null pointer!", file, line); abort (); #else return DHCP_R_INVALIDARG; #endif } if ((*h) -> refcnt <= 0) { #if defined (POINTER_DEBUG) log_error ("%s(%d): dereference of pointer with refcnt of zero!", file, line); #if defined (DEBUG_RC_HISTORY) dump_rc_history (*h); #endif abort (); #else *h = 0; return DHCP_R_INVALIDARG; #endif } --(*h) -> refcnt; rc_register (file, line, h, *h, (*h) -> refcnt, 1, RC_MISC); if ((*h) -> refcnt == 0) dfree (*h, file, line); *h = 0; return ISC_R_SUCCESS; } isc_result_t omapi_typed_data_new (const char *file, int line, omapi_typed_data_t **t, omapi_datatype_t type, ...) { va_list l; omapi_typed_data_t *new; unsigned len; unsigned val = 0; int intval = 0; char *s = NULL; isc_result_t status; omapi_object_t *obj = NULL; va_start (l, type); switch (type) { case omapi_datatype_int: len = OMAPI_TYPED_DATA_INT_LEN; intval = va_arg (l, int); break; case omapi_datatype_string: s = va_arg (l, char *); val = strlen (s); len = OMAPI_TYPED_DATA_NOBUFFER_LEN + val; if (len < val) { va_end(l); return DHCP_R_INVALIDARG; } break; case omapi_datatype_data: val = va_arg (l, unsigned); len = OMAPI_TYPED_DATA_NOBUFFER_LEN + val; if (len < val) { va_end(l); return DHCP_R_INVALIDARG; } break; case omapi_datatype_object: len = OMAPI_TYPED_DATA_OBJECT_LEN; obj = va_arg (l, omapi_object_t *); break; default: va_end (l); return DHCP_R_INVALIDARG; } va_end (l); new = dmalloc (len, file, line); if (!new) return ISC_R_NOMEMORY; memset (new, 0, len); switch (type) { case omapi_datatype_int: new -> u.integer = intval; break; case omapi_datatype_string: memcpy (new -> u.buffer.value, s, val); new -> u.buffer.len = val; break; case omapi_datatype_data: new -> u.buffer.len = val; break; case omapi_datatype_object: status = omapi_object_reference (&new -> u.object, obj, file, line); if (status != ISC_R_SUCCESS) { dfree (new, file, line); return status; } break; } new -> type = type; return omapi_typed_data_reference (t, new, file, line); } isc_result_t omapi_typed_data_reference (omapi_typed_data_t **r, omapi_typed_data_t *h, const char *file, int line) { if (!h || !r) return DHCP_R_INVALIDARG; if (*r) { #if defined (POINTER_DEBUG) log_error ("%s(%d): reference store into non-null pointer!", file, line); abort (); #else return DHCP_R_INVALIDARG; #endif } *r = h; h -> refcnt++; rc_register (file, line, r, h, h -> refcnt, 0, RC_MISC); return ISC_R_SUCCESS; } isc_result_t omapi_typed_data_dereference (omapi_typed_data_t **h, const char *file, int line) { if (!h) return DHCP_R_INVALIDARG; if (!*h) { #if defined (POINTER_DEBUG) log_error ("%s(%d): dereference of null pointer!", file, line); abort (); #else return DHCP_R_INVALIDARG; #endif } if ((*h) -> refcnt <= 0) { #if defined (POINTER_DEBUG) log_error ("%s(%d): dereference of pointer with refcnt of zero!", file, line); #if defined (DEBUG_RC_HISTORY) dump_rc_history (*h); #endif abort (); #else *h = 0; return DHCP_R_INVALIDARG; #endif } --((*h) -> refcnt); rc_register (file, line, h, *h, (*h) -> refcnt, 1, RC_MISC); if ((*h) -> refcnt <= 0 ) { switch ((*h) -> type) { case omapi_datatype_int: case omapi_datatype_string: case omapi_datatype_data: default: break; case omapi_datatype_object: omapi_object_dereference (&(*h) -> u.object, file, line); break; } dfree (*h, file, line); } *h = 0; return ISC_R_SUCCESS; } isc_result_t omapi_data_string_new (omapi_data_string_t **d, unsigned len, const char *file, int line) { omapi_data_string_t *new; unsigned nlen; nlen = OMAPI_DATA_STRING_EMPTY_SIZE + len; if (nlen < len) return DHCP_R_INVALIDARG; new = dmalloc (nlen, file, line); if (!new) return ISC_R_NOMEMORY; memset (new, 0, OMAPI_DATA_STRING_EMPTY_SIZE); new -> len = len; return omapi_data_string_reference (d, new, file, line); } isc_result_t omapi_data_string_reference (omapi_data_string_t **r, omapi_data_string_t *h, const char *file, int line) { if (!h || !r) return DHCP_R_INVALIDARG; if (*r) { #if defined (POINTER_DEBUG) log_error ("%s(%d): reference store into non-null pointer!", file, line); abort (); #else return DHCP_R_INVALIDARG; #endif } *r = h; h -> refcnt++; rc_register (file, line, r, h, h -> refcnt, 0, RC_MISC); return ISC_R_SUCCESS; } isc_result_t omapi_data_string_dereference (omapi_data_string_t **h, const char *file, int line) { if (!h) return DHCP_R_INVALIDARG; if (!*h) { #if defined (POINTER_DEBUG) log_error ("%s(%d): dereference of null pointer!", file, line); abort (); #else return DHCP_R_INVALIDARG; #endif } if ((*h) -> refcnt <= 0) { #if defined (POINTER_DEBUG) log_error ("%s(%d): dereference of pointer with refcnt of zero!", file, line); #if defined (DEBUG_RC_HISTORY) dump_rc_history (*h); #endif abort (); #else *h = 0; return DHCP_R_INVALIDARG; #endif } --((*h) -> refcnt); rc_register (file, line, h, *h, (*h) -> refcnt, 1, RC_MISC); if ((*h) -> refcnt <= 0 ) { dfree (*h, file, line); } *h = 0; return ISC_R_SUCCESS; } isc_result_t omapi_value_new (omapi_value_t **d, const char *file, int line) { omapi_value_t *new; new = dmalloc (sizeof *new, file, line); if (!new) return ISC_R_NOMEMORY; memset (new, 0, sizeof *new); return omapi_value_reference (d, new, file, line); } isc_result_t omapi_value_reference (omapi_value_t **r, omapi_value_t *h, const char *file, int line) { if (!h || !r) return DHCP_R_INVALIDARG; if (*r) { #if defined (POINTER_DEBUG) log_error ("%s(%d): reference store into non-null pointer!", file, line); abort (); #else return DHCP_R_INVALIDARG; #endif } *r = h; h -> refcnt++; rc_register (file, line, r, h, h -> refcnt, 0, RC_MISC); return ISC_R_SUCCESS; } isc_result_t omapi_value_dereference (omapi_value_t **h, const char *file, int line) { if (!h) return DHCP_R_INVALIDARG; if (!*h) { #if defined (POINTER_DEBUG) log_error ("%s(%d): dereference of null pointer!", file, line); abort (); #else return DHCP_R_INVALIDARG; #endif } if ((*h) -> refcnt <= 0) { #if defined (POINTER_DEBUG) log_error ("%s(%d): dereference of pointer with refcnt of zero!", file, line); #if defined (DEBUG_RC_HISTORY) dump_rc_history (*h); #endif abort (); #else *h = 0; return DHCP_R_INVALIDARG; #endif } --((*h) -> refcnt); rc_register (file, line, h, *h, (*h) -> refcnt, 1, RC_MISC); if ((*h) -> refcnt == 0) { if ((*h) -> name) omapi_data_string_dereference (&(*h) -> name, file, line); if ((*h) -> value) omapi_typed_data_dereference (&(*h) -> value, file, line); dfree (*h, file, line); } *h = 0; return ISC_R_SUCCESS; } isc_result_t omapi_addr_list_new (omapi_addr_list_t **d, unsigned count, const char *file, int line) { omapi_addr_list_t *new; new = dmalloc ((count * sizeof (omapi_addr_t)) + sizeof (omapi_addr_list_t), file, line); if (!new) return ISC_R_NOMEMORY; memset (new, 0, ((count * sizeof (omapi_addr_t)) + sizeof (omapi_addr_list_t))); new -> count = count; new -> addresses = (omapi_addr_t *)(new + 1); return omapi_addr_list_reference (d, new, file, line); } isc_result_t omapi_addr_list_reference (omapi_addr_list_t **r, omapi_addr_list_t *h, const char *file, int line) { if (!h || !r) return DHCP_R_INVALIDARG; if (*r) { #if defined (POINTER_DEBUG) log_error ("%s(%d): reference store into non-null pointer!", file, line); abort (); #else return DHCP_R_INVALIDARG; #endif } *r = h; h -> refcnt++; rc_register (file, line, r, h, h -> refcnt, 0, RC_MISC); return ISC_R_SUCCESS; } isc_result_t omapi_addr_list_dereference (omapi_addr_list_t **h, const char *file, int line) { if (!h) return DHCP_R_INVALIDARG; if (!*h) { #if defined (POINTER_DEBUG) log_error ("%s(%d): dereference of null pointer!", file, line); abort (); #else return DHCP_R_INVALIDARG; #endif } if ((*h) -> refcnt <= 0) { #if defined (POINTER_DEBUG) log_error ("%s(%d): dereference of pointer with zero refcnt!", file, line); #if defined (DEBUG_RC_HISTORY) dump_rc_history (*h); #endif abort (); #else *h = 0; return DHCP_R_INVALIDARG; #endif } --((*h) -> refcnt); rc_register (file, line, h, *h, (*h) -> refcnt, 1, RC_MISC); if ((*h) -> refcnt <= 0 ) { dfree (*h, file, line); } *h = 0; return ISC_R_SUCCESS; } dhcp-4.2.4/omapip/array.c000644 000765 000024 00000011466 11301372615 015145 0ustar00sarstaff000000 000000 /* listener.c Subroutines that support the omapi extensible array type. */ /* * Copyright (c) 2004-2007,2009 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 2001-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ * * This software has been written for Internet Systems Consortium * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. * To learn more about Internet Systems Consortium, see * ``https://www.isc.org/''. To learn more about Vixie Enterprises, * see ``http://www.vix.com''. To learn more about Nominum, Inc., see * ``http://www.nominum.com''. */ #include "dhcpd.h" #include /* Allocate a new extensible array. */ isc_result_t omapi_array_allocate (omapi_array_t **array, omapi_array_ref_t ref, omapi_array_deref_t deref, const char *file, int line) { omapi_array_t *aptr; if (!array || *array) return DHCP_R_INVALIDARG; aptr = dmalloc (sizeof (omapi_array_t),file, line); if (!aptr) return ISC_R_NOMEMORY; *array = aptr; aptr -> ref = ref; aptr -> deref = deref; return ISC_R_SUCCESS; } isc_result_t omapi_array_free (omapi_array_t **array, const char *file, int line) { omapi_array_t *aptr; int i; if (!array || !*array) return DHCP_R_INVALIDARG; aptr = *array; for (i = 0; i < aptr -> count; i++) if (aptr -> data [i] && aptr -> deref) (*aptr -> deref) (&aptr -> data [i], file, line); dfree (aptr -> data, MDL); dfree (aptr, MDL); *array = (omapi_array_t *)0; return ISC_R_SUCCESS; } /* Extend the size of the array by one entry (we may allocate more than that) and store the specified value in the new array element. */ isc_result_t omapi_array_extend (omapi_array_t *array, char *ptr, int *index, const char *file, int line) { isc_result_t status; int new = array -> count; status = omapi_array_set (array, ptr, new, file, line); if (index && status == ISC_R_SUCCESS) *index = new; return status; } /* Set a value in the specified array, extending it if necessary. */ isc_result_t omapi_array_set (omapi_array_t *array, void *ptr, int index, const char *file, int line) { char **newbuf; int delta; isc_result_t status; if (!array) return DHCP_R_INVALIDARG; if (!ptr) return DHCP_R_INVALIDARG; if (index < 0) return DHCP_R_INVALIDARG; /* If the proposed index is larger than the current available space in the array, make more space in the array. */ if (array -> max <= index) { delta = index - array -> max + 10; newbuf = dmalloc ((array -> max + delta) * sizeof (char *), file, line); if (!newbuf) return ISC_R_NOMEMORY; /* Zero the new elements. */ memset (&newbuf [array -> max], 0, (sizeof (char *)) * delta); array -> max += delta; /* Copy the old array data into the new buffer. */ if (array -> data) { memcpy (newbuf, array -> data, array -> count * sizeof (char *)); dfree (array -> data, file, line); } array -> data = newbuf; } else { /* If there's already data there, and this is an array of references, dereference what's there. */ if (array -> data [index]) { status = ((*array -> deref) (&array -> data [index], file, line)); if (status != ISC_R_SUCCESS) return status; } } /* Store the pointer using the referencer function. We have either just memset this to zero or dereferenced what was there previously, so there is no need to do anything if the pointer we have been asked to store is null. */ if (ptr) { status = (*array -> ref) (&array -> data [index], ptr, file, line); if (status != ISC_R_SUCCESS) return status; } if (index >= array -> count) array -> count = index + 1; return ISC_R_SUCCESS; } isc_result_t omapi_array_lookup (char **ptr, omapi_array_t *array, int index, const char *file, int line) { if (!array || !ptr || *ptr || index < 0 || index >= array -> count) return DHCP_R_INVALIDARG; if (array -> data [index]) return (*array -> ref) (ptr, array -> data [index], file, line); return ISC_R_NOTFOUND; } dhcp-4.2.4/omapip/auth.c000644 000765 000024 00000017514 11516144546 015000 0ustar00sarstaff000000 000000 /* auth.c Subroutines having to do with authentication. */ /* * Copyright (c) 2009-2010 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 2004,2007 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1998-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ * * This software has been written for Internet Systems Consortium * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. * To learn more about Internet Systems Consortium, see * ``https://www.isc.org/''. To learn more about Vixie Enterprises, * see ``http://www.vix.com''. To learn more about Nominum, Inc., see * ``http://www.nominum.com''. */ #include "dhcpd.h" #include OMAPI_OBJECT_ALLOC (omapi_auth_key, omapi_auth_key_t, omapi_type_auth_key) typedef struct hash omapi_auth_hash_t; HASH_FUNCTIONS_DECL (omapi_auth_key, const char *, omapi_auth_key_t, omapi_auth_hash_t) omapi_auth_hash_t *auth_key_hash; HASH_FUNCTIONS (omapi_auth_key, const char *, omapi_auth_key_t, omapi_auth_hash_t, omapi_auth_key_reference, omapi_auth_key_dereference, do_case_hash) isc_result_t omapi_auth_key_new (omapi_auth_key_t **o, const char *file, int line) { return omapi_auth_key_allocate (o, file, line); } isc_result_t omapi_auth_key_destroy (omapi_object_t *h, const char *file, int line) { omapi_auth_key_t *a; if (h->type != omapi_type_auth_key) return DHCP_R_INVALIDARG; a = (omapi_auth_key_t *)h; if (auth_key_hash != NULL) omapi_auth_key_hash_delete(auth_key_hash, a->name, 0, MDL); if (a->name != NULL) dfree(a->name, MDL); if (a->algorithm != NULL) dfree(a->algorithm, MDL); if (a->key != NULL) omapi_data_string_dereference(&a->key, MDL); if (a->tsec_key != NULL) dns_tsec_destroy(&a->tsec_key); return ISC_R_SUCCESS; } isc_result_t omapi_auth_key_enter (omapi_auth_key_t *a) { omapi_auth_key_t *tk; isc_result_t status; dst_key_t *dstkey; if (a -> type != omapi_type_auth_key) return DHCP_R_INVALIDARG; tk = (omapi_auth_key_t *)0; if (auth_key_hash) { omapi_auth_key_hash_lookup (&tk, auth_key_hash, a -> name, 0, MDL); if (tk == a) { omapi_auth_key_dereference (&tk, MDL); return ISC_R_SUCCESS; } if (tk) { omapi_auth_key_hash_delete (auth_key_hash, tk -> name, 0, MDL); omapi_auth_key_dereference (&tk, MDL); } } else { if (!omapi_auth_key_new_hash(&auth_key_hash, KEY_HASH_SIZE, MDL)) return ISC_R_NOMEMORY; } /* * If possible create a tsec structure for this key, * if we can't create the structure we put out a warning * and continue. */ status = isclib_make_dst_key(a->name, a->algorithm, a->key->value, a->key->len, &dstkey); if (status == ISC_R_SUCCESS) { status = dns_tsec_create(dhcp_gbl_ctx.mctx, dns_tsectype_tsig, dstkey, &a->tsec_key); dst_key_free(&dstkey); } if (status != ISC_R_SUCCESS) log_error("Unable to create tsec structure for %s", a->name); omapi_auth_key_hash_add (auth_key_hash, a -> name, 0, a, MDL); return ISC_R_SUCCESS; } isc_result_t omapi_auth_key_lookup_name (omapi_auth_key_t **a, const char *name) { if (!auth_key_hash) return ISC_R_NOTFOUND; if (!omapi_auth_key_hash_lookup (a, auth_key_hash, name, 0, MDL)) return ISC_R_NOTFOUND; return ISC_R_SUCCESS; } isc_result_t omapi_auth_key_lookup (omapi_object_t **h, omapi_object_t *id, omapi_object_t *ref) { isc_result_t status; omapi_value_t *name = (omapi_value_t *)0; omapi_value_t *algorithm = (omapi_value_t *)0; if (!auth_key_hash) return ISC_R_NOTFOUND; if (!ref) return DHCP_R_NOKEYS; status = omapi_get_value_str (ref, id, "name", &name); if (status != ISC_R_SUCCESS) return status; if ((name -> value -> type != omapi_datatype_string) && (name -> value -> type != omapi_datatype_data)) { omapi_value_dereference (&name, MDL); return ISC_R_NOTFOUND; } status = omapi_get_value_str (ref, id, "algorithm", &algorithm); if (status != ISC_R_SUCCESS) { omapi_value_dereference (&name, MDL); return status; } if ((algorithm -> value -> type != omapi_datatype_string) && (algorithm -> value -> type != omapi_datatype_data)) { omapi_value_dereference (&name, MDL); omapi_value_dereference (&algorithm, MDL); return ISC_R_NOTFOUND; } if (!omapi_auth_key_hash_lookup ((omapi_auth_key_t **)h, auth_key_hash, (const char *) name -> value -> u.buffer.value, name -> value -> u.buffer.len, MDL)) { omapi_value_dereference (&name, MDL); omapi_value_dereference (&algorithm, MDL); return ISC_R_NOTFOUND; } if (omapi_td_strcasecmp (algorithm -> value, ((omapi_auth_key_t *)*h) -> algorithm) != 0) { omapi_value_dereference (&name, MDL); omapi_value_dereference (&algorithm, MDL); omapi_object_dereference (h, MDL); return ISC_R_NOTFOUND; } omapi_value_dereference (&name, MDL); omapi_value_dereference (&algorithm, MDL); return ISC_R_SUCCESS; } isc_result_t omapi_auth_key_stuff_values (omapi_object_t *c, omapi_object_t *id, omapi_object_t *h) { omapi_auth_key_t *a; isc_result_t status; if (h -> type != omapi_type_auth_key) return DHCP_R_INVALIDARG; a = (omapi_auth_key_t *)h; /* Write only the name and algorithm -- not the secret! */ if (a -> name) { status = omapi_connection_put_name (c, "name"); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_put_string (c, a -> name); if (status != ISC_R_SUCCESS) return status; } if (a -> algorithm) { status = omapi_connection_put_name (c, "algorithm"); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_put_string (c, a -> algorithm); if (status != ISC_R_SUCCESS) return status; } return ISC_R_SUCCESS; } isc_result_t omapi_auth_key_get_value (omapi_object_t *h, omapi_object_t *id, omapi_data_string_t *name, omapi_value_t **value) { omapi_auth_key_t *a; isc_result_t status; if (h -> type != omapi_type_auth_key) return ISC_R_UNEXPECTED; a = (omapi_auth_key_t *)h; if (omapi_ds_strcmp (name, "name") == 0) { if (a -> name) return omapi_make_string_value (value, name, a -> name, MDL); else return ISC_R_NOTFOUND; } else if (omapi_ds_strcmp (name, "key") == 0) { if (a -> key) { status = omapi_value_new (value, MDL); if (status != ISC_R_SUCCESS) return status; status = omapi_data_string_reference (&(*value) -> name, name, MDL); if (status != ISC_R_SUCCESS) { omapi_value_dereference (value, MDL); return status; } status = omapi_typed_data_new (MDL, &(*value) -> value, omapi_datatype_data, a -> key -> len); if (status != ISC_R_SUCCESS) { omapi_value_dereference (value, MDL); return status; } memcpy ((*value) -> value -> u.buffer.value, a -> key -> value, a -> key -> len); return ISC_R_SUCCESS; } else return ISC_R_NOTFOUND; } else if (omapi_ds_strcmp (name, "algorithm") == 0) { if (a -> algorithm) return omapi_make_string_value (value, name, a -> algorithm, MDL); else return ISC_R_NOTFOUND; } return ISC_R_SUCCESS; } dhcp-4.2.4/omapip/buffer.c000644 000765 000024 00000045023 11301372615 015274 0ustar00sarstaff000000 000000 /* buffer.c Buffer access functions for the object management protocol... */ /* * Copyright (c) 2004,2005,2007,2009 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1999-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ * * This software has been written for Internet Systems Consortium * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. * To learn more about Internet Systems Consortium, see * ``https://www.isc.org/''. To learn more about Vixie Enterprises, * see ``http://www.vix.com''. To learn more about Nominum, Inc., see * ``http://www.nominum.com''. */ #include "dhcpd.h" #include #include #if defined (TRACING) static void trace_connection_input_input (trace_type_t *, unsigned, char *); static void trace_connection_input_stop (trace_type_t *); static void trace_connection_output_input (trace_type_t *, unsigned, char *); static void trace_connection_output_stop (trace_type_t *); static trace_type_t *trace_connection_input; static trace_type_t *trace_connection_output; static isc_result_t omapi_connection_reader_trace (omapi_object_t *, unsigned, char *, unsigned *); extern omapi_array_t *omapi_connections; void omapi_buffer_trace_setup () { trace_connection_input = trace_type_register ("connection-input", (void *)0, trace_connection_input_input, trace_connection_input_stop, MDL); trace_connection_output = trace_type_register ("connection-output", (void *)0, trace_connection_output_input, trace_connection_output_stop, MDL); } static void trace_connection_input_input (trace_type_t *ttype, unsigned length, char *buf) { unsigned left, taken, cc = 0; char *s; int32_t connect_index; isc_result_t status; omapi_connection_object_t *c = (omapi_connection_object_t *)0; memcpy (&connect_index, buf, sizeof connect_index); connect_index = ntohl (connect_index); omapi_array_foreach_begin (omapi_connections, omapi_connection_object_t, lp) { if (lp -> index == ntohl (connect_index)) { omapi_connection_reference (&c, lp, MDL); omapi_connection_dereference (&lp, MDL); break; } } omapi_array_foreach_end (omapi_connections, omapi_connection_object_t, lp); if (!c) { log_error ("trace connection input: no connection index %ld", (long int)connect_index); return; } s = buf + sizeof connect_index; left = length - sizeof connect_index; while (left) { taken = 0; status = omapi_connection_reader_trace ((omapi_object_t *)c, left, s, &taken); if (status != ISC_R_SUCCESS) { log_error ("trace connection input: %s", isc_result_totext (status)); break; } if (!taken) { if (cc > 0) { log_error ("trace connection_input: %s", "input is not being consumed."); break; } cc++; } else { cc = 0; left -= taken; } } omapi_connection_dereference (&c, MDL); } static void trace_connection_input_stop (trace_type_t *ttype) { } static void trace_connection_output_input (trace_type_t *ttype, unsigned length, char *buf) { /* We *could* check to see if the output is correct, but for now we aren't going to do that. */ } static void trace_connection_output_stop (trace_type_t *ttype) { } #endif /* Make sure that at least len bytes are in the input buffer, and if not, read enough bytes to make up the difference. */ isc_result_t omapi_connection_reader (omapi_object_t *h) { #if defined (TRACING) return omapi_connection_reader_trace (h, 0, (char *)0, (unsigned *)0); } static isc_result_t omapi_connection_reader_trace (omapi_object_t *h, unsigned stuff_len, char *stuff_buf, unsigned *stuff_taken) { #endif omapi_buffer_t *buffer; isc_result_t status; unsigned read_len; int read_status; omapi_connection_object_t *c; unsigned bytes_to_read; if (!h || h -> type != omapi_type_connection) return DHCP_R_INVALIDARG; c = (omapi_connection_object_t *)h; /* See if there are enough bytes. */ if (c -> in_bytes >= OMAPI_BUF_SIZE - 1 && c -> in_bytes > c -> bytes_needed) return ISC_R_SUCCESS; if (c -> inbufs) { for (buffer = c -> inbufs; buffer -> next; buffer = buffer -> next) ; if (!BUFFER_BYTES_FREE (buffer)) { status = omapi_buffer_new (&buffer -> next, MDL); if (status != ISC_R_SUCCESS) return status; buffer = buffer -> next; } } else { status = omapi_buffer_new (&c -> inbufs, MDL); if (status != ISC_R_SUCCESS) return status; buffer = c -> inbufs; } bytes_to_read = BUFFER_BYTES_FREE (buffer); while (bytes_to_read) { if (buffer -> tail > buffer -> head) read_len = sizeof (buffer -> buf) - buffer -> tail; else read_len = buffer -> head - buffer -> tail; #if defined (TRACING) if (trace_playback()) { if (stuff_len) { if (read_len > stuff_len) read_len = stuff_len; if (stuff_taken) *stuff_taken += read_len; memcpy (&buffer -> buf [buffer -> tail], stuff_buf, read_len); stuff_len -= read_len; stuff_buf += read_len; read_status = read_len; } else { break; } } else #endif { read_status = read (c -> socket, &buffer -> buf [buffer -> tail], read_len); } if (read_status < 0) { if (errno == EWOULDBLOCK) break; else if (errno == EIO) return ISC_R_IOERROR; else if (errno == EINVAL) return DHCP_R_INVALIDARG; else if (errno == ECONNRESET) { omapi_disconnect (h, 1); return ISC_R_SHUTTINGDOWN; } else return ISC_R_UNEXPECTED; } /* If we got a zero-length read, as opposed to EWOULDBLOCK, the remote end closed the connection. */ if (read_status == 0) { omapi_disconnect (h, 0); return ISC_R_SHUTTINGDOWN; } #if defined (TRACING) if (trace_record ()) { trace_iov_t iov [2]; int32_t connect_index; connect_index = htonl (c -> index); iov [0].buf = (char *)&connect_index; iov [0].len = sizeof connect_index; iov [1].buf = &buffer -> buf [buffer -> tail]; iov [1].len = read_status; status = (trace_write_packet_iov (trace_connection_input, 2, iov, MDL)); if (status != ISC_R_SUCCESS) { trace_stop (); log_error ("trace connection input: %s", isc_result_totext (status)); } } #endif buffer -> tail += read_status; c -> in_bytes += read_status; if (buffer -> tail == sizeof buffer -> buf) buffer -> tail = 0; if (read_status < read_len) break; bytes_to_read -= read_status; } if (c -> bytes_needed <= c -> in_bytes) { omapi_signal (h, "ready", c); } return ISC_R_SUCCESS; } /* Put some bytes into the output buffer for a connection. */ isc_result_t omapi_connection_copyin (omapi_object_t *h, const unsigned char *bufp, unsigned len) { omapi_buffer_t *buffer; isc_result_t status; int bytes_copied = 0; unsigned copy_len; int sig_flags = SIG_MODE_UPDATE; omapi_connection_object_t *c; /* Make sure len is valid. */ if (len < 0) return DHCP_R_INVALIDARG; if (!h || h -> type != omapi_type_connection) return DHCP_R_INVALIDARG; c = (omapi_connection_object_t *)h; /* If the connection is closed, return an error if the caller tries to copy in. */ if (c -> state == omapi_connection_disconnecting || c -> state == omapi_connection_closed) return ISC_R_NOTCONNECTED; if (c -> outbufs) { for (buffer = c -> outbufs; buffer -> next; buffer = buffer -> next) ; } else { status = omapi_buffer_new (&c -> outbufs, MDL); if (status != ISC_R_SUCCESS) goto leave; buffer = c -> outbufs; } while (bytes_copied < len) { /* If there is no space available in this buffer, allocate a new one. */ if (!BUFFER_BYTES_FREE (buffer)) { status = (omapi_buffer_new (&buffer -> next, MDL)); if (status != ISC_R_SUCCESS) goto leave; buffer = buffer -> next; } if (buffer -> tail > buffer -> head) copy_len = sizeof (buffer -> buf) - buffer -> tail; else copy_len = buffer -> head - buffer -> tail; if (copy_len > (len - bytes_copied)) copy_len = len - bytes_copied; if (c -> out_key) { if (!c -> out_context) sig_flags |= SIG_MODE_INIT; status = omapi_connection_sign_data (sig_flags, c -> out_key, &c -> out_context, &bufp [bytes_copied], copy_len, (omapi_typed_data_t **)0); if (status != ISC_R_SUCCESS) goto leave; } memcpy (&buffer -> buf [buffer -> tail], &bufp [bytes_copied], copy_len); buffer -> tail += copy_len; c -> out_bytes += copy_len; bytes_copied += copy_len; if (buffer -> tail == sizeof buffer -> buf) buffer -> tail = 0; } status = ISC_R_SUCCESS; leave: /* * If we have any bytes to send and we have a proper io object * inform the socket code that we would like to know when we * can send more bytes. */ if (c->out_bytes != 0) { if ((c->outer != NULL) && (c->outer->type == omapi_type_io_object)) { omapi_io_object_t *io = (omapi_io_object_t *)c->outer; isc_socket_fdwatchpoke(io->fd, ISC_SOCKFDWATCH_WRITE); } } return (status); } /* Copy some bytes from the input buffer, and advance the input buffer pointer beyond the bytes copied out. */ isc_result_t omapi_connection_copyout (unsigned char *buf, omapi_object_t *h, unsigned size) { unsigned bytes_remaining; unsigned bytes_this_copy; unsigned first_byte; omapi_buffer_t *buffer; unsigned char *bufp; int sig_flags = SIG_MODE_UPDATE; omapi_connection_object_t *c; isc_result_t status; if (!h || h -> type != omapi_type_connection) return DHCP_R_INVALIDARG; c = (omapi_connection_object_t *)h; if (size > c -> in_bytes) return ISC_R_NOMORE; bufp = buf; bytes_remaining = size; buffer = c -> inbufs; while (bytes_remaining) { if (!buffer) return ISC_R_UNEXPECTED; if (BYTES_IN_BUFFER (buffer)) { if (buffer -> head == (sizeof buffer -> buf) - 1) first_byte = 0; else first_byte = buffer -> head + 1; if (first_byte > buffer -> tail) { bytes_this_copy = (sizeof buffer -> buf - first_byte); } else { bytes_this_copy = buffer -> tail - first_byte; } if (bytes_this_copy > bytes_remaining) bytes_this_copy = bytes_remaining; if (bufp) { if (c -> in_key) { if (!c -> in_context) sig_flags |= SIG_MODE_INIT; status = omapi_connection_sign_data (sig_flags, c -> in_key, &c -> in_context, (unsigned char *) &buffer -> buf [first_byte], bytes_this_copy, (omapi_typed_data_t **)0); if (status != ISC_R_SUCCESS) return status; } memcpy (bufp, &buffer -> buf [first_byte], bytes_this_copy); bufp += bytes_this_copy; } bytes_remaining -= bytes_this_copy; buffer -> head = first_byte + bytes_this_copy - 1; c -> in_bytes -= bytes_this_copy; } if (!BYTES_IN_BUFFER (buffer)) buffer = buffer -> next; } /* Get rid of any input buffers that we emptied. */ buffer = (omapi_buffer_t *)0; while (c -> inbufs && !BYTES_IN_BUFFER (c -> inbufs)) { if (c -> inbufs -> next) { omapi_buffer_reference (&buffer, c -> inbufs -> next, MDL); omapi_buffer_dereference (&c -> inbufs -> next, MDL); } omapi_buffer_dereference (&c -> inbufs, MDL); if (buffer) { omapi_buffer_reference (&c -> inbufs, buffer, MDL); omapi_buffer_dereference (&buffer, MDL); } } return ISC_R_SUCCESS; } isc_result_t omapi_connection_writer (omapi_object_t *h) { unsigned bytes_this_write; int bytes_written; unsigned first_byte; omapi_buffer_t *buffer; omapi_connection_object_t *c; if (!h || h -> type != omapi_type_connection) return DHCP_R_INVALIDARG; c = (omapi_connection_object_t *)h; /* Already flushed... */ if (!c -> out_bytes) return ISC_R_SUCCESS; buffer = c -> outbufs; while (c -> out_bytes) { if (!buffer) return ISC_R_UNEXPECTED; if (BYTES_IN_BUFFER (buffer)) { if (buffer -> head == (sizeof buffer -> buf) - 1) first_byte = 0; else first_byte = buffer -> head + 1; if (first_byte > buffer -> tail) { bytes_this_write = (sizeof buffer -> buf - first_byte); } else { bytes_this_write = buffer -> tail - first_byte; } bytes_written = write (c -> socket, &buffer -> buf [first_byte], bytes_this_write); /* If the write failed with EWOULDBLOCK or we wrote zero bytes, a further write would block, so we have flushed as much as we can for now. Other errors are really errors. */ if (bytes_written < 0) { if (errno == EWOULDBLOCK || errno == EAGAIN) return ISC_R_INPROGRESS; else if (errno == EPIPE) return ISC_R_NOCONN; #ifdef EDQUOT else if (errno == EFBIG || errno == EDQUOT) #else else if (errno == EFBIG) #endif return ISC_R_NORESOURCES; else if (errno == ENOSPC) return ISC_R_NOSPACE; else if (errno == EIO) return ISC_R_IOERROR; else if (errno == EINVAL) return DHCP_R_INVALIDARG; else if (errno == ECONNRESET) return ISC_R_SHUTTINGDOWN; else return ISC_R_UNEXPECTED; } if (bytes_written == 0) return ISC_R_INPROGRESS; #if defined (TRACING) if (trace_record ()) { isc_result_t status; trace_iov_t iov [2]; int32_t connect_index; connect_index = htonl (c -> index); iov [0].buf = (char *)&connect_index; iov [0].len = sizeof connect_index; iov [1].buf = &buffer -> buf [buffer -> tail]; iov [1].len = bytes_written; status = (trace_write_packet_iov (trace_connection_input, 2, iov, MDL)); if (status != ISC_R_SUCCESS) { trace_stop (); log_error ("trace %s output: %s", "connection", isc_result_totext (status)); } } #endif buffer -> head = first_byte + bytes_written - 1; c -> out_bytes -= bytes_written; /* If we didn't finish out the write, we filled the O.S. output buffer and a further write would block, so stop trying to flush now. */ if (bytes_written != bytes_this_write) return ISC_R_INPROGRESS; } if (!BYTES_IN_BUFFER (buffer)) buffer = buffer -> next; } /* Get rid of any output buffers we emptied. */ buffer = (omapi_buffer_t *)0; while (c -> outbufs && !BYTES_IN_BUFFER (c -> outbufs)) { if (c -> outbufs -> next) { omapi_buffer_reference (&buffer, c -> outbufs -> next, MDL); omapi_buffer_dereference (&c -> outbufs -> next, MDL); } omapi_buffer_dereference (&c -> outbufs, MDL); if (buffer) { omapi_buffer_reference (&c -> outbufs, buffer, MDL); omapi_buffer_dereference (&buffer, MDL); } } return ISC_R_SUCCESS; } isc_result_t omapi_connection_get_uint32 (omapi_object_t *c, u_int32_t *result) { u_int32_t inbuf; isc_result_t status; status = omapi_connection_copyout ((unsigned char *)&inbuf, c, sizeof inbuf); if (status != ISC_R_SUCCESS) return status; *result = ntohl (inbuf); return ISC_R_SUCCESS; } isc_result_t omapi_connection_put_uint32 (omapi_object_t *c, u_int32_t value) { u_int32_t inbuf; inbuf = htonl (value); return omapi_connection_copyin (c, (unsigned char *)&inbuf, sizeof inbuf); } isc_result_t omapi_connection_get_uint16 (omapi_object_t *c, u_int16_t *result) { u_int16_t inbuf; isc_result_t status; status = omapi_connection_copyout ((unsigned char *)&inbuf, c, sizeof inbuf); if (status != ISC_R_SUCCESS) return status; *result = ntohs (inbuf); return ISC_R_SUCCESS; } isc_result_t omapi_connection_put_uint16 (omapi_object_t *c, u_int32_t value) { u_int16_t inbuf; inbuf = htons (value); return omapi_connection_copyin (c, (unsigned char *)&inbuf, sizeof inbuf); } isc_result_t omapi_connection_write_typed_data (omapi_object_t *c, omapi_typed_data_t *data) { isc_result_t status; omapi_handle_t handle; /* Null data is valid. */ if (!data) return omapi_connection_put_uint32 (c, 0); switch (data -> type) { case omapi_datatype_int: status = omapi_connection_put_uint32 (c, sizeof (u_int32_t)); if (status != ISC_R_SUCCESS) return status; return omapi_connection_put_uint32 (c, ((u_int32_t) (data -> u.integer))); case omapi_datatype_string: case omapi_datatype_data: status = omapi_connection_put_uint32 (c, data -> u.buffer.len); if (status != ISC_R_SUCCESS) return status; if (data -> u.buffer.len) return omapi_connection_copyin (c, data -> u.buffer.value, data -> u.buffer.len); return ISC_R_SUCCESS; case omapi_datatype_object: if (data -> u.object) { status = omapi_object_handle (&handle, data -> u.object); if (status != ISC_R_SUCCESS) return status; } else handle = 0; status = omapi_connection_put_uint32 (c, sizeof handle); if (status != ISC_R_SUCCESS) return status; return omapi_connection_put_uint32 (c, handle); } return DHCP_R_INVALIDARG; } isc_result_t omapi_connection_put_name (omapi_object_t *c, const char *name) { isc_result_t status; unsigned len = strlen (name); status = omapi_connection_put_uint16 (c, len); if (status != ISC_R_SUCCESS) return status; return omapi_connection_copyin (c, (const unsigned char *)name, len); } isc_result_t omapi_connection_put_string (omapi_object_t *c, const char *string) { isc_result_t status; unsigned len; if (string) len = strlen (string); else len = 0; status = omapi_connection_put_uint32 (c, len); if (status != ISC_R_SUCCESS) return status; if (len) return omapi_connection_copyin (c, (const unsigned char *)string, len); return ISC_R_SUCCESS; } isc_result_t omapi_connection_put_handle (omapi_object_t *c, omapi_object_t *h) { isc_result_t status; omapi_handle_t handle; if (h) { status = omapi_object_handle (&handle, h); if (status != ISC_R_SUCCESS) return status; } else handle = 0; /* The null handle. */ status = omapi_connection_put_uint32 (c, sizeof handle); if (status != ISC_R_SUCCESS) return status; return omapi_connection_put_uint32 (c, handle); } dhcp-4.2.4/omapip/connection.c000644 000765 000024 00000074476 11566576200 016211 0ustar00sarstaff000000 000000 /* connection.c Subroutines for dealing with connections. */ /* * Copyright (c) 2009-2011 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 2004,2007 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1999-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ * * This software has been written for Internet Systems Consortium * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. * To learn more about Internet Systems Consortium, see * ``https://www.isc.org/''. To learn more about Vixie Enterprises, * see ``http://www.vix.com''. To learn more about Nominum, Inc., see * ``http://www.nominum.com''. */ #include "dhcpd.h" #include #include #include #include #if defined (TRACING) static void trace_connect_input (trace_type_t *, unsigned, char *); static void trace_connect_stop (trace_type_t *); static void trace_disconnect_input (trace_type_t *, unsigned, char *); static void trace_disconnect_stop (trace_type_t *); trace_type_t *trace_connect; trace_type_t *trace_disconnect; extern omapi_array_t *trace_listeners; #endif static isc_result_t omapi_connection_connect_internal (omapi_object_t *); OMAPI_OBJECT_ALLOC (omapi_connection, omapi_connection_object_t, omapi_type_connection) isc_result_t omapi_connect (omapi_object_t *c, const char *server_name, unsigned port) { struct hostent *he; unsigned i, hix; omapi_addr_list_t *addrs = (omapi_addr_list_t *)0; struct in_addr foo; isc_result_t status; #ifdef DEBUG_PROTOCOL log_debug ("omapi_connect(%s, port=%d)", server_name, port); #endif if (!inet_aton (server_name, &foo)) { /* If we didn't get a numeric address, try for a domain name. It's okay for this call to block. */ he = gethostbyname (server_name); if (!he) return DHCP_R_HOSTUNKNOWN; for (i = 0; he -> h_addr_list [i]; i++) ; if (i == 0) return DHCP_R_HOSTUNKNOWN; hix = i; status = omapi_addr_list_new (&addrs, hix, MDL); if (status != ISC_R_SUCCESS) return status; for (i = 0; i < hix; i++) { addrs -> addresses [i].addrtype = he -> h_addrtype; addrs -> addresses [i].addrlen = he -> h_length; memcpy (addrs -> addresses [i].address, he -> h_addr_list [i], (unsigned)he -> h_length); addrs -> addresses [i].port = port; } } else { status = omapi_addr_list_new (&addrs, 1, MDL); if (status != ISC_R_SUCCESS) return status; addrs -> addresses [0].addrtype = AF_INET; addrs -> addresses [0].addrlen = sizeof foo; memcpy (addrs -> addresses [0].address, &foo, sizeof foo); addrs -> addresses [0].port = port; hix = 1; } status = omapi_connect_list (c, addrs, (omapi_addr_t *)0); omapi_addr_list_dereference (&addrs, MDL); return status; } isc_result_t omapi_connect_list (omapi_object_t *c, omapi_addr_list_t *remote_addrs, omapi_addr_t *local_addr) { isc_result_t status; omapi_connection_object_t *obj; int flag; struct sockaddr_in local_sin; obj = (omapi_connection_object_t *)0; status = omapi_connection_allocate (&obj, MDL); if (status != ISC_R_SUCCESS) return status; status = omapi_object_reference (&c -> outer, (omapi_object_t *)obj, MDL); if (status != ISC_R_SUCCESS) { omapi_connection_dereference (&obj, MDL); return status; } status = omapi_object_reference (&obj -> inner, c, MDL); if (status != ISC_R_SUCCESS) { omapi_connection_dereference (&obj, MDL); return status; } /* Store the address list on the object. */ omapi_addr_list_reference (&obj -> connect_list, remote_addrs, MDL); obj -> cptr = 0; obj -> state = omapi_connection_unconnected; #if defined (TRACING) /* If we're playing back, don't actually try to connect - just leave the object available for a subsequent connect or disconnect. */ if (!trace_playback ()) { #endif /* Create a socket on which to communicate. */ obj -> socket = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP); if (obj -> socket < 0) { omapi_connection_dereference (&obj, MDL); if (errno == EMFILE || errno == ENFILE || errno == ENOBUFS) return ISC_R_NORESOURCES; return ISC_R_UNEXPECTED; } /* Set up the local address, if any. */ if (local_addr) { /* Only do TCPv4 so far. */ if (local_addr -> addrtype != AF_INET) { omapi_connection_dereference (&obj, MDL); return DHCP_R_INVALIDARG; } local_sin.sin_port = htons (local_addr -> port); memcpy (&local_sin.sin_addr, local_addr -> address, local_addr -> addrlen); #if defined (HAVE_SA_LEN) local_sin.sin_len = sizeof local_addr; #endif local_sin.sin_family = AF_INET; memset (&local_sin.sin_zero, 0, sizeof local_sin.sin_zero); if (bind (obj -> socket, (struct sockaddr *)&local_sin, sizeof local_sin) < 0) { omapi_connection_object_t **objp = &obj; omapi_object_t **o = (omapi_object_t **)objp; omapi_object_dereference(o, MDL); if (errno == EADDRINUSE) return ISC_R_ADDRINUSE; if (errno == EADDRNOTAVAIL) return ISC_R_ADDRNOTAVAIL; if (errno == EACCES) return ISC_R_NOPERM; return ISC_R_UNEXPECTED; } obj -> local_addr = local_sin; } #if defined(F_SETFD) if (fcntl (obj -> socket, F_SETFD, 1) < 0) { close (obj -> socket); omapi_connection_dereference (&obj, MDL); return ISC_R_UNEXPECTED; } #endif /* Set the SO_REUSEADDR flag (this should not fail). */ flag = 1; if (setsockopt (obj -> socket, SOL_SOCKET, SO_REUSEADDR, (char *)&flag, sizeof flag) < 0) { omapi_connection_dereference (&obj, MDL); return ISC_R_UNEXPECTED; } /* Set the file to nonblocking mode. */ if (fcntl (obj -> socket, F_SETFL, O_NONBLOCK) < 0) { omapi_connection_dereference (&obj, MDL); return ISC_R_UNEXPECTED; } #ifdef SO_NOSIGPIPE /* * If available stop the OS from killing our * program on a SIGPIPE failure */ flag = 1; if (setsockopt(obj->socket, SOL_SOCKET, SO_NOSIGPIPE, (char *)&flag, sizeof(flag)) < 0) { omapi_connection_dereference (&obj, MDL); return ISC_R_UNEXPECTED; } #endif status = (omapi_register_io_object ((omapi_object_t *)obj, 0, omapi_connection_writefd, 0, omapi_connection_connect, omapi_connection_reaper)); if (status != ISC_R_SUCCESS) goto out; status = omapi_connection_connect_internal ((omapi_object_t *) obj); /* * inprogress is the same as success but used * to indicate to the dispatch code that we should * mark the socket as requiring more attention. * Routines calling this function should handle * success properly. */ if (status == ISC_R_INPROGRESS) { status = ISC_R_SUCCESS; } #if defined (TRACING) } omapi_connection_register (obj, MDL); #endif out: omapi_connection_dereference (&obj, MDL); return status; } #if defined (TRACING) omapi_array_t *omapi_connections; OMAPI_ARRAY_TYPE(omapi_connection, omapi_connection_object_t) void omapi_connection_trace_setup (void) { trace_connect = trace_type_register ("connect", (void *)0, trace_connect_input, trace_connect_stop, MDL); trace_disconnect = trace_type_register ("disconnect", (void *)0, trace_disconnect_input, trace_disconnect_stop, MDL); } void omapi_connection_register (omapi_connection_object_t *obj, const char *file, int line) { isc_result_t status; trace_iov_t iov [6]; int iov_count = 0; int32_t connect_index, listener_index; static int32_t index; if (!omapi_connections) { status = omapi_connection_array_allocate (&omapi_connections, file, line); if (status != ISC_R_SUCCESS) return; } status = omapi_connection_array_extend (omapi_connections, obj, (int *)0, file, line); if (status != ISC_R_SUCCESS) { obj -> index = -1; return; } #if defined (TRACING) if (trace_record ()) { /* Connection registration packet: int32_t index int32_t listener_index [-1 means no listener] u_int16_t remote_port u_int16_t local_port u_int32_t remote_addr u_int32_t local_addr */ connect_index = htonl (index); index++; if (obj -> listener) listener_index = htonl (obj -> listener -> index); else listener_index = htonl (-1); iov [iov_count].buf = (char *)&connect_index; iov [iov_count++].len = sizeof connect_index; iov [iov_count].buf = (char *)&listener_index; iov [iov_count++].len = sizeof listener_index; iov [iov_count].buf = (char *)&obj -> remote_addr.sin_port; iov [iov_count++].len = sizeof obj -> remote_addr.sin_port; iov [iov_count].buf = (char *)&obj -> local_addr.sin_port; iov [iov_count++].len = sizeof obj -> local_addr.sin_port; iov [iov_count].buf = (char *)&obj -> remote_addr.sin_addr; iov [iov_count++].len = sizeof obj -> remote_addr.sin_addr; iov [iov_count].buf = (char *)&obj -> local_addr.sin_addr; iov [iov_count++].len = sizeof obj -> local_addr.sin_addr; status = trace_write_packet_iov (trace_connect, iov_count, iov, file, line); } #endif } static void trace_connect_input (trace_type_t *ttype, unsigned length, char *buf) { struct sockaddr_in remote, local; int32_t connect_index, listener_index; char *s = buf; omapi_connection_object_t *obj; isc_result_t status; int i; if (length != ((sizeof connect_index) + (sizeof remote.sin_port) + (sizeof remote.sin_addr)) * 2) { log_error ("Trace connect: invalid length %d", length); return; } memset (&remote, 0, sizeof remote); memset (&local, 0, sizeof local); memcpy (&connect_index, s, sizeof connect_index); s += sizeof connect_index; memcpy (&listener_index, s, sizeof listener_index); s += sizeof listener_index; memcpy (&remote.sin_port, s, sizeof remote.sin_port); s += sizeof remote.sin_port; memcpy (&local.sin_port, s, sizeof local.sin_port); s += sizeof local.sin_port; memcpy (&remote.sin_addr, s, sizeof remote.sin_addr); s += sizeof remote.sin_addr; memcpy (&local.sin_addr, s, sizeof local.sin_addr); s += sizeof local.sin_addr; connect_index = ntohl (connect_index); listener_index = ntohl (listener_index); /* If this was a connect to a listener, then we just slap together a new connection. */ if (listener_index != -1) { omapi_listener_object_t *listener; listener = (omapi_listener_object_t *)0; omapi_array_foreach_begin (trace_listeners, omapi_listener_object_t, lp) { if (lp -> address.sin_port == local.sin_port) { omapi_listener_reference (&listener, lp, MDL); omapi_listener_dereference (&lp, MDL); break; } } omapi_array_foreach_end (trace_listeners, omapi_listener_object_t, lp); if (!listener) { log_error ("%s%ld, addr %s, port %d", "Spurious traced listener connect - index ", (long int)listener_index, inet_ntoa (local.sin_addr), ntohs (local.sin_port)); return; } obj = (omapi_connection_object_t *)0; status = omapi_listener_connect (&obj, listener, -1, &remote); if (status != ISC_R_SUCCESS) { log_error ("traced listener connect: %s", isc_result_totext (status)); } if (obj) omapi_connection_dereference (&obj, MDL); omapi_listener_dereference (&listener, MDL); return; } /* Find the matching connect object, if there is one. */ omapi_array_foreach_begin (omapi_connections, omapi_connection_object_t, lp) { for (i = 0; (lp -> connect_list && i < lp -> connect_list -> count); i++) { if (!memcmp (&remote.sin_addr, &lp -> connect_list -> addresses [i].address, sizeof remote.sin_addr) && (ntohs (remote.sin_port) == lp -> connect_list -> addresses [i].port)) lp -> state = omapi_connection_connected; lp -> remote_addr = remote; lp -> remote_addr.sin_family = AF_INET; omapi_addr_list_dereference (&lp -> connect_list, MDL); lp -> index = connect_index; status = omapi_signal_in ((omapi_object_t *)lp, "connect"); omapi_connection_dereference (&lp, MDL); return; } } omapi_array_foreach_end (omapi_connections, omapi_connection_object_t, lp); log_error ("Spurious traced connect - index %ld, addr %s, port %d", (long int)connect_index, inet_ntoa (remote.sin_addr), ntohs (remote.sin_port)); return; } static void trace_connect_stop (trace_type_t *ttype) { } static void trace_disconnect_input (trace_type_t *ttype, unsigned length, char *buf) { int32_t *index; if (length != sizeof *index) { log_error ("trace disconnect: wrong length %d", length); return; } index = (int32_t *)buf; omapi_array_foreach_begin (omapi_connections, omapi_connection_object_t, lp) { if (lp -> index == ntohl (*index)) { omapi_disconnect ((omapi_object_t *)lp, 1); omapi_connection_dereference (&lp, MDL); return; } } omapi_array_foreach_end (omapi_connections, omapi_connection_object_t, lp); log_error ("trace disconnect: no connection matching index %ld", (long int)ntohl (*index)); } static void trace_disconnect_stop (trace_type_t *ttype) { } #endif /* Disconnect a connection object from the remote end. If force is nonzero, close the connection immediately. Otherwise, shut down the receiving end but allow any unsent data to be sent before actually closing the socket. */ isc_result_t omapi_disconnect (omapi_object_t *h, int force) { omapi_connection_object_t *c; #ifdef DEBUG_PROTOCOL log_debug ("omapi_disconnect(%s)", force ? "force" : ""); #endif c = (omapi_connection_object_t *)h; if (c -> type != omapi_type_connection) return DHCP_R_INVALIDARG; #if defined (TRACING) if (trace_record ()) { isc_result_t status; int32_t index; index = htonl (c -> index); status = trace_write_packet (trace_disconnect, sizeof index, (char *)&index, MDL); if (status != ISC_R_SUCCESS) { trace_stop (); log_error ("trace_write_packet: %s", isc_result_totext (status)); } } if (!trace_playback ()) { #endif if (!force) { /* If we're already disconnecting, we don't have to do anything. */ if (c -> state == omapi_connection_disconnecting) return ISC_R_SUCCESS; /* Try to shut down the socket - this sends a FIN to the remote end, so that it won't send us any more data. If the shutdown succeeds, and we still have bytes left to write, defer closing the socket until that's done. */ if (!shutdown (c -> socket, SHUT_RD)) { if (c -> out_bytes > 0) { c -> state = omapi_connection_disconnecting; return ISC_R_SUCCESS; } } } close (c -> socket); #if defined (TRACING) } #endif c -> state = omapi_connection_closed; #if 0 /* * Disconnecting from the I/O object seems incorrect as it doesn't * cause the I/O object to be cleaned and released. Previous to * using the isc socket library this wouldn't have caused a problem * with the socket library we would have a reference to a closed * socket. Instead we now do an unregister to properly free the * I/O object. */ /* Disconnect from I/O object, if any. */ if (h -> outer) { if (h -> outer -> inner) omapi_object_dereference (&h -> outer -> inner, MDL); omapi_object_dereference (&h -> outer, MDL); } #else if (h->outer) { omapi_unregister_io_object(h); } #endif /* If whatever created us registered a signal handler, send it a disconnect signal. */ omapi_signal (h, "disconnect", h); /* Disconnect from protocol object, if any. */ if (h->inner != NULL) { if (h->inner->outer != NULL) { omapi_object_dereference(&h->inner->outer, MDL); } omapi_object_dereference(&h->inner, MDL); } /* XXX: the code to free buffers should be in the dereference function, but there is no special-purpose function to dereference connections, so these just get leaked */ /* Free any buffers */ if (c->inbufs != NULL) { omapi_buffer_dereference(&c->inbufs, MDL); } c->in_bytes = 0; if (c->outbufs != NULL) { omapi_buffer_dereference(&c->outbufs, MDL); } c->out_bytes = 0; return ISC_R_SUCCESS; } isc_result_t omapi_connection_require (omapi_object_t *h, unsigned bytes) { omapi_connection_object_t *c; if (h -> type != omapi_type_connection) return DHCP_R_INVALIDARG; c = (omapi_connection_object_t *)h; c -> bytes_needed = bytes; if (c -> bytes_needed <= c -> in_bytes) { return ISC_R_SUCCESS; } return DHCP_R_NOTYET; } /* Return the socket on which the dispatcher should wait for readiness to read, for a connection object. */ int omapi_connection_readfd (omapi_object_t *h) { omapi_connection_object_t *c; if (h -> type != omapi_type_connection) return -1; c = (omapi_connection_object_t *)h; if (c -> state != omapi_connection_connected) return -1; return c -> socket; } /* * Return the socket on which the dispatcher should wait for readiness * to write, for a connection object. When bytes are buffered we should * also poke the dispatcher to tell it to start or re-start watching the * socket. */ int omapi_connection_writefd (omapi_object_t *h) { omapi_connection_object_t *c; if (h -> type != omapi_type_connection) return -1; c = (omapi_connection_object_t *)h; return c->socket; } isc_result_t omapi_connection_connect (omapi_object_t *h) { isc_result_t status; /* * We use the INPROGRESS status to indicate that * we want more from the socket. In this case we * have now connected and are trying to write to * the socket for the first time. For the signaling * code this is the same as a SUCCESS so we don't * pass it on as a signal. */ status = omapi_connection_connect_internal (h); if (status == ISC_R_INPROGRESS) return ISC_R_INPROGRESS; if (status != ISC_R_SUCCESS) omapi_signal (h, "status", status); return ISC_R_SUCCESS; } static isc_result_t omapi_connection_connect_internal (omapi_object_t *h) { int error; omapi_connection_object_t *c; socklen_t sl; isc_result_t status; if (h -> type != omapi_type_connection) return DHCP_R_INVALIDARG; c = (omapi_connection_object_t *)h; if (c -> state == omapi_connection_connecting) { sl = sizeof error; if (getsockopt (c -> socket, SOL_SOCKET, SO_ERROR, (char *)&error, &sl) < 0) { omapi_disconnect (h, 1); return ISC_R_SUCCESS; } if (!error) c -> state = omapi_connection_connected; } if (c -> state == omapi_connection_connecting || c -> state == omapi_connection_unconnected) { if (c -> cptr >= c -> connect_list -> count) { switch (error) { case ECONNREFUSED: status = ISC_R_CONNREFUSED; break; case ENETUNREACH: status = ISC_R_NETUNREACH; break; default: status = uerr2isc (error); break; } omapi_disconnect (h, 1); return status; } if (c -> connect_list -> addresses [c -> cptr].addrtype != AF_INET) { omapi_disconnect (h, 1); return DHCP_R_INVALIDARG; } memcpy (&c -> remote_addr.sin_addr, &c -> connect_list -> addresses [c -> cptr].address, sizeof c -> remote_addr.sin_addr); c -> remote_addr.sin_family = AF_INET; c -> remote_addr.sin_port = htons (c -> connect_list -> addresses [c -> cptr].port); #if defined (HAVE_SA_LEN) c -> remote_addr.sin_len = sizeof c -> remote_addr; #endif memset (&c -> remote_addr.sin_zero, 0, sizeof c -> remote_addr.sin_zero); ++c -> cptr; error = connect (c -> socket, (struct sockaddr *)&c -> remote_addr, sizeof c -> remote_addr); if (error < 0) { error = errno; if (error != EINPROGRESS) { omapi_disconnect (h, 1); switch (error) { case ECONNREFUSED: status = ISC_R_CONNREFUSED; break; case ENETUNREACH: status = ISC_R_NETUNREACH; break; default: status = uerr2isc (error); break; } return status; } c -> state = omapi_connection_connecting; return DHCP_R_INCOMPLETE; } c -> state = omapi_connection_connected; } /* I don't know why this would fail, so I'm tempted not to test the return value. */ sl = sizeof (c -> local_addr); if (getsockname (c -> socket, (struct sockaddr *)&c -> local_addr, &sl) < 0) { } /* Reregister with the I/O object. If we don't already have an I/O object this turns into a register call, otherwise we simply modify the pointers in the I/O object. */ status = omapi_reregister_io_object (h, omapi_connection_readfd, omapi_connection_writefd, omapi_connection_reader, omapi_connection_writer, omapi_connection_reaper); if (status != ISC_R_SUCCESS) { omapi_disconnect (h, 1); return status; } omapi_signal_in (h, "connect"); omapi_addr_list_dereference (&c -> connect_list, MDL); return ISC_R_INPROGRESS; } /* Reaper function for connection - if the connection is completely closed, reap it. If it's in the disconnecting state, there were bytes left to write when the user closed it, so if there are now no bytes left to write, we can close it. */ isc_result_t omapi_connection_reaper (omapi_object_t *h) { omapi_connection_object_t *c; if (h -> type != omapi_type_connection) return DHCP_R_INVALIDARG; c = (omapi_connection_object_t *)h; if (c -> state == omapi_connection_disconnecting && c -> out_bytes == 0) { #ifdef DEBUG_PROTOCOL log_debug ("omapi_connection_reaper(): disconnect"); #endif omapi_disconnect (h, 1); } if (c -> state == omapi_connection_closed) { #ifdef DEBUG_PROTOCOL log_debug ("omapi_connection_reaper(): closed"); #endif return ISC_R_NOTCONNECTED; } return ISC_R_SUCCESS; } static isc_result_t make_dst_key (dst_key_t **dst_key, omapi_object_t *a) { omapi_value_t *name = (omapi_value_t *)0; omapi_value_t *algorithm = (omapi_value_t *)0; omapi_value_t *key = (omapi_value_t *)0; char *name_str = NULL; isc_result_t status = ISC_R_SUCCESS; if (status == ISC_R_SUCCESS) status = omapi_get_value_str (a, (omapi_object_t *)0, "name", &name); if (status == ISC_R_SUCCESS) status = omapi_get_value_str (a, (omapi_object_t *)0, "algorithm", &algorithm); if (status == ISC_R_SUCCESS) status = omapi_get_value_str (a, (omapi_object_t *)0, "key", &key); if (status == ISC_R_SUCCESS) { if ((algorithm->value->type != omapi_datatype_data && algorithm->value->type != omapi_datatype_string) || strncasecmp((char *)algorithm->value->u.buffer.value, NS_TSIG_ALG_HMAC_MD5 ".", algorithm->value->u.buffer.len) != 0) { status = DHCP_R_INVALIDARG; } } if (status == ISC_R_SUCCESS) { name_str = dmalloc (name -> value -> u.buffer.len + 1, MDL); if (!name_str) status = ISC_R_NOMEMORY; } if (status == ISC_R_SUCCESS) { memcpy (name_str, name -> value -> u.buffer.value, name -> value -> u.buffer.len); name_str [name -> value -> u.buffer.len] = 0; status = isclib_make_dst_key(name_str, DHCP_HMAC_MD5_NAME, key->value->u.buffer.value, key->value->u.buffer.len, dst_key); if (*dst_key == NULL) status = ISC_R_NOMEMORY; } if (name_str) dfree (name_str, MDL); if (key) omapi_value_dereference (&key, MDL); if (algorithm) omapi_value_dereference (&algorithm, MDL); if (name) omapi_value_dereference (&name, MDL); return status; } isc_result_t omapi_connection_sign_data (int mode, dst_key_t *key, void **context, const unsigned char *data, const unsigned len, omapi_typed_data_t **result) { omapi_typed_data_t *td = (omapi_typed_data_t *)0; isc_result_t status; dst_context_t **dctx = (dst_context_t **)context; /* Create the context for the dst module */ if (mode & SIG_MODE_INIT) { status = dst_context_create(key, dhcp_gbl_ctx.mctx, dctx); if (status != ISC_R_SUCCESS) { return status; } } /* If we have any data add it to the context */ if (len != 0) { isc_region_t region; region.base = (unsigned char *)data; region.length = len; dst_context_adddata(*dctx, ®ion); } /* Finish the signature and clean up the context */ if (mode & SIG_MODE_FINAL) { unsigned int sigsize; isc_buffer_t sigbuf; status = dst_key_sigsize(key, &sigsize); if (status != ISC_R_SUCCESS) { goto cleanup; } status = omapi_typed_data_new (MDL, &td, omapi_datatype_data, sigsize); if (status != ISC_R_SUCCESS) { goto cleanup; } isc_buffer_init(&sigbuf, td->u.buffer.value, td->u.buffer.len); status = dst_context_sign(*dctx, &sigbuf); if (status != ISC_R_SUCCESS) { goto cleanup; } if (result) { omapi_typed_data_reference (result, td, MDL); } cleanup: /* We are done with the context and the td. On success * the td is now referenced from result, on failure we * don't need it any more */ if (td) { omapi_typed_data_dereference (&td, MDL); } dst_context_destroy(dctx); return status; } return ISC_R_SUCCESS; } isc_result_t omapi_connection_output_auth_length (omapi_object_t *h, unsigned *l) { omapi_connection_object_t *c; if (h->type != omapi_type_connection) return DHCP_R_INVALIDARG; c = (omapi_connection_object_t *)h; if (c->out_key == NULL) return ISC_R_NOTFOUND; return(dst_key_sigsize(c->out_key, l)); } isc_result_t omapi_connection_set_value (omapi_object_t *h, omapi_object_t *id, omapi_data_string_t *name, omapi_typed_data_t *value) { omapi_connection_object_t *c; isc_result_t status; if (h -> type != omapi_type_connection) return DHCP_R_INVALIDARG; c = (omapi_connection_object_t *)h; if (omapi_ds_strcmp (name, "input-authenticator") == 0) { if (value && value -> type != omapi_datatype_object) return DHCP_R_INVALIDARG; if (c -> in_context) { omapi_connection_sign_data (SIG_MODE_FINAL, c -> in_key, &c -> in_context, 0, 0, (omapi_typed_data_t **) 0); } if (c->in_key != NULL) { dst_key_free(&c->in_key); } if (value) { status = make_dst_key (&c -> in_key, value -> u.object); if (status != ISC_R_SUCCESS) return status; } return ISC_R_SUCCESS; } else if (omapi_ds_strcmp (name, "output-authenticator") == 0) { if (value && value -> type != omapi_datatype_object) return DHCP_R_INVALIDARG; if (c -> out_context) { omapi_connection_sign_data (SIG_MODE_FINAL, c -> out_key, &c -> out_context, 0, 0, (omapi_typed_data_t **) 0); } if (c->out_key != NULL) { dst_key_free(&c->out_key); } if (value) { status = make_dst_key (&c -> out_key, value -> u.object); if (status != ISC_R_SUCCESS) return status; } return ISC_R_SUCCESS; } if (h -> inner && h -> inner -> type -> set_value) return (*(h -> inner -> type -> set_value)) (h -> inner, id, name, value); return ISC_R_NOTFOUND; } isc_result_t omapi_connection_get_value (omapi_object_t *h, omapi_object_t *id, omapi_data_string_t *name, omapi_value_t **value) { omapi_connection_object_t *c; omapi_typed_data_t *td = (omapi_typed_data_t *)0; isc_result_t status; unsigned int sigsize; if (h -> type != omapi_type_connection) return DHCP_R_INVALIDARG; c = (omapi_connection_object_t *)h; if (omapi_ds_strcmp (name, "input-signature") == 0) { if (!c -> in_key || !c -> in_context) return ISC_R_NOTFOUND; status = omapi_connection_sign_data (SIG_MODE_FINAL, c -> in_key, &c -> in_context, 0, 0, &td); if (status != ISC_R_SUCCESS) return status; status = omapi_make_value (value, name, td, MDL); omapi_typed_data_dereference (&td, MDL); return status; } else if (omapi_ds_strcmp (name, "input-signature-size") == 0) { if (c->in_key == NULL) return ISC_R_NOTFOUND; status = dst_key_sigsize(c->in_key, &sigsize); if (status != ISC_R_SUCCESS) { return(status); } return omapi_make_int_value(value, name, sigsize, MDL); } else if (omapi_ds_strcmp (name, "output-signature") == 0) { if (!c -> out_key || !c -> out_context) return ISC_R_NOTFOUND; status = omapi_connection_sign_data (SIG_MODE_FINAL, c -> out_key, &c -> out_context, 0, 0, &td); if (status != ISC_R_SUCCESS) return status; status = omapi_make_value (value, name, td, MDL); omapi_typed_data_dereference (&td, MDL); return status; } else if (omapi_ds_strcmp (name, "output-signature-size") == 0) { if (c->out_key == NULL) return ISC_R_NOTFOUND; status = dst_key_sigsize(c->out_key, &sigsize); if (status != ISC_R_SUCCESS) { return(status); } return omapi_make_int_value(value, name, sigsize, MDL); } if (h -> inner && h -> inner -> type -> get_value) return (*(h -> inner -> type -> get_value)) (h -> inner, id, name, value); return ISC_R_NOTFOUND; } isc_result_t omapi_connection_destroy (omapi_object_t *h, const char *file, int line) { omapi_connection_object_t *c; #ifdef DEBUG_PROTOCOL log_debug ("omapi_connection_destroy()"); #endif if (h -> type != omapi_type_connection) return ISC_R_UNEXPECTED; c = (omapi_connection_object_t *)(h); if (c -> state == omapi_connection_connected) omapi_disconnect (h, 1); if (c -> listener) omapi_listener_dereference (&c -> listener, file, line); if (c -> connect_list) omapi_addr_list_dereference (&c -> connect_list, file, line); return ISC_R_SUCCESS; } isc_result_t omapi_connection_signal_handler (omapi_object_t *h, const char *name, va_list ap) { if (h -> type != omapi_type_connection) return DHCP_R_INVALIDARG; #ifdef DEBUG_PROTOCOL log_debug ("omapi_connection_signal_handler(%s)", name); #endif if (h -> inner && h -> inner -> type -> signal_handler) return (*(h -> inner -> type -> signal_handler)) (h -> inner, name, ap); return ISC_R_NOTFOUND; } /* Write all the published values associated with the object through the specified connection. */ isc_result_t omapi_connection_stuff_values (omapi_object_t *c, omapi_object_t *id, omapi_object_t *m) { if (m -> type != omapi_type_connection) return DHCP_R_INVALIDARG; if (m -> inner && m -> inner -> type -> stuff_values) return (*(m -> inner -> type -> stuff_values)) (c, id, m -> inner); return ISC_R_SUCCESS; } dhcp-4.2.4/omapip/convert.c000644 000765 000024 00000007571 11301372616 015512 0ustar00sarstaff000000 000000 /* convert.c Safe copying of option values into and out of the option buffer, which can't be assumed to be aligned. */ /* * Copyright (c) 2004,2007,2009 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1996-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ * * This software has been written for Internet Systems Consortium * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. * To learn more about Internet Systems Consortium, see * ``https://www.isc.org/''. To learn more about Vixie Enterprises, * see ``http://www.vix.com''. To learn more about Nominum, Inc., see * ``http://www.nominum.com''. */ #include "dhcpd.h" #include u_int32_t getULong (buf) const unsigned char *buf; { u_int32_t ibuf; memcpy (&ibuf, buf, sizeof (u_int32_t)); return ntohl (ibuf); } int32_t getLong (buf) const unsigned char *buf; { int32_t ibuf; memcpy (&ibuf, buf, sizeof (int32_t)); return ntohl (ibuf); } u_int32_t getUShort (buf) const unsigned char *buf; { unsigned short ibuf; memcpy (&ibuf, buf, sizeof (u_int16_t)); return ntohs (ibuf); } int32_t getShort (buf) const unsigned char *buf; { short ibuf; memcpy (&ibuf, buf, sizeof (int16_t)); return ntohs (ibuf); } void putULong (obuf, val) unsigned char *obuf; u_int32_t val; { u_int32_t tmp = htonl (val); memcpy (obuf, &tmp, sizeof tmp); } void putLong (obuf, val) unsigned char *obuf; int32_t val; { int32_t tmp = htonl (val); memcpy (obuf, &tmp, sizeof tmp); } void putUShort (obuf, val) unsigned char *obuf; u_int32_t val; { u_int16_t tmp = htons (val); memcpy (obuf, &tmp, sizeof tmp); } void putShort (obuf, val) unsigned char *obuf; int32_t val; { int16_t tmp = htons (val); memcpy (obuf, &tmp, sizeof tmp); } void putUChar (obuf, val) unsigned char *obuf; u_int32_t val; { *obuf = val; } u_int32_t getUChar (obuf) const unsigned char *obuf; { return obuf [0]; } int converted_length (buf, base, width) const unsigned char *buf; unsigned int base; unsigned int width; { u_int32_t number; u_int32_t column; int power = 1; u_int32_t newcolumn = base; if (base > 16) return 0; if (width == 1) number = getUChar (buf); else if (width == 2) number = getUShort (buf); else if (width == 4) number = getULong (buf); else return 0; do { column = newcolumn; if (number < column) return power; power++; newcolumn = column * base; /* If we wrap around, it must be the next power of two up. */ } while (newcolumn > column); return power; } int binary_to_ascii (outbuf, inbuf, base, width) unsigned char *outbuf; const unsigned char *inbuf; unsigned int base; unsigned int width; { u_int32_t number; static char h2a [] = "0123456789abcdef"; int power = converted_length (inbuf, base, width); int i; if (base > 16) return 0; if (width == 1) number = getUChar (inbuf); else if (width == 2) number = getUShort (inbuf); else if (width == 4) number = getULong (inbuf); else return 0; for (i = power - 1 ; i >= 0; i--) { outbuf [i] = h2a [number % base]; number /= base; } return power; } dhcp-4.2.4/omapip/dispatch.c000644 000765 000024 00000056266 11301372616 015636 0ustar00sarstaff000000 000000 /* dispatch.c I/O dispatcher. */ /* * Copyright (c) 2004,2007-2009 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1999-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ * * This software has been written for Internet Systems Consortium * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. * To learn more about Internet Systems Consortium, see * ``https://www.isc.org/''. To learn more about Vixie Enterprises, * see ``http://www.vix.com''. To learn more about Nominum, Inc., see * ``http://www.nominum.com''. */ #include "dhcpd.h" #include #include static omapi_io_object_t omapi_io_states; struct timeval cur_tv; struct eventqueue *rw_queue_empty; OMAPI_OBJECT_ALLOC (omapi_io, omapi_io_object_t, omapi_type_io_object) OMAPI_OBJECT_ALLOC (omapi_waiter, omapi_waiter_object_t, omapi_type_waiter) void register_eventhandler(struct eventqueue **queue, void (*handler)(void *)) { struct eventqueue *t, *q; /* traverse to end of list */ t = NULL; for (q = *queue ; q ; q = q->next) { if (q->handler == handler) return; /* handler already registered */ t = q; } q = ((struct eventqueue *)dmalloc(sizeof(struct eventqueue), MDL)); if (!q) log_fatal("register_eventhandler: no memory!"); memset(q, 0, sizeof *q); if (t) t->next = q; else *queue = q; q->handler = handler; return; } void unregister_eventhandler(struct eventqueue **queue, void (*handler)(void *)) { struct eventqueue *t, *q; /* traverse to end of list */ t= NULL; for (q = *queue ; q ; q = q->next) { if (q->handler == handler) { if (t) t->next = q->next; else *queue = q->next; dfree(q, MDL); /* Don't access q after this!*/ break; } t = q; } return; } void trigger_event(struct eventqueue **queue) { struct eventqueue *q; for (q=*queue ; q ; q=q->next) { if (q->handler) (*q->handler)(NULL); } } /* * Callback routine to connect the omapi I/O object and socket with * the isc socket code. The isc socket code will call this routine * which will then call the correct local routine to process the bytes. * * Currently we are always willing to read more data, this should be modified * so that on connections we don't read more if we already have enough. * * If we have more bytes to write we ask the library to call us when * we can write more. If we indicate we don't have more to write we need * to poke the library via isc_socket_fdwatchpoke. */ /* * sockdelete indicates if we are deleting the socket or leaving it in place * 1 is delete, 0 is leave in place */ #define SOCKDELETE 1 int omapi_iscsock_cb(isc_task_t *task, isc_socket_t *socket, void *cbarg, int flags) { omapi_io_object_t *obj; isc_result_t status; /* Get the current time... */ gettimeofday (&cur_tv, (struct timezone *)0); /* isc socket stuff */ #if SOCKDELETE /* * walk through the io states list, if our object is on there * service it. if not ignore it. */ for (obj = omapi_io_states.next; (obj != NULL) && (obj->next != NULL); obj = obj->next) { if (obj == cbarg) break; } if (obj == NULL) { return(0); } #else /* Not much to be done if we have the wrong type of object. */ if (((omapi_object_t *)cbarg) -> type != omapi_type_io_object) { log_fatal ("Incorrect object type, must be of type io_object"); } obj = (omapi_io_object_t *)cbarg; /* * If the object is marked as closed don't try and process * anything just indicate that we don't want any more. * * This should be a temporary fix until we arrange to properly * close the socket. */ if (obj->closed == ISC_TRUE) { return(0); } #endif if ((flags == ISC_SOCKFDWATCH_READ) && (obj->reader != NULL) && (obj->inner != NULL)) { obj->reader(obj->inner); /* We always ask for more when reading */ return (1); } else if ((flags == ISC_SOCKFDWATCH_WRITE) && (obj->writer != NULL) && (obj->inner != NULL)) { status = obj->writer(obj->inner); /* If the writer has more to write they should return * ISC_R_INPROGRESS */ if (status == ISC_R_INPROGRESS) { return (1); } } /* * We get here if we either had an error (inconsistent * structures etc) or no more to write, tell the socket * lib we don't have more to do right now. */ return (0); } /* Register an I/O handle so that we can do asynchronous I/O on it. */ isc_result_t omapi_register_io_object (omapi_object_t *h, int (*readfd) (omapi_object_t *), int (*writefd) (omapi_object_t *), isc_result_t (*reader) (omapi_object_t *), isc_result_t (*writer) (omapi_object_t *), isc_result_t (*reaper) (omapi_object_t *)) { isc_result_t status; omapi_io_object_t *obj, *p; int fd_flags = 0, fd = 0; /* omapi_io_states is a static object. If its reference count is zero, this is the first I/O handle to be registered, so we need to initialize it. Because there is no inner or outer pointer on this object, and we're setting its refcnt to 1, it will never be freed. */ if (!omapi_io_states.refcnt) { omapi_io_states.refcnt = 1; omapi_io_states.type = omapi_type_io_object; } obj = (omapi_io_object_t *)0; status = omapi_io_allocate (&obj, MDL); if (status != ISC_R_SUCCESS) return status; obj->closed = ISC_FALSE; /* mark as open */ status = omapi_object_reference (&obj -> inner, h, MDL); if (status != ISC_R_SUCCESS) { omapi_io_dereference (&obj, MDL); return status; } status = omapi_object_reference (&h -> outer, (omapi_object_t *)obj, MDL); if (status != ISC_R_SUCCESS) { omapi_io_dereference (&obj, MDL); return status; } /* * Attach the I/O object to the isc socket library via the * fdwatch function. This allows the socket library to watch * over a socket that we built. If there are both a read and * a write socket we asssume they are the same socket. */ if (readfd) { fd_flags |= ISC_SOCKFDWATCH_READ; fd = readfd(h); } if (writefd) { fd_flags |= ISC_SOCKFDWATCH_WRITE; fd = writefd(h); } if (fd_flags != 0) { status = isc_socket_fdwatchcreate(dhcp_gbl_ctx.socketmgr, fd, fd_flags, omapi_iscsock_cb, obj, dhcp_gbl_ctx.task, &obj->fd); if (status != ISC_R_SUCCESS) { log_error("Unable to register fd with library %s", isc_result_totext(status)); /*sar*/ /* is this the cleanup we need? */ omapi_object_dereference(&h->outer, MDL); omapi_io_dereference (&obj, MDL); return (status); } } /* Find the last I/O state, if there are any. */ for (p = omapi_io_states.next; p && p -> next; p = p -> next) ; if (p) omapi_io_reference (&p -> next, obj, MDL); else omapi_io_reference (&omapi_io_states.next, obj, MDL); obj -> readfd = readfd; obj -> writefd = writefd; obj -> reader = reader; obj -> writer = writer; obj -> reaper = reaper; omapi_io_dereference(&obj, MDL); return ISC_R_SUCCESS; } /* * ReRegister an I/O handle so that we can do asynchronous I/O on it. * If the handle doesn't exist we call the register routine to build it. * If it does exist we change the functions associated with it, and * repoke the fd code to make it happy. Neither the objects nor the * fd are allowed to have changed. */ isc_result_t omapi_reregister_io_object (omapi_object_t *h, int (*readfd) (omapi_object_t *), int (*writefd) (omapi_object_t *), isc_result_t (*reader) (omapi_object_t *), isc_result_t (*writer) (omapi_object_t *), isc_result_t (*reaper) (omapi_object_t *)) { omapi_io_object_t *obj; int fd_flags = 0; if ((!h -> outer) || (h -> outer -> type != omapi_type_io_object)) { /* * If we don't have an object or if the type isn't what * we expect do the normal registration (which will overwrite * an incorrect type, that's what we did historically, may * want to change that) */ return (omapi_register_io_object (h, readfd, writefd, reader, writer, reaper)); } /* We have an io object of the correct type, try to update it */ /*sar*/ /* Should we validate that the fd matches the previous one? * It's suppossed to, that's a requirement, don't bother yet */ obj = (omapi_io_object_t *)h->outer; obj->readfd = readfd; obj->writefd = writefd; obj->reader = reader; obj->writer = writer; obj->reaper = reaper; if (readfd) { fd_flags |= ISC_SOCKFDWATCH_READ; } if (writefd) { fd_flags |= ISC_SOCKFDWATCH_WRITE; } isc_socket_fdwatchpoke(obj->fd, fd_flags); return (ISC_R_SUCCESS); } isc_result_t omapi_unregister_io_object (omapi_object_t *h) { omapi_io_object_t *obj, *ph; #if SOCKDELETE omapi_io_object_t *p, *last; #endif if (!h -> outer || h -> outer -> type != omapi_type_io_object) return DHCP_R_INVALIDARG; obj = (omapi_io_object_t *)h -> outer; ph = (omapi_io_object_t *)0; omapi_io_reference (&ph, obj, MDL); #if SOCKDELETE /* * For now we leave this out. We can't clean up the isc socket * structure cleanly yet so we need to leave the io object in place. * By leaving it on the io states list we avoid it being freed. * We also mark it as closed to avoid using it. */ /* remove from the list of I/O states */ last = &omapi_io_states; for (p = omapi_io_states.next; p; p = p -> next) { if (p == obj) { omapi_io_dereference (&last -> next, MDL); omapi_io_reference (&last -> next, p -> next, MDL); break; } last = p; } if (obj -> next) omapi_io_dereference (&obj -> next, MDL); #endif if (obj -> outer) { if (obj -> outer -> inner == (omapi_object_t *)obj) omapi_object_dereference (&obj -> outer -> inner, MDL); omapi_object_dereference (&obj -> outer, MDL); } omapi_object_dereference (&obj -> inner, MDL); omapi_object_dereference (&h -> outer, MDL); #if SOCKDELETE /* remove isc socket associations */ if (obj->fd != NULL) { isc_socket_cancel(obj->fd, dhcp_gbl_ctx.task, ISC_SOCKCANCEL_ALL); isc_socket_detach(&obj->fd); } #else obj->closed = ISC_TRUE; #endif omapi_io_dereference (&ph, MDL); return ISC_R_SUCCESS; } isc_result_t omapi_dispatch (struct timeval *t) { return omapi_wait_for_completion ((omapi_object_t *)&omapi_io_states, t); } isc_result_t omapi_wait_for_completion (omapi_object_t *object, struct timeval *t) { isc_result_t status; omapi_waiter_object_t *waiter; omapi_object_t *inner; if (object) { waiter = (omapi_waiter_object_t *)0; status = omapi_waiter_allocate (&waiter, MDL); if (status != ISC_R_SUCCESS) return status; /* Paste the waiter object onto the inner object we're waiting on. */ for (inner = object; inner -> inner; inner = inner -> inner) ; status = omapi_object_reference (&waiter -> outer, inner, MDL); if (status != ISC_R_SUCCESS) { omapi_waiter_dereference (&waiter, MDL); return status; } status = omapi_object_reference (&inner -> inner, (omapi_object_t *)waiter, MDL); if (status != ISC_R_SUCCESS) { omapi_waiter_dereference (&waiter, MDL); return status; } } else waiter = (omapi_waiter_object_t *)0; do { status = omapi_one_dispatch ((omapi_object_t *)waiter, t); if (status != ISC_R_SUCCESS) return status; } while (!waiter || !waiter -> ready); if (waiter -> outer) { if (waiter -> outer -> inner) { omapi_object_dereference (&waiter -> outer -> inner, MDL); if (waiter -> inner) omapi_object_reference (&waiter -> outer -> inner, waiter -> inner, MDL); } omapi_object_dereference (&waiter -> outer, MDL); } if (waiter -> inner) omapi_object_dereference (&waiter -> inner, MDL); status = waiter -> waitstatus; omapi_waiter_dereference (&waiter, MDL); return status; } isc_result_t omapi_one_dispatch (omapi_object_t *wo, struct timeval *t) { fd_set r, w, x, rr, ww, xx; int max = 0; int count; int desc; struct timeval now, to; omapi_io_object_t *io, *prev, *next; omapi_waiter_object_t *waiter; omapi_object_t *tmp = (omapi_object_t *)0; if (!wo || wo -> type != omapi_type_waiter) waiter = (omapi_waiter_object_t *)0; else waiter = (omapi_waiter_object_t *)wo; FD_ZERO (&x); /* First, see if the timeout has expired, and if so return. */ if (t) { gettimeofday (&now, (struct timezone *)0); cur_tv.tv_sec = now.tv_sec; cur_tv.tv_usec = now.tv_usec; if (now.tv_sec > t -> tv_sec || (now.tv_sec == t -> tv_sec && now.tv_usec >= t -> tv_usec)) return ISC_R_TIMEDOUT; /* We didn't time out, so figure out how long until we do. */ to.tv_sec = t -> tv_sec - now.tv_sec; to.tv_usec = t -> tv_usec - now.tv_usec; if (to.tv_usec < 0) { to.tv_usec += 1000000; to.tv_sec--; } /* It is possible for the timeout to get set larger than the largest time select() is willing to accept. Restricting the timeout to a maximum of one day should work around this. -DPN. (Ref: Bug #416) */ if (to.tv_sec > (60 * 60 * 24)) to.tv_sec = 60 * 60 * 24; } /* If the object we're waiting on has reached completion, return now. */ if (waiter && waiter -> ready) return ISC_R_SUCCESS; again: /* If we have no I/O state, we can't proceed. */ if (!(io = omapi_io_states.next)) return ISC_R_NOMORE; /* Set up the read and write masks. */ FD_ZERO (&r); FD_ZERO (&w); for (; io; io = io -> next) { /* Check for a read socket. If we shouldn't be trying to read for this I/O object, either there won't be a readfd function, or it'll return -1. */ if (io -> readfd && io -> inner && (desc = (*(io -> readfd)) (io -> inner)) >= 0) { FD_SET (desc, &r); if (desc > max) max = desc; } /* Same deal for write fdets. */ if (io -> writefd && io -> inner && (desc = (*(io -> writefd)) (io -> inner)) >= 0) { FD_SET (desc, &w); if (desc > max) max = desc; } } /* poll if all reader are dry */ now.tv_sec = 0; now.tv_usec = 0; rr=r; ww=w; xx=x; /* poll once */ count = select(max + 1, &r, &w, &x, &now); if (!count) { /* We are dry now */ trigger_event(&rw_queue_empty); /* Wait for a packet or a timeout... XXX */ r = rr; w = ww; x = xx; count = select(max + 1, &r, &w, &x, t ? &to : NULL); } /* Get the current time... */ gettimeofday (&cur_tv, (struct timezone *)0); /* We probably have a bad file descriptor. Figure out which one. When we find it, call the reaper function on it, which will maybe make it go away, and then try again. */ if (count < 0) { struct timeval t0; omapi_io_object_t *prev = (omapi_io_object_t *)0; io = (omapi_io_object_t *)0; if (omapi_io_states.next) omapi_io_reference (&io, omapi_io_states.next, MDL); while (io) { omapi_object_t *obj; FD_ZERO (&r); FD_ZERO (&w); t0.tv_sec = t0.tv_usec = 0; if (io -> readfd && io -> inner && (desc = (*(io -> readfd)) (io -> inner)) >= 0) { FD_SET (desc, &r); count = select (desc + 1, &r, &w, &x, &t0); bogon: if (count < 0) { log_error ("Bad descriptor %d.", desc); for (obj = (omapi_object_t *)io; obj -> outer; obj = obj -> outer) ; for (; obj; obj = obj -> inner) { omapi_value_t *ov; int len; const char *s; ov = (omapi_value_t *)0; omapi_get_value_str (obj, (omapi_object_t *)0, "name", &ov); if (ov && ov -> value && (ov -> value -> type == omapi_datatype_string)) { s = (char *) ov -> value -> u.buffer.value; len = ov -> value -> u.buffer.len; } else { s = ""; len = 0; } log_error ("Object %lx %s%s%.*s", (unsigned long)obj, obj -> type -> name, len ? " " : "", len, s); if (len) omapi_value_dereference (&ov, MDL); } (*(io -> reaper)) (io -> inner); if (prev) { omapi_io_dereference (&prev -> next, MDL); if (io -> next) omapi_io_reference (&prev -> next, io -> next, MDL); } else { omapi_io_dereference (&omapi_io_states.next, MDL); if (io -> next) omapi_io_reference (&omapi_io_states.next, io -> next, MDL); } omapi_io_dereference (&io, MDL); goto again; } } FD_ZERO (&r); FD_ZERO (&w); t0.tv_sec = t0.tv_usec = 0; /* Same deal for write fdets. */ if (io -> writefd && io -> inner && (desc = (*(io -> writefd)) (io -> inner)) >= 0) { FD_SET (desc, &w); count = select (desc + 1, &r, &w, &x, &t0); if (count < 0) goto bogon; } if (prev) omapi_io_dereference (&prev, MDL); omapi_io_reference (&prev, io, MDL); omapi_io_dereference (&io, MDL); if (prev -> next) omapi_io_reference (&io, prev -> next, MDL); } if (prev) omapi_io_dereference (&prev, MDL); } for (io = omapi_io_states.next; io; io = io -> next) { if (!io -> inner) continue; omapi_object_reference (&tmp, io -> inner, MDL); /* Check for a read descriptor, and if there is one, see if we got input on that socket. */ if (io -> readfd && (desc = (*(io -> readfd)) (tmp)) >= 0) { if (FD_ISSET (desc, &r)) ((*(io -> reader)) (tmp)); } /* Same deal for write descriptors. */ if (io -> writefd && (desc = (*(io -> writefd)) (tmp)) >= 0) { if (FD_ISSET (desc, &w)) ((*(io -> writer)) (tmp)); } omapi_object_dereference (&tmp, MDL); } /* Now check for I/O handles that are no longer valid, and remove them from the list. */ prev = NULL; io = NULL; if (omapi_io_states.next != NULL) { omapi_io_reference(&io, omapi_io_states.next, MDL); } while (io != NULL) { if ((io->inner == NULL) || ((io->reaper != NULL) && ((io->reaper)(io->inner) != ISC_R_SUCCESS))) { omapi_io_object_t *tmp = NULL; /* Save a reference to the next pointer, if there is one. */ if (io->next != NULL) { omapi_io_reference(&tmp, io->next, MDL); omapi_io_dereference(&io->next, MDL); } if (prev != NULL) { omapi_io_dereference(&prev->next, MDL); if (tmp != NULL) omapi_io_reference(&prev->next, tmp, MDL); } else { omapi_io_dereference(&omapi_io_states.next, MDL); if (tmp != NULL) omapi_io_reference (&omapi_io_states.next, tmp, MDL); else omapi_signal_in( (omapi_object_t *) &omapi_io_states, "ready"); } if (tmp != NULL) omapi_io_dereference(&tmp, MDL); } else { if (prev != NULL) { omapi_io_dereference(&prev, MDL); } omapi_io_reference(&prev, io, MDL); } /* * Equivalent to: * io = io->next * But using our reference counting voodoo. */ next = NULL; if (io->next != NULL) { omapi_io_reference(&next, io->next, MDL); } omapi_io_dereference(&io, MDL); if (next != NULL) { omapi_io_reference(&io, next, MDL); omapi_io_dereference(&next, MDL); } } if (prev != NULL) { omapi_io_dereference(&prev, MDL); } return ISC_R_SUCCESS; } isc_result_t omapi_io_set_value (omapi_object_t *h, omapi_object_t *id, omapi_data_string_t *name, omapi_typed_data_t *value) { if (h -> type != omapi_type_io_object) return DHCP_R_INVALIDARG; if (h -> inner && h -> inner -> type -> set_value) return (*(h -> inner -> type -> set_value)) (h -> inner, id, name, value); return ISC_R_NOTFOUND; } isc_result_t omapi_io_get_value (omapi_object_t *h, omapi_object_t *id, omapi_data_string_t *name, omapi_value_t **value) { if (h -> type != omapi_type_io_object) return DHCP_R_INVALIDARG; if (h -> inner && h -> inner -> type -> get_value) return (*(h -> inner -> type -> get_value)) (h -> inner, id, name, value); return ISC_R_NOTFOUND; } /* omapi_io_destroy (object, MDL); * * Find the requested IO [object] and remove it from the list of io * states, causing the cleanup functions to destroy it. Note that we must * hold a reference on the object while moving its ->next reference and * removing the reference in the chain to the target object...otherwise it * may be cleaned up from under us. */ isc_result_t omapi_io_destroy (omapi_object_t *h, const char *file, int line) { omapi_io_object_t *obj = NULL, *p, *last = NULL, **holder; if (h -> type != omapi_type_io_object) return DHCP_R_INVALIDARG; /* remove from the list of I/O states */ for (p = omapi_io_states.next; p; p = p -> next) { if (p == (omapi_io_object_t *)h) { omapi_io_reference (&obj, p, MDL); if (last) holder = &last -> next; else holder = &omapi_io_states.next; omapi_io_dereference (holder, MDL); if (obj -> next) { omapi_io_reference (holder, obj -> next, MDL); omapi_io_dereference (&obj -> next, MDL); } return omapi_io_dereference (&obj, MDL); } last = p; } return ISC_R_NOTFOUND; } isc_result_t omapi_io_signal_handler (omapi_object_t *h, const char *name, va_list ap) { if (h -> type != omapi_type_io_object) return DHCP_R_INVALIDARG; if (h -> inner && h -> inner -> type -> signal_handler) return (*(h -> inner -> type -> signal_handler)) (h -> inner, name, ap); return ISC_R_NOTFOUND; } isc_result_t omapi_io_stuff_values (omapi_object_t *c, omapi_object_t *id, omapi_object_t *i) { if (i -> type != omapi_type_io_object) return DHCP_R_INVALIDARG; if (i -> inner && i -> inner -> type -> stuff_values) return (*(i -> inner -> type -> stuff_values)) (c, id, i -> inner); return ISC_R_SUCCESS; } isc_result_t omapi_waiter_signal_handler (omapi_object_t *h, const char *name, va_list ap) { omapi_waiter_object_t *waiter; if (h -> type != omapi_type_waiter) return DHCP_R_INVALIDARG; if (!strcmp (name, "ready")) { waiter = (omapi_waiter_object_t *)h; waiter -> ready = 1; waiter -> waitstatus = ISC_R_SUCCESS; return ISC_R_SUCCESS; } if (!strcmp(name, "status")) { waiter = (omapi_waiter_object_t *)h; waiter->ready = 1; waiter->waitstatus = va_arg(ap, isc_result_t); return ISC_R_SUCCESS; } if (!strcmp (name, "disconnect")) { waiter = (omapi_waiter_object_t *)h; waiter -> ready = 1; waiter -> waitstatus = DHCP_R_CONNRESET; return ISC_R_SUCCESS; } if (h -> inner && h -> inner -> type -> signal_handler) return (*(h -> inner -> type -> signal_handler)) (h -> inner, name, ap); return ISC_R_NOTFOUND; } isc_result_t omapi_io_state_foreach (isc_result_t (*func) (omapi_object_t *, void *), void *p) { omapi_io_object_t *io; isc_result_t status; for (io = omapi_io_states.next; io; io = io -> next) { if (io -> inner) { status = (*func) (io -> inner, p); if (status != ISC_R_SUCCESS) return status; } } return ISC_R_SUCCESS; } dhcp-4.2.4/omapip/errwarn.c000644 000765 000024 00000022670 11232130545 015503 0ustar00sarstaff000000 000000 /* errwarn.c Errors and warnings... */ /* * Copyright (c) 1995 RadioMail Corporation. * Copyright (c) 2004,2007,2009 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1996-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ * * This software was written for RadioMail Corporation by Ted Lemon * under a contract with Vixie Enterprises. Further modifications have * been made for Internet Systems Consortium under a contract * with Vixie Laboratories. */ #include "dhcpd.h" #include #include #include #ifdef DEBUG int log_perror = -1; #else int log_perror = 1; #endif int log_priority; void (*log_cleanup) (void); #define CVT_BUF_MAX 1023 static char mbuf [CVT_BUF_MAX + 1]; static char fbuf [CVT_BUF_MAX + 1]; /* Log an error message, then exit... */ void log_fatal (const char * fmt, ... ) { va_list list; do_percentm (fbuf, fmt); /* %Audit% This is log output. %2004.06.17,Safe% * If we truncate we hope the user can get a hint from the log. */ va_start (list, fmt); vsnprintf (mbuf, sizeof mbuf, fbuf, list); va_end (list); #ifndef DEBUG syslog (log_priority | LOG_ERR, "%s", mbuf); #endif /* Also log it to stderr? */ if (log_perror) { IGNORE_RET (write (STDERR_FILENO, mbuf, strlen (mbuf))); IGNORE_RET (write (STDERR_FILENO, "\n", 1)); } #if !defined (NOMINUM) log_error ("%s", ""); log_error ("If you did not get this software from ftp.isc.org, please"); log_error ("get the latest from ftp.isc.org and install that before"); log_error ("requesting help."); log_error ("%s", ""); log_error ("If you did get this software from ftp.isc.org and have not"); log_error ("yet read the README, please read it before requesting help."); log_error ("If you intend to request help from the dhcp-server@isc.org"); log_error ("mailing list, please read the section on the README about"); log_error ("submitting bug reports and requests for help."); log_error ("%s", ""); log_error ("Please do not under any circumstances send requests for"); log_error ("help directly to the authors of this software - please"); log_error ("send them to the appropriate mailing list as described in"); log_error ("the README file."); log_error ("%s", ""); log_error ("exiting."); #endif if (log_cleanup) (*log_cleanup) (); exit (1); } /* Log an error message... */ int log_error (const char * fmt, ...) { va_list list; do_percentm (fbuf, fmt); /* %Audit% This is log output. %2004.06.17,Safe% * If we truncate we hope the user can get a hint from the log. */ va_start (list, fmt); vsnprintf (mbuf, sizeof mbuf, fbuf, list); va_end (list); #ifndef DEBUG syslog (log_priority | LOG_ERR, "%s", mbuf); #endif if (log_perror) { IGNORE_RET (write (STDERR_FILENO, mbuf, strlen (mbuf))); IGNORE_RET (write (STDERR_FILENO, "\n", 1)); } return 0; } /* Log a note... */ int log_info (const char *fmt, ...) { va_list list; do_percentm (fbuf, fmt); /* %Audit% This is log output. %2004.06.17,Safe% * If we truncate we hope the user can get a hint from the log. */ va_start (list, fmt); vsnprintf (mbuf, sizeof mbuf, fbuf, list); va_end (list); #ifndef DEBUG syslog (log_priority | LOG_INFO, "%s", mbuf); #endif if (log_perror) { IGNORE_RET (write (STDERR_FILENO, mbuf, strlen (mbuf))); IGNORE_RET (write (STDERR_FILENO, "\n", 1)); } return 0; } /* Log a debug message... */ int log_debug (const char *fmt, ...) { va_list list; do_percentm (fbuf, fmt); /* %Audit% This is log output. %2004.06.17,Safe% * If we truncate we hope the user can get a hint from the log. */ va_start (list, fmt); vsnprintf (mbuf, sizeof mbuf, fbuf, list); va_end (list); #ifndef DEBUG syslog (log_priority | LOG_DEBUG, "%s", mbuf); #endif if (log_perror) { IGNORE_RET (write (STDERR_FILENO, mbuf, strlen (mbuf))); IGNORE_RET (write (STDERR_FILENO, "\n", 1)); } return 0; } /* Find %m in the input string and substitute an error message string. */ void do_percentm (obuf, ibuf) char *obuf; const char *ibuf; { const char *s = ibuf; char *p = obuf; int infmt = 0; const char *m; int len = 0; while (*s) { if (infmt) { if (*s == 'm') { #ifndef __CYGWIN32__ m = strerror (errno); #else m = pWSAError (); #endif if (!m) m = ""; len += strlen (m); if (len > CVT_BUF_MAX) goto out; strcpy (p - 1, m); p += strlen (p); ++s; } else { if (++len > CVT_BUF_MAX) goto out; *p++ = *s++; } infmt = 0; } else { if (*s == '%') infmt = 1; if (++len > CVT_BUF_MAX) goto out; *p++ = *s++; } } out: *p = 0; } #ifdef NO_STRERROR char *strerror (err) int err; { extern char *sys_errlist []; extern int sys_nerr; static char errbuf [128]; if (err < 0 || err >= sys_nerr) { sprintf (errbuf, "Error %d", err); return errbuf; } return sys_errlist [err]; } #endif /* NO_STRERROR */ #ifdef _WIN32 char *pWSAError () { int err = WSAGetLastError (); switch (err) { case WSAEACCES: return "Permission denied"; case WSAEADDRINUSE: return "Address already in use"; case WSAEADDRNOTAVAIL: return "Cannot assign requested address"; case WSAEAFNOSUPPORT: return "Address family not supported by protocol family"; case WSAEALREADY: return "Operation already in progress"; case WSAECONNABORTED: return "Software caused connection abort"; case WSAECONNREFUSED: return "Connection refused"; case WSAECONNRESET: return "Connection reset by peer"; case WSAEDESTADDRREQ: return "Destination address required"; case WSAEFAULT: return "Bad address"; case WSAEHOSTDOWN: return "Host is down"; case WSAEHOSTUNREACH: return "No route to host"; case WSAEINPROGRESS: return "Operation now in progress"; case WSAEINTR: return "Interrupted function call"; case WSAEINVAL: return "Invalid argument"; case WSAEISCONN: return "Socket is already connected"; case WSAEMFILE: return "Too many open files"; case WSAEMSGSIZE: return "Message too long"; case WSAENETDOWN: return "Network is down"; case WSAENETRESET: return "Network dropped connection on reset"; case WSAENETUNREACH: return "Network is unreachable"; case WSAENOBUFS: return "No buffer space available"; case WSAENOPROTOOPT: return "Bad protocol option"; case WSAENOTCONN: return "Socket is not connected"; case WSAENOTSOCK: return "Socket operation on non-socket"; case WSAEOPNOTSUPP: return "Operation not supported"; case WSAEPFNOSUPPORT: return "Protocol family not supported"; case WSAEPROCLIM: return "Too many processes"; case WSAEPROTONOSUPPORT: return "Protocol not supported"; case WSAEPROTOTYPE: return "Protocol wrong type for socket"; case WSAESHUTDOWN: return "Cannot send after socket shutdown"; case WSAESOCKTNOSUPPORT: return "Socket type not supported"; case WSAETIMEDOUT: return "Connection timed out"; case WSAEWOULDBLOCK: return "Resource temporarily unavailable"; case WSAHOST_NOT_FOUND: return "Host not found"; #if 0 case WSA_INVALID_HANDLE: return "Specified event object handle is invalid"; case WSA_INVALID_PARAMETER: return "One or more parameters are invalid"; case WSAINVALIDPROCTABLE: return "Invalid procedure table from service provider"; case WSAINVALIDPROVIDER: return "Invalid service provider version number"; case WSA_IO_PENDING: return "Overlapped operations will complete later"; case WSA_IO_INCOMPLETE: return "Overlapped I/O event object not in signaled state"; case WSA_NOT_ENOUGH_MEMORY: return "Insufficient memory available"; #endif case WSANOTINITIALISED: return "Successful WSAStartup not yet performer"; case WSANO_DATA: return "Valid name, no data record of requested type"; case WSANO_RECOVERY: return "This is a non-recoverable error"; #if 0 case WSAPROVIDERFAILEDINIT: return "Unable to initialize a service provider"; case WSASYSCALLFAILURE: return "System call failure"; #endif case WSASYSNOTREADY: return "Network subsystem is unavailable"; case WSATRY_AGAIN: return "Non-authoritative host not found"; case WSAVERNOTSUPPORTED: return "WINSOCK.DLL version out of range"; case WSAEDISCON: return "Graceful shutdown in progress"; #if 0 case WSA_OPERATION_ABORTED: return "Overlapped operation aborted"; #endif } return "Unknown WinSock error"; } #endif /* _WIN32 */ dhcp-4.2.4/omapip/generic.c000644 000765 000024 00000022057 11301372616 015442 0ustar00sarstaff000000 000000 /* generic.c Subroutines that support the generic object. */ /* * Copyright (c) 2004-2007,2009 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1999-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ * * This software has been written for Internet Systems Consortium * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. * To learn more about Internet Systems Consortium, see * ``https://www.isc.org/''. To learn more about Vixie Enterprises, * see ``http://www.vix.com''. To learn more about Nominum, Inc., see * ``http://www.nominum.com''. */ #include "dhcpd.h" #include OMAPI_OBJECT_ALLOC (omapi_generic, omapi_generic_object_t, omapi_type_generic) isc_result_t omapi_generic_new (omapi_object_t **gen, const char *file, int line) { /* Backwards compatibility. */ return omapi_generic_allocate ((omapi_generic_object_t **)gen, file, line); } isc_result_t omapi_generic_set_value (omapi_object_t *h, omapi_object_t *id, omapi_data_string_t *name, omapi_typed_data_t *value) { omapi_generic_object_t *g; omapi_value_t *new; omapi_value_t **va; u_int8_t *ca; int vm_new; int i, vfree = -1; isc_result_t status; if (h -> type != omapi_type_generic) return DHCP_R_INVALIDARG; g = (omapi_generic_object_t *)h; /* See if there's already a value with this name attached to the generic object, and if so, replace the current value with the new one. */ for (i = 0; i < g -> nvalues; i++) { if (!omapi_data_string_cmp (name, g -> values [i] -> name)) { /* There's an inconsistency here: the standard behaviour of a set_values method when passed a matching name and a null value is to delete the value associated with that name (where possible). In the generic object, we remember the name/null pair, because generic objects are generally used to pass messages around, and this is the way that remote entities delete values from local objects. If the get_value method of a generic object is called for a name that maps to a name/null pair, ISC_R_NOTFOUND is returned. */ new = (omapi_value_t *)0; status = (omapi_value_new (&new, MDL)); if (status != ISC_R_SUCCESS) return status; omapi_data_string_reference (&new -> name, name, MDL); if (value) omapi_typed_data_reference (&new -> value, value, MDL); omapi_value_dereference (&(g -> values [i]), MDL); status = (omapi_value_reference (&(g -> values [i]), new, MDL)); omapi_value_dereference (&new, MDL); g -> changed [i] = 1; return status; } /* Notice a free slot if we pass one. */ else if (vfree == -1 && !g -> values [i]) vfree = i; } /* If the name isn't already attached to this object, see if an inner object has it. */ if (h -> inner && h -> inner -> type -> set_value) { status = ((*(h -> inner -> type -> set_value)) (h -> inner, id, name, value)); if (status != ISC_R_NOTFOUND) return status; } /* Okay, so it's a value that no inner object knows about, and (implicitly, since the outer object set_value method would have called this object's set_value method) it's an object that no outer object knows about, it's this object's responsibility to remember it - that's what generic objects do. */ /* Arrange for there to be space for the pointer to the new name/value pair if necessary: */ if (vfree == -1) { vfree = g -> nvalues; if (vfree == g -> va_max) { if (g -> va_max) vm_new = 2 * g -> va_max; else vm_new = 10; va = dmalloc (vm_new * sizeof *va, MDL); if (!va) return ISC_R_NOMEMORY; ca = dmalloc (vm_new * sizeof *ca, MDL); if (!ca) { dfree (va, MDL); return ISC_R_NOMEMORY; } if (g -> va_max) { memcpy (va, g -> values, g -> va_max * sizeof *va); memcpy (ca, g -> changed, g -> va_max * sizeof *ca); } memset (va + g -> va_max, 0, (vm_new - g -> va_max) * sizeof *va); memset (ca + g -> va_max, 0, (vm_new - g -> va_max) * sizeof *ca); if (g -> values) dfree (g -> values, MDL); if (g -> changed) dfree (g -> changed, MDL); g -> values = va; g -> changed = ca; g -> va_max = vm_new; } } status = omapi_value_new (&g -> values [vfree], MDL); if (status != ISC_R_SUCCESS) return status; omapi_data_string_reference (&g -> values [vfree] -> name, name, MDL); if (value) omapi_typed_data_reference (&g -> values [vfree] -> value, value, MDL); g -> changed [vfree] = 1; if (vfree == g -> nvalues) g -> nvalues++; return ISC_R_SUCCESS; } isc_result_t omapi_generic_get_value (omapi_object_t *h, omapi_object_t *id, omapi_data_string_t *name, omapi_value_t **value) { int i; omapi_generic_object_t *g; if (h -> type != omapi_type_generic) return DHCP_R_INVALIDARG; g = (omapi_generic_object_t *)h; /* Look up the specified name in our list of objects. */ for (i = 0; i < g -> nvalues; i++) { if (!g -> values[i]) continue; if (!omapi_data_string_cmp (name, g -> values [i] -> name)) { /* If this is a name/null value pair, this is the same as if there were no value that matched the specified name, so return ISC_R_NOTFOUND. */ if (!g -> values [i] -> value) return ISC_R_NOTFOUND; /* Otherwise, return the name/value pair. */ return omapi_value_reference (value, g -> values [i], MDL); } } if (h -> inner && h -> inner -> type -> get_value) return (*(h -> inner -> type -> get_value)) (h -> inner, id, name, value); return ISC_R_NOTFOUND; } isc_result_t omapi_generic_destroy (omapi_object_t *h, const char *file, int line) { omapi_generic_object_t *g; int i; if (h -> type != omapi_type_generic) return ISC_R_UNEXPECTED; g = (omapi_generic_object_t *)h; if (g -> values) { for (i = 0; i < g -> nvalues; i++) { if (g -> values [i]) omapi_value_dereference (&g -> values [i], file, line); } dfree (g -> values, file, line); dfree (g -> changed, file, line); g -> values = (omapi_value_t **)0; g -> changed = (u_int8_t *)0; g -> va_max = 0; } return ISC_R_SUCCESS; } isc_result_t omapi_generic_signal_handler (omapi_object_t *h, const char *name, va_list ap) { if (h -> type != omapi_type_generic) return DHCP_R_INVALIDARG; if (h -> inner && h -> inner -> type -> signal_handler) return (*(h -> inner -> type -> signal_handler)) (h -> inner, name, ap); return ISC_R_NOTFOUND; } /* Write all the published values associated with the object through the specified connection. */ isc_result_t omapi_generic_stuff_values (omapi_object_t *c, omapi_object_t *id, omapi_object_t *g) { omapi_generic_object_t *src; int i; isc_result_t status; if (g -> type != omapi_type_generic) return DHCP_R_INVALIDARG; src = (omapi_generic_object_t *)g; for (i = 0; i < src -> nvalues; i++) { if (src -> values [i] && src -> values [i] -> name -> len && src -> changed [i]) { status = (omapi_connection_put_uint16 (c, src -> values [i] -> name -> len)); if (status != ISC_R_SUCCESS) return status; status = (omapi_connection_copyin (c, src -> values [i] -> name -> value, src -> values [i] -> name -> len)); if (status != ISC_R_SUCCESS) return status; status = (omapi_connection_write_typed_data (c, src -> values [i] -> value)); if (status != ISC_R_SUCCESS) return status; } } if (g -> inner && g -> inner -> type -> stuff_values) return (*(g -> inner -> type -> stuff_values)) (c, id, g -> inner); return ISC_R_SUCCESS; } /* Clear the changed flags on the object. This has the effect that if generic_stuff is called, any attributes that still have a cleared changed flag aren't sent to the peer. This also deletes any values that are null, presuming that these have now been properly handled. */ isc_result_t omapi_generic_clear_flags (omapi_object_t *o) { int i; omapi_generic_object_t *g; if (o -> type != omapi_type_generic) return DHCP_R_INVALIDARG; g = (omapi_generic_object_t *)o; for (i = 0; i < g -> nvalues; i++) { g -> changed [i] = 0; if (g -> values [i] && !g -> values [i] -> value) omapi_value_dereference (&g -> values [i], MDL); } return ISC_R_SUCCESS; } dhcp-4.2.4/omapip/handle.c000644 000765 000024 00000024622 11726364513 015271 0ustar00sarstaff000000 000000 /* handle.c Functions for maintaining handles on objects. */ /* * Copyright (c) 2009-2010,2012 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 2004-2007 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1999-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ * * This software has been written for Internet Systems Consortium * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. * To learn more about Internet Systems Consortium, see * ``https://www.isc.org/''. To learn more about Vixie Enterprises, * see ``http://www.vix.com''. To learn more about Nominum, Inc., see * ``http://www.nominum.com''. */ #include "dhcpd.h" #include /* The handle table is a hierarchical tree designed for quick mapping of handle identifiers to objects. Objects contain their own handle identifiers if they have them, so the reverse mapping is also quick. The hierarchy is made up of table objects, each of which has 120 entries, a flag indicating whether the table is a leaf table or an indirect table, the handle of the first object covered by the table and the first object after that that's *not* covered by the table, a count of how many objects of either type are currently stored in the table, and an array of 120 entries pointing either to objects or tables. When we go to add an object to the table, we look to see if the next object handle to be assigned is covered by the outermost table. If it is, we find the place within that table where the next handle should go, and if necessary create additional nodes in the tree to contain the new handle. The pointer to the object is then stored in the correct position. Theoretically, we could have some code here to free up handle tables as they go out of use, but by and large handle tables won't go out of use, so this is being skipped for now. It shouldn't be too hard to implement in the future if there's a different application. */ omapi_handle_table_t *omapi_handle_table; omapi_handle_t omapi_next_handle = 1; /* Next handle to be assigned. */ #define FIND_HAND 0 #define CLEAR_HAND 1 static isc_result_t omapi_handle_lookup_in (omapi_object_t **, omapi_handle_t, omapi_handle_table_t *, int); static isc_result_t omapi_object_handle_in_table (omapi_handle_t, omapi_handle_table_t *, omapi_object_t *); static isc_result_t omapi_handle_table_enclose (omapi_handle_table_t **); isc_result_t omapi_object_handle (omapi_handle_t *h, omapi_object_t *o) { isc_result_t status; if (o -> handle) { *h = o -> handle; return ISC_R_SUCCESS; } if (!omapi_handle_table) { omapi_handle_table = dmalloc (sizeof *omapi_handle_table, MDL); if (!omapi_handle_table) return ISC_R_NOMEMORY; memset (omapi_handle_table, 0, sizeof *omapi_handle_table); omapi_handle_table -> first = 0; omapi_handle_table -> limit = OMAPI_HANDLE_TABLE_SIZE; omapi_handle_table -> leafp = 1; } /* If this handle doesn't fit in the outer table, we need to make a new outer table. This is a while loop in case for some reason we decide to do disjoint handle allocation, where the next level of indirection still isn't big enough to enclose the next handle ID. */ while (omapi_next_handle >= omapi_handle_table -> limit) { omapi_handle_table_t *new; new = dmalloc (sizeof *new, MDL); if (!new) return ISC_R_NOMEMORY; memset (new, 0, sizeof *new); new -> first = 0; new -> limit = (omapi_handle_table -> limit * OMAPI_HANDLE_TABLE_SIZE); new -> leafp = 0; new -> children [0].table = omapi_handle_table; omapi_handle_table = new; } /* Try to cram this handle into the existing table. */ status = omapi_object_handle_in_table (omapi_next_handle, omapi_handle_table, o); /* If it worked, return the next handle and increment it. */ if (status == ISC_R_SUCCESS) { *h = omapi_next_handle; omapi_next_handle++; return ISC_R_SUCCESS; } if (status != ISC_R_NOSPACE) return status; status = omapi_handle_table_enclose (&omapi_handle_table); if (status != ISC_R_SUCCESS) return status; status = omapi_object_handle_in_table (omapi_next_handle, omapi_handle_table, o); if (status != ISC_R_SUCCESS) return status; *h = omapi_next_handle; omapi_next_handle++; return ISC_R_SUCCESS; } static isc_result_t omapi_object_handle_in_table (omapi_handle_t h, omapi_handle_table_t *table, omapi_object_t *o) { omapi_handle_table_t *inner; omapi_handle_t scale, index; isc_result_t status; if (table -> first > h || table -> limit <= h) return ISC_R_NOSPACE; /* If this is a leaf table, just stash the object in the appropriate place. */ if (table -> leafp) { status = (omapi_object_reference (&table -> children [h - table -> first].object, o, MDL)); if (status != ISC_R_SUCCESS) return status; o -> handle = h; return ISC_R_SUCCESS; } /* Scale is the number of handles represented by each child of this table. For a leaf table, scale would be 1. For a first level of indirection, 120. For a second, 120 * 120. Et cetera. */ scale = (table -> limit - table -> first) / OMAPI_HANDLE_TABLE_SIZE; /* So the next most direct table from this one that contains the handle must be the subtable of this table whose index into this table's array of children is the handle divided by the scale. */ index = (h - table -> first) / scale; inner = table -> children [index].table; /* If there is no more direct table than this one in the slot we came up with, make one. */ if (!inner) { inner = dmalloc (sizeof *inner, MDL); if (!inner) return ISC_R_NOMEMORY; memset (inner, 0, sizeof *inner); inner -> first = index * scale + table -> first; inner -> limit = inner -> first + scale; if (scale == OMAPI_HANDLE_TABLE_SIZE) inner -> leafp = 1; table -> children [index].table = inner; } status = omapi_object_handle_in_table (h, inner, o); if (status == ISC_R_NOSPACE) { status = (omapi_handle_table_enclose (&table -> children [index].table)); if (status != ISC_R_SUCCESS) return status; return omapi_object_handle_in_table (h, table -> children [index].table, o); } return status; } static isc_result_t omapi_handle_table_enclose (omapi_handle_table_t **table) { omapi_handle_table_t *inner = *table; omapi_handle_table_t *new; int index, base, scale; /* The scale of the table we're enclosing is going to be the difference between its "first" and "limit" members. So the scale of the table enclosing it is going to be that multiplied by the table size. */ scale = (inner -> first - inner -> limit) * OMAPI_HANDLE_TABLE_SIZE; /* The range that the enclosing table covers is going to be the result of subtracting the remainder of dividing the enclosed table's first entry number by the enclosing table's scale. If handle IDs are being allocated sequentially, the enclosing table's "first" value will be the same as the enclosed table's "first" value. */ base = inner -> first - inner -> first % scale; /* The index into the enclosing table at which the enclosed table will be stored is going to be the difference between the "first" value of the enclosing table and the enclosed table - zero, if we are allocating sequentially. */ index = (base - inner -> first) / OMAPI_HANDLE_TABLE_SIZE; new = dmalloc (sizeof *new, MDL); if (!new) return ISC_R_NOMEMORY; memset (new, 0, sizeof *new); new -> first = base; new -> limit = base + scale; if (scale == OMAPI_HANDLE_TABLE_SIZE) new -> leafp = 0; new -> children [index].table = inner; *table = new; return ISC_R_SUCCESS; } isc_result_t omapi_handle_lookup (omapi_object_t **o, omapi_handle_t h) { return(omapi_handle_lookup_in(o, h, omapi_handle_table, FIND_HAND)); } static isc_result_t omapi_handle_lookup_in (omapi_object_t **o, omapi_handle_t h, omapi_handle_table_t *table, int op) { omapi_handle_t scale, index; if (!table || table->first > h || table->limit <= h) return(ISC_R_NOTFOUND); /* If this is a leaf table, just grab the object. */ if (table->leafp) { /* Not there? */ if (!table->children[h - table->first].object) return(ISC_R_NOTFOUND); if (op == CLEAR_HAND) { table->children[h - table->first].object = NULL; return(ISC_R_SUCCESS); } else { return(omapi_object_reference (o, table->children[h - table->first].object, MDL)); } } /* Scale is the number of handles represented by each child of this table. For a leaf table, scale would be 1. For a first level of indirection, 120. For a second, 120 * 120. Et cetera. */ scale = (table->limit - table->first) / OMAPI_HANDLE_TABLE_SIZE; /* So the next most direct table from this one that contains the handle must be the subtable of this table whose index into this table's array of children is the handle divided by the scale. */ index = (h - table->first) / scale; return(omapi_handle_lookup_in(o, h, table->children[index].table, op)); } /* For looking up objects based on handles that have been sent on the wire. */ isc_result_t omapi_handle_td_lookup (omapi_object_t **obj, omapi_typed_data_t *handle) { omapi_handle_t h; if (handle->type == omapi_datatype_int) h = handle->u.integer; else if (handle->type == omapi_datatype_data && handle->u.buffer.len == sizeof h) { memcpy(&h, handle->u.buffer.value, sizeof h); h = ntohl(h); } else return(DHCP_R_INVALIDARG); return(omapi_handle_lookup(obj, h)); } isc_result_t omapi_handle_clear(omapi_handle_t h) { return(omapi_handle_lookup_in(NULL, h, omapi_handle_table, CLEAR_HAND)); } dhcp-4.2.4/omapip/hash.c000644 000765 000024 00000030437 11373361434 014757 0ustar00sarstaff000000 000000 /* hash.c Routines for manipulating hash tables... */ /* * Copyright (c) 2009-2010 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 2004-2007 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1995-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ * * This software has been written for Internet Systems Consortium * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. * To learn more about Internet Systems Consortium, see * ``https://www.isc.org/''. To learn more about Vixie Enterprises, * see ``http://www.vix.com''. To learn more about Nominum, Inc., see * ``http://www.nominum.com''. */ #include "dhcpd.h" #include #include #include static unsigned find_length(const void *key, unsigned (*do_hash)(const void *, unsigned, unsigned)) { if (do_hash == do_case_hash || do_hash == do_string_hash) return strlen((const char *)key); if (do_hash == do_number_hash) return sizeof(unsigned); if (do_hash == do_ip4_hash) return 4; log_debug("Unexpected hash function at %s:%d.", MDL); /* * If we get a hash function we don't specifically expect * return a length of 0, this covers the case where a client * id has a length of 0. */ return 0; } int new_hash_table (tp, count, file, line) struct hash_table **tp; unsigned count; const char *file; int line; { struct hash_table *rval; unsigned extra; if (!tp) { log_error ("%s(%d): new_hash_table called with null pointer.", file, line); #if defined (POINTER_DEBUG) abort (); #endif return 0; } if (*tp) { log_error ("%s(%d): non-null target for new_hash_table.", file, line); #if defined (POINTER_DEBUG) abort (); #endif } /* There is one hash bucket in the structure. Allocate extra * memory beyond the end of the structure to fulfill the requested * count ("count - 1"). Do not let there be less than one. */ if (count <= 1) extra = 0; else extra = count - 1; rval = dmalloc(sizeof(struct hash_table) + (extra * sizeof(struct hash_bucket *)), file, line); if (!rval) return 0; rval -> hash_count = count; *tp = rval; return 1; } void free_hash_table (tp, file, line) struct hash_table **tp; const char *file; int line; { struct hash_table *ptr = *tp; #if defined (DEBUG_MEMORY_LEAKAGE) || \ defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT) int i; struct hash_bucket *hbc, *hbn = (struct hash_bucket *)0; for (i = 0; i < ptr -> hash_count; i++) { for (hbc = ptr -> buckets [i]; hbc; hbc = hbn) { hbn = hbc -> next; if (ptr -> dereferencer && hbc -> value) (*ptr -> dereferencer) (&hbc -> value, MDL); } for (hbc = ptr -> buckets [i]; hbc; hbc = hbn) { hbn = hbc -> next; free_hash_bucket (hbc, MDL); } ptr -> buckets [i] = (struct hash_bucket *)0; } #endif dfree((void *)ptr, MDL); *tp = (struct hash_table *)0; } struct hash_bucket *free_hash_buckets; #if defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT) struct hash_bucket *hash_bucket_hunks; void relinquish_hash_bucket_hunks () { struct hash_bucket *c, *n, **p; /* Account for all the hash buckets on the free list. */ p = &free_hash_buckets; for (c = free_hash_buckets; c; c = c -> next) { for (n = hash_bucket_hunks; n; n = n -> next) { if (c > n && c < n + 127) { *p = c -> next; n -> len++; break; } } /* If we didn't delete the hash bucket from the free list, advance the pointer. */ if (!n) p = &c -> next; } for (c = hash_bucket_hunks; c; c = n) { n = c -> next; if (c -> len != 126) { log_info ("hashbucket %lx hash_buckets %d free %u", (unsigned long)c, 127, c -> len); } dfree (c, MDL); } } #endif struct hash_bucket *new_hash_bucket (file, line) const char *file; int line; { struct hash_bucket *rval; int i = 0; if (!free_hash_buckets) { rval = dmalloc (127 * sizeof (struct hash_bucket), file, line); if (!rval) return rval; # if defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT) rval -> next = hash_bucket_hunks; hash_bucket_hunks = rval; hash_bucket_hunks -> len = 0; i++; rval++; #endif for (; i < 127; i++) { rval -> next = free_hash_buckets; free_hash_buckets = rval; rval++; } } rval = free_hash_buckets; free_hash_buckets = rval -> next; return rval; } void free_hash_bucket (ptr, file, line) struct hash_bucket *ptr; const char *file; int line; { #if defined (DEBUG_MALLOC_POOL) struct hash_bucket *hp; for (hp = free_hash_buckets; hp; hp = hp -> next) { if (hp == ptr) { log_error ("hash bucket freed twice!"); abort (); } } #endif ptr -> next = free_hash_buckets; free_hash_buckets = ptr; } int new_hash(struct hash_table **rp, hash_reference referencer, hash_dereference dereferencer, unsigned hsize, unsigned (*hasher)(const void *, unsigned, unsigned), const char *file, int line) { if (hsize == 0) hsize = DEFAULT_HASH_SIZE; if (!new_hash_table (rp, hsize, file, line)) return 0; memset ((*rp)->buckets, 0, hsize * sizeof(struct hash_bucket *)); (*rp)->referencer = referencer; (*rp)->dereferencer = dereferencer; (*rp)->do_hash = hasher; if (hasher == do_case_hash) (*rp)->cmp = casecmp; else (*rp)->cmp = memcmp; return 1; } unsigned do_case_hash(const void *name, unsigned len, unsigned size) { register unsigned accum = 0; register const unsigned char *s = name; int i = len; register unsigned c; while (i--) { /* Make the hash case-insensitive. */ c = *s++; if (isascii(c)) c = tolower(c); /* Add the character in... */ accum = (accum << 1) + c; /* Add carry back in... */ while (accum > 65535) { accum = (accum & 65535) + (accum >> 16); } } return accum % size; } unsigned do_string_hash(const void *name, unsigned len, unsigned size) { register unsigned accum = 0; register const unsigned char *s = (const unsigned char *)name; int i = len; while (i--) { /* Add the character in... */ accum = (accum << 1) + *s++; /* Add carry back in... */ while (accum > 65535) { accum = (accum & 65535) + (accum >> 16); } } return accum % size; } /* Client identifiers are generally 32-bits of ordinary * non-randomness followed by 24-bits of unordinary randomness. * So, end-align in 24-bit chunks, and xor any preceding data * just to mix it up a little. */ unsigned do_id_hash(const void *name, unsigned len, unsigned size) { register unsigned accum = 0; register const unsigned char *s = (const unsigned char *)name; const unsigned char *end = s + len; if (len == 0) return 0; /* * The switch handles our starting conditions, then we hash the * remaining bytes in groups of 3 */ switch (len % 3) { case 0: break; case 2: accum ^= *s++ << 8; case 1: accum ^= *s++; break; } while (s < end) { accum ^= *s++ << 16; accum ^= *s++ << 8; accum ^= *s++; } return accum % size; } unsigned do_number_hash(const void *key, unsigned len, unsigned size) { register unsigned number = *((const unsigned *)key); return number % size; } unsigned do_ip4_hash(const void *key, unsigned len, unsigned size) { u_int32_t number; memcpy(&number, key, 4); number = ntohl(number); return number % size; } unsigned char * hash_report(struct hash_table *table) { static unsigned char retbuf[sizeof("Contents/Size (%): " "2147483647/2147483647 " "(2147483647%). " "Min/max: 2147483647/2147483647")]; unsigned curlen, pct, contents=0, minlen=UINT_MAX, maxlen=0; unsigned i; struct hash_bucket *bp; if (table == NULL) return (unsigned char *) "No table."; if (table->hash_count == 0) return (unsigned char *) "Invalid hash table."; for (i = 0 ; i < table->hash_count ; i++) { curlen = 0; bp = table->buckets[i]; while (bp != NULL) { curlen++; bp = bp->next; } if (curlen < minlen) minlen = curlen; if (curlen > maxlen) maxlen = curlen; contents += curlen; } if (contents >= (UINT_MAX / 100)) pct = contents / ((table->hash_count / 100) + 1); else pct = (contents * 100) / table->hash_count; if (contents > 2147483647 || table->hash_count > 2147483647 || pct > 2147483647 || minlen > 2147483647 || maxlen > 2147483647) return (unsigned char *) "Report out of range for display."; sprintf((char *)retbuf, "Contents/Size (%%): %u/%u (%u%%). Min/max: %u/%u", contents, table->hash_count, pct, minlen, maxlen); return retbuf; } void add_hash (table, key, len, pointer, file, line) struct hash_table *table; unsigned len; const void *key; hashed_object_t *pointer; const char *file; int line; { int hashno; struct hash_bucket *bp; void *foo; if (!table) return; if (!len) len = find_length(key, table->do_hash); hashno = (*table->do_hash)(key, len, table->hash_count); bp = new_hash_bucket (file, line); if (!bp) { log_error ("Can't add entry to hash table: no memory."); return; } bp -> name = key; if (table -> referencer) { foo = &bp -> value; (*(table -> referencer)) (foo, pointer, file, line); } else bp -> value = pointer; bp -> next = table -> buckets [hashno]; bp -> len = len; table -> buckets [hashno] = bp; } void delete_hash_entry (table, key, len, file, line) struct hash_table *table; unsigned len; const void *key; const char *file; int line; { int hashno; struct hash_bucket *bp, *pbp = (struct hash_bucket *)0; void *foo; if (!table) return; if (!len) len = find_length(key, table->do_hash); hashno = (*table->do_hash)(key, len, table->hash_count); /* Go through the list looking for an entry that matches; if we find it, delete it. */ for (bp = table -> buckets [hashno]; bp; bp = bp -> next) { if ((!bp -> len && !strcmp ((const char *)bp->name, key)) || (bp -> len == len && !(table -> cmp)(bp->name, key, len))) { if (pbp) { pbp -> next = bp -> next; } else { table -> buckets [hashno] = bp -> next; } if (bp -> value && table -> dereferencer) { foo = &bp -> value; (*(table -> dereferencer)) (foo, file, line); } free_hash_bucket (bp, file, line); break; } pbp = bp; /* jwg, 9/6/96 - nice catch! */ } } int hash_lookup (vp, table, key, len, file, line) hashed_object_t **vp; struct hash_table *table; const void *key; unsigned len; const char *file; int line; { int hashno; struct hash_bucket *bp; if (!table) return 0; if (!len) len = find_length(key, table->do_hash); if (*vp != NULL) { log_fatal("Internal inconsistency: storage value has not been " "initialized to zero (from %s:%d).", file, line); } hashno = (*table->do_hash)(key, len, table->hash_count); for (bp = table -> buckets [hashno]; bp; bp = bp -> next) { if (len == bp -> len && !(*table->cmp)(bp->name, key, len)) { if (table -> referencer) (*table -> referencer) (vp, bp -> value, file, line); else *vp = bp -> value; return 1; } } return 0; } int hash_foreach (struct hash_table *table, hash_foreach_func func) { int i; struct hash_bucket *bp, *next; int count = 0; if (!table) return 0; for (i = 0; i < table -> hash_count; i++) { bp = table -> buckets [i]; while (bp) { next = bp -> next; if ((*func)(bp->name, bp->len, bp->value) != ISC_R_SUCCESS) return count; bp = next; count++; } } return count; } int casecmp (const void *v1, const void *v2, size_t len) { size_t i; const unsigned char *s = v1; const unsigned char *t = v2; for (i = 0; i < len; i++) { int c1, c2; if (isascii(s[i])) c1 = tolower(s[i]); else c1 = s[i]; if (isascii(t[i])) c2 = tolower(t[i]); else c2 = t[i]; if (c1 < c2) return -1; if (c1 > c2) return 1; } return 0; } dhcp-4.2.4/omapip/inet_addr.c000644 000765 000024 00000010245 10741251222 015747 0ustar00sarstaff000000 000000 /* $NetBSD: inet_addr.c,v 1.6 1996/02/02 15:22:23 mrg Exp $ */ /* * Copyright (c) 1983, 1990, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #if defined(LIBC_SCCS) && !defined(lint) #if 0 static char sccsid[] = "@(#)inet_addr.c 8.1 (Berkeley) 6/17/93"; #else static char rcsid[] = "$NetBSD: inet_addr.c,v 1.6 1996/02/02 15:22:23 mrg Exp $"; #endif #endif /* LIBC_SCCS and not lint */ #include "dhcpd.h" #include "omapip/omapip_p.h" #ifdef NEED_INET_ATON /* * Check whether "cp" is a valid ascii representation * of an Internet address and convert to a binary address. * Returns 1 if the address is valid, 0 if not. * This replaces inet_addr, the return value from which * cannot distinguish between failure and a local broadcast address. */ int inet_aton(cp, addr) const char *cp; struct in_addr *addr; { register u_long val; register int base, n; register char c; u_int parts[4]; register u_int *pp = parts; for (;;) { /* * Collect number up to ``.''. * Values are specified as for C: * 0x=hex, 0=octal, other=decimal. */ val = 0; base = 10; if (*cp == '0') { if (*++cp == 'x' || *cp == 'X') base = 16, cp++; else base = 8; } while ((c = *cp) != '\0') { if (isascii(c) && isdigit((int)c)) { val = (val * base) + (c - '0'); cp++; continue; } if (base == 16 && isascii(c) && isxdigit((int)c)) { val = (val << 4) + (c + 10 - (islower((int)c) ? 'a' : 'A')); cp++; continue; } break; } if (*cp == '.') { /* * Internet format: * a.b.c.d * a.b.c (with c treated as 16-bits) * a.b (with b treated as 24 bits) */ if (pp >= parts + 3 || val > 0xff) return (0); *pp++ = val, cp++; } else break; } /* * Check for trailing characters. */ if (*cp && (!isascii(*cp) || !isspace((int)*cp))) return (0); /* * Concoct the address according to * the number of parts specified. */ n = pp - parts + 1; switch (n) { case 0: return (0); /* initial nondigit */ case 1: /* a -- 32 bits */ break; case 2: /* a.b -- 8.24 bits */ if (val > 0xffffff) return (0); val |= parts[0] << 24; break; case 3: /* a.b.c -- 8.8.16 bits */ if (val > 0xffff) return (0); val |= (parts[0] << 24) | (parts[1] << 16); break; case 4: /* a.b.c.d -- 8.8.8.8 bits */ if (val > 0xff) return (0); val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8); break; } if (addr) addr->s_addr = htonl(val); return (1); } #endif dhcp-4.2.4/omapip/isclib.c000644 000765 000024 00000013210 11376616315 015273 0ustar00sarstaff000000 000000 /* * Copyright(c) 2009-2010 by Internet Systems Consortium, Inc.("ISC") * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * http://www.isc.org/ * */ /*Trying to figure out what we need to define to get things to work. It looks like we want/need the export library but need the fdwatchcommand which may be a problem */ #include "dhcpd.h" #include dhcp_context_t dhcp_gbl_ctx; void isclib_cleanup(void) { #if defined (NSUPDATE) if (dhcp_gbl_ctx.dnsclient != NULL) dns_client_destroy((dns_client_t **)&dhcp_gbl_ctx.dnsclient); #endif if (dhcp_gbl_ctx.task != NULL) { isc_task_shutdown(dhcp_gbl_ctx.task); isc_task_detach(&dhcp_gbl_ctx.task); } if (dhcp_gbl_ctx.timermgr != NULL) isc_timermgr_destroy(&dhcp_gbl_ctx.timermgr); if (dhcp_gbl_ctx.socketmgr != NULL) isc_socketmgr_destroy(&dhcp_gbl_ctx.socketmgr); if (dhcp_gbl_ctx.taskmgr != NULL) isc_taskmgr_destroy(&dhcp_gbl_ctx.taskmgr); if (dhcp_gbl_ctx.actx_started != ISC_FALSE) { isc_app_ctxfinish(dhcp_gbl_ctx.actx); dhcp_gbl_ctx.actx_started = ISC_FALSE; } if (dhcp_gbl_ctx.actx != NULL) isc_appctx_destroy(&dhcp_gbl_ctx.actx); if (dhcp_gbl_ctx.mctx != NULL) isc_mem_detach(&dhcp_gbl_ctx.mctx); return; } isc_result_t dhcp_context_create(void) { isc_result_t result; /* * Set up the error messages, this isn't the right place * for this call but it is convienent for now. */ result = dhcp_result_register(); if (result != ISC_R_SUCCESS) { log_fatal("register_table() %s: %u", "failed", result); } memset(&dhcp_gbl_ctx, 0, sizeof (dhcp_gbl_ctx)); isc_lib_register(); /* get the current time for use as the random seed */ gettimeofday(&cur_tv, (struct timezone *)0); isc_random_seed(cur_tv.tv_sec); #if defined (NSUPDATE) result = dns_lib_init(); if (result != ISC_R_SUCCESS) goto cleanup; #endif result = isc_mem_create(0, 0, &dhcp_gbl_ctx.mctx); if (result != ISC_R_SUCCESS) goto cleanup; result = isc_appctx_create(dhcp_gbl_ctx.mctx, &dhcp_gbl_ctx.actx); if (result != ISC_R_SUCCESS) goto cleanup; result = isc_app_ctxstart(dhcp_gbl_ctx.actx); if (result != ISC_R_SUCCESS) return (result); dhcp_gbl_ctx.actx_started = ISC_TRUE; result = isc_taskmgr_createinctx(dhcp_gbl_ctx.mctx, dhcp_gbl_ctx.actx, 1, 0, &dhcp_gbl_ctx.taskmgr); if (result != ISC_R_SUCCESS) goto cleanup; result = isc_socketmgr_createinctx(dhcp_gbl_ctx.mctx, dhcp_gbl_ctx.actx, &dhcp_gbl_ctx.socketmgr); if (result != ISC_R_SUCCESS) goto cleanup; result = isc_timermgr_createinctx(dhcp_gbl_ctx.mctx, dhcp_gbl_ctx.actx, &dhcp_gbl_ctx.timermgr); if (result != ISC_R_SUCCESS) goto cleanup; result = isc_task_create(dhcp_gbl_ctx.taskmgr, 0, &dhcp_gbl_ctx.task); if (result != ISC_R_SUCCESS) goto cleanup; #if defined (NSUPDATE) result = dns_client_createx(dhcp_gbl_ctx.mctx, dhcp_gbl_ctx.actx, dhcp_gbl_ctx.taskmgr, dhcp_gbl_ctx.socketmgr, dhcp_gbl_ctx.timermgr, 0, &dhcp_gbl_ctx.dnsclient); if (result != ISC_R_SUCCESS) goto cleanup; #else /* The dst library is inited as part of dns_lib_init, we don't * need it if NSUPDATE is enabled */ result = dst_lib_init(dhcp_gbl_ctx.mctx, NULL, 0); if (result != ISC_R_SUCCESS) goto cleanup; #endif return(ISC_R_SUCCESS); cleanup: /* * Currently we don't try and cleanup, just return an error * expecting that our caller will log the error and exit. */ return(result); } /* * Convert a string name into the proper structure for the isc routines * * Previously we allowed names without a trailing '.' however the current * dns and dst code requires the names to end in a period. If the * name doesn't have a trailing period add one as part of creating * the dns name. */ isc_result_t dhcp_isc_name(unsigned char *namestr, dns_fixedname_t *namefix, dns_name_t **name) { size_t namelen; isc_buffer_t b; isc_result_t result; namelen = strlen((char *)namestr); isc_buffer_init(&b, namestr, namelen); isc_buffer_add(&b, namelen); dns_fixedname_init(namefix); *name = dns_fixedname_name(namefix); result = dns_name_fromtext(*name, &b, dns_rootname, 0, NULL); isc_buffer_invalidate(&b); return(result); } isc_result_t isclib_make_dst_key(char *inname, char *algorithm, unsigned char *secret, int length, dst_key_t **dstkey) { isc_result_t result; dns_name_t *name; dns_fixedname_t name0; isc_buffer_t b; isc_buffer_init(&b, secret, length); isc_buffer_add(&b, length); /* We only support HMAC_MD5 currently */ if (strcasecmp(algorithm, DHCP_HMAC_MD5_NAME) != 0) { return(DHCP_R_INVALIDARG); } result = dhcp_isc_name((unsigned char *)inname, &name0, &name); if (result != ISC_R_SUCCESS) { return(result); } return(dst_key_frombuffer(name, DST_ALG_HMACMD5, DNS_KEYOWNER_ENTITY, DNS_KEYPROTO_DNSSEC, dns_rdataclass_in, &b, dhcp_gbl_ctx.mctx, dstkey)); } dhcp-4.2.4/omapip/iscprint.c000644 000765 000024 00000024270 10216364361 015662 0ustar00sarstaff000000 000000 /* * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001, 2003 Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ /* $Id: iscprint.c,v 1.2 2005-03-17 20:30:41 dhankins Exp $ */ #include "dhcpd.h" #ifdef NO_SNPRINTF #ifndef LINT static char copyright[] = "$Id: iscprint.c,v 1.2 2005-03-17 20:30:41 dhankins Exp $ Copyright (c) 2004 Internet Systems Consortium, Inc. All rights reserved."; #endif #define INSIST(cond) REQUIRE(cond) #define REQUIRE(cond) if (!(cond)) { return 0; } /* * Return length of string that would have been written if not truncated. */ int isc_print_snprintf(char *str, size_t size, const char *format, ...) { va_list ap; int ret; va_start(ap, format); ret = vsnprintf(str, size, format, ap); va_end(ap); return (ret); } /* * Return length of string that would have been written if not truncated. */ int isc_print_vsnprintf(char *str, size_t size, const char *format, va_list ap) { int h; int l; int q; int alt; int zero; int left; int plus; int space; int neg; isc_int64_t tmpi; isc_uint64_t tmpui; unsigned long width; unsigned long precision; unsigned int length; char buf[1024]; char c; void *v; char *save = str; const char *cp; const char *head; int count = 0; int pad; int zeropad; int dot; double dbl; #ifdef HAVE_LONG_DOUBLE long double ldbl; #endif char fmt[32]; INSIST(str != NULL); INSIST(format != NULL); while (*format != '\0') { if (*format != '%') { if (size > 1) { *str++ = *format; size--; } count++; format++; continue; } format++; /* * Reset flags. */ dot = neg = space = plus = left = zero = alt = h = l = q = 0; width = precision = 0; head = ""; length = pad = zeropad = 0; do { if (*format == '#') { alt = 1; format++; } else if (*format == '-') { left = 1; zero = 0; format++; } else if (*format == ' ') { if (!plus) space = 1; format++; } else if (*format == '+') { plus = 1; space = 0; format++; } else if (*format == '0') { if (!left) zero = 1; format++; } else break; } while (1); /* * Width. */ if (*format == '*') { width = va_arg(ap, int); format++; } else if (isdigit((unsigned char)*format)) { char *e; width = strtoul(format, &e, 10); format = e; } /* * Precision. */ if (*format == '.') { format++; dot = 1; if (*format == '*') { precision = va_arg(ap, int); format++; } else if (isdigit((unsigned char)*format)) { char *e; precision = strtoul(format, &e, 10); format = e; } } switch (*format) { case '\0': continue; case '%': if (size > 1) { *str++ = *format; size--; } count++; break; case 'q': q = 1; format++; goto doint; case 'h': h = 1; format++; goto doint; case 'l': l = 1; format++; if (*format == 'l') { q = 1; format++; } goto doint; case 'n': case 'i': case 'd': case 'o': case 'u': case 'x': case 'X': doint: if (precision != 0) zero = 0; switch (*format) { case 'n': if (h) { short int *p; p = va_arg(ap, short *); REQUIRE(p != NULL); *p = str - save; } else if (l) { long int *p; p = va_arg(ap, long *); REQUIRE(p != NULL); *p = str - save; } else { int *p; p = va_arg(ap, int *); REQUIRE(p != NULL); *p = str - save; } break; case 'i': case 'd': if (q) tmpi = va_arg(ap, isc_int64_t); else if (l) tmpi = va_arg(ap, long int); else tmpi = va_arg(ap, int); if (tmpi < 0) { head = "-"; tmpui = -tmpi; } else { if (plus) head = "+"; else if (space) head = " "; else head = ""; tmpui = tmpi; } sprintf(buf, "%u", tmpui); goto printint; case 'o': if (q) tmpui = va_arg(ap, isc_uint64_t); else if (l) tmpui = va_arg(ap, long int); else tmpui = va_arg(ap, int); sprintf(buf, alt ? "%#o" : "%o", tmpui); goto printint; case 'u': if (q) tmpui = va_arg(ap, isc_uint64_t); else if (l) tmpui = va_arg(ap, unsigned long int); else tmpui = va_arg(ap, unsigned int); sprintf(buf, "%u", tmpui); goto printint; case 'x': if (q) tmpui = va_arg(ap, isc_uint64_t); else if (l) tmpui = va_arg(ap, unsigned long int); else tmpui = va_arg(ap, unsigned int); if (alt) { head = "0x"; if (precision > 2) precision -= 2; } sprintf(buf, "%x", tmpui); goto printint; case 'X': if (q) tmpui = va_arg(ap, isc_uint64_t); else if (l) tmpui = va_arg(ap, unsigned long int); else tmpui = va_arg(ap, unsigned int); if (alt) { head = "0X"; if (precision > 2) precision -= 2; } sprintf(buf, "%X", tmpui); goto printint; printint: if (precision != 0 || width != 0) { length = strlen(buf); if (length < precision) zeropad = precision - length; else if (length < width && zero) zeropad = width - length; if (width != 0) { pad = width - length - zeropad - strlen(head); if (pad < 0) pad = 0; } } count += strlen(head) + strlen(buf) + pad + zeropad; if (!left) { while (pad > 0 && size > 1) { *str++ = ' '; size--; pad--; } } cp = head; while (*cp != '\0' && size > 1) { *str++ = *cp++; size--; } while (zeropad > 0 && size > 1) { *str++ = '0'; size--; zeropad--; } cp = buf; while (*cp != '\0' && size > 1) { *str++ = *cp++; size--; } while (pad > 0 && size > 1) { *str++ = ' '; size--; pad--; } break; default: break; } break; case 's': cp = va_arg(ap, char *); REQUIRE(cp != NULL); if (precision != 0) { /* * cp need not be NULL terminated. */ const char *tp; unsigned long n; n = precision; tp = cp; while (n != 0 && *tp != '\0') n--, tp++; length = precision - n; } else { length = strlen(cp); } if (width != 0) { pad = width - length; if (pad < 0) pad = 0; } count += pad + length; if (!left) while (pad > 0 && size > 1) { *str++ = ' '; size--; pad--; } if (precision != 0) while (precision > 0 && *cp != '\0' && size > 1) { *str++ = *cp++; size--; precision--; } else while (*cp != '\0' && size > 1) { *str++ = *cp++; size--; } while (pad > 0 && size > 1) { *str++ = ' '; size--; pad--; } break; case 'c': c = va_arg(ap, int); if (width > 0) { count += width; width--; if (left) { *str++ = c; size--; } while (width-- > 0 && size > 1) { *str++ = ' '; size--; } if (!left && size > 1) { *str++ = c; size--; } } else { count++; if (size > 1) { *str++ = c; size--; } } break; case 'p': v = va_arg(ap, void *); sprintf(buf, "%p", v); length = strlen(buf); if (precision > length) zeropad = precision - length; if (width > 0) { pad = width - length - zeropad; if (pad < 0) pad = 0; } count += length + pad + zeropad; if (!left) while (pad > 0 && size > 1) { *str++ = ' '; size--; pad--; } cp = buf; if (zeropad > 0 && buf[0] == '0' && (buf[1] == 'x' || buf[1] == 'X')) { if (size > 1) { *str++ = *cp++; size--; } if (size > 1) { *str++ = *cp++; size--; } while (zeropad > 0 && size > 1) { *str++ = '0'; size--; zeropad--; } } while (*cp != '\0' && size > 1) { *str++ = *cp++; size--; } while (pad > 0 && size > 1) { *str++ = ' '; size--; pad--; } break; case 'D': /*deprecated*/ INSIST("use %ld instead of %D" == NULL); case 'O': /*deprecated*/ INSIST("use %lo instead of %O" == NULL); case 'U': /*deprecated*/ INSIST("use %lu instead of %U" == NULL); case 'L': #ifdef HAVE_LONG_DOUBLE l = 1; #else INSIST("long doubles are not supported" == NULL); #endif /*FALLTHROUGH*/ case 'e': case 'E': case 'f': case 'g': case 'G': if (!dot) precision = 6; /* * IEEE floating point. * MIN 2.2250738585072014E-308 * MAX 1.7976931348623157E+308 * VAX floating point has a smaller range than IEEE. * * precisions > 324 don't make much sense. * if we cap the precision at 512 we will not * overflow buf. */ if (precision > 512) precision = 512; sprintf(fmt, "%%%s%s.%lu%s%c", alt ? "#" : "", plus ? "+" : space ? " " : "", precision, l ? "L" : "", *format); switch (*format) { case 'e': case 'E': case 'f': case 'g': case 'G': #ifdef HAVE_LONG_DOUBLE if (l) { ldbl = va_arg(ap, long double); sprintf(buf, fmt, ldbl); } else #endif { dbl = va_arg(ap, double); sprintf(buf, fmt, dbl); } length = strlen(buf); if (width > 0) { pad = width - length; if (pad < 0) pad = 0; } count += length + pad; if (!left) while (pad > 0 && size > 1) { *str++ = ' '; size--; pad--; } cp = buf; while (*cp != ' ' && size > 1) { *str++ = *cp++; size--; } while (pad > 0 && size > 1) { *str++ = ' '; size--; pad--; } break; default: continue; } break; default: continue; } format++; } if (size > 0) *str = '\0'; return (count); } #endif dhcp-4.2.4/omapip/listener.c000644 000765 000024 00000031667 11726364513 015672 0ustar00sarstaff000000 000000 /* listener.c Subroutines that support the generic listener object. */ /* * Copyright (c) 2012 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 2004,2007,2009 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1999-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ * * This software has been written for Internet Systems Consortium * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. * To learn more about Internet Systems Consortium, see * ``https://www.isc.org/''. To learn more about Vixie Enterprises, * see ``http://www.vix.com''. To learn more about Nominum, Inc., see * ``http://www.nominum.com''. */ #include "dhcpd.h" #include #include #if defined (TRACING) omapi_array_t *trace_listeners; static void trace_listener_accept_input (trace_type_t *, unsigned, char *); static void trace_listener_remember (omapi_listener_object_t *, const char *, int); static void trace_listener_accept_stop (trace_type_t *); trace_type_t *trace_listener_accept; #endif OMAPI_OBJECT_ALLOC (omapi_listener, omapi_listener_object_t, omapi_type_listener) isc_result_t omapi_listen (omapi_object_t *h, unsigned port, int max) { omapi_addr_t addr; #ifdef DEBUG_PROTOCOL log_debug ("omapi_listen(port=%d, max=%d)", port, max); #endif addr.addrtype = AF_INET; addr.addrlen = sizeof (struct in_addr); memset (addr.address, 0, sizeof addr.address); /* INADDR_ANY */ addr.port = port; return omapi_listen_addr (h, &addr, max); } isc_result_t omapi_listen_addr (omapi_object_t *h, omapi_addr_t *addr, int max) { isc_result_t status; omapi_listener_object_t *obj; int i; /* Currently only support IPv4 addresses. */ if (addr->addrtype != AF_INET) return DHCP_R_INVALIDARG; /* Get the handle. */ obj = (omapi_listener_object_t *)0; status = omapi_listener_allocate (&obj, MDL); if (status != ISC_R_SUCCESS) return status; obj->socket = -1; /* Connect this object to the inner object. */ status = omapi_object_reference (&h -> outer, (omapi_object_t *)obj, MDL); if (status != ISC_R_SUCCESS) goto error_exit; status = omapi_object_reference (&obj -> inner, h, MDL); if (status != ISC_R_SUCCESS) goto error_exit; /* Set up the address on which we will listen... */ obj -> address.sin_port = htons (addr -> port); memcpy (&obj -> address.sin_addr, addr -> address, sizeof obj -> address.sin_addr); #if defined (HAVE_SA_LEN) obj -> address.sin_len = sizeof (struct sockaddr_in); #endif obj -> address.sin_family = AF_INET; memset (&(obj -> address.sin_zero), 0, sizeof obj -> address.sin_zero); #if defined (TRACING) /* If we're playing back a trace file, we remember the object on the trace listener queue. */ if (trace_playback ()) { trace_listener_remember (obj, MDL); } else { #endif /* Create a socket on which to listen. */ obj -> socket = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP); if (obj->socket == -1) { if (errno == EMFILE || errno == ENFILE || errno == ENOBUFS) status = ISC_R_NORESOURCES; else status = ISC_R_UNEXPECTED; goto error_exit; } #if defined (HAVE_SETFD) if (fcntl (obj -> socket, F_SETFD, 1) < 0) { status = ISC_R_UNEXPECTED; goto error_exit; } #endif /* Set the REUSEADDR option so that we don't fail to start if we're being restarted. */ i = 1; if (setsockopt (obj -> socket, SOL_SOCKET, SO_REUSEADDR, (char *)&i, sizeof i) < 0) { status = ISC_R_UNEXPECTED; goto error_exit; } /* Try to bind to the wildcard address using the port number we were given. */ i = bind (obj -> socket, (struct sockaddr *)&obj -> address, sizeof obj -> address); if (i < 0) { if (errno == EADDRINUSE) status = ISC_R_ADDRNOTAVAIL; else if (errno == EPERM) status = ISC_R_NOPERM; else status = ISC_R_UNEXPECTED; goto error_exit; } /* Now tell the kernel to listen for connections. */ if (listen (obj -> socket, max)) { status = ISC_R_UNEXPECTED; goto error_exit; } if (fcntl (obj -> socket, F_SETFL, O_NONBLOCK) < 0) { status = ISC_R_UNEXPECTED; goto error_exit; } status = omapi_register_io_object ((omapi_object_t *)obj, omapi_listener_readfd, 0, omapi_accept, 0, 0); #if defined (TRACING) } #endif omapi_listener_dereference (&obj, MDL); return status; error_exit: if (obj != NULL) { if (h->outer == (omapi_object_t *)obj) { omapi_object_dereference((omapi_object_t **)&h->outer, MDL); } if (obj->inner == h) { omapi_object_dereference((omapi_object_t **)&obj->inner, MDL); } if (obj->socket != -1) { close(obj->socket); } omapi_listener_dereference(&obj, MDL); } return status; } /* Return the socket on which the dispatcher should wait for readiness to read, for a listener object. */ int omapi_listener_readfd (omapi_object_t *h) { omapi_listener_object_t *l; if (h -> type != omapi_type_listener) return -1; l = (omapi_listener_object_t *)h; return l -> socket; } /* Reader callback for a listener object. Accept an incoming connection. */ isc_result_t omapi_accept (omapi_object_t *h) { isc_result_t status; socklen_t len; omapi_connection_object_t *obj; omapi_listener_object_t *listener; struct sockaddr_in addr; int socket; if (h -> type != omapi_type_listener) return DHCP_R_INVALIDARG; listener = (omapi_listener_object_t *)h; /* Accept the connection. */ len = sizeof addr; socket = accept (listener -> socket, ((struct sockaddr *)&(addr)), &len); if (socket < 0) { if (errno == EMFILE || errno == ENFILE || errno == ENOBUFS) return ISC_R_NORESOURCES; return ISC_R_UNEXPECTED; } #if defined (TRACING) /* If we're recording a trace, remember the connection. */ if (trace_record ()) { trace_iov_t iov [3]; iov [0].buf = (char *)&addr.sin_port; iov [0].len = sizeof addr.sin_port; iov [1].buf = (char *)&addr.sin_addr; iov [1].len = sizeof addr.sin_addr; iov [2].buf = (char *)&listener -> address.sin_port; iov [2].len = sizeof listener -> address.sin_port; trace_write_packet_iov (trace_listener_accept, 3, iov, MDL); } #endif obj = (omapi_connection_object_t *)0; status = omapi_listener_connect (&obj, listener, socket, &addr); if (status != ISC_R_SUCCESS) { close (socket); return status; } status = omapi_register_io_object ((omapi_object_t *)obj, omapi_connection_readfd, omapi_connection_writefd, omapi_connection_reader, omapi_connection_writer, omapi_connection_reaper); /* Lose our reference to the connection, so it'll be gc'd when it's reaped. */ omapi_connection_dereference (&obj, MDL); if (status != ISC_R_SUCCESS) omapi_disconnect ((omapi_object_t *)(obj), 1); return status; } isc_result_t omapi_listener_connect (omapi_connection_object_t **obj, omapi_listener_object_t *listener, int socket, struct sockaddr_in *remote_addr) { isc_result_t status; omapi_object_t *h = (omapi_object_t *)listener; omapi_addr_t addr; #ifdef DEBUG_PROTOCOL log_debug ("omapi_accept()"); #endif /* Get the handle. */ status = omapi_connection_allocate (obj, MDL); if (status != ISC_R_SUCCESS) return status; (*obj) -> state = omapi_connection_connected; (*obj) -> remote_addr = *remote_addr; (*obj) -> socket = socket; /* Verify that this host is allowed to connect. */ if (listener -> verify_addr) { addr.addrtype = AF_INET; addr.addrlen = sizeof (remote_addr -> sin_addr); memcpy (addr.address, &remote_addr -> sin_addr, sizeof (remote_addr -> sin_addr)); addr.port = ntohs(remote_addr -> sin_port); status = (listener -> verify_addr) (h, &addr); if (status != ISC_R_SUCCESS) { omapi_disconnect ((omapi_object_t *)(*obj), 1); omapi_connection_dereference (obj, MDL); return status; } } omapi_listener_reference (&(*obj) -> listener, listener, MDL); #if defined (TRACING) omapi_connection_register (*obj, MDL); #endif status = omapi_signal (h, "connect", (*obj)); return status; } #if defined (TRACING) OMAPI_ARRAY_TYPE(omapi_listener, omapi_listener_object_t) void omapi_listener_trace_setup (void) { trace_listener_accept = trace_type_register ("listener-accept", (void *)0, trace_listener_accept_input, trace_listener_accept_stop, MDL); } static void trace_listener_remember (omapi_listener_object_t *obj, const char *file, int line) { isc_result_t status; if (!trace_listeners) { status = omapi_listener_array_allocate (&trace_listeners, file, line); if (status != ISC_R_SUCCESS) { foo: log_error ("trace_listener_remember: %s", isc_result_totext (status)); return; } } status = omapi_listener_array_extend (trace_listeners, obj, &obj -> index, MDL); if (status != ISC_R_SUCCESS) goto foo; } static void trace_listener_accept_input (trace_type_t *ttype, unsigned length, char *buf) { struct in_addr *addr; u_int16_t *remote_port; u_int16_t *local_port; omapi_connection_object_t *obj; isc_result_t status; struct sockaddr_in remote_addr; addr = (struct in_addr *)buf; remote_port = (u_int16_t *)(addr + 1); local_port = remote_port + 1; memset (&remote_addr, 0, sizeof remote_addr); remote_addr.sin_addr = *addr; remote_addr.sin_port = *remote_port; omapi_array_foreach_begin (trace_listeners, omapi_listener_object_t, lp) { if (lp -> address.sin_port == *local_port) { obj = (omapi_connection_object_t *)0; status = omapi_listener_connect (&obj, lp, 0, &remote_addr); if (status != ISC_R_SUCCESS) { log_error("%s:%d: OMAPI: Failed to connect " "a listener.", MDL); } omapi_listener_dereference (&lp, MDL); return; } } omapi_array_foreach_end (trace_listeners, omapi_listener_object_t, lp); log_error ("trace_listener_accept: %s from %s/%d to port %d", "unexpected connect", inet_ntoa (*addr), *remote_port, *local_port); } static void trace_listener_accept_stop (trace_type_t *ttype) { } #endif isc_result_t omapi_listener_configure_security (omapi_object_t *h, isc_result_t (*verify_addr) (omapi_object_t *, omapi_addr_t *)) { omapi_listener_object_t *l; if (h -> type != omapi_type_listener) return DHCP_R_INVALIDARG; l = (omapi_listener_object_t *)h; l -> verify_addr = verify_addr; return ISC_R_SUCCESS; } isc_result_t omapi_listener_set_value (omapi_object_t *h, omapi_object_t *id, omapi_data_string_t *name, omapi_typed_data_t *value) { if (h -> type != omapi_type_listener) return DHCP_R_INVALIDARG; if (h -> inner && h -> inner -> type -> set_value) return (*(h -> inner -> type -> set_value)) (h -> inner, id, name, value); return ISC_R_NOTFOUND; } isc_result_t omapi_listener_get_value (omapi_object_t *h, omapi_object_t *id, omapi_data_string_t *name, omapi_value_t **value) { if (h -> type != omapi_type_listener) return DHCP_R_INVALIDARG; if (h -> inner && h -> inner -> type -> get_value) return (*(h -> inner -> type -> get_value)) (h -> inner, id, name, value); return ISC_R_NOTFOUND; } isc_result_t omapi_listener_destroy (omapi_object_t *h, const char *file, int line) { omapi_listener_object_t *l; if (h -> type != omapi_type_listener) return DHCP_R_INVALIDARG; l = (omapi_listener_object_t *)h; #ifdef DEBUG_PROTOCOL log_debug ("omapi_listener_destroy()"); #endif if (l -> socket != -1) { close (l -> socket); l -> socket = -1; } return ISC_R_SUCCESS; } isc_result_t omapi_listener_signal_handler (omapi_object_t *h, const char *name, va_list ap) { if (h -> type != omapi_type_listener) return DHCP_R_INVALIDARG; if (h -> inner && h -> inner -> type -> signal_handler) return (*(h -> inner -> type -> signal_handler)) (h -> inner, name, ap); return ISC_R_NOTFOUND; } /* Write all the published values associated with the object through the specified connection. */ isc_result_t omapi_listener_stuff_values (omapi_object_t *c, omapi_object_t *id, omapi_object_t *l) { if (l -> type != omapi_type_listener) return DHCP_R_INVALIDARG; if (l -> inner && l -> inner -> type -> stuff_values) return (*(l -> inner -> type -> stuff_values)) (c, id, l -> inner); return ISC_R_SUCCESS; } dhcp-4.2.4/omapip/Makefile.am000644 000765 000024 00000000671 11335116502 015711 0ustar00sarstaff000000 000000 lib_LIBRARIES = libomapi.a noinst_PROGRAMS = svtest libomapi_a_SOURCES = protocol.c buffer.c alloc.c result.c connection.c \ errwarn.c listener.c dispatch.c generic.c support.c \ handle.c message.c convert.c hash.c auth.c inet_addr.c \ array.c trace.c toisc.c iscprint.c isclib.c man_MANS = omapi.3 EXTRA_DIST = $(man_MANS) svtest_SOURCES = test.c svtest_LDADD = libomapi.a ../bind/lib/libdns.a ../bind/lib/libisc.a dhcp-4.2.4/omapip/Makefile.in000644 000765 000024 00000042301 11757500142 015723 0ustar00sarstaff000000 000000 # Makefile.in generated by automake 1.10.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : noinst_PROGRAMS = svtest$(EXEEXT) subdir = omapip DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/includes/config.h CONFIG_CLEAN_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = `echo $$p | sed -e 's|^.*/||'`; am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(man3dir)" libLIBRARIES_INSTALL = $(INSTALL_DATA) LIBRARIES = $(lib_LIBRARIES) AR = ar ARFLAGS = cru libomapi_a_AR = $(AR) $(ARFLAGS) libomapi_a_LIBADD = am_libomapi_a_OBJECTS = protocol.$(OBJEXT) buffer.$(OBJEXT) \ alloc.$(OBJEXT) result.$(OBJEXT) connection.$(OBJEXT) \ errwarn.$(OBJEXT) listener.$(OBJEXT) dispatch.$(OBJEXT) \ generic.$(OBJEXT) support.$(OBJEXT) handle.$(OBJEXT) \ message.$(OBJEXT) convert.$(OBJEXT) hash.$(OBJEXT) \ auth.$(OBJEXT) inet_addr.$(OBJEXT) array.$(OBJEXT) \ trace.$(OBJEXT) toisc.$(OBJEXT) iscprint.$(OBJEXT) \ isclib.$(OBJEXT) libomapi_a_OBJECTS = $(am_libomapi_a_OBJECTS) PROGRAMS = $(noinst_PROGRAMS) am_svtest_OBJECTS = test.$(OBJEXT) svtest_OBJECTS = $(am_svtest_OBJECTS) svtest_DEPENDENCIES = libomapi.a ../bind/lib/libdns.a \ ../bind/lib/libisc.a DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/includes depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) CCLD = $(CC) LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ SOURCES = $(libomapi_a_SOURCES) $(svtest_SOURCES) DIST_SOURCES = $(libomapi_a_SOURCES) $(svtest_SOURCES) man3dir = $(mandir)/man3 NROFF = nroff MANS = $(man_MANS) ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ GREP = @GREP@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDAP_CFLAGS = @LDAP_CFLAGS@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_prefix_program = @ac_prefix_program@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build_alias = @build_alias@ builddir = @builddir@ byte_order = @byte_order@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host_alias = @host_alias@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ lib_LIBRARIES = libomapi.a libomapi_a_SOURCES = protocol.c buffer.c alloc.c result.c connection.c \ errwarn.c listener.c dispatch.c generic.c support.c \ handle.c message.c convert.c hash.c auth.c inet_addr.c \ array.c trace.c toisc.c iscprint.c isclib.c man_MANS = omapi.3 EXTRA_DIST = $(man_MANS) svtest_SOURCES = test.c svtest_LDADD = libomapi.a ../bind/lib/libdns.a ../bind/lib/libisc.a all: all-am .SUFFIXES: .SUFFIXES: .c .o .obj $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ && exit 0; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign omapip/Makefile'; \ cd $(top_srcdir) && \ $(AUTOMAKE) --foreign omapip/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh install-libLIBRARIES: $(lib_LIBRARIES) @$(NORMAL_INSTALL) test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" @list='$(lib_LIBRARIES)'; for p in $$list; do \ if test -f $$p; then \ f=$(am__strip_dir) \ echo " $(libLIBRARIES_INSTALL) '$$p' '$(DESTDIR)$(libdir)/$$f'"; \ $(libLIBRARIES_INSTALL) "$$p" "$(DESTDIR)$(libdir)/$$f"; \ else :; fi; \ done @$(POST_INSTALL) @list='$(lib_LIBRARIES)'; for p in $$list; do \ if test -f $$p; then \ p=$(am__strip_dir) \ echo " $(RANLIB) '$(DESTDIR)$(libdir)/$$p'"; \ $(RANLIB) "$(DESTDIR)$(libdir)/$$p"; \ else :; fi; \ done uninstall-libLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(lib_LIBRARIES)'; for p in $$list; do \ p=$(am__strip_dir) \ echo " rm -f '$(DESTDIR)$(libdir)/$$p'"; \ rm -f "$(DESTDIR)$(libdir)/$$p"; \ done clean-libLIBRARIES: -test -z "$(lib_LIBRARIES)" || rm -f $(lib_LIBRARIES) libomapi.a: $(libomapi_a_OBJECTS) $(libomapi_a_DEPENDENCIES) -rm -f libomapi.a $(libomapi_a_AR) libomapi.a $(libomapi_a_OBJECTS) $(libomapi_a_LIBADD) $(RANLIB) libomapi.a clean-noinstPROGRAMS: -test -z "$(noinst_PROGRAMS)" || rm -f $(noinst_PROGRAMS) svtest$(EXEEXT): $(svtest_OBJECTS) $(svtest_DEPENDENCIES) @rm -f svtest$(EXEEXT) $(LINK) $(svtest_OBJECTS) $(svtest_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/alloc.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/array.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/auth.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/buffer.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/connection.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/convert.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dispatch.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/errwarn.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/generic.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/handle.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hash.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/inet_addr.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isclib.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/iscprint.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/listener.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/message.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/protocol.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/result.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/support.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/toisc.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/trace.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` install-man3: $(man3_MANS) $(man_MANS) @$(NORMAL_INSTALL) test -z "$(man3dir)" || $(MKDIR_P) "$(DESTDIR)$(man3dir)" @list='$(man3_MANS) $(dist_man3_MANS) $(nodist_man3_MANS)'; \ l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ for i in $$l2; do \ case "$$i" in \ *.3*) list="$$list $$i" ;; \ esac; \ done; \ for i in $$list; do \ if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \ else file=$$i; fi; \ ext=`echo $$i | sed -e 's/^.*\\.//'`; \ case "$$ext" in \ 3*) ;; \ *) ext='3' ;; \ esac; \ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ inst=`echo $$inst | sed -e 's/^.*\///'`; \ inst=`echo $$inst | sed '$(transform)'`.$$ext; \ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man3dir)/$$inst'"; \ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man3dir)/$$inst"; \ done uninstall-man3: @$(NORMAL_UNINSTALL) @list='$(man3_MANS) $(dist_man3_MANS) $(nodist_man3_MANS)'; \ l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ for i in $$l2; do \ case "$$i" in \ *.3*) list="$$list $$i" ;; \ esac; \ done; \ for i in $$list; do \ ext=`echo $$i | sed -e 's/^.*\\.//'`; \ case "$$ext" in \ 3*) ;; \ *) ext='3' ;; \ esac; \ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ inst=`echo $$inst | sed -e 's/^.*\///'`; \ inst=`echo $$inst | sed '$(transform)'`.$$ext; \ echo " rm -f '$(DESTDIR)$(man3dir)/$$inst'"; \ rm -f "$(DESTDIR)$(man3dir)/$$inst"; \ done ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) tags=; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$tags $$unique; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) tags=; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$tags$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$tags $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && cd $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) $$here distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ fi; \ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ else \ test -f $(distdir)/$$file \ || cp -p $$d/$$file $(distdir)/$$file \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(LIBRARIES) $(PROGRAMS) $(MANS) installdirs: for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(man3dir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libLIBRARIES clean-noinstPROGRAMS \ mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am info: info-am info-am: install-data-am: install-man install-dvi: install-dvi-am install-exec-am: install-libLIBRARIES install-html: install-html-am install-info: install-info-am install-man: install-man3 install-pdf: install-pdf-am install-ps: install-ps-am installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-libLIBRARIES uninstall-man uninstall-man: uninstall-man3 .MAKE: install-am install-strip .PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ clean-libLIBRARIES clean-noinstPROGRAMS ctags distclean \ distclean-compile distclean-generic distclean-tags distdir dvi \ dvi-am html html-am info info-am install install-am \ install-data install-data-am install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-info install-info-am install-libLIBRARIES install-man \ install-man3 install-pdf install-pdf-am install-ps \ install-ps-am install-strip installcheck installcheck-am \ installdirs maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-compile mostlyclean-generic pdf pdf-am \ ps ps-am tags uninstall uninstall-am uninstall-libLIBRARIES \ uninstall-man uninstall-man3 # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: dhcp-4.2.4/omapip/message.c000644 000765 000024 00000055441 11301372616 015455 0ustar00sarstaff000000 000000 /* message.c Subroutines for dealing with message objects. */ /* * Copyright (c) 2004,2007,2009 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1999-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ * * This software has been written for Internet Systems Consortium * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. * To learn more about Internet Systems Consortium, see * ``https://www.isc.org/''. To learn more about Vixie Enterprises, * see ``http://www.vix.com''. To learn more about Nominum, Inc., see * ``http://www.nominum.com''. */ #include "dhcpd.h" #include OMAPI_OBJECT_ALLOC (omapi_message, omapi_message_object_t, omapi_type_message) omapi_message_object_t *omapi_registered_messages; isc_result_t omapi_message_new (omapi_object_t **o, const char *file, int line) { omapi_message_object_t *m; omapi_object_t *g; isc_result_t status; m = (omapi_message_object_t *)0; status = omapi_message_allocate (&m, file, line); if (status != ISC_R_SUCCESS) return status; g = (omapi_object_t *)0; status = omapi_generic_new (&g, file, line); if (status != ISC_R_SUCCESS) { dfree (m, file, line); return status; } status = omapi_object_reference (&m -> inner, g, file, line); if (status != ISC_R_SUCCESS) { omapi_object_dereference ((omapi_object_t **)&m, file, line); omapi_object_dereference (&g, file, line); return status; } status = omapi_object_reference (&g -> outer, (omapi_object_t *)m, file, line); if (status != ISC_R_SUCCESS) { omapi_object_dereference ((omapi_object_t **)&m, file, line); omapi_object_dereference (&g, file, line); return status; } status = omapi_object_reference (o, (omapi_object_t *)m, file, line); omapi_message_dereference (&m, file, line); omapi_object_dereference (&g, file, line); if (status != ISC_R_SUCCESS) return status; return status; } isc_result_t omapi_message_set_value (omapi_object_t *h, omapi_object_t *id, omapi_data_string_t *name, omapi_typed_data_t *value) { omapi_message_object_t *m; isc_result_t status; if (h -> type != omapi_type_message) return DHCP_R_INVALIDARG; m = (omapi_message_object_t *)h; /* Can't set authlen. */ /* Can set authenticator, but the value must be typed data. */ if (!omapi_ds_strcmp (name, "authenticator")) { if (m -> authenticator) omapi_typed_data_dereference (&m -> authenticator, MDL); omapi_typed_data_reference (&m -> authenticator, value, MDL); return ISC_R_SUCCESS; } else if (!omapi_ds_strcmp (name, "object")) { if (value -> type != omapi_datatype_object) return DHCP_R_INVALIDARG; if (m -> object) omapi_object_dereference (&m -> object, MDL); omapi_object_reference (&m -> object, value -> u.object, MDL); return ISC_R_SUCCESS; } else if (!omapi_ds_strcmp (name, "notify-object")) { if (value -> type != omapi_datatype_object) return DHCP_R_INVALIDARG; if (m -> notify_object) omapi_object_dereference (&m -> notify_object, MDL); omapi_object_reference (&m -> notify_object, value -> u.object, MDL); return ISC_R_SUCCESS; /* Can set authid, but it has to be an integer. */ } else if (!omapi_ds_strcmp (name, "authid")) { if (value -> type != omapi_datatype_int) return DHCP_R_INVALIDARG; m -> authid = value -> u.integer; return ISC_R_SUCCESS; /* Can set op, but it has to be an integer. */ } else if (!omapi_ds_strcmp (name, "op")) { if (value -> type != omapi_datatype_int) return DHCP_R_INVALIDARG; m -> op = value -> u.integer; return ISC_R_SUCCESS; /* Handle also has to be an integer. */ } else if (!omapi_ds_strcmp (name, "handle")) { if (value -> type != omapi_datatype_int) return DHCP_R_INVALIDARG; m -> h = value -> u.integer; return ISC_R_SUCCESS; /* Transaction ID has to be an integer. */ } else if (!omapi_ds_strcmp (name, "id")) { if (value -> type != omapi_datatype_int) return DHCP_R_INVALIDARG; m -> id = value -> u.integer; return ISC_R_SUCCESS; /* Remote transaction ID has to be an integer. */ } else if (!omapi_ds_strcmp (name, "rid")) { if (value -> type != omapi_datatype_int) return DHCP_R_INVALIDARG; m -> rid = value -> u.integer; return ISC_R_SUCCESS; } /* Try to find some inner object that can take the value. */ if (h -> inner && h -> inner -> type -> set_value) { status = ((*(h -> inner -> type -> set_value)) (h -> inner, id, name, value)); if (status == ISC_R_SUCCESS) return status; } return ISC_R_NOTFOUND; } isc_result_t omapi_message_get_value (omapi_object_t *h, omapi_object_t *id, omapi_data_string_t *name, omapi_value_t **value) { omapi_message_object_t *m; if (h -> type != omapi_type_message) return DHCP_R_INVALIDARG; m = (omapi_message_object_t *)h; /* Look for values that are in the message data structure. */ if (!omapi_ds_strcmp (name, "authlen")) return omapi_make_int_value (value, name, (int)m -> authlen, MDL); else if (!omapi_ds_strcmp (name, "authenticator")) { if (m -> authenticator) return omapi_make_value (value, name, m -> authenticator, MDL); else return ISC_R_NOTFOUND; } else if (!omapi_ds_strcmp (name, "authid")) { return omapi_make_int_value (value, name, (int)m -> authid, MDL); } else if (!omapi_ds_strcmp (name, "op")) { return omapi_make_int_value (value, name, (int)m -> op, MDL); } else if (!omapi_ds_strcmp (name, "handle")) { return omapi_make_int_value (value, name, (int)m -> h, MDL); } else if (!omapi_ds_strcmp (name, "id")) { return omapi_make_int_value (value, name, (int)m -> id, MDL); } else if (!omapi_ds_strcmp (name, "rid")) { return omapi_make_int_value (value, name, (int)m -> rid, MDL); } /* See if there's an inner object that has the value. */ if (h -> inner && h -> inner -> type -> get_value) return (*(h -> inner -> type -> get_value)) (h -> inner, id, name, value); return ISC_R_NOTFOUND; } isc_result_t omapi_message_destroy (omapi_object_t *h, const char *file, int line) { omapi_message_object_t *m; if (h -> type != omapi_type_message) return DHCP_R_INVALIDARG; m = (omapi_message_object_t *)h; if (m -> authenticator) { omapi_typed_data_dereference (&m -> authenticator, file, line); } if (!m -> prev && omapi_registered_messages != m) omapi_message_unregister (h); if (m -> id_object) omapi_object_dereference (&m -> id_object, file, line); if (m -> object) omapi_object_dereference (&m -> object, file, line); if (m -> notify_object) omapi_object_dereference (&m -> notify_object, file, line); if (m -> protocol_object) omapi_protocol_dereference (&m -> protocol_object, file, line); return ISC_R_SUCCESS; } isc_result_t omapi_message_signal_handler (omapi_object_t *h, const char *name, va_list ap) { omapi_message_object_t *m; if (h -> type != omapi_type_message) return DHCP_R_INVALIDARG; m = (omapi_message_object_t *)h; if (!strcmp (name, "status")) { if (m -> notify_object && m -> notify_object -> type -> signal_handler) return ((m -> notify_object -> type -> signal_handler)) (m -> notify_object, name, ap); else if (m -> object && m -> object -> type -> signal_handler) return ((m -> object -> type -> signal_handler)) (m -> object, name, ap); } if (h -> inner && h -> inner -> type -> signal_handler) return (*(h -> inner -> type -> signal_handler)) (h -> inner, name, ap); return ISC_R_NOTFOUND; } /* Write all the published values associated with the object through the specified connection. */ isc_result_t omapi_message_stuff_values (omapi_object_t *c, omapi_object_t *id, omapi_object_t *m) { if (m -> type != omapi_type_message) return DHCP_R_INVALIDARG; if (m -> inner && m -> inner -> type -> stuff_values) return (*(m -> inner -> type -> stuff_values)) (c, id, m -> inner); return ISC_R_SUCCESS; } isc_result_t omapi_message_register (omapi_object_t *mo) { omapi_message_object_t *m; if (mo -> type != omapi_type_message) return DHCP_R_INVALIDARG; m = (omapi_message_object_t *)mo; /* Already registered? */ if (m -> prev || m -> next || omapi_registered_messages == m) return DHCP_R_INVALIDARG; if (omapi_registered_messages) { omapi_object_reference ((omapi_object_t **)&m -> next, (omapi_object_t *)omapi_registered_messages, MDL); omapi_object_reference ((omapi_object_t **)&omapi_registered_messages -> prev, (omapi_object_t *)m, MDL); omapi_object_dereference ((omapi_object_t **)&omapi_registered_messages, MDL); } omapi_object_reference ((omapi_object_t **)&omapi_registered_messages, (omapi_object_t *)m, MDL); return ISC_R_SUCCESS;; } isc_result_t omapi_message_unregister (omapi_object_t *mo) { omapi_message_object_t *m; omapi_message_object_t *n; if (mo -> type != omapi_type_message) return DHCP_R_INVALIDARG; m = (omapi_message_object_t *)mo; /* Not registered? */ if (!m -> prev && omapi_registered_messages != m) return DHCP_R_INVALIDARG; n = (omapi_message_object_t *)0; if (m -> next) { omapi_object_reference ((omapi_object_t **)&n, (omapi_object_t *)m -> next, MDL); omapi_object_dereference ((omapi_object_t **)&m -> next, MDL); omapi_object_dereference ((omapi_object_t **)&n -> prev, MDL); } if (m -> prev) { omapi_message_object_t *tmp = (omapi_message_object_t *)0; omapi_object_reference ((omapi_object_t **)&tmp, (omapi_object_t *)m -> prev, MDL); omapi_object_dereference ((omapi_object_t **)&m -> prev, MDL); if (tmp -> next) omapi_object_dereference ((omapi_object_t **)&tmp -> next, MDL); if (n) omapi_object_reference ((omapi_object_t **)&tmp -> next, (omapi_object_t *)n, MDL); omapi_object_dereference ((omapi_object_t **)&tmp, MDL); } else { omapi_object_dereference ((omapi_object_t **)&omapi_registered_messages, MDL); if (n) omapi_object_reference ((omapi_object_t **)&omapi_registered_messages, (omapi_object_t *)n, MDL); } if (n) omapi_object_dereference ((omapi_object_t **)&n, MDL); return ISC_R_SUCCESS; } #ifdef DEBUG_PROTOCOL static const char *omapi_message_op_name(int op) { switch (op) { case OMAPI_OP_OPEN: return "OMAPI_OP_OPEN"; case OMAPI_OP_REFRESH: return "OMAPI_OP_REFRESH"; case OMAPI_OP_UPDATE: return "OMAPI_OP_UPDATE"; case OMAPI_OP_STATUS: return "OMAPI_OP_STATUS"; case OMAPI_OP_DELETE: return "OMAPI_OP_DELETE"; case OMAPI_OP_NOTIFY: return "OMAPI_OP_NOTIFY"; default: return "(unknown op)"; } } #endif static isc_result_t omapi_message_process_internal (omapi_object_t *, omapi_object_t *); isc_result_t omapi_message_process (omapi_object_t *mo, omapi_object_t *po) { isc_result_t status; #if defined (DEBUG_MEMORY_LEAKAGE) && 0 unsigned long previous_outstanding = dmalloc_outstanding; #endif status = omapi_message_process_internal (mo, po); #if defined (DEBUG_MEMORY_LEAKAGE) && 0 log_info ("generation %ld: %ld new, %ld outstanding, %ld long-term", dmalloc_generation, dmalloc_outstanding - previous_outstanding, dmalloc_outstanding, dmalloc_longterm); #endif #if defined (DEBUG_MEMORY_LEAKAGE) && 0 dmalloc_dump_outstanding (); #endif #if defined (DEBUG_RC_HISTORY_EXHAUSTIVELY) && 0 dump_rc_history (); #endif return status; } static isc_result_t omapi_message_process_internal (omapi_object_t *mo, omapi_object_t *po) { omapi_message_object_t *message, *m; omapi_object_t *object = (omapi_object_t *)0; omapi_value_t *tv = (omapi_value_t *)0; unsigned long create, update, exclusive; unsigned long wsi; isc_result_t status, waitstatus; omapi_object_type_t *type; if (mo -> type != omapi_type_message) return DHCP_R_INVALIDARG; message = (omapi_message_object_t *)mo; #ifdef DEBUG_PROTOCOL log_debug ("omapi_message_process(): " "op=%s handle=%#x id=%#x rid=%#x", omapi_message_op_name (message -> op), message -> h, message -> id, message -> rid); #endif if (message -> rid) { for (m = omapi_registered_messages; m; m = m -> next) if (m -> id == message -> rid) break; /* If we don't have a real message corresponding to the message ID to which this message claims it is a response, something's fishy. */ if (!m) return ISC_R_NOTFOUND; /* The authenticator on responses must match the initial message. */ if (message -> authid != m -> authid) return ISC_R_NOTFOUND; } else { m = (omapi_message_object_t *)0; /* All messages must have an authenticator, with the exception of messages that are opening a new authenticator. */ if (omapi_protocol_authenticated(po) && !message->id_object && message->op != OMAPI_OP_OPEN) { return omapi_protocol_send_status (po, message->id_object, DHCP_R_NOKEYS, message->id, "No authenticator on message"); } } switch (message -> op) { case OMAPI_OP_OPEN: if (m) { return omapi_protocol_send_status (po, message->id_object, DHCP_R_INVALIDARG, message->id, "OPEN can't be a response"); } /* Get the type of the requested object, if one was specified. */ status = omapi_get_value_str (mo, message -> id_object, "type", &tv); if (status == ISC_R_SUCCESS && (tv -> value -> type == omapi_datatype_data || tv -> value -> type == omapi_datatype_string)) { for (type = omapi_object_types; type; type = type -> next) if (!omapi_td_strcmp (tv -> value, type -> name)) break; } else type = (omapi_object_type_t *)0; if (tv) omapi_value_dereference (&tv, MDL); /* If this object had no authenticator, the requested object must be an authenticator object. */ if (omapi_protocol_authenticated(po) && !message->id_object && type != omapi_type_auth_key) { return omapi_protocol_send_status (po, message->id_object, DHCP_R_NOKEYS, message->id, "No authenticator on message"); } /* Get the create flag. */ status = omapi_get_value_str (mo, message -> id_object, "create", &tv); if (status == ISC_R_SUCCESS) { status = omapi_get_int_value (&create, tv -> value); omapi_value_dereference (&tv, MDL); if (status != ISC_R_SUCCESS) { return omapi_protocol_send_status (po, message -> id_object, status, message -> id, "invalid create flag value"); } } else create = 0; /* Get the update flag. */ status = omapi_get_value_str (mo, message -> id_object, "update", &tv); if (status == ISC_R_SUCCESS) { status = omapi_get_int_value (&update, tv -> value); omapi_value_dereference (&tv, MDL); if (status != ISC_R_SUCCESS) { return omapi_protocol_send_status (po, message -> id_object, status, message -> id, "invalid update flag value"); } } else update = 0; /* Get the exclusive flag. */ status = omapi_get_value_str (mo, message -> id_object, "exclusive", &tv); if (status == ISC_R_SUCCESS) { status = omapi_get_int_value (&exclusive, tv -> value); omapi_value_dereference (&tv, MDL); if (status != ISC_R_SUCCESS) { return omapi_protocol_send_status (po, message -> id_object, status, message -> id, "invalid exclusive flag value"); } } else exclusive = 0; /* If we weren't given a type, look the object up with the handle. */ if (!type) { if (create) { return omapi_protocol_send_status (po, message->id_object, DHCP_R_INVALIDARG, message->id, "type required on create"); } goto refresh; } /* If the type doesn't provide a lookup method, we can't look up the object. */ if (!type -> lookup) { return omapi_protocol_send_status (po, message -> id_object, ISC_R_NOTIMPLEMENTED, message -> id, "unsearchable object type"); } status = (*(type -> lookup)) (&object, message -> id_object, message -> object); if (status != ISC_R_SUCCESS && status != ISC_R_NOTFOUND && status != DHCP_R_NOKEYS) { return omapi_protocol_send_status (po, message -> id_object, status, message -> id, "object lookup failed"); } /* If we didn't find the object and we aren't supposed to create it, return an error. */ if (status == ISC_R_NOTFOUND && !create) { return omapi_protocol_send_status (po, message -> id_object, ISC_R_NOTFOUND, message -> id, "no object matches specification"); } /* If we found an object, we're supposed to be creating an object, and we're not supposed to have found an object, return an error. */ if (status == ISC_R_SUCCESS && create && exclusive) { omapi_object_dereference (&object, MDL); return omapi_protocol_send_status (po, message -> id_object, ISC_R_EXISTS, message -> id, "specified object already exists"); } /* If we're creating the object, do it now. */ if (!object) { status = omapi_object_create (&object, message -> id_object, type); if (status != ISC_R_SUCCESS) { return omapi_protocol_send_status (po, message -> id_object, status, message -> id, "can't create new object"); } } /* If we're updating it, do so now. */ if (create || update) { /* This check does not belong here. */ if (object -> type == omapi_type_auth_key) { omapi_object_dereference (&object, MDL); return omapi_protocol_send_status (po, message -> id_object, status, message -> id, "can't update object"); } status = omapi_object_update (object, message -> id_object, message -> object, message -> h); if (status != ISC_R_SUCCESS) { omapi_object_dereference (&object, MDL); return omapi_protocol_send_status (po, message -> id_object, status, message -> id, "can't update object"); } } /* If this is an authenticator object, add it to the active set for the connection. */ if (object -> type == omapi_type_auth_key) { omapi_handle_t handle; status = omapi_object_handle (&handle, object); if (status != ISC_R_SUCCESS) { omapi_object_dereference (&object, MDL); return omapi_protocol_send_status (po, message -> id_object, status, message -> id, "can't select authenticator"); } status = omapi_protocol_add_auth (po, object, handle); if (status != ISC_R_SUCCESS) { omapi_object_dereference (&object, MDL); return omapi_protocol_send_status (po, message -> id_object, status, message -> id, "can't select authenticator"); } } /* Now send the new contents of the object back in response. */ goto send; case OMAPI_OP_REFRESH: refresh: status = omapi_handle_lookup (&object, message -> h); if (status != ISC_R_SUCCESS) { return omapi_protocol_send_status (po, message -> id_object, status, message -> id, "no matching handle"); } send: status = omapi_protocol_send_update (po, message -> id_object, message -> id, object); omapi_object_dereference (&object, MDL); return status; case OMAPI_OP_UPDATE: if (m && m -> object) { status = omapi_object_reference (&object, m -> object, MDL); } else { status = omapi_handle_lookup (&object, message -> h); if (status != ISC_R_SUCCESS) { return omapi_protocol_send_status (po, message -> id_object, status, message -> id, "no matching handle"); } } if (object -> type == omapi_type_auth_key || (object -> inner && object -> inner -> type == omapi_type_auth_key)) { if (!m) { omapi_object_dereference (&object, MDL); return omapi_protocol_send_status (po, message -> id_object, status, message -> id, "cannot update authenticator"); } status = omapi_protocol_add_auth (po, object, message -> h); } else { status = omapi_object_update (object, message -> id_object, message -> object, message -> h); } if (status != ISC_R_SUCCESS) { omapi_object_dereference (&object, MDL); if (!message -> rid) return omapi_protocol_send_status (po, message -> id_object, status, message -> id, "can't update object"); if (m) omapi_signal ((omapi_object_t *)m, "status", status, (omapi_typed_data_t *)0); return ISC_R_SUCCESS; } if (!message -> rid) status = omapi_protocol_send_status (po, message -> id_object, ISC_R_SUCCESS, message -> id, (char *)0); if (m) { omapi_signal ((omapi_object_t *)m, "status", ISC_R_SUCCESS, (omapi_typed_data_t *)0); omapi_message_unregister ((omapi_object_t *)m); } omapi_object_dereference (&object, MDL); return status; case OMAPI_OP_NOTIFY: return omapi_protocol_send_status (po, message -> id_object, ISC_R_NOTIMPLEMENTED, message -> id, "notify not implemented yet"); case OMAPI_OP_STATUS: /* The return status of a request. */ if (!m) return ISC_R_UNEXPECTED; /* Get the wait status. */ status = omapi_get_value_str (mo, message -> id_object, "result", &tv); if (status == ISC_R_SUCCESS) { status = omapi_get_int_value (&wsi, tv -> value); waitstatus = wsi; omapi_value_dereference (&tv, MDL); if (status != ISC_R_SUCCESS) waitstatus = ISC_R_UNEXPECTED; } else waitstatus = ISC_R_UNEXPECTED; status = omapi_get_value_str (mo, message -> id_object, "message", &tv); omapi_signal ((omapi_object_t *)m, "status", waitstatus, tv); if (status == ISC_R_SUCCESS) omapi_value_dereference (&tv, MDL); omapi_message_unregister((omapi_object_t *)m); return ISC_R_SUCCESS; case OMAPI_OP_DELETE: status = omapi_handle_lookup (&object, message -> h); if (status != ISC_R_SUCCESS) { return omapi_protocol_send_status (po, message -> id_object, status, message -> id, "no matching handle"); } if (!object -> type -> remove) return omapi_protocol_send_status (po, message -> id_object, ISC_R_NOTIMPLEMENTED, message -> id, "no remove method for object"); status = (*(object -> type -> remove)) (object, message -> id_object); omapi_object_dereference (&object, MDL); return omapi_protocol_send_status (po, message -> id_object, status, message -> id, (char *)0); } return ISC_R_NOTIMPLEMENTED; } dhcp-4.2.4/omapip/omapi.3000644 000765 000024 00000017737 11414676760 015100 0ustar00sarstaff000000 000000 .\" omapi.3 .\" .\" Copyright (c) 2009-2010 by Internet Systems Consortium, Inc. ("ISC") .\" Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") .\" Copyright (c) 2000-2003 by Internet Software Consortium .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above .\" copyright notice and this permission notice appear in all copies. .\" .\" THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES .\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR .\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES .\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT .\" OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" .\" Internet Systems Consortium, Inc. .\" 950 Charter Street .\" Redwood City, CA 94063 .\" .\" https://www.isc.org/ .\" .\" This software has been written for Internet Systems Consortium .\" by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. .\" .\" Support and other services are available for ISC products - see .\" https://www.isc.org for more information or to learn more about ISC. .\" .TH omapi 3 .SH NAME OMAPI - Object Management Application Programming Interface .SH DESCRIPTION .PP OMAPI is an programming layer designed for controlling remote applications, and for querying them for their state. It is currently used by the ISC DHCP server and this outline addresses the parts of OMAPI appropriate to the clients of DHCP server. It does this by also describing the use of a thin API layered on top of OMAPI called \'dhcpctl\' .PP OMAPI uses TCP/IP as the transport for server communication, and security can be imposed by having the client and server cryptographically sign messages using a shared secret. .PP dhcpctl works by presenting the client with handles to objects that act as surrogates for the real objects in the server. For example a client will create a handle for a lease object, and will request the server to fill the lease handle's state. The client application can then pull details such as the lease expiration time from the lease handle. .PP Modifications can be made to the server state by creating handles to new objects, or by modifying attributes of handles to existing objects, and then instructing the server to update itself according to the changes made. .SH USAGE .PP The client application must always call dhcpctl_initialize() before making calls to any other dhcpctl functions. This initializes various internal data structures. .PP To create the connection to the server the client must use dhcpctl_connect() function. As well as making the physical connection it will also set up the connection data structures to do authentication on each message, if that is required. .PP All the dhcpctl functions return an integer value of type isc_result_t. A successful call will yield a result of ISC_R_SUCCESS. If the call fails for a reason local to the client (e.g. insufficient local memory, or invalid arguments to the call) then the return value of the dhcpctl function will show that. If the call succeeds but the server couldn't process the request the error value from the server is returned through another way, shown below. .PP The easiest way to understand dhcpctl is to see it in action. The following program is fully functional, but almost all error checking has been removed to make is shorter and easier to understand. This program will query the server running on the localhost for the details of the lease for IP address 10.0.0.101. It will then print out the time the lease ends. .PP .nf #include #include #include #include #include #include #include int main (int argc, char **argv) { dhcpctl_data_string ipaddrstring = NULL; dhcpctl_data_string value = NULL; .fi .PP All modifications of handles and all accesses of handle data happen via dhcpctl_data_string objects. .PP .nf dhcpctl_handle connection = NULL; dhcpctl_handle lease = NULL; isc_result_t waitstatus; struct in_addr convaddr; time_t thetime; dhcpctl_initialize (); .fi .PP Required first step. .PP .nf dhcpctl_connect (&connection, "127.0.0.1", 7911, 0); .fi .PP Sets up the connection to the server. The server normally listens on port 7911 unless configured to do otherwise. .PP .nf dhcpctl_new_object (&lease, connection, "lease"); .fi .PP Here we create a handle to a lease. This call just sets up local data structure. The server hasn't yet made any association between the client's data structure and any lease it has. .PP .nf memset (&ipaddrstring, 0, sizeof ipaddrstring); inet_pton(AF_INET, "10.0.0.101", &convaddr); omapi_data_string_new (&ipaddrstring, 4, MDL); .fi .PP Create a new data string to storing in the handle. .PP .nf memcpy(ipaddrstring->value, &convaddr.s_addr, 4); dhcpctl_set_value (lease, ipaddrstring, "ip-address"); .fi .PP We're setting the ip-address attribute of the lease handle to the given address. We've not set any other attributes so when the server makes the association the ip address will be all it uses to look up the lease in its tables. .PP .nf dhcpctl_open_object (lease, connection, 0); .fi .PP Here we prime the connection with the request to look up the lease in the server and fill up the local handle with the attributes the server will send over in its answer. .PP .nf dhcpctl_wait_for_completion (lease, &waitstatus); .fi .PP This call causes the message to get sent to the server (the message to look up the lease and send back the attribute values in the answer). The value in the variable waitstatus when the function returns will be the result from the server. If the message could not be processed properly by the server then the error will be reflected here. .PP .nf if (waitstatus != ISC_R_SUCCESS) { /* server not authoritative */ exit (0); } dhcpctl_data_string_dereference(&ipaddrstring, MDL); .fi .PP Clean-up memory we no longer need. .PP .nf dhcpctl_get_value (&value, lease, "ends"); .fi .PP Get the attribute named ``ends'' from the lease handle. This is a 4-byte integer of the time (in unix epoch seconds) that the lease will expire. .PP .nf memcpy(&thetime, value->value, value->len); dhcpctl_data_string_dereference(&value, MDL); fprintf (stdout, "ending time is %s", ctime(&thetime)); } .fi .SH AUTHENTICATION If the server demands authenticated connections then before opening the connection the user must call dhcpctl_new_authenticator. .PP .nf dhcpctl_handle authenticator = NULL; const char *keyname = "a-key-name"; const char *algorithm = "hmac-md5"; const char *secret = "a-shared-secret"; dhcpctl_new_authenticator (&authenticator, keyname, algorithm, secret, strlen(secret) + 1); .fi .PP The keyname, algorithm and must all match what is specified in the server's dhcpd.conf file, excepting that the secret should appear in \'raw\' form, not in base64 as it would in dhcpd.conf: .PP .nf key "a-key-name" { algorithm hmac-md5; secret "a-shared-secret"; }; # Set the omapi-key value to use # authenticated connections omapi-key a-key-name; .fi .PP The authenticator handle that is created by the call to dhcpctl_new_authenticator must be given as the last (the 4th) argument to the call to dhcpctl_connect(). All messages will then be signed with the given secret string using the specified algorithm. .SH SEE ALSO dhcpctl(3), omshell(1), dhcpd(8), dhclient(8), dhcpd.conf(5), dhclient.conf(5). .SH AUTHOR .B omapi was created by Ted Lemon of Nominum, Inc. This documentation was written by James Brister of Nominum, Inc. dhcp-4.2.4/omapip/protocol.c000644 000765 000024 00000110764 11741323273 015675 0ustar00sarstaff000000 000000 /* protocol.c Functions supporting the object management protocol... */ /* * Copyright (c) 2009,2012 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 2004-2007 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1999-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ * * This software has been written for Internet Systems Consortium * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. * To learn more about Internet Systems Consortium, see * ``https://www.isc.org/''. To learn more about Vixie Enterprises, * see ``http://www.vix.com''. To learn more about Nominum, Inc., see * ``http://www.nominum.com''. */ #include "dhcpd.h" #include OMAPI_OBJECT_ALLOC (omapi_protocol, omapi_protocol_object_t, omapi_type_protocol) OMAPI_OBJECT_ALLOC (omapi_protocol_listener, omapi_protocol_listener_object_t, omapi_type_protocol_listener) isc_result_t omapi_protocol_connect (omapi_object_t *h, const char *server_name, unsigned port, omapi_object_t *a) { isc_result_t rstatus, status; omapi_protocol_object_t *obj; #ifdef DEBUG_PROTOCOL log_debug ("omapi_protocol_connect(%s port=%d)", server_name, port); #endif obj = (omapi_protocol_object_t *)0; status = omapi_protocol_allocate (&obj, MDL); if (status != ISC_R_SUCCESS) return status; rstatus = omapi_connect ((omapi_object_t *)obj, server_name, port); if (rstatus != ISC_R_SUCCESS && rstatus != DHCP_R_INCOMPLETE) { omapi_protocol_dereference (&obj, MDL); return rstatus; } status = omapi_object_reference (&h -> outer, (omapi_object_t *)obj, MDL); if (status != ISC_R_SUCCESS) { omapi_protocol_dereference (&obj, MDL); return status; } status = omapi_object_reference (&obj -> inner, h, MDL); if (status != ISC_R_SUCCESS) { omapi_protocol_dereference (&obj, MDL); return status; } /* If we were passed a default authenticator, store it now. We'll open it once we're connected. */ if (a) { obj -> default_auth = dmalloc (sizeof(omapi_remote_auth_t), MDL); if (!obj -> default_auth) { omapi_protocol_dereference (&obj, MDL); return ISC_R_NOMEMORY; } obj -> default_auth -> next = (omapi_remote_auth_t *)0; status = omapi_object_reference (&obj -> default_auth -> a, a, MDL); if (status != ISC_R_SUCCESS) { dfree (obj -> default_auth, MDL); omapi_protocol_dereference (&obj, MDL); return status; } obj -> insecure = 0; rstatus = DHCP_R_INCOMPLETE; } else { obj -> insecure = 1; #if 0 status = ISC_R_SUCCESS; #endif } omapi_protocol_dereference (&obj, MDL); return rstatus; } /* Send the protocol introduction message. */ isc_result_t omapi_protocol_send_intro (omapi_object_t *h, unsigned ver, unsigned hsize) { isc_result_t status; omapi_protocol_object_t *p; #ifdef DEBUG_PROTOCOL log_debug ("omapi_protocol_send_intro()"); #endif if (h -> type != omapi_type_protocol) return DHCP_R_INVALIDARG; p = (omapi_protocol_object_t *)h; if (!h -> outer || h -> outer -> type != omapi_type_connection) return ISC_R_NOTCONNECTED; status = omapi_connection_put_uint32 (h -> outer, ver); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_put_uint32 (h -> outer, hsize); if (status != ISC_R_SUCCESS) return status; /* Require the other end to send an intro - this kicks off the protocol input state machine. */ p -> state = omapi_protocol_intro_wait; status = omapi_connection_require (h -> outer, 8); if (status != ISC_R_SUCCESS && status != DHCP_R_NOTYET) return status; /* Make up an initial transaction ID for this connection. */ p -> next_xid = random (); return ISC_R_SUCCESS; } #ifdef DEBUG_PROTOCOL extern const char *omapi_message_op_name(int); #endif /* DEBUG_PROTOCOL */ isc_result_t omapi_protocol_send_message (omapi_object_t *po, omapi_object_t *id, omapi_object_t *mo, omapi_object_t *omo) { omapi_protocol_object_t *p; omapi_object_t *c; omapi_message_object_t *m, *om; omapi_remote_auth_t *ra; omapi_value_t *signature; isc_result_t status; unsigned auth_len; if (po -> type != omapi_type_protocol || !po -> outer || po -> outer -> type != omapi_type_connection || mo -> type != omapi_type_message) return DHCP_R_INVALIDARG; if (omo && omo -> type != omapi_type_message) return DHCP_R_INVALIDARG; p = (omapi_protocol_object_t *)po; c = (omapi_object_t *)(po -> outer); m = (omapi_message_object_t *)mo; om = (omapi_message_object_t *)omo; #ifdef DEBUG_PROTOCOL log_debug ("omapi_protocol_send_message(): " "op=%s handle=%#lx id=%#lx rid=%#lx", omapi_message_op_name (m->op), (long)(m -> object ? m -> object -> handle : m -> handle), (long)p -> next_xid, (long)m -> rid); #endif /* Find the authid to use for this message. */ if (id) { for (ra = p -> remote_auth_list; ra; ra = ra -> next) { if (ra -> a == id) { break; } } if (!ra) return DHCP_R_KEY_UNKNOWN; } else if (p -> remote_auth_list) { ra = p -> default_auth; } else { ra = (omapi_remote_auth_t *)0; } if (ra) { m -> authid = ra -> remote_handle; status = omapi_object_reference (&m -> id_object, ra -> a, MDL); if (status != ISC_R_SUCCESS) return status; } /* Write the ID of the authentication key we're using. */ status = omapi_connection_put_uint32 (c, ra ? ra -> remote_handle : 0); if (status != ISC_R_SUCCESS) { omapi_disconnect (c, 1); return status; } /* Activate the authentication key on the connection. */ auth_len = 0; if (ra) { status = omapi_set_object_value (c, (omapi_object_t *)0, "output-authenticator", ra -> a); if (status != ISC_R_SUCCESS) { omapi_disconnect (c, 1); return status; } status = omapi_connection_output_auth_length (c, &auth_len); if (status != ISC_R_SUCCESS) { omapi_disconnect (c, 1); return status; } } /* Write the authenticator length */ status = omapi_connection_put_uint32 (c, auth_len); if (status != ISC_R_SUCCESS) { omapi_disconnect (c, 1); return status; } /* Write the opcode. */ status = omapi_connection_put_uint32 (c, m -> op); if (status != ISC_R_SUCCESS) { omapi_disconnect (c, 1); return status; } /* Write the handle. If we've been given an explicit handle, use that. Otherwise, use the handle of the object we're sending. The caller is responsible for arranging for one of these handles to be set (or not). */ status = omapi_connection_put_uint32 (c, (m -> h ? m -> h : (m -> object ? m -> object -> handle : 0))); if (status != ISC_R_SUCCESS) { omapi_disconnect (c, 1); return status; } /* Set and write the transaction ID. */ m -> id = p -> next_xid++; status = omapi_connection_put_uint32 (c, m -> id); if (status != ISC_R_SUCCESS) { omapi_disconnect (c, 1); return status; } /* Write the transaction ID of the message to which this is a response, if there is such a message. */ status = omapi_connection_put_uint32 (c, om ? om -> id : m -> rid); if (status != ISC_R_SUCCESS) { omapi_disconnect (c, 1); return status; } /* Stuff out the name/value pairs specific to this message. */ status = omapi_stuff_values (c, id, (omapi_object_t *)m); if (status != ISC_R_SUCCESS) { omapi_disconnect (c, 1); return status; } /* Write the zero-length name that terminates the list of name/value pairs specific to the message. */ status = omapi_connection_put_uint16 (c, 0); if (status != ISC_R_SUCCESS) { omapi_disconnect (c, 1); return status; } /* Stuff out all the published name/value pairs in the object that's being sent in the message, if there is one. */ if (m -> object) { status = omapi_stuff_values (c, id, m -> object); if (status != ISC_R_SUCCESS) { omapi_disconnect (c, 1); return status; } } /* Write the zero-length name that terminates the list of name/value pairs for the associated object. */ status = omapi_connection_put_uint16 (c, 0); if (status != ISC_R_SUCCESS) { omapi_disconnect (c, 1); return status; } if (ra) { /* Calculate the message signature. */ signature = (omapi_value_t *)0; status = omapi_get_value_str (c, (omapi_object_t *)0, "output-signature", &signature); if (status != ISC_R_SUCCESS) { omapi_disconnect (c, 1); return status; } /* Write the authenticator... */ status = (omapi_connection_copyin (c, signature -> value -> u.buffer.value, signature -> value -> u.buffer.len)); omapi_value_dereference (&signature, MDL); if (status != ISC_R_SUCCESS) { omapi_disconnect (c, 1); return status; } /* Dectivate the authentication key on the connection. */ status = omapi_set_value_str (c, (omapi_object_t *)0, "output-authenticator", (omapi_typed_data_t *)0); if (status != ISC_R_SUCCESS) { omapi_disconnect (c, 1); return status; } } if (!omo) { omapi_protocol_reference (&m -> protocol_object, p, MDL); } return ISC_R_SUCCESS; } isc_result_t omapi_protocol_signal_handler (omapi_object_t *h, const char *name, va_list ap) { isc_result_t status; omapi_protocol_object_t *p; omapi_object_t *c; omapi_message_object_t *m; omapi_value_t *signature; u_int16_t nlen; u_int32_t vlen; u_int32_t th; #if defined (DEBUG_MEMORY_LEAKAGE) unsigned long previous_outstanding = 0xDEADBEEF; unsigned long connect_outstanding = 0xDEADBEEF; #endif if (h -> type != omapi_type_protocol) { /* XXX shouldn't happen. Put an assert here? */ return ISC_R_UNEXPECTED; } p = (omapi_protocol_object_t *)h; if (!strcmp (name, "connect")) { #if defined (DEBUG_MEMORY_LEAKAGE) connect_outstanding = dmalloc_outstanding; #endif /* Send the introductory message. */ status = omapi_protocol_send_intro (h, OMAPI_PROTOCOL_VERSION, sizeof (omapi_protocol_header_t)); if (status != ISC_R_SUCCESS) { omapi_disconnect (p -> outer, 1); return status; } return ISC_R_SUCCESS; } /* Should only receive these when opening the initial authenticator. */ if (!strcmp (name, "status")) { status = va_arg (ap, isc_result_t); if (status != ISC_R_SUCCESS) { omapi_signal_in (h -> inner, "status", status, (omapi_object_t *)0); omapi_disconnect (p -> outer, 1); return status; } else { return omapi_signal_in (h -> inner, "ready"); } } /* If we get a disconnect, dump memory usage. */ if (!strcmp (name, "disconnect")) { #if defined (DEBUG_MEMORY_LEAKAGE) if (connect_outstanding != 0xDEADBEEF) { log_info ("generation %ld: %ld new, %ld outstanding, %ld%s", dmalloc_generation, dmalloc_outstanding - previous_outstanding, dmalloc_outstanding, dmalloc_longterm, " long-term"); } #endif #if defined (DEBUG_MEMORY_LEAKAGE) dmalloc_dump_outstanding (); #endif #if defined (DEBUG_RC_HISTORY_EXHAUSTIVELY) dump_rc_history (h); #endif for (m = omapi_registered_messages; m; m = m -> next) { if (m -> protocol_object == p) { if (m -> object) omapi_signal (m -> object, "disconnect"); } } /* XXX */ return ISC_R_SUCCESS; } /* Not a signal we recognize? */ if (strcmp (name, "ready")) { if (p -> inner && p -> inner -> type -> signal_handler) return (*(p -> inner -> type -> signal_handler)) (h, name, ap); return ISC_R_NOTFOUND; } if (!p -> outer || p -> outer -> type != omapi_type_connection) return DHCP_R_INVALIDARG; c = p -> outer; /* We get here because we requested that we be woken up after some number of bytes were read, and that number of bytes has in fact been read. */ switch (p -> state) { case omapi_protocol_intro_wait: /* Get protocol version and header size in network byte order. */ omapi_connection_get_uint32 (c, &p -> protocol_version); omapi_connection_get_uint32 (c, &p -> header_size); /* We currently only support the current protocol version. */ if (p -> protocol_version != OMAPI_PROTOCOL_VERSION) { omapi_disconnect (c, 1); return DHCP_R_VERSIONMISMATCH; } if (p -> header_size < sizeof (omapi_protocol_header_t)) { omapi_disconnect (c, 1); return DHCP_R_PROTOCOLERROR; } if (p -> default_auth) { status = omapi_protocol_send_open (h, (omapi_object_t *)0, "authenticator", p -> default_auth -> a, OMAPI_NOTIFY_PROTOCOL); if (status != ISC_R_SUCCESS) { omapi_disconnect (c, 1); return status; } } else { status = omapi_signal_in (h -> inner, "ready"); } to_header_wait: /* The next thing we're expecting is a message header. */ p -> state = omapi_protocol_header_wait; /* Register a need for the number of bytes in a header, and if we already have that many, process them immediately. */ if ((omapi_connection_require (c, p -> header_size)) != ISC_R_SUCCESS) break; /* If we already have the data, fall through. */ case omapi_protocol_header_wait: #if defined (DEBUG_MEMORY_LEAKAGE) if (previous_outstanding != 0xDEADBEEF) { log_info ("%s %ld: %ld new, %ld outstanding, %ld%s", "generation", dmalloc_generation, dmalloc_outstanding - previous_outstanding, dmalloc_outstanding, dmalloc_longterm, " long-term"); #endif #if (defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL)) dmalloc_dump_outstanding (); #endif #if defined (DEBUG_RC_HISTORY_EXHAUSTIVELY) dump_rc_history (h); #endif #if defined (DEBUG_MEMORY_LEAKAGE) } previous_outstanding = dmalloc_outstanding; #endif status = omapi_message_new ((omapi_object_t **)&p -> message, MDL); if (status != ISC_R_SUCCESS) { omapi_disconnect (c, 1); return status; } p -> verify_result = ISC_R_SUCCESS; /* Swap in the header... */ omapi_connection_get_uint32 (c, &p -> message -> authid); /* Bind the authenticator to the message object. */ if (p -> message -> authid) { status = (omapi_protocol_lookup_auth (&p -> message -> id_object, h, p -> message -> authid)); if (status != ISC_R_SUCCESS) p -> verify_result = status; /* Activate the authentication key. */ status = omapi_set_object_value (c, (omapi_object_t *)0, "input-authenticator", p -> message -> id_object); if (status != ISC_R_SUCCESS) { omapi_disconnect (c, 1); return status; } } omapi_connection_get_uint32 (c, &p -> message -> authlen); omapi_connection_get_uint32 (c, &p -> message -> op); omapi_connection_get_uint32 (c, &th); p -> message -> h = th; omapi_connection_get_uint32 (c, &p -> message -> id); omapi_connection_get_uint32 (c, &p -> message -> rid); /* If there was any extra header data, skip over it. */ if (p -> header_size > sizeof (omapi_protocol_header_t)) { omapi_connection_copyout (0, c, (p -> header_size - sizeof (omapi_protocol_header_t))); } /* XXX must compute partial signature across the XXX preceding bytes. Also, if authenticator specifies encryption as well as signing, we may have to decrypt the data on the way in. */ /* First we read in message-specific values, then object values. */ p -> reading_message_values = 1; need_name_length: /* The next thing we're expecting is length of the first name. */ p -> state = omapi_protocol_name_length_wait; /* Wait for a 16-bit length. */ if ((omapi_connection_require (c, 2)) != ISC_R_SUCCESS) break; /* If it's already here, fall through. */ case omapi_protocol_name_length_wait: omapi_connection_get_uint16 (c, &nlen); /* A zero-length name means that we're done reading name+value pairs. */ if (nlen == 0) { /* If we've already read in the object, we are done reading the message, but if we've just finished reading in the values associated with the message, we need to read the object. */ if (p -> reading_message_values) { p -> reading_message_values = 0; goto need_name_length; } /* If the authenticator length is zero, there's no signature to read in, so go straight to processing the message. */ if (p -> message -> authlen == 0) goto message_done; /* The next thing we're expecting is the message signature. */ p -> state = omapi_protocol_signature_wait; /* Wait for the number of bytes specified for the authenticator. If we already have it, go read it in. */ if (omapi_connection_require (c, p -> message -> authlen) == ISC_R_SUCCESS) goto signature_wait; break; } /* Allocate a buffer for the name. */ status = (omapi_data_string_new (&p -> name, nlen, MDL)); if (status != ISC_R_SUCCESS) { omapi_disconnect (c, 1); return ISC_R_NOMEMORY; } p -> state = omapi_protocol_name_wait; if (omapi_connection_require (c, nlen) != ISC_R_SUCCESS) break; /* If it's already here, fall through. */ case omapi_protocol_name_wait: omapi_connection_copyout (p -> name -> value, c, p -> name -> len); /* Wait for a 32-bit length. */ p -> state = omapi_protocol_value_length_wait; if ((omapi_connection_require (c, 4)) != ISC_R_SUCCESS) break; /* If it's already here, fall through. */ case omapi_protocol_value_length_wait: omapi_connection_get_uint32 (c, &vlen); /* Zero-length values are allowed - if we get one, we don't have to read any data for the value - just get the next one, if there is a next one. */ if (!vlen) goto insert_new_value; status = omapi_typed_data_new (MDL, &p -> value, omapi_datatype_data, vlen); if (status != ISC_R_SUCCESS) { omapi_disconnect (c, 1); return ISC_R_NOMEMORY; } p -> state = omapi_protocol_value_wait; if (omapi_connection_require (c, vlen) != ISC_R_SUCCESS) break; /* If it's already here, fall through. */ case omapi_protocol_value_wait: omapi_connection_copyout (p -> value -> u.buffer.value, c, p -> value -> u.buffer.len); insert_new_value: if (p -> reading_message_values) { status = (omapi_set_value ((omapi_object_t *)p -> message, p -> message -> id_object, p -> name, p -> value)); } else { if (!p -> message -> object) { /* We need a generic object to hang off of the incoming message. */ status = (omapi_generic_new (&p -> message -> object, MDL)); if (status != ISC_R_SUCCESS) { omapi_disconnect (c, 1); return status; } } status = (omapi_set_value ((omapi_object_t *)p -> message -> object, p -> message -> id_object, p -> name, p -> value)); } if (status != ISC_R_SUCCESS) { omapi_disconnect (c, 1); return status; } omapi_data_string_dereference (&p -> name, MDL); if (p -> value) omapi_typed_data_dereference (&p -> value, MDL); goto need_name_length; signature_wait: case omapi_protocol_signature_wait: if (p -> message -> id_object) { /* Compute the signature of the message. */ signature = (omapi_value_t *)0; status = omapi_get_value_str (c, (omapi_object_t *)0, "input-signature", &signature); if (status != ISC_R_SUCCESS) { omapi_disconnect (c, 1); return status; } /* Disable the authentication key on the connection. */ status = omapi_set_value_str (c, (omapi_object_t *)0, "input-authenticator", (omapi_typed_data_t *)0); if (status != ISC_R_SUCCESS) { omapi_value_dereference (&signature, MDL); omapi_disconnect (c, 1); return status; } } /* Read the authenticator. */ status = omapi_typed_data_new (MDL, &p -> message -> authenticator, omapi_datatype_data, p -> message -> authlen); if (status != ISC_R_SUCCESS) { omapi_value_dereference (&signature, MDL); omapi_disconnect (c, 1); return ISC_R_NOMEMORY; } omapi_connection_copyout (p -> message -> authenticator -> u.buffer.value, c, p -> message -> authlen); /* Verify the signature. */ if (p -> message -> id_object && ((signature -> value -> u.buffer.len != p -> message -> authlen) || (memcmp (signature -> value -> u.buffer.value, p -> message -> authenticator -> u.buffer.value, p -> message -> authlen) != 0))) { /* Invalid signature. */ p->verify_result = DHCP_R_INVALIDKEY; } omapi_value_dereference (&signature, MDL); /* Process the message. */ message_done: if (p -> verify_result != ISC_R_SUCCESS) { status = omapi_protocol_send_status (h, (omapi_object_t *)0, p -> verify_result, p -> message -> id, (char *)0); } else { status = omapi_message_process ((omapi_object_t *)p -> message, h); } if (status != ISC_R_SUCCESS) { omapi_disconnect (c, 1); return ISC_R_NOMEMORY; } omapi_message_dereference (&p -> message, MDL); #if defined (DEBUG_MEMORY_LEAKAGE) log_info ("generation %ld: %ld new, %ld outstanding, %ld%s", dmalloc_generation, dmalloc_outstanding - previous_outstanding, dmalloc_outstanding, dmalloc_longterm, " long-term"); #endif #if (defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL)) dmalloc_dump_outstanding (); #endif #if defined (DEBUG_RC_HISTORY_EXHAUSTIVELY) dump_rc_history (h); #endif #if defined (DEBUG_MEMORY_LEAKAGE) previous_outstanding = 0xDEADBEEF; #endif /* Now wait for the next message. */ goto to_header_wait; default: /* XXX should never get here. Assertion? */ break; } return ISC_R_SUCCESS; } isc_result_t omapi_protocol_add_auth (omapi_object_t *po, omapi_object_t *ao, omapi_handle_t handle) { omapi_protocol_object_t *p; omapi_remote_auth_t *r; isc_result_t status; if (ao -> type != omapi_type_auth_key && (!ao -> inner || ao -> inner -> type != omapi_type_auth_key)) return DHCP_R_INVALIDARG; if (po -> type != omapi_type_protocol) return DHCP_R_INVALIDARG; p = (omapi_protocol_object_t *)po; #ifdef DEBUG_PROTOCOL log_debug ("omapi_protocol_add_auth(name=%s)", ((omapi_auth_key_t *)ao) -> name); #endif if (p -> verify_auth) { status = (p -> verify_auth) (po, (omapi_auth_key_t *)ao); if (status != ISC_R_SUCCESS) return status; } /* If omapi_protocol_connect() was called with a default authenticator, p -> default_auth will already be set, but p -> remote_auth_list will not yet be initialized. */ if (p -> default_auth && !p -> remote_auth_list) { if (p -> default_auth -> a != ao) { /* Something just went horribly wrong. */ omapi_disconnect (p -> outer, 1); return ISC_R_UNEXPECTED; } p -> remote_auth_list = p -> default_auth; p -> default_auth -> remote_handle = handle; return omapi_signal_in (p -> inner, "ready"); } r = dmalloc (sizeof(*r), MDL); if (!r) return ISC_R_NOMEMORY; status = omapi_object_reference (&r -> a, ao, MDL); if (status != ISC_R_SUCCESS) { dfree (r, MDL); return status; } r -> remote_handle = handle; r -> next = p -> remote_auth_list; p -> remote_auth_list = r; return ISC_R_SUCCESS; } isc_result_t omapi_protocol_lookup_auth (omapi_object_t **a, omapi_object_t *po, omapi_handle_t handle) { omapi_protocol_object_t *p; omapi_remote_auth_t *r; if (po -> type != omapi_type_protocol) return DHCP_R_INVALIDARG; p = (omapi_protocol_object_t *)po; for (r = p -> remote_auth_list; r; r = r -> next) if (r -> remote_handle == handle) return omapi_object_reference (a, r -> a, MDL); return DHCP_R_KEY_UNKNOWN; } isc_result_t omapi_protocol_set_value (omapi_object_t *h, omapi_object_t *id, omapi_data_string_t *name, omapi_typed_data_t *value) { omapi_protocol_object_t *p; omapi_remote_auth_t *r; if (h -> type != omapi_type_protocol) return DHCP_R_INVALIDARG; p = (omapi_protocol_object_t *)h; if (omapi_ds_strcmp (name, "default-authenticator") == 0) { if (value -> type != omapi_datatype_object) return DHCP_R_INVALIDARG; if (!value || !value -> u.object) { p -> default_auth = (omapi_remote_auth_t *)0; } else { for (r = p -> remote_auth_list; r; r = r -> next) if (r -> a == value -> u.object) break; if (!r) return DHCP_R_KEY_UNKNOWN; p -> default_auth = r; } return ISC_R_SUCCESS; } if (h -> inner && h -> inner -> type -> set_value) return (*(h -> inner -> type -> set_value)) (h -> inner, id, name, value); return ISC_R_NOTFOUND; } isc_result_t omapi_protocol_get_value (omapi_object_t *h, omapi_object_t *id, omapi_data_string_t *name, omapi_value_t **value) { omapi_protocol_object_t *p; if (h -> type != omapi_type_protocol) return DHCP_R_INVALIDARG; p = (omapi_protocol_object_t *)h; if (omapi_ds_strcmp (name, "default-authenticator") == 0) { if (!p -> default_auth) return ISC_R_NOTFOUND; return omapi_make_object_value (value, name, p -> default_auth -> a, MDL); } if (h -> inner && h -> inner -> type -> get_value) return (*(h -> inner -> type -> get_value)) (h -> inner, id, name, value); return ISC_R_NOTFOUND; } isc_result_t omapi_protocol_destroy (omapi_object_t *h, const char *file, int line) { omapi_protocol_object_t *p; if (h -> type != omapi_type_protocol) return DHCP_R_INVALIDARG; p = (omapi_protocol_object_t *)h; if (p -> message) omapi_message_dereference (&p -> message, file, line); /* This will happen if: 1) A default authenticator is supplied to omapi_protocol_connect(), and 2) something goes wrong before the authenticator can be opened. */ if (p -> default_auth && !p -> remote_auth_list) dfree (p -> default_auth, file, line); while (p -> remote_auth_list) { omapi_remote_auth_t *r = p -> remote_auth_list; p -> remote_auth_list = p -> remote_auth_list -> next; omapi_object_dereference (&r -> a, file, line); dfree (r, file, line); } return ISC_R_SUCCESS; } /* Write all the published values associated with the object through the specified connection. */ isc_result_t omapi_protocol_stuff_values (omapi_object_t *c, omapi_object_t *id, omapi_object_t *p) { if (p -> type != omapi_type_protocol) return DHCP_R_INVALIDARG; if (p -> inner && p -> inner -> type -> stuff_values) return (*(p -> inner -> type -> stuff_values)) (c, id, p -> inner); return ISC_R_SUCCESS; } /* Returns a boolean indicating whether this protocol requires that messages be authenticated or not. */ isc_boolean_t omapi_protocol_authenticated (omapi_object_t *h) { if (h -> type != omapi_type_protocol) return isc_boolean_false; if (((omapi_protocol_object_t *)h) -> insecure) return isc_boolean_false; else return isc_boolean_true; } /* Sets the address and authenticator verification callbacks. The handle is to a listener object, not a protocol object. */ isc_result_t omapi_protocol_configure_security (omapi_object_t *h, isc_result_t (*verify_addr) (omapi_object_t *, omapi_addr_t *), isc_result_t (*verify_auth) (omapi_object_t *, omapi_auth_key_t *)) { omapi_protocol_listener_object_t *l; if (h -> outer && h -> outer -> type == omapi_type_protocol_listener) h = h -> outer; if (h -> type != omapi_type_protocol_listener) return DHCP_R_INVALIDARG; l = (omapi_protocol_listener_object_t *)h; l -> verify_auth = verify_auth; l -> insecure = 0; return omapi_listener_configure_security (h -> outer, verify_addr); } /* Set up a listener for the omapi protocol. The handle stored points to a listener object, not a protocol object. */ isc_result_t omapi_protocol_listen (omapi_object_t *h, unsigned port, int max) { isc_result_t status; omapi_protocol_listener_object_t *obj; obj = (omapi_protocol_listener_object_t *)0; status = omapi_protocol_listener_allocate (&obj, MDL); if (status != ISC_R_SUCCESS) return status; status = omapi_object_reference (&h -> outer, (omapi_object_t *)obj, MDL); if (status != ISC_R_SUCCESS) { omapi_protocol_listener_dereference (&obj, MDL); return status; } status = omapi_object_reference (&obj -> inner, h, MDL); if (status != ISC_R_SUCCESS) { omapi_protocol_listener_dereference (&obj, MDL); return status; } /* What a terrible default. */ obj -> insecure = 1; status = omapi_listen ((omapi_object_t *)obj, port, max); omapi_protocol_listener_dereference (&obj, MDL); return status; } /* Signal handler for protocol listener - if we get a connect signal, create a new protocol connection, otherwise pass the signal down. */ isc_result_t omapi_protocol_listener_signal (omapi_object_t *o, const char *name, va_list ap) { isc_result_t status; omapi_object_t *c; omapi_protocol_object_t *obj; omapi_protocol_listener_object_t *p; if (!o || o -> type != omapi_type_protocol_listener) return DHCP_R_INVALIDARG; p = (omapi_protocol_listener_object_t *)o; /* Not a signal we recognize? */ if (strcmp (name, "connect")) { if (p -> inner && p -> inner -> type -> signal_handler) return (*(p -> inner -> type -> signal_handler)) (p -> inner, name, ap); return ISC_R_NOTFOUND; } c = va_arg (ap, omapi_object_t *); if (!c || c -> type != omapi_type_connection) return DHCP_R_INVALIDARG; obj = (omapi_protocol_object_t *)0; status = omapi_protocol_allocate (&obj, MDL); if (status != ISC_R_SUCCESS) return status; obj -> verify_auth = p -> verify_auth; obj -> insecure = p -> insecure; status = omapi_object_reference (&obj -> outer, c, MDL); if (status != ISC_R_SUCCESS) { lose: omapi_protocol_dereference (&obj, MDL); omapi_disconnect (c, 1); return status; } status = omapi_object_reference (&c -> inner, (omapi_object_t *)obj, MDL); if (status != ISC_R_SUCCESS) goto lose; /* Send the introductory message. */ status = omapi_protocol_send_intro ((omapi_object_t *)obj, OMAPI_PROTOCOL_VERSION, sizeof (omapi_protocol_header_t)); if (status != ISC_R_SUCCESS) goto lose; omapi_protocol_dereference (&obj, MDL); return status; } isc_result_t omapi_protocol_listener_set_value (omapi_object_t *h, omapi_object_t *id, omapi_data_string_t *name, omapi_typed_data_t *value) { if (h -> type != omapi_type_protocol_listener) return DHCP_R_INVALIDARG; if (h -> inner && h -> inner -> type -> set_value) return (*(h -> inner -> type -> set_value)) (h -> inner, id, name, value); return ISC_R_NOTFOUND; } isc_result_t omapi_protocol_listener_get_value (omapi_object_t *h, omapi_object_t *id, omapi_data_string_t *name, omapi_value_t **value) { if (h -> type != omapi_type_protocol_listener) return DHCP_R_INVALIDARG; if (h -> inner && h -> inner -> type -> get_value) return (*(h -> inner -> type -> get_value)) (h -> inner, id, name, value); return ISC_R_NOTFOUND; } isc_result_t omapi_protocol_listener_destroy (omapi_object_t *h, const char *file, int line) { if (h -> type != omapi_type_protocol_listener) return DHCP_R_INVALIDARG; return ISC_R_SUCCESS; } /* Write all the published values associated with the object through the specified connection. */ isc_result_t omapi_protocol_listener_stuff (omapi_object_t *c, omapi_object_t *id, omapi_object_t *p) { if (p -> type != omapi_type_protocol_listener) return DHCP_R_INVALIDARG; if (p -> inner && p -> inner -> type -> stuff_values) return (*(p -> inner -> type -> stuff_values)) (c, id, p -> inner); return ISC_R_SUCCESS; } isc_result_t omapi_protocol_send_status (omapi_object_t *po, omapi_object_t *id, isc_result_t waitstatus, unsigned rid, const char *msg) { isc_result_t status; omapi_message_object_t *message = (omapi_message_object_t *)0; omapi_object_t *mo; if (po -> type != omapi_type_protocol) return DHCP_R_INVALIDARG; status = omapi_message_new ((omapi_object_t **)&message, MDL); if (status != ISC_R_SUCCESS) return status; mo = (omapi_object_t *)message; status = omapi_set_int_value (mo, (omapi_object_t *)0, "op", OMAPI_OP_STATUS); if (status != ISC_R_SUCCESS) { omapi_message_dereference (&message, MDL); return status; } status = omapi_set_int_value (mo, (omapi_object_t *)0, "rid", (int)rid); if (status != ISC_R_SUCCESS) { omapi_message_dereference (&message, MDL); return status; } status = omapi_set_int_value (mo, (omapi_object_t *)0, "result", (int)waitstatus); if (status != ISC_R_SUCCESS) { omapi_message_dereference (&message, MDL); return status; } /* If a message has been provided, send it. */ if (msg) { status = omapi_set_string_value (mo, (omapi_object_t *)0, "message", msg); if (status != ISC_R_SUCCESS) { omapi_message_dereference (&message, MDL); return status; } } status = omapi_protocol_send_message (po, id, mo, (omapi_object_t *)0); omapi_message_dereference (&message, MDL); return status; } /* The OMAPI_NOTIFY_PROTOCOL flag will cause the notify-object for the message to be set to the protocol object. This is used when opening the default authenticator. */ isc_result_t omapi_protocol_send_open (omapi_object_t *po, omapi_object_t *id, const char *type, omapi_object_t *object, unsigned flags) { isc_result_t status; omapi_message_object_t *message = (omapi_message_object_t *)0; omapi_object_t *mo; if (po -> type != omapi_type_protocol) return DHCP_R_INVALIDARG; status = omapi_message_new ((omapi_object_t **)&message, MDL); mo = (omapi_object_t *)message; if (status == ISC_R_SUCCESS) status = omapi_set_int_value (mo, (omapi_object_t *)0, "op", OMAPI_OP_OPEN); if (status == ISC_R_SUCCESS) status = omapi_set_object_value (mo, (omapi_object_t *)0, "object", object); if ((flags & OMAPI_CREATE) && (status == ISC_R_SUCCESS)) status = omapi_set_boolean_value (mo, (omapi_object_t *)0, "create", 1); if ((flags & OMAPI_UPDATE) && (status == ISC_R_SUCCESS)) status = omapi_set_boolean_value (mo, (omapi_object_t *)0, "update", 1); if ((flags & OMAPI_EXCL) && (status == ISC_R_SUCCESS)) status = omapi_set_boolean_value (mo, (omapi_object_t *)0, "exclusive", 1); if ((flags & OMAPI_NOTIFY_PROTOCOL) && (status == ISC_R_SUCCESS)) status = omapi_set_object_value (mo, (omapi_object_t *)0, "notify-object", po); if (type && (status == ISC_R_SUCCESS)) status = omapi_set_string_value (mo, (omapi_object_t *)0, "type", type); if (status == ISC_R_SUCCESS) status = omapi_message_register (mo); if (status == ISC_R_SUCCESS) { status = omapi_protocol_send_message (po, id, mo, (omapi_object_t *)0); if (status != ISC_R_SUCCESS) omapi_message_unregister (mo); } if (message) omapi_message_dereference (&message, MDL); return status; } isc_result_t omapi_protocol_send_update (omapi_object_t *po, omapi_object_t *id, unsigned rid, omapi_object_t *object) { isc_result_t status; omapi_message_object_t *message = (omapi_message_object_t *)0; omapi_object_t *mo; if (po -> type != omapi_type_protocol) return DHCP_R_INVALIDARG; status = omapi_message_new ((omapi_object_t **)&message, MDL); if (status != ISC_R_SUCCESS) return status; mo = (omapi_object_t *)message; status = omapi_set_int_value (mo, (omapi_object_t *)0, "op", OMAPI_OP_UPDATE); if (status != ISC_R_SUCCESS) { omapi_message_dereference (&message, MDL); return status; } if (rid) { omapi_handle_t handle; status = omapi_set_int_value (mo, (omapi_object_t *)0, "rid", (int)rid); if (status != ISC_R_SUCCESS) { omapi_message_dereference (&message, MDL); return status; } status = omapi_object_handle (&handle, object); if (status != ISC_R_SUCCESS) { omapi_message_dereference (&message, MDL); return status; } status = omapi_set_int_value (mo, (omapi_object_t *)0, "handle", (int)handle); if (status != ISC_R_SUCCESS) { omapi_message_dereference (&message, MDL); return status; } } status = omapi_set_object_value (mo, (omapi_object_t *)0, "object", object); if (status != ISC_R_SUCCESS) { omapi_message_dereference (&message, MDL); return status; } status = omapi_protocol_send_message (po, id, mo, (omapi_object_t *)0); omapi_message_dereference (&message, MDL); return status; } dhcp-4.2.4/omapip/result.c000644 000765 000024 00000005265 11271742256 015355 0ustar00sarstaff000000 000000 /* result.c */ /* * Copyright (c) 2004,2007,2009 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1999-2003 by Internet Software Consortium * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ * */ #include "dhcpd.h" /* * In the previous code the results started at 36 * rather than ISC_RESULTCLASS_DHCP + 0 * ISC_R_NOTCONNECTED was + 4 (40), it has been superseeded by the isc version */ static const char *text[DHCP_R_NRESULTS] = { "host unknown", /* 0 */ "protocol version mismatch", /* 1 */ "protocol error", /* 2 */ "invalid argument", /* 3 */ "data not yet available", /* 4 */ "object unchanged", /* 5 */ "more than one object matches key", /* 6 */ "key conflict", /* 7 */ "parse error(s) occurred", /* 8 */ "no key specified", /* 9 */ "zone TSIG key not known", /* 10 */ "invalid TSIG key", /* 11 */ "operation in progress", /* 12 */ "DNS format error", /* 13 */ "DNS server failed", /* 14 */ "no such domain", /* 15 */ "not implemented", /* 16 */ "refused", /* 17 */ "domain already exists", /* 18 */ "RRset already exists", /* 19 */ "no such RRset", /* 20 */ "not authorized", /* 21 */ "not a zone", /* 22 */ "bad DNS signature", /* 23 */ "bad DNS key", /* 24 */ "clock skew too great", /* 25 */ "no root zone", /* 26 */ "destination address required", /* 27 */ "cross-zone update", /* 28 */ "no TSIG signature", /* 29 */ "not equal", /* 30 */ "connection reset by peer", /* 31 */ "unknown attribute" /* 32 */ }; #define DHCP_RESULT_RESULTSET 2 #define DHCP_RESULT_UNAVAILABLESET 3 // This is a placeholder as we don't allow for external message catalogs yet isc_msgcat_t * dhcp_msgcat = NULL; isc_result_t dhcp_result_register(void) { isc_result_t result; result = isc_result_register(ISC_RESULTCLASS_DHCP, DHCP_R_NRESULTS, text, dhcp_msgcat, DHCP_RESULT_RESULTSET); return(result); } dhcp-4.2.4/omapip/support.c000644 000765 000024 00000054423 11337051263 015545 0ustar00sarstaff000000 000000 /* support.c Subroutines providing general support for objects. */ /* * Copyright (c) 2004-2007,2009-2010 * by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1999-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ * * This software has been written for Internet Systems Consortium * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. * To learn more about Internet Systems Consortium, see * ``https://www.isc.org/''. To learn more about Vixie Enterprises, * see ``http://www.vix.com''. To learn more about Nominum, Inc., see * ``http://www.nominum.com''. */ #include "dhcpd.h" #include omapi_object_type_t *omapi_type_connection; omapi_object_type_t *omapi_type_listener; omapi_object_type_t *omapi_type_io_object; omapi_object_type_t *omapi_type_datagram; omapi_object_type_t *omapi_type_generic; omapi_object_type_t *omapi_type_protocol; omapi_object_type_t *omapi_type_protocol_listener; omapi_object_type_t *omapi_type_waiter; omapi_object_type_t *omapi_type_remote; omapi_object_type_t *omapi_type_message; omapi_object_type_t *omapi_type_auth_key; omapi_object_type_t *omapi_object_types; int omapi_object_type_count; #if defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT) void omapi_type_relinquish () { omapi_object_type_t *t, *n; for (t = omapi_object_types; t; t = n) { n = t -> next; dfree (t, MDL); } omapi_object_types = (omapi_object_type_t *)0; } #endif isc_result_t omapi_init (void) { isc_result_t status; /* Register all the standard object types... */ status = omapi_object_type_register (&omapi_type_connection, "connection", omapi_connection_set_value, omapi_connection_get_value, omapi_connection_destroy, omapi_connection_signal_handler, omapi_connection_stuff_values, 0, 0, 0, 0, 0, 0, sizeof (omapi_connection_object_t), 0, RC_MISC); if (status != ISC_R_SUCCESS) return status; status = omapi_object_type_register (&omapi_type_listener, "listener", omapi_listener_set_value, omapi_listener_get_value, omapi_listener_destroy, omapi_listener_signal_handler, omapi_listener_stuff_values, 0, 0, 0, 0, 0, 0, sizeof (omapi_listener_object_t), 0, RC_MISC); if (status != ISC_R_SUCCESS) return status; status = omapi_object_type_register (&omapi_type_io_object, "io", omapi_io_set_value, omapi_io_get_value, omapi_io_destroy, omapi_io_signal_handler, omapi_io_stuff_values, 0, 0, 0, 0, 0, 0, sizeof (omapi_io_object_t), 0, RC_MISC); if (status != ISC_R_SUCCESS) return status; status = omapi_object_type_register (&omapi_type_generic, "generic", omapi_generic_set_value, omapi_generic_get_value, omapi_generic_destroy, omapi_generic_signal_handler, omapi_generic_stuff_values, 0, 0, 0, 0, 0, 0, sizeof (omapi_generic_object_t), 0, RC_MISC); if (status != ISC_R_SUCCESS) return status; status = omapi_object_type_register (&omapi_type_protocol, "protocol", omapi_protocol_set_value, omapi_protocol_get_value, omapi_protocol_destroy, omapi_protocol_signal_handler, omapi_protocol_stuff_values, 0, 0, 0, 0, 0, 0, sizeof (omapi_protocol_object_t), 0, RC_MISC); if (status != ISC_R_SUCCESS) return status; status = (omapi_object_type_register (&omapi_type_protocol_listener, "protocol-listener", omapi_protocol_listener_set_value, omapi_protocol_listener_get_value, omapi_protocol_listener_destroy, omapi_protocol_listener_signal, omapi_protocol_listener_stuff, 0, 0, 0, 0, 0, 0, sizeof (omapi_protocol_listener_object_t), 0, RC_MISC)); if (status != ISC_R_SUCCESS) return status; status = omapi_object_type_register (&omapi_type_message, "message", omapi_message_set_value, omapi_message_get_value, omapi_message_destroy, omapi_message_signal_handler, omapi_message_stuff_values, 0, 0, 0, 0, 0, 0, sizeof (omapi_message_object_t), 0, RC_MISC); if (status != ISC_R_SUCCESS) return status; status = omapi_object_type_register (&omapi_type_waiter, "waiter", 0, 0, 0, omapi_waiter_signal_handler, 0, 0, 0, 0, 0, 0, 0, sizeof (omapi_waiter_object_t), 0, RC_MISC); if (status != ISC_R_SUCCESS) return status; status = omapi_object_type_register (&omapi_type_auth_key, "authenticator", 0, omapi_auth_key_get_value, omapi_auth_key_destroy, 0, omapi_auth_key_stuff_values, omapi_auth_key_lookup, 0, 0, 0, 0, 0, sizeof (omapi_auth_key_t), 0, RC_MISC); if (status != ISC_R_SUCCESS) return status; #if defined (TRACING) omapi_listener_trace_setup (); omapi_connection_trace_setup (); omapi_buffer_trace_setup (); #endif /* This seems silly, but leave it. */ return ISC_R_SUCCESS; } isc_result_t omapi_object_type_register (omapi_object_type_t **type, const char *name, isc_result_t (*set_value) (omapi_object_t *, omapi_object_t *, omapi_data_string_t *, omapi_typed_data_t *), isc_result_t (*get_value) (omapi_object_t *, omapi_object_t *, omapi_data_string_t *, omapi_value_t **), isc_result_t (*destroy) (omapi_object_t *, const char *, int), isc_result_t (*signal_handler) (omapi_object_t *, const char *, va_list), isc_result_t (*stuff_values) (omapi_object_t *, omapi_object_t *, omapi_object_t *), isc_result_t (*lookup) (omapi_object_t **, omapi_object_t *, omapi_object_t *), isc_result_t (*create) (omapi_object_t **, omapi_object_t *), isc_result_t (*remove) (omapi_object_t *, omapi_object_t *), isc_result_t (*freer) (omapi_object_t *, const char *, int), isc_result_t (*allocator) (omapi_object_t **, const char *, int), isc_result_t (*sizer) (size_t), size_t size, isc_result_t (*initialize) (omapi_object_t *, const char *, int), int rc_flag) { omapi_object_type_t *t; t = dmalloc (sizeof *t, MDL); if (!t) return ISC_R_NOMEMORY; memset (t, 0, sizeof *t); t -> name = name; t -> set_value = set_value; t -> get_value = get_value; t -> destroy = destroy; t -> signal_handler = signal_handler; t -> stuff_values = stuff_values; t -> lookup = lookup; t -> create = create; t -> remove = remove; t -> next = omapi_object_types; t -> sizer = sizer; t -> size = size; t -> freer = freer; t -> allocator = allocator; t -> initialize = initialize; t -> rc_flag = rc_flag; omapi_object_types = t; if (type) *type = t; return ISC_R_SUCCESS; } isc_result_t omapi_signal (omapi_object_t *handle, const char *name, ...) { va_list ap; omapi_object_t *outer; isc_result_t status; va_start (ap, name); for (outer = handle; outer -> outer; outer = outer -> outer) ; if (outer -> type -> signal_handler) status = (*(outer -> type -> signal_handler)) (outer, name, ap); else status = ISC_R_NOTFOUND; va_end (ap); return status; } isc_result_t omapi_signal_in (omapi_object_t *handle, const char *name, ...) { va_list ap; isc_result_t status; if (!handle) return ISC_R_NOTFOUND; va_start (ap, name); if (handle -> type -> signal_handler) status = (*(handle -> type -> signal_handler)) (handle, name, ap); else status = ISC_R_NOTFOUND; va_end (ap); return status; } isc_result_t omapi_set_value (omapi_object_t *h, omapi_object_t *id, omapi_data_string_t *name, omapi_typed_data_t *value) { omapi_object_t *outer; isc_result_t status; #if defined (DEBUG) if (!value) { log_info ("omapi_set_value (%.*s, NULL)", (int)name -> len, name -> value); } else if (value -> type == omapi_datatype_int) { log_info ("omapi_set_value (%.*s, %ld)", (int)name -> len, name -> value, (long)value -> u.integer); } else if (value -> type == omapi_datatype_string) { log_info ("omapi_set_value (%.*s, %.*s)", (int)name -> len, name -> value, (int)value -> u.buffer.len, value -> u.buffer.value); } else if (value -> type == omapi_datatype_data) { log_info ("omapi_set_value (%.*s, %ld %lx)", (int)name -> len, name -> value, (long)value -> u.buffer.len, (unsigned long)value -> u.buffer.value); } else if (value -> type == omapi_datatype_object) { log_info ("omapi_set_value (%.*s, %s)", (int)name -> len, name -> value, value -> u.object ? (value -> u.object -> type ? value -> u.object -> type -> name : "(unknown object)") : "(unknown object)"); } #endif for (outer = h; outer -> outer; outer = outer -> outer) ; if (outer -> type -> set_value) status = (*(outer -> type -> set_value)) (outer, id, name, value); else status = ISC_R_NOTFOUND; #if defined (DEBUG) log_info (" ==> %s", isc_result_totext (status)); #endif return status; } isc_result_t omapi_set_value_str (omapi_object_t *h, omapi_object_t *id, const char *name, omapi_typed_data_t *value) { omapi_data_string_t *nds; isc_result_t status; nds = (omapi_data_string_t *)0; status = omapi_data_string_new (&nds, strlen (name), MDL); if (status != ISC_R_SUCCESS) return status; memcpy (nds -> value, name, strlen (name)); status = omapi_set_value (h, id, nds, value); omapi_data_string_dereference (&nds, MDL); return status; } isc_result_t omapi_set_boolean_value (omapi_object_t *h, omapi_object_t *id, const char *name, int value) { isc_result_t status; omapi_typed_data_t *tv = (omapi_typed_data_t *)0; omapi_data_string_t *n = (omapi_data_string_t *)0; status = omapi_data_string_new (&n, strlen (name), MDL); if (status != ISC_R_SUCCESS) return status; memcpy (n -> value, name, strlen (name)); status = omapi_typed_data_new (MDL, &tv, omapi_datatype_int, value); if (status != ISC_R_SUCCESS) { omapi_data_string_dereference (&n, MDL); return status; } status = omapi_set_value (h, id, n, tv); omapi_data_string_dereference (&n, MDL); omapi_typed_data_dereference (&tv, MDL); return status; } isc_result_t omapi_set_int_value (omapi_object_t *h, omapi_object_t *id, const char *name, int value) { isc_result_t status; omapi_typed_data_t *tv = (omapi_typed_data_t *)0; omapi_data_string_t *n = (omapi_data_string_t *)0; status = omapi_data_string_new (&n, strlen (name), MDL); if (status != ISC_R_SUCCESS) return status; memcpy (n -> value, name, strlen (name)); status = omapi_typed_data_new (MDL, &tv, omapi_datatype_int, value); if (status != ISC_R_SUCCESS) { omapi_data_string_dereference (&n, MDL); return status; } status = omapi_set_value (h, id, n, tv); omapi_data_string_dereference (&n, MDL); omapi_typed_data_dereference (&tv, MDL); return status; } isc_result_t omapi_set_object_value (omapi_object_t *h, omapi_object_t *id, const char *name, omapi_object_t *value) { isc_result_t status; omapi_typed_data_t *tv = (omapi_typed_data_t *)0; omapi_data_string_t *n = (omapi_data_string_t *)0; status = omapi_data_string_new (&n, strlen (name), MDL); if (status != ISC_R_SUCCESS) return status; memcpy (n -> value, name, strlen (name)); status = omapi_typed_data_new (MDL, &tv, omapi_datatype_object, value); if (status != ISC_R_SUCCESS) { omapi_data_string_dereference (&n, MDL); return status; } status = omapi_set_value (h, id, n, tv); omapi_data_string_dereference (&n, MDL); omapi_typed_data_dereference (&tv, MDL); return status; } isc_result_t omapi_set_string_value (omapi_object_t *h, omapi_object_t *id, const char *name, const char *value) { isc_result_t status; omapi_typed_data_t *tv = (omapi_typed_data_t *)0; omapi_data_string_t *n = (omapi_data_string_t *)0; status = omapi_data_string_new (&n, strlen (name), MDL); if (status != ISC_R_SUCCESS) return status; memcpy (n -> value, name, strlen (name)); status = omapi_typed_data_new (MDL, &tv, omapi_datatype_string, value); if (status != ISC_R_SUCCESS) { omapi_data_string_dereference (&n, MDL); return status; } status = omapi_set_value (h, id, n, tv); omapi_data_string_dereference (&n, MDL); omapi_typed_data_dereference (&tv, MDL); return status; } isc_result_t omapi_get_value (omapi_object_t *h, omapi_object_t *id, omapi_data_string_t *name, omapi_value_t **value) { omapi_object_t *outer; for (outer = h; outer -> outer; outer = outer -> outer) ; if (outer -> type -> get_value) return (*(outer -> type -> get_value)) (outer, id, name, value); return ISC_R_NOTFOUND; } isc_result_t omapi_get_value_str (omapi_object_t *h, omapi_object_t *id, const char *name, omapi_value_t **value) { omapi_object_t *outer; omapi_data_string_t *nds; isc_result_t status; nds = (omapi_data_string_t *)0; status = omapi_data_string_new (&nds, strlen (name), MDL); if (status != ISC_R_SUCCESS) return status; memcpy (nds -> value, name, strlen (name)); for (outer = h; outer -> outer; outer = outer -> outer) ; if (outer -> type -> get_value) status = (*(outer -> type -> get_value)) (outer, id, nds, value); else status = ISC_R_NOTFOUND; omapi_data_string_dereference (&nds, MDL); return status; } isc_result_t omapi_stuff_values (omapi_object_t *c, omapi_object_t *id, omapi_object_t *o) { omapi_object_t *outer; for (outer = o; outer -> outer; outer = outer -> outer) ; if (outer -> type -> stuff_values) return (*(outer -> type -> stuff_values)) (c, id, outer); return ISC_R_NOTFOUND; } isc_result_t omapi_object_create (omapi_object_t **obj, omapi_object_t *id, omapi_object_type_t *type) { if (!type -> create) return ISC_R_NOTIMPLEMENTED; return (*(type -> create)) (obj, id); } isc_result_t omapi_object_update (omapi_object_t *obj, omapi_object_t *id, omapi_object_t *src, omapi_handle_t handle) { omapi_generic_object_t *gsrc; isc_result_t status; int i; if (!src) return DHCP_R_INVALIDARG; if (src -> type != omapi_type_generic) return ISC_R_NOTIMPLEMENTED; gsrc = (omapi_generic_object_t *)src; for (i = 0; i < gsrc -> nvalues; i++) { status = omapi_set_value (obj, id, gsrc -> values [i] -> name, gsrc -> values [i] -> value); if (status != ISC_R_SUCCESS && status != DHCP_R_UNCHANGED) return status; } if (handle) omapi_set_int_value (obj, id, "remote-handle", (int)handle); status = omapi_signal (obj, "updated"); if (status != ISC_R_NOTFOUND) return status; return ISC_R_SUCCESS; } int omapi_data_string_cmp (omapi_data_string_t *s1, omapi_data_string_t *s2) { unsigned len; int rv; if (s1 -> len > s2 -> len) len = s2 -> len; else len = s1 -> len; rv = memcmp (s1 -> value, s2 -> value, len); if (rv) return rv; if (s1 -> len > s2 -> len) return 1; else if (s1 -> len < s2 -> len) return -1; return 0; } int omapi_ds_strcmp (omapi_data_string_t *s1, const char *s2) { unsigned len, slen; int rv; slen = strlen (s2); if (slen > s1 -> len) len = s1 -> len; else len = slen; rv = memcmp (s1 -> value, s2, len); if (rv) return rv; if (s1 -> len > slen) return 1; else if (s1 -> len < slen) return -1; return 0; } int omapi_td_strcmp (omapi_typed_data_t *s1, const char *s2) { unsigned len, slen; int rv; /* If the data type is not compatible, never equal. */ if (s1 -> type != omapi_datatype_data && s1 -> type != omapi_datatype_string) return -1; slen = strlen (s2); if (slen > s1 -> u.buffer.len) len = s1 -> u.buffer.len; else len = slen; rv = memcmp (s1 -> u.buffer.value, s2, len); if (rv) return rv; if (s1 -> u.buffer.len > slen) return 1; else if (s1 -> u.buffer.len < slen) return -1; return 0; } int omapi_td_strcasecmp (omapi_typed_data_t *s1, const char *s2) { unsigned len, slen; int rv; /* If the data type is not compatible, never equal. */ if (s1 -> type != omapi_datatype_data && s1 -> type != omapi_datatype_string) return -1; slen = strlen (s2); if (slen > s1 -> u.buffer.len) len = s1 -> u.buffer.len; else len = slen; rv = casecmp (s1 -> u.buffer.value, s2, len); if (rv) return rv; if (s1 -> u.buffer.len > slen) return 1; else if (s1 -> u.buffer.len < slen) return -1; return 0; } isc_result_t omapi_make_value (omapi_value_t **vp, omapi_data_string_t *name, omapi_typed_data_t *value, const char *file, int line) { isc_result_t status; status = omapi_value_new (vp, file, line); if (status != ISC_R_SUCCESS) return status; status = omapi_data_string_reference (&(*vp) -> name, name, file, line); if (status != ISC_R_SUCCESS) { omapi_value_dereference (vp, file, line); return status; } if (value) { status = omapi_typed_data_reference (&(*vp) -> value, value, file, line); if (status != ISC_R_SUCCESS) { omapi_value_dereference (vp, file, line); return status; } } return ISC_R_SUCCESS; } isc_result_t omapi_make_const_value (omapi_value_t **vp, omapi_data_string_t *name, const unsigned char *value, unsigned len, const char *file, int line) { isc_result_t status; status = omapi_value_new (vp, file, line); if (status != ISC_R_SUCCESS) return status; status = omapi_data_string_reference (&(*vp) -> name, name, file, line); if (status != ISC_R_SUCCESS) { omapi_value_dereference (vp, file, line); return status; } if (value) { status = omapi_typed_data_new (file, line, &(*vp) -> value, omapi_datatype_data, len); if (status != ISC_R_SUCCESS) { omapi_value_dereference (vp, file, line); return status; } memcpy ((*vp) -> value -> u.buffer.value, value, len); } return ISC_R_SUCCESS; } isc_result_t omapi_make_int_value (omapi_value_t **vp, omapi_data_string_t *name, int value, const char *file, int line) { isc_result_t status; status = omapi_value_new (vp, file, line); if (status != ISC_R_SUCCESS) return status; status = omapi_data_string_reference (&(*vp) -> name, name, file, line); if (status != ISC_R_SUCCESS) { omapi_value_dereference (vp, file, line); return status; } status = omapi_typed_data_new (file, line, &(*vp) -> value, omapi_datatype_int, value); if (status != ISC_R_SUCCESS) { omapi_value_dereference (vp, file, line); return status; } return ISC_R_SUCCESS; } isc_result_t omapi_make_uint_value (omapi_value_t **vp, omapi_data_string_t *name, unsigned int value, const char *file, int line) { return omapi_make_int_value (vp, name, (int)value, file, line); } isc_result_t omapi_make_object_value (omapi_value_t **vp, omapi_data_string_t *name, omapi_object_t *value, const char *file, int line) { isc_result_t status; status = omapi_value_new (vp, file, line); if (status != ISC_R_SUCCESS) return status; status = omapi_data_string_reference (&(*vp) -> name, name, file, line); if (status != ISC_R_SUCCESS) { omapi_value_dereference (vp, file, line); return status; } if (value) { status = omapi_typed_data_new (file, line, &(*vp) -> value, omapi_datatype_object, value); if (status != ISC_R_SUCCESS) { omapi_value_dereference (vp, file, line); return status; } } return ISC_R_SUCCESS; } isc_result_t omapi_make_handle_value (omapi_value_t **vp, omapi_data_string_t *name, omapi_object_t *value, const char *file, int line) { isc_result_t status; status = omapi_value_new (vp, file, line); if (status != ISC_R_SUCCESS) return status; status = omapi_data_string_reference (&(*vp) -> name, name, file, line); if (status != ISC_R_SUCCESS) { omapi_value_dereference (vp, file, line); return status; } if (value) { status = omapi_typed_data_new (file, line, &(*vp) -> value, omapi_datatype_int); if (status != ISC_R_SUCCESS) { omapi_value_dereference (vp, file, line); return status; } status = (omapi_object_handle ((omapi_handle_t *)&(*vp) -> value -> u.integer, value)); if (status != ISC_R_SUCCESS) { omapi_value_dereference (vp, file, line); return status; } } return ISC_R_SUCCESS; } isc_result_t omapi_make_string_value (omapi_value_t **vp, omapi_data_string_t *name, const char *value, const char *file, int line) { isc_result_t status; status = omapi_value_new (vp, file, line); if (status != ISC_R_SUCCESS) return status; status = omapi_data_string_reference (&(*vp) -> name, name, file, line); if (status != ISC_R_SUCCESS) { omapi_value_dereference (vp, file, line); return status; } if (value) { status = omapi_typed_data_new (file, line, &(*vp) -> value, omapi_datatype_string, value); if (status != ISC_R_SUCCESS) { omapi_value_dereference (vp, file, line); return status; } } return ISC_R_SUCCESS; } isc_result_t omapi_get_int_value (unsigned long *v, omapi_typed_data_t *t) { u_int32_t rv; if (t -> type == omapi_datatype_int) { *v = t -> u.integer; return ISC_R_SUCCESS; } else if (t -> type == omapi_datatype_string || t -> type == omapi_datatype_data) { if (t -> u.buffer.len != sizeof (rv)) return DHCP_R_INVALIDARG; memcpy (&rv, t -> u.buffer.value, sizeof rv); *v = ntohl (rv); return ISC_R_SUCCESS; } return DHCP_R_INVALIDARG; } dhcp-4.2.4/omapip/test.c000644 000765 000024 00000006502 11376616315 015013 0ustar00sarstaff000000 000000 /* test.c Test code for omapip... */ /* * Copyright (c) 2009-2010 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1999-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ * * This software has been written for Internet Systems Consortium * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. * To learn more about Internet Systems Consortium, see * ``https://www.isc.org/''. To learn more about Vixie Enterprises, * see ``http://www.vix.com''. To learn more about Nominum, Inc., see * ``http://www.nominum.com''. */ #include "config.h" #include #include #include #include #include #include #include #include #include int main (int argc, char **argv) { omapi_object_t *listener = (omapi_object_t*)0; omapi_object_t *connection = (omapi_object_t*)0; isc_result_t status; status = dhcp_context_create(); if (status != ISC_R_SUCCESS) { fprintf(stderr, "Can't initialize context: %s\n", isc_result_totext(status)); exit(1); } omapi_init (); if (argc > 1 && !strcmp (argv [1], "listen")) { if (argc < 3) { fprintf (stderr, "Usage: test listen port\n"); exit (1); } status = omapi_generic_new (&listener, MDL); if (status != ISC_R_SUCCESS) { fprintf (stderr, "omapi_generic_new: %s\n", isc_result_totext (status)); exit (1); } status = omapi_protocol_listen (listener, (unsigned)atoi (argv [2]), 1); if (status != ISC_R_SUCCESS) { fprintf (stderr, "omapi_listen: %s\n", isc_result_totext (status)); exit (1); } omapi_dispatch (0); } else if (argc > 1 && !strcmp (argv [1], "connect")) { if (argc < 4) { fprintf (stderr, "Usage: test listen address port\n"); exit (1); } status = omapi_generic_new (&connection, MDL); if (status != ISC_R_SUCCESS) { fprintf (stderr, "omapi_generic_new: %s\n", isc_result_totext (status)); exit (1); } status = omapi_protocol_connect (connection, argv [2], (unsigned)atoi (argv [3]), 0); fprintf (stderr, "connect: %s\n", isc_result_totext (status)); if (status != ISC_R_SUCCESS) exit (1); status = omapi_wait_for_completion (connection, 0); fprintf (stderr, "completion: %s\n", isc_result_totext (status)); if (status != ISC_R_SUCCESS) exit (1); /* ... */ } else { fprintf (stderr, "Usage: test [listen | connect] ...\n"); exit (1); } return 0; } dhcp-4.2.4/omapip/toisc.c000644 000765 000024 00000010502 11301372616 015137 0ustar00sarstaff000000 000000 /* toisc.c Convert non-ISC result codes to ISC result codes. */ /* * Copyright (c) 2004,2007,2009 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 2001-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ * * This software has been written for Internet Systems Consortium * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. * To learn more about Internet Systems Consortium, see * ``https://www.isc.org/''. To learn more about Vixie Enterprises, * see ``http://www.vix.com''. To learn more about Nominum, Inc., see * ``http://www.nominum.com''. */ #include "dhcpd.h" #include #include "arpa/nameser.h" #include "minires.h" #include isc_result_t uerr2isc (int err) { switch (err) { case EPERM: return ISC_R_NOPERM; case ENOENT: return ISC_R_NOTFOUND; case ESRCH: return ISC_R_NOTFOUND; case EIO: return ISC_R_IOERROR; case ENXIO: return ISC_R_NOTFOUND; case E2BIG: return ISC_R_NOSPACE; case ENOEXEC: return DHCP_R_FORMERR; case ECHILD: return ISC_R_NOTFOUND; case ENOMEM: return ISC_R_NOMEMORY; case EACCES: return ISC_R_NOPERM; case EFAULT: return DHCP_R_INVALIDARG; case EEXIST: return ISC_R_EXISTS; case EINVAL: return DHCP_R_INVALIDARG; case ENOTTY: return DHCP_R_INVALIDARG; case EFBIG: return ISC_R_NOSPACE; case ENOSPC: return ISC_R_NOSPACE; case EROFS: return ISC_R_NOPERM; case EMLINK: return ISC_R_NOSPACE; case EPIPE: return ISC_R_NOTCONNECTED; case EINPROGRESS: return ISC_R_ALREADYRUNNING; case EALREADY: return ISC_R_ALREADYRUNNING; case ENOTSOCK: return ISC_R_INVALIDFILE; case EDESTADDRREQ: return DHCP_R_DESTADDRREQ; case EMSGSIZE: return ISC_R_NOSPACE; case EPROTOTYPE: return DHCP_R_INVALIDARG; case ENOPROTOOPT: return ISC_R_NOTIMPLEMENTED; case EPROTONOSUPPORT: return ISC_R_NOTIMPLEMENTED; case ESOCKTNOSUPPORT: return ISC_R_NOTIMPLEMENTED; case EOPNOTSUPP: return ISC_R_NOTIMPLEMENTED; case EPFNOSUPPORT: return ISC_R_NOTIMPLEMENTED; case EAFNOSUPPORT: return ISC_R_NOTIMPLEMENTED; case EADDRINUSE: return ISC_R_ADDRINUSE; case EADDRNOTAVAIL: return ISC_R_ADDRNOTAVAIL; case ENETDOWN: return ISC_R_NETDOWN; case ENETUNREACH: return ISC_R_NETUNREACH; case ECONNABORTED: return ISC_R_TIMEDOUT; case ECONNRESET: return DHCP_R_CONNRESET; case ENOBUFS: return ISC_R_NOSPACE; case EISCONN: return ISC_R_ALREADYRUNNING; case ENOTCONN: return ISC_R_NOTCONNECTED; case ESHUTDOWN: return ISC_R_SHUTTINGDOWN; case ETIMEDOUT: return ISC_R_TIMEDOUT; case ECONNREFUSED: return ISC_R_CONNREFUSED; case EHOSTDOWN: return ISC_R_HOSTDOWN; case EHOSTUNREACH: return ISC_R_HOSTUNREACH; #ifdef EDQUOT case EDQUOT: return ISC_R_QUOTA; #endif #ifdef EBADRPC case EBADRPC: return ISC_R_NOTIMPLEMENTED; #endif #ifdef ERPCMISMATCH case ERPCMISMATCH: return DHCP_R_VERSIONMISMATCH; #endif #ifdef EPROGMISMATCH case EPROGMISMATCH: return DHCP_R_VERSIONMISMATCH; #endif #ifdef EAUTH case EAUTH: return DHCP_R_NOTAUTH; #endif #ifdef ENEEDAUTH case ENEEDAUTH: return DHCP_R_NOTAUTH; #endif #ifdef EOVERFLOW case EOVERFLOW: return ISC_R_NOSPACE; #endif } return ISC_R_UNEXPECTED; } dhcp-4.2.4/omapip/trace.c000644 000765 000024 00000045547 11377337061 015145 0ustar00sarstaff000000 000000 /* trace.c Subroutines that support tracing of OMAPI wire transactions and provide a mechanism for programs using OMAPI to trace their own transactions... */ /* * Copyright (c) 2009-2010 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 2004-2007 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 2001-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ * * This software has been written for Internet Systems Consortium * by Ted Lemon, as part of a project for Nominum, Inc. To learn more * about Internet Systems Consortium, see https://www.isc.org/. To * learn more about Nominum, Inc., see ``http://www.nominum.com''. */ #include "dhcpd.h" #include #include #if defined (TRACING) void (*trace_set_time_hook) (TIME); static int tracing_stopped; static int traceoutfile; static int traceindex; static trace_type_t **trace_types; static int trace_type_count; static int trace_type_max; static trace_type_t *new_trace_types; static FILE *traceinfile; static tracefile_header_t tracefile_header; static int trace_playback_flag; trace_type_t trace_time_marker; #if defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT) extern omapi_array_t *trace_listeners; extern omapi_array_t *omapi_connections; extern int errno; void trace_free_all () { trace_type_t *tp; int i; tp = new_trace_types; while (tp) { new_trace_types = tp -> next; if (tp -> name) { dfree (tp -> name, MDL); tp -> name = (char *)0; } dfree (tp, MDL); tp = new_trace_types; } for (i = 0; i < trace_type_count; i++) { if (trace_types [i]) { if (trace_types [i] -> name) dfree (trace_types [i] -> name, MDL); dfree (trace_types [i], MDL); } } dfree (trace_types, MDL); trace_types = (trace_type_t **)0; trace_type_count = trace_type_max = 0; omapi_array_free (&trace_listeners, MDL); omapi_array_free (&omapi_connections, MDL); } #endif static isc_result_t trace_type_record (trace_type_t *, unsigned, const char *, int); int trace_playback () { return trace_playback_flag; } int trace_record () { if (traceoutfile && !tracing_stopped) return 1; return 0; } isc_result_t trace_init (void (*set_time) (TIME), const char *file, int line) { trace_type_t *root_type; static int root_setup = 0; if (root_setup) return ISC_R_SUCCESS; trace_set_time_hook = set_time; root_type = trace_type_register ("trace-index-mapping", (void *)0, trace_index_map_input, trace_index_stop_tracing, file, line); if (!root_type) return ISC_R_UNEXPECTED; if (new_trace_types == root_type) new_trace_types = new_trace_types -> next; root_type -> index = 0; trace_type_stash (root_type); root_setup = 1; return ISC_R_SUCCESS; } isc_result_t trace_begin (const char *filename, const char *file, int line) { tracefile_header_t tfh; int status; trace_type_t *tptr, *next; isc_result_t result; if (traceoutfile) { log_error ("%s(%d): trace_begin called twice", file, line); return DHCP_R_INVALIDARG; } traceoutfile = open (filename, O_CREAT | O_WRONLY | O_EXCL, 0600); if (traceoutfile < 0 && errno == EEXIST) { log_error ("WARNING: Overwriting trace file \"%s\"", filename); traceoutfile = open (filename, O_WRONLY | O_EXCL | O_TRUNC, 0600); } if (traceoutfile < 0) { log_error ("%s(%d): trace_begin: %s: %m", file, line, filename); return ISC_R_UNEXPECTED; } #if defined (HAVE_SETFD) if (fcntl (traceoutfile, F_SETFD, 1) < 0) log_error ("Can't set close-on-exec on %s: %m", filename); #endif tfh.magic = htonl (TRACEFILE_MAGIC); tfh.version = htonl (TRACEFILE_VERSION); tfh.hlen = htonl (sizeof (tracefile_header_t)); tfh.phlen = htonl (sizeof (tracepacket_t)); status = write (traceoutfile, &tfh, sizeof tfh); if (status < 0) { log_error ("%s(%d): trace_begin write failed: %m", file, line); return ISC_R_UNEXPECTED; } else if (status != sizeof tfh) { log_error ("%s(%d): trace_begin: short write (%d:%ld)", file, line, status, (long)(sizeof tfh)); trace_stop (); return ISC_R_UNEXPECTED; } /* Stash all the types that have already been set up. */ if (new_trace_types) { next = new_trace_types; new_trace_types = (trace_type_t *)0; for (tptr = next; tptr; tptr = next) { next = tptr -> next; if (tptr -> index != 0) { result = (trace_type_record (tptr, strlen (tptr -> name), file, line)); if (result != ISC_R_SUCCESS) return status; } } } return ISC_R_SUCCESS; } isc_result_t trace_write_packet (trace_type_t *ttype, unsigned length, const char *buf, const char *file, int line) { trace_iov_t iov; iov.buf = buf; iov.len = length; return trace_write_packet_iov (ttype, 1, &iov, file, line); } isc_result_t trace_write_packet_iov (trace_type_t *ttype, int count, trace_iov_t *iov, const char *file, int line) { tracepacket_t tmp; int status; int i; int length; /* Really shouldn't get called here, but it may be hard to turn off tracing midstream if the trace file write fails or something. */ if (tracing_stopped) return 0; if (!ttype) { log_error ("%s(%d): trace_write_packet with null trace type", file ? file : "", line); return DHCP_R_INVALIDARG; } if (!traceoutfile) { log_error ("%s(%d): trace_write_packet with no tracefile.", file ? file : "", line); return DHCP_R_INVALIDARG; } /* Compute the total length of the iov. */ length = 0; for (i = 0; i < count; i++) length += iov [i].len; /* We have to swap out the data, because it may be read back on a machine of different endianness. */ tmp.type_index = htonl (ttype -> index); tmp.when = htonl (time ((time_t *)0)); /* XXX */ tmp.length = htonl (length); status = write (traceoutfile, &tmp, sizeof tmp); if (status < 0) { log_error ("%s(%d): trace_write_packet write failed: %m", file, line); return ISC_R_UNEXPECTED; } else if (status != sizeof tmp) { log_error ("%s(%d): trace_write_packet: short write (%d:%ld)", file, line, status, (long)(sizeof tmp)); trace_stop (); } for (i = 0; i < count; i++) { status = write (traceoutfile, iov [i].buf, iov [i].len); if (status < 0) { log_error ("%s(%d): %s write failed: %m", file, line, "trace_write_packet"); return ISC_R_UNEXPECTED; } else if (status != iov [i].len) { log_error ("%s(%d): %s: short write (%d:%d)", file, line, "trace_write_packet", status, length); trace_stop (); } } /* Write padding on the end of the packet to align the next packet to an 8-byte boundary. This is in case we decide to use mmap in some clever way later on. */ if (length % 8) { static char zero [] = { 0, 0, 0, 0, 0, 0, 0 }; unsigned padl = 8 - (length % 8); status = write (traceoutfile, zero, padl); if (status < 0) { log_error ("%s(%d): trace_write_packet write failed: %m", file, line); return ISC_R_UNEXPECTED; } else if (status != padl) { log_error ("%s(%d): trace_write_packet: short write (%d:%d)", file, line, status, padl); trace_stop (); } } return ISC_R_SUCCESS; } void trace_type_stash (trace_type_t *tptr) { trace_type_t **vec; int delta; if (trace_type_max <= tptr -> index) { delta = tptr -> index - trace_type_max + 10; vec = dmalloc (((trace_type_max + delta) * sizeof (trace_type_t *)), MDL); if (!vec) return; memset (&vec [trace_type_max], 0, (sizeof (trace_type_t *)) * delta); trace_type_max += delta; if (trace_types) { memcpy (vec, trace_types, trace_type_count * sizeof (trace_type_t *)); dfree (trace_types, MDL); } trace_types = vec; } trace_types [tptr -> index] = tptr; if (tptr -> index >= trace_type_count) trace_type_count = tptr -> index + 1; } trace_type_t *trace_type_register (const char *name, void *baggage, void (*have_packet) (trace_type_t *, unsigned, char *), void (*stop_tracing) (trace_type_t *), const char *file, int line) { trace_type_t *ttmp; unsigned slen = strlen (name); isc_result_t status; ttmp = dmalloc (sizeof *ttmp, file, line); if (!ttmp) return ttmp; ttmp -> index = -1; ttmp -> name = dmalloc (slen + 1, file, line); if (!ttmp -> name) { dfree (ttmp, file, line); return (trace_type_t *)0; } strcpy (ttmp -> name, name); ttmp -> have_packet = have_packet; ttmp -> stop_tracing = stop_tracing; if (traceoutfile) { status = trace_type_record (ttmp, slen, file, line); if (status != ISC_R_SUCCESS) { dfree (ttmp -> name, file, line); dfree (ttmp, file, line); return (trace_type_t *)0; } } else { ttmp -> next = new_trace_types; new_trace_types = ttmp; } return ttmp; } static isc_result_t trace_type_record (trace_type_t *ttmp, unsigned slen, const char *file, int line) { trace_index_mapping_t *tim; isc_result_t status; tim = dmalloc (slen + TRACE_INDEX_MAPPING_SIZE, file, line); if (!tim) return ISC_R_NOMEMORY; ttmp -> index = ++traceindex; trace_type_stash (ttmp); tim -> index = htonl (ttmp -> index); memcpy (tim -> name, ttmp -> name, slen); status = trace_write_packet (trace_types [0], slen + TRACE_INDEX_MAPPING_SIZE, (char *)tim, file, line); dfree (tim, file, line); return status; } /* Stop all registered trace types from trying to trace. */ void trace_stop (void) { int i; for (i = 0; i < trace_type_count; i++) if (trace_types [i] -> stop_tracing) (*(trace_types [i] -> stop_tracing)) (trace_types [i]); tracing_stopped = 1; } void trace_index_map_input (trace_type_t *ttype, unsigned length, char *buf) { trace_index_mapping_t *tmap; unsigned len; trace_type_t *tptr, **prev; if (length < TRACE_INDEX_MAPPING_SIZE) { log_error ("short trace index mapping"); return; } tmap = (trace_index_mapping_t *)buf; prev = &new_trace_types; for (tptr = new_trace_types; tptr; tptr = tptr -> next) { len = strlen (tptr -> name); if (len == length - TRACE_INDEX_MAPPING_SIZE && !memcmp (tptr -> name, tmap -> name, len)) { tptr -> index = ntohl (tmap -> index); trace_type_stash (tptr); *prev = tptr -> next; return; } prev = &tptr -> next; } log_error ("No registered trace type for type name %.*s", (int)length - TRACE_INDEX_MAPPING_SIZE, tmap -> name); return; } void trace_index_stop_tracing (trace_type_t *ttype) { } void trace_replay_init (void) { trace_playback_flag = 1; } void trace_file_replay (const char *filename) { tracepacket_t *tpkt = NULL; int status; char *buf = NULL; unsigned buflen; unsigned bufmax = 0; trace_type_t *ttype = NULL; isc_result_t result; int len; traceinfile = fopen (filename, "r"); if (!traceinfile) { log_error("Can't open tracefile %s: %m", filename); return; } #if defined (HAVE_SETFD) if (fcntl (fileno(traceinfile), F_SETFD, 1) < 0) log_error("Can't set close-on-exec on %s: %m", filename); #endif status = fread(&tracefile_header, 1, sizeof tracefile_header, traceinfile); if (status < sizeof tracefile_header) { if (ferror(traceinfile)) log_error("Error reading trace file header: %m"); else log_error("Short read on trace file header: %d %ld.", status, (long)(sizeof tracefile_header)); goto out; } tracefile_header.magic = ntohl(tracefile_header.magic); tracefile_header.version = ntohl(tracefile_header.version); tracefile_header.hlen = ntohl(tracefile_header.hlen); tracefile_header.phlen = ntohl(tracefile_header.phlen); if (tracefile_header.magic != TRACEFILE_MAGIC) { log_error("%s: not a dhcp trace file.", filename); goto out; } if (tracefile_header.version > TRACEFILE_VERSION) { log_error ("tracefile version %ld > current %ld.", (long int)tracefile_header.version, (long int)TRACEFILE_VERSION); goto out; } if (tracefile_header.phlen < sizeof *tpkt) { log_error("tracefile packet size too small - %ld < %ld", (long int)tracefile_header.phlen, (long int)sizeof *tpkt); goto out; } len = (sizeof tracefile_header) - tracefile_header.hlen; if (len < 0) { log_error("tracefile header size too small - %ld < %ld", (long int)tracefile_header.hlen, (long int)sizeof tracefile_header); goto out; } if (len > 0) { status = fseek(traceinfile, (long)len, SEEK_CUR); if (status < 0) { log_error("can't seek past header: %m"); goto out; } } tpkt = dmalloc((unsigned)tracefile_header.phlen, MDL); if (tpkt == NULL) { log_error ("can't allocate trace packet header."); goto out; } while ((result = trace_get_next_packet(&ttype, tpkt, &buf, &buflen, &bufmax)) == ISC_R_SUCCESS) { (*ttype->have_packet)(ttype, tpkt->length, buf); ttype = NULL; } out: fclose(traceinfile); if (buf != NULL) dfree(buf, MDL); if (tpkt != NULL) dfree(tpkt, MDL); } /* Get the next packet from the file. If ttp points to a nonzero pointer to a trace type structure, check the next packet to see if it's of the expected type, and back off if not. */ isc_result_t trace_get_next_packet (trace_type_t **ttp, tracepacket_t *tpkt, char **buf, unsigned *buflen, unsigned *bufmax) { trace_type_t *ttype; unsigned paylen; int status, curposok = 0; fpos_t curpos; while(1) { curposok = 0; status = fgetpos(traceinfile, &curpos); if (status < 0) { log_error("Can't save tracefile position: %m"); } else { curposok = 1; } status = fread(tpkt, 1, (size_t)tracefile_header.phlen, traceinfile); if (status < tracefile_header.phlen) { if (ferror(traceinfile)) log_error("Error reading trace packet header: " "%m"); else if (status == 0) return ISC_R_EOF; else log_error ("Short read on trace packet header:" " %ld %ld.", (long int)status, (long int)tracefile_header.phlen); return DHCP_R_PROTOCOLERROR; } /* Swap the packet. */ tpkt->type_index = ntohl(tpkt -> type_index); tpkt->length = ntohl(tpkt -> length); tpkt->when = ntohl(tpkt -> when); /* See if there's a handler for this packet type. */ if (tpkt->type_index < trace_type_count && trace_types[tpkt->type_index]) ttype = trace_types[tpkt->type_index]; else { log_error ("Trace packet with unknown index %ld", (long int)tpkt->type_index); return DHCP_R_PROTOCOLERROR; } /* * Determine if we should try to expire any timer events. * We do so if: * we aren't looking for a specific type of packet * we have a hook to use to update the timer * the timestamp on the packet doesn't match the current time * When we do so we rewind the file to the beginning of this * packet and then try for a new packet. This allows * any code triggered by a timeout to get the current packet * while we get the next one. */ if ((ttp != NULL) && (*ttp == NULL) && (tpkt->when != cur_tv.tv_sec) && (trace_set_time_hook != NULL)) { if (curposok == 0) { log_error("no curpos for fsetpos in " "tracefile"); return DHCP_R_PROTOCOLERROR; } status = fsetpos(traceinfile, &curpos); if (status < 0) { log_error("fsetpos in tracefile failed: %m"); return DHCP_R_PROTOCOLERROR; } (*trace_set_time_hook) (tpkt->when); continue; } break; } /* If we were supposed to get a particular kind of packet, check to see that we got the right kind. */ if (ttp && *ttp && ttype != *ttp) { log_error ("Read packet type %s when expecting %s", ttype -> name, (*ttp) -> name); status = fsetpos (traceinfile, &curpos); if (status < 0) { log_error ("fsetpos in tracefile failed: %m"); return DHCP_R_PROTOCOLERROR; } return ISC_R_UNEXPECTEDTOKEN; } paylen = tpkt -> length; if (paylen % 8) paylen += 8 - (tpkt -> length % 8); if (paylen > (*bufmax)) { if ((*buf)) dfree ((*buf), MDL); (*bufmax) = ((paylen + 1023) & ~1023U); (*buf) = dmalloc ((*bufmax), MDL); if (!(*buf)) { log_error ("Can't allocate input buffer sized %d", (*bufmax)); return ISC_R_NOMEMORY; } } status = fread ((*buf), 1, paylen, traceinfile); if (status < paylen) { if (ferror (traceinfile)) log_error ("Error reading trace payload: %m"); else log_error ("Short read on trace payload: %d %d.", status, paylen); return DHCP_R_PROTOCOLERROR; } /* Store the actual length of the payload. */ *buflen = tpkt -> length; if (ttp) *ttp = ttype; return ISC_R_SUCCESS; } isc_result_t trace_get_packet (trace_type_t **ttp, unsigned *buflen, char **buf) { tracepacket_t *tpkt; unsigned bufmax = 0; isc_result_t status; if (!buf || *buf) return DHCP_R_INVALIDARG; tpkt = dmalloc ((unsigned)tracefile_header.phlen, MDL); if (!tpkt) { log_error ("can't allocate trace packet header."); return ISC_R_NOMEMORY; } status = trace_get_next_packet (ttp, tpkt, buf, buflen, &bufmax); dfree (tpkt, MDL); return status; } /* Get a packet from the trace input file that contains a file with the specified name. We don't hunt for the packet - it should be the next packet in the tracefile. If it's not, or something else bad happens, return an error code. */ isc_result_t trace_get_file (trace_type_t *ttype, const char *filename, unsigned *len, char **buf) { fpos_t curpos; unsigned max = 0; tracepacket_t *tpkt; int status; isc_result_t result; /* Disallow some obvious bogosities. */ if (!buf || !len || *buf) return DHCP_R_INVALIDARG; /* Save file position in case of filename mismatch. */ status = fgetpos (traceinfile, &curpos); if (status < 0) log_error ("Can't save tracefile position: %m"); tpkt = dmalloc ((unsigned)tracefile_header.phlen, MDL); if (!tpkt) { log_error ("can't allocate trace packet header."); return ISC_R_NOMEMORY; } result = trace_get_next_packet (&ttype, tpkt, buf, len, &max); if (result != ISC_R_SUCCESS) { dfree (tpkt, MDL); if (*buf) dfree (*buf, MDL); return result; } /* Make sure the filename is right. */ if (strcmp (filename, *buf)) { log_error ("Read file %s when expecting %s", *buf, filename); status = fsetpos (traceinfile, &curpos); if (status < 0) { log_error ("fsetpos in tracefile failed: %m"); dfree (tpkt, MDL); dfree (*buf, MDL); return DHCP_R_PROTOCOLERROR; } return ISC_R_UNEXPECTEDTOKEN; } dfree (tpkt, MDL); return ISC_R_SUCCESS; } #endif /* TRACING */ dhcp-4.2.4/includes/arpa/000777 000765 000024 00000000000 11757514243 015135 5ustar00sarstaff000000 000000 dhcp-4.2.4/includes/cdefs.h000644 000765 000024 00000005307 11726364513 015447 0ustar00sarstaff000000 000000 /* cdefs.h Standard C definitions... */ /* * Copyright (c) 2012 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 2004,2009,2011 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1996-2003 by Internet Software Consortium * Copyright (c) 1995 RadioMail Corporation. All rights reserved. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ * * This software was written for RadioMail Corporation by Ted Lemon * under a contract with Vixie Enterprises. Further modifications have * been made for Internet Systems Consortium under a contract * with Vixie Laboratories. */ #if !defined (__ISC_DHCP_CDEFS_H__) #define __ISC_DHCP_CDEFS_H__ /* Delete attributes if not gcc or not the right version of gcc. */ #if !defined(__GNUC__) || __GNUC__ < 2 || \ (__GNUC__ == 2 && __GNUC_MINOR__ < 5) || defined (darwin) #define __attribute__(x) #endif /* The following macro handles the case of unwanted return values. In * GCC one can specify an attribute for a function to generate a warning * if the return value of the function is ignored and one can't dispose of * the warning by the use of void. In conjunction with the use of -Werror * these warnings prohibit the compilation of the package. This macro * allows us to assign the return value to a variable and then ignore it. * * __attribute__((unused)) is added for avoiding another warning about set, * but unused variable. This is produced by unused-but-set-variable switch * that is enabled by default in gcc 4.6. */ #if !defined(__GNUC__) || (__GNUC__ < 4) #define IGNORE_RET(x) (void) x #else #define IGNORE_RET(x) \ do { \ int __attribute__((unused)) ignore_return ;\ ignore_return = x; \ } while (0) #endif /* This macro is defined to avoid unused-but-set-variable warning * that is enabled in gcc 4.6 */ #define IGNORE_UNUSED(x) { x = x; } #endif /* __ISC_DHCP_CDEFS_H__ */ dhcp-4.2.4/includes/config.h.in000644 000765 000024 00000017176 11757500124 016236 0ustar00sarstaff000000 000000 /* includes/config.h.in. Generated from configure.ac by autoheader. */ /* Define to compile debug-only DHCP software. */ #undef DEBUG /* Define to queue multiple DHCPACK replies per fsync. */ #undef DELAYED_ACK /* Define to BIG_ENDIAN for MSB (Motorola or SPARC CPUs) or LITTLE_ENDIAN for LSB (Intel CPUs). */ #undef DHCP_BYTE_ORDER /* Define to 1 to include DHCPv6 support. */ #undef DHCPv6 /* Define to any value to chroot() prior to loading config. */ #undef EARLY_CHROOT /* Define to include execute() config language support. */ #undef ENABLE_EXECUTE /* Define to include Failover Protocol support. */ #undef FAILOVER_PROTOCOL /* Define to nothing if C supports flexible array members, and to 1 if it does not. That way, with a declaration like `struct s { int n; double d[FLEXIBLE_ARRAY_MEMBER]; };', the struct hack can be used with pre-C99 compilers. When computing the size of such an object, don't use 'sizeof (struct s)' as it overestimates the size. Use 'offsetof (struct s, d)' instead. Don't use 'offsetof (struct s, d[0])', as this doesn't work with MSVC and with C++ compilers. */ #undef FLEXIBLE_ARRAY_MEMBER /* Define to 1 to use the Berkeley Packet Filter interface code. */ #undef HAVE_BPF /* Define to 1 if you have the /dev/random file. */ #undef HAVE_DEV_RANDOM /* Define to 1 to use DLPI interface code. */ #undef HAVE_DLPI /* Define to 1 if you have the header file. */ #undef HAVE_IFADDRS_H /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H /* Define to 1 if you have the header file. */ #undef HAVE_LINUX_TYPES_H /* Define to 1 to use the Linux Packet Filter interface code. */ #undef HAVE_LPF /* Define to 1 if you have the header file. */ #undef HAVE_MEMORY_H /* Define to 1 if you have the header file. */ #undef HAVE_NET_IF6_H /* Define to 1 if you have the header file. */ #undef HAVE_NET_IF_DL_H /* Define to 1 if you have the header file. */ #undef HAVE_REGEX_H /* Define to 1 if the sockaddr structure has a length field. */ #undef HAVE_SA_LEN /* Define to 1 if you have the header file. */ #undef HAVE_STDINT_H /* Define to 1 if you have the header file. */ #undef HAVE_STDLIB_H /* Define to 1 if you have the header file. */ #undef HAVE_STRINGS_H /* Define to 1 if you have the header file. */ #undef HAVE_STRING_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_SOCKET_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_STAT_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TYPES_H /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H /* Define to the string for a noreturn attribute. */ #undef ISC_DHCP_NORETURN /* Define to 1 if the system has 'struct if_laddrconf'. */ #undef ISC_PLATFORM_HAVEIF_LADDRCONF /* Define to 1 if the system has 'struct if_laddrreq'. */ #undef ISC_PLATFORM_HAVEIF_LADDRREQ /* Define to 1 if the system has 'struct lifnum'. */ #undef ISC_PLATFORM_HAVELIFNUM /* Define to 1 if the inet_aton() function is missing. */ #undef NEED_INET_ATON /* Name of package */ #undef PACKAGE /* Define to the address where bug reports for this package should be sent. */ #undef PACKAGE_BUGREPORT /* Define to the full name of this package. */ #undef PACKAGE_NAME /* Define to the full name and version of this package. */ #undef PACKAGE_STRING /* Define to the one symbol short name of this package. */ #undef PACKAGE_TARNAME /* Define to the version of this package. */ #undef PACKAGE_VERSION /* Define to any value to include Ari's PARANOIA patch. */ #undef PARANOIA /* The size of `struct iaddr *', as computed by sizeof. */ #undef SIZEOF_STRUCT_IADDR_P /* Define to 1 if you have the ANSI C header files. */ #undef STDC_HEADERS /* Define to include server activity tracing support. */ #undef TRACING /* Define to 1 to use the standard BSD socket API. */ #undef USE_SOCKETS /* Define to 1 to enable IPv4 packet info support. */ #undef USE_V4_PKTINFO /* Version number of package */ #undef VERSION /* Define to 1 if on AIX 3. System headers sometimes define this. We just want to avoid a redefinition error message. */ #ifndef _ALL_SOURCE # undef _ALL_SOURCE #endif /* Enable GNU extensions on systems that have them. */ #ifndef _GNU_SOURCE # undef _GNU_SOURCE #endif /* Define to 1 if on MINIX. */ #undef _MINIX /* File for dhclient6 leases. */ #undef _PATH_DHCLIENT6_DB /* File for dhclient6 process information. */ #undef _PATH_DHCLIENT6_PID /* File for dhclient leases. */ #undef _PATH_DHCLIENT_DB /* File for dhclient process information. */ #undef _PATH_DHCLIENT_PID /* File for dhcpd6 leases. */ #undef _PATH_DHCPD6_DB /* File for dhcpd6 process information. */ #undef _PATH_DHCPD6_PID /* File for dhcpd leases. */ #undef _PATH_DHCPD_DB /* File for dhcpd process information. */ #undef _PATH_DHCPD_PID /* File for dhcrelay6 process information. */ #undef _PATH_DHCRELAY6_PID /* File for dhcrelay process information. */ #undef _PATH_DHCRELAY_PID /* Define to 2 if the system does not provide POSIX.1 features except with this defined. */ #undef _POSIX_1_SOURCE /* Define to 1 if you need to in order for `stat' and other things to work. */ #undef _POSIX_SOURCE /* Define for Solaris 2.5.1 so the uint32_t typedef from , , or is not used. If the typedef was allowed, the #define below would cause a syntax error. */ #undef _UINT32_T /* Define for Solaris 2.5.1 so the uint64_t typedef from , , or is not used. If the typedef was allowed, the #define below would cause a syntax error. */ #undef _UINT64_T /* Define for Solaris 2.5.1 so the uint8_t typedef from , , or is not used. If the typedef was allowed, the #define below would cause a syntax error. */ #undef _UINT8_T /* Enable extensions on Solaris. */ #ifndef __EXTENSIONS__ # undef __EXTENSIONS__ #endif #ifndef _POSIX_PTHREAD_SEMANTICS # undef _POSIX_PTHREAD_SEMANTICS #endif #ifndef _TANDEM_SOURCE # undef _TANDEM_SOURCE #endif /* Define to the type of a signed integer type of width exactly 16 bits if such a type exists and the standard includes do not define it. */ #undef int16_t /* Define to the type of a signed integer type of width exactly 32 bits if such a type exists and the standard includes do not define it. */ #undef int32_t /* Define to the type of a signed integer type of width exactly 64 bits if such a type exists and the standard includes do not define it. */ #undef int64_t /* Define to the type of a signed integer type of width exactly 8 bits if such a type exists and the standard includes do not define it. */ #undef int8_t /* Define a type for 16-bit unsigned integers. */ #undef u_int16_t /* Define a type for 32-bit unsigned integers. */ #undef u_int32_t /* Define a type for 64-bit unsigned integers. */ #undef u_int64_t /* Define a type for 8-bit unsigned integers. */ #undef u_int8_t /* Define to the type of an unsigned integer type of width exactly 16 bits if such a type exists and the standard includes do not define it. */ #undef uint16_t /* Define to the type of an unsigned integer type of width exactly 32 bits if such a type exists and the standard includes do not define it. */ #undef uint32_t /* Define to the type of an unsigned integer type of width exactly 64 bits if such a type exists and the standard includes do not define it. */ #undef uint64_t /* Define to the type of an unsigned integer type of width exactly 8 bits if such a type exists and the standard includes do not define it. */ #undef uint8_t dhcp-4.2.4/includes/ctrace.h000644 000765 000024 00000005452 11301372615 015614 0ustar00sarstaff000000 000000 /* trace.h Definitions for dhcp tracing facility... */ /* * Copyright (c) 2004,2009 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 2001-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ * * This software has been written for Internet Systems Consortium * by Ted Lemon, as part of a project for Nominum, Inc. To learn more * about Internet Systems Consortium, see https://www.isc.org/. To * learn more about Nominum, Inc., see ``http://www.nominum.com''. */ typedef struct { struct in_addr primary_address; u_int32_t index; struct hardware hw_address; char name [IFNAMSIZ]; } trace_interface_packet_t; typedef struct { u_int32_t index; struct iaddr from; u_int16_t from_port; struct hardware hfrom; u_int8_t havehfrom; } trace_inpacket_t; typedef struct { u_int32_t index; struct iaddr from; struct iaddr to; u_int16_t to_port; struct hardware hto; u_int8_t havehto; } trace_outpacket_t; void trace_interface_register (trace_type_t *, struct interface_info *); void trace_interface_input (trace_type_t *, unsigned, char *); void trace_interface_stop (trace_type_t *); void trace_inpacket_stash (struct interface_info *, struct dhcp_packet *, unsigned, unsigned int, struct iaddr, struct hardware *); void trace_inpacket_input (trace_type_t *, unsigned, char *); void trace_inpacket_stop (trace_type_t *); void trace_outpacket_input (trace_type_t *, unsigned, char *); void trace_outpacket_stop (trace_type_t *); ssize_t trace_packet_send (struct interface_info *, struct packet *, struct dhcp_packet *, size_t, struct in_addr, struct sockaddr_in *, struct hardware *); void trace_icmp_input_input (trace_type_t *, unsigned, char *); void trace_icmp_input_stop (trace_type_t *); void trace_icmp_output_input (trace_type_t *, unsigned, char *); void trace_icmp_output_stop (trace_type_t *); void trace_seed_stash (trace_type_t *, unsigned); void trace_seed_input (trace_type_t *, unsigned, char *); void trace_seed_stop (trace_type_t *); dhcp-4.2.4/includes/dhcp.h000644 000765 000024 00000015524 11717270172 015300 0ustar00sarstaff000000 000000 /* dhcp.h Protocol structures... */ /* * Copyright (c) 2011-2012 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 2004-2009 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1995-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ * * This software has been written for Internet Systems Consortium * by Ted Lemon in cooperation with Vixie Enterprises. To learn more * about Internet Systems Consortium, see ``https://www.isc.org''. * To learn more about Vixie Enterprises, see ``http://www.vix.com''. */ #ifndef DHCP_H #define DHCP_H #define DHCP_UDP_OVERHEAD (20 + /* IP header */ \ 8) /* UDP header */ #define DHCP_SNAME_LEN 64 #define DHCP_FILE_LEN 128 #define DHCP_FIXED_NON_UDP 236 #define DHCP_FIXED_LEN (DHCP_FIXED_NON_UDP + DHCP_UDP_OVERHEAD) /* Everything but options. */ #define BOOTP_MIN_LEN 300 #define DHCP_MTU_MAX 1500 #define DHCP_MTU_MIN 576 #define DHCP_MAX_OPTION_LEN (DHCP_MTU_MAX - DHCP_FIXED_LEN) #define DHCP_MIN_OPTION_LEN (DHCP_MTU_MIN - DHCP_FIXED_LEN) struct dhcp_packet { u_int8_t op; /* 0: Message opcode/type */ u_int8_t htype; /* 1: Hardware addr type (net/if_types.h) */ u_int8_t hlen; /* 2: Hardware addr length */ u_int8_t hops; /* 3: Number of relay agent hops from client */ u_int32_t xid; /* 4: Transaction ID */ u_int16_t secs; /* 8: Seconds since client started looking */ u_int16_t flags; /* 10: Flag bits */ struct in_addr ciaddr; /* 12: Client IP address (if already in use) */ struct in_addr yiaddr; /* 16: Client IP address */ struct in_addr siaddr; /* 18: IP address of next server to talk to */ struct in_addr giaddr; /* 20: DHCP relay agent IP address */ unsigned char chaddr [16]; /* 24: Client hardware address */ char sname [DHCP_SNAME_LEN]; /* 40: Server name */ char file [DHCP_FILE_LEN]; /* 104: Boot filename */ unsigned char options [DHCP_MAX_OPTION_LEN]; /* 212: Optional parameters (actual length dependent on MTU). */ }; /* BOOTP (rfc951) message types */ #define BOOTREQUEST 1 #define BOOTREPLY 2 /* Possible values for flags field... */ #define BOOTP_BROADCAST 32768L /* Possible values for hardware type (htype) field... */ #define HTYPE_ETHER 1 /* Ethernet 10Mbps */ #define HTYPE_IEEE802 6 /* IEEE 802.2 Token Ring... */ #define HTYPE_FDDI 8 /* FDDI... */ #define HTYPE_INFINIBAND 32 /* IP over Infiniband */ #define HTYPE_IPMP 255 /* IPMP - random hw address - there * is no standard for this so we * just steal a type */ /* Magic cookie validating dhcp options field (and bootp vendor extensions field). */ #define DHCP_OPTIONS_COOKIE "\143\202\123\143" /* DHCP Option codes: */ #define DHO_PAD 0 #define DHO_SUBNET_MASK 1 #define DHO_TIME_OFFSET 2 #define DHO_ROUTERS 3 #define DHO_TIME_SERVERS 4 #define DHO_NAME_SERVERS 5 #define DHO_DOMAIN_NAME_SERVERS 6 #define DHO_LOG_SERVERS 7 #define DHO_COOKIE_SERVERS 8 #define DHO_LPR_SERVERS 9 #define DHO_IMPRESS_SERVERS 10 #define DHO_RESOURCE_LOCATION_SERVERS 11 #define DHO_HOST_NAME 12 #define DHO_BOOT_SIZE 13 #define DHO_MERIT_DUMP 14 #define DHO_DOMAIN_NAME 15 #define DHO_SWAP_SERVER 16 #define DHO_ROOT_PATH 17 #define DHO_EXTENSIONS_PATH 18 #define DHO_IP_FORWARDING 19 #define DHO_NON_LOCAL_SOURCE_ROUTING 20 #define DHO_POLICY_FILTER 21 #define DHO_MAX_DGRAM_REASSEMBLY 22 #define DHO_DEFAULT_IP_TTL 23 #define DHO_PATH_MTU_AGING_TIMEOUT 24 #define DHO_PATH_MTU_PLATEAU_TABLE 25 #define DHO_INTERFACE_MTU 26 #define DHO_ALL_SUBNETS_LOCAL 27 #define DHO_BROADCAST_ADDRESS 28 #define DHO_PERFORM_MASK_DISCOVERY 29 #define DHO_MASK_SUPPLIER 30 #define DHO_ROUTER_DISCOVERY 31 #define DHO_ROUTER_SOLICITATION_ADDRESS 32 #define DHO_STATIC_ROUTES 33 #define DHO_TRAILER_ENCAPSULATION 34 #define DHO_ARP_CACHE_TIMEOUT 35 #define DHO_IEEE802_3_ENCAPSULATION 36 #define DHO_DEFAULT_TCP_TTL 37 #define DHO_TCP_KEEPALIVE_INTERVAL 38 #define DHO_TCP_KEEPALIVE_GARBAGE 39 #define DHO_NIS_DOMAIN 40 #define DHO_NIS_SERVERS 41 #define DHO_NTP_SERVERS 42 #define DHO_VENDOR_ENCAPSULATED_OPTIONS 43 #define DHO_NETBIOS_NAME_SERVERS 44 #define DHO_NETBIOS_DD_SERVER 45 #define DHO_NETBIOS_NODE_TYPE 46 #define DHO_NETBIOS_SCOPE 47 #define DHO_FONT_SERVERS 48 #define DHO_X_DISPLAY_MANAGER 49 #define DHO_DHCP_REQUESTED_ADDRESS 50 #define DHO_DHCP_LEASE_TIME 51 #define DHO_DHCP_OPTION_OVERLOAD 52 #define DHO_DHCP_MESSAGE_TYPE 53 #define DHO_DHCP_SERVER_IDENTIFIER 54 #define DHO_DHCP_PARAMETER_REQUEST_LIST 55 #define DHO_DHCP_MESSAGE 56 #define DHO_DHCP_MAX_MESSAGE_SIZE 57 #define DHO_DHCP_RENEWAL_TIME 58 #define DHO_DHCP_REBINDING_TIME 59 #define DHO_VENDOR_CLASS_IDENTIFIER 60 #define DHO_DHCP_CLIENT_IDENTIFIER 61 #define DHO_NWIP_DOMAIN_NAME 62 #define DHO_NWIP_SUBOPTIONS 63 #define DHO_USER_CLASS 77 #define DHO_FQDN 81 #define DHO_DHCP_AGENT_OPTIONS 82 #define DHO_AUTHENTICATE 90 /* RFC3118, was 210 */ #define DHO_CLIENT_LAST_TRANSACTION_TIME 91 #define DHO_ASSOCIATED_IP 92 #define DHO_SUBNET_SELECTION 118 /* RFC3011! */ #define DHO_DOMAIN_SEARCH 119 /* RFC3397 */ #define DHO_VIVCO_SUBOPTIONS 124 #define DHO_VIVSO_SUBOPTIONS 125 #define DHO_END 255 /* DHCP message types. */ #define DHCPDISCOVER 1 #define DHCPOFFER 2 #define DHCPREQUEST 3 #define DHCPDECLINE 4 #define DHCPACK 5 #define DHCPNAK 6 #define DHCPRELEASE 7 #define DHCPINFORM 8 #define DHCPLEASEQUERY 10 #define DHCPLEASEUNASSIGNED 11 #define DHCPLEASEUNKNOWN 12 #define DHCPLEASEACTIVE 13 /* Relay Agent Information option subtypes: */ #define RAI_CIRCUIT_ID 1 #define RAI_REMOTE_ID 2 #define RAI_AGENT_ID 3 #define RAI_LINK_SELECT 5 /* FQDN suboptions: */ #define FQDN_NO_CLIENT_UPDATE 1 #define FQDN_SERVER_UPDATE 2 #define FQDN_ENCODED 3 #define FQDN_RCODE1 4 #define FQDN_RCODE2 5 #define FQDN_HOSTNAME 6 #define FQDN_DOMAINNAME 7 #define FQDN_FQDN 8 #define FQDN_SUBOPTION_COUNT 8 /* Enterprise Suboptions: */ #define VENDOR_ISC_SUBOPTIONS 2495 #endif /* DHCP_H */ dhcp-4.2.4/includes/dhcp6.h000644 000765 000024 00000014345 11337051263 015362 0ustar00sarstaff000000 000000 /* dhcp6.h DHCPv6 Protocol structures... */ /* * Copyright (c) 2006-2010 by Internet Systems Consortium, Inc. ("ISC") * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ */ /* DHCPv6 Option codes: */ #define D6O_CLIENTID 1 /* RFC3315 */ #define D6O_SERVERID 2 #define D6O_IA_NA 3 #define D6O_IA_TA 4 #define D6O_IAADDR 5 #define D6O_ORO 6 #define D6O_PREFERENCE 7 #define D6O_ELAPSED_TIME 8 #define D6O_RELAY_MSG 9 /* Option code 10 unassigned. */ #define D6O_AUTH 11 #define D6O_UNICAST 12 #define D6O_STATUS_CODE 13 #define D6O_RAPID_COMMIT 14 #define D6O_USER_CLASS 15 #define D6O_VENDOR_CLASS 16 #define D6O_VENDOR_OPTS 17 #define D6O_INTERFACE_ID 18 #define D6O_RECONF_MSG 19 #define D6O_RECONF_ACCEPT 20 #define D6O_SIP_SERVERS_DNS 21 /* RFC3319 */ #define D6O_SIP_SERVERS_ADDR 22 /* RFC3319 */ #define D6O_NAME_SERVERS 23 /* RFC3646 */ #define D6O_DOMAIN_SEARCH 24 /* RFC3646 */ #define D6O_IA_PD 25 /* RFC3633 */ #define D6O_IAPREFIX 26 /* RFC3633 */ #define D6O_NIS_SERVERS 27 /* RFC3898 */ #define D6O_NISP_SERVERS 28 /* RFC3898 */ #define D6O_NIS_DOMAIN_NAME 29 /* RFC3898 */ #define D6O_NISP_DOMAIN_NAME 30 /* RFC3898 */ #define D6O_SNTP_SERVERS 31 /* RFC4075 */ #define D6O_INFORMATION_REFRESH_TIME 32 /* RFC4242 */ #define D6O_BCMCS_SERVER_D 33 /* RFC4280 */ #define D6O_BCMCS_SERVER_A 34 /* RFC4280 */ /* 35 is unassigned */ #define D6O_GEOCONF_CIVIC 36 /* RFC4776 */ #define D6O_REMOTE_ID 37 /* RFC4649 */ #define D6O_SUBSCRIBER_ID 38 /* RFC4580 */ #define D6O_CLIENT_FQDN 39 /* RFC4704 */ #define D6O_PANA_AGENT 40 /* paa-option */ #define D6O_NEW_POSIX_TIMEZONE 41 /* RFC4833 */ #define D6O_NEW_TZDB_TIMEZONE 42 /* RFC4833 */ #define D6O_ERO 43 /* RFC4994 */ #define D6O_LQ_QUERY 44 /* RFC5007 */ #define D6O_CLIENT_DATA 45 /* RFC5007 */ #define D6O_CLT_TIME 46 /* RFC5007 */ #define D6O_LQ_RELAY_DATA 47 /* RFC5007 */ #define D6O_LQ_CLIENT_LINK 48 /* RFC5007 */ /* * Status Codes, from RFC 3315 section 24.4, and RFC 3633, 5007. */ #define STATUS_Success 0 #define STATUS_UnspecFail 1 #define STATUS_NoAddrsAvail 2 #define STATUS_NoBinding 3 #define STATUS_NotOnLink 4 #define STATUS_UseMulticast 5 #define STATUS_NoPrefixAvail 6 #define STATUS_UnknownQueryType 7 #define STATUS_MalformedQuery 8 #define STATUS_NotConfigured 9 #define STATUS_NotAllowed 10 /* * DHCPv6 message types, defined in section 5.3 of RFC 3315 */ #define DHCPV6_SOLICIT 1 #define DHCPV6_ADVERTISE 2 #define DHCPV6_REQUEST 3 #define DHCPV6_CONFIRM 4 #define DHCPV6_RENEW 5 #define DHCPV6_REBIND 6 #define DHCPV6_REPLY 7 #define DHCPV6_RELEASE 8 #define DHCPV6_DECLINE 9 #define DHCPV6_RECONFIGURE 10 #define DHCPV6_INFORMATION_REQUEST 11 #define DHCPV6_RELAY_FORW 12 #define DHCPV6_RELAY_REPL 13 #define DHCPV6_LEASEQUERY 14 #define DHCPV6_LEASEQUERY_REPLY 15 extern const char *dhcpv6_type_names[]; extern const int dhcpv6_type_name_max; /* DUID type definitions (RFC3315 section 9). */ #define DUID_LLT 1 #define DUID_EN 2 #define DUID_LL 3 /* Offsets into IA_*'s where Option spaces commence. */ #define IA_NA_OFFSET 12 /* IAID, T1, T2, all 4 octets each */ #define IA_TA_OFFSET 4 /* IAID only, 4 octets */ #define IA_PD_OFFSET 12 /* IAID, T1, T2, all 4 octets each */ /* Offset into IAADDR's where Option spaces commence. */ #define IAADDR_OFFSET 24 /* Offset into IAPREFIX's where Option spaces commence. */ #define IAPREFIX_OFFSET 25 /* Offset into LQ_QUERY's where Option spaces commence. */ #define LQ_QUERY_OFFSET 17 /* * DHCPv6 well-known multicast addressess, from section 5.1 of RFC 3315 */ #define All_DHCP_Relay_Agents_and_Servers "FF02::1:2" #define All_DHCP_Servers "FF05::1:3" /* * DHCPv6 Retransmission Constants (RFC3315 section 5.5, RFC 5007) */ #define SOL_MAX_DELAY 1 #define SOL_TIMEOUT 1 #define SOL_MAX_RT 120 #define REQ_TIMEOUT 1 #define REQ_MAX_RT 30 #define REQ_MAX_RC 10 #define CNF_MAX_DELAY 1 #define CNF_TIMEOUT 1 #define CNF_MAX_RT 4 #define CNF_MAX_RD 10 #define REN_TIMEOUT 10 #define REN_MAX_RT 600 #define REB_TIMEOUT 10 #define REB_MAX_RT 600 #define INF_MAX_DELAY 1 #define INF_TIMEOUT 1 #define INF_MAX_RT 120 #define REL_TIMEOUT 1 #define REL_MAX_RC 5 #define DEC_TIMEOUT 1 #define DEC_MAX_RC 5 #define REC_TIMEOUT 2 #define REC_MAX_RC 8 #define HOP_COUNT_LIMIT 32 #define LQ6_TIMEOUT 1 #define LQ6_MAX_RT 10 #define LQ6_MAX_RC 5 /* * Normal packet format, defined in section 6 of RFC 3315 */ struct dhcpv6_packet { unsigned char msg_type; unsigned char transaction_id[3]; unsigned char options[FLEXIBLE_ARRAY_MEMBER]; }; /* Offset into DHCPV6 Reply packets where Options spaces commence. */ #define REPLY_OPTIONS_INDEX 4 /* * Relay packet format, defined in section 7 of RFC 3315 */ struct dhcpv6_relay_packet { unsigned char msg_type; unsigned char hop_count; unsigned char link_address[16]; unsigned char peer_address[16]; unsigned char options[FLEXIBLE_ARRAY_MEMBER]; }; /* Leasequery query-types (RFC 5007) */ #define LQ6QT_BY_ADDRESS 1 #define LQ6QT_BY_CLIENTID 2 /* * DUID time starts 2000-01-01. * This constant is the number of seconds since 1970-01-01, * when the Unix epoch began. */ #define DUID_TIME_EPOCH 946684800 /* Information-Request Time option (RFC 4242) */ #define IRT_DEFAULT 86400 #define IRT_MINIMUM 600 dhcp-4.2.4/includes/dhcpd.h000644 000765 000024 00000363463 11754542635 015463 0ustar00sarstaff000000 000000 /* dhcpd.h Definitions for dhcpd... */ /* * Copyright (c) 2004-2012 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1996-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ * * This software has been written for Internet Systems Consortium * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. * To learn more about Internet Systems Consortium, see * ``https://www.isc.org/''. To learn more about Vixie Enterprises, * see ``http://www.vix.com''. To learn more about Nominum, Inc., see * ``http://www.nominum.com''. */ #include "config.h" #ifndef __CYGWIN32__ #include #include #include #include #include #include #include #else #define fd_set cygwin_fd_set #include #endif #include #include #include #include #include #include #include #include #include #include #include #undef FDDI #include #include #if HAVE_NET_IF_DL_H # include #endif #include #include "cdefs.h" #include "osdep.h" #include "arpa/nameser.h" #include "minires.h" struct hash_table; typedef struct hash_table group_hash_t; typedef struct hash_table universe_hash_t; typedef struct hash_table option_name_hash_t; typedef struct hash_table option_code_hash_t; typedef struct hash_table dns_zone_hash_t; typedef struct hash_table lease_ip_hash_t; typedef struct hash_table lease_id_hash_t; typedef struct hash_table host_hash_t; typedef struct hash_table class_hash_t; typedef time_t TIME; #ifndef EOL #define EOL '\n' #endif #include #include #include "dhcp.h" #include "dhcp6.h" #include "statement.h" #include "tree.h" #include "inet.h" #include "dhctoken.h" #include #if defined(LDAP_CONFIGURATION) # include # include /* for uname() */ #endif #if !defined (BYTE_NAME_HASH_SIZE) # define BYTE_NAME_HASH_SIZE 401 /* Default would be ridiculous. */ #endif #if !defined (BYTE_CODE_HASH_SIZE) # define BYTE_CODE_HASH_SIZE 254 /* Default would be ridiculous. */ #endif /* Although it is highly improbable that a 16-bit option space might * actually use 2^16 actual defined options, it is the worst case * scenario we must prepare for. Having 4 options per bucket in this * case is pretty reasonable. */ #if !defined (WORD_NAME_HASH_SIZE) # define WORD_NAME_HASH_SIZE 20479 #endif #if !defined (WORD_CODE_HASH_SIZE) # define WORD_CODE_HASH_SIZE 16384 #endif /* Not only is it improbable that the 32-bit spaces might actually use 2^32 * defined options, it is infeasible. It would be best for this kind of * space to be dynamically sized. Instead we size it at the word hash's * level. */ #if !defined (QUAD_NAME_HASH_SIZE) # define QUAD_NAME_HASH_SIZE WORD_NAME_HASH_SIZE #endif #if !defined (QUAD_CODE_HASH_SIZE) # define QUAD_CODE_HASH_SIZE WORD_CODE_HASH_SIZE #endif #if !defined (DNS_HASH_SIZE) # define DNS_HASH_SIZE 0 /* Default. */ #endif /* Default size to use for name/code hashes on user-defined option spaces. */ #if !defined (DEFAULT_SPACE_HASH_SIZE) # define DEFAULT_SPACE_HASH_SIZE 11 #endif #if !defined (NWIP_HASH_SIZE) # define NWIP_HASH_SIZE 17 /* A really small table. */ #endif #if !defined (FQDN_HASH_SIZE) # define FQDN_HASH_SIZE 13 /* A ridiculously small table. */ #endif /* I really doubt a given installation is going to have more than a few * hundred vendors involved. */ #if !defined (VIVCO_HASH_SIZE) # define VIVCO_HASH_SIZE 127 #endif #if !defined (VIVSO_HASH_SIZE) # define VIVSO_HASH_SIZE VIVCO_HASH_SIZE #endif #if !defined (VSIO_HASH_SIZE) # define VSIO_HASH_SIZE VIVCO_HASH_SIZE #endif #if !defined (VIV_ISC_HASH_SIZE) # define VIV_ISC_HASH_SIZE 3 /* An incredulously small table. */ #endif #if !defined (UNIVERSE_HASH_SIZE) # define UNIVERSE_HASH_SIZE 13 /* A really small table. */ #endif #if !defined (GROUP_HASH_SIZE) # define GROUP_HASH_SIZE 0 /* Default. */ #endif /* At least one person has indicated they use ~20k host records. */ #if !defined (HOST_HASH_SIZE) # define HOST_HASH_SIZE 22501 #endif /* We have user reports of use of ISC DHCP numbering leases in the 200k's. * * We also have reports of folks using 10.0/8 as a dynamic range. The * following is something of a compromise between the two. At the ~2-3 * hundred thousand leases, there's ~2-3 leases to search in each bucket. */ #if !defined (LEASE_HASH_SIZE) # define LEASE_HASH_SIZE 100003 #endif /* It is not known what the worst case subclass hash size is. We estimate * high, I think. */ #if !defined (SCLASS_HASH_SIZE) # define SCLASS_HASH_SIZE 12007 #endif #if !defined (AGENT_HASH_SIZE) # define AGENT_HASH_SIZE 11 /* A really small table. */ #endif /* The server hash size is used for both names and codes. There aren't * many (roughly 50 at the moment), so we use a smaller table. If we * use a 1:1 table size, then we get name collisions due to poor name * hashing. So we use double the space we need, which drastically * reduces collisions. */ #if !defined (SERVER_HASH_SIZE) # define SERVER_HASH_SIZE (2*(sizeof(server_options) / sizeof(struct option))) #endif /* How many options are likely to appear in a single packet? */ #if !defined (OPTION_HASH_SIZE) # define OPTION_HASH_SIZE 17 # define OPTION_HASH_PTWO 32 /* Next power of two above option hash. */ # define OPTION_HASH_EXP 5 /* The exponent for that power of two. */ #endif #define compute_option_hash(x) \ (((x) & (OPTION_HASH_PTWO - 1)) + \ (((x) >> OPTION_HASH_EXP) & \ (OPTION_HASH_PTWO - 1))) % OPTION_HASH_SIZE; enum dhcp_shutdown_state { shutdown_listeners, shutdown_omapi_connections, shutdown_drop_omapi_connections, shutdown_dhcp, shutdown_done }; /* Client FQDN option, failover FQDN option, etc. */ typedef struct { u_int8_t codes [2]; unsigned length; u_int8_t *data; } ddns_fqdn_t; #include "failover.h" /* A parsing context. */ struct parse { int lexline; int lexchar; char *token_line; char *prev_line; char *cur_line; const char *tlname; int eol_token; /* * In order to give nice output when we have a parsing error * in our file, we keep track of where we are in the line so * that we can show the user. * * We need to keep track of two lines, because we can look * ahead, via the "peek" function, to the next line sometimes. * * The "line1" and "line2" variables act as buffers for this * information. The "lpos" variable tells us where we are in the * line. * * When we "put back" a character from the parsing context, we * do not want to have the character appear twice in the error * output. So, we set a flag, the "ugflag", which the * get_char() function uses to check for this condition. */ char line1 [81]; char line2 [81]; int lpos; int line; int tlpos; int tline; enum dhcp_token token; int ugflag; char *tval; int tlen; char tokbuf [1500]; int warnings_occurred; int file; char *inbuf; size_t bufix, buflen; size_t bufsiz; struct parse *saved_state; #if defined(LDAP_CONFIGURATION) /* * LDAP configuration uses a call-back to iteratively read config * off of the LDAP repository. * XXX: The token stream can not be rewound reliably, so this must * be addressed for DHCPv6 support. */ int (*read_function)(struct parse *); #endif }; /* Variable-length array of data. */ struct string_list { struct string_list *next; char string [1]; }; /* A name server, from /etc/resolv.conf. */ struct name_server { struct name_server *next; struct sockaddr_in addr; TIME rcdate; }; /* A domain search list element. */ struct domain_search_list { struct domain_search_list *next; char *domain; TIME rcdate; }; /* Option tag structures are used to build chains of option tags, for when we're sure we're not going to have enough of them to justify maintaining an array. */ struct option_tag { struct option_tag *next; u_int8_t data [1]; }; /* An agent option structure. We need a special structure for the Relay Agent Information option because if more than one appears in a message, we have to keep them separate. */ struct agent_options { struct agent_options *next; int length; struct option_tag *first; }; struct option_cache { int refcnt; struct option_cache *next; struct expression *expression; struct option *option; struct data_string data; #define OPTION_HAD_NULLS 0x00000001 u_int32_t flags; }; struct option_state { int refcnt; int universe_count; int site_universe; int site_code_min; void *universes [1]; }; /* A dhcp packet and the pointers to its option values. */ struct packet { struct dhcp_packet *raw; int refcnt; unsigned packet_length; int packet_type; unsigned char dhcpv6_msg_type; /* DHCPv6 message type */ /* DHCPv6 transaction ID */ unsigned char dhcpv6_transaction_id[3]; /* DHCPv6 relay information */ unsigned char dhcpv6_hop_count; struct in6_addr dhcpv6_link_address; struct in6_addr dhcpv6_peer_address; /* DHCPv6 packet containing this one, or NULL if none */ struct packet *dhcpv6_container_packet; int options_valid; int client_port; struct iaddr client_addr; struct interface_info *interface; /* Interface on which packet was received. */ struct hardware *haddr; /* Physical link address of local sender (maybe gateway). */ /* Information for relay agent options (see draft-ietf-dhc-agent-options-xx.txt). */ u_int8_t *circuit_id; /* Circuit ID of client connection. */ int circuit_id_len; u_int8_t *remote_id; /* Remote ID of client. */ int remote_id_len; int got_requested_address; /* True if client sent the dhcp-requested-address option. */ struct shared_network *shared_network; struct option_state *options; #if !defined (PACKET_MAX_CLASSES) # define PACKET_MAX_CLASSES 5 #endif int class_count; struct class *classes [PACKET_MAX_CLASSES]; int known; int authenticated; /* If we stash agent options onto the packet option state, to pretend * options we got in a previous exchange were still there, we need * to signal this in a reliable way. */ isc_boolean_t agent_options_stashed; /* * ISC_TRUE if packet received unicast (as opposed to multicast). * Only used in DHCPv6. */ isc_boolean_t unicast; }; /* A network interface's MAC address. */ struct hardware { u_int8_t hlen; u_int8_t hbuf[21]; }; #if defined(LDAP_CONFIGURATION) # define LDAP_BUFFER_SIZE 8192 # define LDAP_METHOD_STATIC 0 # define LDAP_METHOD_DYNAMIC 1 #if defined (LDAP_USE_SSL) # define LDAP_SSL_OFF 0 # define LDAP_SSL_ON 1 # define LDAP_SSL_TLS 2 # define LDAP_SSL_LDAPS 3 #endif /* This is a tree of the current configuration we are building from LDAP */ struct ldap_config_stack { LDAPMessage * res; /* Pointer returned from ldap_search */ LDAPMessage * ldent; /* Current item in LDAP that we're processing. in res */ int close_brace; /* Put a closing } after we're through with this item */ int processed; /* We set this flag if this base item has been processed. After this base item is processed, we can start processing the children */ struct ldap_config_stack *children; struct ldap_config_stack *next; }; #endif typedef enum { server_startup = 0, server_running = 1, server_shutdown = 2, server_hibernate = 3, server_awaken = 4 } control_object_state_t; typedef struct { OMAPI_OBJECT_PREAMBLE; control_object_state_t state; } dhcp_control_object_t; /* Lease states: */ #define FTS_FREE 1 #define FTS_ACTIVE 2 #define FTS_EXPIRED 3 #define FTS_RELEASED 4 #define FTS_ABANDONED 5 #define FTS_RESET 6 #define FTS_BACKUP 7 typedef u_int8_t binding_state_t; /* FTS_LAST is the highest value that is valid for a lease binding state. */ #define FTS_LAST FTS_BACKUP /* A dhcp lease declaration structure. */ struct lease { OMAPI_OBJECT_PREAMBLE; struct lease *next; struct lease *n_uid, *n_hw; struct iaddr ip_addr; TIME starts, ends, sort_time; char *client_hostname; struct binding_scope *scope; struct host_decl *host; struct subnet *subnet; struct pool *pool; struct class *billing_class; struct option_chain_head *agent_options; struct executable_statement *on_expiry; struct executable_statement *on_commit; struct executable_statement *on_release; unsigned char *uid; unsigned short uid_len; unsigned short uid_max; unsigned char uid_buf [7]; struct hardware hardware_addr; u_int8_t flags; # define STATIC_LEASE 1 # define BOOTP_LEASE 2 # define RESERVED_LEASE 4 # define MS_NULL_TERMINATION 8 # define ON_UPDATE_QUEUE 16 # define ON_ACK_QUEUE 32 # define ON_QUEUE (ON_UPDATE_QUEUE | ON_ACK_QUEUE) # define UNICAST_BROADCAST_HACK 64 # define ON_DEFERRED_QUEUE 128 /* Persistent flags are to be preserved on a given lease structure. */ # define PERSISTENT_FLAGS (ON_ACK_QUEUE | ON_UPDATE_QUEUE) /* Ephemeral flags are to be preserved on a given lease (copied etc). */ # define EPHEMERAL_FLAGS (MS_NULL_TERMINATION | \ UNICAST_BROADCAST_HACK | \ RESERVED_LEASE | \ BOOTP_LEASE) /* * The lease's binding state is its current state. The next binding * state is the next state this lease will move into by expiration, * or timers in general. The desired binding state is used on lease * updates; the caller is attempting to move the lease to the desired * binding state (and this may either succeed or fail, so the binding * state must be preserved). * * The 'rewind' binding state is used in failover processing. It * is used for an optimization when out of communications; it allows * the server to "rewind" a lease to the previous state acknowledged * by the peer, and progress forward from that point. */ binding_state_t binding_state; binding_state_t next_binding_state; binding_state_t desired_binding_state; binding_state_t rewind_binding_state; struct lease_state *state; /* * 'tsfp' is more of an 'effective' tsfp. It may be calculated from * stos+mclt for example if it's an expired lease and the server is * in partner-down state. 'atsfp' is zeroed whenever a lease is * updated - and only set when the peer acknowledges it. This * ensures every state change is transmitted. */ TIME tstp; /* Time sent to partner. */ TIME tsfp; /* Time sent from partner. */ TIME atsfp; /* Actual time sent from partner. */ TIME cltt; /* Client last transaction time. */ u_int32_t last_xid; /* XID we sent in this lease's BNDUPD */ struct lease *next_pending; /* * A pointer to the state of the ddns update for this lease. * It should be set while the update is in progress and cleared * when the update finishes. It can be used to cancel the * update if we want to do a different update. */ struct dhcp_ddns_cb *ddns_cb; }; struct lease_state { struct lease_state *next; struct interface_info *ip; struct packet *packet; /* The incoming packet. */ TIME offered_expiry; struct option_state *options; struct data_string parameter_request_list; int max_message_size; unsigned char expiry[4], renewal[4], rebind[4]; struct data_string filename, server_name; int got_requested_address; int got_server_identifier; struct shared_network *shared_network; /* Shared network of interface on which request arrived. */ u_int32_t xid; u_int16_t secs; u_int16_t bootp_flags; struct in_addr ciaddr; struct in_addr siaddr; struct in_addr giaddr; u_int8_t hops; u_int8_t offer; struct iaddr from; }; #define ROOT_GROUP 0 #define HOST_DECL 1 #define SHARED_NET_DECL 2 #define SUBNET_DECL 3 #define CLASS_DECL 4 #define GROUP_DECL 5 #define POOL_DECL 6 /* Possible modes in which discover_interfaces can run. */ #define DISCOVER_RUNNING 0 #define DISCOVER_SERVER 1 #define DISCOVER_UNCONFIGURED 2 #define DISCOVER_RELAY 3 #define DISCOVER_REQUESTED 4 /* DDNS_UPDATE_STYLE enumerations. */ #define DDNS_UPDATE_STYLE_NONE 0 #define DDNS_UPDATE_STYLE_AD_HOC 1 #define DDNS_UPDATE_STYLE_INTERIM 2 /* Server option names. */ #define SV_DEFAULT_LEASE_TIME 1 #define SV_MAX_LEASE_TIME 2 #define SV_MIN_LEASE_TIME 3 #define SV_BOOTP_LEASE_CUTOFF 4 #define SV_BOOTP_LEASE_LENGTH 5 #define SV_BOOT_UNKNOWN_CLIENTS 6 #define SV_DYNAMIC_BOOTP 7 #define SV_ALLOW_BOOTP 8 #define SV_ALLOW_BOOTING 9 #define SV_ONE_LEASE_PER_CLIENT 10 #define SV_GET_LEASE_HOSTNAMES 11 #define SV_USE_HOST_DECL_NAMES 12 #define SV_USE_LEASE_ADDR_FOR_DEFAULT_ROUTE 13 #define SV_MIN_SECS 14 #define SV_FILENAME 15 #define SV_SERVER_NAME 16 #define SV_NEXT_SERVER 17 #define SV_AUTHORITATIVE 18 #define SV_VENDOR_OPTION_SPACE 19 #define SV_ALWAYS_REPLY_RFC1048 20 #define SV_SITE_OPTION_SPACE 21 #define SV_ALWAYS_BROADCAST 22 #define SV_DDNS_DOMAIN_NAME 23 #define SV_DDNS_HOST_NAME 24 #define SV_DDNS_REV_DOMAIN_NAME 25 #define SV_LEASE_FILE_NAME 26 #define SV_PID_FILE_NAME 27 #define SV_DUPLICATES 28 #define SV_DECLINES 29 #define SV_DDNS_UPDATES 30 #define SV_OMAPI_PORT 31 #define SV_LOCAL_PORT 32 #define SV_LIMITED_BROADCAST_ADDRESS 33 #define SV_REMOTE_PORT 34 #define SV_LOCAL_ADDRESS 35 #define SV_OMAPI_KEY 36 #define SV_STASH_AGENT_OPTIONS 37 #define SV_DDNS_TTL 38 #define SV_DDNS_UPDATE_STYLE 39 #define SV_CLIENT_UPDATES 40 #define SV_UPDATE_OPTIMIZATION 41 #define SV_PING_CHECKS 42 #define SV_UPDATE_STATIC_LEASES 43 #define SV_LOG_FACILITY 44 #define SV_DO_FORWARD_UPDATES 45 #define SV_PING_TIMEOUT 46 #define SV_RESERVE_INFINITE 47 #define SV_DDNS_CONFLICT_DETECT 48 #define SV_LEASEQUERY 49 #define SV_ADAPTIVE_LEASE_TIME_THRESHOLD 50 #define SV_DO_REVERSE_UPDATES 51 #define SV_FQDN_REPLY 52 #define SV_PREFER_LIFETIME 53 #define SV_DHCPV6_LEASE_FILE_NAME 54 #define SV_DHCPV6_PID_FILE_NAME 55 #define SV_LIMIT_ADDRS_PER_IA 56 #define SV_LIMIT_PREFS_PER_IA 57 #define SV_DELAYED_ACK 58 #define SV_MAX_ACK_DELAY 59 #if defined(LDAP_CONFIGURATION) # define SV_LDAP_SERVER 60 # define SV_LDAP_PORT 61 # define SV_LDAP_USERNAME 62 # define SV_LDAP_PASSWORD 63 # define SV_LDAP_BASE_DN 64 # define SV_LDAP_METHOD 65 # define SV_LDAP_DEBUG_FILE 66 # define SV_LDAP_DHCP_SERVER_CN 67 # define SV_LDAP_REFERRALS 68 #if defined (LDAP_USE_SSL) # define SV_LDAP_SSL 69 # define SV_LDAP_TLS_REQCERT 70 # define SV_LDAP_TLS_CA_FILE 71 # define SV_LDAP_TLS_CA_DIR 72 # define SV_LDAP_TLS_CERT 73 # define SV_LDAP_TLS_KEY 74 # define SV_LDAP_TLS_CRLCHECK 75 # define SV_LDAP_TLS_CIPHERS 76 # define SV_LDAP_TLS_RANDFILE 77 #endif #endif #if !defined (DEFAULT_PING_TIMEOUT) # define DEFAULT_PING_TIMEOUT 1 #endif #if !defined (DEFAULT_DELAYED_ACK) # define DEFAULT_DELAYED_ACK 28 /* default SO_SNDBUF size / 576 bytes */ #endif #if !defined (DEFAULT_ACK_DELAY_SECS) # define DEFAULT_ACK_DELAY_SECS 0 #endif #if !defined (DEFAULT_ACK_DELAY_USECS) # define DEFAULT_ACK_DELAY_USECS 250000 /* 1/4 of a second */ #endif #if !defined (DEFAULT_MIN_ACK_DELAY_USECS) # define DEFAULT_MIN_ACK_DELAY_USECS 10000 /* 1/100 second */ #endif #if defined(LDAP_CONFIGURATION) # define SV_LDAP_SERVER 60 # define SV_LDAP_PORT 61 # define SV_LDAP_USERNAME 62 # define SV_LDAP_PASSWORD 63 # define SV_LDAP_BASE_DN 64 # define SV_LDAP_METHOD 65 # define SV_LDAP_DEBUG_FILE 66 # define SV_LDAP_DHCP_SERVER_CN 67 # define SV_LDAP_REFERRALS 68 #if defined (LDAP_USE_SSL) # define SV_LDAP_SSL 69 # define SV_LDAP_TLS_REQCERT 70 # define SV_LDAP_TLS_CA_FILE 71 # define SV_LDAP_TLS_CA_DIR 72 # define SV_LDAP_TLS_CERT 73 # define SV_LDAP_TLS_KEY 74 # define SV_LDAP_TLS_CRLCHECK 75 # define SV_LDAP_TLS_CIPHERS 76 # define SV_LDAP_TLS_RANDFILE 77 #endif #endif #if !defined (DEFAULT_DEFAULT_LEASE_TIME) # define DEFAULT_DEFAULT_LEASE_TIME 43200 #endif #if !defined (DEFAULT_MIN_LEASE_TIME) # define DEFAULT_MIN_LEASE_TIME 300 #endif #if !defined (DEFAULT_MAX_LEASE_TIME) # define DEFAULT_MAX_LEASE_TIME 86400 #endif #if !defined (DEFAULT_DDNS_TTL) # define DEFAULT_DDNS_TTL 3600 #endif #if !defined (MAX_DEFAULT_DDNS_TTL) # define MAX_DEFAULT_DDNS_TTL 3600 #endif #if !defined (MIN_LEASE_WRITE) # define MIN_LEASE_WRITE 15 #endif /* Client option names */ #define CL_TIMEOUT 1 #define CL_SELECT_INTERVAL 2 #define CL_REBOOT_TIMEOUT 3 #define CL_RETRY_INTERVAL 4 #define CL_BACKOFF_CUTOFF 5 #define CL_INITIAL_INTERVAL 6 #define CL_BOOTP_POLICY 7 #define CL_SCRIPT_NAME 8 #define CL_REQUESTED_OPTIONS 9 #define CL_REQUESTED_LEASE_TIME 10 #define CL_SEND_OPTIONS 11 #define CL_MEDIA 12 #define CL_REJECT_LIST 13 #ifndef CL_DEFAULT_TIMEOUT # define CL_DEFAULT_TIMEOUT 60 #endif #ifndef CL_DEFAULT_SELECT_INTERVAL # define CL_DEFAULT_SELECT_INTERVAL 0 #endif #ifndef CL_DEFAULT_REBOOT_TIMEOUT # define CL_DEFAULT_REBOOT_TIMEOUT 10 #endif #ifndef CL_DEFAULT_RETRY_INTERVAL # define CL_DEFAULT_RETRY_INTERVAL 300 #endif #ifndef CL_DEFAULT_BACKOFF_CUTOFF # define CL_DEFAULT_BACKOFF_CUTOFF 120 #endif #ifndef CL_DEFAULT_INITIAL_INTERVAL # define CL_DEFAULT_INITIAL_INTERVAL 10 #endif #ifndef CL_DEFAULT_BOOTP_POLICY # define CL_DEFAULT_BOOTP_POLICY P_ACCEPT #endif #ifndef CL_DEFAULT_REQUESTED_OPTIONS # define CL_DEFAULT_REQUESTED_OPTIONS \ { DHO_SUBNET_MASK, \ DHO_BROADCAST_ADDRESS, \ DHO_TIME_OFFSET, \ DHO_ROUTERS, \ DHO_DOMAIN_NAME, \ DHO_DOMAIN_NAME_SERVERS, \ DHO_HOST_NAME } #endif struct group_object { OMAPI_OBJECT_PREAMBLE; struct group_object *n_dynamic; struct group *group; char *name; int flags; #define GROUP_OBJECT_DELETED 1 #define GROUP_OBJECT_DYNAMIC 2 #define GROUP_OBJECT_STATIC 4 }; /* Group of declarations that share common parameters. */ struct group { struct group *next; int refcnt; struct group_object *object; struct subnet *subnet; struct shared_network *shared_network; int authoritative; struct executable_statement *statements; }; /* A dhcp host declaration structure. */ struct host_decl { OMAPI_OBJECT_PREAMBLE; struct host_decl *n_ipaddr; struct host_decl *n_dynamic; char *name; struct hardware interface; struct data_string client_identifier; struct option *host_id_option; struct data_string host_id; /* XXXSK: fixed_addr should be an array of iaddr values, not an option_cache, but it's referenced in a lot of places, so we'll leave it for now. */ struct option_cache *fixed_addr; struct iaddrcidrnetlist *fixed_prefix; struct group *group; struct group_object *named_group; struct data_string auth_key_id; int flags; #define HOST_DECL_DELETED 1 #define HOST_DECL_DYNAMIC 2 #define HOST_DECL_STATIC 4 }; struct permit { struct permit *next; enum { permit_unknown_clients, permit_known_clients, permit_authenticated_clients, permit_unauthenticated_clients, permit_all_clients, permit_dynamic_bootp_clients, permit_class, permit_after } type; struct class *class; TIME after; /* date after which this clause applies */ }; struct pool { OMAPI_OBJECT_PREAMBLE; struct pool *next; struct group *group; struct shared_network *shared_network; struct permit *permit_list; struct permit *prohibit_list; struct lease *active; struct lease *expired; struct lease *free; struct lease *backup; struct lease *abandoned; struct lease *reserved; TIME next_event_time; int lease_count; int free_leases; int backup_leases; int index; TIME valid_from; /* deny pool use before this date */ TIME valid_until; /* deny pool use after this date */ #if defined (FAILOVER_PROTOCOL) dhcp_failover_state_t *failover_peer; #endif }; struct shared_network { OMAPI_OBJECT_PREAMBLE; struct shared_network *next; char *name; #define SHARED_IMPLICIT 1 /* This network was synthesized. */ int flags; struct subnet *subnets; struct interface_info *interface; struct pool *pools; struct ipv6_pool **ipv6_pools; /* NULL-terminated array */ int last_ipv6_pool; /* offset of last IPv6 pool used to issue a lease */ struct group *group; #if defined (FAILOVER_PROTOCOL) dhcp_failover_state_t *failover_peer; #endif }; struct subnet { OMAPI_OBJECT_PREAMBLE; struct subnet *next_subnet; struct subnet *next_sibling; struct shared_network *shared_network; struct interface_info *interface; struct iaddr interface_address; struct iaddr net; struct iaddr netmask; int prefix_len; /* XXX: currently for IPv6 only */ struct group *group; }; struct collection { struct collection *next; const char *name; struct class *classes; }; /* Used as an argument to parse_clasS_decl() */ #define CLASS_TYPE_VENDOR 0 #define CLASS_TYPE_USER 1 #define CLASS_TYPE_CLASS 2 #define CLASS_TYPE_SUBCLASS 3 /* XXX classes must be reference-counted. */ struct class { OMAPI_OBJECT_PREAMBLE; struct class *nic; /* Next in collection. */ struct class *superclass; /* Set for spawned classes only. */ char *name; /* Not set for spawned classes. */ /* A class may be configured to permit a limited number of leases. */ int lease_limit; int leases_consumed; struct lease **billed_leases; /* If nonzero, class has not been saved since it was last modified. */ int dirty; /* Hash table containing subclasses. */ class_hash_t *hash; struct data_string hash_string; /* Expression used to match class. */ struct expression *expr; /* Expression used to compute subclass identifiers for spawning and to do subclass matching. */ struct expression *submatch; int spawning; struct group *group; /* Statements to execute if class matches. */ struct executable_statement *statements; #define CLASS_DECL_DELETED 1 #define CLASS_DECL_DYNAMIC 2 #define CLASS_DECL_STATIC 4 #define CLASS_DECL_SUBCLASS 8 int flags; }; /* DHCP client lease structure... */ struct client_lease { struct client_lease *next; /* Next lease in list. */ TIME expiry, renewal, rebind; /* Lease timeouts. */ struct iaddr address; /* Address being leased. */ char *server_name; /* Name of boot server. */ char *filename; /* Name of file we're supposed to boot. */ struct string_list *medium; /* Network medium. */ struct auth_key *key; /* Key used in basic DHCP authentication. */ unsigned int is_static : 1; /* If set, lease is from config file. */ unsigned int is_bootp: 1; /* If set, lease was acquired with BOOTP. */ struct option_state *options; /* Options supplied with lease. */ }; /* DHCPv6 lease structures */ struct dhc6_addr { struct dhc6_addr *next; struct iaddr address; u_int8_t plen; /* Address state flags. */ #define DHC6_ADDR_DEPREFFED 0x01 #define DHC6_ADDR_EXPIRED 0x02 u_int8_t flags; TIME starts; u_int32_t preferred_life; u_int32_t max_life; struct option_state *options; }; struct dhc6_ia { struct dhc6_ia *next; unsigned char iaid[4]; u_int16_t ia_type; TIME starts; u_int32_t renew; u_int32_t rebind; struct dhc6_addr *addrs; struct option_state *options; }; struct dhc6_lease { struct dhc6_lease *next; struct data_string server_id; isc_boolean_t released; int score; u_int8_t pref; unsigned char dhcpv6_transaction_id[3]; struct dhc6_ia *bindings; struct option_state *options; }; /* Possible states in which the client can be. */ enum dhcp_state { S_REBOOTING = 1, S_INIT = 2, S_SELECTING = 3, S_REQUESTING = 4, S_BOUND = 5, S_RENEWING = 6, S_REBINDING = 7, S_STOPPED = 8 }; /* Authentication and BOOTP policy possibilities (not all values work for each). */ enum policy { P_IGNORE, P_ACCEPT, P_PREFER, P_REQUIRE, P_DONT }; /* Configuration information from the config file... */ struct client_config { /* * When a message has been received, run these statements * over it. */ struct group *on_receipt; /* * When a message is sent, run these statements. */ struct group *on_transmission; struct option **required_options; /* Options that MUST be present. */ struct option **requested_options; /* Options to request (ORO/PRL). */ TIME timeout; /* Start to panic if we don't get a lease in this time period when SELECTING. */ TIME initial_delay; /* Set initial delay before first transmission. */ TIME initial_interval; /* All exponential backoff intervals start here. */ TIME retry_interval; /* If the protocol failed to produce an address before the timeout, try the protocol again after this many seconds. */ TIME select_interval; /* Wait this many seconds from the first DHCPDISCOVER before picking an offered lease. */ TIME reboot_timeout; /* When in INIT-REBOOT, wait this long before giving up and going to INIT. */ TIME backoff_cutoff; /* When doing exponential backoff, never back off to an interval longer than this amount. */ u_int32_t requested_lease; /* Requested lease time, if user doesn't configure one. */ struct string_list *media; /* Possible network media values. */ char *script_name; /* Name of config script. */ char *vendor_space_name; /* Name of config script. */ enum policy bootp_policy; /* Ignore, accept or prefer BOOTP responses. */ enum policy auth_policy; /* Require authentication, prefer authentication, or don't try to authenticate. */ struct string_list *medium; /* Current network medium. */ struct iaddrmatchlist *reject_list; /* Servers to reject. */ int omapi_port; /* port on which to accept OMAPI connections, or -1 for no listener. */ int do_forward_update; /* If nonzero, and if we have the information we need, update the A record for the address we get. */ }; /* Per-interface state used in the dhcp client... */ /* XXX: consider union {}'ing this for v4/v6. */ struct client_state { struct client_state *next; struct interface_info *interface; char *name; /* Common values. */ struct client_config *config; /* Client configuration. */ struct string_list *env; /* Client script environment. */ int envc; /* Number of entries in environment. */ struct option_state *sent_options; /* Options we sent. */ enum dhcp_state state; /* Current state for this interface. */ TIME last_write; /* Last time this state was written. */ /* DHCPv4 values. */ struct client_lease *active; /* Currently active lease. */ struct client_lease *new; /* New lease. */ struct client_lease *offered_leases; /* Leases offered to us. */ struct client_lease *leases; /* Leases we currently hold. */ struct client_lease *alias; /* Alias lease. */ struct iaddr destination; /* Where to send packet. */ u_int32_t xid; /* Transaction ID. */ u_int16_t secs; /* secs value from DHCPDISCOVER. */ TIME first_sending; /* When was first copy sent? */ TIME interval; /* What's the current resend interval? */ struct string_list *medium; /* Last media type tried. */ struct dhcp_packet packet; /* Outgoing DHCP packet. */ unsigned packet_length; /* Actual length of generated packet. */ struct iaddr requested_address; /* Address we would like to get. */ /* DHCPv6 values. */ unsigned char dhcpv6_transaction_id[3]; u_int8_t refresh_type; struct dhc6_lease *active_lease; struct dhc6_lease *old_lease; struct dhc6_lease *advertised_leases; struct dhc6_lease *selected_lease; struct dhc6_lease *held_leases; struct timeval start_time; u_int16_t elapsed; int txcount; /* See RFC3315 section 14. */ TIME RT; /* In hundredths of seconds. */ TIME IRT; /* In hundredths of seconds. */ TIME MRC; /* Count. */ TIME MRT; /* In hundredths of seconds. */ TIME MRD; /* In seconds, relative. */ TIME next_MRD; /* In seconds, absolute. */ /* Rather than a state, we use a function that shifts around * depending what stage of life the v6 state machine is in. * This is where incoming packets are dispatched to (sometimes * a no-op). */ void (*v6_handler)(struct packet *, struct client_state *); /* * A pointer to the state of the ddns update for this lease. * It should be set while the update is in progress and cleared * when the update finishes. It can be used to cancel the * update if we want to do a different update. */ struct dhcp_ddns_cb *ddns_cb; }; struct envadd_state { struct client_state *client; const char *prefix; }; struct dns_update_state { struct client_state *client; struct iaddr address; int dns_update_timeout; }; /* Information about each network interface. */ struct interface_info { OMAPI_OBJECT_PREAMBLE; struct interface_info *next; /* Next interface in list... */ struct shared_network *shared_network; /* Networks connected to this interface. */ struct hardware hw_address; /* Its physical address. */ struct in_addr *addresses; /* Addresses associated with this * interface. */ int address_count; /* Number of addresses stored. */ int address_max; /* Size of addresses buffer. */ struct in6_addr *v6addresses; /* IPv6 addresses associated with this interface. */ int v6address_count; /* Number of IPv6 addresses associated with this interface. */ int v6address_max; /* Maximum number of IPv6 addresses we can store in current buffer. */ u_int8_t *circuit_id; /* Circuit ID associated with this interface. */ unsigned circuit_id_len; /* Length of Circuit ID, if there is one. */ u_int8_t *remote_id; /* Remote ID associated with this interface (if any). */ unsigned remote_id_len; /* Length of Remote ID. */ char name [IFNAMSIZ]; /* Its name... */ int index; /* Its if_nametoindex(). */ int rfdesc; /* Its read file descriptor. */ int wfdesc; /* Its write file descriptor, if different. */ unsigned char *rbuf; /* Read buffer, if required. */ unsigned int rbuf_max; /* Size of read buffer. */ size_t rbuf_offset; /* Current offset into buffer. */ size_t rbuf_len; /* Length of data in buffer. */ struct ifreq *ifp; /* Pointer to ifreq struct. */ int configured; /* If set to 1, interface has at least * one valid IP address. */ u_int32_t flags; /* Control flags... */ #define INTERFACE_REQUESTED 1 #define INTERFACE_AUTOMATIC 2 #define INTERFACE_RUNNING 4 #define INTERFACE_DOWNSTREAM 8 #define INTERFACE_UPSTREAM 16 #define INTERFACE_STREAMS (INTERFACE_DOWNSTREAM | INTERFACE_UPSTREAM) /* Only used by DHCP client code. */ struct client_state *client; # if defined(USE_DLPI_SEND) || defined(USE_DLPI_RECEIVE) || \ defined(USE_DLPI_HWADDR) int dlpi_sap_length; struct hardware dlpi_broadcast_addr; # endif /* DLPI_SEND || DLPI_RECEIVE */ struct hardware anycast_mac_addr; }; struct hardware_link { struct hardware_link *next; char name [IFNAMSIZ]; struct hardware address; }; struct leasequeue { struct leasequeue *prev; struct leasequeue *next; struct lease *lease; }; typedef void (*tvref_t)(void *, void *, const char *, int); typedef void (*tvunref_t)(void *, const char *, int); struct timeout { struct timeout *next; struct timeval when; void (*func) (void *); void *what; tvref_t ref; tvunref_t unref; isc_timer_t *isc_timeout; }; struct eventqueue { struct eventqueue *next; void (*handler)(void *); }; struct protocol { struct protocol *next; int fd; void (*handler) (struct protocol *); void *local; }; struct dns_query; /* forward */ struct dns_wakeup { struct dns_wakeup *next; /* Next wakeup in chain. */ void (*func) (struct dns_query *); }; struct dns_question { u_int16_t type; /* Type of query. */ u_int16_t class; /* Class of query. */ unsigned char data [1]; /* Query data. */ }; struct dns_answer { u_int16_t type; /* Type of answer. */ u_int16_t class; /* Class of answer. */ int count; /* Number of answers. */ unsigned char *answers[1]; /* Pointers to answers. */ }; struct dns_query { struct dns_query *next; /* Next query in hash bucket. */ u_int32_t hash; /* Hash bucket index. */ TIME expiry; /* Query expiry time (zero if not yet answered. */ u_int16_t id; /* Query ID (also hash table index) */ caddr_t waiters; /* Pointer to list of things waiting on this query. */ struct dns_question *question; /* Question, internal format. */ struct dns_answer *answer; /* Answer, internal format. */ unsigned char *query; /* Query formatted for DNS server. */ unsigned len; /* Length of entire query. */ int sent; /* The query has been sent. */ struct dns_wakeup *wakeups; /* Wakeups to call if this query is answered. */ struct name_server *next_server; /* Next server to try. */ int backoff; /* Current backoff, in seconds. */ }; struct dns_zone { int refcnt; TIME timeout; char *name; struct option_cache *primary; struct option_cache *secondary; struct option_cache *primary6; struct option_cache *secondary6; struct auth_key *key; }; struct icmp_state { OMAPI_OBJECT_PREAMBLE; int socket; void (*icmp_handler) (struct iaddr, u_int8_t *, int); }; #include "ctrace.h" /* Bitmask of dhcp option codes. */ typedef unsigned char option_mask [16]; /* DHCP Option mask manipulation macros... */ #define OPTION_ZERO(mask) (memset (mask, 0, 16)) #define OPTION_SET(mask, bit) (mask [bit >> 8] |= (1 << (bit & 7))) #define OPTION_CLR(mask, bit) (mask [bit >> 8] &= ~(1 << (bit & 7))) #define OPTION_ISSET(mask, bit) (mask [bit >> 8] & (1 << (bit & 7))) #define OPTION_ISCLR(mask, bit) (!OPTION_ISSET (mask, bit)) /* An option occupies its length plus two header bytes (code and length) for every 255 bytes that must be stored. */ #define OPTION_SPACE(x) ((x) + 2 * ((x) / 255 + 1)) /* Default path to dhcpd config file. */ #ifdef DEBUG #undef _PATH_DHCPD_CONF #define _PATH_DHCPD_CONF "dhcpd.conf" #undef _PATH_DHCPD_DB #define _PATH_DHCPD_DB "dhcpd.leases" #undef _PATH_DHCPD6_DB #define _PATH_DHCPD6_DB "dhcpd6.leases" #undef _PATH_DHCPD_PID #define _PATH_DHCPD_PID "dhcpd.pid" #undef _PATH_DHCPD6_PID #define _PATH_DHCPD6_PID "dhcpd6.pid" #else /* !DEBUG */ #ifndef _PATH_DHCPD_CONF #define _PATH_DHCPD_CONF "/etc/dhcpd.conf" #endif /* DEBUG */ #ifndef _PATH_DHCPD_DB #define _PATH_DHCPD_DB LOCALSTATEDIR"/db/dhcpd.leases" #endif #ifndef _PATH_DHCPD6_DB #define _PATH_DHCPD6_DB LOCALSTATEDIR"/db/dhcpd6.leases" #endif #ifndef _PATH_DHCPD_PID #define _PATH_DHCPD_PID LOCALSTATEDIR"/run/dhcpd.pid" #endif #ifndef _PATH_DHCPD6_PID #define _PATH_DHCPD6_PID LOCALSTATEDIR"/run/dhcpd6.pid" #endif #endif /* DEBUG */ #ifndef _PATH_DHCLIENT_CONF #define _PATH_DHCLIENT_CONF "/etc/dhclient.conf" #endif #ifndef _PATH_DHCLIENT_SCRIPT #define _PATH_DHCLIENT_SCRIPT "/sbin/dhclient-script" #endif #ifndef _PATH_DHCLIENT_PID #define _PATH_DHCLIENT_PID LOCALSTATEDIR"/run/dhclient.pid" #endif #ifndef _PATH_DHCLIENT6_PID #define _PATH_DHCLIENT6_PID LOCALSTATEDIR"/run/dhclient6.pid" #endif #ifndef _PATH_DHCLIENT_DB #define _PATH_DHCLIENT_DB LOCALSTATEDIR"/db/dhclient.leases" #endif #ifndef _PATH_DHCLIENT6_DB #define _PATH_DHCLIENT6_DB LOCALSTATEDIR"/db/dhclient6.leases" #endif #ifndef _PATH_RESOLV_CONF #define _PATH_RESOLV_CONF "/etc/resolv.conf" #endif #ifndef _PATH_DHCRELAY_PID #define _PATH_DHCRELAY_PID LOCALSTATEDIR"/run/dhcrelay.pid" #endif #ifndef _PATH_DHCRELAY6_PID #define _PATH_DHCRELAY6_PID LOCALSTATEDIR"/run/dhcrelay6.pid" #endif #ifndef DHCPD_LOG_FACILITY #define DHCPD_LOG_FACILITY LOG_DAEMON #endif #define MAX_TIME 0x7fffffff #define MIN_TIME 0 /* these are referenced */ typedef struct hash_table ia_hash_t; typedef struct hash_table iasubopt_hash_t; /* IAADDR/IAPREFIX lease */ struct iasubopt { int refcnt; /* reference count */ struct in6_addr addr; /* IPv6 address/prefix */ u_int8_t plen; /* iaprefix prefix length */ binding_state_t state; /* state */ struct binding_scope *scope; /* "set var = value;" */ time_t hard_lifetime_end_time; /* time address expires */ time_t soft_lifetime_end_time; /* time ephemeral expires */ u_int32_t prefer; /* cached preferred lifetime */ u_int32_t valid; /* cached valid lifetime */ struct ia_xx *ia; /* IA for this lease */ struct ipv6_pool *ipv6_pool; /* pool for this lease */ /* * For now, just pick an arbitrary time to keep old hard leases * around (value in seconds). */ #define EXPIRED_IPV6_CLEANUP_TIME (60*60) int heap_index; /* index into heap, or -1 (internal use only) */ /* * A pointer to the state of the ddns update for this lease. * It should be set while the update is in progress and cleared * when the update finishes. It can be used to cancel the * update if we want to do a different update. */ struct dhcp_ddns_cb *ddns_cb; }; struct ia_xx { int refcnt; /* reference count */ struct data_string iaid_duid; /* from the client */ u_int16_t ia_type; /* IA_XX */ int num_iasubopt; /* number of IAADDR/PREFIX */ int max_iasubopt; /* space available for IAADDR/PREFIX */ time_t cltt; /* client last transaction time */ struct iasubopt **iasubopt; /* pointers to the IAADDR/IAPREFIXs */ }; extern ia_hash_t *ia_na_active; extern ia_hash_t *ia_ta_active; extern ia_hash_t *ia_pd_active; struct ipv6_pool { int refcnt; /* reference count */ u_int16_t pool_type; /* IA_xx */ struct in6_addr start_addr; /* first IPv6 address */ int bits; /* number of bits, CIDR style */ int units; /* allocation unit in bits */ iasubopt_hash_t *leases; /* non-free leases */ int num_active; /* count of active leases */ isc_heap_t *active_timeouts; /* timeouts for active leases */ int num_inactive; /* count of inactive leases */ isc_heap_t *inactive_timeouts; /* timeouts for expired or released leases */ struct shared_network *shared_network; /* shared_network for this pool */ struct subnet *subnet; /* subnet for this pool */ }; /* Flags and state for dhcp_ddns_cb_t */ #define DDNS_UPDATE_ADDR 0x01 #define DDNS_UPDATE_PTR 0x02 #define DDNS_INCLUDE_RRSET 0x04 #define DDNS_CONFLICT_OVERRIDE 0x08 #define DDNS_CLIENT_DID_UPDATE 0x10 #define DDNS_EXECUTE_NEXT 0x20 #define DDNS_ABORT 0x40 #define DDNS_STATIC_LEASE 0x80 #define DDNS_ACTIVE_LEASE 0x100 /* * The following two groups are separate and we could reuse * values but not reusing them may be useful in the future. */ #define DDNS_STATE_CLEANUP 0 // The previous step failed, cleanup #define DDNS_STATE_ADD_FW_NXDOMAIN 1 #define DDNS_STATE_ADD_FW_YXDHCID 2 #define DDNS_STATE_ADD_PTR 3 #define DDNS_STATE_REM_FW_YXDHCID 17 #define DDNS_STATE_REM_FW_NXRR 18 #define DDNS_STATE_REM_PTR 19 /* * Flags for the dns print function */ #define DDNS_PRINT_INBOUND 1 #define DDNS_PRINT_OUTBOUND 0 struct dhcp_ddns_cb; typedef void (*ddns_action_t)(struct dhcp_ddns_cb *ddns_cb, isc_result_t result); typedef struct dhcp_ddns_cb { struct data_string fwd_name; struct data_string rev_name; struct data_string dhcid; struct iaddr address; int address_type; unsigned long ttl; unsigned char zone_name[DHCP_MAXDNS_WIRE]; isc_sockaddrlist_t zone_server_list; isc_sockaddr_t zone_addrs[DHCP_MAXNS]; int zone_addr_count; struct dns_zone *zone; u_int16_t flags; TIME timeout; int state; ddns_action_t cur_func; struct dhcp_ddns_cb * next_op; /* Lease or client state that triggered the ddns operation */ void *lease; struct binding_scope **scope; void *transaction; void *dataspace; } dhcp_ddns_cb_t; extern struct ipv6_pool **pools; extern int num_pools; /* External definitions... */ HASH_FUNCTIONS_DECL (group, const char *, struct group_object, group_hash_t) HASH_FUNCTIONS_DECL (universe, const char *, struct universe, universe_hash_t) HASH_FUNCTIONS_DECL (option_name, const char *, struct option, option_name_hash_t) HASH_FUNCTIONS_DECL (option_code, const unsigned *, struct option, option_code_hash_t) HASH_FUNCTIONS_DECL (dns_zone, const char *, struct dns_zone, dns_zone_hash_t) HASH_FUNCTIONS_DECL(lease_ip, const unsigned char *, struct lease, lease_ip_hash_t) HASH_FUNCTIONS_DECL(lease_id, const unsigned char *, struct lease, lease_id_hash_t) HASH_FUNCTIONS_DECL (host, const unsigned char *, struct host_decl, host_hash_t) HASH_FUNCTIONS_DECL (class, const char *, struct class, class_hash_t) /* options.c */ extern struct option *vendor_cfg_option; int parse_options (struct packet *); int parse_option_buffer (struct option_state *, const unsigned char *, unsigned, struct universe *); struct universe *find_option_universe (struct option *, const char *); int parse_encapsulated_suboptions (struct option_state *, struct option *, const unsigned char *, unsigned, struct universe *, const char *); int cons_options (struct packet *, struct dhcp_packet *, struct lease *, struct client_state *, int, struct option_state *, struct option_state *, struct binding_scope **, int, int, int, struct data_string *, const char *); int fqdn_universe_decode (struct option_state *, const unsigned char *, unsigned, struct universe *); struct option_cache * lookup_fqdn6_option(struct universe *universe, struct option_state *options, unsigned code); void save_fqdn6_option(struct universe *universe, struct option_state *options, struct option_cache *oc, isc_boolean_t appendp); void delete_fqdn6_option(struct universe *universe, struct option_state *options, int code); void fqdn6_option_space_foreach(struct packet *packet, struct lease *lease, struct client_state *client_state, struct option_state *in_options, struct option_state *cfg_options, struct binding_scope **scope, struct universe *u, void *stuff, void (*func)(struct option_cache *, struct packet *, struct lease *, struct client_state *, struct option_state *, struct option_state *, struct binding_scope **, struct universe *, void *)); int fqdn6_option_space_encapsulate(struct data_string *result, struct packet *packet, struct lease *lease, struct client_state *client_state, struct option_state *in_options, struct option_state *cfg_options, struct binding_scope **scope, struct universe *universe); int fqdn6_universe_decode(struct option_state *options, const unsigned char *buffer, unsigned length, struct universe *u); int append_option(struct data_string *dst, struct universe *universe, struct option *option, struct data_string *src); int store_options(int *ocount, unsigned char *buffer, unsigned buflen, unsigned index, struct packet *packet, struct lease *lease, struct client_state *client_state, struct option_state *in_options, struct option_state *cfg_options, struct binding_scope **scope, unsigned *priority_list, int priority_len, unsigned first_cutoff, int second_cutoff, int terminate, const char *vuname); int store_options6(char *, int, struct option_state *, struct packet *, const int *, struct data_string *); int format_has_text(const char *); int format_min_length(const char *, struct option_cache *); const char *pretty_print_option (struct option *, const unsigned char *, unsigned, int, int); int pretty_escape(char **, char *, const unsigned char **, const unsigned char *); int get_option (struct data_string *, struct universe *, struct packet *, struct lease *, struct client_state *, struct option_state *, struct option_state *, struct option_state *, struct binding_scope **, unsigned, const char *, int); void set_option (struct universe *, struct option_state *, struct option_cache *, enum statement_op); struct option_cache *lookup_option (struct universe *, struct option_state *, unsigned); struct option_cache *lookup_hashed_option (struct universe *, struct option_state *, unsigned); struct option_cache *next_hashed_option(struct universe *, struct option_state *, struct option_cache *); int save_option_buffer (struct universe *, struct option_state *, struct buffer *, unsigned char *, unsigned, unsigned, int); int append_option_buffer(struct universe *, struct option_state *, struct buffer *, unsigned char *, unsigned, unsigned, int); void build_server_oro(struct data_string *, struct option_state *, const char *, int); void save_option(struct universe *, struct option_state *, struct option_cache *); void also_save_option(struct universe *, struct option_state *, struct option_cache *); void save_hashed_option(struct universe *, struct option_state *, struct option_cache *, isc_boolean_t appendp); void delete_option (struct universe *, struct option_state *, int); void delete_hashed_option (struct universe *, struct option_state *, int); int option_cache_dereference (struct option_cache **, const char *, int); int hashed_option_state_dereference (struct universe *, struct option_state *, const char *, int); int store_option (struct data_string *, struct universe *, struct packet *, struct lease *, struct client_state *, struct option_state *, struct option_state *, struct binding_scope **, struct option_cache *); int option_space_encapsulate (struct data_string *, struct packet *, struct lease *, struct client_state *, struct option_state *, struct option_state *, struct binding_scope **, struct data_string *); int hashed_option_space_encapsulate (struct data_string *, struct packet *, struct lease *, struct client_state *, struct option_state *, struct option_state *, struct binding_scope **, struct universe *); int nwip_option_space_encapsulate (struct data_string *, struct packet *, struct lease *, struct client_state *, struct option_state *, struct option_state *, struct binding_scope **, struct universe *); int fqdn_option_space_encapsulate (struct data_string *, struct packet *, struct lease *, struct client_state *, struct option_state *, struct option_state *, struct binding_scope **, struct universe *); void suboption_foreach (struct packet *, struct lease *, struct client_state *, struct option_state *, struct option_state *, struct binding_scope **, struct universe *, void *, void (*) (struct option_cache *, struct packet *, struct lease *, struct client_state *, struct option_state *, struct option_state *, struct binding_scope **, struct universe *, void *), struct option_cache *, const char *); void option_space_foreach (struct packet *, struct lease *, struct client_state *, struct option_state *, struct option_state *, struct binding_scope **, struct universe *, void *, void (*) (struct option_cache *, struct packet *, struct lease *, struct client_state *, struct option_state *, struct option_state *, struct binding_scope **, struct universe *, void *)); void hashed_option_space_foreach (struct packet *, struct lease *, struct client_state *, struct option_state *, struct option_state *, struct binding_scope **, struct universe *, void *, void (*) (struct option_cache *, struct packet *, struct lease *, struct client_state *, struct option_state *, struct option_state *, struct binding_scope **, struct universe *, void *)); int linked_option_get (struct data_string *, struct universe *, struct packet *, struct lease *, struct client_state *, struct option_state *, struct option_state *, struct option_state *, struct binding_scope **, unsigned); int linked_option_state_dereference (struct universe *, struct option_state *, const char *, int); void save_linked_option(struct universe *, struct option_state *, struct option_cache *, isc_boolean_t appendp); void linked_option_space_foreach (struct packet *, struct lease *, struct client_state *, struct option_state *, struct option_state *, struct binding_scope **, struct universe *, void *, void (*) (struct option_cache *, struct packet *, struct lease *, struct client_state *, struct option_state *, struct option_state *, struct binding_scope **, struct universe *, void *)); int linked_option_space_encapsulate (struct data_string *, struct packet *, struct lease *, struct client_state *, struct option_state *, struct option_state *, struct binding_scope **, struct universe *); void delete_linked_option (struct universe *, struct option_state *, int); struct option_cache *lookup_linked_option (struct universe *, struct option_state *, unsigned); void do_packet (struct interface_info *, struct dhcp_packet *, unsigned, unsigned int, struct iaddr, struct hardware *); void do_packet6(struct interface_info *, const char *, int, int, const struct iaddr *, isc_boolean_t); int packet6_len_okay(const char *, int); int add_option(struct option_state *options, unsigned int option_num, void *data, unsigned int data_len); /* dhcpd.c */ extern struct timeval cur_tv; #define cur_time cur_tv.tv_sec extern int ddns_update_style; extern const char *path_dhcpd_conf; extern const char *path_dhcpd_db; extern const char *path_dhcpd_pid; extern int dhcp_max_agent_option_packet_length; extern struct eventqueue *rw_queue_empty; int main(int, char **); void postconf_initialization(int); void postdb_startup(void); void cleanup (void); void lease_pinged (struct iaddr, u_int8_t *, int); void lease_ping_timeout (void *); int dhcpd_interface_setup_hook (struct interface_info *ip, struct iaddr *ia); extern enum dhcp_shutdown_state shutdown_state; isc_result_t dhcp_io_shutdown (omapi_object_t *, void *); isc_result_t dhcp_set_control_state (control_object_state_t oldstate, control_object_state_t newstate); #if defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT) void relinquish_ackqueue(void); #endif /* conflex.c */ isc_result_t new_parse (struct parse **, int, char *, unsigned, const char *, int); isc_result_t end_parse (struct parse **); isc_result_t save_parse_state(struct parse *cfile); isc_result_t restore_parse_state(struct parse *cfile); enum dhcp_token next_token (const char **, unsigned *, struct parse *); enum dhcp_token peek_token (const char **, unsigned *, struct parse *); enum dhcp_token next_raw_token(const char **rval, unsigned *rlen, struct parse *cfile); enum dhcp_token peek_raw_token(const char **rval, unsigned *rlen, struct parse *cfile); /* confpars.c */ void parse_trace_setup (void); isc_result_t readconf (void); isc_result_t read_conf_file (const char *, struct group *, int, int); #if defined (TRACING) void trace_conf_input (trace_type_t *, unsigned, char *); void trace_conf_stop (trace_type_t *ttype); #endif isc_result_t conf_file_subparse (struct parse *, struct group *, int); isc_result_t lease_file_subparse (struct parse *); int parse_statement (struct parse *, struct group *, int, struct host_decl *, int); #if defined (FAILOVER_PROTOCOL) void parse_failover_peer (struct parse *, struct group *, int); void parse_failover_state_declaration (struct parse *, dhcp_failover_state_t *); void parse_failover_state (struct parse *, enum failover_state *, TIME *); #endif int permit_list_match (struct permit *, struct permit *); void parse_pool_statement (struct parse *, struct group *, int); int parse_lbrace (struct parse *); void parse_host_declaration (struct parse *, struct group *); int parse_class_declaration (struct class **, struct parse *, struct group *, int); void parse_shared_net_declaration (struct parse *, struct group *); void parse_subnet_declaration (struct parse *, struct shared_network *); void parse_subnet6_declaration (struct parse *, struct shared_network *); void parse_group_declaration (struct parse *, struct group *); int parse_fixed_addr_param (struct option_cache **, struct parse *, enum dhcp_token); int parse_lease_declaration (struct lease **, struct parse *); int parse_ip6_addr(struct parse *, struct iaddr *); int parse_ip6_addr_expr(struct expression **, struct parse *); int parse_ip6_prefix(struct parse *, struct iaddr *, u_int8_t *); void parse_address_range (struct parse *, struct group *, int, struct pool *, struct lease **); void parse_address_range6(struct parse *cfile, struct group *group); void parse_prefix6(struct parse *cfile, struct group *group); void parse_fixed_prefix6(struct parse *cfile, struct host_decl *host_decl); void parse_ia_na_declaration(struct parse *); void parse_ia_ta_declaration(struct parse *); void parse_ia_pd_declaration(struct parse *); void parse_server_duid(struct parse *cfile); void parse_server_duid_conf(struct parse *cfile); /* ddns.c */ int ddns_updates(struct packet *, struct lease *, struct lease *, struct iasubopt *, struct iasubopt *, struct option_state *); isc_result_t ddns_removals(struct lease *, struct iasubopt *, struct dhcp_ddns_cb *, isc_boolean_t); #if defined (TRACING) void trace_ddns_init(void); #endif /* parse.c */ void add_enumeration (struct enumeration *); struct enumeration *find_enumeration (const char *, int); struct enumeration_value *find_enumeration_value (const char *, int, unsigned *, const char *); void skip_to_semi (struct parse *); void skip_to_rbrace (struct parse *, int); int parse_semi (struct parse *); int parse_string (struct parse *, char **, unsigned *); char *parse_host_name (struct parse *); int parse_ip_addr_or_hostname (struct expression **, struct parse *, int); void parse_hardware_param (struct parse *, struct hardware *); void parse_lease_time (struct parse *, TIME *); unsigned char *parse_numeric_aggregate (struct parse *, unsigned char *, unsigned *, int, int, unsigned); void convert_num (struct parse *, unsigned char *, const char *, int, unsigned); TIME parse_date (struct parse *); TIME parse_date_core(struct parse *); isc_result_t parse_option_name (struct parse *, int, int *, struct option **); void parse_option_space_decl (struct parse *); int parse_option_code_definition (struct parse *, struct option *); int parse_base64 (struct data_string *, struct parse *); int parse_cshl (struct data_string *, struct parse *); int parse_executable_statement (struct executable_statement **, struct parse *, int *, enum expression_context); int parse_executable_statements (struct executable_statement **, struct parse *, int *, enum expression_context); int parse_zone (struct dns_zone *, struct parse *); int parse_key (struct parse *); int parse_on_statement (struct executable_statement **, struct parse *, int *); int parse_switch_statement (struct executable_statement **, struct parse *, int *); int parse_case_statement (struct executable_statement **, struct parse *, int *, enum expression_context); int parse_if_statement (struct executable_statement **, struct parse *, int *); int parse_boolean_expression (struct expression **, struct parse *, int *); int parse_boolean (struct parse *); int parse_data_expression (struct expression **, struct parse *, int *); int parse_numeric_expression (struct expression **, struct parse *, int *); int parse_dns_expression (struct expression **, struct parse *, int *); int parse_non_binary (struct expression **, struct parse *, int *, enum expression_context); int parse_expression (struct expression **, struct parse *, int *, enum expression_context, struct expression **, enum expr_op); int parse_option_data(struct expression **expr, struct parse *cfile, int lookups, struct option *option); int parse_option_statement (struct executable_statement **, struct parse *, int, struct option *, enum statement_op); int parse_option_token (struct expression **, struct parse *, const char **, struct expression *, int, int); int parse_allow_deny (struct option_cache **, struct parse *, int); int parse_auth_key (struct data_string *, struct parse *); int parse_warn (struct parse *, const char *, ...) __attribute__((__format__(__printf__,2,3))); struct expression *parse_domain_list(struct parse *cfile, int); /* tree.c */ #if defined (NSUPDATE) extern struct __res_state resolver_state; extern int resolver_inited; #endif extern struct binding_scope *global_scope; pair cons (caddr_t, pair); int make_const_option_cache (struct option_cache **, struct buffer **, u_int8_t *, unsigned, struct option *, const char *, int); int make_host_lookup (struct expression **, const char *); int enter_dns_host (struct dns_host_entry **, const char *); int make_const_data (struct expression **, const unsigned char *, unsigned, int, int, const char *, int); int make_const_int (struct expression **, unsigned long); int make_concat (struct expression **, struct expression *, struct expression *); int make_encapsulation (struct expression **, struct data_string *); int make_substring (struct expression **, struct expression *, struct expression *, struct expression *); int make_limit (struct expression **, struct expression *, int); int make_let (struct executable_statement **, const char *); int option_cache (struct option_cache **, struct data_string *, struct expression *, struct option *, const char *, int); int evaluate_expression (struct binding_value **, struct packet *, struct lease *, struct client_state *, struct option_state *, struct option_state *, struct binding_scope **, struct expression *, const char *, int); int binding_value_dereference (struct binding_value **, const char *, int); #if defined (NSUPDATE_OLD) int evaluate_dns_expression (ns_updrec **, struct packet *, struct lease *, struct client_state *, struct option_state *, struct option_state *, struct binding_scope **, struct expression *); #endif int evaluate_boolean_expression (int *, struct packet *, struct lease *, struct client_state *, struct option_state *, struct option_state *, struct binding_scope **, struct expression *); int evaluate_data_expression (struct data_string *, struct packet *, struct lease *, struct client_state *, struct option_state *, struct option_state *, struct binding_scope **, struct expression *, const char *, int); int evaluate_numeric_expression (unsigned long *, struct packet *, struct lease *, struct client_state *, struct option_state *, struct option_state *, struct binding_scope **, struct expression *); int evaluate_option_cache (struct data_string *, struct packet *, struct lease *, struct client_state *, struct option_state *, struct option_state *, struct binding_scope **, struct option_cache *, const char *, int); int evaluate_boolean_option_cache (int *, struct packet *, struct lease *, struct client_state *, struct option_state *, struct option_state *, struct binding_scope **, struct option_cache *, const char *, int); int evaluate_boolean_expression_result (int *, struct packet *, struct lease *, struct client_state *, struct option_state *, struct option_state *, struct binding_scope **, struct expression *); void expression_dereference (struct expression **, const char *, int); int is_dns_expression (struct expression *); int is_boolean_expression (struct expression *); int is_data_expression (struct expression *); int is_numeric_expression (struct expression *); int is_compound_expression (struct expression *); int op_precedence (enum expr_op, enum expr_op); enum expression_context expression_context (struct expression *); enum expression_context op_context (enum expr_op); int write_expression (FILE *, struct expression *, int, int, int); struct binding *find_binding (struct binding_scope *, const char *); int free_bindings (struct binding_scope *, const char *, int); int binding_scope_dereference (struct binding_scope **, const char *, int); int fundef_dereference (struct fundef **, const char *, int); int data_subexpression_length (int *, struct expression *); int expr_valid_for_context (struct expression *, enum expression_context); struct binding *create_binding (struct binding_scope **, const char *); int bind_ds_value (struct binding_scope **, const char *, struct data_string *); int find_bound_string (struct data_string *, struct binding_scope *, const char *); int unset (struct binding_scope *, const char *); int data_string_sprintfa(struct data_string *ds, const char *fmt, ...); /* dhcp.c */ extern int outstanding_pings; extern int max_outstanding_acks; extern int max_ack_delay_secs; extern int max_ack_delay_usecs; void dhcp (struct packet *); void dhcpdiscover (struct packet *, int); void dhcprequest (struct packet *, int, struct lease *); void dhcprelease (struct packet *, int); void dhcpdecline (struct packet *, int); void dhcpinform (struct packet *, int); void nak_lease (struct packet *, struct iaddr *cip); void ack_lease (struct packet *, struct lease *, unsigned int, TIME, char *, int, struct host_decl *); void delayed_ack_enqueue(struct lease *); void commit_leases_readerdry(void *); void flush_ackqueue(void *); void dhcp_reply (struct lease *); int find_lease (struct lease **, struct packet *, struct shared_network *, int *, int *, struct lease *, const char *, int); int mockup_lease (struct lease **, struct packet *, struct shared_network *, struct host_decl *); void static_lease_dereference (struct lease *, const char *, int); int allocate_lease (struct lease **, struct packet *, struct pool *, int *); int permitted (struct packet *, struct permit *); int locate_network (struct packet *); int parse_agent_information_option (struct packet *, int, u_int8_t *); unsigned cons_agent_information_options (struct option_state *, struct dhcp_packet *, unsigned, unsigned); void get_server_source_address(struct in_addr *from, struct option_state *options, struct packet *packet); /* dhcpleasequery.c */ void dhcpleasequery (struct packet *, int); void dhcpv6_leasequery (struct data_string *, struct packet *); /* dhcpv6.c */ isc_boolean_t server_duid_isset(void); void copy_server_duid(struct data_string *ds, const char *file, int line); void set_server_duid(struct data_string *new_duid); isc_result_t set_server_duid_from_option(void); void set_server_duid_type(int type); isc_result_t generate_new_server_duid(void); isc_result_t get_client_id(struct packet *, struct data_string *); void dhcpv6(struct packet *); /* bootp.c */ void bootp (struct packet *); /* memory.c */ extern int (*group_write_hook) (struct group_object *); extern struct group *root_group; extern group_hash_t *group_name_hash; isc_result_t delete_group (struct group_object *, int); isc_result_t supersede_group (struct group_object *, int); int clone_group (struct group **, struct group *, const char *, int); int write_group (struct group_object *); /* salloc.c */ void relinquish_lease_hunks (void); struct lease *new_leases (unsigned, const char *, int); #if defined (DEBUG_MEMORY_LEAKAGE) || \ defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT) void relinquish_free_lease_states (void); #endif OMAPI_OBJECT_ALLOC_DECL (lease, struct lease, dhcp_type_lease) OMAPI_OBJECT_ALLOC_DECL (class, struct class, dhcp_type_class) OMAPI_OBJECT_ALLOC_DECL (subclass, struct class, dhcp_type_subclass) OMAPI_OBJECT_ALLOC_DECL (pool, struct pool, dhcp_type_pool) OMAPI_OBJECT_ALLOC_DECL (host, struct host_decl, dhcp_type_host) /* alloc.c */ OMAPI_OBJECT_ALLOC_DECL (subnet, struct subnet, dhcp_type_subnet) OMAPI_OBJECT_ALLOC_DECL (shared_network, struct shared_network, dhcp_type_shared_network) OMAPI_OBJECT_ALLOC_DECL (group_object, struct group_object, dhcp_type_group) OMAPI_OBJECT_ALLOC_DECL (dhcp_control, dhcp_control_object_t, dhcp_type_control) #if defined (DEBUG_MEMORY_LEAKAGE) || \ defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT) void relinquish_free_pairs (void); void relinquish_free_expressions (void); void relinquish_free_binding_values (void); void relinquish_free_option_caches (void); void relinquish_free_packets (void); #endif int option_chain_head_allocate (struct option_chain_head **, const char *, int); int option_chain_head_reference (struct option_chain_head **, struct option_chain_head *, const char *, int); int option_chain_head_dereference (struct option_chain_head **, const char *, int); int group_allocate (struct group **, const char *, int); int group_reference (struct group **, struct group *, const char *, int); int group_dereference (struct group **, const char *, int); struct dhcp_packet *new_dhcp_packet (const char *, int); struct protocol *new_protocol (const char *, int); struct lease_state *new_lease_state (const char *, int); struct domain_search_list *new_domain_search_list (const char *, int); struct name_server *new_name_server (const char *, int); void free_name_server (struct name_server *, const char *, int); struct option *new_option (const char *, const char *, int); int option_reference(struct option **dest, struct option *src, const char * file, int line); int option_dereference(struct option **dest, const char *file, int line); struct universe *new_universe (const char *, int); void free_universe (struct universe *, const char *, int); void free_domain_search_list (struct domain_search_list *, const char *, int); void free_lease_state (struct lease_state *, const char *, int); void free_protocol (struct protocol *, const char *, int); void free_dhcp_packet (struct dhcp_packet *, const char *, int); struct client_lease *new_client_lease (const char *, int); void free_client_lease (struct client_lease *, const char *, int); struct permit *new_permit (const char *, int); void free_permit (struct permit *, const char *, int); pair new_pair (const char *, int); void free_pair (pair, const char *, int); int expression_allocate (struct expression **, const char *, int); int expression_reference (struct expression **, struct expression *, const char *, int); void free_expression (struct expression *, const char *, int); int binding_value_allocate (struct binding_value **, const char *, int); int binding_value_reference (struct binding_value **, struct binding_value *, const char *, int); void free_binding_value (struct binding_value *, const char *, int); int fundef_allocate (struct fundef **, const char *, int); int fundef_reference (struct fundef **, struct fundef *, const char *, int); int option_cache_allocate (struct option_cache **, const char *, int); int option_cache_reference (struct option_cache **, struct option_cache *, const char *, int); int buffer_allocate (struct buffer **, unsigned, const char *, int); int buffer_reference (struct buffer **, struct buffer *, const char *, int); int buffer_dereference (struct buffer **, const char *, int); int dns_host_entry_allocate (struct dns_host_entry **, const char *, const char *, int); int dns_host_entry_reference (struct dns_host_entry **, struct dns_host_entry *, const char *, int); int dns_host_entry_dereference (struct dns_host_entry **, const char *, int); int option_state_allocate (struct option_state **, const char *, int); int option_state_reference (struct option_state **, struct option_state *, const char *, int); int option_state_dereference (struct option_state **, const char *, int); void data_string_copy(struct data_string *, const struct data_string *, const char *, int); void data_string_forget (struct data_string *, const char *, int); void data_string_truncate (struct data_string *, int); int executable_statement_allocate (struct executable_statement **, const char *, int); int executable_statement_reference (struct executable_statement **, struct executable_statement *, const char *, int); int packet_allocate (struct packet **, const char *, int); int packet_reference (struct packet **, struct packet *, const char *, int); int packet_dereference (struct packet **, const char *, int); int binding_scope_allocate (struct binding_scope **, const char *, int); int binding_scope_reference (struct binding_scope **, struct binding_scope *, const char *, int); int dns_zone_allocate (struct dns_zone **, const char *, int); int dns_zone_reference (struct dns_zone **, struct dns_zone *, const char *, int); /* print.c */ #define DEFAULT_TIME_FORMAT 0 #define LOCAL_TIME_FORMAT 1 extern int db_time_format; char *quotify_string (const char *, const char *, int); char *quotify_buf (const unsigned char *, unsigned, const char *, int); char *print_base64 (const unsigned char *, unsigned, const char *, int); char *print_hw_addr (const int, const int, const unsigned char *); void print_lease (struct lease *); void dump_raw (const unsigned char *, unsigned); void dump_packet_option (struct option_cache *, struct packet *, struct lease *, struct client_state *, struct option_state *, struct option_state *, struct binding_scope **, struct universe *, void *); void dump_packet (struct packet *); void hash_dump (struct hash_table *); char *print_hex (unsigned, const u_int8_t *, unsigned, unsigned); void print_hex_only (unsigned, const u_int8_t *, unsigned, char *); void print_hex_or_string (unsigned, const u_int8_t *, unsigned, char *); #define print_hex_1(len, data, limit) print_hex(len, data, limit, 0) #define print_hex_2(len, data, limit) print_hex(len, data, limit, 1) #define print_hex_3(len, data, limit) print_hex(len, data, limit, 2) char *print_dotted_quads (unsigned, const u_int8_t *); char *print_dec_1 (unsigned long); char *print_dec_2 (unsigned long); void print_expression (const char *, struct expression *); int token_print_indent_concat (FILE *, int, int, const char *, const char *, ...); int token_indent_data_string (FILE *, int, int, const char *, const char *, struct data_string *); int token_print_indent (FILE *, int, int, const char *, const char *, const char *); void indent_spaces (FILE *, int); #if defined (NSUPDATE) void print_dns_status (int, struct dhcp_ddns_cb *, isc_result_t); #endif const char *print_time(TIME); void get_hw_addr(const char *name, struct hardware *hw); /* socket.c */ #if defined (USE_SOCKET_SEND) || defined (USE_SOCKET_RECEIVE) \ || defined (USE_SOCKET_FALLBACK) int if_register_socket(struct interface_info *, int, int *); #endif #if defined (USE_SOCKET_FALLBACK) && !defined (USE_SOCKET_SEND) void if_reinitialize_fallback (struct interface_info *); void if_register_fallback (struct interface_info *); ssize_t send_fallback (struct interface_info *, struct packet *, struct dhcp_packet *, size_t, struct in_addr, struct sockaddr_in *, struct hardware *); ssize_t send_fallback6(struct interface_info *, struct packet *, struct dhcp_packet *, size_t, struct in6_addr, struct sockaddr_in6 *, struct hardware *); #endif #ifdef USE_SOCKET_SEND void if_reinitialize_send (struct interface_info *); void if_register_send (struct interface_info *); void if_deregister_send (struct interface_info *); ssize_t send_packet (struct interface_info *, struct packet *, struct dhcp_packet *, size_t, struct in_addr, struct sockaddr_in *, struct hardware *); #endif ssize_t send_packet6(struct interface_info *, const unsigned char *, size_t, struct sockaddr_in6 *); #ifdef USE_SOCKET_RECEIVE void if_reinitialize_receive (struct interface_info *); void if_register_receive (struct interface_info *); void if_deregister_receive (struct interface_info *); ssize_t receive_packet (struct interface_info *, unsigned char *, size_t, struct sockaddr_in *, struct hardware *); #endif #if defined (USE_SOCKET_FALLBACK) isc_result_t fallback_discard (omapi_object_t *); #endif #if defined (USE_SOCKET_SEND) int can_unicast_without_arp (struct interface_info *); int can_receive_unicast_unconfigured (struct interface_info *); int supports_multiple_interfaces (struct interface_info *); void maybe_setup_fallback (void); #endif void if_register6(struct interface_info *info, int do_multicast); ssize_t receive_packet6(struct interface_info *interface, unsigned char *buf, size_t len, struct sockaddr_in6 *from, struct in6_addr *to_addr, unsigned int *if_index); void if_deregister6(struct interface_info *info); /* bpf.c */ #if defined (USE_BPF_SEND) || defined (USE_BPF_RECEIVE) int if_register_bpf (struct interface_info *); #endif #ifdef USE_BPF_SEND void if_reinitialize_send (struct interface_info *); void if_register_send (struct interface_info *); void if_deregister_send (struct interface_info *); ssize_t send_packet (struct interface_info *, struct packet *, struct dhcp_packet *, size_t, struct in_addr, struct sockaddr_in *, struct hardware *); #endif #ifdef USE_BPF_RECEIVE void if_reinitialize_receive (struct interface_info *); void if_register_receive (struct interface_info *); void if_deregister_receive (struct interface_info *); ssize_t receive_packet (struct interface_info *, unsigned char *, size_t, struct sockaddr_in *, struct hardware *); #endif #if defined (USE_BPF_SEND) int can_unicast_without_arp (struct interface_info *); int can_receive_unicast_unconfigured (struct interface_info *); int supports_multiple_interfaces (struct interface_info *); void maybe_setup_fallback (void); #endif /* lpf.c */ #if defined (USE_LPF_SEND) || defined (USE_LPF_RECEIVE) int if_register_lpf (struct interface_info *); #endif #ifdef USE_LPF_SEND void if_reinitialize_send (struct interface_info *); void if_register_send (struct interface_info *); void if_deregister_send (struct interface_info *); ssize_t send_packet (struct interface_info *, struct packet *, struct dhcp_packet *, size_t, struct in_addr, struct sockaddr_in *, struct hardware *); #endif #ifdef USE_LPF_RECEIVE void if_reinitialize_receive (struct interface_info *); void if_register_receive (struct interface_info *); void if_deregister_receive (struct interface_info *); ssize_t receive_packet (struct interface_info *, unsigned char *, size_t, struct sockaddr_in *, struct hardware *); #endif #if defined (USE_LPF_SEND) int can_unicast_without_arp (struct interface_info *); int can_receive_unicast_unconfigured (struct interface_info *); int supports_multiple_interfaces (struct interface_info *); void maybe_setup_fallback (void); #endif /* nit.c */ #if defined (USE_NIT_SEND) || defined (USE_NIT_RECEIVE) int if_register_nit (struct interface_info *); #endif #ifdef USE_NIT_SEND void if_reinitialize_send (struct interface_info *); void if_register_send (struct interface_info *); void if_deregister_send (struct interface_info *); ssize_t send_packet (struct interface_info *, struct packet *, struct dhcp_packet *, size_t, struct in_addr, struct sockaddr_in *, struct hardware *); #endif #ifdef USE_NIT_RECEIVE void if_reinitialize_receive (struct interface_info *); void if_register_receive (struct interface_info *); void if_deregister_receive (struct interface_info *); ssize_t receive_packet (struct interface_info *, unsigned char *, size_t, struct sockaddr_in *, struct hardware *); #endif #if defined (USE_NIT_SEND) int can_unicast_without_arp (struct interface_info *); int can_receive_unicast_unconfigured (struct interface_info *); int supports_multiple_interfaces (struct interface_info *); void maybe_setup_fallback (void); #endif /* dlpi.c */ #if defined (USE_DLPI_SEND) || defined (USE_DLPI_RECEIVE) int if_register_dlpi (struct interface_info *); #endif #ifdef USE_DLPI_SEND int can_unicast_without_arp (struct interface_info *); int can_receive_unicast_unconfigured (struct interface_info *); void if_reinitialize_send (struct interface_info *); void if_register_send (struct interface_info *); void if_deregister_send (struct interface_info *); ssize_t send_packet (struct interface_info *, struct packet *, struct dhcp_packet *, size_t, struct in_addr, struct sockaddr_in *, struct hardware *); int supports_multiple_interfaces (struct interface_info *); void maybe_setup_fallback (void); #endif #ifdef USE_DLPI_RECEIVE void if_reinitialize_receive (struct interface_info *); void if_register_receive (struct interface_info *); void if_deregister_receive (struct interface_info *); ssize_t receive_packet (struct interface_info *, unsigned char *, size_t, struct sockaddr_in *, struct hardware *); #endif /* raw.c */ #ifdef USE_RAW_SEND void if_reinitialize_send (struct interface_info *); void if_register_send (struct interface_info *); void if_deregister_send (struct interface_info *); ssize_t send_packet (struct interface_info *, struct packet *, struct dhcp_packet *, size_t, struct in_addr, struct sockaddr_in *, struct hardware *); int can_unicast_without_arp (struct interface_info *); int can_receive_unicast_unconfigured (struct interface_info *); int supports_multiple_interfaces (struct interface_info *); void maybe_setup_fallback (void); #endif /* discover.c */ extern struct interface_info *interfaces, *dummy_interfaces, *fallback_interface; extern struct protocol *protocols; extern int quiet_interface_discovery; isc_result_t interface_setup (void); void interface_trace_setup (void); extern struct in_addr limited_broadcast; extern int local_family; extern struct in_addr local_address; extern struct in6_addr local_address6; extern u_int16_t local_port; extern u_int16_t remote_port; extern int (*dhcp_interface_setup_hook) (struct interface_info *, struct iaddr *); extern int (*dhcp_interface_discovery_hook) (struct interface_info *); extern isc_result_t (*dhcp_interface_startup_hook) (struct interface_info *); extern void (*bootp_packet_handler) (struct interface_info *, struct dhcp_packet *, unsigned, unsigned int, struct iaddr, struct hardware *); extern void (*dhcpv6_packet_handler)(struct interface_info *, const char *, int, int, const struct iaddr *, isc_boolean_t); extern struct timeout *timeouts; extern omapi_object_type_t *dhcp_type_interface; #if defined (TRACING) extern trace_type_t *interface_trace; extern trace_type_t *inpacket_trace; extern trace_type_t *outpacket_trace; #endif extern struct interface_info **interface_vector; extern int interface_count; extern int interface_max; isc_result_t interface_initialize(omapi_object_t *, const char *, int); void discover_interfaces(int); int setup_fallback (struct interface_info **, const char *, int); int if_readsocket (omapi_object_t *); void reinitialize_interfaces (void); /* dispatch.c */ void set_time(TIME); struct timeval *process_outstanding_timeouts (struct timeval *); void dispatch (void); isc_result_t got_one(omapi_object_t *); isc_result_t got_one_v6(omapi_object_t *); isc_result_t interface_set_value (omapi_object_t *, omapi_object_t *, omapi_data_string_t *, omapi_typed_data_t *); isc_result_t interface_get_value (omapi_object_t *, omapi_object_t *, omapi_data_string_t *, omapi_value_t **); isc_result_t interface_destroy (omapi_object_t *, const char *, int); isc_result_t interface_signal_handler (omapi_object_t *, const char *, va_list); isc_result_t interface_stuff_values (omapi_object_t *, omapi_object_t *, omapi_object_t *); void add_timeout (struct timeval *, void (*) (void *), void *, tvref_t, tvunref_t); void cancel_timeout (void (*) (void *), void *); void cancel_all_timeouts (void); void relinquish_timeouts (void); OMAPI_OBJECT_ALLOC_DECL (interface, struct interface_info, dhcp_type_interface) /* tables.c */ extern char *default_option_format; extern struct universe dhcp_universe; extern struct universe dhcpv6_universe; extern struct universe nwip_universe; extern struct universe fqdn_universe; extern struct universe vsio_universe; extern int dhcp_option_default_priority_list []; extern int dhcp_option_default_priority_list_count; extern const char *hardware_types [256]; extern int universe_count, universe_max; extern struct universe **universes; extern universe_hash_t *universe_hash; void initialize_common_option_spaces (void); extern struct universe *config_universe; /* stables.c */ #if defined (FAILOVER_PROTOCOL) extern failover_option_t null_failover_option; extern failover_option_t skip_failover_option; extern struct failover_option_info ft_options []; extern u_int32_t fto_allowed []; extern int ft_sizes []; extern const char *dhcp_flink_state_names []; #endif extern const char *binding_state_names []; extern struct universe agent_universe; extern struct universe server_universe; extern struct enumeration ddns_styles; extern struct enumeration syslog_enum; void initialize_server_option_spaces (void); /* inet.c */ struct iaddr subnet_number (struct iaddr, struct iaddr); struct iaddr ip_addr (struct iaddr, struct iaddr, u_int32_t); struct iaddr broadcast_addr (struct iaddr, struct iaddr); u_int32_t host_addr (struct iaddr, struct iaddr); int addr_eq (struct iaddr, struct iaddr); int addr_match(struct iaddr *, struct iaddrmatch *); int addr_cmp(const struct iaddr *a1, const struct iaddr *a2); int addr_or(struct iaddr *result, const struct iaddr *a1, const struct iaddr *a2); int addr_and(struct iaddr *result, const struct iaddr *a1, const struct iaddr *a2); isc_boolean_t is_cidr_mask_valid(const struct iaddr *addr, int bits); isc_result_t range2cidr(struct iaddrcidrnetlist **result, const struct iaddr *lo, const struct iaddr *hi); isc_result_t free_iaddrcidrnetlist(struct iaddrcidrnetlist **result); const char *piaddr (struct iaddr); char *piaddrmask(struct iaddr *, struct iaddr *); char *piaddrcidr(const struct iaddr *, unsigned int); u_int16_t validate_port(char *); /* dhclient.c */ extern int nowait; extern int wanted_ia_na; extern int wanted_ia_ta; extern int wanted_ia_pd; extern const char *path_dhclient_conf; extern const char *path_dhclient_db; extern const char *path_dhclient_pid; extern char *path_dhclient_script; extern int interfaces_requested; extern struct data_string default_duid; extern int duid_type; extern struct client_config top_level_config; void dhcpoffer (struct packet *); void dhcpack (struct packet *); void dhcpnak (struct packet *); void send_discover (void *); void send_request (void *); void send_release (void *); void send_decline (void *); void state_reboot (void *); void state_init (void *); void state_selecting (void *); void state_requesting (void *); void state_bound (void *); void state_stop (void *); void state_panic (void *); void bind_lease (struct client_state *); void make_client_options (struct client_state *, struct client_lease *, u_int8_t *, struct option_cache *, struct iaddr *, struct option **, struct option_state **); void make_discover (struct client_state *, struct client_lease *); void make_request (struct client_state *, struct client_lease *); void make_decline (struct client_state *, struct client_lease *); void make_release (struct client_state *, struct client_lease *); void destroy_client_lease (struct client_lease *); void rewrite_client_leases (void); void write_lease_option (struct option_cache *, struct packet *, struct lease *, struct client_state *, struct option_state *, struct option_state *, struct binding_scope **, struct universe *, void *); int write_client_lease (struct client_state *, struct client_lease *, int, int); isc_result_t write_client6_lease(struct client_state *client, struct dhc6_lease *lease, int rewrite, int sync); int dhcp_option_ev_name (char *, size_t, struct option *); void script_init (struct client_state *, const char *, struct string_list *); void client_option_envadd (struct option_cache *, struct packet *, struct lease *, struct client_state *, struct option_state *, struct option_state *, struct binding_scope **, struct universe *, void *); void script_write_params (struct client_state *, const char *, struct client_lease *); int script_go (struct client_state *); void client_envadd (struct client_state *, const char *, const char *, const char *, ...) __attribute__((__format__(__printf__,4,5))); struct client_lease *packet_to_lease (struct packet *, struct client_state *); void go_daemon (void); void write_client_pid_file (void); void client_location_changed (void); void do_release (struct client_state *); int dhclient_interface_shutdown_hook (struct interface_info *); int dhclient_interface_discovery_hook (struct interface_info *); isc_result_t dhclient_interface_startup_hook (struct interface_info *); void dhclient_schedule_updates(struct client_state *client, struct iaddr *addr, int offset); void client_dns_update_timeout (void *cp); isc_result_t client_dns_update(struct client_state *client, dhcp_ddns_cb_t *ddns_cb); void client_dns_remove(struct client_state *client, struct iaddr *addr); void dhcpv4_client_assignments(void); void dhcpv6_client_assignments(void); /* dhc6.c */ void form_duid(struct data_string *duid, const char *file, int line); void dhc6_lease_destroy(struct dhc6_lease **src, const char *file, int line); void start_init6(struct client_state *client); void start_info_request6(struct client_state *client); void start_confirm6(struct client_state *client); void start_release6(struct client_state *client); void start_selecting6(struct client_state *client); void unconfigure6(struct client_state *client, const char *reason); /* db.c */ int write_lease (struct lease *); int write_host (struct host_decl *); int write_server_duid(void); #if defined (FAILOVER_PROTOCOL) int write_failover_state (dhcp_failover_state_t *); #endif int db_printable (const unsigned char *); int db_printable_len (const unsigned char *, unsigned); isc_result_t write_named_billing_class(const void *, unsigned, void *); void write_billing_classes (void); int write_billing_class (struct class *); void commit_leases_timeout (void *); void commit_leases_readerdry(void *); int commit_leases (void); int commit_leases_timed (void); void db_startup (int); int new_lease_file (void); int group_writer (struct group_object *); int write_ia(const struct ia_xx *); /* packet.c */ u_int32_t checksum (unsigned char *, unsigned, u_int32_t); u_int32_t wrapsum (u_int32_t); void assemble_hw_header (struct interface_info *, unsigned char *, unsigned *, struct hardware *); void assemble_udp_ip_header (struct interface_info *, unsigned char *, unsigned *, u_int32_t, u_int32_t, u_int32_t, unsigned char *, unsigned); ssize_t decode_hw_header (struct interface_info *, unsigned char *, unsigned, struct hardware *); ssize_t decode_udp_ip_header (struct interface_info *, unsigned char *, unsigned, struct sockaddr_in *, unsigned, unsigned *); /* ethernet.c */ void assemble_ethernet_header (struct interface_info *, unsigned char *, unsigned *, struct hardware *); ssize_t decode_ethernet_header (struct interface_info *, unsigned char *, unsigned, struct hardware *); /* tr.c */ void assemble_tr_header (struct interface_info *, unsigned char *, unsigned *, struct hardware *); ssize_t decode_tr_header (struct interface_info *, unsigned char *, unsigned, struct hardware *); /* dhxpxlt.c */ void convert_statement (struct parse *); void convert_host_statement (struct parse *, jrefproto); void convert_host_name (struct parse *, jrefproto); void convert_class_statement (struct parse *, jrefproto, int); void convert_class_decl (struct parse *, jrefproto); void convert_lease_time (struct parse *, jrefproto, char *); void convert_shared_net_statement (struct parse *, jrefproto); void convert_subnet_statement (struct parse *, jrefproto); void convert_subnet_decl (struct parse *, jrefproto); void convert_host_decl (struct parse *, jrefproto); void convert_hardware_decl (struct parse *, jrefproto); void convert_hardware_addr (struct parse *, jrefproto); void convert_filename_decl (struct parse *, jrefproto); void convert_servername_decl (struct parse *, jrefproto); void convert_ip_addr_or_hostname (struct parse *, jrefproto, int); void convert_fixed_addr_decl (struct parse *, jrefproto); void convert_option_decl (struct parse *, jrefproto); void convert_lease_statement (struct parse *, jrefproto); void convert_address_range (struct parse *, jrefproto); void convert_date (struct parse *, jrefproto, char *); void convert_numeric_aggregate (struct parse *, jrefproto, int, int, int, int); void indent (int); /* route.c */ void add_route_direct (struct interface_info *, struct in_addr); void add_route_net (struct interface_info *, struct in_addr, struct in_addr); void add_route_default_gateway (struct interface_info *, struct in_addr); void remove_routes (struct in_addr); void remove_if_route (struct interface_info *, struct in_addr); void remove_all_if_routes (struct interface_info *); void set_netmask (struct interface_info *, struct in_addr); void set_broadcast_addr (struct interface_info *, struct in_addr); void set_ip_address (struct interface_info *, struct in_addr); /* clparse.c */ isc_result_t read_client_conf (void); int read_client_conf_file (const char *, struct interface_info *, struct client_config *); void read_client_leases (void); void parse_client_statement (struct parse *, struct interface_info *, struct client_config *); int parse_X (struct parse *, u_int8_t *, unsigned); int parse_option_list (struct parse *, struct option ***); void parse_interface_declaration (struct parse *, struct client_config *, char *); int interface_or_dummy (struct interface_info **, const char *); void make_client_state (struct client_state **); void make_client_config (struct client_state *, struct client_config *); void parse_client_lease_statement (struct parse *, int); void parse_client_lease_declaration (struct parse *, struct client_lease *, struct interface_info **, struct client_state **); int parse_option_decl (struct option_cache **, struct parse *); void parse_string_list (struct parse *, struct string_list **, int); int parse_ip_addr (struct parse *, struct iaddr *); int parse_ip_addr_with_subnet(struct parse *, struct iaddrmatch *); void parse_reject_statement (struct parse *, struct client_config *); /* icmp.c */ OMAPI_OBJECT_ALLOC_DECL (icmp_state, struct icmp_state, dhcp_type_icmp) extern struct icmp_state *icmp_state; void icmp_startup (int, void (*) (struct iaddr, u_int8_t *, int)); int icmp_readsocket (omapi_object_t *); int icmp_echorequest (struct iaddr *); isc_result_t icmp_echoreply (omapi_object_t *); /* dns.c */ #if defined (NSUPDATE) isc_result_t find_tsig_key (ns_tsig_key **, const char *, struct dns_zone *); void tkey_free (ns_tsig_key **); #endif isc_result_t enter_dns_zone (struct dns_zone *); isc_result_t dns_zone_lookup (struct dns_zone **, const char *); int dns_zone_dereference (struct dns_zone **, const char *, int); #if defined (NSUPDATE) #define FIND_FORWARD 0 #define FIND_REVERSE 1 isc_result_t find_cached_zone (dhcp_ddns_cb_t *, int); void forget_zone (struct dns_zone **); void repudiate_zone (struct dns_zone **); //void cache_found_zone (ns_class, char *, struct in_addr *, int); int get_dhcid (struct data_string *, int, const u_int8_t *, unsigned); void dhcid_tolease (struct data_string *, struct data_string *); isc_result_t dhcid_fromlease (struct data_string *, struct data_string *); isc_result_t ddns_update_fwd(struct data_string *, struct iaddr, struct data_string *, unsigned long, unsigned, unsigned); isc_result_t ddns_remove_fwd(struct data_string *, struct iaddr, struct data_string *); #endif /* NSUPDATE */ /* resolv.c */ extern char path_resolv_conf []; extern struct name_server *name_servers; extern struct domain_search_list *domains; void read_resolv_conf (TIME); struct name_server *first_name_server (void); /* inet_addr.c */ #ifdef NEED_INET_ATON int inet_aton (const char *, struct in_addr *); #endif /* class.c */ extern int have_billing_classes; struct class unknown_class; struct class known_class; struct collection default_collection; struct collection *collections; extern struct executable_statement *default_classification_rules; void classification_setup (void); void classify_client (struct packet *); int check_collection (struct packet *, struct lease *, struct collection *); void classify (struct packet *, struct class *); isc_result_t unlink_class (struct class **class); isc_result_t find_class (struct class **, const char *, const char *, int); int unbill_class (struct lease *, struct class *); int bill_class (struct lease *, struct class *); /* execute.c */ int execute_statements (struct binding_value **result, struct packet *, struct lease *, struct client_state *, struct option_state *, struct option_state *, struct binding_scope **, struct executable_statement *); void execute_statements_in_scope (struct binding_value **result, struct packet *, struct lease *, struct client_state *, struct option_state *, struct option_state *, struct binding_scope **, struct group *, struct group *); int executable_statement_dereference (struct executable_statement **, const char *, int); void write_statements (FILE *, struct executable_statement *, int); int find_matching_case (struct executable_statement **, struct packet *, struct lease *, struct client_state *, struct option_state *, struct option_state *, struct binding_scope **, struct expression *, struct executable_statement *); int executable_statement_foreach (struct executable_statement *, int (*) (struct executable_statement *, void *, int), void *, int); /* comapi.c */ extern omapi_object_type_t *dhcp_type_group; extern omapi_object_type_t *dhcp_type_shared_network; extern omapi_object_type_t *dhcp_type_subnet; extern omapi_object_type_t *dhcp_type_control; extern dhcp_control_object_t *dhcp_control_object; void dhcp_common_objects_setup (void); isc_result_t dhcp_group_set_value (omapi_object_t *, omapi_object_t *, omapi_data_string_t *, omapi_typed_data_t *); isc_result_t dhcp_group_get_value (omapi_object_t *, omapi_object_t *, omapi_data_string_t *, omapi_value_t **); isc_result_t dhcp_group_destroy (omapi_object_t *, const char *, int); isc_result_t dhcp_group_signal_handler (omapi_object_t *, const char *, va_list); isc_result_t dhcp_group_stuff_values (omapi_object_t *, omapi_object_t *, omapi_object_t *); isc_result_t dhcp_group_lookup (omapi_object_t **, omapi_object_t *, omapi_object_t *); isc_result_t dhcp_group_create (omapi_object_t **, omapi_object_t *); isc_result_t dhcp_group_remove (omapi_object_t *, omapi_object_t *); isc_result_t dhcp_control_set_value (omapi_object_t *, omapi_object_t *, omapi_data_string_t *, omapi_typed_data_t *); isc_result_t dhcp_control_get_value (omapi_object_t *, omapi_object_t *, omapi_data_string_t *, omapi_value_t **); isc_result_t dhcp_control_destroy (omapi_object_t *, const char *, int); isc_result_t dhcp_control_signal_handler (omapi_object_t *, const char *, va_list); isc_result_t dhcp_control_stuff_values (omapi_object_t *, omapi_object_t *, omapi_object_t *); isc_result_t dhcp_control_lookup (omapi_object_t **, omapi_object_t *, omapi_object_t *); isc_result_t dhcp_control_create (omapi_object_t **, omapi_object_t *); isc_result_t dhcp_control_remove (omapi_object_t *, omapi_object_t *); isc_result_t dhcp_subnet_set_value (omapi_object_t *, omapi_object_t *, omapi_data_string_t *, omapi_typed_data_t *); isc_result_t dhcp_subnet_get_value (omapi_object_t *, omapi_object_t *, omapi_data_string_t *, omapi_value_t **); isc_result_t dhcp_subnet_destroy (omapi_object_t *, const char *, int); isc_result_t dhcp_subnet_signal_handler (omapi_object_t *, const char *, va_list); isc_result_t dhcp_subnet_stuff_values (omapi_object_t *, omapi_object_t *, omapi_object_t *); isc_result_t dhcp_subnet_lookup (omapi_object_t **, omapi_object_t *, omapi_object_t *); isc_result_t dhcp_subnet_create (omapi_object_t **, omapi_object_t *); isc_result_t dhcp_subnet_remove (omapi_object_t *, omapi_object_t *); isc_result_t dhcp_shared_network_set_value (omapi_object_t *, omapi_object_t *, omapi_data_string_t *, omapi_typed_data_t *); isc_result_t dhcp_shared_network_get_value (omapi_object_t *, omapi_object_t *, omapi_data_string_t *, omapi_value_t **); isc_result_t dhcp_shared_network_destroy (omapi_object_t *, const char *, int); isc_result_t dhcp_shared_network_signal_handler (omapi_object_t *, const char *, va_list); isc_result_t dhcp_shared_network_stuff_values (omapi_object_t *, omapi_object_t *, omapi_object_t *); isc_result_t dhcp_shared_network_lookup (omapi_object_t **, omapi_object_t *, omapi_object_t *); isc_result_t dhcp_shared_network_create (omapi_object_t **, omapi_object_t *); isc_result_t dhcp_shared_network_remove (omapi_object_t *, omapi_object_t *); /* omapi.c */ extern int (*dhcp_interface_shutdown_hook) (struct interface_info *); extern omapi_object_type_t *dhcp_type_lease; extern omapi_object_type_t *dhcp_type_pool; extern omapi_object_type_t *dhcp_type_class; extern omapi_object_type_t *dhcp_type_subclass; #if defined (FAILOVER_PROTOCOL) extern omapi_object_type_t *dhcp_type_failover_state; extern omapi_object_type_t *dhcp_type_failover_link; extern omapi_object_type_t *dhcp_type_failover_listener; #endif void dhcp_db_objects_setup (void); isc_result_t dhcp_lease_set_value (omapi_object_t *, omapi_object_t *, omapi_data_string_t *, omapi_typed_data_t *); isc_result_t dhcp_lease_get_value (omapi_object_t *, omapi_object_t *, omapi_data_string_t *, omapi_value_t **); isc_result_t dhcp_lease_destroy (omapi_object_t *, const char *, int); isc_result_t dhcp_lease_signal_handler (omapi_object_t *, const char *, va_list); isc_result_t dhcp_lease_stuff_values (omapi_object_t *, omapi_object_t *, omapi_object_t *); isc_result_t dhcp_lease_lookup (omapi_object_t **, omapi_object_t *, omapi_object_t *); isc_result_t dhcp_lease_create (omapi_object_t **, omapi_object_t *); isc_result_t dhcp_lease_remove (omapi_object_t *, omapi_object_t *); isc_result_t dhcp_host_set_value (omapi_object_t *, omapi_object_t *, omapi_data_string_t *, omapi_typed_data_t *); isc_result_t dhcp_host_get_value (omapi_object_t *, omapi_object_t *, omapi_data_string_t *, omapi_value_t **); isc_result_t dhcp_host_destroy (omapi_object_t *, const char *, int); isc_result_t dhcp_host_signal_handler (omapi_object_t *, const char *, va_list); isc_result_t dhcp_host_stuff_values (omapi_object_t *, omapi_object_t *, omapi_object_t *); isc_result_t dhcp_host_lookup (omapi_object_t **, omapi_object_t *, omapi_object_t *); isc_result_t dhcp_host_create (omapi_object_t **, omapi_object_t *); isc_result_t dhcp_host_remove (omapi_object_t *, omapi_object_t *); isc_result_t dhcp_pool_set_value (omapi_object_t *, omapi_object_t *, omapi_data_string_t *, omapi_typed_data_t *); isc_result_t dhcp_pool_get_value (omapi_object_t *, omapi_object_t *, omapi_data_string_t *, omapi_value_t **); isc_result_t dhcp_pool_destroy (omapi_object_t *, const char *, int); isc_result_t dhcp_pool_signal_handler (omapi_object_t *, const char *, va_list); isc_result_t dhcp_pool_stuff_values (omapi_object_t *, omapi_object_t *, omapi_object_t *); isc_result_t dhcp_pool_lookup (omapi_object_t **, omapi_object_t *, omapi_object_t *); isc_result_t dhcp_pool_create (omapi_object_t **, omapi_object_t *); isc_result_t dhcp_pool_remove (omapi_object_t *, omapi_object_t *); isc_result_t dhcp_class_set_value (omapi_object_t *, omapi_object_t *, omapi_data_string_t *, omapi_typed_data_t *); isc_result_t dhcp_class_get_value (omapi_object_t *, omapi_object_t *, omapi_data_string_t *, omapi_value_t **); isc_result_t dhcp_class_destroy (omapi_object_t *, const char *, int); isc_result_t dhcp_class_signal_handler (omapi_object_t *, const char *, va_list); isc_result_t dhcp_class_stuff_values (omapi_object_t *, omapi_object_t *, omapi_object_t *); isc_result_t dhcp_class_lookup (omapi_object_t **, omapi_object_t *, omapi_object_t *); isc_result_t dhcp_class_create (omapi_object_t **, omapi_object_t *); isc_result_t dhcp_class_remove (omapi_object_t *, omapi_object_t *); isc_result_t dhcp_subclass_set_value (omapi_object_t *, omapi_object_t *, omapi_data_string_t *, omapi_typed_data_t *); isc_result_t dhcp_subclass_get_value (omapi_object_t *, omapi_object_t *, omapi_data_string_t *, omapi_value_t **); isc_result_t dhcp_subclass_destroy (omapi_object_t *, const char *, int); isc_result_t dhcp_subclass_signal_handler (omapi_object_t *, const char *, va_list); isc_result_t dhcp_subclass_stuff_values (omapi_object_t *, omapi_object_t *, omapi_object_t *); isc_result_t dhcp_subclass_lookup (omapi_object_t **, omapi_object_t *, omapi_object_t *); isc_result_t dhcp_subclass_create (omapi_object_t **, omapi_object_t *); isc_result_t dhcp_subclass_remove (omapi_object_t *, omapi_object_t *); isc_result_t dhcp_interface_set_value (omapi_object_t *, omapi_object_t *, omapi_data_string_t *, omapi_typed_data_t *); isc_result_t dhcp_interface_get_value (omapi_object_t *, omapi_object_t *, omapi_data_string_t *, omapi_value_t **); isc_result_t dhcp_interface_destroy (omapi_object_t *, const char *, int); isc_result_t dhcp_interface_signal_handler (omapi_object_t *, const char *, va_list ap); isc_result_t dhcp_interface_stuff_values (omapi_object_t *, omapi_object_t *, omapi_object_t *); isc_result_t dhcp_interface_lookup (omapi_object_t **, omapi_object_t *, omapi_object_t *); isc_result_t dhcp_interface_create (omapi_object_t **, omapi_object_t *); isc_result_t dhcp_interface_remove (omapi_object_t *, omapi_object_t *); void interface_stash (struct interface_info *); void interface_snorf (struct interface_info *, int); isc_result_t binding_scope_set_value (struct binding_scope *, int, omapi_data_string_t *, omapi_typed_data_t *); isc_result_t binding_scope_get_value (omapi_value_t **, struct binding_scope *, omapi_data_string_t *); isc_result_t binding_scope_stuff_values (omapi_object_t *, struct binding_scope *); void register_eventhandler(struct eventqueue **, void (*handler)(void *)); void unregister_eventhandler(struct eventqueue **, void (*handler)(void *)); void trigger_event(struct eventqueue **); /* mdb.c */ extern struct subnet *subnets; extern struct shared_network *shared_networks; extern host_hash_t *host_hw_addr_hash; extern host_hash_t *host_uid_hash; extern host_hash_t *host_name_hash; extern lease_id_hash_t *lease_uid_hash; extern lease_ip_hash_t *lease_ip_addr_hash; extern lease_id_hash_t *lease_hw_addr_hash; extern omapi_object_type_t *dhcp_type_host; extern int numclasseswritten; isc_result_t enter_class (struct class *, int, int); isc_result_t delete_class (struct class *, int); isc_result_t enter_host (struct host_decl *, int, int); isc_result_t delete_host (struct host_decl *, int); void change_host_uid(struct host_decl *host, const char *data, int len); int find_hosts_by_haddr (struct host_decl **, int, const unsigned char *, unsigned, const char *, int); int find_hosts_by_uid (struct host_decl **, const unsigned char *, unsigned, const char *, int); int find_hosts_by_option(struct host_decl **, struct packet *, struct option_state *, const char *, int); int find_host_for_network (struct subnet **, struct host_decl **, struct iaddr *, struct shared_network *); void new_address_range (struct parse *, struct iaddr, struct iaddr, struct subnet *, struct pool *, struct lease **); isc_result_t dhcp_lease_free (omapi_object_t *, const char *, int); isc_result_t dhcp_lease_get (omapi_object_t **, const char *, int); int find_grouped_subnet (struct subnet **, struct shared_network *, struct iaddr, const char *, int); int find_subnet(struct subnet **, struct iaddr, const char *, int); void enter_shared_network (struct shared_network *); void new_shared_network_interface (struct parse *, struct shared_network *, const char *); int subnet_inner_than(const struct subnet *, const struct subnet *, int); void enter_subnet (struct subnet *); void enter_lease (struct lease *); int supersede_lease (struct lease *, struct lease *, int, int, int); void make_binding_state_transition (struct lease *); int lease_copy (struct lease **, struct lease *, const char *, int); void release_lease (struct lease *, struct packet *); void abandon_lease (struct lease *, const char *); #if 0 /* this appears to be unused and I plan to remove it SAR */ void dissociate_lease (struct lease *); #endif void pool_timer (void *); int find_lease_by_uid (struct lease **, const unsigned char *, unsigned, const char *, int); int find_lease_by_hw_addr (struct lease **, const unsigned char *, unsigned, const char *, int); int find_lease_by_ip_addr (struct lease **, struct iaddr, const char *, int); void uid_hash_add (struct lease *); void uid_hash_delete (struct lease *); void hw_hash_add (struct lease *); void hw_hash_delete (struct lease *); int write_leases (void); int write_leases6(void); int lease_enqueue (struct lease *); isc_result_t lease_instantiate(const void *, unsigned, void *); void expire_all_pools (void); void dump_subnets (void); #if defined (DEBUG_MEMORY_LEAKAGE) || \ defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT) void free_everything (void); #endif /* nsupdate.c */ char *ddns_rev_name (struct lease *, struct lease_state *, struct packet *); char *ddns_fwd_name (struct lease *, struct lease_state *, struct packet *); int nsupdateA (const char *, const unsigned char *, u_int32_t, int); int nsupdatePTR (const char *, const unsigned char *, u_int32_t, int); void nsupdate (struct lease *, struct lease_state *, struct packet *, int); int updateA (const struct data_string *, const struct data_string *, unsigned int, struct lease *); int updatePTR (const struct data_string *, const struct data_string *, unsigned int, struct lease *); int deleteA (const struct data_string *, const struct data_string *, struct lease *); int deletePTR (const struct data_string *, const struct data_string *, struct lease *); /* failover.c */ #if defined (FAILOVER_PROTOCOL) extern dhcp_failover_state_t *failover_states; void dhcp_failover_startup (void); int dhcp_failover_write_all_states (void); isc_result_t enter_failover_peer (dhcp_failover_state_t *); isc_result_t find_failover_peer (dhcp_failover_state_t **, const char *, const char *, int); isc_result_t dhcp_failover_link_initiate (omapi_object_t *); isc_result_t dhcp_failover_link_signal (omapi_object_t *, const char *, va_list); isc_result_t dhcp_failover_link_set_value (omapi_object_t *, omapi_object_t *, omapi_data_string_t *, omapi_typed_data_t *); isc_result_t dhcp_failover_link_get_value (omapi_object_t *, omapi_object_t *, omapi_data_string_t *, omapi_value_t **); isc_result_t dhcp_failover_link_destroy (omapi_object_t *, const char *, int); isc_result_t dhcp_failover_link_stuff_values (omapi_object_t *, omapi_object_t *, omapi_object_t *); isc_result_t dhcp_failover_listen (omapi_object_t *); isc_result_t dhcp_failover_listener_signal (omapi_object_t *, const char *, va_list); isc_result_t dhcp_failover_listener_set_value (omapi_object_t *, omapi_object_t *, omapi_data_string_t *, omapi_typed_data_t *); isc_result_t dhcp_failover_listener_get_value (omapi_object_t *, omapi_object_t *, omapi_data_string_t *, omapi_value_t **); isc_result_t dhcp_failover_listener_destroy (omapi_object_t *, const char *, int); isc_result_t dhcp_failover_listener_stuff (omapi_object_t *, omapi_object_t *, omapi_object_t *); isc_result_t dhcp_failover_register (omapi_object_t *); isc_result_t dhcp_failover_state_signal (omapi_object_t *, const char *, va_list); isc_result_t dhcp_failover_state_transition (dhcp_failover_state_t *, const char *); isc_result_t dhcp_failover_set_service_state (dhcp_failover_state_t *state); isc_result_t dhcp_failover_set_state (dhcp_failover_state_t *, enum failover_state); isc_result_t dhcp_failover_peer_state_changed (dhcp_failover_state_t *, failover_message_t *); void dhcp_failover_pool_rebalance (void *); void dhcp_failover_pool_check (struct pool *); int dhcp_failover_state_pool_check (dhcp_failover_state_t *); void dhcp_failover_timeout (void *); void dhcp_failover_send_contact (void *); isc_result_t dhcp_failover_send_state (dhcp_failover_state_t *); isc_result_t dhcp_failover_send_updates (dhcp_failover_state_t *); int dhcp_failover_queue_update (struct lease *, int); int dhcp_failover_send_acks (dhcp_failover_state_t *); void dhcp_failover_toack_queue_timeout (void *); int dhcp_failover_queue_ack (dhcp_failover_state_t *, failover_message_t *msg); void dhcp_failover_ack_queue_remove (dhcp_failover_state_t *, struct lease *); isc_result_t dhcp_failover_state_set_value (omapi_object_t *, omapi_object_t *, omapi_data_string_t *, omapi_typed_data_t *); void dhcp_failover_keepalive (void *); void dhcp_failover_reconnect (void *); void dhcp_failover_startup_timeout (void *); void dhcp_failover_link_startup_timeout (void *); void dhcp_failover_listener_restart (void *); void dhcp_failover_auto_partner_down(void *vs); isc_result_t dhcp_failover_state_get_value (omapi_object_t *, omapi_object_t *, omapi_data_string_t *, omapi_value_t **); isc_result_t dhcp_failover_state_destroy (omapi_object_t *, const char *, int); isc_result_t dhcp_failover_state_stuff (omapi_object_t *, omapi_object_t *, omapi_object_t *); isc_result_t dhcp_failover_state_lookup (omapi_object_t **, omapi_object_t *, omapi_object_t *); isc_result_t dhcp_failover_state_create (omapi_object_t **, omapi_object_t *); isc_result_t dhcp_failover_state_remove (omapi_object_t *, omapi_object_t *); int dhcp_failover_state_match (dhcp_failover_state_t *, u_int8_t *, unsigned); int dhcp_failover_state_match_by_name(dhcp_failover_state_t *, failover_option_t *); const char *dhcp_failover_reject_reason_print (int); const char *dhcp_failover_state_name_print (enum failover_state); const char *dhcp_failover_message_name (unsigned); const char *dhcp_failover_option_name (unsigned); failover_option_t *dhcp_failover_option_printf (unsigned, char *, unsigned *, unsigned, const char *, ...) __attribute__((__format__(__printf__,5,6))); failover_option_t *dhcp_failover_make_option (unsigned, char *, unsigned *, unsigned, ...); isc_result_t dhcp_failover_put_message (dhcp_failover_link_t *, omapi_object_t *, int, u_int32_t, ...); isc_result_t dhcp_failover_send_connect (omapi_object_t *); isc_result_t dhcp_failover_send_connectack (omapi_object_t *, dhcp_failover_state_t *, int, const char *); isc_result_t dhcp_failover_send_disconnect (omapi_object_t *, int, const char *); isc_result_t dhcp_failover_send_bind_update (dhcp_failover_state_t *, struct lease *); isc_result_t dhcp_failover_send_bind_ack (dhcp_failover_state_t *, failover_message_t *, int, const char *); isc_result_t dhcp_failover_send_poolreq (dhcp_failover_state_t *); isc_result_t dhcp_failover_send_poolresp (dhcp_failover_state_t *, int); isc_result_t dhcp_failover_send_update_request (dhcp_failover_state_t *); isc_result_t dhcp_failover_send_update_request_all (dhcp_failover_state_t *); isc_result_t dhcp_failover_send_update_done (dhcp_failover_state_t *); isc_result_t dhcp_failover_process_bind_update (dhcp_failover_state_t *, failover_message_t *); isc_result_t dhcp_failover_process_bind_ack (dhcp_failover_state_t *, failover_message_t *); isc_result_t dhcp_failover_generate_update_queue (dhcp_failover_state_t *, int); isc_result_t dhcp_failover_process_update_request (dhcp_failover_state_t *, failover_message_t *); isc_result_t dhcp_failover_process_update_request_all (dhcp_failover_state_t *, failover_message_t *); isc_result_t dhcp_failover_process_update_done (dhcp_failover_state_t *, failover_message_t *); void ia_remove_all_lease(struct ia_xx *ia, const char *file, int line); void dhcp_failover_recover_done (void *); void failover_print (char *, unsigned *, unsigned, const char *); void update_partner (struct lease *); int load_balance_mine (struct packet *, dhcp_failover_state_t *); int peer_wants_lease (struct lease *); binding_state_t normal_binding_state_transition_check (struct lease *, dhcp_failover_state_t *, binding_state_t, u_int32_t); binding_state_t conflict_binding_state_transition_check (struct lease *, dhcp_failover_state_t *, binding_state_t, u_int32_t); int lease_mine_to_reallocate (struct lease *); OMAPI_OBJECT_ALLOC_DECL (dhcp_failover_state, dhcp_failover_state_t, dhcp_type_failover_state) OMAPI_OBJECT_ALLOC_DECL (dhcp_failover_listener, dhcp_failover_listener_t, dhcp_type_failover_listener) OMAPI_OBJECT_ALLOC_DECL (dhcp_failover_link, dhcp_failover_link_t, dhcp_type_failover_link) #endif /* FAILOVER_PROTOCOL */ const char *binding_state_print (enum failover_state); /* ldap.c */ #if defined(LDAP_CONFIGURATION) extern struct enumeration ldap_methods; #if defined (LDAP_USE_SSL) extern struct enumeration ldap_ssl_usage_enum; extern struct enumeration ldap_tls_reqcert_enum; extern struct enumeration ldap_tls_crlcheck_enum; #endif isc_result_t ldap_read_config (void); int find_haddr_in_ldap (struct host_decl **, int, unsigned, const unsigned char *, const char *, int); int find_subclass_in_ldap (struct class *, struct class **, struct data_string *); #endif /* mdb6.c */ HASH_FUNCTIONS_DECL(ia, unsigned char *, struct ia_xx, ia_hash_t) HASH_FUNCTIONS_DECL(iasubopt, struct in6_addr *, struct iasubopt, iasubopt_hash_t) isc_result_t iasubopt_allocate(struct iasubopt **iasubopt, const char *file, int line); isc_result_t iasubopt_reference(struct iasubopt **iasubopt, struct iasubopt *src, const char *file, int line); isc_result_t iasubopt_dereference(struct iasubopt **iasubopt, const char *file, int line); isc_result_t ia_make_key(struct data_string *key, u_int32_t iaid, const char *duid, unsigned int duid_len, const char *file, int line); isc_result_t ia_allocate(struct ia_xx **ia, u_int32_t iaid, const char *duid, unsigned int duid_len, const char *file, int line); isc_result_t ia_reference(struct ia_xx **ia, struct ia_xx *src, const char *file, int line); isc_result_t ia_dereference(struct ia_xx **ia, const char *file, int line); isc_result_t ia_add_iasubopt(struct ia_xx *ia, struct iasubopt *iasubopt, const char *file, int line); void ia_remove_iasubopt(struct ia_xx *ia, struct iasubopt *iasubopt, const char *file, int line); isc_boolean_t ia_equal(const struct ia_xx *a, const struct ia_xx *b); isc_result_t ipv6_pool_allocate(struct ipv6_pool **pool, u_int16_t type, const struct in6_addr *start_addr, int bits, int units, const char *file, int line); isc_result_t ipv6_pool_reference(struct ipv6_pool **pool, struct ipv6_pool *src, const char *file, int line); isc_result_t ipv6_pool_dereference(struct ipv6_pool **pool, const char *file, int line); isc_result_t create_lease6(struct ipv6_pool *pool, struct iasubopt **addr, unsigned int *attempts, const struct data_string *uid, time_t soft_lifetime_end_time); isc_result_t add_lease6(struct ipv6_pool *pool, struct iasubopt *lease, time_t valid_lifetime_end_time); isc_result_t renew_lease6(struct ipv6_pool *pool, struct iasubopt *lease); isc_result_t expire_lease6(struct iasubopt **leasep, struct ipv6_pool *pool, time_t now); isc_result_t release_lease6(struct ipv6_pool *pool, struct iasubopt *lease); isc_result_t decline_lease6(struct ipv6_pool *pool, struct iasubopt *lease); isc_boolean_t lease6_exists(const struct ipv6_pool *pool, const struct in6_addr *addr); isc_boolean_t lease6_usable(struct iasubopt *lease); isc_result_t cleanup_lease6(ia_hash_t *ia_table, struct ipv6_pool *pool, struct iasubopt *lease, struct ia_xx *ia); isc_result_t mark_lease_unavailble(struct ipv6_pool *pool, const struct in6_addr *addr); isc_result_t create_prefix6(struct ipv6_pool *pool, struct iasubopt **pref, unsigned int *attempts, const struct data_string *uid, time_t soft_lifetime_end_time); isc_boolean_t prefix6_exists(const struct ipv6_pool *pool, const struct in6_addr *pref, u_int8_t plen); isc_result_t add_ipv6_pool(struct ipv6_pool *pool); isc_result_t find_ipv6_pool(struct ipv6_pool **pool, u_int16_t type, const struct in6_addr *addr); isc_boolean_t ipv6_in_pool(const struct in6_addr *addr, const struct ipv6_pool *pool); isc_result_t renew_leases(struct ia_xx *ia); isc_result_t release_leases(struct ia_xx *ia); isc_result_t decline_leases(struct ia_xx *ia); void schedule_lease_timeout(struct ipv6_pool *pool); void schedule_all_ipv6_lease_timeouts(); void mark_hosts_unavailable(void); void mark_phosts_unavailable(void); void mark_interfaces_unavailable(void); dhcp_ddns_cb_t *ddns_cb_alloc(const char *file, int line); void ddns_cb_free (dhcp_ddns_cb_t *ddns_cb, const char *file, int line); void ddns_cb_forget_zone (dhcp_ddns_cb_t *ddns_cb); //void *key_from_zone(struct dns_zone *zone); isc_result_t ddns_modify_fwd(dhcp_ddns_cb_t *ddns_cb, const char *file, int line); isc_result_t ddns_modify_ptr(dhcp_ddns_cb_t *ddns_cb, const char *file, int line); void ddns_cancel(dhcp_ddns_cb_t *ddns_cb, const char *file, int line); #define MAX_ADDRESS_STRING_LEN \ (sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")) dhcp-4.2.4/includes/dhctoken.h000644 000765 000024 00000016343 11717270173 016162 0ustar00sarstaff000000 000000 /* dhctoken.h Tokens for config file lexer and parser. */ /* * Copyright (c) 2004,2007-2012 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1996-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ * * This software has been written for Internet Systems Consortium * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. * To learn more about Internet Systems Consortium, see * ``https://www.isc.org/''. To learn more about Vixie Enterprises, * see ``http://www.vix.com''. To learn more about Nominum, Inc., see * ``http://www.nominum.com''. */ enum dhcp_token { SEMI = ';', DOT = '.', COLON = ':', COMMA = ',', SLASH = '/', LBRACE = '{', RBRACE = '}', LPAREN = '(', RPAREN = ')', EQUAL = '=', TILDE = '~', BANG = '!', PERCENT = '%', PLUS = '+', MINUS = '-', ASTERISK = '*', AMPERSAND = '&', PIPE = '|', CARET = '^', ENDOFLINE = '\n', QUESTIONMARK = '?', HOST = 256, FIRST_TOKEN = HOST, HARDWARE = 257, FILENAME = 258, FIXED_ADDR = 259, OPTION = 260, ETHERNET = 261, STRING = 262, NUMBER = 263, NUMBER_OR_NAME = 264, NAME = 265, TIMESTAMP = 266, STARTS = 267, ENDS = 268, UID = 269, CLASS = 270, LEASE = 271, RANGE = 272, PACKET = 273, CIADDR = 274, YIADDR = 275, SIADDR = 276, GIADDR = 277, SUBNET = 278, NETMASK = 279, DEFAULT_LEASE_TIME = 280, MAX_LEASE_TIME = 281, VENDOR_CLASS = 282, USER_CLASS = 283, SHARED_NETWORK = 284, SERVER_NAME = 285, DYNAMIC_BOOTP = 286, SERVER_IDENTIFIER = 287, DYNAMIC_BOOTP_LEASE_CUTOFF = 288, DYNAMIC_BOOTP_LEASE_LENGTH = 289, BOOT_UNKNOWN_CLIENTS = 290, NEXT_SERVER = 291, TOKEN_RING = 292, GROUP = 293, ONE_LEASE_PER_CLIENT = 294, GET_LEASE_HOSTNAMES = 295, USE_HOST_DECL_NAMES = 296, SEND = 297, CLIENT_IDENTIFIER = 298, REQUEST = 299, REQUIRE = 300, TIMEOUT = 301, RETRY = 302, SELECT_TIMEOUT = 303, SCRIPT = 304, INTERFACE = 305, RENEW = 306, REBIND = 307, EXPIRE = 308, UNKNOWN_CLIENTS = 309, ALLOW = 310, DENY = 312, BOOTING = 313, DEFAULT = 314, MEDIA = 315, MEDIUM = 316, ALIAS = 317, REBOOT = 318, TOKEN_ABANDONED = 319, BACKOFF_CUTOFF = 320, INITIAL_INTERVAL = 321, NAMESERVER = 322, DOMAIN = 323, SEARCH = 324, SUPERSEDE = 325, APPEND = 326, PREPEND = 327, HOSTNAME = 328, CLIENT_HOSTNAME = 329, REJECT = 330, USE_LEASE_ADDR_FOR_DEFAULT_ROUTE = 331, MIN_LEASE_TIME = 332, MIN_SECS = 333, AND = 334, OR = 335, SUBSTRING = 337, SUFFIX = 338, CHECK = 339, EXTRACT_INT = 340, IF = 341, TOKEN_ADD = 342, BREAK = 343, ELSE = 344, ELSIF = 345, SUBCLASS = 346, MATCH = 347, SPAWN = 348, WITH = 349, EXISTS = 350, POOL = 351, UNKNOWN = 352, CLIENTS = 353, KNOWN = 354, AUTHENTICATED = 355, UNAUTHENTICATED = 356, ALL = 357, DYNAMIC = 358, MEMBERS = 359, OF = 360, PSEUDO = 361, LIMIT = 362, BILLING = 363, PEER = 364, FAILOVER = 365, MY = 366, PARTNER = 367, PRIMARY = 368, SECONDARY = 369, IDENTIFIER = 370, PORT = 371, MAX_TRANSMIT_IDLE = 372, MAX_RESPONSE_DELAY = 373, PARTNER_DOWN = 374, NORMAL = 375, COMMUNICATIONS_INTERRUPTED = 376, POTENTIAL_CONFLICT = 377, RECOVER = 378, TOKEN_FDDI = 379, AUTHORITATIVE = 380, TOKEN_NOT = 381, AUTHENTICATION = 383, IGNORE = 384, ACCEPT = 385, PREFER = 386, DONT = 387, CODE = 388, ARRAY = 389, BOOLEAN = 390, INTEGER = 391, SIGNED = 392, UNSIGNED = 393, IP_ADDRESS = 394, TEXT = 395, STRING_TOKEN = 396, SPACE = 397, CONCAT = 398, ENCODE_INT = 399, REVERSE = 402, LEASED_ADDRESS = 403, BINARY_TO_ASCII = 404, PICK = 405, CONFIG_OPTION = 406, HOST_DECL_NAME = 407, ON = 408, EXPIRY = 409, RELEASE = 410, COMMIT = 411, DNS_UPDATE = 412, LEASE_TIME = 413, STATIC = 414, NEVER = 415, INFINITE = 416, TOKEN_DELETED = 417, UPDATED_DNS_RR = 418, DNS_DELETE = 419, DUPLICATES = 420, DECLINES = 421, TSTP = 422, TSFP = 423, OWNER = 424, IS = 425, HBA = 426, MAX_UNACKED_UPDATES = 427, MCLT = 428, SPLIT = 429, AT = 430, TOKEN_NO = 431, TOKEN_DELETE = 432, NS_UPDATE = 433, UPDATE = 434, SWITCH = 435, CASE = 436, NS_FORMERR = 437, NS_NOERROR = 438, NS_NOTAUTH = 439, NS_NOTIMP = 440, NS_NOTZONE = 441, NS_NXDOMAIN = 442, NS_NXRRSET = 443, NS_REFUSED = 444, NS_SERVFAIL = 445, NS_YXDOMAIN = 446, NS_YXRRSET = 447, TOKEN_NULL = 448, TOKEN_SET = 449, DEFINED = 450, UNSET = 451, EVAL = 452, LET = 453, FUNCTION = 454, DEFINE = 455, ZONE = 456, KEY = 457, SECRET = 458, ALGORITHM = 459, LOAD = 460, BALANCE = 461, TOKEN_MAX = 462, SECONDS = 463, ADDRESS = 464, RESOLUTION_INTERRUPTED = 465, STATE = 466, UNKNOWN_STATE = 567, CLTT = 568, INCLUDE = 569, BINDING = 570, TOKEN_FREE = 571, TOKEN_ACTIVE = 572, TOKEN_EXPIRED = 573, TOKEN_RELEASED = 574, TOKEN_RESET = 575, TOKEN_BACKUP = 576, TOKEN_RESERVED = 577, TOKEN_BOOTP = 578, TOKEN_NEXT = 579, OMAPI = 580, LOG = 581, FATAL = 582, ERROR = 583, TOKEN_DEBUG = 584, INFO = 585, RETURN = 586, PAUSED = 587, RECOVER_DONE = 588, SHUTDOWN = 589, STARTUP = 590, ENCAPSULATE = 591, VENDOR = 592, CLIENT_STATE = 593, INIT_REBOOT = 594, TOKEN_INIT = 595, SELECT = 596, BOUND = 597, RENEWING = 598, REBINDING = 599, RECONTACT_INTERVAL = 600, CLIENT_UPDATES = 601, TOKEN_NEW = 601, TRANSMISSION = 602, TOKEN_CLOSE = 603, TOKEN_CREATE = 604, TOKEN_OPEN = 605, TOKEN_HELP = 606, END_OF_FILE = 607, RECOVER_WAIT = 608, TOKEN_SERVER = 609, CONNECT = 610, REMOVE = 611, REFRESH = 612, DOMAIN_NAME = 613, DO_FORWARD_UPDATE = 614, KNOWN_CLIENTS = 615, ATSFP = 616, LCASE = 617, UCASE = 618, WIDTH = 619, LENGTH = 620, HASH = 621, SIZE = 622, EPOCH = 623, DB_TIME_FORMAT = 624, LOCAL = 625, MAX_LEASE_MISBALANCE = 626, MAX_LEASE_OWNERSHIP = 627, MAX_BALANCE = 628, MIN_BALANCE = 629, DOMAIN_LIST = 630, LEASEQUERY = 631, EXECUTE = 632, IP6_ADDRESS = 633, FIXED_ADDR6 = 634, COMPRESSED = 635, SUBNET6 = 636, HOST_IDENTIFIER = 637, IA_NA = 638, IA_TA = 639, IA_PD = 640, IAADDR = 641, IAPREFIX = 642, LEASE6 = 643, PREFERRED_LIFE = 644, MAX_LIFE = 645, DEFAULT_DUID = 646, SERVER_DUID = 647, LLT = 648, EN = 649, LL = 650, RANGE6 = 651, WHITESPACE = 652, TOKEN_ALSO = 653, AFTER = 654, ZEROLEN = 655, TEMPORARY = 656, PREFIX6 = 657, FIXED_PREFIX6 = 658, ANYCAST_MAC = 659, CONFLICT_DONE = 660, AUTO_PARTNER_DOWN = 661, GETHOSTNAME = 662, REWIND = 663, INITIAL_DELAY = 664, GETHOSTBYNAME = 665, PRIMARY6 = 666, SECONDARY6 = 667, TOKEN_INFINIBAND = 668 }; #define is_identifier(x) ((x) >= FIRST_TOKEN && \ (x) != STRING && \ (x) != NUMBER && \ (x) != END_OF_FILE) dhcp-4.2.4/includes/failover.h000644 000765 000024 00000027341 11301372615 016163 0ustar00sarstaff000000 000000 /* failover.h Definitions for address trees... */ /* * Copyright (c) 2004,2005,2007,2009 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 2000-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ * * This software has been written for Internet Systems Consortium * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. * To learn more about Internet Systems Consortium, see * ``https://www.isc.org/''. To learn more about Vixie Enterprises, * see ``http://www.vix.com''. To learn more about Nominum, Inc., see * ``http://www.nominum.com''. */ #if defined (FAILOVER_PROTOCOL) struct failover_option_info { int code; const char *name; enum { FT_UINT8, FT_IPADDR, FT_UINT32, FT_BYTES, FT_TEXT_OR_BYTES, FT_DDNS, FT_DDNS1, FT_UINT16, FT_TEXT, FT_UNDEF, FT_DIGEST } type; int num_present; int offset; u_int32_t bit; }; typedef struct { unsigned count; u_int8_t *data; } failover_option_t; /* Failover configuration defaults. */ #ifndef DEFAULT_MAX_BALANCE_TIME # define DEFAULT_MAX_BALANCE_TIME 3600 #endif #ifndef DEFAULT_MIN_BALANCE_TIME # define DEFAULT_MIN_BALANCE_TIME 60 #endif #ifndef DEFAULT_MAX_LEASE_MISBALANCE # define DEFAULT_MAX_LEASE_MISBALANCE 15 #endif #ifndef DEFAULT_MAX_LEASE_OWNERSHIP # define DEFAULT_MAX_LEASE_OWNERSHIP 10 #endif #ifndef DEFAULT_MAX_FLYING_UPDATES # define DEFAULT_MAX_FLYING_UPDATES 100 #endif #ifndef DEFAULT_MAX_RESPONSE_DELAY # define DEFAULT_MAX_RESPONSE_DELAY 20 #endif /* * IANA has assigned ports 647 ("dhcp-failover") and 847 ("dhcp-failover2"). * Of these, only port 647 is mentioned in the -12 draft revision. We're not * sure if they are supposed to indicate primary and secondary? No matter, * we'll stick to the -12 draft revision level. */ #ifndef DEFAULT_FAILOVER_PORT # define DEFAULT_FAILOVER_PORT 647 #endif #define FM_OFFSET(x) (long)(&(((failover_message_t *)0) -> x)) /* All of the below definitions are mandated by draft-ietf-dhc-failover-12. * The Sections referenced are Sections within that document of that * version, and may be different in other documents of other versions. */ /* Failover message options from Section 12: */ #define FTO_ADDRESSES_TRANSFERRED 1 #define FTB_ADDRESSES_TRANSFERRED 0x00000002 #define FTO_ASSIGNED_IP_ADDRESS 2 #define FTB_ASSIGNED_IP_ADDRESS 0x00000004 #define FTO_BINDING_STATUS 3 #define FTB_BINDING_STATUS 0x00000008 #define FTO_CLIENT_IDENTIFIER 4 #define FTB_CLIENT_IDENTIFIER 0x00000010 #define FTO_CHADDR 5 #define FTB_CHADDR 0x00000020 #define FTO_CLTT 6 #define FTB_CLTT 0x00000040 #define FTO_REPLY_OPTIONS 7 #define FTB_REPLY_OPTIONS 0x00000080 #define FTO_REQUEST_OPTIONS 8 #define FTB_REQUEST_OPTIONS 0x00000100 #define FTO_DDNS 9 #define FTB_DDNS 0x00000200 #define FTO_DELAYED_SERVICE 10 #define FTB_DELAYED_SERVICE 0x00000400 #define FTO_HBA 11 #define FTB_HBA 0x00000800 #define FTO_IP_FLAGS 12 #define FTB_IP_FLAGS 0x00001000 #define FTO_LEASE_EXPIRY 13 #define FTB_LEASE_EXPIRY 0x00002000 #define FTO_MAX_UNACKED 14 #define FTB_MAX_UNACKED 0x00004000 #define FTO_MCLT 15 #define FTB_MCLT 0x00008000 #define FTO_MESSAGE 16 #define FTB_MESSAGE 0x00010000 #define FTO_MESSAGE_DIGEST 17 #define FTB_MESSAGE_DIGEST 0x00020000 #define FTO_POTENTIAL_EXPIRY 18 #define FTB_POTENTIAL_EXPIRY 0x00040000 #define FTO_RECEIVE_TIMER 19 #define FTB_RECEIVE_TIMER 0x00080000 #define FTO_PROTOCOL_VERSION 20 #define FTB_PROTOCOL_VERSION 0x00100000 #define FTO_REJECT_REASON 21 #define FTB_REJECT_REASON 0x00200000 #define FTO_RELATIONSHIP_NAME 22 #define FTB_RELATIONSHIP_NAME 0x00400000 #define FTO_SERVER_FLAGS 23 #define FTB_SERVER_FLAGS 0x00800000 #define FTO_SERVER_STATE 24 #define FTB_SERVER_STATE 0x01000000 #define FTO_STOS 25 #define FTB_STOS 0x02000000 #define FTO_TLS_REPLY 26 #define FTB_TLS_REPLY 0x04000000 #define FTO_TLS_REQUEST 27 #define FTB_TLS_REQUEST 0x08000000 #define FTO_VENDOR_CLASS 28 #define FTB_VENDOR_CLASS 0x10000000 #define FTO_VENDOR_OPTIONS 29 #define FTB_VENDOR_OPTIONS 0x20000000 #define FTO_MAX FTO_VENDOR_OPTIONS /* Failover protocol message types from Section 6.1: */ #define FTM_POOLREQ 1 #define FTM_POOLRESP 2 #define FTM_BNDUPD 3 #define FTM_BNDACK 4 #define FTM_CONNECT 5 #define FTM_CONNECTACK 6 #define FTM_UPDREQALL 7 #define FTM_UPDDONE 8 #define FTM_UPDREQ 9 #define FTM_STATE 10 #define FTM_CONTACT 11 #define FTM_DISCONNECT 12 /* Reject reasons from Section 12.21: */ #define FTR_ILLEGAL_IP_ADDR 1 #define FTR_FATAL_CONFLICT 2 #define FTR_MISSING_BINDINFO 3 #define FTR_TIMEMISMATCH 4 #define FTR_INVALID_MCLT 5 #define FTR_MISC_REJECT 6 #define FTR_DUP_CONNECTION 7 #define FTR_INVALID_PARTNER 8 #define FTR_TLS_UNSUPPORTED 9 #define FTR_TLS_UNCONFIGURED 10 #define FTR_TLS_REQUIRED 11 #define FTR_DIGEST_UNSUPPORTED 12 #define FTR_DIGEST_UNCONFIGURED 13 #define FTR_VERSION_MISMATCH 14 #define FTR_OUTDATED_BIND_INFO 15 #define FTR_LESS_CRIT_BIND_INFO 16 #define FTR_NO_TRAFFIC 17 #define FTR_HBA_CONFLICT 18 #define FTR_IP_NOT_RESERVED 19 #define FTR_IP_DIGEST_FAILURE 20 #define FTR_IP_MISSING_DIGEST 21 #define FTR_UNKNOWN 254 /* Message size limitations defined in Section 6.1: */ #define DHCP_FAILOVER_MIN_MESSAGE_SIZE 12 #define DHCP_FAILOVER_MAX_MESSAGE_SIZE 2048 /* Failover server flags from Section 12.23: */ #define FTF_SERVER_STARTUP 1 /* DDNS flags from Section 12.9. These are really their names. */ #define FTF_DDNS_C 0x0001 #define FTF_DDNS_A 0x0002 #define FTF_DDNS_D 0x0004 #define FTF_DDNS_P 0x0008 /* FTO_IP_FLAGS contents from Section 12.12: */ #define FTF_IP_FLAG_RESERVE 0x0001 #define FTF_IP_FLAG_BOOTP 0x0002 /* FTO_MESSAGE_DIGEST Type Codes from Section 12.17: */ #define FTT_MESSAGE_DIGEST_HMAC_MD5 0x01 typedef struct failover_message { int refcnt; struct failover_message *next; int options_present; u_int32_t time; u_int32_t xid; u_int8_t type; /* One-byte options. */ u_int8_t binding_status; u_int8_t delayed_service; u_int8_t protocol_version; u_int8_t reject_reason; u_int8_t server_flags; u_int8_t server_state; u_int8_t tls_reply; u_int8_t tls_request; /* Two-byte options. */ u_int16_t ip_flags; /* Four-byte options. */ u_int32_t addresses_transferred; u_int32_t assigned_addr; u_int32_t cltt; u_int32_t expiry; u_int32_t max_unacked; u_int32_t mclt; u_int32_t potential_expiry; u_int32_t receive_timer; u_int32_t stos; /* Arbitrary field options. */ failover_option_t chaddr; failover_option_t client_identifier; failover_option_t hba; failover_option_t message; failover_option_t message_digest; failover_option_t relationship_name; failover_option_t reply_options; failover_option_t request_options; failover_option_t vendor_class; failover_option_t vendor_options; /* Special contents options. */ ddns_fqdn_t ddns; } failover_message_t; typedef struct { OMAPI_OBJECT_PREAMBLE; struct option_cache *peer_address; unsigned peer_port; int options_present; enum dhcp_flink_state { dhcp_flink_start, dhcp_flink_message_length_wait, dhcp_flink_message_wait, dhcp_flink_disconnected, dhcp_flink_state_max } state; failover_message_t *imsg; struct _dhcp_failover_state *state_object; u_int16_t imsg_len; unsigned imsg_count; u_int8_t imsg_payoff; /* Pay*load* offset. :') */ u_int32_t xid; } dhcp_failover_link_t; typedef struct _dhcp_failover_listener { OMAPI_OBJECT_PREAMBLE; struct _dhcp_failover_listener *next; omapi_addr_t address; } dhcp_failover_listener_t; #endif /* FAILOVER_PROTOCOL */ /* A failover peer's running state. */ enum failover_state { unknown_state = 0, /* XXX: Not a standard state. */ startup = 1, normal = 2, communications_interrupted = 3, partner_down = 4, potential_conflict = 5, recover = 6, paused = 7, shut_down = 8, recover_done = 9, resolution_interrupted = 10, conflict_done = 11, /* Draft revision 12 of the failover protocol documents a RECOVER-WAIT * state, but does not enumerate its value in the section 12.24 * table. ISC DHCP 3.0.x used value 254 even though the state was * not documented at all. For the time being, we will continue to use * this value. */ recover_wait = 254 }; /* Service states are simplifications of failover states, particularly useful because the startup state isn't actually implementable as a separate failover state without maintaining a state stack. */ enum service_state { unknown_service_state, cooperating, not_cooperating, service_partner_down, not_responding, service_startup }; #if defined (FAILOVER_PROTOCOL) typedef struct _dhcp_failover_config { struct option_cache *address; int port; u_int32_t max_flying_updates; enum failover_state state; TIME stos; u_int32_t max_response_delay; } dhcp_failover_config_t; typedef struct _dhcp_failover_state { OMAPI_OBJECT_PREAMBLE; struct _dhcp_failover_state *next; char *name; /* Name of this failover instance. */ dhcp_failover_config_t me; /* My configuration. */ dhcp_failover_config_t partner; /* Partner's configuration. */ enum failover_state saved_state; /* Saved state during startup. */ struct data_string server_identifier; /* Server identifier (IP addr) */ u_int32_t mclt; u_int8_t *hba; /* Hash bucket array for load balancing. */ int load_balance_max_secs; u_int32_t max_lease_misbalance, max_lease_ownership; u_int32_t max_balance, min_balance; TIME last_balance, sched_balance; u_int32_t auto_partner_down; enum service_state service_state; const char *nrr; /* Printable reason why we're in the not_responding service state (empty string if we are responding. */ dhcp_failover_link_t *link_to_peer; /* Currently-established link to peer. */ enum { primary, secondary } i_am; /* We are primary or secondary in this relationship. */ TIME last_packet_sent; /* Timestamp on last packet we sent. */ TIME last_timestamp_received; /* The last timestamp we sent that has been returned by our partner. */ TIME skew; /* The skew between our clock and our partner's. */ struct lease *update_queue_head; /* List of leases we haven't sent to peer. */ struct lease *update_queue_tail; struct lease *ack_queue_head; /* List of lease updates the peer hasn't yet acked. */ struct lease *ack_queue_tail; struct lease *send_update_done; /* When we get a BNDACK for this lease, send an UPDDONE message. */ int cur_unacked_updates; /* Number of updates we've sent that have not yet been acked. */ /* List of messages which we haven't acked yet. */ failover_message_t *toack_queue_head; failover_message_t *toack_queue_tail; int pending_acks; /* Number of messages in the toack queue. */ int pool_count; /* Number of pools referencing this failover state object. */ int curUPD; /* If an UPDREQ* message is in motion, this value indicates which one. */ u_int32_t updxid; /* XID of UPDREQ* message in action. */ } dhcp_failover_state_t; #define DHCP_FAILOVER_VERSION 1 #endif /* FAILOVER_PROTOCOL */ dhcp-4.2.4/includes/heap.h000644 000765 000024 00000013016 10623646411 015267 0ustar00sarstaff000000 000000 /* * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1997-2001 Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ /* $Id: heap.h,v 1.3 2007-05-19 19:16:25 dhankins Exp $ */ #ifndef ISC_HEAP_H #define ISC_HEAP_H 1 /*! \file isc/heap.h */ /*% * The comparision function returns ISC_TRUE if the first argument has * higher priority than the second argument, and ISC_FALSE otherwise. */ typedef isc_boolean_t (*isc_heapcompare_t)(void *, void *); /*% * The index function allows the client of the heap to receive a callback * when an item's index number changes. This allows it to maintain * sync with its external state, but still delete itself, since deletions * from the heap require the index be provided. */ typedef void (*isc_heapindex_t)(void *, unsigned int); /*% * The heapaction function is used when iterating over the heap. * * NOTE: The heap structure CANNOT BE MODIFIED during the call to * isc_heap_foreach(). */ typedef void (*isc_heapaction_t)(void *, void *); typedef struct isc_heap isc_heap_t; isc_result_t isc_heap_create(isc_heapcompare_t compare, isc_heapindex_t index, unsigned int size_increment, isc_heap_t **heapp); /*!< * \brief Create a new heap. The heap is implemented using a space-efficient * storage method. When the heap elements are deleted space is not freed * but will be reused when new elements are inserted. * * Requires: *\li "mctx" is valid. *\li "compare" is a function which takes two void * arguments and * returns ISC_TRUE if the first argument has a higher priority than * the second, and ISC_FALSE otherwise. *\li "index" is a function which takes a void *, and an unsigned int * argument. This function will be called whenever an element's * index value changes, so it may continue to delete itself from the * heap. This option may be NULL if this functionality is unneeded. *\li "size_increment" is a hint about how large the heap should grow * when resizing is needed. If this is 0, a default size will be * used, which is currently 1024, allowing space for an additional 1024 * heap elements to be inserted before adding more space. *\li "heapp" is not NULL, and "*heap" is NULL. * * Returns: *\li ISC_R_SUCCESS - success *\li ISC_R_NOMEMORY - insufficient memory */ void isc_heap_destroy(isc_heap_t **heapp); /*!< * \brief Destroys a heap. * * Requires: *\li "heapp" is not NULL and "*heap" points to a valid isc_heap_t. */ isc_result_t isc_heap_insert(isc_heap_t *heap, void *elt); /*!< * \brief Inserts a new element into a heap. * * Requires: *\li "heapp" is not NULL and "*heap" points to a valid isc_heap_t. */ void isc_heap_delete(isc_heap_t *heap, unsigned int index); /*!< * \brief Deletes an element from a heap, by element index. * * Requires: *\li "heapp" is not NULL and "*heap" points to a valid isc_heap_t. *\li "index" is a valid element index, as provided by the "index" callback * provided during heap creation. */ void isc_heap_increased(isc_heap_t *heap, unsigned int index); /*!< * \brief Indicates to the heap that an element's priority has increased. * This function MUST be called whenever an element has increased in priority. * * Requires: *\li "heapp" is not NULL and "*heap" points to a valid isc_heap_t. *\li "index" is a valid element index, as provided by the "index" callback * provided during heap creation. */ void isc_heap_decreased(isc_heap_t *heap, unsigned int index); /*!< * \brief Indicates to the heap that an element's priority has decreased. * This function MUST be called whenever an element has decreased in priority. * * Requires: *\li "heapp" is not NULL and "*heap" points to a valid isc_heap_t. *\li "index" is a valid element index, as provided by the "index" callback * provided during heap creation. */ void * isc_heap_element(isc_heap_t *heap, unsigned int index); /*!< * \brief Returns the element for a specific element index. * * Requires: *\li "heapp" is not NULL and "*heap" points to a valid isc_heap_t. *\li "index" is a valid element index, as provided by the "index" callback * provided during heap creation. * * Returns: *\li A pointer to the element for the element index. */ void isc_heap_foreach(isc_heap_t *heap, isc_heapaction_t action, void *uap); /*!< * \brief Iterate over the heap, calling an action for each element. The * order of iteration is not sorted. * * Requires: *\li "heapp" is not NULL and "*heap" points to a valid isc_heap_t. *\li "action" is not NULL, and is a function which takes two arguments. * The first is a void *, representing the element, and the second is * "uap" as provided to isc_heap_foreach. *\li "uap" is a caller-provided argument, and may be NULL. * * Note: *\li The heap structure CANNOT be modified during this iteration. The only * safe function to call while iterating the heap is isc_heap_element(). */ #endif /* ISC_HEAP_H */ dhcp-4.2.4/includes/inet.h000644 000765 000024 00000004701 11301372615 015306 0ustar00sarstaff000000 000000 /* inet.h Portable definitions for internet addresses */ /* * Copyright (c) 2004,2007,2009 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1996-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ * * This software has been written for Internet Systems Consortium * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. * To learn more about Internet Systems Consortium, see * ``https://www.isc.org/''. To learn more about Vixie Enterprises, * see ``http://www.vix.com''. To learn more about Nominum, Inc., see * ``http://www.nominum.com''. */ /* An internet address of up to 128 bits. */ struct iaddr { unsigned len; unsigned char iabuf [16]; }; struct iaddrlist { struct iaddrlist *next; struct iaddr addr; }; /* struct iaddrmatch - used to compare a host IP against a subnet spec * * There is a space/speed tradeoff here implied by the use of a second * struct iaddr to hold the mask; while using an unsigned (byte!) to * represent the subnet prefix length would be more memory efficient, * it makes run-time mask comparisons more expensive. Since such * entries are used currently only in restricted circumstances * (wanting to reject a subnet), the decision is in favour of run-time * efficiency. */ struct iaddrmatch { struct iaddr addr; struct iaddr mask; }; /* its list ... */ struct iaddrmatchlist { struct iaddrmatchlist *next; struct iaddrmatch match; }; /* * Structure to store information about a CIDR network. */ struct iaddrcidrnet { struct iaddr lo_addr; int bits; }; struct iaddrcidrnetlist { struct iaddrcidrnetlist *next; struct iaddrcidrnet cidrnet; }; dhcp-4.2.4/includes/isc-dhcp/000777 000765 000024 00000000000 11757514243 015704 5ustar00sarstaff000000 000000 dhcp-4.2.4/includes/Makefile.am000644 000765 000024 00000000735 11272162770 016243 0ustar00sarstaff000000 000000 nobase_include_HEADERS = omapip/alloc.h omapip/buffer.h omapip/convert.h \ omapip/hash.h omapip/isclib.h omapip/omapip.h \ omapip/omapip_p.h omapip/result.h omapip/trace.h \ isc-dhcp/dst.h EXTRA_DIST = cdefs.h ctrace.h dhcp.h dhcp6.h dhcpd.h dhctoken.h failover.h \ heap.h inet.h minires.h osdep.h site.h statement.h tree.h \ t_api.h \ arpa/nameser.h arpa/nameser_compat.h \ netinet/if_ether.h netinet/ip.h netinet/ip_icmp.h netinet/udp.h dhcp-4.2.4/includes/Makefile.in000644 000765 000024 00000027766 11757500141 016265 0ustar00sarstaff000000 000000 # Makefile.in generated by automake 1.10.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : subdir = includes DIST_COMMON = $(nobase_include_HEADERS) $(srcdir)/Makefile.am \ $(srcdir)/Makefile.in $(srcdir)/config.h.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = config.h CONFIG_CLEAN_FILES = SOURCES = DIST_SOURCES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = `echo $$p | sed -e 's|^.*/||'`; am__installdirs = "$(DESTDIR)$(includedir)" nobase_includeHEADERS_INSTALL = $(install_sh_DATA) HEADERS = $(nobase_include_HEADERS) ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ GREP = @GREP@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDAP_CFLAGS = @LDAP_CFLAGS@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_prefix_program = @ac_prefix_program@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build_alias = @build_alias@ builddir = @builddir@ byte_order = @byte_order@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host_alias = @host_alias@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ nobase_include_HEADERS = omapip/alloc.h omapip/buffer.h omapip/convert.h \ omapip/hash.h omapip/isclib.h omapip/omapip.h \ omapip/omapip_p.h omapip/result.h omapip/trace.h \ isc-dhcp/dst.h EXTRA_DIST = cdefs.h ctrace.h dhcp.h dhcp6.h dhcpd.h dhctoken.h failover.h \ heap.h inet.h minires.h osdep.h site.h statement.h tree.h \ t_api.h \ arpa/nameser.h arpa/nameser_compat.h \ netinet/if_ether.h netinet/ip.h netinet/ip_icmp.h netinet/udp.h all: config.h $(MAKE) $(AM_MAKEFLAGS) all-am .SUFFIXES: $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ && exit 0; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign includes/Makefile'; \ cd $(top_srcdir) && \ $(AUTOMAKE) --foreign includes/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh config.h: stamp-h1 @if test ! -f $@; then \ rm -f stamp-h1; \ $(MAKE) $(AM_MAKEFLAGS) stamp-h1; \ else :; fi stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status @rm -f stamp-h1 cd $(top_builddir) && $(SHELL) ./config.status includes/config.h $(srcdir)/config.h.in: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_srcdir) && $(AUTOHEADER) rm -f stamp-h1 touch $@ distclean-hdr: -rm -f config.h stamp-h1 install-nobase_includeHEADERS: $(nobase_include_HEADERS) @$(NORMAL_INSTALL) test -z "$(includedir)" || $(MKDIR_P) "$(DESTDIR)$(includedir)" @$(am__vpath_adj_setup) \ list='$(nobase_include_HEADERS)'; for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ $(am__vpath_adj) \ echo " $(nobase_includeHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(includedir)/$$f'"; \ $(nobase_includeHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(includedir)/$$f"; \ done uninstall-nobase_includeHEADERS: @$(NORMAL_UNINSTALL) @$(am__vpath_adj_setup) \ list='$(nobase_include_HEADERS)'; for p in $$list; do \ $(am__vpath_adj) \ echo " rm -f '$(DESTDIR)$(includedir)/$$f'"; \ rm -f "$(DESTDIR)$(includedir)/$$f"; \ done ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) tags=; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$tags $$unique; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) tags=; \ list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$tags$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$tags $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && cd $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) $$here distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ fi; \ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ else \ test -f $(distdir)/$$file \ || cp -p $$d/$$file $(distdir)/$$file \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(HEADERS) config.h installdirs: for dir in "$(DESTDIR)$(includedir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic distclean-hdr distclean-tags dvi: dvi-am dvi-am: html: html-am info: info-am info-am: install-data-am: install-nobase_includeHEADERS install-dvi: install-dvi-am install-exec-am: install-html: install-html-am install-info: install-info-am install-man: install-pdf: install-pdf-am install-ps: install-ps-am installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-nobase_includeHEADERS .MAKE: install-am install-strip .PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ ctags distclean distclean-generic distclean-hdr distclean-tags \ distdir dvi dvi-am html html-am info info-am install \ install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-nobase_includeHEADERS install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-generic pdf \ pdf-am ps ps-am tags uninstall uninstall-am \ uninstall-nobase_includeHEADERS # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: dhcp-4.2.4/includes/minires.h000644 000765 000024 00000003216 11271742256 016025 0ustar00sarstaff000000 000000 /* * Copyright (c) 2004,2007-2009 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 2001-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * http://www.isc.org/ */ #ifndef MINIRES_H #define MINIRES_H #include "cdefs.h" #include "osdep.h" /* * Based on the Dynamic DNS reference implementation by Viraj Bais * */ int MRns_name_compress(const char *, u_char *, size_t, const unsigned char **, const unsigned char **); int MRns_name_unpack(const unsigned char *, const unsigned char *, const unsigned char *, unsigned char *, size_t); int MRns_name_pack (const unsigned char *, unsigned char *, unsigned, const unsigned char **, const unsigned char **); int MRns_name_ntop(const unsigned char *, char *, size_t); int MRns_name_pton(const char *, u_char *, size_t); #endif /* MINIRES_H */ dhcp-4.2.4/includes/netinet/000777 000765 000024 00000000000 11757514243 015660 5ustar00sarstaff000000 000000 dhcp-4.2.4/includes/omapip/000777 000765 000024 00000000000 11757514243 015477 5ustar00sarstaff000000 000000 dhcp-4.2.4/includes/osdep.h000644 000765 000024 00000017147 11442257201 015470 0ustar00sarstaff000000 000000 /* osdep.h Operating system dependencies... */ /* * Copyright (c) 2004-2005,2007-2010 by Internet Systems Consortium, * Inc. ("ISC") * Copyright (c) 1996-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ * * This software has been written for Internet Systems Consortium * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. * To learn more about Internet Systems Consortium, see * ``https://www.isc.org/''. To learn more about Vixie Enterprises, * see ``http://www.vix.com''. To learn more about Nominum, Inc., see * ``http://www.nominum.com''. */ #if !defined (__ISC_DHCP_OSDEP_H__) #define __ISC_DHCP_OSDEP_H__ #include "site.h" #include "config.h" #include #ifndef LITTLE_ENDIAN #define LITTLE_ENDIAN 1234 #endif /* LITTLE_ENDIAN */ #ifndef BIG_ENDIAN #define BIG_ENDIAN 4321 #endif /* BIG_ENDIAN */ #ifndef BYTE_ORDER #define BYTE_ORDER DHCP_BYTE_ORDER #endif /* BYTE_ORDER */ /* Porting:: If you add a new network API, you must add a check for it below: */ #if !defined (USE_SOCKETS) && \ !defined (USE_SOCKET_SEND) && \ !defined (USE_SOCKET_RECEIVE) && \ !defined (USE_RAW_SOCKETS) && \ !defined (USE_RAW_SEND) && \ !defined (USE_SOCKET_RECEIVE) && \ !defined (USE_BPF) && \ !defined (USE_BPF_SEND) && \ !defined (USE_BPF_RECEIVE) && \ !defined (USE_LPF) && \ !defined (USE_LPF_SEND) && \ !defined (USE_LPF_RECEIVE) && \ !defined (USE_NIT) && \ !defined (USE_NIT_SEND) && \ !defined (USE_NIT_RECEIVE) && \ !defined (USE_DLPI_SEND) && \ !defined (USE_DLPI_RECEIVE) /* Determine default socket API to USE. */ # if defined(HAVE_BPF) # define USE_BPF 1 # elif defined(HAVE_LPF) # define USE_LPF 1 # elif defined(HAVE_DLPI) # define USE_DLPI 1 # endif #endif #if !defined (TIME_MAX) # define TIME_MAX 2147483647 #endif /* snprintf/vsnprintf hacks. for systems with no libc versions only. */ #ifdef NO_SNPRINTF extern int isc_print_snprintf(char *, size_t, const char *, ...); extern int isc_print_vsnprintf(char *, size_t, const char *, va_list ap); # define snprintf isc_print_snprintf # define vsnprintf isc_print_vsnprintf #endif /* Porting:: If you add a new network API, and have it set up so that it can be used for sending or receiving, but doesn't have to be used for both, then set up an ifdef like the ones below: */ #ifdef USE_SOCKETS # define USE_SOCKET_SEND # define USE_SOCKET_RECEIVE # if defined(HAVE_DLPI) # define USE_DLPI_HWADDR # endif #endif #ifdef USE_RAW_SOCKETS # define USE_RAW_SEND # define USE_SOCKET_RECEIVE #endif #ifdef USE_BPF # define USE_BPF_SEND # define USE_BPF_RECEIVE #endif #ifdef USE_LPF # define USE_LPF_SEND # define USE_LPF_RECEIVE #endif #ifdef USE_NIT # define USE_NIT_SEND # define USE_NIT_RECEIVE #endif #ifdef USE_DLPI # define USE_DLPI_SEND # define USE_DLPI_RECEIVE #endif #ifdef USE_UPF # define USE_UPF_SEND # define USE_UPF_RECEIVE #endif /* Porting:: If you add support for sending packets directly out an interface, and your support does not do ARP or routing, you must use a fallback mechanism to deal with packets that need to be sent to routers. Currently, all low-level packet interfaces use BSD sockets as a fallback. */ #if defined (USE_BPF_SEND) || defined (USE_NIT_SEND) || \ defined (USE_DLPI_SEND) || defined (USE_UPF_SEND) || \ defined (USE_LPF_SEND) || \ (defined (USE_SOCKET_SEND) && defined (HAVE_SO_BINDTODEVICE)) # define USE_SOCKET_FALLBACK # define USE_FALLBACK #endif /* Porting:: If you add support for sending packets directly out an interface and need to be able to assemble packets, add the USE_XXX_SEND definition for your interface to the list tested below. */ #if defined (USE_RAW_SEND) || defined (USE_BPF_SEND) || \ defined (USE_NIT_SEND) || defined (USE_UPF_SEND) || \ defined (USE_DLPI_SEND) || defined (USE_LPF_SEND) # define PACKET_ASSEMBLY #endif /* Porting:: If you add support for receiving packets directly from an interface and need to be able to decode raw packets, add the USE_XXX_RECEIVE definition for your interface to the list tested below. */ #if defined (USE_RAW_RECEIVE) || defined (USE_BPF_SEND) || \ defined (USE_NIT_RECEIVE) || defined (USE_UPF_RECEIVE) || \ defined (USE_DLPI_RECEIVE) || defined (USE_LPF_RECEIVE) # define PACKET_DECODING #endif /* If we don't have a DLPI packet filter, we have to filter in userland. Probably not worth doing, actually. */ #if defined (USE_DLPI_RECEIVE) && !defined (USE_DLPI_PFMOD) # define USERLAND_FILTER #endif /* jmp_buf is assumed to be a struct unless otherwise defined in the system header. */ #ifndef jbp_decl # define jbp_decl(x) jmp_buf *x #endif #ifndef jref # define jref(x) (&(x)) #endif #ifndef jdref # define jdref(x) (*(x)) #endif #ifndef jrefproto # define jrefproto jmp_buf * #endif #ifndef BPF_FORMAT # define BPF_FORMAT "/dev/bpf%d" #endif #if defined (F_SETFD) && !defined (HAVE_SETFD) # define HAVE_SETFD #endif #if defined (IFF_POINTOPOINT) && !defined (HAVE_IFF_POINTOPOINT) # define HAVE_IFF_POINTOPOINT #endif #if defined (AF_LINK) && !defined (HAVE_AF_LINK) # define HAVE_AF_LINK #endif #if defined (ARPHRD_TUNNEL) && !defined (HAVE_ARPHRD_TUNNEL) # define HAVE_ARPHRD_TUNNEL #endif #if defined (ARPHRD_LOOPBACK) && !defined (HAVE_ARPHRD_LOOPBACK) # define HAVE_ARPHRD_LOOPBACK #endif #if defined (ARPHRD_ROSE) && !defined (HAVE_ARPHRD_ROSE) # define HAVE_ARPHRD_ROSE #endif #if defined (ARPHRD_IRDA) && !defined (HAVE_ARPHRD_IRDA) # define HAVE_ARPHRD_IRDA #endif #if defined (ARPHRD_SIT) && !defined (HAVE_ARPHRD_SIT) # define HAVE_ARPHRD_SIT #endif #if defined (ARPHRD_IEEE1394) & !defined (HAVE_ARPHRD_IEEE1394) # define HAVE_ARPHRD_IEEE1394 #endif #if defined (ARPHRD_IEEE802) && !defined (HAVE_ARPHRD_IEEE802) # define HAVE_ARPHRD_IEEE802 #endif #if defined (ARPHRD_IEEE802_TR) && !defined (HAVE_ARPHRD_IEEE802_TR) # define HAVE_ARPHRD_IEEE802_TR #endif #if defined (ARPHRD_FDDI) && !defined (HAVE_ARPHRD_FDDI) # define HAVE_ARPHRD_FDDI #endif #if defined (ARPHRD_AX25) && !defined (HAVE_ARPHRD_AX25) # define HAVE_ARPHRD_AX25 #endif #if defined (ARPHRD_NETROM) && !defined (HAVE_ARPHRD_NETROM) # define HAVE_ARPHRD_NETROM #endif #if defined (ARPHRD_METRICOM) && !defined (HAVE_ARPHRD_METRICOM) # define HAVE_ARPHRD_METRICOM #endif #if defined (SO_BINDTODEVICE) && !defined (HAVE_SO_BINDTODEVICE) # define HAVE_SO_BINDTODEVICE #endif #if defined (AF_LINK) && !defined (HAVE_AF_LINK) # define HAVE_AF_LINK #endif /* Linux needs to define SHUT_* in /usr/include/sys/socket.h someday... */ #if !defined (SHUT_RD) # define SHUT_RD 0 #endif #if !defined (SOCKLEN_T) # define SOCKLEN_T socklen_t #elif defined(_AIX) #undef SOCKLEN_T #define SOCKLEN_T socklen_t #endif #if !defined (STDERR_FILENO) # define STDERR_FILENO 2 #endif #endif /* __ISC_DHCP_OSDEP_H__ */ dhcp-4.2.4/includes/site.h000644 000765 000024 00000020140 11741130254 015305 0ustar00sarstaff000000 000000 /* Site-specific definitions. For supported systems, you shouldn't need to make any changes here. However, you may want to, in order to deal with site-specific differences. */ /* Add any site-specific definitions and inclusions here... */ /* #include */ /* #define SITE_FOOBAR */ /* Define this if you don't want dhcpd to run as a daemon and do want to see all its output printed to stdout instead of being logged via syslog(). This also makes dhcpd use the dhcpd.conf in its working directory and write the dhcpd.leases file there. */ /* #define DEBUG */ /* Define this to see what the parser is parsing. You probably don't want to see this. */ /* #define DEBUG_TOKENS */ /* Define this to see dumps of incoming and outgoing packets. This slows things down quite a bit... */ /* #define DEBUG_PACKET */ /* Define this if you want to see dumps of expression evaluation. */ /* #define DEBUG_EXPRESSIONS */ /* Define this if you want to see dumps of find_lease() in action. */ /* #define DEBUG_FIND_LEASE */ /* Define this if you want to see dumps of parsed expressions. */ /* #define DEBUG_EXPRESSION_PARSE */ /* Define this if you want to watch the class matching process. */ /* #define DEBUG_CLASS_MATCHING */ /* Define this if you want to track memory usage for the purpose of noticing memory leaks quickly. */ /* #define DEBUG_MEMORY_LEAKAGE */ /* #define DEBUG_MEMORY_LEAKAGE_ON_EXIT */ /* Define this if you want exhaustive (and very slow) checking of the malloc pool for corruption. */ /* #define DEBUG_MALLOC_POOL */ /* Define this if you want to see a message every time a lease's state changes. */ /* #define DEBUG_LEASE_STATE_TRANSITIONS */ /* Define this if you want to maintain a history of the last N operations that changed reference counts on objects. This can be used to debug cases where an object is dereferenced too often, or not often enough. */ /* #define DEBUG_RC_HISTORY */ /* Define this if you want to see the history every cycle. */ /* #define DEBUG_RC_HISTORY_EXHAUSTIVELY */ /* This is the number of history entries to maintain - by default, 256. */ /* #define RC_HISTORY_MAX 10240 */ /* Define this if you want dhcpd to dump core when a non-fatal memory allocation error is detected (i.e., something that would cause a memory leak rather than a memory smash). */ /* #define POINTER_DEBUG */ /* Define this if you want debugging output for DHCP failover protocol messages. */ /* #define DEBUG_FAILOVER_MESSAGES */ /* Define this to include contact messages in failover message debugging. The contact messages are sent once per second, so this can generate a lot of log entries. */ /* #define DEBUG_FAILOVER_CONTACT_MESSAGES */ /* Define this if you want debugging output for DHCP failover protocol event timeout timing. */ /* #define DEBUG_FAILOVER_TIMING */ /* Define this if you want to include contact message timing, which is performed once per second and can generate a lot of log entries. */ /* #define DEBUG_FAILOVER_CONTACT_TIMING */ /* Define this if you want all leases written to the lease file, even if they are free leases that have never been used. */ /* #define DEBUG_DUMP_ALL_LEASES */ /* Define this if you want to see the requests and replies between the DHCP code and the DNS library code. */ /* #define DEBUG_DNS_UPDATES */ /* Define this if you want DHCP failover protocol support in the DHCP server. */ /* #define FAILOVER_PROTOCOL */ /* Define this if you want DNS update functionality to be available. */ #define NSUPDATE /* Define this if you want the dhcpd.pid file to go somewhere other than the default (which varies from system to system, but is usually either /etc or /var/run. */ /* #define _PATH_DHCPD_PID "/var/run/dhcpd.pid" */ /* Define this if you want the dhcpd.leases file (the dynamic lease database) to go somewhere other than the default location, which is normally /etc/dhcpd.leases. */ /* #define _PATH_DHCPD_DB "/etc/dhcpd.leases" */ /* Define this if you want the dhcpd.conf file to go somewhere other than the default location. By default, it goes in /etc/dhcpd.conf. */ /* #define _PATH_DHCPD_CONF "/etc/dhcpd.conf" */ /* Network API definitions. You do not need to choose one of these - if you don't choose, one will be chosen for you in your system's config header. DON'T MESS WITH THIS UNLESS YOU KNOW WHAT YOU'RE DOING!!! */ /* Define USE_SOCKETS to use the standard BSD socket API. On many systems, the BSD socket API does not provide the ability to send packets to the 255.255.255.255 broadcast address, which can prevent some clients (e.g., Win95) from seeing replies. This is not a problem on Solaris. In addition, the BSD socket API will not work when more than one network interface is configured on the server. However, the BSD socket API is about as efficient as you can get, so if the aforementioned problems do not matter to you, or if no other API is supported for your system, you may want to go with it. */ /* #define USE_SOCKETS */ /* Define this to use the Sun Streams NIT API. The Sun Streams NIT API is only supported on SunOS 4.x releases. */ /* #define USE_NIT */ /* Define this to use the Berkeley Packet Filter API. The BPF API is available on all 4.4-BSD derivatives, including NetBSD, FreeBSD and BSDI's BSD/OS. It's also available on DEC Alpha OSF/1 in a compatibility mode supported by the Alpha OSF/1 packetfilter interface. */ /* #define USE_BPF */ /* Define this to use the raw socket API. The raw socket API is provided on many BSD derivatives, and provides a way to send out raw IP packets. It is only supported for sending packets - packets must be received with the regular socket API. This code is experimental - I've never gotten it to actually transmit a packet to the 255.255.255.255 broadcast address - so use it at your own risk. */ /* #define USE_RAW_SOCKETS */ /* Define this to change the logging facility used by dhcpd. */ /* #define DHCPD_LOG_FACILITY LOG_DAEMON */ /* Define this if you want to be able to execute external commands during conditional evaluation. */ /* #define ENABLE_EXECUTE */ /* Define this if you aren't debugging and you want to save memory (potentially a _lot_ of memory) by allocating leases in chunks rather than one at a time. */ #define COMPACT_LEASES /* Define this if you want to be able to save and playback server operational traces. */ /* #define TRACING */ /* Define this if you want the server to use the previous behavior when determining the DDNS TTL. If the user has specified a ddns-ttl option that is used to detemine the ttl. (If the user specifies an option that references the lease structure it is only usable for v4. In that case v6 will use the default.) Otherwise when defined the defaults are: v4 - 1/2 the lease time, v6 - DEFAULT_DDNS_TTL. When undefined the defaults are 1/2 the (preferred) lease time for both but with a cap on the maximum. */ /* #define USE_OLD_DDNS_TTL */ /* Define this if you want a DHCPv6 server to send replies to the source port of the message it received. This is useful for testing but is only included for backwards compatibility. */ /* #define REPLY_TO_SOURCE_PORT */ /* Define this if you want to enable strict checks in DNS Updates mechanism. Do not enable this unless are DHCP developer. */ /* #define DNS_UPDATES_MEMORY_CHECKS */ /* Define this if you want to allow domain list in domain-name option. RFC2132 does not allow that behavior, but it is somewhat used due to historic reasons. Note that it may be removed some time in the future. */ #define ACCEPT_LIST_IN_DOMAIN_NAME /* In RFC3315 section 17.2.2 stated that if the server was not going to be able to assign any addresses to any IAs in a subsequent Request from a client that the server should not include any IAs. This requirement was removed in an errata from August 2010. Define the following if you want the pre-errata version. You should only enable this option if you have clients that require the original functionality. */ /* #define RFC3315_PRE_ERRATA_2010_08 */ dhcp-4.2.4/includes/statement.h000644 000765 000024 00000005737 11301372615 016365 0ustar00sarstaff000000 000000 /* statement.h Definitions for executable statements... */ /* * Copyright (c) 2004,2007,2009 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1996-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ * * This software has been written for Internet Systems Consortium * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. * To learn more about Internet Systems Consortium, see * ``https://www.isc.org/''. To learn more about Vixie Enterprises, * see ``http://www.vix.com''. To learn more about Nominum, Inc., see * ``http://www.nominum.com''. */ struct executable_statement { int refcnt; struct executable_statement *next; enum statement_op { null_statement, if_statement, add_statement, eval_statement, break_statement, default_option_statement, supersede_option_statement, append_option_statement, prepend_option_statement, send_option_statement, statements_statement, on_statement, switch_statement, case_statement, default_statement, set_statement, unset_statement, let_statement, define_statement, log_statement, return_statement, execute_statement } op; union { struct { struct executable_statement *tc, *fc; struct expression *expr; } ie; struct expression *eval; struct expression *retval; struct class *add; struct option_cache *option; struct option_cache *supersede; struct option_cache *prepend; struct option_cache *append; struct executable_statement *statements; struct { int evtypes; # define ON_COMMIT 1 # define ON_EXPIRY 2 # define ON_RELEASE 4 # define ON_TRANSMISSION 8 struct executable_statement *statements; } on; struct { struct expression *expr; struct executable_statement *statements; } s_switch; struct expression *c_case; struct { char *name; struct expression *expr; struct executable_statement *statements; } set, let; char *unset; struct { enum { log_priority_fatal, log_priority_error, log_priority_debug, log_priority_info } priority; struct expression *expr; } log; struct { char *command; struct expression *arglist; int argc; } execute; } data; }; dhcp-4.2.4/includes/t_api.h000644 000765 000024 00000004106 11301372615 015442 0ustar00sarstaff000000 000000 /* * Copyright (C) 2004-2007,2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2001 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ /* $Id: t_api.h,v 1.3.8.1 2009-11-20 01:49:01 sar Exp $ */ #ifndef TESTS_T_API_H #define TESTS_T_API_H 1 /*! \file tests/t_api.h */ #include #include #include #include /* * * Result codes. * */ #define T_PASS 0x1 #define T_FAIL 0x2 #define T_UNRESOLVED 0x3 #define T_UNSUPPORTED 0x4 #define T_UNTESTED 0x5 #define T_THREADONLY 0x6 /* * * Assertion class codes. * */ #define T_OPTIONAL 0x0 #define T_REQUIRED 0x1 /* * Misc */ #define T_MAXTOKS 16 #define T_ARG(n) (*(av + (n))) typedef void (*PFV)(void); typedef struct { PFV pfv; const char *func_name; } testspec_t; extern int T_debug; extern testspec_t T_testlist[]; ISC_LANG_BEGINDECLS void t_assert(const char *component, int anum, int class, const char *what, ...) ISC_FORMAT_PRINTF(4, 5); void t_info(const char *format, ...) ISC_FORMAT_PRINTF(1, 2); void t_result(int result); char * t_getenv(const char *name); char * t_fgetbs(FILE *fp); isc_result_t t_dns_result_fromtext(char *result); unsigned int t_dc_method_fromtext(char *dc_method); int t_bustline(char *line, char **toks); int t_eval(const char *filename, int (*func)(char **), int nargs); ISC_LANG_ENDDECLS #endif /* TESTS_T_API_H */ dhcp-4.2.4/includes/tree.h000644 000765 000024 00000021156 11562515514 015317 0ustar00sarstaff000000 000000 /* tree.h Definitions for address trees... */ /* * Copyright (c) 2011 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 2004,2007-2009 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1996-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ * * This software has been written for Internet Systems Consortium * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. * To learn more about Internet Systems Consortium, see * ``https://www.isc.org/''. To learn more about Vixie Enterprises, * see ``http://www.vix.com''. To learn more about Nominum, Inc., see * ``http://www.nominum.com''. */ /* A pair of pointers, suitable for making a linked list. */ typedef struct _pair { caddr_t car; struct _pair *cdr; } *pair; struct option_chain_head { int refcnt; pair first; }; struct enumeration_value { const char *name; u_int8_t value; }; struct enumeration { struct enumeration *next; const char *name; unsigned width; struct enumeration_value *values; }; /* Tree node types... */ #define TREE_CONCAT 1 #define TREE_HOST_LOOKUP 2 #define TREE_CONST 3 #define TREE_LIMIT 4 #define TREE_DATA_EXPR 5 /* A data buffer with a reference count. */ struct buffer { int refcnt; unsigned char data [1]; }; /* XXX The mechanism by which data strings are returned is currently XXX broken: rather than returning an ephemeral pointer, we create XXX a reference to the data in the caller's space, which the caller XXX then has to dereference - instead, the reference should be XXX ephemeral by default and be made a persistent reference explicitly. */ /* XXX on the other hand, it seems to work pretty nicely, so maybe the XXX above comment is meshuggenah. */ /* XXX I think the above comment tries to say this: XXX http://tinyurl.com/2tjqre */ /* A string of data bytes, possibly accompanied by a larger buffer. */ struct data_string { struct buffer *buffer; const unsigned char *data; unsigned len; /* Does not include NUL terminator, if any. */ int terminated; }; enum expression_context { context_any, /* indefinite */ context_boolean, context_data, context_numeric, context_dns, context_data_or_numeric, /* indefinite */ context_function }; struct fundef { int refcnt; struct string_list *args; struct executable_statement *statements; }; struct binding_value { int refcnt; enum { binding_boolean, binding_data, binding_numeric, binding_dns, binding_function } type; union value { struct data_string data; unsigned long intval; int boolean; #if defined (NSUPDATE_OLD) ns_updrec *dns; #endif struct fundef *fundef; struct binding_value *bv; } value; }; struct binding { struct binding *next; char *name; struct binding_value *value; }; struct binding_scope { int refcnt; struct binding_scope *outer; struct binding *bindings; }; /* Expression tree structure. */ enum expr_op { expr_none, expr_match, expr_check, expr_equal, expr_substring, expr_suffix, expr_concat, expr_host_lookup, expr_and, expr_or, expr_not, expr_option, expr_hardware, expr_packet, expr_const_data, expr_extract_int8, expr_extract_int16, expr_extract_int32, expr_encode_int8, expr_encode_int16, expr_encode_int32, expr_const_int, expr_exists, expr_encapsulate, expr_known, expr_reverse, expr_leased_address, expr_binary_to_ascii, expr_config_option, expr_host_decl_name, expr_pick_first_value, expr_lease_time, expr_dns_transaction, expr_static, expr_ns_add, expr_ns_delete, expr_ns_exists, expr_ns_not_exists, expr_not_equal, expr_null, expr_variable_exists, expr_variable_reference, expr_filename, expr_sname, expr_arg, expr_funcall, expr_function, expr_add, expr_subtract, expr_multiply, expr_divide, expr_remainder, expr_binary_and, expr_binary_or, expr_binary_xor, expr_client_state, expr_ucase, expr_lcase, expr_regex_match, expr_iregex_match, expr_gethostname }; struct expression { int refcnt; enum expr_op op; union expr_union { struct { struct expression *expr; struct expression *offset; struct expression *len; } substring; struct expression *equal [2]; struct expression *and [2]; struct expression *or [2]; struct expression *not; struct expression *add; struct expression *subtract; struct expression *multiply; struct expression *divide; struct expression *remainder; struct collection *check; struct { struct expression *expr; struct expression *len; } suffix; struct expression *lcase; struct expression *ucase; struct option *option; struct option *config_option; struct { struct expression *offset; struct expression *len; } packet; struct data_string const_data; struct expression *extract_int; struct expression *encode_int; unsigned long const_int; struct expression *concat [2]; struct dns_host_entry *host_lookup; struct option *exists; struct data_string encapsulate; struct { struct expression *base; struct expression *width; struct expression *separator; struct expression *buffer; } b2a; struct { struct expression *width; struct expression *buffer; } reverse; struct { struct expression *car; struct expression *cdr; } pick_first_value; struct { struct expression *car; struct expression *cdr; } dns_transaction; struct { unsigned rrclass; unsigned rrtype; struct expression *rrname; struct expression *rrdata; struct expression *ttl; } ns_add; struct { unsigned rrclass; unsigned rrtype; struct expression *rrname; struct expression *rrdata; } ns_delete, ns_exists, ns_not_exists; char *variable; struct { struct expression *val; struct expression *next; } arg; struct { char *name; struct expression *arglist; } funcall; struct fundef *func; } data; int flags; # define EXPR_EPHEMERAL 1 }; /* DNS host entry structure... */ struct dns_host_entry { int refcnt; TIME timeout; struct data_string data; char hostname [1]; }; struct option_cache; /* forward */ struct packet; /* forward */ struct option_state; /* forward */ struct decoded_option_state; /* forward */ struct lease; /* forward */ struct client_state; /* forward */ struct universe { const char *name; struct option_cache *(*lookup_func) (struct universe *, struct option_state *, unsigned); void (*save_func) (struct universe *, struct option_state *, struct option_cache *, isc_boolean_t); void (*foreach) (struct packet *, struct lease *, struct client_state *, struct option_state *, struct option_state *, struct binding_scope **, struct universe *, void *, void (*) (struct option_cache *, struct packet *, struct lease *, struct client_state *, struct option_state *, struct option_state *, struct binding_scope **, struct universe *, void *)); void (*delete_func) (struct universe *universe, struct option_state *, int); int (*option_state_dereference) (struct universe *, struct option_state *, const char *, int); int (*decode) (struct option_state *, const unsigned char *, unsigned, struct universe *); int (*encapsulate) (struct data_string *, struct packet *, struct lease *, struct client_state *, struct option_state *, struct option_state *, struct binding_scope **, struct universe *); u_int32_t (*get_tag) (const unsigned char *); void (*store_tag) (unsigned char *, u_int32_t); u_int32_t (*get_length) (const unsigned char *); void (*store_length) (unsigned char *, u_int32_t); int tag_size, length_size; unsigned site_code_min, end; option_name_hash_t *name_hash; option_code_hash_t *code_hash; struct option *enc_opt; int index; /* Flags should probably become condensed. */ int concat_duplicates; }; struct option { const char *name; const char *format; struct universe *universe; unsigned code; int refcnt; }; dhcp-4.2.4/includes/omapip/alloc.h000644 000765 000024 00000007054 11301372615 016732 0ustar00sarstaff000000 000000 /* alloc.h Definitions for the object management API protocol memory allocation... */ /* * Copyright (c) 2004,2009 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1996-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ * * This software has been written for Internet Systems Consortium * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. * To learn more about Internet Systems Consortium, see * ``https://www.isc.org/''. To learn more about Vixie Enterprises, * see ``http://www.vix.com''. To learn more about Nominum, Inc., see * ``http://www.nominum.com''. */ isc_result_t omapi_buffer_new (omapi_buffer_t **, const char *, int); isc_result_t omapi_buffer_reference (omapi_buffer_t **, omapi_buffer_t *, const char *, int); isc_result_t omapi_buffer_dereference (omapi_buffer_t **, const char *, int); #if defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL) || \ defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT) #define DMDOFFSET (sizeof (struct dmalloc_preamble)) #define DMLFSIZE 16 #define DMUFSIZE 16 #define DMDSIZE (DMDOFFSET + DMLFSIZE + DMUFSIZE) struct dmalloc_preamble { struct dmalloc_preamble *prev, *next; const char *file; int line; size_t size; unsigned long generation; unsigned char low_fence [DMLFSIZE]; }; #else #define DMDOFFSET 0 #define DMDSIZE 0 #endif /* rc_history flags... */ #define RC_LEASE 1 #define RC_MISC 2 #if defined (DEBUG_RC_HISTORY) #if !defined (RC_HISTORY_MAX) # define RC_HISTORY_MAX 256 #endif #if !defined (RC_HISTORY_FLAGS) # define RC_HISTORY_FLAGS (RC_LEASE | RC_MISC) #endif struct rc_history_entry { const char *file; int line; void *reference; void *addr; int refcnt; }; #define rc_register(x, l, r, y, z, d, f) do { \ if (RC_HISTORY_FLAGS & ~(f)) { \ rc_history [rc_history_index].file = (x); \ rc_history [rc_history_index].line = (l); \ rc_history [rc_history_index].reference = (r); \ rc_history [rc_history_index].addr = (y); \ rc_history [rc_history_index].refcnt = (z); \ rc_history_next (d); \ } \ } while (0) #define rc_register_mdl(r, y, z, d, f) \ rc_register (__FILE__, __LINE__, r, y, z, d, f) #else #define rc_register(file, line, reference, addr, refcnt, d, f) #define rc_register_mdl(reference, addr, refcnt, d, f) #endif #if defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL) || \ defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT) extern struct dmalloc_preamble *dmalloc_list; extern unsigned long dmalloc_outstanding; extern unsigned long dmalloc_longterm; extern unsigned long dmalloc_generation; extern unsigned long dmalloc_cutoff_generation; #endif #if defined (DEBUG_RC_HISTORY) extern struct rc_history_entry rc_history [RC_HISTORY_MAX]; extern int rc_history_index; extern int rc_history_count; #endif dhcp-4.2.4/includes/omapip/buffer.h000644 000765 000024 00000007050 11301372615 017105 0ustar00sarstaff000000 000000 /* buffer.h Definitions for the object management API protocol buffering... */ /* * Copyright (c) 2004,2009 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1996-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ * * This software has been written for Internet Systems Consortium * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. * To learn more about Internet Systems Consortium, see * ``https://www.isc.org/''. To learn more about Vixie Enterprises, * see ``http://www.vix.com''. To learn more about Nominum, Inc., see * ``http://www.nominum.com''. */ /* OMAPI buffers are ring buffers, which means that the beginning of the buffer and the end of the buffer chase each other around. As long as the tail never catches up to the head, there's room in the buffer for data. - If the tail and the head are equal, the buffer is empty. - If the tail is less than the head, the contents of the buffer are the bytes from the head to the end of buffer, and in addition, the bytes between the beginning of the buffer and the tail, not including the byte addressed by the tail. - If the tail is greater than the head, then the buffer contains valid bytes starting with the byte addressed by the head, and ending with the byte before the byte addressed by the tail. There will always be at least one byte of waste, because the tail can't increase so that it's equal to the head (that would represent an empty buffer. */ #define OMAPI_BUF_SIZE 4048 typedef struct _omapi_buffer { struct _omapi_buffer *next; /* Buffers can be chained. */ u_int32_t refcnt; /* Buffers are reference counted. */ u_int16_t head, tail; /* Buffers are organized in a ring. */ char buf [OMAPI_BUF_SIZE]; /* The actual buffer is included in the buffer data structure. */ } omapi_buffer_t; #define BUFFER_BYTES_FREE(x) \ ((x) -> tail > (x) -> head \ ? sizeof ((x) -> buf) - ((x) -> tail - (x) -> head) \ : (x) -> head - (x) -> tail) #define BYTES_IN_BUFFER(x) \ ((x) -> tail > (x) -> head \ ? (x) -> tail - (x) -> head - 1 \ : sizeof ((x) -> buf) - ((x) -> head - (x) -> tail) - 1) isc_result_t omapi_connection_require (omapi_object_t *, unsigned); isc_result_t omapi_connection_copyout (unsigned char *, omapi_object_t *, unsigned); isc_result_t omapi_connection_copyin (omapi_object_t *, const unsigned char *, unsigned); isc_result_t omapi_connection_flush (omapi_object_t *); isc_result_t omapi_connection_get_uint32 (omapi_object_t *, u_int32_t *); isc_result_t omapi_connection_put_uint32 (omapi_object_t *, u_int32_t); isc_result_t omapi_connection_get_uint16 (omapi_object_t *, u_int16_t *); isc_result_t omapi_connection_put_uint16 (omapi_object_t *, u_int32_t); dhcp-4.2.4/includes/omapip/convert.h000644 000765 000024 00000004131 11301372615 017311 0ustar00sarstaff000000 000000 /* convert.h Safe copying of integers into and out of a non-aligned memory buffer. */ /* * Copyright (c) 2004,2009 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1996-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ * * This software has been written for Internet Systems Consortium * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. * To learn more about Internet Systems Consortium, see * ``https://www.isc.org/''. To learn more about Vixie Enterprises, * see ``http://www.vix.com''. To learn more about Nominum, Inc., see * ``http://www.nominum.com''. */ #ifndef OMAPI_CONVERT_H #define OMAPI_CONVERT_H u_int32_t getULong (const unsigned char *); int32_t getLong (const unsigned char *); u_int32_t getUShort (const unsigned char *); int32_t getShort (const unsigned char *); u_int32_t getUChar (const unsigned char *); void putULong (unsigned char *, u_int32_t); void putLong (unsigned char *, int32_t); void putUShort (unsigned char *, u_int32_t); void putShort (unsigned char *, int32_t); void putUChar (unsigned char *, u_int32_t); int converted_length (const unsigned char *, unsigned int, unsigned int); int binary_to_ascii (unsigned char *, const unsigned char *, unsigned int, unsigned int); #endif /* OMAPI_CONVERT_H */ dhcp-4.2.4/includes/omapip/hash.h000644 000765 000024 00000014155 11301372615 016563 0ustar00sarstaff000000 000000 /* hash.h Definitions for hashing... */ /* * Copyright (c) 2004,2009 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1995-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ * * This software has been written for Internet Systems Consortium * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. * To learn more about Internet Systems Consortium, see * ``https://www.isc.org/''. To learn more about Vixie Enterprises, * see ``http://www.vix.com''. To learn more about Nominum, Inc., see * ``http://www.nominum.com''. */ #ifndef OMAPI_HASH_H #define OMAPI_HASH_H #if !defined (DEFAULT_HASH_SIZE) # define DEFAULT_HASH_SIZE 9973 #endif #if !defined (KEY_HASH_SIZE) # define KEY_HASH_SIZE 1009 #endif /* The purpose of the hashed_object_t struct is to not match anything else. */ typedef struct { int foo; } hashed_object_t; typedef isc_result_t (*hash_foreach_func)(const void *, unsigned, void *); typedef int (*hash_reference) (hashed_object_t **, hashed_object_t *, const char *, int); typedef int (*hash_dereference) (hashed_object_t **, const char *, int); struct hash_bucket { struct hash_bucket *next; const unsigned char *name; unsigned len; hashed_object_t *value; }; typedef int (*hash_comparator_t)(const void *, const void *, size_t); struct hash_table { unsigned hash_count; hash_reference referencer; hash_dereference dereferencer; hash_comparator_t cmp; unsigned (*do_hash)(const void *, unsigned, unsigned); /* This must remain the last entry in this table. */ struct hash_bucket *buckets [1]; }; struct named_hash { struct named_hash *next; const char *name; struct hash_table *hash; }; #define HASH_FUNCTIONS_DECL(name, bufarg, type, hashtype) \ void name##_hash_add (hashtype *, bufarg, unsigned, type *, \ const char *, int); \ void name##_hash_delete (hashtype *, bufarg, unsigned, \ const char *, int); \ int name##_hash_lookup (type **, hashtype *, bufarg, unsigned, \ const char *, int); \ unsigned char * name##_hash_report(hashtype *); \ int name##_hash_foreach (hashtype *, hash_foreach_func); \ int name##_new_hash (hashtype **, unsigned, const char *, int); \ void name##_free_hash_table (hashtype **, const char *, int); #define HASH_FUNCTIONS(name, bufarg, type, hashtype, ref, deref, hasher) \ void name##_hash_add (hashtype *table, \ bufarg buf, unsigned len, type *ptr, \ const char *file, int line) \ { \ add_hash ((struct hash_table *)table, buf, \ len, (hashed_object_t *)ptr, file, line); \ } \ \ void name##_hash_delete (hashtype *table, bufarg buf, unsigned len, \ const char *file, int line) \ { \ delete_hash_entry ((struct hash_table *)table, buf, len, \ file, line); \ } \ \ int name##_hash_lookup (type **ptr, hashtype *table, \ bufarg buf, unsigned len, const char *file, int line) \ { \ return hash_lookup ((hashed_object_t **)ptr, \ (struct hash_table *)table, \ buf, len, file, line); \ } \ \ unsigned char * name##_hash_report(hashtype *table) \ { \ return hash_report((struct hash_table *)table); \ } \ \ int name##_hash_foreach (hashtype *table, hash_foreach_func func) \ { \ return hash_foreach ((struct hash_table *)table, \ func); \ } \ \ int name##_new_hash (hashtype **tp, unsigned c, const char *file, int line) \ { \ return new_hash ((struct hash_table **)tp, \ (hash_reference)ref, (hash_dereference)deref, c, \ hasher, file, line); \ } \ \ void name##_free_hash_table (hashtype **table, const char *file, int line) \ { \ free_hash_table ((struct hash_table **)table, file, line); \ } void relinquish_hash_bucket_hunks (void); int new_hash_table (struct hash_table **, unsigned, const char *, int); void free_hash_table (struct hash_table **, const char *, int); struct hash_bucket *new_hash_bucket (const char *, int); void free_hash_bucket (struct hash_bucket *, const char *, int); int new_hash(struct hash_table **, hash_reference, hash_dereference, unsigned, unsigned (*do_hash)(const void *, unsigned, unsigned), const char *, int); unsigned do_string_hash(const void *, unsigned, unsigned); unsigned do_case_hash(const void *, unsigned, unsigned); unsigned do_id_hash(const void *, unsigned, unsigned); unsigned do_number_hash(const void *, unsigned, unsigned); unsigned do_ip4_hash(const void *, unsigned, unsigned); unsigned char *hash_report(struct hash_table *); void add_hash (struct hash_table *, const void *, unsigned, hashed_object_t *, const char *, int); void delete_hash_entry (struct hash_table *, const void *, unsigned, const char *, int); int hash_lookup (hashed_object_t **, struct hash_table *, const void *, unsigned, const char *, int); int hash_foreach (struct hash_table *, hash_foreach_func); int casecmp (const void *s, const void *t, size_t len); #endif /* OMAPI_HASH_H */ dhcp-4.2.4/includes/omapip/isclib.h000644 000765 000024 00000005506 11271742256 017115 0ustar00sarstaff000000 000000 /* isclib.h connections to the isc and dns libraries */ /* * Copyright (c) 2009 by Internet Systems Consortium, Inc. ("ISC") * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * http://www.isc.org/ * */ #ifndef ISCLIB_H #define ISCLIB_H #include "config.h" #include #define MAXWIRE 256 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "result.h" /* * DHCP context structure * This holds the libisc information for a dhcp entity */ typedef struct dhcp_context { isc_mem_t *mctx; isc_appctx_t *actx; int actx_started; isc_taskmgr_t *taskmgr; isc_task_t *task; isc_socketmgr_t *socketmgr; isc_timermgr_t *timermgr; #if defined (NSUPDATE) dns_client_t *dnsclient; #endif } dhcp_context_t; extern dhcp_context_t dhcp_gbl_ctx; #define DHCP_MAXDNS_WIRE 256 #define DHCP_MAXNS 3 #define DHCP_HMAC_MD5_NAME "HMAC-MD5.SIG-ALG.REG.INT." isc_result_t dhcp_isc_name(unsigned char *namestr, dns_fixedname_t *namefix, dns_name_t **name); isc_result_t isclib_make_dst_key(char *inname, char *algorithm, unsigned char *secret, int length, dst_key_t **dstkey); isc_result_t dhcp_context_create(void); void isclib_cleanup(void); #endif /* ISCLIB_H */ dhcp-4.2.4/includes/omapip/omapip.h000644 000765 000024 00000060100 11301372615 017114 0ustar00sarstaff000000 000000 /* omapip.h Definitions for the object management API and protocol... */ /* * Copyright (c) 2004,2007,2009 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1996-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ * * This software has been written for Internet Systems Consortium * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. * To learn more about Internet Systems Consortium, see * ``https://www.isc.org/''. To learn more about Vixie Enterprises, * see ``http://www.vix.com''. To learn more about Nominum, Inc., see * ``http://www.nominum.com''. */ #ifndef _OMAPIP_H_ #define _OMAPIP_H_ #include "result.h" #include #include typedef unsigned int omapi_handle_t; struct __omapi_object; typedef struct __omapi_object omapi_object_t; typedef enum { omapi_datatype_int, omapi_datatype_string, omapi_datatype_data, omapi_datatype_object } omapi_datatype_t; typedef struct { int refcnt; omapi_datatype_t type; union { struct { unsigned len; #define OMAPI_TYPED_DATA_NOBUFFER_LEN (sizeof (int) + \ sizeof (omapi_datatype_t) + \ sizeof (int)) unsigned char value [1]; } buffer; #define OMAPI_TYPED_DATA_OBJECT_LEN (sizeof (int) + \ sizeof (omapi_datatype_t) + \ sizeof (omapi_object_t *)) omapi_object_t *object; #define OMAPI_TYPED_DATA_REF_LEN (sizeof (int) + \ sizeof (omapi_datatype_t) + \ 3 * sizeof (void *)) struct { void *ptr; isc_result_t (*reference) (void *, void *, const char *, int); isc_result_t (*dereference) (void *, const char *, int); } ref; #define OMAPI_TYPED_DATA_INT_LEN (sizeof (int) + \ sizeof (omapi_datatype_t) + \ sizeof (int)) int integer; } u; } omapi_typed_data_t; typedef struct { int refcnt; unsigned len; #define OMAPI_DATA_STRING_EMPTY_SIZE (2 * sizeof (int)) unsigned char value [1]; } omapi_data_string_t; typedef struct { int refcnt; omapi_data_string_t *name; omapi_typed_data_t *value; } omapi_value_t; typedef struct __omapi_object_type_t { const char *name; struct __omapi_object_type_t *next; isc_result_t (*set_value) (omapi_object_t *, omapi_object_t *, omapi_data_string_t *, omapi_typed_data_t *); isc_result_t (*get_value) (omapi_object_t *, omapi_object_t *, omapi_data_string_t *, omapi_value_t **); isc_result_t (*destroy) (omapi_object_t *, const char *, int); isc_result_t (*signal_handler) (omapi_object_t *, const char *, va_list); isc_result_t (*stuff_values) (omapi_object_t *, omapi_object_t *, omapi_object_t *); isc_result_t (*lookup) (omapi_object_t **, omapi_object_t *, omapi_object_t *); isc_result_t (*create) (omapi_object_t **, omapi_object_t *); isc_result_t (*remove) (omapi_object_t *, omapi_object_t *); isc_result_t (*freer) (omapi_object_t *, const char *, int); isc_result_t (*allocator) (omapi_object_t **, const char *, int); isc_result_t (*sizer) (size_t); size_t size; int rc_flag; isc_result_t (*initialize) (omapi_object_t *, const char *, int); } omapi_object_type_t; #define OMAPI_OBJECT_PREAMBLE \ omapi_object_type_t *type; \ int refcnt; \ omapi_handle_t handle; \ omapi_object_t *outer, *inner /* The omapi handle structure. */ struct __omapi_object { OMAPI_OBJECT_PREAMBLE; }; /* The port on which applications should listen for OMAPI connections. */ #define OMAPI_PROTOCOL_PORT 7911 typedef struct { unsigned addrtype; unsigned addrlen; unsigned char address [16]; unsigned port; } omapi_addr_t; typedef struct { int refcnt; unsigned count; omapi_addr_t *addresses; } omapi_addr_list_t; typedef struct auth_key { OMAPI_OBJECT_PREAMBLE; char *name; char *algorithm; omapi_data_string_t *key; dns_tsec_t *tsec_key; } omapi_auth_key_t; #define OMAPI_CREATE 1 #define OMAPI_UPDATE 2 #define OMAPI_EXCL 4 #define OMAPI_NOTIFY_PROTOCOL 8 #define OMAPI_OBJECT_ALLOC(name, stype, type) \ isc_result_t name##_allocate (stype **p, const char *file, int line) \ { \ return omapi_object_allocate ((omapi_object_t **)p, \ type, 0, file, line); \ } \ \ isc_result_t name##_reference (stype **pptr, stype *ptr, \ const char *file, int line) \ { \ return omapi_object_reference ((omapi_object_t **)pptr, \ (omapi_object_t *)ptr, file, line); \ } \ \ isc_result_t name##_dereference (stype **ptr, const char *file, int line) \ { \ return omapi_object_dereference ((omapi_object_t **)ptr, file, line); \ } #define OMAPI_OBJECT_ALLOC_DECL(name, stype, type) \ isc_result_t name##_allocate (stype **p, const char *file, int line); \ isc_result_t name##_reference (stype **pptr, stype *ptr, \ const char *file, int line); \ isc_result_t name##_dereference (stype **ptr, const char *file, int line); typedef isc_result_t (*omapi_array_ref_t) (char **, char *, const char *, int); typedef isc_result_t (*omapi_array_deref_t) (char **, const char *, int); /* An extensible array type. */ typedef struct { char **data; omapi_array_ref_t ref; omapi_array_deref_t deref; int count; int max; } omapi_array_t; #define OMAPI_ARRAY_TYPE(name, stype) \ isc_result_t name##_array_allocate (omapi_array_t **p, \ const char *file, int line) \ { \ return (omapi_array_allocate \ (p, \ (omapi_array_ref_t)name##_reference, \ (omapi_array_deref_t)name##_dereference, \ file, line)); \ } \ \ isc_result_t name##_array_free (omapi_array_t **p, \ const char *file, int line) \ { \ return omapi_array_free (p, file, line); \ } \ \ isc_result_t name##_array_extend (omapi_array_t *pptr, stype *ptr, int *index,\ const char *file, int line) \ { \ return omapi_array_extend (pptr, (char *)ptr, index, file, line); \ } \ \ isc_result_t name##_array_set (omapi_array_t *pptr, stype *ptr, int index, \ const char *file, int line) \ { \ return omapi_array_set (pptr, (char *)ptr, index, file, line); \ } \ \ isc_result_t name##_array_lookup (stype **ptr, omapi_array_t *pptr, \ int index, const char *file, int line) \ { \ return omapi_array_lookup ((char **)ptr, pptr, index, file, line); \ } #define OMAPI_ARRAY_TYPE_DECL(name, stype) \ isc_result_t name##_array_allocate (omapi_array_t **, const char *, int); \ isc_result_t name##_array_free (omapi_array_t **, const char *, int); \ isc_result_t name##_array_extend (omapi_array_t *, stype *, int *, \ const char *, int); \ isc_result_t name##_array_set (omapi_array_t *, \ stype *, int, const char *, int); \ isc_result_t name##_array_lookup (stype **, \ omapi_array_t *, int, const char *, int) #define omapi_array_foreach_begin(array, stype, var) \ { \ int omapi_array_foreach_index; \ stype *var = (stype *)0; \ for (omapi_array_foreach_index = 0; \ array && \ omapi_array_foreach_index < (array) -> count; \ omapi_array_foreach_index++) { \ if ((array) -> data [omapi_array_foreach_index]) { \ ((*(array) -> ref) \ ((char **)&var, \ (array) -> data [omapi_array_foreach_index],\ MDL)); #define omapi_array_foreach_end(array, stype, var) \ (*(array) -> deref) ((char **)&var, MDL); \ } \ } \ } isc_result_t omapi_protocol_connect (omapi_object_t *, const char *, unsigned, omapi_object_t *); isc_result_t omapi_connect_list (omapi_object_t *, omapi_addr_list_t *, omapi_addr_t *); isc_result_t omapi_protocol_listen (omapi_object_t *, unsigned, int); isc_boolean_t omapi_protocol_authenticated (omapi_object_t *); isc_result_t omapi_protocol_configure_security (omapi_object_t *, isc_result_t (*) (omapi_object_t *, omapi_addr_t *), isc_result_t (*) (omapi_object_t *, omapi_auth_key_t *)); isc_result_t omapi_protocol_accept (omapi_object_t *); isc_result_t omapi_protocol_send_intro (omapi_object_t *, unsigned, unsigned); isc_result_t omapi_protocol_ready (omapi_object_t *); isc_result_t omapi_protocol_add_auth (omapi_object_t *, omapi_object_t *, omapi_handle_t); isc_result_t omapi_protocol_lookup_auth (omapi_object_t **, omapi_object_t *, omapi_handle_t); isc_result_t omapi_protocol_set_value (omapi_object_t *, omapi_object_t *, omapi_data_string_t *, omapi_typed_data_t *); isc_result_t omapi_protocol_get_value (omapi_object_t *, omapi_object_t *, omapi_data_string_t *, omapi_value_t **); isc_result_t omapi_protocol_stuff_values (omapi_object_t *, omapi_object_t *, omapi_object_t *); isc_result_t omapi_protocol_destroy (omapi_object_t *, const char *, int); isc_result_t omapi_protocol_send_message (omapi_object_t *, omapi_object_t *, omapi_object_t *, omapi_object_t *); isc_result_t omapi_protocol_signal_handler (omapi_object_t *, const char *, va_list); isc_result_t omapi_protocol_listener_set_value (omapi_object_t *, omapi_object_t *, omapi_data_string_t *, omapi_typed_data_t *); isc_result_t omapi_protocol_listener_get_value (omapi_object_t *, omapi_object_t *, omapi_data_string_t *, omapi_value_t **); isc_result_t omapi_protocol_listener_destroy (omapi_object_t *, const char *, int); isc_result_t omapi_protocol_listener_signal (omapi_object_t *, const char *, va_list); isc_result_t omapi_protocol_listener_stuff (omapi_object_t *, omapi_object_t *, omapi_object_t *); isc_result_t omapi_protocol_send_status (omapi_object_t *, omapi_object_t *, isc_result_t, unsigned, const char *); isc_result_t omapi_protocol_send_open (omapi_object_t *, omapi_object_t *, const char *, omapi_object_t *, unsigned); isc_result_t omapi_protocol_send_update (omapi_object_t *, omapi_object_t *, unsigned, omapi_object_t *); isc_result_t omapi_connect (omapi_object_t *, const char *, unsigned); isc_result_t omapi_disconnect (omapi_object_t *, int); int omapi_connection_readfd (omapi_object_t *); int omapi_connection_writefd (omapi_object_t *); isc_result_t omapi_connection_connect (omapi_object_t *); isc_result_t omapi_connection_reader (omapi_object_t *); isc_result_t omapi_connection_writer (omapi_object_t *); isc_result_t omapi_connection_reaper (omapi_object_t *); isc_result_t omapi_connection_output_auth_length (omapi_object_t *, unsigned *); isc_result_t omapi_connection_set_value (omapi_object_t *, omapi_object_t *, omapi_data_string_t *, omapi_typed_data_t *); isc_result_t omapi_connection_get_value (omapi_object_t *, omapi_object_t *, omapi_data_string_t *, omapi_value_t **); isc_result_t omapi_connection_destroy (omapi_object_t *, const char *, int); isc_result_t omapi_connection_signal_handler (omapi_object_t *, const char *, va_list); isc_result_t omapi_connection_stuff_values (omapi_object_t *, omapi_object_t *, omapi_object_t *); isc_result_t omapi_connection_write_typed_data (omapi_object_t *, omapi_typed_data_t *); isc_result_t omapi_connection_put_name (omapi_object_t *, const char *); isc_result_t omapi_connection_put_string (omapi_object_t *, const char *); isc_result_t omapi_connection_put_handle (omapi_object_t *c, omapi_object_t *h); isc_result_t omapi_listen (omapi_object_t *, unsigned, int); isc_result_t omapi_listen_addr (omapi_object_t *, omapi_addr_t *, int); isc_result_t omapi_listener_accept (omapi_object_t *); int omapi_listener_readfd (omapi_object_t *); isc_result_t omapi_accept (omapi_object_t *); isc_result_t omapi_listener_configure_security (omapi_object_t *, isc_result_t (*) (omapi_object_t *, omapi_addr_t *)); isc_result_t omapi_listener_set_value (omapi_object_t *, omapi_object_t *, omapi_data_string_t *, omapi_typed_data_t *); isc_result_t omapi_listener_get_value (omapi_object_t *, omapi_object_t *, omapi_data_string_t *, omapi_value_t **); isc_result_t omapi_listener_destroy (omapi_object_t *, const char *, int); isc_result_t omapi_listener_signal_handler (omapi_object_t *, const char *, va_list); isc_result_t omapi_listener_stuff_values (omapi_object_t *, omapi_object_t *, omapi_object_t *); isc_result_t omapi_register_io_object (omapi_object_t *, int (*)(omapi_object_t *), int (*)(omapi_object_t *), isc_result_t (*)(omapi_object_t *), isc_result_t (*)(omapi_object_t *), isc_result_t (*)(omapi_object_t *)); isc_result_t omapi_reregister_io_object (omapi_object_t *, int (*)(omapi_object_t *), int (*)(omapi_object_t *), isc_result_t (*)(omapi_object_t *), isc_result_t (*)(omapi_object_t *), isc_result_t (*)(omapi_object_t *)); isc_result_t omapi_unregister_io_object (omapi_object_t *); isc_result_t omapi_dispatch (struct timeval *); isc_result_t omapi_wait_for_completion (omapi_object_t *, struct timeval *); isc_result_t omapi_one_dispatch (omapi_object_t *, struct timeval *); isc_result_t omapi_io_set_value (omapi_object_t *, omapi_object_t *, omapi_data_string_t *, omapi_typed_data_t *); isc_result_t omapi_io_get_value (omapi_object_t *, omapi_object_t *, omapi_data_string_t *, omapi_value_t **); isc_result_t omapi_io_destroy (omapi_object_t *, const char *, int); isc_result_t omapi_io_signal_handler (omapi_object_t *, const char *, va_list); isc_result_t omapi_io_stuff_values (omapi_object_t *, omapi_object_t *, omapi_object_t *); isc_result_t omapi_waiter_signal_handler (omapi_object_t *, const char *, va_list); isc_result_t omapi_io_state_foreach (isc_result_t (*func) (omapi_object_t *, void *), void *p); isc_result_t omapi_generic_new (omapi_object_t **, const char *, int); isc_result_t omapi_generic_set_value (omapi_object_t *, omapi_object_t *, omapi_data_string_t *, omapi_typed_data_t *); isc_result_t omapi_generic_get_value (omapi_object_t *, omapi_object_t *, omapi_data_string_t *, omapi_value_t **); isc_result_t omapi_generic_destroy (omapi_object_t *, const char *, int); isc_result_t omapi_generic_signal_handler (omapi_object_t *, const char *, va_list); isc_result_t omapi_generic_stuff_values (omapi_object_t *, omapi_object_t *, omapi_object_t *); isc_result_t omapi_generic_clear_flags (omapi_object_t *); isc_result_t omapi_message_new (omapi_object_t **, const char *, int); isc_result_t omapi_message_set_value (omapi_object_t *, omapi_object_t *, omapi_data_string_t *, omapi_typed_data_t *); isc_result_t omapi_message_get_value (omapi_object_t *, omapi_object_t *, omapi_data_string_t *, omapi_value_t **); isc_result_t omapi_message_destroy (omapi_object_t *, const char *, int); isc_result_t omapi_message_signal_handler (omapi_object_t *, const char *, va_list); isc_result_t omapi_message_stuff_values (omapi_object_t *, omapi_object_t *, omapi_object_t *); isc_result_t omapi_message_register (omapi_object_t *); isc_result_t omapi_message_unregister (omapi_object_t *); isc_result_t omapi_message_process (omapi_object_t *, omapi_object_t *); OMAPI_OBJECT_ALLOC_DECL (omapi_auth_key, omapi_auth_key_t, omapi_type_auth_key) isc_result_t omapi_auth_key_new (omapi_auth_key_t **, const char *, int); isc_result_t omapi_auth_key_destroy (omapi_object_t *, const char *, int); isc_result_t omapi_auth_key_enter (omapi_auth_key_t *); isc_result_t omapi_auth_key_lookup_name (omapi_auth_key_t **, const char *); isc_result_t omapi_auth_key_lookup (omapi_object_t **, omapi_object_t *, omapi_object_t *); isc_result_t omapi_auth_key_get_value (omapi_object_t *, omapi_object_t *, omapi_data_string_t *, omapi_value_t **); isc_result_t omapi_auth_key_stuff_values (omapi_object_t *, omapi_object_t *, omapi_object_t *); extern omapi_object_type_t *omapi_type_connection; extern omapi_object_type_t *omapi_type_listener; extern omapi_object_type_t *omapi_type_io_object; extern omapi_object_type_t *omapi_type_generic; extern omapi_object_type_t *omapi_type_protocol; extern omapi_object_type_t *omapi_type_protocol_listener; extern omapi_object_type_t *omapi_type_waiter; extern omapi_object_type_t *omapi_type_remote; extern omapi_object_type_t *omapi_type_message; extern omapi_object_type_t *omapi_type_auth_key; extern omapi_object_type_t *omapi_object_types; void omapi_type_relinquish (void); isc_result_t omapi_init (void); isc_result_t omapi_object_type_register (omapi_object_type_t **, const char *, isc_result_t (*) (omapi_object_t *, omapi_object_t *, omapi_data_string_t *, omapi_typed_data_t *), isc_result_t (*) (omapi_object_t *, omapi_object_t *, omapi_data_string_t *, omapi_value_t **), isc_result_t (*) (omapi_object_t *, const char *, int), isc_result_t (*) (omapi_object_t *, const char *, va_list), isc_result_t (*) (omapi_object_t *, omapi_object_t *, omapi_object_t *), isc_result_t (*) (omapi_object_t **, omapi_object_t *, omapi_object_t *), isc_result_t (*) (omapi_object_t **, omapi_object_t *), isc_result_t (*) (omapi_object_t *, omapi_object_t *), isc_result_t (*) (omapi_object_t *, const char *, int), isc_result_t (*) (omapi_object_t **, const char *, int), isc_result_t (*) (size_t), size_t, isc_result_t (*) (omapi_object_t *, const char *, int), int); isc_result_t omapi_signal (omapi_object_t *, const char *, ...); isc_result_t omapi_signal_in (omapi_object_t *, const char *, ...); isc_result_t omapi_set_value (omapi_object_t *, omapi_object_t *, omapi_data_string_t *, omapi_typed_data_t *); isc_result_t omapi_set_value_str (omapi_object_t *, omapi_object_t *, const char *, omapi_typed_data_t *); isc_result_t omapi_set_boolean_value (omapi_object_t *, omapi_object_t *, const char *, int); isc_result_t omapi_set_int_value (omapi_object_t *, omapi_object_t *, const char *, int); isc_result_t omapi_set_object_value (omapi_object_t *, omapi_object_t *, const char *, omapi_object_t *); isc_result_t omapi_set_string_value (omapi_object_t *, omapi_object_t *, const char *, const char *); isc_result_t omapi_get_value (omapi_object_t *, omapi_object_t *, omapi_data_string_t *, omapi_value_t **); isc_result_t omapi_get_value_str (omapi_object_t *, omapi_object_t *, const char *, omapi_value_t **); isc_result_t omapi_stuff_values (omapi_object_t *, omapi_object_t *, omapi_object_t *); isc_result_t omapi_object_create (omapi_object_t **, omapi_object_t *, omapi_object_type_t *); isc_result_t omapi_object_update (omapi_object_t *, omapi_object_t *, omapi_object_t *, omapi_handle_t); int omapi_data_string_cmp (omapi_data_string_t *, omapi_data_string_t *); int omapi_ds_strcmp (omapi_data_string_t *, const char *); int omapi_td_strcmp (omapi_typed_data_t *, const char *); int omapi_td_strcasecmp (omapi_typed_data_t *, const char *); isc_result_t omapi_make_value (omapi_value_t **, omapi_data_string_t *, omapi_typed_data_t *, const char *, int); isc_result_t omapi_make_const_value (omapi_value_t **, omapi_data_string_t *, const unsigned char *, unsigned, const char *, int); isc_result_t omapi_make_int_value (omapi_value_t **, omapi_data_string_t *, int, const char *, int); isc_result_t omapi_make_uint_value (omapi_value_t **, omapi_data_string_t *, unsigned int, const char *, int); isc_result_t omapi_make_object_value (omapi_value_t **, omapi_data_string_t *, omapi_object_t *, const char *, int); isc_result_t omapi_make_handle_value (omapi_value_t **, omapi_data_string_t *, omapi_object_t *, const char *, int); isc_result_t omapi_make_string_value (omapi_value_t **, omapi_data_string_t *, const char *, const char *, int); isc_result_t omapi_get_int_value (unsigned long *, omapi_typed_data_t *); isc_result_t omapi_object_handle (omapi_handle_t *, omapi_object_t *); isc_result_t omapi_handle_lookup (omapi_object_t **, omapi_handle_t); isc_result_t omapi_handle_td_lookup (omapi_object_t **, omapi_typed_data_t *); void * dmalloc (unsigned, const char *, int); void dfree (void *, const char *, int); #if defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL) || \ defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT) void dmalloc_reuse (void *, const char *, int, int); void dmalloc_dump_outstanding (void); #else #define dmalloc_reuse(x,y,l,z) #endif #define MDL __FILE__, __LINE__ #if defined (DEBUG_RC_HISTORY) void dump_rc_history (void *); void rc_history_next (int); #endif void omapi_print_dmalloc_usage_by_caller (void); isc_result_t omapi_object_allocate (omapi_object_t **, omapi_object_type_t *, size_t, const char *, int); isc_result_t omapi_object_initialize (omapi_object_t *, omapi_object_type_t *, size_t, size_t, const char *, int); isc_result_t omapi_object_reference (omapi_object_t **, omapi_object_t *, const char *, int); isc_result_t omapi_object_dereference (omapi_object_t **, const char *, int); isc_result_t omapi_typed_data_new (const char *, int, omapi_typed_data_t **, omapi_datatype_t, ...); isc_result_t omapi_typed_data_reference (omapi_typed_data_t **, omapi_typed_data_t *, const char *, int); isc_result_t omapi_typed_data_dereference (omapi_typed_data_t **, const char *, int); isc_result_t omapi_data_string_new (omapi_data_string_t **, unsigned, const char *, int); isc_result_t omapi_data_string_reference (omapi_data_string_t **, omapi_data_string_t *, const char *, int); isc_result_t omapi_data_string_dereference (omapi_data_string_t **, const char *, int); isc_result_t omapi_value_new (omapi_value_t **, const char *, int); isc_result_t omapi_value_reference (omapi_value_t **, omapi_value_t *, const char *, int); isc_result_t omapi_value_dereference (omapi_value_t **, const char *, int); isc_result_t omapi_addr_list_new (omapi_addr_list_t **, unsigned, const char *, int); isc_result_t omapi_addr_list_reference (omapi_addr_list_t **, omapi_addr_list_t *, const char *, int); isc_result_t omapi_addr_list_dereference (omapi_addr_list_t **, const char *, int); isc_result_t omapi_array_allocate (omapi_array_t **, omapi_array_ref_t, omapi_array_deref_t, const char *, int); isc_result_t omapi_array_free (omapi_array_t **, const char *, int); isc_result_t omapi_array_extend (omapi_array_t *, char *, int *, const char *, int); isc_result_t omapi_array_set (omapi_array_t *, void *, int, const char *, int); isc_result_t omapi_array_lookup (char **, omapi_array_t *, int, const char *, int); OMAPI_ARRAY_TYPE_DECL(omapi_object, omapi_object_t); #endif /* _OMAPIP_H_ */ dhcp-4.2.4/includes/omapip/omapip_p.h000644 000765 000024 00000022545 11717277025 017460 0ustar00sarstaff000000 000000 /* omapip_p.h Private master include file for the OMAPI library. */ /* * Copyright (c) 2009-2010 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 2004,2007 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1996-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ * * This software has been written for Internet Systems Consortium * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. * To learn more about Internet Systems Consortium, see * ``https://www.isc.org/''. To learn more about Vixie Enterprises, * see ``http://www.vix.com''. To learn more about Nominum, Inc., see * ``http://www.nominum.com''. */ #ifndef __OMAPIP_OMAPIP_P_H__ #define __OMAPIP_OMAPIP_P_H__ #ifndef __CYGWIN32__ #include #include #include #include #include #include #else #define fd_set cygwin_fd_set #include #endif #include #include #include #include #include #include #include #include #include /* * XXX: I'm not sure why these were here. #include "cdefs.h" #include "osdep.h" */ #include #include "result.h" #include #include #include #include /* DST_API control flags */ /* These are used in functions dst_sign_data and dst_verify_data */ #define SIG_MODE_INIT 1 /* initalize digest */ #define SIG_MODE_UPDATE 2 /* add data to digest */ #define SIG_MODE_FINAL 4 /* generate/verify signature */ #define SIG_MODE_ALL (SIG_MODE_INIT|SIG_MODE_UPDATE|SIG_MODE_FINAL) /* OMAPI protocol header, version 1.00 */ typedef struct { u_int32_t authlen; /* Length of authenticator. */ u_int32_t authid; /* Authenticator object ID. */ u_int32_t op; /* Opcode. */ omapi_handle_t handle; /* Handle of object being operated on, or zero. */ u_int32_t id; /* Transaction ID. */ u_int32_t rid; /* ID of transaction to which this is a response. */ } omapi_protocol_header_t; #define OMAPI_PROTOCOL_VERSION 100 #define OMAPI_OP_OPEN 1 #define OMAPI_OP_REFRESH 2 #define OMAPI_OP_UPDATE 3 #define OMAPI_OP_NOTIFY 4 #define OMAPI_OP_STATUS 5 #define OMAPI_OP_DELETE 6 typedef enum { omapi_connection_unconnected, omapi_connection_connecting, omapi_connection_connected, omapi_connection_disconnecting, omapi_connection_closed } omapi_connection_state_t; typedef enum { omapi_protocol_intro_wait, omapi_protocol_header_wait, omapi_protocol_signature_wait, omapi_protocol_name_wait, omapi_protocol_name_length_wait, omapi_protocol_value_wait, omapi_protocol_value_length_wait } omapi_protocol_state_t; typedef struct __omapi_message_object { OMAPI_OBJECT_PREAMBLE; struct __omapi_message_object *next, *prev; omapi_object_t *object; omapi_object_t *notify_object; struct __omapi_protocol_object *protocol_object; u_int32_t authlen; omapi_typed_data_t *authenticator; u_int32_t authid; omapi_object_t *id_object; u_int32_t op; u_int32_t h; u_int32_t id; u_int32_t rid; } omapi_message_object_t; typedef struct __omapi_remote_auth { struct __omapi_remote_auth *next; omapi_handle_t remote_handle; omapi_object_t *a; } omapi_remote_auth_t; typedef struct __omapi_protocol_object { OMAPI_OBJECT_PREAMBLE; u_int32_t header_size; u_int32_t protocol_version; u_int32_t next_xid; omapi_protocol_state_t state; /* Input state. */ int reading_message_values; /* True if reading message-specific values. */ omapi_message_object_t *message; /* Incoming message. */ omapi_data_string_t *name; /* Incoming name. */ omapi_typed_data_t *value; /* Incoming value. */ isc_result_t verify_result; omapi_remote_auth_t *default_auth; /* Default authinfo to use. */ omapi_remote_auth_t *remote_auth_list; /* Authenticators active on this connection. */ isc_boolean_t insecure; /* Set to allow unauthenticated messages. */ isc_result_t (*verify_auth) (omapi_object_t *, omapi_auth_key_t *); } omapi_protocol_object_t; typedef struct { OMAPI_OBJECT_PREAMBLE; isc_boolean_t insecure; /* Set to allow unauthenticated messages. */ isc_result_t (*verify_auth) (omapi_object_t *, omapi_auth_key_t *); } omapi_protocol_listener_object_t; #include typedef struct __omapi_listener_object { OMAPI_OBJECT_PREAMBLE; int socket; /* Connection socket. */ int index; struct sockaddr_in address; isc_result_t (*verify_addr) (omapi_object_t *, omapi_addr_t *); } omapi_listener_object_t; typedef struct __omapi_connection_object { OMAPI_OBJECT_PREAMBLE; int socket; /* Connection socket. */ int32_t index; omapi_connection_state_t state; struct sockaddr_in remote_addr; struct sockaddr_in local_addr; omapi_addr_list_t *connect_list; /* List of addresses to which to connect. */ int cptr; /* Current element we are connecting to. */ u_int32_t bytes_needed; /* Bytes of input needed before wakeup. */ u_int32_t in_bytes; /* Bytes of input already buffered. */ omapi_buffer_t *inbufs; u_int32_t out_bytes; /* Bytes of output in buffers. */ omapi_buffer_t *outbufs; omapi_listener_object_t *listener; /* Listener that accepted this connection, if any. */ dst_key_t *in_key; /* Authenticator signing incoming data. */ void *in_context; /* Input hash context. */ dst_key_t *out_key; /* Authenticator signing outgoing data. */ void *out_context; /* Output hash context. */ } omapi_connection_object_t; typedef struct __omapi_io_object { OMAPI_OBJECT_PREAMBLE; struct __omapi_io_object *next; int (*readfd) (omapi_object_t *); int (*writefd) (omapi_object_t *); isc_result_t (*reader) (omapi_object_t *); isc_result_t (*writer) (omapi_object_t *); isc_result_t (*reaper) (omapi_object_t *); isc_socket_t *fd; isc_boolean_t closed; /* ISC_TRUE = closed, do not use */ } omapi_io_object_t; typedef struct __omapi_generic_object { OMAPI_OBJECT_PREAMBLE; omapi_value_t **values; u_int8_t *changed; int nvalues, va_max; } omapi_generic_object_t; typedef struct __omapi_waiter_object { OMAPI_OBJECT_PREAMBLE; int ready; isc_result_t waitstatus; struct __omapi_waiter_object *next; } omapi_waiter_object_t; #define OMAPI_HANDLE_TABLE_SIZE 120 typedef struct __omapi_handle_table { omapi_handle_t first, limit; omapi_handle_t next; int leafp; union { omapi_object_t *object; struct __omapi_handle_table *table; } children [OMAPI_HANDLE_TABLE_SIZE]; } omapi_handle_table_t; #include OMAPI_OBJECT_ALLOC_DECL (omapi_protocol, omapi_protocol_object_t, omapi_type_protocol) OMAPI_OBJECT_ALLOC_DECL (omapi_protocol_listener, omapi_protocol_listener_object_t, omapi_type_protocol_listener) OMAPI_OBJECT_ALLOC_DECL (omapi_connection, omapi_connection_object_t, omapi_type_connection) OMAPI_OBJECT_ALLOC_DECL (omapi_listener, omapi_listener_object_t, omapi_type_listener) OMAPI_OBJECT_ALLOC_DECL (omapi_io, omapi_io_object_t, omapi_type_io_object) OMAPI_OBJECT_ALLOC_DECL (omapi_waiter, omapi_waiter_object_t, omapi_type_waiter) OMAPI_OBJECT_ALLOC_DECL (omapi_generic, omapi_generic_object_t, omapi_type_generic) OMAPI_OBJECT_ALLOC_DECL (omapi_message, omapi_message_object_t, omapi_type_message) isc_result_t omapi_connection_sign_data (int mode, dst_key_t *key, void **context, const unsigned char *data, const unsigned len, omapi_typed_data_t **result); isc_result_t omapi_listener_connect (omapi_connection_object_t **obj, omapi_listener_object_t *listener, int socket, struct sockaddr_in *remote_addr); void omapi_listener_trace_setup (void); void omapi_connection_trace_setup (void); void omapi_buffer_trace_setup (void); void omapi_connection_register (omapi_connection_object_t *, const char *, int); OMAPI_ARRAY_TYPE_DECL(omapi_listener, omapi_listener_object_t); OMAPI_ARRAY_TYPE_DECL(omapi_connection, omapi_connection_object_t); isc_result_t omapi_handle_clear(omapi_handle_t); extern int log_priority; extern int log_perror; extern void (*log_cleanup) (void); void log_fatal (const char *, ...) __attribute__((__format__(__printf__,1,2))) ISC_DHCP_NORETURN; int log_error (const char *, ...) __attribute__((__format__(__printf__,1,2))); int log_info (const char *, ...) __attribute__((__format__(__printf__,1,2))); int log_debug (const char *, ...) __attribute__((__format__(__printf__,1,2))); void do_percentm (char *obuf, const char *ibuf); isc_result_t uerr2isc (int); isc_result_t ns_rcode_to_isc (int); extern omapi_message_object_t *omapi_registered_messages; #endif /* __OMAPIP_OMAPIP_P_H__ */ dhcp-4.2.4/includes/omapip/result.h000644 000765 000024 00000011107 11271742256 017160 0ustar00sarstaff000000 000000 /* result.h */ /* * Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ */ #ifndef DHCP_RESULT_H #define DHCP_RESULT_H 1 #include #include #include #include /* * DHCP result codes */ /* * In the previous code the results started at 36 * rather than ISC_RESULTCLASS_DHCP + 0 * ISC_R_NOTCONNECTED was + 4 (40), it has been superseded by the isc version */ #define DHCP_R_HOSTUNKNOWN (ISC_RESULTCLASS_DHCP + 0) #define DHCP_R_VERSIONMISMATCH (ISC_RESULTCLASS_DHCP + 1) #define DHCP_R_PROTOCOLERROR (ISC_RESULTCLASS_DHCP + 2) #define DHCP_R_INVALIDARG (ISC_RESULTCLASS_DHCP + 3) #define DHCP_R_NOTYET (ISC_RESULTCLASS_DHCP + 4) #define DHCP_R_UNCHANGED (ISC_RESULTCLASS_DHCP + 5) #define DHCP_R_MULTIPLE (ISC_RESULTCLASS_DHCP + 6) #define DHCP_R_KEYCONFLICT (ISC_RESULTCLASS_DHCP + 7) #define DHCP_R_BADPARSE (ISC_RESULTCLASS_DHCP + 8) #define DHCP_R_NOKEYS (ISC_RESULTCLASS_DHCP + 9) #define DHCP_R_KEY_UNKNOWN (ISC_RESULTCLASS_DHCP + 10) #define DHCP_R_INVALIDKEY (ISC_RESULTCLASS_DHCP + 11) #define DHCP_R_INCOMPLETE (ISC_RESULTCLASS_DHCP + 12) #define DHCP_R_FORMERR (ISC_RESULTCLASS_DHCP + 13) #define DHCP_R_SERVFAIL (ISC_RESULTCLASS_DHCP + 14) #define DHCP_R_NXDOMAIN (ISC_RESULTCLASS_DHCP + 15) #define DHCP_R_NOTIMPL (ISC_RESULTCLASS_DHCP + 16) #define DHCP_R_REFUSED (ISC_RESULTCLASS_DHCP + 17) #define DHCP_R_YXDOMAIN (ISC_RESULTCLASS_DHCP + 18) #define DHCP_R_YXRRSET (ISC_RESULTCLASS_DHCP + 19) #define DHCP_R_NXRRSET (ISC_RESULTCLASS_DHCP + 20) #define DHCP_R_NOTAUTH (ISC_RESULTCLASS_DHCP + 21) #define DHCP_R_NOTZONE (ISC_RESULTCLASS_DHCP + 22) #define DHCP_R_BADSIG (ISC_RESULTCLASS_DHCP + 23) #define DHCP_R_BADKEY (ISC_RESULTCLASS_DHCP + 24) #define DHCP_R_BADTIME (ISC_RESULTCLASS_DHCP + 25) #define DHCP_R_NOROOTZONE (ISC_RESULTCLASS_DHCP + 26) #define DHCP_R_DESTADDRREQ (ISC_RESULTCLASS_DHCP + 27) #define DHCP_R_CROSSZONE (ISC_RESULTCLASS_DHCP + 28) #define DHCP_R_NO_TSIG (ISC_RESULTCLASS_DHCP + 29) #define DHCP_R_NOT_EQUAL (ISC_RESULTCLASS_DHCP + 30) #define DHCP_R_CONNRESET (ISC_RESULTCLASS_DHCP + 31) #define DHCP_R_UNKNOWNATTRIBUTE (ISC_RESULTCLASS_DHCP + 32) #define DHCP_R_NRESULTS 33 /*%< Number of results */ // Included for historical reasons, these should be removed as // soon as reasonable #define ISC_R_HOSTUNKNOWN DHCP_R_HOSTUNKNOWN #define ISC_R_VERSIONMISMATCH DHCP_R_VERSIONMISMATCH #define ISC_R_PROTOCOLERROR DHCP_R_PROTOCOLERROR #define ISC_R_INVALIDARG DHCP_R_INVALIDARG #define ISC_R_NOTYET DHCP_R_NOTYET #define ISC_R_UNCHANGED DHCP_R_UNCHANGED #define ISC_R_MULTIPLE DHCP_R_MULTIPLE #define ISC_R_KEYCONFLICT DHCP_R_KEYCONFLICT #define ISC_R_BADPARSE DHCP_R_BADPARSE #define ISC_R_NOKEYS DHCP_R_NOKEYS #define ISC_R_KEY_UNKNOWN DHCP_R_KEY_UNKNOWN #define ISC_R_INVALIDKEY DHCP_R_INVALIDKEY #define ISC_R_INCOMPLETE DHCP_R_INCOMPLETE #define ISC_R_FORMERR DHCP_R_FORMERR #define ISC_R_SERVFAIL DHCP_R_SERVFAIL #define ISC_R_NXDOMAIN DHCP_R_NXDOMAIN #define ISC_R_NOTIMPL DHCP_R_NOTIMPL #define ISC_R_REFUSED DHCP_R_REFUSED #define ISC_R_YXDOMAIN DHCP_R_YXDOMAIN #define ISC_R_YXRRSET DHCP_R_YXRRSET #define ISC_R_NXRRSET DHCP_R_NXRRSET #define ISC_R_NOTAUTH DHCP_R_NOTAUTH #define ISC_R_NOTZONE DHCP_R_NOTZONE #define ISC_R_BADSIG DHCP_R_BADSIG #define ISC_R_BADKEY DHCP_R_BADKEY #define ISC_R_BADTIME DHCP_R_BADTIME #define ISC_R_NOROOTZONE DHCP_R_NOROOTZONE #define ISC_R_DESTADDRREQ DHCP_R_DESTADDRREQ #define ISC_R_CROSSZONE DHCP_R_CROSSZONE #define ISC_R_NO_TSIG DHCP_R_NO_TSIG #define ISC_R_NOT_EQUAL DHCP_R_NOT_EQUAL #define ISC_R_CONNRESET DHCP_R_CONNRESET #define ISC_R_UNKNOWNATTRIBUTE DHCP_R_UNKNOWNATTRIBUTE isc_result_t dhcp_result_register(void); #endif /* DHCP_RESULT_H */ dhcp-4.2.4/includes/omapip/trace.h000644 000765 000024 00000010232 11301372615 016726 0ustar00sarstaff000000 000000 /* trace.h Definitions for omapi tracing facility... */ /* * Copyright (c) 2004,2005,2007,2009 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 2001-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ * * This software has been written for Internet Systems Consortium * by Ted Lemon, as part of a project for Nominum, Inc. To learn more * about Internet Systems Consortium, see https://www.isc.org/. To * learn more about Nominum, Inc., see ``http://www.nominum.com''. */ #define TRACEFILE_MAGIC 0x64484370UL /* dHCp */ #define TRACEFILE_VERSION 1 /* The first thing in a trace file is the header, which basically just defines the version of the file. */ typedef struct { u_int32_t magic; /* Magic number for trace file. */ u_int32_t version; /* Version of file. */ int32_t hlen; /* Length of this header. */ int32_t phlen; /* Length of packet headers. */ } tracefile_header_t; /* The trace file is composed of a bunch of trace packets. Each such packet has a type, followed by a length, followed by a timestamp, followed by the actual contents of the packet. The type indexes are not fixed - they are allocated either on readback or when writing a trace file. One index type is reserved - type zero means that this record is a type name to index mapping. */ typedef struct { u_int32_t type_index; /* Index to the type of handler that this packet needs. */ u_int32_t length; /* Length of the packet. This includes everything except the fixed header. */ u_int32_t when; /* When the packet was written. */ u_int32_t pad; /* Round this out to a quad boundary. */ } tracepacket_t; #define TRACE_INDEX_MAPPING_SIZE 4 /* trace_index_mapping_t less name. */ typedef struct { u_int32_t index; char name [1]; } trace_index_mapping_t; struct trace_type; /* forward */ typedef struct trace_type trace_type_t; struct trace_type { trace_type_t *next; int index; char *name; void *baggage; void (*have_packet) (trace_type_t *, unsigned, char *); void (*stop_tracing) (trace_type_t *); }; typedef struct trace_iov { const char *buf; unsigned len; } trace_iov_t; typedef struct { u_int16_t addrtype; u_int16_t addrlen; u_int8_t address [16]; u_int16_t port; } trace_addr_t; void trace_free_all (void); int trace_playback (void); int trace_record (void); isc_result_t trace_init(void (*set_time)(time_t), const char *, int); isc_result_t trace_begin (const char *, const char *, int); isc_result_t trace_write_packet (trace_type_t *, unsigned, const char *, const char *, int); isc_result_t trace_write_packet_iov (trace_type_t *, int, trace_iov_t *, const char *, int); void trace_type_stash (trace_type_t *); trace_type_t *trace_type_register (const char *, void *, void (*) (trace_type_t *, unsigned, char *), void (*) (trace_type_t *), const char *, int); void trace_stop (void); void trace_index_map_input (trace_type_t *, unsigned, char *); void trace_index_stop_tracing (trace_type_t *); void trace_replay_init (void); void trace_file_replay (const char *); isc_result_t trace_get_next_packet (trace_type_t **, tracepacket_t *, char **, unsigned *, unsigned *); isc_result_t trace_get_file (trace_type_t *, const char *, unsigned *, char **); isc_result_t trace_get_packet (trace_type_t **, unsigned *, char **); time_t trace_snoop_time (trace_type_t **); dhcp-4.2.4/includes/netinet/if_ether.h000644 000765 000024 00000005121 10745742222 017605 0ustar00sarstaff000000 000000 /* $NetBSD: if_ether.h,v 1.20 1995/06/12 00:47:27 mycroft Exp $ */ /* * Copyright (c) 1982, 1986, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)if_ether.h 8.1 (Berkeley) 6/10/93 */ #ifndef netinet_if_ether_h #define netinet_if_ether_h /* * Ethernet address - 6 octets * this is only used by the ethers(3) functions. */ struct ether_addr { u_int8_t ether_addr_octet[6]; }; /* * Structure of a 10Mb/s Ethernet header. */ #define ETHER_ADDR_LEN 6 struct isc_ether_header { u_int8_t ether_dhost[ETHER_ADDR_LEN]; u_int8_t ether_shost[ETHER_ADDR_LEN]; u_int16_t ether_type; }; #define ETHERTYPE_PUP 0x0200 /* PUP protocol */ #define ETHERTYPE_IP 0x0800 /* IP protocol */ #define ETHERTYPE_ARP 0x0806 /* address resolution protocol */ #define ETHER_HEADER_SIZE (ETHER_ADDR_LEN * 2 + sizeof (u_int16_t)) #endif dhcp-4.2.4/includes/netinet/ip.h000644 000765 000024 00000013312 07045622405 016430 0ustar00sarstaff000000 000000 /* $NetBSD: ip.h,v 1.9 1995/05/15 01:22:44 cgd Exp $ */ /* * Copyright (c) 1982, 1986, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)ip.h 8.1 (Berkeley) 6/10/93 */ /* * Definitions for internet protocol version 4. * Per RFC 791, September 1981. */ #define IPVERSION 4 /* * Structure of an internet header, naked of options. * * We declare ip_len and ip_off to be short, rather than u_short * pragmatically since otherwise unsigned comparisons can result * against negative integers quite easily, and fail in subtle ways. */ struct ip { u_int8_t ip_fvhl; /* header length, version */ u_int8_t ip_tos; /* type of service */ int16_t ip_len; /* total length */ u_int16_t ip_id; /* identification */ int16_t ip_off; /* fragment offset field */ #define IP_DF 0x4000 /* dont fragment flag */ #define IP_MF 0x2000 /* more fragments flag */ #define IP_OFFMASK 0x1fff /* mask for fragmenting bits */ u_int8_t ip_ttl; /* time to live */ u_int8_t ip_p; /* protocol */ u_int16_t ip_sum; /* checksum */ struct in_addr ip_src, ip_dst; /* source and dest address */ }; #define IP_V(iph) ((iph)->ip_fvhl >> 4) #define IP_HL(iph) (((iph)->ip_fvhl & 0x0F) << 2) #define IP_V_SET(iph,x) ((iph)->ip_fvhl = ((iph)->ip_fvhl & 0x0F) | ((x) << 4)) #define IP_HL_SET(iph,x) ((iph)->ip_fvhl = \ ((iph)->ip_fvhl & 0xF0) | (((x) >> 2) & 0x0F)) #define IP_MAXPACKET 65535 /* maximum packet size */ /* * Definitions for IP type of service (ip_tos) */ #define IPTOS_LOWDELAY 0x10 #define IPTOS_THROUGHPUT 0x08 #define IPTOS_RELIABILITY 0x04 /* IPTOS_LOWCOST 0x02 XXX */ /* * Definitions for IP precedence (also in ip_tos) (hopefully unused) */ #define IPTOS_PREC_NETCONTROL 0xe0 #define IPTOS_PREC_INTERNETCONTROL 0xc0 #define IPTOS_PREC_CRITIC_ECP 0xa0 #define IPTOS_PREC_FLASHOVERRIDE 0x80 #define IPTOS_PREC_FLASH 0x60 #define IPTOS_PREC_IMMEDIATE 0x40 #define IPTOS_PREC_PRIORITY 0x20 #define IPTOS_PREC_ROUTINE 0x00 /* * Definitions for options. */ #define IPOPT_COPIED(o) ((o)&0x80) #define IPOPT_CLASS(o) ((o)&0x60) #define IPOPT_NUMBER(o) ((o)&0x1f) #define IPOPT_CONTROL 0x00 #define IPOPT_RESERVED1 0x20 #define IPOPT_DEBMEAS 0x40 #define IPOPT_RESERVED2 0x60 #define IPOPT_EOL 0 /* end of option list */ #define IPOPT_NOP 1 /* no operation */ #define IPOPT_RR 7 /* record packet route */ #define IPOPT_TS 68 /* timestamp */ #define IPOPT_SECURITY 130 /* provide s,c,h,tcc */ #define IPOPT_LSRR 131 /* loose source route */ #define IPOPT_SATID 136 /* satnet id */ #define IPOPT_SSRR 137 /* strict source route */ /* * Offsets to fields in options other than EOL and NOP. */ #define IPOPT_OPTVAL 0 /* option ID */ #define IPOPT_OLEN 1 /* option length */ #define IPOPT_OFFSET 2 /* offset within option */ #define IPOPT_MINOFF 4 /* min value of above */ /* * Time stamp option structure. */ struct ip_timestamp { u_int8_t ipt_code; /* IPOPT_TS */ u_int8_t ipt_len; /* size of structure (variable) */ u_int8_t ipt_ptr; /* index of current entry */ u_int8_t ipt_flg_oflw; /* flags, see below, overflow counter */ union ipt_timestamp { u_int32_t ipt_time[1]; struct ipt_ta { struct in_addr ipt_addr; u_int32_t ipt_time; } ipt_ta[1]; } ipt_timestamp; }; /* flag bits for ipt_flg */ #define IPOPT_TS_TSONLY 0 /* timestamps only */ #define IPOPT_TS_TSANDADDR 1 /* timestamps and addresses */ #define IPOPT_TS_PRESPEC 3 /* specified modules only */ /* bits for security (not byte swapped) */ #define IPOPT_SECUR_UNCLASS 0x0000 #define IPOPT_SECUR_CONFID 0xf135 #define IPOPT_SECUR_EFTO 0x789a #define IPOPT_SECUR_MMMM 0xbc4d #define IPOPT_SECUR_RESTR 0xaf13 #define IPOPT_SECUR_SECRET 0xd788 #define IPOPT_SECUR_TOPSECRET 0x6bc5 /* * Internet implementation parameters. */ #define MAXTTL 255 /* maximum time to live (seconds) */ #define IPDEFTTL 64 /* default ttl, from RFC 1340 */ #define IPFRAGTTL 60 /* time to live for frags, slowhz */ #define IPTTLDEC 1 /* subtracted when forwarding */ #define IP_MSS 576 /* default maximum segment size */ dhcp-4.2.4/includes/netinet/ip_icmp.h000644 000765 000024 00000015673 06307471140 017452 0ustar00sarstaff000000 000000 /* $NetBSD: ip_icmp.h,v 1.11 1996/08/03 15:48:18 neil Exp $ */ /* * Copyright (c) 1982, 1986, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)ip_icmp.h 8.1 (Berkeley) 6/10/93 */ /* * Interface Control Message Protocol Definitions. * Per RFC 792, September 1981. */ /* * Internal of an ICMP Router Advertisement */ struct icmp_ra_addr { u_int32_t ira_addr; u_int32_t ira_preference; }; /* * Structure of an icmp header. */ struct icmp { u_int8_t icmp_type; /* type of message, see below */ u_int8_t icmp_code; /* type sub code */ u_int16_t icmp_cksum; /* ones complement cksum of struct */ union { u_int8_t ih_pptr; /* ICMP_PARAMPROB */ struct in_addr ih_gwaddr; /* ICMP_REDIRECT */ struct ih_idseq { int16_t icd_id; int16_t icd_seq; } ih_idseq; int32_t ih_void; /* ICMP_UNREACH_NEEDFRAG -- Path MTU Discovery (RFC1191) */ struct ih_pmtu { int16_t ipm_void; int16_t ipm_nextmtu; } ih_pmtu; struct ih_rtradv { u_int8_t irt_num_addrs; u_int8_t irt_wpa; u_int16_t irt_lifetime; } ih_rtradv; } icmp_hun; #define icmp_pptr icmp_hun.ih_pptr #define icmp_gwaddr icmp_hun.ih_gwaddr #define icmp_id icmp_hun.ih_idseq.icd_id #define icmp_seq icmp_hun.ih_idseq.icd_seq #define icmp_void icmp_hun.ih_void #define icmp_pmvoid icmp_hun.ih_pmtu.ipm_void #define icmp_nextmtu icmp_hun.ih_pmtu.ipm_nextmtu #define icmp_num_addrs icmp_hun.ih_rtradv.irt_num_addrs #define icmp_wpa icmp_hun.ih_rtradv.irt_wpa #define icmp_lifetime icmp_hun.ih_rtradv.irt_lifetime union { struct id_ts { u_int32_t its_otime; u_int32_t its_rtime; u_int32_t its_ttime; } id_ts; struct id_ip { struct ip idi_ip; /* options and then 64 bits of data */ } id_ip; struct icmp_ra_addr id_radv; u_int32_t id_mask; int8_t id_data[1]; } icmp_dun; #define icmp_otime icmp_dun.id_ts.its_otime #define icmp_rtime icmp_dun.id_ts.its_rtime #define icmp_ttime icmp_dun.id_ts.its_ttime #define icmp_ip icmp_dun.id_ip.idi_ip #define icmp_radv icmp_dun.id_mask #define icmp_mask icmp_dun.id_mask #define icmp_data icmp_dun.id_data }; /* * Lower bounds on packet lengths for various types. * For the error advice packets must first insure that the * packet is large enought to contain the returned ip header. * Only then can we do the check to see if 64 bits of packet * data have been returned, since we need to check the returned * ip header length. */ #define ICMP_MINLEN 8 /* abs minimum */ #define ICMP_TSLEN (8 + 3 * sizeof (u_int32_t)) /* timestamp */ #define ICMP_MASKLEN 12 /* address mask */ #define ICMP_ADVLENMIN (8 + sizeof (struct ip) + 8) /* min */ #define ICMP_ADVLEN(p) (8 + ((p)->icmp_ip.ip_hl << 2) + 8) /* N.B.: must separately check that ip_hl >= 5 */ /* * Definition of type and code field values. */ #define ICMP_ECHOREPLY 0 /* echo reply */ #define ICMP_UNREACH 3 /* dest unreachable, codes: */ #define ICMP_UNREACH_NET 0 /* bad net */ #define ICMP_UNREACH_HOST 1 /* bad host */ #define ICMP_UNREACH_PROTOCOL 2 /* bad protocol */ #define ICMP_UNREACH_PORT 3 /* bad port */ #define ICMP_UNREACH_NEEDFRAG 4 /* IP_DF caused drop */ #define ICMP_UNREACH_SRCFAIL 5 /* src route failed */ #define ICMP_UNREACH_NET_UNKNOWN 6 /* unknown net */ #define ICMP_UNREACH_HOST_UNKNOWN 7 /* unknown host */ #define ICMP_UNREACH_ISOLATED 8 /* src host isolated */ #define ICMP_UNREACH_NET_PROHIB 9 /* prohibited access */ #define ICMP_UNREACH_HOST_PROHIB 10 /* ditto */ #define ICMP_UNREACH_TOSNET 11 /* bad tos for net */ #define ICMP_UNREACH_TOSHOST 12 /* bad tos for host */ #define ICMP_SOURCEQUENCH 4 /* packet lost, slow down */ #define ICMP_REDIRECT 5 /* shorter route, codes: */ #define ICMP_REDIRECT_NET 0 /* for network */ #define ICMP_REDIRECT_HOST 1 /* for host */ #define ICMP_REDIRECT_TOSNET 2 /* for tos and net */ #define ICMP_REDIRECT_TOSHOST 3 /* for tos and host */ #define ICMP_ECHO 8 /* echo service */ #define ICMP_ROUTERADVERT 9 /* router advertisement */ #define ICMP_ROUTERSOLICIT 10 /* router solicitation */ #define ICMP_TIMXCEED 11 /* time exceeded, code: */ #define ICMP_TIMXCEED_INTRANS 0 /* ttl==0 in transit */ #define ICMP_TIMXCEED_REASS 1 /* ttl==0 in reass */ #define ICMP_PARAMPROB 12 /* ip header bad */ #define ICMP_PARAMPROB_OPTABSENT 1 /* req. opt. absent */ #define ICMP_TSTAMP 13 /* timestamp request */ #define ICMP_TSTAMPREPLY 14 /* timestamp reply */ #define ICMP_IREQ 15 /* information request */ #define ICMP_IREQREPLY 16 /* information reply */ #define ICMP_MASKREQ 17 /* address mask request */ #define ICMP_MASKREPLY 18 /* address mask reply */ #define ICMP_MAXTYPE 18 #define ICMP_INFOTYPE(type) \ ((type) == ICMP_ECHOREPLY || (type) == ICMP_ECHO || \ (type) == ICMP_ROUTERADVERT || (type) == ICMP_ROUTERSOLICIT || \ (type) == ICMP_TSTAMP || (type) == ICMP_TSTAMPREPLY || \ (type) == ICMP_IREQ || (type) == ICMP_IREQREPLY || \ (type) == ICMP_MASKREQ || (type) == ICMP_MASKREPLY) #ifdef _KERNEL void icmp_error __P((struct mbuf *, int, int, n_long, struct ifnet *)); void icmp_input __P((struct mbuf *, ...)); void icmp_reflect __P((struct mbuf *)); void icmp_send __P((struct mbuf *, struct mbuf *)); int icmp_sysctl __P((int *, u_int, void *, size_t *, void *, size_t)); #endif dhcp-4.2.4/includes/netinet/udp.h000644 000765 000024 00000006171 11301372615 016610 0ustar00sarstaff000000 000000 /* $NetBSD: udp.h,v 1.6 1995/04/13 06:37:10 cgd Exp $ */ /* * Copyright (c) 1982, 1986, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)udp.h 8.1 (Berkeley) 6/10/93 */ /* * Portions Copyright (c) 2004,2009 by Internet Systems Consortium, Inc. ("ISC") * Portions Copyright (c) 2000-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ */ /* * Udp protocol header. * Per RFC 768, September, 1981. */ struct udphdr { u_int16_t uh_sport; /* source port */ u_int16_t uh_dport; /* destination port */ u_int16_t uh_ulen; /* udp length */ u_int16_t uh_sum; /* udp checksum */ }; dhcp-4.2.4/includes/isc-dhcp/dst.h000644 000765 000024 00000011460 07316222314 016634 0ustar00sarstaff000000 000000 #ifndef DST_H #define DST_H #ifndef HAS_DST_KEY typedef struct dst_key { char *dk_key_name; /* name of the key */ int dk_key_size; /* this is the size of the key in bits */ int dk_proto; /* what protocols this key can be used for */ int dk_alg; /* algorithm number from key record */ unsigned dk_flags; /* and the flags of the public key */ unsigned dk_id; /* identifier of the key */ } DST_KEY; #endif /* HAS_DST_KEY */ /* * DST Crypto API defintions */ void dst_init(void); int dst_check_algorithm(const int); int dst_sign_data(const int mode, /* specifies INIT/UPDATE/FINAL/ALL */ DST_KEY *in_key, /* the key to use */ void **context, /* pointer to state structure */ const u_char *data, /* data to be signed */ const unsigned len, /* length of input data */ u_char *signature, /* buffer to write signature to */ const unsigned sig_len); /* size of output buffer */ int dst_verify_data(const int mode, /* specifies INIT/UPDATE/FINAL/ALL */ DST_KEY *in_key, /* the key to use */ void **context, /* pointer to state structure */ const u_char *data, /* data to be verified */ const unsigned len, /* length of input data */ const u_char *signature,/* buffer containing signature */ const unsigned sig_len); /* length of signature */ DST_KEY *dst_read_key(const char *in_name, /* name of key */ const unsigned in_id, /* key tag identifier */ const int in_alg, /* key algorithm */ const int key_type); /* Private/PublicKey wanted*/ int dst_write_key(const DST_KEY *key, /* key to write out */ const int key_type); /* Public/Private */ DST_KEY *dst_dnskey_to_key(const char *in_name, /* KEY record name */ const u_char *key, /* KEY RDATA */ const unsigned len); /* size of input buffer*/ int dst_key_to_dnskey(const DST_KEY *key, /* key to translate */ u_char *out_storage, /* output buffer */ const unsigned out_len); /* size of out_storage*/ DST_KEY *dst_buffer_to_key(const char *key_name, /* name of the key */ const int alg, /* algorithm */ const unsigned flags, /* dns flags */ const int protocol, /* dns protocol */ const u_char *key_buf, /* key in dns wire fmt */ const unsigned key_len); /* size of key */ int dst_key_to_buffer(DST_KEY *key, u_char *out_buff, unsigned buf_len); DST_KEY *dst_generate_key(const char *name, /* name of new key */ const int bits, /* size of new key */ const int exp, /* alg dependent parameter*/ const unsigned flags, /* key DNS flags */ const int protocol, /* key DNS protocol */ const int alg); /* key algorithm to generate */ DST_KEY *dst_free_key(DST_KEY *f_key); int dst_compare_keys(const DST_KEY *key1, const DST_KEY *key2); int dst_sig_size(DST_KEY *key); int dst_random(const int mode, unsigned wanted, u_char *outran); /* support for dns key tags/ids */ u_int16_t dst_s_dns_key_id(const u_char *dns_key_rdata, const unsigned rdata_len); u_int16_t dst_s_id_calc(const u_char *key_data, const unsigned key_len); /* Used by callers as well as by the library. */ #define RAW_KEY_SIZE 8192 /* large enough to store any key */ /* DST_API control flags */ /* These are used used in functions dst_sign_data and dst_verify_data */ #define SIG_MODE_INIT 1 /* initalize digest */ #define SIG_MODE_UPDATE 2 /* add data to digest */ #define SIG_MODE_FINAL 4 /* generate/verify signature */ #define SIG_MODE_ALL (SIG_MODE_INIT|SIG_MODE_UPDATE|SIG_MODE_FINAL) /* Flags for dst_read_private_key() */ #define DST_FORCE_READ 0x1000000 #define DST_CAN_SIGN 0x010F #define DST_NO_AUTHEN 0x8000 #define DST_EXTEND_FLAG 0x1000 #define DST_STANDARD 0 #define DST_PRIVATE 0x2000000 #define DST_PUBLIC 0x4000000 #define DST_RAND_SEMI 1 #define DST_RAND_STD 2 #define DST_RAND_KEY 3 #define DST_RAND_DSS 4 /* DST algorithm codes */ #define KEY_RSA 1 #define KEY_DH 2 #define KEY_DSA 3 #define KEY_PRIVATE 254 #define KEY_EXPAND 255 #define KEY_HMAC_MD5 157 #define KEY_HMAC_SHA1 158 #define UNKNOWN_KEYALG 0 #define DST_MAX_ALGS KEY_HMAC_SHA1 /* DST constants to locations in KEY record changes in new KEY record */ #define DST_FLAGS_SIZE 2 #define DST_KEY_PROT 2 #define DST_KEY_ALG 3 #define DST_EXT_FLAG 4 #define DST_KEY_START 4 #ifndef SIGN_F_NOKEY #define SIGN_F_NOKEY 0xC000 #endif /* error codes from dst routines */ #define SIGN_INIT_FAILURE (-23) #define SIGN_UPDATE_FAILURE (-24) #define SIGN_FINAL_FAILURE (-25) #define VERIFY_INIT_FAILURE (-26) #define VERIFY_UPDATE_FAILURE (-27) #define VERIFY_FINAL_FAILURE (-28) #define MISSING_KEY_OR_SIGNATURE (-30) #define UNSUPPORTED_KEYALG (-31) #endif /* DST_H */ dhcp-4.2.4/includes/arpa/nameser.h000644 000765 000024 00000041773 11301372615 016736 0ustar00sarstaff000000 000000 /* * Copyright (c) 1983, 1989, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * Copyright (c) 2004,2009 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1996-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ */ /* * $Id: nameser.h,v 1.6.24.1 2009-11-20 01:49:01 sar Exp $ */ #ifndef _ARPA_NAMESER_H_ #define _ARPA_NAMESER_H_ /* * Revision information. This is the release date in YYYYMMDD format. * It can change every day so the right thing to do with it is use it * in preprocessor commands such as "#if (__NAMESER > 19931104)". Do not * compare for equality; rather, use it to determine whether your libbind.a * contains a new enough lib/nameser/ to support the feature you need. */ #define __NAMESER 19991006 /* New interface version stamp. */ /* * Define constants based on RFC 883, RFC 1034, RFC 1035 */ #define NS_PACKETSZ 512 /* maximum packet size */ #define NS_MAXDNAME 1025 /* maximum domain name */ #define NS_MAXCDNAME 255 /* maximum compressed domain name */ #define NS_MAXLABEL 63 /* maximum length of domain label */ #define NS_HFIXEDSZ 12 /* #/bytes of fixed data in header */ #define NS_QFIXEDSZ 4 /* #/bytes of fixed data in query */ #define NS_RRFIXEDSZ 10 /* #/bytes of fixed data in r record */ #define NS_INT32SZ 4 /* #/bytes of data in a u_int32_t */ #define NS_INT16SZ 2 /* #/bytes of data in a u_int16_t */ #define NS_INT8SZ 1 /* #/bytes of data in a u_int8_t */ #define NS_INADDRSZ 4 /* IPv4 T_A */ #define NS_IN6ADDRSZ 16 /* IPv6 T_AAAA */ #define NS_CMPRSFLGS 0xc0 /* Flag bits indicating name compression. */ #define NS_DEFAULTPORT 53 /* For both TCP and UDP. */ /* * These can be expanded with synonyms, just keep ns_parse.c:ns_parserecord() * in synch with it. */ typedef enum __ns_sect { ns_s_qd = 0, /* Query: Question. */ ns_s_zn = 0, /* Update: Zone. */ ns_s_an = 1, /* Query: Answer. */ ns_s_pr = 1, /* Update: Prerequisites. */ ns_s_ns = 2, /* Query: Name servers. */ ns_s_ud = 2, /* Update: Update. */ ns_s_ar = 3, /* Query|Update: Additional records. */ ns_s_max = 4 } ns_sect; /* * This is a message handle. It is caller allocated and has no dynamic data. * This structure is intended to be opaque to all but ns_parse.c, thus the * leading _'s on the member names. Use the accessor functions, not the _'s. */ typedef struct __ns_msg { const u_int8_t *_msg, *_eom; u_int16_t _id, _flags, _counts[ns_s_max]; const u_int8_t *_sections[ns_s_max]; ns_sect _sect; int _rrnum; const u_int8_t *_ptr; } ns_msg; /* Private data structure - do not use from outside library. */ struct _ns_flagdata { int mask, shift; }; extern struct _ns_flagdata _ns_flagdata[]; /* Accessor macros - this is part of the public interface. */ #define ns_msg_getflag(handle, flag) ( \ ((handle)._flags & _ns_flagdata[flag].mask) \ >> _ns_flagdata[flag].shift \ ) #define ns_msg_id(handle) ((handle)._id + 0) #define ns_msg_base(handle) ((handle)._msg + 0) #define ns_msg_end(handle) ((handle)._eom + 0) #define ns_msg_size(handle) ((handle)._eom - (handle)._msg) #define ns_msg_count(handle, section) ((handle)._counts[section] + 0) /* * This is a parsed record. It is caller allocated and has no dynamic data. */ typedef struct __ns_rr { char name[NS_MAXDNAME]; u_int16_t type; u_int16_t rr_class; u_int32_t ttl; u_int16_t rdlength; const u_int8_t *rdata; } ns_rr; /* Accessor macros - this is part of the public interface. */ #define ns_rr_name(rr) (((rr).name[0] != '\0') ? (rr).name : ".") #define ns_rr_type(rr) ((ns_type)((rr).type + 0)) #define ns_rr_class(rr) ((ns_class)((rr).rr_class + 0)) #define ns_rr_ttl(rr) ((rr).ttl + 0) #define ns_rr_rdlen(rr) ((rr).rdlength + 0) #define ns_rr_rdata(rr) ((rr).rdata + 0) /* * These don't have to be in the same order as in the packet flags word, * and they can even overlap in some cases, but they will need to be kept * in synch with ns_parse.c:ns_flagdata[]. */ typedef enum __ns_flag { ns_f_qr, /* Question/Response. */ ns_f_opcode, /* Operation code. */ ns_f_aa, /* Authoritative Answer. */ ns_f_tc, /* Truncation occurred. */ ns_f_rd, /* Recursion Desired. */ ns_f_ra, /* Recursion Available. */ ns_f_z, /* MBZ. */ ns_f_ad, /* Authentic Data (DNSSEC). */ ns_f_cd, /* Checking Disabled (DNSSEC). */ ns_f_rcode, /* Response code. */ ns_f_max } ns_flag; /* * Currently defined opcodes. */ typedef enum __ns_opcode { ns_o_query = 0, /* Standard query. */ ns_o_iquery = 1, /* Inverse query (deprecated/unsupported). */ ns_o_status = 2, /* Name server status query (unsupported). */ /* Opcode 3 is undefined/reserved. */ ns_o_notify = 4, /* Zone change notification. */ ns_o_update = 5, /* Zone update message. */ ns_o_max = 6 } ns_opcode; /* * Currently defined response codes. */ typedef enum __ns_rcode { ns_r_noerror = 0, /* No error occurred. */ ns_r_formerr = 1, /* Format error. */ ns_r_servfail = 2, /* Server failure. */ ns_r_nxdomain = 3, /* Name error. */ ns_r_notimpl = 4, /* Unimplemented. */ ns_r_refused = 5, /* Operation refused. */ /* these are for BIND_UPDATE */ ns_r_yxdomain = 6, /* Name exists */ ns_r_yxrrset = 7, /* RRset exists */ ns_r_nxrrset = 8, /* RRset does not exist */ ns_r_notauth = 9, /* Not authoritative for zone */ ns_r_notzone = 10, /* Zone of record different from zone section */ ns_r_max = 11, /* The following are TSIG extended errors */ ns_r_badsig = 16, ns_r_badkey = 17, ns_r_badtime = 18 } ns_rcode; /* BIND_UPDATE */ typedef enum __ns_update_operation { ns_uop_delete = 0, ns_uop_add = 1, ns_uop_max = 2 } ns_update_operation; /* * This structure is used for TSIG authenticated messages */ struct ns_tsig_key { char name[NS_MAXDNAME], alg[NS_MAXDNAME]; unsigned char *data; unsigned len; }; typedef struct ns_tsig_key ns_tsig_key; /* * This structure is used for TSIG authenticated TCP messages */ struct ns_tcp_tsig_state { int counter; struct dst_key *key; void *ctx; unsigned char sig[NS_PACKETSZ]; unsigned siglen; }; typedef struct ns_tcp_tsig_state ns_tcp_tsig_state; #define NS_TSIG_FUDGE 300 #define NS_TSIG_TCP_COUNT 100 #define NS_TSIG_ALG_HMAC_MD5 "HMAC-MD5.SIG-ALG.REG.INT" #define NS_TSIG_ERROR_NO_TSIG -10 #define NS_TSIG_ERROR_NO_SPACE -11 #define NS_TSIG_ERROR_FORMERR -12 /* * Currently defined type values for resources and queries. */ typedef enum __ns_type { ns_t_invalid = 0, /* Cookie. */ ns_t_a = 1, /* Host address. */ ns_t_ns = 2, /* Authoritative server. */ ns_t_md = 3, /* Mail destination. */ ns_t_mf = 4, /* Mail forwarder. */ ns_t_cname = 5, /* Canonical name. */ ns_t_soa = 6, /* Start of authority zone. */ ns_t_mb = 7, /* Mailbox domain name. */ ns_t_mg = 8, /* Mail group member. */ ns_t_mr = 9, /* Mail rename name. */ ns_t_null = 10, /* Null resource record. */ ns_t_wks = 11, /* Well known service. */ ns_t_ptr = 12, /* Domain name pointer. */ ns_t_hinfo = 13, /* Host information. */ ns_t_minfo = 14, /* Mailbox information. */ ns_t_mx = 15, /* Mail routing information. */ ns_t_txt = 16, /* Text strings. */ ns_t_rp = 17, /* Responsible person. */ ns_t_afsdb = 18, /* AFS cell database. */ ns_t_x25 = 19, /* X_25 calling address. */ ns_t_isdn = 20, /* ISDN calling address. */ ns_t_rt = 21, /* Router. */ ns_t_nsap = 22, /* NSAP address. */ ns_t_nsap_ptr = 23, /* Reverse NSAP lookup (deprecated). */ ns_t_sig = 24, /* Security signature. */ ns_t_key = 25, /* Security key. */ ns_t_px = 26, /* X.400 mail mapping. */ ns_t_gpos = 27, /* Geographical position (withdrawn). */ ns_t_aaaa = 28, /* Ip6 Address. */ ns_t_loc = 29, /* Location Information. */ ns_t_nxt = 30, /* Next domain (security). */ ns_t_eid = 31, /* Endpoint identifier. */ ns_t_nimloc = 32, /* Nimrod Locator. */ ns_t_srv = 33, /* Server Selection. */ ns_t_atma = 34, /* ATM Address */ ns_t_naptr = 35, /* Naming Authority PoinTeR */ ns_t_kx = 36, /* Key Exchange */ ns_t_cert = 37, /* Certification record */ ns_t_a6 = 38, /* IPv6 address (deprecates AAAA) */ ns_t_dname = 39, /* Non-terminal DNAME (for IPv6) */ ns_t_sink = 40, /* Kitchen sink (experimentatl) */ ns_t_opt = 41, /* EDNS0 option (meta-RR) */ ns_t_tsig = 250, /* Transaction signature. */ ns_t_ixfr = 251, /* Incremental zone transfer. */ ns_t_axfr = 252, /* Transfer zone of authority. */ ns_t_mailb = 253, /* Transfer mailbox records. */ ns_t_maila = 254, /* Transfer mail agent records. */ ns_t_any = 255, /* Wildcard match. */ ns_t_zxfr = 256, /* BIND-specific, nonstandard. */ ns_t_max = 65536 } ns_type; /* Exclusively a QTYPE? (not also an RTYPE) */ #define ns_t_qt_p(t) (ns_t_xfr_p(t) || (t) == ns_t_any || \ (t) == ns_t_mailb || (t) == ns_t_maila) /* Some kind of meta-RR? (not a QTYPE, but also not an RTYPE) */ #define ns_t_mrr_p(t) ((t) == ns_t_tsig || (t) == ns_t_opt) /* Exclusively an RTYPE? (not also a QTYPE or a meta-RR) */ #define ns_t_rr_p(t) (!ns_t_qt_p(t) && !ns_t_mrr_p(t)) #define ns_t_udp_p(t) ((t) != ns_t_axfr && (t) != ns_t_zxfr) #define ns_t_xfr_p(t) ((t) == ns_t_axfr || (t) == ns_t_ixfr || \ (t) == ns_t_zxfr) /* * Values for class field */ typedef enum __ns_class { ns_c_invalid = 0, /* Cookie. */ ns_c_in = 1, /* Internet. */ ns_c_2 = 2, /* unallocated/unsupported. */ ns_c_chaos = 3, /* MIT Chaos-net. */ ns_c_hs = 4, /* MIT Hesiod. */ /* Query class values which do not appear in resource records */ ns_c_none = 254, /* for prereq. sections in update requests */ ns_c_any = 255, /* Wildcard match. */ ns_c_max = 65536 } ns_class; /* DNSSEC constants. */ typedef enum __ns_key_types { ns_kt_rsa = 1, /* key type RSA/MD5 */ ns_kt_dh = 2, /* Diffie Hellman */ ns_kt_dsa = 3, /* Digital Signature Standard (MANDATORY) */ ns_kt_private = 254 /* Private key type starts with OID */ } ns_key_types; typedef enum __ns_cert_types { cert_t_pkix = 1, /* PKIX (X.509v3) */ cert_t_spki = 2, /* SPKI */ cert_t_pgp = 3, /* PGP */ cert_t_url = 253, /* URL private type */ cert_t_oid = 254 /* OID private type */ } ns_cert_types; /* Flags field of the KEY RR rdata. */ #define NS_KEY_TYPEMASK 0xC000 /* Mask for "type" bits */ #define NS_KEY_TYPE_AUTH_CONF 0x0000 /* Key usable for both */ #define NS_KEY_TYPE_CONF_ONLY 0x8000 /* Key usable for confidentiality */ #define NS_KEY_TYPE_AUTH_ONLY 0x4000 /* Key usable for authentication */ #define NS_KEY_TYPE_NO_KEY 0xC000 /* No key usable for either; no key */ /* The type bits can also be interpreted independently, as single bits: */ #define NS_KEY_NO_AUTH 0x8000 /* Key unusable for authentication */ #define NS_KEY_NO_CONF 0x4000 /* Key unusable for confidentiality */ #define NS_KEY_RESERVED2 0x2000 /* Security is *mandatory* if bit=0 */ #define NS_KEY_EXTENDED_FLAGS 0x1000 /* reserved - must be zero */ #define NS_KEY_RESERVED4 0x0800 /* reserved - must be zero */ #define NS_KEY_RESERVED5 0x0400 /* reserved - must be zero */ #define NS_KEY_NAME_TYPE 0x0300 /* these bits determine the type */ #define NS_KEY_NAME_USER 0x0000 /* key is assoc. with user */ #define NS_KEY_NAME_ENTITY 0x0200 /* key is assoc. with entity eg host */ #define NS_KEY_NAME_ZONE 0x0100 /* key is zone key */ #define NS_KEY_NAME_RESERVED 0x0300 /* reserved meaning */ #define NS_KEY_RESERVED8 0x0080 /* reserved - must be zero */ #define NS_KEY_RESERVED9 0x0040 /* reserved - must be zero */ #define NS_KEY_RESERVED10 0x0020 /* reserved - must be zero */ #define NS_KEY_RESERVED11 0x0010 /* reserved - must be zero */ #define NS_KEY_SIGNATORYMASK 0x000F /* key can sign RR's of same name */ #define NS_KEY_RESERVED_BITMASK ( NS_KEY_RESERVED2 | \ NS_KEY_RESERVED4 | \ NS_KEY_RESERVED5 | \ NS_KEY_RESERVED8 | \ NS_KEY_RESERVED9 | \ NS_KEY_RESERVED10 | \ NS_KEY_RESERVED11 ) #define NS_KEY_RESERVED_BITMASK2 0xFFFF /* no bits defined here */ /* The Algorithm field of the KEY and SIG RR's is an integer, {1..254} */ #define NS_ALG_MD5RSA 1 /* MD5 with RSA */ #define NS_ALG_DH 2 /* Diffie Hellman KEY */ #define NS_ALG_DSA 3 /* DSA KEY */ #define NS_ALG_DSS NS_ALG_DSA #define NS_ALG_EXPIRE_ONLY 253 /* No alg, no security */ #define NS_ALG_PRIVATE_OID 254 /* Key begins with OID giving alg */ /* Protocol values */ /* value 0 is reserved */ #define NS_KEY_PROT_TLS 1 #define NS_KEY_PROT_EMAIL 2 #define NS_KEY_PROT_DNSSEC 3 #define NS_KEY_PROT_IPSEC 4 #define NS_KEY_PROT_ANY 255 /* Signatures */ #define NS_MD5RSA_MIN_BITS 512 /* Size of a mod or exp in bits */ #define NS_MD5RSA_MAX_BITS 2552 /* Total of binary mod and exp */ #define NS_MD5RSA_MAX_BYTES ((NS_MD5RSA_MAX_BITS+7/8)*2+3) /* Max length of text sig block */ #define NS_MD5RSA_MAX_BASE64 (((NS_MD5RSA_MAX_BYTES+2)/3)*4) #define NS_MD5RSA_MIN_SIZE ((NS_MD5RSA_MIN_BITS+7)/8) #define NS_MD5RSA_MAX_SIZE ((NS_MD5RSA_MAX_BITS+7)/8) #define NS_DSA_SIG_SIZE 41 #define NS_DSA_MIN_SIZE 213 #define NS_DSA_MAX_BYTES 405 /* Offsets into SIG record rdata to find various values */ #define NS_SIG_TYPE 0 /* Type flags */ #define NS_SIG_ALG 2 /* Algorithm */ #define NS_SIG_LABELS 3 /* How many labels in name */ #define NS_SIG_OTTL 4 /* Original TTL */ #define NS_SIG_EXPIR 8 /* Expiration time */ #define NS_SIG_SIGNED 12 /* Signature time */ #define NS_SIG_FOOT 16 /* Key footprint */ #define NS_SIG_SIGNER 18 /* Domain name of who signed it */ /* How RR types are represented as bit-flags in NXT records */ #define NS_NXT_BITS 8 #define NS_NXT_BIT_SET( n,p) (p[(n)/NS_NXT_BITS] |= (0x80>>((n)%NS_NXT_BITS))) #define NS_NXT_BIT_CLEAR(n,p) (p[(n)/NS_NXT_BITS] &= ~(0x80>>((n)%NS_NXT_BITS))) #define NS_NXT_BIT_ISSET(n,p) (p[(n)/NS_NXT_BITS] & (0x80>>((n)%NS_NXT_BITS))) #define NS_NXT_MAX 127 /* * Inline versions of get/put short/long. Pointer is advanced. */ #define NS_GET16(s, cp) do { \ register u_int8_t *t_cp = (u_int8_t *)(cp); \ (s) = ((u_int16_t)t_cp[0] << 8) \ | ((u_int16_t)t_cp[1]) \ ; \ (cp) += NS_INT16SZ; \ } while (0) #define NS_GET32(l, cp) do { \ register u_int8_t *t_cp = (u_int8_t *)(cp); \ (l) = ((u_int32_t)t_cp[0] << 24) \ | ((u_int32_t)t_cp[1] << 16) \ | ((u_int32_t)t_cp[2] << 8) \ | ((u_int32_t)t_cp[3]) \ ; \ (cp) += NS_INT32SZ; \ } while (0) #define NS_PUT16(s, cp) do { \ register u_int16_t t_s = (u_int16_t)(s); \ register u_int8_t *t_cp = (u_int8_t *)(cp); \ *t_cp++ = t_s >> 8; \ *t_cp = t_s; \ (cp) += NS_INT16SZ; \ } while (0) #define NS_PUT32(l, cp) do { \ register u_int32_t t_l = (u_int32_t)(l); \ register u_int8_t *t_cp = (u_int8_t *)(cp); \ *t_cp++ = t_l >> 24; \ *t_cp++ = t_l >> 16; \ *t_cp++ = t_l >> 8; \ *t_cp = t_l; \ (cp) += NS_INT32SZ; \ } while (0) #include #endif /* !_ARPA_NAMESER_H_ */ dhcp-4.2.4/includes/arpa/nameser_compat.h000644 000765 000024 00000014106 07044152210 020263 0ustar00sarstaff000000 000000 /* Copyright (c) 1983, 1989 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * from nameser.h 8.1 (Berkeley) 6/2/93 * $Id: nameser_compat.h,v 1.2 2000-01-27 23:28:08 mellon Exp $ */ #ifndef _ARPA_NAMESER_COMPAT_ #define _ARPA_NAMESER_COMPAT_ /* * Structure for query header. The order of the fields is machine- and * compiler-dependent, depending on the byte/bit order and the layout * of bit fields. We use bit fields only in int variables, as this * is all ANSI requires. This requires a somewhat confusing rearrangement. */ typedef struct { unsigned id :16; /* query identification number */ #if BYTE_ORDER == BIG_ENDIAN /* fields in third byte */ unsigned qr: 1; /* response flag */ unsigned opcode: 4; /* purpose of message */ unsigned aa: 1; /* authoritive answer */ unsigned tc: 1; /* truncated message */ unsigned rd: 1; /* recursion desired */ /* fields in fourth byte */ unsigned ra: 1; /* recursion available */ unsigned unused :1; /* unused bits (MBZ as of 4.9.3a3) */ unsigned ad: 1; /* authentic data from named */ unsigned cd: 1; /* checking disabled by resolver */ unsigned rcode :4; /* response code */ #endif #if BYTE_ORDER == LITTLE_ENDIAN || BYTE_ORDER == PDP_ENDIAN /* fields in third byte */ unsigned rd :1; /* recursion desired */ unsigned tc :1; /* truncated message */ unsigned aa :1; /* authoritive answer */ unsigned opcode :4; /* purpose of message */ unsigned qr :1; /* response flag */ /* fields in fourth byte */ unsigned rcode :4; /* response code */ unsigned cd: 1; /* checking disabled by resolver */ unsigned ad: 1; /* authentic data from named */ unsigned unused :1; /* unused bits (MBZ as of 4.9.3a3) */ unsigned ra :1; /* recursion available */ #endif /* remaining bytes */ unsigned qdcount :16; /* number of question entries */ unsigned ancount :16; /* number of answer entries */ unsigned nscount :16; /* number of authority entries */ unsigned arcount :16; /* number of resource entries */ } HEADER; #define PACKETSZ NS_PACKETSZ #define MAXDNAME NS_MAXDNAME #define MAXCDNAME NS_MAXCDNAME #define MAXLABEL NS_MAXLABEL #define HFIXEDSZ NS_HFIXEDSZ #define QFIXEDSZ NS_QFIXEDSZ #define RRFIXEDSZ NS_RRFIXEDSZ #define INT32SZ NS_INT32SZ #define INT16SZ NS_INT16SZ #define INADDRSZ NS_INADDRSZ #define IN6ADDRSZ NS_IN6ADDRSZ #define INDIR_MASK NS_CMPRSFLGS #define NAMESERVER_PORT NS_DEFAULTPORT #define S_ZONE ns_s_zn #define S_PREREQ ns_s_pr #define S_UPDATE ns_s_ud #define S_ADDT ns_s_ar #define QUERY ns_o_query #define IQUERY ns_o_iquery #define STATUS ns_o_status #define NS_NOTIFY_OP ns_o_notify #define NS_UPDATE_OP ns_o_update #define NOERROR ns_r_noerror #define FORMERR ns_r_formerr #define SERVFAIL ns_r_servfail #define NXDOMAIN ns_r_nxdomain #define NOTIMP ns_r_notimpl #define REFUSED ns_r_refused #define YXDOMAIN ns_r_yxdomain #define YXRRSET ns_r_yxrrset #define NXRRSET ns_r_nxrrset #define NOTAUTH ns_r_notauth #define NOTZONE ns_r_notzone /*#define BADSIG ns_r_badsig*/ /*#define BADKEY ns_r_badkey*/ /*#define BADTIME ns_r_badtime*/ #define DELETE ns_uop_delete #define ADD ns_uop_add #define T_A ns_t_a #define T_NS ns_t_ns #define T_MD ns_t_md #define T_MF ns_t_mf #define T_CNAME ns_t_cname #define T_SOA ns_t_soa #define T_MB ns_t_mb #define T_MG ns_t_mg #define T_MR ns_t_mr #define T_NULL ns_t_null #define T_WKS ns_t_wks #define T_PTR ns_t_ptr #define T_HINFO ns_t_hinfo #define T_MINFO ns_t_minfo #define T_MX ns_t_mx #define T_TXT ns_t_txt #define T_RP ns_t_rp #define T_AFSDB ns_t_afsdb #define T_X25 ns_t_x25 #define T_ISDN ns_t_isdn #define T_RT ns_t_rt #define T_NSAP ns_t_nsap #define T_NSAP_PTR ns_t_nsap_ptr #define T_SIG ns_t_sig #define T_KEY ns_t_key #define T_PX ns_t_px #define T_GPOS ns_t_gpos #define T_AAAA ns_t_aaaa #define T_LOC ns_t_loc #define T_NXT ns_t_nxt #define T_EID ns_t_eid #define T_NIMLOC ns_t_nimloc #define T_SRV ns_t_srv #define T_ATMA ns_t_atma #define T_NAPTR ns_t_naptr #define T_TSIG ns_t_tsig #define T_IXFR ns_t_ixfr #define T_AXFR ns_t_axfr #define T_MAILB ns_t_mailb #define T_MAILA ns_t_maila #define T_ANY ns_t_any #define C_IN ns_c_in #define C_CHAOS ns_c_chaos #define C_HS ns_c_hs /* BIND_UPDATE */ #define C_NONE ns_c_none #define C_ANY ns_c_any #define GETSHORT NS_GET16 #define GETLONG NS_GET32 #define PUTSHORT NS_PUT16 #define PUTLONG NS_PUT32 #endif /* _ARPA_NAMESER_COMPAT_ */ dhcp-4.2.4/dst/base64.c000644 000765 000024 00000024702 11301372615 014415 0ustar00sarstaff000000 000000 /* * Copyright (c) 2004,2009 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1996-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ */ /* * Portions Copyright (c) 1995 by International Business Machines, Inc. * * International Business Machines, Inc. (hereinafter called IBM) grants * permission under its copyrights to use, copy, modify, and distribute this * Software with or without fee, provided that the above copyright notice and * all paragraphs of this notice appear in all copies, and that the name of IBM * not be used in connection with the marketing of any product incorporating * the Software or modifications thereof, without specific, written prior * permission. * * To the extent it has a right to do so, IBM grants an immunity from suit * under its patents, if any, for the use, sale or manufacture of products to * the extent that such products are used for performing Domain Name System * dynamic updates in TCP/IP networks by means of the Software. No immunity is * granted for any product per se or for any other function of any product. * * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES, * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES. */ #if !defined(LINT) && !defined(CODECENTER) static const char rcsid[] = "$Id: base64.c,v 1.5.6.1 2009-11-20 01:49:01 sar Exp $"; #endif /* not lint */ #include #include #include #include #include #include #include #include #include #include #include "cdefs.h" #include "osdep.h" #include "arpa/nameser.h" #define Assert(Cond) if (!(Cond)) abort() static const char Base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; static const char Pad64 = '='; /* (From RFC1521 and draft-ietf-dnssec-secext-03.txt) The following encoding technique is taken from RFC 1521 by Borenstein and Freed. It is reproduced here in a slightly edited form for convenience. A 65-character subset of US-ASCII is used, enabling 6 bits to be represented per printable character. (The extra 65th character, "=", is used to signify a special processing function.) The encoding process represents 24-bit groups of input bits as output strings of 4 encoded characters. Proceeding from left to right, a 24-bit input group is formed by concatenating 3 8-bit input groups. These 24 bits are then treated as 4 concatenated 6-bit groups, each of which is translated into a single digit in the base64 alphabet. Each 6-bit group is used as an index into an array of 64 printable characters. The character referenced by the index is placed in the output string. Table 1: The Base64 Alphabet Value Encoding Value Encoding Value Encoding Value Encoding 0 A 17 R 34 i 51 z 1 B 18 S 35 j 52 0 2 C 19 T 36 k 53 1 3 D 20 U 37 l 54 2 4 E 21 V 38 m 55 3 5 F 22 W 39 n 56 4 6 G 23 X 40 o 57 5 7 H 24 Y 41 p 58 6 8 I 25 Z 42 q 59 7 9 J 26 a 43 r 60 8 10 K 27 b 44 s 61 9 11 L 28 c 45 t 62 + 12 M 29 d 46 u 63 / 13 N 30 e 47 v 14 O 31 f 48 w (pad) = 15 P 32 g 49 x 16 Q 33 h 50 y Special processing is performed if fewer than 24 bits are available at the end of the data being encoded. A full encoding quantum is always completed at the end of a quantity. When fewer than 24 input bits are available in an input group, zero bits are added (on the right) to form an integral number of 6-bit groups. Padding at the end of the data is performed using the '=' character. Since all base64 input is an integral number of octets, only the ------------------------------------------------- following cases can arise: (1) the final quantum of encoding input is an integral multiple of 24 bits; here, the final unit of encoded output will be an integral multiple of 4 characters with no "=" padding, (2) the final quantum of encoding input is exactly 8 bits; here, the final unit of encoded output will be two characters followed by two "=" padding characters, or (3) the final quantum of encoding input is exactly 16 bits; here, the final unit of encoded output will be three characters followed by one "=" padding character. */ int b64_ntop(u_char const *src, size_t srclength, char *target, size_t targsize) { size_t datalength = 0; u_char input[3]; u_char output[4]; size_t i; while (2 < srclength) { input[0] = *src++; input[1] = *src++; input[2] = *src++; srclength -= 3; output[0] = input[0] >> 2; output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4); output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6); output[3] = input[2] & 0x3f; Assert(output[0] < 64); Assert(output[1] < 64); Assert(output[2] < 64); Assert(output[3] < 64); if (datalength + 4 > targsize) return (-1); target[datalength++] = Base64[output[0]]; target[datalength++] = Base64[output[1]]; target[datalength++] = Base64[output[2]]; target[datalength++] = Base64[output[3]]; } /* Now we worry about padding. */ if (0 != srclength) { /* Get what's left. */ input[0] = input[1] = input[2] = '\0'; for (i = 0; i < srclength; i++) input[i] = *src++; output[0] = input[0] >> 2; output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4); output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6); Assert(output[0] < 64); Assert(output[1] < 64); Assert(output[2] < 64); if (datalength + 4 > targsize) return (-1); target[datalength++] = Base64[output[0]]; target[datalength++] = Base64[output[1]]; if (srclength == 1) target[datalength++] = Pad64; else target[datalength++] = Base64[output[2]]; target[datalength++] = Pad64; } if (datalength >= targsize) return (-1); target[datalength] = '\0'; /* Returned value doesn't count \0. */ return (datalength); } /* skips all whitespace anywhere. converts characters, four at a time, starting at (or after) src from base - 64 numbers into three 8 bit bytes in the target area. it returns the number of data bytes stored at the target, or -1 on error. */ int b64_pton(src, target, targsize) char const *src; u_char *target; size_t targsize; { int tarindex, state, ch; char *pos; state = 0; tarindex = 0; while ((ch = *src++) != '\0') { if (isspace(ch)) /* Skip whitespace anywhere. */ continue; if (ch == Pad64) break; pos = strchr(Base64, ch); if (pos == 0) /* A non-base64 character. */ return (-1); switch (state) { case 0: if (target) { if ((size_t)tarindex >= targsize) return (-1); target[tarindex] = (pos - Base64) << 2; } state = 1; break; case 1: if (target) { if ((size_t)tarindex + 1 >= targsize) return (-1); target[tarindex] |= (pos - Base64) >> 4; target[tarindex+1] = ((pos - Base64) & 0x0f) << 4 ; } tarindex++; state = 2; break; case 2: if (target) { if ((size_t)tarindex + 1 >= targsize) return (-1); target[tarindex] |= (pos - Base64) >> 2; target[tarindex+1] = ((pos - Base64) & 0x03) << 6; } tarindex++; state = 3; break; case 3: if (target) { if ((size_t)tarindex >= targsize) return (-1); target[tarindex] |= (pos - Base64); } tarindex++; state = 0; break; default: abort(); } } /* * We are done decoding Base-64 chars. Let's see if we ended * on a byte boundary, and/or with erroneous trailing characters. */ if (ch == Pad64) { /* We got a pad char. */ ch = *src++; /* Skip it, get next. */ switch (state) { case 0: /* Invalid = in first position */ case 1: /* Invalid = in second position */ return (-1); case 2: /* Valid, means one byte of info */ /* Skip any number of spaces. */ for ((void)NULL; ch != '\0'; ch = *src++) if (!isspace(ch)) break; /* Make sure there is another trailing = sign. */ if (ch != Pad64) return (-1); ch = *src++; /* Skip the = */ /* Fall through to "single trailing =" case. */ /* FALLTHROUGH */ case 3: /* Valid, means two bytes of info */ /* * We know this char is an =. Is there anything but * whitespace after it? */ for ((void)NULL; ch != '\0'; ch = *src++) if (!isspace(ch)) return (-1); /* * Now make sure for cases 2 and 3 that the "extra" * bits that slopped past the last full byte were * zeros. If we don't check them, they become a * subliminal channel. */ if (target && target[tarindex] != 0) return (-1); } } else { /* * We ended by seeing the end of the string. Make sure we * have no partial bytes lying around. */ if (state != 0) return (-1); } return (tarindex); } dhcp-4.2.4/dst/dst_api.c000644 000765 000024 00000074576 11741323273 014776 0ustar00sarstaff000000 000000 #ifndef LINT static const char rcsid[] = "$Header: /proj/cvs/prod/DHCP/dst/dst_api.c,v 1.9.6.1 2012-04-11 15:43:55 sar Exp $"; #endif /* * Portions Copyright (c) 1995-1998 by Trusted Information Systems, Inc. * Portions Copyright (c) 2007,2009 by Internet Systems Consortium, Inc. ("ISC") * Portions Copyright (c) 2012 by Internet Systems Consortium, Inc. ("ISC") * * Permission to use, copy modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND TRUSTED INFORMATION SYSTEMS * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL * TRUSTED INFORMATION SYSTEMS BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION * WITH THE USE OR PERFORMANCE OF THE SOFTWARE. */ /* * This file contains the interface between the DST API and the crypto API. * This is the only file that needs to be changed if the crypto system is * changed. Exported functions are: * void dst_init() Initialize the toolkit * int dst_check_algorithm() Function to determines if alg is supported. * int dst_compare_keys() Function to compare two keys for equality. * int dst_sign_data() Incremental signing routine. * int dst_verify_data() Incremental verify routine. * int dst_generate_key() Function to generate new KEY * DST_KEY *dst_read_key() Function to retrieve private/public KEY. * void dst_write_key() Function to write out a key. * DST_KEY *dst_dnskey_to_key() Function to convert DNS KEY RR to a DST * KEY structure. * int dst_key_to_dnskey() Function to return a public key in DNS * format binary * DST_KEY *dst_buffer_to_key() Convert a data in buffer to KEY * int *dst_key_to_buffer() Writes out DST_KEY key material in buffer * void dst_free_key() Releases all memory referenced by key structure */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "cdefs.h" #include "osdep.h" #include "arpa/nameser.h" #include "dst_internal.h" /* static variables */ static int done_init = 0; dst_func *dst_t_func[DST_MAX_ALGS]; const char *key_file_fmt_str = "Private-key-format: v%s\nAlgorithm: %d (%s)\n"; const char *dst_path = ""; /* internal I/O functions */ static DST_KEY *dst_s_read_public_key(const char *in_name, const unsigned in_id, int in_alg); static int dst_s_read_private_key_file(char *name, DST_KEY *pk_key, unsigned in_id, int in_alg); static int dst_s_write_public_key(const DST_KEY *key); static int dst_s_write_private_key(const DST_KEY *key); /* internal function to set up data structure */ static DST_KEY *dst_s_get_key_struct(const char *name, const int alg, const u_int32_t flags, const int protocol, const int bits); /* * dst_init * This function initializes the Digital Signature Toolkit. * Right now, it just checks the DSTKEYPATH environment variable. * Parameters * none * Returns * none */ void dst_init() { char *s; unsigned len; if (done_init != 0) return; done_init = 1; s = getenv("DSTKEYPATH"); len = 0; if (s) { struct stat statbuf; len = strlen(s); if (len > PATH_MAX) { EREPORT(("%s is longer than %d characters, ignoring\n", s, PATH_MAX)); } else if (stat(s, &statbuf) != 0 || !S_ISDIR(statbuf.st_mode)) { EREPORT(("%s is not a valid directory\n", s)); } else { char *dp = (char *) malloc(len + 2); int l; memcpy(dp, s, len + 1); l = strlen (dp); if (dp[l - 1] != '/') { dp[l + 1] = 0; dp[l] = '/'; } dst_path = dp; } } memset(dst_t_func, 0, sizeof(dst_t_func)); /* first one is selected */ #if 0 dst_bsafe_init(); dst_rsaref_init(); #endif dst_hmac_md5_init(); #if 0 dst_eay_dss_init(); dst_cylink_init(); #endif } /* * dst_check_algorithm * This function determines if the crypto system for the specified * algorithm is present. * Parameters * alg 1 KEY_RSA * 3 KEY_DSA * 157 KEY_HMAC_MD5 * future algorithms TBD and registered with IANA. * Returns * 1 - The algorithm is available. * 0 - The algorithm is not available. */ int dst_check_algorithm(const int alg) { return (dst_t_func[alg] != NULL); } /* * dst_s_get_key_struct * This function allocates key structure and fills in some of the * fields of the structure. * Parameters: * name: the name of the key * alg: the algorithm number * flags: the dns flags of the key * protocol: the dns protocol of the key * bits: the size of the key * Returns: * NULL if error * valid pointer otherwise */ static DST_KEY * dst_s_get_key_struct(const char *name, const int alg, const u_int32_t flags, const int protocol, const int bits) { DST_KEY *new_key = NULL; if (dst_check_algorithm(alg)) /* make sure alg is available */ new_key = (DST_KEY *) malloc(sizeof(*new_key)); if (new_key == NULL) return (NULL); memset(new_key, 0, sizeof(*new_key)); new_key->dk_key_name = strdup(name); new_key->dk_alg = alg; new_key->dk_flags = flags; new_key->dk_proto = protocol; new_key->dk_KEY_struct = NULL; new_key->dk_key_size = bits; new_key->dk_func = dst_t_func[alg]; return (new_key); } /* * dst_compare_keys * Compares two keys for equality. * Parameters * key1, key2 Two keys to be compared. * Returns * 0 The keys are equal. * non-zero The keys are not equal. */ int dst_compare_keys(const DST_KEY *key1, const DST_KEY *key2) { if (key1 == key2) return (0); if (key1 == NULL || key2 == NULL) return (4); if (key1->dk_alg != key2->dk_alg) return (1); if (key1->dk_key_size != key2->dk_key_size) return (2); if (key1->dk_id != key2->dk_id) return (3); return (key1->dk_func->compare(key1, key2)); } /* * dst_sign_data * An incremental signing function. Data is signed in steps. * First the context must be initialized (SIG_MODE_INIT). * Then data is hashed (SIG_MODE_UPDATE). Finally the signature * itself is created (SIG_MODE_FINAL). This function can be called * once with INIT, UPDATE and FINAL modes all set, or it can be * called separately with a different mode set for each step. The * UPDATE step can be repeated. * Parameters * mode A bit mask used to specify operation(s) to be performed. * SIG_MODE_INIT 1 Initialize digest * SIG_MODE_UPDATE 2 Add data to digest * SIG_MODE_FINAL 4 Generate signature * from signature * SIG_MODE_ALL (SIG_MODE_INIT,SIG_MODE_UPDATE,SIG_MODE_FINAL * data Data to be signed. * len The length in bytes of data to be signed. * in_key Contains a private key to sign with. * KEY structures should be handled (created, converted, * compared, stored, freed) by the DST. * signature * The location to which the signature will be written. * sig_len Length of the signature field in bytes. * Return * 0 Successful INIT or Update operation * >0 success FINAL (sign) operation * <0 failure */ int dst_sign_data(const int mode, DST_KEY *in_key, void **context, const u_char *data, const unsigned len, u_char *signature, const unsigned sig_len) { DUMP(data, mode, len, "dst_sign_data()"); if (mode & SIG_MODE_FINAL && (in_key->dk_KEY_struct == NULL || signature == NULL)) return (MISSING_KEY_OR_SIGNATURE); if (in_key->dk_func && in_key->dk_func->sign) return (in_key->dk_func->sign(mode, in_key, context, data, len, signature, sig_len)); return (UNKNOWN_KEYALG); } /* * dst_verify_data * An incremental verify function. Data is verified in steps. * First the context must be initialized (SIG_MODE_INIT). * Then data is hashed (SIG_MODE_UPDATE). Finally the signature * is verified (SIG_MODE_FINAL). This function can be called * once with INIT, UPDATE and FINAL modes all set, or it can be * called separately with a different mode set for each step. The * UPDATE step can be repeated. * Parameters * mode Operations to perform this time. * SIG_MODE_INIT 1 Initialize digest * SIG_MODE_UPDATE 2 add data to digest * SIG_MODE_FINAL 4 verify signature * SIG_MODE_ALL * (SIG_MODE_INIT,SIG_MODE_UPDATE,SIG_MODE_FINAL) * data Data to pass through the hash function. * len Length of the data in bytes. * in_key Key for verification. * signature Location of signature. * sig_len Length of the signature in bytes. * Returns * 0 Verify success * Non-Zero Verify Failure */ int dst_verify_data(const int mode, DST_KEY *in_key, void **context, const u_char *data, const unsigned len, const u_char *signature, const unsigned sig_len) { DUMP(data, mode, len, "dst_verify_data()"); if (mode & SIG_MODE_FINAL && (in_key->dk_KEY_struct == NULL || signature == NULL)) return (MISSING_KEY_OR_SIGNATURE); if (in_key->dk_func == NULL || in_key->dk_func->verify == NULL) return (UNSUPPORTED_KEYALG); return (in_key->dk_func->verify(mode, in_key, context, data, len, signature, sig_len)); } /* * dst_read_private_key * Access a private key. First the list of private keys that have * already been read in is searched, then the key accessed on disk. * If the private key can be found, it is returned. If the key cannot * be found, a null pointer is returned. The options specify required * key characteristics. If the private key requested does not have * these characteristics, it will not be read. * Parameters * in_keyname The private key name. * in_id The id of the private key. * options DST_FORCE_READ Read from disk - don't use a previously * read key. * DST_CAN_SIGN The key must be usable for signing. * DST_NO_AUTHEN The key must be usable for authentication. * DST_STANDARD Return any key * Returns * NULL If there is no key found in the current directory or * this key has not been loaded before. * !NULL Success - KEY structure returned. */ DST_KEY * dst_read_key(const char *in_keyname, const unsigned in_id, const int in_alg, const int type) { char keyname[PATH_MAX]; DST_KEY *dg_key = NULL, *pubkey = NULL; if (!dst_check_algorithm(in_alg)) { /* make sure alg is available */ EREPORT(("dst_read_private_key(): Algorithm %d not supported\n", in_alg)); return (NULL); } if ((type & (DST_PUBLIC | DST_PRIVATE)) == 0) return (NULL); if (in_keyname == NULL) { EREPORT(("dst_read_private_key(): Null key name passed in\n")); return (NULL); } else strcpy(keyname, in_keyname); /* before I read in the public key, check if it is allowed to sign */ if ((pubkey = dst_s_read_public_key(keyname, in_id, in_alg)) == NULL) return (NULL); if (type == DST_PUBLIC) return pubkey; if (!(dg_key = dst_s_get_key_struct(keyname, pubkey->dk_alg, pubkey->dk_flags, pubkey->dk_proto, 0))) return (dg_key); /* Fill in private key and some fields in the general key structure */ if (dst_s_read_private_key_file(keyname, dg_key, pubkey->dk_id, pubkey->dk_alg) == 0) dg_key = dst_free_key(dg_key); pubkey = dst_free_key(pubkey); return (dg_key); } int dst_write_key(const DST_KEY *key, const int type) { int pub = 0, priv = 0; if (key == NULL) return (0); if (!dst_check_algorithm(key->dk_alg)) { /* make sure alg is available */ EREPORT(("dst_write_key(): Algorithm %d not supported\n", key->dk_alg)); return (UNSUPPORTED_KEYALG); } if ((type & (DST_PRIVATE|DST_PUBLIC)) == 0) return (0); if (type & DST_PUBLIC) if ((pub = dst_s_write_public_key(key)) < 0) return (pub); if (type & DST_PRIVATE) if ((priv = dst_s_write_private_key(key)) < 0) return (priv); return (priv+pub); } /* * dst_write_private_key * Write a private key to disk. The filename will be of the form: * Kdk_name>+dk_alg>+dk_id>.. * If there is already a file with this name, an error is returned. * * Parameters * key A DST managed key structure that contains * all information needed about a key. * Return * >= 0 Correct behavior. Returns length of encoded key value * written to disk. * < 0 error. */ static int dst_s_write_private_key(const DST_KEY *key) { u_char encoded_block[RAW_KEY_SIZE]; char file[PATH_MAX]; unsigned len; FILE *fp; /* First encode the key into the portable key format */ if (key == NULL) return (-1); if (key->dk_KEY_struct == NULL) return (0); /* null key has no private key */ if (key->dk_func == NULL || key->dk_func->to_file_fmt == NULL) { EREPORT(("dst_write_private_key(): Unsupported operation %d\n", key->dk_alg)); return (-5); } else if ((len = key->dk_func->to_file_fmt(key, (char *)encoded_block, sizeof(encoded_block))) <= 0) { EREPORT(("dst_write_private_key(): Failed encoding private RSA bsafe key %d\n", len)); return (-8); } /* Now I can create the file I want to use */ dst_s_build_filename(file, key->dk_key_name, key->dk_id, key->dk_alg, PRIVATE_KEY, PATH_MAX); /* Do not overwrite an existing file */ if ((fp = dst_s_fopen(file, "w", 0600)) != NULL) { int nn; if ((nn = fwrite(encoded_block, 1, len, fp)) != len) { EREPORT(("dst_write_private_key(): Write failure on %s %d != %d errno=%d\n", file, out_len, nn, errno)); return (-5); } fclose(fp); } else { EREPORT(("dst_write_private_key(): Can not create file %s\n" ,file)); return (-6); } memset(encoded_block, 0, len); return (len); } /* * * dst_read_public_key * Read a public key from disk and store in a DST key structure. * Parameters * in_name K. is the * filename of the key file to be read. * Returns * NULL If the key does not exist or no name is supplied. * NON-NULL Initialized key structure if the key exists. */ static DST_KEY * dst_s_read_public_key(const char *in_name, const unsigned in_id, int in_alg) { unsigned flags, len; int proto, alg, dlen; int c; char name[PATH_MAX], enckey[RAW_KEY_SIZE]; unsigned char *notspace; u_char deckey[RAW_KEY_SIZE]; FILE *fp; if (in_name == NULL) { EREPORT(("dst_read_public_key(): No key name given\n")); return (NULL); } if (dst_s_build_filename(name, in_name, in_id, in_alg, PUBLIC_KEY, PATH_MAX) == -1) { EREPORT(("dst_read_public_key(): Cannot make filename from %s, %d, and %s\n", in_name, in_id, PUBLIC_KEY)); return (NULL); } /* * Open the file and read it's formatted contents up to key * File format: * domain.name [ttl] [IN] KEY * flags, proto, alg stored as decimal (or hex numbers FIXME). * (FIXME: handle parentheses for line continuation.) */ if ((fp = dst_s_fopen(name, "r", 0)) == NULL) { EREPORT(("dst_read_public_key(): Public Key not found %s\n", name)); return (NULL); } /* Skip domain name, which ends at first blank */ while ((c = getc(fp)) != EOF) if (isspace(c)) break; /* Skip blank to get to next field */ while ((c = getc(fp)) != EOF) if (!isspace(c)) break; /* Skip optional TTL -- if initial digit, skip whole word. */ if (isdigit(c)) { while ((c = getc(fp)) != EOF) if (isspace(c)) break; while ((c = getc(fp)) != EOF) if (!isspace(c)) break; } /* Skip optional "IN" */ if (c == 'I' || c == 'i') { while ((c = getc(fp)) != EOF) if (isspace(c)) break; while ((c = getc(fp)) != EOF) if (!isspace(c)) break; } /* Locate and skip "KEY" */ if (c != 'K' && c != 'k') { EREPORT(("\"KEY\" doesn't appear in file: %s", name)); return NULL; } while ((c = getc(fp)) != EOF) if (isspace(c)) break; while ((c = getc(fp)) != EOF) if (!isspace(c)) break; ungetc(c, fp); /* return the character to the input field */ /* Handle hex!! FIXME. */ if (fscanf(fp, "%d %d %d", &flags, &proto, &alg) != 3) { EREPORT(("dst_read_public_key(): Can not read flag/proto/alg field from %s\n" ,name)); return (NULL); } /* read in the key string */ if ((fgets(enckey, sizeof(enckey), fp) == NULL) && (ferror(fp) != 0)) { EREPORT(("dst_read_public_kety(): Error reading key\n")); return (NULL); } /* If we aren't at end-of-file, something is wrong. */ while ((c = getc(fp)) != EOF) if (!isspace(c)) break; if (!feof(fp)) { EREPORT(("Key too long in file: %s", name)); return NULL; } fclose(fp); if ((len = strlen(enckey)) <= 0) return (NULL); /* discard \n */ enckey[--len] = '\0'; /* remove leading spaces */ for (notspace = (unsigned char *)enckey; isspace(*notspace); len--) notspace++; dlen = b64_pton((char *)notspace, deckey, sizeof(deckey)); if (dlen < 0) { EREPORT(("dst_read_public_key: bad return from b64_pton = %d", dlen)); return (NULL); } /* store key and info in a key structure that is returned */ /* return dst_store_public_key(in_name, alg, proto, 666, flags, deckey, dlen);*/ return dst_buffer_to_key(in_name, alg, flags, proto, deckey, (unsigned)dlen); } /* * dst_write_public_key * Write a key to disk in DNS format. * Parameters * key Pointer to a DST key structure. * Returns * 0 Failure * 1 Success */ static int dst_s_write_public_key(const DST_KEY *key) { FILE *fp; char filename[PATH_MAX]; u_char out_key[RAW_KEY_SIZE]; char enc_key[RAW_KEY_SIZE]; int len = 0; memset(out_key, 0, sizeof(out_key)); if (key == NULL) { EREPORT(("dst_write_public_key(): No key specified \n")); return (0); } else if ((len = dst_key_to_dnskey(key, out_key, sizeof(out_key)))< 0) return (0); /* Make the filename */ if (dst_s_build_filename(filename, key->dk_key_name, key->dk_id, key->dk_alg, PUBLIC_KEY, PATH_MAX) == -1) { EREPORT(("dst_write_public_key(): Cannot make filename from %s, %d, and %s\n", key->dk_key_name, key->dk_id, PUBLIC_KEY)); return (0); } /* create public key file */ if ((fp = dst_s_fopen(filename, "w+", 0644)) == NULL) { EREPORT(("DST_write_public_key: open of file:%s failed (errno=%d)\n", filename, errno)); return (0); } /*write out key first base64 the key data */ if (key->dk_flags & DST_EXTEND_FLAG) b64_ntop(&out_key[6], (unsigned)(len - 6), enc_key, sizeof(enc_key)); else b64_ntop(&out_key[4], (unsigned)(len - 4), enc_key, sizeof(enc_key)); fprintf(fp, "%s IN KEY %d %d %d %s\n", key->dk_key_name, key->dk_flags, key->dk_proto, key->dk_alg, enc_key); fclose(fp); return (1); } /* * dst_dnskey_to_public_key * This function converts the contents of a DNS KEY RR into a DST * key structure. * Parameters * len Length of the RDATA of the KEY RR RDATA * rdata A pointer to the the KEY RR RDATA. * in_name Key name to be stored in key structure. * Returns * NULL Failure * NON-NULL Success. Pointer to key structure. * Caller's responsibility to free() it. */ DST_KEY * dst_dnskey_to_key(const char *in_name, const u_char *rdata, const unsigned len) { DST_KEY *key_st; int alg ; int start = DST_KEY_START; if (rdata == NULL || len <= DST_KEY_ALG) /* no data */ return (NULL); alg = (u_int8_t) rdata[DST_KEY_ALG]; if (!dst_check_algorithm(alg)) { /* make sure alg is available */ EREPORT(("dst_dnskey_to_key(): Algorithm %d not supported\n", alg)); return (NULL); } if ((key_st = dst_s_get_key_struct(in_name, alg, 0, 0, 0)) == NULL) return (NULL); if (in_name == NULL) return (NULL); key_st->dk_flags = dst_s_get_int16(rdata); key_st->dk_proto = (u_int16_t) rdata[DST_KEY_PROT]; if (key_st->dk_flags & DST_EXTEND_FLAG) { u_int32_t ext_flags; ext_flags = (u_int32_t) dst_s_get_int16(&rdata[DST_EXT_FLAG]); key_st->dk_flags = key_st->dk_flags | (ext_flags << 16); start += 2; } /* * now point to the beginning of the data representing the encoding * of the key */ if (key_st->dk_func && key_st->dk_func->from_dns_key) { if (key_st->dk_func->from_dns_key(key_st, &rdata[start], len - start) > 0) return (key_st); } else EREPORT(("dst_dnskey_to_public_key(): unsupported alg %d\n", alg)); SAFE_FREE(key_st); return (key_st); } /* * dst_public_key_to_dnskey * Function to encode a public key into DNS KEY wire format * Parameters * key Key structure to encode. * out_storage Location to write the encoded key to. * out_len Size of the output array. * Returns * <0 Failure * >=0 Number of bytes written to out_storage */ int dst_key_to_dnskey(const DST_KEY *key, u_char *out_storage, const unsigned out_len) { u_int16_t val; int loc = 0; int enc_len = 0; if (key == NULL) return (-1); if (!dst_check_algorithm(key->dk_alg)) { /* make sure alg is available */ EREPORT(("dst_key_to_dnskey(): Algorithm %d not supported\n", key->dk_alg)); return (UNSUPPORTED_KEYALG); } memset(out_storage, 0, out_len); val = (u_int16_t)(key->dk_flags & 0xffff); out_storage[0] = (val >> 8) & 0xff; out_storage[1] = val & 0xff; loc += 2; out_storage[loc++] = (u_char) key->dk_proto; out_storage[loc++] = (u_char) key->dk_alg; if (key->dk_flags > 0xffff) { /* Extended flags */ val = (u_int16_t)((key->dk_flags >> 16) & 0xffff); out_storage[loc] = (val >> 8) & 0xff; out_storage[loc+1] = val & 0xff; loc += 2; } if (key->dk_KEY_struct == NULL) return (loc); if (key->dk_func && key->dk_func->to_dns_key) { enc_len = key->dk_func->to_dns_key(key, (u_char *) &out_storage[loc], out_len - loc); if (enc_len > 0) return (enc_len + loc); else return (-1); } else EREPORT(("dst_key_to_dnskey(): Unsupported ALG %d\n", key->dk_alg)); return (-1); } /* * dst_buffer_to_key * Function to encode a string of raw data into a DST key * Parameters * alg The algorithm (HMAC only) * key A pointer to the data * keylen The length of the data * Returns * NULL an error occurred * NON-NULL the DST key */ DST_KEY * dst_buffer_to_key(const char *key_name, /* name of the key */ const int alg, /* algorithm */ const unsigned flags, /* dns flags */ const int protocol, /* dns protocol */ const u_char *key_buf, /* key in dns wire fmt */ const unsigned key_len) /* size of key */ { DST_KEY *dkey = NULL; if (!dst_check_algorithm(alg)) { /* make sure alg is available */ EREPORT(("dst_buffer_to_key(): Algorithm %d not supported\n", alg)); return (NULL); } dkey = dst_s_get_key_struct(key_name, alg, flags, protocol, -1); if (dkey == NULL) return (NULL); if (dkey->dk_func != NULL && dkey->dk_func->from_dns_key != NULL) { if (dkey->dk_func->from_dns_key(dkey, key_buf, key_len) < 0) { EREPORT(("dst_buffer_to_key(): dst_buffer_to_hmac failed\n")); return (dst_free_key(dkey)); } return (dkey); } return (NULL); } int dst_key_to_buffer(DST_KEY *key, u_char *out_buff, unsigned buf_len) { int len; /* this function will extract the secret of HMAC into a buffer */ if(key == NULL) return (0); if(key->dk_func != NULL && key->dk_func != NULL) { len = key->dk_func->to_dns_key(key, out_buff, buf_len); if (len < 0) return (0); return (len); } return (0); } /* * dst_s_read_private_key_file * Function reads in private key from a file. * Fills out the KEY structure. * Parameters * name Name of the key to be read. * pk_key Structure that the key is returned in. * in_id Key identifier (tag) * Return * 1 if everything works * 0 if there is any problem */ static int dst_s_read_private_key_file(char *name, DST_KEY *pk_key, unsigned in_id, int in_alg) { int cnt, alg, len, major, minor, file_major, file_minor; int id; char filename[PATH_MAX]; u_char in_buff[RAW_KEY_SIZE]; char *p; FILE *fp; if (name == NULL || pk_key == NULL) { EREPORT(("dst_read_private_key_file(): No key name given\n")); return (0); } /* Make the filename */ if (dst_s_build_filename(filename, name, in_id, in_alg, PRIVATE_KEY, PATH_MAX) == -1) { EREPORT(("dst_read_private_key(): Cannot make filename from %s, %d, and %s\n", name, in_id, PRIVATE_KEY)); return (0); } /* first check if we can find the key file */ if ((fp = dst_s_fopen(filename, "r", 0)) == NULL) { EREPORT(("dst_s_read_private_key_file: Could not open file %s in directory %s\n", filename, dst_path[0] ? dst_path : (char *) getcwd(NULL, PATH_MAX - 1))); return (0); } /* now read the header info from the file */ if ((cnt = fread(in_buff, 1, sizeof(in_buff), fp)) < 5) { fclose(fp); EREPORT(("dst_s_read_private_key_file: error reading file %s (empty file)\n", filename)); return (0); } /* decrypt key */ fclose(fp); if (memcmp(in_buff, "Private-key-format: v", 20) != 0) goto fail; len = cnt; p = (char *)in_buff; if (!dst_s_verify_str((const char **) &p, "Private-key-format: v")) { EREPORT(("dst_s_read_private_key_file(): Not a Key file/Decrypt failed %s\n", name)); goto fail; } /* read in file format */ sscanf(p, "%d.%d", &file_major, &file_minor); sscanf(KEY_FILE_FORMAT, "%d.%d", &major, &minor); if (file_major < 1) { EREPORT(("dst_s_read_private_key_file(): Unknown keyfile %d.%d version for %s\n", file_major, file_minor, name)); goto fail; } else if (file_major > major || file_minor > minor) EREPORT(( "dst_s_read_private_key_file(): Keyfile %s version higher than mine %d.%d MAY FAIL\n", name, file_major, file_minor)); while (*p++ != '\n') ; /* skip to end of line */ if (!dst_s_verify_str((const char **) &p, "Algorithm: ")) goto fail; if (sscanf(p, "%d", &alg) != 1) goto fail; while (*p++ != '\n') ; /* skip to end of line */ if (pk_key->dk_key_name && !strcmp(pk_key->dk_key_name, name)) SAFE_FREE2(pk_key->dk_key_name, strlen(pk_key->dk_key_name)); pk_key->dk_key_name = (char *) strdup(name); /* allocate and fill in key structure */ if (pk_key->dk_func == NULL || pk_key->dk_func->from_file_fmt == NULL) goto fail; id = pk_key->dk_func->from_file_fmt(pk_key, (char *)p, (unsigned)(&in_buff[len] - (u_char *)p)); if (id < 0) goto fail; /* Make sure the actual key tag matches the input tag used in the filename */ if (id != in_id) { EREPORT(("dst_s_read_private_key_file(): actual tag of key read %d != input tag used to build filename %d.\n", id, in_id)); goto fail; } pk_key->dk_id = (u_int16_t) id; pk_key->dk_alg = alg; memset(in_buff, 0, (unsigned)cnt); return (1); fail: memset(in_buff, 0, (unsigned)cnt); return (0); } /* * dst_generate_key * Generate and store a public/private keypair. * Keys will be stored in formatted files. * Parameters * name Name of the new key. Used to create key files * K++.public and K++.private. * bits Size of the new key in bits. * exp What exponent to use: * 0 use exponent 3 * non-zero use Fermant4 * flags The default value of the DNS Key flags. * The DNS Key RR Flag field is defined in RFC 2065, * section 3.3. The field has 16 bits. * protocol * Default value of the DNS Key protocol field. * The DNS Key protocol field is defined in RFC 2065, * section 3.4. The field has 8 bits. * alg What algorithm to use. Currently defined: * KEY_RSA 1 * KEY_DSA 3 * KEY_HMAC 157 * out_id The key tag is returned. * * Return * NULL Failure * non-NULL the generated key pair * Caller frees the result, and its dk_name pointer. */ DST_KEY * dst_generate_key(const char *name, const int bits, const int exp, const unsigned flags, const int protocol, const int alg) { DST_KEY *new_key = NULL; int res; if (name == NULL) return (NULL); if (!dst_check_algorithm(alg)) { /* make sure alg is available */ EREPORT(("dst_generate_key(): Algorithm %d not supported\n", alg)); return (NULL); } new_key = dst_s_get_key_struct(name, alg, flags, protocol, bits); if (new_key == NULL) return (NULL); if (bits == 0) /* null key we are done */ return (new_key); if (new_key->dk_func == NULL || new_key->dk_func->generate == NULL) { EREPORT(("dst_generate_key_pair():Unsupported algorithm %d\n", alg)); return (dst_free_key(new_key)); } if ((res = new_key->dk_func->generate(new_key, exp)) <= 0) { EREPORT(("dst_generate_key_pair(): Key generation failure %s %d %d %d\n", new_key->dk_key_name, new_key->dk_alg, new_key->dk_key_size, exp)); return (dst_free_key(new_key)); } return (new_key); } /* * dst_free_key * Release all data structures pointed to by a key structure. * Parameters * f_key Key structure to be freed. */ DST_KEY * dst_free_key(DST_KEY *f_key) { if (f_key == NULL) return (f_key); if (f_key->dk_func && f_key->dk_func->destroy) f_key->dk_KEY_struct = f_key->dk_func->destroy(f_key->dk_KEY_struct); else { EREPORT(("dst_free_key(): Unknown key alg %d\n", f_key->dk_alg)); free(f_key->dk_KEY_struct); /* SHOULD NOT happen */ } if (f_key->dk_KEY_struct) { free(f_key->dk_KEY_struct); f_key->dk_KEY_struct = NULL; } if (f_key->dk_key_name) SAFE_FREE(f_key->dk_key_name); SAFE_FREE(f_key); return (NULL); } /* * dst_sig_size * Return the maximum size of signature from the key specified in bytes * Parameters * key * Returns * bytes */ int dst_sig_size(DST_KEY *key) { switch (key->dk_alg) { case KEY_HMAC_MD5: return (16); case KEY_HMAC_SHA1: return (20); case KEY_RSA: return (key->dk_key_size + 7) / 8; case KEY_DSA: return (40); default: EREPORT(("dst_sig_size(): Unknown key alg %d\n", key->dk_alg)); return -1; } } /* * dst_random * function that multiplexes number of random number generators * Parameters * mode: select the random number generator * wanted is how many bytes of random data are requested * outran is a buffer of size at least wanted for the output data * * Returns * number of bytes written to outran */ int dst_random(const int mode, unsigned wanted, u_char *outran) { u_int32_t *buff = NULL, *bp = NULL; int i; if (wanted <= 0 || outran == NULL) return (0); switch (mode) { case DST_RAND_SEMI: bp = buff = (u_int32_t *) malloc(wanted+sizeof(u_int32_t)); for (i = 0; i < wanted; i+= sizeof(u_int32_t), bp++) { *bp = dst_s_quick_random(i); } memcpy(outran, buff, (unsigned)wanted); SAFE_FREE(buff); return (wanted); case DST_RAND_STD: return (dst_s_semi_random(outran, wanted)); case DST_RAND_KEY: return (dst_s_random(outran, wanted)); case DST_RAND_DSS: default: /* need error case here XXX OG */ return (0); } } dhcp-4.2.4/dst/dst_internal.h000644 000765 000024 00000012724 11301372615 016025 0ustar00sarstaff000000 000000 #ifndef DST_INTERNAL_H #define DST_INTERNAL_H /* * Portions Copyright (c) 1995-1998 by Trusted Information Systems, Inc. * Portions Copyright (c) 2007,2009 by Internet Systems Consortium, Inc. ("ISC") * * Permission to use, copy modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND TRUSTED INFORMATION SYSTEMS * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL * TRUSTED INFORMATION SYSTEMS BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION * WITH THE USE OR PERFORMANCE OF THE SOFTWARE. */ #include #include #ifndef PATH_MAX # ifdef POSIX_PATH_MAX # define PATH_MAX POSIX_PATH_MAX # else # define PATH_MAX 255 /* this is the value of POSIX_PATH_MAX */ # endif #endif typedef struct dst_key { char *dk_key_name; /* name of the key */ int dk_key_size; /* this is the size of the key in bits */ int dk_proto; /* what protocols this key can be used for */ int dk_alg; /* algorithm number from key record */ unsigned dk_flags; /* and the flags of the public key */ unsigned dk_id; /* identifier of the key */ void *dk_KEY_struct; /* pointer to key in crypto pkg fmt */ struct dst_func *dk_func; /* point to crypto pgk specific function table */ } DST_KEY; #define HAS_DST_KEY #include /* * define what crypto systems are supported for RSA, * BSAFE is preferred over RSAREF; only one can be set at any time */ #if defined(BSAFE) && defined(RSAREF) # error "Cannot have both BSAFE and RSAREF defined" #endif /* Declare dst_lib specific constants */ #define KEY_FILE_FORMAT "1.2" /* suffixes for key file names */ #define PRIVATE_KEY "private" #define PUBLIC_KEY "key" /* error handling */ #ifdef REPORT_ERRORS #define EREPORT(str) printf str #else #define EREPORT(str) #endif /* use our own special macro to FRRE memory */ #ifndef SAFE_FREE #define SAFE_FREE(a) if(a != NULL){memset(a,0, sizeof(*a)); free(a); a=NULL;} #define SAFE_FREE2(a,s) if (a != NULL && s > 0){memset(a,0, s);free(a); a=NULL;} #endif typedef struct dst_func { int (*sign)(const int mode, DST_KEY *key, void **context, const u_int8_t *data, const unsigned len, u_int8_t *signature, const unsigned sig_len); int (*verify)(const int mode, DST_KEY *key, void **context, const u_int8_t *data, const unsigned len, const u_int8_t *signature, const unsigned sig_len); int (*compare)(const DST_KEY *key1, const DST_KEY *key2); int (*generate)(DST_KEY *key, int parms); void *(*destroy)(void *key); /* conversion functions */ int (*to_dns_key)(const DST_KEY *key, u_int8_t *out, const unsigned out_len); int (*from_dns_key)(DST_KEY *key, const u_int8_t *str, const unsigned str_len); int (*to_file_fmt)(const DST_KEY *key, char *out, const unsigned out_len); int (*from_file_fmt)(DST_KEY *key, const char *out, const unsigned out_len); } dst_func; extern dst_func *dst_t_func[DST_MAX_ALGS]; extern const char *key_file_fmt_str; extern const char *dst_path; #ifndef DST_HASH_SIZE #define DST_HASH_SIZE 20 /* RIPEMD160 and SHA-1 are 20 bytes MD5 is 16 */ #endif #if 0 int dst_bsafe_init(void); int dst_rsaref_init(void); #endif int dst_hmac_md5_init(void); #if 0 int dst_cylink_init(void); int dst_eay_dss_init(void); #endif /* support functions */ /* base64 to bignum conversion routines */ int dst_s_conv_bignum_u8_to_b64( char *out_buf, const unsigned out_len, const char *header, const u_int8_t *bin_data, const unsigned bin_len); int dst_s_conv_bignum_b64_to_u8( const char **buf, u_int8_t *loc, const unsigned loclen) ; /* from higher level support routines */ int dst_s_calculate_bits( const u_int8_t *str, const int max_bits); int dst_s_verify_str( const char **buf, const char *str); /* conversion between dns names and key file names */ size_t dst_s_filename_length( const char *name, const char *suffix); int dst_s_build_filename( char *filename, const char *name, unsigned id, int alg, const char *suffix, size_t filename_length); FILE *dst_s_fopen (const char *filename, const char *mode, unsigned perm); /* from file prandom.c */ int dst_s_random( u_int8_t *output, unsigned size); int dst_s_semi_random( u_int8_t *output, unsigned size); u_int32_t dst_s_quick_random( int inc); void dst_s_quick_random_set( u_int32_t val, u_int32_t cnt); /* * read and write network byte order into u_int?_t * all of these should be retired */ u_int16_t dst_s_get_int16( const u_int8_t *buf); void dst_s_put_int16( u_int8_t *buf, const u_int16_t val); u_int32_t dst_s_get_int32( const u_int8_t *buf); void dst_s_put_int32( u_int8_t *buf, const u_int32_t val); #ifdef DUMP # undef DUMP # define DUMP(a,b,c,d) dst_s_dump(a,b,c,d) #else # define DUMP(a,b,c,d) #endif #if defined (MINIRES_LIB) #define b64_pton MRb64_pton #define b64_ntop MRb64_ntop int b64_pton (char const *, unsigned char *, size_t); int b64_ntop (unsigned char const *, size_t, char *, size_t); #define USE_MD5 #endif #endif /* DST_INTERNAL_H */ dhcp-4.2.4/dst/dst_support.c000644 000765 000024 00000030105 11301372615 015711 0ustar00sarstaff000000 000000 static const char rcsid[] = "$Header: /proj/cvs/prod/DHCP/dst/dst_support.c,v 1.6.6.1 2009-11-20 01:49:01 sar Exp $"; /* * Portions Copyright (c) 1995-1998 by Trusted Information Systems, Inc. * Portions Copyright (c) 2007,2009 by Internet Systems Consortium, Inc. ("ISC") * * Permission to use, copy modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND TRUSTED INFORMATION SYSTEMS * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL * TRUSTED INFORMATION SYSTEMS BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION * WITH THE USE OR PERFORMANCE OF THE SOFTWARE. */ #include #include #include #include #include #include #include #include #include "cdefs.h" #include "osdep.h" #include "arpa/nameser.h" #include "dst_internal.h" /* * dst_s_conv_bignum_u8_to_b64 * This function converts binary data stored as a u_char[] to a * base-64 string. Leading zeroes are discarded. If a header is * supplied, it is prefixed to the input prior to encoding. The * output is \n\0 terminated (the \0 is not included in output length). * Parameters * out_buf binary data to convert * header character string to prefix to the output (label) * bin_data binary data * bin_len size of binary data * Return * -1 not enough space in output work area * 0 no output * >0 number of bytes written to output work area */ int dst_s_conv_bignum_u8_to_b64(char *out_buf, const unsigned out_len, const char *header, const u_char *bin_data, const unsigned bin_len) { const u_char *bp = bin_data; char *op = out_buf; unsigned lenh = 0, len64 = 0; unsigned local_in_len = bin_len; unsigned local_out_len = out_len; if (bin_data == NULL) /* no data no */ return (0); if (out_buf == NULL || out_len <= 0) /* no output_work area */ return (-1); /* suppress leading \0 */ for (; (*bp == 0x0) && (local_in_len > 0); local_in_len--) bp++; if (header) { /* add header to output string */ lenh = strlen(header); if (lenh < out_len) memcpy(op, header, lenh); else return (-1); local_out_len -= lenh; op += lenh; } len64 = b64_ntop(bp, local_in_len, op, local_out_len - 2); if (len64 < 0) return (-1); op += len64++; *(op++) = '\n'; /* put CR in the output */ *op = '\0'; /* make sure output is 0 terminated */ return (lenh + len64); } /* * dst_s_verify_str() * Validate that the input string(*str) is at the head of the input * buffer(**buf). If so, move the buffer head pointer (*buf) to * the first byte of data following the string(*str). * Parameters * buf Input buffer. * str Input string. * Return * 0 *str is not the head of **buff * 1 *str is the head of **buff, *buf is is advanced to * the tail of **buf. */ int dst_s_verify_str(const char **buf, const char *str) { unsigned b, s; if (*buf == NULL) /* error checks */ return (0); if (str == NULL || *str == '\0') return (1); b = strlen(*buf); /* get length of strings */ s = strlen(str); if (s > b || strncmp(*buf, str, s)) /* check if same */ return (0); /* not a match */ (*buf) += s; /* advance pointer */ return (1); } /* * dst_s_conv_bignum_b64_to_u8 * Read a line of base-64 encoded string from the input buffer, * convert it to binary, and store it in an output area. The * input buffer is read until reaching a newline marker or the * end of the buffer. The binary data is stored in the last X * number of bytes of the output area where X is the size of the * binary output. If the operation is successful, the input buffer * pointer is advanced. This procedure does not do network to host * byte order conversion. * Parameters * buf Pointer to encoded input string. Pointer is updated if * function is successful. * loc Output area. * loclen Size in bytes of output area. * Return * >0 Return = number of bytes of binary data stored in loc. * 0 Failure. */ int dst_s_conv_bignum_b64_to_u8(const char **buf, u_char *loc, const unsigned loclen) { unsigned blen; char *bp; u_char bstr[RAW_KEY_SIZE]; if (buf == NULL || *buf == NULL) { /* error checks */ EREPORT(("dst_s_conv_bignum_b64_to_u8: null input buffer.\n")); return (0); } bp = strchr(*buf, '\n'); /* find length of input line */ if (bp != NULL) *bp = '\0'; blen = b64_pton(*buf, bstr, sizeof(bstr)); if (blen <= 0) { EREPORT(("dst_s_conv_bignum_b64_to_u8: decoded value is null.\n")); return (0); } else if (loclen < blen) { EREPORT(("dst_s_conv_bignum_b64_to_u8: decoded value is longer than output buffer.\n")); return (0); } if (bp) *buf = bp; /* advancing buffer past \n */ memset(loc, 0, loclen - blen); /* clearing unused output area */ memcpy(loc + loclen - blen, bstr, blen); /* write last blen bytes */ return (blen); } /* * dst_s_calculate_bits * Given a binary number represented in a u_char[], determine * the number of significant bits used. * Parameters * str An input character string containing a binary number. * max_bits The maximum possible significant bits. * Return * N The number of significant bits in str. */ int dst_s_calculate_bits(const u_char *str, const int max_bits) { const u_char *p = str; u_char i, j = 0x80; int bits; for (bits = max_bits; *p == 0x00 && bits > 0; p++) bits -= 8; for (i = *p; (i & j) != j; j >>= 1) bits--; return (bits); } /* * calculates a checksum used in kmt for a id. * takes an array of bytes and a length. * returns a 16 bit checksum. */ u_int16_t dst_s_id_calc(const u_char *key, const unsigned keysize) { u_int32_t ac; const u_char *kp = key; unsigned size = keysize; if (!key) return 0; for (ac = 0; size > 1; size -= 2, kp += 2) ac += ((*kp) << 8) + *(kp + 1); if (size > 0) ac += ((*kp) << 8); ac += (ac >> 16) & 0xffff; return (ac & 0xffff); } /* * dst_s_dns_key_id() Function to calculated DNSSEC footprint from KEY record * rdata (all of record) * Input: * dns_key_rdata: the raw data in wire format * rdata_len: the size of the input data * Output: * the key footprint/id calculated from the key data */ u_int16_t dst_s_dns_key_id(const u_char *dns_key_rdata, const unsigned rdata_len) { unsigned key_data = 4; if (!dns_key_rdata || (rdata_len < key_data)) return 0; /* check the extended parameters bit in the DNS Key RR flags */ if (dst_s_get_int16(dns_key_rdata) & DST_EXTEND_FLAG) key_data += 2; /* compute id */ if (dns_key_rdata[3] == KEY_RSA) /* Algorithm RSA */ return dst_s_get_int16((const u_char *) &dns_key_rdata[rdata_len - 3]); else /* compute a checksum on the key part of the key rr */ return dst_s_id_calc(&dns_key_rdata[key_data], (rdata_len - key_data)); } /* * dst_s_get_int16 * This routine extracts a 16 bit integer from a two byte character * string. The character string is assumed to be in network byte * order and may be unaligned. The number returned is in host order. * Parameter * buf A two byte character string. * Return * The converted integer value. */ u_int16_t dst_s_get_int16(const u_char *buf) { register u_int16_t a = 0; a = ((u_int16_t)(buf[0] << 8)) | ((u_int16_t)(buf[1])); return (a); } /* * dst_s_get_int32 * This routine extracts a 32 bit integer from a four byte character * string. The character string is assumed to be in network byte * order and may be unaligned. The number returned is in host order. * Parameter * buf A four byte character string. * Return * The converted integer value. */ u_int32_t dst_s_get_int32(const u_char *buf) { register u_int32_t a = 0; a = ((u_int32_t)(buf[0] << 24)) | ((u_int32_t)(buf[1] << 16)) | ((u_int32_t)(buf[2] << 8)) | ((u_int32_t)(buf[3])); return (a); } /* * dst_s_put_int16 * Take a 16 bit integer and store the value in a two byte * character string. The integer is assumed to be in network * order and the string is returned in host order. * * Parameters * buf Storage for a two byte character string. * val 16 bit integer. */ void dst_s_put_int16(u_int8_t *buf, const u_int16_t val) { buf[0] = (u_int8_t)(val >> 8); buf[1] = (u_int8_t)(val); } /* * dst_s_put_int32 * Take a 32 bit integer and store the value in a four byte * character string. The integer is assumed to be in network * order and the string is returned in host order. * * Parameters * buf Storage for a four byte character string. * val 32 bit integer. */ void dst_s_put_int32(u_int8_t *buf, const u_int32_t val) { buf[0] = (u_int8_t)(val >> 24); buf[1] = (u_int8_t)(val >> 16); buf[2] = (u_int8_t)(val >> 8); buf[3] = (u_int8_t)(val); } /* * dst_s_filename_length * * This function returns the number of bytes needed to hold the * filename for a key file. '/', '\' and ':' are not allowed. * form: K++. * * Returns 0 if the filename would contain either '\', '/' or ':' */ size_t dst_s_filename_length(const char *name, const char *suffix) { if (name == NULL) return (0); if (strrchr(name, '\\')) return (0); if (strrchr(name, '/')) return (0); if (strrchr(name, ':')) return (0); if (suffix == NULL) return (0); if (strrchr(suffix, '\\')) return (0); if (strrchr(suffix, '/')) return (0); if (strrchr(suffix, ':')) return (0); return (1 + strlen(name) + 6 + strlen(suffix)); } /* * dst_s_build_filename () * Builds a key filename from the key name, it's id, and a * suffix. '\', '/' and ':' are not allowed. fA filename is of the * form: K. * form: K++. * * Returns -1 if the conversion fails: * if the filename would be too long for space allotted * if the filename would contain a '\', '/' or ':' * Returns 0 on success */ int dst_s_build_filename(char *filename, const char *name, unsigned id, int alg, const char *suffix, size_t filename_length) { unsigned my_id; if (filename == NULL) return (-1); memset(filename, 0, filename_length); if (name == NULL) return (-1); if (suffix == NULL) return (-1); if (filename_length < 1 + strlen(name) + 4 + 6 + 1 + strlen(suffix)) return (-1); my_id = id; sprintf(filename, "K%s+%03d+%05d.%s", name, alg, my_id, (const char *) suffix); if (strrchr(filename, '/')) return (-1); if (strrchr(filename, '\\')) return (-1); if (strrchr(filename, ':')) return (-1); return (0); } /* * dst_s_fopen () * Open a file in the dst_path directory. If perm is specified, the * file is checked for existence first, and not opened if it exists. * Parameters * filename File to open * mode Mode to open the file (passed directly to fopen) * perm File permission, if creating a new file. * Returns * NULL Failure * NON-NULL (FILE *) of opened file. */ FILE * dst_s_fopen(const char *filename, const char *mode, unsigned perm) { FILE *fp; char pathname[PATH_MAX]; unsigned plen = sizeof(pathname); if (*dst_path != '\0') { strcpy(pathname, dst_path); plen -= strlen(pathname); } else pathname[0] = '\0'; if (plen > strlen(filename)) strncpy(&pathname[PATH_MAX - plen], filename, plen-1); else return (NULL); fp = fopen(pathname, mode); if (perm) chmod(pathname, perm); return (fp); } #if 0 void dst_s_dump(const int mode, const u_char *data, const int size, const char *msg) { if (size > 0) { #ifdef LONG_TEST static u_char scratch[1000]; int n ; n = b64_ntop(data, scratch, size, sizeof(scratch)); printf("%s: %x %d %s\n", msg, mode, n, scratch); #else printf("%s,%x %d\n", msg, mode, size); #endif } } #endif dhcp-4.2.4/dst/hmac_link.c000644 000765 000024 00000031543 11301372615 015257 0ustar00sarstaff000000 000000 #ifdef HMAC_MD5 #ifndef LINT static const char rcsid[] = "$Header: /proj/cvs/prod/DHCP/dst/hmac_link.c,v 1.5.6.1 2009-11-20 01:49:01 sar Exp $"; #endif /* * Portions Copyright (c) 1995-1998 by Trusted Information Systems, Inc. * Portions Copyright (c) 2007,2009 by Internet Systems Consortium, Inc. ("ISC") * * Permission to use, copy modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND TRUSTED INFORMATION SYSTEMS * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL * TRUSTED INFORMATION SYSTEMS BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION * WITH THE USE OR PERFORMANCE OF THE SOFTWARE. */ /* * This file contains an implementation of the HMAC-MD5 algorithm. */ #include #include #include #include #include #include #include #include #include #include "cdefs.h" #include "osdep.h" #include "arpa/nameser.h" #include "dst_internal.h" #ifdef USE_MD5 # include "md5.h" # ifndef _MD5_H_ # define _MD5_H_ 1 /* make sure we do not include rsaref md5.h file */ # endif #endif #define HMAC_LEN 64 #define HMAC_IPAD 0x36 #define HMAC_OPAD 0x5c #define MD5_LEN 16 typedef struct hmackey { u_char hk_ipad[64], hk_opad[64]; } HMAC_Key; /************************************************************************** * dst_hmac_md5_sign * Call HMAC signing functions to sign a block of data. * There are three steps to signing, INIT (initialize structures), * UPDATE (hash (more) data), FINAL (generate a signature). This * routine performs one or more of these steps. * Parameters * mode SIG_MODE_INIT, SIG_MODE_UPDATE and/or SIG_MODE_FINAL. * priv_key key to use for signing. * context the context to be used in this digest * data data to be signed. * len length in bytes of data. * signature location to store signature. * sig_len size of the signature location * returns * N Success on SIG_MODE_FINAL = returns signature length in bytes * 0 Success on SIG_MODE_INIT and UPDATE * <0 Failure */ static int dst_hmac_md5_sign(const int mode, DST_KEY *d_key, void **context, const u_char *data, const unsigned len, u_char *signature, const unsigned sig_len) { HMAC_Key *key; int sign_len = 0; MD5_CTX *ctx = NULL; if (mode & SIG_MODE_INIT) ctx = (MD5_CTX *) malloc(sizeof(*ctx)); else if (context) ctx = (MD5_CTX *) *context; if (ctx == NULL) return (-1); if (d_key == NULL || d_key->dk_KEY_struct == NULL) return (-1); key = (HMAC_Key *) d_key->dk_KEY_struct; if (mode & SIG_MODE_INIT) { MD5Init(ctx); MD5Update(ctx, key->hk_ipad, HMAC_LEN); } if ((mode & SIG_MODE_UPDATE) && (data && len > 0)) MD5Update(ctx, (const unsigned char *)data, len); if (mode & SIG_MODE_FINAL) { if (signature == NULL || sig_len < MD5_LEN) return (SIGN_FINAL_FAILURE); MD5Final(signature, ctx); /* perform outer MD5 */ MD5Init(ctx); MD5Update(ctx, key->hk_opad, HMAC_LEN); MD5Update(ctx, signature, MD5_LEN); MD5Final(signature, ctx); sign_len = MD5_LEN; SAFE_FREE(ctx); } else { if (context == NULL) return (-1); *context = (void *) ctx; } return (sign_len); } /************************************************************************** * dst_hmac_md5_verify() * Calls HMAC verification routines. There are three steps to * verification, INIT (initialize structures), UPDATE (hash (more) data), * FINAL (generate a signature). This routine performs one or more of * these steps. * Parameters * mode SIG_MODE_INIT, SIG_MODE_UPDATE and/or SIG_MODE_FINAL. * dkey key to use for verify. * data data signed. * len length in bytes of data. * signature signature. * sig_len length in bytes of signature. * returns * 0 Success * <0 Failure */ static int dst_hmac_md5_verify(const int mode, DST_KEY *d_key, void **context, const u_char *data, const unsigned len, const u_char *signature, const unsigned sig_len) { HMAC_Key *key; MD5_CTX *ctx = NULL; if (mode & SIG_MODE_INIT) ctx = (MD5_CTX *) malloc(sizeof(*ctx)); else if (context) ctx = (MD5_CTX *) *context; if (ctx == NULL) return (-1); if (d_key == NULL || d_key->dk_KEY_struct == NULL) return (-1); key = (HMAC_Key *) d_key->dk_KEY_struct; if (mode & SIG_MODE_INIT) { MD5Init(ctx); MD5Update(ctx, key->hk_ipad, HMAC_LEN); } if ((mode & SIG_MODE_UPDATE) && (data && len > 0)) MD5Update(ctx, (const unsigned char *)data, len); if (mode & SIG_MODE_FINAL) { u_char digest[MD5_LEN]; if (signature == NULL || key == NULL || sig_len != MD5_LEN) return (VERIFY_FINAL_FAILURE); MD5Final(digest, ctx); /* perform outer MD5 */ MD5Init(ctx); MD5Update(ctx, key->hk_opad, HMAC_LEN); MD5Update(ctx, digest, MD5_LEN); MD5Final(digest, ctx); SAFE_FREE(ctx); if (memcmp(digest, signature, MD5_LEN) != 0) return (VERIFY_FINAL_FAILURE); } else { if (context == NULL) return (-1); *context = (void *) ctx; } return (0); } /************************************************************************** * dst_buffer_to_hmac_md5 * Converts key from raw data to an HMAC Key * This function gets in a pointer to the data * Parameters * hkey the HMAC key to be filled in * key the key in raw format * keylen the length of the key * Return * 0 Success * <0 Failure */ static int dst_buffer_to_hmac_md5(DST_KEY *dkey, const u_char *key, const unsigned keylen) { int i; HMAC_Key *hkey = NULL; MD5_CTX ctx; unsigned local_keylen = keylen; if (dkey == NULL || key == NULL || keylen < 0) return (-1); if ((hkey = (HMAC_Key *) malloc(sizeof(HMAC_Key))) == NULL) return (-2); memset(hkey->hk_ipad, 0, sizeof(hkey->hk_ipad)); memset(hkey->hk_opad, 0, sizeof(hkey->hk_opad)); /* if key is longer than HMAC_LEN bytes reset it to key=MD5(key) */ if (keylen > HMAC_LEN) { u_char tk[MD5_LEN]; MD5Init(&ctx); MD5Update(&ctx, (const unsigned char *)key, keylen); MD5Final(tk, &ctx); memset((void *) &ctx, 0, sizeof(ctx)); key = tk; local_keylen = MD5_LEN; } /* start out by storing key in pads */ memcpy(hkey->hk_ipad, key, local_keylen); memcpy(hkey->hk_opad, key, local_keylen); /* XOR key with hk_ipad and opad values */ for (i = 0; i < HMAC_LEN; i++) { hkey->hk_ipad[i] ^= HMAC_IPAD; hkey->hk_opad[i] ^= HMAC_OPAD; } dkey->dk_key_size = local_keylen; dkey->dk_KEY_struct = (void *) hkey; return (1); } /************************************************************************** * dst_hmac_md5_key_to_file_format * Encodes an HMAC Key into the portable file format. * Parameters * hkey HMAC KEY structure * buff output buffer * buff_len size of output buffer * Return * 0 Failure - null input hkey * -1 Failure - not enough space in output area * N Success - Length of data returned in buff */ static int dst_hmac_md5_key_to_file_format(const DST_KEY *dkey, char *buff, const unsigned buff_len) { char *bp; int i; unsigned len, b_len, key_len; u_char key[HMAC_LEN]; HMAC_Key *hkey; if (dkey == NULL || dkey->dk_KEY_struct == NULL) return (0); if (buff == NULL || buff_len <= (int) strlen(key_file_fmt_str)) return (-1); /* no OR not enough space in output area */ hkey = (HMAC_Key *) dkey->dk_KEY_struct; memset(buff, 0, buff_len); /* just in case */ /* write file header */ sprintf(buff, key_file_fmt_str, KEY_FILE_FORMAT, KEY_HMAC_MD5, "HMAC"); bp = (char *) strchr(buff, '\0'); b_len = buff_len - (bp - buff); memset(key, 0, HMAC_LEN); for (i = 0; i < HMAC_LEN; i++) key[i] = hkey->hk_ipad[i] ^ HMAC_IPAD; for (i = HMAC_LEN - 1; i >= 0; i--) if (key[i] != 0) break; key_len = i + 1; strcat(bp, "Key: "); bp += strlen("Key: "); b_len = buff_len - (bp - buff); len = b64_ntop(key, key_len, bp, b_len); if (len < 0) return (-1); bp += len; *(bp++) = '\n'; *bp = '\0'; b_len = buff_len - (bp - buff); return (buff_len - b_len); } /************************************************************************** * dst_hmac_md5_key_from_file_format * Converts contents of a key file into an HMAC key. * Parameters * hkey structure to put key into * buff buffer containing the encoded key * buff_len the length of the buffer * Return * n >= 0 Foot print of the key converted * n < 0 Error in conversion */ static int dst_hmac_md5_key_from_file_format(DST_KEY *dkey, const char *buff, const unsigned buff_len) { const char *p = buff, *eol; u_char key[HMAC_LEN+1]; /* b64_pton needs more than 64 bytes do decode * it should probably be fixed rather than doing * this */ u_char *tmp; unsigned key_len, len; if (dkey == NULL) return (-2); if (buff == NULL) return (-1); memset(key, 0, sizeof(key)); if (!dst_s_verify_str(&p, "Key: ")) return (-3); eol = strchr(p, '\n'); if (eol == NULL) return (-4); len = eol - p; tmp = malloc(len + 2); memcpy(tmp, p, len); *(tmp + len) = 0x0; key_len = b64_pton((char *)tmp, key, HMAC_LEN+1); /* see above */ SAFE_FREE2(tmp, len + 2); if (dst_buffer_to_hmac_md5(dkey, key, key_len) < 0) { return (-6); } return (0); } /* * dst_hmac_md5_to_dns_key() * function to extract hmac key from DST_KEY structure * input: * in_key: HMAC-MD5 key * output: * out_str: buffer to write ot * out_len: size of output buffer * returns: * number of bytes written to output buffer */ static int dst_hmac_md5_to_dns_key(const DST_KEY *in_key, u_char *out_str, const unsigned out_len) { HMAC_Key *hkey; int i; if (in_key == NULL || in_key->dk_KEY_struct == NULL || out_len <= in_key->dk_key_size || out_str == NULL) return (-1); hkey = (HMAC_Key *) in_key->dk_KEY_struct; for (i = 0; i < in_key->dk_key_size; i++) out_str[i] = hkey->hk_ipad[i] ^ HMAC_IPAD; return (i); } /************************************************************************** * dst_hmac_md5_compare_keys * Compare two keys for equality. * Return * 0 The keys are equal * NON-ZERO The keys are not equal */ static int dst_hmac_md5_compare_keys(const DST_KEY *key1, const DST_KEY *key2) { HMAC_Key *hkey1 = (HMAC_Key *) key1->dk_KEY_struct; HMAC_Key *hkey2 = (HMAC_Key *) key2->dk_KEY_struct; return memcmp(hkey1->hk_ipad, hkey2->hk_ipad, HMAC_LEN); } /************************************************************************** * dst_hmac_md5_free_key_structure * Frees all (none) dynamically allocated structures in hkey */ static void * dst_hmac_md5_free_key_structure(void *key) { HMAC_Key *hkey = key; SAFE_FREE(hkey); return (NULL); } /*************************************************************************** * dst_hmac_md5_generate_key * Creates a HMAC key of size size with a maximum size of 63 bytes * generating a HMAC key larger than 63 bytes makes no sense as that key * is digested before use. */ static int dst_hmac_md5_generate_key(DST_KEY *key, const int nothing) { u_char *buff; int n; unsigned size, len; if (key == NULL || key->dk_alg != KEY_HMAC_MD5) return (0); size = (key->dk_key_size + 7) / 8; /* convert to bytes */ if (size <= 0) return(0); len = size > 64 ? 64 : size; buff = malloc(len+8); n = dst_random(DST_RAND_SEMI, len, buff); n += dst_random(DST_RAND_KEY, len, buff); if (n <= len) { /* failed getting anything */ SAFE_FREE2(buff, len); return (-1); } n = dst_buffer_to_hmac_md5(key, buff, len); SAFE_FREE2(buff, len); if (n <= 0) return (n); return (1); } /* * dst_hmac_md5_init() Function to answer set up function pointers for HMAC * related functions */ int dst_hmac_md5_init() { if (dst_t_func[KEY_HMAC_MD5] != NULL) return (1); dst_t_func[KEY_HMAC_MD5] = malloc(sizeof(struct dst_func)); if (dst_t_func[KEY_HMAC_MD5] == NULL) return (0); memset(dst_t_func[KEY_HMAC_MD5], 0, sizeof(struct dst_func)); dst_t_func[KEY_HMAC_MD5]->sign = dst_hmac_md5_sign; dst_t_func[KEY_HMAC_MD5]->verify = dst_hmac_md5_verify; dst_t_func[KEY_HMAC_MD5]->compare = dst_hmac_md5_compare_keys; dst_t_func[KEY_HMAC_MD5]->generate = dst_hmac_md5_generate_key; dst_t_func[KEY_HMAC_MD5]->destroy = dst_hmac_md5_free_key_structure; dst_t_func[KEY_HMAC_MD5]->to_dns_key = dst_hmac_md5_to_dns_key; dst_t_func[KEY_HMAC_MD5]->from_dns_key = dst_buffer_to_hmac_md5; dst_t_func[KEY_HMAC_MD5]->to_file_fmt = dst_hmac_md5_key_to_file_format; dst_t_func[KEY_HMAC_MD5]->from_file_fmt = dst_hmac_md5_key_from_file_format; return (1); } #else int dst_hmac_md5_init(){ return (0); } #endif dhcp-4.2.4/dst/Makefile.am000644 000765 000024 00000000314 10627052612 015214 0ustar00sarstaff000000 000000 AM_CPPFLAGS = -DMINIRES_LIB -DHMAC_MD5 lib_LIBRARIES = libdst.a libdst_a_SOURCES = dst_support.c dst_api.c hmac_link.c md5_dgst.c \ base64.c prandom.c EXTRA_DIST = dst_internal.h md5.h md5_locl.h dhcp-4.2.4/dst/Makefile.in000644 000765 000024 00000032661 11757500140 015236 0ustar00sarstaff000000 000000 # Makefile.in generated by automake 1.10.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : subdir = dst DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/includes/config.h CONFIG_CLEAN_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = `echo $$p | sed -e 's|^.*/||'`; am__installdirs = "$(DESTDIR)$(libdir)" libLIBRARIES_INSTALL = $(INSTALL_DATA) LIBRARIES = $(lib_LIBRARIES) AR = ar ARFLAGS = cru libdst_a_AR = $(AR) $(ARFLAGS) libdst_a_LIBADD = am_libdst_a_OBJECTS = dst_support.$(OBJEXT) dst_api.$(OBJEXT) \ hmac_link.$(OBJEXT) md5_dgst.$(OBJEXT) base64.$(OBJEXT) \ prandom.$(OBJEXT) libdst_a_OBJECTS = $(am_libdst_a_OBJECTS) DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/includes depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) CCLD = $(CC) LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ SOURCES = $(libdst_a_SOURCES) DIST_SOURCES = $(libdst_a_SOURCES) ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ GREP = @GREP@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDAP_CFLAGS = @LDAP_CFLAGS@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_prefix_program = @ac_prefix_program@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build_alias = @build_alias@ builddir = @builddir@ byte_order = @byte_order@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host_alias = @host_alias@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AM_CPPFLAGS = -DMINIRES_LIB -DHMAC_MD5 lib_LIBRARIES = libdst.a libdst_a_SOURCES = dst_support.c dst_api.c hmac_link.c md5_dgst.c \ base64.c prandom.c EXTRA_DIST = dst_internal.h md5.h md5_locl.h all: all-am .SUFFIXES: .SUFFIXES: .c .o .obj $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ && exit 0; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign dst/Makefile'; \ cd $(top_srcdir) && \ $(AUTOMAKE) --foreign dst/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh install-libLIBRARIES: $(lib_LIBRARIES) @$(NORMAL_INSTALL) test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" @list='$(lib_LIBRARIES)'; for p in $$list; do \ if test -f $$p; then \ f=$(am__strip_dir) \ echo " $(libLIBRARIES_INSTALL) '$$p' '$(DESTDIR)$(libdir)/$$f'"; \ $(libLIBRARIES_INSTALL) "$$p" "$(DESTDIR)$(libdir)/$$f"; \ else :; fi; \ done @$(POST_INSTALL) @list='$(lib_LIBRARIES)'; for p in $$list; do \ if test -f $$p; then \ p=$(am__strip_dir) \ echo " $(RANLIB) '$(DESTDIR)$(libdir)/$$p'"; \ $(RANLIB) "$(DESTDIR)$(libdir)/$$p"; \ else :; fi; \ done uninstall-libLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(lib_LIBRARIES)'; for p in $$list; do \ p=$(am__strip_dir) \ echo " rm -f '$(DESTDIR)$(libdir)/$$p'"; \ rm -f "$(DESTDIR)$(libdir)/$$p"; \ done clean-libLIBRARIES: -test -z "$(lib_LIBRARIES)" || rm -f $(lib_LIBRARIES) libdst.a: $(libdst_a_OBJECTS) $(libdst_a_DEPENDENCIES) -rm -f libdst.a $(libdst_a_AR) libdst.a $(libdst_a_OBJECTS) $(libdst_a_LIBADD) $(RANLIB) libdst.a mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/base64.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dst_api.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dst_support.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hmac_link.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/md5_dgst.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/prandom.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) tags=; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$tags $$unique; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) tags=; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$tags$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$tags $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && cd $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) $$here distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ fi; \ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ else \ test -f $(distdir)/$$file \ || cp -p $$d/$$file $(distdir)/$$file \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(LIBRARIES) installdirs: for dir in "$(DESTDIR)$(libdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libLIBRARIES mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-exec-am: install-libLIBRARIES install-html: install-html-am install-info: install-info-am install-man: install-pdf: install-pdf-am install-ps: install-ps-am installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-libLIBRARIES .MAKE: install-am install-strip .PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ clean-libLIBRARIES ctags distclean distclean-compile \ distclean-generic distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-libLIBRARIES install-man install-pdf \ install-pdf-am install-ps install-ps-am install-strip \ installcheck installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ uninstall-am uninstall-libLIBRARIES # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: dhcp-4.2.4/dst/md5.h000644 000765 000024 00000011747 11301372615 014030 0ustar00sarstaff000000 000000 /* crypto/md/md5.h */ /* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com) * All rights reserved. * * This package is an SSL implementation written * by Eric Young (eay@cryptsoft.com). * The implementation was written so as to conform with Netscapes SSL. * * This library is free for commercial and non-commercial use as long as * the following conditions are aheared to. The following conditions * apply to all code found in this distribution, be it the RC4, RSA, * lhash, DES, etc., code; not just the SSL code. The SSL documentation * included with this distribution is covered by the same copyright terms * except that the holder is Tim Hudson (tjh@cryptsoft.com). * * Copyright remains Eric Young's, and as such any Copyright notices in * the code are not to be removed. * If this package is used in a product, Eric Young should be given attribution * as the author of the parts of the library used. * This can be in the form of a textual message at program startup or * in documentation (online or textual) provided with the package. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * "This product includes cryptographic software written by * Eric Young (eay@cryptsoft.com)" * The word 'cryptographic' can be left out if the rouines from the library * being used are not cryptographic related :-). * 4. If you include any Windows specific code (or a derivative thereof) from * the apps directory (application code) you must include an acknowledgement: * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" * * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * The licence and distribution terms for any publically available version or * derivative of this code cannot be changed. i.e. this code cannot simply be * copied and put under another distribution licence * [including the GNU Public Licence.] */ /* * Portions Copyright (c) 2007,2009 by Internet Systems Consortium, Inc. ("ISC") * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ */ #ifndef HEADER_MD5_H #define HEADER_MD5_H #ifdef __cplusplus extern "C" { #endif #define MD5_CBLOCK 64 #define MD5_LBLOCK 16 #define MD5_BLOCK 16 #define MD5_LAST_BLOCK 56 #define MD5_LENGTH_BLOCK 8 #define MD5_DIGEST_LENGTH 16 typedef struct MD5state_st { unsigned long A,B,C,D; unsigned long Nl,Nh; unsigned long data[MD5_LBLOCK]; int num; } MD5_CTX; #ifndef NOPROTO void MD5_Init(MD5_CTX *c); void MD5_Update(MD5_CTX *c, const unsigned char *data, unsigned long len); void MD5_Final(unsigned char *md, MD5_CTX *c); unsigned char *MD5(unsigned char *d, unsigned long n, unsigned char *md); #else void MD5_Init(); void MD5_Update(); void MD5_Final(); unsigned char *MD5(); #endif /* to provide backward compatibleness to RSAREF calls ogud@tis.com 1997/11/14 */ #define MD5Init(c) MD5_Init(c) #define MD5Update(c,data, len) MD5_Update(c,data,len) #define MD5Final(md, c) MD5_Final(md, c) #ifdef __cplusplus } #endif #endif dhcp-4.2.4/dst/md5_dgst.c000644 000765 000024 00000026150 11301372615 015036 0ustar00sarstaff000000 000000 /* crypto/md/md5_dgst.c */ /* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com) * All rights reserved. * * This package is an SSL implementation written * by Eric Young (eay@cryptsoft.com). * The implementation was written so as to conform with Netscapes SSL. * * This library is free for commercial and non-commercial use as long as * the following conditions are aheared to. The following conditions * apply to all code found in this distribution, be it the RC4, RSA, * lhash, DES, etc., code; not just the SSL code. The SSL documentation * included with this distribution is covered by the same copyright terms * except that the holder is Tim Hudson (tjh@cryptsoft.com). * * Copyright remains Eric Young's, and as such any Copyright notices in * the code are not to be removed. * If this package is used in a product, Eric Young should be given attribution * as the author of the parts of the library used. * This can be in the form of a textual message at program startup or * in documentation (online or textual) provided with the package. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * "This product includes cryptographic software written by * Eric Young (eay@cryptsoft.com)" * The word 'cryptographic' can be left out if the rouines from the library * being used are not cryptographic related :-). * 4. If you include any Windows specific code (or a derivative thereof) from * the apps directory (application code) you must include an acknowledgement: * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" * * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * The licence and distribution terms for any publically available version or * derivative of this code cannot be changed. i.e. this code cannot simply be * copied and put under another distribution licence * [including the GNU Public Licence.] */ /* * Portions Copyright (c) 2007,2009 by Internet Systems Consortium, Inc. ("ISC") * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ */ #include #include #include #include #include "md5_locl.h" #include "cdefs.h" #include "osdep.h" #ifdef USE_MD5 /* Added by ogud@tis.com 1998/1/26 */ const char *MD5_version="MD5 part of SSLeay 0.8.1 19-Jul-1997"; /* Implemented from RFC1321 The MD5 Message-Digest Algorithm */ #define INIT_DATA_A (unsigned long)0x67452301L #define INIT_DATA_B (unsigned long)0xefcdab89L #define INIT_DATA_C (unsigned long)0x98badcfeL #define INIT_DATA_D (unsigned long)0x10325476L #ifndef NOPROTO static void md5_block(MD5_CTX *c, unsigned long *p); #else static void md5_block(); #endif void MD5_Init(c) MD5_CTX *c; { c->A=INIT_DATA_A; c->B=INIT_DATA_B; c->C=INIT_DATA_C; c->D=INIT_DATA_D; c->Nl=0; c->Nh=0; c->num=0; } void MD5_Update(c, data, len) MD5_CTX *c; const register unsigned char *data; unsigned long len; { register ULONG *p; int sw,sc; ULONG l; if (len == 0) return; l=(c->Nl+(len<<3))&0xffffffffL; /* 95-05-24 eay Fixed a bug with the overflow handling, thanks to * Wei Dai for pointing it out. */ if (l < c->Nl) /* overflow */ c->Nh++; c->Nh+=(len>>29); c->Nl=l; if (c->num != 0) { p=c->data; sw=c->num>>2; sc=c->num&0x03; if ((c->num+len) >= MD5_CBLOCK) { l= p[sw]; p_c2l(data,l,sc); p[sw++]=l; for (; swnum); md5_block(c,p); c->num=0; /* drop through and do the rest */ } else { int ew,ec; c->num+=(int)len; if ((sc+len) < 4) /* ugly, add char's to a word */ { l= p[sw]; p_c2l_p(data,l,sc,len); p[sw]=l; } else { ew=(c->num>>2); ec=(c->num&0x03); l= p[sw]; p_c2l(data,l,sc); p[sw++]=l; for (; sw < ew; sw++) { c2l(data,l); p[sw]=l; } if (ec) { c2l_p(data,l,ec); p[sw]=l; } } return; } } /* we now can process the input data in blocks of MD5_CBLOCK * chars and save the leftovers to c->data. */ p=c->data; while (len >= MD5_CBLOCK) { #if defined(L_ENDIAN) || defined(B_ENDIAN) memcpy(p,data,MD5_CBLOCK); data+=MD5_CBLOCK; #ifdef B_ENDIAN for (sw=(MD5_LBLOCK/4); sw; sw--) { Endian_Reverse32(p[0]); Endian_Reverse32(p[1]); Endian_Reverse32(p[2]); Endian_Reverse32(p[3]); p+=4; } #endif #else for (sw=(MD5_LBLOCK/4); sw; sw--) { c2l(data,l); *(p++)=l; c2l(data,l); *(p++)=l; c2l(data,l); *(p++)=l; c2l(data,l); *(p++)=l; } #endif p=c->data; md5_block(c,p); len-=MD5_CBLOCK; } sc=(int)len; c->num=sc; if (sc) { sw=sc>>2; /* words to copy */ #ifdef L_ENDIAN p[sw]=0; memcpy(p,data,sc); #else sc&=0x03; for ( ; sw; sw--) { c2l(data,l); *(p++)=l; } c2l_p(data,l,sc); *p=l; #endif } } static void md5_block(c, X) MD5_CTX *c; register ULONG *X; { register ULONG A,B,C,D; A=c->A; B=c->B; C=c->C; D=c->D; /* Round 0 */ LOCL_R0(A,B,C,D,X[ 0], 7,0xd76aa478L); LOCL_R0(D,A,B,C,X[ 1],12,0xe8c7b756L); LOCL_R0(C,D,A,B,X[ 2],17,0x242070dbL); LOCL_R0(B,C,D,A,X[ 3],22,0xc1bdceeeL); LOCL_R0(A,B,C,D,X[ 4], 7,0xf57c0fafL); LOCL_R0(D,A,B,C,X[ 5],12,0x4787c62aL); LOCL_R0(C,D,A,B,X[ 6],17,0xa8304613L); LOCL_R0(B,C,D,A,X[ 7],22,0xfd469501L); LOCL_R0(A,B,C,D,X[ 8], 7,0x698098d8L); LOCL_R0(D,A,B,C,X[ 9],12,0x8b44f7afL); LOCL_R0(C,D,A,B,X[10],17,0xffff5bb1L); LOCL_R0(B,C,D,A,X[11],22,0x895cd7beL); LOCL_R0(A,B,C,D,X[12], 7,0x6b901122L); LOCL_R0(D,A,B,C,X[13],12,0xfd987193L); LOCL_R0(C,D,A,B,X[14],17,0xa679438eL); LOCL_R0(B,C,D,A,X[15],22,0x49b40821L); /* Round 1 */ LOCL_R1(A,B,C,D,X[ 1], 5,0xf61e2562L); LOCL_R1(D,A,B,C,X[ 6], 9,0xc040b340L); LOCL_R1(C,D,A,B,X[11],14,0x265e5a51L); LOCL_R1(B,C,D,A,X[ 0],20,0xe9b6c7aaL); LOCL_R1(A,B,C,D,X[ 5], 5,0xd62f105dL); LOCL_R1(D,A,B,C,X[10], 9,0x02441453L); LOCL_R1(C,D,A,B,X[15],14,0xd8a1e681L); LOCL_R1(B,C,D,A,X[ 4],20,0xe7d3fbc8L); LOCL_R1(A,B,C,D,X[ 9], 5,0x21e1cde6L); LOCL_R1(D,A,B,C,X[14], 9,0xc33707d6L); LOCL_R1(C,D,A,B,X[ 3],14,0xf4d50d87L); LOCL_R1(B,C,D,A,X[ 8],20,0x455a14edL); LOCL_R1(A,B,C,D,X[13], 5,0xa9e3e905L); LOCL_R1(D,A,B,C,X[ 2], 9,0xfcefa3f8L); LOCL_R1(C,D,A,B,X[ 7],14,0x676f02d9L); LOCL_R1(B,C,D,A,X[12],20,0x8d2a4c8aL); /* Round 2 */ LOCL_R2(A,B,C,D,X[ 5], 4,0xfffa3942L); LOCL_R2(D,A,B,C,X[ 8],11,0x8771f681L); LOCL_R2(C,D,A,B,X[11],16,0x6d9d6122L); LOCL_R2(B,C,D,A,X[14],23,0xfde5380cL); LOCL_R2(A,B,C,D,X[ 1], 4,0xa4beea44L); LOCL_R2(D,A,B,C,X[ 4],11,0x4bdecfa9L); LOCL_R2(C,D,A,B,X[ 7],16,0xf6bb4b60L); LOCL_R2(B,C,D,A,X[10],23,0xbebfbc70L); LOCL_R2(A,B,C,D,X[13], 4,0x289b7ec6L); LOCL_R2(D,A,B,C,X[ 0],11,0xeaa127faL); LOCL_R2(C,D,A,B,X[ 3],16,0xd4ef3085L); LOCL_R2(B,C,D,A,X[ 6],23,0x04881d05L); LOCL_R2(A,B,C,D,X[ 9], 4,0xd9d4d039L); LOCL_R2(D,A,B,C,X[12],11,0xe6db99e5L); LOCL_R2(C,D,A,B,X[15],16,0x1fa27cf8L); LOCL_R2(B,C,D,A,X[ 2],23,0xc4ac5665L); /* Round 3 */ LOCL_R3(A,B,C,D,X[ 0], 6,0xf4292244L); LOCL_R3(D,A,B,C,X[ 7],10,0x432aff97L); LOCL_R3(C,D,A,B,X[14],15,0xab9423a7L); LOCL_R3(B,C,D,A,X[ 5],21,0xfc93a039L); LOCL_R3(A,B,C,D,X[12], 6,0x655b59c3L); LOCL_R3(D,A,B,C,X[ 3],10,0x8f0ccc92L); LOCL_R3(C,D,A,B,X[10],15,0xffeff47dL); LOCL_R3(B,C,D,A,X[ 1],21,0x85845dd1L); LOCL_R3(A,B,C,D,X[ 8], 6,0x6fa87e4fL); LOCL_R3(D,A,B,C,X[15],10,0xfe2ce6e0L); LOCL_R3(C,D,A,B,X[ 6],15,0xa3014314L); LOCL_R3(B,C,D,A,X[13],21,0x4e0811a1L); LOCL_R3(A,B,C,D,X[ 4], 6,0xf7537e82L); LOCL_R3(D,A,B,C,X[11],10,0xbd3af235L); LOCL_R3(C,D,A,B,X[ 2],15,0x2ad7d2bbL); LOCL_R3(B,C,D,A,X[ 9],21,0xeb86d391L); c->A+=A&0xffffffffL; c->B+=B&0xffffffffL; c->C+=C&0xffffffffL; c->D+=D&0xffffffffL; } void MD5_Final(md, c) unsigned char *md; MD5_CTX *c; { register int i,j; register ULONG l; register ULONG *p; static unsigned char end[4]={0x80,0x00,0x00,0x00}; unsigned char *cp=end; /* c->num should definitely have room for at least one more byte. */ p=c->data; j=c->num; i=j>>2; /* purify often complains about the following line as an * Uninitialized Memory Read. While this can be true, the * following p_c2l macro will reset l when that case is true. * This is because j&0x03 contains the number of 'valid' bytes * already in p[i]. If and only if j&0x03 == 0, the UMR will * occur but this is also the only time p_c2l will do * l= *(cp++) instead of l|= *(cp++) * Many thanks to Alex Tang for pickup this * 'potential bug' */ #ifdef PURIFY if ((j&0x03) == 0) p[i]=0; #endif l=p[i]; p_c2l(cp,l,j&0x03); p[i]=l; i++; /* i is the next 'undefined word' */ if (c->num >= MD5_LAST_BLOCK) { for (; iNl; p[MD5_LBLOCK-1]=c->Nh; md5_block(c,p); cp=md; l=c->A; l2c(l,cp); l=c->B; l2c(l,cp); l=c->C; l2c(l,cp); l=c->D; l2c(l,cp); /* clear stuff, md5_block may be leaving some stuff on the stack * but I'm not worried :-) */ c->num=0; /* memset((char *)&c,0,sizeof(c));*/ } #ifdef undef int printit(l) unsigned long *l; { int i,ii; for (i=0; i<2; i++) { for (ii=0; ii<8; ii++) { fprintf(stderr,"%08lx ",l[i*8+ii]); } fprintf(stderr,"\n"); } } #endif #endif /* USE_MD5 */ dhcp-4.2.4/dst/md5_locl.h000644 000765 000024 00000016740 11301372615 015037 0ustar00sarstaff000000 000000 /* crypto/md/md5_locl.h */ /* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com) * All rights reserved. * * This package is an SSL implementation written * by Eric Young (eay@cryptsoft.com). * The implementation was written so as to conform with Netscapes SSL. * * This library is free for commercial and non-commercial use as long as * the following conditions are aheared to. The following conditions * apply to all code found in this distribution, be it the RC4, RSA, * lhash, DES, etc., code; not just the SSL code. The SSL documentation * included with this distribution is covered by the same copyright terms * except that the holder is Tim Hudson (tjh@cryptsoft.com). * * Copyright remains Eric Young's, and as such any Copyright notices in * the code are not to be removed. * If this package is used in a product, Eric Young should be given attribution * as the author of the parts of the library used. * This can be in the form of a textual message at program startup or * in documentation (online or textual) provided with the package. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * "This product includes cryptographic software written by * Eric Young (eay@cryptsoft.com)" * The word 'cryptographic' can be left out if the rouines from the library * being used are not cryptographic related :-). * 4. If you include any Windows specific code (or a derivative thereof) from * the apps directory (application code) you must include an acknowledgement: * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" * * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * The licence and distribution terms for any publically available version or * derivative of this code cannot be changed. i.e. this code cannot simply be * copied and put under another distribution licence * [including the GNU Public Licence.] */ /* * Portions Copyright (c) 2007,2009 by Internet Systems Consortium, Inc. ("ISC") * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ */ #include #include #include "md5.h" #define ULONG unsigned long #define UCHAR unsigned char #define UINT unsigned int #if defined(NOCONST) #define const #endif #undef c2l #define c2l(c,l) (l = ((unsigned long)(*((c)++))) , \ l|=(((unsigned long)(*((c)++)))<< 8), \ l|=(((unsigned long)(*((c)++)))<<16), \ l|=(((unsigned long)(*((c)++)))<<24)) #undef p_c2l #define p_c2l(c,l,n) { \ switch (n) { \ case 0: l =((unsigned long)(*((c)++))); \ case 1: l|=((unsigned long)(*((c)++)))<< 8; \ case 2: l|=((unsigned long)(*((c)++)))<<16; \ case 3: l|=((unsigned long)(*((c)++)))<<24; \ } \ } /* NOTE the pointer is not incremented at the end of this */ #undef c2l_p #define c2l_p(c,l,n) { \ l=0; \ (c)+=n; \ switch (n) { \ case 3: l =((unsigned long)(*(--(c))))<<16; \ case 2: l|=((unsigned long)(*(--(c))))<< 8; \ case 1: l|=((unsigned long)(*(--(c)))) ; \ } \ } #undef p_c2l_p #define p_c2l_p(c,l,sc,len) { \ switch (sc) \ { \ case 0: l =((unsigned long)(*((c)++))); \ if (--len == 0) break; \ case 1: l|=((unsigned long)(*((c)++)))<< 8; \ if (--len == 0) break; \ case 2: l|=((unsigned long)(*((c)++)))<<16; \ } \ } #undef l2c #define l2c(l,c) (*((c)++)=(unsigned char)(((l) )&0xff), \ *((c)++)=(unsigned char)(((l)>> 8)&0xff), \ *((c)++)=(unsigned char)(((l)>>16)&0xff), \ *((c)++)=(unsigned char)(((l)>>24)&0xff)) /* NOTE - c is not incremented as per l2c */ #undef l2cn #define l2cn(l1,l2,c,n) { \ c+=n; \ switch (n) { \ case 8: *(--(c))=(unsigned char)(((l2)>>24)&0xff); \ case 7: *(--(c))=(unsigned char)(((l2)>>16)&0xff); \ case 6: *(--(c))=(unsigned char)(((l2)>> 8)&0xff); \ case 5: *(--(c))=(unsigned char)(((l2) )&0xff); \ case 4: *(--(c))=(unsigned char)(((l1)>>24)&0xff); \ case 3: *(--(c))=(unsigned char)(((l1)>>16)&0xff); \ case 2: *(--(c))=(unsigned char)(((l1)>> 8)&0xff); \ case 1: *(--(c))=(unsigned char)(((l1) )&0xff); \ } \ } /* A nice byte order reversal from Wei Dai */ #if defined(WIN32) /* 5 instructions with rotate instruction, else 9 */ #define Endian_Reverse32(a) \ { \ unsigned long l=(a); \ (a)=((ROTATE(l,8)&0x00FF00FF)|(ROTATE(l,24)&0xFF00FF00)); \ } #else /* 6 instructions with rotate instruction, else 8 */ #define Endian_Reverse32(a) \ { \ unsigned long l=(a); \ l=(((l&0xFF00FF00)>>8L)|((l&0x00FF00FF)<<8L)); \ (a)=ROTATE(l,16L); \ } #endif /* #define F(x,y,z) (((x) & (y)) | ((~(x)) & (z))) #define G(x,y,z) (((x) & (z)) | ((y) & (~(z)))) */ /* As pointed out by Wei Dai , the above can be * simplified to the code below. Wei attributes these optimizations * to Peter Gutmann's SHS code, and he attributes it to Rich Schroeppel. */ #define F(x,y,z) ((((y) ^ (z)) & (x)) ^ (z)) #define G(x,y,z) ((((x) ^ (y)) & (z)) ^ (y)) #define H(x,y,z) ((x) ^ (y) ^ (z)) #define I(x,y,z) (((x) | (~(z))) ^ (y)) #undef ROTATE #if defined(WIN32) #define ROTATE(a,n) _lrotl(a,n) #else #define ROTATE(a,n) (((a)<<(n))|(((a)&0xffffffff)>>(32-(n)))) #endif #define LOCL_R0(a,b,c,d,k,s,t) { \ a+=((k)+(t)+F((b),(c),(d))); \ a=ROTATE(a,s); \ a+=b; };\ #define LOCL_R1(a,b,c,d,k,s,t) { \ a+=((k)+(t)+G((b),(c),(d))); \ a=ROTATE(a,s); \ a+=b; }; #define LOCL_R2(a,b,c,d,k,s,t) { \ a+=((k)+(t)+H((b),(c),(d))); \ a=ROTATE(a,s); \ a+=b; }; #define LOCL_R3(a,b,c,d,k,s,t) { \ a+=((k)+(t)+I((b),(c),(d))); \ a=ROTATE(a,s); \ a+=b; }; dhcp-4.2.4/dst/prandom.c000644 000765 000024 00000064406 11726364513 015007 0ustar00sarstaff000000 000000 #ifndef LINT static const char rcsid[] = "$Header: /proj/cvs/prod/DHCP/dst/prandom.c,v 1.8.6.2 2012-03-09 11:28:11 tomasz Exp $"; #endif /* * Portions Copyright (c) 2007,2009,2012 by Internet Systems Consortium, Inc. ("ISC") * Portions Copyright (c) 1995-1998 by Trusted Information Systems, Inc. * * Permission to use, copy modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND TRUSTED INFORMATION SYSTEMS * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL * TRUSTED INFORMATION SYSTEMS BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION * WITH THE USE OR PERFORMANCE OF THE SOFTWARE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #define NEED_PRAND_CONF #include "cdefs.h" #include "osdep.h" #include "dst_internal.h" #include "arpa/nameser.h" #ifndef DST_NUM_HASHES #define DST_NUM_HASHES 4 #endif #ifndef DST_NUMBER_OF_COUNTERS #define DST_NUMBER_OF_COUNTERS 5 /* 32 * 5 == 160 == SHA(1) > MD5 */ #endif /* * the constant below is a prime number to make fixed data structures like * stat and time wrap over blocks. This adds certain randomness to what is * in each digested block. * The prime number 2879 has the special property that when * divided by 2,4 and 6 the result is also a prime numbers */ #ifndef DST_RANDOM_BLOCK_SIZE #define DST_RANDOM_BLOCK_SIZE 2879 #endif /* * This constant dictates how many bits we shift to the right before using a */ #ifndef DST_SHIFT #define DST_SHIFT 9 #endif /* * An initializer that is as bad as any other with half the bits set */ #ifndef DST_RANDOM_PATTERN #define DST_RANDOM_PATTERN 0x8765CA93 #endif /* * things must have changed in the last 3600 seconds to be used */ #define MAX_OLD 3600 /* * Define a single set of configuration for prand stuff. A superset * works okay (failed commands return no data, missing directories * are skipped, and so on. */ static const char *cmds[] = { "/usr/bin/netstat -an 2>&1", "/usr/sbin/netstat -an 2>&1", "/usr/etc/netstat -an 2>&1", "/bin/netstat -an 2>&1", "/usr/ucb/netstat -an 2>&1", /* AIX */ "/bin/ps -ef 2>&1", "/bin/df 2>&1", "/usr/bin/uptime 2>&1", "/usr/bin/printenv 2>&1", "/usr/bin/netstat -s 2>&1", "/usr/bin/w 2>&1", /* Tru64 */ "/usr/bin/dig com. soa +ti=1 +retry=0 2>&1", "/usr/sbin/arp -an 2>&1", "/usr/ucb/uptime 2>&1", "/bin/iostat 2>&1", /* BSD */ "/bin/ps -axlw 2>&1", "/usr/sbin/iostat 2>&1", "/usr/sbin/vmstat 2>&1", /* FreeBSD */ "/usr/bin/vmstat 2>&1", "/usr/bin/w 2>&1", /* HP/UX */ "/usr/bin/ps -ef 2>&1", /* IRIX */ "/usr/etc/arp -a 2>&1", "/usr/bsd/uptime 2>&1", "/usr/bin/printenv 2>&1", "/usr/bsd/w 2>&1", /* Linux */ "/sbin/arp -an 2>&1", "/usr/bin/vmstat 2>&1", /* NetBSD */ /* OpenBSD */ /* QNX */ "/bin/ps -a 2>&1", "/bin/sin 2>&1", "/bin/sin fds 2>&1", "/bin/sin memory 2>&1", /* Solaris */ "/usr/ucb/uptime 2>&1", "/usr/ucb/netstat -an 2>&1", "/usr/bin/netstat -an 2>&1", "/usr/sbin/netstat -an 2>&1", "/usr/etc/netstat -an 2>&1", "/bin/netstat -an 2>&1", "/usr/ucb/netstat -an 2>&1", NULL }; static const char *dirs[] = { "/tmp", "/var/tmp", ".", "/", "/var/spool", "/var/adm", "/dev", "/var/spool/mail", "/var/mail", "/home", "/usr/home", NULL }; static const char *files[] = { "/var/adm/messages", "/var/adm/wtmp", "/var/adm/lastlog", "/var/log/messages", "/var/log/wtmp", "/var/log/lastlog", "/proc/stat", "/proc/rtc", "/proc/meminfo", "/proc/interrupts", "/proc/self/status", "/proc/ipstats", "/proc/dumper", "/proc/self/as", NULL }; /* * these two data structure are used to process input data into digests, * * The first structure contains a pointer to a DST HMAC key * the variables accompanying are used for * step : select every step byte from input data for the hash * block: number of data elements going into each hash * digested: number of data elements digested so far * curr: offset into the next input data for the first byte. */ typedef struct hash { DST_KEY *key; void *ctx; int digested, block, step, curr; } prand_hash; /* * This data structure controls number of hashes and keeps track of * overall progress in generating correct number of bytes of output. * output : array to store the output data in * needed : how many bytes of output are needed * filled : number of bytes in output so far. * bytes : total number of bytes processed by this structure * file_digest : the HMAC key used to digest files. */ typedef struct work { unsigned needed, filled, bytes; u_char *output; prand_hash *hash[DST_NUM_HASHES]; DST_KEY *file_digest; } dst_work; /* * forward function declarations */ static int get_dev_random(u_char *output, unsigned size); static int do_time(dst_work *work); static int do_ls(dst_work *work); static int unix_cmd(dst_work *work); static int digest_file(dst_work *work); static void force_hash(dst_work *work, prand_hash *hash); static int do_hash(dst_work *work, prand_hash *hash, const u_char *input, unsigned size); static int my_digest(dst_work *tmp, const u_char *input, unsigned size); static prand_hash *get_hmac_key(int step, int block); static unsigned own_random(dst_work *work); /* * variables used in the quick random number generator */ static u_int32_t ran_val = DST_RANDOM_PATTERN; static u_int32_t ran_cnt = (DST_RANDOM_PATTERN >> 10); /* * setting the quick_random generator to particular values or if both * input parameters are 0 then set it to initial values */ void dst_s_quick_random_set(u_int32_t val, u_int32_t cnt) { ran_val = (val == 0) ? DST_RANDOM_PATTERN : val; ran_cnt = (cnt == 0) ? (DST_RANDOM_PATTERN >> 10) : cnt; } /* * this is a quick and random number generator that seems to generate quite * good distribution of data */ u_int32_t dst_s_quick_random(int inc) { ran_val = ((ran_val >> 13) ^ (ran_val << 19)) ^ ((ran_val >> 7) ^ (ran_val << 25)); if (inc > 0) /* only increasing values accepted */ ran_cnt += inc; ran_val += ran_cnt++; return (ran_val); } /* * get_dev_random: Function to read /dev/random reliably * this function returns how many bytes where read from the device. * port_after.h should set the control variable HAVE_DEV_RANDOM */ static int get_dev_random(u_char *output, unsigned size) { #ifdef HAVE_DEV_RANDOM struct stat st; int n = 0, fd = -1, s; s = stat("/dev/random", &st); if (s == 0 && S_ISCHR(st.st_mode)) { if ((fd = open("/dev/random", O_RDONLY | O_NONBLOCK)) != -1) { if ((n = read(fd, output, size)) < 0) n = 0; close(fd); } return (n); } #endif return (0); } /* * Portable way of getting the time values if gettimeofday is missing * then compile with -DMISSING_GETTIMEOFDAY time() is POSIX compliant but * gettimeofday() is not. * Time of day is predictable, we are looking for the randomness that comes * the last few bits in the microseconds in the timer are hard to predict when * this is invoked at the end of other operations */ struct timeval *mtime; static int do_time(dst_work *work) { int cnt = 0; static u_char tmp[sizeof(struct timeval) + sizeof(struct timezone)]; struct timezone *zone; zone = (struct timezone *) tmp; mtime = (struct timeval *)(tmp + sizeof(struct timezone)); gettimeofday(mtime, zone); cnt = sizeof(tmp); my_digest(work, tmp, sizeof(tmp)); return (cnt); } /* * this function simulates the ls command, but it uses stat which gives more * information and is harder to guess * Each call to this function will visit the next directory on the list of * directories, in a circular manner. * return value is the number of bytes added to the temp buffer * * do_ls() does not visit subdirectories * if attacker has access to machine it can guess most of the values seen * thus it is important to only visit directories that are frequently updated * Attacker that has access to the network can see network traffic * when NFS mounted directories are accessed and know exactly the data used * but may not know exactly in what order data is used. * Returns the number of bytes that where returned in stat structures */ static int do_ls(dst_work *work) { struct dir_info { uid_t uid; gid_t gid; off_t size; time_t atime, mtime, ctime; }; static struct dir_info dir_info; struct stat buf; struct dirent *entry; static int i = 0; static unsigned long d_round = 0; struct timeval tv; int n = 0, tb_i = 0, out = 0; unsigned dir_len; char file_name[1024]; u_char tmp_buff[1024]; DIR *dir = NULL; if (dirs[i] == NULL) /* if at the end of the list start over */ i = 0; if (stat(dirs[i++], &buf)) /* directory does not exist */ return (0); gettimeofday(&tv,NULL); if (d_round == 0) d_round = tv.tv_sec - MAX_OLD; else if (i==1) /* if starting a new round cut what we accept */ d_round += (tv.tv_sec - d_round)/2; if (buf.st_atime < d_round) return (0); EREPORT(("do_ls i %d filled %4d in_temp %4d\n", i-1, work->filled, work->in_temp)); memcpy(tmp_buff, &buf, sizeof(buf)); tb_i += sizeof(buf); if ((dir = opendir(dirs[i-1])) == NULL)/* open it for read */ return (0); strcpy(file_name, dirs[i-1]); dir_len = strlen(file_name); file_name[dir_len++] = '/'; while ((entry = readdir(dir))) { unsigned len = strlen(entry->d_name); out += len; if (my_digest(work, (u_char *)entry->d_name, len)) break; memcpy(&file_name[dir_len], entry->d_name, len); file_name[dir_len + len] = 0x0; /* for all entries in dir get the stats */ if (stat(file_name, &buf) == 0) { n++; /* count successful stat calls */ /* copy non static fields */ dir_info.uid += buf.st_uid; dir_info.gid += buf.st_gid; dir_info.size += buf.st_size; dir_info.atime += buf.st_atime; dir_info.mtime += buf.st_mtime; dir_info.ctime += buf.st_ctime; out += sizeof(dir_info); if(my_digest(work, (u_char *)&dir_info, sizeof(dir_info))) break; } } closedir(dir); /* done */ out += do_time(work); /* add a time stamp */ return (out); } /* * unix_cmd() * this function executes the a command from the cmds[] list of unix commands * configured in the prand_conf.h file * return value is the number of bytes added to the randomness temp buffer * * it returns the number of bytes that where read in * if more data is needed at the end time is added to the data. * This function maintains a state to selects the next command to run * returns the number of bytes read in from the command */ static int unix_cmd(dst_work *work) { static int cmd_index = 0; int cnt = 0, n; FILE *pipe; u_char buffer[4096]; if (cmds[cmd_index] == NULL) cmd_index = 0; EREPORT(("unix_cmd() i %d filled %4d in_temp %4d\n", cmd_index, work->filled, work->in_temp)); pipe = popen(cmds[cmd_index++], "r"); /* execute the command */ while ((n = fread(buffer, sizeof(char), sizeof(buffer), pipe)) > 0) { cnt += n; /* process the output */ if (my_digest(work, buffer, (unsigned)n)) break; /* this adds some randomness to the output */ cnt += do_time(work); } while ((n = fread(buffer, sizeof(char), sizeof(buffer), pipe)) > 0) ; /* drain the pipe */ pclose(pipe); return (cnt); /* read how many bytes where read in */ } /* * digest_file() This function will read a file and run hash over it * input is a file name */ static int digest_file(dst_work *work) { static int f_cnt = 0; static unsigned long f_round = 0; FILE *fp; void *ctx; const char *name; int no, i; struct stat st; struct timeval tv; u_char buf[1024]; if (f_round == 0 || files[f_cnt] == NULL || work->file_digest == NULL) if (gettimeofday(&tv, NULL)) /* only do this if needed */ return (0); if (f_round == 0) /* first time called set to one hour ago */ f_round = (tv.tv_sec - MAX_OLD); name = files[f_cnt++]; if (files[f_cnt] == NULL) { /* end of list of files */ if(f_cnt <= 1) /* list is too short */ return (0); f_cnt = 0; /* start again on list */ f_round += (tv.tv_sec - f_round)/2; /* set new cutoff */ work->file_digest = dst_free_key(work->file_digest); } if (work->file_digest == NULL) { work->file_digest = dst_buffer_to_key("", KEY_HMAC_MD5, 0, 0, (u_char *)&tv, sizeof(tv)); if (work->file_digest == NULL) return (0); } if (access(name, R_OK) || stat(name, &st)) return (0); /* no such file or not allowed to read it */ if (strncmp(name, "/proc/", 6) && st.st_mtime < f_round) return(0); /* file has not changed recently enough */ if (dst_sign_data(SIG_MODE_INIT, work->file_digest, &ctx, NULL, 0, NULL, 0)) { work->file_digest = dst_free_key(work->file_digest); return (0); } if ((fp = fopen(name, "r")) == NULL) return (0); for (no = 0; (i = fread(buf, sizeof(*buf), sizeof(buf), fp)) > 0; no += i) dst_sign_data(SIG_MODE_UPDATE, work->file_digest, &ctx, buf, (unsigned)i, NULL, 0); fclose(fp); if (no >= 64) { i = dst_sign_data(SIG_MODE_FINAL, work->file_digest, &ctx, NULL, 0, &work->output[work->filled], DST_HASH_SIZE); if (i > 0) work->filled += i; } else if (i > 0) my_digest(work, buf, (unsigned)i); my_digest(work, (const u_char *)name, strlen(name)); return (no + strlen(name)); } /* * function to perform the FINAL and INIT operation on a hash if allowed */ static void force_hash(dst_work *work, prand_hash *hash) { int i = 0; /* * if more than half a block then add data to output * otherwise add the digest to the next hash */ if ((hash->digested * 2) > hash->block) { i = dst_sign_data(SIG_MODE_FINAL, hash->key, &hash->ctx, NULL, 0, &work->output[work->filled], DST_HASH_SIZE); hash->digested = 0; dst_sign_data(SIG_MODE_INIT, hash->key, &hash->ctx, NULL, 0, NULL, 0); if (i > 0) work->filled += i; } return; } /* * This function takes the input data does the selection of data specified * by the hash control block. * The step variable in the work structure determines which 1/step bytes * are used, * */ static int do_hash(dst_work *work, prand_hash *hash, const u_char *input, unsigned size) { const u_char *tmp = input; u_char *tp, *abuf = (u_char *)0; int i, n; unsigned needed, avail, dig, cnt = size; unsigned tmp_size = 0; if (cnt <= 0 || input == NULL) return (0); if (hash->step > 1) { /* if using subset of input data */ tmp_size = size / hash->step + 2; abuf = tp = malloc(tmp_size); tmp = tp; for (cnt = 0, i = hash->curr; i < size; i += hash->step, cnt++) *(tp++) = input[i]; /* calculate the starting point in the next input set */ hash->curr = (hash->step - (i - size)) % hash->step; } /* digest the data in block sizes */ for (n = 0; n < cnt; n += needed) { avail = (cnt - n); needed = hash->block - hash->digested; dig = (avail < needed) ? avail : needed; dst_sign_data(SIG_MODE_UPDATE, hash->key, &hash->ctx, &tmp[n], dig, NULL, 0); hash->digested += dig; if (hash->digested >= hash->block) force_hash(work, hash); if (work->needed < work->filled) { if (abuf) SAFE_FREE2(abuf, tmp_size); return (1); } } if (tmp_size > 0) SAFE_FREE2(abuf, tmp_size); return (0); } /* * Copy data from INPUT for length SIZE into the work-block TMP. * If we fill the work-block, digest it; then, * if work-block needs more data, keep filling with the rest of the input. */ static int my_digest(dst_work *work, const u_char *input, unsigned size) { int i, full = 0; static unsigned counter; counter += size; /* first do each one of the hashes */ for (i = 0; i < DST_NUM_HASHES && full == 0; i++) full = do_hash(work, work->hash[i], input, size) + do_hash(work, work->hash[i], (u_char *) &counter, sizeof(counter)); /* * if enough data has be generated do final operation on all hashes * that have enough date for that */ for (i = 0; full && (i < DST_NUM_HASHES); i++) force_hash(work, work->hash[i]); return (full); } /* * this function gets some semi random data and sets that as an HMAC key * If we get a valid key this function returns that key initialized * otherwise it returns NULL; */ static prand_hash * get_hmac_key(int step, int block) { u_char *buff; int temp = 0, n = 0; unsigned size = 70; DST_KEY *new_key = NULL; prand_hash *new = NULL; /* use key that is larger than digest algorithms (64) for key size */ buff = malloc(size); if (buff == NULL) return (NULL); /* do not memset the allocated memory to get random bytes there */ /* time of day is somewhat random especially in the last bytes */ gettimeofday((struct timeval *) &buff[n], NULL); n += sizeof(struct timeval); /* get some semi random stuff in here stir it with micro seconds */ if (n < size) { temp = dst_s_quick_random((int) buff[n - 1]); memcpy(&buff[n], &temp, sizeof(temp)); n += sizeof(temp); } /* get the pid of this process and its parent */ if (n < size) { temp = (int) getpid(); memcpy(&buff[n], &temp, sizeof(temp)); n += sizeof(temp); } if (n < size) { temp = (int) getppid(); memcpy(&buff[n], &temp, sizeof(temp)); n += sizeof(temp); } /* get the user ID */ if (n < size) { temp = (int) getuid(); memcpy(&buff[n], &temp, sizeof(temp)); n += sizeof(temp); } #ifndef GET_HOST_ID_MISSING if (n < size) { temp = (int) gethostid(); memcpy(&buff[n], &temp, sizeof(temp)); n += sizeof(temp); } #endif /* get some more random data */ if (n < size) { temp = dst_s_quick_random((int) buff[n - 1]); memcpy(&buff[n], &temp, sizeof(temp)); n += sizeof(temp); } /* covert this into a HMAC key */ new_key = dst_buffer_to_key("", KEY_HMAC_MD5, 0, 0, buff, size); SAFE_FREE(buff); /* get the control structure */ if ((new = malloc(sizeof(prand_hash))) == NULL) return (NULL); new->digested = new->curr = 0; new->step = step; new->block = block; new->key = new_key; if (dst_sign_data(SIG_MODE_INIT, new_key, &new->ctx, NULL, 0, NULL, 0)) return (NULL); return (new); } /* * own_random() * This function goes out and from various sources tries to generate enough * semi random data that a hash function can generate a random data. * This function will iterate between the two main random source sources, * information from programs and directories in random order. * This function return the number of bytes added to the random output buffer. */ static unsigned own_random(dst_work *work) { int dir = 0, b; int bytes, n, cmd = 0, dig = 0; /* * now get the initial seed to put into the quick random function from * the address of the work structure */ bytes = (int) getpid(); /* * proceed while needed */ while (work->filled < work->needed) { EREPORT(("own_random r %08x b %6d t %6d f %6d\n", ran_val, bytes, work->in_temp, work->filled)); /* pick a random number in the range of 0..7 based on that random number * perform some operations that yield random data */ n = (dst_s_quick_random(bytes) >> DST_SHIFT) & 0x07; switch (n) { case 0: case 3: if (sizeof(cmds) > 2 *sizeof(*cmds)) { b = unix_cmd(work); cmd += b; } break; case 1: case 7: if (sizeof(dirs) > 2 *sizeof(*dirs)) { b = do_ls(work); dir += b; } break; case 4: case 5: /* retry getting data from /dev/random */ b = get_dev_random(&work->output[work->filled], work->needed - work->filled); if (b > 0) work->filled += b; break; case 6: if (sizeof(files) > 2 * sizeof(*files)) { b = digest_file(work); dig += b; } break; case 2: default: /* to make sure we make some progress */ work->output[work->filled++] = 0xff & dst_s_quick_random(bytes); b = 1; break; } if (b > 0) bytes += b; } return (work->filled); } /* * dst_s_random() This function will return the requested number of bytes * of randomness to the caller it will use the best available sources of * randomness. * The current order is to use /dev/random, precalculated randomness, and * finally use some system calls and programs to generate semi random data * that is then digested to generate randomness. * This function is thread safe as each thread uses its own context, but * concurrent treads will affect each other as they update shared state * information. * It is strongly recommended that this function be called requesting a size * that is not a multiple of the output of the hash function used. * * If /dev/random is not available this function is not suitable to generate * large amounts of data, rather it is suitable to seed a pseudo-random * generator * Returns the number of bytes put in the output buffer */ int dst_s_random(u_char *output, unsigned size) { int n = 0, i; unsigned s; static u_char old_unused[DST_HASH_SIZE * DST_NUM_HASHES]; static unsigned unused = 0; if (size <= 0 || output == NULL) return (0); if (size >= 2048) return (-1); /* * Read from /dev/random */ n = get_dev_random(output, size); /* * If old data is available and needed use it */ if (n < size && unused > 0) { unsigned need = size - n; if (unused <= need) { memcpy(output, old_unused, unused); n += unused; unused = 0; } else { memcpy(output, old_unused, need); n += need; unused -= need; memcpy(old_unused, &old_unused[need], unused); } } /* * If we need more use the simulated randomness here. */ if (n < size) { dst_work *my_work = (dst_work *) malloc(sizeof(dst_work)); if (my_work == NULL) return (n); my_work->needed = size - n; my_work->filled = 0; my_work->output = (u_char *) malloc(my_work->needed + DST_HASH_SIZE * DST_NUM_HASHES); my_work->file_digest = NULL; if (my_work->output == NULL) return (n); memset(my_work->output, 0x0, my_work->needed); /* allocate upto 4 different HMAC hash functions out of order */ #if DST_NUM_HASHES >= 3 my_work->hash[2] = get_hmac_key(3, DST_RANDOM_BLOCK_SIZE / 2); #endif #if DST_NUM_HASHES >= 2 my_work->hash[1] = get_hmac_key(7, DST_RANDOM_BLOCK_SIZE / 6); #endif #if DST_NUM_HASHES >= 4 my_work->hash[3] = get_hmac_key(5, DST_RANDOM_BLOCK_SIZE / 4); #endif my_work->hash[0] = get_hmac_key(1, DST_RANDOM_BLOCK_SIZE); if (my_work->hash[0] == NULL) /* if failure bail out */ return (n); s = own_random(my_work); /* if more generated than needed store it for future use */ if (s >= my_work->needed) { EREPORT(("dst_s_random(): More than needed %d >= %d\n", s, my_work->needed)); memcpy(&output[n], my_work->output, my_work->needed); n += my_work->needed; /* saving unused data for next time */ unused = s - my_work->needed; memcpy(old_unused, &my_work->output[my_work->needed], unused); } else { /* XXXX This should not happen */ EREPORT(("Not enough %d >= %d\n", s, my_work->needed)); memcpy(&output[n], my_work->output, s); n += my_work->needed; } /* delete the allocated work area */ for (i = 0; i < DST_NUM_HASHES; i++) { dst_free_key(my_work->hash[i]->key); SAFE_FREE(my_work->hash[i]); } SAFE_FREE(my_work->output); SAFE_FREE(my_work); } return (n); } /* * A random number generator that is fast and strong * this random number generator is based on HASHing data, * the input to the digest function is a collection of * counters that is incremented between digest operations * each increment operation amortizes to 2 bits changed in that value * for 5 counters thus the input will amortize to have 10 bits changed * The counters are initially set using the strong random function above * the HMAC key is selected by the same method as the HMAC keys for the * strong random function. * Each set of counters is used for 2^25 operations * * returns the number of bytes written to the output buffer * or negative number in case of error */ int dst_s_semi_random(u_char *output, unsigned size) { static u_int32_t counter[DST_NUMBER_OF_COUNTERS]; static u_char semi_old[DST_HASH_SIZE]; static int semi_loc = 0, cnt = 0; static unsigned hb_size = 0; static DST_KEY *my_key = NULL; prand_hash *hash; unsigned out = 0; unsigned i; int n; if (output == NULL || size <= 0) return (-2); /* check if we need a new key */ if (my_key == NULL || cnt > (1 << 25)) { /* get HMAC KEY */ if (my_key) my_key->dk_func->destroy(my_key); if ((hash = get_hmac_key(1, DST_RANDOM_BLOCK_SIZE)) == NULL) return (0); my_key = hash->key; /* check if the key works stir the new key using some old random data */ hb_size = dst_sign_data(SIG_MODE_ALL, my_key, NULL, (u_char *) counter, sizeof(counter), semi_old, sizeof(semi_old)); if (hb_size <= 0) { EREPORT(("dst_s_semi_random() Sign of alg %d failed %d\n", my_key->dk_alg, hb_size)); return (-1); } /* new set the counters to random values */ dst_s_random((u_char *) counter, sizeof(counter)); cnt = 0; } /* if old data around use it first */ if (semi_loc < hb_size) { if (size <= hb_size - semi_loc) { /* need less */ memcpy(output, &semi_old[semi_loc], size); semi_loc += size; return (size); /* DONE */ } else { out = hb_size - semi_loc; memcpy(output, &semi_old[semi_loc], out); semi_loc += out; } } /* generate more random stuff */ while (out < size) { /* * modify at least one bit by incrementing at least one counter * based on the last bit of the last counter updated update * the next one. * minimally this operation will modify at least 1 bit, * amortized 2 bits */ for (n = 0; n < DST_NUMBER_OF_COUNTERS; n++) i = (int) counter[n]++; i = dst_sign_data(SIG_MODE_ALL, my_key, NULL, (u_char *) counter, hb_size, semi_old, sizeof(semi_old)); if (i != hb_size) EREPORT(("HMAC SIGNATURE FAILURE %d\n", i)); cnt++; if (size - out < i) /* Not all data is needed */ semi_loc = i = size - out; memcpy(&output[out], semi_old, i); out += i; } return (out); } dhcp-4.2.4/doc/api+protocol000644 000765 000024 00000044105 06766041312 015476 0ustar00sarstaff000000 000000 This file documents the protocol that the ISC DHCP server and ISC Object Management clients (clients that use the ISC Object Management API) speak between one another. Protocol: All multi-byte numbers are represented in network byte order. On startup, each side sends a status message indicating what version of the protocol they are speaking. The status message looks like this: +---------+---------+ | version | hlength | +---------+---------+ version - a 32-bit fixed-point number with the decimal point between the third and second decimal digits from the left, representing the version of the protocol. The current protocol version is 1.00. If the field were considered as a 32-bit integer, this would correspond to a value of 100 decimal, or 0x64. hlength - a 32-bit integer representing the length of the fixed-length header in subsequent messages. This is normally 56, but can be changed to a value larger than 56 by either side without upgrading the revision number. The startup message is not authenticated. Either side may reject the other side's startup message as invalid by simply closing the connection. The only fixed part of the startup message is the version number - future versions may delete hlength, or add further startup information. Following the startup message, all messages have the same format. Currently, the format includes a fixed-length header (the length in hlength, above) +--------+----+--------+----+-----+---------+------------+------------+-----+ | authid | op | handle | id | rid | authlen | msg values | obj values | sig | +--------+----+--------+----+-----+---------+------------+------------+-----+ The fixed-length header consists of: authid = a 32-bit authenticator handle. For an original message (one not in response to some other message), this will be chosen by the originator. For a message in response to another message, the authenticator for that message is used, except if the response is an error message indicating that the authenticator used was unknown, in which case the null authenticator is used. Messages that are generated as the result of a notify registration use the authenticator used in the original notify registration. The authenticator itself is generated by having one side of the connection send an object of type "authenticator" to the other side with values that indicate what kind of authentication mechanism to use and what key to use. The two most likely things here are a Kerberos V principal name or the name of a shared secret that can be used to calculate an MD5 hash. The mechanism for doing this has yet to be finalized. If authid is zero, the message is not authenticated. op = 32-bit opcode, one of: open = 1 refresh = 2 update = 3 notify = 4 error = 5 delete = 6 handle = 32-bit object handle A handle on the object being opened, created, refreshed or updated. If no handle is yet available (e.g., with open and new), then the value zero is sent. id = 32-bit transaction id of the message - a monotonically increasing number that starts with some randomly chosen number at the beginning of the life of the connection. The value should never be zero. rid = 32-bit transaction ID of the message to which this message is a response, or zero if this message is not in response to a message from the other side. authlen = a 32-bit number representing the length of the authenticator msg values = a series of name+value pairs, specific to this message. Each name+value pair starts with a 16-bit name length, followed by that many bytes of name, followed by a 32-bit value length, followed by that many bytes of value. If the length is zero, this is a value of the blank string. If the length is all ones (2^32-1), then there is no value - for an update, this means the value for this name and the name itself should be deleted from the object, which may or may not be possible. The list of name/value pairs ends with a zero-length name, which is not followed by a value length/value pair. obj values = a series of name+value pairs, as above, specific to the object being created, updated or refreshed. signature = authlen bytes of data signing the message. The signature algorithm is a property of the authenticator handle. Message types: 1: open relevant input values: object-type = the name of the type of object open:create = boolean - create the object if it doesn't yet exist open:exclusive = boolean - don't open the object if it does exist open:update = boolean - update the object with included values if it matches. the handle should always be the null handle The input value must also contain key information for the type of object being searched that uniquely identifies an object, or search information that matches only one object. Each object has a key specification (a key is something that uniquely identifies an object), so see the key specification for that object to see what to send here. An open message with the create flag set must specify a key, and not merely matching criteria. Some objects may allow more than one key, and it may be that the union of those keys is required to uniquely identify the object, or it may be that any one such key will uniquely identify the object. The documentation for the type of object will specify this. An open message will result in an immediate response message whose opcode will either be "error" or "update". The error message may include an error:reason value containing a text string explaining the error, and will always include an error:code value which will be the numeric error code for what went wrong. Possible error codes are: not found - no such object exists already exists - object already exists, and exclusive flag was set. not unique - more than one object matching the specification exists. permission denied - the authenticator ID specified does not have authorization to access this object, or if the update flag was specified, to update the object. If the response is an update message, the update message will include the object handle and all of the name/value pairs associated with that object. 2: refresh no input values except the handle need be specified. The null handle may not be specified. If the handle is valid, and the authenticator ID specified has permission to examine the object, then an update message will be sent for that object. Otherwise, one of the following errors will be sent: invalid handle - the handle does not refer to a known object permisson denied - the handle refers to an object that the requestor does not have permission to examine. 3: update Requests that the contents of the specified object be updated with the values included. Values that are not specified are not updated. The response will be either an error message or an update-ok message. If rid is nonzero, no response will be generated, even if there was an error. Possible errors include: invalid handle - no such object was found permission denied - the handle refers to an object that the requestor does not have permission to modify. not confirmed - the update could not be committed due to some kind of resource problem, for example insufficient memory or a disk failure. 4: notify Requests that whenever the object with the specified handle is modified, an update be sent. If there is something wrong with the request, an error message will be returned immediately. Otherwise, whenever a change is made to the object, an update message will be sent containing whatever changes were made (or possibly all the values associated with the object, depending on the implementation). Possible errors: invalid handle permission denied - the handle refers to an object that the requestor does not have permission to examine. not supported - the object implementation does not support notifications 5: status Sends a status code in response to a message. Always sent in response to a message sent by the other side. There should never be a response to this message. 6: delete Deletes the specified object. Response will be either request-ok, or error. Possible errors include: invalid handle - no such object was found permission denied - the handle refers to an object that the requestor does not have permission to modify. not confirmed - the deletion could not be committed due to some kind of resource problem, for example insufficient memory or a disk failure. 7: notify-cancel Like notify, but requests that an existing notification be cancelled. 8: notify-cancelled Indicates that because of a local change, a notification that had been registered can no longer be performed. This could be as a result of the permissions on a object changing, or an object being deleted. There should never be a response to this message. internals: Both client and server use same protocol and infrastructure. There are many object types, each of which is stored in a registry. Objects whose type is not recognized can either be handled by the generic object type, which is registered with the type "*". If no generic object type is registered, then objects with unknown types are simply not supported. On the client, there are probably no special object handlers (although this is by no means forbidden). On the server, probably everything is a special object. Each object type has the following methods: dhcpctl_status dhcpctl_connect (dhcpctl_handle *connection, char *server_name, int port, dhcpctl_handle *authinfo) synchronous returns nonzero status code if it didn't connect, zero otherwise stores connection handle through connection, which can be used for subsequent access to the specified server. server_name is the name of the server, and port is the TCP port on which it is listening. authinfo is the handle to an object containing authentication information. dhcpctl_status dhcpctl_open_object (dhcpctl_handle h, dhcpctl_handle connection, int flags) asynchronous - just queues the request returns nonzero status code if open couldn't be queued returns zero if open was queued h is a handle to an object created by dhcpctl_new_object connection is a connection to a DHCP server flags include: DHCPCTL_CREATE - if the object doesn't exist, create it DHCPCTL_UPDATE - update the object on the server using the attached parameters DHCPCTL_EXCL - error if the object exists and DHCPCTL_CREATE was also specified dhcpctl_status dhcpctl_new_object (dhcpctl_handle *h, dhcpctl_handle connection, char *object_type) synchronous - creates a local handle for a host entry. returns nonzero status code if the local host entry couldn't be created stores handle to host through h if successful, and returns zero. object_type is a pointer to a NUL-terminated string containing the ascii name of the type of object being accessed - e.g., "host" dhcpctl_status dhcpctl_set_callback (dhcpctl_handle h, void *data, void (*callback) (dhcpctl_handle, dhcpctl_status, void *)) synchronous, with asynchronous aftereffect handle is some object upon which some kind of process has been started - e.g., an open, an update or a refresh. data is an anonymous pointer containing some information that the callback will use to figure out what event completed. return value of 0 means callback was successfully set, a nonzero status code is returned otherwise. Upon completion of whatever task is in process, the callback will be passed the handle to the object, a status code indicating what happened, and the anonymous pointer passed to dhcpctl_status dhcpctl_wait_for_completion (dhcpctl_handle h, dhcpctl_status *s) synchronous returns zero if the callback completes, a nonzero status if there was some problem relating to the wait operation. The status of the queued request will be stored through s, and will also be either zero for success or nonzero for some kind of failure. Never returns until completion or until the connection to the server is lost. This performs the same function as dhcpctl_set_callback and the subsequent callback, for programs that want to do inline execution instead of using callbacks. dhcpctl_status dhcpctl_get_value (data_string *result, dhcpctl_handle h, char *value_name) synchronous returns zero if the call succeeded, a nonzero status code if it didn't. result is the address of an empty data string (initialized with bzero or cleared with data_string_forget). On successful completion, the addressed data string will contain the value that was fetched. dhcpctl_handle refers to some dhcpctl item value_name refers to some value related to that item - e.g., for a handle associated with a completed host lookup, value could be one of "hardware-address", "dhcp-client-identifier", "known" or "client-hostname". dhcpctl_status dhcpctl_get_boolean (int *result, dhcpctl_handle h, char *value_name) like dhcpctl_get_value, but more convenient for boolean values, since no data_string needs to be dealt with. dhcpctl_status dhcpctl_set_value (dhcpctl_handle h, data_string value, char *value_name) Sets a value on an object referred to by a dhcpctl_handle. The opposite of dhcpctl_get_value. Does not update the server - just sets the value on the handle. dhcpctl_status dhcpctl_set_string_value (dhcpctl_handle h, char *value, char *value_name) Sets a NUL-terminated ASCII value on an object referred to by a dhcpctl_handle. like dhcpctl_set_value, but saves the trouble of creating a data_string for a NUL-terminated string. Does not update the server - just sets the value on the handle. dhcpctl_status dhcpctl_set_boolean (dhcpctl_handle h, int value, char *value_name) Sets a boolean value on an object - like dhcpctl_set_value, only more convenient for booleans. dhcpctl_status dhcpctl_object_update (dhcpctl_handle h) Queues an update on the object referenced by the handle (there can't be any other work in progress on the handle). An update means local parameters will be sent to the server. dhcpctl_status dhcpctl_object_refresh (dhcpctl_handle h) Queues an update on the object referenced by the handle (there can't be any other work in progress on the handle). An update means local parameters will be sent to the server. dhcpctl_status dhcpctl_object_delete (dhcpctl_handle h) Queues a delete of the object referenced by the handle (there can't be any other work in progress on the handle). A delete means that the object will be permanently deleted on the remote end, assuming the remote end supports object persistence. So a sample program that would update a host declaration would look something like this: /* Create a local object into which to store authentication information. */ if ((status = dhcpctl_new_object (&auth, dhcpctl_null_handle, "authentication-information"))) dhcpctl_error ("Can't create authentication information: %m"); /* Set up the authenticator with an algorithm type, user name and password. */ if ((status = dhcpctl_set_string_value (&auth, "mellon", "username"))) dhcpctl_error ("Can't set username: %m", status); if ((status = dhcpctl_set_string_value (&auth, "three blind mice", "password"))) dhcpctl_error ("Can't set password: %m", status); if ((status = dhcpctl_set_string_value (&auth, "md5-hash", "algorithm"))) dhcpctl_error ("Can't set authentication algorithm: %m.", status); /* Connect to the server. */ if ((status = dhcpctl_connect (&c, "dhcp.server.com", 612, &auth))) dhcpctl_error ("Can't connect to dhcp.server.com: %m", status); /* Create a host object. */ if ((status = dhcpctl_new_object (&hp, c, "host"))) dhcpctl_error ("Host create failed: %m", status); /* Create a data_string to contain the host's client identifier, and set it. */ if ((status = data_string_create_from_hex (&client_id, "1:08:00:2b:34:1a:c3"))) dhcpctl_error ("Can't create client identifier: %m"); if ((status = dhcpctl_set_value (hp, client_id, "dhcp-client-identifier"))) dhcpctl_error ("Host client identifier set failed."); /* Set the known flag to 1. */ if ((status = dhcpctl_set_boolean (hp, 1, "known"))) dhcpctl_error ("Host known set failed."); /* Open an existing host object that matches the client identifier, and update it from the local context, or if no host entry yet exists matching the identifier, create one and initialize it. */ if ((status = dhcpctl_open_object (&hp, c, DHCPCTL_CREATE | DHCPCTL_UPDATE))) dhcpctl_error ("Can't open host: %m", status); /* Wait for the process to complete, check status. */ if ((status = dhcpctl_wait_for_completion (hp, &wait_status))) dhcpctl_error ("Host create/lookup wait failed: %m", status); if (waitstatus) dhcpctl_error ("Host create/lookup failed: %m", status); The API is a bit complicated, for a couple of reasons. I want to make it general, so that there aren't a bazillion functions to call, one for each data type. I want it to be thread-safe, which is why each function returns a status and the error printer requires a status code for input. I want it to be possible to make it asynchronous, so that it can work in tandem with, for example, an X toolkit. If you're just writing a simple update cgi program, you probably won't want to bother to use the asynchronous callbacks, and indeed the above example doesn't. I glossed over data strings above - basically, they're objects with a pointer to a reference-counted buffer structure, an offset into that buffer, and a length. These are used within the DHCP server, so you can get an idea of how they work - basically, they're a convenient and efficient way to store a string with a length such that substrings can easily be taken and such that more than one user at a time can have a pointer to the string. I will also probably add locking primitives, so that you can get the value of something and be sure that some other updator process won't modify it while you have the lock. dhcp-4.2.4/doc/examples/000777 000765 000024 00000000000 11757514243 014767 5ustar00sarstaff000000 000000 dhcp-4.2.4/doc/IANA-arp-parameters000644 000765 000024 00000012727 06317042746 016532 0ustar00sarstaff000000 000000 ADDRESS RESOLUTION PROTOCOL PARAMETERS The Address Resolution Protocol (ARP) specified in [RFC826] has several parameters. The assigned values for these parameters are listed here. REVERSE ADDRESS RESOLUTION PROTOCOL OPERATION CODES The Reverse Address Resolution Protocol (RARP) specified in [RFC903] uses the "Reverse" codes below. DYNAMIC REVERSE ARP The Dynamic Reverse Address Resolution Protocol (DRARP) uses the "DRARP" codes below. For further information, contact: David Brownell (suneast!helium!db@Sun.COM). INVERSE ADDRESS RESOULUTION PROTOCOL The Inverse Address Resolution Protocol (IARP) specified in [RFC1293] uses the "InARP" codes below. Assignments: Number Operation Code (op) References ------ -------------------------- ---------- 1 REQUEST [RFC826] 2 REPLY [RFC826] 3 request Reverse [RFC903] 4 reply Reverse [RFC903] 5 DRARP-Request [David Brownell] 6 DRARP-Reply [David Brownell] 7 DRARP-Error [David Brownell] 8 InARP-Request [RFC1293] 9 InARP-Reply [RFC1293] 10 ARP-NAK [RFC1577] 11 MARS-Request [Armitage] 12 MARS-Multi [Armitage] 13 MARS-MServ [Armitage] 14 MARS-Join [Armitage] 15 MARS-Leave [Armitage] 16 MARS-NAK [Armitage] 17 MARS-Unserv [Armitage] 18 MARS-SJoin [Armitage] 19 MARS-SLeave [Armitage] 20 MARS-Grouplist-Request [Armitage] 21 MARS-Grouplist-Reply [Armitage] 22 MARS-Redirect-Map [Armitage] 23 MAPOS-UNARP [Maruyama] Number Hardware Type (hrd) References ------ ----------------------------------- ---------- 1 Ethernet (10Mb) [JBP] 2 Experimental Ethernet (3Mb) [JBP] 3 Amateur Radio AX.25 [PXK] 4 Proteon ProNET Token Ring [Doria] 5 Chaos [GXP] 6 IEEE 802 Networks [JBP] 7 ARCNET [JBP] 8 Hyperchannel [JBP] 9 Lanstar [TU] 10 Autonet Short Address [MXB1] 11 LocalTalk [JKR1] 12 LocalNet (IBM PCNet or SYTEK LocalNET) [JXM] 13 Ultra link [RXD2] 14 SMDS [GXC1] 15 Frame Relay [AGM] 16 Asynchronous Transmission Mode (ATM) [JXB2] 17 HDLC [JBP] 18 Fibre Channel [Yakov Rekhter] 19 Asynchronous Transmission Mode (ATM) [RFC1577] 20 Serial Line [JBP] 21 Asynchronous Transmission Mode (ATM) [MXB1] 22 MIL-STD-188-220 [Jensen] 23 Metricom [Stone] 24 IEEE 1394.1995 [Hattig] 25 MAPOS [Maruyama] Protocol Type (pro) Use the same codes as listed in the section called "Ethernet Numbers of Interest" (all hardware types use this code set for the protocol type). REFERENCES [RFC826] Plummer, D., "An Ethernet Address Resolution Protocol or Converting Network Protocol Addresses to 48-bit Ethernet Addresses for Transmission on Ethernet Hardware", STD 37, RFC 826, MIT-LCS, November 1982. [RFC903] Finlayson, R., Mann, T., Mogul, J., and M. Theimer, "A Reverse Address Resolution Protocol", STD 38, RFC 903, Stanford University, June 1984. [RFC1293] Bradley, T., and C. Brown, "Inverse Address Resolution Protocol", RFC 1293, Wellfleet Communications, Inc., January 1992. PEOPLE [Armitage] Grenville Armitage, , April 1995. [AGM] Andy Malis [GXC1] George Clapp [Doria] Avri Doria December 1994. [GXP] Gill Pratt [Jensen] Herb Jensen, , February 1995. [JBP] Jon Postel [JKR1] Joyce K. Reynolds [JXM] Joseph Murdock <---none---> [Hattig] Myron Hattig, , February 1997. [Maruyama] Mitsuru Maruyama, , March 1997. [MXB1] Mike Burrows [PXK] Philip Koch [RXD2] Rajiv Dhingra [Stone] Jonathan Stone, , May 1996. [TU] Tom Unger [David Brownell] [Mark Laubach] [Yakov Rekhter] [] dhcp-4.2.4/doc/ja_JP.eucJP/000777 000765 000024 00000000000 11757514243 015141 5ustar00sarstaff000000 000000 dhcp-4.2.4/doc/Makefile000644 000765 000024 00000002144 11301372615 014574 0ustar00sarstaff000000 000000 # Copyright (c) 2004-2006,2009 by Internet Systems Consortium, Inc. ("ISC") # Copyright (c) 1995-2003 by Internet Software Consortium # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # # Internet Systems Consortium, Inc. # 950 Charter Street # Redwood City, CA 94063 # # https://www.isc.org/ all: References.txt References.html References.txt: References.xml xml2txt References.xml References.html: References.xml xml2html References.xml dhcp-4.2.4/doc/References.html000644 000765 000024 00000255553 11701164253 016122 0ustar00sarstaff000000 000000 ISC-DHCP-REFERENCES: ISC DHCP References Collection
 TOC 
ISC-DHCP-REFERENCESD. Hankins
 T. Mrugalski
 ISC
 January 04, 2012


ISC DHCP References Collection

Abstract

This document describes a collection of reference material to which ISC DHCP has been implemented as well as a more complete listing of references for DHCP and DHCPv6 protocols.

Copyright Notice

Copyright (c) 2006-2007,2009,2011 by Internet Systems Consortium, Inc. ("ISC")

Permission to use, copy, modify, and distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.

THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.



Table of Contents

1.  Introduction

2.  Definition: Reference Implementation

3.  Low Layer References
    3.1.  Ethernet Protocol References
    3.2.  Token Ring Protocol References
    3.3.  FDDI Protocol References
    3.4.  Internet Protocol Version 4 References
    3.5.  Unicast Datagram Protocol References

4.  BOOTP Protocol References

5.  DHCPv4 Protocol References
    5.1.  DHCPv4 Protocol
        5.1.1.  Core Protocol References
    5.2.  DHCPv4 Option References
        5.2.1.  Relay Agent Information Option Options
        5.2.2.  Dynamic DNS Updates References
        5.2.3.  Experimental: Failover References
    5.3.  DHCP Procedures

6.  DHCPv6 Protocol References
    6.1.  DHCPv6 Protocol References
    6.2.  DHCPv6 Options References

7.  References
    7.1.  Published DHCPv4 References
    7.2.  Published Common (DHCPv4/DHCPv6) References
    7.3.  Published DHCPv6 References

§  Authors' Addresses




 TOC 

1.  Introduction

As a little historical anecdote, ISC DHCP once packaged all the relevant RFCs and standards documents along with the software package. Until one day when a voice was heard from one of the many fine institutions that build and distribute this software... they took issue with the IETF's copyright on the RFC's. It seems the IETF's copyrights don't allow modification of RFC's (except for translation purposes).

Our main purpose in providing the RFCs is to aid in documentation, but since RFCs are now available widely from many points of distribution on the Internet, there is no real need to provide the documents themselves. So, this document has been created in their stead, to list the various IETF RFCs one might want to read, and to comment on how well (or poorly) we have managed to implement them.



 TOC 

2.  Definition: Reference Implementation

ISC DHCP, much like its other cousins in ISC software, is self-described as a 'Reference Implementation.' There has been a great deal of confusion about this term. Some people seem to think that this term applies to any software that once passed a piece of reference material on its way to market (but may do quite a lot of things that aren't described in any reference, or may choose to ignore the reference it saw entirely). Other folks get confused by the word 'reference' and understand that to mean that there is some special status applied to the software - that the software itself is the reference by which all other software is measured. Something along the lines of being "The DHCP Protocol's Reference Clock," it is supposed.

The truth is actually quite a lot simpler. Reference implementations are software packages which were written to behave precisely as appears in reference material. They are written "to match reference."

If the software has a behaviour that manifests itself externally (whether it be something as simple as the 'wire format' or something higher level, such as a complicated behaviour that arises from multiple message exchanges), that behaviour must be found in a reference document.

Anything else is a bug, the only question is whether the bug is in reference or software (failing to implement the reference).

This means:

  • To produce new externally-visible behaviour, one must first provide a reference.
  • Before changing externally visible behaviour to work around simple incompatibilities in any other implementation, one must first provide a reference.

That is the lofty goal, at any rate. It's well understood that, especially because the ISC DHCP Software package has not always been held to this standard (but not entirely due to it), there are many non-referenced behaviours within ISC DHCP.

The primary goal of reference implementation is to prove the reference material. If the reference material is good, then you should be able to sit down and write a program that implements the reference, to the word, and come to an implementation that is distinguishable from others in the details, but not in the facts of operating the protocol. This means that there is no need for 'special knowledge' to work around arcane problems that were left undocumented. No secret handshakes need to be learned to be imparted with the necessary "real documentation".

Also, by accepting only reference as the guidebook for ISC DHCP's software implementation, anyone who can make an impact on the color texture or form of that reference has a (somewhat indirect) voice in ISC DHCP's software design. As the IETF RFC's have been selected as the source of reference, that means everyone on the Internet with the will to participate has a say.



 TOC 

3.  Low Layer References

It may surprise you to realize that ISC DHCP implements 802.1 'Ethernet' framing, Token Ring, and FDDI. In order to bridge the gap there between these physical and DHCP layers, it must also implement IP and UDP framing.

The reason for this stems from Unix systems' handling of BSD sockets (the general way one might engage in transmission of UDP packets) on unconfigured interfaces, or even the handling of broadcast addressing on configured interfaces.

There are a few things that DHCP servers, relays, and clients all need to do in order to speak the DHCP protocol in strict compliance with [RFC2131] (Droms, R., “Dynamic Host Configuration Protocol,” March 1997.).

  1. Transmit a UDP packet from IP:0.0.0.0 Ethernet:Self, destined to IP:255.255.255.255 LinkLayer:Broadcast on an unconfigured (no IP address yet) interface.
  2. Receive a UDP packet from IP:remote-system LinkLayer:remote-system, destined to IP:255.255.255.255 LinkLayer:Broadcast, again on an unconfigured interface.
  3. Transmit a UDP packet from IP:Self, Ethernet:Self, destined to IP:remote-system LinkLayer:remote-system, without transmitting a single ARP.
  4. And of course the simple case, a regular IP unicast that is routed via the usual means (so it may be direct to a local system, with ARP providing the glue, or it may be to a remote system via one or more routers as normal). In this case, the interfaces are always configured.

The above isn't as simple as it sounds on a regular BSD socket. Many unix implementations will transmit broadcasts not to 255.255.255.255, but to x.y.z.255 (where x.y.z is the system's local subnet). Such packets are not received by several known DHCP client implementations - and it's not their fault, [RFC2131] (Droms, R., “Dynamic Host Configuration Protocol,” March 1997.) very explicitly demands that these packets' IP destination addresses be set to 255.255.255.255.

Receiving packets sent to 255.255.255.255 isn't a problem on most modern unixes...so long as the interface is configured. When there is no IPv4 address on the interface, things become much more murky.

So, for this convoluted and unfortunate state of affairs in the unix systems of the day ISC DHCP was manufactured, in order to do what it needs not only to implement the reference but to interoperate with other implementations, the software must create some form of raw socket to operate on.

What it actually does is create, for each interface detected on the system, a Berkeley Packet Filter socket (or equivalent), and program it with a filter that brings in only DHCP packets. A "fallback" UDP Berkeley socket is generally also created, a single one no matter how many interfaces. Should the software need to transmit a contrived packet to the local network the packet is formed piece by piece and transmitted via the BPF socket. Hence the need to implement many forms of Link Layer framing and above. The software gets away with not having to implement IP routing tables as well by simply utilizing the aforementioned 'fallback' UDP socket when unicasting between two configured systems is needed.

Modern unixes have opened up some facilities that diminish how much of this sort of nefarious kludgery is necessary, but have not found the state of affairs absolutely resolved. In particular, one might now unicast without ARP by inserting an entry into the ARP cache prior to transmitting. Unconfigured interfaces remain the sticking point, however...on virtually no modern unixes is it possible to receive broadcast packets unless a local IPv4 address has been configured, unless it is done with raw sockets.



 TOC 

3.1.  Ethernet Protocol References

ISC DHCP Implements Ethernet Version 2 ("DIX"), which is a variant of IEEE 802.2. No good reference of this framing is known to exist at this time, but it is vaguely described in [RFC0894] (Hornig, C., “Standard for the transmission of IP datagrams over Ethernet networks,” April 1984.) see the section titled "Packet format"), and the following URL is also thought to be useful.

http://en.wikipedia.org/wiki/DIX_Ethernet



 TOC 

3.2.  Token Ring Protocol References

IEEE 802.5 defines the Token Ring framing format used by ISC DHCP.



 TOC 

3.3.  FDDI Protocol References

[RFC1188] (Katz, D., “Proposed Standard for the Transmission of IP Datagrams over FDDI Networks,” October 1990.) is the most helpful reference ISC DHCP has used to form FDDI packets.



 TOC 

3.4.  Internet Protocol Version 4 References

RFC760 (Postel, J., “DoD standard Internet Protocol,” January 1980.) [RFC0760] fundamentally defines the bare IPv4 protocol which ISC DHCP implements.



 TOC 

3.5.  Unicast Datagram Protocol References

RFC768 (Postel, J., “User Datagram Protocol,” August 1980.) [RFC0768] defines the User Datagram Protocol that ultimately carries the DHCP or BOOTP protocol. The destination DHCP server port is 67, the client port is 68. Source ports are irrelevant.



 TOC 

4.  BOOTP Protocol References

The DHCP Protocol is strange among protocols in that it is grafted over the top of another protocol - BOOTP (but we don't call it "DHCP over BOOTP" like we do, say "TCP over IP"). BOOTP and DHCP share UDP packet formats - DHCP is merely a conventional use of both BOOTP header fields and the trailing 'options' space.

The ISC DHCP server supports BOOTP clients conforming to RFC951 (Croft, B. and J. Gilmore, “Bootstrap Protocol,” September 1985.) [RFC0951] and RFC1542 (Wimer, W., “Clarifications and Extensions for the Bootstrap Protocol,” October 1993.) [RFC1542].



 TOC 

5.  DHCPv4 Protocol References



 TOC 

5.1.  DHCPv4 Protocol

"The DHCP[v4] Protocol" is not defined in a single document. The following collection of references of what ISC DHCP terms "The DHCPv4 Protocol".



 TOC 

5.1.1.  Core Protocol References

RFC2131 (Droms, R., “Dynamic Host Configuration Protocol,” March 1997.) [RFC2131] defines the protocol format and procedures. ISC DHCP is not known to diverge from this document in any way. There are, however, a few points on which different implementations have arisen out of vagueries in the document. DHCP Clients exist which, at one time, present themselves as using a Client Identifier Option which is equal to the client's hardware address. Later, the client transmits DHCP packets with no Client Identifier Option present - essentially identifying themselves using the hardware address. Some DHCP Servers have been developed which identify this client as a single client. ISC has interpreted RFC2131 to indicate that these clients must be treated as two separate entities (and hence two, separate addresses). Client behaviour (Embedded Windows products) has developed that relies on the former implementation, and hence is incompatible with the latter. Also, RFC2131 demands explicitly that some header fields be zeroed upon certain message types. The ISC DHCP Server instead copies many of these fields from the packet received from the client or relay, which may not be zero. It is not known if there is a good reason for this that has not been documented.

RFC2132 (Alexander, S. and R. Droms, “DHCP Options and BOOTP Vendor Extensions,” March 1997.) [RFC2132] defines the initial set of DHCP Options and provides a great deal of guidance on how to go about formatting and processing options. The document unfortunately waffles to a great extent about the NULL termination of DHCP Options, and some DHCP Clients (Windows 95) have been implemented that rely upon DHCP Options containing text strings to be NULL-terminated (or else they crash). So, ISC DHCP detects if clients null-terminate the host-name option and, if so, null terminates any text options it transmits to the client. It also removes NULL termination from any known text option it receives prior to any other processing.



 TOC 

5.2.  DHCPv4 Option References

RFC2241 (Provan, D., “DHCP Options for Novell Directory Services,” November 1997.) [RFC2241] defines options for Novell Directory Services.

RFC2242 (Droms, R. and K. Fong, “NetWare/IP Domain Name and Information,” November 1997.) [RFC2242] defines an encapsulated option space for NWIP configuration.

RFC2485 (Drach, S., “DHCP Option for The Open Group's User Authentication Protocol,” January 1999.) [RFC2485] defines the Open Group's UAP option.

RFC2610 (Perkins, C. and E. Guttman, “DHCP Options for Service Location Protocol,” June 1999.) [RFC2610] defines options for the Service Location Protocol (SLP).

RFC2937 (Smith, C., “The Name Service Search Option for DHCP,” September 2000.) [RFC2937] defines the Name Service Search Option (not to be confused with the domain-search option). The Name Service Search Option allows eg nsswitch.conf to be reconfigured via dhcp. The ISC DHCP server implements this option, and the ISC DHCP client is compatible...but does not by default install this option's value. One would need to make their relevant dhclient-script process this option in a way that is suitable for the system.

RFC3004 (Stump, G., Droms, R., Gu, Y., Vyaghrapuri, R., Demirtjis, A., Beser, B., and J. Privat, “The User Class Option for DHCP,” November 2000.) [RFC3004] defines the User-Class option. Note carefully that ISC DHCP currently does not implement to this reference, but has (inexplicably) selected an incompatible format: a plain text string.

RFC3011 (Waters, G., “The IPv4 Subnet Selection Option for DHCP,” November 2000.) [RFC3011] defines the Subnet-Selection plain DHCPv4 option. Do not confuse this option with the relay agent "link selection" sub-option, although their behaviour is similar.

RFC3396 (Lemon, T. and S. Cheshire, “Encoding Long Options in the Dynamic Host Configuration Protocol (DHCPv4),” November 2002.) [RFC3396] documents both how long options may be encoded in DHCPv4 packets, and also how multiple instances of the same option code within a DHCPv4 packet will be decoded by receivers.

RFC3397 (Aboba, B. and S. Cheshire, “Dynamic Host Configuration Protocol (DHCP) Domain Search Option,” November 2002.) [RFC3397] documents the Domain-Search Option, which allows the configuration of the /etc/resolv.conf 'search' parameter in a way that is RFC1035 (Mockapetris, P., “Domain names - implementation and specification,” November 1987.) [RFC1035] wire format compatible (in fact, it uses the RFC1035 wire format). ISC DHCP has both client and server support, and supports RFC1035 name compression.

RFC3679 (Droms, R., “Unused Dynamic Host Configuration Protocol (DHCP) Option Codes,” January 2004.) [RFC3679] documents a number of options that were documented earlier in history, but were not made use of.

RFC3925 (Littlefield, J., “Vendor-Identifying Vendor Options for Dynamic Host Configuration Protocol version 4 (DHCPv4),” October 2004.) [RFC3925] documents a pair of Enterprise-ID delimited option spaces for vendors to use in order to inform servers of their "vendor class" (sort of like 'uname' or 'who and what am I'), and a means to deliver vendor-specific and vendor-documented option codes and values.

RFC3942 (Volz, B., “Reclassifying Dynamic Host Configuration Protocol version 4 (DHCPv4) Options,” November 2004.) [RFC3942] redefined the 'site local' option space.

[RFC4280] (Chowdhury, K., Yegani, P., and L. Madour, “Dynamic Host Configuration Protocol (DHCP) Options for Broadcast and Multicast Control Servers,” November 2005.) defines two BCMS server options for each protocol family.

RFC4388 (Woundy, R. and K. Kinnear, “Dynamic Host Configuration Protocol (DHCP) Leasequery,” February 2006.) [RFC4388] defined the DHCPv4 LEASEQUERY message type and a number of suitable response messages, for the purpose of sharing information about DHCP served addresses and clients.



 TOC 

5.2.1.  Relay Agent Information Option Options

RFC3046 (Patrick, M., “DHCP Relay Agent Information Option,” January 2001.) [RFC3046] defines the Relay Agent Information Option and provides a number of sub-option definitions.

RFC3256 (Jones, D. and R. Woundy, “The DOCSIS (Data-Over-Cable Service Interface Specifications) Device Class DHCP (Dynamic Host Configuration Protocol) Relay Agent Information Sub-option,” April 2002.) [RFC3256] defines the DOCSIS Device Class sub-option.

RFC3527 (Kinnear, K., Stapp, M., Johnson, R., and J. Kumarasamy, “Link Selection sub-option for the Relay Agent Information Option for DHCPv4,” April 2003.) [RFC3527] defines the Link Selection sub-option.



 TOC 

5.2.2.  Dynamic DNS Updates References

The collection of documents that describe the standards-based method to update dns names of DHCP clients starts most easily with RFC4703 (Stapp, M. and B. Volz, “Resolution of Fully Qualified Domain Name (FQDN) Conflicts among Dynamic Host Configuration Protocol (DHCP) Clients,” October 2006.) [RFC4703] to define the overall architecture, travels through RFCs 4702 (Stapp, M., Volz, B., and Y. Rekhter, “The Dynamic Host Configuration Protocol (DHCP) Client Fully Qualified Domain Name (FQDN) Option,” October 2006.) [RFC4702] and 4704 (Volz, B., “The Dynamic Host Configuration Protocol for IPv6 (DHCPv6) Client Fully Qualified Domain Name (FQDN) Option,” October 2006.) [RFC4704] to describe the DHCPv4 and DHCPv6 FQDN options (to carry the client name), and ends up at RFC4701 (Stapp, M., Lemon, T., and A. Gustafsson, “A DNS Resource Record (RR) for Encoding Dynamic Host Configuration Protocol (DHCP) Information (DHCID RR),” October 2006.) [RFC4701] which describes the DHCID RR used in DNS to perform a kind of atomic locking.

ISC DHCP adopted early versions of these documents, and has not yet synchronized with the final standards versions.

For RFCs 4702 and 4704, the 'N' bit is not yet supported. The result is that it is always set zero, and is ignored if set.

For RFC4701, which is used to match client identities with names in the DNS as part of name conflict resolution. Note that ISC DHCP's implementation of DHCIDs vary wildly from this specification. First, ISC DHCP uses a TXT record in which the contents are stored in hexadecimal. Second, there is a flaw in the selection of the 'Identifier Type', which results in a completely different value being selected than was defined in an older revision of this document...also this field is one byte prior to hexadecimal encoding rather than two. Third, ISC DHCP does not use a digest type code. Rather, all values for such TXT records are reached via an MD5 sum. In short, nothing is compatible, but the principle of the TXT record is the same as the standard DHCID record. However, for DHCPv6 FQDN, we do use DHCID type code '2', as no other value really makes sense in our context.



 TOC 

5.2.3.  Experimental: Failover References

The Failover Protocol defines means by which two DHCP Servers can share all the relevant information about leases granted to DHCP clients on given networks, so that one of the two servers may fail and be survived by a server that can act responsibly.

Unfortunately it has been quite some years (2003) since the last time this document was edited, and the authors no longer show any interest in fielding comments or improving the document.

The status of this protocol is very unsure, but ISC's implementation of it has proven stable and suitable for use in sizable production environments.

draft-ietf-dhc-failover-12.txt (Droms, R., “DHCP Failover Protocol,” March 2003.) [draft‑failover] describes the Failover Protocol. In addition to what is described in this document, ISC DHCP has elected to make some experimental changes that may be revoked in a future version of ISC DHCP (if the draft authors do not adopt the new behaviour). Specifically, ISC DHCP's POOLREQ behaviour differs substantially from what is documented in the draft, and the server also implements a form of 'MAC Address Affinity' which is not described in the failover document. The full nature of these changes have been described on the IETF DHC WG mailing list (which has archives), and also in ISC DHCP's manual pages. Also note that although this document references a RECOVER-WAIT state, it does not document a protocol number assignment for this state. As a consequence, ISC DHCP has elected to use the value 254.

An optimization described in the failover protocol draft is included since 4.2.0a1. It permits a DHCP server operating in communications-interrupted state to 'rewind' a lease to the state most recently transmitted to its peer, greatly increasing a server's endurance in communications-interrupted. This is supported using a new 'rewind state' record on the dhcpd.leases entry for each lease.

[RFC3074] (Volz, B., Gonczi, S., Lemon, T., and R. Stevens, “DHC Load Balancing Algorithm,” February 2001.) describes the Load Balancing Algorithm (LBA) that ISC DHCP uses in concert with the Failover protocol. Note that versions 3.0.* are known to misimplement the hash algorithm (it will only use the low 4 bits of every byte of the hash bucket array).



 TOC 

5.3.  DHCP Procedures

[RFC2939] (Droms, R., “Procedures and IANA Guidelines for Definition of New DHCP Options and Message Types,” September 2000.) explains how to go about obtaining a new DHCP Option code assignment.



 TOC 

6.  DHCPv6 Protocol References



 TOC 

6.1.  DHCPv6 Protocol References

For now there is only one document that specifies the base of the DHCPv6 protocol (there have been no updates yet), [RFC3315] (Droms, R., Bound, J., Volz, B., Lemon, T., Perkins, C., and M. Carney, “Dynamic Host Configuration Protocol for IPv6 (DHCPv6),” July 2003.).

Support for DHCPv6 was first added in version 4.0.0. The server and client support only IA_NA. While the server does support multiple IA_NAs within one packet from the client, our client only supports sending one. There is no relay support.

DHCPv6 introduces some new and uncomfortable ideas to the common software library.

  1. Options sometimes may appear multiple times. The common library used to treat all appearance of multiple options as specified in RFC2131 - to be concatenated. DHCPv6 options may sometimes appear multiple times (such as with IA_NA or IAADDR), but often must not. As of 4.2.1-P1, multiple IA_NA, IA_PD or IA_TA are not supported.
  2. The same option space appears in DHCPv6 packets multiple times. If the packet was got via a relay, then the client's packet is stored to an option within the relay's packet...if there were two relays, this recurses. At each of these steps, the root "DHCPv6 option space" is used. Further, a client packet may contain an IA_NA, which may contain an IAADDR - but really, in an abstract sense, this is again re-encapsulation of the DHCPv6 option space beneath options it also contains.

Precisely how to correctly support the above conundrums has not quite yet been settled, so support is incomplete.

[RFC5453] (Krishnan, S., “Reserved IPv6 Interface Identifiers,” February 2009.) creates a registry at IANA to reserve interface identifiers and specifies a starting set. These IIDs should not be used when constructing addresses to avoid possible conflicts.



 TOC 

6.2.  DHCPv6 Options References

[RFC3319] (Schulzrinne, H. and B. Volz, “Dynamic Host Configuration Protocol (DHCPv6) Options for Session Initiation Protocol (SIP) Servers,” July 2003.) defines the SIP server options for DHCPv6.

[RFC3646] (Droms, R., “DNS Configuration options for Dynamic Host Configuration Protocol for IPv6 (DHCPv6),” December 2003.) documents the DHCPv6 name-servers and domain-search options.

[RFC3633] (Troan, O. and R. Droms, “IPv6 Prefix Options for Dynamic Host Configuration Protocol (DHCP) version 6,” December 2003.) documents the Identity Association Prefix Delegation for DHCPv6, which is included here for protocol wire reference, but which is not supported by ISC DHCP.

[RFC3898] (Kalusivalingam, V., “Network Information Service (NIS) Configuration Options for Dynamic Host Configuration Protocol for IPv6 (DHCPv6),” October 2004.) documents four NIS options for delivering NIS servers and domain information in DHCPv6.

[RFC4075] (Kalusivalingam, V., “Simple Network Time Protocol (SNTP) Configuration Option for DHCPv6,” May 2005.) defines the DHCPv6 SNTP Servers option.

[RFC4242] (Venaas, S., Chown, T., and B. Volz, “Information Refresh Time Option for Dynamic Host Configuration Protocol for IPv6 (DHCPv6),” November 2005.) defines the Information Refresh Time option, which advises DHCPv6 Information-Request clients to return for updated information.

[RFC4280] (Chowdhury, K., Yegani, P., and L. Madour, “Dynamic Host Configuration Protocol (DHCP) Options for Broadcast and Multicast Control Servers,” November 2005.) defines two BCMS server options for each protocol family.

[RFC4580] (Volz, B., “Dynamic Host Configuration Protocol for IPv6 (DHCPv6) Relay Agent Subscriber-ID Option,” June 2006.) defines a DHCPv6 subscriber-id option, which is similar in principle to the DHCPv4 relay agent option of the same name.

[RFC4649] (Volz, B., “Dynamic Host Configuration Protocol for IPv6 (DHCPv6) Relay Agent Remote-ID Option,” August 2006.) defines a DHCPv6 remote-id option, which is similar in principle to the DHCPv4 relay agent remote-id.



 TOC 

7.  References



 TOC 

7.1. Published DHCPv4 References

[RFC0760] Postel, J., “DoD standard Internet Protocol,” RFC 760, January 1980 (TXT).
[RFC0768] Postel, J., “User Datagram Protocol,” STD 6, RFC 768, August 1980 (TXT).
[RFC0894] Hornig, C., “Standard for the transmission of IP datagrams over Ethernet networks,” STD 41, RFC 894, April 1984 (TXT).
[RFC0951] Croft, B. and J. Gilmore, “Bootstrap Protocol,” RFC 951, September 1985 (TXT).
[RFC1035] Mockapetris, P., “Domain names - implementation and specification,” STD 13, RFC 1035, November 1987 (TXT).
[RFC1188] Katz, D., “Proposed Standard for the Transmission of IP Datagrams over FDDI Networks,” RFC 1188, October 1990 (TXT).
[RFC1542] Wimer, W., “Clarifications and Extensions for the Bootstrap Protocol,” RFC 1542, October 1993 (TXT).
[RFC2131] Droms, R., “Dynamic Host Configuration Protocol,” RFC 2131, March 1997 (TXT, HTML, XML).
[RFC2132] Alexander, S. and R. Droms, “DHCP Options and BOOTP Vendor Extensions,” RFC 2132, March 1997 (TXT, HTML, XML).
[RFC2241] Provan, D., “DHCP Options for Novell Directory Services,” RFC 2241, November 1997 (TXT, HTML, XML).
[RFC2242] Droms, R. and K. Fong, “NetWare/IP Domain Name and Information,” RFC 2242, November 1997 (TXT, HTML, XML).
[RFC2485] Drach, S., “DHCP Option for The Open Group's User Authentication Protocol,” RFC 2485, January 1999 (TXT, HTML, XML).
[RFC2563] Troll, R., “DHCP Option to Disable Stateless Auto-Configuration in IPv4 Clients,” RFC 2563, May 1999 (TXT).
[RFC2610] Perkins, C. and E. Guttman, “DHCP Options for Service Location Protocol,” RFC 2610, June 1999 (TXT).
[RFC2855] Fujisawa, K., “DHCP for IEEE 1394,” RFC 2855, June 2000 (TXT).
[RFC2937] Smith, C., “The Name Service Search Option for DHCP,” RFC 2937, September 2000 (TXT).
[RFC2939] Droms, R., “Procedures and IANA Guidelines for Definition of New DHCP Options and Message Types,” BCP 43, RFC 2939, September 2000 (TXT).
[RFC3004] Stump, G., Droms, R., Gu, Y., Vyaghrapuri, R., Demirtjis, A., Beser, B., and J. Privat, “The User Class Option for DHCP,” RFC 3004, November 2000 (TXT).
[RFC3011] Waters, G., “The IPv4 Subnet Selection Option for DHCP,” RFC 3011, November 2000 (TXT).
[RFC3046] Patrick, M., “DHCP Relay Agent Information Option,” RFC 3046, January 2001 (TXT).
[RFC3074] Volz, B., Gonczi, S., Lemon, T., and R. Stevens, “DHC Load Balancing Algorithm,” RFC 3074, February 2001 (TXT).
[RFC3118] Droms, R. and W. Arbaugh, “Authentication for DHCP Messages,” RFC 3118, June 2001 (TXT).
[RFC3203] T'Joens, Y., Hublet, C., and P. De Schrijver, “DHCP reconfigure extension,” RFC 3203, December 2001 (TXT).
[RFC3256] Jones, D. and R. Woundy, “The DOCSIS (Data-Over-Cable Service Interface Specifications) Device Class DHCP (Dynamic Host Configuration Protocol) Relay Agent Information Sub-option,” RFC 3256, April 2002 (TXT).
[RFC3361] Schulzrinne, H., “Dynamic Host Configuration Protocol (DHCP-for-IPv4) Option for Session Initiation Protocol (SIP) Servers,” RFC 3361, August 2002 (TXT).
[RFC3396] Lemon, T. and S. Cheshire, “Encoding Long Options in the Dynamic Host Configuration Protocol (DHCPv4),” RFC 3396, November 2002 (TXT).
[RFC3397] Aboba, B. and S. Cheshire, “Dynamic Host Configuration Protocol (DHCP) Domain Search Option,” RFC 3397, November 2002 (TXT).
[RFC3442] Lemon, T., Cheshire, S., and B. Volz, “The Classless Static Route Option for Dynamic Host Configuration Protocol (DHCP) version 4,” RFC 3442, December 2002 (TXT).
[RFC3456] Patel, B., Aboba, B., Kelly, S., and V. Gupta, “Dynamic Host Configuration Protocol (DHCPv4) Configuration of IPsec Tunnel Mode,” RFC 3456, January 2003 (TXT).
[RFC3495] Beser, B. and P. Duffy, “Dynamic Host Configuration Protocol (DHCP) Option for CableLabs Client Configuration,” RFC 3495, March 2003 (TXT).
[RFC3527] Kinnear, K., Stapp, M., Johnson, R., and J. Kumarasamy, “Link Selection sub-option for the Relay Agent Information Option for DHCPv4,” RFC 3527, April 2003 (TXT).
[RFC3594] Duffy, P., “PacketCable Security Ticket Control Sub-Option for the DHCP CableLabs Client Configuration (CCC) Option,” RFC 3594, September 2003 (TXT).
[RFC3634] Luehrs, K., Woundy, R., Bevilacqua, J., and N. Davoust, “Key Distribution Center (KDC) Server Address Sub-option for the Dynamic Host Configuration Protocol (DHCP) CableLabs Client Configuration (CCC) Option,” RFC 3634, December 2003 (TXT).
[RFC3679] Droms, R., “Unused Dynamic Host Configuration Protocol (DHCP) Option Codes,” RFC 3679, January 2004 (TXT).
[RFC3825] Polk, J., Schnizlein, J., and M. Linsner, “Dynamic Host Configuration Protocol Option for Coordinate-based Location Configuration Information,” RFC 3825, July 2004 (TXT).
[RFC3925] Littlefield, J., “Vendor-Identifying Vendor Options for Dynamic Host Configuration Protocol version 4 (DHCPv4),” RFC 3925, October 2004 (TXT).
[RFC3942] Volz, B., “Reclassifying Dynamic Host Configuration Protocol version 4 (DHCPv4) Options,” RFC 3942, November 2004 (TXT).
[RFC3993] Johnson, R., Palaniappan, T., and M. Stapp, “Subscriber-ID Suboption for the Dynamic Host Configuration Protocol (DHCP) Relay Agent Option,” RFC 3993, March 2005 (TXT).
[RFC4014] Droms, R. and J. Schnizlein, “Remote Authentication Dial-In User Service (RADIUS) Attributes Suboption for the Dynamic Host Configuration Protocol (DHCP) Relay Agent Information Option,” RFC 4014, February 2005 (TXT).
[RFC4030] Stapp, M. and T. Lemon, “The Authentication Suboption for the Dynamic Host Configuration Protocol (DHCP) Relay Agent Option,” RFC 4030, March 2005 (TXT).
[RFC4039] Park, S., Kim, P., and B. Volz, “Rapid Commit Option for the Dynamic Host Configuration Protocol version 4 (DHCPv4),” RFC 4039, March 2005 (TXT).
[RFC4174] Monia, C., Tseng, J., and K. Gibbons, “The IPv4 Dynamic Host Configuration Protocol (DHCP) Option for the Internet Storage Name Service,” RFC 4174, September 2005 (TXT).
[RFC4243] Stapp, M., Johnson, R., and T. Palaniappan, “Vendor-Specific Information Suboption for the Dynamic Host Configuration Protocol (DHCP) Relay Agent Option,” RFC 4243, December 2005 (TXT).
[RFC4361] Lemon, T. and B. Sommerfeld, “Node-specific Client Identifiers for Dynamic Host Configuration Protocol Version Four (DHCPv4),” RFC 4361, February 2006 (TXT).
[RFC4388] Woundy, R. and K. Kinnear, “Dynamic Host Configuration Protocol (DHCP) Leasequery,” RFC 4388, February 2006 (TXT).
[RFC4390] Kashyap, V., “Dynamic Host Configuration Protocol (DHCP) over InfiniBand,” RFC 4390, April 2006 (TXT).
[RFC4436] Aboba, B., Carlson, J., and S. Cheshire, “Detecting Network Attachment in IPv4 (DNAv4),” RFC 4436, March 2006 (TXT).
[RFC4701] Stapp, M., Lemon, T., and A. Gustafsson, “A DNS Resource Record (RR) for Encoding Dynamic Host Configuration Protocol (DHCP) Information (DHCID RR),” RFC 4701, October 2006 (TXT).
[RFC4702] Stapp, M., Volz, B., and Y. Rekhter, “The Dynamic Host Configuration Protocol (DHCP) Client Fully Qualified Domain Name (FQDN) Option,” RFC 4702, October 2006 (TXT).
[RFC4703] Stapp, M. and B. Volz, “Resolution of Fully Qualified Domain Name (FQDN) Conflicts among Dynamic Host Configuration Protocol (DHCP) Clients,” RFC 4703, October 2006 (TXT).
[RFC5010] Kinnear, K., Normoyle, M., and M. Stapp, “The Dynamic Host Configuration Protocol Version 4 (DHCPv4) Relay Agent Flags Suboption,” RFC 5010, September 2007 (TXT).
[RFC5071] Hankins, D., “Dynamic Host Configuration Protocol Options Used by PXELINUX,” RFC 5071, December 2007 (TXT).
[RFC5107] Johnson, R., Kumarasamy, J., Kinnear, K., and M. Stapp, “DHCP Server Identifier Override Suboption,” RFC 5107, February 2008 (TXT).
[RFC5192] Morand, L., Yegin, A., Kumar, S., and S. Madanapalli, “DHCP Options for Protocol for Carrying Authentication for Network Access (PANA) Authentication Agents,” RFC 5192, May 2008 (TXT).
[RFC5223] Schulzrinne, H., Polk, J., and H. Tschofenig, “Discovering Location-to-Service Translation (LoST) Servers Using the Dynamic Host Configuration Protocol (DHCP),” RFC 5223, August 2008 (TXT).
[RFC5859] Johnson, R., “TFTP Server Address Option for DHCPv4,” RFC 5859, June 2010 (TXT).
[RFC5969] Townsley, W. and O. Troan, “IPv6 Rapid Deployment on IPv4 Infrastructures (6rd) -- Protocol Specification,” RFC 5969, August 2010 (TXT).
[draft-failover] Droms, R., “DHCP Failover Protocol,” March 2003.
[I-D.ietf-dhc-dhcpv4-relay-encapsulation] Lemon, T. and H. Deng, “Relay Agent Encapsulation for DHCPv4,” draft-ietf-dhc-dhcpv4-relay-encapsulation-00 (work in progress), October 2010 (TXT).
[I-D.ietf-dhc-dhcpv4-bulk-leasequery] Kinnear, K., Volz, B., Russell, N., Stapp, M., Rao, D., Joshi, B., and P. Kurapati, “Bulk DHCPv4 Lease Query,” draft-ietf-dhc-dhcpv4-bulk-leasequery-03 (work in progress), October 2010 (TXT).
[I-D.ietf-dhc-leasequery-by-remote-id] Kurapati, P. and B. Joshi, “DHCPv4 lease query by Relay Agent Remote ID,” draft-ietf-dhc-leasequery-by-remote-id-09 (work in progress), December 2010 (TXT).
[I-D.ietf-dhc-relay-id-suboption] Stapp, M., “The DHCPv4 Relay Agent Identifier Suboption,” draft-ietf-dhc-relay-id-suboption-07 (work in progress), July 2009 (TXT).
[I-D.ietf-mip6-hiopt] Jang, H., Yegin, A., Chowdhury, K., and J. Choi, “DHCP Options for Home Information Discovery in MIPv6,” draft-ietf-mip6-hiopt-17 (work in progress), May 2008 (TXT).


 TOC 

7.2. Published Common (DHCPv4/DHCPv6) References

[RFC4280] Chowdhury, K., Yegani, P., and L. Madour, “Dynamic Host Configuration Protocol (DHCP) Options for Broadcast and Multicast Control Servers,” RFC 4280, November 2005 (TXT).
[RFC4477] Chown, T., Venaas, S., and C. Strauf, “Dynamic Host Configuration Protocol (DHCP): IPv4 and IPv6 Dual-Stack Issues,” RFC 4477, May 2006 (TXT).
[RFC4578] Johnston, M. and S. Venaas, “Dynamic Host Configuration Protocol (DHCP) Options for the Intel Preboot eXecution Environment (PXE),” RFC 4578, November 2006 (TXT).
[RFC4776] Schulzrinne, H., “Dynamic Host Configuration Protocol (DHCPv4 and DHCPv6) Option for Civic Addresses Configuration Information,” RFC 4776, November 2006 (TXT).
[RFC4833] Lear, E. and P. Eggert, “Timezone Options for DHCP,” RFC 4833, April 2007 (TXT).
[RFC5417] Calhoun, P., “Control And Provisioning of Wireless Access Points (CAPWAP) Access Controller DHCP Option,” RFC 5417, March 2009 (TXT).
[RFC5678] Bajko, G. and S. Das, “Dynamic Host Configuration Protocol (DHCPv4 and DHCPv6) Options for IEEE 802.21 Mobility Services (MoS) Discovery,” RFC 5678, December 2009 (TXT).
[RFC5908] Gayraud, R. and B. Lourdelet, “Network Time Protocol (NTP) Server Option for DHCPv6,” RFC 5908, June 2010 (TXT).
[RFC5970] Huth, T., Freimann, J., Zimmer, V., and D. Thaler, “DHCPv6 Options for Network Boot,” RFC 5970, September 2010 (TXT).
[RFC5986] Thomson, M. and J. Winterbottom, “Discovering the Local Location Information Server (LIS),” RFC 5986, September 2010 (TXT).
[I-D.ietf-dhc-vpn-option] Kinnear, K., Johnson, R., and M. Stapp, “Virtual Subnet Selection Options for DHCPv4 and DHCPv6,” draft-ietf-dhc-vpn-option-12 (work in progress), October 2010 (TXT).


 TOC 

7.3. Published DHCPv6 References

[RFC3315] Droms, R., Bound, J., Volz, B., Lemon, T., Perkins, C., and M. Carney, “Dynamic Host Configuration Protocol for IPv6 (DHCPv6),” RFC 3315, July 2003 (TXT).
[RFC3319] Schulzrinne, H. and B. Volz, “Dynamic Host Configuration Protocol (DHCPv6) Options for Session Initiation Protocol (SIP) Servers,” RFC 3319, July 2003 (TXT).
[RFC3633] Troan, O. and R. Droms, “IPv6 Prefix Options for Dynamic Host Configuration Protocol (DHCP) version 6,” RFC 3633, December 2003 (TXT).
[RFC3646] Droms, R., “DNS Configuration options for Dynamic Host Configuration Protocol for IPv6 (DHCPv6),” RFC 3646, December 2003 (TXT).
[RFC3736] Droms, R., “Stateless Dynamic Host Configuration Protocol (DHCP) Service for IPv6,” RFC 3736, April 2004 (TXT).
[RFC3898] Kalusivalingam, V., “Network Information Service (NIS) Configuration Options for Dynamic Host Configuration Protocol for IPv6 (DHCPv6),” RFC 3898, October 2004 (TXT).
[RFC4075] Kalusivalingam, V., “Simple Network Time Protocol (SNTP) Configuration Option for DHCPv6,” RFC 4075, May 2005 (TXT).
[RFC4076] Chown, T., Venaas, S., and A. Vijayabhaskar, “Renumbering Requirements for Stateless Dynamic Host Configuration Protocol for IPv6 (DHCPv6),” RFC 4076, May 2005 (TXT).
[RFC4242] Venaas, S., Chown, T., and B. Volz, “Information Refresh Time Option for Dynamic Host Configuration Protocol for IPv6 (DHCPv6),” RFC 4242, November 2005 (TXT).
[RFC4580] Volz, B., “Dynamic Host Configuration Protocol for IPv6 (DHCPv6) Relay Agent Subscriber-ID Option,” RFC 4580, June 2006 (TXT).
[RFC4649] Volz, B., “Dynamic Host Configuration Protocol for IPv6 (DHCPv6) Relay Agent Remote-ID Option,” RFC 4649, August 2006 (TXT).
[RFC4704] Volz, B., “The Dynamic Host Configuration Protocol for IPv6 (DHCPv6) Client Fully Qualified Domain Name (FQDN) Option,” RFC 4704, October 2006 (TXT).
[RFC4994] Zeng, S., Volz, B., Kinnear, K., and J. Brzozowski, “DHCPv6 Relay Agent Echo Request Option,” RFC 4994, September 2007 (TXT).
[RFC5007] Brzozowski, J., Kinnear, K., Volz, B., and S. Zeng, “DHCPv6 Leasequery,” RFC 5007, September 2007 (TXT).
[RFC5453] Krishnan, S., “Reserved IPv6 Interface Identifiers,” RFC 5453, February 2009 (TXT).
[RFC5460] Stapp, M., “DHCPv6 Bulk Leasequery,” RFC 5460, February 2009 (TXT).
[I-D.ietf-mif-dhcpv6-route-option] Dec, W., Mrugalski, T., Sun, T., and B. Sarikaya, “DHCPv6 Route Options,” draft-ietf-mif-dhcpv6-route-option-03 (work in progress), September 2011 (TXT).
[I-D.ietf-dhc-dhcpv6-ldra] Miles, D., Ooghe, S., Dec, W., Krishnan, S., and A. Kavanagh, “Lightweight DHCPv6 Relay Agent,” draft-ietf-dhc-dhcpv6-ldra-03 (work in progress), October 2010 (TXT).
[I-D.ietf-dhc-dhcpv6-relay-supplied-options] Lemon, T. and W. Wu, “Relay-Supplied DHCP Options,” draft-ietf-dhc-dhcpv6-relay-supplied-options-09 (work in progress), September 2011 (TXT).
[I-D.ietf-dhc-pd-exclude] Korhonen, J., Savolainen, T., Krishnan, S., and O. Troan, “Prefix Exclude Option for DHCPv6-based Prefix Delegation,” draft-ietf-dhc-pd-exclude-01 (work in progress), January 2011 (TXT).
[I-D.ietf-dhc-secure-dhcpv6] Jiang, S., “Secure DHCPv6 Using CGAs,” draft-ietf-dhc-secure-dhcpv6-02 (work in progress), December 2010 (TXT).
[I-D.ietf-mext-nemo-pd] Droms, R., Thubert, P., Dupont, F., Haddad, W., and C. Bernardos, “DHCPv6 Prefix Delegation for NEMO,” draft-ietf-mext-nemo-pd-07 (work in progress), December 2010 (TXT).
[I-D.ietf-dhc-duid-uuid] Narten, T. and J. Johnson, “Definition of the UUID-based DHCPv6 Unique Identifier (DUID-UUID),” draft-ietf-dhc-duid-uuid-03 (work in progress), February 2011 (TXT).
[I-D.ietf-softwire-ds-lite-tunnel-option] Hankins, D. and T. Mrugalski, “Dynamic Host Configuration Protocol for IPv6 (DHCPv6) Option for Dual- Stack Lite,” draft-ietf-softwire-ds-lite-tunnel-option-10 (work in progress), March 2011 (TXT).
[I-D.ietf-mif-dns-server-selection] Savolainen, T. and J. Kato, “Improved DNS Server Selection for Multi-Homed Nodes,” draft-ietf-mif-dns-server-selection-01 (work in progress), March 2011 (TXT).
[I-D.ietf-geopriv-rfc3825bis] Polk, J., Linsner, M., Thomson, M., and B. Aboba, “Dynamic Host Configuration Protocol Options for Coordinate-based Location Configuration Information,” draft-ietf-geopriv-rfc3825bis-17 (work in progress), February 2011 (TXT).
[draft-addr-params] Mrugalski, T., “Address Parameters Option for DHCPv6,” April 2007.


 TOC 

Authors' Addresses

  David W. Hankins
  Internet Systems Consortium, Inc.
  950 Charter Street
  Redwood City, CA 94063
  
  Tomasz Mrugalski
  Internet Systems Consortium, Inc.
  950 Charter Street
  Redwood City, CA 94063
Phone:  +1 650 423 1345
Email:  Tomasz_Mrugalski@isc.org
dhcp-4.2.4/doc/References.txt000644 000765 000024 00000130673 11701164253 015770 0ustar00sarstaff000000 000000 ISC-DHCP-REFERENCES D. Hankins T. Mrugalski ISC January 04, 2012 ISC DHCP References Collection Abstract This document describes a collection of reference material to which ISC DHCP has been implemented as well as a more complete listing of references for DHCP and DHCPv6 protocols. Copyright Notice Copyright (c) 2006-2007,2009,2011 by Internet Systems Consortium, Inc. ("ISC") Permission to use, copy, modify, and distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. Hankins & Mrugalski [Page 1] ISC DHCP References Collection January 2012 Table of Contents 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . . 3 2. Definition: Reference Implementation . . . . . . . . . . . . . 3 3. Low Layer References . . . . . . . . . . . . . . . . . . . . . 4 3.1. Ethernet Protocol References . . . . . . . . . . . . . . . 6 3.2. Token Ring Protocol References . . . . . . . . . . . . . . 6 3.3. FDDI Protocol References . . . . . . . . . . . . . . . . . 6 3.4. Internet Protocol Version 4 References . . . . . . . . . . 6 3.5. Unicast Datagram Protocol References . . . . . . . . . . . 6 4. BOOTP Protocol References . . . . . . . . . . . . . . . . . . 6 5. DHCPv4 Protocol References . . . . . . . . . . . . . . . . . . 7 5.1. DHCPv4 Protocol . . . . . . . . . . . . . . . . . . . . . 7 5.1.1. Core Protocol References . . . . . . . . . . . . . . . 7 5.2. DHCPv4 Option References . . . . . . . . . . . . . . . . . 7 5.2.1. Relay Agent Information Option Options . . . . . . . . 9 5.2.2. Dynamic DNS Updates References . . . . . . . . . . . . 9 5.2.3. Experimental: Failover References . . . . . . . . . . 9 5.3. DHCP Procedures . . . . . . . . . . . . . . . . . . . . . 10 6. DHCPv6 Protocol References . . . . . . . . . . . . . . . . . . 10 6.1. DHCPv6 Protocol References . . . . . . . . . . . . . . . . 10 6.2. DHCPv6 Options References . . . . . . . . . . . . . . . . 11 7. References . . . . . . . . . . . . . . . . . . . . . . . . . . 12 7.1. Published DHCPv4 References . . . . . . . . . . . . . . . 12 7.2. Published Common (DHCPv4/DHCPv6) References . . . . . . . 17 7.3. Published DHCPv6 References . . . . . . . . . . . . . . . 18 Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . . . 20 Hankins & Mrugalski [Page 2] ISC DHCP References Collection January 2012 1. Introduction As a little historical anecdote, ISC DHCP once packaged all the relevant RFCs and standards documents along with the software package. Until one day when a voice was heard from one of the many fine institutions that build and distribute this software... they took issue with the IETF's copyright on the RFC's. It seems the IETF's copyrights don't allow modification of RFC's (except for translation purposes). Our main purpose in providing the RFCs is to aid in documentation, but since RFCs are now available widely from many points of distribution on the Internet, there is no real need to provide the documents themselves. So, this document has been created in their stead, to list the various IETF RFCs one might want to read, and to comment on how well (or poorly) we have managed to implement them. 2. Definition: Reference Implementation ISC DHCP, much like its other cousins in ISC software, is self- described as a 'Reference Implementation.' There has been a great deal of confusion about this term. Some people seem to think that this term applies to any software that once passed a piece of reference material on its way to market (but may do quite a lot of things that aren't described in any reference, or may choose to ignore the reference it saw entirely). Other folks get confused by the word 'reference' and understand that to mean that there is some special status applied to the software - that the software itself is the reference by which all other software is measured. Something along the lines of being "The DHCP Protocol's Reference Clock," it is supposed. The truth is actually quite a lot simpler. Reference implementations are software packages which were written to behave precisely as appears in reference material. They are written "to match reference." If the software has a behaviour that manifests itself externally (whether it be something as simple as the 'wire format' or something higher level, such as a complicated behaviour that arises from multiple message exchanges), that behaviour must be found in a reference document. Anything else is a bug, the only question is whether the bug is in reference or software (failing to implement the reference). This means: Hankins & Mrugalski [Page 3] ISC DHCP References Collection January 2012 o To produce new externally-visible behaviour, one must first provide a reference. o Before changing externally visible behaviour to work around simple incompatibilities in any other implementation, one must first provide a reference. That is the lofty goal, at any rate. It's well understood that, especially because the ISC DHCP Software package has not always been held to this standard (but not entirely due to it), there are many non-referenced behaviours within ISC DHCP. The primary goal of reference implementation is to prove the reference material. If the reference material is good, then you should be able to sit down and write a program that implements the reference, to the word, and come to an implementation that is distinguishable from others in the details, but not in the facts of operating the protocol. This means that there is no need for 'special knowledge' to work around arcane problems that were left undocumented. No secret handshakes need to be learned to be imparted with the necessary "real documentation". Also, by accepting only reference as the guidebook for ISC DHCP's software implementation, anyone who can make an impact on the color texture or form of that reference has a (somewhat indirect) voice in ISC DHCP's software design. As the IETF RFC's have been selected as the source of reference, that means everyone on the Internet with the will to participate has a say. 3. Low Layer References It may surprise you to realize that ISC DHCP implements 802.1 'Ethernet' framing, Token Ring, and FDDI. In order to bridge the gap there between these physical and DHCP layers, it must also implement IP and UDP framing. The reason for this stems from Unix systems' handling of BSD sockets (the general way one might engage in transmission of UDP packets) on unconfigured interfaces, or even the handling of broadcast addressing on configured interfaces. There are a few things that DHCP servers, relays, and clients all need to do in order to speak the DHCP protocol in strict compliance with [RFC2131]. 1. Transmit a UDP packet from IP:0.0.0.0 Ethernet:Self, destined to IP:255.255.255.255 LinkLayer:Broadcast on an unconfigured (no IP Hankins & Mrugalski [Page 4] ISC DHCP References Collection January 2012 address yet) interface. 2. Receive a UDP packet from IP:remote-system LinkLayer:remote- system, destined to IP:255.255.255.255 LinkLayer:Broadcast, again on an unconfigured interface. 3. Transmit a UDP packet from IP:Self, Ethernet:Self, destined to IP:remote-system LinkLayer:remote-system, without transmitting a single ARP. 4. And of course the simple case, a regular IP unicast that is routed via the usual means (so it may be direct to a local system, with ARP providing the glue, or it may be to a remote system via one or more routers as normal). In this case, the interfaces are always configured. The above isn't as simple as it sounds on a regular BSD socket. Many unix implementations will transmit broadcasts not to 255.255.255.255, but to x.y.z.255 (where x.y.z is the system's local subnet). Such packets are not received by several known DHCP client implementations - and it's not their fault, [RFC2131] very explicitly demands that these packets' IP destination addresses be set to 255.255.255.255. Receiving packets sent to 255.255.255.255 isn't a problem on most modern unixes...so long as the interface is configured. When there is no IPv4 address on the interface, things become much more murky. So, for this convoluted and unfortunate state of affairs in the unix systems of the day ISC DHCP was manufactured, in order to do what it needs not only to implement the reference but to interoperate with other implementations, the software must create some form of raw socket to operate on. What it actually does is create, for each interface detected on the system, a Berkeley Packet Filter socket (or equivalent), and program it with a filter that brings in only DHCP packets. A "fallback" UDP Berkeley socket is generally also created, a single one no matter how many interfaces. Should the software need to transmit a contrived packet to the local network the packet is formed piece by piece and transmitted via the BPF socket. Hence the need to implement many forms of Link Layer framing and above. The software gets away with not having to implement IP routing tables as well by simply utilizing the aforementioned 'fallback' UDP socket when unicasting between two configured systems is needed. Modern unixes have opened up some facilities that diminish how much of this sort of nefarious kludgery is necessary, but have not found the state of affairs absolutely resolved. In particular, one might Hankins & Mrugalski [Page 5] ISC DHCP References Collection January 2012 now unicast without ARP by inserting an entry into the ARP cache prior to transmitting. Unconfigured interfaces remain the sticking point, however...on virtually no modern unixes is it possible to receive broadcast packets unless a local IPv4 address has been configured, unless it is done with raw sockets. 3.1. Ethernet Protocol References ISC DHCP Implements Ethernet Version 2 ("DIX"), which is a variant of IEEE 802.2. No good reference of this framing is known to exist at this time, but it is vaguely described in [RFC0894] see the section titled "Packet format"), and the following URL is also thought to be useful. http://en.wikipedia.org/wiki/DIX_Ethernet 3.2. Token Ring Protocol References IEEE 802.5 defines the Token Ring framing format used by ISC DHCP. 3.3. FDDI Protocol References [RFC1188] is the most helpful reference ISC DHCP has used to form FDDI packets. 3.4. Internet Protocol Version 4 References RFC760 [RFC0760] fundamentally defines the bare IPv4 protocol which ISC DHCP implements. 3.5. Unicast Datagram Protocol References RFC768 [RFC0768] defines the User Datagram Protocol that ultimately carries the DHCP or BOOTP protocol. The destination DHCP server port is 67, the client port is 68. Source ports are irrelevant. 4. BOOTP Protocol References The DHCP Protocol is strange among protocols in that it is grafted over the top of another protocol - BOOTP (but we don't call it "DHCP over BOOTP" like we do, say "TCP over IP"). BOOTP and DHCP share UDP packet formats - DHCP is merely a conventional use of both BOOTP header fields and the trailing 'options' space. The ISC DHCP server supports BOOTP clients conforming to RFC951 [RFC0951] and RFC1542 [RFC1542]. Hankins & Mrugalski [Page 6] ISC DHCP References Collection January 2012 5. DHCPv4 Protocol References 5.1. DHCPv4 Protocol "The DHCP[v4] Protocol" is not defined in a single document. The following collection of references of what ISC DHCP terms "The DHCPv4 Protocol". 5.1.1. Core Protocol References RFC2131 [RFC2131] defines the protocol format and procedures. ISC DHCP is not known to diverge from this document in any way. There are, however, a few points on which different implementations have arisen out of vagueries in the document. DHCP Clients exist which, at one time, present themselves as using a Client Identifier Option which is equal to the client's hardware address. Later, the client transmits DHCP packets with no Client Identifier Option present - essentially identifying themselves using the hardware address. Some DHCP Servers have been developed which identify this client as a single client. ISC has interpreted RFC2131 to indicate that these clients must be treated as two separate entities (and hence two, separate addresses). Client behaviour (Embedded Windows products) has developed that relies on the former implementation, and hence is incompatible with the latter. Also, RFC2131 demands explicitly that some header fields be zeroed upon certain message types. The ISC DHCP Server instead copies many of these fields from the packet received from the client or relay, which may not be zero. It is not known if there is a good reason for this that has not been documented. RFC2132 [RFC2132] defines the initial set of DHCP Options and provides a great deal of guidance on how to go about formatting and processing options. The document unfortunately waffles to a great extent about the NULL termination of DHCP Options, and some DHCP Clients (Windows 95) have been implemented that rely upon DHCP Options containing text strings to be NULL-terminated (or else they crash). So, ISC DHCP detects if clients null-terminate the host-name option and, if so, null terminates any text options it transmits to the client. It also removes NULL termination from any known text option it receives prior to any other processing. 5.2. DHCPv4 Option References RFC2241 [RFC2241] defines options for Novell Directory Services. RFC2242 [RFC2242] defines an encapsulated option space for NWIP configuration. Hankins & Mrugalski [Page 7] ISC DHCP References Collection January 2012 RFC2485 [RFC2485] defines the Open Group's UAP option. RFC2610 [RFC2610] defines options for the Service Location Protocol (SLP). RFC2937 [RFC2937] defines the Name Service Search Option (not to be confused with the domain-search option). The Name Service Search Option allows eg nsswitch.conf to be reconfigured via dhcp. The ISC DHCP server implements this option, and the ISC DHCP client is compatible...but does not by default install this option's value. One would need to make their relevant dhclient-script process this option in a way that is suitable for the system. RFC3004 [RFC3004] defines the User-Class option. Note carefully that ISC DHCP currently does not implement to this reference, but has (inexplicably) selected an incompatible format: a plain text string. RFC3011 [RFC3011] defines the Subnet-Selection plain DHCPv4 option. Do not confuse this option with the relay agent "link selection" sub- option, although their behaviour is similar. RFC3396 [RFC3396] documents both how long options may be encoded in DHCPv4 packets, and also how multiple instances of the same option code within a DHCPv4 packet will be decoded by receivers. RFC3397 [RFC3397] documents the Domain-Search Option, which allows the configuration of the /etc/resolv.conf 'search' parameter in a way that is RFC1035 [RFC1035] wire format compatible (in fact, it uses the RFC1035 wire format). ISC DHCP has both client and server support, and supports RFC1035 name compression. RFC3679 [RFC3679] documents a number of options that were documented earlier in history, but were not made use of. RFC3925 [RFC3925] documents a pair of Enterprise-ID delimited option spaces for vendors to use in order to inform servers of their "vendor class" (sort of like 'uname' or 'who and what am I'), and a means to deliver vendor-specific and vendor-documented option codes and values. RFC3942 [RFC3942] redefined the 'site local' option space. [RFC4280] defines two BCMS server options for each protocol family. RFC4388 [RFC4388] defined the DHCPv4 LEASEQUERY message type and a number of suitable response messages, for the purpose of sharing information about DHCP served addresses and clients. Hankins & Mrugalski [Page 8] ISC DHCP References Collection January 2012 5.2.1. Relay Agent Information Option Options RFC3046 [RFC3046] defines the Relay Agent Information Option and provides a number of sub-option definitions. RFC3256 [RFC3256] defines the DOCSIS Device Class sub-option. RFC3527 [RFC3527] defines the Link Selection sub-option. 5.2.2. Dynamic DNS Updates References The collection of documents that describe the standards-based method to update dns names of DHCP clients starts most easily with RFC4703 [RFC4703] to define the overall architecture, travels through RFCs 4702 [RFC4702] and 4704 [RFC4704] to describe the DHCPv4 and DHCPv6 FQDN options (to carry the client name), and ends up at RFC4701 [RFC4701] which describes the DHCID RR used in DNS to perform a kind of atomic locking. ISC DHCP adopted early versions of these documents, and has not yet synchronized with the final standards versions. For RFCs 4702 and 4704, the 'N' bit is not yet supported. The result is that it is always set zero, and is ignored if set. For RFC4701, which is used to match client identities with names in the DNS as part of name conflict resolution. Note that ISC DHCP's implementation of DHCIDs vary wildly from this specification. First, ISC DHCP uses a TXT record in which the contents are stored in hexadecimal. Second, there is a flaw in the selection of the 'Identifier Type', which results in a completely different value being selected than was defined in an older revision of this document...also this field is one byte prior to hexadecimal encoding rather than two. Third, ISC DHCP does not use a digest type code. Rather, all values for such TXT records are reached via an MD5 sum. In short, nothing is compatible, but the principle of the TXT record is the same as the standard DHCID record. However, for DHCPv6 FQDN, we do use DHCID type code '2', as no other value really makes sense in our context. 5.2.3. Experimental: Failover References The Failover Protocol defines means by which two DHCP Servers can share all the relevant information about leases granted to DHCP clients on given networks, so that one of the two servers may fail and be survived by a server that can act responsibly. Unfortunately it has been quite some years (2003) since the last time Hankins & Mrugalski [Page 9] ISC DHCP References Collection January 2012 this document was edited, and the authors no longer show any interest in fielding comments or improving the document. The status of this protocol is very unsure, but ISC's implementation of it has proven stable and suitable for use in sizable production environments. draft-ietf-dhc-failover-12.txt [draft-failover] describes the Failover Protocol. In addition to what is described in this document, ISC DHCP has elected to make some experimental changes that may be revoked in a future version of ISC DHCP (if the draft authors do not adopt the new behaviour). Specifically, ISC DHCP's POOLREQ behaviour differs substantially from what is documented in the draft, and the server also implements a form of 'MAC Address Affinity' which is not described in the failover document. The full nature of these changes have been described on the IETF DHC WG mailing list (which has archives), and also in ISC DHCP's manual pages. Also note that although this document references a RECOVER-WAIT state, it does not document a protocol number assignment for this state. As a consequence, ISC DHCP has elected to use the value 254. An optimization described in the failover protocol draft is included since 4.2.0a1. It permits a DHCP server operating in communications- interrupted state to 'rewind' a lease to the state most recently transmitted to its peer, greatly increasing a server's endurance in communications-interrupted. This is supported using a new 'rewind state' record on the dhcpd.leases entry for each lease. [RFC3074] describes the Load Balancing Algorithm (LBA) that ISC DHCP uses in concert with the Failover protocol. Note that versions 3.0.* are known to misimplement the hash algorithm (it will only use the low 4 bits of every byte of the hash bucket array). 5.3. DHCP Procedures [RFC2939] explains how to go about obtaining a new DHCP Option code assignment. 6. DHCPv6 Protocol References 6.1. DHCPv6 Protocol References For now there is only one document that specifies the base of the DHCPv6 protocol (there have been no updates yet), [RFC3315]. Support for DHCPv6 was first added in version 4.0.0. The server and client support only IA_NA. While the server does support multiple Hankins & Mrugalski [Page 10] ISC DHCP References Collection January 2012 IA_NAs within one packet from the client, our client only supports sending one. There is no relay support. DHCPv6 introduces some new and uncomfortable ideas to the common software library. 1. Options sometimes may appear multiple times. The common library used to treat all appearance of multiple options as specified in RFC2131 - to be concatenated. DHCPv6 options may sometimes appear multiple times (such as with IA_NA or IAADDR), but often must not. As of 4.2.1-P1, multiple IA_NA, IA_PD or IA_TA are not supported. 2. The same option space appears in DHCPv6 packets multiple times. If the packet was got via a relay, then the client's packet is stored to an option within the relay's packet...if there were two relays, this recurses. At each of these steps, the root "DHCPv6 option space" is used. Further, a client packet may contain an IA_NA, which may contain an IAADDR - but really, in an abstract sense, this is again re-encapsulation of the DHCPv6 option space beneath options it also contains. Precisely how to correctly support the above conundrums has not quite yet been settled, so support is incomplete. [RFC5453] creates a registry at IANA to reserve interface identifiers and specifies a starting set. These IIDs should not be used when constructing addresses to avoid possible conflicts. 6.2. DHCPv6 Options References [RFC3319] defines the SIP server options for DHCPv6. [RFC3646] documents the DHCPv6 name-servers and domain-search options. [RFC3633] documents the Identity Association Prefix Delegation for DHCPv6, which is included here for protocol wire reference, but which is not supported by ISC DHCP. [RFC3898] documents four NIS options for delivering NIS servers and domain information in DHCPv6. [RFC4075] defines the DHCPv6 SNTP Servers option. [RFC4242] defines the Information Refresh Time option, which advises DHCPv6 Information-Request clients to return for updated information. Hankins & Mrugalski [Page 11] ISC DHCP References Collection January 2012 [RFC4280] defines two BCMS server options for each protocol family. [RFC4580] defines a DHCPv6 subscriber-id option, which is similar in principle to the DHCPv4 relay agent option of the same name. [RFC4649] defines a DHCPv6 remote-id option, which is similar in principle to the DHCPv4 relay agent remote-id. 7. References 7.1. Published DHCPv4 References [RFC0760] Postel, J., "DoD standard Internet Protocol", RFC 760, January 1980. [RFC0768] Postel, J., "User Datagram Protocol", STD 6, RFC 768, August 1980. [RFC0894] Hornig, C., "Standard for the transmission of IP datagrams over Ethernet networks", STD 41, RFC 894, April 1984. [RFC0951] Croft, B. and J. Gilmore, "Bootstrap Protocol", RFC 951, September 1985. [RFC1035] Mockapetris, P., "Domain names - implementation and specification", STD 13, RFC 1035, November 1987. [RFC1188] Katz, D., "Proposed Standard for the Transmission of IP Datagrams over FDDI Networks", RFC 1188, October 1990. [RFC1542] Wimer, W., "Clarifications and Extensions for the Bootstrap Protocol", RFC 1542, October 1993. [RFC2131] Droms, R., "Dynamic Host Configuration Protocol", RFC 2131, March 1997. [RFC2132] Alexander, S. and R. Droms, "DHCP Options and BOOTP Vendor Extensions", RFC 2132, March 1997. [RFC2241] Provan, D., "DHCP Options for Novell Directory Services", RFC 2241, November 1997. [RFC2242] Droms, R. and K. Fong, "NetWare/IP Domain Name and Information", RFC 2242, November 1997. [RFC2485] Drach, S., "DHCP Option for The Open Group's User Authentication Protocol", RFC 2485, January 1999. Hankins & Mrugalski [Page 12] ISC DHCP References Collection January 2012 [RFC2563] Troll, R., "DHCP Option to Disable Stateless Auto- Configuration in IPv4 Clients", RFC 2563, May 1999. [RFC2610] Perkins, C. and E. Guttman, "DHCP Options for Service Location Protocol", RFC 2610, June 1999. [RFC2855] Fujisawa, K., "DHCP for IEEE 1394", RFC 2855, June 2000. [RFC2937] Smith, C., "The Name Service Search Option for DHCP", RFC 2937, September 2000. [RFC2939] Droms, R., "Procedures and IANA Guidelines for Definition of New DHCP Options and Message Types", BCP 43, RFC 2939, September 2000. [RFC3004] Stump, G., Droms, R., Gu, Y., Vyaghrapuri, R., Demirtjis, A., Beser, B., and J. Privat, "The User Class Option for DHCP", RFC 3004, November 2000. [RFC3011] Waters, G., "The IPv4 Subnet Selection Option for DHCP", RFC 3011, November 2000. [RFC3046] Patrick, M., "DHCP Relay Agent Information Option", RFC 3046, January 2001. [RFC3074] Volz, B., Gonczi, S., Lemon, T., and R. Stevens, "DHC Load Balancing Algorithm", RFC 3074, February 2001. [RFC3118] Droms, R. and W. Arbaugh, "Authentication for DHCP Messages", RFC 3118, June 2001. [RFC3203] T'Joens, Y., Hublet, C., and P. De Schrijver, "DHCP reconfigure extension", RFC 3203, December 2001. [RFC3256] Jones, D. and R. Woundy, "The DOCSIS (Data-Over-Cable Service Interface Specifications) Device Class DHCP (Dynamic Host Configuration Protocol) Relay Agent Information Sub-option", RFC 3256, April 2002. [RFC3361] Schulzrinne, H., "Dynamic Host Configuration Protocol (DHCP-for-IPv4) Option for Session Initiation Protocol (SIP) Servers", RFC 3361, August 2002. [RFC3396] Lemon, T. and S. Cheshire, "Encoding Long Options in the Dynamic Host Configuration Protocol (DHCPv4)", RFC 3396, November 2002. [RFC3397] Aboba, B. and S. Cheshire, "Dynamic Host Configuration Hankins & Mrugalski [Page 13] ISC DHCP References Collection January 2012 Protocol (DHCP) Domain Search Option", RFC 3397, November 2002. [RFC3442] Lemon, T., Cheshire, S., and B. Volz, "The Classless Static Route Option for Dynamic Host Configuration Protocol (DHCP) version 4", RFC 3442, December 2002. [RFC3456] Patel, B., Aboba, B., Kelly, S., and V. Gupta, "Dynamic Host Configuration Protocol (DHCPv4) Configuration of IPsec Tunnel Mode", RFC 3456, January 2003. [RFC3495] Beser, B. and P. Duffy, "Dynamic Host Configuration Protocol (DHCP) Option for CableLabs Client Configuration", RFC 3495, March 2003. [RFC3527] Kinnear, K., Stapp, M., Johnson, R., and J. Kumarasamy, "Link Selection sub-option for the Relay Agent Information Option for DHCPv4", RFC 3527, April 2003. [RFC3594] Duffy, P., "PacketCable Security Ticket Control Sub-Option for the DHCP CableLabs Client Configuration (CCC) Option", RFC 3594, September 2003. [RFC3634] Luehrs, K., Woundy, R., Bevilacqua, J., and N. Davoust, "Key Distribution Center (KDC) Server Address Sub-option for the Dynamic Host Configuration Protocol (DHCP) CableLabs Client Configuration (CCC) Option", RFC 3634, December 2003. [RFC3679] Droms, R., "Unused Dynamic Host Configuration Protocol (DHCP) Option Codes", RFC 3679, January 2004. [RFC3825] Polk, J., Schnizlein, J., and M. Linsner, "Dynamic Host Configuration Protocol Option for Coordinate-based Location Configuration Information", RFC 3825, July 2004. [RFC3925] Littlefield, J., "Vendor-Identifying Vendor Options for Dynamic Host Configuration Protocol version 4 (DHCPv4)", RFC 3925, October 2004. [RFC3942] Volz, B., "Reclassifying Dynamic Host Configuration Protocol version 4 (DHCPv4) Options", RFC 3942, November 2004. [RFC3993] Johnson, R., Palaniappan, T., and M. Stapp, "Subscriber-ID Suboption for the Dynamic Host Configuration Protocol (DHCP) Relay Agent Option", RFC 3993, March 2005. Hankins & Mrugalski [Page 14] ISC DHCP References Collection January 2012 [RFC4014] Droms, R. and J. Schnizlein, "Remote Authentication Dial-In User Service (RADIUS) Attributes Suboption for the Dynamic Host Configuration Protocol (DHCP) Relay Agent Information Option", RFC 4014, February 2005. [RFC4030] Stapp, M. and T. Lemon, "The Authentication Suboption for the Dynamic Host Configuration Protocol (DHCP) Relay Agent Option", RFC 4030, March 2005. [RFC4039] Park, S., Kim, P., and B. Volz, "Rapid Commit Option for the Dynamic Host Configuration Protocol version 4 (DHCPv4)", RFC 4039, March 2005. [RFC4174] Monia, C., Tseng, J., and K. Gibbons, "The IPv4 Dynamic Host Configuration Protocol (DHCP) Option for the Internet Storage Name Service", RFC 4174, September 2005. [RFC4243] Stapp, M., Johnson, R., and T. Palaniappan, "Vendor- Specific Information Suboption for the Dynamic Host Configuration Protocol (DHCP) Relay Agent Option", RFC 4243, December 2005. [RFC4361] Lemon, T. and B. Sommerfeld, "Node-specific Client Identifiers for Dynamic Host Configuration Protocol Version Four (DHCPv4)", RFC 4361, February 2006. [RFC4388] Woundy, R. and K. Kinnear, "Dynamic Host Configuration Protocol (DHCP) Leasequery", RFC 4388, February 2006. [RFC4390] Kashyap, V., "Dynamic Host Configuration Protocol (DHCP) over InfiniBand", RFC 4390, April 2006. [RFC4436] Aboba, B., Carlson, J., and S. Cheshire, "Detecting Network Attachment in IPv4 (DNAv4)", RFC 4436, March 2006. [RFC4701] Stapp, M., Lemon, T., and A. Gustafsson, "A DNS Resource Record (RR) for Encoding Dynamic Host Configuration Protocol (DHCP) Information (DHCID RR)", RFC 4701, October 2006. [RFC4702] Stapp, M., Volz, B., and Y. Rekhter, "The Dynamic Host Configuration Protocol (DHCP) Client Fully Qualified Domain Name (FQDN) Option", RFC 4702, October 2006. [RFC4703] Stapp, M. and B. Volz, "Resolution of Fully Qualified Domain Name (FQDN) Conflicts among Dynamic Host Configuration Protocol (DHCP) Clients", RFC 4703, October 2006. Hankins & Mrugalski [Page 15] ISC DHCP References Collection January 2012 [RFC5010] Kinnear, K., Normoyle, M., and M. Stapp, "The Dynamic Host Configuration Protocol Version 4 (DHCPv4) Relay Agent Flags Suboption", RFC 5010, September 2007. [RFC5071] Hankins, D., "Dynamic Host Configuration Protocol Options Used by PXELINUX", RFC 5071, December 2007. [RFC5107] Johnson, R., Kumarasamy, J., Kinnear, K., and M. Stapp, "DHCP Server Identifier Override Suboption", RFC 5107, February 2008. [RFC5192] Morand, L., Yegin, A., Kumar, S., and S. Madanapalli, "DHCP Options for Protocol for Carrying Authentication for Network Access (PANA) Authentication Agents", RFC 5192, May 2008. [RFC5223] Schulzrinne, H., Polk, J., and H. Tschofenig, "Discovering Location-to-Service Translation (LoST) Servers Using the Dynamic Host Configuration Protocol (DHCP)", RFC 5223, August 2008. [RFC5859] Johnson, R., "TFTP Server Address Option for DHCPv4", RFC 5859, June 2010. [RFC5969] Townsley, W. and O. Troan, "IPv6 Rapid Deployment on IPv4 Infrastructures (6rd) -- Protocol Specification", RFC 5969, August 2010. [draft-failover] Droms, R., "DHCP Failover Protocol", March 2003. [I-D.ietf-dhc-dhcpv4-relay-encapsulation] Lemon, T. and H. Deng, "Relay Agent Encapsulation for DHCPv4", draft-ietf-dhc-dhcpv4-relay-encapsulation-00 (work in progress), October 2010. [I-D.ietf-dhc-dhcpv4-bulk-leasequery] Kinnear, K., Volz, B., Russell, N., Stapp, M., Rao, D., Joshi, B., and P. Kurapati, "Bulk DHCPv4 Lease Query", draft-ietf-dhc-dhcpv4-bulk-leasequery-03 (work in progress), October 2010. [I-D.ietf-dhc-leasequery-by-remote-id] Kurapati, P. and B. Joshi, "DHCPv4 lease query by Relay Agent Remote ID", draft-ietf-dhc-leasequery-by-remote-id-09 (work in progress), December 2010. Hankins & Mrugalski [Page 16] ISC DHCP References Collection January 2012 [I-D.ietf-dhc-relay-id-suboption] Stapp, M., "The DHCPv4 Relay Agent Identifier Suboption", draft-ietf-dhc-relay-id-suboption-07 (work in progress), July 2009. [I-D.ietf-mip6-hiopt] Jang, H., Yegin, A., Chowdhury, K., and J. Choi, "DHCP Options for Home Information Discovery in MIPv6", draft-ietf-mip6-hiopt-17 (work in progress), May 2008. 7.2. Published Common (DHCPv4/DHCPv6) References [RFC4280] Chowdhury, K., Yegani, P., and L. Madour, "Dynamic Host Configuration Protocol (DHCP) Options for Broadcast and Multicast Control Servers", RFC 4280, November 2005. [RFC4477] Chown, T., Venaas, S., and C. Strauf, "Dynamic Host Configuration Protocol (DHCP): IPv4 and IPv6 Dual-Stack Issues", RFC 4477, May 2006. [RFC4578] Johnston, M. and S. Venaas, "Dynamic Host Configuration Protocol (DHCP) Options for the Intel Preboot eXecution Environment (PXE)", RFC 4578, November 2006. [RFC4776] Schulzrinne, H., "Dynamic Host Configuration Protocol (DHCPv4 and DHCPv6) Option for Civic Addresses Configuration Information", RFC 4776, November 2006. [RFC4833] Lear, E. and P. Eggert, "Timezone Options for DHCP", RFC 4833, April 2007. [RFC5417] Calhoun, P., "Control And Provisioning of Wireless Access Points (CAPWAP) Access Controller DHCP Option", RFC 5417, March 2009. [RFC5678] Bajko, G. and S. Das, "Dynamic Host Configuration Protocol (DHCPv4 and DHCPv6) Options for IEEE 802.21 Mobility Services (MoS) Discovery", RFC 5678, December 2009. [RFC5908] Gayraud, R. and B. Lourdelet, "Network Time Protocol (NTP) Server Option for DHCPv6", RFC 5908, June 2010. [RFC5970] Huth, T., Freimann, J., Zimmer, V., and D. Thaler, "DHCPv6 Options for Network Boot", RFC 5970, September 2010. [RFC5986] Thomson, M. and J. Winterbottom, "Discovering the Local Location Information Server (LIS)", RFC 5986, September 2010. Hankins & Mrugalski [Page 17] ISC DHCP References Collection January 2012 [I-D.ietf-dhc-vpn-option] Kinnear, K., Johnson, R., and M. Stapp, "Virtual Subnet Selection Options for DHCPv4 and DHCPv6", draft-ietf-dhc-vpn-option-12 (work in progress), October 2010. 7.3. Published DHCPv6 References [RFC3315] Droms, R., Bound, J., Volz, B., Lemon, T., Perkins, C., and M. Carney, "Dynamic Host Configuration Protocol for IPv6 (DHCPv6)", RFC 3315, July 2003. [RFC3319] Schulzrinne, H. and B. Volz, "Dynamic Host Configuration Protocol (DHCPv6) Options for Session Initiation Protocol (SIP) Servers", RFC 3319, July 2003. [RFC3633] Troan, O. and R. Droms, "IPv6 Prefix Options for Dynamic Host Configuration Protocol (DHCP) version 6", RFC 3633, December 2003. [RFC3646] Droms, R., "DNS Configuration options for Dynamic Host Configuration Protocol for IPv6 (DHCPv6)", RFC 3646, December 2003. [RFC3736] Droms, R., "Stateless Dynamic Host Configuration Protocol (DHCP) Service for IPv6", RFC 3736, April 2004. [RFC3898] Kalusivalingam, V., "Network Information Service (NIS) Configuration Options for Dynamic Host Configuration Protocol for IPv6 (DHCPv6)", RFC 3898, October 2004. [RFC4075] Kalusivalingam, V., "Simple Network Time Protocol (SNTP) Configuration Option for DHCPv6", RFC 4075, May 2005. [RFC4076] Chown, T., Venaas, S., and A. Vijayabhaskar, "Renumbering Requirements for Stateless Dynamic Host Configuration Protocol for IPv6 (DHCPv6)", RFC 4076, May 2005. [RFC4242] Venaas, S., Chown, T., and B. Volz, "Information Refresh Time Option for Dynamic Host Configuration Protocol for IPv6 (DHCPv6)", RFC 4242, November 2005. [RFC4580] Volz, B., "Dynamic Host Configuration Protocol for IPv6 (DHCPv6) Relay Agent Subscriber-ID Option", RFC 4580, June 2006. [RFC4649] Volz, B., "Dynamic Host Configuration Protocol for IPv6 (DHCPv6) Relay Agent Remote-ID Option", RFC 4649, Hankins & Mrugalski [Page 18] ISC DHCP References Collection January 2012 August 2006. [RFC4704] Volz, B., "The Dynamic Host Configuration Protocol for IPv6 (DHCPv6) Client Fully Qualified Domain Name (FQDN) Option", RFC 4704, October 2006. [RFC4994] Zeng, S., Volz, B., Kinnear, K., and J. Brzozowski, "DHCPv6 Relay Agent Echo Request Option", RFC 4994, September 2007. [RFC5007] Brzozowski, J., Kinnear, K., Volz, B., and S. Zeng, "DHCPv6 Leasequery", RFC 5007, September 2007. [RFC5453] Krishnan, S., "Reserved IPv6 Interface Identifiers", RFC 5453, February 2009. [RFC5460] Stapp, M., "DHCPv6 Bulk Leasequery", RFC 5460, February 2009. [I-D.ietf-mif-dhcpv6-route-option] Dec, W., Mrugalski, T., Sun, T., and B. Sarikaya, "DHCPv6 Route Options", draft-ietf-mif-dhcpv6-route-option-03 (work in progress), September 2011. [I-D.ietf-dhc-dhcpv6-ldra] Miles, D., Ooghe, S., Dec, W., Krishnan, S., and A. Kavanagh, "Lightweight DHCPv6 Relay Agent", draft-ietf-dhc-dhcpv6-ldra-03 (work in progress), October 2010. [I-D.ietf-dhc-dhcpv6-relay-supplied-options] Lemon, T. and W. Wu, "Relay-Supplied DHCP Options", draft-ietf-dhc-dhcpv6-relay-supplied-options-09 (work in progress), September 2011. [I-D.ietf-dhc-pd-exclude] Korhonen, J., Savolainen, T., Krishnan, S., and O. Troan, "Prefix Exclude Option for DHCPv6-based Prefix Delegation", draft-ietf-dhc-pd-exclude-01 (work in progress), January 2011. [I-D.ietf-dhc-secure-dhcpv6] Jiang, S., "Secure DHCPv6 Using CGAs", draft-ietf-dhc-secure-dhcpv6-02 (work in progress), December 2010. [I-D.ietf-mext-nemo-pd] Droms, R., Thubert, P., Dupont, F., Haddad, W., and C. Hankins & Mrugalski [Page 19] ISC DHCP References Collection January 2012 Bernardos, "DHCPv6 Prefix Delegation for NEMO", draft-ietf-mext-nemo-pd-07 (work in progress), December 2010. [I-D.ietf-dhc-duid-uuid] Narten, T. and J. Johnson, "Definition of the UUID-based DHCPv6 Unique Identifier (DUID-UUID)", draft-ietf-dhc-duid-uuid-03 (work in progress), February 2011. [I-D.ietf-softwire-ds-lite-tunnel-option] Hankins, D. and T. Mrugalski, "Dynamic Host Configuration Protocol for IPv6 (DHCPv6) Option for Dual- Stack Lite", draft-ietf-softwire-ds-lite-tunnel-option-10 (work in progress), March 2011. [I-D.ietf-mif-dns-server-selection] Savolainen, T. and J. Kato, "Improved DNS Server Selection for Multi-Homed Nodes", draft-ietf-mif-dns-server-selection-01 (work in progress), March 2011. [I-D.ietf-geopriv-rfc3825bis] Polk, J., Linsner, M., Thomson, M., and B. Aboba, "Dynamic Host Configuration Protocol Options for Coordinate-based Location Configuration Information", draft-ietf-geopriv-rfc3825bis-17 (work in progress), February 2011. [draft-addr-params] Mrugalski, T., "Address Parameters Option for DHCPv6", April 2007. Authors' Addresses David W. Hankins Internet Systems Consortium, Inc. 950 Charter Street Redwood City, CA 94063 Hankins & Mrugalski [Page 20] ISC DHCP References Collection January 2012 Tomasz Mrugalski Internet Systems Consortium, Inc. 950 Charter Street Redwood City, CA 94063 Phone: +1 650 423 1345 Email: Tomasz_Mrugalski@isc.org Hankins & Mrugalski [Page 21] dhcp-4.2.4/doc/References.xml000644 000765 000024 00000106264 11701164253 015750 0ustar00sarstaff000000 000000 ]> ISC DHCP References Collection Internet Systems Consortium, Inc.
950 Charter Street Redwood City CA 94063
Internet Systems Consortium, Inc.
950 Charter Street Redwood City CA 94063 +1 650 423 1345 Tomasz_Mrugalski@isc.org
ISC DHCP Reference Implementation This document describes a collection of reference material to which ISC DHCP has been implemented as well as a more complete listing of references for DHCP and DHCPv6 protocols. Copyright (c) 2006-2007,2009,2011 by Internet Systems Consortium, Inc. ("ISC") Permission to use, copy, modify, and distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
As a little historical anecdote, ISC DHCP once packaged all the relevant RFCs and standards documents along with the software package. Until one day when a voice was heard from one of the many fine institutions that build and distribute this software... they took issue with the IETF's copyright on the RFC's. It seems the IETF's copyrights don't allow modification of RFC's (except for translation purposes). Our main purpose in providing the RFCs is to aid in documentation, but since RFCs are now available widely from many points of distribution on the Internet, there is no real need to provide the documents themselves. So, this document has been created in their stead, to list the various IETF RFCs one might want to read, and to comment on how well (or poorly) we have managed to implement them.
ISC DHCP, much like its other cousins in ISC software, is self-described as a 'Reference Implementation.' There has been a great deal of confusion about this term. Some people seem to think that this term applies to any software that once passed a piece of reference material on its way to market (but may do quite a lot of things that aren't described in any reference, or may choose to ignore the reference it saw entirely). Other folks get confused by the word 'reference' and understand that to mean that there is some special status applied to the software - that the software itself is the reference by which all other software is measured. Something along the lines of being "The DHCP Protocol's Reference Clock," it is supposed. The truth is actually quite a lot simpler. Reference implementations are software packages which were written to behave precisely as appears in reference material. They are written "to match reference." If the software has a behaviour that manifests itself externally (whether it be something as simple as the 'wire format' or something higher level, such as a complicated behaviour that arises from multiple message exchanges), that behaviour must be found in a reference document. Anything else is a bug, the only question is whether the bug is in reference or software (failing to implement the reference). This means: To produce new externally-visible behaviour, one must first provide a reference. Before changing externally visible behaviour to work around simple incompatibilities in any other implementation, one must first provide a reference. That is the lofty goal, at any rate. It's well understood that, especially because the ISC DHCP Software package has not always been held to this standard (but not entirely due to it), there are many non-referenced behaviours within ISC DHCP. The primary goal of reference implementation is to prove the reference material. If the reference material is good, then you should be able to sit down and write a program that implements the reference, to the word, and come to an implementation that is distinguishable from others in the details, but not in the facts of operating the protocol. This means that there is no need for 'special knowledge' to work around arcane problems that were left undocumented. No secret handshakes need to be learned to be imparted with the necessary "real documentation". Also, by accepting only reference as the guidebook for ISC DHCP's software implementation, anyone who can make an impact on the color texture or form of that reference has a (somewhat indirect) voice in ISC DHCP's software design. As the IETF RFC's have been selected as the source of reference, that means everyone on the Internet with the will to participate has a say.
It may surprise you to realize that ISC DHCP implements 802.1 'Ethernet' framing, Token Ring, and FDDI. In order to bridge the gap there between these physical and DHCP layers, it must also implement IP and UDP framing. The reason for this stems from Unix systems' handling of BSD sockets (the general way one might engage in transmission of UDP packets) on unconfigured interfaces, or even the handling of broadcast addressing on configured interfaces. There are a few things that DHCP servers, relays, and clients all need to do in order to speak the DHCP protocol in strict compliance with . Transmit a UDP packet from IP:0.0.0.0 Ethernet:Self, destined to IP:255.255.255.255 LinkLayer:Broadcast on an unconfigured (no IP address yet) interface. Receive a UDP packet from IP:remote-system LinkLayer:remote-system, destined to IP:255.255.255.255 LinkLayer:Broadcast, again on an unconfigured interface. Transmit a UDP packet from IP:Self, Ethernet:Self, destined to IP:remote-system LinkLayer:remote-system, without transmitting a single ARP. And of course the simple case, a regular IP unicast that is routed via the usual means (so it may be direct to a local system, with ARP providing the glue, or it may be to a remote system via one or more routers as normal). In this case, the interfaces are always configured. The above isn't as simple as it sounds on a regular BSD socket. Many unix implementations will transmit broadcasts not to 255.255.255.255, but to x.y.z.255 (where x.y.z is the system's local subnet). Such packets are not received by several known DHCP client implementations - and it's not their fault, very explicitly demands that these packets' IP destination addresses be set to 255.255.255.255. Receiving packets sent to 255.255.255.255 isn't a problem on most modern unixes...so long as the interface is configured. When there is no IPv4 address on the interface, things become much more murky. So, for this convoluted and unfortunate state of affairs in the unix systems of the day ISC DHCP was manufactured, in order to do what it needs not only to implement the reference but to interoperate with other implementations, the software must create some form of raw socket to operate on. What it actually does is create, for each interface detected on the system, a Berkeley Packet Filter socket (or equivalent), and program it with a filter that brings in only DHCP packets. A "fallback" UDP Berkeley socket is generally also created, a single one no matter how many interfaces. Should the software need to transmit a contrived packet to the local network the packet is formed piece by piece and transmitted via the BPF socket. Hence the need to implement many forms of Link Layer framing and above. The software gets away with not having to implement IP routing tables as well by simply utilizing the aforementioned 'fallback' UDP socket when unicasting between two configured systems is needed. Modern unixes have opened up some facilities that diminish how much of this sort of nefarious kludgery is necessary, but have not found the state of affairs absolutely resolved. In particular, one might now unicast without ARP by inserting an entry into the ARP cache prior to transmitting. Unconfigured interfaces remain the sticking point, however...on virtually no modern unixes is it possible to receive broadcast packets unless a local IPv4 address has been configured, unless it is done with raw sockets.
ISC DHCP Implements Ethernet Version 2 ("DIX"), which is a variant of IEEE 802.2. No good reference of this framing is known to exist at this time, but it is vaguely described in see the section titled "Packet format"), and the following URL is also thought to be useful. http://en.wikipedia.org/wiki/DIX_Ethernet
IEEE 802.5 defines the Token Ring framing format used by ISC DHCP.
is the most helpful reference ISC DHCP has used to form FDDI packets.
RFC760 fundamentally defines the bare IPv4 protocol which ISC DHCP implements.
RFC768 defines the User Datagram Protocol that ultimately carries the DHCP or BOOTP protocol. The destination DHCP server port is 67, the client port is 68. Source ports are irrelevant.
The DHCP Protocol is strange among protocols in that it is grafted over the top of another protocol - BOOTP (but we don't call it "DHCP over BOOTP" like we do, say "TCP over IP"). BOOTP and DHCP share UDP packet formats - DHCP is merely a conventional use of both BOOTP header fields and the trailing 'options' space. The ISC DHCP server supports BOOTP clients conforming to RFC951 and RFC1542.
"The DHCP[v4] Protocol" is not defined in a single document. The following collection of references of what ISC DHCP terms "The DHCPv4 Protocol".
RFC2131 defines the protocol format and procedures. ISC DHCP is not known to diverge from this document in any way. There are, however, a few points on which different implementations have arisen out of vagueries in the document. DHCP Clients exist which, at one time, present themselves as using a Client Identifier Option which is equal to the client's hardware address. Later, the client transmits DHCP packets with no Client Identifier Option present - essentially identifying themselves using the hardware address. Some DHCP Servers have been developed which identify this client as a single client. ISC has interpreted RFC2131 to indicate that these clients must be treated as two separate entities (and hence two, separate addresses). Client behaviour (Embedded Windows products) has developed that relies on the former implementation, and hence is incompatible with the latter. Also, RFC2131 demands explicitly that some header fields be zeroed upon certain message types. The ISC DHCP Server instead copies many of these fields from the packet received from the client or relay, which may not be zero. It is not known if there is a good reason for this that has not been documented. RFC2132 defines the initial set of DHCP Options and provides a great deal of guidance on how to go about formatting and processing options. The document unfortunately waffles to a great extent about the NULL termination of DHCP Options, and some DHCP Clients (Windows 95) have been implemented that rely upon DHCP Options containing text strings to be NULL-terminated (or else they crash). So, ISC DHCP detects if clients null-terminate the host-name option and, if so, null terminates any text options it transmits to the client. It also removes NULL termination from any known text option it receives prior to any other processing.
RFC2241 defines options for Novell Directory Services. RFC2242 defines an encapsulated option space for NWIP configuration. RFC2485 defines the Open Group's UAP option. RFC2610 defines options for the Service Location Protocol (SLP). RFC2937 defines the Name Service Search Option (not to be confused with the domain-search option). The Name Service Search Option allows eg nsswitch.conf to be reconfigured via dhcp. The ISC DHCP server implements this option, and the ISC DHCP client is compatible...but does not by default install this option's value. One would need to make their relevant dhclient-script process this option in a way that is suitable for the system. RFC3004 defines the User-Class option. Note carefully that ISC DHCP currently does not implement to this reference, but has (inexplicably) selected an incompatible format: a plain text string. RFC3011 defines the Subnet-Selection plain DHCPv4 option. Do not confuse this option with the relay agent "link selection" sub-option, although their behaviour is similar. RFC3396 documents both how long options may be encoded in DHCPv4 packets, and also how multiple instances of the same option code within a DHCPv4 packet will be decoded by receivers. RFC3397 documents the Domain-Search Option, which allows the configuration of the /etc/resolv.conf 'search' parameter in a way that is RFC1035 wire format compatible (in fact, it uses the RFC1035 wire format). ISC DHCP has both client and server support, and supports RFC1035 name compression. RFC3679 documents a number of options that were documented earlier in history, but were not made use of. RFC3925 documents a pair of Enterprise-ID delimited option spaces for vendors to use in order to inform servers of their "vendor class" (sort of like 'uname' or 'who and what am I'), and a means to deliver vendor-specific and vendor-documented option codes and values. RFC3942 redefined the 'site local' option space. defines two BCMS server options for each protocol family. RFC4388 defined the DHCPv4 LEASEQUERY message type and a number of suitable response messages, for the purpose of sharing information about DHCP served addresses and clients.
RFC3046 defines the Relay Agent Information Option and provides a number of sub-option definitions. RFC3256 defines the DOCSIS Device Class sub-option. RFC3527 defines the Link Selection sub-option.
The collection of documents that describe the standards-based method to update dns names of DHCP clients starts most easily with RFC4703 to define the overall architecture, travels through RFCs 4702 and 4704 to describe the DHCPv4 and DHCPv6 FQDN options (to carry the client name), and ends up at RFC4701 which describes the DHCID RR used in DNS to perform a kind of atomic locking. ISC DHCP adopted early versions of these documents, and has not yet synchronized with the final standards versions. For RFCs 4702 and 4704, the 'N' bit is not yet supported. The result is that it is always set zero, and is ignored if set. For RFC4701, which is used to match client identities with names in the DNS as part of name conflict resolution. Note that ISC DHCP's implementation of DHCIDs vary wildly from this specification. First, ISC DHCP uses a TXT record in which the contents are stored in hexadecimal. Second, there is a flaw in the selection of the 'Identifier Type', which results in a completely different value being selected than was defined in an older revision of this document...also this field is one byte prior to hexadecimal encoding rather than two. Third, ISC DHCP does not use a digest type code. Rather, all values for such TXT records are reached via an MD5 sum. In short, nothing is compatible, but the principle of the TXT record is the same as the standard DHCID record. However, for DHCPv6 FQDN, we do use DHCID type code '2', as no other value really makes sense in our context.
The Failover Protocol defines means by which two DHCP Servers can share all the relevant information about leases granted to DHCP clients on given networks, so that one of the two servers may fail and be survived by a server that can act responsibly. Unfortunately it has been quite some years (2003) since the last time this document was edited, and the authors no longer show any interest in fielding comments or improving the document. The status of this protocol is very unsure, but ISC's implementation of it has proven stable and suitable for use in sizable production environments. draft-ietf-dhc-failover-12.txt describes the Failover Protocol. In addition to what is described in this document, ISC DHCP has elected to make some experimental changes that may be revoked in a future version of ISC DHCP (if the draft authors do not adopt the new behaviour). Specifically, ISC DHCP's POOLREQ behaviour differs substantially from what is documented in the draft, and the server also implements a form of 'MAC Address Affinity' which is not described in the failover document. The full nature of these changes have been described on the IETF DHC WG mailing list (which has archives), and also in ISC DHCP's manual pages. Also note that although this document references a RECOVER-WAIT state, it does not document a protocol number assignment for this state. As a consequence, ISC DHCP has elected to use the value 254. An optimization described in the failover protocol draft is included since 4.2.0a1. It permits a DHCP server operating in communications-interrupted state to 'rewind' a lease to the state most recently transmitted to its peer, greatly increasing a server's endurance in communications-interrupted. This is supported using a new 'rewind state' record on the dhcpd.leases entry for each lease. describes the Load Balancing Algorithm (LBA) that ISC DHCP uses in concert with the Failover protocol. Note that versions 3.0.* are known to misimplement the hash algorithm (it will only use the low 4 bits of every byte of the hash bucket array).
explains how to go about obtaining a new DHCP Option code assignment.
For now there is only one document that specifies the base of the DHCPv6 protocol (there have been no updates yet), . Support for DHCPv6 was first added in version 4.0.0. The server and client support only IA_NA. While the server does support multiple IA_NAs within one packet from the client, our client only supports sending one. There is no relay support. DHCPv6 introduces some new and uncomfortable ideas to the common software library. Options sometimes may appear multiple times. The common library used to treat all appearance of multiple options as specified in RFC2131 - to be concatenated. DHCPv6 options may sometimes appear multiple times (such as with IA_NA or IAADDR), but often must not. As of 4.2.1-P1, multiple IA_NA, IA_PD or IA_TA are not supported. The same option space appears in DHCPv6 packets multiple times. If the packet was got via a relay, then the client's packet is stored to an option within the relay's packet...if there were two relays, this recurses. At each of these steps, the root "DHCPv6 option space" is used. Further, a client packet may contain an IA_NA, which may contain an IAADDR - but really, in an abstract sense, this is again re-encapsulation of the DHCPv6 option space beneath options it also contains. Precisely how to correctly support the above conundrums has not quite yet been settled, so support is incomplete. creates a registry at IANA to reserve interface identifiers and specifies a starting set. These IIDs should not be used when constructing addresses to avoid possible conflicts.
defines the SIP server options for DHCPv6. documents the DHCPv6 name-servers and domain-search options. documents the Identity Association Prefix Delegation for DHCPv6, which is included here for protocol wire reference, but which is not supported by ISC DHCP. documents four NIS options for delivering NIS servers and domain information in DHCPv6. defines the DHCPv6 SNTP Servers option. defines the Information Refresh Time option, which advises DHCPv6 Information-Request clients to return for updated information. defines two BCMS server options for each protocol family. defines a DHCPv6 subscriber-id option, which is similar in principle to the DHCPv4 relay agent option of the same name. defines a DHCPv6 remote-id option, which is similar in principle to the DHCPv4 relay agent remote-id.
&rfc760; &rfc768; &rfc894; &rfc951; &rfc1035; &rfc1188; &rfc1542; &rfc2131; &rfc2132; &rfc2241; &rfc2242; &rfc2485; &rfc2610; &rfc2937; &rfc2939; &rfc3004; &rfc3011; &rfc3046; &rfc3074; &rfc3256; &rfc3396; &rfc3397; &rfc3527; &rfc3679; &rfc3925; &rfc3942; &rfc4361; &rfc4388; DHCP Failover Protocol Cisco Systems &rfc3315; &rfc3319; &rfc3633; &rfc3646; &rfc3898; &rfc4075; &rfc4242; &rfc4580; &rfc4649; Address Parameters Option for DHCPv6 Gdansk University of Technology
dhcp-4.2.4/doc/ja_JP.eucJP/dhclient-script.8000644 000765 000024 00000024534 11301372615 020320 0ustar00sarstaff000000 000000 .\" $Id: dhclient-script.8,v 1.3.24.1 2009-11-20 01:49:01 sar Exp $ .\" .\" Copyright (c) 2004,2009 by Internet Systems Consortium, Inc. ("ISC") .\" Copyright (c) 1996-2003 by Internet Software Consortium .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above .\" copyright notice and this permission notice appear in all copies. .\" .\" THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES .\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR .\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES .\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT .\" OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" .\" Internet Systems Consortium, Inc. .\" 950 Charter Street .\" Redwood City, CA 94063 .\" .\" https://www.isc.org/ .\" .\" This software has been written for Internet Systems Consortium .\" by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. .\" To learn more about Internet Systems Consortium, see .\" ``https://www.isc.org/''. To learn more about Vixie Enterprises, .\" see ``http://www.vix.com''. To learn more about Nominum, Inc., see .\" ``http://www.nominum.com''. .\" .\" %FreeBSD: src/contrib/isc-dhcp/client/dhclient-script.8,v 1.5.2.4 2002/04/11 10:16:45 murray Exp % .\" .\" $FreeBSD: doc/ja_JP.eucJP/man/man8/dhclient-script.8,v 1.13 2002/05/08 03:27:27 horikawa Exp $ .TH dhclient-script 8 .SH ̾ dhclient-script - DHCP 饤ȤΥͥåȥꥹץ .SH DHCP 饤ȤΥͥåȥꥹץȤϡ 뤴Ȥ \fBdhclient(8)\fR ƤӽФޤ DHCP 饤ȤϡܥץȤѤ뤳Ȥˤꡢ ɥ쥹׵Ωijƥ󥿥եνȡ Ϳ줿ɥ쥹θȡ ꡼Υ󥿥եκǽԤޤ ꡼ʤä硢 ѤߤΥ꡼¸ߤʤФ򸡺뤿ܥץȤϻѤ졢 ͭʥ꡼Ƚʤäˤ⤦ 1 󤳤ΥץȤƤФޤ .PP ܥץȤϡɥ桼˥ޥ뤳ȤտޤƤޤ ʥޥɬפʾ硢 (enter) Ƚ (exit) ȤեåѤ뤳ȤDzǽȤʤޤ (ܺ٤ϥեå) Υեåϡ .B /etc/resolv.conf ˡ 饤ȤΥǥեư桼Х饤ɤǤ褦ˤޤ .PP Υڥ졼ƥ󥰥ƥǤϡ 饤ȤμΤưȤƤ⡢ ɸΥץȤưʤ⤷ޤ Ūʥ桼ץȤ¸ΤΤꤹɬפ ȤϤäȤʤȤǤ Ūˤϡ줾Υԥ塼˸ͭΥޥ .B ETCDIR/dhclient.conf ץȤǹԤ٤Ǥ .B ETCDIR/dhclient.conf Υޥ̵ˤǤʤޥ䡢 ȽФΥեåλѤǤϤǤʤޥ˵Ťˤϡ ХݡȤäƤ .SH եå ϻˡ饤ȥץȤϤޤؿޤδؿ .B make_resolv_conf Ǥꡢ .B /etc/resolv.conf ե뤿˻Ѥޤ ǥեư򥪡Х饤ɤˤϡ δؿΥեåץȤǺƤ .PP make_resolv_conf ؿθ塢饤ȥץȤ ¹Բǽ .B ETCDIR/dhclient-enter-hooks ץȤ¸ߤ򸡺 ¸ߤˤ Bourne '.' ޥɤѤ ܥץȤ򥤥饤ǵưޤ ǵҤƤ뤹٤ƤδĶܥץȤǻѲǽǤꡢ ץȤưѹɬפʾˤϴĶνƤޤ ץȼ¹˥顼ȯ硢 exit_status ѿ 0 ͤꤹ뤳ȤǽǤꡢ 饤ȥץȽλľ .B CLIENTBINDIR/dhclient-script ϤΥ顼ɤǽλޤ .PP ٤Ƥνδλˡ .B CLIENTBINDIR/dhclient-script ϼ¹Բǽ .B ETCDIR/dhclient-exit-hooks ץȤ¸ߤ򸡺¸ߤˤ '.' ޥɤǤưޤ dhclient-script λ֤ dhclient-exit-hooks exit_status ѿϤ졢 ư줿Ż˥ץȤˤͤϾ 0 ˤʤޤ dhclient-enter-hooks ιҤ¾δĶѤޤ .B ETCDIR/dhclient-exit-hooks exit_status ˼ä dhclient-script ͤѹǤޤ .SH dhclient 饤ꥹץȤưɬפȤ ͡ѿĶƤ .B CLIENTBINDIR/dhclient-script ưޤ ٤Ƥξˤơ$reason ˤϥץȤưͳ̾ꤵޤ ͳƤޤ: MEDIUM, PREINIT, BOUND, RENEW, REBIND, REBOOT, EXPIRE, FAIL, TIMEOUT .PP .SH MEDIUM DHCP 饤Ȥϡ󥿥եΥǥפƤޤ 󥿥ե̾ $interface Ϥ졢ǥפ $medium Ϥޤ .SH PREINIT DHCP 饤Ȥϡ ºݤΥɥ쥹˥ѥåȤŪǡ ׵̤˥󥿥եꤵ뤳ȤƤޤ BSD Υåȥ饤֥Ѥ륯饤ȤǤϡ IP ɥ쥹 0.0.0.0 ĥ֥ɥ㥹ȥɥ쥹 255.255.255.255 ǡ 󥿥եꤹ뤳Ȥ̣ޤ ¾Υ饤ȤǤϡ ºݤ IP ɥ쥹Ϳ뤳Ȥʤñ˥󥿥եꤹ뤳Ȥ ¸Ǥ礦 󥿥ե̾ $interface Ϥ졢ǥפ $medium Ϥޤ .PP IP ꥢ dhclient.conf Ƥ硢 Υɥ쥹 $alias_ip_address Ϥޤ IP ɥ쥹ؤηϩȤȤˡ IP ɥ쥹оݥ󥿥եɬפޤ .SH BOUND DHCP 饤Ȥϡɥ쥹ؤνηλޤ IP ɥ쥹 $new_ip_address Ϥ졢 󥿥ե̾ $interface Ϥޤ ǥפ $medium Ϥޤ Фץϡ\fBdhcp-options\fR Ƥ ץ̾Ϥޤ 㳰Ȥơ ͭʥѿȤ뤿 å ('-') ϥ('_')֤졢 ѿ̾ new_ dzϤޤ 㤨С֥ͥåȥޥ $new_subnet_mask Ϥޤ .PP ɥ쥹ºݤꤹˡdhclient-script ϲ餫ˡ Υɥ쥹Ф ARP Ԥֻäˤ 0 ͤ λ٤Ǥξ祯饤Ȥ DHCPDECLINE å򥵡 㤦ɥ쥹ޤ κȤ RENEW, REBIND, REBOOT ֤ǤƱͤ˹Ԥޤ ɬɬפǤϤʤºݹޤʤǤ礦 .PP 礬λȡ ͥåȥ˴ؤ¿Υѥ᡼ꤹɬפǤ礦 $new_domain_name $new_domain_name_servers (ˤʣΥФǶڤä󤷤Ƥ뤫⤷ޤ) Ѥơ /etc/resolv.conf ɬפޤ ǥեȷϩϡ$new_routers Ѥꤹɬפޤ Ūϩϡ$new_static_routes Ѥꤹɬפ뤫⤷ޤ .PP IP ꥢƤ硢ꤹɬפޤ ꥢ IP ɥ쥹 $alias_ip_address ȤƵҤ졢 ꥢѤꤵ¾ DHCP ץ (㤨Х֥ͥåȥޥ) ҤΤ褦ѿϤޤ $new_ dzϤΤǤϤʤ $alias_ dzϤޤ ꥢ IP ɥ쥹礵줿 IP ɥ쥹 ($new_ip_address) Ʊ硢ѤƤϤʤʤȤդƤ ʤʤ顢ξˤ¾ΥꥢΥѥ᡼ʤǽ Ǥ .SH RENEW 礬ȡץȤ BOUND Ʊͤ˸ƤФޤ $new_ dzϤѿ˲ä $old dzϤ̤ѿȤȤ 㳰ޤ ѹ줿ǽ³Ūϡɬפޤ 㤨С礵줿ɥ쥹Фϩꤵ줿硢 Ťϩɬפޤ ǥեȷϩѹ줿硢Ťǥեȷϩɬפޤ Ūϩѹ줿硢ŤΤɬפޤ ¾ˤĤƤϡBOUND Ʊͤ˽ǽǤ .SH REBIND DHCP 饤Ȥ DHCP Ф˺Ʒ礵ޤ RENEW Ʊͤ˰ޤIP ɥ쥹Ѥäˤϡ ARP ɽ򥯥ꥢɬפޤ .SH REBOOT DHCP 饤Ȥϡ֡ȸ˸Υɥ쥹Ƴ뤳Ȥޤ BOUND Ʊͤ˽ǽǤ .SH EXPIRE DHCP 饤Ȥϥ꡼ȿ꡼˼Ԥ ꡼δ¤ڤޤ о IP ɥ쥹ɬפꡢ RENEW REBIND ƱͤˡϢѥ᡼ɬפޤ .SH FAIL DHCP 饤Ȥ DHCP Ф³Ǥ ޤ IP ɥ쥹ˤͭʤΤϤޤǤ Ǹ˸꡼Υѥ᡼ϡɬפޤ ϡEXPIRE Ʊͤ˰ޤ .SH TIMEOUT DHCP 饤ȤϤɤ DHCP Фˤ³ǤޤǤ ʤ顢Ť꡼̤졢 BOUND ƱͤˡθŤ꡼Υѥ᡼Ϥޤ 饤ȤꥹץȤϡΥѥ᡼򸡺 줬ͭǤȿͳʤС 0 ǽλ٤Ǥ ǤʤʤС 0 ͤǽλ٤Ǥ .PP ꡼򸡺̾ˡϡREBIND Ʊͤ˥ͥåȥꤷ (ʣΥ꡼򸡺뤿˸ƤФ뤳Ȥ뤫Ǥ) $routers ǽΥ롼 ping 뤳ȤǤ 硢 󥿥ե³ƤͥåȥФơ꡼ͭǤ $new_static_routers ˲ä $new_routers 󤵤Ƥ롼 ping 褦ˤʤС Ǥ礦ߤΥץȤϤʤäƤޤ .SH Ϣե ڥ졼ƥ󥰥ƥФ륹ץȥե ƤƱ⤷ޤ󤬡̤ˤϡ ƥڥ졼ƥ󥰥ƥѤ˳ơΥץȥե뤬٤Ǥ Internet Systems Consortium DHCP ۤ˴ޤޤ륹ץȥեϡ client/scripts ʲۥĥ꡼ˤꡢ ưоݥڥ졼ƥ󥰥ƥ̾ˤʤäƤޤ .SH Х ʣ󥿥եѤ硢 Ф󶡤ѥ᡼ƱΤ ͤʤ褦ˤΤˡϤޤ 㤨С ɸ dhclient-script /etc/resolv.conf ٽ񤭴Ƥޤޤ ʤʣΥ󥿥եꤵƤ硢 륵Ф󶡤ͤ /etc/resolv.conf 줿ˡ ̤ΥФ󶡤ͤ˽Ȥư򷫤֤ޤ ɤΥФ󶡤ͭǤˤϡ ºݾȤϤʤʤΤΡΤȤˤʤꤨޤ .SH Ϣ dhclient.conf(5), dhclient.leases(5), dhclient(8) .SH .B dhclient-script(8) Ted Lemon Vixie Enterprises ȶϤ Internet Systems Consortium Τ 񤭤ޤ Internet Systems Consortium ˤĤƤܤϡ .B https://www.isc.org Vixie Enterprises ˤĤƤܤϡ .B http://www.vix.com dhcp-4.2.4/doc/ja_JP.eucJP/dhclient.8000644 000765 000024 00000030304 11301372615 017006 0ustar00sarstaff000000 000000 .\" $Id: dhclient.8,v 1.3.24.1 2009-11-20 01:49:01 sar Exp $ .\" .\" Copyright (c) 2004,2009 by Internet Systems Consortium, Inc. ("ISC") .\" Copyright (c) 1996-2003 by Internet Software Consortium .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above .\" copyright notice and this permission notice appear in all copies. .\" .\" THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES .\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR .\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES .\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT .\" OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" .\" Internet Systems Consortium, Inc. .\" 950 Charter Street .\" Redwood City, CA 94063 .\" .\" https://www.isc.org/ .\" .\" Portions copyright (c) 2000 David E. O'Brien. .\" All rights reserved. .\" %FreeBSD: src/contrib/isc-dhcp/client/dhclient.8,v 1.8.2.3 2002/04/11 10:16:45 murray Exp % .\" .\" $FreeBSD: doc/ja_JP.eucJP/man/man8/dhclient.8,v 1.8 2002/05/21 03:46:48 horikawa Exp $ .\" WORD: Dynamic Host Configuration Protocol (DHCP) ưŪۥץȥ .\" WORD: lease ꡼ [dhclient.8] .\" WORD: mobile host ưۥ .\" WORD: limited broadcast address ߥƥåɥ֥ɥ㥹ȥɥ쥹 .\" WORD: networking framework ͥåȥ󥰥ե졼 .\" WORD: housekeeping chores .TH dhclient 8 .SH ̾ dhclient - ưŪۥץȥΥ饤 .SH .B dhclient [ .B -p .I port ] [ .B -D ] [ .B -d ] [ .B -q ] [ .B -1 ] [ .B -r ] [ .B -lf .B lease-file ] [ .B -pf .I pid-file ] [ .B -cf .I config-file ] [ .B -sf .I script-file ] [ .B -s server ] [ .B -g relay ] [ .B -n ] [ .B -nw ] [ .B -w ] [ .I if0 [ .I ...ifN ] ] .SH Internet Systems Consortium DHCP 饤ȤǤ dhclient ưŪۥץȥ (DHCP: Dynamic Host Configuration Protocol) ޤ BOOTP ץȥѤơ뤤 Υץȥ뤬Ԥˤϥɥ쥹Ū˳Ƥơ 1 İʾΥͥåȥ󥿥եꤹˡ󶡤ޤ .SH .PP DHCP ץȥǤϡ1 İʾΥ֥ͥåȤ˳Ƥ뤳ȤΤǤ IP ɥ쥹ΥꥹȤФˡۥȤǤޤ DHCP 饤ȤϤΥꥹȤ饢ɥ쥹׵ᤷơ ͥåȥ̿ΰŪѤ뤳ȤǤޤ ޤ DHCP ץȥϡǥեȥ롼ξ͡ॵФξʤɡ 饤Ȥ³Ƥͥåȥ˴ؤפʾ 饤Ȥ˾ܺ٤Τ餻뵡󶡤ޤ .PP ư dhclient .IR dhclient.conf ؼɤ߼ޤ 줫鸽ߤΥƥȤ߹ޤƤ ٤ƤΥͥåȥ󥿥եΥꥹȤޤ ƥ󥿥եФ dhclient DHCP ץȥѤߤޤ .PP ƥ֡Ȥ䥵кƵưκݤ˥꡼򼺤ʤ褦ˡ dhclient ϳƤ줿꡼ΥꥹȤ dhclient.leases(5) ե¸ޤ ưdhclient.conf եɤ߼ä塢 dhclient dhclient.leases եɤ߹ǡ Ƥ줿꡼˴ؤ򹹿ޤ .PP ꡼ȡdhclient.leases եդäޤ ե뤬ü礭ʤΤɤˡ dhclient ϻꥳΥ꡼ǡ١ dhclient.leases եޤ Ť dhclient.leases եϡ dhclient ˥ǡ١ؤޤǡ .IR dhclient.leases~ Ȥ̾¸ޤ .PP dhclient ǽ˵ư줿Ȥ (Ūˤϥƥ֡Ƚδ) DHCP ФѤǤʤС Ť꡼ϻĤޤ ξ硢dhclient.leases ե뤫 ޤ¤ڤƤʤŤ꡼򸡺 ͭǤȽǤСδ¤ڤ뤫 ޤ DHCP ФѤǤ褦ˤʤޤǡΥ꡼Ȥޤ .PP DHCP Ф¸ߤʤͥåȥ˻ꥢɬפ 褦ʰưۥȤϡΥͥåȥθꥢɥ쥹Υ꡼ 餫ɤ߹ǤȤǤޤ DHCP ФؤΥɤʤä硢 dhclient ϤŪʥ꡼ͭǤ뤫ڤ ͭǤм˺ƵưޤǤΥ꡼Ȥޤ .PP ޤưۥȤϡDHCP ѤǤʤ BOOTP ʤѤǤ褦 ͥåȥذư뤳Ȥ⤢Ǥ礦 Τ褦ʾϡŤ꡼缡⡢ ΥͥåȥδԤ̤ BOOTP ǡ١˥ȥƤ餤 Υͥåȥ᤯֡ȤǤ褦ˤȤ褤Ǥ礦 .SH ޥɥ饤 .PP dhclient ꤷ褦Ȥͥåȥ󥿥ե̾ ޥɥ饤ǻǤޤ ޥɥ饤ǥ󥿥ե̾ꤵʤС dhclient Ϥ٤ƤΥͥåȥ󥿥ե̤ ǽʤ֥ɥ㥹ȥ󥿥եϽơ 줾Υ󥿥եꤷ褦Ȥޤ .PP .B dhclient.conf(5) ե̾ǥ󥿥եꤹ뤳ȤǽǤ ˡǥ󥿥եꤷ硢饤Ȥϡ եǻꤷ󥿥ե⤷ϥޥɹԤ ꤷ󥿥եΤɤ餫ꤹǤ礦 .PP .B -D ե饰ꤹȡ .B dhclient .B dhclient-script Ȥ߹碌ƻѤ뤿˺ץȤ .IR /tmp ¸ޤ .PP DHCP 饤Ȥɸݡ (ݡֹ 68) ʳΥݡȤ Եɬפˤ .B -p ե饰Ȥޤ Υե饰³ơdhclient Ȥ udp ݡֹꤷޤ ϼȤƥǥХåŪǤͭѤǤ 饤ȤԵ뤿˻ѤݡȤ ǥեȤȤϰ㤦ݡȤꤹ硢饤Ȥ ⤦ 1 ̤ݡȤѤޤݡȤϡ ꤷݡȤ礭ֹäΤǤ .PP DHCP 饤Ȥϡ̾ IP ɥ쥹Ƥʤ ǤդΥץȥåߥƥåɥ֥ɥ㥹 ɥ쥹Ǥ 255.255.255.255 ؤޤ ǥХåŪǡФΥåɤ̤Υɥ쥹 ʤȤޤ .B -s ե饰θ IP ɥ쥹⤷ϥɥᥤ̾Ĥƻ Ǥޤ ƥŪǡDHCP 饤ȤƤΥѥåȤ giaddr եɤ .B -g ե饰 IP ɥ쥹³Ѥ뤳Ȥꤹ ȤǤޤϥƥŪλΤͭѤʤΤǤꡢ ¤Ȥ䤹ư뤳ȤꤷƤ ޤ .PP DHCP 饤Ȥϡ̾磻󥿥եꤹޤǤ ե饦ɤưθХå饦ɤư 褦ˤʤޤdhclient ˥ե饦ɤ ץȤư뤿ˤϡ .B -d ե饰ꤹɬפޤϡDHCP 饤Ȥ ǥХåΤȤưƤ䡢System V ƥ inittab γ¦ưƤˤͭʤΤǤ .PP Υ饤Ȥϡ̾ϵưåɽɥ쥹 ޤɸ२顼Ϥ˥ץȥ륷󥹤 񤭽Фޤɥ쥹 .B syslog (3) եƥѤƥåΥˤʤޤ .B -q ե饰Ѥȡ顼ʳΥåɸ२顼Ϥ 񤭽Фʤ褦ˤʤޤ .PP 饤ȤϡDHCP ץȥǵ̳ŤƤʤᡢ ̾ϸ߼Ƥ꡼뤳ȤϤޤ ֥ ISP Τʤˤϡ饤Ȥ Ƥ줿IP ɥ쥹ˤϡФ Τ褦˵̳ŤƤȤ⤢ޤ .B -r ե饰ѤȡŪ˸ߤΥ꡼ä ꡼ȥ饤ȤϽλޤ .PP .B -1 ե饰ꤹȡ dhclient ϤҤȤĤΥ꡼Ф 1 ٤ߤޤ ⤷˼Ԥ dhclient Ͻλ 2 ǽλޤ .PP DHCP 饤Ȥϡ̾ .B ETCDIR/dhclient.conf 顢꡼ǡ١ .B DBDIR/dhclient.leases ʬΥץ ID .B RUNDIR/dhclient.pid Ȥ̾Υե¸ ƥͥåȥ󥿥ե .B CLIENTBINDIR/dhclient-script Ѥꤷޤ Υե̤̾ꤷꡢ̤ξ ꤷꤹˤϡ줾 .B -cf, .B -lf, .B -pf .B -sf ե饰򡢸˥ե̾³ǻѤƤ ˡϡ㤨 DHCP 饤ȤưȤ .B DBDIR ⤷ .B RUNDIR ޤޥȤƤʤˤäͭѤʤΤ ʤޤ .PP DHCP 饤Ȥϡꤹ٤ͥåȥ 󥿥եƱǤʤ硢̾Ͻλޤ åץȥåץԥ塼ۥåȥåײǽ I/O Х äԥ塼Ǥϡ֥ɥ㥹ȥ󥿥ե ƥ൯ưɲä뤳Ȥޤ .B -w ե饰ѤȡΤ褦ʥ󥿥ե 1 Ĥ ĤʤȤˤ⥯饤Ȥλʤ褦ˤǤޤ .B omshell (8) ץѤơͥåȥ󥿥եɲä줿 줿ꤷȤ򥯥饤ȤΤ뤳ȤǤ ˤäƥ饤ȤΥ󥿥ե IP ɥ쥹ꤹ褦ߤ뤳ȤǤޤ .PP .B -n ե饰Ѥ뤳ȤǡɤΥ󥿥եꤷ褦 ʤ褦 DHCP 饤Ȥؼ뤳ȤǤޤ Υե饰ϡä .B -w ե饰ȶ˻ѤͭѤǤ礦 .PP IP ɥ쥹ޤԤĤΤǤϤʤ¨¤˥ǡ ʤ褦˥饤Ȥؼ뤳ȤǤޤ .B -nw ե饰ͿȲǽǤ .SH dhclient.conf(5) եν񼰤̤˲⤵Ƥޤ .SH OMAPI DHCP 饤Ȥϡưˤưߤ ȤʤʬȤǤ褦ˤ뤿εǽ󶡤Ƥޤ εǽϡ⡼ȥ֥ API Ǥ OMAPI Ѥ󶡤ƤޤOMAPI 饤ȤϡTCP/IP ѤƤ DHCP 饤Ȥ³ޤơ DHCP 饤Ȥθߤξ֤򸡺Ǥξ֤ѹ뤳Ȥ Ǥޤ .PP 桼ץǤϡäˤ OMAPI ץȥľܼ ΤǤϤʤdhcpctl API ⤷ OMAPI ΤΤѤ٤Ǥ dhcpctl ϡOMAPI ưǹԤäƤϤʤΤĤ򰷤 åѤǤdhcpctl OMAPI ˤĤƤ \fBdhcpctl(3)\fR \fBomapi(3)\fR ˵ҤƤޤ 饤ȤѤƤꤿȤΤۤȤɤϡ̤ʥץ 񤫤ʤȤ \fBomshell(1)\fR ޥɤѤľܼ¸Ǥ ΤǤ .SH 楪֥ 楪֥ȤѤȡDHCP 饤Ȥλ ݻƤ꡼򤹤٤Ƴ饤Ȥɲä DNS 쥳ɤ򤹤٤ƾõ뤳ȤǤ褦ˤʤޤ ޤ饤Ȥߤ饤ȤѤƤ 󥿥եȤǤ褦ˤʤޤ θǡDHCP 饤ȤƵư뤳ȤǤ 󥿥եꤹ뤳ȤǤޤ̾ϥХ͡ åץȥåץԥ塼Ǥϥ꡼פ DHCP 饤ȤߤǤ礦 ơŸäƤ DHCP 饤Ȥ Ǥ礦뤳Ȥǡԥ塼ϥХ͡ ꡼ˤ PC ɤߤƤԥ塼 ϥХ͡䥹꡼פξ֤ ٽ뤳ȤǤ褦ˤʤΤǤ .PP 楪֥Ȥˤ° 1 ĤޤϾ°Ǥ 饤Ȥλˤϡ饤Ȥξ° 2 ꤷޤ饤ȤϼưŪ DHCPRELEASE ԤǤ礦 饤Ȥߤˤϡ饤Ȥξ° 3 ꤷޤ饤Ȥˤϡ饤Ȥ ° 4 ꤷޤ .SH Ϣե .B CLIENTBINDIR/dhclient-script, .B ETCDIR/dhclient.conf, DBDIR/dhclient.leases, RUNDIR/dhclient.pid, .B DBDIR/dhclient.leases~ .SH Ϣ dhclient.conf(5), dhclient.leases(5), dhclient-script(8) .SH .B dhclient(8) Ted Lemon Vixie Enterprises ȶϤ Internet Systems Consortium Τ 񤭤ޤ Internet Systems Consortium ˤĤƤܤϡ .B https://www.isc.org Vixie Enterprises ˤĤƤܤϡ .B http://www.vix.com .PP ܥ饤ȤϡElliot Poger Stanford ؤ MosquitoNet ץȤ˻äƤ֤ˡ Linux ǤѤ˺ݤ˽ɤԤޤ .PP ߤΥСϡElliot ˤ Linux Ǥβɤ餦Ȥ礭Ǥ Internet Systems Consortium DHCP ФȤΤƱ ͥåȥ󥰥ե졼Ѥ褦ˡTed Lemon ʺʬŪʽ񤭴Ԥޤ ƥͭꥳɤʬϥ륹ץȤ˰ܤ줿Τǡ ¿Υڥ졼ƥ󥰥ƥΥݡȤäˤĤ졢 ƥͭꥳɤ򤽤Υڥ졼ƥ󥰥ƥ ܿꤹɬפϤʤʤǤ礦 ˡ륹ץȤĶ˹äġƤӽФ Ṳ̄Ƥޤ .PP dhcp-4.2.4/doc/ja_JP.eucJP/dhclient.conf.5000644 000765 000024 00000055570 11301372615 017743 0ustar00sarstaff000000 000000 .\" $Id: dhclient.conf.5,v 1.3.24.1 2009-11-20 01:49:01 sar Exp $ .\" .\" Copyright (c) 2004,2009 by Internet Systems Consortium, Inc. ("ISC") .\" Copyright (c) 1996-2003 by Internet Software Consortium .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above .\" copyright notice and this permission notice appear in all copies. .\" .\" THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES .\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR .\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES .\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT .\" OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" .\" Internet Systems Consortium, Inc. .\" 950 Charter Street .\" Redwood City, CA 94063 .\" .\" https://www.isc.org/ .\" .\" This software has been written for Internet Systems Consortium .\" by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. .\" To learn more about Internet Systems Consortium, see .\" ``https://www.isc.org/''. To learn more about Vixie Enterprises, .\" see ``http://www.vix.com''. To learn more about Nominum, Inc., see .\" ``http://www.nominum.com''. .\" .\" %FreeBSD: src/contrib/isc-dhcp/client/dhclient.conf.5,v 1.7.2.1 2002/04/11 10:16:46 murray Exp % .\" $FreeBSD: doc/ja_JP.eucJP/man/man5/dhclient.conf.5,v 1.6 2002/05/03 03:23:30 horikawa Exp $ .\" WORD: lease ꡼(ɥ쥹Ϳ)[dhclient.conf.5] .\" WORD: lease discovery request ꡼ȯ׵[dhclient.conf.5] .\" WORD: offer (꡼󶡤)С󶡿[dhclient.conf.5] .TH dhclient.conf 5 .SH ̾ dhclient.conf - DHCP 饤ե .SH dhclient.conf եˤ Internet Systems Consortium DHCP 饤ȤǤ .IR dhclient 󤬴ޤޤޤ .PP dhclient.conf ϼͳ ASCII ƥȥեǤ Υե dhclient Ȥ߹ޤ줿Ƶߥѡ˲Ϥޤ եˤϡŪǥ֤Ԥ;ʬ˴ޤ뤳ȤǤޤ եΥɤǤʸʸ̤ޤ (Ͻ) եΤɤǤ⥳Ȥ֤ȤǤޤ Ȥʸ # ǻϤޤꡢǽޤ .PP dhclient.conf եǡ饤ȤΤޤޤưǤޤ ˤϡץȥΥߥ󥰡ФФ׵᤹ ФФɬܤȤ Ф󶡤ʤäѤǥեȡ Ф󶡤줿񤭤͡ Ф󶡤줿֤֤ͤʤɤޤ ޤDHCP ФʤͥåȥǻȤɥ쥹ǤäƤ⡢ 餫եǽ뤳ȤǤޤ .SH ץȥΥߥ 饤ȤΥߥưϡ桼ꤹɬפϤޤ 桼ߥԤʤС Ф̵٤ͿꤻŬԤ褦ʡ ʬŬڤʥߥưǥեȤѤޤ .PP ɬפ˱ơ ʸꤷ DHCP 饤ȤΥߥưĴǤޤ: .PP .B timeout .I ʸ .PP .B timeout .I time .B ; .PP .I timeout ʸϡ饤Ȥɥ쥹ߤ򳫻ϤƤ顢 Ф˥뤳Ȥ ǤʤȽǤޤǤ˷в᤹٤֤ޤ ǥեȤǤϤΥॢͤ 60 äǤ Υॢͤ᤮ϡ ⤷Ūʥ꡼եƤ뤫 ꡼ǡ١ˤޤڤˤʤäƤʤ꡼ĤäƤС 饤ȤϤΥ꡼ҤȤĤĸڤƤߤơ 줫ͭʤ褦ǤФΥ꡼Υɥ쥹Ȥޤ ⤷Ūʥ꡼⡢꡼ǡ١δ¤ڤƤʤ꡼ ͭʤΤ¸ߤʤС 饤Ȥ줿 retry ֳ֤θǥץȥƳޤ .PP .B retry .I ʸ .PP \fBretry \fItime\fR\fB;\fR .PP .I retry ʸϡ饤Ȥ DHCP Ф¸ߤʤȽǤƤ Ƥ DHCP Ф˥ߤޤǤδ֤ˡв᤹٤֤ޤ ǥեȤǤϡ 5 ʬǤ .PP .B select-timeout .I ʸ .PP \fBselect-timeout \fItime\fR\fB;\fR .PP ͥåȥǡʣ DHCP Фӥ󶡤뤳ȤǤޤ (˾ޤȤո⤢ޤ) ξ硢ǽΥ꡼ȯå (lease discovery message) ؤαȤơ 饤ȤʣΥ꡼󶡤οФ뤳Ȥ⤢ޤ Τ󶡤¾󶡤⹥ޤ⤷ޤ (㤨С饤ȤѤƤɥ쥹󶡤˴ޤޤƤ뤬 ¾󶡤ˤϴޤޤʤʤ) .PP .I select-timeout ϥ饤ȤǽΥ꡼ȯ׵ ơ ʤȤ 1 Ĥ󶡿Ф硢 Ф󶡿ԤޤǤλ֤Ǥ ⤷ .I select-timeout ڤޤǤˤɤ󶡿ФʤС 饤ȤϤΤȺǽ夹󶡿Фޤ .PP ǥեȤǤϡselect-timeout ͤ 0 äǤ Ĥޤꥯ饤ȤϺǽ˼󶡿Фޤ .PP .B reboot .I ʸ .PP \fBreboot \fItime\fR\fB;\fR .PP 饤ȤϡƵưȡ ǸݻƤɥ쥹ޤľȤޤ INIT-REBOOT (֡) ֤ȸƤӤޤ ǸưƤȤƱͥåȥ 饤Ȥޤ³ƤС줬ǤᤤưˡȤʤޤ .I reboot ʸϡ饤Ȥǽ˸Ťɥ쥹κƼߤƤ顢 ƿɥ쥹ȯ褦ȤޤǤˡ в᤹٤֤ꤷޤ ǥեȤǤϡreboot ॢͤ 10 äǤ .PP .B backoff-cutoff .I ʸ .PP \fBbackoff-cutoff \fItime\fR\fB;\fR .PP 饤ȤϡؿŪʰ (backoff) 르ꥺ򡢤٤ դǻѤޤϡ¿Υ饤ȤƱ˼ʬꤷ褦 ȤȤǤ⡢ꥯȤåƤޤȤʤ褦ˤ뤿Ǥ .I backoff-cutoff ʸϡ˵줿֤ꤷޤǥեͤ 2 ʬǤ .PP .B initial-interval .I ʸ .PP \fBinitial-interval \fItime\fR\fB;\fR .PP .I initial-interval ʸϡФؤκǽΥλߤ鼡λߤޤǤδ֤λ֤ ꤷޤåδֳ֤ϡå 1 뤿Ӥˡ ߤδֳ֤ 0 1 δ֤ͤ褸Τ 2 ܤ򡢸ߤδֳ֤ äΤˤʤޤ ͤ backoff-cutoff ͤ礭ʤȡλ֤ꤵޤ ǥեͤ 10 äǤ .SH ꡼׵ȥꥯ DHCP ץȥǤϡ饤Ȥ饵ФФξ褦 ׵ᤷꡢΤǤƤʤ¾ξʤ褦׵ᤷ Ǥޤ ޤФ󶡿Ф˥饤ȤɬפȤ󤬴ޤޤʤ 䡢󶡤줿󤬽ʬǤʤ硢饤Ȥ󶡿Ф ݤ뤳ȤǤޤ .PP DHCP Ф DHCP 饤Ȥ󶡿Ф˴ޤޤǡˤϡ ޤޤʤΤޤ ä׵Ǥǡ \fIDHCP ץ\fR ȸƤФΤǤ DHCP ץ \fBdhcp-options(5)\fR Ƥޤ .PP .B request .I ʸ .PP \fBrequest [ \fIoption\fR ] [\fB,\fI ... \fIoption\fR ]\fB;\fR .PP request ʸꤹ뤳Ȥǡ饤ȤϡФФ 饤Ȥ˱ʤСꤷץͤ褦 ׵᤹褦ˤʤޤ request ʸˤϥץ̾ꤷץѥ᡼ϻꤷޤ ǥեȤǤ DHCP 饤Ȥ subnet-mask, broadcast-address, time-offset, routers, domain-name, domain-name-servers, host-name ץ׵ᤷޤ .PP ˤäƤ׵ꥹȤʤȤ˾ޤȤ⤢ޤ 뤿ˤϡñ˥ѥ᡼ꤷʤ request ʸ񤤤Ʋ: .PP .nf request; .fi .PP .B require .I ʸ .PP \fBrequire [ \fIoption\fR ] [\fB,\fI ... \fIoption ]\fB;\fR .PP require ʸˤϡ󶡿Ф򥯥饤Ȥ뤿 Ф٤ץ󤷤ޤ 󤵤줿ץ󤹤٤Ƥޤޤʤ󶡿Ф̵뤵ޤ .PP .B send .I ʸ .PP \fBsend { [ \fIoption declaration\fR ] [\fB,\fI ... \fIoption declaration\fR ]\fB}\fR .PP send ʸꤹ뤳Ȥǡ饤Ȥϡ ꤷץꤷͤǥФ褦ˤʤޤ ǻǤ륪ץϡ \fBdhcp-options(5)\fR Ƥ륪ץ٤ƤǤ DHCP ץȥǾ륪ץ ˻ꤹ٤ǤϤޤâ \fBrequested-lease-time\fR ץǥեȤΥ꡼ (2 ) ʳͤǻꤹ뤳ȤϤǤޤʸȤ¾ξȤ餫 Τϡʬ̤μΥ饤ȤȤ̤Ǥ褦 򡢥ФФǤ .SH ưŪ DNS ߡ꡼줿ݤ DNS ιԤΡ ˸ŪʥݡȤ饤Ȥˤޤ ϥץȥŪʤΤǤꡢ 餯ʤפäƤ褦ˤưޤ ⤷ʤˤ⼫ʬΤȤ DNS ФδԤǤȤʤ顢 ξ˸¤äƤưޤȤƤ⤢ꤽˤʤȤǤ .PP ư뤿ˤϡDHCP Ф ȥɬפޤ (ܺ٤ \fBdhcpd.conf\fR(5) 򻲾) ޤΤ褦˥饤Ȥ fqdn ץꤹɬפޤ: .PP .nf send fqdn.fqdn "grosse.fugue.com."; send fqdn.encoded on; send fqdn.server-update off; .fi .PP \fIfqdn.fqdn\fR ץ \fBɬ\fR ʥɥᥤ̾ǤʤФʤޤ 륾Ф륾ʸ \fBɬ\fR ʤФʤޤ \fIfqdn.encoded\fR ץϡѤƤ DHCP ФˤäƤϡ \fIon\fR \fIoff\fR ꤹɬפ뤫⤷ޤ .PP .B no-client-updates .I ʸ .PP \fBno-client-updates [ \fIflag\fR ] \fB;\fR .PP DHCP 饤Ȥľ DNS ιԤ⡢ DHCP 饤ȥץ (\fBdhclient-script(8)\fR ) DNS ιԤ (㤨СDHCP 饤ȤľܥݡȤƤʤ SIG(0) ǧڤѤ) ˤϡ\fBno-client-updates\fR ʸȤäơԤʤ褦 饤Ȥ˶뤳ȤǤޤ DHCP 饤Ȥ뤳Ȥ˾ޤʤ \fIflag\fR \fBtrue\fR ˤ 뤳Ȥ˾ \fIflag\fR \fBfalse\fR ˤ뤳Ȥˤʤޤ ǥեȤǤ DHCP 饤Ȥ DNS ιԤޤ .PP .SH ץ󽤾 Υ饤ȤˤȤäƼºݤˤŬڤǤʤ ץǡäꡢɬפʾʤä ǡġξѲǽʥǥեȤͤ 饤¦¸ߤ礬ޤ ޤѲǽǤϤ뤬ξ䤦ɬפΤ 饤ȤȤ⤢ޤ 򰷤ˡ ĤΥץ󽤾ҤѤǤޤ .PP .B default .I ʸ .PP \fBdefault [ \fIoption declaration\fR ] \fB;\fR .PP 륪ץˤĤơ Ф󶡤ͤ򥯥饤ȤȤʤФʤʤ ⤷Фͤ󶡤ʤ 餫ΥǥեͤȤɬפ硢 ͤ .B default ʸ뤳ȤǤޤ .PP .B supersede .I ʸ .PP \fBsupersede [ \fIoption declaration\fR ] \fB;\fR .PP 륪ץˤĤơ ɤΤ褦ͤФ󶡤Ƥ⡢ ˥ꤵ줿ͤȤʤФʤʤ硢 ͤ .B supersede ʸ뤳ȤǤޤ .PP .B prepend .I ʸ .PP \fBprepend [ \fIoption declaration\fR ] \fB;\fR .PP 륪ץνˤĤơޤ桼󶡤ͤȤ μ˥Ф󶡤줿ͤФȤ硢 ͤ .B prepend ʸ뤳ȤǤޤ .B prepend ʸʣͤ뤳ȤΤǤ륪ץˤΤѤ뤳ȤǤޤ ϶ΤǤϤޤ󤬡 ̵뤷硢ɤΤ褦ʵưˤʤ뤫ͽۤǤޤ .PP .B append .I ʸ .PP \fBappend [ \fIoption declaration\fR ] \fB;\fR .PP 륪ץνˤĤơޤФ󶡤줿ͤȤ μ˥桼󶡤ͤФȤ硢 ͤ .B append ʸ뤳ȤǤޤ .B append ʸʣͤ뤳ȤΤǤ륪ץˤΤѤ뤳ȤǤޤ ϶ΤǤϤޤ󤬡 ⤷ȿͽǤʤ̤Ȥʤޤ .SH ꡼ .PP .B lease .I .PP \fBlease {\fR \fIlease-declaration\fR [ ... \fIlease-declaration ] \fB}\fR .PP (\fBץȥΥߥ\fR ) θ塢DHCP 饤Ȥ ФؤΥˤʤȽǤ礬ޤ λǡ饤ȤϼʬäƤ롢Ť꡼Υǡ١ ơڤˤʤäƤʤ꡼Ĵ١˵󤬤äƤ 롼 ping Ԥäơ줬Ѳǽʥ꡼ɤĴ٤ޤ DHCP ӥ BOOTP ӥ¸ߤʤͥåȥΤˡ 1 İʾ \fI\fR ꡼򥯥饤եƤơ 饤Ȥɥ쥹ưŪǤ褦ˤ뤳ȤǤޤ .B lease ʸǹԤޤ .PP : lease ʸϡDHCP Фä꡼Ͽ뤿ˡ dhclient.leases եǤȤޤ ʲ꡼ѤΥ󥿥åˤ dhclient.leases եǤΤɬפʤΤ⤢ޤ ʤΤˤ뤿ᡢΤ褦ʥ󥿥å⤳ǵҤޤ .PP lease ʸϡ꡼ɡ̡1 İʾΥ꡼ʸ ̤³Τǹޤ ꡼ȤơΤΤǽǤ: .PP \fBbootp;\fR .PP .B bootp ʸϡ꡼ DHCP ץȥǤϤʤ BOOTP ץȥѤƼ줿Ȥ򼨤ޤ ʸ򥯥饤ե˻ꤹɬפޤ 饤ȤϤιʸ꡼ǡ١եǻȤޤ .PP \fBinterface\fR \fB"\fR\fIstring\fR\fB";\fR .PP .B interface ꡼ʸϡΥ꡼ͭȤ륤󥿥ե򼨤ޤ 줬ꤵƤ硢Υ꡼ϡꤵ줿󥿥ե ǤΤ߻Ѥޤ Ф꡼äȤ 饤ȤϾˤΥ꡼ä󥿥եֹϿޤ dhclient.conf եǻ˥꡼Ƥ硢׵ᤵƤʤ ΤǤΥ꡼ǥ󥿥ե⤢碌ƻꤷʤ ʤޤ .PP \fBfixed-address\fR \fIip-address\fR\fB;\fR .PP .B fixed-address ʸΥ꡼ IP ɥ쥹ꤹݤ˻Ȥޤ Ϥ٤Ƥ lease ʸɬפǤ IP ɥ쥹 (12.34.56.78 Τ褦) ɥåդ 4 ȷ ꤷʤФʤޤ .PP \fBfilename "\fR\fIstring\fR\fB";\fR .PP .B filename ʸϻѤ֡ȥե̾ꤷޤ ɸŪʥ饤ꥹץȤǤϻȤޤ󤬡 δˤ˴ޤƤޤ .PP \fBserver-name "\fR\fIstring\fR\fB";\fR .PP .B server-name ʸϻѤ֡ȥ̾ꤷޤ ɸŪʥ饤ꥹץȤǤϻȤޤ .PP \fBoption\fR \fIoption-declaration\fR\fB;\fR .PP .B option ʸϡФ󶡤륪ץͤꤹΤ˻Ȥޤ 뤤ϡdhclient.conf ǻ꡼Ƥˤϡ λ꡼Ȥݤ˥饤ꥹץȤǻѤ ߤͤꤷޤ .PP \fBscript "\fIscript-name\fB";\fR .PP .B script ʸ dhcp 饤ꥹץȤΥѥ̾ꤹΤ˻Ȥޤ ΥץȤϡɥ쥹׵ᤷꡢ󶡤줿ɥ쥹 ꡢ ꡼Ƥ饤󥿥եκǽԤäꤹˡ dhcp 饤Ȥƥ󥿥եνԤΤ˻Ȥޤ ꡼Ǥʤäˤϡ ꡼¸ߤ硢ˤΥץȤȤޤ ޤͭʥ꡼ҤȤĤʤäǤ⡢ΥץȤϡ 1 ϸƤӽФޤ ܤϡ .B dhclient-script(8) 򻲾ȤƤ .PP \fBvendor option space "\fIname\fB";\fR .PP .B vendor option space ʸϡvendor-encapsulate-options ץ硢 沽ˤɤΥץ֤Ѥ٤ꤹ뤿˻Ѥޤ ФΥ٥ץΥ饹׵᤹뤿ˡ \fIdhcp-vendor-identifier\fR Ѥ뤳ȤǤޤ ܺ٤ .B dhcp-options(5) 򻲾ȤƤ .PP \fBmedium "\fImedia setup\fB";\fR .PP .B medium ʸϡ³ƤͥåȥΥפͥåȥ󥿥ե ưŪȽǤǤʤ褦ʥƥǻȤȤǤޤ ʸ media setup ϥƥ¸Υѥ᡼ǡ 󥿥եκݤ dhcp 饤ꥹץȤϤޤ Unix Unix ΥƥǤϡ ΰϥ󥿥եꤹȤ ifconfig ޥɥ饤 Ϥޤ .PP ꡼뤿˥󥿥եꤹ ݤˡdhcp 饤Ȥǥ ( .B media ʸ򻲾) Ѥ硢dhcp 饤ȤϡΥѥ᡼ ưŪޤͥåȥ󥿥եǥפ ɬפȤ (˸¤)ʸ꡼ ѤʤФʤޤ .PP \fBrenew\fR \fIdate\fB;\fR .PP \fBrebind\fR \fIdate\fB;\fR .PP \fBexpire\fR \fIdate\fB;\fR .PP \fBrenew\fR ʸϡ߻Υ꡼򹹿 (renew) 뤿ˡ dhcp 饤ȤΥ꡼󶡤Ƥ줿ФؤΥ ߤ򳫻ϤʤФʤʤޤ\fBrebind\fR ʸϡ ꡼򹹿뤿ˡdhcp 饤Ȥ \fI줫\fR dhcp ФؤΥλߤ򳫻ϤʤФʤʤޤ \fBexpire\fR ʸϡ꡼ιΤ˥Ф˥Ǥʤä硢 dhcp 饤ȤΥ꡼λѤߤʤФʤʤ ޤ .PP ϡDHCP 饤Ȥ꡼ǤϼưŪꤵޤ ꡼ΤDHCP 饤Ȥͭ¤᤮ΤѤ ߤʤΤǤϡꤷƤɬפޤ .PP date ϰʲΤ褦˻ꤷޤ .PP \fI \fB/\fI\fB/\fI \fB:\fI\fB:\fI\fR .PP weekday ϡʹ֤ƥ꡼¤狼䤹뤿¸ߤޤ ϡ0 6 ޤǤοǻꤷޤ0 Ǥyear ߤǻꤷޤǤ顢Ĺ꡼̤ˤȡɬ 4 ʤϤǤmonth 1 (1 ɽޤ) Ϥޤǻꤷޤ day Ʊͤ 1 Ϥޤ (ˤ) Ȥƻꤷޤhour ϡ 0 23 δ֤οǤminute second ϤȤ 0 59 δ֤ ꤷޤ .SH ꥢ \fBalias { \fI declarations ... \fB}\fR .PP DHCP 饤Ȥ TCP/IP ߥ (roaming) ץȥ¹Ԥ 硢DHCP Ѥ꡼Ǥʤ줿 IP ꥢ⡢ʬѤ륤󥿥եꤹɬפ 礬ޤInternet Systems Consortium DHCP 饤Ȥϡ ꥢɥ쥹ľܻΥߥ󥰤򥵥ݡȤƤޤ󤬡μμ¸ Ǥ褦ˡ dhcp 饤Ȥϡ .B alias Ȥä IP ꥢꤹϤǤƤޤ .PP alias lease ˻Ƥޤâɸ 饤ꥹץȤǤϡsubnet-mask ץʳ ץȡƼͭ (expiry times) ̵뤵ۤʤޤ ̤ alias Ǥϡ interface IP ꥢΤ ꥢɥ쥹subnet-mask ץޤߤޤalias ˤ medium ʸϷ褷ƴޤޤƤϤʤޤ .SH ¾ \fBreject \fIip-address\fB;\fR .PP .B reject ʸˤꡢDHCP 饤Ȥϻꤷɥ쥹򥵡м̻ҤȤƻѤ Ф󶡿Фݤ褦ˤʤޤɸ˽򤷤ʤ dhcp Фְ㤨Ƥ dhcp Фˤäƥ饤Ȥꤵʤ 褦ˤ뤿ˡʸѤ뤳ȤǤޤʤ顢 ǸȤ٤ǤΩä DHCP Фɤ ľ褤Ǥ .PP \fBinterface "\fIname\fB" { \fIdeclarations ... \fB } .PP ʣΥͥåȥ󥿥եĥ饤Ȥξ硢DHCP ꤵ륤󥿥եˤäưۤʤư򤵤ɬפ礬 ޤlease alias ٤ƤΥߥ󥰥ѥ᡼ interface ǰϤळȤǤޤξ硢Ϥޤ줿 ѥ᡼ϻꤷ̾˹פ륤󥿥եˤΤŬѤޤ interface ʤ󥿥եϡ٤Ƥ interface ¦줿ѥ᡼⤷ϥǥեȤ꤬ŬѤޤ .PP \fBpseudo "\fIname\fR" "\fIreal-name\fB" { \fIdeclarations ... \fB } .PP ˤäƤϲۥ󥿥ե DHCP 饤ȤΥ󥿥եΤ褦ˤ ˤʤޤ ̾ DHCP 饤ȤݡȤƤƥ󥿥եϡ Υ꡼뤿ˡ DHCP 饤Ȥξֵ¹ԤƤޤ ۥ󥿥եϡ\fIreal-name\fR ̾դ줿󥿥ե ƯƤ롢ޤ⤦ĤξֵǤ εǽѤ硢 ۥ󥿥եȼºݤΥ󥿥եξФ 饤ȼ̻Ҥ󶡤ʤФʤޤ ޤѤ IP ɥ쥹Ф벾ۥ󥿥եѤ ʬΥ줿饤ȥץȤ󶡤ʤФʤޤ 㤨мΤ褦ˤʤޤ: .PP .nf interface "ep0" { send dhcp-client-identifier "my-client-ep0"; } pseudo "secondary" "ep0" { send dhcp-client-identifier "my-client-ep0-secondary"; script "/etc/dhclient-secondary"; } .fi .PP ۥ󥿥եΤΥ饤ȥץȤ 󥿥եͭˤ̵ˤꤹ򤹤٤ǤϤޤ äˡ꡼γ乹ξ֡ƥ꡼δڤξ֤ 갷ˤϡΤȤɬפǤ ܺ٤ \fBdhclient-script(8)\fR 򻲾ȤƲ .PP \fBmedia "\fImedia setup\fB"\fI [ \fB, "\fImedia setup\fB", \fI... ]\fB;\fR .PP .B media ʸϡIP ɥ쥹˻Ѥߤ롢ǥѥ᡼ 1 ʾޤdhcp 饤Ȥϡꥹγ media setup ʸ 缡Ѥ륤󥿥ե򤽤ꤷ֡Ȥߤޤ ܤʤм media setup ʸѤޤʸϡ ǥפ򸡽ФǽϤʤͥåȥ󥿥ե ФѤǤޤФؤΥꥯȤǤ ʤСɤΤ褦ʥǥפǤ⤿֤Ǥ (ݾڤϤޤ) .PP media setup ϥɥ쥹νե (DHCPDISCOVER ѥåȤ DHCPOFFER ѥå)ǤΤ߻ѤޤҤȤӥɥ쥹ȡ dhcp 饤ȤϤΥɥ쥹꡼ǡ١˵Ͽ Υɥ쥹ݤѤǥפϿޤ饤Ȥ ꡼򹹿褦ȤݤˤϾˡƱǥפѤޤ ꡼ڤˤƤϤơ饤Ȥϥǥפ˻ ֤ޤ .\"X .SH SAMPLE ... man-jp ɸϤʤää .SH ʲեϡNetBSD 1.3 ¹Ԥ뤢åץȥåץޥ ѤƤΤǤΥޥϡIP ꥢȤ 192.5.5.213 󥿥ե ep0 (3Com 3C589C) ҤȤĻäƤޤΥ饤 ϡDHCP ưۤȤɤʤͥåȥǻ֤ʬ񤹤뤳Ȥ 狼äƤΤǡ֡ȴֳ֤ϥǥեͤ餤֤󾮤 ޤΥޥʣͥåȥ֤ǥߥ (ư) ޤ .nf timeout 60; retry 60; reboot 10; select-timeout 5; initial-interval 2; reject 192.33.137.209; interface "ep0" { send host-name "andare.fugue.com"; send dhcp-client-identifier 1:0:a0:24:ab:fb:9c; send dhcp-lease-time 3600; supersede domain-name "fugue.com rc.vix.com home.vix.com"; prepend domain-name-servers 127.0.0.1; request subnet-mask, broadcast-address, time-offset, routers, domain-name, domain-name-servers, host-name; require subnet-mask, domain-name-servers; script "CLIENTBINDIR/dhclient-script"; media "media 10baseT/UTP", "media 10base2/BNC"; } alias { interface "ep0"; fixed-address 192.5.5.213; option subnet-mask 255.255.255.255; } .fi dhclient.conf եȤƤʣʤΤǤ̤ˡ 󤬻ѤΤϤϤ뤫˴ñʤϤǤ¿ξ硢dhclient.conf եȤƶΥեǽʬʤϤǤ ĤޤꡢǥեͤǤ褤Τ̤Ǥ .SH Ϣ dhcp-options(5), dhclient.leases(5), dhclient(8), RFC2132, RFC2131 .SH .B dhclient(8) Vixie Labs ȤηΤȤ Ted Lemon 񤭤ޤ ܥץȤδ Internet Systems Consortium 󶡤ޤ Internet Systems Consortium ˴ؤϡ .B https://www.isc.org ˤޤ dhcp-4.2.4/doc/ja_JP.eucJP/dhclient.leases.5000644 000765 000024 00000004723 11301372615 020264 0ustar00sarstaff000000 000000 .\" $Id: dhclient.leases.5,v 1.3.24.1 2009-11-20 01:49:01 sar Exp $ .\" .\" Copyright (c) 2004,2009 by Internet Systems Consortium, Inc. ("ISC") .\" Copyright (c) 1997-2003 by Internet Software Consortium .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above .\" copyright notice and this permission notice appear in all copies. .\" .\" THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES .\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR .\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES .\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT .\" OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" .\" Internet Systems Consortium, Inc. .\" 950 Charter Street .\" Redwood City, CA 94063 .\" .\" https://www.isc.org/ .\" .\" This software has been written for Internet Systems Consortium .\" by Ted Lemon in cooperation with Vixie .\" Enterprises. To learn more about Internet Systems Consortium, .\" see ``https://www.isc.org/''. To learn more about Vixie .\" Enterprises, see ``http://www.vix.com''. .\" .\" .\" %FreeBSD: src/contrib/isc-dhcp/client/dhclient.leases.5,v 1.2.4.1 2002/04/11 10:16:46 murray Exp % .\" .\" $FreeBSD: doc/ja_JP.eucJP/man/man5/dhclient.leases.5,v 1.6 2002/05/05 20:40:23 horikawa Exp $ .TH dhclient.leases 5 .SH ̾ dhclient.leases - DHCP 饤ȤΥ꡼ǡ١ .SH Internet Systems Consortium DHCP 饤Ȥϡ ꡼ΤޤͭǤΤ뤿Ρ ³Ūʥǡ١ݻޤ Υǡ١ϡͳ ASCII եǤꡢ ꡼ 1 ĤˤĤͭ 1 Ĵޤߤޤ ꡼Фʣо줹硢 եκǸΤΤѤޤ ΥեϥȤƽ񤭹ޤޤΤǡ Τ褦ʾ֤ˤʤ뤳Ȥϰ۾ǤϤޤ .PP ꡼ν񼰤ϡ .B dhclient.conf(5) ˵ҤƤޤ .SH Ϣե .B DBDIR/dhclient.leases .SH Ϣ dhclient(8), dhcp-options(5), dhclient.conf(5), RFC2132, RFC2131 .SH .B dhclient(8) ϡVixie Labs ȤηΤȤǡTed Lemon Ҥޤ ܥץȤλϡInternet Systems Consortium 󶡤ޤ Internet Systems Consortium ˴ؤϡ .B https://www.isc.org ˤޤ dhcp-4.2.4/doc/ja_JP.eucJP/dhcp-eval.5000644 000765 000024 00000040361 11301372615 017060 0ustar00sarstaff000000 000000 .\" $Id: dhcp-eval.5,v 1.4.24.1 2009-11-20 01:49:01 sar Exp $ .\" .\" Copyright (c) 2004,2009 by Internet Systems Consortium, Inc. ("ISC") .\" Copyright (c) 1996-2003 by Internet Software Consortium .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above .\" copyright notice and this permission notice appear in all copies. .\" .\" THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES .\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR .\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES .\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT .\" OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" .\" Internet Systems Consortium, Inc. .\" 950 Charter Street .\" Redwood City, CA 94063 .\" .\" https://www.isc.org/ .\" .\" This software has been written for Internet Systems Consortium .\" by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. .\" To learn more about Internet Systems Consortium, see .\" ``https://www.isc.org/''. To learn more about Vixie Enterprises, .\" see ``http://www.vix.com''. To learn more about Nominum, Inc., see .\" ``http://www.nominum.com''. .\" $FreeBSD: doc/ja_JP.eucJP/man/man5/dhcp-eval.5,v 1.2 2002/05/23 04:17:13 horikawa Exp $ .TH dhcp-eval 5 .SH ̾ dhcp-eval - ISC DHCP ˤդɾ .SH Internet Systems Consortium DHCP 饤ȤȥФϡɤ ѥåȤ˰¸դưԤǽϤޤ դưʸˡ򤳤˼ޤ .SH : դư դưϡif, else, elsif ʸѤƻꤷޤ ʸϡ̾ʸ (option ʸ) оǽʾϤɤˤǤоǽǤꡢ ޤΤ褦ʸ뤳ȤǽǤ ФˤʸϼΤ褦ˤʤ뤳Ȥ¿Ǥ礦: .PP .nf if option dhcp-user-class = "accounting" { max-lease-time 17600; option domain-name "accounting.example.org"; option domain-name-servers ns1.accounting.example.org, ns2.accounting.example.org; } elsif option dhcp-user-class = "sales" { max-lease-time 17600; option domain-name "sales.example.org"; option domain-name-servers ns1.sales.example.org, ns2.sales.example.org; } elsif option dhcp-user-class = "engineering" { max-lease-time 17600; option domain-name "engineering.example.org"; option domain-name-servers ns1.engineering.example.org, ns2.engineering.example.org; } else { max-lease-time 600; option domain-name "misc.example.org"; option domain-name-servers ns1.misc.example.org, ns2.misc.example.org; } .fi .PP 饤¦ǤϡդɾϼΤ褦ˤʤǤ礦: .PP .nf # example.org ϥե䥦 DNS ե륿Τǡ # example.org ͥåȥ˷ҤȤΤߡ DNS ФѤޤ # example.org ˷ҤΤǤϤʤ硢ʤ DNS ФͥѤޤ if not option domain-name = "example.org" { prepend domain-name-servers 127.0.0.1; } .fi .PP .B if ʸ .B elsif ³ʸϡȤƥ֡뼰ޤ Ĥޤꡢʸϡɾȥ֡ͤη̤뼰ޤ ɾ̤ˤʤȡ .B if ʸľΥ֥졼dz줿ʸ¹Ԥ졢³ .B elsif .B else ϥåפޤ Ǥʤ硢ɾ̤ˤʤ elsif ˽в񤦤ޤǡ³ .B elsif μåޤ Τ褦᤬դȡľΥ֥졼ʸ¹Ԥ졢³ .B elsif .B else ϥåפޤ ٤Ƥ .B if .B elsif ᤬å줿ΤΤɤμ⿿ˤʤʤǡ .B else ᤬¸ߤ硢 .B else ľΥ֥졼ʸɾޤ ˤƤϡɾ̤ˤʤ֡뼰ϵȤưޤ .SH ֡뼰 ʲϡDHCP ʪǸߥݡȤƤ֡뼰ΰǤ .PP .I data-expression-1 \fB=\fI data-expression-2\fR .RS 0.25i .PP \fB=\fR ڥ졼ϡ2 ĤΥǡӤξԤƱϿ֤ ƱǤʤϵ֤ޤ դ⤷ϱդΤ줫ξ硢̤϶ˤʤޤ .RE .PP .I boolean-expression-1 \fBand\fI boolean-expression-2\fR .PP .RS 0.25i \fBand\fR ڥ졼ϡդΥ֡뼰ȱդΥ֡뼰ξɾ̤ ξ硢ɾޤ Ǥʤ硢ɾޤ դ⤷ϱդΤ줫ξ硢̤϶ˤʤޤ .RE .PP .I boolean-expression-1 \fBor\fI boolean-expression-2\fR .PP .RS 0.25i \fBor\fR ڥ졼ϡդΥ֡뼰ȱդΥ֡뼰Τ줫ɾ̤ ξ硢ɾޤ Ǥʤ硢ɾޤ դ⤷ϱդΤ줫ξ硢̤϶ˤʤޤ .RE .PP .B not \fIboolean-expression .PP .RS 0.25i \fBnot\fR ڥ졼ϡ\fIboolean-expression\fR ɾ̤ξ硢 ɾޤ ޤ\fIboolean-expression\fR ɾ̤ξ硢ɾޤ \fIboolean-expression\fR ɾ̤ξ硢̤ޤˤʤޤ .RE .PP .B exists \fIoption-name\fR .PP .RS 0.25i \fBexists\fR ϡоݤ DCHP ѥåˡ ꤵ줿ץ¸ߤ硢֤ޤ .RE .B known .PP .RS 0.25i \fBknown\fR ϡ׵бΥ饤ȤΤξ硢 ʤۥ硢֤ޤ .RE .B static .PP .RS 0.25i \fBstatic\fR ϡ׵бΥ饤ȤؤΥ꡼Ƥ Ūɥ쥹ƤˤΤǤä硢֤ޤ .RE .SH ǡ ҤΥ֡뼰ϡǡɾ̤˰¸ޤ ǡ򤳤˼ޤ .PP .B substring (\fIdata-expr\fB, \fIoffset\fB, \fIlength\fB)\fR .PP .RS 0.25i \fBsubstring\fR ڥ졼ϡǡɾ ɾ \fIoffset\fR ХȤ鳫Ϥ \fIlength\fR Хȷ³ ֥ȥ󥰤֤ޤ \fIoffset\fR \fIlength\fR ϶˿ͼǤ \fIdata-expr\fR, \fIoffset\fR, \fIlength\fR Τ줫ɾ硢 ̤ޤˤʤޤ \fIoffset\fR ɾ줿ǡĹʾǤ硢 Ĺ 0 Υǡʸ֤ޤ \fIlength\fI ɾ줿ǡ \fIoffset\fR Ĺ礭硢 ɾ줿ǡ \fIoffset\fR 齪üޤǤǡޤ ǡʸ֤ޤ .RE .PP .B suffix (\fIdata-expr\fB, \fIlength\fB)\fR .PP .RS 0.25i \fBsuffix\fR ڥ졼ϡ\fIdata-expr\fR ɾ ɾ̤κǸ \fIlength\fR ХȤ֤ޤ \fIlength\fR ϿͼǤ \fIdata-expr\fR ޤ \fIlength\fR ɾ̤ξ硢 ̤ޤˤʤޤ \fIsuffix\fR (: \fIlength\fR Ȼפޤ) ɾ̤ɾ줿ǡĹ礭硢 ɾ줿ǡ֤ޤ .\" horikawa@jp.FreeBSD.org 2002/04/29 .RE .PP .B option \fIoption-name\fR .PP .RS 0.25i \fBoption\fR ڥ졼ϡФΥѥåȤΡ ꤷץƤ֤ޤ .RE .PP .B config-option \fIoption-name\fR .PP .RS 0.25i \fBconfig-option\fR ڥ졼ϡꤷץФ DHCP 饤ȤޤϥФФ褦ꤵ줿֤ͤޤ .RE .PP .B hardware .PP .RS 0.25i \fBhardware\fR ڥ졼ϡǡȥ󥰤֤ޤ ǡȥ󥰤κǽǤϡ оݥѥåȤͥåȥ󥿥եΥפǤꡢ ³Ǥϡ饤ȤΥإɥ쥹Ǥ ѥåȤ¸ߤʤ⤷ RFC2131 \fIhlen\fR եɤ̵ʾ硢 ̤϶ˤʤޤ ϡɥפˤϡͥå (1)ȡ (6) FDDI (8) ޤޤޤ ϡɥפ IETF ˤäƵꤵ졢 ɤΤ褦˥פοͤ뤫ξܺ٤ RFC2131 (ISC DHCP ʪǤϡdoc/ ֥ǥ쥯ȥˤޤ) 򻲾ȤƤ .RE .PP .B packet (\fIoffset\fB, \fIlength\fB)\fR .PP .RS 0.25i \fBpacket\fR ڥ졼ϡоݥѥåȤλʬ֤ оݥѥåȤ̵ʸ̮Ǥ϶֤ޤ \fIoffset\fR \fIlength\fR ϡ \fBsubstring\fR ڥ졼ƱͤˡѥåȤƤŬѤޤ .RE .PP .I string .PP .RS 0.25i Ȥdz줿ȥ󥰤ϥǡȤƻǽǤꡢ Ȥδ֤ ASCII 󥳡ɤΥƥȤ֤ޤ Хåå ('\\') ʸ C ץΤ褦̰ޤ: ʤ '\\t' ϥ֤'\\r' '\\n' ϲԤ'\\b' ϥ٥ ̣ޤ 8 ʿͤ '\\nnn' ǻǽǤꡢnnn 0 ʾ 0377 ʲ 8 ʿͤǤ 16 ʿͤ '\\xnn' ǻǽǤꡢnn 0 ʾ 0xff ʲ 16 ʿͤǤ .\" ͤϰϤθˤĤƤϡMurray ͳǥݡȺ .\" horikawa@jp.FreeBSD.org 2002/05/01 .RE .PP .I colon-separated hexadecimal list .PP .RS 0.25i Ƕڤ줿 16 ʿΥƥåͤΥꥹȤ ǡȤƻǽǤ .RE .PP .B concat (\fIdata-expr1\fB, ..., \fIdata-exprN\fB)\fR .RS 0.25i ɾ졢ɾּ̤ν֤Ϣ뤵ޤ ּΤ줫ɾ̤ˤʤ硢Ϣη̤϶ˤʤޤ .RE .PP .B reverse (\fInumeric-expr1\fB, \fIdata-expr2\fB)\fR .RS 0.25i 2 Ĥμɾ졢ǡɾ̤ξȿžޤ ȿžϡͼǻꤵ礭ñ̤ǹԤޤ 㤨Сͼɾ̤ 4 ξǡ ǡɾ̤ 12 ХȤˤʤ硢 reverse ɾ̤ϡΤ褦 12 ХȤΥǡˤʤޤ ʤϤκǸ 4 Хȡ 4Хȡǽ 4 ХȤ ˤʤޤ .RE .PP .B leased-address .RS 0.25i ʤʸ̮ˤƤ⡢ ׵оݤȤʤäƤ륯饤Ȥ IP ɥ쥹ƺѤξ硢 IP ɥ쥹֤ޤ .RE .PP .B binary-to-ascii (\fInumeric-expr1\fB, \fInumeric-expr2\fB, .B \fIdata-expr1\fB,\fR \fIdata-expr2\fB)\fR .RS 0.25i data-expr2 ɾ̤ƥȥȥ󥰤Ѵޤ ΥƥȥȥǤϡ data-expr2 ɾ̤γǤ1 Ĥοͤˤʤޤ ƿͤϡ줾졢data-expr1 ɾ̤ˤäƶڤޤ numeric-expr1 ɾ̤ϡ (2 16) Ǥꡢ δ˿ͤѴޤ numeric-expr2 ɾ̤ϡƿͤΥӥåǤꡢ 8, 16, 32 Τ줫Ǥ .PP ǽ 3 ĤΥפμȤơ 饤Ȥ˳Ƥ줿 IP ɥ쥹Ѥ PTR 쥳ɤ̾뤿˻Ѳǽʼ򼨤ޤ .RE .PP .nf concat (binary-to-ascii (10, 8, ".", reverse (1, leased-address)), ".in-addr.arpa."); .fi .PP .B encode-int (\fInumeric-expr\fB, \fIwidth\fB)\fR .RS 0.25i ͼɾ졢ꤵ줿Υǡȥ󥰤 ͥåȥХȽ (Ǿ̥ХȤǽ) ǥ󥳡ɤޤ ͼɾ̤ͤˤʤ硢̤ޤǤ .RE .\" ".RE" ̵ȡǥȤʤǤ .\" horikawa@jp.FreeBSD.org 2002/04/29 .PP .B pick-first-value (\fIdata-expr1\fR [ ... \fIexpr\fRn ] \fB)\fR .RS 0.25i pick-first-value ؿϡǤոĤΥǡޤ ꥹȤƬƼɾ졢 ɾ̤ǤϤʤդޤǤ줬³ޤ μ֤졢μ˸³뼰ɾޤ ٤Ƥμɾ̤ξ硢֤ͤޤ .RE .PP .B host-decl-name .RS 0.25i host-decl-name ؿϡ׵оݤȤʤäƤ륯饤Ȥ˥ޥå롢 ۥ֤̾ޤ ɤΥۥޥåʤ硢̤϶ˤʤޤ .RE .SH ͼ ͼϡɾ̤ˤʤ뼰Ǥ ̤ˡκ祵 32 ӥå̤ǤȲꤹ٤ǤϤޤ󤬡 ٤ 32 ӥåȤۤ뤳ȤϤޤ .PP .B extract-int (\fIdata-expr\fB, \fIwidth\fB)\fR .PP .RS 0.25i \fBextract-int\fR ڥ졼ϡͥåȥХȽ ꤷǡɾ̤Фޤ ϡФΥӥåǤ ߡݡȤƤ 8, 16, 32 Τ줫Ǥ ǡɾ̤ꤷ礭ȼФΤ ʬʥӥåȤ󶡤ʤ硢֤ͤޤ .RE .PP .B lease-time .PP .RS 0.25i ߤΥ꡼δ֤Ǥ ʤߤλȥ꡼δ¤ڤȤκǤ .RE .PP .I number .PP .RS 0.25i 0 ɽǽʺ祵ϰϤǤդοͤ򡢿ͼȤƻǽǤ .RE .PP .B client-state .PP .RS 0.25i оݤΥ饤Ȥθߤξ֤Ǥ DHCP 饤եˤƤΤͭѤǤ ͤϼ̤Ǥ: .TP 2 .I \(bu Booting - DHCP 饤Ȥ INIT ֤Ǥꡢ IP ɥ쥹ޤޤ å DHCPDISCOVER Ǥꡢ ϥ֥ɥ㥹Ȥޤ .TP .I \(bu Reboot - DHCP 饤Ȥ INIT-REBOOT ֤Ǥ IP ɥ쥹ޤޤѤƤޤ å DHCPREQUEST Ǥꡢ ϥ֥ɥ㥹Ȥޤ ʹʤȡ饤ȤϤΥɥ쥹˥Хɤ BOUND ֤ܤޤ .TP .I \(bu Select - DHCP 饤Ȥ SELECTING ֤Ǥ ʤȤ 1 Ĥ DHCPOFFER åϼޤ ¾ DHCPOFFER å¾ΥФ뤫ɤԤäƤޤ SELECTING ֤Ǥϥåޤ .TP .I \(bu Request - DHCP 饤Ȥ REQUESTING ֤Ǥ ʤȤ 1 Ĥ DHCPOFFER å ΤΤɤ׵᤹뤫򤷤ޤ å DHCPREQUEST åǤꡢ ϥ֥ɥ㥹Ȥޤ .TP .I \(bu Bound - DHCP 饤Ȥ BOUND ֤Ǥ IP ɥ쥹ͭƤޤ ξ֤Ǥϥåޤ .TP .I \(bu Renew - DHCP 饤Ȥ RENEWING ֤Ǥ IP ɥ쥹ͭƤꡢ򹹿뤿˥Ф³ߤƤޤ å DHCPREQUEST åǤꡢ ϥФľܥ˥㥹Ȥޤ .TP .I \(bu Rebind - DHCP 饤Ȥ REBINDING ֤Ǥ IP ɥ쥹ͭƤꡢ 򹹿뤿ǤդΥФ³ߤƤޤ å DHCPREQUEST åǤꡢ ϥ֥ɥ㥹Ȥޤ .RE .SH : ʸѤơɸͥ˾ǽǤ ʸϡάǽ priority (\fBfatal\fR, \fBerror\fR, \fBinfo\fR, \fBdebug\fR Τ줫) ȡ ǡޤ .PP .B log (\fIpriority\fB, \fIdata-expr\fB)\fR .\" "\FB" "\fB" .\" horikawa@jp.FreeBSD.org 2002/04/29 .PP ʸϡñΥǡΤ߼ޤ ʣΥǡͤϤ硢 \fBconcat\fR ڥ졼ѤƤϢ뤹ɬפޤ .RE .SH : ưŪ DNS .PP DHCP 饤ȤȥФϡ ưŪ˥ɥᥤ͡ॷƥ򹹿ǽϤޤ եˡɤΤ褦˥ɥᥤ͡ॷƥ򹹿ߤ ǽǤ RFC 2136 ˽äƤ뤿ᡢ RFC 2136 򥵥ݡȤ DNS Фϡ DHCP ФιդǽȻפޤ .SH ƥ TSIG DNSSEC ϤޤݡȤƤޤ DHCP Фޤϥ饤Ȥιդ褦 DNS Фꤹ硢¤̵Ф DNS Ф򻯤Ȥˤʤ뤫⤷ޤ 򤱤뤿˺Ǥɤˡϡ IP ɥ쥹١Υѥåȥե륿Ѥơ ¤̵ۥȤι׵ȯԤ޻ߤ뤳ȤǤ 餫ˡǤϥ饤ȤιФ륻ƥ󶡤ˡ ޤ Τˤ TSIG DNSSEC ɬפǤ DHCP ʪˤϤޤޤޤƤޤ .PP ưŪ DNS (DDNS) ϡ\fBdns-update\fR Ѥ뤳ȤǼ¹Ԥޤ \fBdns-update\fR ϡ֡뼰Ǥꡢ4 ĤΥѥ᡼ޤ ȡ̤Ͽˤʤޤ Ԥȡ̤ϵˤʤޤ 4 ĤΥѥ᡼ϡ꥽쥳ɥ (RR) RR κաRR αա쥳ɤŬѤ٤ ttl Ǥ δؿκǤñʻϡdhcpd.conf եλˤꡢ ʤˤ뤫ҤƤޤ ǤϡʣμѤơ \fBdns-update\fR ѤΰƤޤ .PP Ǥϡǽ \fBdns-update\fR ؤ 1 ܤΰϡ A RR פɾǡǤ 2 ܤΰϡDHCP host-name ץ ɥᥤ󡢤ξ "ssd.example.net" ޤƥȥȥ󥰤Ϣ뤹뤳Ȥǡۤޤ 3 ܤΰϡ饤Ȥ˳Ƥ줿ɥ쥹 32 ӥåȤοͤƥХȤ "." Ƕڤä ASCII ʸѴ뤳Ȥǡ ۤޤ 4 ܤΰ TTL ϡ꡼λĤ֤Ǥ (ޤ ʤʤ DNS Фϡ׵ФƤĤ⤳ TTL ͤϤƤޤǤ ϡ꡼ڤοǤäƤǤ) .PP ǽ \fBdns-update\fR ʸȡ ³ 2 ܤιˤ PTR RR 󥹥ȡ뤵ޤ PTR 쥳ɤΥ󥹥ȡϡA RR Υ󥹥ȡƱͤǤ 쥳ɤκդϥ꡼줿ɥ쥹դˤ ".in-addr.arpa" 礵줿ΤǤ դϡɥ쥹Υ꡼襯饤ȤΡʷǤΥɥᥤ̾Ǥ .SH Ϣ dhcpd.conf(5), dhcpd.leases(5), dhclient.conf(5), dhcp-eval(5), dhcpd(8), dhclient(8), RFC2132, RFC2131 .SH Internet Systems Consortium DHCP Distribution ϡVixie Labs ȤηΤȤǡTed Lemon Ҥޤ ܥץȤλϡInternet Systems Consortium 󶡤ޤ Internet Systems Consortium ˴ؤϡ .B https://www.isc.org ˤޤ dhcp-4.2.4/doc/ja_JP.eucJP/dhcp-options.5000644 000765 000024 00000143465 11516144546 017645 0ustar00sarstaff000000 000000 .\" $Id: dhcp-options.5,v 1.3.24.3 2011-01-20 23:46:46 sar Exp $ .\" .\" Copyright (c) 2009-2010 by Internet Systems Consortium, Inc. ("ISC") .\" Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") .\" Copyright (c) 1996-2003 by Internet Software Consortium .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above .\" copyright notice and this permission notice appear in all copies. .\" .\" THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES .\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR .\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES .\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT .\" OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" .\" Internet Systems Consortium, Inc. .\" 950 Charter Street .\" Redwood City, CA 94063 .\" .\" https://www.isc.org/ .\" .\" This software has been written for Internet Systems Consortium .\" by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. .\" To learn more about Internet Systems Consortium, see .\" ``https://www.isc.org/''. To learn more about Vixie Enterprises, .\" see ``http://www.vix.com''. To learn more about Nominum, Inc., see .\" ``http://www.nominum.com''. .\" .\" %FreeBSD: src/contrib/isc-dhcp/common/dhcp-options.5,v 1.2.2.1 2002/04/11 10:16:46 murray Exp % .\" $FreeBSD: doc/ja_JP.eucJP/man/man5/dhcp-options.5,v 1.11 2002/05/21 03:51:52 horikawa Exp $ .\" WORD: Dynamic Host Configuration Protocol ưŪۥȹץȥ .\" WORD: Path MTU Discovery ѥ MTU õ .\" WORD: Router Discovery 롼õ .\" WORD: Router Solicitation 롼 .\" WORD: Mask Discovery ޥõ .\" .TH dhcp-options 5 .SH ̾ dhcp-options - ưŪۥȹץȥΥץ .SH ưŪۥȹץȥ (DHCP: Dynamic Host Configuration Protocol) Ѥ뤳Ȥˤꡢ饤Ȥ DHCP Ф顢ͥåȥ ͥåȥѲǽ͡ʥӥˤĤƵҤƤ .B ץ 뤳ȤǤޤ .B dhcpd(8) .B dhclient(8) ꤹȤˡФХץɬפǤ礦 Ǥϡץʸˡ ǽʥץ̾Ƚ񼰤ʸ񲽤Ƥޤ .SH ե: ץʸ .PP DHCP \fIoption\fR ʸϡ˥ \fIoption\fR dzϤ ñΥץ̾³ץǡ³ޤ ץ̾ȥǡν񼰤ϸҤޤ ٤Ƥ DHCP ץŪ˻ꤹɬפϤʤ 饤ȤɬפʥץΤߤꤷޤ .PP ץǡˤϡΤ褦͡ʽ񼰤ޤ: .PP .B ip-address ǡפϡŪ IP ɥ쥹 (㤨 239.254.197.10) ޤ ɥᥤ̾ (㤨 haagen.isc.org) ΤɤǤǽǤ ɥᥤ̾ǻꤹ硢 Υɥᥤ̾褹ñ IP ɥ쥹ˤʤ褦ˤƤ .PP .B int32 ǡפդ 32 ӥåꤷޤ .B uint32 ǡפ̵ 32 ӥåꤷޤ .B int16 .B uint16 Υǡפϡդ̵ 16 ӥåꤷޤ .B int8 .B uint8 Υǡפϡդ̵ 8 ӥåꤷޤ ̵ 8 ӥåϡƥåȤȸƤФ뤳Ȥ⤢ޤ .PP .B text ǡפ NVT ASCII ʸꤷޤ ʸϥ֥륯Ȥdzɬפޤ 㤨 root-path ץꤹʸˡϡΤ褦ˤʤޤ .nf .sp 1 option root-path "10.0.1.4:/var/tmp/rootfs"; .fi .PP .B domain-name ǡפϥɥᥤ̾ꤷޤ ʸ֥륯ȤdzäƤޤ Υǡפϡ¾δ¸ DHCP ץˤϻȤޤ ɥᥤ̾ϡtext ץǤ뤫Τ褦ݻޤ .\" text ǡפǤ뤫Τ褦? .\" metal .PP .B flag ǡפϥ֡ͤꤷޤ ֡ͤ true ޤ false Τ줫Ǥ (⤷ϡon ޤ off ʬ䤹СǤ⤫ޤޤ) .PP .B string ǡפϡ֥륯Ȥdz NVT ASCII ʸ󤫡 ڤ 16 ʿǻꤵ륪ƥåȤϢ³Τ줫ꤷޤ 㤨мΤ褦ˤʤޤ: .nf .sp 1 option dhcp-client-identifier "CLIENT-FOO"; ⤷ option dhcp-client-identifier 43:4c:49:45:54:2d:46:4f:4f; .fi .SH Ѥץͤ .\" metal 饤ȤФ뤤ĤͤDHCP ץͤꤹΤ ȤʤȤޤ 򤹤ˤϼɾѤǤޤ .B dhcp-eval(5) ޥ˥奢ڡ˼νҤ٤Ƥޤ ɾη̤򥪥ץˤϡץ򼡤Τ褦ޤ: .nf .sp 1 \fBoption \fImy-option \fB= \fIexpression \fB;\fR .fi .PP 㤨мΤ褦ˤޤ: .nf .sp 1 option hostname = binary-to-ascii (16, 8, "-", substring (hardware, 1, 6)); .fi .SH ɸ DHCP ץ ˼͡ʥץ˴ؤ뵭Ҥϡ DHCP ץ˴ؤǿ IETF ɥեʸ񤫤ΤΤǤ ̾ǺܤƤʤץϡޤƤʤ⤷ޤ󤬡 ե뤳ȤǡΤ褦ʥץȤ뤫⤷ޤ ܤϡΡֿץפ³Ҥ򻲾ȤƤ .PP ˵ҤƤ륪ץΤΤĤϡDHCP Ф⤷ 饤ȤˤäƼưŪΤǡ桼ˤǤޤ Τ褦ʥץͤϡ¦ DHCP ץȥ륨 (Ф⤷ϥ饤) եΡ㤨оPʤɤ Ȥޤ Υץͤϡ¦ΥȤեǤ Ȥ뤳ȤϤޤ ȤΤ⡢ͤϡե뤬줿˷ꤵ뤫Ǥ ʹߤεҤˤơΤ褦ʥץˤ ֥桼ꤹ뤳ȤϤǤޤפȵޤ .PP ɸ४ץ򼨤ޤ: .PP .B option \fBall-subnets-local\fR \fIflag\fR\fB;\fR .RS 0.25i .PP ܥץϡ饤Ȥ³Ƥ IP ͥåȥ֥ͥåȤ Ѥ MTU 饤Ȥľ³Ƥ륵֥ͥåȤ MTU ƱǤȡ饤ȤꤷƤ褤ꤷޤ true ϡ֥ͥåȤƱ MTU Ǥ뤳Ȥ̣ޤ false ϡľ³ƤͥåȥΥ֥ͥåȤˤϡ꾮 MTU ĤΤȡ饤Ȥꤹ٤Ǥ뤳Ȥ̣ޤ .RE .PP .B option \fBarp-cache-timeout\fR \fIuint32\fR\fB;\fR .RS 0.25i .PP ܥץϡARP å奨ȥΥॢȤÿǻꤷޤ .RE .PP .B option \fBbootfile-name\fR \fItext\fR\fB;\fR .RS 0.25i .PP ܥץϡưեꤹ뤿˻Ѥޤ 饤ȤˤäƥݡȤƤ硢 \fBfilename\fR Ʊ̤ޤ BOOTP 饤ȤǡΥץ򥵥ݡȤƤΤϾʤǤ礦 DHCP 饤ȤˤäƤϥݡȤΤꡢ ºɬܤȤƤΤޤ .RE .PP .B option \fBboot-size\fR \fIuint16\fR\fB;\fR .RS 0.25i .PP ܥץϡ饤ѤΥǥեȤΥ֡ȥ᡼Ĺ 512 ƥåȥ֥åǻꤷޤ .RE .PP .B option \fBbroadcast-address\fR \fIip-address\fR\fB;\fR .RS 0.25i .PP ܥץϡ饤ȤΥ֥ͥåȤǻѤƤ ֥ɥ㥹ȥɥ쥹ꤷޤ ʥ֥ɥ㥹ȥɥ쥹ͤϡSTD 3 (RFC1122) 3.2.1.3 ꤵƤޤ .RE .PP .B option \fBcookie-servers\fR \fIip-address\fR [\fB,\fR \fIip-address\fR... ]\fB;\fR .RS 0.25i .PP åХץϡ饤ȤѲǽ RFC 865 åФΥꥹȤꤷޤ Фϡͥ褵Τ˥ꥹȤƤ .RE .PP .B option \fBdefault-ip-ttl\fR \fIuint8;\fR .RS 0.25i .PP ܥץϡ饤ȤǡФȤ˻Ѥ٤ ǥեȤ¸ (TTL) ꤷޤ .RE .PP .B option \fBdefault-tcp-ttl\fR \fIuint8\fR\fB;\fR .RS 0.25i .PP ܥץϡ饤Ȥ TCP ȤФȤ˻Ѥ٤ ǥեȤ TTL ꤷޤ Ǿͤ 1 Ǥ .RE .PP .B option \fBdhcp-client-identifier\fR \fIstring\fR\fB;\fR .RS 0.25i .PP ܥץȤäơۥ DHCP 饤ȼ̻Ҥ ꤹ뤳ȤǤޤ Υ饤ȼ̻ҤǾȹԤȤǡ dhcpd ϤΥۥȤΥ쥳ɤȯ뤳ȤǤޤ .PP .\" metal DHCP 饤ȤˤϡASCII ƥȤˤäƥ饤ȼ̻Ҥ ꤵ줿硢 ASCII ƥȤƬ 0 ĤΤ뤳Ȥ դƤ ξ硢 .nf option dhcp-client-identifier "foo"; ǤϤʤʲΤ褦˵ҤɬפǤ礦 option dhcp-client-identifier "\\0foo"; .fi .RE .PP .B option \fBdhcp-lease-time\fR \fIuint32\fR\fB;\fR .RS 0.25i .PP .\" metal ܥץϡ饤׵ (DHCPDISCOVER ޤ DHCPREQUEST) ǡ 饤Ȥ IP ɥ쥹Υ꡼֤׵᤹뤿˻Ѥޤ ޤб (DHCPOFFER) ǡDHCP Ф󼨤꡼֤ ꤹΤˤ⡢ΥץϻȤޤ .PP ܥץϡФǤϥ桼ľꤹ뤳ȤϤǤޤ .B dhcpd.conf(5) \fImax-lease-time\fR \fidefault-lease-time\fR Хץ ȤƤ .RE .PP .B option \fBdhcp-max-message-size\fR \fIuint16\fR\fB;\fR .RS 0.25i .PP .\" metal ܥץϡ饤ȤФ줿硢Ф饤Ȥ Ф뤹٤Ƥακ祵ꤷޤ Фꤵ줿硢饤Ȥ dhcp-max-message-size ץ ƤʤäݤˡΥФꤵ줿ͤѤޤ ϡBOOTP Ǥ DHCP Ʊͤưޤ .RE .PP .B option \fBdhcp-message\fR \fItext\fR\fB;\fR .RS 0.25i .PP .\" metal ܥץϡ㳲ˡDHCP Ф DHCPNAK å DHCP 饤Ȥإ顼å󶡤Τ˻Ѥޤ ޤ饤Ȥ󼨤줿ѥ᡼ݤͳ򼨤ˡ DHCPDECLINE åܥץȤȤ⤢ޤ .PP ܥץϡ桼ꤹ뤳ȤϤǤޤ .RE .PP .B option \fBdhcp-message-type\fR \fIuint8\fR\fB;\fR .RS 0.25i .PP .\" metal ܥץϡ饤ȤȥФξԤФ졢 DHCP ѥåȤޤǤ DHCP åΥפꤷޤ ܥץ󤬼ͤϡʲΤȤǤ (RFC2132 ꤽΤޤȴ) .PP .nf 1 DHCPDISCOVER 2 DHCPOFFER 3 DHCPREQUEST 4 DHCPDECLINE 5 DHCPACK 6 DHCPNAK 7 DHCPRELEASE 8 DHCPINFORM .fi .PP ܥץϡ桼ꤹ뤳ȤϤǤޤ .PP .RE .B option \fBdhcp-option-overload\fR \fIuint8\fR\fB;\fR .RS 0.25i .PP .\" metal ܥץϡDHCP 'sname' ⤷ 'file' եɤ DHCP ץݻ뤿˵߲ͤ᤮ˤʤäƤ뤳Ȥ Τ˻Ȥޤ DHCP ФϡֵѤ줿ѥ᡼ץ̾Ƥ줿 ֤Ķᤷ硢ܥץޤ .PP ܥץ¸ߤ硢饤ȤϡɸΥץեɤ ᤬λ塢ꤵ줿ղåեɤβԤޤ .PP ܥץͤϡʲ̤Ǥ: .PP .nf 1 'file' եɤץݻ˻ѤƤޤ 2 'sname' եɤץݻ˻ѤƤޤ 3 ξΥեɤץݻ˻ѤƤޤ .fi .PP ܥץϡ桼ꤹ뤳ȤϤǤޤ .PP .RE .PP .B option \fBdhcp-parameter-request-list\fR \fIuint16\fR\fB;\fR .RS 0.25i .PP .\" metal ܥץϡ饤ȤФ줿硢 Ф˾륪ץ򥯥饤Ȥꤷޤ ̾ ISC DHCP 饤ȤǤϡ\fIrequest\fR ʸѤƹԤޤ ܥץ󤬥饤Ȥꤵʤä硢̾ DHCP Фϡ ͭı˼ޤ뤹٤ƤΥץ֤ޤ ܥץ󤬥оǻꤵ줿硢ФϤλꤵ줿ץ ֤ޤ ϡ饤Ȥ׵ᤷʤäץ򡢥饤Ȥ Τ˻Ѥޤ ޤ̾掠Ф֤ץΥåȤ򤵤¤ɬפΤ 饤ȤФơDHCP ФαĴΤˤѤޤ .RE .PP .B option \fBdhcp-rebinding-time\fR \fIuint32\fR\fB;\fR .RS 0.25i .PP .\" metal ܥץϡ饤Ȥɥ쥹Ƥ REBINDING ֤ ܹԤޤǤλ֤ÿǻꤷޤ .PP ܥץϡ桼ꤹ뤳ȤϤǤޤ .PP .RE .PP .B option \fBdhcp-renewal-time\fR \fIuint32\fR\fB;\fR .RS 0.25i .PP .\" metal ܥץϡ饤Ȥɥ쥹Ƥ RENEWING ֤ ܹԤޤǤλ֤ÿǻꤷޤ .PP ܥץϡ桼ꤹ뤳ȤϤǤޤ .PP .RE .PP .B option \fBdhcp-requested-address\fR \fIip-address\fR\fB;\fR .RS 0.25i .PP .\" metal ܥץϡ饤ȤDHCPDISCOVER IP ɥ쥹 Ƥ뤳Ȥ׵᤹Τ˻Ѥޤ .PP ܥץϡ桼ꤹ뤳ȤϤǤޤ .PP .RE .PP .B option \fBdhcp-server-identifier\fR \fIip-address\fR\fB;\fR .RS 0.25i .PP .\" metal ܥץϡDHCPOFFER DHCPREQUEST åǻѤ졢 ޤ DHCPACK DHCPNAK åˤޤޤ뤳Ȥޤ DHCP Фϡ饤Ȥ (: ʣФ) ꡼󼨤 ̤Ǥ褦DHCPOFFER ܥץޤޤ DHCP 饤ȤϡDHCP Фإ˥㥹Ȥ뤹٤Ƥ DHCP å 襢ɥ쥹Ȥ 'server identifier' եɤƤѤޤ ޤ DHCP 饤ȤϡDHCPREQUEST åܥץޤᡢ ʣΥ꡼󼨤Τɤ줿򼨤ޤ .PP ܥץͤϡФ IP ɥ쥹Ǥ .PP ܥץϡ桼ľꤹ뤳ȤϤǤޤ .B \fIdhcpd.conf(5) \fIserver-identifier\fR Хץ򻲾ȤƤ .PP .RE .PP .B option \fBdomain-name\fR \fItext\fR\fB;\fR .RS 0.25i .PP ܥץϡɥᥤ͡ॷƥѤƥۥ̾褹Ȥ 饤ȤѤ٤ɥᥤ̾ꤷޤ .RE .PP .B option \fBdomain-name-servers\fR \fIip-address\fR [\fB,\fR \fIip-address\fR... ]\fB;\fR .RS 0.25i .PP domain-name-servers ץϡ饤ȤѲǽ ɥᥤ͡ॷƥ (STD 13, RFC 1035) Υ͡ॵФΥꥹȤꤷޤ Фϡͥ褵Τ˥ꥹȤƤ .RE .PP .B option \fBextensions-path\fR \fItext\fR\fB;\fR .RS 0.25i .PP .\" metal ܥץϡɲåץޤեΥե̾ꤷޤ ɲåץϡRFC2132 ǵꤵƤ DHCP ץν񼰤˱ä ᤵޤ .RE .PP .B option \fBfinger-server\fR \fIip-address\fR [\fB,\fR \fIip-address\fR... ]\fB;\fR .RS 0.25i .PP Finger Хץϡ饤ȤѲǽ Finger ΥꥹȤ ꤷޤ Фϡͥ褵Τ˥ꥹȤƤ .RE .PP .B option \fBfont-servers\fR \fIip-address\fR [\fB,\fR \fIip-address\fR... ]\fB;\fR .RS 0.25i .PP ܥץϡ饤ȤѲǽ X Window System եȥФ ꤷޤ Фϡͥ褵Τ˥ꥹȤƤ .RE .PP .B option \fBhost-name\fR \fIstring\fR\fB;\fR .RS 0.25i .PP ܥץϡ饤Ȥ̾ꤷޤ ̾ϡɥᥤ̾˽ƤƤ⡢ʤƤ⤫ޤ (ɥᥤ̾ꤹˤϡdomain-name ץλѤ򤪴ᤷޤ) ʸˤĤƤ RFC 1035 򻲾ȤƤ 饤ȥޥΥۥ̾ꤵƤʤ (ʤ .B rc.conf(5) ǶʸꤵƤ) Τߡ .B dhclient-script(8) ܥץºŤޤ .RE .PP .B option \fBieee802-3-encapsulation\fR \fIflag\fR\fB;\fR .RS 0.25i .PP ܥץϡ󥿥եͥåȤǤˡ 饤ȤͥåȥС 2 (RFC 894) IEEE 802.3 (RFC 1042) ΤɤΥץ벽Ѥ٤ꤷޤ false ϡ饤Ȥ RFC 894 Υץ벽Ѥ٤Ǥ뤳Ȥ ̣ޤ true ϡ饤Ȥ RFC 1042 Υץ벽Ѥ٤Ǥ뤳Ȥ ̣ޤ .RE .PP .B option \fBien116-name-servers\fR \fIip-address\fR [\fB,\fR \fIip-address\fR... ]; .RS 0.25i .PP ien116-name-servers ץϡ 饤ȤѲǽ IEN 116 ͡ॵФΥꥹȤꤷޤ Фϡͥ褵Τ˥ꥹȤƤ .RE .PP .B option \fBimpress-servers\fR \fIip-address\fR [\fB,\fR \fIip-address\fR... ]\fB;\fR .RS 0.25i .PP impress-server ץϡ 饤ȤѲǽ Imagen Impress ФΥꥹȤꤷޤ Фϡͥ褵Τ˥ꥹȤƤ .RE .PP .B option \fBinterface-mtu\fR \fIuint16\fR\fB;\fR .RS 0.25i .PP ܥץϡΥ󥿥եФƻѤ MTU ꤷޤ MTU ФǾͤ 68 Ǥ .RE .PP .B option \fBip-forwarding\fR \fIflag\fR\fB;\fR .RS 0.25i .PP ܥץϡ饤ȤѥåȤž褦 ʬ IP ؤꤹ٤ꤷޤ false IP ž̵ˤ뤳Ȥ̣ true IP žͭˤ뤳Ȥ̣ޤ .RE .PP .B option \fBirc-server\fR \fIip-address\fR [\fB,\fR \fIip-address\fR... ]\fB;\fR .RS 0.25i .PP IRC Хץϡ饤ȤѲǽ IRC ΥꥹȤꤷޤ Фϡͥ褵Τ˥ꥹȤƤ .RE .PP .B option \fBlog-servers\fR \fIip-address\fR [\fB,\fR \fIip-address\fR... ]\fB;\fR .RS 0.25i .PP log-server ץϡ饤ȤѲǽ MIT-LCS UDP Ф ꥹȤꤷޤ Фϡͥ褵Τ˥ꥹȤƤ .RE .PP .B option \fBlpr-servers\fR \fIip-address \fR [\fB,\fR \fIip-address\fR... ]\fB;\fR .RS 0.25i .PP LPR Хץϡ 饤ȤѲǽ RFC 1179 饤ץ󥿥ФΥꥹȤꤷޤ Фϡͥ褵Τ˥ꥹȤƤ .RE .PP .B option \fBmask-supplier\fR \fIflag\fR\fB;\fR .RS 0.25i .PP ܥץϡICMP Ѥ֥ͥåȥޥ׵Фơ 饤Ȥ٤ꤷޤ false ϡ饤Ȥ٤ǤʤȤ̣ޤ true ϡ饤Ȥ٤Ǥ뤳Ȥ̣ޤ .RE .PP .B option \fBmax-dgram-reassembly\fR \fIuint16\fR\fB;\fR .RS 0.25i .PP ܥץϡ饤ȤȤΩƤν򤹤٤ ǡॵꤷޤ Ǿͤ 576 Ǥ .\" The minimum value legal value is 576. .\" The minimum legal value is 576. (horikawa@jp.freebsd.org 19990404) .RE .PP .B option \fBmerit-dump\fR \fItext\fR\fB;\fR .RS 0.25i .PP ܥץϡ饤Ȥå夹Ȥ 饤ȤΥ᡼פեΥѥ̾ꤷޤ ѥν񼰤ϡNVT ASCII ʸʸʤʸǤ .RE .PP .B option \fBmobile-ip-home-agent\fR \fIip-address\fR [\fB,\fR \fIip-address\fR... ]\fB;\fR .RS 0.25i .PP ܥץϡ饤ȤѲǽʥХ IP ۡ२Ȥ IP ɥ쥹ΥꥹȤꤷޤ Ȥϡͥ褵Τ˥ꥹȤƤ ̾泌Ȥ 1 ĤǤ礦 .RE .PP .B option \fBnds-context\fR \fIstring\fR\fB;\fR .RS 0.25i .PP .\" metal nds-context ץϡNDS 饤ȤΤκǽ NetWare ǥ쥯ȥꥵӥ̾ꤷޤ .RE .PP .B option \fBnds-servers\fR \fIip-address\fR [\fB,\fR \fIip-address\fR... ]\fB;\fR .RS 0.25i .PP .\" metal nds-servers ץϡNDS Ф IP ɥ쥹ΥꥹȤꤷޤ .RE .PP .B option \fBnds-tree-name\fR \fIstring\fR\fB;\fR .RS 0.25i .PP .\" metal nds-tree-name ץϡNDS 饤ȤѤ٤ NDS ĥ꡼ ̾ꤷޤ .RE .PP .B option \fBnetbios-dd-server\fR \fIip-address\fR [\fB,\fR \fIip-address\fR... ]\fB;\fR .RS 0.25i .PP NetBIOS ǡۥ (NBDD) ץϡ RFC 1001/1002 NBDD ФΥꥹȤͥ褵Τ˻ꤷޤ .RE .PP .B option \fBnetbios-name-servers\fR \fIip-address\fR [\fB,\fR \fIip-address\fR...]\fB;\fR .RS 0.25i .PP NetBIOS ͡ॵ (NBNS) ץϡ RFC 1001/1002 NBNS ͡ॵФΥꥹȤͥ褵Τ˻ꤷޤ ߤǤϡNetBIOS ͡ॵӥ WINS ȸƤФ뤳Ȥ¿Ǥ netbios-name-servers ץѤơWINS ФǽǤ .RE .PP .B option \fBnetbios-node-type\fR \fIuint8\fR\fB;\fR .RS 0.25i .PP NetBIOS Ρɥץץϡ ǽ NetBIOS over TCP/IP 饤Ȥ RFC 1001/1002 ˵ҤƤ褦ꤷޤ ͤñΥƥåȤȤƻꤵ졢饤ȥפ̣ޤ .PP ѲǽʥΡɥפϼ̤Ǥ: .PP .TP 5 .I 1 B Ρ: ֥ɥ㥹 - WINS ̵ .TP .I 2 P Ρ: ԥ - WINS Τ .TP .I 4 M Ρ: ߥå - ֥ɥ㥹ȸ WINS .TP .I 8 H Ρ: ϥ֥å - WINS ˥֥ɥ㥹 .RE .PP .B option \fBnetbios-scope\fR \fIstring\fR\fB;\fR .RS 0.25i .PP NetBIOS ץץϡRFC 1001/1002 ˵ꤵƤ褦ˡ 饤Ȥ NetBIOS over TCP/IP ץѥ᡼ꤷޤ ʸˤĤƤ RFC1001, RFC1002, RFC1035 򻲾ȤƤ .RE .PP .B option \fBnis-domain\fR \fItext\fR\fB;\fR .RS 0.25i .PP ܥץϡ饤Ȥ NIS (Sun Network Information Services) ɥᥤꤷޤ ɥᥤν񼰤ϡNVT ASCII ʸʸʤʸǤ .RE .PP .B option \fBnis-servers\fR \fIip-address\fR [\fB,\fR \fIip-address\fR... ]\fB;\fR .RS 0.25i .PP ܥץϡ饤ȤѲǽ NIS Ф򼨤 IP ɥ쥹 ꥹȤꤷޤ Фϡͥ褵Τ˥ꥹȤƤ .RE .PP .B option \fBnisplus-domain\fR \fItext\fR\fB;\fR .RS 0.25i .PP ܥץϡ饤Ȥ NIS+ ɥᥤ̾ꤷޤ ɥᥤν񼰤ϡNVT ASCII ʸʸʤʸǤ .RE .PP .B option \fBnisplus-servers\fR \fIip-address\fR [\fB,\fR \fIip-address\fR... ]\fB;\fR .RS 0.25i .PP ܥץϡ饤ȤѲǽ NIS+ Ф򼨤 IP ɥ쥹 ꥹȤꤷޤ Фϡͥ褵Τ˥ꥹȤƤ .RE .PP .B option \fBnntp-server\fR \fIip-address\fR [\fB,\fR \fIip-address\fR... ]\fB;\fR .RS 0.25i .PP NNTP Хץϡ饤ȤѲǽ NNTP ΥꥹȤꤷޤ Фϡͥ褵Τ˥ꥹȤƤ .RE .PP .B option \fBnon-local-source-routing\fR \fIflag\fR\fB;\fR .RS 0.25i .PP ܥץϡʻϩ (non-local source route) ǡž褦ˡ饤Ȥʬ IP ؤꤹ٤ ꤷޤ (ܹܤˤĤƤ [4] 3.3.5 򻲾ȤƤ) false ϤΤ褦ʥǡžĤʤȤ̣ true žḤ̂ޤ .RE .PP .B option \fBntp-servers\fR \fIip-address\fR [\fB,\fR \fIip-address\fR... ]\fB;\fR .RS 0.25i .PP ܥץϡ饤ȤѲǽ NTP (RFC 1035) Ф򼨤 IP ɥ쥹ꤷޤ Фϡͥ褵Τ˥ꥹȤƤ .RE .PP .B option \fBnwip-domain\fR \fIstring\fR\fB;\fR .RS 0.25i .PP .\" metal NetWare/IP 饤ȤѤ٤ NetWare/IP ɥᥤ̾Ǥ .RE .PP .B option \fBnwip-suboptions\fR \fIstring\fR\fB;\fR .RS 0.25i .PP .\" metal NetWare/IP 饤ѤΥ֥ץΥ󥹤Ǥ ܤ RFC2242 򻲾ȤƤ ̾ܥץ NetWare/IP ֥ץꤹ뤳Ȥ ꤵޤ ʤϡNetWare/IP ֥ץפξϤ򻲾ȤƤ .RE .PP .B option \fBpath-mtu-aging-timeout\fR \fIuint32\fR\fB;\fR .RS 0.25i .PP ܥץϡRFC 1191 뵡ȯ줿ѥ MTU ͤ 󥰤˻Ѥ륿ॢ (ñ) ꤷޤ .RE .PP .B option \fBpath-mtu-plateau-table\fR \fIuint16\fR [\fB,\fR \fIuint16\fR... ]\fB;\fR .RS 0.25i .PP ܥץϡRFC 1191 ѥ MTU õ (Path MTU Discovery) »ܻ˻Ѥ MTU Υɽꤷޤ ɽν񼰤ϡǾ˺ޤǤΡ16 ӥå̵ΥꥹȤǤ Ǿ MTU 68 꾮ƤϤʤޤ .RE .PP .B option \fBperform-mask-discovery\fR \fIflag\fR\fB;\fR .RS 0.25i .PP ܥץϡ饤Ȥ ICMP Ѥƥ֥ͥåȥޥõ »ܤ٤ꤷޤ false ϡ饤Ȥޥõ»ܤ٤ǤʤȤ̣ޤ true ϡ饤Ȥޥõ»ܤ٤Ǥ뤳Ȥ̣ޤ .RE .PP .nf .B option \fBpolicy-filter\fR \fIip-address ip-address\fR [\fB,\fR \fIip-address ip-address\fR...]\fB;\fR .RE .fi .RS 0.25i .PP ܥץϡʻϩФݥꥷե륿ꤷޤ ե륿ϡIP ɥ쥹ȥޥȤΥꥹȤʤꡢ 夹ϩ椵줿ǡѤΥե륿Ȥʤ /ޥȤꤷޤ .PP ۥåץɥ쥹ե륿ΤˤŬ礷ʤϩ椵줿 ǡϡ饤Ȥ˴٤Ǥ .PP ʤ STD 3 (RFC1122) 򻲾ȤƤ .RE .PP .B option \fBpop-server\fR \fIip-address\fR [\fB,\fR \fIip-address\fR... ]\fB;\fR .RS 0.25i .PP POP3 Хץϡ饤ȤѲǽ POP3 ΥꥹȤꤷޤ Фϡͥ褵Τ˥ꥹȤƤ .RE .PP .B option \fBresource-location-servers\fR \fIip-address\fR [\fB, \fR\fIip-address\fR...]\fB;\fR .fi .RS 0.25i .PP ܥץϡ饤ȤѲǽ RFC 887 ꥽󥵡ФΥꥹȤꤷޤ Фϡͥ褵Τ˥ꥹȤƤ .RE .PP .B option \fBroot-path\fR \fItext\fB;\fR\fR .RS 0.25i .PP ܥץϡ饤ȤΥ롼ȥǥޤޤѥ̾ꤷޤ ѥν񼰤ϡNVT ASCII ʸʸʤʸǤ .RE .PP .B option \fBrouter-discovery\fR \fIflag\fR\fB;\fR .RS 0.25i .PP ܥץϡRFC 1256 롼õ (Router Discovery) Ѥơ롼٤ꤷޤ false ϡ饤Ȥ롼õ»ܤ٤ǤʤȤ̣ޤ true ϡ饤Ȥϥ롼õ»ܤ٤Ǥ뤳Ȥ̣ޤ .RE .PP .B option \fBrouter-solicitation-address\fR \fIip-address\fR\fB;\fR .RS 0.25i .PP ܥץϡ饤ȤΥ롼襢ɥ쥹ꤷޤ .RE .PP .B option routers \fIip-address\fR [\fB,\fR \fIip-address\fR... ]\fB;\fR .RS 0.25i .PP routers ץϡ饤ȤΥ֥ͥåȾˤ롼 IP ɥ쥹ΥꥹȤꤷޤ 롼ϡͥ褵Τ˥ꥹȤƤ .RE .PP .B option slp-directory-agent \fIboolean ip-address [\fB,\fR \fIip-address\fR... ]\fB;\fR .RS 0.25i .PP .\" metal ܥץϡ2 Ĥιܤꤷޤ: 1 İʾΥӥץȥǥ쥯ȥꥨ (Service Location Protocol Directory Agent) IP ɥ쥹ȡ Υɥ쥹λѤŪɤǤ ǽΥ֡ͤ true ǤСSLP ȤϡͿ줿 IP ɥ쥹ΤߤѤ٤Ǥ ͤ false ǤСSLP ȤϡSLP Ȥ ǽưŪ⤷ϼưŪʥޥ㥹õɲäǹԤäƤ⹽ޤ (ܤ RFC2165 򻲾ȤƤ) .PP ܥץ slp-service-scope ץˤơ SLP ȡפȤϡDHCP ץȥѤꤵ줿ޥ ưƤ륵ӥץȥ륨ȤؤƤ뤳Ȥ դƤ .PP ޤĤδȤ SLP NDS ȸƤǤ뤳ȤⵤդƤ ⤷ NDS ǥ쥯ȥꥨȤꡢΥɥ쥹ꤹɬפ ϡ slp-directory-agent ץѤǤϤǤ .RE .PP .B option slp-service-scope \fIboolean text\fR\fB;\fR .RS 0.25i .PP .\" metal ӥץȥΥӥץץϡ 2 Ĥιܤꤷޤ: SLP ѤΥӥפΥꥹȤȡΥꥹȤλѤŪɤǤ ǽΥ֡ͤ true ǤСSLP Ȥϡܥץˤ 󶡤륹פΥꥹȤΤߤѤ٤Ǥ ǤʤСΥץ󶡤ꥹȤͥ褷ơ 줾θͭŪȤäƤ⹽ޤ .PP text ʸϡSLP ȤѤ٤פΡ޶ڤ ꥹȤȤƤ Ͼάǽǡξ SLP ȤϡʬΤäƤ ٤ƤΥǥ쥯ȥꥨȤΥפΰꥹȤȤޤ .RE .PP .B option \fBsmtp-server\fR \fIip-address\fR [\fB,\fR \fIip-address\fR... ]\fB;\fR .RS 0.25i .PP SMTP Хץϡ饤ȤѲǽ SMTP ФΥꥹȤ ꤷޤ Фϡͥ褵Τ˥ꥹȤƤ .RE .PP .nf .B option \fBstatic-routes\fR \fIip-address ip-address\fR [\fB,\fR \fIip-address ip-address\fR...]\fB;\fR .fi .RS 0.25i .PP ܥץϡ饤ȤϩåȤ߹٤ ŪϩΥꥹȤꤷޤ ƱФʣηϩꤵƤϡ ͥ٤㤯ʤǥꥹȤޤ .PP ϩ IP ɥ쥹ȤΥꥹȤʤޤ ǽΥɥ쥹ϰ襢ɥ쥹Ǥꡢ 2 ܤΥɥ쥹ϤΰФ롼Υɥ쥹Ǥ .PP ǥեȷϩ (0.0.0.0) ϡŪϩФƤʰǤ ǥեȷϩꤹˤϡ .B routers ץѤƤ ޤܥץϡ饹쥹 IP ϩտޤΤǤ ʤȤդƲ ϥ֥ͥåȥޥޤǤޤ ߡ饹쥹 IP ϩϡäȤ⹭ŸƤ ϩɸʤΤǡܥץϼ¼Ụ̵̄Ǥ ơޥե DHCP 饤ȤϤȤ褯Τ줿 DHCP 饤ȤˤϼƤޤ .RE .PP .nf .B option \fBstreettalk-directory-assistance-server\fR \fIip-address\fR [\fB,\fR \fIip-address\fR...]\fB;\fR .fi .RS 0.25i .PP StreetTalk Directory Assistance (STDA) Хץϡ 饤ȤѲǽ STDA ΥꥹȤꤷޤ Фϡͥ褵Τ˥ꥹȤƤ .RE .PP .B option \fBstreettalk-server\fR \fIip-address\fR [\fB,\fR \fIip-address\fR... ]\fB;\fR .RS 0.25i .PP StreetTalk Хץϡ 饤ȤѲǽ StreetTalk ΥꥹȤꤷޤ Фϡͥ褵Τ˥ꥹȤƤ .RE .PP .B option subnet-mask \fIip-address\fR\fB;\fR .RS 0.25i .PP ֥ͥåȥޥץϡRFC 950 ˽äơ 饤ȤΥ֥ͥåȥޥꤷޤ Τɤˤ⥵֥ͥåȥޥץ󤬻ꤵƤʤ硢 ǽʤȤơdhcpd ϡɥ쥹Ƥ褦ȤƤ ͥåȥΥ֥ͥå顢֥ͥåȥޥѤޤ ɥ쥹Ƥ褦ȤƤͥåȥΥ .I ɤΤ褦 ֥ͥåȥޥץǤäƤ⡢ ֥ͥåǻꤵ줿֥ͥåȥޥͥ褷ޤ .RE .PP .B option \fBsubnet-selection\fR \fIstring\fR\fB;\fR .RS 0.25i .PP .\" metal (׵᤬Ф줿֥ͥåȤˤĤʤ줿졼ФΥɥ쥹˴Ť) ̾򤵤ǤΤǤϤʤ֥ͥåȤΥɥ쥹ɬפʾ硢 饤ȤФޤ RFC3011 򻲾ȤƤ ΥФˤƻȤ륪ץʥФ 118 Ǥ ΥʥФϰ餺äƤʥФǤϤʤ 㤦ͤѤ륯饤Ȥ¸ߤ뤳ȤդƤ ΥץλѤϾ¸ŪǤȹͤ٤Ǥ礦! .PP ܥץϡФǤϥ桼ꤹ뤳ȤϤǤޤ .PP .RE .PP .B option \fBswap-server\fR \fIip-address\fR\fB;\fR .RS 0.25i .PP ܥץϡ饤ȤΥåץФ IP ɥ쥹ꤷޤ .RE .PP .B option \fBtcp-keepalive-garbage\fR \fIflag\fR\fB;\fR .RS 0.25i .PP ܥץϡŤȤθߴΤˡߤΥƥåȤȰˡ TCP ץ饤֥å򥯥饤Ȥ٤ꤷޤ false ϡߤΥƥåȤ٤ǤʤȤ̣ޤ true ϡߤΥƥåȤ٤Ǥ뤳Ȥ̣ޤ .RE .PP .B option \fBtcp-keepalive-interval\fR \fIuint32\fR\fB;\fR .RS 0.25i .PP ܥץϡ饤Ȥ TCP ץ饤 (keepalive) å TCP ³ԤĤ٤ֳ (ñ) ꤷޤ ֤ 32 ӥå̵ǻꤷޤ 0 ϡץꥱŪ׵ᤷʤ¤ꡢ饤Ȥ ³˥ץ饤֥å٤ǤʤȤ̣ޤ .RE .PP .B option \fBtftp-server-name\fR \fItext\fR\fB;\fR .RS 0.25i .PP ܥץ TFTP ФꤹΤ˻Ѥ졢饤Ȥ ݡȤƤˤ \fBserver-name\fR Ʊ̤ޤ BOOTP 饤Ȥϡܥץ򥵥ݡȤʤǤ礦 DHCP 饤ȤˤäƤϥݡȤƤΤꡢ ºɬܤȤƤΤޤ .RE .PP .B option time-offset \fIint32\fR\fB;\fR .RS 0.25i .PP time-offset ץϡ (UTC) Ȥơ 饤ȤΥ֥ͥåȤΥեåȤäǻꤷޤ .RE .PP .B option time-servers \fIip-address\fR [, \fIip-address\fR... ]\fB;\fR .RS 0.25i .PP time-server ץϡ饤ȤѲǽ RFC 868 掠Ф ꥹȤꤷޤ Фϡͥ褵Τ˥ꥹȤƤ .RE .PP .B option \fBtrailer-encapsulation\fR \fIflag\fR\fB;\fR .RS 0.25i .PP ܥץϡARP ץȥѻˡ饤Ȥȥ쥤Ѥ ͥ (RFC 893 [14]) 򤹤٤ꤷޤ false ϡ饤Ȥȥ쥤Ѥߤ٤ǤʤỌ̇̄ޤ true ϡ饤Ȥȥ쥤Ѥߤ٤ǤỌ̇̄ޤ .RE .PP .B option \fBuap-servers\fR \fItext\fR\fB;\fR .RS 0.25i .PP .\" metal ܥץϡ桼ǧڥץȥ (UAP) ޤ줿ǧ׵ ǽϤΤ桼ǧڥӥ򤽤줾ؤƤ URL ΥꥹȤꤷޤ UAP Ф HTTP 1.1 ³ SSLv3 ³뤳ȤǤޤ ꥹȤ˴ޤޤ줿 URL ˥ݡʬޤޤƤʤϡ ̾ΥǥեȥݡȤꤵޤ (Ĥޤ http ˤ 80 ֡https ˤ 443 ) ꥹȤ˴ޤޤ줿 URL ˥ѥʬޤޤƤʤϡ ѥ /uap Ȳꤵޤ 2 İʾ URL ΥꥹȤ˻ꤵ줿硢URL ϶Ƕڤޤ .RE .PP .B option \fBuser-class\fR \fIstring\fR\fB;\fR .RS 0.25i .PP .\" metal ܥץϡ桼̾򥯥饤Ȥ˻ꤹʤȤơ Ĥ DHCP 饤ȤǻȤޤ vendor-class-identifier ץƱͤ˻Ȥޤ ͤϡ٥ǤϤʤ桼ˤäƻꤵޤ ǶΤۤȤɤ DHCP 饤Ȥϡμ̻Ҥͤꤹ뤿 桼󥿥եƤޤ μ̻Ҥϡ̾ƥʸǤ .RE .PP .B option \fBvendor-class-identifier\fR \fIstring\fR\fB;\fR .RS 0.25i .PP .\" metal ܥץϡ٥פ䡢ǽǤ DHCP 饤Ȥ ̤뤿ˡĤ DHCP 饤ȤǻȤޤ ξƤϡ٥ͭΥХʸǡɸǤϵꤵƤޤ 饤ȤФ٥饹̻Ҥǧˤϡ ʲ DHCP ե˲äƤ: .nf .PP set vendor-class option vendor-class-identifier; .fi .PP ϡDHCP ФΥ꡼ǡ١եΡ ʲΤ褦 set ʸ vendor-class-identifier ץ äƤ륯饤Ȥ٤ƤΥȥ˺Ѥޤ .nf .PP set vendor-class "SUNW.Ultra-5_10"; .fi .PP vendor-class-identifier ץϡ̾ DHCP Server ˤäơ .B vendor-encapsulated-options ץ֤륪ץꤹΤ˻Ȥޤ ʤϡdhcpd.conf ޥ˥奢ڡ VENDOR ENCAPSULATED OPTIONS Ϥ򻲾ȤƤ .RE .PP .B option \fBvendor-encapsulated-options\fR \fIstring\fR\fB;\fR .RS 0.25i .PP .\" metal \fBvendor-encapsulated-options\fR ץϡ1 ĤΥ٥ͭ͡ ⤷ 1 ĤޤϤʾΥ٥֥ͭץޤߤޤ ܥץϡ̾ DHCP ФեꤵΤǤ ޤ ̾ϡ٥饹٥졢 ٥饹֥ץ졢Υ֥ץͤ 졢DHCP ФϤȤ˱Ȥ߾夲ޤ .PP 褯Τ줿 DHCP 饤ȥ٥ (ΤȤ Microsoft Windows 2000 DHCP 饤) ΤĤΥǥեȤưǤϡ ΥץϼưŪꤵޤ¾ΤΤ˴ؤƤϡ ưꤷʤФʤޤ ܺ٤ \fIdhcpd.conf\fI VENDOR ENCAPSULATED OPTIONS ξϤ ȤƤ .RE .PP .B option \fBwww-server\fR \fIip-address\fR [\fB,\fR \fIip-address\fR... ]\fB;\fR .RS 0.25i .PP WWW Хץϡ饤ȤѲǽ WWW ΥꥹȤꤷޤ Фϡͥ褵Τ˥ꥹȤƤ .RE .PP .B option \fBx-display-manager\fR \fIip-address\fR [\fB,\fR \fIip-address\fR... ]\fB;\fR .RS 0.25i .PP ܥץϡ饤ȤѲǽ X Window System ǥץ쥤ޥ͡¹ԤƤ륷ƥΥꥹȤꤷޤ ɥ쥹ϡͥ褵Τ˥ꥹȤƤ .RE .SH 졼Ⱦ󥪥ץ .\" metal IETF ɥե draft-ietf-dhc-agent-options-11.txt ˤϡ DHCP 졼Ȥ DHCP ѥåȤ DHCP Фžݡ DHCP ѥåȤղä뤳ȤΤǤϢΥץ벽줿ץ Ƥޤ ФϡΥץ˴Ťɥ쥹η (䡢¾Ƚ) ԤȤǤޤ ޤФϡ졼Ȥ̤֤ɤΥѥåȤˤ Υץ֤ޤ ˤäƥ졼Ȥϡ䥢ƥ󥰤ʤɤ ԤˡΥץ˴ޤޤѤǤޤ .PP ߤΥɥեȤˤ 2 ĤΥץƤޤ DHCP ФǤΥץ򻲾Ȥˤϡץ̾ "agent" ΤȤ˥ԥꥪɤĤθ˥ץ̾³Ƥ ФǤΥץͤ뤳Ȥϡ ̾濫ޤͭǤϤޤ󤬡ƤƤޤ Υץϡ饤ȤǤϥݡȤƤޤ .PP .B option \fBagent.circuit-id\fR \fIstring\fR\fB;\fR .RS 0.25i .PP circuit-id ֥ץϡ饤Ȥ饵Фؤ DHCP ѥåȤ äåȤ򼨤ȥʥåȼ̻Ҥ 󥳡ɤƤޤ ϡDHCP ŬڤʥåȤؤ֤褦 ȤˤäƻȤ뤳ȤտޤƤޤ ߡΥץν񼰤ϥ٥¸ȤʤäƤꡢ ¿ʬΤޤ޻ĤǤ礦 褳ν񼰤ɸಽǽ⡢ߤΥɥեȤˤϻĤƤޤ .RE .PP .B option \fBagent.remote-id\fR \fIstring\fR\fB;\fR .RS 0.25i .PP remote-id ֥ץϡåȤνüΥ⡼ȥۥȤ 򥨥󥳡ɤƤޤ ˴ޤޤǤϡΤ褦ʤΤǤ ƽи ID 󡢥桼̾󡢥⡼ ATM ɥ쥹֥ǥ ID ¾Ʊͤʾ §ŪˤϡΥץΰ̣ϤƤޤ ̾åȤΥ⡼ȥɤФưդǤ褦 ݾڤ줿ʤ餫Υ֥Ȥȹͤ٤ΤǤ .RE .SH 饤 FQDN ֥ץ .\" metal ߡ󥿡ͥåȥɥե draft-ietf-dhc-fqdn-option-00.txt Ƥ륯饤 FQDN ץϡޤɸȤʤäƤϤޤ Ǥ˽ʬѤƤꡢ桹⤳Ƥޤ ץν񼰤ʣʤᡢǤϡñȤΥץǤϤʤ ֥ץ֤˼Ƥޤ Ūˤϡܥץϡ桼ˤäꤵΤǤϤʤ ư DNS ƥΰȤƻȤ٤ΤǤ .PP .B option fqdn.no-client-update \fIflag\fB; .RS 0.25i .PP ܥץ󤬥饤ȤФ줿硢줬 true ǤС 饤Ȥϼʬ A 쥳ɤ򹹿ʤȤ̣ޤ Ф饯饤ȤФ줿ϡ饤Ȥ ʬ A 쥳ɤ򹹿 \fI٤ǤϤʤ\fR Ȥ̣ޤ .RE .PP .B option fqdn.server-update \fIflag\fB; .RS 0.25i .PP ܥץ󤬥饤Ȥ饵ФФ줿硢 Ф˥饤Ȥ A 쥳ɤι׵ᤷƤޤ ФФ줿硢Ф饤Ȥ A 쥳ɤ (⤷Ϥ⤦Ȥ) Ǥ뤳Ȥ̣ޤ .RE .PP .B option fqdn.encoded \fIflag\fB; .RS 0.25i .PP true Ǥäץ˴ޤޤɥᥤ̾ ASCII ƥȤǤϤʤDNS 磻եޥåȤ 󥳡ɤƤ뤳Ȥ򼨤Ƥޤ 饤Ȥϡʬ FQDN ץ DNS 磻եޥåȤ ݡȤƤʤ硢̾盧Υ֥ץ false ꤷޤ ФϾˡ饤ȤꤷΤƱͤꤷ֤٤Ǥ ͤեꤵƤϡ\fIfqdn.fqdn\fR ֥ץ 󥳡ɤեޥåȤ椷ޤ .RE .PP .B option fqdn.rcode1 \fIflag\fB; .PP .B option fqdn.rcode2 \fIflag\fB; .RS 0.25i .PP ΥץϤ줾졢A 쥳ɤ PTR 쥳ɤι̤򼨤ޤ ϡDHCP Ф DHCP 饤ȤؤΤޤ ΥեɤͤϡDNS ץȥ뵬ʤˤƤޤ .RE .PP .B option fqdn.fqdn \fItext\fB; .RS 0.25i .PP 饤ȤѤ˾ɥᥤ̾ꤷޤ ϴ줿ɥᥤ̾Ǥ⡢ñΥ٥Ǥ⹽ޤ ⤷̾ '.' ʸޤޤʤС̾ϴƤ餺 Ф̾줿ɥᥤΤ̾򹹿ޤ .RE .PP ⤷Υ֥ץѤ褦ȻפäƤΤǤС 饤 FQDN ץΥɥե (⤷ϡɸˤʤäϤɸ) 򻲾Ȥ뤳Ȥ򶯤侩ޤ ʸϡΥɥեȤ٤绨ĤԴǤꡢ 饤 FQDN ץ󵬳ʤ򤹤Ǥ򤷤Ƥͤ˻Ȥ뤳Ȥ ñ˰տޤƤΤǤ .SH NetWare/IP ֥ץ .\" metal RFC2242 ϡNovell NetWare/IP 饤ѤΥץ벽줿 ץȤƤޤ DHCP ФˤƤΥץѤˤϡץ̾ "nwip" θ˥ԥꥪɤĤθ˥ץ̾³Ƥ ʲΥץ󤬻Ǥޤ: .PP .B option \fBnwip.nsq-broadcast\fR \fIflag\fR\fB;\fR .RS 0.25i .PP true Ǥä硢饤ȤϡNetWare/IP Фΰ֤ õΤ NetWare Nearest Server Query Ȥ٤Ǥ ܥ֥ץ false Ǥä硢⤷ϻꤵʤä Novell 饤ȤưϵꤵƤޤ .PP .RE .B option \fBnwip.preferred-dss\fR \fIip-address\fR [\fB,\fR \fIip-address\fR... ]\fR\fB;\fR .RS 0.25i .PP ܥ֥ץˤϡ5 ĤޤǤ IP ɥ쥹ΥꥹȤꤷޤ 줾Υɥ쥹ϡNetWare ɥᥤ SAP/RIP (DSS) IP ɥ쥹Ǥ .RE .PP .B option \fBnwip.nearest-nwip-server\fR \fI\fIip-address\fR [\fB,\fR \fIip-address\fR...]\fR\fB;\fR .RS 0.25i .PP ܥ֥ץˤϡ5 ĤޤǤ IP ɥ쥹ΥꥹȤꤷޤ 줾Υɥ쥹ϡܤ NetWare IP (Nearest NetWare IP Server) IP ɥ쥹Ǥ .RE .PP .B option \fBnwip.autoretries\fR \fIuint8\fR\fB;\fR .RS 0.25i .PP ưˡNetWare/IP 饤ȤͿ줿 DSS Ф ̿ߤ٤ꤷޤ .RE .PP .B option \fBnwip.autoretry-secs\fR \fIuint8\fR\fB;\fR .RS 0.25i .PP ưˡNetWare/IP 饤ȤͿ줿 DSS Ф ̿Ωˡȥ饤δֲԤĤ٤ꤷޤ .RE .PP .B option \fBnwip.nwip-1-1\fR \fIuint8\fR\fB;\fR .RS 0.25i .PP true Ǥä硢NetWare/IP 饤Ȥ NetWare/IP С 1.1 򥵥ݡȤƤ٤Ǥ ϡ饤Ȥ NetWare/IP С 1.1 ΥФ ̿ΤɬפǤ .RE .PP .B option \fBnwip.primary-dss\fR \fIip-address\fR\fB;\fR .RS 0.25i .PP NetWare/IP ɥᥤΥץ饤ޥɥᥤ SAP/RIP ӥ (DSS) IP ɥ쥹ꤷޤ DSS ФˡNetWare/IP 桼ƥƥϡ ͤץ饤ޥ DSS ФȤƻѤޤ .RE .SH ץ .\" metal Internet Systems Consortium DHCP 饤ȤȥФϡ ץ뵡󶡤Ƥޤ 줾 DHCP ץϡ̾ȥɡ¤äƤޤ ̾ϡѼԤץ򻲾ȤΤ˻Ѥޤ ɤϡDHCP Фȥ饤Ȥץ򻲾ȤΤ ѤֹǤ ¤ϡץƤɤΤ褦ʤΤ򵭽ҤƤޤ .PP ץˤϡ¾ΥץǤϻȤƤʤ̾ ɬפޤ 㤨С"host-name" ȸ̾ϻѤǤޤ ȤΤ⡢Υޥ˥奢ڡ˽ФƤ褦ˡ DHCP ץȥ뤬 host-name ץƤ뤫Ǥ Υޥ˥奢ڡ˽ФƤƤʤץ̾ʤ ȤäƤ⹽ޤ󤬡ФƤ륪ץȽŤʤʤ褦ˡ ץ̾κǽȼʸĤ뤳Ȥϡ¿ʬͤǤ礦 㤨С DHCP ץˤ "local" ǻϤޤΤʤΤǡ "local-host-name" ȸ̾ϡ餫¿ǤǤ礦 .PP ̾򤷤顢ϥɤФͤФʤޤ DHCP ץ 128 256 ޤǤΥɤϡ ȥ륪ץѤȤͽ󤵤ƤΤǡ ΥɤʤɤǤ֤ȤǤޤ ºݤˤϡץȥ򾯡ޤ˲ᤷƤ٥ꡢ 128 礭ͤΥץ󥳡ɤѤƤޤ ˲򤹤ˡϤޤ󤬡 ºݤˤϤ礭ΤǤϤʤǤ礦 .PP ץι¤Ȥϡñ˥ץΥǡɽƤǤ ISC DHCP Фϡ֡͡ʸ󤽤 IP ɥ쥹Ȥä Ĥñʥǡ򥵥ݡȤƤꡢ ޤñǡΥǡ뤳ȤǤޤ .PP ץϡʲΤ褦ޤ: .PP .B option .I new-name .B code .I new-code .B = .I definition .B ; .PP .I new-name .I new-code ͤϡץѤˤʤΤǤ .I definition ϡץι¤Ǥ .PP ʲñʥץηݡȤƤޤ: .PP .B ֡ .PP .B option .I new-name .B code .I new-code .B = .B boolean .B ; .PP ֡뷿Υץϡon ޤ off (⤷ true false) ͤ ĥե饰Ǥ ֡뷿λϡʲΤ褦ˤʤޤ: .nf option use-zephyr code 180 = boolean; option use-zephyr on; .fi .B .PP .B option .I new-name .B code .I new-code .B = .I sign .B integer .I width .B ; .PP \fIsign\fR ȡϡ\fIunsigned\fR\fIsigned\fR Τ줫Ǥ width 8, 16, 32 Τ줫ǡ bit 򼨤ޤ 㤨Сʲ 2 Ԥϡsql-connection-max ץ ˡ򼨤ޤ: .nf option sql-connection-max code 192 = unsigned integer 16; option sql-connection-max 1536; .fi .B IP ɥ쥹 .PP .B option .I new-name .B code .I new-code .B = .B ip-address .B ; .PP IP ɥ쥹ι¤ĥץϡɥᥤ̾⤷ ɥåȶڤ 4 ɽޤ ʲϡIP ɥ쥹λǤ: .nf option sql-server-address code 193 = ip-address; option sql-server-address sql.example.com; .fi .PP .B ƥ .PP .B option .I new-name .B code .I new-code .B = .B text .B ; .PP ƥȷΥץϡASCII ƥʸ򥨥󥳡ɤޤ 㤨: .nf option sql-default-connection-name code 194 = text; option sql-default-connection-name "PRODZA"; .fi .PP .B ǡʸ .PP .B option .I new-name .B code .I new-code .B = .B string .B ; .PP ǡʸ󷿤ΥץϡܼŪˤñʤХȤνΤǤ ƥȷΤ褦˥Ȥ줿ƥȤǻꤵ뤫 ⤷ϥڤ 16 ʿΥꥹȤǻꤵޤ λǶڤ줿Ȥϡ0 FF δ֤ͤǤʤФʤޤ 㤨: .nf option sql-identification-token code 195 = string; option sql-identification-token 17:23:19:a6:42:ea:99:7c:22; .fi .PP .B ץ벽 .PP .B option .I new-name .B code .I new-code .B = .B encapsulate .I identifier .B ; .PP ץ벽Υץϡ\fIidentifier\fR ǻꤵ줿 ץ֤Ȥ򥫥ץ벽ޤ DHCP ץȥ¸ߤ륫ץ벽ץϡ vendor-encapsulated-options ץnetware-suboptions ץ relay-agent-information ץʤɤǤ .nf option space local; option local.demo code 1 = text; option local-encapsulation code 197 = encapsulate local; option local.demo "demo"; .fi .PP .B .PP ץϡƥȷȥǡʸ󷿰ʳξҤΤʤǡ ޤळȤǤޤ ƥȷȥǡʸ󷿤ϡǤϥݡȤƤޤ ϰʲ̤Ǥ: .nf option kerberos-servers code 200 = array of ip-address; option kerberos-servers 10.20.10.1, 10.20.11.1; .fi .B 쥳 .PP ץϡǡǹǡ¤ޤळȤǤޤ ϤФХ쥳ɷȸƤФޤ 㤨: .nf option contrived-001 code 201 = { boolean, integer 32, text }; option contrived-001 on 1772 "contrivance"; .fi ޤ쥳ɤΥץĤȤǤޤ 㤨: .nf option new-static-routes code 201 = array of { ip-address, ip-address, ip-address, integer 8 }; option static-routes 10.0.0.0 255.255.255.0 net-0-rtr.example.com 1, 10.0.1.0 255.255.255.0 net-1-rtr.example.com 1, 10.2.0.0 255.255.224.0 net-2-0-rtr.example.com 3; .fi .SH ٥ץ벽ץ .\" metal DHCP ץȥˤϡ\fB vendor-encapsulated-options\fR ץ Ƥޤ ٥ϡΥץˤäơ٥ͭΥץ ɸ DHCP ץ˴ޤФ뤳ȤǤޤ .B vendor-encapsulated-options ץν񼰤ϡ񼰤ꤵƤʤϢΥХ ⤷ϰϢΥץǤ ץΤ줾Υץϡ1 ХȤΥ٥ͭ ץ󥳡ɤθ 1 ХȤΥǡĹ ƤΥǡĹǻꤵ줿礭Υǡ³Τǹޤ (ǡĹˤϡǡĹȤ䥪ץ󥳡ɤϴޤޤޤ) .PP ܥץͤϡ2 ĤˡΤ줫ꤵޤ 1 ܤˡϡñ˥ǡľܻꤹΤǤ ǡλˤϡƥʸ󤫥Ƕڤ줿 16 ʿͤѤޤ 㤨: .PP .nf option vendor-encapsulated-options 2:4:AC:11:41:1: 3:12:73:75:6e:64:68:63:70:2d:73:65:72:76:65:72:31:37:2d:31: 4:12:2f:65:78:70:6f:72:74:2f:72:6f:6f:74:2f:69:38:36:70:63; .fi .PP ܥץꤹ 2 ܤˡϡDHCP Ф ٥ͭץХåեȤΤǤ 򤹤ˤϡʲ 4 ĤΤȤ򤹤ɬפޤ: ץ֤Υץ˥ץ ͤ꿶ꡢǸˤΥץ֤ .B vendor-encapsulated-options ץ˻Ѥ뤳Ȥꤷޤ .PP ٥ץ󤬳Ǽ륪ץ֤򿷵ˤϡ \fRoption space\fP ʸѤޤ: .PP .B option .B space .I name .B ; .PP ʸˤޤǽ񤫤Ƥ褦ˡ name ϡץǻѤ뤳ȤǤޤ 㤨: .nf option space SUNW; option SUNW.server-address code 2 = ip-address; option SUNW.server-name code 3 = text; option SUNW.root-path code 4 = text; .fi ١ץ֤ȥץν񼰤顢 Υץͤ륹פǤ Υץ򤤤ĻȤꤹ뤳ȤǤޤ 㤨С2 Ĥΰۤʤ륯饹Υ饤Ȥ򰷤Ȥޤ礦 ҤǼץ֤ȤäơʲΤ褦ˡ 饤ȤƤ vendor-class-identifier ץ˴Ťơ ۤʤ륪ץͤۤʤ륯饤ȤФ뤳ȤǤޤ .PP .nf class "vendor-classes" { match option vendor-class-identifier; } option SUNW.server-address 172.17.65.1; option SUNW.server-name "sundhcp-server17-1"; subclass "vendor-classes" "SUNW.Ultra-5_10" { vendor-option-space SUNW; option SUNW.root-path "/export/root/sparc"; } subclass "vendor-classes" "SUNW.i86pc" { vendor-option-space SUNW; option SUNW.root-path "/export/root/i86pc"; } .fi .PP Ǹ褦ˡ̾Υץ롼ŬѤ뤳Ȥǡ Хͤ򥰥Х륹Ǥ Υ饹˸ͭͤ륹פǤޤ \fBvendor-option-space\fR ȤȤǡ .B vendor-encapsulated-options ץΤˡSUNW ץΥץȤ褦 DHCP Ф˻ؼ뤳ȤǤޤ .SH Ϣ dhclient.conf(5), dhcp-eval(5), dhclient(8), RFC2132, RFC2131 .SH Internet Systems Consortium DHCP Distribution ϡVixie Labs ȤηΤȤǡTed Lemon Ҥޤ ܥץȤλϡInternet Systems Consortium 󶡤ޤ Internet Systems Consortium ˴ؤϡ .B https://www.isc.org ˤޤ dhcp-4.2.4/doc/examples/dhclient-dhcpv6.conf000644 000765 000024 00000000576 11066376036 020623 0ustar00sarstaff000000 000000 # Client configuration file example for DHCPv6 # The client side command to enable rapid-commit (2 packet exchange) ##send dhcp6.rapid-commit; # name-servers and domain-search are requested by default. # here is the way to request sip-servers-addresses too also request dhcp6.sip-servers-addresses; # Likely to be useful: the script path script "/usr/local/etc/dhclient-script"; dhcp-4.2.4/doc/examples/dhcpd-dhcpv6.conf000644 000765 000024 00000006355 11573741106 020111 0ustar00sarstaff000000 000000 # Server configuration file example for DHCPv6 # From the file used for TAHI tests. # IPv6 address valid lifetime # (at the end the address is no longer usable by the client) # (set to 30 days, the usual IPv6 default) default-lease-time 2592000; # IPv6 address preferred lifetime # (at the end the address is deprecated, i.e., the client should use # other addresses for new connections) # (set to 7 days, the usual IPv6 default) preferred-lifetime 604800; # T1, the delay before Renew # (default is 1/2 preferred lifetime) # (set to 1 hour) option dhcp-renewal-time 3600; # T2, the delay before Rebind (if Renews failed) # (default is 3/4 preferred lifetime) # (set to 2 hours) option dhcp-rebinding-time 7200; # Enable RFC 5007 support (same than for DHCPv4) allow leasequery; # Global definitions for name server address(es) and domain search list option dhcp6.name-servers 3ffe:501:ffff:100:200:ff:fe00:3f3e; option dhcp6.domain-search "test.example.com","example.com"; # Set preference to 255 (maximum) in order to avoid waiting for # additional servers when there is only one ##option dhcp6.preference 255; # Server side command to enable rapid-commit (2 packet exchange) ##option dhcp6.rapid-commit; # The delay before information-request refresh # (minimum is 10 minutes, maximum one day, default is to not refresh) # (set to 6 hours) option dhcp6.info-refresh-time 21600; # The path of the lease file dhcpv6-lease-file-name "/usr/local/var/db/dhcpd6.leases"; # Static definition (must be global) host myclient { # The entry is looked up by this host-identifier option dhcp6.client-id 00:01:00:01:00:04:93:e0:00:00:00:00:a2:a2; # A fixed address fixed-address6 3ffe:501:ffff:100::1234; # A fixed prefix fixed-prefix6 3ffe:501:ffff:101::/64; # Override of the global definitions, # works only when a resource (address or prefix) is assigned option dhcp6.name-servers 3ffe:501:ffff:100:200:ff:fe00:4f4e; # For debug (to see when the entry statements are executed) # (log "sol" when a matching Solicitation is received) ##if packet(0,1) = 1 { log(debug,"sol"); } } host otherclient { # This host entry is hopefully matched if the client supplies a DUID-LL # or DUID-LLT containing this MAC address. hardware ethernet 01:00:80:a2:55:67; fixed-address6 3ffe:501:ffff:100::4321; } # The subnet where the server is attached # (i.e., the server has an address in this subnet) subnet6 3ffe:501:ffff:100::/64 { # Two addresses available to clients # (the third client should get NoAddrsAvail) range6 3ffe:501:ffff:100::10 3ffe:501:ffff:100::11; # Use the whole /64 prefix for temporary addresses # (i.e., direct application of RFC 4941) range6 3ffe:501:ffff:100:: temporary; # Some /64 prefixes available for Prefix Delegation (RFC 3633) prefix6 3ffe:501:ffff:100:: 3ffe:501:ffff:111:: /64; } # A second subnet behind a relay agent subnet6 3ffe:501:ffff:101::/64 { range6 3ffe:501:ffff:101::10 3ffe:501:ffff:101::11; # Override of the global definitions, # works only when a resource (address or prefix) is assigned option dhcp6.name-servers 3ffe:501:ffff:101:200:ff:fe00:3f3e; } # A third subnet behind a relay agent chain subnet6 3ffe:501:ffff:102::/64 { range6 3ffe:501:ffff:102::10 3ffe:501:ffff:102::11; } dhcp-4.2.4/dhcpctl/callback.c000644 000765 000024 00000012337 11301372615 015715 0ustar00sarstaff000000 000000 /* callback.c The dhcpctl callback object. */ /* * Copyright (c) 2004,2007,2009 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1999-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ * * This software has been written for Internet Systems Consortium * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. * To learn more about Internet Systems Consortium, see * ``https://www.isc.org/''. To learn more about Vixie Enterprises, * see ``http://www.vix.com''. To learn more about Nominum, Inc., see * ``http://www.nominum.com''. */ #include "dhcpd.h" #include #include "dhcpctl.h" /* dhcpctl_set_callback synchronous, with asynchronous aftereffect handle is some object upon which some kind of process has been started - e.g., an open, an update or a refresh. data is an anonymous pointer containing some information that the callback will use to figure out what event completed. return value of 0 means callback was successfully set, a nonzero status code is returned otherwise. Upon completion of whatever task is in process, the callback will be passed the handle to the object, a status code indicating what happened, and the anonymous pointer passed to */ dhcpctl_status dhcpctl_set_callback (dhcpctl_handle h, void *data, void (*func) (dhcpctl_handle, dhcpctl_status, void *)) { dhcpctl_callback_object_t *callback; omapi_object_t *inner; callback = dmalloc (sizeof *callback, MDL); if (!callback) return ISC_R_NOMEMORY; /* Tie the callback object to the innermost object in the chain. */ for (inner = h; inner -> inner; inner = inner -> inner) ; omapi_object_reference (&inner -> inner, (omapi_object_t *)callback, MDL); omapi_object_reference ((omapi_object_t **)&callback -> outer, inner, MDL); /* Save the actual handle pointer we were passed for the callback. */ omapi_object_reference (&callback -> object, h, MDL); callback -> data = data; callback -> callback = func; return ISC_R_SUCCESS; } /* Callback methods (not meant to be called directly) */ isc_result_t dhcpctl_callback_set_value (omapi_object_t *h, omapi_object_t *id, omapi_data_string_t *name, omapi_typed_data_t *value) { if (h -> type != dhcpctl_callback_type) return DHCP_R_INVALIDARG; if (h -> inner && h -> inner -> type -> set_value) return (*(h -> inner -> type -> set_value)) (h -> inner, id, name, value); return ISC_R_NOTFOUND; } isc_result_t dhcpctl_callback_get_value (omapi_object_t *h, omapi_object_t *id, omapi_data_string_t *name, omapi_value_t **value) { if (h -> type != dhcpctl_callback_type) return DHCP_R_INVALIDARG; if (h -> inner && h -> inner -> type -> get_value) return (*(h -> inner -> type -> get_value)) (h -> inner, id, name, value); return ISC_R_NOTFOUND; } isc_result_t dhcpctl_callback_signal_handler (omapi_object_t *o, const char *name, va_list ap) { dhcpctl_callback_object_t *p; isc_result_t waitstatus; if (o -> type != dhcpctl_callback_type) return DHCP_R_INVALIDARG; p = (dhcpctl_callback_object_t *)o; /* Not a signal we recognize? */ if (strcmp (name, "ready")) { if (p -> inner && p -> inner -> type -> signal_handler) return (*(p -> inner -> type -> signal_handler)) (p -> inner, name, ap); return ISC_R_NOTFOUND; } if (p -> object -> type == dhcpctl_remote_type) { waitstatus = (((dhcpctl_remote_object_t *) (p -> object)) -> waitstatus); } else waitstatus = ISC_R_SUCCESS; /* Do the callback. */ if (p -> callback) (*(p -> callback)) (p -> object, waitstatus, p -> data); return ISC_R_SUCCESS; } isc_result_t dhcpctl_callback_destroy (omapi_object_t *h, const char *file, int line) { dhcpctl_callback_object_t *p; if (h -> type != dhcpctl_callback_type) return DHCP_R_INVALIDARG; p = (dhcpctl_callback_object_t *)h; if (p -> handle) omapi_object_dereference ((omapi_object_t **)&p -> handle, file, line); return ISC_R_SUCCESS; } /* Write all the published values associated with the object through the specified connection. */ isc_result_t dhcpctl_callback_stuff_values (omapi_object_t *c, omapi_object_t *id, omapi_object_t *p) { if (p -> type != dhcpctl_callback_type) return DHCP_R_INVALIDARG; if (p -> inner && p -> inner -> type -> stuff_values) return (*(p -> inner -> type -> stuff_values)) (c, id, p -> inner); return ISC_R_SUCCESS; } dhcp-4.2.4/dhcpctl/cltest.c000644 000765 000024 00000011401 11301372615 015446 0ustar00sarstaff000000 000000 /* cltest.c Example program that uses the dhcpctl library. */ /* * Copyright (c) 2004,2007,2009 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 2000-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ * * This software was contributed to Internet Systems Consortium * by Brian Murrell. */ #include #include #include #include #include #include #include "omapip/result.h" #include "dhcpctl.h" int main (int, char **); enum modes { up, down, undefined }; static void usage (char *s) { fprintf (stderr, "Usage: %s [-n ] [-p ] [-a ]" "(-u | -d) \n", s); exit (1); } int main (argc, argv) int argc; char **argv; { isc_result_t status, waitstatus; dhcpctl_handle authenticator; dhcpctl_handle connection; dhcpctl_handle interface_handle; dhcpctl_data_string result; int i; int mode = undefined; const char *interface = 0; const char *action; for (i = 1; i < argc; i++) { if (!strcmp (argv[i], "-u")) { mode = up; } else if (!strcmp (argv [i], "-d")) { mode = down; } else if (argv[i][0] == '-') { usage(argv[0]); } else { interface = argv[i]; } } if (!interface) usage(argv[0]); if (mode == undefined) usage(argv[0]); status = dhcpctl_initialize (); if (status != ISC_R_SUCCESS) { fprintf (stderr, "dhcpctl_initialize: %s\n", isc_result_totext (status)); exit (1); } authenticator = dhcpctl_null_handle; connection = dhcpctl_null_handle; status = dhcpctl_connect (&connection, "127.0.0.1", 7911, authenticator); if (status != ISC_R_SUCCESS) { fprintf (stderr, "dhcpctl_connect: %s\n", isc_result_totext (status)); exit (1); } interface_handle = dhcpctl_null_handle; status = dhcpctl_new_object (&interface_handle, connection, "interface"); if (status != ISC_R_SUCCESS) { fprintf (stderr, "dhcpctl_new_object: %s\n", isc_result_totext (status)); exit (1); } status = dhcpctl_set_string_value (interface_handle, interface, "name"); if (status != ISC_R_SUCCESS) { fprintf (stderr, "dhcpctl_set_value: %s\n", isc_result_totext (status)); exit (1); } if (mode == up) { /* "up" the interface */ printf ("upping interface %s\n", interface); action = "create"; status = dhcpctl_open_object (interface_handle, connection, DHCPCTL_CREATE | DHCPCTL_EXCL); if (status != ISC_R_SUCCESS) { fprintf (stderr, "dhcpctl_open_object: %s\n", isc_result_totext (status)); exit (1); } } else { /* down the interface */ printf ("downing interface %s\n", interface); action = "remove"; status = dhcpctl_open_object (interface_handle, connection, 0); if (status != ISC_R_SUCCESS) { fprintf (stderr, "dhcpctl_open_object: %s\n", isc_result_totext (status)); exit (1); } status = dhcpctl_wait_for_completion (interface_handle, &waitstatus); if (status != ISC_R_SUCCESS) { fprintf (stderr, "dhcpctl_wait_for_completion: %s\n", isc_result_totext (status)); exit (1); } if (waitstatus != ISC_R_SUCCESS) { fprintf (stderr, "dhcpctl_wait_for_completion: %s\n", isc_result_totext (waitstatus)); exit (1); } status = dhcpctl_object_remove (connection, interface_handle); if (status != ISC_R_SUCCESS) { fprintf (stderr, "dhcpctl_open_object: %s\n", isc_result_totext (status)); exit (1); } } status = dhcpctl_wait_for_completion (interface_handle, &waitstatus); if (status != ISC_R_SUCCESS) { fprintf (stderr, "dhcpctl_wait_for_completion: %s\n", isc_result_totext (status)); exit (1); } if (waitstatus != ISC_R_SUCCESS) { fprintf (stderr, "interface object %s: %s\n", action, isc_result_totext (waitstatus)); exit (1); } memset (&result, 0, sizeof result); status = dhcpctl_get_value (&result, interface_handle, "state"); if (status != ISC_R_SUCCESS) { fprintf (stderr, "dhcpctl_get_value: %s\n", isc_result_totext (status)); exit (1); } exit (0); } dhcp-4.2.4/dhcpctl/dhcpctl.3000644 000765 000024 00000026450 11555404240 015524 0ustar00sarstaff000000 000000 .\" -*- nroff -*- .\" .\" Project: DHCP .\" File: dhcpctl.3 .\" RCSId: $Id: dhcpctl.3,v 1.7.24.2 2011-04-25 23:49:52 sar Exp $ .\" .\" Copyright (c) 2011 by Internet Systems Consortium, Inc. ("ISC") .\" Copyright (c) 2004,2009 by Internet Systems Consortium, Inc. ("ISC") .\" Copyright (c) 2000-2003 by Internet Software Consortium .\" Copyright (c) 2000 Nominum, Inc. .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above .\" copyright notice and this permission notice appear in all copies. .\" .\" THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES .\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR .\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES .\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT .\" OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" .\" Internet Systems Consortium, Inc. .\" 950 Charter Street .\" Redwood City, CA 94063 .\" .\" https://www.isc.org/ .\" .\" Description: dhcpctl man page. .\" .\" .Dd Nov 15, 2000 .Dt DHCPCTL 3 .Os DHCP 3 .ds vT DHCP Programmer's Manual .\" .\" .\" .Sh NAME .Nm dhcpctl_initialize .Nd dhcpctl library initialization. .\" .\" .\" .Sh SYNOPSIS .Fd #include .Ft dhcpctl_status .Fo dhcpctl_initialize .Fa void .Fc .\" .Ft dhcpctl_status .Fo dhcpctl_connect .Fa "dhcpctl_handle *cxn" .Fa "const char *host" .Fa "int port" .Fa "dhcpctl_handle auth" .Fc .\" .\" .\" .Ft dhcpctl_status .Fo dhcpctl_wait_for_completion .Fa "dhcpctl_handle object" .Fa "dhcpctl_status *status" .Fc .\" .\" .\" .Ft dhcpctl_status .Fo dhcpctl_get_value .Fa "dhcpctl_data_string *value" .Fa "dhcpctl_handle object" .Fa "const char *name" .Fc .\" .\" .\" .Ft dhcpctl_status .Fo dhcpctl_get_boolean .Fa "int *value" .Fa "dhcpctl_handle object" .Fa "const char *name" .Fc .\" .\" .\" .Ft dhcpctl_status .Fo dhcpctl_set_value .Fa "dhcpctl_handle object" .Fa "dhcpctl_data_string value" .Fa "const char *name" .Fc .\" .\" .\" .Ft dhcpctl_status .Fo dhcpctl_set_string_value .Fa "dhcpctl_handle object" .Fa "const char *value" .Fa "const char *name" .Fc .\" .\" .\" .Ft dhcpctl_status .Fo dhcpctl_set_boolean_value .Fa "dhcpctl_handle object" .Fa "int value" .Fa "const char *name" .Fc .\" .\" .\" .Ft dhcpctl_status .Fo dhcpctl_set_int_value .Fa "dhcpctl_handle object" .Fa "int value" .Fa "const char *name" .Fc .\" .\" .\" .Ft dhcpctl_status .Fo dhcpctl_object_update .Fa "dhcpctl_handle connection" .Fa "dhcpctl_handle object" .Fc .\" .\" .\" .Ft dhcpctl_status .Fo dhcpctl_object_refresh .Fa "dhcpctl_handle connection" .Fa "dhcpctl_handle object" .Fc .\" .\" .\" .Ft dhcpctl_status .Fo dhcpctl_object_remove .Fa "dhcpctl_handle connection" .Fa "dhcpctl_handle object" .Fc .\" .\" .\" .Ft dhcpctl_status .Fo dhcpctl_set_callback .Fa "dhcpctl_handle object" .Fa "void *data" .Fa "void (*function) (dhcpctl_handle, dhcpctl_status, void *)" .Fc .\" .\" .\" .Ft dhcpctl_status .Fo dhcpctl_new_authenticator .Fa "dhcpctl_handle *object" .Fa "const char *name" .Fa "const char *algorithm" .Fa "const char *secret" .Fa "unsigned secret_len" .Fc .\" .\" .\" .Ft dhcpctl_status .Fo dhcpctl_new_object .Fa "dhcpctl_handle *object" .Fa "dhcpctl_handle connection" .Fa "const char *object_type" .Fc .\" .\" .\" .Ft dhcpctl_status .Fo dhcpctl_open_object .Fa "dhcpctl_handle object" .Fa "dhcpctl_handle connection" .Fa "int flags" .Fc .\" .\" .\" .Ft isc_result_t .Fo omapi_data_string_new .Fa dhcpctl_data_string *data .Fa unsigned int length .Fa const char *filename, .Fa int lineno .Fc .\" .\" .\" .Ft isc_result_t .Fo dhcpctl_data_string_dereference .Fa "dhcpctl_data_string *" .Fa "const char *" .Fa "int" .Fc .Sh DESCRIPTION The dhcpctl set of functions provide an API that can be used to communicate with and manipulate a running ISC DHCP server. All functions return a value of .Dv isc_result_t . The return values reflects the result of operations to local data structures. If an operation fails on the server for any reason, then the error result will be returned through the second parameter of the .Fn dhcpctl_wait_for_completion call. .\" .\" .\" .Pp .Fn dhcpctl_initialize sets up the data structures the library needs to do its work. This function must be called once before any other. .Pp .Fn dhcpctl_connect opens a connection to the DHCP server at the given host and port. If an authenticator has been created for the connection, then it is given as the 4th argument. On a successful return the address pointed at by the first argument will have a new connection object assigned to it. .Pp For example: .Bd -literal -offset indent s = dhcpctl_connect(&cxn, "127.0.0.1", 7911, NULL); .Ed .Pp connects to the DHCP server on the localhost via port 7911 (the standard OMAPI port). No authentication is used for the connection. .\" .\" .\" .Pp .Fn dhcpctl_wait_for_completion flushes a pending message to the server and waits for the response. The result of the request as processed on the server is returned via the second parameter. .Bd -literal -offset indent s = dhcpctl_wait_for_completion(cxn, &wv); if (s != ISC_R_SUCCESS) local_failure(s); else if (wv != ISC_R_SUCCESS) server_failure(wc); .Ed .Pp The call to .Fn dhcpctl_wait_for_completion won't return until the remote message processing completes or the connection to the server is lost. .\" .\" .\" .Pp .Fn dhcpctl_get_value extracts a value of an attribute from the handle. The value can be of any length and is treated as a sequence of bytes. The handle must have been created first with .Fn dhcpctl_new_object and opened with .Fn dhcpctl_open_object . The value is returned via the parameter named .Dq value . The last parameter is the name of attribute to retrieve. .Bd -literal -offset indent dhcpctl_data_string value = NULL; dhcpctl_handle lease; time_t thetime; s = dhcpctl_get_value (&value, lease, "ends"); assert(s == ISC_R_SUCCESS && value->len == sizeof(thetime)); memcpy(&thetime, value->value, value->len); .Ed .\" .\" .\" .Pp .Fn dhcpctl_get_boolean extracts a boolean valued attribute from the object handle. .\" .\" .\" .Pp The .Fn dhcpctl_set_value , .Fn dhcpctl_set_string_value , .Fn dhcpctl_set_boolean_value , and .Fn dhcpctl_set_int_value functions all set a value on the object handle. .\" .\" .\" .Pp .Fn dhcpctl_object_update function queues a request for all the changes made to the object handle be be sent to the remote for processing. The changes made to the atributes on the handle will be applied to remote object if permitted. .\" .\" .\" .Pp .Fn dhcpctl_object_refresh queues up a request for a fresh copy of all the attribute values to be sent from the remote to refresh the values in the local object handle. .\" .\" .\" .Pp .Fn dhcpctl_object_remove queues a request for the removal on the server of the object referenced by the handle. .\" .\" .\" .Pp The .Fn dhcpctl_set_callback function sets up a user-defined function to be called when an event completes on the given object handle. This is needed for asynchronous handling of events, versus the synchronous handling given by .Fn dhcpctl_wait_for_completion . When the function is called the first parameter is the object the event arrived for, the second is the status of the message that was processed, the third is the same value as the second parameter given to .Fn dhcpctl_set_callback . .\" .\" .\" .Pp The .Fn dhcpctl_new_authenticator creates a new authenticator object to be used for signing the messages that cross over the network. The .Dq name , .Dq algorithm , and .Dq secret values must all match what the server uses and are defined in its configuration file. The created object is returned through the first parameter and must be used as the 4th parameter to .Fn dhcpctl_connect . Note that the 'secret' value must not be base64 encoded, which is different from how the value appears in the dhcpd.conf file. .\" .\" .\" .Pp .Fn dhcpctl_new_object creates a local handle for an object on the the server. The .Dq object_type parameter is the ascii name of the type of object being accessed. e.g. .Qq lease . This function only sets up local data structures, it does not queue any messages to be sent to the remote side, .Fn dhcpctl_open_object does that. .\" .\" .\" .Pp .Fn dhcpctl_open_object builds and queues the request to the remote side. This function is used with handle created via .Fn dhcpctl_new_object . The flags argument is a bit mask with the following values available for setting: .Bl -tag -offset indent -width 20 .It DHCPCTL_CREATE if the object does not exist then the remote will create it .It DHCPCTL_UPDATE update the object on the remote side using the attributes already set in the handle. .It DHCPCTL_EXCL return and error if the object exists and DHCPCTL_CREATE was also specified .El .\" .\" .\" .Pp The .Fn omapi_data_string_new function allocates a new .Ft dhcpctl_data_string object. The data string will be large enough to hold .Dq length bytes of data. The .Dq file and .Dq lineno arguments are the source file location the call is made from, typically by using the .Dv __FILE__ and .Dv __LINE__ macros or the .Dv MDL macro defined in . .\" .\" .\" .Pp .Fn dhcpctl_data_string_dereference deallocates a data string created by .Fn omapi_data_string_new . The memory for the object won't be freed until the last reference is released. .Sh EXAMPLES .Pp The following program will connect to the DHCP server running on the local host and will get the details of the existing lease for IP address 10.0.0.101. It will then print out the time the lease is due to expire. Note that most error checking has been ommitted for brevity. .Bd -literal -offset indent #include #include #include #include #include #include #include #include #include "omapip/result.h" #include "dhcpctl.h" int main (int argc, char **argv) { dhcpctl_data_string ipaddrstring = NULL; dhcpctl_data_string value = NULL; dhcpctl_handle connection = NULL; dhcpctl_handle lease = NULL; isc_result_t waitstatus; struct in_addr convaddr; time_t thetime; dhcpctl_initialize (); dhcpctl_connect (&connection, "127.0.0.1", 7911, 0); dhcpctl_new_object (&lease, connection, "lease"); memset (&ipaddrstring, 0, sizeof ipaddrstring); inet_pton(AF_INET, "10.0.0.101", &convaddr); omapi_data_string_new (&ipaddrstring, 4, MDL); memcpy(ipaddrstring->value, &convaddr.s_addr, 4); dhcpctl_set_value (lease, ipaddrstring, "ip-address"); dhcpctl_open_object (lease, connection, 0); dhcpctl_wait_for_completion (lease, &waitstatus); if (waitstatus != ISC_R_SUCCESS) { /* server not authoritative */ exit (0); } dhcpctl_data_string_dereference(&ipaddrstring, MDL); dhcpctl_get_value (&value, lease, "ends"); memcpy(&thetime, value->value, value->len); dhcpctl_data_string_dereference(&value, MDL); fprintf (stdout, "ending time is %s", ctime(&thetime)); } .Ed .Sh SEE ALSO omapi(3), omshell(1), dhcpd(8), dhclient(8), dhcpd.conf(5), dhclient.conf(5). .Sh AUTHOR .Em dhcpctl was written by Ted Lemon of Nominum, Inc. This preliminary documentation was written by James Brister of Nominum, Inc. dhcp-4.2.4/dhcpctl/dhcpctl.c000644 000765 000024 00000042476 11301372615 015611 0ustar00sarstaff000000 000000 /* dhcpctl.c Subroutines providing general support for objects. */ /* * Copyright (c) 2004,2007,2009 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1999-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ * * This software has been written for Internet Systems Consortium * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. * To learn more about Internet Systems Consortium, see * ``https://www.isc.org/''. To learn more about Vixie Enterprises, * see ``http://www.vix.com''. To learn more about Nominum, Inc., see * ``http://www.nominum.com''. */ #include "dhcpd.h" #include #include "dhcpctl.h" omapi_object_type_t *dhcpctl_callback_type; omapi_object_type_t *dhcpctl_remote_type; /* dhcpctl_initialize () Must be called before any other dhcpctl function. */ dhcpctl_status dhcpctl_initialize () { isc_result_t status; /* Set up the isc and dns library managers */ status = dhcp_context_create(); if (status != ISC_R_SUCCESS) return status; status = omapi_init(); if (status != ISC_R_SUCCESS) return status; status = omapi_object_type_register (&dhcpctl_callback_type, "dhcpctl-callback", dhcpctl_callback_set_value, dhcpctl_callback_get_value, dhcpctl_callback_destroy, dhcpctl_callback_signal_handler, dhcpctl_callback_stuff_values, 0, 0, 0, 0, 0, 0, sizeof (dhcpctl_callback_object_t), 0, RC_MISC); if (status != ISC_R_SUCCESS) return status; status = omapi_object_type_register (&dhcpctl_remote_type, "dhcpctl-remote", dhcpctl_remote_set_value, dhcpctl_remote_get_value, dhcpctl_remote_destroy, dhcpctl_remote_signal_handler, dhcpctl_remote_stuff_values, 0, 0, 0, 0, 0, 0, sizeof (dhcpctl_remote_object_t), 0, RC_MISC); if (status != ISC_R_SUCCESS) return status; return ISC_R_SUCCESS; } /* dhcpctl_connect synchronous returns nonzero status code if it didn't connect, zero otherwise stores connection handle through connection, which can be used for subsequent access to the specified server. server_name is the name of the server, and port is the TCP port on which it is listening. authinfo is the handle to an object containing authentication information. */ dhcpctl_status dhcpctl_connect (dhcpctl_handle *connection, const char *server_name, int port, dhcpctl_handle authinfo) { isc_result_t status; status = omapi_generic_new (connection, MDL); if (status != ISC_R_SUCCESS) { return status; } status = omapi_protocol_connect (*connection, server_name, (unsigned)port, authinfo); if (status == ISC_R_SUCCESS) return status; if (status != DHCP_R_INCOMPLETE) { omapi_object_dereference (connection, MDL); return status; } status = omapi_wait_for_completion (*connection, 0); if (status != ISC_R_SUCCESS) { omapi_object_dereference (connection, MDL); return status; } return status; } /* dhcpctl_wait_for_completion synchronous returns zero if the callback completes, a nonzero status if there was some problem relating to the wait operation. The status of the queued request will be stored through s, and will also be either zero for success or nonzero for some kind of failure. Never returns until completion or until the connection to the server is lost. This performs the same function as dhcpctl_set_callback and the subsequent callback, for programs that want to do inline execution instead of using callbacks. */ dhcpctl_status dhcpctl_wait_for_completion (dhcpctl_handle h, dhcpctl_status *s) { isc_result_t status; status = omapi_wait_for_completion (h, 0); if (status != ISC_R_SUCCESS) return status; if (h -> type == dhcpctl_remote_type) *s = ((dhcpctl_remote_object_t *)h) -> waitstatus; return ISC_R_SUCCESS; } /* dhcpctl_get_value synchronous returns zero if the call succeeded, a nonzero status code if it didn't. result is the address of an empty data string (initialized with bzero or cleared with data_string_forget). On successful completion, the addressed data string will contain the value that was fetched. dhcpctl_handle refers to some dhcpctl item value_name refers to some value related to that item - e.g., for a handle associated with a completed host lookup, value could be one of "hardware-address", "dhcp-client-identifier", "known" or "client-hostname". */ dhcpctl_status dhcpctl_get_value (dhcpctl_data_string *result, dhcpctl_handle h, const char *value_name) { isc_result_t status; omapi_value_t *tv = (omapi_value_t *)0; unsigned len; int ip; status = omapi_get_value_str (h, (omapi_object_t *)0, value_name, &tv); if (status != ISC_R_SUCCESS) return status; switch (tv -> value -> type) { case omapi_datatype_int: len = sizeof (int); break; case omapi_datatype_string: case omapi_datatype_data: len = tv -> value -> u.buffer.len; break; case omapi_datatype_object: len = sizeof (omapi_handle_t); break; default: omapi_typed_data_dereference (&tv -> value, MDL); return ISC_R_UNEXPECTED; } status = omapi_data_string_new (result, len, MDL); if (status != ISC_R_SUCCESS) { omapi_typed_data_dereference (&tv -> value, MDL); return status; } switch (tv -> value -> type) { case omapi_datatype_int: ip = htonl (tv -> value -> u.integer); memcpy ((*result) -> value, &ip, sizeof ip); break; case omapi_datatype_string: case omapi_datatype_data: memcpy ((*result) -> value, tv -> value -> u.buffer.value, tv -> value -> u.buffer.len); break; case omapi_datatype_object: ip = htonl (tv -> value -> u.object -> handle); memcpy ((*result) -> value, &ip, sizeof ip); break; } omapi_value_dereference (&tv, MDL); return ISC_R_SUCCESS; } /* dhcpctl_get_boolean like dhcpctl_get_value, but more convenient for boolean values, since no data_string needs to be dealt with. */ dhcpctl_status dhcpctl_get_boolean (int *result, dhcpctl_handle h, const char *value_name) { isc_result_t status; dhcpctl_data_string data = (dhcpctl_data_string)0; int rv; status = dhcpctl_get_value (&data, h, value_name); if (status != ISC_R_SUCCESS) return status; if (data -> len != sizeof rv) { omapi_data_string_dereference (&data, MDL); return ISC_R_UNEXPECTED; } memcpy (&rv, data -> value, sizeof rv); *result = ntohl (rv); return ISC_R_SUCCESS; } /* dhcpctl_set_value Sets a value on an object referred to by a dhcpctl_handle. The opposite of dhcpctl_get_value. Does not update the server - just sets the value on the handle. */ dhcpctl_status dhcpctl_set_value (dhcpctl_handle h, dhcpctl_data_string value, const char *value_name) { isc_result_t status; omapi_typed_data_t *tv = (omapi_typed_data_t *)0; omapi_data_string_t *name = (omapi_data_string_t *)0; status = omapi_data_string_new (&name, strlen (value_name), MDL); if (status != ISC_R_SUCCESS) return status; memcpy (name -> value, value_name, strlen (value_name)); status = omapi_typed_data_new (MDL, &tv, omapi_datatype_data, value -> len); if (status != ISC_R_SUCCESS) { omapi_data_string_dereference (&name, MDL); return status; } memcpy (tv -> u.buffer.value, value -> value, value -> len); status = omapi_set_value (h, (omapi_object_t *)0, name, tv); omapi_data_string_dereference (&name, MDL); omapi_typed_data_dereference (&tv, MDL); return status; } /* dhcpctl_set_string_value Sets a NUL-terminated ASCII value on an object referred to by a dhcpctl_handle. like dhcpctl_set_value, but saves the trouble of creating a data_string for a NUL-terminated string. Does not update the server - just sets the value on the handle. */ dhcpctl_status dhcpctl_set_string_value (dhcpctl_handle h, const char *value, const char *value_name) { isc_result_t status; omapi_typed_data_t *tv = (omapi_typed_data_t *)0; omapi_data_string_t *name = (omapi_data_string_t *)0; status = omapi_data_string_new (&name, strlen (value_name), MDL); if (status != ISC_R_SUCCESS) return status; memcpy (name -> value, value_name, strlen (value_name)); status = omapi_typed_data_new (MDL, &tv, omapi_datatype_string, value); if (status != ISC_R_SUCCESS) { omapi_data_string_dereference (&name, MDL); return status; } status = omapi_set_value (h, (omapi_object_t *)0, name, tv); omapi_data_string_dereference (&name, MDL); omapi_typed_data_dereference (&tv, MDL); return status; } /* dhcpctl_set_buffer_value Sets a value on an object referred to by a dhcpctl_handle. like dhcpctl_set_value, but saves the trouble of creating a data_string for string for which we have a buffer and length. Does not update the server - just sets the value on the handle. */ dhcpctl_status dhcpctl_set_data_value (dhcpctl_handle h, const char *value, unsigned len, const char *value_name) { isc_result_t status; omapi_typed_data_t *tv = (omapi_typed_data_t *)0; omapi_data_string_t *name = (omapi_data_string_t *)0; unsigned ll; ll = strlen (value_name); status = omapi_data_string_new (&name, ll, MDL); if (status != ISC_R_SUCCESS) return status; memcpy (name -> value, value_name, ll); status = omapi_typed_data_new (MDL, &tv, omapi_datatype_data, len, value); if (status != ISC_R_SUCCESS) { omapi_data_string_dereference (&name, MDL); return status; } memcpy (tv -> u.buffer.value, value, len); status = omapi_set_value (h, (omapi_object_t *)0, name, tv); omapi_data_string_dereference (&name, MDL); omapi_typed_data_dereference (&tv, MDL); return status; } /* dhcpctl_set_null_value Sets a null value on an object referred to by a dhcpctl_handle. */ dhcpctl_status dhcpctl_set_null_value (dhcpctl_handle h, const char *value_name) { isc_result_t status; omapi_data_string_t *name = (omapi_data_string_t *)0; unsigned ll; ll = strlen (value_name); status = omapi_data_string_new (&name, ll, MDL); if (status != ISC_R_SUCCESS) return status; memcpy (name -> value, value_name, ll); status = omapi_set_value (h, (omapi_object_t *)0, name, (omapi_typed_data_t *)0); omapi_data_string_dereference (&name, MDL); return status; } /* dhcpctl_set_boolean_value Sets a boolean value on an object - like dhcpctl_set_value, only more convenient for booleans. */ dhcpctl_status dhcpctl_set_boolean_value (dhcpctl_handle h, int value, const char *value_name) { isc_result_t status; omapi_typed_data_t *tv = (omapi_typed_data_t *)0; omapi_data_string_t *name = (omapi_data_string_t *)0; status = omapi_data_string_new (&name, strlen (value_name), MDL); if (status != ISC_R_SUCCESS) return status; memcpy (name -> value, value_name, strlen (value_name)); status = omapi_typed_data_new (MDL, &tv, omapi_datatype_int, value); if (status != ISC_R_SUCCESS) { omapi_data_string_dereference (&name, MDL); return status; } status = omapi_set_value (h, (omapi_object_t *)0, name, tv); omapi_data_string_dereference (&name, MDL); omapi_typed_data_dereference (&tv, MDL); return status; } /* dhcpctl_set_int_value Sets a boolean value on an object - like dhcpctl_set_value, only more convenient for booleans. */ dhcpctl_status dhcpctl_set_int_value (dhcpctl_handle h, int value, const char *value_name) { isc_result_t status; omapi_typed_data_t *tv = (omapi_typed_data_t *)0; omapi_data_string_t *name = (omapi_data_string_t *)0; status = omapi_data_string_new (&name, strlen (value_name), MDL); if (status != ISC_R_SUCCESS) return status; memcpy (name -> value, value_name, strlen (value_name)); status = omapi_typed_data_new (MDL, &tv, omapi_datatype_int, value); if (status != ISC_R_SUCCESS) { omapi_data_string_dereference (&name, MDL); return status; } status = omapi_set_value (h, (omapi_object_t *)0, name, tv); omapi_data_string_dereference (&name, MDL); omapi_typed_data_dereference (&tv, MDL); return status; } /* dhcpctl_object_update Queues an update on the object referenced by the handle (there can't be any other work in progress on the handle). An update means local parameters will be sent to the server. */ dhcpctl_status dhcpctl_object_update (dhcpctl_handle connection, dhcpctl_handle h) { isc_result_t status; omapi_object_t *message = (omapi_object_t *)0; dhcpctl_remote_object_t *ro; if (h -> type != dhcpctl_remote_type) return DHCP_R_INVALIDARG; ro = (dhcpctl_remote_object_t *)h; status = omapi_message_new (&message, MDL); if (status != ISC_R_SUCCESS) { omapi_object_dereference (&message, MDL); return status; } status = omapi_set_int_value (message, (omapi_object_t *)0, "op", OMAPI_OP_UPDATE); if (status != ISC_R_SUCCESS) { omapi_object_dereference (&message, MDL); return status; } status = omapi_set_object_value (message, (omapi_object_t *)0, "object", h); if (status != ISC_R_SUCCESS) { omapi_object_dereference (&message, MDL); return status; } status = omapi_set_int_value (message, (omapi_object_t *)0, "handle", (int)(ro -> remote_handle)); if (status != ISC_R_SUCCESS) { omapi_object_dereference (&message, MDL); return status; } omapi_message_register (message); status = omapi_protocol_send_message (connection -> outer, (omapi_object_t *)0, message, (omapi_object_t *)0); omapi_object_dereference (&message, MDL); return status; } /* Requests a refresh on the object referenced by the handle (there can't be any other work in progress on the handle). A refresh means local parameters are updated from the server. */ dhcpctl_status dhcpctl_object_refresh (dhcpctl_handle connection, dhcpctl_handle h) { isc_result_t status; omapi_object_t *message = (omapi_object_t *)0; dhcpctl_remote_object_t *ro; if (h -> type != dhcpctl_remote_type) return DHCP_R_INVALIDARG; ro = (dhcpctl_remote_object_t *)h; status = omapi_message_new (&message, MDL); if (status != ISC_R_SUCCESS) { omapi_object_dereference (&message, MDL); return status; } status = omapi_set_int_value (message, (omapi_object_t *)0, "op", OMAPI_OP_REFRESH); if (status != ISC_R_SUCCESS) { omapi_object_dereference (&message, MDL); return status; } status = omapi_set_int_value (message, (omapi_object_t *)0, "handle", (int)(ro -> remote_handle)); if (status != ISC_R_SUCCESS) { omapi_object_dereference (&message, MDL); return status; } omapi_message_register (message); status = omapi_protocol_send_message (connection -> outer, (omapi_object_t *)0, message, (omapi_object_t *)0); /* We don't want to send the contents of the object down the wire, but we do need to reference it so that we know what to do with the update. */ status = omapi_set_object_value (message, (omapi_object_t *)0, "object", h); if (status != ISC_R_SUCCESS) { omapi_object_dereference (&message, MDL); return status; } omapi_object_dereference (&message, MDL); return status; } /* Requests the removal of the object referenced by the handle (there can't be any other work in progress on the handle). A removal means that all searchable references to the object on the server are deleted. */ dhcpctl_status dhcpctl_object_remove (dhcpctl_handle connection, dhcpctl_handle h) { isc_result_t status; omapi_object_t *message = (omapi_object_t *)0; dhcpctl_remote_object_t *ro; if (h -> type != dhcpctl_remote_type) return DHCP_R_INVALIDARG; ro = (dhcpctl_remote_object_t *)h; status = omapi_message_new (&message, MDL); if (status != ISC_R_SUCCESS) { omapi_object_dereference (&message, MDL); return status; } status = omapi_set_int_value (message, (omapi_object_t *)0, "op", OMAPI_OP_DELETE); if (status != ISC_R_SUCCESS) { omapi_object_dereference (&message, MDL); return status; } status = omapi_set_int_value (message, (omapi_object_t *)0, "handle", (int)(ro -> remote_handle)); if (status != ISC_R_SUCCESS) { omapi_object_dereference (&message, MDL); return status; } status = omapi_set_object_value (message, (omapi_object_t *)0, "notify-object", h); if (status != ISC_R_SUCCESS) { omapi_object_dereference (&message, MDL); return status; } omapi_message_register (message); status = omapi_protocol_send_message (connection -> outer, (omapi_object_t *)0, message, (omapi_object_t *)0); omapi_object_dereference (&message, MDL); return status; } isc_result_t dhcpctl_data_string_dereference (dhcpctl_data_string *vp, const char *file, int line) { return omapi_data_string_dereference (vp, file, line); } dhcp-4.2.4/dhcpctl/dhcpctl.h000644 000765 000024 00000011723 11301372615 015605 0ustar00sarstaff000000 000000 /* $Id: dhcpctl.h,v 1.17.24.1 2009-11-20 01:49:01 sar Exp $ Subroutines providing general support for objects. */ /* * Copyright (c) 2004,2009 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1999-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ * * This software has been written for Internet Systems Consortium * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. * To learn more about Internet Systems Consortium, see * ``https://www.isc.org/''. To learn more about Vixie Enterprises, * see ``http://www.vix.com''. To learn more about Nominum, Inc., see * ``http://www.nominum.com''. */ #ifndef _DHCPCTL_H_ #define _DHCPCTL_H_ #include typedef isc_result_t dhcpctl_status; typedef omapi_object_t *dhcpctl_handle; typedef omapi_data_string_t *dhcpctl_data_string; #define dhcpctl_null_handle ((dhcpctl_handle) 0) #define DHCPCTL_CREATE OMAPI_CREATE #define DHCPCTL_UPDATE OMAPI_UPDATE #define DHCPCTL_EXCL OMAPI_EXCL typedef struct { OMAPI_OBJECT_PREAMBLE; omapi_object_t *object; void *data; void (*callback) (dhcpctl_handle, dhcpctl_status, void *); } dhcpctl_callback_object_t; typedef struct { OMAPI_OBJECT_PREAMBLE; omapi_typed_data_t *rtype; isc_result_t waitstatus; omapi_typed_data_t *message; omapi_handle_t remote_handle; } dhcpctl_remote_object_t; extern omapi_object_type_t *dhcpctl_callback_type; extern omapi_object_type_t *dhcpctl_remote_type; dhcpctl_status dhcpctl_initialize (void); dhcpctl_status dhcpctl_connect (dhcpctl_handle *, const char *, int, dhcpctl_handle); dhcpctl_status dhcpctl_wait_for_completion (dhcpctl_handle, dhcpctl_status *); dhcpctl_status dhcpctl_get_value (dhcpctl_data_string *, dhcpctl_handle, const char *); dhcpctl_status dhcpctl_get_boolean (int *, dhcpctl_handle, const char *); dhcpctl_status dhcpctl_set_value (dhcpctl_handle, dhcpctl_data_string, const char *); dhcpctl_status dhcpctl_set_string_value (dhcpctl_handle, const char *, const char *); dhcpctl_status dhcpctl_set_data_value (dhcpctl_handle, const char *, unsigned, const char *); dhcpctl_status dhcpctl_set_null_value (dhcpctl_handle, const char *); dhcpctl_status dhcpctl_set_boolean_value (dhcpctl_handle, int, const char *); dhcpctl_status dhcpctl_set_int_value (dhcpctl_handle, int, const char *); dhcpctl_status dhcpctl_object_update (dhcpctl_handle, dhcpctl_handle); dhcpctl_status dhcpctl_object_refresh (dhcpctl_handle, dhcpctl_handle); dhcpctl_status dhcpctl_object_remove (dhcpctl_handle, dhcpctl_handle); dhcpctl_status dhcpctl_set_callback (dhcpctl_handle, void *, void (*) (dhcpctl_handle, dhcpctl_status, void *)); isc_result_t dhcpctl_callback_set_value (omapi_object_t *, omapi_object_t *, omapi_data_string_t *, omapi_typed_data_t *); isc_result_t dhcpctl_callback_get_value (omapi_object_t *, omapi_object_t *, omapi_data_string_t *, omapi_value_t **); isc_result_t dhcpctl_callback_destroy (omapi_object_t *, const char *, int); isc_result_t dhcpctl_callback_signal_handler (omapi_object_t *, const char *, va_list); isc_result_t dhcpctl_callback_stuff_values (omapi_object_t *, omapi_object_t *, omapi_object_t *); dhcpctl_status dhcpctl_new_authenticator (dhcpctl_handle *, const char *, const char *, const unsigned char *, unsigned); dhcpctl_status dhcpctl_open_object (dhcpctl_handle, dhcpctl_handle, int); dhcpctl_status dhcpctl_new_object (dhcpctl_handle *, dhcpctl_handle, const char *); isc_result_t dhcpctl_remote_set_value (omapi_object_t *, omapi_object_t *, omapi_data_string_t *, omapi_typed_data_t *); isc_result_t dhcpctl_remote_get_value (omapi_object_t *, omapi_object_t *, omapi_data_string_t *, omapi_value_t **); isc_result_t dhcpctl_remote_destroy (omapi_object_t *, const char *, int); isc_result_t dhcpctl_remote_signal_handler (omapi_object_t *, const char *, va_list); isc_result_t dhcpctl_remote_stuff_values (omapi_object_t *, omapi_object_t *, omapi_object_t *); isc_result_t dhcpctl_data_string_dereference (dhcpctl_data_string *, const char *, int); #endif /* _DHCPCTL_H_ */ dhcp-4.2.4/dhcpctl/Makefile.am000644 000765 000024 00000000746 11271742256 016062 0ustar00sarstaff000000 000000 bin_PROGRAMS = omshell lib_LIBRARIES = libdhcpctl.a noinst_PROGRAMS = cltest man_MANS = omshell.1 dhcpctl.3 EXTRA_DIST = $(man_MANS) omshell_SOURCES = omshell.c omshell_LDADD = libdhcpctl.a ../common/libdhcp.a ../omapip/libomapi.a \ ../bind/lib/libdns.a ../bind/lib/libisc.a libdhcpctl_a_SOURCES = dhcpctl.c callback.c remote.c cltest_SOURCES = cltest.c cltest_LDADD = libdhcpctl.a ../common/libdhcp.a ../omapip/libomapi.a \ ../bind/lib/libdns.a ../bind/lib/libisc.adhcp-4.2.4/dhcpctl/Makefile.in000644 000765 000024 00000045510 11757500141 016063 0ustar00sarstaff000000 000000 # Makefile.in generated by automake 1.10.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : bin_PROGRAMS = omshell$(EXEEXT) noinst_PROGRAMS = cltest$(EXEEXT) subdir = dhcpctl DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/includes/config.h CONFIG_CLEAN_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = `echo $$p | sed -e 's|^.*/||'`; am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" \ "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(man3dir)" libLIBRARIES_INSTALL = $(INSTALL_DATA) LIBRARIES = $(lib_LIBRARIES) AR = ar ARFLAGS = cru libdhcpctl_a_AR = $(AR) $(ARFLAGS) libdhcpctl_a_LIBADD = am_libdhcpctl_a_OBJECTS = dhcpctl.$(OBJEXT) callback.$(OBJEXT) \ remote.$(OBJEXT) libdhcpctl_a_OBJECTS = $(am_libdhcpctl_a_OBJECTS) binPROGRAMS_INSTALL = $(INSTALL_PROGRAM) PROGRAMS = $(bin_PROGRAMS) $(noinst_PROGRAMS) am_cltest_OBJECTS = cltest.$(OBJEXT) cltest_OBJECTS = $(am_cltest_OBJECTS) cltest_DEPENDENCIES = libdhcpctl.a ../common/libdhcp.a \ ../omapip/libomapi.a ../bind/lib/libdns.a ../bind/lib/libisc.a am_omshell_OBJECTS = omshell.$(OBJEXT) omshell_OBJECTS = $(am_omshell_OBJECTS) omshell_DEPENDENCIES = libdhcpctl.a ../common/libdhcp.a \ ../omapip/libomapi.a ../bind/lib/libdns.a ../bind/lib/libisc.a DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/includes depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) CCLD = $(CC) LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ SOURCES = $(libdhcpctl_a_SOURCES) $(cltest_SOURCES) $(omshell_SOURCES) DIST_SOURCES = $(libdhcpctl_a_SOURCES) $(cltest_SOURCES) \ $(omshell_SOURCES) man1dir = $(mandir)/man1 man3dir = $(mandir)/man3 NROFF = nroff MANS = $(man_MANS) ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ GREP = @GREP@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDAP_CFLAGS = @LDAP_CFLAGS@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_prefix_program = @ac_prefix_program@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build_alias = @build_alias@ builddir = @builddir@ byte_order = @byte_order@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host_alias = @host_alias@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ lib_LIBRARIES = libdhcpctl.a man_MANS = omshell.1 dhcpctl.3 EXTRA_DIST = $(man_MANS) omshell_SOURCES = omshell.c omshell_LDADD = libdhcpctl.a ../common/libdhcp.a ../omapip/libomapi.a \ ../bind/lib/libdns.a ../bind/lib/libisc.a libdhcpctl_a_SOURCES = dhcpctl.c callback.c remote.c cltest_SOURCES = cltest.c cltest_LDADD = libdhcpctl.a ../common/libdhcp.a ../omapip/libomapi.a \ ../bind/lib/libdns.a ../bind/lib/libisc.a all: all-am .SUFFIXES: .SUFFIXES: .c .o .obj $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ && exit 0; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign dhcpctl/Makefile'; \ cd $(top_srcdir) && \ $(AUTOMAKE) --foreign dhcpctl/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh install-libLIBRARIES: $(lib_LIBRARIES) @$(NORMAL_INSTALL) test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" @list='$(lib_LIBRARIES)'; for p in $$list; do \ if test -f $$p; then \ f=$(am__strip_dir) \ echo " $(libLIBRARIES_INSTALL) '$$p' '$(DESTDIR)$(libdir)/$$f'"; \ $(libLIBRARIES_INSTALL) "$$p" "$(DESTDIR)$(libdir)/$$f"; \ else :; fi; \ done @$(POST_INSTALL) @list='$(lib_LIBRARIES)'; for p in $$list; do \ if test -f $$p; then \ p=$(am__strip_dir) \ echo " $(RANLIB) '$(DESTDIR)$(libdir)/$$p'"; \ $(RANLIB) "$(DESTDIR)$(libdir)/$$p"; \ else :; fi; \ done uninstall-libLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(lib_LIBRARIES)'; for p in $$list; do \ p=$(am__strip_dir) \ echo " rm -f '$(DESTDIR)$(libdir)/$$p'"; \ rm -f "$(DESTDIR)$(libdir)/$$p"; \ done clean-libLIBRARIES: -test -z "$(lib_LIBRARIES)" || rm -f $(lib_LIBRARIES) libdhcpctl.a: $(libdhcpctl_a_OBJECTS) $(libdhcpctl_a_DEPENDENCIES) -rm -f libdhcpctl.a $(libdhcpctl_a_AR) libdhcpctl.a $(libdhcpctl_a_OBJECTS) $(libdhcpctl_a_LIBADD) $(RANLIB) libdhcpctl.a install-binPROGRAMS: $(bin_PROGRAMS) @$(NORMAL_INSTALL) test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" @list='$(bin_PROGRAMS)'; for p in $$list; do \ p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ if test -f $$p \ ; then \ f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \ echo " $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(bindir)/$$f'"; \ $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(bindir)/$$f" || exit 1; \ else :; fi; \ done uninstall-binPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(bin_PROGRAMS)'; for p in $$list; do \ f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ echo " rm -f '$(DESTDIR)$(bindir)/$$f'"; \ rm -f "$(DESTDIR)$(bindir)/$$f"; \ done clean-binPROGRAMS: -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS) clean-noinstPROGRAMS: -test -z "$(noinst_PROGRAMS)" || rm -f $(noinst_PROGRAMS) cltest$(EXEEXT): $(cltest_OBJECTS) $(cltest_DEPENDENCIES) @rm -f cltest$(EXEEXT) $(LINK) $(cltest_OBJECTS) $(cltest_LDADD) $(LIBS) omshell$(EXEEXT): $(omshell_OBJECTS) $(omshell_DEPENDENCIES) @rm -f omshell$(EXEEXT) $(LINK) $(omshell_OBJECTS) $(omshell_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/callback.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cltest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dhcpctl.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/omshell.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/remote.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` install-man1: $(man1_MANS) $(man_MANS) @$(NORMAL_INSTALL) test -z "$(man1dir)" || $(MKDIR_P) "$(DESTDIR)$(man1dir)" @list='$(man1_MANS) $(dist_man1_MANS) $(nodist_man1_MANS)'; \ l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ for i in $$l2; do \ case "$$i" in \ *.1*) list="$$list $$i" ;; \ esac; \ done; \ for i in $$list; do \ if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \ else file=$$i; fi; \ ext=`echo $$i | sed -e 's/^.*\\.//'`; \ case "$$ext" in \ 1*) ;; \ *) ext='1' ;; \ esac; \ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ inst=`echo $$inst | sed -e 's/^.*\///'`; \ inst=`echo $$inst | sed '$(transform)'`.$$ext; \ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man1dir)/$$inst'"; \ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man1dir)/$$inst"; \ done uninstall-man1: @$(NORMAL_UNINSTALL) @list='$(man1_MANS) $(dist_man1_MANS) $(nodist_man1_MANS)'; \ l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ for i in $$l2; do \ case "$$i" in \ *.1*) list="$$list $$i" ;; \ esac; \ done; \ for i in $$list; do \ ext=`echo $$i | sed -e 's/^.*\\.//'`; \ case "$$ext" in \ 1*) ;; \ *) ext='1' ;; \ esac; \ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ inst=`echo $$inst | sed -e 's/^.*\///'`; \ inst=`echo $$inst | sed '$(transform)'`.$$ext; \ echo " rm -f '$(DESTDIR)$(man1dir)/$$inst'"; \ rm -f "$(DESTDIR)$(man1dir)/$$inst"; \ done install-man3: $(man3_MANS) $(man_MANS) @$(NORMAL_INSTALL) test -z "$(man3dir)" || $(MKDIR_P) "$(DESTDIR)$(man3dir)" @list='$(man3_MANS) $(dist_man3_MANS) $(nodist_man3_MANS)'; \ l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ for i in $$l2; do \ case "$$i" in \ *.3*) list="$$list $$i" ;; \ esac; \ done; \ for i in $$list; do \ if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \ else file=$$i; fi; \ ext=`echo $$i | sed -e 's/^.*\\.//'`; \ case "$$ext" in \ 3*) ;; \ *) ext='3' ;; \ esac; \ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ inst=`echo $$inst | sed -e 's/^.*\///'`; \ inst=`echo $$inst | sed '$(transform)'`.$$ext; \ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man3dir)/$$inst'"; \ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man3dir)/$$inst"; \ done uninstall-man3: @$(NORMAL_UNINSTALL) @list='$(man3_MANS) $(dist_man3_MANS) $(nodist_man3_MANS)'; \ l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ for i in $$l2; do \ case "$$i" in \ *.3*) list="$$list $$i" ;; \ esac; \ done; \ for i in $$list; do \ ext=`echo $$i | sed -e 's/^.*\\.//'`; \ case "$$ext" in \ 3*) ;; \ *) ext='3' ;; \ esac; \ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ inst=`echo $$inst | sed -e 's/^.*\///'`; \ inst=`echo $$inst | sed '$(transform)'`.$$ext; \ echo " rm -f '$(DESTDIR)$(man3dir)/$$inst'"; \ rm -f "$(DESTDIR)$(man3dir)/$$inst"; \ done ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) tags=; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$tags $$unique; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) tags=; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$tags$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$tags $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && cd $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) $$here distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ fi; \ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ else \ test -f $(distdir)/$$file \ || cp -p $$d/$$file $(distdir)/$$file \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(LIBRARIES) $(PROGRAMS) $(MANS) installdirs: for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(man3dir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-binPROGRAMS clean-generic clean-libLIBRARIES \ clean-noinstPROGRAMS mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am info: info-am info-am: install-data-am: install-man install-dvi: install-dvi-am install-exec-am: install-binPROGRAMS install-libLIBRARIES install-html: install-html-am install-info: install-info-am install-man: install-man1 install-man3 install-pdf: install-pdf-am install-ps: install-ps-am installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-binPROGRAMS uninstall-libLIBRARIES \ uninstall-man uninstall-man: uninstall-man1 uninstall-man3 .MAKE: install-am install-strip .PHONY: CTAGS GTAGS all all-am check check-am clean clean-binPROGRAMS \ clean-generic clean-libLIBRARIES clean-noinstPROGRAMS ctags \ distclean distclean-compile distclean-generic distclean-tags \ distdir dvi dvi-am html html-am info info-am install \ install-am install-binPROGRAMS install-data install-data-am \ install-dvi install-dvi-am install-exec install-exec-am \ install-html install-html-am install-info install-info-am \ install-libLIBRARIES install-man install-man1 install-man3 \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-compile mostlyclean-generic pdf pdf-am ps ps-am \ tags uninstall uninstall-am uninstall-binPROGRAMS \ uninstall-libLIBRARIES uninstall-man uninstall-man1 \ uninstall-man3 # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: dhcp-4.2.4/dhcpctl/omshell.1000644 000765 000024 00000025742 11301372615 015546 0ustar00sarstaff000000 000000 .\" $Id: omshell.1,v 1.5.24.1 2009-11-20 01:49:01 sar Exp $ .\" .\" Copyright (c) 2004,2009 by Internet Systems Consortium, Inc. ("ISC") .\" Copyright (c) 2001-2003 by Internet Software Consortium .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above .\" copyright notice and this permission notice appear in all copies. .\" .\" THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES .\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR .\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES .\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT .\" OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" .\" Internet Systems Consortium, Inc. .\" 950 Charter Street .\" Redwood City, CA 94063 .\" .\" https://www.isc.org/ .\" .\" This software has been written for Internet Systems Consortium .\" by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. .\" To learn more about Internet Systems Consortium, see .\" ``https://www.isc.org/''. To learn more about Vixie Enterprises, .\" see ``http://www.vix.com''. To learn more about Nominum, Inc., see .\" ``http://www.nominum.com''. .TH omshell 1 .SH NAME omshell - OMAPI Command Shell .SH SYNOPSIS .B omshell .SH DESCRIPTION The OMAPI Command Shell, omshell, provides an interactive way to connect to, query, and possibly change, the ISC DHCP Server's state via OMAPI, the Object Management API. By using OMAPI and omshell, you do not have to stop, make changes, and then restart the DHCP server, but can make the changes while the server is running. Omshell provides a way of accessing OMAPI. .PP OMAPI is simply a communications mechanism that allows you to manipulate objects. In order to actually \fIuse\fR omshell, you .I must understand what objects are available and how to use them. Documentation for OMAPI objects can be found in the documentation for the server that provides them - for example, in the \fBdhcpd(1)\fR manual page and the \fBdhclient(1)\fR manual page. .SH CONTRIBUTIONS .PP This software is free software. At various times its development has been underwritten by various organizations, including the ISC and Vixie Enterprises. The development of 3.0 has been funded almost entirely by Nominum, Inc. .PP At this point development is being shepherded by Ted Lemon, and hosted by the ISC, but the future of this project depends on you. If you have features you want, please consider implementing them. .SH LOCAL AND REMOTE OBJECTS .PP Throughout this document, there are references to local and remote objects. Local objects are ones created in omshell with the \fBnew\fR command. Remote objects are ones on the server: leases, hosts, and groups that the DHCP server knows about. Local and remote objects are associated together to enable viewing and modification of object attributes. Also, new remote objects can be created to match local objects. .SH OPENING A CONNECTION .PP omshell is started from the command line. Once omshell is started, there are several commands that can be issued: .PP .B server \fIaddress\fR .RS 0.5i where address is the IP address of the DHCP server to connect to. If this is not specified, the default server is 127.0.0.1 (localhost). .RE .PP .B port \fInumber\fR .RS 0.5i where number is the port that OMAPI listens on. By default, this is 7911. .RE .PP .B key \fIname secret\fR .RS 0.5i This specifies the TSIG key to use to authenticate the OMAPI transactions. \fIname\fR is the name of a key defined in \fIdhcpd.conf\fR with the \fBomapi-key\fR statement. The \fIsecret\fR is the secret key generated from \fBdnssec-keygen\fR or another key generation program. .RE .PP .B connect .RS 0.5i This starts the OMAPI connection to the server as specified by the \fIserver\fR statement. .SH CREATING LOCAL OBJECTS .PP Any object defined in OMAPI can be created, queried, and/or modified. The object types available to OMAPI are defined in \fBdhcpd(8)\fR and \fBdhclient(8)\fR. When using omshell, objects are first defined locally, manipulated as desired, and then associated with an object on the server. Only one object can be manipulated at a time. To create a local object, use .PP .B new \fIobject-type\fR .RS 0.5i \fIobject-type\fR is one of group, host, or lease. .RE .PP At this point, you now have an object that you can set properties on. For example, if a new lease object was created with \fInew lease\fR, any of a lease's attributes can be set as follows: .PP .B set \fIattribute-name = value\fR .RS 0.5i \fBAttribute\fR names are defined in \fBdhcpd(8)\fR and \fBdhclient(8)\fR. Values should be quoted if they are strings. So, to set a lease's IP address, you would do the following: \fB set ip-address = 192.168.4.50\fR .SH ASSOCIATING LOCAL AND REMOTE OBJECTS .PP At this point, you can query the server for information about this lease, by .PP .B open .PP Now, the local lease object you created and set the IP address for is associated with the corresponding lease object on the DHCP server. All of the lease attributes from the DHCP server are now also the attributes on the local object, and will be shown in omshell. .SH VIEWING A REMOTE OBJECT .PP To query a lease of address 192.168.4.50, and find out its attributes, after connecting to the server, take the following steps: .PP .B new "lease" .PP This creates a new local lease object. .PP .B set ip-address = 192.168.4.50 .PP This sets the \fIlocal\fR object's IP address to be 192.168.4.50 .PP .B open .PP Now, if a lease with that IP address exists, you will see all the information the DHCP server has about that particular lease. Any data that isn't readily printable text will show up in colon-separated hexadecimal values. In this example, output back from the server for the entire transaction might look like this: .nf .sp 1 > new "lease" obj: lease > set ip-address = 192.168.4.50 obj: lease ip-address = c0:a8:04:32 > open obj: lease ip-address = c0:a8:04:32 state = 00:00:00:02 dhcp-client-identifier = 01:00:10:a4:b2:36:2c client-hostname = "wendelina" subnet = 00:00:00:06 pool = 00:00:00:07 hardware-address = 00:10:a4:b2:36:2c hardware-type = 00:00:00:01 ends = dc:d9:0d:3b starts = 5c:9f:04:3b tstp = 00:00:00:00 tsfp = 00:00:00:00 cltt = 00:00:00:00 .fi .PP As you can see here, the IP address is represented in hexadecimal, as are the starting and ending times of the lease. .SH MODIFYING A REMOTE OBJECT .PP Attributes of remote objects are updated by using the \fBset\fR command as before, and then issuing an \fBupdate\fR command. The \fBset\fR command sets the attributes on the current local object, and the \fBupdate\fR command pushes those changes out to the server. .PP Continuing with the previous example, if a \fBset client-hostname = "something-else"\fR was issued, followed by an \fBupdate\fR command, the output would look about like this: .nf .sp 1 > set client-hostname = "something-else" obj: lease ip-address = c0:a8:04:32 state = 00:00:00:02 dhcp-client-identifier = 01:00:10:a4:b2:36:2c client-hostname = "something-else" subnet = 00:00:00:06 pool = 00:00:00:07 hardware-address = 00:10:a4:b2:36:2c hardware-type = 00:00:00:01 ends = dc:d9:0d:3b starts = 5c:9f:04:3b tstp = 00:00:00:00 tsfp = 00:00:00:00 cltt = 00:00:00:00 > update obj: lease ip-address = c0:a8:04:32 state = 00:00:00:02 dhcp-client-identifier = 01:00:10:a4:b2:36:2c client-hostname = "something-else" subnet = 00:00:00:06 pool = 00:00:00:07 hardware-address = 00:10:a4:b2:36:2c hardware-type = 00:00:00:01 ends = dc:d9:0d:3b starts = 5c:9f:04:3b tstp = 00:00:00:00 tsfp = 00:00:00:00 cltt = 00:00:00:00 .fi .SH NEW REMOTE OBJECTS .PP New remote objects are created much in the same way that existing server objects are modified. Create a local object using \fBnew\fR, set the attributes as you'd wish them to be, and then create the remote object with the same properties by using .PP .B create .PP Now a new object exists on the DHCP server which matches the properties that you gave your local object. Objects created via OMAPI are saved into the dhcpd.leases file. .PP For example, if a new host with the IP address of 192.168.4.40 needs to be created it would be done as follows: .nf .sp 1 > new host obj: host > set name = "some-host" obj: host name = "some-host" > set hardware-address = 00:80:c7:84:b1:94 obj: host name = "some-host" hardware-address = 00:80:c7:84:b1:94 > set hardware-type = 1 obj: host name = "some-host" hardware-address = 00:80:c7:84:b1:94 hardware-type = 1 > set ip-address = 192.168.4.40 obj: host name = "some-host" hardware-address = 00:80:c7:84:b1:94 hardware-type = 1 ip-address = c0:a8:04:28 > create obj: host name = "some-host" hardware-address = 00:80:c7:84:b1:94 hardware-type = 00:00:00:01 ip-address = c0:a8:04:28 > .fi .PP Your dhcpd.leases file would then have an entry like this in it: .nf .sp 1 host some-host { dynamic; hardware ethernet 00:80:c7:84:b1:94; fixed-address 192.168.4.40; } .fi .PP The \fIdynamic;\fR line is to denote that this host entry did not come from dhcpd.conf, but was created dynamically via OMAPI. .SH RESETTING ATTRIBUTES .PP If you want to remove an attribute from an object, you can do this with the \fBunset\fR command. Once you have unset an attribute, you must use the \fBupdate\fR command to update the remote object. So, if the host "some-host" from the previous example will not have a static IP address anymore, the commands in omshell would look like this: .nf .sp 1 obj: host name = "some-host" hardware-address = 00:80:c7:84:b1:94 hardware-type = 00:00:00:01 ip-address = c0:a8:04:28 > unset ip-address obj: host name = "some-host" hardware-address = 00:80:c7:84:b1:94 hardware-type = 00:00:00:01 ip-address = > .fi .SH REFRESHING OBJECTS .PP A local object may be refreshed with the current remote object properties using the \fBrefresh\fR command. This is useful for object that change periodically, like leases, to see if they have been updated. This isn't particularly useful for hosts. .SH DELETING OBJECTS .PP Any remote object that can be created can also be destroyed. This is done by creating a new local object, setting attributes, associating the local and remote object using \fBopen\fR, and then using the \fBremove\fR command. If the host "some-host" from before was created in error, this could be corrected as follows: .nf .sp 1 obj: host name = "some-host" hardware-address = 00:80:c7:84:b1:94 hardware-type = 00:00:00:01 ip-address = c0:a8:04:28 > remove obj: > .fi .SH HELP .PP The \fBhelp\fR command will print out all of the commands available in omshell, with some syntax pointers. .SH SEE ALSO dhcpctl(3), omapi(3), dhcpd(8), dhclient(8), dhcpd.conf(5), dhclient.conf(5). .SH AUTHOR .B omshell was written by Ted Lemon of Nominum, Inc. Information about Nominum can be found at .B http://www.nominum.com. This preliminary documentation was written by Wendy Verschoor of Nominum, Inc., while she was testing omshell. dhcp-4.2.4/dhcpctl/omshell.c000644 000765 000024 00000044145 11571545655 015645 0ustar00sarstaff000000 000000 /* omshell.c Examine and modify omapi objects. */ /* * Copyright (c) 2009-2011 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 2004-2007 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 2001-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ * * This software has been written for Internet Systems Consortium * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. * To learn more about Internet Systems Consortium, see * ``https://www.isc.org/''. To learn more about Vixie Enterprises, * see ``http://www.vix.com''. To learn more about Nominum, Inc., see * ``http://www.nominum.com''. */ #include "config.h" #include #include #include #include #include #include //#include "result.h" #include #include "dhcpctl.h" #include "dhcpd.h" /* Fixups */ isc_result_t find_class (struct class **c, const char *n, const char *f, int l) { return 0; } int parse_allow_deny (struct option_cache **oc, struct parse *cfile, int flag) { return 0; } void dhcp (struct packet *packet) { } void bootp (struct packet *packet) { } #ifdef DHCPv6 /* XXX: should we warn or something here? */ void dhcpv6(struct packet *packet) { } #endif /* DHCPv6 */ int check_collection (struct packet *p, struct lease *l, struct collection *c) { return 0; } void classify (struct packet *packet, struct class *class) { } static void usage (char *s) { fprintf (stderr, "Usage: %s\n", s); exit (1); } static void check (isc_result_t status, const char *func) { if (status != ISC_R_SUCCESS) { fprintf (stderr, "%s: %s\n", func, isc_result_totext (status)); exit (1); } } int main(int argc, char **argv) { isc_result_t status, waitstatus; dhcpctl_handle connection; dhcpctl_handle authenticator; dhcpctl_handle oh; struct data_string secret; const char *name = 0, *algorithm = "hmac-md5"; int i; int port = 7911; const char *server = "127.0.0.1"; struct parse *cfile; enum dhcp_token token; const char *val; char *s; char buf[1024]; char s1[1024]; int connected = 0; char hex_buf[1025]; for (i = 1; i < argc; i++) { usage(argv[0]); } /* Initially, log errors to stderr as well as to syslogd. */ openlog ("omshell", LOG_NDELAY, DHCPD_LOG_FACILITY); status = dhcpctl_initialize (); if (status != ISC_R_SUCCESS) { fprintf (stderr, "dhcpctl_initialize: %s\n", isc_result_totext (status)); exit (1); } memset (&oh, 0, sizeof oh); do { if (!connected) { } else if (oh == NULL) { printf ("obj: \n"); } else { dhcpctl_remote_object_t *r = (dhcpctl_remote_object_t *)oh; omapi_generic_object_t *g = (omapi_generic_object_t *)(r -> inner); printf ("obj: "); if (r -> rtype -> type != omapi_datatype_string) { printf ("?\n"); } else { printf ("%.*s\n", (int)(r -> rtype -> u . buffer . len), r -> rtype -> u . buffer . value); } for (i = 0; i < g -> nvalues; i++) { omapi_value_t *v = g -> values [i]; if (!g -> values [i]) continue; printf ("%.*s = ", (int)v -> name -> len, v -> name -> value); if (!v -> value) { printf ("\n"); continue; } switch (v -> value -> type) { case omapi_datatype_int: printf ("%d\n", v -> value -> u . integer); break; case omapi_datatype_string: printf ("\"%.*s\"\n", (int) v -> value -> u.buffer.len, v -> value -> u.buffer.value); break; case omapi_datatype_data: print_hex_or_string(v->value->u.buffer.len, v->value->u.buffer.value, sizeof(hex_buf), hex_buf); printf("%s\n", hex_buf); break; case omapi_datatype_object: printf ("\n"); break; } } } fputs ("> ", stdout); fflush (stdout); if (fgets (buf, sizeof(buf), stdin) == NULL) break; status = new_parse (&cfile, -1, buf, strlen(buf), "", 1); check(status, "new_parse()"); token = next_token (&val, (unsigned *)0, cfile); switch (token) { default: parse_warn (cfile, "unknown token: %s", val); skip_to_semi (cfile); break; case END_OF_FILE: case ENDOFLINE: /* EOL: */ break; case TOKEN_HELP: case QUESTIONMARK: /* '?': */ printf ("Commands:\n"); printf (" port \n"); printf (" server \n"); printf (" key \n"); printf (" connect\n"); printf (" new \n"); printf (" set = \n"); printf (" create\n"); printf (" open\n"); printf (" update\n"); printf (" unset \n"); printf (" refresh\n"); printf (" remove\n"); skip_to_semi (cfile); break; case PORT: token = next_token (&val, (unsigned *)0, cfile); if (is_identifier (token)) { struct servent *se; se = getservbyname (val, "tcp"); if (se) port = ntohs (se -> s_port); else { printf ("unknown service name: %s\n", val); break; } } else if (token == NUMBER) { port = atoi (val); } else { skip_to_semi (cfile); printf ("usage: port \n"); break; } token = next_token (&val, (unsigned *)0, cfile); if (token != END_OF_FILE && token != EOL) { printf ("usage: port \n"); skip_to_semi (cfile); break; } break; case TOKEN_SERVER: token = next_token (&val, (unsigned *)0, cfile); if (token == NUMBER) { int alen = (sizeof buf) - 1; int len; s = &buf [0]; len = strlen (val); if (len + 1 > alen) { baddq: printf ("usage: server \n"); skip_to_semi (cfile); break; } strcpy (buf, val); s += len; token = next_token (&val, (unsigned *)0, cfile); if (token != DOT) goto baddq; *s++ = '.'; token = next_token (&val, (unsigned *)0, cfile); if (token != NUMBER) goto baddq; len = strlen (val); if (len + 1 > alen) goto baddq; strcpy (s, val); s += len; token = next_token (&val, (unsigned *)0, cfile); if (token != DOT) goto baddq; *s++ = '.'; token = next_token (&val, (unsigned *)0, cfile); if (token != NUMBER) goto baddq; len = strlen (val); if (len + 1 > alen) goto baddq; strcpy (s, val); s += len; token = next_token (&val, (unsigned *)0, cfile); if (token != DOT) goto baddq; *s++ = '.'; token = next_token (&val, (unsigned *)0, cfile); if (token != NUMBER) goto baddq; len = strlen (val); if (len + 1 > alen) goto baddq; strcpy (s, val); val = &buf [0]; } else if (is_identifier (token)) { /* Use val directly. */ } else { printf ("usage: server \n"); skip_to_semi (cfile); break; } s = dmalloc (strlen (val) + 1, MDL); if (!server) { printf ("no memory to store server name.\n"); skip_to_semi (cfile); break; } strcpy (s, val); server = s; token = next_token (&val, (unsigned *)0, cfile); if (token != END_OF_FILE && token != EOL) { printf ("usage: server \n"); skip_to_semi (cfile); break; } break; case KEY: token = peek_token(&val, (unsigned *)0, cfile); if (token == STRING) { token = next_token (&val, (unsigned *)0, cfile); if (!is_identifier (token)) { printf ("usage: key \n"); skip_to_semi (cfile); break; } s = dmalloc (strlen (val) + 1, MDL); if (!s) { printf ("no memory for key name.\n"); skip_to_semi (cfile); break; } strcpy (s, val); } else { s = parse_host_name(cfile); if (s == NULL) { printf ("usage: key \n"); skip_to_semi(cfile); break; } } name = s; memset (&secret, 0, sizeof secret); if (!parse_base64 (&secret, cfile)) { skip_to_semi (cfile); break; } token = next_token (&val, (unsigned *)0, cfile); if (token != END_OF_FILE && token != EOL) { printf ("usage: key \n"); skip_to_semi (cfile); break; } break; case CONNECT: token = next_token (&val, (unsigned *)0, cfile); if (token != END_OF_FILE && token != EOL) { printf ("usage: connect\n"); skip_to_semi (cfile); break; } authenticator = dhcpctl_null_handle; if (name) { status = dhcpctl_new_authenticator (&authenticator, name, algorithm, secret.data, secret.len); if (status != ISC_R_SUCCESS) { fprintf (stderr, "Cannot create authenticator: %s\n", isc_result_totext (status)); break; } } memset (&connection, 0, sizeof connection); status = dhcpctl_connect (&connection, server, port, authenticator); if (status != ISC_R_SUCCESS) { fprintf (stderr, "dhcpctl_connect: %s\n", isc_result_totext (status)); break; } connected = 1; break; case TOKEN_NEW: token = next_token (&val, (unsigned *)0, cfile); if ((!is_identifier (token) && token != STRING)) { printf ("usage: new \n"); break; } if (oh) { printf ("an object is already open.\n"); skip_to_semi (cfile); break; } if (!connected) { printf ("not connected.\n"); skip_to_semi (cfile); break; } status = dhcpctl_new_object (&oh, connection, val); if (status != ISC_R_SUCCESS) { printf ("can't create object: %s\n", isc_result_totext (status)); break; } token = next_token (&val, (unsigned *)0, cfile); if (token != END_OF_FILE && token != EOL) { printf ("usage: new \n"); skip_to_semi (cfile); break; } break; case TOKEN_CLOSE: token = next_token (&val, (unsigned *)0, cfile); if (token != END_OF_FILE && token != EOL) { printf ("usage: close\n"); skip_to_semi (cfile); break; } if (!connected) { printf ("not connected.\n"); skip_to_semi (cfile); break; } if (!oh) { printf ("not open.\n"); skip_to_semi (cfile); break; } omapi_object_dereference (&oh, MDL); break; case TOKEN_SET: token = next_token (&val, (unsigned *)0, cfile); if ((!is_identifier (token) && token != STRING)) { set_usage: printf ("usage: set = \n"); skip_to_semi (cfile); break; } if (oh == NULL) { printf ("no open object.\n"); skip_to_semi (cfile); break; } if (!connected) { printf ("not connected.\n"); skip_to_semi (cfile); break; } s1[0] = '\0'; strncat (s1, val, sizeof(s1)-1); token = next_token (&val, (unsigned *)0, cfile); if (token != EQUAL) goto set_usage; token = next_token (&val, (unsigned *)0, cfile); switch (token) { case STRING: dhcpctl_set_string_value (oh, val, s1); token = next_token (&val, (unsigned *)0, cfile); break; case NUMBER: strcpy (buf, val); token = peek_token (&val, (unsigned *)0, cfile); /* Colon-separated hex list? */ if (token == COLON) goto cshl; else if (token == DOT) { s = buf; val = buf; do { int intval = atoi (val); if (intval > 255) { parse_warn (cfile, "dotted octet > 255: %s", val); skip_to_semi (cfile); goto badnum; } *s++ = intval; token = next_token (&val, (unsigned *)0, cfile); if (token != DOT) break; /* DOT is zero. */ while ((token = next_token (&val, (unsigned *)0, cfile)) == DOT) *s++ = 0; } while (token == NUMBER); dhcpctl_set_data_value (oh, buf, (unsigned)(s - buf), s1); break; } dhcpctl_set_int_value (oh, atoi (buf), s1); token = next_token (&val, (unsigned *)0, cfile); badnum: break; case NUMBER_OR_NAME: strcpy (buf, val); cshl: s = buf; val = buf; do { convert_num (cfile, (unsigned char *)s, val, 16, 8); ++s; token = next_token (&val, (unsigned *)0, cfile); if (token != COLON) break; token = next_token (&val, (unsigned *)0, cfile); } while (token == NUMBER || token == NUMBER_OR_NAME); dhcpctl_set_data_value (oh, buf, (unsigned)(s - buf), s1); break; default: printf ("invalid value.\n"); skip_to_semi (cfile); } if (token != END_OF_FILE && token != EOL) goto set_usage; break; case UNSET: token = next_token (&val, (unsigned *)0, cfile); if ((!is_identifier (token) && token != STRING)) { unset_usage: printf ("usage: unset \n"); skip_to_semi (cfile); break; } if (!oh) { printf ("no open object.\n"); skip_to_semi (cfile); break; } if (!connected) { printf ("not connected.\n"); skip_to_semi (cfile); break; } s1[0] = '\0'; strncat (s1, val, sizeof(s1)-1); token = next_token (&val, (unsigned *)0, cfile); if (token != END_OF_FILE && token != EOL) goto unset_usage; dhcpctl_set_null_value (oh, s1); break; case TOKEN_CREATE: case TOKEN_OPEN: i = token; token = next_token (&val, (unsigned *)0, cfile); if (token != END_OF_FILE && token != EOL) { printf ("usage: %s\n", val); skip_to_semi (cfile); break; } if (!connected) { printf ("not connected.\n"); skip_to_semi (cfile); break; } if (!oh) { printf ("you must make a new object first!\n"); skip_to_semi (cfile); break; } if (i == TOKEN_CREATE) i = DHCPCTL_CREATE | DHCPCTL_EXCL; else i = 0; status = dhcpctl_open_object (oh, connection, i); if (status == ISC_R_SUCCESS) status = dhcpctl_wait_for_completion (oh, &waitstatus); if (status == ISC_R_SUCCESS) status = waitstatus; if (status != ISC_R_SUCCESS) { printf ("can't open object: %s\n", isc_result_totext (status)); break; } break; case UPDATE: token = next_token (&val, (unsigned *)0, cfile); if (token != END_OF_FILE && token != EOL) { printf ("usage: %s\n", val); skip_to_semi (cfile); break; } if (!connected) { printf ("not connected.\n"); skip_to_semi (cfile); break; } if (!oh) { printf ("you haven't opened an object yet!\n"); skip_to_semi (cfile); break; } status = dhcpctl_object_update(connection, oh); if (status == ISC_R_SUCCESS) status = dhcpctl_wait_for_completion (oh, &waitstatus); if (status == ISC_R_SUCCESS) status = waitstatus; if (status != ISC_R_SUCCESS) { printf ("can't update object: %s\n", isc_result_totext (status)); break; } break; case REMOVE: token = next_token (&val, (unsigned *)0, cfile); if (token != END_OF_FILE && token != EOL) { printf ("usage: remove\n"); skip_to_semi (cfile); break; } if (!connected) { printf ("not connected.\n"); break; } if (!oh) { printf ("no object.\n"); break; } status = dhcpctl_object_remove(connection, oh); if (status == ISC_R_SUCCESS) status = dhcpctl_wait_for_completion (oh, &waitstatus); if (status == ISC_R_SUCCESS) status = waitstatus; if (status != ISC_R_SUCCESS) { printf ("can't destroy object: %s\n", isc_result_totext (status)); break; } omapi_object_dereference (&oh, MDL); break; case REFRESH: token = next_token (&val, (unsigned *)0, cfile); if (token != END_OF_FILE && token != EOL) { printf ("usage: refresh\n"); skip_to_semi (cfile); break; } if (!connected) { printf ("not connected.\n"); break; } if (!oh) { printf ("no object.\n"); break; } status = dhcpctl_object_refresh(connection, oh); if (status == ISC_R_SUCCESS) status = dhcpctl_wait_for_completion (oh, &waitstatus); if (status == ISC_R_SUCCESS) status = waitstatus; if (status != ISC_R_SUCCESS) { printf ("can't refresh object: %s\n", isc_result_totext (status)); break; } break; } end_parse (&cfile); } while (1); exit (0); } /* Sigh */ isc_result_t dhcp_set_control_state (control_object_state_t oldstate, control_object_state_t newstate) { return ISC_R_SUCCESS; } dhcp-4.2.4/dhcpctl/remote.c000644 000765 000024 00000025015 11301372615 015451 0ustar00sarstaff000000 000000 /* remote.c The dhcpctl remote object. */ /* * Copyright (c) 2004,2007,2009 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1999-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ * * This software has been written for Internet Systems Consortium * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. * To learn more about Internet Systems Consortium, see * ``https://www.isc.org/''. To learn more about Vixie Enterprises, * see ``http://www.vix.com''. To learn more about Nominum, Inc., see * ``http://www.nominum.com''. */ #include "dhcpd.h" #include #include "dhcpctl.h" /* dhcpctl_new_authenticator synchronous - creates an authenticator object. returns nonzero status code if the object couldn't be created stores handle to authenticator through h if successful, and returns zero. name is the authenticator name (NUL-terminated string). algorithm is the NUL-terminated string name of the algorithm to use (currently, only "hmac-md5" is supported). secret and secret_len is the key secret. */ dhcpctl_status dhcpctl_new_authenticator (dhcpctl_handle *h, const char *name, const char *algorithm, const unsigned char *secret, unsigned secret_len) { struct auth_key *key = (struct auth_key *)0; isc_result_t status; status = omapi_auth_key_new (&key, MDL); if (status != ISC_R_SUCCESS) return status; key -> name = dmalloc (strlen (name) + 1, MDL); if (!key -> name) { omapi_auth_key_dereference (&key, MDL); return ISC_R_NOMEMORY; } strcpy (key -> name, name); /* If the algorithm name isn't an FQDN, tack on the .SIG-ALG.REG.NET. domain. */ if (strchr (algorithm, '.') == 0) { static char add[] = ".SIG-ALG.REG.INT."; key -> algorithm = dmalloc (strlen (algorithm) + sizeof (add), MDL); if (!key -> algorithm) { omapi_auth_key_dereference (&key, MDL); return ISC_R_NOMEMORY; } strcpy (key -> algorithm, algorithm); strcat (key -> algorithm, add); } else { key -> algorithm = dmalloc (strlen (algorithm) + 1, MDL); if (!key -> algorithm) { omapi_auth_key_dereference (&key, MDL); return ISC_R_NOMEMORY; } strcpy (key -> algorithm, algorithm); } status = omapi_data_string_new (&key -> key, secret_len, MDL); if (status != ISC_R_SUCCESS) { omapi_auth_key_dereference (&key, MDL); return status; } memcpy (key -> key -> value, secret, secret_len); key -> key -> len = secret_len; *h = (dhcpctl_handle) key; return ISC_R_SUCCESS; } /* dhcpctl_new_object synchronous - creates a local handle for a host entry. returns nonzero status code if the local host entry couldn't be created stores handle to host through h if successful, and returns zero. object_type is a pointer to a NUL-terminated string containing the ascii name of the type of object being accessed - e.g., "host" */ dhcpctl_status dhcpctl_new_object (dhcpctl_handle *h, dhcpctl_handle connection, const char *object_type) { dhcpctl_remote_object_t *m; omapi_object_t *g; isc_result_t status; m = (dhcpctl_remote_object_t *)0; status = omapi_object_allocate((omapi_object_t **)&m, dhcpctl_remote_type, 0, MDL); if (status != ISC_R_SUCCESS) return status; g = (omapi_object_t *)0; status = omapi_generic_new (&g, MDL); if (status != ISC_R_SUCCESS) { dfree (m, MDL); return status; } status = omapi_object_reference (&m -> inner, g, MDL); if (status != ISC_R_SUCCESS) { omapi_object_dereference ((omapi_object_t **)&m, MDL); omapi_object_dereference (&g, MDL); return status; } status = omapi_object_reference (&g -> outer, (omapi_object_t *)m, MDL); if (status != ISC_R_SUCCESS) { omapi_object_dereference ((omapi_object_t **)&m, MDL); omapi_object_dereference (&g, MDL); return status; } status = omapi_typed_data_new (MDL, &m -> rtype, omapi_datatype_string, object_type); if (status != ISC_R_SUCCESS) { omapi_object_dereference ((omapi_object_t **)&m, MDL); omapi_object_dereference (&g, MDL); return status; } status = omapi_object_reference (h, (omapi_object_t *)m, MDL); omapi_object_dereference ((omapi_object_t **)&m, MDL); omapi_object_dereference (&g, MDL); if (status != ISC_R_SUCCESS) return status; return status; } /* asynchronous - just queues the request returns nonzero status code if open couldn't be queued returns zero if open was queued h is a handle to an object created by dhcpctl_new_object connection is a connection to a DHCP server flags include: DHCPCTL_CREATE - if the object doesn't exist, create it DHCPCTL_UPDATE - update the object on the server using the attached parameters DHCPCTL_EXCL - error if the object exists and DHCPCTL_CREATE was also specified */ dhcpctl_status dhcpctl_open_object (dhcpctl_handle h, dhcpctl_handle connection, int flags) { isc_result_t status; omapi_object_t *message = (omapi_object_t *)0; dhcpctl_remote_object_t *remote; if (h -> type != dhcpctl_remote_type) return DHCP_R_INVALIDARG; remote = (dhcpctl_remote_object_t *)h; status = omapi_message_new (&message, MDL); if (status != ISC_R_SUCCESS) return status; status = omapi_set_int_value (message, (omapi_object_t *)0, "op", OMAPI_OP_OPEN); if (status != ISC_R_SUCCESS) { omapi_object_dereference (&message, MDL); return status; } status = omapi_set_object_value (message, (omapi_object_t *)0, "object", h); if (status != ISC_R_SUCCESS) { omapi_object_dereference (&message, MDL); return status; } if (flags & DHCPCTL_CREATE) { status = omapi_set_boolean_value (message, (omapi_object_t *)0, "create", 1); if (status != ISC_R_SUCCESS) { omapi_object_dereference (&message, MDL); return status; } } if (flags & DHCPCTL_UPDATE) { status = omapi_set_boolean_value (message, (omapi_object_t *)0, "update", 1); if (status != ISC_R_SUCCESS) { omapi_object_dereference (&message, MDL); return status; } } if (flags & DHCPCTL_EXCL) { status = omapi_set_boolean_value (message, (omapi_object_t *)0, "exclusive", 1); if (status != ISC_R_SUCCESS) { omapi_object_dereference (&message, MDL); return status; } } if (remote -> rtype) { status = omapi_set_value_str (message, (omapi_object_t *)0, "type", remote -> rtype); if (status != ISC_R_SUCCESS) { omapi_object_dereference (&message, MDL); return status; } } status = omapi_message_register (message); if (status != ISC_R_SUCCESS) { omapi_object_dereference (&message, MDL); return status; } status = omapi_protocol_send_message (connection -> outer, (omapi_object_t *)0, message, (omapi_object_t *)0); if (status != ISC_R_SUCCESS) omapi_message_unregister (message); omapi_object_dereference (&message, MDL); return status; } /* Callback methods (not meant to be called directly) */ isc_result_t dhcpctl_remote_set_value (omapi_object_t *h, omapi_object_t *id, omapi_data_string_t *name, omapi_typed_data_t *value) { dhcpctl_remote_object_t *ro; unsigned long rh; isc_result_t status; if (h -> type != dhcpctl_remote_type) return DHCP_R_INVALIDARG; ro = (dhcpctl_remote_object_t *)h; if (!omapi_ds_strcmp (name, "remote-handle")) { status = omapi_get_int_value (&rh, value); if (status == ISC_R_SUCCESS) ro -> remote_handle = rh; return status; } if (h -> inner && h -> inner -> type -> set_value) return (*(h -> inner -> type -> set_value)) (h -> inner, id, name, value); return ISC_R_NOTFOUND; } isc_result_t dhcpctl_remote_get_value (omapi_object_t *h, omapi_object_t *id, omapi_data_string_t *name, omapi_value_t **value) { if (h -> type != dhcpctl_remote_type) return DHCP_R_INVALIDARG; if (h -> inner && h -> inner -> type -> get_value) return (*(h -> inner -> type -> get_value)) (h -> inner, id, name, value); return ISC_R_NOTFOUND; } isc_result_t dhcpctl_remote_signal_handler (omapi_object_t *o, const char *name, va_list ap) { dhcpctl_remote_object_t *p; omapi_typed_data_t *tv; if (o -> type != dhcpctl_remote_type) return DHCP_R_INVALIDARG; p = (dhcpctl_remote_object_t *)o; if (!strcmp (name, "updated")) { p -> waitstatus = ISC_R_SUCCESS; if (o -> inner -> type == omapi_type_generic) omapi_generic_clear_flags (o -> inner); return omapi_signal_in (o -> inner, "ready"); } if (!strcmp (name, "status")) { p -> waitstatus = va_arg (ap, isc_result_t); if (p -> message) omapi_typed_data_dereference (&p -> message, MDL); tv = va_arg (ap, omapi_typed_data_t *); if (tv) omapi_typed_data_reference (&p -> message, tv, MDL); return omapi_signal_in (o -> inner, "ready"); } if (p -> inner && p -> inner -> type -> signal_handler) return (*(p -> inner -> type -> signal_handler)) (p -> inner, name, ap); return ISC_R_SUCCESS; } isc_result_t dhcpctl_remote_destroy (omapi_object_t *h, const char *file, int line) { dhcpctl_remote_object_t *p; if (h -> type != dhcpctl_remote_type) return DHCP_R_INVALIDARG; p = (dhcpctl_remote_object_t *)h; if (p -> handle) omapi_object_dereference ((omapi_object_t **)&p -> handle, file, line); if (p -> rtype) omapi_typed_data_dereference ((omapi_typed_data_t **)&p->rtype, file, line); return ISC_R_SUCCESS; } /* Write all the published values associated with the object through the specified connection. */ isc_result_t dhcpctl_remote_stuff_values (omapi_object_t *c, omapi_object_t *id, omapi_object_t *p) { if (p -> type != dhcpctl_remote_type) return DHCP_R_INVALIDARG; if (p -> inner && p -> inner -> type -> stuff_values) return (*(p -> inner -> type -> stuff_values)) (c, id, p -> inner); return ISC_R_SUCCESS; } dhcp-4.2.4/contrib/3.0b1-lease-convert000755 000765 000024 00000005267 07267364116 017273 0ustar00sarstaff000000 000000 #!/usr/bin/perl # # Start Date: Mon, 26 Mar 2001 14:24:09 +0200 # Time-stamp: # File: leaseconvertor.pl # RCSId: $Id: 3.0b1-lease-convert,v 1.1 2001-04-18 19:17:34 mellon Exp $ # # Description: Convert 3.0b1 to 3.0b2/final lease file format # require 5.004; my $rcsID =<<'EOM'; $Id: 3.0b1-lease-convert,v 1.1 2001-04-18 19:17:34 mellon Exp $ EOM use strict; my $revstatement =<<'EOS'; switch (ns-update (delete (1, 12, ddns-rev-name, null))) { case 0: unset ddns-rev-name; break; } EOS my $fwdstatement =<<'EOS'; switch (ns-update (delete (1, 1, ddns-fwd-name, leased-address))) { case 0: unset ddns-fwd-name; break; } EOS if (@ARGV && $ARGV[0] =~ m!^-!) { usage(); } # read stdin and write stdout. while (<>) { if (! /^lease\s/) { print; } else { my $lease = $_; while (<>) { $lease .= $_; # in a b1 file we should only see a left curly brace on a lease # lines. Seening it anywhere else means the user is probably # running a b2 or later file through this. # Ditto for a 'set' statement. if (m!\{! || m!^\s*set\s!) { warn "this doesn't look like a 3.0b1 file. Ignoring rest.\n"; print $lease; dumpRestAndExit(); } last if m!^\}\s*$!; } # $lease contains all the lines for the lease entry. $lease = makeNewLease($lease); print $lease; } } sub usage { my $prog = $0; $prog =~ s!.*/!!; print STDERR <) { print; } exit (0); } dhcp-4.2.4/contrib/dhclient-tz-exithook.sh000644 000765 000024 00000011735 10614504217 020447 0ustar00sarstaff000000 000000 #!/bin/bash # # dhclient-tz-exithook.sh # Version 1.01 elear # # Copyright (c) 2007, Cisco Systems, Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # - Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # # - Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in # the documentation and/or other materials provided with the # distribution. # # - Neither the name of Cisco Systems, Inc. nor the names of its # contributors may be used to endorse or promote products derived # from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, # INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE # GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, # WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # the following script is used to set the timezone based on the new # dhcp timezone option defined currently in the IETF document # draft-ietf-dhc-timezone-option-04.txt. # this code is intended for use with ISC's dhclient. it is to be called # either as, or by, dhclient-exit-hooks # # As this is test code, in order for it to be called two changes # must be made to /etc/dhclient.conf. First, dhclient.conf must be # aware of the tzName option. The IANA has assigned tzName option # code 101. You may need to add this to your configuration file. # # option tzName code 101 = text; # # Next, add tzName to the list of options in the "request" statement. # For example: # # request subnet-mask, broadcast-address, time-offset, routers, # domain-name, domain-name-servers, host-name, tzName; # # # And of course make sure that your dhcp server is transmitting timezone # information for option 101. For IOS this can be done as follows: # # option 101 ascii "Europe/Berlin" # timefile=/etc/localtime oldfile=$timefile.old tmpfile=$timefile.$$ # function to clean up just in case we are interrupted or something # bad happens. restore_file () { if [ ! -f $timefile ]; then $DEBUG mv $tmpfile $timefile fi $DEBUG rm $tmpfile exit } #set DEBUG to "echo" to see what would happen. if [ x$DEBUG = x ]; then DEBUG= fi # if something has already gone wrong we're not doing a thing. if [ x$exit_status != x0 ]; then exit $exit_status fi # if we don't have a new timezone, then we have nothing to change, so # goodbye. if [ x$new_tzName = x ]; then exit 0 fi # if the timezone doesn't exist, goodbye. if [ ! -e $timefile ]; then exit 0 fi # find zoneinfo. use the first one. ftz=0 for a in /usr/share/zoneinfo /usr/lib/zoneinfo /var/share/zoneinfo /var/zoneinfo; do if [ -d $a -a $ftz = 0 ]; then zoneinfo=$a ftz=1 fi done # no zoneinfo found. goodbye. if [ x$zoneinfo = x ]; then exit 0 fi # timezone not found. goodbye. if [ ! -f $zoneinfo/$new_tzName ]; then exit 0 fi # if we're here we can actually do something useful. # first, link a copy of the existing timefile. $DEBUG ln $timefile $tmpfile if [ $? != 0 ]; then echo "unable to create temporary file" exit -1 fi # in case of interrupt, cleanup. trap restore_file SIGINT SIGSEGV SIGQUIT SIGTERM # we destroy old backup files in this process. if we cannot and the # file exists then something went wrong. if [ -e $oldfile ]; then $DEBUG rm $oldfile if [ $? != 0 ]; then echo "$0: failed to remove $oldfile" rm -f $tmpfile exit -1 fi fi # sensitive part happens here: # $DEBUG mv $timefile $oldfile if [ $? != 0 ]; then echo "$0: failed to move old $timefile file out of the way" rm $tmpfile exit -1 fi $DEBUG ln $zoneinfo/$new_tzName $timefile # we don't complain just yet- a hard link could fail because # we're on two different file systems. Go for a soft link. # if [ $? != 0 ]; then $DEBUG ln -s $zoneinfo/$new_tzName $timefile fi if [ $? != 0 ]; then # failed to softlink. now we're getting nervous. echo "$0: unable to establish new timezone. Attempting to revert." $DEBUG ln $tmpfile $timefile fi if [ $? != 0 ]; then # we're absolutely hosed echo "$0: unable to link or softlink timezone file, and unable to restore old file - giving up!" exit -1 fi $DEBUG rm $tmpfile exit $? dhcp-4.2.4/contrib/dhcp.spec000644 000765 000024 00000010111 10216362506 015614 0ustar00sarstaff000000 000000 Summary: The Internet Systems Consortium (ISC) DHCP server Name: dhcp %define version 3.0.2 Version: %{version} Release: 2tac Group: System Environment/Daemons Source: /usr/local/src/RPM/SOURCES/dhcp-%{version}.tar.gz Copyright: ISC BuildRoot: /var/tmp/dhcp-%{version}-root %description Dhcp includes the DHCP server which is used for dynamically configuring hosts on a network. Host configuration items such as IP address, name servers, domain name, etc. can all be retrieved from the DHCP server by a DHCP client. This eases the burden of network wide configuration by putting all of the configuration into one place. %package client Summary: A DHCP client Group: System Environment/Configuration %description client Dhcp client is a DHCP client for various UNIX operating systems. It allows a UNIX machine to obtain it's networking parameters from a DHCP server. %package relay Summary: A DHCP relay Group: System Environment/Daemons %description relay Dhcp relay is a relay agent for DHCP packets. It is used on a subnet with DHCP clients to "relay" their requests to a subnet that has a DHCP server on it. Because DHCP packets can be broadcast, they will not be routed off of the local subnet. The DHCP relay takes care of this for the client. %package devel Summary: Development headers and libraries for the dhcpctl API Group: Development/Libraries %description devel Dhcp devel contains all of the libraries and headers for developing with the dhcpctl API. %prep %setup -q -n dhcp-%{version} # do some file editing egrep "VARRUN ETC VARDB" site.conf | sed -e 's/ *=/=/g' -e 's/= */=/g' > vars . ./vars cat << EOF >> includes/site.h #define _PATH_DHCPD_PID "$VARRUN/dhcpd.pid" #define _PATH_DHCPD_DB "$ETC/dhcpd.leases" #define _PATH_DHCPD_CONF "$ETC/dhcpd.conf" EOF ./configure --with-nsupdate %build make %install rm -rf $RPM_BUILD_ROOT mkdir -p $RPM_BUILD_ROOT/usr/local/sbin make DESTDIR="$RPM_BUILD_ROOT" install %ifos linux mkdir -p ${RPM_BUILD_ROOT}/etc/rc.d/{init,rc0,rc1,rc2,rc3,rc4,rc5,rc6}.d install -m 755 linux.init ${RPM_BUILD_ROOT}/etc/rc.d/init.d/dhcpd %else %ifos solaris mkdir -p ${RPM_BUILD_ROOT}/etc/init.d sed -e s'|@PREFIX@|%{_prefix}|g' < contrib/solaris.init > ${RPM_BUILD_ROOT}/etc/init.d/dhcpd chmod 755 ${RPM_BUILD_ROOT}/etc/init.d/dhcpd %endif %endif # strip binaries and libraries strip $RPM_BUILD_ROOT%{_prefix}/sbin/* || : for i in `find $RPM_BUILD_ROOT/ -type 'f' -perm '+a=x' ! -name 'lib*so*'`; do file $i |grep -q "not stripped" && strip $i done %post %ifos linux /sbin/chkconfig --add dhcpd /etc/rc.d/init.d/dhcpd start %else %ifos solaris ln /etc/init.d/dhcpd /etc/rc2.d/S90dhcpd ln /etc/init.d/dhcpd /etc/rc0.d/K30dhcpd /etc/init.d/dhcpd start %else echo "Unknown O/S. You will need to manually configure your\nsystem" echo "to start the DHCP server on system startup." %endif %endif %preun if [ $1 = 0 ]; then %ifos linux /etc/rc.d/init.d/dhcpd stop /sbin/chkconfig --del dhcpd %else %ifos solaris /etc/init.d/dhcpd stop rm /etc/rc2.d/S90dhcpd rm /etc/rc0.d/K30dhcpd %else echo "Unknown O/S. You will need to manually clean up the DHCP" echo "server startup\n in your system startup environment." %endif %endif fi %clean rm -rf $RPM_BUILD_ROOT %files %defattr(-,root,root) %doc COPYRIGHT DOCUMENTATION ISC-LICENSE CHANGES README RELNOTES doc/* %{_prefix}/sbin/dhcpd %{_prefix}/man/cat1m/dhcpd.1m %{_prefix}/man/cat4/dhcpd.conf.4 %{_prefix}/man/cat4/dhcpd.leases.4 %{_prefix}/man/cat4/dhcp-options.4 %{_prefix}/man/cat4/dhcp-eval.4 %{_prefix}/man/cat4/dhcp-contrib.4 %ifos linux %config /etc/rc.d/init.d/dhcpd %else %ifos solaris %config /etc/init.d/dhcpd %endif %endif %files devel %{_prefix}/man/cat3 %{_prefix}/lib %{_prefix}/include %files client %{_prefix}/etc/dhclient-script %{_prefix}/sbin/dhclient %{_prefix}/man/cat1m/dhclient.1m %{_prefix}/man/cat1m/dhclient-script.1m %{_prefix}/man/cat4/dhclient.conf.4 %{_prefix}/man/cat4/dhclient.leases.4 %files relay %{_prefix}/sbin/dhcrelay %{_prefix}/man/cat1m/dhcrelay.1m %changelog * Fri Oct 1 1999 Brian J. Murrell - write a spec file for dhcpd dhcp-4.2.4/contrib/ldap/000777 000765 000024 00000000000 11757514243 014764 5ustar00sarstaff000000 000000 dhcp-4.2.4/contrib/ms2isc/000777 000765 000024 00000000000 11757514243 015244 5ustar00sarstaff000000 000000 dhcp-4.2.4/contrib/sethostname.sh000644 000765 000024 00000001603 06776230707 016733 0ustar00sarstaff000000 000000 #!/bin/sh # This script can be installed in /etc/dhclient-enter-hooks to set the client's # hostname based either on the hostname that the DHCP server supplied or the # hostname in whatever ptr record exists for the assigned IP address. if [ x$new_host_name = x ]; then ptrname=`echo $new_ip_address \ |sed -e \ 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\4.\3.\2.\1.in-addr.arpa/'` (echo "set type=ptr"; echo "$ptrname") |nslookup >/tmp/nslookup.$$ set `sed -n -e "s/$ptrname[ ]*\(canonical \)*name *= *\(.*\)/\2 \1/p" \ < /tmp/nslookup.$$` _ if [ x$1 = x_ ]; then new_host_name="" else if [ $# -gt 1 ] && [ x$2 = xcanonical ]; then new_host_name=`sed -n -e "s/$1[ ]*name *= *\(.*\)/\1/p" \ -o [-p [-k ]] [-f ] Server IP or name for NT4 DHCP server to fetch the configuration from. Output filename for the configuration file. Primary DNS server name for sending the dynamic DNS update to. Key name for use in updating the dynamic DNS zone. Failover peer name shared with the DHCP partner. Essentially the needs to be an NT4 (3.x should work but not tested) which you should have registry read access to. You must run this script from a Windows machine because of the requirement to access the registry. The is optional parameter for desginating the dynamic DNS update if missing then the "zone" section of the declaration will be skipped. The is needed if you've configured your DNS zone with a key, in addition, you'll need to define that key in this DHCP configuration file elsewhere manually, read the DHCP Handbook to figure out what you need to define. The specifies the fail-over peer name in the pool section, you'll need to define additional detail elsewhere manually, again read the DHCP handbook. NOTE: the program only knows of the following global and subnet options: 3, 6, 15, 28, 44, and 46 If it runs into options other than the known ones, it will quit. You may fix this by modifying the following procedures: GetGlobalOptions GetScopes PrintSubnetConfig In addition, the resulting subnets configuration will have the "deny dynamic bootp clients" you should take them out if that's not what you want :). Finally, as the parameter structures implied, it is assumed that you want the same zone primary and update key for all zones and that the same failover is to be applied to all the pools. Furthermore the subnet zones are all assumed to be class C delineated, but if you happend to be delegated at the class B level, this will work fine too. Author: Shu-Min Chang Copyright: Please read the top of the source code Acknowledgement: Brian L. King for coding help, Douglas A. Darrah for testing, and James E. Pressley for being the DHCP reference book :). Usage: $ARGV -s -o [-p [-k ]] [-f ] Version: 1.0.1 ENDOFHELP ###################### Begin Main Program #################################### my (%opts, %GlobalOptions, %SuperScopes, %Scopes); ### Get parameters and make sure that they meet the require/optoinal criteria getopts('s:o:p:k:f:', \%opts) or die $usage; ($opts{s} and $opts{o}) or die $usage; if ($opts{k}) { $opts{p} or die $usage; } ### Read all the registry stuff into the memory %GlobalOptions = GetGlobalOptions($opts{s}); %SuperScopes = GetSuperScope($opts{s}); %Scopes = GetScopes ($opts{s}); ### Process and print out to the output file my ($outfile, $i, $j, @Domains); $outfile = new FileHandle "> $opts{o}"; if (!defined $outfile) { die "Can't open file: $opts{o}: $!"; } for $i (keys %SuperScopes) { print $outfile "\n##############################################################\n"; my ($Scopename) = $i; $Scopename =~ s/ //g; print $outfile "shared-network $Scopename {\n"; foreach $j (@{$SuperScopes{$i}}) { PrintSubnetConfig($outfile, \%GlobalOptions, \%{$Scopes{$j}}, $j, "\t", $opts{f}); InsertIfUnique (\@Domains, $Scopes{$j}{domain}) if exists $Scopes{$j}{domain}; delete $Scopes{$j}; } print $outfile "}\n"; if ($opts{p} or $opts{k}) { foreach $j (@{$SuperScopes{$i}}) { PrintSubnetUpdate($outfile, $j, $opts{p}, $opts{k}); } } } for $i (keys %Scopes) { print $outfile "\n##############################################################\n"; PrintSubnetConfig($outfile, \%GlobalOptions, \%{$Scopes{$i}}, $i, "", $opts{f}); if ($opts{p} or $opts{k}) { PrintSubnetUpdate($outfile, $i, $opts{p}, $opts{k}); } InsertIfUnique (\@Domains, $Scopes{$i}{domain}) if exists $Scopes{$i}{domain}; } if ($opts{p} or $opts{k}) { InsertIfUnique (\@Domains, $GlobalOptions{domain}) if exists $GlobalOptions{domain}; for $i (@Domains) { PrintDomainUpdate($outfile, $i, $opts{p}, $opts{k}); } } undef ($outfile); print "Done.\n"; exit(); ################################## End Main Program ########################### ###################################################################### sub InsertIfUnique ($$) { my ($Array, $data) = @_; # purpose: insert $data into array @{$Array} iff the data is not in there yet # input: # $data: scalar data to be added to the @{$Array} if unique # $Array: reference of the Array to compare the uniqueness of the $data # output: # $Array: reference of the array with the resulting array. # return: none my ($i); for ($i=0; $i<=$#{$Array} && ${$Array}[$i] ne $data; $i++) { } if ($i > $#{$Array}) { ${$Array}[$i] = $data; } } ###################################################################### sub PrintDomainUpdate ($$$$) { my ($outfile, $Domain, $DDNSServer, $key) = @_; # purpose: print out the foward domain zone update declaration # input: # $outfile: filehandle of the file to write the output to # $Domain: a string representing the forward domain # $DDNSServer: a string of the DNS server accepting the DDNS update # $key: a string representing the key used to update the zone # output: none # return: none # print $outfile "zone $Domain {\n"; print $outfile "\tprimary $DDNSServer;\n"; !$key or print $outfile "\tkey $key;\n"; print $outfile "}\n"; } ###################################################################### sub PrintSubnetUpdate ($$$$) { my ($outfile, $Subnet, $DDNSServer, $key) = @_; # purpose: print out the reverse domain zone update declaration # input: # $outfile: filehandle of the file to write the output to # $Subnet: a string representing the subnet in the form 1.2.3.4 # $DDNSServer: a string of the DNS server accepting the DDNS update # $key: a string representing the key used to update the zone # output: none # return: none # my ($Reverse); $_ = join (".", reverse(split(/\./, $Subnet))); m/\d*\.(.*)/; $Reverse = $1; print $outfile "zone $Reverse.in-addr.arpa. {\n"; print $outfile "\tprimary $DDNSServer;\n"; !$key or print $outfile "\tkey $key;\n"; print $outfile "}\n"; } ###################################################################### sub PrintSubnetConfig ($$$$$$) { my ($outfile, $GlobalOptions, $Scope, $Subnet, $prefix, $failover) = @_; # purpose: print out the effective scope configuration for one subnet as # derived from the global and scope options. # input: # $outfile: filehandle of the file to write the output to # $GlobalOptions: refernce to the hashed variable from GetGlobalOptions # $Scopes: reference to the hashed variable of the subnet in interest # $Subnet: string variable of the subnet being processed # $prefix: string to be printed before each line (designed for tab) # $failover: string to be used for the "failover peer" line # output: none # return: none # my ($pound) = ( ${$Scope}{disable}? "#".$prefix : $prefix); print $outfile $pound, "subnet $Subnet netmask ${$Scope}{mask} {\n"; print $outfile "$prefix# Name: ${$Scope}{name}\n"; print $outfile "$prefix# Comment: ${$Scope}{comment}\n"; if (exists ${$Scope}{routers}) { print $outfile $pound, "\toption routers @{${$Scope}{routers}};\n"; } elsif (exists ${$GlobalOptions}{routers}) { print $outfile $pound, "\toption routers @{${$GlobalOptions}{routers}};\t# NOTE: obtained from global option, bad practice detected\n"; } else { print $outfile "### WARNING: No router was found for this subnet!!! ##########\n"; } if (exists ${$Scope}{dnses}) { print $outfile $pound, "\toption domain-name-servers ", join(",", @{${$Scope}{dnses}}), ";\n"; } elsif (exists ${$GlobalOptions}{dnses}) { print $outfile $pound, "\toption domain-name-servers ", join(",", @{${$GlobalOptions}{dnses}}), ";\n"; } if (exists ${$Scope}{domain}) { print $outfile $pound, "\toption domain-name \"${$Scope}{domain}\";\n"; } elsif (exists ${$GlobalOptions}{domain}) { print $outfile $pound, "\toption domain-name \"${$GlobalOptions}{domain}\";\n"; } if (exists ${$Scope}{broadcast}) { print $outfile $pound, "\toption broadcast-address ${$Scope}{broadcast};\n"; } elsif (exists ${$GlobalOptions}{broadcast}) { print $outfile $pound, "\toption broadcast-address ${$GlobalOptions}{broadcast};\n"; } if (exists ${$Scope}{winses}) { print $outfile $pound, "\toption netbios-name-servers ", join(",", @{${$Scope}{winses}}), ";\n"; } elsif (exists ${$GlobalOptions}{winses}) { print $outfile $pound, "\toption netbios-name-servers ", join(",", @{${$GlobalOptions}{winses}}), ";\n"; } if (exists ${$Scope}{winstype}) { print $outfile $pound, "\toption netbios-node-type ${$Scope}{winstype};\n"; } elsif (exists ${$GlobalOptions}{winstype}) { print $outfile $pound, "\toption netbios-node-type ${$GlobalOptions}{winstype};\n" } print $outfile $pound, "\tdefault-lease-time ${$Scope}{leaseduration};\n"; print $outfile $pound, "\tpool {\n"; for (my $r=0; $r<=$#{${$Scope}{ranges}}; $r+=2) { print $outfile $pound, "\t\trange ${$Scope}{ranges}[$r] ${$Scope}{ranges}[$r+1];\n"; } !$failover or print $outfile $pound, "\t\tfailover peer \"$failover\";\n"; print $outfile $pound, "\t\tdeny dynamic bootp clients;\n"; print $outfile $pound, "\t}\n"; print $outfile $pound, "}\n"; } ###################################################################### sub GetScopes ($) { my ($Server) = @_; my (%Scopes); # purpose: to return NT4 server's scope configuration # input: # $Server: string of the valid IP or name of the NT4 server # output: none # return: # %Scope: hash of hash of hash of various data types to be returned of the # following data structure # $Scope{}{disable} => boolean # $Scope{}{mask} => string (e.g. "1.2.3.255") # $Scope{}{name} => string (e.g "Office Subnet #1") # $Scope{}{comment} => string (e.g. "This is a funny subnet") # $Scope{}{ranges} => array of paired inclusion IP addresses # (e.g. "1.2.3.1 1.2.3.10 1.2.3.100 10.2.3.200 # says that we have 2 inclusion ranges of # 1-10 and 100-200) # $Scopes{}{routers} => array of IP address strings # $Scopes{}{dnses} => array of IP address/name string # $Scopes{}{domain} > string # $Scopes{}{broadcast} => string # $Scopes{}{winses} => array of IP addresses/name string # $Scopes{}{winstype} => integer # $Scopes{}{leaseduration} => integer my ($RegVal, @Subnets, @Router, $SubnetName, $SubnetComment, @SubnetOptions, @SRouter, @SDNSServers, @SDomainname, @SWINSservers, @SNetBIOS, @SLeaseDuration, @SSubnetState, @SExclusionRanges, @SSubnetAddress, @SSubnetMask, @SFirstAddress, $SStartAddress, $SEndAddress, @InclusionRanges, @SBroadcastAddress); print "Getting list of subnets\n"; if (Registry::GetRegSubkeyList ("\\\\$Server\\HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\DHCPServer\\Configuration\\Subnets", \@Subnets)) { die "Unable to obtain a list of subnets from the server!\n"; } for (my $i=0; $i<=$#Subnets; $i++) { print "\t Fetching Subnet $Subnets[$i] (",$i+1, "/", $#Subnets+1, "): "; print "."; if (!Registry::GetRegSubkeyList ("\\\\$Server\\HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\DHCPServer\\Configuration\\Subnets\\$Subnets[$i]\\IpRanges", \@SFirstAddress)) { # Don't know why MS has a tree for this, but as far # as I can tell, only one subtree will ever come out of # this, so I'm skipping the 'for' loop print "."; if (!Registry::GetRegKeyVal ("\\\\$Server\\HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\DHCPServer\\Configuration\\Subnets\\$Subnets[$i]\\IpRanges\\$SFirstAddress[0]\\StartAddress", \$RegVal)) { $SStartAddress = $RegVal; } print "."; if (!Registry::GetRegKeyVal ("\\\\$Server\\HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\DHCPServer\\Configuration\\Subnets\\$Subnets[$i]\\IpRanges\\$SFirstAddress[0]\\EndAddress", \$RegVal)) { $SEndAddress = $RegVal; } # print "\n\tInclusion Range: ", Registry::ExtractIp($SStartAddress), " - ", Registry::ExtractIp($SEndAddress),"\n"; } else { die "\n\n# Error Getting Inclusion Range FirstAddress!!!\n\n"; } if (!Registry::GetRegKeyVal ("\\\\$Server\\HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\DHCPServer\\Configuration\\Subnets\\$Subnets[$i]\\ExcludedIpRanges", \$RegVal)) { @SExclusionRanges = Registry::ExtractExclusionRanges($RegVal); # for (my $j=2; $j<=$#SExclusionRanges; $j+=2) { # if (unpack("L",$SExclusionRanges[$j]) < unpack("L",$SExclusionRanges[$j-2])) { # print ("\n******** Subnet exclusion ranges out of order ********\n"); # } # } @SExclusionRanges = sort(@SExclusionRanges); # print "\n\tExclusion Ranges: "; # for (my $j=0; $j<=$#SExclusionRanges; $j+=2) { # print "\n\t\t",Registry::ExtractIp($SExclusionRanges[$j])," - ",Registry::ExtractIp($SExclusionRanges[$j+1]); # } } @InclusionRanges = FindInclusionRanges ($SStartAddress, $SEndAddress, @SExclusionRanges); print "."; if (!Registry::GetRegKeyVal ("\\\\$Server\\HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\DHCPServer\\Configuration\\Subnets\\$Subnets[$i]\\SubnetName", \$RegVal)) { $SubnetName = $RegVal; # print "\n\tSubnetName: $SubnetName"; } print "."; if (!Registry::GetRegKeyVal ("\\\\$Server\\HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\DHCPServer\\Configuration\\Subnets\\$Subnets[$i]\\SubnetComment", \$RegVal)) { $SubnetComment = $RegVal; # print "\n\tSubnetComment: $SubnetComment"; } print "."; if (!Registry::GetRegKeyVal ("\\\\$Server\\HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\DHCPServer\\Configuration\\Subnets\\$Subnets[$i]\\SubnetAddress", \$RegVal)) { @SSubnetAddress = Registry::ExtractIp($RegVal); # print "\n\tSubnetAddress: $SSubnetAddress[0]"; } print "."; if (!Registry::GetRegKeyVal ("\\\\$Server\\HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\DHCPServer\\Configuration\\Subnets\\$Subnets[$i]\\SubnetMask", \$RegVal)) { @SSubnetMask = Registry::ExtractIp($RegVal); # print "\n\tSubnetMask: $SSubnetMask[0]"; } print "."; if (!Registry::GetRegKeyVal ("\\\\$Server\\HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\DHCPServer\\Configuration\\Subnets\\$Subnets[$i]\\SubnetState", \$RegVal)) { @SSubnetState = Registry::ExtractHex ($RegVal); # print "\n\tSubnetState = $SSubnetState[0]"; } $Scopes{$Subnets[$i]}{disable} = hex($SSubnetState[0]) ? 1 : 0; $Scopes{$Subnets[$i]}{mask} = $SSubnetMask[0]; $Scopes{$Subnets[$i]}{name} = $SubnetName; $Scopes{$Subnets[$i]}{comment} = $SubnetComment; for (my $r=0; $r<=$#InclusionRanges; $r++) { $Scopes{$Subnets[$i]}{ranges}[$r] = Registry::ExtractIp($InclusionRanges[$r]); } ################## Get scope options my (@SubnetOptionsList); print "\n\t\tOptions:"; if (Registry::GetRegSubkeyList ("\\\\$Server\\HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\DHCPServer\\Configuration\\Subnets\\$Subnets[$i]\\SubnetOptions", \@SubnetOptionsList)) { die "Unable to get subnet options list for $Subnets[$i]!\n"; } for (my $j=0; $j<=$#SubnetOptionsList; $j++) { print "."; if (!Registry::GetRegKeyVal ("\\\\$Server\\HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\DHCPServer\\Configuration\\Subnets\\$Subnets[$i]\\SubnetOptions\\$SubnetOptionsList[$j]\\OptionValue", \$RegVal)) { for ($SubnetOptionsList[$j]) { /003/ and do { # @SRouter = Registry::ExtractOptionIps($RegVal); $Scopes{$Subnets[$i]}{routers} = [Registry::ExtractOptionIps($RegVal)]; last; }; /006/ and do { @SDNSServers = Registry::ExtractOptionIps($RegVal); for (my $d=0; $d<=$#SDNSServers; $d++) { my ($ipname, $rest) = gethostbyaddr(pack("C4", split(/\./, $SDNSServers[$d])), &AF_INET); $Scopes{$Subnets[$i]}{dnses}[$d] = $ipname ? $ipname : $SDNSServers[$d]; } last; }; /015/ and do { @SDomainname = Registry::ExtractOptionStrings($RegVal); $Scopes{$Subnets[$i]}{domain} = $SDomainname[0]; last; }; /028/ and do { @SBroadcastAddress = Registry::ExtractOptionIps($RegVal); $Scopes{$Subnets[$i]}{broadcast} = $SBroadcastAddress[0]; last; }; /044/ and do { @SWINSservers = Registry::ExtractOptionIps($RegVal); for (my $w=0; $w<=$#SWINSservers; $w++) { my ($ipname, $rest) = gethostbyaddr(pack("C4", split(/\./, $SWINSservers[$w])), &AF_INET); $Scopes{$Subnets[$i]}{winses}[$w] = $ipname ? $ipname : $SWINSservers[$w]; } last; }; /046/ and do { @SNetBIOS = Registry::ExtractOptionHex($RegVal); $Scopes{$Subnets[$i]}{winstype} = hex($SNetBIOS[0]); last; }; /051/ and do { @SLeaseDuration = Registry::ExtractOptionHex($RegVal); $Scopes{$Subnets[$i]}{leaseduration} = hex($SLeaseDuration[0]); last; }; die "This program does not recognize subnet option \#$SubnetOptionsList[$j] yet!\n" } } else { die "Unable to obtain option SubnetOptionsList[$j] from $Subnets[$i], most likely a registry problem!\n" } } print "\n"; } return %Scopes; } ###################################################################### sub FindInclusionRanges ($$@) { my ($StartAddress, $EndAddress, @ExclusionRanges) = @_; # Purpose: to calculate and return the DHCP inclusion ranges out of # data provided by the NT4 DHCP server # input: $StartAddress: # $EndAddress: # @ExclusionRanges # output: none # return: An arry of IP address pair representing the inclusion ranges # in the native registry format. # my ($SA, $EA, @ER); $SA = unpack("L", $StartAddress); $EA = unpack("L", $EndAddress); @ER = @ExclusionRanges; for (my $i=0; $i<=$#ER; $i++) { $ER[$i] = unpack ("L", $ER[$i]); } my @InclusionRanges; $InclusionRanges[0] = $SA; $InclusionRanges[1] = $EA; for (my $i=0; $i<=$#ER; $i+=2) { if ($ER[$i] == $InclusionRanges[$#InclusionRanges-1]) { $InclusionRanges[$#InclusionRanges-1] = $ER[$i+1] + 1; } if ($ER[$i] > $InclusionRanges[$#InclusionRanges-1]) { $InclusionRanges[$#InclusionRanges] = $ER[$i]-1; } if (($ER[$i+1] > $InclusionRanges[$#InclusionRanges]) && ($ER[$i+1] != $EA)) { $InclusionRanges[$#InclusionRanges+1] = $ER[$i+1] + 1; $InclusionRanges[$#InclusionRanges+1] = $EA; } if ($InclusionRanges[$#InclusionRanges] < $InclusionRanges[$#InclusionRanges-1]) { $#InclusionRanges -= 2; } } for (my $i=0; $i<=$#InclusionRanges; $i++) { $InclusionRanges[$i] = pack("L", $InclusionRanges[$i]); # print "Inclusion: ", Registry::ExtractIp($InclusionRanges[$i]), "\n"; } return @InclusionRanges; } #################################################################### sub GetSuperScope ($) { my ($Server) = @_; my (%SuperScopes); # # purpose: gets the Superscope list from the given server # input: # $Server: string of the valid IP address or name of the NT4 server # ouput: none # return: # %SuperScopes: hash of array subnets with the following data structure # $SuperScopes{} => array of sunbets # my (@SuperScopeNames, @SCSubnetList); print "Getting Superscope list: "; if (!Registry::GetRegSubkeyList ("\\\\$Server\\HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\DHCPServer\\Configuration\\SuperScope", \@SuperScopeNames)) { for (my $i=0; $i<=$#SuperScopeNames; $i++) { print "."; if (!Registry::GetRegSubkeyList ("\\\\$Server\\HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\DHCPServer\\Configuration\\SuperScope\\$SuperScopeNames[$i]", \@SCSubnetList)) { $SuperScopes{$SuperScopeNames[$i]} = [@SCSubnetList]; } } print "\n"; } return %SuperScopes; } #################################################################### sub GetGlobalOptions($) { my ($Server) = @_; my (%GlobalOptions); # purpose: to return NT4 server's global scope configuration # input: # $Server: string of the valid IP or name of the NT4 server # output: none # return: # %GlobalOptions: hash of hash of various data types to be returned of the # following data structure # $GlobalOptions{routers} => array of IP address strings # $GlobalOptions{dnses} => array of IP address/name string # $GlobalOptions{domain} > string # $GlobalOptions{broadcast} => string # $GlobalOptions{winses} => array of IP addresses/name string # $GlobalOptions{winstype} => integer my ($RegVal, @temp, @GlobalOptionValues); print "Getting Global Options: "; if (Registry::GetRegSubkeyList ("\\\\$Server\\HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\DHCPServer\\Configuration\\GlobalOptionValues", \@GlobalOptionValues)) { die "Unable to obtain GlobalOptionValues"; } for (my $i=0; $i<=$#GlobalOptionValues; $i++) { print "."; if (Registry::GetRegKeyVal ("\\\\$Server\\HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\DHCPServer\\configuration\\globaloptionvalues\\$GlobalOptionValues[$i]\\optionvalue", \$RegVal)) { die "Unable to retrive global option $GlobalOptionValues[$i]\n"; } for ($GlobalOptionValues[$i]) { /003/ and do { @temp=Registry::ExtractOptionIps($RegVal); $GlobalOptions{routers} = [@temp]; last; }; /006/ and do { # DNS Servers @temp = Registry::ExtractOptionIps($RegVal); for (my $d=0; $d<=$#temp; $d++) { my ($ipname, $rest) = gethostbyaddr(pack("C4", split(/\./, $temp[$d])), &AF_INET); $GlobalOptions{dnses}[$d] = $ipname ? $ipname : $temp[$d]; } last; }; /015/ and do { # Domain Name @temp = Registry::ExtractOptionStrings($RegVal); $GlobalOptions{domain} = $temp[0]; last; }; /028/ and do { # broadcast address @temp = Registry::ExtractOptionIps($RegVal); $GlobalOptions{broadcast} = $temp[0]; last; }; /044/ and do { # WINS Servers @temp = Registry::ExtractOptionIps ($RegVal); $GlobalOptions{winses} = [@temp]; for (my $w=0; $w<=$#temp; $w++) { my ($ipname, $rest) = gethostbyaddr(pack("C4", split(/\./, $temp[$w])), &AF_INET); $GlobalOptions{winses}[$w] = $ipname ? $ipname : $temp[$w]; } last; }; /046/ and do { # NETBIOS node type @temp = Registry::ExtractOptionHex($RegVal); $GlobalOptions{winstype} = hex($temp[0]); last; }; die "This program does not recgonize global option \#$GlobalOptionValues[$i] yet!\n" } } print "\n"; return %GlobalOptions; } dhcp-4.2.4/contrib/ms2isc/readme.txt000644 000765 000024 00000001015 10216364361 017224 0ustar00sarstaff000000 000000 Copyright: please read the top of the source code. Usage: Objective: please read the help screen by executing the program without any parameter. Revision: SMC: Shu-Min Chang Who When What --- ------ -------------------------------------------------------------------- SMC 021107 Initial release Version 1.0 to ISC DHCP repository SMC 030129 Fixed inclusion range calculation by sorting exclusion before passing to FindInclusionRanges SMC 030228 release 1.0.1 to ISC DHCP repository dhcp-4.2.4/contrib/ms2isc/Registry.pm000644 000765 000024 00000030040 10216364361 017374 0ustar00sarstaff000000 000000 # Registry.pm # A perl module provided easy Windows Registry access # # Author: Shu-Min Chang # # Copyright(c) 2002 Intel Corporation. All rights reserved # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, # this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright notice # this list of conditions and the following disclaimer in the documentation # and/or other materials provided with the distribution # 3. Neither the name of Intel Corporation nor the names of its contributors # may be used to endorse or promote products derived from this software # without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE INTEL CORPORATION AND CONTRIBUTORS "AS IS" # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE INTEL CORPORATION OR CONTRIBUTORS BE # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL EXEMPLARY, OR # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO PROCUREMENT OF SUBSTITUE # GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT # OF THE USE OF THIS SOFTWARE, EVEN IF ADVICED OF THE POSSIBILITY OF SUCH # DAMAGE. package Registry; use strict; use Win32API::Registry 0.21 qw( :ALL ); ############################################################################### #----------------------------------------- sub GetRegKeyVal($*) { my ($FullRegPath, $value) = @_; #----------------------------------------- # Purpose: uses Win32API to get registry information from a given server # # WARNING: this procedure is VERY Win32 specific, you'll need a Win32 manual # to figure out why something is done. # input: $FullRegPath: a MS specific way of fully qualifying a registry path # \\Server\RootKey\Path\ValueName # output: *value: the value of the registry key of $FullRegPath # my ($RemoteMachine, $RootKey, $RegPath, $KeyName, $i); #print "in sub:GetRegKeyVal:Parameters:", @_, "\n"; # Check the for valid fully qualified registry path return -1 if (! ($FullRegPath =~ /\\.+\\.+/)) && (!($FullRegPath =~ /\\\\.+\\.+\\.+/)); $RemoteMachine = (index($FullRegPath, "\\\\") == $[ ? substr($FullRegPath, $[+2, index($FullRegPath, "\\", $[+2)-2):0); #print "RemoteMachine = $RemoteMachine\n"; $i = $RemoteMachine ? $[+3+length($RemoteMachine) : $[+1; $RootKey = substr ($FullRegPath, $i, index($FullRegPath, "\\", $i)-$i); $KeyName = $FullRegPath; $KeyName =~ s/.*\\(.+)/$1/; #print "KeyName = $KeyName\n"; $i = index($FullRegPath, $RootKey, $[+length($RemoteMachine)) + $[ + length($RootKey)+1; $RegPath = substr ($FullRegPath, $i, length($FullRegPath) - length($KeyName) -$i - 1); #print "RegPath = $RegPath\n"; my ($RootKeyHandle, $handle, $key, $type); if ($RemoteMachine) { $RootKeyHandle = regConstant($RootKey); if (!RegConnectRegistry ($RemoteMachine, $RootKeyHandle, $handle)) { $$value = regLastError(); return -2; } } else { # not valid actually because I can't find the mapping table of default # local handle mapping. Should always pass in the Machine name to use for now $handle = $RootKey; } if (!RegOpenKeyEx ($handle, $RegPath, 0, KEY_READ, $key)) { $$value = regLastError(); #print "regLastError = $$value\n"; return -3; } if (!RegQueryValueEx( $key, $KeyName, [], $type, $$value, [] )) { $$value = regLastError(); #print "regLastError = $$value\n"; return -4; } #print "RegType=$type\n"; # Perl doesn't fetch type, at this in this # ActiveState 5.6.0 that I'm using #print "RegValue=$$value\n"; RegCloseKey ($key); RegCloseKey ($handle); return 0; } ############################################################################### #----------------------------------------- sub GetRegSubkeyList($*) { my ($FullKeyRegPath, $Subkeys) = @_; #----------------------------------------- # Purpose: uses Win32API to get registry subkey list from a given server # # WARNING: this procedure is VERY Win32 specific, you'll need a Win32 manual # to figure out why something is done. # input: $FullKeyRegPath: a MS specific way of fully qualifying a registry path # \\Server\RootKey\Path\KeyName # output: *Subkeys: the list of subkeys in array of the registry key of # $FullKeyRegPath # my ($RemoteMachine, $RootKey, $RegPath, $KeyName, $i); #print "in sub:GetRegSubkeyList:Parameters:", @_, "\n"; # Check the for valid registry key path return -1 if (! ($FullKeyRegPath =~ /\\.+\\.+/)) && (!($FullKeyRegPath =~ /\\\\.+\\.+\\.+/)); $RemoteMachine = (index($FullKeyRegPath, "\\\\") == $[ ? substr($FullKeyRegPath, $[+2, index($FullKeyRegPath, "\\", $[+2)-2):0); #print "RemoteMachine = $RemoteMachine\n"; $i = $RemoteMachine ? $[+3+length($RemoteMachine) : $[+1; $RootKey = substr ($FullKeyRegPath, $i, index($FullKeyRegPath, "\\", $i)-$i); $i = index($FullKeyRegPath, $RootKey, $[+length($RemoteMachine)) + $[ + length($RootKey)+1; $RegPath = substr ($FullKeyRegPath, $i); #print "RegPath = $RegPath\n"; my ($RootKeyHandle, $handle, $key, $type); if ($RemoteMachine) { $RootKeyHandle = regConstant($RootKey); if (!RegConnectRegistry ($RemoteMachine, $RootKeyHandle, $handle)) { @$Subkeys[0]= regLastError(); return -2; } } else { # not valid actually because I can't find the mapping table of default # local handle mapping. Should always pass in the Machine name to use for now $handle = $RootKey; } if (!RegOpenKeyEx ($handle, $RegPath, 0, KEY_READ, $key)) { @$Subkeys[0] = regLastError(); #print "regLastError = @$Subkeys[0]\n"; return -3; } my $tmp; # For some reason, the regLastError() stays at ERROR_NO_MORE_ITEMS # in occasional call sequence, so I'm resetting the error code # before entering the loop regLastError(0); for ($i=0; regLastError()==regConstant("ERROR_NO_MORE_ITEMS"); $i++) { #print "\nERROR: error enumumerating reg\n"; if (RegEnumKeyEx ($key, $i, $tmp, [], [], [], [], [])) { @$Subkeys[$i] = $tmp; } } #print "RegType=$type\n"; #print "RegValue=@$Subkeys\n"; RegCloseKey ($key); RegCloseKey ($handle); return 0; } ##################################################### sub ExtractOptionIps ($) { my ($MSDHCPOption6Value) = @_; my @ip; # purpose: DHCP registry specific; to return the extracted IP addresses from # the input variable # input: # $MSDHCPOption6Value: Option 6 was used to develop, but it works for any # other options of the same datatype. # output: none # return: # @ip: an arry of IP addresses in human readable format. # First extract the size of the option my ($byte, $size, $ind1, $ind2, @octet) = unpack("VVVV", $MSDHCPOption6Value); # print "byte = $byte\nsize=$size\nind1=$ind1\nind2=$ind2\n"; # Calculate total number of bytes that IP addresses occupy my $number = $size * $ind1; ($byte, $size, $ind1, $ind2, @octet) = unpack("VVVVC$number", $MSDHCPOption6Value); for (my $i=0; $i<$#octet; $i=$i+4) { $ip[$i/4] = "$octet[$i+3]\.$octet[$i+2]\.$octet[$i+1]\.$octet[$i]"; } return @ip; } ##################################################### sub ExtractOptionStrings ($) { my ($MSDHCPOption15Value) = @_; my @string; # purpose: DHCP registry specific; to return the extracted string from # the input variable # input: # $MSDHCPOption15Value: Option 15 was used to develop, but it works for any # other options of the same datatype. # output: none # return: # @string: an arry of strings in human readable format. # First extract the size of the option my ($byte, $start, $ind1, $ind2, $size, @data) = unpack("VVVVV", $MSDHCPOption15Value); # print "byte = $byte\nstart=$start\nind1=$ind1\nind2=$ind2\nsize=$size\n"; # Calculate total number of bytes that IP addresses occupy my $number = $size * $ind1; ($byte, $start, $ind1, $ind2, $size, @data) = unpack("VVVVVC$number", $MSDHCPOption15Value); for (my $i=0; $i<$ind1; $i++) { # actually this is only programmed to do one string, until I see # example of how the multiple strings are represented, I don't have a # guess to how to program them properly. for (my $j=0; $j<$#data & $data[$j]!=0; $j+=2) { $string[$i] = $string[$i].chr($data[$j]); } } return @string; } ##################################################### sub ExtractOptionHex ($) { my ($MSDHCPOption46Value) = @_; my @Hex; # purpose: DHCP registry specific; to return the extracted hex from the input # variable # input: # $MSDHCPOption46Value: Option 46 was used to develop, but it works for any # other options of the same datatype. # output: none # return: # @Hex: an arry of hex strings in human readable format. my $Temp; # First extract the size of the option my ($byte, $unknown, $ind1, $ind2, @data) = unpack("VVVV", $MSDHCPOption46Value); # print "byte=$byte\nunknown=$unknown\nind1=$ind1\nind2=$ind2\n"; # Calculate total number of bytes that IP addresses occupy my $number = $byte - 15; ($byte, $unknown, $ind1, $ind2, @data) = unpack("VVVVC$number", $MSDHCPOption46Value); # printf "data=%4x\n", $data[0]; for (my $i=0; $i<$ind1; $i++) { # actually this is only programmed to do one Hex, until I see # example of how the multiple Hexes are represented, I don't have a # guess to how to program them properly. for (my $j=3; $j>=0; $j--) { $Hex[$i] = $Hex[$i].sprintf ("%x", $data[$j+$i*4]); } } return @Hex; } ##################################################### sub ExtractExclusionRanges ($) { my ($MSDHCPExclusionRanges) = @_; my @RangeList; # purpose: DHCP registry specific; to return the extracted exclusion ranges # from the input variable # input: # $MSDHCPExclusionRanges: Exclusion range as DHCP server returns them # output: none # return: # @RangeList: an arry of paird IP addresses strings in human readable format. # First extract the size of the option my ($paircount, @data) = unpack("V", $MSDHCPExclusionRanges); # print "paircount = $paircount\n"; # Calculate total number of bytes that IP addresses occupy # my $number = $paircount * 4*2; # ($paircount, @data) = unpack("VC$number", $MSDHCPExclusionRanges); # # for (my $i=0; $i<$#data; $i=$i+4) { # $ip[$i/4] = "$data[$i+3]\.$data[$i+2]\.$data[$i+1]\.$data[$i]"; # } # my $number = $paircount * 2; ($paircount, @data) = unpack("VL$number", $MSDHCPExclusionRanges); for (my $i=0; $i<=$#data; $i++) { $RangeList[$i] = pack ("L", $data[$i]); # print "extracted", ExtractIp ($RangeList[$i]), "\n"; } return @RangeList; } ##################################################### sub ExtractIp ($) { my ($octet) = @_; # purpose: to return the registry saved IP address in a readable form # input: # $octet: a 4 byte data storing the IP address as the registry save it as # output: none # return: anonymous variable of a string of IP address my (@data) = unpack ("C4", $octet); return "$data[3]\.$data[2]\.$data[1]\.$data[0]"; } ##################################################### sub ExtractHex ($) { my ($HexVal) = @_; my @Hex; # purpose: to return the registry saved hex number in a readable form # input: # $octet: a 4 byte data storing the hex number as the registry save it as # output: none # return: # $Hex: string of hex digit # First extract the size of the option my (@data) = unpack("C4", $HexVal); for (my $i=3; $i>=0; $i--) { $Hex[0] = $Hex[0] . sprintf ("%x", $data[$i]); } return @Hex; } 1; dhcp-4.2.4/contrib/ldap/dhcp.schema000644 000765 000024 00000051752 11352700324 017056 0ustar00sarstaff000000 000000 attributetype ( 2.16.840.1.113719.1.203.4.1 NAME 'dhcpPrimaryDN' EQUALITY distinguishedNameMatch DESC 'The DN of the dhcpServer which is the primary server for the configuration.' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 SINGLE-VALUE ) attributetype ( 2.16.840.1.113719.1.203.4.2 NAME 'dhcpSecondaryDN' EQUALITY distinguishedNameMatch DESC 'The DN of dhcpServer(s) which provide backup service for the configuration.' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 ) attributetype ( 2.16.840.1.113719.1.203.4.3 NAME 'dhcpStatements' EQUALITY caseIgnoreIA5Match DESC 'Flexible storage for specific data depending on what object this exists in. Like conditional statements, server parameters, etc. This allows the standard to evolve without needing to adjust the schema.' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) attributetype ( 2.16.840.1.113719.1.203.4.4 NAME 'dhcpRange' EQUALITY caseIgnoreIA5Match DESC 'The starting & ending IP Addresses in the range (inclusive), separated by a hyphen; if the range only contains one address, then just the address can be specified with no hyphen. Each range is defined as a separate value.' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) attributetype ( 2.16.840.1.113719.1.203.4.5 NAME 'dhcpPermitList' EQUALITY caseIgnoreIA5Match DESC 'This attribute contains the permit lists associated with a pool. Each permit list is defined as a separate value.' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) attributetype ( 2.16.840.1.113719.1.203.4.6 NAME 'dhcpNetMask' EQUALITY integerMatch DESC 'The subnet mask length for the subnet. The mask can be easily computed from this length.' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) attributetype ( 2.16.840.1.113719.1.203.4.7 NAME 'dhcpOption' EQUALITY caseIgnoreIA5Match DESC 'Encoded option values to be sent to clients. Each value represents a single option and contains (OptionTag, Length, OptionValue) encoded in the format used by DHCP.' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) attributetype ( 2.16.840.1.113719.1.203.4.8 NAME 'dhcpClassData' EQUALITY caseIgnoreIA5Match DESC 'Encoded text string or list of bytes expressed in hexadecimal, separated by colons. Clients match subclasses based on matching the class data with the results of match or spawn with statements in the class name declarations.' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE ) attributetype ( 2.16.840.1.113719.1.203.4.9 NAME 'dhcpOptionsDN' EQUALITY distinguishedNameMatch DESC 'The distinguished name(s) of the dhcpOption objects containing the configuration options provided by the server.' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 ) attributetype ( 2.16.840.1.113719.1.203.4.10 NAME 'dhcpHostDN' EQUALITY distinguishedNameMatch DESC 'the distinguished name(s) of the dhcpHost objects.' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 ) attributetype ( 2.16.840.1.113719.1.203.4.11 NAME 'dhcpPoolDN' EQUALITY distinguishedNameMatch DESC 'The distinguished name(s) of pools.' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 ) attributetype ( 2.16.840.1.113719.1.203.4.12 NAME 'dhcpGroupDN' EQUALITY distinguishedNameMatch DESC 'The distinguished name(s) of the groups.' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 ) attributetype ( 2.16.840.1.113719.1.203.4.13 NAME 'dhcpSubnetDN' EQUALITY distinguishedNameMatch DESC 'The distinguished name(s) of the subnets.' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 ) attributetype ( 2.16.840.1.113719.1.203.4.14 NAME 'dhcpLeaseDN' EQUALITY distinguishedNameMatch DESC 'The distinguished name of a client address.' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 SINGLE-VALUE) attributetype ( 2.16.840.1.113719.1.203.4.15 NAME 'dhcpLeasesDN' DESC 'The distinguished name(s) client addresses.' EQUALITY distinguishedNameMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 ) attributetype ( 2.16.840.1.113719.1.203.4.16 NAME 'dhcpClassesDN' EQUALITY distinguishedNameMatch DESC 'The distinguished name(s) of a class(es) in a subclass.' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 ) attributetype ( 2.16.840.1.113719.1.203.4.17 NAME 'dhcpSubclassesDN' EQUALITY distinguishedNameMatch DESC 'The distinguished name(s) of subclass(es).' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 ) attributetype ( 2.16.840.1.113719.1.203.4.18 NAME 'dhcpSharedNetworkDN' EQUALITY distinguishedNameMatch DESC 'The distinguished name(s) of sharedNetworks.' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 ) attributetype ( 2.16.840.1.113719.1.203.4.19 NAME 'dhcpServiceDN' EQUALITY distinguishedNameMatch DESC 'The DN of dhcpService object(s)which contain the configuration information. Each dhcpServer object has this attribute identifying the DHCP configuration(s) that the server is associated with.' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 ) attributetype ( 2.16.840.1.113719.1.203.4.20 NAME 'dhcpVersion' DESC 'The version attribute of this object.' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE ) attributetype ( 2.16.840.1.113719.1.203.4.21 NAME 'dhcpImplementation' EQUALITY caseIgnoreIA5Match DESC 'Description of the DHCP Server implementation e.g. DHCP Servers vendor.' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE ) attributetype ( 2.16.840.1.113719.1.203.4.22 NAME 'dhcpAddressState' EQUALITY caseIgnoreIA5Match DESC 'This stores information about the current binding-status of an address. For dynamic addresses managed by DHCP, the values should be restricted to the following: "FREE", "ACTIVE", "EXPIRED", "RELEASED", "RESET", "ABANDONED", "BACKUP". For other addresses, it SHOULD be one of the following: "UNKNOWN", "RESERVED" (an address that is managed by DHCP that is reserved for a specific client), "RESERVED-ACTIVE" (same as reserved, but address is currently in use), "ASSIGNED" (assigned manually or by some other mechanism), "UNASSIGNED", "NOTASSIGNABLE".' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE ) attributetype ( 2.16.840.1.113719.1.203.4.23 NAME 'dhcpExpirationTime' EQUALITY generalizedTimeMatch DESC 'This is the time the current lease for an address expires.' SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 SINGLE-VALUE ) attributetype ( 2.16.840.1.113719.1.203.4.24 NAME 'dhcpStartTimeOfState' EQUALITY generalizedTimeMatch DESC 'This is the time of the last state change for a leased address.' SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 SINGLE-VALUE ) attributetype ( 2.16.840.1.113719.1.203.4.25 NAME 'dhcpLastTransactionTime' EQUALITY generalizedTimeMatch DESC 'This is the last time a valid DHCP packet was received from the client.' SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 SINGLE-VALUE ) attributetype ( 2.16.840.1.113719.1.203.4.26 NAME 'dhcpBootpFlag' EQUALITY booleanMatch DESC 'This indicates whether the address was assigned via BOOTP.' SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE ) attributetype ( 2.16.840.1.113719.1.203.4.27 NAME 'dhcpDomainName' EQUALITY caseIgnoreIA5Match DESC 'This is the name of the domain sent to the client by the server. It is essentially the same as the value for DHCP option 15 sent to the client, and represents only the domain - not the full FQDN. To obtain the full FQDN assigned to the client you must prepend the "dhcpAssignedHostName" to this value with a ".".' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE ) attributetype ( 2.16.840.1.113719.1.203.4.28 NAME 'dhcpDnsStatus' EQUALITY integerMatch DESC 'This indicates the status of updating DNS resource records on behalf of the client by the DHCP server for this address. The value is a 16-bit bitmask.' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) attributetype ( 2.16.840.1.113719.1.203.4.29 NAME 'dhcpRequestedHostName' EQUALITY caseIgnoreIA5Match DESC 'This is the hostname that was requested by the client.' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE ) attributetype ( 2.16.840.1.113719.1.203.4.30 NAME 'dhcpAssignedHostName' EQUALITY caseIgnoreIA5Match DESC 'This is the actual hostname that was assigned to a client. It may not be the name that was requested by the client. The fully qualified domain name can be determined by appending the value of "dhcpDomainName" (with a dot separator) to this name.' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE ) attributetype ( 2.16.840.1.113719.1.203.4.31 NAME 'dhcpReservedForClient' EQUALITY distinguishedNameMatch DESC 'The distinguished name of a "dhcpClient" that an address is reserved for. This may not be the same as the "dhcpAssignedToClient" attribute if the address is being reassigned but the current lease has not yet expired.' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 SINGLE-VALUE ) attributetype ( 2.16.840.1.113719.1.203.4.32 NAME 'dhcpAssignedToClient' EQUALITY distinguishedNameMatch DESC 'This is the distinguished name of a "dhcpClient" that an address is currently assigned to. This attribute is only present in the class when the address is leased.' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 SINGLE-VALUE ) attributetype ( 2.16.840.1.113719.1.203.4.33 NAME 'dhcpRelayAgentInfo' EQUALITY octetStringMatch DESC 'If the client request was received via a relay agent, this contains information about the relay agent that was available from the DHCP request. This is a hex-encoded option value.' SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 SINGLE-VALUE ) attributetype ( 2.16.840.1.113719.1.203.4.34 NAME 'dhcpHWAddress' EQUALITY caseIgnoreIA5Match DESC 'The clients hardware address that requested this IP address.' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE ) attributetype ( 2.16.840.1.113719.1.203.4.35 NAME 'dhcpHashBucketAssignment' EQUALITY octetStringMatch DESC 'HashBucketAssignment bit map for the DHCP Server, as defined in DHC Load Balancing Algorithm [RFC 3074].' SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 SINGLE-VALUE ) attributetype ( 2.16.840.1.113719.1.203.4.36 NAME 'dhcpDelayedServiceParameter' EQUALITY integerMatch DESC 'Delay in seconds corresponding to Delayed Service Parameter configuration, as defined in DHC Load Balancing Algorithm [RFC 3074]. ' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) attributetype ( 2.16.840.1.113719.1.203.4.37 NAME 'dhcpMaxClientLeadTime' EQUALITY integerMatch DESC 'Maximum Client Lead Time configuration in seconds, as defined in DHCP Failover Protocol [FAILOVR]' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) attributetype ( 2.16.840.1.113719.1.203.4.38 NAME 'dhcpFailOverEndpointState' EQUALITY caseIgnoreIA5Match DESC 'Server (Failover Endpoint) state, as defined in DHCP Failover Protocol [FAILOVR]' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE ) attributetype ( 2.16.840.1.113719.1.203.4.39 NAME 'dhcpErrorLog' EQUALITY caseIgnoreIA5Match DESC 'Generic error log attribute that allows logging error conditions within a dhcpService or a dhcpSubnet, like no IP addresses available for lease.' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE ) attributetype ( 2.16.840.1.113719.1.203.4.40 NAME 'dhcpLocatorDN' EQUALITY distinguishedNameMatch DESC 'The DN of dhcpLocator object which contain the DNs of all DHCP configuration objects. There will be a single dhcpLocator object in the tree with links to all the DHCP objects in the tree' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 ) attributetype ( 2.16.840.1.113719.1.203.4.41 NAME 'dhcpKeyAlgorithm' EQUALITY caseIgnoreIA5Match DESC 'Algorithm to generate TSIG Key' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE ) attributetype ( 2.16.840.1.113719.1.203.4.42 NAME 'dhcpKeySecret' EQUALITY octetStringMatch DESC 'Secret to generate TSIG Key' SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 SINGLE-VALUE ) attributetype ( 2.16.840.1.113719.1.203.4.43 NAME 'dhcpDnsZoneServer' EQUALITY caseIgnoreIA5Match DESC 'Master server of the DNS Zone' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE ) attributetype ( 2.16.840.1.113719.1.203.4.44 NAME 'dhcpKeyDN' EQUALITY distinguishedNameMatch DESC 'The DNs of TSIG Key to use in secure dynamic updates. In case of locator object, this will be list of TSIG keys. In case of DHCP Service, Shared Network, Subnet and DNS Zone, it will be a single key.' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12) attributetype ( 2.16.840.1.113719.1.203.4.45 NAME 'dhcpZoneDN' EQUALITY distinguishedNameMatch DESC 'The DNs of DNS Zone. In case of locator object, this will be list of DNS Zones in the tree. In case of DHCP Service, Shared Network and Subnet, it will be a single DNS Zone.' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12) attributetype ( 2.16.840.1.113719.1.203.4.46 NAME 'dhcpFailOverPrimaryServer' EQUALITY caseIgnoreIA5Match DESC 'IP address or DNS name of the server playing primary role in DHC Load Balancing and Fail over.' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) attributetype ( 2.16.840.1.113719.1.203.4.47 NAME 'dhcpFailOverSecondaryServer' EQUALITY caseIgnoreIA5Match DESC 'IP address or DNS name of the server playing secondary role in DHC Load Balancing and Fail over.' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) attributetype ( 2.16.840.1.113719.1.203.4.48 NAME 'dhcpFailOverPrimaryPort' EQUALITY integerMatch DESC 'Port on which primary server listens for connections from its fail over peer (secondary server)' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 ) attributetype ( 2.16.840.1.113719.1.203.4.49 NAME 'dhcpFailOverSecondaryPort' EQUALITY integerMatch DESC 'Port on which secondary server listens for connections from its fail over peer (primary server)' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 ) attributetype ( 2.16.840.1.113719.1.203.4.50 NAME 'dhcpFailOverResponseDelay' EQUALITY integerMatch DESC 'Maximum response time in seconds, before Server assumes that connection to fail over peer has failed' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 ) attributetype ( 2.16.840.1.113719.1.203.4.51 NAME 'dhcpFailOverUnackedUpdates' EQUALITY integerMatch DESC 'Number of BNDUPD messages that server can send before it receives BNDACK from its fail over peer' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 ) attributetype ( 2.16.840.1.113719.1.203.4.52 NAME 'dhcpFailOverSplit' EQUALITY integerMatch DESC 'Split between the primary and secondary servers for fail over purpose' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 ) attributetype ( 2.16.840.1.113719.1.203.4.53 NAME 'dhcpFailOverLoadBalanceTime' EQUALITY integerMatch DESC 'Cutoff time in seconds, after which load balance is disabled' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 ) attributetype ( 2.16.840.1.113719.1.203.4.54 NAME 'dhcpFailOverPeerDN' EQUALITY distinguishedNameMatch DESC 'The DNs of Fail over peers. In case of locator object, this will be list of fail over peers in the tree. In case of Subnet and pool, it will be a single Fail Over Peer' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 ) #List of all servers in the tree attributetype ( 2.16.840.1.113719.1.203.4.55 NAME 'dhcpServerDN' EQUALITY distinguishedNameMatch DESC 'List of all DHCP Servers in the tree. Used by dhcpLocatorObject' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 ) attributetype ( 2.16.840.1.113719.1.203.4.56 NAME 'dhcpComments' EQUALITY caseIgnoreIA5Match DESC 'Generic attribute that allows coments within any DHCP object' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE ) # Classes objectclass ( 2.16.840.1.113719.1.203.6.1 NAME 'dhcpService' DESC 'Service object that represents the actual DHCP Service configuration. This is a container object.' SUP top MUST (cn) MAY ( dhcpPrimaryDN $ dhcpSecondaryDN $ dhcpServerDN $ dhcpSharedNetworkDN $ dhcpSubnetDN $ dhcpGroupDN $ dhcpHostDN $ dhcpClassesDN $ dhcpOptionsDN $ dhcpZoneDN $ dhcpKeyDN $ dhcpFailOverPeerDN $ dhcpStatements $dhcpComments $ dhcpOption) ) objectclass ( 2.16.840.1.113719.1.203.6.2 NAME 'dhcpSharedNetwork' DESC 'This stores configuration information for a shared network.' SUP top MUST cn MAY ( dhcpSubnetDN $ dhcpPoolDN $ dhcpOptionsDN $ dhcpZoneDN $ dhcpStatements $dhcpComments $ dhcpOption) X-NDS_CONTAINMENT ('dhcpService' ) ) objectclass ( 2.16.840.1.113719.1.203.6.3 NAME 'dhcpSubnet' DESC 'This class defines a subnet. This is a container object.' SUP top MUST ( cn $ dhcpNetMask ) MAY ( dhcpRange $ dhcpPoolDN $ dhcpGroupDN $ dhcpHostDN $ dhcpClassesDN $ dhcpLeasesDN $ dhcpOptionsDN $ dhcpZoneDN $ dhcpKeyDN $ dhcpFailOverPeerDN $ dhcpStatements $ dhcpComments $ dhcpOption ) X-NDS_CONTAINMENT ('dhcpService' 'dhcpSharedNetwork') ) objectclass ( 2.16.840.1.113719.1.203.6.4 NAME 'dhcpPool' DESC 'This stores configuration information about a pool.' SUP top MUST ( cn $ dhcpRange ) MAY ( dhcpClassesDN $ dhcpPermitList $ dhcpLeasesDN $ dhcpOptionsDN $ dhcpZoneDN $dhcpKeyDN $ dhcpStatements $ dhcpComments $ dhcpOption ) X-NDS_CONTAINMENT ('dhcpSubnet' 'dhcpSharedNetwork') ) objectclass ( 2.16.840.1.113719.1.203.6.5 NAME 'dhcpGroup' DESC 'Group object that lists host DNs and parameters. This is a container object.' SUP top MUST cn MAY ( dhcpHostDN $ dhcpOptionsDN $ dhcpStatements $ dhcpComments $ dhcpOption ) X-NDS_CONTAINMENT ('dhcpSubnet' 'dhcpService' ) ) objectclass ( 2.16.840.1.113719.1.203.6.6 NAME 'dhcpHost' DESC 'This represents information about a particular client' SUP top MUST cn MAY (dhcpLeaseDN $ dhcpHWAddress $ dhcpOptionsDN $ dhcpStatements $ dhcpComments $ dhcpOption) X-NDS_CONTAINMENT ('dhcpService' 'dhcpSubnet' 'dhcpGroup') ) objectclass ( 2.16.840.1.113719.1.203.6.7 NAME 'dhcpClass' DESC 'Represents information about a collection of related clients.' SUP top MUST cn MAY (dhcpSubClassesDN $ dhcpOptionsDN $ dhcpStatements $ dhcpComments $ dhcpOption) X-NDS_CONTAINMENT ('dhcpService' 'dhcpSubnet' ) ) objectclass ( 2.16.840.1.113719.1.203.6.8 NAME 'dhcpSubClass' DESC 'Represents information about a collection of related classes.' SUP top MUST cn MAY (dhcpClassData $ dhcpOptionsDN $ dhcpStatements $ dhcpComments $ dhcpOption) X-NDS_CONTAINMENT 'dhcpClass' ) objectclass ( 2.16.840.1.113719.1.203.6.9 NAME 'dhcpOptions' DESC 'Represents information about a collection of options defined.' SUP top AUXILIARY MUST cn MAY ( dhcpOption $ dhcpComments ) X-NDS_CONTAINMENT ('dhcpService' 'dhcpSharedNetwork' 'dhcpSubnet' 'dhcpPool' 'dhcpGroup' 'dhcpHost' 'dhcpClass' ) ) objectclass ( 2.16.840.1.113719.1.203.6.10 NAME 'dhcpLeases' DESC 'This class represents an IP Address, which may or may not have been leased.' SUP top MUST ( cn $ dhcpAddressState ) MAY ( dhcpExpirationTime $ dhcpStartTimeOfState $ dhcpLastTransactionTime $ dhcpBootpFlag $ dhcpDomainName $ dhcpDnsStatus $ dhcpRequestedHostName $ dhcpAssignedHostName $ dhcpReservedForClient $ dhcpAssignedToClient $ dhcpRelayAgentInfo $ dhcpHWAddress ) X-NDS_CONTAINMENT ( 'dhcpService' 'dhcpSubnet' 'dhcpPool') ) objectclass ( 2.16.840.1.113719.1.203.6.11 NAME 'dhcpLog' DESC 'This is the object that holds past information about the IP address. The cn is the time/date stamp when the address was assigned or released, the address state at the time, if the address was assigned or released.' SUP top MUST ( cn ) MAY ( dhcpAddressState $ dhcpExpirationTime $ dhcpStartTimeOfState $ dhcpLastTransactionTime $ dhcpBootpFlag $ dhcpDomainName $ dhcpDnsStatus $ dhcpRequestedHostName $ dhcpAssignedHostName $ dhcpReservedForClient $ dhcpAssignedToClient $ dhcpRelayAgentInfo $ dhcpHWAddress $ dhcpErrorLog) X-NDS_CONTAINMENT ('dhcpLeases' 'dhcpPool' 'dhcpSubnet' 'dhcpSharedNetwork' 'dhcpService' ) ) objectclass ( 2.16.840.1.113719.1.203.6.12 NAME 'dhcpServer' DESC 'DHCP Server Object' SUP top MUST ( cn ) MAY (dhcpServiceDN $ dhcpLocatorDN $ dhcpVersion $ dhcpImplementation $ dhcpHashBucketAssignment $ dhcpDelayedServiceParameter $ dhcpMaxClientLeadTime $ dhcpFailOverEndpointState $ dhcpStatements $ dhcpComments $ dhcpOption) X-NDS_CONTAINMENT ('organization' 'organizationalunit' 'domain') ) objectclass ( 2.16.840.1.113719.1.203.6.13 NAME 'dhcpTSigKey' DESC 'TSIG key for secure dynamic updates' SUP top MUST (cn $ dhcpKeyAlgorithm $ dhcpKeySecret ) MAY ( dhcpComments ) X-NDS_CONTAINMENT ('dhcpService' 'dhcpSharedNetwork' 'dhcpSubnet') ) objectclass ( 2.16.840.1.113719.1.203.6.14 NAME 'dhcpDnsZone' DESC 'DNS Zone for updating leases' SUP top MUST (cn $ dhcpDnsZoneServer ) MAY (dhcpKeyDN $ dhcpComments) X-NDS_CONTAINMENT ('dhcpService' 'dhcpSharedNetwork' 'dhcpSubnet') ) objectclass ( 2.16.840.1.113719.1.203.6.15 NAME 'dhcpFailOverPeer' DESC 'This class defines the Fail over peer' SUP top MUST ( cn $ dhcpFailOverPrimaryServer $ dhcpFailOverSecondaryServer $ dhcpFailoverPrimaryPort $ dhcpFailOverSecondaryPort) MAY (dhcpFailOverResponseDelay $ dhcpFailOverUnackedUpdates $ dhcpMaxClientLeadTime $ dhcpFailOverSplit $ dhcpHashBucketAssignment $ dhcpFailOverLoadBalanceTime $ dhcpComments ) X-NDS_CONTAINMENT ('dhcpService' 'dhcpSharedNetwork' 'dhcpSubnet') ) objectclass ( 2.16.840.1.113719.1.203.6.16 NAME 'dhcpLocator' DESC 'Locator object for DHCP configuration in the tree. There will be a single dhcpLocator object in the tree with links to all the DHCP objects in the tree' SUP top MUST ( cn ) MAY ( dhcpServiceDN $dhcpServerDN $ dhcpSharedNetworkDN $ dhcpSubnetDN $ dhcpPoolDN $ dhcpGroupDN $ dhcpHostDN $ dhcpClassesDN $ dhcpKeyDN $ dhcpZoneDN $ dhcpFailOverPeerDN $ dhcpOption $ dhcpComments) X-NDS_CONTAINMENT ('organization' 'organizationalunit' 'domain') ) dhcp-4.2.4/contrib/ldap/dhcpd-conf-to-ldap000644 000765 000024 00000041744 11352700324 020244 0ustar00sarstaff000000 000000 #!/usr/bin/perl -w # Brian Masney # To use this script, set your base DN below. Then run # ./dhcpd-conf-to-ldap.pl < /path-to-dhcpd-conf/dhcpd.conf > output-file # The output of this script will generate entries in LDIF format. You can use # the slapadd command to add these entries into your LDAP server. You will # definately want to double check that your LDAP entries are correct before # you load them into LDAP. # This script does not do much error checking. Make sure before you run this # that the DHCP server doesn't give any errors about your config file # FailOver notes: # Failover is disabled by default, since it may need manually intervention. # You can try the '--use=failover' option to see what happens :-) # # If enabled, the failover pool references will be written to LDIF output. # The failover configs itself will be added to the dhcpServer statements # and not to the dhcpService object (since this script uses only one and # it may be usefull to have multiple service containers in failover mode). # Further, this script does not check if primary or secondary makes sense, # it simply converts what it gets... use Net::Domain qw(hostname hostfqdn hostdomain); use Getopt::Long; my $domain = hostdomain(); # your.domain my $basedn = "dc=".$domain; $basedn =~ s/\./,dc=/g; # dc=your,dc=domain my $server = hostname(); # hostname (nodename) my $dhcpcn = 'DHCP Config'; # CN of DHCP config tree my $dhcpdn = "cn=$dhcpcn, $basedn"; # DHCP config tree DN my $second = ''; # secondary server DN / hostname my $i_conf = ''; # dhcp.conf file to read or stdin my $o_ldif = ''; # output ldif file name or stdout my @use = (); # extended flags (failover) sub usage($;$) { my $rc = shift; my $err= shift; print STDERR "Error: $err\n\n" if(defined $err); print STDERR <<__EOF_USAGE__; usage: $0 [options] < dhcpd.conf > dhcpd.ldif options: --basedn "dc=your,dc=domain" ("$basedn") --dhcpdn "dhcp config DN" ("$dhcpdn") --server "dhcp server name" ("$server") --second "secondary server or DN" ("$second") --conf "/path/to/dhcpd.conf" (default is stdin) --ldif "/path/to/output.ldif" (default is stdout) --use "extended features" (see source comments) __EOF_USAGE__ exit($rc); } sub next_token { local ($lowercase) = @_; local ($token, $newline); do { if (!defined ($line) || length ($line) == 0) { $line = <>; return undef if !defined ($line); chop $line; $line_number++; $token_number = 0; } $line =~ s/#.*//; $line =~ s/^\s+//; $line =~ s/\s+$//; } while (length ($line) == 0); if (($token, $newline) = $line =~ /^(.*?)\s+(.*)/) { if ($token =~ /^"/) { #handle quoted token if ($token !~ /"\s*$/) { ($tok, $newline) = $newline =~ /([^"]+")(.*)/; $token .= " $tok"; } } $line = $newline; } else { $token = $line; $line = ''; } $token_number++; $token =~ y/[A-Z]/[a-z]/ if $lowercase; return ($token); } sub remaining_line { local ($block) = shift || 0; local ($tmp, $str); $str = ""; while (defined($tmp = next_token (0))) { $str .= ' ' if !($str eq ""); $str .= $tmp; last if $tmp =~ /;\s*$/; last if($block and $tmp =~ /\s*[}{]\s*$/); } $str =~ s/;$//; return ($str); } sub add_dn_to_stack { local ($dn) = @_; $current_dn = "$dn, $current_dn"; } sub remove_dn_from_stack { $current_dn =~ s/^.*?,\s*//; } sub parse_error { print "Parse error on line number $line_number at token number $token_number\n"; exit (1); } sub print_entry { return if (scalar keys %curentry == 0); if (!defined ($curentry{'type'})) { $hostdn = "cn=$server, $basedn"; print "dn: $hostdn\n"; print "cn: $server\n"; print "objectClass: top\n"; print "objectClass: dhcpServer\n"; print "dhcpServiceDN: $current_dn\n"; if(grep(/FaIlOvEr/i, @use)) { foreach my $fo_peer (keys %failover) { next if(scalar(@{$failover{$fo_peer}}) <= 1); print "dhcpStatements: failover peer $fo_peer { ", join('; ', @{$failover{$fo_peer}}), "; }\n"; } } print "\n"; print "dn: $current_dn\n"; print "cn: $dhcpcn\n"; print "objectClass: top\n"; print "objectClass: dhcpService\n"; if (defined ($curentry{'options'})) { print "objectClass: dhcpOptions\n"; } print "dhcpPrimaryDN: $hostdn\n"; if(grep(/FaIlOvEr/i, @use) and ($second ne '')) { print "dhcpSecondaryDN: $second\n"; } } elsif ($curentry{'type'} eq 'subnet') { print "dn: $current_dn\n"; print "cn: " . $curentry{'ip'} . "\n"; print "objectClass: top\n"; print "objectClass: dhcpSubnet\n"; if (defined ($curentry{'options'})) { print "objectClass: dhcpOptions\n"; } print "dhcpNetMask: " . $curentry{'netmask'} . "\n"; if (defined ($curentry{'ranges'})) { foreach $statement (@{$curentry{'ranges'}}) { print "dhcpRange: $statement\n"; } } } elsif ($curentry{'type'} eq 'shared-network') { print "dn: $current_dn\n"; print "cn: " . $curentry{'descr'} . "\n"; print "objectClass: top\n"; print "objectClass: dhcpSharedNetwork\n"; if (defined ($curentry{'options'})) { print "objectClass: dhcpOptions\n"; } } elsif ($curentry{'type'} eq 'group') { print "dn: $current_dn\n"; print "cn: group", $curentry{'idx'}, "\n"; print "objectClass: top\n"; print "objectClass: dhcpGroup\n"; if (defined ($curentry{'options'})) { print "objectClass: dhcpOptions\n"; } } elsif ($curentry{'type'} eq 'host') { print "dn: $current_dn\n"; print "cn: " . $curentry{'host'} . "\n"; print "objectClass: top\n"; print "objectClass: dhcpHost\n"; if (defined ($curentry{'options'})) { print "objectClass: dhcpOptions\n"; } if (defined ($curentry{'hwaddress'})) { $curentry{'hwaddress'} =~ y/[A-Z]/[a-z]/; print "dhcpHWAddress: " . $curentry{'hwaddress'} . "\n"; } } elsif ($curentry{'type'} eq 'pool') { print "dn: $current_dn\n"; print "cn: pool", $curentry{'idx'}, "\n"; print "objectClass: top\n"; print "objectClass: dhcpPool\n"; if (defined ($curentry{'options'})) { print "objectClass: dhcpOptions\n"; } if (defined ($curentry{'ranges'})) { foreach $statement (@{$curentry{'ranges'}}) { print "dhcpRange: $statement\n"; } } } elsif ($curentry{'type'} eq 'class') { print "dn: $current_dn\n"; print "cn: " . $curentry{'class'} . "\n"; print "objectClass: top\n"; print "objectClass: dhcpClass\n"; if (defined ($curentry{'options'})) { print "objectClass: dhcpOptions\n"; } } elsif ($curentry{'type'} eq 'subclass') { print "dn: $current_dn\n"; print "cn: " . $curentry{'subclass'} . "\n"; print "objectClass: top\n"; print "objectClass: dhcpSubClass\n"; if (defined ($curentry{'options'})) { print "objectClass: dhcpOptions\n"; } print "dhcpClassData: " . $curentry{'class'} . "\n"; } if (defined ($curentry{'statements'})) { foreach $statement (@{$curentry{'statements'}}) { print "dhcpStatements: $statement\n"; } } if (defined ($curentry{'options'})) { foreach $statement (@{$curentry{'options'}}) { print "dhcpOption: $statement\n"; } } print "\n"; undef (%curentry); } sub parse_netmask { local ($netmask) = @_; local ($i); if ((($a, $b, $c, $d) = $netmask =~ /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/) != 4) { parse_error (); } $num = (($a & 0xff) << 24) | (($b & 0xff) << 16) | (($c & 0xff) << 8) | ($d & 0xff); for ($i=1; $i<=32 && $num & (1 << (32 - $i)); $i++) { } $i--; return ($i); } sub parse_subnet { local ($ip, $tmp, $netmask); print_entry () if %curentry; $ip = next_token (0); parse_error () if !defined ($ip); $tmp = next_token (1); parse_error () if !defined ($tmp); parse_error () if !($tmp eq 'netmask'); $tmp = next_token (0); parse_error () if !defined ($tmp); $netmask = parse_netmask ($tmp); $tmp = next_token (0); parse_error () if !defined ($tmp); parse_error () if !($tmp eq '{'); add_dn_to_stack ("cn=$ip"); $curentry{'type'} = 'subnet'; $curentry{'ip'} = $ip; $curentry{'netmask'} = $netmask; $cursubnet = $ip; $curcounter{$ip} = { pool => 0, group => 0 }; } sub parse_shared_network { local ($descr, $tmp); print_entry () if %curentry; $descr = next_token (0); parse_error () if !defined ($descr); $tmp = next_token (0); parse_error () if !defined ($tmp); parse_error () if !($tmp eq '{'); add_dn_to_stack ("cn=$descr"); $curentry{'type'} = 'shared-network'; $curentry{'descr'} = $descr; } sub parse_host { local ($descr, $tmp); print_entry () if %curentry; $host = next_token (0); parse_error () if !defined ($host); $tmp = next_token (0); parse_error () if !defined ($tmp); parse_error () if !($tmp eq '{'); add_dn_to_stack ("cn=$host"); $curentry{'type'} = 'host'; $curentry{'host'} = $host; } sub parse_group { local ($descr, $tmp); print_entry () if %curentry; $tmp = next_token (0); parse_error () if !defined ($tmp); parse_error () if !($tmp eq '{'); my $idx; if(exists($curcounter{$cursubnet})) { $idx = ++$curcounter{$cursubnet}->{'group'}; } else { $idx = ++$curcounter{''}->{'group'}; } add_dn_to_stack ("cn=group".$idx); $curentry{'type'} = 'group'; $curentry{'idx'} = $idx; } sub parse_pool { local ($descr, $tmp); print_entry () if %curentry; $tmp = next_token (0); parse_error () if !defined ($tmp); parse_error () if !($tmp eq '{'); my $idx; if(exists($curcounter{$cursubnet})) { $idx = ++$curcounter{$cursubnet}->{'pool'}; } else { $idx = ++$curcounter{''}->{'pool'}; } add_dn_to_stack ("cn=pool".$idx); $curentry{'type'} = 'pool'; $curentry{'idx'} = $idx; } sub parse_class { local ($descr, $tmp); print_entry () if %curentry; $class = next_token (0); parse_error () if !defined ($class); $tmp = next_token (0); parse_error () if !defined ($tmp); parse_error () if !($tmp eq '{'); $class =~ s/\"//g; add_dn_to_stack ("cn=$class"); $curentry{'type'} = 'class'; $curentry{'class'} = $class; } sub parse_subclass { local ($descr, $tmp); print_entry () if %curentry; $class = next_token (0); parse_error () if !defined ($class); $subclass = next_token (0); parse_error () if !defined ($subclass); $tmp = next_token (0); parse_error () if !defined ($tmp); parse_error () if !($tmp eq '{'); add_dn_to_stack ("cn=$subclass"); $curentry{'type'} = 'subclass'; $curentry{'class'} = $class; $curentry{'subclass'} = $subclass; } sub parse_hwaddress { local ($type, $hw, $tmp); $type = next_token (1); parse_error () if !defined ($type); $hw = next_token (1); parse_error () if !defined ($hw); $hw =~ s/;$//; $curentry{'hwaddress'} = "$type $hw"; } sub parse_range { local ($tmp, $str); $str = remaining_line (); if (!($str eq '')) { $str =~ s/;$//; push (@{$curentry{'ranges'}}, $str); } } sub parse_statement { local ($token) = shift; local ($str); if ($token eq 'option') { $str = remaining_line (); push (@{$curentry{'options'}}, $str); } elsif($token eq 'failover') { $str = remaining_line (1); # take care on block if($str =~ /[{]/) { my ($peername, @statements); parse_error() if($str !~ /^\s*peer\s+(.+?)\s+[{]\s*$/); parse_error() if(($peername = $1) !~ /^\"?[^\"]+\"?$/); # # failover config block found: # e.g. 'failover peer "some-name" {' # if(not grep(/FaIlOvEr/i, @use)) { print STDERR "Warning: Failover config 'peer $peername' found!\n"; print STDERR " Skipping it, since failover disabled!\n"; print STDERR " You may try out --use=failover option.\n"; } until($str =~ /[}]/ or $str eq "") { $str = remaining_line (1); # collect all statements, except ending '}' push(@statements, $str) if($str !~ /[}]/); } $failover{$peername} = [@statements]; } else { # # pool reference to failover config is fine # e.g. 'failover peer "some-name";' # if(not grep(/FaIlOvEr/i, @use)) { print STDERR "Warning: Failover reference '$str' found!\n"; print STDERR " Skipping it, since failover disabled!\n"; print STDERR " You may try out --use=failover option.\n"; } else { push (@{$curentry{'statements'}}, $token. " " . $str); } } } elsif($token eq 'zone') { $str = $token; while($str !~ /}$/) { $str .= ' ' . next_token (0); } push (@{$curentry{'statements'}}, $str); } elsif($token =~ /^(authoritative)[;]*$/) { push (@{$curentry{'statements'}}, $1); } else { $str = $token . " " . remaining_line (); push (@{$curentry{'statements'}}, $str); } } my $ok = GetOptions( 'basedn=s' => \$basedn, 'dhcpdn=s' => \$dhcpdn, 'server=s' => \$server, 'second=s' => \$second, 'conf=s' => \$i_conf, 'ldif=s' => \$o_ldif, 'use=s' => \@use, 'h|help|usage' => sub { usage(0); }, ); unless($server =~ /^\w+/) { usage(1, "invalid server name '$server'"); } unless($basedn =~ /^\w+=[^,]+/) { usage(1, "invalid base dn '$basedn'"); } if($dhcpdn =~ /^cn=([^,]+)/i) { $dhcpcn = "$1"; } $second = '' if not defined $second; unless($second eq '' or $second =~ /^cn=[^,]+\s*,\s*\w+=[^,]+/i) { if($second =~ /^cn=[^,]+$/i) { # relative DN 'cn=name' $second = "$second, $basedn"; } elsif($second =~ /^\w+/) { # assume hostname only $second = "cn=$second, $basedn"; } else { usage(1, "invalid secondary '$second'") } } usage(1) unless($ok); if($i_conf ne "" and -f $i_conf) { if(not open(STDIN, '<', $i_conf)) { print STDERR "Error: can't open conf file '$i_conf': $!\n"; exit(1); } } if($o_ldif ne "") { if(-e $o_ldif) { print STDERR "Error: output ldif name '$o_ldif' already exists!\n"; exit(1); } if(not open(STDOUT, '>', $o_ldif)) { print STDERR "Error: can't open ldif file '$o_ldif': $!\n"; exit(1); } } print STDERR "Creating LDAP Configuration with the following options:\n"; print STDERR "\tBase DN: $basedn\n"; print STDERR "\tDHCP DN: $dhcpdn\n"; print STDERR "\tServer DN: cn=$server, $basedn\n"; print STDERR "\tSecondary DN: $second\n" if(grep(/FaIlOvEr/i, @use) and $second ne ''); print STDERR "\n"; my $token; my $token_number = 0; my $line_number = 0; my %curentry; my $cursubnet = ''; my %curcounter = ( '' => { pool => 0, group => 0 } ); $current_dn = "$dhcpdn"; $curentry{'descr'} = $dhcpcn; $line = ''; %failover = (); while (($token = next_token (1))) { if ($token eq '}') { print_entry () if %curentry; if($current_dn =~ /.+?,\s*${dhcpdn}$/) { # don't go below dhcpdn ... remove_dn_from_stack (); } } elsif ($token eq 'subnet') { parse_subnet (); next; } elsif ($token eq 'shared-network') { parse_shared_network (); next; } elsif ($token eq 'class') { parse_class (); next; } elsif ($token eq 'subclass') { parse_subclass (); next; } elsif ($token eq 'pool') { parse_pool (); next; } elsif ($token eq 'group') { parse_group (); next; } elsif ($token eq 'host') { parse_host (); next; } elsif ($token eq 'hardware') { parse_hwaddress (); next; } elsif ($token eq 'range') { parse_range (); next; } else { parse_statement ($token); next; } } close(STDIN) if($i_conf); close(STDOUT) if($o_ldif); print STDERR "Done.\n"; dhcp-4.2.4/contrib/ldap/README.ldap000644 000765 000024 00000017576 11352700324 016563 0ustar00sarstaff000000 000000 LDAP Support in DHCP Original Author: Brian Masney Current Maintainer: David Cantrell Last updated 07-Jul-2009 This document describes setting up the DHCP server to read it's configuration from LDAP. This work is based on the IETF document draft-ietf-dhc-ldap-schema-01.txt included in the doc directory. For the latest version of this document, please see http://dcantrel.fedorapeople.org/dhcp/ldap-patch/ First question on most people's mind is "Why do I want to store my configuration in LDAP?" If you run a small DHCP server, and the configuration on it rarely changes, then you won't need to store your configuration in LDAP. But, if you have several DHCP servers, and you want an easy way to manage your configuration, this can be a solution. The first step will be to setup your LDAP server. I am using OpenLDAP from www.openldap.org. Building and installing OpenLDAP is beyond the scope of this document. There is plenty of documentation out there about this. Once you have OpenLDAP installed, you will have to edit your slapd.conf file. I added the following 2 lines to my configuration file: include /etc/ldap/schema/dhcp.schema index dhcpHWAddress eq index dhcpClassData eq The first line tells it to include the dhcp schema file. You will find this file under the contrib directory in this distribution. You will need to copy this file to where your other schema files are (maybe /etc/openldap/schema/). The second line sets up an index for the dhcpHWAddress parameter. The third parameter is for reading subclasses from LDAP every time a DHCP request comes in. Make sure you run the slapindex command and restart slapd to have these changes to into effect. Now that you have LDAP setup, you should be able to use gq (http://biot.com/gq/) to verify that the dhcp schema file is loaded into LDAP. Pull up gq, and click on the Schema tab. Go under objectClasses, and you should see at least the following object classes listed: dhcpClass, dhcpGroup, dhcpHost, dhcpOptions, dhcpPool, dhcpServer, dhcpService, dhcpSharedNetwork, dhcpSubClass, and dhcpSubnet. If you do not see these, you need to check over your LDAP configuration before you go any further. You should now be ready to build DHCP. If you would like to enable LDAP in dhcpd, you will need to perform the following steps: * Apply the patch here to the unpacked ISC dhcp source tree. * Regenerate the configure script (requires GNU autoconf and automake): aclocal libtoolize --copy --force autoconf autoheader automake --foreign --add-missing --copy * Run ./configure with the '--with-ldap' argument to enable OpenLDAP. If you want LDAP over SSL, also use the '--with-ldapcrypto' argument. * Run 'make' to build ISC dhcp. Once you have DHCP installed, you will need to setup your initial plaintext config file. In my /etc/dhcpd.conf file, I have: ldap-server "localhost"; ldap-port 389; ldap-username "cn=DHCP User, dc=ntelos, dc=net"; ldap-password "blah"; ldap-base-dn "dc=ntelos, dc=net"; ldap-method dynamic; ldap-debug-file "/var/log/dhcp-ldap-startup.log"; If SSL has been enabled at compile time, the dhcp server trys to use TLS if possible, but continues without TLS if not. You can modify this behaviour using following option in /etc/dhcp/dhcpd.conf: ldap-ssl off: disables TLS/LDAPS. ldaps: enables LDAPS -- don't forget to set ldap-port to 636. start_tls: enables TLS using START_TLS command on: enables LDAPS if ldap-port is set to 636 or TLS in other cases. See also "man 5 ldap.conf" for description the following TLS related options: ldap-tls-reqcert, ldap-tls-ca-file, ldap-tls-ca-dir, ldap-tls-cert ldap-tls-key, ldap-tls-crlcheck, ldap-tls-ciphers, ldap-tls-randfile All of these parameters should be self explanatory except for the ldap-method. You can set this to static or dynamic. If you set it to static, the configuration is read once on startup, and LDAP isn't used anymore. But, if you set this to dynamic, the configuration is read once on startup, and the hosts that are stored in LDAP are looked up every time a DHCP request comes in. When the optional statement ldap-debug-file is specified, on startup the DHCP server will write out the configuration that it generated from LDAP. If you are getting errors about your LDAP configuration, this is a good place to start looking. The next step is to set up your LDAP tree. Here is an example config that will give a 10.100.0.x address to machines that have a host entry in LDAP. Otherwise, it will give a 10.200.0.x address to them. (NOTE: replace dc=ntelos, dc=net with your base dn). If you would like to convert your existing dhcpd.conf file to LDIF format, there is a script dhcpd-conf-to-ldap that will convert it for you. Type dhcpd-conf-to-ldap --help to see the usage information for this script. # You must specify the server's host name in LDAP that you are going to run # DHCP on and point it to which config tree you want to use. Whenever DHCP # first starts up, it will do a search for this entry to find out which # config to use dn: cn=brian.ntelos.net, dc=ntelos, dc=net objectClass: top objectClass: dhcpServer cn: brian.ntelos.net dhcpServiceDN: cn=DHCP Service Config, dc=ntelos, dc=net # Here is the config tree that brian.ntelos.net points to. dn: cn=DHCP Service Config, dc=ntelos, dc=net cn: DHCP Service Config objectClass: top objectClass: dhcpService dhcpPrimaryDN: dc=ntelos, dc=net dhcpStatements: ddns-update-style none dhcpStatements: default-lease-time 600 dhcpStatements: max-lease-time 7200 # Set up a shared network segment dn: cn=WV Test, cn=DHCP Service Config, dc=ntelos, dc=net cn: WV objectClass: top objectClass: dhcpSharedNetwork # Set up a subnet declaration with a pool statement. Also note that we have # a dhcpOptions object with this entry dn: cn=10.100.0.0, cn=WV Test, cn=DHCP Service Config, dc=ntelos, dc=net cn: 10.100.0.0 objectClass: top objectClass: dhcpSubnet objectClass: dhcpOptions dhcpOption: domain-name-servers 10.100.0.2 dhcpOption: routers 10.100.0.1 dhcpOption: subnet-mask 255.255.255.0 dhcpOption: broadcast-address 10.100.0.255 dhcpNetMask: 24 # Set up a pool for this subnet. Only known hosts will get these IPs dn: cn=Known Pool, cn=10.100.0.0, cn=WV Test, cn=DHCP Service Config, dc=ntelos, dc=net cn: Known Pool objectClass: top objectClass: dhcpPool dhcpRange: 10.100.0.3 10.100.0.254 dhcpPermitList: deny unknown-clients # Set up another subnet declaration with a pool statement dn: cn=10.200.0.0, cn=WV Test, cn=DHCP Service Config, dc=ntelos, dc=net cn: 10.200.0.0 objectClass: top objectClass: dhcpSubnet objectClass: dhcpOptions dhcpOption: domain-name-servers 10.200.0.2 dhcpOption: routers 10.200.0.1 dhcpOption: subnet-mask 255.255.255.0 dhcpOption: broadcast-address 10.200.0.255 dhcpNetMask: 24 # Set up a pool for this subnet. Only unknown hosts will get these IPs dn: cn=Known Pool, cn=10.200.0.0, cn=WV Test, cn=DHCP Service Config, dc=ntelos, dc=net cn: Known Pool objectClass: top objectClass: dhcpPool dhcpRange: 10.200.0.3 10.200.0.254 dhcpPermitList: deny known clients # Set aside a group for all of our known MAC addresses dn: cn=Customers, cn=DHCP Service Config, dc=ntelos, dc=net objectClass: top objectClass: dhcpGroup cn: Customers # Host entry for my laptop dn: cn=brianlaptop, cn=Customers, cn=DHCP Service Config, dc=ntelos, dc=net objectClass: top objectClass: dhcpHost cn: brianlaptop dhcpHWAddress: ethernet 00:00:00:00:00:00 You can use the command ldapadd to load all of these entries into your LDAP server. After you load this, you should be able to start up DHCP. If you run into problems reading the configuration, try running dhcpd with the -d flag. If you still have problems, edit the site.conf file in the DHCP source and add the line: COPTS= -DDEBUG_LDAP and recompile DHCP. (make sure you run make clean and rerun configure before you rebuild). dhcp-4.2.4/common/alloc.c000644 000765 000024 00000064153 11301372613 015123 0ustar00sarstaff000000 000000 /* alloc.c Memory allocation... */ /* * Copyright (c) 2004-2007,2009 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1996-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ * * This software has been written for Internet Systems Consortium * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. * To learn more about Internet Systems Consortium, see * ``https://www.isc.org/''. To learn more about Vixie Enterprises, * see ``http://www.vix.com''. To learn more about Nominum, Inc., see * ``http://www.nominum.com''. */ #include "dhcpd.h" #include struct dhcp_packet *dhcp_free_list; struct packet *packet_free_list; int option_chain_head_allocate (ptr, file, line) struct option_chain_head **ptr; const char *file; int line; { struct option_chain_head *h; if (!ptr) { log_error ("%s(%d): null pointer", file, line); #if defined (POINTER_DEBUG) abort (); #else return 0; #endif } if (*ptr) { log_error ("%s(%d): non-null pointer", file, line); #if defined (POINTER_DEBUG) abort (); #else *ptr = (struct option_chain_head *)0; #endif } h = dmalloc (sizeof *h, file, line); if (h) { memset (h, 0, sizeof *h); return option_chain_head_reference (ptr, h, file, line); } return 0; } int option_chain_head_reference (ptr, bp, file, line) struct option_chain_head **ptr; struct option_chain_head *bp; const char *file; int line; { if (!ptr) { log_error ("%s(%d): null pointer", file, line); #if defined (POINTER_DEBUG) abort (); #else return 0; #endif } if (*ptr) { log_error ("%s(%d): non-null pointer", file, line); #if defined (POINTER_DEBUG) abort (); #else *ptr = (struct option_chain_head *)0; #endif } *ptr = bp; bp -> refcnt++; rc_register (file, line, ptr, bp, bp -> refcnt, 0, RC_MISC); return 1; } int option_chain_head_dereference (ptr, file, line) struct option_chain_head **ptr; const char *file; int line; { struct option_chain_head *option_chain_head; pair car, cdr; if (!ptr || !*ptr) { log_error ("%s(%d): null pointer", file, line); #if defined (POINTER_DEBUG) abort (); #else return 0; #endif } option_chain_head = *ptr; *ptr = (struct option_chain_head *)0; --option_chain_head -> refcnt; rc_register (file, line, ptr, option_chain_head, option_chain_head -> refcnt, 1, RC_MISC); if (option_chain_head -> refcnt > 0) return 1; if (option_chain_head -> refcnt < 0) { log_error ("%s(%d): negative refcnt!", file, line); #if defined (DEBUG_RC_HISTORY) dump_rc_history (option_chain_head); #endif #if defined (POINTER_DEBUG) abort (); #else return 0; #endif } /* If there are any options on this head, free them. */ for (car = option_chain_head -> first; car; car = cdr) { cdr = car -> cdr; if (car -> car) option_cache_dereference ((struct option_cache **) (&car -> car), MDL); dfree (car, MDL); car = cdr; } dfree (option_chain_head, file, line); return 1; } int group_allocate (ptr, file, line) struct group **ptr; const char *file; int line; { struct group *g; if (!ptr) { log_error ("%s(%d): null pointer", file, line); #if defined (POINTER_DEBUG) abort (); #else return 0; #endif } if (*ptr) { log_error ("%s(%d): non-null pointer", file, line); #if defined (POINTER_DEBUG) abort (); #else *ptr = (struct group *)0; #endif } g = dmalloc (sizeof *g, file, line); if (g) { memset (g, 0, sizeof *g); return group_reference (ptr, g, file, line); } return 0; } int group_reference (ptr, bp, file, line) struct group **ptr; struct group *bp; const char *file; int line; { if (!ptr) { log_error ("%s(%d): null pointer", file, line); #if defined (POINTER_DEBUG) abort (); #else return 0; #endif } if (*ptr) { log_error ("%s(%d): non-null pointer", file, line); #if defined (POINTER_DEBUG) abort (); #else *ptr = (struct group *)0; #endif } *ptr = bp; bp -> refcnt++; rc_register (file, line, ptr, bp, bp -> refcnt, 0, RC_MISC); return 1; } int group_dereference (ptr, file, line) struct group **ptr; const char *file; int line; { struct group *group; if (!ptr || !*ptr) { log_error ("%s(%d): null pointer", file, line); #if defined (POINTER_DEBUG) abort (); #else return 0; #endif } group = *ptr; *ptr = (struct group *)0; --group -> refcnt; rc_register (file, line, ptr, group, group -> refcnt, 1, RC_MISC); if (group -> refcnt > 0) return 1; if (group -> refcnt < 0) { log_error ("%s(%d): negative refcnt!", file, line); #if defined (DEBUG_RC_HISTORY) dump_rc_history (group); #endif #if defined (POINTER_DEBUG) abort (); #else return 0; #endif } if (group -> object) group_object_dereference (&group -> object, file, line); if (group -> subnet) subnet_dereference (&group -> subnet, file, line); if (group -> shared_network) shared_network_dereference (&group -> shared_network, file, line); if (group -> statements) executable_statement_dereference (&group -> statements, file, line); if (group -> next) group_dereference (&group -> next, file, line); dfree (group, file, line); return 1; } struct dhcp_packet *new_dhcp_packet (file, line) const char *file; int line; { struct dhcp_packet *rval; rval = (struct dhcp_packet *)dmalloc (sizeof (struct dhcp_packet), file, line); return rval; } struct protocol *new_protocol (file, line) const char *file; int line; { struct protocol *rval = dmalloc (sizeof (struct protocol), file, line); return rval; } struct domain_search_list *new_domain_search_list (file, line) const char *file; int line; { struct domain_search_list *rval = dmalloc (sizeof (struct domain_search_list), file, line); return rval; } struct name_server *new_name_server (file, line) const char *file; int line; { struct name_server *rval = dmalloc (sizeof (struct name_server), file, line); return rval; } void free_name_server (ptr, file, line) struct name_server *ptr; const char *file; int line; { dfree ((void *)ptr, file, line); } struct option *new_option (name, file, line) const char *name; const char *file; int line; { struct option *rval; int len; len = strlen(name); rval = dmalloc(sizeof(struct option) + len + 1, file, line); if(rval) { memcpy(rval + 1, name, len); rval->name = (char *)(rval + 1); } return rval; } struct universe *new_universe (file, line) const char *file; int line; { struct universe *rval = dmalloc (sizeof (struct universe), file, line); return rval; } void free_universe (ptr, file, line) struct universe *ptr; const char *file; int line; { dfree ((void *)ptr, file, line); } void free_domain_search_list (ptr, file, line) struct domain_search_list *ptr; const char *file; int line; { dfree ((void *)ptr, file, line); } void free_protocol (ptr, file, line) struct protocol *ptr; const char *file; int line; { dfree ((void *)ptr, file, line); } void free_dhcp_packet (ptr, file, line) struct dhcp_packet *ptr; const char *file; int line; { dfree ((void *)ptr, file, line); } struct client_lease *new_client_lease (file, line) const char *file; int line; { return (struct client_lease *)dmalloc (sizeof (struct client_lease), file, line); } void free_client_lease (lease, file, line) struct client_lease *lease; const char *file; int line; { dfree (lease, file, line); } pair free_pairs; pair new_pair (file, line) const char *file; int line; { pair foo; if (free_pairs) { foo = free_pairs; free_pairs = foo -> cdr; memset (foo, 0, sizeof *foo); dmalloc_reuse (foo, file, line, 0); return foo; } foo = dmalloc (sizeof *foo, file, line); if (!foo) return foo; memset (foo, 0, sizeof *foo); return foo; } void free_pair (foo, file, line) pair foo; const char *file; int line; { foo -> cdr = free_pairs; free_pairs = foo; dmalloc_reuse (free_pairs, __FILE__, __LINE__, 0); } #if defined (DEBUG_MEMORY_LEAKAGE) || \ defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT) void relinquish_free_pairs () { pair pf, pc; for (pf = free_pairs; pf; pf = pc) { pc = pf -> cdr; dfree (pf, MDL); } free_pairs = (pair)0; } #endif struct expression *free_expressions; int expression_allocate (cptr, file, line) struct expression **cptr; const char *file; int line; { struct expression *rval; if (free_expressions) { rval = free_expressions; free_expressions = rval -> data.not; dmalloc_reuse (rval, file, line, 1); } else { rval = dmalloc (sizeof (struct expression), file, line); if (!rval) return 0; } memset (rval, 0, sizeof *rval); return expression_reference (cptr, rval, file, line); } int expression_reference (ptr, src, file, line) struct expression **ptr; struct expression *src; const char *file; int line; { if (!ptr) { log_error ("%s(%d): null pointer", file, line); #if defined (POINTER_DEBUG) abort (); #else return 0; #endif } if (*ptr) { log_error ("%s(%d): non-null pointer", file, line); #if defined (POINTER_DEBUG) abort (); #else *ptr = (struct expression *)0; #endif } *ptr = src; src -> refcnt++; rc_register (file, line, ptr, src, src -> refcnt, 0, RC_MISC); return 1; } void free_expression (expr, file, line) struct expression *expr; const char *file; int line; { expr -> data.not = free_expressions; free_expressions = expr; dmalloc_reuse (free_expressions, __FILE__, __LINE__, 0); } #if defined (DEBUG_MEMORY_LEAKAGE) || \ defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT) void relinquish_free_expressions () { struct expression *e, *n; for (e = free_expressions; e; e = n) { n = e -> data.not; dfree (e, MDL); } free_expressions = (struct expression *)0; } #endif struct binding_value *free_binding_values; int binding_value_allocate (cptr, file, line) struct binding_value **cptr; const char *file; int line; { struct binding_value *rval; if (free_binding_values) { rval = free_binding_values; free_binding_values = rval -> value.bv; dmalloc_reuse (rval, file, line, 1); } else { rval = dmalloc (sizeof (struct binding_value), file, line); if (!rval) return 0; } memset (rval, 0, sizeof *rval); return binding_value_reference (cptr, rval, file, line); } int binding_value_reference (ptr, src, file, line) struct binding_value **ptr; struct binding_value *src; const char *file; int line; { if (!ptr) { log_error ("%s(%d): null pointer", file, line); #if defined (POINTER_DEBUG) abort (); #else return 0; #endif } if (*ptr) { log_error ("%s(%d): non-null pointer", file, line); #if defined (POINTER_DEBUG) abort (); #else *ptr = (struct binding_value *)0; #endif } *ptr = src; src -> refcnt++; rc_register (file, line, ptr, src, src -> refcnt, 0, RC_MISC); return 1; } void free_binding_value (bv, file, line) struct binding_value *bv; const char *file; int line; { bv -> value.bv = free_binding_values; free_binding_values = bv; dmalloc_reuse (free_binding_values, (char *)0, 0, 0); } #if defined (DEBUG_MEMORY_LEAKAGE) || \ defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT) void relinquish_free_binding_values () { struct binding_value *b, *n; for (b = free_binding_values; b; b = n) { n = b -> value.bv; dfree (b, MDL); } free_binding_values = (struct binding_value *)0; } #endif int fundef_allocate (cptr, file, line) struct fundef **cptr; const char *file; int line; { struct fundef *rval; rval = dmalloc (sizeof (struct fundef), file, line); if (!rval) return 0; memset (rval, 0, sizeof *rval); return fundef_reference (cptr, rval, file, line); } int fundef_reference (ptr, src, file, line) struct fundef **ptr; struct fundef *src; const char *file; int line; { if (!ptr) { log_error ("%s(%d): null pointer", file, line); #if defined (POINTER_DEBUG) abort (); #else return 0; #endif } if (*ptr) { log_error ("%s(%d): non-null pointer", file, line); #if defined (POINTER_DEBUG) abort (); #else *ptr = (struct fundef *)0; #endif } *ptr = src; src -> refcnt++; rc_register (file, line, ptr, src, src -> refcnt, 0, RC_MISC); return 1; } struct option_cache *free_option_caches; #if defined (DEBUG_MEMORY_LEAKAGE) || \ defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT) void relinquish_free_option_caches () { struct option_cache *o, *n; for (o = free_option_caches; o; o = n) { n = (struct option_cache *)(o -> expression); dfree (o, MDL); } free_option_caches = (struct option_cache *)0; } #endif int option_cache_allocate (cptr, file, line) struct option_cache **cptr; const char *file; int line; { struct option_cache *rval; if (free_option_caches) { rval = free_option_caches; free_option_caches = (struct option_cache *)(rval -> expression); dmalloc_reuse (rval, file, line, 0); } else { rval = dmalloc (sizeof (struct option_cache), file, line); if (!rval) return 0; } memset (rval, 0, sizeof *rval); return option_cache_reference (cptr, rval, file, line); } int option_cache_reference (ptr, src, file, line) struct option_cache **ptr; struct option_cache *src; const char *file; int line; { if (!ptr) { log_error ("%s(%d): null pointer", file, line); #if defined (POINTER_DEBUG) abort (); #else return 0; #endif } if (*ptr) { log_error ("%s(%d): non-null pointer", file, line); #if defined (POINTER_DEBUG) abort (); #else *ptr = (struct option_cache *)0; #endif } *ptr = src; src -> refcnt++; rc_register (file, line, ptr, src, src -> refcnt, 0, RC_MISC); return 1; } int buffer_allocate (ptr, len, file, line) struct buffer **ptr; unsigned len; const char *file; int line; { struct buffer *bp; /* XXXSK: should check for bad ptr values, otherwise we leak memory if they are wrong */ bp = dmalloc (len + sizeof *bp, file, line); if (!bp) return 0; /* XXXSK: both of these initializations are unnecessary */ memset (bp, 0, sizeof *bp); bp -> refcnt = 0; return buffer_reference (ptr, bp, file, line); } int buffer_reference (ptr, bp, file, line) struct buffer **ptr; struct buffer *bp; const char *file; int line; { if (!ptr) { log_error ("%s(%d): null pointer", file, line); #if defined (POINTER_DEBUG) abort (); #else return 0; #endif } if (*ptr) { log_error ("%s(%d): non-null pointer", file, line); #if defined (POINTER_DEBUG) abort (); #else *ptr = (struct buffer *)0; #endif } *ptr = bp; bp -> refcnt++; rc_register (file, line, ptr, bp, bp -> refcnt, 0, RC_MISC); return 1; } int buffer_dereference (ptr, file, line) struct buffer **ptr; const char *file; int line; { if (!ptr) { log_error ("%s(%d): null pointer", file, line); #if defined (POINTER_DEBUG) abort (); #else return 0; #endif } if (!*ptr) { log_error ("%s(%d): null pointer", file, line); #if defined (POINTER_DEBUG) abort (); #else return 0; #endif } (*ptr) -> refcnt--; rc_register (file, line, ptr, *ptr, (*ptr) -> refcnt, 1, RC_MISC); if (!(*ptr) -> refcnt) { dfree ((*ptr), file, line); } else if ((*ptr) -> refcnt < 0) { log_error ("%s(%d): negative refcnt!", file, line); #if defined (DEBUG_RC_HISTORY) dump_rc_history (*ptr); #endif #if defined (POINTER_DEBUG) abort (); #else return 0; #endif } *ptr = (struct buffer *)0; return 1; } int dns_host_entry_allocate (ptr, hostname, file, line) struct dns_host_entry **ptr; const char *hostname; const char *file; int line; { struct dns_host_entry *bp; bp = dmalloc (strlen (hostname) + sizeof *bp, file, line); if (!bp) return 0; memset (bp, 0, sizeof *bp); bp -> refcnt = 0; strcpy (bp -> hostname, hostname); return dns_host_entry_reference (ptr, bp, file, line); } int dns_host_entry_reference (ptr, bp, file, line) struct dns_host_entry **ptr; struct dns_host_entry *bp; const char *file; int line; { if (!ptr) { log_error ("%s(%d): null pointer", file, line); #if defined (POINTER_DEBUG) abort (); #else return 0; #endif } if (*ptr) { log_error ("%s(%d): non-null pointer", file, line); #if defined (POINTER_DEBUG) abort (); #else *ptr = (struct dns_host_entry *)0; #endif } *ptr = bp; bp -> refcnt++; rc_register (file, line, ptr, bp, bp -> refcnt, 0, RC_MISC); return 1; } int dns_host_entry_dereference (ptr, file, line) struct dns_host_entry **ptr; const char *file; int line; { if (!ptr || !*ptr) { log_error ("%s(%d): null pointer", file, line); #if defined (POINTER_DEBUG) abort (); #else return 0; #endif } (*ptr) -> refcnt--; rc_register (file, line, ptr, *ptr, (*ptr) -> refcnt, 1, RC_MISC); if (!(*ptr) -> refcnt) dfree ((*ptr), file, line); if ((*ptr) -> refcnt < 0) { log_error ("%s(%d): negative refcnt!", file, line); #if defined (DEBUG_RC_HISTORY) dump_rc_history (*ptr); #endif #if defined (POINTER_DEBUG) abort (); #else return 0; #endif } *ptr = (struct dns_host_entry *)0; return 1; } int option_state_allocate (ptr, file, line) struct option_state **ptr; const char *file; int line; { unsigned size; if (!ptr) { log_error ("%s(%d): null pointer", file, line); #if defined (POINTER_DEBUG) abort (); #else return 0; #endif } if (*ptr) { log_error ("%s(%d): non-null pointer", file, line); #if defined (POINTER_DEBUG) abort (); #else *ptr = (struct option_state *)0; #endif } size = sizeof **ptr + (universe_count - 1) * sizeof (void *); *ptr = dmalloc (size, file, line); if (*ptr) { memset (*ptr, 0, size); (*ptr) -> universe_count = universe_count; (*ptr) -> refcnt = 1; rc_register (file, line, ptr, *ptr, (*ptr) -> refcnt, 0, RC_MISC); return 1; } return 0; } int option_state_reference (ptr, bp, file, line) struct option_state **ptr; struct option_state *bp; const char *file; int line; { if (!ptr) { log_error ("%s(%d): null pointer", file, line); #if defined (POINTER_DEBUG) abort (); #else return 0; #endif } if (*ptr) { log_error ("%s(%d): non-null pointer", file, line); #if defined (POINTER_DEBUG) abort (); #else *ptr = (struct option_state *)0; #endif } *ptr = bp; bp -> refcnt++; rc_register (file, line, ptr, bp, bp -> refcnt, 0, RC_MISC); return 1; } int option_state_dereference (ptr, file, line) struct option_state **ptr; const char *file; int line; { int i; struct option_state *options; if (!ptr || !*ptr) { log_error ("%s(%d): null pointer", file, line); #if defined (POINTER_DEBUG) abort (); #else return 0; #endif } options = *ptr; *ptr = (struct option_state *)0; --options -> refcnt; rc_register (file, line, ptr, options, options -> refcnt, 1, RC_MISC); if (options -> refcnt > 0) return 1; if (options -> refcnt < 0) { log_error ("%s(%d): negative refcnt!", file, line); #if defined (DEBUG_RC_HISTORY) dump_rc_history (options); #endif #if defined (POINTER_DEBUG) abort (); #else return 0; #endif } /* Loop through the per-universe state. */ for (i = 0; i < options -> universe_count; i++) if (options -> universes [i] && universes [i] -> option_state_dereference) ((*(universes [i] -> option_state_dereference)) (universes [i], options, file, line)); dfree (options, file, line); return 1; } int executable_statement_allocate (ptr, file, line) struct executable_statement **ptr; const char *file; int line; { struct executable_statement *bp; bp = dmalloc (sizeof *bp, file, line); if (!bp) return 0; memset (bp, 0, sizeof *bp); return executable_statement_reference (ptr, bp, file, line); } int executable_statement_reference (ptr, bp, file, line) struct executable_statement **ptr; struct executable_statement *bp; const char *file; int line; { if (!ptr) { log_error ("%s(%d): null pointer", file, line); #if defined (POINTER_DEBUG) abort (); #else return 0; #endif } if (*ptr) { log_error ("%s(%d): non-null pointer", file, line); #if defined (POINTER_DEBUG) abort (); #else *ptr = (struct executable_statement *)0; #endif } *ptr = bp; bp -> refcnt++; rc_register (file, line, ptr, bp, bp -> refcnt, 0, RC_MISC); return 1; } static struct packet *free_packets; #if defined (DEBUG_MEMORY_LEAKAGE) || \ defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT) void relinquish_free_packets () { struct packet *p, *n; for (p = free_packets; p; p = n) { n = (struct packet *)(p -> raw); dfree (p, MDL); } free_packets = (struct packet *)0; } #endif int packet_allocate (ptr, file, line) struct packet **ptr; const char *file; int line; { struct packet *p; if (!ptr) { log_error ("%s(%d): null pointer", file, line); #if defined (POINTER_DEBUG) abort (); #else return 0; #endif } if (*ptr) { log_error ("%s(%d): non-null pointer", file, line); #if defined (POINTER_DEBUG) abort (); #else *ptr = (struct packet *)0; #endif } if (free_packets) { p = free_packets; free_packets = (struct packet *)(p -> raw); dmalloc_reuse (p, file, line, 1); } else { p = dmalloc (sizeof *p, file, line); } if (p) { memset (p, 0, sizeof *p); return packet_reference (ptr, p, file, line); } return 0; } int packet_reference (ptr, bp, file, line) struct packet **ptr; struct packet *bp; const char *file; int line; { if (!ptr) { log_error ("%s(%d): null pointer", file, line); #if defined (POINTER_DEBUG) abort (); #else return 0; #endif } if (*ptr) { log_error ("%s(%d): non-null pointer", file, line); #if defined (POINTER_DEBUG) abort (); #else *ptr = (struct packet *)0; #endif } *ptr = bp; bp -> refcnt++; rc_register (file, line, ptr, bp, bp -> refcnt, 0, RC_MISC); return 1; } int packet_dereference (ptr, file, line) struct packet **ptr; const char *file; int line; { int i; struct packet *packet; if (!ptr || !*ptr) { log_error ("%s(%d): null pointer", file, line); #if defined (POINTER_DEBUG) abort (); #else return 0; #endif } packet = *ptr; *ptr = (struct packet *)0; --packet -> refcnt; rc_register (file, line, ptr, packet, packet -> refcnt, 1, RC_MISC); if (packet -> refcnt > 0) return 1; if (packet -> refcnt < 0) { log_error ("%s(%d): negative refcnt!", file, line); #if defined (DEBUG_RC_HISTORY) dump_rc_history (packet); #endif #if defined (POINTER_DEBUG) abort (); #else return 0; #endif } if (packet -> options) option_state_dereference (&packet -> options, file, line); if (packet -> interface) interface_dereference (&packet -> interface, MDL); if (packet -> shared_network) shared_network_dereference (&packet -> shared_network, MDL); for (i = 0; i < packet -> class_count && i < PACKET_MAX_CLASSES; i++) { if (packet -> classes [i]) omapi_object_dereference ((omapi_object_t **) &packet -> classes [i], MDL); } packet -> raw = (struct dhcp_packet *)free_packets; free_packets = packet; dmalloc_reuse (free_packets, __FILE__, __LINE__, 0); return 1; } int dns_zone_allocate (ptr, file, line) struct dns_zone **ptr; const char *file; int line; { struct dns_zone *d; if (!ptr) { log_error ("%s(%d): null pointer", file, line); #if defined (POINTER_DEBUG) abort (); #else return 0; #endif } if (*ptr) { log_error ("%s(%d): non-null pointer", file, line); #if defined (POINTER_DEBUG) abort (); #else *ptr = (struct dns_zone *)0; #endif } d = dmalloc (sizeof *d, file, line); if (d) { memset (d, 0, sizeof *d); return dns_zone_reference (ptr, d, file, line); } return 0; } int dns_zone_reference (ptr, bp, file, line) struct dns_zone **ptr; struct dns_zone *bp; const char *file; int line; { if (!ptr) { log_error ("%s(%d): null pointer", file, line); #if defined (POINTER_DEBUG) abort (); #else return 0; #endif } if (*ptr) { log_error ("%s(%d): non-null pointer", file, line); #if defined (POINTER_DEBUG) abort (); #else *ptr = (struct dns_zone *)0; #endif } *ptr = bp; bp -> refcnt++; rc_register (file, line, ptr, bp, bp -> refcnt, 0, RC_MISC); return 1; } int binding_scope_allocate (ptr, file, line) struct binding_scope **ptr; const char *file; int line; { struct binding_scope *bp; if (!ptr) { log_error ("%s(%d): null pointer", file, line); #if defined (POINTER_DEBUG) abort (); #else return 0; #endif } if (*ptr) { log_error ("%s(%d): non-null pointer", file, line); #if defined (POINTER_DEBUG) abort (); #else return 0; #endif } bp = dmalloc (sizeof *bp, file, line); if (!bp) return 0; memset (bp, 0, sizeof *bp); binding_scope_reference (ptr, bp, file, line); return 1; } int binding_scope_reference (ptr, bp, file, line) struct binding_scope **ptr; struct binding_scope *bp; const char *file; int line; { if (!ptr) { log_error ("%s(%d): null pointer", file, line); #if defined (POINTER_DEBUG) abort (); #else return 0; #endif } if (*ptr) { log_error ("%s(%d): non-null pointer", file, line); #if defined (POINTER_DEBUG) abort (); #else *ptr = (struct binding_scope *)0; #endif } *ptr = bp; bp -> refcnt++; rc_register (file, line, ptr, bp, bp -> refcnt, 0, RC_MISC); return 1; } /* Make a copy of the data in data_string, upping the buffer reference count if there's a buffer. */ void data_string_copy(struct data_string *dest, const struct data_string *src, const char *file, int line) { if (src -> buffer) { buffer_reference (&dest -> buffer, src -> buffer, file, line); } else { dest->buffer = NULL; } dest -> data = src -> data; dest -> terminated = src -> terminated; dest -> len = src -> len; } /* Release the reference count to a data string's buffer (if any) and zero out the other information, yielding the null data string. */ void data_string_forget (data, file, line) struct data_string *data; const char *file; int line; { if (data -> buffer) buffer_dereference (&data -> buffer, file, line); memset (data, 0, sizeof *data); } /* If the data_string is larger than the specified length, reduce the data_string to the specified size. */ void data_string_truncate (dp, len) struct data_string *dp; int len; { /* XXX: do we need to consider the "terminated" flag in the check? */ if (len < dp -> len) { dp -> terminated = 0; dp -> len = len; } } dhcp-4.2.4/common/bpf.c000644 000765 000024 00000042635 11301372613 014601 0ustar00sarstaff000000 000000 /* bpf.c BPF socket interface code, originally contributed by Archie Cobbs. */ /* * Copyright (c) 2004,2007,2009 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1996-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ * * This software was contributed to Internet Systems Consortium * by Archie Cobbs. * * Patches for FDDI support on Digital Unix were written by Bill * Stapleton, and maintained for a while by Mike Meredith before he * managed to get me to integrate them. */ #include "dhcpd.h" #if defined (USE_BPF_SEND) || defined (USE_BPF_RECEIVE) \ || defined (USE_LPF_RECEIVE) # if defined (USE_LPF_RECEIVE) # include # include # define bpf_insn sock_filter /* Linux: dare to be gratuitously different. */ # else # include # include # include # include # if defined (NEED_OSF_PFILT_HACKS) # include # endif # endif #include #include "includes/netinet/ip.h" #include "includes/netinet/udp.h" #include "includes/netinet/if_ether.h" #endif #ifdef USE_BPF_RECEIVE #include #endif #include /* Reinitializes the specified interface after an address change. This is not required for packet-filter APIs. */ #ifdef USE_BPF_SEND void if_reinitialize_send (info) struct interface_info *info; { } #endif #ifdef USE_BPF_RECEIVE void if_reinitialize_receive (info) struct interface_info *info; { } #endif /* Called by get_interface_list for each interface that's discovered. Opens a packet filter for each interface and adds it to the select mask. */ #if defined (USE_BPF_SEND) || defined (USE_BPF_RECEIVE) int if_register_bpf (info) struct interface_info *info; { int sock; char filename[50]; int b; /* Open a BPF device */ for (b = 0; 1; b++) { /* %Audit% 31 bytes max. %2004.06.17,Safe% */ sprintf(filename, BPF_FORMAT, b); sock = open (filename, O_RDWR, 0); if (sock < 0) { if (errno == EBUSY) { continue; } else { if (!b) log_fatal ("No bpf devices.%s%s%s", " Please read the README", " section for your operating", " system."); log_fatal ("Can't find free bpf: %m"); } } else { break; } } /* Set the BPF device to point at this interface. */ if (ioctl (sock, BIOCSETIF, info -> ifp) < 0) log_fatal ("Can't attach interface %s to bpf device %s: %m", info -> name, filename); get_hw_addr(info->name, &info->hw_address); return sock; } #endif /* USE_BPF_SEND || USE_BPF_RECEIVE */ #ifdef USE_BPF_SEND void if_register_send (info) struct interface_info *info; { /* If we're using the bpf API for sending and receiving, we don't need to register this interface twice. */ #ifndef USE_BPF_RECEIVE info -> wfdesc = if_register_bpf (info, interface); #else info -> wfdesc = info -> rfdesc; #endif if (!quiet_interface_discovery) log_info ("Sending on BPF/%s/%s%s%s", info -> name, print_hw_addr (info -> hw_address.hbuf [0], info -> hw_address.hlen - 1, &info -> hw_address.hbuf [1]), (info -> shared_network ? "/" : ""), (info -> shared_network ? info -> shared_network -> name : "")); } void if_deregister_send (info) struct interface_info *info; { /* If we're using the bpf API for sending and receiving, we don't need to register this interface twice. */ #ifndef USE_BPF_RECEIVE close (info -> wfdesc); #endif info -> wfdesc = -1; if (!quiet_interface_discovery) log_info ("Disabling output on BPF/%s/%s%s%s", info -> name, print_hw_addr (info -> hw_address.hbuf [0], info -> hw_address.hlen - 1, &info -> hw_address.hbuf [1]), (info -> shared_network ? "/" : ""), (info -> shared_network ? info -> shared_network -> name : "")); } #endif /* USE_BPF_SEND */ #if defined (USE_BPF_RECEIVE) || defined (USE_LPF_RECEIVE) /* Packet filter program... XXX Changes to the filter program may require changes to the constant offsets used in if_register_send to patch the BPF program! XXX */ struct bpf_insn dhcp_bpf_filter [] = { /* Make sure this is an IP packet... */ BPF_STMT (BPF_LD + BPF_H + BPF_ABS, 12), BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_IP, 0, 8), /* Make sure it's a UDP packet... */ BPF_STMT (BPF_LD + BPF_B + BPF_ABS, 23), BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 0, 6), /* Make sure this isn't a fragment... */ BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 20), BPF_JUMP(BPF_JMP + BPF_JSET + BPF_K, 0x1fff, 4, 0), /* Get the IP header length... */ BPF_STMT (BPF_LDX + BPF_B + BPF_MSH, 14), /* Make sure it's to the right port... */ BPF_STMT (BPF_LD + BPF_H + BPF_IND, 16), BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, 67, 0, 1), /* patch */ /* If we passed all the tests, ask for the whole packet. */ BPF_STMT(BPF_RET+BPF_K, (u_int)-1), /* Otherwise, drop it. */ BPF_STMT(BPF_RET+BPF_K, 0), }; #if defined (DEC_FDDI) struct bpf_insn *bpf_fddi_filter; #endif int dhcp_bpf_filter_len = sizeof dhcp_bpf_filter / sizeof (struct bpf_insn); #if defined (HAVE_TR_SUPPORT) struct bpf_insn dhcp_bpf_tr_filter [] = { /* accept all token ring packets due to variable length header */ /* if we want to get clever, insert the program here */ /* If we passed all the tests, ask for the whole packet. */ BPF_STMT(BPF_RET+BPF_K, (u_int)-1), /* Otherwise, drop it. */ BPF_STMT(BPF_RET+BPF_K, 0), }; int dhcp_bpf_tr_filter_len = (sizeof dhcp_bpf_tr_filter / sizeof (struct bpf_insn)); #endif /* HAVE_TR_SUPPORT */ #endif /* USE_LPF_RECEIVE || USE_BPF_RECEIVE */ #if defined (USE_BPF_RECEIVE) void if_register_receive (info) struct interface_info *info; { int flag = 1; struct bpf_version v; struct bpf_program p; #ifdef NEED_OSF_PFILT_HACKS u_int32_t bits; #endif #ifdef DEC_FDDI int link_layer; #endif /* DEC_FDDI */ /* Open a BPF device and hang it on this interface... */ info -> rfdesc = if_register_bpf (info); /* Make sure the BPF version is in range... */ if (ioctl (info -> rfdesc, BIOCVERSION, &v) < 0) log_fatal ("Can't get BPF version: %m"); if (v.bv_major != BPF_MAJOR_VERSION || v.bv_minor < BPF_MINOR_VERSION) log_fatal ("BPF version mismatch - recompile DHCP!"); /* Set immediate mode so that reads return as soon as a packet comes in, rather than waiting for the input buffer to fill with packets. */ if (ioctl (info -> rfdesc, BIOCIMMEDIATE, &flag) < 0) log_fatal ("Can't set immediate mode on bpf device: %m"); #ifdef NEED_OSF_PFILT_HACKS /* Allow the copyall flag to be set... */ if (ioctl(info -> rfdesc, EIOCALLOWCOPYALL, &flag) < 0) log_fatal ("Can't set ALLOWCOPYALL: %m"); /* Clear all the packet filter mode bits first... */ bits = 0; if (ioctl (info -> rfdesc, EIOCMBIS, &bits) < 0) log_fatal ("Can't clear pfilt bits: %m"); /* Set the ENBATCH, ENCOPYALL, ENBPFHDR bits... */ bits = ENBATCH | ENCOPYALL | ENBPFHDR; if (ioctl (info -> rfdesc, EIOCMBIS, &bits) < 0) log_fatal ("Can't set ENBATCH|ENCOPYALL|ENBPFHDR: %m"); #endif /* Get the required BPF buffer length from the kernel. */ if (ioctl (info -> rfdesc, BIOCGBLEN, &info -> rbuf_max) < 0) log_fatal ("Can't get bpf buffer length: %m"); info -> rbuf = dmalloc (info -> rbuf_max, MDL); if (!info -> rbuf) log_fatal ("Can't allocate %ld bytes for bpf input buffer.", (long)(info -> rbuf_max)); info -> rbuf_offset = 0; info -> rbuf_len = 0; /* Set up the bpf filter program structure. */ p.bf_len = dhcp_bpf_filter_len; #ifdef DEC_FDDI /* See if this is an FDDI interface, flag it for later. */ if (ioctl(info -> rfdesc, BIOCGDLT, &link_layer) >= 0 && link_layer == DLT_FDDI) { if (!bpf_fddi_filter) { bpf_fddi_filter = dmalloc (sizeof bpf_fddi_filter, MDL); if (!bpf_fddi_filter) log_fatal ("No memory for FDDI filter."); memcpy (bpf_fddi_filter, dhcp_bpf_filter, sizeof dhcp_bpf_filter); /* Patch the BPF program to account for the difference in length between ethernet headers (14), FDDI and 802.2 headers (16 +8=24, +10). XXX changes to filter program may require changes to XXX the insn number(s) used below! */ bpf_fddi_filter[0].k += 10; bpf_fddi_filter[2].k += 10; bpf_fddi_filter[4].k += 10; bpf_fddi_filter[6].k += 10; bpf_fddi_filter[7].k += 10; } p.bf_insns = bpf_fddi_filter; } else #endif /* DEC_FDDI */ p.bf_insns = dhcp_bpf_filter; /* Patch the server port into the BPF program... XXX changes to filter program may require changes to the insn number(s) used below! XXX */ dhcp_bpf_filter [8].k = ntohs (local_port); if (ioctl (info -> rfdesc, BIOCSETF, &p) < 0) log_fatal ("Can't install packet filter program: %m"); if (!quiet_interface_discovery) log_info ("Listening on BPF/%s/%s%s%s", info -> name, print_hw_addr (info -> hw_address.hbuf [0], info -> hw_address.hlen - 1, &info -> hw_address.hbuf [1]), (info -> shared_network ? "/" : ""), (info -> shared_network ? info -> shared_network -> name : "")); } void if_deregister_receive (info) struct interface_info *info; { close (info -> rfdesc); info -> rfdesc = -1; if (!quiet_interface_discovery) log_info ("Disabling input on BPF/%s/%s%s%s", info -> name, print_hw_addr (info -> hw_address.hbuf [0], info -> hw_address.hlen - 1, &info -> hw_address.hbuf [1]), (info -> shared_network ? "/" : ""), (info -> shared_network ? info -> shared_network -> name : "")); } #endif /* USE_BPF_RECEIVE */ #ifdef USE_BPF_SEND ssize_t send_packet (interface, packet, raw, len, from, to, hto) struct interface_info *interface; struct packet *packet; struct dhcp_packet *raw; size_t len; struct in_addr from; struct sockaddr_in *to; struct hardware *hto; { unsigned hbufp = 0, ibufp = 0; double hw [4]; double ip [32]; struct iovec iov [3]; int result; if (!strcmp (interface -> name, "fallback")) return send_fallback (interface, packet, raw, len, from, to, hto); if (hto == NULL && interface->anycast_mac_addr.hlen) hto = &interface->anycast_mac_addr; /* Assemble the headers... */ assemble_hw_header (interface, (unsigned char *)hw, &hbufp, hto); assemble_udp_ip_header (interface, (unsigned char *)ip, &ibufp, from.s_addr, to -> sin_addr.s_addr, to -> sin_port, (unsigned char *)raw, len); /* Fire it off */ iov [0].iov_base = ((char *)hw); iov [0].iov_len = hbufp; iov [1].iov_base = ((char *)ip); iov [1].iov_len = ibufp; iov [2].iov_base = (char *)raw; iov [2].iov_len = len; result = writev(interface -> wfdesc, iov, 3); if (result < 0) log_error ("send_packet: %m"); return result; } #endif /* USE_BPF_SEND */ #ifdef USE_BPF_RECEIVE ssize_t receive_packet (interface, buf, len, from, hfrom) struct interface_info *interface; unsigned char *buf; size_t len; struct sockaddr_in *from; struct hardware *hfrom; { int length = 0; int offset = 0; struct bpf_hdr hdr; unsigned paylen; /* All this complexity is because BPF doesn't guarantee that only one packet will be returned at a time. We're getting what we deserve, though - this is a terrible abuse of the BPF interface. Sigh. */ /* Process packets until we get one we can return or until we've done a read and gotten nothing we can return... */ do { /* If the buffer is empty, fill it. */ if (interface -> rbuf_offset == interface -> rbuf_len) { length = read (interface -> rfdesc, interface -> rbuf, (size_t)interface -> rbuf_max); if (length <= 0) { #ifdef __FreeBSD__ if (errno == ENXIO) { #else if (errno == EIO) { #endif dhcp_interface_remove ((omapi_object_t *)interface, (omapi_object_t *)0); } return length; } interface -> rbuf_offset = 0; interface -> rbuf_len = BPF_WORDALIGN (length); } /* If there isn't room for a whole bpf header, something went wrong, but we'll ignore it and hope it goes away... XXX */ if (interface -> rbuf_len - interface -> rbuf_offset < sizeof hdr) { interface -> rbuf_offset = interface -> rbuf_len; continue; } /* Copy out a bpf header... */ memcpy (&hdr, &interface -> rbuf [interface -> rbuf_offset], sizeof hdr); /* If the bpf header plus data doesn't fit in what's left of the buffer, stick head in sand yet again... */ if (interface -> rbuf_offset + hdr.bh_hdrlen + hdr.bh_caplen > interface -> rbuf_len) { interface -> rbuf_offset = interface -> rbuf_len; continue; } /* If the captured data wasn't the whole packet, or if the packet won't fit in the input buffer, all we can do is drop it. */ if (hdr.bh_caplen != hdr.bh_datalen) { interface -> rbuf_offset = BPF_WORDALIGN (interface -> rbuf_offset + hdr.bh_hdrlen + hdr.bh_caplen); continue; } /* Skip over the BPF header... */ interface -> rbuf_offset += hdr.bh_hdrlen; /* Decode the physical header... */ offset = decode_hw_header (interface, interface -> rbuf, interface -> rbuf_offset, hfrom); /* If a physical layer checksum failed (dunno of any physical layer that supports this, but WTH), skip this packet. */ if (offset < 0) { interface -> rbuf_offset = BPF_WORDALIGN (interface -> rbuf_offset + hdr.bh_caplen); continue; } interface -> rbuf_offset += offset; hdr.bh_caplen -= offset; /* Decode the IP and UDP headers... */ offset = decode_udp_ip_header (interface, interface -> rbuf, interface -> rbuf_offset, from, hdr.bh_caplen, &paylen); /* If the IP or UDP checksum was bad, skip the packet... */ if (offset < 0) { interface -> rbuf_offset = BPF_WORDALIGN (interface -> rbuf_offset + hdr.bh_caplen); continue; } interface -> rbuf_offset = interface -> rbuf_offset + offset; hdr.bh_caplen -= offset; /* If there's not enough room to stash the packet data, we have to skip it (this shouldn't happen in real life, though). */ if (hdr.bh_caplen > len) { interface -> rbuf_offset = BPF_WORDALIGN (interface -> rbuf_offset + hdr.bh_caplen); continue; } /* Copy out the data in the packet... */ memcpy(buf, interface->rbuf + interface->rbuf_offset, paylen); interface -> rbuf_offset = BPF_WORDALIGN (interface -> rbuf_offset + hdr.bh_caplen); return paylen; } while (!length); return 0; } int can_unicast_without_arp (ip) struct interface_info *ip; { return 1; } int can_receive_unicast_unconfigured (ip) struct interface_info *ip; { return 1; } int supports_multiple_interfaces (ip) struct interface_info *ip; { return 1; } void maybe_setup_fallback () { isc_result_t status; struct interface_info *fbi = (struct interface_info *)0; if (setup_fallback (&fbi, MDL)) { if_register_fallback (fbi); status = omapi_register_io_object ((omapi_object_t *)fbi, if_readsocket, 0, fallback_discard, 0, 0); if (status != ISC_R_SUCCESS) log_fatal ("Can't register I/O handle for %s: %s", fbi -> name, isc_result_totext (status)); interface_dereference (&fbi, MDL); } } void get_hw_addr(const char *name, struct hardware *hw) { struct ifaddrs *ifa; struct ifaddrs *p; struct sockaddr_dl *sa; if (getifaddrs(&ifa) != 0) { log_fatal("Error getting interface information; %m"); } /* * Loop through our interfaces finding a match. */ sa = NULL; for (p=ifa; (p != NULL) && (sa == NULL); p = p->ifa_next) { if ((p->ifa_addr->sa_family == AF_LINK) && !strcmp(p->ifa_name, name)) { sa = (struct sockaddr_dl *)p->ifa_addr; } } if (sa == NULL) { log_fatal("No interface called '%s'", name); } /* * Pull out the appropriate information. */ switch (sa->sdl_type) { case IFT_ETHER: hw->hlen = sa->sdl_alen + 1; hw->hbuf[0] = HTYPE_ETHER; memcpy(&hw->hbuf[1], LLADDR(sa), sa->sdl_alen); break; case IFT_ISO88023: case IFT_ISO88024: /* "token ring" */ case IFT_ISO88025: case IFT_ISO88026: hw->hlen = sa->sdl_alen + 1; hw->hbuf[0] = HTYPE_IEEE802; memcpy(&hw->hbuf[1], LLADDR(sa), sa->sdl_alen); break; #ifdef IFT_FDDI case IFT_FDDI: hw->hlen = sa->sdl_alen + 1; hw->hbuf[0] = HTYPE_FDDI; memcpy(&hw->hbuf[1], LLADDR(sa), sa->sdl_alen); break; #endif /* IFT_FDDI */ default: log_fatal("Unsupported device type %d for \"%s\"", sa->sdl_type, name); } freeifaddrs(ifa); } #endif dhcp-4.2.4/common/comapi.c000644 000765 000024 00000062464 11726364512 015316 0ustar00sarstaff000000 000000 /* omapi.c OMAPI object interfaces for the DHCP server. */ /* * Copyright (c) 2012 Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 2004-2007,2009 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1999-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ * * This software has been written for Internet Systems Consortium * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. * To learn more about Internet Systems Consortium, see * ``https://www.isc.org/''. To learn more about Vixie Enterprises, * see ``http://www.vix.com''. To learn more about Nominum, Inc., see * ``http://www.nominum.com''. */ /* Many, many thanks to Brian Murrell and BCtel for this code - BCtel provided the funding that resulted in this code and the entire OMAPI support library being written, and Brian helped brainstorm and refine the requirements. To the extent that this code is useful, you have Brian and BCtel to thank. Any limitations in the code are a result of mistakes on my part. -- Ted Lemon */ #include "dhcpd.h" #include OMAPI_OBJECT_ALLOC (subnet, struct subnet, dhcp_type_subnet) OMAPI_OBJECT_ALLOC (shared_network, struct shared_network, dhcp_type_shared_network) OMAPI_OBJECT_ALLOC (group_object, struct group_object, dhcp_type_group) OMAPI_OBJECT_ALLOC (dhcp_control, dhcp_control_object_t, dhcp_type_control) omapi_object_type_t *dhcp_type_interface; omapi_object_type_t *dhcp_type_group; omapi_object_type_t *dhcp_type_shared_network; omapi_object_type_t *dhcp_type_subnet; omapi_object_type_t *dhcp_type_control; dhcp_control_object_t *dhcp_control_object; void dhcp_common_objects_setup () { isc_result_t status; status = omapi_object_type_register (&dhcp_type_control, "control", dhcp_control_set_value, dhcp_control_get_value, dhcp_control_destroy, dhcp_control_signal_handler, dhcp_control_stuff_values, dhcp_control_lookup, dhcp_control_create, dhcp_control_remove, 0, 0, 0, sizeof (dhcp_control_object_t), 0, RC_MISC); if (status != ISC_R_SUCCESS) log_fatal ("Can't register control object type: %s", isc_result_totext (status)); status = dhcp_control_allocate (&dhcp_control_object, MDL); if (status != ISC_R_SUCCESS) log_fatal ("Can't make initial control object: %s", isc_result_totext (status)); dhcp_control_object -> state = server_startup; status = omapi_object_type_register (&dhcp_type_group, "group", dhcp_group_set_value, dhcp_group_get_value, dhcp_group_destroy, dhcp_group_signal_handler, dhcp_group_stuff_values, dhcp_group_lookup, dhcp_group_create, dhcp_group_remove, 0, 0, 0, sizeof (struct group_object), 0, RC_MISC); if (status != ISC_R_SUCCESS) log_fatal ("Can't register group object type: %s", isc_result_totext (status)); status = omapi_object_type_register (&dhcp_type_subnet, "subnet", dhcp_subnet_set_value, dhcp_subnet_get_value, dhcp_subnet_destroy, dhcp_subnet_signal_handler, dhcp_subnet_stuff_values, dhcp_subnet_lookup, dhcp_subnet_create, dhcp_subnet_remove, 0, 0, 0, sizeof (struct subnet), 0, RC_MISC); if (status != ISC_R_SUCCESS) log_fatal ("Can't register subnet object type: %s", isc_result_totext (status)); status = omapi_object_type_register (&dhcp_type_shared_network, "shared-network", dhcp_shared_network_set_value, dhcp_shared_network_get_value, dhcp_shared_network_destroy, dhcp_shared_network_signal_handler, dhcp_shared_network_stuff_values, dhcp_shared_network_lookup, dhcp_shared_network_create, dhcp_shared_network_remove, 0, 0, 0, sizeof (struct shared_network), 0, RC_MISC); if (status != ISC_R_SUCCESS) log_fatal ("Can't register shared network object type: %s", isc_result_totext (status)); interface_setup (); } isc_result_t dhcp_group_set_value (omapi_object_t *h, omapi_object_t *id, omapi_data_string_t *name, omapi_typed_data_t *value) { struct group_object *group; isc_result_t status; if (h -> type != dhcp_type_group) return DHCP_R_INVALIDARG; group = (struct group_object *)h; /* XXX For now, we can only set these values on new group objects. XXX Soon, we need to be able to update group objects. */ if (!omapi_ds_strcmp (name, "name")) { if (group -> name) return ISC_R_EXISTS; if (value -> type == omapi_datatype_data || value -> type == omapi_datatype_string) { group -> name = dmalloc (value -> u.buffer.len + 1, MDL); if (!group -> name) return ISC_R_NOMEMORY; memcpy (group -> name, value -> u.buffer.value, value -> u.buffer.len); group -> name [value -> u.buffer.len] = 0; } else return DHCP_R_INVALIDARG; return ISC_R_SUCCESS; } if (!omapi_ds_strcmp (name, "statements")) { if (group -> group && group -> group -> statements) return ISC_R_EXISTS; if (!group -> group) { if (!clone_group (&group -> group, root_group, MDL)) return ISC_R_NOMEMORY; } if (value -> type == omapi_datatype_data || value -> type == omapi_datatype_string) { struct parse *parse; int lose = 0; parse = NULL; status = new_parse(&parse, -1, (char *) value->u.buffer.value, value->u.buffer.len, "network client", 0); if (status != ISC_R_SUCCESS || parse == NULL) return status; if (!(parse_executable_statements (&group -> group -> statements, parse, &lose, context_any))) { end_parse (&parse); return DHCP_R_BADPARSE; } end_parse (&parse); return ISC_R_SUCCESS; } else return DHCP_R_INVALIDARG; } /* Try to find some inner object that can take the value. */ if (h -> inner && h -> inner -> type -> set_value) { status = ((*(h -> inner -> type -> set_value)) (h -> inner, id, name, value)); if (status == ISC_R_SUCCESS || status == DHCP_R_UNCHANGED) return status; } return ISC_R_NOTFOUND; } isc_result_t dhcp_group_get_value (omapi_object_t *h, omapi_object_t *id, omapi_data_string_t *name, omapi_value_t **value) { struct group_object *group; isc_result_t status; if (h -> type != dhcp_type_group) return DHCP_R_INVALIDARG; group = (struct group_object *)h; if (!omapi_ds_strcmp (name, "name")) return omapi_make_string_value (value, name, group -> name, MDL); /* Try to find some inner object that can take the value. */ if (h -> inner && h -> inner -> type -> get_value) { status = ((*(h -> inner -> type -> get_value)) (h -> inner, id, name, value)); if (status == ISC_R_SUCCESS) return status; } return ISC_R_NOTFOUND; } isc_result_t dhcp_group_destroy (omapi_object_t *h, const char *file, int line) { struct group_object *group, *t; if (h -> type != dhcp_type_group) return DHCP_R_INVALIDARG; group = (struct group_object *)h; if (group -> name) { if (group_name_hash) { t = (struct group_object *)0; if (group_hash_lookup (&t, group_name_hash, group -> name, strlen (group -> name), MDL)) { group_hash_delete (group_name_hash, group -> name, strlen (group -> name), MDL); group_object_dereference (&t, MDL); } } dfree (group -> name, file, line); group -> name = (char *)0; } if (group -> group) group_dereference (&group -> group, MDL); return ISC_R_SUCCESS; } isc_result_t dhcp_group_signal_handler (omapi_object_t *h, const char *name, va_list ap) { struct group_object *group; isc_result_t status; int updatep = 0; if (h -> type != dhcp_type_group) return DHCP_R_INVALIDARG; group = (struct group_object *)h; if (!strcmp (name, "updated")) { /* A group object isn't valid if a subgroup hasn't yet been associated with it. */ if (!group -> group) return DHCP_R_INVALIDARG; /* Group objects always have to have names. */ if (!group -> name) { char hnbuf [64]; sprintf (hnbuf, "ng%08lx%08lx", (unsigned long)cur_time, (unsigned long)group); group -> name = dmalloc (strlen (hnbuf) + 1, MDL); if (!group -> name) return ISC_R_NOMEMORY; strcpy (group -> name, hnbuf); } supersede_group (group, 1); updatep = 1; } /* Try to find some inner object that can take the value. */ if (h -> inner && h -> inner -> type -> get_value) { status = ((*(h -> inner -> type -> signal_handler)) (h -> inner, name, ap)); if (status == ISC_R_SUCCESS) return status; } if (updatep) return ISC_R_SUCCESS; return ISC_R_NOTFOUND; } isc_result_t dhcp_group_stuff_values (omapi_object_t *c, omapi_object_t *id, omapi_object_t *h) { struct group_object *group; isc_result_t status; if (h -> type != dhcp_type_group) return DHCP_R_INVALIDARG; group = (struct group_object *)h; /* Write out all the values. */ if (group -> name) { status = omapi_connection_put_name (c, "name"); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_put_string (c, group -> name); if (status != ISC_R_SUCCESS) return status; } /* Write out the inner object, if any. */ if (h -> inner && h -> inner -> type -> stuff_values) { status = ((*(h -> inner -> type -> stuff_values)) (c, id, h -> inner)); if (status == ISC_R_SUCCESS) return status; } return ISC_R_SUCCESS; } isc_result_t dhcp_group_lookup (omapi_object_t **lp, omapi_object_t *id, omapi_object_t *ref) { omapi_value_t *tv = (omapi_value_t *)0; isc_result_t status; struct group_object *group; if (!ref) return DHCP_R_NOKEYS; /* First see if we were sent a handle. */ status = omapi_get_value_str (ref, id, "handle", &tv); if (status == ISC_R_SUCCESS) { status = omapi_handle_td_lookup (lp, tv -> value); omapi_value_dereference (&tv, MDL); if (status != ISC_R_SUCCESS) return status; /* Don't return the object if the type is wrong. */ if ((*lp) -> type != dhcp_type_group) { omapi_object_dereference (lp, MDL); return DHCP_R_INVALIDARG; } } /* Now look for a name. */ status = omapi_get_value_str (ref, id, "name", &tv); if (status == ISC_R_SUCCESS) { group = (struct group_object *)0; if (group_name_hash && group_hash_lookup (&group, group_name_hash, (const char *) tv -> value -> u.buffer.value, tv -> value -> u.buffer.len, MDL)) { omapi_value_dereference (&tv, MDL); if (*lp && *lp != (omapi_object_t *)group) { group_object_dereference (&group, MDL); omapi_object_dereference (lp, MDL); return DHCP_R_KEYCONFLICT; } else if (!*lp) { /* XXX fix so that hash lookup itself creates XXX the reference. */ omapi_object_reference (lp, (omapi_object_t *)group, MDL); group_object_dereference (&group, MDL); } } else if (!*lp) return ISC_R_NOTFOUND; } /* If we get to here without finding a group, no valid key was specified. */ if (!*lp) return DHCP_R_NOKEYS; if (((struct group_object *)(*lp)) -> flags & GROUP_OBJECT_DELETED) { omapi_object_dereference (lp, MDL); return ISC_R_NOTFOUND; } return ISC_R_SUCCESS; } isc_result_t dhcp_group_create (omapi_object_t **lp, omapi_object_t *id) { struct group_object *group; isc_result_t status; group = (struct group_object *)0; status = group_object_allocate (&group, MDL); if (status != ISC_R_SUCCESS) return status; group -> flags = GROUP_OBJECT_DYNAMIC; status = omapi_object_reference (lp, (omapi_object_t *)group, MDL); group_object_dereference (&group, MDL); return status; } isc_result_t dhcp_group_remove (omapi_object_t *lp, omapi_object_t *id) { struct group_object *group; isc_result_t status; if (lp -> type != dhcp_type_group) return DHCP_R_INVALIDARG; group = (struct group_object *)lp; group -> flags |= GROUP_OBJECT_DELETED; if (group_write_hook) { if (!(*group_write_hook) (group)) return ISC_R_IOERROR; } status = dhcp_group_destroy ((omapi_object_t *)group, MDL); return status; } isc_result_t dhcp_control_set_value (omapi_object_t *h, omapi_object_t *id, omapi_data_string_t *name, omapi_typed_data_t *value) { dhcp_control_object_t *control; isc_result_t status; unsigned long newstate; if (h -> type != dhcp_type_control) return DHCP_R_INVALIDARG; control = (dhcp_control_object_t *)h; if (!omapi_ds_strcmp (name, "state")) { status = omapi_get_int_value (&newstate, value); if (status != ISC_R_SUCCESS) return status; status = dhcp_set_control_state (control -> state, newstate); if (status == ISC_R_SUCCESS) control -> state = value -> u.integer; return status; } /* Try to find some inner object that can take the value. */ if (h -> inner && h -> inner -> type -> set_value) { status = ((*(h -> inner -> type -> set_value)) (h -> inner, id, name, value)); if (status == ISC_R_SUCCESS || status == DHCP_R_UNCHANGED) return status; } return ISC_R_NOTFOUND; } isc_result_t dhcp_control_get_value (omapi_object_t *h, omapi_object_t *id, omapi_data_string_t *name, omapi_value_t **value) { dhcp_control_object_t *control; isc_result_t status; if (h -> type != dhcp_type_control) return DHCP_R_INVALIDARG; control = (dhcp_control_object_t *)h; if (!omapi_ds_strcmp (name, "state")) return omapi_make_int_value (value, name, (int)control -> state, MDL); /* Try to find some inner object that can take the value. */ if (h -> inner && h -> inner -> type -> get_value) { status = ((*(h -> inner -> type -> get_value)) (h -> inner, id, name, value)); if (status == ISC_R_SUCCESS) return status; } return ISC_R_NOTFOUND; } isc_result_t dhcp_control_destroy (omapi_object_t *h, const char *file, int line) { if (h -> type != dhcp_type_control) return DHCP_R_INVALIDARG; /* Can't destroy the control object. */ return ISC_R_NOPERM; } isc_result_t dhcp_control_signal_handler (omapi_object_t *h, const char *name, va_list ap) { /* In this function h should be a (dhcp_control_object_t *) */ isc_result_t status; if (h -> type != dhcp_type_control) return DHCP_R_INVALIDARG; /* Try to find some inner object that can take the value. */ if (h -> inner && h -> inner -> type -> get_value) { status = ((*(h -> inner -> type -> signal_handler)) (h -> inner, name, ap)); if (status == ISC_R_SUCCESS) return status; } return ISC_R_NOTFOUND; } isc_result_t dhcp_control_stuff_values (omapi_object_t *c, omapi_object_t *id, omapi_object_t *h) { dhcp_control_object_t *control; isc_result_t status; if (h -> type != dhcp_type_control) return DHCP_R_INVALIDARG; control = (dhcp_control_object_t *)h; /* Write out all the values. */ status = omapi_connection_put_name (c, "state"); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_put_uint32 (c, sizeof (u_int32_t)); if (status != ISC_R_SUCCESS) return status; status = omapi_connection_put_uint32 (c, control -> state); if (status != ISC_R_SUCCESS) return status; /* Write out the inner object, if any. */ if (h -> inner && h -> inner -> type -> stuff_values) { status = ((*(h -> inner -> type -> stuff_values)) (c, id, h -> inner)); if (status == ISC_R_SUCCESS) return status; } return ISC_R_SUCCESS; } isc_result_t dhcp_control_lookup (omapi_object_t **lp, omapi_object_t *id, omapi_object_t *ref) { omapi_value_t *tv = (omapi_value_t *)0; isc_result_t status; /* First see if we were sent a handle. */ if (ref) { status = omapi_get_value_str (ref, id, "handle", &tv); if (status == ISC_R_SUCCESS) { status = omapi_handle_td_lookup (lp, tv -> value); omapi_value_dereference (&tv, MDL); if (status != ISC_R_SUCCESS) return status; /* Don't return the object if the type is wrong. */ if ((*lp) -> type != dhcp_type_control) { omapi_object_dereference (lp, MDL); return DHCP_R_INVALIDARG; } } } /* Otherwise, stop playing coy - there's only one control object, so we can just return it. */ dhcp_control_reference ((dhcp_control_object_t **)lp, dhcp_control_object, MDL); return ISC_R_SUCCESS; } isc_result_t dhcp_control_create (omapi_object_t **lp, omapi_object_t *id) { /* Can't create a control object - there can be only one. */ return ISC_R_NOPERM; } isc_result_t dhcp_control_remove (omapi_object_t *lp, omapi_object_t *id) { /* Form is emptiness; emptiness form. The control object cannot go out of existance. */ return ISC_R_NOPERM; } isc_result_t dhcp_subnet_set_value (omapi_object_t *h, omapi_object_t *id, omapi_data_string_t *name, omapi_typed_data_t *value) { /* In this function h should be a (struct subnet *) */ isc_result_t status; if (h -> type != dhcp_type_subnet) return DHCP_R_INVALIDARG; /* No values to set yet. */ /* Try to find some inner object that can take the value. */ if (h -> inner && h -> inner -> type -> set_value) { status = ((*(h -> inner -> type -> set_value)) (h -> inner, id, name, value)); if (status == ISC_R_SUCCESS || status == DHCP_R_UNCHANGED) return status; } return ISC_R_NOTFOUND; } isc_result_t dhcp_subnet_get_value (omapi_object_t *h, omapi_object_t *id, omapi_data_string_t *name, omapi_value_t **value) { /* In this function h should be a (struct subnet *) */ isc_result_t status; if (h -> type != dhcp_type_subnet) return DHCP_R_INVALIDARG; /* No values to get yet. */ /* Try to find some inner object that can provide the value. */ if (h -> inner && h -> inner -> type -> get_value) { status = ((*(h -> inner -> type -> get_value)) (h -> inner, id, name, value)); if (status == ISC_R_SUCCESS) return status; } return ISC_R_NOTFOUND; } isc_result_t dhcp_subnet_destroy (omapi_object_t *h, const char *file, int line) { #if defined (DEBUG_MEMORY_LEAKAGE) || \ defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT) struct subnet *subnet; #endif if (h -> type != dhcp_type_subnet) return DHCP_R_INVALIDARG; #if defined (DEBUG_MEMORY_LEAKAGE) || \ defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT) subnet = (struct subnet *)h; if (subnet -> next_subnet) subnet_dereference (&subnet -> next_subnet, file, line); if (subnet -> next_sibling) subnet_dereference (&subnet -> next_sibling, file, line); if (subnet -> shared_network) shared_network_dereference (&subnet -> shared_network, file, line); if (subnet -> interface) interface_dereference (&subnet -> interface, file, line); if (subnet -> group) group_dereference (&subnet -> group, file, line); #endif return ISC_R_SUCCESS; } isc_result_t dhcp_subnet_signal_handler (omapi_object_t *h, const char *name, va_list ap) { /* In this function h should be a (struct subnet *) */ isc_result_t status; int updatep = 0; if (h -> type != dhcp_type_subnet) return DHCP_R_INVALIDARG; /* Can't write subnets yet. */ /* Try to find some inner object that can take the value. */ if (h -> inner && h -> inner -> type -> get_value) { status = ((*(h -> inner -> type -> signal_handler)) (h -> inner, name, ap)); if (status == ISC_R_SUCCESS) return status; } if (updatep) return ISC_R_SUCCESS; return ISC_R_NOTFOUND; } isc_result_t dhcp_subnet_stuff_values (omapi_object_t *c, omapi_object_t *id, omapi_object_t *h) { /* In this function h should be a (struct subnet *) */ isc_result_t status; if (h -> type != dhcp_type_subnet) return DHCP_R_INVALIDARG; /* Can't stuff subnet values yet. */ /* Write out the inner object, if any. */ if (h -> inner && h -> inner -> type -> stuff_values) { status = ((*(h -> inner -> type -> stuff_values)) (c, id, h -> inner)); if (status == ISC_R_SUCCESS) return status; } return ISC_R_SUCCESS; } isc_result_t dhcp_subnet_lookup (omapi_object_t **lp, omapi_object_t *id, omapi_object_t *ref) { /* Can't look up subnets yet. */ /* If we get to here without finding a subnet, no valid key was specified. */ if (!*lp) return DHCP_R_NOKEYS; return ISC_R_SUCCESS; } isc_result_t dhcp_subnet_create (omapi_object_t **lp, omapi_object_t *id) { return ISC_R_NOTIMPLEMENTED; } isc_result_t dhcp_subnet_remove (omapi_object_t *lp, omapi_object_t *id) { return ISC_R_NOTIMPLEMENTED; } isc_result_t dhcp_shared_network_set_value (omapi_object_t *h, omapi_object_t *id, omapi_data_string_t *name, omapi_typed_data_t *value) { /* In this function h should be a (struct shared_network *) */ isc_result_t status; if (h -> type != dhcp_type_shared_network) return DHCP_R_INVALIDARG; /* No values to set yet. */ /* Try to find some inner object that can take the value. */ if (h -> inner && h -> inner -> type -> set_value) { status = ((*(h -> inner -> type -> set_value)) (h -> inner, id, name, value)); if (status == ISC_R_SUCCESS || status == DHCP_R_UNCHANGED) return status; } return ISC_R_NOTFOUND; } isc_result_t dhcp_shared_network_get_value (omapi_object_t *h, omapi_object_t *id, omapi_data_string_t *name, omapi_value_t **value) { /* In this function h should be a (struct shared_network *) */ isc_result_t status; if (h -> type != dhcp_type_shared_network) return DHCP_R_INVALIDARG; /* No values to get yet. */ /* Try to find some inner object that can provide the value. */ if (h -> inner && h -> inner -> type -> get_value) { status = ((*(h -> inner -> type -> get_value)) (h -> inner, id, name, value)); if (status == ISC_R_SUCCESS) return status; } return ISC_R_NOTFOUND; } isc_result_t dhcp_shared_network_destroy (omapi_object_t *h, const char *file, int line) { /* In this function h should be a (struct shared_network *) */ #if defined (DEBUG_MEMORY_LEAKAGE) || \ defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT) struct shared_network *shared_network; #endif if (h -> type != dhcp_type_shared_network) return DHCP_R_INVALIDARG; #if defined (DEBUG_MEMORY_LEAKAGE) || \ defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT) shared_network = (struct shared_network *)h; if (shared_network -> next) shared_network_dereference (&shared_network -> next, file, line); if (shared_network -> name) { dfree (shared_network -> name, file, line); shared_network -> name = 0; } if (shared_network -> subnets) subnet_dereference (&shared_network -> subnets, file, line); if (shared_network -> interface) interface_dereference (&shared_network -> interface, file, line); if (shared_network -> pools) omapi_object_dereference ((omapi_object_t **) &shared_network -> pools, file, line); if (shared_network -> group) group_dereference (&shared_network -> group, file, line); #if defined (FAILOVER_PROTOCOL) if (shared_network -> failover_peer) omapi_object_dereference ((omapi_object_t **) &shared_network -> failover_peer, file, line); #endif #endif /* DEBUG_MEMORY_LEAKAGE */ return ISC_R_SUCCESS; } isc_result_t dhcp_shared_network_signal_handler (omapi_object_t *h, const char *name, va_list ap) { /* In this function h should be a (struct shared_network *) */ isc_result_t status; int updatep = 0; if (h -> type != dhcp_type_shared_network) return DHCP_R_INVALIDARG; /* Can't write shared_networks yet. */ /* Try to find some inner object that can take the value. */ if (h -> inner && h -> inner -> type -> get_value) { status = ((*(h -> inner -> type -> signal_handler)) (h -> inner, name, ap)); if (status == ISC_R_SUCCESS) return status; } if (updatep) return ISC_R_SUCCESS; return ISC_R_NOTFOUND; } isc_result_t dhcp_shared_network_stuff_values (omapi_object_t *c, omapi_object_t *id, omapi_object_t *h) { /* In this function h should be a (struct shared_network *) */ isc_result_t status; if (h -> type != dhcp_type_shared_network) return DHCP_R_INVALIDARG; /* Can't stuff shared_network values yet. */ /* Write out the inner object, if any. */ if (h -> inner && h -> inner -> type -> stuff_values) { status = ((*(h -> inner -> type -> stuff_values)) (c, id, h -> inner)); if (status == ISC_R_SUCCESS) return status; } return ISC_R_SUCCESS; } isc_result_t dhcp_shared_network_lookup (omapi_object_t **lp, omapi_object_t *id, omapi_object_t *ref) { /* Can't look up shared_networks yet. */ /* If we get to here without finding a shared_network, no valid key was specified. */ if (!*lp) return DHCP_R_NOKEYS; return ISC_R_SUCCESS; } isc_result_t dhcp_shared_network_create (omapi_object_t **lp, omapi_object_t *id) { return ISC_R_NOTIMPLEMENTED; } isc_result_t dhcp_shared_network_remove (omapi_object_t *lp, omapi_object_t *id) { return ISC_R_NOTIMPLEMENTED; } dhcp-4.2.4/common/conflex.c000644 000765 000024 00000117071 11717270172 015475 0ustar00sarstaff000000 000000 /* conflex.c Lexical scanner for dhcpd config file... */ /* * Copyright (c) 2004-2012 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1995-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ * * This software has been written for Internet Systems Consortium * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. * To learn more about Internet Systems Consortium, see * ``https://www.isc.org/''. To learn more about Vixie Enterprises, * see ``http://www.vix.com''. To learn more about Nominum, Inc., see * ``http://www.nominum.com''. */ #include "dhcpd.h" #include static int get_char (struct parse *); static void unget_char(struct parse *, int); static void skip_to_eol (struct parse *); static enum dhcp_token read_whitespace(int c, struct parse *cfile); static enum dhcp_token read_string (struct parse *); static enum dhcp_token read_number (int, struct parse *); static enum dhcp_token read_num_or_name (int, struct parse *); static enum dhcp_token intern (char *, enum dhcp_token); isc_result_t new_parse (cfile, file, inbuf, buflen, name, eolp) struct parse **cfile; int file; char *inbuf; unsigned buflen; const char *name; int eolp; { isc_result_t status = ISC_R_SUCCESS; struct parse *tmp; tmp = dmalloc(sizeof(struct parse), MDL); if (tmp == NULL) { return (ISC_R_NOMEMORY); } /* * We don't need to initialize things to zero here, since * dmalloc() returns memory that is set to zero. */ tmp->tlname = name; tmp->lpos = tmp -> line = 1; tmp->cur_line = tmp->line1; tmp->prev_line = tmp->line2; tmp->token_line = tmp->cur_line; tmp->cur_line[0] = tmp->prev_line[0] = 0; tmp->file = file; tmp->eol_token = eolp; if (inbuf != NULL) { tmp->inbuf = inbuf; tmp->buflen = buflen; tmp->bufsiz = 0; } else { struct stat sb; if (fstat(file, &sb) < 0) { status = ISC_R_IOERROR; goto cleanup; } if (sb.st_size == 0) goto cleanup; tmp->bufsiz = tmp->buflen = (size_t) sb.st_size; tmp->inbuf = mmap(NULL, tmp->bufsiz, PROT_READ, MAP_SHARED, file, 0); if (tmp->inbuf == MAP_FAILED) { status = ISC_R_IOERROR; goto cleanup; } } *cfile = tmp; return (ISC_R_SUCCESS); cleanup: dfree(tmp, MDL); return (status); } isc_result_t end_parse (cfile) struct parse **cfile; { /* "Memory" config files have no file. */ if ((*cfile)->file != -1) { munmap((*cfile)->inbuf, (*cfile)->bufsiz); close((*cfile)->file); } if ((*cfile)->saved_state != NULL) { dfree((*cfile)->saved_state, MDL); } dfree(*cfile, MDL); *cfile = NULL; return ISC_R_SUCCESS; } /* * Save the current state of the parser. * * Only one state may be saved. Any previous saved state is * lost. */ isc_result_t save_parse_state(struct parse *cfile) { /* * Free any previous saved state. */ if (cfile->saved_state != NULL) { dfree(cfile->saved_state, MDL); } /* * Save our current state. */ cfile->saved_state = dmalloc(sizeof(struct parse), MDL); if (cfile->saved_state == NULL) { return ISC_R_NOMEMORY; } memcpy(cfile->saved_state, cfile, sizeof(*cfile)); return ISC_R_SUCCESS; } /* * Return the parser to the previous saved state. * * You must call save_parse_state() before calling * restore_parse_state(), but you can call restore_parse_state() any * number of times after that. */ isc_result_t restore_parse_state(struct parse *cfile) { struct parse *saved_state; if (cfile->saved_state == NULL) { return DHCP_R_NOTYET; } saved_state = cfile->saved_state; memcpy(cfile, saved_state, sizeof(*cfile)); cfile->saved_state = saved_state; return ISC_R_SUCCESS; } static int get_char (cfile) struct parse *cfile; { /* My kingdom for WITH... */ int c; if (cfile->bufix == cfile->buflen) { #if !defined(LDAP_CONFIGURATION) c = EOF; #else /* defined(LDAP_CONFIGURATION) */ if (cfile->read_function != NULL) c = cfile->read_function(cfile); else c = EOF; #endif } else { c = cfile->inbuf [cfile->bufix]; cfile->bufix++; } if (!cfile->ugflag) { if (c == EOL) { if (cfile->cur_line == cfile->line1) { cfile->cur_line = cfile->line2; cfile->prev_line = cfile->line1; } else { cfile->cur_line = cfile->line1; cfile->prev_line = cfile->line2; } cfile->line++; cfile->lpos = 1; cfile->cur_line [0] = 0; } else if (c != EOF) { if (cfile->lpos <= 80) { cfile->cur_line [cfile->lpos - 1] = c; cfile->cur_line [cfile->lpos] = 0; } cfile->lpos++; } } else cfile->ugflag = 0; return c; } /* * Return a character to our input buffer. */ static void unget_char(struct parse *cfile, int c) { if (c != EOF) { cfile->bufix--; cfile->ugflag = 1; /* do not put characters into our error buffer on the next call to get_char() */ } } /* * GENERAL NOTE ABOUT TOKENS * * We normally only want non-whitespace tokens. There are some * circumstances where we *do* want to see whitespace (for example * when parsing IPv6 addresses). * * Generally we use the next_token() function to read tokens. This * in turn calls get_next_token, which does *not* return tokens for * whitespace. Rather, it skips these. * * When we need to see whitespace, we us next_raw_token(), which also * returns the WHITESPACE token. * * The peek_token() and peek_raw_token() functions work as expected. * * Warning: if you invoke peek_token(), then if there is a whitespace * token, it will be lost, and subsequent use of next_raw_token() or * peek_raw_token() will NOT see it. */ static enum dhcp_token get_raw_token(struct parse *cfile) { int c; enum dhcp_token ttok; static char tb [2]; int l, p; do { l = cfile -> line; p = cfile -> lpos; c = get_char (cfile); if (!((c == '\n') && cfile->eol_token) && isascii(c) && isspace(c)) { ttok = read_whitespace(c, cfile); break; } if (c == '#') { skip_to_eol (cfile); continue; } if (c == '"') { cfile -> lexline = l; cfile -> lexchar = p; ttok = read_string (cfile); break; } if ((isascii (c) && isdigit (c)) || c == '-') { cfile -> lexline = l; cfile -> lexchar = p; ttok = read_number (c, cfile); break; } else if (isascii (c) && isalpha (c)) { cfile -> lexline = l; cfile -> lexchar = p; ttok = read_num_or_name (c, cfile); break; } else if (c == EOF) { ttok = END_OF_FILE; cfile -> tlen = 0; break; } else { cfile -> lexline = l; cfile -> lexchar = p; tb [0] = c; tb [1] = 0; cfile -> tval = tb; cfile -> tlen = 1; ttok = c; break; } } while (1); return ttok; } /* * The get_next_token() function consumes the next token and * returns it to the caller. * * Since the code is almost the same for "normal" and "raw" * input, we pass a flag to alter the way it works. */ static enum dhcp_token get_next_token(const char **rval, unsigned *rlen, struct parse *cfile, isc_boolean_t raw) { int rv; if (cfile -> token) { if (cfile -> lexline != cfile -> tline) cfile -> token_line = cfile -> cur_line; cfile -> lexchar = cfile -> tlpos; cfile -> lexline = cfile -> tline; rv = cfile -> token; cfile -> token = 0; } else { rv = get_raw_token(cfile); cfile -> token_line = cfile -> cur_line; } if (!raw) { while (rv == WHITESPACE) { rv = get_raw_token(cfile); cfile->token_line = cfile->cur_line; } } if (rval) *rval = cfile -> tval; if (rlen) *rlen = cfile -> tlen; #ifdef DEBUG_TOKENS fprintf (stderr, "%s:%d ", cfile -> tval, rv); #endif return rv; } /* * Get the next token from cfile and return it. * * If rval is non-NULL, set the pointer it contains to * the contents of the token. * * If rlen is non-NULL, set the integer it contains to * the length of the token. */ enum dhcp_token next_token(const char **rval, unsigned *rlen, struct parse *cfile) { return get_next_token(rval, rlen, cfile, ISC_FALSE); } /* * The same as the next_token() function above, but will return space * as the WHITESPACE token. */ enum dhcp_token next_raw_token(const char **rval, unsigned *rlen, struct parse *cfile) { return get_next_token(rval, rlen, cfile, ISC_TRUE); } /* * The do_peek_token() function checks the next token without * consuming it, and returns it to the caller. * * Since the code is almost the same for "normal" and "raw" * input, we pass a flag to alter the way it works. (See the * warning in the GENERAL NOTES ABOUT TOKENS above though.) */ enum dhcp_token do_peek_token(const char **rval, unsigned int *rlen, struct parse *cfile, isc_boolean_t raw) { int x; if (!cfile->token || (!raw && (cfile->token == WHITESPACE))) { cfile -> tlpos = cfile -> lexchar; cfile -> tline = cfile -> lexline; do { cfile->token = get_raw_token(cfile); } while (!raw && (cfile->token == WHITESPACE)); if (cfile -> lexline != cfile -> tline) cfile -> token_line = cfile -> prev_line; x = cfile -> lexchar; cfile -> lexchar = cfile -> tlpos; cfile -> tlpos = x; x = cfile -> lexline; cfile -> lexline = cfile -> tline; cfile -> tline = x; } if (rval) *rval = cfile -> tval; if (rlen) *rlen = cfile -> tlen; #ifdef DEBUG_TOKENS fprintf (stderr, "(%s:%d) ", cfile -> tval, cfile -> token); #endif return cfile -> token; } /* * Get the next token from cfile and return it, leaving it for a * subsequent call to next_token(). * * Note that it WILL consume whitespace tokens. * * If rval is non-NULL, set the pointer it contains to * the contents of the token. * * If rlen is non-NULL, set the integer it contains to * the length of the token. */ enum dhcp_token peek_token(const char **rval, unsigned *rlen, struct parse *cfile) { return do_peek_token(rval, rlen, cfile, ISC_FALSE); } /* * The same as the peek_token() function above, but will return space * as the WHITESPACE token. */ enum dhcp_token peek_raw_token(const char **rval, unsigned *rlen, struct parse *cfile) { return do_peek_token(rval, rlen, cfile, ISC_TRUE); } static void skip_to_eol (cfile) struct parse *cfile; { int c; do { c = get_char (cfile); if (c == EOF) return; if (c == EOL) { return; } } while (1); } static enum dhcp_token read_whitespace(int c, struct parse *cfile) { int ofs; /* * Read as much whitespace as we have available. */ ofs = 0; do { cfile->tokbuf[ofs++] = c; c = get_char(cfile); } while (!((c == '\n') && cfile->eol_token) && isascii(c) && isspace(c)); /* * Put the last (non-whitespace) character back. */ unget_char(cfile, c); /* * Return our token. */ cfile->tokbuf[ofs] = '\0'; cfile->tlen = ofs; cfile->tval = cfile->tokbuf; return WHITESPACE; } static enum dhcp_token read_string (cfile) struct parse *cfile; { int i; int bs = 0; int c; int value = 0; int hex = 0; for (i = 0; i < sizeof cfile -> tokbuf; i++) { again: c = get_char (cfile); if (c == EOF) { parse_warn (cfile, "eof in string constant"); break; } if (bs == 1) { switch (c) { case 't': cfile -> tokbuf [i] = '\t'; break; case 'r': cfile -> tokbuf [i] = '\r'; break; case 'n': cfile -> tokbuf [i] = '\n'; break; case 'b': cfile -> tokbuf [i] = '\b'; break; case '0': case '1': case '2': case '3': hex = 0; value = c - '0'; ++bs; goto again; case 'x': hex = 1; value = 0; ++bs; goto again; default: cfile -> tokbuf [i] = c; bs = 0; break; } bs = 0; } else if (bs > 1) { if (hex) { if (c >= '0' && c <= '9') { value = value * 16 + (c - '0'); } else if (c >= 'a' && c <= 'f') { value = value * 16 + (c - 'a' + 10); } else if (c >= 'A' && c <= 'F') { value = value * 16 + (c - 'A' + 10); } else { parse_warn (cfile, "invalid hex digit: %x", c); bs = 0; continue; } if (++bs == 4) { cfile -> tokbuf [i] = value; bs = 0; } else goto again; } else { if (c >= '0' && c <= '7') { value = value * 8 + (c - '0'); } else { if (value != 0) { parse_warn (cfile, "invalid octal digit %x", c); continue; } else cfile -> tokbuf [i] = 0; bs = 0; } if (++bs == 4) { cfile -> tokbuf [i] = value; bs = 0; } else goto again; } } else if (c == '\\') { bs = 1; goto again; } else if (c == '"') break; else cfile -> tokbuf [i] = c; } /* Normally, I'd feel guilty about this, but we're talking about strings that'll fit in a DHCP packet here... */ if (i == sizeof cfile -> tokbuf) { parse_warn (cfile, "string constant larger than internal buffer"); --i; } cfile -> tokbuf [i] = 0; cfile -> tlen = i; cfile -> tval = cfile -> tokbuf; return STRING; } static enum dhcp_token read_number (c, cfile) int c; struct parse *cfile; { int i = 0; int token = NUMBER; cfile -> tokbuf [i++] = c; for (; i < sizeof cfile -> tokbuf; i++) { c = get_char (cfile); /* Promote NUMBER -> NUMBER_OR_NAME -> NAME, never demote. * Except in the case of '0x' syntax hex, which gets called * a NAME at '0x', and returned to NUMBER_OR_NAME once it's * verified to be at least 0xf or less. */ switch(isascii(c) ? token : BREAK) { case NUMBER: if(isdigit(c)) break; /* FALLTHROUGH */ case NUMBER_OR_NAME: if(isxdigit(c)) { token = NUMBER_OR_NAME; break; } /* FALLTHROUGH */ case NAME: if((i == 2) && isxdigit(c) && (cfile->tokbuf[0] == '0') && ((cfile->tokbuf[1] == 'x') || (cfile->tokbuf[1] == 'X'))) { token = NUMBER_OR_NAME; break; } else if(((c == '-') || (c == '_') || isalnum(c))) { token = NAME; break; } /* FALLTHROUGH */ case BREAK: /* At this point c is either EOF or part of the next * token. If not EOF, rewind the file one byte so * the next token is read from there. */ unget_char(cfile, c); goto end_read; default: log_fatal("read_number():%s:%d: impossible case", MDL); } cfile -> tokbuf [i] = c; } if (i == sizeof cfile -> tokbuf) { parse_warn (cfile, "numeric token larger than internal buffer"); --i; } end_read: cfile -> tokbuf [i] = 0; cfile -> tlen = i; cfile -> tval = cfile -> tokbuf; /* * If this entire token from start to finish was "-", such as * the middle parameter in "42 - 7", return just the MINUS token. */ if ((i == 1) && (cfile->tokbuf[i] == '-')) return MINUS; else return token; } static enum dhcp_token read_num_or_name (c, cfile) int c; struct parse *cfile; { int i = 0; enum dhcp_token rv = NUMBER_OR_NAME; cfile -> tokbuf [i++] = c; for (; i < sizeof cfile -> tokbuf; i++) { c = get_char (cfile); if (!isascii (c) || (c != '-' && c != '_' && !isalnum (c))) { unget_char(cfile, c); break; } if (!isxdigit (c)) rv = NAME; cfile -> tokbuf [i] = c; } if (i == sizeof cfile -> tokbuf) { parse_warn (cfile, "token larger than internal buffer"); --i; } cfile -> tokbuf [i] = 0; cfile -> tlen = i; cfile -> tval = cfile -> tokbuf; return intern(cfile->tval, rv); } static enum dhcp_token intern(char *atom, enum dhcp_token dfv) { if (!isascii(atom[0])) return dfv; switch (tolower((unsigned char)atom[0])) { case '-': if (atom [1] == 0) return MINUS; break; case 'a': if (!strcasecmp(atom + 1, "bandoned")) return TOKEN_ABANDONED; if (!strcasecmp(atom + 1, "ctive")) return TOKEN_ACTIVE; if (!strncasecmp(atom + 1, "dd", 2)) { if (atom[3] == '\0') return TOKEN_ADD; else if (!strcasecmp(atom + 3, "ress")) return ADDRESS; break; } if (!strcasecmp(atom + 1, "fter")) return AFTER; if (isascii(atom[1]) && (tolower((unsigned char)atom[1]) == 'l')) { if (!strcasecmp(atom + 2, "gorithm")) return ALGORITHM; if (!strcasecmp(atom + 2, "ias")) return ALIAS; if (isascii(atom[2]) && (tolower((unsigned char)atom[2]) == 'l')) { if (atom[3] == '\0') return ALL; else if (!strcasecmp(atom + 3, "ow")) return ALLOW; break; } if (!strcasecmp(atom + 2, "so")) return TOKEN_ALSO; break; } if (isascii(atom[1]) && (tolower((unsigned char)atom[1]) == 'n')) { if (!strcasecmp(atom + 2, "d")) return AND; if (!strcasecmp(atom + 2, "ycast-mac")) return ANYCAST_MAC; break; } if (!strcasecmp(atom + 1, "ppend")) return APPEND; if (!strcasecmp(atom + 1, "rray")) return ARRAY; if (isascii(atom[1]) && (tolower((unsigned char)atom[1]) == 't')) { if (atom[2] == '\0') return AT; if (!strcasecmp(atom + 2, "sfp")) return ATSFP; break; } if (!strncasecmp(atom + 1, "ut", 2)) { if (isascii(atom[3]) && (tolower((unsigned char)atom[3]) == 'h')) { if (!strncasecmp(atom + 4, "enticat", 7)) { if (!strcasecmp(atom + 11, "ed")) return AUTHENTICATED; if (!strcasecmp(atom + 11, "ion")) return AUTHENTICATION; break; } if (!strcasecmp(atom + 4, "oritative")) return AUTHORITATIVE; break; } if (!strcasecmp(atom + 3, "o-partner-down")) return AUTO_PARTNER_DOWN; break; } break; case 'b': if (!strcasecmp (atom + 1, "ackup")) return TOKEN_BACKUP; if (!strcasecmp (atom + 1, "ootp")) return TOKEN_BOOTP; if (!strcasecmp (atom + 1, "inding")) return BINDING; if (!strcasecmp (atom + 1, "inary-to-ascii")) return BINARY_TO_ASCII; if (!strcasecmp (atom + 1, "ackoff-cutoff")) return BACKOFF_CUTOFF; if (!strcasecmp (atom + 1, "ooting")) return BOOTING; if (!strcasecmp (atom + 1, "oot-unknown-clients")) return BOOT_UNKNOWN_CLIENTS; if (!strcasecmp (atom + 1, "reak")) return BREAK; if (!strcasecmp (atom + 1, "illing")) return BILLING; if (!strcasecmp (atom + 1, "oolean")) return BOOLEAN; if (!strcasecmp (atom + 1, "alance")) return BALANCE; if (!strcasecmp (atom + 1, "ound")) return BOUND; break; case 'c': if (!strcasecmp(atom + 1, "ase")) return CASE; if (!strcasecmp(atom + 1, "heck")) return CHECK; if (!strcasecmp(atom + 1, "iaddr")) return CIADDR; if (isascii(atom[1]) && tolower((unsigned char)atom[1]) == 'l') { if (!strcasecmp(atom + 2, "ass")) return CLASS; if (!strncasecmp(atom + 2, "ient", 4)) { if (!strcasecmp(atom + 6, "s")) return CLIENTS; if (atom[6] == '-') { if (!strcasecmp(atom + 7, "hostname")) return CLIENT_HOSTNAME; if (!strcasecmp(atom + 7, "identifier")) return CLIENT_IDENTIFIER; if (!strcasecmp(atom + 7, "state")) return CLIENT_STATE; if (!strcasecmp(atom + 7, "updates")) return CLIENT_UPDATES; break; } break; } if (!strcasecmp(atom + 2, "ose")) return TOKEN_CLOSE; if (!strcasecmp(atom + 2, "tt")) return CLTT; break; } if (isascii(atom[1]) && tolower((unsigned char)atom[1]) == 'o') { if (!strcasecmp(atom + 2, "de")) return CODE; if (isascii(atom[2]) && tolower((unsigned char)atom[2]) == 'm') { if (!strcasecmp(atom + 3, "mit")) return COMMIT; if (!strcasecmp(atom + 3, "munications-interrupted")) return COMMUNICATIONS_INTERRUPTED; if (!strcasecmp(atom + 3, "pressed")) return COMPRESSED; break; } if (isascii(atom[2]) && tolower((unsigned char)atom[2]) == 'n') { if (!strcasecmp(atom + 3, "cat")) return CONCAT; if (!strcasecmp(atom + 3, "fig-option")) return CONFIG_OPTION; if (!strcasecmp(atom + 3, "flict-done")) return CONFLICT_DONE; if (!strcasecmp(atom + 3, "nect")) return CONNECT; break; } break; } if (!strcasecmp(atom + 1, "reate")) return TOKEN_CREATE; break; case 'd': if (!strcasecmp(atom + 1, "b-time-format")) return DB_TIME_FORMAT; if (!strcasecmp (atom + 1, "ns-update")) return DNS_UPDATE; if (!strcasecmp (atom + 1, "ns-delete")) return DNS_DELETE; if (!strcasecmp (atom + 1, "omain")) return DOMAIN; if (!strncasecmp (atom + 1, "omain-", 6)) { if (!strcasecmp(atom + 7, "name")) return DOMAIN_NAME; if (!strcasecmp(atom + 7, "list")) return DOMAIN_LIST; } if (!strcasecmp (atom + 1, "o-forward-update")) return DO_FORWARD_UPDATE; if (!strcasecmp (atom + 1, "ebug")) return TOKEN_DEBUG; if (!strcasecmp (atom + 1, "eny")) return DENY; if (!strcasecmp (atom + 1, "eleted")) return TOKEN_DELETED; if (!strcasecmp (atom + 1, "elete")) return TOKEN_DELETE; if (!strncasecmp (atom + 1, "efault", 6)) { if (!atom [7]) return DEFAULT; if (!strcasecmp(atom + 7, "-duid")) return DEFAULT_DUID; if (!strcasecmp (atom + 7, "-lease-time")) return DEFAULT_LEASE_TIME; break; } if (!strncasecmp (atom + 1, "ynamic", 6)) { if (!atom [7]) return DYNAMIC; if (!strncasecmp (atom + 7, "-bootp", 6)) { if (!atom [13]) return DYNAMIC_BOOTP; if (!strcasecmp (atom + 13, "-lease-cutoff")) return DYNAMIC_BOOTP_LEASE_CUTOFF; if (!strcasecmp (atom + 13, "-lease-length")) return DYNAMIC_BOOTP_LEASE_LENGTH; break; } } if (!strcasecmp (atom + 1, "uplicates")) return DUPLICATES; if (!strcasecmp (atom + 1, "eclines")) return DECLINES; if (!strncasecmp (atom + 1, "efine", 5)) { if (!strcasecmp (atom + 6, "d")) return DEFINED; if (!atom [6]) return DEFINE; } break; case 'e': if (isascii (atom [1]) && tolower((unsigned char)atom[1]) == 'x') { if (!strcasecmp (atom + 2, "tract-int")) return EXTRACT_INT; if (!strcasecmp (atom + 2, "ists")) return EXISTS; if (!strcasecmp (atom + 2, "piry")) return EXPIRY; if (!strcasecmp (atom + 2, "pire")) return EXPIRE; if (!strcasecmp (atom + 2, "pired")) return TOKEN_EXPIRED; } if (!strcasecmp (atom + 1, "ncode-int")) return ENCODE_INT; if (!strcasecmp(atom + 1, "poch")) return EPOCH; if (!strcasecmp (atom + 1, "thernet")) return ETHERNET; if (!strcasecmp (atom + 1, "nds")) return ENDS; if (!strncasecmp (atom + 1, "ls", 2)) { if (!strcasecmp (atom + 3, "e")) return ELSE; if (!strcasecmp (atom + 3, "if")) return ELSIF; break; } if (!strcasecmp (atom + 1, "rror")) return ERROR; if (!strcasecmp (atom + 1, "val")) return EVAL; if (!strcasecmp (atom + 1, "ncapsulate")) return ENCAPSULATE; if (!strcasecmp(atom + 1, "xecute")) return EXECUTE; if (!strcasecmp(atom+1, "n")) { return EN; } break; case 'f': if (!strcasecmp (atom + 1, "atal")) return FATAL; if (!strcasecmp (atom + 1, "ilename")) return FILENAME; if (!strcasecmp (atom + 1, "ixed-address")) return FIXED_ADDR; if (!strcasecmp (atom + 1, "ixed-address6")) return FIXED_ADDR6; if (!strcasecmp (atom + 1, "ixed-prefix6")) return FIXED_PREFIX6; if (!strcasecmp (atom + 1, "ddi")) return TOKEN_FDDI; if (!strcasecmp (atom + 1, "ormerr")) return NS_FORMERR; if (!strcasecmp (atom + 1, "unction")) return FUNCTION; if (!strcasecmp (atom + 1, "ailover")) return FAILOVER; if (!strcasecmp (atom + 1, "ree")) return TOKEN_FREE; break; case 'g': if (!strncasecmp(atom + 1, "et", 2)) { if (!strcasecmp(atom + 3, "-lease-hostnames")) return GET_LEASE_HOSTNAMES; if (!strcasecmp(atom + 3, "hostbyname")) return GETHOSTBYNAME; if (!strcasecmp(atom + 3, "hostname")) return GETHOSTNAME; break; } if (!strcasecmp (atom + 1, "iaddr")) return GIADDR; if (!strcasecmp (atom + 1, "roup")) return GROUP; break; case 'h': if (!strcasecmp(atom + 1, "ash")) return HASH; if (!strcasecmp (atom + 1, "ba")) return HBA; if (!strcasecmp (atom + 1, "ost")) return HOST; if (!strcasecmp (atom + 1, "ost-decl-name")) return HOST_DECL_NAME; if (!strcasecmp(atom + 1, "ost-identifier")) return HOST_IDENTIFIER; if (!strcasecmp (atom + 1, "ardware")) return HARDWARE; if (!strcasecmp (atom + 1, "ostname")) return HOSTNAME; if (!strcasecmp (atom + 1, "elp")) return TOKEN_HELP; break; case 'i': if (!strcasecmp(atom+1, "a-na")) return IA_NA; if (!strcasecmp(atom+1, "a-ta")) return IA_TA; if (!strcasecmp(atom+1, "a-pd")) return IA_PD; if (!strcasecmp(atom+1, "aaddr")) return IAADDR; if (!strcasecmp(atom+1, "aprefix")) return IAPREFIX; if (!strcasecmp (atom + 1, "nclude")) return INCLUDE; if (!strcasecmp (atom + 1, "nteger")) return INTEGER; if (!strcasecmp (atom + 1, "nfiniband")) return TOKEN_INFINIBAND; if (!strcasecmp (atom + 1, "nfinite")) return INFINITE; if (!strcasecmp (atom + 1, "nfo")) return INFO; if (!strcasecmp (atom + 1, "p-address")) return IP_ADDRESS; if (!strcasecmp (atom + 1, "p6-address")) return IP6_ADDRESS; if (!strcasecmp (atom + 1, "nitial-interval")) return INITIAL_INTERVAL; if (!strcasecmp (atom + 1, "nitial-delay")) return INITIAL_DELAY; if (!strcasecmp (atom + 1, "nterface")) return INTERFACE; if (!strcasecmp (atom + 1, "dentifier")) return IDENTIFIER; if (!strcasecmp (atom + 1, "f")) return IF; if (!strcasecmp (atom + 1, "s")) return IS; if (!strcasecmp (atom + 1, "gnore")) return IGNORE; break; case 'k': if (!strncasecmp (atom + 1, "nown", 4)) { if (!strcasecmp (atom + 5, "-clients")) return KNOWN_CLIENTS; if (!atom[5]) return KNOWN; break; } if (!strcasecmp (atom + 1, "ey")) return KEY; break; case 'l': if (!strcasecmp (atom + 1, "case")) return LCASE; if (!strcasecmp (atom + 1, "ease")) return LEASE; if (!strcasecmp(atom + 1, "ease6")) return LEASE6; if (!strcasecmp (atom + 1, "eased-address")) return LEASED_ADDRESS; if (!strcasecmp (atom + 1, "ease-time")) return LEASE_TIME; if (!strcasecmp(atom + 1, "easequery")) return LEASEQUERY; if (!strcasecmp(atom + 1, "ength")) return LENGTH; if (!strcasecmp (atom + 1, "imit")) return LIMIT; if (!strcasecmp (atom + 1, "et")) return LET; if (!strcasecmp (atom + 1, "oad")) return LOAD; if (!strcasecmp(atom + 1, "ocal")) return LOCAL; if (!strcasecmp (atom + 1, "og")) return LOG; if (!strcasecmp(atom+1, "lt")) { return LLT; } if (!strcasecmp(atom+1, "l")) { return LL; } break; case 'm': if (!strncasecmp (atom + 1, "ax", 2)) { if (!atom [3]) return TOKEN_MAX; if (!strcasecmp (atom + 3, "-balance")) return MAX_BALANCE; if (!strncasecmp (atom + 3, "-lease-", 7)) { if (!strcasecmp(atom + 10, "misbalance")) return MAX_LEASE_MISBALANCE; if (!strcasecmp(atom + 10, "ownership")) return MAX_LEASE_OWNERSHIP; if (!strcasecmp(atom + 10, "time")) return MAX_LEASE_TIME; } if (!strcasecmp(atom + 3, "-life")) return MAX_LIFE; if (!strcasecmp (atom + 3, "-transmit-idle")) return MAX_TRANSMIT_IDLE; if (!strcasecmp (atom + 3, "-response-delay")) return MAX_RESPONSE_DELAY; if (!strcasecmp (atom + 3, "-unacked-updates")) return MAX_UNACKED_UPDATES; } if (!strncasecmp (atom + 1, "in-", 3)) { if (!strcasecmp (atom + 4, "balance")) return MIN_BALANCE; if (!strcasecmp (atom + 4, "lease-time")) return MIN_LEASE_TIME; if (!strcasecmp (atom + 4, "secs")) return MIN_SECS; break; } if (!strncasecmp (atom + 1, "edi", 3)) { if (!strcasecmp (atom + 4, "a")) return MEDIA; if (!strcasecmp (atom + 4, "um")) return MEDIUM; break; } if (!strcasecmp (atom + 1, "atch")) return MATCH; if (!strcasecmp (atom + 1, "embers")) return MEMBERS; if (!strcasecmp (atom + 1, "y")) return MY; if (!strcasecmp (atom + 1, "clt")) return MCLT; break; case 'n': if (!strcasecmp (atom + 1, "ormal")) return NORMAL; if (!strcasecmp (atom + 1, "ameserver")) return NAMESERVER; if (!strcasecmp (atom + 1, "etmask")) return NETMASK; if (!strcasecmp (atom + 1, "ever")) return NEVER; if (!strcasecmp (atom + 1, "ext-server")) return NEXT_SERVER; if (!strcasecmp (atom + 1, "ot")) return TOKEN_NOT; if (!strcasecmp (atom + 1, "o")) return TOKEN_NO; if (!strcasecmp (atom + 1, "s-update")) return NS_UPDATE; if (!strcasecmp (atom + 1, "oerror")) return NS_NOERROR; if (!strcasecmp (atom + 1, "otauth")) return NS_NOTAUTH; if (!strcasecmp (atom + 1, "otimp")) return NS_NOTIMP; if (!strcasecmp (atom + 1, "otzone")) return NS_NOTZONE; if (!strcasecmp (atom + 1, "xdomain")) return NS_NXDOMAIN; if (!strcasecmp (atom + 1, "xrrset")) return NS_NXRRSET; if (!strcasecmp (atom + 1, "ull")) return TOKEN_NULL; if (!strcasecmp (atom + 1, "ext")) return TOKEN_NEXT; if (!strcasecmp (atom + 1, "ew")) return TOKEN_NEW; break; case 'o': if (!strcasecmp (atom + 1, "mapi")) return OMAPI; if (!strcasecmp (atom + 1, "r")) return OR; if (!strcasecmp (atom + 1, "n")) return ON; if (!strcasecmp (atom + 1, "pen")) return TOKEN_OPEN; if (!strcasecmp (atom + 1, "ption")) return OPTION; if (!strcasecmp (atom + 1, "ne-lease-per-client")) return ONE_LEASE_PER_CLIENT; if (!strcasecmp (atom + 1, "f")) return OF; if (!strcasecmp (atom + 1, "wner")) return OWNER; break; case 'p': if (!strcasecmp (atom + 1, "repend")) return PREPEND; if (!strcasecmp(atom + 1, "referred-life")) return PREFERRED_LIFE; if (!strcasecmp (atom + 1, "acket")) return PACKET; if (!strcasecmp (atom + 1, "ool")) return POOL; if (!strcasecmp (atom + 1, "refix6")) return PREFIX6; if (!strcasecmp (atom + 1, "seudo")) return PSEUDO; if (!strcasecmp (atom + 1, "eer")) return PEER; if (!strcasecmp (atom + 1, "rimary")) return PRIMARY; if (!strcasecmp (atom + 1, "rimary6")) return PRIMARY6; if (!strncasecmp (atom + 1, "artner", 6)) { if (!atom [7]) return PARTNER; if (!strcasecmp (atom + 7, "-down")) return PARTNER_DOWN; } if (!strcasecmp (atom + 1, "ort")) return PORT; if (!strcasecmp (atom + 1, "otential-conflict")) return POTENTIAL_CONFLICT; if (!strcasecmp (atom + 1, "ick-first-value") || !strcasecmp (atom + 1, "ick")) return PICK; if (!strcasecmp (atom + 1, "aused")) return PAUSED; break; case 'r': if (!strcasecmp(atom + 1, "ange")) return RANGE; if (!strcasecmp(atom + 1, "ange6")) return RANGE6; if (isascii(atom[1]) && (tolower((unsigned char)atom[1]) == 'e')) { if (!strcasecmp(atom + 2, "bind")) return REBIND; if (!strcasecmp(atom + 2, "boot")) return REBOOT; if (!strcasecmp(atom + 2, "contact-interval")) return RECONTACT_INTERVAL; if (!strncasecmp(atom + 2, "cover", 5)) { if (atom[7] == '\0') return RECOVER; if (!strcasecmp(atom + 7, "-done")) return RECOVER_DONE; if (!strcasecmp(atom + 7, "-wait")) return RECOVER_WAIT; break; } if (!strcasecmp(atom + 2, "fresh")) return REFRESH; if (!strcasecmp(atom + 2, "fused")) return NS_REFUSED; if (!strcasecmp(atom + 2, "ject")) return REJECT; if (!strcasecmp(atom + 2, "lease")) return RELEASE; if (!strcasecmp(atom + 2, "leased")) return TOKEN_RELEASED; if (!strcasecmp(atom + 2, "move")) return REMOVE; if (!strcasecmp(atom + 2, "new")) return RENEW; if (!strcasecmp(atom + 2, "quest")) return REQUEST; if (!strcasecmp(atom + 2, "quire")) return REQUIRE; if (isascii(atom[2]) && (tolower((unsigned char)atom[2]) == 's')) { if (!strcasecmp(atom + 3, "erved")) return TOKEN_RESERVED; if (!strcasecmp(atom + 3, "et")) return TOKEN_RESET; if (!strcasecmp(atom + 3, "olution-interrupted")) return RESOLUTION_INTERRUPTED; break; } if (!strcasecmp(atom + 2, "try")) return RETRY; if (!strcasecmp(atom + 2, "turn")) return RETURN; if (!strcasecmp(atom + 2, "verse")) return REVERSE; if (!strcasecmp(atom + 2, "wind")) return REWIND; break; } break; case 's': if (!strcasecmp(atom + 1, "cript")) return SCRIPT; if (isascii(atom[1]) && tolower((unsigned char)atom[1]) == 'e') { if (!strcasecmp(atom + 2, "arch")) return SEARCH; if (isascii(atom[2]) && tolower((unsigned char)atom[2]) == 'c') { if (!strncasecmp(atom + 3, "ond", 3)) { if (!strcasecmp(atom + 6, "ary")) return SECONDARY; if (!strcasecmp(atom + 6, "ary6")) return SECONDARY6; if (!strcasecmp(atom + 6, "s")) return SECONDS; break; } if (!strcasecmp(atom + 3, "ret")) return SECRET; break; } if (!strncasecmp(atom + 2, "lect", 4)) { if (atom[6] == '\0') return SELECT; if (!strcasecmp(atom + 6, "-timeout")) return SELECT_TIMEOUT; break; } if (!strcasecmp(atom + 2, "nd")) return SEND; if (!strncasecmp(atom + 2, "rv", 2)) { if (!strncasecmp(atom + 4, "er", 2)) { if (atom[6] == '\0') return TOKEN_SERVER; if (atom[6] == '-') { if (!strcasecmp(atom + 7, "duid")) return SERVER_DUID; if (!strcasecmp(atom + 7, "name")) return SERVER_NAME; if (!strcasecmp(atom + 7, "identifier")) return SERVER_IDENTIFIER; break; } break; } if (!strcasecmp(atom + 4, "fail")) return NS_SERVFAIL; break; } if (!strcasecmp(atom + 2, "t")) return TOKEN_SET; break; } if (isascii(atom[1]) && tolower((unsigned char)atom[1]) == 'h') { if (!strcasecmp(atom + 2, "ared-network")) return SHARED_NETWORK; if (!strcasecmp(atom + 2, "utdown")) return SHUTDOWN; break; } if (isascii(atom[1]) && tolower((unsigned char)atom[1]) == 'i') { if (!strcasecmp(atom + 2, "addr")) return SIADDR; if (!strcasecmp(atom + 2, "gned")) return SIGNED; if (!strcasecmp(atom + 2, "ze")) return SIZE; break; } if (isascii(atom[1]) && tolower((unsigned char)atom[1]) == 'p') { if (isascii(atom[2]) && tolower((unsigned char)atom[2]) == 'a') { if (!strcasecmp(atom + 3, "ce")) return SPACE; if (!strcasecmp(atom + 3, "wn")) return SPAWN; break; } if (!strcasecmp(atom + 2, "lit")) return SPLIT; break; } if (isascii(atom[1]) && tolower((unsigned char)atom[1]) == 't') { if (isascii(atom[2]) && tolower((unsigned char)atom[2]) == 'a') { if(!strncasecmp(atom + 3, "rt", 2)) { if (!strcasecmp(atom + 5, "s")) return STARTS; if (!strcasecmp(atom + 5, "up")) return STARTUP; break; } if (isascii(atom[3]) && tolower((unsigned char)atom[3]) == 't') { if (!strcasecmp(atom + 4, "e")) return STATE; if (!strcasecmp(atom + 4, "ic")) return STATIC; break; } } if (!strcasecmp(atom + 2, "ring")) return STRING_TOKEN; break; } if (!strncasecmp(atom + 1, "ub", 2)) { if (!strcasecmp(atom + 3, "class")) return SUBCLASS; if (!strcasecmp(atom + 3, "net")) return SUBNET; if (!strcasecmp(atom + 3, "net6")) return SUBNET6; if (!strcasecmp(atom + 3, "string")) return SUBSTRING; break; } if (isascii(atom[1]) && tolower((unsigned char)atom[1]) == 'u') { if (!strcasecmp(atom + 2, "ffix")) return SUFFIX; if (!strcasecmp(atom + 2, "persede")) return SUPERSEDE; } if (!strcasecmp(atom + 1, "witch")) return SWITCH; break; case 't': if (!strcasecmp (atom + 1, "imestamp")) return TIMESTAMP; if (!strcasecmp (atom + 1, "imeout")) return TIMEOUT; if (!strcasecmp (atom + 1, "oken-ring")) return TOKEN_RING; if (!strcasecmp (atom + 1, "ext")) return TEXT; if (!strcasecmp (atom + 1, "stp")) return TSTP; if (!strcasecmp (atom + 1, "sfp")) return TSFP; if (!strcasecmp (atom + 1, "ransmission")) return TRANSMISSION; if (!strcasecmp(atom + 1, "emporary")) return TEMPORARY; break; case 'u': if (!strcasecmp (atom + 1, "case")) return UCASE; if (!strcasecmp (atom + 1, "nset")) return UNSET; if (!strcasecmp (atom + 1, "nsigned")) return UNSIGNED; if (!strcasecmp (atom + 1, "id")) return UID; if (!strncasecmp (atom + 1, "se", 2)) { if (!strcasecmp (atom + 3, "r-class")) return USER_CLASS; if (!strcasecmp (atom + 3, "-host-decl-names")) return USE_HOST_DECL_NAMES; if (!strcasecmp (atom + 3, "-lease-addr-for-default-route")) return USE_LEASE_ADDR_FOR_DEFAULT_ROUTE; break; } if (!strncasecmp (atom + 1, "nknown", 6)) { if (!strcasecmp (atom + 7, "-clients")) return UNKNOWN_CLIENTS; if (!strcasecmp (atom + 7, "-state")) return UNKNOWN_STATE; if (!atom [7]) return UNKNOWN; break; } if (!strcasecmp (atom + 1, "nauthenticated")) return UNAUTHENTICATED; if (!strcasecmp (atom + 1, "pdated-dns-rr")) return UPDATED_DNS_RR; if (!strcasecmp (atom + 1, "pdate")) return UPDATE; break; case 'v': if (!strcasecmp (atom + 1, "endor-class")) return VENDOR_CLASS; if (!strcasecmp (atom + 1, "endor")) return VENDOR; break; case 'w': if (!strcasecmp (atom + 1, "ith")) return WITH; if (!strcasecmp(atom + 1, "idth")) return WIDTH; break; case 'y': if (!strcasecmp (atom + 1, "iaddr")) return YIADDR; if (!strcasecmp (atom + 1, "xdomain")) return NS_YXDOMAIN; if (!strcasecmp (atom + 1, "xrrset")) return NS_YXRRSET; break; case 'z': if (!strcasecmp (atom + 1, "erolen")) return ZEROLEN; if (!strcasecmp (atom + 1, "one")) return ZONE; break; } return dfv; } dhcp-4.2.4/common/ctrace.c000644 000765 000024 00000017451 11301372613 015271 0ustar00sarstaff000000 000000 /* trace.c Subroutines that support dhcp tracing... */ /* * Copyright (c) 2004,2007,2009 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 2001-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ * * This software has been written for Internet Systems Consortium * by Ted Lemon, as part of a project for Nominum, Inc. To learn more * about Internet Systems Consortium, see https://www.isc.org/. To * learn more about Nominum, Inc., see ``http://www.nominum.com''. */ #include "dhcpd.h" #if defined (TRACING) void trace_interface_register (trace_type_t *ttype, struct interface_info *ip) { trace_interface_packet_t tipkt; if (trace_record ()) { memset (&tipkt, 0, sizeof tipkt); memcpy (&tipkt.hw_address, &ip -> hw_address, sizeof ip -> hw_address); if (ip->address_count) memcpy(&tipkt.primary_address, ip->addresses, sizeof(*ip->addresses)); memcpy (tipkt.name, ip -> name, sizeof ip -> name); tipkt.index = htonl (ip -> index); trace_write_packet (ttype, sizeof tipkt, (char *)&tipkt, MDL); } } void trace_interface_input (trace_type_t *ttype, unsigned len, char *buf) { trace_interface_packet_t *tipkt; struct interface_info *ip; struct sockaddr_in *sin; struct iaddr addr; isc_result_t status; if (len != sizeof *tipkt) { log_error ("trace interface packet size mismatch: %ld != %d", (long)(sizeof *tipkt), len); return; } tipkt = (trace_interface_packet_t *)buf; ip = (struct interface_info *)0; status = interface_allocate (&ip, MDL); if (status != ISC_R_SUCCESS) { foo: log_error ("trace_interface_input: %s.", isc_result_totext (status)); return; } ip -> ifp = dmalloc (sizeof *(ip -> ifp), MDL); if (!ip -> ifp) { interface_dereference (&ip, MDL); status = ISC_R_NOMEMORY; goto foo; } memcpy (&ip -> hw_address, &tipkt -> hw_address, sizeof ip -> hw_address); /* XXX: Without the full addresses state it's not quite a full * trace. */ ip->address_count = ip->address_max = 1; ip->addresses = dmalloc(sizeof(*ip->addresses), MDL); memcpy(ip->addresses, &tipkt->primary_address, sizeof(*ip->addresses)); memcpy (ip -> name, tipkt -> name, sizeof ip -> name); ip -> index = ntohl (tipkt -> index); interface_snorf (ip, 0); if (dhcp_interface_discovery_hook) (*dhcp_interface_discovery_hook) (ip); /* Fake up an ifp. */ memcpy (ip -> ifp -> ifr_name, ip -> name, sizeof ip -> name); #ifdef HAVE_SA_LEN ip -> ifp -> ifr_addr.sa_len = sizeof (struct sockaddr_in); #endif sin = (struct sockaddr_in *)&ip -> ifp -> ifr_addr; sin->sin_addr = ip->addresses[0]; addr.len = 4; memcpy (addr.iabuf, &sin -> sin_addr.s_addr, addr.len); if (dhcp_interface_setup_hook) (*dhcp_interface_setup_hook) (ip, &addr); interface_stash (ip); if (!quiet_interface_discovery) { log_info ("Listening on Trace/%s/%s%s%s", ip -> name, print_hw_addr (ip -> hw_address.hbuf [0], ip -> hw_address.hlen - 1, &ip -> hw_address.hbuf [1]), (ip -> shared_network ? "/" : ""), (ip -> shared_network ? ip -> shared_network -> name : "")); if (strcmp (ip -> name, "fallback")) { log_info ("Sending on Trace/%s/%s%s%s", ip -> name, print_hw_addr (ip -> hw_address.hbuf [0], ip -> hw_address.hlen - 1, &ip -> hw_address.hbuf [1]), (ip -> shared_network ? "/" : ""), (ip -> shared_network ? ip -> shared_network -> name : "")); } } interface_dereference (&ip, MDL); } void trace_interface_stop (trace_type_t *ttype) { /* XXX */ } void trace_inpacket_stash (struct interface_info *interface, struct dhcp_packet *packet, unsigned len, unsigned int from_port, struct iaddr from, struct hardware *hfrom) { trace_inpacket_t tip; trace_iov_t iov [2]; if (!trace_record ()) return; tip.from_port = from_port; tip.from = from; tip.from.len = htonl (tip.from.len); if (hfrom) { tip.hfrom = *hfrom; tip.havehfrom = 1; } else { memset (&tip.hfrom, 0, sizeof tip.hfrom); tip.havehfrom = 0; } tip.index = htonl (interface -> index); iov [0].buf = (char *)&tip; iov [0].len = sizeof tip; iov [1].buf = (char *)packet; iov [1].len = len; trace_write_packet_iov (inpacket_trace, 2, iov, MDL); } void trace_inpacket_input (trace_type_t *ttype, unsigned len, char *buf) { trace_inpacket_t *tip; int index; if (len < sizeof *tip) { log_error ("trace_input_packet: too short - %d", len); return; } tip = (trace_inpacket_t *)buf; index = ntohl (tip -> index); tip -> from.len = ntohl (tip -> from.len); if (index > interface_count || index < 0 || !interface_vector [index]) { log_error ("trace_input_packet: unknown interface index %d", index); return; } if (!bootp_packet_handler) { log_error ("trace_input_packet: no bootp packet handler."); return; } (*bootp_packet_handler) (interface_vector [index], (struct dhcp_packet *)(tip + 1), len - sizeof *tip, tip -> from_port, tip -> from, (tip -> havehfrom ? &tip -> hfrom : (struct hardware *)0)); } void trace_inpacket_stop (trace_type_t *ttype) { } ssize_t trace_packet_send (struct interface_info *interface, struct packet *packet, struct dhcp_packet *raw, size_t len, struct in_addr from, struct sockaddr_in *to, struct hardware *hto) { trace_outpacket_t tip; trace_iov_t iov [2]; if (trace_record ()) { if (hto) { tip.hto = *hto; tip.havehto = 1; } else { memset (&tip.hto, 0, sizeof tip.hto); tip.havehto = 0; } tip.from.len = 4; memcpy (tip.from.iabuf, &from, 4); tip.to.len = 4; memcpy (tip.to.iabuf, &to -> sin_addr, 4); tip.to_port = to -> sin_port; tip.index = htonl (interface -> index); iov [0].buf = (char *)&tip; iov [0].len = sizeof tip; iov [1].buf = (char *)raw; iov [1].len = len; trace_write_packet_iov (outpacket_trace, 2, iov, MDL); } if (!trace_playback ()) { return send_packet (interface, packet, raw, len, from, to, hto); } return len; } void trace_outpacket_input (trace_type_t *ttype, unsigned len, char *buf) { trace_outpacket_t *tip; int index; if (len < sizeof *tip) { log_error ("trace_input_packet: too short - %d", len); return; } tip = (trace_outpacket_t *)buf; index = ntohl (tip -> index); if (index > interface_count || index < 0 || !interface_vector [index]) { log_error ("trace_input_packet: unknown interface index %d", index); return; } /* XXX would be nice to somehow take notice of these. */ } void trace_outpacket_stop (trace_type_t *ttype) { } void trace_seed_stash (trace_type_t *ttype, unsigned seed) { u_int32_t outseed; if (!trace_record ()) return; outseed = htonl (seed); trace_write_packet (ttype, sizeof outseed, (char *)&outseed, MDL); return; } void trace_seed_input (trace_type_t *ttype, unsigned length, char *buf) { u_int32_t *seed; if (length != sizeof seed) { log_error ("trace_seed_input: wrong size (%d)", length); } seed = (u_int32_t *)buf; srandom (ntohl (*seed)); } void trace_seed_stop (trace_type_t *ttype) { } #endif /* TRACING */ dhcp-4.2.4/common/dhcp-eval.5000644 000765 000024 00000052610 11755217170 015622 0ustar00sarstaff000000 000000 .\" $Id: dhcp-eval.5,v 1.29.24.4 2012-05-17 15:51:20 sar Exp $ .\" .\" Copyright (c) 2009-2011 by Internet Systems Consortium, Inc. ("ISC") .\" Copyright (c) 2004,2007 by Internet Systems Consortium, Inc. ("ISC") .\" Copyright (c) 1996-2003 by Internet Software Consortium .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above .\" copyright notice and this permission notice appear in all copies. .\" .\" THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES .\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR .\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES .\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT .\" OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" .\" Internet Systems Consortium, Inc. .\" 950 Charter Street .\" Redwood City, CA 94063 .\" .\" https://www.isc.org/ .\" .\" This software has been written for Internet Systems Consortium .\" by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. .\" .\" Support and other services are available for ISC products - see .\" https://www.isc.org for more information or to learn more about ISC. .\" .TH dhcp-eval 5 .SH NAME dhcp-eval - ISC DHCP conditional evaluation .SH DESCRIPTION The Internet Systems Consortium DHCP client and server both provide the ability to perform conditional behavior depending on the contents of packets they receive. The syntax for specifying this conditional behaviour is documented here. .SH REFERENCE: CONDITIONAL BEHAVIOUR Conditional behaviour is specified using the if statement and the else or elsif statements. A conditional statement can appear anywhere that a regular statement (e.g., an option statement) can appear, and can enclose one or more such statements. A typical conditional statement in a server might be: .PP .nf if option dhcp-user-class = "accounting" { max-lease-time 17600; option domain-name "accounting.example.org"; option domain-name-servers ns1.accounting.example.org, ns2.accounting.example.org; } elsif option dhcp-user-class = "sales" { max-lease-time 17600; option domain-name "sales.example.org"; option domain-name-servers ns1.sales.example.org, ns2.sales.example.org; } elsif option dhcp-user-class = "engineering" { max-lease-time 17600; option domain-name "engineering.example.org"; option domain-name-servers ns1.engineering.example.org, ns2.engineering.example.org; } else { max-lease-time 600; option domain-name "misc.example.org"; option domain-name-servers ns1.misc.example.org, ns2.misc.example.org; } .fi .PP On the client side, an example of conditional evaluation might be: .PP .nf # example.org filters DNS at its firewall, so we have to use their DNS # servers when we connect to their network. If we are not at # example.org, prefer our own DNS server. if not option domain-name = "example.org" { prepend domain-name-servers 127.0.0.1; } .fi .PP The .B if statement and the .B elsif continuation statement both take boolean expressions as their arguments. That is, they take expressions that, when evaluated, produce a boolean result. If the expression evaluates to true, then the statements enclosed in braces following the .B if statement are executed, and all subsequent .B elsif and .B else clauses are skipped. Otherwise, each subsequent .B elsif clause's expression is checked, until an elsif clause is encountered whose test evaluates to true. If such a clause is found, the statements in braces following it are executed, and then any subsequent .B elsif and .B else clauses are skipped. If all the .B if and .B elsif clauses are checked but none of their expressions evaluate true, then if there is an .B else clause, the statements enclosed in braces following the .B else are evaluated. Boolean expressions that evaluate to null are treated as false in conditionals. .SH BOOLEAN EXPRESSIONS The following is the current list of boolean expressions that are supported by the DHCP distribution. .PP .I data-expression-1 \fB=\fR \fIdata-expression-2\fR .RS 0.25i .PP The \fB=\fR operator compares the values of two data expressions, returning true if they are the same, false if they are not. If either the left-hand side or the right-hand side are null, the result is also null. .RE .PP .I data-expression-1 \fB~=\fR \fIdata-expression-2\fR .I data-expression-1 \fB~~\fR \fIdata-expression-2\fR .RS 0.25i .PP The \fB~=\fR and \fB~~\fR operators (not available on all systems) perform extended regex(7) matching of the values of two data expressions, returning true if \fIdata-expression-1\fR matches against the regular expression evaluated by \fIdata-expression-2\fR, or false if it does not match or encounters some error. If either the left-hand side or the right-hand side are null or empty strings, the result is also false. The \fB~~\fR operator differs from the \fB~=\fR operator in that it is case-insensitive. .RE .PP .I boolean-expression-1 \fBand\fR \fIboolean-expression-2\fR .PP .RS 0.25i The \fBand\fR operator evaluates to true if the boolean expression on the left-hand side and the boolean expression on the right-hand side both evaluate to true. Otherwise, it evaluates to false. If either the expression on the left-hand side or the expression on the right-hand side are null, the result is null. .RE .PP .I boolean-expression-1 \fBor\fR \fIboolean-expression-2\fR .PP .RS 0.25i The \fBor\fR operator evaluates to true if either the boolean expression on the left-hand side or the boolean expression on the right-hand side evaluate to true. Otherwise, it evaluates to false. If either the expression on the left-hand side or the expression on the right-hand side are null, the result is null. .RE .PP .B not \fIboolean-expression .PP .RS 0.25i The \fBnot\fR operator evaluates to true if \fIboolean-expression\fR evaluates to false, and returns false if \fIboolean-expression\fR evaluates to true. If \fIboolean-expression\fR evaluates to null, the result is also null. .RE .PP .B exists \fIoption-name\fR .PP .RS 0.25i The \fBexists\fR expression returns true if the specified option exists in the incoming DHCP packet being processed. .RE .B known .PP .RS 0.25i The \fBknown\fR expression returns true if the client whose request is currently being processed is known - that is, if there's a host declaration for it. .RE .B static .PP .RS 0.25i The \fBstatic\fR expression returns true if the lease assigned to the client whose request is currently being processed is derived from a static address assignment. .RE .SH DATA EXPRESSIONS Several of the boolean expressions above depend on the results of evaluating data expressions. A list of these expressions is provided here. .PP .B substring (\fIdata-expr\fB, \fIoffset\fB, \fIlength\fB)\fR .PP .RS 0.25i The \fBsubstring\fR operator evaluates the data expression and returns the substring of the result of that evaluation that starts \fIoffset\fR bytes from the beginning, continuing for \fIlength\fR bytes. \fIOffset\fR and \fIlength\fR are both numeric expressions. If \fIdata-expr\fR, \fIoffset\fR or \fIlength\fR evaluate to null, then the result is also null. If \fIoffset\fR is greater than or equal to the length of the evaluated data, then a zero-length data string is returned. If \fIlength\fI is greater then the remaining length of the evaluated data after \fIoffset\fR, then a data string containing all data from \fIoffset\fR to the end of the evaluated data is returned. .RE .PP .B suffix (\fIdata-expr\fB, \fIlength\fB)\fR .PP .RS 0.25i The \fBsuffix\fR operator evaluates \fIdata-expr\fR and returns the last \fIlength\fR bytes of the result of that evaluation. \fILength\fR is a numeric expression. If \fIdata-expr\fR or \fIlength\fR evaluate to null, then the result is also null. If \fIsuffix\fR evaluates to a number greater than the length of the evaluated data, then the evaluated data is returned. .RE .PP .B lcase (\fIdata-expr\fB)\fR .PP .RS 0.25i The \fBlcase\fR function returns the result of evaluating \fIdata-expr\fR converted to lower case. If \fIdata-expr\fR evaluates to null, then the result is also null. .RE .PP .B ucase (\fIdata-expr\fB)\fR .PP .RS 0.25i The \fBucase\fR function returns the result of evaluating \fIdata-expr\fR converted to upper case. If \fIdata-expr\fR evaluates to null, then the result is also null. .RE .PP .B option \fIoption-name\fR .PP .RS 0.25i The \fBoption\fR operator returns the contents of the specified option in the packet to which the server is responding. .RE .PP .B config-option \fIoption-name\fR .PP .RS 0.25i The \fBconfig-option\fR operator returns the value for the specified option that the DHCP client or server has been configured to send. .RE .PP .B gethostname() .PP .RS 0.25i The \fBgethostname()\fR function returns a data string whose contents are a character string, the results of calling gethostname() on the local system with a size limit of 255 bytes (not including NULL terminator). This can be used for example to configure dhclient to send the local hostname without knowing the local hostname at the time dhclient.conf is written. .RE .PP .B hardware .PP .RS 0.25i The \fBhardware\fR operator returns a data string whose first element is the type of network interface indicated in packet being considered, and whose subsequent elements are client's link-layer address. If there is no packet, or if the RFC2131 \fIhlen\fR field is invalid, then the result is null. Hardware types include ethernet (1), token-ring (6), and fddi (8). Hardware types are specified by the IETF, and details on how the type numbers are defined can be found in RFC2131 (in the ISC DHCP distribution, this is included in the doc/ subdirectory). .RE .PP .B packet (\fIoffset\fB, \fIlength\fB)\fR .PP .RS 0.25i The \fBpacket\fR operator returns the specified portion of the packet being considered, or null in contexts where no packet is being considered. \fIOffset\fR and \fIlength\fR are applied to the contents packet as in the \fBsubstring\fR operator. .RE .PP .I string .PP .RS 0.25i A string, enclosed in quotes, may be specified as a data expression, and returns the text between the quotes, encoded in ASCII. The backslash ('\\') character is treated specially, as in C programming: '\\t' means TAB, '\\r' means carriage return, '\\n' means newline, and '\\b' means bell. Any octal value can be specified with '\\nnn', where nnn is any positive octal number less than 0400. Any hexadecimal value can be specified with '\\xnn', where nn is any positive hexadecimal number less than or equal to 0xff. .RE .PP .I colon-separated hexadecimal list .PP .RS 0.25i A list of hexadecimal octet values, separated by colons, may be specified as a data expression. .RE .PP .B concat (\fIdata-expr1\fB, ..., \fIdata-exprN\fB)\fR .RS 0.25i The expressions are evaluated, and the results of each evaluation are concatenated in the sequence that the subexpressions are listed. If any subexpression evaluates to null, the result of the concatenation is null. .RE .PP .B reverse (\fInumeric-expr1\fB, \fIdata-expr2\fB)\fR .RS 0.25i The two expressions are evaluated, and then the result of evaluating the data expression is reversed in place, using hunks of the size specified in the numeric expression. For example, if the numeric expression evaluates to four, and the data expression evaluates to twelve bytes of data, then the reverse expression will evaluate to twelve bytes of data, consisting of the last four bytes of the the input data, followed by the middle four bytes, followed by the first four bytes. .RE .PP .B leased-address .RS 0.25i In any context where the client whose request is being processed has been assigned an IP address, this data expression returns that IP address. In any context where the client whose request is being processed has not been assigned an ip address, if this data expression is found in executable statements executed on that client's behalf, a log message indicating "there is no lease associated with this client" is syslogged to the debug level (this is considered dhcpd.conf debugging information). .RE .PP .B binary-to-ascii (\fInumeric-expr1\fB, \fInumeric-expr2\fB, .B \fIdata-expr1\fB,\fR \fIdata-expr2\fB)\fR .RS 0.25i Converts the result of evaluating data-expr2 into a text string containing one number for each element of the result of evaluating data-expr2. Each number is separated from the other by the result of evaluating data-expr1. The result of evaluating numeric-expr1 specifies the base (2 through 16) into which the numbers should be converted. The result of evaluating numeric-expr2 specifies the width in bits of each number, which may be either 8, 16 or 32. .PP As an example of the preceding three types of expressions, to produce the name of a PTR record for the IP address being assigned to a client, one could write the following expression: .RE .PP .nf concat (binary-to-ascii (10, 8, ".", reverse (1, leased-address)), ".in-addr.arpa."); .fi .RE .PP .B encode-int (\fInumeric-expr\fB, \fIwidth\fB)\fR .RS 0.25i Numeric-expr is evaluated and encoded as a data string of the specified width, in network byte order (most significant byte first). If the numeric expression evaluates to the null value, the result is also null. .RE .PP .B pick-first-value (\fIdata-expr1\fR [ ... \fIexpr\fRn ] \fB)\fR .RS 0.25i The pick-first-value function takes any number of data expressions as its arguments. Each expression is evaluated, starting with the first in the list, until an expression is found that does not evaluate to a null value. That expression is returned, and none of the subsequent expressions are evaluated. If all expressions evaluate to a null value, the null value is returned. .RE .PP .B host-decl-name .RS 0.25i The host-decl-name function returns the name of the host declaration that matched the client whose request is currently being processed, if any. If no host declaration matched, the result is the null value. .RE .SH NUMERIC EXPRESSIONS Numeric expressions are expressions that evaluate to an integer. In general, the maximum size of such an integer should not be assumed to be representable in fewer than 32 bits, but the precision of such integers may be more than 32 bits. .PP .B extract-int (\fIdata-expr\fB, \fIwidth\fB)\fR .PP .RS 0.25i The \fBextract-int\fR operator extracts an integer value in network byte order from the result of evaluating the specified data expression. Width is the width in bits of the integer to extract. Currently, the only supported widths are 8, 16 and 32. If the evaluation of the data expression doesn't provide sufficient bits to extract an integer of the specified size, the null value is returned. .RE .PP .B lease-time .PP .RS 0.25i The duration of the current lease - that is, the difference between the current time and the time that the lease expires. .RE .PP .I number .PP .RS 0.25i Any number between zero and the maximum representable size may be specified as a numeric expression. .RE .PP .B client-state .PP .RS 0.25i The current state of the client instance being processed. This is only useful in DHCP client configuration files. Possible values are: .TP 2 .I \(bu Booting - DHCP client is in the INIT state, and does not yet have an IP address. The next message transmitted will be a DHCPDISCOVER, which will be broadcast. .TP .I \(bu Reboot - DHCP client is in the INIT-REBOOT state. It has an IP address, but is not yet using it. The next message to be transmitted will be a DHCPREQUEST, which will be broadcast. If no response is heard, the client will bind to its address and move to the BOUND state. .TP .I \(bu Select - DHCP client is in the SELECTING state - it has received at least one DHCPOFFER message, but is waiting to see if it may receive other DHCPOFFER messages from other servers. No messages are sent in the SELECTING state. .TP .I \(bu Request - DHCP client is in the REQUESTING state - it has received at least one DHCPOFFER message, and has chosen which one it will request. The next message to be sent will be a DHCPREQUEST message, which will be broadcast. .TP .I \(bu Bound - DHCP client is in the BOUND state - it has an IP address. No messages are transmitted in this state. .TP .I \(bu Renew - DHCP client is in the RENEWING state - it has an IP address, and is trying to contact the server to renew it. The next message to be sent will be a DHCPREQUEST message, which will be unicast directly to the server. .TP .I \(bu Rebind - DHCP client is in the REBINDING state - it has an IP address, and is trying to contact any server to renew it. The next message to be sent will be a DHCPREQUEST, which will be broadcast. .RE .SH REFERENCE: ACTION EXPRESSIONS .PP .B log (\fIpriority\fB, \fIdata-expr\fB)\fR .RS 0.25i .PP Logging statements may be used to send information to the standard logging channels. A logging statement includes an optional priority (\fBfatal\fR, \fBerror\fR, \fBinfo\fR, or \fBdebug\fR), and a data expression. .PP Logging statements take only a single data expression argument, so if you want to output multiple data values, you will need to use the \fBconcat\fR operator to concatenate them. .RE .PP .B execute (\fIcommand-path\fB [, \fIdata-expr1\fB, ... \fIdata-exprN\fB]);\fR .RS 0.25i .PP The \fBexecute\fR statement runs an external command. The first argument is a string literal containing the name or path of the command to run. The other arguments, if present, are either string literals or data- expressions which evaluate to text strings, to be passed as command-line arguments to the command. .PP \fBexecute\fR is synchronous; the program will block until the external command being run has finished. Please note that lengthy program execution (for example, in an "on commit" in dhcpd.conf) may result in bad performance and timeouts. Only external applications with very short execution times are suitable for use. .PP Passing user-supplied data to an external application might be dangerous. Make sure the external application checks input buffers for validity. Non-printable ASCII characters will be converted into dhcpd.conf language octal escapes ("\\nnn"), make sure your external command handles them as such. .PP It is possible to use the execute statement in any context, not only on events. If you put it in a regular scope in the configuration file you will execute that command every time a scope is evaluated. .RE .SH REFERENCE: DYNAMIC DNS UPDATES .PP The DHCP client and server have the ability to dynamically update the Domain Name System. Within the configuration files, you can define how you want the Domain Name System to be updated. These updates are RFC 2136 compliant so any DNS server supporting RFC 2136 should be able to accept updates from the DHCP server. .SH SECURITY Support for TSIG and DNSSEC is not yet available. When you set your DNS server up to allow updates from the DHCP server or client, you may be exposing it to unauthorized updates. To avoid this, the best you can do right now is to use IP address-based packet filtering to prevent unauthorized hosts from submitting update requests. Obviously, there is currently no way to provide security for client updates - this will require TSIG or DNSSEC, neither of which is yet available in the DHCP distribution. .PP Dynamic DNS (DDNS) updates are performed by using the \fBdns-update\fR expression. The \fBdns-update\fR expression is a boolean expression that takes four parameters. If the update succeeds, the result is true. If it fails, the result is false. The four parameters that the are the resource record type (RR), the left hand side of the RR, the right hand side of the RR and the ttl that should be applied to the record. The simplest example of the use of the function can be found in the reference section of the dhcpd.conf file, where events are described. In this example several statements are being used to make the arguments to the \fBdns-update\fR. .PP In the example, the first argument to the first \f\Bdns-update\fR expression is a data expression that evaluates to the A RR type. The second argument is constructed by concatenating the DHCP host-name option with a text string containing the local domain, in this case "ssd.example.net". The third argument is constructed by converting the address the client has been assigned from a 32-bit number into an ascii string with each byte separated by a ".". The fourth argument, the TTL, specifies the amount of time remaining in the lease (note that this isn't really correct, since the DNS server will pass this TTL out whenever a request comes in, even if that is only a few seconds before the lease expires). .PP If the first \fBdns-update\fR statement succeeds, it is followed up with a second update to install a PTR RR. The installation of a PTR record is similar to installing an A RR except that the left hand side of the record is the leased address, reversed, with ".in-addr.arpa" concatenated. The right hand side is the fully qualified domain name of the client to which the address is being leased. .SH SEE ALSO dhcpd.conf(5), dhcpd.leases(5), dhclient.conf(5), dhcp-options(5), dhcpd(8), dhclient(8), RFC2132, RFC2131. .SH AUTHOR The Internet Systems Consortium DHCP Distribution was written by Ted Lemon under a contract with Vixie Labs. Funding for this project was provided through Internet Systems Consortium. Information about Internet Systems Consortium can be found at .B https://www.isc.org. dhcp-4.2.4/common/dhcp-options.5000644 000765 000024 00000215417 11565475666 016413 0ustar00sarstaff000000 000000 .\" $Id: dhcp-options.5,v 1.45.18.6 2011-05-20 14:33:26 tomasz Exp $ .\" .\" Copyright (c) 2004-2010 by Internet Systems Consortium, Inc. ("ISC") .\" Copyright (c) 1996-2003 by Internet Software Consortium .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above .\" copyright notice and this permission notice appear in all copies. .\" .\" THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES .\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR .\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES .\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT .\" OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" .\" Internet Systems Consortium, Inc. .\" 950 Charter Street .\" Redwood City, CA 94063 .\" .\" https://www.isc.org/ .\" .\" This software has been written for Internet Systems Consortium .\" by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. .\" .\" Support and other services are available for ISC products - see .\" https://www.isc.org for more information or to learn more about ISC. .\" .TH dhcp-options 5 .SH NAME dhcp-options - Dynamic Host Configuration Protocol options .SH DESCRIPTION The Dynamic Host Configuration protocol allows the client to receive .B options from the DHCP server describing the network configuration and various services that are available on the network. When configuring .B dhcpd(8) or .B dhclient(8) , options must often be declared. The syntax for declaring options, and the names and formats of the options that can be declared, are documented here. .SH REFERENCE: OPTION STATEMENTS .PP DHCP \fIoption\fR statements always start with the \fIoption\fR keyword, followed by an option name, followed by option data. The option names and data formats are described below. It is not necessary to exhaustively specify all DHCP options - only those options which are needed by clients must be specified. .PP Option data comes in a variety of formats, as defined below: .PP The .B ip-address data type can be entered either as an explicit IP address (e.g., 239.254.197.10) or as a domain name (e.g., haagen.isc.org). When entering a domain name, be sure that that domain name resolves to a single IP address. .PP The .B ip6-address data specifies an IPv6 address, like ::1 or 3ffe:bbbb:aaaa:aaaa::1. .PP The .B int32 data type specifies a signed 32-bit integer. The .B uint32 data type specifies an unsigned 32-bit integer. The .B int16 and .B uint16 data types specify signed and unsigned 16-bit integers. The .B int8 and .B uint8 data types specify signed and unsigned 8-bit integers. Unsigned 8-bit integers are also sometimes referred to as octets. .PP The .B text data type specifies an NVT ASCII string, which must be enclosed in double quotes - for example, to specify a root-path option, the syntax would be .nf .sp 1 option root-path "10.0.1.4:/var/tmp/rootfs"; .fi .PP The .B domain-name data type specifies a domain name, which must not be enclosed in double quotes. This data type is not used for any existing DHCP options. The domain name is stored just as if it were a text option. .PP The .B domain-list data type specifies a list of domain names, enclosed in double quotes and separated by commas ("example.com", "foo.example.com"). .PP The .B flag data type specifies a boolean value. Booleans can be either true or false (or on or off, if that makes more sense to you). .PP The .B string data type specifies either an NVT ASCII string enclosed in double quotes, or a series of octets specified in hexadecimal, separated by colons. For example: .nf .sp 1 option dhcp-client-identifier "CLIENT-FOO"; or option dhcp-client-identifier 43:4c:49:45:54:2d:46:4f:4f; .fi .SH SETTING OPTION VALUES USING EXPRESSIONS Sometimes it's helpful to be able to set the value of a DHCP option based on some value that the client has sent. To do this, you can use expression evaluation. The .B dhcp-eval(5) manual page describes how to write expressions. To assign the result of an evaluation to an option, define the option as follows: .nf .sp 1 \fBoption \fImy-option \fB= \fIexpression \fB;\fR .fi .PP For example: .nf .sp 1 option hostname = binary-to-ascii (16, 8, "-", substring (hardware, 1, 6)); .fi .SH STANDARD DHCPV4 OPTIONS The documentation for the various options mentioned below is taken from the latest IETF draft document on DHCP options. Options not listed below may not yet be implemented, but it is possible to use such options by defining them in the configuration file. Please see the DEFINING NEW OPTIONS heading later in this document for more information. .PP Some of the options documented here are automatically generated by the DHCP server or by clients, and cannot be configured by the user. The value of such an option can be used in the configuration file of the receiving DHCP protocol agent (server or client), for example in conditional expressions. However, the value of the option cannot be used in the configuration file of the sending agent, because the value is determined only \fIafter\fR the configuration file has been processed. In the following documentation, such options will be shown as "not user configurable" .PP The standard options are: .PP .B option \fBall-subnets-local\fR \fIflag\fR\fB;\fR .RS 0.25i .PP This option specifies whether or not the client may assume that all subnets of the IP network to which the client is connected use the same MTU as the subnet of that network to which the client is directly connected. A value of true indicates that all subnets share the same MTU. A value of false means that the client should assume that some subnets of the directly connected network may have smaller MTUs. .RE .PP .B option \fBarp-cache-timeout\fR \fIuint32\fR\fB;\fR .RS 0.25i .PP This option specifies the timeout in seconds for ARP cache entries. .RE .PP .B option \fBbcms-controller-address\fR \fIip-address\fR [\fB,\fR \fIip-address\fR... ]\fB;\fR .RS 0.25i .PP This option configures a list of IPv4 addresses for use as Broadcast and Multicast Controller Servers ("BCMS"). .RE .PP .B option \fBbcms-controller-names\fR \fIdomain-list\fR\fB;\fR .RS 0.25i .PP This option contains the domain names of local Broadcast and Multicast Controller Servers ("BCMS") controllers which the client may use. .RE .PP .B option \fBbootfile-name\fR \fItext\fR\fB;\fR .RS 0.25i .PP This option is used to identify a bootstrap file. If supported by the client, it should have the same effect as the \fBfilename\fR declaration. BOOTP clients are unlikely to support this option. Some DHCP clients will support it, and others actually require it. .RE .PP .B option \fBboot-size\fR \fIuint16\fR\fB;\fR .RS 0.25i .PP This option specifies the length in 512-octet blocks of the default boot image for the client. .RE .PP .B option \fBbroadcast-address\fR \fIip-address\fR\fB;\fR .RS 0.25i .PP This option specifies the broadcast address in use on the client's subnet. Legal values for broadcast addresses are specified in section 3.2.1.3 of STD 3 (RFC1122). .RE .PP .B option \fBcookie-servers\fR \fIip-address\fR [\fB,\fR \fIip-address\fR... ]\fB;\fR .RS 0.25i .PP The cookie server option specifies a list of RFC 865 cookie servers available to the client. Servers should be listed in order of preference. .RE .PP .B option \fBdefault-ip-ttl\fR \fIuint8;\fR .RS 0.25i .PP This option specifies the default time-to-live that the client should use on outgoing datagrams. .RE .PP .B option \fBdefault-tcp-ttl\fR \fIuint8\fR\fB;\fR .RS 0.25i .PP This option specifies the default TTL that the client should use when sending TCP segments. The minimum value is 1. .RE .PP .B option \fBdefault-url\fR \fIstring\fR\fB;\fR .RS 0.25i .PP The format and meaning of this option is not described in any standards document, but is claimed to be in use by Apple Computer. It is not known what clients may reasonably do if supplied with this option. Use at your own risk. .RE .PP .B option \fBdhcp-client-identifier\fR \fIstring\fR\fB;\fR .RS 0.25i .PP This option can be used to specify a DHCP client identifier in a host declaration, so that dhcpd can find the host record by matching against the client identifier. .PP Please be aware that some DHCP clients, when configured with client identifiers that are ASCII text, will prepend a zero to the ASCII text. So you may need to write: .nf option dhcp-client-identifier "\\0foo"; rather than: option dhcp-client-identifier "foo"; .fi .RE .PP .B option \fBdhcp-lease-time\fR \fIuint32\fR\fB;\fR .RS 0.25i .PP This option is used in a client request (DHCPDISCOVER or DHCPREQUEST) to allow the client to request a lease time for the IP address. In a server reply (DHCPOFFER), a DHCP server uses this option to specify the lease time it is willing to offer. .PP This option is not directly user configurable in the server; refer to the \fImax-lease-time\fR and \fIdefault-lease-time\fR server options in .B dhcpd.conf(5). .RE .PP .B option \fBdhcp-max-message-size\fR \fIuint16\fR\fB;\fR .RS 0.25i .PP This option, when sent by the client, specifies the maximum size of any response that the server sends to the client. When specified on the server, if the client did not send a dhcp-max-message-size option, the size specified on the server is used. This works for BOOTP as well as DHCP responses. .RE .PP .B option \fBdhcp-message\fR \fItext\fR\fB;\fR .RS 0.25i .PP This option is used by a DHCP server to provide an error message to a DHCP client in a DHCPNAK message in the event of a failure. A client may use this option in a DHCPDECLINE message to indicate why the client declined the offered parameters. .PP This option is not user configurable. .RE .PP .B option \fBdhcp-message-type\fR \fIuint8\fR\fB;\fR .RS 0.25i .PP This option, sent by both client and server, specifies the type of DHCP message contained in the DHCP packet. Possible values (taken directly from RFC2132) are: .PP .nf 1 DHCPDISCOVER 2 DHCPOFFER 3 DHCPREQUEST 4 DHCPDECLINE 5 DHCPACK 6 DHCPNAK 7 DHCPRELEASE 8 DHCPINFORM .fi .PP This option is not user configurable. .PP .RE .B option \fBdhcp-option-overload\fR \fIuint8\fR\fB;\fR .RS 0.25i .PP This option is used to indicate that the DHCP \'sname\' or \'file\' fields are being overloaded by using them to carry DHCP options. A DHCP server inserts this option if the returned parameters will exceed the usual space allotted for options. .PP If this option is present, the client interprets the specified additional fields after it concludes interpretation of the standard option fields. .PP Legal values for this option are: .PP .nf 1 the \'file\' field is used to hold options 2 the \'sname\' field is used to hold options 3 both fields are used to hold options .fi .PP This option is not user configurable. .PP .RE .PP .B option \fBdhcp-parameter-request-list\fR \fIuint16\fR [\fB,\fR \fIuint16\fR... ]\fB;\fR .RS 0.25i .PP This option, when sent by the client, specifies which options the client wishes the server to return. Normally, in the ISC DHCP client, this is done using the \fIrequest\fR statement. If this option is not specified by the client, the DHCP server will normally return every option that is valid in scope and that fits into the reply. When this option is specified on the server, the server returns the specified options. This can be used to force a client to take options that it hasn't requested, and it can also be used to tailor the response of the DHCP server for clients that may need a more limited set of options than those the server would normally return. .RE .PP .B option \fBdhcp-rebinding-time\fR \fIuint32\fR\fB;\fR .RS 0.25i .PP This option specifies the number of seconds from the time a client gets an address until the client transitions to the REBINDING state. .PP This option is user configurable, but it will be ignored if the value is greater than the lease time. .PP To make DHCPv4+DHCPv6 migration easier in the future, any value configured in this option is also used as a DHCPv6 "T1" (renew) time. .PP .RE .PP .B option \fBdhcp-renewal-time\fR \fIuint32\fR\fB;\fR .RS 0.25i .PP This option specifies the number of seconds from the time a client gets an address until the client transitions to the RENEWING state. .PP This option is user configurable, but it will be ignored if the value is greater than the rebinding time, or lease time. .PP To make DHCPv4+DHCPv6 migration easier in the future, any value configured in this option is also used as a DHCPv6 "T2" (rebind) time. .PP .RE .PP .B option \fBdhcp-requested-address\fR \fIip-address\fR\fB;\fR .RS 0.25i .PP This option is used by the client in a DHCPDISCOVER to request that a particular IP address be assigned. .PP This option is not user configurable. .PP .RE .PP .B option \fBdhcp-server-identifier\fR \fIip-address\fR\fB;\fR .RS 0.25i .PP This option is used in DHCPOFFER and DHCPREQUEST messages, and may optionally be included in the DHCPACK and DHCPNAK messages. DHCP servers include this option in the DHCPOFFER in order to allow the client to distinguish between lease offers. DHCP clients use the contents of the \'server identifier\' field as the destination address for any DHCP messages unicast to the DHCP server. DHCP clients also indicate which of several lease offers is being accepted by including this option in a DHCPREQUEST message. .PP The value of this option is the IP address of the server. .PP This option is not directly user configurable. See the \fIserver-identifier\fR server option in .B \fIdhcpd.conf(5). .PP .RE .PP .B option \fBdomain-name\fR \fItext\fR\fB;\fR .RS 0.25i .PP This option specifies the domain name that client should use when resolving hostnames via the Domain Name System. .RE .PP .B option \fBdomain-name-servers\fR \fIip-address\fR [\fB,\fR \fIip-address\fR... ]\fB;\fR .RS 0.25i .PP The domain-name-servers option specifies a list of Domain Name System (STD 13, RFC 1035) name servers available to the client. Servers should be listed in order of preference. .RE .PP .B option \fBdomain-search\fR \fIdomain-list\fR\fB;\fR .RS 0.25i .PP The domain-search option specifies a \'search list\' of Domain Names to be used by the client to locate not-fully-qualified domain names. The difference between this option and historic use of the domain-name option for the same ends is that this option is encoded in RFC1035 compressed labels on the wire. For example: .nf .sp 1 option domain-search "example.com", "sales.example.com", "eng.example.com"; .fi .RE .PP .B option \fBextensions-path\fR \fItext\fR\fB;\fR .RS 0.25i .PP This option specifies the name of a file containing additional options to be interpreted according to the DHCP option format as specified in RFC2132. .RE .PP .B option \fBfinger-server\fR \fIip-address\fR [\fB,\fR \fIip-address\fR... ]\fB;\fR .RS 0.25i .PP The Finger server option specifies a list of Finger servers available to the client. Servers should be listed in order of preference. .RE .PP .B option \fBfont-servers\fR \fIip-address\fR [\fB,\fR \fIip-address\fR... ]\fB;\fR .RS 0.25i .PP This option specifies a list of X Window System Font servers available to the client. Servers should be listed in order of preference. .RE .PP .B option \fBhost-name\fR \fIstring\fR\fB;\fR .RS 0.25i .PP This option specifies the name of the client. The name may or may not be qualified with the local domain name (it is preferable to use the domain-name option to specify the domain name). See RFC 1035 for character set restrictions. This option is only honored by .B dhclient-script(8) if the hostname for the client machine is not set. .RE .PP .B option \fBieee802-3-encapsulation\fR \fIflag\fR\fB;\fR .RS 0.25i .PP This option specifies whether or not the client should use Ethernet Version 2 (RFC 894) or IEEE 802.3 (RFC 1042) encapsulation if the interface is an Ethernet. A value of false indicates that the client should use RFC 894 encapsulation. A value of true means that the client should use RFC 1042 encapsulation. .RE .PP .B option \fBien116-name-servers\fR \fIip-address\fR [\fB,\fR \fIip-address\fR... ]; .RS 0.25i .PP The ien116-name-servers option specifies a list of IEN 116 name servers available to the client. Servers should be listed in order of preference. .RE .PP .B option \fBimpress-servers\fR \fIip-address\fR [\fB,\fR \fIip-address\fR... ]\fB;\fR .RS 0.25i .PP The impress-server option specifies a list of Imagen Impress servers available to the client. Servers should be listed in order of preference. .RE .PP .B option \fBinterface-mtu\fR \fIuint16\fR\fB;\fR .RS 0.25i .PP This option specifies the MTU to use on this interface. The minimum legal value for the MTU is 68. .RE .PP .B option \fBip-forwarding\fR \fIflag\fR\fB;\fR .RS 0.25i .PP This option specifies whether the client should configure its IP layer for packet forwarding. A value of false means disable IP forwarding, and a value of true means enable IP forwarding. .RE .PP .B option \fBirc-server\fR \fIip-address\fR [\fB,\fR \fIip-address\fR... ]\fB;\fR .RS 0.25i .PP The IRC server option specifies a list of IRC servers available to the client. Servers should be listed in order of preference. .RE .PP .B option \fBlog-servers\fR \fIip-address\fR [\fB,\fR \fIip-address\fR... ]\fB;\fR .RS 0.25i .PP The log-server option specifies a list of MIT-LCS UDP log servers available to the client. Servers should be listed in order of preference. .RE .PP .B option \fBlpr-servers\fR \fIip-address \fR [\fB,\fR \fIip-address\fR... ]\fB;\fR .RS 0.25i .PP The LPR server option specifies a list of RFC 1179 line printer servers available to the client. Servers should be listed in order of preference. .RE .PP .B option \fBmask-supplier\fR \fIflag\fR\fB;\fR .RS 0.25i .PP This option specifies whether or not the client should respond to subnet mask requests using ICMP. A value of false indicates that the client should not respond. A value of true means that the client should respond. .RE .PP .B option \fBmax-dgram-reassembly\fR \fIuint16\fR\fB;\fR .RS 0.25i .PP This option specifies the maximum size datagram that the client should be prepared to reassemble. The minimum legal value is 576. .RE .PP .B option \fBmerit-dump\fR \fItext\fR\fB;\fR .RS 0.25i .PP This option specifies the path-name of a file to which the client's core image should be dumped in the event the client crashes. The path is formatted as a character string consisting of characters from the NVT ASCII character set. .RE .PP .B option \fBmobile-ip-home-agent\fR \fIip-address\fR [\fB,\fR \fIip-address\fR... ]\fB;\fR .RS 0.25i .PP This option specifies a list of IP addresses indicating mobile IP home agents available to the client. Agents should be listed in order of preference, although normally there will be only one such agent. .RE .PP .B option \fBnds-context\fR \fIstring\fR\fB;\fR .RS 0.25i .PP The nds-context option specifies the name of the initial Netware Directory Service for an NDS client. .RE .PP .B option \fBnds-servers\fR \fIip-address\fR [\fB,\fR \fIip-address\fR... ]\fB;\fR .RS 0.25i .PP The nds-servers option specifies a list of IP addresses of NDS servers. .RE .PP .B option \fBnds-tree-name\fR \fIstring\fR\fB;\fR .RS 0.25i .PP The nds-tree-name option specifies NDS tree name that the NDS client should use. .RE .PP .B option \fBnetbios-dd-server\fR \fIip-address\fR [\fB,\fR \fIip-address\fR... ]\fB;\fR .RS 0.25i .PP The NetBIOS datagram distribution server (NBDD) option specifies a list of RFC 1001/1002 NBDD servers listed in order of preference. .RE .PP .B option \fBnetbios-name-servers\fR \fIip-address\fR [\fB,\fR \fIip-address\fR...]\fB;\fR .RS 0.25i .PP The NetBIOS name server (NBNS) option specifies a list of RFC 1001/1002 NBNS name servers listed in order of preference. NetBIOS Name Service is currently more commonly referred to as WINS. WINS servers can be specified using the netbios-name-servers option. .RE .PP .B option \fBnetbios-node-type\fR \fIuint8\fR\fB;\fR .RS 0.25i .PP The NetBIOS node type option allows NetBIOS over TCP/IP clients which are configurable to be configured as described in RFC 1001/1002. The value is specified as a single octet which identifies the client type. .PP Possible node types are: .PP .TP 5 .I 1 B-node: Broadcast - no WINS .TP .I 2 P-node: Peer - WINS only .TP .I 4 M-node: Mixed - broadcast, then WINS .TP .I 8 H-node: Hybrid - WINS, then broadcast .RE .PP .B option \fBnetbios-scope\fR \fIstring\fR\fB;\fR .RS 0.25i .PP The NetBIOS scope option specifies the NetBIOS over TCP/IP scope parameter for the client as specified in RFC 1001/1002. See RFC1001, RFC1002, and RFC1035 for character-set restrictions. .RE .PP .B option \fBnetinfo-server-address\fR \fIip-address\fR [\fB,\fR \fIip-address\fR... ]\fB;\fR .RS 0.25i .PP The \fBnetinfo-server-address\fR option has not been described in any RFC, but has been allocated (and is claimed to be in use) by Apple Computers. It's hard to say if the above is the correct format, or what clients might be expected to do if values were configured. Use at your own risk. .RE .PP .B option \fBnetinfo-server-tag\fR \fItext\fR\fB;\fR .RS 0.25i .PP The \fBnetinfo-server-tag\fR option has not been described in any RFC, but has been allocated (and is claimed to be in use) by Apple Computers. It's hard to say if the above is the correct format, or what clients might be expected to do if values were configured. Use at your own risk. .RE .PP .B option \fBnis-domain\fR \fItext\fR\fB;\fR .RS 0.25i .PP This option specifies the name of the client's NIS (Sun Network Information Services) domain. The domain is formatted as a character string consisting of characters from the NVT ASCII character set. .RE .PP .B option \fBnis-servers\fR \fIip-address\fR [\fB,\fR \fIip-address\fR... ]\fB;\fR .RS 0.25i .PP This option specifies a list of IP addresses indicating NIS servers available to the client. Servers should be listed in order of preference. .RE .PP .B option \fBnisplus-domain\fR \fItext\fR\fB;\fR .RS 0.25i .PP This option specifies the name of the client's NIS+ domain. The domain is formatted as a character string consisting of characters from the NVT ASCII character set. .RE .PP .B option \fBnisplus-servers\fR \fIip-address\fR [\fB,\fR \fIip-address\fR... ]\fB;\fR .RS 0.25i .PP This option specifies a list of IP addresses indicating NIS+ servers available to the client. Servers should be listed in order of preference. .RE .PP .B option \fBnntp-server\fR \fIip-address\fR [\fB,\fR \fIip-address\fR... ]\fB;\fR .RS 0.25i .PP The NNTP server option specifies a list of NNTP servesr available to the client. Servers should be listed in order of preference. .RE .PP .B option \fBnon-local-source-routing\fR \fIflag\fR\fB;\fR .RS 0.25i .PP This option specifies whether the client should configure its IP layer to allow forwarding of datagrams with non-local source routes (see Section 3.3.5 of [4] for a discussion of this topic). A value of false means disallow forwarding of such datagrams, and a value of true means allow forwarding. .RE .PP .B option \fBntp-servers\fR \fIip-address\fR [\fB,\fR \fIip-address\fR... ]\fB;\fR .RS 0.25i .PP This option specifies a list of IP addresses indicating NTP (RFC 1035) servers available to the client. Servers should be listed in order of preference. .RE .PP .B option \fBnwip-domain\fR \fIstring\fR\fB;\fR .RS 0.25i .PP The name of the NetWare/IP domain that a NetWare/IP client should use. .RE .PP .B option \fBnwip-suboptions\fR \fIstring\fR\fB;\fR .RS 0.25i .PP A sequence of suboptions for NetWare/IP clients - see RFC2242 for details. Normally this option is set by specifying specific NetWare/IP suboptions - see the NETWARE/IP SUBOPTIONS section for more information. .RE .PP .B option \fBpath-mtu-aging-timeout\fR \fIuint32\fR\fB;\fR .RS 0.25i .PP This option specifies the timeout (in seconds) to use when aging Path MTU values discovered by the mechanism defined in RFC 1191. .RE .PP .B option \fBpath-mtu-plateau-table\fR \fIuint16\fR [\fB,\fR \fIuint16\fR... ]\fB;\fR .RS 0.25i .PP This option specifies a table of MTU sizes to use when performing Path MTU Discovery as defined in RFC 1191. The table is formatted as a list of 16-bit unsigned integers, ordered from smallest to largest. The minimum MTU value cannot be smaller than 68. .RE .PP .B option \fBperform-mask-discovery\fR \fIflag\fR\fB;\fR .RS 0.25i .PP This option specifies whether or not the client should perform subnet mask discovery using ICMP. A value of false indicates that the client should not perform mask discovery. A value of true means that the client should perform mask discovery. .RE .PP .nf .B option \fBpolicy-filter\fR \fIip-address ip-address\fR [\fB,\fR \fIip-address ip-address\fR...]\fB;\fR .RE .fi .RS 0.25i .PP This option specifies policy filters for non-local source routing. The filters consist of a list of IP addresses and masks which specify destination/mask pairs with which to filter incoming source routes. .PP Any source routed datagram whose next-hop address does not match one of the filters should be discarded by the client. .PP See STD 3 (RFC1122) for further information. .RE .PP .B option \fBpop-server\fR \fIip-address\fR [\fB,\fR \fIip-address\fR... ]\fB;\fR .RS 0.25i .PP The POP3 server option specifies a list of POP3 servers available to the client. Servers should be listed in order of preference. .RE .PP .B option \fBresource-location-servers\fR \fIip-address\fR [\fB, \fR\fIip-address\fR...]\fB;\fR .fi .RS 0.25i .PP This option specifies a list of RFC 887 Resource Location servers available to the client. Servers should be listed in order of preference. .RE .PP .B option \fBroot-path\fR \fItext\fB;\fR\fR .RS 0.25i .PP This option specifies the path-name that contains the client's root disk. The path is formatted as a character string consisting of characters from the NVT ASCII character set. .RE .PP .B option \fBrouter-discovery\fR \fIflag\fR\fB;\fR .RS 0.25i .PP This option specifies whether or not the client should solicit routers using the Router Discovery mechanism defined in RFC 1256. A value of false indicates that the client should not perform router discovery. A value of true means that the client should perform router discovery. .RE .PP .B option \fBrouter-solicitation-address\fR \fIip-address\fR\fB;\fR .RS 0.25i .PP This option specifies the address to which the client should transmit router solicitation requests. .RE .PP .B option routers \fIip-address\fR [\fB,\fR \fIip-address\fR... ]\fB;\fR .RS 0.25i .PP The routers option specifies a list of IP addresses for routers on the client's subnet. Routers should be listed in order of preference. .RE .PP .B option slp-directory-agent \fIboolean ip-address [\fB,\fR \fIip-address\fR... ]\fB;\fR .RS 0.25i .PP This option specifies two things: the IP addresses of one or more Service Location Protocol Directory Agents, and whether the use of these addresses is mandatory. If the initial boolean value is true, the SLP agent should just use the IP addresses given. If the value is false, the SLP agent may additionally do active or passive multicast discovery of SLP agents (see RFC2165 for details). .PP Please note that in this option and the slp-service-scope option, the term "SLP Agent" is being used to refer to a Service Location Protocol agent running on a machine that is being configured using the DHCP protocol. .PP Also, please be aware that some companies may refer to SLP as NDS. If you have an NDS directory agent whose address you need to configure, the slp-directory-agent option should work. .RE .PP .B option slp-service-scope \fIboolean text\fR\fB;\fR .RS 0.25i .PP The Service Location Protocol Service Scope Option specifies two things: a list of service scopes for SLP, and whether the use of this list is mandatory. If the initial boolean value is true, the SLP agent should only use the list of scopes provided in this option; otherwise, it may use its own static configuration in preference to the list provided in this option. .PP The text string should be a comma-separated list of scopes that the SLP agent should use. It may be omitted, in which case the SLP Agent will use the aggregated list of scopes of all directory agents known to the SLP agent. .RE .PP .B option \fBsmtp-server\fR \fIip-address\fR [\fB,\fR \fIip-address\fR... ]\fB;\fR .RS 0.25i .PP The SMTP server option specifies a list of SMTP servers available to the client. Servers should be listed in order of preference. .RE .PP .nf .B option \fBstatic-routes\fR \fIip-address ip-address\fR [\fB,\fR \fIip-address ip-address\fR...]\fB;\fR .fi .RS 0.25i .PP This option specifies a list of static routes that the client should install in its routing cache. If multiple routes to the same destination are specified, they are listed in descending order of priority. .PP The routes consist of a list of IP address pairs. The first address is the destination address, and the second address is the router for the destination. .PP The default route (0.0.0.0) is an illegal destination for a static route. To specify the default route, use the .B routers option. Also, please note that this option is not intended for classless IP routing - it does not include a subnet mask. Since classless IP routing is now the most widely deployed routing standard, this option is virtually useless, and is not implemented by any of the popular DHCP clients, for example the Microsoft DHCP client. .RE .PP .nf .B option \fBstreettalk-directory-assistance-server\fR \fIip-address\fR [\fB,\fR \fIip-address\fR...]\fB;\fR .fi .RS 0.25i .PP The StreetTalk Directory Assistance (STDA) server option specifies a list of STDA servers available to the client. Servers should be listed in order of preference. .RE .PP .B option \fBstreettalk-server\fR \fIip-address\fR [\fB,\fR \fIip-address\fR... ]\fB;\fR .RS 0.25i .PP The StreetTalk server option specifies a list of StreetTalk servers available to the client. Servers should be listed in order of preference. .RE .PP .B option subnet-mask \fIip-address\fR\fB;\fR .RS 0.25i .PP The subnet mask option specifies the client's subnet mask as per RFC 950. If no subnet mask option is provided anywhere in scope, as a last resort dhcpd will use the subnet mask from the subnet declaration for the network on which an address is being assigned. However, .I any subnet-mask option declaration that is in scope for the address being assigned will override the subnet mask specified in the subnet declaration. .RE .PP .B option \fBsubnet-selection\fR \fIstring\fR\fB;\fR .RS 0.25i .PP Sent by the client if an address is required in a subnet other than the one that would normally be selected (based on the relaying address of the connected subnet the request is obtained from). See RFC3011. Note that the option number used by this server is 118; this has not always been the defined number, and some clients may use a different value. Use of this option should be regarded as slightly experimental! .RE .PP This option is not user configurable in the server. .PP .PP .B option \fBswap-server\fR \fIip-address\fR\fB;\fR .RS 0.25i .PP This specifies the IP address of the client's swap server. .RE .PP .B option \fBtcp-keepalive-garbage\fR \fIflag\fR\fB;\fR .RS 0.25i .PP This option specifies whether or not the client should send TCP keepalive messages with an octet of garbage for compatibility with older implementations. A value of false indicates that a garbage octet should not be sent. A value of true indicates that a garbage octet should be sent. .RE .PP .B option \fBtcp-keepalive-interval\fR \fIuint32\fR\fB;\fR .RS 0.25i .PP This option specifies the interval (in seconds) that the client TCP should wait before sending a keepalive message on a TCP connection. The time is specified as a 32-bit unsigned integer. A value of zero indicates that the client should not generate keepalive messages on connections unless specifically requested by an application. .RE .PP .B option \fBtftp-server-name\fR \fItext\fR\fB;\fR .RS 0.25i .PP This option is used to identify a TFTP server and, if supported by the client, should have the same effect as the \fBserver-name\fR declaration. BOOTP clients are unlikely to support this option. Some DHCP clients will support it, and others actually require it. .RE .PP .B option time-offset \fIint32\fR\fB;\fR .RS 0.25i .PP The time-offset option specifies the offset of the client's subnet in seconds from Coordinated Universal Time (UTC). .RE .PP .B option time-servers \fIip-address\fR [, \fIip-address\fR... ]\fB;\fR .RS 0.25i .PP The time-server option specifies a list of RFC 868 time servers available to the client. Servers should be listed in order of preference. .RE .PP .B option \fBtrailer-encapsulation\fR \fIflag\fR\fB;\fR .RS 0.25i .PP This option specifies whether or not the client should negotiate the use of trailers (RFC 893 [14]) when using the ARP protocol. A value of false indicates that the client should not attempt to use trailers. A value of true means that the client should attempt to use trailers. .RE .PP .B option \fBuap-servers\fR \fItext\fR\fB;\fR .RS 0.25i .PP This option specifies a list of URLs, each pointing to a user authentication service that is capable of processing authentication requests encapsulated in the User Authentication Protocol (UAP). UAP servers can accept either HTTP 1.1 or SSLv3 connections. If the list includes a URL that does not contain a port component, the normal default port is assumed (i.e., port 80 for http and port 443 for https). If the list includes a URL that does not contain a path component, the path /uap is assumed. If more than one URL is specified in this list, the URLs are separated by spaces. .RE .PP .B option \fBuser-class\fR \fIstring\fR\fB;\fR .RS 0.25i .PP This option is used by some DHCP clients as a way for users to specify identifying information to the client. This can be used in a similar way to the vendor-class-identifier option, but the value of the option is specified by the user, not the vendor. Most recent DHCP clients have a way in the user interface to specify the value for this identifier, usually as a text string. .RE .PP .B option \fBvendor-class-identifier\fR \fIstring\fR\fB;\fR .RS 0.25i .PP This option is used by some DHCP clients to identify the vendor type and possibly the configuration of a DHCP client. The information is a string of bytes whose contents are specific to the vendor and are not specified in a standard. To see what vendor class identifier clients are sending, you can write the following in your DHCP server configuration file: .nf .PP set vendor-string = option vendor-class-identifier; .fi .PP This will result in all entries in the DHCP server lease database file for clients that sent vendor-class-identifier options having a set statement that looks something like this: .nf .PP set vendor-string = "SUNW.Ultra-5_10"; .fi .PP The vendor-class-identifier option is normally used by the DHCP server to determine the options that are returned in the .B vendor-encapsulated-options option. Please see the VENDOR ENCAPSULATED OPTIONS section later in this manual page for further information. .RE .PP .B option \fBvendor-encapsulated-options\fR \fIstring\fR\fB;\fR .RS 0.25i .PP The \fBvendor-encapsulated-options\fR option can contain either a single vendor-specific value or one or more vendor-specific suboptions. This option is not normally specified in the DHCP server configuration file - instead, a vendor class is defined for each vendor, vendor class suboptions are defined, values for those suboptions are defined, and the DHCP server makes up a response on that basis. .PP Some default behaviours for well-known DHCP client vendors (currently, the Microsoft Windows 2000 DHCP client) are configured automatically, but otherwise this must be configured manually - see the VENDOR ENCAPSULATED OPTIONS section later in this manual page for details. .RE .PP .B option \fBvivso\fR \fIstring\fR\fB;\fR .RS 0.25i .PP The \fBvivso\fR option can contain multiple separate options, one for each 32-bit Enterprise ID. Each Enterprise-ID discriminated option then contains additional options whose format is defined by the vendor who holds that ID. This option is usually not configured manually, but rather is configured via intervening option definitions. Please also see the VENDOR ENCAPSULATED OPTIONS section later in this manual page for details. .RE .PP .B option \fBwww-server\fR \fIip-address\fR [\fB,\fR \fIip-address\fR... ]\fB;\fR .RS 0.25i .PP The WWW server option specifies a list of WWW servers available to the client. Servers should be listed in order of preference. .RE .PP .B option \fBx-display-manager\fR \fIip-address\fR [\fB,\fR \fIip-address\fR... ]\fB;\fR .RS 0.25i .PP This option specifies a list of systems that are running the X Window System Display Manager and are available to the client. Addresses should be listed in order of preference. .RE .SH RELAY AGENT INFORMATION OPTION An IETF draft, draft-ietf-dhc-agent-options-11.txt, defines a series of encapsulated options that a relay agent can add to a DHCP packet when relaying it to the DHCP server. The server can then make address allocation decisions (or whatever other decisions it wants) based on these options. The server also returns these options in any replies it sends through the relay agent, so that the relay agent can use the information in these options for delivery or accounting purposes. .PP The current draft defines two options. To reference these options in the dhcp server, specify the option space name, "agent", followed by a period, followed by the option name. It is not normally useful to define values for these options in the server, although it is permissible. These options are not supported in the client. .PP .B option \fBagent.circuit-id\fR \fIstring\fR\fB;\fR .RS 0.25i .PP The circuit-id suboption encodes an agent-local identifier of the circuit from which a DHCP client-to-server packet was received. It is intended for use by agents in relaying DHCP responses back to the proper circuit. The format of this option is currently defined to be vendor-dependent, and will probably remain that way, although the current draft allows for for the possibility of standardizing the format in the future. .RE .PP .B option \fBagent.remote-id\fR \fIstring\fR\fB;\fR .RS 0.25i .PP The remote-id suboption encodes information about the remote host end of a circuit. Examples of what it might contain include caller ID information, username information, remote ATM address, cable modem ID, and similar things. In principal, the meaning is not well-specified, and it should generally be assumed to be an opaque object that is administratively guaranteed to be unique to a particular remote end of a circuit. .RE .PP .B option \fBagent.DOCSIS-device-class\fR \fIuint32\fR\fB;\fR .RS 0.25i .PP The DOCSIS-device-class suboption is intended to convey information about the host endpoint, hardware, and software, that either the host operating system or the DHCP server may not otherwise be aware of (but the relay is able to distinguish). This is implemented as a 32-bit field (4 octets), each bit representing a flag describing the host in one of these ways. So far, only bit zero (being the least significant bit) is defined in RFC3256. If this bit is set to one, the host is considered a CPE Controlled Cable Modem (CCCM). All other bits are reserved. .RE .PP .B option \fBagent.link-selection\fR \fIip-address\fR\fB;\fR .RS 0.25i .PP The link-selection suboption is provided by relay agents to inform servers what subnet the client is actually attached to. This is useful in those cases where the giaddr (where responses must be sent to the relay agent) is not on the same subnet as the client. When this option is present in a packet from a relay agent, the DHCP server will use its contents to find a subnet declared in configuration, and from here take one step further backwards to any shared-network the subnet may be defined within...the client may be given any address within that shared network, as normally appropriate. .RE .SH THE CLIENT FQDN SUBOPTIONS The Client FQDN option, currently defined in the Internet Draft draft-ietf-dhc-fqdn-option-00.txt is not a standard yet, but is in sufficiently wide use already that we have implemented it. Due to the complexity of the option format, we have implemented it as a suboption space rather than a single option. In general this option should not be configured by the user - instead it should be used as part of an automatic DNS update system. .PP .B option fqdn.no-client-update \fIflag\fB; .RS 0.25i .PP When the client sends this, if it is true, it means the client will not attempt to update its A record. When sent by the server to the client, it means that the client \fIshould not\fR update its own A record. .RE .PP .B option fqdn.server-update \fIflag\fB; .RS 0.25i .PP When the client sends this to the server, it is requesting that the server update its A record. When sent by the server, it means that the server has updated (or is about to update) the client's A record. .RE .PP .B option fqdn.encoded \fIflag\fB; .RS 0.25i .PP If true, this indicates that the domain name included in the option is encoded in DNS wire format, rather than as plain ASCII text. The client normally sets this to false if it doesn't support DNS wire format in the FQDN option. The server should always send back the same value that the client sent. When this value is set on the configuration side, it controls the format in which the \fIfqdn.fqdn\fR suboption is encoded. .RE .PP .B option fqdn.rcode1 \fIflag\fB; .PP .B option fqdn.rcode2 \fIflag\fB; .RS 0.25i .PP These options specify the result of the updates of the A and PTR records, respectively, and are only sent by the DHCP server to the DHCP client. The values of these fields are those defined in the DNS protocol specification. .RE .PP .B option fqdn.fqdn \fItext\fB; .RS 0.25i .PP Specifies the domain name that the client wishes to use. This can be a fully-qualified domain name, or a single label. If there is no trailing \'.\' character in the name, it is not fully-qualified, and the server will generally update that name in some locally-defined domain. .RE .PP .B option fqdn.hostname \fI--never set--\fB; .RS 0.25i .PP This option should never be set, but it can be read back using the \fBoption\fR and \fBconfig-option\fR operators in an expression, in which case it returns the first label in the \fBfqdn.fqdn\fR suboption - for example, if the value of \fBfqdn.fqdn\fR is "foo.example.com.", then \fBfqdn.hostname\fR will be "foo". .RE .PP .B option fqdn.domainname \fI--never set--\fB; .RS 0.25i .PP This option should never be set, but it can be read back using the \fBoption\fR and \fBconfig-option\fR operators in an expression, in which case it returns all labels after the first label in the \fBfqdn.fqdn\fR suboption - for example, if the value of \fBfqdn.fqdn\fR is "foo.example.com.", then \fBfqdn.hostname\fR will be "example.com.". If this suboption value is not set, it means that an unqualified name was sent in the fqdn option, or that no fqdn option was sent at all. .RE .PP If you wish to use any of these suboptions, we strongly recommend that you refer to the Client FQDN option draft (or standard, when it becomes a standard) - the documentation here is sketchy and incomplete in comparison, and is just intended for reference by people who already understand the Client FQDN option specification. .SH THE NETWARE/IP SUBOPTIONS RFC2242 defines a set of encapsulated options for Novell NetWare/IP clients. To use these options in the dhcp server, specify the option space name, "nwip", followed by a period, followed by the option name. The following options can be specified: .PP .B option \fBnwip.nsq-broadcast\fR \fIflag\fR\fB;\fR .RS 0.25i .PP If true, the client should use the NetWare Nearest Server Query to locate a NetWare/IP server. The behaviour of the Novell client if this suboption is false, or is not present, is not specified. .PP .RE .B option \fBnwip.preferred-dss\fR \fIip-address\fR [\fB,\fR \fIip-address\fR... ]\fR\fB;\fR .RS 0.25i .PP This suboption specifies a list of up to five IP addresses, each of which should be the IP address of a NetWare Domain SAP/RIP server (DSS). .RE .PP .B option \fBnwip.nearest-nwip-server\fR \fI\fIip-address\fR [\fB,\fR \fIip-address\fR...]\fR\fB;\fR .RS 0.25i .PP This suboption specifies a list of up to five IP addresses, each of which should be the IP address of a Nearest NetWare IP server. .RE .PP .B option \fBnwip.autoretries\fR \fIuint8\fR\fB;\fR .RS 0.25i .PP Specifies the number of times that a NetWare/IP client should attempt to communicate with a given DSS server at startup. .RE .PP .B option \fBnwip.autoretry-secs\fR \fIuint8\fR\fB;\fR .RS 0.25i .PP Specifies the number of seconds that a Netware/IP client should wait between retries when attempting to establish communications with a DSS server at startup. .RE .PP .B option \fBnwip.nwip-1-1\fR \fIuint8\fR\fB;\fR .RS 0.25i .PP If true, the NetWare/IP client should support NetWare/IP version 1.1 compatibility. This is only needed if the client will be contacting Netware/IP version 1.1 servers. .RE .PP .B option \fBnwip.primary-dss\fR \fIip-address\fR\fB;\fR .RS 0.25i .PP Specifies the IP address of the Primary Domain SAP/RIP Service server (DSS) for this NetWare/IP domain. The NetWare/IP administration utility uses this value as Primary DSS server when configuring a secondary DSS server. .RE .SH STANDARD DHCPV6 OPTIONS DHCPv6 options differ from DHCPv4 options partially due to using 16-bit code and length tags, but semantically zero-length options are legal in DHCPv6, and multiple options are treated differently. Whereas in DHCPv4 multiple options would be concatenated to form one option, in DHCPv6 they are expected to be individual instantiations. Understandably, many options are not "allowed" to have multiple instances in a packet - normally these are options which are digested by the DHCP protocol software, and not by users or applications. .PP .B option \fBdhcp6.client-id\fR \fIstring\fR\fB;\fR .RS 0.25i .PP This option specifies the client's DUID identifier. DUIDs are similar but different from DHCPv4 client identifiers - there are documented duid types: .PP .I duid-llt .PP .I duid-en .PP .I duid-ll .PP This value should not be configured, but rather is provided by clients and treated as an opaque identifier key blob by servers. .RE .PP .B option \fBdhcp6.server-id\fR \fIstring\fR\fB;\fR .RS 0.25i .PP This option specifies the server's DUID identifier. One may use this option to configure an opaque binary blob for your server's identifier. .RE .PP .B option \fBdhcp6.ia-na\fR \fIstring\fR\fB;\fR .RS 0.25i .PP The Identity Association for Non-temporary Addresses (ia-na) carries assigned addresses that are not temporary addresses for use by the DHCPv6 client. This option is produced by the DHCPv6 server software, and should not be configured. .RE .PP .B option \fBdhcp6.ia-ta\fR \fIstring\fR\fB;\fR .RS 0.25i .PP The Identity Association for Temporary Addresses (ia-ta) carries temporary addresses, which may change upon every renewal. There is no support for this in the current DHCPv6 software. .RE .PP .B option \fBdhcp6.ia-addr\fR \fIstring\fR\fB;\fR .RS 0.25i .PP The Identity Association Address option is encapsulated inside ia-na or ia-ta options in order to represent addresses associated with those IA's. These options are manufactured by the software, so should not be configured. .RE .PP .B option \fBdhcp6.oro\fR \fIuint16\fR [ \fB,\fR \fIuint16\fR\fB,\fR ... ]\fB;\fR .RS 0.25i .PP The Option Request Option ("ORO") is the DHCPv6 equivalent of the parameter-request-list. Clients supply this option to ask servers to reply with options relevant to their needs and use. This option must not be directly configured, the request syntax in dhclient.conf (5) should be used instead. .RE .PP .B option \fBdhcp6.preference\fR \fIuint8\fR\fB;\fR .RS 0.25i .PP The \fBpreference\fR option informs a DHCPv6 client which server is \'preferred\' for use on a given subnet. This preference is only applied during the initial stages of configuration - once a client is bound to an IA, it will remain bound to that IA until it is no longer valid or has expired. This value may be configured on the server, and is digested by the client software. .RE .PP .B option \fBdhcp6.elapsed-time\fR \fIuint16\fR\fB;\fR .RS 0.25i .PP The \fBelapsed-time\fR option is constructed by the DHCPv6 client software, and is potentially consumed by intermediaries. This option should not be configured. .RE .PP .B option \fBdhcp6.relay-msg\fR \fIstring\fR\fB;\fR .RS 0.25i .PP The \fBrelay-msg\fR option is constructed by intervening DHCPv6 relay agent software. This option is entirely used by protocol software, and is not meant for user configuration. .RE .PP .B option \fBdhcp6.unicast\fR \fIip6-address\fR\fB;\fR .RS 0.25i .PP The \fBunicast\fR option is provided by DHCPv6 servers which are willing (or prefer) to receive Renew packets from their clients by exchanging UDP unicasts with them. Normally, DHCPv6 clients will multicast their Renew messages. This may be configured on the server, and should be configured as an address the server is ready to reply to. .RE .PP .B option \fBdhcp6.status-code\fR \fIstatus-code\fR [ \fIstring\fR ] \fB;\fR .RS 0.25i .PP The \fBstatus-code\fR option is provided by DHCPv6 servers to inform clients of error conditions during protocol communication. This option is manufactured and digested by protocol software, and should not be configured. .RE .PP .B option \fBdhcp6.rapid-commit\fR \fB;\fR .RS 0.25i .PP The \fBrapid-commit\fR option is a zero-length option that clients use to indicate their desire to enter into rapid-commit with the server. .RE .PP .B option \fBdhcp6.vendor-opts\fR \fIstring\fR\fB;\fR .RS 0.25i .PP The \fBvendor-opts\fR option is actually an encapsulated sub-option space, in which each Vendor-specific Information Option (VSIO) is identified by a 32-bit Enterprise-ID number. The encapsulated option spaces within these options are defined by the vendors. .PP To make use of this option, the best way is to examine the section titled VENDOR ENCAPSULATED OPTIONS below, in particular the bits about the "vsio" option space. .RE .PP .B option \fBdhcp6.interface-id\fR \fIstring\fR\fB;\fR .RS 0.25i .PP The \fBinterface-id\fR option is manufactured by relay agents, and may be used to guide configuration differentiating clients by the interface they are remotely attached to. It does not make sense to configure a value for this option, but it may make sense to inspect its contents. .RE .PP .B option \fBdhcp6.reconf-msg\fR \fIdhcpv6-message\fR\fB;\fR .RS 0.25i .PP The \fBreconf-msg\fR option is manufactured by servers, and sent to clients in Reconfigure messages to inform them of what message the client should Reconfigure using. There is no support for DHCPv6 Reconfigure extensions, and this option is documented informationally only. .RE .PP .B option \fBdhcp6.reconf-accept ;\fR .RS 0.25i .PP The \fBreconf-accept\fR option is included by DHCPv6 clients that support the Reconfigure extentions, advertising that they will respond if the server were to ask them to Reconfigure. There is no support for DHCPv6 Reconfigure extensions, and this option is documented informationally only. .RE .PP .B option \fBdhcp6.sip-servers-names\fR \fIdomain-list\fR\fB;\fR .RS 0.25i .PP The \fBsip-servers-names\fR option allows SIP clients to locate a local SIP server that is to be used for all outbound SIP requests, a so-called"outbound proxy server." If you wish to use manually entered IPv6 addresses instead, please see the \fBsip-servers-addresses\fR option below. .RE .PP .B option .B dhcp6.sip-servers-addresses .I ip6-address \fR[\fB,\fR .I ip6-address \fR... ] .B ; .RS 0.25i .PP The \fBsip-servers-addresses\fR option allows SIP clients to locate a local SIP server that is to be used for all outbound SIP requests, a so-called "outbound proxy servers." If you wish to use domain names rather than IPv6 addresses, please see the \fBsip-servers-names\fR option above. .RE .PP .B option .B dhcp6.name-servers .I ip6-address \fR[\fB,\fR .I ip6-address \fR... ] .B ; .RS 0.25i .PP The \fBname-servers\fR option instructs clients about locally available recursive DNS servers. It is easiest to describe this as the "nameserver" line in /etc/resolv.conf. .RE .PP .B option \fBdhcp6.domain-search\fR \fIdomain-list\fR\fB;\fR .RS 0.25i .PP The \fBdomain-search\fR option specifies the client's domain search path to be applied to recursive DNS queries. It is easiest to describe this as the "search" line in /etc/resolv.conf. .RE .PP .B option \fBdhcp6.ia-pd\fR \fIstring\fR\fB;\fR .RS 0.25i .PP The \fBia-pd\fR option is manufactured by clients and servers to create a Prefix Delegation binding - to delegate an IPv6 prefix to the client. It is not directly edited in dhcpd.conf(5) or dhclient.conf(5), but rather is manufactured and consumed by the software. .RE .PP .B option \fBdhcp6.ia-prefix\fR \fIstring\fR\fB;\fR .RS 0.25i .PP The \fBia-prefix\fR option is placed inside \fBia-pd\fR options in order to identify the prefix(es) allocated to the client. It is not directly edited in dhcpd.conf(5) or dhclient.conf(5), but rather is manufactured and consumed by the software. .RE .PP .B option .B dhcp6.nis-servers .I ip6-address \fR[\fB, .I ip6-address \fR... ] .B ; .RS 0.25i .PP The \fBnis-servers\fR option identifies, in order, NIS servers available to the client. .RE .PP .B option .B dhcp6.nisp-servers .I ip6-address \fR[\fB, .I ip6-address \fR... ] .B ; .RS 0.25i .PP The \fBnisp-servers\fR option identifies, in order, NIS+ servers available to the client. .RE .PP .B option \fBnis-domain-name\fR \fIdomain-list\fR\fB;\fR .RS 0.25i .PP The \fBnis-domain-name\fR option specifies the NIS domain name the client is expected to use, and is related to the \fBnis-servers\fR option. .RE .PP .B option \fBdhcp6.nis-domain-name\fR \fIdomain-name\fR\fB;\fR .RS 0.25i .PP The \fBdhcp6.nis-domain-name\fR option specfies NIS domain name the client is expected to use, and is related to \fBdhcp6.nis-servers\fR option. .RE .PP .B option \fBnisp-domain-name\fR \fIdomain-list\fR\fB;\fR .RS 0.25i .PP The \fBnisp-domain-name\fR option specifies the NIS+ domain name the client is expected to use, and is related to the \fBnisp-servers\fR option. .RE .PP .B option \fBdhcp6.nisp-domain-name\fR \fIdomain-name\fR\fB;\fR .RS 0.25i .PP The \fBdhcp6.nis-domain-name\fR option specfies NIS+ domain name the client is expected to use, and is related to \fBdhcp6.nisp-servers\fR option. .RE .PP .B option .B dhcp6.sntp-servers .I ip6-address \fR[\fB, .I ip6-address \fR... ] .B ; .RS 0.25i .PP The \fBsntp-servers\fR option specifies a list of local SNTP servers available for the client to synchronize their clocks. .RE .PP .B option \fBdhcp6.info-refresh-time\fR \fIuint32\fR\fB;\fR .RS 0.25i .PP The \fBinfo-refresh-time\fR option gives DHCPv6 clients using Information-request messages a hint as to how long they should between refreshing the information they were given. Note that this option will only be delivered to the client, and be likely to affect the client's behaviour, if the client requested the option. .RE .PP .B option \fBdhcp6.bcms-server-d\fR \fIdomain-list\fR\fB;\fR .RS 0.25i .PP The \fBbcms-server-d\fR option contains the domain names of local BCMS (Broadcast and Multicast Control Services) controllers which the client may use. .RE .PP .B option .B dhcp6.bcms-server-a .I ip6-address \fR[\fB, .I ip6-address \fR... ] .B ; .RS 0.25i .PP The \fBbcms-server-a\fR option contains the IPv6 addresses of local BCMS (Broadcast and Multicast Control Services) controllers which the client may use. .RE .PP .B option \fBdhcp6.remote-id\fR \fIstring\fR\fB;\fR .RS 0.25i .PP The \fBremote-id\fR option is constructed by relay agents, to inform the server of details pertaining to what the relay knows about the client (such as what port it is attached to, and so forth). The contents of this option have some vendor-specific structure (similar to VSIO), but we have chosen to treat this option as an opaque field. .RE .PP .B option \fBdhcp6.subscriber-id\fR\fB;\fR .RS 0.25i .PP The \fBsubscriber-id\fR option is an opaque field provided by the relay agent, which provides additional information about the subscriber in question. The exact contents of this option depend upon the vendor and/or the operator's configuration of the remote device, and as such is an opaque field. .RE .PP .B option \fBdhcp6.fqdn\fR \fIstring\fR\fB;\fR .RS 0.25i .PP The \fBfqdn\fR option is normally constructed by the client or server, and negotiates the client's Fully Qualified Domain Name, as well as which party is responsible for Dynamic DNS Updates. See the section on the Client FQDN SubOptions for full details (the DHCPv4 and DHCPv6 FQDN options use the same "fqdn." encapsulated space, so are in all ways identical). .RE .PP .B option \fBdhcp6.lq-query\fR \fIstring\fR\fB;\fR .RS 0.25i .PP The \fBlq-query\fR option is used internally by for lease query. .RE .PP .B option \fBdhcp6.client-data\fR \fIstring\fR\fB;\fR .RS 0.25i .PP The \fBclient-data\fR option is used internally by for lease query. .RE .PP .B option \fBdhcp6.clt-time\fR \fIuint32\fR\fB;\fR .RS 0.25i .PP The \fBclt-time\fR option is used internally by for lease query. .RE .PP .B option \fBdhcp6.lq-relay-data\fR \fIip6-address string\fR\fB;\fR .RS 0.25i .PP The \fBlq-relay-data\fR option is used internally by for lease query. .RE .PP .B option .B dhcp6.lq-client-link .I ip6-address \fR[\fB,\fR .I ip6-address \fR... ] .B ; .RS 0.25i .PP The \fBlq-client-link\fR option is used internally by for lease query. .RE .PP .RE .SH DEFINING NEW OPTIONS The Internet Systems Consortium DHCP client and server provide the capability to define new options. Each DHCP option has a name, a code, and a structure. The name is used by you to refer to the option. The code is a number, used by the DHCP server and client to refer to an option. The structure describes what the contents of an option looks like. .PP To define a new option, you need to choose a name for it that is not in use for some other option - for example, you can't use "host-name" because the DHCP protocol already defines a host-name option, which is documented earlier in this manual page. If an option name doesn't appear in this manual page, you can use it, but it's probably a good idea to put some kind of unique string at the beginning so you can be sure that future options don't take your name. For example, you might define an option, "local-host-name", feeling some confidence that no official DHCP option name will ever start with "local". .PP Once you have chosen a name, you must choose a code. All codes between 224 and 254 are reserved as \'site-local\' DHCP options, so you can pick any one of these for your site (not for your product/application). In RFC3942, site-local space was moved from starting at 128 to starting at 224. In practice, some vendors have interpreted the protocol rather loosely and have used option code values greater than 128 themselves. There's no real way to avoid this problem, and it was thought to be unlikely to cause too much trouble in practice. If you come across a vendor-documented option code in either the new or old site-local spaces, please contact your vendor and inform them about rfc3942. .PP The structure of an option is simply the format in which the option data appears. The ISC DHCP server currently supports a few simple types, like integers, booleans, strings and IP addresses, and it also supports the ability to define arrays of single types or arrays of fixed sequences of types. .PP New options are declared as follows: .PP .B option .I new-name .B code .I new-code .B = .I definition .B ; .PP The values of .I new-name and .I new-code should be the name you have chosen for the new option and the code you have chosen. The .I definition should be the definition of the structure of the option. .PP The following simple option type definitions are supported: .PP .B BOOLEAN .PP .B option .I new-name .B code .I new-code .B = .B boolean .B ; .PP An option of type boolean is a flag with a value of either on or off (or true or false). So an example use of the boolean type would be: .nf option use-zephyr code 180 = boolean; option use-zephyr on; .fi .B INTEGER .PP .B option .I new-name .B code .I new-code .B = .I sign .B integer .I width .B ; .PP The \fIsign\fR token should either be blank, \fIunsigned\fR or \fIsigned\fR. The width can be either 8, 16 or 32, and refers to the number of bits in the integer. So for example, the following two lines show a definition of the sql-connection-max option and its use: .nf option sql-connection-max code 192 = unsigned integer 16; option sql-connection-max 1536; .fi .B IP-ADDRESS .PP .B option .I new-name .B code .I new-code .B = .B ip-address .B ; .PP An option whose structure is an IP address can be expressed either as a domain name or as a dotted quad. So the following is an example use of the ip-address type: .nf option sql-server-address code 193 = ip-address; option sql-server-address sql.example.com; .fi .B IP6-ADDRESS .PP .B option .I new-name .B code .I new-code .B = .B ip6-address .B ; .PP An option whose structure is an IPv6 address must be expressed as a valid IPv6 address. The following is an example use of the ip6-address type: .nf option dhcp6.some-server code 1234 = array of ip6-address; option dhcp6.some-server 3ffe:bbbb:aaaa:aaaa::1, 3ffe:bbbb:aaaa:aaaa::2; .fi .PP .B TEXT .PP .B option .I new-name .B code .I new-code .B = .B text .B ; .PP An option whose type is text will encode an ASCII text string. For example: .nf option sql-default-connection-name code 194 = text; option sql-default-connection-name "PRODZA"; .fi .PP .B DATA STRING .PP .B option .I new-name .B code .I new-code .B = .B string .B ; .PP An option whose type is a data string is essentially just a collection of bytes, and can be specified either as quoted text, like the text type, or as a list of hexadecimal contents separated by colons whose values must be between 0 and FF. For example: .nf option sql-identification-token code 195 = string; option sql-identification-token 17:23:19:a6:42:ea:99:7c:22; .fi .PP .B DOMAIN-LIST .PP .B option .I new-name .B code .I new-code .B = .B domain-list .B [compressed] .B ; .PP An option whose type is \fBdomain-list\fR is an RFC1035 formatted (on the wire, "DNS Format") list of domain names, separated by root labels. The optional \fBcompressed\fR keyword indicates if the option should be compressed relative to the start of the option contents (not the packet contents). .PP When in doubt, omit the \fBcompressed\fR keyword. When the software recieves an option that is compressed and the \fBcompressed\fR keyword is omitted, it will still decompress the option (relative to the option contents field). The keyword only controls whether or not transmitted packets are compressed. .PP Note that when .B domain-list formatted options are output as environment variables to .B dhclient-script(8), the standard DNS \-escape mechanism is used: they are decimal. This is appropriate for direct use in eg /etc/resolv.conf. .nf .fi .PP .B ENCAPSULATION .PP .B option .I new-name .B code .I new-code .B = .B encapsulate .I identifier .B ; .PP An option whose type is \fBencapsulate\fR will encapsulate the contents of the option space specified in \fIidentifier\fR. Examples of encapsulated options in the DHCP protocol as it currently exists include the vendor-encapsulated-options option, the netware-suboptions option and the relay-agent-information option. .nf option space local; option local.demo code 1 = text; option local-encapsulation code 197 = encapsulate local; option local.demo "demo"; .fi .PP .B ARRAYS .PP Options can contain arrays of any of the above types except for the text and data string types, which aren't currently supported in arrays. An example of an array definition is as follows: .nf option kerberos-servers code 200 = array of ip-address; option kerberos-servers 10.20.10.1, 10.20.11.1; .fi .B RECORDS .PP Options can also contain data structures consisting of a sequence of data types, which is sometimes called a record type. For example: .nf option contrived-001 code 201 = { boolean, integer 32, text }; option contrived-001 on 1772 "contrivance"; .fi It's also possible to have options that are arrays of records, for example: .nf option new-static-routes code 201 = array of { ip-address, ip-address, ip-address, integer 8 }; option static-routes 10.0.0.0 255.255.255.0 net-0-rtr.example.com 1, 10.0.1.0 255.255.255.0 net-1-rtr.example.com 1, 10.2.0.0 255.255.224.0 net-2-0-rtr.example.com 3; .fi .SH VENDOR ENCAPSULATED OPTIONS The DHCP protocol defines the \fBvendor-encapsulated-options\fR option, which allows vendors to define their own options that will be sent encapsulated in a standard DHCP option. It also defines the \fBVendor Identified Vendor Sub Options\fR option ("VIVSO"), and the DHCPv6 protocol defines the \fBVendor-specific Information Option\fR ("VSIO"). The format of all of these options is usually internally a string of options, similarly to other normal DHCP options. The VIVSO and VSIO options differ in that that they contain options that correspond to vendor Enterprise-ID numbers (assigned by IANA), which then contain options according to each Vendor's specifications. You will need to refer to your vendor's documentation in order to form options to their specification. .PP The value of these options can be set in one of two ways. The first way is to simply specify the data directly, using a text string or a colon-separated list of hexadecimal values. For help in forming these strings, please refer to \fBRFC2132\fR for the DHCPv4 \fBVendor Specific Information Option\fR, \fBRFC3925\fR for the DHCPv4 \fBVendor Identified Vendor Sub Options\fR, or \fBRFC3315\fR for the DHCPv6 \fBVendor-specific Information Option\fR. For example: .PP .nf option vendor-encapsulated-options 2:4: AC:11:41:1: 3:12: 73:75:6e:64:68:63:70:2d:73:65:72:76:65:72:31:37:2d:31: 4:12: 2f:65:78:70:6f:72:74:2f:72:6f:6f:74:2f:69:38:36:70:63; option vivso 00:00:09:bf:0E: 01:0c: 48:65:6c:6c:6f:20:77:6f:72:6c:64:21; option dhcp6.vendor-opts 00:00:09:bf: 00:01:00:0c: 48:65:6c:6c:6f:20:77:6f:72:6c:64:21; .fi .PP The second way of setting the value of these options is to have the DHCP server generate a vendor-specific option buffer. To do this, you must do four things: define an option space, define some options in that option space, provide values for them, and specify that that option space should be used to generate the relevant option. .PP To define a new option space in which vendor options can be stored, use the \fRoption space\fP statement: .PP .B option .B space .I name .B [ [ code width .I number .B ] [ length width .I number .B ] [ hash size .I number .B ] ] ; .PP Where the numbers following \fBcode width\fR, \fBlength width\fR, and \fBhash size\fR respectively identify the number of bytes used to describe option codes, option lengths, and the size in buckets of the hash tables to hold options in this space (most DHCPv4 option spaces use 1 byte codes and lengths, which is the default, whereas most DHCPv6 option spaces use 2 byte codes and lengths). .PP The code and length widths are used in DHCP protocol - you must configure these numbers to match the applicable option space you are configuring. They each default to 1. Valid values for code widths are 1, 2 or 4. Valid values for length widths are 0, 1 or 2. Most DHCPv4 option spaces use 1 byte codes and lengths, which is the default, whereas most DHCPv6 option spaces use 2 byte codes and lengths. A zero-byte length produces options similar to the DHCPv6 Vendor-specific Information Option - but not their contents! .PP The hash size defaults depend upon the \fBcode width\fR selected, and may be 254 or 1009. Valid values range between 1 and 65535. Note that the higher you configure this value, the more memory will be used. It is considered good practice to configure a value that is slightly larger than the estimated number of options you plan to configure within the space. Previous versions of ISC DHCP (up to and including DHCP 3.0.*), this value was fixed at 9973. .PP The name can then be used in option definitions, as described earlier in this document. For example: .nf option space SUNW code width 1 length width 1 hash size 3; option SUNW.server-address code 2 = ip-address; option SUNW.server-name code 3 = text; option SUNW.root-path code 4 = text; option space ISC code width 1 length width 1 hash size 3; option ISC.sample code 1 = text; option vendor.ISC code 2495 = encapsulate vivso-sample; option vendor-class.ISC code 2495 = text; option ISC.sample "configuration text here"; option vendor-class.ISC "vendor class here"; option space docsis code width 2 length width 2 hash size 17; option docsis.tftp-servers code 32 = array of ip6-address; option docsis.cablelabs-configuration-file code 33 = text; option docsis.cablelabs-syslog-servers code 34 = array of ip6-address; option docsis.device-id code 36 = string; option docsis.time-servers code 37 = array of ip6-address; option docsis.time-offset code 38 = signed integer 32; option vsio.docsis code 4491 = encapsulate docsis; .fi Once you have defined an option space and the format of some options, you can set up scopes that define values for those options, and you can say when to use them. For example, suppose you want to handle two different classes of clients. Using the option space definition shown in the previous example, you can send different option values to different clients based on the vendor-class-identifier option that the clients send, as follows: .PP .nf class "vendor-classes" { match option vendor-class-identifier; } subclass "vendor-classes" "SUNW.Ultra-5_10" { vendor-option-space SUNW; option SUNW.root-path "/export/root/sparc"; } subclass "vendor-classes" "SUNW.i86pc" { vendor-option-space SUNW; option SUNW.root-path "/export/root/i86pc"; } option SUNW.server-address 172.17.65.1; option SUNW.server-name "sundhcp-server17-1"; option vivso-sample.sample "Hello world!"; option docsis.tftp-servers ::1; .fi .PP As you can see in the preceding example, regular scoping rules apply, so you can define values that are global in the global scope, and only define values that are specific to a particular class in the local scope. The \fBvendor-option-space\fR declaration tells the DHCP server to use options in the SUNW option space to construct the DHCPv4 .B vendor-encapsulated-options option. This is a limitation of that option - the DHCPv4 VIVSO and the DHCPv6 VSIO options can have multiple vendor definitions all at once (even transmitted to the same client), so it is not necessary to configure this. .SH SEE ALSO dhcpd.conf(5), dhcpd.leases(5), dhclient.conf(5), dhcp-eval(5), dhcpd(8), dhclient(8), RFC2132, RFC2131, RFC3046, RFC3315. .SH AUTHOR The Internet Systems Consortium DHCP Distribution was written by Ted Lemon under a contract with Vixie Labs. Funding for this project was provided through Internet Systems Consortium. Information about Internet Systems Consortium can be found at .B https://www.isc.org. dhcp-4.2.4/common/discover.c000644 000765 000024 00000136555 11611401670 015655 0ustar00sarstaff000000 000000 /* discover.c Find and identify the network interfaces. */ /* * Copyright (c) 2004-2009,2011 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1995-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ * * This software has been written for Internet Systems Consortium * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. * To learn more about Internet Systems Consortium, see * ``https://www.isc.org/''. To learn more about Vixie Enterprises, * see ``http://www.vix.com''. To learn more about Nominum, Inc., see * ``http://www.nominum.com''. */ #include "dhcpd.h" #define BSD_COMP /* needed on Solaris for SIOCGLIFNUM */ #include #include #ifdef HAVE_NET_IF6_H # include #endif struct interface_info *interfaces, *dummy_interfaces, *fallback_interface; int interfaces_invalidated; int quiet_interface_discovery; u_int16_t local_port; u_int16_t remote_port; int (*dhcp_interface_setup_hook) (struct interface_info *, struct iaddr *); int (*dhcp_interface_discovery_hook) (struct interface_info *); isc_result_t (*dhcp_interface_startup_hook) (struct interface_info *); int (*dhcp_interface_shutdown_hook) (struct interface_info *); struct in_addr limited_broadcast; int local_family = AF_INET; struct in_addr local_address; #ifdef DHCPv6 struct in6_addr local_address6; #endif /* DHCPv6 */ void (*bootp_packet_handler) (struct interface_info *, struct dhcp_packet *, unsigned, unsigned int, struct iaddr, struct hardware *); #ifdef DHCPv6 void (*dhcpv6_packet_handler)(struct interface_info *, const char *, int, int, const struct iaddr *, isc_boolean_t); #endif /* DHCPv6 */ omapi_object_type_t *dhcp_type_interface; #if defined (TRACING) trace_type_t *interface_trace; trace_type_t *inpacket_trace; trace_type_t *outpacket_trace; #endif struct interface_info **interface_vector; int interface_count; int interface_max; OMAPI_OBJECT_ALLOC (interface, struct interface_info, dhcp_type_interface) isc_result_t interface_setup () { isc_result_t status; status = omapi_object_type_register (&dhcp_type_interface, "interface", dhcp_interface_set_value, dhcp_interface_get_value, dhcp_interface_destroy, dhcp_interface_signal_handler, dhcp_interface_stuff_values, dhcp_interface_lookup, dhcp_interface_create, dhcp_interface_remove, 0, 0, 0, sizeof (struct interface_info), interface_initialize, RC_MISC); if (status != ISC_R_SUCCESS) log_fatal ("Can't register interface object type: %s", isc_result_totext (status)); return status; } #if defined (TRACING) void interface_trace_setup () { interface_trace = trace_type_register ("interface", (void *)0, trace_interface_input, trace_interface_stop, MDL); inpacket_trace = trace_type_register ("inpacket", (void *)0, trace_inpacket_input, trace_inpacket_stop, MDL); outpacket_trace = trace_type_register ("outpacket", (void *)0, trace_outpacket_input, trace_outpacket_stop, MDL); } #endif isc_result_t interface_initialize (omapi_object_t *ipo, const char *file, int line) { struct interface_info *ip = (struct interface_info *)ipo; ip -> rfdesc = ip -> wfdesc = -1; return ISC_R_SUCCESS; } /* * Scanning for Interfaces * ----------------------- * * To find interfaces, we create an iterator that abstracts out most * of the platform specifics. Use is fairly straightforward: * * - begin_iface_scan() starts the process. * - Use next_iface() until it returns 0. * - end_iface_scan() performs any necessary cleanup. * * We check for errors on each call to next_iface(), which returns a * description of the error as a string if any occurs. * * We currently have code for Solaris and Linux. Other systems need * to have code written. * * NOTE: the long-term goal is to use the interface code from BIND 9. */ #if defined(SIOCGLIFCONF) && defined(SIOCGLIFNUM) && defined(SIOCGLIFFLAGS) /* HP/UX doesn't define struct lifconf, instead they define struct * if_laddrconf. Similarly, 'struct lifreq' and 'struct lifaddrreq'. */ #ifdef ISC_PLATFORM_HAVEIF_LADDRCONF # define lifc_len iflc_len # define lifc_buf iflc_buf # define lifc_req iflc_req # define LIFCONF if_laddrconf #else # define ISC_HAVE_LIFC_FAMILY 1 # define ISC_HAVE_LIFC_FLAGS 1 # define LIFCONF lifconf #endif #ifdef ISC_PLATFORM_HAVEIF_LADDRREQ # define lifr_addr iflr_addr # define lifr_name iflr_name # define lifr_dstaddr iflr_dstaddr # define lifr_flags iflr_flags # define sockaddr_storage sockaddr_ext # define ss_family sa_family # define LIFREQ if_laddrreq #else # define LIFREQ lifreq #endif #ifndef IF_NAMESIZE # if defined(LIFNAMSIZ) # define IF_NAMESIZE LIFNAMSIZ # elif defined(IFNAMSIZ) # define IF_NAMESIZE IFNAMSIZ # else # define IF_NAMESIZE 16 # endif #endif #elif !defined(__linux) && !defined(HAVE_IFADDRS_H) # define SIOCGLIFCONF SIOCGIFCONF # define SIOCGLIFFLAGS SIOCGIFFLAGS # define LIFREQ ifreq # define LIFCONF ifconf # define lifr_name ifr_name # define lifr_addr ifr_addr # define lifr_flags ifr_flags # define lifc_len ifc_len # define lifc_buf ifc_buf # define lifc_req ifc_req #ifdef _AIX # define ss_family __ss_family #endif #endif #if defined(SIOCGLIFCONF) && defined(SIOCGLIFFLAGS) /* * Solaris support * --------------- * * The SIOCGLIFCONF ioctl() are the extension that you need to use * on Solaris to get information about IPv6 addresses. * * Solaris' extended interface is documented in the if_tcp man page. */ /* * Structure holding state about the scan. */ struct iface_conf_list { int sock; /* file descriptor used to get information */ int num; /* total number of interfaces */ struct LIFCONF conf; /* structure used to get information */ int next; /* next interface to retrieve when iterating */ }; /* * Structure used to return information about a specific interface. */ struct iface_info { char name[IF_NAMESIZE+1]; /* name of the interface, e.g. "bge0" */ struct sockaddr_storage addr; /* address information */ isc_uint64_t flags; /* interface flags, e.g. IFF_LOOPBACK */ }; /* * Start a scan of interfaces. * * The iface_conf_list structure maintains state for this process. */ int begin_iface_scan(struct iface_conf_list *ifaces) { #ifdef ISC_PLATFORM_HAVELIFNUM struct lifnum lifnum; #else int lifnum; #endif ifaces->sock = socket(local_family, SOCK_DGRAM, IPPROTO_UDP); if (ifaces->sock < 0) { log_error("Error creating socket to list interfaces; %m"); return 0; } memset(&lifnum, 0, sizeof(lifnum)); #ifdef ISC_PLATFORM_HAVELIFNUM lifnum.lifn_family = AF_UNSPEC; #endif #ifdef SIOCGLIFNUM if (ioctl(ifaces->sock, SIOCGLIFNUM, &lifnum) < 0) { log_error("Error finding total number of interfaces; %m"); close(ifaces->sock); ifaces->sock = -1; return 0; } #ifdef ISC_PLATFORM_HAVELIFNUM ifaces->num = lifnum.lifn_count; #else ifaces->num = lifnum; #endif #else ifaces->num = 64; #endif /* SIOCGLIFNUM */ memset(&ifaces->conf, 0, sizeof(ifaces->conf)); #ifdef ISC_HAVE_LIFC_FAMILY ifaces->conf.lifc_family = AF_UNSPEC; #endif ifaces->conf.lifc_len = ifaces->num * sizeof(struct LIFREQ); ifaces->conf.lifc_buf = dmalloc(ifaces->conf.lifc_len, MDL); if (ifaces->conf.lifc_buf == NULL) { log_fatal("Out of memory getting interface list."); } if (ioctl(ifaces->sock, SIOCGLIFCONF, &ifaces->conf) < 0) { log_error("Error getting interfaces configuration list; %m"); dfree(ifaces->conf.lifc_buf, MDL); close(ifaces->sock); ifaces->sock = -1; return 0; } ifaces->next = 0; return 1; } /* * Retrieve the next interface. * * Returns information in the info structure. * Sets err to 1 if there is an error, otherwise 0. */ int next_iface(struct iface_info *info, int *err, struct iface_conf_list *ifaces) { struct LIFREQ *p; struct LIFREQ tmp; isc_boolean_t foundif; #if defined(sun) || defined(__linux) /* Pointer used to remove interface aliases. */ char *s; #endif do { foundif = ISC_FALSE; if (ifaces->next >= ifaces->num) { *err = 0; return 0; } p = ifaces->conf.lifc_req; p += ifaces->next; if (strlen(p->lifr_name) >= sizeof(info->name)) { *err = 1; log_error("Interface name '%s' too long", p->lifr_name); return 0; } /* Reject if interface address family does not match */ if (p->lifr_addr.ss_family != local_family) { ifaces->next++; continue; } strcpy(info->name, p->lifr_name); memset(&info->addr, 0, sizeof(info->addr)); memcpy(&info->addr, &p->lifr_addr, sizeof(p->lifr_addr)); #if defined(sun) || defined(__linux) /* interface aliases look like "eth0:1" or "wlan1:3" */ s = strchr(info->name, ':'); if (s != NULL) { *s = '\0'; } #endif /* defined(sun) || defined(__linux) */ foundif = ISC_TRUE; } while ((foundif == ISC_FALSE) || (strncmp(info->name, "dummy", 5) == 0)); memset(&tmp, 0, sizeof(tmp)); strcpy(tmp.lifr_name, info->name); if (ioctl(ifaces->sock, SIOCGLIFFLAGS, &tmp) < 0) { log_error("Error getting interface flags for '%s'; %m", p->lifr_name); *err = 1; return 0; } info->flags = tmp.lifr_flags; ifaces->next++; *err = 0; return 1; } /* * End scan of interfaces. */ void end_iface_scan(struct iface_conf_list *ifaces) { dfree(ifaces->conf.lifc_buf, MDL); close(ifaces->sock); ifaces->sock = -1; } #elif __linux /* !HAVE_SIOCGLIFCONF */ /* * Linux support * ------------- * * In Linux, we use the /proc pseudo-filesystem to get information * about interfaces, along with selected ioctl() calls. * * Linux low level access is documented in the netdevice man page. */ /* * Structure holding state about the scan. */ struct iface_conf_list { int sock; /* file descriptor used to get information */ FILE *fp; /* input from /proc/net/dev */ #ifdef DHCPv6 FILE *fp6; /* input from /proc/net/if_inet6 */ #endif }; /* * Structure used to return information about a specific interface. */ struct iface_info { char name[IFNAMSIZ]; /* name of the interface, e.g. "eth0" */ struct sockaddr_storage addr; /* address information */ isc_uint64_t flags; /* interface flags, e.g. IFF_LOOPBACK */ }; /* * Start a scan of interfaces. * * The iface_conf_list structure maintains state for this process. */ int begin_iface_scan(struct iface_conf_list *ifaces) { char buf[256]; int len; int i; ifaces->fp = fopen("/proc/net/dev", "r"); if (ifaces->fp == NULL) { log_error("Error opening '/proc/net/dev' to list interfaces"); return 0; } /* * The first 2 lines are header information, so read and ignore them. */ for (i=0; i<2; i++) { if (fgets(buf, sizeof(buf), ifaces->fp) == NULL) { log_error("Error reading headers from '/proc/net/dev'"); fclose(ifaces->fp); ifaces->fp = NULL; return 0; } len = strlen(buf); if ((len <= 0) || (buf[len-1] != '\n')) { log_error("Bad header line in '/proc/net/dev'"); fclose(ifaces->fp); ifaces->fp = NULL; return 0; } } ifaces->sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (ifaces->sock < 0) { log_error("Error creating socket to list interfaces; %m"); fclose(ifaces->fp); ifaces->fp = NULL; return 0; } #ifdef DHCPv6 if (local_family == AF_INET6) { ifaces->fp6 = fopen("/proc/net/if_inet6", "r"); if (ifaces->fp6 == NULL) { log_error("Error opening '/proc/net/if_inet6' to " "list IPv6 interfaces; %m"); close(ifaces->sock); ifaces->sock = -1; fclose(ifaces->fp); ifaces->fp = NULL; return 0; } } #endif return 1; } /* * Read our IPv4 interfaces from /proc/net/dev. * * The file looks something like this: * * Inter-| Receive ... * face |bytes packets errs drop fifo frame ... * lo: 1580562 4207 0 0 0 0 ... * eth0: 0 0 0 0 0 0 ... * eth1:1801552440 37895 0 14 0 ... * * We only care about the interface name, which is at the start of * each line. * * We use an ioctl() to get the address and flags for each interface. */ static int next_iface4(struct iface_info *info, int *err, struct iface_conf_list *ifaces) { char buf[256]; int len; char *p; char *name; struct ifreq tmp; /* * Loop exits when we find an interface that has an address, or * when we run out of interfaces. */ for (;;) { do { /* * Read the next line in the file. */ if (fgets(buf, sizeof(buf), ifaces->fp) == NULL) { if (ferror(ifaces->fp)) { *err = 1; log_error("Error reading interface " "information"); } else { *err = 0; } return 0; } /* * Make sure the line is a nice, * newline-terminated line. */ len = strlen(buf); if ((len <= 0) || (buf[len-1] != '\n')) { log_error("Bad line reading interface " "information"); *err = 1; return 0; } /* * Figure out our name. */ p = strrchr(buf, ':'); if (p == NULL) { log_error("Bad line reading interface " "information (no colon)"); *err = 1; return 0; } *p = '\0'; name = buf; while (isspace(*name)) { name++; } /* * Copy our name into our interface structure. */ len = p - name; if (len >= sizeof(info->name)) { *err = 1; log_error("Interface name '%s' too long", name); return 0; } strcpy(info->name, name); #ifdef ALIAS_NAMED_PERMUTED /* interface aliases look like "eth0:1" or "wlan1:3" */ s = strchr(info->name, ':'); if (s != NULL) { *s = '\0'; } #endif #ifdef SKIP_DUMMY_INTERFACES } while (strncmp(info->name, "dummy", 5) == 0); #else } while (0); #endif memset(&tmp, 0, sizeof(tmp)); strcpy(tmp.ifr_name, name); if (ioctl(ifaces->sock, SIOCGIFADDR, &tmp) < 0) { if (errno == EADDRNOTAVAIL) { continue; } log_error("Error getting interface address " "for '%s'; %m", name); *err = 1; return 0; } memcpy(&info->addr, &tmp.ifr_addr, sizeof(tmp.ifr_addr)); memset(&tmp, 0, sizeof(tmp)); strcpy(tmp.ifr_name, name); if (ioctl(ifaces->sock, SIOCGIFFLAGS, &tmp) < 0) { log_error("Error getting interface flags for '%s'; %m", name); *err = 1; return 0; } info->flags = tmp.ifr_flags; *err = 0; return 1; } } #ifdef DHCPv6 /* * Read our IPv6 interfaces from /proc/net/if_inet6. * * The file looks something like this: * * fe80000000000000025056fffec00008 05 40 20 80 vmnet8 * 00000000000000000000000000000001 01 80 10 80 lo * fe80000000000000025056fffec00001 06 40 20 80 vmnet1 * 200108881936000202166ffffe497d9b 03 40 00 00 eth1 * fe8000000000000002166ffffe497d9b 03 40 20 80 eth1 * * We get IPv6 address from the start, the interface name from the end, * and ioctl() to get flags. */ static int next_iface6(struct iface_info *info, int *err, struct iface_conf_list *ifaces) { char buf[256]; int len; char *p; char *name; int i; struct sockaddr_in6 addr; struct ifreq tmp; do { /* * Read the next line in the file. */ if (fgets(buf, sizeof(buf), ifaces->fp6) == NULL) { if (ferror(ifaces->fp6)) { *err = 1; log_error("Error reading IPv6 " "interface information"); } else { *err = 0; } return 0; } /* * Make sure the line is a nice, newline-terminated line. */ len = strlen(buf); if ((len <= 0) || (buf[len-1] != '\n')) { log_error("Bad line reading IPv6 " "interface information"); *err = 1; return 0; } /* * Figure out our name. */ buf[--len] = '\0'; p = strrchr(buf, ' '); if (p == NULL) { log_error("Bad line reading IPv6 interface " "information (no space)"); *err = 1; return 0; } name = p+1; /* * Copy our name into our interface structure. */ len = strlen(name); if (len >= sizeof(info->name)) { *err = 1; log_error("IPv6 interface name '%s' too long", name); return 0; } strcpy(info->name, name); #ifdef SKIP_DUMMY_INTERFACES } while (strncmp(info->name, "dummy", 5) == 0); #else } while (0); #endif /* * Double-check we start with the IPv6 address. */ for (i=0; i<32; i++) { if (!isxdigit(buf[i]) || isupper(buf[i])) { *err = 1; log_error("Bad line reading IPv6 interface address " "for '%s'", name); return 0; } } /* * Load our socket structure. */ memset(&addr, 0, sizeof(addr)); addr.sin6_family = AF_INET6; for (i=0; i<16; i++) { unsigned char byte; static const char hex[] = "0123456789abcdef"; byte = ((index(hex, buf[i * 2]) - hex) << 4) | (index(hex, buf[i * 2 + 1]) - hex); addr.sin6_addr.s6_addr[i] = byte; } memcpy(&info->addr, &addr, sizeof(addr)); /* * Get our flags. */ memset(&tmp, 0, sizeof(tmp)); strcpy(tmp.ifr_name, name); if (ioctl(ifaces->sock, SIOCGIFFLAGS, &tmp) < 0) { log_error("Error getting interface flags for '%s'; %m", name); *err = 1; return 0; } info->flags = tmp.ifr_flags; *err = 0; return 1; } #endif /* DHCPv6 */ /* * Retrieve the next interface. * * Returns information in the info structure. * Sets err to 1 if there is an error, otherwise 0. */ int next_iface(struct iface_info *info, int *err, struct iface_conf_list *ifaces) { if (next_iface4(info, err, ifaces)) { return 1; } #ifdef DHCPv6 if (!(*err)) { if (local_family == AF_INET6) return next_iface6(info, err, ifaces); } #endif return 0; } /* * End scan of interfaces. */ void end_iface_scan(struct iface_conf_list *ifaces) { fclose(ifaces->fp); ifaces->fp = NULL; close(ifaces->sock); ifaces->sock = -1; #ifdef DHCPv6 if (local_family == AF_INET6) { fclose(ifaces->fp6); ifaces->fp6 = NULL; } #endif } #else /* * BSD support * ----------- * * FreeBSD, NetBSD, OpenBSD, and OS X all have the getifaddrs() * function. * * The getifaddrs() man page describes the use. */ #include /* * Structure holding state about the scan. */ struct iface_conf_list { struct ifaddrs *head; /* beginning of the list */ struct ifaddrs *next; /* current position in the list */ }; /* * Structure used to return information about a specific interface. */ struct iface_info { char name[IFNAMSIZ]; /* name of the interface, e.g. "bge0" */ struct sockaddr_storage addr; /* address information */ isc_uint64_t flags; /* interface flags, e.g. IFF_LOOPBACK */ }; /* * Start a scan of interfaces. * * The iface_conf_list structure maintains state for this process. */ int begin_iface_scan(struct iface_conf_list *ifaces) { if (getifaddrs(&ifaces->head) != 0) { log_error("Error getting interfaces; %m"); return 0; } ifaces->next = ifaces->head; return 1; } /* * Retrieve the next interface. * * Returns information in the info structure. * Sets err to 1 if there is an error, otherwise 0. */ int next_iface(struct iface_info *info, int *err, struct iface_conf_list *ifaces) { if (ifaces->next == NULL) { *err = 0; return 0; } if (strlen(ifaces->next->ifa_name) >= sizeof(info->name)) { log_error("Interface name '%s' too long", ifaces->next->ifa_name); *err = 1; return 0; } strcpy(info->name, ifaces->next->ifa_name); memcpy(&info->addr, ifaces->next->ifa_addr, ifaces->next->ifa_addr->sa_len); info->flags = ifaces->next->ifa_flags; ifaces->next = ifaces->next->ifa_next; *err = 0; return 1; } /* * End scan of interfaces. */ void end_iface_scan(struct iface_conf_list *ifaces) { freeifaddrs(ifaces->head); ifaces->head = NULL; ifaces->next = NULL; } #endif /* XXX: perhaps create drealloc() rather than do it manually */ void add_ipv4_addr_to_interface(struct interface_info *iface, const struct in_addr *addr) { /* * We don't expect a lot of addresses per IPv4 interface, so * we use 4, as our "chunk size" for collecting addresses. */ if (iface->addresses == NULL) { iface->addresses = dmalloc(4 * sizeof(struct in_addr), MDL); if (iface->addresses == NULL) { log_fatal("Out of memory saving IPv4 address " "on interface."); } iface->address_count = 0; iface->address_max = 4; } else if (iface->address_count >= iface->address_max) { struct in_addr *tmp; int new_max; new_max = iface->address_max + 4; tmp = dmalloc(new_max * sizeof(struct in_addr), MDL); if (tmp == NULL) { log_fatal("Out of memory saving IPv4 address " "on interface."); } memcpy(tmp, iface->addresses, iface->address_max * sizeof(struct in_addr)); dfree(iface->addresses, MDL); iface->addresses = tmp; iface->address_max = new_max; } iface->addresses[iface->address_count++] = *addr; } #ifdef DHCPv6 /* XXX: perhaps create drealloc() rather than do it manually */ void add_ipv6_addr_to_interface(struct interface_info *iface, const struct in6_addr *addr) { /* * Each IPv6 interface will have at least two IPv6 addresses, * and likely quite a few more. So we use 8, as our "chunk size" for * collecting addresses. */ if (iface->v6addresses == NULL) { iface->v6addresses = dmalloc(8 * sizeof(struct in6_addr), MDL); if (iface->v6addresses == NULL) { log_fatal("Out of memory saving IPv6 address " "on interface."); } iface->v6address_count = 0; iface->v6address_max = 8; } else if (iface->v6address_count >= iface->v6address_max) { struct in6_addr *tmp; int new_max; new_max = iface->v6address_max + 8; tmp = dmalloc(new_max * sizeof(struct in6_addr), MDL); if (tmp == NULL) { log_fatal("Out of memory saving IPv6 address " "on interface."); } memcpy(tmp, iface->v6addresses, iface->v6address_max * sizeof(struct in6_addr)); dfree(iface->v6addresses, MDL); iface->v6addresses = tmp; iface->v6address_max = new_max; } iface->v6addresses[iface->v6address_count++] = *addr; } #endif /* DHCPv6 */ /* Use the SIOCGIFCONF ioctl to get a list of all the attached interfaces. For each interface that's of type INET and not the loopback interface, register that interface with the network I/O software, figure out what subnet it's on, and add it to the list of interfaces. */ void discover_interfaces(int state) { struct iface_conf_list ifaces; struct iface_info info; int err; struct interface_info *tmp; struct interface_info *last, *next; #ifdef DHCPv6 char abuf[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")]; #endif /* DHCPv6 */ struct subnet *subnet; int ir; isc_result_t status; int wifcount = 0; static int setup_fallback = 0; if (!begin_iface_scan(&ifaces)) { log_fatal("Can't get list of interfaces."); } /* If we already have a list of interfaces, and we're running as a DHCP server, the interfaces were requested. */ if (interfaces && (state == DISCOVER_SERVER || state == DISCOVER_RELAY || state == DISCOVER_REQUESTED)) ir = 0; else if (state == DISCOVER_UNCONFIGURED) ir = INTERFACE_REQUESTED | INTERFACE_AUTOMATIC; else ir = INTERFACE_REQUESTED; /* Cycle through the list of interfaces looking for IP addresses. */ while (next_iface(&info, &err, &ifaces)) { /* See if we've seen an interface that matches this one. */ for (tmp = interfaces; tmp; tmp = tmp->next) { if (!strcmp(tmp->name, info.name)) break; } /* Skip non broadcast interfaces (plus loopback and point-to-point in case an OS incorrectly marks them as broadcast). Also skip down interfaces unless we're trying to get a list of configurable interfaces. */ if ((((local_family == AF_INET && !(info.flags & IFF_BROADCAST)) || #ifdef DHCPv6 (local_family == AF_INET6 && !(info.flags & IFF_MULTICAST)) || #endif info.flags & IFF_LOOPBACK || info.flags & IFF_POINTOPOINT) && !tmp) || (!(info.flags & IFF_UP) && state != DISCOVER_UNCONFIGURED)) continue; /* If there isn't already an interface by this name, allocate one. */ if (tmp == NULL) { status = interface_allocate(&tmp, MDL); if (status != ISC_R_SUCCESS) { log_fatal("Error allocating interface %s: %s", info.name, isc_result_totext(status)); } strcpy(tmp->name, info.name); interface_snorf(tmp, ir); interface_dereference(&tmp, MDL); tmp = interfaces; /* XXX */ } if (dhcp_interface_discovery_hook) { (*dhcp_interface_discovery_hook)(tmp); } if ((info.addr.ss_family == AF_INET) && (local_family == AF_INET)) { struct sockaddr_in *a = (struct sockaddr_in*)&info.addr; struct iaddr addr; /* We don't want the loopback interface. */ if (a->sin_addr.s_addr == htonl(INADDR_LOOPBACK) && ((tmp->flags & INTERFACE_AUTOMATIC) && state == DISCOVER_SERVER)) continue; /* If the only address we have is 0.0.0.0, we shouldn't consider the interface configured. */ if (a->sin_addr.s_addr != htonl(INADDR_ANY)) tmp->configured = 1; add_ipv4_addr_to_interface(tmp, &a->sin_addr); /* invoke the setup hook */ addr.len = 4; memcpy(addr.iabuf, &a->sin_addr.s_addr, addr.len); if (dhcp_interface_setup_hook) { (*dhcp_interface_setup_hook)(tmp, &addr); } } #ifdef DHCPv6 else if ((info.addr.ss_family == AF_INET6) && (local_family == AF_INET6)) { struct sockaddr_in6 *a = (struct sockaddr_in6*)&info.addr; struct iaddr addr; /* We don't want the loopback interface. */ if (IN6_IS_ADDR_LOOPBACK(&a->sin6_addr) && ((tmp->flags & INTERFACE_AUTOMATIC) && state == DISCOVER_SERVER)) continue; /* If the only address we have is 0.0.0.0, we shouldn't consider the interface configured. */ if (IN6_IS_ADDR_UNSPECIFIED(&a->sin6_addr)) tmp->configured = 1; add_ipv6_addr_to_interface(tmp, &a->sin6_addr); /* invoke the setup hook */ addr.len = 16; memcpy(addr.iabuf, &a->sin6_addr, addr.len); if (dhcp_interface_setup_hook) { (*dhcp_interface_setup_hook)(tmp, &addr); } } #endif /* DHCPv6 */ } if (err) { log_fatal("Error getting interface information."); } end_iface_scan(&ifaces); /* Mock-up an 'ifp' structure which is no longer used in the * new interface-sensing code, but is used in higher layers * (for example to sense fallback interfaces). */ for (tmp = interfaces ; tmp != NULL ; tmp = tmp->next) { if (tmp->ifp == NULL) { struct ifreq *tif; tif = (struct ifreq *)dmalloc(sizeof(struct ifreq), MDL); if (tif == NULL) log_fatal("no space for ifp mockup."); strcpy(tif->ifr_name, tmp->name); tmp->ifp = tif; } } /* If we're just trying to get a list of interfaces that we might be able to configure, we can quit now. */ if (state == DISCOVER_UNCONFIGURED) { return; } /* Weed out the interfaces that did not have IP addresses. */ tmp = last = next = NULL; if (interfaces) interface_reference (&tmp, interfaces, MDL); while (tmp) { if (next) interface_dereference (&next, MDL); if (tmp -> next) interface_reference (&next, tmp -> next, MDL); /* skip interfaces that are running already */ if (tmp -> flags & INTERFACE_RUNNING) { interface_dereference(&tmp, MDL); if(next) interface_reference(&tmp, next, MDL); continue; } if ((tmp -> flags & INTERFACE_AUTOMATIC) && state == DISCOVER_REQUESTED) tmp -> flags &= ~(INTERFACE_AUTOMATIC | INTERFACE_REQUESTED); #ifdef DHCPv6 if (!(tmp->flags & INTERFACE_REQUESTED)) { #else if (!tmp -> ifp || !(tmp -> flags & INTERFACE_REQUESTED)) { #endif /* DHCPv6 */ if ((tmp -> flags & INTERFACE_REQUESTED) != ir) log_fatal ("%s: not found", tmp -> name); if (!last) { if (interfaces) interface_dereference (&interfaces, MDL); if (next) interface_reference (&interfaces, next, MDL); } else { interface_dereference (&last -> next, MDL); if (next) interface_reference (&last -> next, next, MDL); } if (tmp -> next) interface_dereference (&tmp -> next, MDL); /* Remember the interface in case we need to know about it later. */ if (dummy_interfaces) { interface_reference (&tmp -> next, dummy_interfaces, MDL); interface_dereference (&dummy_interfaces, MDL); } interface_reference (&dummy_interfaces, tmp, MDL); interface_dereference (&tmp, MDL); if (next) interface_reference (&tmp, next, MDL); continue; } last = tmp; /* We must have a subnet declaration for each interface. */ if (!tmp->shared_network && (state == DISCOVER_SERVER)) { log_error("%s", ""); if (local_family == AF_INET) { log_error("No subnet declaration for %s (%s).", tmp->name, (tmp->addresses == NULL) ? "no IPv4 addresses" : inet_ntoa(tmp->addresses[0])); #ifdef DHCPv6 } else { if (tmp->v6addresses != NULL) { inet_ntop(AF_INET6, &tmp->v6addresses[0], abuf, sizeof(abuf)); } else { strcpy(abuf, "no IPv6 addresses"); } log_error("No subnet6 declaration for %s (%s).", tmp->name, abuf); #endif /* DHCPv6 */ } if (supports_multiple_interfaces(tmp)) { log_error ("** Ignoring requests on %s. %s", tmp -> name, "If this is not what"); log_error (" you want, please write %s", #ifdef DHCPv6 (local_family != AF_INET) ? "a subnet6 declaration" : #endif "a subnet declaration"); log_error (" in your dhcpd.conf file %s", "for the network segment"); log_error (" to %s %s %s", "which interface", tmp -> name, "is attached. **"); log_error ("%s", ""); goto next; } else { log_error ("You must write a %s", #ifdef DHCPv6 (local_family != AF_INET) ? "subnet6 declaration for this" : #endif "subnet declaration for this"); log_error ("subnet. You cannot prevent %s", "the DHCP server"); log_error ("from listening on this subnet %s", "because your"); log_fatal ("operating system does not %s.", "support this capability"); } } /* Find subnets that don't have valid interface addresses... */ for (subnet = (tmp -> shared_network ? tmp -> shared_network -> subnets : (struct subnet *)0); subnet; subnet = subnet -> next_sibling) { /* Set the interface address for this subnet to the first address we found. */ if (subnet->interface_address.len == 0) { if (tmp->address_count > 0) { subnet->interface_address.len = 4; memcpy(subnet->interface_address.iabuf, &tmp->addresses[0].s_addr, 4); } else if (tmp->v6address_count > 0) { subnet->interface_address.len = 16; memcpy(subnet->interface_address.iabuf, &tmp->v6addresses[0].s6_addr, 16); } else { /* XXX: should be one */ log_error("%s missing an interface " "address", tmp->name); continue; } } } /* Flag the index as not having been set, so that the interface registerer can set it or not as it chooses. */ tmp -> index = -1; /* Register the interface... */ if (local_family == AF_INET) { if_register_receive(tmp); if_register_send(tmp); #ifdef DHCPv6 } else { if ((state == DISCOVER_SERVER) || (state == DISCOVER_RELAY)) { if_register6(tmp, 1); } else { if_register6(tmp, 0); } #endif /* DHCPv6 */ } interface_stash (tmp); wifcount++; #if defined (F_SETFD) if (fcntl (tmp -> rfdesc, F_SETFD, 1) < 0) log_error ("Can't set close-on-exec on %s: %m", tmp -> name); if (tmp -> rfdesc != tmp -> wfdesc) { if (fcntl (tmp -> wfdesc, F_SETFD, 1) < 0) log_error ("Can't set close-on-exec on %s: %m", tmp -> name); } #endif next: interface_dereference (&tmp, MDL); if (next) interface_reference (&tmp, next, MDL); } /* * Now register all the remaining interfaces as protocols. * We register with omapi to allow for control of the interface, * we've already registered the fd or socket with the socket * manager as part of if_register_receive(). */ for (tmp = interfaces; tmp; tmp = tmp -> next) { /* not if it's been registered before */ if (tmp -> flags & INTERFACE_RUNNING) continue; if (tmp -> rfdesc == -1) continue; switch (local_family) { #ifdef DHCPv6 case AF_INET6: status = omapi_register_io_object((omapi_object_t *)tmp, if_readsocket, 0, got_one_v6, 0, 0); break; #endif /* DHCPv6 */ case AF_INET: default: status = omapi_register_io_object((omapi_object_t *)tmp, if_readsocket, 0, got_one, 0, 0); break; } if (status != ISC_R_SUCCESS) log_fatal ("Can't register I/O handle for %s: %s", tmp -> name, isc_result_totext (status)); #if defined(DHCPv6) /* Only register the first interface for V6, since they all * use the same socket. XXX: This has some messy side * effects if we start dynamically adding and removing * interfaces, but we're well beyond that point in terms of * mess. */ if (local_family == AF_INET6) break; #endif } /* for (tmp = interfaces; ... */ if (state == DISCOVER_SERVER && wifcount == 0) { log_info ("%s", ""); log_fatal ("Not configured to listen on any interfaces!"); } if ((local_family == AF_INET) && !setup_fallback) { setup_fallback = 1; maybe_setup_fallback(); } #if defined (F_SETFD) if (fallback_interface) { if (fcntl (fallback_interface -> rfdesc, F_SETFD, 1) < 0) log_error ("Can't set close-on-exec on fallback: %m"); if (fallback_interface -> rfdesc != fallback_interface -> wfdesc) { if (fcntl (fallback_interface -> wfdesc, F_SETFD, 1) < 0) log_error ("Can't set close-on-exec on fallback: %m"); } } #endif /* F_SETFD */ } int if_readsocket (h) omapi_object_t *h; { struct interface_info *ip; if (h -> type != dhcp_type_interface) return -1; ip = (struct interface_info *)h; return ip -> rfdesc; } int setup_fallback (struct interface_info **fp, const char *file, int line) { isc_result_t status; status = interface_allocate (&fallback_interface, file, line); if (status != ISC_R_SUCCESS) log_fatal ("Error allocating fallback interface: %s", isc_result_totext (status)); strcpy (fallback_interface -> name, "fallback"); if (dhcp_interface_setup_hook) (*dhcp_interface_setup_hook) (fallback_interface, (struct iaddr *)0); status = interface_reference (fp, fallback_interface, file, line); fallback_interface -> index = -1; interface_stash (fallback_interface); return status == ISC_R_SUCCESS; } void reinitialize_interfaces () { struct interface_info *ip; for (ip = interfaces; ip; ip = ip -> next) { if_reinitialize_receive (ip); if_reinitialize_send (ip); } if (fallback_interface) if_reinitialize_send (fallback_interface); interfaces_invalidated = 1; } isc_result_t got_one (h) omapi_object_t *h; { struct sockaddr_in from; struct hardware hfrom; struct iaddr ifrom; int result; union { unsigned char packbuf [4095]; /* Packet input buffer. Must be as large as largest possible MTU. */ struct dhcp_packet packet; } u; struct interface_info *ip; if (h -> type != dhcp_type_interface) return DHCP_R_INVALIDARG; ip = (struct interface_info *)h; again: if ((result = receive_packet (ip, u.packbuf, sizeof u, &from, &hfrom)) < 0) { log_error ("receive_packet failed on %s: %m", ip -> name); return ISC_R_UNEXPECTED; } if (result == 0) return ISC_R_UNEXPECTED; /* * If we didn't at least get the fixed portion of the BOOTP * packet, drop the packet. * Previously we allowed packets with no sname or filename * as we were aware of at least one client that did. But * a bug caused short packets to not work and nobody has * complained, it seems rational to tighten up that * restriction. */ if (result < DHCP_FIXED_NON_UDP) return ISC_R_UNEXPECTED; #if defined(IP_PKTINFO) && defined(IP_RECVPKTINFO) && defined(USE_V4_PKTINFO) { /* We retrieve the ifindex from the unused hfrom variable */ unsigned int ifindex; memcpy(&ifindex, hfrom.hbuf, sizeof (ifindex)); /* * Seek forward from the first interface to find the matching * source interface by interface index. */ ip = interfaces; while ((ip != NULL) && (if_nametoindex(ip->name) != ifindex)) ip = ip->next; if (ip == NULL) return ISC_R_NOTFOUND; } #endif if (bootp_packet_handler) { ifrom.len = 4; memcpy (ifrom.iabuf, &from.sin_addr, ifrom.len); (*bootp_packet_handler) (ip, &u.packet, (unsigned)result, from.sin_port, ifrom, &hfrom); } /* If there is buffered data, read again. This is for, e.g., bpf, which may return two packets at once. */ if (ip -> rbuf_offset != ip -> rbuf_len) goto again; return ISC_R_SUCCESS; } #ifdef DHCPv6 isc_result_t got_one_v6(omapi_object_t *h) { struct sockaddr_in6 from; struct in6_addr to; struct iaddr ifrom; int result; char buf[65536]; /* maximum size for a UDP packet is 65536 */ struct interface_info *ip; int is_unicast; unsigned int if_idx = 0; if (h->type != dhcp_type_interface) { return DHCP_R_INVALIDARG; } ip = (struct interface_info *)h; result = receive_packet6(ip, (unsigned char *)buf, sizeof(buf), &from, &to, &if_idx); if (result < 0) { log_error("receive_packet6() failed on %s: %m", ip->name); return ISC_R_UNEXPECTED; } /* 0 is 'any' interface. */ if (if_idx == 0) return ISC_R_NOTFOUND; if (dhcpv6_packet_handler != NULL) { /* * If a packet is not multicast, we assume it is unicast. */ if (IN6_IS_ADDR_MULTICAST(&to)) { is_unicast = ISC_FALSE; } else { is_unicast = ISC_TRUE; } ifrom.len = 16; memcpy(ifrom.iabuf, &from.sin6_addr, ifrom.len); /* Seek forward to find the matching source interface. */ ip = interfaces; while ((ip != NULL) && (if_nametoindex(ip->name) != if_idx)) ip = ip->next; if (ip == NULL) return ISC_R_NOTFOUND; (*dhcpv6_packet_handler)(ip, buf, result, from.sin6_port, &ifrom, is_unicast); } return ISC_R_SUCCESS; } #endif /* DHCPv6 */ isc_result_t dhcp_interface_set_value (omapi_object_t *h, omapi_object_t *id, omapi_data_string_t *name, omapi_typed_data_t *value) { struct interface_info *interface; isc_result_t status; if (h -> type != dhcp_type_interface) return DHCP_R_INVALIDARG; interface = (struct interface_info *)h; if (!omapi_ds_strcmp (name, "name")) { if ((value -> type == omapi_datatype_data || value -> type == omapi_datatype_string) && value -> u.buffer.len < sizeof interface -> name) { memcpy (interface -> name, value -> u.buffer.value, value -> u.buffer.len); interface -> name [value -> u.buffer.len] = 0; } else return DHCP_R_INVALIDARG; return ISC_R_SUCCESS; } /* Try to find some inner object that can take the value. */ if (h -> inner && h -> inner -> type -> set_value) { status = ((*(h -> inner -> type -> set_value)) (h -> inner, id, name, value)); if (status == ISC_R_SUCCESS || status == DHCP_R_UNCHANGED) return status; } return ISC_R_NOTFOUND; } isc_result_t dhcp_interface_get_value (omapi_object_t *h, omapi_object_t *id, omapi_data_string_t *name, omapi_value_t **value) { return ISC_R_NOTIMPLEMENTED; } isc_result_t dhcp_interface_destroy (omapi_object_t *h, const char *file, int line) { struct interface_info *interface; if (h -> type != dhcp_type_interface) return DHCP_R_INVALIDARG; interface = (struct interface_info *)h; if (interface -> ifp) { dfree (interface -> ifp, file, line); interface -> ifp = 0; } if (interface -> next) interface_dereference (&interface -> next, file, line); if (interface -> rbuf) { dfree (interface -> rbuf, file, line); interface -> rbuf = (unsigned char *)0; } if (interface -> client) interface -> client = (struct client_state *)0; if (interface -> shared_network) omapi_object_dereference ((omapi_object_t **) &interface -> shared_network, MDL); return ISC_R_SUCCESS; } isc_result_t dhcp_interface_signal_handler (omapi_object_t *h, const char *name, va_list ap) { struct interface_info *ip, *interface; isc_result_t status; if (h -> type != dhcp_type_interface) return DHCP_R_INVALIDARG; interface = (struct interface_info *)h; /* If it's an update signal, see if the interface is dead right now, or isn't known at all, and if that's the case, revive it. */ if (!strcmp (name, "update")) { for (ip = dummy_interfaces; ip; ip = ip -> next) if (ip == interface) break; if (ip && dhcp_interface_startup_hook) return (*dhcp_interface_startup_hook) (ip); for (ip = interfaces; ip; ip = ip -> next) if (ip == interface) break; if (!ip && dhcp_interface_startup_hook) return (*dhcp_interface_startup_hook) (ip); } /* Try to find some inner object that can take the value. */ if (h -> inner && h -> inner -> type -> signal_handler) { status = ((*(h -> inner -> type -> signal_handler)) (h -> inner, name, ap)); if (status == ISC_R_SUCCESS) return status; } return ISC_R_NOTFOUND; } isc_result_t dhcp_interface_stuff_values (omapi_object_t *c, omapi_object_t *id, omapi_object_t *h) { struct interface_info *interface; isc_result_t status; if (h -> type != dhcp_type_interface) return DHCP_R_INVALIDARG; interface = (struct interface_info *)h; /* Write out all the values. */ status = omapi_connection_put_name (c, "state"); if (status != ISC_R_SUCCESS) return status; if ((interface->flags & INTERFACE_REQUESTED) != 0) status = omapi_connection_put_string (c, "up"); else status = omapi_connection_put_string (c, "down"); if (status != ISC_R_SUCCESS) return status; /* Write out the inner object, if any. */ if (h -> inner && h -> inner -> type -> stuff_values) { status = ((*(h -> inner -> type -> stuff_values)) (c, id, h -> inner)); if (status == ISC_R_SUCCESS) return status; } return ISC_R_SUCCESS; } isc_result_t dhcp_interface_lookup (omapi_object_t **ip, omapi_object_t *id, omapi_object_t *ref) { omapi_value_t *tv = (omapi_value_t *)0; isc_result_t status; struct interface_info *interface; if (!ref) return DHCP_R_NOKEYS; /* First see if we were sent a handle. */ status = omapi_get_value_str (ref, id, "handle", &tv); if (status == ISC_R_SUCCESS) { status = omapi_handle_td_lookup (ip, tv -> value); omapi_value_dereference (&tv, MDL); if (status != ISC_R_SUCCESS) return status; /* Don't return the object if the type is wrong. */ if ((*ip) -> type != dhcp_type_interface) { omapi_object_dereference (ip, MDL); return DHCP_R_INVALIDARG; } } /* Now look for an interface name. */ status = omapi_get_value_str (ref, id, "name", &tv); if (status == ISC_R_SUCCESS) { char *s; unsigned len; for (interface = interfaces; interface; interface = interface -> next) { s = memchr (interface -> name, 0, IFNAMSIZ); if (s) len = s - &interface -> name [0]; else len = IFNAMSIZ; if ((tv -> value -> u.buffer.len == len && !memcmp (interface -> name, (char *)tv -> value -> u.buffer.value, len))) break; } if (!interface) { for (interface = dummy_interfaces; interface; interface = interface -> next) { s = memchr (interface -> name, 0, IFNAMSIZ); if (s) len = s - &interface -> name [0]; else len = IFNAMSIZ; if ((tv -> value -> u.buffer.len == len && !memcmp (interface -> name, (char *) tv -> value -> u.buffer.value, len))) break; } } omapi_value_dereference (&tv, MDL); if (*ip && *ip != (omapi_object_t *)interface) { omapi_object_dereference (ip, MDL); return DHCP_R_KEYCONFLICT; } else if (!interface) { if (*ip) omapi_object_dereference (ip, MDL); return ISC_R_NOTFOUND; } else if (!*ip) omapi_object_reference (ip, (omapi_object_t *)interface, MDL); } /* If we get to here without finding an interface, no valid key was specified. */ if (!*ip) return DHCP_R_NOKEYS; return ISC_R_SUCCESS; } /* actually just go discover the interface */ isc_result_t dhcp_interface_create (omapi_object_t **lp, omapi_object_t *id) { struct interface_info *hp; isc_result_t status; hp = (struct interface_info *)0; status = interface_allocate (&hp, MDL); if (status != ISC_R_SUCCESS) return status; hp -> flags = INTERFACE_REQUESTED; status = interface_reference ((struct interface_info **)lp, hp, MDL); interface_dereference (&hp, MDL); return status; } isc_result_t dhcp_interface_remove (omapi_object_t *lp, omapi_object_t *id) { struct interface_info *interface, *ip, *last; interface = (struct interface_info *)lp; /* remove from interfaces */ last = 0; for (ip = interfaces; ip; ip = ip -> next) { if (ip == interface) { if (last) { interface_dereference (&last -> next, MDL); if (ip -> next) interface_reference (&last -> next, ip -> next, MDL); } else { interface_dereference (&interfaces, MDL); if (ip -> next) interface_reference (&interfaces, ip -> next, MDL); } if (ip -> next) interface_dereference (&ip -> next, MDL); break; } last = ip; } if (!ip) return ISC_R_NOTFOUND; /* add the interface to the dummy_interface list */ if (dummy_interfaces) { interface_reference (&interface -> next, dummy_interfaces, MDL); interface_dereference (&dummy_interfaces, MDL); } interface_reference (&dummy_interfaces, interface, MDL); /* do a DHCPRELEASE */ if (dhcp_interface_shutdown_hook) (*dhcp_interface_shutdown_hook) (interface); /* remove the io object */ omapi_unregister_io_object ((omapi_object_t *)interface); switch(local_family) { #ifdef DHCPv6 case AF_INET6: if_deregister6(interface); break; #endif /* DHCPv6 */ case AF_INET: default: if_deregister_send(interface); if_deregister_receive(interface); break; } return ISC_R_SUCCESS; } void interface_stash (struct interface_info *tptr) { struct interface_info **vec; int delta; /* If the registerer didn't assign an index, assign one now. */ if (tptr -> index == -1) { tptr -> index = interface_count++; while (tptr -> index < interface_max && interface_vector [tptr -> index]) tptr -> index = interface_count++; } if (interface_max <= tptr -> index) { delta = tptr -> index - interface_max + 10; vec = dmalloc ((interface_max + delta) * sizeof (struct interface_info *), MDL); if (!vec) return; memset (&vec [interface_max], 0, (sizeof (struct interface_info *)) * delta); interface_max += delta; if (interface_vector) { memcpy (vec, interface_vector, (interface_count * sizeof (struct interface_info *))); dfree (interface_vector, MDL); } interface_vector = vec; } interface_reference (&interface_vector [tptr -> index], tptr, MDL); if (tptr -> index >= interface_count) interface_count = tptr -> index + 1; #if defined (TRACING) trace_interface_register (interface_trace, tptr); #endif } void interface_snorf (struct interface_info *tmp, int ir) { tmp -> circuit_id = (u_int8_t *)tmp -> name; tmp -> circuit_id_len = strlen (tmp -> name); tmp -> remote_id = 0; tmp -> remote_id_len = 0; tmp -> flags = ir; if (interfaces) { interface_reference (&tmp -> next, interfaces, MDL); interface_dereference (&interfaces, MDL); } interface_reference (&interfaces, tmp, MDL); } dhcp-4.2.4/common/dispatch.c000644 000765 000024 00000025366 11562515513 015642 0ustar00sarstaff000000 000000 /* dispatch.c Network input dispatcher... */ /* * Copyright (c) 2004-2011 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1995-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ * */ #include "dhcpd.h" #include struct timeout *timeouts; static struct timeout *free_timeouts; void set_time(TIME t) { /* Do any outstanding timeouts. */ if (cur_tv . tv_sec != t) { cur_tv . tv_sec = t; cur_tv . tv_usec = 0; process_outstanding_timeouts ((struct timeval *)0); } } struct timeval *process_outstanding_timeouts (struct timeval *tvp) { /* Call any expired timeouts, and then if there's still a timeout registered, time out the select call then. */ another: if (timeouts) { struct timeout *t; if ((timeouts -> when . tv_sec < cur_tv . tv_sec) || ((timeouts -> when . tv_sec == cur_tv . tv_sec) && (timeouts -> when . tv_usec <= cur_tv . tv_usec))) { t = timeouts; timeouts = timeouts -> next; (*(t -> func)) (t -> what); if (t -> unref) (*t -> unref) (&t -> what, MDL); t -> next = free_timeouts; free_timeouts = t; goto another; } if (tvp) { tvp -> tv_sec = timeouts -> when . tv_sec; tvp -> tv_usec = timeouts -> when . tv_usec; } return tvp; } else return (struct timeval *)0; } /* Wait for packets to come in using select(). When one does, call receive_packet to receive the packet and possibly strip hardware addressing information from it, and then call through the bootp_packet_handler hook to try to do something with it. */ /* * Use the DHCP timeout list as a place to store DHCP specific * information, but use the ISC timer system to actually dispatch * the events. * * There are several things that the DHCP timer code does that the * ISC code doesn't: * 1) It allows for negative times * 2) The cancel arguments are different. The DHCP code uses the * function and data to find the proper timer to cancel while the * ISC code uses a pointer to the timer. * 3) The DHCP code includes provision for incrementing and decrementing * a reference counter associated with the data. * The first one is fairly easy to fix but will take some time to go throuh * the callers and update them. The second is also not all that difficult * in concept - add a pointer to the appropriate structures to hold a pointer * to the timer and use that. The complications arise in trying to ensure * that all of the corner cases are covered. The last one is potentially * more painful and requires more investigation. * * The plan is continue with the older DHCP calls and timer list. The * calls will continue to manipulate the list but will also pass a * timer to the ISC timer code for the actual dispatch. Later, if desired, * we can go back and modify the underlying calls to use the ISC * timer functions directly without requiring all of the code to change * at the same time. */ void dispatch(void) { isc_result_t status; status = isc_app_ctxrun(dhcp_gbl_ctx.actx); log_fatal ("Dispatch routine failed: %s -- exiting", isc_result_totext (status)); } void isclib_timer_callback(isc_task_t *taskp, isc_event_t *eventp) { struct timeout *t = (struct timeout *)eventp->ev_arg; struct timeout *q, *r; /* Get the current time... */ gettimeofday (&cur_tv, (struct timezone *)0); /* * Find the timeout on the dhcp list and remove it. * As the list isn't ordered we search the entire list */ r = NULL; for (q = timeouts; q; q = q->next) { if (q == t) { if (r) r->next = q->next; else timeouts = q->next; break; } r = q; } /* * The timer should always be on the list. If it is we do * the work and detach the timer block, if not we log an error. * In both cases we attempt free the ISC event and continue * processing. */ if (q != NULL) { /* call the callback function */ (*(q->func)) (q->what); if (q->unref) { (*q->unref) (&q->what, MDL); } q->next = free_timeouts; isc_timer_detach(&q->isc_timeout); free_timeouts = q; } else { /* * Hmm, we should clean up the timer structure but aren't * sure about the pointer to the timer block we got so * don't try to - may change this to a log_fatal */ log_error("Error finding timer structure"); } isc_event_free(&eventp); return; } /* maximum value for usec */ #define USEC_MAX 1000000 #define DHCP_SEC_MAX 0xFFFFFFFF void add_timeout (when, where, what, ref, unref) struct timeval *when; void (*where) (void *); void *what; tvref_t ref; tvunref_t unref; { struct timeout *t, *q; int usereset = 0; isc_result_t status; int64_t sec; int usec; isc_interval_t interval; isc_time_t expires; /* See if this timeout supersedes an existing timeout. */ t = (struct timeout *)0; for (q = timeouts; q; q = q->next) { if ((where == NULL || q->func == where) && q->what == what) { if (t) t->next = q->next; else timeouts = q->next; usereset = 1; break; } t = q; } /* If we didn't supersede a timeout, allocate a timeout structure now. */ if (!q) { if (free_timeouts) { q = free_timeouts; free_timeouts = q->next; } else { q = ((struct timeout *) dmalloc(sizeof(struct timeout), MDL)); if (!q) { log_fatal("add_timeout: no memory!"); } } memset(q, 0, sizeof *q); q->func = where; q->ref = ref; q->unref = unref; if (q->ref) (*q->ref)(&q->what, what, MDL); else q->what = what; } /* * The value passed in is a time from an epoch but we need a relative * time so we need to do some math to try and recover the period. * This is complicated by the fact that not all of the calls cared * about the usec value, if it's zero we assume the caller didn't care. * * The ISC timer library doesn't seem to like negative values * and can't accept any values above 4G-1 seconds so we limit * the values to 0 <= value < 4G-1. We do it before * checking the trace option so that both the trace code and * the working code use the same values. */ sec = when->tv_sec - cur_tv.tv_sec; usec = when->tv_usec - cur_tv.tv_usec; if ((when->tv_usec != 0) && (usec < 0)) { sec--; usec += USEC_MAX; } if (sec < 0) { sec = 0; usec = 0; } else if (sec > DHCP_SEC_MAX) { log_error("Timeout requested too large " "reducing to 2^^32-1"); sec = DHCP_SEC_MAX; usec = 0; } else if (usec < 0) { usec = 0; } else if (usec >= USEC_MAX) { usec = USEC_MAX - 1; } /* * This is necessary for the tracing code but we put it * here in case we want to compare timing information * for some reason, like debugging. */ q->when.tv_sec = cur_tv.tv_sec + (sec & DHCP_SEC_MAX); q->when.tv_usec = usec; #if defined (TRACING) if (trace_playback()) { /* * If we are doing playback we need to handle the timers * within this code rather than having the isclib handle * them for us. We need to keep the timer list in order * to allow us to find the ones to timeout. * * By using a different timer setup in the playback we may * have variations between the orginal and the playback but * it's the best we can do for now. */ /* Beginning of list? */ if (!timeouts || (timeouts->when.tv_sec > q-> when.tv_sec) || ((timeouts->when.tv_sec == q->when.tv_sec) && (timeouts->when.tv_usec > q->when.tv_usec))) { q->next = timeouts; timeouts = q; return; } /* Middle of list? */ for (t = timeouts; t->next; t = t->next) { if ((t->next->when.tv_sec > q->when.tv_sec) || ((t->next->when.tv_sec == q->when.tv_sec) && (t->next->when.tv_usec > q->when.tv_usec))) { q->next = t->next; t->next = q; return; } } /* End of list. */ t->next = q; q->next = (struct timeout *)0; return; } #endif /* * Don't bother sorting the DHCP list, just add it to the front. * Eventually the list should be removed as we migrate the callers * to the native ISC timer functions, if it becomes a performance * problem before then we may need to order the list. */ q->next = timeouts; timeouts = q; isc_interval_set(&interval, sec & DHCP_SEC_MAX, usec * 1000); status = isc_time_nowplusinterval(&expires, &interval); if (status != ISC_R_SUCCESS) { /* * The system time function isn't happy or returned * a value larger than isc_time_t can hold. */ log_fatal("Unable to set up timer: %s", isc_result_totext(status)); } if (usereset == 0) { status = isc_timer_create(dhcp_gbl_ctx.timermgr, isc_timertype_once, &expires, NULL, dhcp_gbl_ctx.task, isclib_timer_callback, (void *)q, &q->isc_timeout); } else { status = isc_timer_reset(q->isc_timeout, isc_timertype_once, &expires, NULL, 0); } /* If it fails log an error and die */ if (status != ISC_R_SUCCESS) { log_fatal("Unable to add timeout to isclib\n"); } return; } void cancel_timeout (where, what) void (*where) (void *); void *what; { struct timeout *t, *q; /* Look for this timeout on the list, and unlink it if we find it. */ t = (struct timeout *)0; for (q = timeouts; q; q = q -> next) { if (q->func == where && q->what == what) { if (t) t->next = q->next; else timeouts = q->next; break; } t = q; } /* * If we found the timeout, cancel it and put it on the free list. * The TRACING stuff is ugly but we don't add a timer when doing * playback so we don't want to remove them then either. */ if (q) { #if defined (TRACING) if (!trace_playback()) { #endif isc_timer_detach(&q->isc_timeout); #if defined (TRACING) } #endif if (q->unref) (*q->unref) (&q->what, MDL); q->next = free_timeouts; free_timeouts = q; } } #if defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT) void cancel_all_timeouts () { struct timeout *t, *n; for (t = timeouts; t; t = n) { n = t->next; isc_timer_detach(&t->isc_timeout); if (t->unref && t->what) (*t->unref) (&t->what, MDL); t->next = free_timeouts; free_timeouts = t; } } void relinquish_timeouts () { struct timeout *t, *n; for (t = free_timeouts; t; t = n) { n = t->next; dfree(t, MDL); } } #endif dhcp-4.2.4/common/dlpi.c000644 000765 000024 00000107576 11562515513 014777 0ustar00sarstaff000000 000000 /* dlpi.c Data Link Provider Interface (DLPI) network interface code. */ /* * Copyright (c) 2009-2011 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 2004,2007 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1996-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ * * This software was written for Internet Systems Consortium * by Eric James Negaard, . To learn more about * Internet Systems Consortium, see ``https://www.isc.org''. * * Joost Mulders has also done considerable work in debugging the DLPI API * support on Solaris and getting this code to work properly on a variety * of different Solaris platforms. */ /* * Based largely in part to the existing NIT code in nit.c. * * This code has been developed and tested on sparc-based machines running * SunOS 5.5.1, with le and hme network interfaces. It should be pretty * generic, though. */ /* * Implementation notes: * * I first tried to write this code to the "vanilla" DLPI 2.0 API. * It worked on a Sun Ultra-1 with a hme interface, but didn't work * on Sun SparcStation 5's with "le" interfaces (the packets sent out * via dlpiunitdatareq contained an Ethernet type of 0x0000 instead * of the expected 0x0800). * * Therefore I added the "DLPI_RAW" code which is a Sun extension to * the DLPI standard. This code works on both of the above machines. * This is configurable in the OS-dependent include file by defining * USE_DLPI_RAW. * * It quickly became apparant that I should also use the "pfmod" * STREAMS module to cut down on the amount of user level packet * processing. I don't know how widely available "pfmod" is, so it's * use is conditionally included. This is configurable in the * OS-dependent include file by defining USE_DLPI_PFMOD. * * A major quirk on the Sun's at least, is that no packets seem to get * sent out the interface until six seconds after the interface is * first "attached" to [per system reboot] (it's actually from when * the interface is attached, not when it is plumbed, so putting a * sleep into the dhclient-script at PREINIT time doesn't help). I * HAVE tried, without success to poll the fd to see when it is ready * for writing. This doesn't help at all. If the sleeps are not done, * the initial DHCPREQUEST or DHCPDISCOVER never gets sent out, so * I've put them here, when register_send and register_receive are * called (split up into two three-second sleeps between the notices, * so that it doesn't seem like so long when you're watching :-). The * amount of time to sleep is configurable in the OS-dependent include * file by defining DLPI_FIRST_SEND_WAIT to be the number of seconds * to sleep. */ /* * The Open Group Technical Standard can be found here: * http://www.opengroup.org/onlinepubs/009618899/index.htm * * The HP DLPI Programmer's Guide can be found here: * http://docs.hp.com/en/B2355-90139/index.html */ #include "dhcpd.h" #if defined (USE_DLPI_SEND) || defined (USE_DLPI_RECEIVE) || \ defined(USE_DLPI_HWADDR) # include # include # include # include # ifdef USE_DLPI_PFMOD # include # endif #include #include # include # include "includes/netinet/ip.h" # include "includes/netinet/udp.h" # include "includes/netinet/if_ether.h" # ifdef USE_DLPI_PFMOD # ifdef USE_DLPI_RAW # define DLPI_MODNAME "DLPI+RAW+PFMOD" # else # define DLPI_MODNAME "DLPI+PFMOD" # endif # else # ifdef USE_DLPI_RAW # define DLPI_MODNAME "DLPI+RAW" # else # define DLPI_MODNAME "DLPI" # endif # endif # ifndef ABS # define ABS(x) ((x) >= 0 ? (x) : 0-(x)) # endif #if defined(USE_DLPI_PFMOD) || defined(USE_DLPI_RAW) static int strioctl (int fd, int cmd, int timeout, int len, char *dp); #endif #define DLPI_MAXDLBUF 8192 /* Buffer size */ #define DLPI_MAXDLADDR 1024 /* Max address size */ #define DLPI_DEVDIR "/dev/" /* Device directory */ static int dlpiopen(const char *ifname); static int dlpiunit (char *ifname); static int dlpiinforeq (int fd); static int dlpiphysaddrreq (int fd, unsigned long addrtype); static int dlpiattachreq (int fd, unsigned long ppa); static int dlpibindreq (int fd, unsigned long sap, unsigned long max_conind, unsigned long service_mode, unsigned long conn_mgmt, unsigned long xidtest); #if defined(UNUSED_DLPI_INTERFACE) /* These functions are unused at present, but may be used at a later date. * defined out to avoid compiler warnings about unused static functions. */ static int dlpidetachreq (int fd); static int dlpiunbindreq (int fd); #endif static int dlpiokack (int fd, char *bufp); static int dlpiinfoack (int fd, char *bufp); static int dlpiphysaddrack (int fd, char *bufp); static int dlpibindack (int fd, char *bufp); #if defined(USE_DLPI_SEND) || defined(USE_DLPI_RECEIVE) /* These functions are not used if we're only sourcing the get_hw_addr() * function (for USE_SOCKETS). */ static int dlpiunitdatareq (int fd, unsigned char *addr, int addrlen, unsigned long minpri, unsigned long maxpri, unsigned char *data, int datalen); static int dlpiunitdataind (int fd, unsigned char *dstaddr, unsigned long *dstaddrlen, unsigned char *srcaddr, unsigned long *srcaddrlen, unsigned long *grpaddr, unsigned char *data, int datalen); #endif /* !USE_DLPI_HWADDR: USE_DLPI_SEND || USE_DLPI_RECEIVE */ static int expected (unsigned long prim, union DL_primitives *dlp, int msgflags); static int strgetmsg (int fd, struct strbuf *ctlp, struct strbuf *datap, int *flagsp, char *caller); /* Reinitializes the specified interface after an address change. This is not required for packet-filter APIs. */ #ifdef USE_DLPI_SEND void if_reinitialize_send (info) struct interface_info *info; { } #endif #ifdef USE_DLPI_RECEIVE void if_reinitialize_receive (info) struct interface_info *info; { } #endif /* Called by get_interface_list for each interface that's discovered. Opens a packet filter for each interface and adds it to the select mask. */ int if_register_dlpi (info) struct interface_info *info; { int sock; int unit; long buf [DLPI_MAXDLBUF]; union DL_primitives *dlp; dlp = (union DL_primitives *)buf; /* Open a DLPI device */ if ((sock = dlpiopen (info -> name)) < 0) { log_fatal ("Can't open DLPI device for %s: %m", info -> name); } /* * Submit a DL_INFO_REQ request, to find the dl_mac_type and * dl_provider_style */ if (dlpiinforeq(sock) < 0 || dlpiinfoack(sock, (char *)buf) < 0) { log_fatal ("Can't get DLPI MAC type for %s: %m", info -> name); } else { switch (dlp -> info_ack.dl_mac_type) { case DL_CSMACD: /* IEEE 802.3 */ case DL_ETHER: info -> hw_address.hbuf [0] = HTYPE_ETHER; break; /* adding token ring 5/1999 - mayer@ping.at */ case DL_TPR: info -> hw_address.hbuf [0] = HTYPE_IEEE802; break; case DL_FDDI: info -> hw_address.hbuf [0] = HTYPE_FDDI; break; default: log_fatal("%s: unsupported DLPI MAC type %lu", info->name, (unsigned long)dlp->info_ack.dl_mac_type); break; } /* * copy the sap length and broadcast address of this interface * to interface_info. This fixes nothing but seemed nicer than to * assume -2 and ffffff. */ info -> dlpi_sap_length = dlp -> info_ack.dl_sap_length; info -> dlpi_broadcast_addr.hlen = dlp -> info_ack.dl_brdcst_addr_length; memcpy (info -> dlpi_broadcast_addr.hbuf, (char *)dlp + dlp -> info_ack.dl_brdcst_addr_offset, dlp -> info_ack.dl_brdcst_addr_length); } if (dlp -> info_ack.dl_provider_style == DL_STYLE2) { /* * Attach to the device. If this fails, the device * does not exist. */ unit = dlpiunit (info -> name); if (dlpiattachreq (sock, unit) < 0 || dlpiokack (sock, (char *)buf) < 0) { log_fatal ("Can't attach DLPI device for %s: %m", info -> name); } } /* * Bind to the IP service access point (SAP), connectionless (CLDLS). */ if (dlpibindreq (sock, ETHERTYPE_IP, 0, DL_CLDLS, 0, 0) < 0 || dlpibindack (sock, (char *)buf) < 0) { log_fatal ("Can't bind DLPI device for %s: %m", info -> name); } /* * Submit a DL_PHYS_ADDR_REQ request, to find * the hardware address */ if (dlpiphysaddrreq (sock, DL_CURR_PHYS_ADDR) < 0 || dlpiphysaddrack (sock, (char *)buf) < 0) { log_fatal ("Can't get DLPI hardware address for %s: %m", info -> name); } info -> hw_address.hlen = dlp -> physaddr_ack.dl_addr_length + 1; memcpy (&info -> hw_address.hbuf [1], (char *)buf + dlp -> physaddr_ack.dl_addr_offset, dlp -> physaddr_ack.dl_addr_length); #ifdef USE_DLPI_RAW if (strioctl (sock, DLIOCRAW, INFTIM, 0, 0) < 0) { log_fatal ("Can't set DLPI RAW mode for %s: %m", info -> name); } #endif #ifdef USE_DLPI_PFMOD if (ioctl (sock, I_PUSH, "pfmod") < 0) { log_fatal ("Can't push packet filter onto DLPI for %s: %m", info -> name); } #endif return sock; } #if defined(USE_DLPI_PFMOD) || defined(USE_DLPI_RAW) static int strioctl (fd, cmd, timeout, len, dp) int fd; int cmd; int timeout; int len; char *dp; { struct strioctl sio; int rslt; sio.ic_cmd = cmd; sio.ic_timout = timeout; sio.ic_len = len; sio.ic_dp = dp; if ((rslt = ioctl (fd, I_STR, &sio)) < 0) { return rslt; } else { return sio.ic_len; } } #endif /* USE_DPI_PFMOD || USE_DLPI_RAW */ #ifdef USE_DLPI_SEND void if_register_send (info) struct interface_info *info; { /* If we're using the DLPI API for sending and receiving, we don't need to register this interface twice. */ #ifndef USE_DLPI_RECEIVE # ifdef USE_DLPI_PFMOD struct packetfilt pf; # endif info -> wfdesc = if_register_dlpi (info); # ifdef USE_DLPI_PFMOD /* Set up an PFMOD filter that rejects everything... */ pf.Pf_Priority = 0; pf.Pf_FilterLen = 1; pf.Pf_Filter [0] = ENF_PUSHZERO; /* Install the filter */ if (strioctl (info -> wfdesc, PFIOCSETF, INFTIM, sizeof (pf), (char *)&pf) < 0) { log_fatal ("Can't set PFMOD send filter on %s: %m", info -> name); } # endif /* USE_DLPI_PFMOD */ #else /* !defined (USE_DLPI_RECEIVE) */ /* * If using DLPI for both send and receive, simply re-use * the read file descriptor that was set up earlier. */ info -> wfdesc = info -> rfdesc; #endif if (!quiet_interface_discovery) log_info ("Sending on DLPI/%s/%s%s%s", info -> name, print_hw_addr (info -> hw_address.hbuf [0], info -> hw_address.hlen - 1, &info -> hw_address.hbuf [1]), (info -> shared_network ? "/" : ""), (info -> shared_network ? info -> shared_network -> name : "")); #ifdef DLPI_FIRST_SEND_WAIT /* See the implementation notes at the beginning of this file */ # ifdef USE_DLPI_RECEIVE sleep (DLPI_FIRST_SEND_WAIT - (DLPI_FIRST_SEND_WAIT / 2)); # else sleep (DLPI_FIRST_SEND_WAIT); # endif #endif } void if_deregister_send (info) struct interface_info *info; { /* If we're using the DLPI API for sending and receiving, we don't need to register this interface twice. */ #ifndef USE_DLPI_RECEIVE close (info -> wfdesc); #endif info -> wfdesc = -1; if (!quiet_interface_discovery) log_info ("Disabling output on DLPI/%s/%s%s%s", info -> name, print_hw_addr (info -> hw_address.hbuf [0], info -> hw_address.hlen - 1, &info -> hw_address.hbuf [1]), (info -> shared_network ? "/" : ""), (info -> shared_network ? info -> shared_network -> name : "")); } #endif /* USE_DLPI_SEND */ #ifdef USE_DLPI_RECEIVE /* Packet filter program... XXX Changes to the filter program may require changes to the constant offsets used in if_register_send to patch the NIT program! XXX */ void if_register_receive (info) struct interface_info *info; { #ifdef USE_DLPI_PFMOD struct packetfilt pf; struct ip iphdr; u_int16_t offset; #endif /* Open a DLPI device and hang it on this interface... */ info -> rfdesc = if_register_dlpi (info); #ifdef USE_DLPI_PFMOD /* Set up the PFMOD filter program. */ /* XXX Unlike the BPF filter program, this one won't work if the XXX IP packet is fragmented or if there are options on the IP XXX header. */ pf.Pf_Priority = 0; pf.Pf_FilterLen = 0; #if defined (USE_DLPI_RAW) # define ETHER_H_PREFIX (14) /* sizeof (ethernet_header) */ /* * ethertype == ETHERTYPE_IP */ offset = 12; pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHWORD + (offset / 2); pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHLIT | ENF_CAND; pf.Pf_Filter [pf.Pf_FilterLen++] = htons (ETHERTYPE_IP); # else # define ETHER_H_PREFIX (0) # endif /* USE_DLPI_RAW */ /* * The packets that will be received on this file descriptor * will be IP packets (due to the SAP that was specified in * the dlbind call). There will be no ethernet header. * Therefore, setup the packet filter to check the protocol * field for UDP, and the destination port number equal * to the local port. All offsets are relative to the start * of an IP packet. */ /* * BOOTPS destination port */ offset = ETHER_H_PREFIX + sizeof (iphdr) + sizeof (u_int16_t); pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHWORD + (offset / 2); pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHLIT | ENF_CAND; pf.Pf_Filter [pf.Pf_FilterLen++] = local_port; /* * protocol should be udp. this is a byte compare, test for * endianess. */ offset = ETHER_H_PREFIX + ((u_int8_t *)&(iphdr.ip_p) - (u_int8_t *)&iphdr); pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHWORD + (offset / 2); pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHLIT | ENF_AND; pf.Pf_Filter [pf.Pf_FilterLen++] = htons (0x00FF); pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHLIT | ENF_CAND; pf.Pf_Filter [pf.Pf_FilterLen++] = htons (IPPROTO_UDP); /* Install the filter... */ if (strioctl (info -> rfdesc, PFIOCSETF, INFTIM, sizeof (pf), (char *)&pf) < 0) { log_fatal ("Can't set PFMOD receive filter on %s: %m", info -> name); } #endif /* USE_DLPI_PFMOD */ if (!quiet_interface_discovery) log_info ("Listening on DLPI/%s/%s%s%s", info -> name, print_hw_addr (info -> hw_address.hbuf [0], info -> hw_address.hlen - 1, &info -> hw_address.hbuf [1]), (info -> shared_network ? "/" : ""), (info -> shared_network ? info -> shared_network -> name : "")); #ifdef DLPI_FIRST_SEND_WAIT /* See the implementation notes at the beginning of this file */ # ifdef USE_DLPI_SEND sleep (DLPI_FIRST_SEND_WAIT / 2); # else sleep (DLPI_FIRST_SEND_WAIT); # endif #endif } void if_deregister_receive (info) struct interface_info *info; { /* If we're using the DLPI API for sending and receiving, we don't need to register this interface twice. */ #ifndef USE_DLPI_SEND close (info -> rfdesc); #endif info -> rfdesc = -1; if (!quiet_interface_discovery) log_info ("Disabling input on DLPI/%s/%s%s%s", info -> name, print_hw_addr (info -> hw_address.hbuf [0], info -> hw_address.hlen - 1, &info -> hw_address.hbuf [1]), (info -> shared_network ? "/" : ""), (info -> shared_network ? info -> shared_network -> name : "")); } #endif /* USE_DLPI_RECEIVE */ #ifdef USE_DLPI_SEND ssize_t send_packet (interface, packet, raw, len, from, to, hto) struct interface_info *interface; struct packet *packet; struct dhcp_packet *raw; size_t len; struct in_addr from; struct sockaddr_in *to; struct hardware *hto; { #ifdef USE_DLPI_RAW double hh [32]; #endif double ih [1536 / sizeof (double)]; unsigned char *dbuf = (unsigned char *)ih; unsigned dbuflen; unsigned char dstaddr [DLPI_MAXDLADDR]; unsigned addrlen; int result; int fudge; if (!strcmp (interface -> name, "fallback")) return send_fallback (interface, packet, raw, len, from, to, hto); if (hto == NULL && interface->anycast_mac_addr.hlen) hto = &interface->anycast_mac_addr; dbuflen = 0; /* Assemble the headers... */ #ifdef USE_DLPI_RAW assemble_hw_header (interface, (unsigned char *)hh, &dbuflen, hto); if (dbuflen > sizeof hh) log_fatal ("send_packet: hh buffer too small.\n"); fudge = dbuflen % 4; /* IP header must be word-aligned. */ memcpy (dbuf + fudge, (unsigned char *)hh, dbuflen); dbuflen += fudge; #else fudge = 0; #endif assemble_udp_ip_header (interface, dbuf, &dbuflen, from.s_addr, to -> sin_addr.s_addr, to -> sin_port, (unsigned char *)raw, len); /* Copy the data into the buffer (yuk). */ memcpy (dbuf + dbuflen, raw, len); dbuflen += len; #ifdef USE_DLPI_RAW result = write (interface -> wfdesc, dbuf + fudge, dbuflen - fudge); #else /* * Setup the destination address (DLSAP) in dstaddr * * If sap_length < 0 we must deliver the DLSAP as phys+sap. * If sap_length > 0 we must deliver the DLSAP as sap+phys. * * sap = Service Access Point == ETHERTYPE_IP * sap + datalink address is called DLSAP in dlpi speak. */ { /* ENCODE DLSAP */ unsigned char phys [DLPI_MAXDLADDR]; unsigned char sap [4]; int sap_len = interface -> dlpi_sap_length; int phys_len = interface -> hw_address.hlen - 1; /* sap = htons (ETHERTYPE_IP) kludge */ memset (sap, 0, sizeof (sap)); # if (BYTE_ORDER == LITTLE_ENDIAN) sap [0] = 0x00; sap [1] = 0x08; # else sap [0] = 0x08; sap [1] = 0x00; # endif if (hto && hto -> hlen == interface -> hw_address.hlen) memcpy ( phys, (char *) &hto -> hbuf [1], phys_len); else memcpy ( phys, interface -> dlpi_broadcast_addr.hbuf, interface -> dlpi_broadcast_addr.hlen); if (sap_len < 0) { memcpy ( dstaddr, phys, phys_len); memcpy ( (char *) &dstaddr [phys_len], sap, ABS (sap_len)); } else { memcpy ( dstaddr, (void *) sap, sap_len); memcpy ( (char *) &dstaddr [sap_len], phys, phys_len); } addrlen = phys_len + ABS (sap_len); } /* ENCODE DLSAP */ result = dlpiunitdatareq (interface -> wfdesc, dstaddr, addrlen, 0, 0, dbuf, dbuflen); #endif /* USE_DLPI_RAW */ if (result < 0) log_error ("send_packet: %m"); return result; } #endif /* USE_DLPI_SEND */ #ifdef USE_DLPI_RECEIVE ssize_t receive_packet (interface, buf, len, from, hfrom) struct interface_info *interface; unsigned char *buf; size_t len; struct sockaddr_in *from; struct hardware *hfrom; { unsigned char dbuf [1536]; unsigned char srcaddr [DLPI_MAXDLADDR]; unsigned long srcaddrlen; int length = 0; int offset = 0; int bufix = 0; unsigned paylen; #ifdef USE_DLPI_RAW length = read (interface -> rfdesc, dbuf, sizeof (dbuf)); #else length = dlpiunitdataind (interface -> rfdesc, (unsigned char *)NULL, (unsigned long *)NULL, srcaddr, &srcaddrlen, (unsigned long *)NULL, dbuf, sizeof (dbuf)); #endif if (length <= 0) { log_error("receive_packet: %m"); return length; } # if !defined (USE_DLPI_RAW) /* * Copy the sender's hw address into hfrom * If sap_len < 0 the DLSAP is as phys+sap. * If sap_len > 0 the DLSAP is as sap+phys. * * sap is discarded here. */ { /* DECODE DLSAP */ int sap_len = interface -> dlpi_sap_length; int phys_len = interface -> hw_address.hlen - 1; if (hfrom && (srcaddrlen == ABS (sap_len) + phys_len )) { hfrom -> hbuf [0] = interface -> hw_address.hbuf [0]; hfrom -> hlen = interface -> hw_address.hlen; if (sap_len < 0) { memcpy ((char *) &hfrom -> hbuf [1], srcaddr, phys_len); } else { memcpy((char *)&hfrom->hbuf[1], srcaddr + sap_len, phys_len); } } else if (hfrom) { memset (hfrom, '\0', sizeof *hfrom); } } /* DECODE_DLSAP */ # endif /* !defined (USE_DLPI_RAW) */ /* Decode the IP and UDP headers... */ bufix = 0; #ifdef USE_DLPI_RAW /* Decode the physical header... */ offset = decode_hw_header (interface, dbuf, bufix, hfrom); /* If a physical layer checksum failed (dunno of any physical layer that supports this, but WTH), skip this packet. */ if (offset < 0) { return 0; } bufix += offset; length -= offset; #endif offset = decode_udp_ip_header (interface, dbuf, bufix, from, length, &paylen); /* * If the IP or UDP checksum was bad, skip the packet... * * Note: this happens all the time when writing packets via the * fallback socket. The packet received by streams does not have * the IP or UDP checksums filled in, as those are calculated by * the hardware. */ if (offset < 0) { return 0; } bufix += offset; length -= offset; if (length < paylen) log_fatal("Internal inconsistency at %s:%d.", MDL); /* Copy out the data in the packet... */ memcpy(buf, &dbuf [bufix], paylen); return paylen; } #endif /* Common DLPI routines ... * * Written by Eric James Negaard, * * Based largely in part to the example code contained in the document * "How to Use the STREAMS Data Link Provider Interface (DLPI)", written * by Neal Nuckolls of SunSoft Internet Engineering. * * This code has been developed and tested on sparc-based machines running * SunOS 5.5.1, with le and hme network interfaces. It should be pretty * generic, though. * * The usual disclaimers apply. This code works for me. Don't blame me * if it makes your machine or network go down in flames. That taken * into consideration, use this code as you wish. If you make usefull * modifications I'd appreciate hearing about it. */ #define DLPI_MAXWAIT 15 /* Max timeout */ /* * Parse an interface name and extract the unit number */ static int dlpiunit (ifname) char *ifname; { char *cp; int unit; if (!ifname) { return 0; } /* Advance to the end of the name */ cp = ifname; while (*cp) cp++; /* Back up to the start of the first digit */ while ((*(cp-1) >= '0' && *(cp-1) <= '9') || *(cp - 1) == ':') cp--; /* Convert the unit number */ unit = 0; while (*cp >= '0' && *cp <= '9') { unit *= 10; unit += (*cp++ - '0'); } return unit; } /* * dlpiopen - open the DLPI device for a given interface name */ static int dlpiopen(const char *ifname) { char devname [50]; char *dp; const char *cp, *ep; if (!ifname) { return -1; } /* Open a DLPI device */ if (*ifname == '/') { dp = devname; } else { /* Prepend the device directory */ memcpy (devname, DLPI_DEVDIR, strlen (DLPI_DEVDIR)); dp = &devname [strlen (DLPI_DEVDIR)]; } /* Find the end of the interface name */ ep = cp = ifname; while (*ep) ep++; /* And back up to the first digit (unit number) */ while ((*(ep - 1) >= '0' && *(ep - 1) <= '9') || *(ep - 1) == ':') ep--; /* Copy everything up to the unit number */ while (cp < ep) { *dp++ = *cp++; } *dp = '\0'; return open (devname, O_RDWR, 0); } /* * dlpiinforeq - request information about the data link provider. */ static int dlpiinforeq (fd) int fd; { dl_info_req_t info_req; struct strbuf ctl; int flags; info_req.dl_primitive = DL_INFO_REQ; ctl.maxlen = 0; ctl.len = sizeof (info_req); ctl.buf = (char *)&info_req; flags = RS_HIPRI; return putmsg (fd, &ctl, (struct strbuf *)NULL, flags); } /* * dlpiphysaddrreq - request the current physical address. */ static int dlpiphysaddrreq (fd, addrtype) int fd; unsigned long addrtype; { dl_phys_addr_req_t physaddr_req; struct strbuf ctl; int flags; physaddr_req.dl_primitive = DL_PHYS_ADDR_REQ; physaddr_req.dl_addr_type = addrtype; ctl.maxlen = 0; ctl.len = sizeof (physaddr_req); ctl.buf = (char *)&physaddr_req; flags = RS_HIPRI; return putmsg (fd, &ctl, (struct strbuf *)NULL, flags); } /* * dlpiattachreq - send a request to attach to a specific unit. */ static int dlpiattachreq (fd, ppa) unsigned long ppa; int fd; { dl_attach_req_t attach_req; struct strbuf ctl; int flags; attach_req.dl_primitive = DL_ATTACH_REQ; attach_req.dl_ppa = ppa; ctl.maxlen = 0; ctl.len = sizeof (attach_req); ctl.buf = (char *)&attach_req; flags = 0; return putmsg (fd, &ctl, (struct strbuf*)NULL, flags); } /* * dlpibindreq - send a request to bind to a specific SAP address. */ static int dlpibindreq (fd, sap, max_conind, service_mode, conn_mgmt, xidtest) unsigned long sap; unsigned long max_conind; unsigned long service_mode; unsigned long conn_mgmt; unsigned long xidtest; int fd; { dl_bind_req_t bind_req; struct strbuf ctl; int flags; bind_req.dl_primitive = DL_BIND_REQ; bind_req.dl_sap = sap; bind_req.dl_max_conind = max_conind; bind_req.dl_service_mode = service_mode; bind_req.dl_conn_mgmt = conn_mgmt; bind_req.dl_xidtest_flg = xidtest; ctl.maxlen = 0; ctl.len = sizeof (bind_req); ctl.buf = (char *)&bind_req; flags = 0; return putmsg (fd, &ctl, (struct strbuf*)NULL, flags); } #if defined(UNUSED_DLPI_INTERFACE) /* * dlpiunbindreq - send a request to unbind. This function is not actually * used by ISC DHCP, but is included for completeness in case it is * ever required for new work. */ static int dlpiunbindreq (fd) int fd; { dl_unbind_req_t unbind_req; struct strbuf ctl; int flags; unbind_req.dl_primitive = DL_UNBIND_REQ; ctl.maxlen = 0; ctl.len = sizeof (unbind_req); ctl.buf = (char *)&unbind_req; flags = 0; return putmsg (fd, &ctl, (struct strbuf*)NULL, flags); } /* * dlpidetachreq - send a request to detach. This function is not actually * used by ISC DHCP, but is included for completeness in case it is * ever required for new work. */ static int dlpidetachreq (fd) int fd; { dl_detach_req_t detach_req; struct strbuf ctl; int flags; detach_req.dl_primitive = DL_DETACH_REQ; ctl.maxlen = 0; ctl.len = sizeof (detach_req); ctl.buf = (char *)&detach_req; flags = 0; return putmsg (fd, &ctl, (struct strbuf*)NULL, flags); } #endif /* UNUSED_DLPI_INTERFACE */ /* * dlpibindack - receive an ack to a dlbindreq. */ static int dlpibindack (fd, bufp) char *bufp; int fd; { union DL_primitives *dlp; struct strbuf ctl; int flags; ctl.maxlen = DLPI_MAXDLBUF; ctl.len = 0; ctl.buf = bufp; if (strgetmsg (fd, &ctl, (struct strbuf*)NULL, &flags, "dlpibindack") < 0) { return -1; } dlp = (union DL_primitives *)ctl.buf; if (expected (DL_BIND_ACK, dlp, flags) == -1) { return -1; } if (ctl.len < sizeof (dl_bind_ack_t)) { /* Returned structure is too short */ return -1; } return 0; } /* * dlpiokack - general acknowledgement reception. */ static int dlpiokack (fd, bufp) char *bufp; int fd; { union DL_primitives *dlp; struct strbuf ctl; int flags; ctl.maxlen = DLPI_MAXDLBUF; ctl.len = 0; ctl.buf = bufp; if (strgetmsg (fd, &ctl, (struct strbuf*)NULL, &flags, "dlpiokack") < 0) { return -1; } dlp = (union DL_primitives *)ctl.buf; if (expected (DL_OK_ACK, dlp, flags) == -1) { return -1; } if (ctl.len < sizeof (dl_ok_ack_t)) { /* Returned structure is too short */ return -1; } return 0; } /* * dlpiinfoack - receive an ack to a dlinforeq. */ static int dlpiinfoack (fd, bufp) char *bufp; int fd; { union DL_primitives *dlp; struct strbuf ctl; int flags; ctl.maxlen = DLPI_MAXDLBUF; ctl.len = 0; ctl.buf = bufp; if (strgetmsg (fd, &ctl, (struct strbuf *)NULL, &flags, "dlpiinfoack") < 0) { return -1; } dlp = (union DL_primitives *) ctl.buf; if (expected (DL_INFO_ACK, dlp, flags) == -1) { return -1; } if (ctl.len < sizeof (dl_info_ack_t)) { /* Returned structure is too short */ return -1; } return 0; } /* * dlpiphysaddrack - receive an ack to a dlpiphysaddrreq. */ int dlpiphysaddrack (fd, bufp) char *bufp; int fd; { union DL_primitives *dlp; struct strbuf ctl; int flags; ctl.maxlen = DLPI_MAXDLBUF; ctl.len = 0; ctl.buf = bufp; if (strgetmsg (fd, &ctl, (struct strbuf *)NULL, &flags, "dlpiphysaddrack") < 0) { return -1; } dlp = (union DL_primitives *)ctl.buf; if (expected (DL_PHYS_ADDR_ACK, dlp, flags) == -1) { return -1; } if (ctl.len < sizeof (dl_phys_addr_ack_t)) { /* Returned structure is too short */ return -1; } return 0; } #if defined(USE_DLPI_SEND) || defined(USE_DLPI_RECEIVE) int dlpiunitdatareq (fd, addr, addrlen, minpri, maxpri, dbuf, dbuflen) int fd; unsigned char *addr; int addrlen; unsigned long minpri; unsigned long maxpri; unsigned char *dbuf; int dbuflen; { long buf [DLPI_MAXDLBUF]; union DL_primitives *dlp; struct strbuf ctl, data; /* Set up the control information... */ dlp = (union DL_primitives *)buf; dlp -> unitdata_req.dl_primitive = DL_UNITDATA_REQ; dlp -> unitdata_req.dl_dest_addr_length = addrlen; dlp -> unitdata_req.dl_dest_addr_offset = sizeof (dl_unitdata_req_t); dlp -> unitdata_req.dl_priority.dl_min = minpri; dlp -> unitdata_req.dl_priority.dl_max = maxpri; /* Append the destination address */ memcpy ((char *)buf + dlp -> unitdata_req.dl_dest_addr_offset, addr, addrlen); ctl.maxlen = 0; ctl.len = dlp -> unitdata_req.dl_dest_addr_offset + addrlen; ctl.buf = (char *)buf; data.maxlen = 0; data.buf = (char *)dbuf; data.len = dbuflen; /* Send the packet down the wire... */ return putmsg (fd, &ctl, &data, 0); } static int dlpiunitdataind (fd, daddr, daddrlen, saddr, saddrlen, grpaddr, dbuf, dlen) int fd; unsigned char *daddr; unsigned long *daddrlen; unsigned char *saddr; unsigned long *saddrlen; unsigned long *grpaddr; unsigned char *dbuf; int dlen; { long buf [DLPI_MAXDLBUF]; union DL_primitives *dlp; struct strbuf ctl, data; int flags = 0; int result; /* Set up the msg_buf structure... */ dlp = (union DL_primitives *)buf; dlp -> unitdata_ind.dl_primitive = DL_UNITDATA_IND; ctl.maxlen = DLPI_MAXDLBUF; ctl.len = 0; ctl.buf = (char *)buf; data.maxlen = dlen; data.len = 0; data.buf = (char *)dbuf; result = getmsg (fd, &ctl, &data, &flags); if (result < 0) { log_debug("dlpiunitdataind: %m"); return -1; } if (ctl.len < sizeof (dl_unitdata_ind_t) || dlp -> unitdata_ind.dl_primitive != DL_UNITDATA_IND) { return -1; } if (data.len <= 0) { return data.len; } /* Copy sender info */ if (saddr) { memcpy (saddr, (char *)buf + dlp -> unitdata_ind.dl_src_addr_offset, dlp -> unitdata_ind.dl_src_addr_length); } if (saddrlen) { *saddrlen = dlp -> unitdata_ind.dl_src_addr_length; } /* Copy destination info */ if (daddr) { memcpy (daddr, (char *)buf + dlp -> unitdata_ind.dl_dest_addr_offset, dlp -> unitdata_ind.dl_dest_addr_length); } if (daddrlen) { *daddrlen = dlp -> unitdata_ind.dl_dest_addr_length; } if (grpaddr) { *grpaddr = dlp -> unitdata_ind.dl_group_address; } return data.len; } #endif /* !USE_DLPI_HWADDR: USE_DLPI_RECEIVE || USE_DLPI_SEND */ /* * expected - see if we got what we wanted. */ static int expected (prim, dlp, msgflags) unsigned long prim; union DL_primitives *dlp; int msgflags; { if (msgflags != RS_HIPRI) { /* Message was not M_PCPROTO */ return -1; } if (dlp->dl_primitive != prim) { /* Incorrect/unexpected return message */ return -1; } return 0; } /* * strgetmsg - get a message from a stream, with timeout. */ static int strgetmsg (fd, ctlp, datap, flagsp, caller) struct strbuf *ctlp, *datap; char *caller; int *flagsp; int fd; { int result; struct pollfd pfd; int count; time_t now; time_t starttime; int to_msec; pfd.fd = fd; pfd.events = POLLPRI; /* We're only interested in knowing * when we can receive the next high * priority message. */ pfd.revents = 0; now = time (&starttime); while (now <= starttime + DLPI_MAXWAIT) { to_msec = ((starttime + DLPI_MAXWAIT) - now) * 1000; count = poll (&pfd, 1, to_msec); if (count == 0) { /* log_fatal ("strgetmsg: timeout"); */ return -1; } else if (count < 0) { if (errno == EAGAIN || errno == EINTR) { time (&now); continue; } else { /* log_fatal ("poll: %m"); */ return -1; } } else { break; } } /* * Set flags argument and issue getmsg (). */ *flagsp = 0; if ((result = getmsg (fd, ctlp, datap, flagsp)) < 0) { return result; } /* * Check for MOREDATA and/or MORECTL. */ if (result & (MORECTL|MOREDATA)) { return -1; } /* * Check for at least sizeof (long) control data portion. */ if (ctlp -> len < sizeof (long)) { return -1; } return 0; } #if defined(USE_DLPI_SEND) int can_unicast_without_arp (ip) struct interface_info *ip; { return 1; } int can_receive_unicast_unconfigured (ip) struct interface_info *ip; { return 1; } int supports_multiple_interfaces (ip) struct interface_info *ip; { return 1; } void maybe_setup_fallback () { isc_result_t status; struct interface_info *fbi = (struct interface_info *)0; if (setup_fallback (&fbi, MDL)) { if_register_fallback (fbi); status = omapi_register_io_object ((omapi_object_t *)fbi, if_readsocket, 0, fallback_discard, 0, 0); if (status != ISC_R_SUCCESS) log_fatal ("Can't register I/O handle for %s: %s", fbi -> name, isc_result_totext (status)); interface_dereference (&fbi, MDL); } } #endif /* USE_DLPI_SEND */ void get_hw_addr(const char *name, struct hardware *hw) { int sock, unit; long buf[DLPI_MAXDLBUF]; union DL_primitives *dlp; dlp = (union DL_primitives *)buf; /* * Open a DLPI device. */ sock = dlpiopen(name); if (sock < 0) { log_fatal("Can't open DLPI device for %s: %m", name); } /* * Submit a DL_INFO_REQ request, to find the dl_mac_type and * dl_provider_style */ if (dlpiinforeq(sock) < 0) { log_fatal("Can't request DLPI MAC type for %s: %m", name); } if (dlpiinfoack(sock, (char *)buf) < 0) { log_fatal("Can't get DLPI MAC type for %s: %m", name); } switch (dlp->info_ack.dl_mac_type) { case DL_CSMACD: /* IEEE 802.3 */ case DL_ETHER: hw->hbuf[0] = HTYPE_ETHER; break; case DL_TPR: hw->hbuf[0] = HTYPE_IEEE802; break; case DL_FDDI: hw->hbuf[0] = HTYPE_FDDI; break; default: log_fatal("%s: unsupported DLPI MAC type %lu", name, (unsigned long)dlp->info_ack.dl_mac_type); } if (dlp->info_ack.dl_provider_style == DL_STYLE2) { /* * Attach to the device. If this fails, the device * does not exist. */ unit = dlpiunit((char *)name); if (dlpiattachreq(sock, unit) < 0 || dlpiokack(sock, (char *)buf) < 0) { log_fatal("Can't attach DLPI device for %s: %m", name); } } /* * Submit a DL_PHYS_ADDR_REQ request, to find * the hardware address. */ if (dlpiphysaddrreq(sock, DL_CURR_PHYS_ADDR) < 0) { log_fatal("Can't request DLPI hardware address for %s: %m", name); } if (dlpiphysaddrack(sock, (char *)buf) < 0) { log_fatal("Can't get DLPI hardware address for %s: %m", name); } if (dlp->physaddr_ack.dl_addr_length < sizeof(hw->hbuf)) { memcpy(hw->hbuf+1, (char *)buf + dlp->physaddr_ack.dl_addr_offset, dlp->physaddr_ack.dl_addr_length); hw->hlen = dlp->physaddr_ack.dl_addr_length + 1; } else { memcpy(hw->hbuf+1, (char *)buf + dlp->physaddr_ack.dl_addr_offset, sizeof(hw->hbuf)-1); hw->hlen = sizeof(hw->hbuf); } close(sock); } #endif /* USE_DLPI_SEND || USE_DLPI_RECEIVE || USE_DLPI_HWADDR */ dhcp-4.2.4/common/dns.c000644 000765 000024 00000146333 11713061722 014621 0ustar00sarstaff000000 000000 /* dns.c Domain Name Service subroutines. */ /* * Copyright (c) 2009-2012 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 2004-2007 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 2001-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ * * The original software was written for Internet Systems Consortium * by Ted Lemon it has since been extensively modified to use the * asynchronous DNS routines. */ #include "dhcpd.h" #include "arpa/nameser.h" #include #include /* * This file contains code to connect the DHCP code to the libdns modules. * As part of that function it maintains a database of zone cuts that can * be used to figure out which server should be contacted to update any * given domain name. Included in the zone information may be a pointer * to a key in which case that key is used for the update. If no zone * is found then the DNS code determines the zone on its own. * * The way this works is that you define the domain name to which an * SOA corresponds, and the addresses of some primaries for that domain name: * * zone FOO.COM { * primary 10.0.17.1; * secondary 10.0.22.1, 10.0.23.1; * key "FOO.COM Key"; * } * * If an update is requested for GAZANGA.TOPANGA.FOO.COM, then the name * server looks in its database for a zone record for "GAZANGA.TOPANGA.FOO.COM", * doesn't find it, looks for one for "TOPANGA.FOO.COM", doesn't find *that*, * looks for "FOO.COM", finds it. So it * attempts the update to the primary for FOO.COM. If that times out, it * tries the secondaries. You can list multiple primaries if you have some * kind of magic name server that supports that. You shouldn't list * secondaries that don't know how to forward updates (e.g., BIND 8 doesn't * support update forwarding, AFAIK). If no TSIG key is listed, the update * is attempted without TSIG. * * You can also include IPv6 addresses via the primary6 and secondary6 * options. The search order for the addresses is primary, primary6, * secondary and lastly secondary6, with a limit on the number of * addresses used. Currently this limit is 3. * * The DHCP server tries to find an existing zone for any given name by * trying to look up a local zone structure for each domain containing * that name, all the way up to '.'. If it finds one cached, it tries * to use that one to do the update. That's why it tries to update * "FOO.COM" above, even though theoretically it should try GAZANGA... * and TOPANGA... first. * * If the update fails with a predefined zone the zone is marked as bad * and another search of the predefined zones is done. If no predefined * zone is found finding a zone is left to the DNS module via examination * of SOA records. If the DNS module finds a zone it may cache the zone * but the zone won't be cached here. * * TSIG updates are not performed on zones found by the DNS module - if * you want TSIG updates you _must_ write a zone definition linking the * key to the zone. In cases where you know for sure what the key is * but do not want to hardcode the IP addresses of the primary or * secondaries, a zone declaration can be made that doesn't include any * primary or secondary declarations. When the DHCP server encounters * this while hunting up a matching zone for a name, it looks up the SOA, * fills in the IP addresses, and uses that record for the update. * If the SOA lookup returns NXRRSET, a warning is printed and the zone is * discarded, TSIG key and all. The search for the zone then continues * as if the zone record hadn't been found. Zones without IP addresses * don't match when initially hunting for a zone to update. * * When an update is attempted and no predefined zone is found * that matches any enclosing domain of the domain being updated, the DHCP * server goes through the same process that is done when the update to a * predefined zone fails - starting with the most specific domain * name (GAZANGA.TOPANGA.FOO.COM) and moving to the least specific (the root), * it tries to look up an SOA record. * * TSIG keys are defined like this: * * key "FOO.COM Key" { * algorithm HMAC-MD5.SIG-ALG.REG.INT; * secret ; * } * * is a number expressed in base64 that represents the key. * It's also permissible to use a quoted string here - this will be * translated as the ASCII bytes making up the string, and will not * include any NUL termination. The key name can be any text string, * and the key type must be one of the key types defined in the draft * or by the IANA. Currently only the HMAC-MD5... key type is * supported. * * The DDNS processing has been split into two areas. One is the * control code that determines what should be done. That code is found * in the client or server directories. The other is the common code * that performs functions such as properly formatting the arguments. * That code is found in this file. The basic processing flow for a * DDNS update is: * In the client or server code determine what needs to be done and * collect the necesary information then pass it to a function from * this file. * In this code lookup the zone and extract the zone and key information * (if available) and prepare the arguments for the DNS module. * When the DNS module completes its work (times out or gets a reply) * it will trigger another function here which does generic processing * and then passes control back to the code from the server or client. * The server or client code then determines the next step which may * result in another call to this module in which case the process repeats. */ dns_zone_hash_t *dns_zone_hash; /* * DHCP dns structures * Normally the relationship between these structures isn't one to one * but in the DHCP case it (mostly) is. To make the allocations, frees, * and passing of the memory easier we make a single structure with all * the pieces. * * The maximum size of the data buffer should be large enough for any * items DHCP will generate */ typedef struct dhcp_ddns_rdata { dns_rdata_t rdata; dns_rdatalist_t rdatalist; dns_rdataset_t rdataset; } dhcp_ddns_data_t; #if defined (NSUPDATE) void ddns_interlude(isc_task_t *, isc_event_t *); #if defined (TRACING) /* * Code to support tracing DDNS packets. We trace packets going to and * coming from the libdns code but don't try to track the packets * exchanged between the libdns code and the dns server(s) it contacts. * * The code is split into two sets of routines * input refers to messages received from the dns module * output refers to messages sent to the dns module * Currently there are three routines in each set * write is used to write information about the message to the trace file * this routine is called directly from the proper place in the code. * read is used to read information about a message from the trace file * this routine is called from the trace loop as it reads through * the file and is registered via the trace_type_register routine. * When playing back a trace file we shall absorb records of output * messages as part of processing the write function, therefore * any output messages we encounter are flagged as errors. * stop isn't currently used in this code but is needed for the register * routine. * * We pass a pointer to a control block to the dns module which it returns * to use as part of the result. As the pointer may vary between traces * we need to map between those from the trace file and the new ones during * playback. * * The mapping is complicated a little as a pointer could be 4 or 8 bytes * long. We treat the old pointer as an 8 byte quantity and pad and compare * as necessary. */ /* * Structure used to map old pointers to new pointers. * Old pointers are 8 bytes long as we don't know if the trace was * done on a 64 bit or 32 bit machine. */ #define TRACE_PTR_LEN 8 typedef struct dhcp_ddns_map { char old_pointer[TRACE_PTR_LEN]; void *new_pointer; struct dhcp_ddns_map *next; } dhcp_ddns_map_t; /* The starting point for the map structure */ static dhcp_ddns_map_t *ddns_map; trace_type_t *trace_ddns_input; trace_type_t *trace_ddns_output; /* * The data written to the trace file is: * 32 bits result from dns * 64 bits pointer of cb */ void trace_ddns_input_write(dhcp_ddns_cb_t *ddns_cb, isc_result_t result) { trace_iov_t iov[2]; u_int32_t old_result; char old_pointer[TRACE_PTR_LEN]; old_result = htonl((u_int32_t)result); memset(old_pointer, 0, TRACE_PTR_LEN); memcpy(old_pointer, &ddns_cb, sizeof(ddns_cb)); iov[0].len = sizeof(old_result); iov[0].buf = (char *)&old_result; iov[1].len = TRACE_PTR_LEN; iov[1].buf = old_pointer; trace_write_packet_iov(trace_ddns_input, 2, iov, MDL); } /* * Process the result and pointer from the trace file. * We use the pointer map to find the proper pointer for this instance. * Then we need to construct an event to pass along to the interlude * function. */ static void trace_ddns_input_read(trace_type_t *ttype, unsigned length, char *buf) { u_int32_t old_result; char old_pointer[TRACE_PTR_LEN]; dns_clientupdateevent_t *eventp; void *new_pointer; dhcp_ddns_map_t *ddns_map_ptr; if (length < (sizeof(old_result) + TRACE_PTR_LEN)) { log_error("trace_ddns_input_read: data too short"); return; } memcpy(&old_result, buf, sizeof(old_result)); memcpy(old_pointer, buf + sizeof(old_result), TRACE_PTR_LEN); /* map the old pointer to a new pointer */ for (ddns_map_ptr = ddns_map; ddns_map_ptr != NULL; ddns_map_ptr = ddns_map_ptr->next) { if ((ddns_map_ptr->new_pointer != NULL) && memcmp(ddns_map_ptr->old_pointer, old_pointer, TRACE_PTR_LEN) == 0) { new_pointer = ddns_map_ptr->new_pointer; ddns_map_ptr->new_pointer = NULL; memset(ddns_map_ptr->old_pointer, 0, TRACE_PTR_LEN); break; } } if (ddns_map_ptr == NULL) { log_error("trace_dns_input_read: unable to map cb pointer"); return; } eventp = (dns_clientupdateevent_t *) isc_event_allocate(dhcp_gbl_ctx.mctx, dhcp_gbl_ctx.task, 0, ddns_interlude, new_pointer, sizeof(dns_clientupdateevent_t)); if (eventp == NULL) { log_error("trace_ddns_input_read: unable to allocate event"); return; } eventp->result = ntohl(old_result); ddns_interlude(dhcp_gbl_ctx.task, (isc_event_t *)eventp); return; } static void trace_ddns_input_stop(trace_type_t *ttype) { } /* * We use the same arguments as for the dns startupdate function to * allows us to choose between the two via a macro. If tracing isn't * in use we simply call the dns function directly. * * If we are doing playback we read the next packet from the file * and compare the type. If it matches we extract the results and pointer * from the trace file. The results are returned to the caller as if * they had called the dns routine. The pointer is used to construct a * map for when the "reply" is processed. * * The data written to trace file is: * 32 bits result * 64 bits pointer of cb (DDNS Control block) * contents of cb */ isc_result_t trace_ddns_output_write(dns_client_t *client, dns_rdataclass_t rdclass, dns_name_t *zonename, dns_namelist_t *prerequisites, dns_namelist_t *updates, isc_sockaddrlist_t *servers, dns_tsec_t *tsec, unsigned int options, isc_task_t *task, isc_taskaction_t action, void *arg, dns_clientupdatetrans_t **transp) { isc_result_t result; u_int32_t old_result; char old_pointer[TRACE_PTR_LEN]; dhcp_ddns_map_t *ddns_map_ptr; if (trace_playback() != 0) { /* We are doing playback, extract the entry from the file */ unsigned buflen = 0; char *inbuf = NULL; result = trace_get_packet(&trace_ddns_output, &buflen, &inbuf); if (result != ISC_R_SUCCESS) { log_error("trace_ddns_output_write: no input found"); return (ISC_R_FAILURE); } if (buflen < (sizeof(old_result) + TRACE_PTR_LEN)) { log_error("trace_ddns_output_write: data too short"); dfree(inbuf, MDL); return (ISC_R_FAILURE); } memcpy(&old_result, inbuf, sizeof(old_result)); result = ntohl(old_result); memcpy(old_pointer, inbuf + sizeof(old_result), TRACE_PTR_LEN); dfree(inbuf, MDL); /* add the pointer to the pointer map */ for (ddns_map_ptr = ddns_map; ddns_map_ptr != NULL; ddns_map_ptr = ddns_map_ptr->next) { if (ddns_map_ptr->new_pointer == NULL) { break; } } /* * If we didn't find an empty entry, allocate an entry and * link it into the list. The list isn't ordered. */ if (ddns_map_ptr == NULL) { ddns_map_ptr = dmalloc(sizeof(*ddns_map_ptr), MDL); if (ddns_map_ptr == NULL) { log_error("trace_ddns_output_write: " "unable to allocate map entry"); return(ISC_R_FAILURE); } ddns_map_ptr->next = ddns_map; ddns_map = ddns_map_ptr; } memcpy(ddns_map_ptr->old_pointer, old_pointer, TRACE_PTR_LEN); ddns_map_ptr->new_pointer = arg; } else { /* We aren't doing playback, make the actual call */ result = dns_client_startupdate(client, rdclass, zonename, prerequisites, updates, servers, tsec, options, task, action, arg, transp); } if (trace_record() != 0) { /* We are recording, save the information to the file */ trace_iov_t iov[3]; old_result = htonl((u_int32_t)result); memset(old_pointer, 0, TRACE_PTR_LEN); memcpy(old_pointer, &arg, sizeof(arg)); iov[0].len = sizeof(old_result); iov[0].buf = (char *)&old_result; iov[1].len = TRACE_PTR_LEN; iov[1].buf = old_pointer; /* Write out the entire cb, in case we want to look at it */ iov[2].len = sizeof(dhcp_ddns_cb_t); iov[2].buf = (char *)arg; trace_write_packet_iov(trace_ddns_output, 3, iov, MDL); } return(result); } static void trace_ddns_output_read(trace_type_t *ttype, unsigned length, char *buf) { log_error("unaccounted for ddns output."); } static void trace_ddns_output_stop(trace_type_t *ttype) { } void trace_ddns_init() { trace_ddns_output = trace_type_register("ddns-output", NULL, trace_ddns_output_read, trace_ddns_output_stop, MDL); trace_ddns_input = trace_type_register("ddns-input", NULL, trace_ddns_input_read, trace_ddns_input_stop, MDL); ddns_map = NULL; } #define ddns_update trace_ddns_output_write #else #define ddns_update dns_client_startupdate #endif /* TRACING */ /* * Code to allocate and free a dddns control block. This block is used * to pass and track the information associated with a DDNS update request. */ dhcp_ddns_cb_t * ddns_cb_alloc(const char *file, int line) { dhcp_ddns_cb_t *ddns_cb; int i; ddns_cb = dmalloc(sizeof(*ddns_cb), file, line); if (ddns_cb != NULL) { ISC_LIST_INIT(ddns_cb->zone_server_list); for (i = 0; i < DHCP_MAXNS; i++) { ISC_LINK_INIT(&ddns_cb->zone_addrs[i], link); } } #if defined (DEBUG_DNS_UPDATES) log_info("%s(%d): Allocating ddns_cb=%p", file, line, ddns_cb); #endif return(ddns_cb); } void ddns_cb_free(dhcp_ddns_cb_t *ddns_cb, const char *file, int line) { #if defined (DEBUG_DNS_UPDATES) log_info("%s(%d): freeing ddns_cb=%p", file, line, ddns_cb); #endif data_string_forget(&ddns_cb->fwd_name, file, line); data_string_forget(&ddns_cb->rev_name, file, line); data_string_forget(&ddns_cb->dhcid, file, line); if (ddns_cb->zone != NULL) { forget_zone((struct dns_zone **)&ddns_cb->zone); } /* Should be freed by now, check just in case. */ if (ddns_cb->transaction != NULL) log_error("Impossible memory leak at %s:%d (attempt to free " "DDNS Control Block before transaction).", MDL); dfree(ddns_cb, file, line); } void ddns_cb_forget_zone(dhcp_ddns_cb_t *ddns_cb) { int i; forget_zone(&ddns_cb->zone); ddns_cb->zone_name[0] = 0; ISC_LIST_INIT(ddns_cb->zone_server_list); for (i = 0; i < DHCP_MAXNS; i++) { ISC_LINK_INIT(&ddns_cb->zone_addrs[i], link); } } isc_result_t find_tsig_key (ns_tsig_key **key, const char *zname, struct dns_zone *zone) { ns_tsig_key *tkey; if (!zone) return ISC_R_NOTFOUND; if (!zone -> key) { return DHCP_R_KEY_UNKNOWN; } if ((!zone -> key -> name || strlen (zone -> key -> name) > NS_MAXDNAME) || (!zone -> key -> algorithm || strlen (zone -> key -> algorithm) > NS_MAXDNAME) || (!zone -> key) || (!zone -> key -> key) || (zone -> key -> key -> len == 0)) { return DHCP_R_INVALIDKEY; } tkey = dmalloc (sizeof *tkey, MDL); if (!tkey) { nomem: return ISC_R_NOMEMORY; } memset (tkey, 0, sizeof *tkey); tkey -> data = dmalloc (zone -> key -> key -> len, MDL); if (!tkey -> data) { dfree (tkey, MDL); goto nomem; } strcpy (tkey -> name, zone -> key -> name); strcpy (tkey -> alg, zone -> key -> algorithm); memcpy (tkey -> data, zone -> key -> key -> value, zone -> key -> key -> len); tkey -> len = zone -> key -> key -> len; *key = tkey; return ISC_R_SUCCESS; } void tkey_free (ns_tsig_key **key) { if ((*key) -> data) dfree ((*key) -> data, MDL); dfree ((*key), MDL); *key = (ns_tsig_key *)0; } #endif isc_result_t enter_dns_zone (struct dns_zone *zone) { struct dns_zone *tz = (struct dns_zone *)0; if (dns_zone_hash) { dns_zone_hash_lookup (&tz, dns_zone_hash, zone -> name, 0, MDL); if (tz == zone) { dns_zone_dereference (&tz, MDL); return ISC_R_SUCCESS; } if (tz) { dns_zone_hash_delete (dns_zone_hash, zone -> name, 0, MDL); dns_zone_dereference (&tz, MDL); } } else { if (!dns_zone_new_hash(&dns_zone_hash, DNS_HASH_SIZE, MDL)) return ISC_R_NOMEMORY; } dns_zone_hash_add (dns_zone_hash, zone -> name, 0, zone, MDL); return ISC_R_SUCCESS; } isc_result_t dns_zone_lookup (struct dns_zone **zone, const char *name) { int len; char *tname = (char *)0; isc_result_t status; if (!dns_zone_hash) return ISC_R_NOTFOUND; len = strlen (name); if (name [len - 1] != '.') { tname = dmalloc ((unsigned)len + 2, MDL); if (!tname) return ISC_R_NOMEMORY; strcpy (tname, name); tname [len] = '.'; tname [len + 1] = 0; name = tname; } if (!dns_zone_hash_lookup (zone, dns_zone_hash, name, 0, MDL)) status = ISC_R_NOTFOUND; else status = ISC_R_SUCCESS; if (tname) dfree (tname, MDL); return status; } int dns_zone_dereference (ptr, file, line) struct dns_zone **ptr; const char *file; int line; { struct dns_zone *dns_zone; if ((ptr == NULL) || (*ptr == NULL)) { log_error("%s(%d): null pointer", file, line); #if defined (POINTER_DEBUG) abort(); #else return (0); #endif } dns_zone = *ptr; *ptr = NULL; --dns_zone->refcnt; rc_register(file, line, ptr, dns_zone, dns_zone->refcnt, 1, RC_MISC); if (dns_zone->refcnt > 0) return (1); if (dns_zone->refcnt < 0) { log_error("%s(%d): negative refcnt!", file, line); #if defined (DEBUG_RC_HISTORY) dump_rc_history(dns_zone); #endif #if defined (POINTER_DEBUG) abort(); #else return (0); #endif } if (dns_zone->name) dfree(dns_zone->name, file, line); if (dns_zone->key) omapi_auth_key_dereference(&dns_zone->key, file, line); if (dns_zone->primary) option_cache_dereference(&dns_zone->primary, file, line); if (dns_zone->secondary) option_cache_dereference(&dns_zone->secondary, file, line); if (dns_zone->primary6) option_cache_dereference(&dns_zone->primary6, file, line); if (dns_zone->secondary6) option_cache_dereference(&dns_zone->secondary6, file, line); dfree(dns_zone, file, line); return (1); } #if defined (NSUPDATE) isc_result_t find_cached_zone(dhcp_ddns_cb_t *ddns_cb, int direction) { isc_result_t status = ISC_R_NOTFOUND; const char *np; struct dns_zone *zone = NULL; struct data_string nsaddrs; struct in_addr zone_addr; struct in6_addr zone_addr6; int ix; if (direction == FIND_FORWARD) { np = (const char *)ddns_cb->fwd_name.data; } else { np = (const char *)ddns_cb->rev_name.data; } /* We can't look up a null zone. */ if ((np == NULL) || (*np == '\0')) { return (DHCP_R_INVALIDARG); } /* * For each subzone, try to find a cached zone. */ for (;;) { status = dns_zone_lookup(&zone, np); if (status == ISC_R_SUCCESS) break; np = strchr(np, '.'); if (np == NULL) break; np++; } if (status != ISC_R_SUCCESS) return (status); /* Make sure the zone is valid. */ if (zone->timeout && zone->timeout < cur_time) { dns_zone_dereference(&zone, MDL); return (ISC_R_CANCELED); } /* Make sure the zone name will fit. */ if (strlen(zone->name) > sizeof(ddns_cb->zone_name)) { dns_zone_dereference(&zone, MDL); return (ISC_R_NOSPACE); } strcpy((char *)&ddns_cb->zone_name[0], zone->name); memset (&nsaddrs, 0, sizeof nsaddrs); ix = 0; if (zone->primary) { if (evaluate_option_cache(&nsaddrs, NULL, NULL, NULL, NULL, NULL, &global_scope, zone->primary, MDL)) { int ip = 0; while (ix < DHCP_MAXNS) { if (ip + 4 > nsaddrs.len) break; memcpy(&zone_addr, &nsaddrs.data[ip], 4); isc_sockaddr_fromin(&ddns_cb->zone_addrs[ix], &zone_addr, NS_DEFAULTPORT); ISC_LIST_APPEND(ddns_cb->zone_server_list, &ddns_cb->zone_addrs[ix], link); ip += 4; ix++; } data_string_forget(&nsaddrs, MDL); } } if (zone->primary6) { if (evaluate_option_cache(&nsaddrs, NULL, NULL, NULL, NULL, NULL, &global_scope, zone->primary6, MDL)) { int ip = 0; while (ix < DHCP_MAXNS) { if (ip + 16 > nsaddrs.len) break; memcpy(&zone_addr6, &nsaddrs.data[ip], 16); isc_sockaddr_fromin6(&ddns_cb->zone_addrs[ix], &zone_addr6, NS_DEFAULTPORT); ISC_LIST_APPEND(ddns_cb->zone_server_list, &ddns_cb->zone_addrs[ix], link); ip += 16; ix++; } data_string_forget(&nsaddrs, MDL); } } if (zone->secondary) { if (evaluate_option_cache(&nsaddrs, NULL, NULL, NULL, NULL, NULL, &global_scope, zone->secondary, MDL)) { int ip = 0; while (ix < DHCP_MAXNS) { if (ip + 4 > nsaddrs.len) break; memcpy(&zone_addr, &nsaddrs.data[ip], 4); isc_sockaddr_fromin(&ddns_cb->zone_addrs[ix], &zone_addr, NS_DEFAULTPORT); ISC_LIST_APPEND(ddns_cb->zone_server_list, &ddns_cb->zone_addrs[ix], link); ip += 4; ix++; } data_string_forget (&nsaddrs, MDL); } } if (zone->secondary6) { if (evaluate_option_cache(&nsaddrs, NULL, NULL, NULL, NULL, NULL, &global_scope, zone->secondary6, MDL)) { int ip = 0; while (ix < DHCP_MAXNS) { if (ip + 16 > nsaddrs.len) break; memcpy(&zone_addr6, &nsaddrs.data[ip], 16); isc_sockaddr_fromin6(&ddns_cb->zone_addrs[ix], &zone_addr6, NS_DEFAULTPORT); ISC_LIST_APPEND(ddns_cb->zone_server_list, &ddns_cb->zone_addrs[ix], link); ip += 16; ix++; } data_string_forget (&nsaddrs, MDL); } } dns_zone_reference(&ddns_cb->zone, zone, MDL); dns_zone_dereference (&zone, MDL); return ISC_R_SUCCESS; } void forget_zone (struct dns_zone **zone) { dns_zone_dereference (zone, MDL); } void repudiate_zone (struct dns_zone **zone) { /* XXX Currently we're not differentiating between a cached XXX zone and a zone that's been repudiated, which means XXX that if we reap cached zones, we blow away repudiated XXX zones. This isn't a big problem since we're not yet XXX caching zones... :'} */ /* verify that we have a pointer at least */ if ((zone == NULL) || (*zone == NULL)) { log_info("Null argument to repudiate zone"); return; } (*zone) -> timeout = cur_time - 1; dns_zone_dereference (zone, MDL); } /* Have to use TXT records for now. */ #define T_DHCID T_TXT int get_dhcid (struct data_string *id, int type, const u_int8_t *data, unsigned len) { unsigned char buf[ISC_MD5_DIGESTLENGTH]; isc_md5_t md5; int i; /* Types can only be 0..(2^16)-1. */ if (type < 0 || type > 65535) return 0; /* * Hexadecimal MD5 digest plus two byte type, NUL, * and one byte for length for dns. */ if (!buffer_allocate (&id -> buffer, (ISC_MD5_DIGESTLENGTH * 2) + 4, MDL)) return 0; id -> data = id -> buffer -> data; /* * DHCP clients and servers should use the following forms of client * identification, starting with the most preferable, and finishing * with the least preferable. If the client does not send any of these * forms of identification, the DHCP/DDNS interaction is not defined by * this specification. The most preferable form of identification is * the Globally Unique Identifier Option [TBD]. Next is the DHCP * Client Identifier option. Last is the client's link-layer address, * as conveyed in its DHCPREQUEST message. Implementors should note * that the link-layer address cannot be used if there are no * significant bytes in the chaddr field of the DHCP client's request, * because this does not constitute a unique identifier. * -- "Interaction between DHCP and DNS" * * M. Stapp, Y. Rekhter * * We put the length into the first byte to turn * this into a dns text string. This avoid needing to * copy the string to add the byte later. */ id->buffer->data[0] = ISC_MD5_DIGESTLENGTH * 2 + 2; /* Put the type in the next two bytes. */ id->buffer->data[1] = "0123456789abcdef"[(type >> 4) & 0xf]; /* This should have been [type & 0xf] but now that * it is in use we need to leave it this way in order * to avoid disturbing customer's lease files */ id->buffer->data[2] = "0123456789abcdef"[type % 15]; /* Mash together an MD5 hash of the identifier. */ isc_md5_init(&md5); isc_md5_update(&md5, data, len); isc_md5_final(&md5, buf); /* Convert into ASCII. */ for (i = 0; i < ISC_MD5_DIGESTLENGTH; i++) { id->buffer->data[i * 2 + 3] = "0123456789abcdef"[(buf[i] >> 4) & 0xf]; id->buffer->data[i * 2 + 4] = "0123456789abcdef"[buf[i] & 0xf]; } id->len = ISC_MD5_DIGESTLENGTH * 2 + 3; id->buffer->data[id->len] = 0; id->terminated = 1; return 1; } /* * The dhcid (text version) that we pass to DNS includes a length byte * at the start but the text we store in the lease doesn't include the * length byte. The following routines are to convert between the two * styles. * * When converting from a dhcid to a leaseid we reuse the buffer and * simply adjust the data pointer and length fields in the data string. * This avoids any prolems with allocating space. */ void dhcid_tolease(struct data_string *dhcid, struct data_string *leaseid) { /* copy the data string then update the fields */ data_string_copy(leaseid, dhcid, MDL); leaseid->data++; leaseid->len--; } isc_result_t dhcid_fromlease(struct data_string *dhcid, struct data_string *leaseid) { if (!buffer_allocate(&dhcid->buffer, leaseid->len + 2, MDL)) { return(ISC_R_FAILURE); } dhcid->data = dhcid->buffer->data; dhcid->buffer->data[0] = leaseid->len; memcpy(dhcid->buffer->data + 1, leaseid->data, leaseid->len); dhcid->len = leaseid->len + 1; if (leaseid->terminated == 1) { dhcid->buffer->data[dhcid->len] = 0; dhcid->terminated = 1; } return(ISC_R_SUCCESS); } /* * Construct the dataset for this item. * This is a fairly simple arrangement as the operations we do are simple. * If there is data we simply have the rdata point to it - the formatting * must be correct already. We then link the rdatalist to the rdata and * create a rdataset from the rdatalist. */ static isc_result_t make_dns_dataset(dns_rdataclass_t dataclass, dns_rdatatype_t datatype, dhcp_ddns_data_t *dataspace, unsigned char *data, int datalen, int ttl) { dns_rdata_t *rdata = &dataspace->rdata; dns_rdatalist_t *rdatalist = &dataspace->rdatalist; dns_rdataset_t *rdataset = &dataspace->rdataset; isc_region_t region; /* set up the rdata */ dns_rdata_init(rdata); if (data == NULL) { /* No data, set up the rdata fields we care about */ rdata->flags = DNS_RDATA_UPDATE; rdata->type = datatype; rdata->rdclass = dataclass; } else { switch(datatype) { case dns_rdatatype_a: case dns_rdatatype_aaaa: case dns_rdatatype_txt: case dns_rdatatype_dhcid: case dns_rdatatype_ptr: /* The data must be in the right format we simply * need to supply it via the correct structure */ region.base = data; region.length = datalen; dns_rdata_fromregion(rdata, dataclass, datatype, ®ion); break; default: return(DHCP_R_INVALIDARG); break; } } /* setup the datalist and attach the rdata to it */ dns_rdatalist_init(rdatalist); rdatalist->type = datatype; rdatalist->rdclass = dataclass; rdatalist->ttl = ttl; ISC_LIST_APPEND(rdatalist->rdata, rdata, link); /* convert the datalist to a dataset */ dns_rdataset_init(rdataset); dns_rdatalist_tordataset(rdatalist, rdataset); return(ISC_R_SUCCESS); } /* * When a DHCP client or server intends to update an A RR, it first * prepares a DNS UPDATE query which includes as a prerequisite the * assertion that the name does not exist. The update section of the * query attempts to add the new name and its IP address mapping (an A * RR), and the DHCID RR with its unique client-identity. * -- "Interaction between DHCP and DNS" * * There are two cases, one for the server and one for the client. * * For the server the first step will have a request of: * The name is not in use * Add an A RR * Add a DHCID RR (currently txt) * * For the client the first step will have a request of: * The A RR does not exist * Add an A RR * Add a DHCID RR (currently txt) */ static isc_result_t ddns_modify_fwd_add1(dhcp_ddns_cb_t *ddns_cb, dhcp_ddns_data_t *dataspace, dns_name_t *pname, dns_name_t *uname) { isc_result_t result; /* Construct the prerequisite list */ if ((ddns_cb->flags & DDNS_INCLUDE_RRSET) != 0) { /* The A RR shouldn't exist */ result = make_dns_dataset(dns_rdataclass_none, ddns_cb->address_type, dataspace, NULL, 0, 0); } else { /* The name is not in use */ result = make_dns_dataset(dns_rdataclass_none, dns_rdatatype_any, dataspace, NULL, 0, 0); } if (result != ISC_R_SUCCESS) { return(result); } ISC_LIST_APPEND(pname->list, &dataspace->rdataset, link); dataspace++; /* Construct the update list */ /* Add the A RR */ result = make_dns_dataset(dns_rdataclass_in, ddns_cb->address_type, dataspace, (unsigned char *)ddns_cb->address.iabuf, ddns_cb->address.len, ddns_cb->ttl); if (result != ISC_R_SUCCESS) { return(result); } ISC_LIST_APPEND(uname->list, &dataspace->rdataset, link); dataspace++; /* Add the DHCID RR */ result = make_dns_dataset(dns_rdataclass_in, dns_rdatatype_txt, dataspace, (unsigned char *)ddns_cb->dhcid.data, ddns_cb->dhcid.len, ddns_cb->ttl); if (result != ISC_R_SUCCESS) { return(result); } ISC_LIST_APPEND(uname->list, &dataspace->rdataset, link); return(ISC_R_SUCCESS); } /* * If the first update operation fails with YXDOMAIN, the updater can * conclude that the intended name is in use. The updater then * attempts to confirm that the DNS name is not being used by some * other host. The updater prepares a second UPDATE query in which the * prerequisite is that the desired name has attached to it a DHCID RR * whose contents match the client identity. The update section of * this query deletes the existing A records on the name, and adds the * A record that matches the DHCP binding and the DHCID RR with the * client identity. * -- "Interaction between DHCP and DNS" * * The message for the second step depends on if we are doing conflict * resolution. If we are we include a prerequisite. If not we delete * the DHCID in addition to all A rrsets. * * Conflict resolution: * DHCID RR exists, and matches client identity. * Delete A RRset. * Add A RR. * * Conflict override: * Delete DHCID RRs. * Add DHCID RR * Delete A RRset. * Add A RR. */ static isc_result_t ddns_modify_fwd_add2(dhcp_ddns_cb_t *ddns_cb, dhcp_ddns_data_t *dataspace, dns_name_t *pname, dns_name_t *uname) { isc_result_t result; /* * If we are doing conflict resolution (unset) we use a prereq list. * If not we delete the DHCID in addition to all A rrsets. */ if ((ddns_cb->flags & DDNS_CONFLICT_OVERRIDE) == 0) { /* Construct the prereq list */ /* The DHCID RR exists and matches the client identity */ result = make_dns_dataset(dns_rdataclass_in, dns_rdatatype_txt, dataspace, (unsigned char *)ddns_cb->dhcid.data, ddns_cb->dhcid.len, 0); if (result != ISC_R_SUCCESS) { return(result); } ISC_LIST_APPEND(pname->list, &dataspace->rdataset, link); dataspace++; } else { /* Start constructing the update list. * Conflict detection override: delete DHCID RRs */ result = make_dns_dataset(dns_rdataclass_any, dns_rdatatype_txt, dataspace, NULL, 0, 0); if (result != ISC_R_SUCCESS) { return(result); } ISC_LIST_APPEND(uname->list, &dataspace->rdataset, link); dataspace++; /* Add current DHCID RR */ result = make_dns_dataset(dns_rdataclass_in, dns_rdatatype_txt, dataspace, (unsigned char *)ddns_cb->dhcid.data, ddns_cb->dhcid.len, ddns_cb->ttl); if (result != ISC_R_SUCCESS) { return(result); } ISC_LIST_APPEND(uname->list, &dataspace->rdataset, link); dataspace++; } /* Start or continue constructing the update list */ /* Delete the A RRset */ result = make_dns_dataset(dns_rdataclass_any, ddns_cb->address_type, dataspace, NULL, 0, 0); if (result != ISC_R_SUCCESS) { return(result); } ISC_LIST_APPEND(uname->list, &dataspace->rdataset, link); dataspace++; /* Add the A RR */ result = make_dns_dataset(dns_rdataclass_in, ddns_cb->address_type, dataspace, (unsigned char *)ddns_cb->address.iabuf, ddns_cb->address.len, ddns_cb->ttl); if (result != ISC_R_SUCCESS) { return(result); } ISC_LIST_APPEND(uname->list, &dataspace->rdataset, link); return(ISC_R_SUCCESS); } /* * The entity chosen to handle the A record for this client (either the * client or the server) SHOULD delete the A record that was added when * the lease was made to the client. * * In order to perform this delete, the updater prepares an UPDATE * query which contains two prerequisites. The first prerequisite * asserts that the DHCID RR exists whose data is the client identity * described in Section 4.3. The second prerequisite asserts that the * data in the A RR contains the IP address of the lease that has * expired or been released. * -- "Interaction between DHCP and DNS" * * First try has: * DHCID RR exists, and matches client identity. * A RR matches the expiring lease. * Delete appropriate A RR. */ static isc_result_t ddns_modify_fwd_rem1(dhcp_ddns_cb_t *ddns_cb, dhcp_ddns_data_t *dataspace, dns_name_t *pname, dns_name_t *uname) { isc_result_t result; /* Consruct the prereq list */ /* The DHCID RR exists and matches the client identity */ result = make_dns_dataset(dns_rdataclass_in, dns_rdatatype_txt, dataspace, (unsigned char *)ddns_cb->dhcid.data, ddns_cb->dhcid.len, 0); if (result != ISC_R_SUCCESS) { return(result); } ISC_LIST_APPEND(pname->list, &dataspace->rdataset, link); dataspace++; /* The A RR matches the expiring lease */ result = make_dns_dataset(dns_rdataclass_in, ddns_cb->address_type, dataspace, (unsigned char *)ddns_cb->address.iabuf, ddns_cb->address.len, 0); if (result != ISC_R_SUCCESS) { return(result); } ISC_LIST_APPEND(pname->list, &dataspace->rdataset, link); dataspace++; /* Construct the update list */ /* Delete A RRset */ result = make_dns_dataset(dns_rdataclass_none, ddns_cb->address_type, dataspace, (unsigned char *)ddns_cb->address.iabuf, ddns_cb->address.len, 0); if (result != ISC_R_SUCCESS) { return(result); } ISC_LIST_APPEND(uname->list, &dataspace->rdataset, link); return(ISC_R_SUCCESS); } /* * If the deletion of the A succeeded, and there are no A or AAAA * records left for this domain, then we can blow away the DHCID * record as well. We can't blow away the DHCID record above * because it's possible that more than one record has been added * to this domain name. * * Second query has: * A RR does not exist. * AAAA RR does not exist. * Delete appropriate DHCID RR. */ static isc_result_t ddns_modify_fwd_rem2(dhcp_ddns_cb_t *ddns_cb, dhcp_ddns_data_t *dataspace, dns_name_t *pname, dns_name_t *uname) { isc_result_t result; /* Construct the prereq list */ /* The A RR does not exist */ result = make_dns_dataset(dns_rdataclass_none, dns_rdatatype_a, dataspace, NULL, 0, 0); if (result != ISC_R_SUCCESS) { return(result); } ISC_LIST_APPEND(pname->list, &dataspace->rdataset, link); dataspace++; /* The AAAA RR does not exist */ result = make_dns_dataset(dns_rdataclass_none, dns_rdatatype_aaaa, dataspace, NULL, 0, 0); if (result != ISC_R_SUCCESS) { return(result); } ISC_LIST_APPEND(pname->list, &dataspace->rdataset, link); dataspace++; /* Construct the update list */ /* Delete DHCID RR */ result = make_dns_dataset(dns_rdataclass_none, dns_rdatatype_txt, dataspace, (unsigned char *)ddns_cb->dhcid.data, ddns_cb->dhcid.len, 0); if (result != ISC_R_SUCCESS) { return(result); } ISC_LIST_APPEND(uname->list, &dataspace->rdataset, link); return(ISC_R_SUCCESS); } /* * This routine converts from the task action call into something * easier to work with. It also handles the common case of a signature * or zone not being correct. */ void ddns_interlude(isc_task_t *taskp, isc_event_t *eventp) { dhcp_ddns_cb_t *ddns_cb = (dhcp_ddns_cb_t *)eventp->ev_arg; dns_clientupdateevent_t *ddns_event = (dns_clientupdateevent_t *)eventp; isc_result_t eresult = ddns_event->result; isc_result_t result; /* We've extracted the information we want from it, get rid of * the event block.*/ isc_event_free(&eventp); #if defined (TRACING) if (trace_record()) { trace_ddns_input_write(ddns_cb, eresult); } #endif #if defined (DEBUG_DNS_UPDATES) print_dns_status(DDNS_PRINT_INBOUND, ddns_cb, eresult); #endif /* This transaction is complete, clear the value */ dns_client_destroyupdatetrans(&ddns_cb->transaction); /* If we cancelled or tried to cancel the operation we just * need to clean up. */ if ((eresult == ISC_R_CANCELED) || ((ddns_cb->flags & DDNS_ABORT) != 0)) { #if defined (DEBUG_DNS_UPDATES) log_info("DDNS: completeing transaction cancellation cb=%p, " "flags=%x, %s", ddns_cb, ddns_cb->flags, isc_result_totext(eresult)); #endif if ((ddns_cb->flags & DDNS_ABORT) == 0) { log_info("DDNS: cleaning up lease pointer for a cancel " "cb=%p", ddns_cb); /* * We shouldn't actually be able to get here but * we are. This means we haven't cleaned up * the lease pointer so we need to do that before * freeing the cb. */ ddns_cb->cur_func(ddns_cb, eresult); return; } if (ddns_cb->next_op != NULL) { /* if necessary cleanup up next op block */ ddns_cb_free(ddns_cb->next_op, MDL); } ddns_cb_free(ddns_cb, MDL); return; } /* If we had a problem with our key or zone try again */ if ((eresult == DNS_R_NOTAUTH) || (eresult == DNS_R_NOTZONE)) { int i; /* Our zone information was questionable, * repudiate it and try again */ log_error("DDNS: bad zone information, repudiating zone %s", ddns_cb->zone_name); repudiate_zone(&ddns_cb->zone); ddns_cb->zone_name[0] = 0; ISC_LIST_INIT(ddns_cb->zone_server_list); for (i = 0; i < DHCP_MAXNS; i++) { ISC_LINK_INIT(&ddns_cb->zone_addrs[i], link); } if ((ddns_cb->state == DDNS_STATE_ADD_PTR) || (ddns_cb->state == DDNS_STATE_REM_PTR)) { result = ddns_modify_ptr(ddns_cb, MDL); } else { result = ddns_modify_fwd(ddns_cb, MDL); } if (result != ISC_R_SUCCESS) { /* if we couldn't redo the query log it and * let the next function clean it up */ log_info("DDNS: Failed to retry after zone failure"); ddns_cb->cur_func(ddns_cb, result); } return; } else { /* pass it along to be processed */ ddns_cb->cur_func(ddns_cb, eresult); } return; } /* * This routine does the generic work for sending a ddns message to * modify the forward record (A or AAAA) and calls one of a set of * routines to build the specific message. */ isc_result_t ddns_modify_fwd(dhcp_ddns_cb_t *ddns_cb, const char *file, int line) { isc_result_t result; dns_tsec_t *tsec_key = NULL; unsigned char *clientname; dhcp_ddns_data_t *dataspace = NULL; dns_namelist_t prereqlist, updatelist; dns_fixedname_t zname0, pname0, uname0; dns_name_t *zname = NULL, *pname, *uname; isc_sockaddrlist_t *zlist = NULL; /* Get a pointer to the clientname to make things easier. */ clientname = (unsigned char *)ddns_cb->fwd_name.data; /* Extract and validate the type of the address. */ if (ddns_cb->address.len == 4) { ddns_cb->address_type = dns_rdatatype_a; } else if (ddns_cb->address.len == 16) { ddns_cb->address_type = dns_rdatatype_aaaa; } else { return DHCP_R_INVALIDARG; } /* * If we already have a zone use it, otherwise try to lookup the * zone in our cache. If we find one we will have a pointer to * the zone that needs to be dereferenced when we are done with it. * If we don't find one that is okay we'll let the DNS code try and * find the information for us. */ if (ddns_cb->zone == NULL) { result = find_cached_zone(ddns_cb, FIND_FORWARD); } /* * If we have a zone try to get any information we need * from it - name, addresses and the key. The address * and key may be empty the name can't be. */ if (ddns_cb->zone) { /* Set up the zone name for use by DNS */ result = dhcp_isc_name(ddns_cb->zone_name, &zname0, &zname); if (result != ISC_R_SUCCESS) { log_error("Unable to build name for zone for " "fwd update: %s %s", ddns_cb->zone_name, isc_result_totext(result)); goto cleanup; } if (!(ISC_LIST_EMPTY(ddns_cb->zone_server_list))) { /* If we have any addresses get them */ zlist = &ddns_cb->zone_server_list; } if (ddns_cb->zone->key != NULL) { /* * Not having a key is fine, having a key * but not a tsec is odd so we warn the user. */ /*sar*/ /* should we do the warning? */ tsec_key = ddns_cb->zone->key->tsec_key; if (tsec_key == NULL) { log_error("No tsec for use with key %s", ddns_cb->zone->key->name); } } } /* Set up the DNS names for the prereq and update lists */ if (((result = dhcp_isc_name(clientname, &pname0, &pname)) != ISC_R_SUCCESS) || ((result = dhcp_isc_name(clientname, &uname0, &uname)) != ISC_R_SUCCESS)) { log_error("Unable to build name for fwd update: %s %s", clientname, isc_result_totext(result)); goto cleanup; } /* Allocate the various isc dns library structures we may require. */ dataspace = isc_mem_get(dhcp_gbl_ctx.mctx, sizeof(*dataspace) * 4); if (dataspace == NULL) { log_error("Unable to allocate memory for fwd update"); result = ISC_R_NOMEMORY; goto cleanup; } ISC_LIST_INIT(prereqlist); ISC_LIST_INIT(updatelist); switch(ddns_cb->state) { case DDNS_STATE_ADD_FW_NXDOMAIN: result = ddns_modify_fwd_add1(ddns_cb, dataspace, pname, uname); if (result != ISC_R_SUCCESS) { goto cleanup; } ISC_LIST_APPEND(prereqlist, pname, link); break; case DDNS_STATE_ADD_FW_YXDHCID: result = ddns_modify_fwd_add2(ddns_cb, dataspace, pname, uname); if (result != ISC_R_SUCCESS) { goto cleanup; } /* If we aren't doing conflict override we have entries * in the pname list and we need to attach it to the * prereqlist */ if ((ddns_cb->flags & DDNS_CONFLICT_OVERRIDE) == 0) { ISC_LIST_APPEND(prereqlist, pname, link); } break; case DDNS_STATE_REM_FW_YXDHCID: result = ddns_modify_fwd_rem1(ddns_cb, dataspace, pname, uname); if (result != ISC_R_SUCCESS) { goto cleanup; } ISC_LIST_APPEND(prereqlist, pname, link); break; case DDNS_STATE_REM_FW_NXRR: result = ddns_modify_fwd_rem2(ddns_cb, dataspace, pname, uname); if (result != ISC_R_SUCCESS) { goto cleanup; } ISC_LIST_APPEND(prereqlist, pname, link); break; default: log_error("Invalid operation in ddns code."); result = DHCP_R_INVALIDARG; goto cleanup; break; } /* * We always have an update list but may not have a prereqlist * if we are doing conflict override. */ ISC_LIST_APPEND(updatelist, uname, link); /* send the message, cleanup and return the result */ result = ddns_update(dhcp_gbl_ctx.dnsclient, dns_rdataclass_in, zname, &prereqlist, &updatelist, zlist, tsec_key, DNS_CLIENTRESOPT_ALLOWRUN, dhcp_gbl_ctx.task, ddns_interlude, (void *)ddns_cb, &ddns_cb->transaction); if (result == ISC_R_FAMILYNOSUPPORT) { log_info("Unable to perform DDNS update, " "address family not supported"); } #if defined (DEBUG_DNS_UPDATES) print_dns_status(DDNS_PRINT_OUTBOUND, ddns_cb, result); #endif cleanup: #if defined (DEBUG_DNS_UPDATES) if (result != ISC_R_SUCCESS) { log_info("DDNS: %s(%d): error in ddns_modify_fwd %s for %p", file, line, isc_result_totext(result), ddns_cb); } #endif if (dataspace != NULL) { isc_mem_put(dhcp_gbl_ctx.mctx, dataspace, sizeof(*dataspace) * 4); } return(result); } isc_result_t ddns_modify_ptr(dhcp_ddns_cb_t *ddns_cb, const char *file, int line) { isc_result_t result; dns_tsec_t *tsec_key = NULL; unsigned char *ptrname; dhcp_ddns_data_t *dataspace = NULL; dns_namelist_t updatelist; dns_fixedname_t zname0, uname0; dns_name_t *zname = NULL, *uname; isc_sockaddrlist_t *zlist = NULL; unsigned char buf[256]; int buflen; /* * Try to lookup the zone in the zone cache. As with the forward * case it's okay if we don't have one, the DNS code will try to * find something also if we succeed we will need to dereference * the zone later. Unlike with the forward case we assume we won't * have a pre-existing zone. */ result = find_cached_zone(ddns_cb, FIND_REVERSE); if ((result == ISC_R_SUCCESS) && !(ISC_LIST_EMPTY(ddns_cb->zone_server_list))) { /* Set up the zone name for use by DNS */ result = dhcp_isc_name(ddns_cb->zone_name, &zname0, &zname); if (result != ISC_R_SUCCESS) { log_error("Unable to build name for zone for " "fwd update: %s %s", ddns_cb->zone_name, isc_result_totext(result)); goto cleanup; } /* If we have any addresses get them */ if (!(ISC_LIST_EMPTY(ddns_cb->zone_server_list))) { zlist = &ddns_cb->zone_server_list; } /* * If we now have a zone try to get the key, NULL is okay, * having a key but not a tsec is odd so we warn. */ /*sar*/ /* should we do the warning if we have a key but no tsec? */ if ((ddns_cb->zone != NULL) && (ddns_cb->zone->key != NULL)) { tsec_key = ddns_cb->zone->key->tsec_key; if (tsec_key == NULL) { log_error("No tsec for use with key %s", ddns_cb->zone->key->name); } } } /* We must have a name for the update list */ /* Get a pointer to the ptrname to make things easier. */ ptrname = (unsigned char *)ddns_cb->rev_name.data; if ((result = dhcp_isc_name(ptrname, &uname0, &uname)) != ISC_R_SUCCESS) { log_error("Unable to build name for fwd update: %s %s", ptrname, isc_result_totext(result)); goto cleanup; } /* * Allocate the various isc dns library structures we may require. * Allocating one blob avoids being halfway through the process * and being unable to allocate as well as making the free easy. */ dataspace = isc_mem_get(dhcp_gbl_ctx.mctx, sizeof(*dataspace) * 2); if (dataspace == NULL) { log_error("Unable to allocate memory for fwd update"); result = ISC_R_NOMEMORY; goto cleanup; } ISC_LIST_INIT(updatelist); /* * Construct the update list * We always delete what's currently there * Delete PTR RR. */ result = make_dns_dataset(dns_rdataclass_any, dns_rdatatype_ptr, &dataspace[0], NULL, 0, 0); if (result != ISC_R_SUCCESS) { goto cleanup; } ISC_LIST_APPEND(uname->list, &dataspace[0].rdataset, link); /* * If we are updating the pointer we then add the new one * Add PTR RR. */ if (ddns_cb->state == DDNS_STATE_ADD_PTR) { #if 0 /* * I've left this dead code in the file for now in case * we decide to try and get rid of the ns_name functions. * sar */ /* * Need to convert pointer into on the wire representation * We replace the '.' characters with the lengths of the * next name and add a length to the beginning for the first * name. */ if (ddns_cb->fwd_name.len == 1) { /* the root */ buf[0] = 0; buflen = 1; } else { unsigned char *cp; buf[0] = '.'; memcpy(&buf[1], ddns_cb->fwd_name.data, ddns_cb->fwd_name.len); for(cp = buf + ddns_cb->fwd_name.len, buflen = 0; cp != buf; cp--) { if (*cp == '.') { *cp = buflen; buflen = 0; } else { buflen++; } } *cp = buflen; buflen = ddns_cb->fwd_name.len + 1; } #endif /* * Need to convert pointer into on the wire representation */ if (MRns_name_pton((char *)ddns_cb->fwd_name.data, buf, 256) == -1) { goto cleanup; } buflen = 0; while (buf[buflen] != 0) { buflen += buf[buflen] + 1; } buflen++; result = make_dns_dataset(dns_rdataclass_in, dns_rdatatype_ptr, &dataspace[1], buf, buflen, ddns_cb->ttl); if (result != ISC_R_SUCCESS) { goto cleanup; } ISC_LIST_APPEND(uname->list, &dataspace[1].rdataset, link); } ISC_LIST_APPEND(updatelist, uname, link); /*sar*/ /* * for now I'll cleanup the dataset immediately, it would be * more efficient to keep it around in case the signaturure failed * and we wanted to retry it. */ /* send the message, cleanup and return the result */ result = ddns_update((dns_client_t *)dhcp_gbl_ctx.dnsclient, dns_rdataclass_in, zname, NULL, &updatelist, zlist, tsec_key, DNS_CLIENTRESOPT_ALLOWRUN, dhcp_gbl_ctx.task, ddns_interlude, (void *)ddns_cb, &ddns_cb->transaction); if (result == ISC_R_FAMILYNOSUPPORT) { log_info("Unable to perform DDNS update, " "address family not supported"); } #if defined (DEBUG_DNS_UPDATES) print_dns_status(DDNS_PRINT_OUTBOUND, ddns_cb, result); #endif cleanup: #if defined (DEBUG_DNS_UPDATES) if (result != ISC_R_SUCCESS) { log_info("DDNS: %s(%d): error in ddns_modify_ptr %s for %p", file, line, isc_result_totext(result), ddns_cb); } #endif if (dataspace != NULL) { isc_mem_put(dhcp_gbl_ctx.mctx, dataspace, sizeof(*dataspace) * 2); } return(result); } void ddns_cancel(dhcp_ddns_cb_t *ddns_cb, const char *file, int line) { ddns_cb->flags |= DDNS_ABORT; if (ddns_cb->transaction != NULL) { dns_client_cancelupdate((dns_clientupdatetrans_t *) ddns_cb->transaction); } ddns_cb->lease = NULL; #if defined (DEBUG_DNS_UPDATES) log_info("DDNS: %s(%d): cancelling transaction for %p", file, line, ddns_cb); #endif } #endif /* NSUPDATE */ HASH_FUNCTIONS (dns_zone, const char *, struct dns_zone, dns_zone_hash_t, dns_zone_reference, dns_zone_dereference, do_case_hash) dhcp-4.2.4/common/ethernet.c000644 000765 000024 00000005731 11301372614 015645 0ustar00sarstaff000000 000000 /* ethernet.c Packet assembly code, originally contributed by Archie Cobbs. */ /* * Copyright (c) 2004,2007,2009 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1996-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ * * This software has been written for Internet Systems Consortium * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. * To learn more about Internet Systems Consortium, see * ``https://www.isc.org/''. To learn more about Vixie Enterprises, * see ``http://www.vix.com''. To learn more about Nominum, Inc., see * ``http://www.nominum.com''. */ #include "dhcpd.h" #if defined (PACKET_ASSEMBLY) || defined (PACKET_DECODING) #include "includes/netinet/if_ether.h" #endif /* PACKET_ASSEMBLY || PACKET_DECODING */ #if defined (PACKET_ASSEMBLY) /* Assemble an hardware header... */ void assemble_ethernet_header (interface, buf, bufix, to) struct interface_info *interface; unsigned char *buf; unsigned *bufix; struct hardware *to; { struct isc_ether_header eh; if (to && to -> hlen == 7) /* XXX */ memcpy (eh.ether_dhost, &to -> hbuf [1], sizeof eh.ether_dhost); else memset (eh.ether_dhost, 0xff, sizeof (eh.ether_dhost)); if (interface -> hw_address.hlen - 1 == sizeof (eh.ether_shost)) memcpy (eh.ether_shost, &interface -> hw_address.hbuf [1], sizeof (eh.ether_shost)); else memset (eh.ether_shost, 0x00, sizeof (eh.ether_shost)); eh.ether_type = htons (ETHERTYPE_IP); memcpy (&buf [*bufix], &eh, ETHER_HEADER_SIZE); *bufix += ETHER_HEADER_SIZE; } #endif /* PACKET_ASSEMBLY */ #ifdef PACKET_DECODING /* Decode a hardware header... */ ssize_t decode_ethernet_header (interface, buf, bufix, from) struct interface_info *interface; unsigned char *buf; unsigned bufix; struct hardware *from; { struct isc_ether_header eh; memcpy (&eh, buf + bufix, ETHER_HEADER_SIZE); #ifdef USERLAND_FILTER if (ntohs (eh.ether_type) != ETHERTYPE_IP) return -1; #endif memcpy (&from -> hbuf [1], eh.ether_shost, sizeof (eh.ether_shost)); from -> hbuf [0] = ARPHRD_ETHER; from -> hlen = (sizeof eh.ether_shost) + 1; return ETHER_HEADER_SIZE; } #endif /* PACKET_DECODING */ dhcp-4.2.4/common/execute.c000644 000765 000024 00000100730 11741122652 015467 0ustar00sarstaff000000 000000 /* execute.c Support for executable statements. */ /* * Copyright (c) 2009,2012 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 2004-2007 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1998-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ * * This software has been written for Internet Systems Consortium * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. * To learn more about Internet Systems Consortium, see * ``https://www.isc.org/''. To learn more about Vixie Enterprises, * see ``http://www.vix.com''. To learn more about Nominum, Inc., see * ``http://www.nominum.com''. */ #include "dhcpd.h" #include #include #include int execute_statements (result, packet, lease, client_state, in_options, out_options, scope, statements) struct binding_value **result; struct packet *packet; struct lease *lease; struct client_state *client_state; struct option_state *in_options; struct option_state *out_options; struct binding_scope **scope; struct executable_statement *statements; { struct executable_statement *r, *e, *next; int rc; int status; struct binding *binding; struct data_string ds; struct binding_scope *ns; if (!statements) return 1; r = (struct executable_statement *)0; next = (struct executable_statement *)0; e = (struct executable_statement *)0; executable_statement_reference (&r, statements, MDL); while (r && !(result && *result)) { if (r -> next) executable_statement_reference (&next, r -> next, MDL); switch (r -> op) { case statements_statement: #if defined (DEBUG_EXPRESSIONS) log_debug ("exec: statements"); #endif status = execute_statements (result, packet, lease, client_state, in_options, out_options, scope, r -> data.statements); #if defined (DEBUG_EXPRESSIONS) log_debug ("exec: statements returns %d", status); #endif if (!status) return 0; break; case on_statement: if (lease) { if (r -> data.on.evtypes & ON_EXPIRY) { #if defined (DEBUG_EXPRESSIONS) log_debug ("exec: on expiry"); #endif if (lease -> on_expiry) executable_statement_dereference (&lease -> on_expiry, MDL); if (r -> data.on.statements) executable_statement_reference (&lease -> on_expiry, r -> data.on.statements, MDL); } if (r -> data.on.evtypes & ON_RELEASE) { #if defined (DEBUG_EXPRESSIONS) log_debug ("exec: on release"); #endif if (lease -> on_release) executable_statement_dereference (&lease -> on_release, MDL); if (r -> data.on.statements) executable_statement_reference (&lease -> on_release, r -> data.on.statements, MDL); } if (r -> data.on.evtypes & ON_COMMIT) { #if defined (DEBUG_EXPRESSIONS) log_debug ("exec: on commit"); #endif if (lease -> on_commit) executable_statement_dereference (&lease -> on_commit, MDL); if (r -> data.on.statements) executable_statement_reference (&lease -> on_commit, r -> data.on.statements, MDL); } } break; case switch_statement: #if defined (DEBUG_EXPRESSIONS) log_debug ("exec: switch"); #endif status = (find_matching_case (&e, packet, lease, client_state, in_options, out_options, scope, r -> data.s_switch.expr, r -> data.s_switch.statements)); #if defined (DEBUG_EXPRESSIONS) log_debug ("exec: switch: case %lx", (unsigned long)e); #endif if (status) { if (!(execute_statements (result, packet, lease, client_state, in_options, out_options, scope, e))) { executable_statement_dereference (&e, MDL); return 0; } executable_statement_dereference (&e, MDL); } break; /* These have no effect when executed. */ case case_statement: case default_statement: break; case if_statement: status = (evaluate_boolean_expression (&rc, packet, lease, client_state, in_options, out_options, scope, r -> data.ie.expr)); #if defined (DEBUG_EXPRESSIONS) log_debug ("exec: if %s", (status ? (rc ? "true" : "false") : "NULL")); #endif /* XXX Treat NULL as false */ if (!status) rc = 0; if (!execute_statements (result, packet, lease, client_state, in_options, out_options, scope, rc ? r -> data.ie.tc : r -> data.ie.fc)) return 0; break; case eval_statement: status = evaluate_expression ((struct binding_value **)0, packet, lease, client_state, in_options, out_options, scope, r -> data.eval, MDL); #if defined (DEBUG_EXPRESSIONS) log_debug ("exec: evaluate: %s", (status ? "succeeded" : "failed")); #endif break; case execute_statement: { #ifdef ENABLE_EXECUTE struct expression *expr; char **argv; int i, argc = r->data.execute.argc; pid_t p; /* save room for the command and the NULL terminator */ argv = dmalloc((argc + 2) * sizeof(*argv), MDL); if (!argv) break; argv[0] = dmalloc(strlen(r->data.execute.command) + 1, MDL); if (argv[0]) { strcpy(argv[0], r->data.execute.command); } else { goto execute_out; } log_debug("execute_statement argv[0] = %s", argv[0]); for (i = 1, expr = r->data.execute.arglist; expr; expr = expr->data.arg.next, i++) { memset (&ds, 0, sizeof(ds)); status = (evaluate_data_expression (&ds, packet, lease, client_state, in_options, out_options, scope, expr->data.arg.val, MDL)); if (status) { argv[i] = dmalloc(ds.len + 1, MDL); if (argv[i]) { memcpy(argv[i], ds.data, ds.len); argv[i][ds.len] = 0; log_debug("execute_statement argv[%d] = %s", i, argv[i]); } data_string_forget (&ds, MDL); if (!argv[i]) { log_debug("execute_statement failed argv[%d]", i); goto execute_out; } } else { log_debug("execute: bad arg %d", i); goto execute_out; } } argv[i] = NULL; if ((p = fork()) > 0) { int status; waitpid(p, &status, 0); if (status) { log_error("execute: %s exit status %d", argv[0], status); } } else if (p == 0) { execvp(argv[0], argv); log_error("Unable to execute %s: %m", argv[0]); _exit(127); } else { log_error("execute: fork() failed"); } execute_out: for (i = 0; i <= argc; i++) { if(argv[i]) dfree(argv[i], MDL); } dfree(argv, MDL); #else /* !ENABLE_EXECUTE */ log_fatal("Impossible case at %s:%d (ENABLE_EXECUTE " "is not defined).", MDL); #endif /* ENABLE_EXECUTE */ break; } case return_statement: status = evaluate_expression (result, packet, lease, client_state, in_options, out_options, scope, r -> data.retval, MDL); #if defined (DEBUG_EXPRESSIONS) log_debug ("exec: return: %s", (status ? "succeeded" : "failed")); #endif break; case add_statement: #if defined (DEBUG_EXPRESSIONS) log_debug ("exec: add %s", (r -> data.add -> name ? r -> data.add -> name : "")); #endif classify (packet, r -> data.add); break; case break_statement: #if defined (DEBUG_EXPRESSIONS) log_debug ("exec: break"); #endif return 1; case supersede_option_statement: case send_option_statement: #if defined (DEBUG_EXPRESSIONS) log_debug ("exec: %s option %s.%s", (r -> op == supersede_option_statement ? "supersede" : "send"), r -> data.option -> option -> universe -> name, r -> data.option -> option -> name); goto option_statement; #endif case default_option_statement: #if defined (DEBUG_EXPRESSIONS) log_debug ("exec: default option %s.%s", r -> data.option -> option -> universe -> name, r -> data.option -> option -> name); goto option_statement; #endif case append_option_statement: #if defined (DEBUG_EXPRESSIONS) log_debug ("exec: append option %s.%s", r -> data.option -> option -> universe -> name, r -> data.option -> option -> name); goto option_statement; #endif case prepend_option_statement: #if defined (DEBUG_EXPRESSIONS) log_debug ("exec: prepend option %s.%s", r -> data.option -> option -> universe -> name, r -> data.option -> option -> name); option_statement: #endif set_option (r -> data.option -> option -> universe, out_options, r -> data.option, r -> op); break; case set_statement: case define_statement: if (!scope) { log_error("set %s: no scope", r->data.set.name); status = 0; break; } if (!*scope) { if (!binding_scope_allocate(scope, MDL)) { log_error("set %s: can't allocate scope", r->data.set.name); status = 0; break; } } binding = find_binding(*scope, r->data.set.name); #if defined (DEBUG_EXPRESSIONS) log_debug("exec: set %s", r->data.set.name); #endif if (binding == NULL) { binding = dmalloc(sizeof(*binding), MDL); if (binding != NULL) { memset(binding, 0, sizeof(*binding)); binding->name = dmalloc(strlen (r->data.set.name) + 1, MDL); if (binding->name != NULL) { strcpy(binding->name, r->data.set.name); binding->next = (*scope)->bindings; (*scope)->bindings = binding; } else { dfree(binding, MDL); binding = NULL; } } } if (binding != NULL) { if (binding->value != NULL) binding_value_dereference (&binding->value, MDL); if (r->op == set_statement) { status = (evaluate_expression (&binding->value, packet, lease, client_state, in_options, out_options, scope, r->data.set.expr, MDL)); } else { if (!(binding_value_allocate (&binding->value, MDL))) { dfree(binding, MDL); binding = NULL; } if ((binding != NULL) && (binding->value != NULL)) { binding->value->type = binding_function; (fundef_reference (&binding->value->value.fundef, r->data.set.expr->data.func, MDL)); } } } #if defined (DEBUG_EXPRESSIONS) log_debug ("exec: set %s%s", r -> data.set.name, (binding && status ? "" : " (failed)")); #endif break; case unset_statement: if (!scope || !*scope) { status = 0; break; } binding = find_binding (*scope, r -> data.unset); if (binding) { if (binding -> value) binding_value_dereference (&binding -> value, MDL); status = 1; } else status = 0; #if defined (DEBUG_EXPRESSIONS) log_debug ("exec: unset %s: %s", r -> data.unset, (status ? "found" : "not found")); #endif break; case let_statement: #if defined (DEBUG_EXPRESSIONS) log_debug ("exec: let %s", r -> data.let.name); #endif ns = (struct binding_scope *)0; binding_scope_allocate (&ns, MDL); e = r; next_let: if (ns) { binding = dmalloc (sizeof *binding, MDL); memset (binding, 0, sizeof *binding); if (!binding) { blb: binding_scope_dereference (&ns, MDL); } else { binding -> name = dmalloc (strlen (e -> data.let.name + 1), MDL); if (binding -> name) strcpy (binding -> name, e -> data.let.name); else { dfree (binding, MDL); binding = (struct binding *)0; goto blb; } } } else binding = NULL; if (ns && binding) { status = (evaluate_expression (&binding -> value, packet, lease, client_state, in_options, out_options, scope, e -> data.set.expr, MDL)); binding -> next = ns -> bindings; ns -> bindings = binding; } #if defined (DEBUG_EXPRESSIONS) log_debug ("exec: let %s%s", e -> data.let.name, (binding && status ? "" : "failed")); #endif if (!e -> data.let.statements) { } else if (e -> data.let.statements -> op == let_statement) { e = e -> data.let.statements; goto next_let; } else if (ns) { if (scope && *scope) binding_scope_reference (&ns -> outer, *scope, MDL); execute_statements (result, packet, lease, client_state, in_options, out_options, &ns, e -> data.let.statements); } if (ns) binding_scope_dereference (&ns, MDL); break; case log_statement: memset (&ds, 0, sizeof ds); status = (evaluate_data_expression (&ds, packet, lease, client_state, in_options, out_options, scope, r -> data.log.expr, MDL)); #if defined (DEBUG_EXPRESSIONS) log_debug ("exec: log"); #endif if (status) { switch (r -> data.log.priority) { case log_priority_fatal: log_fatal ("%.*s", (int)ds.len, ds.data); break; case log_priority_error: log_error ("%.*s", (int)ds.len, ds.data); break; case log_priority_debug: log_debug ("%.*s", (int)ds.len, ds.data); break; case log_priority_info: log_info ("%.*s", (int)ds.len, ds.data); break; } data_string_forget (&ds, MDL); } break; default: log_error ("bogus statement type %d", r -> op); break; } executable_statement_dereference (&r, MDL); if (next) { executable_statement_reference (&r, next, MDL); executable_statement_dereference (&next, MDL); } } return 1; } /* Execute all the statements in a particular scope, and all statements in scopes outer from that scope, but if a particular limiting scope is reached, do not execute statements in that scope or in scopes outer from it. More specific scopes need to take precedence over less specific scopes, so we recursively traverse the scope list, executing the most outer scope first. */ void execute_statements_in_scope (result, packet, lease, client_state, in_options, out_options, scope, group, limiting_group) struct binding_value **result; struct packet *packet; struct lease *lease; struct client_state *client_state; struct option_state *in_options; struct option_state *out_options; struct binding_scope **scope; struct group *group; struct group *limiting_group; { struct group *limit; /* If we've recursed as far as we can, return. */ if (!group) return; /* As soon as we get to a scope that is outer than the limiting scope, we are done. This is so that if somebody does something like this, it does the expected thing: domain-name "fugue.com"; shared-network FOO { host bar { domain-name "othello.fugue.com"; fixed-address 10.20.30.40; } subnet 10.20.30.0 netmask 255.255.255.0 { domain-name "manhattan.fugue.com"; } } The problem with the above arrangement is that the host's group nesting will be host -> shared-network -> top-level, and the limiting scope when we evaluate the host's scope will be the subnet -> shared-network -> top-level, so we need to know when we evaluate the host's scope to stop before we evaluate the shared-networks scope, because it's outer than the limiting scope, which means we've already evaluated it. */ for (limit = limiting_group; limit; limit = limit -> next) { if (group == limit) return; } if (group -> next) execute_statements_in_scope (result, packet, lease, client_state, in_options, out_options, scope, group -> next, limiting_group); execute_statements (result, packet, lease, client_state, in_options, out_options, scope, group -> statements); } /* Dereference or free any subexpressions of a statement being freed. */ int executable_statement_dereference (ptr, file, line) struct executable_statement **ptr; const char *file; int line; { if (!ptr || !*ptr) { log_error ("%s(%d): null pointer", file, line); #if defined (POINTER_DEBUG) abort (); #else return 0; #endif } (*ptr) -> refcnt--; rc_register (file, line, ptr, *ptr, (*ptr) -> refcnt, 1, RC_MISC); if ((*ptr) -> refcnt > 0) { *ptr = (struct executable_statement *)0; return 1; } if ((*ptr) -> refcnt < 0) { log_error ("%s(%d): negative refcnt!", file, line); #if defined (DEBUG_RC_HISTORY) dump_rc_history (*ptr); #endif #if defined (POINTER_DEBUG) abort (); #else return 0; #endif } if ((*ptr) -> next) executable_statement_dereference (&(*ptr) -> next, file, line); switch ((*ptr) -> op) { case statements_statement: if ((*ptr) -> data.statements) executable_statement_dereference (&(*ptr) -> data.statements, file, line); break; case on_statement: if ((*ptr) -> data.on.statements) executable_statement_dereference (&(*ptr) -> data.on.statements, file, line); break; case switch_statement: if ((*ptr) -> data.s_switch.statements) executable_statement_dereference (&(*ptr) -> data.on.statements, file, line); if ((*ptr) -> data.s_switch.expr) expression_dereference (&(*ptr) -> data.s_switch.expr, file, line); break; case case_statement: if ((*ptr) -> data.s_switch.expr) expression_dereference (&(*ptr) -> data.c_case, file, line); break; case if_statement: if ((*ptr) -> data.ie.expr) expression_dereference (&(*ptr) -> data.ie.expr, file, line); if ((*ptr) -> data.ie.tc) executable_statement_dereference (&(*ptr) -> data.ie.tc, file, line); if ((*ptr) -> data.ie.fc) executable_statement_dereference (&(*ptr) -> data.ie.fc, file, line); break; case eval_statement: if ((*ptr) -> data.eval) expression_dereference (&(*ptr) -> data.eval, file, line); break; case return_statement: if ((*ptr) -> data.eval) expression_dereference (&(*ptr) -> data.eval, file, line); break; case set_statement: if ((*ptr)->data.set.name) dfree ((*ptr)->data.set.name, file, line); if ((*ptr)->data.set.expr) expression_dereference (&(*ptr) -> data.set.expr, file, line); break; case unset_statement: if ((*ptr)->data.unset) dfree ((*ptr)->data.unset, file, line); break; case execute_statement: if ((*ptr)->data.execute.command) dfree ((*ptr)->data.execute.command, file, line); if ((*ptr)->data.execute.arglist) expression_dereference (&(*ptr) -> data.execute.arglist, file, line); break; case supersede_option_statement: case send_option_statement: case default_option_statement: case append_option_statement: case prepend_option_statement: if ((*ptr) -> data.option) option_cache_dereference (&(*ptr) -> data.option, file, line); break; default: /* Nothing to do. */ break; } dfree ((*ptr), file, line); *ptr = (struct executable_statement *)0; return 1; } void write_statements (file, statements, indent) FILE *file; struct executable_statement *statements; int indent; { #if defined ENABLE_EXECUTE struct expression *expr; #endif struct executable_statement *r, *x; const char *s, *t, *dot; int col; if (!statements) return; for (r = statements; r; r = r -> next) { switch (r -> op) { case statements_statement: write_statements (file, r -> data.statements, indent); break; case on_statement: indent_spaces (file, indent); fprintf (file, "on "); s = ""; if (r -> data.on.evtypes & ON_EXPIRY) { fprintf (file, "%sexpiry", s); s = " or "; } if (r -> data.on.evtypes & ON_COMMIT) { fprintf (file, "%scommit", s); s = "or"; } if (r -> data.on.evtypes & ON_RELEASE) { fprintf (file, "%srelease", s); s = "or"; } if (r -> data.on.statements) { fprintf (file, " {"); write_statements (file, r -> data.on.statements, indent + 2); indent_spaces (file, indent); fprintf (file, "}"); } else { fprintf (file, ";"); } break; case switch_statement: indent_spaces (file, indent); fprintf (file, "switch ("); col = write_expression (file, r -> data.s_switch.expr, indent + 7, indent + 7, 1); col = token_print_indent (file, col, indent + 7, "", "", ")"); token_print_indent (file, col, indent, " ", "", "{"); write_statements (file, r -> data.s_switch.statements, indent + 2); indent_spaces (file, indent); fprintf (file, "}"); break; case case_statement: indent_spaces (file, indent - 1); fprintf (file, "case "); col = write_expression (file, r -> data.s_switch.expr, indent + 5, indent + 5, 1); token_print_indent (file, col, indent + 5, "", "", ":"); break; case default_statement: indent_spaces (file, indent - 1); fprintf (file, "default: "); break; case if_statement: indent_spaces (file, indent); fprintf (file, "if "); x = r; col = write_expression (file, x -> data.ie.expr, indent + 3, indent + 3, 1); else_if: token_print_indent (file, col, indent, " ", "", "{"); write_statements (file, x -> data.ie.tc, indent + 2); if (x -> data.ie.fc && x -> data.ie.fc -> op == if_statement && !x -> data.ie.fc -> next) { indent_spaces (file, indent); fprintf (file, "} elsif "); x = x -> data.ie.fc; col = write_expression (file, x -> data.ie.expr, indent + 6, indent + 6, 1); goto else_if; } if (x -> data.ie.fc) { indent_spaces (file, indent); fprintf (file, "} else {"); write_statements (file, x -> data.ie.fc, indent + 2); } indent_spaces (file, indent); fprintf (file, "}"); break; case eval_statement: indent_spaces (file, indent); fprintf (file, "eval "); col = write_expression (file, r -> data.eval, indent + 5, indent + 5, 1); fprintf (file, ";"); break; case return_statement: indent_spaces (file, indent); fprintf (file, "return;"); break; case add_statement: indent_spaces (file, indent); fprintf (file, "add \"%s\"", r -> data.add -> name); break; case break_statement: indent_spaces (file, indent); fprintf (file, "break;"); break; case supersede_option_statement: case send_option_statement: s = "supersede"; goto option_statement; case default_option_statement: s = "default"; goto option_statement; case append_option_statement: s = "append"; goto option_statement; case prepend_option_statement: s = "prepend"; option_statement: /* Note: the reason we don't try to pretty print the option here is that the format of the option may change in dhcpd.conf, and then when this statement was read back, it would cause a syntax error. */ if (r -> data.option -> option -> universe == &dhcp_universe) { t = ""; dot = ""; } else { t = (r -> data.option -> option -> universe -> name); dot = "."; } indent_spaces (file, indent); fprintf (file, "%s %s%s%s = ", s, t, dot, r -> data.option -> option -> name); col = (indent + strlen (s) + strlen (t) + strlen (dot) + strlen (r -> data.option -> option -> name) + 4); if (r -> data.option -> expression) write_expression (file, r -> data.option -> expression, col, indent + 8, 1); else token_indent_data_string (file, col, indent + 8, "", "", &r -> data.option -> data); fprintf (file, ";"); /* XXX */ break; case set_statement: indent_spaces (file, indent); fprintf (file, "set "); col = token_print_indent (file, indent + 4, indent + 4, "", "", r -> data.set.name); col = token_print_indent (file, col, indent + 4, " ", " ", "="); col = write_expression (file, r -> data.set.expr, indent + 3, indent + 3, 0); col = token_print_indent (file, col, indent + 4, " ", "", ";"); break; case unset_statement: indent_spaces (file, indent); fprintf (file, "unset "); col = token_print_indent (file, indent + 6, indent + 6, "", "", r -> data.set.name); col = token_print_indent (file, col, indent + 6, " ", "", ";"); break; case log_statement: indent_spaces (file, indent); fprintf (file, "log "); col = token_print_indent (file, indent + 4, indent + 4, "", "", "("); switch (r -> data.log.priority) { case log_priority_fatal: col = token_print_indent (file, col, indent + 4, "", " ", "fatal,"); break; case log_priority_error: col = token_print_indent (file, col, indent + 4, "", " ", "error,"); break; case log_priority_debug: col = token_print_indent (file, col, indent + 4, "", " ", "debug,"); break; case log_priority_info: col = token_print_indent (file, col, indent + 4, "", " ", "info,"); break; } col = write_expression (file, r -> data.log.expr, indent + 4, indent + 4, 0); col = token_print_indent (file, col, indent + 4, "", "", ");"); break; case execute_statement: #ifdef ENABLE_EXECUTE indent_spaces (file, indent); col = token_print_indent(file, indent + 4, indent + 4, "", "", "execute"); col = token_print_indent(file, col, indent + 4, " ", "", "("); col = token_print_indent(file, col, indent + 4, "\"", "\"", r->data.execute.command); for (expr = r->data.execute.arglist; expr; expr = expr->data.arg.next) { col = token_print_indent(file, col, indent + 4, "", " ", ","); col = write_expression (file, expr->data.arg.val, col, indent + 4, 0); } col = token_print_indent(file, col, indent + 4, "", "", ");"); #else /* !ENABLE_EXECUTE */ log_fatal("Impossible case at %s:%d (ENABLE_EXECUTE " "is not defined).", MDL); #endif /* ENABLE_EXECUTE */ break; default: log_fatal ("bogus statement type %d\n", r -> op); } } } /* Find a case statement in the sequence of executable statements that matches the expression, and if found, return the following statement. If no case statement matches, try to find a default statement and return that (the default statement can precede all the case statements). Otherwise, return the null statement. */ int find_matching_case (struct executable_statement **ep, struct packet *packet, struct lease *lease, struct client_state *client_state, struct option_state *in_options, struct option_state *out_options, struct binding_scope **scope, struct expression *expr, struct executable_statement *stmt) { int status, sub; struct executable_statement *s; if (is_data_expression (expr)) { struct data_string cd, ds; memset (&ds, 0, sizeof ds); memset (&cd, 0, sizeof cd); status = (evaluate_data_expression (&ds, packet, lease, client_state, in_options, out_options, scope, expr, MDL)); if (status) { for (s = stmt; s; s = s -> next) { if (s -> op == case_statement) { sub = (evaluate_data_expression (&cd, packet, lease, client_state, in_options, out_options, scope, s -> data.c_case, MDL)); if (sub && cd.len == ds.len && !memcmp (cd.data, ds.data, cd.len)) { data_string_forget (&cd, MDL); data_string_forget (&ds, MDL); executable_statement_reference (ep, s -> next, MDL); return 1; } data_string_forget (&cd, MDL); } } data_string_forget (&ds, MDL); } } else { unsigned long n, c; status = evaluate_numeric_expression (&n, packet, lease, client_state, in_options, out_options, scope, expr); if (status) { for (s = stmt; s; s = s -> next) { if (s -> op == case_statement) { sub = (evaluate_numeric_expression (&c, packet, lease, client_state, in_options, out_options, scope, s -> data.c_case)); if (sub && n == c) { executable_statement_reference (ep, s -> next, MDL); return 1; } } } } } /* If we didn't find a matching case statement, look for a default statement and return the statement following it. */ for (s = stmt; s; s = s -> next) if (s -> op == default_statement) break; if (s) { executable_statement_reference (ep, s -> next, MDL); return 1; } return 0; } int executable_statement_foreach (struct executable_statement *stmt, int (*callback) (struct executable_statement *, void *, int), void *vp, int condp) { struct executable_statement *foo; int ok = 0; for (foo = stmt; foo; foo = foo -> next) { if ((*callback) (foo, vp, condp) != 0) ok = 1; switch (foo -> op) { case null_statement: break; case if_statement: if (executable_statement_foreach (foo -> data.ie.tc, callback, vp, 1)) ok = 1; if (executable_statement_foreach (foo -> data.ie.fc, callback, vp, 1)) ok = 1; break; case add_statement: break; case eval_statement: break; case break_statement: break; case default_option_statement: break; case supersede_option_statement: break; case append_option_statement: break; case prepend_option_statement: break; case send_option_statement: break; case statements_statement: if ((executable_statement_foreach (foo -> data.statements, callback, vp, condp))) ok = 1; break; case on_statement: if ((executable_statement_foreach (foo -> data.on.statements, callback, vp, 1))) ok = 1; break; case switch_statement: if ((executable_statement_foreach (foo -> data.s_switch.statements, callback, vp, 1))) ok = 1; break; case case_statement: break; case default_statement: break; case set_statement: break; case unset_statement: break; case let_statement: if ((executable_statement_foreach (foo -> data.let.statements, callback, vp, 0))) ok = 1; break; case define_statement: break; case log_statement: case return_statement: case execute_statement: break; } } return ok; } dhcp-4.2.4/common/fddi.c000644 000765 000024 00000005626 11301372614 014740 0ustar00sarstaff000000 000000 /* fddi.c Packet assembly code, originally contributed by Archie Cobbs. */ /* * Copyright (c) 2004,2007,2009 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1996-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ * * This software has been written for Internet Systems Consortium * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. * To learn more about Internet Systems Consortium, see * ``https://www.isc.org/''. To learn more about Vixie Enterprises, * see ``http://www.vix.com''. To learn more about Nominum, Inc., see * ``http://www.nominum.com''. */ #include "dhcpd.h" #if defined (DEC_FDDI) #include #include #if defined (PACKET_ASSEMBLY) || defined (PACKET_DECODING) #include "includes/netinet/if_ether.h" #endif /* PACKET_ASSEMBLY || PACKET_DECODING */ #if defined (PACKET_ASSEMBLY) /* Assemble an hardware header... */ void assemble_fddi_header (interface, buf, bufix, to) struct interface_info *interface; unsigned char *buf; unsigned *bufix; struct hardware *to; { struct fddi_header fh; struct llc lh; if (to && to -> hlen == 7) memcpy (fh.fddi_dhost, &to -> hbuf [1], sizeof (fh.fddi_dhost)); memcpy (fh.fddi_shost, &interface -> hw_address.hbuf [1], sizeof (fh.fddi_shost)); fh.fddi_fc = FDDIFC_LLC_ASYNC; memcpy (&buf [*bufix], &fh, sizeof fh); *bufix += sizeof fh; lh.llc_dsap = LLC_SNAP_LSAP; lh.llc_ssap = LLC_SNAP_LSAP; lh.llc_un.type_snap.control = LLC_UI; lh.llc_un.type_snap.ether_type = htons (ETHERTYPE_IP); memcpy (&buf [*bufix], &lh, LLC_SNAP_LEN); *bufix += LLC_SNAP_LEN; } #endif /* PACKET_ASSEMBLY */ #ifdef PACKET_DECODING /* Decode a hardware header... */ ssize_t decode_fddi_header (interface, buf, bufix, from) struct interface_info *interface; unsigned char *buf; unsigned bufix; struct hardware *from; { struct fddi_header fh; struct llc lh; from -> hbuf [0] = HTYPE_FDDI; memcpy (&from -> hbuf [1], fh.fddi_shost, sizeof fh.fddi_shost); return FDDI_HEADER_SIZE + LLC_SNAP_LEN; } #endif /* PACKET_DECODING */ #endif /* DEC_FDDI */ dhcp-4.2.4/common/icmp.c000644 000765 000024 00000020050 11562515513 014754 0ustar00sarstaff000000 000000 /* dhcp.c ICMP Protocol engine - for sending out pings and receiving responses. */ /* * Copyright (c) 2011 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 2004,2007,2009 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1996-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ * * This software has been written for Internet Systems Consortium * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. * To learn more about Internet Systems Consortium, see * ``https://www.isc.org/''. To learn more about Vixie Enterprises, * see ``http://www.vix.com''. To learn more about Nominum, Inc., see * ``http://www.nominum.com''. */ #include "dhcpd.h" #include "netinet/ip.h" #include "netinet/ip_icmp.h" struct icmp_state *icmp_state; static omapi_object_type_t *dhcp_type_icmp; static int no_icmp; OMAPI_OBJECT_ALLOC (icmp_state, struct icmp_state, dhcp_type_icmp) #if defined (TRACING) trace_type_t *trace_icmp_input; trace_type_t *trace_icmp_output; #endif /* Initialize the ICMP protocol. */ void icmp_startup (routep, handler) int routep; void (*handler) (struct iaddr, u_int8_t *, int); { struct protoent *proto; int protocol = 1; int state; isc_result_t result; /* Only initialize icmp once. */ if (dhcp_type_icmp) log_fatal ("attempted to reinitialize icmp protocol"); result = omapi_object_type_register (&dhcp_type_icmp, "icmp", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, sizeof (struct icmp_state), 0, RC_MISC); if (result != ISC_R_SUCCESS) log_fatal ("Can't register icmp object type: %s", isc_result_totext (result)); icmp_state_allocate (&icmp_state, MDL); icmp_state -> icmp_handler = handler; #if defined (TRACING) trace_icmp_input = trace_type_register ("icmp-input", (void *)0, trace_icmp_input_input, trace_icmp_input_stop, MDL); trace_icmp_output = trace_type_register ("icmp-output", (void *)0, trace_icmp_output_input, trace_icmp_output_stop, MDL); /* If we're playing back a trace file, don't create the socket or set up the callback. */ if (!trace_playback ()) { #endif /* Get the protocol number (should be 1). */ proto = getprotobyname ("icmp"); if (proto) protocol = proto -> p_proto; /* Get a raw socket for the ICMP protocol. */ icmp_state -> socket = socket (AF_INET, SOCK_RAW, protocol); if (icmp_state -> socket < 0) { no_icmp = 1; log_error ("unable to create icmp socket: %m"); return; } #if defined (HAVE_SETFD) if (fcntl (icmp_state -> socket, F_SETFD, 1) < 0) log_error ("Can't set close-on-exec on icmp: %m"); #endif /* Make sure it does routing... */ state = 0; if (setsockopt (icmp_state -> socket, SOL_SOCKET, SO_DONTROUTE, (char *)&state, sizeof state) < 0) log_fatal ("Can't disable SO_DONTROUTE on ICMP: %m"); result = (omapi_register_io_object ((omapi_object_t *)icmp_state, icmp_readsocket, 0, icmp_echoreply, 0, 0)); if (result != ISC_R_SUCCESS) log_fatal ("Can't register icmp handle: %s", isc_result_totext (result)); #if defined (TRACING) } #endif } int icmp_readsocket (h) omapi_object_t *h; { struct icmp_state *state; state = (struct icmp_state *)h; return state -> socket; } int icmp_echorequest (addr) struct iaddr *addr; { struct sockaddr_in to; struct icmp icmp; int status; #if defined (TRACING) trace_iov_t iov [2]; #endif if (no_icmp) return 1; if (!icmp_state) log_fatal ("ICMP protocol used before initialization."); memset (&to, 0, sizeof(to)); #ifdef HAVE_SA_LEN to.sin_len = sizeof to; #endif to.sin_family = AF_INET; to.sin_port = 0; /* unused. */ memcpy (&to.sin_addr, addr -> iabuf, sizeof to.sin_addr); /* XXX */ icmp.icmp_type = ICMP_ECHO; icmp.icmp_code = 0; icmp.icmp_cksum = 0; icmp.icmp_seq = 0; #if SIZEOF_STRUCT_IADDR_P == 8 icmp.icmp_id = (((u_int32_t)(u_int64_t)addr) ^ (u_int32_t)(((u_int64_t)addr) >> 32)); #else icmp.icmp_id = (u_int32_t)addr; #endif memset (&icmp.icmp_dun, 0, sizeof icmp.icmp_dun); icmp.icmp_cksum = wrapsum (checksum ((unsigned char *)&icmp, sizeof icmp, 0)); #if defined (TRACING) if (trace_playback ()) { char *buf = (char *)0; unsigned buflen = 0; /* Consume the ICMP event. */ status = trace_get_packet (&trace_icmp_output, &buflen, &buf); if (status != ISC_R_SUCCESS) log_error ("icmp_echorequest: %s", isc_result_totext (status)); if (buf) dfree (buf, MDL); } else { if (trace_record ()) { iov [0].buf = (char *)addr; iov [0].len = sizeof *addr; iov [1].buf = (char *)&icmp; iov [1].len = sizeof icmp; trace_write_packet_iov (trace_icmp_output, 2, iov, MDL); } #endif /* Send the ICMP packet... */ status = sendto (icmp_state -> socket, (char *)&icmp, sizeof icmp, 0, (struct sockaddr *)&to, sizeof to); if (status < 0) log_error ("icmp_echorequest %s: %m", inet_ntoa(to.sin_addr)); if (status != sizeof icmp) return 0; #if defined (TRACING) } #endif return 1; } isc_result_t icmp_echoreply (h) omapi_object_t *h; { struct icmp *icfrom; struct ip *ip; struct sockaddr_in from; u_int8_t icbuf [1500]; int status; SOCKLEN_T sl; int hlen, len; struct iaddr ia; struct icmp_state *state; #if defined (TRACING) trace_iov_t iov [2]; #endif state = (struct icmp_state *)h; sl = sizeof from; status = recvfrom (state -> socket, (char *)icbuf, sizeof icbuf, 0, (struct sockaddr *)&from, &sl); if (status < 0) { log_error ("icmp_echoreply: %m"); return ISC_R_UNEXPECTED; } /* Find the IP header length... */ ip = (struct ip *)icbuf; hlen = IP_HL (ip); /* Short packet? */ if (status < hlen + (sizeof *icfrom)) { return ISC_R_SUCCESS; } len = status - hlen; icfrom = (struct icmp *)(icbuf + hlen); /* Silently discard ICMP packets that aren't echoreplies. */ if (icfrom -> icmp_type != ICMP_ECHOREPLY) { return ISC_R_SUCCESS; } /* If we were given a second-stage handler, call it. */ if (state -> icmp_handler) { memcpy (ia.iabuf, &from.sin_addr, sizeof from.sin_addr); ia.len = sizeof from.sin_addr; #if defined (TRACING) if (trace_record ()) { ia.len = htonl(ia.len); iov [0].buf = (char *)&ia; iov [0].len = sizeof ia; iov [1].buf = (char *)icbuf; iov [1].len = len; trace_write_packet_iov (trace_icmp_input, 2, iov, MDL); ia.len = ntohl(ia.len); } #endif (*state -> icmp_handler) (ia, icbuf, len); } return ISC_R_SUCCESS; } #if defined (TRACING) void trace_icmp_input_input (trace_type_t *ttype, unsigned length, char *buf) { struct iaddr *ia; u_int8_t *icbuf; ia = (struct iaddr *)buf; ia->len = ntohl(ia->len); icbuf = (u_int8_t *)(ia + 1); if (icmp_state -> icmp_handler) (*icmp_state -> icmp_handler) (*ia, icbuf, (int)(length - sizeof ia)); } void trace_icmp_input_stop (trace_type_t *ttype) { } void trace_icmp_output_input (trace_type_t *ttype, unsigned length, char *buf) { struct icmp *icmp; struct iaddr ia; if (length != (sizeof (*icmp) + (sizeof ia))) { log_error ("trace_icmp_output_input: data size mismatch %d:%d", length, (int)((sizeof (*icmp)) + (sizeof ia))); return; } ia.len = 4; memcpy (ia.iabuf, buf, 4); icmp = (struct icmp *)(buf + 1); log_error ("trace_icmp_output_input: unsent ping to %s", piaddr (ia)); } void trace_icmp_output_stop (trace_type_t *ttype) { } #endif /* TRACING */ dhcp-4.2.4/common/inet.c000644 000765 000024 00000035051 11562356232 014773 0ustar00sarstaff000000 000000 /* inet.c Subroutines to manipulate internet addresses and ports in a safely portable way... */ /* * Copyright (c) 2011 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 2007-2009 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 2004,2005 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1995-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ * * This software has been written for Internet Systems Consortium * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. * To learn more about Internet Systems Consortium, see * ``https://www.isc.org/''. To learn more about Vixie Enterprises, * see ``http://www.vix.com''. To learn more about Nominum, Inc., see * ``http://www.nominum.com''. */ #include "dhcpd.h" /* Return just the network number of an internet address... */ struct iaddr subnet_number (addr, mask) struct iaddr addr; struct iaddr mask; { int i; struct iaddr rv; if (addr.len > sizeof(addr.iabuf)) log_fatal("subnet_number():%s:%d: Invalid addr length.", MDL); if (addr.len != mask.len) log_fatal("subnet_number():%s:%d: Addr/mask length mismatch.", MDL); rv.len = 0; /* Both addresses must have the same length... */ if (addr.len != mask.len) return rv; rv.len = addr.len; for (i = 0; i < rv.len; i++) rv.iabuf [i] = addr.iabuf [i] & mask.iabuf [i]; return rv; } /* Combine a network number and a integer to produce an internet address. This won't work for subnets with more than 32 bits of host address, but maybe this isn't a problem. */ struct iaddr ip_addr (subnet, mask, host_address) struct iaddr subnet; struct iaddr mask; u_int32_t host_address; { int i, j, k; u_int32_t swaddr; struct iaddr rv; unsigned char habuf [sizeof swaddr]; if (subnet.len > sizeof(subnet.iabuf)) log_fatal("ip_addr():%s:%d: Invalid addr length.", MDL); if (subnet.len != mask.len) log_fatal("ip_addr():%s:%d: Addr/mask length mismatch.", MDL); swaddr = htonl (host_address); memcpy (habuf, &swaddr, sizeof swaddr); /* Combine the subnet address and the host address. If the host address is bigger than can fit in the subnet, return a zero-length iaddr structure. */ rv = subnet; j = rv.len - sizeof habuf; for (i = sizeof habuf - 1; i >= 0; i--) { if (mask.iabuf [i + j]) { if (habuf [i] > (mask.iabuf [i + j] ^ 0xFF)) { rv.len = 0; return rv; } for (k = i - 1; k >= 0; k--) { if (habuf [k]) { rv.len = 0; return rv; } } rv.iabuf [i + j] |= habuf [i]; break; } else rv.iabuf [i + j] = habuf [i]; } return rv; } /* Given a subnet number and netmask, return the address on that subnet for which the host portion of the address is all ones (the standard broadcast address). */ struct iaddr broadcast_addr (subnet, mask) struct iaddr subnet; struct iaddr mask; { int i; struct iaddr rv; if (subnet.len > sizeof(subnet.iabuf)) log_fatal("broadcast_addr():%s:%d: Invalid addr length.", MDL); if (subnet.len != mask.len) log_fatal("broadcast_addr():%s:%d: Addr/mask length mismatch.", MDL); if (subnet.len != mask.len) { rv.len = 0; return rv; } for (i = 0; i < subnet.len; i++) { rv.iabuf [i] = subnet.iabuf [i] | (~mask.iabuf [i] & 255); } rv.len = subnet.len; return rv; } u_int32_t host_addr (addr, mask) struct iaddr addr; struct iaddr mask; { int i; u_int32_t swaddr; struct iaddr rv; if (addr.len > sizeof(addr.iabuf)) log_fatal("host_addr():%s:%d: Invalid addr length.", MDL); if (addr.len != mask.len) log_fatal("host_addr():%s:%d: Addr/mask length mismatch.", MDL); rv.len = 0; /* Mask out the network bits... */ rv.len = addr.len; for (i = 0; i < rv.len; i++) rv.iabuf [i] = addr.iabuf [i] & ~mask.iabuf [i]; /* Copy out up to 32 bits... */ memcpy (&swaddr, &rv.iabuf [rv.len - sizeof swaddr], sizeof swaddr); /* Swap it and return it. */ return ntohl (swaddr); } int addr_eq (addr1, addr2) struct iaddr addr1, addr2; { if (addr1.len > sizeof(addr1.iabuf)) log_fatal("addr_eq():%s:%d: Invalid addr length.", MDL); if (addr1.len != addr2.len) return 0; return memcmp (addr1.iabuf, addr2.iabuf, addr1.len) == 0; } /* addr_match * * compares an IP address against a network/mask combination * by ANDing the IP with the mask and seeing whether the result * matches the masked network value. */ int addr_match(addr, match) struct iaddr *addr; struct iaddrmatch *match; { int i; if (addr->len != match->addr.len) return 0; i = 0; for (i = 0 ; i < addr->len ; i++) { if ((addr->iabuf[i] & match->mask.iabuf[i]) != match->addr.iabuf[i]) return 0; } return 1; } /* * Compares the addresses a1 and a2. * * If a1 < a2, returns -1. * If a1 == a2, returns 0. * If a1 > a2, returns 1. * * WARNING: if a1 and a2 differ in length, returns 0. */ int addr_cmp(const struct iaddr *a1, const struct iaddr *a2) { int i; if (a1->len != a2->len) { return 0; } for (i=0; ilen; i++) { if (a1->iabuf[i] < a2->iabuf[i]) { return -1; } if (a1->iabuf[i] > a2->iabuf[i]) { return 1; } } return 0; } /* * Performs a bitwise-OR of two addresses. * * Returns 1 if the result is non-zero, or 0 otherwise. * * WARNING: if a1 and a2 differ in length, returns 0. */ int addr_or(struct iaddr *result, const struct iaddr *a1, const struct iaddr *a2) { int i; int all_zero; if (a1->len != a2->len) { return 0; } all_zero = 1; result->len = a1->len; for (i=0; ilen; i++) { result->iabuf[i] = a1->iabuf[i] | a2->iabuf[i]; if (result->iabuf[i] != 0) { all_zero = 0; } } return !all_zero; } /* * Performs a bitwise-AND of two addresses. * * Returns 1 if the result is non-zero, or 0 otherwise. * * WARNING: if a1 and a2 differ in length, returns 0. */ int addr_and(struct iaddr *result, const struct iaddr *a1, const struct iaddr *a2) { int i; int all_zero; if (a1->len != a2->len) { return 0; } all_zero = 1; result->len = a1->len; for (i=0; ilen; i++) { result->iabuf[i] = a1->iabuf[i] & a2->iabuf[i]; if (result->iabuf[i] != 0) { all_zero = 0; } } return !all_zero; } /* * Check if a bitmask of the given length is valid for the address. * This is not the case if any bits longer than the bitmask are 1. * * So, this is valid: * * 127.0.0.0/8 * * But this is not: * * 127.0.0.1/8 * * Because the final ".1" would get masked out by the /8. */ isc_boolean_t is_cidr_mask_valid(const struct iaddr *addr, int bits) { int zero_bits; int zero_bytes; int i; char byte; int shift_bits; /* * Check our bit boundaries. */ if (bits < 0) { return ISC_FALSE; } if (bits > (addr->len * 8)) { return ISC_FALSE; } /* * Figure out how many low-order bits need to be zero. */ zero_bits = (addr->len * 8) - bits; zero_bytes = zero_bits / 8; /* * Check to make sure the low-order bytes are zero. */ for (i=1; i<=zero_bytes; i++) { if (addr->iabuf[addr->len-i] != 0) { return ISC_FALSE; } } /* * Look to see if any bits not in right-hand bytes are * non-zero, by making a byte that has these bits set to zero * comparing to the original byte. If these two values are * equal, then the right-hand bits are zero, and we are * happy. */ shift_bits = zero_bits % 8; if (shift_bits == 0) return ISC_TRUE; byte = addr->iabuf[addr->len-zero_bytes-1]; return (((byte >> shift_bits) << shift_bits) == byte); } /* * range2cidr * * Converts a range of IP addresses to a set of CIDR networks. * * Examples: * 192.168.0.0 - 192.168.0.255 = 192.168.0.0/24 * 10.0.0.0 - 10.0.1.127 = 10.0.0.0/24, 10.0.1.0/25 * 255.255.255.32 - 255.255.255.255 = 255.255.255.32/27, 255.255.255.64/26, * 255.255.255.128/25 */ isc_result_t range2cidr(struct iaddrcidrnetlist **result, const struct iaddr *lo, const struct iaddr *hi) { struct iaddr addr; struct iaddr mask; int bit; struct iaddr end_addr; struct iaddr dummy; int ofs, val; struct iaddrcidrnetlist *net; int tmp; if (result == NULL) { return DHCP_R_INVALIDARG; } if (*result != NULL) { return DHCP_R_INVALIDARG; } if ((lo == NULL) || (hi == NULL) || (lo->len != hi->len)) { return DHCP_R_INVALIDARG; } /* * Put our start and end in the right order, if reversed. */ if (addr_cmp(lo, hi) > 0) { const struct iaddr *tmp; tmp = lo; lo = hi; hi = tmp; } /* * Theory of operation: * * ------------------- * Start at the low end, and keep trying larger networks * until we get one that is too big (explained below). * * We keep a "mask", which is the ones-complement of a * normal netmask. So, a /23 has a netmask of 255.255.254.0, * and a mask of 0.0.1.255. * * We know when a network is too big when we bitwise-AND the * mask with the starting address and we get a non-zero * result, like this: * * addr: 192.168.1.0, mask: 0.0.1.255 * bitwise-AND: 0.0.1.0 * * A network is also too big if the bitwise-OR of the mask * with the starting address is larger than the end address, * like this: * * start: 192.168.1.0, mask: 0.0.1.255, end: 192.168.0.255 * bitwise-OR: 192.168.1.255 * * ------------------- * Once we have found a network that is too big, we add the * appropriate CIDR network to our list of found networks. * * We then use the next IP address as our low address, and * begin the process of searching for a network that is * too big again, starting with an empty mask. */ addr = *lo; bit = 0; memset(&mask, 0, sizeof(mask)); mask.len = addr.len; while (addr_cmp(&addr, hi) <= 0) { /* * Bitwise-OR mask with (1 << bit) */ ofs = addr.len - (bit / 8) - 1; val = 1 << (bit % 8); if (ofs >= 0) { mask.iabuf[ofs] |= val; } /* * See if we're too big, and save this network if so. */ addr_or(&end_addr, &addr, &mask); if ((ofs < 0) || (addr_cmp(&end_addr, hi) > 0) || addr_and(&dummy, &addr, &mask)) { /* * Add a new prefix to our list. */ net = dmalloc(sizeof(*net), MDL); if (net == NULL) { while (*result != NULL) { net = (*result)->next; dfree(*result, MDL); *result = net; } return ISC_R_NOMEMORY; } net->cidrnet.lo_addr = addr; net->cidrnet.bits = (addr.len * 8) - bit; net->next = *result; *result = net; /* * Figure out our new starting address, * by adding (1 << bit) to our previous * starting address. */ tmp = addr.iabuf[ofs] + val; while ((ofs >= 0) && (tmp > 255)) { addr.iabuf[ofs] = tmp - 256; ofs--; tmp = addr.iabuf[ofs] + 1; } if (ofs < 0) { /* Gone past last address, we're done. */ break; } addr.iabuf[ofs] = tmp; /* * Reset our bit and mask. */ bit = 0; memset(mask.iabuf, 0, sizeof(mask.iabuf)); memset(end_addr.iabuf, 0, sizeof(end_addr.iabuf)); } else { /* * If we're not too big, increase our network size. */ bit++; } } /* * We're done. */ return ISC_R_SUCCESS; } /* * Free a list of CIDR networks, such as returned from range2cidr(). */ isc_result_t free_iaddrcidrnetlist(struct iaddrcidrnetlist **result) { struct iaddrcidrnetlist *p; if (result == NULL) { return DHCP_R_INVALIDARG; } if (*result == NULL) { return DHCP_R_INVALIDARG; } while (*result != NULL) { p = *result; *result = p->next; dfree(p, MDL); } return ISC_R_SUCCESS; } /* piaddr() turns an iaddr structure into a printable address. */ /* XXX: should use a const pointer rather than passing the structure */ const char * piaddr(const struct iaddr addr) { static char pbuf[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")]; /* "255.255.255.255" */ /* INSIST((addr.len == 0) || (addr.len == 4) || (addr.len == 16)); */ if (addr.len == 0) { return ""; } if (addr.len == 4) { return inet_ntop(AF_INET, addr.iabuf, pbuf, sizeof(pbuf)); } if (addr.len == 16) { return inet_ntop(AF_INET6, addr.iabuf, pbuf, sizeof(pbuf)); } log_fatal("piaddr():%s:%d: Invalid address length %d.", MDL, addr.len); /* quell compiler warnings */ return NULL; } /* piaddrmask takes an iaddr structure mask, determines the bitlength of * the mask, and then returns the printable CIDR notation of the two. */ char * piaddrmask(struct iaddr *addr, struct iaddr *mask) { int mw; unsigned int oct, bit; if ((addr->len != 4) && (addr->len != 16)) log_fatal("piaddrmask():%s:%d: Address length %d invalid", MDL, addr->len); if (addr->len != mask->len) log_fatal("piaddrmask():%s:%d: Address and mask size mismatch", MDL); /* Determine netmask width in bits. */ for (mw = (mask->len * 8) ; mw > 0 ; ) { oct = (mw - 1) / 8; bit = 0x80 >> ((mw - 1) % 8); if (!mask->iabuf[oct]) mw -= 8; else if (mask->iabuf[oct] & bit) break; else mw--; } if (mw < 0) log_fatal("Impossible condition at %s:%d.", MDL); return piaddrcidr(addr, mw); } /* Format an address and mask-length into printable CIDR notation. */ char * piaddrcidr(const struct iaddr *addr, unsigned int bits) { static char ret[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255/128")]; /* "255.255.255.255/32" */ /* INSIST(addr != NULL); */ /* INSIST((addr->len == 4) || (addr->len == 16)); */ /* INSIST(bits <= (addr->len * 8)); */ if (bits > (addr->len * 8)) return NULL; sprintf(ret, "%s/%d", piaddr(*addr), bits); return ret; } /* Validate that the string represents a valid port number and * return it in network byte order */ u_int16_t validate_port(char *port) { long local_port = 0; long lower = 1; long upper = 65535; char *endptr; errno = 0; local_port = strtol(port, &endptr, 10); if ((*endptr != '\0') || (errno == ERANGE) || (errno == EINVAL)) log_fatal ("Invalid port number specification: %s", port); if (local_port < lower || local_port > upper) log_fatal("Port number specified is out of range (%ld-%ld).", lower, upper); return htons((u_int16_t)local_port); } dhcp-4.2.4/common/lpf.c000644 000765 000024 00000031610 11562247002 014604 0ustar00sarstaff000000 000000 /* lpf.c Linux packet filter code, contributed by Brian Murrel at Interlinx Support Services in Vancouver, B.C. */ /* * Copyright (c) 2004,2007,2009 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1996-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ */ #include "dhcpd.h" #if defined (USE_LPF_SEND) || defined (USE_LPF_RECEIVE) #include #include #include #include #include #include #include #include #include "includes/netinet/ip.h" #include "includes/netinet/udp.h" #include "includes/netinet/if_ether.h" #include /* Reinitializes the specified interface after an address change. This is not required for packet-filter APIs. */ #ifdef USE_LPF_SEND void if_reinitialize_send (info) struct interface_info *info; { } #endif #ifdef USE_LPF_RECEIVE void if_reinitialize_receive (info) struct interface_info *info; { } #endif /* Called by get_interface_list for each interface that's discovered. Opens a packet filter for each interface and adds it to the select mask. */ int if_register_lpf (info) struct interface_info *info; { int sock; struct sockaddr sa; /* Make an LPF socket. */ if ((sock = socket(PF_PACKET, SOCK_PACKET, htons((short)ETH_P_ALL))) < 0) { if (errno == ENOPROTOOPT || errno == EPROTONOSUPPORT || errno == ESOCKTNOSUPPORT || errno == EPFNOSUPPORT || errno == EAFNOSUPPORT || errno == EINVAL) { log_error ("socket: %m - make sure"); log_error ("CONFIG_PACKET (Packet socket) %s", "and CONFIG_FILTER"); log_error ("(Socket Filtering) are enabled %s", "in your kernel"); log_fatal ("configuration!"); } log_fatal ("Open a socket for LPF: %m"); } /* Bind to the interface name */ memset (&sa, 0, sizeof sa); sa.sa_family = AF_PACKET; strncpy (sa.sa_data, (const char *)info -> ifp, sizeof sa.sa_data); if (bind (sock, &sa, sizeof sa)) { if (errno == ENOPROTOOPT || errno == EPROTONOSUPPORT || errno == ESOCKTNOSUPPORT || errno == EPFNOSUPPORT || errno == EAFNOSUPPORT || errno == EINVAL) { log_error ("socket: %m - make sure"); log_error ("CONFIG_PACKET (Packet socket) %s", "and CONFIG_FILTER"); log_error ("(Socket Filtering) are enabled %s", "in your kernel"); log_fatal ("configuration!"); } log_fatal ("Bind socket to interface: %m"); } get_hw_addr(info->name, &info->hw_address); return sock; } #endif /* USE_LPF_SEND || USE_LPF_RECEIVE */ #ifdef USE_LPF_SEND void if_register_send (info) struct interface_info *info; { /* If we're using the lpf API for sending and receiving, we don't need to register this interface twice. */ #ifndef USE_LPF_RECEIVE info -> wfdesc = if_register_lpf (info); #else info -> wfdesc = info -> rfdesc; #endif if (!quiet_interface_discovery) log_info ("Sending on LPF/%s/%s%s%s", info -> name, print_hw_addr (info -> hw_address.hbuf [0], info -> hw_address.hlen - 1, &info -> hw_address.hbuf [1]), (info -> shared_network ? "/" : ""), (info -> shared_network ? info -> shared_network -> name : "")); } void if_deregister_send (info) struct interface_info *info; { /* don't need to close twice if we are using lpf for sending and receiving */ #ifndef USE_LPF_RECEIVE /* for LPF this is simple, packet filters are removed when sockets are closed */ close (info -> wfdesc); #endif info -> wfdesc = -1; if (!quiet_interface_discovery) log_info ("Disabling output on LPF/%s/%s%s%s", info -> name, print_hw_addr (info -> hw_address.hbuf [0], info -> hw_address.hlen - 1, &info -> hw_address.hbuf [1]), (info -> shared_network ? "/" : ""), (info -> shared_network ? info -> shared_network -> name : "")); } #endif /* USE_LPF_SEND */ #ifdef USE_LPF_RECEIVE /* Defined in bpf.c. We can't extern these in dhcpd.h without pulling in bpf includes... */ extern struct sock_filter dhcp_bpf_filter []; extern int dhcp_bpf_filter_len; #if defined (HAVE_TR_SUPPORT) extern struct sock_filter dhcp_bpf_tr_filter []; extern int dhcp_bpf_tr_filter_len; static void lpf_tr_filter_setup (struct interface_info *); #endif static void lpf_gen_filter_setup (struct interface_info *); void if_register_receive (info) struct interface_info *info; { /* Open a LPF device and hang it on this interface... */ info -> rfdesc = if_register_lpf (info); #if defined (HAVE_TR_SUPPORT) if (info -> hw_address.hbuf [0] == HTYPE_IEEE802) lpf_tr_filter_setup (info); else #endif lpf_gen_filter_setup (info); if (!quiet_interface_discovery) log_info ("Listening on LPF/%s/%s%s%s", info -> name, print_hw_addr (info -> hw_address.hbuf [0], info -> hw_address.hlen - 1, &info -> hw_address.hbuf [1]), (info -> shared_network ? "/" : ""), (info -> shared_network ? info -> shared_network -> name : "")); } void if_deregister_receive (info) struct interface_info *info; { /* for LPF this is simple, packet filters are removed when sockets are closed */ close (info -> rfdesc); info -> rfdesc = -1; if (!quiet_interface_discovery) log_info ("Disabling input on LPF/%s/%s%s%s", info -> name, print_hw_addr (info -> hw_address.hbuf [0], info -> hw_address.hlen - 1, &info -> hw_address.hbuf [1]), (info -> shared_network ? "/" : ""), (info -> shared_network ? info -> shared_network -> name : "")); } static void lpf_gen_filter_setup (info) struct interface_info *info; { struct sock_fprog p; memset(&p, 0, sizeof(p)); /* Set up the bpf filter program structure. This is defined in bpf.c */ p.len = dhcp_bpf_filter_len; p.filter = dhcp_bpf_filter; /* Patch the server port into the LPF program... XXX changes to filter program may require changes to the insn number(s) used below! XXX */ dhcp_bpf_filter [8].k = ntohs ((short)local_port); if (setsockopt (info -> rfdesc, SOL_SOCKET, SO_ATTACH_FILTER, &p, sizeof p) < 0) { if (errno == ENOPROTOOPT || errno == EPROTONOSUPPORT || errno == ESOCKTNOSUPPORT || errno == EPFNOSUPPORT || errno == EAFNOSUPPORT) { log_error ("socket: %m - make sure"); log_error ("CONFIG_PACKET (Packet socket) %s", "and CONFIG_FILTER"); log_error ("(Socket Filtering) are enabled %s", "in your kernel"); log_fatal ("configuration!"); } log_fatal ("Can't install packet filter program: %m"); } } #if defined (HAVE_TR_SUPPORT) static void lpf_tr_filter_setup (info) struct interface_info *info; { struct sock_fprog p; memset(&p, 0, sizeof(p)); /* Set up the bpf filter program structure. This is defined in bpf.c */ p.len = dhcp_bpf_tr_filter_len; p.filter = dhcp_bpf_tr_filter; /* Patch the server port into the LPF program... XXX changes to filter program may require changes XXX to the insn number(s) used below! XXX Token ring filter is null - when/if we have a filter XXX that's not, we'll need this code. XXX dhcp_bpf_filter [?].k = ntohs (local_port); */ if (setsockopt (info -> rfdesc, SOL_SOCKET, SO_ATTACH_FILTER, &p, sizeof p) < 0) { if (errno == ENOPROTOOPT || errno == EPROTONOSUPPORT || errno == ESOCKTNOSUPPORT || errno == EPFNOSUPPORT || errno == EAFNOSUPPORT) { log_error ("socket: %m - make sure"); log_error ("CONFIG_PACKET (Packet socket) %s", "and CONFIG_FILTER"); log_error ("(Socket Filtering) are enabled %s", "in your kernel"); log_fatal ("configuration!"); } log_fatal ("Can't install packet filter program: %m"); } } #endif /* HAVE_TR_SUPPORT */ #endif /* USE_LPF_RECEIVE */ #ifdef USE_LPF_SEND ssize_t send_packet (interface, packet, raw, len, from, to, hto) struct interface_info *interface; struct packet *packet; struct dhcp_packet *raw; size_t len; struct in_addr from; struct sockaddr_in *to; struct hardware *hto; { unsigned hbufp = 0, ibufp = 0; double hh [16]; double ih [1536 / sizeof (double)]; unsigned char *buf = (unsigned char *)ih; struct sockaddr_pkt sa; int result; int fudge; if (!strcmp (interface -> name, "fallback")) return send_fallback (interface, packet, raw, len, from, to, hto); if (hto == NULL && interface->anycast_mac_addr.hlen) hto = &interface->anycast_mac_addr; /* Assemble the headers... */ assemble_hw_header (interface, (unsigned char *)hh, &hbufp, hto); fudge = hbufp % 4; /* IP header must be word-aligned. */ memcpy (buf + fudge, (unsigned char *)hh, hbufp); ibufp = hbufp + fudge; assemble_udp_ip_header (interface, buf, &ibufp, from.s_addr, to -> sin_addr.s_addr, to -> sin_port, (unsigned char *)raw, len); memcpy (buf + ibufp, raw, len); /* For some reason, SOCK_PACKET sockets can't be connected, so we have to do a sentdo every time. */ memset (&sa, 0, sizeof sa); sa.spkt_family = AF_PACKET; strncpy ((char *)sa.spkt_device, (const char *)interface -> ifp, sizeof sa.spkt_device); sa.spkt_protocol = htons(ETH_P_IP); result = sendto (interface -> wfdesc, buf + fudge, ibufp + len - fudge, 0, (const struct sockaddr *)&sa, sizeof sa); if (result < 0) log_error ("send_packet: %m"); return result; } #endif /* USE_LPF_SEND */ #ifdef USE_LPF_RECEIVE ssize_t receive_packet (interface, buf, len, from, hfrom) struct interface_info *interface; unsigned char *buf; size_t len; struct sockaddr_in *from; struct hardware *hfrom; { int length = 0; int offset = 0; unsigned char ibuf [1536]; unsigned bufix = 0; unsigned paylen; length = read (interface -> rfdesc, ibuf, sizeof ibuf); if (length <= 0) return length; bufix = 0; /* Decode the physical header... */ offset = decode_hw_header (interface, ibuf, bufix, hfrom); /* If a physical layer checksum failed (dunno of any physical layer that supports this, but WTH), skip this packet. */ if (offset < 0) { return 0; } bufix += offset; length -= offset; /* Decode the IP and UDP headers... */ offset = decode_udp_ip_header (interface, ibuf, bufix, from, (unsigned)length, &paylen); /* If the IP or UDP checksum was bad, skip the packet... */ if (offset < 0) return 0; bufix += offset; length -= offset; if (length < paylen) log_fatal("Internal inconsistency at %s:%d.", MDL); /* Copy out the data in the packet... */ memcpy(buf, &ibuf[bufix], paylen); return paylen; } int can_unicast_without_arp (ip) struct interface_info *ip; { return 1; } int can_receive_unicast_unconfigured (ip) struct interface_info *ip; { return 1; } int supports_multiple_interfaces (ip) struct interface_info *ip; { return 1; } void maybe_setup_fallback () { isc_result_t status; struct interface_info *fbi = (struct interface_info *)0; if (setup_fallback (&fbi, MDL)) { if_register_fallback (fbi); status = omapi_register_io_object ((omapi_object_t *)fbi, if_readsocket, 0, fallback_discard, 0, 0); if (status != ISC_R_SUCCESS) log_fatal ("Can't register I/O handle for \"%s\": %s", fbi -> name, isc_result_totext (status)); interface_dereference (&fbi, MDL); } } void get_hw_addr(const char *name, struct hardware *hw) { int sock; struct ifreq tmp; struct sockaddr *sa; if (strlen(name) >= sizeof(tmp.ifr_name)) { log_fatal("Device name too long: \"%s\"", name); } sock = socket(AF_INET, SOCK_DGRAM, 0); if (sock < 0) { log_fatal("Can't create socket for \"%s\": %m", name); } memset(&tmp, 0, sizeof(tmp)); strcpy(tmp.ifr_name, name); if (ioctl(sock, SIOCGIFHWADDR, &tmp) < 0) { log_fatal("Error getting hardware address for \"%s\": %m", name); } sa = &tmp.ifr_hwaddr; switch (sa->sa_family) { case ARPHRD_ETHER: hw->hlen = 7; hw->hbuf[0] = HTYPE_ETHER; memcpy(&hw->hbuf[1], sa->sa_data, 6); break; case ARPHRD_IEEE802: #ifdef ARPHRD_IEEE802_TR case ARPHRD_IEEE802_TR: #endif /* ARPHRD_IEEE802_TR */ hw->hlen = 7; hw->hbuf[0] = HTYPE_IEEE802; memcpy(&hw->hbuf[1], sa->sa_data, 6); break; case ARPHRD_FDDI: hw->hlen = 17; hw->hbuf[0] = HTYPE_FDDI; memcpy(&hw->hbuf[1], sa->sa_data, 16); break; default: log_fatal("Unsupported device type %ld for \"%s\"", (long int)sa->sa_family, name); } close(sock); } #endif dhcp-4.2.4/common/Makefile.am000644 000765 000024 00000000740 11527537032 015721 0ustar00sarstaff000000 000000 AM_CPPFLAGS = -I.. -DLOCALSTATEDIR='"@localstatedir@"' AM_CFLAGS = $(LDAP_CFLAGS) noinst_LIBRARIES = libdhcp.a libdhcp_a_SOURCES = alloc.c bpf.c comapi.c conflex.c ctrace.c discover.c \ dispatch.c dlpi.c dns.c ethernet.c execute.c fddi.c \ icmp.c inet.c lpf.c memory.c nit.c ns_name.c options.c \ packet.c parse.c print.c raw.c resolv.c socket.c \ tables.c tr.c tree.c upf.c man_MANS = dhcp-eval.5 dhcp-options.5 EXTRA_DIST = $(man_MANS) SUBDIRS = tests dhcp-4.2.4/common/Makefile.in000644 000765 000024 00000047741 11757500141 015742 0ustar00sarstaff000000 000000 # Makefile.in generated by automake 1.10.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : subdir = common DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/includes/config.h CONFIG_CLEAN_FILES = LIBRARIES = $(noinst_LIBRARIES) AR = ar ARFLAGS = cru libdhcp_a_AR = $(AR) $(ARFLAGS) libdhcp_a_LIBADD = am_libdhcp_a_OBJECTS = alloc.$(OBJEXT) bpf.$(OBJEXT) comapi.$(OBJEXT) \ conflex.$(OBJEXT) ctrace.$(OBJEXT) discover.$(OBJEXT) \ dispatch.$(OBJEXT) dlpi.$(OBJEXT) dns.$(OBJEXT) \ ethernet.$(OBJEXT) execute.$(OBJEXT) fddi.$(OBJEXT) \ icmp.$(OBJEXT) inet.$(OBJEXT) lpf.$(OBJEXT) memory.$(OBJEXT) \ nit.$(OBJEXT) ns_name.$(OBJEXT) options.$(OBJEXT) \ packet.$(OBJEXT) parse.$(OBJEXT) print.$(OBJEXT) raw.$(OBJEXT) \ resolv.$(OBJEXT) socket.$(OBJEXT) tables.$(OBJEXT) \ tr.$(OBJEXT) tree.$(OBJEXT) upf.$(OBJEXT) libdhcp_a_OBJECTS = $(am_libdhcp_a_OBJECTS) DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/includes depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) CCLD = $(CC) LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ SOURCES = $(libdhcp_a_SOURCES) DIST_SOURCES = $(libdhcp_a_SOURCES) RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ html-recursive info-recursive install-data-recursive \ install-dvi-recursive install-exec-recursive \ install-html-recursive install-info-recursive \ install-pdf-recursive install-ps-recursive install-recursive \ installcheck-recursive installdirs-recursive pdf-recursive \ ps-recursive uninstall-recursive man5dir = $(mandir)/man5 am__installdirs = "$(DESTDIR)$(man5dir)" NROFF = nroff MANS = $(man_MANS) RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive ETAGS = etags CTAGS = ctags DIST_SUBDIRS = $(SUBDIRS) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ GREP = @GREP@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDAP_CFLAGS = @LDAP_CFLAGS@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_prefix_program = @ac_prefix_program@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build_alias = @build_alias@ builddir = @builddir@ byte_order = @byte_order@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host_alias = @host_alias@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AM_CPPFLAGS = -I.. -DLOCALSTATEDIR='"@localstatedir@"' AM_CFLAGS = $(LDAP_CFLAGS) noinst_LIBRARIES = libdhcp.a libdhcp_a_SOURCES = alloc.c bpf.c comapi.c conflex.c ctrace.c discover.c \ dispatch.c dlpi.c dns.c ethernet.c execute.c fddi.c \ icmp.c inet.c lpf.c memory.c nit.c ns_name.c options.c \ packet.c parse.c print.c raw.c resolv.c socket.c \ tables.c tr.c tree.c upf.c man_MANS = dhcp-eval.5 dhcp-options.5 EXTRA_DIST = $(man_MANS) SUBDIRS = tests all: all-recursive .SUFFIXES: .SUFFIXES: .c .o .obj $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ && exit 0; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign common/Makefile'; \ cd $(top_srcdir) && \ $(AUTOMAKE) --foreign common/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh clean-noinstLIBRARIES: -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) libdhcp.a: $(libdhcp_a_OBJECTS) $(libdhcp_a_DEPENDENCIES) -rm -f libdhcp.a $(libdhcp_a_AR) libdhcp.a $(libdhcp_a_OBJECTS) $(libdhcp_a_LIBADD) $(RANLIB) libdhcp.a mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/alloc.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bpf.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/comapi.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/conflex.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ctrace.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/discover.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dispatch.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dlpi.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dns.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ethernet.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/execute.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fddi.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/icmp.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/inet.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lpf.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/memory.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nit.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ns_name.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/options.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/packet.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parse.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/print.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/raw.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/resolv.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/socket.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tables.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tr.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tree.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/upf.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` install-man5: $(man5_MANS) $(man_MANS) @$(NORMAL_INSTALL) test -z "$(man5dir)" || $(MKDIR_P) "$(DESTDIR)$(man5dir)" @list='$(man5_MANS) $(dist_man5_MANS) $(nodist_man5_MANS)'; \ l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ for i in $$l2; do \ case "$$i" in \ *.5*) list="$$list $$i" ;; \ esac; \ done; \ for i in $$list; do \ if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \ else file=$$i; fi; \ ext=`echo $$i | sed -e 's/^.*\\.//'`; \ case "$$ext" in \ 5*) ;; \ *) ext='5' ;; \ esac; \ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ inst=`echo $$inst | sed -e 's/^.*\///'`; \ inst=`echo $$inst | sed '$(transform)'`.$$ext; \ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man5dir)/$$inst'"; \ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man5dir)/$$inst"; \ done uninstall-man5: @$(NORMAL_UNINSTALL) @list='$(man5_MANS) $(dist_man5_MANS) $(nodist_man5_MANS)'; \ l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ for i in $$l2; do \ case "$$i" in \ *.5*) list="$$list $$i" ;; \ esac; \ done; \ for i in $$list; do \ ext=`echo $$i | sed -e 's/^.*\\.//'`; \ case "$$ext" in \ 5*) ;; \ *) ext='5' ;; \ esac; \ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ inst=`echo $$inst | sed -e 's/^.*\///'`; \ inst=`echo $$inst | sed '$(transform)'`.$$ext; \ echo " rm -f '$(DESTDIR)$(man5dir)/$$inst'"; \ rm -f "$(DESTDIR)$(man5dir)/$$inst"; \ done # This directory's subdirectories are mostly independent; you can cd # into them and run `make' without going through this Makefile. # To change the values of `make' variables: instead of editing Makefiles, # (1) if the variable is set in `config.status', edit `config.status' # (which will cause the Makefiles to be regenerated when you run `make'); # (2) otherwise, pass the desired values on the `make' command line. $(RECURSIVE_TARGETS): @failcom='exit 1'; \ for f in x $$MAKEFLAGS; do \ case $$f in \ *=* | --[!k]*);; \ *k*) failcom='fail=yes';; \ esac; \ done; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ list='$(SUBDIRS)'; for subdir in $$list; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ dot_seen=yes; \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" $(RECURSIVE_CLEAN_TARGETS): @failcom='exit 1'; \ for f in x $$MAKEFLAGS; do \ case $$f in \ *=* | --[!k]*);; \ *k*) failcom='fail=yes';; \ esac; \ done; \ dot_seen=no; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ rev=''; for subdir in $$list; do \ if test "$$subdir" = "."; then :; else \ rev="$$subdir $$rev"; \ fi; \ done; \ rev="$$rev ."; \ target=`echo $@ | sed s/-recursive//`; \ for subdir in $$rev; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done && test -z "$$fail" tags-recursive: list='$(SUBDIRS)'; for subdir in $$list; do \ test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ done ctags-recursive: list='$(SUBDIRS)'; for subdir in $$list; do \ test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ done ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) tags=; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ tags="$$tags $$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$tags $$unique; \ fi ctags: CTAGS CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) tags=; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$tags$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$tags $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && cd $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) $$here distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ fi; \ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ else \ test -f $(distdir)/$$file \ || cp -p $$d/$$file $(distdir)/$$file \ || exit 1; \ fi; \ done list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ distdir=`$(am__cd) $(distdir) && pwd`; \ top_distdir=`$(am__cd) $(top_distdir) && pwd`; \ (cd $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$top_distdir" \ distdir="$$distdir/$$subdir" \ am__remove_distdir=: \ am__skip_length_check=: \ distdir) \ || exit 1; \ fi; \ done check-am: all-am check: check-recursive all-am: Makefile $(LIBRARIES) $(MANS) installdirs: installdirs-recursive installdirs-am: for dir in "$(DESTDIR)$(man5dir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-recursive clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am distclean: distclean-recursive -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive info: info-recursive info-am: install-data-am: install-man install-dvi: install-dvi-recursive install-exec-am: install-html: install-html-recursive install-info: install-info-recursive install-man: install-man5 install-pdf: install-pdf-recursive install-ps: install-ps-recursive installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-compile mostlyclean-generic pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: uninstall-man uninstall-man: uninstall-man5 .MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) install-am \ install-strip .PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ all all-am check check-am clean clean-generic \ clean-noinstLIBRARIES ctags ctags-recursive distclean \ distclean-compile distclean-generic distclean-tags distdir dvi \ dvi-am html html-am info info-am install install-am \ install-data install-data-am install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-info install-info-am install-man install-man5 \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ installdirs-am maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-compile mostlyclean-generic pdf pdf-am \ ps ps-am tags tags-recursive uninstall uninstall-am \ uninstall-man uninstall-man5 # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: dhcp-4.2.4/common/memory.c000644 000765 000024 00000011543 11301372614 015335 0ustar00sarstaff000000 000000 /* memory.c Memory-resident database... */ /* * Copyright (c) 2004,2007,2009 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1995-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ * * This software has been written for Internet Systems Consortium * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. * To learn more about Internet Systems Consortium, see * ``https://www.isc.org/''. To learn more about Vixie Enterprises, * see ``http://www.vix.com''. To learn more about Nominum, Inc., see * ``http://www.nominum.com''. */ #include "dhcpd.h" struct group *root_group; group_hash_t *group_name_hash; int (*group_write_hook) (struct group_object *); isc_result_t delete_group (struct group_object *group, int writep) { struct group_object *d; /* The group should exist and be hashed - if not, it's invalid. */ if (group_name_hash) { d = (struct group_object *)0; group_hash_lookup (&d, group_name_hash, group -> name, strlen (group -> name), MDL); } else return DHCP_R_INVALIDARG; if (!d) return DHCP_R_INVALIDARG; /* Also not okay to delete a group that's not the one in the hash table. */ if (d != group) return DHCP_R_INVALIDARG; /* If it's dynamic, and we're deleting it, we can just blow away the hash table entry. */ if ((group -> flags & GROUP_OBJECT_DYNAMIC) && !(group -> flags & GROUP_OBJECT_STATIC)) { group_hash_delete (group_name_hash, group -> name, strlen (group -> name), MDL); } else { group -> flags |= GROUP_OBJECT_DELETED; if (group -> group) group_dereference (&group -> group, MDL); } /* Store the group declaration in the lease file. */ if (writep && group_write_hook) { if (!(*group_write_hook) (group)) return ISC_R_IOERROR; } return ISC_R_SUCCESS; } isc_result_t supersede_group (struct group_object *group, int writep) { struct group_object *t; /* Register the group in the group name hash table, so we can look it up later. */ if (group_name_hash) { t = (struct group_object *)0; group_hash_lookup (&t, group_name_hash, group -> name, strlen (group -> name), MDL); if (t && t != group) { /* If this isn't a dynamic entry, then we need to flag the replacement as not dynamic either - otherwise, if the dynamic entry is deleted later, the static entry will come back next time the server is stopped and restarted. */ if (!(t -> flags & GROUP_OBJECT_DYNAMIC)) group -> flags |= GROUP_OBJECT_STATIC; /* Delete the old object if it hasn't already been deleted. If it has already been deleted, get rid of the hash table entry. This is a legitimate situation - a deleted static object needs to be kept around so we remember it's deleted. */ if (!(t -> flags & GROUP_OBJECT_DELETED)) delete_group (t, 0); else { group_hash_delete (group_name_hash, group -> name, strlen (group -> name), MDL); group_object_dereference (&t, MDL); } } } else { group_new_hash(&group_name_hash, GROUP_HASH_SIZE, MDL); t = (struct group_object *)0; } /* Add the group to the group name hash if it's not already there, and also thread it into the list of dynamic groups if appropriate. */ if (!t) { group_hash_add (group_name_hash, group -> name, strlen (group -> name), group, MDL); } /* Store the group declaration in the lease file. */ if (writep && group_write_hook) { if (!(*group_write_hook) (group)) return ISC_R_IOERROR; } return ISC_R_SUCCESS; } int clone_group (struct group **gp, struct group *group, const char *file, int line) { struct group *g = (struct group *)0; /* Normally gp should contain the null pointer, but for convenience it's permissible to clone a group into itself. */ if (*gp && *gp != group) return 0; if (!group_allocate (&g, file, line)) return 0; if (group == *gp) *gp = (struct group *)0; group_reference (gp, g, file, line); g -> authoritative = group -> authoritative; group_reference (&g -> next, group, file, line); group_dereference (&g, file, line); return 1; } dhcp-4.2.4/common/nit.c000644 000765 000024 00000027474 11301372615 014632 0ustar00sarstaff000000 000000 /* nit.c Network Interface Tap (NIT) network interface code, by Ted Lemon with one crucial tidbit of help from Stu Grossmen. */ /* * Copyright (c) 2004,2007,2009 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1996-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ * * This software has been written for Internet Systems Consortium * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. * To learn more about Internet Systems Consortium, see * ``https://www.isc.org/''. To learn more about Vixie Enterprises, * see ``http://www.vix.com''. To learn more about Nominum, Inc., see * ``http://www.nominum.com''. */ #include "dhcpd.h" #if defined (USE_NIT_SEND) || defined (USE_NIT_RECEIVE) #include #include #include #include #include #include #include #include #include #include #include "includes/netinet/ip.h" #include "includes/netinet/udp.h" #include "includes/netinet/if_ether.h" /* Reinitializes the specified interface after an address change. This is not required for packet-filter APIs. */ #ifdef USE_NIT_SEND void if_reinitialize_send (info) struct interface_info *info; { } #endif #ifdef USE_NIT_RECEIVE void if_reinitialize_receive (info) struct interface_info *info; { } #endif /* Called by get_interface_list for each interface that's discovered. Opens a packet filter for each interface and adds it to the select mask. */ int if_register_nit (info) struct interface_info *info; { int sock; char filename[50]; struct ifreq ifr; struct strioctl sio; /* Open a NIT device */ sock = open ("/dev/nit", O_RDWR); if (sock < 0) log_fatal ("Can't open NIT device for %s: %m", info -> name); /* Set the NIT device to point at this interface. */ sio.ic_cmd = NIOCBIND; sio.ic_len = sizeof *(info -> ifp); sio.ic_dp = (char *)(info -> ifp); sio.ic_timout = INFTIM; if (ioctl (sock, I_STR, &sio) < 0) log_fatal ("Can't attach interface %s to nit device: %m", info -> name); /* Get the low-level address... */ sio.ic_cmd = SIOCGIFADDR; sio.ic_len = sizeof ifr; sio.ic_dp = (char *)𝔦 sio.ic_timout = INFTIM; if (ioctl (sock, I_STR, &sio) < 0) log_fatal ("Can't get physical layer address for %s: %m", info -> name); /* XXX code below assumes ethernet interface! */ info -> hw_address.hlen = 7; info -> hw_address.hbuf [0] = ARPHRD_ETHER; memcpy (&info -> hw_address.hbuf [1], ifr.ifr_ifru.ifru_addr.sa_data, 6); if (ioctl (sock, I_PUSH, "pf") < 0) log_fatal ("Can't push packet filter onto NIT for %s: %m", info -> name); return sock; } #endif /* USE_NIT_SEND || USE_NIT_RECEIVE */ #ifdef USE_NIT_SEND void if_register_send (info) struct interface_info *info; { /* If we're using the nit API for sending and receiving, we don't need to register this interface twice. */ #ifndef USE_NIT_RECEIVE struct packetfilt pf; struct strioctl sio; info -> wfdesc = if_register_nit (info); pf.Pf_Priority = 0; pf.Pf_FilterLen = 1; pf.Pf_Filter [0] = ENF_PUSHZERO; /* Set up an NIT filter that rejects everything... */ sio.ic_cmd = NIOCSETF; sio.ic_len = sizeof pf; sio.ic_dp = (char *)&pf; sio.ic_timout = INFTIM; if (ioctl (info -> wfdesc, I_STR, &sio) < 0) log_fatal ("Can't set NIT filter: %m"); #else info -> wfdesc = info -> rfdesc; #endif if (!quiet_interface_discovery) log_info ("Sending on NIT/%s%s%s", print_hw_addr (info -> hw_address.hbuf [0], info -> hw_address.hlen - 1, &info -> hw_address.hbuf [1]), (info -> shared_network ? "/" : ""), (info -> shared_network ? info -> shared_network -> name : "")); } void if_deregister_send (info) struct interface_info *info; { /* If we're using the nit API for sending and receiving, we don't need to register this interface twice. */ #ifndef USE_NIT_RECEIVE close (info -> wfdesc); #endif info -> wfdesc = -1; if (!quiet_interface_discovery) log_info ("Disabling output on NIT/%s%s%s", print_hw_addr (info -> hw_address.hbuf [0], info -> hw_address.hlen - 1, &info -> hw_address.hbuf [1]), (info -> shared_network ? "/" : ""), (info -> shared_network ? info -> shared_network -> name : "")); } #endif /* USE_NIT_SEND */ #ifdef USE_NIT_RECEIVE /* Packet filter program... XXX Changes to the filter program may require changes to the constant offsets used in if_register_send to patch the NIT program! XXX */ void if_register_receive (info) struct interface_info *info; { int flag = 1; u_int32_t x; struct packetfilt pf; struct strioctl sio; u_int16_t addr [2]; struct timeval t; /* Open a NIT device and hang it on this interface... */ info -> rfdesc = if_register_nit (info); /* Set the snap length to 0, which means always take the whole packet. */ x = 0; if (ioctl (info -> rfdesc, NIOCSSNAP, &x) < 0) log_fatal ("Can't set NIT snap length on %s: %m", info -> name); /* Set the stream to byte stream mode */ if (ioctl (info -> rfdesc, I_SRDOPT, RMSGN) != 0) log_info ("I_SRDOPT failed on %s: %m", info -> name); #if 0 /* Push on the chunker... */ if (ioctl (info -> rfdesc, I_PUSH, "nbuf") < 0) log_fatal ("Can't push chunker onto NIT STREAM: %m"); /* Set the timeout to zero. */ t.tv_sec = 0; t.tv_usec = 0; if (ioctl (info -> rfdesc, NIOCSTIME, &t) < 0) log_fatal ("Can't set chunk timeout: %m"); #endif /* Ask for no header... */ x = 0; if (ioctl (info -> rfdesc, NIOCSFLAGS, &x) < 0) log_fatal ("Can't set NIT flags on %s: %m", info -> name); /* Set up the NIT filter program. */ /* XXX Unlike the BPF filter program, this one won't work if the XXX IP packet is fragmented or if there are options on the IP XXX header. */ pf.Pf_Priority = 0; pf.Pf_FilterLen = 0; pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHWORD + 6; pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHLIT + ENF_CAND; pf.Pf_Filter [pf.Pf_FilterLen++] = htons (ETHERTYPE_IP); pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHLIT; pf.Pf_Filter [pf.Pf_FilterLen++] = htons (IPPROTO_UDP); pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHWORD + 11; pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHLIT + ENF_AND; pf.Pf_Filter [pf.Pf_FilterLen++] = htons (0xFF); pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_CAND; pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHWORD + 18; pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHLIT + ENF_CAND; pf.Pf_Filter [pf.Pf_FilterLen++] = local_port; /* Install the filter... */ sio.ic_cmd = NIOCSETF; sio.ic_len = sizeof pf; sio.ic_dp = (char *)&pf; sio.ic_timout = INFTIM; if (ioctl (info -> rfdesc, I_STR, &sio) < 0) log_fatal ("Can't set NIT filter on %s: %m", info -> name); if (!quiet_interface_discovery) log_info ("Listening on NIT/%s%s%s", print_hw_addr (info -> hw_address.hbuf [0], info -> hw_address.hlen - 1, &info -> hw_address.hbuf [1]), (info -> shared_network ? "/" : ""), (info -> shared_network ? info -> shared_network -> name : "")); } void if_deregister_receive (info) struct interface_info *info; { /* If we're using the nit API for sending and receiving, we don't need to register this interface twice. */ close (info -> rfdesc); info -> rfdesc = -1; if (!quiet_interface_discovery) log_info ("Disabling input on NIT/%s%s%s", print_hw_addr (info -> hw_address.hbuf [0], info -> hw_address.hlen - 1, &info -> hw_address.hbuf [1]), (info -> shared_network ? "/" : ""), (info -> shared_network ? info -> shared_network -> name : "")); } #endif /* USE_NIT_RECEIVE */ #ifdef USE_NIT_SEND ssize_t send_packet (interface, packet, raw, len, from, to, hto) struct interface_info *interface; struct packet *packet; struct dhcp_packet *raw; size_t len; struct in_addr from; struct sockaddr_in *to; struct hardware *hto; { unsigned hbufp, ibufp; double hh [16]; double ih [1536 / sizeof (double)]; unsigned char *buf = (unsigned char *)ih; struct sockaddr *junk; struct strbuf ctl, data; struct sockaddr_in foo; int result; if (!strcmp (interface -> name, "fallback")) return send_fallback (interface, packet, raw, len, from, to, hto); if (hto == NULL && interface->anycast_mac_addr.hlen) hto = &interface->anycast_mac_addr; /* Start with the sockaddr struct... */ junk = (struct sockaddr *)&hh [0]; hbufp = (((unsigned char *)&junk -> sa_data [0]) - (unsigned char *)&hh[0]); ibufp = 0; /* Assemble the headers... */ assemble_hw_header (interface, (unsigned char *)junk, &hbufp, hto); assemble_udp_ip_header (interface, buf, &ibufp, from.s_addr, to -> sin_addr.s_addr, to -> sin_port, (unsigned char *)raw, len); /* Copy the data into the buffer (yuk). */ memcpy (buf + ibufp, raw, len); /* Set up the sockaddr structure... */ #if USE_SIN_LEN junk -> sa_len = hbufp - 2; /* XXX */ #endif junk -> sa_family = AF_UNSPEC; /* Set up the msg_buf structure... */ ctl.buf = (char *)&hh [0]; ctl.maxlen = ctl.len = hbufp; data.buf = (char *)&ih [0]; data.maxlen = data.len = ibufp + len; result = putmsg (interface -> wfdesc, &ctl, &data, 0); if (result < 0) log_error ("send_packet: %m"); return result; } #endif /* USE_NIT_SEND */ #ifdef USE_NIT_RECEIVE ssize_t receive_packet (interface, buf, len, from, hfrom) struct interface_info *interface; unsigned char *buf; size_t len; struct sockaddr_in *from; struct hardware *hfrom; { int nread; int length = 0; int offset = 0; unsigned char ibuf [1536]; int bufix = 0; unsigned paylen; length = read (interface -> rfdesc, ibuf, sizeof ibuf); if (length <= 0) return length; /* Decode the physical header... */ offset = decode_hw_header (interface, ibuf, bufix, hfrom); /* If a physical layer checksum failed (dunno of any physical layer that supports this, but WTH), skip this packet. */ if (offset < 0) { return 0; } bufix += offset; length -= offset; /* Decode the IP and UDP headers... */ offset = decode_udp_ip_header (interface, ibuf, bufix, from, length, &paylen); /* If the IP or UDP checksum was bad, skip the packet... */ if (offset < 0) return 0; bufix += offset; length -= offset; if (length < paylen) log_fatal("Internal inconsistency at %s:%d.", MDL); /* Copy out the data in the packet... */ memcpy(buf, &ibuf[bufix], paylen); return paylen; } int can_unicast_without_arp (ip) struct interface_info *ip; { return 1; } int can_receive_unicast_unconfigured (ip) struct interface_info *ip; { return 1; } int supports_multiple_interfaces (ip) struct interface_info *ip; { return 1; } void maybe_setup_fallback () { isc_result_t status; struct interface_info *fbi = (struct interface_info *)0; if (setup_fallback (&fbi, MDL)) { if_register_fallback (fbi); status = omapi_register_io_object ((omapi_object_t *)fbi, if_readsocket, 0, fallback_discard, 0, 0); if (status != ISC_R_SUCCESS) log_fatal ("Can't register I/O handle for %s: %s", fbi -> name, isc_result_totext (status)); interface_dereference (&fbi, MDL); } } #endif dhcp-4.2.4/common/ns_name.c000644 000765 000024 00000033361 11271742255 015457 0ustar00sarstaff000000 000000 /* * Copyright (c) 2004,2009 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1996-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * http://www.isc.org/ */ #ifndef lint static const char rcsid[] = "$Id: ns_name.c,v 1.2 2009-10-28 04:12:29 sar Exp $"; #endif #include #include #include #include #include #include #include "minires.h" #include "arpa/nameser.h" /* Data. */ static const char digits[] = "0123456789"; /* Forward. */ static int special(int); static int printable(int); static int dn_find(const u_char *, const u_char *, const u_char * const *, const u_char * const *); /* Public. */ /* * MRns_name_ntop(src, dst, dstsiz) * Convert an encoded domain name to printable ascii as per RFC1035. * return: * Number of bytes written to buffer, or -1 (with errno set) * notes: * The root is returned as "." * All other domains are returned in non absolute form */ int MRns_name_ntop(const u_char *src, char *dst, size_t dstsiz) { const u_char *cp; char *dn, *eom; u_char c; u_int n; cp = src; dn = dst; eom = dst + dstsiz; while ((n = *cp++) != 0) { if ((n & NS_CMPRSFLGS) != 0) { /* Some kind of compression pointer. */ errno = EMSGSIZE; return (-1); } if (dn != dst) { if (dn >= eom) { errno = EMSGSIZE; return (-1); } *dn++ = '.'; } if (dn + n >= eom) { errno = EMSGSIZE; return (-1); } for ((void)NULL; n > 0; n--) { c = *cp++; if (special(c)) { if (dn + 1 >= eom) { errno = EMSGSIZE; return (-1); } *dn++ = '\\'; *dn++ = (char)c; } else if (!printable(c)) { if (dn + 3 >= eom) { errno = EMSGSIZE; return (-1); } *dn++ = '\\'; *dn++ = digits[c / 100]; *dn++ = digits[(c % 100) / 10]; *dn++ = digits[c % 10]; } else { if (dn >= eom) { errno = EMSGSIZE; return (-1); } *dn++ = (char)c; } } } if (dn == dst) { if (dn >= eom) { errno = EMSGSIZE; return (-1); } *dn++ = '.'; } if (dn >= eom) { errno = EMSGSIZE; return (-1); } *dn++ = '\0'; return (dn - dst); } /* * MRns_name_pton(src, dst, dstsiz) * Convert a ascii string into an encoded domain name as per RFC1035. * return: * -1 if it fails * 1 if string was fully qualified * 0 is string was not fully qualified * notes: * Enforces label and domain length limits. */ int MRns_name_pton(const char *src, u_char *dst, size_t dstsiz) { u_char *label, *bp, *eom; int c, n, escaped; char *cp; escaped = 0; bp = dst; eom = dst + dstsiz; label = bp++; while ((c = *src++) != 0) { if (escaped) { if ((cp = strchr(digits, c)) != NULL) { n = (cp - digits) * 100; if ((c = *src++) == 0 || (cp = strchr(digits, c)) == NULL) { errno = EMSGSIZE; return (-1); } n += (cp - digits) * 10; if ((c = *src++) == 0 || (cp = strchr(digits, c)) == NULL) { errno = EMSGSIZE; return (-1); } n += (cp - digits); if (n > 255) { errno = EMSGSIZE; return (-1); } c = n; } escaped = 0; } else if (c == '\\') { escaped = 1; continue; } else if (c == '.') { c = (bp - label - 1); if ((c & NS_CMPRSFLGS) != 0) { /* Label too big. */ errno = EMSGSIZE; return (-1); } if (label >= eom) { errno = EMSGSIZE; return (-1); } *label = c; /* Fully qualified ? */ if (*src == '\0') { if (c != 0) { if (bp >= eom) { errno = EMSGSIZE; return (-1); } *bp++ = '\0'; } if ((bp - dst) > MAXCDNAME) { errno = EMSGSIZE; return (-1); } return (1); } if (c == 0 || *src == '.') { errno = EMSGSIZE; return (-1); } label = bp++; continue; } if (bp >= eom) { errno = EMSGSIZE; return (-1); } *bp++ = (u_char)c; } c = (bp - label - 1); if ((c & NS_CMPRSFLGS) != 0) { /* Label too big. */ errno = EMSGSIZE; return (-1); } if (label >= eom) { errno = EMSGSIZE; return (-1); } *label = c; if (c != 0) { if (bp >= eom) { errno = EMSGSIZE; return (-1); } *bp++ = 0; } if ((bp - dst) > MAXCDNAME) { /* src too big */ errno = EMSGSIZE; return (-1); } return (0); } /* * MRns_name_ntol(src, dst, dstsiz) * Convert a network strings labels into all lowercase. * return: * Number of bytes written to buffer, or -1 (with errno set) * notes: * Enforces label and domain length limits. */ int MRns_name_ntol(const u_char *src, u_char *dst, size_t dstsiz) { const u_char *cp; u_char *dn, *eom; u_char c; u_int n; cp = src; dn = dst; eom = dst + dstsiz; if (dn >= eom) { errno = EMSGSIZE; return (-1); } while ((n = *cp++) != 0) { if ((n & NS_CMPRSFLGS) != 0) { /* Some kind of compression pointer. */ errno = EMSGSIZE; return (-1); } *dn++ = n; if (dn + n >= eom) { errno = EMSGSIZE; return (-1); } for ((void)NULL; n > 0; n--) { c = *cp++; if (isupper(c)) *dn++ = tolower(c); else *dn++ = c; } } *dn++ = '\0'; return (dn - dst); } /* * MRns_name_unpack(msg, eom, src, dst, dstsiz) * Unpack a domain name from a message, source may be compressed. * return: * -1 if it fails, or consumed octets if it succeeds. */ int MRns_name_unpack(const u_char *msg, const u_char *eom, const u_char *src, u_char *dst, size_t dstsiz) { const u_char *srcp, *dstlim; u_char *dstp; unsigned n; int len; int checked; len = -1; checked = 0; dstp = dst; srcp = src; dstlim = dst + dstsiz; if (srcp < msg || srcp >= eom) { errno = EMSGSIZE; return (-1); } /* Fetch next label in domain name. */ while ((n = *srcp++) != 0) { /* Check for indirection. */ switch (n & NS_CMPRSFLGS) { case 0: /* Limit checks. */ if (dstp + n + 1 >= dstlim || srcp + n >= eom) { errno = EMSGSIZE; return (-1); } checked += n + 1; *dstp++ = n; memcpy(dstp, srcp, n); dstp += n; srcp += n; break; case NS_CMPRSFLGS: if (srcp >= eom) { errno = EMSGSIZE; return (-1); } if (len < 0) len = srcp - src + 1; srcp = msg + (((n & 0x3f) << 8) | (*srcp & 0xff)); if (srcp < msg || srcp >= eom) { /* Out of range. */ errno = EMSGSIZE; return (-1); } checked += 2; /* * Check for loops in the compressed name; * if we've looked at the whole message, * there must be a loop. */ if (checked >= eom - msg) { errno = EMSGSIZE; return (-1); } break; default: errno = EMSGSIZE; return (-1); /* flag error */ } } *dstp = '\0'; if (len < 0) len = srcp - src; return (len); } /* * MRns_name_pack(src, dst, dstsiz, dnptrs, lastdnptr) * Pack domain name 'domain' into 'comp_dn'. * return: * Size of the compressed name, or -1. * notes: * 'dnptrs' is an array of pointers to previous compressed names. * dnptrs[0] is a pointer to the beginning of the message. The array * ends with NULL. * 'lastdnptr' is a pointer to the end of the array pointed to * by 'dnptrs'. * Side effects: * The list of pointers in dnptrs is updated for labels inserted into * the message as we compress the name. If 'dnptr' is NULL, we don't * try to compress names. If 'lastdnptr' is NULL, we don't update the * list. */ int MRns_name_pack(const u_char *src, u_char *dst, unsigned dstsiz, const u_char **dnptrs, const u_char **lastdnptr) { u_char *dstp; const u_char **cpp, **lpp, *eob, *msg; const u_char *srcp; unsigned n; int l; srcp = src; dstp = dst; eob = dstp + dstsiz; lpp = cpp = NULL; if (dnptrs != NULL) { if ((msg = *dnptrs++) != NULL) { for (cpp = dnptrs; *cpp != NULL; cpp++) (void)NULL; lpp = cpp; /* end of list to search */ } } else msg = NULL; /* make sure the domain we are about to add is legal */ l = 0; do { n = *srcp; if ((n & NS_CMPRSFLGS) != 0) { errno = EMSGSIZE; return (-1); } l += n + 1; if (l > MAXCDNAME) { errno = EMSGSIZE; return (-1); } srcp += n + 1; } while (n != 0); /* from here on we need to reset compression pointer array on error */ srcp = src; do { /* Look to see if we can use pointers. */ n = *srcp; if (n != 0 && msg != NULL) { l = dn_find(srcp, msg, (const u_char * const *)dnptrs, (const u_char * const *)lpp); if (l >= 0) { if (dstp + 1 >= eob) { goto cleanup; } *dstp++ = (l >> 8) | NS_CMPRSFLGS; *dstp++ = l % 256; return (dstp - dst); } /* Not found, save it. */ if (lastdnptr != NULL && cpp < lastdnptr - 1 && (dstp - msg) < 0x4000) { *cpp++ = dstp; *cpp = NULL; } } /* copy label to buffer */ if (n & NS_CMPRSFLGS) { /* Should not happen. */ goto cleanup; } if (dstp + 1 + n >= eob) { goto cleanup; } memcpy(dstp, srcp, n + 1); srcp += n + 1; dstp += n + 1; } while (n != 0); if (dstp > eob) { cleanup: if (msg != NULL) *lpp = NULL; errno = EMSGSIZE; return (-1); } return (dstp - dst); } /* * MRns_name_uncompress(msg, eom, src, dst, dstsiz) * Expand compressed domain name to presentation format. * return: * Number of bytes read out of `src', or -1 (with errno set). * note: * Root domain returns as "." not "". */ int MRns_name_uncompress(const u_char *msg, const u_char *eom, const u_char *src, char *dst, size_t dstsiz) { u_char tmp[NS_MAXCDNAME]; int n; if ((n = MRns_name_unpack(msg, eom, src, tmp, sizeof tmp)) == -1) return (-1); if (MRns_name_ntop(tmp, dst, dstsiz) == -1) return (-1); return (n); } /* * MRns_name_compress(src, dst, dstsiz, dnptrs, lastdnptr) * Compress a domain name into wire format, using compression pointers. * return: * Number of bytes consumed in `dst' or -1 (with errno set). * notes: * 'dnptrs' is an array of pointers to previous compressed names. * dnptrs[0] is a pointer to the beginning of the message. * The list ends with NULL. 'lastdnptr' is a pointer to the end of the * array pointed to by 'dnptrs'. Side effect is to update the list of * pointers for labels inserted into the message as we compress the name. * If 'dnptr' is NULL, we don't try to compress names. If 'lastdnptr' * is NULL, we don't update the list. */ int MRns_name_compress(const char *src, u_char *dst, size_t dstsiz, const u_char **dnptrs, const u_char **lastdnptr) { u_char tmp[NS_MAXCDNAME]; if (MRns_name_pton(src, tmp, sizeof tmp) == -1) return (-1); return (MRns_name_pack(tmp, dst, dstsiz, dnptrs, lastdnptr)); } /* * MRns_name_skip(ptrptr, eom) * Advance *ptrptr to skip over the compressed name it points at. * return: * 0 on success, -1 (with errno set) on failure. */ int MRns_name_skip(const u_char **ptrptr, const u_char *eom) { const u_char *cp; u_int n; cp = *ptrptr; while (cp < eom && (n = *cp++) != 0) { /* Check for indirection. */ switch (n & NS_CMPRSFLGS) { case 0: /* normal case, n == len */ cp += n; continue; case NS_CMPRSFLGS: /* indirection */ cp++; break; default: /* illegal type */ errno = EMSGSIZE; return (-1); } break; } if (cp > eom) { errno = EMSGSIZE; return (-1); } *ptrptr = cp; return (0); } /* Private. */ /* * special(ch) * Thinking in noninternationalized USASCII (per the DNS spec), * is this characted special ("in need of quoting") ? * return: * boolean. */ static int special(int ch) { switch (ch) { case 0x22: /* '"' */ case 0x2E: /* '.' */ case 0x3B: /* ';' */ case 0x5C: /* '\\' */ /* Special modifiers in zone files. */ case 0x40: /* '@' */ case 0x24: /* '$' */ return (1); default: return (0); } } /* * printable(ch) * Thinking in noninternationalized USASCII (per the DNS spec), * is this character visible and not a space when printed ? * return: * boolean. */ static int printable(int ch) { return (ch > 0x20 && ch < 0x7f); } /* * Thinking in noninternationalized USASCII (per the DNS spec), * convert this character to lower case if it's upper case. */ static int mklower(int ch) { if (ch >= 0x41 && ch <= 0x5A) return (ch + 0x20); return (ch); } /* * dn_find(domain, msg, dnptrs, lastdnptr) * Search for the counted-label name in an array of compressed names. * return: * offset from msg if found, or -1. * notes: * dnptrs is the pointer to the first name on the list, * not the pointer to the start of the message. */ static int dn_find(const u_char *domain, const u_char *msg, const u_char * const *dnptrs, const u_char * const *lastdnptr) { const u_char *dn, *cp, *sp; const u_char * const *cpp; u_int n; for (cpp = dnptrs; cpp < lastdnptr; cpp++) { dn = domain; sp = cp = *cpp; while ((n = *cp++) != 0) { /* * check for indirection */ switch (n & NS_CMPRSFLGS) { case 0: /* normal case, n == len */ if (n != *dn++) goto next; for ((void)NULL; n > 0; n--) if (mklower(*dn++) != mklower(*cp++)) goto next; /* Is next root for both ? */ if (*dn == '\0' && *cp == '\0') return (sp - msg); if (*dn) continue; goto next; case NS_CMPRSFLGS: /* indirection */ cp = msg + (((n & 0x3f) << 8) | *cp); break; default: /* illegal type */ errno = EMSGSIZE; return (-1); } } next: ; } errno = ENOENT; return (-1); } dhcp-4.2.4/common/options.c000644 000765 000024 00000327422 11731747771 015547 0ustar00sarstaff000000 000000 /* options.c DHCP options parsing and reassembly. */ /* * Copyright (c) 2004-2012 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1995-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ * * This software has been written for Internet Systems Consortium * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. * To learn more about Internet Systems Consortium, see * ``https://www.isc.org/''. To learn more about Vixie Enterprises, * see ``http://www.vix.com''. To learn more about Nominum, Inc., see * ``http://www.nominum.com''. */ #define DHCP_OPTION_DATA #include "dhcpd.h" #include #include struct option *vendor_cfg_option; static int pretty_text(char **, char *, const unsigned char **, const unsigned char *, int); static int pretty_domain(char **, char *, const unsigned char **, const unsigned char *); static int prepare_option_buffer(struct universe *universe, struct buffer *bp, unsigned char *buffer, unsigned length, unsigned code, int terminatep, struct option_cache **opp); /* Parse all available options out of the specified packet. */ int parse_options (packet) struct packet *packet; { struct option_cache *op = (struct option_cache *)0; /* Allocate a new option state. */ if (!option_state_allocate (&packet -> options, MDL)) { packet -> options_valid = 0; return 0; } /* If we don't see the magic cookie, there's nothing to parse. */ if (memcmp (packet -> raw -> options, DHCP_OPTIONS_COOKIE, 4)) { packet -> options_valid = 0; return 1; } /* Go through the options field, up to the end of the packet or the End field. */ if (!parse_option_buffer (packet -> options, &packet -> raw -> options [4], (packet -> packet_length - DHCP_FIXED_NON_UDP - 4), &dhcp_universe)) { /* STSN servers have a bug where they send a mangled domain-name option, and whatever is beyond that in the packet is junk. Microsoft clients accept this, which is probably why whoever implemented the STSN server isn't aware of the problem yet. To work around this, we will accept corrupt packets from the server if they contain a valid DHCP_MESSAGE_TYPE option, but will not accept any corrupt client packets (the ISC DHCP server is sufficiently widely used that it is probably beneficial for it to be picky) and will not accept packets whose type can't be determined. */ if ((op = lookup_option (&dhcp_universe, packet -> options, DHO_DHCP_MESSAGE_TYPE))) { if (!op -> data.data || (op -> data.data [0] != DHCPOFFER && op -> data.data [0] != DHCPACK && op -> data.data [0] != DHCPNAK)) return 0; } else return 0; } /* If we parsed a DHCP Option Overload option, parse more options out of the buffer(s) containing them. */ if ((op = lookup_option (&dhcp_universe, packet -> options, DHO_DHCP_OPTION_OVERLOAD))) { if (op -> data.data [0] & 1) { if (!parse_option_buffer (packet -> options, (unsigned char *)packet -> raw -> file, sizeof packet -> raw -> file, &dhcp_universe)) return 0; } if (op -> data.data [0] & 2) { if (!parse_option_buffer (packet -> options, (unsigned char *)packet -> raw -> sname, sizeof packet -> raw -> sname, &dhcp_universe)) return 0; } } packet -> options_valid = 1; return 1; } /* Parse options out of the specified buffer, storing addresses of option * values in packet->options. */ int parse_option_buffer (options, buffer, length, universe) struct option_state *options; const unsigned char *buffer; unsigned length; struct universe *universe; { unsigned len, offset; unsigned code; struct option_cache *op = NULL, *nop = NULL; struct buffer *bp = (struct buffer *)0; struct option *option = NULL; char *reason = "general failure"; if (!buffer_allocate (&bp, length, MDL)) { log_error ("no memory for option buffer."); return 0; } memcpy (bp -> data, buffer, length); for (offset = 0; (offset + universe->tag_size) <= length && (code = universe->get_tag(buffer + offset)) != universe->end; ) { offset += universe->tag_size; /* Pad options don't have a length - just skip them. */ if (code == DHO_PAD) continue; /* Don't look for length if the buffer isn't that big. */ if ((offset + universe->length_size) > length) { reason = "code tag at end of buffer - missing " "length field"; goto bogus; } /* All other fields (except PAD and END handled above) * have a length field, unless it's a DHCPv6 zero-length * options space (eg any of the enterprise-id'd options). * * Zero-length-size option spaces basically consume the * entire options buffer, so have at it. */ if (universe->get_length != NULL) len = universe->get_length(buffer + offset); else if (universe->length_size == 0) len = length - universe->tag_size; else { log_fatal("Improperly configured option space(%s): " "may not have a nonzero length size " "AND a NULL get_length function.", universe->name); /* Silence compiler warnings. */ return 0; } offset += universe->length_size; option_code_hash_lookup(&option, universe->code_hash, &code, 0, MDL); /* If the length is outrageous, the options are bad. */ if (offset + len > length) { reason = "option length exceeds option buffer length"; bogus: log_error("parse_option_buffer: malformed option " "%s.%s (code %u): %s.", universe->name, option ? option->name : "", code, reason); buffer_dereference (&bp, MDL); return 0; } /* If the option contains an encapsulation, parse it. If the parse fails, or the option isn't an encapsulation (by far the most common case), or the option isn't entirely an encapsulation, keep the raw data as well. */ if (!(option && (option->format[0] == 'e' || option->format[0] == 'E') && (parse_encapsulated_suboptions(options, option, bp->data + offset, len, universe, NULL)))) { op = lookup_option(universe, options, code); if (op != NULL && universe->concat_duplicates) { struct data_string new; memset(&new, 0, sizeof new); if (!buffer_allocate(&new.buffer, op->data.len + len, MDL)) { log_error("parse_option_buffer: " "No memory."); buffer_dereference(&bp, MDL); return 0; } /* Copy old option to new data object. */ memcpy(new.buffer->data, op->data.data, op->data.len); /* Concat new option behind old. */ memcpy(new.buffer->data + op->data.len, bp->data + offset, len); new.len = op->data.len + len; new.data = new.buffer->data; /* Save new concat'd object. */ data_string_forget(&op->data, MDL); data_string_copy(&op->data, &new, MDL); data_string_forget(&new, MDL); } else if (op != NULL) { /* We must append this statement onto the * end of the list. */ while (op->next != NULL) op = op->next; if (!option_cache_allocate(&nop, MDL)) { log_error("parse_option_buffer: " "No memory."); buffer_dereference(&bp, MDL); return 0; } option_reference(&nop->option, op->option, MDL); nop->data.buffer = NULL; buffer_reference(&nop->data.buffer, bp, MDL); nop->data.data = bp->data + offset; nop->data.len = len; option_cache_reference(&op->next, nop, MDL); option_cache_dereference(&nop, MDL); } else { save_option_buffer(universe, options, bp, bp->data + offset, len, code, 1); } } option_dereference(&option, MDL); offset += len; } buffer_dereference (&bp, MDL); return 1; } /* If an option in an option buffer turns out to be an encapsulation, figure out what to do. If we don't know how to de-encapsulate it, or it's not well-formed, return zero; otherwise, return 1, indicating that we succeeded in de-encapsulating it. */ struct universe *find_option_universe (struct option *eopt, const char *uname) { int i; char *s, *t; struct universe *universe = (struct universe *)0; /* Look for the E option in the option format. */ s = strchr (eopt -> format, 'E'); if (!s) { log_error ("internal encapsulation format error 1."); return 0; } /* Look for the universe name in the option format. */ t = strchr (++s, '.'); /* If there was no trailing '.', or there's something after the trailing '.', the option is bogus and we can't use it. */ if (!t || t [1]) { log_error ("internal encapsulation format error 2."); return 0; } if (t == s && uname) { for (i = 0; i < universe_count; i++) { if (!strcmp (universes [i] -> name, uname)) { universe = universes [i]; break; } } } else if (t != s) { for (i = 0; i < universe_count; i++) { if (strlen (universes [i] -> name) == t - s && !memcmp (universes [i] -> name, s, (unsigned)(t - s))) { universe = universes [i]; break; } } } return universe; } /* If an option in an option buffer turns out to be an encapsulation, figure out what to do. If we don't know how to de-encapsulate it, or it's not well-formed, return zero; otherwise, return 1, indicating that we succeeded in de-encapsulating it. */ int parse_encapsulated_suboptions (struct option_state *options, struct option *eopt, const unsigned char *buffer, unsigned len, struct universe *eu, const char *uname) { int i; struct universe *universe = find_option_universe (eopt, uname); /* If we didn't find the universe, we can't do anything with it right now (e.g., we can't decode vendor options until we've decoded the packet and executed the scopes that it matches). */ if (!universe) return 0; /* If we don't have a decoding function for it, we can't decode it. */ if (!universe -> decode) return 0; i = (*universe -> decode) (options, buffer, len, universe); /* If there is stuff before the suboptions, we have to keep it. */ if (eopt -> format [0] != 'E') return 0; /* Otherwise, return the status of the decode function. */ return i; } int fqdn_universe_decode (struct option_state *options, const unsigned char *buffer, unsigned length, struct universe *u) { struct buffer *bp = (struct buffer *)0; /* FQDN options have to be at least four bytes long. */ if (length < 3) return 0; /* Save the contents of the option in a buffer. */ if (!buffer_allocate (&bp, length + 4, MDL)) { log_error ("no memory for option buffer."); return 0; } memcpy (&bp -> data [3], buffer + 1, length - 1); if (buffer [0] & 4) /* encoded */ bp -> data [0] = 1; else bp -> data [0] = 0; if (!save_option_buffer(&fqdn_universe, options, bp, bp->data, 1, FQDN_ENCODED, 0)) { bad: buffer_dereference (&bp, MDL); return 0; } if (buffer [0] & 1) /* server-update */ bp -> data [2] = 1; else bp -> data [2] = 0; if (buffer [0] & 2) /* no-client-update */ bp -> data [1] = 1; else bp -> data [1] = 0; /* XXX Ideally we should store the name in DNS format, so if the XXX label isn't in DNS format, we convert it to DNS format, XXX rather than converting labels specified in DNS format to XXX the plain ASCII representation. But that's hard, so XXX not now. */ /* Not encoded using DNS format? */ if (!bp -> data [0]) { unsigned i; /* Some broken clients NUL-terminate this option. */ if (buffer [length - 1] == 0) { --length; bp -> data [1] = 1; } /* Determine the length of the hostname component of the name. If the name contains no '.' character, it represents a non-qualified label. */ for (i = 3; i < length && buffer [i] != '.'; i++); i -= 3; /* Note: If the client sends a FQDN, the first '.' will be used as a NUL terminator for the hostname. */ if (i && (!save_option_buffer(&fqdn_universe, options, bp, &bp->data[5], i, FQDN_HOSTNAME, 0))) goto bad; /* Note: If the client sends a single label, the FQDN_DOMAINNAME option won't be set. */ if (length > 4 + i && (!save_option_buffer(&fqdn_universe, options, bp, &bp -> data[6 + i], length - 4 - i, FQDN_DOMAINNAME, 1))) goto bad; /* Also save the whole name. */ if (length > 3) { if (!save_option_buffer(&fqdn_universe, options, bp, &bp -> data [5], length - 3, FQDN_FQDN, 1)) goto bad; } } else { unsigned len; unsigned total_len = 0; unsigned first_len = 0; int terminated = 0; unsigned char *s; s = &bp -> data[5]; while (s < &bp -> data[0] + length + 2) { len = *s; if (len > 63) { log_info ("fancy bits in fqdn option"); return 0; } if (len == 0) { terminated = 1; break; } if (s + len > &bp -> data [0] + length + 3) { log_info ("fqdn tag longer than buffer"); return 0; } if (first_len == 0) { first_len = len; } *s = '.'; s += len + 1; total_len += len + 1; } /* We wind up with a length that's one too many because we shouldn't increment for the last label, but there's no way to tell we're at the last label until we exit the loop. :'*/ if (total_len > 0) total_len--; if (!terminated) { first_len = total_len; } if (first_len > 0 && !save_option_buffer(&fqdn_universe, options, bp, &bp -> data[6], first_len, FQDN_HOSTNAME, 0)) goto bad; if (total_len > 0 && first_len != total_len) { if (!save_option_buffer(&fqdn_universe, options, bp, &bp->data[6 + first_len], total_len - first_len, FQDN_DOMAINNAME, 1)) goto bad; } if (total_len > 0) if (!save_option_buffer (&fqdn_universe, options, bp, &bp -> data [6], total_len, FQDN_FQDN, 1)) goto bad; } if (!save_option_buffer (&fqdn_universe, options, bp, &bp -> data [1], 1, FQDN_NO_CLIENT_UPDATE, 0)) goto bad; if (!save_option_buffer (&fqdn_universe, options, bp, &bp -> data [2], 1, FQDN_SERVER_UPDATE, 0)) goto bad; if (!save_option_buffer (&fqdn_universe, options, bp, &bp -> data [3], 1, FQDN_RCODE1, 0)) goto bad; if (!save_option_buffer (&fqdn_universe, options, bp, &bp -> data [4], 1, FQDN_RCODE2, 0)) goto bad; buffer_dereference (&bp, MDL); return 1; } /* * Load all options into a buffer, and then split them out into the three * separate fields in the dhcp packet (options, file, and sname) where * options can be stored. */ int cons_options(struct packet *inpacket, struct dhcp_packet *outpacket, struct lease *lease, struct client_state *client_state, int mms, struct option_state *in_options, struct option_state *cfg_options, struct binding_scope **scope, int overload_avail, int terminate, int bootpp, struct data_string *prl, const char *vuname) { #define PRIORITY_COUNT 300 unsigned priority_list[PRIORITY_COUNT]; int priority_len; unsigned char buffer[4096], agentopts[1024]; unsigned index = 0; unsigned mb_size = 0, mb_max = 0; unsigned option_size = 0, agent_size = 0; unsigned length; int i; struct option_cache *op; struct data_string ds; pair pp, *hash; int overload_used = 0; int of1 = 0, of2 = 0; memset(&ds, 0, sizeof ds); /* * If there's a Maximum Message Size option in the incoming packet * and no alternate maximum message size has been specified, or * if the one specified in the packet is shorter than the * alternative, take the one in the packet. */ if (inpacket && (op = lookup_option(&dhcp_universe, inpacket->options, DHO_DHCP_MAX_MESSAGE_SIZE))) { evaluate_option_cache(&ds, inpacket, lease, client_state, in_options, cfg_options, scope, op, MDL); if (ds.len >= sizeof (u_int16_t)) { i = getUShort(ds.data); if(!mms || (i < mms)) mms = i; } data_string_forget(&ds, MDL); } /* * If the client has provided a maximum DHCP message size, * use that, up to the MTU limit. Otherwise, if it's BOOTP, * only 64 bytes; otherwise use up to the minimum IP MTU size * (576 bytes). * * XXX if a BOOTP client specifies a max message size, we will * honor it. */ if (mms) { if (mms < DHCP_MTU_MIN) /* Enforce minimum packet size, per RFC 2132 */ mb_size = DHCP_MIN_OPTION_LEN; else if (mms > DHCP_MTU_MAX) /* * TODO: Packets longer than 1500 bytes really * should be allowed, but it requires upstream * changes to the way the packet is allocated. For * now, we forbid them. They won't be needed very * often anyway. */ mb_size = DHCP_MAX_OPTION_LEN; else mb_size = mms - DHCP_FIXED_LEN; } else if (bootpp) { mb_size = 64; if (inpacket != NULL && (inpacket->packet_length >= 64 + DHCP_FIXED_NON_UDP)) mb_size = inpacket->packet_length - DHCP_FIXED_NON_UDP; } else mb_size = DHCP_MIN_OPTION_LEN; /* * If answering a client message, see whether any relay agent * options were included with the message. If so, save them * to copy back in later, and make space in the main buffer * to accommodate them */ if (client_state == NULL) { priority_list[0] = DHO_DHCP_AGENT_OPTIONS; priority_len = 1; agent_size = store_options(NULL, agentopts, 0, sizeof(agentopts), inpacket, lease, client_state, in_options, cfg_options, scope, priority_list, priority_len, 0, 0, 0, NULL); mb_size += agent_size; if (mb_size > DHCP_MAX_OPTION_LEN) mb_size = DHCP_MAX_OPTION_LEN; } /* * Set offsets for buffer data to be copied into filename * and servername fields */ mb_max = mb_size; if (overload_avail & 1) { of1 = mb_max; mb_max += DHCP_FILE_LEN; } if (overload_avail & 2) { of2 = mb_max; mb_max += DHCP_SNAME_LEN; } /* * Preload the option priority list with protocol-mandatory options. * This effectively gives these options the highest priority. * This provides the order for any available options, the option * must be in the option cache in order to actually be included. */ priority_len = 0; priority_list[priority_len++] = DHO_DHCP_MESSAGE_TYPE; priority_list[priority_len++] = DHO_DHCP_SERVER_IDENTIFIER; priority_list[priority_len++] = DHO_DHCP_LEASE_TIME; priority_list[priority_len++] = DHO_DHCP_RENEWAL_TIME; priority_list[priority_len++] = DHO_DHCP_REBINDING_TIME; priority_list[priority_len++] = DHO_DHCP_MESSAGE; priority_list[priority_len++] = DHO_DHCP_REQUESTED_ADDRESS; priority_list[priority_len++] = DHO_ASSOCIATED_IP; if (prl != NULL && prl->len > 0) { if ((op = lookup_option(&dhcp_universe, cfg_options, DHO_SUBNET_SELECTION))) { if (priority_len < PRIORITY_COUNT) priority_list[priority_len++] = DHO_SUBNET_SELECTION; } data_string_truncate(prl, (PRIORITY_COUNT - priority_len)); /* * Copy the client's PRL onto the priority_list after our high * priority header. */ for (i = 0; i < prl->len; i++) { /* * Prevent client from changing order of delivery * of relay agent information option. */ if (prl->data[i] != DHO_DHCP_AGENT_OPTIONS) priority_list[priority_len++] = prl->data[i]; } /* * If the client doesn't request the FQDN option explicitly, * to indicate priority, consider it lowest priority. Fit * in the packet if there is space. Note that the option * may only be included if the client supplied one. */ if ((priority_len < PRIORITY_COUNT) && (lookup_option(&fqdn_universe, inpacket->options, FQDN_ENCODED) != NULL)) priority_list[priority_len++] = DHO_FQDN; /* * Some DHCP Servers will give the subnet-mask option if * it is not on the parameter request list - so some client * implementations have come to rely on this - so we will * also make sure we supply this, at lowest priority. * * This is only done in response to DHCPDISCOVER or * DHCPREQUEST messages, to avoid providing the option on * DHCPINFORM or DHCPLEASEQUERY responses (if the client * didn't request it). */ if ((priority_len < PRIORITY_COUNT) && ((inpacket->packet_type == DHCPDISCOVER) || (inpacket->packet_type == DHCPREQUEST))) priority_list[priority_len++] = DHO_SUBNET_MASK; } else { /* * First, hardcode some more options that ought to be * sent first...these are high priority to have in the * packet. */ priority_list[priority_len++] = DHO_SUBNET_MASK; priority_list[priority_len++] = DHO_ROUTERS; priority_list[priority_len++] = DHO_DOMAIN_NAME_SERVERS; priority_list[priority_len++] = DHO_HOST_NAME; priority_list[priority_len++] = DHO_FQDN; /* * Append a list of the standard DHCP options from the * standard DHCP option space. Actually, if a site * option space hasn't been specified, we wind up * treating the dhcp option space as the site option * space, and the first for loop is skipped, because * it's slightly more general to do it this way, * taking the 1Q99 DHCP futures work into account. */ if (cfg_options->site_code_min) { for (i = 0; i < OPTION_HASH_SIZE; i++) { hash = cfg_options->universes[dhcp_universe.index]; if (hash) { for (pp = hash[i]; pp; pp = pp->cdr) { op = (struct option_cache *)(pp->car); if (op->option->code < cfg_options->site_code_min && priority_len < PRIORITY_COUNT && op->option->code != DHO_DHCP_AGENT_OPTIONS) priority_list[priority_len++] = op->option->code; } } } } /* * Now cycle through the site option space, or if there * is no site option space, we'll be cycling through the * dhcp option space. */ for (i = 0; i < OPTION_HASH_SIZE; i++) { hash = cfg_options->universes[cfg_options->site_universe]; if (hash != NULL) for (pp = hash[i]; pp; pp = pp->cdr) { op = (struct option_cache *)(pp->car); if (op->option->code >= cfg_options->site_code_min && priority_len < PRIORITY_COUNT && op->option->code != DHO_DHCP_AGENT_OPTIONS) priority_list[priority_len++] = op->option->code; } } /* * Put any spaces that are encapsulated on the list, * sort out whether they contain values later. */ for (i = 0; i < cfg_options->universe_count; i++) { if (universes[i]->enc_opt && priority_len < PRIORITY_COUNT && universes[i]->enc_opt->universe == &dhcp_universe) { if (universes[i]->enc_opt->code != DHO_DHCP_AGENT_OPTIONS) priority_list[priority_len++] = universes[i]->enc_opt->code; } } /* * The vendor option space can't stand on its own, so always * add it to the list. */ if (priority_len < PRIORITY_COUNT) priority_list[priority_len++] = DHO_VENDOR_ENCAPSULATED_OPTIONS; } /* Put the cookie up front... */ memcpy(buffer, DHCP_OPTIONS_COOKIE, 4); index += 4; /* Copy the options into the big buffer... */ option_size = store_options(&overload_used, buffer, index, mb_max, inpacket, lease, client_state, in_options, cfg_options, scope, priority_list, priority_len, of1, of2, terminate, vuname); /* If store_options() failed */ if (option_size == 0) return 0; /* How much was stored in the main buffer? */ index += option_size; /* * If we're going to have to overload, store the overload * option first. */ if (overload_used) { if (mb_size - agent_size - index < 3) return 0; buffer[index++] = DHO_DHCP_OPTION_OVERLOAD; buffer[index++] = 1; buffer[index++] = overload_used; if (overload_used & 1) memcpy(outpacket->file, &buffer[of1], DHCP_FILE_LEN); if (overload_used & 2) memcpy(outpacket->sname, &buffer[of2], DHCP_SNAME_LEN); } /* Now copy in preserved agent options, if any */ if (agent_size) { if (mb_size - index >= agent_size) { memcpy(&buffer[index], agentopts, agent_size); index += agent_size; } else log_error("Unable to store relay agent information " "in reply packet."); } /* Tack a DHO_END option onto the packet if we need to. */ if (index < mb_size) buffer[index++] = DHO_END; /* Copy main buffer into the options buffer of the packet */ memcpy(outpacket->options, buffer, index); /* Figure out the length. */ length = DHCP_FIXED_NON_UDP + index; return length; } /* * XXX: We currently special case collecting VSIO options. * We should be able to handle this in a more generic fashion, by * including any encapsulated options that are present and desired. * This will look something like the VSIO handling VSIO code. * We may also consider handling the ORO-like options within * encapsulated spaces. */ struct vsio_state { char *buf; int buflen; int bufpos; }; static void vsio_options(struct option_cache *oc, struct packet *packet, struct lease *dummy_lease, struct client_state *dummy_client_state, struct option_state *dummy_opt_state, struct option_state *opt_state, struct binding_scope **dummy_binding_scope, struct universe *universe, void *void_vsio_state) { struct vsio_state *vs = (struct vsio_state *)void_vsio_state; struct data_string ds; int total_len; memset(&ds, 0, sizeof(ds)); if (evaluate_option_cache(&ds, packet, NULL, NULL, opt_state, NULL, &global_scope, oc, MDL)) { total_len = ds.len + universe->tag_size + universe->length_size; if (total_len <= (vs->buflen - vs->bufpos)) { if (universe->tag_size == 1) { vs->buf[vs->bufpos++] = oc->option->code; } else if (universe->tag_size == 2) { putUShort((unsigned char *)vs->buf+vs->bufpos, oc->option->code); vs->bufpos += 2; } else if (universe->tag_size == 4) { putULong((unsigned char *)vs->buf+vs->bufpos, oc->option->code); vs->bufpos += 4; } if (universe->length_size == 1) { vs->buf[vs->bufpos++] = ds.len; } else if (universe->length_size == 2) { putUShort((unsigned char *)vs->buf+vs->bufpos, ds.len); vs->bufpos += 2; } else if (universe->length_size == 4) { putULong((unsigned char *)vs->buf+vs->bufpos, ds.len); vs->bufpos += 4; } memcpy(vs->buf + vs->bufpos, ds.data, ds.len); vs->bufpos += ds.len; } else { log_debug("No space for option %d in VSIO space %s.", oc->option->code, universe->name); } data_string_forget(&ds, MDL); } else { log_error("Error evaluating option %d in VSIO space %s.", oc->option->code, universe->name); } } /* * Stores the options from the DHCPv6 universe into the buffer given. * * Required options are given as a 0-terminated list of option codes. * Once those are added, the ORO is consulted. */ int store_options6(char *buf, int buflen, struct option_state *opt_state, struct packet *packet, const int *required_opts, struct data_string *oro) { int i, j; struct option_cache *oc; struct option *o; struct data_string ds; int bufpos; int oro_size; u_int16_t code; int in_required_opts; int vsio_option_code; int vsio_wanted; struct vsio_state vs; unsigned char *tmp; bufpos = 0; vsio_wanted = 0; /* * Find the option code for the VSIO universe. */ vsio_option_code = 0; o = vsio_universe.enc_opt; while (o != NULL) { if (o->universe == &dhcpv6_universe) { vsio_option_code = o->code; break; } o = o->universe->enc_opt; } if (vsio_option_code == 0) { log_fatal("No VSIO option code found."); } if (required_opts != NULL) { for (i=0; required_opts[i] != 0; i++) { if (required_opts[i] == vsio_option_code) { vsio_wanted = 1; } oc = lookup_option(&dhcpv6_universe, opt_state, required_opts[i]); if (oc == NULL) { continue; } memset(&ds, 0, sizeof(ds)); for (; oc != NULL ; oc = oc->next) { if (evaluate_option_cache(&ds, packet, NULL, NULL, opt_state, NULL, &global_scope, oc, MDL)) { if ((ds.len + 4) <= (buflen - bufpos)) { tmp = (unsigned char *)buf; tmp += bufpos; /* option tag */ putUShort(tmp, required_opts[i]); /* option length */ putUShort(tmp+2, ds.len); /* option data */ memcpy(tmp+4, ds.data, ds.len); /* update position */ bufpos += (4 + ds.len); } else { log_debug("No space for " "option %d", required_opts[i]); } data_string_forget(&ds, MDL); } else { log_error("Error evaluating option %d", required_opts[i]); } } } } if (oro == NULL) { oro_size = 0; } else { oro_size = oro->len / 2; } for (i=0; idata+(i*2), 2); code = ntohs(code); /* * See if we've already included this option because * it is required. */ in_required_opts = 0; if (required_opts != NULL) { for (j=0; required_opts[j] != 0; j++) { if (required_opts[j] == code) { in_required_opts = 1; break; } } } if (in_required_opts) { continue; } /* * See if this is the VSIO option. */ if (code == vsio_option_code) { vsio_wanted = 1; } /* * Not already added, find this option. */ oc = lookup_option(&dhcpv6_universe, opt_state, code); memset(&ds, 0, sizeof(ds)); for (; oc != NULL ; oc = oc->next) { if (evaluate_option_cache(&ds, packet, NULL, NULL, opt_state, NULL, &global_scope, oc, MDL)) { if ((ds.len + 4) <= (buflen - bufpos)) { tmp = (unsigned char *)buf + bufpos; /* option tag */ putUShort(tmp, code); /* option length */ putUShort(tmp+2, ds.len); /* option data */ memcpy(tmp+4, ds.data, ds.len); /* update position */ bufpos += (4 + ds.len); } else { log_debug("No space for option %d", code); } data_string_forget(&ds, MDL); } else { log_error("Error evaluating option %d", code); } } } if (vsio_wanted) { for (i=0; i < opt_state->universe_count; i++) { if (opt_state->universes[i] != NULL) { o = universes[i]->enc_opt; if ((o != NULL) && (o->universe == &vsio_universe)) { /* * Add the data from this VSIO option. */ vs.buf = buf; vs.buflen = buflen; vs.bufpos = bufpos+8; option_space_foreach(packet, NULL, NULL, NULL, opt_state, NULL, universes[i], (void *)&vs, vsio_options); /* * If there was actually data here, * add the "header". */ if (vs.bufpos > bufpos+8) { tmp = (unsigned char *)buf + bufpos; putUShort(tmp, vsio_option_code); putUShort(tmp+2, vs.bufpos-bufpos-4); putULong(tmp+4, o->code); bufpos = vs.bufpos; } } } } } return bufpos; } /* * Store all the requested options into the requested buffer. * XXX: ought to be static */ int store_options(int *ocount, unsigned char *buffer, unsigned index, unsigned buflen, struct packet *packet, struct lease *lease, struct client_state *client_state, struct option_state *in_options, struct option_state *cfg_options, struct binding_scope **scope, unsigned *priority_list, int priority_len, unsigned first_cutoff, int second_cutoff, int terminate, const char *vuname) { int bufix = 0, six = 0, tix = 0; int i; int ix; int tto; int bufend, sbufend; struct data_string od; struct option_cache *oc; struct option *option = NULL; unsigned code; /* * These arguments are relative to the start of the buffer, so * reduce them by the current buffer index, and advance the * buffer pointer to where we're going to start writing. */ buffer = &buffer[index]; buflen -= index; if (first_cutoff) first_cutoff -= index; if (second_cutoff) second_cutoff -= index; /* Calculate the start and end of each section of the buffer */ bufend = sbufend = buflen; if (first_cutoff) { if (first_cutoff >= buflen) log_fatal("%s:%d:store_options: Invalid first cutoff.", MDL); bufend = first_cutoff; if (second_cutoff) { if (second_cutoff >= buflen) log_fatal("%s:%d:store_options: Invalid second cutoff.", MDL); sbufend = second_cutoff; } } else if (second_cutoff) { if (second_cutoff >= buflen) log_fatal("%s:%d:store_options: Invalid second cutoff.", MDL); bufend = second_cutoff; } memset (&od, 0, sizeof od); /* Eliminate duplicate options from the parameter request list. * Enforce RFC-mandated ordering of options that are present. */ for (i = 0; i < priority_len - 1; i++) { /* Eliminate duplicates. */ tto = 0; for (ix = i + 1; ix < priority_len + tto; ix++) { if (tto) priority_list [ix - tto] = priority_list [ix]; if (priority_list [i] == priority_list [ix]) { tto++; priority_len--; } } /* Enforce ordering of SUBNET_MASK options, according to * RFC2132 Section 3.3: * * If both the subnet mask and the router option are * specified in a DHCP reply, the subnet mask option MUST * be first. * * This guidance does not specify what to do if the client * PRL explicitly requests the options out of order, it is * a general statement. */ if (priority_list[i] == DHO_SUBNET_MASK) { for (ix = i - 1 ; ix >= 0 ; ix--) { if (priority_list[ix] == DHO_ROUTERS) { /* swap */ priority_list[ix] = DHO_SUBNET_MASK; priority_list[i] = DHO_ROUTERS; break; } } } } /* Copy out the options in the order that they appear in the priority list... */ for (i = 0; i < priority_len; i++) { /* Number of bytes left to store (some may already have been stored by a previous pass). */ unsigned length; int optstart, soptstart, toptstart; struct universe *u; int have_encapsulation = 0; struct data_string encapsulation; int splitup; memset (&encapsulation, 0, sizeof encapsulation); have_encapsulation = 0; if (option != NULL) option_dereference(&option, MDL); /* Code for next option to try to store. */ code = priority_list [i]; /* Look up the option in the site option space if the code is above the cutoff, otherwise in the DHCP option space. */ if (code >= cfg_options -> site_code_min) u = universes [cfg_options -> site_universe]; else u = &dhcp_universe; oc = lookup_option (u, cfg_options, code); if (oc && oc->option) option_reference(&option, oc->option, MDL); else option_code_hash_lookup(&option, u->code_hash, &code, 0, MDL); /* If it's a straight encapsulation, and the user supplied a * value for the entire option, use that. Otherwise, search * the encapsulated space. * * If it's a limited encapsulation with preceding data, and the * user supplied values for the preceding bytes, search the * encapsulated space. */ if ((option != NULL) && (((oc == NULL) && (option->format[0] == 'E')) || ((oc != NULL) && (option->format[0] == 'e')))) { static char *s, *t; struct option_cache *tmp; struct data_string name; s = strchr (option->format, 'E'); if (s) t = strchr (++s, '.'); if (s && t) { memset (&name, 0, sizeof name); /* A zero-length universe name means the vendor option space, if one is defined. */ if (t == s) { if (vendor_cfg_option) { tmp = lookup_option (vendor_cfg_option -> universe, cfg_options, vendor_cfg_option -> code); if (tmp) evaluate_option_cache (&name, packet, lease, client_state, in_options, cfg_options, scope, tmp, MDL); } else if (vuname) { name.data = (unsigned char *)s; name.len = strlen (s); } } else { name.data = (unsigned char *)s; name.len = t - s; } /* If we found a universe, and there are options configured for that universe, try to encapsulate it. */ if (name.len) { have_encapsulation = (option_space_encapsulate (&encapsulation, packet, lease, client_state, in_options, cfg_options, scope, &name)); data_string_forget (&name, MDL); } } } /* In order to avoid memory leaks, we have to get to here with any option cache that we allocated in tmp not being referenced by tmp, and whatever option cache is referenced by oc being an actual reference. lookup_option doesn't generate a reference (this needs to be fixed), so the preceding goop ensures that if we *didn't* generate a new option cache, oc still winds up holding an actual reference. */ /* If no data is available for this option, skip it. */ if (!oc && !have_encapsulation) { continue; } /* Find the value of the option... */ od.len = 0; if (oc) { evaluate_option_cache (&od, packet, lease, client_state, in_options, cfg_options, scope, oc, MDL); /* If we have encapsulation for this option, and an oc * lookup succeeded, but the evaluation failed, it is * either because this is a complex atom (atoms before * E on format list) and the top half of the option is * not configured, or this is a simple encapsulated * space and the evaluator is giving us a NULL. Prefer * the evaluator's opinion over the subspace. */ if (!od.len) { data_string_forget (&encapsulation, MDL); data_string_forget (&od, MDL); continue; } } /* We should now have a constant length for the option. */ length = od.len; if (have_encapsulation) { length += encapsulation.len; /* od.len can be nonzero if we got here without an * oc (cache lookup failed), but did have an encapsulated * simple encapsulation space. */ if (!od.len) { data_string_copy (&od, &encapsulation, MDL); data_string_forget (&encapsulation, MDL); } else { struct buffer *bp = (struct buffer *)0; if (!buffer_allocate (&bp, length, MDL)) { option_cache_dereference (&oc, MDL); data_string_forget (&od, MDL); data_string_forget (&encapsulation, MDL); continue; } memcpy (&bp -> data [0], od.data, od.len); memcpy (&bp -> data [od.len], encapsulation.data, encapsulation.len); data_string_forget (&od, MDL); data_string_forget (&encapsulation, MDL); od.data = &bp -> data [0]; buffer_reference (&od.buffer, bp, MDL); buffer_dereference (&bp, MDL); od.len = length; od.terminated = 0; } } /* Do we add a NUL? */ if (terminate && option && format_has_text(option->format)) { length++; tto = 1; } else { tto = 0; } /* Try to store the option. */ /* If the option's length is more than 255, we must store it in multiple hunks. Store 255-byte hunks first. However, in any case, if the option data will cross a buffer boundary, split it across that boundary. */ if (length > 255) splitup = 1; else splitup = 0; ix = 0; optstart = bufix; soptstart = six; toptstart = tix; while (length) { unsigned incr = length; int *pix; unsigned char *base; /* Try to fit it in the options buffer. */ if (!splitup && ((!six && !tix && (i == priority_len - 1) && (bufix + 2 + length < bufend)) || (bufix + 5 + length < bufend))) { base = buffer; pix = &bufix; /* Try to fit it in the second buffer. */ } else if (!splitup && first_cutoff && (first_cutoff + six + 3 + length < sbufend)) { base = &buffer[first_cutoff]; pix = &six; /* Try to fit it in the third buffer. */ } else if (!splitup && second_cutoff && (second_cutoff + tix + 3 + length < buflen)) { base = &buffer[second_cutoff]; pix = &tix; /* Split the option up into the remaining space. */ } else { splitup = 1; /* Use any remaining options space. */ if (bufix + 6 < bufend) { incr = bufend - bufix - 5; base = buffer; pix = &bufix; /* Use any remaining first_cutoff space. */ } else if (first_cutoff && (first_cutoff + six + 4 < sbufend)) { incr = sbufend - (first_cutoff + six) - 3; base = &buffer[first_cutoff]; pix = &six; /* Use any remaining second_cutoff space. */ } else if (second_cutoff && (second_cutoff + tix + 4 < buflen)) { incr = buflen - (second_cutoff + tix) - 3; base = &buffer[second_cutoff]; pix = &tix; /* Give up, roll back this option. */ } else { bufix = optstart; six = soptstart; tix = toptstart; break; } } if (incr > length) incr = length; if (incr > 255) incr = 255; /* Everything looks good - copy it in! */ base [*pix] = code; base [*pix + 1] = (unsigned char)incr; if (tto && incr == length) { if (incr > 1) memcpy (base + *pix + 2, od.data + ix, (unsigned)(incr - 1)); base [*pix + 2 + incr - 1] = 0; } else { memcpy (base + *pix + 2, od.data + ix, (unsigned)incr); } length -= incr; ix += incr; *pix += 2 + incr; } data_string_forget (&od, MDL); } if (option != NULL) option_dereference(&option, MDL); /* If we can overload, and we have, then PAD and END those spaces. */ if (first_cutoff && six) { if ((first_cutoff + six + 1) < sbufend) memset (&buffer[first_cutoff + six + 1], DHO_PAD, sbufend - (first_cutoff + six + 1)); else if (first_cutoff + six >= sbufend) log_fatal("Second buffer overflow in overloaded options."); buffer[first_cutoff + six] = DHO_END; if (ocount != NULL) *ocount |= 1; /* So that caller knows there's data there. */ } if (second_cutoff && tix) { if (second_cutoff + tix + 1 < buflen) { memset (&buffer[second_cutoff + tix + 1], DHO_PAD, buflen - (second_cutoff + tix + 1)); } else if (second_cutoff + tix >= buflen) log_fatal("Third buffer overflow in overloaded options."); buffer[second_cutoff + tix] = DHO_END; if (ocount != NULL) *ocount |= 2; /* So that caller knows there's data there. */ } if ((six || tix) && (bufix + 3 > bufend)) log_fatal("Not enough space for option overload option."); return bufix; } /* Return true if the format string has a variable length text option * ("t"), return false otherwise. */ int format_has_text(format) const char *format; { const char *p; p = format; while (*p != '\0') { switch (*p++) { case 'd': case 't': return 1; /* These symbols are arbitrary, not fixed or * determinable length...text options with them is * invalid (whatever the case, they are never NULL * terminated). */ case 'A': case 'a': case 'X': case 'x': case 'D': return 0; case 'c': /* 'c' only follows 'D' atoms, and indicates that * compression may be used. If there was a 'D' * atom already, we would have returned. So this * is an error, but continue looking for 't' anyway. */ log_error("format_has_text(%s): 'c' atoms are illegal " "except after 'D' atoms.", format); break; /* 'E' is variable length, but not arbitrary...you * can find its length if you can find an END option. * N is (n)-byte in length but trails a name of a * space defining the enumeration values. So treat * both the same - valid, fixed-length fields. */ case 'E': case 'N': /* Consume the space name. */ while ((*p != '\0') && (*p++ != '.')) ; break; default: break; } } return 0; } /* Determine the minimum length of a DHCP option prior to any variable * or inconsistent length formats, according to its configured format * variable (and possibly from supplied option cache contents for variable * length format symbols). */ int format_min_length(format, oc) const char *format; struct option_cache *oc; { const char *p, *name; int min_len = 0; int last_size = 0; struct enumeration *espace; p = format; while (*p != '\0') { switch (*p++) { case '6': /* IPv6 Address */ min_len += 16; last_size = 16; break; case 'I': /* IPv4 Address */ case 'l': /* int32_t */ case 'L': /* uint32_t */ case 'T': /* Lease Time, uint32_t equivalent */ min_len += 4; last_size = 4; break; case 's': /* int16_t */ case 'S': /* uint16_t */ min_len += 2; last_size = 2; break; case 'N': /* Enumeration value. */ /* Consume space name. */ name = p; p = strchr(p, '.'); if (p == NULL) log_fatal("Corrupt format: %s", format); espace = find_enumeration(name, p - name); if (espace == NULL) { log_error("Unknown enumeration: %s", format); /* Max is safest value to return. */ return INT_MAX; } min_len += espace->width; last_size = espace->width; p++; break; case 'b': /* int8_t */ case 'B': /* uint8_t */ case 'F': /* Flag that is always true. */ case 'f': /* Flag */ min_len++; last_size = 1; break; case 'o': /* Last argument is optional. */ min_len -= last_size; /* XXX: It MAY be possible to sense the end of an * encapsulated space, but right now this is too * hard to support. Return a safe value. */ case 'e': /* Encapsulation hint (there is an 'E' later). */ case 'E': /* Encapsulated options. */ return min_len; case 'd': /* "Domain name" */ case 'D': /* "rfc1035 formatted names" */ case 't': /* "ASCII Text" */ case 'X': /* "ASCII or Hex Conditional */ case 'x': /* "Hex" */ case 'A': /* Array of all that precedes. */ case 'a': /* Array of preceding symbol. */ case 'Z': /* nothing. */ return min_len; case 'c': /* Compress flag for D atom. */ log_error("format_min_length(%s): 'c' atom is illegal " "except after 'D' atom.", format); return INT_MAX; default: /* No safe value is known. */ log_error("format_min_length(%s): No safe value " "for unknown format symbols.", format); return INT_MAX; } } return min_len; } /* Format the specified option so that a human can easily read it. */ const char *pretty_print_option (option, data, len, emit_commas, emit_quotes) struct option *option; const unsigned char *data; unsigned len; int emit_commas; int emit_quotes; { static char optbuf [32768]; /* XXX */ static char *endbuf = &optbuf[sizeof(optbuf)]; int hunksize = 0; int opthunk = 0; int hunkinc = 0; int numhunk = -1; int numelem = 0; int count; int i, j, k, l; char fmtbuf[32] = ""; struct iaddr iaddr; struct enumeration *enumbuf[32]; /* MUST be same as fmtbuf */ char *op = optbuf; const unsigned char *dp = data; char comma; unsigned long tval; if (emit_commas) comma = ','; else comma = ' '; memset (enumbuf, 0, sizeof enumbuf); /* Figure out the size of the data. */ for (l = i = 0; option -> format [i]; i++, l++) { if (l >= sizeof(fmtbuf) - 1) log_fatal("Bounds failure on internal buffer at " "%s:%d", MDL); if (!numhunk) { log_error ("%s: Extra codes in format string: %s", option -> name, &(option -> format [i])); break; } numelem++; fmtbuf [l] = option -> format [i]; switch (option -> format [i]) { case 'a': case 'A': --numelem; fmtbuf [l] = 0; numhunk = 0; break; case 'E': /* Skip the universe name. */ while (option -> format [i] && option -> format [i] != '.') i++; /* Fall Through! */ case 'X': for (k = 0; k < len; k++) { if (!isascii (data [k]) || !isprint (data [k])) break; } /* If we found no bogus characters, or the bogus character we found is a trailing NUL, it's okay to print this option as text. */ if (k == len || (k + 1 == len && data [k] == 0)) { fmtbuf [l] = 't'; numhunk = -2; } else { fmtbuf [l] = 'x'; hunksize++; comma = ':'; numhunk = 0; } fmtbuf [l + 1] = 0; break; case 'c': /* The 'c' atom is a 'D' modifier only. */ log_error("'c' atom not following D atom in format " "string: %s", option->format); break; case 'D': /* * Skip the 'c' atom, if present. It does not affect * how we convert wire->text format (if compression is * present either way, we still process it). */ if (option->format[i+1] == 'c') i++; fmtbuf[l + 1] = 0; numhunk = -2; break; case 'd': fmtbuf[l] = 't'; /* Fall Through ! */ case 't': fmtbuf[l + 1] = 0; numhunk = -2; break; case 'N': k = i; while (option -> format [i] && option -> format [i] != '.') i++; enumbuf [l] = find_enumeration (&option -> format [k] + 1, i - k - 1); if (enumbuf[l] == NULL) { hunksize += 1; hunkinc = 1; } else { hunksize += enumbuf[l]->width; hunkinc = enumbuf[l]->width; } break; case '6': hunksize += 16; hunkinc = 16; break; case 'I': case 'l': case 'L': case 'T': hunksize += 4; hunkinc = 4; break; case 's': case 'S': hunksize += 2; hunkinc = 2; break; case 'b': case 'B': case 'f': case 'F': hunksize++; hunkinc = 1; break; case 'e': case 'Z': break; case 'o': opthunk += hunkinc; break; default: log_error ("%s: garbage in format string: %s", option -> name, &(option -> format [i])); break; } } /* Check for too few bytes... */ if (hunksize - opthunk > len) { log_error ("%s: expecting at least %d bytes; got %d", option -> name, hunksize, len); return ""; } /* Check for too many bytes... */ if (numhunk == -1 && hunksize < len) log_error ("%s: %d extra bytes", option -> name, len - hunksize); /* If this is an array, compute its size. */ if (!numhunk) numhunk = len / hunksize; /* See if we got an exact number of hunks. */ if (numhunk > 0 && numhunk * hunksize < len) log_error ("%s: %d extra bytes at end of array\n", option -> name, len - numhunk * hunksize); /* A one-hunk array prints the same as a single hunk. */ if (numhunk < 0) numhunk = 1; /* Cycle through the array (or hunk) printing the data. */ for (i = 0; i < numhunk; i++) { for (j = 0; j < numelem; j++) { switch (fmtbuf [j]) { case 't': /* endbuf-1 leaves room for NULL. */ k = pretty_text(&op, endbuf - 1, &dp, data + len, emit_quotes); if (k == -1) { log_error("Error printing text."); break; } *op = 0; break; case 'D': /* RFC1035 format name list */ for( ; dp < (data + len) ; dp += k) { unsigned char nbuff[NS_MAXCDNAME]; const unsigned char *nbp, *nend; nend = &nbuff[sizeof(nbuff)]; /* If this is for ISC DHCP consumption * (emit_quotes), lay it out as a list * of STRING tokens. Otherwise, it is * a space-separated list of DNS- * escaped names as /etc/resolv.conf * might digest. */ if (dp != data) { if (op + 2 > endbuf) break; if (emit_quotes) *op++ = ','; *op++ = ' '; } /* XXX: if fmtbuf[j+1] != 'c', we * should warn if the data was * compressed anyway. */ k = MRns_name_unpack(data, data + len, dp, nbuff, sizeof(nbuff)); if (k == -1) { log_error("Invalid domain " "list."); break; } /* If emit_quotes, then use ISC DHCP * escapes. Otherwise, rely only on * ns_name_ntop(). */ if (emit_quotes) { nbp = nbuff; pretty_domain(&op, endbuf-1, &nbp, nend); } else { /* ns_name_ntop() includes * a trailing NUL in its * count. */ count = MRns_name_ntop( nbuff, op, (endbuf-op)-1); if (count <= 0) { log_error("Invalid " "domain name."); break; } /* Consume all but the trailing * NUL. */ op += count - 1; /* Replace the trailing NUL * with the implicit root * (in the unlikely event the * domain name /is/ the root). */ *op++ = '.'; } } *op = '\0'; break; /* pretty-printing an array of enums is going to get ugly. */ case 'N': if (!enumbuf [j]) { tval = *dp++; goto enum_as_num; } switch (enumbuf[j]->width) { case 1: tval = getUChar(dp); break; case 2: tval = getUShort(dp); break; case 4: tval = getULong(dp); break; default: log_fatal("Impossible case at %s:%d.", MDL); return ""; } for (i = 0; ;i++) { if (!enumbuf [j] -> values [i].name) goto enum_as_num; if (enumbuf [j] -> values [i].value == tval) break; } strcpy (op, enumbuf [j] -> values [i].name); dp += enumbuf[j]->width; break; enum_as_num: sprintf(op, "%lu", tval); break; case 'I': iaddr.len = 4; memcpy(iaddr.iabuf, dp, 4); strcpy(op, piaddr(iaddr)); dp += 4; break; case '6': iaddr.len = 16; memcpy(iaddr.iabuf, dp, 16); strcpy(op, piaddr(iaddr)); dp += 16; break; case 'l': sprintf (op, "%ld", (long)getLong (dp)); dp += 4; break; case 'T': tval = getULong (dp); if (tval == -1) sprintf (op, "%s", "infinite"); else sprintf(op, "%lu", tval); break; case 'L': sprintf(op, "%lu", (unsigned long)getULong(dp)); dp += 4; break; case 's': sprintf (op, "%d", (int)getShort (dp)); dp += 2; break; case 'S': sprintf(op, "%u", (unsigned)getUShort(dp)); dp += 2; break; case 'b': sprintf (op, "%d", *(const char *)dp++); break; case 'B': sprintf (op, "%d", *dp++); break; case 'X': case 'x': sprintf (op, "%x", *dp++); break; case 'f': strcpy (op, *dp++ ? "true" : "false"); break; case 'F': strcpy (op, "true"); break; case 'e': case 'Z': *op = '\0'; break; default: log_error ("Unexpected format code %c", fmtbuf [j]); } op += strlen (op); if (dp == data + len) break; if (j + 1 < numelem && comma != ':') *op++ = ' '; } if (i + 1 < numhunk) { *op++ = comma; } if (dp == data + len) break; } return optbuf; } int get_option (result, universe, packet, lease, client_state, in_options, cfg_options, options, scope, code, file, line) struct data_string *result; struct universe *universe; struct packet *packet; struct lease *lease; struct client_state *client_state; struct option_state *in_options; struct option_state *cfg_options; struct option_state *options; struct binding_scope **scope; unsigned code; const char *file; int line; { struct option_cache *oc; if (!universe -> lookup_func) return 0; oc = ((*universe -> lookup_func) (universe, options, code)); if (!oc) return 0; if (!evaluate_option_cache (result, packet, lease, client_state, in_options, cfg_options, scope, oc, file, line)) return 0; return 1; } void set_option (universe, options, option, op) struct universe *universe; struct option_state *options; struct option_cache *option; enum statement_op op; { struct option_cache *oc, *noc; switch (op) { case if_statement: case add_statement: case eval_statement: case break_statement: default: log_error ("bogus statement type in set_option."); break; case default_option_statement: oc = lookup_option (universe, options, option -> option -> code); if (oc) break; save_option (universe, options, option); break; case supersede_option_statement: case send_option_statement: /* Install the option, replacing any existing version. */ save_option (universe, options, option); break; case append_option_statement: case prepend_option_statement: oc = lookup_option (universe, options, option -> option -> code); if (!oc) { save_option (universe, options, option); break; } /* If it's not an expression, make it into one. */ if (!oc -> expression && oc -> data.len) { if (!expression_allocate (&oc -> expression, MDL)) { log_error ("Can't allocate const expression."); break; } oc -> expression -> op = expr_const_data; data_string_copy (&oc -> expression -> data.const_data, &oc -> data, MDL); data_string_forget (&oc -> data, MDL); } noc = (struct option_cache *)0; if (!option_cache_allocate (&noc, MDL)) break; if (op == append_option_statement) { if (!make_concat (&noc -> expression, oc -> expression, option -> expression)) { option_cache_dereference (&noc, MDL); break; } } else { if (!make_concat (&noc -> expression, option -> expression, oc -> expression)) { option_cache_dereference (&noc, MDL); break; } } option_reference(&(noc->option), oc->option, MDL); save_option (universe, options, noc); option_cache_dereference (&noc, MDL); break; } } struct option_cache *lookup_option (universe, options, code) struct universe *universe; struct option_state *options; unsigned code; { if (!options) return (struct option_cache *)0; if (universe -> lookup_func) return (*universe -> lookup_func) (universe, options, code); else log_error ("can't look up options in %s space.", universe -> name); return (struct option_cache *)0; } struct option_cache *lookup_hashed_option (universe, options, code) struct universe *universe; struct option_state *options; unsigned code; { int hashix; pair bptr; pair *hash; /* Make sure there's a hash table. */ if (universe -> index >= options -> universe_count || !(options -> universes [universe -> index])) return (struct option_cache *)0; hash = options -> universes [universe -> index]; hashix = compute_option_hash (code); for (bptr = hash [hashix]; bptr; bptr = bptr -> cdr) { if (((struct option_cache *)(bptr -> car)) -> option -> code == code) return (struct option_cache *)(bptr -> car); } return (struct option_cache *)0; } /* Save a specified buffer into an option cache. */ int save_option_buffer(struct universe *universe, struct option_state *options, struct buffer *bp, unsigned char *buffer, unsigned length, unsigned code, int terminatep) { struct option_cache *op = NULL; int status = 1; status = prepare_option_buffer(universe, bp, buffer, length, code, terminatep, &op); if (status == 0) goto cleanup; save_option(universe, options, op); cleanup: if (op != NULL) option_cache_dereference(&op, MDL); return status; } /* Append a specified buffer onto the tail of an option cache. */ int append_option_buffer(struct universe *universe, struct option_state *options, struct buffer *bp, unsigned char *buffer, unsigned length, unsigned code, int terminatep) { struct option_cache *op = NULL; int status = 1; status = prepare_option_buffer(universe, bp, buffer, length, code, terminatep, &op); if (status == 0) goto cleanup; also_save_option(universe, options, op); cleanup: if (op != NULL) option_cache_dereference(&op, MDL); return status; } /* Create/copy a buffer into a new option cache. */ static int prepare_option_buffer(struct universe *universe, struct buffer *bp, unsigned char *buffer, unsigned length, unsigned code, int terminatep, struct option_cache **opp) { struct buffer *lbp = NULL; struct option *option = NULL; struct option_cache *op; int status = 1; /* Code sizes of 8, 16, and 32 bits are allowed. */ switch(universe->tag_size) { case 1: if (code > 0xff) return 0; break; case 2: if (code > 0xffff) return 0; break; case 4: if (code > 0xffffffff) return 0; break; default: log_fatal("Inconsistent universe tag size at %s:%d.", MDL); } option_code_hash_lookup(&option, universe->code_hash, &code, 0, MDL); /* If we created an option structure for each option a client * supplied, it's possible we may create > 2^32 option structures. * That's not feasible. So by failing to enter these option * structures into the code and name hash tables, references will * never be more than 1 - when the option cache is destroyed, this * will be cleaned up. */ if (!option) { char nbuf[sizeof("unknown-4294967295")]; sprintf(nbuf, "unknown-%u", code); option = new_option(nbuf, MDL); if (!option) return 0; option->format = default_option_format; option->universe = universe; option->code = code; /* new_option() doesn't set references, pretend. */ option->refcnt = 1; } if (!option_cache_allocate (opp, MDL)) { log_error("No memory for option code %s.%s.", universe->name, option->name); status = 0; goto cleanup; } /* Pointer rather than double pointer makes for less parens. */ op = *opp; option_reference(&op->option, option, MDL); /* If we weren't passed a buffer in which the data are saved and refcounted, allocate one now. */ if (!bp) { if (!buffer_allocate (&lbp, length + terminatep, MDL)) { log_error ("no memory for option buffer."); status = 0; goto cleanup; } memcpy (lbp -> data, buffer, length + terminatep); bp = lbp; buffer = &bp -> data [0]; /* Refer to saved buffer. */ } /* Reference buffer copy to option cache. */ op -> data.buffer = (struct buffer *)0; buffer_reference (&op -> data.buffer, bp, MDL); /* Point option cache into buffer. */ op -> data.data = buffer; op -> data.len = length; if (terminatep) { /* NUL terminate (we can get away with this because we (or the caller!) allocated one more than the buffer size, and because the byte following the end of an option is always the code of the next option, which the caller is getting out of the *original* buffer. */ buffer [length] = 0; op -> data.terminated = 1; } else op -> data.terminated = 0; /* If this option is ultimately a text option, null determinate to * comply with RFC2132 section 2. Mark a flag so this can be sensed * later to echo NULLs back to clients that supplied them (they * probably expect them). */ if (format_has_text(option->format)) { int min_len = format_min_length(option->format, op); while ((op->data.len > min_len) && (op->data.data[op->data.len-1] == '\0')) { op->data.len--; op->flags |= OPTION_HAD_NULLS; } } /* And let go of our references. */ cleanup: option_dereference(&option, MDL); return status; } static void count_options(struct option_cache *dummy_oc, struct packet *dummy_packet, struct lease *dummy_lease, struct client_state *dummy_client_state, struct option_state *dummy_opt_state, struct option_state *opt_state, struct binding_scope **dummy_binding_scope, struct universe *dummy_universe, void *void_accumulator) { int *accumulator = (int *)void_accumulator; *accumulator += 1; } static void collect_oro(struct option_cache *oc, struct packet *dummy_packet, struct lease *dummy_lease, struct client_state *dummy_client_state, struct option_state *dummy_opt_state, struct option_state *opt_state, struct binding_scope **dummy_binding_scope, struct universe *dummy_universe, void *void_oro) { struct data_string *oro = (struct data_string *)void_oro; putUShort(oro->buffer->data + oro->len, oc->option->code); oro->len += 2; } /* build_server_oro() is presently unusued, but may be used at a future date * with support for Reconfigure messages (as a hint to the client about new * option value contents). */ void build_server_oro(struct data_string *server_oro, struct option_state *options, const char *file, int line) { int num_opts; int i; struct option *o; /* * Count the number of options, so we can allocate enough memory. * We want to mention sub-options too, so check all universes. */ num_opts = 0; option_space_foreach(NULL, NULL, NULL, NULL, options, NULL, &dhcpv6_universe, (void *)&num_opts, count_options); for (i=0; i < options->universe_count; i++) { if (options->universes[i] != NULL) { o = universes[i]->enc_opt; while (o != NULL) { if (o->universe == &dhcpv6_universe) { num_opts++; break; } o = o->universe->enc_opt; } } } /* * Allocate space. */ memset(server_oro, 0, sizeof(*server_oro)); if (!buffer_allocate(&server_oro->buffer, num_opts * 2, MDL)) { log_fatal("no memory to build server ORO"); } server_oro->data = server_oro->buffer->data; /* * Copy the data in. * We want to mention sub-options too, so check all universes. */ server_oro->len = 0; /* gets set in collect_oro */ option_space_foreach(NULL, NULL, NULL, NULL, options, NULL, &dhcpv6_universe, (void *)server_oro, collect_oro); for (i=0; i < options->universe_count; i++) { if (options->universes[i] != NULL) { o = universes[i]->enc_opt; while (o != NULL) { if (o->universe == &dhcpv6_universe) { unsigned char *tmp; tmp = server_oro->buffer->data; putUShort(tmp + server_oro->len, o->code); server_oro->len += 2; break; } o = o->universe->enc_opt; } } } } /* Wrapper function to put an option cache into an option state. */ void save_option(struct universe *universe, struct option_state *options, struct option_cache *oc) { if (universe->save_func) (*universe->save_func)(universe, options, oc, ISC_FALSE); else log_error("can't store options in %s space.", universe->name); } /* Wrapper function to append an option cache into an option state's list. */ void also_save_option(struct universe *universe, struct option_state *options, struct option_cache *oc) { if (universe->save_func) (*universe->save_func)(universe, options, oc, ISC_TRUE); else log_error("can't store options in %s space.", universe->name); } void save_hashed_option(struct universe *universe, struct option_state *options, struct option_cache *oc, isc_boolean_t appendp) { int hashix; pair bptr; pair *hash = options -> universes [universe -> index]; struct option_cache **ocloc; if (oc -> refcnt == 0) abort (); /* Compute the hash. */ hashix = compute_option_hash (oc -> option -> code); /* If there's no hash table, make one. */ if (!hash) { hash = (pair *)dmalloc (OPTION_HASH_SIZE * sizeof *hash, MDL); if (!hash) { log_error ("no memory to store %s.%s", universe -> name, oc -> option -> name); return; } memset (hash, 0, OPTION_HASH_SIZE * sizeof *hash); options -> universes [universe -> index] = (void *)hash; } else { /* Try to find an existing option matching the new one. */ for (bptr = hash [hashix]; bptr; bptr = bptr -> cdr) { if (((struct option_cache *) (bptr -> car)) -> option -> code == oc -> option -> code) break; } /* Deal with collisions on the hash list. */ if (bptr) { ocloc = (struct option_cache **)&bptr->car; /* * If appendp is set, append it onto the tail of the * ->next list. If it is not set, rotate it into * position at the head of the list. */ if (appendp) { do { ocloc = &(*ocloc)->next; } while (*ocloc != NULL); } else { option_cache_dereference(ocloc, MDL); } option_cache_reference(ocloc, oc, MDL); return; } } /* Otherwise, just put the new one at the head of the list. */ bptr = new_pair (MDL); if (!bptr) { log_error ("No memory for option_cache reference."); return; } bptr -> cdr = hash [hashix]; bptr -> car = 0; option_cache_reference ((struct option_cache **)&bptr -> car, oc, MDL); hash [hashix] = bptr; } void delete_option (universe, options, code) struct universe *universe; struct option_state *options; int code; { if (universe -> delete_func) (*universe -> delete_func) (universe, options, code); else log_error ("can't delete options from %s space.", universe -> name); } void delete_hashed_option (universe, options, code) struct universe *universe; struct option_state *options; int code; { int hashix; pair bptr, prev = (pair)0; pair *hash = options -> universes [universe -> index]; /* There may not be any options in this space. */ if (!hash) return; /* Try to find an existing option matching the new one. */ hashix = compute_option_hash (code); for (bptr = hash [hashix]; bptr; bptr = bptr -> cdr) { if (((struct option_cache *)(bptr -> car)) -> option -> code == code) break; prev = bptr; } /* If we found one, wipe it out... */ if (bptr) { if (prev) prev -> cdr = bptr -> cdr; else hash [hashix] = bptr -> cdr; option_cache_dereference ((struct option_cache **)(&bptr -> car), MDL); free_pair (bptr, MDL); } } extern struct option_cache *free_option_caches; /* XXX */ int option_cache_dereference (ptr, file, line) struct option_cache **ptr; const char *file; int line; { if (!ptr || !*ptr) { log_error ("Null pointer in option_cache_dereference: %s(%d)", file, line); #if defined (POINTER_DEBUG) abort (); #else return 0; #endif } (*ptr) -> refcnt--; rc_register (file, line, ptr, *ptr, (*ptr) -> refcnt, 1, RC_MISC); if (!(*ptr) -> refcnt) { if ((*ptr) -> data.buffer) data_string_forget (&(*ptr) -> data, file, line); if ((*ptr)->option) option_dereference(&(*ptr)->option, MDL); if ((*ptr) -> expression) expression_dereference (&(*ptr) -> expression, file, line); if ((*ptr) -> next) option_cache_dereference (&((*ptr) -> next), file, line); /* Put it back on the free list... */ (*ptr) -> expression = (struct expression *)free_option_caches; free_option_caches = *ptr; dmalloc_reuse (free_option_caches, (char *)0, 0, 0); } if ((*ptr) -> refcnt < 0) { log_error ("%s(%d): negative refcnt!", file, line); #if defined (DEBUG_RC_HISTORY) dump_rc_history (*ptr); #endif #if defined (POINTER_DEBUG) abort (); #else *ptr = (struct option_cache *)0; return 0; #endif } *ptr = (struct option_cache *)0; return 1; } int hashed_option_state_dereference (universe, state, file, line) struct universe *universe; struct option_state *state; const char *file; int line; { pair *heads; pair cp, next; int i; /* Get the pointer to the array of hash table bucket heads. */ heads = (pair *)(state -> universes [universe -> index]); if (!heads) return 0; /* For each non-null head, loop through all the buckets dereferencing the attached option cache structures and freeing the buckets. */ for (i = 0; i < OPTION_HASH_SIZE; i++) { for (cp = heads [i]; cp; cp = next) { next = cp -> cdr; option_cache_dereference ((struct option_cache **)&cp -> car, file, line); free_pair (cp, file, line); } } dfree (heads, file, line); state -> universes [universe -> index] = (void *)0; return 1; } /* The 'data_string' primitive doesn't have an appension mechanism. * This function must then append a new option onto an existing buffer * by first duplicating the original buffer and appending the desired * values, followed by coping the new value into place. */ int append_option(struct data_string *dst, struct universe *universe, struct option *option, struct data_string *src) { struct data_string tmp; if (src->len == 0 && option->format[0] != 'Z') return 0; memset(&tmp, 0, sizeof(tmp)); /* Allocate a buffer to hold existing data, the current option's * tag and length, and the option's content. */ if (!buffer_allocate(&tmp.buffer, (dst->len + universe->length_size + universe->tag_size + src->len), MDL)) { /* XXX: This kills all options presently stored in the * destination buffer. This is the way the original code * worked, and assumes an 'all or nothing' approach to * eg encapsulated option spaces. It may or may not be * desirable. */ data_string_forget(dst, MDL); return 0; } tmp.data = tmp.buffer->data; /* Copy the existing data off the destination. */ if (dst->len != 0) memcpy(tmp.buffer->data, dst->data, dst->len); tmp.len = dst->len; /* Place the new option tag and length. */ (*universe->store_tag)(tmp.buffer->data + tmp.len, option->code); tmp.len += universe->tag_size; (*universe->store_length)(tmp.buffer->data + tmp.len, src->len); tmp.len += universe->length_size; /* Copy the option contents onto the end. */ memcpy(tmp.buffer->data + tmp.len, src->data, src->len); tmp.len += src->len; /* Play the shell game. */ data_string_forget(dst, MDL); data_string_copy(dst, &tmp, MDL); data_string_forget(&tmp, MDL); return 1; } int store_option(struct data_string *result, struct universe *universe, struct packet *packet, struct lease *lease, struct client_state *client_state, struct option_state *in_options, struct option_state *cfg_options, struct binding_scope **scope, struct option_cache *oc) { struct data_string tmp; struct universe *subu=NULL; int status; char *start, *end; memset(&tmp, 0, sizeof(tmp)); if (evaluate_option_cache(&tmp, packet, lease, client_state, in_options, cfg_options, scope, oc, MDL)) { /* If the option is an extended 'e'ncapsulation (not a * direct 'E'ncapsulation), append the encapsulated space * onto the currently prepared value. */ do { if (oc->option->format && oc->option->format[0] == 'e') { /* Skip forward to the universe name. */ start = strchr(oc->option->format, 'E'); if (start == NULL) break; /* Locate the name-terminating '.'. */ end = strchr(++start, '.'); /* A zero-length name is not allowed in * these kinds of encapsulations. */ if (end == NULL || start == end) break; universe_hash_lookup(&subu, universe_hash, start, end - start, MDL); if (subu == NULL) { log_error("store_option: option %d " "refers to unknown " "option space '%.*s'.", oc->option->code, (int)(end - start), start); break; } /* Append encapsulations, if any. We * already have the prepended values, so * we send those even if there are no * encapsulated options (and ->encapsulate() * returns zero). */ subu->encapsulate(&tmp, packet, lease, client_state, in_options, cfg_options, scope, subu); subu = NULL; } } while (ISC_FALSE); status = append_option(result, universe, oc->option, &tmp); data_string_forget(&tmp, MDL); return status; } return 0; } int option_space_encapsulate (result, packet, lease, client_state, in_options, cfg_options, scope, name) struct data_string *result; struct packet *packet; struct lease *lease; struct client_state *client_state; struct option_state *in_options; struct option_state *cfg_options; struct binding_scope **scope; struct data_string *name; { struct universe *u = NULL; int status = 0; universe_hash_lookup(&u, universe_hash, (const char *)name->data, name->len, MDL); if (u == NULL) { log_error("option_space_encapsulate: option space '%.*s' does " "not exist, but is configured.", (int)name->len, name->data); return status; } if (u->encapsulate != NULL) { if (u->encapsulate(result, packet, lease, client_state, in_options, cfg_options, scope, u)) status = 1; } else log_error("encapsulation requested for '%s' with no support.", name->data); return status; } /* Attempt to store any 'E'ncapsulated options that have not yet been * placed on the option buffer by the above (configuring a value in * the space over-rides any values in the child universe). * * Note that there are far fewer universes than there will ever be * options in any universe. So it is faster to traverse the * configured universes, checking if each is encapsulated in the * current universe, and if so attempting to do so. * * For each configured universe for this configuration option space, * which is encapsulated within the current universe, can not be found * by the lookup function (the universe-specific encapsulation * functions would already have stored such a value), and encapsulates * at least one option, append it. */ static int search_subencapsulation(struct data_string *result, struct packet *packet, struct lease *lease, struct client_state *client_state, struct option_state *in_options, struct option_state *cfg_options, struct binding_scope **scope, struct universe *universe) { struct data_string sub; struct universe *subu; int i, status = 0; memset(&sub, 0, sizeof(sub)); for (i = 0 ; i < cfg_options->universe_count ; i++) { subu = universes[i]; if (subu == NULL) log_fatal("Impossible condition at %s:%d.", MDL); if (subu->enc_opt != NULL && subu->enc_opt->universe == universe && subu->enc_opt->format != NULL && subu->enc_opt->format[0] == 'E' && lookup_option(universe, cfg_options, subu->enc_opt->code) == NULL && subu->encapsulate(&sub, packet, lease, client_state, in_options, cfg_options, scope, subu)) { if (append_option(result, universe, subu->enc_opt, &sub)) status = 1; data_string_forget(&sub, MDL); } } return status; } int hashed_option_space_encapsulate (result, packet, lease, client_state, in_options, cfg_options, scope, universe) struct data_string *result; struct packet *packet; struct lease *lease; struct client_state *client_state; struct option_state *in_options; struct option_state *cfg_options; struct binding_scope **scope; struct universe *universe; { pair p, *hash; int status; int i; if (universe -> index >= cfg_options -> universe_count) return 0; hash = cfg_options -> universes [universe -> index]; if (!hash) return 0; /* For each hash bucket, and each configured option cache within * that bucket, append the option onto the buffer in encapsulated * format appropriate to the universe. */ status = 0; for (i = 0; i < OPTION_HASH_SIZE; i++) { for (p = hash [i]; p; p = p -> cdr) { if (store_option(result, universe, packet, lease, client_state, in_options, cfg_options, scope, (struct option_cache *)p->car)) status = 1; } } if (search_subencapsulation(result, packet, lease, client_state, in_options, cfg_options, scope, universe)) status = 1; return status; } int nwip_option_space_encapsulate (result, packet, lease, client_state, in_options, cfg_options, scope, universe) struct data_string *result; struct packet *packet; struct lease *lease; struct client_state *client_state; struct option_state *in_options; struct option_state *cfg_options; struct binding_scope **scope; struct universe *universe; { pair ocp; int status; static struct option_cache *no_nwip; struct data_string ds; struct option_chain_head *head; if (universe -> index >= cfg_options -> universe_count) return 0; head = ((struct option_chain_head *) cfg_options -> universes [nwip_universe.index]); if (!head) return 0; status = 0; for (ocp = head -> first; ocp; ocp = ocp -> cdr) { if (store_option (result, universe, packet, lease, client_state, in_options, cfg_options, scope, (struct option_cache *)ocp -> car)) status = 1; } /* If there's no data, the nwip suboption is supposed to contain a suboption saying there's no data. */ if (!status) { if (!no_nwip) { unsigned one = 1; static unsigned char nni [] = { 1, 0 }; memset (&ds, 0, sizeof ds); ds.data = nni; ds.len = 2; if (option_cache_allocate (&no_nwip, MDL)) data_string_copy (&no_nwip -> data, &ds, MDL); if (!option_code_hash_lookup(&no_nwip->option, nwip_universe.code_hash, &one, 0, MDL)) log_fatal("Nwip option hash does not contain " "1 (%s:%d).", MDL); } if (no_nwip) { if (store_option (result, universe, packet, lease, client_state, in_options, cfg_options, scope, no_nwip)) status = 1; } } else { memset (&ds, 0, sizeof ds); /* If we have nwip options, the first one has to be the nwip-exists-in-option-area option. */ if (!buffer_allocate (&ds.buffer, result -> len + 2, MDL)) { data_string_forget (result, MDL); return 0; } ds.data = &ds.buffer -> data [0]; ds.buffer -> data [0] = 2; ds.buffer -> data [1] = 0; memcpy (&ds.buffer -> data [2], result -> data, result -> len); data_string_forget (result, MDL); data_string_copy (result, &ds, MDL); data_string_forget (&ds, MDL); } return status; } /* We don't want to use ns_name_pton()...it doesn't tell us how many bytes * it has consumed, and it plays havoc with our escapes. * * So this function does DNS encoding, and returns either the number of * octects consumed (on success), or -1 on failure. */ static int fqdn_encode(unsigned char *dst, int dstlen, const unsigned char *src, int srclen) { unsigned char *out; int i, j, len, outlen=0; out = dst; for (i = 0, j = 0 ; i < srclen ; i = j) { while ((j < srclen) && (src[j] != '.') && (src[j] != '\0')) j++; len = j - i; if ((outlen + 1 + len) > dstlen) return -1; *out++ = len; outlen++; /* We only do one FQDN, ending in one root label. */ if (len == 0) return outlen; memcpy(out, src + i, len); out += len; outlen += len; /* Advance past the root label. */ j++; } if ((outlen + 1) > dstlen) return -1; /* Place the root label. */ *out++ = 0; outlen++; return outlen; } int fqdn_option_space_encapsulate (result, packet, lease, client_state, in_options, cfg_options, scope, universe) struct data_string *result; struct packet *packet; struct lease *lease; struct client_state *client_state; struct option_state *in_options; struct option_state *cfg_options; struct binding_scope **scope; struct universe *universe; { pair ocp; struct data_string results [FQDN_SUBOPTION_COUNT + 1]; int status = 1; int i; unsigned len; struct buffer *bp = (struct buffer *)0; struct option_chain_head *head; /* If there's no FQDN universe, don't encapsulate. */ if (fqdn_universe.index >= cfg_options -> universe_count) return 0; head = ((struct option_chain_head *) cfg_options -> universes [fqdn_universe.index]); if (!head) return 0; /* Figure out the values of all the suboptions. */ memset (results, 0, sizeof results); for (ocp = head -> first; ocp; ocp = ocp -> cdr) { struct option_cache *oc = (struct option_cache *)(ocp -> car); if (oc -> option -> code > FQDN_SUBOPTION_COUNT) continue; evaluate_option_cache (&results [oc -> option -> code], packet, lease, client_state, in_options, cfg_options, scope, oc, MDL); } /* We add a byte for the flags field. * We add two bytes for the two RCODE fields. * We add a byte because we will prepend a label count. * We add a byte because the input len doesn't count null termination, * and we will add a root label. */ len = 5 + results [FQDN_FQDN].len; /* Save the contents of the option in a buffer. */ if (!buffer_allocate (&bp, len, MDL)) { log_error ("no memory for option buffer."); status = 0; goto exit; } buffer_reference (&result -> buffer, bp, MDL); result -> len = 3; result -> data = &bp -> data [0]; memset (&bp -> data [0], 0, len); /* XXX: The server should set bit 4 (yes, 4, not 3) to 1 if it is * not going to perform any ddns updates. The client should set the * bit if it doesn't want the server to perform any updates. * The problem is at this layer of abstraction we have no idea if * the caller is a client or server. * * See RFC4702, Section 3.1, 'The "N" bit'. * * if (?) * bp->data[0] |= 8; */ if (results [FQDN_NO_CLIENT_UPDATE].len && results [FQDN_NO_CLIENT_UPDATE].data [0]) bp -> data [0] |= 2; if (results [FQDN_SERVER_UPDATE].len && results [FQDN_SERVER_UPDATE].data [0]) bp -> data [0] |= 1; if (results [FQDN_RCODE1].len) bp -> data [1] = results [FQDN_RCODE1].data [0]; if (results [FQDN_RCODE2].len) bp -> data [2] = results [FQDN_RCODE2].data [0]; if (results [FQDN_ENCODED].len && results [FQDN_ENCODED].data [0]) { bp->data[0] |= 4; if (results [FQDN_FQDN].len) { i = fqdn_encode(&bp->data[3], len - 3, results[FQDN_FQDN].data, results[FQDN_FQDN].len); if (i < 0) { status = 0; goto exit; } result->len += i; result->terminated = 0; } } else { if (results [FQDN_FQDN].len) { memcpy (&bp -> data [3], results [FQDN_FQDN].data, results [FQDN_FQDN].len); result -> len += results [FQDN_FQDN].len; result -> terminated = 0; } } exit: for (i = 1; i <= FQDN_SUBOPTION_COUNT; i++) { if (results [i].len) data_string_forget (&results [i], MDL); } buffer_dereference (&bp, MDL); if (!status) data_string_forget(result, MDL); return status; } /* * Trap invalid attempts to inspect FQND6 contents. */ struct option_cache * lookup_fqdn6_option(struct universe *universe, struct option_state *options, unsigned code) { log_fatal("Impossible condition at %s:%d.", MDL); return NULL; } /* * Trap invalid attempts to save options directly to FQDN6 rather than FQDN. */ void save_fqdn6_option(struct universe *universe, struct option_state *options, struct option_cache *oc, isc_boolean_t appendp) { log_fatal("Impossible condition at %s:%d.", MDL); } /* * Trap invalid attempts to delete an option out of the FQDN6 universe. */ void delete_fqdn6_option(struct universe *universe, struct option_state *options, int code) { log_fatal("Impossible condition at %s:%d.", MDL); } /* Shill to the DHCPv4 fqdn option cache any attempts to traverse the * V6's option cache entry. * * This function is called speculatively by dhclient to setup * environment variables. But it would have already called the * foreach on the normal fqdn universe, so this is superfluous. */ void fqdn6_option_space_foreach(struct packet *packet, struct lease *lease, struct client_state *client_state, struct option_state *in_options, struct option_state *cfg_options, struct binding_scope **scope, struct universe *u, void *stuff, void (*func)(struct option_cache *, struct packet *, struct lease *, struct client_state *, struct option_state *, struct option_state *, struct binding_scope **, struct universe *, void *)) { /* Pretend it is empty. */ return; } /* Turn the FQDN option space into a DHCPv6 FQDN option buffer. */ int fqdn6_option_space_encapsulate(struct data_string *result, struct packet *packet, struct lease *lease, struct client_state *client_state, struct option_state *in_options, struct option_state *cfg_options, struct binding_scope **scope, struct universe *universe) { pair ocp; struct option_chain_head *head; struct option_cache *oc; unsigned char *data; int i, len, rval = 0, count; struct data_string results[FQDN_SUBOPTION_COUNT + 1]; if (fqdn_universe.index >= cfg_options->universe_count) return 0; head = ((struct option_chain_head *) cfg_options->universes[fqdn_universe.index]); if (head == NULL) return 0; memset(results, 0, sizeof(results)); for (ocp = head->first ; ocp != NULL ; ocp = ocp->cdr) { oc = (struct option_cache *)(ocp->car); if (oc->option->code > FQDN_SUBOPTION_COUNT) log_fatal("Impossible condition at %s:%d.", MDL); evaluate_option_cache(&results[oc->option->code], packet, lease, client_state, in_options, cfg_options, scope, oc, MDL); } /* We add a byte for the flags field at the start of the option. * We add a byte because we will prepend a label count. * We add a byte because the input length doesn't include a trailing * NULL, and we will add a root label. */ len = results[FQDN_FQDN].len + 3; if (!buffer_allocate(&result->buffer, len, MDL)) { log_error("No memory for virtual option buffer."); goto exit; } data = result->buffer->data; result->data = data; /* The first byte is the flags field. */ result->len = 1; data[0] = 0; /* XXX: The server should set bit 3 (yes, 3, not 4) to 1 if we * are not going to perform any DNS updates. The problem is * that at this layer of abstraction, we do not know if the caller * is the client or the server. * * See RFC4704 Section 4.1, 'The "N" bit'. * * if (?) * data[0] |= 4; */ if (results[FQDN_NO_CLIENT_UPDATE].len && results[FQDN_NO_CLIENT_UPDATE].data[0]) data[0] |= 2; if (results[FQDN_SERVER_UPDATE].len && results[FQDN_SERVER_UPDATE].data[0]) data[0] |= 1; /* If there is no name, we're done. */ if (results[FQDN_FQDN].len == 0) { rval = 1; goto exit; } /* Convert textual representation to DNS format. */ count = fqdn_encode(data + 1, len - 1, results[FQDN_FQDN].data, results[FQDN_FQDN].len); if (count < 0) { rval = 0; data_string_forget(result, MDL); goto exit; } result->len += count; result->terminated = 0; /* Success! */ rval = 1; exit: for (i = 1 ; i <= FQDN_SUBOPTION_COUNT ; i++) { if (result[i].len) data_string_forget(&results[i], MDL); } return rval; } /* Read the DHCPv6 FQDN option's contents into the FQDN virtual space. */ int fqdn6_universe_decode(struct option_state *options, const unsigned char *buffer, unsigned length, struct universe *u) { struct buffer *bp = NULL; unsigned char *first_dot; int len, hlen, dlen; /* The FQDN option has to be at least 1 byte long. */ if (length < 1) return 0; /* Save the contents of the option in a buffer. There are 3 * one-byte values we record from the packet, so we go ahead * and allocate a bigger buffer to accommodate them. But the * 'length' we got (because it is a DNS encoded string) is * one longer than we need...so we only add two extra octets. */ if (!buffer_allocate(&bp, length + 2, MDL)) { log_error("No memory for dhcp6.fqdn option buffer."); return 0; } /* The v6 FQDN is always 'encoded' per DNS. */ bp->data[0] = 1; if (!save_option_buffer(&fqdn_universe, options, bp, bp->data, 1, FQDN_ENCODED, 0)) goto error; /* XXX: We need to process 'The "N" bit'. */ if (buffer[0] & 1) /* server-update. */ bp->data[2] = 1; else bp->data[2] = 0; if (!save_option_buffer(&fqdn_universe, options, bp, bp->data + 2, 1, FQDN_SERVER_UPDATE, 0)) goto error; if (buffer[0] & 2) /* no-client-update. */ bp->data[1] = 1; else bp->data[1] = 0; if (!save_option_buffer(&fqdn_universe, options, bp, bp->data + 1, 1, FQDN_NO_CLIENT_UPDATE, 0)) goto error; /* Convert the domain name to textual representation for config. */ len = MRns_name_ntop(buffer + 1, (char *)bp->data + 3, length - 1); if (len == -1) { log_error("Unable to convert dhcp6.fqdn domain name to " "printable form."); goto error; } /* Save the domain name. */ if (len > 0) { unsigned char *fqdn_start = bp->data + 3; if (!save_option_buffer(&fqdn_universe, options, bp, fqdn_start, len, FQDN_FQDN, 1)) goto error; first_dot = (unsigned char *)strchr((char *)fqdn_start, '.'); if (first_dot != NULL) { hlen = first_dot - fqdn_start; dlen = len - hlen; } else { hlen = len; dlen = 0; } if (!save_option_buffer(&fqdn_universe, options, bp, fqdn_start, len, FQDN_FQDN, 1) || ((hlen > 0) && !save_option_buffer(&fqdn_universe, options, bp, fqdn_start, hlen, FQDN_HOSTNAME, 0)) || ((dlen > 0) && !save_option_buffer(&fqdn_universe, options, bp, first_dot, dlen, FQDN_DOMAINNAME, 0))) goto error; } buffer_dereference(&bp, MDL); return 1; error: buffer_dereference(&bp, MDL); return 0; } void option_space_foreach (struct packet *packet, struct lease *lease, struct client_state *client_state, struct option_state *in_options, struct option_state *cfg_options, struct binding_scope **scope, struct universe *u, void *stuff, void (*func) (struct option_cache *, struct packet *, struct lease *, struct client_state *, struct option_state *, struct option_state *, struct binding_scope **, struct universe *, void *)) { if (u -> foreach) (*u -> foreach) (packet, lease, client_state, in_options, cfg_options, scope, u, stuff, func); } void suboption_foreach (struct packet *packet, struct lease *lease, struct client_state *client_state, struct option_state *in_options, struct option_state *cfg_options, struct binding_scope **scope, struct universe *u, void *stuff, void (*func) (struct option_cache *, struct packet *, struct lease *, struct client_state *, struct option_state *, struct option_state *, struct binding_scope **, struct universe *, void *), struct option_cache *oc, const char *vsname) { struct universe *universe = find_option_universe (oc -> option, vsname); if (universe -> foreach) (*universe -> foreach) (packet, lease, client_state, in_options, cfg_options, scope, universe, stuff, func); } void hashed_option_space_foreach (struct packet *packet, struct lease *lease, struct client_state *client_state, struct option_state *in_options, struct option_state *cfg_options, struct binding_scope **scope, struct universe *u, void *stuff, void (*func) (struct option_cache *, struct packet *, struct lease *, struct client_state *, struct option_state *, struct option_state *, struct binding_scope **, struct universe *, void *)) { pair *hash; int i; struct option_cache *oc; if (cfg_options -> universe_count <= u -> index) return; hash = cfg_options -> universes [u -> index]; if (!hash) return; for (i = 0; i < OPTION_HASH_SIZE; i++) { pair p; /* XXX save _all_ options! XXX */ for (p = hash [i]; p; p = p -> cdr) { oc = (struct option_cache *)p -> car; (*func) (oc, packet, lease, client_state, in_options, cfg_options, scope, u, stuff); } } } void save_linked_option(struct universe *universe, struct option_state *options, struct option_cache *oc, isc_boolean_t appendp) { pair *tail; struct option_chain_head *head; struct option_cache **ocloc; if (universe -> index >= options -> universe_count) return; head = ((struct option_chain_head *) options -> universes [universe -> index]); if (!head) { if (!option_chain_head_allocate (((struct option_chain_head **) &options -> universes [universe -> index]), MDL)) return; head = ((struct option_chain_head *) options -> universes [universe -> index]); } /* Find the tail of the list. */ for (tail = &head -> first; *tail; tail = &((*tail) -> cdr)) { ocloc = (struct option_cache **)&(*tail)->car; if (oc->option->code == (*ocloc)->option->code) { if (appendp) { do { ocloc = &(*ocloc)->next; } while (*ocloc != NULL); } else { option_cache_dereference(ocloc, MDL); } option_cache_reference(ocloc, oc, MDL); return; } } *tail = cons (0, 0); if (*tail) { option_cache_reference ((struct option_cache **) (&(*tail) -> car), oc, MDL); } } int linked_option_space_encapsulate (result, packet, lease, client_state, in_options, cfg_options, scope, universe) struct data_string *result; struct packet *packet; struct lease *lease; struct client_state *client_state; struct option_state *in_options; struct option_state *cfg_options; struct binding_scope **scope; struct universe *universe; { int status = 0; pair oc; struct option_chain_head *head; if (universe -> index >= cfg_options -> universe_count) return status; head = ((struct option_chain_head *) cfg_options -> universes [universe -> index]); if (!head) return status; for (oc = head -> first; oc; oc = oc -> cdr) { if (store_option (result, universe, packet, lease, client_state, in_options, cfg_options, scope, (struct option_cache *)(oc -> car))) status = 1; } if (search_subencapsulation(result, packet, lease, client_state, in_options, cfg_options, scope, universe)) status = 1; return status; } void delete_linked_option (universe, options, code) struct universe *universe; struct option_state *options; int code; { pair *tail, tmp = (pair)0; struct option_chain_head *head; if (universe -> index >= options -> universe_count) return; head = ((struct option_chain_head *) options -> universes [universe -> index]); if (!head) return; for (tail = &head -> first; *tail; tail = &((*tail) -> cdr)) { if (code == ((struct option_cache *)(*tail) -> car) -> option -> code) { tmp = (*tail) -> cdr; option_cache_dereference ((struct option_cache **) (&(*tail) -> car), MDL); dfree (*tail, MDL); (*tail) = tmp; break; } } } struct option_cache *lookup_linked_option (universe, options, code) struct universe *universe; struct option_state *options; unsigned code; { pair oc; struct option_chain_head *head; if (universe -> index >= options -> universe_count) return 0; head = ((struct option_chain_head *) options -> universes [universe -> index]); if (!head) return 0; for (oc = head -> first; oc; oc = oc -> cdr) { if (code == ((struct option_cache *)(oc -> car)) -> option -> code) { return (struct option_cache *)(oc -> car); } } return (struct option_cache *)0; } int linked_option_state_dereference (universe, state, file, line) struct universe *universe; struct option_state *state; const char *file; int line; { return (option_chain_head_dereference ((struct option_chain_head **) (&state -> universes [universe -> index]), MDL)); } void linked_option_space_foreach (struct packet *packet, struct lease *lease, struct client_state *client_state, struct option_state *in_options, struct option_state *cfg_options, struct binding_scope **scope, struct universe *u, void *stuff, void (*func) (struct option_cache *, struct packet *, struct lease *, struct client_state *, struct option_state *, struct option_state *, struct binding_scope **, struct universe *, void *)) { pair car; struct option_chain_head *head; if (u -> index >= cfg_options -> universe_count) return; head = ((struct option_chain_head *) cfg_options -> universes [u -> index]); if (!head) return; for (car = head -> first; car; car = car -> cdr) { (*func) ((struct option_cache *)(car -> car), packet, lease, client_state, in_options, cfg_options, scope, u, stuff); } } void do_packet (interface, packet, len, from_port, from, hfrom) struct interface_info *interface; struct dhcp_packet *packet; unsigned len; unsigned int from_port; struct iaddr from; struct hardware *hfrom; { struct option_cache *op; struct packet *decoded_packet; #if defined (DEBUG_MEMORY_LEAKAGE) unsigned long previous_outstanding = dmalloc_outstanding; #endif #if defined (TRACING) trace_inpacket_stash (interface, packet, len, from_port, from, hfrom); #endif decoded_packet = (struct packet *)0; if (!packet_allocate (&decoded_packet, MDL)) { log_error ("do_packet: no memory for incoming packet!"); return; } decoded_packet -> raw = packet; decoded_packet -> packet_length = len; decoded_packet -> client_port = from_port; decoded_packet -> client_addr = from; interface_reference (&decoded_packet -> interface, interface, MDL); decoded_packet -> haddr = hfrom; if (packet -> hlen > sizeof packet -> chaddr) { packet_dereference (&decoded_packet, MDL); log_info ("Discarding packet with bogus hlen."); return; } /* If there's an option buffer, try to parse it. */ if (decoded_packet -> packet_length >= DHCP_FIXED_NON_UDP + 4) { if (!parse_options (decoded_packet)) { if (decoded_packet -> options) option_state_dereference (&decoded_packet -> options, MDL); packet_dereference (&decoded_packet, MDL); return; } if (decoded_packet -> options_valid && (op = lookup_option (&dhcp_universe, decoded_packet -> options, DHO_DHCP_MESSAGE_TYPE))) { struct data_string dp; memset (&dp, 0, sizeof dp); evaluate_option_cache (&dp, decoded_packet, (struct lease *)0, (struct client_state *)0, decoded_packet -> options, (struct option_state *)0, (struct binding_scope **)0, op, MDL); if (dp.len > 0) decoded_packet -> packet_type = dp.data [0]; else decoded_packet -> packet_type = 0; data_string_forget (&dp, MDL); } } if (decoded_packet -> packet_type) dhcp (decoded_packet); else bootp (decoded_packet); /* If the caller kept the packet, they'll have upped the refcnt. */ packet_dereference (&decoded_packet, MDL); #if defined (DEBUG_MEMORY_LEAKAGE) log_info ("generation %ld: %ld new, %ld outstanding, %ld long-term", dmalloc_generation, dmalloc_outstanding - previous_outstanding, dmalloc_outstanding, dmalloc_longterm); #endif #if defined (DEBUG_MEMORY_LEAKAGE) dmalloc_dump_outstanding (); #endif #if defined (DEBUG_RC_HISTORY_EXHAUSTIVELY) dump_rc_history (0); #endif } int packet6_len_okay(const char *packet, int len) { if (len < 1) { return 0; } if ((packet[0] == DHCPV6_RELAY_FORW) || (packet[0] == DHCPV6_RELAY_REPL)) { if (len >= offsetof(struct dhcpv6_relay_packet, options)) { return 1; } else { return 0; } } else { if (len >= offsetof(struct dhcpv6_packet, options)) { return 1; } else { return 0; } } } #ifdef DHCPv6 void do_packet6(struct interface_info *interface, const char *packet, int len, int from_port, const struct iaddr *from, isc_boolean_t was_unicast) { unsigned char msg_type; const struct dhcpv6_packet *msg; const struct dhcpv6_relay_packet *relay; struct packet *decoded_packet; if (!packet6_len_okay(packet, len)) { log_info("do_packet6: " "short packet from %s port %d, len %d, dropped", piaddr(*from), from_port, len); return; } decoded_packet = NULL; if (!packet_allocate(&decoded_packet, MDL)) { log_error("do_packet6: no memory for incoming packet."); return; } if (!option_state_allocate(&decoded_packet->options, MDL)) { log_error("do_packet6: no memory for options."); packet_dereference(&decoded_packet, MDL); return; } /* IPv4 information, already set to 0 */ /* decoded_packet->packet_type = 0; */ /* memset(&decoded_packet->haddr, 0, sizeof(decoded_packet->haddr)); */ /* decoded_packet->circuit_id = NULL; */ /* decoded_packet->circuit_id_len = 0; */ /* decoded_packet->remote_id = NULL; */ /* decoded_packet->remote_id_len = 0; */ decoded_packet->raw = (struct dhcp_packet *) packet; decoded_packet->packet_length = (unsigned) len; decoded_packet->client_port = from_port; decoded_packet->client_addr = *from; interface_reference(&decoded_packet->interface, interface, MDL); decoded_packet->unicast = was_unicast; msg_type = packet[0]; if ((msg_type == DHCPV6_RELAY_FORW) || (msg_type == DHCPV6_RELAY_REPL)) { int relaylen = (int)(offsetof(struct dhcpv6_relay_packet, options)); relay = (const struct dhcpv6_relay_packet *)packet; decoded_packet->dhcpv6_msg_type = relay->msg_type; /* relay-specific data */ decoded_packet->dhcpv6_hop_count = relay->hop_count; memcpy(&decoded_packet->dhcpv6_link_address, relay->link_address, sizeof(relay->link_address)); memcpy(&decoded_packet->dhcpv6_peer_address, relay->peer_address, sizeof(relay->peer_address)); if (!parse_option_buffer(decoded_packet->options, relay->options, len - relaylen, &dhcpv6_universe)) { /* no logging here, as parse_option_buffer() logs all cases where it fails */ packet_dereference(&decoded_packet, MDL); return; } } else { int msglen = (int)(offsetof(struct dhcpv6_packet, options)); msg = (const struct dhcpv6_packet *)packet; decoded_packet->dhcpv6_msg_type = msg->msg_type; /* message-specific data */ memcpy(decoded_packet->dhcpv6_transaction_id, msg->transaction_id, sizeof(decoded_packet->dhcpv6_transaction_id)); if (!parse_option_buffer(decoded_packet->options, msg->options, len - msglen, &dhcpv6_universe)) { /* no logging here, as parse_option_buffer() logs all cases where it fails */ packet_dereference(&decoded_packet, MDL); return; } } dhcpv6(decoded_packet); packet_dereference(&decoded_packet, MDL); } #endif /* DHCPv6 */ int pretty_escape(char **dst, char *dend, const unsigned char **src, const unsigned char *send) { int count = 0; /* If there aren't as many bytes left as there are in the source * buffer, don't even bother entering the loop. */ if (dst == NULL || dend == NULL || src == NULL || send == NULL || *dst == NULL || *src == NULL || (*dst >= dend) || (*src > send) || ((send - *src) > (dend - *dst))) return -1; for ( ; *src < send ; (*src)++) { if (!isascii (**src) || !isprint (**src)) { /* Skip trailing NUL. */ if ((*src + 1) != send || **src != '\0') { if (*dst + 4 > dend) return -1; sprintf(*dst, "\\%03o", **src); (*dst) += 4; count += 4; } } else if (**src == '"' || **src == '\'' || **src == '$' || **src == '`' || **src == '\\' || **src == '|' || **src == '&') { if (*dst + 2 > dend) return -1; **dst = '\\'; (*dst)++; **dst = **src; (*dst)++; count += 2; } else { if (*dst + 1 > dend) return -1; **dst = **src; (*dst)++; count++; } } return count; } static int pretty_text(char **dst, char *dend, const unsigned char **src, const unsigned char *send, int emit_quotes) { int count; if (dst == NULL || dend == NULL || src == NULL || send == NULL || *dst == NULL || *src == NULL || ((*dst + (emit_quotes ? 2 : 0)) > dend) || (*src > send)) return -1; if (emit_quotes) { **dst = '"'; (*dst)++; } /* dend-1 leaves 1 byte for the closing quote. */ count = pretty_escape(dst, dend - (emit_quotes ? 1 : 0), src, send); if (count == -1) return -1; if (emit_quotes && (*dst < dend)) { **dst = '"'; (*dst)++; /* Includes quote prior to pretty_escape(); */ count += 2; } return count; } static int pretty_domain(char **dst, char *dend, const unsigned char **src, const unsigned char *send) { const unsigned char *tend; int count = 2; int tsiz, status; if (dst == NULL || dend == NULL || src == NULL || send == NULL || *dst == NULL || *src == NULL || ((*dst + 2) > dend) || (*src >= send)) return -1; **dst = '"'; (*dst)++; do { /* Continue loop until end of src buffer. */ if (*src >= send) break; /* Consume tag size. */ tsiz = **src; (*src)++; /* At root, finis. */ if (tsiz == 0) break; tend = (*src) + tsiz; /* If the tag exceeds the source buffer, it's illegal. * This should also trap compression pointers (which should * not be in these buffers). */ if (tend > send) return -1; /* dend-2 leaves room for a trailing dot and quote. */ status = pretty_escape(dst, dend-2, src, tend); if ((status == -1) || ((*dst + 2) > dend)) return -1; **dst = '.'; (*dst)++; count += status + 1; } while(1); **dst = '"'; (*dst)++; return count; } /* * Add the option identified with the option number and data to the * options state. */ int add_option(struct option_state *options, unsigned int option_num, void *data, unsigned int data_len) { struct option_cache *oc; struct option *option; /* INSIST(options != NULL); */ /* INSIST(data != NULL); */ option = NULL; if (!option_code_hash_lookup(&option, dhcp_universe.code_hash, &option_num, 0, MDL)) { log_error("Attempting to add unknown option %d.", option_num); return 0; } oc = NULL; if (!option_cache_allocate(&oc, MDL)) { log_error("No memory for option cache adding %s (option %d).", option->name, option_num); return 0; } if (!make_const_data(&oc->expression, data, data_len, 0, 0, MDL)) { log_error("No memory for constant data adding %s (option %d).", option->name, option_num); option_cache_dereference(&oc, MDL); return 0; } option_reference(&(oc->option), option, MDL); save_option(&dhcp_universe, options, oc); option_cache_dereference(&oc, MDL); return 1; } dhcp-4.2.4/common/packet.c000644 000765 000024 00000023416 11717270172 015305 0ustar00sarstaff000000 000000 /* packet.c Packet assembly code, originally contributed by Archie Cobbs. */ /* * Copyright (c) 2009,2012 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 2004,2005,2007 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1996-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ * * This code was originally contributed by Archie Cobbs, and is still * very similar to that contribution, although the packet checksum code * has been hacked significantly with the help of quite a few ISC DHCP * users, without whose gracious and thorough help the checksum code would * still be disabled. */ #include "dhcpd.h" #if defined (PACKET_ASSEMBLY) || defined (PACKET_DECODING) #include "includes/netinet/ip.h" #include "includes/netinet/udp.h" #include "includes/netinet/if_ether.h" #endif /* PACKET_ASSEMBLY || PACKET_DECODING */ /* Compute the easy part of the checksum on a range of bytes. */ u_int32_t checksum (buf, nbytes, sum) unsigned char *buf; unsigned nbytes; u_int32_t sum; { unsigned i; #ifdef DEBUG_CHECKSUM log_debug ("checksum (%x %d %x)", buf, nbytes, sum); #endif /* Checksum all the pairs of bytes first... */ for (i = 0; i < (nbytes & ~1U); i += 2) { #ifdef DEBUG_CHECKSUM_VERBOSE log_debug ("sum = %x", sum); #endif sum += (u_int16_t) ntohs(*((u_int16_t *)(buf + i))); /* Add carry. */ if (sum > 0xFFFF) sum -= 0xFFFF; } /* If there's a single byte left over, checksum it, too. Network byte order is big-endian, so the remaining byte is the high byte. */ if (i < nbytes) { #ifdef DEBUG_CHECKSUM_VERBOSE log_debug ("sum = %x", sum); #endif sum += buf [i] << 8; /* Add carry. */ if (sum > 0xFFFF) sum -= 0xFFFF; } return sum; } /* Finish computing the checksum, and then put it into network byte order. */ u_int32_t wrapsum (sum) u_int32_t sum; { #ifdef DEBUG_CHECKSUM log_debug ("wrapsum (%x)", sum); #endif sum = ~sum & 0xFFFF; #ifdef DEBUG_CHECKSUM_VERBOSE log_debug ("sum = %x", sum); #endif #ifdef DEBUG_CHECKSUM log_debug ("wrapsum returns %x", htons (sum)); #endif return htons(sum); } #ifdef PACKET_ASSEMBLY void assemble_hw_header (interface, buf, bufix, to) struct interface_info *interface; unsigned char *buf; unsigned *bufix; struct hardware *to; { switch (interface->hw_address.hbuf[0]) { #if defined(HAVE_TR_SUPPORT) case HTYPE_IEEE802: assemble_tr_header(interface, buf, bufix, to); break; #endif #if defined (DEC_FDDI) case HTYPE_FDDI: assemble_fddi_header(interface, buf, bufix, to); break; #endif case HTYPE_INFINIBAND: log_error("Attempt to assemble hw header for infiniband"); break; case HTYPE_ETHER: default: assemble_ethernet_header(interface, buf, bufix, to); break; } } /* UDP header and IP header assembled together for convenience. */ void assemble_udp_ip_header (interface, buf, bufix, from, to, port, data, len) struct interface_info *interface; unsigned char *buf; unsigned *bufix; u_int32_t from; u_int32_t to; u_int32_t port; unsigned char *data; unsigned len; { struct ip ip; struct udphdr udp; memset (&ip, 0, sizeof ip); /* Fill out the IP header */ IP_V_SET (&ip, 4); IP_HL_SET (&ip, 20); ip.ip_tos = IPTOS_LOWDELAY; ip.ip_len = htons(sizeof(ip) + sizeof(udp) + len); ip.ip_id = 0; ip.ip_off = 0; ip.ip_ttl = 128; ip.ip_p = IPPROTO_UDP; ip.ip_sum = 0; ip.ip_src.s_addr = from; ip.ip_dst.s_addr = to; /* Checksum the IP header... */ ip.ip_sum = wrapsum (checksum ((unsigned char *)&ip, sizeof ip, 0)); /* Copy the ip header into the buffer... */ memcpy (&buf [*bufix], &ip, sizeof ip); *bufix += sizeof ip; /* Fill out the UDP header */ udp.uh_sport = local_port; /* XXX */ udp.uh_dport = port; /* XXX */ udp.uh_ulen = htons(sizeof(udp) + len); memset (&udp.uh_sum, 0, sizeof udp.uh_sum); /* Compute UDP checksums, including the ``pseudo-header'', the UDP header and the data. */ udp.uh_sum = wrapsum (checksum ((unsigned char *)&udp, sizeof udp, checksum (data, len, checksum ((unsigned char *) &ip.ip_src, 2 * sizeof ip.ip_src, IPPROTO_UDP + (u_int32_t) ntohs (udp.uh_ulen))))); /* Copy the udp header into the buffer... */ memcpy (&buf [*bufix], &udp, sizeof udp); *bufix += sizeof udp; } #endif /* PACKET_ASSEMBLY */ #ifdef PACKET_DECODING /* Decode a hardware header... */ /* Support for ethernet, TR and FDDI * Doesn't support infiniband yet as the supported oses shouldn't get here */ ssize_t decode_hw_header (interface, buf, bufix, from) struct interface_info *interface; unsigned char *buf; unsigned bufix; struct hardware *from; { switch(interface->hw_address.hbuf[0]) { #if defined (HAVE_TR_SUPPORT) case HTYPE_IEEE802: return (decode_tr_header(interface, buf, bufix, from)); #endif #if defined (DEC_FDDI) case HTYPE_FDDI: return (decode_fddi_header(interface, buf, bufix, from)); #endif case HTYPE_INFINIBAND: log_error("Attempt to decode hw header for infiniband"); return (0); case HTYPE_ETHER: default: return (decode_ethernet_header(interface, buf, bufix, from)); } } /* UDP header and IP header decoded together for convenience. */ ssize_t decode_udp_ip_header(struct interface_info *interface, unsigned char *buf, unsigned bufix, struct sockaddr_in *from, unsigned buflen, unsigned *rbuflen) { unsigned char *data; struct ip ip; struct udphdr udp; unsigned char *upp, *endbuf; u_int32_t ip_len, ulen, pkt_len; u_int32_t sum, usum; static int ip_packets_seen; static int ip_packets_bad_checksum; static int udp_packets_seen; static int udp_packets_bad_checksum; static int udp_packets_length_checked; static int udp_packets_length_overflow; unsigned len; /* Designate the end of the input buffer for bounds checks. */ endbuf = buf + bufix + buflen; /* Assure there is at least an IP header there. */ if ((buf + bufix + sizeof(ip)) > endbuf) return -1; /* Copy the IP header into a stack aligned structure for inspection. * There may be bits in the IP header that we're not decoding, so we * copy out the bits we grok and skip ahead by ip.ip_hl * 4. */ upp = buf + bufix; memcpy(&ip, upp, sizeof(ip)); ip_len = (*upp & 0x0f) << 2; upp += ip_len; /* Check the IP packet length. */ pkt_len = ntohs(ip.ip_len); if (pkt_len > buflen) return -1; /* Assure after ip_len bytes that there is enough room for a UDP header. */ if ((upp + sizeof(udp)) > endbuf) return -1; /* Copy the UDP header into a stack aligned structure for inspection. */ memcpy(&udp, upp, sizeof(udp)); #ifdef USERLAND_FILTER /* Is it a UDP packet? */ if (ip.ip_p != IPPROTO_UDP) return -1; /* Is it to the port we're serving? */ if (udp.uh_dport != local_port) return -1; #endif /* USERLAND_FILTER */ ulen = ntohs(udp.uh_ulen); if (ulen < sizeof(udp)) return -1; udp_packets_length_checked++; if ((upp + ulen) > endbuf) { udp_packets_length_overflow++; if ((udp_packets_length_checked > 4) && ((udp_packets_length_checked / udp_packets_length_overflow) < 2)) { log_info("%d udp packets in %d too long - dropped", udp_packets_length_overflow, udp_packets_length_checked); udp_packets_length_overflow = 0; udp_packets_length_checked = 0; } return -1; } if ((ulen < sizeof(udp)) || ((upp + ulen) > endbuf)) return -1; /* Check the IP header checksum - it should be zero. */ ++ip_packets_seen; if (wrapsum (checksum (buf + bufix, ip_len, 0))) { ++ip_packets_bad_checksum; if (ip_packets_seen > 4 && (ip_packets_seen / ip_packets_bad_checksum) < 2) { log_info ("%d bad IP checksums seen in %d packets", ip_packets_bad_checksum, ip_packets_seen); ip_packets_seen = ip_packets_bad_checksum = 0; } return -1; } /* Copy out the IP source address... */ memcpy(&from->sin_addr, &ip.ip_src, 4); /* Compute UDP checksums, including the ``pseudo-header'', the UDP header and the data. If the UDP checksum field is zero, we're not supposed to do a checksum. */ data = upp + sizeof(udp); len = ulen - sizeof(udp); usum = udp.uh_sum; udp.uh_sum = 0; /* XXX: We have to pass &udp, because we have to zero the checksum * field before calculating the sum...'upp' isn't zeroed. */ sum = wrapsum(checksum((unsigned char *)&udp, sizeof(udp), checksum(data, len, checksum((unsigned char *)&ip.ip_src, 8, IPPROTO_UDP + ulen)))); udp_packets_seen++; if (usum && usum != sum) { udp_packets_bad_checksum++; if (udp_packets_seen > 4 && (udp_packets_seen / udp_packets_bad_checksum) < 2) { log_info ("%d bad udp checksums in %d packets", udp_packets_bad_checksum, udp_packets_seen); udp_packets_seen = udp_packets_bad_checksum = 0; } return -1; } /* Copy out the port... */ memcpy (&from -> sin_port, &udp.uh_sport, sizeof udp.uh_sport); /* Save the length of the UDP payload. */ if (rbuflen != NULL) *rbuflen = len; /* Return the index to the UDP payload. */ return ip_len + sizeof udp; } #endif /* PACKET_DECODING */ dhcp-4.2.4/common/parse.c000644 000765 000024 00000443217 11726364512 015157 0ustar00sarstaff000000 000000 /* parse.c Common parser code for dhcpd and dhclient. */ /* * Copyright (c) 2004-2012 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1995-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ * * This software has been written for Internet Systems Consortium * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. * To learn more about Internet Systems Consortium, see * ``https://www.isc.org/''. To learn more about Vixie Enterprises, * see ``http://www.vix.com''. To learn more about Nominum, Inc., see * ``http://www.nominum.com''. */ #include "dhcpd.h" #include /* Enumerations can be specified in option formats, and are used for parsing, so we define the routines that manage them here. */ struct enumeration *enumerations; void add_enumeration (struct enumeration *enumeration) { enumeration -> next = enumerations; enumerations = enumeration; } struct enumeration *find_enumeration (const char *name, int length) { struct enumeration *e; for (e = enumerations; e; e = e -> next) if (strlen (e -> name) == length && !memcmp (e -> name, name, (unsigned)length)) return e; return (struct enumeration *)0; } struct enumeration_value *find_enumeration_value (const char *name, int length, unsigned *widthp, const char *value) { struct enumeration *e; int i; e = find_enumeration (name, length); if (e) { if (widthp != NULL) *widthp = e->width; for (i = 0; e -> values [i].name; i++) { if (!strcmp (value, e -> values [i].name)) return &e -> values [i]; } } return (struct enumeration_value *)0; } /* Skip to the semicolon ending the current statement. If we encounter braces, the matching closing brace terminates the statement. If we encounter a right brace but haven't encountered a left brace, return leaving the brace in the token buffer for the caller. If we see a semicolon and haven't seen a left brace, return. This lets us skip over: statement; statement foo bar { } statement foo bar { statement { } } statement} ...et cetera. */ void skip_to_semi (cfile) struct parse *cfile; { skip_to_rbrace (cfile, 0); } void skip_to_rbrace (cfile, brace_count) struct parse *cfile; int brace_count; { enum dhcp_token token; const char *val; #if defined (DEBUG_TOKEN) log_error ("skip_to_rbrace: %d\n", brace_count); #endif do { token = peek_token (&val, (unsigned *)0, cfile); if (token == RBRACE) { token = next_token (&val, (unsigned *)0, cfile); if (brace_count) { if (!--brace_count) return; } else return; } else if (token == LBRACE) { brace_count++; } else if (token == SEMI && !brace_count) { token = next_token (&val, (unsigned *)0, cfile); return; } else if (token == EOL) { /* EOL only happens when parsing /etc/resolv.conf, and we treat it like a semicolon because the resolv.conf file is line-oriented. */ token = next_token (&val, (unsigned *)0, cfile); return; } token = next_token (&val, (unsigned *)0, cfile); } while (token != END_OF_FILE); } int parse_semi (cfile) struct parse *cfile; { enum dhcp_token token; const char *val; token = next_token (&val, (unsigned *)0, cfile); if (token != SEMI) { parse_warn (cfile, "semicolon expected."); skip_to_semi (cfile); return 0; } return 1; } /* string-parameter :== STRING SEMI */ int parse_string (cfile, sptr, lptr) struct parse *cfile; char **sptr; unsigned *lptr; { const char *val; enum dhcp_token token; char *s; unsigned len; token = next_token (&val, &len, cfile); if (token != STRING) { parse_warn (cfile, "expecting a string"); skip_to_semi (cfile); return 0; } s = (char *)dmalloc (len + 1, MDL); if (!s) log_fatal ("no memory for string %s.", val); memcpy (s, val, len + 1); if (!parse_semi (cfile)) { dfree (s, MDL); return 0; } if (sptr) *sptr = s; else dfree (s, MDL); if (lptr) *lptr = len; return 1; } /* * hostname :== IDENTIFIER * | IDENTIFIER DOT * | hostname DOT IDENTIFIER */ char *parse_host_name (cfile) struct parse *cfile; { const char *val; enum dhcp_token token; unsigned len = 0; char *s; char *t; pair c = (pair)0; int ltid = 0; /* Read a dotted hostname... */ do { /* Read a token, which should be an identifier. */ token = peek_token (&val, (unsigned *)0, cfile); if (!is_identifier (token) && token != NUMBER) break; token = next_token (&val, (unsigned *)0, cfile); /* Store this identifier... */ if (!(s = (char *)dmalloc (strlen (val) + 1, MDL))) log_fatal ("can't allocate temp space for hostname."); strcpy (s, val); c = cons ((caddr_t)s, c); len += strlen (s) + 1; /* Look for a dot; if it's there, keep going, otherwise we're done. */ token = peek_token (&val, (unsigned *)0, cfile); if (token == DOT) { token = next_token (&val, (unsigned *)0, cfile); ltid = 1; } else ltid = 0; } while (token == DOT); /* Should be at least one token. */ if (!len) return (char *)0; /* Assemble the hostname together into a string. */ if (!(s = (char *)dmalloc (len + ltid, MDL))) log_fatal ("can't allocate space for hostname."); t = s + len + ltid; *--t = 0; if (ltid) *--t = '.'; while (c) { pair cdr = c -> cdr; unsigned l = strlen ((char *)(c -> car)); t -= l; memcpy (t, (char *)(c -> car), l); /* Free up temp space. */ dfree (c -> car, MDL); dfree (c, MDL); c = cdr; if (t != s) *--t = '.'; } return s; } /* ip-addr-or-hostname :== ip-address | hostname ip-address :== NUMBER DOT NUMBER DOT NUMBER DOT NUMBER Parse an ip address or a hostname. If uniform is zero, put in an expr_substring node to limit hostnames that evaluate to more than one IP address. Note that RFC1123 permits hostnames to consist of all digits, making it difficult to quickly disambiguate them from ip addresses. */ int parse_ip_addr_or_hostname (expr, cfile, uniform) struct expression **expr; struct parse *cfile; int uniform; { const char *val; enum dhcp_token token; unsigned char addr [4]; unsigned len = sizeof addr; char *name; struct expression *x = (struct expression *)0; int ipaddr = 0; token = peek_token (&val, (unsigned *)0, cfile); if (token == NUMBER) { /* * a hostname may be numeric, but domain names must * start with a letter, so we can disambiguate by * looking ahead a few tokens. we save the parse * context first, and restore it after we know what * we're dealing with. */ save_parse_state(cfile); (void) next_token(NULL, NULL, cfile); if (next_token(NULL, NULL, cfile) == DOT && next_token(NULL, NULL, cfile) == NUMBER) ipaddr = 1; restore_parse_state(cfile); if (ipaddr && parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8)) return make_const_data (expr, addr, len, 0, 1, MDL); } if (is_identifier (token) || token == NUMBER) { name = parse_host_name (cfile); if (!name) return 0; if (!make_host_lookup (expr, name)) { dfree(name, MDL); return 0; } dfree(name, MDL); if (!uniform) { if (!make_limit (&x, *expr, 4)) return 0; expression_dereference (expr, MDL); *expr = x; } } else { if (token != RBRACE && token != LBRACE) token = next_token (&val, (unsigned *)0, cfile); parse_warn (cfile, "%s (%d): expecting IP address or hostname", val, token); if (token != SEMI) skip_to_semi (cfile); return 0; } return 1; } /* * ip-address :== NUMBER DOT NUMBER DOT NUMBER DOT NUMBER */ int parse_ip_addr (cfile, addr) struct parse *cfile; struct iaddr *addr; { addr -> len = 4; if (parse_numeric_aggregate (cfile, addr -> iabuf, &addr -> len, DOT, 10, 8)) return 1; return 0; } /* * Return true if every character in the string is hexadecimal. */ static int is_hex_string(const char *s) { while (*s != '\0') { if (!isxdigit((int)*s)) { return 0; } s++; } return 1; } /* * ip-address6 :== (complicated set of rules) * * See section 2.2 of RFC 1884 for details. * * We are lazy for this. We pull numbers, names, colons, and dots * together and then throw the resulting string at the inet_pton() * function. */ int parse_ip6_addr(struct parse *cfile, struct iaddr *addr) { enum dhcp_token token; const char *val; int val_len; char v6[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")]; int v6_len; /* * First token is non-raw. This way we eat any whitespace before * our IPv6 address begins, like one would expect. */ token = peek_token(&val, NULL, cfile); /* * Gather symbols. */ v6_len = 0; for (;;) { if ((((token == NAME) || (token == NUMBER_OR_NAME)) && is_hex_string(val)) || (token == NUMBER) || (token == DOT) || (token == COLON)) { next_raw_token(&val, NULL, cfile); val_len = strlen(val); if ((v6_len + val_len) >= sizeof(v6)) { parse_warn(cfile, "Invalid IPv6 address."); skip_to_semi(cfile); return 0; } memcpy(v6+v6_len, val, val_len); v6_len += val_len; } else { break; } token = peek_raw_token(&val, NULL, cfile); } v6[v6_len] = '\0'; /* * Use inet_pton() for actual work. */ if (inet_pton(AF_INET6, v6, addr->iabuf) <= 0) { parse_warn(cfile, "Invalid IPv6 address."); skip_to_semi(cfile); return 0; } addr->len = 16; return 1; } /* * Same as parse_ip6_addr() above, but returns the value in the * expression rather than in an address structure. */ int parse_ip6_addr_expr(struct expression **expr, struct parse *cfile) { struct iaddr addr; if (!parse_ip6_addr(cfile, &addr)) { return 0; } return make_const_data(expr, addr.iabuf, addr.len, 0, 1, MDL); } /* * ip6-prefix :== ip6-address "/" NUMBER */ int parse_ip6_prefix(struct parse *cfile, struct iaddr *addr, u_int8_t *plen) { enum dhcp_token token; const char *val; int n; if (!parse_ip6_addr(cfile, addr)) { return 0; } token = next_token(&val, NULL, cfile); if (token != SLASH) { parse_warn(cfile, "Slash expected."); if (token != SEMI) skip_to_semi(cfile); return 0; } token = next_token(&val, NULL, cfile); if (token != NUMBER) { parse_warn(cfile, "Number expected."); if (token != SEMI) skip_to_semi(cfile); return 0; } n = atoi(val); if ((n < 0) || (n > 128)) { parse_warn(cfile, "Invalid IPv6 prefix length."); skip_to_semi(cfile); return 0; } if (!is_cidr_mask_valid(addr, n)) { parse_warn(cfile, "network mask too short."); skip_to_semi(cfile); return 0; } *plen = n; return 1; } /* * ip-address-with-subnet :== ip-address | * ip-address "/" NUMBER */ int parse_ip_addr_with_subnet(cfile, match) struct parse *cfile; struct iaddrmatch *match; { const char *val, *orig; enum dhcp_token token; int prefixlen; int fflen; unsigned char newval, warnmask=0; if (parse_ip_addr(cfile, &match->addr)) { /* default to host mask */ prefixlen = match->addr.len * 8; token = peek_token(&val, NULL, cfile); if (token == SLASH) { next_token(&val, NULL, cfile); token = next_token(&val, NULL, cfile); if (token != NUMBER) { parse_warn(cfile, "Invalid CIDR prefix length:" " expecting a number."); return 0; } prefixlen = atoi(val); if (prefixlen < 0 || prefixlen > (match->addr.len * 8)) { parse_warn(cfile, "subnet prefix is out of " "range [0..%d].", match->addr.len * 8); return 0; } } /* construct a suitable mask field */ /* copy length */ match->mask.len = match->addr.len; /* count of 0xff bytes in mask */ fflen = prefixlen / 8; /* set leading mask */ memset(match->mask.iabuf, 0xff, fflen); /* set zeroes */ if (fflen < match->mask.len) { match->mask.iabuf[fflen] = "\x00\x80\xc0\xe0\xf0\xf8\xfc\xfe"[prefixlen % 8]; memset(match->mask.iabuf+fflen+1, 0x00, match->mask.len - fflen - 1); /* AND-out insignificant bits from supplied netmask. */ orig = piaddr(match->addr); do { newval = match->addr.iabuf[fflen] & match->mask.iabuf[fflen]; if (newval != match->addr.iabuf[fflen]) { warnmask = 1; match->addr.iabuf[fflen] = newval; } } while (++fflen < match->mask.len); if (warnmask) { log_error("Warning: Extraneous bits removed " "in address component of %s/%d.", orig, prefixlen); log_error("New value: %s/%d.", piaddr(match->addr), prefixlen); } } return 1; } parse_warn(cfile, "expecting ip-address or ip-address/prefixlen"); return 0; /* let caller pick up pieces */ } /* * hardware-parameter :== HARDWARE hardware-type colon-separated-hex-list SEMI * hardware-type :== ETHERNET | TOKEN_RING | TOKEN_FDDI | INFINIBAND * Note that INFINIBAND may not be useful for some items, such as classification * as the hardware address won't always be available. */ void parse_hardware_param (cfile, hardware) struct parse *cfile; struct hardware *hardware; { const char *val; enum dhcp_token token; unsigned hlen; unsigned char *t; token = next_token(&val, NULL, cfile); switch (token) { case ETHERNET: hardware->hbuf[0] = HTYPE_ETHER; break; case TOKEN_RING: hardware->hbuf[0] = HTYPE_IEEE802; break; case TOKEN_FDDI: hardware->hbuf[0] = HTYPE_FDDI; break; case TOKEN_INFINIBAND: hardware->hbuf[0] = HTYPE_INFINIBAND; break; default: if (!strncmp(val, "unknown-", 8)) { hardware->hbuf[0] = atoi(&val[8]); } else { parse_warn(cfile, "expecting a network hardware type"); skip_to_semi(cfile); return; } } /* Parse the hardware address information. Technically, it would make a lot of sense to restrict the length of the data we'll accept here to the length of a particular hardware address type. Unfortunately, there are some broken clients out there that put bogus data in the chaddr buffer, and we accept that data in the lease file rather than simply failing on such clients. Yuck. */ hlen = 0; token = peek_token(&val, NULL, cfile); if (token == SEMI) { hardware->hlen = 1; goto out; } t = parse_numeric_aggregate(cfile, NULL, &hlen, COLON, 16, 8); if (t == NULL) { hardware->hlen = 1; return; } if (hlen + 1 > sizeof(hardware->hbuf)) { dfree(t, MDL); parse_warn(cfile, "hardware address too long"); } else { hardware->hlen = hlen + 1; memcpy((unsigned char *)&hardware->hbuf[1], t, hlen); if (hlen + 1 < sizeof(hardware->hbuf)) memset(&hardware->hbuf[hlen + 1], 0, (sizeof(hardware->hbuf)) - hlen - 1); dfree(t, MDL); } out: token = next_token(&val, NULL, cfile); if (token != SEMI) { parse_warn(cfile, "expecting semicolon."); skip_to_semi(cfile); } } /* lease-time :== NUMBER SEMI */ void parse_lease_time (cfile, timep) struct parse *cfile; TIME *timep; { const char *val; enum dhcp_token token; u_int32_t num; token = next_token (&val, (unsigned *)0, cfile); if (token != NUMBER) { parse_warn (cfile, "Expecting numeric lease time"); skip_to_semi (cfile); return; } convert_num(cfile, (unsigned char *)&num, val, 10, 32); /* Unswap the number - convert_num returns stuff in NBO. */ *timep = ntohl(num); parse_semi (cfile); } /* No BNF for numeric aggregates - that's defined by the caller. What this function does is to parse a sequence of numbers separated by the token specified in separator. If max is zero, any number of numbers will be parsed; otherwise, exactly max numbers are expected. Base and size tell us how to internalize the numbers once they've been tokenized. */ unsigned char *parse_numeric_aggregate (cfile, buf, max, separator, base, size) struct parse *cfile; unsigned char *buf; unsigned *max; int separator; int base; unsigned size; { const char *val; enum dhcp_token token; unsigned char *bufp = buf, *s, *t; unsigned count = 0; pair c = (pair)0; if (!bufp && *max) { bufp = (unsigned char *)dmalloc (*max * size / 8, MDL); if (!bufp) log_fatal ("no space for numeric aggregate"); s = 0; } else s = bufp; do { if (count) { token = peek_token (&val, (unsigned *)0, cfile); if (token != separator) { if (!*max) break; if (token != RBRACE && token != LBRACE) token = next_token (&val, (unsigned *)0, cfile); parse_warn (cfile, "too few numbers."); if (token != SEMI) skip_to_semi (cfile); return (unsigned char *)0; } token = next_token (&val, (unsigned *)0, cfile); } token = next_token (&val, (unsigned *)0, cfile); if (token == END_OF_FILE) { parse_warn (cfile, "unexpected end of file"); break; } /* Allow NUMBER_OR_NAME if base is 16. */ if (token != NUMBER && (base != 16 || token != NUMBER_OR_NAME)) { parse_warn (cfile, "expecting numeric value."); skip_to_semi (cfile); return (unsigned char *)0; } /* If we can, convert the number now; otherwise, build a linked list of all the numbers. */ if (s) { convert_num (cfile, s, val, base, size); s += size / 8; } else { t = (unsigned char *)dmalloc (strlen (val) + 1, MDL); if (!t) log_fatal ("no temp space for number."); strcpy ((char *)t, val); c = cons ((caddr_t)t, c); } } while (++count != *max); /* If we had to cons up a list, convert it now. */ if (c) { bufp = (unsigned char *)dmalloc (count * size / 8, MDL); if (!bufp) log_fatal ("no space for numeric aggregate."); s = bufp + count - size / 8; *max = count; } while (c) { pair cdr = c -> cdr; convert_num (cfile, s, (char *)(c -> car), base, size); s -= size / 8; /* Free up temp space. */ dfree (c -> car, MDL); dfree (c, MDL); c = cdr; } return bufp; } void convert_num (cfile, buf, str, base, size) struct parse *cfile; unsigned char *buf; const char *str; int base; unsigned size; { const unsigned char *ptr = (const unsigned char *)str; int negative = 0; u_int32_t val = 0; int tval; int max; if (*ptr == '-') { negative = 1; ++ptr; } /* If base wasn't specified, figure it out from the data. */ if (!base) { if (ptr [0] == '0') { if (ptr [1] == 'x') { base = 16; ptr += 2; } else if (isascii (ptr [1]) && isdigit (ptr [1])) { base = 8; ptr += 1; } else { base = 10; } } else { base = 10; } } do { tval = *ptr++; /* XXX assumes ASCII... */ if (tval >= 'a') tval = tval - 'a' + 10; else if (tval >= 'A') tval = tval - 'A' + 10; else if (tval >= '0') tval -= '0'; else { parse_warn (cfile, "Bogus number: %s.", str); break; } if (tval >= base) { parse_warn (cfile, "Bogus number %s: digit %d not in base %d", str, tval, base); break; } val = val * base + tval; } while (*ptr); if (negative) max = (1 << (size - 1)); else max = (1 << (size - 1)) + ((1 << (size - 1)) - 1); if (val > max) { switch (base) { case 8: parse_warn (cfile, "%s%lo exceeds max (%d) for precision.", negative ? "-" : "", (unsigned long)val, max); break; case 16: parse_warn (cfile, "%s%lx exceeds max (%d) for precision.", negative ? "-" : "", (unsigned long)val, max); break; default: parse_warn (cfile, "%s%lu exceeds max (%d) for precision.", negative ? "-" : "", (unsigned long)val, max); break; } } if (negative) { switch (size) { case 8: *buf = -(unsigned long)val; break; case 16: putShort (buf, -(long)val); break; case 32: putLong (buf, -(long)val); break; default: parse_warn (cfile, "Unexpected integer size: %d\n", size); break; } } else { switch (size) { case 8: *buf = (u_int8_t)val; break; case 16: putUShort (buf, (u_int16_t)val); break; case 32: putULong (buf, val); break; default: parse_warn (cfile, "Unexpected integer size: %d\n", size); break; } } } /* * date :== NUMBER NUMBER SLASH NUMBER SLASH NUMBER * NUMBER COLON NUMBER COLON NUMBER | * NUMBER NUMBER SLASH NUMBER SLASH NUMBER * NUMBER COLON NUMBER COLON NUMBER NUMBER | * EPOCH NUMBER | * NEVER * * Dates are stored in UTC or with a timezone offset; first number is day * of week; next is year/month/day; next is hours:minutes:seconds on a * 24-hour clock, followed by the timezone offset in seconds, which is * optional. */ /* * just parse the date * any trailing semi must be consumed by the caller of this routine */ TIME parse_date_core(cfile) struct parse *cfile; { int guess; int tzoff, year, mon, mday, hour, min, sec; const char *val; enum dhcp_token token; static int months[11] = { 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; /* "never", "epoch" or day of week */ token = peek_token(&val, NULL, cfile); if (token == NEVER) { token = next_token(&val, NULL, cfile); /* consume NEVER */ return(MAX_TIME); } /* This indicates 'local' time format. */ if (token == EPOCH) { token = next_token(&val, NULL, cfile); /* consume EPOCH */ token = peek_token(&val, NULL, cfile); if (token != NUMBER) { if (token != SEMI) token = next_token(&val, NULL, cfile); parse_warn(cfile, "Seconds since epoch expected."); return((TIME)0); } token = next_token(&val, NULL, cfile); /* consume number */ guess = atoi(val); return((TIME)guess); } if (token != NUMBER) { if (token != SEMI) token = next_token(&val, NULL, cfile); parse_warn(cfile, "numeric day of week expected."); return((TIME)0); } token = next_token(&val, NULL, cfile); /* consume day of week */ /* we are not using this for anything */ /* Year... */ token = peek_token(&val, NULL, cfile); if (token != NUMBER) { if (token != SEMI) token = next_token(&val, NULL, cfile); parse_warn(cfile, "numeric year expected."); return((TIME)0); } token = next_token(&val, NULL, cfile); /* consume year */ /* Note: the following is not a Y2K bug - it's a Y1.9K bug. Until somebody invents a time machine, I think we can safely disregard it. This actually works around a stupid Y2K bug that was present in a very early beta release of dhcpd. */ year = atoi(val); if (year > 1900) year -= 1900; /* Slash separating year from month... */ token = peek_token(&val, NULL, cfile); if (token != SLASH) { if (token != SEMI) token = next_token(&val, NULL, cfile); parse_warn(cfile, "expected slash separating year from month."); return((TIME)0); } token = next_token(&val, NULL, cfile); /* consume SLASH */ /* Month... */ token = peek_token(&val, NULL, cfile); if (token != NUMBER) { if (token != SEMI) token = next_token(&val, NULL, cfile); parse_warn(cfile, "numeric month expected."); return((TIME)0); } token = next_token(&val, NULL, cfile); /* consume month */ mon = atoi(val) - 1; /* Slash separating month from day... */ token = peek_token(&val, NULL, cfile); if (token != SLASH) { if (token != SEMI) token = next_token(&val, NULL, cfile); parse_warn(cfile, "expected slash separating month from day."); return((TIME)0); } token = next_token(&val, NULL, cfile); /* consume SLASH */ /* Day of month... */ token = peek_token(&val, NULL, cfile); if (token != NUMBER) { if (token != SEMI) token = next_token(&val, NULL, cfile); parse_warn(cfile, "numeric day of month expected."); return((TIME)0); } token = next_token(&val, NULL, cfile); /* consume day of month */ mday = atoi(val); /* Hour... */ token = peek_token(&val, NULL, cfile); if (token != NUMBER) { if (token != SEMI) token = next_token(&val, NULL, cfile); parse_warn(cfile, "numeric hour expected."); return((TIME)0); } token = next_token(&val, NULL, cfile); /* consume hour */ hour = atoi(val); /* Colon separating hour from minute... */ token = peek_token(&val, NULL, cfile); if (token != COLON) { if (token != SEMI) token = next_token(&val, NULL, cfile); parse_warn(cfile, "expected colon separating hour from minute."); return((TIME)0); } token = next_token(&val, NULL, cfile); /* consume colon */ /* Minute... */ token = peek_token(&val, NULL, cfile); if (token != NUMBER) { if (token != SEMI) token = next_token(&val, NULL, cfile); parse_warn(cfile, "numeric minute expected."); return((TIME)0); } token = next_token(&val, NULL, cfile); /* consume minute */ min = atoi(val); /* Colon separating minute from second... */ token = peek_token(&val, NULL, cfile); if (token != COLON) { if (token != SEMI) token = next_token(&val, NULL, cfile); parse_warn(cfile, "expected colon separating minute from second."); return((TIME)0); } token = next_token(&val, NULL, cfile); /* consume colon */ /* Second... */ token = peek_token(&val, NULL, cfile); if (token != NUMBER) { if (token != SEMI) token = next_token(&val, NULL, cfile); parse_warn(cfile, "numeric second expected."); return((TIME)0); } token = next_token(&val, NULL, cfile); /* consume second */ sec = atoi(val); tzoff = 0; token = peek_token(&val, NULL, cfile); if (token == NUMBER) { token = next_token(&val, NULL, cfile); /* consume tzoff */ tzoff = atoi(val); } else if (token != SEMI) { token = next_token(&val, NULL, cfile); parse_warn(cfile, "Time zone offset or semicolon expected."); return((TIME)0); } /* Guess the time value... */ guess = ((((((365 * (year - 70) + /* Days in years since '70 */ (year - 69) / 4 + /* Leap days since '70 */ (mon /* Days in months this year */ ? months [mon - 1] : 0) + (mon > 1 && /* Leap day this year */ !((year - 72) & 3)) + mday - 1) * 24) + /* Day of month */ hour) * 60) + min) * 60) + sec + tzoff; /* This guess could be wrong because of leap seconds or other weirdness we don't know about that the system does. For now, we're just going to accept the guess, but at some point it might be nice to do a successive approximation here to get an exact value. Even if the error is small, if the server is restarted frequently (and thus the lease database is reread), the error could accumulate into something significant. */ return((TIME)guess); } /* * Wrapper to consume the semicolon after the date * :== date semi */ TIME parse_date(cfile) struct parse *cfile; { TIME guess; guess = parse_date_core(cfile); /* Make sure the date ends in a semicolon... */ if (!parse_semi(cfile)) return((TIME)0); return(guess); } /* * option-name :== IDENTIFIER | IDENTIFIER . IDENTIFIER */ isc_result_t parse_option_name (cfile, allocate, known, opt) struct parse *cfile; int allocate; int *known; struct option **opt; { const char *val; enum dhcp_token token; char *uname; struct universe *universe; struct option *option; unsigned code; if (opt == NULL) return DHCP_R_INVALIDARG; token = next_token (&val, (unsigned *)0, cfile); if (!is_identifier (token)) { parse_warn (cfile, "expecting identifier after option keyword."); if (token != SEMI) skip_to_semi (cfile); return DHCP_R_BADPARSE; } uname = dmalloc (strlen (val) + 1, MDL); if (!uname) log_fatal ("no memory for uname information."); strcpy (uname, val); token = peek_token (&val, (unsigned *)0, cfile); if (token == DOT) { /* Go ahead and take the DOT token... */ token = next_token (&val, (unsigned *)0, cfile); /* The next token should be an identifier... */ token = next_token (&val, (unsigned *)0, cfile); if (!is_identifier (token)) { parse_warn (cfile, "expecting identifier after '.'"); if (token != SEMI) skip_to_semi (cfile); return DHCP_R_BADPARSE; } /* Look up the option name hash table for the specified uname. */ universe = (struct universe *)0; if (!universe_hash_lookup (&universe, universe_hash, uname, 0, MDL)) { parse_warn (cfile, "no option space named %s.", uname); skip_to_semi (cfile); return ISC_R_NOTFOUND; } } else { /* Use the default hash table, which contains all the standard dhcp option names. */ val = uname; universe = &dhcp_universe; } /* Look up the actual option info... */ option_name_hash_lookup(opt, universe->name_hash, val, 0, MDL); option = *opt; /* If we didn't get an option structure, it's an undefined option. */ if (option) { if (known) *known = 1; /* If the option name is of the form unknown-[decimal], use * the trailing decimal value to find the option definition. * If there is no definition, construct one. This is to * support legacy use of unknown options in config files or * lease databases. */ } else if (strncasecmp(val, "unknown-", 8) == 0) { code = atoi(val+8); /* Option code 0 is always illegal for us, thanks * to the option decoder. */ if (code == 0 || code == universe->end) { parse_warn(cfile, "Option codes 0 and %u are illegal " "in the %s space.", universe->end, universe->name); skip_to_semi(cfile); dfree(uname, MDL); return ISC_R_FAILURE; } /* It's odd to think of unknown option codes as * being known, but this means we know what the * parsed name is talking about. */ if (known) *known = 1; option_code_hash_lookup(opt, universe->code_hash, &code, 0, MDL); option = *opt; /* If we did not find an option of that code, * manufacture an unknown-xxx option definition. * Its single reference will ensure that it is * deleted once the option is recycled out of * existence (by the parent). */ if (option == NULL) { option = new_option(val, MDL); option->universe = universe; option->code = code; option->format = default_option_format; option_reference(opt, option, MDL); } else log_info("option %s has been redefined as option %s. " "Please update your configs if neccessary.", val, option->name); /* If we've been told to allocate, that means that this * (might) be an option code definition, so we'll create * an option structure and return it for the parent to * decide. */ } else if (allocate) { option = new_option(val, MDL); option -> universe = universe; option_reference(opt, option, MDL); } else { parse_warn(cfile, "no option named %s in space %s", val, universe->name); skip_to_semi (cfile); dfree(uname, MDL); return ISC_R_NOTFOUND; } /* Free the initial identifier token. */ dfree (uname, MDL); return ISC_R_SUCCESS; } /* IDENTIFIER [WIDTHS] SEMI * WIDTHS ~= LENGTH WIDTH NUMBER * CODE WIDTH NUMBER */ void parse_option_space_decl (cfile) struct parse *cfile; { int token; const char *val; struct universe **ua, *nu; char *nu_name; int tsize=1, lsize=1, hsize = 0; next_token (&val, (unsigned *)0, cfile); /* Discard the SPACE token, which was checked by the caller. */ token = next_token (&val, (unsigned *)0, cfile); if (!is_identifier (token)) { parse_warn (cfile, "expecting identifier."); skip_to_semi (cfile); return; } nu = new_universe (MDL); if (!nu) log_fatal ("No memory for new option space."); /* Set up the server option universe... */ nu_name = dmalloc (strlen (val) + 1, MDL); if (!nu_name) log_fatal ("No memory for new option space name."); strcpy (nu_name, val); nu -> name = nu_name; do { token = next_token(&val, NULL, cfile); switch(token) { case SEMI: break; case CODE: token = next_token(&val, NULL, cfile); if (token != WIDTH) { parse_warn(cfile, "expecting width token."); goto bad; } token = next_token(&val, NULL, cfile); if (token != NUMBER) { parse_warn(cfile, "expecting number 1, 2, 4."); goto bad; } tsize = atoi(val); switch (tsize) { case 1: if (!hsize) hsize = BYTE_NAME_HASH_SIZE; break; case 2: if (!hsize) hsize = WORD_NAME_HASH_SIZE; break; case 4: if (!hsize) hsize = QUAD_NAME_HASH_SIZE; break; default: parse_warn(cfile, "invalid code width (%d), " "expecting a 1, 2 or 4.", tsize); goto bad; } break; case LENGTH: token = next_token(&val, NULL, cfile); if (token != WIDTH) { parse_warn(cfile, "expecting width token."); goto bad; } token = next_token(&val, NULL, cfile); if (token != NUMBER) { parse_warn(cfile, "expecting number 1 or 2."); goto bad; } lsize = atoi(val); if (lsize != 1 && lsize != 2) { parse_warn(cfile, "invalid length width (%d) " "expecting 1 or 2.", lsize); goto bad; } break; case HASH: token = next_token(&val, NULL, cfile); if (token != SIZE) { parse_warn(cfile, "expecting size token."); goto bad; } token = next_token(&val, NULL, cfile); if (token != NUMBER) { parse_warn(cfile, "expecting a 10base number"); goto bad; } /* (2^31)-1 is the highest Mersenne prime we should * probably allow... */ hsize = atoi(val); if (hsize < 0 || hsize > 0x7FFFFFFF) { parse_warn(cfile, "invalid hash length: %d", hsize); goto bad; } break; default: parse_warn(cfile, "Unexpected token."); } } while (token != SEMI); if (!hsize) hsize = DEFAULT_SPACE_HASH_SIZE; nu -> lookup_func = lookup_hashed_option; nu -> option_state_dereference = hashed_option_state_dereference; nu -> foreach = hashed_option_space_foreach; nu -> save_func = save_hashed_option; nu -> delete_func = delete_hashed_option; nu -> encapsulate = hashed_option_space_encapsulate; nu -> decode = parse_option_buffer; nu -> length_size = lsize; nu -> tag_size = tsize; switch(tsize) { case 1: nu->get_tag = getUChar; nu->store_tag = putUChar; break; case 2: nu->get_tag = getUShort; nu->store_tag = putUShort; break; case 4: nu->get_tag = getULong; nu->store_tag = putULong; break; default: log_fatal("Impossible condition at %s:%d.", MDL); } switch(lsize) { case 0: nu->get_length = NULL; nu->store_length = NULL; break; case 1: nu->get_length = getUChar; nu->store_length = putUChar; break; case 2: nu->get_length = getUShort; nu->store_length = putUShort; break; default: log_fatal("Impossible condition at %s:%d.", MDL); } nu -> index = universe_count++; if (nu -> index >= universe_max) { ua = dmalloc (universe_max * 2 * sizeof *ua, MDL); if (!ua) log_fatal ("No memory to expand option space array."); memcpy (ua, universes, universe_max * sizeof *ua); universe_max *= 2; dfree (universes, MDL); universes = ua; } universes [nu -> index] = nu; if (!option_name_new_hash(&nu->name_hash, hsize, MDL) || !option_code_new_hash(&nu->code_hash, hsize, MDL)) log_fatal("Can't allocate %s option hash table.", nu->name); universe_hash_add (universe_hash, nu -> name, 0, nu, MDL); return; bad: dfree(nu_name, MDL); dfree(nu, MDL); } /* This is faked up to look good right now. Ideally, this should do a recursive parse and allow arbitrary data structure definitions, but for now it just allows you to specify a single type, an array of single types, a sequence of types, or an array of sequences of types. ocd :== NUMBER EQUALS ocsd SEMI ocsd :== ocsd_type | ocsd_type_sequence | ARRAY OF ocsd_simple_type_sequence ocsd_type_sequence :== LBRACE ocsd_types RBRACE ocsd_simple_type_sequence :== LBRACE ocsd_simple_types RBRACE ocsd_types :== ocsd_type | ocsd_types ocsd_type ocsd_type :== ocsd_simple_type | ARRAY OF ocsd_simple_type ocsd_simple_types :== ocsd_simple_type | ocsd_simple_types ocsd_simple_type ocsd_simple_type :== BOOLEAN | INTEGER NUMBER | SIGNED INTEGER NUMBER | UNSIGNED INTEGER NUMBER | IP-ADDRESS | TEXT | STRING | ENCAPSULATE identifier */ int parse_option_code_definition (cfile, option) struct parse *cfile; struct option *option; { const char *val; enum dhcp_token token; struct option *oldopt; unsigned arrayp = 0; int recordp = 0; int no_more_in_record = 0; char tokbuf [128]; unsigned tokix = 0; char type; int is_signed; char *s; int has_encapsulation = 0; struct universe *encapsulated; /* Parse the option code. */ token = next_token (&val, (unsigned *)0, cfile); if (token != NUMBER) { parse_warn (cfile, "expecting option code number."); skip_to_semi (cfile); return 0; } option -> code = atoi (val); token = next_token (&val, (unsigned *)0, cfile); if (token != EQUAL) { parse_warn (cfile, "expecting \"=\""); skip_to_semi (cfile); return 0; } /* See if this is an array. */ token = next_token (&val, (unsigned *)0, cfile); if (token == ARRAY) { token = next_token (&val, (unsigned *)0, cfile); if (token != OF) { parse_warn (cfile, "expecting \"of\"."); skip_to_semi (cfile); return 0; } arrayp = 1; token = next_token (&val, (unsigned *)0, cfile); } if (token == LBRACE) { recordp = 1; token = next_token (&val, (unsigned *)0, cfile); } /* At this point we're expecting a data type. */ next_type: if (has_encapsulation) { parse_warn (cfile, "encapsulate must always be the last item."); skip_to_semi (cfile); return 0; } switch (token) { case ARRAY: if (arrayp) { parse_warn (cfile, "no nested arrays."); skip_to_rbrace (cfile, recordp); if (recordp) skip_to_semi (cfile); return 0; } token = next_token (&val, (unsigned *)0, cfile); if (token != OF) { parse_warn (cfile, "expecting \"of\"."); skip_to_semi (cfile); return 0; } arrayp = recordp + 1; token = next_token (&val, (unsigned *)0, cfile); if ((recordp) && (token == LBRACE)) { parse_warn (cfile, "only uniform array inside record."); skip_to_rbrace (cfile, recordp + 1); skip_to_semi (cfile); return 0; } goto next_type; case BOOLEAN: type = 'f'; break; case INTEGER: is_signed = 1; parse_integer: token = next_token (&val, (unsigned *)0, cfile); if (token != NUMBER) { parse_warn (cfile, "expecting number."); skip_to_rbrace (cfile, recordp); if (recordp) skip_to_semi (cfile); return 0; } switch (atoi (val)) { case 8: type = is_signed ? 'b' : 'B'; break; case 16: type = is_signed ? 's' : 'S'; break; case 32: type = is_signed ? 'l' : 'L'; break; default: parse_warn (cfile, "%s bit precision is not supported.", val); skip_to_rbrace (cfile, recordp); if (recordp) skip_to_semi (cfile); return 0; } break; case SIGNED: is_signed = 1; parse_signed: token = next_token (&val, (unsigned *)0, cfile); if (token != INTEGER) { parse_warn (cfile, "expecting \"integer\" keyword."); skip_to_rbrace (cfile, recordp); if (recordp) skip_to_semi (cfile); return 0; } goto parse_integer; case UNSIGNED: is_signed = 0; goto parse_signed; case IP_ADDRESS: type = 'I'; break; case IP6_ADDRESS: type = '6'; break; case DOMAIN_NAME: type = 'd'; goto no_arrays; case DOMAIN_LIST: /* Consume optional compression indicator. */ token = peek_token(&val, NULL, cfile); if (token == COMPRESSED) { token = next_token(&val, NULL, cfile); tokbuf[tokix++] = 'D'; type = 'c'; } else type = 'D'; goto no_arrays; case TEXT: type = 't'; no_arrays: if (arrayp) { parse_warn (cfile, "arrays of text strings not %s", "yet supported."); skip_to_rbrace (cfile, recordp); if (recordp) skip_to_semi (cfile); return 0; } no_more_in_record = 1; break; case STRING_TOKEN: type = 'X'; goto no_arrays; case ENCAPSULATE: token = next_token (&val, (unsigned *)0, cfile); if (!is_identifier (token)) { parse_warn (cfile, "expecting option space identifier"); skip_to_semi (cfile); return 0; } encapsulated = NULL; if (!universe_hash_lookup(&encapsulated, universe_hash, val, strlen(val), MDL)) { parse_warn(cfile, "unknown option space %s", val); skip_to_semi (cfile); return 0; } if (strlen (val) + tokix + 2 > sizeof (tokbuf)) goto toobig; tokbuf [tokix++] = 'E'; strcpy (&tokbuf [tokix], val); tokix += strlen (val); type = '.'; has_encapsulation = 1; break; case ZEROLEN: type = 'Z'; if (arrayp) { parse_warn (cfile, "array incompatible with zerolen."); skip_to_rbrace (cfile, recordp); if (recordp) skip_to_semi (cfile); return 0; } no_more_in_record = 1; break; default: parse_warn (cfile, "unknown data type %s", val); skip_to_rbrace (cfile, recordp); if (recordp) skip_to_semi (cfile); return 0; } if (tokix == sizeof tokbuf) { toobig: parse_warn (cfile, "too many types in record."); skip_to_rbrace (cfile, recordp); if (recordp) skip_to_semi (cfile); return 0; } tokbuf [tokix++] = type; if (recordp) { token = next_token (&val, (unsigned *)0, cfile); if (arrayp > recordp) { if (tokix == sizeof tokbuf) { parse_warn (cfile, "too many types in record."); skip_to_rbrace (cfile, 1); skip_to_semi (cfile); return 0; } arrayp = 0; tokbuf[tokix++] = 'a'; } if (token == COMMA) { if (no_more_in_record) { parse_warn (cfile, "%s must be at end of record.", type == 't' ? "text" : "string"); skip_to_rbrace (cfile, 1); if (recordp) skip_to_semi (cfile); return 0; } token = next_token (&val, (unsigned *)0, cfile); goto next_type; } if (token != RBRACE) { parse_warn (cfile, "expecting right brace."); skip_to_rbrace (cfile, 1); if (recordp) skip_to_semi (cfile); return 0; } } if (!parse_semi (cfile)) { parse_warn (cfile, "semicolon expected."); skip_to_semi (cfile); if (recordp) skip_to_semi (cfile); return 0; } if (has_encapsulation && arrayp) { parse_warn (cfile, "Arrays of encapsulations don't make sense."); return 0; } s = dmalloc(tokix + (arrayp ? 1 : 0) + 1, MDL); if (s == NULL) { log_fatal("no memory for option format."); } memcpy(s, tokbuf, tokix); if (arrayp) { s[tokix++] = (arrayp > recordp) ? 'a' : 'A'; } s[tokix] = '\0'; option -> format = s; oldopt = NULL; option_code_hash_lookup(&oldopt, option->universe->code_hash, &option->code, 0, MDL); if (oldopt != NULL) { /* * XXX: This illegalizes a configuration syntax that was * valid in 3.0.x, where multiple name->code mappings are * given, but only one code->name mapping survives. It is * unclear what can or should be done at this point, but it * seems best to retain 3.0.x behaviour for upgrades to go * smoothly. * option_name_hash_delete(option->universe->name_hash, oldopt->name, 0, MDL); */ option_code_hash_delete(option->universe->code_hash, &oldopt->code, 0, MDL); option_dereference(&oldopt, MDL); } option_code_hash_add(option->universe->code_hash, &option->code, 0, option, MDL); option_name_hash_add(option->universe->name_hash, option->name, 0, option, MDL); if (has_encapsulation) { /* INSIST(tokbuf[0] == 'E'); */ /* INSIST(encapsulated != NULL); */ if (!option_code_hash_lookup(&encapsulated->enc_opt, option->universe->code_hash, &option->code, 0, MDL)) { log_fatal("error finding encapsulated option (%s:%d)", MDL); } } return 1; } /* * base64 :== NUMBER_OR_STRING */ int parse_base64 (data, cfile) struct data_string *data; struct parse *cfile; { enum dhcp_token token; const char *val; int i, j, k; unsigned acc = 0; static unsigned char from64 [] = {64, 64, 64, 64, 64, 64, 64, 64, /* \"#$%&' */ 64, 64, 64, 62, 64, 64, 64, 63, /* ()*+,-./ */ 52, 53, 54, 55, 56, 57, 58, 59, /* 01234567 */ 60, 61, 64, 64, 64, 64, 64, 64, /* 89:;<=>? */ 64, 0, 1, 2, 3, 4, 5, 6, /* @ABCDEFG */ 7, 8, 9, 10, 11, 12, 13, 14, /* HIJKLMNO */ 15, 16, 17, 18, 19, 20, 21, 22, /* PQRSTUVW */ 23, 24, 25, 64, 64, 64, 64, 64, /* XYZ[\]^_ */ 64, 26, 27, 28, 29, 30, 31, 32, /* 'abcdefg */ 33, 34, 35, 36, 37, 38, 39, 40, /* hijklmno */ 41, 42, 43, 44, 45, 46, 47, 48, /* pqrstuvw */ 49, 50, 51, 64, 64, 64, 64, 64}; /* xyz{|}~ */ struct string_list *bufs = (struct string_list *)0, *last = (struct string_list *)0, *t; int cc = 0; int terminated = 0; /* It's possible for a + or a / to cause a base64 quantity to be tokenized into more than one token, so we have to parse them all in before decoding. */ do { unsigned l; token = next_token (&val, &l, cfile); t = dmalloc (l + sizeof *t, MDL); if (!t) log_fatal ("no memory for base64 buffer."); memset (t, 0, (sizeof *t) - 1); memcpy (t -> string, val, l + 1); cc += l; if (last) last -> next = t; else bufs = t; last = t; token = peek_token (&val, (unsigned *)0, cfile); } while (token == NUMBER_OR_NAME || token == NAME || token == EQUAL || token == NUMBER || token == PLUS || token == SLASH || token == STRING); data -> len = cc; data -> len = (data -> len * 3) / 4; if (!buffer_allocate (&data -> buffer, data -> len, MDL)) { parse_warn (cfile, "can't allocate buffer for base64 data."); data -> len = 0; data -> data = (unsigned char *)0; return 0; } j = k = 0; for (t = bufs; t; t = t -> next) { for (i = 0; t -> string [i]; i++) { unsigned foo = t -> string [i]; if (terminated && foo != '=') { parse_warn (cfile, "stuff after base64 '=' terminator: %s.", &t -> string [i]); goto bad; } if (foo < ' ' || foo > 'z') { bad64: parse_warn (cfile, "invalid base64 character %d.", t -> string [i]); bad: data_string_forget (data, MDL); goto out; } if (foo == '=') terminated = 1; else { foo = from64 [foo - ' ']; if (foo == 64) goto bad64; acc = (acc << 6) + foo; switch (k % 4) { case 0: break; case 1: data -> buffer -> data [j++] = (acc >> 4); acc = acc & 0x0f; break; case 2: data -> buffer -> data [j++] = (acc >> 2); acc = acc & 0x03; break; case 3: data -> buffer -> data [j++] = acc; acc = 0; break; } } k++; } } if (k % 4) { if (acc) { parse_warn (cfile, "partial base64 value left over: %d.", acc); } } data -> len = j; data -> data = data -> buffer -> data; out: for (t = bufs; t; t = last) { last = t -> next; dfree (t, MDL); } if (data -> len) return 1; else return 0; } /* * colon-separated-hex-list :== NUMBER | * NUMBER COLON colon-separated-hex-list */ int parse_cshl (data, cfile) struct data_string *data; struct parse *cfile; { u_int8_t ibuf [128]; unsigned ilen = 0; unsigned tlen = 0; struct option_tag *sl = (struct option_tag *)0; struct option_tag *next, **last = &sl; enum dhcp_token token; const char *val; unsigned char *rvp; do { token = next_token (&val, (unsigned *)0, cfile); if (token != NUMBER && token != NUMBER_OR_NAME) { parse_warn (cfile, "expecting hexadecimal number."); skip_to_semi (cfile); for (; sl; sl = next) { next = sl -> next; dfree (sl, MDL); } return 0; } if (ilen == sizeof ibuf) { next = (struct option_tag *) dmalloc (ilen - 1 + sizeof (struct option_tag), MDL); if (!next) log_fatal ("no memory for string list."); memcpy (next -> data, ibuf, ilen); *last = next; last = &next -> next; tlen += ilen; ilen = 0; } convert_num (cfile, &ibuf [ilen++], val, 16, 8); token = peek_token (&val, (unsigned *)0, cfile); if (token != COLON) break; token = next_token (&val, (unsigned *)0, cfile); } while (1); if (!buffer_allocate (&data -> buffer, tlen + ilen, MDL)) log_fatal ("no memory to store octet data."); data -> data = &data -> buffer -> data [0]; data -> len = tlen + ilen; data -> terminated = 0; rvp = &data -> buffer -> data [0]; while (sl) { next = sl -> next; memcpy (rvp, sl -> data, sizeof ibuf); rvp += sizeof ibuf; dfree (sl, MDL); sl = next; } memcpy (rvp, ibuf, ilen); return 1; } /* * executable-statements :== executable-statement executable-statements | * executable-statement * * executable-statement :== * IF if-statement | * ADD class-name SEMI | * BREAK SEMI | * OPTION option-parameter SEMI | * SUPERSEDE option-parameter SEMI | * PREPEND option-parameter SEMI | * APPEND option-parameter SEMI */ int parse_executable_statements (statements, cfile, lose, case_context) struct executable_statement **statements; struct parse *cfile; int *lose; enum expression_context case_context; { struct executable_statement **next; next = statements; while (parse_executable_statement (next, cfile, lose, case_context)) next = &((*next) -> next); if (!*lose) return 1; return 0; } int parse_executable_statement (result, cfile, lose, case_context) struct executable_statement **result; struct parse *cfile; int *lose; enum expression_context case_context; { #if defined(ENABLE_EXECUTE) unsigned len; struct expression **ep; #endif enum dhcp_token token; const char *val; struct class *cta; struct option *option=NULL; struct option_cache *cache; int known; int flag; int i; struct dns_zone *zone; isc_result_t status; char *s; token = peek_token (&val, (unsigned *)0, cfile); switch (token) { case DB_TIME_FORMAT: next_token(&val, NULL, cfile); token = next_token(&val, NULL, cfile); if (token == DEFAULT) { db_time_format = DEFAULT_TIME_FORMAT; } else if (token == LOCAL) { db_time_format = LOCAL_TIME_FORMAT; } else { parse_warn(cfile, "Expecting 'local' or 'default'."); if (token != SEMI) skip_to_semi(cfile); *lose = 1; return 0; } token = next_token(&val, NULL, cfile); if (token != SEMI) { parse_warn(cfile, "Expecting a semicolon."); *lose = 1; return 0; } /* We're done here. */ return 1; case IF: next_token (&val, (unsigned *)0, cfile); return parse_if_statement (result, cfile, lose); case TOKEN_ADD: token = next_token (&val, (unsigned *)0, cfile); token = next_token (&val, (unsigned *)0, cfile); if (token != STRING) { parse_warn (cfile, "expecting class name."); skip_to_semi (cfile); *lose = 1; return 0; } cta = (struct class *)0; status = find_class (&cta, val, MDL); if (status != ISC_R_SUCCESS) { parse_warn (cfile, "class %s: %s", val, isc_result_totext (status)); skip_to_semi (cfile); *lose = 1; return 0; } if (!parse_semi (cfile)) { *lose = 1; return 0; } if (!executable_statement_allocate (result, MDL)) log_fatal ("no memory for new statement."); (*result) -> op = add_statement; (*result) -> data.add = cta; break; case BREAK: token = next_token (&val, (unsigned *)0, cfile); if (!parse_semi (cfile)) { *lose = 1; return 0; } if (!executable_statement_allocate (result, MDL)) log_fatal ("no memory for new statement."); (*result) -> op = break_statement; break; case SEND: token = next_token (&val, (unsigned *)0, cfile); known = 0; status = parse_option_name (cfile, 0, &known, &option); if (status != ISC_R_SUCCESS || option == NULL) { *lose = 1; return 0; } status = parse_option_statement(result, cfile, 1, option, send_option_statement); option_dereference(&option, MDL); return status; case SUPERSEDE: case OPTION: token = next_token (&val, (unsigned *)0, cfile); known = 0; status = parse_option_name (cfile, 0, &known, &option); if (status != ISC_R_SUCCESS || option == NULL) { *lose = 1; return 0; } status = parse_option_statement(result, cfile, 1, option, supersede_option_statement); option_dereference(&option, MDL); return status; case ALLOW: flag = 1; goto pad; case DENY: flag = 0; goto pad; case IGNORE: flag = 2; pad: token = next_token (&val, (unsigned *)0, cfile); cache = (struct option_cache *)0; if (!parse_allow_deny (&cache, cfile, flag)) return 0; if (!executable_statement_allocate (result, MDL)) log_fatal ("no memory for new statement."); (*result) -> op = supersede_option_statement; (*result) -> data.option = cache; break; case DEFAULT: token = next_token (&val, (unsigned *)0, cfile); token = peek_token (&val, (unsigned *)0, cfile); if (token == COLON) goto switch_default; known = 0; status = parse_option_name (cfile, 0, &known, &option); if (status != ISC_R_SUCCESS || option == NULL) { *lose = 1; return 0; } status = parse_option_statement(result, cfile, 1, option, default_option_statement); option_dereference(&option, MDL); return status; case PREPEND: token = next_token (&val, (unsigned *)0, cfile); known = 0; status = parse_option_name (cfile, 0, &known, &option); if (status != ISC_R_SUCCESS || option == NULL) { *lose = 1; return 0; } status = parse_option_statement(result, cfile, 1, option, prepend_option_statement); option_dereference(&option, MDL); return status; case APPEND: token = next_token (&val, (unsigned *)0, cfile); known = 0; status = parse_option_name (cfile, 0, &known, &option); if (status != ISC_R_SUCCESS || option == NULL) { *lose = 1; return 0; } status = parse_option_statement(result, cfile, 1, option, append_option_statement); option_dereference(&option, MDL); return status; case ON: token = next_token (&val, (unsigned *)0, cfile); return parse_on_statement (result, cfile, lose); case SWITCH: token = next_token (&val, (unsigned *)0, cfile); return parse_switch_statement (result, cfile, lose); case CASE: token = next_token (&val, (unsigned *)0, cfile); if (case_context == context_any) { parse_warn (cfile, "case statement in inappropriate scope."); *lose = 1; skip_to_semi (cfile); return 0; } return parse_case_statement (result, cfile, lose, case_context); switch_default: token = next_token (&val, (unsigned *)0, cfile); if (case_context == context_any) { parse_warn (cfile, "switch default statement in %s", "inappropriate scope."); *lose = 1; return 0; } else { if (!executable_statement_allocate (result, MDL)) log_fatal ("no memory for default statement."); (*result) -> op = default_statement; return 1; } case DEFINE: case TOKEN_SET: token = next_token (&val, (unsigned *)0, cfile); if (token == DEFINE) flag = 1; else flag = 0; token = next_token (&val, (unsigned *)0, cfile); if (token != NAME && token != NUMBER_OR_NAME) { parse_warn (cfile, "%s can't be a variable name", val); badset: skip_to_semi (cfile); *lose = 1; return 0; } if (!executable_statement_allocate (result, MDL)) log_fatal ("no memory for set statement."); (*result) -> op = flag ? define_statement : set_statement; (*result) -> data.set.name = dmalloc (strlen (val) + 1, MDL); if (!(*result)->data.set.name) log_fatal ("can't allocate variable name"); strcpy ((*result) -> data.set.name, val); token = next_token (&val, (unsigned *)0, cfile); if (token == LPAREN) { struct string_list *head, *cur, *new; struct expression *expr; head = cur = (struct string_list *)0; do { token = next_token (&val, (unsigned *)0, cfile); if (token == RPAREN) break; if (token != NAME && token != NUMBER_OR_NAME) { parse_warn (cfile, "expecting argument name"); skip_to_rbrace (cfile, 0); *lose = 1; executable_statement_dereference (result, MDL); return 0; } new = ((struct string_list *) dmalloc (sizeof (struct string_list) + strlen (val), MDL)); if (!new) log_fatal ("can't allocate string."); memset (new, 0, sizeof *new); strcpy (new -> string, val); if (cur) { cur -> next = new; cur = new; } else { head = cur = new; } token = next_token (&val, (unsigned *)0, cfile); } while (token == COMMA); if (token != RPAREN) { parse_warn (cfile, "expecting right paren."); badx: skip_to_semi (cfile); *lose = 1; executable_statement_dereference (result, MDL); return 0; } token = next_token (&val, (unsigned *)0, cfile); if (token != LBRACE) { parse_warn (cfile, "expecting left brace."); goto badx; } expr = (struct expression *)0; if (!(expression_allocate (&expr, MDL))) log_fatal ("can't allocate expression."); expr -> op = expr_function; if (!fundef_allocate (&expr -> data.func, MDL)) log_fatal ("can't allocate fundef."); expr -> data.func -> args = head; (*result) -> data.set.expr = expr; if (!(parse_executable_statements (&expr -> data.func -> statements, cfile, lose, case_context))) { if (*lose) goto badx; } token = next_token (&val, (unsigned *)0, cfile); if (token != RBRACE) { parse_warn (cfile, "expecting rigt brace."); goto badx; } } else { if (token != EQUAL) { parse_warn (cfile, "expecting '=' in %s statement.", flag ? "define" : "set"); goto badset; } if (!parse_expression (&(*result) -> data.set.expr, cfile, lose, context_any, (struct expression **)0, expr_none)) { if (!*lose) parse_warn (cfile, "expecting expression."); else *lose = 1; skip_to_semi (cfile); executable_statement_dereference (result, MDL); return 0; } if (!parse_semi (cfile)) { *lose = 1; executable_statement_dereference (result, MDL); return 0; } } break; case UNSET: token = next_token (&val, (unsigned *)0, cfile); token = next_token (&val, (unsigned *)0, cfile); if (token != NAME && token != NUMBER_OR_NAME) { parse_warn (cfile, "%s can't be a variable name", val); skip_to_semi (cfile); *lose = 1; return 0; } if (!executable_statement_allocate (result, MDL)) log_fatal ("no memory for set statement."); (*result) -> op = unset_statement; (*result) -> data.unset = dmalloc (strlen (val) + 1, MDL); if (!(*result)->data.unset) log_fatal ("can't allocate variable name"); strcpy ((*result) -> data.unset, val); if (!parse_semi (cfile)) { *lose = 1; executable_statement_dereference (result, MDL); return 0; } break; case EVAL: token = next_token (&val, (unsigned *)0, cfile); if (!executable_statement_allocate (result, MDL)) log_fatal ("no memory for eval statement."); (*result) -> op = eval_statement; if (!parse_expression (&(*result) -> data.eval, cfile, lose, context_data, /* XXX */ (struct expression **)0, expr_none)) { if (!*lose) parse_warn (cfile, "expecting data expression."); else *lose = 1; skip_to_semi (cfile); executable_statement_dereference (result, MDL); return 0; } if (!parse_semi (cfile)) { *lose = 1; executable_statement_dereference (result, MDL); } break; case EXECUTE: #ifdef ENABLE_EXECUTE token = next_token(&val, NULL, cfile); if (!executable_statement_allocate (result, MDL)) log_fatal ("no memory for execute statement."); (*result)->op = execute_statement; token = next_token(&val, NULL, cfile); if (token != LPAREN) { parse_warn(cfile, "left parenthesis expected."); skip_to_semi(cfile); *lose = 1; return 0; } token = next_token(&val, &len, cfile); if (token != STRING) { parse_warn(cfile, "Expecting a quoted string."); skip_to_semi(cfile); *lose = 1; return 0; } (*result)->data.execute.command = dmalloc(len + 1, MDL); if ((*result)->data.execute.command == NULL) log_fatal("can't allocate command name"); strcpy((*result)->data.execute.command, val); ep = &(*result)->data.execute.arglist; (*result)->data.execute.argc = 0; while((token = next_token(&val, NULL, cfile)) == COMMA) { if (!expression_allocate(ep, MDL)) log_fatal ("can't allocate expression"); if (!parse_data_expression (&(*ep) -> data.arg.val, cfile, lose)) { if (!*lose) { parse_warn (cfile, "expecting expression."); *lose = 1; } skip_to_semi(cfile); *lose = 1; return 0; } ep = &(*ep)->data.arg.next; (*result)->data.execute.argc++; } if (token != RPAREN) { parse_warn(cfile, "right parenthesis expected."); skip_to_semi(cfile); *lose = 1; return 0; } if (!parse_semi (cfile)) { *lose = 1; executable_statement_dereference (result, MDL); } #else /* ! ENABLE_EXECUTE */ parse_warn(cfile, "define ENABLE_EXECUTE in site.h to " "enable execute(); expressions."); skip_to_semi(cfile); *lose = 1; return 0; #endif /* ENABLE_EXECUTE */ break; case RETURN: token = next_token (&val, (unsigned *)0, cfile); if (!executable_statement_allocate (result, MDL)) log_fatal ("no memory for return statement."); (*result) -> op = return_statement; if (!parse_expression (&(*result) -> data.retval, cfile, lose, context_data, (struct expression **)0, expr_none)) { if (!*lose) parse_warn (cfile, "expecting data expression."); else *lose = 1; skip_to_semi (cfile); executable_statement_dereference (result, MDL); return 0; } if (!parse_semi (cfile)) { *lose = 1; executable_statement_dereference (result, MDL); return 0; } break; case LOG: token = next_token (&val, (unsigned *)0, cfile); if (!executable_statement_allocate (result, MDL)) log_fatal ("no memory for log statement."); (*result) -> op = log_statement; token = next_token (&val, (unsigned *)0, cfile); if (token != LPAREN) { parse_warn (cfile, "left parenthesis expected."); skip_to_semi (cfile); *lose = 1; return 0; } token = peek_token (&val, (unsigned *)0, cfile); i = 1; if (token == FATAL) { (*result) -> data.log.priority = log_priority_fatal; } else if (token == ERROR) { (*result) -> data.log.priority = log_priority_error; } else if (token == TOKEN_DEBUG) { (*result) -> data.log.priority = log_priority_debug; } else if (token == INFO) { (*result) -> data.log.priority = log_priority_info; } else { (*result) -> data.log.priority = log_priority_debug; i = 0; } if (i) { token = next_token (&val, (unsigned *)0, cfile); token = next_token (&val, (unsigned *)0, cfile); if (token != COMMA) { parse_warn (cfile, "comma expected."); skip_to_semi (cfile); *lose = 1; return 0; } } if (!(parse_data_expression (&(*result) -> data.log.expr, cfile, lose))) { skip_to_semi (cfile); *lose = 1; return 0; } token = next_token (&val, (unsigned *)0, cfile); if (token != RPAREN) { parse_warn (cfile, "right parenthesis expected."); skip_to_semi (cfile); *lose = 1; return 0; } token = next_token (&val, (unsigned *)0, cfile); if (token != SEMI) { parse_warn (cfile, "semicolon expected."); skip_to_semi (cfile); *lose = 1; return 0; } break; /* Not really a statement, but we parse it here anyway because it's appropriate for all DHCP agents with parsers. */ case ZONE: token = next_token (&val, (unsigned *)0, cfile); zone = (struct dns_zone *)0; if (!dns_zone_allocate (&zone, MDL)) log_fatal ("no memory for new zone."); zone -> name = parse_host_name (cfile); if (!zone -> name) { parse_warn (cfile, "expecting hostname."); badzone: *lose = 1; skip_to_semi (cfile); dns_zone_dereference (&zone, MDL); return 0; } i = strlen (zone -> name); if (zone -> name [i - 1] != '.') { s = dmalloc ((unsigned)i + 2, MDL); if (!s) { parse_warn (cfile, "no trailing '.' on zone"); goto badzone; } strcpy (s, zone -> name); s [i] = '.'; s [i + 1] = 0; dfree (zone -> name, MDL); zone -> name = s; } if (!parse_zone (zone, cfile)) goto badzone; status = enter_dns_zone (zone); if (status != ISC_R_SUCCESS) { parse_warn (cfile, "dns zone key %s: %s", zone -> name, isc_result_totext (status)); dns_zone_dereference (&zone, MDL); return 0; } dns_zone_dereference (&zone, MDL); return 1; /* Also not really a statement, but same idea as above. */ case KEY: token = next_token (&val, (unsigned *)0, cfile); if (!parse_key (cfile)) { *lose = 1; return 0; } return 1; default: if (config_universe && is_identifier (token)) { option = (struct option *)0; option_name_hash_lookup(&option, config_universe->name_hash, val, 0, MDL); if (option) { token = next_token (&val, (unsigned *)0, cfile); status = parse_option_statement (result, cfile, 1, option, supersede_option_statement); option_dereference(&option, MDL); return status; } } if (token == NUMBER_OR_NAME || token == NAME) { /* This is rather ugly. Since function calls are data expressions, fake up an eval statement. */ if (!executable_statement_allocate (result, MDL)) log_fatal ("no memory for eval statement."); (*result) -> op = eval_statement; if (!parse_expression (&(*result) -> data.eval, cfile, lose, context_data, (struct expression **)0, expr_none)) { if (!*lose) parse_warn (cfile, "expecting " "function call."); else *lose = 1; skip_to_semi (cfile); executable_statement_dereference (result, MDL); return 0; } if (!parse_semi (cfile)) { *lose = 1; executable_statement_dereference (result, MDL); return 0; } break; } *lose = 0; return 0; } return 1; } /* zone-statements :== zone-statement | zone-statement zone-statements zone-statement :== PRIMARY ip-addresses SEMI | SECONDARY ip-addresses SEMI | PRIMARY6 ip-address6 SEMI | SECONDARY6 ip-address6 SEMI | key-reference SEMI ip-addresses :== ip-addr-or-hostname | ip-addr-or-hostname COMMA ip-addresses key-reference :== KEY STRING | KEY identifier */ int parse_zone (struct dns_zone *zone, struct parse *cfile) { int token; const char *val; char *key_name; struct option_cache *oc; int done = 0; token = next_token (&val, (unsigned *)0, cfile); if (token != LBRACE) { parse_warn (cfile, "expecting left brace"); return 0; } do { token = peek_token (&val, (unsigned *)0, cfile); switch (token) { case PRIMARY: if (zone -> primary) { parse_warn (cfile, "more than one primary."); skip_to_semi (cfile); return 0; } if (!option_cache_allocate (&zone -> primary, MDL)) log_fatal ("can't allocate primary option cache."); oc = zone -> primary; goto consemup; case SECONDARY: if (zone -> secondary) { parse_warn (cfile, "more than one secondary."); skip_to_semi (cfile); return 0; } if (!option_cache_allocate (&zone -> secondary, MDL)) log_fatal ("can't allocate secondary."); oc = zone -> secondary; consemup: token = next_token (&val, (unsigned *)0, cfile); do { struct expression *expr = (struct expression *)0; if (!parse_ip_addr_or_hostname (&expr, cfile, 0)) { parse_warn (cfile, "expecting IP addr or hostname."); skip_to_semi (cfile); return 0; } if (oc -> expression) { struct expression *old = (struct expression *)0; expression_reference (&old, oc -> expression, MDL); expression_dereference (&oc -> expression, MDL); if (!make_concat (&oc -> expression, old, expr)) log_fatal ("no memory for concat."); expression_dereference (&expr, MDL); expression_dereference (&old, MDL); } else { expression_reference (&oc -> expression, expr, MDL); expression_dereference (&expr, MDL); } token = next_token (&val, (unsigned *)0, cfile); } while (token == COMMA); if (token != SEMI) { parse_warn (cfile, "expecting semicolon."); skip_to_semi (cfile); return 0; } break; case PRIMARY6: if (zone->primary6) { parse_warn(cfile, "more than one primary6."); skip_to_semi(cfile); return (0); } if (!option_cache_allocate (&zone->primary6, MDL)) log_fatal("can't allocate primary6 option cache."); oc = zone->primary6; goto consemup6; case SECONDARY6: if (zone->secondary6) { parse_warn(cfile, "more than one secondary6."); skip_to_semi(cfile); return (0); } if (!option_cache_allocate (&zone->secondary6, MDL)) log_fatal("can't allocate secondary6 " "option cache."); oc = zone->secondary6; consemup6: token = next_token(&val, NULL, cfile); do { struct expression *expr = NULL; if (parse_ip6_addr_expr(&expr, cfile) == 0) { parse_warn(cfile, "expecting IPv6 addr."); skip_to_semi(cfile); return (0); } if (oc->expression) { struct expression *old = NULL; expression_reference(&old, oc->expression, MDL); expression_dereference(&oc->expression, MDL); if (!make_concat(&oc->expression, old, expr)) log_fatal("no memory for concat."); expression_dereference(&expr, MDL); expression_dereference(&old, MDL); } else { expression_reference(&oc->expression, expr, MDL); expression_dereference(&expr, MDL); } token = next_token(&val, NULL, cfile); } while (token == COMMA); if (token != SEMI) { parse_warn(cfile, "expecting semicolon."); skip_to_semi(cfile); return (0); } break; case KEY: token = next_token (&val, (unsigned *)0, cfile); token = peek_token (&val, (unsigned *)0, cfile); if (token == STRING) { token = next_token (&val, (unsigned *)0, cfile); key_name = (char *)0; } else { key_name = parse_host_name (cfile); if (!key_name) { parse_warn (cfile, "expecting key name."); skip_to_semi (cfile); return 0; } val = key_name; } if (omapi_auth_key_lookup_name (&zone -> key, val) != ISC_R_SUCCESS) parse_warn (cfile, "unknown key %s", val); if (key_name) dfree (key_name, MDL); if (!parse_semi (cfile)) return 0; break; default: done = 1; break; } } while (!done); token = next_token (&val, (unsigned *)0, cfile); if (token != RBRACE) { parse_warn (cfile, "expecting right brace."); return 0; } return 1; } /* key-statements :== key-statement | key-statement key-statements key-statement :== ALGORITHM host-name SEMI | secret-definition SEMI secret-definition :== SECRET base64val | SECRET STRING */ int parse_key (struct parse *cfile) { int token; const char *val; int done = 0; struct auth_key *key; struct data_string ds; isc_result_t status; char *s; key = (struct auth_key *)0; if (omapi_auth_key_new (&key, MDL) != ISC_R_SUCCESS) log_fatal ("no memory for key"); token = peek_token (&val, (unsigned *)0, cfile); if (token == STRING) { token = next_token (&val, (unsigned *)0, cfile); key -> name = dmalloc (strlen (val) + 1, MDL); if (!key -> name) log_fatal ("no memory for key name."); strcpy (key -> name, val); } else { key -> name = parse_host_name (cfile); if (!key -> name) { parse_warn (cfile, "expecting key name."); skip_to_semi (cfile); goto bad; } } token = next_token (&val, (unsigned *)0, cfile); if (token != LBRACE) { parse_warn (cfile, "expecting left brace"); goto bad; } do { token = next_token (&val, (unsigned *)0, cfile); switch (token) { case ALGORITHM: if (key -> algorithm) { parse_warn (cfile, "key %s: too many algorithms", key -> name); goto rbad; } key -> algorithm = parse_host_name (cfile); if (!key -> algorithm) { parse_warn (cfile, "expecting key algorithm name."); goto rbad; } if (!parse_semi (cfile)) goto rbad; /* If the algorithm name isn't an FQDN, tack on the .SIG-ALG.REG.NET. domain. */ s = strrchr (key -> algorithm, '.'); if (!s) { static char add [] = ".SIG-ALG.REG.INT."; s = dmalloc (strlen (key -> algorithm) + sizeof (add), MDL); if (!s) { log_error ("no memory for key %s.", "algorithm"); goto rbad; } strcpy (s, key -> algorithm); strcat (s, add); dfree (key -> algorithm, MDL); key -> algorithm = s; } else if (s [1]) { /* If there is no trailing '.', hack one in. */ s = dmalloc (strlen (key -> algorithm) + 2, MDL); if (!s) { log_error ("no memory for key %s.", key -> algorithm); goto rbad; } strcpy (s, key -> algorithm); strcat (s, "."); dfree (key -> algorithm, MDL); key -> algorithm = s; } break; case SECRET: if (key -> key) { parse_warn (cfile, "key %s: too many secrets", key -> name); goto rbad; } memset (&ds, 0, sizeof(ds)); if (!parse_base64 (&ds, cfile)) goto rbad; status = omapi_data_string_new (&key -> key, ds.len, MDL); if (status != ISC_R_SUCCESS) goto rbad; memcpy (key -> key -> value, ds.buffer -> data, ds.len); data_string_forget (&ds, MDL); if (!parse_semi (cfile)) goto rbad; break; default: done = 1; break; } } while (!done); if (token != RBRACE) { parse_warn (cfile, "expecting right brace."); goto rbad; } /* Allow the BIND 8 syntax, which has a semicolon after each closing brace. */ token = peek_token (&val, (unsigned *)0, cfile); if (token == SEMI) token = next_token (&val, (unsigned *)0, cfile); /* Remember the key. */ status = omapi_auth_key_enter (key); if (status != ISC_R_SUCCESS) { parse_warn (cfile, "tsig key %s: %s", key -> name, isc_result_totext (status)); goto bad; } omapi_auth_key_dereference (&key, MDL); return 1; rbad: skip_to_rbrace (cfile, 1); bad: omapi_auth_key_dereference (&key, MDL); return 0; } /* * on-statement :== event-types LBRACE executable-statements RBRACE * event-types :== event-type OR event-types | * event-type * event-type :== EXPIRY | COMMIT | RELEASE */ int parse_on_statement (result, cfile, lose) struct executable_statement **result; struct parse *cfile; int *lose; { enum dhcp_token token; const char *val; if (!executable_statement_allocate (result, MDL)) log_fatal ("no memory for new statement."); (*result) -> op = on_statement; do { token = next_token (&val, (unsigned *)0, cfile); switch (token) { case EXPIRY: (*result) -> data.on.evtypes |= ON_EXPIRY; break; case COMMIT: (*result) -> data.on.evtypes |= ON_COMMIT; break; case RELEASE: (*result) -> data.on.evtypes |= ON_RELEASE; break; case TRANSMISSION: (*result) -> data.on.evtypes |= ON_TRANSMISSION; break; default: parse_warn (cfile, "expecting a lease event type"); skip_to_semi (cfile); *lose = 1; executable_statement_dereference (result, MDL); return 0; } token = next_token (&val, (unsigned *)0, cfile); } while (token == OR); /* Semicolon means no statements. */ if (token == SEMI) return 1; if (token != LBRACE) { parse_warn (cfile, "left brace expected."); skip_to_semi (cfile); *lose = 1; executable_statement_dereference (result, MDL); return 0; } if (!parse_executable_statements (&(*result) -> data.on.statements, cfile, lose, context_any)) { if (*lose) { /* Try to even things up. */ do { token = next_token (&val, (unsigned *)0, cfile); } while (token != END_OF_FILE && token != RBRACE); executable_statement_dereference (result, MDL); return 0; } } token = next_token (&val, (unsigned *)0, cfile); if (token != RBRACE) { parse_warn (cfile, "right brace expected."); skip_to_semi (cfile); *lose = 1; executable_statement_dereference (result, MDL); return 0; } return 1; } /* * switch-statement :== LPAREN expr RPAREN LBRACE executable-statements RBRACE * */ int parse_switch_statement (result, cfile, lose) struct executable_statement **result; struct parse *cfile; int *lose; { enum dhcp_token token; const char *val; if (!executable_statement_allocate (result, MDL)) log_fatal ("no memory for new statement."); (*result) -> op = switch_statement; token = next_token (&val, (unsigned *)0, cfile); if (token != LPAREN) { parse_warn (cfile, "expecting left brace."); pfui: *lose = 1; skip_to_semi (cfile); gnorf: executable_statement_dereference (result, MDL); return 0; } if (!parse_expression (&(*result) -> data.s_switch.expr, cfile, lose, context_data_or_numeric, (struct expression **)0, expr_none)) { if (!*lose) { parse_warn (cfile, "expecting data or numeric expression."); goto pfui; } goto gnorf; } token = next_token (&val, (unsigned *)0, cfile); if (token != RPAREN) { parse_warn (cfile, "right paren expected."); goto pfui; } token = next_token (&val, (unsigned *)0, cfile); if (token != LBRACE) { parse_warn (cfile, "left brace expected."); goto pfui; } if (!(parse_executable_statements (&(*result) -> data.s_switch.statements, cfile, lose, (is_data_expression ((*result) -> data.s_switch.expr) ? context_data : context_numeric)))) { if (*lose) { skip_to_rbrace (cfile, 1); executable_statement_dereference (result, MDL); return 0; } } token = next_token (&val, (unsigned *)0, cfile); if (token != RBRACE) { parse_warn (cfile, "right brace expected."); goto pfui; } return 1; } /* * case-statement :== CASE expr COLON * */ int parse_case_statement (result, cfile, lose, case_context) struct executable_statement **result; struct parse *cfile; int *lose; enum expression_context case_context; { enum dhcp_token token; const char *val; if (!executable_statement_allocate (result, MDL)) log_fatal ("no memory for new statement."); (*result) -> op = case_statement; if (!parse_expression (&(*result) -> data.c_case, cfile, lose, case_context, (struct expression **)0, expr_none)) { if (!*lose) { parse_warn (cfile, "expecting %s expression.", (case_context == context_data ? "data" : "numeric")); } pfui: *lose = 1; skip_to_semi (cfile); executable_statement_dereference (result, MDL); return 0; } token = next_token (&val, (unsigned *)0, cfile); if (token != COLON) { parse_warn (cfile, "colon expected."); goto pfui; } return 1; } /* * if-statement :== boolean-expression LBRACE executable-statements RBRACE * else-statement * * else-statement :== | * ELSE LBRACE executable-statements RBRACE | * ELSE IF if-statement | * ELSIF if-statement */ int parse_if_statement (result, cfile, lose) struct executable_statement **result; struct parse *cfile; int *lose; { enum dhcp_token token; const char *val; int parenp; if (!executable_statement_allocate (result, MDL)) log_fatal ("no memory for if statement."); (*result) -> op = if_statement; token = peek_token (&val, (unsigned *)0, cfile); if (token == LPAREN) { parenp = 1; next_token (&val, (unsigned *)0, cfile); } else parenp = 0; if (!parse_boolean_expression (&(*result) -> data.ie.expr, cfile, lose)) { if (!*lose) parse_warn (cfile, "boolean expression expected."); executable_statement_dereference (result, MDL); *lose = 1; return 0; } #if defined (DEBUG_EXPRESSION_PARSE) print_expression ("if condition", (*result) -> data.ie.expr); #endif if (parenp) { token = next_token (&val, (unsigned *)0, cfile); if (token != RPAREN) { parse_warn (cfile, "expecting right paren."); *lose = 1; executable_statement_dereference (result, MDL); return 0; } } token = next_token (&val, (unsigned *)0, cfile); if (token != LBRACE) { parse_warn (cfile, "left brace expected."); skip_to_semi (cfile); *lose = 1; executable_statement_dereference (result, MDL); return 0; } if (!parse_executable_statements (&(*result) -> data.ie.tc, cfile, lose, context_any)) { if (*lose) { /* Try to even things up. */ do { token = next_token (&val, (unsigned *)0, cfile); } while (token != END_OF_FILE && token != RBRACE); executable_statement_dereference (result, MDL); return 0; } } token = next_token (&val, (unsigned *)0, cfile); if (token != RBRACE) { parse_warn (cfile, "right brace expected."); skip_to_semi (cfile); *lose = 1; executable_statement_dereference (result, MDL); return 0; } token = peek_token (&val, (unsigned *)0, cfile); if (token == ELSE) { token = next_token (&val, (unsigned *)0, cfile); token = peek_token (&val, (unsigned *)0, cfile); if (token == IF) { token = next_token (&val, (unsigned *)0, cfile); if (!parse_if_statement (&(*result) -> data.ie.fc, cfile, lose)) { if (!*lose) parse_warn (cfile, "expecting if statement"); executable_statement_dereference (result, MDL); *lose = 1; return 0; } } else if (token != LBRACE) { parse_warn (cfile, "left brace or if expected."); skip_to_semi (cfile); *lose = 1; executable_statement_dereference (result, MDL); return 0; } else { token = next_token (&val, (unsigned *)0, cfile); if (!(parse_executable_statements (&(*result) -> data.ie.fc, cfile, lose, context_any))) { executable_statement_dereference (result, MDL); return 0; } token = next_token (&val, (unsigned *)0, cfile); if (token != RBRACE) { parse_warn (cfile, "right brace expected."); skip_to_semi (cfile); *lose = 1; executable_statement_dereference (result, MDL); return 0; } } } else if (token == ELSIF) { token = next_token (&val, (unsigned *)0, cfile); if (!parse_if_statement (&(*result) -> data.ie.fc, cfile, lose)) { if (!*lose) parse_warn (cfile, "expecting conditional."); executable_statement_dereference (result, MDL); *lose = 1; return 0; } } else (*result) -> data.ie.fc = (struct executable_statement *)0; return 1; } /* * boolean_expression :== CHECK STRING | * NOT boolean-expression | * data-expression EQUAL data-expression | * data-expression BANG EQUAL data-expression | * data-expression REGEX_MATCH data-expression | * boolean-expression AND boolean-expression | * boolean-expression OR boolean-expression * EXISTS OPTION-NAME */ int parse_boolean_expression (expr, cfile, lose) struct expression **expr; struct parse *cfile; int *lose; { /* Parse an expression... */ if (!parse_expression (expr, cfile, lose, context_boolean, (struct expression **)0, expr_none)) return 0; if (!is_boolean_expression (*expr) && (*expr) -> op != expr_variable_reference && (*expr) -> op != expr_funcall) { parse_warn (cfile, "Expecting a boolean expression."); *lose = 1; expression_dereference (expr, MDL); return 0; } return 1; } /* boolean :== ON SEMI | OFF SEMI | TRUE SEMI | FALSE SEMI */ int parse_boolean (cfile) struct parse *cfile; { const char *val; int rv; (void)next_token(&val, NULL, cfile); if (!strcasecmp (val, "true") || !strcasecmp (val, "on")) rv = 1; else if (!strcasecmp (val, "false") || !strcasecmp (val, "off")) rv = 0; else { parse_warn (cfile, "boolean value (true/false/on/off) expected"); skip_to_semi (cfile); return 0; } parse_semi (cfile); return rv; } /* * data_expression :== SUBSTRING LPAREN data-expression COMMA * numeric-expression COMMA * numeric-expression RPAREN | * CONCAT LPAREN data-expression COMMA * data-expression RPAREN * SUFFIX LPAREN data_expression COMMA * numeric-expression RPAREN | * LCASE LPAREN data_expression RPAREN | * UCASE LPAREN data_expression RPAREN | * OPTION option_name | * HARDWARE | * PACKET LPAREN numeric-expression COMMA * numeric-expression RPAREN | * STRING | * colon_separated_hex_list */ int parse_data_expression (expr, cfile, lose) struct expression **expr; struct parse *cfile; int *lose; { /* Parse an expression... */ if (!parse_expression (expr, cfile, lose, context_data, (struct expression **)0, expr_none)) return 0; if (!is_data_expression (*expr) && (*expr) -> op != expr_variable_reference && (*expr) -> op != expr_funcall) { expression_dereference (expr, MDL); parse_warn (cfile, "Expecting a data expression."); *lose = 1; return 0; } return 1; } /* * numeric-expression :== EXTRACT_INT LPAREN data-expression * COMMA number RPAREN | * NUMBER */ int parse_numeric_expression (expr, cfile, lose) struct expression **expr; struct parse *cfile; int *lose; { /* Parse an expression... */ if (!parse_expression (expr, cfile, lose, context_numeric, (struct expression **)0, expr_none)) return 0; if (!is_numeric_expression (*expr) && (*expr) -> op != expr_variable_reference && (*expr) -> op != expr_funcall) { expression_dereference (expr, MDL); parse_warn (cfile, "Expecting a numeric expression."); *lose = 1; return 0; } return 1; } #if defined (NSUPDATE_OLD) /* * dns-expression :== * UPDATE LPAREN ns-class COMMA ns-type COMMA data-expression COMMA * data-expression COMMA numeric-expression RPAREN * DELETE LPAREN ns-class COMMA ns-type COMMA data-expression COMMA * data-expression RPAREN * EXISTS LPAREN ns-class COMMA ns-type COMMA data-expression COMMA * data-expression RPAREN * NOT EXISTS LPAREN ns-class COMMA ns-type COMMA data-expression COMMA * data-expression RPAREN * ns-class :== IN | CHAOS | HS | NUMBER * ns-type :== A | PTR | MX | TXT | NUMBER */ int parse_dns_expression (expr, cfile, lose) struct expression **expr; struct parse *cfile; int *lose; { /* Parse an expression... */ if (!parse_expression (expr, cfile, lose, context_dns, (struct expression **)0, expr_none)) return 0; if (!is_dns_expression (*expr) && (*expr) -> op != expr_variable_reference && (*expr) -> op != expr_funcall) { expression_dereference (expr, MDL); parse_warn (cfile, "Expecting a dns update subexpression."); *lose = 1; return 0; } return 1; } #endif /* NSUPDATE_OLD */ /* Parse a subexpression that does not contain a binary operator. */ int parse_non_binary (expr, cfile, lose, context) struct expression **expr; struct parse *cfile; int *lose; enum expression_context context; { enum dhcp_token token; const char *val; struct collection *col; struct expression *nexp, **ep; int known; char *cptr; #if defined (NSUPDATE_OLD) enum expr_op opcode; const char *s; unsigned long u; #endif isc_result_t status; unsigned len; token = peek_token (&val, (unsigned *)0, cfile); /* Check for unary operators... */ switch (token) { case CHECK: token = next_token (&val, (unsigned *)0, cfile); token = next_token (&val, (unsigned *)0, cfile); if (token != STRING) { parse_warn (cfile, "string expected."); skip_to_semi (cfile); *lose = 1; return 0; } for (col = collections; col; col = col -> next) if (!strcmp (col -> name, val)) break; if (!col) { parse_warn (cfile, "unknown collection."); *lose = 1; return 0; } if (!expression_allocate (expr, MDL)) log_fatal ("can't allocate expression"); (*expr) -> op = expr_check; (*expr) -> data.check = col; break; case TOKEN_NOT: token = next_token (&val, (unsigned *)0, cfile); #if defined(NSUPDATE_OLD) if (context == context_dns) { token = peek_token (&val, (unsigned *)0, cfile); goto not_exists; } #endif if (!expression_allocate (expr, MDL)) log_fatal ("can't allocate expression"); (*expr) -> op = expr_not; if (!parse_non_binary (&(*expr) -> data.not, cfile, lose, context_boolean)) { if (!*lose) { parse_warn (cfile, "expression expected"); skip_to_semi (cfile); } *lose = 1; expression_dereference (expr, MDL); return 0; } if (!is_boolean_expression ((*expr) -> data.not)) { *lose = 1; parse_warn (cfile, "boolean expression expected"); skip_to_semi (cfile); expression_dereference (expr, MDL); return 0; } break; case LPAREN: token = next_token (&val, (unsigned *)0, cfile); if (!parse_expression (expr, cfile, lose, context, (struct expression **)0, expr_none)) { if (!*lose) { parse_warn (cfile, "expression expected"); skip_to_semi (cfile); } *lose = 1; return 0; } token = next_token (&val, (unsigned *)0, cfile); if (token != RPAREN) { *lose = 1; parse_warn (cfile, "right paren expected"); skip_to_semi (cfile); return 0; } break; case EXISTS: #if defined(NSUPDATE_OLD) if (context == context_dns) goto ns_exists; #endif token = next_token (&val, (unsigned *)0, cfile); if (!expression_allocate (expr, MDL)) log_fatal ("can't allocate expression"); (*expr) -> op = expr_exists; known = 0; /* Pass reference directly to expression structure. */ status = parse_option_name(cfile, 0, &known, &(*expr)->data.option); if (status != ISC_R_SUCCESS || (*expr)->data.option == NULL) { *lose = 1; expression_dereference (expr, MDL); return 0; } break; case STATIC: token = next_token (&val, (unsigned *)0, cfile); if (!expression_allocate (expr, MDL)) log_fatal ("can't allocate expression"); (*expr) -> op = expr_static; break; case KNOWN: token = next_token (&val, (unsigned *)0, cfile); if (!expression_allocate (expr, MDL)) log_fatal ("can't allocate expression"); (*expr) -> op = expr_known; break; case SUBSTRING: token = next_token (&val, (unsigned *)0, cfile); if (!expression_allocate (expr, MDL)) log_fatal ("can't allocate expression"); (*expr) -> op = expr_substring; token = next_token (&val, (unsigned *)0, cfile); if (token != LPAREN) { nolparen: expression_dereference (expr, MDL); parse_warn (cfile, "left parenthesis expected."); *lose = 1; return 0; } if (!parse_data_expression (&(*expr) -> data.substring.expr, cfile, lose)) { nodata: expression_dereference (expr, MDL); if (!*lose) { parse_warn (cfile, "expecting data expression."); skip_to_semi (cfile); *lose = 1; } return 0; } token = next_token (&val, (unsigned *)0, cfile); if (token != COMMA) { nocomma: expression_dereference (expr, MDL); parse_warn (cfile, "comma expected."); *lose = 1; return 0; } if (!parse_numeric_expression (&(*expr) -> data.substring.offset,cfile, lose)) { nonum: if (!*lose) { parse_warn (cfile, "expecting numeric expression."); skip_to_semi (cfile); *lose = 1; } expression_dereference (expr, MDL); return 0; } token = next_token (&val, (unsigned *)0, cfile); if (token != COMMA) goto nocomma; if (!parse_numeric_expression (&(*expr) -> data.substring.len, cfile, lose)) goto nonum; token = next_token (&val, (unsigned *)0, cfile); if (token != RPAREN) { norparen: parse_warn (cfile, "right parenthesis expected."); *lose = 1; expression_dereference (expr, MDL); return 0; } break; case SUFFIX: token = next_token (&val, (unsigned *)0, cfile); if (!expression_allocate (expr, MDL)) log_fatal ("can't allocate expression"); (*expr) -> op = expr_suffix; token = next_token (&val, (unsigned *)0, cfile); if (token != LPAREN) goto nolparen; if (!parse_data_expression (&(*expr) -> data.suffix.expr, cfile, lose)) goto nodata; token = next_token (&val, (unsigned *)0, cfile); if (token != COMMA) goto nocomma; if (!parse_numeric_expression (&(*expr) -> data.suffix.len, cfile, lose)) goto nonum; token = next_token (&val, (unsigned *)0, cfile); if (token != RPAREN) goto norparen; break; case LCASE: token = next_token(&val, (unsigned *)0, cfile); if (!expression_allocate(expr, MDL)) log_fatal ("can't allocate expression"); (*expr)->op = expr_lcase; token = next_token(&val, (unsigned *)0, cfile); if (token != LPAREN) goto nolparen; if (!parse_data_expression(&(*expr)->data.lcase, cfile, lose)) goto nodata; token = next_token(&val, (unsigned *)0, cfile); if (token != RPAREN) goto norparen; break; case UCASE: token = next_token(&val, (unsigned *)0, cfile); if (!expression_allocate(expr, MDL)) log_fatal ("can't allocate expression"); (*expr)->op = expr_ucase; token = next_token (&val, (unsigned *)0, cfile); if (token != LPAREN) goto nolparen; if (!parse_data_expression(&(*expr)->data.ucase, cfile, lose)) goto nodata; token = next_token(&val, (unsigned *)0, cfile); if (token != RPAREN) goto norparen; break; case CONCAT: token = next_token (&val, (unsigned *)0, cfile); if (!expression_allocate (expr, MDL)) log_fatal ("can't allocate expression"); (*expr) -> op = expr_concat; token = next_token (&val, (unsigned *)0, cfile); if (token != LPAREN) goto nolparen; if (!parse_data_expression (&(*expr) -> data.concat [0], cfile, lose)) goto nodata; token = next_token (&val, (unsigned *)0, cfile); if (token != COMMA) goto nocomma; concat_another: if (!parse_data_expression (&(*expr) -> data.concat [1], cfile, lose)) goto nodata; token = next_token (&val, (unsigned *)0, cfile); if (token == COMMA) { nexp = (struct expression *)0; if (!expression_allocate (&nexp, MDL)) log_fatal ("can't allocate at CONCAT2"); nexp -> op = expr_concat; expression_reference (&nexp -> data.concat [0], *expr, MDL); expression_dereference (expr, MDL); expression_reference (expr, nexp, MDL); expression_dereference (&nexp, MDL); goto concat_another; } if (token != RPAREN) goto norparen; break; case BINARY_TO_ASCII: token = next_token (&val, (unsigned *)0, cfile); if (!expression_allocate (expr, MDL)) log_fatal ("can't allocate expression"); (*expr) -> op = expr_binary_to_ascii; token = next_token (&val, (unsigned *)0, cfile); if (token != LPAREN) goto nolparen; if (!parse_numeric_expression (&(*expr) -> data.b2a.base, cfile, lose)) goto nodata; token = next_token (&val, (unsigned *)0, cfile); if (token != COMMA) goto nocomma; if (!parse_numeric_expression (&(*expr) -> data.b2a.width, cfile, lose)) goto nodata; token = next_token (&val, (unsigned *)0, cfile); if (token != COMMA) goto nocomma; if (!parse_data_expression (&(*expr) -> data.b2a.separator, cfile, lose)) goto nodata; token = next_token (&val, (unsigned *)0, cfile); if (token != COMMA) goto nocomma; if (!parse_data_expression (&(*expr) -> data.b2a.buffer, cfile, lose)) goto nodata; token = next_token (&val, (unsigned *)0, cfile); if (token != RPAREN) goto norparen; break; case REVERSE: token = next_token (&val, (unsigned *)0, cfile); if (!expression_allocate (expr, MDL)) log_fatal ("can't allocate expression"); (*expr) -> op = expr_reverse; token = next_token (&val, (unsigned *)0, cfile); if (token != LPAREN) goto nolparen; if (!(parse_numeric_expression (&(*expr) -> data.reverse.width, cfile, lose))) goto nodata; token = next_token (&val, (unsigned *)0, cfile); if (token != COMMA) goto nocomma; if (!(parse_data_expression (&(*expr) -> data.reverse.buffer, cfile, lose))) goto nodata; token = next_token (&val, (unsigned *)0, cfile); if (token != RPAREN) goto norparen; break; case PICK: /* pick (a, b, c) actually produces an internal representation that looks like pick (a, pick (b, pick (c, nil))). */ token = next_token (&val, (unsigned *)0, cfile); if (!(expression_allocate (expr, MDL))) log_fatal ("can't allocate expression"); token = next_token (&val, (unsigned *)0, cfile); if (token != LPAREN) goto nolparen; nexp = (struct expression *)0; expression_reference (&nexp, *expr, MDL); do { nexp -> op = expr_pick_first_value; if (!(parse_data_expression (&nexp -> data.pick_first_value.car, cfile, lose))) goto nodata; token = next_token (&val, (unsigned *)0, cfile); if (token == COMMA) { struct expression *foo = (struct expression *)0; if (!expression_allocate (&foo, MDL)) log_fatal ("can't allocate expr"); expression_reference (&nexp -> data.pick_first_value.cdr, foo, MDL); expression_dereference (&nexp, MDL); expression_reference (&nexp, foo, MDL); expression_dereference (&foo, MDL); } } while (token == COMMA); expression_dereference (&nexp, MDL); if (token != RPAREN) goto norparen; break; #if defined(NSUPDATE_OLD) /* dns-update and dns-delete are present for historical purposes, but are deprecated in favor of ns-update in combination with update, delete, exists and not exists. */ case DNS_UPDATE: case DNS_DELETE: #if !defined (NSUPDATE) parse_warn (cfile, "Please rebuild dhcpd with --with-nsupdate."); #endif token = next_token (&val, (unsigned *)0, cfile); if (token == DNS_UPDATE) opcode = expr_ns_add; else opcode = expr_ns_delete; token = next_token (&val, (unsigned *)0, cfile); if (token != LPAREN) goto nolparen; token = next_token (&val, (unsigned *)0, cfile); if (token != STRING) { parse_warn (cfile, "parse_expression: expecting string."); badnsupdate: skip_to_semi (cfile); *lose = 1; return 0; } if (!strcasecmp (val, "a")) u = T_A; else if (!strcasecmp (val, "aaaa")) u = T_AAAA; else if (!strcasecmp (val, "ptr")) u = T_PTR; else if (!strcasecmp (val, "mx")) u = T_MX; else if (!strcasecmp (val, "cname")) u = T_CNAME; else if (!strcasecmp (val, "TXT")) u = T_TXT; else { parse_warn (cfile, "unexpected rrtype: %s", val); goto badnsupdate; } s = (opcode == expr_ns_add ? "old-dns-update" : "old-dns-delete"); cptr = dmalloc (strlen (s) + 1, MDL); if (!cptr) log_fatal ("can't allocate name for %s", s); strcpy (cptr, s); if (!expression_allocate (expr, MDL)) log_fatal ("can't allocate expression"); (*expr) -> op = expr_funcall; (*expr) -> data.funcall.name = cptr; /* Fake up a function call. */ ep = &(*expr) -> data.funcall.arglist; if (!expression_allocate (ep, MDL)) log_fatal ("can't allocate expression"); (*ep) -> op = expr_arg; if (!make_const_int (&(*ep) -> data.arg.val, u)) log_fatal ("can't allocate rrtype value."); token = next_token (&val, (unsigned *)0, cfile); if (token != COMMA) goto nocomma; ep = &((*ep) -> data.arg.next); if (!expression_allocate (ep, MDL)) log_fatal ("can't allocate expression"); (*ep) -> op = expr_arg; if (!(parse_data_expression (&(*ep) -> data.arg.val, cfile, lose))) goto nodata; token = next_token (&val, (unsigned *)0, cfile); if (token != COMMA) goto nocomma; ep = &((*ep) -> data.arg.next); if (!expression_allocate (ep, MDL)) log_fatal ("can't allocate expression"); (*ep) -> op = expr_arg; if (!(parse_data_expression (&(*ep) -> data.arg.val, cfile, lose))) goto nodata; if (opcode == expr_ns_add) { token = next_token (&val, (unsigned *)0, cfile); if (token != COMMA) goto nocomma; ep = &((*ep) -> data.arg.next); if (!expression_allocate (ep, MDL)) log_fatal ("can't allocate expression"); (*ep) -> op = expr_arg; if (!(parse_numeric_expression (&(*ep) -> data.arg.val, cfile, lose))) { parse_warn (cfile, "expecting numeric expression."); goto badnsupdate; } } token = next_token (&val, (unsigned *)0, cfile); if (token != RPAREN) goto norparen; break; case NS_UPDATE: #if !defined (NSUPDATE) parse_warn (cfile, "Please rebuild dhcpd with --with-nsupdate."); #endif token = next_token (&val, (unsigned *)0, cfile); if (!expression_allocate (expr, MDL)) log_fatal ("can't allocate expression"); token = next_token (&val, (unsigned *)0, cfile); if (token != LPAREN) goto nolparen; nexp = *expr; do { nexp -> op = expr_dns_transaction; if (!(parse_dns_expression (&nexp -> data.dns_transaction.car, cfile, lose))) { if (!*lose) parse_warn (cfile, "expecting dns expression."); expression_dereference (expr, MDL); *lose = 1; return 0; } token = next_token (&val, (unsigned *)0, cfile); if (token == COMMA) { if (!(expression_allocate (&nexp -> data.dns_transaction.cdr, MDL))) log_fatal ("can't allocate expression"); nexp = nexp -> data.dns_transaction.cdr; } } while (token == COMMA); if (token != RPAREN) goto norparen; break; /* NOT EXISTS is special cased above... */ not_exists: token = peek_token (&val, (unsigned *)0, cfile); if (token != EXISTS) { parse_warn (cfile, "expecting DNS prerequisite."); *lose = 1; return 0; } opcode = expr_ns_not_exists; goto nsupdatecode; case TOKEN_ADD: opcode = expr_ns_add; goto nsupdatecode; case TOKEN_DELETE: opcode = expr_ns_delete; goto nsupdatecode; ns_exists: opcode = expr_ns_exists; nsupdatecode: token = next_token (&val, (unsigned *)0, cfile); #if !defined (NSUPDATE) parse_warn (cfile, "Please rebuild dhcpd with --with-nsupdate."); #endif if (!expression_allocate (expr, MDL)) log_fatal ("can't allocate expression"); (*expr) -> op = opcode; token = next_token (&val, (unsigned *)0, cfile); if (token != LPAREN) goto nolparen; token = next_token (&val, (unsigned *)0, cfile); if (!is_identifier (token) && token != NUMBER) { parse_warn (cfile, "expecting identifier or number."); badnsop: expression_dereference (expr, MDL); skip_to_semi (cfile); *lose = 1; return 0; } if (token == NUMBER) (*expr) -> data.ns_add.rrclass = atoi (val); else if (!strcasecmp (val, "in")) (*expr) -> data.ns_add.rrclass = C_IN; else if (!strcasecmp (val, "chaos")) (*expr) -> data.ns_add.rrclass = C_CHAOS; else if (!strcasecmp (val, "hs")) (*expr) -> data.ns_add.rrclass = C_HS; else { parse_warn (cfile, "unexpected rrclass: %s", val); goto badnsop; } token = next_token (&val, (unsigned *)0, cfile); if (token != COMMA) goto nocomma; token = next_token (&val, (unsigned *)0, cfile); if (!is_identifier (token) && token != NUMBER) { parse_warn (cfile, "expecting identifier or number."); goto badnsop; } if (token == NUMBER) (*expr) -> data.ns_add.rrtype = atoi (val); else if (!strcasecmp (val, "a")) (*expr) -> data.ns_add.rrtype = T_A; else if (!strcasecmp (val, "aaaa")) (*expr) -> data.ns_add.rrtype = T_AAAA; else if (!strcasecmp (val, "ptr")) (*expr) -> data.ns_add.rrtype = T_PTR; else if (!strcasecmp (val, "mx")) (*expr) -> data.ns_add.rrtype = T_MX; else if (!strcasecmp (val, "cname")) (*expr) -> data.ns_add.rrtype = T_CNAME; else if (!strcasecmp (val, "TXT")) (*expr) -> data.ns_add.rrtype = T_TXT; else { parse_warn (cfile, "unexpected rrtype: %s", val); goto badnsop; } token = next_token (&val, (unsigned *)0, cfile); if (token != COMMA) goto nocomma; if (!(parse_data_expression (&(*expr) -> data.ns_add.rrname, cfile, lose))) goto nodata; token = next_token (&val, (unsigned *)0, cfile); if (token != COMMA) goto nocomma; if (!(parse_data_expression (&(*expr) -> data.ns_add.rrdata, cfile, lose))) goto nodata; if (opcode == expr_ns_add) { token = next_token (&val, (unsigned *)0, cfile); if (token != COMMA) goto nocomma; if (!(parse_numeric_expression (&(*expr) -> data.ns_add.ttl, cfile, lose))) { if (!*lose) parse_warn (cfile, "expecting numeric expression."); goto badnsupdate; } } token = next_token (&val, (unsigned *)0, cfile); if (token != RPAREN) goto norparen; break; #endif /* NSUPDATE_OLD */ case OPTION: case CONFIG_OPTION: if (!expression_allocate (expr, MDL)) log_fatal ("can't allocate expression"); (*expr) -> op = (token == OPTION ? expr_option : expr_config_option); token = next_token (&val, (unsigned *)0, cfile); known = 0; /* Pass reference directly to expression structure. */ status = parse_option_name(cfile, 0, &known, &(*expr)->data.option); if (status != ISC_R_SUCCESS || (*expr)->data.option == NULL) { *lose = 1; expression_dereference (expr, MDL); return 0; } break; case HARDWARE: token = next_token (&val, (unsigned *)0, cfile); if (!expression_allocate (expr, MDL)) log_fatal ("can't allocate expression"); (*expr) -> op = expr_hardware; break; case LEASED_ADDRESS: token = next_token (&val, (unsigned *)0, cfile); if (!expression_allocate (expr, MDL)) log_fatal ("can't allocate expression"); (*expr) -> op = expr_leased_address; break; case CLIENT_STATE: token = next_token (&val, (unsigned *)0, cfile); if (!expression_allocate (expr, MDL)) log_fatal ("can't allocate expression"); (*expr) -> op = expr_client_state; break; case FILENAME: token = next_token (&val, (unsigned *)0, cfile); if (!expression_allocate (expr, MDL)) log_fatal ("can't allocate expression"); (*expr) -> op = expr_filename; break; case SERVER_NAME: token = next_token (&val, (unsigned *)0, cfile); if (!expression_allocate (expr, MDL)) log_fatal ("can't allocate expression"); (*expr) -> op = expr_sname; break; case LEASE_TIME: token = next_token (&val, (unsigned *)0, cfile); if (!expression_allocate (expr, MDL)) log_fatal ("can't allocate expression"); (*expr) -> op = expr_lease_time; break; case TOKEN_NULL: token = next_token (&val, (unsigned *)0, cfile); if (!expression_allocate (expr, MDL)) log_fatal ("can't allocate expression"); (*expr) -> op = expr_null; break; case HOST_DECL_NAME: token = next_token (&val, (unsigned *)0, cfile); if (!expression_allocate (expr, MDL)) log_fatal ("can't allocate expression"); (*expr) -> op = expr_host_decl_name; break; #if defined(NSUPDATE_OLD) case UPDATED_DNS_RR: token = next_token (&val, (unsigned *)0, cfile); token = next_token (&val, (unsigned *)0, cfile); if (token != LPAREN) goto nolparen; token = next_token (&val, (unsigned *)0, cfile); if (token != STRING) { parse_warn (cfile, "expecting string."); bad_rrtype: *lose = 1; return 0; } if (!strcasecmp (val, "a")) s = "ddns-fwd-name"; else if (!strcasecmp (val, "ptr")) s = "ddns-rev-name"; else { parse_warn (cfile, "invalid DNS rrtype: %s", val); goto bad_rrtype; } token = next_token (&val, (unsigned *)0, cfile); if (token != RPAREN) goto norparen; if (!expression_allocate (expr, MDL)) log_fatal ("can't allocate expression"); (*expr) -> op = expr_variable_reference; (*expr) -> data.variable = dmalloc (strlen (s) + 1, MDL); if (!(*expr) -> data.variable) log_fatal ("can't allocate variable name."); strcpy ((*expr) -> data.variable, s); break; #endif /* NSUPDATE_OLD */ case PACKET: token = next_token (&val, (unsigned *)0, cfile); if (!expression_allocate (expr, MDL)) log_fatal ("can't allocate expression"); (*expr) -> op = expr_packet; token = next_token (&val, (unsigned *)0, cfile); if (token != LPAREN) goto nolparen; if (!parse_numeric_expression (&(*expr) -> data.packet.offset, cfile, lose)) goto nonum; token = next_token (&val, (unsigned *)0, cfile); if (token != COMMA) goto nocomma; if (!parse_numeric_expression (&(*expr) -> data.packet.len, cfile, lose)) goto nonum; token = next_token (&val, (unsigned *)0, cfile); if (token != RPAREN) goto norparen; break; case STRING: token = next_token (&val, &len, cfile); if (!make_const_data (expr, (const unsigned char *)val, len, 1, 1, MDL)) log_fatal ("can't make constant string expression."); break; case EXTRACT_INT: token = next_token (&val, (unsigned *)0, cfile); token = next_token (&val, (unsigned *)0, cfile); if (token != LPAREN) { parse_warn (cfile, "left parenthesis expected."); *lose = 1; return 0; } if (!expression_allocate (expr, MDL)) log_fatal ("can't allocate expression"); if (!parse_data_expression (&(*expr) -> data.extract_int, cfile, lose)) { if (!*lose) { parse_warn (cfile, "expecting data expression."); skip_to_semi (cfile); *lose = 1; } expression_dereference (expr, MDL); return 0; } token = next_token (&val, (unsigned *)0, cfile); if (token != COMMA) { parse_warn (cfile, "comma expected."); *lose = 1; expression_dereference (expr, MDL); return 0; } token = next_token (&val, (unsigned *)0, cfile); if (token != NUMBER) { parse_warn (cfile, "number expected."); *lose = 1; expression_dereference (expr, MDL); return 0; } switch (atoi (val)) { case 8: (*expr) -> op = expr_extract_int8; break; case 16: (*expr) -> op = expr_extract_int16; break; case 32: (*expr) -> op = expr_extract_int32; break; default: parse_warn (cfile, "unsupported integer size %d", atoi (val)); *lose = 1; skip_to_semi (cfile); expression_dereference (expr, MDL); return 0; } token = next_token (&val, (unsigned *)0, cfile); if (token != RPAREN) { parse_warn (cfile, "right parenthesis expected."); *lose = 1; expression_dereference (expr, MDL); return 0; } break; case ENCODE_INT: token = next_token (&val, (unsigned *)0, cfile); token = next_token (&val, (unsigned *)0, cfile); if (token != LPAREN) { parse_warn (cfile, "left parenthesis expected."); *lose = 1; return 0; } if (!expression_allocate (expr, MDL)) log_fatal ("can't allocate expression"); if (!parse_numeric_expression (&(*expr) -> data.encode_int, cfile, lose)) { parse_warn (cfile, "expecting numeric expression."); skip_to_semi (cfile); *lose = 1; expression_dereference (expr, MDL); return 0; } token = next_token (&val, (unsigned *)0, cfile); if (token != COMMA) { parse_warn (cfile, "comma expected."); *lose = 1; expression_dereference (expr, MDL); return 0; } token = next_token (&val, (unsigned *)0, cfile); if (token != NUMBER) { parse_warn (cfile, "number expected."); *lose = 1; expression_dereference (expr, MDL); return 0; } switch (atoi (val)) { case 8: (*expr) -> op = expr_encode_int8; break; case 16: (*expr) -> op = expr_encode_int16; break; case 32: (*expr) -> op = expr_encode_int32; break; default: parse_warn (cfile, "unsupported integer size %d", atoi (val)); *lose = 1; skip_to_semi (cfile); expression_dereference (expr, MDL); return 0; } token = next_token (&val, (unsigned *)0, cfile); if (token != RPAREN) { parse_warn (cfile, "right parenthesis expected."); *lose = 1; expression_dereference (expr, MDL); return 0; } break; case NUMBER: /* If we're in a numeric context, this should just be a number, by itself. */ if (context == context_numeric || context == context_data_or_numeric) { next_token (&val, (unsigned *)0, cfile); if (!expression_allocate (expr, MDL)) log_fatal ("can't allocate expression"); (*expr) -> op = expr_const_int; (*expr) -> data.const_int = atoi (val); break; } case NUMBER_OR_NAME: if (!expression_allocate (expr, MDL)) log_fatal ("can't allocate expression"); (*expr) -> op = expr_const_data; if (!parse_cshl (&(*expr) -> data.const_data, cfile)) { expression_dereference (expr, MDL); return 0; } break; case NS_FORMERR: known = FORMERR; goto ns_const; ns_const: token = next_token (&val, (unsigned *)0, cfile); if (!expression_allocate (expr, MDL)) log_fatal ("can't allocate expression"); (*expr) -> op = expr_const_int; (*expr) -> data.const_int = known; break; case NS_NOERROR: known = ISC_R_SUCCESS; goto ns_const; case NS_NOTAUTH: known = DHCP_R_NOTAUTH; goto ns_const; case NS_NOTIMP: known = ISC_R_NOTIMPLEMENTED; goto ns_const; case NS_NOTZONE: known = DHCP_R_NOTZONE; goto ns_const; case NS_NXDOMAIN: known = DHCP_R_NXDOMAIN; goto ns_const; case NS_NXRRSET: known = DHCP_R_NXRRSET; goto ns_const; case NS_REFUSED: known = DHCP_R_REFUSED; goto ns_const; case NS_SERVFAIL: known = DHCP_R_SERVFAIL; goto ns_const; case NS_YXDOMAIN: known = DHCP_R_YXDOMAIN; goto ns_const; case NS_YXRRSET: known = DHCP_R_YXRRSET; goto ns_const; case BOOTING: known = S_INIT; goto ns_const; case REBOOT: known = S_REBOOTING; goto ns_const; case SELECT: known = S_SELECTING; goto ns_const; case REQUEST: known = S_REQUESTING; goto ns_const; case BOUND: known = S_BOUND; goto ns_const; case RENEW: known = S_RENEWING; goto ns_const; case REBIND: known = S_REBINDING; goto ns_const; case DEFINED: token = next_token (&val, (unsigned *)0, cfile); token = next_token (&val, (unsigned *)0, cfile); if (token != LPAREN) goto nolparen; token = next_token (&val, (unsigned *)0, cfile); if (token != NAME && token != NUMBER_OR_NAME) { parse_warn (cfile, "%s can't be a variable name", val); skip_to_semi (cfile); *lose = 1; return 0; } if (!expression_allocate (expr, MDL)) log_fatal ("can't allocate expression"); (*expr) -> op = expr_variable_exists; (*expr) -> data.variable = dmalloc (strlen (val) + 1, MDL); if (!(*expr)->data.variable) log_fatal ("can't allocate variable name"); strcpy ((*expr) -> data.variable, val); token = next_token (&val, (unsigned *)0, cfile); if (token != RPAREN) goto norparen; break; /* This parses 'gethostname()'. */ case GETHOSTNAME: token = next_token(&val, NULL, cfile); if (!expression_allocate(expr, MDL)) log_fatal("can't allocate expression"); (*expr)->op = expr_gethostname; token = next_token(NULL, NULL, cfile); if (token != LPAREN) goto nolparen; token = next_token(NULL, NULL, cfile); if (token != RPAREN) goto norparen; break; case GETHOSTBYNAME: token = next_token(&val, NULL, cfile); token = next_token(NULL, NULL, cfile); if (token != LPAREN) goto nolparen; /* The argument is a quoted string. */ token = next_token(&val, NULL, cfile); if (token != STRING) { parse_warn(cfile, "Expecting quoted literal: " "\"foo.example.com\""); skip_to_semi(cfile); *lose = 1; return 0; } if (!make_host_lookup(expr, val)) log_fatal("Error creating gethostbyname() internal " "record. (%s:%d)", MDL); token = next_token(NULL, NULL, cfile); if (token != RPAREN) goto norparen; break; /* Not a valid start to an expression... */ default: if (token != NAME && token != NUMBER_OR_NAME) return 0; token = next_token (&val, (unsigned *)0, cfile); /* Save the name of the variable being referenced. */ cptr = dmalloc (strlen (val) + 1, MDL); if (!cptr) log_fatal ("can't allocate variable name"); strcpy (cptr, val); /* Simple variable reference, as far as we can tell. */ token = peek_token (&val, (unsigned *)0, cfile); if (token != LPAREN) { if (!expression_allocate (expr, MDL)) log_fatal ("can't allocate expression"); (*expr) -> op = expr_variable_reference; (*expr) -> data.variable = cptr; break; } token = next_token (&val, (unsigned *)0, cfile); if (!expression_allocate (expr, MDL)) log_fatal ("can't allocate expression"); (*expr) -> op = expr_funcall; (*expr) -> data.funcall.name = cptr; /* Now parse the argument list. */ ep = &(*expr) -> data.funcall.arglist; do { if (!expression_allocate (ep, MDL)) log_fatal ("can't allocate expression"); (*ep) -> op = expr_arg; if (!parse_expression (&(*ep) -> data.arg.val, cfile, lose, context_any, (struct expression **)0, expr_none)) { if (!*lose) { parse_warn (cfile, "expecting expression."); *lose = 1; } skip_to_semi (cfile); expression_dereference (expr, MDL); return 0; } ep = &((*ep) -> data.arg.next); token = next_token (&val, (unsigned *)0, cfile); } while (token == COMMA); if (token != RPAREN) { parse_warn (cfile, "Right parenthesis expected."); skip_to_semi (cfile); *lose = 1; expression_dereference (expr, MDL); return 0; } break; } return 1; } /* Parse an expression. */ int parse_expression (expr, cfile, lose, context, plhs, binop) struct expression **expr; struct parse *cfile; int *lose; enum expression_context context; struct expression **plhs; enum expr_op binop; { enum dhcp_token token; const char *val; struct expression *rhs = (struct expression *)0, *tmp; struct expression *lhs = (struct expression *)0; enum expr_op next_op; enum expression_context lhs_context = context_any, rhs_context = context_any; /* Consume the left hand side we were passed. */ if (plhs) { expression_reference (&lhs, *plhs, MDL); expression_dereference (plhs, MDL); } new_rhs: if (!parse_non_binary (&rhs, cfile, lose, context)) { /* If we already have a left-hand side, then it's not okay for there not to be a right-hand side here, so we need to flag it as an error. */ if (lhs) { if (!*lose) { parse_warn (cfile, "expecting right-hand side."); *lose = 1; skip_to_semi (cfile); } expression_dereference (&lhs, MDL); } return 0; } /* At this point, rhs contains either an entire subexpression, or at least a left-hand-side. If we do not see a binary token as the next token, we're done with the expression. */ token = peek_token (&val, (unsigned *)0, cfile); switch (token) { case BANG: token = next_token (&val, (unsigned *)0, cfile); token = peek_token (&val, (unsigned *)0, cfile); if (token != EQUAL) { parse_warn (cfile, "! in boolean context without ="); *lose = 1; skip_to_semi (cfile); if (lhs) expression_dereference (&lhs, MDL); return 0; } next_op = expr_not_equal; context = expression_context (rhs); break; case EQUAL: next_op = expr_equal; context = expression_context (rhs); break; case TILDE: #ifdef HAVE_REGEX_H token = next_token(&val, NULL, cfile); token = peek_token(&val, NULL, cfile); if (token == TILDE) next_op = expr_iregex_match; else if (token == EQUAL) next_op = expr_regex_match; else { parse_warn(cfile, "expecting ~= or ~~ operator"); *lose = 1; skip_to_semi(cfile); if (lhs) expression_dereference(&lhs, MDL); return 0; } context = expression_context(rhs); #else parse_warn(cfile, "No support for regex operator."); *lose = 1; skip_to_semi(cfile); if (lhs != NULL) expression_dereference(&lhs, MDL); return 0; #endif break; case AND: next_op = expr_and; context = expression_context (rhs); break; case OR: next_op = expr_or; context = expression_context (rhs); break; case PLUS: next_op = expr_add; context = expression_context (rhs); break; case MINUS: next_op = expr_subtract; context = expression_context (rhs); break; case SLASH: next_op = expr_divide; context = expression_context (rhs); break; case ASTERISK: next_op = expr_multiply; context = expression_context (rhs); break; case PERCENT: next_op = expr_remainder; context = expression_context (rhs); break; case AMPERSAND: next_op = expr_binary_and; context = expression_context (rhs); break; case PIPE: next_op = expr_binary_or; context = expression_context (rhs); break; case CARET: next_op = expr_binary_xor; context = expression_context (rhs); break; default: next_op = expr_none; } /* If we have no lhs yet, we just parsed it. */ if (!lhs) { /* If there was no operator following what we just parsed, then we're done - return it. */ if (next_op == expr_none) { *expr = rhs; return 1; } lhs = rhs; rhs = (struct expression *)0; binop = next_op; next_token (&val, (unsigned *)0, cfile); goto new_rhs; } /* If the next binary operator is of greater precedence than the * current operator, then rhs we have parsed so far is actually * the lhs of the next operator. To get this value, we have to * recurse. */ if (binop != expr_none && next_op != expr_none && op_precedence (binop, next_op) < 0) { /* Eat the subexpression operator token, which we pass to * parse_expression...we only peek()'d earlier. */ token = next_token (&val, (unsigned *)0, cfile); /* Continue parsing of the right hand side with that token. */ tmp = rhs; rhs = (struct expression *)0; if (!parse_expression (&rhs, cfile, lose, op_context (next_op), &tmp, next_op)) { if (!*lose) { parse_warn (cfile, "expecting a subexpression"); *lose = 1; } return 0; } next_op = expr_none; } if (binop != expr_none) { rhs_context = expression_context(rhs); lhs_context = expression_context(lhs); if ((rhs_context != context_any) && (lhs_context != context_any) && (rhs_context != lhs_context)) { parse_warn (cfile, "illegal expression relating different types"); skip_to_semi (cfile); expression_dereference (&rhs, MDL); expression_dereference (&lhs, MDL); *lose = 1; return 0; } switch(binop) { case expr_not_equal: case expr_equal: if ((rhs_context != context_data_or_numeric) && (rhs_context != context_data) && (rhs_context != context_numeric) && (rhs_context != context_any)) { parse_warn (cfile, "expecting data/numeric expression"); skip_to_semi (cfile); expression_dereference (&rhs, MDL); *lose = 1; return 0; } break; case expr_regex_match: #ifdef HAVE_REGEX_H if (expression_context(rhs) != context_data) { parse_warn(cfile, "expecting data expression"); skip_to_semi(cfile); expression_dereference(&rhs, MDL); *lose = 1; return 0; } #else /* It should not be possible to attempt to parse the right * hand side of an operator there is no support for. */ log_fatal("Impossible condition at %s:%d.", MDL); #endif break; case expr_and: case expr_or: if ((rhs_context != context_boolean) && (rhs_context != context_any)) { parse_warn (cfile, "expecting boolean expressions"); skip_to_semi (cfile); expression_dereference (&rhs, MDL); *lose = 1; return 0; } break; case expr_add: case expr_subtract: case expr_divide: case expr_multiply: case expr_remainder: case expr_binary_and: case expr_binary_or: case expr_binary_xor: if ((rhs_context != context_numeric) && (rhs_context != context_any)) { parse_warn (cfile, "expecting numeric expressions"); skip_to_semi (cfile); expression_dereference (&rhs, MDL); *lose = 1; return 0; } break; default: break; } } /* Now, if we didn't find a binary operator, we're done parsing this subexpression, so combine it with the preceding binary operator and return the result. */ if (next_op == expr_none) { if (!expression_allocate (expr, MDL)) log_fatal ("Can't allocate expression!"); (*expr) -> op = binop; /* All the binary operators' data union members are the same, so we'll cheat and use the member for the equals operator. */ (*expr) -> data.equal [0] = lhs; (*expr) -> data.equal [1] = rhs; return 1; } /* Eat the operator token - we now know it was a binary operator... */ token = next_token (&val, (unsigned *)0, cfile); /* Now combine the LHS and the RHS using binop. */ tmp = (struct expression *)0; if (!expression_allocate (&tmp, MDL)) log_fatal ("No memory for equal precedence combination."); /* Store the LHS and RHS. */ tmp -> data.equal [0] = lhs; tmp -> data.equal [1] = rhs; tmp -> op = binop; lhs = tmp; tmp = (struct expression *)0; rhs = (struct expression *)0; /* Recursions don't return until we have parsed the end of the expression, so if we recursed earlier, we can now return what we got. */ if (next_op == expr_none) { *expr = lhs; return 1; } binop = next_op; goto new_rhs; } int parse_option_data (expr, cfile, lookups, option) struct expression **expr; struct parse *cfile; int lookups; struct option *option; { const char *val; const char *fmt = NULL; struct expression *tmp; enum dhcp_token token; do { /* * Set a flag if this is an array of a simple type (i.e., * not an array of pairs of IP addresses, or something like * that. */ int uniform = 0; and_again: /* Set fmt to start of format for 'A' and one char back * for 'a'. */ if ((fmt != NULL) && (fmt != option->format) && (*fmt == 'a')) fmt -= 1; else if ((fmt == NULL) || (*fmt == 'A')) fmt = option->format; /* 'a' means always uniform */ if ((fmt[0] != 'Z') && (tolower((unsigned char)fmt[1]) == 'a')) uniform = 1; do { if ((*fmt == 'A') || (*fmt == 'a')) break; if (*fmt == 'o') { /* consume the optional flag */ fmt++; continue; } if (fmt[1] == 'o') { /* * A value for the current format is * optional - check to see if the next * token is a semi-colon if so we don't * need to parse it and doing so would * consume the semi-colon which our * caller is expecting to parse */ token = peek_token(&val, (unsigned *)0, cfile); if (token == SEMI) { fmt++; continue; } } tmp = *expr; *expr = NULL; if (!parse_option_token(expr, cfile, &fmt, tmp, uniform, lookups)) { if (fmt [1] != 'o') { if (tmp) expression_dereference (&tmp, MDL); return 0; } *expr = tmp; tmp = NULL; } if (tmp) expression_dereference (&tmp, MDL); fmt++; } while (*fmt != '\0'); if ((*fmt == 'A') || (*fmt == 'a')) { token = peek_token (&val, (unsigned *)0, cfile); /* Comma means: continue with next element in array */ if (token == COMMA) { token = next_token (&val, (unsigned *)0, cfile); continue; } /* no comma: end of array. 'A' or end of string means: leave the loop */ if ((*fmt == 'A') || (fmt[1] == '\0')) break; /* 'a' means: go on with next char */ if (*fmt == 'a') { fmt++; goto and_again; } } } while ((*fmt == 'A') || (*fmt == 'a')); return 1; } /* option-statement :== identifier DOT identifier SEMI | identifier SEMI Option syntax is handled specially through format strings, so it would be painful to come up with BNF for it. However, it always starts as above and ends in a SEMI. */ int parse_option_statement (result, cfile, lookups, option, op) struct executable_statement **result; struct parse *cfile; int lookups; struct option *option; enum statement_op op; { const char *val; enum dhcp_token token; struct expression *expr = (struct expression *)0; int lose; token = peek_token (&val, (unsigned *)0, cfile); if ((token == SEMI) && (option->format[0] != 'Z')) { /* Eat the semicolon... */ /* * XXXSK: I'm not sure why we should ever get here, but we * do during our startup. This confuses things if * we are parsing a zero-length option, so don't * eat the semicolon token in that case. */ token = next_token (&val, (unsigned *)0, cfile); } else if (token == EQUAL) { /* Eat the equals sign. */ token = next_token (&val, (unsigned *)0, cfile); /* Parse a data expression and use its value for the data. */ if (!parse_data_expression (&expr, cfile, &lose)) { /* In this context, we must have an executable statement, so if we found something else, it's still an error. */ if (!lose) { parse_warn (cfile, "expecting a data expression."); skip_to_semi (cfile); } return 0; } } else { if (! parse_option_data(&expr, cfile, lookups, option)) return 0; } if (!parse_semi (cfile)) return 0; if (!executable_statement_allocate (result, MDL)) log_fatal ("no memory for option statement."); (*result)->op = op; if (expr && !option_cache (&(*result)->data.option, NULL, expr, option, MDL)) log_fatal ("no memory for option cache"); if (expr) expression_dereference (&expr, MDL); return 1; } int parse_option_token (rv, cfile, fmt, expr, uniform, lookups) struct expression **rv; struct parse *cfile; const char **fmt; struct expression *expr; int uniform; int lookups; { const char *val; enum dhcp_token token; struct expression *t = (struct expression *)0; unsigned char buf [4]; unsigned len; struct iaddr addr; int compress; isc_boolean_t freeval = ISC_FALSE; const char *f, *g; struct enumeration_value *e; switch (**fmt) { case 'U': token = next_token (&val, &len, cfile); if (!is_identifier (token)) { if ((*fmt) [1] != 'o') { parse_warn (cfile, "expecting identifier."); if (token != SEMI) skip_to_semi (cfile); } return 0; } if (!make_const_data (&t, (const unsigned char *)val, len, 1, 1, MDL)) log_fatal ("No memory for %s", val); break; case 'E': g = strchr (*fmt, '.'); if (!g) { parse_warn (cfile, "malformed encapsulation format (bug!)"); skip_to_semi (cfile); return 0; } *fmt = g; case 'X': token = peek_token (&val, (unsigned *)0, cfile); if (token == NUMBER_OR_NAME || token == NUMBER) { if (!expression_allocate (&t, MDL)) return 0; if (!parse_cshl (&t -> data.const_data, cfile)) { expression_dereference (&t, MDL); return 0; } t -> op = expr_const_data; } else { token = next_token (&val, &len, cfile); if(token == STRING) { if (!make_const_data (&t, (const unsigned char *)val, len, 1, 1, MDL)) log_fatal ("No memory for \"%s\"", val); } else { if ((*fmt) [1] != 'o') { parse_warn (cfile, "expecting string " "or hexadecimal data."); skip_to_semi (cfile); } return 0; } } break; case 'D': /* Domain list... */ if ((*fmt)[1] == 'c') { compress = 1; /* Skip the compress-flag atom. */ (*fmt)++; } else compress = 0; t = parse_domain_list(cfile, compress); if (!t) { if ((*fmt)[1] != 'o') skip_to_semi(cfile); return 0; } break; case 'd': /* Domain name... */ val = parse_host_name (cfile); if (!val) { parse_warn (cfile, "not a valid domain name."); skip_to_semi (cfile); return 0; } len = strlen (val); freeval = ISC_TRUE; goto make_string; case 't': /* Text string... */ token = next_token (&val, &len, cfile); if (token != STRING && !is_identifier (token)) { if ((*fmt) [1] != 'o') { parse_warn (cfile, "expecting string."); if (token != SEMI) skip_to_semi (cfile); } return 0; } make_string: if (!make_const_data (&t, (const unsigned char *)val, len, 1, 1, MDL)) log_fatal ("No memory for concatenation"); if (freeval == ISC_TRUE) { dfree((char *)val, MDL); freeval = ISC_FALSE; } break; case 'N': f = (*fmt) + 1; g = strchr (*fmt, '.'); if (!g) { parse_warn (cfile, "malformed %s (bug!)", "enumeration format"); foo: skip_to_semi (cfile); return 0; } *fmt = g; token = next_token (&val, (unsigned *)0, cfile); if (!is_identifier (token)) { parse_warn (cfile, "identifier expected"); goto foo; } e = find_enumeration_value (f, (*fmt) - f, &len, val); if (!e) { parse_warn (cfile, "unknown value"); goto foo; } if (!make_const_data (&t, &e -> value, len, 0, 1, MDL)) return 0; break; case 'I': /* IP address or hostname. */ if (lookups) { if (!parse_ip_addr_or_hostname (&t, cfile, uniform)) return 0; } else { if (!parse_ip_addr (cfile, &addr)) return 0; if (!make_const_data (&t, addr.iabuf, addr.len, 0, 1, MDL)) return 0; } break; case '6': /* IPv6 address. */ if (!parse_ip6_addr(cfile, &addr)) { return 0; } if (!make_const_data(&t, addr.iabuf, addr.len, 0, 1, MDL)) { return 0; } break; case 'T': /* Lease interval. */ token = next_token (&val, (unsigned *)0, cfile); if (token != INFINITE) goto check_number; putLong (buf, -1); if (!make_const_data (&t, buf, 4, 0, 1, MDL)) return 0; break; case 'L': /* Unsigned 32-bit integer... */ case 'l': /* Signed 32-bit integer... */ token = next_token (&val, (unsigned *)0, cfile); check_number: if ((token != NUMBER) && (token != NUMBER_OR_NAME)) { need_number: if ((*fmt) [1] != 'o') { parse_warn (cfile, "expecting number."); if (token != SEMI) skip_to_semi (cfile); } return 0; } convert_num (cfile, buf, val, 0, 32); if (!make_const_data (&t, buf, 4, 0, 1, MDL)) return 0; break; case 's': /* Signed 16-bit integer. */ case 'S': /* Unsigned 16-bit integer. */ token = next_token (&val, (unsigned *)0, cfile); if ((token != NUMBER) && (token != NUMBER_OR_NAME)) goto need_number; convert_num (cfile, buf, val, 0, 16); if (!make_const_data (&t, buf, 2, 0, 1, MDL)) return 0; break; case 'b': /* Signed 8-bit integer. */ case 'B': /* Unsigned 8-bit integer. */ token = next_token (&val, (unsigned *)0, cfile); if ((token != NUMBER) && (token != NUMBER_OR_NAME)) goto need_number; convert_num (cfile, buf, val, 0, 8); if (!make_const_data (&t, buf, 1, 0, 1, MDL)) return 0; break; case 'f': /* Boolean flag. */ token = next_token (&val, (unsigned *)0, cfile); if (!is_identifier (token)) { if ((*fmt) [1] != 'o') parse_warn (cfile, "expecting identifier."); bad_flag: if ((*fmt) [1] != 'o') { if (token != SEMI) skip_to_semi (cfile); } return 0; } if (!strcasecmp (val, "true") || !strcasecmp (val, "on")) buf [0] = 1; else if (!strcasecmp (val, "false") || !strcasecmp (val, "off")) buf [0] = 0; else if (!strcasecmp (val, "ignore")) buf [0] = 2; else { if ((*fmt) [1] != 'o') parse_warn (cfile, "expecting boolean."); goto bad_flag; } if (!make_const_data (&t, buf, 1, 0, 1, MDL)) return 0; break; case 'Z': /* Zero-length option. */ token = peek_token (&val, (unsigned *)0, cfile); if (token != SEMI) { parse_warn(cfile, "semicolon expected."); skip_to_semi(cfile); } buf[0] = '\0'; if (!make_const_data(&t, /* expression */ buf, /* buffer */ 0, /* length */ 0, /* terminated */ 1, /* allocate */ MDL)) return 0; break; default: parse_warn (cfile, "Bad format '%c' in parse_option_token.", **fmt); skip_to_semi (cfile); return 0; } if (expr) { if (!make_concat (rv, expr, t)) return 0; } else expression_reference (rv, t, MDL); expression_dereference (&t, MDL); return 1; } int parse_option_decl (oc, cfile) struct option_cache **oc; struct parse *cfile; { const char *val; int token; u_int8_t buf [4]; u_int8_t hunkbuf [1024]; unsigned hunkix = 0; const char *fmt, *f; struct option *option=NULL; struct iaddr ip_addr; u_int8_t *dp; const u_int8_t *cdp; unsigned len; int nul_term = 0; struct buffer *bp; int known = 0; int compress; struct expression *express = NULL; struct enumeration_value *e; isc_result_t status; status = parse_option_name (cfile, 0, &known, &option); if (status != ISC_R_SUCCESS || option == NULL) return 0; /* Parse the option data... */ do { for (fmt = option -> format; *fmt; fmt++) { if (*fmt == 'A') break; if (*fmt == 'o' && fmt != option -> format) continue; switch (*fmt) { case 'E': fmt = strchr (fmt, '.'); if (!fmt) { parse_warn (cfile, "malformed %s (bug!)", "encapsulation format"); goto parse_exit; } case 'X': len = parse_X (cfile, &hunkbuf [hunkix], sizeof hunkbuf - hunkix); hunkix += len; break; case 't': /* Text string... */ token = peek_token (&val, &len, cfile); if (token == SEMI && fmt[1] == 'o') { fmt++; break; } token = next_token (&val, &len, cfile); if (token != STRING) { parse_warn (cfile, "expecting string."); goto parse_exit; } if (hunkix + len + 1 > sizeof hunkbuf) { parse_warn (cfile, "option data buffer %s", "overflow"); goto parse_exit; } memcpy (&hunkbuf [hunkix], val, len + 1); nul_term = 1; hunkix += len; break; case 'D': if (fmt[1] == 'c') { compress = 1; fmt++; } else compress = 0; express = parse_domain_list(cfile, compress); if (express == NULL) goto exit; if (express->op != expr_const_data) { parse_warn(cfile, "unexpected " "expression"); goto parse_exit; } len = express->data.const_data.len; cdp = express->data.const_data.data; if ((hunkix + len) > sizeof(hunkbuf)) { parse_warn(cfile, "option data buffer " "overflow"); goto parse_exit; } memcpy(&hunkbuf[hunkix], cdp, len); hunkix += len; expression_dereference(&express, MDL); break; case 'N': f = fmt + 1; fmt = strchr (fmt, '.'); if (!fmt) { parse_warn (cfile, "malformed %s (bug!)", "enumeration format"); goto parse_exit; } token = next_token (&val, (unsigned *)0, cfile); if (!is_identifier (token)) { parse_warn (cfile, "identifier expected"); goto parse_exit; } e = find_enumeration_value (f, fmt - f, &len, val); if (!e) { parse_warn (cfile, "unknown value"); goto parse_exit; } dp = &e -> value; goto alloc; case '6': if (!parse_ip6_addr(cfile, &ip_addr)) goto exit; len = ip_addr.len; dp = ip_addr.iabuf; goto alloc; case 'I': /* IP address. */ if (!parse_ip_addr (cfile, &ip_addr)) goto exit; len = ip_addr.len; dp = ip_addr.iabuf; alloc: if (hunkix + len > sizeof hunkbuf) { parse_warn (cfile, "option data buffer %s", "overflow"); goto parse_exit; } memcpy (&hunkbuf [hunkix], dp, len); hunkix += len; break; case 'L': /* Unsigned 32-bit integer... */ case 'l': /* Signed 32-bit integer... */ token = next_token (&val, (unsigned *)0, cfile); if ((token != NUMBER) && (token != NUMBER_OR_NAME)) { need_number: parse_warn (cfile, "expecting number."); if (token != SEMI) goto parse_exit; else goto exit; } convert_num (cfile, buf, val, 0, 32); len = 4; dp = buf; goto alloc; case 's': /* Signed 16-bit integer. */ case 'S': /* Unsigned 16-bit integer. */ token = next_token (&val, (unsigned *)0, cfile); if ((token != NUMBER) && (token != NUMBER_OR_NAME)) goto need_number; convert_num (cfile, buf, val, 0, 16); len = 2; dp = buf; goto alloc; case 'b': /* Signed 8-bit integer. */ case 'B': /* Unsigned 8-bit integer. */ token = next_token (&val, (unsigned *)0, cfile); if ((token != NUMBER) && (token != NUMBER_OR_NAME)) goto need_number; convert_num (cfile, buf, val, 0, 8); len = 1; dp = buf; goto alloc; case 'f': /* Boolean flag. */ token = next_token (&val, (unsigned *)0, cfile); if (!is_identifier (token)) { parse_warn (cfile, "expecting identifier."); bad_flag: if (token != SEMI) goto parse_exit; else goto exit; } if (!strcasecmp (val, "true") || !strcasecmp (val, "on")) buf [0] = 1; else if (!strcasecmp (val, "false") || !strcasecmp (val, "off")) buf [0] = 0; else { parse_warn (cfile, "expecting boolean."); goto bad_flag; } len = 1; dp = buf; goto alloc; case 'Z': /* Zero-length option */ token = next_token(&val, (unsigned *)0, cfile); if (token != SEMI) { parse_warn(cfile, "semicolon expected."); goto parse_exit; } len = 0; buf[0] = '\0'; break; default: log_error ("parse_option_param: Bad format %c", *fmt); goto parse_exit; } } token = next_token (&val, (unsigned *)0, cfile); } while (*fmt == 'A' && token == COMMA); if (token != SEMI) { parse_warn (cfile, "semicolon expected."); goto parse_exit; } bp = (struct buffer *)0; if (!buffer_allocate (&bp, hunkix + nul_term, MDL)) log_fatal ("no memory to store option declaration."); if (!bp -> data) log_fatal ("out of memory allocating option data."); memcpy (bp -> data, hunkbuf, hunkix + nul_term); if (!option_cache_allocate (oc, MDL)) log_fatal ("out of memory allocating option cache."); (*oc) -> data.buffer = bp; (*oc) -> data.data = &bp -> data [0]; (*oc) -> data.terminated = nul_term; (*oc) -> data.len = hunkix; option_reference(&(*oc)->option, option, MDL); option_dereference(&option, MDL); return 1; parse_exit: if (express != NULL) expression_dereference(&express, MDL); skip_to_semi (cfile); exit: option_dereference(&option, MDL); return 0; } /* Consider merging parse_cshl into this. */ int parse_X (cfile, buf, max) struct parse *cfile; u_int8_t *buf; unsigned max; { int token; const char *val; unsigned len; token = peek_token (&val, (unsigned *)0, cfile); if (token == NUMBER_OR_NAME || token == NUMBER) { len = 0; do { token = next_token (&val, (unsigned *)0, cfile); if (token != NUMBER && token != NUMBER_OR_NAME) { parse_warn (cfile, "expecting hexadecimal constant."); skip_to_semi (cfile); return 0; } convert_num (cfile, &buf [len], val, 16, 8); if (len++ > max) { parse_warn (cfile, "hexadecimal constant too long."); skip_to_semi (cfile); return 0; } token = peek_token (&val, (unsigned *)0, cfile); if (token == COLON) token = next_token (&val, (unsigned *)0, cfile); } while (token == COLON); val = (char *)buf; } else if (token == STRING) { token = next_token (&val, &len, cfile); if (len + 1 > max) { parse_warn (cfile, "string constant too long."); skip_to_semi (cfile); return 0; } memcpy (buf, val, len + 1); } else { parse_warn (cfile, "expecting string or hexadecimal data"); skip_to_semi (cfile); return 0; } return len; } int parse_warn (struct parse *cfile, const char *fmt, ...) { va_list list; char lexbuf [256]; char mbuf [1024]; char fbuf [1024]; unsigned i, lix; do_percentm (mbuf, fmt); /* %Audit% This is log output. %2004.06.17,Safe% * If we truncate we hope the user can get a hint from the log. */ snprintf (fbuf, sizeof fbuf, "%s line %d: %s", cfile -> tlname, cfile -> lexline, mbuf); va_start (list, fmt); vsnprintf (mbuf, sizeof mbuf, fbuf, list); va_end (list); lix = 0; for (i = 0; cfile -> token_line [i] && i < (cfile -> lexchar - 1); i++) { if (lix < (sizeof lexbuf) - 1) lexbuf [lix++] = ' '; if (cfile -> token_line [i] == '\t') { for (; lix < (sizeof lexbuf) - 1 && (lix & 7); lix++) lexbuf [lix] = ' '; } } lexbuf [lix] = 0; #ifndef DEBUG syslog (log_priority | LOG_ERR, "%s", mbuf); syslog (log_priority | LOG_ERR, "%s", cfile -> token_line); if (cfile -> lexchar < 81) syslog (log_priority | LOG_ERR, "%s^", lexbuf); #endif if (log_perror) { IGNORE_RET (write (STDERR_FILENO, mbuf, strlen (mbuf))); IGNORE_RET (write (STDERR_FILENO, "\n", 1)); IGNORE_RET (write (STDERR_FILENO, cfile -> token_line, strlen (cfile -> token_line))); IGNORE_RET (write (STDERR_FILENO, "\n", 1)); if (cfile -> lexchar < 81) IGNORE_RET (write (STDERR_FILENO, lexbuf, lix)); IGNORE_RET (write (STDERR_FILENO, "^\n", 2)); } cfile -> warnings_occurred = 1; return 0; } struct expression * parse_domain_list(struct parse *cfile, int compress) { const char *val; enum dhcp_token token = SEMI; struct expression *t = NULL; unsigned len, clen = 0; int result; unsigned char compbuf[256 * NS_MAXCDNAME]; const unsigned char *dnptrs[256], **lastdnptr; memset(compbuf, 0, sizeof(compbuf)); memset(dnptrs, 0, sizeof(dnptrs)); dnptrs[0] = compbuf; lastdnptr = &dnptrs[255]; do { /* Consume the COMMA token if peeked. */ if (token == COMMA) next_token(&val, NULL, cfile); /* Get next (or first) value. */ token = next_token(&val, &len, cfile); if (token != STRING) { parse_warn(cfile, "Expecting a domain string."); return NULL; } /* If compression pointers are enabled, compress. If not, * just pack the names in series into the buffer. */ if (compress) { result = MRns_name_compress(val, compbuf + clen, sizeof(compbuf) - clen, dnptrs, lastdnptr); if (result < 0) { parse_warn(cfile, "Error compressing domain " "list: %m"); return NULL; } clen += result; } else { result = MRns_name_pton(val, compbuf + clen, sizeof(compbuf) - clen); /* result == 1 means the input was fully qualified. * result == 0 means the input wasn't. * result == -1 means bad things. */ if (result < 0) { parse_warn(cfile, "Error assembling domain " "list: %m"); return NULL; } /* * We need to figure out how many bytes to increment * our buffer pointer since pton doesn't tell us. */ while (compbuf[clen] != 0) clen += compbuf[clen] + 1; /* Count the last label (0). */ clen++; } if (clen > sizeof(compbuf)) log_fatal("Impossible error at %s:%d", MDL); token = peek_token(&val, NULL, cfile); } while (token == COMMA); if (!make_const_data(&t, compbuf, clen, 1, 1, MDL)) log_fatal("No memory for domain list object."); return t; } dhcp-4.2.4/common/print.c000644 000765 000024 00000101031 11726364513 015163 0ustar00sarstaff000000 000000 /* print.c Turn data structures into printable text. */ /* * Copyright (c) 2009-2012 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 2004-2007 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1995-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ * * This software has been written for Internet Systems Consortium * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. * To learn more about Internet Systems Consortium, see * ``https://www.isc.org/''. To learn more about Vixie Enterprises, * see ``http://www.vix.com''. To learn more about Nominum, Inc., see * ``http://www.nominum.com''. */ #include "dhcpd.h" int db_time_format = DEFAULT_TIME_FORMAT; char *quotify_string (const char *s, const char *file, int line) { unsigned len = 0; const char *sp; char *buf, *nsp; for (sp = s; sp && *sp; sp++) { if (*sp == ' ') len++; else if (!isascii ((int)*sp) || !isprint ((int)*sp)) len += 4; else if (*sp == '"' || *sp == '\\') len += 2; else len++; } buf = dmalloc (len + 1, file, line); if (buf) { nsp = buf; for (sp = s; sp && *sp; sp++) { if (*sp == ' ') *nsp++ = ' '; else if (!isascii ((int)*sp) || !isprint ((int)*sp)) { sprintf (nsp, "\\%03o", *(const unsigned char *)sp); nsp += 4; } else if (*sp == '"' || *sp == '\\') { *nsp++ = '\\'; *nsp++ = *sp; } else *nsp++ = *sp; } *nsp++ = 0; } return buf; } char *quotify_buf (const unsigned char *s, unsigned len, const char *file, int line) { unsigned nulen = 0; char *buf, *nsp; int i; for (i = 0; i < len; i++) { if (s [i] == ' ') nulen++; else if (!isascii (s [i]) || !isprint (s [i])) nulen += 4; else if (s [i] == '"' || s [i] == '\\') nulen += 2; else nulen++; } buf = dmalloc (nulen + 1, MDL); if (buf) { nsp = buf; for (i = 0; i < len; i++) { if (s [i] == ' ') *nsp++ = ' '; else if (!isascii (s [i]) || !isprint (s [i])) { sprintf (nsp, "\\%03o", s [i]); nsp += 4; } else if (s [i] == '"' || s [i] == '\\') { *nsp++ = '\\'; *nsp++ = s [i]; } else *nsp++ = s [i]; } *nsp++ = 0; } return buf; } char *print_base64 (const unsigned char *buf, unsigned len, const char *file, int line) { char *s, *b; unsigned bl; int i; unsigned val, extra; static char to64 [] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; bl = ((len * 4 + 2) / 3) + 1; b = dmalloc (bl + 1, file, line); if (!b) return (char *)0; i = 0; s = b; while (i != len) { val = buf [i++]; extra = val & 3; val = val >> 2; *s++ = to64 [val]; if (i == len) { *s++ = to64 [extra << 4]; *s++ = '='; break; } val = (extra << 8) + buf [i++]; extra = val & 15; val = val >> 4; *s++ = to64 [val]; if (i == len) { *s++ = to64 [extra << 2]; *s++ = '='; break; } val = (extra << 8) + buf [i++]; extra = val & 0x3f; val = val >> 6; *s++ = to64 [val]; *s++ = to64 [extra]; } if (!len) *s++ = '='; *s++ = 0; if (s > b + bl + 1) abort (); return b; } char *print_hw_addr (htype, hlen, data) const int htype; const int hlen; const unsigned char *data; { static char habuf [49]; char *s; int i; if (hlen <= 0) habuf [0] = 0; else { s = habuf; for (i = 0; i < hlen; i++) { sprintf (s, "%02x", data [i]); s += strlen (s); *s++ = ':'; } *--s = 0; } return habuf; } void print_lease (lease) struct lease *lease; { struct tm *t; char tbuf [32]; log_debug (" Lease %s", piaddr (lease -> ip_addr)); t = gmtime (&lease -> starts); strftime (tbuf, sizeof tbuf, "%Y/%m/%d %H:%M:%S", t); log_debug (" start %s", tbuf); t = gmtime (&lease -> ends); strftime (tbuf, sizeof tbuf, "%Y/%m/%d %H:%M:%S", t); log_debug (" end %s", tbuf); if (lease -> hardware_addr.hlen) log_debug (" hardware addr = %s", print_hw_addr (lease -> hardware_addr.hbuf [0], lease -> hardware_addr.hlen - 1, &lease -> hardware_addr.hbuf [1])); log_debug (" host %s ", lease -> host ? lease -> host -> name : ""); } #if defined (DEBUG_PACKET) void dump_packet_option (struct option_cache *oc, struct packet *packet, struct lease *lease, struct client_state *client, struct option_state *in_options, struct option_state *cfg_options, struct binding_scope **scope, struct universe *u, void *foo) { const char *name, *dot; struct data_string ds; memset (&ds, 0, sizeof ds); if (u != &dhcp_universe) { name = u -> name; dot = "."; } else { name = ""; dot = ""; } if (evaluate_option_cache (&ds, packet, lease, client, in_options, cfg_options, scope, oc, MDL)) { log_debug (" option %s%s%s %s;\n", name, dot, oc -> option -> name, pretty_print_option (oc -> option, ds.data, ds.len, 1, 1)); data_string_forget (&ds, MDL); } } void dump_packet (tp) struct packet *tp; { struct dhcp_packet *tdp = tp -> raw; log_debug ("packet length %d", tp -> packet_length); log_debug ("op = %d htype = %d hlen = %d hops = %d", tdp -> op, tdp -> htype, tdp -> hlen, tdp -> hops); log_debug ("xid = %x secs = %ld flags = %x", tdp -> xid, (unsigned long)tdp -> secs, tdp -> flags); log_debug ("ciaddr = %s", inet_ntoa (tdp -> ciaddr)); log_debug ("yiaddr = %s", inet_ntoa (tdp -> yiaddr)); log_debug ("siaddr = %s", inet_ntoa (tdp -> siaddr)); log_debug ("giaddr = %s", inet_ntoa (tdp -> giaddr)); log_debug ("chaddr = %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x", ((unsigned char *)(tdp -> chaddr)) [0], ((unsigned char *)(tdp -> chaddr)) [1], ((unsigned char *)(tdp -> chaddr)) [2], ((unsigned char *)(tdp -> chaddr)) [3], ((unsigned char *)(tdp -> chaddr)) [4], ((unsigned char *)(tdp -> chaddr)) [5]); log_debug ("filename = %s", tdp -> file); log_debug ("server_name = %s", tdp -> sname); if (tp -> options_valid) { int i; for (i = 0; i < tp -> options -> universe_count; i++) { if (tp -> options -> universes [i]) { option_space_foreach (tp, (struct lease *)0, (struct client_state *)0, (struct option_state *)0, tp -> options, &global_scope, universes [i], 0, dump_packet_option); } } } log_debug ("%s", ""); } #endif void dump_raw (buf, len) const unsigned char *buf; unsigned len; { int i; char lbuf [80]; int lbix = 0; /* 1 2 3 4 5 6 7 01234567890123456789012345678901234567890123456789012345678901234567890123 280: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................. */ memset(lbuf, ' ', 79); lbuf [79] = 0; for (i = 0; i < len; i++) { if ((i & 15) == 0) { if (lbix) { lbuf[53]=' '; lbuf[54]=' '; lbuf[55]=' '; lbuf[73]='\0'; log_info ("%s", lbuf); } memset(lbuf, ' ', 79); lbuf [79] = 0; sprintf (lbuf, "%03x:", i); lbix = 4; } else if ((i & 7) == 0) lbuf [lbix++] = ' '; if(isprint(buf[i])) { lbuf[56+(i%16)]=buf[i]; } else { lbuf[56+(i%16)]='.'; } sprintf (&lbuf [lbix], " %02x", buf [i]); lbix += 3; lbuf[lbix]=' '; } lbuf[53]=' '; lbuf[54]=' '; lbuf[55]=' '; lbuf[73]='\0'; log_info ("%s", lbuf); } void hash_dump (table) struct hash_table *table; { int i; struct hash_bucket *bp; if (!table) return; for (i = 0; i < table -> hash_count; i++) { if (!table -> buckets [i]) continue; log_info ("hash bucket %d:", i); for (bp = table -> buckets [i]; bp; bp = bp -> next) { if (bp -> len) dump_raw (bp -> name, bp -> len); else log_info ("%s", (const char *)bp -> name); } } } /* * print a string as hex. This only outputs * colon separated hex list no matter what * the input looks like. See print_hex * for a function that prints either cshl * or a string if all bytes are printible * It only uses limit characters from buf * and doesn't do anything if buf == NULL * * len - length of data * data - input data * limit - length of buf to use * buf - output buffer */ void print_hex_only (len, data, limit, buf) unsigned len; const u_int8_t *data; unsigned limit; char *buf; { unsigned i; if ((buf == NULL) || (limit < 3)) return; for (i = 0; (i < limit / 3) && (i < len); i++) { sprintf(&buf[i*3], "%02x:", data[i]); } buf[(i * 3) - 1] = 0; return; } /* * print a string as either text if all the characters * are printable or colon separated hex if they aren't * * len - length of data * data - input data * limit - length of buf to use * buf - output buffer */ void print_hex_or_string (len, data, limit, buf) unsigned len; const u_int8_t *data; unsigned limit; char *buf; { unsigned i; if ((buf == NULL) || (limit < 3)) return; for (i = 0; (i < (limit - 3)) && (i < len); i++) { if (!isascii(data[i]) || !isprint(data[i])) { print_hex_only(len, data, limit, buf); return; } } buf[0] = '"'; i = len; if (i > (limit - 3)) i = limit - 3; memcpy(&buf[1], data, i); buf[i + 1] = '"'; buf[i + 2] = 0; return; } /* * print a string as either hex or text * using static buffers to hold the output * * len - length of data * data - input data * limit - length of buf * buf_num - the output buffer to use */ #define HBLEN 1024 char *print_hex(len, data, limit, buf_num) unsigned len; const u_int8_t *data; unsigned limit; unsigned buf_num; { static char hex_buf_1[HBLEN + 1]; static char hex_buf_2[HBLEN + 1]; static char hex_buf_3[HBLEN + 1]; char *hex_buf; switch(buf_num) { case 0: hex_buf = hex_buf_1; if (limit >= sizeof(hex_buf_1)) limit = sizeof(hex_buf_1); break; case 1: hex_buf = hex_buf_2; if (limit >= sizeof(hex_buf_2)) limit = sizeof(hex_buf_2); break; case 2: hex_buf = hex_buf_3; if (limit >= sizeof(hex_buf_3)) limit = sizeof(hex_buf_3); break; default: return(NULL); } print_hex_or_string(len, data, limit, hex_buf); return(hex_buf); } #define DQLEN 80 char *print_dotted_quads (len, data) unsigned len; const u_int8_t *data; { static char dq_buf [DQLEN + 1]; int i; char *s; s = &dq_buf [0]; i = 0; /* %Audit% Loop bounds checks to 21 bytes. %2004.06.17,Safe% * The sprintf can't exceed 18 bytes, and since the loop enforces * 21 bytes of space per iteration at no time can we exit the * loop without at least 3 bytes spare. */ do { sprintf (s, "%u.%u.%u.%u, ", data [i], data [i + 1], data [i + 2], data [i + 3]); s += strlen (s); i += 4; } while ((s - &dq_buf [0] > DQLEN - 21) && i + 3 < len); if (i == len) s [-2] = 0; else strcpy (s, "..."); return dq_buf; } char *print_dec_1 (val) unsigned long val; { static char vbuf [32]; sprintf (vbuf, "%lu", val); return vbuf; } char *print_dec_2 (val) unsigned long val; { static char vbuf [32]; sprintf (vbuf, "%lu", val); return vbuf; } static unsigned print_subexpression (struct expression *, char *, unsigned); static unsigned print_subexpression (expr, buf, len) struct expression *expr; char *buf; unsigned len; { unsigned rv, left; const char *s; switch (expr -> op) { case expr_none: if (len > 3) { strcpy (buf, "nil"); return 3; } break; case expr_match: if (len > 7) { strcpy (buf, "(match)"); return 7; } break; case expr_check: rv = 10 + strlen (expr -> data.check -> name); if (len > rv) { sprintf (buf, "(check %s)", expr -> data.check -> name); return rv; } break; case expr_equal: if (len > 6) { rv = 4; strcpy (buf, "(eq "); rv += print_subexpression (expr -> data.equal [0], buf + rv, len - rv - 2); buf [rv++] = ' '; rv += print_subexpression (expr -> data.equal [1], buf + rv, len - rv - 1); buf [rv++] = ')'; buf [rv] = 0; return rv; } break; case expr_not_equal: if (len > 7) { rv = 5; strcpy (buf, "(neq "); rv += print_subexpression (expr -> data.equal [0], buf + rv, len - rv - 2); buf [rv++] = ' '; rv += print_subexpression (expr -> data.equal [1], buf + rv, len - rv - 1); buf [rv++] = ')'; buf [rv] = 0; return rv; } break; case expr_regex_match: if (len > 10) { rv = 4; strcpy(buf, "(regex "); rv += print_subexpression(expr->data.equal[0], buf + rv, len - rv - 2); buf[rv++] = ' '; rv += print_subexpression(expr->data.equal[1], buf + rv, len - rv - 1); buf[rv++] = ')'; buf[rv] = 0; return rv; } break; case expr_substring: if (len > 11) { rv = 8; strcpy (buf, "(substr "); rv += print_subexpression (expr -> data.substring.expr, buf + rv, len - rv - 3); buf [rv++] = ' '; rv += print_subexpression (expr -> data.substring.offset, buf + rv, len - rv - 2); buf [rv++] = ' '; rv += print_subexpression (expr -> data.substring.len, buf + rv, len - rv - 1); buf [rv++] = ')'; buf [rv] = 0; return rv; } break; case expr_suffix: if (len > 10) { rv = 8; strcpy (buf, "(suffix "); rv += print_subexpression (expr -> data.suffix.expr, buf + rv, len - rv - 2); if (len > rv) buf [rv++] = ' '; rv += print_subexpression (expr -> data.suffix.len, buf + rv, len - rv - 1); if (len > rv) buf [rv++] = ')'; buf [rv] = 0; return rv; } break; case expr_lcase: if (len > 9) { rv = 7; strcpy(buf, "(lcase "); rv += print_subexpression(expr->data.lcase, buf + rv, len - rv - 1); buf[rv++] = ')'; buf[rv] = 0; return rv; } break; case expr_ucase: if (len > 9) { rv = 7; strcpy(buf, "(ucase "); rv += print_subexpression(expr->data.ucase, buf + rv, len - rv - 1); buf[rv++] = ')'; buf[rv] = 0; return rv; } break; case expr_concat: if (len > 10) { rv = 8; strcpy (buf, "(concat "); rv += print_subexpression (expr -> data.concat [0], buf + rv, len - rv - 2); buf [rv++] = ' '; rv += print_subexpression (expr -> data.concat [1], buf + rv, len - rv - 1); buf [rv++] = ')'; buf [rv] = 0; return rv; } break; case expr_pick_first_value: if (len > 8) { rv = 6; strcpy (buf, "(pick1st "); rv += print_subexpression (expr -> data.pick_first_value.car, buf + rv, len - rv - 2); buf [rv++] = ' '; rv += print_subexpression (expr -> data.pick_first_value.cdr, buf + rv, len - rv - 1); buf [rv++] = ')'; buf [rv] = 0; return rv; } break; case expr_host_lookup: rv = 15 + strlen (expr -> data.host_lookup -> hostname); if (len > rv) { sprintf (buf, "(dns-lookup %s)", expr -> data.host_lookup -> hostname); return rv; } break; case expr_and: s = "and"; binop: rv = strlen (s); if (len > rv + 4) { buf [0] = '('; strcpy (&buf [1], s); rv += 1; buf [rv++] = ' '; rv += print_subexpression (expr -> data.and [0], buf + rv, len - rv - 2); buf [rv++] = ' '; rv += print_subexpression (expr -> data.and [1], buf + rv, len - rv - 1); buf [rv++] = ')'; buf [rv] = 0; return rv; } break; case expr_or: s = "or"; goto binop; case expr_add: s = "+"; goto binop; case expr_subtract: s = "-"; goto binop; case expr_multiply: s = "*"; goto binop; case expr_divide: s = "/"; goto binop; case expr_remainder: s = "%"; goto binop; case expr_binary_and: s = "&"; goto binop; case expr_binary_or: s = "|"; goto binop; case expr_binary_xor: s = "^"; goto binop; case expr_not: if (len > 6) { rv = 5; strcpy (buf, "(not "); rv += print_subexpression (expr -> data.not, buf + rv, len - rv - 1); buf [rv++] = ')'; buf [rv] = 0; return rv; } break; case expr_config_option: s = "cfg-option"; goto dooption; case expr_option: s = "option"; dooption: rv = strlen (s) + 2 + (strlen (expr -> data.option -> name) + strlen (expr -> data.option -> universe -> name)); if (len > rv) { sprintf (buf, "(option %s.%s)", expr -> data.option -> universe -> name, expr -> data.option -> name); return rv; } break; case expr_hardware: if (len > 10) { strcpy (buf, "(hardware)"); return 10; } break; case expr_packet: if (len > 10) { rv = 8; strcpy (buf, "(substr "); rv += print_subexpression (expr -> data.packet.offset, buf + rv, len - rv - 2); buf [rv++] = ' '; rv += print_subexpression (expr -> data.packet.len, buf + rv, len - rv - 1); buf [rv++] = ')'; buf [rv] = 0; return rv; } break; case expr_const_data: s = print_hex_1 (expr -> data.const_data.len, expr -> data.const_data.data, len); rv = strlen (s); if (rv >= len) rv = len - 1; strncpy (buf, s, rv); buf [rv] = 0; return rv; case expr_encapsulate: rv = 13; strcpy (buf, "(encapsulate "); rv += expr -> data.encapsulate.len; if (rv + 2 > len) rv = len - 2; strncpy (buf, (const char *)expr -> data.encapsulate.data, rv - 13); buf [rv++] = ')'; buf [rv++] = 0; break; case expr_extract_int8: if (len > 7) { rv = 6; strcpy (buf, "(int8 "); rv += print_subexpression (expr -> data.extract_int, buf + rv, len - rv - 1); buf [rv++] = ')'; buf [rv] = 0; return rv; } break; case expr_extract_int16: if (len > 8) { rv = 7; strcpy (buf, "(int16 "); rv += print_subexpression (expr -> data.extract_int, buf + rv, len - rv - 1); buf [rv++] = ')'; buf [rv] = 0; return rv; } break; case expr_extract_int32: if (len > 8) { rv = 7; strcpy (buf, "(int32 "); rv += print_subexpression (expr -> data.extract_int, buf + rv, len - rv - 1); buf [rv++] = ')'; buf [rv] = 0; return rv; } break; case expr_encode_int8: if (len > 7) { rv = 6; strcpy (buf, "(to-int8 "); rv += print_subexpression (expr -> data.encode_int, buf + rv, len - rv - 1); buf [rv++] = ')'; buf [rv] = 0; return rv; } break; case expr_encode_int16: if (len > 8) { rv = 7; strcpy (buf, "(to-int16 "); rv += print_subexpression (expr -> data.encode_int, buf + rv, len - rv - 1); buf [rv++] = ')'; buf [rv] = 0; return rv; } break; case expr_encode_int32: if (len > 8) { rv = 7; strcpy (buf, "(to-int32 "); rv += print_subexpression (expr -> data.encode_int, buf + rv, len - rv - 1); buf [rv++] = ')'; buf [rv] = 0; return rv; } break; case expr_const_int: s = print_dec_1 (expr -> data.const_int); rv = strlen (s); if (len > rv) { strcpy (buf, s); return rv; } break; case expr_exists: rv = 10 + (strlen (expr -> data.option -> name) + strlen (expr -> data.option -> universe -> name)); if (len > rv) { sprintf (buf, "(exists %s.%s)", expr -> data.option -> universe -> name, expr -> data.option -> name); return rv; } break; case expr_variable_exists: rv = 10 + strlen (expr -> data.variable); if (len > rv) { sprintf (buf, "(defined %s)", expr -> data.variable); return rv; } break; case expr_variable_reference: rv = strlen (expr -> data.variable); if (len > rv) { sprintf (buf, "%s", expr -> data.variable); return rv; } break; case expr_known: s = "known"; astring: rv = strlen (s); if (len > rv) { strcpy (buf, s); return rv; } break; case expr_leased_address: s = "leased-address"; goto astring; case expr_client_state: s = "client-state"; goto astring; case expr_host_decl_name: s = "host-decl-name"; goto astring; case expr_lease_time: s = "lease-time"; goto astring; case expr_static: s = "static"; goto astring; case expr_filename: s = "filename"; goto astring; case expr_sname: s = "server-name"; goto astring; case expr_reverse: if (len > 11) { rv = 13; strcpy (buf, "(reverse "); rv += print_subexpression (expr -> data.reverse.width, buf + rv, len - rv - 2); buf [rv++] = ' '; rv += print_subexpression (expr -> data.reverse.buffer, buf + rv, len - rv - 1); buf [rv++] = ')'; buf [rv] = 0; return rv; } break; case expr_binary_to_ascii: if (len > 5) { rv = 9; strcpy (buf, "(b2a "); rv += print_subexpression (expr -> data.b2a.base, buf + rv, len - rv - 4); buf [rv++] = ' '; rv += print_subexpression (expr -> data.b2a.width, buf + rv, len - rv - 3); buf [rv++] = ' '; rv += print_subexpression (expr -> data.b2a.separator, buf + rv, len - rv - 2); buf [rv++] = ' '; rv += print_subexpression (expr -> data.b2a.buffer, buf + rv, len - rv - 1); buf [rv++] = ')'; buf [rv] = 0; return rv; } break; case expr_dns_transaction: rv = 10; if (len < rv + 2) { buf [0] = '('; strcpy (&buf [1], "ns-update "); while (len < rv + 2) { rv += print_subexpression (expr -> data.dns_transaction.car, buf + rv, len - rv - 2); buf [rv++] = ' '; expr = expr -> data.dns_transaction.cdr; } buf [rv - 1] = ')'; buf [rv] = 0; return rv; } return 0; case expr_ns_delete: s = "delete"; left = 4; goto dodnsupd; case expr_ns_exists: s = "exists"; left = 4; goto dodnsupd; case expr_ns_not_exists: s = "not_exists"; left = 4; goto dodnsupd; case expr_ns_add: s = "update"; left = 5; dodnsupd: rv = strlen (s); if (len > strlen (s) + 1) { buf [0] = '('; strcpy (buf + 1, s); rv++; buf [rv++] = ' '; s = print_dec_1 (expr -> data.ns_add.rrclass); if (len > rv + strlen (s) + left) { strcpy (&buf [rv], s); rv += strlen (&buf [rv]); } buf [rv++] = ' '; left--; s = print_dec_1 (expr -> data.ns_add.rrtype); if (len > rv + strlen (s) + left) { strcpy (&buf [rv], s); rv += strlen (&buf [rv]); } buf [rv++] = ' '; left--; rv += print_subexpression (expr -> data.ns_add.rrname, buf + rv, len - rv - left); buf [rv++] = ' '; left--; rv += print_subexpression (expr -> data.ns_add.rrdata, buf + rv, len - rv - left); buf [rv++] = ' '; left--; rv += print_subexpression (expr -> data.ns_add.ttl, buf + rv, len - rv - left); buf [rv++] = ')'; buf [rv] = 0; return rv; } break; case expr_null: if (len > 6) { strcpy (buf, "(null)"); return 6; } break; case expr_funcall: rv = 12 + strlen (expr -> data.funcall.name); if (len > rv + 1) { strcpy (buf, "(funcall "); strcpy (buf + 9, expr -> data.funcall.name); buf [rv++] = ' '; rv += print_subexpression (expr -> data.funcall.arglist, buf + rv, len - rv - 1); buf [rv++] = ')'; buf [rv] = 0; return rv; } break; case expr_arg: rv = print_subexpression (expr -> data.arg.val, buf, len); if (expr -> data.arg.next && rv + 2 < len) { buf [rv++] = ' '; rv += print_subexpression (expr -> data.arg.next, buf, len); if (rv + 1 < len) buf [rv++] = 0; return rv; } break; case expr_function: rv = 9; if (len > rv + 1) { struct string_list *foo; strcpy (buf, "(function"); for (foo = expr -> data.func -> args; foo; foo = foo -> next) { if (len > rv + 2 + strlen (foo -> string)) { buf [rv - 1] = ' '; strcpy (&buf [rv], foo -> string); rv += strlen (foo -> string); } } buf [rv++] = ')'; buf [rv] = 0; return rv; } case expr_gethostname: if (len > 13) { strcpy(buf, "(gethostname)"); return 13; } break; default: log_fatal("Impossible case at %s:%d (undefined expression " "%d).", MDL, expr->op); break; } return 0; } void print_expression (name, expr) const char *name; struct expression *expr; { char buf [1024]; print_subexpression (expr, buf, sizeof buf); log_info ("%s: %s", name, buf); } int token_print_indent_concat (FILE *file, int col, int indent, const char *prefix, const char *suffix, ...) { va_list list; unsigned len; char *s, *t, *u; va_start (list, suffix); s = va_arg (list, char *); len = 0; while (s) { len += strlen (s); s = va_arg (list, char *); } va_end (list); t = dmalloc (len + 1, MDL); if (!t) log_fatal ("token_print_indent: no memory for copy buffer"); va_start (list, suffix); s = va_arg (list, char *); u = t; while (s) { len = strlen (s); strcpy (u, s); u += len; s = va_arg (list, char *); } va_end (list); len = token_print_indent (file, col, indent, prefix, suffix, t); dfree (t, MDL); return col; } int token_indent_data_string (FILE *file, int col, int indent, const char *prefix, const char *suffix, struct data_string *data) { int i; char *buf; char obuf [3]; /* See if this is just ASCII. */ for (i = 0; i < data -> len; i++) if (!isascii (data -> data [i]) || !isprint (data -> data [i])) break; /* If we have a purely ASCII string, output it as text. */ if (i == data -> len) { buf = dmalloc (data -> len + 3, MDL); if (buf) { buf [0] = '"'; memcpy (buf + 1, data -> data, data -> len); buf [data -> len + 1] = '"'; buf [data -> len + 2] = 0; i = token_print_indent (file, col, indent, prefix, suffix, buf); dfree (buf, MDL); return i; } } for (i = 0; i < data -> len; i++) { sprintf (obuf, "%2.2x", data -> data [i]); col = token_print_indent (file, col, indent, i == 0 ? prefix : "", (i + 1 == data -> len ? suffix : ""), obuf); if (i + 1 != data -> len) col = token_print_indent (file, col, indent, prefix, suffix, ":"); } return col; } int token_print_indent (FILE *file, int col, int indent, const char *prefix, const char *suffix, const char *buf) { int len = strlen (buf) + strlen (prefix); if (col + len > 79) { if (indent + len < 79) { indent_spaces (file, indent); col = indent; } else { indent_spaces (file, col); col = len > 79 ? 0 : 79 - len - 1; } } else if (prefix && *prefix) { fputs (prefix, file); col += strlen (prefix); } fputs (buf, file); col += len; if (suffix && *suffix) { if (col + strlen (suffix) > 79) { indent_spaces (file, indent); col = indent; } else { fputs (suffix, file); col += strlen (suffix); } } return col; } void indent_spaces (FILE *file, int indent) { int i; fputc ('\n', file); for (i = 0; i < indent; i++) fputc (' ', file); } #if defined (NSUPDATE) #if defined (DEBUG_DNS_UPDATES) /* * direction outbound (messages to the dns server) * inbound (messages from the dns server) * ddns_cb is the control block associated with the message * result is the result from the dns code. For outbound calls * it is from the call to pass the message to the dns library. * For inbound calls it is from the event returned by the library. * * For outbound messages we print whatever we think is interesting * from the control block. * For inbound messages we only print the transaction id pointer * and the result and expect that the user will match them up as * necessary. Note well: the transaction information is opaque to * us so we simply print the pointer to it. This should be sufficient * to match requests and replys in a short sequence but is awkward * when trying to use it for longer sequences. */ void print_dns_status (int direction, struct dhcp_ddns_cb *ddns_cb, isc_result_t result) { char obuf[1024]; char *s = obuf, *end = &obuf[sizeof(obuf)-2]; char *en; const char *result_str; char ddns_address[ sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")]; if (direction == DDNS_PRINT_INBOUND) { log_info("DDNS reply: id ptr %p, result: %s", ddns_cb->transaction, isc_result_totext(result)); return; } /* * To avoid having to figure out if any of the strings * aren't NULL terminated, just 0 the whole string */ memset(obuf, 0, 1024); en = "DDNS request: id ptr "; if (s + strlen(en) + 16 < end) { sprintf(s, "%s%p", en, ddns_cb->transaction); s += strlen(s); } else { goto bailout; } switch (ddns_cb->state) { case DDNS_STATE_ADD_FW_NXDOMAIN: en = " add forward "; break; case DDNS_STATE_ADD_FW_YXDHCID: en = " modify forward "; break; case DDNS_STATE_ADD_PTR: en = " add reverse "; break; case DDNS_STATE_REM_FW_YXDHCID: en = " remove forward "; break; case DDNS_STATE_REM_FW_NXRR: en = " remove rrset "; break; case DDNS_STATE_REM_PTR: en = " remove reverse "; break; case DDNS_STATE_CLEANUP: en = " cleanup "; break; default: en = " unknown state "; break; } switch (ddns_cb->state) { case DDNS_STATE_ADD_FW_NXDOMAIN: case DDNS_STATE_ADD_FW_YXDHCID: case DDNS_STATE_REM_FW_YXDHCID: case DDNS_STATE_REM_FW_NXRR: strcpy(ddns_address, piaddr(ddns_cb->address)); if (s + strlen(en) + strlen(ddns_address) + ddns_cb->fwd_name.len + 5 < end) { sprintf(s, "%s%s for %.*s", en, ddns_address, ddns_cb->fwd_name.len, ddns_cb->fwd_name.data); s += strlen(s); } else { goto bailout; } break; case DDNS_STATE_ADD_PTR: case DDNS_STATE_REM_PTR: if (s + strlen(en) + ddns_cb->fwd_name.len + ddns_cb->rev_name.len + 5 < end) { sprintf(s, "%s%.*s for %.*s", en, ddns_cb->fwd_name.len, ddns_cb->fwd_name.data, ddns_cb->rev_name.len, ddns_cb->rev_name.data); s += strlen(s); } else { goto bailout; } break; case DDNS_STATE_CLEANUP: default: if (s + strlen(en) < end) { sprintf(s, "%s", en); s += strlen(s); } else { goto bailout; } break; } en = " zone: "; if (s + strlen(en) + strlen((char *)ddns_cb->zone_name) < end) { sprintf(s, "%s%s", en, ddns_cb->zone_name); s += strlen(s); } else { goto bailout; } en = " dhcid: "; if (ddns_cb->dhcid.len > 0) { if (s + strlen(en) + ddns_cb->dhcid.len-1 < end) { strcpy(s, en); s += strlen(s); strncpy(s, (char *)ddns_cb->dhcid.data+1, ddns_cb->dhcid.len-1); s += strlen(s); } else { goto bailout; } } else { en = " dhcid: "; if (s + strlen(en) < end) { strcpy(s, en); s += strlen(s); } else { goto bailout; } } en = " ttl: "; if (s + strlen(en) + 10 < end) { sprintf(s, "%s%ld", en, ddns_cb->ttl); s += strlen(s); } else { goto bailout; } en = " result: "; result_str = isc_result_totext(result); if (s + strlen(en) + strlen(result_str) < end) { sprintf(s, "%s%s", en, result_str); s += strlen(s); } else { goto bailout; } bailout: /* * We either finished building the string or ran out * of space, print whatever we have in case it is useful */ log_info("%s", obuf); return; } #endif #endif /* NSUPDATE */ /* Format the given time as "A; # B", where A is the format * used by the parser, and B is the local time, for humans. */ const char * print_time(TIME t) { static char buf[sizeof("epoch 9223372036854775807; " "# Wed Jun 30 21:49:08 2147483647")]; static char buf1[sizeof("# Wed Jun 30 21:49:08 2147483647")]; time_t since_epoch; /* The string: "6 2147483647/12/31 23:59:60;" * is smaller than the other, used to declare the buffer size, so * we can use one buffer for both. */ if (t == MAX_TIME) return "never;"; if (t < 0) return NULL; /* For those lucky enough to have a 128-bit time_t, ensure that * whatever (corrupt) value we're given doesn't exceed the static * buffer. */ #if (MAX_TIME > 0x7fffffffffffffff) if (t > 0x7fffffffffffffff) return NULL; #endif if (db_time_format == LOCAL_TIME_FORMAT) { since_epoch = mktime(localtime(&t)); if ((strftime(buf1, sizeof(buf1), "# %a %b %d %H:%M:%S %Y", localtime(&t)) == 0) || (snprintf(buf, sizeof(buf), "epoch %lu; %s", (unsigned long)since_epoch, buf1) >= sizeof(buf))) return NULL; } else { /* No bounds check for the year is necessary - in this case, * strftime() will run out of space and assert an error. */ if (strftime(buf, sizeof(buf), "%w %Y/%m/%d %H:%M:%S;", gmtime(&t)) == 0) return NULL; } return buf; } dhcp-4.2.4/common/raw.c000644 000765 000024 00000010572 11301372615 014620 0ustar00sarstaff000000 000000 /* raw.c BSD raw socket interface code... */ /* XXX It's not clear how this should work, and that lack of clarity is terribly detrimental to the NetBSD 1.1 kernel - it crashes and burns. Using raw sockets ought to be a big win over using BPF or something like it, because you don't need to deal with the complexities of the physical layer, but it appears not to be possible with existing raw socket implementations. This may be worth revisiting in the future. For now, this code can probably be considered a curiosity. Sigh. */ /* * Copyright (c) 2004,2007,2009 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1995-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ * * This software has been written for Internet Systems Consortium * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. * To learn more about Internet Systems Consortium, see * ``https://www.isc.org/''. To learn more about Vixie Enterprises, * see ``http://www.vix.com''. To learn more about Nominum, Inc., see * ``http://www.nominum.com''. */ #include "dhcpd.h" #if defined (USE_RAW_SEND) #include /* Generic interface registration routine... */ void if_register_send (info) struct interface_info *info; { struct sockaddr_in name; int sock; struct socklist *tmp; int flag; /* Set up the address we're going to connect to. */ name.sin_family = AF_INET; name.sin_port = local_port; name.sin_addr.s_addr = htonl (INADDR_BROADCAST); memset (name.sin_zero, 0, sizeof (name.sin_zero)); /* List addresses on which we're listening. */ if (!quiet_interface_discovery) log_info ("Sending on %s, port %d", piaddr (info -> address), htons (local_port)); if ((sock = socket (AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) log_fatal ("Can't create dhcp socket: %m"); /* Set the BROADCAST option so that we can broadcast DHCP responses. */ flag = 1; if (setsockopt (sock, SOL_SOCKET, SO_BROADCAST, &flag, sizeof flag) < 0) log_fatal ("Can't set SO_BROADCAST option on dhcp socket: %m"); /* Set the IP_HDRINCL flag so that we can supply our own IP headers... */ if (setsockopt (sock, IPPROTO_IP, IP_HDRINCL, &flag, sizeof flag) < 0) log_fatal ("Can't set IP_HDRINCL flag: %m"); info -> wfdesc = sock; if (!quiet_interface_discovery) log_info ("Sending on Raw/%s%s%s", info -> name, (info -> shared_network ? "/" : ""), (info -> shared_network ? info -> shared_network -> name : "")); } void if_deregister_send (info) struct interface_info *info; { close (info -> wfdesc); info -> wfdesc = -1; if (!quiet_interface_discovery) log_info ("Disabling output on Raw/%s%s%s", info -> name, (info -> shared_network ? "/" : ""), (info -> shared_network ? info -> shared_network -> name : "")); } size_t send_packet (interface, packet, raw, len, from, to, hto) struct interface_info *interface; struct packet *packet; struct dhcp_packet *raw; size_t len; struct in_addr from; struct sockaddr_in *to; struct hardware *hto; { unsigned char buf [256]; int bufp = 0; struct iovec iov [2]; int result; /* Assemble the headers... */ assemble_udp_ip_header (interface, buf, &bufp, from.s_addr, to -> sin_addr.s_addr, to -> sin_port, (unsigned char *)raw, len); /* Fire it off */ iov [0].iov_base = (char *)buf; iov [0].iov_len = bufp; iov [1].iov_base = (char *)raw; iov [1].iov_len = len; result = writev(interface -> wfdesc, iov, 2); if (result < 0) log_error ("send_packet: %m"); return result; } #endif /* USE_SOCKET_SEND */ dhcp-4.2.4/common/resolv.c000644 000765 000024 00000012322 11301372615 015334 0ustar00sarstaff000000 000000 /* resolv.c Parser for /etc/resolv.conf file. */ /* * Copyright (c) 2004-2007,2009 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1996-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ * * This software has been written for Internet Systems Consortium * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. * To learn more about Internet Systems Consortium, see * ``https://www.isc.org/''. To learn more about Vixie Enterprises, * see ``http://www.vix.com''. To learn more about Nominum, Inc., see * ``http://www.nominum.com''. */ #include "dhcpd.h" struct name_server *name_servers; struct domain_search_list *domains; char path_resolv_conf [] = _PATH_RESOLV_CONF; void read_resolv_conf (parse_time) TIME parse_time; { int file; struct parse *cfile; const char *val; int token; struct name_server *sp, *sl, *ns; struct domain_search_list *dp, *dl, *nd; isc_result_t status; if ((file = open (path_resolv_conf, O_RDONLY)) < 0) { log_error ("Can't open %s: %m", path_resolv_conf); return; } cfile = NULL; status = new_parse(&cfile, file, NULL, 0, path_resolv_conf, 1); if (status != ISC_R_SUCCESS || cfile == NULL) return; do { token = next_token (&val, (unsigned *)0, cfile); if (token == END_OF_FILE) break; else if (token == EOL) continue; else if (token == DOMAIN || token == SEARCH) { do { struct domain_search_list *nd, **dp; char *dn; dn = parse_host_name (cfile); if (!dn) break; dp = &domains; for (nd = domains; nd; nd = nd -> next) { dp = &nd -> next; if (!strcmp (nd -> domain, dn)) break; } if (!nd) { nd = new_domain_search_list (MDL); if (!nd) log_fatal ("No memory for %s", dn); nd -> next = (struct domain_search_list *)0; *dp = nd; nd -> domain = dn; dn = (char *)0; } nd -> rcdate = parse_time; token = peek_token (&val, (unsigned *)0, cfile); } while (token != EOL); if (token != EOL) { parse_warn (cfile, "junk after domain declaration"); skip_to_semi (cfile); } token = next_token (&val, (unsigned *)0, cfile); } else if (token == NAMESERVER) { struct name_server *ns, **sp; struct iaddr iaddr; parse_ip_addr (cfile, &iaddr); sp = &name_servers; for (ns = name_servers; ns; ns = ns -> next) { sp = &ns -> next; if (!memcmp (&ns -> addr.sin_addr, iaddr.iabuf, iaddr.len)) break; } if (!ns) { ns = new_name_server (MDL); if (!ns) log_fatal ("No memory for nameserver %s", piaddr (iaddr)); ns -> next = (struct name_server *)0; *sp = ns; memcpy (&ns -> addr.sin_addr, iaddr.iabuf, iaddr.len); #ifdef HAVE_SA_LEN ns -> addr.sin_len = sizeof ns -> addr; #endif ns -> addr.sin_family = AF_INET; ns -> addr.sin_port = htons (53); memset (ns -> addr.sin_zero, 0, sizeof ns -> addr.sin_zero); } ns -> rcdate = parse_time; skip_to_semi (cfile); } else skip_to_semi (cfile); /* Ignore what we don't grok. */ } while (1); token = next_token (&val, (unsigned *)0, cfile); /* Lose servers that are no longer in /etc/resolv.conf. */ sl = (struct name_server *)0; for (sp = name_servers; sp; sp = ns) { ns = sp -> next; if (sp -> rcdate != parse_time) { if (sl) sl -> next = sp -> next; else name_servers = sp -> next; /* We can't actually free the name server structure, because somebody might be hanging on to it. If your /etc/resolv.conf file changes a lot, this could be a noticeable memory leak. */ } else sl = sp; } /* Lose domains that are no longer in /etc/resolv.conf. */ dl = (struct domain_search_list *)0; for (dp = domains; dp; dp = nd) { nd = dp -> next; if (dp -> rcdate != parse_time) { if (dl) dl -> next = dp -> next; else domains = dp -> next; free_domain_search_list (dp, MDL); } else dl = dp; } end_parse (&cfile); } /* Pick a name server from the /etc/resolv.conf file. */ struct name_server *first_name_server () { static TIME rcdate; struct stat st; /* Check /etc/resolv.conf and reload it if it's changed. */ if (cur_time > rcdate) { if (stat (path_resolv_conf, &st) < 0) { log_error ("Can't stat %s", path_resolv_conf); return (struct name_server *)0; } if (st.st_mtime > rcdate) { rcdate = cur_time + 1; read_resolv_conf (rcdate); } } return name_servers; } dhcp-4.2.4/common/socket.c000644 000765 000024 00000075277 11726364513 015345 0ustar00sarstaff000000 000000 /* socket.c BSD socket interface code... */ /* * Copyright (c) 2004-2012 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1995-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ * * This software has been written for Internet Systems Consortium * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. * To learn more about Internet Systems Consortium, see * ``https://www.isc.org/''. To learn more about Vixie Enterprises, * see ``http://www.vix.com''. To learn more about Nominum, Inc., see * ``http://www.nominum.com''. */ /* SO_BINDTODEVICE support added by Elliot Poger (poger@leland.stanford.edu). * This sockopt allows a socket to be bound to a particular interface, * thus enabling the use of DHCPD on a multihomed host. * If SO_BINDTODEVICE is defined in your system header files, the use of * this sockopt will be automatically enabled. * I have implemented it under Linux; other systems should be doable also. */ #include "dhcpd.h" #include #include #include #include #if defined(sun) && defined(USE_V4_PKTINFO) #include #include #include #include #include #endif #ifdef USE_SOCKET_FALLBACK # if !defined (USE_SOCKET_SEND) # define if_register_send if_register_fallback # define send_packet send_fallback # define if_reinitialize_send if_reinitialize_fallback # endif #endif #if defined(DHCPv6) /* * XXX: this is gross. we need to go back and overhaul the API for socket * handling. */ static unsigned int global_v6_socket_references = 0; static int global_v6_socket = -1; static void if_register_multicast(struct interface_info *info); #endif /* * We can use a single socket for AF_INET (similar to AF_INET6) on all * interfaces configured for DHCP if the system has support for IP_PKTINFO * and IP_RECVPKTINFO (for example Solaris 11). */ #if defined(IP_PKTINFO) && defined(IP_RECVPKTINFO) && defined(USE_V4_PKTINFO) static unsigned int global_v4_socket_references = 0; static int global_v4_socket = -1; #endif /* * If we can't bind() to a specific interface, then we can only have * a single socket. This variable insures that we don't try to listen * on two sockets. */ #if !defined(SO_BINDTODEVICE) && !defined(USE_FALLBACK) static int once = 0; #endif /* !defined(SO_BINDTODEVICE) && !defined(USE_FALLBACK) */ /* Reinitializes the specified interface after an address change. This is not required for packet-filter APIs. */ #if defined (USE_SOCKET_SEND) || defined (USE_SOCKET_FALLBACK) void if_reinitialize_send (info) struct interface_info *info; { #if 0 #ifndef USE_SOCKET_RECEIVE once = 0; close (info -> wfdesc); #endif if_register_send (info); #endif } #endif #ifdef USE_SOCKET_RECEIVE void if_reinitialize_receive (info) struct interface_info *info; { #if 0 once = 0; close (info -> rfdesc); if_register_receive (info); #endif } #endif #if defined (USE_SOCKET_SEND) || \ defined (USE_SOCKET_RECEIVE) || \ defined (USE_SOCKET_FALLBACK) /* Generic interface registration routine... */ int if_register_socket(struct interface_info *info, int family, int *do_multicast) { struct sockaddr_storage name; int name_len; int sock; int flag; int domain; #ifdef DHCPv6 struct sockaddr_in6 *addr6; #endif struct sockaddr_in *addr; /* INSIST((family == AF_INET) || (family == AF_INET6)); */ #if !defined(SO_BINDTODEVICE) && !defined(USE_FALLBACK) /* Make sure only one interface is registered. */ if (once) { log_fatal ("The standard socket API can only support %s", "hosts with a single network interface."); } once = 1; #endif /* * Set up the address we're going to bind to, depending on the * address family. */ memset(&name, 0, sizeof(name)); switch (family) { #ifdef DHCPv6 case AF_INET6: addr6 = (struct sockaddr_in6 *)&name; addr6->sin6_family = AF_INET6; addr6->sin6_port = local_port; /* XXX: What will happen to multicasts if this is nonzero? */ memcpy(&addr6->sin6_addr, &local_address6, sizeof(addr6->sin6_addr)); #ifdef HAVE_SA_LEN addr6->sin6_len = sizeof(*addr6); #endif name_len = sizeof(*addr6); domain = PF_INET6; if ((info->flags & INTERFACE_STREAMS) == INTERFACE_UPSTREAM) { *do_multicast = 0; } break; #endif /* DHCPv6 */ case AF_INET: default: addr = (struct sockaddr_in *)&name; addr->sin_family = AF_INET; addr->sin_port = local_port; memcpy(&addr->sin_addr, &local_address, sizeof(addr->sin_addr)); #ifdef HAVE_SA_LEN addr->sin_len = sizeof(*addr); #endif name_len = sizeof(*addr); domain = PF_INET; break; } /* Make a socket... */ sock = socket(domain, SOCK_DGRAM, IPPROTO_UDP); if (sock < 0) { log_fatal("Can't create dhcp socket: %m"); } /* Set the REUSEADDR option so that we don't fail to start if we're being restarted. */ flag = 1; if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&flag, sizeof(flag)) < 0) { log_fatal("Can't set SO_REUSEADDR option on dhcp socket: %m"); } /* Set the BROADCAST option so that we can broadcast DHCP responses. We shouldn't do this for fallback devices, and we can detect that a device is a fallback because it has no ifp structure. */ if (info->ifp && (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char *)&flag, sizeof(flag)) < 0)) { log_fatal("Can't set SO_BROADCAST option on dhcp socket: %m"); } #if defined(DHCPv6) && defined(SO_REUSEPORT) /* * We only set SO_REUSEPORT on AF_INET6 sockets, so that multiple * daemons can bind to their own sockets and get data for their * respective interfaces. This does not (and should not) affect * DHCPv4 sockets; we can't yet support BSD sockets well, much * less multiple sockets. */ if (local_family == AF_INET6) { flag = 1; if (setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, (char *)&flag, sizeof(flag)) < 0) { log_fatal("Can't set SO_REUSEPORT option on dhcp " "socket: %m"); } } #endif /* Bind the socket to this interface's IP address. */ if (bind(sock, (struct sockaddr *)&name, name_len) < 0) { log_error("Can't bind to dhcp address: %m"); log_error("Please make sure there is no other dhcp server"); log_error("running and that there's no entry for dhcp or"); log_error("bootp in /etc/inetd.conf. Also make sure you"); log_error("are not running HP JetAdmin software, which"); log_fatal("includes a bootp server."); } #if defined(SO_BINDTODEVICE) /* Bind this socket to this interface. */ if ((local_family != AF_INET6) && (info->ifp != NULL) && setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, (char *)(info -> ifp), sizeof(*(info -> ifp))) < 0) { log_fatal("setsockopt: SO_BINDTODEVICE: %m"); } #endif /* IP_BROADCAST_IF instructs the kernel which interface to send * IP packets whose destination address is 255.255.255.255. These * will be treated as subnet broadcasts on the interface identified * by ip address (info -> primary_address). This is only known to * be defined in SCO system headers, and may not be defined in all * releases. */ #if defined(SCO) && defined(IP_BROADCAST_IF) if (info->address_count && setsockopt(sock, IPPROTO_IP, IP_BROADCAST_IF, &info->addresses[0], sizeof(info->addresses[0])) < 0) log_fatal("Can't set IP_BROADCAST_IF on dhcp socket: %m"); #endif #if defined(IP_PKTINFO) && defined(IP_RECVPKTINFO) && defined(USE_V4_PKTINFO) /* * If we turn on IP_RECVPKTINFO we will be able to receive * the interface index information of the received packet. */ if (family == AF_INET) { int on = 1; if (setsockopt(sock, IPPROTO_IP, IP_RECVPKTINFO, &on, sizeof(on)) != 0) { log_fatal("setsockopt: IPV_RECVPKTINFO: %m"); } } #endif #ifdef DHCPv6 /* * If we turn on IPV6_PKTINFO, we will be able to receive * additional information, such as the destination IP address. * We need this to spot unicast packets. */ if (family == AF_INET6) { int on = 1; #ifdef IPV6_RECVPKTINFO /* RFC3542 */ if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on)) != 0) { log_fatal("setsockopt: IPV6_RECVPKTINFO: %m"); } #else /* RFC2292 */ if (setsockopt(sock, IPPROTO_IPV6, IPV6_PKTINFO, &on, sizeof(on)) != 0) { log_fatal("setsockopt: IPV6_PKTINFO: %m"); } #endif } if ((family == AF_INET6) && ((info->flags & INTERFACE_UPSTREAM) != 0)) { int hop_limit = 32; if (setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &hop_limit, sizeof(int)) < 0) { log_fatal("setsockopt: IPV6_MULTICAST_HOPS: %m"); } } #endif /* DHCPv6 */ return sock; } #endif /* USE_SOCKET_SEND || USE_SOCKET_RECEIVE || USE_SOCKET_FALLBACK */ #if defined (USE_SOCKET_SEND) || defined (USE_SOCKET_FALLBACK) void if_register_send (info) struct interface_info *info; { #ifndef USE_SOCKET_RECEIVE info->wfdesc = if_register_socket(info, AF_INET, 0); /* If this is a normal IPv4 address, get the hardware address. */ if (strcmp(info->name, "fallback") != 0) get_hw_addr(info->name, &info->hw_address); #if defined (USE_SOCKET_FALLBACK) /* Fallback only registers for send, but may need to receive as well. */ info->rfdesc = info->wfdesc; #endif #else info->wfdesc = info->rfdesc; #endif if (!quiet_interface_discovery) log_info ("Sending on Socket/%s%s%s", info->name, (info->shared_network ? "/" : ""), (info->shared_network ? info->shared_network->name : "")); } #if defined (USE_SOCKET_SEND) void if_deregister_send (info) struct interface_info *info; { #ifndef USE_SOCKET_RECEIVE close (info -> wfdesc); #endif info -> wfdesc = -1; if (!quiet_interface_discovery) log_info ("Disabling output on Socket/%s%s%s", info -> name, (info -> shared_network ? "/" : ""), (info -> shared_network ? info -> shared_network -> name : "")); } #endif /* USE_SOCKET_SEND */ #endif /* USE_SOCKET_SEND || USE_SOCKET_FALLBACK */ #ifdef USE_SOCKET_RECEIVE void if_register_receive (info) struct interface_info *info; { #if defined(IP_PKTINFO) && defined(IP_RECVPKTINFO) && defined(USE_V4_PKTINFO) if (global_v4_socket_references == 0) { global_v4_socket = if_register_socket(info, AF_INET, 0); if (global_v4_socket < 0) { /* * if_register_socket() fatally logs if it fails to * create a socket, this is just a sanity check. */ log_fatal("Failed to create AF_INET socket %s:%d", MDL); } } info->rfdesc = global_v4_socket; global_v4_socket_references++; #else /* If we're using the socket API for sending and receiving, we don't need to register this interface twice. */ info->rfdesc = if_register_socket(info, AF_INET, 0); #endif /* IP_PKTINFO... */ /* If this is a normal IPv4 address, get the hardware address. */ if (strcmp(info->name, "fallback") != 0) get_hw_addr(info->name, &info->hw_address); if (!quiet_interface_discovery) log_info ("Listening on Socket/%s%s%s", info->name, (info->shared_network ? "/" : ""), (info->shared_network ? info->shared_network->name : "")); } void if_deregister_receive (info) struct interface_info *info; { #if defined(IP_PKTINFO) && defined(IP_RECVPKTINFO) && defined(USE_V4_PKTINFO) /* Dereference the global v4 socket. */ if ((info->rfdesc == global_v4_socket) && (info->wfdesc == global_v4_socket) && (global_v4_socket_references > 0)) { global_v4_socket_references--; info->rfdesc = -1; } else { log_fatal("Impossible condition at %s:%d", MDL); } if (global_v4_socket_references == 0) { close(global_v4_socket); global_v4_socket = -1; } #else close(info->rfdesc); info->rfdesc = -1; #endif /* IP_PKTINFO... */ if (!quiet_interface_discovery) log_info ("Disabling input on Socket/%s%s%s", info -> name, (info -> shared_network ? "/" : ""), (info -> shared_network ? info -> shared_network -> name : "")); } #endif /* USE_SOCKET_RECEIVE */ #ifdef DHCPv6 /* * This function joins the interface to DHCPv6 multicast groups so we will * receive multicast messages. */ static void if_register_multicast(struct interface_info *info) { int sock = info->rfdesc; struct ipv6_mreq mreq; if (inet_pton(AF_INET6, All_DHCP_Relay_Agents_and_Servers, &mreq.ipv6mr_multiaddr) <= 0) { log_fatal("inet_pton: unable to convert '%s'", All_DHCP_Relay_Agents_and_Servers); } mreq.ipv6mr_interface = if_nametoindex(info->name); if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) < 0) { log_fatal("setsockopt: IPV6_JOIN_GROUP: %m"); } /* * The relay agent code sets the streams so you know which way * is up and down. But a relay agent shouldn't join to the * Server address, or else you get fun loops. So up or down * doesn't matter, we're just using that config to sense this is * a relay agent. */ if ((info->flags & INTERFACE_STREAMS) == 0) { if (inet_pton(AF_INET6, All_DHCP_Servers, &mreq.ipv6mr_multiaddr) <= 0) { log_fatal("inet_pton: unable to convert '%s'", All_DHCP_Servers); } mreq.ipv6mr_interface = if_nametoindex(info->name); if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) < 0) { log_fatal("setsockopt: IPV6_JOIN_GROUP: %m"); } } } void if_register6(struct interface_info *info, int do_multicast) { /* Bounce do_multicast to a stack variable because we may change it. */ int req_multi = do_multicast; if (global_v6_socket_references == 0) { global_v6_socket = if_register_socket(info, AF_INET6, &req_multi); if (global_v6_socket < 0) { /* * if_register_socket() fatally logs if it fails to * create a socket, this is just a sanity check. */ log_fatal("Impossible condition at %s:%d", MDL); } else { log_info("Bound to *:%d", ntohs(local_port)); } } info->rfdesc = global_v6_socket; info->wfdesc = global_v6_socket; global_v6_socket_references++; if (req_multi) if_register_multicast(info); get_hw_addr(info->name, &info->hw_address); if (!quiet_interface_discovery) { if (info->shared_network != NULL) { log_info("Listening on Socket/%d/%s/%s", global_v6_socket, info->name, info->shared_network->name); log_info("Sending on Socket/%d/%s/%s", global_v6_socket, info->name, info->shared_network->name); } else { log_info("Listening on Socket/%s", info->name); log_info("Sending on Socket/%s", info->name); } } } void if_deregister6(struct interface_info *info) { /* Dereference the global v6 socket. */ if ((info->rfdesc == global_v6_socket) && (info->wfdesc == global_v6_socket) && (global_v6_socket_references > 0)) { global_v6_socket_references--; info->rfdesc = -1; info->wfdesc = -1; } else { log_fatal("Impossible condition at %s:%d", MDL); } if (!quiet_interface_discovery) { if (info->shared_network != NULL) { log_info("Disabling input on Socket/%s/%s", info->name, info->shared_network->name); log_info("Disabling output on Socket/%s/%s", info->name, info->shared_network->name); } else { log_info("Disabling input on Socket/%s", info->name); log_info("Disabling output on Socket/%s", info->name); } } if (global_v6_socket_references == 0) { close(global_v6_socket); global_v6_socket = -1; log_info("Unbound from *:%d", ntohs(local_port)); } } #endif /* DHCPv6 */ #if defined (USE_SOCKET_SEND) || defined (USE_SOCKET_FALLBACK) ssize_t send_packet (interface, packet, raw, len, from, to, hto) struct interface_info *interface; struct packet *packet; struct dhcp_packet *raw; size_t len; struct in_addr from; struct sockaddr_in *to; struct hardware *hto; { int result; #ifdef IGNORE_HOSTUNREACH int retry = 0; do { #endif #if defined(IP_PKTINFO) && defined(IP_RECVPKTINFO) && defined(USE_V4_PKTINFO) struct in_pktinfo pktinfo; if (interface->ifp != NULL) { memset(&pktinfo, 0, sizeof (pktinfo)); pktinfo.ipi_ifindex = interface->ifp->ifr_index; if (setsockopt(interface->wfdesc, IPPROTO_IP, IP_PKTINFO, (char *)&pktinfo, sizeof(pktinfo)) < 0) log_fatal("setsockopt: IP_PKTINFO: %m"); } #endif result = sendto (interface -> wfdesc, (char *)raw, len, 0, (struct sockaddr *)to, sizeof *to); #ifdef IGNORE_HOSTUNREACH } while (to -> sin_addr.s_addr == htonl (INADDR_BROADCAST) && result < 0 && (errno == EHOSTUNREACH || errno == ECONNREFUSED) && retry++ < 10); #endif if (result < 0) { log_error ("send_packet: %m"); if (errno == ENETUNREACH) log_error ("send_packet: please consult README file%s", " regarding broadcast address."); } return result; } #endif /* USE_SOCKET_SEND || USE_SOCKET_FALLBACK */ #ifdef DHCPv6 /* * Solaris 9 is missing the CMSG_LEN and CMSG_SPACE macros, so we will * synthesize them (based on the BIND 9 technique). */ #ifndef CMSG_LEN static size_t CMSG_LEN(size_t len) { size_t hdrlen; /* * Cast NULL so that any pointer arithmetic performed by CMSG_DATA * is correct. */ hdrlen = (size_t)CMSG_DATA(((struct cmsghdr *)NULL)); return hdrlen + len; } #endif /* !CMSG_LEN */ #ifndef CMSG_SPACE static size_t CMSG_SPACE(size_t len) { struct msghdr msg; struct cmsghdr *cmsgp; /* * XXX: The buffer length is an ad-hoc value, but should be enough * in a practical sense. */ union { struct cmsghdr cmsg_sizer; u_int8_t pktinfo_sizer[sizeof(struct cmsghdr) + 1024]; } dummybuf; memset(&msg, 0, sizeof(msg)); msg.msg_control = &dummybuf; msg.msg_controllen = sizeof(dummybuf); cmsgp = (struct cmsghdr *)&dummybuf; cmsgp->cmsg_len = CMSG_LEN(len); cmsgp = CMSG_NXTHDR(&msg, cmsgp); if (cmsgp != NULL) { return (char *)cmsgp - (char *)msg.msg_control; } else { return 0; } } #endif /* !CMSG_SPACE */ #endif /* DHCPv6 */ #if defined(DHCPv6) || \ (defined(IP_PKTINFO) && defined(IP_RECVPKTINFO) && \ defined(USE_V4_PKTINFO)) /* * For both send_packet6() and receive_packet6() we need to allocate * space for the cmsg header information. We do this once and reuse * the buffer. We also need the control buf for send_packet() and * receive_packet() when we use a single socket and IP_PKTINFO to * send the packet out the correct interface. */ static void *control_buf = NULL; static size_t control_buf_len = 0; static void allocate_cmsg_cbuf(void) { control_buf_len = CMSG_SPACE(sizeof(struct in6_pktinfo)); control_buf = dmalloc(control_buf_len, MDL); return; } #endif /* DHCPv6, IP_PKTINFO ... */ #ifdef DHCPv6 /* * For both send_packet6() and receive_packet6() we need to use the * sendmsg()/recvmsg() functions rather than the simpler send()/recv() * functions. * * In the case of send_packet6(), we need to do this in order to insure * that the reply packet leaves on the same interface that it arrived * on. * * In the case of receive_packet6(), we need to do this in order to * get the IP address the packet was sent to. This is used to identify * whether a packet is multicast or unicast. * * Helpful man pages: recvmsg, readv (talks about the iovec stuff), cmsg. * * Also see the sections in RFC 3542 about IPV6_PKTINFO. */ /* Send an IPv6 packet */ ssize_t send_packet6(struct interface_info *interface, const unsigned char *raw, size_t len, struct sockaddr_in6 *to) { struct msghdr m; struct iovec v; int result; struct in6_pktinfo *pktinfo; struct cmsghdr *cmsg; /* * If necessary allocate space for the control message header. * The space is common between send and receive. */ if (control_buf == NULL) { allocate_cmsg_cbuf(); if (control_buf == NULL) { log_error("send_packet6: unable to allocate cmsg header"); return(ENOMEM); } } memset(control_buf, 0, control_buf_len); /* * Initialize our message header structure. */ memset(&m, 0, sizeof(m)); /* * Set the target address we're sending to. */ m.msg_name = to; m.msg_namelen = sizeof(*to); /* * Set the data buffer we're sending. (Using this wacky * "scatter-gather" stuff... we only have a single chunk * of data to send, so we declare a single vector entry.) */ v.iov_base = (char *)raw; v.iov_len = len; m.msg_iov = &v; m.msg_iovlen = 1; /* * Setting the interface is a bit more involved. * * We have to create a "control message", and set that to * define the IPv6 packet information. We could set the * source address if we wanted, but we can safely let the * kernel decide what that should be. */ m.msg_control = control_buf; m.msg_controllen = control_buf_len; cmsg = CMSG_FIRSTHDR(&m); cmsg->cmsg_level = IPPROTO_IPV6; cmsg->cmsg_type = IPV6_PKTINFO; cmsg->cmsg_len = CMSG_LEN(sizeof(*pktinfo)); pktinfo = (struct in6_pktinfo *)CMSG_DATA(cmsg); memset(pktinfo, 0, sizeof(*pktinfo)); pktinfo->ipi6_ifindex = if_nametoindex(interface->name); m.msg_controllen = cmsg->cmsg_len; result = sendmsg(interface->wfdesc, &m, 0); if (result < 0) { log_error("send_packet6: %m"); } return result; } #endif /* DHCPv6 */ #ifdef USE_SOCKET_RECEIVE ssize_t receive_packet (interface, buf, len, from, hfrom) struct interface_info *interface; unsigned char *buf; size_t len; struct sockaddr_in *from; struct hardware *hfrom; { #if !(defined(IP_PKTINFO) && defined(IP_RECVPKTINFO) && defined(USE_V4_PKTINFO)) SOCKLEN_T flen = sizeof *from; #endif int result; /* * The normal Berkeley socket interface doesn't give us any way * to know what hardware interface we received the message on, * but we should at least make sure the structure is emptied. */ memset(hfrom, 0, sizeof(*hfrom)); #ifdef IGNORE_HOSTUNREACH int retry = 0; do { #endif #if defined(IP_PKTINFO) && defined(IP_RECVPKTINFO) && defined(USE_V4_PKTINFO) struct msghdr m; struct iovec v; struct cmsghdr *cmsg; struct in_pktinfo *pktinfo; unsigned int ifindex; /* * If necessary allocate space for the control message header. * The space is common between send and receive. */ if (control_buf == NULL) { allocate_cmsg_cbuf(); if (control_buf == NULL) { log_error("receive_packet: unable to allocate cmsg " "header"); return(ENOMEM); } } memset(control_buf, 0, control_buf_len); /* * Initialize our message header structure. */ memset(&m, 0, sizeof(m)); /* * Point so we can get the from address. */ m.msg_name = from; m.msg_namelen = sizeof(*from); /* * Set the data buffer we're receiving. (Using this wacky * "scatter-gather" stuff... but we that doesn't really make * sense for us, so we use a single vector entry.) */ v.iov_base = buf; v.iov_len = len; m.msg_iov = &v; m.msg_iovlen = 1; /* * Getting the interface is a bit more involved. * * We set up some space for a "control message". We have * previously asked the kernel to give us packet * information (when we initialized the interface), so we * should get the interface index from that. */ m.msg_control = control_buf; m.msg_controllen = control_buf_len; result = recvmsg(interface->rfdesc, &m, 0); if (result >= 0) { /* * If we did read successfully, then we need to loop * through the control messages we received and * find the one with our inteface index. */ cmsg = CMSG_FIRSTHDR(&m); while (cmsg != NULL) { if ((cmsg->cmsg_level == IPPROTO_IP) && (cmsg->cmsg_type == IP_PKTINFO)) { pktinfo = (struct in_pktinfo *)CMSG_DATA(cmsg); ifindex = pktinfo->ipi_ifindex; /* * We pass the ifindex back to the caller * using the unused hfrom parameter avoiding * interface changes between sockets and * the discover code. */ memcpy(hfrom->hbuf, &ifindex, sizeof(ifindex)); return (result); } cmsg = CMSG_NXTHDR(&m, cmsg); } /* * We didn't find the necessary control message * flag it as an error */ result = -1; errno = EIO; } #else result = recvfrom(interface -> rfdesc, (char *)buf, len, 0, (struct sockaddr *)from, &flen); #endif /* IP_PKTINFO ... */ #ifdef IGNORE_HOSTUNREACH } while (result < 0 && (errno == EHOSTUNREACH || errno == ECONNREFUSED) && retry++ < 10); #endif return (result); } #endif /* USE_SOCKET_RECEIVE */ #ifdef DHCPv6 ssize_t receive_packet6(struct interface_info *interface, unsigned char *buf, size_t len, struct sockaddr_in6 *from, struct in6_addr *to_addr, unsigned int *if_idx) { struct msghdr m; struct iovec v; int result; struct cmsghdr *cmsg; struct in6_pktinfo *pktinfo; /* * If necessary allocate space for the control message header. * The space is common between send and receive. */ if (control_buf == NULL) { allocate_cmsg_cbuf(); if (control_buf == NULL) { log_error("receive_packet6: unable to allocate cmsg " "header"); return(ENOMEM); } } memset(control_buf, 0, control_buf_len); /* * Initialize our message header structure. */ memset(&m, 0, sizeof(m)); /* * Point so we can get the from address. */ m.msg_name = from; m.msg_namelen = sizeof(*from); /* * Set the data buffer we're receiving. (Using this wacky * "scatter-gather" stuff... but we that doesn't really make * sense for us, so we use a single vector entry.) */ v.iov_base = buf; v.iov_len = len; m.msg_iov = &v; m.msg_iovlen = 1; /* * Getting the interface is a bit more involved. * * We set up some space for a "control message". We have * previously asked the kernel to give us packet * information (when we initialized the interface), so we * should get the destination address from that. */ m.msg_control = control_buf; m.msg_controllen = control_buf_len; result = recvmsg(interface->rfdesc, &m, 0); if (result >= 0) { /* * If we did read successfully, then we need to loop * through the control messages we received and * find the one with our destination address. */ cmsg = CMSG_FIRSTHDR(&m); while (cmsg != NULL) { if ((cmsg->cmsg_level == IPPROTO_IPV6) && (cmsg->cmsg_type == IPV6_PKTINFO)) { pktinfo = (struct in6_pktinfo *)CMSG_DATA(cmsg); *to_addr = pktinfo->ipi6_addr; *if_idx = pktinfo->ipi6_ifindex; return (result); } cmsg = CMSG_NXTHDR(&m, cmsg); } /* * We didn't find the necessary control message * flag is as an error */ result = -1; errno = EIO; } return (result); } #endif /* DHCPv6 */ #if defined (USE_SOCKET_FALLBACK) /* This just reads in a packet and silently discards it. */ isc_result_t fallback_discard (object) omapi_object_t *object; { char buf [1540]; struct sockaddr_in from; SOCKLEN_T flen = sizeof from; int status; struct interface_info *interface; if (object -> type != dhcp_type_interface) return DHCP_R_INVALIDARG; interface = (struct interface_info *)object; status = recvfrom (interface -> wfdesc, buf, sizeof buf, 0, (struct sockaddr *)&from, &flen); #if defined (DEBUG) /* Only report fallback discard errors if we're debugging. */ if (status < 0) { log_error ("fallback_discard: %m"); return ISC_R_UNEXPECTED; } #else /* ignore the fact that status value is never used */ IGNORE_UNUSED(status); #endif return ISC_R_SUCCESS; } #endif /* USE_SOCKET_FALLBACK */ #if defined (USE_SOCKET_SEND) int can_unicast_without_arp (ip) struct interface_info *ip; { return 0; } int can_receive_unicast_unconfigured (ip) struct interface_info *ip; { #if defined (SOCKET_CAN_RECEIVE_UNICAST_UNCONFIGURED) return 1; #else return 0; #endif } int supports_multiple_interfaces (ip) struct interface_info *ip; { #if defined(SO_BINDTODEVICE) || \ (defined(IP_PKTINFO) && defined(IP_RECVPKTINFO) && \ defined(USE_V4_PKTINFO)) return(1); #else return(0); #endif } /* If we have SO_BINDTODEVICE, set up a fallback interface; otherwise, do not. */ void maybe_setup_fallback () { #if defined (USE_SOCKET_FALLBACK) isc_result_t status; struct interface_info *fbi = (struct interface_info *)0; if (setup_fallback (&fbi, MDL)) { fbi -> wfdesc = if_register_socket (fbi, AF_INET, 0); fbi -> rfdesc = fbi -> wfdesc; log_info ("Sending on Socket/%s%s%s", fbi -> name, (fbi -> shared_network ? "/" : ""), (fbi -> shared_network ? fbi -> shared_network -> name : "")); status = omapi_register_io_object ((omapi_object_t *)fbi, if_readsocket, 0, fallback_discard, 0, 0); if (status != ISC_R_SUCCESS) log_fatal ("Can't register I/O handle for %s: %s", fbi -> name, isc_result_totext (status)); interface_dereference (&fbi, MDL); } #endif } #if defined(sun) && defined(USE_V4_PKTINFO) /* This code assumes the existence of SIOCGLIFHWADDR */ void get_hw_addr(const char *name, struct hardware *hw) { struct sockaddr_dl *dladdrp; int sock, i; struct lifreq lifr; memset(&lifr, 0, sizeof (lifr)); (void) strlcpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); /* * Check if the interface is a virtual or IPMP interface - in those * cases it has no hw address, so generate a random one. */ if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0 || ioctl(sock, SIOCGLIFFLAGS, &lifr) < 0) { if (sock != -1) (void) close(sock); #ifdef DHCPv6 /* * If approrpriate try this with an IPv6 socket */ if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) >= 0 && ioctl(sock, SIOCGLIFFLAGS, &lifr) >= 0) { goto flag_check; } if (sock != -1) (void) close(sock); #endif log_fatal("Couldn't get interface flags for %s: %m", name); } flag_check: if (lifr.lifr_flags & (IFF_VIRTUAL|IFF_IPMP)) { hw->hlen = sizeof (hw->hbuf); srandom((long)gethrtime()); hw->hbuf[0] = HTYPE_IPMP; for (i = 1; i < hw->hlen; ++i) { hw->hbuf[i] = random() % 256; } if (sock != -1) (void) close(sock); return; } if (ioctl(sock, SIOCGLIFHWADDR, &lifr) < 0) log_fatal("Couldn't get interface hardware address for %s: %m", name); dladdrp = (struct sockaddr_dl *)&lifr.lifr_addr; hw->hlen = dladdrp->sdl_alen+1; switch (dladdrp->sdl_type) { case DL_CSMACD: /* IEEE 802.3 */ case DL_ETHER: hw->hbuf[0] = HTYPE_ETHER; break; case DL_TPR: hw->hbuf[0] = HTYPE_IEEE802; break; case DL_FDDI: hw->hbuf[0] = HTYPE_FDDI; break; case DL_IB: hw->hbuf[0] = HTYPE_INFINIBAND; break; default: log_fatal("%s: unsupported DLPI MAC type %lu", name, (unsigned long)dladdrp->sdl_type); } memcpy(hw->hbuf+1, LLADDR(dladdrp), hw->hlen-1); if (sock != -1) (void) close(sock); } #endif /* defined(sun) */ #endif /* USE_SOCKET_SEND */ dhcp-4.2.4/common/tables.c000644 000765 000024 00000136425 11717270172 015315 0ustar00sarstaff000000 000000 /* tables.c Tables of information... */ /* * Copyright (c) 2011-2012 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 2004-2009 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1995-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ * * This software has been written for Internet Systems Consortium * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. * To learn more about Internet Systems Consortium, see * ``https://www.isc.org/''. To learn more about Vixie Enterprises, * see ``http://www.vix.com''. To learn more about Nominum, Inc., see * ``http://www.nominum.com''. */ #include "dhcpd.h" /* XXXDPN: Moved here from hash.c, when it moved to libomapi. Not sure where these really belong. */ HASH_FUNCTIONS (group, const char *, struct group_object, group_hash_t, group_reference, group_dereference, do_string_hash) HASH_FUNCTIONS (universe, const char *, struct universe, universe_hash_t, 0, 0, do_case_hash) HASH_FUNCTIONS (option_name, const char *, struct option, option_name_hash_t, option_reference, option_dereference, do_case_hash) HASH_FUNCTIONS (option_code, const unsigned *, struct option, option_code_hash_t, option_reference, option_dereference, do_number_hash) /* DHCP Option names, formats and codes, from RFC1533. Format codes: I - IPv4 address 6 - IPv6 address l - 32-bit signed integer L - 32-bit unsigned integer s - 16-bit signed integer S - 16-bit unsigned integer b - 8-bit signed integer B - 8-bit unsigned integer t - ASCII text T - Lease Time, 32-bit unsigned integer implying a number of seconds from some event. The special all-ones value means 'infinite'. May either be printed as a decimal, eg, "3600", or as this name, eg, "infinite". f - flag (true or false) A - array of whatever precedes (e.g., IA means array of IP addresses) a - array of the preceding character (e.g., IIa means two or more IP addresses) U - name of an option space (universe) F - implicit flag - the presence of the option indicates that the flag is true. o - the preceding value is optional. E - encapsulation, string or colon-separated hex list (the latter two for parsing). E is followed by a text string containing the name of the option space to encapsulate, followed by a '.'. If the E is immediately followed by '.', the applicable vendor option space is used if one is defined. e - If an encapsulation directive is not the first thing in the string, the option scanner requires an efficient way to find the encapsulation. This is done by placing a 'e' at the beginning of the option. The 'e' has no other purpose, and is not required if 'E' is the first thing in the option. X - either an ASCII string or binary data. On output, the string is scanned to see if it's printable ASCII and, if so, output as a quoted string. If not, it's output as colon-separated hex. On input, the option can be specified either as a quoted string or as a colon-separated hex list. N - enumeration. N is followed by a text string containing the name of the set of enumeration values to parse or emit, followed by a '.'. The width of the data is specified in the named enumeration. Named enumerations are tracked in parse.c. d - Domain name (i.e., FOO or FOO.BAR). D - Domain list (i.e., example.com eng.example.com) c - When following a 'D' atom, enables compression pointers. Z - Zero-length option */ struct universe dhcp_universe; static struct option dhcp_options[] = { { "subnet-mask", "I", &dhcp_universe, 1, 1 }, { "time-offset", "l", &dhcp_universe, 2, 1 }, { "routers", "IA", &dhcp_universe, 3, 1 }, { "time-servers", "IA", &dhcp_universe, 4, 1 }, { "ien116-name-servers", "IA", &dhcp_universe, 5, 1 }, { "domain-name-servers", "IA", &dhcp_universe, 6, 1 }, { "log-servers", "IA", &dhcp_universe, 7, 1 }, { "cookie-servers", "IA", &dhcp_universe, 8, 1 }, { "lpr-servers", "IA", &dhcp_universe, 9, 1 }, { "impress-servers", "IA", &dhcp_universe, 10, 1 }, { "resource-location-servers", "IA", &dhcp_universe, 11, 1 }, { "host-name", "t", &dhcp_universe, 12, 1 }, { "boot-size", "S", &dhcp_universe, 13, 1 }, { "merit-dump", "t", &dhcp_universe, 14, 1 }, { "domain-name", "t", &dhcp_universe, 15, 1 }, { "swap-server", "I", &dhcp_universe, 16, 1 }, { "root-path", "t", &dhcp_universe, 17, 1 }, { "extensions-path", "t", &dhcp_universe, 18, 1 }, { "ip-forwarding", "f", &dhcp_universe, 19, 1 }, { "non-local-source-routing", "f", &dhcp_universe, 20, 1 }, { "policy-filter", "IIA", &dhcp_universe, 21, 1 }, { "max-dgram-reassembly", "S", &dhcp_universe, 22, 1 }, { "default-ip-ttl", "B", &dhcp_universe, 23, 1 }, { "path-mtu-aging-timeout", "L", &dhcp_universe, 24, 1 }, { "path-mtu-plateau-table", "SA", &dhcp_universe, 25, 1 }, { "interface-mtu", "S", &dhcp_universe, 26, 1 }, { "all-subnets-local", "f", &dhcp_universe, 27, 1 }, { "broadcast-address", "I", &dhcp_universe, 28, 1 }, { "perform-mask-discovery", "f", &dhcp_universe, 29, 1 }, { "mask-supplier", "f", &dhcp_universe, 30, 1 }, { "router-discovery", "f", &dhcp_universe, 31, 1 }, { "router-solicitation-address", "I", &dhcp_universe, 32, 1 }, { "static-routes", "IIA", &dhcp_universe, 33, 1 }, { "trailer-encapsulation", "f", &dhcp_universe, 34, 1 }, { "arp-cache-timeout", "L", &dhcp_universe, 35, 1 }, { "ieee802-3-encapsulation", "f", &dhcp_universe, 36, 1 }, { "default-tcp-ttl", "B", &dhcp_universe, 37, 1 }, { "tcp-keepalive-interval", "L", &dhcp_universe, 38, 1 }, { "tcp-keepalive-garbage", "f", &dhcp_universe, 39, 1 }, { "nis-domain", "t", &dhcp_universe, 40, 1 }, { "nis-servers", "IA", &dhcp_universe, 41, 1 }, { "ntp-servers", "IA", &dhcp_universe, 42, 1 }, { "vendor-encapsulated-options", "E.", &dhcp_universe, 43, 1 }, { "netbios-name-servers", "IA", &dhcp_universe, 44, 1 }, { "netbios-dd-server", "IA", &dhcp_universe, 45, 1 }, { "netbios-node-type", "B", &dhcp_universe, 46, 1 }, { "netbios-scope", "t", &dhcp_universe, 47, 1 }, { "font-servers", "IA", &dhcp_universe, 48, 1 }, { "x-display-manager", "IA", &dhcp_universe, 49, 1 }, { "dhcp-requested-address", "I", &dhcp_universe, 50, 1 }, { "dhcp-lease-time", "L", &dhcp_universe, 51, 1 }, { "dhcp-option-overload", "B", &dhcp_universe, 52, 1 }, { "dhcp-message-type", "B", &dhcp_universe, 53, 1 }, { "dhcp-server-identifier", "I", &dhcp_universe, 54, 1 }, { "dhcp-parameter-request-list", "BA", &dhcp_universe, 55, 1 }, { "dhcp-message", "t", &dhcp_universe, 56, 1 }, { "dhcp-max-message-size", "S", &dhcp_universe, 57, 1 }, { "dhcp-renewal-time", "L", &dhcp_universe, 58, 1 }, { "dhcp-rebinding-time", "L", &dhcp_universe, 59, 1 }, { "vendor-class-identifier", "X", &dhcp_universe, 60, 1 }, { "dhcp-client-identifier", "X", &dhcp_universe, 61, 1 }, { "nwip-domain", "t", &dhcp_universe, 62, 1 }, { "nwip-suboptions", "Enwip.", &dhcp_universe, 63, 1 }, { "nisplus-domain", "t", &dhcp_universe, 64, 1 }, { "nisplus-servers", "IA", &dhcp_universe, 65, 1 }, { "tftp-server-name", "t", &dhcp_universe, 66, 1 }, { "bootfile-name", "t", &dhcp_universe, 67, 1 }, { "mobile-ip-home-agent", "IA", &dhcp_universe, 68, 1 }, { "smtp-server", "IA", &dhcp_universe, 69, 1 }, { "pop-server", "IA", &dhcp_universe, 70, 1 }, { "nntp-server", "IA", &dhcp_universe, 71, 1 }, { "www-server", "IA", &dhcp_universe, 72, 1 }, { "finger-server", "IA", &dhcp_universe, 73, 1 }, { "irc-server", "IA", &dhcp_universe, 74, 1 }, { "streettalk-server", "IA", &dhcp_universe, 75, 1 }, { "streettalk-directory-assistance-server", "IA", &dhcp_universe, 76, 1 }, { "user-class", "t", &dhcp_universe, 77, 1 }, { "slp-directory-agent", "fIa", &dhcp_universe, 78, 1 }, { "slp-service-scope", "fto", &dhcp_universe, 79, 1 }, /* 80 is the zero-length rapid-commit (RFC 4039) */ { "fqdn", "Efqdn.", &dhcp_universe, 81, 1 }, { "relay-agent-information", "Eagent.", &dhcp_universe, 82, 1 }, /* 83 is iSNS (RFC 4174) */ /* 84 is unassigned */ { "nds-servers", "IA", &dhcp_universe, 85, 1 }, { "nds-tree-name", "t", &dhcp_universe, 86, 1 }, { "nds-context", "t", &dhcp_universe, 87, 1 }, /* Note: RFC4280 fails to identify if the DHCPv4 option is to use * compression pointers or not. Assume not. */ { "bcms-controller-names", "D", &dhcp_universe, 88, 1 }, { "bcms-controller-address", "Ia", &dhcp_universe, 89, 1 }, /* 90 is the authentication option (RFC 3118) */ { "client-last-transaction-time", "L", &dhcp_universe, 91, 1 }, { "associated-ip", "Ia", &dhcp_universe, 92, 1 }, #if 0 /* Defined by RFC 4578 */ { "pxe-system-type", "S", &dhcp_universe, 93, 1 }, { "pxe-interface-id", "BBB", &dhcp_universe, 94, 1 }, { "pxe-client-id", "BX", &dhcp_universe, 97, 1 }, #endif { "uap-servers", "t", &dhcp_universe, 98, 1 }, { "netinfo-server-address", "Ia", &dhcp_universe, 112, 1 }, { "netinfo-server-tag", "t", &dhcp_universe, 113, 1 }, { "default-url", "t", &dhcp_universe, 114, 1 }, { "subnet-selection", "I", &dhcp_universe, 118, 1 }, { "domain-search", "Dc", &dhcp_universe, 119, 1 }, { "vivco", "Evendor-class.", &dhcp_universe, 124, 1 }, { "vivso", "Evendor.", &dhcp_universe, 125, 1 }, #if 0 /* Referenced by RFC 4578. * DO NOT UNCOMMENT THESE DEFINITIONS: these names are placeholders * and will not be used in future versions of the software. */ { "pxe-undefined-1", "X", &dhcp_universe, 128, 1 }, { "pxe-undefined-2", "X", &dhcp_universe, 129, 1 }, { "pxe-undefined-3", "X", &dhcp_universe, 130, 1 }, { "pxe-undefined-4", "X", &dhcp_universe, 131, 1 }, { "pxe-undefined-5", "X", &dhcp_universe, 132, 1 }, { "pxe-undefined-6", "X", &dhcp_universe, 133, 1 }, { "pxe-undefined-7", "X", &dhcp_universe, 134, 1 }, { "pxe-undefined-8", "X", &dhcp_universe, 135, 1 }, #endif #if 0 /* Not defined by RFC yet */ { "tftp-server-address", "Ia", &dhcp_universe, 150, 1 }, #endif #if 0 /* PXELINUX options: defined by RFC 5071 */ { "pxelinux-magic", "BBBB", &dhcp_universe, 208, 1 }, { "loader-configfile", "t", &dhcp_universe, 209, 1 }, { "loader-pathprefix", "t", &dhcp_universe, 210, 1 }, { "loader-reboottime", "L", &dhcp_universe, 211, 1 }, #endif #if 0 /* Not defined by RFC yet */ { "vss-info", "BX", &dhcp_universe, 221, 1 }, #endif { NULL, NULL, NULL, 0, 0 } }; struct universe nwip_universe; static struct option nwip_options[] = { { "illegal-1", "", &nwip_universe, 1, 1 }, { "illegal-2", "", &nwip_universe, 2, 1 }, { "illegal-3", "", &nwip_universe, 3, 1 }, { "illegal-4", "", &nwip_universe, 4, 1 }, { "nsq-broadcast", "f", &nwip_universe, 5, 1 }, { "preferred-dss", "IA", &nwip_universe, 6, 1 }, { "nearest-nwip-server", "IA", &nwip_universe, 7, 1 }, { "autoretries", "B", &nwip_universe, 8, 1 }, { "autoretry-secs", "B", &nwip_universe, 9, 1 }, { "nwip-1-1", "f", &nwip_universe, 10, 1 }, { "primary-dss", "I", &nwip_universe, 11, 1 }, { NULL, NULL, NULL, 0, 0 } }; /* Note that the "FQDN suboption space" does not reflect the FQDN option * format - rather, this is a handy "virtualization" of a flat option * which makes manual configuration and presentation of some of its * contents easier (each of these suboptions is a fixed-space field within * the fqdn contents - domain and host names are derived from a common field, * and differ in the left and right hand side of the leftmost dot, fqdn is * the combination of the two). * * Note further that the DHCPv6 and DHCPv4 'fqdn' options use the same * virtualized option space to store their work. */ struct universe fqdn_universe; struct universe fqdn6_universe; static struct option fqdn_options[] = { { "no-client-update", "f", &fqdn_universe, 1, 1 }, { "server-update", "f", &fqdn_universe, 2, 1 }, { "encoded", "f", &fqdn_universe, 3, 1 }, { "rcode1", "B", &fqdn_universe, 4, 1 }, { "rcode2", "B", &fqdn_universe, 5, 1 }, { "hostname", "t", &fqdn_universe, 6, 1 }, { "domainname", "t", &fqdn_universe, 7, 1 }, { "fqdn", "t", &fqdn_universe, 8, 1 }, { NULL, NULL, NULL, 0, 0 } }; struct universe vendor_class_universe; static struct option vendor_class_options[] = { { "isc", "X", &vendor_class_universe, 2495, 1 }, { NULL, NULL, NULL, 0, 0 } }; struct universe vendor_universe; static struct option vendor_options[] = { { "isc", "Eisc.", &vendor_universe, 2495, 1 }, { NULL, NULL, NULL, 0, 0 } }; struct universe isc_universe; static struct option isc_options [] = { { "media", "t", &isc_universe, 1, 1 }, { "update-assist", "X", &isc_universe, 2, 1 }, { NULL, NULL, NULL, 0, 0 } }; struct universe dhcpv6_universe; static struct option dhcpv6_options[] = { /* RFC3315 OPTIONS */ /* Client and server DUIDs are opaque fields, but marking them * up somewhat makes configuration easier. */ { "client-id", "X", &dhcpv6_universe, 1, 1 }, { "server-id", "X", &dhcpv6_universe, 2, 1 }, /* ia-* options actually have at their ends a space for options * that are specific to this instance of the option. We can not * handle this yet at this stage of development, so the encoding * of these options is unspecified ("X"). */ { "ia-na", "X", &dhcpv6_universe, 3, 1 }, { "ia-ta", "X", &dhcpv6_universe, 4, 1 }, { "ia-addr", "X", &dhcpv6_universe, 5, 1 }, /* "oro" is DHCPv6 speak for "parameter-request-list" */ { "oro", "SA", &dhcpv6_universe, 6, 1 }, { "preference", "B", &dhcpv6_universe, 7, 1 }, { "elapsed-time", "S", &dhcpv6_universe, 8, 1 }, { "relay-msg", "X", &dhcpv6_universe, 9, 1 }, /* Option code 10 is curiously unassigned. */ /* * In draft-ietf-dhc-dhcpv6-25 there were two OPTION_CLIENT_MSG and * OPTION_SERVER_MSG options. They were eventually unified as * OPTION_RELAY_MSG, hence no option with value of 10. */ #if 0 /* XXX: missing suitable atoms for the auth option. We may want * to 'virtually encapsulate' this option a la the fqdn option * seeing as it is processed explicitly by the server and unlikely * to be configured by hand by users as such. */ { "auth", "Nauth-protocol.Nauth-algorithm.Nrdm-type.LLX", &dhcpv6_universe, 11, 1 }, #endif { "unicast", "6", &dhcpv6_universe, 12, 1 }, { "status-code", "Nstatus-codes.to", &dhcpv6_universe, 13, 1 }, { "rapid-commit", "Z", &dhcpv6_universe, 14, 1 }, #if 0 /* XXX: user-class contents are of the form "StA" where the * integer describes the length of the text field. We don't have * an atom for pre-determined-length octet strings yet, so we * can't quite do these two. */ { "user-class", "X", &dhcpv6_universe, 15, 1 }, { "vendor-class", "X", &dhcpv6_universe, 16, 1 }, #endif { "vendor-opts", "Evsio.", &dhcpv6_universe, 17, 1 }, { "interface-id", "X", &dhcpv6_universe, 18, 1 }, { "reconf-msg", "Ndhcpv6-messages.", &dhcpv6_universe, 19, 1 }, { "reconf-accept", "Z", &dhcpv6_universe, 20, 1 }, /* RFC3319 OPTIONS */ /* Of course: we would HAVE to have a different atom for * domain names without compression. Typical. */ { "sip-servers-names", "D", &dhcpv6_universe, 21, 1 }, { "sip-servers-addresses", "6A", &dhcpv6_universe, 22, 1 }, /* RFC3646 OPTIONS */ { "name-servers", "6A", &dhcpv6_universe, 23, 1 }, { "domain-search", "D", &dhcpv6_universe, 24, 1 }, /* RFC3633 OPTIONS */ { "ia-pd", "X", &dhcpv6_universe, 25, 1 }, { "ia-prefix", "X", &dhcpv6_universe, 26, 1 }, /* RFC3898 OPTIONS */ { "nis-servers", "6A", &dhcpv6_universe, 27, 1 }, { "nisp-servers", "6A", &dhcpv6_universe, 28, 1 }, { "nis-domain-name", "D", &dhcpv6_universe, 29, 1 }, { "nisp-domain-name", "D", &dhcpv6_universe, 30, 1 }, /* RFC4075 OPTIONS */ { "sntp-servers", "6A", &dhcpv6_universe, 31, 1 }, /* RFC4242 OPTIONS */ { "info-refresh-time", "T", &dhcpv6_universe, 32, 1 }, /* RFC4280 OPTIONS */ { "bcms-server-d", "D", &dhcpv6_universe, 33, 1 }, { "bcms-server-a", "6A", &dhcpv6_universe, 34, 1 }, /* Note that 35 is not assigned. */ /* Not yet considering for inclusion. */ #if 0 /* RFC4776 OPTIONS */ { "geoconf-civic", "X", &dhcpv6_universe, 36, 1 }, #endif /* RFC4649 OPTIONS */ /* The remote-id option looks like the VSIO option, but for all * intents and purposes we only need to treat the entire field * like a globally unique identifier (and if we create such an * option, ensure the first 4 bytes are our enterprise-id followed * by a globally unique ID so long as you're within that enterprise * id). So we'll use "X" for now unless someone grumbles. */ { "remote-id", "X", &dhcpv6_universe, 37, 1 }, /* RFC4580 OPTIONS */ { "subscriber-id", "X", &dhcpv6_universe, 38, 1 }, /* RFC4704 OPTIONS */ /* The DHCPv6 FQDN option is...weird. * * We use the same "virtual" encapsulated space as DHCPv4's FQDN * option, so it can all be configured in one place. Since the * options system does not support multiple inheritance, we use * a 'shill' layer to perform the different protocol conversions, * and to redirect any queries in the DHCPv4 FQDN's space. */ { "fqdn", "Efqdn6-if-you-see-me-its-a-bug-bug-bug.", &dhcpv6_universe, 39, 1 }, /* Not yet considering for inclusion. */ #if 0 /* draft-ietf-dhc-paa-option-05 */ { "pana-agent", "6A", &dhcpv6_universe, 40, 1 }, /* RFC4833 OPTIONS */ { "new-posix-timezone", "t", &dhcpv6_universe, 41, 1 }, { "new-tzdb-timezone", "t", &dhcpv6_universe, 42, 1 }, /* RFC4994 OPTIONS */ { "ero", "SA", &dhcpv6_universe, 43, 1 }, #endif /* RFC5007 OPTIONS */ { "lq-query", "X", &dhcpv6_universe, 44, 1 }, { "client-data", "X", &dhcpv6_universe, 45, 1 }, { "clt-time", "L", &dhcpv6_universe, 46, 1 }, { "lq-relay-data", "6X", &dhcpv6_universe, 47, 1 }, { "lq-client-link", "6A", &dhcpv6_universe, 48, 1 }, { NULL, NULL, NULL, 0, 0 } }; struct enumeration_value dhcpv6_duid_type_values[] = { { "duid-llt", DUID_LLT }, /* Link-Local Plus Time */ { "duid-en", DUID_EN }, /* DUID based upon enterprise-ID. */ { "duid-ll", DUID_LL }, /* DUID from Link Local address only. */ { NULL, 0 } }; struct enumeration dhcpv6_duid_types = { NULL, "duid-types", 2, dhcpv6_duid_type_values }; struct enumeration_value dhcpv6_status_code_values[] = { { "success", 0 }, /* Success */ { "UnspecFail", 1 }, /* Failure, for unspecified reasons. */ { "NoAddrsAvail", 2 }, /* Server has no addresses to assign. */ { "NoBinding", 3 }, /* Client record (binding) unavailable. */ { "NotOnLink", 4 }, /* Bad prefix for the link. */ { "UseMulticast", 5 }, /* Not just good advice. It's the law. */ { "NoPrefixAvail", 6 }, /* Server has no prefixes to assign. */ { "UnknownQueryType", 7 }, /* Query-type unknown/unsupported. */ { "MalformedQuery", 8 }, /* Leasequery not valid. */ { "NotConfigured", 9 }, /* The target address is not in config. */ { "NotAllowed", 10 }, /* Server doesn't allow the leasequery. */ { NULL, 0 } }; struct enumeration dhcpv6_status_codes = { NULL, "status-codes", 2, dhcpv6_status_code_values }; struct enumeration_value lq6_query_type_values[] = { { "query-by-address", 1 }, { "query-by-clientid", 2 }, { NULL, 0 } }; struct enumeration lq6_query_types = { NULL, "query-types", 2, lq6_query_type_values }; struct enumeration_value dhcpv6_message_values[] = { { "SOLICIT", 1 }, { "ADVERTISE", 2 }, { "REQUEST", 3 }, { "CONFIRM", 4 }, { "RENEW", 5 }, { "REBIND", 6 }, { "REPLY", 7 }, { "RELEASE", 8 }, { "DECLINE", 9 }, { "RECONFIGURE", 10 }, { "INFORMATION-REQUEST", 11 }, { "RELAY-FORW", 12 }, { "RELAY-REPL", 13 }, { "LEASEQUERY", 14 }, { "LEASEQUERY-REPLY", 15 }, { NULL, 0 } }; /* Some code refers to a different table. */ const char *dhcpv6_type_names[] = { NULL, "Solicit", "Advertise", "Request", "Confirm", "Renew", "Rebind", "Reply", "Release", "Decline", "Reconfigure", "Information-request", "Relay-forward", "Relay-reply", "Leasequery", "Leasequery-reply" }; const int dhcpv6_type_name_max = (sizeof(dhcpv6_type_names) / sizeof(dhcpv6_type_names[0])); struct enumeration dhcpv6_messages = { NULL, "dhcpv6-messages", 1, dhcpv6_message_values }; struct universe vsio_universe; static struct option vsio_options[] = { { "isc", "Eisc6.", &vsio_universe, 2495, 1 }, { NULL, NULL, NULL, 0, 0 } }; struct universe isc6_universe; static struct option isc6_options[] = { { "media", "t", &isc6_universe, 1, 1 }, { "update-assist", "X", &isc6_universe, 2, 1 }, { NULL, NULL, NULL, 0, 0 } }; const char *hardware_types [] = { "unknown-0", "ethernet", "unknown-2", "unknown-3", "unknown-4", "unknown-5", "token-ring", "unknown-7", "fddi", "unknown-9", "unknown-10", "unknown-11", "unknown-12", "unknown-13", "unknown-14", "unknown-15", "unknown-16", "unknown-17", "unknown-18", "unknown-19", "unknown-20", "unknown-21", "unknown-22", "unknown-23", "unknown-24", "unknown-25", "unknown-26", "unknown-27", "unknown-28", "unknown-29", "unknown-30", "unknown-31", "infiniband", "unknown-33", "unknown-34", "unknown-35", "unknown-36", "unknown-37", "unknown-38", "unknown-39", "unknown-40", "unknown-41", "unknown-42", "unknown-43", "unknown-44", "unknown-45", "unknown-46", "unknown-47", "unknown-48", "unknown-49", "unknown-50", "unknown-51", "unknown-52", "unknown-53", "unknown-54", "unknown-55", "unknown-56", "unknown-57", "unknown-58", "unknown-59", "unknown-60", "unknown-61", "unknown-62", "unknown-63", "unknown-64", "unknown-65", "unknown-66", "unknown-67", "unknown-68", "unknown-69", "unknown-70", "unknown-71", "unknown-72", "unknown-73", "unknown-74", "unknown-75", "unknown-76", "unknown-77", "unknown-78", "unknown-79", "unknown-80", "unknown-81", "unknown-82", "unknown-83", "unknown-84", "unknown-85", "unknown-86", "unknown-87", "unknown-88", "unknown-89", "unknown-90", "unknown-91", "unknown-92", "unknown-93", "unknown-94", "unknown-95", "unknown-96", "unknown-97", "unknown-98", "unknown-99", "unknown-100", "unknown-101", "unknown-102", "unknown-103", "unknown-104", "unknown-105", "unknown-106", "unknown-107", "unknown-108", "unknown-109", "unknown-110", "unknown-111", "unknown-112", "unknown-113", "unknown-114", "unknown-115", "unknown-116", "unknown-117", "unknown-118", "unknown-119", "unknown-120", "unknown-121", "unknown-122", "unknown-123", "unknown-124", "unknown-125", "unknown-126", "unknown-127", "unknown-128", "unknown-129", "unknown-130", "unknown-131", "unknown-132", "unknown-133", "unknown-134", "unknown-135", "unknown-136", "unknown-137", "unknown-138", "unknown-139", "unknown-140", "unknown-141", "unknown-142", "unknown-143", "unknown-144", "unknown-145", "unknown-146", "unknown-147", "unknown-148", "unknown-149", "unknown-150", "unknown-151", "unknown-152", "unknown-153", "unknown-154", "unknown-155", "unknown-156", "unknown-157", "unknown-158", "unknown-159", "unknown-160", "unknown-161", "unknown-162", "unknown-163", "unknown-164", "unknown-165", "unknown-166", "unknown-167", "unknown-168", "unknown-169", "unknown-170", "unknown-171", "unknown-172", "unknown-173", "unknown-174", "unknown-175", "unknown-176", "unknown-177", "unknown-178", "unknown-179", "unknown-180", "unknown-181", "unknown-182", "unknown-183", "unknown-184", "unknown-185", "unknown-186", "unknown-187", "unknown-188", "unknown-189", "unknown-190", "unknown-191", "unknown-192", "unknown-193", "unknown-194", "unknown-195", "unknown-196", "unknown-197", "unknown-198", "unknown-199", "unknown-200", "unknown-201", "unknown-202", "unknown-203", "unknown-204", "unknown-205", "unknown-206", "unknown-207", "unknown-208", "unknown-209", "unknown-210", "unknown-211", "unknown-212", "unknown-213", "unknown-214", "unknown-215", "unknown-216", "unknown-217", "unknown-218", "unknown-219", "unknown-220", "unknown-221", "unknown-222", "unknown-223", "unknown-224", "unknown-225", "unknown-226", "unknown-227", "unknown-228", "unknown-229", "unknown-230", "unknown-231", "unknown-232", "unknown-233", "unknown-234", "unknown-235", "unknown-236", "unknown-237", "unknown-238", "unknown-239", "unknown-240", "unknown-241", "unknown-242", "unknown-243", "unknown-244", "unknown-245", "unknown-246", "unknown-247", "unknown-248", "unknown-249", "unknown-250", "unknown-251", "unknown-252", "unknown-253", "unknown-254", "unknown-255" }; universe_hash_t *universe_hash; struct universe **universes; int universe_count, universe_max; /* Universe containing names of configuration options, which, rather than writing "option universe-name.option-name ...;", can be set by writing "option-name ...;". */ struct universe *config_universe; /* XXX: omapi must die...all the below keeps us from having to make the * option structures omapi typed objects, which is a bigger headache. */ char *default_option_format = (char *) "X"; /* Must match hash_reference/dereference types in omapip/hash.h. */ int option_reference(struct option **dest, struct option *src, const char * file, int line) { if (!dest || !src) return DHCP_R_INVALIDARG; if (*dest) { #if defined(POINTER_DEBUG) log_fatal("%s(%d): reference store into non-null pointer!", file, line); #else return DHCP_R_INVALIDARG; #endif } *dest = src; src->refcnt++; rc_register(file, line, dest, src, src->refcnt, 0, RC_MISC); return(ISC_R_SUCCESS); } int option_dereference(struct option **dest, const char *file, int line) { if (!dest) return DHCP_R_INVALIDARG; if (!*dest) { #if defined (POINTER_DEBUG) log_fatal("%s(%d): dereference of null pointer!", file, line); #else return DHCP_R_INVALIDARG; #endif } if ((*dest)->refcnt <= 0) { #if defined (POINTER_DEBUG) log_fatal("%s(%d): dereference of <= 0 refcnt!", file, line); #else return DHCP_R_INVALIDARG; #endif } (*dest)->refcnt--; rc_register(file, line, dest, (*dest), (*dest)->refcnt, 1, RC_MISC); if ((*dest)->refcnt == 0) { /* The option name may be packed in the same alloc as the * option structure. */ if ((char *) (*dest)->name != (char *) ((*dest) + 1)) dfree((char *) (*dest)->name, file, line); /* It's either a user-configured format (allocated), or the * default static format. */ if (((*dest)->format != NULL) && ((*dest)->format != default_option_format)) { dfree((char *) (*dest)->format, file, line); } dfree(*dest, file, line); } *dest = NULL; return ISC_R_SUCCESS; } void initialize_common_option_spaces() { unsigned code; int i; /* The 'universes' table is dynamically grown to contain * universe as they're configured - except during startup. * Since we know how many we put down in .c files, we can * allocate a more-than-right-sized buffer now, leaving some * space for user-configured option spaces. * * 1: dhcp_universe (dhcpv4 options) * 2: nwip_universe (dhcpv4 NWIP option) * 3: fqdn_universe (dhcpv4 fqdn option - reusable for v6) * 4: vendor_class_universe (VIVCO) * 5: vendor_universe (VIVSO) * 6: isc_universe (dhcpv4 isc config space) * 7: dhcpv6_universe (dhcpv6 options) * 8: vsio_universe (DHCPv6 Vendor-Identified space) * 9: isc6_universe (ISC's Vendor universe in DHCPv6 VSIO) * 10: fqdn6_universe (dhcpv6 fqdn option shill to v4) * 11: agent_universe (dhcpv4 relay agent - see server/stables.c) * 12: server_universe (server's config, see server/stables.c) * 13: user-config * 14: more user-config * 15: more user-config * 16: more user-config */ universe_max = 16; i = universe_max * sizeof(struct universe *); if (i <= 0) log_fatal("Ludicrous initial size option space table."); universes = dmalloc(i, MDL); if (universes == NULL) log_fatal("Can't allocate option space table."); memset(universes, 0, i); /* Set up the DHCP option universe... */ dhcp_universe.name = "dhcp"; dhcp_universe.concat_duplicates = 1; dhcp_universe.lookup_func = lookup_hashed_option; dhcp_universe.option_state_dereference = hashed_option_state_dereference; dhcp_universe.save_func = save_hashed_option; dhcp_universe.delete_func = delete_hashed_option; dhcp_universe.encapsulate = hashed_option_space_encapsulate; dhcp_universe.foreach = hashed_option_space_foreach; dhcp_universe.decode = parse_option_buffer; dhcp_universe.length_size = 1; dhcp_universe.tag_size = 1; dhcp_universe.get_tag = getUChar; dhcp_universe.store_tag = putUChar; dhcp_universe.get_length = getUChar; dhcp_universe.store_length = putUChar; dhcp_universe.site_code_min = 0; dhcp_universe.end = DHO_END; dhcp_universe.index = universe_count++; universes [dhcp_universe.index] = &dhcp_universe; if (!option_name_new_hash(&dhcp_universe.name_hash, BYTE_NAME_HASH_SIZE, MDL) || !option_code_new_hash(&dhcp_universe.code_hash, BYTE_CODE_HASH_SIZE, MDL)) log_fatal ("Can't allocate dhcp option hash table."); for (i = 0 ; dhcp_options[i].name ; i++) { option_code_hash_add(dhcp_universe.code_hash, &dhcp_options[i].code, 0, &dhcp_options[i], MDL); option_name_hash_add(dhcp_universe.name_hash, dhcp_options [i].name, 0, &dhcp_options [i], MDL); } #if defined(REPORT_HASH_PERFORMANCE) log_info("DHCP name hash: %s", option_name_hash_report(dhcp_universe.name_hash)); log_info("DHCP code hash: %s", option_code_hash_report(dhcp_universe.code_hash)); #endif /* Set up the Novell option universe (for option 63)... */ nwip_universe.name = "nwip"; nwip_universe.concat_duplicates = 0; /* XXX: reference? */ nwip_universe.lookup_func = lookup_linked_option; nwip_universe.option_state_dereference = linked_option_state_dereference; nwip_universe.save_func = save_linked_option; nwip_universe.delete_func = delete_linked_option; nwip_universe.encapsulate = nwip_option_space_encapsulate; nwip_universe.foreach = linked_option_space_foreach; nwip_universe.decode = parse_option_buffer; nwip_universe.length_size = 1; nwip_universe.tag_size = 1; nwip_universe.get_tag = getUChar; nwip_universe.store_tag = putUChar; nwip_universe.get_length = getUChar; nwip_universe.store_length = putUChar; nwip_universe.site_code_min = 0; nwip_universe.end = 0; code = DHO_NWIP_SUBOPTIONS; nwip_universe.enc_opt = NULL; if (!option_code_hash_lookup(&nwip_universe.enc_opt, dhcp_universe.code_hash, &code, 0, MDL)) log_fatal("Unable to find NWIP parent option (%s:%d).", MDL); nwip_universe.index = universe_count++; universes [nwip_universe.index] = &nwip_universe; if (!option_name_new_hash(&nwip_universe.name_hash, NWIP_HASH_SIZE, MDL) || !option_code_new_hash(&nwip_universe.code_hash, NWIP_HASH_SIZE, MDL)) log_fatal ("Can't allocate nwip option hash table."); for (i = 0 ; nwip_options[i].name ; i++) { option_code_hash_add(nwip_universe.code_hash, &nwip_options[i].code, 0, &nwip_options[i], MDL); option_name_hash_add(nwip_universe.name_hash, nwip_options[i].name, 0, &nwip_options[i], MDL); } #if defined(REPORT_HASH_PERFORMANCE) log_info("NWIP name hash: %s", option_name_hash_report(nwip_universe.name_hash)); log_info("NWIP code hash: %s", option_code_hash_report(nwip_universe.code_hash)); #endif /* Set up the FQDN option universe... */ fqdn_universe.name = "fqdn"; fqdn_universe.concat_duplicates = 0; fqdn_universe.lookup_func = lookup_linked_option; fqdn_universe.option_state_dereference = linked_option_state_dereference; fqdn_universe.save_func = save_linked_option; fqdn_universe.delete_func = delete_linked_option; fqdn_universe.encapsulate = fqdn_option_space_encapsulate; fqdn_universe.foreach = linked_option_space_foreach; fqdn_universe.decode = fqdn_universe_decode; fqdn_universe.length_size = 1; fqdn_universe.tag_size = 1; fqdn_universe.get_tag = getUChar; fqdn_universe.store_tag = putUChar; fqdn_universe.get_length = getUChar; fqdn_universe.store_length = putUChar; fqdn_universe.site_code_min = 0; fqdn_universe.end = 0; fqdn_universe.index = universe_count++; code = DHO_FQDN; fqdn_universe.enc_opt = NULL; if (!option_code_hash_lookup(&fqdn_universe.enc_opt, dhcp_universe.code_hash, &code, 0, MDL)) log_fatal("Unable to find FQDN parent option (%s:%d).", MDL); universes [fqdn_universe.index] = &fqdn_universe; if (!option_name_new_hash(&fqdn_universe.name_hash, FQDN_HASH_SIZE, MDL) || !option_code_new_hash(&fqdn_universe.code_hash, FQDN_HASH_SIZE, MDL)) log_fatal ("Can't allocate fqdn option hash table."); for (i = 0 ; fqdn_options[i].name ; i++) { option_code_hash_add(fqdn_universe.code_hash, &fqdn_options[i].code, 0, &fqdn_options[i], MDL); option_name_hash_add(fqdn_universe.name_hash, fqdn_options[i].name, 0, &fqdn_options[i], MDL); } #if defined(REPORT_HASH_PERFORMANCE) log_info("FQDN name hash: %s", option_name_hash_report(fqdn_universe.name_hash)); log_info("FQDN code hash: %s", option_code_hash_report(fqdn_universe.code_hash)); #endif /* Set up the Vendor Identified Vendor Class options (for option * 125)... */ vendor_class_universe.name = "vendor-class"; vendor_class_universe.concat_duplicates = 0; /* XXX: reference? */ vendor_class_universe.lookup_func = lookup_hashed_option; vendor_class_universe.option_state_dereference = hashed_option_state_dereference; vendor_class_universe.save_func = save_hashed_option; vendor_class_universe.delete_func = delete_hashed_option; vendor_class_universe.encapsulate = hashed_option_space_encapsulate; vendor_class_universe.foreach = hashed_option_space_foreach; vendor_class_universe.decode = parse_option_buffer; vendor_class_universe.length_size = 1; vendor_class_universe.tag_size = 4; vendor_class_universe.get_tag = getULong; vendor_class_universe.store_tag = putULong; vendor_class_universe.get_length = getUChar; vendor_class_universe.store_length = putUChar; vendor_class_universe.site_code_min = 0; vendor_class_universe.end = 0; code = DHO_VIVCO_SUBOPTIONS; vendor_class_universe.enc_opt = NULL; if (!option_code_hash_lookup(&vendor_class_universe.enc_opt, dhcp_universe.code_hash, &code, 0, MDL)) log_fatal("Unable to find VIVCO parent option (%s:%d).", MDL); vendor_class_universe.index = universe_count++; universes[vendor_class_universe.index] = &vendor_class_universe; if (!option_name_new_hash(&vendor_class_universe.name_hash, VIVCO_HASH_SIZE, MDL) || !option_code_new_hash(&vendor_class_universe.code_hash, VIVCO_HASH_SIZE, MDL)) log_fatal("Can't allocate Vendor Identified Vendor Class " "option hash table."); for (i = 0 ; vendor_class_options[i].name ; i++) { option_code_hash_add(vendor_class_universe.code_hash, &vendor_class_options[i].code, 0, &vendor_class_options[i], MDL); option_name_hash_add(vendor_class_universe.name_hash, vendor_class_options[i].name, 0, &vendor_class_options[i], MDL); } #if defined(REPORT_HASH_PERFORMANCE) log_info("VIVCO name hash: %s", option_name_hash_report(vendor_class_universe.name_hash)); log_info("VIVCO code hash: %s", option_code_hash_report(vendor_class_universe.code_hash)); #endif /* Set up the Vendor Identified Vendor Sub-options (option 126)... */ vendor_universe.name = "vendor"; vendor_universe.concat_duplicates = 0; /* XXX: reference? */ vendor_universe.lookup_func = lookup_hashed_option; vendor_universe.option_state_dereference = hashed_option_state_dereference; vendor_universe.save_func = save_hashed_option; vendor_universe.delete_func = delete_hashed_option; vendor_universe.encapsulate = hashed_option_space_encapsulate; vendor_universe.foreach = hashed_option_space_foreach; vendor_universe.decode = parse_option_buffer; vendor_universe.length_size = 1; vendor_universe.tag_size = 4; vendor_universe.get_tag = getULong; vendor_universe.store_tag = putULong; vendor_universe.get_length = getUChar; vendor_universe.store_length = putUChar; vendor_universe.site_code_min = 0; vendor_universe.end = 0; code = DHO_VIVSO_SUBOPTIONS; vendor_universe.enc_opt = NULL; if (!option_code_hash_lookup(&vendor_universe.enc_opt, dhcp_universe.code_hash, &code, 0, MDL)) log_fatal("Unable to find VIVSO parent option (%s:%d).", MDL); vendor_universe.index = universe_count++; universes[vendor_universe.index] = &vendor_universe; if (!option_name_new_hash(&vendor_universe.name_hash, VIVSO_HASH_SIZE, MDL) || !option_code_new_hash(&vendor_universe.code_hash, VIVSO_HASH_SIZE, MDL)) log_fatal("Can't allocate Vendor Identified Vendor Sub-" "options hash table."); for (i = 0 ; vendor_options[i].name ; i++) { option_code_hash_add(vendor_universe.code_hash, &vendor_options[i].code, 0, &vendor_options[i], MDL); option_name_hash_add(vendor_universe.name_hash, vendor_options[i].name, 0, &vendor_options[i], MDL); } #if defined(REPORT_HASH_PERFORMANCE) log_info("VIVSO name hash: %s", option_name_hash_report(vendor_universe.name_hash)); log_info("VIVSO code hash: %s", option_code_hash_report(vendor_universe.code_hash)); #endif /* Set up the ISC Vendor-option universe (for option 125.2495)... */ isc_universe.name = "isc"; isc_universe.concat_duplicates = 0; /* XXX: check VIVSO ref */ isc_universe.lookup_func = lookup_linked_option; isc_universe.option_state_dereference = linked_option_state_dereference; isc_universe.save_func = save_linked_option; isc_universe.delete_func = delete_linked_option; isc_universe.encapsulate = linked_option_space_encapsulate; isc_universe.foreach = linked_option_space_foreach; isc_universe.decode = parse_option_buffer; isc_universe.length_size = 2; isc_universe.tag_size = 2; isc_universe.get_tag = getUShort; isc_universe.store_tag = putUShort; isc_universe.get_length = getUShort; isc_universe.store_length = putUShort; isc_universe.site_code_min = 0; isc_universe.end = 0; code = VENDOR_ISC_SUBOPTIONS; isc_universe.enc_opt = NULL; if (!option_code_hash_lookup(&isc_universe.enc_opt, vendor_universe.code_hash, &code, 0, MDL)) log_fatal("Unable to find ISC parent option (%s:%d).", MDL); isc_universe.index = universe_count++; universes[isc_universe.index] = &isc_universe; if (!option_name_new_hash(&isc_universe.name_hash, VIV_ISC_HASH_SIZE, MDL) || !option_code_new_hash(&isc_universe.code_hash, VIV_ISC_HASH_SIZE, MDL)) log_fatal("Can't allocate ISC Vendor options hash table."); for (i = 0 ; isc_options[i].name ; i++) { option_code_hash_add(isc_universe.code_hash, &isc_options[i].code, 0, &isc_options[i], MDL); option_name_hash_add(isc_universe.name_hash, isc_options[i].name, 0, &isc_options[i], MDL); } #if defined(REPORT_HASH_PERFORMANCE) log_info("ISC name hash: %s", option_name_hash_report(isc_universe.name_hash)); log_info("ISC code hash: %s", option_code_hash_report(isc_universe.code_hash)); #endif /* Set up the DHCPv6 root universe. */ dhcpv6_universe.name = "dhcp6"; dhcpv6_universe.concat_duplicates = 0; dhcpv6_universe.lookup_func = lookup_hashed_option; dhcpv6_universe.option_state_dereference = hashed_option_state_dereference; dhcpv6_universe.save_func = save_hashed_option; dhcpv6_universe.delete_func = delete_hashed_option; dhcpv6_universe.encapsulate = hashed_option_space_encapsulate; dhcpv6_universe.foreach = hashed_option_space_foreach; dhcpv6_universe.decode = parse_option_buffer; dhcpv6_universe.length_size = 2; dhcpv6_universe.tag_size = 2; dhcpv6_universe.get_tag = getUShort; dhcpv6_universe.store_tag = putUShort; dhcpv6_universe.get_length = getUShort; dhcpv6_universe.store_length = putUShort; dhcpv6_universe.site_code_min = 0; /* DHCPv6 has no END option. */ dhcpv6_universe.end = 0x00; dhcpv6_universe.index = universe_count++; universes[dhcpv6_universe.index] = &dhcpv6_universe; if (!option_name_new_hash(&dhcpv6_universe.name_hash, WORD_NAME_HASH_SIZE, MDL) || !option_code_new_hash(&dhcpv6_universe.code_hash, WORD_CODE_HASH_SIZE, MDL)) log_fatal("Can't allocate dhcpv6 option hash tables."); for (i = 0 ; dhcpv6_options[i].name ; i++) { option_code_hash_add(dhcpv6_universe.code_hash, &dhcpv6_options[i].code, 0, &dhcpv6_options[i], MDL); option_name_hash_add(dhcpv6_universe.name_hash, dhcpv6_options[i].name, 0, &dhcpv6_options[i], MDL); } /* Add DHCPv6 protocol enumeration sets. */ add_enumeration(&dhcpv6_duid_types); add_enumeration(&dhcpv6_status_codes); add_enumeration(&dhcpv6_messages); /* Set up DHCPv6 VSIO universe. */ vsio_universe.name = "vsio"; vsio_universe.concat_duplicates = 0; vsio_universe.lookup_func = lookup_hashed_option; vsio_universe.option_state_dereference = hashed_option_state_dereference; vsio_universe.save_func = save_hashed_option; vsio_universe.delete_func = delete_hashed_option; vsio_universe.encapsulate = hashed_option_space_encapsulate; vsio_universe.foreach = hashed_option_space_foreach; vsio_universe.decode = parse_option_buffer; vsio_universe.length_size = 0; vsio_universe.tag_size = 4; vsio_universe.get_tag = getULong; vsio_universe.store_tag = putULong; vsio_universe.get_length = NULL; vsio_universe.store_length = NULL; vsio_universe.site_code_min = 0; /* No END option. */ vsio_universe.end = 0x00; code = D6O_VENDOR_OPTS; if (!option_code_hash_lookup(&vsio_universe.enc_opt, dhcpv6_universe.code_hash, &code, 0, MDL)) log_fatal("Unable to find VSIO parent option (%s:%d).", MDL); vsio_universe.index = universe_count++; universes[vsio_universe.index] = &vsio_universe; if (!option_name_new_hash(&vsio_universe.name_hash, VSIO_HASH_SIZE, MDL) || !option_code_new_hash(&vsio_universe.code_hash, VSIO_HASH_SIZE, MDL)) log_fatal("Can't allocate Vendor Specific Information " "Options space."); for (i = 0 ; vsio_options[i].name != NULL ; i++) { option_code_hash_add(vsio_universe.code_hash, &vsio_options[i].code, 0, &vsio_options[i], MDL); option_name_hash_add(vsio_universe.name_hash, vsio_options[i].name, 0, &vsio_options[i], MDL); } /* Add ISC VSIO sub-sub-option space. */ isc6_universe.name = "isc6"; isc6_universe.concat_duplicates = 0; isc6_universe.lookup_func = lookup_hashed_option; isc6_universe.option_state_dereference = hashed_option_state_dereference; isc6_universe.save_func = save_hashed_option; isc6_universe.delete_func = delete_hashed_option; isc6_universe.encapsulate = hashed_option_space_encapsulate; isc6_universe.foreach = hashed_option_space_foreach; isc6_universe.decode = parse_option_buffer; isc6_universe.length_size = 0; isc6_universe.tag_size = 4; isc6_universe.get_tag = getULong; isc6_universe.store_tag = putULong; isc6_universe.get_length = NULL; isc6_universe.store_length = NULL; isc6_universe.site_code_min = 0; /* No END option. */ isc6_universe.end = 0x00; code = 2495; if (!option_code_hash_lookup(&isc6_universe.enc_opt, vsio_universe.code_hash, &code, 0, MDL)) log_fatal("Unable to find ISC parent option (%s:%d).", MDL); isc6_universe.index = universe_count++; universes[isc6_universe.index] = &isc6_universe; if (!option_name_new_hash(&isc6_universe.name_hash, VIV_ISC_HASH_SIZE, MDL) || !option_code_new_hash(&isc6_universe.code_hash, VIV_ISC_HASH_SIZE, MDL)) log_fatal("Can't allocate Vendor Specific Information " "Options space."); for (i = 0 ; isc6_options[i].name != NULL ; i++) { option_code_hash_add(isc6_universe.code_hash, &isc6_options[i].code, 0, &isc6_options[i], MDL); option_name_hash_add(isc6_universe.name_hash, isc6_options[i].name, 0, &isc6_options[i], MDL); } /* The fqdn6 option space is a protocol-wrapper shill for the * old DHCPv4 space. */ fqdn6_universe.name = "fqdn6-if-you-see-me-its-a-bug-bug-bug"; fqdn6_universe.lookup_func = lookup_fqdn6_option; fqdn6_universe.option_state_dereference = NULL; /* Covered by v4. */ fqdn6_universe.save_func = save_fqdn6_option; fqdn6_universe.delete_func = delete_fqdn6_option; fqdn6_universe.encapsulate = fqdn6_option_space_encapsulate; fqdn6_universe.foreach = fqdn6_option_space_foreach; fqdn6_universe.decode = fqdn6_universe_decode; /* This is not a 'normal' encapsulated space, so these values are * meaningless. */ fqdn6_universe.length_size = 0; fqdn6_universe.tag_size = 0; fqdn6_universe.get_tag = NULL; fqdn6_universe.store_tag = NULL; fqdn6_universe.get_length = NULL; fqdn6_universe.store_length = NULL; fqdn6_universe.site_code_min = 0; fqdn6_universe.end = 0; fqdn6_universe.index = universe_count++; code = D6O_CLIENT_FQDN; fqdn6_universe.enc_opt = NULL; if (!option_code_hash_lookup(&fqdn6_universe.enc_opt, dhcpv6_universe.code_hash, &code, 0, MDL)) log_fatal("Unable to find FQDN v6 parent option. (%s:%d).", MDL); universes[fqdn6_universe.index] = &fqdn6_universe; /* The fqdn6 space shares the same option space as the v4 space. * So there are no name or code hashes on the v6 side. */ fqdn6_universe.name_hash = NULL; fqdn6_universe.code_hash = NULL; /* Set up the hash of DHCPv4 universes. */ universe_new_hash(&universe_hash, UNIVERSE_HASH_SIZE, MDL); universe_hash_add(universe_hash, dhcp_universe.name, 0, &dhcp_universe, MDL); universe_hash_add(universe_hash, nwip_universe.name, 0, &nwip_universe, MDL); universe_hash_add(universe_hash, fqdn_universe.name, 0, &fqdn_universe, MDL); universe_hash_add(universe_hash, vendor_class_universe.name, 0, &vendor_class_universe, MDL); universe_hash_add(universe_hash, vendor_universe.name, 0, &vendor_universe, MDL); universe_hash_add(universe_hash, isc_universe.name, 0, &isc_universe, MDL); /* Set up hashes for DHCPv6 universes. */ universe_hash_add(universe_hash, dhcpv6_universe.name, 0, &dhcpv6_universe, MDL); universe_hash_add(universe_hash, vsio_universe.name, 0, &vsio_universe, MDL); universe_hash_add(universe_hash, isc6_universe.name, 0, &isc6_universe, MDL); /* This should not be necessary. Listing here just for consistency. * universe_hash_add(universe_hash, fqdn6_universe.name, 0, * &fqdn6_universe, MDL); */ } dhcp-4.2.4/common/tests/000777 000765 000024 00000000000 11757514244 015037 5ustar00sarstaff000000 000000 dhcp-4.2.4/common/tr.c000644 000765 000024 00000026024 11562515513 014460 0ustar00sarstaff000000 000000 /* tr.c token ring interface support Contributed in May of 1999 by Andrew Chittenden */ /* * Copyright (c) 2011 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 2004-2007,2009 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1996-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ */ #include "dhcpd.h" #if defined (HAVE_TR_SUPPORT) && \ (defined (PACKET_ASSEMBLY) || defined (PACKET_DECODING)) #include "includes/netinet/ip.h" #include "includes/netinet/udp.h" #include "includes/netinet/if_ether.h" #include "netinet/if_tr.h" #include /* * token ring device handling subroutines. These are required as token-ring * does not have a simple on-the-wire header but requires the use of * source routing */ static int insert_source_routing (struct trh_hdr *trh, struct interface_info* interface); static void save_source_routing (struct trh_hdr *trh, struct interface_info* interface); static void expire_routes (void); /* * As we keep a list of interesting routing information only, a singly * linked list is all we need */ struct routing_entry { struct routing_entry *next; unsigned char addr[TR_ALEN]; unsigned char iface[5]; u_int16_t rcf; /* route control field */ u_int16_t rseg[8]; /* routing registers */ unsigned long access_time; /* time we last used this entry */ }; static struct routing_entry *routing_info = NULL; static int routing_timeout = 10; static struct timeval routing_timer; void assemble_tr_header (interface, buf, bufix, to) struct interface_info *interface; unsigned char *buf; unsigned *bufix; struct hardware *to; { struct trh_hdr *trh; int hdr_len; struct trllc *llc; /* set up the token header */ trh = (struct trh_hdr *) &buf[*bufix]; if (interface -> hw_address.hlen - 1 == sizeof (trh->saddr)) memcpy (trh->saddr, &interface -> hw_address.hbuf [1], sizeof (trh->saddr)); else memset (trh->saddr, 0x00, sizeof (trh->saddr)); if (to && to -> hlen == 7) /* XXX */ memcpy (trh->daddr, &to -> hbuf [1], sizeof trh->daddr); else memset (trh->daddr, 0xff, sizeof (trh->daddr)); hdr_len = insert_source_routing (trh, interface); trh->ac = AC; trh->fc = LLC_FRAME; /* set up the llc header for snap encoding after the tr header */ llc = (struct trllc *)(buf + *bufix + hdr_len); llc->dsap = EXTENDED_SAP; llc->ssap = EXTENDED_SAP; llc->llc = UI_CMD; llc->protid[0] = 0; llc->protid[1] = 0; llc->protid[2] = 0; llc->ethertype = htons(ETHERTYPE_IP); hdr_len += sizeof(struct trllc); *bufix += hdr_len; } static unsigned char tr_broadcast[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; /* * decoding the token header is a bit complex as you can see here. It is * further complicated by the linux kernel stripping off some valuable * information (see comment below) even though we've asked for the raw * packets. */ ssize_t decode_tr_header (interface, buf, bufix, from) struct interface_info *interface; unsigned char *buf; unsigned bufix; struct hardware *from; { struct trh_hdr *trh = (struct trh_hdr *) buf + bufix; struct trllc *llc; struct ip *ip; struct udphdr *udp; unsigned int route_len = 0; ssize_t hdr_len; struct timeval now; /* see whether any source routing information has expired */ gettimeofday(&now, NULL); if (routing_timer.tv_sec == 0) routing_timer.tv_sec = now.tv_sec + routing_timeout; else if ((now.tv_sec - routing_timer.tv_sec) > 0) expire_routes(); /* the kernel might have stripped off the source * routing bit. We try a heuristic to determine whether * this is the case and put it back on if so */ route_len = (ntohs(trh->rcf) & TR_RCF_LEN_MASK) >> 8; llc = (struct trllc *)(buf + bufix + sizeof(struct trh_hdr)-TR_MAXRIFLEN+route_len); if (llc->dsap == EXTENDED_SAP && llc->ssap == EXTENDED_SAP && llc->llc == UI_CMD && llc->protid[0] == 0 && llc->protid[1] == 0 && llc->protid[2] == 0) { /* say there is source routing information present */ trh->saddr[0] |= TR_RII; } if (trh->saddr[0] & TR_RII) route_len = (ntohs(trh->rcf) & TR_RCF_LEN_MASK) >> 8; else route_len = 0; hdr_len = sizeof (struct trh_hdr) - TR_MAXRIFLEN + route_len; /* now filter out unwanted packets: this is based on the packet * filter code in bpf.c */ llc = (struct trllc *)(buf + bufix + hdr_len); ip = (struct ip *) (llc + 1); udp = (struct udphdr *) ((unsigned char*) ip + IP_HL (ip)); /* make sure it is a snap encoded, IP, UDP, unfragmented packet sent * to our port */ if (llc->dsap != EXTENDED_SAP || ntohs(llc->ethertype) != ETHERTYPE_IP || ip->ip_p != IPPROTO_UDP || (ntohs (ip->ip_off) & IP_OFFMASK) != 0 || udp->uh_dport != local_port) return -1; /* only save source routing information for packets from valued hosts */ save_source_routing(trh, interface); return hdr_len + sizeof (struct trllc); } /* insert_source_routing inserts source route information into the token ring * header */ static int insert_source_routing (trh, interface) struct trh_hdr *trh; struct interface_info* interface; { struct routing_entry *rover; struct timeval now; unsigned int route_len = 0; gettimeofday(&now, NULL); /* single route broadcasts as per rfc 1042 */ if (memcmp(trh->daddr, tr_broadcast,TR_ALEN) == 0) { trh->saddr[0] |= TR_RII; trh->rcf = ((sizeof(trh->rcf)) << 8) & TR_RCF_LEN_MASK; trh->rcf |= (TR_RCF_FRAME2K | TR_RCF_LIMITED_BROADCAST); trh->rcf = htons(trh->rcf); } else { /* look for a routing entry */ for (rover = routing_info; rover != NULL; rover = rover->next) { if (memcmp(rover->addr, trh->daddr, TR_ALEN) == 0) break; } if (rover != NULL) { /* success: route that frame */ if ((rover->rcf & TR_RCF_LEN_MASK) >> 8) { u_int16_t rcf = rover->rcf; memcpy(trh->rseg,rover->rseg,sizeof(trh->rseg)); rcf ^= TR_RCF_DIR_BIT; rcf &= ~TR_RCF_BROADCAST_MASK; trh->rcf = htons(rcf); trh->saddr[0] |= TR_RII; } rover->access_time = now.tv_sec; } else { /* we don't have any routing information so send a * limited broadcast */ trh->saddr[0] |= TR_RII; trh->rcf = ((sizeof(trh->rcf)) << 8) & TR_RCF_LEN_MASK; trh->rcf |= (TR_RCF_FRAME2K | TR_RCF_LIMITED_BROADCAST); trh->rcf = htons(trh->rcf); } } /* return how much of the header we've actually used */ if (trh->saddr[0] & TR_RII) route_len = (ntohs(trh->rcf) & TR_RCF_LEN_MASK) >> 8; else route_len = 0; return sizeof (struct trh_hdr) - TR_MAXRIFLEN + route_len; } /* * save any source routing information */ static void save_source_routing(trh, interface) struct trh_hdr *trh; struct interface_info *interface; { struct routing_entry *rover; struct timeval now; unsigned char saddr[TR_ALEN]; u_int16_t rcf = 0; gettimeofday(&now, NULL); memcpy(saddr, trh->saddr, sizeof(saddr)); saddr[0] &= 0x7f; /* strip off source routing present flag */ /* scan our table to see if we've got it */ for (rover = routing_info; rover != NULL; rover = rover->next) { if (memcmp(&rover->addr[0], &saddr[0], TR_ALEN) == 0) break; } /* found an entry so update it with fresh information */ if (rover != NULL) { if ((trh->saddr[0] & TR_RII) && ((ntohs(trh->rcf) & TR_RCF_LEN_MASK) >> 8) > 2) { rcf = ntohs(trh->rcf); rcf &= ~TR_RCF_BROADCAST_MASK; memcpy(rover->rseg, trh->rseg, sizeof(rover->rseg)); } rover->rcf = rcf; rover->access_time = now.tv_sec; return; /* that's all folks */ } /* no entry found, so create one */ rover = dmalloc (sizeof (struct routing_entry), MDL); if (rover == NULL) { fprintf(stderr, "%s: unable to save source routing information\n", __FILE__); return; } memcpy(rover->addr, saddr, sizeof(rover->addr)); memcpy(rover->iface, interface->name, 5); rover->access_time = now.tv_sec; if (trh->saddr[0] & TR_RII) { if (((ntohs(trh->rcf) & TR_RCF_LEN_MASK) >> 8) > 2) { rcf = ntohs(trh->rcf); rcf &= ~TR_RCF_BROADCAST_MASK; memcpy(rover->rseg, trh->rseg, sizeof(rover->rseg)); } rover->rcf = rcf; } /* insert into list */ rover->next = routing_info; routing_info = rover; return; } /* * get rid of old routes */ static void expire_routes() { struct routing_entry *rover; struct routing_entry **prover = &routing_info; struct timeval now; gettimeofday(&now, NULL); while((rover = *prover) != NULL) { if ((now.tv_sec - rover->access_time) > routing_timeout) { *prover = rover->next; dfree (rover, MDL); } else prover = &rover->next; } /* Reset the timer */ routing_timer.tv_sec = now.tv_sec + routing_timeout; routing_timer.tv_usec = now.tv_usec; } #endif dhcp-4.2.4/common/tree.c000644 000765 000024 00000350771 11664747132 015012 0ustar00sarstaff000000 000000 /* tree.c Routines for manipulating parse trees... */ /* * Copyright (c) 2011 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 2004-2007,2009 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1995-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ * * This software has been written for Internet Systems Consortium * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. * To learn more about Internet Systems Consortium, see * ``https://www.isc.org/''. To learn more about Vixie Enterprises, * see ``http://www.vix.com''. To learn more about Nominum, Inc., see * ``http://www.nominum.com''. */ #include "dhcpd.h" #include #include #include #ifdef HAVE_REGEX_H # include #endif struct binding_scope *global_scope; static int do_host_lookup (struct data_string *, struct dns_host_entry *); #define DS_SPRINTF_SIZE 128 /* * If we are using a data_string structure to hold a NUL-terminated * ASCII string, this function can be used to append a printf-formatted * string to the end of it. The data_string structure will be resized to * be big enough to hold the new string. * * If the append works, then 1 is returned. * * If it is not possible to allocate a buffer big enough to hold the * new value, then the old data_string is unchanged, and 0 is returned. */ int data_string_sprintfa(struct data_string *ds, const char *fmt, ...) { va_list args; int cur_strlen; int max; int vsnprintf_ret; int new_len; struct buffer *tmp_buffer; /* * If the data_string is empty, then initialize it. */ if (ds->data == NULL) { /* INSIST(ds.buffer == NULL); */ if (!buffer_allocate(&ds->buffer, DS_SPRINTF_SIZE, MDL)) { return 0; } ds->data = ds->buffer->data; ds->len = DS_SPRINTF_SIZE; *((char *)ds->data) = '\0'; } /* * Get the length of the string, and figure out how much space * is left. */ cur_strlen = strlen((char *)ds->data); max = ds->len - cur_strlen; /* * Use vsnprintf(), which won't write past our space, but will * tell us how much space it wants. */ va_start(args, fmt); vsnprintf_ret = vsnprintf((char *)ds->data+cur_strlen, max, fmt, args); va_end(args); /* INSIST(vsnprintf_ret >= 0); */ /* * If our buffer is not big enough, we need a new buffer. */ if (vsnprintf_ret >= max) { /* * Figure out a size big enough. */ new_len = ds->len * 2; while (new_len <= cur_strlen + vsnprintf_ret) { new_len *= 2; } /* * Create a new buffer and fill it. */ tmp_buffer = NULL; if (!buffer_allocate(&tmp_buffer, new_len, MDL)) { /* * If we can't create a big enough buffer, * we should remove any truncated output that we had. */ *((char *)ds->data+cur_strlen) = '\0'; va_end(args); return 0; } memcpy(tmp_buffer->data, ds->data, cur_strlen); /* Rerun the vsprintf. */ va_start(args, fmt); vsprintf((char *)tmp_buffer->data + cur_strlen, fmt, args); va_end(args); /* * Replace our old buffer with the new buffer. */ buffer_dereference(&ds->buffer, MDL); buffer_reference(&ds->buffer, tmp_buffer, MDL); buffer_dereference(&tmp_buffer, MDL); ds->data = ds->buffer->data; ds->len = new_len; } return 1; } pair cons (car, cdr) caddr_t car; pair cdr; { pair foo = (pair)dmalloc (sizeof *foo, MDL); if (!foo) log_fatal ("no memory for cons."); foo -> car = car; foo -> cdr = cdr; return foo; } int make_const_option_cache (oc, buffer, data, len, option, file, line) struct option_cache **oc; struct buffer **buffer; u_int8_t *data; unsigned len; struct option *option; const char *file; int line; { struct buffer *bp; if (buffer) { bp = *buffer; *buffer = 0; } else { bp = (struct buffer *)0; if (!buffer_allocate (&bp, len, file, line)) { log_error ("%s(%d): can't allocate buffer.", file, line); return 0; } } if (!option_cache_allocate (oc, file, line)) { log_error ("%s(%d): can't allocate option cache.", file, line); buffer_dereference (&bp, file, line); return 0; } (*oc) -> data.len = len; (*oc) -> data.buffer = bp; (*oc) -> data.data = &bp -> data [0]; (*oc) -> data.terminated = 0; if (data) memcpy (&bp -> data [0], data, len); option_reference(&((*oc)->option), option, MDL); return 1; } int make_host_lookup (expr, name) struct expression **expr; const char *name; { if (!expression_allocate (expr, MDL)) { log_error ("No memory for host lookup tree node."); return 0; } (*expr) -> op = expr_host_lookup; if (!enter_dns_host (&((*expr) -> data.host_lookup), name)) { expression_dereference (expr, MDL); return 0; } return 1; } int enter_dns_host (dh, name) struct dns_host_entry **dh; const char *name; { /* XXX This should really keep a hash table of hostnames XXX and just add a new reference to a hostname that XXX already exists, if possible, rather than creating XXX a new structure. */ if (!dns_host_entry_allocate (dh, name, MDL)) { log_error ("Can't allocate space for new host."); return 0; } return 1; } int make_const_data (struct expression **expr, const unsigned char *data, unsigned len, int terminated, int allocate, const char *file, int line) { struct expression *nt; if (!expression_allocate (expr, file, line)) { log_error ("No memory for make_const_data tree node."); return 0; } nt = *expr; if (len) { if (allocate) { if (!buffer_allocate (&nt -> data.const_data.buffer, len + terminated, file, line)) { log_error ("Can't allocate const_data buffer"); expression_dereference (expr, file, line); return 0; } nt -> data.const_data.data = &nt -> data.const_data.buffer -> data [0]; memcpy (nt -> data.const_data.buffer -> data, data, len + terminated); } else nt -> data.const_data.data = data; nt -> data.const_data.terminated = terminated; } else nt -> data.const_data.data = 0; nt -> op = expr_const_data; nt -> data.const_data.len = len; return 1; } int make_const_int (expr, val) struct expression **expr; unsigned long val; { if (!expression_allocate (expr, MDL)) { log_error ("No memory for make_const_int tree node."); return 0; } (*expr) -> op = expr_const_int; (*expr) -> data.const_int = val; return 1; } int make_concat (expr, left, right) struct expression **expr; struct expression *left, *right; { /* If we're concatenating a null tree to a non-null tree, just return the non-null tree; if both trees are null, return a null tree. */ if (!left) { if (!right) return 0; expression_reference (expr, right, MDL); return 1; } if (!right) { expression_reference (expr, left, MDL); return 1; } /* Otherwise, allocate a new node to concatenate the two. */ if (!expression_allocate (expr, MDL)) { log_error ("No memory for concatenation expression node."); return 0; } (*expr) -> op = expr_concat; expression_reference (&(*expr) -> data.concat [0], left, MDL); expression_reference (&(*expr) -> data.concat [1], right, MDL); return 1; } int make_encapsulation (expr, name) struct expression **expr; struct data_string *name; { /* Allocate a new node to store the encapsulation. */ if (!expression_allocate (expr, MDL)) { log_error ("No memory for encapsulation expression node."); return 0; } (*expr) -> op = expr_encapsulate; data_string_copy (&(*expr) -> data.encapsulate, name, MDL); return 1; } int make_substring (new, expr, offset, length) struct expression **new; struct expression *expr; struct expression *offset; struct expression *length; { /* Allocate an expression node to compute the substring. */ if (!expression_allocate (new, MDL)) { log_error ("no memory for substring expression."); return 0; } (*new) -> op = expr_substring; expression_reference (&(*new) -> data.substring.expr, expr, MDL); expression_reference (&(*new) -> data.substring.offset, offset, MDL); expression_reference (&(*new) -> data.substring.len, length, MDL); return 1; } int make_limit (new, expr, limit) struct expression **new; struct expression *expr; int limit; { /* Allocate a node to enforce a limit on evaluation. */ if (!expression_allocate (new, MDL)) log_error ("no memory for limit expression"); (*new) -> op = expr_substring; expression_reference (&(*new) -> data.substring.expr, expr, MDL); /* Offset is a constant 0. */ if (!expression_allocate (&(*new) -> data.substring.offset, MDL)) { log_error ("no memory for limit offset expression"); expression_dereference (new, MDL); return 0; } (*new) -> data.substring.offset -> op = expr_const_int; (*new) -> data.substring.offset -> data.const_int = 0; /* Length is a constant: the specified limit. */ if (!expression_allocate (&(*new) -> data.substring.len, MDL)) { log_error ("no memory for limit length expression"); expression_dereference (new, MDL); return 0; } (*new) -> data.substring.len -> op = expr_const_int; (*new) -> data.substring.len -> data.const_int = limit; return 1; } int option_cache (struct option_cache **oc, struct data_string *dp, struct expression *expr, struct option *option, const char *file, int line) { if (!option_cache_allocate (oc, file, line)) return 0; if (dp) data_string_copy (&(*oc) -> data, dp, file, line); if (expr) expression_reference (&(*oc) -> expression, expr, file, line); option_reference(&(*oc)->option, option, MDL); return 1; } int make_let (result, name) struct executable_statement **result; const char *name; { if (!(executable_statement_allocate (result, MDL))) return 0; (*result) -> op = let_statement; (*result) -> data.let.name = dmalloc (strlen (name) + 1, MDL); if (!(*result) -> data.let.name) { executable_statement_dereference (result, MDL); return 0; } strcpy ((*result) -> data.let.name, name); return 1; } static int do_host_lookup (result, dns) struct data_string *result; struct dns_host_entry *dns; { struct hostent *h; unsigned i, count; unsigned new_len; #ifdef DEBUG_EVAL log_debug ("time: now = %d dns = %d diff = %d", cur_time, dns -> timeout, cur_time - dns -> timeout); #endif /* If the record hasn't timed out, just copy the data and return. */ if (cur_time <= dns -> timeout) { #ifdef DEBUG_EVAL log_debug ("easy copy: %d %s", dns -> data.len, (dns -> data.len > 4 ? inet_ntoa (*(struct in_addr *)(dns -> data.data)) : 0)); #endif data_string_copy (result, &dns -> data, MDL); return 1; } #ifdef DEBUG_EVAL log_debug ("Looking up %s", dns -> hostname); #endif /* Otherwise, look it up... */ h = gethostbyname (dns -> hostname); if (!h) { #ifndef NO_H_ERRNO switch (h_errno) { case HOST_NOT_FOUND: #endif log_error ("%s: host unknown.", dns -> hostname); #ifndef NO_H_ERRNO break; case TRY_AGAIN: log_error ("%s: temporary name server failure", dns -> hostname); break; case NO_RECOVERY: log_error ("%s: name server failed", dns -> hostname); break; case NO_DATA: log_error ("%s: no A record associated with address", dns -> hostname); } #endif /* !NO_H_ERRNO */ /* Okay to try again after a minute. */ dns -> timeout = cur_time + 60; data_string_forget (&dns -> data, MDL); return 0; } #ifdef DEBUG_EVAL log_debug ("Lookup succeeded; first address is %s", inet_ntoa (h -> h_addr_list [0])); #endif /* Count the number of addresses we got... */ for (count = 0; h -> h_addr_list [count]; count++) ; /* Dereference the old data, if any. */ data_string_forget (&dns -> data, MDL); /* Do we need to allocate more memory? */ new_len = count * h -> h_length; if (!buffer_allocate (&dns -> data.buffer, new_len, MDL)) { log_error ("No memory for %s.", dns -> hostname); return 0; } dns -> data.data = &dns -> data.buffer -> data [0]; dns -> data.len = new_len; dns -> data.terminated = 0; /* Addresses are conveniently stored one to the buffer, so we have to copy them out one at a time... :'( */ for (i = 0; i < count; i++) { memcpy (&dns -> data.buffer -> data [h -> h_length * i], h -> h_addr_list [i], (unsigned)(h -> h_length)); } #ifdef DEBUG_EVAL log_debug ("dns -> data: %x h -> h_addr_list [0]: %x", *(int *)(dns -> buffer), h -> h_addr_list [0]); #endif /* XXX Set the timeout for an hour from now. XXX This should really use the time on the DNS reply. */ dns -> timeout = cur_time + 3600; #ifdef DEBUG_EVAL log_debug ("hard copy: %d %s", dns -> data.len, (dns -> data.len > 4 ? inet_ntoa (*(struct in_addr *)(dns -> data.data)) : 0)); #endif data_string_copy (result, &dns -> data, MDL); return 1; } int evaluate_expression (result, packet, lease, client_state, in_options, cfg_options, scope, expr, file, line) struct binding_value **result; struct packet *packet; struct lease *lease; struct client_state *client_state; struct option_state *in_options; struct option_state *cfg_options; struct binding_scope **scope; struct expression *expr; const char *file; int line; { struct binding_value *bv; int status; struct binding *binding; bv = (struct binding_value *)0; if (expr -> op == expr_variable_reference) { if (!scope || !*scope) return 0; binding = find_binding (*scope, expr -> data.variable); if (binding && binding -> value) { if (result) binding_value_reference (result, binding -> value, file, line); return 1; } else return 0; } else if (expr -> op == expr_funcall) { struct string_list *s; struct expression *arg; struct binding_scope *ns; struct binding *nb; if (!scope || !*scope) { log_error ("%s: no such function.", expr -> data.funcall.name); return 0; } binding = find_binding (*scope, expr -> data.funcall.name); if (!binding || !binding -> value) { log_error ("%s: no such function.", expr -> data.funcall.name); return 0; } if (binding -> value -> type != binding_function) { log_error ("%s: not a function.", expr -> data.funcall.name); return 0; } /* Create a new binding scope in which to define the arguments to the function. */ ns = (struct binding_scope *)0; if (!binding_scope_allocate (&ns, MDL)) { log_error ("%s: can't allocate argument scope.", expr -> data.funcall.name); return 0; } arg = expr -> data.funcall.arglist; s = binding -> value -> value.fundef -> args; while (arg && s) { nb = dmalloc (sizeof *nb, MDL); if (!nb) { blb: binding_scope_dereference (&ns, MDL); return 0; } else { memset (nb, 0, sizeof *nb); nb -> name = dmalloc (strlen (s -> string) + 1, MDL); if (nb -> name) strcpy (nb -> name, s -> string); else { dfree (nb, MDL); nb = (struct binding *)0; goto blb; } } evaluate_expression (&nb -> value, packet, lease, client_state, in_options, cfg_options, scope, arg -> data.arg.val, file, line); nb -> next = ns -> bindings; ns -> bindings = nb; arg = arg -> data.arg.next; s = s -> next; } if (arg) { log_error ("%s: too many arguments.", expr -> data.funcall.name); binding_scope_dereference (&ns, MDL); return 0; } if (s) { log_error ("%s: too few arguments.", expr -> data.funcall.name); binding_scope_dereference (&ns, MDL); return 0; } if (scope && *scope) binding_scope_reference (&ns -> outer, *scope, MDL); status = (execute_statements (&bv, packet, lease, client_state, in_options, cfg_options, &ns, binding -> value -> value.fundef -> statements)); binding_scope_dereference (&ns, MDL); if (!bv) return 1; } else if (is_boolean_expression (expr)) { if (!binding_value_allocate (&bv, MDL)) return 0; bv -> type = binding_boolean; status = (evaluate_boolean_expression (&bv -> value.boolean, packet, lease, client_state, in_options, cfg_options, scope, expr)); } else if (is_numeric_expression (expr)) { if (!binding_value_allocate (&bv, MDL)) return 0; bv -> type = binding_numeric; status = (evaluate_numeric_expression (&bv -> value.intval, packet, lease, client_state, in_options, cfg_options, scope, expr)); } else if (is_data_expression (expr)) { if (!binding_value_allocate (&bv, MDL)) return 0; bv -> type = binding_data; status = (evaluate_data_expression (&bv -> value.data, packet, lease, client_state, in_options, cfg_options, scope, expr, MDL)); #if defined (NSUPDATE_OLD) } else if (is_dns_expression (expr)) { if (!binding_value_allocate (&bv, MDL)) return 0; bv -> type = binding_dns; status = (evaluate_dns_expression (&bv -> value.dns, packet, lease, client_state, in_options, cfg_options, scope, expr)); #endif } else { log_error ("%s: invalid expression type: %d", "evaluate_expression", expr -> op); return 0; } if (result && status) binding_value_reference (result, bv, file, line); binding_value_dereference (&bv, MDL); return status; } int binding_value_dereference (struct binding_value **v, const char *file, int line) { struct binding_value *bv = *v; *v = (struct binding_value *)0; /* Decrement the reference count. If it's nonzero, we're done. */ --(bv -> refcnt); rc_register (file, line, v, bv, bv -> refcnt, 1, RC_MISC); if (bv -> refcnt > 0) return 1; if (bv -> refcnt < 0) { log_error ("%s(%d): negative refcnt!", file, line); #if defined (DEBUG_RC_HISTORY) dump_rc_history (bv); #endif #if defined (POINTER_DEBUG) abort (); #else return 0; #endif } switch (bv -> type) { case binding_boolean: case binding_numeric: break; case binding_data: if (bv -> value.data.buffer) data_string_forget (&bv -> value.data, file, line); break; case binding_dns: #if defined (NSUPDATE_OLD) if (bv -> value.dns) { if (bv -> value.dns -> r_data) { dfree (bv -> value.dns -> r_data_ephem, MDL); bv -> value.dns -> r_data = (unsigned char *)0; bv -> value.dns -> r_data_ephem = (unsigned char *)0; } minires_freeupdrec (bv -> value.dns); } break; #endif default: log_error ("%s(%d): invalid binding type: %d", file, line, bv -> type); return 0; } free_binding_value(bv, file, line); return 1; } #if defined (NSUPDATE_OLD) int evaluate_dns_expression (result, packet, lease, client_state, in_options, cfg_options, scope, expr) ns_updrec **result; struct packet *packet; struct lease *lease; struct client_state *client_state; struct option_state *in_options; struct option_state *cfg_options; struct binding_scope **scope; struct expression *expr; { unsigned long ttl = 0; char *tname; struct data_string name, data; int r0, r1, r2; if (!result || *result) { log_error ("evaluate_dns_expression called with non-null %s", "result pointer"); #if defined (POINTER_DEBUG) abort (); #else return 0; #endif } switch (expr -> op) { #if defined (NSUPDATE) case expr_ns_add: r0 = evaluate_numeric_expression (&ttl, packet, lease, client_state, in_options, cfg_options, scope, expr -> data.ns_add.ttl); goto nsfinish; case expr_ns_exists: ttl = 1; case expr_ns_delete: case expr_ns_not_exists: r0 = 1; nsfinish: memset (&name, 0, sizeof name); r1 = evaluate_data_expression (&name, packet, lease, client_state, in_options, cfg_options, scope, expr -> data.ns_add.rrname, MDL); if (r1) { /* The result of the evaluation may or may not be NUL-terminated, but we need it terminated for sure, so we have to allocate a buffer and terminate it. */ tname = dmalloc (name.len + 1, MDL); if (!tname) { r2 = 0; r1 = 0; data_string_forget (&name, MDL); } else { memcpy (tname, name.data, name.len); tname [name.len] = 0; memset (&data, 0, sizeof data); r2 = evaluate_data_expression (&data, packet, lease, client_state, in_options, cfg_options, scope, expr -> data.ns_add.rrdata, MDL); } } else { r2 = 0; tname = NULL; } if (r0 && r1 && (r2 || expr -> op != expr_ns_add)) { *result = minires_mkupdrec (((expr -> op == expr_ns_add || expr -> op == expr_ns_delete) ? S_UPDATE : S_PREREQ), tname, expr -> data.ns_add.rrclass, expr -> data.ns_add.rrtype, ttl); if (!*result) { ngood: if (r2) { data_string_forget (&data, MDL); r2 = 0; } } else { if (data.len) { /* As a special case, if we get exactly four bytes of data, it's an IP address represented as a 32-bit quantity, which is actually what we *should* be getting here. Because res_mkupdrec is currently broken and expects a dotted quad, convert it. This should be fixed when the new resolver is merged. */ if (data.len == 4) { (*result) -> r_data_ephem = dmalloc (16, MDL); if (!(*result) -> r_data_ephem) goto dpngood; (*result) -> r_data = (*result) -> r_data_ephem; /*%Audit% 16 bytes max. %2004.06.17,Safe%*/ sprintf ((char *)(*result) -> r_data_ephem, "%u.%u.%u.%u", data.data [0] & 0xff, data.data [1] & 0xff, data.data [2] & 0xff, data.data [3] & 0xff); (*result) -> r_size = strlen ((const char *) (*result) -> r_data); } else { (*result) -> r_size = data.len; (*result) -> r_data_ephem = dmalloc (data.len, MDL); if (!(*result) -> r_data_ephem) { dpngood: /* double plus ungood. */ minires_freeupdrec (*result); *result = 0; goto ngood; } (*result) -> r_data = (*result) -> r_data_ephem; memcpy ((*result) -> r_data_ephem, data.data, data.len); } } else { (*result) -> r_data = 0; (*result) -> r_size = 0; } switch (expr -> op) { case expr_ns_add: (*result) -> r_opcode = ADD; break; case expr_ns_delete: (*result) -> r_opcode = DELETE; break; case expr_ns_exists: (*result) -> r_opcode = YXRRSET; break; case expr_ns_not_exists: (*result) -> r_opcode = NXRRSET; break; /* Can't happen, but satisfy gcc. */ default: break; } } } if (r1) { data_string_forget (&name, MDL); dfree (tname, MDL); } if (r2) data_string_forget (&data, MDL); /* One flaw in the thinking here: an IP address and an ASCII string both look like data expressions, but for A records, we want an ASCII string, not a binary IP address. Do I need to turn binary IP addresses into a separate type? */ return (r0 && r1 && (r2 || expr -> op != expr_ns_add) && *result); #else case expr_ns_add: case expr_ns_delete: case expr_ns_exists: case expr_ns_not_exists: return 0; #endif case expr_funcall: log_error ("%s: dns values for functions not supported.", expr -> data.funcall.name); break; case expr_variable_reference: log_error ("%s: dns values for variables not supported.", expr -> data.variable); break; case expr_check: case expr_equal: case expr_not_equal: case expr_regex_match: case expr_iregex_match: case expr_and: case expr_or: case expr_not: case expr_match: case expr_static: case expr_known: case expr_exists: case expr_variable_exists: log_error ("Boolean opcode in evaluate_dns_expression: %d", expr -> op); return 0; case expr_none: case expr_substring: case expr_suffix: case expr_lcase: case expr_ucase: case expr_option: case expr_hardware: case expr_const_data: case expr_packet: case expr_concat: case expr_encapsulate: case expr_host_lookup: case expr_encode_int8: case expr_encode_int16: case expr_encode_int32: case expr_binary_to_ascii: case expr_reverse: case expr_filename: case expr_sname: case expr_pick_first_value: case expr_host_decl_name: case expr_config_option: case expr_leased_address: case expr_null: case expr_gethostname: log_error ("Data opcode in evaluate_dns_expression: %d", expr -> op); return 0; case expr_extract_int8: case expr_extract_int16: case expr_extract_int32: case expr_const_int: case expr_lease_time: case expr_dns_transaction: case expr_add: case expr_subtract: case expr_multiply: case expr_divide: case expr_remainder: case expr_binary_and: case expr_binary_or: case expr_binary_xor: case expr_client_state: log_error ("Numeric opcode in evaluate_dns_expression: %d", expr -> op); return 0; case expr_function: log_error ("Function opcode in evaluate_dns_expression: %d", expr -> op); return 0; case expr_arg: break; } log_error ("Bogus opcode in evaluate_dns_expression: %d", expr -> op); return 0; } #endif /* defined (NSUPDATE_OLD) */ int evaluate_boolean_expression (result, packet, lease, client_state, in_options, cfg_options, scope, expr) int *result; struct packet *packet; struct lease *lease; struct client_state *client_state; struct option_state *in_options; struct option_state *cfg_options; struct binding_scope **scope; struct expression *expr; { struct data_string left, right; int bleft, bright; int sleft, sright; struct binding *binding; struct binding_value *bv, *obv; #ifdef HAVE_REGEX_H int regflags = REG_EXTENDED | REG_NOSUB; regex_t re; #endif switch (expr -> op) { case expr_check: *result = check_collection (packet, lease, expr -> data.check); #if defined (DEBUG_EXPRESSIONS) log_debug ("bool: check (%s) returns %s", expr -> data.check -> name, *result ? "true" : "false"); #endif return 1; case expr_equal: case expr_not_equal: bv = obv = (struct binding_value *)0; sleft = evaluate_expression (&bv, packet, lease, client_state, in_options, cfg_options, scope, expr -> data.equal [0], MDL); sright = evaluate_expression (&obv, packet, lease, client_state, in_options, cfg_options, scope, expr -> data.equal [1], MDL); if (sleft && sright) { if (bv -> type != obv -> type) *result = expr -> op == expr_not_equal; else { switch (obv -> type) { case binding_boolean: if (bv -> value.boolean == obv -> value.boolean) *result = expr -> op == expr_equal; else *result = expr -> op == expr_not_equal; break; case binding_data: if ((bv -> value.data.len == obv -> value.data.len) && !memcmp (bv -> value.data.data, obv -> value.data.data, obv -> value.data.len)) *result = expr -> op == expr_equal; else *result = expr -> op == expr_not_equal; break; case binding_numeric: if (bv -> value.intval == obv -> value.intval) *result = expr -> op == expr_equal; else *result = expr -> op == expr_not_equal; break; #if defined (NSUPDATE_OLD) case binding_dns: #if defined (NSUPDATE) /* XXX This should be a comparison for equal XXX values, not for identity. */ if (bv -> value.dns == obv -> value.dns) *result = expr -> op == expr_equal; else *result = expr -> op == expr_not_equal; #else *result = expr -> op == expr_not_equal; #endif break; #endif /* NSUPDATE_OLD */ case binding_function: if (bv -> value.fundef == obv -> value.fundef) *result = expr -> op == expr_equal; else *result = expr -> op == expr_not_equal; break; default: *result = expr -> op == expr_not_equal; break; } } } else if (!sleft && !sright) *result = expr -> op == expr_equal; else *result = expr -> op == expr_not_equal; #if defined (DEBUG_EXPRESSIONS) log_debug ("bool: %sequal = %s", expr -> op == expr_not_equal ? "not" : "", (*result ? "true" : "false")); #endif if (sleft) binding_value_dereference (&bv, MDL); if (sright) binding_value_dereference (&obv, MDL); return 1; case expr_iregex_match: #ifdef HAVE_REGEX_H regflags |= REG_ICASE; #endif /* FALL THROUGH */ case expr_regex_match: #ifdef HAVE_REGEX_H memset(&left, 0, sizeof left); bleft = evaluate_data_expression(&left, packet, lease, client_state, in_options, cfg_options, scope, expr->data.equal[0], MDL); memset(&right, 0, sizeof right); bright = evaluate_data_expression(&right, packet, lease, client_state, in_options, cfg_options, scope, expr->data.equal[1], MDL); *result = 0; memset(&re, 0, sizeof(re)); if (bleft && bright && (left.data != NULL) && (right.data != NULL) && (regcomp(&re, (char *)right.data, regflags) == 0) && (regexec(&re, (char *)left.data, (size_t)0, NULL, 0) == 0)) *result = 1; #if defined (DEBUG_EXPRESSIONS) log_debug("bool: %s ~= %s yields %s", bleft ? print_hex_1(left.len, left.data, 20) : "NULL", bright ? print_hex_2 (right.len, right.data, 20) : "NULL", *result ? "true" : "false"); #endif if (bleft) data_string_forget(&left, MDL); if (bright) data_string_forget(&right, MDL); regfree(&re); /* * If we have bleft and bright then we have a good * syntax, otherwise not. * * XXX: we don't warn on invalid regular expression * syntax, should we? */ return bleft && bright; #else /* It shouldn't be possible to configure a regex operator * when there's no support. */ log_fatal("Impossible condition at %s:%d.", MDL); break; #endif case expr_and: sleft = evaluate_boolean_expression (&bleft, packet, lease, client_state, in_options, cfg_options, scope, expr -> data.and [0]); if (sleft && bleft) sright = evaluate_boolean_expression (&bright, packet, lease, client_state, in_options, cfg_options, scope, expr -> data.and [1]); else sright = bright = 0; #if defined (DEBUG_EXPRESSIONS) log_debug ("bool: and (%s, %s) = %s", sleft ? (bleft ? "true" : "false") : "NULL", sright ? (bright ? "true" : "false") : "NULL", ((sleft && sright) ? (bleft && bright ? "true" : "false") : "NULL")); #endif if (sleft && sright) { *result = bleft && bright; return 1; } return 0; case expr_or: bleft = bright = 0; sleft = evaluate_boolean_expression (&bleft, packet, lease, client_state, in_options, cfg_options, scope, expr -> data.or [0]); if (!sleft || !bleft) sright = evaluate_boolean_expression (&bright, packet, lease, client_state, in_options, cfg_options, scope, expr -> data.or [1]); else sright = 0; #if defined (DEBUG_EXPRESSIONS) log_debug ("bool: or (%s, %s) = %s", sleft ? (bleft ? "true" : "false") : "NULL", sright ? (bright ? "true" : "false") : "NULL", ((sleft || sright) ? (bleft || bright ? "true" : "false") : "NULL")); #endif if (sleft || sright) { *result = bleft || bright; return 1; } return 0; case expr_not: sleft = evaluate_boolean_expression (&bleft, packet, lease, client_state, in_options, cfg_options, scope, expr -> data.not); #if defined (DEBUG_EXPRESSIONS) log_debug ("bool: not (%s) = %s", sleft ? (bleft ? "true" : "false") : "NULL", ((sleft && sright) ? (!bleft ? "true" : "false") : "NULL")); #endif if (sleft) { *result = !bleft; return 1; } return 0; case expr_exists: memset (&left, 0, sizeof left); if (!in_options || !get_option (&left, expr -> data.exists -> universe, packet, lease, client_state, in_options, cfg_options, in_options, scope, expr -> data.exists -> code, MDL)) *result = 0; else { *result = 1; data_string_forget (&left, MDL); } #if defined (DEBUG_EXPRESSIONS) log_debug ("bool: exists %s.%s = %s", expr -> data.option -> universe -> name, expr -> data.option -> name, *result ? "true" : "false"); #endif return 1; case expr_known: if (!packet) { #if defined (DEBUG_EXPRESSIONS) log_debug ("bool: known = NULL"); #endif return 0; } #if defined (DEBUG_EXPRESSIONS) log_debug ("bool: known = %s", packet -> known ? "true" : "false"); #endif *result = packet -> known; return 1; case expr_static: if (!lease || !(lease -> flags & STATIC_LEASE)) { #if defined (DEBUG_EXPRESSIONS) log_debug ("bool: static = false (%s %s %s %d)", lease ? "y" : "n", (lease && (lease -> flags & STATIC_LEASE) ? "y" : "n"), piaddr (lease -> ip_addr), lease ? lease -> flags : 0); #endif *result = 0; return 1; } #if defined (DEBUG_EXPRESSIONS) log_debug ("bool: static = true"); #endif *result = 1; return 1; case expr_variable_exists: if (scope && *scope) { binding = find_binding (*scope, expr -> data.variable); if (binding) { if (binding -> value) *result = 1; else *result = 0; } else *result = 0; } else *result = 0; #if defined (DEBUG_EXPRESSIONS) log_debug ("boolean: %s? = %s", expr -> data.variable, *result ? "true" : "false"); #endif return 1; case expr_variable_reference: if (scope && *scope) { binding = find_binding (*scope, expr -> data.variable); if (binding && binding -> value) { if (binding -> value -> type == binding_boolean) { *result = binding -> value -> value.boolean; sleft = 1; } else { log_error ("binding type %d in %s.", binding -> value -> type, "evaluate_boolean_expression"); sleft = 0; } } else sleft = 0; } else sleft = 0; #if defined (DEBUG_EXPRESSIONS) log_debug ("boolean: %s = %s", expr -> data.variable, sleft ? (*result ? "true" : "false") : "NULL"); #endif return sleft; case expr_funcall: bv = (struct binding_value *)0; sleft = evaluate_expression (&bv, packet, lease, client_state, in_options, cfg_options, scope, expr, MDL); if (sleft) { if (bv -> type != binding_boolean) log_error ("%s() returned type %d in %s.", expr -> data.funcall.name, bv -> type, "evaluate_boolean_expression"); else *result = bv -> value.boolean; binding_value_dereference (&bv, MDL); } #if defined (DEBUG_EXPRESSIONS) log_debug ("boolean: %s() = %s", expr -> data.funcall.name, sleft ? (*result ? "true" : "false") : "NULL"); #endif break; case expr_none: case expr_match: case expr_substring: case expr_suffix: case expr_lcase: case expr_ucase: case expr_option: case expr_hardware: case expr_const_data: case expr_packet: case expr_concat: case expr_encapsulate: case expr_host_lookup: case expr_encode_int8: case expr_encode_int16: case expr_encode_int32: case expr_binary_to_ascii: case expr_reverse: case expr_pick_first_value: case expr_host_decl_name: case expr_config_option: case expr_leased_address: case expr_null: case expr_filename: case expr_sname: case expr_gethostname: log_error ("Data opcode in evaluate_boolean_expression: %d", expr -> op); return 0; case expr_extract_int8: case expr_extract_int16: case expr_extract_int32: case expr_const_int: case expr_lease_time: case expr_dns_transaction: case expr_add: case expr_subtract: case expr_multiply: case expr_divide: case expr_remainder: case expr_binary_and: case expr_binary_or: case expr_binary_xor: case expr_client_state: log_error ("Numeric opcode in evaluate_boolean_expression: %d", expr -> op); return 0; case expr_ns_add: case expr_ns_delete: case expr_ns_exists: case expr_ns_not_exists: log_error ("dns opcode in evaluate_boolean_expression: %d", expr -> op); return 0; case expr_function: log_error ("function definition in evaluate_boolean_expr"); return 0; case expr_arg: break; } log_error ("Bogus opcode in evaluate_boolean_expression: %d", expr -> op); return 0; } int evaluate_data_expression (result, packet, lease, client_state, in_options, cfg_options, scope, expr, file, line) struct data_string *result; struct packet *packet; struct lease *lease; struct client_state *client_state; struct option_state *in_options; struct option_state *cfg_options; struct binding_scope **scope; struct expression *expr; const char *file; int line; { struct data_string data, other; unsigned long offset, len, i; int s0, s1, s2, s3; int status; struct binding *binding; unsigned char *s; struct binding_value *bv; switch (expr -> op) { /* Extract N bytes starting at byte M of a data string. */ case expr_substring: memset (&data, 0, sizeof data); s0 = evaluate_data_expression (&data, packet, lease, client_state, in_options, cfg_options, scope, expr -> data.substring.expr, MDL); /* Evaluate the offset and length. */ s1 = evaluate_numeric_expression (&offset, packet, lease, client_state, in_options, cfg_options, scope, expr -> data.substring.offset); s2 = evaluate_numeric_expression (&len, packet, lease, client_state, in_options, cfg_options, scope, expr -> data.substring.len); if (s0 && s1 && s2) { /* If the offset is after end of the string, return an empty string. Otherwise, do the adjustments and return what's left. */ if (data.len > offset) { data_string_copy (result, &data, file, line); result -> len -= offset; if (result -> len > len) { result -> len = len; result -> terminated = 0; } result -> data += offset; } s3 = 1; } else s3 = 0; #if defined (DEBUG_EXPRESSIONS) log_debug ("data: substring (%s, %s, %s) = %s", s0 ? print_hex_1 (data.len, data.data, 30) : "NULL", s1 ? print_dec_1 (offset) : "NULL", s2 ? print_dec_2 (len) : "NULL", (s3 ? print_hex_2 (result -> len, result -> data, 30) : "NULL")); #endif if (s0) data_string_forget (&data, MDL); if (s3) return 1; return 0; /* Extract the last N bytes of a data string. */ case expr_suffix: memset (&data, 0, sizeof data); s0 = evaluate_data_expression (&data, packet, lease, client_state, in_options, cfg_options, scope, expr -> data.suffix.expr, MDL); /* Evaluate the length. */ s1 = evaluate_numeric_expression (&len, packet, lease, client_state, in_options, cfg_options, scope, expr -> data.suffix.len); if (s0 && s1) { data_string_copy (result, &data, file, line); /* If we are returning the last N bytes of a string whose length is <= N, just return the string - otherwise, compute a new starting address and decrease the length. */ if (data.len > len) { result -> data += data.len - len; result -> len = len; } data_string_forget (&data, MDL); } #if defined (DEBUG_EXPRESSIONS) log_debug ("data: suffix (%s, %s) = %s", s0 ? print_hex_1 (data.len, data.data, 30) : "NULL", s1 ? print_dec_1 (len) : "NULL", ((s0 && s1) ? print_hex_2 (result -> len, result -> data, 30) : "NULL")); #endif return s0 && s1; /* Convert string to lowercase. */ case expr_lcase: memset(&data, 0, sizeof data); s0 = evaluate_data_expression(&data, packet, lease, client_state, in_options, cfg_options, scope, expr->data.lcase, MDL); s1 = 0; if (s0) { result->len = data.len; if (buffer_allocate(&result->buffer, result->len + data.terminated, MDL)) { result->data = &result->buffer->data[0]; memcpy(result->buffer->data, data.data, data.len + data.terminated); result->terminated = data.terminated; s = (unsigned char *)result->data; for (i = 0; i < result->len; i++, s++) *s = tolower(*s); s1 = 1; } else { log_error("data: lcase: no buffer memory."); } } #if defined (DEBUG_EXPRESSIONS) log_debug("data: lcase (%s) = %s", s0 ? print_hex_1(data.len, data.data, 30) : "NULL", s1 ? print_hex_2(result->len, result->data, 30) : "NULL"); #endif if (s0) data_string_forget(&data, MDL); return s1; /* Convert string to uppercase. */ case expr_ucase: memset(&data, 0, sizeof data); s0 = evaluate_data_expression(&data, packet, lease, client_state, in_options, cfg_options, scope, expr->data.lcase, MDL); s1 = 0; if (s0) { result->len = data.len; if (buffer_allocate(&result->buffer, result->len + data.terminated, file, line)) { result->data = &result->buffer->data[0]; memcpy(result->buffer->data, data.data, data.len + data.terminated); result->terminated = data.terminated; s = (unsigned char *)result->data; for (i = 0; i < result->len; i++, s++) *s = toupper(*s); s1 = 1; } else { log_error("data: lcase: no buffer memory."); } } #if defined (DEBUG_EXPRESSIONS) log_debug("data: ucase (%s) = %s", s0 ? print_hex_1(data.len, data.data, 30) : "NULL", s1 ? print_hex_2(result->len, result->data, 30) : "NULL"); #endif if (s0) data_string_forget(&data, MDL); return s1; /* Extract an option. */ case expr_option: if (in_options) s0 = get_option (result, expr -> data.option -> universe, packet, lease, client_state, in_options, cfg_options, in_options, scope, expr -> data.option -> code, file, line); else s0 = 0; #if defined (DEBUG_EXPRESSIONS) log_debug ("data: option %s.%s = %s", expr -> data.option -> universe -> name, expr -> data.option -> name, s0 ? print_hex_1 (result -> len, result -> data, 60) : "NULL"); #endif return s0; case expr_config_option: if (cfg_options) s0 = get_option (result, expr -> data.option -> universe, packet, lease, client_state, in_options, cfg_options, cfg_options, scope, expr -> data.option -> code, file, line); else s0 = 0; #if defined (DEBUG_EXPRESSIONS) log_debug ("data: config-option %s.%s = %s", expr -> data.option -> universe -> name, expr -> data.option -> name, s0 ? print_hex_1 (result -> len, result -> data, 60) : "NULL"); #endif return s0; /* Combine the hardware type and address. */ case expr_hardware: /* On the client, hardware is our hardware. */ if (client_state) { memset (result, 0, sizeof *result); result -> data = client_state -> interface -> hw_address.hbuf; result -> len = client_state -> interface -> hw_address.hlen; #if defined (DEBUG_EXPRESSIONS) log_debug ("data: hardware = %s", print_hex_1 (result -> len, result -> data, 60)); #endif return 1; } /* The server cares about the client's hardware address, so only in the case where we are examining a packet can we return anything. */ if (!packet || !packet -> raw) { log_error ("data: hardware: raw packet not available"); return 0; } if (packet -> raw -> hlen > sizeof packet -> raw -> chaddr) { log_error ("data: hardware: invalid hlen (%d)\n", packet -> raw -> hlen); return 0; } result -> len = packet -> raw -> hlen + 1; if (buffer_allocate (&result -> buffer, result -> len, file, line)) { result -> data = &result -> buffer -> data [0]; result -> buffer -> data [0] = packet -> raw -> htype; memcpy (&result -> buffer -> data [1], packet -> raw -> chaddr, packet -> raw -> hlen); result -> terminated = 0; } else { log_error ("data: hardware: no memory for buffer."); return 0; } #if defined (DEBUG_EXPRESSIONS) log_debug ("data: hardware = %s", print_hex_1 (result -> len, result -> data, 60)); #endif return 1; /* Extract part of the raw packet. */ case expr_packet: if (!packet || !packet -> raw) { log_error ("data: packet: raw packet not available"); return 0; } s0 = evaluate_numeric_expression (&offset, packet, lease, client_state, in_options, cfg_options, scope, expr -> data.packet.offset); s1 = evaluate_numeric_expression (&len, packet, lease, client_state, in_options, cfg_options, scope, expr -> data.packet.len); if (s0 && s1 && offset < packet -> packet_length) { if (offset + len > packet -> packet_length) result -> len = packet -> packet_length - offset; else result -> len = len; if (buffer_allocate (&result -> buffer, result -> len, file, line)) { result -> data = &result -> buffer -> data [0]; memcpy (result -> buffer -> data, (((unsigned char *)(packet -> raw)) + offset), result -> len); result -> terminated = 0; } else { log_error ("data: packet: no buffer memory."); return 0; } s2 = 1; } else s2 = 0; #if defined (DEBUG_EXPRESSIONS) log_debug ("data: packet (%ld, %ld) = %s", offset, len, s2 ? print_hex_1 (result -> len, result -> data, 60) : NULL); #endif return s2; /* The encapsulation of all defined options in an option space... */ case expr_encapsulate: if (cfg_options) s0 = option_space_encapsulate (result, packet, lease, client_state, in_options, cfg_options, scope, &expr -> data.encapsulate); else s0 = 0; #if defined (DEBUG_EXPRESSIONS) log_debug ("data: encapsulate (%s) = %s", expr -> data.encapsulate.data, s0 ? print_hex_1 (result -> len, result -> data, 60) : "NULL"); #endif return s0; /* Some constant data... */ case expr_const_data: #if defined (DEBUG_EXPRESSIONS) log_debug ("data: const = %s", print_hex_1 (expr -> data.const_data.len, expr -> data.const_data.data, 60)); #endif data_string_copy (result, &expr -> data.const_data, file, line); return 1; /* Hostname lookup... */ case expr_host_lookup: s0 = do_host_lookup (result, expr -> data.host_lookup); #if defined (DEBUG_EXPRESSIONS) log_debug ("data: DNS lookup (%s) = %s", expr -> data.host_lookup -> hostname, (s0 ? print_dotted_quads (result -> len, result -> data) : "NULL")); #endif return s0; /* Concatenation... */ case expr_concat: memset (&data, 0, sizeof data); s0 = evaluate_data_expression (&data, packet, lease, client_state, in_options, cfg_options, scope, expr -> data.concat [0], MDL); memset (&other, 0, sizeof other); s1 = evaluate_data_expression (&other, packet, lease, client_state, in_options, cfg_options, scope, expr -> data.concat [1], MDL); if (s0 && s1) { result -> len = data.len + other.len; if (!buffer_allocate (&result -> buffer, (result -> len + other.terminated), file, line)) { log_error ("data: concat: no memory"); result -> len = 0; data_string_forget (&data, MDL); data_string_forget (&other, MDL); return 0; } result -> data = &result -> buffer -> data [0]; memcpy (result -> buffer -> data, data.data, data.len); memcpy (&result -> buffer -> data [data.len], other.data, other.len + other.terminated); } if (s0) data_string_forget (&data, MDL); if (s1) data_string_forget (&other, MDL); #if defined (DEBUG_EXPRESSIONS) log_debug ("data: concat (%s, %s) = %s", s0 ? print_hex_1 (data.len, data.data, 20) : "NULL", s1 ? print_hex_2 (other.len, other.data, 20) : "NULL", ((s0 && s1) ? print_hex_3 (result -> len, result -> data, 30) : "NULL")); #endif return s0 && s1; case expr_encode_int8: s0 = evaluate_numeric_expression (&len, packet, lease, client_state, in_options, cfg_options, scope, expr -> data.encode_int); if (s0) { result -> len = 1; if (!buffer_allocate (&result -> buffer, 1, file, line)) { log_error ("data: encode_int8: no memory"); result -> len = 0; s0 = 0; } else { result -> data = &result -> buffer -> data [0]; result -> buffer -> data [0] = len; } } else result -> len = 0; #if defined (DEBUG_EXPRESSIONS) if (!s0) log_debug ("data: encode_int8 (NULL) = NULL"); else log_debug ("data: encode_int8 (%ld) = %s", len, print_hex_2 (result -> len, result -> data, 20)); #endif return s0; case expr_encode_int16: s0 = evaluate_numeric_expression (&len, packet, lease, client_state, in_options, cfg_options, scope, expr -> data.encode_int); if (s0) { result -> len = 2; if (!buffer_allocate (&result -> buffer, 2, file, line)) { log_error ("data: encode_int16: no memory"); result -> len = 0; s0 = 0; } else { result -> data = &result -> buffer -> data [0]; putUShort (result -> buffer -> data, len); } } else result -> len = 0; #if defined (DEBUG_EXPRESSIONS) if (!s0) log_debug ("data: encode_int16 (NULL) = NULL"); else log_debug ("data: encode_int16 (%ld) = %s", len, print_hex_2 (result -> len, result -> data, 20)); #endif return s0; case expr_encode_int32: s0 = evaluate_numeric_expression (&len, packet, lease, client_state, in_options, cfg_options, scope, expr -> data.encode_int); if (s0) { result -> len = 4; if (!buffer_allocate (&result -> buffer, 4, file, line)) { log_error ("data: encode_int32: no memory"); result -> len = 0; s0 = 0; } else { result -> data = &result -> buffer -> data [0]; putULong (result -> buffer -> data, len); } } else result -> len = 0; #if defined (DEBUG_EXPRESSIONS) if (!s0) log_debug ("data: encode_int32 (NULL) = NULL"); else log_debug ("data: encode_int32 (%ld) = %s", len, print_hex_2 (result -> len, result -> data, 20)); #endif return s0; case expr_binary_to_ascii: /* Evaluate the base (offset) and width (len): */ s0 = evaluate_numeric_expression (&offset, packet, lease, client_state, in_options, cfg_options, scope, expr -> data.b2a.base); s1 = evaluate_numeric_expression (&len, packet, lease, client_state, in_options, cfg_options, scope, expr -> data.b2a.width); /* Evaluate the separator string. */ memset (&data, 0, sizeof data); s2 = evaluate_data_expression (&data, packet, lease, client_state, in_options, cfg_options, scope, expr -> data.b2a.separator, MDL); /* Evaluate the data to be converted. */ memset (&other, 0, sizeof other); s3 = evaluate_data_expression (&other, packet, lease, client_state, in_options, cfg_options, scope, expr -> data.b2a.buffer, MDL); if (s0 && s1 && s2 && s3) { unsigned buflen, i; if (len != 8 && len != 16 && len != 32) { log_info ("binary_to_ascii: %s %ld!", "invalid width", len); status = 0; goto b2a_out; } len /= 8; /* The buffer must be a multiple of the number's width. */ if (other.len % len) { log_info ("binary-to-ascii: %s %d %s %ld!", "length of buffer", other.len, "not a multiple of width", len); status = 0; goto b2a_out; } /* Count the width of the output. */ buflen = 0; for (i = 0; i < other.len; i += len) { if (len == 1) { if (offset == 8) { if (other.data [i] < 8) buflen++; else if (other.data [i] < 64) buflen += 2; else buflen += 3; } else if (offset == 10) { if (other.data [i] < 10) buflen++; else if (other.data [i] < 100) buflen += 2; else buflen += 3; } else if (offset == 16) { if (other.data [i] < 16) buflen++; else buflen += 2; } else buflen += (converted_length (&other.data [i], offset, 1)); } else buflen += (converted_length (&other.data [i], offset, len)); if (i + len != other.len) buflen += data.len; } if (!buffer_allocate (&result -> buffer, buflen + 1, file, line)) { log_error ("data: binary-to-ascii: no memory"); status = 0; goto b2a_out; } result -> data = &result -> buffer -> data [0]; result -> len = buflen; result -> terminated = 1; buflen = 0; for (i = 0; i < other.len; i += len) { buflen += (binary_to_ascii (&result -> buffer -> data [buflen], &other.data [i], offset, len)); if (i + len != other.len) { memcpy (&result -> buffer -> data [buflen], data.data, data.len); buflen += data.len; } } /* NUL terminate. */ result -> buffer -> data [buflen] = 0; status = 1; } else status = 0; b2a_out: #if defined (DEBUG_EXPRESSIONS) log_debug ("data: binary-to-ascii (%s, %s, %s, %s) = %s", s0 ? print_dec_1 (offset) : "NULL", s1 ? print_dec_2 (len) : "NULL", s2 ? print_hex_1 (data.len, data.data, 30) : "NULL", s3 ? print_hex_2 (other.len, other.data, 30) : "NULL", (status ? print_hex_3 (result -> len, result -> data, 30) : "NULL")); #endif if (s2) data_string_forget (&data, MDL); if (s3) data_string_forget (&other, MDL); if (status) return 1; return 0; case expr_reverse: /* Evaluate the width (len): */ s0 = evaluate_numeric_expression (&len, packet, lease, client_state, in_options, cfg_options, scope, expr -> data.reverse.width); /* Evaluate the data. */ memset (&data, 0, sizeof data); s1 = evaluate_data_expression (&data, packet, lease, client_state, in_options, cfg_options, scope, expr -> data.reverse.buffer, MDL); if (s0 && s1) { int i; /* The buffer must be a multiple of the number's width. */ if (data.len % len) { log_info ("reverse: %s %d %s %ld!", "length of buffer", data.len, "not a multiple of width", len); status = 0; goto reverse_out; } /* XXX reverse in place? I don't think we can. */ if (!buffer_allocate (&result -> buffer, data.len, file, line)) { log_error ("data: reverse: no memory"); status = 0; goto reverse_out; } result -> data = &result -> buffer -> data [0]; result -> len = data.len; result -> terminated = 0; for (i = 0; i < data.len; i += len) { memcpy (&result -> buffer -> data [i], &data.data [data.len - i - len], len); } status = 1; } else status = 0; reverse_out: #if defined (DEBUG_EXPRESSIONS) log_debug ("data: reverse (%s, %s) = %s", s0 ? print_dec_1 (len) : "NULL", s1 ? print_hex_1 (data.len, data.data, 30) : "NULL", (status ? print_hex_3 (result -> len, result -> data, 30) : "NULL")); #endif if (s0) data_string_forget (&data, MDL); if (status) return 1; return 0; case expr_leased_address: if (!lease) { log_debug("data: \"leased-address\" configuration " "directive: there is no lease associated " "with this client."); return 0; } result -> len = lease -> ip_addr.len; if (buffer_allocate (&result -> buffer, result -> len, file, line)) { result -> data = &result -> buffer -> data [0]; memcpy (&result -> buffer -> data [0], lease -> ip_addr.iabuf, lease -> ip_addr.len); result -> terminated = 0; } else { log_error ("data: leased-address: no memory."); return 0; } #if defined (DEBUG_EXPRESSIONS) log_debug ("data: leased-address = %s", print_hex_1 (result -> len, result -> data, 60)); #endif return 1; case expr_pick_first_value: memset (&data, 0, sizeof data); if ((evaluate_data_expression (result, packet, lease, client_state, in_options, cfg_options, scope, expr -> data.pick_first_value.car, MDL))) { #if defined (DEBUG_EXPRESSIONS) log_debug ("data: pick_first_value (%s, xxx)", print_hex_1 (result -> len, result -> data, 40)); #endif return 1; } if (expr -> data.pick_first_value.cdr && (evaluate_data_expression (result, packet, lease, client_state, in_options, cfg_options, scope, expr -> data.pick_first_value.cdr, MDL))) { #if defined (DEBUG_EXPRESSIONS) log_debug ("data: pick_first_value (NULL, %s)", print_hex_1 (result -> len, result -> data, 40)); #endif return 1; } #if defined (DEBUG_EXPRESSIONS) log_debug ("data: pick_first_value (NULL, NULL) = NULL"); #endif return 0; case expr_host_decl_name: if (!lease || !lease -> host) { log_error ("data: host_decl_name: not available"); return 0; } result -> len = strlen (lease -> host -> name); if (buffer_allocate (&result -> buffer, result -> len + 1, file, line)) { result -> data = &result -> buffer -> data [0]; strcpy ((char *)&result -> buffer -> data [0], lease -> host -> name); result -> terminated = 1; } else { log_error ("data: host-decl-name: no memory."); return 0; } #if defined (DEBUG_EXPRESSIONS) log_debug ("data: host-decl-name = %s", lease -> host -> name); #endif return 1; case expr_null: #if defined (DEBUG_EXPRESSIONS) log_debug ("data: null = NULL"); #endif return 0; case expr_variable_reference: if (scope && *scope) { binding = find_binding (*scope, expr -> data.variable); if (binding && binding -> value) { if (binding -> value -> type == binding_data) { data_string_copy (result, &binding -> value -> value.data, file, line); s0 = 1; } else if (binding -> value -> type != binding_data) { log_error ("binding type %d in %s.", binding -> value -> type, "evaluate_data_expression"); s0 = 0; } else s0 = 0; } else s0 = 0; } else s0 = 0; #if defined (DEBUG_EXPRESSIONS) log_debug ("data: %s = %s", expr -> data.variable, s0 ? print_hex_1 (result -> len, result -> data, 50) : "NULL"); #endif return s0; case expr_funcall: bv = (struct binding_value *)0; s0 = evaluate_expression (&bv, packet, lease, client_state, in_options, cfg_options, scope, expr, MDL); if (s0) { if (bv -> type != binding_data) log_error ("%s() returned type %d in %s.", expr -> data.funcall.name, bv -> type, "evaluate_data_expression"); else data_string_copy (result, &bv -> value.data, file, line); binding_value_dereference (&bv, MDL); } #if defined (DEBUG_EXPRESSIONS) log_debug ("data: %s = %s", expr -> data.funcall.name, s0 ? print_hex_1 (result -> len, result -> data, 50) : "NULL"); #endif break; /* Extract the filename. */ case expr_filename: if (packet && packet -> raw -> file [0]) { char *fn = memchr (packet -> raw -> file, 0, sizeof packet -> raw -> file); if (!fn) fn = ((char *)packet -> raw -> file + sizeof packet -> raw -> file); result -> len = fn - &(packet -> raw -> file [0]); if (buffer_allocate (&result -> buffer, result -> len + 1, file, line)) { result -> data = &result -> buffer -> data [0]; memcpy (&result -> buffer -> data [0], packet -> raw -> file, result -> len); result -> buffer -> data [result -> len] = 0; result -> terminated = 1; s0 = 1; } else { log_error ("data: filename: no memory."); s0 = 0; } } else s0 = 0; #if defined (DEBUG_EXPRESSIONS) log_info ("data: filename = \"%s\"", s0 ? (const char *)(result -> data) : "NULL"); #endif return s0; /* Extract the server name. */ case expr_sname: if (packet && packet -> raw -> sname [0]) { char *fn = memchr (packet -> raw -> sname, 0, sizeof packet -> raw -> sname); if (!fn) fn = ((char *)packet -> raw -> sname + sizeof packet -> raw -> sname); result -> len = fn - &packet -> raw -> sname [0]; if (buffer_allocate (&result -> buffer, result -> len + 1, file, line)) { result -> data = &result -> buffer -> data [0]; memcpy (&result -> buffer -> data [0], packet -> raw -> sname, result -> len); result -> buffer -> data [result -> len] = 0; result -> terminated = 1; s0 = 1; } else { log_error ("data: sname: no memory."); s0 = 0; } } else s0 = 0; #if defined (DEBUG_EXPRESSIONS) log_info ("data: sname = \"%s\"", s0 ? (const char *)(result -> data) : "NULL"); #endif return s0; /* Provide the system's local hostname as a return value. */ case expr_gethostname: /* * Allocate a buffer to return. * * The largest valid hostname is maybe 64 octets at a single * label, or 255 octets if you think a hostname is allowed * to contain labels (plus termination). */ memset(result, 0, sizeof(*result)); if (!buffer_allocate(&result->buffer, 255, file, line)) { log_error("data: gethostname(): no memory for buffer"); return 0; } result->data = result->buffer->data; /* * On successful completion, gethostname() resturns 0. It may * not null-terminate the string if there was insufficient * space. */ if (!gethostname((char *)result->buffer->data, 255)) { if (result->buffer->data[255] == '\0') result->len = strlen((char *)result->buffer->data); else result->len = 255; return 1; } data_string_forget(result, MDL); return 0; case expr_check: case expr_equal: case expr_not_equal: case expr_regex_match: case expr_iregex_match: case expr_and: case expr_or: case expr_not: case expr_match: case expr_static: case expr_known: case expr_none: case expr_exists: case expr_variable_exists: log_error ("Boolean opcode in evaluate_data_expression: %d", expr -> op); return 0; case expr_extract_int8: case expr_extract_int16: case expr_extract_int32: case expr_const_int: case expr_lease_time: case expr_dns_transaction: case expr_add: case expr_subtract: case expr_multiply: case expr_divide: case expr_remainder: case expr_binary_and: case expr_binary_or: case expr_binary_xor: case expr_client_state: log_error ("Numeric opcode in evaluate_data_expression: %d", expr -> op); return 0; case expr_ns_add: case expr_ns_delete: case expr_ns_exists: case expr_ns_not_exists: log_error ("dns update opcode in evaluate_data_expression: %d", expr -> op); return 0; case expr_function: log_error ("function definition in evaluate_data_expression"); return 0; case expr_arg: break; } log_error ("Bogus opcode in evaluate_data_expression: %d", expr -> op); return 0; } int evaluate_numeric_expression (result, packet, lease, client_state, in_options, cfg_options, scope, expr) unsigned long *result; struct packet *packet; struct lease *lease; struct client_state *client_state; struct option_state *in_options; struct option_state *cfg_options; struct binding_scope **scope; struct expression *expr; { struct data_string data; int status, sleft, sright; #if defined (NSUPDATE_OLD) ns_updrec *nut; ns_updque uq; struct expression *cur, *next; #endif struct binding *binding; struct binding_value *bv; unsigned long ileft, iright; switch (expr -> op) { case expr_check: case expr_equal: case expr_not_equal: case expr_regex_match: case expr_iregex_match: case expr_and: case expr_or: case expr_not: case expr_match: case expr_static: case expr_known: case expr_none: case expr_exists: case expr_variable_exists: log_error ("Boolean opcode in evaluate_numeric_expression: %d", expr -> op); return 0; case expr_substring: case expr_suffix: case expr_lcase: case expr_ucase: case expr_option: case expr_hardware: case expr_const_data: case expr_packet: case expr_concat: case expr_encapsulate: case expr_host_lookup: case expr_encode_int8: case expr_encode_int16: case expr_encode_int32: case expr_binary_to_ascii: case expr_reverse: case expr_filename: case expr_sname: case expr_pick_first_value: case expr_host_decl_name: case expr_config_option: case expr_leased_address: case expr_null: case expr_gethostname: log_error ("Data opcode in evaluate_numeric_expression: %d", expr -> op); return 0; case expr_extract_int8: memset (&data, 0, sizeof data); status = evaluate_data_expression (&data, packet, lease, client_state, in_options, cfg_options, scope, expr -> data.extract_int, MDL); if (status) *result = data.data [0]; #if defined (DEBUG_EXPRESSIONS) log_debug ("num: extract_int8 (%s) = %s", status ? print_hex_1 (data.len, data.data, 60) : "NULL", status ? print_dec_1 (*result) : "NULL" ); #endif if (status) data_string_forget (&data, MDL); return status; case expr_extract_int16: memset (&data, 0, sizeof data); status = (evaluate_data_expression (&data, packet, lease, client_state, in_options, cfg_options, scope, expr -> data.extract_int, MDL)); if (status && data.len >= 2) *result = getUShort (data.data); #if defined (DEBUG_EXPRESSIONS) log_debug ("num: extract_int16 (%s) = %ld", ((status && data.len >= 2) ? print_hex_1 (data.len, data.data, 60) : "NULL"), *result); #endif if (status) data_string_forget (&data, MDL); return (status && data.len >= 2); case expr_extract_int32: memset (&data, 0, sizeof data); status = (evaluate_data_expression (&data, packet, lease, client_state, in_options, cfg_options, scope, expr -> data.extract_int, MDL)); if (status && data.len >= 4) *result = getULong (data.data); #if defined (DEBUG_EXPRESSIONS) log_debug ("num: extract_int32 (%s) = %ld", ((status && data.len >= 4) ? print_hex_1 (data.len, data.data, 60) : "NULL"), *result); #endif if (status) data_string_forget (&data, MDL); return (status && data.len >= 4); case expr_const_int: *result = expr -> data.const_int; #if defined (DEBUG_EXPRESSIONS) log_debug ("number: CONSTANT = %ld", *result); #endif return 1; case expr_lease_time: if (!lease) { log_error ("data: leased_lease: not available"); return 0; } if (lease -> ends < cur_time) { log_error ("%s %lu when it is now %lu", "data: lease_time: lease ends at", (long)(lease -> ends), (long)cur_time); return 0; } *result = lease -> ends - cur_time; #if defined (DEBUG_EXPRESSIONS) log_debug ("number: lease-time = (%lu - %lu) = %ld", lease -> ends, cur_time, *result); #endif return 1; case expr_dns_transaction: #if !defined (NSUPDATE_OLD) return 0; #else if (!resolver_inited) { minires_ninit (&resolver_state); resolver_inited = 1; resolver_state.retrans = 1; resolver_state.retry = 1; } ISC_LIST_INIT (uq); cur = expr; do { next = cur -> data.dns_transaction.cdr; nut = 0; status = (evaluate_dns_expression (&nut, packet, lease, client_state, in_options, cfg_options, scope, cur -> data.dns_transaction.car)); if (!status) goto dns_bad; ISC_LIST_APPEND (uq, nut, r_link); cur = next; } while (next); /* Do the update and record the error code, if there was an error; otherwise set it to NOERROR. */ *result = minires_nupdate (&resolver_state, ISC_LIST_HEAD (uq)); status = 1; print_dns_status ((int)*result, &uq); dns_bad: while (!ISC_LIST_EMPTY (uq)) { ns_updrec *tmp = ISC_LIST_HEAD (uq); ISC_LIST_UNLINK (uq, tmp, r_link); if (tmp -> r_data_ephem) { dfree (tmp -> r_data_ephem, MDL); tmp -> r_data = (unsigned char *)0; tmp -> r_data_ephem = (unsigned char *)0; } minires_freeupdrec (tmp); } return status; #endif /* NSUPDATE_OLD */ case expr_variable_reference: if (scope && *scope) { binding = find_binding (*scope, expr -> data.variable); if (binding && binding -> value) { if (binding -> value -> type == binding_numeric) { *result = binding -> value -> value.intval; status = 1; } else { log_error ("binding type %d in %s.", binding -> value -> type, "evaluate_numeric_expression"); status = 0; } } else status = 0; } else status = 0; #if defined (DEBUG_EXPRESSIONS) if (status) log_debug ("numeric: %s = %ld", expr -> data.variable, *result); else log_debug ("numeric: %s = NULL", expr -> data.variable); #endif return status; case expr_funcall: bv = (struct binding_value *)0; status = evaluate_expression (&bv, packet, lease, client_state, in_options, cfg_options, scope, expr, MDL); if (status) { if (bv -> type != binding_numeric) log_error ("%s() returned type %d in %s.", expr -> data.funcall.name, bv -> type, "evaluate_numeric_expression"); else *result = bv -> value.intval; binding_value_dereference (&bv, MDL); } #if defined (DEBUG_EXPRESSIONS) log_debug ("data: %s = %ld", expr -> data.funcall.name, status ? *result : 0); #endif break; case expr_add: sleft = evaluate_numeric_expression (&ileft, packet, lease, client_state, in_options, cfg_options, scope, expr -> data.and [0]); sright = evaluate_numeric_expression (&iright, packet, lease, client_state, in_options, cfg_options, scope, expr -> data.and [1]); #if defined (DEBUG_EXPRESSIONS) if (sleft && sright) log_debug ("num: %ld + %ld = %ld", ileft, iright, ileft + iright); else if (sleft) log_debug ("num: %ld + NULL = NULL", ileft); else log_debug ("num: NULL + %ld = NULL", iright); #endif if (sleft && sright) { *result = ileft + iright; return 1; } return 0; case expr_subtract: sleft = evaluate_numeric_expression (&ileft, packet, lease, client_state, in_options, cfg_options, scope, expr -> data.and [0]); sright = evaluate_numeric_expression (&iright, packet, lease, client_state, in_options, cfg_options, scope, expr -> data.and [1]); #if defined (DEBUG_EXPRESSIONS) if (sleft && sright) log_debug ("num: %ld - %ld = %ld", ileft, iright, ileft - iright); else if (sleft) log_debug ("num: %ld - NULL = NULL", ileft); else log_debug ("num: NULL - %ld = NULL", iright); #endif if (sleft && sright) { *result = ileft - iright; return 1; } return 0; case expr_multiply: sleft = evaluate_numeric_expression (&ileft, packet, lease, client_state, in_options, cfg_options, scope, expr -> data.and [0]); sright = evaluate_numeric_expression (&iright, packet, lease, client_state, in_options, cfg_options, scope, expr -> data.and [1]); #if defined (DEBUG_EXPRESSIONS) if (sleft && sright) log_debug ("num: %ld * %ld = %ld", ileft, iright, ileft * iright); else if (sleft) log_debug ("num: %ld * NULL = NULL", ileft); else log_debug ("num: NULL * %ld = NULL", iright); #endif if (sleft && sright) { *result = ileft * iright; return 1; } return 0; case expr_divide: sleft = evaluate_numeric_expression (&ileft, packet, lease, client_state, in_options, cfg_options, scope, expr -> data.and [0]); sright = evaluate_numeric_expression (&iright, packet, lease, client_state, in_options, cfg_options, scope, expr -> data.and [1]); #if defined (DEBUG_EXPRESSIONS) if (sleft && sright) { if (iright != 0) log_debug ("num: %ld / %ld = %ld", ileft, iright, ileft / iright); else log_debug ("num: %ld / %ld = NULL", ileft, iright); } else if (sleft) log_debug ("num: %ld / NULL = NULL", ileft); else log_debug ("num: NULL / %ld = NULL", iright); #endif if (sleft && sright && iright) { *result = ileft / iright; return 1; } return 0; case expr_remainder: sleft = evaluate_numeric_expression (&ileft, packet, lease, client_state, in_options, cfg_options, scope, expr -> data.and [0]); sright = evaluate_numeric_expression (&iright, packet, lease, client_state, in_options, cfg_options, scope, expr -> data.and [1]); #if defined (DEBUG_EXPRESSIONS) if (sleft && sright) { if (iright != 0) log_debug ("num: %ld %% %ld = %ld", ileft, iright, ileft % iright); else log_debug ("num: %ld %% %ld = NULL", ileft, iright); } else if (sleft) log_debug ("num: %ld %% NULL = NULL", ileft); else log_debug ("num: NULL %% %ld = NULL", iright); #endif if (sleft && sright && iright) { *result = ileft % iright; return 1; } return 0; case expr_binary_and: sleft = evaluate_numeric_expression (&ileft, packet, lease, client_state, in_options, cfg_options, scope, expr -> data.and [0]); sright = evaluate_numeric_expression (&iright, packet, lease, client_state, in_options, cfg_options, scope, expr -> data.and [1]); #if defined (DEBUG_EXPRESSIONS) if (sleft && sright) log_debug ("num: %ld | %ld = %ld", ileft, iright, ileft & iright); else if (sleft) log_debug ("num: %ld & NULL = NULL", ileft); else log_debug ("num: NULL & %ld = NULL", iright); #endif if (sleft && sright) { *result = ileft & iright; return 1; } return 0; case expr_binary_or: sleft = evaluate_numeric_expression (&ileft, packet, lease, client_state, in_options, cfg_options, scope, expr -> data.and [0]); sright = evaluate_numeric_expression (&iright, packet, lease, client_state, in_options, cfg_options, scope, expr -> data.and [1]); #if defined (DEBUG_EXPRESSIONS) if (sleft && sright) log_debug ("num: %ld | %ld = %ld", ileft, iright, ileft | iright); else if (sleft) log_debug ("num: %ld | NULL = NULL", ileft); else log_debug ("num: NULL | %ld = NULL", iright); #endif if (sleft && sright) { *result = ileft | iright; return 1; } return 0; case expr_binary_xor: sleft = evaluate_numeric_expression (&ileft, packet, lease, client_state, in_options, cfg_options, scope, expr -> data.and [0]); sright = evaluate_numeric_expression (&iright, packet, lease, client_state, in_options, cfg_options, scope, expr -> data.and [1]); #if defined (DEBUG_EXPRESSIONS) if (sleft && sright) log_debug ("num: %ld ^ %ld = %ld", ileft, iright, ileft ^ iright); else if (sleft) log_debug ("num: %ld ^ NULL = NULL", ileft); else log_debug ("num: NULL ^ %ld = NULL", iright); #endif if (sleft && sright) { *result = ileft ^ iright; return 1; } return 0; case expr_client_state: if (client_state) { #if defined (DEBUG_EXPRESSIONS) log_debug ("num: client-state = %d", client_state -> state); #endif *result = client_state -> state; return 1; } else { #if defined (DEBUG_EXPRESSIONS) log_debug ("num: client-state = NULL"); #endif return 0; } case expr_ns_add: case expr_ns_delete: case expr_ns_exists: case expr_ns_not_exists: log_error ("dns opcode in evaluate_numeric_expression: %d", expr -> op); return 0; case expr_function: log_error ("function definition in evaluate_numeric_expr"); return 0; case expr_arg: break; default: log_fatal("Impossible case at %s:%d. Undefined operator " "%d.", MDL, expr->op); break; } log_error ("evaluate_numeric_expression: bogus opcode %d", expr -> op); return 0; } /* Return data hanging off of an option cache structure, or if there isn't any, evaluate the expression hanging off of it and return the result of that evaluation. There should never be both an expression and a valid data_string. */ int evaluate_option_cache (result, packet, lease, client_state, in_options, cfg_options, scope, oc, file, line) struct data_string *result; struct packet *packet; struct lease *lease; struct client_state *client_state; struct option_state *in_options; struct option_state *cfg_options; struct binding_scope **scope; struct option_cache *oc; const char *file; int line; { if (oc->data.data != NULL) { data_string_copy (result, &oc -> data, file, line); return 1; } if (!oc -> expression) return 0; return evaluate_data_expression (result, packet, lease, client_state, in_options, cfg_options, scope, oc -> expression, file, line); } /* Evaluate an option cache and extract a boolean from the result, returning the boolean. Return false if there is no data. */ int evaluate_boolean_option_cache (ignorep, packet, lease, client_state, in_options, cfg_options, scope, oc, file, line) int *ignorep; struct packet *packet; struct lease *lease; struct client_state *client_state; struct option_state *in_options; struct option_state *cfg_options; struct binding_scope **scope; struct option_cache *oc; const char *file; int line; { struct data_string ds; int result; /* So that we can be called with option_lookup as an argument. */ if (!oc || !in_options) return 0; memset (&ds, 0, sizeof ds); if (!evaluate_option_cache (&ds, packet, lease, client_state, in_options, cfg_options, scope, oc, file, line)) return 0; /* The boolean option cache is actually a trinary value. Zero is * off, one is on, and 2 is 'ignore'. */ if (ds.len) { result = ds.data [0]; if (result == 2) { result = 0; if (ignorep != NULL) *ignorep = 1; } else if (ignorep != NULL) *ignorep = 0; } else result = 0; data_string_forget (&ds, MDL); return result; } /* Evaluate a boolean expression and return the result of the evaluation, or FALSE if it failed. */ int evaluate_boolean_expression_result (ignorep, packet, lease, client_state, in_options, cfg_options, scope, expr) int *ignorep; struct packet *packet; struct lease *lease; struct client_state *client_state; struct option_state *in_options; struct option_state *cfg_options; struct binding_scope **scope; struct expression *expr; { int result; /* So that we can be called with option_lookup as an argument. */ if (!expr) return 0; if (!evaluate_boolean_expression (&result, packet, lease, client_state, in_options, cfg_options, scope, expr)) return 0; if (result == 2) { *ignorep = 1; result = 0; } else *ignorep = 0; return result; } /* Dereference an expression node, and if the reference count goes to zero, dereference any data it refers to, and then free it. */ void expression_dereference (eptr, file, line) struct expression **eptr; const char *file; int line; { struct expression *expr = *eptr; /* Zero the pointer. */ *eptr = (struct expression *)0; /* Decrement the reference count. If it's nonzero, we're done. */ --(expr -> refcnt); rc_register (file, line, eptr, expr, expr -> refcnt, 1, RC_MISC); if (expr -> refcnt > 0) return; if (expr -> refcnt < 0) { log_error ("%s(%d): negative refcnt!", file, line); #if defined (DEBUG_RC_HISTORY) dump_rc_history (expr); #endif #if defined (POINTER_DEBUG) abort (); #else return; #endif } /* Dereference subexpressions. */ switch (expr -> op) { /* All the binary operators can be handled the same way. */ case expr_equal: case expr_not_equal: case expr_regex_match: case expr_iregex_match: case expr_concat: case expr_and: case expr_or: case expr_add: case expr_subtract: case expr_multiply: case expr_divide: case expr_remainder: case expr_binary_and: case expr_binary_or: case expr_binary_xor: case expr_client_state: if (expr -> data.equal [0]) expression_dereference (&expr -> data.equal [0], file, line); if (expr -> data.equal [1]) expression_dereference (&expr -> data.equal [1], file, line); break; case expr_substring: if (expr -> data.substring.expr) expression_dereference (&expr -> data.substring.expr, file, line); if (expr -> data.substring.offset) expression_dereference (&expr -> data.substring.offset, file, line); if (expr -> data.substring.len) expression_dereference (&expr -> data.substring.len, file, line); break; case expr_suffix: if (expr -> data.suffix.expr) expression_dereference (&expr -> data.suffix.expr, file, line); if (expr -> data.suffix.len) expression_dereference (&expr -> data.suffix.len, file, line); break; case expr_lcase: if (expr->data.lcase) expression_dereference(&expr->data.lcase, MDL); break; case expr_ucase: if (expr->data.ucase) expression_dereference(&expr->data.ucase, MDL); break; case expr_not: if (expr -> data.not) expression_dereference (&expr -> data.not, file, line); break; case expr_packet: if (expr -> data.packet.offset) expression_dereference (&expr -> data.packet.offset, file, line); if (expr -> data.packet.len) expression_dereference (&expr -> data.packet.len, file, line); break; case expr_extract_int8: case expr_extract_int16: case expr_extract_int32: if (expr -> data.extract_int) expression_dereference (&expr -> data.extract_int, file, line); break; case expr_encode_int8: case expr_encode_int16: case expr_encode_int32: if (expr -> data.encode_int) expression_dereference (&expr -> data.encode_int, file, line); break; case expr_encapsulate: case expr_const_data: data_string_forget (&expr -> data.const_data, file, line); break; case expr_host_lookup: if (expr -> data.host_lookup) dns_host_entry_dereference (&expr -> data.host_lookup, file, line); break; case expr_binary_to_ascii: if (expr -> data.b2a.base) expression_dereference (&expr -> data.b2a.base, file, line); if (expr -> data.b2a.width) expression_dereference (&expr -> data.b2a.width, file, line); if (expr -> data.b2a.separator) expression_dereference (&expr -> data.b2a.separator, file, line); if (expr -> data.b2a.buffer) expression_dereference (&expr -> data.b2a.buffer, file, line); break; case expr_pick_first_value: if (expr -> data.pick_first_value.car) expression_dereference (&expr -> data.pick_first_value.car, file, line); if (expr -> data.pick_first_value.cdr) expression_dereference (&expr -> data.pick_first_value.cdr, file, line); break; case expr_reverse: if (expr -> data.reverse.width) expression_dereference (&expr -> data.reverse.width, file, line); if (expr -> data.reverse.buffer) expression_dereference (&expr -> data.reverse.buffer, file, line); break; case expr_dns_transaction: if (expr -> data.dns_transaction.car) expression_dereference (&expr -> data.dns_transaction.car, file, line); if (expr -> data.dns_transaction.cdr) expression_dereference (&expr -> data.dns_transaction.cdr, file, line); break; case expr_ns_add: if (expr -> data.ns_add.rrname) expression_dereference (&expr -> data.ns_add.rrname, file, line); if (expr -> data.ns_add.rrdata) expression_dereference (&expr -> data.ns_add.rrdata, file, line); if (expr -> data.ns_add.ttl) expression_dereference (&expr -> data.ns_add.ttl, file, line); break; case expr_ns_delete: case expr_ns_exists: case expr_ns_not_exists: if (expr -> data.ns_delete.rrname) expression_dereference (&expr -> data.ns_delete.rrname, file, line); if (expr -> data.ns_delete.rrdata) expression_dereference (&expr -> data.ns_delete.rrdata, file, line); break; case expr_variable_reference: case expr_variable_exists: if (expr -> data.variable) dfree (expr -> data.variable, file, line); break; case expr_funcall: if (expr -> data.funcall.name) dfree (expr -> data.funcall.name, file, line); if (expr -> data.funcall.arglist) expression_dereference (&expr -> data.funcall.arglist, file, line); break; case expr_arg: if (expr -> data.arg.val) expression_dereference (&expr -> data.arg.val, file, line); if (expr -> data.arg.next) expression_dereference (&expr -> data.arg.next, file, line); break; case expr_function: fundef_dereference (&expr -> data.func, file, line); break; /* No subexpressions. */ case expr_leased_address: case expr_lease_time: case expr_filename: case expr_sname: case expr_const_int: case expr_check: case expr_option: case expr_hardware: case expr_exists: case expr_known: case expr_null: case expr_gethostname: break; default: break; } free_expression (expr, MDL); } int is_dns_expression (expr) struct expression *expr; { return (expr -> op == expr_ns_add || expr -> op == expr_ns_delete || expr -> op == expr_ns_exists || expr -> op == expr_ns_not_exists); } int is_boolean_expression (expr) struct expression *expr; { return (expr -> op == expr_check || expr -> op == expr_exists || expr -> op == expr_variable_exists || expr -> op == expr_equal || expr -> op == expr_not_equal || expr->op == expr_regex_match || expr->op == expr_iregex_match || expr -> op == expr_and || expr -> op == expr_or || expr -> op == expr_not || expr -> op == expr_known || expr -> op == expr_static); } int is_data_expression (expr) struct expression *expr; { return (expr->op == expr_substring || expr->op == expr_suffix || expr->op == expr_lcase || expr->op == expr_ucase || expr->op == expr_option || expr->op == expr_hardware || expr->op == expr_const_data || expr->op == expr_packet || expr->op == expr_concat || expr->op == expr_encapsulate || expr->op == expr_encode_int8 || expr->op == expr_encode_int16 || expr->op == expr_encode_int32 || expr->op == expr_host_lookup || expr->op == expr_binary_to_ascii || expr->op == expr_filename || expr->op == expr_sname || expr->op == expr_reverse || expr->op == expr_pick_first_value || expr->op == expr_host_decl_name || expr->op == expr_leased_address || expr->op == expr_config_option || expr->op == expr_null || expr->op == expr_gethostname); } int is_numeric_expression (expr) struct expression *expr; { return (expr -> op == expr_extract_int8 || expr -> op == expr_extract_int16 || expr -> op == expr_extract_int32 || expr -> op == expr_const_int || expr -> op == expr_lease_time || expr -> op == expr_dns_transaction || expr -> op == expr_add || expr -> op == expr_subtract || expr -> op == expr_multiply || expr -> op == expr_divide || expr -> op == expr_remainder || expr -> op == expr_binary_and || expr -> op == expr_binary_or || expr -> op == expr_binary_xor || expr -> op == expr_client_state); } int is_compound_expression (expr) struct expression *expr; { return (expr -> op == expr_ns_add || expr -> op == expr_ns_delete || expr -> op == expr_ns_exists || expr -> op == expr_ns_not_exists || expr -> op == expr_substring || expr -> op == expr_suffix || expr -> op == expr_option || expr -> op == expr_concat || expr -> op == expr_encode_int8 || expr -> op == expr_encode_int16 || expr -> op == expr_encode_int32 || expr -> op == expr_binary_to_ascii || expr -> op == expr_reverse || expr -> op == expr_pick_first_value || expr -> op == expr_config_option || expr -> op == expr_extract_int8 || expr -> op == expr_extract_int16 || expr -> op == expr_extract_int32 || expr -> op == expr_dns_transaction); } static int op_val (enum expr_op); static int op_val (op) enum expr_op op; { switch (op) { case expr_none: case expr_match: case expr_static: case expr_check: case expr_substring: case expr_suffix: case expr_lcase: case expr_ucase: case expr_concat: case expr_encapsulate: case expr_host_lookup: case expr_not: case expr_option: case expr_hardware: case expr_packet: case expr_const_data: case expr_extract_int8: case expr_extract_int16: case expr_extract_int32: case expr_encode_int8: case expr_encode_int16: case expr_encode_int32: case expr_const_int: case expr_exists: case expr_variable_exists: case expr_known: case expr_binary_to_ascii: case expr_reverse: case expr_filename: case expr_sname: case expr_pick_first_value: case expr_host_decl_name: case expr_config_option: case expr_leased_address: case expr_lease_time: case expr_dns_transaction: case expr_null: case expr_variable_reference: case expr_ns_add: case expr_ns_delete: case expr_ns_exists: case expr_ns_not_exists: case expr_arg: case expr_funcall: case expr_function: /* XXXDPN: Need to assign sane precedences to these. */ case expr_binary_and: case expr_binary_or: case expr_binary_xor: case expr_client_state: case expr_gethostname: return 100; case expr_equal: case expr_not_equal: case expr_regex_match: case expr_iregex_match: return 4; case expr_or: case expr_and: return 3; case expr_add: case expr_subtract: return 2; case expr_multiply: case expr_divide: case expr_remainder: return 1; } return 100; } int op_precedence (op1, op2) enum expr_op op1, op2; { return op_val (op1) - op_val (op2); } enum expression_context expression_context (struct expression *expr) { if (is_data_expression (expr)) return context_data; if (is_numeric_expression (expr)) return context_numeric; if (is_boolean_expression (expr)) return context_boolean; if (is_dns_expression (expr)) return context_dns; return context_any; } enum expression_context op_context (op) enum expr_op op; { switch (op) { /* XXX Why aren't these specific? */ case expr_none: case expr_match: case expr_static: case expr_check: case expr_substring: case expr_suffix: case expr_lcase: case expr_ucase: case expr_concat: case expr_encapsulate: case expr_host_lookup: case expr_not: case expr_option: case expr_hardware: case expr_packet: case expr_const_data: case expr_extract_int8: case expr_extract_int16: case expr_extract_int32: case expr_encode_int8: case expr_encode_int16: case expr_encode_int32: case expr_const_int: case expr_exists: case expr_variable_exists: case expr_known: case expr_binary_to_ascii: case expr_reverse: case expr_filename: case expr_sname: case expr_pick_first_value: case expr_host_decl_name: case expr_config_option: case expr_leased_address: case expr_lease_time: case expr_null: case expr_variable_reference: case expr_ns_add: case expr_ns_delete: case expr_ns_exists: case expr_ns_not_exists: case expr_dns_transaction: case expr_arg: case expr_funcall: case expr_function: case expr_gethostname: return context_any; case expr_equal: case expr_not_equal: case expr_regex_match: case expr_iregex_match: return context_data; case expr_and: return context_boolean; case expr_or: return context_boolean; case expr_add: case expr_subtract: case expr_multiply: case expr_divide: case expr_remainder: case expr_binary_and: case expr_binary_or: case expr_binary_xor: case expr_client_state: return context_numeric; } return context_any; } int write_expression (file, expr, col, indent, firstp) FILE *file; struct expression *expr; int col; int indent; int firstp; { struct expression *e; const char *s; char obuf [65]; int scol; int width; /* If this promises to be a fat expression, start a new line. */ if (!firstp && is_compound_expression (expr)) { indent_spaces (file, indent); col = indent; } switch (expr -> op) { case expr_none: col = token_print_indent (file, col, indent, "", "", "null"); break; case expr_check: col = token_print_indent (file, col, indent, "", "", "check"); col = token_print_indent_concat (file, col, indent, " ", "", "\"", expr -> data.check -> name, "\"", (char *)0); break; case expr_regex_match: s = "~="; goto binary; case expr_iregex_match: s = "~~"; goto binary; case expr_not_equal: s = "!="; goto binary; case expr_equal: s = "="; binary: col = write_expression (file, expr -> data.equal [0], col, indent, 1); col = token_print_indent (file, col, indent, " ", " ", s); col = write_expression (file, expr -> data.equal [1], col, indent + 2, 0); break; case expr_substring: col = token_print_indent (file, col, indent, "", "", "substring"); col = token_print_indent (file, col, indent, " ", "", "("); scol = col; col = write_expression (file, expr -> data.substring.expr, col, scol, 1); col = token_print_indent (file, col, indent, "", " ", ","); col = write_expression (file, expr -> data.substring.offset, col, indent, 0); col = token_print_indent (file, col, scol, "", " ", ","); col = write_expression (file, expr -> data.substring.len, col, scol, 0); col = token_print_indent (file, col, indent, "", "", ")"); break; case expr_suffix: col = token_print_indent (file, col, indent, "", "", "suffix"); col = token_print_indent (file, col, indent, " ", "", "("); scol = col; col = write_expression (file, expr -> data.suffix.expr, col, scol, 1); col = token_print_indent (file, col, scol, "", " ", ","); col = write_expression (file, expr -> data.suffix.len, col, scol, 0); col = token_print_indent (file, col, indent, "", "", ")"); case expr_lcase: col = token_print_indent(file, col, indent, "", "", "lcase"); col = token_print_indent(file, col, indent, " ", "", "("); scol = col; col = write_expression(file, expr->data.lcase, col, scol, 1); col = token_print_indent(file, col, indent, "", "", ")"); break; case expr_ucase: col = token_print_indent(file, col, indent, "", "", "ucase"); col = token_print_indent(file, col, indent, " ", "", "("); scol = col; col = write_expression(file, expr->data.ucase, col, scol, 1); col = token_print_indent(file, col, indent, "", "", ")"); break; case expr_concat: e = expr; col = token_print_indent (file, col, indent, "", "", "concat"); col = token_print_indent (file, col, indent, " ", "", "("); scol = col; firstp = 1; concat_again: col = write_expression (file, e -> data.concat [0], col, scol, firstp); firstp = 0; if (!e -> data.concat [1]) goto no_concat_cdr; col = token_print_indent (file, col, scol, "", " ", ","); if (e -> data.concat [1] -> op == expr_concat) { e = e -> data.concat [1]; goto concat_again; } col = write_expression (file, e -> data.concat [1], col, scol, 0); no_concat_cdr: col = token_print_indent (file, col, indent, "", "", ")"); break; case expr_host_lookup: col = token_print_indent (file, col, indent, "", "", "gethostbyname"); col = token_print_indent (file, col, indent, " ", "", "("); col = token_print_indent_concat (file, col, indent, "", "", "\"", expr -> data.host_lookup -> hostname, "\"", (char *)0); col = token_print_indent (file, col, indent, "", "", ")"); break; case expr_add: s = "+"; goto binary; case expr_subtract: s = "-"; goto binary; case expr_multiply: s = "*"; goto binary; case expr_divide: s = "/"; goto binary; case expr_remainder: s = "%"; goto binary; case expr_binary_and: s = "&"; goto binary; case expr_binary_or: s = "|"; goto binary; case expr_binary_xor: s = "^"; goto binary; case expr_and: s = "and"; goto binary; case expr_or: s = "or"; goto binary; case expr_not: col = token_print_indent (file, col, indent, "", " ", "not"); col = write_expression (file, expr -> data.not, col, indent + 2, 1); break; case expr_option: s = "option"; print_option_name: col = token_print_indent (file, col, indent, "", "", s); if (expr -> data.option -> universe != &dhcp_universe) { col = token_print_indent (file, col, indent, " ", "", (expr -> data.option -> universe -> name)); col = token_print_indent (file, col, indent, "", "", "."); col = token_print_indent (file, col, indent, "", "", expr -> data.option -> name); } else { col = token_print_indent (file, col, indent, " ", "", expr -> data.option -> name); } break; case expr_hardware: col = token_print_indent (file, col, indent, "", "", "hardware"); break; case expr_packet: col = token_print_indent (file, col, indent, "", "", "packet"); col = token_print_indent (file, col, indent, " ", "", "("); scol = col; col = write_expression (file, expr -> data.packet.offset, col, indent, 1); col = token_print_indent (file, col, scol, "", " ", ","); col = write_expression (file, expr -> data.packet.len, col, scol, 0); col = token_print_indent (file, col, indent, "", "", ")"); break; case expr_const_data: col = token_indent_data_string (file, col, indent, "", "", &expr -> data.const_data); break; case expr_extract_int8: width = 8; extract_int: col = token_print_indent (file, col, indent, "", "", "extract-int"); col = token_print_indent (file, col, indent, " ", "", "("); scol = col; col = write_expression (file, expr -> data.extract_int, col, indent, 1); col = token_print_indent (file, col, scol, "", " ", ","); sprintf (obuf, "%d", width); col = token_print_indent (file, col, scol, " ", "", obuf); col = token_print_indent (file, col, indent, "", "", ")"); break; case expr_extract_int16: width = 16; goto extract_int; case expr_extract_int32: width = 32; goto extract_int; case expr_encode_int8: width = 8; encode_int: col = token_print_indent (file, col, indent, "", "", "encode-int"); col = token_print_indent (file, col, indent, " ", "", "("); scol = col; col = write_expression (file, expr -> data.extract_int, col, indent, 1); col = token_print_indent (file, col, scol, "", " ", ","); sprintf (obuf, "%d", width); col = token_print_indent (file, col, scol, " ", "", obuf); col = token_print_indent (file, col, indent, "", "", ")"); break; case expr_encode_int16: width = 16; goto encode_int; case expr_encode_int32: width = 32; goto encode_int; case expr_const_int: sprintf (obuf, "%lu", expr -> data.const_int); col = token_print_indent (file, col, indent, "", "", obuf); break; case expr_exists: s = "exists"; goto print_option_name; case expr_encapsulate: col = token_print_indent (file, col, indent, "", "", "encapsulate"); col = token_indent_data_string (file, col, indent, " ", "", &expr -> data.encapsulate); break; case expr_known: col = token_print_indent (file, col, indent, "", "", "known"); break; case expr_reverse: col = token_print_indent (file, col, indent, "", "", "reverse"); col = token_print_indent (file, col, indent, " ", "", "("); scol = col; col = write_expression (file, expr -> data.reverse.width, col, scol, 1); col = token_print_indent (file, col, scol, "", " ", ","); col = write_expression (file, expr -> data.reverse.buffer, col, scol, 0); col = token_print_indent (file, col, indent, "", "", ")"); break; case expr_leased_address: col = token_print_indent (file, col, indent, "", "", "leased-address"); break; case expr_client_state: col = token_print_indent (file, col, indent, "", "", "client-state"); break; case expr_binary_to_ascii: col = token_print_indent (file, col, indent, "", "", "binary-to-ascii"); col = token_print_indent (file, col, indent, " ", "", "("); scol = col; col = write_expression (file, expr -> data.b2a.base, col, scol, 1); col = token_print_indent (file, col, scol, "", " ", ","); col = write_expression (file, expr -> data.b2a.width, col, scol, 0); col = token_print_indent (file, col, scol, "", " ", ","); col = write_expression (file, expr -> data.b2a.separator, col, scol, 0); col = token_print_indent (file, col, scol, "", " ", ","); col = write_expression (file, expr -> data.b2a.buffer, col, scol, 0); col = token_print_indent (file, col, indent, "", "", ")"); break; case expr_config_option: s = "config-option"; goto print_option_name; case expr_host_decl_name: col = token_print_indent (file, col, indent, "", "", "host-decl-name"); break; case expr_pick_first_value: e = expr; col = token_print_indent (file, col, indent, "", "", "concat"); col = token_print_indent (file, col, indent, " ", "", "("); scol = col; firstp = 1; pick_again: col = write_expression (file, e -> data.pick_first_value.car, col, scol, firstp); firstp = 0; /* We're being very lisp-like right now - instead of representing this expression as (first middle . last) we're representing it as (first middle last), which means that the tail cdr is always nil. Apologies to non-wisp-lizards - may this obscure way of describing the problem motivate you to learn more about the one true computing language. */ if (!e -> data.pick_first_value.cdr) goto no_pick_cdr; col = token_print_indent (file, col, scol, "", " ", ","); if (e -> data.pick_first_value.cdr -> op == expr_pick_first_value) { e = e -> data.pick_first_value.cdr; goto pick_again; } col = write_expression (file, e -> data.pick_first_value.cdr, col, scol, 0); no_pick_cdr: col = token_print_indent (file, col, indent, "", "", ")"); break; case expr_lease_time: col = token_print_indent (file, col, indent, "", "", "lease-time"); break; case expr_dns_transaction: col = token_print_indent (file, col, indent, "", "", "ns-update"); col = token_print_indent (file, col, indent, " ", "", "("); scol = 0; for (e = expr; e && e -> op == expr_dns_transaction; e = e -> data.dns_transaction.cdr) { if (!scol) { scol = col; firstp = 1; } else firstp = 0; col = write_expression (file, e -> data.dns_transaction.car, col, scol, firstp); if (e -> data.dns_transaction.cdr) col = token_print_indent (file, col, scol, "", " ", ","); } if (e) col = write_expression (file, e, col, scol, 0); col = token_print_indent (file, col, indent, "", "", ")"); break; case expr_ns_add: col = token_print_indent (file, col, indent, "", "", "update"); col = token_print_indent (file, col, indent, " ", "", "("); scol = col; sprintf (obuf, "%d", expr -> data.ns_add.rrclass); col = token_print_indent (file, col, scol, "", "", obuf); col = token_print_indent (file, col, scol, "", " ", ","); sprintf (obuf, "%d", expr -> data.ns_add.rrtype); col = token_print_indent (file, col, scol, "", "", obuf); col = token_print_indent (file, col, scol, "", " ", ","); col = write_expression (file, expr -> data.ns_add.rrname, col, scol, 0); col = token_print_indent (file, col, scol, "", " ", ","); col = write_expression (file, expr -> data.ns_add.rrdata, col, scol, 0); col = token_print_indent (file, col, scol, "", " ", ","); col = write_expression (file, expr -> data.ns_add.ttl, col, scol, 0); col = token_print_indent (file, col, indent, "", "", ")"); break; case expr_ns_delete: col = token_print_indent (file, col, indent, "", "", "delete"); col = token_print_indent (file, col, indent, " ", "", "("); finish_ns_small: scol = col; sprintf (obuf, "%d", expr -> data.ns_add.rrclass); col = token_print_indent (file, col, scol, "", "", obuf); col = token_print_indent (file, col, scol, "", " ", ","); sprintf (obuf, "%d", expr -> data.ns_add.rrtype); col = token_print_indent (file, col, scol, "", "", obuf); col = token_print_indent (file, col, scol, "", " ", ","); col = write_expression (file, expr -> data.ns_add.rrname, col, scol, 0); col = token_print_indent (file, col, scol, "", " ", ","); col = write_expression (file, expr -> data.ns_add.rrdata, col, scol, 0); col = token_print_indent (file, col, indent, "", "", ")"); break; case expr_ns_exists: col = token_print_indent (file, col, indent, "", "", "exists"); col = token_print_indent (file, col, indent, " ", "", "("); goto finish_ns_small; case expr_ns_not_exists: col = token_print_indent (file, col, indent, "", "", "not exists"); col = token_print_indent (file, col, indent, " ", "", "("); goto finish_ns_small; case expr_static: col = token_print_indent (file, col, indent, "", "", "static"); break; case expr_null: col = token_print_indent (file, col, indent, "", "", "null"); break; case expr_variable_reference: col = token_print_indent (file, indent, indent, "", "", expr -> data.variable); break; case expr_variable_exists: col = token_print_indent (file, indent, indent, "", "", "defined"); col = token_print_indent (file, col, indent, " ", "", "("); col = token_print_indent (file, col, indent, "", "", expr -> data.variable); col = token_print_indent (file, col, indent, "", "", ")"); break; case expr_gethostname: col = token_print_indent(file, col, indent, "", "", "gethostname()"); break; case expr_funcall: col = token_print_indent(file, indent, indent, "", "", expr->data.funcall.name); col = token_print_indent(file, col, indent, " ", "", "("); firstp = 1; e = expr->data.funcall.arglist; while (e != NULL) { if (!firstp) col = token_print_indent(file, col, indent, "", " ", ","); col = write_expression(file, e->data.arg.val, col, indent, firstp); firstp = 0; e = e->data.arg.next; } col = token_print_indent(file, col, indent, "", "", ")"); break; default: log_fatal ("invalid expression type in print_expression: %d", expr -> op); } return col; } struct binding *find_binding (struct binding_scope *scope, const char *name) { struct binding *bp; struct binding_scope *s; for (s = scope; s; s = s -> outer) { for (bp = s -> bindings; bp; bp = bp -> next) { if (!strcasecmp (name, bp -> name)) { return bp; } } } return (struct binding *)0; } int free_bindings (struct binding_scope *scope, const char *file, int line) { struct binding *bp, *next; for (bp = scope -> bindings; bp; bp = next) { next = bp -> next; if (bp -> name) dfree (bp -> name, file, line); if (bp -> value) binding_value_dereference (&bp -> value, file, line); dfree (bp, file, line); } scope -> bindings = (struct binding *)0; return 1; } int binding_scope_dereference (ptr, file, line) struct binding_scope **ptr; const char *file; int line; { struct binding_scope *binding_scope; if (!ptr || !*ptr) { log_error ("%s(%d): null pointer", file, line); #if defined (POINTER_DEBUG) abort (); #else return 0; #endif } binding_scope = *ptr; *ptr = (struct binding_scope *)0; --binding_scope -> refcnt; rc_register (file, line, ptr, binding_scope, binding_scope -> refcnt, 1, RC_MISC); if (binding_scope -> refcnt > 0) return 1; if (binding_scope -> refcnt < 0) { log_error ("%s(%d): negative refcnt!", file, line); #if defined (DEBUG_RC_HISTORY) dump_rc_history (binding_scope); #endif #if defined (POINTER_DEBUG) abort (); #else return 0; #endif } free_bindings (binding_scope, file, line); if (binding_scope -> outer) binding_scope_dereference (&binding_scope -> outer, MDL); dfree (binding_scope, file, line); return 1; } int fundef_dereference (ptr, file, line) struct fundef **ptr; const char *file; int line; { struct fundef *bp = *ptr; struct string_list *sp, *next; if (!ptr) { log_error ("%s(%d): null pointer", file, line); #if defined (POINTER_DEBUG) abort (); #else return 0; #endif } if (!bp) { log_error ("%s(%d): null pointer", file, line); #if defined (POINTER_DEBUG) abort (); #else return 0; #endif } bp -> refcnt--; rc_register (file, line, ptr, bp, bp -> refcnt, 1, RC_MISC); if (bp -> refcnt < 0) { log_error ("%s(%d): negative refcnt!", file, line); #if defined (DEBUG_RC_HISTORY) dump_rc_history (bp); #endif #if defined (POINTER_DEBUG) abort (); #else return 0; #endif } if (!bp -> refcnt) { for (sp = bp -> args; sp; sp = next) { next = sp -> next; dfree (sp, file, line); } if (bp -> statements) executable_statement_dereference (&bp -> statements, file, line); dfree (bp, file, line); } *ptr = (struct fundef *)0; return 1; } #if defined (NOTYET) /* Post 3.0 final. */ int data_subexpression_length (int *rv, struct expression *expr) { int crhs, clhs, llhs, lrhs; switch (expr -> op) { case expr_substring: if (expr -> data.substring.len && expr -> data.substring.len -> op == expr_const_int) { (*rv = (int)expr -> data.substring.len -> data.const_int); return 1; } return 0; case expr_packet: case expr_suffix: if (expr -> data.suffix.len && expr -> data.suffix.len -> op == expr_const_int) { (*rv = (int)expr -> data.suffix.len -> data.const_int); return 1; } return 0; case expr_lcase: return data_subexpression_length(rv, expr->data.lcase); case expr_ucase: return data_subexpression_length(rv, expr->data.ucase); case expr_concat: clhs = data_subexpression_length (&llhs, expr -> data.concat [0]); crhs = data_subexpression_length (&lrhs, expr -> data.concat [1]); if (crhs == 0 || clhs == 0) return 0; *rv = llhs + lrhs; return 1; break; case expr_hardware: return 0; case expr_const_data: *rv = expr -> data.const_data.len; return 2; case expr_reverse: return data_subexpression_length (rv, expr -> data.reverse.buffer); case expr_leased_address: case expr_lease_time: *rv = 4; return 2; case expr_pick_first_value: clhs = data_subexpression_length (&llhs, expr -> data.concat [0]); crhs = data_subexpression_length (&lrhs, expr -> data.concat [1]); if (crhs == 0 || clhs == 0) return 0; if (llhs > lrhs) *rv = llhs; else *rv = lrhs; return 1; case expr_binary_to_ascii: case expr_config_option: case expr_host_decl_name: case expr_encapsulate: case expr_filename: case expr_sname: case expr_host_lookup: case expr_option: case expr_none: case expr_match: case expr_check: case expr_equal: case expr_regex_match: case expr_iregex_match: case expr_and: case expr_or: case expr_not: case expr_extract_int8: case expr_extract_int16: case expr_extract_int32: case expr_encode_int8: case expr_encode_int16: case expr_encode_int32: case expr_const_int: case expr_exists: case expr_known: case expr_dns_transaction: case expr_static: case expr_ns_add: case expr_ns_delete: case expr_ns_exists: case expr_ns_not_exists: case expr_not_equal: case expr_null: case expr_variable_exists: case expr_variable_reference: case expr_arg: case expr_funcall: case expr_function: case expr_add: case expr_subtract: case expr_multiply: case expr_divide: case expr_remainder: case expr_binary_and: case expr_binary_or: case expr_binary_xor: case expr_client_state: case expr_gethostname: return 0; } return 0; } int expr_valid_for_context (struct expression *expr, enum expression_context context) { /* We don't know at parse time what type of value a function may return, so we can't flag an error on it. */ if (expr -> op == expr_funcall || expr -> op == expr_variable_reference) return 1; switch (context) { case context_any: return 1; case context_boolean: if (is_boolean_expression (expr)) return 1; return 0; case context_data: if (is_data_expression (expr)) return 1; return 0; case context_numeric: if (is_numeric_expression (expr)) return 1; return 0; case context_dns: if (is_dns_expression (expr)) { return 1; } return 0; case context_data_or_numeric: if (is_numeric_expression (expr) || is_data_expression (expr)) { return 1; } return 0; case context_function: if (expr -> op == expr_function) return 1; return 0; } return 0; } #endif /* NOTYET */ struct binding *create_binding (struct binding_scope **scope, const char *name) { struct binding *binding; if (!*scope) { if (!binding_scope_allocate (scope, MDL)) return (struct binding *)0; } binding = find_binding (*scope, name); if (!binding) { binding = dmalloc (sizeof *binding, MDL); if (!binding) return (struct binding *)0; memset (binding, 0, sizeof *binding); binding -> name = dmalloc (strlen (name) + 1, MDL); if (!binding -> name) { dfree (binding, MDL); return (struct binding *)0; } strcpy (binding -> name, name); binding -> next = (*scope) -> bindings; (*scope) -> bindings = binding; } return binding; } int bind_ds_value (struct binding_scope **scope, const char *name, struct data_string *value) { struct binding *binding; binding = create_binding (scope, name); if (!binding) return 0; if (binding -> value) binding_value_dereference (&binding -> value, MDL); if (!binding_value_allocate (&binding -> value, MDL)) return 0; data_string_copy (&binding -> value -> value.data, value, MDL); binding -> value -> type = binding_data; return 1; } int find_bound_string (struct data_string *value, struct binding_scope *scope, const char *name) { struct binding *binding; binding = find_binding (scope, name); if (!binding || !binding -> value || binding -> value -> type != binding_data) return 0; if (binding -> value -> value.data.terminated) { data_string_copy (value, &binding -> value -> value.data, MDL); } else { buffer_allocate (&value -> buffer, binding -> value -> value.data.len, MDL); if (!value -> buffer) return 0; memcpy (value -> buffer -> data, binding -> value -> value.data.data, binding -> value -> value.data.len); value -> data = value -> buffer -> data; value -> len = binding -> value -> value.data.len; } return 1; } int unset (struct binding_scope *scope, const char *name) { struct binding *binding; binding = find_binding (scope, name); if (binding) { if (binding -> value) binding_value_dereference (&binding -> value, MDL); return 1; } return 0; } /* vim: set tabstop=8: */ dhcp-4.2.4/common/upf.c000644 000765 000024 00000024715 11301372615 014625 0ustar00sarstaff000000 000000 /* upf.c Ultrix PacketFilter interface code. */ /* * Copyright (c) 2004,2007,2009 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1996-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ * * This software has been written for Internet Systems Consortium * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. * To learn more about Internet Systems Consortium, see * ``https://www.isc.org/''. To learn more about Vixie Enterprises, * see ``http://www.vix.com''. To learn more about Nominum, Inc., see * ``http://www.nominum.com''. */ #include "dhcpd.h" #if defined (USE_UPF_SEND) || defined (USE_UPF_RECEIVE) #include #include #include #include #include "includes/netinet/ip.h" #include "includes/netinet/udp.h" #include "includes/netinet/if_ether.h" /* Reinitializes the specified interface after an address change. This is not required for packet-filter APIs. */ #ifdef USE_UPF_SEND void if_reinitialize_send (info) struct interface_info *info; { } #endif #ifdef USE_UPF_RECEIVE void if_reinitialize_receive (info) struct interface_info *info; { } #endif /* Called by get_interface_list for each interface that's discovered. Opens a packet filter for each interface and adds it to the select mask. */ int if_register_upf (info) struct interface_info *info; { int sock; char filename[50]; int b; struct endevp param; /* Open a UPF device */ for (b = 0; 1; b++) { /* %Audit% Cannot exceed 36 bytes. %2004.06.17,Safe% */ sprintf(filename, "/dev/pf/pfilt%d", b); sock = open (filename, O_RDWR, 0); if (sock < 0) { if (errno == EBUSY) { continue; } else { log_fatal ("Can't find free upf: %m"); } } else { break; } } /* Set the UPF device to point at this interface. */ if (ioctl (sock, EIOCSETIF, info -> ifp) < 0) log_fatal ("Can't attach interface %s to upf device %s: %m", info -> name, filename); /* Get the hardware address. */ if (ioctl (sock, EIOCDEVP, ¶m) < 0) log_fatal ("Can't get interface %s hardware address: %m", info -> name); /* We only know how to do ethernet. */ if (param.end_dev_type != ENDT_10MB) log_fatal ("Invalid device type on network interface %s: %d", info -> name, param.end_dev_type); if (param.end_addr_len != 6) log_fatal ("Invalid hardware address length on %s: %d", info -> name, param.end_addr_len); info -> hw_address.hlen = 7; info -> hw_address.hbuf [0] = ARPHRD_ETHER; memcpy (&info -> hw_address.hbuf [1], param.end_addr, 6); return sock; } #endif /* USE_UPF_SEND || USE_UPF_RECEIVE */ #ifdef USE_UPF_SEND void if_register_send (info) struct interface_info *info; { /* If we're using the upf API for sending and receiving, we don't need to register this interface twice. */ #ifndef USE_UPF_RECEIVE info -> wfdesc = if_register_upf (info, interface); #else info -> wfdesc = info -> rfdesc; #endif if (!quiet_interface_discovery) log_info ("Sending on UPF/%s/%s%s%s", info -> name, print_hw_addr (info -> hw_address.hbuf [0], info -> hw_address.hlen - 1, &info -> hw_address.hbuf [1]), (info -> shared_network ? "/" : ""), (info -> shared_network ? info -> shared_network -> name : "")); } void if_deregister_send (info) struct interface_info *info; { #ifndef USE_UPF_RECEIVE close (info -> wfdesc); #endif info -> wfdesc = -1; if (!quiet_interface_discovery) log_info ("Disabling output on UPF/%s/%s%s%s", info -> name, print_hw_addr (info -> hw_address.hbuf [0], info -> hw_address.hlen - 1, &info -> hw_address.hbuf [1]), (info -> shared_network ? "/" : ""), (info -> shared_network ? info -> shared_network -> name : "")); } #endif /* USE_UPF_SEND */ #ifdef USE_UPF_RECEIVE /* Packet filter program... XXX Changes to the filter program may require changes to the constant offsets used in if_register_send to patch the UPF program! XXX */ void if_register_receive (info) struct interface_info *info; { int flag = 1; u_int32_t addr; struct enfilter pf; u_int32_t bits; /* Open a UPF device and hang it on this interface... */ info -> rfdesc = if_register_upf (info); /* Allow the copyall flag to be set... */ if (ioctl(info -> rfdesc, EIOCALLOWCOPYALL, &flag) < 0) log_fatal ("Can't set ALLOWCOPYALL: %m"); /* Clear all the packet filter mode bits first... */ flag = (ENHOLDSIG | ENBATCH | ENTSTAMP | ENPROMISC | ENNONEXCL | ENCOPYALL); if (ioctl (info -> rfdesc, EIOCMBIC, &flag) < 0) log_fatal ("Can't clear pfilt bits: %m"); /* Set the ENBATCH and ENCOPYALL bits... */ bits = ENBATCH | ENCOPYALL; if (ioctl (info -> rfdesc, EIOCMBIS, &bits) < 0) log_fatal ("Can't set ENBATCH|ENCOPYALL: %m"); /* Set up the UPF filter program. */ /* XXX Unlike the BPF filter program, this one won't work if the XXX IP packet is fragmented or if there are options on the IP XXX header. */ pf.enf_Priority = 0; pf.enf_FilterLen = 0; pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHWORD + 6; pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHLIT + ENF_CAND; pf.enf_Filter [pf.enf_FilterLen++] = htons (ETHERTYPE_IP); pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHLIT; pf.enf_Filter [pf.enf_FilterLen++] = htons (IPPROTO_UDP); pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHWORD + 11; pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHLIT + ENF_AND; pf.enf_Filter [pf.enf_FilterLen++] = htons (0xFF); pf.enf_Filter [pf.enf_FilterLen++] = ENF_CAND; pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHWORD + 18; pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHLIT + ENF_CAND; pf.enf_Filter [pf.enf_FilterLen++] = local_port; if (ioctl (info -> rfdesc, EIOCSETF, &pf) < 0) log_fatal ("Can't install packet filter program: %m"); if (!quiet_interface_discovery) log_info ("Listening on UPF/%s/%s%s%s", info -> name, print_hw_addr (info -> hw_address.hbuf [0], info -> hw_address.hlen - 1, &info -> hw_address.hbuf [1]), (info -> shared_network ? "/" : ""), (info -> shared_network ? info -> shared_network -> name : "")); } void if_deregister_receive (info) struct interface_info *info; { close (info -> rfdesc); info -> rfdesc = -1; if (!quiet_interface_discovery) log_info ("Disabling input on UPF/%s/%s%s%s", info -> name, print_hw_addr (info -> hw_address.hbuf [0], info -> hw_address.hlen - 1, &info -> hw_address.hbuf [1]), (info -> shared_network ? "/" : ""), (info -> shared_network ? info -> shared_network -> name : "")); } #endif /* USE_UPF_RECEIVE */ #ifdef USE_UPF_SEND ssize_t send_packet (interface, packet, raw, len, from, to, hto) struct interface_info *interface; struct packet *packet; struct dhcp_packet *raw; size_t len; struct in_addr from; struct sockaddr_in *to; struct hardware *hto; { unsigned hbufp = 0, ibufp = 0; double hw [4]; double ip [32]; struct iovec iov [3]; int result; int fudge; if (!strcmp (interface -> name, "fallback")) return send_fallback (interface, packet, raw, len, from, to, hto); if (hto == NULL && interface->anycast_mac_addr.hlen) hto = &interface->anycast_mac_addr; /* Assemble the headers... */ assemble_hw_header (interface, (unsigned char *)hw, &hbufp, hto); assemble_udp_ip_header (interface, (unsigned char *)ip, &ibufp, from.s_addr, to -> sin_addr.s_addr, to -> sin_port, (unsigned char *)raw, len); /* Fire it off */ iov [0].iov_base = ((char *)hw); iov [0].iov_len = hbufp; iov [1].iov_base = ((char *)ip); iov [1].iov_len = ibufp; iov [2].iov_base = (char *)raw; iov [2].iov_len = len; result = writev(interface -> wfdesc, iov, 3); if (result < 0) log_error ("send_packet: %m"); return result; } #endif /* USE_UPF_SEND */ #ifdef USE_UPF_RECEIVE ssize_t receive_packet (interface, buf, len, from, hfrom) struct interface_info *interface; unsigned char *buf; size_t len; struct sockaddr_in *from; struct hardware *hfrom; { int nread; int length = 0; int offset = 0; unsigned char ibuf [1500 + sizeof (struct enstamp)]; int bufix = 0; unsigned paylen; length = read (interface -> rfdesc, ibuf, sizeof ibuf); if (length <= 0) return length; bufix = sizeof (struct enstamp); /* Decode the physical header... */ offset = decode_hw_header (interface, ibuf, bufix, hfrom); /* If a physical layer checksum failed (dunno of any physical layer that supports this, but WTH), skip this packet. */ if (offset < 0) { return 0; } bufix += offset; length -= offset; /* Decode the IP and UDP headers... */ offset = decode_udp_ip_header (interface, ibuf, bufix, from, length, &paylen); /* If the IP or UDP checksum was bad, skip the packet... */ if (offset < 0) return 0; bufix += offset; length -= offset; if (length < paylen) log_fatal("Internal inconsistency at %s:%d.", MDL); /* Copy out the data in the packet... */ memcpy (buf, &ibuf[bufix], paylen); return paylen; } int can_unicast_without_arp (ip) struct interface_info *ip; { return 1; } int can_receive_unicast_unconfigured (ip) struct interface_info *ip; { return 1; } int supports_multiple_interfaces (ip) struct interface_info *ip; { return 1; } void maybe_setup_fallback () { isc_result_t status; struct interface_info *fbi = (struct interface_info *)0; if (setup_fallback (&fbi, MDL)) { if_register_fallback (fbi); status = omapi_register_io_object ((omapi_object_t *)fbi, if_readsocket, 0, fallback_discard, 0, 0); if (status != ISC_R_SUCCESS) log_fatal ("Can't register I/O handle for %s: %s", fbi -> name, isc_result_totext (status)); interface_dereference (&fbi, MDL); } } #endif dhcp-4.2.4/common/tests/Makefile.am000644 000765 000024 00000000367 11271742256 017072 0ustar00sarstaff000000 000000 AM_CPPFLAGS = -I../.. check_PROGRAMS = test_alloc TESTS = test_alloc test_alloc_SOURCES = test_alloc.c test_alloc_LDADD = ../libdhcp.a ../../tests/libt_api.a \ ../../omapip/libomapi.a ../../bind/lib/libdns.a \ ../../bind/lib/libisc.a dhcp-4.2.4/common/tests/Makefile.in000644 000765 000024 00000034025 11757500141 017073 0ustar00sarstaff000000 000000 # Makefile.in generated by automake 1.10.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : check_PROGRAMS = test_alloc$(EXEEXT) TESTS = test_alloc$(EXEEXT) subdir = common/tests DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/includes/config.h CONFIG_CLEAN_FILES = am_test_alloc_OBJECTS = test_alloc.$(OBJEXT) test_alloc_OBJECTS = $(am_test_alloc_OBJECTS) test_alloc_DEPENDENCIES = ../libdhcp.a ../../tests/libt_api.a \ ../../omapip/libomapi.a ../../bind/lib/libdns.a \ ../../bind/lib/libisc.a DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/includes depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) CCLD = $(CC) LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ SOURCES = $(test_alloc_SOURCES) DIST_SOURCES = $(test_alloc_SOURCES) ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ GREP = @GREP@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDAP_CFLAGS = @LDAP_CFLAGS@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_prefix_program = @ac_prefix_program@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build_alias = @build_alias@ builddir = @builddir@ byte_order = @byte_order@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host_alias = @host_alias@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AM_CPPFLAGS = -I../.. test_alloc_SOURCES = test_alloc.c test_alloc_LDADD = ../libdhcp.a ../../tests/libt_api.a \ ../../omapip/libomapi.a ../../bind/lib/libdns.a \ ../../bind/lib/libisc.a all: all-am .SUFFIXES: .SUFFIXES: .c .o .obj $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ && exit 0; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign common/tests/Makefile'; \ cd $(top_srcdir) && \ $(AUTOMAKE) --foreign common/tests/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh clean-checkPROGRAMS: -test -z "$(check_PROGRAMS)" || rm -f $(check_PROGRAMS) test_alloc$(EXEEXT): $(test_alloc_OBJECTS) $(test_alloc_DEPENDENCIES) @rm -f test_alloc$(EXEEXT) $(LINK) $(test_alloc_OBJECTS) $(test_alloc_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_alloc.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) tags=; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$tags $$unique; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) tags=; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$tags$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$tags $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && cd $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) $$here distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags check-TESTS: $(TESTS) @failed=0; all=0; xfail=0; xpass=0; skip=0; ws='[ ]'; \ srcdir=$(srcdir); export srcdir; \ list=' $(TESTS) '; \ if test -n "$$list"; then \ for tst in $$list; do \ if test -f ./$$tst; then dir=./; \ elif test -f $$tst; then dir=; \ else dir="$(srcdir)/"; fi; \ if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *$$ws$$tst$$ws*) \ xpass=`expr $$xpass + 1`; \ failed=`expr $$failed + 1`; \ echo "XPASS: $$tst"; \ ;; \ *) \ echo "PASS: $$tst"; \ ;; \ esac; \ elif test $$? -ne 77; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *$$ws$$tst$$ws*) \ xfail=`expr $$xfail + 1`; \ echo "XFAIL: $$tst"; \ ;; \ *) \ failed=`expr $$failed + 1`; \ echo "FAIL: $$tst"; \ ;; \ esac; \ else \ skip=`expr $$skip + 1`; \ echo "SKIP: $$tst"; \ fi; \ done; \ if test "$$failed" -eq 0; then \ if test "$$xfail" -eq 0; then \ banner="All $$all tests passed"; \ else \ banner="All $$all tests behaved as expected ($$xfail expected failures)"; \ fi; \ else \ if test "$$xpass" -eq 0; then \ banner="$$failed of $$all tests failed"; \ else \ banner="$$failed of $$all tests did not behave as expected ($$xpass unexpected passes)"; \ fi; \ fi; \ dashes="$$banner"; \ skipped=""; \ if test "$$skip" -ne 0; then \ skipped="($$skip tests were not run)"; \ test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$skipped"; \ fi; \ report=""; \ if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ report="Please report to $(PACKAGE_BUGREPORT)"; \ test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$report"; \ fi; \ dashes=`echo "$$dashes" | sed s/./=/g`; \ echo "$$dashes"; \ echo "$$banner"; \ test -z "$$skipped" || echo "$$skipped"; \ test -z "$$report" || echo "$$report"; \ echo "$$dashes"; \ test "$$failed" -eq 0; \ else :; fi distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ fi; \ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ else \ test -f $(distdir)/$$file \ || cp -p $$d/$$file $(distdir)/$$file \ || exit 1; \ fi; \ done check-am: all-am $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) $(MAKE) $(AM_MAKEFLAGS) check-TESTS check: check-am all-am: Makefile installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-checkPROGRAMS clean-generic mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-exec-am: install-html: install-html-am install-info: install-info-am install-man: install-pdf: install-pdf-am install-ps: install-ps-am installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: install-am install-strip .PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \ clean-checkPROGRAMS clean-generic ctags distclean \ distclean-compile distclean-generic distclean-tags distdir dvi \ dvi-am html html-am info info-am install install-am \ install-data install-data-am install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-info install-info-am install-man install-pdf \ install-pdf-am install-ps install-ps-am install-strip \ installcheck installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ uninstall-am # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: dhcp-4.2.4/common/tests/test_alloc.c000644 000765 000024 00000024241 11135740516 017324 0ustar00sarstaff000000 000000 /* * We test the functions provided in alloc.c here. These are very * basic functions, and it is very important that they work correctly. * * You can see two different styles of testing: * * - In the first, we have a single test for each function that tests * all of the possible ways it can operate. (This is the case for * the buffer tests.) * * - In the second, we have a separate test for each of the ways a * function can operate. (This is the case for the data_string * tests.) * * The advantage of a single test per function is that you have fewer * tests, and less duplicated and extra code. The advantage of having * a separate test is that each test is simpler. Plus if you need to * allow certain tests to fail for some reason (known bugs that are * hard to fix for example), then */ /* TODO: dmalloc() test */ #include "config.h" #include "t_api.h" #include "dhcpd.h" static void test_buffer_allocate(void); static void test_buffer_reference(void); static void test_buffer_dereference(void); static void test_data_string_forget(void); static void test_data_string_forget_nobuf(void); static void test_data_string_copy(void); static void test_data_string_copy_nobuf(void); /* * T_testlist is a list of tests that are invoked. */ testspec_t T_testlist[] = { { test_buffer_allocate, "buffer_allocate()" }, { test_buffer_reference, "buffer_reference()" }, { test_buffer_dereference, "buffer_dereference()" }, { test_data_string_forget, "data_string_forget()" }, { test_data_string_forget_nobuf, "data_string_forget(), no buffer" }, { test_data_string_copy, "data_string_copy()" }, { test_data_string_copy_nobuf, "data_string_copy(), no buffer" }, { NULL, NULL } }; static void test_buffer_allocate(void) { static const char *test_desc = "buffer_allocate basic test"; struct buffer *buf; t_assert("buffer_allocate", 1, T_REQUIRED, "%s", test_desc); /* * Check a 0-length buffer. */ buf = NULL; if (!buffer_allocate(&buf, 0, MDL)) { t_info("failed on 0-len buffer\n"); t_result(T_FAIL); return; } if (!buffer_dereference(&buf, MDL)) { t_info("buffer_dereference() failed\n"); t_result(T_FAIL); return; } if (buf != NULL) { t_info("buffer_dereference() did not NULL-out buffer\n"); t_result(T_FAIL); return; } /* * Check an actual buffer. */ buf = NULL; if (!buffer_allocate(&buf, 100, MDL)) { t_info("failed on allocate\n"); t_result(T_FAIL); return; } if (!buffer_dereference(&buf, MDL)) { t_info("buffer_dereference() failed\n"); t_result(T_FAIL); return; } if (buf != NULL) { t_info("buffer_dereference() did not NULL-out buffer\n"); t_result(T_FAIL); return; } /* * Okay, we're happy. */ t_result(T_PASS); } static void test_buffer_reference(void) { static const char *test_desc = "buffer_reference basic test"; int result = T_PASS; struct buffer *a, *b; t_assert("buffer_reference", 1, T_REQUIRED, "%s", test_desc); /* * Create a buffer. */ a = NULL; if (!buffer_allocate(&a, 100, MDL)) { t_info("failed on allocate\n"); t_result(T_FAIL); return; } /* * Confirm buffer_reference() doesn't work if we pass in NULL. * * TODO: we should confirm we get an error message here. */ if (buffer_reference(NULL, a, MDL)) { t_info("succeeded on an error input\n"); t_result(T_FAIL); return; } /* * TODO: we should confirm we get an error message if we pass * a non-NULL target. */ /* * Confirm we work under normal circumstances. */ b = NULL; if (!buffer_reference(&b, a, MDL)) { t_info("buffer_reference() failed\n"); t_result(T_FAIL); return; } if (b != a) { t_info("incorrect pointer\n"); result = T_FAIL; } if (b->refcnt != 2) { t_info("incorrect refcnt\n"); result = T_FAIL; } /* * Clean up. */ if (!buffer_dereference(&b, MDL)) { t_info("buffer_dereference() failed\n"); t_result(T_FAIL); return; } if (!buffer_dereference(&a, MDL)) { t_info("buffer_dereference() failed\n"); t_result(T_FAIL); return; } t_result(result); } static void test_buffer_dereference(void) { static const char *test_desc = "buffer_dereference basic test"; struct buffer *a, *b; t_assert("buffer_dereference", 1, T_REQUIRED, "%s", test_desc); /* * Confirm buffer_dereference() doesn't work if we pass in NULL. * * TODO: we should confirm we get an error message here. */ if (buffer_dereference(NULL, MDL)) { t_info("succeeded on an error input\n"); t_result(T_FAIL); return; } /* * Confirm buffer_dereference() doesn't work if we pass in * a pointer to NULL. * * TODO: we should confirm we get an error message here. */ a = NULL; if (buffer_dereference(&a, MDL)) { t_info("succeeded on an error input\n"); t_result(T_FAIL); return; } /* * Confirm we work under normal circumstances. */ a = NULL; if (!buffer_allocate(&a, 100, MDL)) { t_info("failed on allocate\n"); t_result(T_FAIL); return; } if (!buffer_dereference(&a, MDL)) { t_info("buffer_dereference() failed\n"); t_result(T_FAIL); return; } if (a != NULL) { t_info("non-null buffer after buffer_dereference()\n"); t_result(T_FAIL); return; } /* * Confirm we get an error from negative refcnt. * * TODO: we should confirm we get an error message here. */ a = NULL; if (!buffer_allocate(&a, 100, MDL)) { t_info("failed on allocate\n"); t_result(T_FAIL); return; } b = NULL; if (!buffer_reference(&b, a, MDL)) { t_info("buffer_reference() failed\n"); t_result(T_FAIL); return; } a->refcnt = 0; /* purposely set to invalid value */ if (buffer_dereference(&a, MDL)) { t_info("buffer_dereference() succeeded on error input\n"); t_result(T_FAIL); return; } a->refcnt = 2; if (!buffer_dereference(&b, MDL)) { t_info("buffer_dereference() failed\n"); t_result(T_FAIL); return; } if (!buffer_dereference(&a, MDL)) { t_info("buffer_dereference() failed\n"); t_result(T_FAIL); return; } t_result(T_PASS); } static void test_data_string_forget(void) { static const char *test_desc = "data_string_forget basic test"; int result = T_PASS; struct buffer *buf; struct data_string a; const char *str = "Lorem ipsum dolor sit amet turpis duis."; t_assert("data_string_forget", 1, T_REQUIRED, "%s", test_desc); /* * Create the string we want to forget. */ memset(&a, 0, sizeof(a)); a.len = strlen(str); buf = NULL; if (!buffer_allocate(&buf, a.len, MDL)) { t_info("out of memory\n"); t_result(T_FAIL); return; } if (!buffer_reference(&a.buffer, buf, MDL)) { t_info("buffer_reference() failed\n"); t_result(T_FAIL); return; } a.data = a.buffer->data; memcpy(a.buffer->data, str, a.len); /* * Forget and confirm we've forgotten. */ data_string_forget(&a, MDL); if (a.len != 0) { t_info("incorrect length\n"); result = T_FAIL; } if (a.data != NULL) { t_info("incorrect data\n"); result = T_FAIL; } if (a.terminated) { t_info("incorrect terminated\n"); result = T_FAIL; } if (a.buffer != NULL) { t_info("incorrect buffer\n"); result = T_FAIL; } if (buf->refcnt != 1) { t_info("too many references to buf\n"); result = T_FAIL; } /* * Clean up buffer. */ if (!buffer_dereference(&buf, MDL)) { t_info("buffer_reference() failed\n"); t_result(T_FAIL); return; } t_result(result); } static void test_data_string_forget_nobuf(void) { static const char *test_desc = "data_string_forget test, data_string without buffer"; int result = T_PASS; struct data_string a; const char *str = "Lorem ipsum dolor sit amet massa nunc."; t_assert("data_string_forget, no buffer", 1, T_REQUIRED, "%s", test_desc); /* * Create the string we want to forget. */ memset(&a, 0, sizeof(a)); a.len = strlen(str); a.data = (const unsigned char *)str; a.terminated = 1; /* * Forget and confirm we've forgotten. */ data_string_forget(&a, MDL); if (a.len != 0) { t_info("incorrect length\n"); result = T_FAIL; } if (a.data != NULL) { t_info("incorrect data\n"); result = T_FAIL; } if (a.terminated) { t_info("incorrect terminated\n"); result = T_FAIL; } if (a.buffer != NULL) { t_info("incorrect buffer\n"); result = T_FAIL; } t_result(result); } static void test_data_string_copy(void) { static const char *test_desc = "data_string_copy basic test"; int result = T_PASS; struct data_string a, b; const char *str = "Lorem ipsum dolor sit amet orci aliquam."; t_assert("data_string_copy", 1, T_REQUIRED, "%s", test_desc); /* * Create the string we want to copy. */ memset(&a, 0, sizeof(a)); a.len = strlen(str); if (!buffer_allocate(&a.buffer, a.len, MDL)) { t_info("out of memory\n"); t_result(T_FAIL); return; } a.data = a.buffer->data; memcpy(a.buffer->data, str, a.len); /* * Copy the string, and confirm it works. */ memset(&b, 0, sizeof(b)); data_string_copy(&b, &a, MDL); if (b.len != a.len) { t_info("incorrect length\n"); result = T_FAIL; } if (b.data != a.data) { t_info("incorrect data\n"); result = T_FAIL; } if (b.terminated != a.terminated) { t_info("incorrect terminated\n"); result = T_FAIL; } if (b.buffer != a.buffer) { t_info("incorrect buffer\n"); result = T_FAIL; } /* * Clean up. */ data_string_forget(&b, MDL); data_string_forget(&a, MDL); t_result(result); } static void test_data_string_copy_nobuf(void) { static const char *test_desc = "data_string_copy test, data_string without buffer"; int result = T_PASS; struct data_string a, b; const char *str = "Lorem ipsum dolor sit amet cras amet."; t_assert("data_string_copy, no buffer", 1, T_REQUIRED, "%s", test_desc); /* * Create the string we want to copy. */ memset(&a, 0, sizeof(a)); a.len = strlen(str); a.data = (const unsigned char *)str; a.terminated = 1; /* * Copy the string, and confirm it works. */ memset(&b, 0, sizeof(b)); data_string_copy(&b, &a, MDL); if (b.len != a.len) { t_info("incorrect length\n"); result = T_FAIL; } if (b.data != a.data) { t_info("incorrect data\n"); result = T_FAIL; } if (b.terminated != a.terminated) { t_info("incorrect terminated\n"); result = T_FAIL; } if (b.buffer != a.buffer) { t_info("incorrect buffer\n"); result = T_FAIL; } /* * Clean up. */ data_string_forget(&b, MDL); data_string_forget(&a, MDL); t_result(result); } dhcp-4.2.4/client/clparse.c000644 000765 000024 00000153505 11726364512 015462 0ustar00sarstaff000000 000000 /* clparse.c Parser for dhclient config and lease files... */ /* * Copyright (c) 2004-2012 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1996-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ * * This software has been written for Internet Systems Consortium * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. * To learn more about Internet Systems Consortium, see * ``https://www.isc.org/''. To learn more about Vixie Enterprises, * see ``http://www.vix.com''. To learn more about Nominum, Inc., see * ``http://www.nominum.com''. */ #include "dhcpd.h" #include struct client_config top_level_config; #define NUM_DEFAULT_REQUESTED_OPTS 9 struct option *default_requested_options[NUM_DEFAULT_REQUESTED_OPTS + 1]; static void parse_client_default_duid(struct parse *cfile); static void parse_client6_lease_statement(struct parse *cfile); #ifdef DHCPv6 static struct dhc6_ia *parse_client6_ia_na_statement(struct parse *cfile); static struct dhc6_ia *parse_client6_ia_ta_statement(struct parse *cfile); static struct dhc6_ia *parse_client6_ia_pd_statement(struct parse *cfile); static struct dhc6_addr *parse_client6_iaaddr_statement(struct parse *cfile); static struct dhc6_addr *parse_client6_iaprefix_statement(struct parse *cfile); #endif /* DHCPv6 */ /* client-conf-file :== client-declarations END_OF_FILE client-declarations :== | client-declaration | client-declarations client-declaration */ isc_result_t read_client_conf () { struct client_config *config; struct interface_info *ip; isc_result_t status; unsigned code; /* * TODO: LATER constant is very undescriptive. We should review it and * change it to something more descriptive or even better remove it * completely as it is currently not used. */ #ifdef LATER struct parse *parse = NULL; #endif /* Initialize the default request list. */ memset(default_requested_options, 0, sizeof(default_requested_options)); /* 1 */ code = DHO_SUBNET_MASK; option_code_hash_lookup(&default_requested_options[0], dhcp_universe.code_hash, &code, 0, MDL); /* 2 */ code = DHO_BROADCAST_ADDRESS; option_code_hash_lookup(&default_requested_options[1], dhcp_universe.code_hash, &code, 0, MDL); /* 3 */ code = DHO_TIME_OFFSET; option_code_hash_lookup(&default_requested_options[2], dhcp_universe.code_hash, &code, 0, MDL); /* 4 */ code = DHO_ROUTERS; option_code_hash_lookup(&default_requested_options[3], dhcp_universe.code_hash, &code, 0, MDL); /* 5 */ code = DHO_DOMAIN_NAME; option_code_hash_lookup(&default_requested_options[4], dhcp_universe.code_hash, &code, 0, MDL); /* 6 */ code = DHO_DOMAIN_NAME_SERVERS; option_code_hash_lookup(&default_requested_options[5], dhcp_universe.code_hash, &code, 0, MDL); /* 7 */ code = DHO_HOST_NAME; option_code_hash_lookup(&default_requested_options[6], dhcp_universe.code_hash, &code, 0, MDL); /* 8 */ code = D6O_NAME_SERVERS; option_code_hash_lookup(&default_requested_options[7], dhcpv6_universe.code_hash, &code, 0, MDL); /* 9 */ code = D6O_DOMAIN_SEARCH; option_code_hash_lookup(&default_requested_options[8], dhcpv6_universe.code_hash, &code, 0, MDL); for (code = 0 ; code < NUM_DEFAULT_REQUESTED_OPTS ; code++) { if (default_requested_options[code] == NULL) log_fatal("Unable to find option definition for " "index %u during default parameter request " "assembly.", code); } /* Initialize the top level client configuration. */ memset (&top_level_config, 0, sizeof top_level_config); /* Set some defaults... */ top_level_config.timeout = 60; top_level_config.select_interval = 0; top_level_config.reboot_timeout = 10; top_level_config.retry_interval = 300; top_level_config.backoff_cutoff = 15; top_level_config.initial_interval = 3; /* * RFC 2131, section 4.4.1 specifies that the client SHOULD wait a * random time between 1 and 10 seconds. However, we choose to not * implement this default. If user is inclined to really have that * delay, he is welcome to do so, using 'initial-delay X;' parameter * in config file. */ top_level_config.initial_delay = 0; top_level_config.bootp_policy = P_ACCEPT; top_level_config.script_name = path_dhclient_script; top_level_config.requested_options = default_requested_options; top_level_config.omapi_port = -1; top_level_config.do_forward_update = 1; /* Requested lease time, used by DHCPv6 (DHCPv4 uses the option cache) */ top_level_config.requested_lease = 7200; group_allocate (&top_level_config.on_receipt, MDL); if (!top_level_config.on_receipt) log_fatal ("no memory for top-level on_receipt group"); group_allocate (&top_level_config.on_transmission, MDL); if (!top_level_config.on_transmission) log_fatal ("no memory for top-level on_transmission group"); status = read_client_conf_file (path_dhclient_conf, (struct interface_info *)0, &top_level_config); if (status != ISC_R_SUCCESS) { ; #ifdef LATER /* Set up the standard name service updater routine. */ status = new_parse(&parse, -1, default_client_config, sizeof(default_client_config) - 1, "default client configuration", 0); if (status != ISC_R_SUCCESS) log_fatal ("can't begin default client config!"); } if (parse != NULL) { do { token = peek_token(&val, NULL, cfile); if (token == END_OF_FILE) break; parse_client_statement(cfile, NULL, &top_level_config); } while (1); end_parse(&parse); #endif } /* Set up state and config structures for clients that don't have per-interface configuration statements. */ config = (struct client_config *)0; for (ip = interfaces; ip; ip = ip -> next) { if (!ip -> client) { ip -> client = (struct client_state *) dmalloc (sizeof (struct client_state), MDL); if (!ip -> client) log_fatal ("no memory for client state."); memset (ip -> client, 0, sizeof *(ip -> client)); ip -> client -> interface = ip; } if (!ip -> client -> config) { if (!config) { config = (struct client_config *) dmalloc (sizeof (struct client_config), MDL); if (!config) log_fatal ("no memory for client config."); memcpy (config, &top_level_config, sizeof top_level_config); } ip -> client -> config = config; } } return status; } int read_client_conf_file (const char *name, struct interface_info *ip, struct client_config *client) { int file; struct parse *cfile; const char *val; int token; isc_result_t status; if ((file = open (name, O_RDONLY)) < 0) return uerr2isc (errno); cfile = NULL; status = new_parse(&cfile, file, NULL, 0, path_dhclient_conf, 0); if (status != ISC_R_SUCCESS || cfile == NULL) return status; do { token = peek_token (&val, (unsigned *)0, cfile); if (token == END_OF_FILE) break; parse_client_statement (cfile, ip, client); } while (1); token = next_token (&val, (unsigned *)0, cfile); status = (cfile -> warnings_occurred ? DHCP_R_BADPARSE : ISC_R_SUCCESS); end_parse (&cfile); return status; } /* lease-file :== client-lease-statements END_OF_FILE client-lease-statements :== | client-lease-statements LEASE client-lease-statement */ void read_client_leases () { int file; isc_result_t status; struct parse *cfile; const char *val; int token; /* Open the lease file. If we can't open it, just return - we can safely trust the server to remember our state. */ if ((file = open (path_dhclient_db, O_RDONLY)) < 0) return; cfile = NULL; status = new_parse(&cfile, file, NULL, 0, path_dhclient_db, 0); if (status != ISC_R_SUCCESS || cfile == NULL) return; do { token = next_token (&val, (unsigned *)0, cfile); if (token == END_OF_FILE) break; switch (token) { case DEFAULT_DUID: parse_client_default_duid(cfile); break; case LEASE: parse_client_lease_statement(cfile, 0); break; case LEASE6: parse_client6_lease_statement(cfile); break; default: log_error ("Corrupt lease file - possible data loss!"); skip_to_semi (cfile); break; } } while (1); end_parse (&cfile); } /* client-declaration :== SEND option-decl | DEFAULT option-decl | SUPERSEDE option-decl | PREPEND option-decl | APPEND option-decl | hardware-declaration | ALSO REQUEST option-list | ALSO REQUIRE option-list | REQUEST option-list | REQUIRE option-list | TIMEOUT number | RETRY number | REBOOT number | SELECT_TIMEOUT number | SCRIPT string | VENDOR_SPACE string | interface-declaration | LEASE client-lease-statement | ALIAS client-lease-statement | KEY key-definition */ void parse_client_statement (cfile, ip, config) struct parse *cfile; struct interface_info *ip; struct client_config *config; { int token; const char *val; struct option *option = NULL; struct executable_statement *stmt; int lose; char *name; enum policy policy; int known; int tmp, i; isc_result_t status; struct option ***append_list, **new_list, **cat_list; switch (peek_token (&val, (unsigned *)0, cfile)) { case INCLUDE: next_token (&val, (unsigned *)0, cfile); token = next_token (&val, (unsigned *)0, cfile); if (token != STRING) { parse_warn (cfile, "filename string expected."); skip_to_semi (cfile); } else { status = read_client_conf_file (val, ip, config); if (status != ISC_R_SUCCESS) parse_warn (cfile, "%s: bad parse.", val); parse_semi (cfile); } return; case KEY: next_token (&val, (unsigned *)0, cfile); if (ip) { /* This may seem arbitrary, but there's a reason for doing it: the authentication key database is not scoped. If we allow the user to declare a key other than in the outer scope, the user is very likely to believe that the key will only be used in that scope. If the user only wants the key to be used on one interface, because it's known that the other interface may be connected to an insecure net and the secret key is considered sensitive, we don't want to lull them into believing they've gotten their way. This is a bit contrived, but people tend not to be entirely rational about security. */ parse_warn (cfile, "key definition not allowed here."); skip_to_semi (cfile); break; } parse_key (cfile); return; case TOKEN_ALSO: /* consume ALSO */ next_token(&val, NULL, cfile); /* consume type of ALSO list. */ token = next_token(&val, NULL, cfile); if (token == REQUEST) { append_list = &config->requested_options; } else if (token == REQUIRE) { append_list = &config->required_options; } else { parse_warn(cfile, "expected REQUEST or REQUIRE list"); skip_to_semi(cfile); return; } /* If there is no list, cut the concat short. */ if (*append_list == NULL) { parse_option_list(cfile, append_list); return; } /* Count the length of the existing list. */ for (i = 0 ; (*append_list)[i] != NULL ; i++) ; /* This space intentionally left blank. */ /* If there's no codes on the list, cut the concat short. */ if (i == 0) { parse_option_list(cfile, append_list); return; } tmp = parse_option_list(cfile, &new_list); if (tmp == 0 || new_list == NULL) return; /* Allocate 'i + tmp' buckets plus a terminator. */ cat_list = dmalloc(sizeof(struct option *) * (i + tmp + 1), MDL); if (cat_list == NULL) { log_error("Unable to allocate memory for new " "request list."); skip_to_semi(cfile); return; } for (i = 0 ; (*append_list)[i] != NULL ; i++) option_reference(&cat_list[i], (*append_list)[i], MDL); tmp = i; for (i = 0 ; new_list[i] != 0 ; i++) option_reference(&cat_list[tmp++], new_list[i], MDL); cat_list[tmp] = 0; /* XXX: We cannot free the old list, because it may have been * XXX: assigned from an outer configuration scope (or may be * XXX: the static default setting). */ *append_list = cat_list; return; /* REQUIRE can either start a policy statement or a comma-separated list of names of required options. */ case REQUIRE: next_token (&val, (unsigned *)0, cfile); token = peek_token (&val, (unsigned *)0, cfile); if (token == AUTHENTICATION) { policy = P_REQUIRE; goto do_policy; } parse_option_list (cfile, &config -> required_options); return; case IGNORE: next_token (&val, (unsigned *)0, cfile); policy = P_IGNORE; goto do_policy; case ACCEPT: next_token (&val, (unsigned *)0, cfile); policy = P_ACCEPT; goto do_policy; case PREFER: next_token (&val, (unsigned *)0, cfile); policy = P_PREFER; goto do_policy; case DONT: next_token (&val, (unsigned *)0, cfile); policy = P_DONT; goto do_policy; do_policy: token = next_token (&val, (unsigned *)0, cfile); if (token == AUTHENTICATION) { if (policy != P_PREFER && policy != P_REQUIRE && policy != P_DONT) { parse_warn (cfile, "invalid authentication policy."); skip_to_semi (cfile); return; } config -> auth_policy = policy; } else if (token != TOKEN_BOOTP) { if (policy != P_PREFER && policy != P_IGNORE && policy != P_ACCEPT) { parse_warn (cfile, "invalid bootp policy."); skip_to_semi (cfile); return; } config -> bootp_policy = policy; } else { parse_warn (cfile, "expecting a policy type."); skip_to_semi (cfile); return; } break; case OPTION: token = next_token (&val, (unsigned *)0, cfile); token = peek_token (&val, (unsigned *)0, cfile); if (token == SPACE) { if (ip) { parse_warn (cfile, "option space definitions %s", " may not be scoped."); skip_to_semi (cfile); break; } parse_option_space_decl (cfile); return; } known = 0; status = parse_option_name(cfile, 1, &known, &option); if (status != ISC_R_SUCCESS || option == NULL) return; token = next_token (&val, (unsigned *)0, cfile); if (token != CODE) { parse_warn (cfile, "expecting \"code\" keyword."); skip_to_semi (cfile); option_dereference(&option, MDL); return; } if (ip) { parse_warn (cfile, "option definitions may only appear in %s", "the outermost scope."); skip_to_semi (cfile); option_dereference(&option, MDL); return; } /* * If the option was known, remove it from the code and name * hash tables before redefining it. */ if (known) { option_name_hash_delete(option->universe->name_hash, option->name, 0, MDL); option_code_hash_delete(option->universe->code_hash, &option->code, 0, MDL); } parse_option_code_definition(cfile, option); option_dereference(&option, MDL); return; case MEDIA: token = next_token (&val, (unsigned *)0, cfile); parse_string_list (cfile, &config -> media, 1); return; case HARDWARE: token = next_token (&val, (unsigned *)0, cfile); if (ip) { parse_hardware_param (cfile, &ip -> hw_address); } else { parse_warn (cfile, "hardware address parameter %s", "not allowed here."); skip_to_semi (cfile); } return; case ANYCAST_MAC: token = next_token(&val, NULL, cfile); if (ip != NULL) { parse_hardware_param(cfile, &ip->anycast_mac_addr); } else { parse_warn(cfile, "anycast mac address parameter " "not allowed here."); skip_to_semi (cfile); } return; case REQUEST: token = next_token (&val, (unsigned *)0, cfile); if (config -> requested_options == default_requested_options) config -> requested_options = NULL; parse_option_list (cfile, &config -> requested_options); return; case TIMEOUT: token = next_token (&val, (unsigned *)0, cfile); parse_lease_time (cfile, &config -> timeout); return; case RETRY: token = next_token (&val, (unsigned *)0, cfile); parse_lease_time (cfile, &config -> retry_interval); return; case SELECT_TIMEOUT: token = next_token (&val, (unsigned *)0, cfile); parse_lease_time (cfile, &config -> select_interval); return; case OMAPI: token = next_token (&val, (unsigned *)0, cfile); token = next_token (&val, (unsigned *)0, cfile); if (token != PORT) { parse_warn (cfile, "unexpected omapi subtype: %s", val); skip_to_semi (cfile); return; } token = next_token (&val, (unsigned *)0, cfile); if (token != NUMBER) { parse_warn (cfile, "invalid port number: `%s'", val); skip_to_semi (cfile); return; } tmp = atoi (val); if (tmp < 0 || tmp > 65535) parse_warn (cfile, "invalid omapi port %d.", tmp); else if (config != &top_level_config) parse_warn (cfile, "omapi port only works at top level."); else config -> omapi_port = tmp; parse_semi (cfile); return; case DO_FORWARD_UPDATE: token = next_token (&val, (unsigned *)0, cfile); token = next_token (&val, (unsigned *)0, cfile); if (!strcasecmp (val, "on") || !strcasecmp (val, "true")) config -> do_forward_update = 1; else if (!strcasecmp (val, "off") || !strcasecmp (val, "false")) config -> do_forward_update = 0; else { parse_warn (cfile, "expecting boolean value."); skip_to_semi (cfile); return; } parse_semi (cfile); return; case REBOOT: token = next_token (&val, (unsigned *)0, cfile); parse_lease_time (cfile, &config -> reboot_timeout); return; case BACKOFF_CUTOFF: token = next_token (&val, (unsigned *)0, cfile); parse_lease_time (cfile, &config -> backoff_cutoff); return; case INITIAL_INTERVAL: token = next_token (&val, (unsigned *)0, cfile); parse_lease_time (cfile, &config -> initial_interval); return; case INITIAL_DELAY: token = next_token (&val, (unsigned *)0, cfile); parse_lease_time (cfile, &config -> initial_delay); return; case SCRIPT: token = next_token (&val, (unsigned *)0, cfile); parse_string (cfile, &config -> script_name, (unsigned *)0); return; case VENDOR: token = next_token (&val, (unsigned *)0, cfile); token = next_token (&val, (unsigned *)0, cfile); if (token != OPTION) { parse_warn (cfile, "expecting 'vendor option space'"); skip_to_semi (cfile); return; } token = next_token (&val, (unsigned *)0, cfile); if (token != SPACE) { parse_warn (cfile, "expecting 'vendor option space'"); skip_to_semi (cfile); return; } token = next_token (&val, (unsigned *)0, cfile); if (!is_identifier (token)) { parse_warn (cfile, "expecting an identifier."); skip_to_semi (cfile); return; } config -> vendor_space_name = dmalloc (strlen (val) + 1, MDL); if (!config -> vendor_space_name) log_fatal ("no memory for vendor option space name."); strcpy (config -> vendor_space_name, val); for (i = 0; i < universe_count; i++) if (!strcmp (universes [i] -> name, config -> vendor_space_name)) break; if (i == universe_count) { log_error ("vendor option space %s not found.", config -> vendor_space_name); } parse_semi (cfile); return; case INTERFACE: token = next_token (&val, (unsigned *)0, cfile); if (ip) parse_warn (cfile, "nested interface declaration."); parse_interface_declaration (cfile, config, (char *)0); return; case PSEUDO: token = next_token (&val, (unsigned *)0, cfile); token = next_token (&val, (unsigned *)0, cfile); name = dmalloc (strlen (val) + 1, MDL); if (!name) log_fatal ("no memory for pseudo interface name"); strcpy (name, val); parse_interface_declaration (cfile, config, name); return; case LEASE: token = next_token (&val, (unsigned *)0, cfile); parse_client_lease_statement (cfile, 1); return; case ALIAS: token = next_token (&val, (unsigned *)0, cfile); parse_client_lease_statement (cfile, 2); return; case REJECT: token = next_token (&val, (unsigned *)0, cfile); parse_reject_statement (cfile, config); return; default: lose = 0; stmt = (struct executable_statement *)0; if (!parse_executable_statement (&stmt, cfile, &lose, context_any)) { if (!lose) { parse_warn (cfile, "expecting a statement."); skip_to_semi (cfile); } } else { struct executable_statement **eptr, *sptr; if (stmt && (stmt -> op == send_option_statement || (stmt -> op == on_statement && (stmt -> data.on.evtypes & ON_TRANSMISSION)))) { eptr = &config -> on_transmission -> statements; if (stmt -> op == on_statement) { sptr = (struct executable_statement *)0; executable_statement_reference (&sptr, stmt -> data.on.statements, MDL); executable_statement_dereference (&stmt, MDL); executable_statement_reference (&stmt, sptr, MDL); executable_statement_dereference (&sptr, MDL); } } else eptr = &config -> on_receipt -> statements; if (stmt) { for (; *eptr; eptr = &(*eptr) -> next) ; executable_statement_reference (eptr, stmt, MDL); } return; } break; } parse_semi (cfile); } /* option-list :== option_name | option_list COMMA option_name */ int parse_option_list(struct parse *cfile, struct option ***list) { int ix; int token; const char *val; pair p = (pair)0, q = (pair)0, r; struct option *option = NULL; isc_result_t status; ix = 0; do { token = peek_token (&val, (unsigned *)0, cfile); if (token == SEMI) { token = next_token (&val, (unsigned *)0, cfile); break; } if (!is_identifier (token)) { parse_warn (cfile, "%s: expected option name.", val); token = next_token (&val, (unsigned *)0, cfile); skip_to_semi (cfile); return 0; } status = parse_option_name(cfile, 0, NULL, &option); if (status != ISC_R_SUCCESS || option == NULL) { parse_warn (cfile, "%s: expected option name.", val); return 0; } r = new_pair (MDL); if (!r) log_fatal ("can't allocate pair for option code."); /* XXX: we should probably carry a reference across this */ r->car = (caddr_t)option; option_dereference(&option, MDL); r -> cdr = (pair)0; if (p) q -> cdr = r; else p = r; q = r; ++ix; token = next_token (&val, (unsigned *)0, cfile); } while (token == COMMA); if (token != SEMI) { parse_warn (cfile, "expecting semicolon."); skip_to_semi (cfile); return 0; } /* XXX we can't free the list here, because we may have copied XXX it from an outer config state. */ *list = NULL; if (ix) { *list = dmalloc ((ix + 1) * sizeof(struct option *), MDL); if (!*list) log_error ("no memory for option list."); else { ix = 0; for (q = p; q; q = q -> cdr) option_reference(&(*list)[ix++], (struct option *)q->car, MDL); (*list)[ix] = NULL; } while (p) { q = p -> cdr; free_pair (p, MDL); p = q; } } return ix; } /* interface-declaration :== INTERFACE string LBRACE client-declarations RBRACE */ void parse_interface_declaration (cfile, outer_config, name) struct parse *cfile; struct client_config *outer_config; char *name; { int token; const char *val; struct client_state *client, **cp; struct interface_info *ip = (struct interface_info *)0; token = next_token (&val, (unsigned *)0, cfile); if (token != STRING) { parse_warn (cfile, "expecting interface name (in quotes)."); skip_to_semi (cfile); return; } if (!interface_or_dummy (&ip, val)) log_fatal ("Can't allocate interface %s.", val); /* If we were given a name, this is a pseudo-interface. */ if (name) { make_client_state (&client); client -> name = name; client -> interface = ip; for (cp = &ip -> client; *cp; cp = &((*cp) -> next)) ; *cp = client; } else { if (!ip -> client) { make_client_state (&ip -> client); ip -> client -> interface = ip; } client = ip -> client; } if (!client -> config) make_client_config (client, outer_config); ip -> flags &= ~INTERFACE_AUTOMATIC; interfaces_requested = 1; token = next_token (&val, (unsigned *)0, cfile); if (token != LBRACE) { parse_warn (cfile, "expecting left brace."); skip_to_semi (cfile); return; } do { token = peek_token (&val, (unsigned *)0, cfile); if (token == END_OF_FILE) { parse_warn (cfile, "unterminated interface declaration."); return; } if (token == RBRACE) break; parse_client_statement (cfile, ip, client -> config); } while (1); token = next_token (&val, (unsigned *)0, cfile); } int interface_or_dummy (struct interface_info **pi, const char *name) { struct interface_info *i; struct interface_info *ip = (struct interface_info *)0; isc_result_t status; /* Find the interface (if any) that matches the name. */ for (i = interfaces; i; i = i -> next) { if (!strcmp (i -> name, name)) { interface_reference (&ip, i, MDL); break; } } /* If it's not a real interface, see if it's on the dummy list. */ if (!ip) { for (ip = dummy_interfaces; ip; ip = ip -> next) { if (!strcmp (ip -> name, name)) { interface_reference (&ip, i, MDL); break; } } } /* If we didn't find an interface, make a dummy interface as a placeholder. */ if (!ip) { if ((status = interface_allocate (&ip, MDL)) != ISC_R_SUCCESS) log_fatal ("Can't record interface %s: %s", name, isc_result_totext (status)); if (strlen(name) >= sizeof(ip->name)) { interface_dereference(&ip, MDL); return 0; } strcpy(ip->name, name); if (dummy_interfaces) { interface_reference (&ip -> next, dummy_interfaces, MDL); interface_dereference (&dummy_interfaces, MDL); } interface_reference (&dummy_interfaces, ip, MDL); } if (pi) status = interface_reference (pi, ip, MDL); else status = ISC_R_FAILURE; interface_dereference (&ip, MDL); if (status != ISC_R_SUCCESS) return 0; return 1; } void make_client_state (state) struct client_state **state; { *state = ((struct client_state *)dmalloc (sizeof **state, MDL)); if (!*state) log_fatal ("no memory for client state\n"); memset (*state, 0, sizeof **state); } void make_client_config (client, config) struct client_state *client; struct client_config *config; { client -> config = (((struct client_config *) dmalloc (sizeof (struct client_config), MDL))); if (!client -> config) log_fatal ("no memory for client config\n"); memcpy (client -> config, config, sizeof *config); if (!clone_group (&client -> config -> on_receipt, config -> on_receipt, MDL) || !clone_group (&client -> config -> on_transmission, config -> on_transmission, MDL)) log_fatal ("no memory for client state groups."); } /* client-lease-statement :== LBRACE client-lease-declarations RBRACE client-lease-declarations :== | client-lease-declaration | client-lease-declarations client-lease-declaration */ void parse_client_lease_statement (cfile, is_static) struct parse *cfile; int is_static; { struct client_lease *lease, *lp, *pl, *next; struct interface_info *ip = (struct interface_info *)0; int token; const char *val; struct client_state *client = (struct client_state *)0; token = next_token (&val, (unsigned *)0, cfile); if (token != LBRACE) { parse_warn (cfile, "expecting left brace."); skip_to_semi (cfile); return; } lease = ((struct client_lease *) dmalloc (sizeof (struct client_lease), MDL)); if (!lease) log_fatal ("no memory for lease.\n"); memset (lease, 0, sizeof *lease); lease -> is_static = is_static; if (!option_state_allocate (&lease -> options, MDL)) log_fatal ("no memory for lease options.\n"); do { token = peek_token (&val, (unsigned *)0, cfile); if (token == END_OF_FILE) { parse_warn (cfile, "unterminated lease declaration."); return; } if (token == RBRACE) break; parse_client_lease_declaration (cfile, lease, &ip, &client); } while (1); token = next_token (&val, (unsigned *)0, cfile); /* If the lease declaration didn't include an interface declaration that we recognized, it's of no use to us. */ if (!ip) { destroy_client_lease (lease); return; } /* Make sure there's a client state structure... */ if (!ip -> client) { make_client_state (&ip -> client); ip -> client -> interface = ip; } if (!client) client = ip -> client; /* If this is an alias lease, it doesn't need to be sorted in. */ if (is_static == 2) { ip -> client -> alias = lease; return; } /* The new lease may supersede a lease that's not the active lease but is still on the lease list, so scan the lease list looking for a lease with the same address, and if we find it, toss it. */ pl = (struct client_lease *)0; for (lp = client -> leases; lp; lp = next) { next = lp -> next; if (lp -> address.len == lease -> address.len && !memcmp (lp -> address.iabuf, lease -> address.iabuf, lease -> address.len)) { if (pl) pl -> next = next; else client -> leases = next; destroy_client_lease (lp); break; } else pl = lp; } /* If this is a preloaded lease, just put it on the list of recorded leases - don't make it the active lease. */ if (is_static) { lease -> next = client -> leases; client -> leases = lease; return; } /* The last lease in the lease file on a particular interface is the active lease for that interface. Of course, we don't know what the last lease in the file is until we've parsed the whole file, so at this point, we assume that the lease we just parsed is the active lease for its interface. If there's already an active lease for the interface, and this lease is for the same ip address, then we just toss the old active lease and replace it with this one. If this lease is for a different address, then if the old active lease has expired, we dump it; if not, we put it on the list of leases for this interface which are still valid but no longer active. */ if (client -> active) { if (client -> active -> expiry < cur_time) destroy_client_lease (client -> active); else if (client -> active -> address.len == lease -> address.len && !memcmp (client -> active -> address.iabuf, lease -> address.iabuf, lease -> address.len)) destroy_client_lease (client -> active); else { client -> active -> next = client -> leases; client -> leases = client -> active; } } client -> active = lease; /* phew. */ } /* client-lease-declaration :== BOOTP | INTERFACE string | FIXED_ADDR ip_address | FILENAME string | SERVER_NAME string | OPTION option-decl | RENEW time-decl | REBIND time-decl | EXPIRE time-decl | KEY id */ void parse_client_lease_declaration (cfile, lease, ipp, clientp) struct parse *cfile; struct client_lease *lease; struct interface_info **ipp; struct client_state **clientp; { int token; const char *val; struct interface_info *ip; struct option_cache *oc; struct client_state *client = (struct client_state *)0; switch (next_token (&val, (unsigned *)0, cfile)) { case KEY: token = next_token (&val, (unsigned *)0, cfile); if (token != STRING && !is_identifier (token)) { parse_warn (cfile, "expecting key name."); skip_to_semi (cfile); break; } if (omapi_auth_key_lookup_name (&lease -> key, val) != ISC_R_SUCCESS) parse_warn (cfile, "unknown key %s", val); parse_semi (cfile); break; case TOKEN_BOOTP: lease -> is_bootp = 1; break; case INTERFACE: token = next_token (&val, (unsigned *)0, cfile); if (token != STRING) { parse_warn (cfile, "expecting interface name (in quotes)."); skip_to_semi (cfile); break; } if (!interface_or_dummy (ipp, val)) log_fatal ("Can't allocate interface %s.", val); break; case NAME: token = next_token (&val, (unsigned *)0, cfile); ip = *ipp; if (!ip) { parse_warn (cfile, "state name precedes interface."); break; } for (client = ip -> client; client; client = client -> next) if (client -> name && !strcmp (client -> name, val)) break; if (!client) parse_warn (cfile, "lease specified for unknown pseudo."); *clientp = client; break; case FIXED_ADDR: if (!parse_ip_addr (cfile, &lease -> address)) return; break; case MEDIUM: parse_string_list (cfile, &lease -> medium, 0); return; case FILENAME: parse_string (cfile, &lease -> filename, (unsigned *)0); return; case SERVER_NAME: parse_string (cfile, &lease -> server_name, (unsigned *)0); return; case RENEW: lease -> renewal = parse_date (cfile); return; case REBIND: lease -> rebind = parse_date (cfile); return; case EXPIRE: lease -> expiry = parse_date (cfile); return; case OPTION: oc = (struct option_cache *)0; if (parse_option_decl (&oc, cfile)) { save_option(oc->option->universe, lease->options, oc); option_cache_dereference (&oc, MDL); } return; default: parse_warn (cfile, "expecting lease declaration."); skip_to_semi (cfile); break; } token = next_token (&val, (unsigned *)0, cfile); if (token != SEMI) { parse_warn (cfile, "expecting semicolon."); skip_to_semi (cfile); } } /* Parse a default-duid ""; statement. */ static void parse_client_default_duid(struct parse *cfile) { struct data_string new_duid; const char *val = NULL; unsigned len; int token; memset(&new_duid, 0, sizeof(new_duid)); token = next_token(&val, &len, cfile); if (token != STRING) { parse_warn(cfile, "Expected DUID string."); skip_to_semi(cfile); return; } if (len <= 2) { parse_warn(cfile, "Invalid DUID contents."); skip_to_semi(cfile); return; } if (!buffer_allocate(&new_duid.buffer, len, MDL)) { parse_warn(cfile, "Out of memory parsing default DUID."); skip_to_semi(cfile); return; } new_duid.data = new_duid.buffer->data; new_duid.len = len; memcpy(new_duid.buffer->data, val, len); /* Rotate the last entry into place. */ if (default_duid.buffer != NULL) data_string_forget(&default_duid, MDL); data_string_copy(&default_duid, &new_duid, MDL); data_string_forget(&new_duid, MDL); parse_semi(cfile); } /* Parse a lease6 {} construct. The v6 client is a little different * than the v4 client today, in that it only retains one lease, the * active lease, and discards any less recent information. It may * be useful in the future to cache additional information, but it * is not worth the effort for the moment. */ static void parse_client6_lease_statement(struct parse *cfile) { #if !defined(DHCPv6) parse_warn(cfile, "No DHCPv6 support."); skip_to_semi(cfile); #else /* defined(DHCPv6) */ struct option_cache *oc = NULL; struct dhc6_lease *lease; struct dhc6_ia **ia; struct client_state *client = NULL; struct interface_info *iface = NULL; struct data_string ds; const char *val; unsigned len; int token, has_ia, no_semi, has_name; token = next_token(NULL, NULL, cfile); if (token != LBRACE) { parse_warn(cfile, "Expecting open curly brace."); skip_to_semi(cfile); return; } lease = dmalloc(sizeof(*lease), MDL); if (lease == NULL) { parse_warn(cfile, "Unable to allocate lease state."); skip_to_rbrace(cfile, 1); return; } option_state_allocate(&lease->options, MDL); if (lease->options == NULL) { parse_warn(cfile, "Unable to allocate option cache."); skip_to_rbrace(cfile, 1); dfree(lease, MDL); return; } has_ia = 0; has_name = 0; ia = &lease->bindings; token = next_token(&val, NULL, cfile); while (token != RBRACE) { no_semi = 0; switch(token) { case IA_NA: *ia = parse_client6_ia_na_statement(cfile); if (*ia != NULL) { ia = &(*ia)->next; has_ia = 1; } no_semi = 1; break; case IA_TA: *ia = parse_client6_ia_ta_statement(cfile); if (*ia != NULL) { ia = &(*ia)->next; has_ia = 1; } no_semi = 1; break; case IA_PD: *ia = parse_client6_ia_pd_statement(cfile); if (*ia != NULL) { ia = &(*ia)->next; has_ia = 1; } no_semi = 1; break; case INTERFACE: if (iface != NULL) { parse_warn(cfile, "Multiple interface names?"); skip_to_semi(cfile); no_semi = 1; break; } token = next_token(&val, &len, cfile); if (token != STRING) { strerror: parse_warn(cfile, "Expecting a string."); skip_to_semi(cfile); no_semi = 1; break; } for (iface = interfaces ; iface != NULL ; iface = iface->next) { if (strcmp(iface->name, val) == 0) break; } if (iface == NULL) { parse_warn(cfile, "Unknown interface."); break; } break; case NAME: has_name = 1; if (client != NULL) { parse_warn(cfile, "Multiple state names?"); skip_to_semi(cfile); no_semi = 1; break; } if (iface == NULL) { parse_warn(cfile, "Client name without " "interface."); skip_to_semi(cfile); no_semi = 1; break; } token = next_token(&val, &len, cfile); if (token != STRING) goto strerror; for (client = iface->client ; client != NULL ; client = client->next) { if ((client->name != NULL) && (strcmp(client->name, val) == 0)) break; } if (client == NULL) { parse_warn(cfile, "Unknown client state %s.", val); break; } break; case OPTION: if (parse_option_decl(&oc, cfile)) { save_option(oc->option->universe, lease->options, oc); option_cache_dereference(&oc, MDL); } no_semi = 1; break; case TOKEN_RELEASED: case TOKEN_ABANDONED: lease->released = ISC_TRUE; break; default: parse_warn(cfile, "Unexpected token, %s.", val); no_semi = 1; skip_to_semi(cfile); break; } if (!no_semi) parse_semi(cfile); token = next_token(&val, NULL, cfile); if (token == END_OF_FILE) { parse_warn(cfile, "Unexpected end of file."); break; } } if (!has_ia) { log_debug("Lease with no IA's discarded from lease db."); dhc6_lease_destroy(&lease, MDL); return; } if (iface == NULL) parse_warn(cfile, "Lease has no interface designation."); else if (!has_name && (client == NULL)) { for (client = iface->client ; client != NULL ; client = client->next) { if (client->name == NULL) break; } } if (client == NULL) { parse_warn(cfile, "No matching client state."); dhc6_lease_destroy(&lease, MDL); return; } /* Fetch Preference option from option cache. */ memset(&ds, 0, sizeof(ds)); oc = lookup_option(&dhcpv6_universe, lease->options, D6O_PREFERENCE); if ((oc != NULL) && evaluate_option_cache(&ds, NULL, NULL, NULL, lease->options, NULL, &global_scope, oc, MDL)) { if (ds.len != 1) { log_error("Invalid length of DHCPv6 Preference option " "(%d != 1)", ds.len); data_string_forget(&ds, MDL); dhc6_lease_destroy(&lease, MDL); return; } else lease->pref = ds.data[0]; data_string_forget(&ds, MDL); } /* Fetch server-id option from option cache. */ oc = lookup_option(&dhcpv6_universe, lease->options, D6O_SERVERID); if ((oc == NULL) || !evaluate_option_cache(&lease->server_id, NULL, NULL, NULL, lease->options, NULL, &global_scope, oc, MDL) || (lease->server_id.len == 0)) { /* This should be impossible... */ log_error("Invalid SERVERID option cache."); dhc6_lease_destroy(&lease, MDL); return; } if (client->active_lease != NULL) dhc6_lease_destroy(&client->active_lease, MDL); client->active_lease = lease; #endif /* defined(DHCPv6) */ } /* Parse an ia_na object from the client lease. */ #ifdef DHCPv6 static struct dhc6_ia * parse_client6_ia_na_statement(struct parse *cfile) { struct option_cache *oc = NULL; struct dhc6_ia *ia; struct dhc6_addr **addr; const char *val; int token, no_semi, len; u_int8_t buf[5]; ia = dmalloc(sizeof(*ia), MDL); if (ia == NULL) { parse_warn(cfile, "Out of memory allocating IA_NA state."); skip_to_semi(cfile); return NULL; } ia->ia_type = D6O_IA_NA; /* Get IAID. */ len = parse_X(cfile, buf, 5); if (len == 4) { memcpy(ia->iaid, buf, 4); } else { parse_warn(cfile, "Expecting IAID of length 4, got %d.", len); skip_to_semi(cfile); dfree(ia, MDL); return NULL; } token = next_token(NULL, NULL, cfile); if (token != LBRACE) { parse_warn(cfile, "Expecting open curly brace."); skip_to_semi(cfile); dfree(ia, MDL); return NULL; } option_state_allocate(&ia->options, MDL); if (ia->options == NULL) { parse_warn(cfile, "Unable to allocate option state."); skip_to_rbrace(cfile, 1); dfree(ia, MDL); return NULL; } addr = &ia->addrs; token = next_token(&val, NULL, cfile); while (token != RBRACE) { no_semi = 0; switch (token) { case STARTS: token = next_token(&val, NULL, cfile); if (token == NUMBER) { ia->starts = atoi(val); } else { parse_warn(cfile, "Expecting a number."); skip_to_semi(cfile); no_semi = 1; } break; case RENEW: token = next_token(&val, NULL, cfile); if (token == NUMBER) { ia->renew = atoi(val); } else { parse_warn(cfile, "Expecting a number."); skip_to_semi(cfile); no_semi = 1; } break; case REBIND: token = next_token(&val, NULL, cfile); if (token == NUMBER) { ia->rebind = atoi(val); } else { parse_warn(cfile, "Expecting a number."); skip_to_semi(cfile); no_semi = 1; } break; case IAADDR: *addr = parse_client6_iaaddr_statement(cfile); if (*addr != NULL) addr = &(*addr)->next; no_semi = 1; break; case OPTION: if (parse_option_decl(&oc, cfile)) { save_option(oc->option->universe, ia->options, oc); option_cache_dereference(&oc, MDL); } no_semi = 1; break; default: parse_warn(cfile, "Unexpected token."); no_semi = 1; skip_to_semi(cfile); break; } if (!no_semi) parse_semi(cfile); token = next_token(&val, NULL, cfile); if (token == END_OF_FILE) { parse_warn(cfile, "Unexpected end of file."); break; } } return ia; } #endif /* DHCPv6 */ /* Parse an ia_ta object from the client lease. */ #ifdef DHCPv6 static struct dhc6_ia * parse_client6_ia_ta_statement(struct parse *cfile) { struct option_cache *oc = NULL; struct dhc6_ia *ia; struct dhc6_addr **addr; const char *val; int token, no_semi, len; u_int8_t buf[5]; ia = dmalloc(sizeof(*ia), MDL); if (ia == NULL) { parse_warn(cfile, "Out of memory allocating IA_TA state."); skip_to_semi(cfile); return NULL; } ia->ia_type = D6O_IA_TA; /* Get IAID. */ len = parse_X(cfile, buf, 5); if (len == 4) { memcpy(ia->iaid, buf, 4); } else { parse_warn(cfile, "Expecting IAID of length 4, got %d.", len); skip_to_semi(cfile); dfree(ia, MDL); return NULL; } token = next_token(NULL, NULL, cfile); if (token != LBRACE) { parse_warn(cfile, "Expecting open curly brace."); skip_to_semi(cfile); dfree(ia, MDL); return NULL; } option_state_allocate(&ia->options, MDL); if (ia->options == NULL) { parse_warn(cfile, "Unable to allocate option state."); skip_to_rbrace(cfile, 1); dfree(ia, MDL); return NULL; } addr = &ia->addrs; token = next_token(&val, NULL, cfile); while (token != RBRACE) { no_semi = 0; switch (token) { case STARTS: token = next_token(&val, NULL, cfile); if (token == NUMBER) { ia->starts = atoi(val); } else { parse_warn(cfile, "Expecting a number."); skip_to_semi(cfile); no_semi = 1; } break; /* No RENEW or REBIND */ case IAADDR: *addr = parse_client6_iaaddr_statement(cfile); if (*addr != NULL) addr = &(*addr)->next; no_semi = 1; break; case OPTION: if (parse_option_decl(&oc, cfile)) { save_option(oc->option->universe, ia->options, oc); option_cache_dereference(&oc, MDL); } no_semi = 1; break; default: parse_warn(cfile, "Unexpected token."); no_semi = 1; skip_to_semi(cfile); break; } if (!no_semi) parse_semi(cfile); token = next_token(&val, NULL, cfile); if (token == END_OF_FILE) { parse_warn(cfile, "Unexpected end of file."); break; } } return ia; } #endif /* DHCPv6 */ /* Parse an ia_pd object from the client lease. */ #ifdef DHCPv6 static struct dhc6_ia * parse_client6_ia_pd_statement(struct parse *cfile) { struct option_cache *oc = NULL; struct dhc6_ia *ia; struct dhc6_addr **pref; const char *val; int token, no_semi, len; u_int8_t buf[5]; ia = dmalloc(sizeof(*ia), MDL); if (ia == NULL) { parse_warn(cfile, "Out of memory allocating IA_PD state."); skip_to_semi(cfile); return NULL; } ia->ia_type = D6O_IA_PD; /* Get IAID. */ len = parse_X(cfile, buf, 5); if (len == 4) { memcpy(ia->iaid, buf, 4); } else { parse_warn(cfile, "Expecting IAID of length 4, got %d.", len); skip_to_semi(cfile); dfree(ia, MDL); return NULL; } token = next_token(NULL, NULL, cfile); if (token != LBRACE) { parse_warn(cfile, "Expecting open curly brace."); skip_to_semi(cfile); dfree(ia, MDL); return NULL; } option_state_allocate(&ia->options, MDL); if (ia->options == NULL) { parse_warn(cfile, "Unable to allocate option state."); skip_to_rbrace(cfile, 1); dfree(ia, MDL); return NULL; } pref = &ia->addrs; token = next_token(&val, NULL, cfile); while (token != RBRACE) { no_semi = 0; switch (token) { case STARTS: token = next_token(&val, NULL, cfile); if (token == NUMBER) { ia->starts = atoi(val); } else { parse_warn(cfile, "Expecting a number."); skip_to_semi(cfile); no_semi = 1; } break; case RENEW: token = next_token(&val, NULL, cfile); if (token == NUMBER) { ia->renew = atoi(val); } else { parse_warn(cfile, "Expecting a number."); skip_to_semi(cfile); no_semi = 1; } break; case REBIND: token = next_token(&val, NULL, cfile); if (token == NUMBER) { ia->rebind = atoi(val); } else { parse_warn(cfile, "Expecting a number."); skip_to_semi(cfile); no_semi = 1; } break; case IAPREFIX: *pref = parse_client6_iaprefix_statement(cfile); if (*pref != NULL) pref = &(*pref)->next; no_semi = 1; break; case OPTION: if (parse_option_decl(&oc, cfile)) { save_option(oc->option->universe, ia->options, oc); option_cache_dereference(&oc, MDL); } no_semi = 1; break; default: parse_warn(cfile, "Unexpected token."); no_semi = 1; skip_to_semi(cfile); break; } if (!no_semi) parse_semi(cfile); token = next_token(&val, NULL, cfile); if (token == END_OF_FILE) { parse_warn(cfile, "Unexpected end of file."); break; } } return ia; } #endif /* DHCPv6 */ /* Parse an iaaddr {} structure. */ #ifdef DHCPv6 static struct dhc6_addr * parse_client6_iaaddr_statement(struct parse *cfile) { struct option_cache *oc = NULL; struct dhc6_addr *addr; const char *val; int token, no_semi; addr = dmalloc(sizeof(*addr), MDL); if (addr == NULL) { parse_warn(cfile, "Unable to allocate IAADDR state."); skip_to_semi(cfile); return NULL; } /* Get IP address. */ if (!parse_ip6_addr(cfile, &addr->address)) { skip_to_semi(cfile); dfree(addr, MDL); return NULL; } token = next_token(NULL, NULL, cfile); if (token != LBRACE) { parse_warn(cfile, "Expecting open curly bracket."); skip_to_semi(cfile); dfree(addr, MDL); return NULL; } option_state_allocate(&addr->options, MDL); if (addr->options == NULL) { parse_warn(cfile, "Unable to allocate option state."); skip_to_semi(cfile); dfree(addr, MDL); return NULL; } token = next_token(&val, NULL, cfile); while (token != RBRACE) { no_semi = 0; switch (token) { case STARTS: token = next_token(&val, NULL, cfile); if (token == NUMBER) { addr->starts = atoi(val); } else { parse_warn(cfile, "Expecting a number."); skip_to_semi(cfile); no_semi = 1; } break; case PREFERRED_LIFE: token = next_token(&val, NULL, cfile); if (token == NUMBER) { addr->preferred_life = atoi(val); } else { parse_warn(cfile, "Expecting a number."); skip_to_semi(cfile); no_semi = 1; } break; case MAX_LIFE: token = next_token(&val, NULL, cfile); if (token == NUMBER) { addr->max_life = atoi(val); } else { parse_warn(cfile, "Expecting a number."); skip_to_semi(cfile); no_semi = 1; } break; case OPTION: if (parse_option_decl(&oc, cfile)) { save_option(oc->option->universe, addr->options, oc); option_cache_dereference(&oc, MDL); } no_semi = 1; break; default: parse_warn(cfile, "Unexpected token."); skip_to_rbrace(cfile, 1); no_semi = 1; break; } if (!no_semi) parse_semi(cfile); token = next_token(&val, NULL, cfile); if (token == END_OF_FILE) { parse_warn(cfile, "Unexpected end of file."); break; } } return addr; } #endif /* DHCPv6 */ /* Parse an iaprefix {} structure. */ #ifdef DHCPv6 static struct dhc6_addr * parse_client6_iaprefix_statement(struct parse *cfile) { struct option_cache *oc = NULL; struct dhc6_addr *pref; const char *val; int token, no_semi; pref = dmalloc(sizeof(*pref), MDL); if (pref == NULL) { parse_warn(cfile, "Unable to allocate IAPREFIX state."); skip_to_semi(cfile); return NULL; } /* Get IP prefix. */ if (!parse_ip6_prefix(cfile, &pref->address, &pref->plen)) { skip_to_semi(cfile); dfree(pref, MDL); return NULL; } token = next_token(NULL, NULL, cfile); if (token != LBRACE) { parse_warn(cfile, "Expecting open curly bracket."); skip_to_semi(cfile); dfree(pref, MDL); return NULL; } option_state_allocate(&pref->options, MDL); if (pref->options == NULL) { parse_warn(cfile, "Unable to allocate option state."); skip_to_semi(cfile); dfree(pref, MDL); return NULL; } token = next_token(&val, NULL, cfile); while (token != RBRACE) { no_semi = 0; switch (token) { case STARTS: token = next_token(&val, NULL, cfile); if (token == NUMBER) { pref->starts = atoi(val); } else { parse_warn(cfile, "Expecting a number."); skip_to_semi(cfile); no_semi = 1; } break; case PREFERRED_LIFE: token = next_token(&val, NULL, cfile); if (token == NUMBER) { pref->preferred_life = atoi(val); } else { parse_warn(cfile, "Expecting a number."); skip_to_semi(cfile); no_semi = 1; } break; case MAX_LIFE: token = next_token(&val, NULL, cfile); if (token == NUMBER) { pref->max_life = atoi(val); } else { parse_warn(cfile, "Expecting a number."); skip_to_semi(cfile); no_semi = 1; } break; case OPTION: if (parse_option_decl(&oc, cfile)) { save_option(oc->option->universe, pref->options, oc); option_cache_dereference(&oc, MDL); } no_semi = 1; break; default: parse_warn(cfile, "Unexpected token."); skip_to_rbrace(cfile, 1); no_semi = 1; break; } if (!no_semi) parse_semi(cfile); token = next_token(&val, NULL, cfile); if (token == END_OF_FILE) { parse_warn(cfile, "Unexpected end of file."); break; } } return pref; } #endif /* DHCPv6 */ void parse_string_list (cfile, lp, multiple) struct parse *cfile; struct string_list **lp; int multiple; { int token; const char *val; struct string_list *cur, *tmp; /* Find the last medium in the media list. */ if (*lp) { for (cur = *lp; cur -> next; cur = cur -> next) ; } else { cur = (struct string_list *)0; } do { token = next_token (&val, (unsigned *)0, cfile); if (token != STRING) { parse_warn (cfile, "Expecting media options."); skip_to_semi (cfile); return; } tmp = ((struct string_list *) dmalloc (strlen (val) + sizeof (struct string_list), MDL)); if (!tmp) log_fatal ("no memory for string list entry."); strcpy (tmp -> string, val); tmp -> next = (struct string_list *)0; /* Store this medium at the end of the media list. */ if (cur) cur -> next = tmp; else *lp = tmp; cur = tmp; token = next_token (&val, (unsigned *)0, cfile); } while (multiple && token == COMMA); if (token != SEMI) { parse_warn (cfile, "expecting semicolon."); skip_to_semi (cfile); } } void parse_reject_statement (cfile, config) struct parse *cfile; struct client_config *config; { int token; const char *val; struct iaddrmatch match; struct iaddrmatchlist *list; int i; do { if (!parse_ip_addr_with_subnet (cfile, &match)) { /* no warn: parser will have reported what's wrong */ skip_to_semi (cfile); return; } /* check mask is not all zeros (because that would * reject EVERY address). This check could be * simplified if we assume that the mask *always* * represents a prefix .. but perhaps it might be * useful to have a mask which is not a proper prefix * (perhaps for ipv6?). The following is almost as * efficient as inspection of match.mask.iabuf[0] when * it IS a true prefix, and is more general when it is * not. */ for (i=0 ; i < match.mask.len ; i++) { if (match.mask.iabuf[i]) { break; } } if (i == match.mask.len) { /* oops we found all zeros */ parse_warn(cfile, "zero-length prefix is not permitted " "for reject statement"); skip_to_semi(cfile); return; } list = dmalloc(sizeof(struct iaddrmatchlist), MDL); if (!list) log_fatal ("no memory for reject list!"); list->match = match; list->next = config->reject_list; config->reject_list = list; token = next_token (&val, (unsigned *)0, cfile); } while (token == COMMA); if (token != SEMI) { parse_warn (cfile, "expecting semicolon."); skip_to_semi (cfile); } } /* allow-deny-keyword :== BOOTP | BOOTING | DYNAMIC_BOOTP | UNKNOWN_CLIENTS */ int parse_allow_deny (oc, cfile, flag) struct option_cache **oc; struct parse *cfile; int flag; { parse_warn (cfile, "allow/deny/ignore not permitted here."); skip_to_semi (cfile); return 0; } dhcp-4.2.4/client/dhc6.c000644 000765 000024 00000416000 11442512237 014637 0ustar00sarstaff000000 000000 /* dhc6.c - DHCPv6 client routines. */ /* * Copyright (c) 2006-2010 by Internet Systems Consortium, Inc. ("ISC") * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ */ #include "dhcpd.h" #ifdef DHCPv6 struct sockaddr_in6 DHCPv6DestAddr; /* * Option definition structures that are used by the software - declared * here once and assigned at startup to save lookups. */ struct option *clientid_option = NULL; struct option *elapsed_option = NULL; struct option *ia_na_option = NULL; struct option *ia_ta_option = NULL; struct option *ia_pd_option = NULL; struct option *iaaddr_option = NULL; struct option *iaprefix_option = NULL; struct option *oro_option = NULL; struct option *irt_option = NULL; static struct dhc6_lease *dhc6_dup_lease(struct dhc6_lease *lease, const char *file, int line); static struct dhc6_ia *dhc6_dup_ia(struct dhc6_ia *ia, const char *file, int line); static struct dhc6_addr *dhc6_dup_addr(struct dhc6_addr *addr, const char *file, int line); static void dhc6_ia_destroy(struct dhc6_ia **src, const char *file, int line); static isc_result_t dhc6_parse_ia_na(struct dhc6_ia **pia, struct packet *packet, struct option_state *options); static isc_result_t dhc6_parse_ia_ta(struct dhc6_ia **pia, struct packet *packet, struct option_state *options); static isc_result_t dhc6_parse_ia_pd(struct dhc6_ia **pia, struct packet *packet, struct option_state *options); static isc_result_t dhc6_parse_addrs(struct dhc6_addr **paddr, struct packet *packet, struct option_state *options); static isc_result_t dhc6_parse_prefixes(struct dhc6_addr **ppref, struct packet *packet, struct option_state *options); static struct dhc6_ia *find_ia(struct dhc6_ia *head, u_int16_t type, const char *id); static struct dhc6_addr *find_addr(struct dhc6_addr *head, struct iaddr *address); static struct dhc6_addr *find_pref(struct dhc6_addr *head, struct iaddr *prefix, u_int8_t plen); void init_handler(struct packet *packet, struct client_state *client); void info_request_handler(struct packet *packet, struct client_state *client); void rapid_commit_handler(struct packet *packet, struct client_state *client); void do_init6(void *input); void do_info_request6(void *input); void do_confirm6(void *input); void reply_handler(struct packet *packet, struct client_state *client); static isc_result_t dhc6_add_ia_na(struct client_state *client, struct data_string *packet, struct dhc6_lease *lease, u_int8_t message); static isc_result_t dhc6_add_ia_ta(struct client_state *client, struct data_string *packet, struct dhc6_lease *lease, u_int8_t message); static isc_result_t dhc6_add_ia_pd(struct client_state *client, struct data_string *packet, struct dhc6_lease *lease, u_int8_t message); static isc_boolean_t stopping_finished(void); static void dhc6_merge_lease(struct dhc6_lease *src, struct dhc6_lease *dst); void do_select6(void *input); void do_refresh6(void *input); static void do_release6(void *input); static void start_bound(struct client_state *client); static void start_informed(struct client_state *client); void informed_handler(struct packet *packet, struct client_state *client); void bound_handler(struct packet *packet, struct client_state *client); void start_renew6(void *input); void start_rebind6(void *input); void do_depref(void *input); void do_expire(void *input); static void make_client6_options(struct client_state *client, struct option_state **op, struct dhc6_lease *lease, u_int8_t message); static void script_write_params6(struct client_state *client, const char *prefix, struct option_state *options); static isc_boolean_t active_prefix(struct client_state *client); static int check_timing6(struct client_state *client, u_int8_t msg_type, char *msg_str, struct dhc6_lease *lease, struct data_string *ds); extern int onetry; extern int stateless; /* * The "best" default DUID, since we cannot predict any information * about the system (such as whether or not the hardware addresses are * integrated into the motherboard or similar), is the "LLT", link local * plus time, DUID. For real stateless "LL" is better. * * Once generated, this duid is stored into the state database, and * retained across restarts. * * For the time being, there is probably a different state database for * every daemon, so this winds up being a per-interface identifier...which * is not how it is intended. Upcoming rearchitecting the client should * address this "one daemon model." */ void form_duid(struct data_string *duid, const char *file, int line) { struct interface_info *ip; int len; /* For now, just use the first interface on the list. */ ip = interfaces; if (ip == NULL) log_fatal("Impossible condition at %s:%d.", MDL); if ((ip->hw_address.hlen == 0) || (ip->hw_address.hlen > sizeof(ip->hw_address.hbuf))) log_fatal("Impossible hardware address length at %s:%d.", MDL); if (duid_type == 0) duid_type = stateless ? DUID_LL : DUID_LLT; /* * 2 bytes for the 'duid type' field. * 2 bytes for the 'htype' field. * (DUID_LLT) 4 bytes for the 'current time'. * enough bytes for the hardware address (note that hw_address has * the 'htype' on byte zero). */ len = 4 + (ip->hw_address.hlen - 1); if (duid_type == DUID_LLT) len += 4; if (!buffer_allocate(&duid->buffer, len, MDL)) log_fatal("no memory for default DUID!"); duid->data = duid->buffer->data; duid->len = len; /* Basic Link Local Address type of DUID. */ if (duid_type == DUID_LLT) { putUShort(duid->buffer->data, DUID_LLT); putUShort(duid->buffer->data + 2, ip->hw_address.hbuf[0]); putULong(duid->buffer->data + 4, cur_time - DUID_TIME_EPOCH); memcpy(duid->buffer->data + 8, ip->hw_address.hbuf + 1, ip->hw_address.hlen - 1); } else { putUShort(duid->buffer->data, DUID_LL); putUShort(duid->buffer->data + 2, ip->hw_address.hbuf[0]); memcpy(duid->buffer->data + 4, ip->hw_address.hbuf + 1, ip->hw_address.hlen - 1); } } /* * Assign DHCPv6 port numbers as a client. */ void dhcpv6_client_assignments(void) { struct servent *ent; unsigned code; if (path_dhclient_pid == NULL) path_dhclient_pid = _PATH_DHCLIENT6_PID; if (path_dhclient_db == NULL) path_dhclient_db = _PATH_DHCLIENT6_DB; if (local_port == 0) { ent = getservbyname("dhcpv6-client", "udp"); if (ent == NULL) local_port = htons(546); else local_port = ent->s_port; } if (remote_port == 0) { ent = getservbyname("dhcpv6-server", "udp"); if (ent == NULL) remote_port = htons(547); else remote_port = ent->s_port; } memset(&DHCPv6DestAddr, 0, sizeof(DHCPv6DestAddr)); DHCPv6DestAddr.sin6_family = AF_INET6; DHCPv6DestAddr.sin6_port = remote_port; inet_pton(AF_INET6, All_DHCP_Relay_Agents_and_Servers, &DHCPv6DestAddr.sin6_addr); code = D6O_CLIENTID; if (!option_code_hash_lookup(&clientid_option, dhcpv6_universe.code_hash, &code, 0, MDL)) log_fatal("Unable to find the CLIENTID option definition."); code = D6O_ELAPSED_TIME; if (!option_code_hash_lookup(&elapsed_option, dhcpv6_universe.code_hash, &code, 0, MDL)) log_fatal("Unable to find the ELAPSED_TIME option definition."); code = D6O_IA_NA; if (!option_code_hash_lookup(&ia_na_option, dhcpv6_universe.code_hash, &code, 0, MDL)) log_fatal("Unable to find the IA_NA option definition."); code = D6O_IA_TA; if (!option_code_hash_lookup(&ia_ta_option, dhcpv6_universe.code_hash, &code, 0, MDL)) log_fatal("Unable to find the IA_TA option definition."); code = D6O_IA_PD; if (!option_code_hash_lookup(&ia_pd_option, dhcpv6_universe.code_hash, &code, 0, MDL)) log_fatal("Unable to find the IA_PD option definition."); code = D6O_IAADDR; if (!option_code_hash_lookup(&iaaddr_option, dhcpv6_universe.code_hash, &code, 0, MDL)) log_fatal("Unable to find the IAADDR option definition."); code = D6O_IAPREFIX; if (!option_code_hash_lookup(&iaprefix_option, dhcpv6_universe.code_hash, &code, 0, MDL)) log_fatal("Unable to find the IAPREFIX option definition."); code = D6O_ORO; if (!option_code_hash_lookup(&oro_option, dhcpv6_universe.code_hash, &code, 0, MDL)) log_fatal("Unable to find the ORO option definition."); code = D6O_INFORMATION_REFRESH_TIME; if (!option_code_hash_lookup(&irt_option, dhcpv6_universe.code_hash, &code, 0, MDL)) log_fatal("Unable to find the IRT option definition."); #ifndef __CYGWIN32__ /* XXX */ endservent(); #endif } /* * Instead of implementing RFC3315 RAND (section 14) as a float "between" * -0.1 and 0.1 non-inclusive, we implement it as an integer. * * The result is expected to follow this table: * * split range answer * - ERROR - base <= 0 * 0 1 0..0 1 <= base <= 10 * 1 3 -1..1 11 <= base <= 20 * 2 5 -2..2 21 <= base <= 30 * 3 7 -3..3 31 <= base <= 40 * ... * * XXX: For this to make sense, we really need to do timing on a * XXX: usec scale...we currently can assume zero for any value less than * XXX: 11, which are very common in early stages of transmission for most * XXX: messages. */ static TIME dhc6_rand(TIME base) { TIME rval; TIME range; TIME split; /* * A zero or less timeout is a bad thing...we don't want to * DHCP-flood anyone. */ if (base <= 0) log_fatal("Impossible condition at %s:%d.", MDL); /* * The first thing we do is count how many random integers we want * in either direction (best thought of as the maximum negative * integer, as we will subtract this potentially from a random 0). */ split = (base - 1) / 10; /* Don't bother with the rest of the math if we know we'll get 0. */ if (split == 0) return 0; /* * Then we count the total number of integers in this set. This * is twice the number of integers in positive and negative * directions, plus zero (-1, 0, 1 is 3, -2..2 adds 2 to 5, so forth). */ range = (split * 2) + 1; /* Take a random number from [0..(range-1)]. */ rval = random(); rval %= range; /* Offset it to uncover potential negative values. */ rval -= split; return rval; } /* Initialize message exchange timers (set RT from Initial-RT). */ static void dhc6_retrans_init(struct client_state *client) { int xid; /* Initialize timers. */ client->txcount = 0; client->RT = client->IRT + dhc6_rand(client->IRT); /* Generate a new random 24-bit transaction ID for this exchange. */ #if (RAND_MAX >= 0x00ffffff) xid = random(); #elif (RAND_MAX >= 0x0000ffff) xid = (random() << 16) ^ random(); #elif (RAND_MAX >= 0x000000ff) xid = (random() << 16) ^ (random() << 8) ^ random(); #else # error "Random number generator of less than 8 bits not supported." #endif client->dhcpv6_transaction_id[0] = (xid >> 16) & 0xff; client->dhcpv6_transaction_id[1] = (xid >> 8) & 0xff; client->dhcpv6_transaction_id[2] = xid & 0xff; } /* Advance the DHCPv6 retransmission state once. */ static void dhc6_retrans_advance(struct client_state *client) { struct timeval elapsed; /* elapsed = cur - start */ elapsed.tv_sec = cur_tv.tv_sec - client->start_time.tv_sec; elapsed.tv_usec = cur_tv.tv_usec - client->start_time.tv_usec; if (elapsed.tv_usec < 0) { elapsed.tv_sec -= 1; elapsed.tv_usec += 1000000; } /* retrans_advance is called after consuming client->RT. */ /* elapsed += RT */ elapsed.tv_sec += client->RT / 100; elapsed.tv_usec += (client->RT % 100) * 10000; if (elapsed.tv_usec >= 1000000) { elapsed.tv_sec += 1; elapsed.tv_usec -= 1000000; } /* * RT for each subsequent message transmission is based on the previous * value of RT: * * RT = 2*RTprev + RAND*RTprev */ client->RT += client->RT + dhc6_rand(client->RT); /* * MRT specifies an upper bound on the value of RT (disregarding the * randomization added by the use of RAND). If MRT has a value of 0, * there is no upper limit on the value of RT. Otherwise: * * if (RT > MRT) * RT = MRT + RAND*MRT */ if ((client->MRT != 0) && (client->RT > client->MRT)) client->RT = client->MRT + dhc6_rand(client->MRT); /* * Further, if there's an MRD, we should wake up upon reaching * the MRD rather than at some point after it. */ if (client->MRD == 0) { /* Done. */ client->txcount++; return; } /* elapsed += client->RT */ elapsed.tv_sec += client->RT / 100; elapsed.tv_usec += (client->RT % 100) * 10000; if (elapsed.tv_usec >= 1000000) { elapsed.tv_sec += 1; elapsed.tv_usec -= 1000000; } if (elapsed.tv_sec >= client->MRD) { /* * wake at RT + cur = start + MRD */ client->RT = client->MRD + (client->start_time.tv_sec - cur_tv.tv_sec); client->RT = client->RT * 100 + (client->start_time.tv_usec - cur_tv.tv_usec) / 10000; } client->txcount++; } /* Quick validation of DHCPv6 ADVERTISE packet contents. */ static int valid_reply(struct packet *packet, struct client_state *client) { struct data_string sid, cid; struct option_cache *oc; int rval = ISC_TRUE; memset(&sid, 0, sizeof(sid)); memset(&cid, 0, sizeof(cid)); if (!lookup_option(&dhcpv6_universe, packet->options, D6O_SERVERID)) { log_error("Response without a server identifier received."); rval = ISC_FALSE; } oc = lookup_option(&dhcpv6_universe, packet->options, D6O_CLIENTID); if (!oc || !evaluate_option_cache(&sid, packet, NULL, client, packet->options, client->sent_options, &global_scope, oc, MDL)) { log_error("Response without a client identifier."); rval = ISC_FALSE; } oc = lookup_option(&dhcpv6_universe, client->sent_options, D6O_CLIENTID); if (!oc || !evaluate_option_cache(&cid, packet, NULL, client, client->sent_options, NULL, &global_scope, oc, MDL)) { log_error("Local client identifier is missing!"); rval = ISC_FALSE; } if (sid.len == 0 || sid.len != cid.len || memcmp(sid.data, cid.data, sid.len)) { log_error("Advertise with matching transaction ID, but " "mismatching client id."); rval = ISC_FALSE; } return rval; } /* * Create a complete copy of a DHCPv6 lease structure. */ static struct dhc6_lease * dhc6_dup_lease(struct dhc6_lease *lease, const char *file, int line) { struct dhc6_lease *copy; struct dhc6_ia **insert_ia, *ia; copy = dmalloc(sizeof(*copy), file, line); if (copy == NULL) { log_error("Out of memory for v6 lease structure."); return NULL; } data_string_copy(©->server_id, &lease->server_id, file, line); copy->pref = lease->pref; memcpy(copy->dhcpv6_transaction_id, lease->dhcpv6_transaction_id, sizeof(copy->dhcpv6_transaction_id)); option_state_reference(©->options, lease->options, file, line); insert_ia = ©->bindings; for (ia = lease->bindings ; ia != NULL ; ia = ia->next) { *insert_ia = dhc6_dup_ia(ia, file, line); if (*insert_ia == NULL) { dhc6_lease_destroy(©, file, line); return NULL; } insert_ia = &(*insert_ia)->next; } return copy; } /* * Duplicate an IA structure. */ static struct dhc6_ia * dhc6_dup_ia(struct dhc6_ia *ia, const char *file, int line) { struct dhc6_ia *copy; struct dhc6_addr **insert_addr, *addr; copy = dmalloc(sizeof(*ia), file, line); memcpy(copy->iaid, ia->iaid, sizeof(copy->iaid)); copy->ia_type = ia->ia_type; copy->starts = ia->starts; copy->renew = ia->renew; copy->rebind = ia->rebind; insert_addr = ©->addrs; for (addr = ia->addrs ; addr != NULL ; addr = addr->next) { *insert_addr = dhc6_dup_addr(addr, file, line); if (*insert_addr == NULL) { dhc6_ia_destroy(©, file, line); return NULL; } insert_addr = &(*insert_addr)->next; } if (ia->options != NULL) option_state_reference(©->options, ia->options, file, line); return copy; } /* * Duplicate an IAADDR or IAPREFIX structure. */ static struct dhc6_addr * dhc6_dup_addr(struct dhc6_addr *addr, const char *file, int line) { struct dhc6_addr *copy; copy = dmalloc(sizeof(*addr), file, line); if (copy == NULL) return NULL; memcpy(©->address, &addr->address, sizeof(copy->address)); copy->plen = addr->plen; copy->flags = addr->flags; copy->starts = addr->starts; copy->preferred_life = addr->preferred_life; copy->max_life = addr->max_life; if (addr->options != NULL) option_state_reference(©->options, addr->options, file, line); return copy; } /* * Form a DHCPv6 lease structure based upon packet contents. Creates and * populates IA's and any IAADDR/IAPREFIX's they contain. * Parsed options are deleted in order to not save them in the lease file. */ static struct dhc6_lease * dhc6_leaseify(struct packet *packet) { struct data_string ds; struct dhc6_lease *lease; struct option_cache *oc; lease = dmalloc(sizeof(*lease), MDL); if (lease == NULL) { log_error("Out of memory for v6 lease structure."); return NULL; } memcpy(lease->dhcpv6_transaction_id, packet->dhcpv6_transaction_id, 3); option_state_reference(&lease->options, packet->options, MDL); memset(&ds, 0, sizeof(ds)); /* Determine preference (default zero). */ oc = lookup_option(&dhcpv6_universe, lease->options, D6O_PREFERENCE); if (oc && evaluate_option_cache(&ds, packet, NULL, NULL, lease->options, NULL, &global_scope, oc, MDL)) { if (ds.len != 1) { log_error("Invalid length of DHCPv6 Preference option " "(%d != 1)", ds.len); data_string_forget(&ds, MDL); dhc6_lease_destroy(&lease, MDL); return NULL; } else { lease->pref = ds.data[0]; log_debug("RCV: X-- Preference %u.", (unsigned)lease->pref); } data_string_forget(&ds, MDL); } delete_option(&dhcpv6_universe, lease->options, D6O_PREFERENCE); /* * Dig into recursive DHCPv6 pockets for IA_NA and contained IAADDR * options. */ if (dhc6_parse_ia_na(&lease->bindings, packet, lease->options) != ISC_R_SUCCESS) { /* Error conditions are logged by the caller. */ dhc6_lease_destroy(&lease, MDL); return NULL; } /* * Dig into recursive DHCPv6 pockets for IA_TA and contained IAADDR * options. */ if (dhc6_parse_ia_ta(&lease->bindings, packet, lease->options) != ISC_R_SUCCESS) { /* Error conditions are logged by the caller. */ dhc6_lease_destroy(&lease, MDL); return NULL; } /* * Dig into recursive DHCPv6 pockets for IA_PD and contained IAPREFIX * options. */ if (dhc6_parse_ia_pd(&lease->bindings, packet, lease->options) != ISC_R_SUCCESS) { /* Error conditions are logged by the caller. */ dhc6_lease_destroy(&lease, MDL); return NULL; } /* * This is last because in the future we may want to make a different * key based upon additional information from the packet (we may need * to allow multiple leases in one client state per server, but we're * not sure based on what additional keys now). */ oc = lookup_option(&dhcpv6_universe, packet->options, D6O_SERVERID); if (!evaluate_option_cache(&lease->server_id, packet, NULL, NULL, lease->options, NULL, &global_scope, oc, MDL) || lease->server_id.len == 0) { /* This should be impossible due to validation checks earlier. */ log_error("Invalid SERVERID option cache."); dhc6_lease_destroy(&lease, MDL); return NULL; } else { log_debug("RCV: X-- Server ID: %s", print_hex_1(lease->server_id.len, lease->server_id.data, 52)); } return lease; } static isc_result_t dhc6_parse_ia_na(struct dhc6_ia **pia, struct packet *packet, struct option_state *options) { struct data_string ds; struct dhc6_ia *ia; struct option_cache *oc; isc_result_t result; memset(&ds, 0, sizeof(ds)); oc = lookup_option(&dhcpv6_universe, options, D6O_IA_NA); for ( ; oc != NULL ; oc = oc->next) { ia = dmalloc(sizeof(*ia), MDL); if (ia == NULL) { log_error("Out of memory allocating IA_NA structure."); return ISC_R_NOMEMORY; } else if (evaluate_option_cache(&ds, packet, NULL, NULL, options, NULL, &global_scope, oc, MDL) && ds.len >= 12) { memcpy(ia->iaid, ds.data, 4); ia->ia_type = D6O_IA_NA; ia->starts = cur_time; ia->renew = getULong(ds.data + 4); ia->rebind = getULong(ds.data + 8); log_debug("RCV: X-- IA_NA %s", print_hex_1(4, ia->iaid, 59)); /* XXX: This should be the printed time I think. */ log_debug("RCV: | X-- starts %u", (unsigned)ia->starts); log_debug("RCV: | X-- t1 - renew +%u", ia->renew); log_debug("RCV: | X-- t2 - rebind +%u", ia->rebind); /* * RFC3315 section 22.4, discard IA_NA's that * have t1 greater than t2, and both not zero. * Since RFC3315 defines this behaviour, it is not * an error - just normal operation. * * Note that RFC3315 says we MUST honor these values * if they are not zero. So insane values are * totally OK. */ if ((ia->renew > 0) && (ia->rebind > 0) && (ia->renew > ia->rebind)) { log_debug("RCV: | !-- INVALID renew/rebind " "times, IA_NA discarded."); dfree(ia, MDL); data_string_forget(&ds, MDL); continue; } if (ds.len > 12) { log_debug("RCV: | X-- [Options]"); if (!option_state_allocate(&ia->options, MDL)) { log_error("Out of memory allocating " "IA_NA option state."); dfree(ia, MDL); data_string_forget(&ds, MDL); return ISC_R_NOMEMORY; } if (!parse_option_buffer(ia->options, ds.data + 12, ds.len - 12, &dhcpv6_universe)) { log_error("Corrupt IA_NA options."); option_state_dereference(&ia->options, MDL); dfree(ia, MDL); data_string_forget(&ds, MDL); return DHCP_R_BADPARSE; } } data_string_forget(&ds, MDL); if (ia->options != NULL) { result = dhc6_parse_addrs(&ia->addrs, packet, ia->options); if (result != ISC_R_SUCCESS) { option_state_dereference(&ia->options, MDL); dfree(ia, MDL); return result; } } while (*pia != NULL) pia = &(*pia)->next; *pia = ia; pia = &ia->next; } else { log_error("Invalid IA_NA option cache."); dfree(ia, MDL); if (ds.len != 0) data_string_forget(&ds, MDL); return ISC_R_UNEXPECTED; } } delete_option(&dhcpv6_universe, options, D6O_IA_NA); return ISC_R_SUCCESS; } static isc_result_t dhc6_parse_ia_ta(struct dhc6_ia **pia, struct packet *packet, struct option_state *options) { struct data_string ds; struct dhc6_ia *ia; struct option_cache *oc; isc_result_t result; memset(&ds, 0, sizeof(ds)); oc = lookup_option(&dhcpv6_universe, options, D6O_IA_TA); for ( ; oc != NULL ; oc = oc->next) { ia = dmalloc(sizeof(*ia), MDL); if (ia == NULL) { log_error("Out of memory allocating IA_TA structure."); return ISC_R_NOMEMORY; } else if (evaluate_option_cache(&ds, packet, NULL, NULL, options, NULL, &global_scope, oc, MDL) && ds.len >= 4) { memcpy(ia->iaid, ds.data, 4); ia->ia_type = D6O_IA_TA; ia->starts = cur_time; log_debug("RCV: X-- IA_TA %s", print_hex_1(4, ia->iaid, 59)); /* XXX: This should be the printed time I think. */ log_debug("RCV: | X-- starts %u", (unsigned)ia->starts); if (ds.len > 4) { log_debug("RCV: | X-- [Options]"); if (!option_state_allocate(&ia->options, MDL)) { log_error("Out of memory allocating " "IA_TA option state."); dfree(ia, MDL); data_string_forget(&ds, MDL); return ISC_R_NOMEMORY; } if (!parse_option_buffer(ia->options, ds.data + 4, ds.len - 4, &dhcpv6_universe)) { log_error("Corrupt IA_TA options."); option_state_dereference(&ia->options, MDL); dfree(ia, MDL); data_string_forget(&ds, MDL); return DHCP_R_BADPARSE; } } data_string_forget(&ds, MDL); if (ia->options != NULL) { result = dhc6_parse_addrs(&ia->addrs, packet, ia->options); if (result != ISC_R_SUCCESS) { option_state_dereference(&ia->options, MDL); dfree(ia, MDL); return result; } } while (*pia != NULL) pia = &(*pia)->next; *pia = ia; pia = &ia->next; } else { log_error("Invalid IA_TA option cache."); dfree(ia, MDL); if (ds.len != 0) data_string_forget(&ds, MDL); return ISC_R_UNEXPECTED; } } delete_option(&dhcpv6_universe, options, D6O_IA_TA); return ISC_R_SUCCESS; } static isc_result_t dhc6_parse_ia_pd(struct dhc6_ia **pia, struct packet *packet, struct option_state *options) { struct data_string ds; struct dhc6_ia *ia; struct option_cache *oc; isc_result_t result; memset(&ds, 0, sizeof(ds)); oc = lookup_option(&dhcpv6_universe, options, D6O_IA_PD); for ( ; oc != NULL ; oc = oc->next) { ia = dmalloc(sizeof(*ia), MDL); if (ia == NULL) { log_error("Out of memory allocating IA_PD structure."); return ISC_R_NOMEMORY; } else if (evaluate_option_cache(&ds, packet, NULL, NULL, options, NULL, &global_scope, oc, MDL) && ds.len >= 12) { memcpy(ia->iaid, ds.data, 4); ia->ia_type = D6O_IA_PD; ia->starts = cur_time; ia->renew = getULong(ds.data + 4); ia->rebind = getULong(ds.data + 8); log_debug("RCV: X-- IA_PD %s", print_hex_1(4, ia->iaid, 59)); /* XXX: This should be the printed time I think. */ log_debug("RCV: | X-- starts %u", (unsigned)ia->starts); log_debug("RCV: | X-- t1 - renew +%u", ia->renew); log_debug("RCV: | X-- t2 - rebind +%u", ia->rebind); /* * RFC3633 section 9, discard IA_PD's that * have t1 greater than t2, and both not zero. * Since RFC3633 defines this behaviour, it is not * an error - just normal operation. */ if ((ia->renew > 0) && (ia->rebind > 0) && (ia->renew > ia->rebind)) { log_debug("RCV: | !-- INVALID renew/rebind " "times, IA_PD discarded."); dfree(ia, MDL); data_string_forget(&ds, MDL); continue; } if (ds.len > 12) { log_debug("RCV: | X-- [Options]"); if (!option_state_allocate(&ia->options, MDL)) { log_error("Out of memory allocating " "IA_PD option state."); dfree(ia, MDL); data_string_forget(&ds, MDL); return ISC_R_NOMEMORY; } if (!parse_option_buffer(ia->options, ds.data + 12, ds.len - 12, &dhcpv6_universe)) { log_error("Corrupt IA_PD options."); option_state_dereference(&ia->options, MDL); dfree(ia, MDL); data_string_forget(&ds, MDL); return DHCP_R_BADPARSE; } } data_string_forget(&ds, MDL); if (ia->options != NULL) { result = dhc6_parse_prefixes(&ia->addrs, packet, ia->options); if (result != ISC_R_SUCCESS) { option_state_dereference(&ia->options, MDL); dfree(ia, MDL); return result; } } while (*pia != NULL) pia = &(*pia)->next; *pia = ia; pia = &ia->next; } else { log_error("Invalid IA_PD option cache."); dfree(ia, MDL); if (ds.len != 0) data_string_forget(&ds, MDL); return ISC_R_UNEXPECTED; } } delete_option(&dhcpv6_universe, options, D6O_IA_PD); return ISC_R_SUCCESS; } static isc_result_t dhc6_parse_addrs(struct dhc6_addr **paddr, struct packet *packet, struct option_state *options) { struct data_string ds; struct option_cache *oc; struct dhc6_addr *addr; memset(&ds, 0, sizeof(ds)); oc = lookup_option(&dhcpv6_universe, options, D6O_IAADDR); for ( ; oc != NULL ; oc = oc->next) { addr = dmalloc(sizeof(*addr), MDL); if (addr == NULL) { log_error("Out of memory allocating " "address structure."); return ISC_R_NOMEMORY; } else if (evaluate_option_cache(&ds, packet, NULL, NULL, options, NULL, &global_scope, oc, MDL) && (ds.len >= 24)) { addr->address.len = 16; memcpy(addr->address.iabuf, ds.data, 16); addr->starts = cur_time; addr->preferred_life = getULong(ds.data + 16); addr->max_life = getULong(ds.data + 20); log_debug("RCV: | | X-- IAADDR %s", piaddr(addr->address)); log_debug("RCV: | | | X-- Preferred lifetime %u.", addr->preferred_life); log_debug("RCV: | | | X-- Max lifetime %u.", addr->max_life); /* * RFC 3315 section 22.6 says we must discard * addresses whose pref is later than valid. */ if ((addr->preferred_life > addr->max_life)) { log_debug("RCV: | | | !-- INVALID lifetimes, " "IAADDR discarded. Check your " "server configuration."); dfree(addr, MDL); data_string_forget(&ds, MDL); continue; } /* * Fortunately this is the last recursion in the * protocol. */ if (ds.len > 24) { if (!option_state_allocate(&addr->options, MDL)) { log_error("Out of memory allocating " "IAADDR option state."); dfree(addr, MDL); data_string_forget(&ds, MDL); return ISC_R_NOMEMORY; } if (!parse_option_buffer(addr->options, ds.data + 24, ds.len - 24, &dhcpv6_universe)) { log_error("Corrupt IAADDR options."); option_state_dereference(&addr->options, MDL); dfree(addr, MDL); data_string_forget(&ds, MDL); return DHCP_R_BADPARSE; } } if (addr->options != NULL) log_debug("RCV: | | | X-- " "[Options]"); data_string_forget(&ds, MDL); *paddr = addr; paddr = &addr->next; } else { log_error("Invalid IAADDR option cache."); dfree(addr, MDL); if (ds.len != 0) data_string_forget(&ds, MDL); return ISC_R_UNEXPECTED; } } delete_option(&dhcpv6_universe, options, D6O_IAADDR); return ISC_R_SUCCESS; } static isc_result_t dhc6_parse_prefixes(struct dhc6_addr **ppfx, struct packet *packet, struct option_state *options) { struct data_string ds; struct option_cache *oc; struct dhc6_addr *pfx; memset(&ds, 0, sizeof(ds)); oc = lookup_option(&dhcpv6_universe, options, D6O_IAPREFIX); for ( ; oc != NULL ; oc = oc->next) { pfx = dmalloc(sizeof(*pfx), MDL); if (pfx == NULL) { log_error("Out of memory allocating " "prefix structure."); return ISC_R_NOMEMORY; } else if (evaluate_option_cache(&ds, packet, NULL, NULL, options, NULL, &global_scope, oc, MDL) && (ds.len >= 25)) { pfx->preferred_life = getULong(ds.data); pfx->max_life = getULong(ds.data + 4); pfx->plen = getUChar(ds.data + 8); pfx->address.len = 16; memcpy(pfx->address.iabuf, ds.data + 9, 16); pfx->starts = cur_time; log_debug("RCV: | | X-- IAPREFIX %s/%d", piaddr(pfx->address), (int)pfx->plen); log_debug("RCV: | | | X-- Preferred lifetime %u.", pfx->preferred_life); log_debug("RCV: | | | X-- Max lifetime %u.", pfx->max_life); /* Sanity check over the prefix length */ if ((pfx->plen < 4) || (pfx->plen > 128)) { log_debug("RCV: | | | !-- INVALID prefix " "length, IAPREFIX discarded. " "Check your server configuration."); dfree(pfx, MDL); data_string_forget(&ds, MDL); continue; } /* * RFC 3633 section 10 says we must discard * prefixes whose pref is later than valid. */ if ((pfx->preferred_life > pfx->max_life)) { log_debug("RCV: | | | !-- INVALID lifetimes, " "IAPREFIX discarded. Check your " "server configuration."); dfree(pfx, MDL); data_string_forget(&ds, MDL); continue; } /* * Fortunately this is the last recursion in the * protocol. */ if (ds.len > 25) { if (!option_state_allocate(&pfx->options, MDL)) { log_error("Out of memory allocating " "IAPREFIX option state."); dfree(pfx, MDL); data_string_forget(&ds, MDL); return ISC_R_NOMEMORY; } if (!parse_option_buffer(pfx->options, ds.data + 25, ds.len - 25, &dhcpv6_universe)) { log_error("Corrupt IAPREFIX options."); option_state_dereference(&pfx->options, MDL); dfree(pfx, MDL); data_string_forget(&ds, MDL); return DHCP_R_BADPARSE; } } if (pfx->options != NULL) log_debug("RCV: | | | X-- " "[Options]"); data_string_forget(&ds, MDL); *ppfx = pfx; ppfx = &pfx->next; } else { log_error("Invalid IAPREFIX option cache."); dfree(pfx, MDL); if (ds.len != 0) data_string_forget(&ds, MDL); return ISC_R_UNEXPECTED; } } delete_option(&dhcpv6_universe, options, D6O_IAPREFIX); return ISC_R_SUCCESS; } /* Clean up a lease object, deallocate all its parts, and set it to NULL. */ void dhc6_lease_destroy(struct dhc6_lease **src, const char *file, int line) { struct dhc6_ia *ia, *nia; struct dhc6_lease *lease; if (src == NULL || *src == NULL) { log_error("Attempt to destroy null lease."); return; } lease = *src; if (lease->server_id.len != 0) data_string_forget(&lease->server_id, file, line); for (ia = lease->bindings ; ia != NULL ; ia = nia) { nia = ia->next; dhc6_ia_destroy(&ia, file, line); } if (lease->options != NULL) option_state_dereference(&lease->options, file, line); dfree(lease, file, line); *src = NULL; } /* * Traverse the addresses list, and destroy their contents, and NULL the * list pointer. */ static void dhc6_ia_destroy(struct dhc6_ia **src, const char *file, int line) { struct dhc6_addr *addr, *naddr; struct dhc6_ia *ia; if (src == NULL || *src == NULL) { log_error("Attempt to destroy null IA."); return; } ia = *src; for (addr = ia->addrs ; addr != NULL ; addr = naddr) { naddr = addr->next; if (addr->options != NULL) option_state_dereference(&addr->options, file, line); dfree(addr, file, line); } if (ia->options != NULL) option_state_dereference(&ia->options, file, line); dfree(ia, file, line); *src = NULL; } /* * For a given lease, insert it into the tail of the lease list. Upon * finding a duplicate by server id, remove it and take over its position. */ static void insert_lease(struct dhc6_lease **head, struct dhc6_lease *new) { while (*head != NULL) { if ((*head)->server_id.len == new->server_id.len && memcmp((*head)->server_id.data, new->server_id.data, new->server_id.len) == 0) { new->next = (*head)->next; dhc6_lease_destroy(head, MDL); break; } head= &(*head)->next; } *head = new; return; } /* * Not really clear what to do here yet. */ static int dhc6_score_lease(struct client_state *client, struct dhc6_lease *lease) { struct dhc6_ia *ia; struct dhc6_addr *addr; struct option **req; int i; if (lease->score) return lease->score; lease->score = 1; /* If this lease lacks a required option, dump it. */ /* XXX: we should be able to cache the failure... */ req = client->config->required_options; if (req != NULL) { for (i = 0 ; req[i] != NULL ; i++) { if (lookup_option(&dhcpv6_universe, lease->options, req[i]->code) == NULL) { lease->score = 0; return lease->score; } } } /* If this lease contains a requested option, improve its score. */ req = client->config->requested_options; if (req != NULL) { for (i = 0 ; req[i] != NULL ; i++) { if (lookup_option(&dhcpv6_universe, lease->options, req[i]->code) != NULL) lease->score++; } } for (ia = lease->bindings ; ia != NULL ; ia = ia->next) { lease->score += 50; for (addr = ia->addrs ; addr != NULL ; addr = addr->next) { lease->score += 100; } } return lease->score; } /* * start_init6() kicks off the process, transmitting a packet and * scheduling a retransmission event. */ void start_init6(struct client_state *client) { struct timeval tv; log_debug("PRC: Soliciting for leases (INIT)."); client->state = S_INIT; /* Initialize timers, RFC3315 section 17.1.2. */ client->IRT = SOL_TIMEOUT * 100; client->MRT = SOL_MAX_RT * 100; client->MRC = 0; /* Default is 0 (no max) but -1 changes this. */ if (!onetry) client->MRD = 0; else client->MRD = client->config->timeout; dhc6_retrans_init(client); /* * RFC3315 section 17.1.2 goes out of its way: * Also, the first RT MUST be selected to be strictly greater than IRT * by choosing RAND to be strictly greater than 0. */ /* if RAND < 0 then RAND = -RAND */ if (client->RT <= client->IRT) client->RT = client->IRT + (client->IRT - client->RT); /* if RAND == 0 then RAND = 1 */ if (client->RT <= client->IRT) client->RT = client->IRT + 1; client->v6_handler = init_handler; /* * RFC3315 section 17.1.2 says we MUST start the first packet * between 0 and SOL_MAX_DELAY seconds. The good news is * SOL_MAX_DELAY is 1. */ tv.tv_sec = cur_tv.tv_sec; tv.tv_usec = cur_tv.tv_usec; tv.tv_usec += (random() % (SOL_MAX_DELAY * 100)) * 10000; if (tv.tv_usec >= 1000000) { tv.tv_sec += 1; tv.tv_usec -= 1000000; } add_timeout(&tv, do_init6, client, NULL, NULL); if (nowait) go_daemon(); } /* * start_info_request6() kicks off the process, transmitting an info * request packet and scheduling a retransmission event. */ void start_info_request6(struct client_state *client) { struct timeval tv; log_debug("PRC: Requesting information (INIT)."); client->state = S_INIT; /* Initialize timers, RFC3315 section 18.1.5. */ client->IRT = INF_TIMEOUT * 100; client->MRT = INF_MAX_RT * 100; client->MRC = 0; /* Default is 0 (no max) but -1 changes this. */ if (!onetry) client->MRD = 0; else client->MRD = client->config->timeout; dhc6_retrans_init(client); client->v6_handler = info_request_handler; /* * RFC3315 section 18.1.5 says we MUST start the first packet * between 0 and INF_MAX_DELAY seconds. The good news is * INF_MAX_DELAY is 1. */ tv.tv_sec = cur_tv.tv_sec; tv.tv_usec = cur_tv.tv_usec; tv.tv_usec += (random() % (INF_MAX_DELAY * 100)) * 10000; if (tv.tv_usec >= 1000000) { tv.tv_sec += 1; tv.tv_usec -= 1000000; } add_timeout(&tv, do_info_request6, client, NULL, NULL); if (nowait) go_daemon(); } /* * start_confirm6() kicks off an "init-reboot" version of the process, at * startup to find out if old bindings are 'fair' and at runtime whenever * a link cycles state we'll eventually want to do this. */ void start_confirm6(struct client_state *client) { struct timeval tv; /* If there is no active lease, there is nothing to check. */ if ((client->active_lease == NULL) || !active_prefix(client) || client->active_lease->released) { start_init6(client); return; } log_debug("PRC: Confirming active lease (INIT-REBOOT)."); client->state = S_REBOOTING; /* Initialize timers, RFC3315 section 17.1.3. */ client->IRT = CNF_TIMEOUT * 100; client->MRT = CNF_MAX_RT * 100; client->MRC = 0; client->MRD = CNF_MAX_RD; dhc6_retrans_init(client); client->v6_handler = reply_handler; /* * RFC3315 section 18.1.2 says we MUST start the first packet * between 0 and CNF_MAX_DELAY seconds. The good news is * CNF_MAX_DELAY is 1. */ tv.tv_sec = cur_tv.tv_sec; tv.tv_usec = cur_tv.tv_usec; tv.tv_usec += (random() % (CNF_MAX_DELAY * 100)) * 10000; if (tv.tv_usec >= 1000000) { tv.tv_sec += 1; tv.tv_usec -= 1000000; } if (wanted_ia_pd != 0) { client->state = S_REBINDING; client->refresh_type = DHCPV6_REBIND; add_timeout(&tv, do_refresh6, client, NULL, NULL); } else add_timeout(&tv, do_confirm6, client, NULL, NULL); } /* * check_timing6() check on the timing for sending a v6 message * and then do the basic initialization for a v6 message. */ #define CHK_TIM_SUCCESS 0 #define CHK_TIM_MRC_EXCEEDED 1 #define CHK_TIM_MRD_EXCEEDED 2 #define CHK_TIM_ALLOC_FAILURE 3 int check_timing6 (struct client_state *client, u_int8_t msg_type, char *msg_str, struct dhc6_lease *lease, struct data_string *ds) { struct timeval elapsed; /* * Start_time starts at the first transmission. */ if (client->txcount == 0) { client->start_time.tv_sec = cur_tv.tv_sec; client->start_time.tv_usec = cur_tv.tv_usec; } else if ((client->MRC != 0) && (client->txcount > client->MRC)) { log_info("Max retransmission count exceeded."); return(CHK_TIM_MRC_EXCEEDED); } /* elapsed = cur - start */ elapsed.tv_sec = cur_tv.tv_sec - client->start_time.tv_sec; elapsed.tv_usec = cur_tv.tv_usec - client->start_time.tv_usec; if (elapsed.tv_usec < 0) { elapsed.tv_sec -= 1; elapsed.tv_usec += 1000000; } /* Check if finished (-1 argument). */ if ((client->MRD != 0) && (elapsed.tv_sec > client->MRD)) { log_info("Max retransmission duration exceeded."); return(CHK_TIM_MRD_EXCEEDED); } memset(ds, 0, sizeof(*ds)); if (!buffer_allocate(&(ds->buffer), 4, MDL)) { log_error("Unable to allocate memory for %s.", msg_str); return(CHK_TIM_ALLOC_FAILURE); } ds->data = ds->buffer->data; ds->len = 4; ds->buffer->data[0] = msg_type; memcpy(ds->buffer->data + 1, client->dhcpv6_transaction_id, 3); /* Form an elapsed option. */ /* Maximum value is 65535 1/100s coded as 0xffff. */ if ((elapsed.tv_sec < 0) || (elapsed.tv_sec > 655) || ((elapsed.tv_sec == 655) && (elapsed.tv_usec > 350000))) { client->elapsed = 0xffff; } else { client->elapsed = elapsed.tv_sec * 100; client->elapsed += elapsed.tv_usec / 10000; } if (client->elapsed == 0) log_debug("XMT: Forming %s, 0 ms elapsed.", msg_str); else log_debug("XMT: Forming %s, %u0 ms elapsed.", msg_str, (unsigned)client->elapsed); client->elapsed = htons(client->elapsed); make_client6_options(client, &client->sent_options, lease, msg_type); return(CHK_TIM_SUCCESS); } /* * do_init6() marshals and transmits a solicit. */ void do_init6(void *input) { struct client_state *client; struct dhc6_ia *old_ia; struct dhc6_addr *old_addr; struct data_string ds; struct data_string ia; struct data_string addr; struct timeval tv; u_int32_t t1, t2; int i, idx, len, send_ret; client = input; /* * In RFC3315 section 17.1.2, the retransmission timer is * used as the selecting timer. */ if (client->advertised_leases != NULL) { start_selecting6(client); return; } switch(check_timing6(client, DHCPV6_SOLICIT, "Solicit", NULL, &ds)) { case CHK_TIM_MRC_EXCEEDED: case CHK_TIM_ALLOC_FAILURE: return; case CHK_TIM_MRD_EXCEEDED: client->state = S_STOPPED; if (client->active_lease != NULL) { dhc6_lease_destroy(&client->active_lease, MDL); client->active_lease = NULL; } /* Stop if and only if this is the last client. */ if (stopping_finished()) exit(2); return; } /* * Fetch any configured 'sent' options (includes DUID) in wire format. */ dhcpv6_universe.encapsulate(&ds, NULL, NULL, client, NULL, client->sent_options, &global_scope, &dhcpv6_universe); /* Use a specific handler with rapid-commit. */ if (lookup_option(&dhcpv6_universe, client->sent_options, D6O_RAPID_COMMIT) != NULL) { client->v6_handler = rapid_commit_handler; } /* Append IA_NA. */ for (i = 0; i < wanted_ia_na; i++) { /* * XXX: maybe the IA_NA('s) should be put into the sent_options * cache. They'd have to be pulled down as they also contain * different option caches in the same universe... */ memset(&ia, 0, sizeof(ia)); if (!buffer_allocate(&ia.buffer, 12, MDL)) { log_error("Unable to allocate memory for IA_NA."); data_string_forget(&ds, MDL); return; } ia.data = ia.buffer->data; ia.len = 12; /* * A simple IAID is the last 4 bytes * of the hardware address. */ if (client->interface->hw_address.hlen > 4) { idx = client->interface->hw_address.hlen - 4; len = 4; } else { idx = 0; len = client->interface->hw_address.hlen; } memcpy(ia.buffer->data, client->interface->hw_address.hbuf + idx, len); if (i) ia.buffer->data[3] += i; t1 = client->config->requested_lease / 2; t2 = t1 + (t1 / 2); putULong(ia.buffer->data + 4, t1); putULong(ia.buffer->data + 8, t2); log_debug("XMT: X-- IA_NA %s", print_hex_1(4, ia.buffer->data, 55)); log_debug("XMT: | X-- Request renew in +%u", (unsigned)t1); log_debug("XMT: | X-- Request rebind in +%u", (unsigned)t2); if ((client->active_lease != NULL) && ((old_ia = find_ia(client->active_lease->bindings, D6O_IA_NA, (char *)ia.buffer->data)) != NULL)) { /* * For each address in the old IA_NA, * request a binding. */ memset(&addr, 0, sizeof(addr)); for (old_addr = old_ia->addrs ; old_addr != NULL ; old_addr = old_addr->next) { if (old_addr->address.len != 16) { log_error("Invalid IPv6 address " "length %d. " "Ignoring. (%s:%d)", old_addr->address.len, MDL); continue; } if (!buffer_allocate(&addr.buffer, 24, MDL)) { log_error("Unable to allocate memory " "for IAADDR."); data_string_forget(&ia, MDL); data_string_forget(&ds, MDL); return; } addr.data = addr.buffer->data; addr.len = 24; memcpy(addr.buffer->data, old_addr->address.iabuf, 16); t1 = client->config->requested_lease; t2 = t1 + (t1 / 2); putULong(addr.buffer->data + 16, t1); putULong(addr.buffer->data + 20, t2); log_debug("XMT: | X-- Request address %s.", piaddr(old_addr->address)); log_debug("XMT: | | X-- Request " "preferred in +%u", (unsigned)t1); log_debug("XMT: | | X-- Request valid " "in +%u", (unsigned)t2); append_option(&ia, &dhcpv6_universe, iaaddr_option, &addr); data_string_forget(&addr, MDL); } } append_option(&ds, &dhcpv6_universe, ia_na_option, &ia); data_string_forget(&ia, MDL); } /* Append IA_TA. */ for (i = 0; i < wanted_ia_ta; i++) { /* * XXX: maybe the IA_TA('s) should be put into the sent_options * cache. They'd have to be pulled down as they also contain * different option caches in the same universe... */ memset(&ia, 0, sizeof(ia)); if (!buffer_allocate(&ia.buffer, 4, MDL)) { log_error("Unable to allocate memory for IA_TA."); data_string_forget(&ds, MDL); return; } ia.data = ia.buffer->data; ia.len = 4; /* * A simple IAID is the last 4 bytes * of the hardware address. */ if (client->interface->hw_address.hlen > 4) { idx = client->interface->hw_address.hlen - 4; len = 4; } else { idx = 0; len = client->interface->hw_address.hlen; } memcpy(ia.buffer->data, client->interface->hw_address.hbuf + idx, len); if (i) ia.buffer->data[3] += i; log_debug("XMT: X-- IA_TA %s", print_hex_1(4, ia.buffer->data, 55)); if ((client->active_lease != NULL) && ((old_ia = find_ia(client->active_lease->bindings, D6O_IA_TA, (char *)ia.buffer->data)) != NULL)) { /* * For each address in the old IA_TA, * request a binding. */ memset(&addr, 0, sizeof(addr)); for (old_addr = old_ia->addrs ; old_addr != NULL ; old_addr = old_addr->next) { if (old_addr->address.len != 16) { log_error("Invalid IPv6 address " "length %d. " "Ignoring. (%s:%d)", old_addr->address.len, MDL); continue; } if (!buffer_allocate(&addr.buffer, 24, MDL)) { log_error("Unable to allocate memory " "for IAADDR."); data_string_forget(&ia, MDL); data_string_forget(&ds, MDL); return; } addr.data = addr.buffer->data; addr.len = 24; memcpy(addr.buffer->data, old_addr->address.iabuf, 16); t1 = client->config->requested_lease; t2 = t1 + (t1 / 2); putULong(addr.buffer->data + 16, t1); putULong(addr.buffer->data + 20, t2); log_debug("XMT: | X-- Request address %s.", piaddr(old_addr->address)); log_debug("XMT: | | X-- Request " "preferred in +%u", (unsigned)t1); log_debug("XMT: | | X-- Request valid " "in +%u", (unsigned)t2); append_option(&ia, &dhcpv6_universe, iaaddr_option, &addr); data_string_forget(&addr, MDL); } } append_option(&ds, &dhcpv6_universe, ia_ta_option, &ia); data_string_forget(&ia, MDL); } /* Append IA_PD. */ for (i = 0; i < wanted_ia_pd; i++) { /* * XXX: maybe the IA_PD('s) should be put into the sent_options * cache. They'd have to be pulled down as they also contain * different option caches in the same universe... */ memset(&ia, 0, sizeof(ia)); if (!buffer_allocate(&ia.buffer, 12, MDL)) { log_error("Unable to allocate memory for IA_PD."); data_string_forget(&ds, MDL); return; } ia.data = ia.buffer->data; ia.len = 12; /* * A simple IAID is the last 4 bytes * of the hardware address. */ if (client->interface->hw_address.hlen > 4) { idx = client->interface->hw_address.hlen - 4; len = 4; } else { idx = 0; len = client->interface->hw_address.hlen; } memcpy(ia.buffer->data, client->interface->hw_address.hbuf + idx, len); if (i) ia.buffer->data[3] += i; t1 = client->config->requested_lease / 2; t2 = t1 + (t1 / 2); putULong(ia.buffer->data + 4, t1); putULong(ia.buffer->data + 8, t2); log_debug("XMT: X-- IA_PD %s", print_hex_1(4, ia.buffer->data, 55)); log_debug("XMT: | X-- Request renew in +%u", (unsigned)t1); log_debug("XMT: | X-- Request rebind in +%u", (unsigned)t2); if ((client->active_lease != NULL) && ((old_ia = find_ia(client->active_lease->bindings, D6O_IA_PD, (char *)ia.buffer->data)) != NULL)) { /* * For each prefix in the old IA_PD, * request a binding. */ memset(&addr, 0, sizeof(addr)); for (old_addr = old_ia->addrs ; old_addr != NULL ; old_addr = old_addr->next) { if (old_addr->address.len != 16) { log_error("Invalid IPv6 prefix, " "Ignoring. (%s:%d)", MDL); continue; } if (!buffer_allocate(&addr.buffer, 25, MDL)) { log_error("Unable to allocate memory " "for IAPREFIX."); data_string_forget(&ia, MDL); data_string_forget(&ds, MDL); return; } addr.data = addr.buffer->data; addr.len = 25; t1 = client->config->requested_lease; t2 = t1 + (t1 / 2); putULong(addr.buffer->data, t1); putULong(addr.buffer->data + 4, t2); putUChar(addr.buffer->data + 8, old_addr->plen); memcpy(addr.buffer->data + 9, old_addr->address.iabuf, 16); log_debug("XMT: | X-- Request prefix %s/%u.", piaddr(old_addr->address), (unsigned) old_addr->plen); log_debug("XMT: | | X-- Request " "preferred in +%u", (unsigned)t1); log_debug("XMT: | | X-- Request valid " "in +%u", (unsigned)t2); append_option(&ia, &dhcpv6_universe, iaprefix_option, &addr); data_string_forget(&addr, MDL); } } append_option(&ds, &dhcpv6_universe, ia_pd_option, &ia); data_string_forget(&ia, MDL); } /* Transmit and wait. */ log_info("XMT: Solicit on %s, interval %ld0ms.", client->name ? client->name : client->interface->name, (long int)client->RT); send_ret = send_packet6(client->interface, ds.data, ds.len, &DHCPv6DestAddr); if (send_ret != ds.len) { log_error("dhc6: send_packet6() sent %d of %d bytes", send_ret, ds.len); } data_string_forget(&ds, MDL); /* Wait RT */ tv.tv_sec = cur_tv.tv_sec + client->RT / 100; tv.tv_usec = cur_tv.tv_usec + (client->RT % 100) * 10000; if (tv.tv_usec >= 1000000) { tv.tv_sec += 1; tv.tv_usec -= 1000000; } add_timeout(&tv, do_init6, client, NULL, NULL); dhc6_retrans_advance(client); } /* do_info_request6() marshals and transmits an information-request. */ void do_info_request6(void *input) { struct client_state *client; struct data_string ds; struct timeval tv; int send_ret; client = input; switch(check_timing6(client, DHCPV6_INFORMATION_REQUEST, "Info-Request", NULL, &ds)) { case CHK_TIM_MRC_EXCEEDED: case CHK_TIM_ALLOC_FAILURE: return; case CHK_TIM_MRD_EXCEEDED: exit(2); case CHK_TIM_SUCCESS: break; } /* Fetch any configured 'sent' options (includes DUID) in wire format. */ dhcpv6_universe.encapsulate(&ds, NULL, NULL, client, NULL, client->sent_options, &global_scope, &dhcpv6_universe); /* Transmit and wait. */ log_info("XMT: Info-Request on %s, interval %ld0ms.", client->name ? client->name : client->interface->name, (long int)client->RT); send_ret = send_packet6(client->interface, ds.data, ds.len, &DHCPv6DestAddr); if (send_ret != ds.len) { log_error("dhc6: send_packet6() sent %d of %d bytes", send_ret, ds.len); } data_string_forget(&ds, MDL); /* Wait RT */ tv.tv_sec = cur_tv.tv_sec + client->RT / 100; tv.tv_usec = cur_tv.tv_usec + (client->RT % 100) * 10000; if (tv.tv_usec >= 1000000) { tv.tv_sec += 1; tv.tv_usec -= 1000000; } add_timeout(&tv, do_info_request6, client, NULL, NULL); dhc6_retrans_advance(client); } /* do_confirm6() creates a Confirm packet and transmits it. This function * is called on every timeout to (re)transmit. */ void do_confirm6(void *input) { struct client_state *client; struct data_string ds; int send_ret; struct timeval tv; client = input; if (client->active_lease == NULL) log_fatal("Impossible condition at %s:%d.", MDL); /* In section 17.1.3, it is said: * * If the client receives no responses before the message * transmission process terminates, as described in section 14, * the client SHOULD continue to use any IP addresses, using the * last known lifetimes for those addresses, and SHOULD continue * to use any other previously obtained configuration parameters. * * So if confirm times out, we go active. * * XXX: Should we reduce all IA's t1 to 0, so that we renew and * stick there until we get a reply? */ switch(check_timing6(client, DHCPV6_CONFIRM, "Confirm", client->active_lease, &ds)) { case CHK_TIM_MRC_EXCEEDED: case CHK_TIM_MRD_EXCEEDED: start_bound(client); return; case CHK_TIM_ALLOC_FAILURE: return; case CHK_TIM_SUCCESS: break; } /* Fetch any configured 'sent' options (includes DUID') in wire format. */ dhcpv6_universe.encapsulate(&ds, NULL, NULL, client, NULL, client->sent_options, &global_scope, &dhcpv6_universe); /* Append IA's. */ if (wanted_ia_na && dhc6_add_ia_na(client, &ds, client->active_lease, DHCPV6_CONFIRM) != ISC_R_SUCCESS) { data_string_forget(&ds, MDL); return; } if (wanted_ia_ta && dhc6_add_ia_ta(client, &ds, client->active_lease, DHCPV6_CONFIRM) != ISC_R_SUCCESS) { data_string_forget(&ds, MDL); return; } /* Transmit and wait. */ log_info("XMT: Confirm on %s, interval %ld0ms.", client->name ? client->name : client->interface->name, (long int)client->RT); send_ret = send_packet6(client->interface, ds.data, ds.len, &DHCPv6DestAddr); if (send_ret != ds.len) { log_error("dhc6: sendpacket6() sent %d of %d bytes", send_ret, ds.len); } data_string_forget(&ds, MDL); /* Wait RT */ tv.tv_sec = cur_tv.tv_sec + client->RT / 100; tv.tv_usec = cur_tv.tv_usec + (client->RT % 100) * 10000; if (tv.tv_usec >= 1000000) { tv.tv_sec += 1; tv.tv_usec -= 1000000; } add_timeout(&tv, do_confirm6, client, NULL, NULL); dhc6_retrans_advance(client); } /* * Release addresses. */ void start_release6(struct client_state *client) { /* Cancel any pending transmissions */ cancel_timeout(do_confirm6, client); cancel_timeout(do_select6, client); cancel_timeout(do_refresh6, client); cancel_timeout(do_release6, client); client->state = S_STOPPED; /* * It is written: "The client MUST NOT use any of the addresses it * is releasing as the source address in the Release message or in * any subsequently transmitted message." So unconfigure now. */ unconfigure6(client, "RELEASE6"); /* Note this in the lease file. */ if (client->active_lease == NULL) return; client->active_lease->released = ISC_TRUE; write_client6_lease(client, client->active_lease, 0, 1); /* Set timers per RFC3315 section 18.1.6. */ client->IRT = REL_TIMEOUT * 100; client->MRT = 0; client->MRC = REL_MAX_RC; client->MRD = 0; dhc6_retrans_init(client); client->v6_handler = reply_handler; do_release6(client); } /* * do_release6() creates a Release packet and transmits it. */ static void do_release6(void *input) { struct client_state *client; struct data_string ds; int send_ret; struct timeval tv; client = input; if ((client->active_lease == NULL) || !active_prefix(client)) return; switch(check_timing6(client, DHCPV6_RELEASE, "Release", client->active_lease, &ds)) { case CHK_TIM_MRC_EXCEEDED: case CHK_TIM_ALLOC_FAILURE: case CHK_TIM_MRD_EXCEEDED: goto release_done; case CHK_TIM_SUCCESS: break; } /* * Don't use unicast as we don't know if we still have an * available address with enough scope. */ dhcpv6_universe.encapsulate(&ds, NULL, NULL, client, NULL, client->sent_options, &global_scope, &dhcpv6_universe); /* Append IA's (but don't release temporary addresses). */ if (wanted_ia_na && dhc6_add_ia_na(client, &ds, client->active_lease, DHCPV6_RELEASE) != ISC_R_SUCCESS) { data_string_forget(&ds, MDL); goto release_done; } if (wanted_ia_pd && dhc6_add_ia_pd(client, &ds, client->active_lease, DHCPV6_RELEASE) != ISC_R_SUCCESS) { data_string_forget(&ds, MDL); goto release_done; } /* Transmit and wait. */ log_info("XMT: Release on %s, interval %ld0ms.", client->name ? client->name : client->interface->name, (long int)client->RT); send_ret = send_packet6(client->interface, ds.data, ds.len, &DHCPv6DestAddr); if (send_ret != ds.len) { log_error("dhc6: sendpacket6() sent %d of %d bytes", send_ret, ds.len); } data_string_forget(&ds, MDL); /* Wait RT */ tv.tv_sec = cur_tv.tv_sec + client->RT / 100; tv.tv_usec = cur_tv.tv_usec + (client->RT % 100) * 10000; if (tv.tv_usec >= 1000000) { tv.tv_sec += 1; tv.tv_usec -= 1000000; } add_timeout(&tv, do_release6, client, NULL, NULL); dhc6_retrans_advance(client); return; release_done: dhc6_lease_destroy(&client->active_lease, MDL); client->active_lease = NULL; if (stopping_finished()) exit(0); } /* status_log() just puts a status code into displayable form and logs it * to info level. */ static void status_log(int code, const char *scope, const char *additional, int len) { const char *msg = NULL; switch(code) { case STATUS_Success: msg = "Success"; break; case STATUS_UnspecFail: msg = "UnspecFail"; break; case STATUS_NoAddrsAvail: msg = "NoAddrsAvail"; break; case STATUS_NoBinding: msg = "NoBinding"; break; case STATUS_NotOnLink: msg = "NotOnLink"; break; case STATUS_UseMulticast: msg = "UseMulticast"; break; case STATUS_NoPrefixAvail: msg = "NoPrefixAvail"; break; default: msg = "UNKNOWN"; break; } if (len > 0) log_info("%s status code %s: %s", scope, msg, print_hex_1(len, (const unsigned char *)additional, 50)); else log_info("%s status code %s.", scope, msg); } /* Acquire a status code. */ static isc_result_t dhc6_get_status_code(struct option_state *options, unsigned *code, struct data_string *msg) { struct option_cache *oc; struct data_string ds; isc_result_t rval = ISC_R_SUCCESS; if ((options == NULL) || (code == NULL)) return DHCP_R_INVALIDARG; if ((msg != NULL) && (msg->len != 0)) return DHCP_R_INVALIDARG; memset(&ds, 0, sizeof(ds)); /* Assume success if there is no option. */ *code = STATUS_Success; oc = lookup_option(&dhcpv6_universe, options, D6O_STATUS_CODE); if ((oc != NULL) && evaluate_option_cache(&ds, NULL, NULL, NULL, options, NULL, &global_scope, oc, MDL)) { if (ds.len < 2) { log_error("Invalid status code length %d.", ds.len); rval = DHCP_R_FORMERR; } else *code = getUShort(ds.data); if ((msg != NULL) && (ds.len > 2)) { data_string_copy(msg, &ds, MDL); msg->data += 2; msg->len -= 2; } data_string_forget(&ds, MDL); return rval; } return ISC_R_NOTFOUND; } /* Look at status codes in an advertise, and reform the return value. */ static isc_result_t dhc6_check_status(isc_result_t rval, struct option_state *options, const char *scope, unsigned *code) { struct data_string msg; isc_result_t status; if ((scope == NULL) || (code == NULL)) return DHCP_R_INVALIDARG; /* If we don't find a code, we assume success. */ *code = STATUS_Success; /* If there is no options cache, then there is no code. */ if (options != NULL) { memset(&msg, 0, sizeof(msg)); status = dhc6_get_status_code(options, code, &msg); if (status == ISC_R_SUCCESS) { status_log(*code, scope, (char *)msg.data, msg.len); data_string_forget(&msg, MDL); if (*code != STATUS_Success) rval = ISC_R_FAILURE; } else if (status != ISC_R_NOTFOUND) rval = status; } return rval; } /* Look in the packet, any IA's, and any IAADDR's within those IA's to find * status code options that are not SUCCESS. */ static isc_result_t dhc6_check_advertise(struct dhc6_lease *lease) { struct dhc6_ia *ia; struct dhc6_addr *addr; isc_result_t rval = ISC_R_SUCCESS; int have_addrs = ISC_FALSE; unsigned code; const char *scope; rval = dhc6_check_status(rval, lease->options, "message", &code); for (ia = lease->bindings ; ia != NULL ; ia = ia->next) { switch (ia->ia_type) { case D6O_IA_NA: scope = "IA_NA"; break; case D6O_IA_TA: scope = "IA_TA"; break; case D6O_IA_PD: scope = "IA_PD"; break; default: log_error("dhc6_check_advertise: no type."); return ISC_R_FAILURE; } rval = dhc6_check_status(rval, ia->options, scope, &code); for (addr = ia->addrs ; addr != NULL ; addr = addr->next) { if (ia->ia_type != D6O_IA_PD) scope = "IAADDR"; else scope = "IAPREFIX"; rval = dhc6_check_status(rval, addr->options, scope, &code); have_addrs = ISC_TRUE; } } if (have_addrs != ISC_TRUE) rval = ISC_R_ADDRNOTAVAIL; return rval; } /* status code <-> action matrix for the client in INIT state * (rapid/commit). Returns always false as no action is defined. */ static isc_boolean_t dhc6_init_action(struct client_state *client, isc_result_t *rvalp, unsigned code) { if (rvalp == NULL) log_fatal("Impossible condition at %s:%d.", MDL); if (client == NULL) { *rvalp = DHCP_R_INVALIDARG; return ISC_FALSE; } if (*rvalp == ISC_R_SUCCESS) return ISC_FALSE; /* No possible action in any case... */ return ISC_FALSE; } /* status code <-> action matrix for the client in SELECT state * (request/reply). Returns true if action was taken (and the * packet should be ignored), or false if no action was taken. */ static isc_boolean_t dhc6_select_action(struct client_state *client, isc_result_t *rvalp, unsigned code) { struct dhc6_lease *lease; isc_result_t rval; if (rvalp == NULL) log_fatal("Impossible condition at %s:%d.", MDL); if (client == NULL) { *rvalp = DHCP_R_INVALIDARG; return ISC_FALSE; } rval = *rvalp; if (rval == ISC_R_SUCCESS) return ISC_FALSE; switch (code) { /* We may have an earlier failure status code (so no * success rval), and a success code now. This * doesn't upgrade the rval to success, but it does * mean we take no action here. */ case STATUS_Success: /* Gimpy server, or possibly an attacker. */ case STATUS_NoBinding: case STATUS_UseMulticast: /* Take no action. */ return ISC_FALSE; /* If the server can't deal with us, either try the * next advertised server, or continue retrying if there * weren't any. */ default: case STATUS_UnspecFail: if (client->advertised_leases != NULL) { dhc6_lease_destroy(&client->selected_lease, MDL); client->selected_lease = NULL; start_selecting6(client); break; } else /* Take no action - continue to retry. */ return ISC_FALSE; /* If the server has no addresses, try other servers if * we got some, otherwise go to INIT to hope for more * servers. */ case STATUS_NoAddrsAvail: case STATUS_NoPrefixAvail: if (client->state == S_REBOOTING) return ISC_FALSE; if (client->selected_lease == NULL) log_fatal("Impossible case at %s:%d.", MDL); dhc6_lease_destroy(&client->selected_lease, MDL); client->selected_lease = NULL; if (client->advertised_leases != NULL) start_selecting6(client); else start_init6(client); break; /* If we got a NotOnLink from a Confirm, then we're not * on link. Kill the old-active binding and start over. * * If we got a NotOnLink from our Request, something weird * happened. Start over from scratch anyway. */ case STATUS_NotOnLink: if (client->state == S_REBOOTING) { if (client->active_lease == NULL) log_fatal("Impossible case at %s:%d.", MDL); dhc6_lease_destroy(&client->active_lease, MDL); } else { if (client->selected_lease == NULL) log_fatal("Impossible case at %s:%d.", MDL); dhc6_lease_destroy(&client->selected_lease, MDL); client->selected_lease = NULL; while (client->advertised_leases != NULL) { lease = client->advertised_leases; client->advertised_leases = lease->next; dhc6_lease_destroy(&lease, MDL); } } start_init6(client); break; } return ISC_TRUE; } static void dhc6_withdraw_lease(struct client_state *client) { struct dhc6_ia *ia; struct dhc6_addr *addr; if ((client == NULL) || (client->active_lease == NULL)) return; for (ia = client->active_lease->bindings ; ia != NULL ; ia = ia->next) { for (addr = ia->addrs ; addr != NULL ; addr = addr->next) { addr->max_life = addr->preferred_life = 0; } } /* Perform expiry. */ do_expire(client); } /* status code <-> action matrix for the client in BOUND state * (request/reply). Returns true if action was taken (and the * packet should be ignored), or false if no action was taken. */ static isc_boolean_t dhc6_reply_action(struct client_state *client, isc_result_t *rvalp, unsigned code) { isc_result_t rval; if (rvalp == NULL) log_fatal("Impossible condition at %s:%d.", MDL); if (client == NULL) { *rvalp = DHCP_R_INVALIDARG; return ISC_FALSE; } rval = *rvalp; if (rval == ISC_R_SUCCESS) return ISC_FALSE; switch (code) { /* It's possible an earlier status code set rval to a failure * code, and we've encountered a later success. */ case STATUS_Success: /* In "refreshes" (where we get replies), we probably * still have a valid lease. So "take no action" and * the upper levels will keep retrying until the lease * expires (or we rebind). */ case STATUS_UnspecFail: /* For unknown codes...it's a soft (retryable) error. */ default: return ISC_FALSE; /* The server is telling us to use a multicast address, so * we have to delete the unicast option from the active * lease, then allow retransmission to occur normally. * (XXX: It might be preferable in this case to retransmit * sooner than the current interval, but for now we don't.) */ case STATUS_UseMulticast: if (client->active_lease != NULL) delete_option(&dhcp_universe, client->active_lease->options, D6O_UNICAST); return ISC_FALSE; /* "When the client receives a NotOnLink status from the * server in response to a Request, the client can either * re-issue the Request without specifying any addresses * or restart the DHCP server discovery process." * * This is strange. If competing server evaluation is * useful (and therefore in the protocol), then why would * a client's first reaction be to request from the same * server on a different link? Surely you'd want to * re-evaluate your server selection. * * Well, I guess that's the answer. */ case STATUS_NotOnLink: /* In this case, we need to rescind all current active * bindings (just 'expire' them all normally, if early). * They're no use to us on the wrong link. Then head back * to init, redo server selection and get new addresses. */ dhc6_withdraw_lease(client); break; /* "If the status code is NoAddrsAvail, the client has * received no usable addresses in the IA and may choose * to try obtaining addresses for the IA from another * server." */ case STATUS_NoAddrsAvail: case STATUS_NoPrefixAvail: /* Head back to init, keeping any active bindings (!). */ start_init6(client); break; /* - sends a Request message if the IA contained a Status * Code option with the NoBinding status (and does not * send any additional Renew/Rebind messages) */ case STATUS_NoBinding: if (client->advertised_leases != NULL) log_fatal("Impossible condition at %s:%d.", MDL); client->advertised_leases = dhc6_dup_lease(client->active_lease, MDL); start_selecting6(client); break; } return ISC_TRUE; } /* status code <-> action matrix for the client in STOPPED state * (release/decline). Returns true if action was taken (and the * packet should be ignored), or false if no action was taken. * NoBinding is translated into Success. */ static isc_boolean_t dhc6_stop_action(struct client_state *client, isc_result_t *rvalp, unsigned code) { isc_result_t rval; if (rvalp == NULL) log_fatal("Impossible condition at %s:%d.", MDL); if (client == NULL) { *rvalp = DHCP_R_INVALIDARG; return ISC_FALSE; } rval = *rvalp; if (rval == ISC_R_SUCCESS) return ISC_FALSE; switch (code) { /* It's possible an earlier status code set rval to a failure * code, and we've encountered a later success. */ case STATUS_Success: /* For unknown codes...it's a soft (retryable) error. */ case STATUS_UnspecFail: default: return ISC_FALSE; /* NoBinding is not an error */ case STATUS_NoBinding: if (rval == ISC_R_FAILURE) *rvalp = ISC_R_SUCCESS; return ISC_FALSE; /* Should not happen */ case STATUS_NoAddrsAvail: case STATUS_NoPrefixAvail: break; /* Give up on it */ case STATUS_NotOnLink: break; /* The server is telling us to use a multicast address, so * we have to delete the unicast option from the active * lease, then allow retransmission to occur normally. * (XXX: It might be preferable in this case to retransmit * sooner than the current interval, but for now we don't.) */ case STATUS_UseMulticast: if (client->active_lease != NULL) delete_option(&dhcp_universe, client->active_lease->options, D6O_UNICAST); return ISC_FALSE; } return ISC_TRUE; } /* Look at a new and old lease, and make sure the new information is not * losing us any state. */ static isc_result_t dhc6_check_reply(struct client_state *client, struct dhc6_lease *new) { isc_boolean_t (*action)(struct client_state *, isc_result_t *, unsigned); struct dhc6_ia *ia; struct dhc6_addr *addr; isc_result_t rval = ISC_R_SUCCESS; unsigned code; const char *scope; int nscore, sscore; if ((client == NULL) || (new == NULL)) return DHCP_R_INVALIDARG; switch (client->state) { case S_INIT: action = dhc6_init_action; break; case S_SELECTING: case S_REBOOTING: action = dhc6_select_action; break; case S_RENEWING: case S_REBINDING: action = dhc6_reply_action; break; case S_STOPPED: action = dhc6_stop_action; break; default: log_fatal("Impossible condition at %s:%d.", MDL); return ISC_R_CANCELED; } /* If there is a code to extract, and if there is some * action to take based on that code, then take the action * and do not continue. */ rval = dhc6_check_status(rval, new->options, "message", &code); if (action(client, &rval, code)) return ISC_R_CANCELED; for (ia = new->bindings ; ia != NULL ; ia = ia->next) { switch (ia->ia_type) { case D6O_IA_NA: scope = "IA_NA"; break; case D6O_IA_TA: scope = "IA_TA"; break; case D6O_IA_PD: scope = "IA_PD"; break; default: log_error("dhc6_check_reply: no type."); return DHCP_R_INVALIDARG; } rval = dhc6_check_status(rval, ia->options, scope, &code); if (action(client, &rval, code)) return ISC_R_CANCELED; for (addr = ia->addrs ; addr != NULL ; addr = addr->next) { if (ia->ia_type != D6O_IA_PD) scope = "IAADDR"; else scope = "IAPREFIX"; rval = dhc6_check_status(rval, addr->options, scope, &code); if (action(client, &rval, code)) return ISC_R_CANCELED; } } /* A Confirm->Reply is unsuitable for comparison to the old lease. */ if (client->state == S_REBOOTING) return rval; /* No old lease in rapid-commit. */ if (client->state == S_INIT) return rval; switch (client->state) { case S_SELECTING: /* Compare the new lease with the selected lease to make * sure there is no risky business. */ nscore = dhc6_score_lease(client, new); sscore = dhc6_score_lease(client, client->selected_lease); if ((client->advertised_leases != NULL) && (nscore < (sscore / 2))) { /* XXX: An attacker might reply this way to make * XXX: sure we latch onto their configuration. * XXX: We might want to ignore the packet and * XXX: schedule re-selection at the next timeout? */ log_error("PRC: BAIT AND SWITCH detected. Score of " "supplied lease (%d) is substantially " "smaller than the advertised score (%d). " "Trying other servers.", nscore, sscore); dhc6_lease_destroy(&client->selected_lease, MDL); client->selected_lease = NULL; start_selecting6(client); return ISC_R_CANCELED; } break; case S_RENEWING: case S_REBINDING: /* This leaves one RFC3315 status check unimplemented: * * - sends a Renew/Rebind if the IA is not in the Reply * message * * We rely on the scheduling system to note that the IA has * not left Renewal/Rebinding/whatever since it still carries * old times from the last successful binding. So this is * implemented actually, just not explicitly. */ break; case S_STOPPED: /* Nothing critical to do at this stage. */ break; default: log_fatal("REALLY impossible condition at %s:%d.", MDL); return ISC_R_CANCELED; } return rval; } /* While in init state, we only collect advertisements. If there happens * to be an advertisement with a preference option of 255, that's an * automatic exit. Otherwise, we collect advertisements until our timeout * expires (client->RT). */ void init_handler(struct packet *packet, struct client_state *client) { struct dhc6_lease *lease; /* In INIT state, we send solicits, we only expect to get * advertises (rapid commit has its own handler). */ if (packet->dhcpv6_msg_type != DHCPV6_ADVERTISE) return; /* RFC3315 section 15.3 validation (same as 15.10 since we * always include a client id). */ if (!valid_reply(packet, client)) { log_error("Invalid Advertise - rejecting."); return; } lease = dhc6_leaseify(packet); if (dhc6_check_advertise(lease) != ISC_R_SUCCESS) { log_debug("PRC: Lease failed to satisfy."); dhc6_lease_destroy(&lease, MDL); return; } insert_lease(&client->advertised_leases, lease); /* According to RFC3315 section 17.1.2, the client MUST wait for * the first RT before selecting a lease. But on the 400th RT, * we dont' want to wait the full timeout if we finally get an * advertise. We could probably wait a second, but ohwell, * RFC3315 doesn't say so. * * If the lease is highest possible preference, 255, RFC3315 claims * we should continue immediately even on the first RT. We probably * should not if the advertise contains less than one IA and address. */ if ((client->txcount > 1) || ((lease->pref == 255) && (dhc6_score_lease(client, lease) > 150))) { log_debug("RCV: Advertisement immediately selected."); cancel_timeout(do_init6, client); start_selecting6(client); } else log_debug("RCV: Advertisement recorded."); } /* info_request_handler() accepts a Reply to an Info-request. */ void info_request_handler(struct packet *packet, struct client_state *client) { isc_result_t check_status; unsigned code; if (packet->dhcpv6_msg_type != DHCPV6_REPLY) return; /* RFC3315 section 15.10 validation (same as 15.3 since we * always include a client id). */ if (!valid_reply(packet, client)) { log_error("Invalid Reply - rejecting."); return; } check_status = dhc6_check_status(ISC_R_SUCCESS, packet->options, "message", &code); if (check_status != ISC_R_SUCCESS) { /* If no action was taken, but there is an error, then * we wait for a retransmission. */ if (check_status != ISC_R_CANCELED) return; } /* We're done retransmitting at this point. */ cancel_timeout(do_info_request6, client); /* Action was taken, so now that we've torn down our scheduled * retransmissions, return. */ if (check_status == ISC_R_CANCELED) return; /* Cleanup if a previous attempt to go bound failed. */ if (client->old_lease != NULL) { dhc6_lease_destroy(&client->old_lease, MDL); client->old_lease = NULL; } /* Cache options in the active_lease. */ if (client->active_lease != NULL) client->old_lease = client->active_lease; client->active_lease = dmalloc(sizeof(struct dhc6_lease), MDL); if (client->active_lease == NULL) log_fatal("Out of memory for v6 lease structure."); option_state_reference(&client->active_lease->options, packet->options, MDL); start_informed(client); } /* Specific version of init_handler() for rapid-commit. */ void rapid_commit_handler(struct packet *packet, struct client_state *client) { struct dhc6_lease *lease; isc_result_t check_status; /* On ADVERTISE just fall back to the init_handler(). */ if (packet->dhcpv6_msg_type == DHCPV6_ADVERTISE) { init_handler(packet, client); return; } else if (packet->dhcpv6_msg_type != DHCPV6_REPLY) return; /* RFC3315 section 15.10 validation (same as 15.3 since we * always include a client id). */ if (!valid_reply(packet, client)) { log_error("Invalid Reply - rejecting."); return; } /* A rapid-commit option MUST be here. */ if (lookup_option(&dhcpv6_universe, packet->options, D6O_RAPID_COMMIT) == 0) { log_error("Reply without Rapid-Commit - rejecting."); return; } lease = dhc6_leaseify(packet); /* This is an out of memory condition...hopefully a temporary * problem. Returning now makes us try to retransmit later. */ if (lease == NULL) return; check_status = dhc6_check_reply(client, lease); if (check_status != ISC_R_SUCCESS) { dhc6_lease_destroy(&lease, MDL); return; } /* Jump to the selecting state. */ cancel_timeout(do_init6, client); client->state = S_SELECTING; /* Merge any bindings in the active lease (if there is one) into * the new active lease. */ dhc6_merge_lease(client->active_lease, lease); /* Cleanup if a previous attempt to go bound failed. */ if (client->old_lease != NULL) { dhc6_lease_destroy(&client->old_lease, MDL); client->old_lease = NULL; } /* Make this lease active and BIND to it. */ if (client->active_lease != NULL) client->old_lease = client->active_lease; client->active_lease = lease; /* We're done with the ADVERTISEd leases, if any. */ while(client->advertised_leases != NULL) { lease = client->advertised_leases; client->advertised_leases = lease->next; dhc6_lease_destroy(&lease, MDL); } start_bound(client); } /* Find the 'best' lease in the cache of advertised leases (usually). From * RFC3315 Section 17.1.3: * * Upon receipt of one or more valid Advertise messages, the client * selects one or more Advertise messages based upon the following * criteria. * * - Those Advertise messages with the highest server preference value * are preferred over all other Advertise messages. * * - Within a group of Advertise messages with the same server * preference value, a client MAY select those servers whose * Advertise messages advertise information of interest to the * client. For example, the client may choose a server that returned * an advertisement with configuration options of interest to the * client. * * - The client MAY choose a less-preferred server if that server has a * better set of advertised parameters, such as the available * addresses advertised in IAs. * * Note that the first and third contradict each other. The third should * probably be taken to mean that the client should prefer answers that * offer bindings, even if that violates the preference rule. * * The above also isn't deterministic where there are ties. So the final * tiebreaker we add, if all other values are equal, is to compare the * server identifiers and to select the numerically lower one. */ static struct dhc6_lease * dhc6_best_lease(struct client_state *client, struct dhc6_lease **head) { struct dhc6_lease **rpos, *rval, **candp, *cand; int cscore, rscore; if (head == NULL || *head == NULL) return NULL; rpos = head; rval = *rpos; rscore = dhc6_score_lease(client, rval); candp = &rval->next; cand = *candp; log_debug("PRC: Considering best lease."); log_debug("PRC: X-- Initial candidate %s (s: %d, p: %u).", print_hex_1(rval->server_id.len, rval->server_id.data, 48), rscore, (unsigned)rval->pref); for (; cand != NULL ; candp = &cand->next, cand = *candp) { cscore = dhc6_score_lease(client, cand); log_debug("PRC: X-- Candidate %s (s: %d, p: %u).", print_hex_1(cand->server_id.len, cand->server_id.data, 48), cscore, (unsigned)cand->pref); /* Above you'll find quoted RFC3315 Section 17.1.3. * * The third clause tells us to give up on leases that * have no bindings even if their preference is better. * So where our 'selected' lease's score is less than 150 * (1 ia + 1 addr), choose any candidate >= 150. * * The first clause tells us to make preference the primary * deciding factor. So if it's lower, reject, if it's * higher, select. * * The second clause tells us where the preference is * equal, we should use 'our judgement' of what we like * to see in an advertisement primarily. * * But there can still be a tie. To make this deterministic, * we compare the server identifiers and select the binary * lowest. * * Since server id's are unique in this list, there is * no further tie to break. */ if ((rscore < 150) && (cscore >= 150)) { log_debug("PRC: | X-- Selected, has bindings."); } else if (cand->pref < rval->pref) { log_debug("PRC: | X-- Rejected, lower preference."); continue; } else if (cand->pref > rval->pref) { log_debug("PRC: | X-- Selected, higher preference."); } else if (cscore > rscore) { log_debug("PRC: | X-- Selected, equal preference, " "higher score."); } else if (cscore < rscore) { log_debug("PRC: | X-- Rejected, equal preference, " "lower score."); continue; } else if ((cand->server_id.len < rval->server_id.len) || ((cand->server_id.len == rval->server_id.len) && (memcmp(cand->server_id.data, rval->server_id.data, cand->server_id.len) < 0))) { log_debug("PRC: | X-- Selected, equal preference, " "equal score, binary lesser server ID."); } else { log_debug("PRC: | X-- Rejected, equal preference, " "equal score, binary greater server ID."); continue; } rpos = candp; rval = cand; rscore = cscore; } /* Remove the selected lease from the chain. */ *rpos = rval->next; return rval; } /* Select a lease out of the advertised leases and setup state to try and * acquire that lease. */ void start_selecting6(struct client_state *client) { struct dhc6_lease *lease; if (client->advertised_leases == NULL) { log_error("Can not enter DHCPv6 SELECTING state with no " "leases to select from!"); return; } log_debug("PRC: Selecting best advertised lease."); client->state = S_SELECTING; lease = dhc6_best_lease(client, &client->advertised_leases); if (lease == NULL) log_fatal("Impossible error at %s:%d.", MDL); client->selected_lease = lease; /* Set timers per RFC3315 section 18.1.1. */ client->IRT = REQ_TIMEOUT * 100; client->MRT = REQ_MAX_RT * 100; client->MRC = REQ_MAX_RC; client->MRD = 0; dhc6_retrans_init(client); client->v6_handler = reply_handler; /* ("re")transmit the first packet. */ do_select6(client); } /* Transmit a Request to select a lease offered in Advertisements. In * the event of failure, either move on to the next-best advertised lease, * or head back to INIT state if there are none. */ void do_select6(void *input) { struct client_state *client; struct dhc6_lease *lease; struct data_string ds; struct timeval tv; int send_ret; client = input; /* 'lease' is fewer characters to type. */ lease = client->selected_lease; if (lease == NULL || lease->bindings == NULL) { log_error("Illegal to attempt selection without selecting " "a lease."); return; } switch(check_timing6(client, DHCPV6_REQUEST, "Request", lease, &ds)) { case CHK_TIM_MRC_EXCEEDED: case CHK_TIM_MRD_EXCEEDED: log_debug("PRC: Lease %s failed.", print_hex_1(lease->server_id.len, lease->server_id.data, 56)); /* Get rid of the lease that timed/counted out. */ dhc6_lease_destroy(&lease, MDL); client->selected_lease = NULL; /* If there are more leases great. If not, get more. */ if (client->advertised_leases != NULL) start_selecting6(client); else start_init6(client); return; case CHK_TIM_ALLOC_FAILURE: return; case CHK_TIM_SUCCESS: break; } /* Now make a packet that looks suspiciously like the one we * got from the server. But different. * * XXX: I guess IAID is supposed to be something the client * indicates and uses as a key to its internal state. It is * kind of odd to ask the server for IA's whose IAID the client * did not manufacture. We first need a formal dhclient.conf * construct for the iaid, then we can delve into this matter * more properly. In the time being, this will work. */ /* Fetch any configured 'sent' options (includes DUID) in wire format. */ dhcpv6_universe.encapsulate(&ds, NULL, NULL, client, NULL, client->sent_options, &global_scope, &dhcpv6_universe); /* Now append any IA's, and within them any IAADDR/IAPREFIXs. */ if (wanted_ia_na && dhc6_add_ia_na(client, &ds, lease, DHCPV6_REQUEST) != ISC_R_SUCCESS) { data_string_forget(&ds, MDL); return; } if (wanted_ia_ta && dhc6_add_ia_ta(client, &ds, lease, DHCPV6_REQUEST) != ISC_R_SUCCESS) { data_string_forget(&ds, MDL); return; } if (wanted_ia_pd && dhc6_add_ia_pd(client, &ds, lease, DHCPV6_REQUEST) != ISC_R_SUCCESS) { data_string_forget(&ds, MDL); return; } log_info("XMT: Request on %s, interval %ld0ms.", client->name ? client->name : client->interface->name, (long int)client->RT); send_ret = send_packet6(client->interface, ds.data, ds.len, &DHCPv6DestAddr); if (send_ret != ds.len) { log_error("dhc6: send_packet6() sent %d of %d bytes", send_ret, ds.len); } data_string_forget(&ds, MDL); /* Wait RT */ tv.tv_sec = cur_tv.tv_sec + client->RT / 100; tv.tv_usec = cur_tv.tv_usec + (client->RT % 100) * 10000; if (tv.tv_usec >= 1000000) { tv.tv_sec += 1; tv.tv_usec -= 1000000; } add_timeout(&tv, do_select6, client, NULL, NULL); dhc6_retrans_advance(client); } /* For each IA_NA in the lease, for each address in the IA_NA, * append that information onto the packet-so-far. */ static isc_result_t dhc6_add_ia_na(struct client_state *client, struct data_string *packet, struct dhc6_lease *lease, u_int8_t message) { struct data_string iads; struct data_string addrds; struct dhc6_addr *addr; struct dhc6_ia *ia; isc_result_t rval = ISC_R_SUCCESS; TIME t1, t2; memset(&iads, 0, sizeof(iads)); memset(&addrds, 0, sizeof(addrds)); for (ia = lease->bindings; ia != NULL && rval == ISC_R_SUCCESS; ia = ia->next) { if (ia->ia_type != D6O_IA_NA) continue; if (!buffer_allocate(&iads.buffer, 12, MDL)) { log_error("Unable to allocate memory for IA_NA."); rval = ISC_R_NOMEMORY; break; } /* Copy the IAID into the packet buffer. */ memcpy(iads.buffer->data, ia->iaid, 4); iads.data = iads.buffer->data; iads.len = 12; switch (message) { case DHCPV6_REQUEST: case DHCPV6_RENEW: case DHCPV6_REBIND: t1 = client->config->requested_lease / 2; t2 = t1 + (t1 / 2); #if MAX_TIME > 0xffffffff if (t1 > 0xffffffff) t1 = 0xffffffff; if (t2 > 0xffffffff) t2 = 0xffffffff; #endif putULong(iads.buffer->data + 4, t1); putULong(iads.buffer->data + 8, t2); log_debug("XMT: X-- IA_NA %s", print_hex_1(4, iads.data, 59)); log_debug("XMT: | X-- Requested renew +%u", (unsigned) t1); log_debug("XMT: | X-- Requested rebind +%u", (unsigned) t2); break; case DHCPV6_CONFIRM: case DHCPV6_RELEASE: case DHCPV6_DECLINE: /* Set t1 and t2 to zero; server will ignore them */ memset(iads.buffer->data + 4, 0, 8); log_debug("XMT: X-- IA_NA %s", print_hex_1(4, iads.buffer->data, 55)); break; default: log_fatal("Impossible condition at %s:%d.", MDL); } for (addr = ia->addrs ; addr != NULL ; addr = addr->next) { /* * Do not confirm expired addresses, do not request * expired addresses (but we keep them around for * solicit). */ if (addr->flags & DHC6_ADDR_EXPIRED) continue; if (addr->address.len != 16) { log_error("Illegal IPv6 address length (%d), " "ignoring. (%s:%d)", addr->address.len, MDL); continue; } if (!buffer_allocate(&addrds.buffer, 24, MDL)) { log_error("Unable to allocate memory for " "IAADDR."); rval = ISC_R_NOMEMORY; break; } addrds.data = addrds.buffer->data; addrds.len = 24; /* Copy the address into the packet buffer. */ memcpy(addrds.buffer->data, addr->address.iabuf, 16); /* Copy in additional information as appropriate */ switch (message) { case DHCPV6_REQUEST: case DHCPV6_RENEW: case DHCPV6_REBIND: t1 = client->config->requested_lease; t2 = t1 + 300; putULong(addrds.buffer->data + 16, t1); putULong(addrds.buffer->data + 20, t2); log_debug("XMT: | | X-- IAADDR %s", piaddr(addr->address)); log_debug("XMT: | | | X-- Preferred " "lifetime +%u", (unsigned)t1); log_debug("XMT: | | | X-- Max lifetime +%u", (unsigned)t2); break; case DHCPV6_CONFIRM: /* * Set preferred and max life to zero, * per 17.1.3. */ memset(addrds.buffer->data + 16, 0, 8); log_debug("XMT: | X-- Confirm Address %s", piaddr(addr->address)); break; case DHCPV6_RELEASE: /* Preferred and max life are irrelevant */ memset(addrds.buffer->data + 16, 0, 8); log_debug("XMT: | X-- Release Address %s", piaddr(addr->address)); break; case DHCPV6_DECLINE: /* Preferred and max life are irrelevant */ memset(addrds.buffer->data + 16, 0, 8); log_debug("XMT: | X-- Decline Address %s", piaddr(addr->address)); break; default: log_fatal("Impossible condition at %s:%d.", MDL); } append_option(&iads, &dhcpv6_universe, iaaddr_option, &addrds); data_string_forget(&addrds, MDL); } /* * It doesn't make sense to make a request without an * address. */ if (ia->addrs == NULL) { log_debug("!!!: V IA_NA has no IAADDRs - removed."); rval = ISC_R_FAILURE; } else if (rval == ISC_R_SUCCESS) { log_debug("XMT: V IA_NA appended."); append_option(packet, &dhcpv6_universe, ia_na_option, &iads); } data_string_forget(&iads, MDL); } return rval; } /* For each IA_TA in the lease, for each address in the IA_TA, * append that information onto the packet-so-far. */ static isc_result_t dhc6_add_ia_ta(struct client_state *client, struct data_string *packet, struct dhc6_lease *lease, u_int8_t message) { struct data_string iads; struct data_string addrds; struct dhc6_addr *addr; struct dhc6_ia *ia; isc_result_t rval = ISC_R_SUCCESS; TIME t1, t2; memset(&iads, 0, sizeof(iads)); memset(&addrds, 0, sizeof(addrds)); for (ia = lease->bindings; ia != NULL && rval == ISC_R_SUCCESS; ia = ia->next) { if (ia->ia_type != D6O_IA_TA) continue; if (!buffer_allocate(&iads.buffer, 4, MDL)) { log_error("Unable to allocate memory for IA_TA."); rval = ISC_R_NOMEMORY; break; } /* Copy the IAID into the packet buffer. */ memcpy(iads.buffer->data, ia->iaid, 4); iads.data = iads.buffer->data; iads.len = 4; log_debug("XMT: X-- IA_TA %s", print_hex_1(4, iads.buffer->data, 55)); for (addr = ia->addrs ; addr != NULL ; addr = addr->next) { /* * Do not confirm expired addresses, do not request * expired addresses (but we keep them around for * solicit). */ if (addr->flags & DHC6_ADDR_EXPIRED) continue; if (addr->address.len != 16) { log_error("Illegal IPv6 address length (%d), " "ignoring. (%s:%d)", addr->address.len, MDL); continue; } if (!buffer_allocate(&addrds.buffer, 24, MDL)) { log_error("Unable to allocate memory for " "IAADDR."); rval = ISC_R_NOMEMORY; break; } addrds.data = addrds.buffer->data; addrds.len = 24; /* Copy the address into the packet buffer. */ memcpy(addrds.buffer->data, addr->address.iabuf, 16); /* Copy in additional information as appropriate */ switch (message) { case DHCPV6_REQUEST: case DHCPV6_RENEW: case DHCPV6_REBIND: t1 = client->config->requested_lease; t2 = t1 + 300; putULong(addrds.buffer->data + 16, t1); putULong(addrds.buffer->data + 20, t2); log_debug("XMT: | | X-- IAADDR %s", piaddr(addr->address)); log_debug("XMT: | | | X-- Preferred " "lifetime +%u", (unsigned)t1); log_debug("XMT: | | | X-- Max lifetime +%u", (unsigned)t2); break; case DHCPV6_CONFIRM: /* * Set preferred and max life to zero, * per 17.1.3. */ memset(addrds.buffer->data + 16, 0, 8); log_debug("XMT: | X-- Confirm Address %s", piaddr(addr->address)); break; case DHCPV6_RELEASE: /* Preferred and max life are irrelevant */ memset(addrds.buffer->data + 16, 0, 8); log_debug("XMT: | X-- Release Address %s", piaddr(addr->address)); break; default: log_fatal("Impossible condition at %s:%d.", MDL); } append_option(&iads, &dhcpv6_universe, iaaddr_option, &addrds); data_string_forget(&addrds, MDL); } /* * It doesn't make sense to make a request without an * address. */ if (ia->addrs == NULL) { log_debug("!!!: V IA_TA has no IAADDRs - removed."); rval = ISC_R_FAILURE; } else if (rval == ISC_R_SUCCESS) { log_debug("XMT: V IA_TA appended."); append_option(packet, &dhcpv6_universe, ia_ta_option, &iads); } data_string_forget(&iads, MDL); } return rval; } /* For each IA_PD in the lease, for each prefix in the IA_PD, * append that information onto the packet-so-far. */ static isc_result_t dhc6_add_ia_pd(struct client_state *client, struct data_string *packet, struct dhc6_lease *lease, u_int8_t message) { struct data_string iads; struct data_string prefds; struct dhc6_addr *pref; struct dhc6_ia *ia; isc_result_t rval = ISC_R_SUCCESS; TIME t1, t2; memset(&iads, 0, sizeof(iads)); memset(&prefds, 0, sizeof(prefds)); for (ia = lease->bindings; ia != NULL && rval == ISC_R_SUCCESS; ia = ia->next) { if (ia->ia_type != D6O_IA_PD) continue; if (!buffer_allocate(&iads.buffer, 12, MDL)) { log_error("Unable to allocate memory for IA_PD."); rval = ISC_R_NOMEMORY; break; } /* Copy the IAID into the packet buffer. */ memcpy(iads.buffer->data, ia->iaid, 4); iads.data = iads.buffer->data; iads.len = 12; switch (message) { case DHCPV6_REQUEST: case DHCPV6_RENEW: case DHCPV6_REBIND: t1 = client->config->requested_lease / 2; t2 = t1 + (t1 / 2); #if MAX_TIME > 0xffffffff if (t1 > 0xffffffff) t1 = 0xffffffff; if (t2 > 0xffffffff) t2 = 0xffffffff; #endif putULong(iads.buffer->data + 4, t1); putULong(iads.buffer->data + 8, t2); log_debug("XMT: X-- IA_PD %s", print_hex_1(4, iads.data, 59)); log_debug("XMT: | X-- Requested renew +%u", (unsigned) t1); log_debug("XMT: | X-- Requested rebind +%u", (unsigned) t2); break; case DHCPV6_RELEASE: /* Set t1 and t2 to zero; server will ignore them */ memset(iads.buffer->data + 4, 0, 8); log_debug("XMT: X-- IA_PD %s", print_hex_1(4, iads.buffer->data, 55)); break; default: log_fatal("Impossible condition at %s:%d.", MDL); } for (pref = ia->addrs ; pref != NULL ; pref = pref->next) { /* * Do not confirm expired prefixes, do not request * expired prefixes (but we keep them around for * solicit). */ if (pref->flags & DHC6_ADDR_EXPIRED) continue; if (pref->address.len != 16) { log_error("Illegal IPv6 prefix " "ignoring. (%s:%d)", MDL); continue; } if (pref->plen == 0) { log_info("Null IPv6 prefix, " "ignoring. (%s:%d)", MDL); } if (!buffer_allocate(&prefds.buffer, 25, MDL)) { log_error("Unable to allocate memory for " "IAPREFIX."); rval = ISC_R_NOMEMORY; break; } prefds.data = prefds.buffer->data; prefds.len = 25; /* Copy the prefix into the packet buffer. */ putUChar(prefds.buffer->data + 8, pref->plen); memcpy(prefds.buffer->data + 9, pref->address.iabuf, 16); /* Copy in additional information as appropriate */ switch (message) { case DHCPV6_REQUEST: case DHCPV6_RENEW: case DHCPV6_REBIND: t1 = client->config->requested_lease; t2 = t1 + 300; putULong(prefds.buffer->data, t1); putULong(prefds.buffer->data + 4, t2); log_debug("XMT: | | X-- IAPREFIX %s/%u", piaddr(pref->address), (unsigned) pref->plen); log_debug("XMT: | | | X-- Preferred " "lifetime +%u", (unsigned)t1); log_debug("XMT: | | | X-- Max lifetime +%u", (unsigned)t2); break; case DHCPV6_RELEASE: /* Preferred and max life are irrelevant */ memset(prefds.buffer->data, 0, 8); log_debug("XMT: | X-- Release Prefix %s/%u", piaddr(pref->address), (unsigned) pref->plen); break; default: log_fatal("Impossible condition at %s:%d.", MDL); } append_option(&iads, &dhcpv6_universe, iaprefix_option, &prefds); data_string_forget(&prefds, MDL); } /* * It doesn't make sense to make a request without an * address. */ if (ia->addrs == NULL) { log_debug("!!!: V IA_PD has no IAPREFIXs - removed."); rval = ISC_R_FAILURE; } else if (rval == ISC_R_SUCCESS) { log_debug("XMT: V IA_PD appended."); append_option(packet, &dhcpv6_universe, ia_pd_option, &iads); } data_string_forget(&iads, MDL); } return rval; } /* stopping_finished() checks if there is a remaining work to do. */ static isc_boolean_t stopping_finished(void) { struct interface_info *ip; struct client_state *client; for (ip = interfaces; ip; ip = ip -> next) { for (client = ip -> client; client; client = client -> next) { if (client->state != S_STOPPED) return ISC_FALSE; if (client->active_lease != NULL) return ISC_FALSE; } } return ISC_TRUE; } /* reply_handler() accepts a Reply while we're attempting Select or Renew or * Rebind. Basically any Reply packet. */ void reply_handler(struct packet *packet, struct client_state *client) { struct dhc6_lease *lease; isc_result_t check_status; if (packet->dhcpv6_msg_type != DHCPV6_REPLY) return; /* RFC3315 section 15.10 validation (same as 15.3 since we * always include a client id). */ if (!valid_reply(packet, client)) { log_error("Invalid Reply - rejecting."); return; } lease = dhc6_leaseify(packet); /* This is an out of memory condition...hopefully a temporary * problem. Returning now makes us try to retransmit later. */ if (lease == NULL) return; check_status = dhc6_check_reply(client, lease); if (check_status != ISC_R_SUCCESS) { dhc6_lease_destroy(&lease, MDL); /* If no action was taken, but there is an error, then * we wait for a retransmission. */ if (check_status != ISC_R_CANCELED) return; } /* We're done retransmitting at this point. */ cancel_timeout(do_confirm6, client); cancel_timeout(do_select6, client); cancel_timeout(do_refresh6, client); cancel_timeout(do_release6, client); /* If this is in response to a Release/Decline, clean up and return. */ if (client->state == S_STOPPED) { if (client->active_lease == NULL) return; dhc6_lease_destroy(&client->active_lease, MDL); client->active_lease = NULL; /* We should never wait for nothing!? */ if (stopping_finished()) exit(0); return; } /* Action was taken, so now that we've torn down our scheduled * retransmissions, return. */ if (check_status == ISC_R_CANCELED) return; if (client->selected_lease != NULL) { dhc6_lease_destroy(&client->selected_lease, MDL); client->selected_lease = NULL; } /* If this is in response to a confirm, we use the lease we've * already got, not the reply we were sent. */ if (client->state == S_REBOOTING) { if (client->active_lease == NULL) log_fatal("Impossible condition at %s:%d.", MDL); dhc6_lease_destroy(&lease, MDL); start_bound(client); return; } /* Merge any bindings in the active lease (if there is one) into * the new active lease. */ dhc6_merge_lease(client->active_lease, lease); /* Cleanup if a previous attempt to go bound failed. */ if (client->old_lease != NULL) { dhc6_lease_destroy(&client->old_lease, MDL); client->old_lease = NULL; } /* Make this lease active and BIND to it. */ if (client->active_lease != NULL) client->old_lease = client->active_lease; client->active_lease = lease; /* We're done with the ADVERTISEd leases, if any. */ while(client->advertised_leases != NULL) { lease = client->advertised_leases; client->advertised_leases = lease->next; dhc6_lease_destroy(&lease, MDL); } start_bound(client); } /* DHCPv6 packets are a little sillier than they needed to be - the root * packet contains options, then IA's which contain options, then within * that IAADDR's which contain options. * * To sort this out at dhclient-script time (which fetches config parameters * in environment variables), start_bound() iterates over each IAADDR, and * calls this function to marshall an environment variable set that includes * the most-specific option values related to that IAADDR in particular. * * To achieve this, we load environment variables for the root options space, * then the IA, then the IAADDR. Any duplicate option names will be * over-written by the later versions. */ static void dhc6_marshall_values(const char *prefix, struct client_state *client, struct dhc6_lease *lease, struct dhc6_ia *ia, struct dhc6_addr *addr) { /* Option cache contents, in descending order of * scope. */ if ((lease != NULL) && (lease->options != NULL)) script_write_params6(client, prefix, lease->options); if ((ia != NULL) && (ia->options != NULL)) script_write_params6(client, prefix, ia->options); if ((addr != NULL) && (addr->options != NULL)) script_write_params6(client, prefix, addr->options); /* addr fields. */ if (addr != NULL) { if ((ia != NULL) && (ia->ia_type == D6O_IA_PD)) { client_envadd(client, prefix, "ip6_prefix", "%s/%u", piaddr(addr->address), (unsigned) addr->plen); } else { /* Current practice is that all subnets are /64's, but * some suspect this may not be permanent. */ client_envadd(client, prefix, "ip6_prefixlen", "%d", 64); client_envadd(client, prefix, "ip6_address", "%s", piaddr(addr->address)); } if ((ia != NULL) && (ia->ia_type == D6O_IA_TA)) { client_envadd(client, prefix, "ip6_type", "temporary"); } client_envadd(client, prefix, "life_starts", "%d", (int)(addr->starts)); client_envadd(client, prefix, "preferred_life", "%d", (int)(addr->preferred_life)); client_envadd(client, prefix, "max_life", "%d", (int)(addr->max_life)); } /* ia fields. */ if (ia != NULL) { client_envadd(client, prefix, "iaid", "%s", print_hex_1(4, ia->iaid, 12)); client_envadd(client, prefix, "starts", "%d", (int)(ia->starts)); client_envadd(client, prefix, "renew", "%u", ia->renew); client_envadd(client, prefix, "rebind", "%u", ia->rebind); } } /* Look at where the client's active lease is sitting. If it's looking to * time out on renew, rebind, depref, or expiration, do those things. */ static void dhc6_check_times(struct client_state *client) { struct dhc6_lease *lease; struct dhc6_ia *ia; struct dhc6_addr *addr; TIME renew=MAX_TIME, rebind=MAX_TIME, depref=MAX_TIME, lo_expire=MAX_TIME, hi_expire=0, tmp; int has_addrs = ISC_FALSE; struct timeval tv; lease = client->active_lease; /* Bit spammy. We should probably keep record of scheduled * events instead. */ cancel_timeout(start_renew6, client); cancel_timeout(start_rebind6, client); cancel_timeout(do_depref, client); cancel_timeout(do_expire, client); for(ia = lease->bindings ; ia != NULL ; ia = ia->next) { TIME this_ia_lo_expire, this_ia_hi_expire, use_expire; this_ia_lo_expire = MAX_TIME; this_ia_hi_expire = 0; for (addr = ia->addrs ; addr != NULL ; addr = addr->next) { if(!(addr->flags & DHC6_ADDR_DEPREFFED)) { if (addr->preferred_life == 0xffffffff) tmp = MAX_TIME; else tmp = addr->starts + addr->preferred_life; if (tmp < depref) depref = tmp; } if (!(addr->flags & DHC6_ADDR_EXPIRED)) { /* Find EPOCH-relative expiration. */ if (addr->max_life == 0xffffffff) tmp = MAX_TIME; else tmp = addr->starts + addr->max_life; /* Make the times ia->starts relative. */ tmp -= ia->starts; if (tmp > this_ia_hi_expire) this_ia_hi_expire = tmp; if (tmp < this_ia_lo_expire) this_ia_lo_expire = tmp; has_addrs = ISC_TRUE; } } /* These times are ia->starts relative. */ if (this_ia_lo_expire <= (this_ia_hi_expire / 2)) use_expire = this_ia_hi_expire; else use_expire = this_ia_lo_expire; /* * If the auto-selected expiration time is "infinite", or * zero, assert a reasonable default. */ if ((use_expire == MAX_TIME) || (use_expire <= 1)) use_expire = client->config->requested_lease / 2; else use_expire /= 2; /* Don't renew/rebind temporary addresses. */ if (ia->ia_type != D6O_IA_TA) { if (ia->renew == 0) { tmp = ia->starts + use_expire; } else if (ia->renew == 0xffffffff) tmp = MAX_TIME; else tmp = ia->starts + ia->renew; if (tmp < renew) renew = tmp; if (ia->rebind == 0) { /* Set rebind to 3/4 expiration interval. */ tmp = ia->starts; tmp += use_expire + (use_expire / 2); } else if (ia->renew == 0xffffffff) tmp = MAX_TIME; else tmp = ia->starts + ia->rebind; if (tmp < rebind) rebind = tmp; } /* * Return expiration ranges to EPOCH relative for event * scheduling (add_timeout()). */ this_ia_hi_expire += ia->starts; this_ia_lo_expire += ia->starts; if (this_ia_hi_expire > hi_expire) hi_expire = this_ia_hi_expire; if (this_ia_lo_expire < lo_expire) lo_expire = this_ia_lo_expire; } /* If there are no addresses, give up, go to INIT. * Note that if an address is unexpired with a date in the past, * we're scheduling an expiration event to ocurr in the past. We * could probably optimize this to expire now (but then there's * recursion). * * In the future, we may decide that we're done here, or to * schedule a future request (using 4-pkt info-request model). */ if (has_addrs == ISC_FALSE) { dhc6_lease_destroy(&client->active_lease, MDL); client->active_lease = NULL; /* Go back to the beginning. */ start_init6(client); return; } switch(client->state) { case S_BOUND: /* We'd like to hit renewing, but if rebinding has already * passed (time warp), head straight there. */ if ((rebind > cur_time) && (renew < rebind)) { log_debug("PRC: Renewal event scheduled in %d seconds, " "to run for %u seconds.", (int)(renew - cur_time), (unsigned)(rebind - renew)); client->next_MRD = rebind; tv.tv_sec = renew; tv.tv_usec = 0; add_timeout(&tv, start_renew6, client, NULL, NULL); break; } /* FALL THROUGH */ case S_RENEWING: /* While actively renewing, MRD is bounded by the time * we stop renewing and start rebinding. This helps us * process the state change on time. */ client->MRD = rebind - cur_time; if (rebind != MAX_TIME) { log_debug("PRC: Rebind event scheduled in %d seconds, " "to run for %d seconds.", (int)(rebind - cur_time), (int)(hi_expire - rebind)); client->next_MRD = hi_expire; tv.tv_sec = rebind; tv.tv_usec = 0; add_timeout(&tv, start_rebind6, client, NULL, NULL); } break; case S_REBINDING: /* For now, we rebind up until the last lease expires. In * the future, we might want to start SOLICITing when we've * depreffed an address. */ client->MRD = hi_expire - cur_time; break; default: log_fatal("Impossible condition at %s:%d.", MDL); } /* Separately, set a time at which we will depref and expire * leases. This might happen with multiple addresses while we * keep trying to refresh. */ if (depref != MAX_TIME) { log_debug("PRC: Depreference scheduled in %d seconds.", (int)(depref - cur_time)); tv.tv_sec = depref; tv.tv_usec = 0; add_timeout(&tv, do_depref, client, NULL, NULL); } if (lo_expire != MAX_TIME) { log_debug("PRC: Expiration scheduled in %d seconds.", (int)(lo_expire - cur_time)); tv.tv_sec = lo_expire; tv.tv_usec = 0; add_timeout(&tv, do_expire, client, NULL, NULL); } } /* In a given IA chain, find the IA with the same type and 'iaid'. */ static struct dhc6_ia * find_ia(struct dhc6_ia *head, u_int16_t type, const char *id) { struct dhc6_ia *ia; for (ia = head ; ia != NULL ; ia = ia->next) { if (ia->ia_type != type) continue; if (memcmp(ia->iaid, id, 4) == 0) return ia; } return NULL; } /* In a given address chain, find a matching address. */ static struct dhc6_addr * find_addr(struct dhc6_addr *head, struct iaddr *address) { struct dhc6_addr *addr; for (addr = head ; addr != NULL ; addr = addr->next) { if ((addr->address.len == address->len) && (memcmp(addr->address.iabuf, address->iabuf, address->len) == 0)) return addr; } return NULL; } /* In a given prefix chain, find a matching prefix. */ static struct dhc6_addr * find_pref(struct dhc6_addr *head, struct iaddr *prefix, u_int8_t plen) { struct dhc6_addr *pref; for (pref = head ; pref != NULL ; pref = pref->next) { if ((pref->address.len == prefix->len) && (pref->plen == plen) && (memcmp(pref->address.iabuf, prefix->iabuf, prefix->len) == 0)) return pref; } return NULL; } /* Merge the bindings from the source lease into the destination lease * structure, where they are missing. We have to copy the stateful * objects rather than move them over, because later code needs to be * able to compare new versus old if they contain any bindings. */ static void dhc6_merge_lease(struct dhc6_lease *src, struct dhc6_lease *dst) { struct dhc6_ia *sia, *dia, *tia; struct dhc6_addr *saddr, *daddr, *taddr; int changes = 0; if ((dst == NULL) || (src == NULL)) return; for (sia = src->bindings ; sia != NULL ; sia = sia->next) { dia = find_ia(dst->bindings, sia->ia_type, (char *)sia->iaid); if (dia == NULL) { tia = dhc6_dup_ia(sia, MDL); if (tia == NULL) log_fatal("Out of memory merging lease - " "Unable to continue without losing " "state! (%s:%d)", MDL); /* XXX: consider sorting? */ tia->next = dst->bindings; dst->bindings = tia; changes = 1; } else { for (saddr = sia->addrs ; saddr != NULL ; saddr = saddr->next) { if (sia->ia_type != D6O_IA_PD) daddr = find_addr(dia->addrs, &saddr->address); else daddr = find_pref(dia->addrs, &saddr->address, saddr->plen); if (daddr == NULL) { taddr = dhc6_dup_addr(saddr, MDL); if (taddr == NULL) log_fatal("Out of memory " "merging lease - " "Unable to continue " "without losing " "state! (%s:%d)", MDL); /* XXX: consider sorting? */ taddr->next = dia->addrs; dia->addrs = taddr; changes = 1; } } } } /* If we made changes, reset the score to 0 so it is recalculated. */ if (changes) dst->score = 0; } /* We've either finished selecting or succeeded in Renew or Rebinding our * lease. In all cases we got a Reply. Give dhclient-script a tickle * to inform it about the new values, and then lay in wait for the next * event. */ static void start_bound(struct client_state *client) { struct dhc6_ia *ia, *oldia; struct dhc6_addr *addr, *oldaddr; struct dhc6_lease *lease, *old; const char *reason; #if defined (NSUPDATE) TIME dns_update_offset = 1; #endif lease = client->active_lease; if (lease == NULL) { log_error("Cannot enter bound state unless an active lease " "is selected."); return; } lease->released = ISC_FALSE; old = client->old_lease; client->v6_handler = bound_handler; switch (client->state) { case S_SELECTING: case S_REBOOTING: /* Pretend we got bound. */ reason = "BOUND6"; break; case S_RENEWING: reason = "RENEW6"; break; case S_REBINDING: reason = "REBIND6"; break; default: log_fatal("Impossible condition at %s:%d.", MDL); /* Silence compiler warnings. */ return; } log_debug("PRC: Bound to lease %s.", print_hex_1(client->active_lease->server_id.len, client->active_lease->server_id.data, 55)); client->state = S_BOUND; write_client6_lease(client, lease, 0, 1); oldia = NULL; for (ia = lease->bindings ; ia != NULL ; ia = ia->next) { if (old != NULL) oldia = find_ia(old->bindings, ia->ia_type, (char *)ia->iaid); else oldia = NULL; for (addr = ia->addrs ; addr != NULL ; addr = addr->next) { if (oldia != NULL) { if (ia->ia_type != D6O_IA_PD) oldaddr = find_addr(oldia->addrs, &addr->address); else oldaddr = find_pref(oldia->addrs, &addr->address, addr->plen); } else oldaddr = NULL; #if defined (NSUPDATE) if ((oldaddr == NULL) && (ia->ia_type == D6O_IA_NA)) dhclient_schedule_updates(client, &addr->address, dns_update_offset++); #endif /* Shell out to setup the new binding. */ script_init(client, reason, NULL); if (old != NULL) dhc6_marshall_values("old_", client, old, oldia, oldaddr); dhc6_marshall_values("new_", client, lease, ia, addr); script_go(client); } /* XXX: maybe we should loop on the old values instead? */ if (ia->addrs == NULL) { script_init(client, reason, NULL); if (old != NULL) dhc6_marshall_values("old_", client, old, oldia, oldia != NULL ? oldia->addrs : NULL); dhc6_marshall_values("new_", client, lease, ia, NULL); script_go(client); } } /* XXX: maybe we should loop on the old values instead? */ if (lease->bindings == NULL) { script_init(client, reason, NULL); if (old != NULL) dhc6_marshall_values("old_", client, old, old->bindings, (old->bindings != NULL) ? old->bindings->addrs : NULL); dhc6_marshall_values("new_", client, lease, NULL, NULL); script_go(client); } go_daemon(); if (client->old_lease != NULL) { dhc6_lease_destroy(&client->old_lease, MDL); client->old_lease = NULL; } /* Schedule events. */ dhc6_check_times(client); } /* While bound, ignore packets. In the future we'll want to answer * Reconfigure-Request messages and the like. */ void bound_handler(struct packet *packet, struct client_state *client) { log_debug("RCV: Input packets are ignored once bound."); } /* start_renew6() gets us all ready to go to start transmitting Renew packets. * Note that client->next_MRD must be set before entering this function - * it must be set to the time at which the client should start Rebinding. */ void start_renew6(void *input) { struct client_state *client; client = (struct client_state *)input; log_info("PRC: Renewing lease on %s.", client->name ? client->name : client->interface->name); client->state = S_RENEWING; client->v6_handler = reply_handler; /* Times per RFC3315 section 18.1.3. */ client->IRT = REN_TIMEOUT * 100; client->MRT = REN_MAX_RT * 100; client->MRC = 0; /* MRD is special in renew - we need to set it by checking timer * state. */ client->MRD = client->next_MRD - cur_time; dhc6_retrans_init(client); client->refresh_type = DHCPV6_RENEW; do_refresh6(client); } /* do_refresh6() transmits one DHCPv6 packet, be it a Renew or Rebind, and * gives the retransmission state a bump for the next time. Note that * client->refresh_type must be set before entering this function. */ void do_refresh6(void *input) { struct option_cache *oc; struct sockaddr_in6 unicast, *dest_addr = &DHCPv6DestAddr; struct data_string ds; struct client_state *client; struct dhc6_lease *lease; struct timeval elapsed, tv; int send_ret; client = (struct client_state *)input; memset(&ds, 0, sizeof(ds)); lease = client->active_lease; if (lease == NULL) { log_error("Cannot renew without an active binding."); return; } /* Ensure we're emitting a valid message type. */ switch (client->refresh_type) { case DHCPV6_RENEW: case DHCPV6_REBIND: break; default: log_fatal("Internal inconsistency (%d) at %s:%d.", client->refresh_type, MDL); } /* * Start_time starts at the first transmission. */ if (client->txcount == 0) { client->start_time.tv_sec = cur_tv.tv_sec; client->start_time.tv_usec = cur_tv.tv_usec; } /* elapsed = cur - start */ elapsed.tv_sec = cur_tv.tv_sec - client->start_time.tv_sec; elapsed.tv_usec = cur_tv.tv_usec - client->start_time.tv_usec; if (elapsed.tv_usec < 0) { elapsed.tv_sec -= 1; elapsed.tv_usec += 1000000; } if (((client->MRC != 0) && (client->txcount > client->MRC)) || ((client->MRD != 0) && (elapsed.tv_sec >= client->MRD))) { /* We're done. Move on to the next phase, if any. */ dhc6_check_times(client); return; } /* * Check whether the server has sent a unicast option; if so, we can * use the address it specified for RENEWs. */ oc = lookup_option(&dhcpv6_universe, lease->options, D6O_UNICAST); if (oc && evaluate_option_cache(&ds, NULL, NULL, NULL, lease->options, NULL, &global_scope, oc, MDL)) { if (ds.len < 16) { log_error("Invalid unicast option length %d.", ds.len); } else { memset(&unicast, 0, sizeof(DHCPv6DestAddr)); unicast.sin6_family = AF_INET6; unicast.sin6_port = remote_port; memcpy(&unicast.sin6_addr, ds.data, 16); if (client->refresh_type == DHCPV6_RENEW) { dest_addr = &unicast; } } data_string_forget(&ds, MDL); } /* Commence forming a renew packet. */ memset(&ds, 0, sizeof(ds)); if (!buffer_allocate(&ds.buffer, 4, MDL)) { log_error("Unable to allocate memory for packet."); return; } ds.data = ds.buffer->data; ds.len = 4; ds.buffer->data[0] = client->refresh_type; memcpy(ds.buffer->data + 1, client->dhcpv6_transaction_id, 3); /* Form an elapsed option. */ /* Maximum value is 65535 1/100s coded as 0xffff. */ if ((elapsed.tv_sec < 0) || (elapsed.tv_sec > 655) || ((elapsed.tv_sec == 655) && (elapsed.tv_usec > 350000))) { client->elapsed = 0xffff; } else { client->elapsed = elapsed.tv_sec * 100; client->elapsed += elapsed.tv_usec / 10000; } if (client->elapsed == 0) log_debug("XMT: Forming %s, 0 ms elapsed.", dhcpv6_type_names[client->refresh_type]); else log_debug("XMT: Forming %s, %u0 ms elapsed.", dhcpv6_type_names[client->refresh_type], (unsigned)client->elapsed); client->elapsed = htons(client->elapsed); make_client6_options(client, &client->sent_options, lease, client->refresh_type); /* Put in any options from the sent cache. */ dhcpv6_universe.encapsulate(&ds, NULL, NULL, client, NULL, client->sent_options, &global_scope, &dhcpv6_universe); /* Append IA's */ if (wanted_ia_na && dhc6_add_ia_na(client, &ds, lease, client->refresh_type) != ISC_R_SUCCESS) { data_string_forget(&ds, MDL); return; } if (wanted_ia_pd && dhc6_add_ia_pd(client, &ds, lease, client->refresh_type) != ISC_R_SUCCESS) { data_string_forget(&ds, MDL); return; } log_info("XMT: %s on %s, interval %ld0ms.", dhcpv6_type_names[client->refresh_type], client->name ? client->name : client->interface->name, (long int)client->RT); send_ret = send_packet6(client->interface, ds.data, ds.len, dest_addr); if (send_ret != ds.len) { log_error("dhc6: send_packet6() sent %d of %d bytes", send_ret, ds.len); } data_string_forget(&ds, MDL); /* Wait RT */ tv.tv_sec = cur_tv.tv_sec + client->RT / 100; tv.tv_usec = cur_tv.tv_usec + (client->RT % 100) * 10000; if (tv.tv_usec >= 1000000) { tv.tv_sec += 1; tv.tv_usec -= 1000000; } add_timeout(&tv, do_refresh6, client, NULL, NULL); dhc6_retrans_advance(client); } /* start_rebind6() gets us all set up to go and rebind a lease. Note that * client->next_MRD must be set before entering this function. In this case, * MRD must be set to the maximum time any address in the packet will * expire. */ void start_rebind6(void *input) { struct client_state *client; client = (struct client_state *)input; log_info("PRC: Rebinding lease on %s.", client->name ? client->name : client->interface->name); client->state = S_REBINDING; client->v6_handler = reply_handler; /* Times per RFC3315 section 18.1.4. */ client->IRT = REB_TIMEOUT * 100; client->MRT = REB_MAX_RT * 100; client->MRC = 0; /* MRD is special in rebind - it's determined by the timer * state. */ client->MRD = client->next_MRD - cur_time; dhc6_retrans_init(client); client->refresh_type = DHCPV6_REBIND; do_refresh6(client); } /* do_depref() runs through a given lease's addresses, for each that has * not yet been depreffed, shells out to the dhclient-script to inform it * of the status change. The dhclient-script should then do...something... * to encourage applications to move off the address and onto one of the * remaining 'preferred' addresses. */ void do_depref(void *input) { struct client_state *client; struct dhc6_lease *lease; struct dhc6_ia *ia; struct dhc6_addr *addr; client = (struct client_state *)input; lease = client->active_lease; if (lease == NULL) return; for (ia = lease->bindings ; ia != NULL ; ia = ia->next) { for (addr = ia->addrs ; addr != NULL ; addr = addr->next) { if (addr->flags & DHC6_ADDR_DEPREFFED) continue; if (addr->starts + addr->preferred_life <= cur_time) { script_init(client, "DEPREF6", NULL); dhc6_marshall_values("cur_", client, lease, ia, addr); script_go(client); addr->flags |= DHC6_ADDR_DEPREFFED; if (ia->ia_type != D6O_IA_PD) log_info("PRC: Address %s depreferred.", piaddr(addr->address)); else log_info("PRC: Prefix %s/%u depreferred.", piaddr(addr->address), (unsigned) addr->plen); #if defined (NSUPDATE) /* Remove DDNS bindings at depref time. */ if ((ia->ia_type == D6O_IA_NA) && client->config->do_forward_update) client_dns_remove(client, &addr->address); #endif } } } dhc6_check_times(client); } /* do_expire() searches through all the addresses on a given lease, and * expires/removes any addresses that are no longer valid. */ void do_expire(void *input) { struct client_state *client; struct dhc6_lease *lease; struct dhc6_ia *ia; struct dhc6_addr *addr; int has_addrs = ISC_FALSE; client = (struct client_state *)input; lease = client->active_lease; if (lease == NULL) return; for (ia = lease->bindings ; ia != NULL ; ia = ia->next) { for (addr = ia->addrs ; addr != NULL ; addr = addr->next) { if (addr->flags & DHC6_ADDR_EXPIRED) continue; if (addr->starts + addr->max_life <= cur_time) { script_init(client, "EXPIRE6", NULL); dhc6_marshall_values("old_", client, lease, ia, addr); script_go(client); addr->flags |= DHC6_ADDR_EXPIRED; if (ia->ia_type != D6O_IA_PD) log_info("PRC: Address %s expired.", piaddr(addr->address)); else log_info("PRC: Prefix %s/%u expired.", piaddr(addr->address), (unsigned) addr->plen); #if defined (NSUPDATE) /* We remove DNS records at depref time, but * it is possible that we might get here * without depreffing. */ if ((ia->ia_type == D6O_IA_NA) && client->config->do_forward_update && !(addr->flags & DHC6_ADDR_DEPREFFED)) client_dns_remove(client, &addr->address); #endif continue; } has_addrs = ISC_TRUE; } } /* Clean up empty leases. */ if (has_addrs == ISC_FALSE) { log_info("PRC: Bound lease is devoid of active addresses." " Re-initializing."); dhc6_lease_destroy(&lease, MDL); client->active_lease = NULL; start_init6(client); return; } /* Schedule the next run through. */ dhc6_check_times(client); } /* * Run client script to unconfigure interface. * Called with reason STOP6 when dhclient -x is run, or with reason * RELEASE6 when server has replied to a Release message. * Stateless is a special case. */ void unconfigure6(struct client_state *client, const char *reason) { struct dhc6_ia *ia; struct dhc6_addr *addr; if (stateless) { script_init(client, reason, NULL); if (client->active_lease != NULL) script_write_params6(client, "old_", client->active_lease->options); script_go(client); return; } if (client->active_lease == NULL) return; for (ia = client->active_lease->bindings ; ia != NULL ; ia = ia->next) { if (ia->ia_type == D6O_IA_TA) continue; for (addr = ia->addrs ; addr != NULL ; addr = addr->next) { script_init(client, reason, NULL); dhc6_marshall_values("old_", client, client->active_lease, ia, addr); script_go(client); #if defined (NSUPDATE) if ((ia->ia_type == D6O_IA_NA) && client->config->do_forward_update) client_dns_remove(client, &addr->address); #endif } } } void refresh_info_request6(void *input) { struct client_state *client; client = (struct client_state *)input; start_info_request6(client); } /* Timeout for Information-Request (using the IRT option). */ static void dhc6_check_irt(struct client_state *client) { struct option **req; struct option_cache *oc; TIME expire = MAX_TIME; struct timeval tv; int i; isc_boolean_t found = ISC_FALSE; cancel_timeout(refresh_info_request6, client); req = client->config->requested_options; for (i = 0; req[i] != NULL; i++) { if (req[i] == irt_option) { found = ISC_TRUE; break; } } /* Simply return gives a endless loop waiting for nothing. */ if (!found) exit(0); oc = lookup_option(&dhcpv6_universe, client->active_lease->options, D6O_INFORMATION_REFRESH_TIME); if (oc != NULL) { struct data_string irt; memset(&irt, 0, sizeof(irt)); if (!evaluate_option_cache(&irt, NULL, NULL, client, client->active_lease->options, NULL, &global_scope, oc, MDL) || (irt.len < 4)) { log_error("Can't evaluate IRT."); } else { expire = getULong(irt.data); if (expire < IRT_MINIMUM) expire = IRT_MINIMUM; if (expire == 0xffffffff) expire = MAX_TIME; } data_string_forget(&irt, MDL); } else expire = IRT_DEFAULT; if (expire != MAX_TIME) { log_debug("PRC: Refresh event scheduled in %u seconds.", (unsigned) expire); tv.tv_sec = cur_time + expire; tv.tv_usec = 0; add_timeout(&tv, refresh_info_request6, client, NULL, NULL); } } /* We got a Reply. Give dhclient-script a tickle to inform it about * the new values, and then lay in wait for the next event. */ static void start_informed(struct client_state *client) { client->v6_handler = informed_handler; log_debug("PRC: Done."); client->state = S_BOUND; script_init(client, "RENEW6", NULL); if (client->old_lease != NULL) script_write_params6(client, "old_", client->old_lease->options); script_write_params6(client, "new_", client->active_lease->options); script_go(client); go_daemon(); if (client->old_lease != NULL) { dhc6_lease_destroy(&client->old_lease, MDL); client->old_lease = NULL; } /* Schedule events. */ dhc6_check_irt(client); } /* While informed, ignore packets. */ void informed_handler(struct packet *packet, struct client_state *client) { log_debug("RCV: Input packets are ignored once bound."); } /* make_client6_options() fetches option caches relevant to the client's * scope and places them into the sent_options cache. This cache is later * used to populate DHCPv6 output packets with options. */ static void make_client6_options(struct client_state *client, struct option_state **op, struct dhc6_lease *lease, u_int8_t message) { struct option_cache *oc; struct option **req; struct buffer *buffer; int buflen, i, oro_len; if ((op == NULL) || (client == NULL)) return; if (*op) option_state_dereference(op, MDL); /* Create a cache to carry options to transmission. */ option_state_allocate(op, MDL); /* Create and store an 'elapsed time' option in the cache. */ oc = NULL; if (option_cache_allocate(&oc, MDL)) { const unsigned char *cdata; cdata = (unsigned char *)&client->elapsed; if (make_const_data(&oc->expression, cdata, 2, 0, 0, MDL)) { option_reference(&oc->option, elapsed_option, MDL); save_option(&dhcpv6_universe, *op, oc); } option_cache_dereference(&oc, MDL); } /* Bring in any configured options to send. */ if (client->config->on_transmission) execute_statements_in_scope(NULL, NULL, NULL, client, lease ? lease->options : NULL, *op, &global_scope, client->config->on_transmission, NULL); /* Rapid-commit is only for SOLICITs. */ if (message != DHCPV6_SOLICIT) delete_option(&dhcpv6_universe, *op, D6O_RAPID_COMMIT); /* See if the user configured a DUID in a relevant scope. If not, * introduce our default manufactured id. */ if ((oc = lookup_option(&dhcpv6_universe, *op, D6O_CLIENTID)) == NULL) { if (!option_cache(&oc, &default_duid, NULL, clientid_option, MDL)) log_fatal("Failure assembling a DUID."); save_option(&dhcpv6_universe, *op, oc); option_cache_dereference(&oc, MDL); } /* In cases where we're responding to a single server, put the * server's id in the response. * * Note that lease is NULL for SOLICIT or INFO request messages, * and otherwise MUST be present. */ if (lease == NULL) { if ((message != DHCPV6_SOLICIT) && (message != DHCPV6_INFORMATION_REQUEST)) log_fatal("Impossible condition at %s:%d.", MDL); } else if ((message != DHCPV6_REBIND) && (message != DHCPV6_CONFIRM)) { oc = lookup_option(&dhcpv6_universe, lease->options, D6O_SERVERID); if (oc != NULL) save_option(&dhcpv6_universe, *op, oc); } /* 'send dhcp6.oro foo;' syntax we used in 4.0.0a1/a2 has been * deprecated by adjustments to the 'request' syntax also used for * DHCPv4. */ if (lookup_option(&dhcpv6_universe, *op, D6O_ORO) != NULL) log_error("'send dhcp6.oro' syntax is deprecated, please " "use the 'request' syntax (\"man dhclient.conf\")."); /* Construct and store an ORO (Option Request Option). It is a * fatal error to fail to send an ORO (of at least zero length). * * Discussion: RFC3315 appears to be inconsistent in its statements * of whether or not the ORO is mandatory. In section 18.1.1 * ("Creation and Transmission of Request Messages"): * * The client MUST include an Option Request option (see section * 22.7) to indicate the options the client is interested in * receiving. The client MAY include options with data values as * hints to the server about parameter values the client would like * to have returned. * * This MUST is missing from the creation/transmission of other * messages (such as Renew and Rebind), and the section 22.7 ("Option * Request Option" format and definition): * * A client MAY include an Option Request option in a Solicit, * Request, Renew, Rebind, Confirm or Information-request message to * inform the server about options the client wants the server to * send to the client. A server MAY include an Option Request * option in a Reconfigure option to indicate which options the * client should request from the server. * * seems to relax the requirement from MUST to MAY (and still other * language in RFC3315 supports this). * * In lieu of a clarification of RFC3315, we will conform with the * MUST. Instead of an absent ORO, we will if there are no options * to request supply an empty ORO. Theoretically, an absent ORO is * difficult to interpret (does the client want all options or no * options?). A zero-length ORO is intuitively clear: requesting * nothing. */ buffer = NULL; oro_len = 0; buflen = 32; if (!buffer_allocate(&buffer, buflen, MDL)) log_fatal("Out of memory constructing DHCPv6 ORO."); req = client->config->requested_options; if (req != NULL) { for (i = 0 ; req[i] != NULL ; i++) { if (buflen == oro_len) { struct buffer *tmpbuf = NULL; buflen += 32; /* Shell game. */ buffer_reference(&tmpbuf, buffer, MDL); buffer_dereference(&buffer, MDL); if (!buffer_allocate(&buffer, buflen, MDL)) log_fatal("Out of memory resizing " "DHCPv6 ORO buffer."); memcpy(buffer->data, tmpbuf->data, oro_len); buffer_dereference(&tmpbuf, MDL); } if (req[i]->universe == &dhcpv6_universe) { /* Append the code to the ORO. */ putUShort(buffer->data + oro_len, req[i]->code); oro_len += 2; } } } oc = NULL; if (make_const_option_cache(&oc, &buffer, NULL, oro_len, oro_option, MDL)) { save_option(&dhcpv6_universe, *op, oc); } else { log_fatal("Unable to create ORO option cache."); } /* * Note: make_const_option_cache() consumes the buffer, we do not * need to dereference it (XXX). */ option_cache_dereference(&oc, MDL); } /* A clone of the DHCPv4 script_write_params() minus the DHCPv4-specific * filename, server-name, etc specifics. * * Simply, store all values present in all universes of the option state * (probably derived from a DHCPv6 packet) into environment variables * named after the option names (and universe names) but with the 'prefix' * prepended. * * Later, dhclient-script may compare for example "new_time_servers" and * "old_time_servers" for differences, and only upon detecting a change * bother to rewrite ntp.conf and restart it. Or something along those * generic lines. */ static void script_write_params6(struct client_state *client, const char *prefix, struct option_state *options) { struct envadd_state es; int i; if (options == NULL) return; es.client = client; es.prefix = prefix; for (i = 0 ; i < options->universe_count ; i++) { option_space_foreach(NULL, NULL, client, NULL, options, &global_scope, universes[i], &es, client_option_envadd); } } /* * Check if there is something not fully defined in the active lease. */ static isc_boolean_t active_prefix(struct client_state *client) { struct dhc6_lease *lease; struct dhc6_ia *ia; struct dhc6_addr *pref; char zeros[16]; lease = client->active_lease; if (lease == NULL) return ISC_FALSE; memset(zeros, 0, 16); for (ia = lease->bindings; ia != NULL; ia = ia->next) { if (ia->ia_type != D6O_IA_PD) continue; for (pref = ia->addrs; pref != NULL; pref = pref->next) { if (pref->plen == 0) return ISC_FALSE; if (pref->address.len != 16) return ISC_FALSE; if (memcmp(pref->address.iabuf, zeros, 16) == 0) return ISC_FALSE; } } return ISC_TRUE; } #endif /* DHCPv6 */ dhcp-4.2.4/client/dhclient-script.8000644 000765 000024 00000026063 11414676757 017063 0ustar00sarstaff000000 000000 .\" dhclient-script.8 .\" .\" Copyright (c) 2009-2010 by Internet Systems Consortium, Inc. ("ISC") .\" Copyright (c) 2004-2005 by Internet Systems Consortium, Inc. ("ISC") .\" Copyright (c) 1996-2003 by Internet Software Consortium .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above .\" copyright notice and this permission notice appear in all copies. .\" .\" THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES .\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR .\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES .\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT .\" OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" .\" Internet Systems Consortium, Inc. .\" 950 Charter Street .\" Redwood City, CA 94063 .\" .\" https://www.isc.org/ .\" .\" This software has been written for Internet Systems Consortium .\" by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. .\" .\" Support and other services are available for ISC products - see .\" https://www.isc.org for more information or to learn more about ISC. .\" .\" $Id: dhclient-script.8,v 1.12.24.2 2010-07-06 19:03:11 sar Exp $ .\" .TH dhclient-script 8 .SH NAME dhclient-script - DHCP client network configuration script .SH DESCRIPTION The DHCP client network configuration script is invoked from time to time by \fBdhclient(8)\fR. This script is used by the dhcp client to set each interface's initial configuration prior to requesting an address, to test the address once it has been offered, and to set the interface's final configuration once a lease has been acquired. If no lease is acquired, the script is used to test predefined leases, if any, and also called once if no valid lease can be identified. .PP This script is not meant to be customized by the end user. If local customizations are needed, they should be possible using the enter and exit hooks provided (see HOOKS for details). These hooks will allow the user to override the default behaviour of the client in creating a .B /etc/resolv.conf file. .PP No standard client script exists for some operating systems, even though the actual client may work, so a pioneering user may well need to create a new script or modify an existing one. In general, customizations specific to a particular computer should be done in the .B ETCDIR/dhclient.conf file. If you find that you can't make such a customization without customizing .B ETCDIR/dhclient.conf or using the enter and exit hooks, please submit a bug report. .SH HOOKS When it starts, the client script first defines a shell function, .B make_resolv_conf , which is later used to create the .B /etc/resolv.conf file. To override the default behaviour, redefine this function in the enter hook script. .PP On after defining the make_resolv_conf function, the client script checks for the presence of an executable .B ETCDIR/dhclient-enter-hooks script, and if present, it invokes the script inline, using the Bourne shell \'.\' command. The entire environment documented under OPERATION is available to this script, which may modify the environment if needed to change the behaviour of the script. If an error occurs during the execution of the script, it can set the exit_status variable to a nonzero value, and .B CLIENTBINDIR/dhclient-script will exit with that error code immediately after the client script exits. .PP After all processing has completed, .B CLIENTBINDIR/dhclient-script checks for the presence of an executable .B ETCDIR/dhclient-exit-hooks script, which if present is invoked using the \'.\' command. The exit status of dhclient-script will be passed to dhclient-exit-hooks in the exit_status shell variable, and will always be zero if the script succeeded at the task for which it was invoked. The rest of the environment as described previously for dhclient-enter-hooks is also present. The .B ETCDIR/dhclient-exit-hooks script can modify the valid of exit_status to change the exit status of dhclient-script. .SH OPERATION When dhclient needs to invoke the client configuration script, it defines a set of variables in the environment, and then invokes .B CLIENTBINDIR/dhclient-script. In all cases, $reason is set to the name of the reason why the script has been invoked. The following reasons are currently defined: MEDIUM, PREINIT, BOUND, RENEW, REBIND, REBOOT, EXPIRE, FAIL, STOP, RELEASE, NBI and TIMEOUT. .PP .SH MEDIUM The DHCP client is requesting that an interface's media type be set. The interface name is passed in $interface, and the media type is passed in $medium. .SH PREINIT The DHCP client is requesting that an interface be configured as required in order to send packets prior to receiving an actual address. For clients which use the BSD socket library, this means configuring the interface with an IP address of 0.0.0.0 and a broadcast address of 255.255.255.255. For other clients, it may be possible to simply configure the interface up without actually giving it an IP address at all. The interface name is passed in $interface, and the media type in $medium. .PP If an IP alias has been declared in dhclient.conf, its address will be passed in $alias_ip_address, and that ip alias should be deleted from the interface, along with any routes to it. .SH BOUND The DHCP client has done an initial binding to a new address. The new ip address is passed in $new_ip_address, and the interface name is passed in $interface. The media type is passed in $medium. Any options acquired from the server are passed using the option name described in \fBdhcp-options\fR, except that dashes (\'-\') are replaced by underscores (\'_\') in order to make valid shell variables, and the variable names start with new_. So for example, the new subnet mask would be passed in $new_subnet_mask. .PP Before actually configuring the address, dhclient-script should somehow ARP for it and exit with a nonzero status if it receives a reply. In this case, the client will send a DHCPDECLINE message to the server and acquire a different address. This may also be done in the RENEW, REBIND, or REBOOT states, but is not required, and indeed may not be desirable. .PP When a binding has been completed, a lot of network parameters are likely to need to be set up. A new /etc/resolv.conf needs to be created, using the values of $new_domain_name and $new_domain_name_servers (which may list more than one server, separated by spaces). A default route should be set using $new_routers, and static routes may need to be set up using $new_static_routes. .PP If an IP alias has been declared, it must be set up here. The alias IP address will be written as $alias_ip_address, and other DHCP options that are set for the alias (e.g., subnet mask) will be passed in variables named as described previously except starting with $alias_ instead of $new_. Care should be taken that the alias IP address not be used if it is identical to the bound IP address ($new_ip_address), since the other alias parameters may be incorrect in this case. .SH RENEW When a binding has been renewed, the script is called as in BOUND, except that in addition to all the variables starting with $new_, there is another set of variables starting with $old_. Persistent settings that may have changed need to be deleted - for example, if a local route to the bound address is being configured, the old local route should be deleted. If the default route has changed, the old default route should be deleted. If the static routes have changed, the old ones should be deleted. Otherwise, processing can be done as with BOUND. .SH REBIND The DHCP client has rebound to a new DHCP server. This can be handled as with RENEW, except that if the IP address has changed, the ARP table should be cleared. .SH REBOOT The DHCP client has successfully reacquired its old address after a reboot. This can be processed as with BOUND. .SH EXPIRE The DHCP client has failed to renew its lease or acquire a new one, and the lease has expired. The IP address must be relinquished, and all related parameters should be deleted, as in RENEW and REBIND. .SH FAIL The DHCP client has been unable to contact any DHCP servers, and any leases that have been tested have not proved to be valid. The parameters from the last lease tested should be deconfigured. This can be handled in the same way as EXPIRE. .SH STOP The dhclient has been informed to shut down gracefully, the dhclient-script should unconfigure or shutdown the interface as appropriate. .SH RELEASE The dhclient has been executed using the -r flag, indicating that the administrator wishes it to release its lease(s). dhclient-script should unconfigure or shutdown the interface. .SH NBI No-Broadcast-Interfaces...dhclient was unable to find any interfaces upon which it believed it should commence DHCP. What dhclient-script should do in this situation is entirely up to the implementor. .SH TIMEOUT The DHCP client has been unable to contact any DHCP servers. However, an old lease has been identified, and its parameters have been passed in as with BOUND. The client configuration script should test these parameters and, if it has reason to believe they are valid, should exit with a value of zero. If not, it should exit with a nonzero value. .PP The usual way to test a lease is to set up the network as with REBIND (since this may be called to test more than one lease) and then ping the first router defined in $routers. If a response is received, the lease must be valid for the network to which the interface is currently connected. It would be more complete to try to ping all of the routers listed in $new_routers, as well as those listed in $new_static_routes, but current scripts do not do this. .SH FILES Each operating system should generally have its own script file, although the script files for similar operating systems may be similar or even identical. The script files included in Internet Systems Consortium DHCP distribution appear in the distribution tree under client/scripts, and bear the names of the operating systems on which they are intended to work. .SH BUGS If more than one interface is being used, there's no obvious way to avoid clashes between server-supplied configuration parameters - for example, the stock dhclient-script rewrites /etc/resolv.conf. If more than one interface is being configured, /etc/resolv.conf will be repeatedly initialized to the values provided by one server, and then the other. Assuming the information provided by both servers is valid, this shouldn't cause any real problems, but it could be confusing. .SH SEE ALSO dhclient(8), dhcpd(8), dhcrelay(8), dhclient.conf(5) and dhclient.leases(5). .SH AUTHOR .B dhclient-script(8) has been written for Internet Systems Consortium by Ted Lemon in cooperation with Vixie Enterprises. To learn more about Internet Systems Consortium, see .B https://www.isc.org. To learn more about Vixie Enterprises, see .B http://www.vix.com. dhcp-4.2.4/client/dhclient.8000644 000765 000024 00000037121 11552141342 015532 0ustar00sarstaff000000 000000 .\" $Id: dhclient.8,v 1.32.24.4 2011-04-15 22:12:50 sar Exp $ .\" .\" Copyright (c) 2004,2007-2011 by Internet Systems Consortium, Inc. ("ISC") .\" Copyright (c) 1996-2003 by Internet Software Consortium .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above .\" copyright notice and this permission notice appear in all copies. .\" .\" THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES .\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR .\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES .\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT .\" OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" .\" Internet Systems Consortium, Inc. .\" 950 Charter Street .\" Redwood City, CA 94063 .\" .\" https://www.isc.org/ .\" .\" Support and other services are available for ISC products - see .\" https://www.isc.org for more information or to learn more about ISC. .\" .TH dhclient 8 .SH NAME dhclient - Dynamic Host Configuration Protocol Client .SH SYNOPSIS .B dhclient [ .B -4 | .B -6 ] [ .B -S ] [ .B -N [ .B -N... ] ] [ .B -T [ .B -T... ] ] [ .B -P [ .B -P... ] ] [ .B -D .I LL|LLT ] [ .B -p .I port ] [ .B -d ] [ .B -e .I VAR=value ] [ .B -q ] [ .B -1 ] [ .B -r | .B -x ] [ .B -lf .I lease-file ] [ .B -pf .I pid-file ] [ .B --no-pid ] [ .B -cf .I config-file ] [ .B -sf .I script-file ] [ .B -s .I server-addr ] [ .B -g .I relay ] [ .B -n ] [ .B -nw ] [ .B -w ] [ .B -v ] [ .B --version ] [ .I if0 [ .I ...ifN ] ] .SH DESCRIPTION The Internet Systems Consortium DHCP Client, \fBdhclient\fR, provides a means for configuring one or more network interfaces using the Dynamic Host Configuration Protocol, BOOTP protocol, or if these protocols fail, by statically assigning an address. .SH OPERATION .PP The DHCP protocol allows a host to contact a central server which maintains a list of IP addresses which may be assigned on one or more subnets. A DHCP client may request an address from this pool, and then use it on a temporary basis for communication on network. The DHCP protocol also provides a mechanism whereby a client can learn important details about the network to which it is attached, such as the location of a default router, the location of a name server, and so on. .PP There are two versions of the DHCP protocol DHCPv4 and DHCPv6. At startup the client may be started for one or the other via the .B -4 or .B -6 options. .PP On startup, \fBdhclient\fR reads the dhclient.conf for configuration instructions. It then gets a list of all the network interfaces that are configured in the current system. For each interface, it attempts to configure the interface using the DHCP protocol. .PP In order to keep track of leases across system reboots and server restarts, \fBdhclient\fR keeps a list of leases it has been assigned in the dhclient.leases file. On startup, after reading the dhclient.conf file, \fBdhclient\fR reads the dhclient.leases file to refresh its memory about what leases it has been assigned. .PP When a new lease is acquired, it is appended to the end of the dhclient.leases file. In order to prevent the file from becoming arbitrarily large, from time to time \fBdhclient\fR creates a new dhclient.leases file from its in-core lease database. The old version of the dhclient.leases file is retained under the name .IR dhclient.leases~ until the next time \fBdhclient\fR rewrites the database. .PP Old leases are kept around in case the DHCP server is unavailable when \fBdhclient\fR is first invoked (generally during the initial system boot process). In that event, old leases from the dhclient.leases file which have not yet expired are tested, and if they are determined to be valid, they are used until either they expire or the DHCP server becomes available. .PP A mobile host which may sometimes need to access a network on which no DHCP server exists may be preloaded with a lease for a fixed address on that network. When all attempts to contact a DHCP server have failed, \fBdhclient\fR will try to validate the static lease, and if it succeeds, will use that lease until it is restarted. .PP A mobile host may also travel to some networks on which DHCP is not available but BOOTP is. In that case, it may be advantageous to arrange with the network administrator for an entry on the BOOTP database, so that the host can boot quickly on that network rather than cycling through the list of old leases. .SH COMMAND LINE .PP The names of the network interfaces that \fBdhclient\fR should attempt to configure may be specified on the command line. If no interface names are specified on the command line \fBdhclient\fR will normally identify all network interfaces, eliminating non-broadcast interfaces if possible, and attempt to configure each interface. .PP It is also possible to specify interfaces by name in the dhclient.conf file. If interfaces are specified in this way, then the client will only configure interfaces that are either specified in the configuration file or on the command line, and will ignore all other interfaces. .PP The client normally prints no output during its startup sequence. It can be made to emit verbose messages displaying the startup sequence events until it has acquired an address by supplying the .B -v command line argument. In either case, the client logs messages using the .B syslog(3) facility. .SH OPTIONS .TP .BI \-4 Use the DHCPv4 protocol to obtain an IPv4 address and configuration parameters. This is the default and cannot be combined with \fB\-6\fR. .TP .BI \-6 Use the DHCPv6 protocol to obtain whatever IPv6 addresses are available along with configuration parameters. It cannot be combined with \fB\-4\fR. The \fB\-S -T -P -N\fR and \fB\-D\fR arguments provide more control over aspects of the DHCPv6 processing. Note: it is not recommended to mix queries of different types together or even to share the lease file between them. .TP .BI \-1 Try to get a lease once. On failure exit with code 2. In DHCPv6 this sets the maximum duration of the initial exchange to .I timeout (from .IR dhclient.conf(5) with a default of sixty seconds). .TP .BI \-d .\" This is not intuitive. Force .B dhclient to run as a foreground process. Normally the DHCP client will run in the foreground until is has configured an interface at which time it will revert to running in the background. This option is useful when running the client under a debugger, or when running it out of inittab on System V systems. This implies \fB-v\fR. .TP .BI \-nw Become a daemon immediately (nowait) rather than waiting until an an IP address has been acquired. .TP .BI \-q Be quiet at startup, this is the default. .TP .BI \-v Enable verbose log messages. .\" This prints the version, copyright and URL. .TP .BI \-w Continue running even if no broadcast interfaces were found. Normally DHCP client will exit if it isn't able to identify any network interfaces to configure. On laptop computers and other computers with hot-swappable I/O buses, it is possible that a broadcast interface may be added after system startup. This flag can be used to cause the client not to exit when it doesn't find any such interfaces. The .B omshell(1) program can then be used to notify the client when a network interface has been added or removed, so that the client can attempt to configure an IP address on that interface. .TP .BI \-n Do not configure any interfaces. This is most likely to be useful in combination with the .B -w flag. .TP .BI \-e \ VAR=val Define additional environment variables for the environment where .B dhclient-script(8) executes. You may specify multiple .B \-e options on the command line. .TP .BI \-r Release the current lease and stop the running DHCP client as previously recorded in the PID file. When shutdown via this method .B dhclient-script(8) will be executed with the specific reason for calling the script set. The client normally doesn't release the current lease as this is not required by the DHCP protocol but some cable ISPs require their clients to notify the server if they wish to release an assigned IP address. .\" TODO what dhclient-script argument? .\" When released, .TP .BI \-x Stop the running DHCP client without releasing the current lease. Kills existing \fBdhclient\fR process as previously recorded in the PID file. When shutdown via this method .B dhclient-script(8) will be executed with the specific reason for calling the script set. .TP .BI \-p \ port The UDP port number on which the DHCP client should listen and transmit. If unspecified, .B dhclient uses the default port of 68. This is mostly useful for debugging purposes. If a different port is specified on which the client should listen and transmit, the client will also use a different destination port - one less than the specified port. .TP .BI \-s \ server-addr Specify the server IP address or fully qualified domain name to use as a destination for DHCP protocol messages before .B dhclient has acquired an IP address. Normally, .B dhclient transmits these messages to 255.255.255.255 (the IP limited broadcast address). Overriding this is mostly useful for debugging purposes. This feature is not supported in DHCPv6 (\fB-6\fR) mode. .TP .BI \-g \ relay .\" mockup relay Set the giaddr field of all packets to the \fIrelay\fR IP address simulating a relay agent. This is for testing pruposes only and should not be expected to work in any consistent or useful way. .TP .BI \--version Print version number and exit. .PP .I Options available for DHCPv6 mode: .TP .BI \-S .\" TODO: mention DUID? Use Information-request to get only stateless configuration parameters (i.e., without address). This implies \fB\-6\fR. It also doesn't rewrite the lease database. .\" TODO: May not be used with -N -P or -T. ?? .TP .BI \-T .\" TODO wanted_ia_ta++ Ask for IPv6 temporary addresses, one set per \fB\-T\fR flag. This implies \fB\-6\fR and also disables the normal address query. See \fB\-N\fR to restore it. .TP .BI \-P Enable IPv6 prefix delegation. This implies \fB\-6\fR and also disables the normal address query. See \fB\-N\fR to restore it. Note only one requested interface is allowed. .TP .BI \-D \ LL\ or\ LLT Override the default when selecting the type of DUID to use. By default, DHCPv6 \fBdhclient\fR creates an identifier based on the link-layer address (DUID-LL) if it is running in stateless mode (with \fB\-S\fR, not requesting an address), or it creates an identifier based on the link-layer address plus a timestamp (DUID-LLT) if it is running in stateful mode (without \fB\-S\fR, requesting an address). \fB\-D\fR overrides this default, with a value of either \fILL\fR or \fILLT\fR. .TP .BI \-N .\" TODO: is this for telling an already running dhclient? Restore normal address query for IPv6. This implies \fB-6\fR. It is used to restore normal operation after using \fB-T\fR or \fB-P\fR. .PP .I Modifying default file locations: The following options can be used to modify the locations a client uses for it's files. They can be particularly useful if, for example, .B DBDIR or .B RUNDIR have not been mounted when the DHCP client is started. .TP .BI \-cf \ config-file Path to the client configuration file. If unspecified, the default .B ETCDIR/dhclient.conf is used. See \fBdhclient.conf(5)\fR for a description of this file. .TP .BI \-lf \ lease-file Path to the lease database file. If unspecified, the default .B DBDIR/dhclient.leases is used. See \fBdhclient.leases(5)\fR for a descriptionof this file. .TP .BI \-pf \ pid-file Path to the process ID file. If unspecified, the default .B RUNDIR/dhclient.pid is used. .TP .BI \--no-pid Option to disable writing pid files. By default the program will write a pid file. If the program is invoked with this option it will not attempt to kill any existing client processes even if invoked with \fB-r\fR or \fB-x\fR. .TP .BI \-sf \ script-file Path to the network configuration script invoked by .B dhclient when it gets a lease. If unspecified, the default .B CLIENTBINDIR/dhclient-script is used. See \fBdhclient-script(8)\fR for a description of this file. .PP .SH CONFIGURATION The syntax of the \fBdhclient.conf(5)\fR file is discussed separately. .SH OMAPI The DHCP client provides some ability to control it while it is running, without stopping it. This capability is provided using OMAPI, an API for manipulating remote objects. OMAPI clients connect to the client using TCP/IP, authenticate, and can then examine the client's current status and make changes to it. .PP Rather than implementing the underlying OMAPI protocol directly, user programs should use the dhcpctl API or OMAPI itself. Dhcpctl is a wrapper that handles some of the housekeeping chores that OMAPI does not do automatically. Dhcpctl and OMAPI are documented in \fBdhcpctl(3)\fR and \fBomapi(3)\fR. Most things you'd want to do with the client can be done directly using the \fBomshell(1)\fR command, rather than having to write a special program. .SH THE CONTROL OBJECT The control object allows you to shut the client down, releasing all leases that it holds and deleting any DNS records it may have added. It also allows you to pause the client - this unconfigures any interfaces the client is using. You can then restart it, which causes it to reconfigure those interfaces. You would normally pause the client prior to going into hibernation or sleep on a laptop computer. You would then resume it after the power comes back. This allows PC cards to be shut down while the computer is hibernating or sleeping, and then reinitialized to their previous state once the computer comes out of hibernation or sleep. .PP The control object has one attribute - the state attribute. To shut the client down, set its state attribute to 2. It will automatically do a DHCPRELEASE. To pause it, set its state attribute to 3. To resume it, set its state attribute to 4. .PP .SH ENVIRONMENT VARIABLES .PP The following environment variables may be defined to override the builtin defaults for file locations. Note that use of the related command-line options will ignore the corresponding environment variable settings. .TP .B PATH_DHCLIENT_CONF The dhclient.conf configuration file. .TP .B PATH_DHCLIENT_DB The dhclient.leases database. .TP .B PATH_DHCLIENT_PID The dhclient PID file. .TP .B PATH_DHCLIENT_SCRIPT The dhclient-script file. .PP .SH FILES .B CLIENTBINDIR/dhclient-script, .B ETCDIR/dhclient.conf, DBDIR/dhclient.leases, RUNDIR/dhclient.pid, .B DBDIR/dhclient.leases~. .SH SEE ALSO dhcpd(8), dhcrelay(8), dhclient-script(8), dhclient.conf(5), dhclient.leases(5), dhcp-eval(5). .SH AUTHOR .B dhclient(8) has been written for Internet Systems Consortium by Ted Lemon in cooperation with Vixie Enterprises. To learn more about Internet Systems Consortium, see .B https://www.isc.org To learn more about Vixie Enterprises, see .B http://www.vix.com. .PP This client was substantially modified and enhanced by Elliot Poger for use on Linux while he was working on the MosquitoNet project at Stanford. .PP The current version owes much to Elliot's Linux enhancements, but was substantially reorganized and partially rewritten by Ted Lemon so as to use the same networking framework that the Internet Systems Consortium DHCP server uses. Much system-specific configuration code was moved into a shell script so that as support for more operating systems is added, it will not be necessary to port and maintain system-specific configuration code to these operating systems - instead, the shell script can invoke the native tools to accomplish the same purpose. .PP dhcp-4.2.4/client/dhclient.c000644 000765 000024 00000345661 11741366354 015634 0ustar00sarstaff000000 000000 /* dhclient.c DHCP Client. */ /* * Copyright (c) 2004-2012 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1995-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * * https://www.isc.org/ * * This code is based on the original client state machine that was * written by Elliot Poger. The code has been extensively hacked on * by Ted Lemon since then, so any mistakes you find are probably his * fault and not Elliot's. */ #include "dhcpd.h" #include #include #include #include #include #include #include TIME default_lease_time = 43200; /* 12 hours... */ TIME max_lease_time = 86400; /* 24 hours... */ const char *path_dhclient_conf = _PATH_DHCLIENT_CONF; const char *path_dhclient_db = NULL; const char *path_dhclient_pid = NULL; static char path_dhclient_script_array[] = _PATH_DHCLIENT_SCRIPT; char *path_dhclient_script = path_dhclient_script_array; /* False (default) => we write and use a pid file */ isc_boolean_t no_pid_file = ISC_FALSE; int dhcp_max_agent_option_packet_length = 0; int interfaces_requested = 0; struct iaddr iaddr_broadcast = { 4, { 255, 255, 255, 255 } }; struct iaddr iaddr_any = { 4, { 0, 0, 0, 0 } }; struct in_addr inaddr_any; struct sockaddr_in sockaddr_broadcast; struct in_addr giaddr; struct data_string default_duid; int duid_type = 0; /* ASSERT_STATE() does nothing now; it used to be assert (state_is == state_shouldbe). */ #define ASSERT_STATE(state_is, state_shouldbe) {} static const char copyright[] = "Copyright 2004-2012 Internet Systems Consortium."; static const char arr [] = "All rights reserved."; static const char message [] = "Internet Systems Consortium DHCP Client"; static const char url [] = "For info, please visit https://www.isc.org/software/dhcp/"; u_int16_t local_port = 0; u_int16_t remote_port = 0; int no_daemon = 0; struct string_list *client_env = NULL; int client_env_count = 0; int onetry = 0; int quiet = 1; int nowait = 0; int stateless = 0; int wanted_ia_na = -1; /* the absolute value is the real one. */ int wanted_ia_ta = 0; int wanted_ia_pd = 0; char *mockup_relay = NULL; void run_stateless(int exit_mode); static void usage(void); static isc_result_t write_duid(struct data_string *duid); static void add_reject(struct packet *packet); static int check_domain_name(const char *ptr, size_t len, int dots); static int check_domain_name_list(const char *ptr, size_t len, int dots); static int check_option_values(struct universe *universe, unsigned int opt, const char *ptr, size_t len); int main(int argc, char **argv) { int fd; int i; struct interface_info *ip; struct client_state *client; unsigned seed; char *server = NULL; isc_result_t status; int exit_mode = 0; int release_mode = 0; struct timeval tv; omapi_object_t *listener; isc_result_t result; int persist = 0; int no_dhclient_conf = 0; int no_dhclient_db = 0; int no_dhclient_pid = 0; int no_dhclient_script = 0; #ifdef DHCPv6 int local_family_set = 0; #endif /* DHCPv6 */ char *s; /* Initialize client globals. */ memset(&default_duid, 0, sizeof(default_duid)); /* Make sure that file descriptors 0 (stdin), 1, (stdout), and 2 (stderr) are open. To do this, we assume that when we open a file the lowest available file descriptor is used. */ fd = open("/dev/null", O_RDWR); if (fd == 0) fd = open("/dev/null", O_RDWR); if (fd == 1) fd = open("/dev/null", O_RDWR); if (fd == 2) log_perror = 0; /* No sense logging to /dev/null. */ else if (fd != -1) close(fd); openlog("dhclient", LOG_NDELAY, LOG_DAEMON); #if !(defined(DEBUG) || defined(__CYGWIN32__)) setlogmask(LOG_UPTO(LOG_INFO)); #endif /* Set up the isc and dns library managers */ status = dhcp_context_create(); if (status != ISC_R_SUCCESS) log_fatal("Can't initialize context: %s", isc_result_totext(status)); /* Set up the OMAPI. */ status = omapi_init(); if (status != ISC_R_SUCCESS) log_fatal("Can't initialize OMAPI: %s", isc_result_totext(status)); /* Set up the OMAPI wrappers for various server database internal objects. */ dhcp_common_objects_setup(); dhcp_interface_discovery_hook = dhclient_interface_discovery_hook; dhcp_interface_shutdown_hook = dhclient_interface_shutdown_hook; dhcp_interface_startup_hook = dhclient_interface_startup_hook; for (i = 1; i < argc; i++) { if (!strcmp(argv[i], "-r")) { release_mode = 1; no_daemon = 1; #ifdef DHCPv6 } else if (!strcmp(argv[i], "-4")) { if (local_family_set && local_family != AF_INET) log_fatal("Client can only do v4 or v6, not " "both."); local_family_set = 1; local_family = AF_INET; } else if (!strcmp(argv[i], "-6")) { if (local_family_set && local_family != AF_INET6) log_fatal("Client can only do v4 or v6, not " "both."); local_family_set = 1; local_family = AF_INET6; #endif /* DHCPv6 */ } else if (!strcmp(argv[i], "-x")) { /* eXit, no release */ release_mode = 0; no_daemon = 0; exit_mode = 1; } else if (!strcmp(argv[i], "-p")) { if (++i == argc) usage(); local_port = validate_port(argv[i]); log_debug("binding to user-specified port %d", ntohs(local_port)); } else if (!strcmp(argv[i], "-d")) { no_daemon = 1; quiet = 0; } else if (!strcmp(argv[i], "-pf")) { if (++i == argc) usage(); path_dhclient_pid = argv[i]; no_dhclient_pid = 1; } else if (!strcmp(argv[i], "--no-pid")) { no_pid_file = ISC_TRUE; } else if (!strcmp(argv[i], "-cf")) { if (++i == argc) usage(); path_dhclient_conf = argv[i]; no_dhclient_conf = 1; } else if (!strcmp(argv[i], "-lf")) { if (++i == argc) usage(); path_dhclient_db = argv[i]; no_dhclient_db = 1; } else if (!strcmp(argv[i], "-sf")) { if (++i == argc) usage(); path_dhclient_script = argv[i]; no_dhclient_script = 1; } else if (!strcmp(argv[i], "-1")) { onetry = 1; } else if (!strcmp(argv[i], "-q")) { quiet = 1; } else if (!strcmp(argv[i], "-s")) { if (++i == argc) usage(); server = argv[i]; } else if (!strcmp(argv[i], "-g")) { if (++i == argc) usage(); mockup_relay = argv[i]; } else if (!strcmp(argv[i], "-nw")) { nowait = 1; } else if (!strcmp(argv[i], "-n")) { /* do not start up any interfaces */ interfaces_requested = -1; } else if (!strcmp(argv[i], "-w")) { /* do not exit if there are no broadcast interfaces. */ persist = 1; } else if (!strcmp(argv[i], "-e")) { struct string_list *tmp; if (++i == argc) usage(); tmp = dmalloc(strlen(argv[i]) + sizeof *tmp, MDL); if (!tmp) log_fatal("No memory for %s", argv[i]); strcpy(tmp->string, argv[i]); tmp->next = client_env; client_env = tmp; client_env_count++; #ifdef DHCPv6 } else if (!strcmp(argv[i], "-S")) { if (local_family_set && (local_family == AF_INET)) { usage(); } local_family_set = 1; local_family = AF_INET6; wanted_ia_na = 0; stateless = 1; } else if (!strcmp(argv[i], "-N")) { if (local_family_set && (local_family == AF_INET)) { usage(); } local_family_set = 1; local_family = AF_INET6; if (wanted_ia_na < 0) { wanted_ia_na = 0; } wanted_ia_na++; } else if (!strcmp(argv[i], "-T")) { if (local_family_set && (local_family == AF_INET)) { usage(); } local_family_set = 1; local_family = AF_INET6; if (wanted_ia_na < 0) { wanted_ia_na = 0; } wanted_ia_ta++; } else if (!strcmp(argv[i], "-P")) { if (local_family_set && (local_family == AF_INET)) { usage(); } local_family_set = 1; local_family = AF_INET6; if (wanted_ia_na < 0) { wanted_ia_na = 0; } wanted_ia_pd++; } else if (!strcmp(argv[i], "-D")) { if (local_family_set && (local_family == AF_INET)) { usage(); } local_family_set = 1; local_family = AF_INET6; if (++i == argc) usage(); if (!strcasecmp(argv[i], "LL")) { duid_type = DUID_LL; } else if (!strcasecmp(argv[i], "LLT")) { duid_type = DUID_LLT; } else { usage(); } #endif /* DHCPv6 */ } else if (!strcmp(argv[i], "-v")) { quiet = 0; } else if (!strcmp(argv[i], "--version")) { log_info("isc-dhclient-%s", PACKAGE_VERSION); exit(0); } else if (argv[i][0] == '-') { usage(); } else if (interfaces_requested < 0) { usage(); } else { struct interface_info *tmp = NULL; status = interface_allocate(&tmp, MDL); if (status != ISC_R_SUCCESS) log_fatal("Can't record interface %s:%s", argv[i], isc_result_totext(status)); if (strlen(argv[i]) >= sizeof(tmp->name)) log_fatal("%s: interface name too long (is %ld)", argv[i], (long)strlen(argv[i])); strcpy(tmp->name, argv[i]); if (interfaces) { interface_reference(&tmp->next, interfaces, MDL); interface_dereference(&interfaces, MDL); } interface_reference(&interfaces, tmp, MDL); tmp->flags = INTERFACE_REQUESTED; interfaces_requested++; } } if (wanted_ia_na < 0) { wanted_ia_na = 1; } /* Support only one (requested) interface for Prefix Delegation. */ if (wanted_ia_pd && (interfaces_requested != 1)) { usage(); } if (!no_dhclient_conf && (s = getenv("PATH_DHCLIENT_CONF"))) { path_dhclient_conf = s; } if (!no_dhclient_db && (s = getenv("PATH_DHCLIENT_DB"))) { path_dhclient_db = s; } if (!no_dhclient_pid && (s = getenv("PATH_DHCLIENT_PID"))) { path_dhclient_pid = s; } if (!no_dhclient_script && (s = getenv("PATH_DHCLIENT_SCRIPT"))) { path_dhclient_script = s; } /* Set up the initial dhcp option universe. */ initialize_common_option_spaces(); /* Assign v4 or v6 specific running parameters. */ if (local_family == AF_INET) dhcpv4_client_assignments(); #ifdef DHCPv6 else if (local_family == AF_INET6) dhcpv6_client_assignments(); #endif /* DHCPv6 */ else log_fatal("Impossible condition at %s:%d.", MDL); /* * convert relative path names to absolute, for files that need * to be reopened after chdir() has been called */ if (path_dhclient_db[0] != '/') { char *path = dmalloc(PATH_MAX, MDL); if (path == NULL) log_fatal("No memory for filename\n"); path_dhclient_db = realpath(path_dhclient_db, path); if (path_dhclient_db == NULL) log_fatal("%s: %s", path, strerror(errno)); } if (path_dhclient_script[0] != '/') { char *path = dmalloc(PATH_MAX, MDL); if (path == NULL) log_fatal("No memory for filename\n"); path_dhclient_script = realpath(path_dhclient_script, path); if (path_dhclient_script == NULL) log_fatal("%s: %s", path, strerror(errno)); } /* * See if we should kill off any currently running client * we don't try to kill it off if the user told us not * to write a pid file - we assume they are controlling * the process in some other fashion. */ if ((release_mode || exit_mode) && (no_pid_file == ISC_FALSE)) { FILE *pidfd; pid_t oldpid; long temp; int e; oldpid = 0; if ((pidfd = fopen(path_dhclient_pid, "r")) != NULL) { e = fscanf(pidfd, "%ld\n", &temp); oldpid = (pid_t)temp; if (e != 0 && e != EOF) { if (oldpid) kill(oldpid, SIGTERM); } fclose(pidfd); } } if (!quiet) { log_info("%s %s", message, PACKAGE_VERSION); log_info(copyright); log_info(arr); log_info(url); log_info("%s", ""); } else { log_perror = 0; quiet_interface_discovery = 1; } /* If we're given a relay agent address to insert, for testing purposes, figure out what it is. */ if (mockup_relay) { if (!inet_aton(mockup_relay, &giaddr)) { struct hostent *he; he = gethostbyname(mockup_relay); if (he) { memcpy(&giaddr, he->h_addr_list[0], sizeof giaddr); } else { log_fatal("%s: no such host", mockup_relay); } } } /* Get the current time... */ gettimeofday(&cur_tv, NULL); sockaddr_broadcast.sin_family = AF_INET; sockaddr_broadcast.sin_port = remote_port; if (server) { if (!inet_aton(server, &sockaddr_broadcast.sin_addr)) { struct hostent *he; he = gethostbyname(server); if (he) { memcpy(&sockaddr_broadcast.sin_addr, he->h_addr_list[0], sizeof sockaddr_broadcast.sin_addr); } else sockaddr_broadcast.sin_addr.s_addr = INADDR_BROADCAST; } } else { sockaddr_broadcast.sin_addr.s_addr = INADDR_BROADCAST; } inaddr_any.s_addr = INADDR_ANY; /* Stateless special case. */ if (stateless) { if (release_mode || (wanted_ia_na > 0) || wanted_ia_ta || wanted_ia_pd || (interfaces_requested != 1)) { usage(); } run_stateless(exit_mode); return 0; } /* Discover all the network interfaces. */ discover_interfaces(DISCOVER_UNCONFIGURED); /* Parse the dhclient.conf file. */ read_client_conf(); /* Parse the lease database. */ read_client_leases(); /* Rewrite the lease database... */ rewrite_client_leases(); /* XXX */ /* config_counter(&snd_counter, &rcv_counter); */ /* * If no broadcast interfaces were discovered, call the script * and tell it so. */ if (!interfaces) { /* * Call dhclient-script with the NBI flag, * in case somebody cares. */ script_init(NULL, "NBI", NULL); script_go(NULL); /* * If we haven't been asked to persist, waiting for new * interfaces, then just exit. */ if (!persist) { /* Nothing more to do. */ log_info("No broadcast interfaces found - exiting."); exit(0); } } else if (!release_mode && !exit_mode) { /* Call the script with the list of interfaces. */ for (ip = interfaces; ip; ip = ip->next) { /* * If interfaces were specified, don't configure * interfaces that weren't specified! */ if ((interfaces_requested > 0) && ((ip->flags & (INTERFACE_REQUESTED | INTERFACE_AUTOMATIC)) != INTERFACE_REQUESTED)) continue; if (local_family == AF_INET6) { script_init(ip->client, "PREINIT6", NULL); } else { script_init(ip->client, "PREINIT", NULL); if (ip->client->alias != NULL) script_write_params(ip->client, "alias_", ip->client->alias); } script_go(ip->client); } } /* At this point, all the interfaces that the script thinks are relevant should be running, so now we once again call discover_interfaces(), and this time ask it to actually set up the interfaces. */ discover_interfaces(interfaces_requested != 0 ? DISCOVER_REQUESTED : DISCOVER_RUNNING); /* Make up a seed for the random number generator from current time plus the sum of the last four bytes of each interface's hardware address interpreted as an integer. Not much entropy, but we're booting, so we're not likely to find anything better. */ seed = 0; for (ip = interfaces; ip; ip = ip->next) { int junk; memcpy(&junk, &ip->hw_address.hbuf[ip->hw_address.hlen - sizeof seed], sizeof seed); seed += junk; } srandom(seed + cur_time + (unsigned)getpid()); /* Start a configuration state machine for each interface. */ #ifdef DHCPv6 if (local_family == AF_INET6) { /* Establish a default DUID. This may be moved to the * DHCPv4 area later. */ if (default_duid.len == 0) { if (default_duid.buffer != NULL) data_string_forget(&default_duid, MDL); form_duid(&default_duid, MDL); write_duid(&default_duid); } for (ip = interfaces ; ip != NULL ; ip = ip->next) { for (client = ip->client ; client != NULL ; client = client->next) { if (release_mode) { start_release6(client); continue; } else if (exit_mode) { unconfigure6(client, "STOP6"); continue; } /* If we have a previous binding, Confirm * that we can (or can't) still use it. */ if ((client->active_lease != NULL) && !client->active_lease->released) start_confirm6(client); else start_init6(client); } } } else #endif /* DHCPv6 */ { for (ip = interfaces ; ip ; ip = ip->next) { ip->flags |= INTERFACE_RUNNING; for (client = ip->client ; client ; client = client->next) { if (exit_mode) state_stop(client); else if (release_mode) do_release(client); else { client->state = S_INIT; if (top_level_config.initial_delay>0) { tv.tv_sec = 0; if (top_level_config. initial_delay>1) tv.tv_sec = cur_time + random() % (top_level_config. initial_delay-1); tv.tv_usec = random() % 1000000; /* * this gives better * distribution than just *whole seconds */ add_timeout(&tv, state_reboot, client, 0, 0); } else { state_reboot(client); } } } } } if (exit_mode) return 0; if (release_mode) { #ifndef DHCPv6 return 0; #else if (local_family == AF_INET6) { if (onetry) return 0; } else return 0; #endif /* DHCPv6 */ } /* Start up a listener for the object management API protocol. */ if (top_level_config.omapi_port != -1) { listener = NULL; result = omapi_generic_new(&listener, MDL); if (result != ISC_R_SUCCESS) log_fatal("Can't allocate new generic object: %s\n", isc_result_totext(result)); result = omapi_protocol_listen(listener, (unsigned) top_level_config.omapi_port, 1); if (result != ISC_R_SUCCESS) log_fatal("Can't start OMAPI protocol: %s", isc_result_totext (result)); } /* Set up the bootp packet handler... */ bootp_packet_handler = do_packet; #ifdef DHCPv6 dhcpv6_packet_handler = do_packet6; #endif /* DHCPv6 */ #if defined(DEBUG_MEMORY_LEAKAGE) || defined(DEBUG_MALLOC_POOL) || \ defined(DEBUG_MEMORY_LEAKAGE_ON_EXIT) dmalloc_cutoff_generation = dmalloc_generation; dmalloc_longterm = dmalloc_outstanding; dmalloc_outstanding = 0; #endif /* If we're not supposed to wait before getting the address, don't. */ if (nowait) go_daemon(); /* If we're not going to daemonize, write the pid file now. */ if (no_daemon || nowait) write_client_pid_file(); /* Start dispatching packets and timeouts... */ dispatch(); /*NOTREACHED*/ return 0; } static void usage() { log_info("%s %s", message, PACKAGE_VERSION); log_info(copyright); log_info(arr); log_info(url); log_fatal("Usage: dhclient " #ifdef DHCPv6 "[-4|-6] [-SNTP1dvrx] [-nw] [-p ] [-D LL|LLT]\n" #else /* DHCPv6 */ "[-1dvrx] [-nw] [-p ]\n" #endif /* DHCPv6 */ " [-s server-addr] [-cf config-file] " "[-lf lease-file]\n" " [-pf pid-file] [--no-pid] [-e VAR=val]\n" " [-sf script-file] [interface]"); } void run_stateless(int exit_mode) { #ifdef DHCPv6 struct client_state *client; omapi_object_t *listener; isc_result_t result; /* Discover the network interface. */ discover_interfaces(DISCOVER_REQUESTED); if (!interfaces) usage(); /* Parse the dhclient.conf file. */ read_client_conf(); /* Parse the lease database. */ read_client_leases(); /* Establish a default DUID. */ if (default_duid.len == 0) { if (default_duid.buffer != NULL) data_string_forget(&default_duid, MDL); form_duid(&default_duid, MDL); } /* Start a configuration state machine. */ for (client = interfaces->client ; client != NULL ; client = client->next) { if (exit_mode) { unconfigure6(client, "STOP6"); continue; } start_info_request6(client); } if (exit_mode) return; /* Start up a listener for the object management API protocol. */ if (top_level_config.omapi_port != -1) { listener = NULL; result = omapi_generic_new(&listener, MDL); if (result != ISC_R_SUCCESS) log_fatal("Can't allocate new generic object: %s\n", isc_result_totext(result)); result = omapi_protocol_listen(listener, (unsigned) top_level_config.omapi_port, 1); if (result != ISC_R_SUCCESS) log_fatal("Can't start OMAPI protocol: %s", isc_result_totext(result)); } /* Set up the packet handler... */ dhcpv6_packet_handler = do_packet6; #if defined(DEBUG_MEMORY_LEAKAGE) || defined(DEBUG_MALLOC_POOL) || \ defined(DEBUG_MEMORY_LEAKAGE_ON_EXIT) dmalloc_cutoff_generation = dmalloc_generation; dmalloc_longterm = dmalloc_outstanding; dmalloc_outstanding = 0; #endif /* If we're not supposed to wait before getting the address, don't. */ if (nowait) go_daemon(); /* If we're not going to daemonize, write the pid file now. */ if (no_daemon || nowait) write_client_pid_file(); /* Start dispatching packets and timeouts... */ dispatch(); /*NOTREACHED*/ #endif /* DHCPv6 */ return; } isc_result_t find_class (struct class **c, const char *s, const char *file, int line) { return 0; } int check_collection (packet, lease, collection) struct packet *packet; struct lease *lease; struct collection *collection; { return 0; } void classify (packet, class) struct packet *packet; struct class *class; { } int unbill_class (lease, class) struct lease *lease; struct class *class; { return 0; } int find_subnet (struct subnet **sp, struct iaddr addr, const char *file, int line) { return 0; } /* Individual States: * * Each routine is called from the dhclient_state_machine() in one of * these conditions: * -> entering INIT state * -> recvpacket_flag == 0: timeout in this state * -> otherwise: received a packet in this state * * Return conditions as handled by dhclient_state_machine(): * Returns 1, sendpacket_flag = 1: send packet, reset timer. * Returns 1, sendpacket_flag = 0: just reset the timer (wait for a milestone). * Returns 0: finish the nap which was interrupted for no good reason. * * Several per-interface variables are used to keep track of the process: * active_lease: the lease that is being used on the interface * (null pointer if not configured yet). * offered_leases: leases corresponding to DHCPOFFER messages that have * been sent to us by DHCP servers. * acked_leases: leases corresponding to DHCPACK messages that have been * sent to us by DHCP servers. * sendpacket: DHCP packet we're trying to send. * destination: IP address to send sendpacket to * In addition, there are several relevant per-lease variables. * T1_expiry, T2_expiry, lease_expiry: lease milestones * In the active lease, these control the process of renewing the lease; * In leases on the acked_leases list, this simply determines when we * can no longer legitimately use the lease. */ void state_reboot (cpp) void *cpp; { struct client_state *client = cpp; /* If we don't remember an active lease, go straight to INIT. */ if (!client -> active || client -> active -> is_bootp || client -> active -> expiry <= cur_time) { state_init (client); return; } /* We are in the rebooting state. */ client -> state = S_REBOOTING; /* * make_request doesn't initialize xid because it normally comes * from the DHCPDISCOVER, but we haven't sent a DHCPDISCOVER, * so pick an xid now. */ client -> xid = random (); /* * Make a DHCPREQUEST packet, and set * appropriate per-interface flags. */ make_request (client, client -> active); client -> destination = iaddr_broadcast; client -> first_sending = cur_time; client -> interval = client -> config -> initial_interval; /* Zap the medium list... */ client -> medium = NULL; /* Send out the first DHCPREQUEST packet. */ send_request (client); } /* Called when a lease has completely expired and we've been unable to renew it. */ void state_init (cpp) void *cpp; { struct client_state *client = cpp; ASSERT_STATE(state, S_INIT); /* Make a DHCPDISCOVER packet, and set appropriate per-interface flags. */ make_discover (client, client -> active); client -> xid = client -> packet.xid; client -> destination = iaddr_broadcast; client -> state = S_SELECTING; client -> first_sending = cur_time; client -> interval = client -> config -> initial_interval; /* Add an immediate timeout to cause the first DHCPDISCOVER packet to go out. */ send_discover (client); } /* * state_selecting is called when one or more DHCPOFFER packets have been * received and a configurable period of time has passed. */ void state_selecting (cpp) void *cpp; { struct client_state *client = cpp; struct client_lease *lp, *next, *picked; ASSERT_STATE(state, S_SELECTING); /* * Cancel state_selecting and send_discover timeouts, since either * one could have got us here. */ cancel_timeout (state_selecting, client); cancel_timeout (send_discover, client); /* * We have received one or more DHCPOFFER packets. Currently, * the only criterion by which we judge leases is whether or * not we get a response when we arp for them. */ picked = NULL; for (lp = client -> offered_leases; lp; lp = next) { next = lp -> next; /* * Check to see if we got an ARPREPLY for the address * in this particular lease. */ if (!picked) { picked = lp; picked -> next = NULL; } else { destroy_client_lease (lp); } } client -> offered_leases = NULL; /* * If we just tossed all the leases we were offered, go back * to square one. */ if (!picked) { client -> state = S_INIT; state_init (client); return; } /* If it was a BOOTREPLY, we can just take the address right now. */ if (picked -> is_bootp) { client -> new = picked; /* Make up some lease expiry times XXX these should be configurable. */ client -> new -> expiry = cur_time + 12000; client -> new -> renewal += cur_time + 8000; client -> new -> rebind += cur_time + 10000; client -> state = S_REQUESTING; /* Bind to the address we received. */ bind_lease (client); return; } /* Go to the REQUESTING state. */ client -> destination = iaddr_broadcast; client -> state = S_REQUESTING; client -> first_sending = cur_time; client -> interval = client -> config -> initial_interval; /* Make a DHCPREQUEST packet from the lease we picked. */ make_request (client, picked); client -> xid = client -> packet.xid; /* Toss the lease we picked - we'll get it back in a DHCPACK. */ destroy_client_lease (picked); /* Add an immediate timeout to send the first DHCPREQUEST packet. */ send_request (client); } /* state_requesting is called when we receive a DHCPACK message after having sent out one or more DHCPREQUEST packets. */ void dhcpack (packet) struct packet *packet; { struct interface_info *ip = packet -> interface; struct client_state *client; struct client_lease *lease; struct option_cache *oc; struct data_string ds; /* If we're not receptive to an offer right now, or if the offer has an unrecognizable transaction id, then just drop it. */ for (client = ip -> client; client; client = client -> next) { if (client -> xid == packet -> raw -> xid) break; } if (!client || (packet -> interface -> hw_address.hlen - 1 != packet -> raw -> hlen) || (memcmp (&packet -> interface -> hw_address.hbuf [1], packet -> raw -> chaddr, packet -> raw -> hlen))) { #if defined (DEBUG) log_debug ("DHCPACK in wrong transaction."); #endif return; } if (client -> state != S_REBOOTING && client -> state != S_REQUESTING && client -> state != S_RENEWING && client -> state != S_REBINDING) { #if defined (DEBUG) log_debug ("DHCPACK in wrong state."); #endif return; } log_info ("DHCPACK from %s", piaddr (packet -> client_addr)); lease = packet_to_lease (packet, client); if (!lease) { log_info ("packet_to_lease failed."); return; } client -> new = lease; /* Stop resending DHCPREQUEST. */ cancel_timeout (send_request, client); /* Figure out the lease time. */ oc = lookup_option (&dhcp_universe, client -> new -> options, DHO_DHCP_LEASE_TIME); memset (&ds, 0, sizeof ds); if (oc && evaluate_option_cache (&ds, packet, (struct lease *)0, client, packet -> options, client -> new -> options, &global_scope, oc, MDL)) { if (ds.len > 3) client -> new -> expiry = getULong (ds.data); else client -> new -> expiry = 0; data_string_forget (&ds, MDL); } else client -> new -> expiry = 0; if (client->new->expiry == 0) { struct timeval tv; log_error ("no expiry time on offered lease."); /* Quench this (broken) server. Return to INIT to reselect. */ add_reject(packet); /* 1/2 second delay to restart at INIT. */ tv.tv_sec = cur_tv.tv_sec; tv.tv_usec = cur_tv.tv_usec + 500000; if (tv.tv_usec >= 1000000) { tv.tv_sec++; tv.tv_usec -= 1000000; } add_timeout(&tv, state_init, client, 0, 0); return; } /* * A number that looks negative here is really just very large, * because the lease expiry offset is unsigned. */ if (client->new->expiry < 0) client->new->expiry = TIME_MAX; /* Take the server-provided renewal time if there is one. */ oc = lookup_option (&dhcp_universe, client -> new -> options, DHO_DHCP_RENEWAL_TIME); if (oc && evaluate_option_cache (&ds, packet, (struct lease *)0, client, packet -> options, client -> new -> options, &global_scope, oc, MDL)) { if (ds.len > 3) client -> new -> renewal = getULong (ds.data); else client -> new -> renewal = 0; data_string_forget (&ds, MDL); } else client -> new -> renewal = 0; /* If it wasn't specified by the server, calculate it. */ if (!client -> new -> renewal) client -> new -> renewal = client -> new -> expiry / 2 + 1; if (client -> new -> renewal <= 0) client -> new -> renewal = TIME_MAX; /* Now introduce some randomness to the renewal time: */ if (client->new->renewal <= ((TIME_MAX / 3) - 3)) client->new->renewal = (((client->new->renewal * 3) + 3) / 4) + (((random() % client->new->renewal) + 3) / 4); /* Same deal with the rebind time. */ oc = lookup_option (&dhcp_universe, client -> new -> options, DHO_DHCP_REBINDING_TIME); if (oc && evaluate_option_cache (&ds, packet, (struct lease *)0, client, packet -> options, client -> new -> options, &global_scope, oc, MDL)) { if (ds.len > 3) client -> new -> rebind = getULong (ds.data); else client -> new -> rebind = 0; data_string_forget (&ds, MDL); } else client -> new -> rebind = 0; if (client -> new -> rebind <= 0) { if (client -> new -> expiry <= TIME_MAX / 7) client -> new -> rebind = client -> new -> expiry * 7 / 8; else client -> new -> rebind = client -> new -> expiry / 8 * 7; } /* Make sure our randomness didn't run the renewal time past the rebind time. */ if (client -> new -> renewal > client -> new -> rebind) { if (client -> new -> rebind <= TIME_MAX / 3) client -> new -> renewal = client -> new -> rebind * 3 / 4; else client -> new -> renewal = client -> new -> rebind / 4 * 3; } client -> new -> expiry += cur_time; /* Lease lengths can never be negative. */ if (client -> new -> expiry < cur_time) client -> new -> expiry = TIME_MAX; client -> new -> renewal += cur_time; if (client -> new -> renewal < cur_time) client -> new -> renewal = TIME_MAX; client -> new -> rebind += cur_time; if (client -> new -> rebind < cur_time) client -> new -> rebind = TIME_MAX; bind_lease (client); } void bind_lease (client) struct client_state *client; { struct timeval tv; /* Remember the medium. */ client -> new -> medium = client -> medium; /* Run the client script with the new parameters. */ script_init (client, (client -> state == S_REQUESTING ? "BOUND" : (client -> state == S_RENEWING ? "RENEW" : (client -> state == S_REBOOTING ? "REBOOT" : "REBIND"))), client -> new -> medium); if (client -> active && client -> state != S_REBOOTING) script_write_params (client, "old_", client -> active); script_write_params (client, "new_", client -> new); if (client -> alias) script_write_params (client, "alias_", client -> alias); /* If the BOUND/RENEW code detects another machine using the offered address, it exits nonzero. We need to send a DHCPDECLINE and toss the lease. */ if (script_go (client)) { make_decline (client, client -> new); send_decline (client); destroy_client_lease (client -> new); client -> new = (struct client_lease *)0; state_init (client); return; } /* Write out the new lease if it has been long enough. */ if (!client->last_write || (cur_time - client->last_write) >= MIN_LEASE_WRITE) write_client_lease(client, client->new, 0, 0); /* Replace the old active lease with the new one. */ if (client -> active) destroy_client_lease (client -> active); client -> active = client -> new; client -> new = (struct client_lease *)0; /* Set up a timeout to start the renewal process. */ tv.tv_sec = client->active->renewal; tv.tv_usec = ((client->active->renewal - cur_tv.tv_sec) > 1) ? random() % 1000000 : cur_tv.tv_usec; add_timeout(&tv, state_bound, client, 0, 0); log_info ("bound to %s -- renewal in %ld seconds.", piaddr (client -> active -> address), (long)(client -> active -> renewal - cur_time)); client -> state = S_BOUND; reinitialize_interfaces (); go_daemon (); #if defined (NSUPDATE) if (client->config->do_forward_update) dhclient_schedule_updates(client, &client->active->address, 1); #endif } /* state_bound is called when we've successfully bound to a particular lease, but the renewal time on that lease has expired. We are expected to unicast a DHCPREQUEST to the server that gave us our original lease. */ void state_bound (cpp) void *cpp; { struct client_state *client = cpp; struct option_cache *oc; struct data_string ds; ASSERT_STATE(state, S_BOUND); /* T1 has expired. */ make_request (client, client -> active); client -> xid = client -> packet.xid; memset (&ds, 0, sizeof ds); oc = lookup_option (&dhcp_universe, client -> active -> options, DHO_DHCP_SERVER_IDENTIFIER); if (oc && evaluate_option_cache (&ds, (struct packet *)0, (struct lease *)0, client, (struct option_state *)0, client -> active -> options, &global_scope, oc, MDL)) { if (ds.len > 3) { memcpy (client -> destination.iabuf, ds.data, 4); client -> destination.len = 4; } else client -> destination = iaddr_broadcast; data_string_forget (&ds, MDL); } else client -> destination = iaddr_broadcast; client -> first_sending = cur_time; client -> interval = client -> config -> initial_interval; client -> state = S_RENEWING; /* Send the first packet immediately. */ send_request (client); } /* state_stop is called when we've been told to shut down. We unconfigure the interfaces, and then stop operating until told otherwise. */ void state_stop (cpp) void *cpp; { struct client_state *client = cpp; /* Cancel all timeouts. */ cancel_timeout(state_selecting, client); cancel_timeout(send_discover, client); cancel_timeout(send_request, client); cancel_timeout(state_bound, client); /* If we have an address, unconfigure it. */ if (client->active) { script_init(client, "STOP", client->active->medium); script_write_params(client, "old_", client->active); if (client->alias) script_write_params(client, "alias_", client->alias); script_go(client); } } int commit_leases () { return 0; } int write_lease (lease) struct lease *lease; { return 0; } int write_host (host) struct host_decl *host; { return 0; } void db_startup (testp) int testp; { } void bootp (packet) struct packet *packet; { struct iaddrmatchlist *ap; char addrbuf[4*16]; char maskbuf[4*16]; if (packet -> raw -> op != BOOTREPLY) return; /* If there's a reject list, make sure this packet's sender isn't on it. */ for (ap = packet -> interface -> client -> config -> reject_list; ap; ap = ap -> next) { if (addr_match(&packet->client_addr, &ap->match)) { /* piaddr() returns its result in a static buffer sized 4*16 (see common/inet.c). */ strcpy(addrbuf, piaddr(ap->match.addr)); strcpy(maskbuf, piaddr(ap->match.mask)); log_info("BOOTREPLY from %s rejected by rule %s " "mask %s.", piaddr(packet->client_addr), addrbuf, maskbuf); return; } } dhcpoffer (packet); } void dhcp (packet) struct packet *packet; { struct iaddrmatchlist *ap; void (*handler) (struct packet *); const char *type; char addrbuf[4*16]; char maskbuf[4*16]; switch (packet -> packet_type) { case DHCPOFFER: handler = dhcpoffer; type = "DHCPOFFER"; break; case DHCPNAK: handler = dhcpnak; type = "DHCPNACK"; break; case DHCPACK: handler = dhcpack; type = "DHCPACK"; break; default: return; } /* If there's a reject list, make sure this packet's sender isn't on it. */ for (ap = packet -> interface -> client -> config -> reject_list; ap; ap = ap -> next) { if (addr_match(&packet->client_addr, &ap->match)) { /* piaddr() returns its result in a static buffer sized 4*16 (see common/inet.c). */ strcpy(addrbuf, piaddr(ap->match.addr)); strcpy(maskbuf, piaddr(ap->match.mask)); log_info("%s from %s rejected by rule %s mask %s.", type, piaddr(packet->client_addr), addrbuf, maskbuf); return; } } (*handler) (packet); } #ifdef DHCPv6 void dhcpv6(struct packet *packet) { struct iaddrmatchlist *ap; struct client_state *client; char addrbuf[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")]; /* Silently drop bogus messages. */ if (packet->dhcpv6_msg_type >= dhcpv6_type_name_max) return; /* Discard, with log, packets from quenched sources. */ for (ap = packet->interface->client->config->reject_list ; ap ; ap = ap->next) { if (addr_match(&packet->client_addr, &ap->match)) { strcpy(addrbuf, piaddr(packet->client_addr)); log_info("%s from %s rejected by rule %s", dhcpv6_type_names[packet->dhcpv6_msg_type], addrbuf, piaddrmask(&ap->match.addr, &ap->match.mask)); return; } } /* Screen out nonsensical messages. */ switch(packet->dhcpv6_msg_type) { case DHCPV6_ADVERTISE: case DHCPV6_RECONFIGURE: if (stateless) return; /* Falls through */ case DHCPV6_REPLY: log_info("RCV: %s message on %s from %s.", dhcpv6_type_names[packet->dhcpv6_msg_type], packet->interface->name, piaddr(packet->client_addr)); break; default: return; } /* Find a client state that matches the incoming XID. */ for (client = packet->interface->client ; client ; client = client->next) { if (memcmp(&client->dhcpv6_transaction_id, packet->dhcpv6_transaction_id, 3) == 0) { client->v6_handler(packet, client); return; } } /* XXX: temporary log for debugging */ log_info("Packet received, but nothing done with it."); } #endif /* DHCPv6 */ void dhcpoffer (packet) struct packet *packet; { struct interface_info *ip = packet -> interface; struct client_state *client; struct client_lease *lease, *lp; struct option **req; int i; int stop_selecting; const char *name = packet -> packet_type ? "DHCPOFFER" : "BOOTREPLY"; char obuf [1024]; struct timeval tv; #ifdef DEBUG_PACKET dump_packet (packet); #endif /* Find a client state that matches the xid... */ for (client = ip -> client; client; client = client -> next) if (client -> xid == packet -> raw -> xid) break; /* If we're not receptive to an offer right now, or if the offer has an unrecognizable transaction id, then just drop it. */ if (!client || client -> state != S_SELECTING || (packet -> interface -> hw_address.hlen - 1 != packet -> raw -> hlen) || (memcmp (&packet -> interface -> hw_address.hbuf [1], packet -> raw -> chaddr, packet -> raw -> hlen))) { #if defined (DEBUG) log_debug ("%s in wrong transaction.", name); #endif return; } sprintf (obuf, "%s from %s", name, piaddr (packet -> client_addr)); /* If this lease doesn't supply the minimum required DHCPv4 parameters, * ignore it. */ req = client->config->required_options; if (req != NULL) { for (i = 0 ; req[i] != NULL ; i++) { if ((req[i]->universe == &dhcp_universe) && !lookup_option(&dhcp_universe, packet->options, req[i]->code)) { struct option *option = NULL; unsigned code = req[i]->code; option_code_hash_lookup(&option, dhcp_universe.code_hash, &code, 0, MDL); if (option) log_info("%s: no %s option.", obuf, option->name); else log_info("%s: no unknown-%u option.", obuf, code); option_dereference(&option, MDL); return; } } } /* If we've already seen this lease, don't record it again. */ for (lease = client -> offered_leases; lease; lease = lease -> next) { if (lease -> address.len == sizeof packet -> raw -> yiaddr && !memcmp (lease -> address.iabuf, &packet -> raw -> yiaddr, lease -> address.len)) { log_debug ("%s: already seen.", obuf); return; } } lease = packet_to_lease (packet, client); if (!lease) { log_info ("%s: packet_to_lease failed.", obuf); return; } /* If this lease was acquired through a BOOTREPLY, record that fact. */ if (!packet -> options_valid || !packet -> packet_type) lease -> is_bootp = 1; /* Record the medium under which this lease was offered. */ lease -> medium = client -> medium; /* Figure out when we're supposed to stop selecting. */ stop_selecting = (client -> first_sending + client -> config -> select_interval); /* If this is the lease we asked for, put it at the head of the list, and don't mess with the arp request timeout. */ if (lease -> address.len == client -> requested_address.len && !memcmp (lease -> address.iabuf, client -> requested_address.iabuf, client -> requested_address.len)) { lease -> next = client -> offered_leases; client -> offered_leases = lease; } else { /* Put the lease at the end of the list. */ lease -> next = (struct client_lease *)0; if (!client -> offered_leases) client -> offered_leases = lease; else { for (lp = client -> offered_leases; lp -> next; lp = lp -> next) ; lp -> next = lease; } } /* If the selecting interval has expired, go immediately to state_selecting(). Otherwise, time out into state_selecting at the select interval. */ if (stop_selecting <= cur_tv.tv_sec) state_selecting (client); else { tv.tv_sec = stop_selecting; tv.tv_usec = cur_tv.tv_usec; add_timeout(&tv, state_selecting, client, 0, 0); cancel_timeout(send_discover, client); } log_info("%s", obuf); } /* Allocate a client_lease structure and initialize it from the parameters in the specified packet. */ struct client_lease *packet_to_lease (packet, client) struct packet *packet; struct client_state *client; { struct client_lease *lease; unsigned i; struct option_cache *oc; struct option *option = NULL; struct data_string data; lease = (struct client_lease *)new_client_lease (MDL); if (!lease) { log_error ("packet_to_lease: no memory to record lease.\n"); return (struct client_lease *)0; } memset (lease, 0, sizeof *lease); /* Copy the lease options. */ option_state_reference (&lease -> options, packet -> options, MDL); lease -> address.len = sizeof (packet -> raw -> yiaddr); memcpy (lease -> address.iabuf, &packet -> raw -> yiaddr, lease -> address.len); memset (&data, 0, sizeof data); if (client -> config -> vendor_space_name) { i = DHO_VENDOR_ENCAPSULATED_OPTIONS; /* See if there was a vendor encapsulation option. */ oc = lookup_option (&dhcp_universe, lease -> options, i); if (oc && client -> config -> vendor_space_name && evaluate_option_cache (&data, packet, (struct lease *)0, client, packet -> options, lease -> options, &global_scope, oc, MDL)) { if (data.len) { if (!option_code_hash_lookup(&option, dhcp_universe.code_hash, &i, 0, MDL)) log_fatal("Unable to find VENDOR " "option (%s:%d).", MDL); parse_encapsulated_suboptions (packet -> options, option, data.data, data.len, &dhcp_universe, client -> config -> vendor_space_name ); option_dereference(&option, MDL); } data_string_forget (&data, MDL); } } else i = 0; /* Figure out the overload flag. */ oc = lookup_option (&dhcp_universe, lease -> options, DHO_DHCP_OPTION_OVERLOAD); if (oc && evaluate_option_cache (&data, packet, (struct lease *)0, client, packet -> options, lease -> options, &global_scope, oc, MDL)) { if (data.len > 0) i = data.data [0]; else i = 0; data_string_forget (&data, MDL); } else i = 0; /* If the server name was filled out, copy it. */ if (!(i & 2) && packet -> raw -> sname [0]) { unsigned len; /* Don't count on the NUL terminator. */ for (len = 0; len < DHCP_SNAME_LEN; len++) if (!packet -> raw -> sname [len]) break; lease -> server_name = dmalloc (len + 1, MDL); if (!lease -> server_name) { log_error ("dhcpoffer: no memory for server name.\n"); destroy_client_lease (lease); return (struct client_lease *)0; } else { memcpy (lease -> server_name, packet -> raw -> sname, len); lease -> server_name [len] = 0; } } /* Ditto for the filename. */ if (!(i & 1) && packet -> raw -> file [0]) { unsigned len; /* Don't count on the NUL terminator. */ for (len = 0; len < DHCP_FILE_LEN; len++) if (!packet -> raw -> file [len]) break; lease -> filename = dmalloc (len + 1, MDL); if (!lease -> filename) { log_error ("dhcpoffer: no memory for filename.\n"); destroy_client_lease (lease); return (struct client_lease *)0; } else { memcpy (lease -> filename, packet -> raw -> file, len); lease -> filename [len] = 0; } } execute_statements_in_scope ((struct binding_value **)0, (struct packet *)packet, (struct lease *)0, client, lease -> options, lease -> options, &global_scope, client -> config -> on_receipt, (struct group *)0); return lease; } void dhcpnak (packet) struct packet *packet; { struct interface_info *ip = packet -> interface; struct client_state *client; /* Find a client state that matches the xid... */ for (client = ip -> client; client; client = client -> next) if (client -> xid == packet -> raw -> xid) break; /* If we're not receptive to an offer right now, or if the offer has an unrecognizable transaction id, then just drop it. */ if (!client || (packet -> interface -> hw_address.hlen - 1 != packet -> raw -> hlen) || (memcmp (&packet -> interface -> hw_address.hbuf [1], packet -> raw -> chaddr, packet -> raw -> hlen))) { #if defined (DEBUG) log_debug ("DHCPNAK in wrong transaction."); #endif return; } if (client -> state != S_REBOOTING && client -> state != S_REQUESTING && client -> state != S_RENEWING && client -> state != S_REBINDING) { #if defined (DEBUG) log_debug ("DHCPNAK in wrong state."); #endif return; } log_info ("DHCPNAK from %s", piaddr (packet -> client_addr)); if (!client -> active) { #if defined (DEBUG) log_info ("DHCPNAK with no active lease.\n"); #endif return; } /* If we get a DHCPNAK, we use the EXPIRE dhclient-script state * to indicate that we want all old bindings to be removed. (It * is possible that we may get a NAK while in the RENEW state, * so we might have bindings active at that time) */ script_init(client, "EXPIRE", NULL); script_write_params(client, "old_", client->active); if (client->alias) script_write_params(client, "alias_", client->alias); script_go(client); destroy_client_lease (client -> active); client -> active = (struct client_lease *)0; /* Stop sending DHCPREQUEST packets... */ cancel_timeout (send_request, client); /* On some scripts, 'EXPIRE' causes the interface to be ifconfig'd * down (this expunges any routes and arp cache). This makes the * interface unusable by state_init(), which we call next. So, we * need to 'PREINIT' the interface to bring it back up. */ script_init(client, "PREINIT", NULL); if (client->alias) script_write_params(client, "alias_", client->alias); script_go(client); client -> state = S_INIT; state_init (client); } /* Send out a DHCPDISCOVER packet, and set a timeout to send out another one after the right interval has expired. If we don't get an offer by the time we reach the panic interval, call the panic function. */ void send_discover (cpp) void *cpp; { struct client_state *client = cpp; int result; int interval; int increase = 1; struct timeval tv; /* Figure out how long it's been since we started transmitting. */ interval = cur_time - client -> first_sending; /* If we're past the panic timeout, call the script and tell it we haven't found anything for this interface yet. */ if (interval > client -> config -> timeout) { state_panic (client); return; } /* If we're selecting media, try the whole list before doing the exponential backoff, but if we've already received an offer, stop looping, because we obviously have it right. */ if (!client -> offered_leases && client -> config -> media) { int fail = 0; again: if (client -> medium) { client -> medium = client -> medium -> next; increase = 0; } if (!client -> medium) { if (fail) log_fatal ("No valid media types for %s!", client -> interface -> name); client -> medium = client -> config -> media; increase = 1; } log_info ("Trying medium \"%s\" %d", client -> medium -> string, increase); script_init (client, "MEDIUM", client -> medium); if (script_go (client)) { fail = 1; goto again; } } /* If we're supposed to increase the interval, do so. If it's currently zero (i.e., we haven't sent any packets yet), set it to initial_interval; otherwise, add to it a random number between zero and two times itself. On average, this means that it will double with every transmission. */ if (increase) { if (!client->interval) client->interval = client->config->initial_interval; else client->interval += random() % (2 * client->interval); /* Don't backoff past cutoff. */ if (client->interval > client->config->backoff_cutoff) client->interval = (client->config->backoff_cutoff / 2) + (random() % client->config->backoff_cutoff); } else if (!client->interval) client->interval = client->config->initial_interval; /* If the backoff would take us to the panic timeout, just use that as the interval. */ if (cur_time + client -> interval > client -> first_sending + client -> config -> timeout) client -> interval = (client -> first_sending + client -> config -> timeout) - cur_time + 1; /* Record the number of seconds since we started sending. */ if (interval < 65536) client -> packet.secs = htons (interval); else client -> packet.secs = htons (65535); client -> secs = client -> packet.secs; log_info ("DHCPDISCOVER on %s to %s port %d interval %ld", client -> name ? client -> name : client -> interface -> name, inet_ntoa (sockaddr_broadcast.sin_addr), ntohs (sockaddr_broadcast.sin_port), (long)(client -> interval)); /* Send out a packet. */ result = send_packet(client->interface, NULL, &client->packet, client->packet_length, inaddr_any, &sockaddr_broadcast, NULL); if (result < 0) { log_error("%s:%d: Failed to send %d byte long packet over %s " "interface.", MDL, client->packet_length, client->interface->name); } /* * If we used 0 microseconds here, and there were other clients on the * same network with a synchronized local clock (ntp), and a similar * zero-microsecond-scheduler behavior, then we could be participating * in a sub-second DOS ttck. */ tv.tv_sec = cur_tv.tv_sec + client->interval; tv.tv_usec = client->interval > 1 ? random() % 1000000 : cur_tv.tv_usec; add_timeout(&tv, send_discover, client, 0, 0); } /* state_panic gets called if we haven't received any offers in a preset amount of time. When this happens, we try to use existing leases that haven't yet expired, and failing that, we call the client script and hope it can do something. */ void state_panic (cpp) void *cpp; { struct client_state *client = cpp; struct client_lease *loop; struct client_lease *lp; struct timeval tv; loop = lp = client -> active; log_info ("No DHCPOFFERS received."); /* We may not have an active lease, but we may have some predefined leases that we can try. */ if (!client -> active && client -> leases) goto activate_next; /* Run through the list of leases and see if one can be used. */ while (client -> active) { if (client -> active -> expiry > cur_time) { log_info ("Trying recorded lease %s", piaddr (client -> active -> address)); /* Run the client script with the existing parameters. */ script_init (client, "TIMEOUT", client -> active -> medium); script_write_params (client, "new_", client -> active); if (client -> alias) script_write_params (client, "alias_", client -> alias); /* If the old lease is still good and doesn't yet need renewal, go into BOUND state and timeout at the renewal time. */ if (!script_go (client)) { if (cur_time < client -> active -> renewal) { client -> state = S_BOUND; log_info ("bound: renewal in %ld %s.", (long)(client -> active -> renewal - cur_time), "seconds"); tv.tv_sec = client->active->renewal; tv.tv_usec = ((client->active->renewal - cur_time) > 1) ? random() % 1000000 : cur_tv.tv_usec; add_timeout(&tv, state_bound, client, 0, 0); } else { client -> state = S_BOUND; log_info ("bound: immediate renewal."); state_bound (client); } reinitialize_interfaces (); go_daemon (); return; } } /* If there are no other leases, give up. */ if (!client -> leases) { client -> leases = client -> active; client -> active = (struct client_lease *)0; break; } activate_next: /* Otherwise, put the active lease at the end of the lease list, and try another lease.. */ for (lp = client -> leases; lp -> next; lp = lp -> next) ; lp -> next = client -> active; if (lp -> next) { lp -> next -> next = (struct client_lease *)0; } client -> active = client -> leases; client -> leases = client -> leases -> next; /* If we already tried this lease, we've exhausted the set of leases, so we might as well give up for now. */ if (client -> active == loop) break; else if (!loop) loop = client -> active; } /* No leases were available, or what was available didn't work, so tell the shell script that we failed to allocate an address, and try again later. */ if (onetry) { if (!quiet) log_info ("Unable to obtain a lease on first try.%s", " Exiting."); exit (2); } log_info ("No working leases in persistent database - sleeping."); script_init (client, "FAIL", (struct string_list *)0); if (client -> alias) script_write_params (client, "alias_", client -> alias); script_go (client); client -> state = S_INIT; tv.tv_sec = cur_tv.tv_sec + ((client->config->retry_interval + 1) / 2 + (random() % client->config->retry_interval)); tv.tv_usec = ((tv.tv_sec - cur_tv.tv_sec) > 1) ? random() % 1000000 : cur_tv.tv_usec; add_timeout(&tv, state_init, client, 0, 0); go_daemon (); } void send_request (cpp) void *cpp; { struct client_state *client = cpp; int result; int interval; struct sockaddr_in destination; struct in_addr from; struct timeval tv; /* Figure out how long it's been since we started transmitting. */ interval = cur_time - client -> first_sending; /* If we're in the INIT-REBOOT or REQUESTING state and we're past the reboot timeout, go to INIT and see if we can DISCOVER an address... */ /* XXX In the INIT-REBOOT state, if we don't get an ACK, it means either that we're on a network with no DHCP server, or that our server is down. In the latter case, assuming that there is a backup DHCP server, DHCPDISCOVER will get us a new address, but we could also have successfully reused our old address. In the former case, we're hosed anyway. This is not a win-prone situation. */ if ((client -> state == S_REBOOTING || client -> state == S_REQUESTING) && interval > client -> config -> reboot_timeout) { cancel: client -> state = S_INIT; cancel_timeout (send_request, client); state_init (client); return; } /* If we're in the reboot state, make sure the media is set up correctly. */ if (client -> state == S_REBOOTING && !client -> medium && client -> active -> medium ) { script_init (client, "MEDIUM", client -> active -> medium); /* If the medium we chose won't fly, go to INIT state. */ if (script_go (client)) goto cancel; /* Record the medium. */ client -> medium = client -> active -> medium; } /* If the lease has expired, relinquish the address and go back to the INIT state. */ if (client -> state != S_REQUESTING && cur_time > client -> active -> expiry) { /* Run the client script with the new parameters. */ script_init (client, "EXPIRE", (struct string_list *)0); script_write_params (client, "old_", client -> active); if (client -> alias) script_write_params (client, "alias_", client -> alias); script_go (client); /* Now do a preinit on the interface so that we can discover a new address. */ script_init (client, "PREINIT", (struct string_list *)0); if (client -> alias) script_write_params (client, "alias_", client -> alias); script_go (client); client -> state = S_INIT; state_init (client); return; } /* Do the exponential backoff... */ if (!client -> interval) client -> interval = client -> config -> initial_interval; else { client -> interval += ((random () >> 2) % (2 * client -> interval)); } /* Don't backoff past cutoff. */ if (client -> interval > client -> config -> backoff_cutoff) client -> interval = ((client -> config -> backoff_cutoff / 2) + ((random () >> 2) % client -> config -> backoff_cutoff)); /* If the backoff would take us to the expiry time, just set the timeout to the expiry time. */ if (client -> state != S_REQUESTING && cur_time + client -> interval > client -> active -> expiry) client -> interval = client -> active -> expiry - cur_time + 1; /* If the lease T2 time has elapsed, or if we're not yet bound, broadcast the DHCPREQUEST rather than unicasting. */ if (client -> state == S_REQUESTING || client -> state == S_REBOOTING || cur_time > client -> active -> rebind) destination.sin_addr = sockaddr_broadcast.sin_addr; else memcpy (&destination.sin_addr.s_addr, client -> destination.iabuf, sizeof destination.sin_addr.s_addr); destination.sin_port = remote_port; destination.sin_family = AF_INET; #ifdef HAVE_SA_LEN destination.sin_len = sizeof destination; #endif if (client -> state == S_RENEWING || client -> state == S_REBINDING) memcpy (&from, client -> active -> address.iabuf, sizeof from); else from.s_addr = INADDR_ANY; /* Record the number of seconds since we started sending. */ if (client -> state == S_REQUESTING) client -> packet.secs = client -> secs; else { if (interval < 65536) client -> packet.secs = htons (interval); else client -> packet.secs = htons (65535); } log_info ("DHCPREQUEST on %s to %s port %d", client -> name ? client -> name : client -> interface -> name, inet_ntoa (destination.sin_addr), ntohs (destination.sin_port)); if (destination.sin_addr.s_addr != INADDR_BROADCAST && fallback_interface) { result = send_packet(fallback_interface, NULL, &client->packet, client->packet_length, from, &destination, NULL); if (result < 0) { log_error("%s:%d: Failed to send %d byte long packet " "over %s interface.", MDL, client->packet_length, fallback_interface->name); } } else { /* Send out a packet. */ result = send_packet(client->interface, NULL, &client->packet, client->packet_length, from, &destination, NULL); if (result < 0) { log_error("%s:%d: Failed to send %d byte long packet" " over %s interface.", MDL, client->packet_length, client->interface->name); } } tv.tv_sec = cur_tv.tv_sec + client->interval; tv.tv_usec = ((tv.tv_sec - cur_tv.tv_sec) > 1) ? random() % 1000000 : cur_tv.tv_usec; add_timeout(&tv, send_request, client, 0, 0); } void send_decline (cpp) void *cpp; { struct client_state *client = cpp; int result; log_info ("DHCPDECLINE on %s to %s port %d", client->name ? client->name : client->interface->name, inet_ntoa(sockaddr_broadcast.sin_addr), ntohs(sockaddr_broadcast.sin_port)); /* Send out a packet. */ result = send_packet(client->interface, NULL, &client->packet, client->packet_length, inaddr_any, &sockaddr_broadcast, NULL); if (result < 0) { log_error("%s:%d: Failed to send %d byte long packet over %s" " interface.", MDL, client->packet_length, client->interface->name); } } void send_release (cpp) void *cpp; { struct client_state *client = cpp; int result; struct sockaddr_in destination; struct in_addr from; memcpy (&from, client -> active -> address.iabuf, sizeof from); memcpy (&destination.sin_addr.s_addr, client -> destination.iabuf, sizeof destination.sin_addr.s_addr); destination.sin_port = remote_port; destination.sin_family = AF_INET; #ifdef HAVE_SA_LEN destination.sin_len = sizeof destination; #endif /* Set the lease to end now, so that we don't accidentally reuse it if we restart before the old expiry time. */ client -> active -> expiry = client -> active -> renewal = client -> active -> rebind = cur_time; if (!write_client_lease (client, client -> active, 1, 1)) { log_error ("Can't release lease: lease write failed."); return; } log_info ("DHCPRELEASE on %s to %s port %d", client -> name ? client -> name : client -> interface -> name, inet_ntoa (destination.sin_addr), ntohs (destination.sin_port)); if (fallback_interface) { result = send_packet(fallback_interface, NULL, &client->packet, client->packet_length, from, &destination, NULL); if (result < 0) { log_error("%s:%d: Failed to send %d byte long packet" " over %s interface.", MDL, client->packet_length, fallback_interface->name); } } else { /* Send out a packet. */ result = send_packet(client->interface, NULL, &client->packet, client->packet_length, from, &destination, NULL); if (result < 0) { log_error ("%s:%d: Failed to send %d byte long packet" " over %s interface.", MDL, client->packet_length, client->interface->name); } } } void make_client_options(struct client_state *client, struct client_lease *lease, u_int8_t *type, struct option_cache *sid, struct iaddr *rip, struct option **prl, struct option_state **op) { unsigned i; struct option_cache *oc; struct option *option = NULL; struct buffer *bp = (struct buffer *)0; /* If there are any leftover options, get rid of them. */ if (*op) option_state_dereference (op, MDL); /* Allocate space for options. */ option_state_allocate (op, MDL); /* Send the server identifier if provided. */ if (sid) save_option (&dhcp_universe, *op, sid); oc = (struct option_cache *)0; /* Send the requested address if provided. */ if (rip) { client -> requested_address = *rip; i = DHO_DHCP_REQUESTED_ADDRESS; if (!(option_code_hash_lookup(&option, dhcp_universe.code_hash, &i, 0, MDL) && make_const_option_cache(&oc, NULL, rip->iabuf, rip->len, option, MDL))) log_error ("can't make requested address cache."); else { save_option (&dhcp_universe, *op, oc); option_cache_dereference (&oc, MDL); } option_dereference(&option, MDL); } else { client -> requested_address.len = 0; } i = DHO_DHCP_MESSAGE_TYPE; if (!(option_code_hash_lookup(&option, dhcp_universe.code_hash, &i, 0, MDL) && make_const_option_cache(&oc, NULL, type, 1, option, MDL))) log_error ("can't make message type."); else { save_option (&dhcp_universe, *op, oc); option_cache_dereference (&oc, MDL); } option_dereference(&option, MDL); if (prl) { int len; /* Probe the length of the list. */ len = 0; for (i = 0 ; prl[i] != NULL ; i++) if (prl[i]->universe == &dhcp_universe) len++; if (!buffer_allocate (&bp, len, MDL)) log_error ("can't make parameter list buffer."); else { unsigned code = DHO_DHCP_PARAMETER_REQUEST_LIST; len = 0; for (i = 0 ; prl[i] != NULL ; i++) if (prl[i]->universe == &dhcp_universe) bp->data[len++] = prl[i]->code; if (!(option_code_hash_lookup(&option, dhcp_universe.code_hash, &code, 0, MDL) && make_const_option_cache(&oc, &bp, NULL, len, option, MDL))) log_error ("can't make option cache"); else { save_option (&dhcp_universe, *op, oc); option_cache_dereference (&oc, MDL); } option_dereference(&option, MDL); } } /* Run statements that need to be run on transmission. */ if (client -> config -> on_transmission) execute_statements_in_scope ((struct binding_value **)0, (struct packet *)0, (struct lease *)0, client, (lease ? lease -> options : (struct option_state *)0), *op, &global_scope, client -> config -> on_transmission, (struct group *)0); } void make_discover (client, lease) struct client_state *client; struct client_lease *lease; { unsigned char discover = DHCPDISCOVER; struct option_state *options = (struct option_state *)0; memset (&client -> packet, 0, sizeof (client -> packet)); make_client_options (client, lease, &discover, (struct option_cache *)0, lease ? &lease -> address : (struct iaddr *)0, client -> config -> requested_options, &options); /* Set up the option buffer... */ client -> packet_length = cons_options ((struct packet *)0, &client -> packet, (struct lease *)0, client, /* maximum packet size */1500, (struct option_state *)0, options, /* scope */ &global_scope, /* overload */ 0, /* terminate */0, /* bootpp */0, (struct data_string *)0, client -> config -> vendor_space_name); option_state_dereference (&options, MDL); if (client -> packet_length < BOOTP_MIN_LEN) client -> packet_length = BOOTP_MIN_LEN; client -> packet.op = BOOTREQUEST; client -> packet.htype = client -> interface -> hw_address.hbuf [0]; client -> packet.hlen = client -> interface -> hw_address.hlen - 1; client -> packet.hops = 0; client -> packet.xid = random (); client -> packet.secs = 0; /* filled in by send_discover. */ if (can_receive_unicast_unconfigured (client -> interface)) client -> packet.flags = 0; else client -> packet.flags = htons (BOOTP_BROADCAST); memset (&(client -> packet.ciaddr), 0, sizeof client -> packet.ciaddr); memset (&(client -> packet.yiaddr), 0, sizeof client -> packet.yiaddr); memset (&(client -> packet.siaddr), 0, sizeof client -> packet.siaddr); client -> packet.giaddr = giaddr; if (client -> interface -> hw_address.hlen > 0) memcpy (client -> packet.chaddr, &client -> interface -> hw_address.hbuf [1], (unsigned)(client -> interface -> hw_address.hlen - 1)); #ifdef DEBUG_PACKET dump_raw ((unsigned char *)&client -> packet, client -> packet_length); #endif } void make_request (client, lease) struct client_state *client; struct client_lease *lease; { unsigned char request = DHCPREQUEST; struct option_cache *oc; memset (&client -> packet, 0, sizeof (client -> packet)); if (client -> state == S_REQUESTING) oc = lookup_option (&dhcp_universe, lease -> options, DHO_DHCP_SERVER_IDENTIFIER); else oc = (struct option_cache *)0; if (client -> sent_options) option_state_dereference (&client -> sent_options, MDL); make_client_options (client, lease, &request, oc, ((client -> state == S_REQUESTING || client -> state == S_REBOOTING) ? &lease -> address : (struct iaddr *)0), client -> config -> requested_options, &client -> sent_options); /* Set up the option buffer... */ client -> packet_length = cons_options ((struct packet *)0, &client -> packet, (struct lease *)0, client, /* maximum packet size */1500, (struct option_state *)0, client -> sent_options, /* scope */ &global_scope, /* overload */ 0, /* terminate */0, /* bootpp */0, (struct data_string *)0, client -> config -> vendor_space_name); if (client -> packet_length < BOOTP_MIN_LEN) client -> packet_length = BOOTP_MIN_LEN; client -> packet.op = BOOTREQUEST; client -> packet.htype = client -> interface -> hw_address.hbuf [0]; client -> packet.hlen = client -> interface -> hw_address.hlen - 1; client -> packet.hops = 0; client -> packet.xid = client -> xid; client -> packet.secs = 0; /* Filled in by send_request. */ /* If we own the address we're requesting, put it in ciaddr; otherwise set ciaddr to zero. */ if (client -> state == S_BOUND || client -> state == S_RENEWING || client -> state == S_REBINDING) { memcpy (&client -> packet.ciaddr, lease -> address.iabuf, lease -> address.len); client -> packet.flags = 0; } else { memset (&client -> packet.ciaddr, 0, sizeof client -> packet.ciaddr); if (can_receive_unicast_unconfigured (client -> interface)) client -> packet.flags = 0; else client -> packet.flags = htons (BOOTP_BROADCAST); } memset (&client -> packet.yiaddr, 0, sizeof client -> packet.yiaddr); memset (&client -> packet.siaddr, 0, sizeof client -> packet.siaddr); if (client -> state != S_BOUND && client -> state != S_RENEWING) client -> packet.giaddr = giaddr; else memset (&client -> packet.giaddr, 0, sizeof client -> packet.giaddr); if (client -> interface -> hw_address.hlen > 0) memcpy (client -> packet.chaddr, &client -> interface -> hw_address.hbuf [1], (unsigned)(client -> interface -> hw_address.hlen - 1)); #ifdef DEBUG_PACKET dump_raw ((unsigned char *)&client -> packet, client -> packet_length); #endif } void make_decline (client, lease) struct client_state *client; struct client_lease *lease; { unsigned char decline = DHCPDECLINE; struct option_cache *oc; struct option_state *options = (struct option_state *)0; /* Create the options cache. */ oc = lookup_option (&dhcp_universe, lease -> options, DHO_DHCP_SERVER_IDENTIFIER); make_client_options(client, lease, &decline, oc, &lease->address, NULL, &options); /* Consume the options cache into the option buffer. */ memset (&client -> packet, 0, sizeof (client -> packet)); client -> packet_length = cons_options ((struct packet *)0, &client -> packet, (struct lease *)0, client, 0, (struct option_state *)0, options, &global_scope, 0, 0, 0, (struct data_string *)0, client -> config -> vendor_space_name); /* Destroy the options cache. */ option_state_dereference (&options, MDL); if (client -> packet_length < BOOTP_MIN_LEN) client -> packet_length = BOOTP_MIN_LEN; client -> packet.op = BOOTREQUEST; client -> packet.htype = client -> interface -> hw_address.hbuf [0]; client -> packet.hlen = client -> interface -> hw_address.hlen - 1; client -> packet.hops = 0; client -> packet.xid = client -> xid; client -> packet.secs = 0; /* Filled in by send_request. */ if (can_receive_unicast_unconfigured (client -> interface)) client -> packet.flags = 0; else client -> packet.flags = htons (BOOTP_BROADCAST); /* ciaddr must always be zero. */ memset (&client -> packet.ciaddr, 0, sizeof client -> packet.ciaddr); memset (&client -> packet.yiaddr, 0, sizeof client -> packet.yiaddr); memset (&client -> packet.siaddr, 0, sizeof client -> packet.siaddr); client -> packet.giaddr = giaddr; memcpy (client -> packet.chaddr, &client -> interface -> hw_address.hbuf [1], client -> interface -> hw_address.hlen); #ifdef DEBUG_PACKET dump_raw ((unsigned char *)&client -> packet, client -> packet_length); #endif } void make_release (client, lease) struct client_state *client; struct client_lease *lease; { unsigned char request = DHCPRELEASE; struct option_cache *oc; struct option_state *options = (struct option_state *)0; memset (&client -> packet, 0, sizeof (client -> packet)); oc = lookup_option (&dhcp_universe, lease -> options, DHO_DHCP_SERVER_IDENTIFIER); make_client_options(client, lease, &request, oc, NULL, NULL, &options); /* Set up the option buffer... */ client -> packet_length = cons_options ((struct packet *)0, &client -> packet, (struct lease *)0, client, /* maximum packet size */1500, (struct option_state *)0, options, /* scope */ &global_scope, /* overload */ 0, /* terminate */0, /* bootpp */0, (struct data_string *)0, client -> config -> vendor_space_name); if (client -> packet_length < BOOTP_MIN_LEN) client -> packet_length = BOOTP_MIN_LEN; option_state_dereference (&options, MDL); client -> packet.op = BOOTREQUEST; client -> packet.htype = client -> interface -> hw_address.hbuf [0]; client -> packet.hlen = client -> interface -> hw_address.hlen - 1; client -> packet.hops = 0; client -> packet.xid = random (); client -> packet.secs = 0; client -> packet.flags = 0; memcpy (&client -> packet.ciaddr, lease -> address.iabuf, lease -> address.len); memset (&client -> packet.yiaddr, 0, sizeof client -> packet.yiaddr); memset (&client -> packet.siaddr, 0, sizeof client -> packet.siaddr); client -> packet.giaddr = giaddr; memcpy (client -> packet.chaddr, &client -> interface -> hw_address.hbuf [1], client -> interface -> hw_address.hlen); #ifdef DEBUG_PACKET dump_raw ((unsigned char *)&client -> packet, client -> packet_length); #endif } void destroy_client_lease (lease) struct client_lease *lease; { if (lease -> server_name) dfree (lease -> server_name, MDL); if (lease -> filename) dfree (lease -> filename, MDL); option_state_dereference (&lease -> options, MDL); free_client_lease (lease, MDL); } FILE *leaseFile = NULL; int leases_written = 0; void rewrite_client_leases () { struct interface_info *ip; struct client_state *client; struct client_lease *lp; if (leaseFile != NULL) fclose (leaseFile); leaseFile = fopen (path_dhclient_db, "w"); if (leaseFile == NULL) { log_error ("can't create %s: %m", path_dhclient_db); return; } /* If there is a default duid, write it out. */ if (default_duid.len != 0) write_duid(&default_duid); /* Write out all the leases attached to configured interfaces that we know about. */ for (ip = interfaces; ip; ip = ip -> next) { for (client = ip -> client; client; client = client -> next) { for (lp = client -> leases; lp; lp = lp -> next) { write_client_lease (client, lp, 1, 0); } if (client -> active) write_client_lease (client, client -> active, 1, 0); if (client->active_lease != NULL) write_client6_lease(client, client->active_lease, 1, 0); /* Reset last_write after rewrites. */ client->last_write = 0; } } /* Write out any leases that are attached to interfaces that aren't currently configured. */ for (ip = dummy_interfaces; ip; ip = ip -> next) { for (client = ip -> client; client; client = client -> next) { for (lp = client -> leases; lp; lp = lp -> next) { write_client_lease (client, lp, 1, 0); } if (client -> active) write_client_lease (client, client -> active, 1, 0); if (client->active_lease != NULL) write_client6_lease(client, client->active_lease, 1, 0); /* Reset last_write after rewrites. */ client->last_write = 0; } } fflush (leaseFile); } void write_lease_option (struct option_cache *oc, struct packet *packet, struct lease *lease, struct client_state *client_state, struct option_state *in_options, struct option_state *cfg_options, struct binding_scope **scope, struct universe *u, void *stuff) { const char *name, *dot; struct data_string ds; char *preamble = stuff; memset (&ds, 0, sizeof ds); if (u != &dhcp_universe) { name = u -> name; dot = "."; } else { name = ""; dot = ""; } if (evaluate_option_cache (&ds, packet, lease, client_state, in_options, cfg_options, scope, oc, MDL)) { fprintf(leaseFile, "%soption %s%s%s %s;\n", preamble, name, dot, oc->option->name, pretty_print_option(oc->option, ds.data, ds.len, 1, 1)); data_string_forget (&ds, MDL); } } /* Write an option cache to the lease store. */ static void write_options(struct client_state *client, struct option_state *options, const char *preamble) { int i; for (i = 0; i < options->universe_count; i++) { option_space_foreach(NULL, NULL, client, NULL, options, &global_scope, universes[i], (char *)preamble, write_lease_option); } } /* Write the default DUID to the lease store. */ static isc_result_t write_duid(struct data_string *duid) { char *str; int stat; if ((duid == NULL) || (duid->len <= 2)) return DHCP_R_INVALIDARG; if (leaseFile == NULL) { /* XXX? */ leaseFile = fopen(path_dhclient_db, "w"); if (leaseFile == NULL) { log_error("can't create %s: %m", path_dhclient_db); return ISC_R_IOERROR; } } /* It would make more sense to write this as a hex string, * but our function to do that (print_hex_n) uses a fixed * length buffer...and we can't guarantee a duid would be * less than the fixed length. */ str = quotify_buf(duid->data, duid->len, MDL); if (str == NULL) return ISC_R_NOMEMORY; stat = fprintf(leaseFile, "default-duid \"%s\";\n", str); dfree(str, MDL); if (stat <= 0) return ISC_R_IOERROR; if (fflush(leaseFile) != 0) return ISC_R_IOERROR; return ISC_R_SUCCESS; } /* Write a DHCPv6 lease to the store. */ isc_result_t write_client6_lease(struct client_state *client, struct dhc6_lease *lease, int rewrite, int sync) { struct dhc6_ia *ia; struct dhc6_addr *addr; int stat; const char *ianame; /* This should include the current lease. */ if (!rewrite && (leases_written++ > 20)) { rewrite_client_leases(); leases_written = 0; return ISC_R_SUCCESS; } if (client == NULL || lease == NULL) return DHCP_R_INVALIDARG; if (leaseFile == NULL) { /* XXX? */ leaseFile = fopen(path_dhclient_db, "w"); if (leaseFile == NULL) { log_error("can't create %s: %m", path_dhclient_db); return ISC_R_IOERROR; } } stat = fprintf(leaseFile, "lease6 {\n"); if (stat <= 0) return ISC_R_IOERROR; stat = fprintf(leaseFile, " interface \"%s\";\n", client->interface->name); if (stat <= 0) return ISC_R_IOERROR; for (ia = lease->bindings ; ia != NULL ; ia = ia->next) { switch (ia->ia_type) { case D6O_IA_NA: default: ianame = "ia-na"; break; case D6O_IA_TA: ianame = "ia-ta"; break; case D6O_IA_PD: ianame = "ia-pd"; break; } stat = fprintf(leaseFile, " %s %s {\n", ianame, print_hex_1(4, ia->iaid, 12)); if (stat <= 0) return ISC_R_IOERROR; if (ia->ia_type != D6O_IA_TA) stat = fprintf(leaseFile, " starts %d;\n" " renew %u;\n" " rebind %u;\n", (int)ia->starts, ia->renew, ia->rebind); else stat = fprintf(leaseFile, " starts %d;\n", (int)ia->starts); if (stat <= 0) return ISC_R_IOERROR; for (addr = ia->addrs ; addr != NULL ; addr = addr->next) { if (ia->ia_type != D6O_IA_PD) stat = fprintf(leaseFile, " iaaddr %s {\n", piaddr(addr->address)); else stat = fprintf(leaseFile, " iaprefix %s/%d {\n", piaddr(addr->address), (int)addr->plen); if (stat <= 0) return ISC_R_IOERROR; stat = fprintf(leaseFile, " starts %d;\n" " preferred-life %u;\n" " max-life %u;\n", (int)addr->starts, addr->preferred_life, addr->max_life); if (stat <= 0) return ISC_R_IOERROR; if (addr->options != NULL) write_options(client, addr->options, " "); stat = fprintf(leaseFile, " }\n"); if (stat <= 0) return ISC_R_IOERROR; } if (ia->options != NULL) write_options(client, ia->options, " "); stat = fprintf(leaseFile, " }\n"); if (stat <= 0) return ISC_R_IOERROR; } if (lease->released) { stat = fprintf(leaseFile, " released;\n"); if (stat <= 0) return ISC_R_IOERROR; } if (lease->options != NULL) write_options(client, lease->options, " "); stat = fprintf(leaseFile, "}\n"); if (stat <= 0) return ISC_R_IOERROR; if (fflush(leaseFile) != 0) return ISC_R_IOERROR; if (sync) { if (fsync(fileno(leaseFile)) < 0) { log_error("write_client_lease: fsync(): %m"); return ISC_R_IOERROR; } } return ISC_R_SUCCESS; } int write_client_lease (client, lease, rewrite, makesure) struct client_state *client; struct client_lease *lease; int rewrite; int makesure; { struct data_string ds; int errors = 0; char *s; const char *tval; if (!rewrite) { if (leases_written++ > 20) { rewrite_client_leases (); leases_written = 0; } } /* If the lease came from the config file, we don't need to stash a copy in the lease database. */ if (lease -> is_static) return 1; if (leaseFile == NULL) { /* XXX */ leaseFile = fopen (path_dhclient_db, "w"); if (leaseFile == NULL) { log_error ("can't create %s: %m", path_dhclient_db); return 0; } } errno = 0; fprintf (leaseFile, "lease {\n"); if (lease -> is_bootp) { fprintf (leaseFile, " bootp;\n"); if (errno) { ++errors; errno = 0; } } fprintf (leaseFile, " interface \"%s\";\n", client -> interface -> name); if (errno) { ++errors; errno = 0; } if (client -> name) { fprintf (leaseFile, " name \"%s\";\n", client -> name); if (errno) { ++errors; errno = 0; } } fprintf (leaseFile, " fixed-address %s;\n", piaddr (lease -> address)); if (errno) { ++errors; errno = 0; } if (lease -> filename) { s = quotify_string (lease -> filename, MDL); if (s) { fprintf (leaseFile, " filename \"%s\";\n", s); if (errno) { ++errors; errno = 0; } dfree (s, MDL); } else errors++; } if (lease->server_name != NULL) { s = quotify_string(lease->server_name, MDL); if (s != NULL) { fprintf(leaseFile, " server-name \"%s\";\n", s); if (errno) { ++errors; errno = 0; } dfree(s, MDL); } else ++errors; } if (lease -> medium) { s = quotify_string (lease -> medium -> string, MDL); if (s) { fprintf (leaseFile, " medium \"%s\";\n", s); if (errno) { ++errors; errno = 0; } dfree (s, MDL); } else errors++; } if (errno != 0) { errors++; errno = 0; } memset (&ds, 0, sizeof ds); write_options(client, lease->options, " "); tval = print_time(lease->renewal); if (tval == NULL || fprintf(leaseFile, " renew %s\n", tval) < 0) errors++; tval = print_time(lease->rebind); if (tval == NULL || fprintf(leaseFile, " rebind %s\n", tval) < 0) errors++; tval = print_time(lease->expiry); if (tval == NULL || fprintf(leaseFile, " expire %s\n", tval) < 0) errors++; if (fprintf(leaseFile, "}\n") < 0) errors++; if (fflush(leaseFile) != 0) errors++; client->last_write = cur_time; if (!errors && makesure) { if (fsync (fileno (leaseFile)) < 0) { log_info ("write_client_lease: %m"); return 0; } } return errors ? 0 : 1; } /* Variables holding name of script and file pointer for writing to script. Needless to say, this is not reentrant - only one script can be invoked at a time. */ char scriptName [256]; FILE *scriptFile; void script_init (client, reason, medium) struct client_state *client; const char *reason; struct string_list *medium; { struct string_list *sl, *next; if (client) { for (sl = client -> env; sl; sl = next) { next = sl -> next; dfree (sl, MDL); } client -> env = (struct string_list *)0; client -> envc = 0; if (client -> interface) { client_envadd (client, "", "interface", "%s", client -> interface -> name); } if (client -> name) client_envadd (client, "", "client", "%s", client -> name); if (medium) client_envadd (client, "", "medium", "%s", medium -> string); client_envadd (client, "", "reason", "%s", reason); client_envadd (client, "", "pid", "%ld", (long int)getpid ()); } } void client_option_envadd (struct option_cache *oc, struct packet *packet, struct lease *lease, struct client_state *client_state, struct option_state *in_options, struct option_state *cfg_options, struct binding_scope **scope, struct universe *u, void *stuff) { struct envadd_state *es = stuff; struct data_string data; memset (&data, 0, sizeof data); if (evaluate_option_cache (&data, packet, lease, client_state, in_options, cfg_options, scope, oc, MDL)) { if (data.len) { char name [256]; if (dhcp_option_ev_name (name, sizeof name, oc->option)) { const char *value; size_t length; value = pretty_print_option(oc->option, data.data, data.len, 0, 0); length = strlen(value); if (check_option_values(oc->option->universe, oc->option->code, value, length) == 0) { client_envadd(es->client, es->prefix, name, "%s", value); } else { log_error("suspect value in %s " "option - discarded", name); } data_string_forget (&data, MDL); } } } } void script_write_params (client, prefix, lease) struct client_state *client; const char *prefix; struct client_lease *lease; { int i; struct data_string data; struct option_cache *oc; struct envadd_state es; es.client = client; es.prefix = prefix; client_envadd (client, prefix, "ip_address", "%s", piaddr (lease -> address)); /* For the benefit of Linux (and operating systems which may have similar needs), compute the network address based on the supplied ip address and netmask, if provided. Also compute the broadcast address (the host address all ones broadcast address, not the host address all zeroes broadcast address). */ memset (&data, 0, sizeof data); oc = lookup_option (&dhcp_universe, lease -> options, DHO_SUBNET_MASK); if (oc && evaluate_option_cache (&data, (struct packet *)0, (struct lease *)0, client, (struct option_state *)0, lease -> options, &global_scope, oc, MDL)) { if (data.len > 3) { struct iaddr netmask, subnet, broadcast; /* * No matter the length of the subnet-mask option, * use only the first four octets. Note that * subnet-mask options longer than 4 octets are not * in conformance with RFC 2132, but servers with this * flaw do exist. */ memcpy(netmask.iabuf, data.data, 4); netmask.len = 4; data_string_forget (&data, MDL); subnet = subnet_number (lease -> address, netmask); if (subnet.len) { client_envadd (client, prefix, "network_number", "%s", piaddr (subnet)); oc = lookup_option (&dhcp_universe, lease -> options, DHO_BROADCAST_ADDRESS); if (!oc || !(evaluate_option_cache (&data, (struct packet *)0, (struct lease *)0, client, (struct option_state *)0, lease -> options, &global_scope, oc, MDL))) { broadcast = broadcast_addr (subnet, netmask); if (broadcast.len) { client_envadd (client, prefix, "broadcast_address", "%s", piaddr (broadcast)); } } } } data_string_forget (&data, MDL); } if (lease->filename) { if (check_option_values(NULL, DHO_ROOT_PATH, lease->filename, strlen(lease->filename)) == 0) { client_envadd(client, prefix, "filename", "%s", lease->filename); } else { log_error("suspect value in %s " "option - discarded", lease->filename); } } if (lease->server_name) { if (check_option_values(NULL, DHO_HOST_NAME, lease->server_name, strlen(lease->server_name)) == 0 ) { client_envadd (client, prefix, "server_name", "%s", lease->server_name); } else { log_error("suspect value in %s " "option - discarded", lease->server_name); } } for (i = 0; i < lease -> options -> universe_count; i++) { option_space_foreach ((struct packet *)0, (struct lease *)0, client, (struct option_state *)0, lease -> options, &global_scope, universes [i], &es, client_option_envadd); } client_envadd (client, prefix, "expiry", "%d", (int)(lease -> expiry)); } int script_go (client) struct client_state *client; { char *scriptName; char *argv [2]; char **envp; char reason [] = "REASON=NBI"; static char client_path [] = CLIENT_PATH; int i; struct string_list *sp, *next; int pid, wpid, wstatus; if (client) scriptName = client -> config -> script_name; else scriptName = top_level_config.script_name; envp = dmalloc (((client ? client -> envc : 2) + client_env_count + 2) * sizeof (char *), MDL); if (!envp) { log_error ("No memory for client script environment."); return 0; } i = 0; /* Copy out the environment specified on the command line, if any. */ for (sp = client_env; sp; sp = sp -> next) { envp [i++] = sp -> string; } /* Copy out the environment specified by dhclient. */ if (client) { for (sp = client -> env; sp; sp = sp -> next) { envp [i++] = sp -> string; } } else { envp [i++] = reason; } /* Set $PATH. */ envp [i++] = client_path; envp [i] = (char *)0; argv [0] = scriptName; argv [1] = (char *)0; pid = fork (); if (pid < 0) { log_error ("fork: %m"); wstatus = 0; } else if (pid) { do { wpid = wait (&wstatus); } while (wpid != pid && wpid > 0); if (wpid < 0) { log_error ("wait: %m"); wstatus = 0; } } else { /* We don't want to pass an open file descriptor for * dhclient.leases when executing dhclient-script. */ if (leaseFile != NULL) fclose(leaseFile); execve (scriptName, argv, envp); log_error ("execve (%s, ...): %m", scriptName); exit (0); } if (client) { for (sp = client -> env; sp; sp = next) { next = sp -> next; dfree (sp, MDL); } client -> env = (struct string_list *)0; client -> envc = 0; } dfree (envp, MDL); gettimeofday(&cur_tv, NULL); return (WIFEXITED (wstatus) ? WEXITSTATUS (wstatus) : -WTERMSIG (wstatus)); } void client_envadd (struct client_state *client, const char *prefix, const char *name, const char *fmt, ...) { char spbuf [1024]; char *s; unsigned len; struct string_list *val; va_list list; va_start (list, fmt); len = vsnprintf (spbuf, sizeof spbuf, fmt, list); va_end (list); val = dmalloc (strlen (prefix) + strlen (name) + 1 /* = */ + len + sizeof *val, MDL); if (!val) return; s = val -> string; strcpy (s, prefix); strcat (s, name); s += strlen (s); *s++ = '='; if (len >= sizeof spbuf) { va_start (list, fmt); vsnprintf (s, len + 1, fmt, list); va_end (list); } else strcpy (s, spbuf); val -> next = client -> env; client -> env = val; client -> envc++; } int dhcp_option_ev_name (buf, buflen, option) char *buf; size_t buflen; struct option *option; { int i, j; const char *s; j = 0; if (option -> universe != &dhcp_universe) { s = option -> universe -> name; i = 0; } else { s = option -> name; i = 1; } do { while (*s) { if (j + 1 == buflen) return 0; if (*s == '-') buf [j++] = '_'; else buf [j++] = *s; ++s; } if (!i) { s = option -> name; if (j + 1 == buflen) return 0; buf [j++] = '_'; } ++i; } while (i != 2); buf [j] = 0; return 1; } void go_daemon () { static int state = 0; int pid; /* Don't become a daemon if the user requested otherwise. */ if (no_daemon) { write_client_pid_file (); return; } /* Only do it once. */ if (state) return; state = 1; /* Stop logging to stderr... */ log_perror = 0; /* Become a daemon... */ if ((pid = fork ()) < 0) log_fatal ("Can't fork daemon: %m"); else if (pid) exit (0); /* Become session leader and get pid... */ pid = setsid (); /* Close standard I/O descriptors. */ close(0); close(1); close(2); /* Reopen them on /dev/null. */ open("/dev/null", O_RDWR); open("/dev/null", O_RDWR); open("/dev/null", O_RDWR); write_client_pid_file (); IGNORE_RET (chdir("/")); } void write_client_pid_file () { FILE *pf; int pfdesc; /* nothing to do if the user doesn't want a pid file */ if (no_pid_file == ISC_TRUE) { return; } pfdesc = open (path_dhclient_pid, O_CREAT | O_TRUNC | O_WRONLY, 0644); if (pfdesc < 0) { log_error ("Can't create %s: %m", path_dhclient_pid); return; } pf = fdopen (pfdesc, "w"); if (!pf) { close(pfdesc); log_error ("Can't fdopen %s: %m", path_dhclient_pid); } else { fprintf (pf, "%ld\n", (long)getpid ()); fclose (pf); } } void client_location_changed () { struct interface_info *ip; struct client_state *client; for (ip = interfaces; ip; ip = ip -> next) { for (client = ip -> client; client; client = client -> next) { switch (client -> state) { case S_SELECTING: cancel_timeout (send_discover, client); break; case S_BOUND: cancel_timeout (state_bound, client); break; case S_REBOOTING: case S_REQUESTING: case S_RENEWING: cancel_timeout (send_request, client); break; case S_INIT: case S_REBINDING: case S_STOPPED: break; } client -> state = S_INIT; state_reboot (client); } } } void do_release(client) struct client_state *client; { struct data_string ds; struct option_cache *oc; /* Pick a random xid. */ client -> xid = random (); /* is there even a lease to release? */ if (client -> active) { /* Make a DHCPRELEASE packet, and set appropriate per-interface flags. */ make_release (client, client -> active); memset (&ds, 0, sizeof ds); oc = lookup_option (&dhcp_universe, client -> active -> options, DHO_DHCP_SERVER_IDENTIFIER); if (oc && evaluate_option_cache (&ds, (struct packet *)0, (struct lease *)0, client, (struct option_state *)0, client -> active -> options, &global_scope, oc, MDL)) { if (ds.len > 3) { memcpy (client -> destination.iabuf, ds.data, 4); client -> destination.len = 4; } else client -> destination = iaddr_broadcast; data_string_forget (&ds, MDL); } else client -> destination = iaddr_broadcast; client -> first_sending = cur_time; client -> interval = client -> config -> initial_interval; /* Zap the medium list... */ client -> medium = (struct string_list *)0; /* Send out the first and only DHCPRELEASE packet. */ send_release (client); /* Do the client script RELEASE operation. */ script_init (client, "RELEASE", (struct string_list *)0); if (client -> alias) script_write_params (client, "alias_", client -> alias); script_write_params (client, "old_", client -> active); script_go (client); } /* Cancel any timeouts. */ cancel_timeout (state_bound, client); cancel_timeout (send_discover, client); cancel_timeout (state_init, client); cancel_timeout (send_request, client); cancel_timeout (state_reboot, client); client -> state = S_STOPPED; } int dhclient_interface_shutdown_hook (struct interface_info *interface) { do_release (interface -> client); return 1; } int dhclient_interface_discovery_hook (struct interface_info *tmp) { struct interface_info *last, *ip; /* See if we can find the client from dummy_interfaces */ last = 0; for (ip = dummy_interfaces; ip; ip = ip -> next) { if (!strcmp (ip -> name, tmp -> name)) { /* Remove from dummy_interfaces */ if (last) { ip = (struct interface_info *)0; interface_reference (&ip, last -> next, MDL); interface_dereference (&last -> next, MDL); if (ip -> next) { interface_reference (&last -> next, ip -> next, MDL); interface_dereference (&ip -> next, MDL); } } else { ip = (struct interface_info *)0; interface_reference (&ip, dummy_interfaces, MDL); interface_dereference (&dummy_interfaces, MDL); if (ip -> next) { interface_reference (&dummy_interfaces, ip -> next, MDL); interface_dereference (&ip -> next, MDL); } } /* Copy "client" to tmp */ if (ip -> client) { tmp -> client = ip -> client; tmp -> client -> interface = tmp; } interface_dereference (&ip, MDL); break; } last = ip; } return 1; } isc_result_t dhclient_interface_startup_hook (struct interface_info *interface) { struct interface_info *ip; struct client_state *client; /* This code needs some rethinking. It doesn't test against a signal name, and it just kind of bulls into doing something that may or may not be appropriate. */ if (interfaces) { interface_reference (&interface -> next, interfaces, MDL); interface_dereference (&interfaces, MDL); } interface_reference (&interfaces, interface, MDL); discover_interfaces (DISCOVER_UNCONFIGURED); for (ip = interfaces; ip; ip = ip -> next) { /* If interfaces were specified, don't configure interfaces that weren't specified! */ if (ip -> flags & INTERFACE_RUNNING || (ip -> flags & (INTERFACE_REQUESTED | INTERFACE_AUTOMATIC)) != INTERFACE_REQUESTED) continue; script_init (ip -> client, "PREINIT", (struct string_list *)0); if (ip -> client -> alias) script_write_params (ip -> client, "alias_", ip -> client -> alias); script_go (ip -> client); } discover_interfaces (interfaces_requested != 0 ? DISCOVER_REQUESTED : DISCOVER_RUNNING); for (ip = interfaces; ip; ip = ip -> next) { if (ip -> flags & INTERFACE_RUNNING) continue; ip -> flags |= INTERFACE_RUNNING; for (client = ip->client ; client ; client = client->next) { client->state = S_INIT; state_reboot(client); } } return ISC_R_SUCCESS; } /* The client should never receive a relay agent information option, so if it does, log it and discard it. */ int parse_agent_information_option (packet, len, data) struct packet *packet; int len; u_int8_t *data; { return 1; } /* The client never sends relay agent information options. */ unsigned cons_agent_information_options (cfg_options, outpacket, agentix, length) struct option_state *cfg_options; struct dhcp_packet *outpacket; unsigned agentix; unsigned length; { return length; } static void shutdown_exit (void *foo) { exit (0); } #if defined (NSUPDATE) /* * If the first query fails, the updater MUST NOT delete the DNS name. It * may be that the host whose lease on the server has expired has moved * to another network and obtained a lease from a different server, * which has caused the client's A RR to be replaced. It may also be * that some other client has been configured with a name that matches * the name of the DHCP client, and the policy was that the last client * to specify the name would get the name. In this case, the DHCID RR * will no longer match the updater's notion of the client-identity of * the host pointed to by the DNS name. * -- "Interaction between DHCP and DNS" */ /* The first and second stages are pretty similar so we combine them */ void client_dns_remove_action(dhcp_ddns_cb_t *ddns_cb, isc_result_t eresult) { isc_result_t result; if ((eresult == ISC_R_SUCCESS) && (ddns_cb->state == DDNS_STATE_REM_FW_YXDHCID)) { /* Do the second stage of the FWD removal */ ddns_cb->state = DDNS_STATE_REM_FW_NXRR; result = ddns_modify_fwd(ddns_cb, MDL); if (result == ISC_R_SUCCESS) { return; } } /* If we are done or have an error clean up */ ddns_cb_free(ddns_cb, MDL); return; } void client_dns_remove(struct client_state *client, struct iaddr *addr) { dhcp_ddns_cb_t *ddns_cb; isc_result_t result; /* if we have an old ddns request for this client, cancel it */ if (client->ddns_cb != NULL) { ddns_cancel(client->ddns_cb, MDL); client->ddns_cb = NULL; } ddns_cb = ddns_cb_alloc(MDL); if (ddns_cb != NULL) { ddns_cb->address = *addr; ddns_cb->timeout = 0; ddns_cb->state = DDNS_STATE_REM_FW_YXDHCID; ddns_cb->flags = DDNS_UPDATE_ADDR; ddns_cb->cur_func = client_dns_remove_action; result = client_dns_update(client, ddns_cb); if (result != ISC_R_TIMEDOUT) { ddns_cb_free(ddns_cb, MDL); } } } #endif isc_result_t dhcp_set_control_state (control_object_state_t oldstate, control_object_state_t newstate) { struct interface_info *ip; struct client_state *client; struct timeval tv; /* Do the right thing for each interface. */ for (ip = interfaces; ip; ip = ip -> next) { for (client = ip -> client; client; client = client -> next) { switch (newstate) { case server_startup: return ISC_R_SUCCESS; case server_running: return ISC_R_SUCCESS; case server_shutdown: if (client -> active && client -> active -> expiry > cur_time) { #if defined (NSUPDATE) if (client->config->do_forward_update) { client_dns_remove(client, &client->active->address); } #endif do_release (client); } break; case server_hibernate: state_stop (client); break; case server_awaken: state_reboot (client); break; } } } if (newstate == server_shutdown) { tv.tv_sec = cur_tv.tv_sec; tv.tv_usec = cur_tv.tv_usec + 1; add_timeout(&tv, shutdown_exit, 0, 0, 0); } return ISC_R_SUCCESS; } #if defined (NSUPDATE) /* * Called after a timeout if the DNS update failed on the previous try. * Starts the retry process. If the retry times out it will schedule * this routine to run again after a 10x wait. */ void client_dns_update_timeout (void *cp) { dhcp_ddns_cb_t *ddns_cb = (dhcp_ddns_cb_t *)cp; struct client_state *client = (struct client_state *)ddns_cb->lease; isc_result_t status = ISC_R_FAILURE; if ((client != NULL) && ((client->active != NULL) || (client->active_lease != NULL))) status = client_dns_update(client, ddns_cb); /* * A status of timedout indicates that we started the update and * have released control of the control block. Any other status * indicates that we should clean up the control block. We either * got a success which indicates that we didn't really need to * send an update or some other error in which case we weren't able * to start the update process. In both cases we still own * the control block and should free it. */ if (status != ISC_R_TIMEDOUT) { if (client != NULL) { client->ddns_cb = NULL; } ddns_cb_free(ddns_cb, MDL); } } /* * If the first query succeeds, the updater can conclude that it * has added a new name whose only RRs are the A and DHCID RR records. * The A RR update is now complete (and a client updater is finished, * while a server might proceed to perform a PTR RR update). * -- "Interaction between DHCP and DNS" * * If the second query succeeds, the updater can conclude that the current * client was the last client associated with the domain name, and that * the name now contains the updated A RR. The A RR update is now * complete (and a client updater is finished, while a server would * then proceed to perform a PTR RR update). * -- "Interaction between DHCP and DNS" * * If the second query fails with NXRRSET, the updater must conclude * that the client's desired name is in use by another host. At this * juncture, the updater can decide (based on some administrative * configuration outside of the scope of this document) whether to let * the existing owner of the name keep that name, and to (possibly) * perform some name disambiguation operation on behalf of the current * client, or to replace the RRs on the name with RRs that represent * the current client. If the configured policy allows replacement of * existing records, the updater submits a query that deletes the * existing A RR and the existing DHCID RR, adding A and DHCID RRs that * represent the IP address and client-identity of the new client. * -- "Interaction between DHCP and DNS" */ /* The first and second stages are pretty similar so we combine them */ void client_dns_update_action(dhcp_ddns_cb_t *ddns_cb, isc_result_t eresult) { isc_result_t result; struct timeval tv; switch(eresult) { case ISC_R_SUCCESS: default: /* Either we succeeded or broke in a bad way, clean up */ break; case DNS_R_YXRRSET: /* * This is the only difference between the two stages, * check to see if it is the first stage, in which case * start the second stage */ if (ddns_cb->state == DDNS_STATE_ADD_FW_NXDOMAIN) { ddns_cb->state = DDNS_STATE_ADD_FW_YXDHCID; ddns_cb->cur_func = client_dns_update_action; result = ddns_modify_fwd(ddns_cb, MDL); if (result == ISC_R_SUCCESS) { return; } } break; case ISC_R_TIMEDOUT: /* * We got a timeout response from the DNS module. Schedule * another attempt for later. We forget the name, dhcid and * zone so if it gets changed we will get the new information. */ data_string_forget(&ddns_cb->fwd_name, MDL); data_string_forget(&ddns_cb->dhcid, MDL); if (ddns_cb->zone != NULL) { forget_zone((struct dns_zone **)&ddns_cb->zone); } /* Reset to doing the first stage */ ddns_cb->state = DDNS_STATE_ADD_FW_NXDOMAIN; ddns_cb->cur_func = client_dns_update_action; /* and update our timer */ if (ddns_cb->timeout < 3600) ddns_cb->timeout *= 10; tv.tv_sec = cur_tv.tv_sec + ddns_cb->timeout; tv.tv_usec = cur_tv.tv_usec; add_timeout(&tv, client_dns_update_timeout, ddns_cb, NULL, NULL); return; } ddns_cb_free(ddns_cb, MDL); return; } /* See if we should do a DNS update, and if so, do it. */ isc_result_t client_dns_update(struct client_state *client, dhcp_ddns_cb_t *ddns_cb) { struct data_string client_identifier; struct option_cache *oc; int ignorep; int result; isc_result_t rcode; /* If we didn't send an FQDN option, we certainly aren't going to be doing an update. */ if (!client -> sent_options) return ISC_R_SUCCESS; /* If we don't have a lease, we can't do an update. */ if ((client->active == NULL) && (client->active_lease == NULL)) return ISC_R_SUCCESS; /* If we set the no client update flag, don't do the update. */ if ((oc = lookup_option (&fqdn_universe, client -> sent_options, FQDN_NO_CLIENT_UPDATE)) && evaluate_boolean_option_cache (&ignorep, (struct packet *)0, (struct lease *)0, client, client -> sent_options, (struct option_state *)0, &global_scope, oc, MDL)) return ISC_R_SUCCESS; /* If we set the "server, please update" flag, or didn't set it to false, don't do the update. */ if (!(oc = lookup_option (&fqdn_universe, client -> sent_options, FQDN_SERVER_UPDATE)) || evaluate_boolean_option_cache (&ignorep, (struct packet *)0, (struct lease *)0, client, client -> sent_options, (struct option_state *)0, &global_scope, oc, MDL)) return ISC_R_SUCCESS; /* If no FQDN option was supplied, don't do the update. */ if (!(oc = lookup_option (&fqdn_universe, client -> sent_options, FQDN_FQDN)) || !evaluate_option_cache (&ddns_cb->fwd_name, (struct packet *)0, (struct lease *)0, client, client -> sent_options, (struct option_state *)0, &global_scope, oc, MDL)) return ISC_R_SUCCESS; /* If this is a DHCPv6 client update, make a dhcid string out of * the DUID. If this is a DHCPv4 client update, choose either * the client identifier, if there is one, or the interface's * MAC address. */ result = 0; memset(&client_identifier, 0, sizeof(client_identifier)); if (client->active_lease != NULL) { if (((oc = lookup_option(&dhcpv6_universe, client->sent_options, D6O_CLIENTID)) != NULL) && evaluate_option_cache(&client_identifier, NULL, NULL, client, client->sent_options, NULL, &global_scope, oc, MDL)) { /* RFC4701 defines type '2' as being for the DUID * field. We aren't using RFC4701 DHCID RR's yet, * but this is as good a value as any. */ result = get_dhcid(&ddns_cb->dhcid, 2, client_identifier.data, client_identifier.len); data_string_forget(&client_identifier, MDL); } else log_fatal("Impossible condition at %s:%d.", MDL); } else { if (((oc = lookup_option(&dhcp_universe, client->sent_options, DHO_DHCP_CLIENT_IDENTIFIER)) != NULL) && evaluate_option_cache(&client_identifier, NULL, NULL, client, client->sent_options, NULL, &global_scope, oc, MDL)) { result = get_dhcid(&ddns_cb->dhcid, DHO_DHCP_CLIENT_IDENTIFIER, client_identifier.data, client_identifier.len); data_string_forget(&client_identifier, MDL); } else result = get_dhcid(&ddns_cb->dhcid, 0, client->interface->hw_address.hbuf, client->interface->hw_address.hlen); } if (!result) { return ISC_R_SUCCESS; } /* * Perform updates. */ if (ddns_cb->fwd_name.len && ddns_cb->dhcid.len) { rcode = ddns_modify_fwd(ddns_cb, MDL); } else rcode = ISC_R_FAILURE; /* * A success from the modify routine means we are performing * async processing, for which we use the timedout error message. */ if (rcode == ISC_R_SUCCESS) { rcode = ISC_R_TIMEDOUT; } return rcode; } /* * Schedule the first update. They will continue to retry occasionally * until they no longer time out (or fail). */ void dhclient_schedule_updates(struct client_state *client, struct iaddr *addr, int offset) { dhcp_ddns_cb_t *ddns_cb; struct timeval tv; if (!client->config->do_forward_update) return; /* cancel any outstanding ddns requests */ if (client->ddns_cb != NULL) { ddns_cancel(client->ddns_cb, MDL); client->ddns_cb = NULL; } ddns_cb = ddns_cb_alloc(MDL); if (ddns_cb != NULL) { ddns_cb->lease = (void *)client; ddns_cb->address = *addr; ddns_cb->timeout = 1; /* * XXX: DNS TTL is a problem we need to solve properly. * Until that time, 300 is a placeholder default for * something that is less insane than a value scaled * by lease timeout. */ ddns_cb->ttl = 300; ddns_cb->state = DDNS_STATE_ADD_FW_NXDOMAIN; ddns_cb->cur_func = client_dns_update_action; ddns_cb->flags = DDNS_UPDATE_ADDR | DDNS_INCLUDE_RRSET; client->ddns_cb = ddns_cb; tv.tv_sec = cur_tv.tv_sec + offset; tv.tv_usec = cur_tv.tv_usec; add_timeout(&tv, client_dns_update_timeout, ddns_cb, NULL, NULL); } else { log_error("Unable to allocate dns update state for %s", piaddr(*addr)); } } #endif void dhcpv4_client_assignments(void) { struct servent *ent; if (path_dhclient_pid == NULL) path_dhclient_pid = _PATH_DHCLIENT_PID; if (path_dhclient_db == NULL) path_dhclient_db = _PATH_DHCLIENT_DB; /* Default to the DHCP/BOOTP port. */ if (!local_port) { /* If we're faking a relay agent, and we're not using loopback, use the server port, not the client port. */ if (mockup_relay && giaddr.s_addr != htonl (INADDR_LOOPBACK)) { local_port = htons(67); } else { ent = getservbyname ("dhcpc", "udp"); if (!ent) local_port = htons (68); else local_port = ent -> s_port; #ifndef __CYGWIN32__ endservent (); #endif } } /* If we're faking a relay agent, and we're not using loopback, we're using the server port, not the client port. */ if (mockup_relay && giaddr.s_addr != htonl (INADDR_LOOPBACK)) { remote_port = local_port; } else remote_port = htons (ntohs (local_port) - 1); /* XXX */ } /* * The following routines are used to check that certain * strings are reasonable before we pass them to the scripts. * This avoids some problems with scripts treating the strings * as commands - see ticket 23722 * The domain checking code should be done as part of assembling * the string but we are doing it here for now due to time * constraints. */ static int check_domain_name(const char *ptr, size_t len, int dots) { const char *p; /* not empty or complete length not over 255 characters */ if ((len == 0) || (len > 256)) return(-1); /* consists of [[:alnum:]-]+ labels separated by [.] */ /* a [_] is against RFC but seems to be "widely used"... */ for (p=ptr; (*p != 0) && (len-- > 0); p++) { if ((*p == '-') || (*p == '_')) { /* not allowed at begin or end of a label */ if (((p - ptr) == 0) || (len == 0) || (p[1] == '.')) return(-1); } else if (*p == '.') { /* each label has to be 1-63 characters; we allow [.] at the end ('foo.bar.') */ size_t d = p - ptr; if ((d <= 0) || (d >= 64)) return(-1); ptr = p + 1; /* jump to the next label */ if ((dots > 0) && (len > 0)) dots--; } else if (isalnum((unsigned char)*p) == 0) { /* also numbers at the begin are fine */ return(-1); } } return(dots ? -1 : 0); } static int check_domain_name_list(const char *ptr, size_t len, int dots) { const char *p; int ret = -1; /* at least one needed */ if ((ptr == NULL) || (len == 0)) return(-1); for (p=ptr; (*p != 0) && (len > 0); p++, len--) { if (*p != ' ') continue; if (p > ptr) { if (check_domain_name(ptr, p - ptr, dots) != 0) return(-1); ret = 0; } ptr = p + 1; } if (p > ptr) return(check_domain_name(ptr, p - ptr, dots)); else return(ret); } static int check_option_values(struct universe *universe, unsigned int opt, const char *ptr, size_t len) { if (ptr == NULL) return(-1); /* just reject options we want to protect, will be escaped anyway */ if ((universe == NULL) || (universe == &dhcp_universe)) { switch(opt) { case DHO_DOMAIN_NAME: #ifdef ACCEPT_LIST_IN_DOMAIN_NAME return check_domain_name_list(ptr, len, 0); #else return check_domain_name(ptr, len, 0); #endif case DHO_HOST_NAME: case DHO_NIS_DOMAIN: case DHO_NETBIOS_SCOPE: return check_domain_name(ptr, len, 0); break; case DHO_DOMAIN_SEARCH: return check_domain_name_list(ptr, len, 0); break; case DHO_ROOT_PATH: if (len == 0) return(-1); for (; (*ptr != 0) && (len-- > 0); ptr++) { if(!(isalnum((unsigned char)*ptr) || *ptr == '#' || *ptr == '%' || *ptr == '+' || *ptr == '-' || *ptr == '_' || *ptr == ':' || *ptr == '.' || *ptr == ',' || *ptr == '@' || *ptr == '~' || *ptr == '\\' || *ptr == '/' || *ptr == '[' || *ptr == ']' || *ptr == '=' || *ptr == ' ')) return(-1); } return(0); break; } } #ifdef DHCPv6 if (universe == &dhcpv6_universe) { switch(opt) { case D6O_SIP_SERVERS_DNS: case D6O_DOMAIN_SEARCH: case D6O_NIS_DOMAIN_NAME: case D6O_NISP_DOMAIN_NAME: return check_domain_name_list(ptr, len, 0); break; } } #endif return(0); } static void add_reject(struct packet *packet) { struct iaddrmatchlist *list; list = dmalloc(sizeof(struct iaddrmatchlist), MDL); if (!list) log_fatal ("no memory for reject list!"); /* * client_addr is misleading - it is set to source address in common * code. */ list->match.addr = packet->client_addr; /* Set mask to indicate host address. */ list->match.mask.len = list->match.addr.len; memset(list->match.mask.iabuf, 0xff, sizeof(list->match.mask.iabuf)); /* Append to reject list for the source interface. */ list->next = packet->interface->client->config->reject_list; packet->interface->client->config->reject_list = list; /* * We should inform user that we won't be accepting this server * anymore. */ log_info("Server added to list of rejected servers."); } dhcp-4.2.4/client/dhclient.conf000644 000765 000024 00000002000 11443777534 016315 0ustar00sarstaff000000 000000 send host-name = pick-first-value(gethostname(), "ISC-dhclient"); send dhcp-client-identifier 1:0:a0:24:ab:fb:9c; send dhcp-lease-time 3600; supersede domain-search "fugue.com", "home.vix.com"; prepend domain-name-servers 127.0.0.1; request subnet-mask, broadcast-address, time-offset, routers, domain-name, domain-name-servers, host-name; require subnet-mask, domain-name-servers; timeout 60; retry 60; reboot 10; select-timeout 5; initial-interval 2; script "/etc/dhclient-script"; media "-link0 -link1 -link2", "link0 link1"; reject 192.33.137.209; alias { interface "ep0"; fixed-address 192.5.5.213; option subnet-mask 255.255.255.255; } lease { interface "ep0"; fixed-address 192.33.137.200; medium "link0 link1"; option host-name "andare.swiftmedia.com"; option subnet-mask 255.255.255.0; option broadcast-address 192.33.137.255; option routers 192.33.137.250; option domain-name-servers 127.0.0.1; renew 2 2000/1/12 00:00:01; rebind 2 2000/1/12 00:00:01; expire 2 2000/1/12 00:00:01; } dhcp-4.2.4/client/dhclient.conf.5000644 000765 000024 00000071375 11743052074 016471 0ustar00sarstaff000000 000000 .\" $Id: dhclient.conf.5,v 1.25.24.10 2012-04-16 17:17:48 sar Exp $ .\" .\" Copyright (c) 2009-2012 by Internet Systems Consortium, Inc. ("ISC") .\" Copyright (c) 2004,2007 by Internet Systems Consortium, Inc. ("ISC") .\" Copyright (c) 1996-2003 by Internet Software Consortium .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above .\" copyright notice and this permission notice appear in all copies. .\" .\" THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES .\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR .\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES .\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT .\" OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" .\" Internet Systems Consortium, Inc. .\" 950 Charter Street .\" Redwood City, CA 94063 .\" .\" https://www.isc.org/ .\" .\" This software has been written for Internet Software Consortium .\" by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. .\" .\" Support and other services are available for ISC products - see .\" https://www.isc.org for more information or to learn more about ISC. .\" .TH dhclient.conf 5 .SH NAME dhclient.conf - DHCP client configuration file .SH DESCRIPTION The dhclient.conf file contains configuration information for .IR dhclient, the Internet Systems Consortium DHCP Client. .PP The dhclient.conf file is a free-form ASCII text file. It is parsed by the recursive-descent parser built into dhclient. The file may contain extra tabs and newlines for formatting purposes. Keywords in the file are case-insensitive. Comments may be placed anywhere within the file (except within quotes). Comments begin with the # character and end at the end of the line. .PP The dhclient.conf file can be used to configure the behaviour of the client in a wide variety of ways: protocol timing, information requested from the server, information required of the server, defaults to use if the server does not provide certain information, values with which to override information provided by the server, or values to prepend or append to information provided by the server. The configuration file can also be preinitialized with addresses to use on networks that don't have DHCP servers. .SH PROTOCOL TIMING The timing behaviour of the client need not be configured by the user. If no timing configuration is provided by the user, a fairly reasonable timing behaviour will be used by default - one which results in fairly timely updates without placing an inordinate load on the server. .PP The following statements can be used to adjust the timing behaviour of the DHCP client if required, however: .PP .I The .B timeout .I statement .PP .B timeout .I time .B ; .PP The .I timeout statement determines the amount of time that must pass between the time that the client begins to try to determine its address and the time that it decides that it's not going to be able to contact a server. By default, this timeout is sixty seconds. After the timeout has passed, if there are any static leases defined in the configuration file, or any leases remaining in the lease database that have not yet expired, the client will loop through these leases attempting to validate them, and if it finds one that appears to be valid, it will use that lease's address. If there are no valid static leases or unexpired leases in the lease database, the client will restart the protocol after the defined retry interval. .PP .I The .B retry .I statement .PP \fBretry \fItime\fR\fB;\fR .PP The .I retry statement determines the time that must pass after the client has determined that there is no DHCP server present before it tries again to contact a DHCP server. By default, this is five minutes. .PP .I The .B select-timeout .I statement .PP \fBselect-timeout \fItime\fR\fB;\fR .PP It is possible (some might say desirable) for there to be more than one DHCP server serving any given network. In this case, it is possible that a client may be sent more than one offer in response to its initial lease discovery message. It may be that one of these offers is preferable to the other (e.g., one offer may have the address the client previously used, and the other may not). .PP The .I select-timeout is the time after the client sends its first lease discovery request at which it stops waiting for offers from servers, assuming that it has received at least one such offer. If no offers have been received by the time the .I select-timeout has expired, the client will accept the first offer that arrives. .PP By default, the select-timeout is zero seconds - that is, the client will take the first offer it sees. .PP .I The .B reboot .I statement .PP \fBreboot \fItime\fR\fB;\fR .PP When the client is restarted, it first tries to reacquire the last address it had. This is called the INIT-REBOOT state. If it is still attached to the same network it was attached to when it last ran, this is the quickest way to get started. The .I reboot statement sets the time that must elapse after the client first tries to reacquire its old address before it gives up and tries to discover a new address. By default, the reboot timeout is ten seconds. .PP .I The .B backoff-cutoff .I statement .PP \fBbackoff-cutoff \fItime\fR\fB;\fR .PP The client uses an exponential backoff algorithm with some randomness, so that if many clients try to configure themselves at the same time, they will not make their requests in lockstep. The .I backoff-cutoff statement determines the maximum amount of time that the client is allowed to back off, the actual value will be evaluated randomly between 1/2 to 1 1/2 times the \fItime\fR specified. It defaults to fifteen seconds. .PP .I The .B initial-interval .I statement .PP \fBinitial-interval \fItime\fR\fB;\fR .PP The .I initial-interval statement sets the amount of time between the first attempt to reach a server and the second attempt to reach a server. Each time a message is sent, the interval between messages is incremented by twice the current interval multiplied by a random number between zero and one. If it is greater than the backoff-cutoff amount, it is set to that amount. It defaults to ten seconds. .PP .I The initial-delay .I statement .PP \fBinitial-delay \fItime\fR\fB;\fR .PP .I initial-delay parameter sets the maximum time client can wait after start before commencing first transmission. According to RFC2131 Section 4.4.1, client should wait a random time between startup and the actual first transmission. Previous versions of ISC DHCP client used to wait random time up to 5 seconds, but that was unwanted due to impact on startup time. As such, new versions have the default initial delay set to 0. To restore old behavior, please set initial-delay to 5. .SH LEASE REQUIREMENTS AND REQUESTS The DHCP protocol allows the client to request that the server send it specific information, and not send it other information that it is not prepared to accept. The protocol also allows the client to reject offers from servers if they don't contain information the client needs, or if the information provided is not satisfactory. .PP There is a variety of data contained in offers that DHCP servers send to DHCP clients. The data that can be specifically requested is what are called \fIDHCP Options\fR. DHCP Options are defined in \fBdhcp-options(5)\fR. .PP .I The .B request .I statement .PP \fB[ also ] request [ [ \fIoption-space\fR . ] \fIoption\fR ] [\fB,\fI ... ]\fB;\fR .PP The request statement causes the client to request that any server responding to the client send the client its values for the specified options. Only the option names should be specified in the request statement - not option parameters. By default, the DHCPv4 client requests the subnet-mask, broadcast-address, time-offset, routers, domain-name, domain-name-servers and host-name options while the DHCPv6 client requests the dhcp6 name-servers and domain-search options. Note that if you enter a \'request\' statement, you over-ride these defaults and these options will not be requested. .PP In some cases, it may be desirable to send no parameter request list at all. To do this, simply write the request statement but specify no parameters: .PP .nf request; .fi .PP In most cases, it is desirable to simply add one option to the request list which is of interest to the client in question. In this case, it is best to \'also request\' the additional options: .PP .nf also request domain-search, dhcp6.sip-servers-addresses; .fi .PP .I The .B require .I statement .PP \fB[ also ] require [ [ \fIoption-space\fR . ] \fIoption\fR ] [\fB,\fI ... ]\fB;\fR .PP The require statement lists options that must be sent in order for an offer to be accepted. Offers that do not contain all the listed options will be ignored. There is no default require list. .PP .nf require name-servers; interface eth0 { also require domain-search; } .PP .I The .B send .I statement .PP \fBsend { [ \fIoption declaration\fR ] [\fB,\fI ... \fIoption declaration\fR ]\fB}\fR .PP The send statement causes the client to send the specified options to the server with the specified values. These are full option declarations as described in \fBdhcp-options(5)\fR. Options that are always sent in the DHCP protocol should not be specified here, except that the client can specify a requested \fBdhcp-lease-time\fR option other than the default requested lease time, which is two hours. The other obvious use for this statement is to send information to the server that will allow it to differentiate between this client and other clients or kinds of clients. .SH DYNAMIC DNS The client now has some very limited support for doing DNS updates when a lease is acquired. This is prototypical, and probably doesn't do what you want. It also only works if you happen to have control over your DNS server, which isn't very likely. .PP Note that everything in this section is true whether you are using DHCPv4 or DHCPv6. The exact same syntax is used for both. .PP To make it work, you have to declare a key and zone as in the DHCP server (see \fBdhcpd.conf\fR(5) for details). You also need to configure the fqdn option on the client, as follows: .PP .nf send fqdn.fqdn "grosse.fugue.com."; send fqdn.encoded on; send fqdn.server-update off; also request fqdn, dhcp6.fqdn; .fi .PP The \fIfqdn.fqdn\fR option \fBMUST\fR be a fully-qualified domain name. You \fBMUST\fR define a zone statement for the zone to be updated. The \fIfqdn.encoded\fR option may need to be set to \fIon\fR or \fIoff\fR, depending on the DHCP server you are using. .PP .I The .B do-forward-updates .I statement .PP \fBdo-forward-updates [ \fIflag\fR ] \fB;\fR .PP If you want to do DNS updates in the DHCP client script (see \fBdhclient-script(8)\fR) rather than having the DHCP client do the update directly (for example, if you want to use SIG(0) authentication, which is not supported directly by the DHCP client, you can instruct the client not to do the update using the \fBdo-forward-updates\fR statement. \fIFlag\fR should be \fBtrue\fR if you want the DHCP client to do the update, and \fBfalse\fR if you don't want the DHCP client to do the update. By default, the DHCP client will do the DNS update. .SH OPTION MODIFIERS In some cases, a client may receive option data from the server which is not really appropriate for that client, or may not receive information that it needs, and for which a useful default value exists. It may also receive information which is useful, but which needs to be supplemented with local information. To handle these needs, several option modifiers are available. .PP .I The .B default .I statement .PP \fBdefault [ \fIoption declaration\fR ] \fB;\fR .PP If for some option the client should use the value supplied by the server, but needs to use some default value if no value was supplied by the server, these values can be defined in the .B default statement. .PP .I The .B supersede .I statement .PP \fBsupersede [ \fIoption declaration\fR ] \fB;\fR .PP If for some option the client should always use a locally-configured value or values rather than whatever is supplied by the server, these values can be defined in the .B supersede statement. .PP .I The .B prepend .I statement .PP \fBprepend [ \fIoption declaration\fR ] \fB;\fR .PP If for some set of options the client should use a value you supply, and then use the values supplied by the server, if any, these values can be defined in the .B prepend statement. The .B prepend statement can only be used for options which allow more than one value to be given. This restriction is not enforced - if you ignore it, the behaviour will be unpredictable. .PP .I The .B append .I statement .PP \fBappend [ \fIoption declaration\fR ] \fB;\fR .PP If for some set of options the client should first use the values supplied by the server, if any, and then use values you supply, these values can be defined in the .B append statement. The .B append statement can only be used for options which allow more than one value to be given. This restriction is not enforced - if you ignore it, the behaviour will be unpredictable. .SH LEASE DECLARATIONS .PP .I The .B lease .I declaration .PP \fBlease {\fR \fIlease-declaration\fR [ ... \fIlease-declaration ] \fB}\fR .PP The DHCP client may decide after some period of time (see \fBPROTOCOL TIMING\fR) that it is not going to succeed in contacting a server. At that time, it consults its own database of old leases and tests each one that has not yet timed out by pinging the listed router for that lease to see if that lease could work. It is possible to define one or more \fIfixed\fR leases in the client configuration file for networks where there is no DHCP or BOOTP service, so that the client can still automatically configure its address. This is done with the .B lease statement. .PP NOTE: the lease statement is also used in the dhclient.leases file in order to record leases that have been received from DHCP servers. Some of the syntax for leases as described below is only needed in the dhclient.leases file. Such syntax is documented here for completeness. .PP A lease statement consists of the lease keyword, followed by a left curly brace, followed by one or more lease declaration statements, followed by a right curly brace. The following lease declarations are possible: .PP \fBbootp;\fR .PP The .B bootp statement is used to indicate that the lease was acquired using the BOOTP protocol rather than the DHCP protocol. It is never necessary to specify this in the client configuration file. The client uses this syntax in its lease database file. .PP \fBinterface\fR \fB"\fR\fIstring\fR\fB";\fR .PP The .B interface lease statement is used to indicate the interface on which the lease is valid. If set, this lease will only be tried on a particular interface. When the client receives a lease from a server, it always records the interface number on which it received that lease. If predefined leases are specified in the dhclient.conf file, the interface should also be specified, although this is not required. .PP \fBfixed-address\fR \fIip-address\fR\fB;\fR .PP The .B fixed-address statement is used to set the ip address of a particular lease. This is required for all lease statements. The IP address must be specified as a dotted quad (e.g., 12.34.56.78). .PP \fBfilename "\fR\fIstring\fR\fB";\fR .PP The .B filename statement specifies the name of the boot filename to use. This is not used by the standard client configuration script, but is included for completeness. .PP \fBserver-name "\fR\fIstring\fR\fB";\fR .PP The .B server-name statement specifies the name of the boot server name to use. This is also not used by the standard client configuration script. .PP \fBoption\fR \fIoption-declaration\fR\fB;\fR .PP The .B option statement is used to specify the value of an option supplied by the server, or, in the case of predefined leases declared in dhclient.conf, the value that the user wishes the client configuration script to use if the predefined lease is used. .PP \fBscript "\fIscript-name\fB";\fR .PP The .B script statement is used to specify the pathname of the dhcp client configuration script. This script is used by the dhcp client to set each interface's initial configuration prior to requesting an address, to test the address once it has been offered, and to set the interface's final configuration once a lease has been acquired. If no lease is acquired, the script is used to test predefined leases, if any, and also called once if no valid lease can be identified. For more information, see .B dhclient-script(8). .PP \fBvendor option space "\fIname\fB";\fR .PP The .B vendor option space statement is used to specify which option space should be used for decoding the vendor-encapsulate-options option if one is received. The \fIdhcp-vendor-identifier\fR can be used to request a specific class of vendor options from the server. See .B dhcp-options(5) for details. .PP \fBmedium "\fImedia setup\fB";\fR .PP The .B medium statement can be used on systems where network interfaces cannot automatically determine the type of network to which they are connected. The media setup string is a system-dependent parameter which is passed to the dhcp client configuration script when initializing the interface. On Unix and Unix-like systems, the argument is passed on the ifconfig command line when configuring the interface. .PP The dhcp client automatically declares this parameter if it uses a media type (see the .B media statement) when configuring the interface in order to obtain a lease. This statement should be used in predefined leases only if the network interface requires media type configuration. .PP \fBrenew\fR \fIdate\fB;\fR .PP \fBrebind\fR \fIdate\fB;\fR .PP \fBexpire\fR \fIdate\fB;\fR .PP The \fBrenew\fR statement defines the time at which the dhcp client should begin trying to contact its server to renew a lease that it is using. The \fBrebind\fR statement defines the time at which the dhcp client should begin to try to contact \fIany\fR dhcp server in order to renew its lease. The \fBexpire\fR statement defines the time at which the dhcp client must stop using a lease if it has not been able to contact a server in order to renew it. .PP These declarations are automatically set in leases acquired by the DHCP client, but must also be configured in predefined leases - a predefined lease whose expiry time has passed will not be used by the DHCP client. .PP Dates are specified in one of two ways. The software will output times in these two formats depending on if the \fBdb-time-format\fR configuration parameter has been set to \fIdefault\fR or \fIlocal\fR. .PP If it is set to \fIdefault\fR, then \fIdate\fR values appear as follows: .PP \fI \fB/\fI\fB/\fI \fB:\fI\fB:\fI\fR .PP The weekday is present to make it easy for a human to tell when a lease expires - it's specified as a number from zero to six, with zero being Sunday. When declaring a predefined lease, it can always be specified as zero. The year is specified with the century, so it should generally be four digits except for really long leases. The month is specified as a number starting with 1 for January. The day of the month is likewise specified starting with 1. The hour is a number between 0 and 23, the minute a number between 0 and 59, and the second also a number between 0 and 59. .PP If the \fBdb-time-format\fR configuration was set to \fIlocal\fR, then the \fIdate\fR values appear as follows: .PP \fBepoch\fR \fI\fR\fB; #\fR \fI \fR\fB:\fR\fI\fR\fB:\fR\fI \fR .PP The \fIseconds-since-epoch\fR is as according to the system's local clock (often referred to as "unix time"). The \fB#\fR symbol supplies a comment that describes what actual time this is as according to the system's configured timezone, at the time the value was written. It is provided only for human inspection, the epoch time is the only recommended value for machine inspection. .PP Note that when defining a static lease, one may use either time format one wishes, and need not include the comment or values after it. .PP If the time is infinite in duration, then the \fIdate\fR is \fBnever\fR instead of an actual date. .SH ALIAS DECLARATIONS \fBalias { \fI declarations ... \fB}\fR .PP Some DHCP clients running TCP/IP roaming protocols may require that in addition to the lease they may acquire via DHCP, their interface also be configured with a predefined IP alias so that they can have a permanent IP address even while roaming. The Internet Systems Consortium DHCP client doesn't support roaming with fixed addresses directly, but in order to facilitate such experimentation, the dhcp client can be set up to configure an IP alias using the .B alias declaration. .PP The alias declaration resembles a lease declaration, except that options other than the subnet-mask option are ignored by the standard client configuration script, and expiry times are ignored. A typical alias declaration includes an interface declaration, a fixed-address declaration for the IP alias address, and a subnet-mask option declaration. A medium statement should never be included in an alias declaration. .SH OTHER DECLARATIONS \fBdb-time-format\fR [ \fIdefault\fR | \fIlocal\fR ] \fB;\fR .PP The \fBdb-time-format\fR option determines which of two output methods are used for printing times in leases files. The \fIdefault\fR format provides day-and-time in UTC, whereas \fIlocal\fR uses a seconds-since-epoch to store the time value, and helpfully places a local timezone time in a comment on the same line. The formats are described in detail in this manpage, whithin the LEASE DECLARATIONS section. .PP \fBreject \fIcidr-ip-address\fR [\fB,\fR \fI...\fB \fIcidr-ip-address\fR ] \fB;\fR .PP The .B reject statement causes the DHCP client to reject offers from servers whose server identifier matches any of the specified hosts or subnets. This can be used to avoid being configured by rogue or misconfigured dhcp servers, although it should be a last resort - better to track down the bad DHCP server and fix it. .PP The \fIcidr-ip-address\fR configuration type is of the form \fIip-address\fR[\fB/\fIprefixlen\fR], where \fIip-address\fR is a dotted quad IP address, and \fRprefixlen\fR is the CIDR prefix length of the subnet, counting the number of significant bits in the netmask starting from the leftmost end. Example configuration syntax: .PP .I \fIreject\fR 192.168.0.0\fB/\fR16\fB,\fR 10.0.0.5\fB;\fR .PP The above example would cause offers from any server identifier in the entire RFC 1918 "Class C" network 192.168.0.0/16, or the specific single address 10.0.0.5, to be rejected. .PP \fBinterface "\fIname\fB" { \fIdeclarations ... \fB } .PP A client with more than one network interface may require different behaviour depending on which interface is being configured. All timing parameters and declarations other than lease and alias declarations can be enclosed in an interface declaration, and those parameters will then be used only for the interface that matches the specified name. Interfaces for which there is no interface declaration will use the parameters declared outside of any interface declaration, or the default settings. .PP .B Note well: ISC dhclient only maintains one list of interfaces, which is either determined at startup from command line arguments, or otherwise is autodetected. If you supplied the list of interfaces on the command line, this configuration clause will add the named interface to the list in such a way that will cause it to be configured by DHCP. Which may not be the result you had intended. This is an undesirable side effect that will be addressed in a future release. .PP \fBpseudo "\fIname\fR" "\fIreal-name\fB" { \fIdeclarations ... \fB } .PP Under some circumstances it can be useful to declare a pseudo-interface and have the DHCP client acquire a configuration for that interface. Each interface that the DHCP client is supporting normally has a DHCP client state machine running on it to acquire and maintain its lease. A pseudo-interface is just another state machine running on the interface named \fIreal-name\fR, with its own lease and its own state. If you use this feature, you must provide a client identifier for both the pseudo-interface and the actual interface, and the two identifiers must be different. You must also provide a separate client script for the pseudo-interface to do what you want with the IP address. For example: .PP .nf interface "ep0" { send dhcp-client-identifier "my-client-ep0"; } pseudo "secondary" "ep0" { send dhcp-client-identifier "my-client-ep0-secondary"; script "/etc/dhclient-secondary"; } .fi .PP The client script for the pseudo-interface should not configure the interface up or down - essentially, all it needs to handle are the states where a lease has been acquired or renewed, and the states where a lease has expired. See \fBdhclient-script(8)\fR for more information. .PP \fBmedia "\fImedia setup\fB"\fI [ \fB, "\fImedia setup\fB", \fI... ]\fB;\fR .PP The .B media statement defines one or more media configuration parameters which may be tried while attempting to acquire an IP address. The dhcp client will cycle through each media setup string on the list, configuring the interface using that setup and attempting to boot, and then trying the next one. This can be used for network interfaces which aren't capable of sensing the media type unaided - whichever media type succeeds in getting a request to the server and hearing the reply is probably right (no guarantees). .PP The media setup is only used for the initial phase of address acquisition (the DHCPDISCOVER and DHCPOFFER packets). Once an address has been acquired, the dhcp client will record it in its lease database and will record the media type used to acquire the address. Whenever the client tries to renew the lease, it will use that same media type. The lease must expire before the client will go back to cycling through media types. .PP \fBhardware\fR \fIlink-type mac-address\fR\fB;\fR .PP The .B hardware statement defines the hardware MAC address to use for this interface, for DHCP servers or relays to direct their replies. dhclient will determine the interface's MAC address automatically, so use of this parameter is not recommended. The \fIlink-type\fR corresponds to the interface's link layer type (example: \'ethernet\'), while the \fImac-address\fR is a string of colon-separated hexadecimal values for octets. .PP \fBanycast-mac\fR \fIlink-type mac-address\fR\fB;\fR .PP The .B anycast-mac statement over-rides the all-ones broadcast MAC address dhclient will use when it is transmitting packets to the all-ones limited broadcast IPv4 address. This configuration parameter is useful to reduce the number of broadcast packets transmitted by DHCP clients, but is only useful if you know the DHCP service(s) anycast MAC address prior to configuring your client. The \fIlink-type\fR and \fImac-address\fR parameters are configured in a similar manner to the \fBhardware\fR statement. .PP .SH SAMPLE The following configuration file is used on a laptop running NetBSD 1.3. The laptop has an IP alias of 192.5.5.213, and has one interface, ep0 (a 3com 3C589C). Booting intervals have been shortened somewhat from the default, because the client is known to spend most of its time on networks with little DHCP activity. The laptop does roam to multiple networks. .nf timeout 60; retry 60; reboot 10; select-timeout 5; initial-interval 2; reject 192.33.137.209; interface "ep0" { send host-name "andare.fugue.com"; hardware ethernet 00:a0:24:ab:fb:9c; send dhcp-client-identifier 1:0:a0:24:ab:fb:9c; send dhcp-lease-time 3600; supersede domain-search "fugue.com", "rc.vix.com", "home.vix.com"; prepend domain-name-servers 127.0.0.1; request subnet-mask, broadcast-address, time-offset, routers, domain-name, domain-name-servers, host-name; require subnet-mask, domain-name-servers; script "CLIENTBINDIR/dhclient-script"; media "media 10baseT/UTP", "media 10base2/BNC"; } alias { interface "ep0"; fixed-address 192.5.5.213; option subnet-mask 255.255.255.255; } .fi This is a very complicated dhclient.conf file - in general, yours should be much simpler. In many cases, it's sufficient to just create an empty dhclient.conf file - the defaults are usually fine. .SH SEE ALSO dhcp-options(5), dhcp-eval(5), dhclient.leases(5), dhcpd(8), dhcpd.conf(5), RFC2132, RFC2131. .SH AUTHOR .B dhclient(8) was written by Ted Lemon under a contract with Vixie Labs. Funding for this project was provided by Internet Systems Consortium. Information about Internet Systems Consortium can be found at .B https://www.isc.org. dhcp-4.2.4/client/dhclient.leases.5000644 000765 000024 00000004563 11531316665 017017 0ustar00sarstaff000000 000000 .\" $Id: dhclient.leases.5,v 1.5.24.3 2011-02-23 23:52:21 sar Exp $ .\" .\" Copyright (c) 2009-2011 by Internet Systems Consortium, Inc. ("ISC") .\" Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") .\" Copyright (c) 1997-2003 by Internet Software Consortium .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above .\" copyright notice and this permission notice appear in all copies. .\" .\" THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES .\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR .\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES .\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT .\" OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" .\" Internet Systems Consortium, Inc. .\" 950 Charter Street .\" Redwood City, CA 94063 .\" .\" https://www.isc.org/ .\" .\" This software has been written for Internet Systems Consortium .\" by Ted Lemon in cooperation with Vixie Enterprises. .\" .\" Support and other services are available for ISC products - see .\" https://www.isc.org for more information or to learn more about ISC. .\" .\" $Id: dhclient.leases.5,v 1.5.24.3 2011-02-23 23:52:21 sar Exp $ .\" .TH dhclient.leases 5 .SH NAME dhclient.leases - DHCP client lease database .SH DESCRIPTION The Internet Systems Consortium DHCP client keeps a persistent database of leases that it has acquired that are still valid. The database is a free-form ASCII file containing one valid declaration per lease. If more than one declaration appears for a given lease, the last one in the file is used. The file is written as a log, so this is not an unusual occurrence. .PP The format of the lease declarations is described in .B dhclient.conf(5). .SH FILES .B DBDIR/dhclient.leases .SH SEE ALSO dhclient(8), dhcp-options(5), dhclient.conf(5), dhcpd(8), dhcpd.conf(5), RFC2132, RFC2131. .SH AUTHOR .B dhclient(8) was written by Ted Lemon under a contract with Vixie Labs. Funding for this project was provided by Internet Systems Consortium. Information about Internet Systems Consortium can be found at .B https://www.isc.org. dhcp-4.2.4/client/Makefile.am000644 000765 000024 00000001405 11443774004 015705 0ustar00sarstaff000000 000000 dist_sysconf_DATA = dhclient.conf sbin_PROGRAMS = dhclient dhclient_SOURCES = clparse.c dhclient.c dhc6.c \ scripts/bsdos scripts/freebsd scripts/linux scripts/macos \ scripts/netbsd scripts/nextstep scripts/openbsd \ scripts/solaris scripts/openwrt dhclient_LDADD = ../common/libdhcp.a ../omapip/libomapi.a \ ../bind/lib/libdns.a ../bind/lib/libisc.a man_MANS = dhclient.8 dhclient-script.8 dhclient.conf.5 dhclient.leases.5 EXTRA_DIST = $(man_MANS) dhclient.o: dhclient.c $(COMPILE) -DCLIENT_PATH='"PATH=$(sbindir):/sbin:/bin:/usr/sbin:/usr/bin"' \ -DLOCALSTATEDIR='"$(localstatedir)"' -c dhclient.c dhc6.o: dhc6.c $(COMPILE) -DCLIENT_PATH='"PATH=$(sbindir):/sbin:/bin:/usr/sbin:/usr/bin"' \ -DLOCALSTATEDIR='"$(localstatedir)"' -c dhc6.c dhcp-4.2.4/client/Makefile.in000644 000765 000024 00000043521 11757500140 015717 0ustar00sarstaff000000 000000 # Makefile.in generated by automake 1.10.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : sbin_PROGRAMS = dhclient$(EXEEXT) subdir = client DIST_COMMON = $(dist_sysconf_DATA) $(srcdir)/Makefile.am \ $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/includes/config.h CONFIG_CLEAN_FILES = am__installdirs = "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(man5dir)" \ "$(DESTDIR)$(man8dir)" "$(DESTDIR)$(sysconfdir)" sbinPROGRAMS_INSTALL = $(INSTALL_PROGRAM) PROGRAMS = $(sbin_PROGRAMS) am_dhclient_OBJECTS = clparse.$(OBJEXT) dhclient.$(OBJEXT) \ dhc6.$(OBJEXT) dhclient_OBJECTS = $(am_dhclient_OBJECTS) dhclient_DEPENDENCIES = ../common/libdhcp.a ../omapip/libomapi.a \ ../bind/lib/libdns.a ../bind/lib/libisc.a DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/includes depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) CCLD = $(CC) LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ SOURCES = $(dhclient_SOURCES) DIST_SOURCES = $(dhclient_SOURCES) man5dir = $(mandir)/man5 man8dir = $(mandir)/man8 NROFF = nroff MANS = $(man_MANS) am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = `echo $$p | sed -e 's|^.*/||'`; dist_sysconfDATA_INSTALL = $(INSTALL_DATA) DATA = $(dist_sysconf_DATA) ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ GREP = @GREP@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDAP_CFLAGS = @LDAP_CFLAGS@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_prefix_program = @ac_prefix_program@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build_alias = @build_alias@ builddir = @builddir@ byte_order = @byte_order@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host_alias = @host_alias@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ dist_sysconf_DATA = dhclient.conf dhclient_SOURCES = clparse.c dhclient.c dhc6.c \ scripts/bsdos scripts/freebsd scripts/linux scripts/macos \ scripts/netbsd scripts/nextstep scripts/openbsd \ scripts/solaris scripts/openwrt dhclient_LDADD = ../common/libdhcp.a ../omapip/libomapi.a \ ../bind/lib/libdns.a ../bind/lib/libisc.a man_MANS = dhclient.8 dhclient-script.8 dhclient.conf.5 dhclient.leases.5 EXTRA_DIST = $(man_MANS) all: all-am .SUFFIXES: .SUFFIXES: .c .o .obj $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ && exit 0; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign client/Makefile'; \ cd $(top_srcdir) && \ $(AUTOMAKE) --foreign client/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh install-sbinPROGRAMS: $(sbin_PROGRAMS) @$(NORMAL_INSTALL) test -z "$(sbindir)" || $(MKDIR_P) "$(DESTDIR)$(sbindir)" @list='$(sbin_PROGRAMS)'; for p in $$list; do \ p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ if test -f $$p \ ; then \ f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \ echo " $(INSTALL_PROGRAM_ENV) $(sbinPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(sbindir)/$$f'"; \ $(INSTALL_PROGRAM_ENV) $(sbinPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(sbindir)/$$f" || exit 1; \ else :; fi; \ done uninstall-sbinPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(sbin_PROGRAMS)'; for p in $$list; do \ f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ echo " rm -f '$(DESTDIR)$(sbindir)/$$f'"; \ rm -f "$(DESTDIR)$(sbindir)/$$f"; \ done clean-sbinPROGRAMS: -test -z "$(sbin_PROGRAMS)" || rm -f $(sbin_PROGRAMS) dhclient$(EXEEXT): $(dhclient_OBJECTS) $(dhclient_DEPENDENCIES) @rm -f dhclient$(EXEEXT) $(LINK) $(dhclient_OBJECTS) $(dhclient_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/clparse.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dhc6.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dhclient.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` install-man5: $(man5_MANS) $(man_MANS) @$(NORMAL_INSTALL) test -z "$(man5dir)" || $(MKDIR_P) "$(DESTDIR)$(man5dir)" @list='$(man5_MANS) $(dist_man5_MANS) $(nodist_man5_MANS)'; \ l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ for i in $$l2; do \ case "$$i" in \ *.5*) list="$$list $$i" ;; \ esac; \ done; \ for i in $$list; do \ if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \ else file=$$i; fi; \ ext=`echo $$i | sed -e 's/^.*\\.//'`; \ case "$$ext" in \ 5*) ;; \ *) ext='5' ;; \ esac; \ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ inst=`echo $$inst | sed -e 's/^.*\///'`; \ inst=`echo $$inst | sed '$(transform)'`.$$ext; \ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man5dir)/$$inst'"; \ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man5dir)/$$inst"; \ done uninstall-man5: @$(NORMAL_UNINSTALL) @list='$(man5_MANS) $(dist_man5_MANS) $(nodist_man5_MANS)'; \ l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ for i in $$l2; do \ case "$$i" in \ *.5*) list="$$list $$i" ;; \ esac; \ done; \ for i in $$list; do \ ext=`echo $$i | sed -e 's/^.*\\.//'`; \ case "$$ext" in \ 5*) ;; \ *) ext='5' ;; \ esac; \ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ inst=`echo $$inst | sed -e 's/^.*\///'`; \ inst=`echo $$inst | sed '$(transform)'`.$$ext; \ echo " rm -f '$(DESTDIR)$(man5dir)/$$inst'"; \ rm -f "$(DESTDIR)$(man5dir)/$$inst"; \ done install-man8: $(man8_MANS) $(man_MANS) @$(NORMAL_INSTALL) test -z "$(man8dir)" || $(MKDIR_P) "$(DESTDIR)$(man8dir)" @list='$(man8_MANS) $(dist_man8_MANS) $(nodist_man8_MANS)'; \ l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ for i in $$l2; do \ case "$$i" in \ *.8*) list="$$list $$i" ;; \ esac; \ done; \ for i in $$list; do \ if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \ else file=$$i; fi; \ ext=`echo $$i | sed -e 's/^.*\\.//'`; \ case "$$ext" in \ 8*) ;; \ *) ext='8' ;; \ esac; \ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ inst=`echo $$inst | sed -e 's/^.*\///'`; \ inst=`echo $$inst | sed '$(transform)'`.$$ext; \ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man8dir)/$$inst'"; \ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man8dir)/$$inst"; \ done uninstall-man8: @$(NORMAL_UNINSTALL) @list='$(man8_MANS) $(dist_man8_MANS) $(nodist_man8_MANS)'; \ l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ for i in $$l2; do \ case "$$i" in \ *.8*) list="$$list $$i" ;; \ esac; \ done; \ for i in $$list; do \ ext=`echo $$i | sed -e 's/^.*\\.//'`; \ case "$$ext" in \ 8*) ;; \ *) ext='8' ;; \ esac; \ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ inst=`echo $$inst | sed -e 's/^.*\///'`; \ inst=`echo $$inst | sed '$(transform)'`.$$ext; \ echo " rm -f '$(DESTDIR)$(man8dir)/$$inst'"; \ rm -f "$(DESTDIR)$(man8dir)/$$inst"; \ done install-dist_sysconfDATA: $(dist_sysconf_DATA) @$(NORMAL_INSTALL) test -z "$(sysconfdir)" || $(MKDIR_P) "$(DESTDIR)$(sysconfdir)" @list='$(dist_sysconf_DATA)'; for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ f=$(am__strip_dir) \ echo " $(dist_sysconfDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(sysconfdir)/$$f'"; \ $(dist_sysconfDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(sysconfdir)/$$f"; \ done uninstall-dist_sysconfDATA: @$(NORMAL_UNINSTALL) @list='$(dist_sysconf_DATA)'; for p in $$list; do \ f=$(am__strip_dir) \ echo " rm -f '$(DESTDIR)$(sysconfdir)/$$f'"; \ rm -f "$(DESTDIR)$(sysconfdir)/$$f"; \ done ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) tags=; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$tags $$unique; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) tags=; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$tags$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$tags $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && cd $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) $$here distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ fi; \ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ else \ test -f $(distdir)/$$file \ || cp -p $$d/$$file $(distdir)/$$file \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(PROGRAMS) $(MANS) $(DATA) installdirs: for dir in "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(man5dir)" "$(DESTDIR)$(man8dir)" "$(DESTDIR)$(sysconfdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-sbinPROGRAMS mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am info: info-am info-am: install-data-am: install-man install-dvi: install-dvi-am install-exec-am: install-dist_sysconfDATA install-sbinPROGRAMS install-html: install-html-am install-info: install-info-am install-man: install-man5 install-man8 install-pdf: install-pdf-am install-ps: install-ps-am installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-dist_sysconfDATA uninstall-man \ uninstall-sbinPROGRAMS uninstall-man: uninstall-man5 uninstall-man8 .MAKE: install-am install-strip .PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ clean-sbinPROGRAMS ctags distclean distclean-compile \ distclean-generic distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dist_sysconfDATA install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-man5 install-man8 install-pdf install-pdf-am \ install-ps install-ps-am install-sbinPROGRAMS install-strip \ installcheck installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ uninstall-am uninstall-dist_sysconfDATA uninstall-man \ uninstall-man5 uninstall-man8 uninstall-sbinPROGRAMS dhclient.o: dhclient.c $(COMPILE) -DCLIENT_PATH='"PATH=$(sbindir):/sbin:/bin:/usr/sbin:/usr/bin"' \ -DLOCALSTATEDIR='"$(localstatedir)"' -c dhclient.c dhc6.o: dhc6.c $(COMPILE) -DCLIENT_PATH='"PATH=$(sbindir):/sbin:/bin:/usr/sbin:/usr/bin"' \ -DLOCALSTATEDIR='"$(localstatedir)"' -c dhc6.c # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: dhcp-4.2.4/client/scripts/000777 000765 000024 00000000000 11757514244 015352 5ustar00sarstaff000000 000000 dhcp-4.2.4/client/scripts/bsdos000755 000765 000024 00000023106 11565022662 016403 0ustar00sarstaff000000 000000 #!/bin/sh make_resolv_conf() { if [ x"$new_domain_name_servers" != x ]; then cat /dev/null > /etc/resolv.conf.dhclient if [ "x$new_domain_search" != x ]; then echo search $new_domain_search >> /etc/resolv.conf.dhclient elif [ "x$new_domain_name" != x ]; then # Note that the DHCP 'Domain Name Option' is really just a domain # name, and that this practice of using the domain name option as # a search path is both nonstandard and deprecated. echo search $new_domain_name >> /etc/resolv.conf.dhclient fi for nameserver in $new_domain_name_servers; do echo nameserver $nameserver >> /etc/resolv.conf.dhclient done mv /etc/resolv.conf.dhclient /etc/resolv.conf elif [ "x${new_dhcp6_name_servers}" != x ] ; then cat /dev/null > /etc/resolv.conf.dhclient6 chmod 644 /etc/resolv.conf.dhclient6 if [ "x${new_dhcp6_domain_search}" != x ] ; then echo search ${new_dhcp6_domain_search} >> /etc/resolv.conf.dhclient6 fi for nameserver in ${new_dhcp6_name_servers} ; do # If the nameserver has a link-local address # add a (interface name) to it. case $nameserver in fe80:*) zone_id="%$interface";; FE80:*) zone_id="%$interface";; *) zone_id='';; esac echo nameserver ${nameserver}$zone_id >> /etc/resolv.conf.dhclient6 done mv /etc/resolv.conf.dhclient6 /etc/resolv.conf fi } # Must be used on exit. Invokes the local dhcp client exit hooks, if any. exit_with_hooks() { exit_status=$1 if [ -f /etc/dhclient-exit-hooks ]; then . /etc/dhclient-exit-hooks fi # probably should do something with exit status of the local script exit $exit_status } # Invoke the local dhcp client enter hooks, if they exist. if [ -f /etc/dhclient-enter-hooks ]; then exit_status=0 . /etc/dhclient-enter-hooks # allow the local script to abort processing of this state # local script must set exit_status variable to nonzero. if [ $exit_status -ne 0 ]; then exit $exit_status fi fi if [ x$new_network_number != x ]; then echo New Network Number: $new_network_number fi if [ x$new_broadcast_address != x ]; then echo New Broadcast Address: $new_broadcast_address new_broadcast_arg="broadcast $new_broadcast_address" fi if [ x$old_broadcast_address != x ]; then old_broadcast_arg="broadcast $old_broadcast_address" fi if [ x$new_subnet_mask != x ]; then new_netmask_arg="netmask $new_subnet_mask" fi if [ x$old_subnet_mask != x ]; then old_netmask_arg="netmask $old_subnet_mask" fi if [ x$alias_subnet_mask != x ]; then alias_subnet_arg="netmask $alias_subnet_mask" fi if [ x$new_interface_mtu != x ]; then mtu_arg="mtu $new_interface_mtu" fi if [ x$IF_METRIC != x ]; then metric_arg="metric $IF_METRIC" fi if [ x$reason = xMEDIUM ]; then eval "ifconfig $interface $medium" eval "ifconfig $interface inet -alias 0.0.0.0 $medium" >/dev/null 2>&1 sleep 1 exit_with_hooks 0 fi ### ### DHCPv4 Handlers ### if [ x$reason = xPREINIT ]; then if [ x$alias_ip_address != x ]; then ifconfig $interface inet -alias $alias_ip_address > /dev/null 2>&1 route delete $alias_ip_address 127.0.0.1 > /dev/null 2>&1 fi ifconfig $interface inet 0.0.0.0 netmask 0.0.0.0 \ broadcast 255.255.255.255 up exit_with_hooks 0 fi if [ x$reason = xARPCHECK ] || [ x$reason = xARPSEND ]; then exit_with_hooks 0; fi if [ x$reason = xBOUND ] || [ x$reason = xRENEW ] || \ [ x$reason = xREBIND ] || [ x$reason = xREBOOT ]; then current_hostname=`hostname` if [ x$current_hostname = x ] || \ [ x$current_hostname = x$old_host_name ]; then if [ x$current_hostname = x ] || \ [ x$new_host_name != x$old_host_name ]; then hostname $new_host_name fi fi if [ x$old_ip_address != x ] && [ x$alias_ip_address != x ] && \ [ x$alias_ip_address != x$old_ip_address ]; then ifconfig $interface inet -alias $alias_ip_address > /dev/null 2>&1 route delete $alias_ip_address 127.0.0.1 > /dev/null 2>&1 fi if [ x$old_ip_address != x ] && [ x$old_ip_address != x$new_ip_address ] then eval "ifconfig $interface inet -alias $old_ip_address $medium" route delete $old_ip_address 127.1 >/dev/null 2>&1 for router in $old_routers; do route delete default $router >/dev/null 2>&1 done if [ "$old_static_routes" != "" ]; then set $old_static_routes while [ $# -gt 1 ]; do route delete $1 $2 shift; shift done fi arp -n -a | sed -n -e 's/^.*(\(.*\)) at .*$/arp -n -d \1/p' |sh fi if [ x$old_ip_address = x ] || [ x$old_ip_address != x$new_ip_address ] || \ [ x$reason = xBOUND ] || [ x$reason = xREBOOT ]; then eval "ifconfig $interface inet $new_ip_address $new_netmask_arg \ $new_broadcast_arg $mtu_arg $metric_arg $medium" route add $new_ip_address 127.1 >/dev/null 2>&1 for router in $new_routers; do route add default $router >/dev/null 2>&1 done if [ "$new_static_routes" != "" ]; then set $new_static_routes while [ $# -gt 1 ]; do route add $1 $2 shift; shift done fi else # we haven't changed the address, have we changed other options # that we wish to update? if [ x$new_routers != x ] && [ x$new_routers != x$old_routers ] ; then # if we've changed routers delete the old and add the new. $LOGGER "New Routers: $new_routers" for router in $old_routers; do route delete default $router >/dev/null 2>&1 done for router in $new_routers; do route add default $router >/dev/null 2>&1 done fi fi if [ x$new_ip_address != x$alias_ip_address ] && [ x$alias_ip_address != x ]; then ifconfig $interface inet alias $alias_ip_address $alias_subnet_arg route add $alias_ip_address 127.0.0.1 fi make_resolv_conf exit_with_hooks 0 fi if [ x$reason = xEXPIRE ] || [ x$reason = xFAIL ] || [ x$reason = xRELEASE ] \ || [ x$reason = xSTOP ]; then if [ x$alias_ip_address != x ]; then ifconfig $interface inet -alias $alias_ip_address > /dev/null 2>&1 route delete $alias_ip_address 127.0.0.1 > /dev/null 2>&1 fi if [ x$old_ip_address != x ]; then eval "ifconfig $interface inet -alias $old_ip_address $medium" route delete $old_ip_address 127.1 >/dev/null 2>&1 for router in $old_routers; do route delete default $router >/dev/null 2>&1 done if [ "$old_static_routes" != "" ]; then set $old_static_routes while [ $# -gt 1 ]; do route delete $1 $2 shift; shift done fi arp -n -a | sed -n -e 's/^.*(\(.*\)) at .*$/arp -n -d \1/p' \ |sh >/dev/null 2>&1 fi if [ x$alias_ip_address != x ]; then ifconfig $interface inet alias $alias_ip_address $alias_subnet_arg route add $alias_ip_address 127.0.0.1 fi exit_with_hooks 0 fi if [ x$reason = xTIMEOUT ]; then if [ x$alias_ip_address != x ]; then ifconfig $interface inet -alias $alias_ip_address > /dev/null 2>&1 route delete $alias_ip_address 127.0.0.1 > /dev/null 2>&1 fi eval "ifconfig $interface inet $new_ip_address $new_netmask_arg \ $new_broadcast_arg $mtu_arg $metric_arg $medium" sleep 1 if [ "$new_routers" != "" ]; then set $new_routers if ping -q -c 1 -w 1 $1; then if [ x$new_ip_address != x$alias_ip_address ] && \ [ x$alias_ip_address != x ]; then ifconfig $interface inet alias $alias_ip_address $alias_subnet_arg route add $alias_ip_address 127.0.0.1 fi route add $new_ip_address 127.1 >/dev/null 2>&1 for router in $new_routers; do route add default $router >/dev/null 2>&1 done set $new_static_routes while [ $# -gt 1 ]; do route add $0 $1 shift; shift done make_resolv_conf exit_with_hooks 0 fi fi eval "ifconfig $interface inet -alias $new_ip_address $medium" for router in $old_routers; do route delete default $router >/dev/null 2>&1 done if [ "$old_static_routes" != "" ]; then set $old_static_routes while [ $# -gt 1 ]; do route delete $1 $2 shift; shift done fi arp -n -a | sed -n -e 's/^.*(\(.*\)) at .*$/arp -n -d \1/p' \ |sh >/dev/null 2>&1 exit_with_hooks 1 fi ### ### DHCPv6 Handlers ### if [ ${reason} = PREINIT6 ] ; then # Ensure interface is up. ifconfig ${interface} up # XXX: Remove any stale addresses from aborted clients. exit_with_hooks 0 fi if [ x${old_ip6_prefix} != x ] || [ x${new_ip6_prefix} != x ] ; then echo Prefix ${reason} old=${old_ip6_prefix} new=${new_ip6_prefix} exit_with_hooks 0 fi if [ ${reason} = BOUND6 ] ; then if [ x${new_ip6_address} = x ] || [ x${new_ip6_prefixlen} = x ] ; then exit_with_hooks 2; fi ifconfig ${interface} inet6 add ${new_ip6_address}/${new_ip6_prefixlen} # Check for nameserver options. make_resolv_conf exit_with_hooks 0 fi if [ ${reason} = RENEW6 ] || [ ${reason} = REBIND6 ] ; then # Make sure nothing has moved around on us. # Nameservers/domains/etc. if [ "x${new_dhcp6_name_servers}" != "x${old_dhcp6_name_servers}" ] || [ "x${new_dhcp6_domain_search}" != "x${old_dhcp6_domain_search}" ] ; then make_resolv_conf fi exit_with_hooks 0 fi if [ ${reason} = DEPREF6 ] ; then if [ x${new_ip6_prefixlen} = x ] ; then exit_with_hooks 2; fi # XXX: # There doesn't appear to be a way to update an addr to indicate # preference. exit_with_hooks 0 fi if [ ${reason} = EXPIRE6 -o ${reason} = RELEASE6 -o ${reason} = STOP6 ] ; then if [ x${old_ip6_address} = x ] || [ x${old_ip6_prefixlen} = x ] ; then exit_with_hooks 2; fi ifconfig ${interface} inet6 delete ${old_ip6_address}/${old_ip6_prefixlen} exit_with_hooks 0 fi exit_with_hooks 0 dhcp-4.2.4/client/scripts/freebsd000755 000765 000024 00000027526 11565022662 016715 0ustar00sarstaff000000 000000 #!/bin/sh # # $Id: freebsd,v 1.23.54.1 2011-05-18 20:01:54 sar Exp $ # # $FreeBSD$ if [ -x /usr/bin/logger ]; then LOGGER="/usr/bin/logger -s -p user.notice -t dhclient" else LOGGER=echo fi make_resolv_conf() { if [ x"$new_domain_name_servers" != x ]; then ( cat /dev/null > /etc/resolv.conf.dhclient ) exit_status=$? if [ $exit_status -ne 0 ]; then $LOGGER "Unable to create /etc/resolv.conf.dhclient: Error $exit_status" else if [ "x$new_domain_search" != x ]; then ( echo search $new_domain_search >> /etc/resolv.conf.dhclient ) exit_status=$? elif [ "x$new_domain_name" != x ]; then # Note that the DHCP 'Domain Name Option' is really just a domain # name, and that this practice of using the domain name option as # a search path is both nonstandard and deprecated. ( echo search $new_domain_name >> /etc/resolv.conf.dhclient ) exit_status=$? fi for nameserver in $new_domain_name_servers; do if [ $exit_status -ne 0 ]; then break fi ( echo nameserver $nameserver >>/etc/resolv.conf.dhclient ) exit_status=$? done # If there were no errors, attempt to mv the new file into place. if [ $exit_status -eq 0 ]; then ( mv /etc/resolv.conf.dhclient /etc/resolv.conf ) exit_status=$? fi if [ $exit_status -ne 0 ]; then $LOGGER "Error while writing new /etc/resolv.conf." fi fi elif [ "x${new_dhcp6_name_servers}" != x ] ; then ( cat /dev/null > /etc/resolv.conf.dhclient6 ) exit_status=$? if [ $exit_status -ne 0 ] ; then $LOGGER "Unable to create /etc/resolv.conf.dhclient6: Error $exit_status" else if [ "x${new_dhcp6_domain_search}" != x ] ; then ( echo search ${new_dhcp6_domain_search} >> /etc/resolv.conf.dhclient6 ) exit_status=$? fi for nameserver in ${new_dhcp6_name_servers} ; do if [ $exit_status -ne 0 ] ; then break fi # If the nameserver has a link-local address # add a (interface name) to it. case $nameserver in fe80:*) zone_id="%$interface";; FE80:*) zone_id="%$interface";; *) zone_id='';; esac ( echo nameserver ${nameserver}$zone_id >> /etc/resolv.conf.dhclient6 ) exit_status=$? done if [ $exit_status -eq 0 ] ; then ( mv /etc/resolv.conf.dhclient6 /etc/resolv.conf ) exit_status=$? fi if [ $exit_status -ne 0 ] ; then $LOGGER "Error while writing new /etc/resolv.conf." fi fi fi } # Must be used on exit. Invokes the local dhcp client exit hooks, if any. exit_with_hooks() { exit_status=$1 if [ -f /etc/dhclient-exit-hooks ]; then . /etc/dhclient-exit-hooks fi # probably should do something with exit status of the local script exit $exit_status } # Invoke the local dhcp client enter hooks, if they exist. if [ -f /etc/dhclient-enter-hooks ]; then exit_status=0 . /etc/dhclient-enter-hooks # allow the local script to abort processing of this state # local script must set exit_status variable to nonzero. if [ $exit_status -ne 0 ]; then exit $exit_status fi fi if [ x$new_network_number != x ]; then $LOGGER New Network Number: $new_network_number fi if [ x$new_broadcast_address != x ]; then $LOGGER New Broadcast Address: $new_broadcast_address new_broadcast_arg="broadcast $new_broadcast_address" fi if [ x$old_broadcast_address != x ]; then old_broadcast_arg="broadcast $old_broadcast_address" fi if [ x$new_subnet_mask != x ]; then new_netmask_arg="netmask $new_subnet_mask" fi if [ x$old_subnet_mask != x ]; then old_netmask_arg="netmask $old_subnet_mask" fi if [ x$alias_subnet_mask != x ]; then alias_subnet_arg="netmask $alias_subnet_mask" fi if [ x$new_interface_mtu != x ]; then mtu_arg="mtu $new_interface_mtu" fi if [ x$IF_METRIC != x ]; then metric_arg="metric $IF_METRIC" fi if [ x$reason = xMEDIUM ]; then eval "ifconfig $interface $medium" eval "ifconfig $interface inet -alias 0.0.0.0 $medium" >/dev/null 2>&1 sleep 1 exit_with_hooks 0 fi ### ### DHCPv4 Handlers ### if [ x$reason = xPREINIT ]; then if [ x$alias_ip_address != x ]; then ifconfig $interface inet -alias $alias_ip_address > /dev/null 2>&1 route delete $alias_ip_address 127.0.0.1 > /dev/null 2>&1 fi ifconfig $interface inet 0.0.0.0 netmask 0.0.0.0 \ broadcast 255.255.255.255 up exit_with_hooks 0 fi if [ x$reason = xARPCHECK ] || [ x$reason = xARPSEND ]; then exit_with_hooks 0; fi if [ x$reason = xBOUND ] || [ x$reason = xRENEW ] || \ [ x$reason = xREBIND ] || [ x$reason = xREBOOT ]; then current_hostname=`/bin/hostname` if [ x$current_hostname = x ] || \ [ x$current_hostname = x$old_host_name ]; then if [ x$current_hostname = x ] || \ [ x$new_host_name != x$old_host_name ]; then $LOGGER "New Hostname: $new_host_name" hostname $new_host_name fi fi if [ x$old_ip_address != x ] && [ x$alias_ip_address != x ] && \ [ x$alias_ip_address != x$old_ip_address ]; then ifconfig $interface inet -alias $alias_ip_address > /dev/null 2>&1 route delete $alias_ip_address 127.0.0.1 > /dev/null 2>&1 fi if [ x$old_ip_address != x ] && [ x$old_ip_address != x$new_ip_address ] then eval "ifconfig $interface inet -alias $old_ip_address $medium" route delete $old_ip_address 127.1 >/dev/null 2>&1 for router in $old_routers; do route delete default $router >/dev/null 2>&1 done if [ -n "$old_static_routes" ]; then set -- $old_static_routes while [ $# -gt 1 ]; do route delete $1 $2 shift; shift done fi arp -n -a | sed -n -e 's/^.*(\(.*\)) at .*$/arp -d \1/p' |sh fi if [ x$old_ip_address = x ] || [ x$old_ip_address != x$new_ip_address ] || \ [ x$reason = xBOUND ] || [ x$reason = xREBOOT ]; then eval "ifconfig $interface inet $new_ip_address $new_netmask_arg \ $new_broadcast_arg $mtu_arg $metric_arg $medium" $LOGGER "New IP Address ($interface): $new_ip_address" $LOGGER "New Subnet Mask ($interface): $new_subnet_mask" $LOGGER "New Broadcast Address ($interface): $new_broadcast_address" if [ -n "$new_routers" ]; then $LOGGER "New Routers: $new_routers" fi route add $new_ip_address 127.1 >/dev/null 2>&1 for router in $new_routers; do # If the subnet is captive, eg the netmask is /32 but the default # gateway is (obviously) outside of this, then we need to produce a # host route to reach the gateway. if [ "x$new_subnet_mask" = "x255.255.255.255" ] ; then route add -host $router -interface $interface fi route add default $router >/dev/null 2>&1 done if [ -n "$new_static_routes" ]; then $LOGGER "New Static Routes: $new_static_routes" set -- $new_static_routes while [ $# -gt 1 ]; do route add $1 $2 shift; shift done fi else # we haven't changed the address, have we changed other options # that we wish to update? if [ x$new_routers != x ] && [ x$new_routers != x$old_routers ] ; then # if we've changed routers delete the old and add the new. $LOGGER "New Routers: $new_routers" for router in $old_routers; do route delete default $router >/dev/null 2>&1 done for router in $new_routers; do # If the subnet is captive, eg the netmask is /32 but the default # gateway is (obviously) outside of this, then we need to produce a # host route to reach the gateway. if [ "x$new_subnet_mask" = "x255.255.255.255" ] ; then route add -host $router -interface $interface fi route add default $router >/dev/null 2>&1 done fi fi if [ x$new_ip_address != x$alias_ip_address ] && [ x$alias_ip_address != x ]; then ifconfig $interface inet alias $alias_ip_address $alias_subnet_arg route add $alias_ip_address 127.0.0.1 fi make_resolv_conf exit_with_hooks 0 fi if [ x$reason = xEXPIRE ] || [ x$reason = xFAIL ] || [ x$reason = xRELEASE ] \ || [ x$reason = xSTOP ]; then if [ x$alias_ip_address != x ]; then ifconfig $interface inet -alias $alias_ip_address > /dev/null 2>&1 route delete $alias_ip_address 127.0.0.1 > /dev/null 2>&1 fi if [ x$old_ip_address != x ]; then eval "ifconfig $interface inet -alias $old_ip_address $medium" route delete $old_ip_address 127.1 >/dev/null 2>&1 for router in $old_routers; do route delete default $router >/dev/null 2>&1 done if [ -n "$old_static_routes" ]; then set -- $old_static_routes while [ $# -gt 1 ]; do route delete $1 $2 shift; shift done fi arp -n -a | sed -n -e 's/^.*(\(.*\)) at .*$/arp -d \1/p' \ |sh >/dev/null 2>&1 fi if [ x$alias_ip_address != x ]; then ifconfig $interface inet alias $alias_ip_address $alias_subnet_arg route add $alias_ip_address 127.0.0.1 fi exit_with_hooks 0 fi if [ x$reason = xTIMEOUT ]; then if [ x$alias_ip_address != x ]; then ifconfig $interface inet -alias $alias_ip_address > /dev/null 2>&1 route delete $alias_ip_address 127.0.0.1 > /dev/null 2>&1 fi eval "ifconfig $interface inet $new_ip_address $new_netmask_arg \ $new_broadcast_arg $mtu_arg $metric_arg $medium" $LOGGER "New IP Address ($interface): $new_ip_address" $LOGGER "New Subnet Mask ($interface): $new_subnet_mask" $LOGGER "New Broadcast Address ($interface): $new_broadcast_address" sleep 1 if [ -n "$new_routers" ]; then $LOGGER "New Routers: $new_routers" set -- $new_routers if ping -q -c 1 $1; then if [ x$new_ip_address != x$alias_ip_address ] && \ [ x$alias_ip_address != x ]; then ifconfig $interface inet alias $alias_ip_address $alias_subnet_arg route add $alias_ip_address 127.0.0.1 fi route add $new_ip_address 127.1 >/dev/null 2>&1 for router in $new_routers; do if [ "x$new_subnet_mask" = "x255.255.255.255" ] ; then route add -host $router -interface $interface fi route add default $router >/dev/null 2>&1 done set -- $new_static_routes while [ $# -gt 1 ]; do route add $1 $2 shift; shift done make_resolv_conf exit_with_hooks 0 fi fi eval "ifconfig $interface inet -alias $new_ip_address $medium" for router in $old_routers; do route delete default $router >/dev/null 2>&1 done if [ -n "$old_static_routes" ]; then set -- $old_static_routes while [ $# -gt 1 ]; do route delete $1 $2 shift; shift done fi arp -n -a | sed -n -e 's/^.*(\(.*\)) at .*$/arp -d \1/p' \ |sh >/dev/null 2>&1 exit_with_hooks 1 fi ### ### DHCPv6 Handlers ### if [ ${reason} = PREINIT6 ] ; then # Ensure interface is up. ifconfig ${interface} up # XXX: Remove any stale addresses from aborted clients. exit_with_hooks 0 fi if [ x${old_ip6_prefix} != x ] || [ x${new_ip6_prefix} != x ] ; then echo Prefix ${reason} old=${old_ip6_prefix} new=${new_ip6_prefix} exit_with_hooks 0 fi if [ ${reason} = BOUND6 ] ; then if [ x${new_ip6_address} = x ] || [ x${new_ip6_prefixlen} = x ] ; then exit_with_hooks 2; fi ifconfig ${interface} inet6 ${new_ip6_address}/${new_ip6_prefixlen} alias # Check for nameserver options. make_resolv_conf exit_with_hooks 0 fi if [ ${reason} = RENEW6 ] || [ ${reason} = REBIND6 ] ; then # Make sure nothing has moved around on us. # Nameservers/domains/etc. if [ "x${new_dhcp6_name_servers}" != "x${old_dhcp6_name_servers}" ] || [ "x${new_dhcp6_domain_search}" != "x${old_dhcp6_domain_search}" ] ; then make_resolv_conf fi exit_with_hooks 0 fi if [ ${reason} = DEPREF6 ] ; then if [ x${new_ip6_address} = x ] ; then exit_with_hooks 2; fi ifconfig ${interface} inet6 ${new_ip6_address} deprecated exit_with_hooks 0 fi if [ ${reason} = EXPIRE6 -o ${reason} = RELEASE6 -o ${reason} = STOP6 ] ; then if [ x${old_ip6_address} = x ] || [ x${old_ip6_prefixlen} = x ] ; then exit_with_hooks 2; fi ifconfig ${interface} inet6 ${old_ip6_address}/${old_ip6_prefixlen} -alias exit_with_hooks 0 fi exit_with_hooks 0 dhcp-4.2.4/client/scripts/linux000755 000765 000024 00000022622 11565022662 016432 0ustar00sarstaff000000 000000 #!/bin/bash # dhclient-script for Linux. Dan Halbert, March, 1997. # Updated for Linux 2.[12] by Brian J. Murrell, January 1999. # No guarantees about this. I'm a novice at the details of Linux # networking. # Notes: # 0. This script is based on the netbsd script supplied with dhcp-970306. # 1. ifconfig down apparently deletes all relevant routes and flushes # the arp cache, so this doesn't need to be done explicitly. # 2. The alias address handling here has not been tested AT ALL. # I'm just going by the doc of modern Linux ip aliasing, which uses # notations like eth0:0, eth0:1, for each alias. # 3. I have to calculate the network address, and calculate the broadcast # address if it is not supplied. This might be much more easily done # by the dhclient C code, and passed on. # 4. TIMEOUT not tested. ping has a flag I don't know, and I'm suspicious # of the $1 in its args. # 'ip' just looks too weird. /sbin/ip looks less weird. ip=/sbin/ip make_resolv_conf() { if [ x"$new_domain_name_servers" != x ]; then cat /dev/null > /etc/resolv.conf.dhclient chmod 644 /etc/resolv.conf.dhclient if [ x"$new_domain_search" != x ]; then echo search $new_domain_search >> /etc/resolv.conf.dhclient elif [ x"$new_domain_name" != x ]; then # Note that the DHCP 'Domain Name Option' is really just a domain # name, and that this practice of using the domain name option as # a search path is both nonstandard and deprecated. echo search $new_domain_name >> /etc/resolv.conf.dhclient fi for nameserver in $new_domain_name_servers; do echo nameserver $nameserver >>/etc/resolv.conf.dhclient done mv /etc/resolv.conf.dhclient /etc/resolv.conf elif [ "x${new_dhcp6_name_servers}" != x ] ; then cat /dev/null > /etc/resolv.conf.dhclient6 chmod 644 /etc/resolv.conf.dhclient6 if [ "x${new_dhcp6_domain_search}" != x ] ; then echo search ${new_dhcp6_domain_search} >> /etc/resolv.conf.dhclient6 fi shopt -s nocasematch for nameserver in ${new_dhcp6_name_servers} ; do # If the nameserver has a link-local address # add a (interface name) to it. if [[ "$nameserver" =~ ^fe80:: ]] then zone_id="%$interface" else zone_id= fi echo nameserver ${nameserver}$zone_id >> /etc/resolv.conf.dhclient6 done shopt -u nocasematch mv /etc/resolv.conf.dhclient6 /etc/resolv.conf fi } # Must be used on exit. Invokes the local dhcp client exit hooks, if any. exit_with_hooks() { exit_status=$1 if [ -f /etc/dhclient-exit-hooks ]; then . /etc/dhclient-exit-hooks fi # probably should do something with exit status of the local script exit $exit_status } # Invoke the local dhcp client enter hooks, if they exist. if [ -f /etc/dhclient-enter-hooks ]; then exit_status=0 . /etc/dhclient-enter-hooks # allow the local script to abort processing of this state # local script must set exit_status variable to nonzero. if [ $exit_status -ne 0 ]; then exit $exit_status fi fi ### ### DHCPv4 Handlers ### if [ x$new_broadcast_address != x ]; then new_broadcast_arg="broadcast $new_broadcast_address" fi if [ x$old_broadcast_address != x ]; then old_broadcast_arg="broadcast $old_broadcast_address" fi if [ x$new_subnet_mask != x ]; then new_subnet_arg="netmask $new_subnet_mask" fi if [ x$old_subnet_mask != x ]; then old_subnet_arg="netmask $old_subnet_mask" fi if [ x$alias_subnet_mask != x ]; then alias_subnet_arg="netmask $alias_subnet_mask" fi if [ x$new_interface_mtu != x ]; then mtu_arg="mtu $new_interface_mtu" fi if [ x$IF_METRIC != x ]; then metric_arg="metric $IF_METRIC" fi if [ x$reason = xMEDIUM ]; then # Linux doesn't do mediums (ok, ok, media). exit_with_hooks 0 fi if [ x$reason = xPREINIT ]; then if [ x$alias_ip_address != x ]; then # Bring down alias interface. Its routes will disappear too. ifconfig $interface:0- inet 0 fi ifconfig $interface 0 up # We need to give the kernel some time to get the interface up. sleep 1 exit_with_hooks 0 fi if [ x$reason = xARPCHECK ] || [ x$reason = xARPSEND ]; then exit_with_hooks 0 fi if [ x$reason = xBOUND ] || [ x$reason = xRENEW ] || \ [ x$reason = xREBIND ] || [ x$reason = xREBOOT ]; then current_hostname=`hostname` if [ x$current_hostname = x ] || \ [ x$current_hostname = "x(none)" ] || \ [ x$current_hostname = xlocalhost ] || \ [ x$current_hostname = x$old_host_name ]; then if [ x$new_host_name != x$old_host_name ]; then hostname "$new_host_name" fi fi if [ x$old_ip_address != x ] && [ x$alias_ip_address != x ] && \ [ x$alias_ip_address != x$old_ip_address ]; then # Possible new alias. Remove old alias. ifconfig $interface:0- inet 0 fi if [ x$old_ip_address != x ] && [ x$old_ip_address != x$new_ip_address ]; then # IP address changed. Bringing down the interface will delete all routes, # and clear the ARP cache. ifconfig $interface inet 0 down fi if [ x$old_ip_address = x ] || [ x$old_ip_address != x$new_ip_address ] || \ [ x$reason = xBOUND ] || [ x$reason = xREBOOT ]; then ifconfig $interface inet $new_ip_address $new_subnet_arg \ $new_broadcast_arg $mtu_arg # Add a network route to the computed network address. for router in $new_routers; do if [ "x$new_subnet_mask" = "x255.255.255.255" ] ; then route add -host $router dev $interface fi route add default gw $router $metric_arg dev $interface done else # we haven't changed the address, have we changed other options # that we wish to update? if [ x$new_routers != x ] && [ x$new_routers != x$old_routers ] ; then # if we've changed routers delete the old and add the new. for router in $old_routers; do route del default gw $router done for router in $new_routers; do if [ "x$new_subnet_mask" = "x255.255.255.255" ] ; then route add -host $router dev $interface fi route add default gw $router $metric_arg dev $interface done fi fi if [ x$new_ip_address != x$alias_ip_address ] && [ x$alias_ip_address != x ]; then ifconfig $interface:0- inet 0 ifconfig $interface:0 inet $alias_ip_address $alias_subnet_arg route add -host $alias_ip_address $interface:0 fi make_resolv_conf exit_with_hooks 0 fi if [ x$reason = xEXPIRE ] || [ x$reason = xFAIL ] || [ x$reason = xRELEASE ] \ || [ x$reason = xSTOP ]; then if [ x$alias_ip_address != x ]; then # Turn off alias interface. ifconfig $interface:0- inet 0 fi if [ x$old_ip_address != x ]; then # Shut down interface, which will delete routes and clear arp cache. ifconfig $interface inet 0 down fi if [ x$alias_ip_address != x ]; then ifconfig $interface:0 inet $alias_ip_address $alias_subnet_arg route add -host $alias_ip_address $interface:0 fi exit_with_hooks 0 fi if [ x$reason = xTIMEOUT ]; then if [ x$alias_ip_address != x ]; then ifconfig $interface:0- inet 0 fi ifconfig $interface inet $new_ip_address $new_subnet_arg \ $new_broadcast_arg $mtu_arg set $new_routers if ping -q -c 1 $1; then if [ x$new_ip_address != x$alias_ip_address ] && \ [ x$alias_ip_address != x ]; then ifconfig $interface:0 inet $alias_ip_address $alias_subnet_arg route add -host $alias_ip_address dev $interface:0 fi for router in $new_routers; do if [ "x$new_subnet_mask" = "x255.255.255.255" ] ; then route add -host $router dev $interface fi route add default gw $router $metric_arg dev $interface done make_resolv_conf exit_with_hooks 0 fi ifconfig $interface inet 0 down exit_with_hooks 1 fi ### ### DHCPv6 Handlers ### if [ x$reason = xPREINIT6 ] ; then # Ensure interface is up. ${ip} link set ${interface} up # Remove any stale addresses from aborted clients. ${ip} -f inet6 addr flush dev ${interface} scope global permanent exit_with_hooks 0 fi if [ x${old_ip6_prefix} != x ] || [ x${new_ip6_prefix} != x ] ; then echo Prefix ${reason} old=${old_ip6_prefix} new=${new_ip6_prefix} exit_with_hooks 0 fi if [ x$reason = xBOUND6 ] ; then if [ x${new_ip6_address} = x ] || [ x${new_ip6_prefixlen} = x ] ; then exit_with_hooks 2; fi ${ip} -f inet6 addr add ${new_ip6_address}/${new_ip6_prefixlen} \ dev ${interface} scope global # Check for nameserver options. make_resolv_conf exit_with_hooks 0 fi if [ x$reason = xRENEW6 ] || [ x$reason = xREBIND6 ] ; then if [ x${new_ip6_address} = x ] || [ x${new_ip6_prefixlen} = x ] ; then exit_with_hooks 2; fi ${ip} -f inet6 addr add ${new_ip6_address}/${new_ip6_prefixlen} \ dev ${interface} scope global # Make sure nothing has moved around on us. # Nameservers/domains/etc. if [ "x${new_dhcp6_name_servers}" != "x${old_dhcp6_name_servers}" ] || [ "x${new_dhcp6_domain_search}" != "x${old_dhcp6_domain_search}" ] ; then make_resolv_conf fi exit_with_hooks 0 fi if [ x$reason = xDEPREF6 ] ; then if [ x${new_ip6_prefixlen} = x ] ; then exit_with_hooks 2; fi ${ip} -f inet6 addr change ${new_ip6_address}/${new_ip6_prefixlen} \ dev ${interface} scope global preferred_lft 0 exit_with_hooks 0 fi if [ x$reason = xEXPIRE6 -o x$reason = xRELEASE6 -o x$reason = xSTOP6 ] ; then if [ x${old_ip6_address} = x ] || [ x${old_ip6_prefixlen} = x ] ; then exit_with_hooks 2; fi ${ip} -f inet6 addr del ${old_ip6_address}/${old_ip6_prefixlen} \ dev ${interface} exit_with_hooks 0 fi exit_with_hooks 0 dhcp-4.2.4/client/scripts/macos000755 000765 000024 00000012753 11636143603 016377 0ustar00sarstaff000000 000000 #!/bin/sh # # $Id: macos,v 1.2.108.2 2011-09-20 17:04:03 sar Exp $ # # automous run of this script will commit the DNS setting # if [ -x /usr/bin/logger ]; then LOGGER="/usr/bin/logger -s -p user.notice -t dhclient" else LOGGER=echo fi to_commit="yes" make_resolv_conf() { to_commit="no" if [ "x${new_dhcp6_name_servers}" != x ]; then ( cat /dev/null > /var/run/resolv.conf.dhclient6 ) exit_status=$? if [ $exit_status -ne 0 ]; then $LOGGER "Unable to create /var/run/resolv.conf.dhclient6: Error $exit_status" else if [ "x${new_dhcp6_domain_search}" != x ]; then ( echo search ${new_dhcp6_domain_search} >> /var/run/resolv.conf.dhclient6 ) exit_status=$? fi for nameserver in ${new_dhcp6_name_servers} ; do if [ $exit_status -ne 0 ]; then break fi # If the nameserver has a link-local address # add a (interface name) to it. case $nameserver in fe80:*) zone_id="%$interface";; FE80:*) zone_id="%$interface";; *) zone_id='';; esac ( echo nameserver ${nameserver}$zone_id >> /etc/resolv.conf.dhclient6 ) exit_status=$? done if [ $exit_status -eq 0 ]; then to_commit="force" commit_resolv_conf fi fi fi } # Try to commit /var/run/resolv.conf.dhclient6 contents to # System Configuration framework's Dynamic Store. # Note this will be cleared by the next location change # or preempted by IPv4. # # The System Configuration agent "IPMonitor" gets the DNS configuration # from the IPv4 or IPv6 primary service in the Dynamic Store # (managed by configd). commit_resolv_conf() { if [ -f /var/run/resolv.conf.dhclient6 ]; then if [ -x /usr/sbin/scutil ]; then serviceID=`echo show State:/Network/Global/IPv6 | \ /usr/sbin/scutil | \ awk '/PrimaryService/ { print $3 }'` echo $serviceID if [ x$serviceID = x ]; then $LOGGER "Can't find the primary IPv6 service" else tmp=`mktemp SC_dhclient6.XXXXXXXXXX` echo list | /usr/sbin/scutil > /tmp/$tmp grep -q State:/Network/Service/$serviceID/DNS /tmp/$tmp grep_status=$? if [ $grep_status -eq 0 ]; then $LOGGER "DNS service already set in primary IPv6 service" rm /tmp/$tmp else res=/var/run/resolv.conf.dhclient6 cp /dev/null /tmp/$tmp grep -q '^nameserver' $res grep_status=$? if [ $grep_status -eq 0 ]; then echo d.add ServerAddresses '*' \ `awk 'BEGIN { n="" } \ /^nameserver/ { n=n " " $2 } \ END { print n}' < $res` >> /tmp/$tmp fi grep -q '^search' $res grep_status=$? if [ $grep_status -eq 0 ]; then echo d.add SearchDomains '*' \ `sed 's/^search//' < $res` >> /tmp/$tmp fi echo set State:/Network/Service/$serviceID/DNS >> /tmp/$tmp echo quit >> /tmp/$tmp cat /tmp/$tmp /usr/sbin/scutil < /tmp/$tmp rm /tmp/$tmp fi fi else $LOGGER "Can't find SystemConfiguration tools." fi else if [ $to_commit = force ]; then $LOGGER "Can't find /var/run/resolv.conf.dhclient6" fi fi to_commit="done" } # Must be used on exit. Invokes the local dhcp client exit hooks, if any. exit_with_hooks() { exit_status=$1 if [ -f /etc/dhclient-exit-hooks ]; then . /etc/dhclient-exit-hooks fi # probably should do something with exit status of the local script exit $exit_status } # Invoke the local dhcp client enter hooks, if they exist. if [ -f /etc/dhclient-enter-hooks ]; then exit_status=0 . /etc/dhclient-enter-hooks # allow the local script to abort processing of this state # local script must set exit_status variable to nonzero. if [ $exit_status -ne 0 ]; then exit $exit_status fi fi if [ x$reason = xMEDIUM ]; then eval "ifconfig $interface $medium" eval "ifconfig $interface inet -alias 0.0.0.0 $medium" >/dev/null 2>&1 sleep 1 exit_with_hooks 0 fi ### ### DHCPv6 Handlers ### if [ x$reason = xPREINIT6 ]; then # Ensure interface is up. ifconfig ${interface} up # XXX: Remove any stale addresses from aborted clients. exit_with_hooks 0 fi if [ x${old_ip6_prefix} != x ] || [ x${new_ip6_prefix} != x ]; then echo Prefix $reason old=${old_ip6_prefix} new=${new_ip6_prefix} exit_with_hooks 0 fi if [ x$reason = xBOUND6 ]; then if [ x${new_ip6_address} = x ] || [ x${new_ip6_prefixlen} = x ]; then exit_with_hooks 2; fi ifconfig ${interface} inet6 ${new_ip6_address}/${new_ip6_prefixlen} alias # Check for nameserver options. make_resolv_conf exit_with_hooks 0 fi if [ x$reason = xRENEW6 ] || [ x$reason = xREBIND6 ]; then # Make sure nothing has moved around on us. # Nameservers/domains/etc. if [ "x${new_dhcp6_name_servers}" != "x${old_dhcp6_name_servers}" ] || [ "x${new_dhcp6_domain_search}" != "x${old_dhcp6_domain_search}" ]; then make_resolv_conf fi exit_with_hooks 0 fi if [ x$reason = xDEPREF6 ]; then if [ x${new_ip6_address} = x ]; then exit_with_hooks 2; fi ifconfig ${interface} inet6 ${new_ip6_address} deprecated exit_with_hooks 0 fi if [ x$reason = xEXPIRE6 -o x$reason = xRELEASE6 -o x$reason = xSTOP6 ]; then if [ x${old_ip6_address} = x ] || [ x${old_ip6_prefixlen} = x ]; then exit_with_hooks 2; fi ifconfig ${interface} inet6 ${old_ip6_address}/${old_ip6_prefixlen} -alias exit_with_hooks 0 fi if [ $to_commit = yes ]; then commit_resolv_conf fi exit_with_hooks 0 dhcp-4.2.4/client/scripts/netbsd000755 000765 000024 00000023141 11565022662 016547 0ustar00sarstaff000000 000000 #!/bin/sh make_resolv_conf() { if [ "x$new_domain_name" != x ] && [ x"$new_domain_name_servers" != x ]; then cat /dev/null > /etc/resolv.conf.dhclient if [ "x$new_domain_search" != x ]; then echo search $new_domain_search >> /etc/resolv.conf.dhclient elif [ "x$new_domain_name" != x ]; then # Note that the DHCP 'Domain Name Option' is really just a domain # name, and that this practice of using the domain name option as # a search path is both nonstandard and deprecated. echo search $new_domain_name >> /etc/resolv.conf.dhclient fi for nameserver in $new_domain_name_servers; do echo nameserver $nameserver >>/etc/resolv.conf.dhclient done mv /etc/resolv.conf.dhclient /etc/resolv.conf elif [ "x${new_dhcp6_name_servers}" != x ] ; then cat /dev/null > /etc/resolv.conf.dhclient6 chmod 644 /etc/resolv.conf.dhclient6 if [ "x${new_dhcp6_domain_search}" != x ] ; then echo search ${new_dhcp6_domain_search} >> /etc/resolv.conf.dhclient6 fi for nameserver in ${new_dhcp6_name_servers} ; do # If the nameserver has a link-local address # add a (interface name) to it. case $nameserver in fe80:*) zone_id="%$interface";; FE80:*) zone_id="%$interface";; *) zone_id='';; esac echo nameserver ${nameserver}$zone_id >> /etc/resolv.conf.dhclient6 done mv /etc/resolv.conf.dhclient6 /etc/resolv.conf fi } # Must be used on exit. Invokes the local dhcp client exit hooks, if any. exit_with_hooks() { exit_status=$1 if [ -f /etc/dhclient-exit-hooks ]; then . /etc/dhclient-exit-hooks fi # probably should do something with exit status of the local script exit $exit_status } # Invoke the local dhcp client enter hooks, if they exist. if [ -f /etc/dhclient-enter-hooks ]; then exit_status=0 . /etc/dhclient-enter-hooks # allow the local script to abort processing of this state # local script must set exit_status variable to nonzero. if [ $exit_status -ne 0 ]; then exit $exit_status fi fi if [ x$new_network_number != x ]; then echo New Network Number: $new_network_number fi if [ x$new_broadcast_address != x ]; then echo New Broadcast Address: $new_broadcast_address new_broadcast_arg="broadcast $new_broadcast_address" fi if [ x$old_broadcast_address != x ]; then old_broadcast_arg="broadcast $old_broadcast_address" fi if [ x$new_subnet_mask != x ]; then new_netmask_arg="netmask $new_subnet_mask" fi if [ x$old_subnet_mask != x ]; then old_netmask_arg="netmask $old_subnet_mask" fi if [ x$alias_subnet_mask != x ]; then alias_subnet_arg="netmask $alias_subnet_mask" fi if [ x$new_interface_mtu != x ]; then mtu_arg="mtu $new_interface_mtu" fi if [ x$IF_METRIC != x ]; then metric_arg="metric $IF_METRIC" fi if [ x$reason = xMEDIUM ]; then eval "ifconfig $interface $medium" eval "ifconfig $interface inet -alias 0.0.0.0 $medium" >/dev/null 2>&1 sleep 1 exit_with_hooks 0 fi ### ### DHCPv4 Handlers ### if [ x$reason = xPREINIT ]; then if [ x$alias_ip_address != x ]; then ifconfig $interface inet -alias $alias_ip_address > /dev/null 2>&1 route delete $alias_ip_address 127.0.0.1 > /dev/null 2>&1 fi ifconfig $interface inet 0.0.0.0 netmask 0.0.0.0 \ broadcast 255.255.255.255 up exit_with_hooks 0 fi if [ x$reason = xARPCHECK ] || [ x$reason = xARPSEND ]; then exit_with_hooks 0 fi if [ x$reason = xBOUND ] || [ x$reason = xRENEW ] || \ [ x$reason = xREBIND ] || [ x$reason = xREBOOT ]; then current_hostname=`hostname` if [ x$current_hostname = x ] || \ [ x$current_hostname = x$old_host_name ]; then if [ x$current_hostname = x ] || \ [ x$new_host_name != x$old_host_name ]; then hostname $new_host_name fi fi if [ x$old_ip_address != x ] && [ x$alias_ip_address != x ] && \ [ x$alias_ip_address != x$old_ip_address ]; then ifconfig $interface inet -alias $alias_ip_address > /dev/null 2>&1 route delete $alias_ip_address 127.0.0.1 > /dev/null 2>&1 fi if [ x$old_ip_address != x ] && [ x$old_ip_address != x$new_ip_address ] then eval "ifconfig $interface inet -alias $old_ip_address $medium" route delete $old_ip_address 127.1 >/dev/null 2>&1 for router in $old_routers; do route delete default $router >/dev/null 2>&1 done if [ "$old_static_routes" != "" ]; then set $old_static_routes while [ $# -gt 1 ]; do route delete $1 $2 shift; shift done fi arp -n -a | sed -n -e 's/^.*(\(.*\)) at .*$/arp -n -d \1/p' |sh fi if [ x$old_ip_address = x ] || [ x$old_ip_address != x$new_ip_address ] || \ [ x$reason = xBOUND ] || [ x$reason = xREBOOT ]; then eval "ifconfig $interface inet $new_ip_address $new_netmask_arg \ $new_broadcast_arg $mtu_arg $metric_arg $medium" route add $new_ip_address 127.1 >/dev/null 2>&1 for router in $new_routers; do route add default $router >/dev/null 2>&1 done if [ "$new_static_routes" != "" ]; then set $new_static_routes while [ $# -gt 1 ]; do route add $1 $2 shift; shift done fi else # we haven't changed the address, have we changed other options # that we wish to update? if [ x$new_routers != x ] && [ x$new_routers != x$old_routers ] ; then # if we've changed routers delete the old and add the new. $LOGGER "New Routers: $new_routers" for router in $old_routers; do route delete default $router >/dev/null 2>&1 done for router in $new_routers; do route add default $router >/dev/null 2>&1 done fi fi if [ x$new_ip_address != x$alias_ip_address ] && [ x$alias_ip_address != x ]; then ifconfig $interface inet alias $alias_ip_address $alias_subnet_arg route add $alias_ip_address 127.0.0.1 fi make_resolv_conf exit_with_hooks 0 fi if [ x$reason = xEXPIRE ] || [ x$reason = xFAIL ] || [ x$reason = xRELEASE ] \ || [ x$reason = xSTOP ]; then if [ x$alias_ip_address != x ]; then ifconfig $interface inet -alias $alias_ip_address > /dev/null 2>&1 route delete $alias_ip_address 127.0.0.1 > /dev/null 2>&1 fi if [ x$old_ip_address != x ]; then eval "ifconfig $interface inet -alias $old_ip_address $medium" route delete $old_ip_address 127.1 >/dev/null 2>&1 for router in $old_routers; do route delete default $router >/dev/null 2>&1 done if [ "$old_static_routes" != "" ]; then set $old_static_routes while [ $# -gt 1 ]; do route delete $1 $2 shift; shift done fi arp -n -a | sed -n -e 's/^.*(\(.*\)) at .*$/arp -n -d \1/p' \ |sh >/dev/null 2>&1 fi if [ x$alias_ip_address != x ]; then ifconfig $interface inet alias $alias_ip_address $alias_subnet_arg route add $alias_ip_address 127.0.0.1 fi exit_with_hooks 0 fi if [ x$reason = xTIMEOUT ]; then if [ x$alias_ip_address != x ]; then ifconfig $interface inet -alias $alias_ip_address > /dev/null 2>&1 route delete $alias_ip_address 127.0.0.1 > /dev/null 2>&1 fi eval "ifconfig $interface inet $new_ip_address $new_netmask_arg \ $new_broadcast_arg $mtu_arg $metric_arg $medium" sleep 1 if [ "$new_routers" != "" ]; then set $new_routers if ping -q -c 1 -w 1 $1; then if [ x$new_ip_address != x$alias_ip_address ] && \ [ x$alias_ip_address != x ]; then ifconfig $interface inet alias $alias_ip_address $alias_subnet_arg route add $alias_ip_address 127.0.0.1 fi route add $new_ip_address 127.1 >/dev/null 2>&1 for router in $new_routers; do route add default $router >/dev/null 2>&1 done set $new_static_routes while [ $# -gt 1 ]; do route add $0 $1 shift; shift done make_resolv_conf exit_with_hooks 0 fi fi eval "ifconfig $interface inet -alias $new_ip_address $medium" for router in $old_routers; do route delete default $router >/dev/null 2>&1 done if [ "$old_static_routes" != "" ]; then set $old_static_routes while [ $# -gt 1 ]; do route delete $1 $2 shift; shift done fi arp -n -a | sed -n -e 's/^.*(\(.*\)) at .*$/arp -n -d \1/p' \ |sh >/dev/null 2>&1 exit_with_hooks 1 fi ### ### DHCPv6 Handlers ### if [ ${reason} = PREINIT6 ] ; then # Ensure interface is up. ifconfig ${interface} up # XXX: Remove any stale addresses from aborted clients. exit_with_hooks 0 fi if [ x${old_ip6_prefix} != x ] || [ x${new_ip6_prefix} != x ] ; then echo Prefix ${reason} old=${old_ip6_prefix} new=${new_ip6_prefix} exit_with_hooks 0 fi if [ ${reason} = BOUND6 ] ; then if [ x${new_ip6_address} = x ] || [ x${new_ip6_prefixlen} = x ] ; then exit_with_hooks 2; fi ifconfig ${interface} inet6 add ${new_ip6_address}/${new_ip6_prefixlen} # Check for nameserver options. make_resolv_conf exit_with_hooks 0 fi if [ ${reason} = RENEW6 ] || [ ${reason} = REBIND6 ] ; then # Make sure nothing has moved around on us. # Nameservers/domains/etc. if [ "x${new_dhcp6_name_servers}" != "x${old_dhcp6_name_servers}" ] || [ "x${new_dhcp6_domain_search}" != "x${old_dhcp6_domain_search}" ] ; then make_resolv_conf fi exit_with_hooks 0 fi if [ ${reason} = DEPREF6 ] ; then if [ x${new_ip6_prefixlen} = x ] ; then exit_with_hooks 2; fi # XXX: # There doesn't appear to be a way to update an addr to indicate # preference. exit_with_hooks 0 fi if [ ${reason} = EXPIRE6 -o ${reason} = RELEASE6 -o ${reason} = STOP6 ] ; then if [ x${old_ip6_address} = x ] || [ x${old_ip6_prefixlen} = x ] ; then exit_with_hooks 2; fi ifconfig ${interface} inet6 delete ${old_ip6_address}/${old_ip6_prefixlen} exit_with_hooks 0 fi exit_with_hooks 0 dhcp-4.2.4/client/scripts/nextstep000644 000765 000024 00000004042 11443774005 017136 0ustar00sarstaff000000 000000 #!/bin/sh # # simplified dhclient-script for NeXTSTEP/OPENSTEP # # removed a lot of the cruft from the netbsd version since NeXTSTEP doesn't # support aliases and lots of things were breaking for no good reason # # 14 Sep 1997, David W. Young # if [ x$reason = xPREINIT ]; then ifconfig $interface inet 0.0.0.0 netmask 0.0.0.0 up >/dev/null 2>&1 exit 0 fi if [ x$reason = xBOUND ] || [ x$reason = xRENEW ] || \ [ x$reason = xREBIND ] || [ x$reason = xREBOOT ]; then current_hostname=`hostname` if [ x$current_hostname = x ] || \ [ x$current_hostname = x$old_host_name ]; then if [ x$current_hostname = x ] || \ [ x$new_host_name != x$old_host_name ]; then hostname $new_host_name fi fi if [ x$old_ip_address != x ] && [ x$old_ip_address != x$new_ip_address ] then ifconfig $interface $new_ip_address netmask $new_subnet_mask \ >/dev/null 2>&1 route add $new_ip_address 127.1 0 >/dev/null 2>&1 for router in $new_routers ; do route add default $router 1 >/dev/null 2>&1 done fi if [ x"$new_domain_name_servers" != x ]; then cat /dev/null > /etc/resolv.conf.dhclient if [ "x$new_domain_search" != x ]; then echo search $new_domain_search >> /etc/resolv.conf.dhclient elif [ "x$new_domain_name" != x ]; then # Note that the DHCP 'Domain Name Option' is really just a domain # name, and that this practice of using the domain name option as # a search path is both nonstandard and deprecated. echo search $new_domain_name >> /etc/resolv.conf.dhclient fi for nameserver in $new_domain_name_servers; do echo nameserver $nameserver >>/etc/resolv.conf.dhclient done mv /etc/resolv.conf.dhclient /etc/resolv.conf fi exit 0 fi if [ x$reason = xEXPIRE ] || [ x$reason = xFAIL ] || [ x$reason = xRELEASE ] \ || [ x$reason = xSTOP ]; then if [ x$old_ip_address != x ]; then route delete $old_ip_address 127.1 >/dev/null 2>&1 for $router in $old_routers ; do route delete default $router >/dev/null 2>&1 done fi exit 0 fi dhcp-4.2.4/client/scripts/openbsd000644 000765 000024 00000022613 11565022662 016722 0ustar00sarstaff000000 000000 #!/bin/sh make_resolv_conf() { if [ x"$new_domain_name_servers" != x ]; then cat /dev/null > /etc/resolv.conf.dhclient if [ x"$new_domain_search" != x ]; then echo search $new_domain_search >> /etc/resolv.conf.dhclient elif [ x"$new_domain_name" != x ]; then # Note that the DHCP 'Domain Name Option' is really just a domain # name, and that this practice of using the domain name option as # a search path is both nonstandard and deprecated. echo search $new_domain_name >> /etc/resolv.conf.dhclient fi for nameserver in $new_domain_name_servers; do echo nameserver $nameserver >>/etc/resolv.conf.dhclient done mv /etc/resolv.conf.dhclient /etc/resolv.conf elif [ "x${new_dhcp6_name_servers}" != x ] ; then cat /dev/null > /etc/resolv.conf.dhclient6 chmod 644 /etc/resolv.conf.dhclient6 if [ "x${new_dhcp6_domain_search}" != x ] ; then echo search ${new_dhcp6_domain_search} >> /etc/resolv.conf.dhclient6 fi for nameserver in ${new_dhcp6_name_servers} ; do # If the nameserver has a link-local address # add a (interface name) to it. case $nameserver in fe80:*) zone_id="%$interface";; FE80:*) zone_id="%$interface";; *) zone_id='';; esac echo nameserver ${nameserver}$zone_id >> /etc/resolv.conf.dhclient6 done mv /etc/resolv.conf.dhclient6 /etc/resolv.conf fi } # Must be used on exit. Invokes the local dhcp client exit hooks, if any. exit_with_hooks() { exit_status=$1 if [ -f /etc/dhclient-exit-hooks ]; then . /etc/dhclient-exit-hooks fi # probably should do something with exit status of the local script exit $exit_status } # Invoke the local dhcp client enter hooks, if they exist. if [ -f /etc/dhclient-enter-hooks ]; then exit_status=0 . /etc/dhclient-enter-hooks # allow the local script to abort processing of this state # local script must set exit_status variable to nonzero. if [ $exit_status -ne 0 ]; then exit $exit_status fi fi if [ x$new_network_number != x ]; then echo New Network Number: $new_network_number fi if [ x$new_broadcast_address != x ]; then echo New Broadcast Address: $new_broadcast_address new_broadcast_arg="broadcast $new_broadcast_address" fi if [ x$old_broadcast_address != x ]; then old_broadcast_arg="broadcast $old_broadcast_address" fi if [ x$new_subnet_mask != x ]; then new_netmask_arg="netmask $new_subnet_mask" fi if [ x$old_subnet_mask != x ]; then old_netmask_arg="netmask $old_subnet_mask" fi if [ x$alias_subnet_mask != x ]; then alias_subnet_arg="netmask $alias_subnet_mask" fi if [ x$reason = xMEDIUM ]; then eval "ifconfig $interface $medium" eval "ifconfig $interface inet -alias 0.0.0.0 $medium" >/dev/null 2>&1 sleep 1 exit_with_hooks 0 fi ### ### DHCPv4 Handlers ### if [ x$reason = xPREINIT ]; then if [ x$alias_ip_address != x ]; then ifconfig $interface inet -alias $alias_ip_address > /dev/null 2>&1 route delete $alias_ip_address 127.0.0.1 > /dev/null 2>&1 fi ifconfig $interface inet 0.0.0.0 netmask 0.0.0.0 \ broadcast 255.255.255.255 up exit_with_hooks 0 fi if [ x$reason = xARPCHECK ] || [ x$reason = xARPSEND ]; then exit_with_hooks 0; fi if [ x$reason = xBOUND ] || [ x$reason = xRENEW ] || \ [ x$reason = xREBIND ] || [ x$reason = xREBOOT ]; then current_hostname=`hostname` if [ x$current_hostname = x ] || \ [ x$current_hostname = x$old_host_name ]; then if [ x$current_hostname = x ] || \ [ x$new_host_name != x$old_host_name ]; then hostname $new_host_name fi fi if [ x$old_ip_address != x ] && [ x$alias_ip_address != x ] && \ [ x$alias_ip_address != x$old_ip_address ]; then ifconfig $interface inet -alias $alias_ip_address > /dev/null 2>&1 route delete $alias_ip_address 127.0.0.1 > /dev/null 2>&1 fi if [ x$old_ip_address != x ] && [ x$old_ip_address != x$new_ip_address ] then eval "ifconfig $interface inet -alias $old_ip_address $medium" route delete $old_ip_address 127.1 >/dev/null 2>&1 for router in $old_routers; do route delete default $router >/dev/null 2>&1 done if [ "$old_static_routes" != "" ]; then set $old_static_routes while [ $# -gt 1 ]; do route delete $1 $2 shift; shift done fi arp -n -a | sed -n -e 's/^.*(\(.*\)) at .*$/arp -n -d \1/p' |sh fi if [ x$old_ip_address = x ] || [ x$old_ip_address != x$new_ip_address ] || \ [ x$reason = xBOUND ] || [ x$reason = xREBOOT ]; then eval "ifconfig $interface inet $new_ip_address $new_netmask_arg \ $new_broadcast_arg $medium" route add $new_ip_address 127.1 >/dev/null 2>&1 for router in $new_routers; do route add default $router >/dev/null 2>&1 done if [ "$new_static_routes" != "" ]; then set $new_static_routes while [ $# -gt 1 ]; do route add $1 $2 shift; shift done fi else # we haven't changed the address, have we changed other options # that we wish to update? if [ x$new_routers != x ] && [ x$new_routers != x$old_routers ] ; then # if we've changed routers delete the old and add the new. $LOGGER "New Routers: $new_routers" for router in $old_routers; do route delete default $router >/dev/null 2>&1 done for router in $new_routers; do route add default $router >/dev/null 2>&1 done fi fi if [ x$new_ip_address != x$alias_ip_address ] && [ x$alias_ip_address != x ]; then ifconfig $interface inet alias $alias_ip_address $alias_subnet_arg route add $alias_ip_address 127.0.0.1 fi make_resolv_conf exit_with_hooks 0 fi if [ x$reason = xEXPIRE ] || [ x$reason = xFAIL ] || [ x$reason = xRELEASE ] \ || [ x$reason = xSTOP ]; then if [ x$alias_ip_address != x ]; then ifconfig $interface inet -alias $alias_ip_address > /dev/null 2>&1 route delete $alias_ip_address 127.0.0.1 > /dev/null 2>&1 fi if [ x$old_ip_address != x ]; then eval "ifconfig $interface inet -alias $old_ip_address $medium" route delete $old_ip_address 127.1 >/dev/null 2>&1 for router in $old_routers; do route delete default $router >/dev/null 2>&1 done if [ "$old_static_routes" != "" ]; then set $old_static_routes while [ $# -gt 1 ]; do route delete $1 $2 shift; shift done fi arp -n -a | sed -n -e 's/^.*(\(.*\)) at .*$/arp -n -d \1/p' \ |sh >/dev/null 2>&1 fi if [ x$alias_ip_address != x ]; then ifconfig $interface inet alias $alias_ip_address $alias_subnet_arg route add $alias_ip_address 127.0.0.1 fi exit_with_hooks 0 fi if [ x$reason = xTIMEOUT ]; then if [ x$alias_ip_address != x ]; then ifconfig $interface inet -alias $alias_ip_address > /dev/null 2>&1 route delete $alias_ip_address 127.0.0.1 > /dev/null 2>&1 fi eval "ifconfig $interface inet $new_ip_address $new_netmask_arg \ $new_broadcast_arg $medium" sleep 1 if [ "$new_routers" != "" ]; then set $new_routers if ping -q -c 1 -w 1 $1; then if [ x$new_ip_address != x$alias_ip_address ] && \ [ x$alias_ip_address != x ]; then ifconfig $interface inet alias $alias_ip_address $alias_subnet_arg route add $alias_ip_address 127.0.0.1 fi route add $new_ip_address 127.1 >/dev/null 2>&1 for router in $new_routers; do route add default $router >/dev/null 2>&1 done set $new_static_routes while [ $# -gt 1 ]; do route add $0 $1 shift; shift done make_resolv_conf exit_with_hooks 0 fi fi eval "ifconfig $interface inet -alias $new_ip_address $medium" for router in $old_routers; do route delete default $router >/dev/null 2>&1 done if [ "$old_static_routes" != "" ]; then set $old_static_routes while [ $# -gt 1 ]; do route delete $1 $2 shift; shift done fi arp -n -a | sed -n -e 's/^.*(\(.*\)) at .*$/arp -n -d \1/p' \ |sh >/dev/null 2>&1 exit_with_hooks 1 fi ### ### DHCPv6 Handlers ### if [ ${reason} = PREINIT6 ] ; then # Ensure interface is up. ifconfig ${interface} up # XXX: Remove any stale addresses from aborted clients. exit_with_hooks 0 fi if [ x${old_ip6_prefix} != x ] || [ x${new_ip6_prefix} != x ] ; then echo Prefix ${reason} old=${old_ip6_prefix} new=${new_ip6_prefix} exit_with_hooks 0 fi if [ ${reason} = BOUND6 ] ; then if [ x${new_ip6_address} = x ] || [ x${new_ip6_prefixlen} = x ] ; then exit_with_hooks 2; fi ifconfig ${interface} inet6 add ${new_ip6_address}/${new_ip6_prefixlen} # Check for nameserver options. make_resolv_conf exit_with_hooks 0 fi if [ ${reason} = RENEW6 ] || [ ${reason} = REBIND6 ] ; then # Make sure nothing has moved around on us. # Nameservers/domains/etc. if [ "x${new_dhcp6_name_servers}" != "x${old_dhcp6_name_servers}" ] || [ "x${new_dhcp6_domain_search}" != "x${old_dhcp6_domain_search}" ] ; then make_resolv_conf fi exit_with_hooks 0 fi if [ ${reason} = DEPREF6 ] ; then if [ x${new_ip6_prefixlen} = x ] ; then exit_with_hooks 2; fi # XXX: # There doesn't appear to be a way to update an addr to indicate # preference. exit_with_hooks 0 fi if [ ${reason} = EXPIRE6 -o ${reason} = RELEASE6 -o ${reason} = STOP6 ] ; then if [ x${old_ip6_address} = x ] || [ x${old_ip6_prefixlen} = x ] ; then exit_with_hooks 2; fi ifconfig ${interface} inet6 delete ${old_ip6_address}/${old_ip6_prefixlen} exit_with_hooks 0 fi exit_with_hooks 0 dhcp-4.2.4/client/scripts/openwrt000755 000765 000024 00000020050 11565022662 016762 0ustar00sarstaff000000 000000 #!/bin/sh make_resolv_conf() { if [ x"$new_domain_name_servers" != x ]; then cat /dev/null > /etc/resolv.conf.dhclient chmod 644 /etc/resolv.conf.dhclient if [ x"$new_domain_search" != x ]; then echo search $new_domain_search >> /etc/resolv.conf.dhclient elif [ x"$new_domain_name" != x ]; then # Note that the DHCP 'Domain Name Option' is really just a domain # name, and that this practice of using the domain name option as # a search path is both nonstandard and deprecated. echo search $new_domain_name >> /etc/resolv.conf.dhclient fi for nameserver in $new_domain_name_servers; do echo nameserver $nameserver >>/etc/resolv.conf.dhclient done mv /etc/resolv.conf.dhclient /etc/resolv.conf elif [ "x${new_dhcp6_name_servers}" != x ] ; then cat /dev/null > /etc/resolv.conf.dhclient6 chmod 644 /etc/resolv.conf.dhclient6 if [ "x${new_dhcp6_domain_search}" != x ] ; then echo search ${new_dhcp6_domain_search} >> /etc/resolv.conf.dhclient6 fi for nameserver in ${new_dhcp6_name_servers} ; do # If the nameserver has a link-local address # add a (interface name) to it. case $nameserver in fe80:*) zone_id="%$interface";; FE80:*) zone_id="%$interface";; *) zone_id='';; esac echo nameserver ${nameserver}$zone_id >> /etc/resolv.conf.dhclient6 done mv /etc/resolv.conf.dhclient6 /etc/resolv.conf fi } # Must be used on exit. Invokes the local dhcp client exit hooks, if any. exit_with_hooks() { exit_status=$1 if [ -f /etc/dhclient-exit-hooks ]; then . /etc/dhclient-exit-hooks fi # probably should do something with exit status of the local script exit $exit_status } # Invoke the local dhcp client enter hooks, if they exist. if [ -f /etc/dhclient-enter-hooks ]; then exit_status=0 . /etc/dhclient-enter-hooks # allow the local script to abort processing of this state # local script must set exit_status variable to nonzero. if [ $exit_status -ne 0 ]; then exit $exit_status fi fi ### ### DHCPv4 Handlers ### if [ x$new_broadcast_address != x ]; then new_broadcast_arg="broadcast $new_broadcast_address" fi if [ x$new_subnet_mask != x ]; then new_subnet_arg="netmask $new_subnet_mask" fi if [ x$alias_subnet_mask != x ]; then alias_subnet_arg="netmask $alias_subnet_mask" fi if [ x$new_interface_mtu != x ]; then mtu_arg="mtu $new_interface_mtu" fi if [ x$IF_METRIC != x ]; then metric_arg="metric $IF_METRIC" fi if [ x$reason = xMEDIUM ]; then # Linux doesn't do mediums (ok, ok, media). exit_with_hooks 0 fi if [ x$reason = xPREINIT ]; then if [ x$alias_ip_address != x ]; then # Bring down alias interface. Its routes will disappear too. ifconfig $interface:0- 0.0.0.0 fi ifconfig $interface 0.0.0.0 up # We need to give the kernel some time to get the interface up. sleep 1 exit_with_hooks 0 fi if [ x$reason = xARPCHECK ] || [ x$reason = xARPSEND ]; then exit_with_hooks 0 fi if [ x$reason = xBOUND ] || [ x$reason = xRENEW ] || \ [ x$reason = xREBIND ] || [ x$reason = xREBOOT ]; then current_hostname=`hostname` if [ x$current_hostname = x ] || \ [ x$current_hostname = x$old_host_name ]; then if [ x$current_hostname = x ] || \ [ x$new_host_name != x$old_host_name ]; then hostname $new_host_name fi fi if [ x$old_ip_address != x ] && [ x$alias_ip_address != x ] && \ [ x$alias_ip_address != x$old_ip_address ]; then # Possible new alias. Remove old alias. ifconfig $interface:0- 0.0.0.0 fi if [ x$old_ip_address != x ] && [ x$old_ip_address != x$new_ip_address ]; then # IP address changed. Bringing down the interface will delete all routes, # and clear the ARP cache. ifconfig $interface 0.0.0.0 down fi if [ x$old_ip_address = x ] || [ x$old_ip_address != x$new_ip_address ] || \ [ x$reason = xBOUND ] || [ x$reason = xREBOOT ]; then ifconfig $interface $new_ip_address $new_subnet_arg \ $new_broadcast_arg $mtu_arg $metric_arg for router in $new_routers; do if [ "x$new_subnet_mask" = "x255.255.255.255" ] ; then route add -host $router dev $interface fi route add default gw $router done else # we haven't changed the address, have we changed other options # that we wish to update? if [ x$new_routers != x ] && [ x$new_routers != x$old_routers ] ; then # if we've changed routers delete the old and add the new. $LOGGER "New Routers: $new_routers" for router in $old_routers; do route delete default $router done for router in $new_routers; do if [ "x$new_subnet_mask" = "x255.255.255.255" ] ; then route add -host $router dev $interface fi route add default gw $router done fi fi if [ x$new_ip_address != x$alias_ip_address ] && [ x$alias_ip_address != x ]; then ifconfig $interface:0- 0.0.0.0 ifconfig $interface:0 $alias_ip_address $alias_subnet_arg route add -host $alias_ip_address $interface:0 fi make_resolv_conf exit_with_hooks 0 fi if [ x$reason = xEXPIRE ] || [ x$reason = xFAIL ] || [ x$reason = xRELEASE ] \ || [ x$reason = xSTOP ]; then if [ x$alias_ip_address != x ]; then # Turn off alias interface. ifconfig $interface:0- 0.0.0.0 fi if [ x$old_ip_address != x ]; then # Shut down interface, which will delete routes and clear arp cache. ifconfig $interface 0.0.0.0 down fi if [ x$alias_ip_address != x ]; then ifconfig $interface:0 $alias_ip_address $alias_subnet_arg route add -host $alias_ip_address $interface:0 fi exit_with_hooks 0 fi if [ x$reason = xTIMEOUT ]; then if [ x$alias_ip_address != x ]; then ifconfig $interface:0- 0.0.0.0 fi ifconfig $interface $new_ip_address $new_subnet_arg \ $new_broadcast_arg $mtu_arg $metric_arg set $new_routers if ping -q -c 1 $1; then if [ x$new_ip_address != x$alias_ip_address ] && \ [ x$alias_ip_address != x ]; then ifconfig $interface:0 $alias_ip_address $alias_subnet_arg route add -host $alias_ip_address dev $interface:0 fi for router in $new_routers; do if [ "x$new_subnet_mask" = "x255.255.255.255" ] ; then route add -host $router dev $interface fi route add default gw $router done make_resolv_conf exit_with_hooks 0 fi ifconfig $interface 0.0.0.0 down exit_with_hooks 1 fi ### ### DHCPv6 Handlers ### if [ x$reason = xPREINIT6 ]; then # Ensure interface is up. ifconfig ${interface} up # Remove any stale addresses from aborted clients. ip -f inet6 addr flush dev ${interface} scope global exit_with_hooks 0 fi if [ x${old_ip6_prefix} != x ] || [ x${new_ip6_prefix} != x ] ; then echo Prefix ${reason} old=${old_ip6_prefix} new=${new_ip6_prefix} exit_with_hooks 0 fi if [ x$reason = xBOUND6 ]; then if [ x${new_ip6_address} = x ] || [ x${new_ip6_prefixlen} = x ] ; then exit_with_hooks 2; fi ifconfig ${interface} inet6 ${new_ip6_address}/${new_ip6_prefixlen} alias # Check for nameserver options. make_resolv_conf exit_with_hooks 0 fi if [ x$reason = xRENEW6 ] || [ x$reason = xREBIND6 ]; then if [ x${new_ip6_address} = x ] || [ x${new_ip6_prefixlen} = x ] ; then exit_with_hooks 2; fi ifconfig ${interface} inet6 ${new_ip6_address}/${new_ip6_prefixlen} alias # Make sure nothing has moved around on us. # Nameservers/domains/etc. if [ "x${new_dhcp6_name_servers}" != "x${old_dhcp6_name_servers}" ] || [ "x${new_dhcp6_domain_search}" != "x${old_dhcp6_domain_search}" ] ; then make_resolv_conf fi exit_with_hooks 0 fi if [ x$reason = xDEPREF6 ]; then if [ x${new_ip6_address} = x ] ; then exit_with_hooks 2; fi ifconfig ${interface} inet6 ${new_ip6_address} deprecated exit_with_hooks 0 fi if [ x$reason = xEXPIRE6 -o x$reason = xRELEASE6 -o x$reason = xSTOP6 ]; then if [ x${old_ip6_address} = x ] || [ x${old_ip6_prefixlen} = x ] ; then exit_with_hooks 2; fi ifconfig ${interface} inet6 ${old_ip6_address}/${old_ip6_prefixlen} -alias exit_with_hooks 0 fi exit_with_hooks 0 dhcp-4.2.4/client/scripts/solaris000755 000765 000024 00000014751 11565022663 016754 0ustar00sarstaff000000 000000 #!/bin/sh make_resolv_conf() { if [ x"$new_domain_name_servers" != x ]; then cat /dev/null > /etc/resolv.conf.dhclient if [ x"$new_domain_search" != x ]; then echo search $new_domain_search >> /etc/resolv.conf.dhclient elif [ x"$new_domain_name" != x ]; then # Note that the DHCP 'Domain Name Option' is really just a domain # name, and that this practice of using the domain name option as # a search path is both nonstandard and deprecated. echo search $new_domain_name >> /etc/resolv.conf.dhclient fi for nameserver in $new_domain_name_servers; do echo nameserver $nameserver >>/etc/resolv.conf.dhclient done mv /etc/resolv.conf.dhclient /etc/resolv.conf fi } # Must be used on exit. Invokes the local dhcp client exit hooks, if any. exit_with_hooks() { exit_status=$1 if [ -f /etc/dhclient-exit-hooks ]; then . /etc/dhclient-exit-hooks fi # probably should do something with exit status of the local script exit $exit_status } # Invoke the local dhcp client enter hooks, if they exist. if [ -f /etc/dhclient-enter-hooks ]; then exit_status=0 . /etc/dhclient-enter-hooks # allow the local script to abort processing of this state # local script must set exit_status variable to nonzero. if [ $exit_status -ne 0 ]; then exit $exit_status fi fi if [ x$new_broadcast_address != x ]; then new_broadcast_arg="broadcast $new_broadcast_address" fi if [ x$old_broadcast_address != x ]; then old_broadcast_arg="broadcast $old_broadcast_address" fi if [ x$new_subnet_mask != x ]; then new_netmask_arg="netmask $new_subnet_mask" fi if [ x$old_subnet_mask != x ]; then old_netmask_arg="netmask $old_subnet_mask" fi if [ x$alias_subnet_mask != x ]; then alias_subnet_arg="netmask $alias_subnet_mask" fi if [ x$new_interface_mtu != x ]; then mtu_arg="mtu $new_interface_mtu" fi if [ x$IF_METRIC != x ]; then metric_arg="metric $IF_METRIC" fi ifconfig=/sbin/ifconfig release=`uname -r` release=`expr $release : '\(.*\)\..*'` relmajor=`echo $release |sed -e 's/^\([^\.]*\)\..*$/\1/'` relminor=`echo $release |sed -e 's/^.*\.\([^\.]*\)$/\1/'` if [ x$reason = xMEDIUM ]; then eval "$ifconfig $interface $medium" $ifconfig $interface sleep 1 exit_with_hooks 0 fi if [ x$reason = xPREINIT ]; then if [ x$alias_ip_address != x ]; then $ifconfig ${interface}:1 0 down > /dev/null 2>&1 route delete $alias_ip_address 127.0.0.1 > /dev/null 2>&1 fi if [ $relmajor -gt 5 ] || ( [ $relmajor -eq 5 ] && [ $relminor -ge 5 ] ) then # Turn the interface on $ifconfig $interface plumb $ifconfig $interface up else $ifconfig $interface inet 0.0.0.0 netmask 0.0.0.0 \ broadcast 255.255.255.255 up fi exit_with_hooks 0 fi if [ x$reason = xARPCHECK ] || [ x$reason = xARPSEND ]; then exit_with_hooks 0; fi if [ x$reason = xBOUND ] || [ x$reason = xRENEW ] || \ [ x$reason = xREBIND ] || [ x$reason = xREBOOT ]; then current_hostname=`hostname` if [ x$current_hostname = x ] || \ [ x$current_hostname = x$old_host_name ]; then if [ x$current_hostname = x ] || \ [ x$new_host_name != x$old_host_name ]; then hostname $new_host_name fi fi if [ x$old_ip_address != x ] && [ x$alias_ip_address != x ] && \ [ x$alias_ip_address != x$old_ip_address ]; then $ifconfig ${interface}:1 inet 0 down > /dev/null 2>&1 route delete $alias_ip_address 127.0.0.1 > /dev/null 2>&1 fi if [ x$old_ip_address != x ] && [ x$old_ip_address != x$new_ip_address ]; then $ifconfig ${interface} inet 0 down route delete $old_ip_address 127.1 >/dev/null 2>&1 for router in $old_routers; do route delete default $router >/dev/null 2>&1 done fi if [ x$old_ip_address = x ] || [ x$old_ip_address != x$new_ip_address ] || \ [ x$reason = xBOUND ] || [ x$reason = xREBOOT ]; then eval "$ifconfig $interface inet $new_ip_address $new_netmask_arg \ $new_broadcast_arg $mtu_arg $metric_arg $medium" route add $new_ip_address 127.1 1 >/dev/null 2>&1 for router in $new_routers; do route add default $router 1 >/dev/null 2>&1 done else # we haven't changed the address, have we changed other options # that we wish to update? if [ x$new_routers != x ] && [ x$new_routers != x$old_routers ] ; then # if we've changed routers delete the old and add the new. $LOGGER "New Routers: $new_routers" for router in $old_routers; do route delete default $router >/dev/null 2>&1 done for router in $new_routers; do route add default $router 1 >/dev/null 2>&1 done fi fi if [ x$new_ip_address != x$alias_ip_address ] && [ x$alias_ip_address != x ]; then $ifconfig ${interface}:1 inet $alias_ip_address $alias_subnet_arg route add $alias_ip_address 127.0.0.1 1 fi make_resolv_conf exit_with_hooks 0 fi if [ x$reason = xEXPIRE ] || [ x$reason = xFAIL ] || [ x$reason = xRELEASE ] \ || [ x$reason = xSTOP ]; then if [ x$alias_ip_address != x ]; then $ifconfig ${interface}:1 0 down > /dev/null 2>&1 route delete $alias_ip_address 127.0.0.1 > /dev/null 2>&1 fi if [ x$old_ip_address != x ]; then $ifconfig $interface inet 0 down route delete $old_ip_address 127.1 >/dev/null 2>&1 for router in $old_routers; do route delete default $router >/dev/null 2>&1 done fi if [ x$alias_ip_address != x ]; then $ifconfig ${interface}:1 inet $alias_ip_address $alias_subnet_arg route add $alias_ip_address 127.0.0.1 1 fi exit_with_hooks 0 fi if [ x$reason = xTIMEOUT ]; then if [ x$alias_ip_address != x ]; then $ifconfig ${interface}:1 0 down > /dev/null 2>&1 route delete $alias_ip_address 127.0.0.1 > /dev/null 2>&1 fi eval "$ifconfig $interface inet $new_ip_address $new_netmask_arg \ $new_broadcast_arg $mtu_arg $metric_arg $medium" sleep 1 set $new_routers if ping -s -n -I 1 $1 64 1; then if [ x$new_ip_address != x$alias_ip_address ] && \ [ x$alias_ip_address != x ]; then $ifconfig ${interface}:1 inet $alias_ip_address $alias_subnet_arg route add $alias_ip_address 127.0.0.1 1 fi route add $new_ip_address 127.1 1 >/dev/null 2>&1 for router in $new_routers; do route add default $router 1 >/dev/null 2>&1 done make_resolv_conf exit_with_hooks 0 fi $ifconfig $interface inet 0 down for router in $old_routers; do route delete default $router >/dev/null 2>&1 done exit_with_hooks 1 fi exit_with_hooks 0 dhcp-4.2.4/bind/bind.tar.gz000644 000765 000024 00032533302 11757513767 015404 0ustar00sarstaff000000 000000 O[isHҞ֯׽1SޙX,a7B2 _6\O>{cgޘ&%OeUUǭ|3_)G]bQ]Oj]TjRQb\-~ ?+bʁ>tA3l5ZV;8?}<_*օ˵FZDW+x GH;Ob'bz5MB?fg11Q̦Qc7K+Ovj8rJ$3>u |$Luv!v$f$V„A܍'waɄq6Z1}DB\Hc`C$k=$?]!iի0d'ejtLޙy#2Q {JG]ɀ]"in|5f*Ant\;&m@:(ڹ T}U-znSEU;~S #҈#򵬙ĸ@өLTE:UerӁ}Hm-!Ш j8Ќtt,ԫۛ 4zЛ2ܟ.©=C<0dF2% R_Tz~M]B&4\Ue-#ӡh+)(]TeѕI^^ o}B6hFJZEUT.K\96N Lƣ`AEHz,;@:#Be7%h``#ϵʩ͸hA;S@nL쀥cpKׇPy΋?^kb33m3ΰWQWO%Dt1DIg#?I>TeepB|lpx>0 x.Bd3,u_aB!`9 Z~a໋q<: f)h ! <<P#68Zۃ{r!wkUOf}Bl#xͱh -8=Q-;\=-}:eiRW~ c$}-f@:Զ9ҳkJ S@̘л&C*gb t)NRl#e|!5Θ'VLp| MzfE%|C`qK0l]u)0Ԓޮց91nWd6j%3ZVgclDXC׊LʠF1dLD?oCi0itq&|{0ܽҟW1Ԧt:TtXb g*D3E})Pk쯀b NcL GJB!E(Lb,0xD` @!g|i ܸLip:;rHT~A9 ҋq@y 2r=o /V~BcLSeP' 7ͰSc@1ˤ+3C,܇t{4<"l w9.p?/ v$aQ&yL~ps“=̃̀38)~J;O0Y+g'BoTYidmO(MBI3LG8 %bώ|x?i!ΰ1#kg%1d(oы 4A qʗ7Ƌɨ :I8ԩӐ>'m\7x>0e ou"1wcBm`0V 7 0= pP4o ܋T|hx5bN3]ôŔK7__^A@\rߟrEYD HA߷}/w-bˍoT)JQՆ2c\\Kdc;#L׷-rP3'PECe%n 'FCjr1<@=xE-ZqԿd[_ſr[S R.J"IA&bgMދE)ܵQz1(m69%Qߚ<l,׋K4"!8pȩuH+O- 1ca{K{[ E]? b$~<Pw26@(h"vbS xz.ke7˻xJm\&x1lKQD+ӫ00/bsܔ-,כws2pfc ~WbsV [i⥔7 Θ2b(Ub+ ;Vh iHDcQDYD̚ )i(B)`XG$b1ٵ(bl#v].m x^AnMvL$C)ce!L_3coSL 8XUeBSO(_ 'ōzG4&u=\`2uA\h<@maJ:bx&#=f ~&YQm PkSC` 61¢xbN(I+p Xq |Nbf:F|.7>z}B %/+ YHv}@'P"6j"PXUl!0|ng+0WZA wBjdT_tB-,7Kl< 7^! M%7_.:mtrngg'W*eS}wiSko/tOHKSS|Q망ͻH;bQ1Y˹/?^ju{2ڬmT)WV,,fb;y=@һzyTSIW-/%֘Nﯭ\a>/LEa6wX] vw~U~{VҝC{ǠBUQ?=\͢meo=j]iEǒɻaX~~غ)X\Njd7^sl@hgWөjMG};(?sɺz:=o?O +/jy?.[4KCɓqHWk{Y jUN ;ǴuݨoTYA/ ֲgynJ4NyE 6Is>\/nGNpz>&BT&(TJ?7~љXi2EA⋼\P P1k+g5!I'B0E~q)CU~LTQ`z1}`Gi)adZ88q2Z?$s>GyZoTiU ɶȰ-6V4V3㴼TcHpGڮc|Q@WA,mQRSV!_v2 @_-*0">['515߭bQD5C(H,vbqPLq$ ؛t֚O ݂zwx16O4;n-RmժX͘AaBPmuu-fVO1kLee(@O0DL3K|Z"I|+cka' &!2DR٣C@)He/(GǿL @|L6f4L!i`ǂkf?$@5b1%U NdM(qQ gO  i G=0c*A֋Ŕ1WםpK0Dيz*1,MŪy1v1Z5,fR\KACk(+l.=j̘ ZT)6ݥSz :;{lYAh+UXh scqV]9g> Yb1>_RF0.T;sw*Bب B;kPhm`O>0Bq';eQBX UdT~=[0sJA.*N<=4\81}hiejA98̓ج)JmK-X0@i8TVb<3$-L$1<4rV- U,âM4Z͎Abz@HKXrhz5v g2?N/BV\!Cc r,1&5& ) O~YbACz0yzb >@cD t .Nfc3,Q?ʇHd4Rb1_on@VR4Tq 6^4o["Ai [inJccu5oĄT((P( ď0 n$9D}~E\h!S"HfIa*NIfsHB Lu<=k]ʹ$ws{-<>nF,2ar8:;{m$,9jCy!0@>spΎ]d<avFIU #ز;![Wג&ŪK-LjWHZ|B'xc$r.hgO>y5?ݴyKOQroދ6nhc2u>e%'ǬZKM&sOZjއ7͈e6퇕 y1 YqYIo)ͳ7+GBmW@m!zɺa6&!~6_`pqȶR#ny?iy]wHE'4NPkI|*ԀH/Auz~-Y5\:z 'oB2apux8#%߀ÒNdoͷced';6 s)o]_\\90|ZWv(nyVnBlNVMv\)b[pE-B,by9.f*~9ћh^f<_H%8+5Pp.; F۳?aer) I\8 g]@)&!:t_Ju!KX v!:~X{6.  +|]lmź,^LTمOc2a؄O͇K]R 7MixӛpʠB[01ZMGx =ݗVEˌ8t`_p/Au%p͖mU4R 5'Y5,ϕh1r^k) $/W Ǡ}iiFi͉@jcq|/D _VR=Hiv:;iA^ bimgލ7& Ĵb_*q#!jr_<3?2jiq Yr(bM"GVh{$ގIr v氐ª}j6SW.w7s]~Ύ{Xp/͎\\<(*~L逻uVV r qZ!c$6,'m!Hye%o$8EVRxg5aā嗈$ 3|<:EւF57$].I~l Hz#8͆+w)S`FRqm`kQoFjVa6㹑'7#dЋsQq?=}Mxmx,Mg.{# LT+<1md4A7f+J~|csa#JȊZڝ\CMCÓ4L]y裰 3H 7p'HC{:d!4ˎahLӧSZ|J;$ g Ȕ[ ) Q5c0@JwI|sՊr&Bo.oލ~L?8FR$rM'rq_oaDzja](JVw3! 1٥tV"Ԫ=hM#۽Z9Esvw| ȄJP*UVKevkxGẸYLPgxHjk1Dq AQ1nB8z7'b=ϸ=To!npm*R:#qUA#PP hY*=2 5p[ 8CP@^rtDjDA1K p/>O;8u%h2xEX *|'l%!0u)~x&u'tyyD7Qݑ ,pu3}qz{v%1h0˭zY+*723OP}|B &@ G9)M܆1> x.$R4+HsSLG 9;\3m۰Yp٩_X\B6|'NhϹ/X9H`2IݞdPTجE#MZAKDZN2G'%!MOSPHXj8RrhV MN«ŧk>>](/]5]1QYҋޜ=kIo {Ʀgw fxFĨE.XZH>䭪Uaz=d8>ᵈ,cՅEYSuͰ ~NGJy6QmWДZt?k}"}&["S;>Ύ}M^S馳j+4I꺾4%;-?UM7n?ZDrRqnB.*^3E!c5Z_&_$s7"љ&MqegU7XonW$96wSWv'|]hPSx.Hfَ K盟5ɀi;5Y`ڇ)xQW5TI+mߋ$M*ER}n>1誵ߣƜ,&UU)ZLӷde/ܻ N"-t;cp(NG:ïz$5$CH11JU5GRS&['Z56J 7.6.g>Ջ'ջioɌRb:au "Y Yև`TW>\^h(#f*DkaL$IV6ݐ>;?8d]"fR~H%4?Ս:RM?_|SM_d?j;&uz;~M ^|Q "c^Cn06л#!Ku˯k9HadڥR㭞|m ZU Vx'zQWg%g[ W 9|}ՍҰ{1ӤmZ@UmCs:ǝɼǁ:e`]%R!I%ws}A1|=eujp`GPlrjD9nd ,IΎUB)I3xjjW.Kew@pkǩS.+ KS*Z 6(,:+ui]kҸZiރ»^ >JNhe' @wXk0撇8mCG I_!3S3 ut[=&[X k:R7,*[9;A9luxNJUvia $ Fݮғ3XGWdl[r 8Yio˽Oߞ]cO@Dt ǃsrs{q{rݸCt,r2Fvbi%r,)*)3 ["ĪIB-eQ]4Z r5rrwСmLN%[m@7XaY!5B\I*3'i3^"Fp]4Ϡ<̎5o=^EۆzjDyqԺjD*ͳRka.L48]ci/( v|QCDr~đұW?zM/!T*&W$i|mf8)w).v d6@7CK.j6& c9GR/N 1a|F@'|($2UkԸ8,.7ekNƋ77fxK" ȓbuLڂiIi9; LV¦C-Tf2&,%@״Xe&-`%\i$7sJdwB(ziOx/@j2EVVg&a:?PkgEjcs5YBC PogdͶҧVG֓\<>g5+[S  U)Cv0Gڭ@a4 c9P~(Ґ74GuMcj^ym× *rУ+*W_w?7 ])Տ?r7V*iחڿl[3SBHJǩn'ċwP.GrK6/6Fpcلc?WwRb*8oQO-|>Ҷ=TgV=%պ$y!JR}pb]-Tͦ|E뿭zGoGjrjf `A{ȓ`BF-/.1\DUU 7LSx.E=`r&)%в,~_,fkߤT0j?p*b13Vxwq|&F{WxR7׿pvDC"nS.+pjy1#n}'_Kf1ұ:Cv(Q)=imieOWusCkt2^0qlo"@k'sc] 8Mumf7ݦ.@jjEy7[ͫHP d&=]d}rмӮ~d'ջf6W~~e:on/ǧR)vBv#3fwh %[]K'>沬.4.盤',%esQؚg΢7p.bxORw^@Ή$`"q$)m d˚T47ZS58`h/4/w@^yR Mv[Hޡ6~Fq5Z⫗|ܠІnYD:h%LVڦ,m5H_:fOO=)cZ-Wg~PUQKඕ;j|_PHB $݇h&JjU"'id ۘd+h5թјi#Ik0[vCA8Y\1m"$=(sL^U|+JZݬDz]M>8)JղL4xڌ ~BpqRe|N&c@-v$-<eo;_T+D0̒uߖ7rooĹ<\|mQu G|͜ԿhjrvQe#SZ➀E~R9Ĵ,-ZWFbQA1-{xDNΜ-Ç";C2ZNq>i+q"3.+vYsVo;c65 F3`/ fǮG68'a_`1U`B"s%0 FAeطUc8Q(<,gQVEP'熅8GHG@!nszZvnԢU 5/O㻙ٍΠ&9^#q=l`W`"tn/eo[~w_g9 Uµrr)\" t~|v~~7.xWdܫҹ2r䴇͋f 0[Qsn,nZZ/h&C.C˝iUbqӺ]qr!"g cҩ7ӝp(Vu<{s }P-SJ(?hnTXBNn 5dbDjɑDkunńoJB XUx%wVa Ü|߄&pO"p`| 2?wΙk#&ԡ7OU=kEPƾSH{v*FOX ʭM2MÓ xZ(Uy%m$@r@2E…ΫzLTN3_'nђ|M"f KDDQօX;R$e1 sBl)>e#)0ۮk}.( 8JSttT3dw7~'#Dba:L'h'ΠGs;kYf%~-5N4b*ak'ELbZm%?Ïg(lcGZ(`dg1 1l*^c InCJ 虛M՝%HB R9CP}Kt)s8իTb:3(JguULHQv,ggo|g8wް&{9W$I 2lWk(?=-HUgFO NQ v(ˏ}} [K.iN8PA K:^Mjѝ큺F6 {1*-MvM,Ȉur 0MލeԌX2.d&ZeȽ}-f7ٲ}A6IECQbE͈rYga*J[&eL$7;6 X[}1{5_X&$tZ"sIR-@RW4~86Ht/T+NV_889883 BZ>^$OV%pdOLoBUTS_m$c=WO k€1A-'dݭa*bn{˳&P>@~JNuF ,WgYvqj"D$ZJ@3:>zP%#:J?]] @|"&j+r=5"($%VrOa&gi2B:'^HP{M"Gҵ}z}#7 s@s05UM6C60]wxc8 uP%N` Zi5`ȜUcxPhv{X:U>U֋Osdi9S7 8(uZ#v~vUB]3H}/A G.\n_-&swM_-E@OIY-8S׻ )̶H%Jf!ӀUZ |Ɉ# lRu D\Jr,[ê0Re8fx2U۳H^cvJ|R㣑ev)/ d:[6". yvHS'^k%M#+0WijP| NG P0|7߄DZ3 'Q#oU nj'gѨ˙>Ϫ\j`!2F:1;(#h19$ O+0| +j/S IҪlE`v9;e}Ӹ!I$t*F)Lu} ESٍn͉'Y8x=TcHͅA ?o0Jgn"%z (eD}ɋch~^F+j]9,\34"msDC>K9[zf~\ c:P spQH-<=hRQO=huF_h<Ke+q eYѠ4)ed j|M"-_R%},g8wCJ} ۼ7dM楫cWuyv&ٶ|ɕ;;Kn8"U"1h,an Fâ61gumOw.fQ4 C0F[WΧ (nCJ`bܪfr1װkoFɱB1rbJO#ExDgrxy9DCJ#NH*8WEc[[df8+l#nHpE\dyUR ]̟r~FӽC-BׂJR!|O+ >vu.SH쿔gpu5\9idi` c 0N:ScT}2NqPPLX;$7Zk:ϳ^ɰN[:'c F=cnF !]ALk4O[С>n!;vY#ig,Ӕ!\sk43q%7Ľ fXU{k9%IbORM~Cۋ]Cl0F󓠨<@G* xkg':~)w~$$g[t5Zep2裏֠n4{}u8>>.^WXR/ kLC{~u@M@to{BijXYG $1I mӮ֟&o#NtSJbG #ŴDX6`ALhUTNTo ?hrEY\pLj8wraPn%9$"z>0[j[дnɂbd eGu[/ ^Q~I<Gey==:-E^&aE^*71=lwUyW7-k:Q Vο 1+qxiwmݍ|W4pvxp )؄vu!$܃ѩo(I8VM@O}HCmtHIk5f,̒KA#``X5,OFNCZ8TvC%l9;>ޞr $q`^鵢JE;"byBoS[I{t"#$bL޷{ky\5Or1/s}!Buy3ꖦ5p'sr#KV B =`Ghf]큳CI`a}R昴:tD^hm%e@죄x*g+9j]|!C1"^58[*bU^JO'$\+@jUa_~fU&Z#2y7{ ʲ۠nbU kTmG^ʫ4lz-C*%:29lT(uuڮ> iح'qW'!6վB&΃SvKW)`Mm9p8+Jwsb&@cg[u2XFy[b9FS5]}`Xc"r!f-fBK0indP0L~a< Zjj;&÷?Ky12x'SI2bv2$А;Il#ŷ#҅pY)~N( c2(AQ@SIr1B\9Xqn|SN:ġ?܄p_?^; qُr[ ; ;%C[wfFen'9$S)`mgC&;֛HXNn1Jߌ/sjG(٠>?8/L3a3}x{TÆAA644E)ׇ/_/ )cxWhT 008bJLEm҂= J._7ôLҴZe?P#ĝN)A>~uA[6t Gn1 +7 R9#HMܮ̧51M P͞C BYjdKca{;HgHؚ QzE"ɽ<-h<0f=J hTK;'c{vO3b FqJTzV%.nՙqfg|73ijRh#'w7GcʮAF@,g TFz?FmzNg[^%7;3C$m$o'B$B!~zmR&'vV2s@&q#&frx,6,ǥvkddJ6dv+W_f!Z>Jk~Ҳ GՁ[!(Og714(S!^n)"-fˇ0Qb&C5f(0g cU${ _M\I ! -H\,S4~gjOTNģA֘-*0x+PW&"%^ P\^B윮AeiP|ÐHT۪e%onv<Ty5_&Z7B'!>R: mT?7$j {̠T:["06;͒ Qy wX 47ſO %TD:߽r#?U@P3ynxΝOw=~l'}J\Sv HM IXw|Z9D6X8#U JѕaWUPx2p٦naf'y. 1;5̷s7K{$M> şO8zga9|Ϡe hC?kn" 5jXz%:ZCK;+2iҙV@/lTj5~s,Fo&P}=t&_wCvFNRb ҝF#6f=Zq<|wɰV+Ɠ4 SHfWoͻ{cԈ-0:8_F7v!/̗ݣoFNR'%/GRST20L'b{qqarWpTф''qoP-muNWt= Wp^nLcFBɕ(#.)NV}K# w׭{Ci2 }Wto[nJj?8 CvɂXؖ"D"ʆ+(i~#gZ=^r_0Mv"![>&$R+˴ TĪl8~z[kLgwj14Ax;qRQЉjkB)$e,"eXY&Z0N˱ HyX־ͿAj 9EkgWv0 jWLD瞚&Mψ)9P<WU@RI]Gâ^Z* }1&[b9<_} C/eEt?WYZe)6aQhVVF'-;8jcL1$hoU"Jztɋ|msY 3Ap ^ o#+,A |h}Z0Fs8"` V?~{yʊu^Z>^H7y$_E:x!^Y᠆Sn]nz Okݾ7%$ 1UÚ00 S\J<,O2m~kV b\{8$9I"D*rRLE$Z}r7I#\4!5h aVŗaKrIyLNN>'{MYdLUEFn`)LHtBoReL >& #{,fc#rAh!N(2 cD=VE е3}Ri&o1^}:9FuYW3cudIaˈqY #9Gfc}VAWɬ"8'Em%&ܚrUjŮDPtǓThj x3_=bꟶͷ wA^'~/z"AQO(<<<*M@UK[X;O5Eh=0.n:bv-%ydlSV(g]n*c*?U8.ן<Kz>ev[i P%߈U4SHڕA7!Y'J[RuJn  s6BQ&aEYHCѪZ[9/ m,'1wpWkfb3=Y$V Ȏ \D&dη!jbi)N';ۍz8'FCH*i%C޾qf,/nδŕ>XRI5-PGKwr?V#Ltq&;",Ww Vc 8ZTvRw^`?5Na@~YK;ZDrʏ ¼FLm˳4CN(C:ɽ܏u;"GE~V5DJ(*dhaj-t&|9j!umIkqJ#Kn傐iʝ*9QYNVڎQHb;a:7Qցn<*Fv9tP&]HJIeZ8'jЋ1"ٓLHvn3=Y3dT4lN$Z <-Z3S0>_ 77?lӨ)tQN {.m< `y2f(pDc;xJjSy]M8TiB8*PnSPAAՆm_΄a]K;-6 OOƢrd- ֓AY=6擪U;,ò°L&,0GoetDrp2s$ENLY|m%E(ekm :Rr0!QQzdM,AL,U@1 ]^#=&9i}dZX/vv?FOٺrbaʶh?!Qtdʱr!I9'XDLᥭ?TҪzPzäC EݸGd~I盟)$"GɿOlQLM&BЍ"N6@O = |\6͌K qy۲./FƺI*N;+2.[f 5he2M?f`%v]PK_njt6Zn BEec ÔάkŅ!/~eUlQOb, `20 Xч4}2#jM026!eU@lmrA#̄>M,']>VW&pnza0'D*oH⥸fo ƠZ.vNzWP(o^+q!4 diO 26ÑQayya+'(=]RpfUNĜ>(o)':Y&^*e Po OYİ)fӊ8pҢ@IȼV[*E>bOؒOq8JBؙ]O ZL6k7Ӱ g.S4Ot􃀆Wj7Nwk6aݗ%YUҌ$MR֢dڭzoMDF;Trr)QKIp$,^rʽ:0p̤ij9p=NW$INZIպFX7t8-,w4@%;TJ`K%l=GiɬOkY~@O`|عh69AU͖#/g$i#v}-uE1XOi3[ȒԎcDZ3xǣ1.΂mTy^=ZH(G)S3TRy(H<u 1JEe+ )7^eRŅh}H)Hj{wL#5u$ `"Aͪ>BI6|b('=]bEmBJ^J2UX VDzzOP! *,^[UC  yRD*AͤFPv ہ]$mσ #-^39OМ (Xa9U~p(nz8dҘ)i90 u+ >$x:.=a#x&ndU`qDƻOﯯn ?(#2M)ǽX| N"ZJwQ*+~ھ 46D`RV_0 b5I|k=&>O40Qp#^ ś7~}&E/qtYM(l3ExmbB\b@^4J(,ꅨPN,ϖMVV_~Mvx@kh% /xr,>X=01 (=X &tSd, `\@O%);K\U>EqStMP.NT#JV ;5%0h?l,Zo MͳmcZ _(kC]Oă$"K XU0PE|-\y hARQ2f4(e;Ns*کU;)+YkMxLS.6`~N _nчʼn{\Au135W*K;9+/DjB/IA+4ZeEFLICpK6wyFo{ӇJzIkiuƃ⨩dm1$Z@mc0jX+ģIGLaCb>l2?cji' |u v{߄5IMda;po55M9%!a  qhu0mEzrsBz}M^ۨyJ &3O"<~p;_ )SHi: lbwiש~U Vo?m{C||}Ɏ{(clOuoڣcG|"ك$de>tϥ<a\{XcNS~+}&spE`4ΔaPqd]&ZQ6W9nу~usnfc-UwT8:G8/C9qdFJ\u`3slx`8]~N,D<Q!ÄF: dzGtbz7|>Ǖ i1f-$a5*iqAI^/U5fO] ne[kRZ?"@&pXe.2EHFuv@!{xF-:ZGc< WSs`=q^ PI *w @R4?X3sH# Ŗ6E-6N]^^s1eЮq-ugHymA J,дP) Wo:̏VvNDdI'Cլy@d)Vo<$--9?h.R\`%+(;{M(ZmWz](;𐑚P'r@4^{6hK:Cp@O'@+,mny;fX~t\p`r/Ւ/ޖ%$j@=X-++B[gHr/urΔ 1*䟪8R*@lEDQr@}$>c9z{ȶe"֘ @Ш}-HG!@ӺOkJE^ք3y8EYLŹZo,B'} J-׺]ڧ 7˳6֞$ɔLoB j|z.-E5[aM=n } _=Hw#?.T-YϥSkB(6O!jiGmRd/+88Sgf'yULD-sW/ZɥW^k,_TtR!ap7ݼL^9:V&I2KO$Qå }pUgEWL8Wˈk8z1>k}GS83R"T%拴ڜZɦQql^ S|(ױ/)&DE kzilK8xꉝ@Mz[>'Wov6tFC {nӬmtZW"!eA9p!#ib{H(!oSg.rN~6]ZpU-x,q:k~bw^ZeVJ:|l =\>GDߋ³ꖠ:+ bB ϾS*vB޲ MR#iR\jB~/F37tN-Э*D {snWa3Ϸ ĤL+Ȣ6VL&ROmE.CT tXve:"GIHOR7!v~A*|uU2mkW1-dmJΕTͮlWʈk_Pb*ʉ5-N?%2v1-$̧:˧ Uo S2c֛*4]|>t@A>/0HgIqITG"&xT/RW"ƖšƾS+~~U깒y7'>'|sL&D1BU\[IE.TGS;qRr1}n듓/_؜TDfB簖,]gjw4L]ٴu4"wMqϮ?0utjڹ '~q+:nsÜ֑_vMsN?TI! lh)oBc߼y [|'tG+U}&opzz&I1.!*6G!'2/t10GKvp*g QI" zT.2 I[#E{ ~g h)lmdMV]Ǐ~NaBTnqE+Ӫ@x~ZRe#:.\̭=9K ;_9fd9bMNFݹH!;W.խ?@b[8ԃEtJZf Dh[~حk`~? _!( 7ҧotI(SS%GE[ Zԥ=5Oz=6qވ^.Y%z4|ݎ>vp~"\|+b~J0mx8]UVǓǰ7&1Y$d|ԧXcIX<ޞ0[~-֪[hf1|qx\N}^j&PIr29O{ֽ#QL)VIgd[HOr)bرZd.eFICV}gcJL+_5Yt .ZOXIu%gXͩ˲C\RKеfެIu}$>۬UZvd3/<+t'5aEEk|#iwFZ.hC%Ds#2s2yQxwBwKt*acl:1=V:xi4fX1)iԷiSD,['1!,=Ga.uH#BZ$lqR̙֙I82IrZs ʸfu>&_9tST1qY"&(m\Oվ @@@[bB Qfce佶}08-޲zz-}YaxPW#`cn}X0!+z\}av"8$J 1i= Sه nfPM&lq*@J69e]GšLaհID[s[@_aΈ ԘjtTooC[\ 괆j!ز红Xw(r^j7d4da>B]S~A2qu6'P3)YLO}sSHǗs*)x"'k2}//3`^w<24H?)@36®ɏ(ᤉKUU>V m?~ĚaO[m{S v; c<4hu@`!2H yRYdkaڇҢ"UAC,%`ܻqC_S T(vfG vwPj@|qs6=+_,8NCk.6٬J+mϺBKNT|}Z%qKJ 6~FLSvRV3A@U)#}-xn IҴ9ؤ%ʠ8*轊*rӜIfL{Avk)8 ߑuJnjhi=̏E#v/lj_|\0 9`8EU4 &vrg*I@@g۠~۱E^lj!d@~Mߋ4Ιr^]h`&|xFżrwrK/:aϧ.5i\r~,iuXMi˖'CI!B?{P-هCլޅV{&;_,ݒ',=(425~4-^{=m+D?\b- itd{E$t |aH\*Tr C|Kzf!.@ih8Zn{gEb}5˶nwMeS*Lc<tr m?LGYG#6{aK٥Fq~uᩮ碤:D= }fv>oߢ&KJ+c$)ECa kIWVDW=! jB$׫UYT7XJ ![_|yӘK$B5;Y?T[]I0qeIOJ K98'9yFt#~[]r֤ǭd.;?_SܭvUz5Q kvus>y7o~==5J8Hs/9chbTb8ZW79ć$>z23w&o v RESd391.4pY.(ڷB7 _nGDnǏvD_90F P!wK*bYjQՅ^C[a3';p5̠%AS7zrg?݇Ʉ\:)}qZuOkhDlm!g]pd}Q.d$!Q^HJzp"6B2ra ˇo"8ռK|wo Y>AoU5uA h((QkCh>9 EwԐw,y꿇ϧ ;N5.旳ΦuIHp6.#>, ף}16O2J) j]^ݞp *6IXQFi}LFl, ?7[O(JgY> S㤅!g-|n(sװ(ev+J*!PZ=?݉#k@KU{HO<`9Pf˘#?#y!]5A-X[(==)Q-3R+&C0W!ΏxB)cj #cVXb8/aMO;E}P,LkåuvO!1AUtǿe-Np%~d>~WaHBuuzhT"ÑK_iTO]^QijImXz/58x\F!'7w(ɹ:9!?UЕ kSu{buE8YI)DjVTZ p agqR&9I73A_`ʲhp,blHNi:1a $3:xl2D8JbWu$+uPi=c<.x[xoth~S P7sXycG3 CPyr#jISԷP6fWtRd]0 $dyoޠfjDC$ Sw]H \lwUR,ز<2=ğ~mo*Q ŀ ʅ[dIo!ؤU[o7XM?=Ē(RuI8@XŸ>S;ؕHq:&__.ҾnvWuy"\ 챙R  /36U@jdk2|>,)Sg/6@"ˢTjˀ@LqJh Y" \'> ۗE9(%l zjTs*B+eO3 (iL]={HM4ZEu2$mZs+Tx::Dl:fUό%V#D}dzkxm}UWG.msfDgy ۉ bZF'+x]}1dNY˖È5ڀeRҬ^m7o+ujBQXx^lV 2ʖ62ʼngco_8X5LوRkͶY8uF U+}[DfbƓ'7lK/^.kؚ:|4WqŜo*/A^YvW#ID2B/B4X/)ib|(Vb`,(r$±yEvuB13˅pQa4 py=*N#.hdIn'ps,GO[鐰Gxb[\xՉ)Qw6f  *̍{0Z Tu* !KM~Sxs¯7g(Έ$&dPiN|:c-Kqz62nZ wrK9` ` ,n,) QERTPG(CLj1P39Q|8D!ffGbTﰗJI<'Oz0(7('{ܭTCM.R1IHY}zJ&_ h*onjJf |A2긑7 66OݫO )r;8R9| dD'YVJBtb)IR ':8dkTki}zFR % vw #VHR݆w^͙3b HoX؆  {u \|Bƽ ,aĒRAG!"{m.ߝy|7ߙ#I8׮cd9hXf Cw*Es|.Jډq\V !|)7 RMK:F;_"6-vk# |'u^mвHCTquX+l4 ^(rS+x Lw$گݍ4/l ϯY;ënbKbҮE݉ٳpwG})>%tq1A_NNBLL|e蜌,zu";+4q}/lSj/*)TYVX?;)G$Y etv:)Jcć#qNJX+<ЃLUVX˔]5,ZLu1t)jpr^_߲7z>ݦSQ3} ȉ;+I<#La;cEb mYȇI0!_` lVy/rO{b x]VCz_؆9;{摸` }fBĄ4'o7F,(,)⟉d-zUSȩ|Rv<"rmKLX=b ylIZ eCfAL:ٷ}vz`Ѧϊn]-8ÕõE/hS*z g.LNEw yv&vD.\*a#20"E_Zm}<# $f6*e%А%4@46iKR+4ďT 簾g* mAx-ؑ<ѝh?hsMl''>w$.ߋ,!E?ho9,.)>}a'/tO qSgtԃ쵝H_ȃG7tR>$XMF2z ̾-Wr|Uj \Fz;=E:l%LObif Kys%4SƂ)4uRuOj>MD4 r%7j i=UB1;ꝧC%٘Yԣ%Dv9 ^ywvX[2q7ͤ=A̬,*$| hJ6Y=ЩM*EحSHӆEIJF 9ӫHBۂe5^Uc^nM6f8NY7˰W,zY ӑt&>K %}gԚnQwT+:e$a!-u3_}Om)pR𧃑B/Kj AP̎"WU`.NMS8J ܾccrnϊՈ0ÈQrlfSՊ SSy+Q|ȩd!rH]t~uqT\} .㟏?h[Ϯr6⯯ְ4 <$v_x?ŸNx#~PdP2Q}}DF^pTԅ1IoϮޝhJFxvFq(ۯK^:sY!mE. {*1;̐X:=y-Ao__ڮ-%Po.T|`57m+o8tUvi::m&VGo,y |7pCwo߂GƋJi u;ˑCo[h#. fd;7C!Etٗ" cxAT8H)fW]xW:Hgd*g?ED槳N0*>l )\$wj> {:y#@wಁ}>EgrE"&Sy{II1դub' ߱pTf*bT.w7.'OHۢ6rw$!OVWnAc羃`&.6s94My8Ȟ1w ti~vy;UҔ`W;+I,K:]Ibzτ B9N8ʹz!fb;|mT~$8>N ce ڷ366i~N=p/71(W{.'0D.,_r\D[4s7FnCt&kIuSpT[,&{ >43s}z%mf+a\N'<-2STfϓ qw)U-4[>H%.Ih`Sqk5:zi+~/0n;*y{Vl)5~:{zKKdb2[꓎6vQ86nD#v)"G?fM#{99J"do&&~RĹ#kRgC"÷؀e[*ci7c RUө8^SȑCѮE?܌CLv$_z|F4iKWjB&q8TcP\ay߳#rn6MG~T/ϊauwߴ)/ ]UYq`_̠Ww܈<qfOr>r *y:euv9CA;xmRؽ;OGttݴ^Q`0To^')+;9 " IFáz]G e{]\fiy=JY@hcփBt~o♕z|{#ǫ77?9뺐 z8`nm4@=OM%#Ve*ŖmphͰ& n\){nO)n۴bP{)fgKV~b#˽vW^xYQr N\onk6,-}͹TDSzsJ;VJ~z/ €;{ɓf2q]~qaMIFiXX4OҵJУbINr,X\˘bz Yi I[ _Ϯ]_?\&3#5:gQRBQVP(ޣj2=x۟Cdc#u|w4`4Bb Z]˳1Ύ߿mJ %!b?>,Qv/Uxxi4mnMd@fd3 !q t5P4 X_.t&%C&嚐$#厯0Iv27OЭ x:vMKnwԥW4qM.vQ><aX۫RQNWd|cljB#RFv$7Z4evOB t:ӐϹzȋ\݉ ^¸}RLܰ4QAvOD`l#8$\1-<=ƽ6zYmCbh5K6hS>VYR4>T2z=3Zz5 RDŽj;E윛tZa- v_{Dž"Y0L9 {FgFr1*Z2t,l4V@N[iVd]zikBʼn3<瞂GknAC})R*0b^KqaE0H_Ia Kv/%׌\݉ypЗ sffn0Wk(GQ=wS*_Lo8)ظb8iFVO /R@yh㤼ie|(;ʫGͿl>,j+V"׷56a'q0G~KzGHzT"uh[YW],I]glxo66Ljǵ~an'L_ٰ}A8JKXvAMJ4ߵmj#^`]@j-:sVpi>T뜺 UcCz͒\7R`0y=4;mLb+U~u-S(|"\z+jG>^ or[5My9~!18cRTB@he;"ֆ$Z!|no<'9ex !U*۶`QP`kGC*f(" uVI0`G=Bc\U* tl`$BV}pHwI? \x(kSGiQR$QOmGIcD7< 5ftw|ΥAS Hʥ|A].H'Szc)Yh5mPMx-;CmC8a oE fgw~ŕ :Jwc/g2v>uWArL=F4p3$^@0Z xRq*(Tge :C=|@YGjz~YqK9.!&T 6.Ox7N/ ;`"؇i "9ξ&eup(CIЉ9,87p1$k<=&RŰSV8z_˙>==wS0x%<2iT*N-Y""EI}Q6,oW;4lepF4VxPOo9-u1[ZHPU%@gC8xsӄ7>D?OӰ~mfzdw2v}Uv3!)u&.Jhf*iVIv26ZLaω$$,QY>|VϫĨtHwfM+=L Q9޻i$sW؃u]F4GJqںK6˩O@`|.F#W]tu^*lJaH_b aXCOzr(4/ NEM4ZkJ ޫReJe.;8՜h 0wJ쥃B:ֈmgK3P􅷫:ICɜ'q/VLOA|AMSg_on:4DB Ûhs \Jy?Ϟ_2F >t5虸N_G"Z%=7pB${>bmɦNԗ MQ38>uuD ~ONC_ƿwو)xAẔv/kzMV8Y ~xiw-ʣ:9i.;ﳳ7*.`q˼fWʇCcyp t}|e[lħN}7ߗ[ڏTJ_ׇMz/|M.I/}[=`Vb~\R힞7*>s7WD~Ƅ4"YK*!|B[A|,f>3^0amG8} w׶ڣ,Ճ^ tHyo5"<9AT/ T*Σ[mU_~\(. y՝-3Nq[О푳P燰w^  1tq)<6yG̗.#qpoB"!rz&ޠˁr`ӧ׎>akiK1[Az9\=#*juqF :[% ORvVvSVu, DO"@mZjU?lW(WܔӴ|@_Od[4b;{LX.Oh+# Jb$s[𗔖gjMsOJWt[l~N8r@M⤰wwL ʔyZ>sBF\ RPH7 j~G2-G'Y2eFCȵ}aNBcZi*vkFKFJuSiHԚi߃KR`Ɩ5L}gj/7lLOoծǿM7sO8\ժT}F's9=c%OZYF7JAlhn@m֧A%o ]RV׏L;E+#gr;έD,5}ֳ4 ]ERn!UA[94z8^*J@Z6}m Ist|+ P JOɊ\~S5M]'d" vjmɘ7w\ewoY:ޯ^Wh/qUᜲkX(fYPK~ =ΗVvEh^O&s{A!3@.WˣzZ)K 4Gpt'[v8xwh,[wO7ϊj6mW/C^݇eA0UokEFU̟LWk:|&%n:7b\ ><:15,"vΑvmfB}2 ,uͫbT^aޙ‚i~tn/ PL3t_t)v<'ze.׹$?:)8 |7Q$rtPXkGјG :{ig9>A)3JfOw`C#맧O;jԼt=7]~a#[FDpbJfhBfyѮꕬ~Z(ݽKTR骷sYTFF"ffLiښ&N cQI_V i{dyۋ(t,HWGpJ4A:9&sE9U,H38X"FU*Tsu^7K)e:MMmV+1Z==Vc>^‰U*?{~K4`"45}OקT5iY[E0t*JR돯\ZLšݪ եъrIX%(J2 K2e;:_Okk)sJbZ!1ndT#Φf+EПWa)A6Aǖ60>Oƒ''싶SZӄ)^^U|sP\?@^h 3And }b 1FSH~ֺ<۴i۳%cܦRw,.1,B9UKu1iNG~^SDHeA9줺/x̾0Ddd{! [&{hv%ðj-QM@ռГ|rk>HN em69nc31HeJX&x:nا_͒'C}s&bmċv9<+paDWP2Z)]n1KbZ:"F XiXw9,ɒRr1zCߵRC J}.wN py%| 3S]g\}vHdO7i$oKەdWmN/`B>rk, S4|6; xRcQYvk_Z?K|V>{ʮR0!ç?{tXKF!xY:o]r'+_M&e]´-F=m>HiqXcΟϋZr 4s@Iڻ71\̸gdnpX1M|kcǰ)8b:K 1l(0Nx]A¢t!z>R\=jM2έTkXʸb&/h{kLV_Mv2E@t5#|5Y H(}*ѫaV>1`G*wcYH}],tץaq LIoֺ$,CVc+Kcf@_w & ][#|b=PFNqw3EkD׸HZ―{ޡ&+ K~a w45ŕ?Z4HB*!K5j0D!#W0*8pbeT<oDX/M=h(aX R]{ Ph*oG "5аfTAHפr:ԯ>/V-XBRV+cFU(4/.ӞB7MqUcJDc؈?Kt{R"Eqb/eTj\2uj#.3ƭA&Yo"kʲeK!,pEJ$^mI+# DYyyVU>YvAQurVO*xwWB- \vśK&̤~V &iڻtBrQ~WcWsTqEHbR깵THKJd'\b UCr2ICBު`̦՚-(_ ȧOAaYXð b 4u Id7:{hŸ)EK r\R &66gq>KB+T-s'?bq;<$[&{.پ4nþvEJ? BFV7Zk='w^se=N;MCYʤٛq97Kƙm{!"Gl|@q_ \Vr5Re\q֧6Զ&鍍.n.7۫m8IvONRX)F[::Q=b.GN[iBIS(.>'Na`[=>0jr47wxU okDoD*a{a5]SPQKz9bl^Oc}1_Qx|7E̓bR\jу,y"T.F8'kWgQK82H iȄ3͙i%24=m&~sQ;.Rr[o9|'CYןSآe,CƓ!ܛ4E~ &=[(llS# ӬɖL55"<99qm/C#Ez (42E/L`bj5d1INKjRjo)Xfw\^fZNRLmø1hoi'܂ I Nh>/+Jtז6%Q-j-i8iUQAZ7NY9zjim -:Ng·žPlh TZhGwĮ?pfBC&BEMͨGJ%!cX91}lqKNi4$#aFEP`ƭo ?Ndi(PsW:u0w^XN /❽ QMuv[mNu~M,PhZڮS>ȳry:zսLĦBSYƗa0/+03ȁHy4>,ݑ]gT);~ +J+1ěUhbz(w>B\,kNE7] ݾ(ZytlXIt$$̮w1Nf)y@2HBBPnRn~dD0#ހ'CГ^jkX: m1E|ZȗC9XvzZ=>ߍ9R/aK߹KCQ d08ń#Zoã/i]G 6%2a `w"[ ڨZ6=dޭĮ+\/g e$O⢂OcJpn"z֑kuN}}2IqumLD➸׬\Oauy/ME(@%'qrv?-U&\|y}K3ZJ+'lF\=qs)W5n~:'Ȼ쏆ܘ#*5vx'itg17:]wTtTd˿J5dJR E R vSwDПnٕi-څ3*RLǣ*Mk,5bʹ2AaL FIZCQ+=gU,LO7>> HL kF<K֯\4p_Ft7d(;DP:Vu3 aL*DSʯK2a+nF"0qqʨO1G]0?a\"7Mqi;4W!En7A.A3œ( EPQk97Z+rHb=6]=CJlMLYnֵPi!Í~4ŬidQm]hg^Uzw[? 7P:Ƭ(l+ ٓ/noߘrd! uZC*a~vצKkpo)\oeiDE|o iā:/: 'ӯHfCOyeCvEa<4pХY* r +%JKS(@4|! SQ\}!* Fӆ\GEQSmk((Kh R8O|b٨3yZ*i8C|Kg۰K1J:DF lKO J;sd4BCi+xB_b?=|nS8ZN},JlRxJQXE|&uq׍4v{@+ j5\#j4 `)Dv\QbQ_VI.mqQ 9I]G\r0T\FI%E 7U^ p$[|;գ|X¥slkW_Sz5t,n6o&<^Wqhg_ZJ@0C@ RuFSh>;._1\˟㙀P|-7sOihgi6OpL$tYoz{Ź5)z%>j։ ^4+CxUL1%6$KOLccR:4?N :q +h5 7[~>€NJ`Y4Z#߮<:e+X-iPgޢ9L 3ܛ-)*T`b Qhc׹j}O$82Ie- ѕe-}WVZ ~[glD_BhKW 6~ ݒNI%w3 o.?gME_5`,a9r|Kf:ߖaQLLXdQx-HΤ |,! |tl; YHxp*aLxx=!zbA c72`#>yspTqԇ?[,ML"m"ASۺ;[' OnAWG2c-G\+ W&3>Ku݅48+vu+S>fj ܍etȼ}" +.(ORE6dznO"Ԛ.TX< H;P?JOckDZYvWms)'dU7AK^NO{:zTSxN.]5{qX"ܥv[/)5O|%bT6 rPL>SeJWqpSY'yJ܃볃Zގ@U cXT&Z(qz^m\;9n`ۛW>C_XSAm@/PϛW'wGh4Ƨw#w 2-Zevx-E+a8VpHT-y*qfnUxGrLx~$zIKT808>pf^p</ZQ֩{3 P,柤GOT G*-LtM6_7LpV܅WX8RZ4ݜk g'ȱ7$@X[k},R7ɩW1))YU9KaK$JxO#!z k{-fR\놌7H!̗)p1) 5a`NAg9[bh,4{ܺڄo`fǞ$~:HجՑkԶU@ 顲L^%ix糋drnQխ#~wy[1akM"up~F" N^gqpi@_~4C㐞&`QնTCHqwufgyIvURD4GS;.7́4ӷ*CK&`L)H|;¿ ^zol;;ph7~v pn<8@@@ ybLClv"CJ@"Q;MMdE&+X)4Y:DƌF.&’3k~nm~wt]}<]؛x?<,ϝhTxP2VVtl5mrw}wd5%|P`|77D3ӕ_UDߺ]0[4Ztd?ϐXl(MOM1fݣC$,e=w8-nK4!uޯ#Z ub*xoŽ_E ڽ Izf8qi˯ͽ?rr lXԎs[&Ө$"aaAJxJNdbeBN-cOV*87;6>\Wn/ߝ)ޞyahӝSW*TfJ2Q_9JV_*uNo w=-WX((/FnEd EO老)>!.Q(bg=s)=㼞{ϰ5mI;zQ˔qqWx\ 9PqlTfU!UU;F W5) /*%lY:Je[l]`  ;{*[_\ = S1A˼;.ޗO "6; 4;" JA葇X# ?ex4Y "^nflIsp0"4_FcsF=AV_j{Gvp띻\lN)[vroA>6]  d7BW |=v2\-s>H遅1YFD>5ak&beD ZL 0Pn?"آ&`;R0" F(|0ORkzR=SJIsȯ읒6dբD=;c}oHU3ii\=!"aSg2Ű ݧpFC~^lMV˦TEJYr 7 s@}mS90wށR&cq Y-n7B 6O7>@NOTyZ-5vIJvӂל+;Iՠ`\(-qKq:Y}B=]X'F{=8OĴeS~ͫGe\'Z'Kʃz J:Gq/5Yo"xVHA+g_iH#5Ωrz_tZC$`+]㱍| ͻ){`g馼6}SzΦ)E Qlu_M~>-nwo>^\ހtd6I|C>ߌbX; ADi =!QD/6(ECOqpT~FK$"b Vvlz42utJ?$?ϜIFDQ.gAJ5|o ;gΗRRߑv>._-7/t [NI؅Ϝ,g۬_Ux4+ i3M+*"ԌhCd"Gd$q1k-XZ}b]zOȿ4X[x|^WĘoRn\2P|}Ch "N:k_ry]K0<,p%:),(LsĎ e4_sVO_n,||wꇫ s'NO^Æβr! v=:ӝVeC;ua&3JGXԂ3>I,5dz2ٱ 9Itcr\"sv;与䯡ש.d;+6(X/{da6wyG6s?4^rVRH:|BGezh$).4+J="ByB/wk[9>n.,Q)UHh8bF!hbےUq򠗕KA&[@jI:MatLh댝'W qƭ?PT["Bc(GFPTT)6Ղ\1eDF3D4@mljYx#/P>Mb&S@5ĊNR,-glU[O SDƽ)Ud \-bKӼ5< [ꨮw9)_ %ۈ`_R;1^m/BUHa!  (Pi ms# O] Rl$o uHx1'-,]#NzV:v&' 4sfۏSk?IFv;OhV"Xto>/q[45sKqxE&C0H8ԕJz{ژ<> jݘ?lvy. ͭ)uW?IʵR. 2E3,/g?JQ2ֆ@\[A ID'p֗諃Gۤ􈜕lHQ[I$l-1x!6q. _k ,Z{*<"c|K;hڮz0ќwŖdVd]NN?ᇋ)ޠF r'j8fVU|xTR?}yrpޠݍQgCL C/p)-23Cn)SIx@6)74e*}׈˜C;ʝ8ns5V":J m|V'R/oÁ?09TTRЕ?ɌI5cEҜp \ ,FqZ:K)8C̩ /x]o>_ޠ+7 fuo.XgtN :ɶ^%1o\P&ke:妛rm~hamɫ{r5/ XE;@Q~3T1=0Ze@\26(tد%*)%`1O0=}}3TF[6zn}}0G|P_q&I$⟠9sTj@R=jVDk՘im0TZ:C*^JV5<ՍŦO{3 ?pG`^D˺W /7xOR9 DirȻl_v=vo0Au/bvHz5D3RƥJ9>* ]_tB~*zH0~s"AbƼkf N^MCsC6qOF^ݎEn1h$!*,, i尅!=M/{|uQG\aQqPn $"Osy rXgY9Z&GFa[C]XA&'++P;ITYMdz$u^f}vWb}zzpcT77v(.&v6Wݛjih-A K~y싥p 0L^ f0@ |7sh\vD2>~8"MI%&،$|9IubQTg8bRˁcRepz9!ힷ2Z9ekmm@}yFm@aX6QUeHNI>)h;5E&P\J,"F޽Y!QYt;.:)Km'䓝SjO߮u%g4HR %R΀C'TfOF'j_~65|%ݧ.a a8b33B@%f+Ȣmp/PfY4Vl!S@Hgp OPDݼjTSÛx j㷍\MkqJGuɦi PcBBVP5ڳ2bcWu|Hhr̡?^'oDa^% 2ܜBk<^gߴ[$H:ѥk0d[~]1HӫcN)q"sv7O<4fr,=tr]0Il_eO氓%ZbM'w OC_/$kq~ qD1dVf͐;:lRcq܆uTnF<3Du|8g9L_U3K-:RrZ*X[:֨=F$A5-c7\W0]vȼGrUy qZ+cKBv.miUoY]IsgW_ ʑHj8l'SW\X;Bq. =3!pW Y$ 3%-%s{|\ҥtD k_prOi8Փ v *mR+kK? zf|(>J߇ C+G2,7?]prD}tfvKR*TIIUۂ9:V}M*a/J_PzYvN}!=ưu~HM0Uhexl:"_8eə /%ez eK<K.r)vZB 1_A?겷Hw'i\ܴ[ͻٶ, h]}ڂz֋!aP9vrLC>{GҎYW"Zxdž{04S#ëShiׄSF]w~IЫMD*F0wc`([ [fqFX%ز 9nG,)j%+G~ݨIU Nq;_D s*8ԇ0h+xbKfaϿ&~<}ls 3I$CDU\Fe::'UyTdDTkG#=:px _  lDV|.@^1HX <5^ڴ:zElG,_=P۰be&Cjut޾ͫ@kwM6bQq~Z8DT,}wgn-3ZrDz" ?B!w%CWzĔC]\8f2_(&]N, <L_Y!,rHŜ]"yK N7)t#fe#U0Fȭ7Z1aAhl3V׳H:>yw_]%4vist P[1֫DjK_{c],p~}z=+f 8DT>HL!ʥf EՍ ($z 4dpQ-3QO7)֑-&ãr*̓D oPz7^1e$TپhۼI$ή߾A3tJ]!!C7#YYTW}qsTS =_T(&+=dGEc)UNp>F|xvO< IVWj=0u#8n?IJA'(⯼0W,+]܎ŧӧ.v6+ֽ/nnS1rR\1)TQ_5H_+Kd HL@$dժniJ8,!$@#&h+[֐*Ye-aHƧ}HVš㤵4lOT"yگTD -ba2bߒ/Sl]QjI fɵ,TgHE{i9}s]ID\  ^V(|ZMAf̗:Ѻňڽ>GFbUbPa,<㶩2M&mhH;]Y]N\$a8^ @|}Ϩ2dLtDCS??{w~f|v~~Kj2iyd;t=@Qg2s })%WuelY7$杠R{Cp?$l36eN^,[f9Rܺ< Zz5T=p'q%Ͳ8@@(/>@E[ˡujj5I_U崲GY"-6ԍ/(5n۶ƒ$[\+ YW *o@dr2=I:DiKAP5}2s7QyΝysoe iv7eki$8=h{GMd\m/5G6. 띩>b+<:O X !‰B "ۮQ2;Tu35J S jfe;G!)$kqX +5MsaԐ99#'WM`҅Ӳ'8Zc&wML^xOo:/Gqe-!MU6Hdn'sI{zBݻx9`[Ks_ #JduCY904;7lϘb Y?.OOgo/4)fH"` 7,)bqb2HK)PdA ÄY!+X"tN2D'3.e3!8s"V&Lݧ ZA ?!ʻL>;;I^CUVWwFjRiR>,  z! 9lfch=H럏W8~GvU %#ٮnV:r:\ZZ-P-oN%>vWxF{ySj |ö.dO,5'2ZcZrn-)KvGcx5sR̳M.%/Fݖ]Z_nQَ]+8>;`K~F2$wT@'=pæLj29:繑buQF^}d͌YaE) cYiތ5y-S2#⠑v̳Z\ɄW ^CpXϑmf'N:YnDwcK)g-ZJl3Q%R[<OrmݒPF ؿtN-@GA@`;RWGR="t2"I-|-^ E@G#+s ΰ7Vl=w@Ptwz=2/!hD?qbm &9͍H Gq@ 2ԕ!n5(Sq;`늺b.WE{iґzQj+ N.5zmJ{ Gj7= =]z85{i>t>WD\^sHuUs@bres7',4GK1sW\9QR3 =G`OJ ~ML%y]s@V~뀵[:C@QS>s}؍.TILh=mQ%¿`ʩu(\Hi,Zoɮڠ"Cc2 r;#.=Ww%鳞>KK~]Lsn+{ kT1 pnwϹ(1[64OBgX.`o-v|b@5z'oh꾌ETwc{Z2^0Y[L)]b mQ4F5[מ{h=QYh]:AgΣdV0OR{϶2Z/6cz^.l-ۙ5yVEbRA"埜뼿- ^|4([XQ,6$\^\\7ESjڶV 택`)Ǒe*O-:%ݏ`d#;pTil=5g/^=f\K1+K!毑=Gt|K K51F>|y:,&K6k']7GYI-dz*2p6=އ8v;yǶN,Fm8oK?9I>'Ep <'X%L؟ 0gejMVɴsKJ|cT_2ٶ қZ u%&>saeM"Ph~٬k"'le(olp~#CAm*vZa}{2rϴf䄨$j2#/vBǨI-Wؕ‹2A59wrufDxH}wOuT8j@M!/'tw9DZ_8ru#XӲu"7!> pOdL6K"v Z\KȪsZQp3ފMRV5lwrɲHl7GqIzJJiŽ̞]gwwpe-yJ7QfdZ~cHKoExZ~0Z@:#~3Yo)l 9W?ØO2'M˨A w-&&e95=ҡ/F:iC0|iF+0_o5d ])JԓZD67.r%wE4fc~37{L% 7\]#gФ+@KD㡂o{n<9]#?,W71}=8·NI *G9oxMm)4gY`V |AS- o5~_/Vcvk9r9VR^,:o;)Z*5'4QG֫-H|˅=lJxHD؄jo؀H"]|ĴTIi8h(ǚ K9"nɥ܂_W+HMΉ#)4V7ͨtH`?H5u݉>|{>g‚^hHvt7|pW㝻QsxEݜW߿L60N^ܘȗh/~ur]aŷ񝌤ӻ1 #XLeP%=U Z6 \ւPR52%l&n"2>dgGhm^Ʌ*a{rkT4r]83[21,hHIrխ߻jh.98G3 sF*8pr7YdpVݠ*x6Iġ@/3p4t ,e(eEX.MPŁ.6йzN ]V&a]GB_V-17_^᡻'nspײ$rj==@GQb;Q:EgR{ζ*dY2keҴ~+py;⊘Izftӫq EGru7~%h υ]zwq:KCH&$%93,ޮSƉ_n8.U5m4o+!#%8˲B9c:c!<(vk\J7(O/_(ΖYLt&lVtTaPcL/sN-&X k0<"s&~~)eT3- >6|ْBo=~ /*Y3Oex}8?;n.VU<{o.k]D> M0kpHJG5 N"_M%$G@hKX$xN,KaBY)bXcrƟ*ԷY޸bƺaݾ+秗{\OAr9:r'kc초DpdDvM^ڮ&.~w0K$2C9w-&Я[Sf~ݛpH|2c咧.xɘմbu#immؔ}uIsBvES #O7b#!H]N1D7'/"@Q|v;6"<.A49x5"~FWm FE{7_o0:sj:Egclk.g^o¥0~fH|G#LI, C\pA(FǼϮn bN ۔ +ss1>E&dE@}LT %YAB2WLɗ`\ a*K=a4ϮH^`z6l޴c>i+ѵU%;y6ZBJB 7?.O3P>ſH tJae/e[(r$H+K1ۣw1uK]^_6j GICF-rVNF؃?-/.$=MWS{OH(sȈGI60}̄گ{wG}Ö&&^hFB,lx_F(f:;-N{=6akUvw d߯Lj9c{{w;|ȇ[x5ZK̄Xx*Г~4١ lke]4-ّjᛌ?lŗSTA~Ăiu*v 5P tzej^̄0 0 ݃,WRnǙ%Iݖ#= Fϭ-$s8L,,9n^ojJ'24B( BuU )Nx}LW&jSH;kU3XIHL|52JU'm7e֔vc.4`t^^f~3OuCpUts(:n)LDJVKTE]ͤd9$3 L]]e(;{&6#bmg-ta2OVYF p b:V{N ny|-ͅb\^p^ݔ47cnXka-׀#mWz):JLmu:%;zT9Ƌ֘xtqem ~9maT<&x8;k~AٰDRFSylzUq}d+)ʵ_hxv~{ޫ7=ꧫ9/TQf #j1n61I&^]*zUí;N[l9joĪ Nd)&29R[3GNyD漿dmD&69B[fsd9|^Ĝ` 6 ₮pY/2Mr@tO8GuB%g[/tfz[-2٠VJwp ~X#LIveyxQخy6;dQ[9gH,aI>,-)f,G©MFbe!$<کYFdHpB6FMd D@֗" 6}sUe<]GHy4p$؃O*[sY<> ڠPWyҴy.~y{bቬ 8xбD7x9B-2es9Y`2Žm1M;}Ѽw UeaWo_}4^+YE >xeξ:YUq|?h/0hj:.=u.9eL^Ci0:!-SPN7mnKZhVp'w@7 [ hj{SGJ+Ք+]-ƬyF9!+d6ˮlw=n mwn,vf(S 6 EYlbE& إ:׃B}熉)'׫wfx"g܅r1z,ɱȑNf t)#SӧkfLA%U) "mNq1Vp%ј՗uG`_4SE?75s 5lmjzmVq#'؏5mqA"Ƅ;][Uﬥ򳿇Rjj)4o?7 o4cPCDIl:uIpWz9gwšci{¿+n4S{s SJPfu-UJP|(A(|<:9(q3?(o|k@C1Ͼv2iҐ5aa10;*"aDd+IEpM8SovA(s5  HRyn<]&Mlʯr\()_:Zec<'"x0|)(d5 ot8[a3pFwz,Y'8 "Q-mtxdspA{O: -tܞʨmG--#kCvtku<*-_]ViީF:s4+O=+}Q8:蒲[c>9q[ΧC5 ;{vp\A[KrOdk7۝I9oIpT y=~vz64a' K$((g7Bw9*]!GR2_ 1@:#9N.+؍?Q+d*U+]ooy@VF7Q W6Tmo'x6pg97jE-lID`Ԁl%V*`Wఴ(\=J*Y0v&ʋHUyaYX8:?JJj_o@űFxkh`k#m0} ɿ{u6]ϸG v/̺v@Q?+ ΒV;e?g@^mMPLt]Q4Vz#wáTjjbg5&jI*3Bd˶w%uRTV:uF{z*H6ԋ 1Q0Z%OɟiKR5_cGZ.l40s<)IߤtkAIEL@LG^kz2֦H+ HdeR0gN'׀ؤMD`w.?(쒤]$43Yq^kzk<@p"s\8^F5^)5w*Yށ#t(>}\.Ԋ2/i)!t`$0QM[ĸifa|4sjPмt˵&B)%?uu5K>aJ(j+?8uj,€(HgvqGUsQ%(TPwG,Yp>d/?ej"mK]Gvl܀եZ{[s?FkԱ2/W^5kH+aF#7. ޓhKyvVsNWHM$ub/fK vĈn*AH)6\4bm;4?cؚ"H%~ɨY.=O)N'vu 8c j2 ʳ%IX `:͜de!j 3mQf[| 9nz~pxx% Żcŷx=NjN> "+Ի:jN O_|Hą(ѠD)z YlaL\Egjs[SnZ6`bD6j?$qn+:wfJZ3/q΋!*KxuvlSJON˵j>#v_h`v5!!"h,Դ(qdџ?ng-k%1[أN<-D{FLr/ePڎ: O8[L|U{z=214ߔ#!ՙQ{űe,#BР"/&"TwձlÀ2Vmq'w0'&BmkyJWrXaTH:m)Nɸ$<ϥVL=5 UW@Y.@Mf=n yĮ?ыǴzJbEП{EZ/wr@h{Mx+DDP 8|? xU;}r=!PYզkC-xrz%BrwT-w߇u-9ZM(u|;bSsK9"vl>_Q#E.Lg>z6"sQ Tywg" I@<|AM + O[;Qyj"T'n{ׂ YAzP "s+_cS_g@f0:XCq_d1?nwI>%BHt6?e2GL[*^fUr.xwVVJJgt|oFv+<+woVMSħ=丢|Et4Tjb|H ?W|v3ܩ!Vab ͏T\#pvW 6w2xz)CO2d*rDWD2246vfÿWެʛqPP !J!agvӥSq;B缊xIe ކfnˇ`/ƩP՘'. >I/V3xbV[VyvMm~ $//;#0A{gG\})jmZ@^q>[ p z:RUhn $Cz>;͆qSVCm͢=eyYW'pv$1h=Y֓%֫fkX^By+ZRGwU|;C{a.}Ka0T`Hᛳ'gGo8yBnlB>88iq9>YWUq|*;y69->&Q#Ĕ'|-6,,MDjFSg-B*F1rF}7eɳ2ރl&W WgqZƏ&r]vP @2hSq3^׭qč aV(Ӿ",ۼ{~{SSO]7'uIX$셧O jx~uKK#ĸ{I@Z2b%'ێ'xӸ'u)⑼b:gL}Ҿon@dvt,/B^8'ߣd Z4Čui蟃@kJtf=б:dIc{.&Kq fO:=;xw6AUNDzsWbhz4^k7 X97\lyqJPklG|@:k-'#=v%6nz@vN AQ>)WVE9,gjdF\*5XC9"H fiiY)Y9SBĒ{x'3UQTSDsiI"mNG0ʚ.k""O9A}$2H)z"G= xe{ޓɥ 8UVM&01+و$-B|YЂ]Q@OFa^Jq%s8Mչ 9bA<ͨy}}T^cZ@.q9+rd?䜕ٶLt((viR>&C]]Q>otQU!Xq:}-״q2oGZ-;, {O/||{Ր?}{zݩxvi-1iFiK`=,q7R# {C;ݮ`ѬRQ*rxiE Ƀn^dvf&l[Z}RⱢβϳ$$\BYӘt(!>3C\v߹ˑ ~"9p;Y<;RڄqO8j879qr[8W]g|r$&eF G} w}fƌlbBE|ϢaYdL_r|{{strK]e $A;VIe$c >b 5h \m&1+%lۺRM\܄2cUFcxqX.VXؙNQKJ PTp>OHnC~gq%Rl[ o;LUBasIӤ> r@uϛn/h2W|^5Y*:HzH%Pv# p-Wtx%f%)|fl̛>uu8g@7+j{ ̱Օg@-ċE:/:W $v%>ĥ2>{[C45шI7q` D@txAb/18i|ojݿBf{bF3:SxZ.askBj }9N 'pSU`XvbVphuēa*K-YN@RACͽu3&8qث,4{kSd(KRZS:/QXy{xm HYV.{RosBAfFP77vY=akCy&l9r)/KDEwe`r-jsl٘HJ a=ս\N(I5^U̙iەiΪj?]R9p˵V\=.KOFACGyp7MX+`n8R4W UFC$e@M f d;OB%]|nA@K42?h؂<_ۛydj${e-dBX0]ًa|uC-q +MKl"1(~$M3{nftTL lQsZ[s\0GE2H2 RF͛ybZ՛Xya;)>"l8 L2leی@Lx\C~>e-tU"GZFU?:tp볋sh믑8[es) eB,ad4 /(nxSgoƄhs6+eɒx7# xl2f|}j~ѡ$D㮤md5ϢRT ŌA'1|OQu뎪Xa7\|Z^o-ofE&QWcp6~zOk̨N䵈('N65m\`fjk/IP?{^<GӋwJ`[}$JQZ[x pҗlcjg 8Lډ(Dk S9Ȥ c%#R{8p93y(Ga .rJEbl`Κg6SR P$ZnWfRj8#.9}N?Ov ܁] _pF<7 z';MoM]O( Uh:!1'ѯ6ӛ-M Գo"w͐ Ɲh2t%&H mqShzutUA;Z)lM)3tQxm.bL}[ٞerw;\kɥ|u亍X-τADxY":{ܮ)Ӈt©aE} ur'W7$=~|zB>\\5~iG/EZC _qB"t9@"1  ) 4(Q 1)DWEӱiViRn$B-S5j$v(eJ? ]HNlZC|^L"5|aeW&Ý! $IDdP ̋ALf{U+2jy?_ptP-읪Ζ j8 t&IOƣ`Wanm8%j>|ڀy.c 3QLTXV1 <.|wWxㆿNۭ>yE+[%\n)XDzej9#mqg9 Kt*8VR,fk 9&DõM˽?((2 qOBjv8."Lf!^A \ni5o<^+{$lZ-vwªc%jq`!ld0 F H/E7~V/+]gEj0"d c} opoQ'k‰M$5~։i?V2LV*>VQ*:OZ沌HзnyYnz8,hU0Lh5h(0S蛬@8މ"84vJU"@k /J>NWxv0:L㧭Zq N"[GAUFfѺ:'OV4Z J׶B8usQxw FcRmXh&Jm/tzj@ӫZ408 b8/2>Wǃw.~VN?8hOx\]P:pC\p|ي7^&۬$4Cd0 yݭA^7(Myx~L UėI0\ c,h=ӯsy(H>nda!icc_wtׅTgZl7>j)6299lz{|P΋6Yx Ӣv1Gk3=:EyȜ%=,axU.#?n3(J?,ZKqϗ ޕ. c"^p :3"l.͜TC@AaRk˥s)~^= з6n< ɥ_,]׮o0pA`6"5Tl(oeREzpMD#g Z f2Sƃn*Zyav_Ln,G+KC3.5[X3 8Nj! -)r6 8aDLsa)*6oN p6rNphX G3t'p<`wQD œQe^*XTb֫`&q,q|gmxd|D*Bcf bD+7!fB+'HH7]oЁ+ 2b1'6oK\Q ] .: G9|8,X7ӟ+#M+aoP3ցz})Ÿ'RLa )t0צI#WvUh Y j" ٚj gYg1\t~@2x?i-DAȕ'DDswe6r~uV3Ub?Oʶ+_.'Edy;(pr MY@`HvlCZ@c/cHRTk%&+UN鄜kŚg.qCw\Z}W2EYϫίvgu]HIC^YH4]JDfvv $b8-r[i ,Z~J+&,h%)$Ű2ِD's$'E]:8VS0KQb0\<簚daIȤ+Ufi:n&v+AY, |nK ;@v S!vE h iUgތiKqODT3zPNٛ)Yߧf@d )tzI bS$Fa  b k y#R"GXQ]\ۮ*S\ď Q{J( W4OX w_Jfa: 6+6>y}orQAT=X`Ê%& N\`h>K #zy|ҹ-<4uqmf5oS=J -i5(z5ᰦF6 üʨ#o7۬SDj8'֘w]Mu=!x8]UvJ2 #Q JhSEwykݣ3ЪBlK7Z;4iʫ.h#Uj314uo {z5Ș]Ni<}eo2ՄCKS:{moֶRybZx6p~= W}-,դr]u^^[Yӝn0K2+^~ltw=%W}BoLs}ΓDR`ǎk:_Rno4µ+qD!kV8~\C{~(|6㋓SeR;ٽ=Ck#$rWƭ&ykN}A8Oy#s>cC t %qsp{P ?Oyih~:J<+@mw`uMHww/[?dKAaޕՃ#VϞ"-HŶpOVԿlh gru:dj JAjRgFC_Aݝڥ<-{ݦcZcN\uMH0!Ý|9!v> wRfDusSSNDq2-E??9Pz ZLkDy)x&W >a)'nNɭB婌x*ey޾|Z{-p䅻UPZr 4.E{gAI*+:4 (-lf"wR OhIl12Q ؅5hți]ekvJe{C{okD#A)G]''҆Eօ1(LތZTEuZ੼ 2PlTnJfNE>T_DwZӥf*G[tT0Yv{+=Eh0OS@káJվX(~@peb`ah_d?g7DczEwa?9'^(Ʊz+Y'c@ҸUpTLG7[Ƕi"n& wU"?;L˖oaaYaަWyw_Vb>;p̧e -R=Zs W%}瞫2;rsΘB $) #2/? cg]y%E`f@Y^gfIȨfZ٘ ?ɑ M}l;흽PT!c7SE,)ƂL]%PJU|:}Nojt!M"jܦ {Nq/寘O O E?bbCk.pLJL˔_H>'@ 8ٛIHEWD%Q§q]w7|Q>TH8\UZb_xmGE',|A޿2__ 馫pu鐗f=;$r7}Z$z^ݝMfꦽfn8^4fhysEjyw{|+ey9 -8tAJ7OHb> ¬-gAP@$+U}vGڬGء*AMS hlܤ6b ]USq=mz vC7I7s\!QYҘ97KΝS叁 Xs~M4k(7=MfNL)?I\5ԛ9rEul&f0+ͦ[%Y'6.MO3,9m2{rr ܀`* ^=23N;BSʼnz|FeZb j8mDj GDaԤk`,2<15ctxaM 73pC5̕"S2ڮ2_ FdHR?IՐ;4QSS)T0ei#9I FKMPL8:|2Cc$l&ط?\\B遰 HNVP XKdك݆09 ?L%x8 9d[^=KG+tF&@ȸ]oڬ3SVa0Q Nd:unat.!v(h5C" {O+8poD)1@DžimͺZ_;&Nh@N|G&nD,^-{=&;؃TjZ7fv!طˡ#eR`|Ft^\To3LHe3y\ˑʶ'َGyM4ʑD~jkbPHagӇ| I@>DhozMO Yx6pL7=Q]x* \@6Tou]#z0&:ytQOMƁ#/4[4͊EW(3TQ+{s ý+B'ċ>P,DN ;]Йϩa珄x,߹{3z;WoCBG/ PV-=v$#j59,PPVǎHulJY%2ӈ.]uJL7b%z蠟Bԡ?v}&bz H<~on0^i{r(BaȁPĦBә_Mu'"DCd|bRKX^Ju?y|4>X4l;|'¯#;@ejIHsj4Sa/50'[y)( xs=Y%鈳\euRE5NՑ賃1#4] Esj]6=^b<{z_Iu>L 9W7Sy5"S/gr2fd է(Hfɲ9WZWHi2civ; EQQ+Ι7IR*l1"o'~QZTCtFMHhd-G$Í?u NNW;ԱU <˰B41H6Cx4.skPN˼FAZ9eh^m0=|# ѷc,x.bDWӫub㹎x8  t-}~W T9e9Xn(^woRo  _g%/YMA1ǁH.0J[cP"`C¦m۰q&RCʄ$i!Ұa[09/;_, !Y]g? YwӸm^g U=RcZK;].IA=f`Wܬ*'J?R*v/]1HD9a>w,rདྷdSD5b^Cpھjk 3+TBa+F\do Lj:S^N\(ػ9j98Z61-80e2Ĝ,r; J#]CPPF@ w T? wQt<fh9_!4'sq¢TƋ&Jt#}>ˠ^Dt MHW%x 1n r̸fS:·ᵮ(6+:yfXFmlE;ǧHeHS~6"+:O~A"طGo8t(oYM B5\Iв@H2h>s 1waaVs).G^1qz, *xĝDO u+\tKS퀭RlڲS"kef, K!k4к}:DlcWY0-gdM ֲ߭ Scn1tQiU v|'i-Z6V /d&=``TҦ}O{ Yvܰc'|:mv2{JYllaYZJU~'e؈NDFÅ0|#NwXD}{lVEg MH-\9As>jfqu;x~UN|%9<}r=I?l"Zmcij}4 aɏ}XtfRI N 0 H2'/1>vZ UqRk%~$9Ep/e[S6yc=BE bD !Kq0v}G*{"$PCɕS58n&҅ǴT$7ǂ\ v}n\Va WF1>h6asIF%npFZU<ePoiM1F#r߱ʹi:F+#StXZ?~ A^e* s&$%Ҧ:&$j)\Wߩ>,d\ų 7LJ[UFYTx_8W`ɍ2!rOj23ġʗKě%Yﰿ#\/RoV=D^Ă~D0Pqq5/,u@$I{$8/N X?K#ca]~^7Ѥr̶JXU ZZ.XV 8$xVgzxaŋOݮv+(, ]k8hE"OZAÈG7O*X5ۖ|{>?e4p?9hw[= ?8;=_mB'dzky }/hϢz @Ŗ;Rآ0c=T($=K>g Lٗ6npޣRoneL롉+bPTGjrߋ8??<==<:Vh9 $Y?6YvDe+Kf ,0Zw_JD~/3=ɤi Dq,ȾiZ)l{e:c2\Y2ZN|̌$2FOEg#FAjIMO1迨!b9!Ih`[Dʴ뉊ĐU8 j(qOwRL_h)Um)J l隈:y!|6Rv1 #+:w`-%,AR$-@6'gY xNe$G?RܣemFJ?-*>e!2_w!#wD< iF^#6M ϘJ{Y>:-}moѓ( c ,_C+E:d++S0:ŮXW8Z*fNMBQF|ѱH=5+-Ix2CecZ!"op&?Ϧ;scH2! 5yV~%h~xB_!0<)dO+@vs-li8I=gpˑTElM =tj9Xxóe32m;އ"8ŸLLNiT dA/4}. Qnjv1#î4PR lJu0 Q_1Jo< U%4ӡ靵LmJM5dz;!`AKhKM'7В+=SN`}qwGϻ?-tW@g eMZ=80.4I RMPco9!,ZF=z^,}{H_Iqr$f%$)GzyiwxcqYNI_t:- +<|\78WxժPjU2w܄:Q/%-p8 5ff\-#^^/2?&/r[mjW%4ӎ \&<[[s3e5nt'&^%+ h\XV3Q0ӛ 慻/)?G0D)ӭxezYuMm:}%*I6Ұ8Y6KeĚnvm!,o3kͣU"qCCt qCM꜎D{&nqBL<q n\],L@|E`A?ӌQr:vm%M TӛϙzDl淋uI}3Mm' m˗Mr粊ِdW%3wnŭK nˍbyȿ$rYj0U"\XsqT ՞2!kZPĮK%*1z݊:~W 5ΌGEAw{>=ynRm^s= >l)]V4GcDi yT#{vh "3'we#M_R |if?oAYsYMh(\`ԧYcK5J,̿YㅱWxƕ'm2W)YtDsr Cq+jeZF0!;kzV& O]G d߯q($;Dc,|+gg@zL0 zJE3u6ΚYƅa텗_(e0 x0 'őL5ٖ.cѼg XR jXJCPr-/שO\&vh=G-@@\ub}S${ `QDrmgKW!.RaA'MⓆz;BBΣ A IJr $3z=W)U`CrޙP!qcҖ[ou6`f|S֋{|oJѢ]6'm3`09}ϋrG2qr5Q8m7}|;[f80Y5}6LD8* p`T5&P8sF"@3 "jXϸ > UR"X(*pA|.%%fw1'n\ +Ȼpd}! +(MAg콷w(L$ /-;g  ؎f?8Q7+.ڦpkHskdA E̬ 2n jH']K7/g}t틦HĩF1WZ @N$oNv/ΞC ="ߔS?ס۶B Wv w3B(s!K8!M[77 +`i},pa#l]:d{&&Pʚ$NnʲR}ѹ0e/}iⅩ [}Z]GQ~ǡ*ӧH?l2i)Mˍ"qܞs%N>oߞ^>|xv~-CUa~ީ!!U2h:Z"^T>tdSr=;v8tf(ŨLY}IWw=?jKkF-5'JJJ7ė0.g!Q(:G2ae;6kf'kE|C!ܻ÷.(NG4I 雭m:3sar=ÿZpw kT-& `FH2h*OW3#9UxmjMwR6ƈN @vUNҊb<HkH8!8\ q`-X1Ԩ}w1RI;J.} ޱ@.mY4=#߫\{FH*t8Oc^r%8a8anI0yI~u8vª۽ȽO0a!/A " Yw_٬Rko8U>wZCV e(F8<%{ƥ? l;svLz(^3y9|[Vq>W~ 'Aؗ68%K>+ zGh1O9y̡L n޶dqmvHU,yۣM[y4n`gy1h{b'+>N3֒Oo:#l tC9R8j$w [HMEh~&/3Gb-vOr>̇WG_e(\^$l.J{ Bc.I8t5gIftDYMt012JjN.e?_n{0_q*+W M7ez2δFH.NJfCV&j=L[RʯcU,W *(uKKws8)vn8,)Fe#.a[bE_ =F؞j0U {m`e}5IKn&?8@ZJ@4WD[9Ŀ.gK%k<.Vr#GhnEHoI:F-# 2 OZ3ǧy2LPsQ}Z]r~+` P6NyE]mi#jFJ=OY9j[ћۋS{秿_&;T!!'vc'vCwxzvwSu[)Nޞ_\}:1%( ?cCSϓizV\ N޼}wӣnVӉ f`-qT*fc_{a3E1 Yo#;Y 'X>7cV MjNUR/|,ZMki\, 6T~{Zri5Cw*f1?@JdQWE?.i.n]"pC/?q z5kL]|83u5>Շ LM9m<{Of(~z[^Uu|yDWtL O'(D=h%(G5g0QCP9[G3@+t3VVs4$MIa3޲dS߻8*0М( يDΆ&$&!qS}9n_\x1񗖹KL=T^ .+tō``uل}"f|GtGFz㐈,cWD{X.jpA `P d4<ݮ<ěݯy5|o&3{Np<,gS'{Ffeq#2W$u"],oyx#o<9se3^t) A./{?)SEd8X )s0bI3(yQS}۽~4-!pLF@$blqV3GNbD6NT.eTuzj~,竒"3xvo;_7 gCyfMN39wY|IQ:&H%o[)ѤC{&]-9߫JI&\'(!c=ƿYE&oi 0{耢kdwjeӓ~ʰuL:,qBغ;7E %p3&vYS^z~t8`i ? Vt 8!rL /+gt>Í$T/FW}.,D h/~2R IUNէCQ\zhCFO$k`S&J[Kcڤ Q" DZ9"Y(DC`QLɃ` M5$̹3-.ŷ8[  N"L"Oc%p|g0\2'\rR`'gpP?'['/1 3{"'6n=}ji&4r.W*Y8s@mHoBoW!2 4M Dp<{eF( z$|uK>;4vaq _ې"$fFFƹw;(N~dV5K:;}2)p7MkuxIؒSAkjM'b[VԚґN<]{ 0ߐE 12%/a8)-q}ACJy緷ZUoj$eߚNm%Úx x{[XL.H9[~0V3pNlxᛖK_IU}TڪghMGTHSb> !<9U\"ծ6'YKOShoc7L\~ɅV'g%|sdf6_3L; #cLϓ!BH^y-( Gd9 $T)EC8u(#'ƫ<6=C{xJ_ľ"Ӽtma.:FU D:Y\2@;o;cVbug,+r{햧PSFM5|RN8ǻ&kbOǬ(*gQ$~lLdv(%ֲ$NI%6 D*_Y](($KGX0(8 Ts Greq;u5P⌐z a:J[UgÉP-l?v:s;6$,]^6U nʹy(KY%j8Ui ]/("rkldx.Z;,6>< a2)Su]0z`zldx;(35$J+d@\܄rZB-EZҚibj娿,0ׄaANx5@oH28;5Ƿi6N)N : XII_4{{aSZB.d>!ͤYI|Bixpo f~4VQ|@&V|Y7mhCĚhXjӀ!.5PޓSZI~:Jә.\}{&{1y%v2aFTj&^A^*!" t0%q\ڕm#8wE|E.,,, AftdrO]= Xj{CIo6"0 hMз0e5m`f-hFY|V7M `s:eƾ U<| 2a[WnH@ K'ʽew2Wg=5 JԚdZjIH=6Mu^V$5csc!,I*ų`R#Io ;O]3OT򢮂#ڄ0v\`A9pi!rTDE1Jh/଻_[KT$~pԋ Gx(c$}[6W@(ܜgo&[+Љ-kr8./XHa -A^r] =_D>ЖOv]vNά9\PQ 2{ɤA=blJ5ôӏndV$-xz[P}{ &2LZ, VA\+/O)g#,),T"f&VIp,j7<2(.Gcq\{P9 FEƊT(Oj+c Nx%_f7ȩOpxe}s:^D{&7+q sѓ%ϖfMTH@q{Cnʍ\ZU|(<0îrYD hԥ[p -`yu#rW._~۾BThQ@͑c-[0zn'Nt3!~ft^7;1Hʹ>Jnb3kZ@67[!\5WrEG̅H{L"SG9JCso*=fe }aau%?8ԱhӫWv6||ޭ2[v@raN )뾖* |7aPZA0 +JFa R Ao""3 CLHgo89,}V_^0KYsvWsUs1po/#?򖰩#2%o WӺv^I>akn%PظX|ҽi55= _WO>r4OujE~ZђЩ^cd=И4ԞHm3?]"5`7ٶI`3GAf_?qnf 3PJ-ҧL? "~PB33d)GD[j]Ď:dB-ܿ݀wCF%6+)E?G>&QPNK(ޚ>KnEc(2x؅2YJG@Sij®93 H%'f )b! ˋwm/!Y_CXt!n1(O޼=;?OUQ9nj<.yۗiu^h)|AX'_\U$&|boJx.Z预'aOx~yz05BLf:>д$Gq%SOj >UL"b9&* l=-`>r @.[\hٓR\4ŎoXb{Z̗tU5#YAcEhTJiLÒh/L G8HV%gՎfP k;,2{1pJfcnd Ba %l4v3l#NwQԕT llϬY[7Z_+h 6{@Nީ.rB8_5T%O6Z{{ӜqG9c.",#/~f-cbا`.KNmZ2?+& 65GƏzu_9yT !>M{%[3HiO@%d-dL4j7JuG_g#]xs#ų%SƘd-ΣCcD)\)gie)Ѻ91!ޙz `T@ޡg5M4pvpqB^>9|!ŵI>PbCMbfQ:g@D_IEeP rci#b-]#N9ckkJ=Z V}8a.CM48T 1b#:a_Z`],}|'BtӒXXh&ڧRPh/" w0aدD!g6Wnzi.ڗ1&L'V)9ϑ1gON8pq]DOgD.1ᯫ(ju#A&Ġ*Sk2TͷdR'Q1xC}\AEׂ%~x3V3xٔ+\}U6`E7HZyqVt3*9C-ACΔfS3ZF@@!͏Ʋ[CMm_Htr|d守P\>tOMY>vrY9Nq"C!"e{x'5\f;wO#@ |S wZMx$n |EFH 1J;rQBkI0W0gsukeJB:;!S]CA)VՋM%ne>8BŦ{$kJh2Nɑ(Z\!'ˁ.i6Gp}cE*iqWH,<6ۍ@Ly㢈,킊kE|bu:U\G z >*k{se~k%W V!`D:eF' <%"c)j.CmTNaVLKQ %Bf{zW'f:p;\SD;^"E91_*%`sxX,d^) ;dci,`J`:I hfU ByCH).(eQ˖-")4cG+>Kz :,sA d7XlńD=S*NRYZ0@/ajQ8uWV2li਌ndhSn?( ׺Oi ıA &0p@PǗ Gvy0h$eAZ -%~uz< hnF3m.iVN\{~oe>.E3Z/ )8` p(|T\.B5)VhR;ӱ+72Mn\>ЁO֔>(N>yt&.[T"{Z`-YY&h)~i>(W|JW1AI$nC[ه?5r@b;'^ISΊ_گ|E 1쭿.OSZ|ݬ!0B[K A1˥\(_) CeNlEgɞ¨Ķm90 a~XH6;[ 2^i L7N\{yw(šW)RE-Sb6^5ahbȞn(lv!br)]gK@#l>Mg~Khn/P6pf{OqX%˺>,\#DZMMb)ӳ6Q͗E6m I oh/zIytYa<_cK*%NSfڳ# 6aVv;8(_6sWޘ3;Rd] jCNF[3k} ͺq%2 qgl,@:]~Uǝby2El7(Rh2ZC,;5F_M YGdC?pxs^?鄂rE5Ze ,ȜQ{ܤv_"F/C%AHoHFFK rIrN63m2߬ 9֏4-;11bdf^1)#j'X7Ҝ8y!߉լ ծ{&whAJ_R%2Zn훂w,Y 6y[|şIAzw4û<'o'_$=;]J?UZ^< yx˔KlSZPL&z03'婵 -ZwѸ p^`-(͇Qw(:QsDe>(Q*M\q&Gs>p"pqIRL^+?WG5Zlbg*p`/lZXiчު3S $ yߠI:P߾CFțXV@%IEQ2Bɗmzom&5rS2r mx5+U ϛ=UcC Wp Wip^n_>NF:. ,->R0oH @+CӫmzZ^UEsCp# Q)O:| ~uGgc0WrtfCF(K>"mUBO=g]q<i/#gOՏ8Kڏ*kjQ81l^d|3%LpZ'ÓrPʖa#o`/DT 臱EHRxP5L<8"Kad,Wޒ1=S .&j|GV OLX 5L̹qƱKCȽH-K*K21*xIàD>ɎHdlhyK;l01@t30LR:c̗ck$z WҥjP=>&w5CZ|Oy?+~ntMDNڻ)r[C( z-- S\x7~o񛫓gKmd _x>8ዧyZqu ޺FGFNF@kkyZ$L" n^\2ZR#P ;r@O܀qhkR41ۈj6&5iH7:/,I̳@Pj9ڱ.e:6r0V5IbV\ͥ* Lx2 :J$9S?~^g?LsuZw#Zvk=J0\%fՕ> P27enE.VyM8! &,.GDZ܉<=P0)Ne4h!rCknab8#o0f^I8'?`LP.t&cP$i0Nf(lcrlDU'<:TغGAyjTw@rˊ_ɫP# a欅+耻AMc<'jQ!EgbC%Lql{,"3 LGdc4/\D v%siY^YD[:`rp֫!⯶Cl; t؝;3VA@Y}N;I,v\$PLn/t8&s XM IiYX{!6ޣȗj:`2gyqLJ3cJsx[Q&voXnW<=-â)1*jʲ?7Ϛ&8ɝǬ ޗ=9ӿi$1)fUL@Z%Ʒm!~EzBzQfzPN?E7g'A/L,[Nܲ ւd@8m)/7ٞ^mg%PfLjx7ݝÝ!~Ul酶7M|4:8*|TQ4HEbr{O ;@ɶ&'[`'|cry\&-Gy=%G(^>v))K]3wo909K\n7Q V;nXK'Dfq.?)9xtxf.g h^o(ֺ'FEx}P/KފW#r*?jDMVr9P3ݧP@@x<NžT'6dW w5^ꃐ%]__JD:b^Mp9-Ffݥusyp(,[S_4]-ZlkS@[+GWK.&;+w+& wh֗)-lsԼ/{: .eW*-r-LJ:(jȷbl՞aضoF~4]MFz'Z[9fp'C'xqIX$Ns+G)0rrˬv![u-\ؚc)4^D$ U=*%rLz04Ipp"а@x+w2بԑH\L-CSEoe\ŀguwKu,RlH>t-3*‡31ӡH`UwX ۿT=@j"l0@fM7`dA3+K! ^ ²FCTl'y݌~?BWtcn7'oRݫdF_%ϬI'vl R a53*Pr>Y2>FXc1H\%-mMURDtNsS92}JLJmxdM:m^/R)IMjFʷ>U$y />"J2{t5ē}kr$McӾol[NKy,(֤M?%U탭@r  (H}Ep,9X bOu0=O2}ҭ6`|zyٰRC :>I!4qdxMUswJ0L˯=/-Y>J@Y4mVʔ╭ovYps{t7SiE"!s1-YEUW% eFЮDd.-KXzqE|U#hKl^Y#L^(ONN|AfZ#5,=a0H8;۶ ~b\: +Z/iéR&w)3a9W0adJn]i%1<=:\Ϯê{E6 DgwMCydgE#LOǷW)Ĉ'nڼk qi8i» y9LML[Ԛflru>;-hyM>?ײc"fLV=р@$p&PfYwn~$/Y*#ejە&hV< tA2F d5c1Zic~j`#+YҫW=XNR/ڮ D娱YZrG,sc[囉vt*S؎0x.V۶woanFG-:|-סNcKoW3R2 PhE0k"E&JyŒɨTF^q y}75]a̰DZ r6|siۙv O:R @ҝvQ4  X027'Q,STŽŽwULkW\XR۽4m^u.ր [a%t{Gا:Ѣu`4G>l2@z`'{B.e!]rǹNgzN7I &$u5 t %N1FW7hӶsq8EFcy2q&c̖ )^Xc$ $[=F-oVqδɂl(F0F+ҥo`c4\+z k3SӞln[u%Jh&Cm=UagNke%W>2 Ta5U4 5VN?_VCj$A{8imد'o { cō:,G07;4-/b)l! 'n7< `!2G;:!rxf>D tWWN@+v^Lc3Cr]z~;u!JuLh"B`RYx 2R_ xY]6Ap(t'ʒȣ (2eZk/>Q/\] !tBbC&Jd1R \x.UroS#| ^kXfg#馱2u[aq$S0ߗg/9%Y;QRHC=rS/c'_cvh\@&I|{J3!;?NebV!&X(`=̥S6]8/0$b&f WMpmfWq{=miX/ k-&.єh &w71_rhQ[]qF'-ߠX5ާvu%9mFm#^aEx+ʶ xmAmtd!"j;??ݣs&TإEs6C>M\9dI ujGWggWZ4a઒>9C"Az4zpyv~}}GH>F/߮ȉCоU3d9(m4m.0F&WNsh2bcC}̸}j܀_GuQԮxEt8G*~#DTw=qaqxҋ WUL=pLƛe=,L![<ȍR+1k9\{_:SkJLnփhYi(}&0{I|yrC 'D9v(0EN8k:TeN)k 4mM:S47u5jNl=:6-g[ph&Ȇ•qU!,0𡢗B"Ht&/ H@ ^?J M쉼d9ɎsTop'f٣j]{p&e,alƓbr`IK 1/:TQeOuRd8 ,&.29(I7*:w4ENED"*.%jqԣC@1Kr˄(Mn心H۰`I+%Iڥ .V-qjXy?#`Œ1󋣏? Uqru$e0⒟mud‡ϪW Vx1̃$,~?rD'X!4ǡ|SId>Ed8Gi5'6(#oCy0Lء}"~@N0Pa$(w(> 2 ZOj8S\zz(X9gK)z7=ijA> 1ϒ8$LO_Sd:D[[smBAuܞ2uQMD6,FPP_FjzB XK1SR-([Xcʘ bN(ʼn/&G9kD܉4x/.J9ɮ;F-bu,NMD\ ՘PawKpf( -%: 4H9OPRqW~nԶ}a{,4I<_Yaa>+86II0%s};,Y 7^\d,2N>wzmN)R(a52:v}&΍0?I--Zp$c$6t[-ItzJh X&&Mh\ $c!݆aFʊ;Qo†-(|Nbielb#[[Yg,t=@]@>kSxs/woc 71Yt5cdžz{.Fn;JK\\jK$&&tfX+F}F&Jr gY+nchd%viXA MRHA%, ~0'*4T?{ONx/l`ֳ9oE>'dҍOrc {ѐ%%gv ň`X%zr\O4 owүNy M*璅 u+8/_% $Jg0 tBB%^J2^;aãoN8;?9=~wk~>?=? )Mr+?+&d^V|*rxj@eUr>&B|vNJǝ9YlO*p2ҡ尅CWhQ3?L@Zgʍ RP&&[T||$X/}I [zņ{GI`/D#1!䫼߅8rnJf>c,_ ק>_8Rru$P}Z)ȇ;Cw֡Yb62c+' Gg&+?[CEDB}5ۡDH$Ax ɬ޶&Idm@kև1Vb7IgMy[}?)jA16YQKҽ(ݵ!^ESCg02s@ Z7Nㆋ6@f55[蝉gobJ8~ㅙ7;qBNi?m,guC씖4M!a,+F5aݯGaVKJS?.,~moɮ奮>_}G_"'IՔϯُ 7 ۵N%Ek(^Ji{({F'4h͟5d׃elm(75TeD]CZjrԯm] <?.٠3(Qz ֆ0InOg=g\7頯KDH=?" :+zlt4)iKi@A}]9[:~sv+!eQz[g/&S>mu g 'kڿpUx_.ȽTJx c@W(B" Y#lz zm5Vb/˅QhXr0CVRqf~Oz`qyDH^bQcL:zd?awPȈn1% ;a䗐$~uJ[_0Y/e~թڜr9~D ~T5`_kKmqv;|MKO,3̠qd҉DAuc \J?TQݭHD'wRU?_ I| N6; s0ʣ֥K[fY&]Q7b6f\c Ordȭa F%c^qt5Ld˪@ eq|xwt-|yӓ?_&_3}EX>b&k%^x ~E8StɊAI]_a.\]_%#r͒Қ|#t@b9XC#jPeCp)K 9:$(3*L <6]dzj'Ѿ[㧎?<НP1Zz,T{6kAR!EEQl`3Ƥ釩'-/[DEK@pNOW{% ;{}W U靿hP)L~mY.1GC/zv{kpNg^A #"䮬P.^6AFvd# %B9 @,ް3gc40e6n en@]/_x#]!L YVyX[De;\n;Ʌxn©`bO,.m;#'Tc?)e@UVF9(yZH<@&_EvTWRZiE6<@R'QDTU6.x̦CJ]zaU\t?~@Njw?<\r|^wx[V*L܉Z62All\g:\(?\&iHCHD[g3!eT`o&))jB4'_nE?Rfy7nS vg)׊_6/$WӃ1t'j*esEd.f1D`RNf Ubl)w. _w - Fh>*~N~,I eP+%d"ATy#h} }eD?E.RJ2KȆHi)T}DG:r ( }jW RbqKUCۙsrBz@[V Mg>6W'7Dc Z)z'`Og>^imjQ FfrwODڬ>3E2 K2)0{jEGI3ySN8ʨ1k>a* +IjI'鰶9&RɈJ> o-afqROn\Cď^8uR:h$s,Fv/| M_86寃wg?egNU R0d$ј0L =* N5>nu7mMp|&vˤ\ R!E_t#3<-Dw҃-Kń0@je{217]N.*iQkl2_ȋ%?Z.gPR JUxׁ%bCPi2C;/Fa&F.=!sbZ^plCedOܽ(|)~iFSՕd l{ߜ]w D$ؒ2ԑ{Lr)]6KXwKM;@N"'$dB=Mm<؟)N/3(ߑ3te$N8b-H@q;~csf*8it$#=(%7ȿ}iXAov7D8R[hd"hi)_\ &8ۀBTapr J %C‰q["k#؋J†W ?^N*M)uSd2BAvq39dsLom嶶LQd|"S{\AW@zT_yNȿ4nl ɣD|<]W[#MB*H [*qLGKg> EEܦMf,}3OqzTk98DYZjq5 G箶>Gj3(!(^#٣^فCӔ c"!N2Oc]S`v,h`O dOĴ*FN5!emݞIK̜$*Hxj*5zP;t4dPן) `Vkڢ|]|+7=*i)Y86+GQR;a}zSEl*gh5Vk涯24b:Dwx^O:t ;:)C\:)(3MfRl6iAyk5њ#| (X,2lh6q*}/Cu]w89G{ T(*QQ%"6O{@&ơՠv8q.q Jz"q8i G|UzZfd lMwreq  b\{tH|  FڠIBlց:;[bzcWۉȦl{BpH3$=˟ ^dHFuOQK*8Z&Z, / 9)(B I*XofNU")~@ѼS _;ԧl"=dˑl~9Yǃƃ߰n}Bh/"G5kG(9}r R-("QDNdZ*_YgQQ<)q: -1 &gBGKv%#)G As"CE!uy fJm\=)o`7<k*Hv_zS&fNFg;^J7GVSDShlsQYpP|Yao=J-X/62ׂACeLkj '`H|!.zp(0_4}_E>l$@3Lă}g z&g+ {Ute1[zϕh=)[ %|/1^Ҷ6OƤ)7' LhBRM_|XpނIr =G{@j#?|SRRg@%dDeJR"IIo^\ {49b<^"s^OrԤM"%aFcO$=u=INi*na$Ced.AxNkz|m$!z-cA"("Xn Pl9cC7o3 o5}ފxfZ#8O-J5 B1;}z1Z_[uߪa|xҍMV:֒}$mXRcZkLrQ+І:er  ~$+|skj= 7J¦V >Hr}I$qJ _ o *`ʭR O+{ %҈4"IPӷCrm)M? t5@h *;Tj]įuTao+<{KS}M&)7rOZ!lSǙS>bBwYsu3ZlKǭvY֛X\=`1la .-H#[@K[,-$(Lly1S` @EC7`;&8f. QP8R~^X4xbV;wur>>`jf%RE$ 芦g&g?ދ>I_JyQ^XQ^2Oyyj͐øBx"Q0%ţ= T]y ϐSp6IORXNͩHxC, Y Ȅ +7FM3H},to]\Rpk$"lz(76o=岙b!vIDYXzj#Ǖlϝw6Cd_kxC*Pq Tl՗ 탣rR[ʽ1bN勄{+K/\H%X~>],KvjW¼ζl٨Dcj_8d#CDΗ9~1sS f,03'fS9NZ¤)aj+MRXժ e}qNcDrP=zTz㿛Q3w_x2kfӿ?\_o7y:me;€شsߨ%jx\櫲4څT&uy McOeM`ٓW}ɚ%&8w{NJ" ,2||jkiPsINk6tK5cSPP8岬_#e]KX!ib- <'l:BVo/3ɉ)+d2|5!ΒxJl֪$JYxX83z;dU pV39-մI%jdǾb`:ճ60),|4X Z:it**oӞieǩ޿MXUu{#y~$`#Av\MHXMDgJm;'Rk)5RUƄv( иJZ8|Y!zl}.[@}ZFE9P3Cm(䅈K0(m;9KzQЦ70Fbm:%rV8*zz)ˁ>,N {jg:N/Hnzo:mOh)4vsWTNI1-5?Nx b,qDw*)@ ]:31cWb'&)a띘!)~LG d#Bqu~O< J:- *S}lc`sL\ە6`_O -kGW~>Xo]KwV;B0;Pp.b؍_"mhbJ3*,JfKԿ}6x]b3o0>< W[[#u H!T`׀+0۹5.O8#ScI˴2z%mm啮W:nCE`BNJ,Yib)할aegF0xeu;R%'|`!q9Lf2K`aqiI%Uf "]C?PMߪ4n[a38K9-ɝNY12烩%[A35G(yJy[cZQVҩpoݰfbn=s~9j Ÿ2^t4Wڤ*@5MW*n<|)ׄ[m)e:|˒:*dJ>VNrtQỐʯ<;n7k+aCPjH yBaIx<`erR{o0WȻМN1 tAݼD:IѢ! p &_2'h:WQOʥ/i1PnӝM'HO]2F#0G4(b舃B0Owh蘉py?BZUV #q SSST_t0Q }"=B-jn]fҕ3D/fMM q䑏Oj;r߈iY|z mLO\J~H2d5$3: @Wˌ{+8x3V  RE.54*K2RxG[B Z/t@aư <7A:hx vJfA+21fT6GˠY ;Zwf.}m#_=$߁fYc },sd2B2xm$dߪn[m{w`,u?}ﮪK\^VW?Ks6NxJR<+R/uvI 3d ;>pXv ʡv2zfMVWj|}pxk\LA᷀T =,fI*WEr i;{.{}~'sܧ‘Ik TjiW*/JJHRlKHls}:>~V.fzVo6XrJ{XEFҤ@o }/cus5XWg| ~^@ 5 esx6Cy]Ƶ>K@Ϝ|nb>1 %f @ PB yHHdIn*J9Ya I7 6>$hYϲ#|Y-fD_@RL)& U Y\#'BjRГbZvOw!rI-K_Orʻ+i–wS4|@=HZ]TS=kjy<\0[3%GG|*I37mXb _"5eKw-%z//k Z5o ߱eCf~j?XyQKߧdSmLSFɃֆٷr\.`䰈q_"oc;@m{M:G3@AtGDgG˃[@kW v4v`w9k n,Y ~i*+{\;]&( |j sXzΤ 3Dؼug=<+U0]]"iP6Q9<p;-t1dǓzsEo1=}Vo\ȌA1JrWe%{"G3xaq3#aG~QDm3Kη{4crPĎÈ,?u^O CD3te0Cr-BbZNĖ;yXۯэ|P|Uv"SbV<(d*9XgתJp(Nί~&o"zΨOvϛ/' DWoV)rx}9p(|Ӭf|(‹buIZ?.ҍ7Jj1@#i:[E ca3h} J}, %sPQ#|S|') uu :E^hL wu?nDeln?}E1;2mQGl ?ND~BKEyFW!"ya@PoPO,*yHB_C]㍔5 H(;HԮV0UB"rz2qRJ7*&LtI,]j#tzwS3=MNQ?MsE2po=*5GwH) \3X 86%^lq>XS$3}`齼JcA)gWW$2\c IJGʛpR!9P9PUբC>O%K睢9-Iː?_=t5⃧*aj n7L0 B Pfk)u1>踆u@@>Gs&xgCJSTSo`T`:rחt+$|4Bfۣ օs3"ꚇ2wLG`8>kTJE8C`?]Q0Vcr!oy:}Kw 2( oӁ7B?@A|R[2yU2 $% ˩gO#&@:0M|hv+.Ux>)5oE6(v J L WsU$y]tټLGQ <>yF{"\ vKxOG*nE866J`Lxp"7x褥TH͹(A@JF| :kFG+KY pCDzE>d0t0qBx2(q@]mY]+Y-V:5(NrdaGS{6~"8d!1fNmoxos lhK-R{j@5u= (w{wtAȬ; GcQA~Su rdU̖ɵmWJ?%⠌}"xRe Dtɴu$J9L<+簀&])V Lm%Oog}ᗧz\^ҥY5K D@}N5LMXIuvpsĵDw~zsYq;X_3c3j#tB=ls›\(#nSESf:@<`H}Vvא4tM%3$u _8<䰳T&P&#ky$!\/P`\Cw&U)WLז4Xeޡ% FZK1<(8G3aAM9rrljXĆL qUdmw7Շsr.'z+pp6#*gڡr8:"5&I-_mz!@^(&[r;c~6g i{|La׈'}nZyK'Ȍ;~l׾NtE~n{GB3<W%G(M 8tg/?¸0{\`Lw[ _J/(m!iI1fh$EȲ<Ra[³4'":\h끉lXŋ(: 9l{űfh Jz_8ee/WMpz/܎\|CV>y2T#],4 Жenh[IzIzןrGʃ=yR3Kӓȃ7{R4e҉ Ц>n~b(w~e3.W& /B$8c4o=I|vքNh:1\1_u X$uÑ$ ,Ix}N(LG-*\Z&r]kLVKW%_ NxjWy2AW:+LU ӑ $ Q?Gq:g'>BeMf5/2*ZzEE/:)n ^&om٭+H*Pn8mvzf+ra(2g,TGSgܑm^rU{Ehn@shQ2 9<^8=Sсz0) !ݯ|Yל#˰?{mox ,js9(=s#wB>>wä'\s%Q,ܹYBQB6Oz݈S Y_6v7dxTZ:wT^,vzLxZhPhJ#Wl*%ݙt|*T=ջF{1, Kt7Sz= _ǍtՀ wC1ҷOlw[ '~|AyG֊ qjCIo<#7'۸(+mwX㪬%y?Dܯ+Ћ:nWWWH9_{rzbfIK8S&skqE+^[[}P=IQCfbx4۷r,יL}'9kr>Կrqq>K={CyDQ+.[r3EWK&Wfh"`3y έ;L!)7"~~f#ZhQGXP*j^uHn{| 9v +w"Ʀ]KQQ?Tr(6wiH%lp44M@J>24Σʊz|~n'Խ7y;ϳB"b9ppz\`w،T=Xw [mR'ˍf$,*|{װ,Ov&W\%$L}kc;N鯫e1 c IE]>wJOX.xkUxj/]5Ê<G;4:Cԧ`>*[ϱ$z4R-*@zbjQa2DBaUR䌽v]LIW0%`k }JG0E<S8 ؃q6xG@;4|tE[9zM\]YZ^HH?d{9BiD@ j};ȕ֜ '߷ {ww~ߣBr /7{7>+ww ߷?sP~/d1,7.Lc'!k _]'G̞Snhl:9{vݪ¶R(=~pYw<@zSve/{ݬnl!z2t 'fnHhySQ u\U)zR\Mk6wgS8/Kv2p< _n]5$E$}3}p4i2=nEWcH`tA9t<ٺq1XdN^3jlb Vi:F~fJ y ]ֻ1N*Bfq^7O(cݨ:fgFz _+GFzi&̎z5[̸0]f`za0` Gfj؁vjwMAj)D*g-^Vf J@LA;3kLi@1nsCAej@v RCN+4N02E=7EVM,uEaL4|PxKS@GUh2k 28#2=0o)Ѱ s4Tta)Vf*xoU27q4TÆ3쩍=hijѺOi>J"5nԛW* pV-&䒫H%FaFZvB=1@H^4'deF¸7ZF슶$+" 9(G<@rmq+ode0=)]laڟtp`s̸NQuQC=e]$ #m&_`c'2{t(I2]Y:sMYq]NцrwG ]bhhڻǭzT8nz\oV q+@``MD2jǼ "֭7eIƸW+*ymnJ^FykY6GԃɈ2d ove"]P2=(scd`}eGJosc"8F6j{ AF Ni:ٶyƯɴ¶yF9",Bw /6{tp8:Q]Z|Q`b|U OX{Wm?rtFnێo,\R@p>cH޺TCkϹF5 :"Y\`8QuyuKy9f4rxfVci& "<Y} )mXs4)pY]G=P:϶Z]4RFj,BYpUrRҷVD0I!'\aO" Q,;UJժ QbXi[H.bNMN[='x҂F˪jZNJkr&Y,luaFuzc&y_'^ܧ7szG&cri}&<ӶgO  zD%J8ն(šuud 4c{ua)g`7`{\kVoXWƂsgg'^$ThfM@6e lF挠}hrL܀M: DUm8G@O3=MYQsɁ# 98?m$=3!cj#O{tɩ4)&?`xt0V|Ό#ηIYgUM_P֪)גJ[KV1!S?/jtdpE7,&/N:a96?r5K8ja Yu?-WfPT"T, /[iRi^i=憎Oa`O/&YVJp`E7Cg, \uBzE^R+^R\-ūm+&SNn:"| Tg5rl7L1&W Jz?Q@oc\iC"ת&JAU<~]{9L2NP/Tyy0fЇ8Ag/ǐk -.!{G>aK^%M)*9Vjt|eWk*A t?I?IXnS/޼yR}4y]x1m#Dluz¦ABgtvTFqM@f*vDt9VoLc0p@z9 L$4[VhrtԐItz=ّ)].`fمK΂rYoKfKᩰW(&(.gU"ˆ`]Ovz>[%LM*r452Q^ ;Ux.0pG@Rj Zhzh@zg6$_\p+zWI\,bH&( 4+Ď *vB=I''O%w㺓ilN-ieK89RB4@L8EX5_1HYS!Fijd\H1= iκ'?P23k;_䢿\a,H@^UѴ(~ l8siIi GIN0CFo#:ܗ:hVW|լn\}B_Av)Nl|-@Iqى4`HeGy_i9SSJ*`WEJnYU%qUmhu(EiW8bh#gA]T^Ү;n@H4plF L/ie|=@N:7;[ִh #3,:d&Yah:֮(Kf Vl.eLa(WRY!D  ;D~ wQvڧDN-a&‡% ̬e+,?Bbg{No<ɋ*K}9o$?/3|G{')(0&6el?Du O3xwF{fq6tfGp|O#x}f/|Krlm eFyQiӨw7F>S{< wY4͓~O]6>r2[ k~Qx.-NzFi,5=sQʏz`Ϥ%Y2 q=ȥ!kwC.F%3'q3G@am6duғ_"IFh6IM8 9pofwԂmh(E ^~cBOq>nk 'lktZ*2Z#xH;Ej=xM,f&IjpN|ΐJ~}B)8%&QsWd ªD&7O9Pj6\#}ӃMűgp|wႡU.A5i"x$x̹Uu"gOhNʊ]Ӄ^&Iq& RB/ ޔ%@ #e";O91dᐶ x:e4C'FmE/&~ $եyB9 \0agpMY qY#*&VhIC,Ce \D2S.sı/f&:[,T%ˍ ǟ7e,W,7/yq UB9O@D]vw~=OvʑT HPeˎ] ,mkSve|%]GVo}-MqV%JZ"&_yIWڦdcp `zaזVpe qgEYGӪbUkHZi4m噟_]QVc=A\+nBPV8@*M+/}Éu3b7nv,>NH{xJAoQD]W xKmR3x$%Ea^)`]>QsPWj S{_Jix9h򼜤zDd29S|<7z]1'fP~p ϑXF@1oh"i\e%i; .uijįT s@SF;t +nJ19(97>щ%rt-MwҖU07@q}'7{L5cN.<߭=zL% F/-/ZkI c^)X<pJ5"g^aneu$!R _`-mC;pQ^0q]3v: r`{A}{5c[`_ڹ?5ƹF ;#]R=t%LuFH H4(pI|"*bj SFf)+&d]gJ׃х* kՋX)D58fS G)x`=B,DVyS^0{;/ ӊq{POqwbuWScx97X&=\?5\4@kd*|:35x'(ie6l;|31TgÐ`lRqo'[څg[;ZzzffQrI&T|tCZ,Sj3/΋Cٓ̑ƴ5,;bm ZF,kvlV4x*p&1ty g3%|r.fjH:_Y^ChMG43hmU.smWRP7^A@ Ȋc,!C4*:LX(8~bnyAl५g)+RO+~p_gw+{CIr"@3g]ZY1̉i7O_7WVVVzpQ$| UJLӵ^~ k^#6zzA4r]Dgq,JB}8ke~RI?ER핌 ` m(aEQ'ux)k |[IF=r7.yn{jՄ_aܲk`F<^7h ?J5`G 4`Q,ώ @8 3L u=U.siJݵe*3]:X֯4ɳS4 ^BGAބb;PpW>kzPenr.2WtChP8V33|wse> ACϑ l$9ٌ9lI3sN$)D)zMADmFxbgӾ/3"1Iwmy42#{`TuN8s32Ҵo sΆYprB$߼h (bLt*@6l#.O %tX]ْƤNnT''W23DQ2OJ,ֻrP"J6SCkJNy*ShBkyn.( b9s S;ŏyYH)6+9S݀Ns^tAr=-ЍC]\xiSr"vLTٵJ) 6rv#Ofd?&<@Qm5|B [yU.d?0VXM` ckR+R7;F j :bHdy4YQ5Up|JÍy*P2AteU3Fqvt7  %X~@3u4pY2ڍg缪`oK rut nj!kٿZ9#lfy;(7WKy0Ѕr&ꜘ/A'ugkˏI_Dk%YE y$9Fޤʎ"ܕ渹St.xjgH)S'٘DSllfΧP>x*`3'?$2gik+SsU| ӣ|=U2?1A3ւ(T/+"ا(]!F߭>ڌ 3_!G>[<͢1^Y["lr̞fgn.{05#CV0'ebJVuG"9|eJbijPͯmH]`r}ȣSNlM~}%pnĒ 큰 PQ0|PGٌ*lTc B43kϣ<ꍌi4RG%Nx$PǟJt*#o/u<cib%)%.hmu-3ៜp0̢Lb<.o>dGS7DUf5ૺ{Q@UFl*|>\==t. GT8>;*:dvU835* cAC4Vs'EQMBV}45A$jyB =աgy}YA}qݔD?Vr'YIFKHT݋'9UC$d2 \j>O*_6#*>:jf3QX,;5YU2g=~_.sD0>]?[CaTFWO5Yʷ+Ueh??5|Uʬ sĎx9HJ*S*MfƏ60/w͂sEw-ԼX+4 lA(oYK eϚytazi =eEG- ٗI`bL/Osx͌cOg:#>+%"k{ĂQ5Z 04 ˯~ IɁN_Ë7^Mת>s×<|ϊÑ74 waJƍ+ե-Znm29gwUd`$ S#;1rnMb.:,0'H3lv w. h(]-}v>K#m+r$=WΓ5Tu}W:/* O#)AL4[׬vrcTU yN2Em*6ibGAgkli+IHkqK ұ[xmXDudE.Z/y8D R63w7 8r\6#27|Q|@&>,RPʁƊK :ɓBcf^Y~Z>QKt__[4i2xj %;1 UP2oHA:DO5Lkzɠ,!-E,뱊X$,OmGTk=oݮ>ђ,W.IdHG Rӑb4a}1Ș d X "*X]=FYmj6Ά %ڧo{"4XK9ԉJVcZ#עanj;uReQC3 |T>aS*ܓV-%&qs2WhNN.U?Y{m>juIl8]qfHƼry! D~ahloGsQ]4HCʮ7dUmH/E5`GLt=RTfHBȞ i̵*׍TވM9Fܴ& _|[S;l7Y4bzdH>JpO~[ֆ\!g)H`F,彸PO澣2䨌.R J>ix8s yx8 4 *< h4&(< EF0Tjd@pYǎ^F:D|ΩgC@KTqΪCd#g?Q1h \`cCؕ#luEԀj3lG;M\* 6 #Ij50kisj9md+K%6$JgSbm U:bBD^,gEQjVltʗt$?Q8Ղ_Hcg8RMrNH+3yP`;z^A=mjl1G5(uiw]fAZ*?Q-[))->AN헚Z1"f,elFLXm~B^<OKhhNIόa!ՋRnkOI1UexV=#c߶8;;oo`(VӥoQz]^3JKzzǟdAs(uh|F p7aKaF96$OXFt^rVz {zH. #T!xnrY^ql4}ҩѪPLLa͢kP[ @1q!0Gl5q8D0\>2z45Csge!a-2.!$ƸpSWF('\+l^#UI-_%tkNrJ&z r;F¹JROC~Nje!;i|Ӳ>p <g^怦ofAK@hOHN\ ~I~{@KY* W9iaGSQO?xaJ#ӪJdMAINS_6H+Q ZWKyH..YxG暞NA)Rɽ'V Nq涊ZCsBp'\>}4v8P5glW+SW R g ZA]mC५R릭2qN ν))gc`:zJ/Ya2Vnx|K|_5MU4 2B `z`4NZc6C~S7TD&W&S m*8i7>Ø3SI5wUHoʗy)@/ xcnv|?y/.?j4<+̬*s"F5ƛz\9x73L&]_Fy~)7o)K="`#KyNs9%#QH$E@<|s8i|O4Ik\ΒY$] LnHc,:INbh+]=YXfn:HHf [rCYO&F+j< 6 F[ƬL{zeg2/iI$5do9>gZ+`R["%ΖJ sxbBNQʱ+$';'<ѥ޼p\,8^,EH<"Z>]or^'"_f-b4fYr= 0ʀVmӢBam4_?nZ0:r:ZꂠTъ":?+q3#OZ->3XuD3+n$J,*rjd}mEacJ5U=7~=e_=/2&)҉+(o钷SH]Sw3 z7Q['c\L>a~lb~4u"AǎrѾЙVu ᚨJ]9u~- )MzO'u^t"Qa;ˤGJ;zp;$louğ S^h",/{#/.ёOBeJ SGl:;i0ǺDk2v#0YD%NV(xұ==DjL-j CwBwPձ_\T3حlyUؑ$:F*IG6Y{fp@/_,6 ō63%+إ3!ilPx3>`zx׿&Nj v;Е8@ڸk5cWxWw]( 0h(6=V꒺kRZIkUx q{BI PuK_ymqpVkK7]n-;;nmjpKHkقmmltK:l;G4^d{bo_~jk-z;[]Z͝Ehayz{2, Oso [\X}z 5/wQ޹ߦiͣM, CMm/B !G{=:6^lj5[ SC-,6ֺHb84sHEm nd,aMOtiWb<|\!4"G&u g.JLa ;`(bw'$rio( ^B onPDtlwj;L!_@$.޽7S0!|z%l/U0*.M[wYؠvkͫk͟_"z\#{nL"( W|G:yGn*uؓ*gmw(Qj>e/2^b תh6Ӈh[Bj~YEw%n}|M8 ߶bJocnÔްTnZA)-:kz; Ƥ ֵPhx-vG"Cbak*/Ph 1 ]"—\=SbQb:!^9i~i(i%t%\]d>YD&qGX3|kj=?1 =X6 lA|^z!J_"֊-Wj&ҁ 銍Pm|L@2yRƨմRO(P:tɂfJ%̓ċw]VLuv7"%V̀PPKKj< lGrd=glN_b/ adu[^[ZtEUuN9no@H'TTK˭w j+ /nx]Q!yTce36n I&K=fnF| ё}+!mt;3xjFBơ+{m=n^B[l@DNnu?lڏeL Db,{lG-ܞ%>Ļ8"| ~a=cSǼWvnA`c;\m :yKH[n.6FGoZV7vf=-_ m{ux+&ޢߣ`q,h4=0rM썌}=;nUdS`j\/Ot0-\7r"Ds$q]R,Th-f&C%ݵSwd%,G n➱GCfPQt`#I YɆ 'D 3{~oQW2yЃ&8yC#isCq?k4. gA=^CݬM PduT+` b3TWA$UDjxxTUCL0Fn,%˷? iZ+o Euuk\[ %(ІPYLIS*}'/Ge3۠ 7֋8 aA[-EIJl[ n)zFV)ل0~>iYb,Ea/g 0Fz" 5r;uHnIP~֖fH48xaFfH ?EO1 7 X(`oY F8J8Ґ?j? SGh#^ {rQjě)y]=v>>8JmyTI]\Akmro"cE02ԜvbK.bυ"r|3$6)F1kJhkyimh]ٍ[#-۵iͬx2Ofոx&b~or Rr#/{kn}zGrA' m3pg1 K"£:qu^FGBv1@v7shR FuMK;ڨ6uG)<}r pr }^g:(gۜx3{#+Y>b ';ԌC] l9֧5`MG#ډ{SU~l};,m6YEMvGŠ~Ȫ%qZqS~ s!Cf$/+f?6b~eE4q)g/2wHo3{Z1%>HkLy}U w)_V I4vWS,gw$jz$żK{!#raV2D^BkJQHv3x ԠU~-`54w ZT$V@_hu~\4U]oįS,1`wFG^ud̸0ẽL Q7W(ȿbs%]G*1hHVe<D`5ٽ%:]vRPMT { gq<~tyyY,U2`aR41TE-6XMo%,m#+v԰H*B[4ʐ2]Z7B2hc烩B9jӵ:&l6Π>~u2iZ)du `|Fc(>l47ۭ tǶ _o~݁5Ն%mƟ NУ"_Z䣁Nl:|in50H]W-~vgz^V`Ca'oW<_43VB0N$jQˍ2!zw^bB˓rg! ] fL]2)66d΂ua\(PxA1DɈJx ̍'biE= ?_YX~\@$s =r s Gh p\D)+V҉h$q ÌlY=YºxFtyB ֭P}8ah)DD9IOIZiWT-8ŔZ"gГIt #!:1I}AQv:5XZ)j5l13FY!JQ r7K* {pQFb@x~'?)J5cw`_\Nخ{Cb8߽D.CEEuDH܀d$Nd#v)4@}59l;7w~MnIV({UX鰜6s9X0Fz(".\.a _(:4sR=2,CYK˼0i?~w|**k4x݀tZUUDlT l ٓW yԁ0z@ Jv.Au KeI5P'`<;F{-dj |mh.yJa4iÉT']8SgNO  V^m, BY*/`IF!"ױZ_fVZ?~ *mnv-mw6/}Q 8a^PSya,ȍ3R❠>"!=dW+ /X"ElNk'nnvMo%.Fd'G !d!TS.2cBJ\꠽(OG@N[ <>iv6wvMSwags8? 2a4sl/h#g({~`):ɹQ4[8r x철Kou:=~W&t?L`5: FRـ]ӣI`YN2ol$вp0˄ROc96X: '$v6#3C@ܞUά20;1x",25 ½LPHld |ȍQەJ$V0*H A P(Fo(nX%󫴳۟hrDzDc3ֱjACC`L_ G^=jel|M|+VOb6r2;3fXxv3ʆ[z%d`j#8օ! ,|($QÄ&$9S^DF+xOsa 6!|44Y.$ѭeN*b"S%$0q %5ղF⬡J6\m~G=ɱN~I\Ϯ:\(q&#*]6 S("::c+X @)e̜ac8QQbw7 .ԉJ&\hU&0[&Xn|ЃYK}JN\!soF]F{Lͳer@?s.ɳasid|CkniFxJvHAʑƠnˣ55|W/ZHNchծf7t+Q-L6`NħS&O01NḍZTRC.|15G,kO_ n/\H t2dos7`y@&-|Ũt45 PSHWM*h5@z걔*_҈L\NtIMm p&DV]4STeƩ KFt a5w;VC:lt(RvhYi(^N.?qi$wD=H'V/*Ƽgi+ tQdÉ5#8UP89,ljVOJ+O"[y –MA̡ϼjyIVrHGbHx*Vd0˷y;MHl5cf΁]M&u&H@J)`XM5'VmpsyE!j,%rI&!9 zFc'@VAg(,|Nuc7|ܐؒj򒾧-x#P3,K2wY5+*Zy- ́ ^NZogqei_uZ*L 暝c %M~K7(Q}zKF!\Z_Y0׫~K@FK!>Oeq֐K/9iE r -0ͩ W7m@늒JA*kB2ߨmoMk*uE)P˨Řl"}'aaC˸9#>@Je0dz%oңpFW'0D ͌].#lEݦzua?L* wu0E䡟p@*x_J갧hrXHhPPS#]pUyR`RYnLޕsgtX%D%%Y[R&S܊ӱA0ET.S^؇UJL؇q"jug{6 z+9ĢRiKՍ>:Xm|Vq6 q 9k H_}C g(EER! i)C7@ , DŽKC|TIsы'BF!! &XD(WPK(|YFf E"(%$ݑL'Wy:Pu`dZfC=jۉҗ P%DnDZQ`s卍ymEm""lL)e:\yt)i ۄI_E"gԴPeG59 p#~$HQ+Qhք KfQ@(sl xאuZd6Zu)/?d1A~;^|AtEenOX'\7UJ2$mLbPߢ.˯Vֿ_Pe]͈GцW~!CZ:a)`>M'wVnOcQ̴JOf1fCk1dtQ3qi[<!ެ4HSi!v8ͤY,iuV-҇PxK ℹ3x\Թjefmky0N' /p$icԙH9X{|\VA0u$3E-*X(j J֑Cs۰G2Ujzc`R W ;^2"1^jk!nR 88tF 9Tmn619cP.޵%"jNtjͷgIJgn\:L (%E̜o=m w(JVk5)k6Cw5si?L̻ (L9ww@rᇺP(GtP//KE#]]e9UzZjX<-tB9D 'Dң34pk4 %>pҎ,~تd|q\ξ4sj\Fuxh.D H+0 9PA'\sdl};{DHN'I*2mBZy;ly}P{tpj ű nlHY(ǖL _1$Ie=⅞ubK9O/;cQEM9|{W)e`~_3\ѐɐ؈)%Ge,&(T,Eȅ#vDQ%KV);X#ΆT&6&_#r$ƬFFj7Om^ d@,jVz%g=,9][ܫboU͘%cr[ 2UwqbHVD~`롼DRS˨~R LcHQDi2Z@~Pk H+/ډz+C_/py@us3kyL8Lln d:ߪ"o9IĂ3wr{SM?~ӱR0x[TfVsJ17d&bIJa( IVw M ^1Xj ̝,53J74ޡ·91:_Mu^U)r[ߟ7j^ ׁut]gݡ֠o:W㶝/nHyC\~P&Yrg%"2nÄ㻅fWn6~#@v{oP(zsCg&aRERϏHEC/Uy >oaq1 ĠEهT(e.{^P?A KsAyM'Th)nF?S G[R%[P uCYR5՛F֛fnq_|CjfPnkwTm#wVmfShW2lԄXSi#w3?Μ-(x eP&)P$|؅j8;Gr٩Wxf{g_:E M~5OY?Ĭn>mX_n|7Ui| V tv pJn>.W6wlM{b{o 2Bs%bee2aCvմ攄Sz.l_G?Go;G;Gͭ=NiӒq?v7;o_'eS8N4LNj/c//:'P_^$ʇV ?a@ 'cv;oڭf{7 -/z2/U3 v}&6w6_&헸~ɮZɒS^n6[G5[ۀOöթVsmx&"?"i/7{u7[d.ao:GODZ탽֫}bdN>8ڕZ[?`^I9JMO8:i~)nm-ȭhN.4wjh(/"~Xom0aISZup/~/-#:B3{GFt Ƀm=:XTf+qd:Ss~z(O&hh?'vv^R_He6! aUCC=T|\TY EL7 P0ъLlK&4EK&(c=~pFƮH?#43+/N[2u*A40UG̤6hO#Z"h7kBܺ +}?CADDUea=74kϓzɥqH#-\es~bZl +ctOړ3D3wyu/uqn̖xΰo6ȼ%C@fܨr(ܸ[g NI{zD&?!;N$"{ _R3:鄽^C\'r+؋LbD  &߂4Dˊ#㧲`)^LX0e3dlfפ,]K TV`&ƗHJ0 iE1siGEƾ0vpJYrd.})4Y1bc HU!;Rq$.}Dfiԍ/-7O:SqRÒ8.%&Ro>X'Mb5i4dEwL O}'Cuʢ"ySjĢ?'+ԭCXvh^Shԝd"yG'SQꔚtkLZL Sy)/!ke)Ѩ#uQeȲ\In+ M/aT#1F՚ 'AJ崍v=~b>/rD`D$C* kˮ&͐ݙT N:j 6$;5FL!Q0l8 ڣrPMjB/|b@F$핪'ldb"8;e~cj'P՗hPBaUUEC=JYihF_j^S00jK?WSn,7Oi;uuJTsaVn5Fp-v8:K9 z2 _X(ӥզ"lfڨ#oc ןD&R\8ʋ,mJWLk~QX!ƧTPojpfj`̏$C9sGǹSARj dj3?p!V.m+\RA0_嗽,d8XRc cWrLt;#* f*L)A5LT&2?R$Rlavc*r'27v7zR&̫ž   3 Lr"1w<V5#e, ׄp(btTP kO"T-9?vPԤ%EsL H&uHolBTM֗agM"U">/CWIPTQwTSMIGOc&$ɨ0oHx$ˤIPT m. 2?pLυ-gaOunm0ª)2SnKXR=u(UVSMHGO8L6ƈjrFE XaSEeojN}۟֗.:JHRٟ֗asFB7 -~f2g^ǦO_ݐH :qey@j@5?p!P-̅$x`c鏍CԤHe~a=kCAɭM ty MH}Ure~$C}UDf̎IGf&qe~a%2fڗ=lrQRMbRg$&AR>gqJuH/أiSP'ARՁGyl7{vT&F?ӽ6uF~iL͚IG$#gOALd o3e}JujN"sFY31:Vr_X*)B+yjʬbSɍ='.?k&ΆQ,g>^#)65ę#?S *6"eɜΊl*HiRQ` M: UasF}VHo}ѼhP*uH7(oaH!fU(.!6H+l8 _{"K/ t#l mtdR#M QIMFl:"mf F8 YTnW[멚ϼHsTlLL:"2? D'I3מ#=Lc%>ͩ%ҢtPT@ X5F8 ni8E(q)֗}'ARiRmWM(?ML3'AcԜ7ivK:Zr8J&a ?[Rl8 V UUT8 ~R:s.[2k,K8_2~{e*ww F "NǫD[y ~eLRy.N]%!7䭄n1="mysyw:e<.׫~!M?pa@z%Lebxq2?pL3iBv4E*U 5ɟ㓄 hblj:ХpDjp=FBO]=N#zsn|BiWjy.a-מ1ƦUQZ!EK7Nh>C`2CmPGZ/sϳS:((LH=}Qzɢf2Lk?J[F3bsaVZhCO{ y.&IHg ѥ;)Qy=T]iF[TWQ۫?%aWU?g߉᭖z$L ?R5w lqO} wyڟ1;^~3䏔')^aj^q M O+z ۗR'X()+,R{%цUQ=Vsw ϝ8t P )K ]Nʌr6O>PsR5k6M "TRCr AR&uMxDFӒO;! ~UB(vׇ{[LXɚv%IW>`d1I I[ apO,(;B9TR)"QʼnѳjW |e:TyшH/mSaߴh.?Awщ_{ᾲ'ʱؒ/ \ 04JN#S7S)Kv k Ό>áAsI2 oa #Hn;\% IKdžS=zykį/{Ct Wo=OOd4PIݞUH$YGaz)g.~Vaq6-iiڬ_O o)_ڋ > .iz*y0@^ŒV(e;)g҉V糵nA-,>6]չ %<)%}S{XZj)Gڙ2P3ޘ07{߶Zvm4j'3nKd~Kwm ~þg8XȵIc$rexAE?]R/9 b#P4"`eŜ*>Tr$yvFѠQT:,<钌)'>,Q1YGBCvslZfOm*TN+6-"mZjd7"zu1N|߅A))<b2l<ȪTO:7|tgd0(Z|:%_.9áS` }SsCE[9w).yGKڥ18d2FP #t8 W!.@J()2BȱZ/hS;C!/ ?ͥ7oZ}Rܣf=;l/T!`4SIeQhM|PKԝ) lY!q;c8xz2@L,J|'_$cM2Agl% iMW|sdl0I%E>T6Jmw@/r!y.yUJ-8)GN=pkP3kqX7,ޑ3 ,ϭ9sھ"iөg=]bUKvѢMBs:l|IV"ILU5<Rh{v,!ɘE ǖ$2PC:OSFtlR"m:HD]e %28;9E8^tn0D&`^4S;fШ;ۛw ۩}p>xɖ-dϔjNůuB,҃M,@/[Go[ɈQJ*q MȔOދ wBf&?jFuILq2ԛ.N)}kr@f)8#(xE7[fi 9CBs o%O#;Y+ y]L)H94j- ֽDE{KK87$S 0 ^OuÄpH8J1ر:J1|ٹ<m)6ݟ]f44<'jY-fzC/\kM9M2A a'9a/a/uY6 %;ւpk Mj'-T1닳tY8鮡n+O`O, "ң$NڈoS&#LmJwRJ|},ffzf[@,D^"Fdff=N>xe \Sʃ1h8sQ@g9]q<9]S:!k$~  "9))Zk#z.JCT @I (m%I O`МM2oݖ"S-LS>@2s ܡiۣF=A<:tJfuo"脮:##+Wֳ Rx.#.8Q1( eǾ!KN*6_MO@snhsm6V"P6?tH P2NUҢ_Q~.+$D20QZf (10|樆 +G447TTDsxM\*{lT٣Tu{ݴMLmķE!61o/L5U_''àʩ饁y9,/-Bxig7#.bj0 ?mw#uM﫵9Фl _*NERbJڋWOFKM % E?AUxu,k%c, w`GH9jR^6YMjR%&:XiUg6ħU'd iNRR9e‡lǺ5c.j;6ԻI|??untŦ(Ef9$Q<%gy eޥw!KDh54XV/+w~@WR6D(/gfmH8]K\xH`͑y! ]SFM@ye 㴮FІgzT6e#+3b)K~t{d6ſaZE5<(^L5g,s[regҒH\vTSz&M@L*LbBLK><:魂E_M٥$:p'挲,*%lrc˛EHӧ;Jʥ(Icڐfi/n:J#^6ZCyjj=r̟khOu,{wre3ȡ2xLb(PЗ)x| gѴ# s?x.ݺwlT>lJ* d$u@ث)ҥ>3}.j0q0)87͌$ d%_ܲ7x8ˮG7lí{Gxk|B_Xo"oޛA<||#d||ኦMd{n9wW^_%< L)yB΀y Zt Iu":ʡjaT DJ'-¶a%N_ l&fC]CGzĦ ioHo-Gk`a%/3d,E@Jl?RFeDj5XgpUKhPAoR}LkӞ .Drh}J6'QՇk{͋3iLBE|=} ͪWhjv:l8d2QTndKvPW S\Ct'H/.X' 0t G8rk4%Lq'K90FtYI#σhNݮ#-H#'[ *0j۬$p?W6IU88Cj,$ nQlUO Ğc0FW%KBR #סK6hp(uD"# /m~\t =E@+PO`X*_h]l݋}WX%qVu";PLbهI*OU'l`V= m_51rsiHw ෴ZKpo{;Kn4·9[ϠUylE5Lb!Qᄪ"#j歈I^q␐02nUCSND~ yfr=C\M"&V)Z#՟K`80M;a\w+}UT7DGVo,,|zXߑT s*|whC~!8"iR?%~}dX!$27sss  ( lbR!TurS3ΕXak+jj+_G0+WTyTrq*?>n GE_҅nIu^7 q%N*)2cp:Tw8~}Bۯ`|*pǽ7{vҚΎfJݺSQ`)cQe{?uYtI-rt ut [ hDo*FnI<&]̆`~}~! /K =t2H+b:|C^(l(z6,AXo 뀻td(u0ʻDiYUPXbY{c8"fn˲b.ՒrNf7|hgB,؟ iʇLQA?K_ 2Dfve.27)S_T:{3/;!"(f 4 gfӰ0) G6Ku`Mx</ܫGޅ$2I7 j ʶO%40GߜIӆpzhO&n!>4Yt(r.v6;[:<Nzڍ$ZMQ"dIy뎙'E`h,1#jLC҉qXZ9&~2N :yxq;KK>~P6$]"õ3~N 9)B]tq_7:apIu8vCћ[kf蒣 Q\kndsV(n4s9 w'}9開nU, -IAB 0㣜Lǜ¹+]హ/S?LngBqͤpEorKze襌b !i$-} Z)' diEwظp/sjn^k:ǕFt4ƌ'@]]TJs7cd ӽT+0"'p5R7ՍOzv`ׄ4&($ll )slU5"4XV6;XK8D(9\OVFXHs&c(# EkV +ngρPx 3a٠F<0!ss1:#rܳ#obȸ"ˑ5/VN9cl_ . N7qPn̐}`vp(YϮ/ ~3*=%\Uu8T*U11bYoe?+Vcq34I_3LW00Z.c@ob8 cDdm`CKUf̯C/ TUy4Ȥ,X*:tGY:lALYԒۃ9†$ca{{&c}t#śW#7;(*B7jk1[u"8t|ժX1ɔ~WP: "DD)%@*'IKt2,!viY4ZV*GYTsN{eg5w<L(Ta j6%V~č՗J;//W%vCM A6U#[L.L\9ݸkK.0M Lq5d +ESXY^n5b*bBFCQE%%ʭ쭉ZREs0d·>D BiUIɩ L*.oa=RꙔcw[nݟxW~>S3x5-~Q}tz mx -pFF_dW)j |uuf-%TDYXfwEECzl_dr2FX8nU?~4ANf^7"F ]ʮo=q+2p^5&G0ys4= *yOP6(&e I822+]' d3JnJAE5CX:Xi7mǍr GrgUjDiMQB*%rm7PQ|/yYP)0a(^5d!BB:m'3Nѡ"p&W)8mrW,EaTh^>[g<v8EgΨPfT2':Vl)™Qq3U\uYÇU0LTl3˔,ԝ^ҙ#=NFtQ$\D]8V3}\L0O,/]CO| oő‡Ğ+ K_pKE@m"ҝ^N)̔#˧5DLߥ>u^ ߝ*GeUj'C ‘ЅN<u(*GKb4(>ܒpΦd2!cwqA£o^Ir]ye&rW%X}ʺTIeIUɀs9풤h䂤ʙQHV*io?jx k'ǥX7#3=<%Y5xis?RgsM\PPb@psa:ݱT+:+)ya_ԟ 9 ,+yzNJȿ7^1碅j80E0a5N0S-#i5Tl[1[SO1 ,5L\#uV8$^u^xle ;թ2ip)ǒ}CaUM*ۺTA:Dv+AFϋ|?"o?8@_8 GCM> 䑒 Øv NwL/zQInuI5ǥ Em Jcȸ ݖp]RSZlf@򒙊;l_d6Pe iÉYIχ: ٨w3s*,0d2!MA)+tǯ}6,&\;߲_ EMu>%>\o4vn}b2z!ӛF"xOMeٲ o/XoYL -$D%iHWʘ3TO0?!o@, 6eN ]\f^2%5% Ո=ٙ7U{ue ezR[bS٭Ut%V{8P+@ KV SQ2"DlK>ZyImqJ4{&'MRI!$ Z.9ѣlJZLZaIrښSXs?)4cT Z%&x*5oy*,o F$e0+$"t@ HV-"HH6n?t>鉇%uzo U?L}M1MmQv{Կ[qw)?Kn_9ʿ ( oPR\ٕ~+ T2tKQЋUACɶ{Hk﬙q7'BۋHALSvVwR7|`rz JL/F|0x A`X՛gs&k39A%IG?Rr0x0DU^ؐE5gd`Ui͢4o)DYOeer&_мKlJJPRQjrkN綨^fWwzJ[,ʟJ*j:7Jf"\MD l T-{Y_ۇS =t GNz$A1rD4PFRֿ:e"H{BׂSBWgJmB`=;&!ƁVajuAd,@1t윢O8ֳ]žcXZRcV> tS9ICҹ~j'$j$8]>RZe \dBs˷"Z1uGWJg6u_RJKXE"jhMT RrIQDk[5RM)*AHH}e9. Cbf|HMž{X,([@ٖIb3ˊZR Ҙ-{œ7e-Zb"8$[]eA&QId*DoҧC/w9pHdP!BZG=)\U~_"zK3K1#(F>a/I7ȓ7P ʰ&u%ьw:u󺎥[ GQ7r +t8+w3HuK-7{pD NtLE^w9OѰI󞴳1iUIR;ψOH Kjt}E7,igIE 77ob%Hʷ52)t )L!S c-9h1p-,rKOݶ,qb6ز*5镫,.سS`.p*i0čH5(NhLGHKώ,xu(>|";&Q|r+0k/&tvFۍsWƭ T;Χυ E>f.OaMkDD1BfDDikJć`9UN]~}J|r{%} .}XYԠQĴ( C}$jZכtcX C}d@Y偁fٻÂ&Smx| U~):,"X^ʡ-חrJYl 0c^lpmkS7 G鄲|K.ԡ>lT/q#ztmQEq<>{4|z]23 QIWN9r8 Ks۞Bn0 Zy ~;vןuvDg䮇?T{(PH^J8Ă3U&I>a^2'{yuF9`$oʼn H)qÙyU*KdAfGma,:NQ q @ow#F<= įvI$` \ iXy#(*zQLfP$ݠKWͦ9L)u.Im4JqKUͦTmD6'`-4!ƴ%N+ /\Ȑj4#%Xcm?)2n2E$NlaΚ/SPg[ASfdUjMޗE)6]C'bUn3Ѥjuۤ$3q[~jR^}|'3ގw>{ŷ!ѳk5s ۝pu- (>vVΥ'Hp\K b*Q a(a-ן[#ٺ('p68 5L8)/B5FxP Fꢐ_ 496E cHv9:O&o&w{XdPQE t+"% ^.xu!<6B ؊̎spQ1hxñoˢ ]@ (iV!E6Z)=i '>Mt~7VsZ8s 0xm#.Y2ݨK' *t|>f>mG(cReD /y,|_Q`n E ;O9I׽? zל\@]:$!, 儡s MEU(>Фae-3FcYMA^A9BF^ A}E!bE<SĂpt[nnaȝvL/<Ƒ BunH3C/3b4Ψ7LS2ڴ~pU_ 0ѩ`qc^ w&yEk  gs*U3Y=vk"*`PLN询,Ԁp(HPqmX b 1n=Wd!}C / u#\mڦ#j[ovo"Dbd貿t;xBOnDO@E:&ܑ+Xm5-֦\qXctlNsisGJs"'P]ҭt3NxRIpu eRIIm"|f"qזe$;M=B"Uru=9e^B/p#=x| fvF_:ֽf=a0izU4ZZY:.|iprO.s{erː\g#g!7 ݷ{W2N=%}Q8#Xb6mD J@,;U79We1^O;ADr=p# 3~r;:HrAl.@rDj譳H9&zQ}BRh; nV~gOWV=^GSssZG;{O=r!nI-gɃwFs?0 v`M, W+Hl`uMd5z[=;H']Gc=f\j,8?d5 OGSWs)--aFc̡ - hVQ+XY_u#U(|TD (*X9]2KzZ Yf$qӜ' z(v-R)P,Ù8߮KN4标DCj7"U8*[Bhsڅjq;>8۪l ~o*EmnkE47ves(m+o6l ]:g6S6U|#OҭrVtIl#]6នDu=MO|_4yQ ωʔ2 QT+N2 ?L)c`{>'Sf0]^*S U,F|R]bvMOuƂE*s TUQ5Du^2 V | F~6ڲa΋X OQ N(pU#܅UO̩IjYYۗdPqC.gerMyƎ,ޔpdJ,s괻7I)t]b-gORhij)>UoCm_TzBizVc 1t;`~/'SP2P[0rxxz]QkRNST퍢*JkLxg:Z\8lu'0uvR@fiI/ǧ6?<ȒøQ^z_u~\_*ktG=i(dxa Ϗ$K?[X +Blڡ;?PiQi8?MqW;[iӹje8%|L-.k [3,ɜ|8/hP# <1B=$:!YJ[%mN/S~jd˻ڡ"nUqѪܰPdߚ8Ns >3y)NzZjƩF3=ܴ7 x5@/؈^ˉ{"thěc}XԐsc\[FjxdZ AT1]uQjb:NYJp.$F\^s~b-_it0m<32cxU> Q3T6ۈ>L+&sJh N.HMO$& Ҩݥe*mm\wgvwF;[$5ޝfs>)6+{wJ'W jL,@3*ɲAfAu5~f2bbEk0m/4I%JȦKuQ"39h*md T$䉸bHjH$ ؠSc"yD8GZtbzD?*Wƛϔ%Di\l;J;Q^ ֖aDDZ7YkQJdSLvt!? .Y=w=tM ,KL6gPrFumZpDR9NVAd0AhO$Wac躴_h?h= E} ;]!XAbߔ$hR6aVrDOK#M`9ĢT؉$lU+*wSpAVW Tٖkt*HF]{{yY/Pㄔ& e=~P']I^<{L3-=SPăf2"bwD]]9KMa t!y#*E PZ\I:PO.~ǻzqEIU' nݵH=z|cMĵv^w$W0Hk-1f2D%Ayi9,3-^81vj[{PRsb}FV~f1euC@GA .,n A Bu:;Ԓ;ԖkD VDI*QHU>/"o]pȋb@dM;;{`Dg2Veo9 /aek>nH^Wwk@ܠS t0P凞Kl \\NTܙVͩYܴ Y*dzU y 1lORgr}u>V 79mgSyVeGJ^0} ksdoY2 Gϟ\!W/ 1>Yw#"cϱw.uU Gx~o D {D럋Nod-W?ۏ.$J5X %W'D[T'FH#kX?K7wd25Q Zᑿu; #~_~R#o}͠4gpqB%wړwF]ݮύIfȫ o1LT~~\ɯj@WRlD)S P!ʯ3#'6c8_Fc=ǮP/F?喦[q4'@Z "@6I@7fTS(>fA{ x` ι6 05WCsvd"Y眤+Sh QN2i\/ryJJpFs{JGY1%BBVzYseZ;SxItXJ7_l[VQnc4_hȯ/48gḘ` Ή-ͱy5xrJG6j5k,R$}%ɋ*B|;NS+(hE'g{>.J|4қMd"ҭ!By9<"mAC:T 3e-yBo&9NnJϘùqx3?B >2EOǾ^ x)!1Sԭw5 4Pڛ?}($IO ׸B8`+# fgtZ*Ɵ{kL9gWyww>t̻fv\h1rk|2yֵ;WZWS2 6g^k'|5ZZ_^2}6 ]S> ɜAJ<]EMaW0Kp1̽6aF<~jh24wDyy-]J[-I)$_a+O|CpS,g\MhYxVƜ=,8t /k!O8֓1ܝV|; -axLG]"f%A5V*3x1?-šP%!N0H-{[<Ν\,K'ճ<4 y >qۼWiн8tڒR+JO_xG{ E_֧ 7MsJNF9g'{?_6ی3qaO?Oxۉ xTj``=;DU(}b"|!cY8ע2tY.{+A; )>9Y/W"/ ZRl7$cE_#xGϴ)j mH=5YNwJKa߅DQ3JS-(/*V+bH[ ݊X(;e]C`*Z698ٍ?fY| GMx*3w<”zBPfESzqnP>(=Z6z@ vev;مjf_Pv&B.SkSdtqgE!ILd]s /;4C ~6 ( GADYYPN̶*RvMT_~%cI}TVfUp(7˜aJ;}V.zh9^ti-n3e?33~AnЧHaeEFԥ+9OɲCdBo*HHI2I (U>}n#KҾnB; 9TNvT#-b5Bg +ꀁEI/ԓ/&șѼ.̥&iKܔ9z(/zহ2NZ\$4-5|:f*Jol{&uzJӚNO3BVHIr(r7 A[ V:&1<N@)uW\:  W*a7fO`+U2Q<Т\-ϴ8'jAWWWϧ?sLjgYD?ثY22/ ~xɹs+Jm lrokgݾݣOP^ޮ=/'St#M,1 V|ϖٸ/q?=B7xr>¶…:+y,8oL*INr\2Plϫ>E+)/Qx\+zTj/s]JjN.PË,|LH?)a0Յ<(hM*)P{.kn+e'8Y ¨t%xG)i'~\HaP$81Z %L9ܞBx( +VV\z{PDg #\N&FΣ3h ]>`8ͩkx]cBZMf_ܥ4@X2 K_9D^ vյvA^~'$)cE u`+1Q!Rxh0#qbGyuX萉]'BG7-w!UfJ-Z9ks0k(Ҥ axGu"r.l)*5)5*2Dq$ܻpUBһ+]4- g{ʣG=RAB X:`+3Zl}}т ڷºx {hX8@𚏀Mp2:4kuQ0#5yZy {M^&[YAQ8YTjRוrX#+J"Аu޴ԁ8Q3s^_{L_ask HgFvQ,Lw hGRL!s\Jtg󦻿[^}l2K q+q2:oŒwK~%ˉ=pxU!oC6V%U(HwbRtcmPt O( vy 1(Foۯ:IaOd3_Hœee@uOyOFoK U)JKVJ}\fXsX@hF^>u{j 2KbE¨Æ Ar=X9hԠ|5!F[o[bEJf":E0#HOGN/!:#`*Xg{tÔ1H}]ǮJU9<홶P$j)27xWsœ\/%׿$ii uHCﭡsTNg>hPxT)p TèEioWgؒUCd7!3xwgg{J= ȟ_ɐ"z{&:sp/E#8,ϋwLp a_73?J)oF=OD2fD;yEGj߽hn^ޗԡ;Ň=g\JvHi9 ;6IPX(/lϩ^kW+TQL%ŋ>j|O[愶Ң;]MetQ.UqPKKxdsxeci\.ޥEA@8aF3[B3оw8Bx;8O`U$(C xj?*>oZFZ4v}=$Ԁ$p)si Ɨk(|>Y;l>"fEhyE;c_sV qW\:K ɩr7 T54_&j\>TxE_l.ga%0 Dq0!:r?#ȶu0OIӲ߻ IUr}Fe`p=`>;/!e 0aH2?Wǿ-/*CKP\ 2'%]АvT5R֊(Gy h$޸Y\P'yFViVIV9z3r^ߎTYfekkχ+PN $;#W6LYwTGunU?5+MąWW |-Bi 'q2 ԋ _hK;Wb(-dy1/U8U˫Hgfߡx/uT2Cmzg< )y4Yߋ5$o Cvp~[4. ˜Dx{&^Z]yR$`*0ƻXs*Hys]!%S`I) ؾ]oBI.w|p<Ih4es-Ijr.eɡ<9 9kob{KX,i.*-çݗ(bA'Ey݃N,xV^t2QjEFMRԍ/8jFY3qi&X%o{\Yѐƅ0pznOgh~SSjD`OM6!8O}pף@̷i[E;[_mf81.ܚ%%Uv۵vex#'xRq= C@I;m6rg$X|ǔ'^#ü~Kob{KZKLV;M0wU,TZ"R dcNym_xa~\C\'p|/:CrߧVܵ[6KT!ޚn_΢Z CF-mUFOHHDqHA@Q 7Bx euGbBŨn ? G?zd F {ڙakI.- ݡj%dX:^x1{\Y]&4Q/\V@P2P5hj=yd-quKؾp30/mh~EE(`-/IpH.p? g,G4R=ԊZ2lU]՛$gsuwulu{ydS=W͚Ŷc,fG^Cj(` m,7@{[^V-d8Z/2]<=sa^vg&pVmhF2J@h]6[H!9nxU9"hd؂ៗИz8|V ں8:bWE|U]nx u Ϟܽ]#:/x3r m۽FPri9޹>xk[H7Y]< 66ۗ 7@KTs8-B PAW9xBw&2+ӞaP>S'~a[rpYcrc/L1ԬP-7C/1@ej&# v_m_bd`B@bmm#olg6>me|a|7fIs!2JjBkJcfB4 u}{!n,E'Kćܐ{rŗ=ɟ~*T]>Uo>5Oͯ:XƥoEVVj鳤Gϣ,:5I'ˆ.2ܘ2͆φD0+Ɂf~j P[ǪfloF6|ɤ{_-qq[#2yO2XSLe0@jlF,g-X*C $ ho?d{=_|mo"&( T6ʀ@^pJ!C[Tîzx bcN^A&r%_-i^Ǫ%cjcǤVO(7ej>!q&uYXS񮄽}V^Zsx?.Fq8WT-`v; :+u `5FU ^WN cd5qΪSl;m3%54!|T?eil6-ϖݬU 8s]9&2; 2HXk6]W|a#8A܆cXAYڬkZܢqAhW.!eWVer1͑k!Œ`'8А=jq(Ӭi9{x<=y.`^e)8% =E{z*pʊ BdzH"⒅-=Ul5_GQZH̨{wҁuڷgOAmrȭajB`IRL8띞w B uZ ,69_2kń(ՍR+q4 卺 #Aq:&0L\P {ɲܲiǷPr$[p°M@8ehs64љ< S-A8%7JLԑ8.“h! ӏs7W-D/WTpJ<P]>B( B/Zx K&JI/[Faʊپ\Ja۹FW8n쳼3>_vnLy[?nXܓZ\0l.`+3(M` g g.8R3i&O~!JCuK~*ysu+ t7e\ǝ~ϼw% T}xV_n곤.ϟlU2 0ePS9h%5R!O,4l%YsXop>B"g[j~n=x9fo\@d?cu. pd_,׿Msvv?Nz:9bͫ7iw:1vnt>q8Q/{Ggۿ|n+s—.]LLfN|jέ\)f31zh P+%M) 5Ѯ([$zLˌ͠Arv sKmDzW>XdQpRrj]{O+]^tUECb.{Teo_Ic5 Q?ѽҷ&׍>1P9%pr8us|6P|{vf 7FW NY:<)3/2kT#N\t묰ۛX. %47Grkƫk^/ h ҦXm=C7 FQCgVq4*Ӛ#:TNj>t@)t14jG…,ѭ1( iCh* (4u84wCΖO6Ww|Cm꘲Ă9?mnlo糝G̓;Gu~C6PvV{Rn=W߯qK,T 7^hhac6mXYm 8m27aE)ib2'uUBQ/pM l 0.O>_~DӭܶP^V+zƌׅM޿W̡:vVْO)!MpNt.}vu.mz: BHR%s.mT2*="GKh.!$2>sጩ$WSD_3hLC)aײ`xN$ϤWIicd-GmiUأ %SB{A2萢c8sdW={=-U見t̴ T9f1 jrMD+fܷ߇dɆS]orD@|2+NQ7tMU7"W(vRCEAHaSifPMoJER.ndjjEUKԖMD2ej!`}ȬM*=m:5$ ;ns?H:9x&oY.ؘ5jq#WSl8)wS\9μ+gH ,*bnY+#]ivVcqJǥ%枘 4ų²7L>TZyh`#~c\)2#sPWI:vG ȹ1׼7"dAc0g"6uv3 tC hJ(YStwL_qD,y'|~ `*pF;űV@91gKSk;߾}2:jgz?|0ҥb"T6q Y6: 4vnBp=A/uزyadg;:/鞏wwP|Kٞl%D\w\S*t&H(wqk lfV/x[/l~D)z]xWB{8a 0CU8\Cޓk`s0V &BU5aP u7fL·`Ŀ YJ $`c uV>Ћi +tzH4A1A%,$}ٙ%ȏ.7,C3{ǓPgPNdaMj`\)+d[׻ADBo2-k|p^e576FЕ.F1e~?E1YY?1e--bl0._ݫ.VShI ,H1O7 mX-Dc|cLc< iA Znu}6Z_Lww˺F>vSjv/~2P?]o j¤;(-|/ ]:xAYv̞ -w~{Xk~~ S֝, օcy)wd2Oyk,_:{|,QSshĎ傐A/ЫEF`X~fμ 7Y?L(&AuN' E#l<B/3{xv¹y 4khTVh6%j-4"s~I A^oENq;πE Ͻ,x>b`n{U8=+AKmqEOjK=h|Š1,g,cxb w{ K5ĚFrk,G1BP2i!`>ifuPըki6@@6)hȮ $\?хP-&f0 M,^3~7;X} 4HUG\dJ 1 Apy@L 5=~8?˿w`c9u Bb\6jᣤRvx;NƷ<1r&ǕndPlf1rN<ҔH>&rqG.^TCh | GF1>&^xfz)Bcl$I[ڜ;4e.m_We-׫9' cϮ>mf 3KR^P/mF/n\H<5zV+ Ns4&@Ts _/:\ D@͖PaŠ٦.fo XB.Co.҆B3Y0[y@uFBebɊ%&dI"FL.9(0rɝ +iٓںsrxD#GI8c81h1Rf8 G3 M+R4 z-"ػAژcװ3 RلH]b2@9-:Ćbn)f Dњ.FO x5mЅpreBC O`O *:R1'7;030L$TcN@+@ZVIPw2 Nȓn:FÉཱྀdGg~qx~bY$%ŗc9i!\p0nlqd4PQ" 6EtELz@浝(ESȕ#S@B.86㷋i۟@m>rHČ۽nz##yxCKfOhy+!] fZv}$\Hrvvb&wdϟ)oAA@'5`V5+ğx_疮FvV%E]=Hd F06F kKR[uu4.J-!>t;۠*;-x/1J!6]K=vԻy!cT%Vxh+`$>B_B^vv/8~(LԕJ,\D,LMjX'CΨO>,H쵁61D7L!&kRڎ袢fA3Me="_#^ DvxSvX˰ Qtrw(y{*t`#VYWJւK!7^eu|eӜvlV98*}:-MZ^h_G̞ʮ c-F*g V%nFKr⅔w u@$T8 :R{Y:畑+`%?;ڴ;{Om墨K`8 >YD4:Cw\FoZwqw*ד~h~H#\%˧G-[74A瑰FaDܷ hYǘ_d8#(Ӎ/w)uSḾМOs % !MLʣWLӽkj%~ng1jxʈ FՄ'[ZZ.M4l@ο&쬧ꚪL<[?<41@ujӛ+1 *,c"q+5&sLԥmXbP@*KgV:]֑`B@#ѽ!0M<*Efaml$_Fi!` ._ݷf BwP%l)[3tXS"? S-`#nd@W }!/C ra`z/;8/6c7ט[4V{\Tk׷M?Z;1?Z1eh'R@ds\Ӄ}gxody/-*kjcC˨3ۉe'_&'xVk˔! _6?OL{lL|D9sh;$@=N@Yjkd4qB4=*s$2m;yxv{󫱂_=`,&=,NŽy%Vmb4X*?֫eCd'Z*A#H ċN! -BztF4'G6V3aG )BvE4CX ݏz\G=B4\d/V|- m&՘vL9;P @4lW)ȇX#A3 0hmpژfRDFн;d#e-U'\UG`{]X$lf=NImI4HQ E m< :"#w͐^h1Bw0XYGr&ğudtL|h6SNm {AvGct\qavnjg喘0_Saɫ'rzRe|1Yt=nsxGxmݺs~tV(ў$|#DMuOk9(:yk4 p%\zrUfO^Dc",UV)|dD0I ;*#iZ!u it J@mҸY.ݶ5)'g'\EUu6:2 Q! 7z$D2*^P7E$Rrʤ4p^>nj  jۇ53Hہ!]y )R q -TgS7W<.8kY*Y(ZZ.CBOFuQC[p6i#?DUe iUXw7xdIIaԻBPOw̕fkZ8NCU9#<E[PiUEP̷ _.DIوc)+ơF4}wCIfDh gY]fĜi)Q ]$Gk&: ad eDEsA[lX34+ GF_p0KSUuWW`K0ݵfq#9gs=um]=u՜x[tbLN@ȣ=7H)nSDNt>vqbiObBi 2@.j.pJ$6H5Uש1FrZqeƳߎ[X11AWfz""ĺ׋z+_7Y]pXz5ÿZ_\Qg&z g`~)dOo}%9FaʵfLg$|`efZLhf&_YFA:Qhgeʻg[/;/l9;xsA%L~Vլ#3PċW0RwSk\d3zOtiS tg'U$L{#1Kåw.K\x72g,p\?: #Isܨ"ʌWA"dQZ]Bܪw[nյ$̭ Y6[nUmE#"~حw'qȧ)gunRzUٕ~P)Տe[w!ڷ߅wm};U8Pag C+uٳӮe3G 0\0;ð>m8Us-8ЉS?HODit'[fu^>KɄp1tlśٗ%m /S1:ޮNj\taIܛq%.JbeqX[xTKG7^.sYqmw2ɄdטUɁ9p 6݈sf9asa>\({Iz:p`8o¿2 71G_(i}g<ۇ{sI%#~m;qT濏70XΉT/1{~d̙$ۆ̏7%y jK?(phIs7B[> KI{%MQl2gAD/lpQ+ԞOuֳibddIM:%:W禚 νEBrdM:fox{ځÏx6݌WVKqmDigbDZmY' }]}ފ8 lAcG #ɠ5B{6mR 1Vf_ݭ:C9oaA @a[cqa+Vo$q(,RїXCS|h󭝢Й9:}q.*czJ{;ß7vg$%(./1im#4 cv߰ 8i>i n'mĜC fcLa퀠We@kZuy71ً^YKsgs,ޜsBv_)y벓ʦ>^1H#@?N%*]L--gh^8#1\uZA9eʭJB eIogփLTJ,kz%.e|8ĝ8LIƐTT_d<,O50peu&&.Rqkg+,;vPȊ kƊû{c!9Q6JUVOs5ٲ+0eb|1|3fELNPnF%]1; jxyt*QpvI R@.މkd1;|l9uXi~o9Auz}ud'yEO?q|( ,.*vd泽Rߓ(tF3UnOg9`>kàmqUJޅRf3!Q>RBL:w,%BP ;pE?לٸ$]n7 6}ta〹^y"}嫍))n܂;amU.Aw*6*':X,$/~MAzWw_ۉ.sa4Iq"@ff|0}RJٙ[mjS AAK8X[Gk+FHV~r$؁4(]$K690qȒ",d'H2GUfn_VU--T.|bcȴ 1`Dth6j\ml!\ YaZDg5(.]90vXR3K) q{eSLx,74MXgKNяe.'Bp5i4ʀ9u:ߊƱr2:'L 8 80k RhsUFV *DX_1 ~WDqƥoU~B)S,y e ~&&"0%{8/nd^4e4a^\6҉y.zmԔyĆG.ب#v܇m4A;Y 7U3-~l}Zb*ӹ?-+&kI,Xd] 𓽻E{opBt'tn+d?B8$@zvX{? "X+:^R0% O]HM 1碰\мޘ  sh# k df^ Jrm_ }ځ_2hxXst{~永82Z;rT \Ies3hv_o֚{ͲRH` Or$cp2X4IJܲ{jwa>6`dq)9`2dX>Z>vȫEITA1; ʏ&9 ^w  {D/8xA odUCHKܛz] 3VQC$8E] UaIgjYwˠ6(PQAѳ}b`h'h $` < [)`F@=)xZBYeġ@8kÀa;kNjK>/$$ҙa#]IxeGΦb0ϣ6aΝ/TlVC,;a쨙RfL(-GJcVEmJb㝧ջÍ2$6߷G;n4 7N87>}[W O)#2<^_8[>bZQ삘asG_}D qawTr/"j0^ibz@|aNQw5((#hZO%ܺ.hÔ@-;xi8Em*-r -L@cR1 ؎!C|`B[lhȤƖ/@['9*=RL}p.L.KJe0c8U坄_806bhtl.?%IdKA}ȡ UNn oP@SO%-<\jʜqך&ɍ'Ymz,̐K=2U֖z]g*Mv[et6FYNKk4.kq>碘FM+h#- &ddXņ" 34hZIt}ujTb9WlXDgꚫEQ60M4C !pc a-twj3e:ImX9"n>e =req5/!ɑv` #͐6~VQ\'Q&xF]mK5=3Yy|,`#^%H+(#.㓩8e`Vee@V1] ,i#"XcС="s8L|Ix(2ɦR.YI4ata NGAMC(^2NHpȐ|Im]^ 1Bg Fv deV|,2hbjrL@ -qZ3#A$amM;]hR.ͻaͻPTפveX[TdU)RsQm1׎3dx 3Hj&dcr A^ Bzv8hXhpZ$h!1׿7VW7_[q[_SG!6!)wqYu̚ c]1 *;hF/1 LGc*^lO] ?y(]Qu>"`q5oF'x:88]dqPr UMH&/WWT~%g:pj/p,8EjUj0Cz9BɉK-)ҠIĪNðGi׉3Q"".1"ʢ$2BnxrҘa7C"0X`j.FXɌ6Fi"!՞ ӯ,1-7&@"jÒqRW1\yYcUyo>%tLpßwYU!Ԇ jƟPʹ_*)ML;3& ?#Kx[CN5x\ҵ.uy?e@,W zaάi!+Ӟҟ'-b)> [2SXU@@b`X%h-CZ M6ǺƥUu;ӄ:Nj_apa,ɂ^$ς"^},$} |W-">o֝˫Nϭ^7OĜsSC[<"+HwoUm^H ' tzp ݏn5DJt2y_DlxKQ i pQCIjՖST-"Mf5$|[ѯYm։|XlbWpBxݓ5AKIhF@+xP>V5yl&1EZ As~.IB"[>Zhox1eoxq/ as"VR,Ι%"C5/0+_p!vハ)0sb-#'X4ӽuIΏ];b-l9B y3 -\#H.?3d93F3{ M<b*NɴGj~*S$C` М< R'핹,}Y//h!~/9:銣&'-.ǘ6e6cg5eVr1Sq=!:Bu*B9bhg(@7Ygmkt"emeng/3 .f`qcH63v Lgkɀ#KbFjج^4aOڳ\<@O|6JNu\wml nIvy]Խƥd;5S,t];-䕦eD"^4j,Cݷ2CŽpÁ躻wޜpfM&uA8m0O[䱴j_y79ڢ_r@"wΉ1V{ۼ{kW*_Q[;ZlɁỾwt6O[Csyŝ="#ۺ\S#ķ _-LrהAo!9B2pl>jJ-^9xC>kK5ƫ7^T(VW}j^ivxAUOk6k%"f W7$!͹RD$6Xp@Hj8(׳7wGqd}eWI857:cp2 ߠ0`(I Q#lR'%tiƈw* -^%8H5WZ0Lx6`bM^672m:a7Q mK s־.=1^,gƞv)8gh0;m\Iv\I!b%Z8o77?Ms^qٖLfy-lu;=49jp/)̴;22|lۓס=v p%Opnç  )o8w߻Ma StdfCo+s-m>oQ<@FIشmxM}"R"M׵IOr" 7; "xd'71Mgo-*{:TN;:.KRO\V\gV;u}"k:M]|sp&0e]L9,bJ 33M ̇U?+> 6. @{SgʹD^Ecnc92R'G3Av1͢1qA#0UQz+Nf] 3mY~Fb`Op7@_9Nlh'b&dyH'5=?qy &cEpE--GRqGӟXɯ-N?`ch2vѥ9KT*nP{-[]0˥@f{DtpQĚ2V(V)4-jc*w^l_<}9`D  {H ; #7@AX9ZqbRQ R@=:K)KSLwJ$1d`5O; gw:ӥsl=^TO<(*PFWbж #B[PgxށT e d 1ML/Q _0OZAm M} ( `,3҂||xtCOUCp hL@.RZP{uuzU'ӀS9d5Xwn',{@iR#zEA$Yv%o)[*ε@ pYfUWH7w08vn,[w{xEtf&fm}~ls]SaqVbXoX/ehLZn X:YL Xn%*亨'nΉ#k? (Q|%{n)+p0q5zѠQtL y+#`4qQKC\)C(}9`~og10.ހ,}͔ #ƒ?F%`sa+L63K͒6`< 5Ci :0N:<ǀbV:.3FDT&q5V!dK48ȥGR C]IFf}-)=⻏JJ㰐v=]vlmr8iv8`Q;;hRdȒb;Ԯ3d8ЌSdqev1۴8&(Rg!' 2'-G/dЉAm#h35:%n9`(k,+Bk wS:\g/0 2÷"]@zV,Snw j2ڴa!Wqوdί`%(U= lO": ʻ5s-8)"edց 1Mtt6t~ n IӽǛ{E8o;f‚SDn޳fvER9P0~1=+mtf>BDlU jt#1^pCH&fOuOgcٛՋ(h)7EFWRݖ5(֒%ݵfO YElZ]>Qw s"l_{Dlar7BI7tf|†CE?22w{U?4N4h-E3-ȒFڦdMxu{^!6yN^Z~YFј$|D<@r jI\,HfZFe4y|ư?Yda kU~0 3% 2lŌ;9~X|RK?z Q2p;e/S;>k /]c&r.E¦j>ݜFi&>WќNu3K,NVJ&kyTiii0lw@,|.N3,_X/, i5?WTo[5 ktQpGG( :+Ui&d}?3.3u-K1mzO _\Ñm)ᱸ0ɳTwx9,\_΋g-uBo&]ȯyQZFAW%%Űԇ^'7:h xa jR ^pQ[|tV>yo6W`9 ;D8rW~%偐trt ]H1!-`Яe1.p6a5A\d;+qR_o 5':𿨞yo2'),^HBʢtW;njc,jNnţFO(8<пqnna'lpfg Ǎ1z0YFtQʌ7qExYlS^q_X<=8?G؏;hĎ6y̟gt#1\iaC'ޢq ]o-usםUcZ='}#},1c33B8qQpcbvfFh;f둼 K.bpM79(x :ᐂIP&_܊D)d5bL;`85rh znmVmӃJ0!PϟFo{Vtƌ(vEa;c/ Eͥ;8RR6Nv4'ncH `.z;c+T7zqx^xg$쵇8۝MiњqH6Q2JEr2p^kV#pKx)]nΗa$x;+wb;;@>za"O}8B4 ꐋ6\ijoC͇dFV=/ChMgl^d2ɽICg z 3_Asu&ؤ JocrxԆuEy>l9ܐ#Ӿf!`q8J~7HG#oh%?2ih!emI:jV4# K˜<LOY@|iO}Z_8p`oὃ;}Hg{5rpj<`Qm̢H09:`;Z ЅjʭVxU׭2X}GnMI4B e=節^\FK!Qu1Ѝ T[^?:U㞎c/{ &M2sbRk{J Q5E<v6nG~ ʫ{^c%|r85u1 ƾd&}k*o1&8z g?TwVWWYp'qfśKL!ȟK G RZ^|b]Q@EXghO&2,Uzm>gmݏ%Ndg7"yc=MB΀ju:q>ܮH0 SϨgBHJi/, ٿh<\K|O3eNm>jo=əMl]m/͠-biTUv;q/^@%Yɋ"Behc7p®`Fb?s_/R)㖊ޛz.Y*>[= aN N.jn8CL@_>1尼L/_o ZN{FMkjqMQfBizGU+S[1dm?n7@E-.E5q4wbW*BQѿp¨]I_5O%kGm+56H P[)p8k pEZؙriF)Qk[8#Ҁ 6LV$6AMc%|-vR^1LrF A ` c9ygWH,$9/hwhIǙ.-DNt8 |yf_Ж%fQ#odz ^0!@B? JFBsRvp.é};KTX`a}8am.(٩DOSZKs|ռpL`PYg:[T*KXRY2'Cٵ0ޙ5RyxjYsObO2KVbdc͠%كe$PڦHMeA'b67{Jd)iG$.B /|Ռ="oSid?} ^xP Knc}DB_bH,0//ί!Ʉp.[ 1Y#W.. uRZd/SGLhi@>`af s\8)'ܒd ^i_=G]6)!]&!15uP9RT|cJDdщiCׇxIoX-}#:43F۶2Lahjf K::Fѣ6:3nT182j~›8.qlSѨ~U%YёMhf6)i٨ -[e huuu49$S3,e {NX1NS>87.jW\K!ٳ̓ϟkGM5!r=FI1O`S4/La$Ьz-M~!2+V2/R:scQu̦zo0@9iMܭ98=qsM`B 744boq2_pC(_ ؙ`Ĭ#dn7 {c{u:D%&ހ[KJkZmV5e(7g@J \p8g SCÝG8 9kC\j[617iAW^e<&5c[;O{|;8<^_I럞~hfkK{?u [T5F*Ol9SjtXah_@ɥSlTd[Eg< #&E\v;>#P);,TUWbPf>=jJH5W+wݪ0'mbMeX'EKoEwb.8ϊ]Jl:˄nty#VOxGt/6O3:0/oL z0 cɍepu XaXTӢSK+PVdT)TdvCuDtn2U.1Y[!?ck@06 Di9+OF&ܸiqU|?w("}~̝lQpzeˣ֪ز  obe7P82l5rcaAu nAX/ЖO'!6: 7]YzI#UyHj^txC{ޘiCEH>B3"#]_k"9&:xkNWgή5} P0y `j8-t{٘+*"#0 Hԁ?EIxǰF]|q2.PrKO/#c6 j걎p nήVˁr SmY2ܵbyVhQ<<(uBio;e,aYNu(A[HiTro-uM4ջ2jQ m; +%NOƂfnTʈ5l~ZJ$A͊>zϫ*&AfֿiX~auC w+hŗ"UnY A y ate.TBU}{ꆿMp52jڪ|LT*|RRl7RC$b^r'fq޹d+A)BiXh̓1F=cYYxx10 ȩu7k_eP^0QJ![@;po-- ݪ-ɸ m(+d*8iZR&-K / a*$t5ZSхɧnjciI .Ո@׌5 zWvHs;rI8uf2.jdՓݗp,8ҊR1wcIu3o9qA H7xˑ7)-rYnkCՅ-s>rذ*ƤEJ3 X {oiɥ޺/-hTKVX2^Kd*SI|lL@^O=_GE̤ * HKJֈ_>j+:A03)R]gĜih7(QԌzih]zR7.JQIp䦔1UDzWGFJc.+=|R.2-^3!ހEQM߆GNؔdd=1]40zhk`Nib: ѧAtbAs˸1aB+z)MI68.RrՀK-֮Axz.thwtً‚hH,e&{YC%1ҩ3:dùu%q$9IsEՈNcq_9 4̈́Dνav̝F9O|tݮ*Pͅ %}r/}r a)Qu_|k ]CZXi .V%3<@ Er ZZ) 8BE̚- h-QB23Э=IgyOKϟi9r{]TJ_#r~8ĻV|_s>P:m.GfEfݱqWvخXH{8 zc\BL7YD+"]xRm ا=B]k9L:$J]:J=2?o,QG7?>^CYcUUǞ$ 4i$cbv7܎}lqrez Ewck QdOmoAAP9%t|؏,8+ZY~^oZK ԗ0U&7 . 5]XzZț#=Bgܐ{;cyecL?Q21HLk8gsέX:;\rsOG?P?[ G :¸OյF0 0%nSt;d^ёn;վSD8ʀݑwN{WE0|||7?1moE|1 oYw$(PxFC9Lgz<N.F9p)Z fgĄԦeCZiȾ\i;v+Oʭ-2q.\!YMg0#~v'MHxkt#7VEBCN߿Vep7uV3)yDd`H*HޕWW8,%.sgܑX1BQ#WSCmLctwzι4FM;N:,W{GX5rViT҇dRBgGj|ćH]# ߪ4riumJGZ?}_r-2av*I@Ҷzw=]M8kS]Q+Ѫ(eŜ4Zd]ϥN뗓T |}AV7s}qDoQfޙ-伓D_97 86 $6v p-ݩn,ܔY(bkF0 Ie0.V-^,L c&X8̀|\%X~)=0OI0#fRf_RVսWdIpP;ڈngf\y^R7u :Af7Њ--v9C-Cr 90a@%"K9D /I|qUrʸ {1E!ɖ&BK ~qѤOɓ$yggQ!BL8:a_m=x<{ ][8߼{@O{ɓ-~䜎eTYH&C=Rx=>ڻOÓћe ?K(P6#x%6XTgJZݿCTk޿{Vv3BFז"?ǀǾ%g,8P?NWk!.bqqoaa߆1^K{G3GLC=5"ϸĄGph`ف(lksl1GGBvx@J %}".xrMV쾔hÒGTiCm: ~?}b6k 'io.dfƸA>aLOz]ܭcb.GEYb`z6DQe HȽh&[І=b _]홝CMu\"|[{*.F !REa!A^ERErOj2Z=Z9HE .ʍ(,%WLB/꿼d7!=CrJ,Qk}˒uc0 Xsĉh*f8[zy?}x9~+814Qk)Gh>$~h5+MuSR(d%$z a80qk *{ h>[mOiOCNd6 쩘]/蹘gHܼ1;d@u\6ٓzAgazb|d ,z'[1UH((*ZCiHbU9Yc`ssH}XtQ/`pۊӘ*#D!ƵU Fp|(h7ᧈwP ~\/̭@į`: NF-DS>U+-+ 0L_=3nm{`elVfW lx;:]uCqQ0mNBS tЌ܄d똓AJ0lrfeVH0TֶJoīJk[Υ1SY$Y"&}i>ym4®ZShD@4w`jFXʤj~ogZRSD|e!0=CxɠwQE^xZ`4/JS#]#O:9mf$:ÅO!fHd24ݜ̄#~sB 3c6=x'-eM>YMWMX"y٤Thl9% w54wn-}zog=cX]iX IlwHpKwT]BǙ`t(P$v>%?̎! ~sMnhyQx#J*FєX_m<:p[͛h_,{_ebgG-tTCxM9jª~t9 6)ʱlfarZ٬%@Ўw<;Auw]}1 o8pdə3*n)1Q̠t:n 6b Y9wVt-qY³M  Id )1 יĬy2歫̮ks+u6]]ӿ,<_[lˌ%q]p A}fƚ3( ε 7 p !Y7I}i GQ4w}rE[zpf| bّijPzSU:R_G֠ g8)2tNG̓EvT.*C_M oѶrDSJͱ7 7^"π0X|_/@~lė~E"ܺ$3n US},{D3ߩ^x4wR#%*Izj-PZ(̏<Gd7 ?unks^48ZBewGܐf^ r(p Djj h D *FM,x4@"}pk՟dxk &ع˅/ DJ(?1|> n:F\2Z@VyzOd~i."fWEݬRFALaI6 ~>*7ᩋs.fmk3[f%ܚ/x^Π>#'݁h 2¢Oeur H2hIF{\ZUxG+5teĪ gc8O[8OwF5sO9\eu:f_<]EoL.z/w_ `cnZM^c](v_!2 fayV<ت3F[f3烙~̈&F=;~M#2 l>4_WQ\F"oP_1 0 ֈ)B)F^̶{:B uɄM؏0^is n:#ԿEN0 4Gڠ4N8BIa Cp'ƃC)s5r,0 {qRooԹス}=x++CZ> G*;Q0ËPZƬRr-lr/&d!‰,4B+z+4|DWh( |=d٥# ;A0fF`O0LX(q^V㋠;5 9[{! NtJ1:7P1?FI pPכZoQ8؜ajtufH񆧧A'z);f 1 :sfzF'/q}>{}R8-TK^th#YBU׹TaYW? lU+~ W5H߱Hs珺R.F]ߟ~\-<pX%S@~'o//ћ[ȺhTŋ,⯾^yaVȁ?땽;?5@Y}%ׇ !tZ#*e>aXz%^L,⧽r;Gjًu|v@U! 3 &4DBuF!V͙`1@f?/C^1i(x Ax3/G{ȚaS!Kl4J|f RAcO°4g1;..dشGJH ؊w>0 b1oí2Dq M/>*DX_Q/ W&F'xZ0Q\~8ہy-4^7Xkmt`.cn fb=*| ~\Gc|WXb7[kI6ER&'ZxEcv7qk `WV!ʪ *'*mT /Ԃd-P\ɅUB 򰮊 L֜*}2XYc+k Q//"y|$5HZj/"5ƵCTj)e W99؜ YRF M8g2^*oM&9=2鷩e@ j ql6 V8s_4k~IʇuuFhQI8A&A/p+4’JRqWdy0#zFPA-)xÝ}+YUW_}U=yGp9H,>X(Q4R,@VJ$R6cTv!Fϓ(@ b7"P HI`ĝ/?ήCfH*1G6"NljvPFU2q: L`5ųӘMZUtf֬ZGo]|Y} 6αd\xK\|TBM|x_opX8ɱg,uvB+߃Q>]o1d26-yeTWI= <-_y*"L[x!'ܿ[+ UOu'5[S>ߍ1 w?ćgV315 b-ߤ8)NrfXxh?KH.E0dxqoj6bvbߓH9i0&RlmȨȸTW@<ՅK5_qkl_z3.7,piQD"Ή8k p&`z8RW=4Tw/tdփ>`9{ytb {(^=S%u\ gg?9>lۡ]̊Ili0pCޟT=ϴ2r%j79X3Z"hX-Hv d/~|ճfLFr3worpr9 |x~G^7+zZyәݛ"wN*~j+N5iġˤwD^gYȡx Ӊan6?&c8&ZcM6_=: wjm>u`)g5 7MȰ{i ƮOT1V=ݟsو^93nXsTUxM]: O,rNM g`rucwhׂqϻ4 ُ ұMfl)YvG&Ep""bUD=Vwͯբu]w3睍4<16`^*ο->&_TweN>}Dp0hw[&կA43K |Cfp|u 1;SCiP@L2Ʃ` XP'ecuR;ijZ43 >=ENq&,([ԗq< +sܵ;=&[K悒$jʘOc;+{Z' PYI~3䉰`FFưh<ݙYt6nx&?M-CoC ziYF{ٙFxl#C|{R O^ YOA#į$ms@IS r&*GG2 VllʴsUm,)^c63AXYZ]-0U/Vj->) _TKk=q_b2PK()e;a|i|! *d"ҹXgg1h-<lӮ9zŖ )W:lN:\w:LLٯ-ڦʚ_YhaQ2Zo"h[[m}PT[8v%wzEsƩMR%z ,eyݻwש*]딭e^KG }r|?Ē&.L=EWM!ѝv B6PC)"z ?Ǖ=8# ͐9 )BL̟Q㘔{/'!EA|{٭*k/ł?R,.Ƶ4 T=%rҜ̀Wh_)ᵈmqYTwz &z.g.]C rVqdC H08 10kC+4W"&wnxbZr#RHk۾o4 e 8-Ǔl]6=1^3qjNv+cp1*ߔ'G\I?C6ScpcR0dſ1m CDN` 6kL<2mDkHPLT߇&ҔL~L: R\俨6hIa/0[pgƝ" uOF804e.m_Ѫ1ݰRFG=u@ۆ-fYf")^@lQ$e7FھNȫ3fỮXέSiShӀoAMl9VmkF|e.> s6ɂ9b{@cȴ7[kV,7&KM1rltyY3ov΅jH n2-Fػ9]8MVbM퍲h"+ǂB,IR8|; 6p[Dpxǒeg&D0F w,lFG!vP`r}/FO\ᩊk.'W+Zq0.SDdܓܳx!5"bN:V⦾yg9u2R~e16> Di1qU"cRZ]U}W0Nȹ[l}X H9L8K뛨} 'E^}9f&&=`ZvϬYvXWXj,lfRјopnhțLۙޛqtAƒŻĈhHRoС[=Tv Ԑ)C8;+ u(loJd^g\óe.z#liUYS|T^F,cϏĞ-Q@W[Ġ8p|ީ${ʜs&eZ~_yDB iT/v c&{$gW~^7_ EVۛGGK=P~4 b]js7ُ 0!,qV% to^{ɓÝ㽝{vcz-ۊOlol|~'(Ǯїr%\7x!.v_mkɼ؀7 ʋg܆evfHb_,zUd0UQum%M'y2%؈?ZY2:V:B1>f[Zj-P/F 2Mԗ. 4 %y,b Ku:xmM"H.*ZVb=,mBo^)78Qh 8n Be#HA0:Sķ:+8<ʬ.YL"zd HAA#g埁(LִCqq_Ց@ w=0`CQ _ڙcMcdMSpQ;E>^۔Iei"X9*n`۽ǩAlXZz݈q`ydTj~{c&f[q[_ch(,y*>Xn\%JfM'箃LDVQhbPl$q4b~:?C9ߎ{lQnU(N3:A]]˦b38 1A\]lı%`Q]3圬ڋN#N"$lؑj!ao Mz { LC-#RÀJ<Pn"y'(* ‚GMydw^ll` D`a|b*"ӑq_FRX>t8gĶH U8ְ>b p HN\MI5+0sb-#'q4ӽuIΏ];b-l9B y3 -\#H.?3d9 pNخ <HL߰1E/C.Vq%\{ 3i"$D-]: 4wP2)"/`߀7 Lr|Ro{,YjҾI2Is΃`PQ Ty06kLWjue5L7NVwIf$?\buh:QH u ٱ"k&&M;!,t(=J{tH^ʻ̽/LדV\^;%S7V"fs 'jo<NYmXnmyIgQ¬ T4%^Qj Bo -6r^'袦A(T6ݗqI坡p,qtFr).{w@BB3Y p(ipK &pR;f(  R&NelmCoh| pc[$K xilTc0\Hj>{B t ʺQU?Co?0x $\Hlu1a#'cr8HgkXt8 Z[QQ/Ii`N3]_=xn]> Ry5iC[bjJ&;MA;5Ndyin!Tf!G{i>XY2сm5B`HN S80=#]wS,tp` ?y,-6F>r@+2ʕut;m+eW߯(魝D`oGU]; :0u[CsyŝUc "~aL FQ|tXTi-a25d,cՈFW?u e6$C5}sX&~‚ HɅG/׭'P<4ꃹLNU.VH]EC6-q>f@0R:1n sdCf7Hţr,$8@rɊ/hY% /ɒ(D'_:KT5qWth?F17D5;q/]t Gud%kUY[^~76lbղqkʠVU{Xi+z W(jZ/<~xR[^QI0W㑪Uw[?{# Y YzMJs_=%Pꐼv_zR("4ը6d xAÀ6fpbOM&Pg)P ^0튱cq,kz$<׿Fǵh+a2LMIm6,ZXKm"k9PkF|1/ign"{m+)nBu+)dWEF?ڍO?Wܟ&ce %(f6x`:LC^+V ’ݱ0c+קּH?P;t'AEӀrld縌v);f̲,Z㻺r*LJOTz]gt[v9y*7 5/bVmo <@^BIشܔxiMz\Wp<Մ>i:|;OQWqν/񶙬E8x]zz#=:#,gܹt3LnRwS g5ucu> |CK:*z1#:|nQ Cj ]MitD1l40Gc@Gg>|^MZc>u(@hyJ8G6irDUt1T&W 4LZzd>d(, 42[0 _i4D&>+ GE˚3vj{Gh%q?G;3'@:11HS˧)iPg8'W8"senkHev°2ypr3׀2E /Xr9niJH 3+Ok\*5OQ{Df6d XqXU,n^EMW?b4˝'/{;lh5Ccd@}`(7G+ND=CsK')bGfrDloU6%Heܢ7}֊[/0޽,7u*P'|DQ3@q\iPD.u 3f"Bgf 8 {!z0N%]8 "{Gͭ_7J$&+\E=kp{2<-"%@h/%fAaɍ&?wT51$#^2E= _S>^\j|N]}Ƃ[ SLwL$4k)^F3S~dqжr<m%x۶@B m xF{6SÝ6Ώ">lJZSwzt/gv4RxXOpGp(W8L7'0&З#A(o $yѠ0ww3c-2X9F &$^A}8ͣItF2/AdI33:`8/N˦38l nBt7oHh4v`:sJmM ur?LYFcFob]_2ÄIv!]ŭHI4=B(Rm,G^ 6a?oͿwPρEQkJ?3 u8J yk߹d<ȸhΣZLi#+G O;4!a6@"B =ɬSu+k0i$>ޔ6IvGnJR\Iy&v:FW ys9ㄤy%!Ii0_[i.">|VLԔ<(ґJ8M ¸ʩPO82CR;d_LTqy"9ӯদ' v9!3OD2P`Z-(f"dq'#^OJh!46EC/%8@UU O{A{zsd0_sΨu\򾀾đ s2hJ)5LL\6 Јpjʭ-m_*1Z&v)&6A2t{U[3J+&5ǗCf/:%}>/jJUS!Lt\O>hy7nר2Z43^6:*uN(0b2w~'Kbe㝧Q}u6Ov89ΐA)hOP4Ɉt Ux {/˒CPq =2PmHJ>1 0H,)e_X7I%|p̺aa #!\MZMQt&&dک:Oxc#7Gv_hMW~ċ+|AN̤^L(h,TP@ơ%GdZ'XcF^_viC_3fdw^yizJ)­m& U&,0wc;yD@=&Qy@7JZg~nՖa%ÊIHF 9Tܘ~zluXKӶtv#7X[,Ȋ(r|I:.^Оcqyl'NC^ A0 Oǒ/W<LJۘ cF3*dEWRH ˌ%@X!0& ʌm>݅z4?Mo9L:ե*0ǁȯrV]AFg=ۿ<{Wf%8?!pBJgt28H Zv̎mxȬYSC*XAި`86{j:/P:cd~rՏ"zIP\jO84glh_mD5 }|C'Ŗ4!`j&Oјሄ0O21If|N#+ 6Z :܂O78=1'C=a8I(5cȖlrYFD"D;Hnh|3v#$,%5^-K Vۘҩe.E%3\\j")ݣűKx oea -{0IMݬ[;P>:tHg ܜ)J%vώLIgaW%KSJ%4.=4FǖXQfޞolXʈFULP+]XLƌxr$+;ќ蜰Ď6Jɶvs/~3h81 )XSAʵ'@ ˒3$ۘsMn)畒,IUŠg:hyBGҠ#aV`Н =|yfЖ%f[QP#oah`C-Vm. Ӆf礴i F]:SvJ8Q> 雭F-eh5wEQkYh9&<:?Y7 sTκjRv!d`p̦Ic,{ĄW -&1~#k-q`@F&cQ)T fꛋ2Ɣ4E p,4fiKѮ$fI˞L khSf&Y|+#XC-c<=c9ǚOXNv{Pu% .ᵶFtd#Z=o8xx{- B72;At)ѯԑ2"o$ >{TFB6*X2l(gE?& 6 >*,hwIjLC/Cؚ $h)@kc[E90ơX6 =j ^a]:SO W6%(ŽiLID:aeuGɠy`.ba[? .m^nbE}wNI.ܗigvDF=4ڮF%-Uu,}~6I#JRl9p9*,;-;L$(L!CF6јOb7<9'eSNxȜky`^I,vvoO{R)ban wW]W\m(A2湉c6iCBa>OAb ?H'hwה,o0eI'NҺV#:4 2ڶ2LfW<BFtÍje Do[x+XyS FCJX녦)ZvNCӲQ= &X$mIp foom:Fdyw./7lOu[\. wG=n"9)N#HM7pd\@#.O֊jN(𪌀+N4@E JT<8$N6X(1+S߲ɇ9Z5JkR[+K,3g&y4b+թ 9O4v2x3/%XIM+[O^Fz2Md"`lZ#*$πxŭ'h@l_B!su}z1(-4O;mܮrK10p2FëxͅQ.|sKՌ_}!c*H睝]cH\2&@(* IlT۲CC\Fjޭ-m FCfm6Թ@~ \ ntL`$@6EbFm~/ޙG͓?{-o.6 l)7;O@H|[ ~LۍWbY2RGZѨԶ/lw=.atf4\ ,o72Ȟs'IJQ/*psǬ4!xAj<]\&m`=V^ZsbqY{?oc>d^h+V`_#<; ȸ_7V_]_n@׿|\N4fH*}SybNȉ=ܓ^RYط}tk1ҞE0EL0U( G?C>%M'_3O |_IvkwyĆ LK^/}_57Aڨ9.S$ 0s?(rnU/a.(W?(@ۗ{kgB]./jb9N|X f֎kg&[uIo1xa;Ž5nzjnIϽz6l4FƏy3P#ܒ_ M*.agu5+Uk 1܊gI3V,t꧰&@1xܘ14-Y`P7R>tlݑLG-z#Yѹ7U!`,`rgYTB%g?<9bL)p*%wogĥBcMZh*آK:< 2zcY[\ţ)s ‹M'+8wKZp9wewP0j:=Y3ѩ͘zVKV6Psk(r22Q?]h5gCPdwxM+Oj"RױS? Bκ BG.?}Swͯ2fQ!k0mq2>&節>cSW)faJ>97l Vޅ&Gj%0(\QwD5Lt:Xt2]"㟂ݑ[hx~Ҁzx) ھ >@ OUȨӻtƫ-rSq*t:6{Yk  1] lQcɠ(dԃ8lfxy3]PM# ?)m,'=B.P:!>ifuQtFO q`EAB'z;`Qه'oź)qaD6cY$[IGSH,v^M^;LvYPsX4bej\(5>:s%'0!yJ݉E! 6y!&x[Rx5o@0mwVÌ#'Xm9'\T 0GA FSTfI/MYX4Ȏ>/V-7g lVcs#Kk`U{e32E_DY n9z?ػKHq%d=`"T 0_ a3kyE@YpSdPGbjt0@ya{`[Lٗ'yfEk$%DdF( ^wwkjJrS:eծ^^un58IUdZXKd|W]֩*ө]딭h0e8Q1=[oTH#",jU~cY1Mua8Ke0-zċ.6PoqIX,L܄UE&1(߸$[ē)\dQ.F%4I-N] :#^H%m.Sr2'a7 11o)cD[ǤJY:9{S#.oGhbV~%;MH7p:-Yd%ޗ~yf;vpRN>_t NFp=qbUgHǏ,>?R>gSTLI/S&*FȰ>$bXX_ܐi\"3##33!ٙظ3r1B^h!UըXQ&D[d0s*QD%+M4[CmWx+vs&ȪN(봘HcYoψ :cQXe{_1 -}+faC" ӃD3fBQWBu)TK)cݠkEkui0kCs7g# E8P,q_jb;UJzS'BPagYFC8I>!b~kKDZ]JK ~5^ݭo=m"D7O56Zs#mSF#4:k+Pј=[+3]rj/ iSv|/ޅ Gˤg3ix٤u/ ğYjZ1>VX;O>uTZYYQv=k-0rR|aoMlFB F8&FI)҄Tq^L R7F CDrӁ$i&.o*eyk 7,uެcEqԝXsz_LrJ ' q2"zE.~hkmջ:2f{+v.WhL@t@# KrY1(MحkΑNC A+ f|A?ua>k.'w/)aw/>yŏH&0R·8($^/ vA Ō^)(V'rU|jcpdc^|P_wjMVõz߮}w8ɚ@vF69ȃ[bids6 WVFXi4ޛ6qd ßѯ0$vH /3#KjE-lU]՛$ۙqN:!MR$H73dnKðR$IӢFGwđ{0S %ߘ&(&y\=746󟊝\\|76-' JUc3"r 2a)lb*GZIK|bƚ1b)8UbX}Wn_>Y|*ysG6SpDbnIS8JleUufO.ff% 6UMKF: DXxFEZoٰՙMp8NGW>*&Is,{|C4gaS,qJ{ “J8;  B< I1vw_$&l1R3@r[?6z,>5bG*N4p90{܏J1+ޞLMLvT #;X;{I10 5b, 2<\2 <}> FlLˡ0.`F~m )m J3҈!ƱRiq*rOvNՔkQe<^Dޯal"tT4r(>;F|TM{`fB38hi?x5Gx')8|jп/ofZd_Х g*MY73l3&oI'Ss"=i#cE*qQWV$BIg|^8Scػ1c&OHmK3Y1 &iC/;;[{p0nv;f" 3`#gvgMA ؙtktM!5EAc/lJ'Dj m( L遉L\ekd,]-5p(@gJ2c о!K=shB3ڳqm%wdggʇ97Fh8(u?GRm*QeIĺ٬M4R>t"adD<dC #^Gg$Ksv<v8GE׿`Xٚ<ɰLZ?5x߬*P`=_M{jÇ뒿GKp ۰u %,:E{8&QP\4vV^$`IywM$h-laa-I*oq s KPe@bcyK3XcdzuKFP'6iļEleL i.tqhgKSngㇷ1h8Á̈岺N31gZeJ0OJhg2ci[OnrtYu*qT*C-CByۏWgXԋ"Q| O cP(͋EV0K,hˊ~.W%N1\m7n;ee,]6I,-"ċD6\s^rqEK$yE9-ZUa#Wp 3Xnڠ s/+~'S:,m^,J&bh㯴UYĭc'jlFΦI۞$]j֯]7>8Qؾr+V) 2+D_ _xpq^d"u JaQ/w^776wrs%icP,8$}6^aZzC,Ԩd""Fk0u#廯<oTuF]kWD3 ەhp4;hJ ey zkiQ$lB'twOy3}h`JlS,MƯsx!xRңro U;S I}-dQ{9N _,n j<;P+uuxR=dCd0)4E= 1#n=c@vFLQZ#Ȭ>B6P@Sᰣ-)8 ;(-_Ӛ@/ԫFY;MqN|]_)-nUh\հ_v\Yb)F^*Z{YtC@ڎr"P'&QhzXYm:Ea{ګ>yQt33qpf7}^nuJ>Dh':YOeZP-' z`:{ '=FJ*128fxq`ƏE&SŋRYQ5/q&ωXo;M. (ǤPTO fAZl'*RN4%L3c 6E4.-hv{*N{f(KlLӏa?Mz}:d[ӧ؝®bK|VzXf>ډ/]NK(o ;.) ,=þ%m zU2Fu4lHs~? "2bMM9rnzMΝ5L43ON0Sݹ9&% 5f)ڤ"yK If򶙁YL/wr( DNw,bqq"74^QrM^4c.+8YzL&@vh?7K'CPG֟"7&j4z}*7*_ZX|](q*/n-LҦ.HA*Ceɳ`Sn./& C1so?%y(N=78޹d~DShfnv9;×1b ѼPfBut COjx}NPF9f'qDMu̼ L>zpeqHϿKoڬ1ZkMCY;r%W< `,&~\wuOY^zkiRGG֕o1$r#/L{7elvT7~e\w0w=R -8~.YRl"$^a(D<|xNaSD6 p-we"`r sJ ˶tdN$G{2С+1(pד#iALwOn/O1vIzy^;*X12ཬma_ vzp@V^V=-眸CS'*N8K4) I!p|/աqGF1{U񢦄Ɂ_]I彇n=$'DJ&G%OR~"DKp5)LJ茍7Ѡ;W|3#Ƴ|YCedD/?\幧8 \*:Ǥ[0]ENdZ T+LrmEH_2_; 0^,Mid9c,eڸ8)<]g#C:,diI.@t; E0% ĺ?{`W?: @Npʈ}&0Ղ\)o행% grh^+n4u dO'!Q{~'zHأQjPZR|1|gX?TJ-bmDCG^]"FnS`ja 6MOQ|HaYpqL~0O&Lteou[i=ly[j'Ayrkgw˭cn8F=Xऊ%,,}dqӉܽ2C1(#||djѮ,BoP{RKE6 @[zaT%4==u2CL:2,:|rJW1 `ib`|*pe?IF|y_1  s ʤ.YD%0RPr4 4܁I"zL H.$\Y4zs6mgYS%;~P0uq4zOaI4RX+6HfHn'VVνZ\ѵ>ؘ}\#nMcT(,2!)qYD흦Yɩ F/b\fcME;fIh3žk;~> K%\,KC1:FY]hpj,4#PUÈ".&̺g9Y8q,8Eʅ=I҃HYIbWN\jmrE,J(xJWzt(@eQHT;J9Ұ4 ݂KǡQ<|2+iD!;Ջ+ os"@"MrT=ŚW1loI#Qyo>Gv32U~ل)yE*'T3Q)F!"׸I&Vb#GLAmW0 FA{G1].j 8k]R?nuzA=(Bb V Vd`K!`̫.q"Z|SX[<U|h gy,K2=^+U/N1u="45Hs_? zX_u$ŅŅQ> 2o&tVڿ>Ys6[O] ~gL4v `ʪNs*X0E-HF-2v#kr CՖST"IFEgv.Xm"m)@9I8"(50nnHZxPœ{,VCaE%yDd56wGIB">Zh1e]_q_R¦E­!3KB$X*kX_ K?18$EWT.~xNKaIϑ'i_u$ǍL.㝜i6^Xr Tk.MD$zNQ[񭁭p)uxcB$:ad+oIp]kd/x7K_`UVc"$̻գt#[I4,p)췩Te6aVr{ZOr1Sq0o t Ķ Kx4`Dq vK$VzZ~Yv[lnD BDb~9 $;$a Md٫zHͳ:pJ# ,zBZzl}Apm}-}&)duQꗢ\V{ 0w>zH:-~dD"^17jv>g8ɀ_8+LO@ݽxS2e7C?mǒB`^wJN6JFuF=X0_U|q zTe O uӠ`v 5pzzm΋t.dx0<~Mxؚ? q`~О\{]u|AD81OR*萘6Z.doYƪ`^|Ci“z<}sX&~‚{l4E/׭CKQBYzShr$!:G cZ-fT,>bwNL%%A UJ $LSTs=,$4AB-N[*Z\(\ڏz]S?tE^Kg#:KSV& QY{wVl#4c5Z2e_ 'F.Fͼ?hy}~-y)^} OTUhs8PF[X+U.R\mt4Bvې"5" 0"/ ju,c_J@Օ: ᡶ?~0q6dxArÀ6fpbOM&PPHDWZ0̄x6{c9"GËt 2:E[+CMDp7,scZa u&WsbYc3/8} Ms乒0&S%䊕:nn|x4aX7Tq*Mdhf2'p#6xP<4`2gNͷy""uG@|0mRjK@ }{]t;>uFO?ϔ~h W&Sf1^>:;Oqh|[,̐J^.YsV|HHwx_$S,?D]a繇E蓛'ȷ=Ł)On`z;.u^9V3bR>ΰbsg^şBp.n[c<7[֛ 3 hY1DP=37]؛o LF`N}]u"Fڱ\&h/{LlӾ!p -{,'0tFPh}&NAQY֧42Y0 C_ԵAd i0:Ӗ5t}?ABl[ +lDLc2? EDa.+y6o&uS/ni9Y涖TlG=M~- {l'#|ƁcͶ֙ߞc%9rw(Xr9nirH 3+k\*dHG< ŚY--`ŁbU{25]ѐ7כ{Ϸ^ݗ{[ۛlh!^ad@Ð>0rћ' үՉg%XPwKd鎩fN#h4u!P86vUms RM|*eWf-U\iHr2X!.Ǣ{NvKula[F_,p3O$G(or0[jV ZF_Y_0>oa!fW-wT)0|Zr FKcn{5r𽮕{|(_HC9 i޶hJ)5LL\F8jpFuabb nI4q4l7(w&WzMH32k/5^t !dK|@_1 0H$)e_XwI%tP$̲a!Y2qTs!7i5Eҙh ?E;2ck/֛/ai-I|Bqu)9 ̠-qW9. 3>W/ʬkPvw+8yc.;R`K(xd$*5z-rqKE州KfqF2>߆zI8w)Q0,9(Г8-.@քu\eĸ/P׉Pf0g؆s_Gƽ뭗tp/$X_|= ʑ|.:~txi%slUKh.QjL?vRQ i %j9%c԰#-( Jx3/p :?b5? pB'Jgd#} L- [fGL6xtKDD<{$V, )evcB VK5*M!#ڣ ~}<-e \Eެph$Tw39s*lB|Dv 6 y|]Ŗ4!`P5 O_~kH-/Q ?h}TH2۝|2kM'pP Rv>ǜH f$Ԍ"Z䒌@;pnhx1vĊj/%+emLTBlqSD2RcâϒQP.5Ѣ]c%T[y&-FLRR7֦Nm`j2Nt1&&79gs67gfPxiųz~hx5W$_BrZJKLbɩCC4<6e+>%yDΕVZ~P`cV;XfjWW-aD & .&u@DcF<9"N$':',RvmDyܴ8K3T#fbaV`%\{,l-^9L9Wr$;0RdPu^Na|'t) :^̽.ݕG`:lޅ,.d)m$aqVEm<=Z/D ]Udž.ltI9)mAFؾ&N.0wDZU/WUj; -ϙOœ?.ڳldd$\+iy51!ü"gp̩HǚEC.e8Qh/Sر( d3 E1%M hlS+c`IЕ=&Aֆ̄M.W44![ "9xz^#s5ak0:>z!zKfY?C 6e;],km,kmc01^4Eҥ|GbgcGRy#I`٣21V9Df/!C9c.h9Ji1W&u@jN7czq֤ 6F5+)xm/1e(ڔַ^QSR7O=u\2of_h 9 1&!ɺZwUăEnG)ȊmuLHp)96,*[ԗsJv L?d-̷%6t V+me~LcDŶ1-%NYe,Vb{yeiIf'AfB^aj (9tI?)T7tjC8_0ȣ3Jb1^G}J؋=>A&]CtaB\q^Ou@esGlSGC d}(8D~F"O);Y`ʒhOuztVY=6|p^h |63[qv`_rZ)-W=Do)EQm U%,BS D-Te{# liوN{U,&s]bo"1ĬuY!^q=]z^yp9d{\=2pd _jt̩ՈhCф=櫤 O- TRKn!kD6}/22 VM4I\^?: 5wYW^lul2߼E|WqrX! u❞mc籗N1F (jD}W`I@¤umqFcfm6@l6Jzb]#$ W:7g@(ӭV y P3-Ajb.Zxp4$#J (]O[bJ|X˜1`UsT-c۸1`KM[hMeņ6Q 37'kJX8Ʉj{NSGW hɶ=Zo7zJ2ZMԊY2Ykจ1X|?>s[-<:2TkPpmɊFS[f2Y7or^o -k|S>]Ѷc1/`{+8ݭ`(fH`\eruh)+c[6˽'ТyrChRAzSyf>Cټ5vǔ8!KP2t|/=o.H PwNT`6`3OzaMrH0 ڞ&va&d Z-9 R0cf\0 (c,:LrhIQ_wl"`{*? .~vyR</EvndveN =A'] Lֿ-찓+@`S#վ41l- Cs)I̩w\f'  0^Ev'-t <43eyW$ 1+^?!L΋~iaQ=TjWRoPo:7OTҷJRO_dm/i_~cRLgv.Suo_T fϜjb Xz`VLe]s2ˡ?ed YLptgt '(i/"( t^!wkRrCRbvlnPBen<νv%߁Ɨ}i(rzZZQ:hvsXd,o4V :Orz 6U\LR^-(OH2R'!:21=yr|CZ/ &%;OUNPBЩCvMػXJcp bE:_=H!hh"LEkKz)3=de@dnpIc/7 7 u#{ӒnkQKFMGF"?dE)󸕇KU\WmkZ5QԼr-//m̓MZr}xn0 llW 7bLZ3 H\ֹ%lKnm`e-va9MY,ua‰F5П ֹE$)|"!kt#ֈBRlecOs&|mo 68.l_o\41eA\Dz/inxD$ݢ`ʘ #qj'"c%ȺjQ~ز-P1jQߧ5gĜՎ|8L٨ ' + IԴF:HIbӝe\qMuBk78Ư8njW$YdMN=0`㜥Og .E( {kU/OVp4Lp}"uCث dD6cY-YQv_nu2$aZEgI1c}m/M,M|5繠Y#S\v2%C${5?EtAD$Tc .;-kж|lrlݳY&jS퓂ζ#7[3o"Rw7V+ V zT42;^=~+m ټ/ƛ u{#rǩWp do1,ĚsM^E 9]rNV#˷u jtBQe(BR[h)Nq xgP(hD6+.U xpNcv$l;: ~ke'&LDP$"2@<oY ѩlRIꂃqfn5vRN>_M("%K٩܉XQ EZ0/V| '/vc tyetάg*\[8 ɦύEwWlhCMH3JmΌ3e ƕ;/F1BZHe$t'jXWm)ß@Ut &B/Y18t*{-tc4LD)+U)Q^2#]u>bd5}{Jdݽ㮇LA=GI}4Wat):"LJČ;ڜוd'pPoܙ kVu00 FnH& :jW2|^n>~y<\{6xۄ1/Z(Gh'08d2F3xzs=ా0@cHtnAڱy @F$M-Yq&zjDG"}iG DC=LR#5o?x0Oɀ p϶*4i'f eNHEj{cƼށ}E!x\E|čGFa CrTc/ǗtҎP"퍆CJK,LoS -=(\,ֲI&od8lHG}J4??~gD qQCC}y߄f$dcOac"DnB^!MN)KL0 R쵞7FiCDr0>J&.=U{2[b9ҁ8&VWϽyԏZ_;ς^q4=ؽ?v(oE.iӄ`{ܸ|HPQ52E< 7 /=AF ̤owfb!}u|$ʀ*B͔)+R=E[hkf.?u|eI:S[\H ZҁLF$ qcP:u9Zd#,G[!DkZeun|mS.?ΏN&0DR/s uZZTExH1 թ'&-s#182}YT>oåEjÇZ~peV_:J&(hᏅB9lr[G팾j pWioTYA#ьkF G' R?4 xIҴqJ޹? (7H 7&6A;HuFύī)b'.(M 1RL܀)鵂~Xo-션Q6(r2shxgu4h* _ӭ}#J'vTCӮnVG"qd0X<w173|Fɶ8A^3'@j2eAՇef̲Xf +e~(d_rŭ[mpqJQܿ"|}!":4R6[`2ZlӧYds2:OSj0^n~/KZ^MYI3wXJ7,3ηӑUi % Ii` q1À-eKFsD푊 `N:c5vLcJ'_>=ӡD);6))v:VϏy.l<|[ĩPP }<\_? KH4cMxg>ؿ*AC;HS ڳ)Z4-;r÷qOWޓ/R#10 5b, 2<\2 <}> FlLˡ0.`F~mJm J3҈!ƱRiq*rOvNՔkQe<^Dޯal"t4r>;F|TMz`fB38hi?x5Gx')8|jп/ofZd_Х g*MY73l3&oI'SC"=i#cE*PWV$Bք]30)&( N# _aŪ,+ Owg e']*A>3H O!ĀSBzdS '{~k>P* )1=)Ziz^u0:;qiH $XÃM[yNY7`"Ru8R T wWU-״VE4R!Sbp2(,N82885t%i*9eZLgV8YkA~CO s`%, ejW+lc~_MvkXR(Ѓd[$eCGU#UC{]Hx&KN\7dZ"r;sZ&QV\ebZf\a?NxZOD,@ cmahMM1%C8ιBIIP=k I!SJӕ3әofO8+4Ujr%j1rzReѐHkrNv94&8"^A&PޭmMTCjꁖ"r#38at* 3 5+;)"Hܨ'IViBzKdKb20T[iԾ#$ѣsxQ72Q -fXK笢tUĪFCG`& ExB8)Lgؘ9>l1BU޻2e v(r&=uʣ%8m:@UӢ=R&~͵uu(yrӏ_,(ń+GPB=-bD!hl5n+K蒲 q -۫[d耯ޗfXzҁWˋ_+%գW_2:qrexHG&0.O4cNwqؤEs8_l;kį?A pHA|7gF0~:u lL̙V%!1n>XZz"ۓgܨVJfUJd0hFYG#y-/Hj6z%Z1iQ:t C8 /A`}QM^ weE얣LrPzRm]Xfr*^mO :?I*7{/ND\ժ~Q;xQn+O>xO䛅b*휕jM37jVfF +CtF:B$ J3xpͮŸf0LDghtٴ'ᷴ/>pymJ@>Ʃ-e`dpal GtjV7^5̘Vc .l2p3Xg=lLqlp0bq|?4EeZsM::|Rp$ʢf4hlDޱI,|/i=Qo{93+R3i?P/"N\@elh8NgXxD4QGjM!eZyrm}uscso{/7w0Ï*qdyH TNI/bgTJ-/N\l3GL9I|ӥe ,r.gɥY܅.nىL(7ďV?rH'WjM!&u8BJ."RoTF C]7RQ( Y.64}ި1hFtQ7a )ߗG?nĵc'yn׹ zQU~T)!O%NBV?v|_s>ۥ̕𡷹Xw)Еl491#frggڜ:pA49RkH,ޏ#oC]% TPHM abc_k BA:(a[r^}~a,Zo7:$»!RҀ\Dnuv@s&/A mQWrj űuT0OJz>]xjg*a?WĵF |8j/EAgj´2"hu`T٤`(8 Fh-VGCLTjj +dq0iϘCQ+:}D`,8H22+^TMa8hdemn0J &<=F=o0:7kf B'bcoܽmunig [=Z8@:l+yWփw1t]pȜH.8ԉnT;\t?kuNxز9*Ç{^ԃ:5LL+M&e['Q*N1@T >E:"htѵcM\D80""Gey𬨚N`Ƹ%DT&cR(r)s-MJg;)l'vgۙ1"k oZF;y -Rv}[t Phdu%?rΈ0IpFA>-SNaw%_>+fnWns3Jgrqė.Lo%A P(aߒ6LIN r ģU2Gu5lu~? "2bNM9rzMΝ5L43ONUSݹَ&% 5f)<ۤ"d~Bm3r_Q="ɉ7"Y7Y,EnhŽiף嚼h\Vyd{PGͱ/VeڏLLz:d47{&̨ZLf$i&6&$_f&›woS/L䟹6g&3GрnD: CtlM4b-N'l|'XmlnoNM!6ʺD\ 6P&+YV[;/7/kvag׸JC19oXoKDm~!iIn+mpK '&#ǹ)4Ͼ01Cx떷d158Œ}ItPeS8y˱i&SymvVAEu=o}6qڋ/L$2*/тn>NFeIGA(At9Qo"Mh)*UnT;lYQUsL_ZЃəJM/g]T g!('n]^ơrM>Bb:WcAJ1K1K;P&V'@{n.q=Ns}t)4e'?'Yt<1LsRw/c,@|y'FyE9 \~feKs\V 񨑓K~,;$1>Apݣ1QrҶpS>ű&#EYnvN%d^ ۉV#躍2a"q7)` h8@sʠYsb#^n0&WNbS# )WϽ#^hr' ΁nkqm]b>z $FzAb|Ed})L9]шS0 FCBӽ[Ϥ̿GQ dc^/s^; [E`KEdtC }KԔ; )_sNg$;zu{jy|+VߴY}[c1{ %HwJ xң)^LU/ꤟxN+ߎcHF^); >on9,8&RbRV S/J⳷ﺭxy4Pn6_ZG-B͋UxxVͱ?7CGpRE烒g ȞľgE^XFwVufzs2hWZ! EEAxLI ag0?:šwKKD9TYJc9k%üf?t{4w10wx^~‹Ĥ|IkffԹkeR|,aWpci)(n9Ly$amc=&CVV v=ЋQ _3,Z)Ԓw?szLqDxw:cxx80^ ),$3]PiyW+jvH ^c- ZQ_l̾c|cX ~*lpfyY[,NSGϬ u@1.&d$q4bԵP?rȥώ{l!xIFV48MQP`CaD3c~EQf]3ܸ u"ExB$vz~$1+'.569x"%Xg|< V+Fw:_JtKH(AP^DiJn( >4hpcřVaYz} C&pbͫ$ꑉۨ7#N*lB>"ZWD(wPqk$J+#}sg+.}N5Q_x\ҵ.uY7e@,WBnQbNR $gִLMOt'DYdb:DVDU1+`X+y2 l%Z֋t0DbHӸNo-]-V* BO_Ly>^4 {3"op)Ŭ Dwu5%'0ײ /񴶌ThQ?Qhû(duQ%hUI2qNQb8D:iE=;*%aq,(88˧%h|ڏvJY}L|PiJ l[}zhЮw2jו_^nmC&7_?XqE>pcT 0=H'gs8ʀώ\:BubB% j"8J@|;P% x{+KM =Vd,L 67Le"p!"Dl}Jt?K0l&2^Fc}^E8}d]P=z?ua|6>Fi |6>>Q2mKA.ٽ;=MhGJbg2Vw/͇Ctlmd/ ~b')2 p[e6cI!0rG/VV׻%'{ }F%`:#Xmo|/ÿaENo8}|k=ņ'iZ}R;j=n6E xw_Vb "~a FQ|tHXq-a2t,cՈFWۈJ0/zl [IDhf9G,?aB=6Pؗ֡w(܀yhjLl\Xx#vѱ wzgYx\1;f'Yɒ n*G%GY)qȁdU GN 'Xrs C-@-.[=.ީ:z/ %?h)y+}vը=U;@|hq_ͱJ-2诅#txOxfΟ]>Zl?X6y%> ½. :S|CgJ?4CM+L )}3/8xWs-|@dQfHx %/݃Eۊ,Mǎ9+>$Y$;/t])PX0b xAC"MYyʞ'7oȺM\OyDq}f)_qQgX3}!8}M -ǘ\PV"_(e|G՛@ ͷLoy#MH@G>|Y#Um{ϊ=|iD{IT]}O8=:#(zj>d(, ,bZw24GNi˚ >џ J!-uJ ~6Qv"&ҋO1`wbPc"0NSt رf[^oq䱒f 9;T,n?4@ 9Gwǵ_.2# nbͬ@XԌHdhHכͽ[˽}M/q02D aH MъQ\U&$}gEQI\&VkS2_-za?:q5YYɮDS2^ث{"?%CqPOE:D0h.quRԆVwQ+:0ی_UfdKD= =q\0 "7kõϞe^$s$Ep2<jh 1EKɶYkXr#15Dxk1$#^2D=ݮϤ{usyu 3bcj&Y#b3Mݳ9e2]lU@=܃pO.\|۶xQC[QTp & \E|2l 87mqC}9'|Xp ^/*RYJF pSΰ}y^ЫGg:nN}pE+H{6PN`a=@0^KJek|h:_K8aU7!ɨY}nb2z뻈:P36ok|y&hB9 1v#,!<&ݕP4^W'DL. ؕEQG@C d"rb < uA"%DvJZs|H5C=.Lc@o8PkMbsO(d!Kp=yk\2x Q&QUD$Ŕfppx 0r2?0~D "-I:W Q: :"v89wz1yO%?F܏~3 ,FkJsj-WRlm^!~yCN=3f,* KR(ՍöFމ ľ*$p1K* ͞,Ӈ.>o s9_JFYY$@A*3 3hlK|rhl`]>grGr$.dXƖs2;%8܌|u*ֶU$lF0dj<"h%8|@|?هUU >{ƅh>8և#ҘpF|k. 8F8B{NB-RJ 2@#j(7Q~ݨ@jإlRht e eh睊 %^ҌK!H>5Ogdڨ,ZvH~*WG;+qCF /bE15Z)F,WB[Տ?6dR ,½{Գ[;(:Vk/NS$j "}Y<A_r"Qjϣ'ߡtYw!OL IJ8V]R ,T9ɀ3:lXHhֿcasr:\MZMQt&&$ک:Oxc57Gv_hMW~ċ+tANW>QbrIa! CØK]`5N 鎼N_DL]iW^;opkk@UID Pṍ:@6l5d>}\/iNUث"+w&!%Rqcxӑwe5.MVڊܬgbo+6[/TwJ]/=3xǬ㲽HBu`+O&1@^WoeL#0JB)X"fү"mc=OюXڋKi|aP\]JN3hxxUΪ,茸o=$2+aƹ1];("|/ ;N'Dˎ Y/I &a `bodRbiE(pŰ4 AϷ^gy9ΠxhJ=q3ay& j9ΨF -?5aŸ&(j]!W51 ub/T*1:_?.qo:=>z%'\nF8! V+rr$ˠ;ꪎ;!yZs >qR7ZKӏݧT`.H燣(v`(Zsf45CK8JB \ϥXlE ǏD*O ؠE??U/My&1`Tb?A rҋi/:6IwNл춘2![r&[AP?Ȃ :r~I|xEgGЉ:H)!Sn?Cu77H_W9EMbT /"bKTZdnU9vgf=+ 6Z (k;Ԃ]@O;891'C=a8I(5cȺV6$#na"P[-^u ]/b䟥ċeJYrS: [w?ѼLdf+KM$%{(tטx V^ bѲMSڼ S0!]L|M͙2-egj`Zx@礟=^͕,I)SXrP5<}N)L9(c$Tz qJsKw%0bwa )YJIXnu?zFO _WhUᱡK)械?]h>yNJf`ѥc1o%䳋<0lKm);D+1k-ZBs󓵳0υ鬋,1[l792Il4F^ͲGL}0"a2s*w1ұfK:zd:˔v0 3$L}( CQkLISBcj& }-&8{teOcIi4;13a,y MH1cA',faA^eYP BNZ[{d5Z=o8xxk- BW3;At)okؑiaDHX-}9lU dPΘ%d|UIh->!͘^@5@(xiQn͊r E `C6zè&tSO W6%(BiLIjtu!auGyQo.ba[?%\e z꜒]B/2Y&mt7zh4]çJkjYSQmLeKFVY-r:^sD^YvZwICWDC>i8>ky:sOʦ. 9W/% #Xll{R)ban% wW]W\S] s@lQg1pC!3Ye' NрQkNu7D$o'i]UA 22LfW<Bj je}oO?d&Q|2:j+b?oJav[p{zCU rДB>%QK5Ui[`Z6h- \"joF۰H 12F&i~_#p6+s!8h%n=\;݀(C_'BX98"] gJ24}jQ;{uRy jyiiAX-oDt=猇.Wvr(3'tx~ۘye 3Esp-43-H-Z(̬ F8m'6H?5R,0yczxr&hb1j-P .5kq)m D s#@$pE~J[VV,ʎi#Rڧj5ƍs\jڢBk*G-61EJ\Y/M=1gET I&Ts8bJ@Ki1-:qFDτ}ZMk)2ٿk޸U+2X|?{>srZ-*W`(tWȯ._] @\ 478[g2&_ń+@˔52%m<Vl%k2b$t:k3;CuAڐhB&ff-L5$ DX/P8#.hʇ(m& |jԇ["LMb.7[2(_aQoXez]U78#vْLj؎im:a*V$M>X Gm 2SSbw2$Vt 4+qE/U#p28>wrV+HSpGٵe4#qNR%Q:]hD4OF BDohj4HzIC9i nQ5'mmokdhoni =悚xMTtaT=[_;'W(E_KJ6Jʚ(#E?WXnQڪ'h7 Tl!`6)M7s,4\_J.i]:cd>3 ܆ uXD>g;󙆡޼}I齼=[{NU~5S_صT?|JaE8(РEu{<~eSЕ%aG^Qrdn.9]d|ig.woӇ @u.BFAítp@KA)cRtMj)^&Z \OyD9+;WIR*rN;%4jg[;'J̻y6,.^\\ԁۭSb덖ʖB?𝒻@(\LSl45xA4iEyA=~9@?v.AqL  O{i3Mϔla x?\PWLau*1v/2bB"܆ z/2l"l79FV:| F{hbs|yyQ]cb;)ph% k oƠ'$FwϷ7g˒n_KD>r%-oƪ2ߐdf#%OQ研|b-O .{ZG:br-KRc@q-I&p~blrar팿䨔PO%H|~uC2-M>{f[yYT|{9KjŚ-\n2{@0mvz13;\"J FN:X=) *$p% CFz M,bB(!C 4K.%POwYaw3^+o>ӅZ u/iooSn* ~Ewp8hnܼcRSbu4~nhBMq1Aw`PEbGJZUĐ7#*<赞ԕYc/Sigu UD<ӚPj337X᲎>}_5--bA%<%M؃S+TC=\GTBkֻ!O|ഀ/|WsewEn  @阘cDZw+2rVG2ql|mo&&$@7zy-+wiȕܛ7\/?]&omQJuJ-%u,(*k5@(RB`['lysDql,UfMD73A<A'lj ` 1DI"c@a$&L&c {dAC2 (&` [!NPu4[8AZCm{WzH! N jVnuCJ)/jI fqiI9vwlcuv{k *2 @sީUh=>Ci\rPlh(Y/kCf<`Lz@0'duS^]D q{MWeqVcGEwL;3aZ =.3Q~B"ldU挆2?3ыh,bH1'saˌbF&ohf-^4^k%l870ݠբӠ " vr(AD޻>^K'זJ8 XϬ<'+s_E"YX̉rAdzQBX8.]a1H8KE!z귃HtkĬU+j1j'kO@&?- .nWեqOsQ$'¼c=蓹k;[;/-2uIW2BlE (?L rW~,SBE#ᖕ1`&kd0FinCo"rZH/:JQ]~&E%]vf=z+U(m>0+I x+ ;XUeKYS댞 36:JLbW $t~6ӁÄ/cqxʱiISF'=T<J[&.6TKdh=4 [rHE<+EEP5k_XHξd<(F'妑KUԘʅ:ӝ38I,5IYOwrK/߯#I_%EDkTթÁ uVFS_אָM nb+!Œ(\ Qj65%*ooL~YO꘎&GfoY4KO'dr{|qDg]}74e/`'Ӈ0:}hO<;iUloh8D+Q sDdN(yh3tBN_ޱF,&ļ,xɽsm  3vߩo< \i{7=ņnv¥˒QFWiIs|!/"@x2/ZUǻHAL.uc3[(R9jgfAA U(!A@i)Ef mV:X,/YuUX) "25p$Zkb.c*- \_IFb"!IZQ ]p\88zCcZ(&\C8δ~jk뛻ϭ]/]zZXq#F>2Ye ^,Yu>BD d9r\{ #Di?]Fm1.%_lmm`%C`"z%Ð6(IYm\KU47{a a6]R1%1@/4vD7O 1a@nyNrb̑^V*YC#t`.i| 4n <0?V# @h2V^`᫂|Ljx{>zWcn7b }izuuI;Xa[`@\sÀPF'poAL~Vꉪ-"l={ c+9r}A}#r!zM{0:@;C\)RƆ3Nzl?zs8t\h{X, . ^V~?؟:ט]cUsP՘%%i Ο&(.94ZCSf3.L.&*,z*`~:6E4S[FW7u _67_n4eJh\DDO@eG:&LIiqH&96%ʺ]IvB£HĈmkl6[]fW$Ȼ/ҒzuFq"doOqoBtI"WzcZBXJ葑3HŰiU@KuA34-[0"-ہz ЌP[пvŐR.n\1a\JxdjVY(v;ۥ+@1.!#bK3vFM6y)zwosG͍z)|p\|ΩcV89xXu^'H8o\t:=_:*%cnj8aGȄ=1v߶&asgYcg_G!Ju/;>c>z-Az@hbล0T(όș "&uZu A3C"uSewΑyE`9S 0<=&u;r%zR=3&Su(E`b}4V[μ)`ݨߪ;qԞ` -DH3G8݃jyfKOAPӀ2Q(퐵"= [ZeI`Ua!p@4$; Rcf\l:l?_o>xpA^qzB0N2jL$pT98)qH9"I'dI ]J܏e*%DV)3o~%a\~(4r{R;cSs%{ m rRs%Ek=͗ t`]ԗ+JdzI~%ՇfK| JQ,S[c('GZ(r&_:S Y#N792n:OES`-ؙ٪o$k_+Ks.7g[sjUՏ W*~joO[UVյCMACs UiY5q6ߠjddbT(gL&V5R׻(AOcdnzs ol9G~T+V g&wzǢs z(l_=IwօE2٥ҋUcn\0ny^v^'|Wѱu3u}EK'G(6l5Vcx[o-" vY S&xE@o"WQm18y C&,"4r]=LbVBv0󳣒$"u˪2}G)idho̓4neN3kd?[.YeA֫XA H V*pe}hs% 53AWF1x~]P 2RϷ^|,CFS_8=:_9Q08hU(KPKƮxܻRxb](ۇ%xBxZNHmjw&R췤uJN_HEGq\PWPJN/ξ_ZX(=60o%$;j4( G=Q$w(4z{N;>).TIbÚ`Hb > 9$wwU׷ҚMQhPfS5wߞ"r i.98j@w0_gȯsmQ𝟟S{c6c{]r0o?5, Y"%To~x>,Z@# >Y> ۝+!/'{jтZ!\07Kot~@~RQE〽\oW|x~p KT?^]c"JԶ_] Vm'j#5{0v͢&pEq5ֺF1xS{^̓d?~k?fșī׵+fsÜ:O8ϲ6Wiȑ"`")~֍juw 긡l.vLdk )a͵*z2YP\hnh񤛡dRnqlq+uTI8͡$ܱM<8sxX*\V}V2d͸[VI,Xfg2+S_s: ɟ>/qn5)a\ 8 HXP>KElzLC ws] JzLb$H9fF i2zG.ƺ*0QԝfS羪A:xv ,ne][mq+^eX|I_vj1La✶=u?Nˮ4b-.H\af~- Ҙ/ɴb)`.CfsۙGS-5'Ɩ8ZPm}4OvXk?^$0|[S!y}',c}X'J.qd[ҥ \ooz\_ggr=f _1gcc2eok1fQzl r U ڮːH#$ҍ+iy)tP$NϷ)KM8-I3HfN.RU/ߑd2NT,IQb΂_^mjd.(j2l%P"(d#vH-4܆w:ͮܒw@zbfp.`PfAӸ}~nVnۍrp$crf`qYf-)'M•?7ͻ,uU)TJ8[@m6C8Kc&9M"n#(TzyX?H1w:΄wwdpI9[7:7uNk͝桲pObb7ŰS'Z dةGk07?N &[=9:K7a 0[ǁD^?xX# 'tS=8(MdQ7y[&ӢQK⬹eRF})}<5b]~c'^n6}62Ta5fsvVe;w{9m)=8_Osd>oYǎkU'87/͌؅oxMI4E;,w>XݝETn »?GȧoM3CPdۄ>ir"ː.)/jbʙwe7 ];W)siW)rF.+F*t#]I}'jCH~^mCqe狛5x/lmClal]S;;jr}fs``鸙s6oN{ _/yOw>go4 SX/_܂( .sk{]}A[^kh:>Fd:oѨƽt| ohVLǟ}6ԏ(0* xG?ٶe{Xe;FgqBw4O x]+%ɵBV Ml[yG@hHsT)~tp΍|,׬4ml6΂VrY mܣ1ykC,;eaJq%n<38=0NȟlD!rDK J<8(<7&%<8\?% 2d̓8a|.܅=b%~cB),3\nf&IxQ/&cOCT,؍l7᭬3z55"^ V^Ca|㫡c \۟@9_y1)xc ^<;-W%n똨On bh_Z3J{ ޽>9:.(. `;Q.{aȪuC7 7@)pXc`}pNCR1 ^8*y2FuaU竆tt HA$T6l]{UYwu8de >U~ v?v Z@ \e3{PJfϧlAΨAI`ZAqgA!')Z^HaOiQ(HN؜P;$&=fswcs>wg!/;D:~2o^47w6v4C@R>vjdŲ:nMn]훻 yGa:۹wZZ%F+ށr23⏷cJs-N t! i̬_?/萡swr͘ƜH>0_yhz쀭Zx.A)T#! <ad+u:}r&"NkQ8֐Bx,Eg(Q+. =^[y#xCe~~~EdAXG֣6I}p(Ԣ$#` f[u?s|tA+9ؠl>ؤ?hJ\_Y\GCn=ugMfO7O)0f/KZŠ:}ۑAQl̃Ǣhafl]vMfLĉvWN႙L6p`t 3MŲ :g^8Y4=+}FZ4|@kᰃ" Y~A=~N`B Ʀez]uG5?GFя3-s[ER$GEHl}J<+RhANI޵AZ^E,v–ױ~.D'1ZLBT,ȳ+͠~%/J9@qfF{.6 ^5ZhYt8Q R۶88llP//<@>˃uy>1YC5B(d&׻.%@{u J['ꑃ>. V5iAĀqO5N- L0IJ909P9\Ȃ:>gBg&W5S- ֻI2'6F hqGGQ!?P9s`d8U$. 麵QL\`#Bd3L8]n;jW$MOr0O0S5RЁ ]Au!ӋԠQ$uΑ^Dب6*܄@+ 0gjߍÒNBU^` G(9)uiBA1h.[M9?^z ~fMp_ZVN j+nst`A)@:Eӓdwöޛlfm. ֹMVg&~5ӺU ]fRyZu}8xW`l|e{:)A'$4@a foSo!̓=Mwf60Opzsހ//H܎Rz805Oħ^C+_ )t%X5l.A):=ŶGُE3smͽ_.HCnm ?Gl1vi$F٩W6v/7h;'eاdwR_R̠tdDΑk^a8 Gf5h't_cHfx;j9׵B&k -JSn‚e1iPN%92X0!5ԁ fNAk%h$[@4V̜ErM^(/B6bIA+۬(3i؞?Q[jloLNKKKۘ i'۶R3 d5zIL7.B, L[ 9xʨ;% CbZK}{'V OB@onH-pϒ͹_n^K % q.ӘM ´L4:8lMwS#'HDَ~A/bWsV绘m~v!S#M/"<pE}",T&ַ@V2lM%̢J Ŗ.ieo,IL!1@ƊKDR,9p+I` U~t T/.`niInkՓg',XLݾ,v$l`^4voAwNV̾63 ~ pS]U/ۂ C1xإ׹S: ӳa(1@@)LFr'2kEP*]f\mw ۶*oڨlZ頦4A+ecO j&nnF5WfCG&92_ۈReuF 9 θ$ZvDdD{.KjP t v\ TÞld5o׌.|p5[x"sE^?($d4eÿsph>d$4 H~ >ING * NgsHbSҺ~S9T|vϮP`8AWrN<@omo--S]@}[H-ޑ:{78~dhL7=Xx88.W*!$"력>wxAaE#?%=@EԀL(96dZnpOėqx|([ؘEPELB* &+sͣRD "q` ,(*%*"c9Al mD=TEEl ԝ97SkM5ENpfNX6] 2^wg }2XOI0vh:.z&t~皖O=Dd:S֚QrJ%3&Y_ؒ7 15NE40a5"j2I1᧲s3gG2{\de`rC0iQs` Lje?E7|ko#nKqs1 ﵮ1a qxl-,ed?VyM Gܜʻt LqXcG5eo2=\!zG̬#=x7?ң  I خz)M?Yqkk9U<qu/XsQ9UT 9Eel*|kS4x$S! J#_1 I- !0a*? "nF*j $Z7z6ukۊ 0%baJЭBti[¤n{ ,S Gץj,C;;YCk7?])iSv!^z2;%:y2^DTM3w0 \>PU*ٙ& 8ŵq;tEnؔHFˤB8rDZ] BJ#VDd;&سn?VRMXVc8PH:ýTP1Բ-65+(^sH[#IjƱqKшZi r0=nFr\5,IpF|_R9L>dIML;$ЀnouI\)ox͡4|SIM#ڊCTЌ/y-^3 G1G*Bܢe#! UGߍαG\ DK)h9-uUÂbiB7dِΙFFVZ4SE \=AB%u:o"`D,L/s7fv Z㒪:e'~C-PB@MiVM}Ja"\4b3y2:jqU C) Q.YLLcz=:~A&JR99`$:fY ,W+9W=B~ q;"SZ\#6[wr=#jpܭye~,b,,iP EEpw>?0_WwX ˓de2vz=Ax=D֛iv!Od`xG%CF#ձ #FiWȢ*"Fy_1u1.èۏX@1IG}QZ>QN1<| g|;$kG`Xw<_<7C#[XOTPS"9O9Z(4G -.+pHzy߻P3LsGA{v.wy-^߅4 ].R>+|*ۮ rԤ+[% C5ݲ<Wb~Sa) Y 䝄eeܑCp<9Leċ0r5I{oPEu/i+c`Y$YQ"iQz)CB h4hP ~k\du:=_ǜ1b{BkuN&OO[-΄n'YUlBۈ; KoS:7C;JzLp)k305ppK eʘ*Ww[S=j j'VD6r<@OIJ咎rOmhRڊ@:hHąAJab/Dyh QxQW"I-FaX(< Q<0P!ZFa+3@Q+I2 E%ce&H(wcd1`ҹ ޥb- o!:9+r:&_YD9Z3-vpQ*WcXv 5?!ڂPքNV JqUMfR2#7K2q[GYQ9!'(HE%+eT Rv|ĔUFif^+}R#=1dMDP% ˂yj>C "?#"|}l}l"|,l^֝%˾@\\lYYb*wi MղkZO֔ب7@pYM\Ik_靟>Á*y]#Z5G?~U!|Ez_"UUU#}I !F@YϏki7wHpƎm4l=,:;|. ]NF/–̮ou-7ۙi;̪.ookvxc5^vps*X_Sۀy4onBy'㫃MAN\ɸ#0Dy)t ?y%ﴃj_Rvoݯ)v /ax*T+]_2ԙ`k[يnDj@&“WR+UEQUzs)Qp?})'s H&LeYU&U0 (tHb')Ÿ4[+M_\nmq`:mϘL2ۛ Xo$0x3= o84Oa4Z/oN>K5/6=fN\iM6hڹF1׃ JZ`n5@D/i\^ `"ilB$w|X-kdOmի]hf &U;̚|Vc9Hʨcfiyc>-/~h08Jzͽ݃1Tm\9ZϞd$;lz(Qf 1lq"Lmp}wg?sCZY\(^DwVxCVX}!G EX$7cCt6UEnjs"Fc̚pwnˏp'Qp ŋS:SbyC2_Ei[eG1 fUyII$F8 mlV>qλvVn#*n3QZD":q٥DQ٥,d7hN yr{HlჄ9&^bZb\%ZF WozVFݑ])VQ#i88 meuVf8-Z=UX̝EQiϓ?FD@+QǙu;ۆZ{i j$-$҂:x\r{S_BF/\Dݓ zGqtA\5jfp6tÞ|n;-r9pͅr9) js깕ndTx<Ӭ6,4QO:aԢшuXc6ּ$ČW&-f0!&!:a&Qu(b8v4G=1m? jspDc@6bO>24&; a B~,?h/PBhH wy4AL;kU&O1!ѭ҅Lx8kU1fL¿=bDJi3SID-LFVGH zYO^ Ҁ%ͭ2PFQ7+G8jo/˫e~9maCubrN\JǏ"\:Uw=XZXYʃI6M(w_V1P{bO×{U6vFj'P{S \啥Fp*Y.P2GKJ>)U6g&yP u$bP4&@6AImA[lo-{lVO\2?,,?z4[e/RR{yS|-Y'gg`,w7܊~ç:s(kh8T:=ڨ+P)qpA dTb^`WOS}r/"<.y*PBqKowJQ3(K Js@xS@7G὎Fl'2A=N0ɟ;  )&"G8ۊY  nћ Ps-㍷E4q^ic(4@W_th&\LEd@F6q]3d*lEolv31 '8B17GbUE"F YϢԲl@hR)?'%~PIgx{&Mexd2Dv$\ȌKLdEEوؐ菽 =~~Om^^K+%C%!wYj"bQ~d% 9]>ZOeuOm:W74 ^fюS~m9`=穢_'`sompwD)(# !TVlmeRy.DNhIP.6Y*AʭѐxO(SE]~LxEuA `˜e8.jjN''MRNQTC_'g΁!gzrV4`.Ө9%5v&͚Na:N\owd.4XѾ - g^o=gl4ss0̇yj0x͚9ݽíݝr\Eut!-٩DKE.Iy}4(. $/VdHHN3ث)]>嚏ð3|Lj>e(>䛏WXb%.fw2w(v$p_lVzOvݍ˽j jCtu}=Uakpm{T /jx*jJa͈j5t}gGo*[(DS2Ml4_mv䐮NE헕(R⾞ڇywZRtނf2'=$VbDyS:P/]C N&;kX`s(ڠ^d&a*IbIb&aWux%%E\"*@SIgkgT2)wsf ?o,I@&< -AٞDbP7!\ Ы+|؍Kt^ 5#ee7K6 ]fq6NK Q)ɻ~K`$p_h\4 1UѰ#fk;8;G.;B~g7X,H=/0"w@XQ<*jzZ<({$2txL<0jd= /:s/<4D;1v/M_GԳ+Ӄ]x;ǭM=9Fs#NfC~iTdAбDJyx"Wyl !VPk݊1}?Y~B)zl?{0bJ\4&miIiE'7XL8)Fw |c3r/ɟdPi\w  4gΰeQlZOx #@T/h7CF;jwQ!aU#oP+Fl6y+UCR)peJbvMyџVٕV9(Os4]{(SǛ[%(zj5z0֋7 0i4ZH`k8=`otc CƳ.# ߻p\uEf_qX|`>NH`*X4*Wͷ: 1ADBC+JV'm bbB$ @6d["Yk.n <3 og;uRXm<9%̞ʦ _l~ i~7x+QLQIuQ9NIk15"~Hl* Bpl1Y>a-+!xq7eYHbǟ)3 +v.2C+vԎT>o~Efpknv4P,b^daL5G [V\  <"-\`>|IlD.8%AA.QaLn}8BOݾG+A*+\+ Q Op}s/EȖjpe!^H  # ڢ]x|Ql[ȓԦpū.\@'?WԳzJCE~`J6[uIWW+b5 S,!I{ MW%kRdOpr$綸s"*BLa.lM5WR25ݺYJ8겔; ^EE=P ?BqbLR3-B4O8_)J̯ :1Kږy4taCCXKt "u IJx-7-vXm56 |@+  KAzhxl1QaM奜y'hdY.\*k4,k/NHfC2|'/d71K)b00= y̪r|qE71hb&a^ Ctk\Cn6pǂtg6u* 7vo8-xv[ztkd5RNQ~u'gV:b(,{`)o{ZX섀X r9UN0a v0mn%eMj2.u}p^dɩ'3׹gܡ=-w g򶌧ww&-i"ww: Nfh7Sz룵?|`{Vy4\gȯ~u \>W}rR !ý9  JY&=Ǯ^&0<[ۼR F2"{`Ħir_bBz`SpAY+(W(iہ$s&/b;ITLG<+?lKq2W L/ʩXbfm.h%]Ov=~qXk#gg 7anE|:~evKZ1w-$J:Pe j|]AF%mIH$#7ly|ivRJ3LTVj,. $(4*f3ߝ4t O:n#j9wR44+9z+@=;^~eD{^AiS &Mk`{qta|o| chfu2 82 ڰFk/J-߃J- SQ;Gw(g fbެEet5ܺ4gs+} L!sZ;^ % *k ?_o9ᛢPp8ax…!JFS`P΢t[^ֈ (%Sv/C3<4'nÇlhp~04tb>j~W_}x}Xwpv٥m5LȖ:fM -: L;NwţW؞G/^Eh3m֛0^ )m. `٬:6[a݋;ؓ!o@PGdtFe^[ #{mb¬< YhtF(e2J $يʀL4J:n,桱3s*3zIJJrt \8k~znHAA\3HHiذ[w NwNaQmYv nHc1Z p* $ *}O0Ua] 8~[ ^t7=Pqa).P}'٘)r(tӆ'%+z4N |alCl=h+\xV(ˡd|'t i8>ys=B0问3tg}g\K`Wzr5R+h,Os#sݩ;7_Ͱ~w]<xC_G >FdlAlH+םơȆ`xJ Xosl qm#c\p0/FqSPwYi ջ*l:Pu-M|}w \#^g/0 \_\ӨuԪcPB|nO _v".X*&(- pc,AT䛡;6z;,=l~}ԩsZOEyh@ǝxi@9[!b0 ?0j Eb%1r!wG2N` ;I)$|,w>(ٞoiQd/ni ȔF3Ԉ>oDӻDQbDq'j~[TĐ2qߏ3$ˬZsG ϵ7"3At0~yD 9ЛĹBlq~ڐYb6[$zfpc3tXC"[0L2Qi,IdPOe _NJ:U$'c*+nk٠iEdX[d¬>4L% Jirv?FxA9}u!V<y|݌Ext^!ߧm%:v/&KB[=."ø vklH{GEkXg[͗<f m@K*4оa>9MЃjerT@qKw)< X̙-oQl)P=wή91J>G\3Wf< P {G8#aeJVJ;v9CM['7)*)S#fNgbBmK̠Ԭ^rϭsb %89ٯGaZ"Z{ޅ7wF7_ ĺB7/3ơ /GCqi퍟nsφrdc툦hܠa\lVOƌa&6]M޹-tFꭹ{>VG;;3T4QxG=G|6ВG|aaH8>qo5Mdr:lmnoy*3͓\qEr[o.Z磙i&dǑ  fJl1csʗI X_[W\lba +=';kwv# IM;x2ߐqїd^(ˡ'cڅYHr`-Nqv''w[NLtT0+K Ҩ-mr-M g '>gpBP%bPi{bK1'lnƊ.4pK,5p+O@P$n܄e  ucf'EP;cc4s{V| ~3wy1sG|K:e܎>̘C`D${{ [x#8XنFuF7ݟřNGw^@;gngu5ΚwQG_W&HV9 PcҊ'9rN.#QTP{ݦB?|k\cr+۰"YȲ&~SNfFlh+@%_n{>|?٩obYtP,,7G >G-1ޤ&^_X8WJ"?S}Rf%6uYC{_7M0ɄAG aJXj9%J0BQl<<`qC6ĵޯ#T9,զ,εo拱,N[n^RލNpIf>Pe~jVHñrTRʷc_Do/om?=-Zt1bڟ/g M\_ˮtH;fֻq4հ@SOCswvUvߝާsf~1EkYyTi@c )XNlgS+>~ey`ՊkVgBdwP,1GS_~##Xe1ŝ@)Ujw$ut@KZTUI#mKGwa|SsJUfjpo3 _R)e7l:Z7}0Gpr? FޜcwPG^z]b@$#d"!B& wYv@Kv%d6_jaP^(3%rlbCGOSq@|>EpW `j*\(e-W_ TWqOqq?EhzU1pPYC*j8?"/)dDl{5g/Saҟ }^mNe`Lس,qjτ^t-ގ䄝(pUkaGEpgst*bNwLӞ;R߼0]|WX?c} |uib?a(̇CtrΦwv'pttIco&P1#O?8vzL{d_ڌ%b EDې>.1T/4%^B9·ebr\u"_b MK$t40l|H3@u1QIK'2 T0jߘvH[ǫhԱـ<~0ώP&{pcodjJvU{3lc5bn =$0qMӶ1 w/_#?}__hZH#rVC-R,+]P *de*Z#{ "B.z1N{9]TvP.G:,H#wﶟ=Z/[[o7+>, .-/3?ty][<=>{b]Lj3[ ^N qݎ/Π}b{Vݿq(4/t`ZGco1w)!fB!P"՘"xM^pAvѨ 7 R 8y7ND`o}6C&B.`a2"O,p@VFO:BPHkP\#Nˡ=#G`a@&m ~1g0N}b__"/Obp܌NngxÝ 6>8WC,wwww x3^:,%pRl|ߘI@ƠW8pG Di &q)ϱ0L`d qi[`QEX&@ g1 NEJ2Lj4}^Fc2W/U/ܱ;q k-ǂ;BxܹE}:\{PIf ^},ӎn;BT 2AL*bQa,6Bs [d@ġ%4,hE͚:A+ʹ;Soj Ml3KU t8タIYxgW-U6TBllr"vCN&l?qgeSeݼL.=*Wփ~5hW>H #}ّ'fEyy2v?*A.K+Cb^958YwM{nZ"\}rd8[x(KWӔ)\B1g"'qz Cؽ"lEا~Cؘ%ܰ %cp:<.\.Mǀ@aKH%`Fbkг84Z4niKK}:.ZJ&)z*ق[RJOҤ+A3#Ocwn4[X%^Gjƌ=y=ث ȭGJ 2-."l !$p:#ok{{)MɩyRVBz$ AiBHC w XP6n贵 ss3}x Uߠs*ɶҰ糳K-^[+3>Ali pe624 Ii옶xy(;{^_56Vm1f.&#oߥVD*ʴM-Qi>GX?ƗGѪo;귺;h˴|Hʨ=cKӇW$c<{h0qXù7hɁɸtlE֠K-c G{]` "9`n?[5:[=d|Ip>&7v처 t6HU0fJϿt]Wiv*_وX2wk?_wvo[/Dk~u|qs$xgZIp*lؠN飚-+יT{,c,+r8F>'eo:BMuKo1BM cS- ek{ۻ 2f6d03Ydf{?n$՘E&}f󟓙i같Z63S1lf?0l6Y<&[2S0IؙT%[(a5}xbE*v@`x0`>A;l Z>-WNVJQ@F@璗B M#J(=|U~FRzJwdK~07>[ GV\-7b@p~LJ-&2mw+/pާsdGg;@|1*\`]cu:1ř? 9]vG|/[vޟ 63];龸̓.ӑ7)baiAq*`>,Ȼvɍ2yP>_\ewµ#MܸyYizmjG3IeNd%BpL7&R1r޻=Ya%ұGِ?lQk |:DrJ6<ñZnC73x)crSë0|v4ٕUz2cW0@:C1T2uqy1-ٟ' q܉Z53Vgʖ;eX ź U1'OMzF?t{{zU?k`(5sQT2VجmMT`B0@ٺ I{on^c'o(jAs ' P{dD<+O Pjf 9L0nz3|WWgf{򨹿W_%qk+gKtGkV93g v2$e#4ښߢ?"U<`ЬP'AahMO2\䆜B1\Y@WV uVa'c%u;pR^1L ͔BbgB^CAG!}F͹v\š8C#p-dm˭!h؎}h K;|;#iNt7naZ-Gҹ_DCà8v51В{҃UQr95?վ V3-']9&q2$^y iQ[bJ 8Ŭ(J3*p$TO.Au i0Sb5yנ ջ 8*C *0R\*A6 hT}3Y0$Cg:q˟xZa0-|?kGd:5NN$F˖vCfٸHdO碞&OWe OItoŜșpdJ35F2'0֌#j}TRp4M|ݕ>h}vfwƳȘx !|/eϧA!跘;w=ə'<\A7W<iL;j3juy,V=r:!FU:?l)Mb\kZz(nO:ưbfqK3=6Jzu[Sc_jJYꨁ5AJb6EnFR#|bsk 493ZR 6db֜MQ.'sMΨuHUsTM&UZ*;{=uwVZ{8bך].Sk.];N{'IGf5k7QF~^6=k5]hhD l}~N݁?aެG&] {klV?zSuۨ>u{WD.jX -B g[xut.aZ׍VȠh{ueu]}mB)}{#Nr9h"u6:k5eݼF_0 P/ zY HxY{|$N$8!|7hc|mLѺݹބFk"zÎ͜stPo}Gf,Q/Y 0uw. 3.U ,M5<#Ν5d֦P6zpK%l f8aiYreчn5$y3H@I\((W&N)JkYKPjFLK\LGmUZ\(E,C &Cc&O06e=\!{G;l0ʇn ||!B?S.2_Z2ëFN l kh})vR.⿱BP#Fbi!,- 5a@EwҝwwكDe3Eeb;i*=h8Zs( |EHX}^ |p&1~,V&a1x ӷ}sPlbTM1|<ư *Ÿ |Z$"{xGj,[۱ރQ'ó'zeO]fe_)S?Z{<+W\cw z<~IWv9)jZ6J4kBKQi&ԓeJ{&E٥@@ '>amrPm{cR53~((pr373|t鎦XbLK*5Pn}LfL*D׀'&^!:b4S4[cSlB .Op`_iX6QI[AŜ JOF]וb4 ^[`6^+6rׯ׃aQA/KJ gPL{63 ~h_!ճ$7D}׍Vhۇ M vD?iPtN=Sti.qQ<y2u7+ѕ\wiObiz;Y hUN}Ų95B>;ӹ7z7ނ=TTSXPR$a"QEI䀮^w& #.$Q|k$[I˜_$#re#}~h;[t ~&)?w t/9Z3 7.8\IpKG@M\ڙ:>@IՄ^dJd-Gg:#G{r3N^3 Q`\ &ɏ14(4HW x/b2H fr,ڲYMɮ20_WTZA?ˡ$@ ػsE(aNCa\R_LܵS֖6CՐ/$g>b 3՟%_:>L`l`5Aٿ4 Y\+*.c3f]`c5{8yJE l4 5Pʴ# KKx;UZȁ0lkJ{{~|}|w'ko6_8B,ͷ&j2@ ,e(OGWBJ#Ne?ٕ0!؃Hb,,ycGJ<p")P%icbL ɕ)MުcQJVLYIEef qMLvoX:6-Hm\L*8"M0,,o'r/aU`RL:UpGwe-RSTc ȍn8ixc>G#[+™}㻌vor0"E#18Ό,w:*tם7"zHx+xI*6hǎ[VVƟc>(+Gwn#ŸK@0D n*b6BS3ڥ58~N3opLxN֏үҿfIZިlUwZJ. z1zCYXߓuJޠ˻#yv  @E(ZlޑâfG#KQ@i{RXJa䛯0IJ/k7ZM߻NQ1V,+{Wn_$ s2?un5/Be {"߁B!:XFH{AQ ;sYx݉vc8q $ԉl߫j6Kϻbt)ŀ[D ȕ+]ߙJ0:\EwlF]ª+A 0XzQ؁y՞*s|mLIw}OTlviolUĬjS܋tdAs/v?ʵ;7o@A=I2x1=XʭrRqgLgZA;YqM`+ƕhI,;Y*Ys`zGjb>"ِ?wQu.πߎ, 1#ׂ Ì nCZOǕ PVliRH. @Ryu4aUF#L3s'~;qp65W`{xE|aS(0Ŝ&ŀWpHM;KctApСbs0Nߗg7+͇2)C]q[S.H|̰fPFG$eh12O\$26;j( hYg֢)-I4P8S9[+>_Ŝ|&$CDY*`$nz=FyPO5OlnټU͛x nX{3,ٷFlgvQmC<.lMKV6mTMd%a8߅ R5IQD%1SXՄ@T&2DVIR Tss]^1I *ahY4 `'+^Q4ܼΆ7ν0| (Ԭ. `V̥̂;EG8:wBc(菏_;?9ycG5b|~ G^9C>H:֛D>5"s@g>kzT`~' 9©;XZe.(IVdk@)TuI^#nRAKOyO998H&/Lڏe ye\?$*Čh5 H5PgAMRBєz Mϑ@l r.ywPe/I^xcFb l7xX9:u\FG%B!ĨV^r֮2t̟0D"[p4Ŀ$+:"npA UCZ(Z)|QF'JO˛f eKXjQ&" GnPWb |Hnٮ{؋0Yq.\^PS~}=p(]zVV,$4Z? ܧ?`pRq1b88j( ($֕` B)ZgV5갻]<"0ޟhwxg<@~_3\];_k>n2a^F m>CǿFc>ڋL.gqPK+s4Sຫ7:IW'!,ŽOԱ4[hEA; BW-y̓W֙V(doC"ؤÈHQNؔ\Om2fYHNd-JԨdsO<G\(>Q$䶑o)'3u棰Ƞ* 554ռp!ϒrZdܖј slzrS2 )E,2A1\9,v8,&kAL}WсܖbV1%h6/khTWwB&pl v?fHFF!]vR8Ja9lGƣ2JU+XVTLƋW3v v(O Z.\IՒńp0L ƍOjI ]vݦC),! \(x=擠Ne*Twv#g㎱B<ó3qIwB{W,ϕ3VȚcn_4uHS n0i$ Tx 4ʘ9$ zcI)3qiC*b [yI,("U jӁ:âat. fev>d > $LĵJph4#RSU@sO!ġѶ M <7C*W'TO-x7, 7"2vIj`-aɼ7p7`@a!,r\&?HK, OҬ.Pwqgy#1i h`43 t 0@`4RA3p5AuC D5\l8#edk.t {%Y0ATdBW2;hHhd*1|{Q(@Nꖠֳ m6E. SϐŒϳ[+gkbV^Q]9Y0V,? L awlI=od3YoUF^;o܆>1+7)%H vcO4~kKTJr&]L6jT6 bǚ.R$Cj$s=GG/Oc~(gٞe!󇹋t^ &3~h7I\∟0?tK^@e4<3#RqlNX{ ex)˔*"+GL-vn<GJ-̝Y/8ytuoc QU4T/X/ BJ%6Ugd+ٯxU |'xN 'CUτ"HrFuȓ '#ֲ> m9Nqp_5NaL-5īˋYG*w29s!a dBN-Pd2ȀA.3xyVY/z =І}gvS,8㓓lI'o*wYS`%'7f4ZT7"}-fc޴֓rH1ޱ[:lT[uEwr>A Mgrjem-oQ,"I27ޕ+OhXͶ\ n2o} g߇4[0"3ڒ$W:gչyM NGcAQG}3 1 vԻ%aM OЈpms rF{Ye8NԲ蔠($TYqI&t.͢tiJ5<F bX hjO0^uAS{=/?11Fv deroo$܌%"?%R~GvE~n\e$0SlST9l>_hs =TBgCC֡$+A+YEJL0WM}C&pr 7kRDFhE0M숓#@gz {M(OO'7F9P2eR !^ `) M}AOJ &OheS S9P[#y1& RNJa ]Xdax$1qSKro3D*/shIXBZ?TH6*yKnx~ ˆf^DEGYxѻN앴vIƙӍȧRRoB6*#Ț4ɘXr6.5Aվ%"(N;cP7J.,WT^j0R ʫY PhŞQ, ޮeu5 鈣AS*eH{W k oͫg@]xŪ@-Є BާWA.r*wv9 zv P m{l1;zqla7߫ P|0\Bg_ o+T Yȣ8bPΤġ4,4}erqWG)>~erq 5 ү6T, 5ᯌ*4Lȗ1#WF-v:Pd}1bɈEoN$uEqV10%W9HpB Eso=Q![U6 +} T Pqzc#]\CXb;RCbPdžX˪/-lWbX] rO>A23Ȋ"d " B`:Yn! HYYH,{.R$a\l{ -nUdxY o2ì *"U4AM@Gy@ A*9@nh;Kٰg  B`YM@ pF `[A{V@lG=`0b%"~@kc&WJ#h{) YHCV.W* #jޓ$KYWKBlJsSaU-UBD{Ta10ݧ{HaŖԌUtA|kƫJ&Nj 75(Vᓔ&b3ֽ  "Xv, O\|W) z3ëXs Kޯ.w᮶&B|~U2}k5J"WA-!\xI%dKD+{4 NHb =p#c!*V1"H) kҖgV+CC{aW0۝Pە #JK^S^0F4&b,$_;;w2#yȦ Ճ9A$)s1Ʀ3={e2s~uf8@vvW<+oի*덖~bi͡?@>I@ޚ}DШ7 x#=8φu/vǞ;`cbOCCKoxH|qуX<7w&M!y@!z*#TWSOCZ1Xc0" :n&sIpю>NnWƙKap] ]G_g9="t*g|"kr&'_`O3{__jOgy 7_+0Fg2aW|Ȟ@ɋM]}+/Ķz*g>@lez0xrboW-ˆB uIԝ|戕R+}K-d>.wkN:?H)1!0p*bkaKW ,{%'T< A9#^Sy/V}.YS?U˗&^NaDeu[[ֈ1/fzG@}\Soi~J&] OUcF:~ޝ bY#5딫#`_Qph贿F̞eO9'Y|?<Uɇ<I6O\8 edDl4󹘦d 4A@{vͣЄ䷾G9 7HvU6y³;v1ފ;2 EV8!xr !1Rx0Ch<7x? 8>+xQ`3d+`aL_e`ʡpfWb&vt  \qOr'ى F{QsNfg)AFoTdzlr*%(fwF<;ؖʋϫ`42@Sn$Wv%)L2TT/dnX 6rI > 曼Q1c[Py8Moʆ 7޺|,vSsd Z= %{]tf?= 7_#*2vO1U]ǿKj̝WPE]kE˲r0SV#^ZSw8k=UVYo ZU4?1هvF& &AWw `*tV4iX<"\fʿ+,9 Vz%3\`:R2>J>`6PO~zד'2Btٓt[MkwkAq+YZHJEДnUzS#3nE:`B+mEHK9= je- ~"鏙{G $H@^Q I }LjU,]UznN_$X#hMHE3w8$Gʀ>7U#E֪gGVBLg#cz7f" 7HΘ*GL<ԲJ/Tv/zn ƻK}]&?̃CA%8n79~a_'us ((=g6s(&T [,{E72ߑ޽`UL_WܳS\̲ݡƇ!cj#.ӇaW 2\ia#8D"70^%|ByQWfsdh'|8#[FTdkMO '^/nN mnd;{SleD`"*vIi<8j/3,}0H?.Ivmg$E(tsI&[Xxt}+G<̉cb _ c1eIP@Ǚ]GйX.xyIVP (0_dSL#@<0.KaSmh:4 `StC"; m ȃoOՎ(-I=؄T@0h~ Iqd9OMd'd5\ODǝ'ֱG#I8 jsHAWfyeǁ7a;SqfixEG&g̝Wo^j2t2w87^9QAxN7v6 |s 6-XY[ <-dRe bSù|խ$ם0pz΀g!.};'GC>˟,f#>9`1$3O tT<ρd =JBO?3?CQ9lheԙ_\8gp@տHެb-;d8JYpW< xY(^,DSXµ`19{{; jE"5`V,$2itK 8S83&dnTX'XHf FpS1Ç]Î^.wR^Ϋ݈qWUq[2k6i`hv.,8t;0lIIRǝH*ho|'.3`pI>5ycN|yfjЈ~q q!ء;$E9lPQtե1Ŕ`Ė`B 0J:U$M0v;c  X~T * f`l~ (yU jUGjKĆjX)X@FWVcO, JK.(48` )/Aέh3bx^-[}HHeP m3Fad'eIO?|.<5-|ZնYQy eڍrlA$Chy}f{ ljˍ,GF@±@22 8&/Q!o~߾<֐N_Tor&ᛜ2|/2oF>r#o.-woP%NUE%$ZDU XCymWRx)9̀AղEᙜj~;sXNZ_Se?*_e2A-$a37|~7.S5' Ve&H4Cd) f[CYlFn78,I68o) 2|@+>N2IȆcQFRf&cD{NmAFwb%G.XݮQ<2g5j_c>t `D U ]e.NgX7-/C {|C/fԦI?ex0OjceeH0KQ5 ,I1Rk7Yf /8o=Y&y~DSNU6*/Q AI^N>TJ)Xc1)E;!\L省 C.E2'+a" )œㆍԦ5٥ps`|^ǜa`…9֏fnI?C"QVX탡PAK No1~ʈAY^8.b(+rઞbr&ڮ:Dc_Ћ'¸GdgJD %~+EC,a@@E-3 keM.9+,FxO/9OnU>" #:_~GwE4kw]Z/(t.&4dl7/p C.PȇmِuR`=,#ڶk8e`$}")CH\Nr(brQ] 'u%9.N{ls CIpn<3kC1@p pdPZ@層BF Z3]Ff.me -׌.1aWQ8vC7ߐs=Vm"5h"D+N`}{r!gݵBZ ؗkp|zЖU0@ь1<1θߧ׀iO,_` Ӝ%"=qPfq5/_wL-`LLd5daLAo.]zi\*pKĜ 0 X ,+p l\|Wa=H0}$43a9e=<] yt-مS&f֔ 'hQo6Z>0~koYcpxloe֩^AE K|u8TLj9HFCd# "[#!'l/ ϓL ;wSI#PcK#v|(]Gh4 GXco~}#'C%ZgOsߒ_PfosάM=I@w7Yb}"cbhuYa?u fAyx cqfUIY ߧn+dJ($ǵDr{Kjx"zxиr¨`L' OxǫrJΘ0kGУxǔ7ul~L/6//sn=|!6}Gl~V$[eMo?;?Oɧl 'dz7+zA& vڭ-qEW DKoqUAYgz #vD29ߠALLCwvYp"2BHRSDw<[n+cb6E_tFT%?k7v Ⓟɵjzcw6vI7p>\UYөK.C7Sazo~&ͮ8l5DօYr#(~yhZltO@iuD (OU?C>MnoN l7{?6Ujt D4[!<Т ߬oWYtfm4=T [? @A56 ?m}:J]j0ZaȠ"lpv5k[ :5lCzѪ7VG QW)ZJ>a6,!v@.hpPXšr&32z oַ wj~,m]y"*YNi!T}NIilsCz[[\fo]E4#3A;N1u岮2j~MpAFuO@T1!U|=A匿O4q?`dzʹWJ=5-b*ZG9Ye@8½ zL(I8yYtc(B,6huf4!g߽Uƿ|W|koy]ֻ~g[5^5[d)u^岟@8g/LkNc+0"K=rxq坋*qzj2C@r`]/$PAB>f{ =\?Fehe`2UEC{C sg:k`)?8!lb4"2-8sz􊺺΢hE<_GVu4*oaJf.b԰8K;#9馡4̷tʉ:a&d Šz环ل]mxKLf sB͔zY. %^R]0@/`G}m5Xuvq -ꌂ⽊}K0st;=WJ ISQM 4?6;{l3`&W4P =,=PW,e<'}jES g{)Js-RtΎ4 w8I/:ʡ?u3|.6[4$tS@t5'4%Wg ͑Q`γGmi ݴP$7g.EB 'qkI1Hh.'c- ›b*HY#^oU<0534,By/Cx*& _lN!RS>gj WcaL)rX>L2;=61ΜzCẁ'rmr䘮%΃[a=RG;~-"p {s8`դ7Of"w:GJrTp#ǎA"y~m-nS.ccMQr n=kО MM ыz9x&ub %n:-)ϊ|Xg89Er3Mpt^:7Y)φxUWvZ!| 8+\uHEMTN%uhLqKuFbXaSiapof[rq{WS |х1i20Tz$l= X<ЋxS::'9H}2=l4_WG:\㢤Ã_ܪ4 jo4^6:r ѫT{sX9z3E=݅7\/B_KuúA)xBą@jػ 7o[-C=,5x];bQZ<ā3^O0c |+x>.6+;=dk{k zUٗsRgz!^-qzG8%1$grB_b3 vۆOf6&ջY0(K.6qZN2|Z4hFL1&۟vu^- m:Ab,8^p1e~4u=j{{>=|#!q$)O8yt 8sAuF,.g8 y`ity;  zs϶:(?{̓F,ݳcs5#PBuP#Bfa7װ),jzWO$I[x_ݽ&BdC %9ig.-XHaw!~"$q߅B]/es ؓN3XWxe~+XcMZ d2Pܼe.5j8jpGD~l3:P2Ueo,HHbl1Sc;TGii;Ӵf7xiH۔&P&e#C|dJXeudP'29P+d0ME(Q%Xzy2UF@ZPpߊ1qLIt 3%x!yeKؘ9WL[KkjP>`zü*z6PTD|*E&t~4}08ɕx_r ɗ^nߨO R$P\)fP'`mĊH<`mHzd'v򸑆Ef)Br 4~Zqdف]!t6RrW;QqJ ی3L_ⓗfK:QO^c"{Rϔڛi̺D+%)*^|$BVKl@ƓhqJB[4؃*z֗ ' E;] U0f~5SB?/~5@  +M',rFu56sCe\pHn1^.ዚtBϪkQ,{ݞr?odmI ~Cu#N]&'m̱$kmaMTc2-2'b!$LtR/Of*q(3YU1,L$P29xseCKkk4 LWP K i猦L25殶lVoaHA O֘͡ĝ/ɯT:AFcJYS ;(}yl5ZPH!R\6DM2_B&-+iTNB'<Ҁ VZ `WgYG֟Ghd+dxgÇs^-sYsve(p*C|H\n:1J\h$k0 ˆlt2U #Wl6 +B+R5XPB H*iP@#5ni&d 26tJ (ʴ/=ZQ PMZ݂[ZB!]=S>YF>IՌǫxgq,Eֵb^BE&Ԕ3I|0$"Ό&e6z(p":5KS ؾ: 'nLѬ]! l{)JȘZRb4zo{|+抓Mj+ׇ+'1"[AhDbL5ƋT\+>a=]e!=^!~?w{c-@ GAve/OBXY>r\RxؗjQ*NEFM#6_K$MBusss&k|vođGQhddDL_?ڼ=g&cb$lAE E> P0a":,`DzְE[CJOmȥV1sZM򀬕"F}MɪDTDn;5:>k6ej8{8S\q~LKƏ} ;MҠ[/YOpi-kz C&6\FCg~侇#Thr61@0gw}onqF/&ʂ؛ '<[fILue'p,bIi!y3tZE *5hQΒ*d(|> Yraoaá?Ar=oAGkΒR²&5[3(0p mc]w1*+i(^f>= *FN-kn%M F?SPY9[6{AY zʨ088]>[(c>U``2:qf^tOJu'=[KgĨcCw{ar76">t3rB]Esh 띟{mS 6RΈl OO@^ŘU[1"&…,y_ٸ1KU#Bc!3״ eaȦ^IJ u #1u !\KwR4b2[+B\-ݭ-XECtW0x%9{/jr,$Ȉ!anNk˼BɼBq7I*q̿ur:ں#M w\I%UW/n^ܤYR#sa_E1tkldzgVVgU5+Tߥ(M0" XX N TLܑTD @:ۿAXDXB=?Q[@\j$ (.fz&W5S>#cM cHF+ p& U`tyI?&sOxޮm@QsBxdngmQs2;|Fdb2$B߰-4K#~*c%Nu#fzBXqlI$. Ԛ ohYMb1ƵClF耯%O"+tx]A&׋paM- 1A 7;alo޾}Wg_oj'cMyx~K% 2x^֕7|~]< I7{H7`pvq|=ab W_I[zopfO Hb`<0?/ɡtb/i9d^U?M]J~[vm>DxUgOg܃5\ߧW͕3t))$檵yip40㿡S]o l rD ! ?ҞWAv<Z#oxTH0wfp&%3)"ȅވn.&¹qnCa\1W-綈I:>I1XLcŠ6$M JqG(mzsXL˙s)e7)%dK#c 4R塿4U)`&1I!u:t"_4i -G0aՔϵL&]u> <;NrCw˖ K8E@scaΕG ilDhD^&Ȋ@,&C )YK妢V.iZ"RDKcgl`huBDQTwt|GO.!]ܽ]ښcR0韝=Nʵq$\/$bB,Ds Q1V.Ę0aI0.h#@S7j0[Lϓ'XC\ؖ=TKz } yM2WJfzL(1r/ד;Α^n޻R:Nc&RHx@EЀ}-(KIJZdxԝTPQT4p\/7u^Sgf=R)-K<||ۇÌțwy̆Hf#ˆ]YVe'+;X( ѼfȕO8^C[XMK e`}U[}Ȭc0EvKC<  *u.҅ߩZ*rB>[7dB%Ҧ@eWnҌ`ªZ+04X$aD5 ,d/ ᵙ] )tWKzn_asbdp+#G̰G3bBy/R0|ñk@F S}װx.FCU"f0{m#ӂ3(>XL=NThacC6:Oϵ ?Ewel x:#1wRN*J 3QG^cnZk}峅Ҋ)Ղ9Oӫ-S噺%MLN%XeZ7Ca[Av XSƍ+kI7`MRYo8DV#:"(IWYNl(>%zo:ګ"V6<{gW%G95}HyFK#vH㸚wP`776JCx ~ąWG0A!2J< xdTu BO֖ 'w3 C&H:AY -'kI@ǃ!V4dj^ EH %T&Q1XUFS( + DC>m ޣJzF۫@Ox1AOs^="ݒEf}tMĞ<[iy]T?amyP`C&,y-"}||}z!T(vFg_|%tryC ‡zȻ'ȁfqP0e"(ew)7a+fyKՐ9oT U=)L=˘״zkBe[4BǼe ڡ'4 yF'Bti'FC EAboJnEc,)uF }Ͻ*WwgZT.B=`A`,f3 gA lE  aZ v Yl^7Vi?cݨjXARh}Hߢ?$촡 !j<P/4!E1^\\Lr&Ƙbߢ7,^%o1A~sڻy6޽1%,Md{N:m1 ٠Ikv+veL ۫35Y&%a %󳄋uraeiƁJرo[ƫ>9QԛxT*JgGaUF!{oC eVm9;δi^]R"\E::aq(YKd3mI= 25X<ŮjZW>[=-Ƥ'_0t~H1m˛WԊ4F(]ʣ%K 9D y QXf]: L'xJ:Pr,߻YV1v6)Dw2 ]81aI=.w2tZ5IRT{@f4+Jf鴁fdF.4j39,;OyyqadGA!u/eEAe-P\{5"&4!pIlw0He.|~v/?VuÇQ/ /7[ `G2uyqæV K!M c|,M?\6x"eJg;MJib#%HGYѯJ}UI1enWS jaNuj <4u~a@ΨV|VbU66P `J٤aQ(nUY(l/"MA9PiX- e^mjjI&-A2)  eWQn5PHX)/MiҌa._P3A8326c!]Z:r2t}yE7%㭩F!14C':M"͢G>g?5ʀ.gȍDұ :zRll LK{ [;V~}1\ S͢4IɭX)7TiQ0[rHMiXK^mX.wWs :mJ5)q3`[3cNw%>Aeao#X 2%ht_; `ݱ W+|~&5zSsh%GnWcP4ݔ DA E46rJ?A# =T7LO<(CpǨ@c!C|gHHG3B-OZ16FF"OHa^WS)?%_+3hO|8=Чg\_|C}:;DU5KA="J]Ce=\&e֢P&ٚ|gHOu4ι;w Ǜ^=dBVIaBuT>g6ĀǨyo@ )e;%+!0 Ud̆]P Qf]GD\3l)$e6eb D#,GX]4{> ;JEu陜Bndk˚"G9 i ~(E\{ [lmNwn=ի@>g_宣;4jqY9+1I987;*joH|,w|]εw8CouybF2ucA 7 {Pr"Fy'vu\U^%$TrSՠG6 FX Um%%|Ù{% ?X]fpˣ¹DŽœs捼Ll6]X ;Q轋19?B FG7~ⵘd>J oe:CKk!@[o=z/"~eLuLRt7sr Wcdm8HViXs@IOUͱ!bO 9lA-#w/N"G}QBcr XlUc[9\S9V+QoV^ƋҾ %nJ6NYu4wIdb-Z|E,/4;p6B兼|Y&'\2?FSJ vx´ _}qSH;)F<K&s< ;cJźi*?}?G}T:*7)Xe'̓a=tlb2w+혲?:j>{lHh/&^<% cp!8=!lL\P+%1eS|G ͡9cEE(w[LE̿p@xn޻'jtYJUH aJ!ij%ZJQ+ē61 1! n#5rh E›|DcS01~ĭ )1C&Z6K[% ($fr1#n%j1V2'&9V _|2aNycjV)M`Hoq QXHbS j|H) K_x*]H9ϰǛ0&(3Zd6ߖ&*LeL M,\ˉj4LNY×d \03*ZBw r9Eq.M%CT}EUrЀ-ݯ_ݣ،!'~mI5u3Gm_hz+ W'*% 5$h+tOʭfs'UȒ/Hs j 1 (yQ\c~'HlXւDOdC>$D.'ˍ'> e"Ya5ឬsq`pDZ)_Zmkn],_ gc^]RCpw?ICdDɀ!!KJ!v-VBBIP!Ʀ1MtA02l›yTK*j^tBNi3m3 n',,Ai*+0^+|&'bt#CY_20qhbzFT9@ .,寇V|˞~W]7Wގu_TVZWV@ Nx֝R3B2S4FϊɔLe@sʏ>tg6u*: ҁNo8-xvduګ>m=E՝ Bu1l@"ynkh!i9o{Z=`Y\rٝLN0aȎ_xAp=x)#S>pL Ehs;U~Vޖ]/Mc 85;E 0Szlmx;?=ǐ^Vy4\8~%%ux!+r-A `j@UPTK|dgBBV-%e`+{V2QanꦱtaI?gJxrEgL^4aWp`fG'>vO?U{#xy_2h޳g ?<8G4@4&x>&P1F`ķ?`lwzW[a&Di""LM'w:03U9hJF4+?a,Ap41ϋۨfJx# ! 3 у-vIP+l,F8 yV40uAU׳0f9լAK|RN-3Յ6Zfv2^6Z#oy8RA+ZrCZK}~lϏkЪ<:f0ɋ܆KK9' BʔV=)7N$p+pnl =3]9)[rRBs9W.zO ڙQPF Z8pˌr@>TI= s?@f_x6mqzvy21c|I/y[" dq?vŢM Ӻ?pG~lHõY_c'y<왦)5/n|H KuQ9i&xk6Ägɱ\\L_QvEcYҪ\#) ކp>L=V[/$Lߑ0XM$h0QrlzeH=A5=qR1:uJ9N6[t>]d vM0Bg衄Zykvڽ=}3xb@nbzSZgĴ/"d$Q"(uPJ-j̀(D; &FUHILx>4:FfU_,,H8,H1O+.S ^2BiYG!oHL23=O%99leNH,9:g9]Y1 ` j8zAk+Atf 7b)3U|>o e#lJQ_ T˾\u͠qa#J%}0Je',su}Oq/7„zhuqد{Dt!r@C[ԙ9W1;"!K)ϑPoڇ Uy⎇y&Dh E'(OCS~]F;_p[D/)Pu;*sߝ{\O Z-=`NM3Ր(NTh8GlZ۳t&8L 9C{M SNԔNOYb+GӀ ĽlOA-|)즵(e",a+ jD((Q[Gj4% ~0嵊HWY&KPdj od_n@d3q. ԟ4Ǫx TN"˟fR,KkK?v[AxSEbCˋ#fI$ak 4e+ROqƛ As fc[8M= ZS(:F hߌExtb':ZF=zOD9PSO$ϵaS9aDv86Q_E>#1; =Ų=/)~bZf'F._rMC av]#*herѠ@vwMr;YP ,̈3|_s!:rsή8ɤ'_<ˬ ua3j<(%^*D } ~.O #GLekRWཕtmbgGd'Fh 9d`1< }e 8Ѓ S|tn|:|~= `h=ys*~1|_ <нx&0nCfazD_cd:otenx6 ]"c@=׹ge"ߦϨ]2%5.j(F?4Z=Y- %lmnoy*3MGNDQ ֛˗Hfz&af`Z{o4TbR ( Q4G=f>vc h#FqAG\װOЮf'sF5\~)Ù$c #]3t=ňUٜ/E="Or6 Eb^b (-PzWə?ÉݖC> oQ#^9kKCa+wk *Y EH Qkt\yEc+_:Ja,8,b>M"팴^˗ELFO&~|(lNzBP56a~Q?40}kw~xd~`gMu%Y]P9(o@qT@;hb<[({_4U-~40p@_F`"5"딚WG&cvJ qFj=t!ѢS}؃5[͖̟@p 3rCjR+ۢ5ڬI.f쎶;lE)0yWK0C ЙM4H +и о{v>*^A0INe'.2JK"x7!PK|@WJ:u;L%ߌ9aHBWG`aTca HQAn^7Nv1Θ6g:uDž@)yH;Q)ٌ=첵FDa`6}ydF $QS_$-rh0ś[ xpr/nke!Bc˳T]띛1#zlQ˒0:Gnёrs bLn(*΢#qZ7:e^Z[rS^l#}`&Sd`vYR1FDr5u9:t0:/;@!GXqBW>dF;n?2+&"$xt&s2pz½q]/Y'6PT&< hU3xVTr^oH'|yJ רw1rO*lŸt_% !'A@C;NP[Rs.bz2*X!޾}Wg}';.d e˺c<@z;{o:ڭzjB?}q1>/om?==-{@}r1_LuMV1>$iy+RƟ.6.n7˱)}qA5z811D}:r?>,᳈, hF }!?o^ {9$q]*br5ɥ,O3HgNcaW|{ XӯB`f ʮ%Ӻ#I%($ͦf.$7G~Zlp%y>5izrszKIݐkP8ԁ[u ld9JLĨz8vSbc8cbzLBE{$'[ #;rKzЉhlE!mNAYQhI@ŀeI'=f Q|qlXP-9 fV R9щ>@noS&pCbaLh- ))鮏Tف3ĮP`Z 7xCw hvg>X.ikbid/R%m|6g`Z]NntPήP0#g^:;z.99qxP?h0uzE k]'v+g|5˚ǵCUPijC8Ɠw lxTJEtYAPwnՎP&6N!u 8'ǫvU{xlT({-Bz48DĘ'w bvc/NR8v4}a769ZGxW&b{|*|^Un"'tEbGޒjm~~:T:H!#@ #׀$B7/O[I=άk\g4Jg4t6JDA !e^yS/yi &q)ϱ0L2I2nQi)# d,u**?ю 1j)^cw-SB jTI2 ws.t{" = `F{gt7X(t}#f\Ϲ2T_hj!hE`̚: Q+Îo @je[͸ -#Rw1 B#*!6\p69S`!'#1ĸnhLꦛrZO%r}}q=Px=;l(6o7Oٝ?b,wZ78!Z˰1XY0ZQd&wx,ԖJ%ˋeQN'9m}8p5SU˪pG^<^հ$9bX*X'0ذlS'6d F  h8?@V=2n8ǚpf8 Y J-oݤ񵰌Q$5K_ώ'l!Zyɪ%AF 7RCƯG%BvN$Ni(j'Eok{iY0;soo^kA;I!(D" nM@BA l4 Ϡ%!y,PȱL1+aI4wJ՛{|UߠXʓڗkɒdĹwCe@HbX/0ʎ<U&! $-T(Q"s)em7vwjZ9=u{l͎ަˡ^7GA̼9NV.ܕ52ڳ%gVɁKbb"TrfbFrS[aڨڭ#Ԅ*G0A8R*CI))cV=ԩ.VѫlϽ J+Mƥgi_Fֿα? G!Hdnrlv8Rg2J~'`FM[4 u5Eyiad4ܐa T\Nn`ǥфS^e'8؁1&GtmbpwɼT^͊XRki+lulg~z߮P~k_@F\gtuVV~Y٫&4f[dpr1G\A;p`lKr޻kNq*&QOL"@Wָ ź1 '~^ޢwȣ_dv捇7+p^Py+=>ʒ 6T4yf#gml/ SVQř)<=:snM APt2t6xgWr2X跧eZwąll )ءq%!oQ|rʧUQk7Nuw"-ŦsYR}3 +pWv9@hK;0|5p@"5\FhyD\c*8؇S6P_L F7@_6!{?n|=+èTdq!¥mB7vfwMr=: <1^PG)>fBЏN,?#F@;QWCJ|!6[[6JĠ^m- ] 4XNmTlx[?RVM:!8xy(r؋gа%~@:9e)_,7_hLcu{5x䞹I ~1ǐ}g%GuknP۪f#d4$v^ +@^:̚2Vl:I1vq4źt.O!,umծ&#^L2؜t$^2H(K# iˎd>B[vG:fd 04?ŸU/*t?R3Jʌ$*1Ua#&ʚ:S[lmމM]n~s؛+2Π{);nt匧h}(|7G̾.ǠzHdv=Ҵd8>AF(?u`nC$FrM"|-<%k<[QrCZldk;5rDO&nTg#- ^kU5d@ָjS ֑Pt򕙉c#dGOoUϲ}3A(u #QX KZt1s!Փab3;pF4f~< șAFڗ"ώtL%h=*/mPimRÇ s ۍBˏZP&ͨ$B#ݡSy%w?O +Gk5 Fx\C&yĨD}(ǎZy%ى1pӘ!~٪5Ѐ-J͜ZY,kB[-[S}P"VMTW!m1ٳ,l]Dž7<fi?Ļv2~OՆX¤"H B Ui {򨹿W_%Vu{gzq@cvC%,BED"[Mc(WwUnDt^29l) 0˕rqjMy,AbI$Oc@50c=-FPA8VSs&[Le!#i*I`%0]<Υ  de9z@d>lDw^OC4L^B @}Wav<ȿ!X},0oQ3_A.I Kh9 g:؏`w: ,)I¼BcM#iR>}HS*uR;gYFeN`F6glιƈ}-lv,#latGIVUwKd v?JݭWWuU+Hw(K^/ )j1g X*UD _x%e.-}7Pd'NJ vͦ.:f JYЃ~FV?Թ l6#aDN rsP|Yj:5hZ~qWw h?|c/w IQ~&NBU:KVU+{ۘu=շ^ػ??`@A U OS2KƿR5)/[ 6eݤv({p(Jœ1GA"U!L\A9}tFX(Bh X=J,B['TkɁ O1 2K|jٷ,FN͐ t*쓓bb=(H ^k/ %BԊx!Z S>&'MNDdlP`.ٖ ʗvtoėa_Ս?jM4r%4ʒ~W0lHƞ$g7RPi=h=oolCd[鵟ķ%ɩb빢b I1}:)ͩ0vjH&iocFq8CL(Hy PK'Eit5qVBѺr@_JB߸'9TVB? ']f /M)?c<~lr] –#-uwGa]n(CQ8;>uzxw]@J)=r tlG܄r09P @t",aY)Jx7ҿ(M Vt⻟2Uw-g lPXVӏ&=v2ţ~Tf C}Y' ªEqq4.,#xUV"n¾+ol Rƹ),e*~.*/;@ho<oŤJ:RU[$3WYJ(zut7z3?S4΂9:slt4ݷs7>rèzJ{*qQխbܫ26 GiD'(rsK|W{X qMDj/-n[DE;c9JW7ZrWKqQbOl &ɈMQ 6Yc>dekט=r|xL|bG085* F6cU}jd\@0ق/4x5H.;wq{ؔvNr|́;0ɛT` ::ޥg7߇~Zͭ+C+lowj{§̅٬<6Ƃix:b4hb:]$jC͇'PfU`{| b t'\/^ nEB _ ['IQ庖"iTb=ycl˥$蒉F0g;WhR@V@3 78`?x,Q]PCwOW=Yܫ~w>P"]^ΨI>;7'e?coggkw\tU?ߟzV/pՇ>OYmPAz5 Kô g2vq5W`ؚj8xc&mjkw%;m-R5n@_!Bs|_0 ekۧjcpc ij_T8fucsomT_EF|nyE | :.KA"1k^5CJ/g'1ux`@viglnѕct"e=8Prq٨3/F*5X 9\nOөh=Yy BiV(ͦ4J(BiJ9( :?:XM->&85*$2{ݷfYm؞=t1.x?\b3y#odxodO[(nl [C?9=ޓGЊ?5'ZM@-6S\ Br2[@L{IhŞC+ *&"JGڅĦO#LDC+ю``r[LH~6m71ekbK}zMt%3>p/ 6mG\uD:C$f3nJ^ E $ o1$:1FQz>tEݏC@Yb#lG4q~nb<<-f,[@e)X-˲Z@VR?ղ,c,jY-KZX-yz=wk02{>2{9z*| ţDT4H:e W+{P^%ӈ]$5|  PH$LS$'b},jL` FKkK6. ;rcs|)rɒO@wW,6v1+ F 7#y-c6E,k鹀6Fp!]2d3@Wp=2\&yg ߉ Uߗ2c[ "> @ V|PqLd~09N i{|`cY G= ’̿ Ľ != `-qYpU\J%R3^‡*1qpIk@k0wIŊq c>{ѽ9r;L!(a^N&I~t&"+Aoڃ[2r#W\qPu] u z.%yN@KD5d{tr9s h+z4=lSaC@^FV[~B dH }$j1F/tx萼Wow;C:[ПIx^Rrn ^NS${y9elك쁗OWr"¾ { H7lBi_ֳX-K|GX|8|8w(:[gs8 Y<壋g| | Ls*͕wG/TYaN`g2W&3fG{3oG=3g&&!WI ;3gر9= ,5}C"tuGxg|˓=SdOnRLPcGh(]w05`;>D~[Ϡ0t($ JdJ 8u mE5= 59e4'F73OvY()v?omZNQ/)GxBrznm0°l~ |[?_`+. 0.jyssDbzDϐj"+7#k澬JB-va,lӢF@ghJGs0-T'gg)ƟK_ȐsC/)'\ޙ0cOuVRޕD^1t&3IaRv%%f`gÉ=tVmi)!$lO H8mteNFtр l{/ 6nJFlUʪ~i`iA;#:~ <ŻIdu:xzu# ),{j;BG ׈l#aHx`+{g lCe&ҵjRE<%UPV]|9κ .Fg'=JۺV:%X+` +vak]/ͯD= ! ߏ5TmJ ƩFy(Ez{1Ebo.4y Z3_xl“fI;)Ϫs#F`V"}rr.<.ehNoAпsrPާ1E~{Ŷc_+>B+#[%։#OlHHBL2_Uu97L"޻JHUkp{V m4Jo/% IYhq w#ؽӡ|W?IRa:c_]ӣf:3l&Q1#(z9W]J!|M/hqB~و_ʁ/8趛qϞZ7趨eDp䪖y#ʹ.2Ŭx9-dꑀP"EpYg"9h v.b:-~4Х47ffF;&fbX!h@C! tY. KeǒGCMbl1~rðuq:Gg[jLp3_N{b{q‡+{=5"M` Nq4ɵwXF>w 67Yԭ, PwĐ,C?nMiۼ yH ~ '4Np5o[w,^Y;xgdI |G>/l4qh,M$edg76HÌ R\`$6f !UИȄ!yɥ~; zX >逶fk=9‡$/" ̀POoXWHCXO';i3BP3w݅UE^ .>[a͍ƦP^P ip&{q|[[t|T[zA/;ţD-xAh.,{$[/ڍi5N Y>{φXNq?{h6ko؟%|2~5i0#gu?j˙aw0) L/fI!; t$;A*w<:bjĐ~t\ASA)APȝti"Q;3,+f<ѿ 1=yuvBUEBzP' 9sٚk72M=_j<`>0F8cXXlǝ )0%u}kI83@W RҎL`G[.4_Dye3 ,F90~3%!C-m,܉'Aw9FbvIM-BݲgʮS4 YNiܕVX>uֳ54mpgݶ v[? ׋[m9VZH`CP77E567L0 PRZT{}#FypWo* h ;mCUK;ǵޅjhdQ"\(+Y%x;G=DڂKB1 ŃӁ+Z~Uu{n̆kh41juK/3#3cޓPѐGlּQ/ Sa`G="Ut߱VgDUm9jQ$mUuvıgi)~ !ĉm9ܳ0DV&K1 6j/:n AP[$+29e:h x'4Oڟٺ`obIH*+^7-Õ([B(2(κCa^: +/c:ޱ7XGeYпlu8ǗYl)n`áB{dBہ\jٶ&Vm`F: G:祉AZ':CtZZB#mYlz=208cyYALDn(_ʹp"֢mX*c&v^*JVry-PUc|j,|\˖XKP B4vL bIvn6H&1o33g\ۦUWixh`6omܮc 6L4V9sMu!cpBFs79= QDuQr.[U3A;,W^ӄ(= ZYZSd/,!/.'}X 9/0{F.nRU-R{RvezoP9gq:U`&*xqFuE#7FYmWg%,%(ZnEXpUFieV@[/QgJ+Y9fbk2LPL2[܁Ap ?b>]1 $7h $F 8@HB$Q7I"‚,Հ _&̲XiO4`.+/ksJ Ϟ>{fjX' ?7i(%ɲS'~%įt!gSTfČ?Ó.}mj业 \p-Iʯfà8 7FXVƚ0F^;tFg1^b6:2.BUKEr$"b%`I@x2( ,]EyNO]"AIzu`PϸiCE:@Zq\In|rfPRg2ZBq%=f)fKn JLsP&,?<[ݚw<6MkEy':cbƅ-9}-;Ƶ7Ꞩ&.ȊMƪネN.Q.T30Ũ3p|sa}iY"MA / nxMQa{$D7Eg=ν*$@'_v4o0=nOc<~дؐ:x.*;N>XQyJ4XUiHF֣h30g}L@sZWCh6fZ3o[\Z[~ bڂ_T_Z!2<( !c=jGpF3$,MsP~mL I¢GG9,x6#HFѩf JpE "Ҷp#BT# ޵SgiGڡ tUx%GG.EXk P~qiy q{|X:I1v~uڃ9m "{Za܊;4]?|σH P.m) |9`*9& jߑqi,UNј+Bچ3@| F=>9`WkOj ~DQIU q@J5hmH[˰^R@ucotBS3w.YD.+5sRũFx)N͍~\_2<䉕BO/aH|Nn mq8,<#2NziNX/ ű"MC7VKre &"݂ue!>\u.lԨ(~J\NYYǷQs_k]xD-Kk HyPQ Nt)Q D7oCA)BR+XƷTơsI!LIhݙ+e+}!C+e[ `˅+_R)Ɵn^۞u3v/y@o$]R6ElVXyu(e'Nʒ,(귯nQJJAA@Eu Dm0?YЭOVkgJ?*zvB$U\] uufTy\;zԺ/ˬaƉnCRa3uUCN_%5OA;u-crG*41Y?%2o..VQ!݉f< /I(k?-X*ovm7OħۏsHaוvM 6LǶ#)Ow'9*Ȇ~)W7ÍhgRn 1` ~v2^FcɓԮv# EjnNШ Qr.0"ÛYHfCj$L1ԔJt= z}lsrZdn:PnZ""P㩰WV Śu4FIM0sƐCp^&%fӘ54*&flQN]M\XUB*n"Yɍżh6HRZ8[1]CBo7jFXBHpq GTfTdaXEe$fMkiHm'6(˲4JUD+GfƌꌄQ-IJC()3 rO \\J]Yoh& 3ƢJ6}  HלXdkCwįP>X"CG6Hݮc=g}v:]($\2fH5dǷ"Lt6&j~$b98 "=V\DYf  8Bxgtn`$8r}:8s!IԴ goQi4Oa,^ 60DwC"tٖF˸؄0D ])#)ACMd1@ohԌ dԇQ2{)B`d CApMPQ 0 /1%}L`‡! $2 Lb8oʨl/cĎ)H4)9eׂH}v%C)J#kR*wV- 2UDψ@%ErhTn]a$M؍ڰ>TUcG>C(3F,lN]ه2uO3R3gk;JvaA;Z{߼u u1MdP k}s::G`]k7}פ5'4|"wϭT@$"k/;T-w2mp*Iȓt{Z`c\1>!W?#gNP9̲5 Iq8b1@Ne`p @4[3̬ExIZ:gsWEۍzHlÀЋE  'Q˥:6xՓVSZkދ߶Ƣ7Bh-q OcdhX1b} YtMwA˧zAMr;ԭoK OꏉX/rM->/,b=t"+!Ntحw!PQ'*t g!{p,J˧Tra0Hn*ysu:6;"4tL&S㞊dx!.Ru}Z`9B4QtښؓY}^_^|s>fs:l_%p>bmlW~p&Bd הkq[1e9Aتd3+Lsv` x8K2>3,[r4WZ*4d0hrEgNDZaM"-q1,2)_9AD).rw {i ZazSX2+ƫC4U?a_0Ĕ2VLDI~l* <,QbWs׃ODf3ni8[,5+6i]dX3)pQzuRPk3Ou{&kz my^S1~u&0\{p⎂+#plAؓXmN eG;~zԋOq6KU%k\Pi70 U/Iq b˲s6YOjrY t:Pz&1lA>,ΐ1V!p6AY0iC#OllU JHGk:U(1J ( 0U03NsO1qm- ki-0E"${`Rو+Z[Dbq3;5;W۽s h$Sml9b:Q )k&a2OV޴%Tn; O DkBXڼmVӬ+G^gjy> r5Ty`IiU E ͂4#R<#7d9@U*〭N16g%uZT*iAnxWtTGZac2\IKIf@9:889(*!+x P{WКw&'6!rq8ТX2an6S40x0It&>bIRzXk9JfIGH[1.X0B8_h.(\e ಊW|K=f3܅:ї%\Ý;"LJnCb{$Rq~72h2zһIp"G5 DPQ9.fl3G8 m>=#֜|45Jwmx>MAZ$gj=C%v[>rTVbvFejQR A8;[SvҺz_bUE;5h;b 'VjjbÐΏ` yܶ-ORoH 5ӌjSs9%c%qUpj\gF3츥ga8͂rqֈ#3_gֆE~w!* 8flDs}uK}g0I&)$YCoPd %"46M(iU@;`?s ,nk CiMjx ;tWdd;b._\3g%wٙ^_K27gRalEᲊ/#-1+ɇ6DұxDˍ/Uo_e 5S1V:ؚFX >Z|ZfåҤA;c6gTGdH{PȳmJҒIL-3s)2ݽw=Wn~e^a!TM9L~z5O 2[oܛQo8_TؠuY(ѧGsW{Z=@0G;׏ ҫpx&YT2[}4 _Q2| T?V8W0{%\U\Yz~BĎH$NEm b|\c'injNpb g}o&4F=IVF\<'ȯM%] zڄ՟60!om/4 ^TI9Tgdz_ɺ=~]ko4X=xi"Z[_xZ4ylu3nSY5$moV1/z5P#` /Oj***xa5bY[&qiRmDJ Yq螄mS]VJDm@+>_XZ܊ߑzDDoLK+qTzl˺lW"zE6Nd2XFitmjVBk?% Wgtr(YahXo0<)y'0%W;s"Y^ʛkye~{OgSxۚ6PrX$A<8GJ#LQ繎SVs_MM/jzٿc1'PtdDFcb}NlbJu/jf=8 iC?tQb$eP5i.*6I4,}^^^}jk1OiN6_Ntzp 9v;Y;xو{.(RkQOҼä5N0PfɨFZN8щt8\^|?ǨW}>;`6CvddKZwNF#:/3[Iք3!-6\H=kk'%-KX=sm3 dt1׹pJVʡ1G<\zƆ"FݫD_f#QRҊ+DR̄$dh![^{ã͙Y[Zz7:l '=vmի'̮ݘhϪ7~*DeA&فWd0 Sd8]:#IZ=M>hlɧ::jd"[aewrnAd򲇿WW¢^X/u^򸾼ѳP?# %oPd<ٟ6:4PwΦWjFumŭ8ov/~٠Ҳ3a\2vܢsFUC5}巇ҳ?U%f7@.W ^ФЛDNvԭ X͖w/heZYXr[O@ i3 x#$Ej*ơha-dF[κ#)4deeq+jj&d Zj)mG̾CI>_o{?nm{; ;[[^yA 6vw=*~~9~_mmy&56fkgW;ݡ^z{GƋݝ}sh;x?!Ӌmowgj57w6v+4ܣ Z"2G~xTh`o*mmmvDj=_졹݃Mc8@mZ6lBUiI0 >JSGݝWhp#*u*N9F&5-byh AuboF>j(C,oz)f\xueñ-k88ϓox_yW}oړm}\FАgXˁ 5("Bq>IqT!#ptR~5sg52'<2w qwLjZC&^l'<_|`Gg?^ `NpvgҔI;]1SfMRz9uC}7̄mBCO'G0i0ӡLT97z D)Om9|Q#Ɏ3VCK18S*yɌ8uzc=ޚ35c뷎QM\ktJPS NyeafqP?S$S9$@\eƏH ze&46K9cP9"to5 A{@i@\]3.A#]4gVт^G/7 K+3^B#qBtAkU(wpψ!94dudL5F:~Ek'YĢHp5 ǭEv@'˫ CTSrb25OdnHHKk \qI7Mw:H",BGUm$vG>U<=N6r?v4-MIXs'[?;#)7Da?v eVm>-ԷV*wոVn@ryrڈQ4p)ʺrʱr*d0$c(FI CԇY!R(8F0eLyXSj]zr>@ytF1!)%QS(M`8)FS el ms $f6frbELMa(5i~8 &,q4p#PLφ q~ArMLsi*՞JmC[|=09-,= ?Rz0PPO .b8 5'8mSX0NwjЬ3ƃPU3<8y%DdL06L( n;K:$IlV " ǍWJjlOmKxʗ8РZd";a¥PVdkFU$+РH'Ezetn(Ǘ^ vZ+Ns>{TR7}->v_ܨJasXH,>x0꩸^̬ OP.,ol1x66={9}dXgTb ;oPczitei(6r앳kJ%`da?D{( UMÈl[骖+έaL=M*kmњ/;h<{bپV'l*uw?`Ɠ4gxu@.6, 1FPe]9x}PIpKH=}? z#/chR`߂S+T{ľ"*dEZBQyJGIz[ ؋}#lb, Yt1d9{mǢDjk 8~m,3aO,@$+Dݯ{fg*"37?QpT?kLSm,T6 AgeBOǐ`dDK*bf)C cW*"6axux}T ˿&hin˓|pȊ-2 LD{k8ɍFBa&f4^D{IƤklllp %#wrzb{" @,9BO oVI;!Яb/5D̍B LU6fkɔ^>'-cNSl*V~RzrEN ˕1K9|!q@ T/ڠk"&пV͐KRK1.V \TJ Њ~ؾ87lt,~9s!tNNVxCZbE9VSb14-|k8Ȯ0:/pi YeϦ_4tl4?RE Rƕ $ߧ[lKC_ZcYC͉kdX&.ˆN`J4,Bt p 0C1sj2H9fQX0+bjjaJ?U*qdTtܺ8B@"8i\+*,K`rL"ŚՆ}XΙͤdXZB'eoA3dr\@IaެGFC;yXK^=yɨwt$6h%H`'郠%ľ!2Ml>09M00+;yT}9gn` 񳮳ؘf-T$E0Ԧ[!*1^zQWwJ]z ;Ě:s_Q,fX0.$@9&2hM>ӧYp:1}mȰ@$l'F"i3ĺ6ڽV;x=c[*6m/Lvo*L}{ W:4ef65SMMMAԮp{TuSYH:gF8*ea8e T<)gEծ7܀A.r{^"apx؅ggM4+kރDI(­7# Sq{2٨L-r%RN(s zI8[089㫀kGIOPX`Ogz}w].`} CJvH4VMXl)XXɨ4ZPo뷮cޱ7xHr`$ \w" bdB65@֎Ep2I0xkb)=g5}Uwl-{}aC#f)lR0&[ !$.ɂ8@h+FKnol"&/\Zۼ5go r+F#lK60ABZs,zׯU`p!)7s-Q vU8 Fډ9 p`l"p U1kҳ{"D9vg8#2-Ed[")\ã4kXpxQ%T`0|$3$WʼnaCV䙈8/V4ôcZ̍LB $nEMܛ-#i]#Aou^c.[) 5qf.ud$ ܀N/5 56JC,44M)ǙS.G7d ܤ6 q rŶᗒšM퇢naw:dIc0[ g?LeMd1 %}Y"s#cͩΐ9 ;\p{>sS_~ČEP|K2C:~k[5rnaS+,fE^Nql6N(%Ыvc05.n R)+  ob7ROK.X 0㷨V#L^&w:〧R#=O^cxchMPsE5%`TNNLڴJ (P}d~nXxjD}?>EpbSxIN:իO\=F; +53Сt4C- Xeix>[Uoә8ĆE}+I,gxv- <́$Jq>e(CG]XC+I]1%'bE3)Z+64 GfOCdW~ þ픓G=Ouc7/W5sQ[1Sf&1Pȸ04 ;+!"}0Hl(ԭ\`96^;jV*Yğ޶ykpiBs鵯 Fa>=bul wշjkV[~BI|6X j5mfwite*S[:LzTQn@,8lv>!&nG!A&F6yhak޶^Y+|`ufZ m\9D Y\~S[g6CIƏ4;R.D`mpgnh_̧VA2c,зIlM#¤9%<[/Drba2x7,Қn{37A^Z]Rj9+F->0a9,cB^B:45owĺ^cX18jv$Y79,V~L/"mB+LFoUo0޷'Ȼ&dU 2xhHDr:kW2Yu!w7I|#M7<Ӥ7@NvJkdeC|$ʹ–nC}[Вf!dleCӂMH"h`Tv,x!mk1b22M\9'E[kM'DLsrPs@uh [N6Ⱦ3a{!4T r䮱p27hx < /āM3̗\&7`N,0J,֜Ii#YiULhBy% ȓșxƐqMAK[y4w]e l%.~Ʊہcͤo1zmlux7#~v s32NV#A dg5FdA:a% 3e21aļj`C7hvV] n^Bc#B'8| N0fʇXr}UUkS8jWw[[ _{ŵcplkܹ!bLv9 ` ӠG/7 ij)ZdNbˤ0N<ND':2)ii=zD!nVϙDԔytVBѸ2=u'FYAgDЕ> #tXO'&hRyqyIB:u@#{nNk,$k`d|D8<Oqz2.|+0R ` ]r8kPtƏE^*:^(腧_6xR5f>9BPC-`S}1#Nԍ{ui"p($x5 #Fb 5'G{ͬu.O=Kbb11:CPFuo\$ ;-ꌘ-.N;ݠIjE3YOlzlc:(+c.E?eBjB[>v}drMG͊+8Eql;RſVުUTx[C3΂ۙY,=ؘ(#{mJ*Zb ͂7T( 0cWYC4!K.+`! $b/Ӯn 17ʿ${̹(AWpeOMozoCfķ`[ ߌnՉD(`8\$\YC\șZ;>&]MiD#6ZVM4>5Y8Ȧj3!lI4)6o f|u(P'|D}a(MΉpC :֝ޕ2(n; i'#P G+}T7+~k|oժ# jb"ν.B3'bI@uxY"yC x'B&*,4$XIJ1aܱE>Q ݧ3ٍ} 5e+)RU"0%ko^0r<k.Qk-auC8Lx9z$AA]IϱiFN$Y3 ~uck8::Uv6+l* g֕3Xb4 lgb=i`zޠh"&Bs"-0I K b@h_ehd$lPLF/lC,[*Hn^_dsG>.X  tZ0v44y`u`KtW!Frgɣ,xإvRuVg >{g@R¾8l7{e.FĂ9#Gq$E0$گP2D |%d׋cF֫X}q1 o}կ?^m&k C{Wk“4?V5>>?gְvY XV9M7p9/GC&TEj!Š!e1KcT&t%QHKz=Q]p!=EJei<b49V}bMEGoyRP#8^wW>Te4z |BP,NdVؼQ?d/ mՉѐnŚY2 !WG:M!HpAp, Ӭ griި1!=Bs)ia)ЪҘ`B'Ba`}_oD5/whY;la){:2>1K,sIGJ1$o0IEm)]&R5L <3}2tCgmU7ʂڰ5+c4uM5r$١ k[}ejn0v:QO pEu'IcFwU%P;X,9ͼ>|;J]Mil \Gq >iN;& }Aalk-*1{&E3rR2"95<Ylħj͓H..5qJ&3*'d(ŤѫjnO=g6F<ruF@Fm "*6Ks*7_YQ#rsL_K'.4Ɏ|KV ?8Y7F}m ?(&GN>7xQBZ}!vU}Ci+i55$R5VNjr— 89UMhx!P&.'7J6sBūA A& c @7+Ѳ $'Guh76Đ4v3$eK"=$&gdy!p x˘l8mĦ+L&<{ (a#=&\ $ԓO2l -ˌ8r1S`|Kh-XcqT0ڌ=Z~],gc٬޹Eml9wֵ4pTQX93[h:D;${خ7k]04? `Z.xyy?/ XA W%_2O] `𳃩8BcUe96(`X.#cmHc jW.MTICmYST=jT!RDV \aV~}xR$P(Ba9FG[;G(bR'1YDqDE4cjJI$܋5]<w?fU#: :J y㮸$x_TXh"oK[6s 0`YTE4M)xUO(V8.SDtgф䛙/o5))x\VjՀ.+YI&dUң\oMK '+"4s02@ֳ¼{v2fDUZ 9+}9\[i҉Di3tv +I0SX"YF AI34L]g*Y 2'9x8~p5֐zm Q#xZm^2xQ(Q yb;ɕ$!vE4ٵf{q=0 F%&2Tsq#0!+=s^~6J.s6}d>b_|4%LHS gK*2ϊ1/_xr6& +F]v*FlM2rSK}YJ"X1εXf 0sӱr!wl3:HrRk-U8(!8l{g*&4fִfn (t[gL'e@-?-U(ZH͎ͨ+|xn{ː#fؾ'_ꌑwЫAll@yz@dP1[xҢ翝P,d#uQ׊J7z6ѧ¯QN#6f`\˕xm NցX0u+abE\X"j7X\~wy"O|MdЙ6 Kܰ?LAvgǜQGaح*eR ~`7k,@C Zp1<*dWr7Ği)6. v6$+EK~sPݓ u{$UtrNBb&$R K[q~f% +HMLj%w {ާeKFͦ&$?hJF39uYsX_X}|O%:IJFIkS ƳӺ_!h7N( {Fjc 3H\_cM噀:Ib|2rz25Gys,v/yOXSvh[C/6Y;ޅl+2> <5f쫹.J# ҵ%oٗ㙭:Jz<kFp5x8d~#5`6C" JTm= f呐X&+ e I'7 srQ ~6Q$Xf[[//yer N&"w0N΋'J[y4xtv CaS5'} a fHL_6 匣(ܥa;Zh0i ,MN+F.t%~2%#N8k?(=t ?/Թ6;vBgߚh'b 4gd6xu{ʶ02QŤh8 xV/|Kc;a:>"B'3N4 Bl" T$w>$gTAc C牘蹌 TN }t ÿ~>?Nn_ΪFSwfRc2š~TP=`7}ez>B.pOʎ{Cm" XƽcoM;v#Nh0 {oVRBg jn%i$0J%604Bc Y\LXojw=0(q3ҺD=/=3w>[?}?jwG?}>V=}7[^^++ B}ieax ~(N; %oPd<ȧ1""8Qxsv?G'#:YT|\nԋeV~ &mN(c׏Yy6s (cйH(.4EMHvV Sqcy"RƷzsg˩;}/IbUlm.€UF "aʺCHz)]'J^@2_]T$~JhȇaxON@*t*嘶AsYsML04X}$UTmv83qVtAm.JlYVLɰIxєJ|ga6< "?jH5:`j*kloHhOt{T剱u܉ΔK-00sz3 i'8SeL;w2*VXLa`9%ta ͈ :a~g" 9#z?'=)T,M\O66^ziDQha1uM(ḋ QX/gm~>Ce#U.7!V0hyII/aPeۑ ?i wxdu sW#G4yMzY3{FiLl:{]ea^LA~`['.ȅ5fHDaľTЪF 6AЀl )U]DhE0F8M6RK`Ue"RqWNdrDC42OtGȀBjţDuA#z%kmySRf\9$򈺤Cڥvb98=Ȓw u_8> &}E-•`SƸ롐5< ɐ/596!;Tծ-O40:vM|a2,9]x9tbU4C藐!!p|Fk6_/_p(mkɼ*$Œ;ntGI l4*`F{+&:2' >rhq<(NCCɚ^]8V.-M4:UGm⽱夵`xNy4n6LuLL<>:@sGbGpOr[Jٕkl(9xplqB=[ y #.%b(X"H}ΫS-.4Mzv7v݃ͲWH+ѻA-+ñ͙ԲsLHV~'\viV9jEBr˜UU'K@ iOIaFUA$1kj 5Ĭ-1?8)q£Uuᚆɍ `*2QwNxjT?P=Չo"{ +Ŭ  Q#4O|QM1`hn/bpAީ6P&kDzH7 "4lQT|e\7Xj7ԫChaAL~E@ڶQѢ0%u B<aʴ4A bu*˦Ƙ?P.S.ӌ4Xӭ. 1&N KOW*F= D(VpxZ%€hUy?mkp1E-rB SkcT\^Ë3CPhS˖p/PŐ*2>ޅ2$nuhfviFOBSwLOeE&.4%¹MT Z1 @1Ba&p i:f(>9jyޖO?8^+Mͳ=yb{[^rܝ9#4o1W߬e˜#z/k#H U+<5TyNH| 5^X 33ZM︭m۱, 0 DT/'`0Me5`tOоRh`2ymv_FF񲖖"IE_ZƄ.XiT GX5 Pm%:4$HZ:p5t s= âx>2W85*X6J7Z{cGJ1*utGv""IG@:'^YjDﰷ7@eE@2msr ɨt m1H()[!C8ysH3^L^`3pf/}%&a؝Ψ h;I,+i w{ 7_B[E$I*M زN l:cĶ )M!(~M"[҄ԁY4"WYl'4e[Zr}7#y_vAIϘDFzC u % m+ʧ'x WQC TYt,@~Afp l,ALITJtMiapSU7RtD I4BE|71-Nl(k]cWQ΀<Q .N!:@gIffʆw2$/ang ޘϟmN|ݛԔ -+'dDŽۢхNقXxg^JS;!eP(.aV\YÑٵPYI 17\f-rvkД*PCg FRh.Mn;\$Ë vUᘳ&(!悙JcK0$iHV , ot=`YS4: tؙ9%20;KcȡڣaUP&]1Iz(ɋEmI.Z9E6*9T\Ķ;4&= 1HY:="ϼϸz_؏m'e}r-ϭy;='ŭaG/ v#riq{* [qOwOQK [xeov+%s͊fedO.œ6 ;K%QP͍{-t% Q֏ߕIzwyOZr^zTzdT-gQQy FR7U1idLan4ŀ<L׿#RhltBD GBQ^L5?Lj% YIP$d :L^0PkYG~,@i)4iV+#EU$k`&J6`~xU.:[UL =[nRscU #A!4Ԕaq^QcSn,*ԐQNFd(]ٛR*IFhlnvʐm$e GHd!Ɉ!s6ZK^艁KQ<N-|M H7n^K*["/0DhR. v"=vG iלlݠ1=Gz6{lY8 khn!Ю%siA1 8% "89><:xŶUH]}9 kUn/aju:C' %PFDL;Ϧ23fLT#͹*mx(Q%0g ^`vgKiC~bk?kz̯i_ixLuhG^cz=wG{bХOh`'𷭝#c.#6*$vW.Ӈ`pVMmjL呝*AgɯtJ]+4ҋlɠdLλ*Oޟֽ+SBpu9/lLyt:F)QgF-s^JL/35@rFЈYi Jk$]wۚ < 4X|i~p$5*T|LK& ;Cs=C ScP/MMʦ( f#Q-"TXd`4P-=YR ,Z覱qwD&`S* R'ͮMb]Z 9CL`UN>KSzJS\]Zpʜ"y˜7JH%h%VwLAZ\w/OXS^@jlOJw^6gJ3%T?タӗ_@O7X*{>h\M T4o$?ϔ@U=]2/RP?~*k߱t^Rw}f&yUPS4߿Lѭ.NZ6Rഥe NWq׵0i^ Ԟ3oS< 4BCN;B LjGގ1o2!&GcBl ƳXYׁ QDUfkソwۥX %z" 7&LK.J`=\Tzdk%*,6^2xzɹ #A n_.os߭늒j#n,4-3'mQ܏"Z2AN -a+|e7t# Y ؽNh~uuQgܸA]asc|yw82|;8 i"1aE\SyTUē0BM8q 6;c†h6A# \~ ̾2)BZ͗,t %pIKSfɹ_v2,үXˎ ~vs^пEIpDIh/tyԭ˖͖wnzA`eŢ[nHYlHD>'Oq70az* _o{?nm{; ;[[^yAo-gwcgmzThcxgs:~qPRW\6;ԾKooh5xs_o7Po^5Dzl^Qn|y\vG6r+ B?8nPwG4ƛc{ailSGNKGmT6-A<9Gih~j{s\ ihq@o7JoKX|C8\ nbmP먓ٌtw/X׎ kHH>E1y؜VzPdo^j?ulǭ*'>?z[ OLG k˿3l<,$8﫴P/w^eN[]kq=[5ίtǏ;ϼcOpc?j2ievaάo].e{_NBJM-!M 4hial}՗KO_dxz佣*>UE':ɖ,(Ògimm76v4ѕw`v Rb|.]\}%4FڍZUq[ImM O؆Z Ⱦc3/㧬vF_hL7{f CjV1NZךYӣ~me~_5_9 ~9===㆚NIcY߮<%ic+AsǶᢔ>4 @KQ[. \dvZxq1|r 3-dNأnNX#Z(8' v2GvvYc*JV(8 ~'($ǐ0pGǦp j؂[,tvBҹR*fVcq}h  z_Q]o{'p` 6d,o7 /H3)^fGGbct0;7>8@uK̓ßv^>.Rl+f>Tm>&Js~>nռ*{|i`m$y镫ǵVʧz_kmJ#5qUSCu}巇m5ϻgymDb}i%D#.yY}d7QPK_/}#-7NPKR8A}CD%ytOY0+^_R[X՟xKkˏזxÓ۾{9[F^i2 m48\ɞ 9Vfi dxo3CxVs_j n}wzZv~/ V_LQ֯>>W<;cg5a3==aڱnoḆh%*ܢiì:}ҁmЮ86q3ᬞW}V?6(8IT|ޝ ޣM]eU^^eEO -CTɮ$fVJrjAM¯91"(8>P%Aj!J$L+=%SH4e)+J*Eo[?=@e^{|˰̖=HVz8T ^gFDhF䜚#y(s0LrRngn~&I2|XYZvE]I_&iA~ZŹ3SV `%B$YW΂㯞?w2^2Zal0vvE""/^A_PamlύTi<uv%g~mkov3Q,ߨ[ K yNj]>t?U+O rBΔU{v^ޔ\M>ȯ2ja  k}qP}djL ɝ"^ķ؎9O2"$n'~z`-'yUf|(˲w,/,s9a ),nk)96iᖧ'ԾaI38oo6/>I&{=W)6)K:}V}5A97Gdpw`7Uˌ<9b^Y\LEo-+++| 8&\fc%-#K2GJp}o*>|ѷ>GH@Afc[c>RZ;6\][1,[APe47MKiΕ>ZϞy/KoNٸ޻ݝGۍVzgw봣>p+%?@7>v Ul-N8ygi9s% YTMK_8,GD,goSE#Alٳ!"$"G?7@qD lTP<NJ>pZr uԔ~j|s)_MvOؠiSOLMsϜ2E%qvLƓijm-iY7~`&&؂ `6;~/9}˿i9Z OϜҧg7'Բ Zg2`Pᐸn5 ,j+!<CY-I-1|M&Ww !T7MƗrugʗTTrZ%*hiiڦacǍͭ;t8jn5N_onftfiJ [͇RIjGɨ-0tܡ)WS)Fs&] CZpR;6њ#""`\{[T~pH翛O?\XI7~ UK[MF?e<7F"ugyii?yf@v<:>dЮW"1X d}SXFPI +*hdn(DddP݈hޫx@ >D}>;G?F~hs*UG / \C#D`>q &Q$gp\P +yaZaɆ.VDW,) X,_ї`(x+6.g04w^n6g66Cjc>@sKYRrg@疶 ]nFp?zY]UvkMeJ7?]G^P>zkAUQE.dr2fB$7B9Ǚ wN ]wَhp/l.Wj*c&=C Whe<@Sc|``Unx6_X{әnO/%pvň'=^6$#n:+Mh&mOLYtroh@[-XӱD-_q3;3 w_vc9ss}mTxxg/7͝}*[Xnsc`gscq|Kovv$WTPd oEv6/w7^M.X~QX@2Ϳ5_XYr[K3 vm=f=6~iRr$[/5:JU)nӒ.%H~j4667Wv^l zrs햠.vlʛ{;GqAsۛ/66h.$xf R]->BJNFU Y&kj j+鄭1ԬH. ,#.9 qno7Aj7*=Nl*&:M]zH7:dI7&*VqvsR_8[2)R<3oJnƃFCdt""E<?ˉ Z8 La)T D漛RE|b)K4恨'fJA6yT~?Nχs5S|!Fw:W2,p3vWeSsZ9{ql)WM.bh ΢%RMαͤhơR@mn1ZSpqξ ev {|G; (GxץEj,ֽzL)EG}\>9b 8fU1+=Nnk{Mܝqa0mx|{&[;D+{WGw5yȜ^JLC916pg֋{U ~kh!ta4nZkZ'ZPJf8;S,rw+,и% 9fۤ>mn%z?O//i0lV-!Eɹ:\6Ǹrb%5,(X;.*ܜƐt-ZMȊΠ'f`t$O7D8ccsTQrY NM1\__w`>|HZHe^Ƀ9OӁBj9h^;o:o7F(ĶDf~kSٟϜr/(HscIu)^{sq} f//;'1y/ųUk)ʅה <O2FpǂqO#uh諑$G>A~JАISGDfLEEO(9-^=ËZoD?s~֞q R|νGXE?X0O+/;Vf6R5q G[l pCٯ:Yl\uPwۣ7I@i Wv|yO Yn5Ӣ&jb"sm@Е܃|s`y/-d,EkK:@1B)# ڡrrmI8dˢQzH}s^NQ Z3jnfL*mMM!AT< :w8y_``~cgemKT`n_/ャt}M7X£ϗ/5vatE}&0h.gyf~sto L&AIIh,sr)&1fd̶QKZT,cR<[ĜgzoF d8p;:mNGw+؋e3ѻ C#B->X/LGz PAE9~'foph叶 u}?h]JPsWOV .KgEs({[ ;H~ :C66oYv1qnGT}KPO*OV竲OGݻ>qsh8ӨogsO[ٳ| Mė<]jՙ ޞ)y3<ܙTAd}FW?M ~&=ET 9CwZ!4~b۞R.^C"̧V0cп)LmWo\8tS3r=: m켽-إl.QF07(NO3uS#TK 6rCuy]kj\LOϛ?Ͽy42SrXW}m B$\g=FL1r$RU=5~)C;ͦǫhoWŠ2s 2C(gJСIC_,5wwgzl\o&@-Q?fjk_74^\i^rf&iίtw.{9 > X}e9$#ho VB7x161k۱nl ew$YitM?PD6@\PK:O ۖ?ۼ@4VO]bqfxv^0rм2smH'̽S8N[]Hv+lnP3> 5i ɃRJj|tjW!n{y[QBk Qo:v Ϭkx j-Y|&J傥:k.>Ίpvpf*Y{Nw?E~HMK%6[a㻘P+c˙ՙ\+P{h,|J₎;ũy<;Fg8 ꛷ާ7/6K!l $Xf [ pfG=Xz9Ws VgZuC)Ķаb 5bO_qDlZ ujX", KһꉍV~Mo#`FD"RiMa}&kށxz߈Ϊ㟕wr=&joHdu1~:NY#<ǭ85OR'Y!ٞW;]e\fcKۚ4?{DsԈ "mEg4D*F؄q/O,C<<PhȘz'b#7fo0H\Wh/ _tW TKg0x8>C&ce]f:}qqh&aV1`rk:'Dy--tA4=1^cSql!˛ ]BPf:|a*\R>͒N ?yND\q83C1ypԴrqT_ԶsBnv.cjƳaԧ\w7jƔ4R  e뀰y);T ^e&pM ,5g~pjgcv6銽taU-i͌:[FۈXQ6`N?'{39Eӝ``Qw*:?!PKS&0݄nXz`d6g&{K5X`* Ő=USR=)<3[L6?v߾y=C 1.LƇkDX_+ioR"~/.Bo9TD:!sS)I03(A=JCl!_'2-NbP#ΗW PuۧdÀ>Am M{ȓ !1*Lc)[<Q^Bj kO78\3l!qWʨ q/ArIA**Њ43kr\6X:ySx/>'X k &wTd{p\2*al 'fh>YNkWukK+ia.WѕT\m1J&zXHkl` 7vgS+9|d Á}4ݗեE}msgcuf2EY%*.OzS>j=tqyZh]w=f3f+[¹׼Ot fŗ [jūvIҍwn|2ޛv[2Ns|gw9M@{{LՓ&'DρM6W@N~k>_,}>HX [Yp} 9"9mFKTJ"m4]ZmM3wnyis c[:LjrƬIē Q*}ғr!e}&޽[>Mco2LZxX56~k [0S=aj amǭIsx<7E}ևڙZM~S'd@Xbi̕3-cc(\BUmR3D<`'B ZW8EH^GlvΚKӠDTܫN)土g9X4fp-33Ijupn[g0<Ҷ]K%^ ܺ n40Z+:f;yt&ĶʜtEEVɵEa2:HtٽFcv} ңwoW_R583HLj&u}s+#1q":NsIeqrǚ'aJOӣSPv]z>dKP%>;w*c a/GN/ bm^9/8:vBrcb428G7!P4btD)cvi K "O uATm5$|7+_ƪetA5LfY(#~_~?$nfLel4jܚK);mzq1ZI>y#16w?m-f%- % V!1HW%ypVt@L _¶iA`\!a,0#ZL2:ɝ2~}w6T b\`’nmGSDzgN$2c7x7azcg;0]^ iD"jZ` 5!WCoJo緿2u-p_fOYZz[x92 `ͤǑAxVI*4@fC s {o< <dUK 7;7j9?˅*TD@ѠZWO@T7 {g&~Zl^ V.ݧKvUIArMd@p>Mj{0JVmjyg +݌[d7iI_g,WnrV .myoBI#ҦfqUC4^LMQ))1GFr-"ߥA| GF̡D9  <B]KLÎvJm s繾Q'OJsſZ}+Ȯ~{=ݕո$PiSgv4@$O I=*42D0A+huPQ@f!폄U#ko,0M]'ea@[RAT|: {e&FOrK~0(Yf?`#N`&j]..~3e~g19z5yԊ6"9YN¨)B$2bԿ[ff?-p&GintĉxtЅiyen@މh9ݭ#"2L4fds!tF}@_M4 3:vnl SM BlV\~' "1; p+!uBw.G<҈tЩGu!o:zBq3++KSpaA1FSގG$g\Gf͞iHW/b]JD=ӝX_^f(5n| W:oCt|A޷䀅774h47W'r8!) vay]",a":yAjtRިMyصK$|iɁ4X9+*_8vnM MorȒ~zd hDy1b!SC~Qc9ms9 F#(%6nқUib?V46o:^n62l4U?bձMm,r򚥖SjnGM?H@ΨB^M9 lQBI$ShfD$>gO:-Lay1iy QWOmyGǻ[0h1vT#_m:ukgEٌ6 Ҋyp?8yfdCj$ S5(++z0̫װ64I:q^S^ΔKgoW/mF2F2cRۖ3L[[˗̶6ނSE6{fWCDW,{ r8ŃcCŧ_Jhv\3 gm'Ľم 3T:ON>hU%wy◕2<7kТЂzHӶ"+vՉS?ހcD$zZTS[OK_>hqk*V%y֯O˧\"zs9i5}Z/96b)gqӛ1 (eSRV2M {©SME&~IheVʝ8h7\nƽkmrqYc|OӮ|][p"=r$n;Yv}khD>ca`g]J_] Tvڈh6ם^Ldsm OyY&Lg̤sSrCKQ.\LHB4"5V‚|{КW9fx0|hA;4o]8_onBvWl]vasekuaVI6k<.MP5D}~~zZƞ"4DfUQ@m ?.^_3x2*ssGed9Fٜrw.OXa)Fo\sUCŻ྽X$!sOU*8ZA>CT!rq iڋ褂**߾S׺$&'G9@jJf`+Nr'9T(1R=YU[ƒ2R?(a{ívwGs*@g@m"b47f|WÜaW/~B,-OZO)|ރK^>- 5kEgmc!ll]p?_f?0_=>7AI!~5<^r=0jd,ëPL4'hӈ&#t`)DJ33qBy<tfx- E1Đ#Ȅі@^ de(q;27|$ɨq]z"ugK 9Z]_u~kTjs>Eh:Rʌ2 DcђnqL[-[&5_ "  Q@tkFqjˀz%g ZC@5wzBƣA*RB|N?83aaQ"[D[0-%ZK9ۮ"=+&}ۣPn;b͔_%Ql;kY/CӊQB`8b^FI/AX (!tMClMz:Z,]0մ kj-K@\Is׭ :ubϸ! @Ď - ʣ-Dor0XErD]d^ 8$xzGA>D8Y9``8D[p&nSGV^n!20]̬JNlSJuR@Lj>&ME5jDx&hBC 92qV$r E> .IHIc[L(~w=bD\Fg ^bdžex`q"OBwx^fezU謜i SybQO88E@jH vo۫ bŽإV<)l5x>16(%b.WyO񹸑NJ(+4|alHU50f fŤn QW;[zEiw^^NWN8vlM*BQuvM 'd2i ϙ0Rr>0%fU.*d>;9t-:Ws aZMK^u|%'Lf`׾\0lPySwaJe߲ʥr3:s."yYYԜ#'8P(kVlJ3i!PϏWUyYO8Zd9l!|VidGA)~Ӳ3͕rI䆒OމW~Z]JQ$-{&;5Ɓ,kCjl>*yZj]f0sD57X@?ڐg"'bz1e<夨FhI@+X_ y$5vsK;>A\w@L"!|Iɐ ex>`6Ez,ǏSDnY4'y+٬ |bz,Sj*<@A"> c0pEⱐ#dbm:71If&nܜ̏ɐo1'ɩzL|5Szjg|X/IZ^q^.?U |dA6OZS#^([% }h幌YU_j,JKA}S M,ө^Asj)Vr/%95(ӄ5~Ÿ߽>33/1:Iv8ܨ7uG]NK :r5sv_R <,Q`Y;Œx R.$5A@RHq?O|=H Zb5Cp$V8}6&LjH-7@2F(޴dɒXc{ӥC0n沨Fҡ3gq pOǡ0\n 'ǻw4v䷞' GhG>C`MVR A"+˼AOMѬ 5"Z‚inſyŷqOT[[j!61-RŅnmLSHh zgL9ڄ6qAd+џ9K{l 4S"!E؉n&}"ĭC co_˸''e>k[x|5l6t"z> GܺǛa1@dfūB$t9;&rl M6kJ2҈Pz4$ᬉsqF:l̈VE[!Z4R1pgEˡXy:btҹrʀFPEyT./V‚-iV8 3L91!'kK>`%4]\0wl >JB6Bܯsn ]qd<ɜ#җdSЄ։qP~Iv؉l&O;.ڠ-{2F~gY.u j]#oS|:-K#*Ԟ(V\1 EDQ{@zyW{ioěK!FAgf?ӟ}5ϽOۜQA7dxBOre:wOX 8]8O2Q r6QVĸw#"Vn2dӿ-<(,z=28KVN#(c < Wq)oDHD12iɢ2221 $N%Xc! ɵ͐V-!XHNZjNB%b t4j|ŔQ+\Ĺu R2mrN\Wsp;Hǂ_v<݄oi4xmfhӳos5GHr>&C9G|egt_{CG!s{Ssw 4FLY~F !DBĞcNy59Y5k6a.M!9:>[8^.cPHb4߽/.Aᴇ8V7 녝͔6m:mY-Fo7I\}?=%g&fQ4}htUw(AnGڣ[Re8Mӻ7:QE9"D:ߧYU]aTZ_B+t6|:]85zQa7[&7`}E( .kCMR_zC%k~c?5Z:m';H!)=XM(J|iE*2{zqr=t}?S =Dmp6hVh 0ڋ59`F#w`-~]VvᛷMU4V}U.c>ҏOrQ&M&n')c-x᳣ z vʦ@u|i#IFx x `p| M=V>,g[7ظ>N VLF5ԠV!`.AG-7/n5^҉/o ؏Y*@:څRlee?UWs{M,~MdM^#+-W{H")w_I{{#8 pQ.øbB)K"MKS-Ag͐ cJL0Xd @衻{e7< l]L#݂Րe 5$T\T2s&]I09_]ZuLz_]p|'I7+;Ly~`x ΢"^yjN_dwAN![62+t|L@~7Nm{uٝ!y]oD/wFS ܨ!2r6Leέe)a T'N¢@nŧ~<9(BI !I7SK!sNB3qV}myoBa'v3z5h¾$z$sD:z'FMbWrP:L䒓1'1.K4Tc> XI530&>e{Cj)Gs&K7aqn|"Է{/mp l)e{eVoȟ՞T[痭oӤnB߼}_TT{=~~o}oƣ}9L;U.0l;Jdyű AͲ6N@{>4'EOLxϱlK 8j5gn灓A)H?]6MTFvBSe,Wԕn  wjPTe 4y(F5tL&G)uir4GUXNkVCsca{ JI8\qS0o c}K}/[l58.ig¾0_X 2p,WZW:Itd> +۵#qR8u'U] һwOck <n!l N[ŸrHQ,wɆCQHE!禔`5pmt3x'weE_?7 *U\X"^pI)^&n]L6/=j ;D'!B6s>$RF'HMBK5(6]|o!3quS>B˘,9m.2؝"iz#'H`tAܤtIeK^']cDŘ;tC% *m,0|ߝa%1SEuc09w8®n/lyO-=( 6;C[DK_aX%~_` ]]RysG^܈mou{Ϸ۽y'R"} 0S򦞎Nna9ony9󱏳e?̕E!^dT'1\&BxC-8qLKwUok\*Rig:%rtn) #y9Mلɦb*2rr=˓ģa>Nsa''GYǢhs%`ӻAnT΃eMϴixDb xcl'?V`cF$Ajf67ӬDV!T<0c[Q_<>pU$Yln@hFĒ1iC"r%OƱQyfFPe!DRCUO`QseŹgsڌx_pIy"ft#+ӟϗoy$ؐRiY$$1M6 +{% iP:i! 5{Wmn$mwoo۟yOn/ɆQs`s6IHI1ʌ Tx%.dm ax[p{Gg?ADԷ$7)g+H_E>zs [G9{sݍWM*S5=2 5Dtr/?OWuο&KK2bh7qi[HKKAߤDn>zs8ixi ~g3&1tbƿč\8*I2#=#>  ` Ǯ鲘3HEI^ZqԒ̩K#?͒^ u ! =2N-\dDP iIxbLr7)u 32Ɍ\+'9M8s,?Mm-agZqlӷ `ΘSgwIO9ΏTKs[-_WCD9gBҘ 69q̼5qk>-Fz$tM޶1{=`$%*TraoY昅;b혅M,c@%fL,r?X:};"MN1o<#bIO\ {#E%3-rq٧wwF/!HԘ5q'PpC;|nE>n< cߍ~ ;I67lT4o2y1S.e$'Y=/7CVo+@d駄Zy :yܕԄo^* 0qSjX*TوܤD2(6hע\p9pzCLQ1K5d ~@^ _6gM̰GRCV<]EUqi Z!]᤽3>7r73z273Z鴗om}F릉"  }}:_jy8}'öBIp-m$~8l+4z@bga+>ʰYHwWf8'vbNȨ5FT{ۢ宲OpW{}mVka_E-˸u2Չ& 919 fo0实 nk\@-8;+4p ȨV!tߡAc筏GSN^`%j4S)^NIT%\k~Չ*:qcrl;Eg&^VnzNWi1sFȐK6eZ,9=ͩej|"͵}4v^)&KIpxsrZ+CyNs,ZH;1KA#eosۀj\#rgP42 ;VQE,Uy ]y('j1*=>x՟eT~ f :utF0l Ǥ}n!7 X{#ΚhӤ~x69i%J T! [ *:8,)γC\y[O [I͗C Aѯi[8 8WDk3Ґqix]AVAnKBTSN-T =q1ndtVաpT"(Ct:eX8Oh>EQ4vXڝхpaɜY۵\07HhZvkn~Isz=2; I-mNJ joŠ f .#qj.e4`ٕvݬجjKlO݋{U|8ѹkds҃9 [h i-r ,RaXw䯿z0XQS}I`6Fmn?m>hRś]킠ilEh,l`ijZe=f"3ݱVMJnp/8ITJc20YͱyF3A;35Ixij~PFtr(+sp/EПj5=}\scW2m!Ua΍ݕ?-P6 #q "Ud8岁S@\$ C?4έv~fu\ 0qB /BmUİG0(Ҳ{Mr_LعAl!Gf Y'q`F-sWko| ]ë0%TOg>hz-'a-IC™P- @&=M0+s#ɫ^ n6bD%e!/9I):R_L3TB_=Ks1&r" /^ǹ*?'!0*h| KB*7r h<Ѻ;ZݽLCcYK$Z4$vPr7S!A_Ku)%D^0UHIݤJOO‡ّ4%uhRx8dD$-\o|dO 탋Cm7"7Gۻ؇O2.8Pɧ4#:ժwxpt-EMŒ% vD<2m/gPĹXlh$6 l8'bzWVnJvzwE/gỏ ~O;Oek!vʙe"ŕi an4dT)2S! -T\c"'!jᄱ L#AsqfMr@B^mh<4_XE:])J_ҝG.Bl6'4T&Q2Z9¢,̀l  XV>F`X +\gg3xFHy+dނ, :>Q06c8XE ˙rc7,(ь E½XXC"]&:U7$k nFSQ)u-/Lk8wXC&Pm8G_ԳPM.>ZacBżJEIrĬN1F(.NP<.@vAHKg4 y2<qo! %MݫdKt}!w`yUkSrͪ z+̊l捩1[gwgVa4_<pOyx8Mc>x_[oMoHx>1U=bz,ϚKCӺIAU~r]&!z<3r&CĔ&vq&1,F4zq5h:!#Q1&ξEQfE5 OZ?8 T0Eq"1Fpu˜IuwRb>ԝ|KVYϯ9/sɑzY4D:wL6CsgS19aȇգƦe|wÝ9kt1iW.NϜ wlN*(ڜV#?0LEk(薋@Em8hH:MM۴/wJ,¹%J<s2&Uyd[w*ȡw_{K=|7kh[@&ӠȽ2NV-EF9Gwop4K;1i9諬,'d .f BfPik t]Eb}~CGo#nQ?+:S# o KJwxt:eMWaXؼ&3{yѰh]rl+L6fɷD{Hҵ lgQ:7gG2%d}H<9gd# \kXsawKjpUE#jU-_pIt2QP j; vn!{{ + e5!vGm Ce5D]pB{ۦH2(lU?FLhnjkn?ҠDdx1Ё~) zb#DT (1s@ӤY)]B=*I }xLNzt>EZQ<`p}\<ӵa@CKXT& b'ASH=JR!䠝o;JdHx0섣M 9'qֱ4 ;M\ ďCo9&2Ws1_e#n{X:Nl6j"Į flvh83vFQ;jdɆJǏՏv*q۩8^ 9QF}h`=52RIQH7> >ah7W_MEhs( (8Ҡ7"PSϛ ّZgq"_g^A-_{;ͽ*R|y{y`~Q$t+{Afuޞ"׮W{xlnt𨙮c$MKP |sN_a$d+b|:NÓG۷ULvz>>Y^OrD¡eJ쐬qgD&bSKa!$O"[qN"{5nJ@FQ4)oȻiSh6۔؆ xy2.6;'1|;1Of k:^~-w;SeP=. :ZUU^[,`-%6$^j=A~-bߎ6ND_M簩?&Olqq|\zi=;/_~R2w6+lAF1-6Ol9Oϋ]zpǥEֿvNn2R%A+$c0E:"? 4a`lPlщ4hh݂M]1x1W@gDs6NN6 /'y~-cspǹw7?/QQ}f0I|/U;GՅ`Z$5 2^l讎gc)5Q_$^,Ӷ1U~o,,Lfn#髭WlqYd?LPAN lEU\!ġVsYXs!&y@u1l/_R^5$VimTzZC2lѣC&,uz ND!q=Bp4#Pvd(b{} 5LRU4iB>-.DZ v{(%lo MDO.EdӶL?KE&)&u{'pS)=Mΐb2B㾬8:SLAtkJ:wcdF( im-lb֨kSKgm3]g`" O.Isژ<\xl2) q7*y?m@L,EY=SS,x$M3CMzS_<1 x:XoC LY)HMApM.xN-CLRtљ |'3kk [M >T)Zy]~+)dŵP07ޗ9|iZD-Q +4Qz}͍ `fy|}W?zexL/ڤ̆@i]_߃UEJTNZ&0A6 R:w"F(REyt'/4+>Ԃֽ{ǒF /BΡ.1eސHLȥvޏk5ZlL +Laܭ%nO>G7 \º 7pIN|jgTʋ^4?yZaぉx^rT&*ɋjk%^`ϒb]F_8xMxpDwA =fobbT֛urW(ńR 5*cp:sU#ƕ3(%Ny`kBrB>)n3)Tq; epe.@vIΦw"Po{^%7HW^=;I2?Rpy p18챙(Fs^gDG# _z1,=~)ԏ"DoEFܦѨ5hncvM@9?)TҩblFi2Fڭ8rk" ''TR.wTfԧijL~Ygo ;-)P-wa @ߡoA:2I,jb:V'HHV#츛g(c#mI\ns7~AEEW1c&6.ٔ!0 F%*`gv&#aC#mp30g[`hQBmb!4狗NJ"F6 sB41Yu/$|iB@e9(̕^DCDЍTo}0%x=Î$ǘU7c;6R(0rv WBƚa; :෎4Qk%:8ul *H< m[7c<5(CBq,̌)vMW*tM:"pDF2 MNԗHFi2iY=~͛G [R=mUD׾EG9})~'?vj;&m'D4fp" Q}bH!{P8F+tcsAj LK\cps4VPc(nY KڞU{^Z}\t17%j]&jsjp9a+vNs +yUNa'kЗ N8 tv=EŘ&ggRfsV%F =WZ%=-uS< GV9-̈UVq_j^ Cwp'!ToQ^ YϙȺcn m@o{${.'"&M:pxWbzVFPE;Q9"c(K-w:lw#u -@G[GMjӣH0 _Z=,g%CTʄ+'|JC@s; E4J6+gUç˾1@ଜK  ŢR΁"A"^tt&W"%PVeEH8:NQBW9pa#_d'ñQ[&F~le<]3O D3Meᘨ,ٰI ur[f(yTt*;@ҏ\~G`Ny̖̕fqOo)@e7gFxUk5xwQ%{awSPKkӷ8}cP^[GL L%=_D)\YnS|1Ѓtĩ=(9"9I0ro'їЯ [n#o*H40X6i{|5vYEhbqxb.bĹh@kc;ۀVOa b!'&0sJ]w[T^6jj՜1Z-'/$D\...[anm'eY?WϿֽ~&>FbdB #-&Ϭ3D<:1Zd`! f w${.㘓v[f#CR>uR8,ڐM>9n,JXY>=ͮt7l|MDgz;h1 f#O9osK[ICB.Y艫ݸj+g`bd䱽شee<+3:=MƆ߿]|&>i&/ؔ"!Mo pTE!Y g'{}F-ܕ@[D-,؝(c w$gЯDzŽ $k{!Zp*ڻK}^ '} @|>\~IgsC"5u=u|*7'Gl ?l7<' ,j(*f˨4ǁB( )2Z`HnJ2]fÈ?D| *kfCYb1y8=b nOb;mhN-9:qO[L?Rv;}Y4BGz2/>dVBDyLp"@(*9]Z_VA%5Ge5 ZQE=͗jUƊZr}CuO=xW_?]$`֑YOet :qgWa?C9ɳ @Zd§0-K+Om6HԒ(8`aƃ69 Їཷ!WG76& 򽇍AݕN>R;V8b5E?@g0 ׏]0E8a\m4O}>s.Z>;* O#B;AONtmq#ӳA3a:(,Mjlvai4WEj8CU}rI ů8(ؖ POK;:Ax_%+3U= nfMarHhP$/0^tJzf֦ d ZGڊn e(Qp1anujw& ax+9| R b0<~ E%a<x(|N#Ovnt~aNl!&?FsS'GAF-4z ۦSz^U&D}e53O9*kJG;ν%Y }8kUNA =t۰??68wofm#̚Z+65~_eqM:2:  M+ UðM ӈYQdg2 Û!jGjEqٮ/ous3`=))t(}IQ$Pƕ}qIt0W@vnü^Hz4M\Zto&U뷟w33dc?"Сn6w6x"8쪚ooA s=sJ19.)@3fX}.kb1&XT?÷qbQ,HmHa.%fVɼtJEj]66tc:"bF2p8b%~HnKܓǭNۘ +]Gk:FhG40*PsY*άf:gaw#P%5gN{G*"Vnc@iaʺ0.~n0Qџc~#|4Dηp5Ɖr9X~}4M=sY{ $<+r*u]$M:??Z7@=׾[΋/1ReFLVBwfw@!k#OutPBq]Z[lgD%VH f)0">H|> 2%K/c2Rܤ&-WiQ*/"E0aqffw 2#IXLL1܆i ?JҢ W"'%F?;0ڳ:8<ⱌ(2ҕ_^}C2<||VGۊX&i'#JۯLߐ[(HnwWWR/Q+eslW85k߼cxup+~P_~ ?,[t˄8I0 3msVʌgE頙3g׽YwqF&2! 4Zg\ z¿|~K#;GцmтoL0Uz?:aWQҁ=&UI|n /""]QK\&ÉKo\^[TŊ5]B'57tj\ #mtzСJRlٙ.W}ޮƽ{?OlVߋɁb7]%uuRqxj/_3dnܻxsV?k4!(YhoK"_Tl;.UmokI;Auv89<'l2 |i8H]NIT1ވx0J,PpI6ApIhī{)!2m?b*D2tPp+pdgE.Y)zo5=j/n_x~hpO2omSGEÝ]|ʹ=_7]@_!Wɾ܂H[כ}g+Y]`{⿷M^ wryAɚbpy 6h㢪Şv.PUTJv1c °Ңىk$jE8LXe| ɇA-ՐCr=:A;O_,.\7</v^3:!=ywKOTF] lR7Un"k"T;#D-h;D!i,e"ŝ5LꨒA$ I.KP] RMٱ]kΧM@9G=`7?uĚaç% (y%X6c KA+[8./ gN c?mz0 Gq||@2>=EY=MEvR;^DÕk*nޗOh4j6ʳL OW bG, >%lbscن@E)5T5Q4P[du)QÈC 1*'2r92I``F$+-m R"a扌Aݱ 8ł&MBajbqaEh5II)%x]kⱘ]x'Έ8"uƩ(^GKs..jiR).Nt@ 4ȇa 3}L֎wEPNVL~z1#KU궉Hhn".$U`~QNaBf|BMgQyR u=r!DZ >D s`1-\Xf O4ufL|,%} ГLqO]\4gJNU[;F5Fŕp)QZ졍[g3Nczi[-S5Qܨ֙t֙䔞6* e&~G~G|`SreIL`lw#;NI$~ʡ{0n '@ȡˊ0%2 @pZ$ڝ,OlXv}|lcϩ@͇y GN EErJk րz”$%DⳖ*$NTz1\t}DJt wC1qAk=Xld%i0 :*Ѡ;w/z褞لԁvZ&2o8pz6PpjLd `"ɽpNju.BZ"#Qsly-P9XWc W6CmIf4,gA[ _ljhJL`giԯie* 7!ͭo r# \?wzΝAmۆH4DEQ> ix e$6ω&[տJ)q .6&H([{Ďs/"#W;};_^rIoҖ9i8%#& ӯIax' C2B1kNޡ /9tf,@dAɦE|%qj9$b/ꏴ3jH̩>ApjTkYԛ%,J~,Y Ql5/_z P8DsY62>끋-0M6iH zǬLRVE'icǣ V'>!T|grqVQD{4(uY.CEK(&F؍]οzBEճ|: _OpD;fi6ӛŏz ۃ&h#'Y d,۰4A94Q +2=?aLgBZa"jz֗]]/!j6G] )OVbrGO6K]Cbd^{7AM=S" cd2Hpt-> o X] y|u*Vt7FcwwluX49wgd6m[4pl^B#IU?f9ʑ<쫭W՜ڇZE#дHW=r?  #v9 §0\œ9m8ܯ6jS@PӶQT (D"0 с!T"Th,렇k3#D, du0jؼ!A;i:>Kě ! l*˜&pi\3cm8`W 87(fq[ڝL#|A73RB9c:lhkC A@$Ag"$~ RaʟDEOK-*hWa"`bZƷf7];d x [3~~x{n(w\yZݑ;鎂);hni^JgfՌJYUs%[hx|O;Z`->T)c"/L|DIBzJՑuj"A𣞌4Z|LhQI4(A䎎yY('VxELeg 絞\UAYCe^Ez4{KPcdm2@ x@Q?6%'>(BiҦ~I.y$䗋;&P8 q9DkjVX3DYPQ;z>ݣÃ{ZlI-"A+8lhQY^xU/@ȡ24P:xQ`:}B#nDX72B Px{V$4WLBSx[q #k&}vBxkyO4 1hSuf[=FMp<4k:(nQ; ,Fk 6Dcɔy,hw3r=nywYn QZ;XQx ڴJ3{?G~LRpX6ʭ9Qי[XiXnIڴͦR˭O-d|Ogʙ[.L-M(1o0l Z\/{t'{ #/5-Ct(a(&[WE T˷\ŷ-6Th&XPV8\7agAbh8).(Sc Ľ>-W#_< g4basi-#t yAt.A$ѵ H mv1܉5& BLD{iAxl4AoUh0nPm6vtkюMS-<4曷_f | \B_<[UWoZ  *˚ů<\11Ws_VNSݼz R[a(OpS'8zH3RkZSjQ++Ow^OerczJW]wC̖n˙^BwBy^FSA+_~/SUS/;O8nF_#<7M T`sQ=f̽DanTG[<+ֳ]U||d nmRa$܅Iju|o[8E`n7ni{Y}͗U~SUQ :~@GKc #~>)*NB`@ >B'lʏa^gNz~\v~Nգ[-ypX 1A rD_N.9 :B^<Ԇ=-v ln1[ºR˷B<::Bګxm,Iǹ_}(5534.hE`~d8Z#@+?|Dm~:::8a)jt5(GC'{{'?Zzzxԋ#8/ԋG/w늤Wdvl(t󏰝"D0jEL<f QՏGU`z.,CO;S8@>3şokkkkͱ'4W*GɄ$j;ްxIdN0~$!0-Rb#.ҁ/THa?"D#.2XMI1, Ënju6(tmrIBW0X$mcNsLvn{ X/-([]Wህ#2|'$lb%v۳o x@p<`Č >7RKTE0P0>dLo浟O7hki}a)) ;w1gW<-t3Tk?EfĖ"ſɦo57ɞn.&`~SiA<(ؘ2P1,aF~pvYG`KxEOB]\Xz\3JG4H{ig5Yq>=BZ/(z! ~$沛nV7#{/HC~!4\"ږh 9O!=+cK[Gr먤0Ƶր ~: Ah.4u^D5vC1Ӹ48*N2@mQeEwv% O}%tQIбEN*YEyl)x_~^ϩs9,gH)KbtKGtq#\sJs] 10|vs9|4mn\\ujg_C3hx\)ȫ+7?v^>Sn%|q^t.\C1jyo9 !M~faq "/Ah%Gk7j)A)D!Atͅ"O2'wR? `KfPM}bMXBٚ&Cmodvkb ۈ#?PT+Y}dߤz| dmԧ?1G:_V/=Ս.J'݄:R!ݜE<׳I(G8UEdh-dw%W,]4B6v\V\w%ΥWM s ł; jF/7˩BDc+I;No.nw1魉z6剡qNm BX/)h)ꞧgm1C..[98{Тa#Tj:lhsC/; D΁#8RJ:$̴,P7Fd$S9~I{8%S`|th&)'5Ԓ[䗫:X.aU9mdiu3%yoe[)I 2]|1,4(wB}]?\Wig/8fE"hGU+|̄ ScUoMI faLo`S5˶GHY;Ocy>cIlӲxA#jd+$j?Z\U%TRT=E)_S_Dcf2r3S,TeNYV-cl0dԑ*FZ L~q'LfK )+C38F]a"1$R.咣vΝUZ-]*',FF,ˍ{%yJ.L9LR!Biq:o;#јHo?Sϻ8VX`p8V;bc؞q٪{.tMZY0"j COdFCGOf},f1!^qK=G'0M]cBK#{O$kH|%_C]0cY>DDg'0dL.!^ʳc˿ al0413o,{_eG'c戛QZ.瑵5IJ1EEY+·ZUZQԾ_w:4hnw!ѽ{͓laxev m %]d3i;be@s(YUUʷ؟.4K<'agӥg+>otd:i !/mT/Η)Z{m"O7n7Wט/A9PISFvyH;fd(䜗^f$1HKS\@tSee>HəTCrB5LH&{L]ݼΰ&*<(NH!6cV`LԭpPnзQ3;>4&=u`b2a`)Y0l z!|C3"ݾȖ[T(7/jF4k_4=yӿܕ8ߜơgyy&ЯUl|!aPL _+eG>@& /d PּI`%q|:_zr9XOQ*fƼ%vs4ER$εPh>WP*S-L;2?̞;\r6 933,a5TLtk$ƴ?+7NGF42;8r^Кj Y!9xRıٟ.R0KI_:u6?prH!iN|-vv wE6hbi_6NOtF~F3.\6BqiJMWō[kon428v&,bc Iej|~N^6^{ebSOm+ys_r%b#nQFivPgdz/KmYsNY\t?c? gRw0Aو HTNxeefVK>nO.5N^0mMGQb)5]84{7t0xL}nJ] ?WHhО{Ti@^`RAnx_*{צ ϖt'Lynp"L pGI0COS?RD'J*XpBpmyv= Rѯ82A!,&SO.˫N\rb*4ݰ ʼ63eM*G~XPs'@ra"-fL״o,b)( Dfkޏkn{+;|qwx@](Fv&Q?K\t4XiKrZ(e05Lnޙ PY`4l",`h- V{; Da~{9Aڷ'0!hi+''}uBGjJ >cf:YX˱ճAZ&V|\KP&h|=Irf¡]=BtS2 -Σ+$ʘ^C;;v1 D ;$Y/7+xVgœyz7p[_?}v &pj h8=Fja: LfbXzUwX>En,W|!0Iv~s"ir̀\1?U}E5}y 1xuP  ‡kR7.OHWzO>k* Y*^zNXhNҤ ܰa!MLa ? lAg{'?rT(іD{%Q'/Mfx#`h1"0E x0݂+2^ 3=յ v4TתҸr3ىEȆtCCex}k=+I+uK8$Q[&pV*$yt9Pgi+F2*jEpge0< 6ĽsbVICu4klm4 DabbcA'SaRI&+V^V o45G̯32O0R^-: j|IE;?9ci[DuB)yl>H*UK u$>.x?-3ԋa4P`;t=07޳6ׂ ?2|fK%M!h$D#Gbzsɟu㓝fL_v)B54Y)Yu yI(VXqVy1 6Ds(f ȥL" G|cQ7}K&BFWv^\ s.gɨ<:1ƔD.'p;pP4HoS5n#v!J={ZZw:.ew:5j}F?H׭g}LaSZ09$ 6In(xM-v% uRx Z(KO|Ge!ZW:)VE*:,Ià J ;щ~YiMSSt%~3Z!eVjD&fd\3) t"7s}!HMm)5)_!L$F5NSF-ƟzצR[RÝ|*nlJON\p @Գ$p:CN,-F9C\Z1\aR/u.8qt&76ZV0!h82n)lկ+M43gı@P8u*(~E/^F UǦ 5+E2@/9`P>rsXNe IKǑ 6)ɺ'.V U!ʱaI Hi8ܒX+PqZ6 ` 184 uҜO:Fu7f\McKFhW렷"֎K6;:tsat`dggIͲ)p({1 IܾÈ)B[70ǔEOoVoPxLϿoҝQڢR` XIÛs ~.t<=~ԯ >j*A jfXϳa]ԝTGt-qݛ/N @W0c24I[j?ji٥>%*zeWAÕx8dXWvVh*Nm LzHxͽ)U .w0d 5W> ߯IvR|\!01^ NV >ph^u'l'D v!09R71'A};| ( ВHk;CU~6<'?I=$.cǮF(ݷEbS;ujs?1,shby Y{?HOu t3h{= E-ax8{xê>9g=""o~Xo>MZ,sTIUc snifBjW4z4)aqw/u7.yBn8S*Hj˂oϏտ:8ґYndL!7%*D_1f v߹=M`~ N_qV4@޲b^pK g\\ )yQsko~Teעa2#6d)3;NkyD׌ .ϳQVg2 Xhd/Zl^vR~6Z|'xn/[vkC  IƐ0NA_J(!fՁ\}lVs'1з/phD<+)N0flO ^9jQ w9VSn4_>}[ ,pUe׬tU?!*uV ? X\}JN]IL(t.:X#}  I.a} hBV"BҊlgݟOpX8Cا= ;qp}qm9iFޤ:pW ɍ@xߙŞ}ںԵ)5թci,ǻkҫ+*m&2ZiE,FOәuNh:{u*;');'mgS[;`#|Ҏ>B`5PCۯT/FcqNtd:5тCNÂmh%/[oFRxqm/}g{W ֬\?]EلG[' H0@VZ|3v?b7 !ǜOy;-dfJy7-Vw\/Ÿ^!^kAWކAp.ѷ \w *No'KO匞m yr@*/\pwz .sd%: -A 7G+tWZZSbj+xHYm٠un@ Ϲb d8KjW2>Or 4EdVBLwk!RD ;bmeQ+SthuSr5SM/sB]OW]ö#DmQ~[e•!HWP.#wx=Ϝ]O|1a=ӡY$/|'z}N߸70h6"3~tZO`EoQ<>_Oss$%'H/"l]qOk_M {Wg iF0k yjn 53G~J(/~{]5G u _"I6J)&C1gřǭ)cHM'Z3Wφ9 ^.:LwθnS?K=4Nx"ViRz])T?:tRQd ~f46[Ro*Ǐ~ƹcgJm+Fك D(S87oV''&jcMll>|o4^8|s~ڏ= yvRL1 ]6 s ~6yӬTޔy2}/U-'%zIAHAlI7L@uR*lI泥gNR7Gymz?5ۄNMZ6`6/DLRy٧~|MP+o@45(HHw1uGG*|jƩP)s lE5j^q3IO{IO1uY[hh@z .+U4@?UJ߄,?.:>%x]7Jņ: ?>Wڀ34Z*5bOL2!oq?dmM湟Js!b p)bcbzL6D`)<[ȸ(HJJt4ma:&at ǻD<"طMb#r tl }ԈNCvINLLvTdTPGV8O*$L$(?ܕM2;,/ ]/6.u Ɯ]1bQ] cJY')>j`![#@_>`|u1p$>lR7p$ Pɘ!Du|~@/Z-2ma{6:n9@I|>rSsH{?(1&YK[x zѪʣwIoҦ,Wv{8b,혽| FvƲO4Ґߩ1bwna1r lk䜡:qѩ$~sH+ szc e)$"H%zPqv|,$ensJ~fktNAӬS613dY> V_|>H/ðnBjf"E;F|ۿJ+++pH jN"XokU7"5XjL #30ש "sJB'8xL@Gh!EuT@4߈5|0muhߖxos Y(|3M@TÞ*s w5\\T,G9FgG0$d櫿hގZP.C<I`+!-ÄX:iv'H1<ƻnʍET0aq9 SA%gPxذT0aCLk=)t2`$\'8 aكauI|M T>VԕKgm:|IP7 P٥̨sc‰LH`VdkR&= SDA9lpG Z3 XP@pt$cfo \Y ;:U˙"?b,2% էLg}:j(QWBjPǍWysAgϭB߰ʄ1 =^ZXޱ'rUrOQ8m$ PF]1)M;Eµt   Nq*[%:$#Mkw~--x_XO \gL(̙Ve%Չy&Qɮ">l@ x/I|>9") #Wϊy}Qg71-b}tCnw Uwmcj9·EPL̞H*dUH* :ߎ{]gI-v.03#=%OnWIo-Ɉ z Lie%a8`N@ ./)bmV ?VO8&hy\KUcE𡺧<\_iY-jHSY xOq3~%FWQ |ӈ?Fsc,J1l2'UՏK^ jWZAO9{rFР|Wx#sр4*~XT![} iaU,_BAAFgܷΟWQ՞c w_a<*/`(x!o::VVaF]ݬvtqdh~eX^X(l>t[8)u60j6(ه1uZ{V=[*9+.?Igf+Ao*ASHFlr>ӝf *{ɼ#Mւ:k)a:HV9*Mꦛ iP+ӫ ?sYZv#QY:!-"9\fE"GvUMM6ItxF -&)vr֎>乲}|,٘zFf|~RT(u:Rb 4卭)w>uZoԿA<:zk :R'e0Aw̳AHQj~hbRb`.3 G 8u!g%b5Ԉ*r@>s1EViH !/y>Lxg{d>씑_Na3gG$tc~hRz0D7kd׊k?>O~PX!~byUЪ"䴠1Sv9gSI:"I#5v u G /R$Q*_dSΓZB]]?t)ﱹ-5Uf4Ɛ=G' 17wK|W_Sv )mB\hkX糘 pX8<ȀɣuU~=8>͵ a d5I0GV1&k{OJ`ZW\WOmHLLV^{ ?<8=A GAdb&x mgt= bY;ɴlQIê:~ 5h/ɗJ{c#Hh|FNH{t("6EfAx?nF3`SX/ @F~ !`J\ ӔJO]\{.JL6:U<][9upHҽ-~F>Vt eX ̴⋇$?x0#[F)5[TDW%b4dmd_ЭeC,[UFT 2ċXA*gHݑ#k<ԺH:j7PYx7uf3Gb(s#+9]_CE}M[#&g+؎ 6y9`UMig+mq/[E;HF:YdڈQǰjTCfYi:ܷzi"㠇)s>t玽Jں=gaLکHC %SDIDh)E8aRHNAm~{!p.t*j,mut4dM2Efh+DZu i S3ppt\`0q7]tnŠPa@Q.R Ovy e>0o} Gtno ;8Re)Na \\x驵ӱ% ~_1xVĺe DG,-\n hcxo]PǪuz En38"f~*\ 4=Cp!,R=+<2:N3:";Sfe %^Y./m@e4TPS(KYt T1Y9vLMʢrnJ^tQE}ad@ Sȫo޷$b}* )y^'~MՆ"tEvۉj;U\:f>sqAy4(3p&x'r&@OM^GףM36~;cL{KK+F ( sئLyme!Dr-)odUպ2;g#j0_7r*0"͇^zEvdmJh8v4z)9V7b0CphN _l|?W2d™7XI]>HEsnDW$kZZ?t4y4! ܠ+HSj -,F` 4|kUsgw0ѳݓ*>x3fY xTj~Z3Ho][ߎPp<27]C$"\NȽ4[̼ ,k᜝!Eó8;Zuܬblڭ|ȴQ΃e~ﮆa^8‘FAWi!t'A .^.g}Ǡ`6^*\"S\Y5iWSUY*u,Ӡ'TVfĩ7/d{T8R.œȺi^쌌9@cLuɴ}ɏ@>Jȗ^c#o'::EVgLȈq o>0kaEkX9EV棻mvn4kE`Z$b.#l_E/r xj*e>g5p>Vq bhZ׉ЁaƤՁ[ G1G<#Ҙyz:aj6W[x?+(Ǣ7H{FMgƼ=%9G%qljŬFh坣, .{([ճ%>CeQܱq?E{|=6Фq2y"HSQ|N+y$Q, ۦm$i0 V7s3E_79Y (bA1΄ʥa6ͯ{꽛$O9'GLD2G~:y{3An=|ն@7*\a= hrt&ƺ-sMagrCja6qϻ=:;F8΅g=Nrf,Yp| &$)Z)dNLVd:q;cg9|ǥh '%Øدw9+-lJmށƘc}!YVp:t8µvŧԳk? :rH>Pхc3 /+ΔԬt(=nK7ȼ$#Ěv)~P>}Gv73(Z0 #|MkI(MQXqc>&qSLHyz3՟3Ü4Y1=:M܅S*LIj?FYu =o w!n[nU'_d3azΦZVv=FLVp:ۑ=6Sy6Lpum>Og,sc!vM"֦m䛕2 N=FHsA<0p?MUs'}qR ylD-DllNP n;G{/NЃ`bli[sFV2P{w[G;3vaM.1im#-kn GavXp>L(wz0ceSxmvD1LI8S׳y6 _uiwXb=:(+<7G)~nK1Y;IX'*(4Hn~T_Ywwia NT9lbl98J&PxRk0oC 7LUb`p]mY)Eu^/)ԥC%^gYzrxT_n vs% l}fͭ+#*I)W/vrXA_&CQ۩uR)Ow06TI8luXd ;}$!}N>f{Xh },Y=%5#EG;F٘(a< ~gFkf6xPlJ#|w%Dx ķ1ċ{O@Ɖ}l'sh(gҷ)fۙ 6E5e#t~~ԚX3*{gK ["GWRLf_S.1L0fR/.:ׯyJV c'1BT]xW0 Ԋ'7bbY9Lr82K0HR=Wf>ۋSQÃJgwbH:3#`:MRJ/| Qt7FVؿ1a1#GRyy9/`Ԫ.%tkHɴfNGap8~N3bIlHOiٸK=@Y&21x?b,MV em]dXK$6!?S#',9A-n~W~7>wR,g\2͝F3 ֘_e{\ZϏ5v_,Ϝ"M g((Sb ]S( ʑ ".x(p X eQmqOUH-NݬxZLtA,MZR?`Mҳd"ezS0Hϰ|elʞaulQWNێPL"YNhZ|U(!hAك.%aw5@\,tPQ@ L$EfzV"e聨Lm+ s.`/\H'kb&JԥZrj"fGݣ_R}Yk*Ea*##M]툯7muM5ĢŸÐBvP bkel:$g]p)3}Gs?J_yGuU8As3W!=o''GϚ@OKpx wO"O3)8!j<(wGWWӗKs:|SU8nV%D*1;x:hn4|CoCo1m:ɨ݉=>JϠfpO=y(Ff+䔊9~t +QphWܻ z{St1<Y] ZU;? qU~M!0ˏX04w rqU:u`c@g=;fC)c7_l3*'lT`ư'G/wˊ8ZC#c'9xf9pZp{xN:tK7W^MxH(,s9 Rpٯ{fVX+x_.uuEja-j7Zao i.Nnك9e2B2`җalLDxV,BqJzS?:>i8bmMՈ~l.*PxEJr@KGQJ jvFOOR08ڮ*DCϵa/p[8n~yB~!!?;(̠BE˭( 2y|P,^$De:Os` t8]XG/rb7Tq$w~[\Vʥ뚡SCܬHJIȉ~31;9^[*?"9+j_h;Yv[lPy|Jϡx t:!GwEz$d%J KE䠢ݝDf/|vwTiz9 è{2Oص xͺxsN52Cp|oj -Npz*4ކ%ȟGWu, >IASЖHz>9KЎ@а?G"|#-Dv;ހ-Cðq< "J+&* g򫯿G|w>,´LXr LM h3\8T =A9̛azs4\]Vh=N>۩z*{gGl;.ߦ;[GWCLt%Przf+:9&+V /C{epf^bDK5$%UA+g]NЯrOG7X6t5 {O{n>Sdxd5 >v{\~*՗uo?Z[R_{QCI(v~>=M2K~vUB(~iGD  9GbiI4  EFH!aꪛx t(Eѹ Hnǃ!,m/o_oj~!~DB[+p-xL=[ȟp&kGjިgz~\WfR^uD8K,7(-N e%@+e]FzfFi UۀO_nJm=4`?brQwK@ws o㓭/6V_[___?fnk_nL3:^-8;&fPFʰ= V!Re~[\ ~ @j458aj JBn.c?? q%y4H~)#K#d ‰gS.H-@s_/:?'?ۇ['c(u̲UQ~_vm RdQOF2o1E#lAoS%~)Fz`^ǤB]ET ױݬ*$B,1G7 i N.sASS 5A cDd*9ׄ+H"4pZ< Ga75DaT S@FIsqKy3F]L-W$LC0Kxa7T&&1R{֮-IkއJDЊ MH%j#1,A(hp<&)u~z\Rj6K˥,i3;ybg喝: >R3tǠɨ2̇"nP'! uM[5=̍aHqP?e'r\䘠Zygpx4:vq*UkmYi7 H.\7F]>:9|I*s„Exuj?zm{av诺J e"ƼV]l͖?w;a@v8vF{ HʅL~,SN^yPe$JK_u8'*9It@  "[7& EL&-J:XQ; @Gw+^Lhj2̌Kb}V1/%$e"JY/HDTN5]Ts5j_T_Xl(|]ŕxg*Hj[<k\W}iaaUUT+U/~௟Gr*E H\q=p!=oA ! pl%5xnʠ Oq[*Rz1<7ldP/vjqƙ2|o6\b4l AM{] ]OfZ+UHn7]'$jl4 ! ^ GX9O uTɿ{ `/0IYdL1p z UJ1$LZ#yqHhz( k!- L VVkE0JW+,yò IY\Sxd5! +Y^;9V-Cۜ.A} F,л3@6#(iէ吒e@F7;Mx(_JAQv L}$fE5n,HƒH2g!2 SHK0Ԇ[rLnWA'A0g?-*`MՓg{J 3}xtr扉\ <]@QL :aQ)K05A:u /jU=ؙPlWf윹#ǓqdX$ W̗/Е-m-.d rN-{V3?ԱуJŧ̹w3gp$GRQg{$!E5]/ [MYMܒ$ /P݄X~GI53-/ݱ|b.Wh*-ܰ:CBz<SK8h+}„-in;VkŒF\!i,S(uQV p Sv4+Y/UnP,LFkE$Z3:dV`pJ=E+nTT_4Y8knJ*XjAu2L(q3 4 [h5&ހ4Q)P_"OmJ1xV&Y}GGG ۜu;Q^ռ!Bzu6wYh43˹acx$Vm_P< O {K@d`L])>U  yd^JUxWuK; -"6@o+n1h . M.k?H{ߜ5$I#Ў5}"7Dz͢$QIJ2y LF?@ hW%6B!RaH ,CїhUt6(ɮߘBzMca gȁ~]6H0GȨ#ƭMǃ/1{pb]qc' ]7HR a^243TaYl?0[vj0x?By+ue~z:ԙPRt[X񏵫yF-8A().g{zx_9 !ܧt)~=jóX;ǧE&Lp#ӎ"4 Rty=Iqt6*+Q2hR*~h!7.m#VD03Tz`cOxc_\Kh 5|~Krl7˛XZ ѼZw#Nɗ|@+Fsmb][by ʵ(VhJ}j]㟄4 Tu]|*ȫTa+4gX{J;WHvr,,rJZ2i:Zf A7aPhOq]:تO)Nn:sX9[Zk[GώMoN էЛi+#W$#}D&jMCYLޏz$^`Fy[*49RNF {zkj D ]KbqzƋ?rR @1"5z=cyyMLgu(-+R"^Y0|p-Es-ׄd"19Mض6٣uW <RnI ۇ$岫WgEi$hcf< q"gSXA[D޺QZɈlSNR>&C/c&Nm~cja,!Cdj(P0{%̖֝!' ʦX]`;gy-HmʄBM(x jỗ&CQYk~\ӀE=^ieo3@1HlLt7~ckVBdAW c*ǧE~O~m^]I$x1Y*'k /8Z=d" HV«);Cq#8hj4V-5aUw_֕c{7kqS!QZ,nn gh8T`d9 O(;څRfm|ʚt5$׊6e[篙A c#jnT.#ʹms>%qMwA`mz̚f;%B4{$0&*3V9%8U8@[1Ϙn?d[stŭ SyF#͑Ȑ ֵfSPo;ΞU&fhB8&w92wuR=n'͇'h9AX2JnC!Rѻ.SlV^w{IVa;\*,$}߼N 9CFGYza 1IFo՜X!a|$Mӯ, ZWk6%c WTP@&XHЛ@c_Md& Ԁ~qWoo{ 6+,M^oq Q`f^L ԅgbZ5cJNJ}IQ0b paq})J*jPe aVƩcLHq:촭fk杝o]l:Pƭ4ȃpE9p3-a9u9k'JDL!q1 P@=K)@&DF'z6g oG䊃iQ|j_0gj=#.2!PHИq aEٻưZ[4HIy4Wù;,-%.k{:ch lw2JLdev(bT_[GvsvS'q> $ fN"$"}XT%/8󝑎Zk{3 }9z6+. P7$gD-vgꁏ9"go,1Pޣff:,`39'k;]׳S.Bn}_OuDkns^T^tI>Zi*3ojM(bB/]bGEBl6e0c/2XǬ^t#>P?L>AJdj+5ioFۄ_ ?Z'-#p\3 (TmLe_-r6 ] HRk1AG,ޖRVHHih6%-$1"z7*8b6HKEƬ2&*my"{o419Sޫ=h'*+iXp!A~:$18;Ii_2zb WZFp=9STp;v+dl^c&w q|.C@I`\ *}I(i7DeJ[L-iԢZ(>GAR|V$~Ѵd[nw~{R6YLK.a9ESρĂmD@ed$2EkKx NNI[?L"c; Pd?5sMx iV.a*9ߓ{rRfp\z*9.k~c0)P$2t܍t)zFNrW@4Rpj9Hc_`k&yt|u~B/vOσhsao%2a$<7 6f;5$Bp_u?ּfKh> Y\U)Q8.4!9&&[%d+{@~ ?8;tSu/xF&sQ"GfHȡ]]9HLeȒn8&H=u &Wdǚv63 X!ح˵ʲu9cipZ^Ԭ$f2aֱ95d7_3PJҹI$G[?\ dG $ⒼIOp?E+R)휑 n_ؒ1bID34a;\`ܧ64ԦcԆ"U+y?B?uↁ#j]E*K&=Ĥ9:;`e}a0&J m1(ґ ODt(%4( ڷsq-3Ҫh`959tA&|K6a }xIoj_؏Txyt0EXH& +$k4+M?,,} WBqRg`_~ȷI7CPXKHϏ'P_@3h}f慔J6b?qԂ>Y~I`kb}YEb7'Ws+u0[ @rn7%*2FJ[ә_{f.L.ܱbErMhyr7N r1]uC{s|~w jP-=XT0I^XiGH<"nxכndk?vH- GYw1y|&3'l):v"MHwe,$G*OIL^8 da:/I:u~p36~[&ڋoR9&t@KIlYdHtf_N%9:f֛iRn>~ύT' _@Y{2p@g)GMBJj.V=*gՙ:SfWNԯbS[ϵ52L).¤NͰ^3/^NMc4[C (1l'eߋFI|N16K[alhZ} l~8d_ re_r5XXa2 3I5u͇˺L^dPn H j׬ɏDĴa!^^E555gL;4}ӘP=Ina_2k G*ق<[4 yhPYI#OH(}gƤsCbPv~Eah\d6$:Qg+Uw|BvصÍL%x HqqCԎzUi#~l k^Z`r%dgع_f_sw6giO}N9C SZ9a2p뜤%ht2-%fÊfhx$ȳB&~U颊qVYkZ&ڢΖb4e(G,Ď*սùvZ;Co Ph<@YYWV gR7ʞ߆AFp) Uپi=ءՑoʁ,\?ݖ#^\߬Ϣ8Lg&Ή[1i$6nRɥ4־%ɂk25ɓ1Xo/ ѽSzL#HHd&ɲ=fT.6uE)i6I!Z]6HR+l4١G =\% (iqƉB×MՙS2S o٩H3%pQ-uQh8424#^IgX賉0Nj]wrvRZ( s} Rџqc-gEGWn\s~Lq) z5Z̏ᬽ~fOPUd`o  r.u}L`|o _a[6yAW2^N}Q˭G [W/\(5r+7IC X:aT6=R!:0*J₸U|c&>(Lh)`tTreXOtr JNѩ{rX|8"YM|2-tb\LXUkY\k=Iۙ颥Oi0df0)kn̦>9ulFO5Зdقf.Cǚ:4o˾L[v :ei?.˶z]{>۱WE۔:;+D9jZ%ׄ8k9Ñ޽Q SrM妍Pl5n&zCe=[&"q^8\j LpK51( eAlPIꡭ[{Dƍ.9=/{ˏx1lq#|i| fo pl}Vbȋ4/$2@mpuz*?^-n&gd"f=3.oII]fciҤ7g8c&ʑM9K1E1$Ij6Z삉\x{jp$:И>'6|θ?w4)m ,<h҂ɰyا9,mG]qpA> tZTl[ijmz1WỰEC.֢1) ҺOSeU򊘔   8he,)"ף_RMt/Z"b.N*j_aiAJ.L'5y'e>3e9X$sCu@?JzGtS0#;E.&!kJg;f,=w~{ZW'u{x8@MLXCQ<Gi噦$2{k*RW-oevh^8b\Xh^&ű^Uɐq]6W3Pf]5+@bs>oёKF঻֩ Rkv>;}%;@}L3}st{ &}؍w*紡{_WV,lN}Ճ1,yAxvF7&*g4Gq/ԦOs5J\*CvBhԓmZjKιFGż&%㙦bۭJ*Vl͡`П:$Ohl3EpKHEtr?'".MM8(eZ9Tel\`O+qF= !{i^(C6<@gk["i0˿mBn-z2;0a69*I5ph(B^u̿œ8xc"T>@(HV'N[UI!p6z%*Gc2dɅL[o Ri8LΣ23rƺBUK*ZsUdy" m1iW8eO WZ>|X{޻*z[)ŹV &490<씝8PIL#0OX'_3#*.4m5m—ݭ$Ihwo%}/45 H-PtN, \P)ԣ,0#K 7b9S!ȶ˄e%  G^tqzK&ahZ1֡ VrHxD Z445KBfu*+OvJgՠTFvjΝei&iK# $žii1)o^pnF~W ">;LO:j9X blqxV2@ 2)”etS8TO=(Ff9J|J )WW+ZM os1*R9_2nCQ~DcCt`Q"ջ.8 CԼK1vRѪX@0~ʎD&i*ӂθ=|߱1f9hf`b-tID@ Fz}7IEz)"ԞM: ť>Uq/Ϡ;]džv!'z4 { 7==1eeZՉNJOEfk#NrC7W&p'.ZqXڳnRҙvcf1՝E+L&nOe SPgd()4ASmfɓKUw0qo̭"-54G.x?,".BY|AGT# Nr!ɽҖimٍq%o |+,-3}O o ep@بYw 9LH,76T FpoY4'cD*)Y@ad`@fɸ}h^Oٜ]I]2mĥP4 bA(*nfBwK NIrC*E`aJ 6 :13l&3xzl]j郷wZ5Շ7!zlu.Q A9kܑJaS$Od-B E{vT nffn*;+I,ޱȨ*4" Q9TU]M b ,tΝY~ iM{&Wӗ Fj|^j扚4T-Ԫ.'t~0Qw &ߞ kP#jqƖN.,Zi@`0%W|36ĺ\)VfZpW Bv<O9W6gc|+zDGK8XÄv[%#-:'>HZ"\÷k7FK* =#eZj/,ڍQwE^Fw=ó&o:L\"8gW;ti}9V:6!*zB(5T෈jD&9IUz@Lvw3 ՠqL66RDZ[6X8@xSht^3`9)DQZ:nz0 [+WMlz!{7y杮hFS9+_Igպ!ڲʱ!a>ū>6:tZ!IڝT/y~9gwtDj <-'gk~a )XnAYS/l@ UcAr9e],/k[63c:#1W·~\*u#BEU wP,/vF9ro %HtNisCTg/[YB]4Azt-d M߉:f'o3goMv֜,m/9ymmGcQz=R7~r O`c.x DY^m*˜N~ g`49: T5/ɚu@NX32~%%ng0ҧ\AfrTT M+tO;fYj%J /yN\LM81ry?a (}~[oखEbZmDЄ>OY5ᯖVF[-QaJNLm#(Ҭ_NC_TdSN, \Kn&{9PB`.a <_DDkiKX2'{t~Y{08,m Ta0̹r_070H?5jj5`w9gqp@ Pi}4]"'S)N9@|1%gKʧKi% bJSe`F-e&q5tNd}&LJt9&S+ 4t G s58>r;\Aށݜe웗1'­-*@:L(p1fOgʻ;Ȥ&b= 3s԰!-/!d:`U_w!\ۤ,<%9!TÊiKƌ5@e7DF9Z]AEنU6-{nQ59R#N?Ln\~X&~[0x|W.'}ju0;y Q_ c%)xhk8|*[8N^V@)5FqwtqCZ5plH"r'E|!uI~3Noa$ť@zu8g?D4*']TH8+ELiXQBZwn=*ѣݫ&rދaGԧ dtLD}ŃN""7:}hbiĐyغ,ϯЭ1x%ke`^b*Wi)LOCĻtmMMm:KMy$ѠnX)%EKw'H G綞vzꜘ.,+B p4AYH,~4|a/<pLnpty''8ZqjsI؀#[ܕ0v4Yl M5"sO]Q 띟;bz=!)%ХȾRn9SSm ȣ8'˪I69I%{RO]zIh$i!Oީy;SW@ 3$5jǽhx/Sx)*|r^J2UkRu!U#A`]L5H`8Ctեf"G{g؆pP铃1\fW QLロnXGî@a6A&٫f){.=u O9l(P"EOR|Fhh,@c!FN|IFL "=D:p1.阓λVSZ 9\ B~aWV[&Q}@@NbPdC'E0%AqtP'θTz4'PSP|.wˠZ;8 bAnf\] C2ިG6#Ls֦af%zPJ!4X2"p2חE~<p }R#rtpV"z gmH"P]rN$а\,@K,S,99%t6*NyQ$b39JxM ?$յVN #uFt(ƃ.hfmu׷SJ?%3wRuä.0I c݊Ĉ7Hbẙ:.=Ghowϟ:%YD" SKYD>'cב7n7j2i~a&c$ř&vTpM8`[Q*o}!STQe J6 M$](o5#{ mSem 鋽m'87S>Zєc< JeD3uma 9V8Z۲X~/8cݚ׹D< ՉIVQL0ȆU* xcKA+NVXb,8! ܏6 F_`Af= #TRmtPB@>l[ } ڷ7,ǐyZFqj$=5GUǟ Htv JX Һ|SÎU <֥X?V A'R^mWzLU׏_nL4]B081nR1ڟ:WLJg9YcG7h~ErOiǚ[[N ےg9kLgfKmo$UbD9Wg<>0*H\Ahv&g1G& aJ䎉⒂:HE6A._:!zMf<|)Cںf ]c,-zVg-]lKI,G p@՟x &ϱ-.Nڝ=}sLɃ^6 ~T(ep`],ޚaiNaXIavL[_x| : Iܾѽ0ߘގ6Mژuu 0WJ;#&fJH =~4:K?{_ڞƱ,~ϓAE(/I'XmhBNk<4,غ!q6qr,ުkdWc.褭1A t;5"{vjiOtf (vǝ1rh"|^0ӢNW`R {o6s,IY Zmw30Am  @6 lcbVUpxd1x×N]J%t^Fؖwݢ4^¾0IlI7)rNs|n6AY~RqLݲp9yBÒ\q[h}&=_(K/s$/oǢe###2 sG()iF׮];t"=vbz{e~0{D`/v iFeK(6Ǝl7ƃAA{]#ڔ6-үxàX[KNF] ~奎:@ p ' y[ =IBǪ t/sTezA(C:aPI@:O\u:1SgRiU% T΀EI~d-fb茂 G#!B&q8/aCh8hAB(<17Ӿ~ ӵ[lj5^ZmBuq]NmNN\%lJ'GO Vũt3I8уN/;V*{v77ǻ' UM p^$n隸h=n*~$#uU/:$஀hOwo/0W+*h35EWMh?^5T.H./؜uzę( +:ljHGH#\noNb^0|Nrؠ:^M6a ڒP&M%ǥ-?#OalSCc*QB֦~|4ęEk4 _ s P.WC0:g0vQ⑨䀥H2^t;,a֏+J98Yv̻Wxt4s!e`vC̊)zF.cE|RIޓk.#xlf$dlԊ\7tEgY? hPXS 9fM/`ZaNIH=O< oe9al2wq(,dK%ȠEh9x1 )T42_`d:(aqJ^ 2uH_rXebHY(2tܧtArn\G\ݱ ,,Q8領{oMqYA!Ttϕu)ša7aˉg9#ؔ9?9<p ~9yI $cr뒌}0?펟NCii٫N?<慉 V1xE6W/j՗Kj^\1̇ETE9bLű!m74HodB4`%N& R# Σe+3y> pFQЮgvXV; YĒ@O[QXH/Riz&핆x?:{p WJi%M>qԣs2R=/u% )M]WMr:ڐ7G@Mk?g4q=Gvgf朔!Y ^6Q1:EB`a2(&ݤˇMϢ>{n|$#7)RQ{\ '˯(:<4*\L9qMRf^F;!хIp:KxbYKYx E?Fr]X7]/ %/6Ǹϸ|Ř )%Q>^s!T y7 xR8g LuK{Q*s6biWĨt%Xt@CJR'j{1Djʼn]]Fp^=Kx R>f%/7W䱓*A+,K1꒢{Sl |&U3*7M4pW͢UaD(Ar{?|}̈́~u:o!lu5T3*=גP%nw4NܾQo;U>!e:(ܰYU[InKEիEfMpnLO9 8Ҭ}ND0tM r:MP(8F {1MY\ׁZ`Z &-'LFfJ',wGn89WaHZIpCD;ss Ա =Li$iW)QN@s~Z{ 鸊~[lwRpt\3z0zr;[Cݔ̏ݼ3ϯpM4f';q'5dfy4N)&BJð8gޣ%<{ڊM;.\7z3j3U> wFAx8$ !‡Z[bD/MadXfBG t y1{TH;jϹM@>}x><} NObrFz$% {vv87ED:!Wφ6 0&maG9'gG4ZZ| PnIY%_ vYLd$cqQ?B3?"3S@V91Y *ہKL]@ ^ӯvdpaՅwt].zwoL$ٵ򀱃A%qvxb 6B3%zp!<ٞ^ݍ5큺JrȔmOKOl_ZiWP]kpH|6Ukˍr Bu %8b*EW\{e2>I2d:vL.Q| )=WG{Icw{?Ck3P#|lȻ4@gL!.͊ldDruŚPʧzyj筝a~ yp5 g~j̩dPC80SQ":t#6;1y s-5,HsC /$ DHh~CdCeN5[!nll@ybDغnG3tj3}g+:?q,Z[OgkΪnsUsYM5ZRMNhs13$xb@(VJ|/d}2&V3 #Jr]+$6ɶJ PMz|UL'Χ>+R-H?`=U^v/;jT^|:+Q 3V7Ff-Cp6k2Ք~MMfϽINΛQ }ָ{;OD,/̦;60W+fae02 >Һ,I?nxnϼuq{*A% șZk.+/}dj߽%$vYccʐ;_8d"ޤi֐8#TMTֺk&K߰A ŲEZ{Ab˹M&L ܞ85a:Y\ 5-cy|@X3 @bsa&6=ȢjQxq[@ 4\E4֍≩Pĺ?kG 0:iHi&xps]X 0˜=,btsNHr7lj(v$oZ$X/A~#SSsmeRs^:~;8Pc/_ao2aM䢻ؘ^ó.7herahMe~B)=9k)e5ɿ~gUtGu5~nMYMFFZJa%kR-$>g3BzE5??OPO >IQ㢝bXQdmr2&'t2wr]Fˑ|n6[r2^m_5»NJF6 {T0ub?GhRsrI }8}=`rVXRĊ~+UrP.vf'̈ugr;-Ic>Trqe}ck_|fl%pw oNN9+өA]a{ ̄ޢf.V)JLN<,MÝZ C0'<4+k([3nRRoÅJARYҫ3Oی7EJۊh9ۑ–x{s:cm :]DN&$ Sv@ yt|p=8/0❚#ߌG8q^Y,QO>* {zu'Y'p JCswl:t7֨PqN׊#pcL(fpj t uwܐyûU$wZExojIӏof?_~?Y49ӟa_I3 ud9ɆHP(dƪܩӇg ?.)Ȇ8̊@ȳtc{h0"Ly#5TS39[,.j}ɾ6ٌ>&k^$>.k0<ߣCJy\&]XZK|_F-vv݌q]{c Shn?1kǎFmjYs4\Ea )u, p1=yT9>$[`7 9u6!M"4} \7XJ6lqs~.3RjVyz{Υ3a.#&XW4si"F}%W/e75Zty6jm'FV%!O1JE!F|IAx<|'J̈́Z-,=],h^kDQ6~3}±%".%}kj0^3wa;P\uk`n-"vhΥƜ:s|F:y~5Ul W>!ՈL6^NSHthuZZFXOɥZ8<:xrTu᰾cɶZisp8b|t OUt XM] !pwl338jT;OXyى@;ڒ(&</݆](iQͳKv6ޥuLDhiLR1> B m^,.JڮfV9`x&aEEщLMB_a3l;K1C'G6 [IM7,H؅9."U)`-uo6fa=>eWgKa'&"!K܆|k>Hn/m*QJ-Iꥅ򠤊)DP'JB=(ʺ*sS=!Όer, J`)-J}-˙j⋗K.lYd2jY_%}^ǧ1")DںȄ-=O={Xvp-‹b.+ت_}3eK3G>p1GGc7Rd< M̥/(& kc":KzԿi!G虣!bԸDd.,u~@~mC",U}m*0'+212-⥇_QYri=K&2?Ԏ aFTȞTݮr(/oZ q.Kyfït8Vqj? aGCEYy@a_σ!ԏ2m0@,; GYA8]戨(#1Ab~=i^/[㺊7VUoRwIf AU?5h[ ,Q\wRu;NgQAM p܉ XCڿ &sY)+,ArjpUî/F]Ӭ]DL[ߴS RV*j]V+WfW"=<QcKAGяg[I%{ğp4,aMІMs$N.9Ҹ~,h-VӘeRlmkE>T^((5YDor~`d|&V'-c0ƞArΑŪ]w•%H;zCI4u摱d{pw3$Gf ÷G]w|VO4za{;U:R$ί;w=GePe#lTrWlqcme:bT=Ve;t|0~95okc&631 )3MkilٻTv%wZTshjMsvLgYLla?A=#$a jcNS=ZK(<04$gtD|QЏECP/A ?M?n'ٝ 춌OC[p6>z*aMIKz*r+~9xv|J}YɝBd[H,z+w^<7!yqPCJ6 ۡfrSzWE3cp9LzM %װBk9y_iB,d3x% s:틛ct)_=ҖJ/CW7:?);31L3FG!"'v (~IbsA,ga Թ&$c2~֗laρAuzJs3}GI>#شZ[/Q2/,Yl2MUYqNR-'Qܙ-ύ6[B3v_?0I͇z1 th'<ЅN^#ɴsvhJ8cö\>D ̱)0!6bMOGvL9>F681&֌siғI,9Ӕ"dsw~2Ne4턂|2_P3"NGɇbUaS&O$ۜJ)5Y^5l)VӽWnuUt' s{-zic蘁}S̏1#]⟄8\ 2LӯVOڜƮo7}xͥM)3G&Z%ReƓ690ׄG?p7|`s ӽNO)jX )̞C:M8Wf{G Ms,Nwkda.ۆV(t;κgPE^7Z¼ϼ$Ķim7Q/-W 0_MD2]23g^\t^e*'E f1M]h!]{:&v#뉭On׹Mt^%Kckpaj]>`dj;U`J^<uڤr75z0R o<&^ضe`@5zch{V24Quz~E] u ,L+ON"jɥ& IIvT Alhܳm.aBpZs۽7C :t2ɖ,"/' L٦w$'4=[P>dQovޢy 02(E(Q,K"G}2Dq$<0|L;S7ςQr]&˨6Ƨ]aiklv[* JnWӖxNՕ5nۇ=V}E]tޭ\ ͕Kul [ 4*oCyZΫ?B p2qeFZkRc=W0mv @iwZ76je^R&Σ TMC' Z+e@6̙.+?P3,:;P3<^}w`swsEǽ;|[.]O2NvYx;Z ~N5a/+ A+ R㴺T !cdDQWlTS4WlKmIO~>n.*.UTV+й)t_Z?[' ڔ>ɂ1;58τbֈA+@};Zt1EBC6ZN1=r@a:I5pK0EŊJ4uI<0;ЇR8) ߼xY.))?Y?h0# ~uYΩ3cse xU|Y+ꫤ/VtlqU]}HuØN B#z Cǹ|$v5;EN7(Nnx0:z_ *V<%dz>mTHhʗ MO\ "ωIAՓژխ\Q:!nv*L;;O=3.n`,p%N>C|9{M5Nky [.(4L@=Pk  [VX?"n$CSl5ΪE vxfȜzfpyjE%6D4_7BUq{/E\/KMU⻿d$_Ʃ$fT%z|!ηv{Q wgy~p'GbqH{V_J΀&}&Wz82nFclE) mSI.এ.YYDGpmtsv8Pwq<$!*3's_44" jl1`KV\-<AE'= p/㱺#i׫"v(95J#s *%vǟdz``>xB8V5F2)tJQ we&H W2!樔KԋsxjV;/4G!lh١cs{B | 'a19f˼z,E2S0qͻO "\ru)oD4*0ipz,uW_hf+ˆykcu_8d~N䤿)N ]]V fI,זf;õA'Mߔ ]0*evƷO8g;$wIW|k+E~`=`VګMJhܲg8Omr9kjeu9t s&wˡ"+^"ccQ[+>Pz3zm[cUKn0Y,8K ׄ?@g"s~3X}^yjis#w)*i.TRo;n'Seq^4MG>wU:Q,LZ9\'b2氍뭠T e-qi"tup҉ʬ-J8z?HX4s9upjm L+y'af =E%NCy!L&`mbqM9x63z'$5rXsi-&HyKiSw6ZH:zΥ=D*˓ a;0fM* |>Glݸ_eT9av;!&G)7NQxPGwF'L( /whFo%Zal&śFqͼv~+t10G2/tz=mCͅ}>g(A^ 3>jV(R)A #wN|p324L4Da ?1E gJ@Yo2̦=@VDnsaȚp\aaNy [ַS%*)ׁ͕[ M's?ٸ*ZNëtFjfbG^LG6H.iIa}mJk$LW" Dcd}`P=Eb&7AkDr˕L Զ"vI @D8& xNGr;yF?z8MR>t`~ CJZ edAL#fgT_lkVE5; [fcɿ5AbwR'}%+EJ?~BT޸lwz&U0:# ]C-#e4&1ZVQ`n4Ym/}֑S˻yMZ*6zF],Ž Պٗ$wΈ>ܐ:Etɏ*GaGlnMbO6^Q :׋XVд_9U\2)XhRYk8<8o$rp=غq 6n^9z^9OyosG7Mtyi/KIYh1*j6 eO* QA+?Y \LPwm&rμ %9t}=.Ee JMgMQvþo]kKW?(lB j "=!tXj7f|cPyS~XP|\,=' *$(ldx9jpTy<AÉaië\N)d f_zJL#2S:Hn-$8:LUH41HޔϮf}x ᧷Gw*@"74 _3`[JQpP* {'~EZ,Ƃ|)gOaƂI9}cIya䟬E͆h#f:&:*vNB'paWƸJ2gQO>WA#).Z ՔfI֓5 p@YŜыJoГcØ'VEqf ӕ' X'o3y. zG:r/zgm&4W_38^iҖ[t[۟ގQ 7*z(O;ordCKP.vYo;^R1g`8OdhMҙԜ[˒\=Mv'뿄hx9êQ1XygiSձ ʎUޙ,WLp޴9>c&xG"1'??`v!<@h1rbl\_A0B 7!^-憯hsB{y&qo2vYi%m@\VuLN7?(.ݤ1X RD$,cA6Ii[D)%`mIȊgUK\i5\9ԡ)6=;tq5k\-Gg#e)QPREIsl|Hf}! [.\ vBMyfko:yƓG5{w 7B 褍4\2f2!8.2wrNT ŕְ )n*zKhY@-UL9 0HdDDAiBLH=g޿~Kq,)Y]Q;iO6lK]JN$Hskxق!P"v = SsWWe$ej߬{őݢKK#x$~9~WNu,E} ⓜTp=ʊ-t% `WI]IǷdB>%^sٔKqN/H}1M1`Lpf[D2p 5ƢZ^~vt rww4zN;*"Y]_3ZNy6-[L=HYȰ;8xY70}4Pn>u6cOD6kN6OBmNFN^W)PCװV DAnF۔k󮙮lI:g7gvy%g9A?"Utf,r ǝj\ȦU CXT&)W` pfuɸ.PJɤRM6d5 w|NRZIXP,_브VM8s P+g#beu'C팠Vp1D2Du6* *Ъ䨹3S#^[45TY)wg*NP=`AeOTivC齜j}61/Zj؜=[ڟ{2Ucrrh00']|A.>M!W9 LG)t*5Zy˱q)KB,ޚ{i޿&*+(NR%D6М.{=:xAP.!P(=CWa?l|9E\J*hR~wSXea<@vpԼ(#1o;|c쒎[mp/錗Ԓ[x]wi9VzwQIfѿJfW}{Z.*yk xƳP4 q)qFQk߄}xtNq1a,ZWƓpRlը\"+BP Ap=+j h=;`2{⁙yo~zo+ŦshN6y!Tl(I+z.eBktQ߿IC\fV-F 6|#HuAywX$iݷC:b!"Bi0~|/9UƗz5hJltq+5??OM֐̘d:51}ƠʡS4څ*8DR qFC9TiIzΎ1 J&j=jU_اE ߶׹9c-.p[ FRк@s|]󖶾L =*]?P~ 23^5)#85̙]O` ߂:kFNj{F6Vuc}ktJGf:.vlQ-cK3c谍Q>r.&i6=6.PԦb%X.f:U'4R;4w!(H44HGfҾ#頥SWʬLb#72y%"o\П.FP&ԝv;_(س]=MT lf&ܵOr+Ym,=PGJ$̆.| z^$scxEsO@q7Qn;X<ЋDW%YzPh,BysT%a) y"UJ{C-(Jfo W]nC?cGv D.Y@$u2>%;[ds6#̫[MWRq\BۤrS)-1;)>>@`y!4- Ԣ,QG1YCv& K3CUlE-İ@Ćv_w6|Q{۩%q Clh6_3!KAG7gs.M޶K'|d kc$]eԉQR,LjߝM-YPIJQb y؊)辱o<۫oMvZe)t&svVQv`v/m #4n$nm,%,~f zoݺ *@J;/B [8ٴ }rX!`d;ۙz":Ti3*Ug8hs 6o2x\?ܗm9;9Mf Mm|SLۄ̌8:/$#z6;O7;DcVAimІ'ς#Ϗ_u/<&I^yX~,1N/I43]:NV̋AwGk~:8' VFm~fx$P$Q͢$ "ĹYɒMN:MM2/6R5eԒ'3٪_nt9q/̍Hٶ-XH =h.emqm/HL],Iѐ,:rԘӠסd|nɫR"Quh̼<-N&͡`n>ETsqQOEA~޾"R"kjk N꩕?cVyQNqZ>btL{hE)#۾aS@xa֛7m1ӑꭓ9p {ɥ`tۼ$ l&v\ ,tJe. 4Q XJ]@4oUSEg}>iwY<IƂQ\W:96J 9̉Ʃ4DWc-rL~|o{];5 Cs{'(rԩ]]g]g!LƍN\k'{ u8P$"\l{}PJQ3̓]Jh]⋱,*V;ة%zĉ| r+X?z4m14']:Z= 4N N$jzƁ1o [1 o \$i nHzCų0Œjrzhjaenxp͖bjLj0B+$;1AWw](88?1dϖ ;8SPAS7ٔG\G7ε4ZGh8&l8m3z.{mw:aW23QE)ѿIV#f zD[ LQw*J=+{SXѲ]A`DK Fo5EGP{qMBȶG-|!SF 'U/B⇳aR3c'cўzqWu^Gp:6b=m(Z>M0$pu6$I܎&Il86_߰W*ôn6(*=HԢ6rZ*Kv4v hsJ}g˥mz j^Y]DIXaOlnkSlRdctA U<;b:%ώ6i& th,#bii̡\ 15 WWi秽iD#(Ȧ /wN%pt%_;`+JH2 e"&xM#/Z2#Kr_>(ξ)Rc0xI7.$I4fI gYi; X'Ah4骛_Ќ^bdhu.h#*X ;f7Bp}}Alϳi1!Q1rۇ'Vxؑp֤ 9RtnC{OcG}[O R%Mem7>#sH(t4g #_pESlCgD ,CK8hy#*l%N ~zVN^ck$ 'O&pHҁE}$z)YYhG)T0z͜:F"7Tx7뻻Ι*FOT5Rx+̀`I6W- ָA# ^bg N<]c<5fZH'ˣV!@gO6fT"`H|Gl&61Ȼ;?zO3şeY3+6 (.hneYs#GM'+;2Z SMKЅXWq泣G?`'/_涧WKϸ"T/H{avю^y  2te%Qv*`4Kf pv#ԠqD6+ dA *S"͉cHaIfe!uJKYwRy=`ZY@ڗ.aX:w ,nA =\;b8acUÄA{ьLKv(憚YJg9uA|78 s%kTdCn/sso,1MeG}$'ŸJ܋>l,Hioq RKdSy~ 1L"8(@"(QN82:"*pxԍH2 "+,fl~ )0"Ȅbc0:_E ag"\Cӎ]0 VI_76Iy6[TBhC89Q8s"d!׳ЎQ&ChJRE v [纻[#('cU^@r4|02Rz0:l]H\ZR#%8jkW c>~<.<d=ǂ`Al(;^g36ȅn R/UuA"90Yc} m;gT}[ ^˿G+++ܻ}vG~s{w_޹sS~Τ?cX!t%}2/q֟mݻkY돏Z^mƃ!e_[,5X*]*> ,@~]4i߮NcX.A~ݷj.gP؂xw|kTĢe2'c0$dbjۤӐ 8R'A`6XeSPd:p0J~;%WAȾl5 U>j<>~vঢ়-eYoBe-̠ڂv;{ PP??@GOG[@ sswНSYs @Vo7pá?VzhN#`A_Tp{s[mo#/ò? R[=VRYiqvL=hP5q+ÔAW yݭ(`ih}~d{sA*|pE5JEՏv*X@mSN+G0 {u5% ~gaZyVk[ݥʹ2+aoB hF1a:1gA˖~(~x] 7 Y (:8v-18x01?GOljajZd%Luǣ/M$_~U5.ϑ!5 &)tSN"8GI~:5iom-9>_r e8O{*Q֚< xlv} lp]z<=|Ԃփ.| u TWUW#g5>Fmx ' Q8H*&;렩i?v+V*]o.//?o~3= 8+oxe&ͅ| J1o Ay5P%Uuk˦DssBu\x5FI7m kS@zqM0CphcA@:3QE>.!:C#ZȠC[{ۿC?wܽ{?EYYP/*;&sa4~H"ƙza^(2"(s)ՈV1Na;ZU>a{ _ƒ9TIt]:qcy$0%@;fd|\o* WI~,FЋ ^q$ij$wKQ\†jW8(SmA~ yLꑮk~jjO`0 C$sqToE.RoF|n;HQNA;vV{"*C7Z*_0;GsrƫyHQ[)dѳ ?鞜 WGҷk/ó'6ss O0 +4F x6o Qߌ0Ouzʬ;JNPF yԶ#5XճZӰŎsM񬱽&GQl~Cե kU2\_Udk͢ #U;Gk岻u*Lِ/rB5<-r[${*Vz$ *zMa oCrODzw~.JTO7HO.YUpaH! ( l xDfE?8 yK`BhZJ@*Yʈx?(:m 5V(6%$% H%j˓ 9'm*4G4 4&3ݏ7]J9"q Y }<v:X= QN`q $:.xQ,-H@zfC͏y и4u*AU)V/ f}\ދ-OTaKKY&cL} Aрi7)LǯdkOv*_Ap l(R -a%f-6eU32 P:shC7ۅM`#<7 ,G êLXcy>T`t'S3wDIJYJzg2̡R1F :ɹdvHrq>^n][=s%ux 祺Mue\.AtNi H#̺FˆP@ ;a8NTMsc_Xk3xD՘Gc`5?FPW }z: o8A}cz '^K.@&v俈}:qPd˂6b :C)tШBc1U чPCsoJFv(";2)pT ;q<Ԑ~lÂ9^Eh.֏%ZH8axFcD(!Hm~Kơ 7TgDmOp8%/zp /a̎  vEQ0șo6D;5h MՑHpX4nE0yN}6'fS$X]-σt#V\e뻻?a֏{g[mWώ[}t'Vމ lļN5-81bi0] _@ g@;!PyC%{Ud 6P vDwB{.Y?.mH), Mؼ~Ɯ G+AJRWKc!N3bl{i=> UTPUo8>Ҁ}𠁅qNzFu.0.3iI *ބ4dFƎ'wQVdu.Ӣ#] 0;AW[}/x./$a>jlTZmPmxX}\V1^V VjX͇VJ$DE=w8}UxqD}[Qj:q4Vw+/=ӎTVV?Z:vvgڝJv q,nu@8ȴՐ%>X@CHXZ"ВR9'' 9v EdNŅVU&gY]w @)4*8r"uXgqt6[@o/y +k{j.!" AcؖcT8ڲ5-#AxŞ~t]Uķ 7u>.r %!@OZ$V!a77Kǩ d\s$2@#_r.kH#^n.T9p<*w㷪3m\=– @H+&nccWaR7vimNm f]&5JQ%[+m"ؕmhp5iNS; Zqk5"Xp53wY:5d6IQV;O6xrjG*J7ɔycIk`29(VD5:v7|ZoloEL?no@Klcğl7D̬5 ^INwf?nmƊ PϺcU~-4QUzBȺyZu$nL=T|# l. %0ƧUzx2&H^cԱupI$_ޛgk*R3/Lq;ƧeꂝgÝuD e`HAps#54tcM <ǭg!?׏7R~szViݝ&$V ㍵ӻ[ IMMۤ~` WhxI"$!  D6*-QyŨcjuaN!/-h8k{{upssXRX\-8W~R@vkM&iB_vwy!q鬘BIL‹sgշ:R|!QL*DmrPPoEs{x95`/E75[+5GLrQM/˒ޓ@Yn sCo`BA6<~7APФlcaSub5ĂOĿAeF RdCq(x ΜDgg:ړGMX.А.UUʖmN^`3)'VJEzF58QKǧQo>|V6K)}RW1sITovՏAMQ!S0%=fӹw!C Wx1!Ftah 39 sF@g:L_t]=5Gq;v(b`<"< +Wv0}NY@(fI!%ҋ[o܀9?b$'I))i|$'_Áb}^XBXҋ$PgtT  s=2EſV /2x-+PO›jUhF IѬȑzX' XlxB;Ŕwcu))IUxnzH2ff0tz0Z@ވm{I[:}a// !@|nU$XTAg_7ۀ h6Ź@Ųh$Z͍(65gdb%48"` =ZRNt2hME+u ۩A -"ZE˫D>eh޵o@(afoxb/x8`1[uef{svM"˶ ãMnm7eueܑ°ѡ&|Z@֨^|w@DCֽF$nH^*hm <0X~cGeUd@>-dKI =&s#$Ut0Me.R:Q.x8<)a yKwّQ.sM91m6NMA3KmO+ro{9:N@9˓ V E⤢5mi /W42_, , 2ImH۲ۊ!x:PmV쏽܋̄ݙZXVhr(dKv#xӢeؐP?]J L΅d}$M#ILw3a^߽{8-EAu?% WǎtB +}ShLLxLC|/C[k2%X$'JLa -*hrγ7'3|׺ W^j`,( FIC,%Ps!BO%)Z]H0tP-UDFhC1"-iw dq߱0RdNŞ Q$S2j'QИ݉U?yV"0)'ME"5ffaY!lrA@'F(^k GptDwI1΄~n}i~n|53?|B"#ϖGr]iz/Cm>ahZ@p3 hSV>#8 0G:yYja"Դ [٠ qY ֻC4QX4odU='R i*>G+iDx^#i H '1g5aaM)=޵Bs ,;va, th Aۖ {4*޼b_::kK.׊x,c{2ȪwBW,qq_GZÛ̜^p`'Ej=owWVn}hC}s|ӷqMoVn}DۘWZ8J"2XU5m>&g lx!۫OGv뷅CƯw  ?Q>)ps>s|YgR:G1wHmqHcq'ItEׅ`~ґ4j++_`uuj{kjn9?@?8onS/(@OA몈+֊Z h$n:胢rćP\w`~=ݻ/ WWWދpφoFzSr64xN\<7eTCin*g9$9:2$ϰ)mn[T[?-}n_W;mK׿-ccT~}{Ds·ar~`U|zEa.9fS#Lv4R,B$q/5Xil@Vi8Y@5%g3UT`V0yttzaM$iI+hɠD s-?\3`g)FrwlH$~2W?EP(cTaBR_s3P =~m:<:igk{K ]T-0n}g1Q}xg~9~ʰԏ[`)w 8 #|\D  xx_j@mO Ѷݩ?V/qS߭@7+ O yg ^ v??70lG`4TaÍ Tކ=N㝃}, -ձOvwlon3<}@UԪN>xv *fx+Ȼ}WX[X%a4h8a%0MaQDܧ6|^{YT^G wH`8ۨL 0N"AݥɜoRKl\L5NCJvn]qXR8L)MN8Z)M!i%3LJ$'k ; :LcյڊtE!hTp*U`86=I(%Uv]KԎL>cK؍YIZ1+CZ3:$ ň'(1AibC=M(`>!Fnz-< S)w9 ;Gq '],VSakXm>~!E PA޶ow[[ۇjQ7UIKK/%s[ڒ4qX<&vf*=(=v?rTҞ!Cf &"L'ttS2:)5 9- Pqp<1_[Ȥʹ>!*hB[kRrka ;?|L8<ȡ@L$91ɇoۤ:MmҹO˔aBA%>%3\q4.WsQ1f0~=@?pA;~aK8K~G̪D>)k;[Ӣ}0צTJQ0V~9VͭiR?7<Hr)>weO?w``O?`M P)691dsF5s~o;AJ[z`C<]k f_÷ vg5 }tX͝;E[÷'mZOY5i3`6^3[m n@ŒPW^6ĝ$Y]_/(0<@ Bw[T Og03\4ȇ6u_8q(aFm\szg5}ܽ=?gʇ0cn9[A8mݞ[7:k}F@O0Ѿ#y$C[aVm+)#$0)Xt\g11Qd vҘKuۼ08 -=h^;Am(_j7䄯,J{$q>L~T50?']~<B:0ØG{DkQ1zj𗣝'OsHF`2R7C/\V|6;RSGPf05f-w0AtJaH?͙yD xM c,(XxSnCV5C1u0^WT|rWqz5ԇt;P[j ףk+* r/:åzhc M߉~Q]n/PӉ$fR zUW$S; `ѝdxǣh)ISnC r+c he̓>g47l.ta5 "5p c8#l`Ls0$"# pѸ$oarg Z9۴ߑXW!y=V^F/ Nj(/o?iFڸg޽on?Uܪ~{В@+L2vd`UITMUG!b;Hߗ79 Ib8nCw^BIYF㏦Oo%k+w3wnjD%sb |]],2םӜOoݧ9'<ܧ9'<ܧ;'; UօjaD-tDFѨ>|DKe~^~YʡvDg?[2QC?.|?(ߍ~axᎎrP:<ԋ/|\C'謋KnۇRҞVɭJFMW|[$o˃k][6;.>y EWϥpشE}$EQx 4D`0l'tN {`}i LbZZuvhS6}|TF [`T?P>=)]&Bń=ب3$q71sQ\@r:U{$c!)\zqN:ơj_QQGK<qG-vl֍ʼ@ `@gw/K\^m_^o~SvPk{^̮]oM/О.Ly5oІbYn <=!{.U'v`f Q K\RmvX0S.TR; ke];ȾIFޥ Kvm@DAѷ0)NڀgbHT zP+ LPqC..xb%` .:8QV s\6:ׇW!9 Wv٭ǏwvLzehj|X7os;fir|(`fXLB܎{crҐf:A2<>4~vᅷأ ЂByL9jS`>2 1Ը5^Hs ;7F2ãb"E4f]e܄ З5pJ?R\,C^>BUV$-=jKl `rvUjWq il`֧ ("(GH ܌kk+i;+wnsS߭VwM )ej2{/`.q6j]4JZ Qwg/)R i]VY+W*u;T,F'{A{'^h oUK!d]jk1@ۜO}dBY.3 %y$$|,~g3$4o1|}sYn{`_~N)LLjE|e/x8rQ@2 ¬8)=S2z`#IQJAߠDbHH$D97+\)J^J K ~Ed֓wT ߊ”3VbdJ_"{PX=04p2!UbTEc$B RqL@N-7cuQOFP0҈Ӣ*-/p } >! m6w-/uTb6vQD 8S;'5l o|8pR 5ZZ.J&l/1&4q:*bm҃ˋ%wr xsmnǿn5URGM}15P4h&=ȆcZ`ex#>;-'>i{~vQ gr۩S:G!UJ?U A4hEUяyZ!V9+̔fcxHӗ5G9]dW5SY٫XAp#A%sE@G~>'_癖tt>gkdE!;:7ǶjU$N7&#P`)9a/H&)R/-2*&SJ{~UU - HhGqN}Q'X]Nm QH@% VXcy_#EV N7p>c| eei /e@⣘`6XTA\CJ{Eo:Y3+q09X˩Ea(t*Xq(aX|X8E3JtTlaxKLeĬbݍxcSlGi3o498Am4]xZnCE'Ȥ4n'H̞jE1դܛ'6" L)5@1tmipDHc4'.h8eVp[.e* /:vo!@5~`:̈ %%T y>x)'b,k"eOn|AR&Z/S'|(ZBlflP$l|J-*5սS[[L 'JG|'s\zi' C' 5e顭?aMQɜtf*p8|dl2+ pNzL!@n߶ۺ(h̥fuok^BrSR9$ЁjcPVT`zπ{ s(U{{pц@Togc@a$gY7ߪ£Z}wb{N 3:dF^nOzso*9aoq0-"93FMJ蔈x28(; G옌5,px;곏zd}8t6I(@%@gND0b'{(nz=K41i] NNd3k9=AګKLv 49eάgM$jR3 %ԂClj/Oɧd΋43 gjc4[_\øcRp@\K_Sh_ -uLH0 1QC( : |0޷BB3 tbGҧq'˜s$roN}+'R%~dHdH Q_0)jr$@)`QYZ.4+5$~%d\A:{crAIE22nN`8Hvt_9ph]umqB$TqvG8mv-܆y̿mI:_JWx ay$=zLJnaC/ϼJx+`1ULdE6 xumpJ:8M ry>JI&ԇZpXO.[3)Go Ά0<5 mА&41D}G)+&nBDլRM8* DƋ0RQ!͹Jj8 <.y xX_ 47Q;)c%nQS}mu;^6֭Z^|Vq{H;8.re8|H Bك9I aՋ`D jvHpOh Р'mh0B̓#c>60fQʸDU1ErQkpZ9E ٽ7oQȣk_Z>w_-"43a|I0$6;`2% UOgrU"*@=:~|6ъ1%>5 ! ⲑBUdA :0q;5;Qgx<@m/Xe;'7 GYG\T*Y>3|H̗[/[/Ôg"7r5۷RE0 QY`sQ'zw֞6`* 2=I}~*9W9KKK?kua_DޥZ/7v}7ɲ}Ewùu. %K3FT%qDѰ.V n. umN2:s67O5fM]yÊc{`Bs'gXrѸ79|cM8~Pج~hM7c;#v00y^Ӿ8 h8!h{оaEn0Rg c^+Muʌ _vYq/E7W}j2pYul JMrټ7G˗!4~xb"y_l![]uPpWP1G4Nʟ9EܹfJJ)v?w$@|nHd7d:3bˆټk 06bmz-[_lhDl~)ǵܴ)إpؕݝmXI/&'+58Mhw֠( .B'[ @zmUTÖL0HeªkojwlZ/y/gX?H5?eݻY>7jod-p*tz4PI\U0"igI$2V&YE΀lҼ˜+eaai,ήʵA{f3~fcӞC[VR':]ΦA 7fzÒ3ud) )= 6tяƯbIݼƬfmƫtɼBoS~^Y'g _g]aJ D\b7 z4biB) Qr4Sw<.)XgIKeژX7l fSf2ܹkS:-?}p6ëp:$R+]?={ gc49oܬǞWߑ(6}L~ ޸M9BT(s;f$抈 Us3A{=ഋ~zUNB2=IP:ĕ5ĕICi1b^/%}c$n_"..+@ɇnA%Be KV뽠4<͚6,%3@x|l^awr5و?{!z5it66t߯:G 8;.R>y]BK->Ta5K ebx7n/.e ~=)_)׶8*lfAH/,h|6ZғcQ9ȝ/"k MaFxhfE)G,ԭsR7@zZQ Bhjax|߼0 ʷ .Sff*RlfDwQ+"J𫵿D[xHsNvO-7,_#Zy|ow-6kT^Xn%sg߷-l~m8]EO֤ JY+G۟A}DV%'7n51QY42b2T`L9399bl4rH.&<P|YV4d5~;QGDb;JGDOKۆ]c04!YR'.L5t4}J :Hơ0-.#EL֧24$5Fm:%mf**_J&U9ؼfOfCMCO0S@1=G ގ`y330?06c[K`BRLj+6G.J1z)3=٪In [ a7W l5Y-o=qo ?ֆ;MLFU\/?U*2K"wX˳ jT%_4dF ׫U8Hi7xqb] An .ؔ  >3lqcB/ #FW`_"&~kUBHy8OG;o( b[Ct[U|?k/ eӪEHb' JDyI@@/ dTRHAs30'5+EjrEQdPϲ,yC%jP'A%I6F&i5MtSJ t\燤L6H\Nvt?L7>KXV=AY4*4usËъiڮxP-{rp.^'}:wo7_Y3Q9n->o->s,>5D mNcyPXgVp}8W Dې&`SZxh}1<@_IxߓR*_ ~GqҎI` #mL>  %+5(7ZE[#dH OC'=U2CChfYKo݈~Og;O5tkwޞs|&t:"f6Sq{S5T}<{$F;a m?VjkC|?pz'ﯭ,/ڼ[[YV'o,?WP`W6OA\qR ƺWE]^]]0G;9[,̡ 8P. ! :%6^A})oa|rBnAU1> o;Hhh@Ih=/ h٭~|SՕ{7_3Vr)0_$PUUuJ?ÏBcX[,V(b@ީpb"U Z)oPL,`C\co CBc"z@Q/<\J4y*Ƙ!aBla#C[d|k1@EkyBN]&R&hFr . [eQ "6ۭhn+:EKVǏ[$4@~^@ErX [@+,w]SR) T .4EOlhY#W#էSn;]V^vuVgXQ2i+} am7 u8l X}Y+ǨKS 9vey:8{t9 ?̥ev6)ߎ Y#"`ԢFU|6סz^Ee4 )=[@ .>kP@]K"|sA(t$zč9ۏG F' ?ۇ}<A QKF R!,c0a) kM`4<#u6=R/ɓS(*&* >K>c;v_lqP {:slzM5MfxdX.+-!&9W#ZQ<#7>>I ⳨M2,"ChC/>&Q⋼e4[ώ@J,uCIp'yBp]ib;;, ]z|6 yAc=~S/sʗԟ=o8~~ Y?yc4`8nW;Zz'z_rN^p7.V0~B-\%%4PAR0tQʵ^9^x3yW}2oaTG'Cl#P$!qܵGt?Ff=JVPEXD-YF;ȲaD$qw њ}Ê&nC?$oMxlCwT(| J"Ap SG3Gn.7;-eB1;`;J za}'\T}_ee-EfRhoRa͊uL^ca`e E%@(9h9sR^bO R"hKo?>MQrOC 0@xsNCᔨ6ȝ4q LqGE N+q$hk{+cO?~/5*6 ̃Ć-\j5G~GoΟoS_ۮ("UZP@xi$[ZkY@qE G϶+. &FҺB`IƶH 3Th٣16ޢ4EkXN؊ D_FiDY)K<ۃ}i],8ahzR'U`]M_^Ik΂B"Z"$,cy+nuEȼpfЌ#weN d?S.HH5q+t+%(Λ}b~Q@$ 3eCာz" Cn ΥZ撰g!4@Rp$:)ܩQ‰e% a,M(∶ӯpAZl&'n Q cJ3o3j8ax CXn؈fβfkV hQ&$.ΨyAޞ-Q5GP2Dx4؝ BF4 `Vbvp\Nc?'jքҺ:h$]i#7SȒtԗPJ~sq*$9-% iYXJ $?P؁ԍ.1V`j=b6'$8y z#ޢ0Bԡ {tI>HE#&PP%,\5bfUJ/, A'WND#Q; ֩Cթ;>sI R`*a0{x 68T{}Zfe:h<fXEĘ HIrP?cBpz/$#aziܬ1Suq+3}CN1G} ="d8Q:WZWfo_BuWSZ*Ev% ^ɨjŒz WfBT;/I$Dsk -lwr%&5)312Ezy"sn@е 6a*BU4IXc1LbʦDMYpVsFI/1a3հfVeg5PhX$hBnHqC.}$\6o/DhƬcw @O`^y@ˊJGaNQWոDxQ_;ArKF Ev7-AnƸ851j tV>v+˱d;LYfm.$VxH+6RئFAV^ *j) YF@ ԥ(Obj{{PkuJS}Ȧb/*2W /[:S=> FB hl_EI1#).J1-Zbw1u]:%e tJW=Н N;R 7pHn5FBjuB)r<Ԁ8n**,=׹]徔{xM6`]$pL(с }[[2Oa4TKC+xehQ(93 WiCv{^Zqg&˲o`Ά "@_ Odb5бYN/h3Ӓgq.6tEfk Ulg 9MNަ3YS#Qkmv:8N+u=Bmu3)Z5ˤjoK'}tZꅁ2 u"2攀q@ VGQOn XhǯU02P)f&# O.u- .Q NMjd GhHߨ4uwb\ӕ@~q+uՉ@뒀(jm{&ӱ>.%(*:VpqF)%_kKgnX8})V[< JI? 6^h@Td G$6f^9z#d&tH,a#EƈDڕAp 0yį4wBo.BoNe,"v_-'FD ;Q&L`!qO4 Wtŝ$[~=_ K5&zL.Xv ]18#cすs<'E(֞},hlz;JLr=Fl@y2\귨_܋z_~xk3ս-[Alv]cjyOwxc Iê; `7TMWN:3%x> $;5 j2%rngC]T mNZJEApkc&s'dYrXGBOӮD9aXDI,3}q,t[ 44,={_9|gT@ 56ߝQP%S|2vL9ޚbt}dh1P .{&Plt!ȯMA .v% п d0_|яlM,ŠV3oNh -S.?Bgۡn^AӿT"7}X-羵\Sdu]TONa&2%}&L( OӉ:iSXv[ u50qloos _xLF;+a uHp#߿ZPaa۾\Œy$G=y&zX=^b\Ǐ$~^Aī=̠n׷"V͖C;*tDӘʸQ4h0=TBVܣMv׆%) T-F$7PH|UCA%M#sqpxDgn~R R"M,l|bllu[7հ?ӻO"A݆3f/C\Qx+\o:LY;?Ccsgq猁[!8ԛgePG\NJspk\H&d7{ئ4Pcȉ"I6 u$q4$kQf 3Fo!qӚ?Eb)IkN@7BrꈢHQߓ\L{ Pv;Ϧ-Մ^!SހWK8-]WqwZvB*}[tcS(|ʥs->+K( {u}Ii;2>Nw]RjW&6Neie/LsZ a[hI)89)7br wG\X$r.%y4ޤ8[BNYn* XKT/k,BtsyK:hqD5ڠ0/Q D#A'=ç+es;5( X2[t(]\$O%d~b<4, #t‹ł}!!!:>3m=$9HD4&a~l=8v ݯ.JhCC6kFƝ«ʈ|=Lk WHK [ 8WD݃H!,JtU<ÊŲX&?߂SⷄQM5E uZNk,7+r"BsՖ,V0H>úcu|q`ik G"rf(S9#[l?)c!ôӁpw!GS_|`Kԭ w0=M﹌fku!`=̬GbF9:>ӃCmzv/Y+Z`[:K) g4iB|.ZFٻuas[ .X{)f'W#zZ>{,wG+AYd(%oLUZxG\ڭU.ـ q lM,z 9&a4 ?efdd!" 9豃zS11Rb2l 1x|^5Z̧hJ0VQ_H]8MѼ8wgI0(`W^h-77D|+"gɐ !ODQB5h'3xHpS otm Ƨe^*LBdQ5\Xl$cHJ$3K2=fG"BRr'HlcBz%Y;ik|b߿AP='ڎѬ%RհDDY::v*6҅+G0YeIh?ǯr šiŋySbaD\t^:(:jmL{-dt\}Zvx H HFk2hJ@U ]xᙑK}*Owu% 0PdvfQbvx5햬~*-,J[9@6qHzĤď/T{J=ۃ#@Wij׋MIhaEϞgR@|X+H*/兗/u:e֣/-7)nTҤs]40ޫf2qԶjY`-RW?ַÄ}HÉ~^x{.$#88ڮo>/4%LYC([쮐?'W/Utl]6":CCKPtjF[*=b9cU'Y)K{q& (-,賝sqWf;fO9H1:k}4q+3I/$]*+CR~J&Urpl n|r"7\:FHeo,x(J|''=8^?`r"9]LHFܜᅙUЀNH]bxFaaUʼn3*% 5%q(@\ꂌ;JĎFLt /^Ny1upCGpڽWU34n]wRGi e_",6! ;Io/l s Ҋ+Cmɹ $\#w94n$R}V<5Cd%Lk{pD2),my}9;+cD3VnQ}IZO+eVmP/UL0ky5~x[Mp:>tJ$]Todueꠞn~B%p& "d :@V)vM+%dYDdmJx vt* $qV9I0ч$Z5B%!*?ʚZ|eR.l s5fVd'#(h:Q5&u5Ua.' Σ3;9He,EMi [?X6Kr{{W\RaT&Ke/ePO_x9axHO.CÊk_Wtt!ٻ4vm~9;\-}ED]._zkr+wfzھ/LV]ogdg'IvvV [GYÂ@=`J<cZiƊނH*#RuZZz+Q~trI2El. *"<&@ x/m?d?.wVgP"37Y(bt0Eo;/6 E6eIs?_ˢE M(Nk#wl1;KM_,̽ _eN7,Xx!K&D3}>*PA?ftYA01ބWrwB!T(S0h$ri`r %tK *A+(F3O T:s'D፞k&Exs;|P³«$a;-}YT h`H Z;C;D3p"/7l$w$"ėG|0-%1FT =Ώdѫ~taW{kh\tO0j;Hu+w3 =5QNuTvt&T+6;›ٖFx^$ 5/DWiAk%6/7"+zlz:O 2kOM:ߏ.1A,ZT[Pw)`DWIeBKQtc;u+&:FrbdMEa <rkQ*R$ɒI?Wݫʎ[FcΪPAqhj¼[ g']*.<'hYSLGTt6L<]9 )42w\q#S]sb^! O Ad0Ypc#o!b5.8 u s(Z|v~,{o>wMgS+ !}fh8Ǘ c# u2":ۉz?+[~Hjz4䛎>$U=gY \107 $L,HqX x< G8W#%kp,@i(IX.T݄gM԰jgjѭ:qW͌Ge{?;1kOx\1>Sptf)k#Bˋ E~Zf@MgP[yUy1cb8atPÿdՈbٟHǦEA0ݣLj4ܴqdpw~b(hWZU?l(6KԚ eQ+IAQ22X; ~]oy4R) Kϖ7EQ]ȨY+ٕц*Voj҆M)ꇘ,Û~ZiRv s<,Ql+NNQo*UAy|E}bJEFC/FNAY.zo%J௺!Zr_PbtCmсHHT'#(ꂊv*u~(h^iwe$rTPz,ֱEUހLE@A0|*Xu\#r١#k*-Bfl_zb}P+lexߔ5KW}R[ B}‚U+GZ H>TZ5h ]WpsWM7UCQuce8SbqǍFwX[<טDފ~48xuq" tnf\/s<zY{gsŋ5?1%h~@e P5?xFhF]#I\ xP9V`1'P@yfpIgs)pv`Z |!poQ;)zËЫVF!o B$LaDEoTE.DܧAYDS@9L=6zrF;K>Y0j{G'07ջ'Z-O.Ȕe-tS\ΡDϬ}Kc^s^^EzgW 2"&'X~Yh}432#|p}|Qw< I;NEԧ[V)jz_- L99Ю;_Jˆp5 `oͲ!7t@l%:! P_++t^A<$2hV*`jb/$l-2:j*r{qEB+$N'o%|V XFkXa@~,owAa@nB7 hE4Em,_r/wo҇'!r3g=2qICLBV7tDK) )D$('iU` 0um +پNpekTtFRe^=GX202RlzAСñǞ5R*=t@|܎؜? Id*ΞI9&EߝOH3@A d 31a"-r@dHN)gѥk2Gt_ bGz=vxdi (TK5F"1Y@ @l8.[ I.<_%i.6   G .}!E`ʉd.IEk{*WL'W9u]qC)УsN?{~cH*Bʐ HIBXM qM 'ZbV(r,M9=Zחp}V {''U fo7 ;vׯJa}`ET[[DD7g^|Z8VoZS&1i(Z#o$/5"tLe.pdH[]bCwIOt- es:%Q_N8޿AUnO1?x,g xYHDPEW#r+VC'] h8 (4H''~T,DmUr_ාm~Iu>-A]$T~ 5衻n*TJ! D?T mu <_ 99uPu4vP%LY!x[V2gbV_eRCe d='KZ"ZG>eUZ$~ PĥE-Ee]HKm:>Z]M `$ M8Q3[&5\{/IR?R¥Srzd4 + *$Vi2Κ;ʆ"c]lrTF+_H/[K%U[b'FBed C#<t;`y$-s`_dfJ(:~Ci~ALi 6XL=;/ RK'D%zSZ^h"(5o`|MX IK_4@2[W-4!F}l8q1c[eڔ۝.ܢ$;1nRZ:AYk|O)2 ;D{`# I\9g8V~ 9WXK4fhT,.it=CL.iM[Y*RHNT)=τ[5~} Tz!8(ƬІfP8thr:sְ -cV 4~Er=eb}3hA Z"eYWiNk?dk#oC(xֈ5]2g|HZfB~߇^0xp+v3+yN{_Ƒ4^D $8Jv`p},G f-id`mokf$ěwfz:P/It^t/ƺT|%h xLͦ1a(uaqƮeSW ē\0m $1γ.mͪv$ dC$ z9?CIC+ t,sC~ǖL W\/%n\?KX6,7C6X.InVRp[H 1bt {i7T%^0Y[/ʪ^5כ5;, }̘i$S:\int ϥ;~ϿC7l~X1,]N.N|uj9h]Qx=QcW/ (X2׼D{3bj΋ (*U])K66Ck`{пAmNIIL.1P_8baȜHɎ Ĉ{=is 0*i|90ؿO5 .: --{'t"B(⧯[[*`7Ki_5% Pv$ @Қ.F3l7`RϛOjZlL z椼 k1EaDbbIo}m.^|":muD"@\ue*y Fw,|8ͪTPSsccXZ=67wTAQBZ cIu8\b-A!uN'Z@(EP8h#[5f=ØqԪᏨa(O 4U|I5Wqt?LbҽG poR*!}BF&p:^Jqs.7誌P1m.=vU|ɘK.HmvZ U(՚KeAi"ߌKé t^N*ZKw'|۠.٪;U-zm[@hȯSbkc.Z <NI4*)nu*z Vk4iس58 x.Ch`un$!H[gA08Et=j15Iӳ_ozA<}'o/.]{;GG;棭O~{O?G/~?d%Gvh ߻oN zI_@p!HεTIbz)v)u\R5$;PID.syNTևEa/ NM=m? `Z־V]*, ;D%?\ԔڨV Ձh oU5wò]<>׾5oz"^3,@\D3\XQX7כkuJL9G Lk\?BwWzsE;ۇt:b/7-f7?S^(?|(&\T Np,b{..+JIcLkI`Mro&AmXWHp--WeAqy9,o$?xC)Jdօ@!ݢxɜD= Y{Xr.g+GO#Z:ai`n"$Z>:,sir͙9D kƐ-ĵ7(j){+08b3p1:4O=%7jBOa\Z|ax0zZdv ^(΃ZM>8uZ)veo;XZG'^+,VB5P]di=XX`]~v}uhvYr ޏ?*x\xpB!n)j=kRïWLMt@,q\? BJ `Ixj"r:_,}~~k/Z_m󚓜Z:I#\i߀UI[E̜Ԯ=e7n&jwg*>c)T=MI,ʾKps!Mf|8Kj d.JՕriBdWR;)F`\HN BDQXLPF~xHr-1q*W4@Q B?D]/Y4 W104渜栳Yev%Ho6 etP̍Vv1U(;qRf\ovJ(7vOϫ/^2Βq )++gAZDj*kR5Z򎌇P1@/] #b a'=$k=l,Ĺ9Eyp;y4&x}M(;g_׵WF+_v. O04NVYdEwr9F>h~Biٓީ) 1=8 mX fS`Q;W-:k(Y4l!Dʶ@N[m2y)]m, 0*kfXH5\I|HD}5kŕG,8r*¹7zY-~*g)s܌zhhE:DpDArfy1kEݤQDbک^GՔtكEKZݯ/4 Nx1Iw&xG789WǾc>0s,ܡ--,Toa "$sXY x20,3.r`tNzǽ@^L߰Ê9Nu͡Vax6._-sQ6{pՑ H \,7ec]ZM8׌~GtzK#9 yNQGa D15Gk!csbCcV^ļ;RyUy!O;`cXΩ?q]b)F.%,9܏Ș 2_ {8]/t8M3Klm耾`21~X\\M#pZk ǐ30Hh_^ q0)."ȃY/I97hreFHy2`j!`*o5BFoň_-R\#pj&Ƌ~eCH/j+*uZ}/L.*M]|:IXwqOfBNC=!Z3]1S)4sW_3hk܀{8(,ntѠS/n=EN|[ ">>FTZW .$k~xo y i|EQ;C Qo9泏T'E.6yB -lNasnEe:ޫ%.qxN?کBW5J2 i$J~U>78Iuei(=w|6X6E|OoBz"/ q*+`<;q)P$Du d_xzY_"_~Fה %u:~>)`>+Dںģ{ۭ/I ϟo[1D8xVX.ZNzwN<:xw?!:f ?{paȟ==*l鋣=66 ?煽gC.1.=S /Ԭku1쨅Oaן |)Zya=Z[l>-[A Zm_6_3G ͭͽEo ;L5nomFlAGUF"{N"H@}%Ntb,n=fYfG}1`oJRjv/ްat0Pֆ!2>F&5 4gȔ&*5C6]Y]z.QlNaXeи f1/-t3im$+BM1( $\.]LpNYEj f40pD7q&t\K8mQw<㷱7;lBF8Q? )iF#96W(OƱ @fr( pܮDɽ#QG8p,DKR#: ߊIp FV(9=@.15q|L諥 R}d A*8?-CPN4g8m SYv/NϚ!Z:16efczYB ވ$ޢ$›z֟i) |L& * v0Ԗэ)UCvGdioń\5jiP87q\KumK;%[ݸ޲H2 bKsGDCG/~k^nn}X܉6*\UVIEoO̊ۺoGtN*,P7EFv!X꽙9>f{=ӛr-t:⽹/rƉ}V~3B^ Jh|"e]FSgz:)2sΆ_Ck,GjZ85IoկjbqQJwrJS\P6[A-i82_94` (!\,4赩=d83pȱ[J/NEU'? 6(ESQ?ojpfY5-;`l sT's͓~T4eDy |@ifBG sfJHCGllLVoCb@QΒ<So{ >X!n $IO-3g"("ghZ)"Xv{ol< lotL{SG~;q1r)ԻSγ}ԃT7N$<2ghC\T%R.X}qm<ζQ?hFJ6nȲ"r["I]&{s_}4O~ L_|t9ՄtBupSγ3"QA.8ϩ[#i\AWt~-ߵeP4{s_眑0 pFÈ I&3oRR捯iHvY$LӏI?/"ey@D̼@u_gh϶|e.mɸ:Mw*qU\7y6F  {pSd pԄԻ[%'yol͓itݐP)Lzo1OA~GIrS9i$gtԻ꽥9yz}.笕~4OA~M䝂/γ}4OAw`F.fNʤuSkӯivӳY3);rލ{ȴLJѐz_GPGP sZ3͚II'GP>F١ʚԧt S*6%}zisfRlㅯEhS8sg]tjYŦ^$9Y11-^)@* $hfK,ò}qy2mr9mML' %NAghL~D!3~_3*U~4O JX/8ghÔxz 8&'6dŮH59Ի8>' Vo9բtBu1Rγ}4OflqOHX"hW/ZF5>'[-T0lj *:c>'|ſKj(]&qwTfY(?śeq}{e[*wwHe >#NV/f^_8B T^@&^7n͓~7k3!ۍY wp/ܛ 4QQGv^TM:yI?VGΚ,II'xi~}qLۄhr0T@47TؒrA d@MسBɸ) ׳ܰ4ŀEȩٜw@H Jk2 իwq̖_ͧ˪r-*C*nNi>8˧;q F^m{gO6(@aD+KV Cx*ގڍf4F&ŠYr-w9Z|ȇDѮ$y0 5gk/WVXy,[|B]p G;M=Sg6=!O9nSE37_naoWHc9?*>% K,'jwdž3;yb-cc=4("A'RcISR6+H/6Rخ/ tlڧX0Ф g̭_|guCdj/Mc >C mWN_̔HLW3 Khz!}Avbػ13e|4FSx'L*b Bt stjŜ*kIKR 9 EKڭ~r(HuqD$)eKpv,I8?yѐKܦbaOHʯris`^Ц%ID4Q5op2013!b2l<ꯑp7'tNލ1 .$ :`~&!Ȅprn:su$߯cל3[wNIpSscnl&L,ti.ibfLcpɷ⢏$PMcN\>zD-.X$atްrB&(:+ 8+ݘ`⥺W[3ds Z> }ArU`8.ݝ7Z.G_??ÜeAaPvVHDx@<ֲNk+jk #@P"=m}P0PkJ! !o4:ޱ;+l6N>:{cf1pp˛Gd!Aճ/޿NdV>sjeu"ӥT!iE['ԗ >kOՋh6U?Q`UYq _۟XTaVnA#[[PPM`fݽ%xq|q"X)w^c[X疀tKJs|?:Ԫ7HD&ԴZ.9Yj3~~e݆Ȇ<ԁxEɯ3 quF⒋Sj~jF I^4/GWf ,-2c'%f}T!U()ɴ2¼f 9c%=Ín>ek '/a\&愖uGTtJ< pԘ<[ 'a3ӤYFW9Pt̗Nl􌤤U-ųvM4H4*`2(hz>9-e#_!43ytsU~+W$,z)hryB}ڭ=Ȥh7:W vQgxl81XS?.Iz]]:UFy(,}mUO_5s.WɁn4%NWv( bð1ekѣl}V^"*O Cn۾܂zFXYfvϴ8] P rI.0 D57ړڌh-:=RmnR|#9**}g5=)&RgUXz-,\(q(sVDݭ:rO+ ɓdxatu`R$&g^̄B^oYM0V9nmZ f 9L&#O+ E9=v8iROD<:w3ֺP綠`20KJBinH{xCj,OsCEmշQ8՛5ZnC`mrfm~|ilbDL=UHU̻ <~#K贈)Wx< ;+WmȔٽ ˴+ 6%3AS8}'H{j4 IpZlUW"Wƕ.HqKQ0c3L((&:xNc >:\,PhևE.]5O>ry$$jDEM]~>uWQ+2 Oyq~fgHm$FJxFUҏ~_[< Ž9Z7թt8|GXF {THkdoOr Y`;K9;4{xwW'd \"f଩14ŰP8P3?}=wUt֬t6UV+0 .Q6Ey ӼlR7Rz_ޟ>i9 X\sHX 1k^-u_ա\Yr~9bO^4(K\*qek}#hGO =:UbhxDׯZoHKy(4u#,z(@t~9cےF/;{N#] rrSM!m4Qr)CXAYk"liwxX0_m.`Դf:l: ZEiߴҩ EAl'oġwV&›+R^˙+:Dm=nSBhn?dkLGz rfmVi8G8TC؋6n|I"-]+(:AJa\R`ml7+[ #0w {aR1_,ȋYϳJc6*]roγjAciM@YᰣLrzv; ;}WR@ZVg7JsXZ+~GoR*Fo)0hVKZ"}.Zx"Y4& \YozpOD^lB.ܞxV>0өs7ł/Ѐ%m5f\bf܌<nͰ˿^._c*,k6oOQP -fG-*J= yVqޡU1jR\ Ę/ $6rIQzH5 Z1KtȽ8 V̒,[ZN5TtbqC\cCAkB&Gd.>\&:(hXrCoMkLhL7:J{q9CLu>:ձR,L73Ճ}HTlQm}R2e`{js.(1C&XF' ޞZnR+߶L㸂ShJHLEI{!9]8b 2آBg(fmlM}j OQd< x@lrb=199S5_&t 8e@>{s8gw pn8n'h9VnѴjƦvZ`-8ǠL?*^<Ԗg(B}NIU*I`.[ãVݹ`:+hd#·!&gyV<p 2 FPa Oa vjuV6Cc'[[LیM?)]J#k4F'a;@-9jem~0nL'FXF=qVeg![5I怔c04^h{+.CUq{L ojnzK4.enH' 2RDc4Aw\&]08!_򛅁A{< PjD`Dh 7{"&J k\. oB$A$L R>,|"D!n4 ωVww}˟j{ =k<\-2]RROF x/׽ e,uy̥gtFnşu>9F;+ s} |_1ԟo7o- -oNo[Ϸo? ~ls/s?tZOdHݕ> КަqQu&m>Z?轰iaÒw\w3mtT aCބBawLaJ,r)_0/ծwԌ ֈK/hĥ3_ Zl1 2d|n#ii6y8(P~\}*_R߳# >2#h2[&[+[I4K!Τ^C9>Wy ,ceA0o\xOy`" /$ y526DAmi~sO>M틓?41BD"i4Y1( ކLJyOÝG $N+GΣ }em2豑6Xo>זMۑ且 Bf˫pr..Q4X^AM(sB/Mܓ&4 Pa5ry0fM& 'WgE؀ |4{JGg";aLh.9;!oUÐ&}Fš٤՜5JOF7@I#G5Θ%R_WcW|:^fR@fonhF)a7W fA' #'dhux tވwxS$|C6o^tF79Trq=P0XFB?*֬LGFraPcght,O.X"y ;F O@Jl57й:>PYؑp$E@XGQJn g3 !i$╬&qՎaM;l\8wIҫ^jo-cl!f<~wiQ31ue z֓k¹/c`58&dJ 5p{P#8] z8`TdpßZO~|`kg`y5tR.~sm<^! Z2ڔh*3v!g !~)! X'H5IRY7k NR6O5 =4 M(9ו"Td&&"1f"e:k&&/J)!Rq!e8oeh0>dhpMӮ=f#L@6;43pù,BztGZsܳ#b]Ĺ՚kedݻs7n9-ѱ N8LkUii?gWNB~~Q;bHGaҗuK8c MTZxfZP(U}~ WSk_͌(۾5g@a`>ؖZ-[Db8Ƿfdmw 3١\/ι7js$ #W+ph$99‡$)73p:,N G/iE-p%E{ïn@4nN1Q/68'Ar1mIwqdZ"hthP`Do X!הǓU؟]:Qx )6y[N  Wl-fOFyjn#ϜhPǂ qx-qa]'K pRَfUZGgM8;@MT=Ul2>@+8:uɊp|o[0TT~qswVF<ԁX;?9IsWJ90Y(KtAeRA@8U:SSn4\Aov]Vmв%MILyn^hΎU /b^@x%N4paQu. $9.&ɚfHR|(`! wLYTI,^(hS4VwMg4"gfܯڽ gq! |w>* J{;YܚIJkvnk{3م sw`pĴ}1Os^h) "tю+Eߍ9x'Ը,R!" ]{=k)&"s\gauUjWjYUlU  gE(h_,u\a=mO8N\RgeBvcN}8@cW+{B1R Xzǣ_، )qyDJOC׬h>r}FJK:gՈH[mjrS+8󴨳J:mfjZu:4 S ϑi[y#,6ɸ"<`rA waͽ'Djӻ0c8LgW3:Y36ĔlDSB^3@*]qrQoW)3;$3q%@#l'WP)T/ݔ Ϭ)8U0cv (f}'n.`!"1N`<4-`D*x錂D%F> %\y DH% G[=4`ZʉD\6+sc4[q  &vOW-]- 1H-2jsuANUp<)248&):jJKm N8afbIIltW o%渡 ?\]^0Y4tZBn >}]ѶغY0\-Pr5E1CV5yy [B :gy8'pBl7ŒF],_wQ.-㖃7CUq{!uƀbD`;!Cྱ:P:y 6r]ի1hnB9eN‘:n` GpU^J->X£?_6m:5W*DS֥Y4[X 8gQC.IFK$=둪%]^~kNἫ1yzw"5=|zYta0>dSY2}Xxg],UycT:s#h&cQ (~7F1#qjZmam/_HVٯ&ht*Im2?/N^(xRsobZ*bV$n('&!o!x8Df;1B'IGaBh/S0Sc@Mvhb 9L'QwܺNGdP-:J9xIA:#m]Ի4x) qt$ $RAO(8+ qwmZrV#:/KʁNYRLJpꠣ©дb;5vmia[f@gZwC`\ nǓf-sKDI1O// j1@ku[z]GmRf>vi '+?2w35C=Tr2HJyԽ*kT wp4Hm#NT [hlT2- 8!;P3,'SvCk+"%ЧG@2k[! p󔖤3ٙ:v{C C`[$QrIIf}kzv`q ŝ OcZtޛstt \+j+;ϴQwsZ5[ѬyA~k/.`W~HYѕTmhbxx9pfgb0@X3cv*y3ǀ|,](qȄXEO0[D(>% 6/=eǶx4^1N.&)j@:T(\ibD)-5qjߐ'kārpHy65ZĮ@]+ʼSJ-3@:/nt|I3jkh~@a]~]^_z6UKEh&q==11[On`SORir$}SO#(']Yr{h+ n)tMC+eKq#Lv(\캽),\!;O7(py/J­~qA$sicoǺԉ:dZ f7T|yLk7N $Cݮ1DHGsQ!,CyFaL]50+J[,TNC}0(1"Rc(jpЅ9P6z3vkY2:pF<\zRC] z֣Tâ]m/-UƨW&p10G80ngق"A Q3TE'9[M zP ^{̺tK4bF1/S%|8M'irBn%pHyɦn nNelsKлW9n֏!IX^dptYKH_O&,,”jDZ2 $\v. ărp=@,<$BNq$ _tpâ^ }}^Iz}F :0@ &ujhn!KMUE~E~KoF:wRy, ʎ@w$G35URGTdZcAPNBuO=h=S!@.{"[HRb"SaBJ}4Jc1x|*w>=K]6ɣTT~~㎦߯-W45f5ؔxHioSDtTnF}&;EyjF.+7FsR1^ӫ4vO6'@Qw3pBnt``4KKx9Tk(E+SJ 7b- t:vd4eiP$h/s=I,nt nٝIiokB \qBV66֊t )m ]A*4c!π;+)wcџ{cd qΉF]P0EZwgt?6709O[{RtEk4XN![ѝidvpsp?TW^aReޒ'39%ij|U¡I7c,ykYGllNU5-6t<8aJ*8]zS߿⋆ H_w" xŌ@#tSWk7@,ڄD_{ AD ,[m?c@1Ԇ{;OA” iY-A"o(usl|eTPQ}Tp8ǜK6P}s-4q'7jΡ8)Mb^jK8zuƂni3WT<]"mҤA ;oGrڇ1!0&&($Xݭ'l Z~_Bb_AV)xxxV0%K9<$+fѷ mE\I^ZZAzɮ/OIطX_#gnNP)~^vO/6, / K} `y,Q],eR.\K2hWN2ęZ%V P ;;oskoksValLQ{-7K pa(,1v^WcV=1_evBUt.ĜP:Ld ɦu+,vA*=/FFg\HIfn΢*4J_:Oz@19r3KfϩUIgU={qH7&@.qn0LnMĈ\nfFfP,NJqISۜ59O߆wQ#>0}k0V艌=.d2?y1Rrꠓ/cKVXUeaeAR%`Yk9 = ڗU< :1 l.0pQtizه4*6=+Yp`yȆGH"S$mn|yF"ÝGZG/vNXL S|_IGMw"8`kn[[B},2=?A50E!6 NĎiA"27)* ]K1rbFܑt'vM5Ox; c1*WGPI"Vq>DU?\ᡡr{?kl..OyG,'|([~.G)mIRKcҞf3T(mG4ag" ttV U4.i53Η&zSpөY4TNJ :OぉvV}v? AR $cC 8uv-Rn5CVlo ju /P{J%5a,QѱCFC!Herq9BO؏-A{&*)D@ IevuWeUP o%v8ה`WA?[ a{g$v0]‘` e8fQ(5F4S&X?-'t->M?fX4+jGwF [-8hrLS0xbًODh AKH(~DЬmgqlWw$ 2dEDV6'44Rs֏M˻O.ѥVpzK ,~PKK%]ZEB=&ʅ g ob}Ѵ^D#YCVrrOruIgE[~@(RԷQ݀Ő!$`m5h!af9@6c˜7k=m˚eMF =~MeNdl"jpd$&HZAnVe *ԗQG^C9h:.ZztݏBUg-)Z.Llb*MPANZO`u htkӲ!&jE5fuG)3DaovK35&+jHUxǓ  MTy%dc;ˊc-q30d^^/cf;yeB3U$YVeIwG}i%{Z3a4Q;-eĮvю]zwa焿#Rɉo?/\JɿtQԍӺ N+ɀiJ_{CNRC0hVkkĵm"/Eҵ>p5 +|G:,;A3*rgB2qC%gˮ9z|ص)B%90G<ѸڎFm V\\{>^ιNPsj‚,Wk6Pi?vXQ'qa.J]Za1ԖdA"״E(,0>,lb8rG}C_V{\jj Pl}K 1 Ier=t<D س`UnN6%s[`bU"Kr; G,E1%|Љ<Y"|r<3lWaDRbenΈ9wm܆RNmqF_cC9"c'XY7+bʧ7*ܨ#jN d?7]ɸŵRǻ{;j ĥ 6Dd\\QbK[]٥nVc?)- ZA9˙KgAyu)_Q]ѽI7tۈZ^&B*{aLCѧ5vjHQc[Vv?BU=nX?BwcoBdZPZyYodF}nC}Hdv'ZNQڞ#w.r&dQMC@_EFz00=@KN+E[1@WPB8)j0Ho j.O  ؊dǹ\z[qhxñ?|VU]x@*g%^Tu. d*;&1X iO?YxA} ڨ` Yh / '? qػ\1R E`{j̡܉2'|Q߯h+wTBv:t^E#_6QOZ[*"հ Mb(;DU^$ˠUi G;. ,8rXk/8GzbPG6Tu `S8=naȝv#{#F.>̐e2*M8qx颂3FmA6=]uc_慽ǥnu< *$T,teir59PF/o8.}0ÊZ;H|~ZDf?LDTmim'!yu,,T7n[;EH|ˣg*Г ;XG58-3$ʻ@};nmcI ysN=VENjkJvv a2,y~ݰ @w>X⧙H%o(grĒCd)#,xC/ޖ1|2q4n:cKT &zzse?Gabl Q.n^0]S&PBZ׉u7)17dHP a #Ҫf[G]pwVl#0FM, `ߦeyKj)076%~oQ۰Tq)$mb 2y(`/x(Ecwm$HG!a޸ǺChw 5<F^.!qq<lTν}cD`8Em:qVIJ=`2h>00_؄]BLE(N`AYbrb%2wzS}$ s4'$]Vxy ]A&eMs,lAJQ.9жcJlq~ܬTJZ}XV߫I\1aqh&ut<ް$1M'`zZNAޤ?P߮%Y!FrVި/J#bu5)2ĥґI0?S**MΊ .>qcht[8P(%!:v%>Ib( jOQpR zD\LQ r=uuOW_f.uĊE/b8KQvq+rre U |T;+C8Zu5-,wn8x ݑ|PJq0>x=x-=]80]>"۴tv 8 2zIEorgH’ hgQ̧ 2.DuJ{1CON2>u@l-?DBm IT*"&7^XцZmmuv<N}~-5\-ژv]<e=^#jՀ41r.hBmtQ`϶뛑yyIqs5d>o4 -x$9$9t,ib܈Nn+vu%?5q)G^+w \]@/` r< ȽK9 \qZ;7K({l!ȇLaYKAϾa<I n:ݹL4zTel)?4Be!9htxF̸U f`,D|FF}t{xkBJ֝0's';'7f(B+X3Ss[FWUwTy)xR))N(ꢴƬë|cعDZ3عϱs;c'ع۱v|cyzȘp_c|$[>cc1;4j~%oI%<ǎtd۱9؎l;a;rly:ez8w<|G'rriBTW=L0Fi5hudd}Gr pLA6F'F_ Fp U,ZE(OJ0$ 87cVPτpn~fZU}(y.vlԓ^pǣqh0uӾ{],'_4/N3 k\,sXXHժaH j.ꊭC#fuo;}Rt‹E7]?dp%d`*-[+Jy3-"%ƴI&a0 ǵG /Cv*ؽ`.m'wzl"/ٻ*+guC9x!sUl3z;A>Ɔ\oOrEѰ9G\KKbG_.XFΞL&SYkƪƫj);Î80q_.}+w(m̡c@B1qmIYQ\Huۑ['j/sc9$>y.bGb7XScXxJBOeRx }!oMǦaR="0F)a,T>u.ʦ'{uUc -+qp}n/U}cJ2o0Qt}J'+ a&lfɹdh~&#z5!\)xJb%k0m/4۶?O>A46v[uGU4yzXE]`2NڛLM|@@0$ϞMgO]{wH-q#<Eʂ TOP\FrG5F.n'du^L' YdD)9E'ʳp{v$TxC(1Fw(>th%΄H4\+RCCh}_8ZQo|F !{..tO2ƙΊϛnrЏ/p2@G"8:L~1NO'L\{4԰O6Էk߭x|^0 A?: ĝML?I\Yv|2iE0Ա7DU^Έa{A8>I:Q#ʑN0S`@zo{7e&(#:2+n Xw2՜;P^&q/G(ݏc7?VXj!tn 2Sj1<{3x`*,LQ5n7AsA7gJ;)l)j^V\!]5dOog&FZ"ʬVuZ']S~Bw;oބXz <][ g-QDm?>qb'#Md+S| xLaGZG@5ݥ;KoPQV Gв$@/$I%OwЛ .ܐ>C¨{TUyAp4ٔZ^[L*3Q@~<Vﯮ:.( ' 1'liv{@MB K1F Q<h4^TF ՝f6jACqzzXe_ŗc]Z> I~S#ێ1i<鿜Vbg_/IREk>rRFa#4;ͬ#GG/A57'C #_-ii& F0c=w a^w\`YtJ TP bvg@:*;ǘb'' /<`j^xyFh:Z?ΐXCC*@}J>亥Hj4-|rG1"GͣbNzKk6$,JHE#!+_rxA7qnX .mnL I"h!Z0`t(zXPFe-..?8 _ԗ?9(sÊZPSRDni 6+׭TT5-M7bP<_UƟv n;GuS>39z4_5DkQؙOy7'!qN?Tr0J/@&|0TGSۑ:ݨ/>毊tg-;R*Xjj( \u6ְ>Z42nj)l$>i7NGVWKf;5 u )#o0Rvmg ]3#U[3qJ-i-ӴrB\M?tϚ}Y3tBB롔#OvRM%f&`UrnsF<;] С7Fug)> gY|sW ϥ~p猧OvZ[O˅Ln0A QMdgLiZQЅ2^M0  ?@t >Qj5j? zKQU*Pʷphn{8ѪM2dLwg{}x߇mmuH_f:VeWIzt>o휤å0JЊҚ4T{zhyUhUNHb`i!زS3i- *ڲR%1aYrǩbmXE/k+6Qྦྷu%v?U}WiUn>?8ۣpڽug!??7[.뫭=ۃ6]Z4idqψi@KKPv[du2g T|3{bՁ`]Z@0j +;AW+h&`4yNҩRD \1Ⱦ}[\X1i[G:,Tg%Ã}<@*uWQ$T{`rkGe^Vtl2~5!=:IkNèsnJ-hκ>Do32_/4Z1z7"L(6tP=lq<>]k+]=uʨ_o|y>lLGW&m> J~,Vd|!{:{T4mM5iGJŗGa?$7ai<^omݛj1EgZV,񦵔7م̀+K S;yw}`t'16 ^>o͍A5A}P2 er>eh`koa*\!'yZ-iA07#((K)Č3]#EO<ۑP(Bj}Ϻ'SuO4'jXڝ3"o/hN4eUlIGwHrw 9>/c'p3Kf 3s 2uܼ(ҍ ЧKoAKvu:qG*o959P,HS3+5LgoĹ쬃@k\%,O2c[GEw2Or#9|n}yӸat ~2;4i{a&\иp6aXO* us w AOL#MivC{{#Z.KGVW3z?s\Gy\֣2^lB]T8s؊Tpש&Kv8ڤvԒ7c@A*AXn:!^O qG=_'/kaS*b)/?McՔm 怓)ό(rhI3I V[Ɓ$$ðu#t Ojt(ßjnrJSJ-BO#kC[[pӹ ]W݀FQ8f+\ @vs+P1F6PP[vũs=! dƊf5׆uu Z04 iJ n%ֆ {onx,Ƒd `\b?CЋËRQL tV^tȽv/R (:yE5zR/(zuAtVtHvH({0jAFY2V4"A"i#खkIkkω,@6^[[<=@ϲ1K G qEڎG\N1"IcZkE6qWJ px'ƴ;7<4뇜݇זKb;-/ #`3W.׍5 ]:ZntkR_϶w+ 8R%S]]um0lͥfFwpU]j?D a//!@Uo+0n!xpI^OWu+0FMEf"T `rGKӲ%+\YaJ7g!y`+\f?N=%%[zIV6Dbh%1ڄ!;ϑ]qLoQ:B.drlpJbԅ37IŭzWX UhA"EX Du .z}ȫ냮',U94Ap'jᇂSy!&)̦jY8NJ+/8@&IcanYh#Pْ)%9$S8QO `w==p MdB7 3v|&8'jw]gjJԐa5?tjp~?6F?c>: # l)wX:H/~l^&|c-1C;J) jJxUwʶ?MrR]ICyt$M,ga)BvkN?Ųޝ0a-)CBNrzU/ .'9G9$584t]q>O-cmrxX O6e/T.Ît:yZ5 膢ww,>\:VE< j|(]u(^s6g 0Ը ʨGV tPd{CA||ZyWAx] FWأK)ޯճ3 g|Cx$%RZ2;iUC見H_S%J4PXGAܢpJрc8Sr$z<c0t3%w^ag&C^%t3aAܺMfzi҅d (h2[XyAAR N\aɆ- /4AGW2M{J[4hNc֓?]r}pH}0A@f2.^gRg4}kSouI3cXRjWȵeͽ-œS8'F)C{\Pİje?-eGԓi0Dw{5!nNS8aY|*(Ctuj>0& fѮvKHRz\:4!e#3]i߬rgx -t#B"AtP,qч1fP֡(e!F]DuJ"rvn=ޜ#c>}N> vbdՀ#VN{ԁAq>a}EzC+Nz(XsOn d x=7TL|q& j[Yo&Q.m=N`i*~Rն#grk(R.#iU۞>ZՊ~vڙtst}Lmvr-PK; VQ>qRw-.(St%gDŨ?bc/g%Fzl$4GY_8?/vdW$ihocFoΰNEc*)ƖrzPM[i]ΤUyȔLXGҋqjv|.p#e9rxNg\]TrMxS'kGeP* +w7O q d6ih)Lfq+El-BiU?@%o;yc.WS#F›}co)w y_ Ù@,Z]/RJ'yjvyʨmWQOKt*q?Ciw68-q+cHQ'Og3#r-q):c| }]݀4t{=lRYhs@*ELǂ,L7*tcgN{QsCwċ~b[nmGoM<H ҔÒJ>O*)eJX㲥.aGgLܿ;~wȞ MePo\7aRiP'Wf9̪D7dWVNY"ԍq7wξNM K|Swr)|*3{;rB AXwSjt8am ImWD!*nF_ 3dMǧmZ aVӖ1i -zH9;E8/v>蕺]hyP~-EpAy.Cg͊ztskek{?<;jm<9B+,`ʃ{NW߭fCכSj[8~3Ҡc]%s";jO͌ArJrrcAً꙾\gUE@((;GZFw0j/Pܪ#V& YїSFZ> :]guf 6򛭋U.a?Q,>8ub\x4ÚYcddQ&k/]| )ZWI18/YG^|"d1$|;I I(('v]X# u cTu< : zU@IR#ok5^87n.?¢z1&Y`Hck$AgOS)ʥ}Fgˣn&$xrz<.'tB0P w$/``\(qY@0,+FR ilp&,"`GHH|2#C,@6~ 5/GM8` ۠؎@`u_ŠyE"4d c100As=Ȣ1&'C.<:8`Ȉ 1n9MΈcL()x䏧8@kbX^xl fD,cqW򊂮;܁ 8~ M&Uu4|U-8 [˜)tCmIf@&П g'qn*J轁DyLP;iqS3M[HYTGUr(5_2 22}fb + 7|v '?gJ甘9[ɸӾN 6[nZ0:Mu{q@q\/W*x}Ax,*e\,Pݯ](=0х|1C+X 9%˝ovfQ^3}-K\n39uUcz-^[+!E^R(n7?o@p펢^ㄮvǗCሬ"`D~L΋G!Q 2T ffKzqE5Z9}_wT/x+d?dwʛe/U*j!T g<ҔzɢPTW^Q&[2t:F(_,ZB٥jRR&)PIQwK+D{5W_KP Hz*+zRXX=Rug)l4m:(~cgY3 kVIAA ]O׃w30g7&\7U~'W.^50%!4Yu'Mөmj\;Lfvn:X0s5`Ζ{Mn2\HSևe:yNe/ْ_E& c#E)>BTƐN,B MA<|tFt^Ew:ѨRvE=kj‡F7PդißZLUyw`Գ֓Ghn&eͬ+i"4繱O5D[Nm޲f:1՜[ӠOau{ HM̬dD'),"RMmP:yaGij{卑ۻ)a2AtqOm‰Ӫm5: ܓ-672 Q$) t2ɭֳͧ;F2F$Po8k! p}Xҏ߄e]o `0+/+ ֣`C![:*$h< cY" SlFE19A }}@P ă9^.cߖ'-lb$| `yxs`Oԛoh>Fr\ ʀ3=(9KE;/[+cfR+ޙPy[[5v/Ȳ"' M\ [k㸴>[i7 ^"W U9\2/~m&EARqEK5 G0@}fㅘLMzyw4†5vݭS@8ѡMl"Hh0ؘN6}Z>m=eg+ӄ* yefq֠i-nq 8D0 B)Z]GAj[L|gFQMbxV~tZ9{ʙ# eCqXJzzSwVy}F$jGʨOBVEqqԓ6 T[nV$ Sy}pZZ-`䕽Y~s)r41ldcڵ\/կ56i9vb~*6|Qt 2 cMoQ aG&nAoWY(Ԉ A(>gKLS MxLtvCqDӆb,ܓnPPQ0_bC07"n^ X I]'@Vy <@#?=q9S/Qv\&AAp  d`iUwcjPL@&lN_#KaM@$\Z >+:\loo!詳#;Xr%-VSz1 /[_ssދ?ş^dA(h49T4{"N6qbvHcuEqښC;d0ɏ'<(b9҈RRA'SĿtMZC?-6ɡt tjx?`ĸX \Ĥc:pIZZ<`nXm)ktuQ&̹jß*aׇnKY<9;X5"ϡRtӜWMK Sk3z%MfdG0SPtMbGpDZz̓% ezܶxޑn.Ou{pR?1] O+aN"-$Q,kiUљvT9{T]UtJCUM-U5 L~:]i=wJO]mvGٽ¼_ӡSa/;Gjs`70L/#U a`.X6FG4cm}> !l["q<Տ Tуk %:Gv ? vwbCMiVӅq; 3߃Q[6 α ^(W/)XI+$ZBsJh J#"N01o0#)p1q!7rmsp ҿt1m {Q53BPOI3 F4.aa''{{_~v&E.݌FW\Wۇ9G@SwJ=4v۩gaEę s8$ܚǨU#U0@"H#DDs B%υ%JqI%@vuCAGgET! IL˽˞u˷Tvl8[-8y|ਜp+ kΜ>E7pdn-2?=cn-ClYnbݕ~yKc{uhAH"+TR(DQֶywGl b mёv<kQ}.‚Yy&!\Мսw!duvAZ:v4#r3!5B2 Q؋ۘ3MB&TP'N9 UœQz,8!2ihx"UrO, ]j04qjLg=n-1. g/ɳj뫯YCwm jxx h̗UhޙS`qDCN3>7 u,~z5s 3r@m`ϱ7% ,`iOwİdIO<lrkM\> xzՓ nM&S|wﰃj{YhG-Oާ4^;W7ezhq05I:?9vͷG 0(7?;bvZm1 ?3p)U)^6e<~`iȍL'[[K;ڪ٬6XPD.i 0aǺ^p^}xښw_߰=f$& <7w=$,O`Zߤji2!s8F>ucHmX8ܑj0̽9v9ֳgAz+iE)XkX[!+֍w~BDJIU}WߏIinp2h-V#ukI`XtFPm]W?ÃLd`WE%jbfy'`\v׹0S3Fvq}-oduAM$q3`bg0Bk.0 ٬Y(LqrIs=0A}:v"%䜎vo~rz8D\3'4l 1AtqHLԎ9~K0x mˮOž6gYa hij"̘( iIr lBݒeWX gZ3+We! :ڢA]jrin&cF6~%~rC=Wq,P\_19_4",E):J ݩh']>'ͯ̓ooYOL2ΥK)Cb&N'|F|4vAt}x<զf[}cA0䝫ufQRq!s"q 3ś6a3]1_ɘ/2+&NbHo. Z[ee~L*ST$x-!YZ@cmpMƐTv_@=0*m坐(F<.Hv͵Ϥ ̵2 گK ;4>Nh~~73Oi'oyp4$ƲʱV'Ԑ>e7wLKg1Gtٜ9! eg&_tx╜csMk"!QD^B:ypi,H6Cz0ȠPB.܂N2g_7]7,Bk1O0s ϑ~?>u%ww6}>~},uHē4 5Hq_/b Z7'ڥ\k0L--oK歷9#`U]!jQc'r<½݈':c #iG !'6&5gO60vV2ZWyLa1]"TU&_pi0r ~w18v̢{7Da#onmՁr"^*mW,뜶˚>n6m= Mx?DƉɀU';^&-0a\4w L!\4X!xFb- N ]D o57iZ.={ ::pe>FAJ04rR-:z@12R-8_YY-4DXk&7VpĽ8L}CS?b& &Ik/U_r 2ѶH.pѸ5B%EEOWLz#5AJw1Χ‰0>…Y uE%a054} ~ׅʆA;a41b#e^ .UY W [ 0 zC`uHMUK Gp{Z*}\)1%꣍(J@J&=}šR;l.'Nm̕I~&KjvTG|""Rf-@VG2;Vr)_U7;&A ȭ"1gvK(sދM z0/zy( fVҘOjIZ13pؠm, ˨Sv_ ^Hq欈Ժ=4I2✏U?']_"RҁFN8jv#jrIbSn: Y< Y0BEroSK .֤tTńF] )moKr#ok]~&Cao! wV[V"BЪ:lȏHfba|zC†B"ס"k#nM*,; #GDb}y՟.zdetehʮ3dyV-bϊr[`2MbSzUjL˹\RM( kiJ&gI[:c?yx>r;zoW{sXq{ۧr1Q["Ч91HS1eE u+혭@.>3.⮃Wν6UGCw"]vׯ:෹DWvMmomj]ѯny%|s,Dtv"O4zcU4V՗QWPtѤXݹ[K8yi-7!tXhQ9CP:Y҅0p4{k`. =Lg2\~l H/в[_d7&T7Oa멹l4.}u+>'a긼c}+lWCoEY{ZP]ah(~W\ya(EӰzɥ&2 G`G4.I؋1` :~< w2CՎꎂS]Ꭼ QDc0o}@=tM}9 ([Zw +\x}xcwCo5pBr$.B􁤒T^"dtpc Q+q{iTPW{j]5WjoYv8m9VZ+,AB %W)|Dt0A˸ 4Ic&@U'G0v8&)Ї )8"LEJ~F\%?X>s-n^5VC/PS=.1p@+3+9gpqUYZ6>4`zcK5x+a C,6)V:w]4IFTҊ~Hq2X6_xq:+{\`6gqKŵ3ظw:̸ޜ3 k/2#j{jNq8m?%@g'hڲn"0΢3ҡeŃґ}隒a^k=)k=gdmB3>B=88etx-cY*duz4sha0 D4R_'6GptCX5a d깑j~73ނxO8kaЯhQXcF\iqw6{~][Ƌ1 i[m㩋e2FZUwskfIuC| ]ė"~^ob1??ߜ_u:Lk=yqx[F l #'W50{h&Vktܽ8Q7b^Fi(;U4_i !N-ѵ7G(q( @&^0a{L,ZduKW]y"I'[*ktS'sc!-)vbє&]-`Y”P %rGr@q+G4R9ڪݠ nhBU[kXEhP ێ!@WbpL# BuYl} 2U7h^f bRzG(% U<*VPo rXLN?[Y[Y~x_!N4ìl7yrKR_Y%ȇǣ~a(\C̭=Yq=7f 5Q]b$Rjҿ_{~{T[W_3A@MBn|EIgQҝQӯ\Ķc)W> (]H^Ēp2&``ØBw|ŪKrpfC {(:340tQAA , ;("MUG[dxUUTmgK8_}UG]-hE3ҭ!DUTBz•D\FZ!rJs0i,-wyÄHaȴ;uW\eiqܧյuƁ~ 6[VfؐEݯ-8x[%WM3MXj7qr#t+C*ѹ*SucƥUxkN-C=Ycq-EF}؂2˝(ĖZ3m^ sfXuA< 9yb?3: suk.GE4V@2-2$Y8m4}Კ3\7͂h5,S+)7UEIjlk $bX״$(&DJ"KΥA`R# Lc--n6,Sg4J^{RҔ,|Z2pf0uN/k" Mj:IEǵ5P$N- Ka^Mog먁sT9Zlwc#wit2QЙϯKęT(% [v@>5(y.qLڡU~֖VS̈ ؍@ ]Wh X*c  dEp-6 ߷6Po=kerva[ mP K-U PF3 Ǔ@>,|(0DtV, \Qq*- ; .ن(L:ԻBU/xAwzs/P.8u41^0s4at_ʶxl"= tDff rvٶfI[pY+y-~]4/'i̫:6WtVE!?0n 3&DY5[b!ՎRcG]]޺@ =""VD|.>}]nvc(ȳX8;/zםc"І7GJr:5qkְ9E܊/T3k>ð,ǶWS@2\xc٦6'dCRrY 'tJD(0^aG3j-GE+GaԏЙ4T}ilpdGEO<jQ)иw~t`(ofX.gG0s:軬'wk؝1<#P4aEeN\qĞ{ظK-|WByU0dTqQo?8lA E+.1CB9xltxD/N0=: IܹŌrY9[/\\>zrTط)EY j>#h҅1Duũxxt%x/L7loIH8Jc2;?1Y \׫if2EYY"zSs%Z!Rn%Dc[SzGi:2/enU-^8Ws儑ؔ]AY}22 w|Кt?&ھ%fJf(]GgURVibU=Kͫzn^U( [3mQyaӂ܏zmﻵ[ hWk1 %X hzxj?1|˽]O]Ij"#avTM(Rx3.~;;+{Zœ;J,)bG/W?r@Qp.s1>sl8.Gw4.s|@h縧E'S$Dz\OX?-t=EΪl' {ukNc^WxͼLA^Z/ece߲j7P\;ա$`m nD _NP#|&iVgU ^1 w-h$"cdAW˪LklSs};,%ȕW'jzVW3:$U0, 3;#&] f ga.r^G|5[|7vǝTM±v#"F>&~Z4J辖ui կ\#揧/XGO9r"9}gNgK^ڙA*j;[ϏP#Y9ř.?my 3_΢:}doG=vU.3 l*؈ck0?՘XO *hi+ 'SENap @Z V~u+#Ԕ5lIS<+8KB/l^e9AM PVcl. Ja d '8=1EO /]U"Q_$栘rh ut[ gSdMph^]M/[A ']" "\[:ZÛL O-HzyG;7oj+=@rɋquz#1yaTCyIk&Ԗ+֢u*QVA qxzb a9cșcHvkJG'J%5ǥ^AD@׺侜*'ƹTD`@-rumNJ!\TJ*B%s[vইwE4Gs^|P;^;sZ~6E> cTLLݘ5ɶbF@>BhYi#2k60K0Bu-wkb"7{fߍ$yC/ϱ)}:DyB7`WQEuGvDa?$QA󸃈(֒6>$Q$O6; :.:%Prl7~ 2P>ԃX->`ph = qI?d ܋|z/mc]׸аvMiE9Og:|63so83ܙp&);:{0C;:9'csbWؒэѫno.Uȴ~3+Hjaְt48+wv`E36;o#n==Vl!0]JQճ#R sCՏNwyaҐktq: Y u. . vmzqK̾/1/O62&d`n]_evnDpt~lUrgz%<> cLYTn ճC؎%zlk$X= 4-#U-31_$f Af4kP6yȋfcO(,9EV9JͤʅF>3Lc9YASw$-*S?(_t<5aCo(7F_~]p{_]D-EUt<6K.փ`ǾvR$tǮtѨQM K ¨% [,h4}6mR xܹTCJ$nV(i@`H:7}rt-g9?@oV)(>za ‹B-B2N'· Ylp4SYD RMXQZ"8 uHBq$i~9YM&b#pSy[h&{n"}G31&Fw:]sĶQ}4nXnNN5GSeS4zSrzkdEZ8tr\L)?q͐ifw`΢3jdf;X ƾew̫,L][xSôLt9-i$$1)%l D(Gdƶ4f\ ΀F[O{A٨E=Wr=7gdb5;U +Y[Iȉ+ hg8?zAd1`b8fײ `֒Fqf_SGwOϥp$x7h:NUF-ŌZP7qEм :1̓aY:Мiީ#JQZ!Ǘn]Z =ΈNJ 0|]L,5&p**㐐6 HFr4k,830Yl}'QB|y.yvz]& xʞ #/~V ӄ%fQ:_?X?; #̋O7)*`O63@2^r\1ig[Mؼlk!zz%bSȧn.*1^&ēX  2Pc9n5%<^wVT'q|P)8K+֮*Q4IyzG ѫQ]fIB]ഓqk?ͫxю8FJT bEPQxR+U"6w%4hcCҶiNR`` ɕ%}"d<- lʴC|-#}3kG֌zzoË T`YX&;| ?|ǒLp%ԋKˑ>[ǘ?#2RWi;7Oh [} x1; 奩Nn%dyCQRHb x NWaBnjdZdC+K`v_lay(85b3v @껑g+!dHlZ%9bʨE(-0':ȩ*O/Mʐ+e@]F/5B:0Sz(x߾-֛ o-6bcMj^Egwh c<ڝ(/ ;-&$3ѹ{3'7 \ \ *duh2UT&9_oKLQawQhgynk:F ixy9zAUrBϔ*; DaDVFiJSAgsXZ5%/wwCF@!\e6Iƽ}9NMNCQ6`+fȎH*R [!{ǻ 9!|H!sJSFcQ/q͈4&C""CfXXjuO&uT<)a8[ŏrs?wzxTWDMD&Hih71,vzA DMnY9צ3*&~@1z@I*MeKKajS2 Z;hz]ц,o08XdQmJuKzaФ9RhT:/~^cG夷NnK?^i&ꈟ 9ԔM=a9# E7v]*I#r zRHnfu2Kn 31w~2L-DM"˟zM~1#~E.A:1§ IPO"ާOx>kG͸vw>[?l Iy\ڕ," |3 g8@ / b8=%v(gLd=hXSᡋAt^?ah $rn>'fXlW|Z௰>-V(ݭ}wƫ ;0Lgnxz >pC,!]EW/gO~gON[8ËهwOnv2t"c2C@8J@E5VF&ZLlMdس+ )5d41m{n@df:WaƱJy"ԑW҇EJViv<2 &!8$'0t 2C\U=#t`a.EAMk&%thZY֚ {(h@F,iZV^B_"KV@ʅxw‘?KkcaB>P{_M:cٴӄq;@5`Z#y?I"g< ^R!D׆-Yv v?SߡɞR2{#fһ Mf,C8:S2L^e+|≃]sB< -n{w@zBfrbUDR. xx3L*ˋ΃%Jd gz}xx~ٶTwx:ύ!Oz0C_LHYv*%+ N6N:IJP@s HJMIjހH[Ur'Df;Y^ak "l7D/`6:Վ\ a;nO6/\>Rpe?$ߖ O•?<~owJ(~C<,S y򜔙'~-i2)U^tC1NI3(r$.%a4s̻Om>! Іɥ !w:3><>"@ r@z}+Q:$5Z!S#o橲XlK-gauH28y֋Eą#GW6#nO DgoyrG'LL%JaG(9}|Ȟ @ $mN&Ս̋W_LK:g[Nա\_T%i~Va "@FiD$#ڬ&cLGJtqd9{#Ӥ֧a\=kJ:f9$x|(!bw#c* J[81cskiɷ@};v NjBք|is:+=hD˔i韎W6.:dk&uVvvqh)gf(ױ,[.ɽT" blD%ǁ.Dh㭍֋cj{g-N F#>SAy8 ~u+ШܺӔilr$)8z>BE\t]>pMl_(n"~ԣe51hGPQ+iҴ[wA-qى7:Wng2tpe8s,]FɳѢGQ(p+|6GPTX^oϷaEW#ʯ H95⋨E. ^ԩF0K߭_3CUD99!aYe(y =F")DwU@;LVɀc>u,LWd ܬzqRFDE8=nξkC]jdT{ޘ99fn"3e aa #h2 haSXރ=)(KУ[z: =8j&QHvyg%3cL €*0@Q{cIϻjQy)dmXv[ɉ\(%leˌw6^@Z '?l?xu. ByK*;p$4dZuuOf$6KQ : vrxNbNMBA@Iĺ=T`L PŎ&8eKc9:FhG ^126RvnE'eDAS4EuMzؽlj6+A%{끳qvA!N2d*:=P?0P"VzȕO1bF3hߕjtxRT 髣r>P#=KH vsYى m圂=O'L|8;N^?*R}`#~ޏpzTچղ+>hq|mZts%f_jmmbfK>.{|=κs'U-ea\Y7k#&ʄ,*wcs\4ոS1[66{ÜyNV_-c*vZ"ƙW'xQTR0Lp1.9YdH J7(L]L (d1ETi횕VmU~+gVgQ!P-ZŤiߞѬkI*jࡩ~=K09.4u VwL斮l[DEWmC?vH)Acc)UJvљ+[p4`,~jEړI42'P~2DžN舘AEh3O;|qy@-otv^ȼ`X9GHJ Xz85hf^:tM!9<_Iƭ!iU]@.o#S%g=VWuQ,i-Yک2( HJtX61JNuȂQ N2JFAGjD np1Bmݒ]"qp's{X.;X*`L7x9X߅=ߊQ3Ŋp(tŐʦ< "=}ӠTW7:x-t)/zpa1 g_)$>HfZ#52/^wGYʥ}LsHɸffOo?lt+:j=,wY60}qC*=xJ%Md,4(RMl Y+Z<я |0/;CU]K*hѧ>P\ yJdêU|ςLπ jVUΔ,%GʙAo˭Iک3j 6!/Hʮꇜ7Z\*  f-҈W\l/˸輅!2ܷwxb7gU(nG"D g@C1Dg_,8k|Fq&.% *xF:ظ9Hldo7t}[ uc];p1T_6gMzXin:A_ d (#&r ~!(,Y?8@&:RU x]|9dܭ a (9YIĦ7=`|kY)) +:+~R,q@ rQdv(-pR$߷ةMq>9*X"sK!$ Z&9ѣl{ -w&-Ѱ~U$ZSmMm 3cTyM#!yc6}t50ӫƛݗ,pڼԊR #H ƻt<*"M1"Fo*rVXʯt;x(,d?6$CΨsiXbr;@*!TJv:' T!8ƨ}Zo;kjc4ABw0ǕR՟կH(&rƑmũw Z{rJPn`qjNnh,<,XxZݮK7,l 4l,w 9PM5rYTYFR?66,9JJPkحB4"gNNG%Q)t/E\%!Al0N!lmZbmA=Y]$ v0]844j8Q*5FuG9w$H_-zз)S|X.SDV"Eo,= la8$͒U\ZKj^s3St7U?#m;Cbh!VJDߥㄶ ,yi|JMb.hm;`|>ŋcnXKwe}hÂ1;nV6'i7dQJz$8]6QHbjFF"giQ 4єٕ-f=h9d~ Y݄'@KZ~]#ӳO!uHS ȌKd7 x 젧 @!Hǁ Gtb[)Wl˲$JeYvT-;5ї)q+S޸!\^zC0a0I5twrDjRY3xd!ȉIytZa:YL^y̮RKb))A`(`P<oZ [QW:BRΖX ~; obȹX PV}a#Aš An.ȭ$÷;1]ВzU4 '$̅A/EeH^1P*867`2;E٠GOjKb(h'!j{}8F!6'm:AK+8v+0!)EJͫ_~)sfC,frsd^nJnbWPG;tz FuaZcsD8atUPAgԦ2؊;w=.t8FיC1vR^#FT]ZZ*}ӀTB:)%Sa+Q/khЧP`ZF@f2+Б%sa$M^ ^}}E$HX xXnϨ4 Γ%aamCNh>̐& Y4EypU_tGMǁ6y.:PuEkefn+gYs`v}JEB+ *B k ^.r1"ho a}Ɓؤ kY[`#Ѹ@ ڰم=rs_z0r>gcN5ِ1ͭ-+rUE'}k4Q#-"aj:>%0ЈތȨ@రwcNfs< w~\ hG7},cj072LK7Ŗج#N6ap'Ww`'Cy,wYB>Ec/ o(r=rXKJY%mca`/xX0>sf;醽qͤ2_cOM:קν~ vB(6+̀gQ 81G`` @9$!0^xɷ fN 0V`FoEF2j_ D_pBБ 1yCё\dQ3MѶ<5/6׫YBrXo.ׇ%%c q# {-2 <lxchw${)Xs?8,C'-X!ZBި?/YVnX(从?i*=|6|MdU$cDpGR*ƀ'09!a`߾7+iqQ ~#hъa(SThU=.X<O3=},._ ,R*2b_M:U [;/ 8r:z0aDkMԃsuz#D Mڲ>ْ X=%}\#Z80)]DhU`g} J^mrQe-}]n _씊PĹB;afLuhZh|NaSx"|2P;6&'!'vhIc6P_X;8$ܒ0aH)HsR78 Ax(Z_ڇ..zjwzMY"`%Ra6$7Չ(ӳF%?=?MT!h$Ma# ىz"D[58a8K#çr\$L@-).l_mn54-8 5]6@y94ktn]XħܜdR/}ֻz~B[tS̖4h8.MHӴ |ջlK)xv@L? dvjgV8W.S5U8zN|[JttQZ*fJh,WL[ Au+łX3m..P"3g@Z? ݆z "$MMg|E+\Z{=-{i36'accwĤKBi>a=?2~l. sJ@Uoƒߕq~W Á}g+49J_.- 2%p%.SDq~[ipP;S~]XYMtr7gV?euk.-ۃL?. 'Gx61M|<6qMUpk& M"_ q{r$#LN`0=kӉ v3;y<9>I4wa @I=$ș[|O\qPt/ 0iDƌfM5:BMҗrr9Lʴug(8pc/ y>Q$hʙyQ|(,3%v5Q&@%Ftxׇ;;cW%ׇK\.>\r}p%?%Lg:7ykcȻ:_t=>λ:}]u1w]deWH{UK_w%n6j{D}DL%Ꟙ%"hƲj%%%%%%%%j6KKԯ+܃%%%%%%%%%%%```*,Q,QKKKԿ%j  )G( -wX͑I>e0Ұp\C4zܻ$a!-C 2qJf*9>m \V1d-ZS| $\g2EV'2ؑÙp̩Ӽx7X]Ȱ Ga'$M"84 ۅ/e)y6"Uf,/P{=`F:&Ș({D HMRHIX-0t9 ]qB@\ε6Z/`F-dϱQwNTBU Vu'ݝ.#E''JL3P܊;ML|?@.;֞"kNi5P973!za 윌ZA^6ۈjjD ]w g^n< y-;J{ \׀WkSb$|/ JIl\:ﶹ`pc #SU(l^o:C\ϽNv=?-h Ρ[6=\+%u6$zlnL{Q1T& +?AbNw9Ԩr&SBL[.0f+<ȣ`=$}#|[ZPr'İNJkxA'D'X`.۬pL){I皶fC'Bn;:rYG*~+ t2@iWлO|6`upYOFT 2d-k sa؁f/Nm07M24=(AZZ`xݐ^C@RB*/e_a3 p1 e8(jsDv#q0dsQ+qZW{6r'+$*)>guTGc~q\M\8Bfm8]h(m%G7* \i>Wt:SXkF:?+E`hD9h #C@!9tv91зRG% aCECphKCu4JP,^QL 0}uʍ!_pD*OĊ#&L'DR%XsYڵ9}+.;2Jh/s$&'{5{:]^za[lW℁>˙2Ϙ])}wڵ)YrŰ,hٌ!|c]K&t+V0=Br^hY23ߕ+W,2HLmfJ!-qvBZ@I$mCM߻F`TZX4 V4^F8T)7̊<"SEL*KpꝞ{*@~;ΰ!LG#(X"UxĦ/{EXZ)զq4N>vUyzU?Պ;2T$#u暊/g]|3Ue&zbb fÐ |llTenhic27p"c`Vn}u%/EK2 BR;C}/6,0<|^*BTeW6Ud*=UeDžք݋`MI|w )6 sB ?% 11%SJ,`ibR0J+Uu$Ձl^VpBsř3p|/NrJ#W) oWʘdJ撬ܐ(&H3`(~qv,>^H#ޣDH;ǢA5ޅ|h!^ZI1"ΐ%n*%QCgs7_%iyqI9%z+_7,y!QCaqQ#ds0.>l pD:!6E+1Kc#1kAsѫUiwFE">}Aʰ՝&(J_n(@cW#ug s!!N'!dx剶 }*DZI1: 3CNYz'i?v =j,h~- m&)ʂ>.`b5qVUvQf 4HvE.`^յwl 7MR==uϸ~صhbq0DzM`8CQ%RJx: b։2#cIR "TU҆DZ0gO|Z8VQu-quB]x@NJ?V喼ZWkT9A ]p% eR,p2T3m |^iw.dЕL=e䑅j맜f&6rS% Ccɜ9ًy&sܜL9V&Wr &#s49hd"W4\H ʾ)W=GVp<14Ms$nX^R?GDRR);;,G8N] ҳ7j\l9 $kv Y,|f/V*@sNV}z@Sti<%^'v>HEd)`! 8UoL {3QcV@s>ʜګSLs0'sd=*J}E]#pޕنy@Ld+v`2bo_rrdf>J9AP1ң;+55s6n:M Wc.!2s¢z,>U(ԸUGMWZ, mi!QC?0 L[x~X;hNZB2˗"8DΟcY)ɬ9Zd_W\:_.xA\HKȱf:/Ins D}:j)@Lϰckn%g@ŲPTRl9:[U܁@<79捇< \GLܡ2DiqY )LV|,9gйYD;k^Z@cu) V(t{7HOjmtD˧iufl5 *+ xHi~bn?JFQߗi7f's}gi(ɆSpm+ 30 ;?s[8 7վך6u3`k4ɇTz#'Q$tFW ^N#e5-%LW /nǦr>[g9%< :oWH(i)j"g!]QڳSX ϑdK"HcoLuƌr` /3o] T!M񘭋PޱRV**}( ,_3h5E$Ae"Y>Ģ/9p\#tcRbOh$! v7Rt"b4@c~Om//-~*^."ogK11m 6~h/>{ C@3kȀLc5w\csyYZq{PV\kXX,RNRa>"} ]H㻌jb/Ltߓs>#|Wbt#Ѱ畾sl Z~MM=ZJ4jXZ1}c,Сa[o!}"[eQw`8^8Hhpk =-GCI'O HVNbc"^}sPX֓Y)/qiy3Y(XHPnLJue$ŁJWK7l,SugxӞG#eB7FWH?,Y/dˤ!\zxm$ l5r_$%侂)WJW>DN騙exXzɮW_ n!]ݼ\4Z E`ٔahU1PV7QjJAByz?v7:#o.0STA#Ech*#+iju}ewr{`r$٨5:`AպѸ@=>!囊N= >핷z\s*N'x.~۰CzWE]F/Td.|_c>.HPّ !) #IcGugRήIQIK-cmc@h5JXTwt+-ӏfMqy._95vn)Wd*t.]& Ö 1VS>4Qj-9S9a KVQB7SF<]U]&qF_2{_ wҞR d ySVвYhiQEoO)"AW ]{Hj:j?3ܦ.Sƪu)L`QlYH4J:xJ'lAbywgplY{E5-NdV)Gww+Hlg'؊HҴx"ɣtKR-/= ̃;fPnu wX]x(Mf?@iNl:S G'2|p!5մŔrmZIV` [F|L$Ud<״Nqn_7Ph6A"1̀ܟ5 ,@7v6[w[hJ9b+aD ؟_#6{ PI%w}mAOh𧈺nWnm?%wX} W|nV~[CpÈ܋>#U~U'wUt7rpڽU+Hoנ2||&!խ,'$ p QaKT5ߩ>2I9Os'JΞE\<ݫtq8΋7)x0yУr),R>b78]iӱZ흵ۢiu*8=R60He!+u Չz%`TQ>=u$ ̓6%l\4aɔJ$ɞP}9[*|R5R]:@HöeJ_J8P J̡XH0-ԞcW1>Oߩ ;sZ_]%ƧKh]QdfaX")(v5yqec\qx`sJImLüv'\ŝt4:\4R{W>/Q^2f4\eLW1C>^F$}/W|8g:wt dn (6k8wd?}Acj0w=v])v1v$=(= QEv`!>yFvwFm٪^V+b_+ZHoh'îMe@0\EJن)6.iJ٠$TUB@3R/i0%v JbJR;4k%Ԁ-Hڈ )!y~GqZ!腒T`IoTLE}!7PԞ} 2JimglX fn3"ɯc}:F v _xxh#+AV癦|n=s+˳Yƫ)!}VO1:Pn%k>dPߘFң{1]7f9A+36qbό5_jˍ8>Hyr˽I.S.IzQcм8H56r'՗%w2/PFad3,]:t5YV%M;Er^g7 updqtI~> @./$_b2el{k+OkKiI)g}`Gu1o*J:8)\t/hRΐj'XKϙN%߱nĒSgaJDha t9GΪxCqi,}<㰳VKGuA(H˜e"Df0 ؃ku)'A@&Y@|(K;EY>*A䂆|]4lJ@ Ʌ:z˒<ڞ{sU)baxdX[;!S@;uPC I!P(\HRin }x^>0,kK%4rU1lnjUg"d_%?'A HaşgswM%78 a1 Kե,9z(vВFwVO^w "_* D @TxTݠZcp\JqTƆF=%┝M3̓|zwR `z!t .*]7ܰv@ڰ՜9 fIQ%{|v8;2hL 0.seV$m2A5 #92I7l): HUH~22s7M0`Zĩ] (dMvls{Qhl +|, G=bl%^3 7kv!G`;잴fkZMF֦M [$DSBU!~$:hp%(:YvU͛VRt}ךq*)o 2'ND!-pzZ I@莮}fe)ؔOuZh栉\hZ4$ Gp#[dX6,˺lt"C>Q [ E;Сǝ%dG "Z*L  H'c1DZМQ'iAqXuV1wDnc1⍐XhJa@ spo7 p\kO|\˫X6""d$ "1 %"1LYŏ87scQC9x",5#AUYx¼dt/<5{&L<6Nո& *츾$zF{ڏC$`xpk'߀<$_ߋo)ж7a/lF5^wx? _:SsM#nAgԀqU |ҵZMhVA Ri ]ME\`mD1ѲƍaW)eg1ƬTy*b+0v#@/`mo <|@XH2[9Xy*TzK9Ϟ(>W NmXY& (OQ 4s|4򂪵gHV,ufB86 VxB߶sFT $Ax@HNœ]`{Z&9|Gq 'Gƫdĭ-:PpUUR?'=K8W62嚱x$` FU.q,E2;0^' i=G[V;n~(n[Pв0767wvZ[(cj^zJ32m;R<.|q//z&7 H &ڻ`^l}>!OsgRRWiեYvxC)Kuq  y($,5{耸MnF]M^ϞTOaMc4 ~@L5AqK2x5Cj(*sTqzK;葽=ʈh"Lqr(@\ rEcvQ(k9ZRY:^%:Ҡ`u ;kS+eehoybRsMkNl&b1:z^ڨ~&a?B(bc}>= 0/h 9ͫ0\nX萪{C+*BTGۮ|NDT |Nks5[_jK'olF*+|n_Ղm)3탐ǥsF$gTP2U'~Χ1Pud uK;X>׌/6 "-~Z7.$;lbKӘ{׬MrGtl1ȈeOKb^<{(j :$cx#[?(;x{u(~ut0 `":`Qv AcwUUvPQ,{EkScfNIGchm qNQ/ ͏Btlc,J# R3ICXpsb2V!é1//E>hmgJ$@Y-OGwh2ښl0kwmrMDme^77qp!Y ]sS .7,^fTZк P"(>UXͩH2M;*3 0ž }ƍ"i]K#x$}y cXBѮRuZ.N6,y^%q2RQMζNrf;F63&_ӬҏLNMjx8H^Ļ$/6ftj}kss?"$\'}YwƲk,1]VoLZKqg <@) )e0g@cJsjѤV17Rc=}bLF>B. FtIlg!=Z21jGC,lŎ#G(վ(H oP <lBۆu\2Y^-o1S#v BZ eh \YX)&8 !PdAka ,Q(p$kX[du4 U @=S c$m(C5TM!)q)Nq5AEBQ][qOAð|$Z|Z[;jqܼS+V;Kf!xƹYcr+]P1#j3,dݛY]~YPӢ[XW I=0/^af7aD@O Xp\LY;<g GbE" aYe6Qf2U&^m!W+ @`GX-7|UGsSOƟg_+ȗKܙ;%F"5}6_oool<8|V1DlK5Z|!bo׷ZfXW@sLA%neSZ/w^8wZTjwbi7wr| gF-K:BsX4Do C3cJW \"S5$$%Mm{_ƉuT#qϱ43s -1 d1ƺ07TDSNL4FtX5&Q3{3@hxQ PF09njI liSMvy?MC\y(BSN&nj\I}TȷmaFT!]a)ߨ2M],1.Lۅ ȀC=!8y|,O0QtJVRɨ@iPV-, s2Kq .Nh-2_%5FZ~@[8}oXZulNt`TFB-?#plKEn Q5Y1CɪB!`qAv+s!1Q9?`֠ eWo (1G7ŏNIZ¤Ԩ B f(uħpg9FqbxLp)t9pF꿞v Чn.RQ!z6d׉ޜ(wN1WNMbJxn3u)Hf ``yF!J퇧 ^i+*>l]B@ ^14y( 9yAH!:dQ+@f :̢p Km]2-'bc:q.0dt J }c p(2zt8`Vjft4Rr,{_܂8Wd̗8$E`ɬ,-#`]y76jsGsWNYa `q9՝eHkw3݈E~3[fֽR;ProQZ:7 :BO +9U9&/]BFn]8vF-Żm_lp̔߾-Q^Gez3X-fp,ԂYК(b ^:Q^2mؑ%A ndFAZ3Bq&d}tsC8ߖ<` a5ZNQ$NfM!QQ-r~>0f"a>S~̪ Vz>溗Т]Y4 ҍ]J&<m> */<vN03JUvN=1G2P 2/<]4_YH!sJS5 tE5ci24-"›;;8Ru'GrVEH 2]%Q[|& G\z#k{r|}V/|ڛgAm]Z?+?-'uR[ST=tE9Ks/DCh40?{k"zTch zU˨ّ_u+z^9N5'b^hmF?Ve)yj[%~a 24Ӕ9/o\R1ke4rׄ\TH~䎏z$|r;EЀ*dT \E| CB_ CȠx(t8<Ϯ_iި?4aW+rw (čt̊(8'"<_ 򬳠{C31íRqRd6Ai`0/&ubfsoT)HQB)†FR07+ xEM>l?])FߐrJ_^J2 dzeB77hLM+JRpJA@lBr6!'|y8ZشLACԤa*pggMyJYĎI pS?\y 3eIb, w#S2* 1}H_7 kTpuftMF[$Af)Pam〬n`F^`Twz=it>$n]^ynl@D\x/L?kji̗hD@G1c>79f-\;΢:rjc=r&- 쐽Qd(k. +Ӧ{kϞfOrҞԖkˉ,2#&5VS\ u2i{bd"3z,}. }yQwW;?.G4R0Bez6[iq뮹 Đ9㟰o3S"mgK ތpdO+u`=fx;h6k'm0וGω;<+-+O>Jw+Ab*,CN6 np a\C8!ҢJvQq]ɳ' v?Uų'F-  DE ɑfl`Pofh'j E$Л dpk>LٚDgi+U4PN^!QCFN^[+pH_1O*e>*OYp=O摙oTd4 яޞqJbvol^*ma[sihazdtٴؕS@[:+h8\*Dw:N7 EZ_D?oF:fP.|3 )XZ+"z'HA}u Ha[Zr|jeҞ1g8ęc_[j $/] ~qUNDYN5Fk0@!}88 d?%c}|v{w_tH xLY!Y5 920SKqu'lף=! ywAGy}! ٽ5BoUhW5|V7=|IedIˣ%csb^/ꝵv2O}b3dI$B_L٘) KڥȀ<&+ |'"t(*O!l1Oq){nھwP! l 'N+Jmf  Hl)/fT!1Uw@.:ޅ{c x$;-C~JT(qWGN[-`$Z-DX2OG&9ĚaSzz8wXk|1y.H⾒.csxwݤ: 鎒DVb,FHG lDDc%@x$3Ggr.|x-gk%'.!$yhnwaL3Xh(e^j%w}U2VʳSV.E3x-xnfǣN"(QnALmIIR+B0^H3(r$.%a4U̻mό+XڐRzw=3DɃ4- 'ݙuALR9;V_R+&7W}F>l^$pGnY[d\?l{t;kQs/!:$~˻<:k2|}db.Q <PosZ؉/A w`ણ) bʜ׻ \ ʓ+O^@&϶CW4?v0#Z|O98mq8fjUk#2+0ЩeV : ܫK}Vr%> ShSYS1!+@I-SMP'DhRaN TҦDv8Jԣ|}Ϝ5!),:h+v f@k"SF:^Z,/w:l OH;8gӱuX*U@7;|rհֳQ4x 3JqыYkxkbXl:`Ss, ) GP1 ШܺӔilr$Yy鶃vELgA{3@ nykxoz e77:٣뫰H;"r pN AչrhnHyxjs|X# $UBUcx%X  (.L .3Qe5b |Jo퍍ݐm*ٌ>RK3KoH('3#R9"0 =sꪑrʙݪhL,fh"`= ER=#6E]REʘte@E,,hڊ-VC \A) V2eŃz8t nOo3"4h̜])ՄefHr123'(!/T&J zş'GnPx%sH9Ug6(;g3۱ΖC8J-&K)oF@DOdx %!BN 8U=o(6'd#Y`%hwZE_a}=<-0_QxѠcBv/iw܎Lkyܳti|[hCW5onʫ@0Bcv^n> H>u;HrV{aev!g7`|F7.rI%nJ ٩`,2.x~gK<{cs]@Ҋ&f>zɡ?Dj/mdO~qs >|h`zk1FED֟GowStJπnCqB;#GEk{9dR1Wy4Hu^nnn=\z9 Dҍn^mwpVcR-8J`dz܄FA~7i$?v=R~U"y٤N,I'mA~fF@JP)ΐQDu2 RҋFc DF!DZms>p^V9m v[\U ,b)d`qhE0`EKLvHRHǼcjrΩ]ѹa(`a8 8zg'7zpBnh_K,Xs݆DJ,C<a_Zlhm62)! T acũsn_?VDAto#MǬ%OYR"k /;մaAϼvSHKnp<|W -}Z;+ѐ;NhYiGJ $uHDZ:S#{*Ѧ\67PL%]Z~݈p;BҲS !F@x0-~F]?덍Cʯ/ַw^lMeJ[mńdK˭}(bu&wߩմ(]S ȣN xMD?s"dy4]9YY;I5+"(k5 F5Yg7ty<* `p+b*ѢZw$V9"]xeڝBZXx͸Ad`7ŚC1I7ZmZ+ȿɄWۻ{胷!ۡX)$༶ri˘6Y*qyM{aFNEUh'[I}c0׏>jo>mq(r6q ah(??:1 ZwD#  O ZYʢuaEh6 A h!6fD rE`+s몠a U4 bRf\F`5]ج'Y 7= !Hх&g}i WVmY説[* o Qw7p(y݉c"/~@ C&玎^ezOm;tnl_4=rI1_ d{gٽx74m0;*og 3 ٸ"c8ߟ qO5eeF ufOz|,/>M5e3S1h÷h;O`ju5-(h*OU>k?ʬʯߨqw?HƝhS7ϫ=IdgO9j͜tzG@GFO*T:mn ɜoa%BJZwМ]7{/_?>cyPC4rY4!O"\@=tнp{7OCp {ȷBLTd#+$0TC t\uЈ&rȉU:%6SH ԅ-͚ mC]lE22cj£ŜYVa^oNW'0Mz9ءM\a (S'$3]{wl23ZeV*sS*襪 dUHwNʡ 4"ީw^p -t#ܖ(w0 7Ya)`O}Z,3/wFPeװj("(!LPl:[gp6wU~,"6U-X2(XdpB8 @ CZ_6gMƫjnhD-(M>e6`T yzب؄ɖ@JB:~pWR6xW)+F25ܭ aM=P)1񈢚 >I}'5腈QYH™ %噡=BAdv q3>#C~|cZZl'/N'V`蓣v¶5ѷ"apΈ/0mh8*;n0Ɇ@@,dDxDp-Aeg&g %PHp sҢ?T*($Oe( .ÐSǍ hq uTzT]g̜<` rd@ޣ]D{ʉUj` l*Xaܞ&0Kzvѵ7B* BO|pa})^jt+pp!Cyy# @RQ\?و50v;VJQpUbIsPf0v0|#8 HC52,Xj%Tg, @2&LZ] e0תF|\ڠC~X88%BxdeDH;\*o@pEu.bơW!8ؕh$`Tu/+b' p6΄6  3EQa5[+UsS|F هMUm,FwO-c(vhZ)o.Wz'?-6ˍb\N.&HEom _`hנwy5#od7 ݗrXhzjtwv$#1)C_Z/,<\#V+yWzO6Pà3-db#OT0N$JkBg=ɚe1@wP js6B:KXt8=X#EF0: B71~qf"NG_T œK.gk9A [vo0#|L5aY@>ԛZ)Շ*I4=s~cdmv Fǣq$ ~6fyS+8c}EO:a9rU  o蔋u7M~WWPu)87+7*(31Zȡu.N܌%"'`e.oZ%RS]A'&`άhЖ5<= ;6mjl*5&  ƙ$HU<FqV;Lqf{E"+Dt w}ns5%Z0`#Q*~䧛RDuS~N zFAn.Urqo5m2]+m8trM0#ۼ_#"=}:Q ˼"7`o_7kZ} k^.N %욗ea7ePVjbwhDŽ>N ǫ1CX-/E9 2Vb:H.FFy9V!GhGaT/̀DQvC}0N᭬V  YwTsKHDͭS^n4S&u EgQE&^]Q^#@kf=`o}. Q lﺖH;a[L 76;2[be::w|~ߝW@>l1- n:$v̩D!+DD1V5璉UB0&3(u4Sd uƾH2/E>j/Sk~0D V$}sZbTa 76wFmU0ZB6㜎y7"gAw D5 ktmph I>sjFUDDžNF9fhE5㟘Ob{my䧼R0,~@GaP8 hKy~$ix_>2,  NP!{9OV@Y*͍WUb`>@;ÞZ{|`UuSA9ApYT0H H9>:|æn*,<~M6~ktMr]5bIWHX<9>*8{ +ֱzb8en<RD_y6S9Ȫ Ի@8jiBWuW8NuD*d*7+mL-|lX{>βuVIFFQ{ڕj@,d3˅9Ud%I2_m3覝9<ʤt5T;1TRA%@I@@ +!YOx|o)s>/ȊF^XA)?t8,YTsa'<%hԗ%Qaa "KOy!LW*37 { MB?Jabu5Y~,6e'hruk^d饏,/+& ۀ}A::i'K\&oS7!bhգCOJq7Hko1KL N`d 0B0{ӑ:Chҡ"ifſVb@;RH*+IW*T\HfNUiρ}Y3@77B*WjW)/ ua5*ejV`p[ cy- {}Qo > ^5>8y&`4{#gc5x8kh Iuw!7eO.;iS]ifU  @X\gu˜ 37J:n@Tku groq1ޚ ]>kۃlV)D6hBSc'IoJWe||U/`$2挴zM;Φ*-K4D%P@(VJv}uR,Qe~\[,-igl苞FtU@ 3g˛`}{;,Roq۵۷m}{Vfmpc6'8Oѷ: 8.`RiQ⟲Oƒ6: 3gSQiUpd+ ɲuģduH q۪1X+QߖvhD&Q*f" CNaB+fBctGt |H6R 'lj3uk2EA m-h[*DHQNv6['qT9l{|fO,ՖW)/v}/w_ 䮀}9ڶT2a RaXa Jr K!<;ۻJ@(<<4r$ԾDY(xx} B+`G` Vo'+Q/n/Z  eW xvCr8\\r[9 Pqe ? WkƯ"n  B[DttEL*16b6$K,4OK|c$|"=ܘq`A#B#Hk=zcL[xͷLCy4(tI3i]U8Z'."~2IQʃB5i;{Bq|uX==wzCS`02 _Hrf[%q <:|#CꆸQwh߰F.Tl!?yHɌGW!ux]X L'CU]tQ/ $<`HޮmY?zcj}bJhh0F`P4r2\Q.̧oQ 3,]P`]'|~Yjq{׹G[\?p^Eo?"23=d ]hXk]켅ǎ7E$ٴIw҉%aʥt9q"uA˶K1~Ӯ*,]5Չ #nxZŻ=hט7P CeYWCݾ:~\oVA+2pn]AXtipxiY*C )TxZ$J7W[*h&_wؐؖQzx'NK7rypMǴC#uE3hXÜ?#= ~? rr͜I6d9rNT7KrJDD o ydn%|D$lb%JQ+J‰B0У~R_dlT z+w,JP;1-njdVDdOaF}*X.% yxK7Q&t<[ $pWoX[R\~RL#"F;7MFn4@l@@z j/t 2StMo7BD@@6]&'ƾE~vZdx z{@D\DgGY3KeI#}-xLA%Yu΅ Q}3>b-d; }m@rLX*mvt: QyۢK&(uFPI K7Û xC<+[e4eNnmu˜,3yoo%oEng}e}5KX>jpAqZg "OC3" =2^( *m60+; 06ݝJQ gB2gdׯbI38Þ{Ȩ}':؎ ;%`}wg Sf>3PMLA h0xEN&p `76L@M!Ƭ!C&6˙D} ik ݡ k;N7M*=UBCA }>m2ϲNK:⢔Y, z4g\OZBG 8T L^KImޥH~ a\~i :'K(X*IeҎERgyWckB$lmnLEޏ,|<ۋfI ij'L{=8eR|<(Dolhq}`lXgߋUІA.HN}'ޗg8Te:װm$-<^v*J |wN{WtP+<=Жr 5sj`v2oR.t<6UK:hwpnY&؇xjs/ΕſͤߤK65m&B [`99de38癀Y#$>̈́@f9dYhə"/3u,ƙs,Hfrfq&o2\ac`rn1dQF#y&Y-ޖFT͠% >m6arI5gW+HdM|eX̆ɳP1g w8gpt`ɳË06 k%wYābGM!@N[TMSQ:׭'9ѧu$7>`Am;ηbJgQOEKT,8`@YrI䙍Vjq+c Yb5P;|lX5UV^Vmg%A7a/0(_kǶ%} {Tx5ŀ119KD"e4io\K.NxgC R[BoAB=ΑqʯRsbyYǼ}>ũ?&Ib| r@ʑa_Qfc|k~q cZyJL2eX;黮utz\R,_5$54FXD`L5>9@jRj&ZXtst ;pL:ŶLYUBc ^`WKACF)ҿUeYc{ʙrJ5 Qy%IZHqT1Z/$rƴYe5dh!PFo,"#P$%zu6q)mY1'"Fi9SYsH~3[fabj½ xj?p!KјɃ3'٧;+_0c90EF*g/TM*Kԛ zVrDڵdxE*Eޏ ]?Q$=Ic1Rbmsc 焦CH8C%z#ڮB6x&Y:"я9ޮ dvw[^=o~~xġ7lKEQ$0HO|jh.3:xi#ƥ"@ѿ{A-kP2p3N3}ff[SعUN8#lX "ʫuya1Iv([~#@}F1 v> Y}"TU^]AxQiAe:.u`Ns$3 Dz&]EnGPSO>X%Zi䵕)P3}@;;4W3G?)]P荜^0:~n; vjbzkO]U+(D vgl8u87bŸ @!5@:u}QGC\{\S. c5y?"IHh,Ž}ՑB-39p4s_0m8oB g:68GN:j'7VTck=#ΥmcFlHaڏA;1*b&vGM9 !V < R (pQ@}pS1 Pb %F"MyЁZǛaK8uD _bP4 *r75OH]2:EWjt0Bk%t}cz\8Q'iNp F|&n r6@JbIWeą^.e"姅(-{锱 ZAdaԷb? QCkٞpXXsT>0G&Um+HN֍lp39V:iA^F$Faȑ+@(cپt^.-Z2 9Y\^!r"R3m5*{aGͥ姥|o gH*iI@&58$~w~AQxKE"Ùs߱s^ #n;J# l}9Xިmd*r^T ~[Y [/wa/Pn)MG5MhR.~JoNfؒ(4{A#fOuk-WDPEżU;YxE^ZIB̌P[M;ۯbv5j|X%GӌM3U] cٞwh= *(}MyQRq}g'r_&N=ɕjt7@E= ׁ%f,1s ي< dNEc8an-3@K$ZQ7eq@kbJ(ro X SP:Z"rKBP_?|kQo٭wzaX8onz +0 ?Au*{(襰:Bq͛f1^ofc|W?Z׹v \B6XUJ-rƷhe,p}ʭ1 )&RAwu$Y菺@(YOFw?ƠP@vQò8lA !Fxլ*@?c V(_I;N "("Z"*Ӡ贾v]Y5Ņo+k?*QYŖ6[Jw֤aXQ!D/j/;\AeaY <2`ՏTJGMT c~}GcALn"B- bjaK`nڷ: 1qުu(0<i4V >"c!gb y )!tfxXĄ対>q^qWv޷Hev5-ŮaY R"`#ܐ O~wuWܬUӖ!Lݑ2$*!| |m{=$Q1—J@례IL'Yఓ B %c\Qǿ8[Pb=k&w1i͉wzj_H!Y]J/jS*qHS%_]$M]FQb^$ͥ ڃo?ź4ϓ@&PJx!J4y9bxy^}|hCn9JXJG=HӅgb2"؉T\{T'U{P 2X})$YF*Ub A=l{H~]#JFNtkǬi8W˔ug&;ca>pcfZ=hTWQNW/pfQ rWka W E#! d{AM919rv]7ۘ=jHF`8 *'4ѓw<݆C 5y2Us2 M9 bȖe6\] ,q;g_;5y+ꌌEq Bќ\]fё'HL]̄O9ZN X,]DQu8by3 f ˘(g7ܳNFz  DRA=2'Li. Yq>~dԜZKX< D񆨬QGm X᧳*Kb$ Ҍ1bEqRT97c03O߾_6ӧӪ|OgI)Jj7"I!ojk6bڗ>"Э?hk:p^UbjdJgg|vĕB>14!l9a#+c/HV6'z%b;O\JJM6s $GM|Rq!~BU[΀iZg17/Z]5T0LcIj@4+HEEFy\L>Ua"P)4 }lsw t[/K >Q^i M2DL_kn(Y(97ܬ7Fs2gMPa,-N}JI o'Lj^\ZB#!.V`^V F]tI7Q*OHdPOl32:">}.̋uajK V15!K6/],`[]T>mDK2קeg _jGQ6C6pbY𲣾%.x;(䞺 ^͈K6V"KQYXq}ϑ@).4;iY#.Yc<<2H$^Ԕu"J/Fo^;EQySkXfdˎH\񂉦I/pu25AJ%wAIO:M[Vc#տ6Z|ЭcZ5׹n 'n+T-z6]g dRfھW06aW[$A`ǜKqcmJFDp[X& ѨRndb]n+ C|뗞ƫezXR޴(و)qXt hhOf?N[nEN|T稕&ILݗhZhPEury\@^Yur_"_~WOߝ<֐N*YwE>D]Q?rN+LDp#wg%MJCd4j\*bZ#' O>Fe2җur!'6-&#|"Yy $ ,Z>6Q"KCe,i4Q:c<9y+zu<r(v Ѫ Eb}3 ʾ } A# d#Dp3!6@Ҫ4JH{[0.NK55IZW qġ /Q1 a>kEldyDMDQHL~V 'AotOK&dKXL.E 3ӣw*bOh{&MGv׼οnr` yNΔw@N#π"mnT0-KK`9"di5^SDbA='nGls,$7hjd˂LKeWti@P5; ~T|mh6Ztt0^j{Y '@ 'gP^皎=e:gYڵ>b*z. q_7NOf25U2 SG] 8-wG= lHwIs!!OKT:@~g/Pbѿq^ln{b]moY?#b z1:NhoiC$6v;mXQ]%cRD#hݗmSkѰNr>=yW`Tz g^<w|pvoob2t2ك=6>m/.@`=Ru1Rׇ뵂RWF+Μ6orP Ly䅒ABt~~^5C 'x[Ҳ1Psث;Us%b]҅)+d8vTT/"8ś3#ѺxK v'#r kLN+|wMRrd823hfwReV(TʍV}=i\^[=!<"q֞`ҧ]5ZAݰveyRyu%`%<+ r>dQIUK@nTq&`. s11  Iܽv\biuA 4!,')Q4BмN0e8HI[^hB#:!4Pۃ5 N-5Dއw\^Wԅe\>9DcyY<t؂ސ00 lxo&1u <tZl=7Ec x_٘<,,ʣ-=bD ˲-Rn,*YLڅq|z0v^2h(ի/v5w.l( 7#Pa=#$RhO\K߈*gIY(X= x O$/|j)GQ[QXĮRc6F:>m/O U78 DIve.Lg](<qb 9且/(p9)6X)\pF+@h^q \PV-JZ㑌gU.#{1N|ot|REh0$a 4w/zj,W~e`xn" 4e-#Ũ(eTkB=弤ZZ~gn[/p0CpWѯԫĊ]y;AcERwJ|5@4;pj곊5,Gt nF-:˚XpT*&,Se]Q1~m) b)ȁ lzgn@I34 `C[%[qWE"ܘMj(_/;BA~> ;ckU|29/EVkŪVӐ^ʝU K^+aO'lk!|xD[$.-@\F?[겺7($ ;n71⍛ګRםm$ft$W6>Mm|tE`+"]!%HI3'{mhF7 Е#npkqL4qAbjunyX̗69H^qҽoy1;lmx'.zMq=-J*ϱfU(>Q.Uu0HN,.iǶ>yaz!Cz Q?uo:d&80G2'r`bڧ¡Oʌ+@i2KwRdQXX^7bX⪜Q@ 9[ۓQjR7 D&nq}1գTDϋ:>'?<x8@'2㛑X9>kb>:1XuqNC=>8ѨAWnK=.o{1j څX4Y۶~3 fZgc$+[I|> . u<`Y>.Oma''e0 ,R-BM㽞n=8xAEsژKb ek>x=-{0QB. D`?Sv#kh 9|ꆦ 1!b{x8YW@E^x]ƿ.stLqUE~bb\1c]=샴!a\sv^Z>R!EĦM5<.{tr;''8p b0 G#vZ=9٭V` \]7?՘GS3RJ2M~(h|R,1 J+AR'Ν4dZoq&A)ɬLj#Rbi+x&ȓѝ%s](hM`lieKTL2cKHY/9N&D!}< ]۞d́.^ 4:BA;q挠j:P\ .>4 +PO 9lL914M4-(AniL ,vt:Muð.(oY >P8Rh \k{ }ًx:՗h j[w|͋ L8_`kƋ.!|ʃ#ߗ5F.ayq(HnvŗuqEhFAqR@EA茏w?-]K$}4Y /:Vo6 ߷~J<^(w*:!R_8Pm|,Oj XKO9O9ʚMo:1 N/Z2T8W#QWWښ/X \HAaC<(W7}PEEXJclR TʀsMxҎozD8DX0kϪ)41k3N#~'ڦ^uQhSeyKLoe[B?#"95>_ @iĊ(Rj^ TZhYx|K|z Ikb,!mJJRhYnoWt۵mٿV Hl76Vղ:A kWfIزjA8Ry ^ s!fCt 6(-KK|-|\C?D>}[)ŽNmǁ(_7_sp^S@/Ω-m7m]~$.o 2^4Od5ܟ9}o~2pU~Rua 1uQhqXИZ+S)+]\bӼb+I|>KYmYΞm[L6.U{o-2Yg̛Ƌ$lca>XLpC\ffxLeg|18MIy}̺ŘlB>_ܦ.v3ѐیL*ۈTќ8]r1XNY9V3M\gXwlj;N9xbu>9dgWǁ}F*+gUI\ vR~d;$z3eB@.הz}v&/#a0|!ܸ5q$ʅT\ /ץy֣`."0^uOxIqQ"Te*@~z u <$DvSbZ\dwP>Ts($:쭐f,!ŸG=&νAU]Xp@pWcW ch'8TIhf(ЪPAM%aFUM K6ކI F3|VeA ](kś:J&䨁xw1E=m[0#TO&*D^ }0{dx ^qbh{T|ѯքOqPyiiurRNRq!86yp\@ _Z~GC17V,j Mzԃ!^R8 Fm"zC8Fe̙Fl^zykYJCs꘸SLp~LyF%͉qrӝY_0"f%S~ QVY)3`f x_ +?Tnz?laQ?m葇>}osn>Ļϻ?0~H%S&Z߹1+k:%׷g}]X+IHƚvؼO+`sm/}Uꄐ/?KU[qu$ -еζt4Dq}{`EudѪ("|Ѕ^W :Վ}gTʃkowHI*5HRd9Q#oacr;N8RCA`ސX^׼3>9=u;|zG3󣽝#݊sz|tviϝ YYtF)^q|bq~N̊p`ygDD+B,ͻævv{AUyW;`,cqF[;?T iu y~^?ФZ>2Ý@o힟R2pģ{ϪV=u/,=8xתPhi~|^G UOOOkޫ߀A@9`7OGuWUx*KA`| Sϴ<Y=ڭWq~ۯUנk$.sωk@d{iyM@*jBDHb1 x#]Y"%fYaig&cc{sEA90xxǺ }mvߣ oT<7xW@дS#ܫ]}#+Шzmķ'>6\\lf-w_AYvW=K+1>2Nw%d#Q oOdLwwwg;/g.,ެ'{5x473f< dNyO>b]Orڍ3&6xdt'r`uamB5]L|ߣ0*hGIOT\s>qE̎֨#i}ΦM^I 冒TS w(&-j)d^&ñNkq _zUr|dީ9ybvZLfXQhnk 9sm+N%K^mHuB OB Q^gnݷwEܻlɭ:CXF;УB!2`pv'[sP@ Lp.a&f(Ƥܻ5W_UwY}_os* E̒.Ok`w$0G_TjTtp Ά'Tm\O\F0x|_c'G+Oi\T ߣO@E9{ՃixAs.kksWXہ9wˣtz~tq |6&\叻pBMpjW%"{-I}Z{;t7@%Iה.,ׯ3ڤבCcWuij?,|?<n?z#?eZ'a" EhmUAB/Bٲ 5T9jh]ZGc- ƢXO݊s%ճ`uyا/LϺIg'gh߽ 8[z7A+"wt@$!!9f8 ! p4{narah+lEW^m?[%G?WnRI??y4'K`أ-mT*,JwT:tTAFqQi#̓dEy+fST&)HDT "+ Ǝ*&*CF ⨡)#f-.M)E &JG"PuX6IHzWiֳV>cSurOK؃Yw<aTƻ@2`ST(79(}IU8ȶp,;Pjv$*C9J zU"I&(Xn!؏aX4ӎS$$DYڢһW^; xoY/e,zuuʃ Q!.my3C0B09LblXOH6/vFJcKl}uL_p9W/)~Z ժ&T0;UCw<6t=Ã|f֏󇧍ǍV'yC&ݻ+8;r[^7oxꌢixa~\k8&bZ> }Nj@rH[Z"HfP o^3ã] z 'ʖSoxdB>}|"~NǮe ^Mu-LJX:.d|z! |?Tyrk2 .Pčxqx-ɑ{t<-/Ɵ>/[`rm̪\=~\z){ϊj`̤͇OR'g".'{CZ\ҽ#Hubt:S͹@dW`V8Ӊ.g~\S gPT2e t鉥\7|\bD=y%)xYjSzxSڲW3~Dg B{}.6ӡfA} ܲGAt st9 u>?mK# 6n&MW.n%wf,'V3l$d,ʎ q65e v~ M5A3B :9 ^% ^c@o|JHH⫌byEsPȑ^O 6  :Kw`*4(Nnh u*HEX0^*ư< :bmd:1GeIesh(Y;@=2hmL:,2(uv/Uʓ$5MZ`µՓ Z7(9uu\E'ԙ=F "se+=ԮXvE%~OuFe'F72C?^9beG' A]H7Y%FfDckgҕk\vg2J4;vWxĹv>CѱxB#$2$!x"'"gŢߏ%yuEC8"J>|'|!3 z\(cR<CZ8bص\lcGt"*^  i!4ɬn6O b^2I2UpM"aÊLvAў}~Yr д;Kɣwݍ\ B1-$#@lP3YS(a*R}5(%.أpWӼZ/rTI0)d2Bn‡vKSh=Ŝpr24຃|y ΜLB)y-:.cџLL%,γFYA=$yz*юeIbiL&L% [6 CÌniB8*[0jfPiAh#'-V jBth8â3rqg^xS@,Ԕh&1ߧzgw&zg6]"Ydu3w 1jӾ0)ml/G|I\\;#( 'ᛘ0Ma K @ 2 x"Q&76QFɫ-/J㶗چ7<jB7~%FFoN(<^ws=QK/_ RjִQ}@ ?yg-o~.'?ޒa+/~ +?lx](Rt;ZOKT'7^9w_W00R]%QpA9laRC̀[a^{U?;Rٻjh((oo "O.h%'4,>qw_}yhh I7JϖzMhe U@ώW៵% j T>$+UND Ŀ[(c;O26X52/WRWquIw\ǷzՇCa>7u6xZO{oY _(e~t)]6:1 )/ߧn }HO迏O5σTrvǁvOf D!Jph6yЧEbWr4ClAEa8(NQiyy'jxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`eb]o{I1cSq%6$i_H.2 KQz {wiy^,*0٫z ½L\[k4ezt%b%ݚWnx#R$˶P3ȕ,s|I^ {0˭Ow2Ua>ΌQT 3_ѭW@C y*k|~^İ{~<\\^1_}} hB&FW"YD&~+KVtOCEI|c`J{|x|[俆^#Ty1A?ŒPސ832oabOg|-L5#{Ğx7-R5{ΞNJgO8RksWR=LoYrś tIη"8);^!/5z9qLoхēPHg{+3%`]r:bR Ҍn-Gwu N}kE; T#x!FW$TֺV)7ÀE>dC)O֗.{Mn?$NjpMT:O90Sn[gGjr{<[DR-vO ̇FЧUbPÞ Rn˔.Sc iFmgDH1}xl3 0}_ Q cl go?\zx'{G1t7@R!?C7qvɯL 65jMJԾɑVWKkSJOG`h-:7t)3 QL ?j7 ~RG:e 7 U_E]t/]7S>xw:#}$mAi#>|(Gf55@Fr7l0 ;. x&l/ ^^wQJMIf,kOKZ߫TGUtЊpQLwepɧPW8xSLi zYR,u߉5.J;Y%AEb/!g= >0+oQ+%// JWrg&I}V}菎lw׼Bܗ薢U_K>{&S)/op[gMX^YT.IKh^vrK[q]G׉f ڋbaQCc#jhe~ȥ,K@"=9GWcۀM{y^c{13o fi];zJ̇#"Gc\䩶f:MSvJ}O3tfNe7d?xgoۦ&W@aeG{Tw |fd舸…$1!0.Z7{Fh2| ׺cQd6p5 _J: Tã}:b#V\7-[ zXeFmT3JȢ>-ڷ %W[OӬ%ɓm/9l8K "4J)o N<(!!zٜy d]TR0:䀍XKvT)rc\m] McUVkbE~dؼԨ -MczkZlpBjBKDRtqI?oM7t!}m)m16lV9߻'&}1GrVYKmJCXKϴ=ޗ=GK{%!g۞x/֠Eֲf 3mɍUCbxmW| X0'3r[3# n\iIp8Xl<'<(,f8RZ4:VNoZ@v/kn8hA9 3Xg<\xd3At t&ƹ0@y.L`3ͥ"ǭi &XfH-ByF, 3_ucMGK%!gڞ8pҞ=֒F{3l-8k)%Vky<:Kt@.mZEI1n|փ=l>ү5ggteiE8K gbRth2tEMasv5?k gΐ*:J<x{J5 #-C})('/>jY)&k)53jA g1y &hб :֠ix}9sQ$ lEAދ,EZ^i?HFH%|  #fx Iy*eCLeW sp0ģev;$('1׏Z˙M{#2$[bu-H{WhV1$`rb|D'esdNR('`7q 3SG%CEe-sG7j^݃=ɡ/#{=zK_]lyuI~4MVdB}q"kȢ@֎OwE.TPq*Y6n( ԍoڇTK&m,B0!u>ZgC%mǛ3[EhLH=60G@z9^^J: g\剛 JX  h/2OǙY򗊃MajC) &9,?d5. KäΜ0ztcsB =d'p=0R>;a!Ǧe7B{yM!hv8vP᱃v8x2'= 4q(gZ-bv]6L si"@sH24þh166 M2U/ Åa0 0\ ?0m=qyw%qFÒ#QI\$.H~xZ::=~^aU[e &uϬ-f֍J]5(6  V}#Fđ]ǁ3E-PqG°dٻ)!c'2BD~KդWAæH7q|bлZ™VK[)SɌԦ>Ule9]ߔ+*m)*`4n^%.Uv^bqeTO zBlyU{|M>j3Yыc]}}vCN/_v^V˫B:M)R@W} y5e[<^<ʘXk\uæ7w}<[h=n 4\ϼOL9}kf]K/o^=w@0qbןU0n(""hmv 5:+Z@\ߟK;g;3?௳껻N{6cP'' wր|:u xːx^S a v|VL<ⷳϪ$1Fo~. |?Ý_=B/~y{ewwzrxW+ȞA>3qEEo})dU7z-c At"˿M} ޞO,? %7L97/O0t*_K/$ kzWSs9*nyī|t~Ap(tR#~»~?|O ^O|wr/Ns.L(Hth @('5^ti ~z^Ѽ H|K ɊԗP/%b{,Ƌ%ݵ!|AJ9tFDtt+xWsQ,?,Z9,D;ϾL (]lsw1zxZ=i[ߥ\K _k=cQħ9 w,Ep% <%B|f$R|:O"$̏ UvA4 m%YU1Pi[g鄗?bNcY@V{hx @p]X;}݅@9;E h Jr8&#bv3vzq6b2,/e 4[Z;IVk¨Qݣ6C x_#lʞG\DԛJq#3O&@K9nxM5կ-dJX xE:N;{OQ(vaoIetԇWg77htiyMM:hèXNѢGANf,%*$W*W~uzh␥`%%mS ޛUJ_vʾ*{ $C+{G%KtnOrnOB}fh+_z:㰡6}U%ot7Q`+-^Ha VDزMv7= t6(/N/*4;wɫДvwR4ѐ^ma(_v-]]Z7?QJnGQI8$>S7$[u㕷R" [Z{CPYqRS=.J2%٧TTuuW+)NJ? g*qK$`-cWUI">*)˖Wr%ꐘ|dNXrrr~sZw1˹`ԼQL{2B#=!'slDf;ekvЈ6/tL%$p{8b7aFG)J.5]zr'mHCOQe:9S[K5,ךWhAiɫ+Z ֔>hwbVz.bXir٤6Y_`bUd ^idz B-k.HnC{uxZ.*ǹE鋽XZ[U _ŤRN(C2]BLh' )vXUgB"uX,YPJZwݳqXi&}$N_@m*euq۬i Lo\e".REN;A w.?$ջ jXp& cK^b qX>J: ?jee{.Nz׺|bnYV1BWKJW4My e҄%!qaVTrㆅʾ*{ Q&Jc#OIq̈,WC7!X}bI=FHq̊Evu\jONYƂ;iy;r.''˹6-{'I%%F 1T2H|,EH9-wn@Azi w7 yͮZYq&huLJ3#Y.*!֕9",(*T\)%Hnq)cQ\)EDnqIJK pJ yhIe֡S-R-5Y([%ǒY~G`&l5/ 0clYfa6u\f*f4Ւ L6] _kOW $ wha[  (vX+j\WQhMBHQFULrJBk{ WAEq1P"cԆ`C1jtF=3镦?ֳ1].#uxۥލLɮt;b5UimX4gBttԚA*T{t=6kOI$ԈwY1I z%%qZtrL˰K[ҝSrq# C:Sjo.5:("is8kIqTzY$%֊+ZMNL #]M'oceltty-]~Z MZ*"[{ W7emɴ, gcNYD)>şVR mσTQ$&?hPmJ 4&*Ħ5pHİ>tvmͻ{n nTxZ~zGK ?K~\|]m{UС. _/Y]-ҾAX~0XCCŻ@b/hz0r=ꆊg7 &gq5G2SF/8@,@m)gOPn=Sx+B+K@wwy]ϞGfk4c0_<ލDCA< +As0| >}8|&xƙvzA<]5I2TUNR䴺|T?lcFiEiw;H!+h b"yiG-?"B]"X)B&Td٣J὘jg;g^zW=Ks҄ WYs 5[H?ұdZGk ߠt \n-)3+Jj(djRHϼU n}PXXzڥK"dhcij~Wyv-%/.I05rʊUsSrAUq!9cbV6;2͛e  HcyJ$[c+ۋ,# &~ 9)Tb@t=#pIjJJ+r_Vkms?¼T[D:!I*emFbv C@_/WpNM}cy[j ZR%UK%ugKRTt8?%c;:q.T 蔾ꔙ`rI)?2GkIm/I,(hze96ckO$ -yBd!3ØзK"j>mDag1:|vI"  K'+4yf\b%% f5J]'`)܆K`HWWڬUU\Ukzs0ʡr̶pU-/q} j=3'sh^W/kIBJb@g[*S&Ly*03L9%kJmLB$mK2d,!`3*\ 酔HBgɥ5OG' fCgI^1_E.\CcQVҚw+D9W"Rz̷1*FYW` wLn~0)SHfG nu'Gк(DlbcI`h$B{dnd)ӽb/:߲aΥS=;f Ҷ^FqmTrS6]WchN|1Gކ3 NmZPmhB'i\5bRzl[Ռ^o\m&2檁C^R( qZB+ }KWfjD܆v$Ѣ,$l[VY=gX6.MS3䶴W_4 0X}&R1ߊj2[e62YL4L4ZAq\:҇ZMf^35ܞnn'b%&tq1^$] 7^I{q-uέ+C'y:1At19dԐSnӗINgM +gǴ[S*t*:W 9Pq~>9ҜʜFa~r2e9,(`5JR$+DEEV$- X\ט}\P5rElZ4B)&*qL ѥ0 eflt[psh8!)Fq( aP&b+~eg#3[&l88~.=gl%7qkFGd63>]LJvyӂ9$;u 5}ԋgЎ=ԑv.;43c\/?ъ]ޚ̀~Fut\c9m|Nir2i0NcMHnL5;cVfj [h׾NHK6&BY0Fmev5rd,`aaB\,ni9cv&jw؈>OF .>WuDkf+υ5u;E t.ɣ=3 ;ĖA0]CvQ̢KR4ew8>q Dř: ștМ/WGMYmf7ie\:7VXi[kc#IP6Ӗs[Vamԡf6a|:sCjv:D1GK3ͤOltfw~VaV7ܻC͢KletfPeha 3~H Q-_T}2 1 ' {q{ W}Wk*c` fends6 H0(V Ӈ98c/KNa:i@Ό:8Ɏ gfe1ٟ13|.m[9],\3fw<_ޢe1=n"7HFȽTirl,VwpZfp6HL-N.)}(ϙՉO:.0)E:6?s^]k>QG ӗ,Gٟ"/x..׸x#$~ gJu8 9mtv4fwkb]޲(]1fض*/NVG΍z-MĴNd8dYYMgEZLӬ}߅b5ͷ[y39o27Lrnrڶ1V+ˆ3w>E=;,͞Jlq-&gs7t-˶r+%ccjrdnIeeoGȱer`6^7I/4qNagޟ\E"5Imr|, $jg/i"-.(":Q?b'W 8u  ?D}A4@Z  N@[[hbk~*qXq4G6b\.7rlΎz-.N0& JfwWq[l bVۈqsz<| & yfϷj>Wk .wGG"6ƨ21,>?BR iLjw[Sm'iQÙA7 gOoԾ%$4ykѦJWaDi8?I}hC1TR,VCi`8yc1Y\jSN8489Nn0wYKVZlͲM,’.) SZdN:pN{4eD&?Oֽ3]I'1tseO֌d\uPb/cS#r[:AWlvjkfV~[J*P[ީiY2>q#j\r ?MLЗI|E]MाϐN`j ֞4dv9xߩstVl @M lSԹ.k YYɰz3UFr6Lܼks]ŝ7*]כtλ¤p6jM&OnJjB`;wG"ΨUd&`lHLS16#e,, lEW~\DnDeЩ,)0ڔDWE'l6;,ϭZQa =̞]ѕWLgR.iYU9`GȦdQ6H֕- +~׵e 6;\;%$ڒfI t""GҖ0FÁw'YXL,%,2R$e YQu B ;)'nJ)&$!# xq2+U-\VPYvI_Wy j1 -4p < p#M3Nke%X{,iBfbӏFW?pͬLQ)}խI.SY.*$}NAZ8"ڲCeO-%4&zrQumt,ux61lof.κJh5}dm9P=Kr uM(꾆.7/7쯿{[kR|5.kfޖL po3owsy.-/kpe)eBL߲f½FC@;x]6ƈl5NHsGJtKXXkX=br dPqO\}zi c)e $+ܱd84Έ*ާTvf+ \Wi+&ZEoR dA- -ŇV̠eG7Lc-Sƹxih9}[5ը7Ѡ ϋ(Kc $=^!~K8`kX=lr:dIFLt5ƀVnkE2had 4ʼ{1H)ws(f$w,ʥFs tkdc\eV55ʬUpssF d̀ΕGWN`ec#3c^"JǕ(UP3r`rҤs=J hȓ32Ϸc6}á Cq@'`v+o3􎵞qA9JMX8'EQ*=9ܫNϫϟIv5=kp) |}$`'ȦIgffHKlhӼeULP[3A>ٴVs΄6m0ԭ4 B<{I8SjsuT[d%66[icm{q5cO7S:*\ó%V0ΒZ9KƾLYAc=FR)4'1i L_3t{g-X`X]Xgha>kQg=: s^׍ҵ?T30-8wU^=zaveh !csB=##zj 8"@bNGSl)4N1;`c1Xsef{e=3;yixrR{<㗳DIp+LTUz|¬pBA fofv10k5`9C#!"sλc~u-9WclB]f˼+9WꘝֲE,uR"g&8ghfdL000^cf~5`1C=;<DUqf-U@2\qu3E 7$Xx>mޟfp"MJnUˏ͠˵|Hа<]^+E?c\^=>܃^`rr+S}a=6㧓0ͶËѠl,׊^ %|-0lBK`)̗m  fmŧs.f w?g؁C ~ysG?}jS ;3Qzpv3N /Wuc\=  g7|v||d.4g.^8yY۵r6m@N@ꋚwU;]ݓUڍ?HZ@!ا~*8"V2zunѨ^\9؛Ug0xdTtǗBmȥ/JjNCm-hȬ¤LvffWer\`yCM}TL}ckBL)/ؗIoy\ k+L|Iƾj{/|L6e57=e.9T fwQ& `)Ռ - PsR32&镤"oYV\ K (L竀|Ij{/|L2)!-zjk!Y㝑%{9nsAQ$vnjbhghO#IGtFt?{D' ~O69#SHeDrP$]5=eC~>C~&eFIXNtb!oMdqH\#z^cUrkvd%8/=EADkt] 2;rkb5|EB-mW`E w"qHftEa").:B&̜**5HV,>Z4jG׵ {heBL8Z[jcjcv檭$?@o֏9X!;\QTBȦ&& XP'?@pU&X.=H.ҁ]QXH NFDr3gDDf*n _L"&y06% hG*ל)]>њib-\ܤӭyԥ #ŁqՎ(X@U8UrHfLaQ_z 71W(v-\|ҭk-֩3#.j*V@H .wvQTb~VV fus}R ZE`l"J-q%^/ԱS\h-|U73_(-|μӭy(cJ#Z?¡bDLrJFQ]v "[eeւX`dׯgR~=s <2hmcLp 9UBNݣ.H ~:I4]Ix7-ͷ\LfwĠϹG}#k؎3Ȝ^?Ґy)nkL;oIwnI8ith'tcq > /HPUF`|⟟W!A[^~ gA' dl\(t_-ڔj ªj}pjl=ˍ3PUM&SP kr4c)CX_LmRMJrg1&擹YN_&ZXI/IYzn&gDLʊ5+Ƽ8 ֚,\͚w&h$&PJzW4 r oMLP0Y֩?} NH.,׫ڦ2TgY3SIig:3YCJ[A`1|f03jș Osj `&,_߶´juE=ݤjr6nrw'w$͜)MV/5IۥvtB͛oF6rfH\G#3g4pY$]lrDߖ t˓,m } l h,1nfj_R-ji3:i3US/clU_Tˏ`|caL@L)js^Dmn?A-*r*Ԃ.*FIzr?gTVOa2MKoIbP}Q-d &ngqL[($z͘oDALaL"\̹@*4h_岰]R/UZI1Q;dJHF+>XUY(\QĔ!T\Q`N9ng>O&oWN~k,+l6 4i5e1n]Q&/W;1w)]-s/[K0vnEgo+HJ',-"_b5 Ŀm jCI֊)/,T(`";.oa8/@ `(5!E݋~S-@~sDw˫Gǧ;0@kg;¿%./%'k  uD}Hox @ߖ<eSE-%pൽ6΃g^3ėa--/`l]PzCߠͰx_SdBQBۉ\jZdV{// ^9VT}[4(7&M]#++ #꠮7?qwyY,)*7 @C'Eʟj$h \F`ٴm0%$YzK/W^R^xB 70 SBz?@♣hۏ&ۏG(%,3oWo?G_(Mۏ q_g޶ʢ]o;OBo?Lo?.[4> ȏ]:0}~<~\@o?.}!9z*vInE(2p˞B2W}ɚI6ERgA\0CTGDS$ITa i$+=5Zg{;d#aC ,(4+4FリhjB*l]h$s[,Bcojİf,*4f$4\a“B,Ch&KlBcmlDLA> 2,j Ǥ E4Xfkd2d衠lP3j>بFI"?!<v1E(\)*ȸN,#23%QPI\25}y'`z;2fGc$+lY99mɆ1*({Z\KjlKUy0<9L4(!Ndvi drer,/Y\Hfv;-mY_@ɋ[XD/DL1$\a披ɱY ?^kc|.m!EǓe:M_dkKfɹ}qO/ )Ed1bYPpxx4L0G—5&d#`\ToG'q N_[ mC]hsްǑ'[cPNːn~?ts1[+`eNWť;nSmhD'Z'!EY?t;ؓ)ζ[>YD{_GqZ@*CYnAN"̕aG~0z*#[rM76ߍ-ByRVN~ް$_ 5Ǎ.O\}R8''`_y524% oL>0XWLS v, "t1;cRS !RYP2W%7UZzo铬G{Gc@Û5xFWfBЃ:?3w&Pr[KC2wspΕ yW=jG|g0U?ԲM$\`peuTƯנKfkxҟUj2UvlԖh U{j:WplyF"k|!("v"K2{2|$j)Q\MһR.vraMER0J$Rhbaد_:}C)@7ՇK܆/5=7ɢJߍhC*<j1\9hov&'甕O<_ZU) |tw S'nz~g0ݻ\6L=9'oP8.UFLî쾃_;hM_EK2Aʛ,/}{ƥošuU!})臠5a ?xazw¿=z+wڽw,_*.;hTRDXv.7Mw.oI&2@fjye @{/o?ѯkb Uror/܃^G[m~]]]ڰ2]@X9 l_v]ѕ?Gc,eX,La#%vF`͈h-i%3&faH0xB,G\BJC=}B'.3K>SX&"9BB~ js|U.dW0yC."}"c^_k3"o $a k7ڨllo\>E'VJ>­ ҝLܒ+?PHp]mާgVUOOOau[`K֒L>>K%(4꺶dmzf+i~AɔXz8^񶽊opD5:7`Z9"O{wWU)IAcnD:Ug@~wˣMޮ{Ž=]?9=~ysJKW>?8KOĕoy@x >9g_^T 瀥HOVE'm /@*+I`tm vكRS0B sDWPeh8䅋mScIicᦓH1[6$bB|U;yP~[.GOٟ錟/iIݒ $/KJۨ/^0h7{P93*]뻡$S YrdVj|;QBݾ 28BU (V2s F sç3@F=*ݟ5Őv||:U|x>$|JsķR?>('sNo.۸= z0mѲ?.yE*+f 2$#G}ׇa,ȼ4~Ëҩ Zel9 JLz)8}_voh.IL}|yKeq^Z;]\3y UȰ5l 0<u6%OP;^{ePԜCI9$C/[UU?\JYٵMsƿ\×tnł1whpFT/C &lozBfO'ɴvm8ݔї"j85{h`VN{r]A}[&,\y'dnVΧ[n~(=Z;ZvӦ 5CrV"^Fxkh1x6{ǻ' X܁: Fmpu:'مƛi Eqxte[ϻ` o|3 g&va]i6HZ6! R'<h/ H9MԀD}&je iOdӑk*״n0>nLPfhV h 5kV&\iN5T}ALS脗xi{yy\A*Qjkn(1?zފ'q >7TV 堵= 4T O~{(OKgy .a녣a4ĥʏ y ag\J]xCG R|Cxù@@vG ]c9;5~kȂ8^q%Ѷr,^v!AIK!;%2BlJC^Mx&qO>xgA RyXyʓk/1t-02p}Gx7?zxygE@3D߬?k2sc^j{p~T41 1٫ Yڍ+LP󣒗.]H;NQh{n79j[++ 0QEe@ u*y̗[ Po#ˇabs{8g Lqp͠mmDˡACy{0Ge_zxߋX 7aV'dj'r^8"DۃȽ錌/-BM~$.J>(}0({|O"@q#-3cJP@+V zGV G?:d}>6~E}2i 6Paݘ2/ $n!RBLKew9ETh\ˋ(,Hw6 e؀!yh$G\Hy~Mr ~B#buB Q*RNR˙H)^pr|[# !KvP^aYi*e fD ڠ}'e<6lOc6{h>*!ҼӉB 6u03 kDb\%FRJ30O&趶bYɵ3Z.:U>HE*jzĵXcU*ڼIߨM*!!eG>& #}+ CjAK2^b,!vJֽ`_Bu!޲%1ãhXC <0Z:?Лڄ /ژ.mTʩWg|C*/)(-cVTȵ47.+i*Hq7"49T]q"02)(EN<.iWBk-͔e- Cw+gLETX ` VҨ - rA[88?4qL' 225X~Xm*L[ٱ,|[{PvR% JyӁ4sP\/:?}k~G<ߴ#_'vv>v4ЉťNH6$2dJI`&b{ fTrN֕C#NAM u^Y8;QL0:Z?Whc$ $X$!~G?5зWm=i"b9._Y,| =0쪹w-"x!bl٫3J{$^B8qsպ.4'-F$Y}wV5P9+C&g=[1&2[ka(AN޿4A5tƮe%$4aM,/}fW)X\"%AfS[R0lpխ_5KJ@B*0rc}~t%M4l 0uHn"Vm< df^kh{l9CK RT*pڦ=)A}{GLNοіRz KVNAh[RμCM;kE.#5",FE\ꉽ.j^ku^`j{QY${6G-hbcGz@X/MWC67Z!F;bp :Rэ+E: ыlymjfH] gW T:aa*d-):a'LΠ#ERhhC^!>3J0h?d.@9d{`ΊԭTDĠ05Z@%H!b0Mw虰L)NtD뢄SZ\y w*t^*SA{h"of>C .ʊnz rg|rڢ :.9|G .,)fb:.\Iu :/ONiP'ܞœ:JHS,4N9xVW-Vp)S-n,wX_%*.0H oqOr+8F Fq]v(Oi%l l$ ܕHnf ]YEpA[>h(#(ڽ{:MEvGmB2V:FY ">R/&[򲐚bwpw͒,wYj; ÓgCOMXrP0p(5l/ mvbq-)И06Ŧ]or\ MW zCZմڭ,7GpVXO:yچ)qHKIfȭ%ɛ-)Cj"S[Yk4e|ٕ]N siBl++6.KEx>vaNΓ*;0'=v>.(B'AſI^.BvF w#ˬ b;76(6dpJ)blR,@!.N3uU.4sA\Jl_i +RHS&\Xѭr).7UZ^*DЌtG,@R{__#V?[SwhmuXΪ&,:8*v(\4Þp'C] p犮@Zmv$)ڔk8"z(" O;k~X{ ?jgPjTÏEmhDO8s"# Ed8Qtr\-\ U&BVN{kZ>+7R,i}J2j9i@aUgkd*(c-[- ەJe 28BmA`I8du~}먂}eyՅCZUEb0J * 9("G=ㅴ>␞f<ա-:"y hr "Hj?3u(t@7+X﷕EW.0> ]/3J-C.eS{u MRYI!p 8{7!J0," Q?H7Ӟ5Z<@(GtpA#@x@M?H٧+2$ˮ+Qpq$m ֠6MVY6}#/ҙ>F'YHqS ‚+Q>(':Nx!cÇVtU3qi#-cCt|[h W*Q]g.y]1-X "Lj ;)d"`LKV 3@tTP.z5ovpųy{"Ӎ? Kepl!b x-Adq-5(&Rя -F0mЬIjA3އԟ`^f+d].JqhV+"NMprMNmn UT{ t-1&\~^[8=Hzv@`Cx];8mrq@X%bO -9iBNAY2Sͦ:fcĪVFi1VȉUa z*MӸ6in~!LVloPTAF/8 g?蔑xM4\I#gqy#r8oҟPb&徍኷"+T6%ה!?G+9 >nn;|EW (G-/К ^㑾-\IKkH{w5u|a2E-Wqݘ7k [7 Fkߚ ^w4i$,*7.>LIC\$&G@q:~Bw!m$ף<yc8 {بv @4!qdzjC\ I¦W阼7γލ<.Btb<`D#4m4SϺ2г50ʅhb q֨G(:BP6">%C;h5Ê ΁tNFT!t ]d"0 Px^Kd2Xy"Ln7F{4zx &ÄW`pûBW."*N==Nώ6Өǃ6 `p|b)D &z3cejI}aRRa›Ȯ%'ZzfkR)aylmC075Cv/l NKR'FnRa%#q~xEɣU5SKO,ZGԱn}i!qm Éy>޲&y`$y%q9VgSGvo>Myr"mw>yQaXpA gi~eCFnZbb0dV"Z<+\h &U+i[45 -Ҧuڽ[2b3ɨk V 5\4zWz%[Fw|Q9#v$fQi: AkJѡyL.);q._ejQ盏M0=HГPDVܩH. v)|1 )E+@<*-*^z6|<%SIDd{~ThG Q:e|J [im;?KXH91_g"n{LO~?z6.+_ S;.}#*X oF [CO=6Uk41?+½0a9}wlxa.ǃ`زTɥR ͻgzq)V~OZxzV@N\^O+6ԑ=>~%nbDb n7 jc\q| F2^Bu AāK6 h7B1MrxE8پ[l .eijшv%A@ۛЗE,Xެ$HxE46zBPkoHv!O!BI:jXPET.wiBB#>4-ak.zPPmtx++_ )gk^o;U~W~>VauFru|~sFeV=㣳`N pW^iVOÓ} Wk눀;wt|:.WfߩgGX r;9==?9NOOkU۹_=?U׫Z=:j`yLMF\"w~>r5G#' ֽIuwT_W=; |$,;;/9~=? vslH^k_wg1v V]Jvz >9rV===?9;Pz L>x oTp{vtHy5n"c~]_C}OMשWޯHi !G(Ƚn \G mvW#h;4L%00ӾH&>5%\-pЍ?;h([% Ð(ظgǓvMXf < Hp(aD)[ACEV1j^^>P3[iޭko{+o3_$?F7|@J=KYY?Eh5{w{C|F[MXGD0vz|t<;=?ڥ_h*=Sc wUqLdcF'@ŭe"Q1]>Ҍ;_Q="Nh'L%{F/ n]זa*ߖT%ZX". R~>I 575?tXQjY17㖽K> S/(~O/'IXݓ={JØ3G/M{p%+z1Е`_Viz6ֳϣ0h] ;M:]/%ΖGȵRbbƦj o>xHiHL؊يVxU;Фh?.j=&h|^ÒFf՘@{xxۓD_С@t,<8rUL\Z~Ybj!W'yl=Vnl%*[ȫs}Q.;Zd#IfRAq4[`Ow.{>}YSda8Gdž_/oɺޛq*DcԃnKiV̇&fAտ `O=TkʼDE7ӧ/)i}L4t`r\g6dg}ؗ"hkt0\rsx|Iuu|.ykedEf3]ufB=avΧ /FC2|ndTn'D‹bS9 {K)%NʙRBiL=BL2&T3n{#bR=CYQj]bi E# vz|֌ d ZS3 %=v ϜdN |g@nHu h"?𝤒W_k绻Zw_H.beRsaoeh&U+(P~+yvpP^Xf2d Xd|Q{<4{cBi*gX0nRnuJi({$ee*$M(p\uvϙ0i}lFI" 5$( QM"8^RLa`0'AqV|/S/ѵ#rgsrEQ. Ip^Ѣn-pkEm7l"vݻD8zٵ ͑~~ Dbϣ4Li#8DiٸUx\:-C BFM[Ab|oiVpFSUyfU0Eړm~d4T-}>A$A#Cb0$`֙I ډI)Y6osl-6Hu1IW&EKޅ&=X K ȹ'+^ =v@R'᳦vHP)og9 8b[/Gϔ$ Q,Fڗʒ18ʬ3h`IK&=ɨ,z8\Of F 3. uDADP|۫% w7 _$7\Hdscn[9AkþloY46+X! a&;%@BxTV. C@q,f;@r?:Hf9mfF[Qm1 ݅"Y,c,^, $%r)tt)S# t1bRLhë?gfmC$ZVf- !j.~3*Orě4x3a2'v̄Isŀf,J⭭}&6 ݰW&#/,ߝҝ*u̓w yߙ);!;38}tGԔބh&绱ߧ:}gw&?}g6GdY3sw<}g6L}LtHR :2@2y[_3'˻wQ&kFeOek]ɟ {SxfnAg0ҠqBLȧ ^;n@M|؎GZ__QOṯ=<`a''\؂ [pa .lA-ȇ[a6={%/yV.4ft_Ńo΍}n{ks[ -eD\EYW5v0}ukp9mʡ׾@[oKГ ()4OVkWV[] V]l͢9P\Ց1f35?:#+{:kFM- e{ zA8f"$`L3YL*@jY&^@ٙ, WeK2L8 `ujy(f>@JZ (doiw3IܝFrP_C.<޽QOgZN$&Wf:YwY}wVfeY+?;C:R՗ʽbͻNls8iWw5XhD&m"-qҒVZluvsZjQ9EZ1itϯ2+zk);)<(2Fz1|6]D2 M*b%]$VK5aqD2rdW wn [B,),&fD r"Xae[d]^0f~j&P#&LzOe!!4!9iIGf"+=&]Elmfe(B5Hf+ݹ@l@^yvɤǞJNԤƕdC_ RBN99B ز(pΰ6ŅH^tfW|29z*')."/}" &- y+tUHB(T9* (8P1# 'UFT +#@ckKH'"tklmY2ly6nK"LsKg S<`q SYjߕ}ÍDw1~0PM)8BO[[[Ln1EjކsKqx " /v]̿U9v%:@!FWJoqQ`Iar'u'H'[G9L!jdHgMaӄp nVZOgp9oLf޸{'hsq=1T@ƀꡫAxͲ F=tz$hrsQcnh,AmuPj Z23Q^ɪG32 Jᆴp6JB"DN#(ZzZ-%RWr)6yy,rKYLgb"EƠ͙]$#E~T dY.tY^Y/dYHy/Eދ,nD 7`"Е@uV~oXT38O߷88888YҒQ؛[o/-Čt+'uD _j ~ZNĜ'\.d|}0= o1 8d2Y @\sndu(<5QGz/+(6o6*ǺWq~%(8D)AhUO0DQhRpt&q]+dK4me3# <)l-A#Ls_?ߑWnkYGNIE[_(bX,VUbZP9r#ϼmϜw-2t,86w-\s6/U_o g=uUf:a-E (z]p=ۃ囬t#B_DI30$Iw[uX}nZL ʁYP՝U 4,"b0$mTw)7JP}Kv{vA1mkF%WY^|`^{U?;qgK29e~RYsD_ZiOoCYD_Zi2CeZ[*9>l5uxJLau. ,^i\O5S5YlNr{@bYsD_Zi-g[˴Pb8̰QL 37R ߦ zKR.WcՑǛ mM]x{ޅw]x{gr̊R?ƻ^)G:s:5/|2OދdcR_J+F-RɔĿqݬ%|.gmO}cL|__1 [GN͇/߷^kZ`bEG*.b<˕b =TxP:/n0;@KQbؼlH;aZ.Mgl "]Z/+4FG-acvQ<Ә= üvG{K;c$-NGb+(>@W8%GG| AǭaY3D<&">%#q=,XFl-.뱏4ρJ4;FScdyWhtX]ASfA<`(z@>>\Dv v.#I˳$M=5r䍷Y&jgb+ 5<0'O1{ݼ]6D2Woo gl5!i(ܫdߋTy`4]xХ4h0L3+qu+Sg)K0LEp}F0uddr?{w - g0ʀv `Q2Ӻ+Q -$CIBȸ9M`1Nn 8GJYXxnߵdY &]Z ׼m&?!==逻NZK+I eeM23a ƥWyK=?CLE&X/R>KXK h>$S*#>~ ;M.]"4oy"}q+<@ fI:}B(gE,/BKIf[ #b7lf6z|S0ďUd huw21=^^c{(z" dgN->H5ܟsUG/pˮwlr{c" &Jb)Aqw8=ginR m/ns-\醴[MKx?zR l(MCˢM{+CQs &>:+8]司H!Ǽ`"[19l%A!iȼh"%|[g3{zpϫ׸`'nzͫWcoy7r@2BM$ÎXh"2 lP,ø]rB' qWNn<<f?i_ ðS~.9T <:h;CN(U)n2FF dKZCɅO)ꞽhޯQ@?c7lteܺCz$2Vǿ,g.s"y)4"k:("]mHT"} j|SIVIZ<1f8&ڕ !RieaxE˔A83,#F ToXZH:=&M+0MXdwD膞.. ~L5f$}Xdgl"Uډ<%ؿQp~=.o^2)ϣJѤutI2GuJ>` }p*y%x Fyaz0b #g@ T3 KI?Lb:1L#33S <ńfj_1b[\Xw*1★Ϙhk#*F ؽwϓ6-ƣVًnUZ`uRqWi1Ѩa. znѺnNLPC<))REWT+^?ֽ7d ׃ګ5 ĪzM%M >oĪi=^w 0-)b~│Ԫ@$E^}d<5Xcݶ䃒–?>eⵤrW:%7N~=@׵muAc߻;_ve3ƀ_7ךa2b%Qg8_ IN*)Gj@@CE4|]`)^.̿,χh,F4<7? ,ap]擻<1P&ׄ7n0odM Yـ-;[n A/Dۂb~̄߷Cv"> SPvB GY$ zf 9wLJ;/ZV1!,A:M л΂)" MVU :M"PGly~;A$<>>6jkׁ`RC4|C׼@9 D{x}05ߞ$4DMcj:/?\=ǀV>y:g/~׎Owdv3qϋZE94,Q%- 4 1~^YW! xj۰| p0"F|tAu0O%nfu}PtQP-JRqqYյQ%13=h:}]DP*&@ꮡR #+~4+3+rV/t"ݬ2$4{'o_owWvzJV lBԉ7|C\}OJ5oHNMC#RzbO0 jakxΒk~%Xa&ۗx9p_D 5l)FN&"#4ypD/t)2K^ q':KKGuW'*סV*{3 |E<:o7ሲ 7$oDzܹ_= .:Tz0a}|]Yw)&*ÒPIjrT}hv3󡥥%qlwoE}߼yv?7߸2>5'bB}[~ïA࿣GДƣ?ג%I9VWn+˸gIk[<0'0 qLL XCQWxɬ`h+  ?#Mk+ɎAczݓF+>p{Rg6H֘ iVJ z9:>9:B νHGW)w #{4^黳fƚ:R-LճWu)۷lGC{Kn SN%Hr/M K]d'^puzPxuߨcxl yE(>o`xKҚ@Q#&u۠ts4_TwO.H`ixg/ }0vヽ,؞~?@Ubы}5 KjQՑљ*܄g_8ڳYu7hg070 fÝZoXbh @)@ H"B _ Y]aDE+ !cV6.?T<)hJu/?mч:ƏY8yGGQ0qo A@ hX1uk&2OWZ}5Yt&4z {*imn,+ +d{I{/)aлD-ޝ;I]<-9a E*9=ONA "1X5e|"nGxÙVFH M0M#nWprđ#7쑹T;^ǿ҆6lF!,I ap\ ZcI%og-0K:: :5#ZMΑG0Fu{<#dki{zGGKu_7X>Y?xgJ:_;=XCR}ʂYΙS@Ϥ==u5=9kjw5pwڞ\'e(IsjMLy;vs]׺]h]EzU,1!(\[^FRX(Zl f0kݤNzWcqD@/ȯb?EF0SC Eŗ~kE5J֕Cyj{]leQqOHNF %^{+ e |omvHC{ aSוԺl!Iݡ2!t0RJ\^eڇd1Œb7L@[mn0J⺓ތ 5F7^<\+HF5*B9*6hʅPy_#aӀ9懬k_֦F99Bõ;r'VW^$`z4s{A63T/ O/ψPֻepXjw׬Q/|^?IH?nb8C>΄0tXnlc뀕" _f̝2/+LQ[Qupʝ&.MpZI A=`J"S؄,D0{#MfnEVmG{,^췪yhT$H͋lUpJ17iYb5Ngj! OM kÀ~7K{XF8p&AT4.zn=.2-ўa x4)3w{2eY] 7dMrQ؃i|6q|sssٷ "#m9 vUr^(?DF AY FGƒN ڔX8Dė"L$%H:UQK<D9jPyD|G: `d{$a<۝$\FXod+<҄Ed) ?ingYhOB\!% kzq~a-IxIlAKʓ  Jh|H@ 3,B/iZ+O>TEOmX-0֥?^z0+# 6dh- VW>-;6J,x;co d4l5CU~Cq(IRq$ShBu:a4CEUSG PzZ41 @s(4I;aD0?/j:!Qf:!JDs׈hP}uvCk> 3}'Ir%ѱ_aT=&ƣ-ㄦ|bP̮8=8.jA)'{c"Yyjz :33= 1wy-\kݻt)k]P^E ^K({%Zp")|a+1JMr4RO2lJ $PRŖ1h^Ǥ/$| P/7Áy(C6sXi mÀ֡qOIvfHLB,JC}qoRr7koX@E(~ލ_2a" 6ұe|_ Հx"*J=I dUS&uc#t) IEA'6ZHwf|2ڔZ2/x3*טY+.Ɠ.6vd,1udM= 5&ɚit+¿ ^f4W6wBLY t4AbBHa ki]bju&T6E2u;#~sR_mLL1Cg-VӤ(j?a>e0<);^9:TKNTke(?y+ŗ4hVJGJ{p -@>a>l>O; ]C&OvBFxRʴr,f! 㹰Tжf%mV*( 1x*&2c46,~XNKݕ\|d*vr[SJΔwr\uȕNN<,qz#ZZ\.~`|}% OҎ;ZWe6>0[2ƽķf>}踕+gϵv//ڰh-ex(AF 8t܆fм =ф//pd@{)Uț;$o*4ɖm|.eZ*ن9A2u'Kgй│ h%REdh8!)m8A#q\iM [kK o {oh$637==;@mv\M^mb[pq7ߩ. v[">p| }pފFNI+42@[Rvvʕ1ۣl=+2oNjj$ ʲ8֞zYgDD1Ɖ?aavAV{9N߰o"#iɵv;LZBV@vraAws   RsO㻚Iv׉XR_OG⴬%JV꨺x gS :]ZP΍4M"hWv3*PpTh(+2TÃ4I}uIbϟr>^9UO;Ʒ$-w{Wqܒeu+/ev},Q7nQ햮Mo6MQX7*Ze _o Y,Blt~%i 0 [cɄ {Rx(1ЕǝKCR^J2s#.Xs47˗8)o\iN3`/UcKѵ+pج@a4s6)RK+5`Y)+]vK€1znR5S (x׌Lw& xlaCz*"h2ىbr{B' X(Jxh( ETEȚHAXhq$.?/| G:m%-ZoʶP7(zGWN )[hb~~^<~7YVJA.jAӅϾk_큓M N?֡Vw3+?S4ZXC\!cBMpVۇ y񯗯_qe GX~jn(wakrcH"WL !ef %I?nkS|sObf WyP/Py[I_NA.PvegI@aApLݩ- . &ahoB-{,pDhcLpWhTwRkQXZ&C@ >˼2pKD LLlFI'%z,/x,c} _gO(d 5٣<=6Ԟ"A:; I00,,ƫ`0: ZNM̮-S3@ne5JL6>+gbۀR5<wN+at?ߨAbdlTl{ԕk>rAz BۚEoGeo.g֜}oרgT-YW !tSc[>k3#ey@މfL9IAxSԅ 6FTFTE[ᩯz6Ԏo%h͌>h(#Ī/$Q_;v^r(d"+T?"66BRXl0Zne G&ɬXnZj,``Ph(Ysq<]BYd 3VX8B:Af_DڬlI;~/P}BK9+<]$|߮ܬ*b- F}vlM μU~:syT,[*:7FIdw7UBQ!VeԃI+g{fSjZȂ̂`[dOqUXQgw[U4m $_%8dcͦWZ2C̠H\n"I09<`Yꕤ$1z@AӬJD$&Aƺ6 i-.wCYKX?dx,lJε@Eh\Tr 8dD$A^1sx+JԥDآsKTe̓`2$h|]6R61>]:˳WyK]{9"oӱ'Ŭ B"_8ɱ8QᛖkN4Q'I1Qh>^r,S9S`RL2ⲻ_+JIH,wŇ'?u>9tQZ{tĉj %bt⨨|zLH0G4h7d+Zt0apowڗ~I"1ztB ERY ?KT_铤-sj/Oť%~/(66Zn_Tв`Ä>)r=mw(|tdKVJ2Qgӵt;#9N '4fcĸF; ZRe.(_Ŷ83^B*DzRD preڭUVz[ :^x^lqcŔ2edoܠ ޙMJv@5A}8T ':;M}mU:[QBX-@j7rxkL<2q=gVzUt)!N<= ?\nاbD9hZc=` G LD K?)D*y#Sj5?C/ B-Nbp,&׵VVR%tfq%r &L0B=%?ŵ7Aai43жW`y3f* >UO{J\\sU^3S_*ezr ܜ+Gw1T@r,Haz,ҼE6|`10DrI|58@0Լ  a}ڬkV` 48|&9HT/ gj΍u}Y̙ݏHLH$^_ȢcZ!^Ӣcj\1s\|x T9< 7s0aѥܶ1LУHIf7Q6TV3>wTT/CTVV醲chF>$ Q Gf/:Y)#kAMp!l2T3&XH t xuBKm0K⪤{wіcF,WiNk/S¼ډ a㵌p\GTY(4-t)#r`_|[1;E6.׶ND_"e&{;QQ!?p<Ԍn(B-T"R'BZuz]/d5d%&"D|t!>+نʏ,/6w7T"+g"H<:شۻ/Wno6v6~b{{ hUQkY҈P4R68$,^ Yx$F4g֒xQӒfI[|j.8a[NVTAx<}Єrq",ѲҬC˫ta-*-䡆c+gSȰUV*\}=[UXƏ)8].Be@0)e>f\Ӛ9Ge{I> m(q\<ENM~{1xxR!rnE\nPY6mI 9|q.-TLMv$g|u7ǵO`1P"#" jTpK{Qʇ7H}H~cnϐMjqr MԄ`TץD_ Svlva|C^+Z]NE&͒fu#cql7.X-# `>C~ZrVBFOjŬJbA֕&F ~\,=0l"ݓZd*c5r-xvSw=l:f@'׼Ϳ [)>#˝y"iQ9H 4Vz]!O"+}XO2 ! Tu=y^Gf{N審U^ #!*l'괪'M!VHv6u0rԮֵj%X3M ?|DJғ+qPǧkk)89E-c208R2Y8Eu1I pXfAُf_dWS"{: *n m=6m<$kRq\8Ȃtڭ`RDYU-I{R;PU 8bMu'/6wvL}ܟQhqR*iL8Q`|C~ >ǘ~|SDq)db$T`v= Ok,WaV2*Y/ ߘHр,Ur`7?${QleZ5B[xnd Hj{!컎 ԲDyTȸ?(! t(;n#2/ &nuM.S^"1w^ѝa}܉CxН!/Q2/oBQוȒWi4Ғs)QQgs>/6) 2 6,tG.ĞŠ0l8Q]"џ ܶ"Xrήtö̆@ \B k!PN>[d@fLwd^mmn擘 n̈Z۩o6~?ܥe>nvG] z@bbC:CS%F#DZYjc[P'E PN5 A(x\` iZm>oy& ƭ(nߗ ;ɪ)I%(#f8%$ Q: &/ϛw#u3(2ʆ–6lDA`:6tTBNN+ɓOӏ,m*:fϸD"En~;wO8J'KbΕ3k w=(eՕ5ڥ*$F*֌G,PhS}yӧX=n}kP?'߽ 5}f3 Ҫ@JvתeGSJ͆4ä # :Ď6 ^v1`f3qLgu_U2Cy^OPO<˦-iLe"b93% < w`˫kVj\3z)}GkժOl Ɠ@ߊ`ؤKvڌ&w'uG7 X0nz9qzTs<^7;Ig 08L%fb2L7Ω=5Idl<>ޗC8RRvOFtkbGK\O:DZs>k@=_o0E*Kj=Q0R]{ɾ4jV9ЄDҢCRmL|iP ~4arKVDb-QS PbY1N%.'=z2UeQ1DiYZ[ !Kol(;RpRfTThcXu5Ԧ8Hzb]xEzjSwcɌ9E|/16fYb+\l]Æ9o4#` *. Rb@;]z!);|LzB**skL)ۇovKkQ[[Lv!$ Dzҭ,tlWlRMkQ(H\$jeb)~>hlMdv i7{Km-}wS9}Щ~'ۻ/Ă3켨]氾?S~xXeNFǻ3d(1 +dIZ~e /vU۽hZ(]Gkn r8\$ (I,,W1ٱ3.>h`g2BeCA͜Xhu0t6xG\LԸD0sȂ` %Y`I=}or 1BA2 JVnONigդظڒ*Yr5I*\9> \'&5Bxz/"~0dZW T8ZڔպUK8Q%.5dqf.]7[cQ;S9a[}[e0n2 S' mye^KDZ}$}ZҿzԧMB,tl& \0|a3 ޷:HoKؠYGì Μ&?EғTF~T9LW:9K ӺH_m2/q|~Z&:^z&MrĔ&oqkf"eۙ);+!₍x-yE n"פRX..9 D߹CdRZɯ|Tp}3 D7.^Du&e1SC9iCƫ (U-Rq NT'Nk;ϩ)vz YF,7DE:jVXZ AHÊ9u.*yUzQV b& C9ľ@wYTiMO V9IMR.ۺӼ[?{b俵E>>KᔛwL.Ozd^T΢2HjLꁚ|IrVU rp@)a yC ~ 3jcnzZK/I!E+D+SK G/y rl,MW#2 C4{A4Th"VW!M9vZ@~kMWCi'|4z~˱ "L;Kq3 #${}W[|l9?@ ;^DLRUkVrʚ?U?T% i~Uy)NV\~TyL^ē,dXl9]2`ZtbGW=zj"qtlP,]Md}C6(KpaХE`iZm9qa`tЕ]?Wgny3phĝdҗ۞MX=*bUsfR!NizAq85O ҡLx!LA bbzEf"`^R`oIox,p0S?ql2L40K#jlpM߇-&U|0fh5@5P>#7_l@D] QҪ:ߟ J¸kۮ qѼwx ^( I?opVKQQ&g}@T]RVF=4LIɜz a^&F*fDo&ԛd?;kk`]Z{$s"<1p$ͦN?vB-~ALWխCb>3J!<(J>Vve fW,=T,k=QJ' 1&c"Jצ#kD.&༲9K0@y;{ۍ7{fh{kAh#U#.jU*=jFtPx)5zF?0-pnxp\xݒ9>TmGц="*X~&E!`{jY󣺭H/o?k^17~e~H2e`}U A,Ps+.hZVb- *7\:v^bWgupwg[ͭ-!: ڶ,ɨpUKAL_%?KV (@yTBVv K%İXBm/0Rcx6PPP֘LSTj^AMV3a<bA;֍j.9n %<}@Pm?k$1}c*a(_]AL\.ݹBD;Ey$ا׿T wm h0Y4/-"Q&v&x]BͿ[b B,( m22&տY8mJfo)Khq|V4VKOgIN`u …hGHb+9yb0AwZ,&Vr 4hE]i/NoԮ+@u:@peR׎.P !P>#PY~AvV =Б^2g-VE RRa$!p!V(a' t; ;µ)~A:Q=.;Q<-3͚s op/:ۼ(krMр{4|Vj^` Nz+J$h7!C~+(P| •*K-'gʵaxIC9#CHfPgcz;ۍ`ӎ&:L);[i%!3`QkC@:ݜ1jS l@!I=œ8n- ۀ2x n UYIHAZV[|La`~fҼɂn~;:PŁ @D]ju&oi^>"s a0`>PrׂAj85:*<+˓ 4|@܋P/=}̲og`³\_d,kGfuyk6o U;l2fPP:ujNdN`vq:'N"ޯ|Fw -\yQKT_H9)@BNL>~jfؑ =-x[$Ym}xR*_Z[\:Y8>u Yd+,9x+ͥ!=U^e;8L03둬DWm8hI* & '&d"У+NÆwBu pwrg0)u _LUەEd1|&'ՀSIV%Q0p~'4ySz~s%4Q̆K7RuYUn qڠ}67V(ފbZ/[btM{K13sTGko~0)ޅZ 6)dX028ïD?۳?MꐔC`#EiI&+TnAbC&Y k3X:dܚ.ĜEɀ*وWTѢlZTU 6]}PV$ؓS( ATI{%l%t U t:y˂0~hQi/zE7Z$~Qrn, @=LD J.ܰ񂢾LbSF\d RLSUNOh)~ЗNqƩ.oh}(d^l&g85#G!'j< *қMI)ϝRnu+uq{K4q e.&a.}\]`0fɸ i0)__Rk]/M@:B} %g,Mqk~.^XIc |H<5Zm![0\]v2znł2ܨ6)pMAq䜠m۷a -ɼtR'v&6//uv "SJhJmLЭ2v>QO &b,Ra2B_=(>Lǜ8/w°zZlV)pI |L2Z4e5:I[u[X%~p1s91i!U-btnfNmV;='18?2Jֱ[ҹ%0?~)uLX /0 ؐF';iI|VN-AG %3Jd*"=t9'<>^Y} 283/tL7$jQWӌ].э*'߁dYGB?MRyQdѼIif]FQDd+[K5X?h9*iS '8iOHhJg<]V1pxkJhɒW_!1F.ܹٻ쏮݄_VyChJJ*ٸK*t\ a LL9H:hD"]ƣ^OY/ЇӢ*MgTVLҴxԋ{Cm_"Ũj^y@ƫmԗ}zEL!-VťAt- 5s,qK% vysٙbwC'<'PR_)L_]nMlC6]r0"XG1"$GMXx]}eXdEw+FSf'(&ɓ'z$VkrebIPjgF<]KmXx](wۻ/S'ѵc):@ ?2R4ɌZEܵ/ ?Z3eVkkS671^}-̵CgWOzƛX,pck #3-4jZw#U%&aP2 K".'_>^X"zw>>~ bēg]"ln<^C=s8ynFP@ځk ?ӵsk+ *C~f<~= \02"c2I@{O4/&ZLMdѺm,"*ANB? ЌZ"s? !U S 9@ :@zR*0|z*ʔ6Qդ P|A܆bqfOò+'C!X|DnTWddp `q=㸙:|9' >ݍۻʽblBӲyBQ_MN 3”HdB|TqL \i)zNmM=ЙC}H}aͨHso lQov t2(i9 U!d)4gV8D57ه2C :fYR m4k*ZR:d+~U–DàB{X3 ˫jL>@;[ Ge(u)v[H-k/~-K땹SԖ_7NPCaAdlяb8^I&q Wâ5[^AE'Q+O3 O"Q+cH+NvꝼszNT}`SyF@5!-ڇʿ| d,7 orjV۵pt:˝;k[rJw 8ajUNAPPy#܅Ra )x>qH_L-Z PdktF*k7pQ7aњ$R2>5lT& GZL >Bh-r#Jqς'M.)o3uGq־JS+-iOwnI'-oJ[Y Sh `*(@{aGd,pK%0ۑ~>E;P%TTWi6` yPb dVrM-魗'8VKA'bpZuoM*:FUZ]kW} vn's 䐒(kΰic }0_fnA]7r za 31֏Vll͞Qok8DKXo)e7Fcg[jN5\_ʈ'%q`Z|zΐPmq^~3PIYUcL$GJ8 ڪ=G HyNj5}>-/ĭcC%u8舁&O(c$RD=KO0ߖvG_S:IPCp IV[5WX%`42eG}R06I$6ԧM=-wJYQ *!Lݎ )d(ZD7>8\vtny+tF=sNm08b/Sr Fm;Rƶ NwϫJFJ՟T1qJϊTT+Oj a=@ڦE=vTPvs lQD5aE}Qj QH4_[˸A̺Fڕ,G.zlUWڪ!ӶZtwIXIHBH!_gw0RwJA)eKŜA[f޿`gxF0SBn  XXrC/p rQ/_u cFG*] Tx8bF%ZJy0g)Vd*9 Rkw20 % lU&3 "5ȜBͥ Yafnɍ7cZ)c!L(=LL\ZC3w6cY]*"F[w/Ƚ"$<.Ӓ\FWiƃ\UʞXz \QEMwgőMo!QoTbt> ނ"Prj8^U{=h&L'eL,CL:O*&N͗0-\~|"Pt {*꬗B]Ld.Jd* *cx{&ߍD J(`Q{kD CqYa L:*izpmmsn[d;1ZF*\}WQ4*mwAE(.*^ ވˈ;@6<5Y& Xp, zf:ۗs.(&Wu Zm Yf'ta?ɾgAœ+oVѦF6"  Uɽ]A?12C$3&"SR3zQ9KWRΜ8~#bPsk1`nRYIuzUCjFjadzaMcswglӷȾtMM~VWjko}6Cn֩r܅6C"\f VIL#HdNpnL-YсG8.r6l%<xyl .MZVqun4Ly~S##k'UBc>n@ux8У~ c{Gv2;W[ttM hdUalyuF@5#BAV#?~f a8 tR;-)*, #fs -YNIӓ<P:2`&+EG£اD%ZU0d^-0}-B[DJBb+=Oퟝ6A,p<Àާ+v~Yq9_fP3$ U2q9]$Cc&hةn(3$M rLz9gڵii3ٓߩTb834PssZ.J"TRKMU)hHH/ӑPBX@d.g_)Q}_՟#oCړ:*3sr`:s("3c%VlڗX:x.ɶlonrlpF~I61 UZ ML"4z L-#9w"kaI 23jjzϏ^lLUP峞bzHiy( u6)iQaLj$,R1cN)0'x&&e>nu(U:~DNcDCjN*fDG P.q  *Q9kӀ;N2~O t\~aT>7&cҖȕ;U#OofBB1aк*>'Ynt%]E$THТ17JB/aD$`/hP&(a`V)Lf5xY”%\: k@2;S}¢1u'/V䔟0RH6U5 ߀{o'w&N*.F`>{-8S K q|L Sf'*S{6ZڂW/@jzBRq(q6F/aU 6|֦@[QCKCG8]0+n! %{$$7i X ef^3ٔB2U܄Qxۻ/FvEr٫bAJQK~0 >:2Ii%ie4mrB+j60<*ۓƗ;P\ؓFXîj37O 'H϶vO#MvLYɑxq{:pS"ڀ+Wd J1 )|SHT #J@:\Lq:u*L:Yǽ%Q&Ǟ[?Ö5e[A [PFD Kb#V+lWK;G}s5\x({QG./2# ki]߷B}"䴝XcS4]{صE%u}9GE~Wqj2Tcy5{T~|-[usRb]nb̌|<}kכՃú25t:dP[9NJ(ω?kwN4Mur:/^ɞQ $݊CZ!rJ=QO Q 0{ G '+dCN|OX̐n@H hs^[؋*8`氀Ӄ r=|Sy*gžqj r|:"0MHBUyZ= q:IhmIqﴔT"+LC ݳR2=ޫ }n%J[a5m<̴,{5eaJ8%떍 ^3h1ʳL[$9A-#^1x] GulH+HnCUM*acC qjm2LDM~?FstFXAer@#5D⇖PFE0,9^'UPiՒbW~ Ia`pHpRv9ouhw]HģsO=t?2G5`?K&pi 1/]̴T'eRL{`ؑ`I[BG;$܆"mqT:lVT{^7MSrrOnS eSHt5L@I튃1=nSJub[RlwE9Oi myuM/eT.@_^/2-P߼ )i5nh hBEB"() m B;\?كKΓD5GC;Q) 2VWƩyEnUz]P¹Z]p{%jФ{ح;w6YaϋzZY7<\ƌD{mZWLXE1ZD<oߏXo4"XX'a>78<|؅VYj\+ , T}{%NNN#ޢD !._Uw7LI(̣&JSdm?%S0lFZB&(vFs_?u˫@G-|ݚSbi]{ NqئYZy氢qjΑˆ1sՄڅ_mt| [鴄F'$!Ods]\6J' ǍQn+L m9̂4Qjt?bՈvf ZցUƎi拉U/4>(5ɆM;,WVNnek>M|E%G <꾊 9E l< +ZA  4CU_xeMB SLE\ ddCɪӥ9l h8R͸\>\*ۀO7V,(to,)1X<1#fc3~G׏'Ņrއ@ͫ"Y ,,k~(>pFߋ-AX:d酏!D\N??]FQ}#"ʉaC0:˲5[ UH_tM~kǘQdA!F O]+2&(2*. 'hD:*3]{AJQLS^ zNSRC)LKM |]_A^ A]Dc 8 <˹/>fuD_z*?( g:~c:`Ў~il#fDes4/)1  6 !'EqV'߉"5P֚j ș1Dt5evUisXXcB7X}HfYy+o㽤 +"ȝ@&U!JI%T̹:WJLHmЖ7xͩ$͹{AfGX}O'A|.Aev9Ws1ulyq@!6ZCL/bOx}>7goE% tHXq[gZ1$M֘ M"dɸ)pL;F=$l(ȅ#BҹEYi[6h>\IZ2pK$3 P1&3tbԎGi%ë}[iRB,vgҲSo,GV,jImE&Ŷ?Uy+f\҇4dYn2 NBifŜIZ٩)&|D "+'SdIeyĉ20.9tcHXdw\2gZLϒN#JRL-{wu)㪢Y:d 2RN}jt25aw]uy\~؜JިtH!up84"W-e#9(ILD]S-`aE/߾MiTS)M,n$ZK2R)}eu[`;Eh UseڴhPU —CY㘤ܰLB5* 'P&9O7ᚨőcWjSmu~.ى;o_m=Je^.3xoWu/ucL0)^J 3;;kmT|p?N b>^.dTJU-c,3Wi',;e;ЭWfla NWh_1sv[ м6%&; K%0PN!<4${a <*5tg\8 .8I9Z 92?UN ɍ10/V,ꏆQ}PrXe_fnvwo1tV.MN4u-_e}&Cٗ0G~hlA/B_^rEow_/_ȍ/:'ՔpuXP hS;262#XfAߪp+S,d~IsrRWf}3?"G 2c;כ]z /٩ހjB2IZCvɣCL Hm{.BW :ӵgF36?{oMtTɸmIT㛢Ģ)^8Ȧ"fB&*j3D}R,g Չ(6CsM&O&f!5ɥ6=5W=Y'T8Ǩkp+H|c6N2nvNtyvǙ/(V=&[2iUT#L!'pDARTT! * uL۰s|k5__j[?zNj5^9^dh2hs&VdA4ha>,sޅ3j^[W?-7fmAOFpnxy3(~<HlvH;]G)Z#tEj=E#Y\y#8f^%NC>ɉ$Z[܋qVxb/%sq)cjhr'be/]"7ɧ?8mǬFD C0Zk#A_Z~vY}1r&[5E@,.QԪ@z wPxy2iLXܴn;+-WCKd~uozImΕڊVY m wέ8IChBAgM="S_}6x1iIC7-Esd&տQ&d,y/<Ώs_kށBbi% -=su=@;Bc>y tVN9i,Q24yT݄h3N:ijI%GtB'%?h1`\)} 0]Ny&v4S=y,Amw9.-dZH:ꖔ֠;]`BqzgVVjǮZrc?߼:-=/rPx>P{`P! ]eXAr'V=EJ9 fEWhz?`'0*=ʘx)d1F>W++? J܊[{sb08%3HW?iSs1|^ӡ'H#SQ [ c^R<8t .}B/ͣͥg60h|c)N<*Saۛ;?ô<a`lJtT²[%uQxqn7>;[b q`ԣT m %-;X6ܞ[ ]uDfA -:fS Db9=d!岺%;0ʘ)F!rDiB <:a04*Nkqؕ`la@;%Uˎzn φK6^A,NnuO|=@Dީ,`\M_X A跃+zuA_5Ty2XKCXT3͠*WWQ EF7682#e`K:% zSPLWdzWqgbD&Ogbe(fEQN)aQMm [gb p77&;D?eRJ1 \jQoHZl𐗋cY NO.{QT+9T}pKp&$1hEQ32c#';h`[ǣ+vN6QVbl?%1jn#%Ivi/~ŁkN%ͷbaCNW[vyN mZ|ɓ@͐-Hi9mB IXnU:΅&h#E8ܤ<0T'~8[ ~]窗AH"T҉lD.^)%P.YR]#0DӬ] M!`6uƤN{ԑ[<+5s95b&`eFX&]X߮Prmu =~Xj$U2-W(Lo*98ĺr;B{([zNcJCOTs|UQuȈqqȍvb2ʥ-_ 8pv`|a-)\܇?9ޔ5Fhpn ;rkq9xȺ! |33ns/ⴡ^s{(?Nɪ%bnĸ+e>TѠ|')O0$Δ /8uM>ɨ6^r(>,&g QHyrBRuߦ>O|ޮx\bzv4"I ձӈS>s%#m'Y0ʉ΢~7,a;zd :crEǃ++(&Y'Mhxz!-۶Xs,:NBK_nΘl&}Ѻ9gsK:'TJ'K.*x*Ŷo[&P8џ\KbU,է+kkXy׫,%髩+*kQ(,%1?x6ʩRہO5q m]FHRjaǍV0 D˒U ePwT^D;,G. pM7UمkW]5gS53;zEO#[-X_mAɸ#梒!9KvdO+8UgG {T=ҭ"`O\ģ'N)Mi4M<<̶˝xgjesԴyĿ]6wPT_"LRbToǁGcpx^ !m V9u0vD:53&aqT>zՖ&;:ҋe%]zVw^w@'}^΄[]|9k$Nԡ<;~&;8߭sg<7ә<ީxYr|Z*rMJ|+?kB%äFĤ&USkL!V4՟My[W Nj,Iy%΀@֡.gSVKlW >:oi!˨ e\^R)cfBȓ$)KkŒ+^yn"d-S6w GS{/!9ɓ3͡S4^Xy"4)*4ri4w_4ȭ=-Z^}7V#CӴB:cXfxl'鄧Өt*8 ¡ [b$=]L.-UjpvҼBre@)TT%ƴ ?b 8# #1_ 0d]B$]0=q!9X3m 蔬Ë@bZ${}` Nai{u؎Pv0T؎qdS'|}`i?1N{->}R[=&x4fàɶH?q}X;I%c8h-}qEF /.NZ)Ɖ`6@r!};[ڢ#cfo:BVп`}@p =c udx>ˆ@Srl:8h /S B`mIpM4sOF<:DUҿw Gb$PG: y*;9LUCNRfxLsMyC]ae#JΆfխ>e<`ﻨ"_%~~.Ό#['sģo2=^Om'+{j`;R4EcN\B$gZQD4,s@a`bdOSAM;/^4+͖pV 3g !a35: z c G:eH0V]+LĝVid'0;V F<@vz00ҼBUrTr- ]tg 򔽡G+lB܁ )Λt/jxe!be. 'wD?6uqOĸm IB&t\BI`]n*F;+G*4BC|ӏGBO$@:[YT*JNgJQ2N_m'gFRQ wF MG93DXꛆu;H: R Yr P :Rw0 T=J}1*+R a-4), hNNm A<']BNaԄ߾[ zB8@$)ň%w$q fs(+8-yxm-Z+3?c\2|ɌQZ #< f/uUd:0W9A /֨#:csl0] !ceS8EC ATzaQbn_nsS8eYVIe%[/J^ "D2%R e!kAn߻R ieyUr}gt38gS6i~򱲰˚OƜwXeN;VLY'nV; x{9MuZ4;n\O:so.}3Ǵ4P1a?t6 `& phՔ0|!1#"$)-3Z[2qF~d4Q&ED uƫX y_EY]]dFu\K@&-9Ix]Qk~!_BW!$nkOs.Ձ|9C )E9ӛ <\0\aRQΎWt*OP.ҙVC`1 đ '2aiOÓ1#iPE[{!H1ЄĚWA2%Q4 #1Ta#$IGb6W9FP-9쉌M[FX#hy 7J,ZJ7GE(??h7c8Mɥ38tWYVp(T .~n4yΞJb{J¹ΦgRT/Ӛ#=Phlڃ T>jFՅ=nj$*nD@*nѣphHh1@l`4PS鰉J.*fE(j3HxZE0\g#HB] Ҷ0 ZaGP\Pٓen&뾤x-s0ŖyXy(G=tX !pہO;359gQMcںd|=hXq)bk_`,ib`̣{gl nqfIN$N?L,ޣs),9)ٵ7x>i~\ &3߹Qg|iB8njo}͝F$jYG[AUeB`>&r]+ĸFҼSm(P[Y{DO/V3?gOۦLo#!sN w&;{mOxF?:SUMƝ$VɮevGpnӗ9yAZAJKI.}cLn8 H6pٚxI?{t_+z,fN{vS,SXxfȚ}¦',&1zmz/Y ,3:gr/Qߒn݃>[g&9Ȳ9V8&UZJqUQrc\1)0`n⨡VtGPEZ+A򎵤oD/jVF;ʊɀLEo p,UI{-9}X i6)csc}z^өv=m?j٬(b{p{]7-]3~yʞj.euWܛ-v"ĉt0k2fnS v03t:tձL־J//Ӳv{_d77ͼ:1P"8`W+*^7iƣ3a(Sgsfwnf:ZXZ˓ᰧq-5-9$cYT''ЕOu貢Ӑr_e̊j7STLל$Shd24'emfdxH"V'1+(Go*=B?==`c Z0NNT,{BRb8-r#r7ckWZ<9g4@*Xq,!`=kjB̛06tgūNIX4;ۣ \NStC(1JZ{*98R[lH_kۨ#+KsDtHY.;ᄼ=vŐ0n B Bg qėy{<9,VѩjCt! T6TD)M=L ;:pLEHvF4w/M!6mCK4'Lr&q/e"'+i~=g'àbQ0/7,|\MQl޾Dq*j8ɔý1KJ ˤ( ԩH/-_X"1Jv&.#ڗaYnsVw wځK[BםA-;gRO|҄Simz齠9ew w{.vZ?3h .G'Q럁&u+˧v;e,b"J/1⊬]2ծ?LkY|哉ҍC x@r8'O=RJ8'"Z)oZ*C!YR(Erwh^B)(0kC qRb#sG e*''"e-i(;%ctvn83G7]8Hťjl%D}c钸0ctMJf` wȻ"|>YrPΖ7$TD/d2eO 2cx\H$Id^Kjtj|"  ;x(e9iYo:|8>|{p N u~p'7(PD-l)q}\rkp|Z ߖ} ŻOģ6X{=m: V-^Z@n2`(Sks,e]Rg@J+F栛*DLya0/(/ˡtnF@{(G{̻.NsKz ?bkb}>sN DLuʰ qBT%"e1朌C3,(YԠD:sPw:ð*D '& <"dm2 -0pbM?JtBN If@LsӾh%Fy@.%i~gGb UT#N#D2M pȢdخrX]vjP >q! &q֪xQ jՊ~T!2cG4]zY~+?Q!s@p vCn6N`|kSFDUgAmɤ]Wڀ9es<8 {nT[5w\HN:5{9˄qYĶ3\j\tץ =L|wqN<ڤqbܒd)ӟ 9lIC05ZS5q4\MMb-L}0M$eu&C;-OR\3usn1MyTr)=5]Xg$$*(ŀ{C(N}dLV PóKQKz5$r⚈[a`axu P1ecjtE T@>s2'Ԑ`9߲NrZ z2-S/J78h ҡ<#' 1c#SG)^AGbaǶ̘ԹQt 䱝D`1` Qѹv>32oW߅3"k((F "XSX=l` #,ɞ:TEdɒgLI31`PRH20{+T%Fڇ/aӚ7zF;&!cr x,f)+$`l5\*)ݡA"c~Ʒ$Onh=(`9s%Ѣ\?-*K5 ;Hsv=EH_t JNN1dP[1b,"$[N5N5?!B nl;/;Pe^Tsv/|tzb4kŴ 6xQHʓ \PaHDmⸯ$hJISkڣqj0ZQ.F h^ uh5zoNE1kqn4>-VV-9V:&7"[EϤ I.ziYfh"јΖn1 ÐtqX~捇O> N\BȘea GrmI `^>&ޟZCLSbj0&-el iD؈ÚM̹S_ ZbK!C驨L"Fat]1<(݉FYh$+ش>y+ '!{Te_+ zZ`~hG&q^ީg=7c^_aة2J?ll(ӧz{qᣨ'G;—fy} 7,T7* Z"嘐i!j2ޤc>ZT \*0)8P/"?NGJ ]}^I=H6 mK0iV IF-.AB^+{ *GT.ctopI?8QNP* [8ToVNlV2weC8>^~ 92SZ̿:1ebLR xSon8e+ *Dt#rz5cbpkCb M.`Pd6)]qZҔ1´,k4I9$ s]#W=N% &*J(w rzTmHreg G_,yO0[F%Ă_^?d-úr4l\.zX 5myC…G4[wIՕښ8 Wy 7Tuf/9H$Hwд]w.%z-avb戀OH9=Tav$# =*TXt qTn<3BM(ಠ7KI))m7UQm"6t¼6ז A;YV-6-`]OeG={?|lWɱv ƹ:{pʄHWew -?kO3YH kT6\-: $ =*Xufa" \oDɴ΍4"ЍhF΍„t+tUr6ܕ.sQ>1:~UvT6W̺^邶 c삌mX \aF`iY|F!nKܞL+d\tcQL} kKl2l6ؑK)(YC7j>HY)D[4[-K,W [K",ng!}oA4]+X&ZE?ҕTfGp:9:N~z԰ \`5l/CY_mX%ʵ ԯmƢZOK(?u mWZEYЅ= `J0p7 qW$\vƮt3[O¾[{3Stݝ4bײR4]b RQFH,_ !UPW(tCFig$V;h7 ;,-e+k,>AϔO9wo( 8E$YJ7at375˨5iMFRV8Hŀ8z^Im{?k <;!PhTvvp?Q ƽ 1V̉,1 D4jb+cu`fzydZa UW%L @~ЀUD?U`X*t& \;K%HfoZ5+%)YRЍ:@Wq#r땰 ,^MƆI}NBLf),0!i1(aC 0S@ 􆌏1CCb|7 {+c rc`A5ڀ"E"i7Do[ؿT-n[D:XpȊ@qCڟ!{-h]y083QrGq =-6CX 'cnqvEe,#ZRNj E E7$IOٝ2He 3tu*鷺Ic6<T8/09Bs -lqsUAS)=k 0g6+v qʝ#'RJ8yidm<7Ra"?bP 'mgZEZ$*\B(F;Qh+I;д\ :VK|cs`}m z>v==y . ي,/@GV;>^}|z^[H$ṿX$UU ;,RHzHѩ6WOsޙ2aP/&ozw|Ҷ"~2CIv\%\[?\g akCn,riVK0 >58\h *{$Gu7y 4XFM~wI"{\GӴD, VV*±agk;sR=?/}k|AmIO?7cRq&٘)҆S5 tvŢ'wWV͹5Fr,؄ {`*LķA9~rGfΝ*]J-#8?TD gmPΰG @:)sck*=׵AL#)g ޓ!ru#}>Q'YtεuA{~=퐬֬ q|\RI'Y ^ssB: 6^VܻFT5s\j0|EXW$U8C' +Z'R? *dފz3^?l-cE$m3ԞЁ3dlV{ }X e1F/kv0n/Qi|i_TaJY!g;~x-:{a_󳊑CV?8q7;'%lo.XE=,8e<6ٸ3r[ٌr}AͶ`65H1!5dk䓫 D9+0FIXè!LsdMFs׾ynjrCq%[JgfqXd.֛mÙtbsu@KWșt.%N RJ m+*gVgUA#S=Y'nkZ,#P4IOwnKAH|;0Q y`qBNF gFnGg)jS_U="DEfJ/C "v^jnʝ`ſ"`C.n!:?9ab#UN"OfNb8FA ,yt.YOf誳PE*\0`4Al-5d% gO#Gt8C7`DP.K1Ql`(+ÔF q\ď\H䑅ݍ3Z9AL%N7V1p`8s sбKqAOJjW),yꚋH#RYg%D̜ˏVؿޕF@!xxP`7:ޣ)N3?M+R> nSy,N :dFͶ?_9[,˷T9iu~?Z7%̓wͣ7i]1L|Hiff&_4 e4rV+e9k~Qܤls(ڍ̆~8@:yO&iسvZh֛%d nz΍knǬcQ·8WYS )%\ 2b趸7f_GfT|Yun?0TJ" 5|tV&JjJbzdql1XO5?\tYʝwr\n9 %Gqv)7STLo c\P]XAW> * Zb}+j:Nrɏ(M,Ƒvd>hcJQԂSa3kHGa`66`NWF~fԝ=UgN8 .fD@/ ˲rtD߽gĢ~?2Jek);RO,~!EKWۯwU8#AZF;zi(:$V?JšA$2mw#'HQ63ȽHqP}GT$6xbz^Jdg­uq%{RqO2F0cl*l|1v\yg$ uKErq-!>g蛖қLW0s 隢r I!xCRs'C|̍F`xGJ#{-Fw/ W)IJ0i%M~Dl0l ٪dz3}NyR) ~|>ěg! MfrVrcC3{u}|XLAΒn>&A98u^7߭P<]Sߣ2X n_{H78;칙&qAݡ+ba57G2ݝ:~ wCnJmytK+^yh-"῏]4~u+gScw pcu<^d|ŋ:5䫈 |Z;qRlsV˂HfJPwMm\aiJmU`7 jx+k>KbU,է+kkXy׫,YSb4ʯFK9sT zFT|9(#I١镉6vrX{kmǫVCD3IE'舊bG`4L٨@\gn⨡a;MigF!)U h3(fak-6 j+GNqP+q55Nٵѕ`S7i6U^D&Քx1@̅(X^u<x]}󖽍 0"eIS)J":F uVbp32RF(K툆a@NJxdׅr?ܞNoe =ct+xlр}Ʀ"/MU~J@͟ԿdFbcՈQpvE_ _t^EID#=, 3Iv\}&zZBOMg7S(^Wd( sw *;P4qn&73S HJaRĝt#c?_V(:RH1Fxtb%,S qnV0xPplo7B8cu sJoʗD5TmْPtRP]$ I(|"H~EY c1-_.T~?ez!;A4;@uPOJ)_$QI+PƑH: @k|B=* ]TFhu(6UG2ㆎn3@RTqXf]=|}2Fs_~K!&B*

qNNэOȖտ&zs1W7S*߹tl7۟Z+})R3Ή{O uOjXģ'$·aހGYN|&>x-זWJ_,'뙱QV 26vo(̇B0&/p,#(zrJ.kmӪ-O~(__YcW. zkLr v6Y<\[]|9Y{A6jE(S~S)!S4)`u/#$AԠ=b3| ;ْ ;@ '3qlZ6\NeC ߃ YքsT"%7Kp8Ꝉ xB"'o327Vw 6%+Jzz -x>kf$3H8pQ}$LLGVޏ?ٛ,|G t"(@PqRv8iM%^WiV9Vf S=YԪk0F-娃Oesӻ;%঑7߼92a?'ƒZ^0D+&KȀFc{E#nmQմz݄pyw=sNukp!NYdqL㑚S,ǧ ys4x">9j܇QWWjO&n^b'ֶYv.MQm}+ٛc7H[4>U6lv>`>c و Ru xyFSI2mb4zY>ڸ};`rWɞ6o}L4oz94Yi]>uB9> \Ec$&?Le6͢trA3mŌrk3E6139C -j@ R9b̍hE|xxEGԧ B0H/g5zV]X*㒾4pqCX= ]شړecq99t1FFYodžK*6y0/1¸yzO'\fڪZBg/awdYCX6SǏ2Ο '#5ŕXү'sGsjjn?^Mxg]s Cӷ맽Sy>{` T,'bFZJ:ioV}Y{GEz =mѠ[M8A/:QVpht)Κ`v,Y>%x8B #ª8KB?l9cd{ԃVg'~ Y,<*1ߟǘs),9M\^\1A9* "N&x9rgnTפq5@ i8R1v,X3g+ 5(u Js<*%Q65Z<L2]\FQ+w: "BV2T/au)tËOeI=U&#}ف'HJn1gg5sSx?brPkRQb-'$~E)dН^Ygk 0W߼zU4xy5n1=hYo:|8>|{p\̅rʝb,B\ԍQHqc7 וՒw-+~h`]=e0ցIv^]92je.ŋ@¢I02W!.D&!F=`bqĻ^t%k/u8E|jz6~tϷ_syAN=EݯBI7ؕ_6_e?llx/Q;/ev6B,Zz}άV Xjn^҃vTގ_Yr #rgswseiy`YB0ZnɝIPExj$[rގ)b)(cTc^1 U"9ך@33t 5 ڣqV PF7G;_l"<<-zhs6ZIv&z1A%IwZ/p؜x fM$$58hä(`2SiH<YZ¦ }H q6,d+TMWPP (Q2d:Aq)H K!!:BoK:P~* +Ǣ0?C1? -[9cşY3ILNK /EbІX~&n $cpPp‡Bt xl? ('vYF/z.Gp q~al*P ~az*3E0X\|o,+P0  { WOةue_SER`b\vɹ?G]5Κi)bbFRO 0:JYC^zuR/;`{`i|mA9E%5Z 92q%O{oX#GZ1fS8]LUߎ!a`(yQˋR~w`Ѣ؇oHo2*. ќW̝фۚ93G̾qTz]vN@~gPݧ#>v sBz uWJi <dZ@"Yb;Uo(7wWq U@,Z%ZZWx,!&Z@Iʇ2C.qN̓@c#v286.7ct.5W=jK̘9>9dǨzI\ Xv,&t U٥pIur%[r&ƽDe qykY||RN}q?'H cWqEOn qq _@=Wd0L.]G xWnV<J~+BU=@ƭjTl_ .LO0DMDSTN_}[Q'BAf8`H8x5DK ?RG8OxN6TH`M)( kJRE4ţG@[GG8%~;x''#J: KXPX-kQZq2PxA9 tza2Z9܎ua7FmIؾEV$"/?ԶtWMU% h k`jD?lS)4jhP,~)ɫAY5HS :YՒMsP'!}`;hfZ绬l4#NEŽEM#Mk<}KSXaOjO+tPneEr:'2%c@RjȾFO.")!>u;!l\|sA-eƫJ+5(F72n%wd0}K2@puKQy7񷋒JgxK[Js#EmG9 ;K: k{:,,tBɔvz{Ks gjڵ>K•Pel L4iV:>x <$Gͺ.bH 0>f|6nx#Ӷ0/ai6t8 pw#z:-xz $ Q| s`10F2Fa'C-2`1Gt̤I7ɸR[@R^+ԥ f oLj, +U&v|d4ӊ7?XǪL\-Xx`x2@g%diNX PN We*=a_,PHA8L+nA3ɗ["1 3`vbIqoX0֢i*)5\+Lpy'vvHvȔnM6ɚhӚ\:aYQO4,TFn@7j:A"ȗc*۬l#.UL>E];GhMF#%7G|k6 ٫x'K$\=ֈ/ڀ&TL־l޾%sS2 g]#-dhMY} >$`c+UJ[ܬ]ʩj6cK!Bs`hC 9 ~N2HRA@(KG!cO`2̇]/թQ*;j4T~KQ dZqK?Cȣ6>vұ_P3x;?!Ol? gls6<g="c6o`WT=8-(R E@^o<ApQInQE=SjQ^hqgŗ-OW*U%-(~/f#jvZEޟ! .-[$I؂{+*bey"ޒ;92n1UPo ̷Xee Ḿ5~]m)TDvQہC[gBYitg6AN¶ՙ }Kr˺At2G"Ĩ( 3)D|k#ؖB_Ջ z!J. 4CA9(oI{K?֛W)05ڨB2}䋊j"~'EhVJJ}ژiUu3{_w"=tn0ЦL[d{I4% چ㴠7}=@>P64H|B\ _4Y oSW_.-y#zS[#P[dԈ/bx`c$Tӡn&Q ~!(8L@UщBw#HYYf-zد\r`G!L8QwPԢT4DQ&yAEs?'KVXUfH@jp&&@E@2w82.0k: QPIFo)VbNCԱ # 0\Ql,DNw !pX% JtJߑ/KU4΋Í"L7ąгכ@Oh1PY|[(FT؂Q!נ_7P`%N'Hr}ʂ2(G𭡹X|6~l,ME |Rƥb 1 \Q8}?)c0]zcY~o/rKxtݿX[:{K(gjcOx+מj,y!&ճQX4Y @g%B:0= W$A+ОˡzVxKT)Hqr.Z:^KK% =9;:QL'Nlqc0#yFiZ6^  3HguVy$V Cd,ss:嘵57UȪdQsx={)P 6?50'CyE{2q|n)Eő]e$ 8|pfGp~a y|d %`pY ? T֬e^AP#;Շu6ylxR+hmzm.Tw"ֆhVnE=A GX= V(robSpo=*$; Gb5d¬o%2'#ہRDT(ᖚqYGTCk`^gE 1IxLH6<8)zD@)+A-( 33Ff#Qfܜ$i~-W;O\glIaj4fxT~USbcU}"TcHAZl?oa<\>){A Dv}FEPb2j0p7"OjdY$Z#4P~DhW>`LO^x9Z>~ ۸Ш|hd`±)c9ۖ.9VI %ksuу *@iAk sl$ 2ro/œjme`?˭uia#QJq7:HuX[ tp$tHR1S+ =ey\[oz@Jtб~6p#x~.D'ZF`Z'*fD+_Z]3T&9mtMsWUA= ;{-ÂTaLhe! )U|]9C'-ȃ]7} eSXn~ϯВH &&QIcYE=@@\ a!%g}xHd誌0(zg+6˗ %?ʿ 2t~tYxjlܸUY-;\ޡ,7DKCIA]v iZw-t,Y!I75~CY =zUc蚢pR׎1zQ%wIկuʓ?O8)³3 ?p;6@|x /]x%,T8=]<)oNVVrGeUɍ}nq-IB4 ,i.e;,瀾N)^:`ڋKpC/fW<;G}MVN=.ڢ'V-IJH|:xI!bf[]DDC5\G:-=-f&_N?;mU}S{4%خƃRwm34@3ܫkk?~>W7~zumU|d+kO2|qQt%Av{{П!⇠ii@^y'X5E@Do}^k 5x1qWD-HU;&~T /QDSMi6XԊ(Db#.do7un>ՈcфQ  :G -3!֍Za;dS D}iGL6@>=(# ԨB2&B7=r1E>Llc+ 9v?mL*+hU 6^n7«~)Gc\F)  T&S8˜]+Fq}mJ8ԯB8@@xlݔҖP۽JOj>Mlв^=,;vBB $lIli4Iyp}w(+PFc 08Rl53S d8<Υıu;ɱg4U% t^1Nǰ|;٥stgr%ZK\ [Srr &HR6z@e: c1]Gx Ǐ[p]\h7F?c%2n GI9:6P1u=uZ!fW&I]p}j/Ht Ph !bpOkb>Q#3-E*RJ:L $GL6F9W8tWQe_s@m*D-wfNUkP 'e$oſeazҀ7%xǴHb! }ჲdZ~l>  FÀAR ˂8JQ|~AAn" |vגR'_Kr5&j9ԙ\VB;HFH`9Kk2FA=D$[pqN]$J!CMb *{^W)o04Βq0Zn@fL/B8sÀ8NAf/hYǗ#R34᪶@>(@fB9$a,BYQ ^Teaf2nK %\zsG@Aރ2/ ,YrGGK6{eCuً7u0\)BX4-2ة?}L2twT:ҚReF6(3cz7:y 9;MYh}^^5V#g`b}H0.#(>L=vF*GZ9ڴXG3h=eTlE響&5[ʃ\oG3us8jCz{~_V~y>9RQ}O`TٯW^mdoσ1A5cb;1{~%_ciIɏ' Jz}'Vqr7}U$;P7yy㐙ٯ[Td^DGî G\ۀ12gZ2ne\C(#ߥL=Ii5{g6lr&:v^}=+]jcɣq}NސnB8ao eՎ%;m} w 7;=>aAD&Oj#t2=$Yޒ@nbiQPvcS=PE* `j!i]0x-q V?.J/3/QzdOB!/Ji ׮ 5Ss[]x+YT:&95'p) :/hTXO>ӅGQɝU|sQ2r7ci&G70-1qZs3 u4JR?*n*QsN ]y  :ܰq(ۡsMu G^#㐥Uwd-t9 ˖qܝ/-X]m?:1RCRCUz'>hx*2u(B\b:ң.'9=0*`lEh> JJ  `ő`؟T^a L)/n\t8RK ȅ7O CD{s mcƞc2K/eD }Ja~YG( _{ l_dmNP{r٤ڃ7*IHLX"3qYhG%e .E9N\Vw;UCJz]rKbL>vLS|'2[=89 )v"/Svh(Ai B4B=f{&WX3r_ n ?/p sz,†tb+'̀1Cg 9O@m5rgc?3U3v OO|E)nJp|Eȯ.,dy&`vE][_ٺ[z0o(~]Sm Sse65+LreƯ.gNV{mXy.ROB8ht12z:N Ǫ$uܿct4Yᗕݣt'µ>&,La-r0}vwFin0¯7nSP1PxC]+$}Sh7zsɧ6zhD/LrT;?./:Ÿ-u_h idƿei@+wi+v:S>"(QcQpUTDV6Tw,71eCp^Dj2 ˰SsW8E5`ȧ/cf;r6>a@zM%$ʣA)ƵK6! Xڀ|Au\%ZgS#DSzF]<s-H ЌvA4d,O'4ܠ{z0)#5lE F+CI'rn'q@ӫ /CUI̵wB*oL9呏J9d"i!C.]}0uyl_DZs>^աBhE* +I9.p>g6pg-4l7O26<[),9 kԙObNG1Eъ(xsɏv+G) pG )<¾!λDte ƻo*;{ o8rw,(~LF#&ItpͩRyNƭ7;ۇ4ao;&k9gjp۩s;^.e(IcGۻ/{/ VuY/_W_%sl=MNv⓯}ʴIm@6ڵ ))K%p>\o*0RX&`jm ϔ/ӫnW^T_V^TҋܑfPm{S^oS5ʦ_Ba?O q5Rt Âv3wՄuzu72S=m7o*+??^X*nJ(WS?ޫ>s|m }M}r+I^ ْ= cESw6UT⁩8J*"ST`{"W}*\_SjTƷ#s+rzRH~KXbN UX,RMȡp34qKoPɁCy8D;fJ.W"}.G+KD#R`zP~~p v}=`um9vg:C^$'4tT% ?L :M% Nm<Ӄf=EO@ V DQPcQ z;'|Y,^calNNwǃh5wssZpG4r-c+ 1 pRS<[S"(U@yPe}7D Z5liԋ 4iEҒFpG_놗UK] p8iّp&9G/n *;/_m}Lslދ Zg1}(*{/x<{x$>~l_wC| -Vw}A. Њݝ7;Px?OHV/í|gwOjʡ8x{4[y({5pmAϷMT? ̋- m=ݼ8:/ﶡK?BTT^A/s`dmjh R=C+B5|h'r}xs@ _08@?0҄"/x yz$ ں͢./LW;-Ghman HWcnil사hG "k9Rb/0[*0+*BaUߏ/9!'ν難W\ R|r g >W'΅}m ^ux_VH%ie>ë"@DL`VMlN)7K̉I0W pV..QLr1SջħvSm>{K?mhkq -;<"/0!]C&x;.E]͉6E4g *TSJe37Dy~vOj0n?!N!m{"'gn{N eNO. =_JrvGEIc֖Ǐ5==?Cs Ǫ%Ffi,xNf$Զ'voUZ %k(?^T[Ϋ ڗ/UnN*Uj5SDqI7{j-s*"[ժKovM:'GҜ)XJ9> CRɡCW[nfR;Ip2葦 ɶп㷇d˜JݞD>ǻr7T3TA=G(u{ͻċO/pxh;=j*ݩ`?KK=?VJ߷So*M忩w?fĬtziVpOtӇڐ95Y8S1Gr[+`xW1WƝ8WQ7c >̥saq *dΝNs=ZLJ\Z1ms|Ai~ڤO7W[mÏQ"~ 5v[ _D--?n3TS>G=rC0!܃{`>eeegӝOw?οjnhtn]~ݣN5sϏ$u7^,"<]ma1&|h3E@0?1uќ,Y?ʮ qGDq^7l$UhUJWN'3hPxyFT}tNs@ZNF4Xd{gnR1*Z(l$?㏿ @9ӈg6 k=ɷ }Q/-.N%W.>Z- k^'u>+$3lHloG3)aK6̜Wă&\YNLpFRsIh XN6Һbj8je72nٯa=yP16\D0bA@aDRgpB?ՇD,[o>laE >-1U^Zmt 2m ^[JS6>cN7TRKy#z P7ݿmTw| /9@q-UJ,02wiSG^ԝv[eޘp:׉>m"\]mߣ˜+%JgS  F>/j_55t\ZɕxjكyW_U̖ OId{ffv9=$ďWLwZNP\Ab%|:nS /A 8 sׯXu\ݤ]F φIH lX?2F}7bYLqBd{= K<ร78nLnff15뗅}]/Am63o2Pt%!$[!J*LO^H("Yn'PuѼ$͈˟m=Gwkm@H//;0& j(/YӅuwsГՋbS6TAܥN҉o'fW>[ r,6]Gb{ƚeд@^ T@ JT6 yQyILxhdˢdU5ϺˢMiЍ9"96Ȏ; AYc|[^K]Xw.4w71x|uQh((oz(R\?2y֎ !K|SVd Sf@_3yhb)j(Mm\I$G!p|Lz~avQ?SDL˛"+D` _~]ܼb,^Ί?_,+$sA:'9 megMu;ȆzQ8o[CoD6í7‰m:6>Sia|kHXjtsQab޽A^;2h e{*4k 3Jn6Zѩl4BY9Bg!6αJ 6 cW!Cc"E2)GJu" ' w -` 'P+m묻m`iQTʻӟ&&aZ LŦ K,٢EιS/A OSR?_n:ϳ/_a[ |N+3[{Ȧ6_NJ{&`W9 bdu5/ѡﰃk\S*8M\Ne H@/]ffL·|ϐC[@̑lQ%3#Ln7TsB kQhIKЉ%-)yEɱknQ^E,X/;Z$4VWV]v׃@aTkQR',bGRPv=ֱ.m KprL!y`G GǕWpoqR\;*\qVPQu1wۅoodr_Ֆ nー+󢝽ZP+TUϙ]X0r[~GYnυ(nEP%!df^׸g[5hd0'П\{6@E|<;+RsdeSP_yx.WiF8Ă􌳢 g ST!24IѦou@  Qa|L6$BH{Ekz,GS A vACm_#"4iO _s)B.)sڋʀZm%&k][̕{^05J! e\XLZTp̯ʶLa/jj^7ŖD( /U 5 L%7Ocjo\}A2k\iN,W+!I. q-*~,$Ĉ:ABTRF~L#?ȏiE~:>˥Xqam$轝"@h͌j= a򰋖f"uGe%9,X u>mmؓo{Ւi,0CWX^8.x ālu;Beנ0O=,G!F".OR*xCAq@yXQΓF@wta4[᝷n ܦ۰AkB_;L0p T|#)Mf"_0tf{^սa{]Ҕ"hY;u#j -wȈM&c\Bbculh?m(a0΁2ZݬծvnB.p];~@e|ZixU[g6 }j;"Kڒqcq%s4a,JCҔJo4l6ݖ4rr(㚲٧.udK;a_b#lɿ"aݼ}sN: n0 ;d€$ E)8TkWqDvSQa/|媢> ݖ6{jC;_@;o*l8a)N?l:,5MA C ^a>!QOgjRqh䚇E.G. m'?t}cN.@i<1|aІb{wN/8ˢజ߱OrDŽHWs0zOqwvpiDnАHeף`*s` F@[ YZm@Qcx@}g7 Kt} ㉳3hΌzDd1WA\KIjv nw[T=%>ʈJLS vƂ{vKn{G! pbtڰ`4턔3_74r7|' 8\AJSoi:Iq&4=5Lh5eSTZ 2Aܸy.視,}J{߸Θ:^,Hk B ?s츇6=RiL )-3*m٬N;`놷D󖌹GΠΨъt܃ b;FT` n:,Q)qϮ'#P8)h!*(mQbL4@Otσ9#&6S$yYlPDn_r>%= ۭXzv@$Tu@W[_Nn 0Z9Ԕ"gȕ4p .(.xk06-$aukf5F}E!qddku; 28*a^HcIPRCn=A`ĊEafMnr]0eV# 7,W͙v8EĨ$(Yyɚ7#ؘ.ERch3u-EgczV|RmЄSRJ*rrv킰 m9A!T]k>uh#OniL^2]] 473XsHlBΥ2B xR(6y#R^Jq 8'1etp27huU\ަz  x B?Vdd l0,h~?̃k ="ПeDgK!3m[m7M̓B*@6Q'Tʲlb=<>?eqyvL3%Ӂ!V$gxv3B+!LM>ta3sĬ( ={|>2LW.<&I Ag9=o>qR!u)+=d7ա2el9uUhT+ '|hT2i &x?d5ܦk90AjRWQw;cmӬ#AK6ymMDF)O稣ڕO NxKo#/jIAZGmʎUd0QȞjd\]9"+n\xX>Ck&%#@Eo:ddQ'Ra&> ץqCC7 ^qqqiI{rG4+'%. b5|v#]T 4Z/Vn3N?ϻIJO?'SoP<;NA6,MpsxK.*"d :%>) =~D*T)(@ Bgΐ`8˕nDScnnLZCy0=!\du88bxh.;rA<X^(j' C-B$s`QTft"2s8}qH_]-hNTFw+ŒKnE4 (of{)(KW}51'5iȱa ʢavTuRYN- +#C7t+az&N%{~Kp(58+#'|+ONs! [gRVlsP\F!%/PoUw0uJjwA#$/đv]mF'ǖ.Eӕ#jh7Iuի`A6dF'> 4iMO0QNN"G/ '1ʔN^VA}'MQ8ODdNQ& q d!B2:∷\ad*ףes8vhʡ5Sޯ2)p\6ȡp&aq6 C9uB0ZM$)/]8 T2SiJMpJ$WmCp%~醔/~7L3S\/M}Wo3>M@S+ t@9pߣ#U,Nm5L} UJk:HPGlQ&h<% 5OxnNSjz̮iN^#-׷g"'Ns|YF ÌےQs= b]c(7DQVjj봅P`ז::2mcaiRzP,f-uMR'rSSm.F zkဃS3jCtlE fZ0vЊ*p5M ]wǰYph@;2bq?uT޻.MwƢ)0KEX;I %1Tڷ!CSE7cd5`0Wʑ aFWE*(Tqp g=0n4ɨ>3($*cXvA*dW~/ms9]eGƓ' ^% (Xayhqc?s.54&BurF\/<፴g@&"q[Y-}P_al `8c#EeކŕaVUFU0XPDu_ǏuuF_8v-c̊Prq `Ry5;`}_A<JsGV"$P\i)N9mtOaDCdz}C꼓y2uH+%k[׍s@%EŧR6`L1 Hltr#xݦ(Й_a9r-gw@[̇]Ior1JOH/ncV}Gqw I$CΛvrDg>+*0[q\dI ݰB*G.D3ַh#IR"RyV}ܻ&'B3 qex\R~Zh9B! opA7܇8t.ٹT2,޾G4!lm3!EBBԇ:v*xz#Ri0G,U(pM@gs=~xK%&>2fU{۾7'nZEGnc@rOskfg&냰g&̌3ssOx<7Dyyfqgޝ};3̌ï33|:37̌ǟ3scoX|93XhାǛB`X[ە=-|t 8j¥VM$8U6!bleib6Ps@:#(#A>9xY@" "(FH/xgNe=j^0n&,{lcA>됵cIML6 6M;m-\TVʷZ$4V>  K}?Iccd??~sXcnX$@7qNH#KPw,b pc9AD(7DAdA썄A1i18ÚSK-3YFZn`D/Ze aߢ,ZQ~$^Bt\yѬ b(e*n]n}s<7ͫ6,˄i+# Ms3F9bD^0|FaPFT%0)l##HLpi.p^d̲L'>Z,4Gʰw;U d6TM*絼$ s]`]/( a? P?A ZZ[n3TSn#K`% lGMxbry]DNrjE ZTʓU)aoi|Bte)&FsR;^I6SeJD+Q og1}N k ,

vd6Pg΀{P߃{P2t! Ai1 }P2[ vwJQ#aRn^Mla)KmNB,ʠ{ruFN;0hOq.D&28/T:@HH7%3,NF7IB;B: zg\$}`vY;3}4>#.S3cN{m}eV³wa3IthѡLeiP%` ٢΅;^t~NrhD;|r#@bL f4ku?H}F} 4K,DO/lk´n:2Y9&Myd~ߘ~||sJ}ܽ8 &cʖa?͆t,|"& ) Q)'@b4z ;TN{;QTh»GCHRv (2Q6jg?/e^͔أqޔ͌eyKWg7U"؇d t( 8߆b!@T>1 FbH\[ rM}kNekcHaOoLkD:Đ58DylhbjgF8>Mzo_pǹ+>D|z{sBߺin4%p\ %Ճj (tC=LN[YVm|TSo*7/O4S>|7|@z:D8T"$BaHl[-j<=ƒ;)5w_T^z T7lW_oR ,E S3sՌ#t-tb]5_ D_KÝTERkDW}j Somst6g }Q=z]=>S[:@2EJ%Y2\2g(qH"] d}%#d}f5.Hx4辤}I!qR>PE /M!{N'mn`ʡ[A>"=ʨ- Qi l߾:>;VToYҰg,ZLf|,! 1ݬG6]V ;M0 tA泰_.|1[޼_}tFVd",L}N'S 4:nsz\mMSD]Ԯ<Q14ۭ|ˬAX\rec #jXZJ)eH} :޿>ޚh?QxVVJ\Χ5,o*99Pj"`B0 ?nB(7!ƀIPcp#My~!<cqcw?Pn!bG${#/pWۃ{z{iyw9*z{߹݃Üv}ȋżxi{V9v"Kmا G B/A5( 7ms1M47M5L#>וLsm ֗m|TSo*fZ~$.ȅ`E q8,?76A+d~^,\ 9p}H>G&dC@n~rgo Of-yM-? z!]鮭&Г\ZHCFt:$n;5sv3yI[}`;vBgzplzV^ԟ)m^{6KJ  5ǑriԇX8w/oܧn_YquAX&H>@F;%w611naNq-"5mDXTg 4rn4gTg$;&w=ۭzU(rLr?oV~l_c0=nF@5?Fn=@3lj~&g _im1~o4{+sBLS+ 8N/ڤ⯮Ӿµ k6Wqi9`l_Š ;ڍ lf(Cv xƇZ`+`V+Mߊ_I}3-NW 4ũ%jڵ ԕ[a糓lBoVYE /45pQXil82qjmNa;r63":LfL0R=8G-P-os7 ~AQI&GJIJ=TZnͬYQ8˅x>H6/eaGϠB%DX=a,i'Y|ID)nD/ [7ikE{ ,@{)ҤPVUYURc4оϛ0 [4=qhhn%=O3p[[F.\Dz \FW!C\9˺w}M}GGt""7R?$="bqf ChE&Rc&Ȏ8-\ިVMAUl }Y7l\.Պ@bL/!`)lal:%:<ǧFhGkcoyu=~$v/yg6KY}ڌ[J(. T:g {ZNٌXxWds Jo73eaPNeu)b,,Wߖ8:Xc8v&ė"B$¡Ԫa%Yj)z,.$ J?\tU]Z]QBdTa1䋟Q悽APBA4VVF-%. ւ;BuY#3lDr,QCzw]D)z=-JR/9z, Aք8M*rʶs@݌B'mqOYmyvl;/R@4bފy `kN]{[N;_S/"6A +.zIw1\>l7WvG% 3c  24>.t|FB|&"^Iq(8^ZVBV\Ȋ+/"Rl0vŸ02,=ka,z8igG鷮dMv= W7IrlS nK$*վM5/4z\wD@6<yu;xZ!yuo{6'5k}yiumV> fg7л8z_0U9Yuh<ʣ67RniLpK1|4cpOͣM0 %j|wݒmIuԷG's!oҽ"KRt;6ϯ褸ϤԤ/q[hk[[v[Xm,߰,a0+~nc@Z<4|S3L?wcne!wii.E'J&⸆ݿ= gaPӻv$nxK!aD;_ZíM ^lBpϚGb&Kd5j9d}WV39?G'DQ(}0|4~N,9*(G}urѪ~yhlB;n 7 ~DCmL>X5Q=ѕIňd;58cz{j,G_^%PcReYg]}mEkR.u/s2hdaFzhAᡱn|ϵ?Fi_Ѐ?+kK_֧n3L?{y JxQ@ZZ) YRkk6MzmN0¿۸.v6;-!ˉI@ CbogFd >b.lGO"wnKÎ"v|!x~%NǍƇbn )v쨸זQFf Aj\_TS*O{%JѤ~SAy:X(X^LBc]OЉLCn;-&iCĢaE=UĻ乮rumk5KXp;+m?N,s0ڿ_j0F]rݘaMEKշ۝ KKKo3TS^ [hf`s &">52@k2-޺G#gP& [\>J6eo0}۠A𫶵ߠS!~1;)ziḿši@I~I~4Rѵ'EkOeRmG">Lݣ`]C M3gX+6hI$K'0]Ⴄ>ZpB7ʚIp%\بffD!#ff՛PnSE*49Yo+[]HP7>0&._& ^8G 8p:2C=4 4"K~.^V]z-MA 0X0`p/m9 58鶝"TBځ(,Wϫ$?ZN#pو>栈(0>Df&eavQ Pll2-f&S?39K'DD6|^7re3F"/Y|UKDlN:y`$ft0>"lԯ_mfTrf4KpxY, MqHRzwr+ΟUynoΖ6/Lsg$s#%lXx<Ш}P"3g?.6T;qz(`B~J*$  0.]>\7T_.zP9,6Y-COvd7Kz4nFܳJ1 n n0Z#<&s}J| ׃'0ZӸb"lNvBaxݤǕ@{myM  cMFb{hD9QoFCY[y1mQ-7sn AI+j:9 nfD&HMPA4p@ O<CB=__͵l06m+٦ūt(mON>̋9a`_:Uo-:d〒xu*lGf5H⯛E&\K,.B AVQP{Z4nI!A A䋃Na 4m< 0߼'"PS4₼l>܀P5~3k(fb- eӽW`wh`~Etq%be0K+YSxAfZmLt$vEEXX..29RQ (,YepQu[>aۻ#=a O~իIZ?iyRT4+/A ژ;5TiH" -`B֣P_ )gkQvRw7dg&ݦ1ĊdQMњT,Q$ttvi~@ylj[b?JMs 1+*942]% Dz%X6#ZFlr# q+!՜@{sXev. LU{ |Lؑ^W/W0LdQ{ ixt[Gs00Vmf::orq]J QmBV>h8;-}{ݢV5y ^ѭ xX`ӯTLͩsY:R/LlK 8Kwײ8BT@bRҦ !ؾ ߔ>kGNh΄y՗ Ql&{̩ȇa&yS0ݝíMpOYGT#e"E4izDx)2 9]T)+VOaX9Ț-^nBWgKQf*D7Jn;@ujv +ozq0p9B"p^v}`** ?kΖo!-m,BhaXɜ!=ɐQXR[?,XJrG'!tyGA tCj3ʜ71ނ_9a+lMp($d#)hS7AE  Z8$GUQeueDBL>F%nV`&L]~lvRb&Pf&;+KgZA&Rq/hEII=|>.;‡/f?ߞ 'sX~Ne5HL?XUم,م,|i?T+1 xn`J6_ُrzᰐ.\̎̉o[ruv .#e/;ꀼ2 or@r Ne!Eu,/acYj],HsEwz O"PչPB`vY4i a ymq?qPnHE[qM wRAr} ˶X䀗6b6٭9Zᆆe;fAK:2aDcπ! 8h!{6BW՗/>DIϒw#{h]=@LG\;gB6&J?>'MY išb2#%t(E>IN|DH M $aĊ~F^9Yd̮sذ j^.g`S={רPq&\iSav +JC-K4ȅGSm$g.k;vy3*yؽEFNWWAMXL]] gH8 z$U QT_""ZfBY p %p*5-^C`";pB5䞅$E%Gcw6_cԛp@-̡྆ۂin5Luh{hwڵvtwOk _hz~v^~rwV>>>,d{(˟o9tO?V/@\YcȳU\Nă٢Y('h95,hCo]QdDR uG \Ѱ1lBEi2[[ɿ2R"<_Kd\ԲXCE3[D|\ !0(| .<)X~bx&BOH҂_ml˪ ԉ>sbxZ^WѢ6 X0-#^n>2_?3%Cц댒KI%{U`T͌ 9~sef{s'H>65J6$0|A"EYiNW[!W S!eG6jmZ]Ұq8yѦ/ TkB+u-0dN QiQ#qahxV4R>C({D386##3q$-a$l-7Y]T[Oq^]YƹHht fV6F^ Uts7>;mV>Ϟdվm0lIg ŌbYR19#/!}ľ5{HfR_}|0?Wؘ#BolL 9r&j[Ϩ$]nSOKަ+8,uNJ x|3dCI_Qi_Qy_jJ*Uy6s]L#,NpZ~m⧿+z水ew[&[ȐĬ 6lm: +EgP3Ll uJ tAk0G?U`lvwwDE(āvs 6=eZ#juȁ(ht`/PShOjd{}pS, ?N<ʨAȋE 6&mynw[ +mv 8$5̧ oTL7ݣO {#͊&Ӏ΢i+ 8 +RN{#MWu Pn;ML:Pt~ ^j ).5vu:!d4FBn_R~DžC9h(U҅cZ^P@Q@bVVīcqzCxTUm/BHH-Hl4K>?8Z,RY$y[GZt̳*4Ա_RGU$Vsv}/F: -G@e /Pn lSF(?bRs K.&gS8T`ȯlPaH ~*Ȍx0;0J8EzqTJZO@!M>},_'+H;oZkr3ST~Dhwˋƻr *^$sܥ4l' f<@却KbJ'/ YÑI{dB5$DʓJ@ϲ2Ω g 煡4c]їs,9ȴ8vQhv¥I܁MA>6ٛa>L@LlݥAJ0N 6d0g^.ުm6Ul9neM>y9F]#)v;mI$j[zd t^hK=#IP_a$3FABVi#J-|~O D.anÚʿBp~¼,T+8?amB4$ a|rWc,h@;0ߣjp5C!kg>:&\۽;ڑ2o^~Uh΄_߾㕘, K`#odsWLtx4:|{}5y2F{3̊ԏǬ62ֆB-@-q;OZ9ndC $%Q?1=(jz:~eTol[`hX(io9 -zT^#l~d rMyFUVQ+bym&չeC{Ng*ǨP l+ w\6DBYByl=ld(,\FJ2J؅bb)I,r,Fˠ0^`g社Qds t#2I98Po$)dc`l,"2bT f“ cmFAo "Xؔ#!L/ u=shL<R61bCjXJ\*X->#$ֻ G HRYAiY HV%kE¦/o'#\Q$G pJ1BB/: 9HhaA#', tǀB7s|s񝝍.g[8ш*BǸ@7 bDR>B<ؑZ蝾 9W7 iUӠL2#S#i(DN3yz j#2IWn;ltȬۜK[TX0k{ :yo-Lpjl#ۘ~`x`ID3~RBD[G3/ᐘq8| b~ '3*_YH L<IK%XGPfi.:N`wOǜu-!jB X.MBe&Iv0?D(IF~ z煜<^|J3#N䧴~֨TfFl=#Y3ң K+DӼϼtmKRq\xc>Ugt46x<XsƴPy4mv4 m u ~k3C^7&Xauf[\NB^-7]8]s.#%0Mu)i 901]"ZVi\0S.L9Biaq+= t~tU`˼Z` ʚsD/@ht=}"q 'h~K^]U` y8/̗tzCîC#sYQS9&"` 8 LJZwkbd0rxN}훲x]2!"#s*:{@/(%oi({s\FՌOJ8cEn: H ş?K)(>{?+J@,SX7hţz(Ƃ` >xĢ'"P Ȉ-_ғg+%g9L+a}!MM?O\oEdg&,4ݔç@MRc9P Wjv<̈́q\$ ˦DŽ#0]c# "zc3ꊬ6_DGG,C! @z?7TG-zD(~&E,vvDn:ya@+n_n3mFfFxD)Csj{W!t(oNS%ؘFAZAfid$:/ !W%rCO)z:=| {R~yv2哌tX7xWJ!PY~ s?E jufp MrħŽ'+"߮KACZKrJA>q!2@aaw~np̪5Z\JQUƷ56郊l.WwoUIF:ʢY*E og@FyvIc>%jㅦV#f.4 )naм z`l8\!G N8GAb-FS *FTvYH(3 OZd4pKYbʽ' Jqb+B&hXg*ٕUY /H"d魎&-n7\=7أ j΀;;90$(Xznyum G:Thc|q*`&ϙ{ڙ4.ZhQ B7|ciIQP7jRwU H'QEQ4D8zM,'ޣLiW)< -SPFBpz=M!v7w[Onh% @MC &jQi[׉(LE >FPpXY`(:)A-ltP$3ٕ(o Qr1yiW=1JZ3~9,6:m fݧ#N~% )viKCl㘱ж>cbz*$ͱyYҵ)O\0F*KD!3xb,ĝ5$Jq5b y-$֏zVI3#s/rųhpg^} {Φ=Vs7R*M1}S_  ][V,"!! 攣7PqBA,S[$qU"-9mq&Y%1+RTXuݔ32t&{tҰOg=;FHSXRZW%8~Q _>5DW4=zKA5h)]~@bS|Ờ#ӛ$K}&UT?bDm].ufpuN0\K:]VhQ힧eߑCP̧QI@+mP# _џ^T7f /* l2<./ N' 0~7j8 T/~Uд1I|Ft"𓯆Or28 W)NFo !8"}KRQMWHsi7_W֥3= 9_g?Zvoޠ)ll4V3 'L)yϣN%Ӕ BZbi9)ҌbHvFPI2f]uzmj`JwwWФ<Ɉy͕ҜMg@f@S:>ƀ}¡3ݠ cj*Pە=J>?||1 *mO l >PP2S,pE۱7/^Xy3¢>}2Dx]dPE0 3cDN!*x}\z3L*(AMz ?O-:CN}([`q HdZ(TJz|0V1FY;) Xȭ9 ?'’V0p*C`x@j*L5zT4N\R;IAq0+#K{Қz?Ot@d`0[T9JRaIqx^dipƥV/f(K'$󏳑W2L.6b.wwO8g鷮t:"I=3`?bf>Pk4YP3)R8٦,R͵F()l2=bn }eeUf Z+_IXEr;yq+ӜMŨ]-|dUYkJ0Y)HՐ(C(5)EYtzjgnfx@p?3q@\{Vz@6I,b^7ƐQ'R>#af;,D/m;1MɆ;2|hehL|q`!eDsqtqdBq2|,7!ev:!FoX$M LMJFJN"ӷ/s\b >sY论 k]jb)Otf9^.3}Jː/)xj>kbo6p_\֏+180#;⛘ިm_r./335Ս_*)N٦r!0OyQw7 bv tu XW).GV\]cEaa YĎ薌; H#` ނ\ѻD$@Gm 4>үv)۽}{Nf1F uXO*캑Noc!=fs/MШ'3pPz'$T :2EъUhLuz,eM~@ A|PQYO7lN7ϱ&?bdBe-I z^$ >0h#vΎA>]^mmzcQwY 02E&iӈ)4OA&bljݹg Ir'_ͳ'8'??>y\|ýWZɖ jt / ׫, 7p:~iEgv3ǨtC4G3fZᵘ-('ø% TAbV="R(Ē.vr[a鈂mFLfy },p-R(pj u[!ɶ,f8ai\n܈( ToQ'.FAU!nӋ Z%:H(X^E>ya4A *,gz݅_{Y H/GB-"Ƹ44fW2r~SYXcEfF t\m3 Swj5'T q!~(SzbJ^^(:;utC' Y%^8OZ;ǂy?)V).+u׵#nTW`S)N{B ;ė?z.CKڼv N-gG7ǖ96<Us>15sV*:aP<$f`79SA>kyڸ ޥBd|'Z[I#2tE ȷ ԨLV i|i9'ؤIJe2sGY"%\Ajr pPŧ/o{k:&tJ.tp%#i>i0IAhG>\pb9GPp<)fP&Ve8jdeY4*z-SW x H뷒@RZŒ}.jkrJyJh-|k}NQa32͸L\ل s;{Zь{m:Ϗ0&6هiu]g9/?r.3Ltg?G"PD:ujr),Gf$~oBfڐT> (<)#j  3\|AlӬjE~1'~Nr&%̣ b*@q)'U'ǃnyr䝓F*n_~^C6b}͆#Zn8C{je֟Ѣ0fhMt)=p9IxErB0P6Iݖze&13IBh ]@bf(u#j>-=x+[m7m]uMwb=67auȱ%İQNYQ`T }٥kpe]gN8y&+rb FLG#bG+N\>@On>Sȸ  j`I=u 9_o+KzRZU5f _ܯov7dꞱO$S{H++ % O14l&lFSUxDvoЍGӄKG Oz]3kCݔeKѮ2 %vSbD_!Hh˨wF,% iat6W˸Zr"T띧pz4LtȣY!2.̿WNmHְF!PUIpbbA-+7L|1lJ<$17|D7y֌= ~cl2PfOy9R7zq4YC%q=?0&×Xgob\dz0tTu7udH慵,+X0ͧOGVd6ǒdh9~3çq[)8ƊtXLvy-<(hR'_oZ\mnAߟp]}ꅋLY[Ls:}/%q; +2}鑱r&& 4&DPıijH_,~5ܗg )b*CGeSR~E3Ѷ`|l2ʆvŲZIp1:+ZTmPJ(zr@^݁iE@yy\;ww GZ9O@r\YKF}Rҝ*MPeҒ%٭qJ+Ui os W)Y$kT\M]oeuJ]K# mz+k,WzL\A}$Wd)qIwVT*Q""Khb"$biLjI|1G Lpԇ 7wX({Nr_N#]=[aqԱWS99b?;oS^'?oƱ1GgHoap7w%IO,[4 CI;dpn5-JX(l.Kǻp-`5bkiY+Q^8Ay-ٚsxRnʴ}_]] k50mZN֖*g?AΙlkC-IKkiZ[1%K8S\87- 5&7oӾzG kv;3Qr6u&g\k˳vW%]Lki\irn&>~;j&"xm,ח&#X'< 퉑kwIN>}zsL_~a2;ɇ~M&2 uêe!5 &qp~rGI'A|`,mʑOY џg7+z1j'*"U 52[]Vi񫼫޼xNt$%ԗTq-X&5é%#ܒE$R<fLO0{t7fjTK0t t餱n5!.CD8s&vA^2j]$jlxLݤDelНOn QCu+,om",;(/+/r2]jm) ".˂ 0s q}}ڸpQv-$}$3\_j#AfUI4C+D)mܙ]gs:̷O2ڜVfα9fִ2XJ̷ߛnO+}%7 ?ieT6F7*~9p4ձjTS/GبhX?beوXYIXYXiw>*>_wtyQE WYAUT*ʒu{3jop"i[!e?PPnP{!Rd'H<tBE+wu9Fב4ąm&Ƣz2ݴui{Muְ1F۴F|⧴icΜNQǹ=nI2+v]_)%\77db;vd/t\ ywsfw)禛ݼ>mrrx>7µo|\Y֕l՟n]6wkbx-W=^ˆt-q>!%U-U0i:)_q#»9+tZid3"֡x._,*!qjkX4HZŀn*qZVZd, p;+ GIcjܙ86f#z8S`c_s%ƌdp͉6YeQ4=E=Sģg\͕a]}D.E[ K as\0i)mIvuVIM#)&5pT;ܩgDwخ&K7vUVw֊jX1גkYsVޙ{ͩ9+봯а埉Ӯۨmqi]L+̗k/-ѨBC&bT۵ŇRVK{qְσV|I\ sݺឦ펝T%p`ş~۟tFݛ!rG& ¹4(qj" Pg\{H0 (RY k>@W?ٯ-o91! ºU ;_Z1dG:Eѻ^^]wo}C!ѾihE燃rUG UP {Hp݁fdꂆ|#616a0U㹶x]4pY@Ž^KΒz-,{_!Ӡt+\|_χFFO' PY_L,J$'9AC2j&”FFh^*ى|aK*qnaV"Q3 h-YHdޙHD/=F9O"D--[ɧmm0Ή^sl*+|^̞ ;#h1Esu1ح'&߱[-J>n}' (7 \ṣB{U`@9}=׽j]UV]ǡyCpڻr35c'X}X8C{ 'Ɵ܊R; cœda0[x+ɭ,Or%'+Yg4T-ٜ Ԅi{,Cvni]&Ay6(pgT~4y@RD[Oo?->]ZOMx:<-kX.yQaȆ3?bGӕb<;sj'lNYA _}l"[#XAF5smvVgQ$h}rb|s*(JO2ixPkx:|# ЇˬO\{.mQ98ngI3JvOR-ѓYn·c6HuoYEiQ́Wtk"4f)pt0U3\3N\'\W'.\ ށ-q*$r}֐|od<&gˇudXA}3pݩ~yb MpG(Y{(4CilR›)Y{(4H.N$J,eq@ViaYX3}r%mIxaA.'"t{oCߠlL M ` ߎ{7ۿ;j)܁$: N:\o$2҄dt1Z}vP| r:\7uVR'!5ƺ'%{GIH'Mؒ?̬M~z6W/pgOZOݓ֞4v=)2ٗXw`Ozzddfjr FbNP.qRNn<ԓ}jnScם3}u;M֛Kg;Y"r nKP.kRNn<}jnScק}uOM(edRkpM~\ S'2:r y8=I> 3'ϯ[ө^du~Wm1D+@#[Dwa72S _v=#4uM(EjsA뗍,} .4(YM\zr3s)CQ1&k--%lo". k}0҄ˋmnhmlFzCV/yǿ9%+w=؜&lUsTi暿1I!{G 4|lfӄMjzk$-O\ @ 1H0d0#6iY Ya!Kvc|0C6㕕r/ʼnX~1'&ԍ&\>mv%A}0F-kNl\"jL mwp"WSD;;XĹx&KW=`Nx']M<Զt1P[O#v '|mu-ryQs-΍Ӑ'%V'|pmu=:N+Skqv&|bimqĨе6XhQk)6awZ[ΘOU4q-swhR<+QEdhFRoX2yzHd}»zQ>Ԕnu/;'D'fB78R>T此FN8na7Vmh8TV(NLk;gvѹ CRνQ\HB F:n $EW()ez~.g??¹\q-XmǮi fr\=:?˯E)x"9v ? bV@Ysn nl<>!jAlz# Tw:I]ם"1Dԑ`wwLcR܅XLD&ug4Ϛ0?tOssMo]cU6ȇm|m(KvGglwZS֏%{h3S榙I4/ Gp#8qpb n1bd?;eowM§fR)p11^Gׄ}H(CnOwCus .CqNR(|oMCXw'?s\.ٯCs{w>H&7=K=Q=or<JPvӻ9Af K;ߚZslrg~hpTχV'5g/'gcr<뎛R)O61F Ϧ{/\r^-/{8SC>1cDTϱ'ws\.63+2i={ٽP='ưRXЫ)M6yezۺv#0t2+%9Vjw]]O.Esvt.&l}eV0U;K'E+«L&'WٳU|XgBϪVUMFZֿwwók٪VoŰ~W6%|nsĔI56%L.t}j[Ie]KZԼYcAקݝ(36u+fYGaSXXտwwzgUSG0[ϩ OO ],@ Wc2 n4#}VV]_[K?k+TZ_]Z]/,ť5wOTy}ԽJ{,/WzٶgI`RYߺj͉% /`~=ski=Di7QVۿts,؞;[󽺋NL?JvZX4aA:6pS_IBF֜<q'lE Z5l`m&R/*ФA &*Pum:^VcC9vmqCfG™pzHD6C.S`B]Zеџ{G;G{ b X sż6e+ȍZҸBd$ ?e3 (@?OHp/Hi8vic[->7iIɗ6uA X'g Ժs'P}XB^no_Ym%ag]!3z<]؋YہnP¦pl=ڷ8X>וkֵYZKv> ?Kߧoim% ~ J@P o+c,qQ?CF?`dE'n,1R?Oϔ !#&aqX3`r=vzrUbCȜJEƚAt a :vQ.}:Ƃa-^Z] %ȊY=Ī Lt|X.-(]&UY;AlaY L K߭mX&g<7aHbd 9HR$( ՋSJ4z"d[\|\i.Ors9bBwd4]\T;ΗƀUՎ}.i 3\!~ֿaWqrɈ\F?;b*2]{</,Ϋ"sQaU`s(]eVgmt.%Bkbe&2ӆS! 74"x?~Խ~ytϋ)@hۚv&z^6ΐb"kq3 ez.5z5*. dz< A\ڍrQlĻnۃs  h-!絼(]ѥZbzTޚ?wxN$u@ou5M+-TObBpab3Z 83p&gƠ\wcL736F 5}3Pfơ͌A雹73oXk{3-WrEU±밦PUk]^ \Zj?B3J;AF<[; cq'hͫ/=e@e fAr< TAAc:1fd1\PWQASo/d o"++GӋgf[eCuF|걏qsQ,+'$.ȟ7 y!, B@I!'0)8PI"xZ+Au)_9'~WG@W` z4  P^>?;`E @v[ Gೡ -zg#wyDA㝷$(zJe[4s}\ӱ=7~+=ʢlt4J@BsvϱBSQdz.Q x';Yŝ){Dl<І ԅ93l%_`5;(x[Pl=09T/Beu-5KK=r2 Qj6$v+8 TݖE"^f{F?wPlK!䏴+n+ejx^Ts$p7Dڋ*nֻ[ÁjawiV3m^ϲ^T$^9˓/д!N o|n  V9s fW,bBQ;˖3Aޝ x:n% .>y)Y;NDfӄK*Ҳ;058*R+o6qEJe#/mzf5|_2gymmc}1A&a̝c0rl$qV5)P_mGdyTHܒP͐<}]5 Sz*Aщ?.rnVgHg:k-w"[n>^GWG,7DR $ɳrHJ5F1g[Ѕu؂cM*4ߘ$q预X!~=BM3t=$5FhǑx-(diyQd1:&֭ U7<gyZg_=`5FB@0h,s0<4W(Ĕre|9q:WW''Ϛ6XH8~^"ֶh'R4T7$ f?Qyi)89QO̧NDRl m%.++kSm|naaaaaar/<ʈFk:W-(/>57\$o< y#jT.3J;~Ycn:M}e>UBeH~`#gp\t@Ak0T`v5ڗ]WӇņ/0*u{mXh ZxWX^) L6'"VE#~zDSZ'3b@ƵŁڧsQ@йDH.ª9N*hU`^1!a;*R!\XWi;SWy BeSL~t.52L-:)0 O/N<(2&9Q#Ϸ2$,%rW̅Gxī -gA!L4%Y=4G#i6j"{kt A %;1k%vm_By2Ys>"j+s(}ۈ6EjT,;\^0Ű\n~BP+`\pS(^1>f*r½\ִ32PWdo٣]|ؐ9\hώvVRxvSE'g"}`؆3FoxZBS$s1H(-uᐎA?=inkΡDbY͵"b%>B%pS gUUpv婔W ԜmtaKd!5@o=:|1\1]=KZdMS"*uˆVB "z-Ӕ u6vFOoz#W$NgMe0ƞ*zUd.-G;^=1Ǡ1_T?'5;|]~qw^/vv7fz:Ka)bIX _&Zq ߔ ׊AҐVL T0@ J0w%^ip (gb:FAX{у\gp KFBI^FNRPc55fkKb nȁBcrBvşѪ\bC6kzL_H_3 pzO ِ]R᧐ }GT>O,x,-hNha@srvW3ǭ(żXcN!C{ӠViS32 ihsxD،kɈwXw%bӚ#թMqAj;5OQ!Ǯ8_$ X,CFvS ۿԮ"lZpRvsS %= jӰ$"Y$}H_&y3ٮo?O6\w"]OsMJ&Hpb\7/oenM;l8算1QO <0A+%XO!$5"@|wca #B}I۫?qb<+~=1ڂhq\H[+Bq[*OiC99#;,׊#T}#J =ԢLiz)!ZR9ѓ欔kYiԩRH{KRb{Kcj6 sB>힕ޯ>}5vRя; 6 H›XH,H, 49$[xj4^QM0|M88f7!0Yp &?"nc'0{ RT*J) 1lP#_oۨ]R!Ӵ@Ӭ5W2'@p~݀{|aj yrHhU{[ɥ+ R XdY-4E,܍ң"NT M%M-'-'QX݁*K~_^60o 0W@'4H Ku/[i 4< ⓝT٦#L)vHxx!E0{_xx284 4s2m28KEڕ*Dg'i :;Zٷtp[%럼Nb'ezP/`l씀e-XXVlMˊ%XRVL;++CQBlf_y%1 MYR.~Wmn2'PYvU|D`rl3jqC-ǏW\cs3׵Li λ 6'n5bqYQA@t+|BAɲ)ʏukIKd2~zLC]RhBLWd#4fa6ֻi649@e'ikյ$9mK~4 RfAλ^x>W}qSSGffPU}<Q > smⱅ]܂uam>L\~EG$uS3W8w?83 ;O f qٚÃ/^~j0TMz_&L]XlT7tÅ 4ݭXs45 qHPsb}sFJ䎸%oV)CP/YJڧ8QlX+ ˆBQC{ИP}'Ţ-/VV\hq^y*[_~-W4tŒGƶ2u!b~څ3wh |KV=-›he9!2F#&<0%fꁌTS_e{a!N'.&#,deW"L?)pNQm] vt튚0_0٨M23;J77jKDzABS9TLj̯- o o`3˺S]+,7A]:se@4xBҮ΋.G1'. Ib֋$REr* {YdSLj'b'!nA~[}[U.e7@,}&DfM<;2Ebw}(c-9 Ү:zk Ti*pwbBľ[~/_y@*iBV5Gw9/_cfK!:?#ąq떈C_X\}{Q)8紥ah72od<(^EY m}D 7 u׋F=EL4miM6;N~7ڐl L+\#Jdz--_%\i*^ 32SYd+m+Va3u.|ҙ]flmͷಓҚ:dh#mǂeEV|py-.&^k;c4X[x^ ݭ_xIImY^.lDF;>qɆN褡 t ی:) @z'"ܪiqK10<?,_sWNNm.j_*`n?Khe,2#u̐§E;Ol( 2@6K؂"KK&ޓw꣡^g%͏_6eվ7ME@0mlZ_E"Ӯ" Rh "V떭7rwdJ_= {CgǶx+I4Com<2]D>!>Q]zZmOiUaYߧ6)L}COВwpXG!l?9%B߬"r5Çх3`DZ|)C"q4p>=z8/  O8No7g C%=ʡ}:4DYƻIbV@K% |߷3p3o݆U8/V1P$!U}_|NJmp B@;{NLvPؔQXd)xV H)үzl$Ҙ)aeQ&E?f1W`96ad'fөXO _J5FmwZG0c95uTk5 h.n4_).o#wnWȨdUI!+i"u+|M;cv,XEΖ)9+ɶ~db], 4f_ٿƜ9SPw[XjѾEW֢|eӢZZ3td]}bRGԬ-Xz]|9:x}ErЭv)(+jdbS}m#_u#bm#߈mHJZ[\}It$}  y M+r}dيjUʦx5꺿tu=?u.Z$.j(a*| VijsT*:H1J25XeLG%0HҡWܽ9)*" YK4D)ڡA) ˊ[VTRr)+$E[A!*~5U*T+WQůCULvgx׉/wA]^yOvh8&v<&A{mT?|nkeQuϼi79^[cݩQ-\tWfp+JfS J?U!zZ@#?\7 68kd2Y~@%zvxZC$M ܟf#_0p(.~l=әw:EI48Կ.g ?i!2A/H.^r @` wEUhjbL.l*a+Sx YD:#}3i3"4i&--0*4 *kua*r9z:#4qrLfI"کG.X>kl(ٌЁ}P h>S/ȱ&uot]Ģ}ZSޢɉIӀN%:@mb"@<ݺ:l]+ED\ێ`G Q-`;VmV$W1N7,Mo LfN ^f[!oJd69gFΪAI&Tpl)74CYlSߧi>'4wI0[DU 'ۀ$4 Ͱ]AGiy> zClaN)Kr!`-uBg`x'%̔ 8E 9Q+X8`KBT‰D>b: ^ϟ"7ը`)o Ccč٢Fp"Ad8 6//Q+9Mb|yC쎢?AdŲ3 vR. \S8 af eQm%<OHb+# (>ȴ8)%ePhB;Aɠaˈt(bi3e L$#-奌c lj){a4BG < ;O @QػRp5(bsG)Q?ԅs(zJL"U4" 0f 6P9 W6-4sR ~̲ _B:g)*Ca S`7hmKPkH bWL>aT;)48y2k%E*R#9,-=h mRť)04\x6rBC-VL6٩NHz3/EBH{D1e5]=1]D.GJ -ˑ M$nB1HPSPy\W׍IRdz1&MZ |\pы/ X d =IX=I5- ƀbG,岺$*so'h/0>jbRS(6Bymx=bZ}EyEz֠ q\Er흮b*0ڰS.&Ԓw:Yf,ahoB9TVhc'd𒆲J4n@N:n !"#4-@*YcUPS?N\uk@iBN},\:_z8 [a0>ߧ 1Ps']://mnJDN.W?2m<,dl&ީI҆Qaa3ȣ m@{)N mKFrDnTH0 4$9bqAv^n$愊xOq q!-Qy-IDJF |{OS/%ˣ8Rn&aS jĨvP 7, hkvI Ab G>4 սK.XBb{B>6\#Χ$j]HxC<5V:>I܄s"gƒYۍD3ilq"W-24t.`S%lzFa^,VteQөj~J'ﶅljN%`mGrx3V[:i[|Boi7ȥqg/46~8ca7M@X4CjƑ(ɍr@sp$+y>&)+2H0@c8fs˹lml8[e:PST @%-U=]x(yS,Obԇx N𘳁p$ ť|QWLͱ5}ƫZ,eP<=QTt6dc >U=2K:^MISin&#q* C=m9䯏4'Ca U00.E&zoACI~%8[F1Xր 6.3l=(у+0sqtD(E\8;TOnwj{Gvmo⳸{^||oK#6oor{wtgC\3ǯƍE#gs-7Aj-ȝ8[~VgߔQx i)FkLU+shӃRh +n|'d50ȶD;O|z1Gs;Bؒ]vR0% ^l<a4!( ߅\FMc01<]Ο|~6/dcaaĦh[hg 6w>J(p`TcQjAp`3Y> {#إB(xSB, 50ۇzo2Yr?Y73Wk\nN!T,A\Rkda`,E_3h ȍ >]O8,%eaM,E3eR2|d.%&G/9SXVǰDI=|B#? 2ZGA|oDƑ_ݻM{8|v_1E K ȅh/pZsm^ft#୹oq} kf_3MEUBɌUxw4U,_pQWkÖ!a&(цrmi>+Vt #A[Zji\z|A.]޳h;1u[L fS?i"t"2q)–IzGI>9DPR'Bi>lWͻ%Pxi26 4:yq|Ξ1N| k dzie ;@X%B'Oɕ4!6:;`Rfn[g=[4,R:Gƙ:*1(,<ɾ?ٹzdwŎ#x&DBhpӄs::{3A)7IGN3m۽.Ie_=W{M OUvkgh[ǹB`| /(cf2ćW bJH/}m"9^B0 u&XwYY8-9hLqgɾ$c(cŰy}F=L |x up\ewS]WlAZ,ZN0.{#-9ҝ9҄inH8{I%Q.hᢸ U (44=Tl-c2Cכ.9`6Wi{%ה /X"[øe7hȚ´=%wǎ$uX׶dOhR0CZLoweD<[(\OȉOȬ<񗑍e@N.2mJ`47pFsD?ܐHx`y@K |k$e?4 GޤΦ\;;s<]|d{2ldK ]cY?p%Ԡ)]c Jyq *b.8OWhëQa} ?+M|0{KR*kv30B]xm6  k˱.4Xq-h]wm9ߵe}זa][wmArlk |זb]ໆ^?{u.c~uE z!O}+ jncnoEaDBi8[cDt[oț>vۢҀĜ5GUg̈n{ 1fȕp32Yʓ&܊e  }k+oK#_ jq !Ե] .T't5q (3yF^$ 1/tFl Ys{Nbx.-G|5xZ ”!Ӈc⬑AAdF& i4awa/ jCfdpf<\(c<ڤ[:_!3Z'lئ4bLi MimJ+Mi?֑Sl)q3SOiܔF]&zCTֆ2H`‰HZ&+ UCOO S}V>]y|K/9!{}b^E傽RˡZ2}I󇖴1>{=%7߫qA]Eつ)s!b!nbܘ.Kg ,z_vAwN&ݸ5-Z\ 04ҁZ) Y>I_..uH̝OoR^JWK̃hJ~fO  .F?VnwWq& N0PѾ1vb"țHi$9NY>oOzGFvw/S1W9>zßV&>+cIS^3$}ʚpٖAuȦd߁Xvij@[gWně曥s/i0D7>HYUڒcoh].v69#fCѺ"` 1gyä3Q8B HB2Y\Uu6'h~3>ϳGI7]Ҹ8,/gJBhhvn#m?9bk_iXYnsjϷ|=jw=_SW5+ߪH6;O@\yb<htY*>;Dx5nOyu`^u/rx|'t6A&BpmJ](Ov2 /؇,".4̟s-:M o18_6%qC}t$9N2}O9p#\W;Վp!l--n =xH2-e eNye;v}!ƷT~޶ȊOY0{-MxKsg+$A&Th)Аr ҹ] u_}-;.7_W+/e99N"<^g3Sƿs/$\s)w2"^sa<tJv4=)&S 7cqvp> xJP"wm LELyzVхn7SP_ OEIЀt_jrs<; o4~ _)gK_~/|~pS%Lz8q"z0ӹjLIe$)!vy)0Cui9 a:Opx?}f=yZ9^6:GҎ?&l3O]elq)aaƦ^4 2rz/[n4d4uP9>z>_t݃Xbe^˪Au=b="0˃Akij@E@ҡ8nɭ"TzBrv dLE \fJ  }7T26#5pWĴL:~tì%#SF{cb A0%yL@1%-bAd{3LQI^qOg'|MϷsx@Uul2͔[q.?x~ӊ:Y&&m ӴIaxa()R"pw(DD xؽ$in0>:lt{:(5J| ߈Df; avhO 9M'8sܧĴҿzΧ"ivVm2̎m;F53B@h&G2; ZX\C މ3x#WB@O9 H:S)hvAޙ7Le0N \ObMj:^!L9-_lxZT2k# 27{ME,q}EH *fO|,탄Ϫ͞8A\;9MVMZjf{~M(`w׊mXBYY}FA(ěɡAHړ$Pd& ,A:`A3 w4ޞbޅhZ@5p]80u΀cj`79bޟyϏ t@0bZa}RNKΨ܀0:.b:t;\}kp6<5hC%$E4t{Y]f%KdLUNCO 0-3hM!9 yL6܄?E"OEԜe)JF%*]P?e_) !&Q5 rLE 9f ,b򅗚_5hCakT٘Pcr;.@jjA >K9s2X=@{0^AH% IV"ŀ.YiYã`If ʑ4dJk&wNil[,z ;U%ָa<>|9"%p-HNeF($ӾihopZБjQ 6䶄yv^cKv&XNS⣢K[/t9'$o@(Ο_BhKHnAIw(q zh+#mb!nr [=iwQݡ+SDK%y)yrg;Iwiad$|E_/sQ>R5]v@MJzmsHh=3RFs o .;m5=%)YU;)(F郝`,F|FEVsxGKxEaN­fc MwX#&𩁌6IJJ:ܩGGhx%$:L4p@ s(S @۬6]X~o5qц1u^?+Z5Nm'w:P bY#t֕մdG=5;?ؽyKr9I?TAfaQ+3jDF!T2bД\^J{Ej']} ʓE?w/n XI,iXĠ}rϋj8-} p^&ݓ`P:YWu 08,WY. 62*)HT=&mӫ h1 砵P=ݲ!?Ep0i|6k3Ga%R;Gsl#MIfVMQ,~vsOON\%KMkש$ttyMB9,cҌlGG^/u8MƲ=}ɞ/>O4WL8.x 6[(OSDI=,E})0s]SݥW﮿K&}zwK^!nnkQxNyό'Be,lsЦEB Mjsv`j<ILd ь1˲<*b^4/ֿyyy<9( Fc2omC8 d+R~ (g{5[e(3 zRp\N:6]ϔ@-w%8ڸwZnti~ХfLgt=e,~A8ÃN'LɊQXq;x J{#;/ ;H"80\bfepWnNb`LO8҅wѨh}ӛFv]+'=DxYtr72?}{F_=#kÃWϏ^%-%9هH9d;fS# 1{qyK;F Z%Gj^ffLJ VabpL0*-kprs=o6FcV`*+F$Kzhԍ>֧K ;;,iqdtV1tjx:^=U\Pk {EZ8,ÛA~᤺96 MD6etG/loz..k0a/ƺ':{ &\vf_k_> #7h w2r6br90[fCm4H^ @` )Nie].iupliW4T9}P_&d 6fm=)x ~ʬ yw%RqA`=i6o߹|Au-x1d1ȎoQ٫a{x-x s* .S@vGy3y3iԷ(;SVAXP.q%674,G/^^Rvawٱ 4U55ZT̲YKQnG[ߕxȽjha(Mչִ􇢦RMP+`,Eҫe5h 'vuUA]$h#E+1zZ91o<+ _r"hfPԞ~-e4wTm^5|Wڗzbk G%c=DV(KDaV<>BvsI;iW ucۣAۥr|[Y}çLBYv租tVM|ڟ_c K.l; { Q;,+@ K,37tB+/eX,O@0K) eSe Aޅv c{e]͔g} LK`x8o}4گAW_wo` $Pc@'sLKOW8`خKȐ~v!`M=aIX,`ZQ⬑pXVP؃o7pɚr %R$%T>FL2j|WÆLstDc2ߤ|SAaJ236s; m"TK^cM /(O9C 9(ob[0.cIj`ҕ8whGv;Q1M%xlpY@tdؘLWbP9@̋PJmac4 ,&Fk3Θar >&o/5grS> y >YMv.Ü^LӧCLIpaOqq!g;2'2&"|rr> g# e(1()Yj7}>9m.x|*Bo<~8Ƌ3gӌ,ũ3y=0W8=BotGi/Dxqx߼-{_ˀY 3+wסifaeg?qOJՔ=N{0St6ֈA!~3V"[.TR<:59螗qƂAWG ܤ&7eF8]DF 7: 3!= 1)4z?@Q 65+ 8g$A-=i4q81)}0j>}/_3Xt_G*JT6KRcч,i\#vTaSv8"̭"E!,elb"Ĥ!)%I庝8FZK[(]C.j h04\.A-zK/f^k%E)RM,&WKOg"8>Pl2J"`@++RfmLވl@o^d`x?cMf8%*}ʛa Lbj! rH &qEJs RH8I=xL(>S8'Rt /)TWR E QBa1HD L6++% )y=Գ0P +ua/0T}S,bdM5dxeTdAu(`ZTh̼/lK@mFazf>d>` 7:?]4D5PlA*4tܧ--O2rHdpgr{TX/02@QpyS*W(qblĵ??<+/K|l(8*@G3ӪB*JŰ]K.* %X%1SN| ;}"ڥh8.@ck4`cGvv]J~R})mM:. h^lwX`w qm]|$J m48 >av2΢4.[ImBYnVUl7=dkpQq*D^Ūxh֐`l#_zvFG ՂWpS1xV,cVD 4  KwZ("VN+ΌAa:Y b_:TN]ˢCHmkM BxN˱&:`Іpȇ8 *3٧ʮ6:8O-uWy—/;S65g'FKalӆX6n 1?mɩ4ŠJJwr_?[UâOTޜEPXj_=<etJqj#l. fxU.;G>x{XL k}\>b<+{ 4iȩsqƊq8>?:#Iԑp<q~*yWwC  pK%;jA2Ot͡s (<Ɉק +y,z@FARnqW憳t0"4‹M߮)s!x kn;ưդH! 𴥯J2ut>kMLlkuqrmEK%-nymރLH6tA/ЫxPvwHGJXus.+3Žqݫ|lߠlOOe[qGԂTV 9jEc_pA%?(!_{7#<3! 'VZ o,]uKfA ZF6:ArzM _V,iLuymM 9A5&1£MkBbi:Zw3{޽ &!u6ks%NG})[w?$\8a !|~pCVm85bP/~T ]:;ө !jEz&x܈8i5v6_,_B[1NnߑKZazC֔HLZI*/whGq%ynV"rP7;-762i#= NZԧ vmkodoU.]8qQ-_^v@o^(hP 9ms|iIа9`)\cxYsFbp{E =v>\p\%.nX qx%>;!e=M}8Inh7Ls}ؓў{lU tPrXިp;{#C'EG|t%n0H,skwpPYՋL8BOɚspSM>D*7ⶀA8O&`2J rF(ϧNXDH:!4wAu(e_}g fnŽuQ K ?џsՔ 8sNae)ʿpZH# - rt: }"SaEU6J]eo9 S8sA0.+] M4 M)#(A@촜L$|fKs4k(/c[!?4VUnu gqxl6wMfԞ[vs mq]t򄲰p8KXVc?Gb}i*q.͘-v^%1_uM-ʓ> ᏌM 0 inhRMgH ʨ!Aeʚ ztglߑVbgf1I$ic\ְ dRq:٧ie<2#l!5ޒhY ~$A(xrZ˷YX_6 B?vȉW'|P_+0&?N12GIaGDgt$6'Tn)t+>C2^s LgM`;6bh  ,ӃO%rr".+Ak uGf2Q,`b\6b16D [fҺД4Ynm-VUiP 3b$El7^p#>Uc6Ϥu zMwu_acyl7-Hk-]^@syf J}՜(jOi@f_-V&W (# ΕKŶXLx5k4ܻgca|KMmBq,/4{X0N\ iYum$Jj0(oAmKV\^io5ʬMOϺt]@T\k /_v/$ *RTn#[E#Ůy>a:ZZ=:l^g-sĺk1-.sy4$MDvt9OCVaϦ~z7z%†F4ƔCvw_@쑔ѮbE\v# :q; Eъ;a2|1lt[cQ "5mn眗8D `%^w\m\AZ*%9.ǔz7ӕ}K.ͨ5k.Hj$pk(Dra^7c6/סb{G *>QBs&p0vOua,_yl,ے azʀw“g9態3rǢ ڈMӖS(G CB;P`CbZ6@lR@+cn* L51QU6#e̥c+ě !a#AcèKO, D69y>t%Eg%0蠋Kw݅j]`lO(W`ۺ!P#ۚn@,Akbޯ95X~VU2]my`9ZФD$熒IF.\Tc3ܩ՗fpg_r,T*im$luUȈUk6G97%kWf ՛S'1Jyx.3&LSS&53=`yJ7;+L\.|*e'3(.)1tFa^V;=|/hTLM=Cq.:H}3A'n$nX6XZ-c "29K"Leb#[4(4O2Ey,h,BfS>BXIISUl{S0!IPY;Ny`\CzE~@Ϗ y/PvCx.1q!y FOVhʾJ=77SE5B-^;?[<ݴe_޹SE揨{:fnFLGS)r{.GΚt {Rnw98{ɮ(JIʋ8n+[{FL%MGž$!0 iiBJ.LCW%6{27I1ħFS'飱?VKMJS@>V֋7|3@.<횺9=XD^"yJׯ(Ws~c3 !DȎH v>OEI4 VL8Ƙ`v l0N209g7_?a5`C=A Bhfzl?5Isǥ-KHGǼ0 /,Nwf7u^kZnn,-f~̵|szo@-r'd w .Vհu" ᦍb僢(U:kaDySvķR -S(>=8>zh(Ϛpf~%qNf+/i]ðqs w#҆2'bb&U$NՇՓY;gГ&ѠҀlAro4UN\58y:0 vqK"G &·A+YI525*:f?m%Wsw*\#wbAgT6_";߱@ tg P8uA;0Jlۅ%vDD% K<%XŸ[:) dlgZ=(AHE"H-A}RATL"H__*U"H%R:/INT"H(AD%E,Q,d"HVAX,E%Ae9g=/6\qӁ 2P(.>^[87`q?NS 䒵.?J~ߵE3 ]Q%&.pdw|垒,\JqTqiY+ˏ`(!mW5 ^V RWҒhJbmGzߏnUh [߅|.}O=~йß^wgyr"ʗ7| ح9|abճe [7Kfpz͉ۿ?lWq }+`њhy~BQ 2_VjyK&;Df]KՖX\}/^>yO+ W5 1@5 b{d6?_6SZ&A:)YE:H5&Vf7?-Лy+՛ W&>>~@bt~rA{z+~gRޕ}<;'owxF}E?+N~ϣ&ɟ<% >}rEJ[% hZ FtAR>^-Z) zi=&MLu^-Y^nc<߾e+G%/!qg [َU}$(lW;Woavw2T&v7y]|G 5wiŸfg.=Vf:1m~ai7WCO8 `U vZ,(Dw-xd2ʋoW|F ePRr4rUq*H|!4r5ZhSxnw;Eod-ŠInmiЂ7ӿ*M*oSלUSIY4P~a&RAPR&]e)9ed#A) D{~p-2xk8~Ч(S/}rmc&Áq| YaUؕa%٩rl!ŗ%(_#[7&9:ti)lcP8,| i1z/aװ8zu.fҋ}@;NsViOT:xL30%MۮWl^=WQMh[5$Ú4yX(d1R=?Ʃͧ~n[VsUJ%sDO'H?^≈ ޜmTy*M|m8wkr\6SE'l ,!@Q⑟h'O"#?1D~bX(rB#?AݥD~"P , ,(OLم"?eD~BLܽoFlQ&S'Ic rȈ4r2hP}F,/ziL=RYr,-nϓ6#c2o8Fc4- Ƙ=|7+}vʣ @y̧+Z߁H?v]o4Ln̥BE)ortigv>2,0"iJ 룑e%l&/TO6LX6U밉JFh`=תӒn53iuў6ȒJ윎$hɒd=ijtLΜS7@(zYPӹ ~o߲yO]h9 JT]_M_]-ku3TuۆW^ٸPYJ LE6V08@E⹏hظhifa,+2Ix.ǴLCjם'p?o/*7EE~]%r-lR/)͕2̓;eQZ0Y͵0bL5WdD sYӔY%4Z1kF.^=a,XIFstAr4Ɇ/6Z #n'Whئ-x VzZ4+_׏ho2Ȝ5tE`OL-G4WM*YTzZ2+T_~"qZEFOqoۛ#7ˁY~z1)!F$w;u(gH oa霼T[qEW'׳0-=zuLpYauhaEuFzW37e5`Jڵuv5s]M۲zUJy>|hF>߫߫߫߫?l4FEg|c >$ =# ixq܅)/rࠛB1Mmcbkf}w,(>lUM@# R })ʼnJ̍ *q/jE+,W"S9zDSdr4Uͦ~}q7ѳQR|ɂFiWta 藇VAL:'ǯho $ Ȑ5فԃΟ#ċ*B}-@^rĠ@>gO(\O?3[O%=機L~sve%aTQIh7s! +,yHHcV|aC/rM Q <`Jļmm$o C3ywC/* t-X/`9ΔG?i>v%O4+%dZW:+ްq3V`j]R@=SC*Ved5k#h/e[KJf˒M-Seċ~OaQ&C+|i b b b b bɱ  7_ =y~sņDFwpk>LA)ug} g<Yc:qCzq?Fz`dqQӨT4TE5&-M_UU]_Q@bZfUJ+ f^8tWkSaf(}GA]?]P?}WA8*BYGYHfmjO=]DJMA 0-bLNyo30a;<}??6O/oV]@3 Ĭs"%9rF*1a)pd7j;5/6#ա`1K,e:or kԋх5f'8Em,R>MLJI^곋*Qp9G|D~+P8  c klĔMX#?oɿ2㘥.* I2U"w+F?{ZM.JHA_>9xᫍtUuhnɬ +qut*e3GǚRO߅r"Σr;[ߛW翫>%5.^x͛:̾`6&eG҆qh|s:r&'#w|FRӀ3;ԽB|rnbSk-ǠEeLM\/JF}YX'TZP+-p|-p~o>W7/rXI*;_{JfM׽?&>rjQMfH!^{ožc@?NJuf:Vw5\YDR,8 )ёs=Tv= xgmOKorɂ$F7?sΗ8e*'#g3jn:Iw۹wgIM//IGvt%zx,(.8%o)c&EAa'WSNc 3,oQ':)EfaFiQ}&fn h6F,^Y|tHϠS>B÷|#=n7#=߈n7ۅ#/8#D0/+JRan 1wV 5/_[Eix2k[E1I#Qj[?=|(xuU1dVgk6x@qՕH.4OqZ)N 94Oa\ŷtL֥z>ȇ+el̂V`To<C7 l@B)Yu l4o1GP\6;KBdFwݏcܶ!Lq}xۣyϰW|]ov(:/YzStXU԰sUٔ&Ȗj58!+'d̜mey0/e6vѨ_+w/޾v܉`Fi>oT+5u6#-Xة@OXy"-=R}oz Q \MLY\73gbA39=M =%;#XG xU'M6k]=e+7q-襧ځ0ɬ6pIKʆ tv[]8W_檣ײZy妤t^<OO&锎(FO;?ewnXY %8-g-uY[Ŝ~֖0&-}!}֮ge-gm >k :-gma7x֐.# ri#.zrǏ2 iJ`60%'N7BUu3ݽ?/=XP<5X">]p6.$] A@d+_}+*zAE:9&i.J 6ޅ% EhteI+&BQXX e  l^-Hlx|m(T$_P k?(M=glhuw,"Y%c`϶t*n!&9S S0'ލ} #Zf*)~"!˧'=W=M1n.c#䜃81(N+hj.ʌTfMhml̓i?#@qҨ)Bw QY0,-il~hY C X TybR"W(5&tM吠@KP0˚bbB'K(QyͦؤeXJ 2&l@k,uc[b#Aηn9X ~UKhktQb|I9#7c#0/݈1#WcoμpOqPUuQbCa|CqUZ :8*Ѿd(+-FӡyT-@oKcQqp X Hu017ISwZ#C@]FLV&,($ 1L"Q99$0 w>Ymjˉ\ a9*D1EaRR  PF9hh$DǒJoMV]Gkbo)w#aRb,;;a®,'4hU gcy> @/TsHB9(br=>_Uq_ZP+uPM} ӄ/!2yT(j+`>1c*Wn_q1,1_Jf+;$)P/ b as+m8>`D8G}OݮWႬ,]Tw$Ķug_t {-ړUٙz_ g$d fqrs{Eyg| T%<34ljX"k=%8ҷԆ>@4ڠKZp@+`iӊV bB쫛?T(m,d+3f)3$Ϲ \VHe-U dhVaT^ͷl[2jUAiz}ON>&^+EZ$YB42+a8U(ThBw!*%J*"~R2_.R9Zqj~'BP): Yνm&WD!>s^Ga}P/j!@M@z?F_P*C?86KH W: NYX{+ ,8 a/x9t3 8h_Dħ>F7d-JrP{a)#Vt7X1(0Ƃ)ʍYNp)K. Nt@8Yn\^I}7ĉHhl'2eZXH-? U6_#|zR-9E^S&A:'ILNHF^6od,4auEtB>LOm%GK.wɥIJ 57u^ܐ_ǘӻ7$"&HIup"s31 wE!w+Y`O)q#Ȉ ,İL+mh y`Xmu>(0zWJ}sK9 /gŃh).g-HR˲:9_NSoZn,BS%3o$UXba6RasS9>7^߂ nΞ9(nc f a3F~E_[1dՎ1ad4O Q[<#F1GNY1ƕ9}_Y?e5W}_dvzqbj*,*so8ac]‡:y1ic!IL`Q83ZL]rcc>&ьKm*[rmDSLcK!z G&t'_Zj`6y&/-,.s{S^0ͬ$ynhׯaJ ǫ`:neD9Njۄᦔ=״3ca vB6[mB  `_1<Gnjg0}'~>n* (f"/}^]tJE@b_v`db !]ċ@&`c t 2F8#+hD8.' 4xK<5xHtr <Đ݌^:twHRJs2s؉S^/39P+\NKH YSHk1SotWcX8Dq.L L4uYKo_~;Z6CPyU_{X# q/"a{`+<('u&*P/[oV ^­lG( !"a0gX#P9>|p' G4o% ݨmHZ,iga0+Dijn؃UTICH wh@b"cw䢓6eĎ:u^zSb< /MhV8Eshq!]FE^ȷ>Y %Yt8E%B椅2#JJ$x 7qsYIZlzް_I" iSNdIm'A21J7& <ٷውaMu,}c DMBM{VZn 7ךh Ŋ[5.0x/C>6i ’:}"z5VKw|{DiĮ](&J4P1@%e,˰@XX'}%ɡb_^0vIf ^'L2jDxSd}y,@]=o۾݋JБʂX/G3A6?uDŖʾ[)|h3'qHARY+*@! %o)S#dY[0E=#sD:6K W :w l/j:g&`of;1`l\J®c ,L3)URZ}rcuzC|eF@,iuGZ%?RHgXihl dnz?tOQ2R|M17jF!AB^c^8 I/|'s>vxI vL015ƪ ;/x}0}Du:-򌛬t^ܢ[d&R Q_°-> j.H{8';, xqS^*-#WE,׀DJgpIHq !zgՉb ֣sJ]OaY]A(z1?{1XܚP0榪2pF*uo fn Q{D{4k>a|}jOqϟNH/i>)BmI[ݧk@TݻG92d▖=J.Jʁ 8ZP[.M0:z*s]-AkM_W/`6! T:ׅKm}՚1~4ϢS|(8t@[e%$og9MԹdګM1O8|a[~k\E-O^Z0pA% ͍ԕ7BxwlMuK~ADZOtʀV2Y{z$F6|T)DL! #A6L%E|!x<м9exid^S?);Q*I_xaȥM H{ Ik̳ɶ*B!U6;id8].-!MMǥv7C ۆ[f"ΌÍƗ!/s e2u6;:=&lpjDjw 7xkfYZ(є%sL/޿|Rm|l1 RFLw?~P@HQfLt-җ 'ߋR v&T`ι%tL>c+}a$bP" MqnĊPٛ [ї$.@.cg iDք$J*6*Gr׌ aּ˨bx(FII&6y=չ1AMhӋSJb]7-n$%8Mg4f7?-g:Iǁ׹6oBG}-Aj}}G{qmDϾ: PФ{&`{Ѡ?%EgDjPA..3Jf;|A::: *KjJ^J>";IS$,?<شrPE hO[Uik{g0,ͦ#j1 !w)9ηC"p[9i5ͫ bCG=Xd,d0YahX,+>4}şt:45!?)PNXOch( J(dG?%0r}B&f5Jj$@*"[kzqѠU6 YaMcRAi6Yef2moh*,ǝzfbxI8&rg@hֺB(S'' =z N{2X|))\ P'^KS 5>&,Fi3󆐷2I_kArCK(4^ahgA;ԦfG&6qSxyCЍEP{9`_&ޢm= jB%"g3n`0k(G$LDQ,iat-c˄M'fӔYBF' @\+GGF,\@:wUNaB ȁ‹vƔ]ld]$O?=Y-gfXP#Vnh7Þ/v1xs\Wo2:O"'+cH|" ]#NFA XF׌{``ಝ~ qܘ:?68*TN8 b[.L0kvyխEmq"[-PqN bwh`g03. Gv`:j)WbV(  M.,(dh' *~DLg\MgY/"hIng;0;ߨX_䥄on f? l^x{Nݗ9 *$~}&Ig9֣2I`1Ok"}}SuDN~8lxt|M #pMϦ2(CBDV@^+|N}ޱ>"x3'bC$!(PC91(L!7>el1Їs/UL(6hÔ''E2T`ϔh\[?r4H2rKl*p:a3sq\}+{,#s NR ,uDP zxzӣm.2 J!Qw_̍o}LH%K*Mu0S*AR:|6_ܓrˢWjSRS Kѷ/mꇜ)/5L#GjsM#;MOlwiԪ77^fJes$VekQgq{xT5bLZFV9vPgXo {x듲' ) c Bw z 7 ^$ ) wә/e =>ObAr0/W2,l2 Z._a=tJ@h$yÁz8ZZW:(0ǒb]Ʃ9N}OBAʙEa5ROD$!ur%*T-H'4}V?S̫B )wS?r mwgxIT0,B`+QygDM"{ HX0%qa: vuG銴W7*: )*֧LX͘8J˪LL lJa Js( y4%_\&Xѥ JVWC "2mtUi-JQ&Nѵ))^LOaHmF]fRiZq4IZ*cOIc'5 =oI tDSq*^@oeOĺ6uH榛:UJ[ִ~RAMNe[ cˢX|8ZuКz$[rLyӀh\ng4:/ryA10jdhI%ωf1 9,iJ7_'H_٤NRlCYH̩1|NZ7EBRDoK;@p&^H{hTqW%s_?i"&L {ĉOS`@!Wq_\IGruq}z<|SB`p?$7Ƨ m8۰zs*cR).mRZOۄ': Taa*ُ^D.5邜!I[_C:I3⭣ SR}MP p't ͱ?P?K8enaJ 3Gj #E=+ 0P@cvFk}!.ʎ8 ł 9\l̎ȋywbYҸQ 1 *]rC)i$|̦t(;./tL5&ΊibA݋lŢv>]U(lCC%$= -Yj7"}(|BBJ*5(+f:F!Z`C*פCЌPX.v:@hH@lN5xA.x80Mgv#D|A} V\y ? Cq1'࠘Cc̏0? ґLw2DZP&lj``)ҾW:u '*8l;Ιz&@ 4MɱJ3U3oD$ (Ni4^NwaX|a(tri L AY`&I|Kp<`q̟DP1ݦWM7b]-ųR94j_=5BX̊+Uv3JP Pz^@)ljo2E}~@4?< br6E-E29oh m"'q}{ 3UѐbJHfY6Y(P?RDB`2,ѴT-4Ӛ N-SnLPXi4ʺ|-1l b*h@K`2Y >y Iϻqt.<ҤZjF 7O`7lɪ&hFOLZ)3My:V޹n@#}!^V!`XBO$5+ 9ӗOh~q<(b?~?dy.t8 :u |zTÃp#5L/1ycèmi1~Qx1\`VXq0Fvx=ղ4@:pF#T.^ʺOHr-]٧;3:,1K'(UΩ(=y1I6Q6X5wcީZmv!x7X+xgGQ&teLkqpX0-+pp~HʍKr(REB1)/ifʴPZ ]IVmg^V0RvSN>5**5Z:*2~2it'mD|Ÿfhg6;k-jF@4F1؃>'{GRgXFy .|Y7k0/Jn}g$0;v[mguuuuu_qѱ&{=-O3O>(jGĚ,Fk4b ( NXכF)b'&G\`5$Zr /ܰ]44uة#?LOIE=jhӸr.tZ;1)${2 PM O=QҢE#!AU+x:mm{G(b$ Aw>{?D}?PBgwU jy'>!?q2ȠBL+k!G0q8WE ,1 N2kӥ <΁@w1m}Sk`QYL]'1zO"E{KhתiiQ؊mhec7Nsov>YoyhG/_M Cyu8ʰAe,5?MwzZZUdAZZ(|Jbs vl#9P~+ȝ*V性5"W +Uy' GTkJ#Z5PCʈPҥd.TK/|i!zduz2, H&~sGT#ϖmGE<$eas{zߌUAO Ȥ4zAZJ7 HtDHnaI2CjS?jolP#)( oܔ?IxFhs6b00,$r0M"u?Lx ľ$Q.Cmr` e\gVxQ>"7U!&@J孵da 9Tmx=^0»݇>*EM)U$Kl=hsꔖEi-Jk dD׼Эl.kV=ץ+\]WĨa\tNcOc&ڶ\V\Z,K,lrj7 {ٖ}z.\8YlQ! \W-H UJuB[c-Fs Lt iw93T>|"~; _E$8͍k#LOx>.EJ8VvcC\ׁc쾪*Od1I ;hCZjV]EKdȖz2}S(>᭗=5P.E✂Sx 8B1ë Tr!11U0<#ڡ+$7S>.884ߐP F}>&M΢7 gQ>>~_O')d]sx+) %cgdbMpL!{~΋j|ҍ;|)/p~HatI14'9+1^bƘtzt!/P64Ft (a["u1Ǜ٩|iQUfv6ˤ٫UBR=!ݯ}ʷKL|!bM`JPFRZb.z2/^>I1ՕTd,5?X4=m$>O3)<y[)O$XeE_ dTM( l]<|Z3eW+@ڜ 'Ф,_muv*g+!u?}zx|c:]hfY#LV~<˅Z06>LN$ VҴmR=S^`ڳP`4籠jKWo@8 X@W<׭ϗ{ NN$v醐m|mJ1%J5s /G [FOVLJis81f$53xz᳦(b+%{,KhN\?Y@Ny(rE92'6yV Ւ⳼3wMM#c'4J93*l-V53ZwwJPvM-K)k6i4U })~-cz.d ayuRNH|mx@[[sՑ7=kj˷ʶiKb5X^W=n&=}|-M䩃g4k9gifi>Y

ifS(r9rJ @uaqynodTf?;ɚU=U5co7_mn¾D9j*&sYƉ^%y+6'^ *B2KvFjN5m zkC^KuFfm258h0ۂx3"8GSbax5%"(ⷥ[Z̙e/ژC9m -T_</K{fAH{k׺2:1:ynaeA._HWBfs\zs5u𢡊!O..C۸i;e3Հue4PEM\so,\aj|R._iAnלk`^K˱w~HSEq@MTO,&Gĕgo4Is L֭!=z?aӗT=RQv{;a} $-%~~Co*m0ӊ?q<0cU,v/WGawE-h{9 ƻ=n&;ٍ 9pϻq4HaD?Gr7:jWioV,/*****G~Ӗ^|FkƱ2OQ 0f6P~x Ș)1+ 4(I4 +l/HhFڋ&l׫y+r?m^6ݧtύ2RN:e|~j|n<^i;!F03ޫ4g@wpKJ姀8@!T:xM׼KcVUMy՝iQUxS^A2, oN |S?2cħJ|C^n vEQyI n[V: yJtU@NEw@&o;d_״qլ x. qX?i-k])ÏɛU(K@|yS2+-C/6(nV/?+-VQ UC%T.nPSoo~Yrꦆhm b0Lo[V!F-7l19ys}+QE͒n vH&D g.@ΔYޝf>(9$#?Ri("UtEn Ԡy} ( Hݧ7{ly~%y @09 ^@ESSl!3}-w-LFqmpXJԍH  rV(G|޿?yG _=1DʅqEgf5hSh; 9 (EVSbAu'$RCo$'Ќ^X$z>~*uqB;(X/ĻR{@+zl}2{HݶK!<|P&Y+b=W!ICMcPJzDZ QZmĠW|ey̿UR z4VC,v0hЫFX"`ȐS C,lj t"T A*@eݹ[1H׆nTZ\YР-JwJ)@TYf-5\~pIv*̥+Qt:+,{^y~Iҍ.gx>[O D (q}iβ}w %$K6t^_st\~x27"Ȟ5_[5q^y&_J50̈́@9ANh4KЛV;UP=g Ezt=~iXDwO2FjoqLK& pe{\xD r'4]^=8FvՏkᲷDa<أgeYԙKb 群2NmdS>TlJt@KMC.%jh$4!l[y6[9gAe\P1G2drΊG +i/d*X edsͼhL&x%"o\L*=Ea6 fx&Kn(sm,ڐr`8~ _Rʠ7sd KQgy% 6?9xr:f8mQr`ٰ9ORQxqmaNrjO:6y~".xYlfK(rAA\w1 >5]hGJc&'oX鵭\Y&!RXw&{exg*fھE$ !r|_8ffd)S@fR7v]0O鶏0W ;` h GF%H=~N%Y:^XRҘx}%Cؾ+H9X$ 2JJ/ܙI6~dPZ BF6Ib>ihYWTnck +)b,9auʔ>vFN+sǥyf!Ox]3%)lG/P624)ޡA6Ή 7Jgj;W?PFȴ_1&K뮲ʡcx[;xb+oc._WY :fʜsmѽ]R{|vҐq) u̵Ġ&*lʑOGSɆl"ǣNF~hgVߏY]nkXCH͌nQ A7)Fl~ܫr Pm+T,^3BCz*p9'?.p%s1¹lU/ޥqvJRg⸛(QAxd[A[e˴(e9䯏ag-+--#2W͞SѺ}{ ]7a-(񧝃2c/deD(v) Phn1xS &NMI&r9H$zM+!%r֯:c0x3T,^IH}uY#B.E!T5(\G~D/hor蒉kJl=gHT)vqZF^VOFmǙ7Hv4)d4r38M+-\ pdLKeٚR>Wz_.JD30nfŐ Ӓ!fdVWmX++jS:3-WzR,SĐ lNgGZKApMJ-C?BEW,L-O}ƪ-mLj]@c'%}Z(YWv&nM:RlAaE~|ڽM+,an_8ä{m*EJYՒ$S6 !O=uڻo_˱;0԰jZ̢%ȥŦ!5Ǽ3g .M;*\8YV{_ N)7nfix=:Wչ.od`K;N.&θ`򲗘,~%u( 7wDzmm'՗<W- bujaPDl-ZD疥~xVtenb nTuhFSIٳx>g[Zϙ SykӼSZl窑sUO>g*W@oN25k$wzW%n5O쁦_ '<\RK?+?ި D:?v:?݆sy!0%(KP,z`, i)?ܸpPw)?%@( ,Svb?8w tţ=|",VO?$SO.E`zuIIz-'M ?eO˞v=zo*?*&ҡVEj埂ʐﲉzg6G&yje@r8Ÿ߽f2ѳ%q5_K4鵈܃t #"p_-jwNC讜?mog[>Xn⳼_XXXXXK09/~؅݀qAVTp-I=0zYs*7hke&?lg/_$A?wDQrγW1ѦZ j־)W#'>EGVh ,>vwQdL~s%)рY8!oL k' aO҇90&+qwT=s4Ez1licGI!cz8Y"gP=QM4tKB+N NvIXK\~р .;bj#mi̯7]أGZ#bMb=,SJ)/H .X&p[o{9p('?D T4u`i鼴IRXж*Ka!ǵj@1O}ƝfR3'`M>{3GV2}FXݼ 犡SaylV7YVgeY~h-iҝh͛2X_0] .TjakwA=iޕ;Tgm\XAGG#-:s> F,A덂3F  cId}Ի+(ꥲlBQ3l ^]~>H6U)Ÿ||fcM;}ߵoKMfKX2cݱو^_ /,J~o}OUCӧ|yӃ|&> ho[VE>E3p=bDD0Y}ol(H;pU'X2z5tdO;<}ȟߧ/Zp>N3qz2S,>)h ^f)wn/Oo2 hfcGm w4H\#ksԭ hAe@] &F g6)ѬӮeʑŔ-ĈcԐ<͍VδQtZ7K^4=c3'b~ j"cV2#=m"hXƓTW(<+Y֌աX5tH[+"/ ӟQR9V<Ҝv87Sb+M;L'Ԗ\dLi:t X`W\M>%Cj7]9;88(P!l?Y;4 $G>=<>=߳IŢxq5ꅢI qtzξKSV=[A8RLEU0gkx,vЬk{c q|ߝr [ sğYlQ)-/=Zj`9I%`UvcW=GKrTGu-7g5E))8JʫM?|V&>^yV^+/QqtB }³*oq Py"( fA >ѳ,d cCʾ5!pTJ!}ͽ{9 ~$Њ7|XbiN899P&(nΰs\J?<9tW:n7}=sGMs2цM%dM/~EрF*HԬJٮYPVکY2,J|YzB@;u؛?f̔}5bwxANo6[U)c9ZjZ-\zK#sX\wA^DV&B/:YxI&N״Qui q0~-4^G?wO;زܡq,|i7 ~yhItptNW _Z҆6BG8KQ\FNCL8d2XhB`ӄ{Ќ\*cLƕeʽŠդfί:T؉x%В]@Wf &]^W$,YWya:$c>7ZV+)L)W2ZȢ^7Uwsʹ[D3 ,cC'w/UN#^4hmO ij$N+P8>` P7`my<눤y7{űYo6pEO>QlnXoX Jh 8 ]*4v:^]Pve0rOY3$tKbz=#.[Cܺ24YGTM5]%Udݖ=ᱫ5~ݳ÷oϏ^zݒh#?wG# ڒ%6"uMyhƇO AOZ9MyBK{`E 4rq:C|EaK:g|5=_;+O{ >ȜVy`kmDI*vd)L BMtS@ 4s6Jl_wG 4bْAS`(4%VHAM"/D,%эMwjRPBxPE52 lm"gly}wv<;Aja6jZh_w:<7lMF]ɷuw,ڂvQ|v$DpjgF"`1.jFQ {#% i i[LMbMqQX0)8FtfLb6cdYq:fj)eN7TxqjmN| =mcw'2uxf^pauzO08ePtV@@;`P6;$Ǽ#EG, #&ʹV),3(3y E7_XBY8| .]xmJأM*kQCDDx~O1EF<)4fO*.IJ7YE_#"ZmF Ka::ih>Q 9Kr,Ꜣ*%"1CDvbS}2Lqq$y b:fDŽ%m{A*ω{cdhm &hnGbA'ZfﰼvWR_iMPE"D8t@+(M ލƉNq9b>]a_Q݃mnrFU a%+?f;4A2}X)0Xi8Î0FŎWĥH@P=]tqtކMڰFA*ձ d=AI#o U޴7T,+VZE^o}Um\qh+-:@4}7l-;c%_h=3?sfJ=yFS+>FIl_U|#|߇_A'Bu8z&_~m" =y4Ӵg҄ Lo<Ɯy+i]Hg7c]JXIRWLϤ͜'s:bPMDu$kX%gefwސ8I hKyswcslQLrn!cZ%xKCؕį8D)n p}ʛw'|k.^4:-6#Y"hkԆh8n-A8l|%6F%ձB@px;֣g- rJhgȅ)l.5 6{ph]IFdnOZ01^M(K&:m1%+'q^Dp}{0DrFEAqZOFI'ޟJQ홃q>`LW ]jv`Fw1(DUV<VSi}%vUp𽔅1t"zt {KbrfcHFjNwgEIk ۟֞AgZѿmhV+D-;Nrx7~MN=*-H*R4u?;H"Kv[X"`0  @b~RRIaQ}.ԃL5RKsǃ}jI#d5Q?H#W#DdBE4 ѱ+R.8ͱ5">;.R=1hT$ORdJy M_xw9RēgtKQ/&G\G|ʟc)\&T)[m::œJĩPօyjyD,&9hS$H/#wGG/Ya-Z7W`3HűǧAzW;85}ak *M2RWa2aDUnU Zz!zYKŻ(BCr6@t{[hǢZ-NA+֟ fӧ]B۬ {{uL'R6r5h8 1>JQ4kn" RJ5 (V' M[}%6wR'ܡZ2a 毙w>/5{ n}#YÉD%^tC\uŵW0;w-!533lJ] 35>r&ԨO|IJHDha븣i^zfԺfŠx9LoMn G%,MwښA?ULy$F$iTٯ.'^[Kb?]o)-\BW."Ʌ5A]w3*,.K1R 5]1RtQDd"1BM57 p; iay ?n='_^J&ɃóP\@5&5ak$W;df` z!:VPm!0D̗'oVKWRJĭR1'503 n2q^!Rݣ'=:WFZ'IPGitj)*:νxSIK{kD:<|n +<\Lp!rfOZ|W->ŏQFJx:RZ$D[ITYpUA_e$Ædzngf;}A>_E{_E{_E{_E{_E{_r8x:qiGYy=UN3i"eyGwHoy|^g;+C|VgeYV3o>ӛRhCEv$kt奥ӂ$$ݥnx =q6f!f[؇=ktJN8߼PquG.2L,emM`2ě Dr4YU|a-ؕ/~m'@X@׺#.tL&Ws ݨZTqwc#3g0uXK;a*FOG0{ױ%[ HPlȖoQ:f;)tpdbUOR1[B΃R"ˍ D_jpvg '>@/tA2 &ӳz7f|ÍS2`d/5ϳG23Id i$>_n}=h}-y=Mo׳1{Es3dWn݅!Ca0حf^xIq#1jr{I}v\ Q;E5YeDF g4y #YoUeMfytrt*~T‚V0~W"c|%=F/Rohufue-Ì-"zqG:œ;gn×`mEZt 1 s}(|R dJe릛ִ<E~*V花`YlRT^DڧJ}J#Ӿ9:+{k`oqڅscNh0NI=)jsa/c\\Awi !d0a͍fIU5"TjLT<\0K0ʰgf ɾ4( 1R%1db`葏;Wb!z鱊JCeܚ# !d9zRn!\<.rXP!HzꤒĚ@oBC!Py&,dF.)ViTʉ9s 4Ha6`;f*;k1FqΧ{M kR&f)GİS=Zf+~ ߩzotzwi+d3!kƵzb7{/wcV$T0b.LgXz2D4ߙ) Q 8(OOmp\-'W5Kƈmp QyGoyHw'1 "=ܿ}ZE:é3\$ak& TTS䀯ۛ92Rr瞆rkZw4ʝyjU|4!Y.Ol/KqrۣvD#rUjefi鵺 #^ )*촪Nhkj[v[(5&@PS"hg7^2[ߩ.< Sg2[UgqYj&A~VyіM.Qq꨻ ?\hKKB`,'1RBN_vx ݉Lc,kKcK wj[6CʹF[VqtZ2O"7 \c'X.:ˠI0VRLhmscP&!=SʖAyidTuޣ\yPW]rkȱʈZIBg,TqӼ46:gf!8/W€İԹ-JybGR 8㫠v,-q;q4hW{-U2 *-8(I;] 'Z\}~5S2y' (7=Cy ]ި`YBmA?9>0e<'5|fx2j~ۅ%,.RN1;@wȳ"ϋ|W\R&u2Ńliwl_(Z#@ȓ + l ͟vWL9WټEU ]mr=wXsێ8sV>5"  ՆCΒ>GR #*( /nOaGF7Gqy{g;qUUUUUǯ*{ Si,UYȻ`M;}k:Hѽ1p@ IrSY;(QE }s5.Iy!ϕʙ6SnEŐ\-} xʌCעLa++Ȳ={{ǃR;9ߕϨ RL)Æ-J%ȟqR@1JUP*%FZGp6Fz}%y:H%ު…SVnB# r1,9љtpQxF -wz!h]ౙ[fUnHP$5ŀtr֯G<ۨpNvE+L}M#4i`?Tp)Zh.d-AY0vJ>6F4m_kXj&D[&TFKE8^m&qoI*T֚1~LkqAY7{sAbHHgrqJj45/U`pn]ŇR[ʧλZۑW7SprQ۪3-zD̑ ٔ9(MOҁBJ1ΰzcZιےb ۬P&ʌU~ii?_賲?+|U5q}~K^,t`~z[)棛t4 %L eW#zc+DV oA7w.YSߜA&DNgQRؑϩ}@!s`NBLe %4;Db͐}^zp^7 ۔]Y _փ 4dӚLDW9Uw17+1<;VcH@M`jøg#21Lms|/o˧hH(zWn`(:XK%-\̡C^^B=:"?KW˳kcWr2]#\7ڛ[[+!>?WZJ |(+1?z `*z>37ӛAYx"D JfYaPG/7yy93E#|3C_7jloXJ grXl4H lgF5|/LũZ"[p߿_L$Q{e g5tkK(.~5?U)L*o YXx?y'OZ_?aV5M'ߠ?dmh}@;OZf3v`x/Pel;D9zL bOր&iLJsA0 gI#"S :._q}5B@0;3Jm0pUcIl b7!2dҥĉ6C`c$7!6u.HPqdSÐDBy"RFk E3(M>%ͳ׺+KW}ދalꎢ%TWrJXrJW)%Ҏzwhwʯx\KBl~e 6?6?"ERl~ ;Rl~6?BY@E`c.d˰!&s Gv6$[)N,ac_:ԕT`Qj |S0St^YXԝ| [򿶌-^ז--g_-mq_h_[p_%m+2%k .kY^ז֯͹ԯU*f|.:"{yHOU,~2 cց]\#P}{QofFQѺtŷX4Oo1phE^Ɇ@Z䪟[nXOᶲKq+ Eu ƅuδF;Y粰 HRa*ʻ;t@@ ]KX:io8n3WBx>*). Xd@c>ʣ7p(` #;s ƔNܝ81- ɇ~S`8[>ho{ue&P R 6?ÌZ͋Pl_waϊxa*Pk޺軗p$)5O]n5zFq[,̢^|4*HOx%;6KʤjgOz(Oyh7RTsB4C޴nn\*x%+}~ۍHY4ρQWhTV*~V`щKo P{^tY뇃?an4/9 b `oӤ'lWKbm"HHӉ{?ђod!Znr9,$DLa@ $x 1m /B#X~N|X(d@1iFMV+6-|z؞B֮SoF>)`kig+Mk\.Bé I½>B[դ& &]6p(W籢l3ii?oC|18lL܎p&l|lꮐ^^~8䜥:β-@F>^0֕O #LV4VE4Db?gޔDF0CS2 7d: O5uq&R!8>nP*2w Q8+ZA7uĚ~OT@?ϝGоwjVYGj?ħKwS6Kk0Y=DaM,lF K /ebV}t! 1B+/JX,l'F0Kme1k1Se bIޅ,c6ce.1͔}g0ǶH9< !ޮނ<; Six-08 qJdFr@e&2qHx7oߝ Thf"~ _L(lS涀 xu@<:9|LJo0eٸB)F X*$XIP0%p)Йf\&4G#8?~CASd_!`630bĠt!R9*feŹY%C4c; Qe![`@+9i+ 4GUyN0tRƱ,57ve|1dA]6:<7klC) 5'h3NsYqX(`(Ur) 8 )lbOi^a ٤\Vrv +o?"j'˩u$aC.YSY#*!1a."C Pw؝h.@ba]5Д _!!ɯ@پq4P\6d飡]uW΍kٸE~HSDşOM&H ]<0{E@ JI%$ILR2B0 oq1:&x݄@ tE]"ɬ-3R`hn1S3 om̮37O$bKR(<k. Ywf|sDTNi)ѿ3xD+ԅ:R>>Jsy 57PPfq,$I`a}S-Ć)JhY inx!W{FRiD1eau\&PEԇe\%TQ:bAMƨX)N݋ЙԀ)r=9$RF$?Z 8E(͓A>Nu0 9"ưNTAtvG'"#Lh(nz'Dn(x9}"`g΅4ZS~DCfid _m˿N,?hpM3=(M_2cY{p`ĭ5ˢrgDzD2vȼCӂ_Zut F*K8'{/Va?@gШS''oUU6.C[<&Gg[ |OW䳊F~/?L(MM*%gIDo2Q2K<0pA :{(naJ?%ľn"TeRzqtfuU 'Z|(ԢJڬ1ukr2yBPoJ 0o( ѯ?L=J${hF'2S.r~Kͱ '~9zCAC=C⚙3'W] IXڒ<2\鐄E39\]Ei9uep`ؐl>C:G r7лY+*[9hUe8s{ t}e&XʮlPVv4SO[KLAIFB>~(S~5S%_s!R Eቓh`$޿nW,R1x|6 p5;Us^;(3 .JhGv˔"oii蛀?n⚚'b|ʨ棸ʅG0"J ?2 uu_ =H|yB'xIko:G]tzZ?A$GCc'i(7bLbmQ|%PR!(z63\/un8|{GlNf^jTK51vzڄrƨ4 B>OxpZ7ug. 3t85iWF q7p!z@V=&>I.x Gk~v2mUMdn4ƐgS[HʐTA= L֙{AsosO32,'0XYw*I= Ɨ6>[)+9 t%t*ۈlEwb5 \ctF&wݱ(Vrf7Rc {S}>eG]}#$u5͢S4LZ$.k1*x dCթy _~pbL->"zRQq izǧ5J: Msu<`_7__\]Ij:%S­ygjrw_$o caE,{+öqptq}Q y^Coy6'o mӤB&}Ȣ ٷ /_X-7ms*K2ԖJ9:U?Z~tMv Ӯ 0-o*,/2uDT5 Ƶ1 ]'{A!8/U:s }O6/͠o NW8uZ1=N&J$,(BpR؇m&{6 rT,rxyXI& IsSSX ly_U6aem i먁~la^ܟj/kPh5̯6^ьȲ %iwSjpYuz-AN!'nmRbA*˷w$ Ż߿>>mnle/1fqj&AN:WWW-uK~'mB{I{sf@.{2Xx?\93c Ve+2jm4HeGUl//vӆ ǡJb"?wȎK/0Pi_^;7r_5 ]Kܑha]O*ra Yt1s J\RSLhu:m_DB)Ռ(be~"/‹}Ku+B#r7%R9[b=Rٙ}{7EcKmލʗ[mqߖɗ~)U6yP t͹@1yi?aQZ] GђC]Vl"'ܝAqڛԾL"{ZΤnQ0X̡2Kv\F!WrkDLȧ1bpČ|?;֯V v|~HKgfez@R*͆=qi—`QPǁ]ŲقR܍S-MGWú>捣 Ax5J*Iwb:q!090Cd642$]uZ)iH n WU8,mkt>JLR :vjU :=>@$c3P9Ho&.U>~;I2>xR]ŒmO B_p6[`6|{A>ʻXRYK(ۛz] DKPז*4 cԿi8 ~k ~kw֖-C[[ڷomAom9:*R49JK[KPSSߛb6'[ ` +RɍpSZ3[`r`ӊ<~8/^+6A{I.: 7~RuhMZ\/_T!bT~&ݢA↽=!%Z GgkE-(/2'"7jQr*O=s|@q ƼD`+oT?jH:T@}[\@> Du[t8 9-9QOXtiC$+/ᱸP} 2SΔ+<X 얂$P͞YSZpb`5q)Jt[uGpD xt{TPukq1-vX^aZX`Q*GJպ*Jk]k|ӧ%+ʽ+=ܗ>\E79 >Oġb3lQ,t߮ ZVيI\M VK YOqh=04lk(t_{rG~<~ 9F9@1Q7.I¼ k*<%*O?E@9p'*\wCD1t?A_)ht6dg3҃i> EambO[!9%@%J]g|Gqʤ' B2F#6#vX%z,Xe_"p"T8Lμ)] aMwH 7ِ g]h,Ƙ. }3k !_v.VMzOCACI k4 RW=g2LݞVى3niмC6?y aPq |;)2A܎O Hjer8z6 QG. "{TH#ιژ؊Z{]sMO~ ЦdqWPQGʐ\Ul%tTo.$pc(e\ZnSk3׆R9X !;B_>nr.afAԅ;.لy8K՞* i]פxU4ij^iJvLU9tI8]eVIDʙtd(e K CHɘ"V&WM0lin5x.a̷ 8֪斱(IBexIh[Zҋ疘yQĦ-PcjTl,I;fSW@=u Z82q])W9mH%3@ Ƴ],߁sv~B ]'dvU`#.,%uqA|R ^ J Ro4DMV1W+PO2eE,ep9]Mf($o~WmdW;B‰ѓtG) +Jw I#x[EÙcti0Gm#M\LwrJA ͙~V5Nf%FJ;(m1.KPf)fSb]`W IP̭ю1)$RV7.k7r]\Le5rI1ͥ}ڡ١16NWWʫ.\؊,q"l[ZZCi6OwԩKg, ƾh06ܱ/^97G뻱?:يpj̱Wy'Y<')B<푕I"%ۢ]1&Q{zvvDm*oyGdNGk{ kK\J(Ѝ[ԭ-V[օ'ejS>kicQtԌUJگ$-{z9g~%Zckn>GU%sBQW[gBg+ ;YqRQFMɁ( Ȣɵww-I1c2I r7_?]i<f()YoFIpFY?#$Yd<(g/gv֜Uz+rgf%nӡ[f ?/{bs\PhlXU.]i4rTe(`;+޳0كlwsU?Qɍ,g@-cje9rG+&CU*;ftz17BGˎ|2>{,$BrGS,?$CqG3*t/Ά^ ߿%=}p\^QjzG£xfSznÐ,E5=.0(>WNlE$l!Zw zФ5.pؽ"֔Y:FpuԃGAF/|&ge"mt7B4=0ٳjڐp=)ڌ#wOw^/5X};HUxl'WpxkxG8~ᇙW{4t/xOn1nUo &0[OPy5CxE{{[MRY;(o$cN(C=QUOp񸮏C`맪8&1.4z#6y,Ɋ(1.i.䃒@=}C#cvA\E1ुpЬzDQ$F譫Ը.jh9" ܖI2o[tB#R'?yd.>S4J+Dm%56euyɱ4@g`-?jE%(4 GzklH}` )- Q~|FjO$VӖV4vE&!wSvR G;T%qނw{:Xs֎\VuK{]N˵mf k^W.gQ Ci N7N|,Ĕ!We@eq̥҄uꡛx٘?pժ_I iꊎju`F 5 +6Z@ͷ,$ækeF^ 8i. ͰZ)3q<݆C&I?/QÛG({E[G|jE'ORyˤwxP1M*SYj3 Đ ܀#g"`4Ԕh t M і7Qtt(Dnth( -V~l !%O[u^LjP9hXlR%vv+:DNƂosԵdz$Tͻ}sR)D'!t^ʗ*i㕶,Mv.E4'i ~ +~4',NԠMS2i|ܯTpz xk(eəIF;n.1;[ϓ7?_~W\|$.I]NO޽֣Y%pR#G^_>([FRFT%W(GwR=sa/{.}w'@جk_߽SnYsS>48P_vz k)`tn9b Ԥ+w.ZmK֢*R=#as/WBw}kgW$|P!'49C.g#j' Bsm*Ǧr}Ԏ0]#;-"G9^g9ݚcjeuLrz*#+߀4LҪSz߳ͭ,[Vno[ oq]jO?H-P2-UGD{a;X{.:x/ׁ2;<`9,tϜާZ5g ?p2J*"U6; ~Q¦/qfTNz+?eW"N.5О,(lըrMt͊Ͻw-D*UPL)~OZ'Y\B-ÈZXy,D9F"V:dwыc&Mf@Q͇bPl0c [hb'RxC~ҳ1(ŘV>{%`G(/խ_5O?Gꅴ8Ͽtza>2Zd Z} ^+~hՈmhٿ`pgKV9joL#@U^";>0Pu]✭D˲;[1͞eշټYgAj% h̎uQFdFD89-įcl_ޕӬߡzk-U+8OqRm,'2ɱ5G i"Y53=N2Dj,a~~ +vX(UgJ6@0W6YsdAEdӷn3vʗEmբ d=1L1T jlJ1QQ jl{Bwxx4B XY}!ΜE_kXm,VbXP%,1fsCλGFޱxc z=}j߳|} ~`ws]&R;{/yÁ+|;SrǓu:8,Q>xƍ)x6edO$"fFT emjיą᫣ÿtONяoS+Ilg+3nU4*=%CQs"x(ئPa%|*'*di wfgћ_,{}u/e,ص[xLLѠ+0+.D:iZg,qz0uxқt8Є#,[?ZAT 0?ʴA^Q`wJrxvw]htSP%h5s\gcEo?r}ūw٫6L,y=Er% .gi0 AL LBșS$ϴs}:[I`2Z ) B!2gvi-nj7|uLsf>nwć 'i* ˱]ܳ"Ǔ| a{^9ׇ~+_Xe~rKEKi Yjσ79fc ,[3&iJ\IƼsuUXMϛΝW9s^ yph8|E޴!0NҶuLB6i@nv3 \*;ϗyk_ɖYݳUVduJed\"N"c}^\#$%A-.D4}Ә][uTMw 4Nɤ?)\KfEU{;φ#)xɖ m+3-L:uX_0sU"YVrɯVuٍ+꿢S~Ld]AhYXܫ|IU)w'|fiS986j]+~y}U"ȵ,$\ة2Ow40d(Go0k3}?}u!$* XhӺENڲSHGl?~k_=]{srO9L4@O)%CZ?Wq35ˇgxuITƢQ}u#rγ=yvlA=՜cg_0Ù]+qrĞ=XEչ=˻fO]Ux;ָ}xOj/_oeC@ElyZ\dȳP6K))2=/2}^w%Pt~VJY :?+bxN}\GOS"Ϡ!AQv2*|6W ۲1%d(KP,`},`D, `,% ⸨,` i)YP57)u?mưN0pKz0Ӊ:՚dȫIvL)L9p466z}+:ؼm3l._=KsY}rΗNfG["W.s޼BM i%ז^X7V/n[j+ͽyOSj4FO@1.eh綬2lgV,F,l@(˱,> a-BbV[㱸,^@p mLeX $ XlܯTP/ڭzG,2ϗ/1%q>|#,76F zH)ƆJAN:WWW-zEZ>z,b5<~'J}է^| X{ ln"jaﱺ,'MeVݞ!d`ލ&|ۿ][>fRePAyC*($oKIRmQJ sMD0ϟO/gKd[󶑯?zN=Yy06"PX'o}f'./ݑ&萙 MY@Ӯlүj jkZjkX@,`W6W۴!hxzt+ڽsp909c 2f: ?nhn 5Miz1Ϝ!z.USL/6yC/Ǩ_: Άi* 6I*6sI`7T<轹{E 7THhQ.-_QdؿK>.`O N{1*rbPdŀ}*^?tGʸA}j^/TuhS8UOGUG`ڷUExIh}Z z!V#@AʨBgu',! ֗ ,Y q.m&ni=U;Ez+Pd!R)[ƨѤUn±KQ޿k bp |?p $Sѵu]\Š`n)@vl@[)jb o2)_yfcpY0Mw`5 O>-qTiJsv.,Y6o?đ/ʒN YTìAi䬁,y5=iһo.˨(olWQ}u?L3o_ dQ,\c3ho6wdeNW9I7ޙ;sqϝ\eUj* 늑?uE.%ظ e֨y]&a8UȢ>^VB3EǦқcl2aԭ<_BwǗ'mOC(h6+g!g9zQΌ/6x2 Mi,4O2i֜n,1q7^8hgW7;áKQR?ﴱ6ʫɓ8Dj@J26Ӝ5[4Qe2=ȰZ5-s\β*l塕UX\t^uJ'Mc&Lu lzr6eMPOEA/oE;]  4jig{)~>=c4%6"hmӣ!kg/Q̴MDgyN YEjφC$cq k!"VkOwN6H<F:.[XjSY0KrSd磧4JK.+^Ѫ7figmmǑy%{eK|P ¯|g M1u~ދ _|!v4T-wվ&fQ9TNr==ު[&mŕ\ur] لM=7]{NH5Oey<|J7+Gpη(%@$6 .- ixaw}`"$ |_i@ >HTmv8jfnfnYpƾ? fO@WZ4i1]MQkV9z o/u(/sBjߩ?ۛ??iR%y?7Q,!8bC hdG[6M`k,/7824K1JH zSo?9s31v)(`L`lmχPQ(w#qFt۠'{@Й3ԆG*HJ0R~Bv&.<36,5`N@ߟk7LOe:* \n 1Uha q(hv U="AEAÁ3p}̃홬V@id6":u4 UDCi:}Y gY D ,fփM #Ɋ)|H( !ⅰĐ4+`̇ g7,NQ1A"^9LJK+gn!E9$LH7b[X _hCud?VAAA] K,Fh;if9O2 󈊡 K`I@fkTN>"m#N )WPtnJ%M `-iĒҚt=8|* uB2^V3wN%knZYh\_kX҈ K)`m &?* BdqNqp攨ЪC ;^` &՜MaZh̡wvxPmJJMޱ3y vԕX^6*480DlR4gؾNd#!3P i$f$#fy@Hl`1twBg^BsڄKj㪁I^}7FT&k6DA/'̍?khDM#LP%E/X-q߾`թhqpJ"}bO8y*CQ2(Z.Iͽvz Ǡz!FIQs{.ꢊ\Tcecu͝y6 "xݩ3lTjoVDZtzc s_@ݠyT!ĺ 1>)Τu`8~w?>D*G[oImWrlK:w+o^PN*G:I-Fm̏޽Ċ5ܜ\_[NX˥,hxyt+r61fӾqQ} i)g} !O.t|urG8,|PpȇP> Epǔ]@,|1x&GeMjE/(kAOmŕ1oK@Np]5%Zx&^~,.[gg`2%;`UƠ ?{MQGnkjOc4ZGfT>Nz,pn+wk)ɥ`54%}<>^ I4}ĸ!2qI˺)%׸D_z Ч <Ǖm6ͭ|P|Ps&:l3,+pĴJKg_wOѧG{V0;[ϞmC|*k%X*̵{ Fe؀b,kE,f^[waL-㾐wmA-k1- k }זc][件ڜߵJ6ʸ1 3/px/'7+*_s"JSX++|0$__Bt5F#{6le.`hͨ/]̬"wCQ%bN]C 똺_5?A1jv@`E3?;t;]xӕhM̊\2DW]Ds(d'Yk-nU$TQhM%~y kLԒ/_V%lŋɁ]|}+?TmCJQ#5n]5Ռx P0t ^@B_G9,(7ZV{/s^YG 56I&N<͆7*T?~5ZqκkmnJj{ߕcqͺbYw2enLb/80)LrmID z<'@c>xE2Yֻƻbם$&#lR9dSX-&DkIIUپ^XHkn_V[K&y sԟ] O|,׽okno ȑp*vVV5{HKv2/S&?:Rs3ߜH4/lad]E2wq_۴NP35ٮ׫$o`ԨHfZ,UP{o)]+]׻zF S1fmnA &td>:xdS%MD*9; PB'}}݉oN?`U˂} SJ}[x' طn36߭6_'WDm:}6ͧ;Iͭ%N`{{{;g0Ƕ,߰`;ijD_ b+Ӹ=0\Ilͪ?BO_]]̗u=z˿[_fPK닿ʭOb} rjpH2O[1x,m{c`W^PU/\^؇bj `ƻ_q *罊&Y"{D?sTm5>wU疥]0 r_ͭ¬'ȐXÂkaFtA qpڰ̷13 Wf5;TT" FA8iԗ/~z8wzMDDRPQ;٤hGǙ1(p:ds NZWo'> 8\gH+q`cީV6ZƌeXccv55ZstǨǣBѩ9u?SEw.tV@wcבZ($O!h6"Rjɨ$̹ eƑC)(cnR"+&(J1M9(C6!FD*>x Dqy!!>9{<쌊B;ޯTyP {n%= h8ZT gkOvsm.4+>o0tM<Ո,+!6Rk2IOܑ[`, A:SքAYRUN@g<Zcy.n]rA҃كESrO H͐2>d PN݊JրU&@']I\%ճQU`m!qOn|1(~%7*i\[V?gIGʔd*da26L'/K%µU9`\0 <7Q{;` W?[۟0ťd*@ C4F&h=kgJEnW'JPK}T>:BG@NQe}]9koxc DJ`예A R P5S}$+ON]LQ,%|Ac^buqPr@ {þ9Pl*I/+(OC % UK q?ÇYsP:D [RVS̨4SPDH2IrT<݄ Rcar+VbM42l [,h03Wb%-ĢG!5>&hMFY/<ٕctؒK}q*18E" ,-vUՔFZNÜLǔ 7ya(=B gw2"'PD%NFEް(,ӊ2mU]Ίālkr~%mH? !x#*|)Yr iP~;\^ aT B5vEB5PsDBhnzOQgA Kv! \9>qC`"Ez_+c9$xa3ѽ VXm5*L'ȇJ7 d))L.V[|gH+r^*ef4J (&% c thd?ä=#3Fuj@iN]^.T`ʴF'0^Gq+ hU8YJNR[I:R FBOI` 5wWWџM6j*}VtiߢcFOR({P 5y 'SC^ko葐oF.u獇:!`B3:7}}Jb_2lbKSt™]٩f?+Xx۫6bd ^1^#&kA?,zXduM\2=n0 ~3_X "sM }\w]`S],7w|jVn"R$ǒYFs_ܝ9h8;^ח=Ƨ7ZhBXyagd/QLMt]J=ŲF#V n=iM+[PSD2թzmoik3"6>[6[k}7قC||Hk.C"忴{-϶WC|VJ_+eR{Jy>= N^[SбY)!]bX&'z3|yM;դ7OĆ~XTKbt'z9ٮp"x`|xzW8ŝp;=!&Sz!_:S `hžz↤PQ }cNHl\`2lQT3gH-AqǷ m*(FOP?_nPxPeH`5葨yµ:>?{xvѤ8PթcͺU8Sؘ]eŪG*@!}.JK*"vXQ'zHotd@UO9 L!p)qz(  8²WcQ H0z8PDwXZ:)ai1])\+0grq[2Q`Vf0Ok|GeL{z@\Ŀy(,N2_ 54_b_#PXVhHbu@^ +B"Gw3Z561u;1QpaPBwnyU~x}I\"O]dN,;N'#Ե:;=CWi=>I↔dN# Az%iH+*ov}%w2`\xQq'3w2I0|1w:&o2ep *ɃX > N}EcQ%y/^_vD)ލwcݍ϶2=c%~@Ŕ͊c^h* %h 6SStO"^7w6Sms<]c X|V p8/Kz8T{k6P= c0U>_Eq5c83NG7=b 9^S/͓Sl")ctlyܾHY_7[m) \s3y Pm%He{)m_Td1[` T唃aT.d\jݹENwhj%[-]D8.q1&w`F)js3y۞?e::xk7KiP~)KeFHpBؗ({w'SRIP$!H1j|1HW gO9}oӏo{A>++WlऒYBs}"v>ܑ?ٷDpCVʦPRN{D1l◳瞃`zɡ1T86VL@ ·A8UB"ː.RdIULޘvz慔X6Ak|q.`; :Xs& LFtec\(GFUd|qiA6!2E~ VՅ 8_h9Wcw L A8.'̜HIMJ<5h ]OrWQf{LfgC"Kj$ĸĄád>I=:{-W NVͬɦ_9  A1[[KiVܢle=ڔZx7i. ](3{vLtF 2GB%EF=OchlCƘoEY'&N#2lNK`V"|o{7?Uo:Wl!g(DMBi:%+l6-Y\@F2Hb[~7ˉX=3k}+[oZ sتFҰhDRZ^7Z+Zp]zmg9;Ń@y6wlLʎ]q[zYy&ye:@|%:'$Ȥ{qL-L$5h{X@KqĊ$/7ka[R]h&-4(w Q8T /d+£12i9BqswnI{q)9cl#`Ƭx~W1͢Ujr!zazRqw {/Y/)&uS,q1uA35"dz*=^9&^~w:jX•SgD6H X26@P$QiI/S0f_)#o{Z'yr__֣DS .\x2@4!]$u-y ![r 5vޠ7i(H|СԪRFwj]巰V3 ~#S$A[޸_$sqoO'~`)e!عĖA؛JYqUߡjVs;+ywuzյv #xkl# #9c[[. D-K٭j7W㜕O(Mgc?cmz15o7_ܒƈs/ E7%jUs̥g{ä•\[Ho7gH+Nnhs &LoE% FQᤲ^T>n%HpP?rP?w6W泊n8L2ƷvsfFn#Pظ4n< [a=ÁL4`YWk dDT (04`$ ۨAPsX ?7Ctc#3t՛cZJ:co/@VzP"u."Iu:&4kcf -w4 ojёg9ޠ I#׍{RRe֎ @[EPP$0g^6RbЮAB0RŲa5ܼgQB+eAsj㾥*e 2AY'.@tЊdA p fUڑFN{or6Q%e44ښ,Z !"k5NvZ^.KD`H w=duh;x$LF^Ͳ\xCo,j%/zZ,6/y42$:z.3FSҝ2BVMIb9C nXWXp tQwr{ p6wx=yLCubjZF6bm_#T9T7>(  J{+^]螞-Myx-ϗOIB ?;[;+,,?+^|NA`kݠ@( :ޔ}0AEi(6A1 H4rnZPrcO|FahL ~ReľdcTS|bkEuyW -3Kp c7!QsK5X؞]{ :eȽta:6&|oeWr%vHxhv Ia>w:-g7C[DC݊vs 0hE<u!+&Vo(?.ܾr_)[,hAgOm%gYv]j~Ż؜q 8#73efOTzA*[=QcE^bcM=g^=st)`vgh4:nUA淪N;tp `~_mwj~|q:U=yuVUd Λ_?}dSغIvbTS}.H]K, 6~71l f=o;wS@lg=lps>kp:u͸HWR}^vŶlW^$^ wլy/,ծizS#y ݰ%ty%Eka9}dy1In8wesC[ɓU>yb8sг];.$)zh;?vk&oOMfw'HWd+dl(V0@8[+@ Yc##QMjTߔrn֍y r*= ,hY]\9 (I]q& ,r>鎏A&Y`6u#} tvEWve̿Cq(SK5xzˑ6uYδ P݁s顙\:1-ZK) MWD!耓 %)95S# 1[):ؑMV|f5_a?0Z*D E_0 ДB2[aRHEs") HP5HRсU8MV,uY2O_-ԔpBߛԢVى3W|7mNF+|1 `k`K.RIk/p!h!y:5Lx7 f6S \xXƯ0d ||+A๳oKn>S룃7}nGd{! `$Ȫ ԛ_*64;BYWF֘:D,qmV(P뉡t\4]f7W{wprRKWEiZuK?n<cs |N$ DI)882LLg 8j'>2y)z?>0J@L3%Pu6V%j̥H"wjAؒ(j~Cxj̈́mD˽NFlLbp0%"gUGFxgzxv*w ߧAYB" _{5@=~tTIdqJ׺_90Zxk-!-gs:u9} “3YȌQKKAuK y >+yL&wPpNo?:}ςwu:]vVk9]5ݡ.#aLGĖ%ޒ_qz[mR_Ď|7(@ij>fm<>[-v#ez]={ uF10eǾ.gvDACΦqGt7M-^(.ܱ;eRoBW>8xҊ}l3ikoYVoe[Z=8 XanE7ޙ=h yVPmz'-`R:("a` @k.JEj+1c=n'X{=|tp* ?9lTȣپ 1[kEVF~~1[lvVr (HUZdZt1)wnIa@QtQtxdu-:);YZ+єR3.hR2?5FpSP, X.4CTvv{hxَp9o-@|n@K >yџ -y l5ʝxO$i/)(+n"1Ep%B\Uu3=2Pk>YlA#+g{e aq0beb3]wݰv.g.fl".+`n K'xGӽƿ'N8E*;mv] ٶBKIY4PVX@Y*:e9kIGXv_퀅V@h+ Ttbl+!w $rΧ{.E60OKJ8z8|^׭6\U:dYrTQj-kuL-aa 􈻰8\yh=O(.L ˬm:loMCVP~g)1uhaZݼ)$SOjs1R})#k66nqlpWaIB)"vFzFfv"{IûUj RC^(;.ۻ[w(mľmn+Cl/r .ˑHm%Co[%ŔR l,bš# !$WQG:HO9!YVY~? A:+*)6 E!@!JIb,u|dn1AavW".˯G&ʳƥEy<)e<Ԩ%'X}dH_dYAsD].(]9AiQ((N! EGE JH&7P' D)lDfn/$;ˑdVn.yHĜ]e 9ߩ;rp@.IJ_AuȜjE`420YSB)37cb^s\92[ n%CN;=Uxzl^ uYmԫ`/zRZ*VKEj(Tz1=Q`B䂡.@FNMo_~\H"g%rQ`톸9P&OP/"Wg%RB~2%h5Pf>OR2Z,]QVx{q:-̻eKfGb%$\&RӔć|W_nk硿8~ hm G_/qpj:?}#Q,6KlST:gްAB,8 ]y&y7hA cMOdؒ'݃/-@g.'ͼU^z攐^9%kdN sS0v+.ľ>%ʩCEձP٢Ҹʾ5CH䀖=}T1LXQ/ eIpF-(߆Ϟ>_zZeD/,T5{0_kˈZ[B5Z[N䯅1QR~/km_kw_kˈ_kK`DZ[8Rb}kRzgקX<كiz&Щn.MCąEN~x1DhA?Ce4[fAZeK%sAY\dm;R\ޗÂ˖ pHe+Gvy I߫QUC^9`IڕD}r}JWJ?щJ4ڮh&.[ .m(D |kҫP|bqgk }Qj/t%w7QMiH'VsUQ囮X]:B$jÿQܸX9ʺoknyBV* 0H(URЋފ}p4ati)EObTs2XgÄ k2÷4>$>dKӲ^CH[~ɫ%#*€qNb1IB2(ǏضD7])l0y6Ǐ,/ ZkuYY&3[_="Yãgsk%!|rݩ8l2K@}HjJ+ۊ`]nY3@ګHiq½jF!(m-'%o.ax2Kc:ȟƏ,/ d:wFVźMTL*Fi s yxw?a:P"oZ8FQ;OvvV䳀we]|W6ߕwxf* K.l`w )CJ (: } ȧ5FXěҰ'[WJiy偀F( n?^MuĔ~n 5{j/{CORij X}#5v@$TE($lJ+pM\ M E: $Doryͱhތx=Pm (:v/p`Y!;%ia3V+s"ل%_!\E*GmͅX Sⵕ« $Vp$m(D"vJG^yiERi,&Dt0$`:"M-:rĒ4I{*lt+7}jU&US.N59HC l9GH# s7Fe\⾔Sy>MKt${(Cp}ɹ* B۸GR,'dC}Kt q;tb{vux.rJE@Ƙ)efɺWm{ 9`0{>~'F|1GHxx|mb}\uBuIl7>4zҠDR,r}`No a :L_4{' I*˨E.(㊻Ğ(Y|~ e 6_?NGHI:!kn4ush WImUМbWU#nFMT' ȹzkz[pG?-l"aˮBu)~5/wR⮋G/ZJi`NoQ%oy!MZzAj}jXyZEaSAg; [V,u^UUUUU%e n L`1fYI?1W,]re?imyң<֖vLȟ=Mp?$3~:A7ZjEس=>Ur?ҖIי jF[w|zEj:SX7J)g 7 ]%W4^w:pwϽK.)eEJvI ٝV,wrp:O%yЖ`l_^=AX+ڮ0v:|/wFNa~ȻU'ն<\=!Sr LojfriUcM+ڈZ[0&uejQ (rQчmXHj271q(f2ǁr,Ԋu}DSO(1Rπrz^tA/wltхg"A! %L @"$8C><xՓ8Wo lW?-o"-eP!AO"a~LG}Ql ȵž:OQ UIӪd݊ |ui0AitKh29H2Q4#2x6׍ecGMJ Ek,sBMLE> 3D>);Qo=bDtP8: (ނEχ ֨7 Hf[;>:vNtLfJ1<&:g^]1L$y>#(GHɸ(Ixxx 3C;l<;D ("j FIWRZ9bDmB"qt$ ΢dBh^EBIVs7V1u`6QJs^h%+%&n貿*\#HӾ VPwfuSF 5Ǯ\dKE6\f!l^)*q AZaf:Ki*'j Q`JLWld|/4R4䦕b#p} y,NiRAeYoL]*ȱ0#9]dQ<%hlg,+*]A9l1dRVua`Zh`Ih]$c%F\Ltl:w&쀄qoxGꦝ31U,$hTl-Լl}1+?I4†)sk ;X q o4OPmP1i'tk#U1 V *\iPuơzc7ƐZYFAv?8eyFӀIv[n5E: YAW١)\{ј^%)qמ >XH0H]L6#:VO K}|>>&o|.PA Kռ EQV*[{2H5b -x+ q E^d2_<12%qJKr_ؤA4hy5)և08Q+)ӉwV`F2f@?I9^ )?@Y?U{ICr8şnoF {89} Oإmҫ;uJQEM7#X\"`'"rʬl*MTݦ*OPk~=BE-3RKK3cUEs5mN?%ɂ̍g_jMZݔj|dȫyWArYj޼?:8|d^h-QKBڼTw0k4lś|'w(yҾ b4t@jQS'UND[<"F.+][%3g?_a*b"τ7)#eIJ#(B~%67DNdS̟PI0]zHE*È8]<Ѫ W"+RTּ_ܱHcB/3'p#p DK3_y-(W嵆8? 1zIT Ya'x $+W<E-/SLk`釱_L {}:Fg\䦇6te&zxcF=&SQG L]^)/KuBpA`@zϑ$fW0P9VLY9E{$Âտ)&`w*t2[M9i*&cn%-S{wK:a-R_lJ0K޺P!JQB֖zvh݂q x@RީII ]Bx0ǬZs?H/H֊`Z}?ir4coe"JJvqzhHPY״[zgVOҝ>dLgʔP:= W3fS&RV;G݊JY|)BE9#ї/vKTH xNwo3vE ^N•^6\QrذC>KŬe n%u9>Ɯq?bO7UƮm$=~y su߼}tT W;@ɻsROWɸ92gDk\$#5F3p,lAéE5yW0_{5H2XoK> 4A‹|UK[=V)eݭֳD/(=ge[Voewr1}-AwZWν67,ۦCEtD (++A: :zt wKdy^9]%}> *]>=xB~Q (?5% Xh.x.#G @Z"ރhY=A|'F eOch7rU6*"TT3]J @n#>i8|DR(B/2xBK+= jt-e0y]wȝ0A!>gD.(eՃ~i}wnE=#o]\Z+oO;Ĭ)UVsX׎^pek(H>E}6( b3)XrQɦ R2)o˚WP=o,={3SjٛROع z$PNeFnU@A>ĕ_E׹1ʀRohuJ-kNB0)?ZMP?ݱRvW%DVkF3}{ӥvڬ^M% .+Ҕ!Mf[6knbBvqh{3T#eJ&2i3,\͟od%jn+}RMF {a&×Z=y,F>;)eWe_YWpz:7~1ɥo%Z|IdCb_^Mw%v)>2nK>~06fL5!``8$Uz?G`Q9lcޞhED֣2%% G+rk0fLH7l6#CX`H 6 W95ma?WKak1N%ySt)jp`ϳ-6O)^Q񙘌jf{8t4,MF1Tژb4`mL ̂P)JSc3Kr'cIXe,<<1H,d^<4S:!ZlVO9`iJ@ fPײtȖ٪yO[#T;}9E"{ oWl<h79ʙQA8 owV+_Wp=;~ >=vKKu(o(ly3pL; ާxV@-/eۯ0좤HNF2kPBqlRW53l UwWL|;ıM|\w~UHbd jm ج ɓ 2rGbOhrէLw`.8Xi.=(DY ]/qWQp&KQńi٦dmzG%`ܳ3g{Эdl6JbG"_jnj HcLtm-87:Y*L lZ5l/-L|PvOyR:w!jV5`w %NDșG?ۋΉcڡ> BG7{IU qOs}l/k<* dU (sOAfٜRG=Hp*-D‛~Yn;Ʊ+\Ը _a! cp/;rÁ/Ë&%0&cЧa<>O,|&$w N A(,y -BN`479$/u;ith&gـ-ֻ7=TuRhK-'R)=Y% ȖZ$Ctm>`K8s5xƻr,<'{2jbߦ* +?߃ZJc׊> oSӠ+~;=_Y\l9ll:60*'m2 ~mɣL'y'GR`h\ ϙ~WWBյͼ,5+iuY\U`c@l` 9OIG~qS%Om~zV?W_+*W=BO~8yvq>֠*3#fb?OY *pS5Zq`"53'o޽@U{r]` t.1;a]$OZ(ՀXTUp /)Z9z !V6G 5zFvN߾;!PO]9K]wQa'DzD ٯY!Ae p*bO0#9rz@<}gFp %[tH$DZ1{~I܉wWo, u~PB*oH֐z]W\gq`׆M.(I!ցIaYDMϲx!.H'̍u,YQS "WrlE$'1S9L>?+5#h<4:g6 Ӑ2@A1I&8qW[אʞ|8tAaN #%NG+gk>[V0mAD#:\E)Ħ3jD2_[)(UO)tX'npM*~BWYUX>`;5yAbƨf#ZIbI4:7 ^^{CD!E r2qO;5W؛"9RNe]OΫU,Ҭb2W/ Ѭ B3>}w(c@UV`.fM—S7qn^)չ?HFbD+I>M,(OHdSY<, +I(QZuMTUP-t9KQ`݁uPb>RE/uL~"]F$G ].7)~=#1mucIP2jͥXX+; qGL:*pZy"O\`U-N=<7 ^\_Xݍ̋GðY0޵p28 QJ JYP}P ŝu(jFNSZǽDchz⦝NOۙf lҪV=]G.gJI`MDx]jG@ϧ Qa4xL]mțKlc莐0/лÿxÏޡ=' h"ACa$o@jttRR'hx'}7 ⹤I&0J;ha&o7,ݷ93W\x.CV5jZL4-N,3EĞ=hlL EzdHc7>M8挸eWLnI?mHg^eEowowήKr @'+ hڑO̬McjGVIw1+ͽRQoU:tX8a6R`/$QP,3ߝ' ٣qӬ/Hs6Lw5ۚb4F 5sm>{NmWYV+W{"+ Hiyb>dg "p_yDi͈rMT߉=~~g&t=\"F,\Bwo̒ 4n#ϖ<68jэvڡM=9de2IfKm{cI >^JuV ~L\̳twMsZ&Lc>%ykym Y,Ze]iw`?։,N}4O]@!ĥ7 g@ͥR7iwֲղ ?Xu Z(G3Y=$03 bw@kyr'i28~7?~w$j=jϿuw/}N{jm.n]T飝mHDRICjZUSTo+*HGr܀IxRUbSH# |$Ϳ\QnФ+E сEQa)*=bKi᪻i|F[ZxWtmC:V%DZmwS~wɗYW&-,iPc6A._Vw>:]~$g(g? 78dHxrArӚ R&r_a81S_zoY$T`m,<6:wƽ5;?{_ߪ?E^tk hv=b{t~>3]QU&SD#fhJ^Ɓ7aI3WUwlgț\6W o9W*řTxcC@˝!j>X:EcȘq$CAgzAxwk`lsk{ϡ?al\GjJIr3y+pb S=tǗ&8Ŀϵwg ;7 {k/MƧOn'?+,ceZYVVhez+tBoF}xPȰ33Rhʈ"GCY{A,Ur"|xEk02`7udsi] K9t)jKx` ёVPP ,sծa[J7j&qs/ƒ'j_Z9{~StfJZ>gWW=5[ =j߫v '~9z9HHT9 '挱gL<3Ύ(;>SAI 0X[Natpbc1_8nxf=r>,8aEN<"ƈQbz}o *`UBň(/}j:1V35Q Ifu W wN!ºe"2,R_z!E97Yp<P\1t/`%]U hE#\1wn[,/~-SDJ f[⳺,+Z,μ,'@{T'w(bM۝䕑 !}QdKmeۣ͗Skw"s͸dr u}ēXIqԅ2^ّmCJәO?$zI&C #=6mBbtj#dCM%oI!'!='_džC;͌'E !х~OGڠ(ik C{|/y4W~mQYFzcjGX':ІNQ0nMsؽ\ ]ΌwE%]ITSwW˻\قW-xe ^ق'ἣ[qimNXp1)V~/{0{klqhN V*J |mcVl7bxksE ԌM!@P:!/08̽ưȧ.l }C2S>WRM>^ĘU[*/YOft12.E-WcZ|nU%]a㛑? b֕4-tq̊ zq /ɨ܌{^,N;wϽ)^>S>wd[|7Ek;KzNe] 6>Дv_gRvj_~ ?H֖ $~r`x3Gg;Z8!zvXLgnck-,wׅ`9uqzUG) lJ#{7A1Zfw[Z ]%1t |<- ܎4FJGDd3&C7hjIu0̈́.i-dQ4F3b uӈck2 3IZJ^ԍt "nhK+\;a_j Uo[VxYvG|.-Q0$wJLg!N󛽍+qB9`$+CRN oD0llBybB(|wD^e9VY:B鞚;cmtdK_U{ڒS<&n "~&da~}) dcv>q~ yt"h5#_|~݌I`i=?:*$Z_+?/%Vn2zE}rY@yNnI\lCAIGWa @o|Z7\\ a<' ́AVX7V*bi!V a4$:KȽ &d@Y>!\<3G+*Ð?A.ԉ82 Z^8sWKQir~Ֆ{P_uCG$RbM!7ou[dO dǤR6N}`-0Uu&~8n9W5edE~-|nV3Hm|g9Zv96(:hsj2#vz2NStϣQX5#?Ƴ)_- OIkGxV QRŸu+5NJTkݳd4I.uTH*,vSt!" }HIH+=VaI8-/בSƎX(l:*)=[[l.%U<[ǚٺD䧦`Sxw}kmnb1ɯS11tcpWE<Į?& k33q2v>XAjˑ$h(Izn?8@4Q;y8b u t'I7! `g,;Hb_yFdJsLs\`]:-uD4M1f|@sD*ObP` +h4尠P3RML*WOHAPgӄc%SR:D6MUYdI[hy7';.ŝz"˪2 Hl`}IqO{`2#kFbc\Pݐ~sp0/i 搻ڑHyՓd+=ٻUl^zcŘYw ޻4f!_C!q4M85yٿyy X;U;;cz3B"1|3ǧ \7 ;u= ѽP%X2hhՂpp~!|݈۠mWt8r@$FM^4ˊ@Sh?i﬌&L}d,5tjJ,ű!E|0iNI)cx@KӿHQ:mpEQ4ea(hoydv^x|XVw6K޺qip*祵Gqiir+ͳaY, 9dg.8̴V ji !vg0aW5qbOλ XëaNku&ij^lU1@k` `OEs}N5 ڊA^.d ;c͸Uib:,lOV2mQ\i6,FS<-DS<-HSrqcԬ:O{YuS:9<$EӫuZe#W{Q+:)oAXIǗ/;!6~cC-GF N-:DKΉgJwgP:j6u'-N]Ѷ+,? };0͓ii~|dU;[LIonN f:,wirRq] 򄹢Ab"Jw@ Hy6N3d}LR>ӻ9pC#vHϱy4ly>#ZӚ.%7`>J%h'#ؙ)@87ci٪L&ޖC>!O[;w䬦va2(8b k"02C>f&56Ӑ@L.IVQTX4I[LO{َc˜r3TX0jvvfǰbshlg768,5zRiNlJq`:8aQSMC:uxwVgUv혾\˧rǣu|6?6?6?6?6?n7B_ qbOK,$cGR?UR7LA44 ~L?  L2אfMr4Ewk2T³tmcdva +gz*7dJb/w"Z8NوAK, G(t,ݻs4 +R Z< YB_൰X%)]}/ȮlZ:MLa=M mX/*"@H7ӀC1j~mvk2; {6#irpL16Iap0_IK@@ NȢ%$R/Hf'p-"/D76l( (|=d4Ye""%xq w^LA ei/xDxR\5K >d@6;lگ_y"@ĞP2ÄᩔOlVM9΋t5/d"(wVhϞωX\-Jkt?M&y˂ I5@\Qy @"sL``ǐ$p!$\GFJ @"V񴟇*NJPV.t\ꫨpd'lS:%dKmCN*XEࡢJXh7s$5"p?IbMY$%QxŃ ۀt\M{oD= Mt3Pw1Eb wCdqg']F0amȺܰh:sPSTc"r E2sk v%DBC]FnC4 3nφ;$:,pӫ| K׼8؞ aP](KOuk)(0"(Ewb%N΃ݺQ չP\Ob-\1[yL'ot..|,׍xu |$0lޱ}P22 #CzFO2+ [ b?ۑ֬ሞbhZvpYZ'BI5L"7)Psƽi+D_kӘ<\qh QME3cdKJBQU.O`zQ5;0HV4pFB\3`vРof'7"P#i%;Y羊Tlӱ yq•X4 W <;sZc!dȽ*PCPĒ ,ߛAn?P/Jܚ>cS2n,{qgk{|Vn7^/ |^u ?'8MyX ]WLzv!:uigi:8D_1PG"|Uv2e(9MNn5Edhj7߿~ zBq3h-;En'm)VxxBAON`*^5FU]hdE^:;hZN՘҈Yk '5K?W\5 =K9 v[kjKk]F40<׮[Յք"6Fé݀*STՓ+F/\q5i{iR>,n8a&M=1~L+bN:g;#)9/LpGn=/6TVeZMA"cC?Ͳ y^2D:ӋHr[V&CqLjoajjM.,q?T:נ0c]o01UL='##m@=gZ\[UwbIХ =lgAQSdYV`xS( O#OeܫUpb_adw­дp8E SCb2&V;-ny n>MF.6XAFJ)’ z\a0LK4/ڐiqeSXJOkWmrlLd0Uok756'qήdvkژK7 [qqvy6 wLݵ_/[? |e} y0c1eDPL§9wَN)|?$){A^_ߘkQw/Ϧ*ɫmEJڵVu*V!hdtnLjUZSj&8H+\B`qW\׎ϛc3 Ԏ#J!9wJ :MCN}Un.H7v֠[ޕТBz1Z5=єHAQi j_Zщt\>X5ISQcWO-*L^.y6\m̷NN~}-:GYT-L{}c^q6fzcԩf"oeg)j%gU$of6%e_Xqя$q#WyJ4+˳58m4)ʚn5Js媒lUiݹWV];U4RJv%;kW{\9UV}*%n%[RVwJ5ht?5?L(H<(~:{{_o?\ұnC? ~U؇+prAn&Ҙh%pܗp{pp{5n"UzH p{5qn/J<ܞ3({[at2 5Ax|=.lC{V-NiJzvKrmbJ[ګpBN0Ox{$_-7e6?B] ʯ"|2?&iƤegAq1gO|gE6y/ʊ] Qn?۳mY]MMMMMGբZ]eC*Tظ[[*%&fzY!Cy}9QC{DOzaOyX3Ə&^ Sq~ڊ-,<:mx8&bL0O 4V =<6ivY<浪@`Pw*_m#曨@Yۃo)4E &H,zSS oE΢NKChQdFr¢iB.-H$:dݷPLІ˦ ofN'gd/wk4arO{W9yt |GILcܜBS"_`N0mC5>2qrqnZH z;/On袄.%PJ}Lu)5aObhu5;A (K c0!igx -h֔z Ir)ޤMuSb1 jpxw(ywO8W3 xOJ87/ ZAY}98VaT`~o%Pp9UX4${2E .fP;^l 1POvL^w:$x檭&o7`%K(˓hl:E VSUTޯ*'QaU_HDGU(O`+GM%ժ hȷvvZYlJ:nhÐMŮmqkQivҕ~OFqݶEkM mGUe@ET Mn#"4Aچ\M^hV&ȕGwycΞRr6(QA9I+%MfY5u9Ctl'Xn 9OY'4bF o)s'c%zeM/ƭ-XP'l?D*9KÓ ?{K{Dp#H͜}Ԃ Ro* aKΥ]8~OrMH t[;r*,qv*ՂUۊq bOR$H-K4gQ Izg5˳dW&xt91mNY=BVɐ;'0P\bYI~W5SaķZAd:|I8^ 8?g<7F7# &C3凴a^Q+[1/+3c|e_T/ZrDR휍Cqi<S)_@!a&xAc-U埦I ;1wպ' WO4^a}!/>J: >'Kh҄BPoOH{&K&x -<)&u92͸H C ѼY{ewhR DE~2B#SldX5h?)?)ɡ$'X,hg%|TVњMT5C)d5GPP4SG ,aDGSb h7# ܷn-x7f{fʂ@ ŌP٫:K:pj2MC[TLF b^! },C/YE{K tU '7!/[ؒfjx|0klyqQn|I!_"Jo$(+x#K![ 7F<慣 *Ga>FsUo SP827RS ?J~G| PLV=heKyjG6&$iѰz}e5 Z <[Gݍu|6ύsy?-ov1O?u m7o-{;z:3sK.?QӟtƤsBT?vF7S,Ht)egpZ3Vo%Σ|?9> Tt;}_?s[ x\ wMS"HЙsh؉?#/|q6ʳ9bK 87w^nK ul\v:8[\#a葈 ڍF|@ENCxMǓ}ViGLcJ7<@M恋SF?Y[4UJx"9ސ1hd+ @xL#ǎ&WxxLY%,qbgI;CC5fFgI4'9h1@w4Vt2+xWLeѾ +AO~x3gr6Y3Ƹ+a]邠'z[ 1ўL>qo xN3VۼB1ÆUR@?{l A aL}<`xDq?#O>ORͭ `Yγnר̜-i|J3<} >ZW7OKP@j"w{0h >zFv j`]I^xL lz8 zZ/lY=q۱|E>;ǧ~w_ v!@XTq? Rݹ#k'QAS;>^h N&%Vh:A[NiǎOrRˡ%-EjLGwv2Ϻ'q#4Wo#'%c5uC +ouÐh, VWxlAsC.U%t ϢGP3(57kw!}t]$'A$Ɛ !{ns:6p4 TBc~~S5Kwgĵ ~ \45v6͈,<"F2zΓx^xeސ'j77\FGszo xQqs__3Wlm6?|޾&׵|Va/(((((מlg8MfgJ_CJ/LKkĀjwa 5ו@3Ju?~}j+ ^GJL9.@[t $!k.SemeP@y~{ߗFG[ਙ͝&-Ōez,̭*>цvUwjd\Zm("\.):A\GY6YӾ^u Px8YDzBQIֲP\jwo'9Q.WivQYuαkb#ǷRW <<H Q7AL${ >6<+v>_*{4Z{K Y; )0B8@;7bcڴ[ MaH}ezTԐ(!mPp0޸Hʧ AJ"yS t][u\:Rc "P 0"?)=5i7R 4*kϡW_`!ǁWh-n)'uzv|Hy6m}jI#ZΘ逽dEj"o?Y"O{fzvh9/zrKU}벿᭺A?ON_WcԴ\+$4w曠~6 Y$*l+ui UQ/ϻ/liGkjDPš2v ,|,*@Uͪ&#'>?cv56~|u(P4j5"75Vz阳v~B~c&֐%;$"KLpiЉ?w?;I?7n&cHtXN=*7,/R<*G+:QR Ўqi12_׫DZ#?O>|LoLA6}\>L^0ahՇ:X?tgu^NQ M~ݟ{XR>,YР46Vlv=0|6K k;_ U߾/>H*N't=?ȁ(I٫F\6t6J0"f"[ [`åZIp?$: a+*4hx֠ VƟUoowqri1Rjg/?t _z^->EOc> d#ΓX!>{\?IiB5h& :YI~`#Vxp_Ĺԯa^sJ U*կbSGt(=F뗃()sFNb=WQb_+^?+zdr5ǁTO_ne>u?N^o܏)t{z:>K7979797979W1FFrxƣ3;$_9k[:'f e/uKR11W<~IۦLJZxb;pBv_=8jVr8=ً: 26~=ݢ>ebXt_}cn@L'SLGwQ4A?f+"U{#IYj"attp@ .~ҽtb +zr %iyGқ[!Cfo׃ Gūj /CS,3qL>9Hr5Mpx D&OiNj9'HC r~zDFٗZ2&=@ԈpW<1PF́;ecp(>U@ﵣ1 Fz,!8ϕ! `˵Z^ ygO)(傉Ls`@T$HR3Fz^'ok?$¼L%(j `aγKÿ-El]teL:%ܳ4N'XbIqZzaS0ӳd:, }=4M){"Ccs ![ř) bٝhD IZG7#bqw&9QJr!oeAb~2Q-h%+:fIo;_ju7jȊ]}k nAԫD/ 5OnBVXdVƹBc(=5QXI]-C_V֋nzpq8yP [G{?w}\i oe Bvt'ҨErEaL(%ڒ+& C=`wgm:hsD P0` aYvKFpyf Bdk^[@W,&,d`MJL0?fY Bϒ4z4v[aeS 9Eif8}Egi"]7Izxz,r0pce3B4fct'S<hĆQv -@kdGIP: ;卡Oh zXcz|9<\g5? hxmVtvbKE_棟~"݁H߼鶤_uؑ*NPK<jOoMߢb6N,gS9J!6_gjF%h_)ϳdz">I 3# K98({,}I,vAT!F)>^Bh;j'`Ķ֗ 4MƸ67f'ΰl'㧤@k<.RY(#y^B؉xH?|$ !sh?Ĝ[X/@Qm {J aS%` yL?^q) u(LEܯg;Sf`:Nb}&CG-jkї{-q.!O$(xL]ؚN)@vhTW-}a CcwhP]P*66s)'Dj3Rq|>E|ľ0} _ q傆$2_ȸI.H>i7A9PmӉǮo/;#^|1s 4,ccpd|Qsr爤'BwX w3¹9KD' .|v 0%l~!٣1$>a&G|# at\"] 6&yo}K8f;O9 $搸*w5֤R&Nm{\iΪo㼗 KG;S Dߍq.0f<͖+nDB# KG#>tI3JY}A.aWV(%:wmm݆ZUgGa(tA*=?G?xl<6?ϟ#fzE Ok3{ {&hpeu>/L"J v̳lv &?xqwŃi`{;GӘ$OGqfi;jcOr'~~%mЅ?UQV|>8WЉALk6-豒X-Fs  0iuM 5PdyQbu)Uc"Mo@:cC/9Hf&GGyq5J4dBSP㪮m:>b%YX2I$xܙv$;+pB7=ړVN'T__Zln=n/ʪ{ޜU;j&LlTsC|Q{O^bu r.&C[րh`rrz{+Y =:¾TU_4ѕU='!aRA߲ Fl۵*ku<:qʘd_^.Ri:vpWc4]oBu:V[/TZ&{on]o.0|ĸTwd\{T /{!~* -62UQ6oL;wFoS{mv lDDmZe5zBFJl^5vu4˸$a"wlr R˺O_7hp]j6̾'oY41Lvr5XR}hZ7f;bWgj9՚_^d+U\`$6q_Ccդy|yU|fZԱo)p}Y`ެސ*1(ZGdE+Xjm]uMvvZcG x%Ì:sܤ!wxC9^1c\t͉A99FJu7g A<ͦ% M _ku!xT){{ mQGb{)mY>-\y/|{z|FJ)J,MOVkKSkt%|z8gr 2yEmº^y~~W>㳤6Fh~k\3{@ٶac6MhRKkaB/1f?DWaooaFϲ&F h-pA m&%l12 j=DHtބ,tΒG;\>"xbĜN0* ]^vn<1ayiԕMҟ`9Cw~ш N٠n!])}-+`^Q#\J>GC}ei4KH)=1.ǠPz5RFvv,ɔթY~ 3laEc}MPyC釴aT2Vgcy1{pD2I0jQ/a,Lp Me6NA~"F`Lvkι I 7סB .H;s6e(e7yKZ <@Uƒfn|G00't4U .ΐ՚;w,C'1) h^/Rx')CZX8~P Ç7T4^b]6ޥGU]xCh=Q0;6ĉ֎=+e[- ЏQX^2~u@owl?^4C k #`(]ЕM_xdp|r9$9?RcÈ#ȳX݉^@e`+]n,~ f8 ~IWe=":v)7f=ܒ͐=\ ziG->O4:d'->Z#O[_DOifo x:ĂIJboZL&M3v}9~~ g,~ȹ=[>rŜhׂ,aO㳗Kyl,L0Y o$Ǽ(=f"`u0y:,ɟ6Y;hw7峱n@/ L<~G^?~%8bpe^A\NQNiduV5}D+b{ #̽<,B/䘕),͗0U &3_An ^qW o/i5*41vnhpVC2"mEd=SףJ|ͼDxS~QHUۏ/^>Wvy갲Ǯw^fru!iYVgayĊ]%6H&/\Qf| 4gdJDTɠmϮDY=.%r8B0ywODcn/'"֊$ PMO8bP\2[lSeOӲ^cy"Oz%BEo/^6SqKP۰}9Q7+uѐxr6[^ Db`AK~PsJ%ʤ7D9mʴ3XֺF$X wӭC}w{;j·!~<\9[xtAa^[vCi?d?}À쏔}!4q V֢w"i/ʕ߁ͤak$AP]፠a0M2^31ܴ{"]Þّ9mIc6V"Iz隱d}Oc.~O=x^g57VxcX7Vϟ'F4R0 @yf>mM7^2aVwAVfPZqu_=ᘜ[JZVt67RqA7'W4?(IX#{h 9jb5Ķ >Vnj 1n*Ԍ熷SMN }uq2  ?> r(\BTtI{m_=aL:L[flL(5#xǣa=tǻ]<;PߧqWT)$8cӧN' Ů-OSbDG gRFð]>L=O{ZPE(^(1p^t;3Rsލzk^iRgp\hYm42BrC|FNY\ zbM>%LB$تţ "3XzYX>;e%T ʤ,~ψ&{FN.?7NhQxO#A ]llDL뷷~G?R< L#Dw#[ שndN]+s4@%۬l,Sjsa*F0+:,E+b G;Msr.Z_ͽ$pWBޤ4g菕𿇮gZ>l?ύ@u(|Uw^ dyA̹@nч0Dυ&"--K ? gz[ܑ&͙ ct䩹  BiDYN/DI 8Yd^7%/BĜɢ 1fSPoeCclj;!yUwYXJcOaI jލw!b /Ԍc1h)c "kn|KO@ȻOո"!Cۂzr/πD+%W,g^ l>غa@7jWYh;9Lyc;GdpP9H51$쐾0;4*s4, n$5ʚ|'(nd"@ fl:MR'2,S.ь͐_gbzQGuHQG5B9"(0<4 7<;' { oޚrQ]Ў9:D}1q&='L,~ nEβ>ρuko%exvbư0r~q@Aىads+\i\=˷"j>+{4ڌwo6.rԒ'OBv2x&,E\HqhQΈ޳)#.-l;w"C2X)!heҩa9:<p 8m9 Fu;wv6 n+ ވʡK%EuD@F9ꓫ~ܪNO^@(D?fdd #/6z5Y&bl%y>5?7JErF37j V:5N7ơ JꩧC/vNzW4GH,Z=:@grLUS;,vMQ:NÞƪ(XXJv(o/PHhB {.vj4>{GNϋ|4ڀ@{MN[I/ ;(t qOŵN7Ѥ3|oV m *Lְ.qt_ثz^ 2Go9.7]dB5U$l}J4fgdwz o<+Pҿn|U橂XVGXQH<]^6qZ`}A:o(fc&?w^3׀纎`ŬGɝGݔ5:wXBeco`5ڗG>sE* < ub0їԪ"jZR+e%R^Hb\oo>;.:ϣǖGlo<7ߍ ̯ìW0@~VdHy_٘c5gy U'y Qg[,&u%G݋a8$:4k S[&,xEq+hrpp? m]VU7v/< VPfj?qwSd5IfYV$]􈱚?~+/^}w;sSTV|"b03J>}ي^l?iN^*ǸH Kd94xCv"=}%`A}ˋR%){✣~w?w[hnJ1. OFh뉂xR!8DFWőO1!DarVūjʗj %zr ,jZ§'q%{o V#Xsj#>b"(b#5n DaLC(o%s=dOu(܏4fK4 w?7›xII\t׆sY#>Y8oM.}q3R~eX[h^`b4DK wQɛQd/_&42!]RR%򕽟Gb |5滣`6 md`V:GZXXfHz)FzTKgcxЛIpe6o`WW}nsܟEVyo}{7ߍwcX~7kPWf͵$vl-iC9EWDP:Oa) InQ6ݜX2zt/jb x89h gNGI<QD49G|gFS! '=)"BLp'S2H-(Ɛa+D2%(y{{[nZ#ؚ׌nE]8yEh0Q;\(}d/%RX l;C"b a zUn+s#* "{@Ld?@t Zp`yZK4<1BcG-OTO}-o J;>˫4{bЏגJ/y((0}zZ}-p 2w6aetōI #'XӘ8i0fl"= ѵ6>Na\n - %$4@Ph2pF@<,ؠӰXQb5dz|ҥI}Cg7,p؀+|:Z4QYnXw_p{v7?峤/l,?EfWpOt#~rO6߃^;tF|'b `\YҐC(Ͽ-,Kj!U 4 ȟZ)xv0N5uӟŽN䡦j}mjC^Ywu㯟ns<>oD/nO f v ;;\i5֞8Q6P|l߯iٷ ·|it-X{"Zsyf m!mՙGVV:CB)ͺlA Y昃Irد|[4M5/&CMZTO <:V辴>".l^bNz,V8Lలe' <Ři[i{̋9ޕO)4 r7D4s"ެiD_ kȇTY NEQF\~H l~;wAT{y$bxYD LɁ$_l~Y/T Zt(ͭ,#ihԅNeʹgeQ6)1>/zʩ0@G2;zaTl?`PO.z*݆y疥(o.^FwYנ %?`DרufhqV% 5 /j`"̊ӧo*_N \HgnmNŶoI6 ׄ|`C6yEQq 8xc]Y1Xߪ|ᐵ&d5M˰*'cLUYSL3ej.2N'Iv e.#ܗ, 6]d>lJݭkeG̹oj]gAd8_ s3uKKTi"k'밢YxܴNkP.Z>CeLWΕg뗬l`/)bnǓm?z m]gCc &J:>`?SC>0{.af>aF:J[Y_ aJ<',FlsBX; +=aYYC ,"ƨ1Nޥ*h7)GgCpopGEMۇMr }ߋA<y_E><+WEC;|Iqar[?'E8,&IWh/I^yԋ4"ylkTt @T QhDQe*tώ*Ս`&:-]4Ad4*P/uQRĚGdK-LfSfڕcsw 'LQ9xOWtk@ TUrӭxlHPk)FR6IWb zK]mL8'ƅ!lxm࿸-iTW 1YY 1 hLpA޾6( ;z-ܪxll$z.⫝̸o~cx2 ֏GXlmg!} e^ĝ4`O ԼbpEoOXmxj7r;"6J3`}-mի}x-|  6gikbU)jl陘h_o1B3xYLtO:/;e/Ez@NJdog1t$KqM=Ǜ] +gyB$p )=BQkK.3^tBKOSF,3N)Z o'nrWp6%yeF4S& ewhyIMeYLuG4;hN Dh Έ`%Ni]}dzٖ55$>Wj5]<Impa|2q0β2$SBJַҌI Ff"1?*(@Q Nl+"ed>&  L? # !4}.m1pd3"MΡvFEW d6a `N,r \ds u0-‡,o2p,لā 8<e84ob=%lMgva$gjQ ,5!_<AYH,Qd\$0] ŘlK.[z=؛ZȻ$8,l1XY3,'0Q& h fJҷ(vŹ=SRȷ[ m6@Wm.W _/lAᳬ/*G.B|H$\ba3MI (m !G2z01 !ƌiEl}3W9FӶ>rcϫ;Xu%O'RYi,ώiw&rF%Ȟ } b/}4@ݣm\"#1u ܚKM_A!J2E= 囖: )\h|6f%nI_@{kwephqȣ 4La.5F82f#KY jpLhiU)ʣbJ !]eڤʡP㸈1J`!L[)# U8"^4$Jl SKc{s&/ 2@ȶr լ(Hh$;=fj1"Jn@{c%3f3 "  rFo%Pӄ;!B=%PO- U:*Pg-l.('u >;| \'%-Gj,<\qEe})m'W|D{(FmPZaHB9wF;$w֥JEXarĹZ-l冭,H&',&$frxWWa9X4B SZq|-$ɨ];*]9"y[b}Q{,63qgKH enr.b_h10yvIՏoGR|fM"F4=Q`4Εic`  w3ln n {%뜚5)gq,>Ł2H 㘊;`<8b23L4$m?pjK4IH\Fɢ,Mhv}'&;1 ,)#&;d-d=-_Fq1r#kbC̀HރhK =>z&~ZmnҀA{(iKݧkߧϯ ^xQcvE;{X-lW9InsQw^le-07 {5pSI^\oԶl䙃Z"8aZy]76^z(e:g|뜁i 1XEQ`&k1[z+52)Z,3nGO㟞;v" "L69 >M@Pm ̒*ܣQH@sc݇9%ibqӹ!ϯp#%Y_h|s'nz{"}/wngjjwfURr_aIfyln/<)Մ,!@F[Z}^Y fCm _B b$wdQ&aҎ1%ǯ^z&p&K}:@bn~/Q1w:v_f_^ /}\(+P}-{`;=?o3o6;o[// ngxem%` )Zsty JYIn;/o7.!7-*h<'j\"vHQۤȢѽxzzr0#Q^V~wl,MAv$ 5|Mh F;Cu9%ÜoVKfEIT ~o"-(~$ Oe{iA4UÅ ܟMtxZmw<(}H1TSQV ] a>gEO );/ вvyiO;w"O&nh P-/?. lH]9?NcL?\4{ c"3dd_qr$91݋'2Ykk6%dt~{UcC:iwlפjhd'`pjj43H-mH,$aiRmcՅqn ٬894%Q}[S9TF,I_\r7$ |gf()@A;qe5e#ΩU,ttF*_6AɄ\=UU5v P "l( l. "K.3ǘZ2L7y6g+eUTkG0s}q:gKQh{u-ws9ݜ޴AttkM~|ymx8 cO#l5TڞMo{@C 4h^ߠ\Iѭ۠jX>8{m({{FFomiv5 ] &yGм u%_y6Gݮ7M6/P#~7Bp1 ϭZ`e7 PY^3ePH'ruQ6C"~c@/, <O:M!]^os2MO/٢yדr|c#\X81)4')*q,"SZv@2PPbr(A< Rtn-+\d>qz{V)銪G'# zV-UN(ë=9,*Lsp/7F2>`!-UϓI' m|0|)H.MWDiGT3=$hjʷ{%u>jlE _5Em+Ohzk%1BH `)ן8*"aM{F ʅEQ2܇1ȲF]3[mHL wYi¤$+q]9Jss jXw/BY,& o̶`KFO`jIO! WRX#5)Q? |b˘{ͬGGR1GYo_>FN 5ycU^+Zu~@ fj6\ܦpd7_U~Gf' >~vKG~$~Юks?,sĜU"'%L5,=&e6 &dR1x4޼9w1G?>)E<,g >[z b7" >-g/?|'kpt#Mŧ\"ytI$Zc貶60O/kWͶwr.3 >$ѣ=&|Vl|A6 _/|A<oe zi1rFs$Q@5s:0I?pI_+n?FQ}[zߩY_':LoI8m N CD-49t u)i牟nd짵XtU0{8/+YJѝDUlϋW l8`Dc8i@ ޻<vvVa[jY. 0B% zVt6I@GKKxje5;k? 6"! #tlN j2 be;$̘qqŅ_&EZY A?-X,S5и6xxE21?db% KX]~R.~~Y- *2LA]Mj֝b&8{lj!W ZTZ&B0u]İI% P"PczCˑ45[)>o3]vFIzBU{g E߾>{϶,WCss*[@ { ƚ;4dBo?e PTPeP[qo5![ gMS#cq#(ϾE ;WQF aywanދ{ uR\oգvM:N%Ѐ謅=.ϤIm~k\,nA/ %J\/Bo~_|0n6ݱ ȣ1|fn-Yi+i=^Q8q`\68D~gHzs7ʲ=O~5 ]g=گ5o gs4L&}slˉ>f,D VӢ;`$v V.w,P` ;\p@99e9M<5ZCss+v9F͵?SneS6_UIs#*[̇ p8"d>B1IfF%/YwCQUJTޛAo +*&19Rkxqi/0WEÃ2K__m] A u"0x /O8|Jo2)^rUc7Rȹ 6VJpҐꦪ8JDVІ9PoI< {m~VL4:##Sj>'+=o&xe.CJin'}LbCcaY_j\ɐyZ[͐M&s/ÌY`M1UD & \爭gK 9,\N^a.ҽo/ϟMb<%ͷ*fR#Ɓ|y4@ϱ5` o>rvl_ŢgLXYT>gz!;1_(E;Ϋg?[7k E7`o-5]m4E&dS+nsv /Ro$]WVnGJR򱶓0L>_kO&KFgۦ/1;-KuRꆘV7"E̓bI`)Y4`O 9@ p2Ǖ.=g?TO 뗯 wb!vzavGʓ9O }YI|]β}:DcD8úoX<5*'ć<,˷"9{S.0&BKHuׯ^C+0°^jWxdRY/GAeܖ;,`F)"Za@\Q`xYi7<_: )wQvX]ŪB=Ь\hwڝy,v'6N/hcX]Zt 6PZSTlt?F֯ kLU]J[*s}nw-;2Gr6u 􅵨.nx;hQ]`,E+ϼ#_%S`t }$O&[+fkKjc6* <9 <I'3O^'e*r~qَ,ɷ5B*sTq$(!l@ &lZ཭c<,T+hгc {RS0m(%(BRHHhv::ciQ׌4hf8LѰφHUA-ߢ9;ثEgtG y_V?\A⹓ݎ^)ÁGƇ-\?AiK͡55p.?RU 8'Y:BmnD8 4vm\kD~:.3>{:Yȋ+0*,%8EB`H*-1Tg2Ʊ^IuPR0%E*QVDu1H3SG"Rtؠ>?-%b<^sZ>= i=+LG{cn1( WT$/i{dAF3a,O ƭy+i? J2/_Mo>>:0M{u?xw(봟%>B _cO]3NGW[i@hDML)PFcx̎jViB:Bފ9x'c ՜M@o6sSBzoH&{C(IO+sdLig=}A7"{t2{N-c-2~r`|h¯A/ք³^= e ,MI}4}9!].Xj\ yRv~)GBUO䴃0,Hp}g`jRlZvjGjjf;w?}q?usŏ]Ò %pG v")K3xd>f)R0>(](MV b{Cs%$;?f<8&nf,)(E\D]J!VsOS hp$-?MI!G5Ց8/srqN2^|1;cxO ptL&2;'+(jI/;M}xnπW+@0h }=k7؂}@;lyܺe|su ӥڨxxcc76߾s?-)={q|*[ܸ|?U-}?җ,o_h%=}ֲ??NFj{f/ l +[.AZ<2:K2u aG#>=A(ë' p%"-7ſNI4dIE/2$=UIN!^ԇiXy:C!wBG AGbb80);VP7w@#<)&|h` *FH4P%^}X \tca֛M [,>Ob& 4":wrd_׃YhWW4,O ݹ% 7U^^-n{7(TzpfWV5~mP.ƌ0.5:rQҽv;"{#ب~HŚX[nEo$q@QE1oN?1ΊbvNrD\O"cZ6/kǕxx>PX{o-Tf;#қBǑO"sn!C%-&Z[CF-.Yn/AУ0nYk'wb3vwSMb`K޻Z5Pdnڭ7Uq>s! `&o4L=*oY&/Aa1T65eՏ8i'ܓ+hz jH~C 6k47 Y\p/_r^Ȉ8&)y-,_zܨjNcl)d'H&jJۯubq&V { W96` `wvvx҂ߟ]2a;; ě 62[g-ՆZ`[[M݆K;i\". fKJE)蕲|B9iӛx.90-NҎ,.&xzp$LWfӳHi+ Y@Hc0!@wmM?Imȇnq<:K{u79ۜm6|Q^u@$(! x}zٗ[3 CT0}vl@f5 Jqϱ/UAך ޼0tʎʫ}8.L܇rتh6[,6[ݪln6J ^zrEu *\V<%ψgH `6ǎfw͞o6{/dߟ}߳ycNKD&Qas [u:G_ol]p nt.xuAa'OZԸ4W$|%ȉ,sz 2-f55֬P( )۱4zU.njoNE?^ bx\;:0*$~ KԸ2K)eI-v }V-EǽsA^JZ65|ԇ=*'w.t/ĹHhV F0~dxq $EAˏ rtpΓ)*EFSW UA>d Lcv8LѰ/Q/\^jr^}OrXNZ|&/\&o۵o>Yáw y{R*Ex%IT-YFn+$L\g٨G׌q* R­pA`a龫{@l>+ؾ JedRd=WCX`jŰ^ưNF #F³Q}hZ#JZl(֘WV{?c/x/3 ?~:П,<|4VʙpiOЄaaՌ_NېۦJRXK|.s=N+VmbB 4KF;o\gIl|6>o?c>o<:^"q%Zɥ$$帥0ݽdubbU~$b,V:Ց^7 K_OX%+8 6ˁbf:X^ D[3F?s@??7e=?:lm|6@_/bwn XQ̀`f(gq4p,@ Y7};*zou<;ѭڲB 7Ь)߸K"zg~v]y)桻7[osviU7Jt6|WbQ3L/ʾĴݣ^s&w )?xsoRLe?k26*%%r-Å2RIlIVU3bAn{G!E>tIݣ]44C9U/AVdCj1] GIܵ8SDwKkռtZ04l8Mpv}mGK7jnu]۲t<աBN\ʾ\#e@;iVa2- FJ4l3!b yբf0| o Wc悧pv2\-4ݨhSs5):ۊ1X ~55ŷVCKE}=715T/K:bush8}u3fmorA m CubtI d~ifK9-";vǝGl6&s+J.ad"+Sģr͓񰗍@* ;%]?((F\kA?b1lp@&IP?AL^Dq< A('\a&i2UOpbItr@\Nc@ȱ %+`ژ b2!Я%7*I0~ PR擇13 L^\d1+gTcZJ9n?uOɄ9&qrh]4n;?nWQN^c?agh~T5lB9yaIUr! H`[_l )R"+_CH$l9ely)[LIZjXnQj)a{φ#;$R"nV J[E`Bvacq}8mGjgBFXńDc"afa%5XrS@sysõ/lD"&bP2|]]D7ve.TO {` /\L#mڸ\LC&6rauѳl5dMug{])%Gך|.u.<:3)Vi'[? ,= sK_Y9N9>&+=(+uGeC׵<0 ȬbtƳAB3`% bΊ#'Wl3<*V26.JH]%)@4l8 jy琥`:m&)i+U aMswB7^s8vR wvgݟo,?-Fyo:ouF7,~{ܞ/m8oWJv{np].d~[$RYn/9n&Ud|oWn&^Isz5t_ooUO`޼Lc9n0L|'2YCAb[#?6abC@y|x@'O?Wߋ \ oaAs?֪D뱨uk5KܑV3Lzuk{Xdoaҟ Ӥ^݇?Gm@g[ S +leFZOy-&ċ'c՚W_W:kVjU-zAz݌-Vq¤znǓ|H&Sa*Yw&^}< T.ݗ;t|rYn?d30ѿ?"dyv.1`߁:gGxۧw&qtԄR U*SP*eV蛒>FOGx6M-:벹eԳb@vVuX; kic2woNg!xEHPH/?{\ӗ(0HL< ޏ}Cȩ 8z`κ\׀,3kȪꕤVz1cw ?d]O=pS$vZ5 t'zƱ;z{ }x]Ʒ(Xev- wԬ^)/xҨO"OM߿MH~+ҮD]>9WL &&B!Dzࠥ^V{!dE*{u6Zp|ϬA1o">9φb/Ξ <̋lϛc?FQq󿽇,q͙os9ۜ-qw䧚~FqlSKX,HL5t)(HzE6b4HVmn8e/9Ɍ+y*@apÓDxȢO9o;:x]ͳGqMMh蝍X'Wx! ':I\P[Gް]ET$ڴ#&3eXkh`h1g@&i>jcbO {gkKMzMɨ(鷽OC5=((0\%vui+ V0B5l*Br@_7v%:؍F|EI4&Iqm_:ІCMvތvwۃ!sS{O$,jR6-ǭvͿaO9 +@TuBLxuKkQ GІ 2#E*Ã#oprMYtFx#O”0!p܁E4o!ZG%XV>$_9=]3U|VMP#^,@(4  n~hMϘq0ehzRB ry H'=n `y(O@##./?.I7%?<ua![3x3~Y><7{K^&(q,MA~HYx'dݔˌZo0Os}AxИh̨bMM`|;KGW/_LV8!$jj7OxܠGs0/o=*_z@'Ea,LE %#c,Ֆ,* OeUt u}E~|24~y7πDH]pm S#+fx*@{;Kxh d0t\.m˷Qn{]u|Kam)^1P9/o ѲA  cșKvA\ ᰴe4P 匃DXe2U tV]In|S}]>5Kzi1*xz<+a<~:PD!N#<箐 t_lpyxs<<'y jЕU\*/f?]GC⳴Gxt6N]d4woxi<8{߽zfy~ =H5mRaGڎe=-E>5h}@R_iòLa6˻z#n10a"Ů4FӢӽCA֡ zۃG" 2cQX܎vvvZ$wgs}߾ vH|8P/*-P:}Au5ۚX_i np"&p}Q!TO9&͇qvnĿՐ͚xRg{D&j.kiB3%33¬xwQo>kH32zT΋ZVTuy|V趼ŒT4lm)IUխrtmw)[O^$->" N-uzW{$<Ct^8/w4GEg5"Q^,2W([Pa1 s^h8Nfv;QPX'܃6͊lЄz.?R}6=vI!X4I5 M=cN -s0YYd#rYʼnxwߤqK u/;(95aqE戳xl2rvHDeDY1Ф"x~^Sl7E,xΞ "dK䋬 "B cL!@8F M%>QvO,HT+ l]+zZ4;2蠩MmπA2'B!y4=`ѻ',>h!gp9?1'iN"өHBhZ 9799 FH7x[ýUUi{P8%d8i(󉗛ȹtвKROW*d1ۤ^ɨZH leՑ%[> O:C PR8ф!q/JŇCs`Bt6aBqMyY!Z!->9w<Xl2QuC%!D$%0WѰ +M@+e /(O;0gcFjҮ>^_^ͦGÙvwfa]߬hK) _Gozs=}{WG&u_[x .X M+'5Ĵ;S Hlc.zQ !([gGgRaJ@Հd2qݔ sr2)>\@S1v="ڎEF6GcF:]t5F8;{;"6 Nmuֆ23oRB^+.m3!ܑ)`j.<+j#B&CG(wM>:T(e)S8'9rU&@\Dzb؀-)cu!YFZ0\ҊMz^t+9bÕ~,њ 3XX.Zm-}RYn¨fO[i&P΍ XͣiZ**ePShK)D?mEݣ{Q eiL.Zh!Ky,E3;Y֛kDb}1Ƀ8gV13CBGma!@ MV։۪c=~ a愨dR+_˼5s#E}hT5eSŷ{8VKséK17ܡ=O(G;k7Vϑ)YL95jKre>b:}!<{t,klE)Ô9w;a'va>69XtkalUȦ̈́܉&0蠿&}=d6i3{Q;˛9(3ړ3Ǵ&T`>*!6󘥽pQrtx=A9XTh:<Ɩ;EOX*'|;jXtU53qg$;|X=Q mi <gqb&O4X$BL0hi;SRo՝k].sٜ"M҉^ȧѨˆEH4ݧ I]x>mL+!fژ?t֣-N|!#EȂA+Ie.e0 a} a [aP̓Z|lI~t sMhWrzKD&QK.ɏh%_ o? @'b)11qj)Quu,ljixd㑩,Н. %BY_,qd! pN~X0Z 44/ bFnԢT_X%G"a-@AJv9F Wͬ~&A+b(()4(WJC@Zl!+`l:)s q$sHΈ]~)"#!ASkt?n+`jilMV}L-YGYz&bnB`nAE9zVلji+8;qW~MwG]j]k>uCZ&̿]*%-glb')Ԡ2ZI!.NDA)'U]S9`;2cYW709kbkT] xU^:19lc֎xhhy&\Tƚ0~ H]mgKy3`v2 zGm+7x+]}4jћ ^RX?@/z*]dM~`E#Wt'@@ȣU2 Ϣ^; piԟ@qeq;ʥU暻:픾0fYyi"uC~׏;kWв$GP7}/z5/|^kY DrU6O_V0 .`{]du _\&ssUwj w<_D9:[,%L0ۮ̚;yKwNg^b#X{1GpʅٻVA)ZQCd]b(9yDo tdd~0d5-s1 - FDz:K`#vs7h"7D, $,`7%z&n.Y,,'Sh!Iعc qSs69^<8ÝwO&#)K#_ǽiXJ,z DxA6TU3`^jYs>'86N l}zU.8 װϔk 3_նf (/ с8| -0ZkK0@lZ2@Vj{mA-0t3̴uV?)d0(Yg N @$ TA&b< k'n!W4 =gVԬ5 #GH@߸i:Q,3fL`/u>z ݇Pg/}hx:>V?D/amHD񱖉`ۍ`%`8)Z>vEdO_aiqun-%\q]q|(Z<?xa<3 a?ʏ80b}uMqg|L r|*?ݑ-F]7cX7U[+g75O\˻ghjwf5z_j+*Ϟ7ĀU|G<5J,@6jx>8ȿ~%D2k[5 =)jP=I8ʠ+*:ajSAPDj-jv_= L˻%6*"ʁ( Ggf`@%1i zHN;&6uu)կ0 '7à|i.eO*[ V^Df+& l#,T/r.@Mt;vaÕ`츈XR ڝ=xK}ⱀK9u^K> {ړ8m)˽;o7y[ Sw lګ\9ZYd=_VgT$ӮjfsN]u3°JRudqYAl6f,̶>i]\[>;J:S`I{P;s m4jE*e͚iu#y]}kjj\+kO3twN< /fGg̓xK5F3x;Si# bm,M,߂̹Eg;9lb"L8~˶d-i/?4VwCͲɒGn\gsgs 9ܜnNSa\ OBP:<_>١s88x1WJ0WPtdb=]f7ޖػE);aOk3MN=[Ea5&qY-  2mGCم"_f *+.~NIQ=b><im'kHvKLFs ` $&8 'vs9hoNT.)b1nV%n*Y#AdVE6ݘʏ`L U vs>䌌tkn9RGΐЍ}2 ' eKs{|6c7lwz5gL/"LO IL/ɱz-F00 Tŀ)5Fa\&@T"+Z5 M 2{{ݱ߮7`[%>&tC8!lC>Uw9=o6{͞o[W=g?+xg;{8#GV2us A >'O.ϸV8AڊOA܎v xeKGc]x&;Bm$ygd "t$ mC -PsU4eWX;ōLC~UyxGW {}?o)G7>O oi aevomwz*l;a]Ϡ_<4Uˢ!6{F}Q9J]ŗ.j֊3_/Cill Ӽhy, ZJ/@n 8{qBuIN\H<+AhGMkeiIrœɈ~Fb<?i"mٰHXTmw\}g/$~^keY@[_DLp4>7ogC |wc{f_gac 6-Kn(u?S0-gs֭L30;jfk8z7X0#>nt/E4o!blEP׍Fqcbp0m 7LFU0IYԍبzb (]a)ɕְn0'05Ha?<#lbs ,Iu@="`\`"_&*ᚣ.#MĔ|2JRH5# OpnƘ(2*BNH6@툐- :*y h|),{\ Kߏ4Yc l{A؁H= s!XYpT$m޶)!pqH4X䲧F@'ȖŁIBQMuCBlfhD&z:r ӻ}OxVTe]G5%=OlUY@ ]{zÅwd%Da6dKk >_u3Ȇ")vajޓXw|C앎mp@IϪGbtŢ@Y8`s)=C߸ºYP_{j5H31u10>Te6Hiŭ/?Y #XJF#'>=:8u&4pC#je2kTrdKL[? .4${cT.X9HDEުe+|xJEd:+ѥ3{[j=qEyb6• Zl;Ri\'0Ps1['OA<) e*^S=%<$9m? ]CuJmV Va!7AT T;w'>w='_9DC=HUKTrf=;mG%3[6.tWY-d9p^k] DNyԷ3Rrף\'nEX;;p M[1M)$٫Cc#001f^pSJ t.N`Bil4E@Fwr RJmo` vWGD\x}f[gQI]8)cE,ui ]"T*{t!t,&n"LWDndk8'-,Փf%MEIM}B$lF쏷|/tM{ZI 1Ϣ:?m gx\-xp[վA"+kIAX+!6rMÁʞ4DcOfi_Fi'-Hqb*; n2aG*恊0xVq"xTTZj|HDU{LVAaSfaHu ff!J3 ^MqYĦ-_jh*!{L4 i#XH17aCoo#]eڛm'D9Nmb,cpý=_gsgcX6V&[?皏9d3Dk"/iph%MG LQ LF>R7eǺOր;xP)[6 ۫V)ܽ hӪ֡!mO~;SH%F~2Ka"},2~dq8b\}fLM;7A=%Rĸ}BcZ`zP%m-t$Y\oN_ӤBzYݩ{' @b溊^D &(ڌo4@9O*4܎r®EL("Vߡg9Pu}]M% ^o]ĕ‡2 ŽeЪA<4lѓ4n*)qebcs,H^I$_q)\mxwxjpr x Yv+Q ,̌q|ɮy/Z)Ɋgzh{H>0Ç,H?'!vt7jiD%Fս/EqǷpI[4, _R}EƓǭqT Z c_m{oMF:P\47$o{f9.vrl<7(>?l,)Ĝ |v5߱ZLYK{޼: ӅQ劫75:y?&Z)Yx֨rvךzVFh\5fWdsn3_xhI7|X(q_;Zr[ C*%kloi]AojE6@b|CcEjxib2ز2#|Y7N=5Gt\4fcv42dyYm=[<__X/u'̓d6fie'y[UV_3sRI*JUR{X;=O{] =sXa:KخX'_ }=h"9 >+( P1QsW3 Ky1[s-vzz9G GZ.>JEWYB{i[Ie w' Ӝ0t1XsjunJaƝC}I1 nEf'SGhlSv=,>t49_Sݣ,Gmd;XU"= I6,a:cV' 8 l"ft" O;f=[HuBNS5 "Cq>Pێc99MFcƘR }R;f4mIU tAY3SVzr?\]PBUbV r-yN{>E%`O8\ȬEHWcOCww8ܴ]OFmDjrYC/sb/F-<*(XN9vb̮<1dAj٫y-f^#biNG-c|sg?mOyޤ|JĜK& ψ\TfXAueK # VhBp/KqB`K'#&ډr'ڌB[U-%Ұ.R^5"m7wRi!s?Wf׍gϚf"|y2"ݟ[0W) ҆|޻,!/;c4+3n;R@օ7./|[^e;;JE*D7̍[Zty=ٚUᅖfMFr<̲y< uW0ΎSm2 %=8s W W2/;"jZ{jeo}4J![h+& zHz ~03V탐 C:yD;,d߬?+S[[fs=?B[h~ o{i?=GF.3ƿMS+-zU){ަ.Ţ*EҒ݊E}3oEϢ/d,Bqsc;7hrXxnJ{EY 8x2#E/$ca]8={(`ᅡ3U@j7O6D2Dq'6pVBx M阀>>H'(+[+%(BWCWxWt23D4Rf g`FeP<mwu_̀ZqXtU6ջ]dPe PY7؏fۛM ]($bH//Y/wdwa;AꇘK?o4M]o<{8yجFs7q@Ffwrߓ݄v܏ݪ ?ݕRW~`+z㴠H TR=;2z;rAtX1ozpRGm49qx׏;ye- l )%05O3tI w8YujrZi'Wvx7~g鱾K3p fHy*ϊjŧQx#~$Qei(u$FB]E-:QÌlAˊOP=2IQlߢ֕08Vh%TcۯoVfd'mD &$)ѩ?L蘚: S 2XCm9W:M;MB (ZoPoIl?fԅƈMԕS0@$n0 tT4 .OG3g98Xhhs)tn8NɺD"AqGwL+ )"!c SX-LI,lݣj@~}uSMLnzoϹvG>"<$ _Zz;Djbt>N6 wÞ2 <5ONl e#(8wgjH&v2TmǸ[І%n bj25XW{柙: +(W[q,Ydfź͙u!Z] f^IR捔,P4&ΎbU :b΁%,,\xp -BWS:tHpLkfQ.LizL~(Hv`Rw3 s'(~{&ٕA|d;Fmkdn%2Ѫ#W8J(;szyprn$B5ЯL8qӳWL(%"n̦ʲḅ ;x/SW/ivP9Ҟ-YK!d^BhT:֔~ bt?'AcDvCo.T';Dv2x\amA2N"H. $67 qKZV *;73&kfC wr3ʛ_bX?01K-YW# yݰx L?3 dye DMC()mǶh0v Hi[Ds8Hcf>oZVUCjTl6ӇҞbr6jdHI,dW5qGdH=caSR !m0fFp'Vx35 #+օflGoö+nR] J)="u?vg *w1fY'x[cX##w*sQWَ,^egIF;ףݎwu&woCZK`2^g3e3/̥DWI焹7s sy&3,OLfZp~IeFMAeE~܈2kR`x㈊~C # a3=hb1>9n? ѐ98 !v +aQA!nQyw.?:eE(䰮xZU./=ӥ9_:7#x# kĺ7qeǮ3'Ňv^Eꋬ3z+|oC`0NASrȦ tz͚.!e/ @ n)QNL/_t0aE5"-hӧc{k7%S[5[2Vm`7P"=F7' -]*v) n)gb cCE`=?{tՆ:577Өay&n;LHgl D>!QG'е/S@L$xQɓݴlL/gj@I!@)J8P<KKqPb Pvq1 .I]Lퟘ}Ox~Vy":;Cm2D@$ea>Lʉ˪72 )mNW?ԧ~n3ї̽Pvzl9]9 au:x?,i-*w4#3u1ʪ~t8r/ļy9tM ~N Uf#KDX+Rv9ZDb)7(,gʵ"d|9hY&;Nv+Cy~@LD "pSނE Xŝ+$V[Ǐ};q Jkil[C8:"G.E.jxt}w )^}g* jlٯ_Gz^X3 q3H8$1B}ou`t1Y8 ˹7Bt8֢!؄<[`>mKsjx`Zr‡=t$;yfq"'8Ǧeꤞnk&= AtT''o;ˈh6מ>[}]-".".".".">h.WT,gW5;j\Q TH;1.9f˵ l VT3ё8A㏦\0!Łd(˕ >m#y S.1/v,ϥM%u>7 j%%?y[;J544&^2/LGW)7@+ Xm  ; Yn(v?^*&K𻴑~(MbTF0` p ߉y~Ťcvz1y^,rN/'ӋIbsz9<6x!OtZNpXUy[ 1*f UJ :"dQ)?-K]WH5i\vS{DVrrLW6L]њ4NUgr.Wy.ȄA2~"%3Kl/8a'eKqv{لssQ~,jr`fv&RJN"|r=lѬE)`q 8f;լ ͤj%ڃ&,w+eb#rX +̋Gzisx1^W N>C-P_aw~CO j9_/'Gog'bc94yJF+W7=ADvDut<)L5WZOn<[`| mh\Z"% \XjcFܐ_`?ONJzulJ(T-q62pg=ߌgƞG.T;i"c` =f ]?zU9xuz+/&,?0Gok#Yz_5̪jrCZ0Um1)[c$[."GO1?o; ?άs|*ؑ->!+>6/`q@]+HCkAu̶'<"[8e5H`a \/U<3Am EfmEAo98]T@QEfFPt{$S|xT5eM5F$kZ5N~duۤ+g0RlN )G; ؞LWݩʻSwyXj51ƭYwa>=B )ƸI J*̉Ps~I9x})#A-f $z "1:,J`#,"dXxPޑ{m 摻‚{$r? ߼[^! 7,3WLP^]T%-dͮ3\ͷRմPɂm3V~iu /*0nTQ=ҝa.ʪgR\GVù.ll[5vf-KVYO‚NX5xE%=.s.sx?HYfdE-[}˚Y3lkmAcϗ 9)l f]}9Cl ;_%:mSQϤk2/f% HpXhcZd[QyCLc ,aJG(/;566(FQRדmh5ZH~)ܙ;7Ѐޜ bt)}jyOKnɜ*Vz+aܮ 5ߚ9pєoVKdx,%KLXݔ)aaC3.xh邉 Q6C/fc9T71saHL)k풅Pδ26㯜ZÆ'Gl;k-Qkxip'v;ڕ3iYO3]{>s-ޓsS ϰPV8o&^ e_ngS&.HXFFIHLFXQ X^2Ess>^tB ib΃P)̽S)Yu]LCliO'N=b/އ!n<ωGh#hzqw'''KFn'3n*|=_5)9ٳH אENh:p=岬qq1Y=z{KDAW$@ĆT4@U v^ ȷK:K9>l1&8ԃ@`SD`Say7,)HhKY#дci:d`i}F,;z,uK3'&u-h͋H䋃Ol*(g`}cF?}~! .B{x'g?J6#ۈm69+5ڙUKP̲^ůIQaRxSJkUUIvnOLaYdϋb?mیK-aRahɇ3^҅(hZ[~0N!";IӅïipmiwԴix4r-KY2ѫiH vr7AJvIF3]H(/h&?$TMt(c\KLn7R߲ȝNo_ j^܉9IdpB0H85Ճfx$:&U}rP6T;eӺAH8uXE5&.oԀ Dc#aSb^KqΚeبsVVcmZȠf٦PUsTe]1T5E- :T^5m-TTICS_5W[W'6 ڶLfd&(t}AWCZƓygt#vg4:eo z*SPKF$4Ce]G(aAk2p/- y.a}TY%I)):?ƠTH{ YOۓzs3WlLitWA UKY!)'uNY6I 2bh,RSPb$$3 D~ÕԬP&r€H[?^p^V q;ĘQںDLW`v'Lx.z!>3; yǹ'A:c:Z;-K9\ɾ _ƉM$&Ҽ ud.@68@6-@r*aBGPŢwmZwyho^ǶՂk:(VuP(ޔS~"M**qf1elL .W5K{fITa\OhBS[q+2t:I-ȦkL׻,@˜Riu<,YdfxSrSPZδK䤠uDV0  {g+u<)i|"`@h4˫O 4AV^w+i%_MG DGK :I6$C+AQ}mwY6& ҩf4߹=>.bv_8-e2ne.)3 `U(ޖ+mRBχ^g;H)7O)KN)&ï#-1ͅ*y.pU)% QRBD^Iq8_ѭ⒰tgOzY_4E1"""""d~OMɮ$Pg7ezfu^R+ohʆ.H :^x]V/HT聒Jr_wX:T | 譳 *"5ౣRY::8m8a,12bmƄ!|$jFKs)rQ}M}_}6ѐ{?>eo+{]'L>8kqk#qi̡&, k3$u}Z ~׻ѻhJql7fCI燨/7 deѰƇA2ekHHѦu3.o$m0tIh}3!q8ߒt#!盩< :rߓ6teX<&3ئiIz bAφTVjnF 'NZEJ4TkwF`8h'A%L vj~a\`ɰXTԕgCW?߼EwN~Tˠ*6"f aPqK36r~G^ܖL/8)fx0[],׺HI%H.&dLU^ҐHVCobjIwllIO]-"8`ݜg82sg ..ʾJi>䳊IepY lyMihך˪ yk(zm(*P DGM$ʗ^t?Y,? ϟy̒yvt=$s|O !wta: uQh=PQKo\>[r,?Q|mp%KSfo*ۄ;a.~pl8X7D{p4vf.|+ԔJG)H'$1('Wl2bsMS\֍LQFABD\ԤΙH,v"R.ǡlTY)N?Iec5iTlZRH:VUCC +'OβbK(ǒ'(2%ξ'|$kT3 XB`km<3e>I;QDGq|SJ@do5y.6 IE@czPDK8KUbyOn_ /v 0_s}ik ߃|c[Xoa[X_/ȾLvˀQK?D}a7IM#7I-؈$O~G!$7p])OQ:%+Yt)Jp1ʭU Ȳa 1 6k\UrWpQ9E5b\<%yv&;5"ݘF^ze:̅Z\o"=)K&sU)4t l eI0"H&YΒӱvT@Kd ssV*'&C\PijaYFGte,WPJMx|hKO.̿.\3> $@8@Tj$" rx9rӜ)U*dNu`P {[1Ž%bj"S&#VfE&_g`mN,db,~˿+'sb c!Xb\0.pMF)}Yң ?vOCM4L>tsb$ʛ*ew]MIz9v@lta?<7DM3gJIku=_K1z>!ܓb]»hŹrF+y|8F| fgv_v^ rXbΟH?Sœ#T{kg+̗Wb8&9)XZe!fR(nUEug 1,$DMRW4s"Pc rsxz>{lA>K9TYev7@='y.G.s\&NsO|<|<9x-oy>>wv[KK^NNޟ1woQuԻV2gqϿ { EBE. ysƲyStfay y 9¹![TǴ\Zt-ثr$Xasv-Ż=R8rA/wI?i?Ådiiz2[o8&cY4wܾA2ޫ\cǜ L ڲTsٛWow_cwOWDN Ovϸ]AU^$])R$~tCn|ƣ! 24uY}Z&6;-j{5B>:Ϻ()r 5IF5}aOt]8<_j'ȸX_k!>}ȏddߔ U@5,x6h}xnOVJrT5PHZ95`n PBJ3@KF:fPVR~(~9,dOm@٤Ds|3G} \@zTVu{LzH#r^2ZҺDze*9 !${ΙF'#IimLH@elfR H7(Xg[xJKB~K@4) zPB)HCV↜kye>i?D XI9㕞+4=+mq<ȧXz;bqg-Wea\JEJJJhAxhɉ}+;~K(/+EZdwA]ZjhJ1Q!Js$4PDS"or[[B v,^]A+^˛F|8kpE!"R>x-ZaAhFR{{]" ,Creh /VӆR_!D9á79NTbA(U {/vہ DlGO4@K%ɒ%m HZjCʼr-xbVspe-TTrJnn蕮隘5F#rZv(d ^ʗ7ۅ;md-h]Tj1U1bKRœƘ&b4E}؞(vbC5F*bzcE7#?etp1#gνt6cI0 sq% #v궴*;GDBS&!MhO4?(N²'ʒ76S=\B6&0) gMxTY1uazj[`IgdYʱQs.oL7/>nyM{ kdX8?*}/45m|<|@!0u݁W_4 :Z%CM[dc#2< ?9PCU'A?Vpa\XVbyߟ;]`0Y ;# R%43d^OR ">_.i^3X(j?O,yבqkKXcP,C5RʃJ/`x=+,Jsj%A_dO_ggo dMr-E.Dٮ ]߂kL !Z<[?5GQ_x<,n,n,n,n,n<-poKMx|]K?ǂoEMyhK9&s)ov y8|fsf\znX9&h{wbn%Wv۹ As|wq; P͜J'8fۥrM(&. ShžUp\R—mjAuS1 : \YՆw [*~l~0R0 M%͑Y)Jvbb e8"+xS@1ĐaٶGj;׹Sd:O5b5YTTIVA^.I\ /5uS|,cFiqdHjHIDNF-PF4|? F>7Iͷ{nƽܭ>ayu$S烀ky@l9F]uو Pe{!ƤuNHWׯ[t3V~W5őQʊYv" vV4 ho6YZt8+tA3ǎ XrS^#\8dVjpx;+C`|({~+KTSND#FtAD]9F)lУz/F(*p詩tBX-XDKfcu-*lb` ,j*9Ҙ6NaV䐆S̻RdFʚ2)9vM%б2vz?N=^z0^K,×~K"N -˽Bw4qƜk!M64 (~N+<7Wg鳰< #:#R;Ļ~(k4ؙ {{ε;Uͳ}mv]~53&u{.d3R-s"wu>awPp>V5%NE"9x>ADnΕdhѶsGDVxm薜Xʼn缰-TTSdIk5(a+xz;?N2XàE甭'D,nL2Q\0T. _,ʶ(V1/JNYHZ>HS7F:W6ط(|+Ϯ3hB[[Z2q%;v⛕;d Hq@,avLp' I5/G岇u=F%U]6璭zXa~В1`HJˇ?%\118 K9Bcg1oȠ"y{"ML#8p's%r nп1)T̚lc+zm8"TOFO2AMOZ ۲m@F<&>Lsu*wjƽp{VB6BWx*hӧ›pxveFBc2ITH]]Svg^w[> k[Z4,)ʣ$R$y]0ys;6h-HA?Lr64k6c?E,.",",","#;%ʅBZoJ fH G䱫\v6{=?G^djj5=WPvn1|)jVHj8VDFVM2.%x "l9[O=E qg8w y6w %NUK:MK@. ^pUu_sv#tN 76&\6F;OdM:fYԢ Sx{dϹv1b\q{;M)lA]'mЀKAC@r> Q_MR&6Q8iJSVQ]̀4 \fr 5&:@(?rآr0_KPP$"(]h]vO<0؋  )vbzֱ(}u%)$-~" c 4ڽ)Bg4=>TAk ЈJz7H1pZqVN``*(&8|?es˩r7 5|XnTρhcKi׶|뜝`nfq~Rʼn9  e7{5&C@Z3`]<^uL5 ~Fг=YpqyYXEH3@:s98|r0sѻ37bX0^U:e nv|v܊-J6V{ώZ^N3Nm-gn&sRR}x!T~\PMPjFBU-P6Jv#wN͟'̮f9qNbNBjg|3e(/pqgB`w%n̳:UQ_8 v8ﲣ'8 Llt"ś:{x82&rgUpG u_WXmFz:unK&SaƞJO݊`dN%j,0k3kr 5iwjfw h|щ_Eٺoe)2 U*<%N䪼8)tS !SfLw}uI[Ig5 l<~ʍᕞ*xM"=YyAN8e$0dg5{zV;wZ7n +wTw`B6^Z3B:ۋ[̧@&uYI 1#aT-M#ۤL)J<ԤD9'޷&MZAhͣ{:N$L:^⁦s6E]og45cj)hsN`JgD]q5xsOK3ʔSlsY:ed5&+\<B.} -)DUi{?wM3~K<]LݑBػ+VF+'tʪx>Ai5" $$RjhJ@$0e‰llRй>S<ͬ!dz{$:Dya'p][7\|%EA<ᩖ u$½?Q4]q{yZ"1Ҡ^TkAlAIM Ӕwc5ASc;cN~ֶ%t,“BdZU&nvS ٶ.9FS{gf`-gN6nvGs^zD}l! P,>bNwBW\GļHXӶNZ|/|0Mn:YZK ,R->2c}< s@V"W H< 瑉ďE0yb>*c9?LXńi0ٶ976)z^ɖ֖ٸ w\ :i5 O`2M YңQS"̃\rvE"A]w98NBRD CC[|h`S I71@ȊyH"i (V# ~M8>rt ^f;q6;ʭ{#&40F$r ?hșO}vr` 5͝ bQΝhRY?eXbhnqwA[ʛI +sbZ LN6^9'4w_F0˔(1 nX-'K',),Sg\3/Ve1]@µݝ 0S 9?:zr23E%0WG'AZNb{C'}Ϥ#NUFJej+hR*h4MraR)J90JS`4r>̅QKl+hR+Mє0V.̦TprNɕ| S΀t`0LXL3V̈,>3—:CwnϿIǭݗ/A`<-Y{VB|oSq1r!hFO5(YH E9q)0oHSHeRǑIVAZ +e,d (jkL.'2%Lx/ގzc)9z9>/N_:$)3h~~ߡ!m荮L|>? VtdNO0U4&Fp~r9  .bb!`,r7}`][nDzɌ= ^v5k,M5޲a)~G6صa\+?:x:(#Yy"4黽Gif#Рgw/r4 :]1i0))hsax0ʽ C~sp:ed߁'G?^;gDWG_5e$j<:dwNN~=++p|z8\hd`/_W9JU +h콁'/J:8;_A'}t5hy9}-5  >t(X3"fADпx؇Z`O=eka110O{Oa^9_?G ^OO~>?v4rޟW]j5|Q0rrG_rȁB헄f@ /WY8ه']D) pL- >ϔ~{zpo"#~ مqoBU+g^Sap >O;w؉rf ֛; BVyvYXZ`-/E/s.bzAQgJK\4/"vUj5arC/nĬ׿>P7qEQh xEB _j7)CW/,Z(#d\mݿu\x8e|'=qN(;#wBy{YXss68m<[{l.0) ۊîe>)?haþHX ǸW*xd靝s!mAIor {[|zm.kE@ iLr3p:X(2JJ'^߫{ W!hs)p_]S@l߅[u1 Gzr <:ߡ;0/yT N;{l)lO,e*8I_q&sAs%8|%TN=VF"%j:=]DXǟQ_HfEfɬ4J:C,ҵu,.7 Ud6UP~[}3A{XM†׹tcJNwBE^xd-TaX9~#^a⿈X "Wj@GJ=TUTHoKN˯%uob4hգ#+eaL~?%j,5-T;_:ϵ=HvK'LFmHa5w_L2i Qш1lL_}fi!#-~T-kB&pi!'|mn@Cׂu;oKVj1 sjuP>^SSժcA!M&G޿'^{r!sj0Fd*S ^>N63p')՗ zp%38kZ{fI>E,AsngcF0ilE=TvvRƂg C2ǐ!PiXM4qGa@22c<ʛن{$.Ajlc!Uo/0&`7LR'Uݝ9|rh?A>gq833?$ &T} {AzEtd!WvR~t82"kwZQ|Xd$=BHd#AY,v&ێC-.R$OAί ,ںEWJ2h@f%1N`.()VP!'NhWi=j!Zdfp9EF1_cBv%e _}<*?w*Ήf[2?c%OT@)8Ga=8,8ߥv{;¤4Sh:_F g^rS{!uAQLLBG}HoDy W& +y$kRۘoC >GjHqNL>vt{oAIM2XϬY'-a1ۯ%tkrO*;0AfBڅvk"B Gy| }OPO9Ǘ!5HܸA>-} &b~+h!% Z! D_sm[?k.Q[h~ o-4S{&u۰aCV,9# 5[avL0'e^Sa㎏f;> ͇[S׀R!I6GglaSpޗ§ BGs,DɓkevcK Yrdɐ2FwoQGg-,p %x.q<"a}/X^aCL.3BD۠ RDSH^;t l䮢";dFik 覣T *gRY=$eRtBdf̔ ֹT)k79A#z:0`3 6m*#BenoS!u I 6܂]?iP==Tqt=`LG0}dCm.DOF B⦆4oň`2 tUҖ6=!/&lO@:qP6?AJqx09ղ /?,~d/L{]|+?6P5[1_Ѭ'vH]eDQI$}|]a#X k eR:(LebuY.ֶRK(ZKlvU7Z! l+ܢo{Tz1;/R\-gyyjk7ҋPP(ru'Zv>| }ar_]8w(qof?HrCL9shrX۷Lh4OA"!r nIh(B4}69OYӨXblF9Q8ˎ?)Ib;>("uw׭wఔt!sg^# mb)odPmh;cΚ;;w}66߇, .No, xpԸbt5C1 ̫Y̼ƭtŁ}tSf^n'vZ11/!TTyf]nKhTKV-t:1JTh3Sg3zZ$_-Ϝ;Ko?066|ZB Xh -ϬL!ɸ'㯕X; D- w3_0L^F eqfE>KOr%C(^rG#?4y>~ty@ch3rxJEStצw0,,T9?w?%d}\B(xf qlc d] {θ @ 8CԂΨƅQo4uՍ>p ue45S`쀭jL ˛bSgm_[ߖ>7k=qȜZ@kS =P<:]5#א7Ƽ\[>6 8m˹\vkrpִGxlD:^i;x|3u42$c}XXH!b,:&"Uymb97&p6Q i*qs`kLB]02pj@кy=G\b[ 1%˃XZse5&H&nvhQYG^􆢕ױ\qe\c^\3d`ɰ(#ptAv$ 4:8fȇ#ZlFRݔ@-1vuS-b^Un¡db#h@/PIo95S< yF1lGtXy5N>Gx;zH=#LZl/qNj. 6Rw~`,a55/:8rG+sVrr<k3;/*;+ȟ)$ν Oj`RKCTmSصPxG"ݙkM+X) d8WoO#K3T:{&WTl6D5v>F:opڞ9"՝>w.ׇ[ώJj"Tt)͒*U/;2 J]4YdfD9=koynڥӝ!sqG"3‡$)hsx1z}^[9_;_pG\a*a]AzqIuCHYRFy ҼKFI=2ű5tGIJbvq\iT'{hKި"~ ;qdg ñ :avкج?, /MUW]eFP_L`{r^uZO[?Tu~[Y 1%{th4~{2XEfP!1 ւ>; euHHOUMF=YÊR"$ڳ⹡#g6߻..OacT6ʰk&ZU)\Y1Ⱗ2T0 BI?׿b~5is~@O֏0#3-p$b#%Ż8 #sdw*ŠH"v v4*:4ѐ)EQ7C ϶QνnC|@ V8t{ZԳAkApo-uW TqL^02HWu"BG4H/*F;e(4*>Ԙm׈Q:,&=5i8OXNB{KM7W(ɮ`Rr[ ،:Wjh!s^ zC s"t\s)aZ4ɬ$ؼ]R[SN/ >4#ݵJqPTJq*-k56cȒRfBuuw/rmTU#P%{YYQK$E SCz3IjtjΕǘ4[E0v]y9$ZH4K' MFްv<6DAEC_ճ&Ik#R괂y6 3-nHzJ@&JB4W('; OO>KIPp4.<8_XB*Dy]y!nʲ^w3)/ɲ YsTÕֳs̎ޡߝRt<073"Y >|+Q- K(p(aNlS3LziaEXp^cAT$EZˢ'>~[g18 kLȜI7qZH!р'?g"y`z"ͅl*Jɢb.'StP! 3M WTzo^g[|de`y B;&,!KBØ+:{2̄-1zyht뒩m}•B<@ъ63/ ɖ=HD 1_jtjtC~I! cdBb/?ȆƦOlG[VTYջ׽1Pv_7]#ㇳpj6 F-&` T-\Y[PUL(Κrz Z[J,TX s5`;w'qfx|c3'FzſHNu+H=g=`F#NdCg}G^εcDy>X 'g%QQƼ0?7ʅn2I4$ ^y~JTBDQviW4  :{hԆ&p(ք)*Ԇ~t6,{,[{HHhA bϫ8Q6w9Dl_y~>;OY6*Yxf q*d Ĭ)+GVv j.đK FhּjV*i; [n; 'Iyǡ;<b0벮Hr5&1Bwst\LtN_ yX*`$.Z8*XX1 hXQW5cE'[F9'K8[:x: iϒo1!q4[K F[-SckU Ӡ ʮrA]bDzkA{~]xq7P uƠW ]/veg'D3xŶN/I$ Nc X,qBjae33$iASncsI!#A#^?f1WA"fUf-Ӏ3 s)e͢ˣ- ܵ0|88k=xd_g'q?=UW~U.B$[bb?1tstr!,(k؆bMwxt]77777-mJڎqc 渡kKD$^;fEt|zx/1bxF9| -8o]4,^ T"ï X&xij)T}VAHwHY)aD`{Qic(֏QHo"#"GuzmJ# 9zDŽ*GF" >Y8uHם+.t υ_3!mZ"|B_ !9s\e١ãOMAjz@< E\6{@ҽȡXHWc 8Cb<.|th^ݐ]kE&Tl#2.N N;{ިכkC|#( )p!.H+pfON /6?(W.{F}|4M}yc_J)0ZDL-K@\ 5/pa&g.J}z!fn/+ȬcXjQP*Ū뚗Zx 2|d{A H¥l^Wz',U0󷋾p?0>ǯl6x ӹ?"{P0!.?UP Q KZ]FOs,: 'lsv`5 :c,~hBB&l#vPsQ-':5Q.Iؼ KT]zO|5΄pӻ ]-!hgJ)$be"d GQț:q.jp2E:.v_Z7Ģ|%7O="5/$-HwA_SU] g<FFMh4,?vVV˥@,u3 P`\ p9.ih[=?4Lw-n[oyfyX`[oy>&;[b[޷ذ {cECNϐ@p2Q@o}B{# $!ǢGEΓoxix~ïPxe.k~roӦW48(=Ÿyq,1]dy x-?]颠8vzj8יA]V]PY`O1^T(GÒc%]yB\Q䓽1"7/n|W?? <8-KHcG3Pj6?ø"6LyQ\+ +5 F =Q{a jR2:($jI{&=–3#ՀdygP8֩ >@L! >%oYzB_ !/g廾_Oy^7Eŷh#Fչ, W;Fi5_-kmS@!HO' Ԃ=eⳑN8t;^ t>Cgx"}Nxm׿r\H&{}{ܟ)pokY_Y8,ZB jNsÐˌGxIR~S>jb/'m_ߞ51 !/$俐"ڋ?7kMO S+PTzj-Sovt!8zQ,S߻{L&a& 0CۨB{ϼ,B\Ȃ=Y~ NN#H?KXu1;w9&5~|B-.7֫ێ.;k=L\a#8;zH\O>zJO_.jL4K\&9) _WVJz]~#F`8uXH=cO:C̡%nJ@x! n*eQ]"F8* ,;0>jc2MQZm`{RJ?Nu>di7?g ,,PJE a#,%o@'ਜ#$|ilX?у0t;CZhC%q<-RC3tǗ5&ހ, 8-;Ф?F@ij&,vC wΓ';d'ח#QW3tzj<:=/DOjړxos[b,gޓPE#+&P!{ {Õ'06$gNhBDڸD?>tjΧSKgo%j|0"{GǿM-r"/|V-/>!x?x%@p^2uVz^~*9Ui¬SEzZN.JǞ``'`t;}X)}Jr6]hx4 P}X,%BVpr2KA; ( ʱ99ʧ.,p5>\t>h^0o:\@"lĭ94/0{`O],| (IE0KQO\݃O t\Rs8Jk$p\ZNp&ֳBy3dѥ5`X`BeZy+FfvlFQyR pK7䃌2~&Id6x)wDƊ93z܏Ui$LvFd {Ҽܧ}8M*r)jߜةmve16A҂ bUF]Қ Hi`\_03޳bʧOJP0H6 \0|Q> T"iXe*`/~Y _0FFgg x^_{js~.uԏBTg:@e.`C9mvFGA`Q7k?[ҭ{%4R5N7e<J$k/#N9 (xc `,?r[Z0GB¶sL@dLAbuAɊ}Mv "ol8C|p `6Feێ#cڬnZz9rWBk&ڇ %pCf a%(umm>ZƠWϸك_n {VzFO>2~y|sKQ1 Oa)-l]%3h$!:)WF(9?\íX-]p 8!Nn:͘nP eI& ucDv[WN0͢ LXFdl(HdR{+/ 4SXwg chx)$I! RWFoONiV"L妘¸-$,W/A\OGޣlKpZ#k3~+3I_s>>4#>x[_PE:&lHG*Y,!3׌XqOMmLm|/HWKPakdu ۿO+EzGfmUR?c찓1u.aM=߀6ҊNTGAm{>&S:C"viP%\v{qh{Ֆ:~㜹4•?k叟>~uہ_­~~uւՕH$/a0oW?}ڪU?8x# K"K7 K zϐku8.BnQh'=[g CXG!!D&!w0#O~3.[[QA"/P4 P ko;Q8,ip-qRRN-&>rЅ-:jfHy ²_#v(u >]Y-Nil\L|~FF$U["0e}aEDVJy%^,y} bPW6k  s4Kl-#-L*ۮaxYU"Um9M\3?6_? MSj~Lx[ړj4+w If!ӠKf%I2prb$;+2լWb , x`$5u4tO!4 3 !f8'1 m Cv!@}'vYq6\)9E"W\:A08/p̊S6p?eZؘT:mG tp1:tt ᨈKs~X"e̘D HDPYm3.a&ۈٳ.NLK̅N?qȸ 6ث"#d*="dW]e_celĢq-t\w/^{՟;B荷ݝv?h}Uؾl`R쥥A 5=R+V*Q䦝'aV{Rw>祥#fbJ>H} &]$(^f CCvK+LiFb1ZY)rueUE'VҌaf%M$ZaiI󟖐3x\mKw4@lx)E:8cV#:=řćã%m9v@7^@k$z\O?W F_2~;5/AIܜ&(^ i-#f%.c5iqjN, Gפ 2m3 BIv.l.zޔzrG`1=Rpi8p0 |2BvG;N]ZF1E;iZθh; {HZ@y޾D,J" "(жYɎbMvXE0]2R7BR`DȏO =fJjOfNꋒ)OO iya[}*T);'7ԟ= q`^Vas>oX::M#[Oɶ.<Ԗ, Jˣw4t jɓ*~hhIկ>y^MKwgl[`B:duTJ4pXUd-uO)N*}řsSxBj ė_dU]O'|T1m4J)(lC#ksutm[M'N6c=Ly(*i)m _7mPhQj %",U#J\2wez%p#SR8yO":Ƿ#>:%[l;ŋK?A6/qNH`֟W%ܨZH\ yDCR1Z1Aޛ}d 4X_:zɉ}^dRT_zz.գ^Sך__C+#|ZЩV t'P%G<z8zxxgݪjEuWEpkx)$ey;~p'ʫj=c<1߷~=ޯ=|jwI'oG'g=;4@c]4K`̱o@͘Q@@Z>ߪO~oO~#lZ5wіncݥ*/_[%hx2*^6m%aIJ9@^7/ gwwd4Hp(Gp^[G$ƴ*h:CL C+R+33or=7j*t@΢{(:p+/s^XHc}jds[HN׽",Q⢷(\\= kR2v)9a=~]ş5a8ϙ?vuSVT`T+?YX@-ٛHtۋXiaul71##Yxmc ovyyfFZ#Ն^VLu\mqcLG5ǥZjfkh|Aܬ{1]˩}˫¯V𲖎K+j:::ePVCQr\6jMB $ I-i#ɸvI=]>| G^9}wxt?'gïoYq۝w~qחHP]Ome:l C(Ε91э%L$ׄ^C|)͸O$1In^",v.LG+$ŝ%O94E=cODYUzP*ڨo8=6 < znyS[?oIEmxnJ&wQi9b z7S`8յ*ڳzSYV~  myBd ]4QV-WNnjݹM,w'` 7o:ag%vj"CI ຈ]:x@B>8# g+˞흯u?*dX4Eqhjpc5+Ƣy ]:dPĤIRߐfR6'4e"h%x{ڥveMP߸n$ݸ1!2)I$?Zf>r':e"r9ecf Y%-y F1"K"D@/,=]/[2д;t}`Yuwi2 ;_ CoFmxU66l^+4%tEp͊bbvVqguM edҨ{#& ĸ$]ƺ!hĴ)s#. k!kOƦ['0l^<gG ao1Y 4 r*Vz +.g7(WkkvbfJ9F#I,E*n aHmX6>^@jEd=h}F sGKWd &G_)F1]ڕp Ś ZbrLei3K-@ uīņkRtRv}\v^~!/H|P7TJv0PɎ-"O :ϟ7u3 (H`ѳݓg'(ݽo7X#7 'HU[Âڽ"!yB媥 d6JRzmY肀)qKK?v% ᫀPRۇ ,Em2j =뱨ek꬯?[$Hu[sN5Fx]"=0!bEi(Y´k?[~h~5%Zi֚*G~bvrz!].[§!sw/A^4@G(-+QJ\>0o&A?9z}2,R)q$B:K+R^^7y"|5bJ9GpQb>U&Bɂµ=W(;U v #E WQw/@0],.4:([EUk)HͣG8,ԳGPFu @7d\~fYȓuLZK+E>%SX\π]$t{:x:YCSETO3& 6-mCl0Z;} ߣ&OP8~C}6Dm sNl]ʹ6OڃusKuJ BZ_g1m&X 1 3ifWI,lGC؋S@/UXV^XmToNk1[ UlՏkaa[Yrr/qI"+V3VlDgϱ{17?0u*SX!fנ";>Ѩ1[g̾,}Ɣ)_8H)1ެ/ oL|q#;(:IKa-Vt _Q so{9}v P Vit],h$ ̱usu?mѪ'xаh$Xko4hV6l`ZǛ_Po?:ide%XβCik䑨~wr ?37 &JLRHMzV 2 9-GO" kTb czW2&-^Ŗf̪QH!4+-V͜nJ͉9MRrP#se rAA)U[ⷦ;[*7ʍa!n͎Gqbcg]G3-N*kMRFNcJJod&$ۂ-[Tf!Ȱ?j ~O+4f, FyZA|Oq&-EX3~%0%~mPBr8)]WxDt0Ca,fIPPs(@`jVNYĈOX1E9.VꢙqО :v~Ѩ5^2dBI{$NǾ&T K8aѵRV_>wgܨNd%:OkUfNB13)(KluQ/3`Ptvȶ #MDRGHѰ+Nz*`o15I;OʫDt%)[s蘑y h~6omkf!.eoGTxBlBC3]" ?)HSbfje Ë ߃9cD:KE3~ԊϾ9[4w^UW[ֻ՞p((`!GUE!|fG`+`,Mj%\m(<>ko@KةQjrPޘ5[{ݰ&h~FOHѨ4ɚ@& 6!6%1mn;a0鈧Ei0/xZXֳeQgsy53nZxK#@U=v/SĀ'+ <]JȑڧGjVT?ob%:RɗWj@rTv7_ 15PsMZ7>٢xL^R^@/^o\ߓt>XYs3N(&;aww/vjѭvL<ZGK7f f6_|aiE meVD@ p n dZd2gY4\ 1vl};bx)m2Xl>Ӏw^ogr\ >rO5 CL=НIxfk]CᬃN(េIyqexߋ$/ k2dx4SH)_~2('ދ^d O<lJQ;F/y{Х(]A@-L]R:| 'BeZ=pEaoܻ MFzl&X.QF_pⴌ \lA6C!zbcz8HJ@0XWq*$r̉>;(EnC[~w lVApvZ]@gGǙ<C XQ Ow|Q&xagks:ʺN/Ra70V2K#(Uj;~TaA_2.b{aT͚ ./ D?߱Q(dyfĎucGD.4l/a,-y}oɯ,qҗ/iEFBb`"NӮP[{V;$Uᷴ6JfJW[Zͯ4',bSwyd{^Y6|tP}ETMNJnrAܜ(hbtf5X#[[oY[eRoyNcXZvVt XA(GdmEa߽uB,nNfN ݢ0l+KR2wO0 ~+(Ihz% 1C EQ׍FaX%s1a3X}Dj ,qW"ug:(Wƈ0F.ڥNA0"woՉ/j+~QB<)C/ogL=!/;.8;,dI_vdu* D@ڑ4&΄kHK逹60wv%_%w>*, F. ` aF1kޱFc]MZ06jkƅnmWwW,>+,1dEz:3': k{X)۞OYu ?v׍'/O76 !)b++ "0(&2u!>x찿<AiU =-Ҏ" ~gĕ'^}Soi- |RjJh˖IVةOb:;a-77OvOekk&A}p"-tR}+ )0ވ츾=j1ߜ" aAxiQ|=}cU)7^6G/N}|TڸTRˮgݝu('`ucT-uTU =c}rKW<4P'jQ2gʗqx;wp:v~ult/7Pa{ox ~~Ax?0elNdXf֫Lz_{#ux;&w/޸ɏ52 =v퍯1AJIGɩv% /i' sNnTq<"~f+؝kG[`Ɖÿ'əD.%nf ߻[Vtʒ * B# J˂^z멸PpRVȕ)7:H꥞$$=AiFMދf2l?p *eY{^G}?6Ͷ6`Hk\FQM9e"ҏ)^bcWP]:}Ri9YgS?z,b( P6es*(< (ϧrf#_0N=x6H1~:ȗ'BJ(ׯ aY:6RF3<&a dXڔlX65PVN_tХ͢]@lI9Y,P0R,+͂!eF`Bb§ 4C3$@6MPU/zx_iO5yuW~T0v)҄uk:oMvWcVii S_TÞ7b{yji<8`fKQ lc !Sd\ǰO: jQ2u&p [8 7rbB7wPsƈZ쳰~6;>`!_n3K ~7ĩQ7,c{Ԫ$,-3ѦxpSlk.#\xZii&z`[&J9P`d;<~@_!óҲ|bx>a^"KZ.K#L^z\xZh݂z߭TB dy$j*SyErnqKenk)BDRhAtH, dEvBL2"Ј^80vT(,QNKV /1_EI8>vK{@?VMtJ\@g+Fl~ENC)8`YqKrIZͼR+chtYXtP|~pC<7c;e1\DV0h&޿=;xAƦCdbт'-޻0#F2)~^DQ M)/}rW[OL6 408L1z.Pa ͈3&y3=<+mBŧ_tE҆~g0i~n5KΎSVcof? :>sCx[DQm$7XǬb%H>%TcǾ3,heyJ3Pak euMIJi|}k ^wUu٩+\!8^5>KNxѴ/)f` /#n swA(5\Gh<K' ϳ}dâ 5?y]w Iɏ~w,ت)8 c~;(r=E[YLRF7mz9\24R+L22NWV+DΨ7W>@=X OƽЈ;VNǹ3CT<(̄aoqn 9q^P"KM]"HYxa)d%v9VW/zZ^^.I-]kpGuwA>o-ۗ7/0@2˱!FPt@[UPqüeA}ـLF`:Pn``~Vk- \;W̳s|z% NmUAk#egIE#QhiiI8`1(n<_R㖓DZgN չR\eYڱMFwvR5.xeo45Wf5#/Zxek^ź(_%5&RYl5㻇{e"TYI U7,iV彼Arqno؍+wCns@Xvxwz{s tVpuUiy"Sog`|u[Qusޭ~_{^[Cj8ꬒj\(P66w[oZs}i4m475NUrdg3] o_XDab&]z`{^}ڸhP#%c/ގh+PiV]w>3] ۤkwnM>F`A48+:݇=H)=.TWNnNנ#x [$9.%Zݱm]Uc Vq6Pc( w_&,nԛFXUtkSCӃ{7o($TӨ,+ӯ,AP؛"2WxסYR8RZQVڗOd_hFFz6B=YTTCHU6̻Jy  &{t 6K[6Nq K@%5CdpLZo(N)wt1a#S%H7$QCp 0GNIuyuiF!W BY 'D .Gu]ZjDxyC@t2ہzR /K6tXQ-!~h2$BzeQ3\~]^]xÛƞѹ &; T\(ͶN#!ۣHq3x12 8.V&#zCKc4k1$jK\rĤP"`2c,b8Bz: WqC DpX}{.ATOv_s= ZdC0 al׀ss-2w,tf}gy3!PxR/NŶ rk|i=~rԝGg}F{~sZۃӥ4fb,1#<Д!^Vj-x!sGZ,O\:|_a}M#EtBę Pl%q xYJHL_]' d)E? 78[20n!,ђǐfH;ѭ'hk":Zd;ڇ`wт$Q@%"7=ɲSSnĭO>WŪcG:`&締x 1 оά_k F/XMZOwă!Eh|a OtQ7(и \ "XFKc='ᢅhI DO`&#CdWz2`"2E qOtD!Pk⒝ Rwl{@=؊V@+j0h_uƽe W/UDWJ$!9J""Q:\{Aj߼_X~s[;z% OO8Gñ{`Ǘb.cs,JNڨx_=97q47=/n > *JaYz\ wꪌIAL"#5 ~IFl>h6q6IB|j֟Cu׉6?k?N1` 늶 '†EEQY: ;+ZBx,$$bDPZ*80A]:A{Bl{=-ț"]rJ@&.h/3FMNh[MA3*$#O=i|Zْ6l5iŸˮB #" mr$tglHoꃍM ]Z轔G*)i@ӟ:h_A_~UYֹ(É(Sx?M7mhEW+*Bi44.X(ԖTJ2TUBtǒ^{w~m|-_^&ǜ^&A2"_dp2gq _&2JL FWvDUǘF0qi~b;75Sp1y _b@l%FS#IE4_h;=ў5Ea7poy0H\S*4ӚK Vu`z_rV~_1P6(t[XN!!Br&,=F+4mb_ 1m+]X,7t"[Mqs&AIB 0+$_h|1$rLE55}"oD/$r:Q)?Po7qQt0!J]> DjV̼V/6ʦ&n3*$1\Y(?bvˁY-?;$O$̏iSs̷!ǷƐ~!+ͿfW?jDsC^D뷯_ͷo]~W]#Ntoa"Ǖ=:"M0tH|ӊ\lk78;` NgSNdt{G"]Mᔬ?3,Z9{O\o;7YM4}@0=ub5~H.P8'@R=dUB#v$S~#+I<Ϡů܃{m9Me&N"fpQa%WPjAXH>{SsMTuuV ~~sIP:U2I2nzvfjMEXRPׅkPEs*l|BB,ŽE=~G{L,؝OR܊FIfɃAs&1D|b۷wEs0qP.9(2lέH>Tg]z[v)}MAsMњ !dRj-o"`&)Ң++_~5()]&{e7̓1_n=wY\ZX%.i\<ڝÕRc /8-daN I@:~x[AM)^tE &kQ+h`4{PWyI=J$Mak?J(iVtkTL! 0$s}ˆl-P0SNq,"l|Z@t7NK)nH%e6U+ QFK i%־uqr{i ]s<(t>wOr,>bb.GƝsw՘[ϝ?~FׅJyڌ;7Xf# $Zybi<HW)/)zѫSh/V8ck6]춉O%KA~DdE_A֐ 쯣v2g%ʝg_縈' VY1wGo2|VeI䟄44SGW+s*+V7,xRvZj Dֶk$NPjH%I43%N!dX[*[ >.JBE3ǹ6E%sZ^Ny?RQ@iJ;˾)@ij xp|sYÿ`/m%/Nf LtYe䕤W`O9_ۻ9}/+WAaOLwZn_\5_3C RUL$J ;I&J/1`-.39ʮd:)P%"4/ӊViw"(ש`<0MWG"URO-pnAYKk^ϓg?xޙ@I.[)0" A"% $ {/Sc]+y|4V*@lL|=38u.`h#gtXW?ɜ o-^da~o+9oy6{)l%W.+W-ʷï~ݼZ.RiZ ||mE`G|Mq฀]_&D+`aIi/ {(?4ͩwf ]s'@V`ι03F"_Fmaj% &" DM2xwk`0ۤ\_ْ[a=:Q6ml ZcB";/%D܌(PXv><1z# 0(ȥD.D1#Wļ#R*D y"|1vCH&[xMvXޣVk|&|+AA{ƥ5TVZUezKtO35ݬ=KCFSbhT+\^Qn+/gy`fn*z.ZkpV1p0N]45it_α #~b*OZK*gV55U BhMlqNC1x/"É)FĹ)p`8 [eYƳI:a!7>՞|o͍vnqJ!O~Ï8߶6gZu1l]rFs@R̹ag, *D 4`ܸIqq<ډ" .$ejD& -^ ע]0}Z{>Gg%qm+Y 5F^$ӲGww ⮛/x 1w;0lAn{RDq́>xK/:WB cƆ2(Ppz/&i лW@p7"y']jMPG\;`ɔ[ھ,H(m~էnu\B}KJ$ޥa?8 @tәP0TioSR`F#! tމ #)-mh:' nF`M]c;_>%$ꞿ0&ۛ LQo؛~uoW}( SQ} 0O.b{/{ٻTvNqX'fL_w/ ]OK3n40C=^,\xƸ  ",1WGWj;a(:Xw2w~ҳ ˤ~*<0Ä$.["aHe$" XSy4Mk$!XS:_PFjf,^IpQo'K\Z+sAD%;AS5'RnD }`c|jkM_ (pC8+pPꕝE)׷ІTFIͰj?ڂ|tvp Cm-X^w-IL\S~;Wj&skʺqoc(MDAfCژh$;U?<ڜ=Ν!rEvmKT^کwCa 1 B`v @`wuӱ/+fo<w_Wu $ yxquYmG`%%XrAl 7W%釾)o7$6iS4΋wH~jaNQ݁A`ŻF=~zi8?IIP{F* HoUi3"pΧ9e^Lshg'd.z6$MטojE:Nǔ#S]׍:J33T8TR6 9trmIʬJB3U9sRtl#DJD`$F1jb @yӱ&wtsyP+rjr=扥lY|lN('PV 퍒b 3oiڪI\d>QQ Yۥ5}6Zp.{޽6~ml|l<0̓{ѽ?dfa(;yϓ/u좂 mwԤʘs5=ED/g~7:wMpM$}zMF]4GQ'ё 7SD#hE gj'S}.MY,sJyof!a/^GÝ{d"S\ml?(Ċ'x4F xw3i`o8''/×/0S-:g-, ^27=|ktわo"\4HV-UϐLnD_LhJ'n#[VGxj"ÃgarFg)NCs@ OVhg6MT~_Xt^b[ 4Af,4 xdCnx^hxuD1Րt .8>ŏ?:`x,E &ymESJ mVOQ|/j61W}݂KĤ*!Nb_QYy5)rBdo]߷^?J>i {ì).$d[< j9=J!Ǧq2xb͘ IpYAt闋>GF+pG*,am)]i:%<@bc{S G5;)y< >"-@%~+‘GCwE W*̒9>aic cNOI+S8geڪȞn>76SnItv{Z^֤>t(i+o~m]knZ/%4To'+Gt*V嶹:noc;0jAFRzY{p3b9 ,g jA|Z`)m~OH5)@TLE~?gQ%+Eĵx@cR fuNIzk4Zf{yW. /W4K-nGc/5N XijEOyK|f16FGP,gٴ(t [% S1'h K8{}>vUFBLZњJE GK1UE-*s:%`@b' hE q>a/źp%ϞΠ@@WHoLg#uGo jL5u\FaC~=I{?SIIM:Jp6]zJk(j&ElFH{Vtܔ0 eX&+R j $AXN5ܦiE=*/io 6)>%p'_&6pn}( ?Й/y p0{1_L5i.:\/8|@SJH< {T3@˽u} lR@=@gbkY#p :>v34^Xmq[bQ&vуGH6/Z!.(Lz :PcqrY:ν7$2n<ZK:<.ڊj_w~}g_?Gǯw|%g G `W׿Hޒ1p$7aX=~q̦t8] `J'l$_vm+ZQ[,UFCjD'0';(~椗(iuXn!;HnI7AƧ^ѕuO2 /"Ct'2^pI#9tăYem"Pbw_E=Qo6^x2vf}ң4\.t[,3ITU[s@y4YoE׳9٪mhc:2 |)LXimP@cF`*ƽ=N$_iH=lNd' m6BYeJ*{!OP^pAhkkzOnW7xnm=ڂ?{6%@| K)R?NzBb#4vLB`#HcnP+6y"龃)6l-jMhH|2ٸda#Xnb#D=4!=]#AHdx`7&̹r;a$G)T V\5E4ÔG&Hw@ی$"@g W_ӓKj/ipcө []O{274o7D,OV,ndF?Γz~$+^2Nr+Փ)>&sOv+R/<Zh+v-PΕ>ͩ1lWxQ,4;HQܖ|I;yR$$U8z£ K}T]0 W$I|6τ/6*?lG/i0E25CLh2Qw:]ڈ" _vY_L\1Y!3ME]Ԇi[934P4A<[jΨ*(\Gb(%7HdٮRЌ) BtBd;'t8$:oDr\ՠ^0M+Oݞ&͍3}}5'i*6qPhVfN Zc 9U wV~\9F_|犸QjܱUH Z ]pȞEN0|[TzT&ml(2vûqtN32T0k1WPwyUj ,&nXClTu29zTPg!@la!m 7rUgWZ_m7TDD2ODlZrz1"x~8ԸӷWO?֏>5ytC7✍pR&D )]Ԏ2tB{D[r29{NP^]G3 \KRHGY+ޓj+fr2QL54}tlD>")äYڷWH4nϧqy3os5i4",| BN J zѡ'7Tm!8OPr`~d'Q_%G\GgY 8ǬadK7&4n(i2݀d@=*dz0(ٚhF8}|&=?lm4Hf{ /1 >ډ{D%#^+2& G ;ME'EFee}yipKTPbrPr-AaUr %w{;A=n.'+ <- {v(hGY(W 9(I_¯w cIDB%jt9}̏_j?__pjϓOG"4km|us{0ڻG5 D%0))% \=":( Cd,ˋ&jL c1VW[lFȌ^-'"qu20\+Ӄ.V/l6PGVpC:Ms k2 V_ \Րc '$3ߎ+!șzaK8Hh7SA#tBdK:ػ٬?OR!o}FZjJ%<;A#p\XsƹuTדMR=ɨ|#`h;I8UAb>Tm^q:>@>uߘch mWO=X֝` M  F:l 7"@ j u;FH`8"2d$z̰UvAj~V*df68=G =޷0wް_B#j^?+=ݗ;Ƨq̋x1Ծ~sy 6Cik<]>z2wdOx瀏qq߻yV+B%4h~e!,y372NctS5rCI-IrNXeaCڴ nGU#X,Af >aB vA$(v<d"9 8n^:| @؄@m1$ ^fS Z?Q/E'4AD)`8GPKy$[qȦ Ъkӭ;*t7:ZkhqL*\'ŕyL87 8}8=ZwЊKޔԣd%Z83>hUHfz%CKz#Y}-z&X1Ral\^AI3dQDbP[dM]LMQSMRn)!{zYdS,CϜc4 WSqB](:Q՞j;M%Q=E]BV 8ˆ.x!|`=[{a,I'$[>|܀@Lh5lmtxN J?~(aBo Vқ@,@7﷍0/@Ϸiv$5 d81 OW{j Te3k~JB$9i)'%-.LvҼYr-Nd$:DݘU]AjgT"8ېOc7ϝ;rBY.'ey\N|2'g}oϟ:TW#3O4)2| w9MLily69C@^U,2u{̯iD@h@:UdC&L&[Nx_+gLHѵϒfP`NGV^ "Z\^s`5Ȩ *ʡ4{18D+A`1F 06#4 ])Y7ì3jd 4>>y%dk#;r!IjFWG}ᴄ^4$͗=^P 7b7.&5rba.K-5;ac$qs#] H/s\=%6lkAQϜ??rz`sݙր[= D@XatP!EG6~3qj^ Y8MeQ®eclœo=njLZD'RCbJ"Jkx+$b2y#n"NY0qbGVDioU:ܔq=+.$_Dvyk?;³[awp^py`鑷RqwQ rv0+4 eK a~ !B_E>sHZmT^e޶u.mg/Q)=MgIF no)+|6%5M">i+8{E4YW㋰ß6lz7S~<up6e7+'\L&d&z{~WhQT̯FS&1!Z!1:}r/U4zyT7-ַY'')p;usꧣDv ?Y!Q^ 6N3Lrq~>zgO;G?o_~ssR/˳ʗg ?ќ#v!{s枼y{D/`53y>Uĭ _{;g,G{,3Y6'O;)&k(e>j7__;d$驟~1]{C8ѳݟާS?|Wby8FDc+9gCgh;:oIW7Ko)l Ⱥw1fcc\-vPm?˶k |{'G$xLxh]W}T'JEYc]msu|C:Rcw,-akIGg WnTC\6EmB#E܊(LhOӓ=Gp!~DW@/ܪ&E^hׅX܄s(G/BgqM΢m;- ah,&;LԑB`bo@ rLiP>\7#K”WW(ţ$ {ݗ%:BfUqHLv-Oe31݈VЃR l}"\0rڽB?&u2V˴*ȉ wWئG/W#07N4lYo""~vbc25XcZ+PCѪ.EGrD˭un9e՚ΪZ1Mɷn&@MMֺ}kPkRBJƁgӓaKm_zCYo4m9+ZhWt'ݞ,52RNloDF8Eios}1Qx,i&|sc3=B3;e6y% %'=ŻY:M((;aȨs2kxܲAiΧIePH^~  {*ޡnclܕ7'ZdyCJf*$շ8ɻy@=TOr&͓vAHģLoo4d'4$`s\o2Ff,QsQ3ʤ^.(9L%7]fHeH;BԗU~f 7~kvhAL,++14clUNz]M_WكV-k 2gU Pj+WxYOv{-M?O3}ʹGnfFi_:uc,FIr~8-u xǻ80A:ju= NGD pdR h^XȄb>Q&\ULDA"W[!Ufʪ/ÈiR0E8(Ԏȡ4 )=Lv 5dSFQ>Hyln-2H0)Md-&t!Jr֌bbF@jQK],Gc@\hTZi93)l㕲ZNq_xn-m R I ct0.KxZ2|zsְ&BxUԩsJ p3Ua㖍ĬIl=CIný#G$!_ks1la|Kĩ (I+'CYV9 &0d"9i֥^5j!Q0!`> H5\aBBZ6Z%/OsBfcHG2gGp+K4C `0 c^Q\n:@dʪ,-k5Zp2Ɖ FCø-3ww FUs T+θM{{H8?Jٛ)\fuޟ fe/)T-3H&<]:<=#6R |_S,` ~kk5N3R$ =jDSY%q-{3<#{~%lzs6ց*hKcտƽ`tIn]0ʸ"SHmÈ1zJ#9cج$ E9'qg!(=EclD[kNA&2t9B.1i&λHmplИ EeK6}15@wf8{}B'B  ׊V$2CMBhC.CpR< YENiΞzz7X !8? UlX"sT hѴ_7"nQea+znzqyⰳםP¯YIh H6Cv- c59=x,=%1 025ҿ&O/g,'x(X>((;n *wf#^f#9c& pT>p_8_'p)Hƻ Tb_&|#Px__F=#"5nlguK&>lN1qJ4iC!ɓkpLk4oZ{ؾi?jcގKonju&޵Qjqݢ`_SWp[zw,؃ȡbRo?t.Yb£p1LdU{4CaoA.=et CH]%-8v !Ȟ nB;: NojHbq># 14,h>{̾\@ &)R}}*a/3pT8vx`Qp{/[sӘٙ5ǀ n-k4*4 O&-(RlHmWhz2ME]/51 (yݤ%nq# =I^E3k/|EM)D)zr:wr;8ʎg W&F$7R~@5PL.9}T{=}{\қ.G혾Pc^}k~hk#za|i+d#gֲV+@fK.?@-̛cnOpND#J ԇf g4jxYJiE;ek{Qܺ>kv}֜YW芲VgU}0>/1St󉼠czN9^(Yf%PdŤ~4j<k4kfޡo, .S&9]Z.T9U:*&'69Q~h|5xb#fe$FĴ*M_7ɆfFn*]ފN ^jΑ(a/l.2MvHBQU%Y80YlJ1+qv;8 8ޞE= !]M/LCshk i;n:/Ahya("<p<yz {h:2\mKV3ʼaa& B+;:ΠNp;^&"wEī#TaN5u#-8DQﯸ¤VZCMfs8?)OBNqj2 X0U1lFe= [*v H6 0Kzs]eD%z$^@l|sfL{*SŊy@&m▖(=uk q2|$ZI5`u} ʋE&{0޺bn'bOTSs \DR,̌}_h. C#\8''$.VX E?ebڛ ҇Dm1TVLW'пwӽ}Rރ0 7/${и=p l~arßA?M~ r7$ň)oDoE>࿛m`9k98D7TY3D@tS֖>dXFd*]W>kե%X")$75My+ܝ #МĂw7A Xe'Õ!-F4|F1IGS A7W\yKL*ٻ׼<"lVOgiP/$l'! rdԭ.osD葎p&ģk-8.V=W'_H)YmEԬ^-ù4Fr!V ”p{MF.zqV8Xx})x'hOǠ0dpс2(˔- t3eDT}*k7BObjFB̊:5x^lkLM<XM i^(:&L/P;E/9Z%W55©Fs^'T zթuExirQyC~!oآeum`sIƗ7K79v ,8:((u9H "pA 79אr*]*ap]˟b=y7"}ǧi1)Gb ԩ0ŀ2QTSVEi:䷄2ΑM8Q'D>Z;IZ@tM8)ڜ B|*0{ըБت̫!MXUß6wHe`bʡŏ6Wۖcl`ҴA"|M.Է&pl)Kyp)jɛUЊɶzv_2=Q5ܦee\Nۨ?k=G r^ZEast,UC$0725Qg+I ٲ+ʞϥ *#v)`{ׇd$=3CyICm 9g(e•@k1Qd@O/_]\>G, hblӰ@1ĈͶz;GR1:@6~6F^E%M-՚ʒrb H\V& %Z"n\ѽ56J3tzz9A;PK)Oqfz$HZS4?Ns37W#qYkA G7>|^ƪ0VP(ب7S΢LPBٌ>#TXod3#Lu;c7p&٢Zxa)27dnm^b mP VUQ3zWGuܬziϥZnsw)?Bم4:X+?hWpDH#dP$#4i{D/=yvv俁>{(m ˛h;R3˱3PJ~~<%OreBbT_6ԢWCj9aSAx`!m=% "&߮cd`\5@+i_6 %d1.@c͖$FM*`:61PR?)IiIy 9`l_DDlMn/ѓ2+*s9g!cjY\"vYd!l,yB93shE »gs(N'}2`X*O7)7Juy9Qii3Lrgc6!I)1SZHLjpX /a>l3JDNh2+LSw˒J]Jh&ǘ^:DJ$CYV9!Up+؏HJg5hhs#IBve8e2JGќdN6xW,cq5jՆbUi8#L9z@ҵT>LC2bSJll]zs^W](/L sc椣}p㱸-G5y,޿J NVgvV^ͤZJFJɪ//)yx $0"w* 3jxnD/we "߮m k%>k|E^JŪ>k\#uwsɛf+4v%]K$q/ q 55E^&:d$呠$4+6x}dn \MʁŬ$ kx$%Nw.˛|n{<8sҰ^S8IUI 'ۓU Q%wa{asGkpُl3 F+DEqxxiO( j9 uU`_|}r?fHC^_<ό?SWۥ~rx̟WWN7gO޾B~=~]3df2@,_T5fj;yF !-BX如~,lH!(a;YIqS'w2qk|`)9-[pZ|(""RhU* ^ܐ%1Թ%LX.XgtFQ$ŶIFX{bk1Tڇjiemm J*@ 4X׍BQaVQNe᷸c+J]x`F- W*2V܉eG!5q#3O)D)E-H8{W/SaCWsn%^,e]!9)Cuă*I,&M:OA^뱰UfdQW4aĜ8Džj\Kk,vdz谍fF,I\ UFlWx7t9;7<$4p0+#FcEGfzūfƽIy-hkd/ŗ/zkZ `EzwB$Z4TZ$=.S>`Rn>Q@25əLy'~I" S6_v*&I%XŰe*!\rYgٷ2H4r*:`lRPD ƌ Vڕha Y9d&t٪(֖S#/iT3ؙ c 9b[ѩKc ! h3z;`Mt" 9%PWc"p-aOѤ)Ix 2QX1-q0HYhC }ZŒ HbėX[0u#᳨f4/-sCVps6U[zA~pg>ܞ&xoiQE|7.|UGf>"hKDŴ'\MCypmi+e~Lq`%~s[m8\shx,B!zcO^KY.:E)p.%rr ]*"iOѨ:dzޞNť 5ZdPpDb:D' `]wP瀫ȶ4%Eu ΰwX7)}ƒYY핵e^NY"SeJ[?7ͿMc!;u68~8O#6 3'ƒXj&Y Su+1CU NڏnQz2젣v25U{6+wF]͏חBe=4d:8c$ (ۈc{4-|*7:ƸMcrn1/ёE}?@oL>@H:_lRwO"s7G>뎸iz,ji>Waq0W]ɳP ?DPNt ;mFE4Zы9ؗ4KgI(Ph/%[SRg/awhe+jZZ%PnUoJMG&ѓ⪓Tyhh^0 ^:~IE%̑Slź /eeEW @6kHX\>T0mE-?R\b4fbtNKK/N%~%YPyDc{*{X#Jo<;OYVE^}E6,͞'Uw~I(@/İE2 5 @ iTCZ9|zz RSCYLB(S'YEb?꯷[bb bPIOf"a ;y'p*걎n?=W(&V FLO1fĦ?"ucx6; 7':)zL)Sgp29V=!3F_Y!IO7 ` h<5 dɕ=uFAre +[LRfd=2qpFLi<4qdѮFO ZW'>q:ߑ@ӟk$_ӖY??:98pnVfyg6҉FA5%5̂XQpIE,ly:v>pi*C(g*!B̄gL]49J& e t~Qfs:$ȝ!h|jseL1ED[zr Ui:zqk۠!hFE4>unK Nh즢K⻊nۭ3iɗhI:ˆi{Ttp ,yH'h,DɽkXjK O5"J&4S$FPF/: I(tŞ,G)G6>ᚮ連N;Pk=Lϱ ;Mt1LM nVˀ,Wf7+Wߞ 2k0EI̧TE~AH|s8*:{S WN⁤>/K0;^JJMmouseAqڵ>~bmll8(eT0F,l<{?] 7$2 Mpk^&1 ?d`J'QHgq7nIL8;2gЪ㾖i:SF JбJꏈhũ2wWҝ&*Pᢤ9 3a ~ǴQsXF+,V5s պcroQG8%@du}a%㏅roAa;,Tk +̵1(?꥗Y1PKCaڅ9k˛Rbz|! nL|!nS.ĶFXeHv]#dkv sh&q)! Azuɥ.[ZW"3a}N5ODJ{dM&$y2䗢qbUDG/<n|z\Q4[993FS=:}8em3/r q"#8۪by; ,G-#YX4o|ĕHY IB8xQIzϓ3 h&=ww 6\Rڮռ 5#w_oc ] *7^հ)SL{XNqOTڀk1ӜJ"}I-¨i,CC 7 F:7|klwnIf4 }1° v)G BYM9XCMB~'gЛMgRUg&t(yDRåoho[ ojHGG:OS%-t@[C$tpAm+qkim2w,jXId={k0N %:b4mϦFzFH:O[NEɴ>赲v>os'Au{I9J8Hc1:KDh\ @N~>l?֛|{ͽwoC)56"}l6dր,WE7KѽUu8O魨HrIx7GD@ e*SI,sϰ10c1B.hMD?fj>2=Jbl\P#b^٣Ƚ$ LFwL1]TόX@ېLڸd⚑9šs["2n6 R&k ˪xmb=J!5bNAӌ4`)ܟswq%p%豁T 5B7#&@J9L*ػ[F=Y|WYqJ#-2򀢨pU}V%do5Wril >hԾtoCb0A kʺE0.M~~( $vb)̎npJ@EB`}4r}gC\,bq?s .*q[ϰ(9u۪PhXuF?td;Bc` =syZoKaۚi";MDy_Cɷ]IV1؄ U |/ ;׼X\\>o/rΊTk_Ҍǃ>(euEj#0||'f5R߮}es4O]wGHΦ[ CkcO׻|v"%(ڋPJL13 OrEHyb\g U&ZP&ERxVorY/)kj!bbGщAph6K1xrJQ\c/k]Ĵ;,03/}lR sqarclb8?w;vE=MA2x#djP~:_njP4ڵL 4P?p2ʆ}K7+VuRP49K-VOEEFtrd*ٽ9wW) @buSPIQ!oPշ Wα`#SO$$nZخmtDɎC:54\w -T&ߪjrL/͍1mCӱI|gp1ywXpԵ~Qy{?wTJy $r]Wܜ~zHyhPSf4Va%^4^mdz H0KVb.׽C4~{?x+.Z9/Y<]#B#M[YfĆNB[]ɕ~+iƍWsI[4'jHDKiXj9,#pX CCex$vfL1/Wd7F'Y7#p'K̦׾{MZ5a4.Nʥ;22'f'ՠFЖX,J\*P6(Uepgh$, \6]`Qh0K< jIـW`! )q҃mJZ D C.p-=ױ~]LEyY  [}KBcyҚ%ט3 YOJlj.Da _o%wUmݿm味&ĉs2̛żi#TOXXa4Izhnϙ:0úqU h\]kO$e]# ӽ^G] ewe l91^ȹCʪ45hbPܱ#rpwQ}D\M52,sxSW`Io}OLE5WdO&*YXC} _muZ{7U)9Cp$3ϲ g]5dpde|tKc7$lqʪἶ|~N-[6dQII)eY {ΡCئ>8$4G6n!7_(xLڨfx<)}LAsռÛ7w._vVxEMf5zOaP'? P =^5׎@P#IKY!"`%"%ϪЛ%r8>..%is3$Ȓ-3Ҥ&i!`YZ#4cXTp|;f㝗$sTXb;aUA>M GfW([ Qn>Y_st Wdc#w-3J31ֱŧ*X鵗/+Pˠ]v(^觌<)k: 1 =p o3Yv`Wyk 0<H2kBhoқ)rG{?ңlcWh{TzZ^i! Js2+> [DO$d"/_AY@zqCu/0451qL|H5KO ^yfz6GWE3;Z/M $X(W0P!c;o5wBIV?,ݯӆcQ:Xkz;x6ոm^"o7Է&wWတ|%^&l~~#Ji|mV![ lW܁R xlepz5lm?hn -q 0wo=5EFCuK/=_mZL]ة_D7/4tt( @ @Q#)[a%T9Yg{s1sTッqɛ&`lzDdjH7I?93?VGK66tx*҅P*HNULBS$%RAL b"›ޢ"ƴZpw:k~tT,98~OnJ]2Rv0F * [C\X'(??%(cX{}||T1Nœz1_$I=^ª1Óý=x_v_z"ܓ%+&`n!TeDB}pa~Rt&e]jMn|BtsDM2J_ɶ! `ldha&? nvk6@b p]Ji+GcV%ɞ)S̩jd*wj:_8:CRzB$*hzH G,0.0XёorN`:_aT f ۵fksA#F{ANܳsލP/ެROjZdi%ao8G#bs{'YnQ&70"K?#gkBxoU.;=W~=֐M$r:J9Q#ZQNe(<iX;fYF5 &$WJ,ѡq0d:ԓxZTBm&D 0!:IknA{\5/ jh)QmÕ3w-5\B[k rD)C^~uCmH Ε (` JSNU'MlO3Pd~@ËDN ®h7}ZqL:MXwWޛg: ? PIsFUYazFc޽h?Z@Q5Zk <o)ƔzܭQX;v88Rz6c|xb y}EMqc%HoᗑUNpܮkەA3y!t YvԳY^^1lҥQ4(2`|5Nc`ӄ8!V=hEڐJO(?v386xkGGShmS{25=UK:=ɶs n5Ѻ B[8ZB@[굔PəR\ $c(,᠔"`6w|KrT)~ΊH~ph d@JB잹+-/T ӎz0t#zG[{qXO[\ oE'SKq:eneURIȉ^*y^ˊⲪ ]Y"b\NGNS/o +˟jM["B\-mNRP(hDAXr,p\&2~1UGzG/E~D̡Aq.PȉCFy^+Ջi6OR0#5zLS E qGƐ(Sq#0 }*>&(0rn&7__ETK2:N$)MFl'^[g}sGvZSG&emĠ*lP/G]D[W$|bB*zxПAFvc٧t4e!+Ga2mX#"x2_<{ַ%0K@/~",'+ do5J#pr9yj|}g0#<Ǔǯvvw7L)}$V/^G0GEZ~ cy= OB#_LaܰIinJ;]1آG&[|̀FoX'wڗ_Hr_k҈+S Β((*]&%Z(LQrHVEdh.e +1hEŵTMC/>,@?ljB3%@w%P&ĝ{@ʎ5Z<Ǧ]a^=N{][Bu&VX` 9 Mўn](GX[[e$q9Y@d ޿59tb*eQZo B0%6Y'V3}'q+)+]!rahpq秽ϟuAȠKF\n5&:ɼI->YH1[pJDǗ=Ҿ Wl{P]a¢\m+gMUP-=ŶY;V3.D=/Χ2n/c6 9HLu{BMR"Dv&Zы4Ww[u㒋6z V{m>y5dCO uagw'ڵS38 /g+F(MCAT+^SBᅬG4JI Q '8{w"rXx\i$ l&a~&+6TtAtx*U @ٹuSe7q/MH΂睼[\q5K;a$u<% ub3Gib btIHN +%nߡ,3H)tW/Ђ"yn'$&V:L&lT^旅td&h~YZ dUpȶ_a>p?%/ۻa.ne¹f7 JiMy%z.``0i/Cޛ "I/~W[{Hsܕ]'J,Y#b}GS?`O*|LPQ[56a%Je !ׂ4|kM'#7Ew+;w5R-mP{&+ߺ^{7KiaN:̤nw cgju Yk{-=T?>+nvRBhlXS-q!C0O1j KNԫQM'. h\=gEp_Z@pyI3\쳾ˬa`\1Y38d.VAHRSnL&CB21J4P2#zt=Fw?DHIqRGMd1BU @|%\hLOoA*4Vx:%d;-;I@Cq@85o)| !`hҞ|n868aB3o/1]r 8uO(ɐP6O%ߍhЁQ7! WqHEUp["$^4ѥ"3' (veU2 L;kG|]n[oe7>͹}μхWr4TQQ|2]$.8&ԭ##!*lMXW+xcd:^_ŠU;yWФ4nEeC=!uq3ۈiGruKZIY^!:!@ףcB'4hk\w9Ped80bz!i<V^ߜ5~6|  )PԍZY4!"dͪ[Qj\yFИt9?\hcZ<& 2(gVPBhP`1t Vc/PG.ϧB#WCJT\,jG] pdX9ցa QnPlnN ӛ"O@+SNjI+QTmeA"g6&,#!5rJl]̹skӣT!N}/2엡㓢N W:S+lDhH,k) х!W:xRqXsL3ҙ92.D2zEQSpҡ^GD`›9ml !pӷ}9˃+sf.v= 8$`c4bV"/A<)F: t[֣:Ug #s1G$z$Ƅ(p(Ecp[mlnBt>'oImDGjAKֻNIg&Ф'Y"Ӂ,(iֺvs#1@ojް 2;/_vfƯq3vMbYxy' ayt؞xrO>F( i²頷hxa `n6A+5k/C {WP0 (ޒi#Wy~v~!l؜6nKUXi}8iS( -8P}w5n㰐3\ Pvp X*(@8| > /A]+źd4HaDHfմC<4D=P$h(g82F&iUUedF*`4e' u#*Br^!"qu<|9)j*s=9G"+ F1嶅D|R:3Б-}mczx\=={\&/ 9{ ؾ'JwyʻD<*o_]:|b`{񄢸ִLљQ#,:;b?1;ގ<Ewpy»O K(Y cZck58AFX #$)6ONiud_IEW1)2QOM~OͲ*kv&jesX}i?лώvIACԍO}JF0OgRY&ɩ-!h:%"ߞA9X;睿uIݣ}hæC+` \}TAAXda.ЯrPS>i7'gp}Or?bP8`ϺAc:ç 4uxTޘ=ǽ\;H+{|uc!Ef潲Ĵk: 암7_hs[WqfKJŲRL*n+h{sxp,CӦ#"'g3ҹҨ)r5/]{%D&4ы/Cо6Um6azw ,yu< SBusھGEh֒)`6p,`2\(€rmS)XtEU(߄. `~dE2-QAUtjC|0cCJ4,ʷS^) 1c76J贶]9J.ss7ܩ2f7t+mm;Sn* d$mX̡5h>2%p*_asPRZm<Am & amUd}n*΍ o^4{oW,d%ભFRo+2jݩ ol )Û5k!( zeGu(FU9Gf㓕>Σ}O{ ߾i>Iw8mD>r$qνW@Cnvo'm1ZZZZ&vSnlW0W/4cz;Q"l4f s["T`}s mr!Iv'{cJ|Ӂ1XF`FE\@(cx4/ς33䗁:&8 hPV1ײ&,? Ϣs ^;.>-c+EP0vAV"?< 5 {1g[uTSe|z4\uIjyL%-]3u;fPzg /HH=Z!B^@BikZP+XJv혨S,6Yg .knYN&$!]H+M$"ʪӨGtъN􈰑 ¶ՂU4ä3l:7Ƿ-!ܶȧn"oFۿ9Pc/<澡K{,3!7KTB+uR`}#4[6;4s &2VuFc de =]LC*F7-65uaXڜvD1U1t3 @)њώeBNP\^$B@s^eޣ;#v8F+i[Fbv7m| ^J> *)-ƫ~ɏ/R::dy-ϣl(W_21%K@S>Jк_f2dL2N6WA2goGl{pWh3N38lŸ]ůG@K Z XTAygX)*:9}ȶ}J d5BÄbģTѣH#/ώ5cM1ɘ]gSaD:kd^8vp0r0#yG̾(qP^)E0}czEHeH꾁{aB 8 8#ʤ1&IQ-)׊`=Nd8j4I;Ya&տl+hNuO ĎMj-~32e{#RﱏӞ*Dϓ1:/{(67,?( .a-d]7Ζ'|P-2tTJ0 &>Da/H%/;Ǎg<3 Q)57D$(]nB8Ypr=r@IO)p vK lCwc,n'J/€~TJ)=RƈQ@Y2E< UfdRcî<;TGp Td@f"$>ѷ3c%Z`(.^v?dF"TfXV ɽ I\~1Lv64Ur(^[B:R_mG5 /<(KdU݆ )NJ_.|dֆzm-Ұ(\G|@{^*@&(n#ZeQFOt50X6m&7F}V>h j;zLeG3Hn_ sѼ A1 gA]Zڕs15keL#.h=X}{UAsXZp^yX*ǻ6XNa>“+(R8(_x:+S*G*i2ʅh~UOFLP 03#" ?:f_*kzml7l~õZZ0 V~BX,~HS86$Z~3fKΤ 69/1_D1$6UxIP0 j㪵`CKfIp "gT,d,+ >gZc^0E'ttBEti6]b=S1Fz?t 87: 8"Ox>x+r}Szazj>:x۠3&f~sh9."Խ=C9RG/$hpH|VZPFa²7thS>=>|?e`|Ypdp/ 0G޽>dik1 c6.iFWODw9_Eŋ۔~QnW(`ǫJEMCvs̚0B[G 9klmW#.a'4a!ÑVXvG-9Xk^]"" QZ/}Vc/:ђl< 8hl ;$8¥Uo<479 lb,az&s };voefôSDKw %e[aYF&_(1YV+K<"wQ*IJO PGO8eHq"e0٨qlrlTY2$O2[sߚ24V13%((+Mm*)hjU_vH hܕ5g}wpnpC*& ^ K^<4vGd`T,ݡKy(bpm.a$S D ^,A|雖`/=v+:ڤWNwh &}?0tv.$H121\(&kj2J9Zըy>E'i1;1 Rkt~cAͷxoXVP HzxةH\'FhK۟I=Nhh]FY#ɗ^l%|DA2ހ!ū㗯\ VXio!&n,Fc!R,G;s1<R%S<34s5_hAqp [ ]+irj6l&a0Q&Kc0X̘3Rǩ ;_ `wp(/JݑK 欺PۚaM1_3y3Ys1")!p/8B]\i iÙ8 |sQN'Xi%sÄuc+ml$|å"? Kze*؛c q5@È[i5R?Kl+_% !I ʄ탃X߭҉:<#ŀ[`'O薻 pI9=B7 1he2 :gVkZz"MZYI՚~;?0!*7 t#8IJx -$%IiszhD+[gAlTgŒ 1Ɛ%8<%gl 4"SS b=%ʈG(NJ p)3XKJ5HL/Rm9YPjַSb@i\J e]A1ubvX.?/r3Z^Ε(wLBh̘|p[];6-&G^ћ9b `?eS*g/L^Oo%tN۱_"Fx.Gܪ阶~e0.]后r%uГ/ͽKKh~'z5(DB=ly 7k'? %@tg lL4u[@tKjқͼ-j@@aMDA acL#Z `3Օ1;#b@BsQbr% !N)kԛ\7'k&ט񲌹 3G-YT/2iISZyu%#Ͷv{RԆ/uCno|-~0dMG:$7RqF$T0<;~9 yՌ'~-͋t⁈}`WռxW-azVP \usV<M'3]UnSUkvVE!av:_>msqˆ/Y]m#!l>|TŮS.!*OE8W5SM@ԏLŗ,pEV vU&m,.& ffV恶c!Nٝͦ Ttц-ף!fGt;JK @ KDxCDuSt0@_MB©1oJw'2:唔B~q`aWSd$ #TISx|% ^2)g~t@kZ;(%s"$[5P-;H +Kz9OysԕRErM5j2]kd!4!*;ϟn5xo<fRXѢ-g3NIsXlǁN ֚Q@S]bQR( rVEY) Ϧxz놽@1,lb~ Kz@eXP%_Vz$# q@8/ 7H{"r(c)f՝!1oca7hۓ@-rF.V56spyobGgK’C^Ksm$Tw.Ve7s{J's /e5O#Z/ѪDx]QN̵uYmmO ET`u زtj` ^0x mi-Xl`H`j 2:$A964I Ϭ]&  +Fw'2C0:\u "sxnә~&x!VY:ɬk kHLj27>$MQt8o!s1x#)ۙ }|n/ j&oG/SFܷIys[9W~@ [&MnA7r Ne2r,g䟱* If)E}+"99هpb(̸>n?)]Q驞7G dhC;y_G)vr|-І߸uUqpU,ݣqZPRw)YAOʪAF"Mi (%M[ ՑeEEGIC-t5T!|03ɱї#|pơOlrvFA@91AUe,oi:n+J1UV-#$I D.y PX41s#n`A, %:grAsBqF?ej@TlCr&D>3glS'k".辰/FIYf縒LGKHiwިChQ<>,!|PjF]foT FIBy틨gz8܊Er/Zۛ9mkG(C8,+Wu fNCfgQka|`Vd[:w->h@q^Q2X4O:st߀>jϚ(8y-\!ʍ+Q6oQ@?Wƾ*%"26Vygu8_/WYn=mtMޞ]rNSb#!WJLmahc.b3Uh19ܫ+;?<.$#0R I7h6]m]}k7Q\Ҵ7fYy8Ӹi>Y-?xj-帵b--XB㫐۽'AJ"4Xk}S1S%iJmmnA*5Bv![P8o/ϵ[e-H[dO3;η 0Գ+7jfȿU3ֻn,GZj8ܱL` FH}~j;j3粎3J?e6XN9'9K}wT/j/bQ;ϳ*1ط`h%d`_1yp:MimlyZw̷۱s~To3/X2˻o7-a՚{[;@uɐi,@#' ?lPU217jډJSx%v7uںCL9Y98.)0Բi(KpHRLT@DFV7A%kahAsWlN$=&._Rg Mb<3PG6xl4{ֿr iq2hhflvU69Oܖ,taDyAYHx` D&Jgm*k= \;/xOG_z4uX,p%#2̗U*1c0a>f05 w,Yz !/1 Tfq_Lc^\F5\D׃J(:ljZS^R19|Cg0dBD%" \oI=</L6 7-of#e;N-ZY#o9JZ<M;\o!BmU UWlA hQmTAz9..ٰdA+-15gsK!6uI{&Aޒ޸n"\C$d6¨#$M#aM9Y z$ 2bd@jm}hػXDžF&H8REpj.8hoۈg(U!N BRE4el\ԒBOmMWn3͆Q>TLڃm.!+Ҧ۰ oilA|ނ>ncx PT&"'UgVI^B=?A!:C=#Koxju:] E gOKIFpx]\$^u4{\'6WIDkQ{^E1o:[DY Zo^~}4 \aƽ0M=={ M &<:]k tnRt8RQ!DOеF][14=ɼ’"1fٳlq|&%aΏgt)(̒AhnAɈʊ[Q>iVb'59MQ4ِX\*\ИcyzD% gb/ĵȢ!F}\J|heɯt q E*VC6^:c #'T~Q(kNذ!/4"R+eAB.sSe wk[b+~Zn,=( K?FBR|{K( F+ Dϗ9zZѸqQFeq9$* \L֛LEpf ]e|2!-|FgQ&~*ָݏ.IQYJVb/<\a*ImGMM6J4m,q8VֲyFB2xo Xnâ #BL蝶;08dH1䢥 v<*c,$WUXQ/Ad=xiFU(G\w^ykT{ tz{9$IjZ>0WQ~]LwZlk!*Z`x,~9_:_%',uѲJeJ?:hq'۰p[LmE@2kx 9s d\W-:+ܘ%=AqfťΖ1wgCFq<ЗAd;];$V7*qsu|<ﻴQL-ssa8 c<5)Zvg!1-ߎiFNq' Vx13ut)5U[rC*߉5cmu3k@,qէq -`ppw<\B-CxxtI1ny!QN߉Vb(e{b0?X fP5o*O/+IP6t:LTM&j`$4"O/6\/ ,T0U*eܑwx9+ E)${KBQb>~|y@߃4S<FpԜ켖pAKZ#NIs=/а~?6VSoc&.~KxcQy1@eFf\FLFkFK}aYTZ3w[ e!8sT\ɰ?>0|苹-FAcSeY.I @eu}psF,vO|a5GـXu1$72!#G؟mNt0A?zP<^#\K4϶q zϑͿ |hW{ kgD_4 sd<#a &e#A =C:\.1 ᧾oCKZaN?Ɗ/# 0hL(fOTI :L-hZڊǔ!t)rmfR)ﲘ PfD~JkX99U)=i1\tW7Uum̕xvXebCM&mL']T{YBYjڬQjO䉷ٵ Y!Suw%QRjIMpj8ïSi>u &r)#NR6ע0a 0b8n˟Zi`sqmB0$ʗ`]srQz#̼2&`b6 l)FR@+/z )P04]z`FUzr՟F 0"»}z\LќiIT@RZeY=ۓE3LL5dڱŻu!zG/x(c gՈ\KlhNmm.ʊ{C?"˯mْgIvAmFܥɊa#hܸ( ~7-0}sK8j 3.[Zom> { Py`=8f^ä׷vdcA )o0֛{d5cnonD®JeZ!=fVO9UD]&(>iXDBjx2cpH&3`}MOurjE[tmEo~݂85r _Xb&x;v,EGua$h&ʿ`̢-hѢRqM7;Wu_~D}h sܦؖnm9oU*.*y/yRW@FpI11}/r"23%c$,! 7F\P?4UØ4N,#!t4p5_ 22 $[nj_7vb1$ ;0H PѲȢ $ 3Lps{z|Qs@8V>=G/Ć Í|d}o|&uԫO''Hnr]by(N/BYuY,G?##,se#gEDqqHVdB19CuY ߤGn9) җwjiE`0hA\%LkcԴ͚ɳm1a>>`:pz0E\#t5ʗ3C;+A"~xIoǛy\7oc:[)}|l6#zPP0ڏ[n@ O添p"_r@9+TsG_A1sOA?a'}{CӺAmdQڏ bL$(*Z.שZe}p&ܩupM&G߽[ju5w9/EM4E*f#IQEvI w(){u:ʻX~&kEp iRPIxQ\) -@:k{[G8+=~L" 1Ȏ~ vN*4 IYߺm.{K3}KRJe3)oV] TP65g@ZI 8csY x0Zz'nK{! +&qDݢP9's9lQ F8)aQ6ƭ'X*vLۃLxj/hJA̅ ѵ'i;h#=^'V<Ε0Kp~#6g{ԮYxEz.4 vkfIc1XH W"A8U{뤋H&pLmeՏ=46YXnhk ^rQ2/3:j^@)bX5Ti˹.A]f. m586q[!KQB`єl]R_D:|+hЛS@1%wujaࡿ(,{w(x= |R`݅\;Ġuwy-`NGqh] Fξ a8\P>Fw evMRMљV` >%a0*Wi,!v YfiZٌl95I۟! Kd|=TsZT;9u:B#]D Axd9 (PJ8XzoY:l]weG.94arO|p)",HɊ}#Qa&2*E]PLT+ i8#*'2/NtyL?E#dq~\LVZRû .{Ш1 ʵcKzyNTK%'R$Ao7Ogj68.,&jogܦ̯4ަ~&NO'*;.\{E+rœ: )R#:Ԥf*㍂{]4O?t}jdC雳\)JŽP I^1e)2v; ֛ޯt9RXBZ=dSr`*eg{QM:uŸ>+s ''R dy} N xԃn"Za'߁Js?'VI]= Qj(*y ߖO\φ!/ :u}$W+ab"JxsNlF\XPGuQ Di-s|Z<&HG-סCQ' #Rrj5Bw;ZQc~*:첎4( Pٛ鬛N:bIFPV"_3F8^h& 7t L[ˍFe/no~|]N,TeP8xQ02c{5JN=Q?; XB)aƝj?= 8#w4eK;$6TܷQ ׊zat(NW hx9<(N2A0n18_ E= bT!ҿ0N ρǍ0RdM2<nj 0_uN_ϙ?:Wu5'3=.iK,twN>CpO,FEFb:]hm1h>Np,>B~ӜɃNt$>$c0 xZc0@zLu$)"J\N߬eSh'aڜwD=P;49̻v0 u.p c 3 |k۶/Ǩ4kS פy:]wcR&1_SXim#0 k͎Z'O,~:Q.Zr?97DO9Ӱ)JMνҟTmTR 0b'zӘb>COmB&c%16gZiΘ^Kd{´F뜪D\.-nxٲ3&1ԺI nu\׊چA嚯Sge*Jf+2.b$0i+ +oy3KO]=t ^!ԡI+>E=5ycvW-S&-Un_ؙAl@ޕ67ۑ0Bf8>u F9e'hx__\1Voq5weVaFYI X jpO YĪI7(OnوU3akR>hl;˹Q4ODmyMW/zlث&ok]?E,Q*yz3}7sԜ@ڎ 8&cAAG=P EN^uUant dl:7~uOZJA1!f;: ҵ0@$Zd}뛡:q ѧL߬;M\[zUA!rCȷGGàIۗM4&k԰c碬̓ս][e6O}-uA>U]mz7z"6hJ\v|v޵$(##85&:ӻj5s@C7`<9 n! dďʊ"1q{Z!'0p tLw#ٚ$rN٩gsjQ]mDvܯ2>kIGagkd M_ &X&M_=qLjf'| o8+Vuт_6u\=\zcx :m9=:GsRNhL=n_%`x ~Zw ƃ_v(Զi#WJRu,%G GqΒm 8IʣӶB3yV 5@XiCة% E!m; AX^<jw OVDZK5LPkmtJVT[㿶Aί(31B{p8y>t`i: Į/\羶bՕh쬤H/lqlëm06-%N"F4IcSʊpzMZ>jtK l?F@Fhs[Oz&P2!]/N^r'EC %aQ\d !eTla}Zt 5@w"r,:&L *"QzC@;.iUHIT7v_fKBg :zD0ijٕNɋh{$u"b"H~hIh4_g&2y-}lzHM %zڻT 㳇;)+FX\B& 4/>$;:>zZa%e(ٛlp68ТSh$6R 5@1نsQ{tꆉxLӵ[5>\-CWɞG).Qj!uQqkeu"*N w渙C$t1D~̡`NґV]6>Z4ήeCuT ^.܊q`AZWڢ^wM Cp6)DY%'l@dchv;صjtcw#5IM8SF@=xdF:]n\:Q'`VC0saɑd4KdeiD9y8K%Tɨ7G'#פ5v偪5w4`!&M q}/7y""8/5#A`CM|nq~D.M?8 rL#uϦwCgCO9j%lh>hfgg~#f~8CYcq'76(A'.](6H$"8rRKNǡ'Mı $ٿ S @&F )9N30]N_CrGPEI;YiLnXzS(2}I:,zQ $(S7lc[75758 gC&Ö+$ů)-Ï; \OIKL_@O[ՉhY䍜I7?fS #ubz{~ZV}4tH[Wv>g3& `p#6Kn~ZPU}+rҽ778 ʅ#zTv©b8hcW)bIӾnwuj8MnjNsڄ.NeKn?&C <P/LФ+N$ͨB"Wh?"tak^: ~}T*Jqp@Rmgi C*`*o J^/ݯߡJef jEDeGaYs^CYy% P;DMPTd06O[89}U)fF8~@rQ:1@ ƯÑiŤy#r_ם(،D^s,N8/rvʸ슼WDaNe:ByoS kx?I!oS  HR>Ȍ.պNJFl̈́sۚPu&Hď v{b%;q=f> 7n FNJpV{@ h17qůRjU:y#L%5?c)fwg#mLj$HOQ6N&8/X,,8|p By/u/>eelz>Htx |ƣh4hıYzf|(=:X|m6g I:ok:C E-Z8$FFF?]Cod]$$ӈh-SSF]FPv] pzڜ's ř\75;{/ufͱǪ4+(^ta<Òv$yUa`͹mxc_5PW s@=^u+/?Ш9FnM;mdŵ 8&184?MBopW4Ⱦs_l I 1Xcm{Qdnt,BU*jvk ;%)+{x1@85?Fmբr"W%@0S%8t|L r#>R :Kd+㏡$mFRT0@L$VWsS5DLp!^%O ,cT'P}LVD>5D輴d}UgtYS)[NIts F}1s[SzXXsK`BT/S8:Rc`|3^ڭ5ֲөtQ[Zo2*+H?朥Ve H<3MPeFGp2?J}8< %2G1 fowyOH 41N "m&Ǐuv"u\6)e,rωB]R%jaJXy7^vsxsftI6 *fN4y޲Z*h a a!&}e U  ~0?9oqh)&mRpjghK\l}]_ύB(gA} r™H4V*FW 6-sq; nLw*n:t b0R3"]r𽺓9CO?-c]/jtɗc1cj1=hyjYz3M^k-1fk/"ɵڝӓqvܭG`(dU[%{嶘۔n >5}5qe6G7Bvc,gH%W5Yr~wBRnivЂ(S(l($r+aטeR"l%$HI^4BK=pɝv;df Iv_pBNbKK1Ù9EsN: 6e1 !ųӆd0^= x|QceCRy-{)K'ht +eUƨ"6TB?IӒUys9@资H4B軁ax<)n+~ [C<+1?#G/By Y,>Q4bv%)J zRLH :*rm4\CwJySnIuS\=|cH-[*kܹjVSB׈U"IoptddH6ݏ,"y)tQI!&$דF}݇,Pbš4V:IMBɦ@c{ڢZX#OJ>' dkccVrM%r T>M0Ka;|f)L%S,|>k; Q;}=1h?{g1bb$c5$a0#p,5%Ų\Gm_&k \n۵AtG-4nHꇰ\a(eEӓ#A,v'iChTrG[Q6 +)Ke. 0gpܹW+2و]XE"wb)2 yz.Lxdwc mݍ9u&pCYލ 2ȟ ɰQsn9jߴS8{o󗾇f m4yKz;d^Qy]o6 ufu 1*rr޳nz@1QūLo@.'ΔL[83XLFG=k5nW5TU*t"h6`JW7*M3rIQ9(ǐ'ಃ"ptt";ecE[^9+d6vg8[gb6 -G/S%<=1J\<ᩖN5Aff#c8BA2Rui÷yIFّQd{͟N;ES#r[HEU,tF%_|P~պvmq계z> BJWV]ԡ(5A&$Yf.:G" Wư60o=AD5i vNh]'cdj*VdwLb]&Y'Ŧ&ZwuCudWǴЉ@ 4%4@USg̑l#'oo`P-𦦶{qw=)W/t̘HR-ES7][R N:/*qʪ;19C<aM䪻v{r8 .tQ( oljFX9$bOQCAD/Fϝ CԤJJhVx;NƣkssV1ITiFo]]v37ԙ׏ٜL\r%¥xu2T=}巆zac ] \WI:><NWu| |w֛"{Kb0Jh\aɌy2%AѨ2SrtՒBR9AGLlO,7GK$cRQp9@9U<[㶘Yg&(I'< `Kj"䍞qL|s.sZ7Q, zb LpGcH\k[Xҡ1rM f7JGs}`=wŒ wǍf7Y}NMe%G,H#gz ]gRG^hWȣSS[aA UFZK!,!g qtxmB(#|e-lF-'ݲLf=z6(EJ{7\ T($:jPP?:ʈb^8luB5VkP. 7eOq0 Yc߾ut<o[;_^ZG[GUhyƄN_3I* uBcɏWݛi봂Q]>~:V*gI} *\8^lD # 3HL^#}(Ɣ#=;JZZjޒP`Y~lVo}ɸȲyS]+y XKpȏ1$,"Hǜ8@ Cd(:N-czh01Ll̜HDP{z]v&YU ܙ"Z,%Ų AbmZ$#L<1zc ! O2h{%(ai, Ztő K;veޔ2Rm=2t6 ;CfQ0'ʹH%-1NKFMwZV2P{~O|n=fvKy?zXN|.)|7XaЋ)O'-AfEw-"[ěcdլmX(nR8UnK^?セ*M8 L8 ۑS" d+8A}5D!^c Ed(s8 aBV+|#kN"EblNnTET{؏c92骪w}\׊35H][ nw|I88LL?YipB\I-z|tp|ys0z,F>CvsNyn zI2J8ͭL_Mp2fxPD"Y;:ڀWcl|ھ-eHbЙDqM1%_uGU'B 'EpMttk~C:S}qe| `Ņx(\"<\;ggeOb< *m*R6iBk|5 |bQ)HMBi ˰'\"BMZ*Fc袁H0C* S ,_T:?)`U/N[\\ς~9Fd [/KeUSAR,4M8G$)WQ*ss}L(f'2̧qU!0]ggELPb *Z'c[>N4}JfiLdpGX]-y =ySVy&)Pa=׵mŅOҏ3ܑyj=;&8eSՑY-HU _r+x z}Zۡ2pmvszK~T5,FG?E"#Tpõ}=>ԊZU+Ѩ+ Zv~ƥ v*G/>+lF PhBCҪkhXa9C㩨Kn;5\/">{9ha2 ,BqvݭWMU[@41&ϥ] \w;-.MniDVa"M:;pM1@  CЪ'}>M ^NC{8N^ݎdl8̦TZ]1H(Ps.NG ]7b!݋ I*Gn֖GQΌPnk^s~,U$ L, p EvaV&25$KR:k{S_''{%chWde|Z45qܶ\,֫gEcgM-+04^|Gx_QF5%vr4)cXnwRgpx ;qEZ^>;4ċ3Wˇ܄Ɍ#ϽQ4 G\S04|=!a=,eIS3F=Uw`*A]]zcV}RV"ͷkkŽ|,#@ sdk||2뎇o8|` M=@}Iw;͉z}]ee V]ߨSh~.PJ9)ƄswC!XrRB0\wހa@hNS='kͭ!:{=3XFou]BF.!&nq_ :Os_JG&BDU'w |Eat:,aADzu\\+ UYBc,e`vjsNsv9= ?߰EҎ5`)ͣMGvoF~CipFhtq]b?hnQqP,顮'GFdxkuxkh Dyccճ2Y xS0%.&ʹJ3,Hj~Idi/awJ1P .qhd~`/FqL=4HW'5;t,'bx7a 8zy_mck|R|5#HDQ$vvPr].CNu + YD 㮵]0(qDfm`z+F"$Bɲty/bc8K82[|662<;scBf |WCT򃒶SKZc8)Y78bdozoa&6v|˯`5tu"~G3%oZ3.3"g]*O$}DM$ӎ9fM#tyNs MEFқ6B3oIֱryoKj$־=G8,JM$(w 4pF&A 'E^[C Utbyc 8/1n)&s8fM`*0TO dmaÈMQrY5wqmAd$%`pRg-AT:_kBdRD45W0A ߑx/t?cj"gؑJOoq-F ^:Gϱ_YGk#sl71>yaSq̜Mh Tr]vJ8$kko=2LW J&#dfsf$ 2@Ĉ9ny sRq""up3ʤ9W?2Ojs|sq]t>@S"|4mH/m!-f#,,'d8N%Sjԇ,Ě.|- <#@,9"'B yQMB礰F@걬LZ#`rt>V FN"cA^KEih-.+*T;:}8a)A ݷETWDRmT<ܯb{ sCUr%hL.b҈Y=g׻@eUSt=㓀NT1pge0 41mI? +EJY@G;$c@iGژ;IC痤7\&%¥!La x;}Ijb5 пcn) E4 Qx|pLCJ '}ل<e7>^&% Dk.UX WW G/;%^7FgPtj"Vb0ܩQۇ!&sO)F3zJ|"lB._td)V!6cWF#7g}*9f{|}]#m+ĸMQ!Y ymXѬH}AnıÀ9vm@QD=i콪(hnvGPhBHWT/O`Ecq qQcxwP7 'hnn5^w{ڃ^UޑjKؽY^ֹ_qX>BoEnE5 R[lRV:Bz f0(B /`;jh5hCnnlכjw:n+u5|ql GyY#݂;a.,hlaA PQo~C*l Aah܂'ș)٫ƫvB қF^5k4H~q`d '͆` o'<"nEn*iv/ɧޯu57^~X]V+?VO/w>c'eUԚEv {qos9/SEvܡp(.WR1v.OߧBP .$yغ =E|ͭY-Y 4VtK1@#h\%MaPĔ˻T,JrūU&k1Rat,eUH$[T9=v K ^Pej"gZ=< FzHZD2E膆7r7V!=({)9}pOGKC,/3O gn`ӥky1" i CAMA Aw:64j3btoipJ:>ީD*ҟ.pY"l_IV)cito2^q0ѹ4 Gc%h`ÐԻ^ }!b a(dN3`>Ϡ=6/{,@Gp.Z@3\.VA(FbӄӰp4%hL߹URwC.ei ߯k ~m_6OـMS!YD*H ?T+v}]kOi-T-bd'`At H! \K)ԜZkNvv;=868}i< v] blEN~Vy2O_U{}p(j5vf*61U0')jz.<3.=2/?C?o\9Oa-D9E)fMq(+~ga ph(>eϠkEy;Owni`( q`1?_pH}_I8 UP88}.0N*tU<]ck=leٹHg4J7cfaGGN_: m?p:,Go zvo]s64IVrlꇇPy޲tڔLyUmDs^JbA$O>h /y3؄ibBr`=EP6k~Zo;hE;I>G7香yluPvͺ }R ٠ _̈́ӭ!.q^JAƊx1l%Ek< r-(|O7c;ʼB4=3jd(̟Qj[OvXy]9GbAAlY5qS{ݫaϴv\-H-gmG`N-TSqه->Iϱ־>+O>I+wps~Qmş)f>fG(g뭿[ǻs@1 ׋buKf<$JFWVK?zvU>.Ur@֪[W}Oy^gĂ&^Ev쬂$-u&}I0nv.9b#"h!N0FMe%zgXEsԃ/Y,`q\WJJ C_L$ͱpV _URvЍ`( 8eâEXwˍu'A"*]źXwzX#:;nl} 'l(݌ͦ"A:ú3 ;dۗbl#sXF1/$5K8m " 5_}M*(RA{f^߾&K\K< "`ZM.1H,ufd0p q&޴`f_$+?tf] /y.ö4Cy z.æ>1| eY˰[08K˰%?(!L?>DGG2`b 8<80xw狃Һ!MҰATy $ d$Rce!# Aa U,#;w3ȵ;W vk〶A͗u'VJi ʕ)d0C8] DjVi8S)pZ&ip4LĚTTQ(>(<_xPf93(<%~p(njd}KXKy6`I+쓴3u*Nn-$Crg~%] h8b_P@*k.e)8.=ۃ7rlZέfgWAuc(.)'h #;JS֟y͝b@B9of(:-5>8bz[c3+oeMh.Z_75?g$BXƖ?Ƹ^9D}pH rRUi&ՙ+G`Y2o`\t^UPt>E$wu`)pwT̫RFSժlQX|@IHmp5(Tq]^ pb?r _TCPhq$ݼyp@^cK9%8d/*YjVe(wKcg(^b`1:Eh*&SwO $CiO 쀅n59Z=obi1[T`.ߺKP }Kh  KZ{'IFⷥDCn([mԐ{,BVQҞpK>w RM—]Fk%v% ;S?p0󒝝yhfLysUŴ$NQTMlo?^nj>w \Vfo҆8''$EhQ;- wϋ9$-`ji}nI}u0lS.@ŎpCTjbM5>S%L?JBOnH=T{/ߗSjG\6ۂwrRcHz)<ސK\˖(|o峆WQ>u|7>ʚ!. D̤cT3TOGK)#9,pLDҋrp3?[;-W>~]^U>YUa.__\? SE$;]cJ^2#ǫ uͽ>nS01•]cɇr0dH2G{hHc)RcG~&<93>oP:{9݄eѣꆼϋ/b'Z1l!x{wybq<lWx7߬<<{|2h H.VkĻ N0 bP,R~ԁ "tLTv$}[/3^>_8s&HJ\/jUQK)noy*oo?/3Ƣ6(|}^شo@k-okh> \?ј72$up|/Ot 3]LJ~6^/ <~\w|9 {&Yo7z?yKXL pwb[tEUH˹SndQ;F>?>n8.mmӻXm"#+ X;QCЄnKwXCWڸ`cSF8>킀eL1Rqеcr%0S%4rZI@ ;s>\$ Vo;*72>ڔ_.+݈c\Kt^@0 W+K1V_lG& ׊.2|*2`5ij!m1A0*p p'Hb*e=.ߛQ>OQeu & T@֭A`]jJ*5&hf"iևF`k]E" r3UU!v-'Od(MuBXFU…G b̛B6W%v`7@sfҙʔUf'4 v(:J8'Oaˬ ryL>/nǁcTRr[4W Es(T^;)Pxjڪ[d:tK+Nb=#E( Z,aecIH | ms}ipsUn?GCa9~lx<|p?~q$ z|c$;cx5\O?_I?_W1 |d~'OvaIX|߾s h~'cU>xw'ÕU>VWSV?|O~;OM݇~auW+LKkK+?Շ돞zW~'saήf]{ڣ/ڟ4o/YZ,;2565 ܙmݑ -}$ȳ#YZKa#iZKqCyZ;QuDťE(߱j]P0Zm1Hu}^T+)N*]<+_``,,~gv֨q5 kA_6 jX(p݃;;8TbaÞZ8:<77{g>d>W<~>@8P5GNG^b .͒ E w9 O=Kqb{Ldۭc~fSV[^vuzN~QtA] ?u/]Į,%ayeym|)qs͝t|7̃sDB@MQ<:2lj"pB=gU$e:j( VQqϩ|ҙҠ(J¿pNyM 8!$RNS ǹB jX?ӉNjjP:m-_n!Gm O XAz: pօ%pgh)Oj1&ρG=9+`i;nxeSn"HU*yw1J.Fn-hw2ȯalJ`%Lg Ex~وy*?HJd)'_g:spH+#^m1jhp ̟R㍽A|3A  n=kڰw~x&J.(k]7earxwwSV%?{kzxYoa3T\mo2Č++ަ|*_BF0@hǂ3a+]c9&jCo3Vr>$[fnvj0h׽Nt9Z~QiaW#FgMEf9%|0ý͕/<_74ڬuKDk<1(li{(2T')ˆ91_Ue}[H ~K߭\A9j i5*I 淰KT˴FB_(H/½}ݝP#1U#w[{>.r~-' u^%^ό>7; /rL[i/"`fM_jl_0˦ZWރC.T:ġ(7S\ S}{muNEn? 3M'օS>M!o~iny@(w{b13;p>4Q&0F+UY?g]yKZDxL&Be/?6-.G?^E-E:Ђ-e>#pw{a2uw]ܩl6gHYM~VVϟ>GsJT6wS GC9E.2tS~'.$_"x b΍.GqYT+a]">ގR{S 9O3H}eF́~# >r 1.$ɕmP(z(gd ,0 K?D̿ydG3:$8LtTiϫwk߾?7j߽} G=wMZ@K6G}R<ǮUd '67/J3($(FL?fcnLn+Xܜ9S2[raQiމ۟]ڞ=}Zl; F0sP?;S9iO S_a;E05H5oSE|;OTmrk%lAWrݠp(Pnol ópPe(9)Φ֧fh=mӧs;#Txi*iDz` Sy]]e~<xseyA0+ iiZAxs~<2R \z_ޯ̛u Zm=s&g&g6 4-CyzoU>w'A6֝ٸ?wgvG~64]ٸX?wg#lL A1~aa:&)w%&2T y7/6I 6b#6J7aX|.ܲyۊMʥFU^~x؂N86+ŚŪBY;A3Y{yh{iȬ {??;}2 ?:ߟYW&=5>&?ޞ Lx >b.Ϗ˗K&<ߡǝyy>Ry|w/{X-{ѭՖ: Ԟo="ۙںX bɝLr~x pAT{ΣvMD 4PEkAf΁"t&-7̻uP:kμm^&Sn5w[w-ӻQ'ަww[ۺ;WN:`~K /2BZ^7=^Mf@/r@ǦHfz0T3ekgk>찻c2p! _31c{[YP X~ v$o ݽ͐y;Gpe4gqt gN0$h?x&ul^_~c1wwSB5 S\h~;uF[HVcvaُكUTKAԥp-jג_ܡ\hKqzEAm`0y5$cy҇4xqPX}VXZV]0WWW3vpS WҨŰ/9e^l6;YE(-hBamX  kimQŏFIW< S# jIW| {ՓW߫R ~jyÐKBqB$ւ;Tsɒ`1+.xNM~:.QE?:QHv 3-mk\#(QcԂϽp[ ~"V2m\/1>]I,T bxB]5O=~-9Y4aH@t`0iA/ q'4e78@sU(!lCڮӂ1BNՃQ?ZkA]rJ / N3a&,)E0>(`=L!ƛ,$d3Z(xrkY7Egz1izwUicS-`Z [ &{v_JwL!qhm|tAu l9(\}68{ۆFi_ٸ&"kI^Yy4hFs٘ j.e?NaEgJK_;Ѧ3:@NR jyED6yhae"]5%yH1 :KsP,E`{| Rm[ #v07h!5 g+y50l{}PLycO&E4>,d+"'215BraGvl&a*WŁ$̨߂ ;x]M~Ic<ش8h֨%@"e^;j 7]CG ƫQE)h'5XWʌ8|H{ X>AN'+A\s2˷z 8 ` 3cSm7 @)\HTU1\yI+$`N"9a;E*q3#&PeBѰ[G%qxa#2N" /ӣ'qՌ9r:96S.r54ԤC?|'UZfKȂ2?\cyeYN ,N%n0\0tV?"=% 5e`@WbѲsq($"Nަd˦ěv; ܌e7x_Cӯx/l&OC>zej:>[HoI-X$lX ;;7wXBA&(}g-ց\ Z/;$&F7m)?hnT.Gtl]siJv B%$ rW`z4io ?&,w4fo%ΪwVqSZhmYj8tNxUQm(~kwXV#}X(a03::3醻 qXQ-╶K}`{~!W0'PƱZ<<3uY [f"fARx>jLn?{2dde &W$ 8 )U>jl5$W! RVcז_쾵:W2j:ǯOtXְϲmױuD9o{ob@4}7Eu5zZ^\Ԑ/ XjbIRha?))R";Vijf#tT!H&#=T,*tS!rq~XL-bysb%^h'Pt#Ajc *: DqvT_LpwX {'N4zoCwtQG&;lw9 o\GfۖW 4h Zϰ_( ΰ,Y`H`QBDAȥ0{.pm\kҤi!۪Oz޶gZP-(3@ԳM۝~| iA4-<*OjĥLA!3S D9&b+=:C*R~RH^:@)UaGvn\c6|A+z^t"݅7ԇ9m{nl?IBF4B!#Sr]&.?DZv: Lrc<97 Gb.kz1#{In-XF O߾^o%!+af1r^s|y~^Ӌ[D.=n />Rt7HFv٬ %A bq4)(D{;5(Gb ^A}Xx[>+唭e'q̈~akwE}^a%zs{n G\riQ9_4G l~5hK3R~۱gixkǛ}ƖN!0@ z_zk/hJݙ}旭=::[ݙ}QͅEQbH4K^:C#j6d[hzh'[}߫?-gQEQ :Ajևu54 o;$0[EF#33>ƃrDD2{owё˙#l&P \Xc "pވܑn`ɯђotﴄ8e.ǧL/jwʣd<&H]}@"ǝ$"EPG:1@&5}D mu:k1fVj'c4G$oK;iPg_xZ-pQƆ؈515I&KZ7:ZKYK7,#ac 8l9煚l[ uuhu'Hx}(`o28c r!I']HF8# 8b!)+Z髡r1p SWǶa@jD,\N?9i $'h ۖ7H*nFIv \OZ[G1]X08jX+]o2;|PQ H2Ϊy+#,`B唼zV^ʼq/iбz4 x|S 2DڸQ;xjYr4P@^j\uQ@/iuBL7.o^!j Ĥ`~yƇ.!n .tA\@@n2'ߞ@r}L?RW*ߨZh~g}&8pSړ5"I_39E~v>L1lL372}HgqOVi*/|xߟch0 !2 __}:B?L?_j8$xrY) t:jm4Z?8`SHq"lߘ #xs"jq%v'exS(`z ol٪^0xGρǏhi+ ^լxa\6qddpvX;W4P5@-+ߚwTpn/ʅŅ^rXqةŃ?M0yfc {Ͼhn@=&-[FݭWW|{y^C΁U;l\1N~&tu/TO{^n16vdY-\kYmeL0pW#k It4 fY?wI+%8di^&> tUc.6‘ H^v@q2Kt heWSG-(=GAڃB}_ R -U_cT["!ǺiH^VD[pDj"aDrt-dVćo.Bv `u@v[u{eV!b"T0Ut Gibw$RʆRMW@cgfp~ CEZ:F1c4$EH#gg@^^{C#eA 3b/mK ?e(8t`PP;GAbp JXdı~mwВyeOðgAKK6(c}0} N]|"aOEJ毙HF`xFϤ۰Ä@W#ט 4H7Vmfy$+$5 t}o ٘  p ߎpId2 DxhC~ڡ[Xh?(AݮB%ujѯkSj87oLXY.T$>nV(## QsZ.^v+R#8zW>˄֤wvp`xAb:_X줱 v/LN+ףPqz|g㮁kj"$`Ff=yni",S>t=kFfdJ:cVZVlD4vfU[G(/f}ßyp I覘@`bY޽H3! cѺ%1(`I!9"4ˉ&($GPj?~,ũ֫]J!E0z9Ǧ7moFܨ %C ۣn4'Πq㝃m5q|0ͰS`"ג0LMfBLW%7a[-IM%ޘ^]H oIy[t -1#<50#i0 "d^ 'D1qGkKQ2rcpwvC(fFl;jA Ux#YÊ<]FɫvxaQRWCT):{l8FnϤ@q|UiOO;6ETe:bD]g%N qƼ&Eb:,tq$$VL $3 !IUC&iRo|L~k@r> 2ey($GW[+kQςX=e3;C?H !İ1g)AC%44>4v$#;[փpy=B3#oG94HyUfΡz'?cx/ا~7|.Ky_ԢG 1x7 R( $Q8Qtd*tr-&/,uVt3um% r |boIŗɫ+s+wLSq$NB2PgQIt#i& ]/fd ^.Ƥ8k¨`ibN sJ_H>#c 1'@9J[Xd.fS]mFk>A ;"F$ڀ k_N``ʹolMtV Lʃq:nXs6_mAHM)esM6 2e tWvÊhUA"ʗ#c$8qnp89>;suϷ|%/hJaF0g6챏0I wX?"-s=Xl?HQzF͖l7F^d58Nc?UFBMP(]nP.d wrL$ A)'SgYb|RJ\*IUKkKrC>MXwNF*A}A/^7v1l܈F#&#f<r> ڂn .:h&c,T{rwUʽQMIq*`kX0}8$o#mA?&)wۧuQdj&m[œvZJz6Ѭ܀}33b" x #^VU\n i<+RAM I\My?uu6@2qTTM5TUΠq]ZT_go}2;frAZE%~^]yPMo>{#P`fke~E#8mJT3fTzMM{X/} )ݗԍH9;[/{Qٶ}&n#*/@h/2:h%P/oq t!FIHcoiY\F!]Bq}x_qOV_3L_v-ȍ%yzL|t_J_L67LJK;ӹMg.bN?LYYL>O˜?l]#n'FE}h< CiP29%qE8|m'D^tKEo/Nx?Q MBo'bsyREP\zDRmDP'HA]jAɽc-N:ϸH;Ѵ16”264"#Xfr|J 8z,շdd?   u;ª49`0cmoVGU{!!Jbi &Flc00"€d͏h:}'~ttYAnN<J# hC~/-)#1}Ug}{ $`5CRieÇS*i{C*jՖqTx6(tn,փ(ҭOY2&J:E'bqE7o$IjY `FQq߭l+/S\鑧-/" NX%;J Nj<1t8 )ěHl- öȲYFɈ/X\,dCFit^Fqڍ_wWiԲ:8𩕗y}s8ED%bv;`kӳߎta_uMҡSqEymi'YKUmeʺO2Ыí7NN^WhAdrxpOc|ИQ|{Fs;3c~w}@T>3ߖ3"݉gB>.7y28CQK,le~+( u͆ [ƠY]"h֞0(5&t &?>tg"z(h"9,amz$$<3l fȃ[&' X (,MCz$0zcPF83 c5trvʭet_1º^ƖZR6]{vS٥J0٭Fha"YYHJbH_*׹ϱ]q$z/ .w!](6wGF2č0s9KŋNF&Lp`xs rcJo,K9HӒ7-bI>f2}i~R#tP!?7%f(-:Se_X&q1|5MTOOGؒB c0)nNsl š5#kcw$gL MG+2\qj@0̠p8&$j}"sJV"Ֆ{kce{I u`oVqM# =<9qꈋ>> ^ۨ<сCBoERy1b "s+u"°:Nj cLk ܹWΣOcLEԌD3v0Vc!zA/QsSz] ۀU)xvt&6tQq}70`l4Xh:QF$y#}=1)"'״m$$tiM%9p A^hrztX䬛4.HL+?QEF I{mM[aZ e.I$M/9_;!] nh }Wu2d{+kx5ªmSVojj?|VLv߂0qcOu#+~#yxzb,1t11rѭw]y6 : )vj©1ExP}STlHh [%2dosf6Ħjyij,;܈K(oRZi &K!q* +l܅ 2t ]80 $aA^5jdqIormZMh*.-щ㶑0i0L6nrQ Ϗ`dZYY($6Z ֜`1 Ckp_WVf} M *juB1*eC!{+ "Ӌwu, A%a跼Yy$hFMNyl05F?xvh($Q0^} G0j0[5 7p sH7"EPYw9Q+v>/yilP=5m /VŜv/a.3$ԽXPe#ZJt<>w 9^ IV@a<7 Dw{clDY}1Q Y:g)&3'$$S5Poߪab W}d \.+tc76tEt.J28x慈s6~~O&-Xv8=Nh>!oNJ4vxRuO3XX6H'KV&QoJk(fbLRVd&@`р8bD՜ R9X'ڟTrr\qΫڿʁ5ӝLXhݟZ_B٨8ï󂆗ȏFȟkbLE,*n bVYTi3Pch O_tQt+LG4sk 5=yA7qwA[p1c`jEEye $?JFl*$WؔK5:zZƣ2ĥ]JN ghS4y00H/ր: ]B::@ktڭQC2E:8\kj8տ,w)M-X$ <ޥ'?h#-9E]ҌDH`[: 9p.QWnN ?h] G=^W2nF7i+hP@/B_e%ZdJj$qzW[g#U( }F'Bme?ʸm*ee':fgF=ZWmѥ4֠b,G ϣ?08h/Ji..C!k?wɋ"]~ϫkVSWY?ާOtiJ>] ?Q"ݢ2*Z_z ;>N C F)BV8etM``(L$+vTha9=Lh&Nu!LiPUR4`δz(EI xauŋrdQ;r7bXփ q +1NDz։IEkbْq= La\n"C;a =|j iZ3I/Ab7FhtZpa}XofFcFTZT &\UًI/٘[-Hp\x2 +kYV?c:֬Fvl2qU>G>LЛ|]KuxѼEՙ+G+9PZL,ԡjI/'ے˔H[88E;5w^"!aJlmmЫ3m;sɛ Jg<TrZh D iIhD4`lG%|V&6RFR0t: .we*4k4T0ҧg0DQ7`:0cv 0O" EHK&g.|S|8<9-@v:]ʺdLGAT؞?9 U0{ݦO& rPہ AtIUaB&.t4\swYyc9с4UŒO stP NɨHǫUi(fg͇>9b$͠S3#'~DJ"Ŗ{"D8@Lq`Z0qbX4k_(F$ƏU i'pC"ꙹC#wkLlnbǭV:C4&'P0D<*hnze2X-ػ}ܡ\glBK#bKbę !@&3AsV)MH>'Yc5+Ov/$)x lCۤWKGL~dqBTQ9=2Y3} TlszMdn3W J{uaS0EQ4 ql!?3 onDu'ϮaȰ'C^ >H(ąGpݔtHnaQFeQpoHӾ oַB2ӧ?T;hʀɓ_Nǀ,DnN_mt0)sZK*f-= &m9ʭ0KbdR P‰LC> Y8K3&KD*sϱLXi6efiIR bI7qN$QD$rf\Ž/G}0V(H 6LΚ׶!Nnw &gap2 u$d: sn I| &<=Z~ԲF>Oz1>{a} HǍBFpagIWgux F]HmbQ5ZZx"`m8@۝ a!/au24: tWڎ5#){bdJj[[ST4oh!VaږmkHfhZf#m3]6j+;M,;,Ԛi~r[r5p38#mpvɱls#NMqj6вw0MNyymMWYSu>k%{nn`c w\b(ltwܬ,rٽsjHdt+}eU25o30c;%+ YԈD`qݒi݄nMf v6pΎZ#ى b"ocsĕE& EW z*{L;YloN2]P3H KU%ŗ!L8aSHϮ]dPh4؝QP`#dgX7G]ynfa_bR3J:!ƎIlЋ @ hX@rJݹf]BUӥݰHak{F*)QvSfR/Em!Y>1'UbE&eg J>[;x֋6#S?̱/5"^"t^puqQ'ŔeQR`}2,kb7Mk3h.'dC*9S.Mp`ȓ9,̳ K517sKP<<֑ΰ> Z4s}Vuv ]^M'_kDk&=^Y?VNNN'+'{dB`^V@ "溗mrr{㇔t&8 d]vƗ3Oս7ڿѾs6f_[S܅ɾ׳zt}bF\#~ϰO_΄?yi4v3q\i0vdF^dP[W@1Q UȽH|Kfstrl:u]ñNӰ̓FGi,EcXk@ GFcݽ V?YKW%g{q-!;8di!x=ͣrbdNꖺqp:g4 9eU1(.:DgHɦoEo 28C}$m/#jޞCL{\D(Ma3 MIar ,tdyvIĂc; 42s!$<,%& 7uLlG|1wo*YIc S]]c5Ҵ1!* .QҨK|8p,xq,vzUxYa@4ۗVo|In =59pp[ H J{ gѮUTIcᛙjm~-^焵"؃4i`QR#P4 [QkbTQ, 6_@91t8S礖jB4W+͋G? $ )qtVY(DIcm-ʰa&CB'c 4o&2RrurO{h]Ga:VfILhۥS :t9[>ar$ :^?/`(9\y#eIf6\xҏUC1A/c4jb"ASj-Msq}J]0$( {8bM>hP6ɺ89O@W|1U#6ñQ)$[Ŀ],y[N:#-C 5֜*ke)`HnD v%ŁSG@D'YK1ۈq]bj^ZJMPr.,dOTҟmYMLYr-{ pƏfv}TqH<Gcl66oXϘV"ĥ3>98#?@Ζ JIUsk|?_5cc3dt\|̸ uO-'J^0Ժs-UK.:ƒ[֭T@L:{yjL V{d=ǒyIH}pOBrvfNJ@S@ܜq(x|u2Œ b0|MmZ^~J 4)v(lO}0%q:̇Aq 0#pD\X w ٸ576{q%e2]&)"o<G C`ZMR1ISc@4@Ac\&m,W'GdYmgMW3( \>s% Z%-UQ"^bӐnU-P/^?%ʟZ8 ;?Atqex/EUpmL7 MBFL&Iսmŕ)m! 'iMU/T+7xٖ+h0jႹF%ѐ DUِsL5*L.f+(ME0˹q6ٕ@F娠T7tm& ڙq e<:m' K;H#2SN3$A OgG\XMzr-BuiNBA@A-͑6鸜~^~%%d>aΙLg I`e&VHe\l{FQ n\lʒX3 Y=Ð<9@30qzRE!Wj#杼xՑ{j;羮n3[ȝM}vy ޖ90\`|sw, Y`z~O%Il24zSɅODƸ]UҢ*#i枙ZvlNF'bCzVX2x~Z'9y_FF1"j97ɎonL4GӦ3!iKOzwb簉KQccKk_ȔMd|04a2d$û%[sZOv#)t6|&Î3mlomī(2#H@ #o -XH\"H*ލn3JlU Af^ ^vZ}mK$^d G΍)fl:z |8foؿAzǽQUXHn).ٗN32 W{ ĸGFL_AkMz0ddEd>EjMDm]1 cQF븕%߲M< O"\\ RQ=.2ӹê|1n&\oƱ!@M,y($[:^ b+Z8f PiI9P/4yrP-1s *䡞#AO4@+Rb3& XjF|`PVOe%X* 0`T=hNYEjLsvI:%^NA|Od͗jۗ<'@D}`م.p& !4:W4V$5"_,z"b>PTj g$JK ~jn(^thfȚNg*/jem#in5^nёB E>L |c-NpWkJxJEې7o5#UzҐ@ICb2wHrNJ2 OESLÊHLO2e3FQơC> 1o4'0[HH $di_Ƴǹbuv]%>z. ^u%)xYK 5A_IV;HS,8WAuoD!)kCg,Cw7rĒ~ȳo{WF/5IUJqxM.=) EkCpŘ QߤUNvXcrCEäeڵ,L?w3-棗sס>ƅz Ղ32 cdNul1ƵdtU{ǽ能tA0nPTq ^m9iJ4LJrۥ'kRC0Sg'\TکJ>U:#ߘ2[y|x궪Ӝ<[YjNлk&l^ 0DMu*fO{zroZr7t1ܛ ?]s^_s㻐g'FÛO &C\;H[o2P!ĭҊglPT \DZ- "K 6LŘ`%ioP0Ipl nR Z%ߔqpl1՘nL&t;qx&l$F1 BМ%;_˽~K&^+C2ߚN i>Q9ї8> A(YL ܢs/|{$=9(vx2L !-L@*v>y8C }J:%4b0EI640X9 wB{$!FOW&}+)ҧSsf>Cy}g$Fc5qlRY.3HqDm| ^v]YN7 HY2\AQF@AU LY5]օ+y.aXe®P̑InDGHn\F"%qM\]#{қRJ;3MtΗ]բ '7?}Aއ"NDYVC\$=ygD) lոIj<Tt%Cl4]O;r3Y}mv&k6J0N|p=]ѭN Q2KH=U~&KLҒUɡ 3z,Y| "?6Rs ių=e%;Htcwdg9"3v}91.hE95 L1Y8"%&pRmdO'PYcM#=C`'O?u$_l&U6UO`<1 ܅nT¢Z*y'GdNՎH^49̟o=YN{}GLLI'[YLӃ Ggv'fVTa35:'lS*E5173X'g9(0 P<lwy Hb`+ߢ65;VeVj! 3K1 $ ?$] ?7vk1an]r &زyv EHK~{i|hH8et3  yN&H;{)?0hsT55h{r'@T1>.#j4$@=&@l K[r .nsȨ%Ysh_h#HƋcMDL_TޞNŊ%;ZqTG[BN]ZʔRl>u|xߤp^w2ɮ;O&vc["kk0 2mumuKJck2/L m hh5NS(n~scHC7cQ/1?#b{ jh_]w2à ۦNN}> :9149%-:<0C,ВKs/ A!x'9A۷o xy\Ni _wVu:&O(ro\W:h|lЩ$9K7, j6l˦Tj>|`LIA'% :Jexu KdaJ {6cW^-mId#h&N/>Q9"% >DDGݰ^_W[o1J(Aڑ 3#*8lcNOb[M済mT", d@RƠ$#pOa)`[`xNM"gLȦ t1 %I &8tih`N[HyJZ=T(1m\[D PXC8fĢp^3A(E&tz;gcM f S$H:x;jIC2B伍JaN*C1w;bu"!1! (s Q:; nyDi8v_?OOٰ!ǚ_wO)I':n`)ds% *+2`%Tꬊ5'ӌ8~RR,b/$LҕF@21>'pwRJϦs&Sjg'qs!KC,Q[|~]>B`ŮUpaz'{y ijW%ɤ=xhÁnNRN>w.ⴰnbmjk҈LN;X< +xZҋUk _GׅGCTxDZr>SsL5=΁aa  QLq.go' ,9J XWgU&lJ)K1̰HuhE7 ‰\\+m]Sa%Wdeج|5mF TK>h80؉H8c=~+~ښ̳:)\ egdFuF,_.,ExlDC-{N(V;{OJazv4y؊Mу7ol{V:;{";?<Oo JSmtowT,tJ(ё%z1k"+B~׍֍z'VZˆ}ZdSu d?͠Uuq4Xc[ܜ9ThQ? g(z+@᙭ɕ P㣿QnJ(wΆJK"S쏲ZtEP8`qQ$׀4W0U#"Y=086A!d&Q!kD$fߕ#uI/mf^AI0M׆_di|LF~U^y=9m]”Ҏi@hୠnfb~VX%#sCX*D0EC7۴nY ZI32bfV|f2T~/΄9Rʹǹ:"5Lf&9P⬏&mNq KpH H|H*p'1KH"n:ݸ O N!VyԿ:A.y#^Č 鉕?& X"Hay{9I@i tIa{|<`; ^iAm/F1򿋂^k\i1vtfV@(&.Y(|7]R6u0'fu1-lOH:!phVFZđMmZ(:]Sa>;YySrص32SjBYKS$,UޔgiW}f+h XgǴ5d,XVϛ-c y}Cx/_ sbӊi?$8[ 6uPYE]D|Bu$LA݄voҶq{7u@Aw0݁ 6Ҩs#Ps:u,-&nf%.F{bV q{)d$=XK'X`>mjTDf%QA{j/QZ"FP #ѤrtLn,01Vš*B=OT⩌~Ă9h1'ЩXS`Vq2`x?[==[]ނ+uyt>ݳ n䉉kWTMnHi)I@BY9 zĩqx%;eDJ4FZ,(υMpjU:f[6RV9p-,Xx!# 5+wV9AP`ڠ'2y-k3ĐXU#$|AFKDf|J6#$̉ ~f:{D1[-U->.%,^sMdM(xin 񦿊 4)648R4B:;"4dCxHjYecHYO _f2]Ι]tktQO?Sp]iB_y_UkFejGa{pj$5s&s j GQ,XN͛7wdtzfXR#!m Lդ >6E$l$"d>4mwHv5.)0 pqiiFt:]$N4/oG9uXhOPsPECʬ's9 2Ց!NeO(d5 o%XE0"4esM,z)ȬY (:{Yk3{hU$43R2=_aՓZAJO5Z_ S66]q''ǿm;xlE1ؠoTt"- l$ࠣ"ϸd&M{ 彷gHF>naNwi`ܹzlP OsO%ͼ(W9 KkK?6= zL =;4OhբC*JOq̷߀lJQ5c%ʂLN 57"Z:ګ(lm.m%JQ,lAU ,-Ow|F%(V lZi~m&UR3T|rR5#/VpWG8!Wgmd^|xe^f)6X\3 Vu(f#O:fnS0Y}훹,_ֽzK%.wW=H%&q.Aj% nOM>!EuitH<%*6W2kii")bI i(?3&/skO_\d>zwye}σw۝vz]vGvf]pvns 1kх_]"ِƥ *@= TQtSdSy_@w۱xgFv^ػ|nWn2"&-l[amj\SNz{:=ґ -iTr4WQ ".>Ed#'_޶I*biwgષt'paQ# EgX 17q? -2*<:X0{ .0uC:e.=}ab mGM(4]T:IZgSTG\n=t`t+s h !5.xwwUpYvDƗxw\.ǘ3.4mDF)hzE^RW X{l80`S !g4^X{ݐM0]Gc}e|oxeӊG` mߔK/vTm|`հR74XM]Q[ Nn &:2D Jl8 m^ y= 4D:VS뾏B2ZjVVY9Y{kmbTšĀE Z,"^ \+e/HʠIbX#}Ȁ1`g)B;ӔKK]z ?" |p4"Ccq7Fd"&NɪtCԄW}4M2\Dan#Rd ar+#iڋ%5۹=[eLFJZ 2wX/0GdmVJ;y] sm51~tzpnfMHxR嵗$rPVa#4))ґDΟƉI(tzAwv!^/) pK@ZO|;K;PP%+`MDd^+%/^p~N}FQ4%w63ACTX¤JvzYgt?BFq+לpjl4/g<5fوf mq J90$1 VU;:V)qvF4QbY~aJL 3./dLm3!jd9s:]4!~hP;/q%{T5r $ 9GaT"Qn!41H6A8Dse$\)@W ]?ނ؞RL4)C+>RX^޼!\Ɔ q y :S>>Dk|ecF^ɕkgucBMvhv&vY;kڱz4?g%zZY7WTZ\aNeCYɩõx݊**f k-0"u"QqE!u&"DDv`R,9yyfw]XcW$!E*7~ MPШty\$na5b)tnaVy:ݨ͗JrSX64N`JGv4MGjP%f,lLEqZ$t'NPtTVVj0)F]ތLEtitw@~n& %SG5hȿ΍ˋʼn^ERZfkSx'm%D= |;f=eԑɍa+[OΝs ʾQ#K}A*|&_ n)ח R薕Lm?:Ÿ.㮚RІm{;nl}>g\2/7ʛvw~;?Ù`MVOg*U)כּ)y١Es٭aB/ tKX{[O Uw*gO?610+95@E u4l=GT1s{<5 ZoG*1v&F M03$T sl*] 4]kpPATbBpBæ]"Ǐ?2n)?{~;.&G<V^V !njsYϩ($on[E8]3hȅLwuf[=} h!.5}V Wӎ>o_gŌ܌Q|ߘuwNQ?nz(hgoYk{IՈFDFY8-wRq3nbJ)U=qcZ/ J&8kխdH( dvbdD)[eaH][\GI Aqoaugaҿi` wAH)VRq-IW+gU~ZNoZ]] 뙫O7?߃Bm(DÚ}8(D¯U=c0B$1w.襁IXN ݌M#H0~YJ"螞\|.t^ X:"6cP8g 7N>F_xNS?Z=hH(+Q'>κz￟%9Q,Ieqa9kvoְTep@@6\  dț ZZ$^TtZRCǜtLlv$ < :˓b$N.ciwD"]2(K'\qs2&s5Xػ spA@zO nHGD(.iuBy>0r뤒dtujFj^oY|MH}C߃8C E b-1:3 ثIBHSUes X)kHQ7@Ux"푂x>U޺eӋ' KoRyEҹ ˦6/Ekb\ŧu<9fo% ݍRrNlS-ճ pC$ێgaӞ}6/N# 8B!8^2)7[N*^Yy.+Tȥ^A EVxE8ݢO6U7&6u9vwmQ9P2t1-o{ 9HFo,XUJ:G/:mc&6E!>'uv,l wqZ Bn|*Q7{gU6{S1ME1Zܟ;H揗Pxt%U&O*o]>ɋA}sI[광)4a)3>(GJ*]3}&'\_ӣsQ{}F-#$z"fp /L3U..h"]_#9Kߴ5sͶ8Q|>Ā  AX=& sf8/Km8y]N\~xLY5&OkoÆ2奝) n Johy*`r`&/](zy-?z^at=>KK}u ]CӜo܅%Wl1J7YWF:Ц ee&nh$MtƆӜ1,hhs@-^i~>KtpxB q:(H쒛J"F"kсadzP3@{[74%h#d\X%AUhw/X]@H>)|E@ Py(wT!$` y.g)Hkb:P`فdg:$VqH07OeH8L][8aڋki%靔ǴA'ǞߴaoɧQ?+e?m!ti@R'^eX7bą$oiDf+$@Um Ĺb!H+D%wUkfN>[ wʄ`c3Ϥo* C_u }B6AD W Ŗ~#$EB.Q urrCA<CZP`HրE9n%] &1I^rxNonjkYDIŮUE)̺%cu*]' ;}s/*ܦ-Z᪪z)f+|B,Pj2g0)-:g΄3d̨!R`B --S|=zh(adrw&ts1B~|bCUݲ_JѽeBgR⿀0 DɎRY{////GD@2Ӑ0Ӑ0Ő0N:. 8晴8D$v+>[M v3"N IcǑZ2eivY /g ZnMΘ@FRD}LŜ\(at QB(d\_JS ט6Pi'lJF7ҿ>AVؼV6##0ƠS_\@jt!P>kL [FʁdZ&b +QbJ>E28 h uLi݊хxx" b(MtCEAB6}Z3 #Ih"WjșaHkP7Ĝl0$!d,>nlo',ix51j/O+ߎ(-CH><1Gk+Ի_ }B.y۟1XcT[{_HZo4 v~΋@=A41tg}k􉔴wcydh]>Pd^7TQ+#DfrLX];pլ#E~_$c[B$[̎XwbP|D+ol͑D\H<0DOIo/Ag&**A{gZHIhO|&J2wdK{}Vޮ]7q c[$z=n60ܓ&V>\ 1l,U/Zڴt}[ws~o GTie:>٦ّ`ސj5#hZZ,fat=Jnsxs07$/QDX E֧~l|">tC *xA,TTfх`_¨<ɝЃVIwդ.57$^5WĐ6pA3RZ/f /G)E#emh']u@RK|WubZ*xL)Lc$ۼ&c醽~&^<^ %KͮaD\in;67mm1c{p}M)oS+'vOY_rOO0;>4cT[߈su~޺c/G?B?|CbB+06G ,@ߞ},ĥAô(^^vbMѹ|KR/B YxaO{ a'0<3 NGAGT=8[4Isx:YqukgPSAC=EHr͚eØlD@ <G1 (`|?7ExY-D`&r)³f\IH AYsAg] ѵ]hلWĿksM2@0G)"إY,e$d&@;`o-9].WgdG%::$dR]Hێ0NE&7.# deu6dhs=/^ cz^xmz"t< ByIMceZI =Bo83 8ʘ_Q⠫&1~ ZHƏ1[Aa锲dlǢYuLBEGĂYgj:0%`cdtDvE_}g%& 0m՘a)=1?6y^Dh4KZLfW?%FMD0ɧq,jrISz>XP_ _'C&9* V8w*E|"0?nRaމ'Oӕԃ=lUFDUZc&oWM $6QݳENA(|צբkXEK[-@W[,y @QPZ >eH5˘=e_ݍu%ZZvijj-3TsdZ_Ga;j{{֓!$JiEU@M*l >aykJawy쩎XO=à~ N]b@]f);Qt.l;BCfʾ40fp'`TOj2o C\,VrB 0E_]X.?8ܓRMyqC~e,. `7Nī8IÛsRt9$kh.pŏ%23*ۏʴ`R BY0ďgsR2o7L4TxUvQc®;^-i;ņP, ?`e}o@H2~8Sؑ3iFH+at۵ 8~-pPVz+[\ a.JeԎza?BGD h˛%* D;w ICB'z;maiߍXyƜw߲:7rCP06bǻە/ւ?d'vqX^Aw/_\ Z-;!ƀ}59@>s:|i,,FՆLgBl\>a( +YlzS-3 3\ziSD^$x{uQH?Q>KVW 7;vt8ݹ[:(J"1w/#k!Ǡ6 %KfaW7꡽xG{aVb0)^=PT0/X&"Ҁ+I.68?Wܔ\'&tAT6Ra7AE+CHki[۾iżw,bcڜ1b0 ø1B2*u 5rw<Ǫz\id,hf^UQbKj|1l y DŽE|KwaڟylҎ:AxLnۥKPPcRW͋>"%j).0[ bذ7p jb@ٮ?e9 mDУ`OBb;}#;+;'0y#:|.'w;GdGllLQ$ q163Rct>qV/l0fqco)wo? 臏 lbL]<=IuzS-rˁ]^\p(| ܺ"$N{f.|@_GKyףWO`0;3'nyuD? ?7[Dbk(L= yn3R_&x{[=>;CcsJ^%Nuc=@ 2RdV]zmvFn$`Z1ŮDx >[wTM-r ҮG]k/.* F!~q<\;ghUhXޢl Vu؃Kqȅ·є6&g!%N53Yx"b(h |łw'ߊ̇|.LqJkua`8*#X(=C}'u2u.WY1(uBD̼$sfy8*.?f9tL}@œN1BdӟgXD}ߺcV3:K qS4%g -fzsg@'R"H⃥^9KVy2u!}C-kK76vGzXSfrzJwLkzm#c d f*@,?nk Au#.Y#BJ2k'ţ"nc9%-? aؿJc $3n~Ǻ(5_ W;Qce"w d7aEiW=k=fiS+QԹP8AP\=wͨՈYE Ζ)vы"(^"I\GםG,Z[Ў%:y0G~^#wdE:izd]fd8ԛ"vj>@K$4\ul1Lb=R{ 45n P^IXӹBGH ˤ9<(\5r [;^vكypΓLb"{5a4,Z?n$R8N'{C᪯#NCu> .+X $gaP G1uT`F};΄mѮnT܅Jݴ,[f"'07kpAp)m p5o NHj( #J苾ob2/DgOFT`ä| "^J33x:d(^wN8ˇMfcA )cDkERovFt!PHwFВ[TQ@gg:еR!ŷO~{=!7u~. {ιW{KwxpUuewޝ#T&2݉e]ײNkY]-u_KbodUy58$7B`|6s{\٨Փ{56ϛ4bN5[_vfL BTрM9~Ȋy.xc\1x-G`L=b.}& `9'ͫY`eyMLΙu ܨ><=8:PywIdh59 >qn:fL >:xjA{+@J!Bc(DZuX>U'/O'SJnNB|⠜H?>mDpl`"t\ڙS쭄gkk?WDiO8 Č?'g?H{16Eޫ G] | /Ux{;7H1ڤyIilK@uyU#lP.lbZ/e'/W948ߦKbin G5Em}0kĂ\A+x8Zr0n2fL.Bp$퟇Ҽ1Y6@ΗNkԇU9~+K~3`26GK u$iiff²ָt_KBWSL'W+ bT8#UvsNY{ R6} gJQrn ?ُօUs3^LW؉tt*VOP͂ %YNr,,nhG-?5mR:%Ģx2\Sb VQaƕUK*pOW{#F$ G3ה05F8(Qss61oÉs]X'$3A+UB%m*N"LXd*JWI\yQ*}穜P>cwy6φ4B4?&Z#g$G'@aCxiq>W\AIݦJ;A-؏mRoT|g(84Lt4H qEY]{8K*cIM9p*Irf1D%YN: Ig(⹛IQy&c|uc9<|σbΟ/I ?WdVxv`ⴈO{~G;9+\Ӝ?Z9Ο4,k)Syn2:]Lgr8/yL:ZqȼN>!]?3}_'\?7)P T;>)'Е萎B.Iqg$Y9SrnLz5Zj4:Wc&y F4W<+ՈP,fjMpƘ5eNjD(fHL[xɫ IF7 Fvq}NjN% sK \'&-ճhuAfW{-Fs ppT1<Gss{/8x~VxNǷ9"z|;">!{-bBK"7gk\wHEQ=ӱq(ƿ5_rRc 7& Ok,M]Y5i ̕5-?]=!&k)l E[Ɩ詨-ͰJQGӲ[۲,ULUpJ*YR+|I9^=" a$`"S,UW%3+,%,Q.SN4<ϒ]wt%w#,9@Yg|n# ߅ x;(֑6aͱۅ:DĘ"\/ 5jO, 0:A :AYe' VV+ C| Sr_1XÛ()y{҉"E㙊N 1ri`IVnqfe㾷רci pm}~}r7{ a*B?PuZq YZ= FWqW7lX!za,d'&~h8"4sws/+yrSHs^"m˼~B7 },RϤ˘|>3貹x] ݮU!{ѥ^U_ n:cc~?nG9NO7jr",l"L.!_+^y(8GTVELIN\_<{?Q ^f7zo@=o`zD|3ވiP뇟;ճbw/g17Y37߽B$ŀH$#ފD7O 2';'1äbqnHOh\})n(-g҅($mddYIꓖB9"6]DDsP$ q4ĵD""wK1eH55M(KZkѨEvㅃFO9pNǹcPMB]$Fܵ獿n(eQggr u'_3aa/ĬZ%TS 9ho lA{TOCy[64cK%!dVBq8A 7[)^{՝T_v!]"cjɰmw:T'+S߇LSe?g˿U utxKQKasMF#V*ˏ~h5,$l 6 _u09 ()![hj 1q#2z7b-d~Amh0bڋ/lOv3 U$VJ<{,;}Rp FښS3N s7X^9ަ1)ae {G/`G"ϩ 2L[wnyٌl xg-o>B:B|R1lB=[Wx"@'Dlub1䱊l%CJ/3+@$$ ~,{2.75L{7x`|3G*+[[7}_`){ɊVzs)_#Êo) ? ?}{rqǞmǻ;x'MQ=aDO!+2M3՛q$˔>P`eO&ŭ#iVDcYM#5}H O; ë8EU-|ʥpp1Xxۜz}>CҽF=1wt񸎒SeqL8eUF8~TeIpŽ;)jk^+.KȁS[/if~^=Zΰ  :.qz[* L65l"E[ < ?{6LX},(8Vq#}CUP\L&>;2Fg^kikm-$]f2N7@6o쒍TdV $,_S ]N -܉i=11~WZٔ8+#7|e]2'Nϻz;YӍHV &Q~C1~Ψ-Gvr,r]g1ezC8St*^$ ? Y{_?70>$f8Irx-%`Ivl+ǭHlS SS0ڑrsE#@/D[Qᆡa ҚxQo$Zf0@%珈K 3իXjoߘ{vv䂍Ni?@Sq -Kdqzm̑'k{Xui i!ZɸDx Yb)C<3Y& !L iW\Hя[sHxT.WK\z|?vPY儹'ᰅҜU:s-$ i*Me#-Pw⢑LE/F42hѻImrdBTr\Ub.ܔ\JQ)WX"ϻUnMţ? ˗Msž$*zST p04UnyN%/@K* M>YٞD wuc '*Nɤ~LG6!'}2)'}2I'} <}gg^ф p'/G[1U9ٟx&%FhOxJw Ҡ$ ?^W?,,}yv{wgAhߑZݫ<$÷;0#O? a!r4 ;~7m#,%P?>,Ru+LN?z[WSid̟=-~G]g/*taz~g@] vm!nn!PYwYXHKm5FqE\D[DZDYEXDWDV]n!>; Kkv>|$ٓc8:~u^CǧDRQhp=CW?ƿ\϶1X3v_(}CI`{'| Y9G0ex\BA]@~mȾ.qr,OiaVww{PxG|]` ax/mĽq+^7O[0>dl×V zá۹U`}蟗?0 j0 ˗x`TJqvCg~oފ`eE^:X}lvx &St^s8 >:`}}H{R8"oBWƊVQ@pW-]Njwf0,@plLggG OBZH^ 6>t̳g҉lNyn Lܥ9!ԝ['xRJ}ßS)!Y2]܄g$E "e jo$P'A]zEzyq Ju2HWMRGQ;Sc`~oЦ%jo'G.?ѠM&RH7IX!f$h|z#W3-ſaK,]ȧ _)t%MӲz3Hm6J~ךF" Fw>P$3(+1M6@M<^1zgЖw4fq5:Fg@O]_`xlv#QE1HDžu+4R@MTdh6#o0|3|ɊwsszASn%sMzgCzT5*_] -8Nez8G5Q^?q%# ʄ-&gH/p6{?uIES$tG#Ib5` 9Z1%b.bXrqHDy9#7D~PE] j~-a~1w#N (2oQί8՚f%I {a'G3n4/9ka^C!Vd,A!"IrMOYBFe*fCCC ,t8 AHRRcFhÀZwbB|L7B/ i`H]k\- wn[jnjSCi|o;7Nܣ|y'C㛉tL.sk1x&J'M1K.dO jo6iwj עh*z7b#6ۚpFoF3RѤjvW2AɌ޹K A, 2RD*?HQ0NJߕҎ|Ai$O˕ k-L lDȨ;{C̠[V3Q6I:2:Yh cPƃQҧ%OpOrY{Л`T.ntu2Ғ4 S"Ao-hD;GFAH#jwwM"Z{uヒ@_om{RBE8G]P *o4Ȗ/啉د2Z?.w?(-)_p-p[qԀIU =7CBѭs47[Нyf #y7fti|fnj {5O?E?h76rמoC|2{yj=Z~Oryst4d zg~x[L0V=yٟPpVҬAH$׿ekbZr)i, 8p#2n`jǁ/.^y#u`iR @@ҏ>/NJJ-Q792Z_߈lsAKп;–]2w' EJٹ&jiSCwggLfwxa¾ggssgg,wa}qv&Tg~^ԋ5t>@NxSz&c`[pz[}쫺_+mga6V(jhɠ6E1)*N;>E-/#IsKnir#M ۨ1jaTʈq ?VY bƎwb7{ֈAW{{ ̫Җ)b{P3#J9GwRōd#^d0w -ۧ[Ok %wws1ɛtw` zڕUa([ǿ'"&lWcӷӓjp&Zjm3e-{&~{Z#Q#bHlW! H:<">hOoy5 m!y`Q틿ժj/"Ajtv`o7e;/ !"j&@z!QgiD椅v[1:z=n6Oiɼ:̼(W9T惍WK1I6B,uQ-r6.^C dl<1^q&)C ;}&zA'\K6h89@:z&<?r?`oZ @RaooxN⃈h)9]-G֯7/AcuF&WK+1E휵~ǖ2TK|Z:(O-.wQ%d~vֈ-dk@Oh<=<;: vZ-ds?S\M&v~=2hGaGͱ-MEO1>njuutQS)LR [ܸPLW>HaNj!w$T>a[la[`O~>nd@jR9ц w.m0Nt,;a &K%uʡ{{~! 49`x4|2_tf1V;@.TlwnbZJ `\T;6;kgBy؈@>9Ox;/P4|ѵǗQ?`A9jwatO)㱑Y}rBLCY< A<8ºSzf/vJ13~#4Tlx Eoic=~Q3ǻ:Cd/IԴ^ٞ7\j$_p$7_yy俸;V_>T{ϓ}};`GZhv^_QubpuIE 7ڛ.r,x;hx!LfQ^^F8Ϟ;d];=1=Gՠ+i0|lY_o?B!R ?-WWײq.{Zm]${9sN:9/78 (@3_ƝAzQJЂ@! ( z>w"AEFڪF;6\&/lvƑn5ۀ ^w[ˡ 53PC:q3Bկ::TbXsh t#qy؞˧L2=.m:tn6w'ꢸԮ7eUVaE\Ad=G#́/^[S߳O__7qmuߡo{APvfkb{OݪU1m{1Q`p8inޑU$%dϲ;ٟ]a3^؂;í;LQ:`Ij`p%X;X])׃w Z޿ݖ_Ok;C♐zw'X^ر;K%OSˊGی 5] 8,hDžʤV߶; 79c̙3OgY;UãA&N/['3[vO["͢B`\ua+@YYo*p`{RCU߿m>932[#~wwD}~| JFyO|l475;-du)ބ+WQK"-%AOuYֻoĆ+؎_ؐ]6:ju6^9_ݫV:KM$- fgZ- תG;*{sJoTJn7&g4Ͼfw7hǻfIξĝd3(g(wl0o 7rq/۟6mͷ[cc>ecRhP:nPq ]N6guJnwYiW߄Cfohmko6"H\ ʴΪpJTl8G]`*Gc@U՛vc׋p5nbnD*j eǻ xc*G/DŽ>DŽx6Aʵ16>">`?t>ۿݼul0y!1j˿i6,}:d qډ@jb&8ń3 bhڥ$D ēVqf}r~k_޽.k~ʾv] vAeRJK撊)P~?byqx꜇zyl~S_j#=OS:l[i`2V6~Jn:U5Rʖ 7Y *d:e* S?y7cXmMģ9 *<+}61kqcAp/;gl:ۭN_/;`}<~,XɮXk4tB7KjU`i7{i{xzwA<ٽbАhOWk8`|f'8.1yu9W_Bq37ՙ2:o,3KqzQ"~7+Dyy JVu[oLs @{ϜBt^榾\n6S^͌3Y^bѧn^b)jÎh Ӗ[)Fl]jxó@F]S0y=5Jsvͥ#)[pI{@'dT=:#GV T+Ig5fY[jWu*@-"[ 휤y<7i 2;?~z B|JT'-.rJfI CjNgCSPOuԥ1҉d71AHQ aˀVJe?PLE-L&bgU*V HI{HʛB(Q$ J(Y A*t`ByrOuPG?Q$ J!ʅTr!9gRsz'ɑ0wO2d{N)~2Myk V'S˫[M4!2N~q2x-w挓ikL}oM+djI&v(=j:VOzd?12ºj'Z\SdYST'Sk43_RKY|ad93UhU WWӧ꛵۽2\<8z|QMXȢW;͕ ^%IAbcm먌+ {hMcql7<U14N% jICGVe/Ƽq&kBdQ1aHl랚_؁h풩Kf;"~N 4$'XxdKg*1&b]qt%xX6ƨ@726MaQ1it$Cq4Ox¹x4c8>*>u?]Մv/b_Wщáex<,ZHסNZ64HCpPtێ95.6lcՓ, =,S3$0UzQՓK{hw4bhNQm\|jĦяK{dψV7..m-cbI=}aTDFģcT$0ڛ hiTFwFccT$~0*]N:a19&{<ͤم {1`jS vķ#7=[9>QJ Z9{zaۧV JyiH4.x}~괣Oߠ˯8[whǯzq*kj޹~S5￘!% 15OV7MJō:g3ݻ^m+k w>ǿ=:j7 ^J{Ҽm؋ eu3,u\Â#.LČ~c 9pؾCXAۉٿ 1S"u.Яti602wdy&BHu5 /S[(aš(;wO~:{51Nu'(mw):؁?:8٫ւ_N~FHw[;!GX@gU{ s;9je0R=8 j? [dvbT|f{\>Y@H{>U- hjPzނo`ih,w{Uu1=: ^ =<=AT(❦NVmW58KKςoߊX(ht$2b\?ZV0 tKَbdcD&>8iWHH} ߯e&]qވad \xRXGFZ4/&."nʸ}h"azA`׹z;MipA8RĒZ0tXs,z;~c"FNÂ4;=XϽ9]98AP82iD;h5?FdLLjvrPvn)nJNg);Ã\0=6| -htH!Ĩ(^,X? D@‹7j 'Yu `ٹZ9>Z; }yf1  9΀H  r&l_^U>`Çz(qivlb789)4;O3?CߣٙH-D*3mo@&]DY=ojS-t ~O ¹B<Jp^-qVz~ދ. c+Mqjx&X#HDcEzwEkP3gbV,wG&._ic`iVp[D#<`dt+"3o՝C๻ 4` bCQbNטW>`Mn@NQVz;j4z1 ]Efqm͍wTL)NHYi[ӊB`?sXÓSLWrU|x4A6:9TVr`~ڇb$\׎"[(F+0#U9,wG' brB2Gڭ9XHӵ$z{[=>;}wW^n/4,Zfgz7B>;=L0z\%LAI Jb)n41/,҄p2M@x@XaOZj6u(˵>HNhRnG~ AEM6PK@Ӏ3* {c+>wr=^y6Օiѱ$6k ߀wa5[Hijun9l+d33>89ُ61So1PJPrk{M)Q5QbvsϹyx 0Av\9{3xxvk .w! gh \Ŋ8SM*(Ctm}_򺶨O2,Ќ~#]5fۜ97?PÜ;:SzC%a(H 6 NiD,aM,z{![DcԊ%;}i'8Pq$޹(\9t>h52 e_k[-R(xzxvk@|w7.~tكÓ QVeQl?nY. [ea''Ue+k~pX;=Iꕮ#?W_*G1xzei7 ]i}+<I"ŭ_=+c';x_YeO@?hz e-6^=ey]{ѩ+cְ(֜Xsvϧ>DW0=~?}++s@6^LW}d@ kK (Q8ISDed>{GtfG7TpZQ{Stc?j_" ;*Q=lw(j&_zآ0y漦Ԏs'EmQ$ӕ0|cܶV(U6L5m1(?J1eH05E6@^AaTU\Zj>08Jji`Z (!nzFqhGkEFWg R%Ƀ}'G(|zrֻU )FxAcf#m:m;o3XQwFA3ZRU͛(jǷQ/G¡ jp3+D0 8tFZ}8Y`vYBb]S/D!`͙5K)a@ire RcC2*"ZZGZ Q\rDԪðݭ{[OMovvg0`Izrph?Aj>۶tV3 tg X1Mӹ\-6C]G,T V 8 @PPpK<پ!j,Mɭ11ŴMR.޺:@ne#9 6utC KiTN-MaOicG ^`}cj0}~HYcG8?2! };CPLeY NDSLY+zW1o[. LRX%TV@335+vbubhx)ɽmdzm3˟ǮVAxlD(6p>헵[GGL_0^;Nuw Nf$$ݩk:^UW U`* 3UQlRH͏R@+s,;΁ )PqvλRۇW}TxBe+V !=IPi()7eפxh׋EB!4Ms@>o(b;xoc tF6 pК3,WqzrljL2C^->8mDKǖؖ`["̲Pl3 3+̪ޠ$$hg֒ox Yw8K8z7dLcmmWI=\FiГY7ZN[Jk;2 x${Rvxdl&Lq0LeP0Ua E.P |'ZU_Q0HP95%+ ֕ ʩv*GWNw}qDcNljy1_빱*y d8 R$ڠJ& X& GI  ~kUkaQ { |%Jqa tFjFQT‹Tx /Nƒ< OJvڥ{Vfz>Β3,~Q;6 N!*%'9рx6.h.l 7΀'>z4\Y+Vq\a`zVcìb2.zn- ɴ ,YnI|斴ֳx`N]&NeYL2,O=q rI Ƥd9t9apx+;>z8QޚS*;'i9t11KV}5 ߰({K1'(iXo'V|3?\{m, Z" چXqaق z',MxϤ'vXi%'W ve藍!{U2:a␇/1&G$`e|}2B 9۵3P"\7^ΌȎ*)PX*I"m ڰ4WڃÞ=9Q+Ә {V.[ l1"c8 )7Dgg]w\Պ>yydUm^˪,ŏ%uN!zt h']M,.ܹa/߄ìFE(`#q -X?b}!]`o_DQ:p -1̏ P ?5 g)pA54ƕ}hd9?U74|:~4NC8WC||9 O}> ?~] {L?>g?7knidO hLF@S#%&@2,2[ҿ't{ Sr>I$|d|2nI暓/l {a?[M1FCQD%&j[ {p. c̆'<)SD-lHimmgFS\O PK oDr4볔|XU}c7?,EY% xw{PJLXFAkcMϨKWYxS.f~sBMefԿXlvۗqc16O}F2ʬc{3*"Oo=\G1htJ/"D61ٛzۑzҟGg>C.-/d/sռ RnO0Z4:lӪ3dNɢ<ɢʫ8cf+k+oec2}OC)?ı Lzd*M쏠?!N&@x`dBMP& T@ *E.X-p~9i[K>Pʇ%S;Μw:F~Pߵ*BJy\ ^]ݗKKNʕ2JoTcN؇Ϡ\އm_t :^=2Ζ %WJAi3aO*%8b)]Wg+ݿ7/"\As <&{:ݼa :Jyin)8 ۈVq3h3@j` B.#Thrjmx ͞@38XHȱ6d牺e.V*0'_fЕ8@y!uG͐(/rpyݥF]4~xKi|8 ڤa"W+lб2&*rORĢ,56j砆|8bKfيY#)-31s=N<uW,^O&e`N~$(089xX,;TfEUҤ ϝqp m"8k[G{1wSE4^n$/X9qU/Dvz|r^g/:Snθ\*0噹i+sVD0A_7^MơUt.8%$ KgI| p':! i.Pr‚|_I /FўΧGQ4CW 0AL #wP΋nc~Y5 _o .$C@G)CpE.U T *>m D4-XQ5쓡Eg*EZ+r9fzaƎT=#sawD1&16vV ]Zr0l/wZ|p&F$& &:؝`u:(_wRc9TF^y(}04ؚi/6ۅ $XK`bf"WFވBHbƺm݂a4RJ@wCo9v(D/-Yr g$D=0*[M (a#,tx)uڼ`o.-jVzh6qI괻@>qS{=Q;wNr(`}ZMʾPzҞ Dž58} 6v!ohRb6A$Ul"1Z̚ËlaHw]L_ %#`螉1UOs`E(> BlB'Yv1^Ȥy +fޔo8ά,OlN6b/^ׄ.iDt(0) u@ rQ68\\@JG 0xE&)> xe~ٯC`m ds- ɟ^63 x@WJ{sv\bv XVdFuݲRL a#+PLOc,#!`z!k<4\8ns~n,gHfAP (l6у}̓ $ֳJm*|TB?zhCvYB@|tB䘴eBr_mٻfDRL,I lVwx,.҄ @>Tq(wאph D."HwksLiYg3˴k~qA,n'~=° 6i* 7drp9Ja2u0RᚼXXC,pժ~)抠xzgbI=t`@ɇ0dgEx,(>Z7J [~?{IiVk?;c< ^@Ǿ8|ry6VVo$??_=7;ۘ8yNmťí^miidG7~Y+,-UJ)Kr'"rw)!>]7J3?^}D'׍0 J?yRY,W,.yw({TH]Č'aLd'f8Y#ʼn)/NHy1~rq,-0W/reVRErJ?| xՋ.@ PPyCf}c^ZGX|./ $>^NJ G%CAEPFn`G'],RZyS+ͰJVPMj7_-WzN d79%Q;,)=Ô3{jI!OLj|taG I5eueR¬LMմ+#L%J̌},s^:/;Y@2.ςHPql o~[i`i=cP>=pse#)2Fv6tmWbsˍ,be]yqEJ[U4j 3%* gƺ+~ z1V6KՒh{ŗ@@5bN{`hc5 P=0fS>v3ŀ5[^ư3@ư6P"l2q<15IG5LurB&jRl2E" 9e MP6b.6g5~0F2 =Ǧ$&uHcZP(ڎbH3 QkLI9V8'+WB^݄=*NaF]c}j|xm6m[nkj| Ͱ3JJi/qq7)&D<\o~m\#[d/|StՎ}c 9P!4r YZC͐EQMK T^)a=) od39)# iҔadl%6 PB9P IkeHke6ݔ{4Q%49RA++?a?6lrSW .1vVf1wY8mKGhc@l<|fq|Ѽ|Іt&˳ҿFE%FlkӼ{idbw?Ɍ^@+SNpMD{ݐ`_̫3)^?P&;2{xlSɶ;GҀzܵX_=gkk %Wn &y &l51"l4';-Xγf/vWEսA<Eʆx(/{~]'CLw5 D,ZM2Gl^P,?π?N*~qDyَ1 CXW_7K܏I2ImTYI$d&iP%Yz- 4vS2ȯZ#K%\v#](5?y=V@fG_l9]̀aP+)]]0b<]Y16?$#0s.D#4Ҳgbtp*|"u֥A%n靋:ݡMO1 4#ZM z=X2۹@k^y^AAQ$(ivG4TMN_zpÉE2t&p/1!0HF`8@qѝl׮g=ZF8>,& H}"G$2 ᇜ?^ໞ?ׇho`oC'l9&+ ^fStXmsZm^cy !8dSǚntQTs]uhe xC [`ʰEjnM,%~CBH@~G^0ΪJ Ri5y5k}_PxгsIqLdARV L3ea%TX]l'1R@92Waa)Z=DQ #kK>ZBaX}2ƥ _4d)ȃ,={Gd^$5 CWRGO_)o(N}r<9fjq+"3ƮޛSJU|VI}2nlm+SoVL:pϽ2c?, բCΡmk <9h3(~@$2?T!pTQ㫝g*2t{HES?iFe~DLzh9=L+ {Z  HELuE ZdJz.?>Nma`<~0c2+zcXbTˑʦ,f/j076M `dnٚc0.Ȥuyh(-8&d1#u+P ޳8I6 0,ҟaL{e% j^dvr|Gt00 W"pҫEc/A߭!?,0!_>@W1~u> 8Pxw>CY "!,eg/: %ů",0@Hlj1ڴFذ&R|0rKd*bRjIQTV 9%#/fox|"kIkqEJ&B+K"uql)Uop%dme쭡hb6=26IzH:3$" 7`ەyÚO e ߏLe7NCY#x&=)h~H>JJ:%/c)('3N萣֤_FC( >SڮXڹJ.yp`]+5Uΰ!1 YxۇtӲZ,RjHj;Dx}%psϒb).Hڈx{\Vdְ 7+|mHǑ}J:Ի/u /}rS 8FzeyZ^[[=ħ_dܪ򼪂?[UUMݪ&V%k + kr5r7KۜOhBKbou__XqI4|P^2t;-/CD?8wZ% tނi ץ'wwKbmyZ VSeY{pi2W#©]9_*HB= <{`ବ1ZFLbM<i7mp^K @Fut"z]Z.N=KJ_( Q &2b`;u$-wˠ]bƛD:FtQWEJIR~tfNe<7klӯf_p,v$hP:oQp'hTg|x$ibB͹d~M%ˇLĦc5'w%DP!a8WbZMd+72~ f]h?)“{XzrLKXf-oJv҈jɃO7YlqJv҈l[k%IM97> xEʶLR}$9B3Й_3[.& tg5INxlV¢(^ȱ}ٽLKtɽ]tǫ>uyJ\^581GtxTU F7%:f`E{*ld@oAf]S߬BqVla7NX'o6Ҕ[_#dO=cnޖScMn`Sxt'MKBGqhF Mf@pnؚO/^$\MM&;9ځ-f;`ᮘh}T_]PËS=b5VsУw\ݡ:P}<y¬fv|Z4V 8># hh7x>&6eG~Gq7흩C(ø@oMGY]3J717"<3;a9&[`R@C{']xcqwyy5ρ^ ܷg8[;6#{;֔y`x]Gf~h9Ad2I V*{A\jϩ߈`7K\_U \dIYH;΍_\4As WE ] g,b0W'GG.޺2xNfAa"SeX3:[Tao*= =8EK Wt+ LhC,@t߬jr-nT`8^P+_Fzf r'8.czrz|Zbgmnm1b:'2x`nW;Πՠ[(H#lDZzQ L!Azo*P]lݩ"]HuMh@KG:5U'wʂ2[d"X;fu=)1jdڡȸhv8G__reDm~Ҭ?;{oǑ?Bveeu}ÉVT6fpjJKK[ .-#R$9A{EUʝޥ&_CeqI )IV:Hji$zב Y'y>FȋzS ҧX8(=va=B~츭A A=boD&U>x,\}`\B//z'?t[vV6Шz"лUa#XlHyHf J+m Sx>Ud'49D>FbQ&V-!Z$ (d:@$WilvT!HSm /TVH;LHՒ~% pQЋ]KBS ?J P HY|9b MWaB7\^ J&cU@iY>%{<4(i&6G]%zRhoebRY]^qkS Wffտ,0R>#fy`fGGOdx~:= ˍG/.8#)72h—PO_E} U _aաf>|?NJZ n! t bآkkR"H-i8X) iN 4C{&at$_|67!ZtЬakC#}hIeka|x/<ۏ.9CʊMEIa%_b]Jw)7QPd?;q)Nbe2}+Cڏzvޘ%uQ1Źym7@e ]Zrb]Ѥ9 0OnȻYx,oN4 4 4 D(t>@T;B@; 6Ν bÖ7Z< oK`aw/2RtՍ r<(<Rv {z•iX줋!D!jQ谘! Δf2-ͬYQ(T 4*yjew['] fS/RdV*d RBq`y]Gb* n,`E,JdƙP ʱ$yOPw_}0;TܩaPvr*66.SvtK ؍*zk ffIJ0qRvy{S=AU>ue WԣP&Eu%S,p.!"av"z}bxbH鉢 c{)*x`NѰH8a͢,zG@b"y >c*ZHT@7(cͰE` co^Trs#ߏ3'6|P+R) a &v]u 1 *Č;Q[OL36Ҁ3\I|PkX=xʌhP&L@YJIgt7yQԤhmG f5x-r"!JYiBR@h'fiE9'g>< Eӫ3sDDa8XHiBb] )*U )iP:<:w]Ic^T`&; &@`:tѱ"=Swz0KaIQi o3~qN z®4T|*$RD"TDزf+0B2{ii:g :ĝq|߅qo0Xk1选 "ksx 98qtXA"D(8f+̶QTe$Qd"k )b\)ʃ5 fPAl uUĬiHp#L%Ȥ)iN8qaDmrD/ )5i)Ap0 upw8"q,wX`$6cjqb-&PrUXE%$nQH?(E(nD![ w[%2ne& BҚ2 c)'{難'y7 dvPmiӼ̂+~.8FH+3I+x3VU7A>_ywU(`_]ޣ&€=}Dmg1€竏825^ kFZR8]+,/JK }dbv/)>Y~(\F dEJ6.׶/N8":{X|j&1^9[ 1` ̹T6&Sb/5^*S ԉ$Vt;uz+{`=AiG*t@wAjGRCôG=T(rL3"[3(rJJѬKy@t|& ){6H)^#:E/Qo֍%HT˒E/ٳ$!jZ iwp]g4Թ90lL,s!1|-?SԂ_>8;Eca}V ,Zfob]Wa쪲-XOYa+xE6ov$ b潅Ga뛕Bɵ:o-~fE`g,x@J};2L?اC`XLφ.- sx,GWo C[ 6)fãLHq(ҩǰxtČpTd<'bO523߾5\ؔ&L[F;llٟ &l0ea](n\`rF-J4f6tEfD*-ɽ4pj=p3茎qޣ(Sc?2|,!ccmu0>zf0ɜɂZԝuFB余Tgh1C#T4_6z4 7f09C%1f۰#qǴ~MX81gU8l1<;V;f9-(&vۣTʼӨh\)j'c}K_Wl啩C|8444c̏||9Bz0-RMuߠEiI/>h?ǫX<qx F տ$|SIyhRmhݲB~o\/ߝ+}xgEvǂ%")d[NeEþ%T}6& (kl$Hi.],Ocd0Gչ؊nVQَX{G#R܁?>,;k Fd4ʭ~\4bfU.aՇ6UԑB̩$z1c#Rp(gO;h~^}̐ xS9f"ם$iТ6,߹p3g8`͉9SQĤl(bvВD]-Ak8(6|eØ(K^p+gyh|չm, X>k1ŏãÝٻq( O) ]*I``Iq׳*ǭNFVIwx(w hfkl ayT6R+jB3,9&2I S~aY#%aq}x%=+ܴi!60CԤ";Oqѥ x⃥09^,D. 6@6Z'4HΏoYý"ɇZX!rI+ iԇ} IXR** |;MJ2%ln{1y!lL]O"S=і)ctYkv`l\!g@=ܷ*&͘#;5tbo7vͷ\ L,h tP+qX(WGԈ%'ʿVD^h.ofNFgB{zhB`d}]~y\55#2[ʚg$a6'5!|xyK kohZC~y2ju6dc&@S7 !f^l*l;B6q5נ))6ORb-;Յl$V<әFTIZZbζ-X?Ei &RXT;nTw;DmUk{m^xx}Eh:w-C-Mt9ėXL(Mxش:x݈Ę)on)nWY`$ ̧oG}hy\#ƕD!>z%;(Ci5U$IhW~u74|?*?UU̟L~>FN<eT0![^#-ԛҙ;4Y<}TY<D'ؿG$8g I^Zp>w5>DɳtV`k2O#YVDV&>NV"f9_{t͗e{:mxk{>Y(-;&?+*a(s{:E0]H#ȫfM.b`H;o6$=F2'bB$`ɬ:IJN4\Mh(L%7Irf+#YyGY( %0Uf$%lC)=Z6MO_P~vQ_]TԛsZQedr ouȔUWJ\[,B\j1TL1Rɦfg%.1|MLд0ƶ]ݤ3 fw )<Zvb"^0d -(dc(ɶ4Ԭ`x9ܨa1Rl!ZNrI2pKQƊa&`e.a';@Qx$E@өՒoRgίZ ܹHWKSY%`29ZEn6cd n3̜)b9VV_??ʩYך(i?d̳PvF=#%t dKp :I9; tmR 7E9JRچhJS_3MY6DQȗAIX~.>3Sm:%쟛23zf]K ޴2@x>Wr}~VNV$%sƉ#S]e+97x-vbNfk4}c=l[6a~#l;N_lLmu@[ggd[V)&œ`efD;PV\iflVZ|Ҥ!`H{abpxʣ4,$#!6WLm< 08l\0qI5%Ec!Crx7΁fl,l]tכ0\"ICt/T=cLYWPZ}KaYmw:IqӨô5 w+vs&<7`)b9hZ|}jiii/5f_[н1%2jb*.pk?ƹrsE$Zg!G$g4HE>c;\|G:!x<@nY.:pf,8]Ķ67$Ҹ ,Yh8b_u󿬬O:*9_3L?)J =;DOX`PG_,l:"WE'{l.W('&HƏ*3<Mwj9dS2WJF(BYcZoB2ub+!a~cU'f*,kV&~d=t"OqՋjɅj)(x7Q3=X2jrM*ep*ѣUjA.{ylL Ǜtc$|eZPOOnm=KZ}R,3/i}0aӄiLpBu/)xc<*8" wPˑA # N 0,%<+u]bi'{<#КV.8v(@ăX-+;=0?Ɓ͹'6M3::'jꕧq`ǁ5 e̻̕/"Ԫu11PoP{D*}";Ԅ@ngo;L t707c^yCXm*1a+=S56Gvo%mlL= |>/YWqvHpW gcW'KC?]H/E X,dFyFn@* [MW${,~Yk7X8Hp[lg vGM/)8TE^Q(C^(rK ;"]݈6?D#~.Fp;=9 | ~轸 *; ϟ?TQ %Iזpc?VxzH/-Tmt#-@twd%nY ;e(,E:,,u(7"Z3fUԉʵWV $.]O he#:~x w? 0.`mHX(QuGs1)с-[|%״ opZiNߨ%3]B>Ʃg%%+^PØ0v2L`Pm$g7oȓ܁ cHZ'!f*Ue1)j. Pfo4Ft.J/70.Cђ w Dj'*ڀn8 HubR+6cW/D)lK3٭ҝ0p Tp\+yBLA o7W(Q#PФ=5{)&a<I+f /!O:X8}+6УW?ӓY^x_2Z`ğ(bao2[pG$QbF=ሇAiA(N=U̻WGs FJtWwj] SlIF0wh, #%\bԦ!eps#%1 [#֞ӱV1JX.ZPKm{-9j$Rm/zIJt i1z!Tl@{3Z?95Ta?gˁx8qFPA !(0+:z$04M64c?$ ۖOƎɏ$*ΘH0}-aȭMFY -Nأ+ժG<(Q uKަY`?.0]6ƞ9azyJsXGPQ$oi󪘔Uk{wo_txB-*z'b0LR$lqv0Mѷ&Hݞ{mmpkP|rɦi*bJO2jfv,B @ST,~ڕ,CΙDr m s/:Gq%X,:{]E;AɕaڋWdI$n,}hJ̖8XlraG)n $WA)EeK em$ò7&5c4r+y p#>br&t<heɌ`kpi1mc0i .G'^Q0h_ OY,9VfAhqCyIJM}krmvEC,}JWIg`ac'-ȳb Ԍf+"ژd/c\&[0vi 1hFc4`G4YnŽ{!b +zq82ܫ 0(ۄaTiπϜP" \EfhL%G- Y4lAvK6!'ar#\7ponnp/tWA%fy& cqٶg@4_RwJi# / {@7&Jgt"0>(O -Cq,d.?ոF2J"uQC\d[ %6*s EJhΙ0OȈݬٝvz=̋1yf|a /~x:rU¸^R&fսa|W7#m_exm+@IOmQ8 ک|a8OIxxRsٮi&t 1> h50l@fL{,.^] #RG, xAQ咭CN^QCzjL:k+jdY(qW^,;# /&V?UqIq'NC:/Zz񛬮͉I[썧sU7Sc7V>4 񫚺U}YL9wtȠ2/T oB(@ fGp::OCJbf#3lr3q&*F&ެ o2g: Pmi6XAM(.q32[ׄJ PvC Ɔ'}Zyd[Nfw~3Y|ڣG[SWzQ;D&&wRC›B›mR?ٕ~Nq|lWS&(]#kEDV>ro%X5\%߽4ZIo4h$ܛpxr <m&XIԿ19\].)_fWWֻ&ݺ\dqvr1:[۾^xlRx=E|ɛ$8<8sq cgA~9hN0۟z" M{dv/f3E 5Qxv~4'4h14yR)'_"7Gs ;s Iy`ЖА} xɞ"}Ԃ݆NFk[eZG$kmlp-|Ml Dk̡i4)jb8> B!-8]{]E> >M&u.I0VmAyW5/d >JRj#{zy{,(>BzaSѵPX廿&Y@ZVN"5g:IH;M]t\eY3 \`gpT_9>Jw;I0Nz-^ 0.B`3lI1@1"Tۭ8MRF? Dya˧ ƒF3|3C&/^oŠ5v>{h}}'H^0Pv6pBh@ڭ5Mô/)YR2Y$@lOet$Rfg^,&+ܠ"&Iڍ(i`5a')xFPh@_ԍL 1voi_]O:X) Lf;)Tcb"ɠb93v:v'"eݧٴCJHBKz]G6Н`/4! 8o(x7d.qO]-mɗvҀֲv:)YqL^ zKx7- %32F'ěò22m e5£XpӨqS|JK.Gܬ6x?MX|Yh-r)o%,jQ{cm6>G{NntśW筕ս9;4&>}Zi+]ŕR~Wy9l~74:5ќ37\:Nף_Olip 'w\F < mÒy׳Uz4+2^ <.*g$[M0CLnJ HvQF\x*}u?x8|}yd4z*jz9#X/j9r[{'fVDTsdezYXtdYv*-QTVfd9}0r煲#**.i^J y;C"h3;hˌ`| h_ޫ0Hog.~&Bhk6e$b tȌo|sӽ6Uϓm B=B+!31ŝ9Xg5O5r;CrC[ ;=J+At;lnjlQ=32<('j;ֶժm Gۛ^EnټnJF7MFB&,GCYVf{+Q:;󄗤J%)M.,{_s^Э0̈́F򺒧9w&yPHI(OT3|fNs|vq.0{=-dU!Hva,xL :a=Gx%*T `RF* VPˮ+u=W`w$'J6՗aX06a:ۢayDXPt'Tpk瑣}&3kԤKOVkaV)2fGr g-J@wsTWL vVpT\=+؛;B=0$G N ΦyS .r6%><' sRH!q=ds;bs]%H)ϧ%_l>-RO(-8ED*HYRN`oN9θ&MZ^}M]\9.2'd'c*m߉" <-TTDVqpv*; ":e@a_wܩ]ɓܩ+9;;Ib۔K];N<5JY22[ mtUE*q{bW#Gv|M/?Grqԉ5dy(BA hg$g#r)тPɁsgI%@~VO:IB.Aۓz++u _3Uƽ7F ЪBWVꌤ3Oh*p"C_uMnD92^ϥ/^Ø)>y;X?HBPU8WItNFϭ́ă^ ,R-FNqƿQ;EJ$hN^itl6n&s!wsU(bs!zz|^6 ӏgQ27Im0',,SC"<&foaRd I؀n5/f3cO-=I(0tJ5ciKцwGj R@$gxMǮmMdf n6dIM%[a`&5(H›_&z -S]mh(I(s ßd[&vK:s1; 2 ;sjI%Ch%tuf JPD)(<)/Ȣցu)K;idAL+A%B oPgmAZgJw)@ Bp* Rٻ8{v?FܘjwBdn)~ULY0S'g|;~՘~qp7B zkmo5'wG~r2ZbEO"R9eۘaso64`?gw4~Dj!sjiʭ8e֠5eU1,Mݮ83`H&K^¸^jkTT/ /*mb'ˊӄ,٤6VjvԘG'Fp329gKEQbYl"*0͜U1ZBwЭy{6b:<8[Fl1 |cs]#Hd5'<,MR& q7&|6c1hX\f*:/ZpבJbe~7;6n~nұ :,B! BPRCP8 5x@o2$#! Bp DDJP) ?DF wG@L??x>O0>9O C =]]mPn%X%\5uM^k۸;O0ɇ'ѠgWsoSv᫽hn3O%Ituݿyt~++n]|9D;FxpI t`ܬS/|l$tSy6Z$jLÞs/N~=8<: CUaoY{OG&~4z4 ޓhKbe4*#_X?/e`:uG3Wt@5Hor-țٱnllr7?7ܻ{ *<9:0pr/{M4IBIy~zFYu iؗXP)Y9>ȦVӊ17i_Nso)D J(b4 Hz_%)؆YBR!6N6j@cxx&|unLR/wPtoæݚ-.S8s>s]j~k j нd;М!j$ իct_w$NտѺ4& zI^ `dΈp᥃Bq1.(iR#B]o#{zNδG!.?4r/eVr+a}tb#oHLhA'n]m5` XANbICzkB^З`j}h{۽bV ;z8{za - -:C@sE%ӣԇe"uVWeRܿz~Q53EJL$Kh6+zn֬UM+}[]hr٥[!3Jp?%DLǸզk %62 ,MO^ͱ:H'gwV&E5L: FE^Q~ m׎Hvl"zū^Wr)X68`7uxׁJzKAf!Ʀ.ͅڦ#|,sq&B zq[ӫ{$DwH wD_zOsZNЗ0+)LBMoii#_hs{ۍ9^2#-gAQ9]ԜjVB';LUf̡Fy*XYQ`8`LLТ# +^9g(vM^jΈ}C6{ZX(a A̼y3WZNXmZC9Zc-23tvgu;̺ ~(l#V#DUX-aa+0i MH=X, 0s 1H,PĆ kZ"eK:) ozD6Ȑ݉~kr7Z-[vrwpA{o|:TPy܎:-Zyqi~|7K;h}B(o!hϥi^ÈX>gXkO_{Spk)mAjQ`?ʧ]$ͪ?YuUOͪ'cVXUsTgWI!9Be[Հ)ysa&!.x~@<Fr02HmؘOtD<7svfFxЪZ٢羽lFsr9ݴS.`0Rd$H]6 J/ !Р",:MM+lcM+lQ]8)7ʺ$Zy^DlAwh]b*UR3j/[tXdKro-~:f%Weӧhp1;m㹩N2Sxr+y@d(릑"suGbWGv],NyߚD* !FJGKEc1Qhdq [2} ٻFfvɥ3 rrNEqv1r|uAK~* ]35>"Of\{,rW!O([cVyS,!:vcCi{ΚMz!?xIˤ1RE3KTRXN;e,+W)g=\^.W&˜uī`XAUqm-weS!>O* C,+eNE2SkV}?3Qװ9.s^ s>߂!]qwkLpN.+dچZv^$^,0skxjy>d_]?̶fxm=А /zU/e^=g~IdzmZ NV9yĄ ^YU1Z\ o9iX bT^T:]סSڢ[B% 6H_u2 ss38&G}JI= TEmI!(&FuQ?!$<s10 c2ፊil{*WV.QNvlF&Tx{@g2F yXrH $X; Y`)Ot'R2h5c^DǡZu’lx-;W&~t H"FE,#G]wu](ƘATS-`F]UI~,s Ug2s"e3>4 d(#2r{[ Y#*oQ.$f<ѰPnkl^CPPk bnϙd b9uZ4'q?Zxhoq8WPuq xRtݫ##Z||-B_Ԯܣ$AdU@^:!Ct:! nJ;9[ndB/(P!E :RY Ov`4jo-tD*N>w2M?7*_hXڞn3f~J<.OYK4~O|WTVEls EkC4$rtav~x@=+6NB7FF+n2S]$ JsEJEXt(W_l,±bF0TwH#5s5,iPF{! 騽e|]Ljl#f! 3?EchFh"<4ݛ3QFx֚{BU!uᕗИ8ӺJ.# @1gA,1kVtn-E &0.4]dt9νk9d^8 j_и+s]sG&歒ͺc$]S*.݌$ZL^9bv/ߡw_c1͈gteY֜;RWcD'ÙldaIS|4<͕dڍ9nj^\y)"\W٩>_SW̼xJ٨?kG.v?o=F~jUת_qgNc?W<r9W\n6jgG'W\ݔZ24߆NJh=[ cT^LR ˻Ray+ܭsCsq.uZp}*37Rl6 _ωT5/h\uF9ycͬh` 뚶8&p/[~>݋<[/kT2w_yk&N88nv'Ǻ-+̭Ż-~=@>O/L/L$4THuWu, hz)ykI֏6+ XYfc=Rt;iGUXa^Kzj|&׀B } }MXRjε'R>}8Sl.Cj}U9hj`7m|m/V0Z2`'{/~[}5c a|?r |x'^Aӊn~V%>{:IM9C>W+++ 9Ծae<>Հ m3ա6^) K7<^eA+>9>)V 2O 4@쁁12!*b^b 33iWCWu}b!@} O?H}(]xn2GdԃnmVVҦ5gԥ\N(up8O"fWM>щ#3 39^<7E!Qp6S6SW&]KTPBc2.A@碯H8R_L?9YN|TXaٰ4KU7QbTx0AB(+[K)4 =&*3I)ljiA<d FRUU$ BI54T}p24{ _%qUM<jR#DQPZ2t.{{x/2$5z#Xč"@,K 4PQyHۡJ 9SV a2jz! ۏ7LMMMUƉgu'p!!)e1*'X`Hk0T%_0)Ҭg)>cIh, @y oQ5=7;ΐ "(qÐu%@AJHҽ|~voaM~W?꧈ JXE?Ok%V--Jy(@+ڊ*QB7V@@)weϧøsOےEgam5=ʀ !/ʔw벌6fͅY qfD4JUoe6J\vs Pm `y#CY] d ^OvAe\ 0$E.B_eW4A ]̬^`Q џDW^Q愮}(͛0ҨFw[49xgYydY\-Y(˸JJȌX6u:YWVZ)!*Z'?Wwpt>af\`bóM `TU0V܀ G@T/ Ev_/dƦGL?N?N??Z7B@溅ɰ[BT(ESh7:O3~Gj>VȠʅ. +gmM6!ߒw>gq!G/3иўbL0|\x!'U6o澆KčTj8e}l(^('d\9k3U݋(nP\ʭn6Uqj>Vjv}om),ga̺c7iŷU tN޿[2;t,0pu_]X2 |^Icݘ@@ie_3plc`_Yg(A]6֯% O@S?$mx{>T#ݹovktﬨ6n~WD'eU` VMSI7acR=΋?-Z4ܓ⭳<^% }zN>&hJ+M*&x`!ˤF~$:F$J$IWd?܏ `%FzT#-nxt]ƵKKthW})t'#>ȋY|-c05&tXOj@"rK2ξe%dxV]qǔjVѢ"P]$*=e >$خ| ڶ0v%\S'V`D=^uիcp>1rBw JCmO `ې8gdvf@^%<$nyEFEۈNUx9ߊo BHMG)4XB5oM#+\"Wbp*l"k›4)4t ho*rYHkݔ:c0t6>rZ+k037a~Xύa]Pe3΂yf̑Ǜl5WBFh\dg 7ΑJͽ_8T>}MLF%6<d vcj1jx"BDtᐌONhP}M"xy45%IZ0IgHh"1SRŅFqFojUdwoP53,og'^;9PכBK[ <(݊Y/G{/O^RAeVkHGko8÷QCk acn"Wz6ue#!>oVp|\Xhdk&@b"E,Z$ISfK(Y{w &hV`>{}NBZD+}˽nFVoQΧ09^ }Ɛq)sW/mlHQGo=dsvpl@> *ecT;Eͭ8QP6]xE8KQ_Z-6xC3NQ!.vJZʁraMc!UlR K_|ȶVZضZ+E{Bv5uUX"diitmAWDf`Yq ÜKeUTNLNXɾgێ9CXTbZ eןȱ14,2@Po~V3B PxM6aˤya&;X@T=K7p|r %9[Q- -xPcΩ5I-‡Ppr٪~% |]P e³,B@fbu rKԟؒ=ӎ)4?cc&Z'ȰbfτbOcB}=VͧJ?ZkvdFLaw96_S`=ޜgccϗY?JgwBd`R"qm0ҒΟ!;R_S"G^D&Tk(.ukkBwAIʱ[#Sʲ e>#\LelK)Y`ta+`2y_>+iyGWz8.csMwlGXujUqbS[lVA33}-b+4ڴ0Ԝs-8֛5ެ֌6oWYcM]!q TT B$M8f4}ʞv/)%Cv$k[cxj{iiiO1߯+ O'{LJ1!tpf>>~+k48 yn[sq){lbi ۏEw.ԇJ+7J/Z$/VW\CNSpFA|oD =7P[|˓&. ;7< @gPۣ% d u@c#;6d^v]>ڝ.b Rҧo{^y)8ӱ$=w{ {qO0ewO~U/O=qw@ D PnT;8<|W4(w*!zl[sݜ#dm'iH̪37&5+{۰hϐѡ?FpuSV>SG_m8$$Wz3#Q!d~-?R~ʧ֊CQkؕ8+V<31po ٔk=:03` Q;^L5:ʚh|ʜ aގ/y/М#9e@[+yiᎉMB =+slDb "~ c s#6(0#cQ.B-$ޘd 19pmdkjE|J3eq|hh(Q e72Xz0|(7VmjhDO)ܩqR^0aY;!׎k6 2O^Ts }JW]x[Xߞo366fl peeنb2~"-_+\CA*LMcq􈢸7h4 zJB, Ɗd3?rFV> PZ=`U_Wُz5wAYu3:e/e)BR Y$4fHMun+6*p-ugǧ\JGpR+w֛Ngr젥7[S9ֱr U\"f ^ U$*Q&eǥcژؕRU8bԿ^} -8?t8__^͵6>S~Iu>z^GJ_dx{^O2d/V|Ñńؠ/[XεQeZKKN3:VX6ɈkjoT|U1rQw;'%e44kD5L9(W-4cqX^s;[w E7j714V5{CIՉ+n(ʪ ijU$m¯_\dkEy,i採p0GS\DJA=h2J= qC!qvO^ﻨ1L b^# ESk9Ũb nue#b6dn7oOJdSOlF_>8.s>gȕ Bs9ӄmf\.أlU( MKQ^P|YeW놏$=P"H(bHp)ubdnQI!DB>A:ZiR"g @FƢ̏"WP xHDݲ61\\4*fvr~-1? ?^GSm|SǟCQe?pGᾸ{ܜ|Xۥr)GMGK-|Br.t輝T9tG64$ǹ)K֜I+ JSOrpHp*y@nkXjG% K)\c40ֶ=X/&2!{Ԟ/ÍGr즔>Em=R%KY+xc=O??ֶǛ[Sm|SGuSt)2XIWF^`7}7 g: t{{}O Kdp@  plH/D`.@3yDiЙmx&s#za_ ;+s|Nߕ,,Wr}t'F8bJxI X<2R%y d4gfrlh,iTQni>_n'v4NV^1HbLNN~ T^"@,ݸݻRzE"VrQYOQ S~.4㤃z&h:}8_':CUα$rQC ZtNƟF%@7LȔ"TE^jdlWEp&b܏谋C@1ZUU%("4%04j^k:6@\a5H1M,"袜..\ e=zA6 )ǃZxCўbgˌUqpXήَL.ZU8O^gĢD,<|G‘0OY,lnYҾfHt0]Y0Glַz{9QeFݴu㠛(ZB;_BjN;!injٽ* xt;DZФu4QN)q)fTr7&-Ar3L H[}J5{ +br\XҁՕ,tᐌIONkb_5fO}D$ .7ptANbx:  V8|a)KL]1`{8WJȫz 2!l^vp$ uzNUg6gֳS+8>~.Nf$&+I#i}Lb4sD;v׻oqt0hǗ){ữđ^׍,sn!oƵ| >eOu76>Sj~_qÙ|b~L0S~x/ߛҹ!еD< 8 xգ @ 8rV0s` VO$8V$[-87ŷ<9'J43?yg[OXzǫj:Yًvf+w= w(1eWFHBU N^Uާt^ l~x^[lсWydOKuyFHBX`-, C"QМ(lM${ʳp5|eV 3 8%pN>޽|^ %E#{Gm#UrmkB,ې}Y՚9jPU-DXG{w!42ige Ji-2{ Ӥ˫+ (^U_#F`F)X%Bі嚅" { DU~mYQwf0gDHS|¶K`VVj>؟ȱhdlصe,حqgkY}A6Tt^tc9*S9#`.w  :ǎJz (~&Sϖwl6sԉ+reN[q鹗a=%\PZ f³LB@Zh 9bUOnCixTe֟ `2g62'YKvFX\Y8ߊҟYgu\Jj'5״/lNo%lqbokkk۵[4q+iii?]W6~- Be v1h m&LQ G{a4ZO:%BԺYAjhpUvaVRW .ltU05 tmRRB\ۯ˹;%)mC2,;3r?(ɵ*-ոvd5s&'} ޴μM},6M#ŶPUu؜Rsq:xeM>KU?x)IK*7&wNsZ_pιYu>4:1\uD-s޳F~6ϋMƠ ͜L$:ʛp%5MgNtrT5imafYq gZmm(oi" lEeTBXfr0*䩬}RfqT>6sҳ=oǔM¦mi8d< i_ɒs+2%kVIbY1A{cK."ܹ2r( wd*i7&V..rL0e5>v '\I ?S Jr7*  z_Kʠ"KbyDsɦ.Pїv(/醀swHr1=j@("h. d$x  bID%ͿCzlMrẍ́u8_ ex0@ J-:*!0{;G}xǸ=JDi2\s?kiQaKLqmOm|cՂov<G(D-\#VF<2lc$+06J}ƧbS :F%Ƅ=yh\U9}זI1iEɻIDsĞ^Ґ[,ORjr]6wĢl-ɠ%e]'V*ޡy16qd#ɩkRE1ETPYl"I 6 z&`5".a: LrtL-n6TKa/j% vů#+^:q(wBtd5wdjҴ',3)0 |0ny,,su[2O~N8IwYw$Ty ̍ԼߓĴ5zhfgIbk+^6r& ;[ V0dJjIc6tvhRL3ݿO2^r⿬m|ߦߦߦjKpL5.?󳨅㪙2on&Z0>tjSM˴ݍEd-:!zKtj'aE;(LuZKNN0 _^S˾{0k^陛O4zn\%w8Xd]ڬM+ʡբ;aY!ۖbUF|`%VUnBL3̺̈́JgO>W^vuLLި XAURVbJ曍 GZ_+/Ǥ*,+?71cX (aV#YJe*“/Tښom6>OOO3`_W(71%%Ҳ OFdkefj ff:ͭL r2  #Mm2uRͼPOx&s/ %3(DcxS"G4ߜ^gG Rue7i^2E &R!-zqrEq%4kun.tnaVE6L~!הT,̚ yĻh PH aaռ#м!#:xhTcM5U$^G0ZǘǑ)pƐl*.=ix`Ii0BRJD7/M)({UBukOM )L)Yac`1Sk x+0p^;;uY7yosA1qt}vZ# 2JaMCk#xStYCWZDjE#D5bTg袋_\[SM7XwXwfe/IY fNP\*V}z{V/ӮζDV&Ju9\&Y$qPTrqt$Saa(I{A ΀>ZЀΡ7Rhyil͚kG3ڰh 1RdУՠ7r :T60ՅSOX N (L<+OBwKCG}SċvU`x$}=ye "yZ+u@lň DŨDGҚK%ܘS`w -[fFm]\g).7mBRDA :ƺا@1h-7Ş.LYrʕhBG 0(V*_$T0d=#!T"N  _#N_"WTo_y1ejY}>3%q]ň`BAs8Bfng8#JBD gEw qQ>|g*t7 ^nSu/в)nM64x?oI~axXgѻ"yU !Md LOOO@%p  se~'}/gF sI$RE-&eOm&G"UYQ5ҨPxsM{ ւT~hpdTTk $7ap_R88%nU`~&z2-OU1k3V~PxIԲrgߺH1MT&Yo/ :mXc6E*2%#.m xVl@$ݻ{W/ %H b:NJA5, ٚ >ٕhȤI4%k|) a!]1X(JC}^"(pB)2(Z9e[!XT%ֽ I0w3J se624˧9l700ЛfzhWU%9RjrA7HP&-LDzNdOlTD9(l/yNQTa2!Xp؉2XDu˚Y6-ZDĚ{.yuc"%ՠՋ%d*G> Ls^ƛS hpYس):=-7*H\ '&GvOoo\ ;P;E:^cŴsWىIV̘tش(04 ʳ;1 Q{sa*oxlQך-/س̷i֖Ҭf HG7?>,[qa ~3zK%Fqe 󫷎  T2RL^ܙ\1^&%\Auދepvx=$qjNUoh$Vvn2`YWD vP0b5\\,.g⃞\Nt02vwΒ.+;e0߬жh < QIjeLoM*դlJuިA W7+wq6P띐׾Tyy"1urDZ-`Deh,aX#m]+w+J;- isAa)XEB1d$Uau;PP<3:NW '&jXXm?Yl[J8ҿztc3>G{7l g~o?| ? {3]Nav pv<~owwvعv*>O0n qDs {mzvn 샙˸J;Y k#.ⰔQB'n xz:NϨ$Xmy=ku)q{1hʪ]JMjR9mhED6ʡ6LF:eB&HeV&ԜU6oʙʀsw_SSeڣyH}RFt&ZVFFV#FFL]YvlyMZMjZ C͘J`5n>,fW Y&˳Y-zYMHspf([F-l$tѵ۱TOUq*Rinvͫl[W:30uUWW:|% liF2%g`f 1Vݻ3Z(*@f'7NGn%<-j#M5%:)Pf-͔Z| p"Zhf,؄(!5Vs.P{.؄qY]/׻ W>uȣFr7tX| eVmĢ]l,f^VHn` pשzfO'h-É_cvߏecxD&0_;w'o3Sܘ$S/ I `c^'^5{;^%eVǛk.1Y]{2yRe A)DԇE|_XID|M*d/Nj/H8шXD)(I[&.'Ş艱'P. cv/g p1y-zOlP~dW:pG񀢢$h.ri2/Q#58N Ywb(6qN4q2*xbGoNf8;dVr6\rI1 ;vUYVN=I:>Yf7?Kh{q3Zq#*{+h]\kJF&x'FA[M4, Oi c8]"$ ҫ62> Mтa)z`_S?iCFq0&5 .qdE5(Z wnCɞ\!SDAϓ$ՕEGxvw <+\3z݇CK8&@^1 ѲnC \3`u pd߶"CdA[j[M`4+ No([L0Fxi}Lxg^jaX); _s rqm'FC14)* C8 h d.._t(n m/l6̚wV{(Å8;3C+%/2zSsDxETeI؅5KEF J1xJU.!2XIfm҉eU<"1DCc^bSϊ,f2Ɣ] E8O;`k¯Xt E9^X*| &~|Wƈ.%8@dc:¡+S6yhO- )?Hf$D@E~g3YCkF%AbT |ˡIaȗC42M |EhScxrɘN[(5(A2aeq? 6kIk `6S2.|nᖙp]"Draeb1l,a/-J*<+Ӡ4k4W*{QTwJt0,E+"9k`6 ?[sV>yJWST3xbY* zzPSD00b̌tF.TȷV"UjK`ZP0P{,.f˒Xy8 i{+(qYO`!=Poo=vi[L?op'v m_,ZO4߽G):Dib4?M4{KG>,V'ڍ;}Ѿlʽ?!fQ7H&=ְVi9UR/u&Qﳎ@3sv}6zvf]!_o~t/=D1Iwv(Bu?Ե]θ^߶ޯo67س/4)6d8U"i4GkK|Axsxxb?KY'0o_0rw|j0u8t'+p{>ީ0iIM o?jB`zfO?;uHp&Qz_i;Mf]uˠQWѱ@ .zA(_*%g&}%>Dbg2|[`-Y\YthA3֝n :L>гUTCFS/{eG_sw5v5>?9{w@k؎f# o_[@ſU2rK.Q( o߈%9<𮆽n{~}Ank%k;[/~-[>ZޢHݣ#k-_|hPޡީ_J0h6zo̓ta [pY_6sxʛ/| .:_y?OKopk6>7??oO|~T*^P9k"`Yq} yfE|Գ/x_[{tp#WC=:`|.zt0<>_X~/VExm,//xP!>WN/ _1 guodPtwS,WQf,ܫ#ݨRx,| grQ<+(TZ-E˔5YQƢ\ 9R檀yc~[CD a-b ;hp^xT0n'tv'u`BG%+}#l(cmlr!jrY nl6{ J8O@J)1&$"vDPuU&%kK|)3qק{b}0IE춳(#@.n[7[/&W{2ੲhO'f 7:Tn3* T)@6(|Ŏ"i7H1@2]%XA3Hwc I9a_&DsazcIC*O i`sZ, ؄`UT#z+ /4:\wW&zDޡCu~=LhUQXM=~q %x)zAdUsl"@Z#LECCK0ֻ-dM:9_рbӣxrDC4uB>H0"vZ<}՜M9D1%4=|F~6FA>:61`IzۥA(@&\1JПsj^.0ƞs`h[Dn4yf Trԉ?%+AXyZܿvPTf KFcZ;&ܞ͏q`랠 K/ [Hq;4Y}1Shu?ѓ`3cT=]c.pNBOcT=[?ҋ؝ZJ`F^2MDx@6qtnT"5\V!O9 ?2SГyG! ^KG5|'M`T=,*亽^ Oi78 )W7isFy/ghHx&?egZ֢g)$7rE!~33Q,RTVW-Nڭ/Q#@oIcJCB <3i0hrzM. d9ԊN@LODXTʸ6^{zؿ`T/Ѭ3S@.+V6l5s=K(ŻUb姨W 33 C*/?P'`-.({evƠFoߝʀE 41.QںB!GH6|".BAt҄BnMU%J4GLs %x8Dq$IP,Ί0XӟZC>G4 >݇".FPLQ-۰=o +SVrM`tz/ Ϝ$PkuUuVy]Jb-KGY4#c4  Q+YcU0^#AR!@E~jma&O! ]b#lEILzf]3t72IW *$^B'AA4-Sy+&͍j1%BRHJ꡹"?AԷ <F9}磬E(U8*y3 4r:q5n3 < 74~%~^c| (b) NzFDOΆzjwsR"o/o6>7svj6h?~^Ӗզ9.a9e2s"^`7x7ׁ8% sI`] Q PʡWtvJM2{k^Ri zrwW2E*Xu籮?:" ;Dėc8Ni^ ͠C2Q;D]؄ HlD٨ဆ l A<^Ep`MT$Sq>]%[(JĄVdh9BB3^ܠ+6HG^Ɣ_z $f,`[4FBc+$E8Ȫ )n5@1LFBKҬ;g9?v~IĐ%?5^9DhC"!Ei$aX|!vޡ⧞V2;̤R$Qm`1m՗tB8k:Xs84Tjzf/I)oPc"BS 0X!KBX#a4j~$L[%i xŊ5q!T : om!$ Ì|l/11*6ңa+t~'v Fw1=bӉ(- EL9RU x2,J` 0@< Nu i$-L<@0U̕|:,[w$MA@GŵްXBQ'5L 3 al|P22"%q*IcҦDD$"w)n4k0#WMpŘE!CVPf o蜉Goe%/՗Dl,5+Bt팲*  r;ǶVCd**ZOYo~/ Pii8o0 H.0\)B{ ʖݚW{gG@'L)֒kl”^aJWq% S<դٳQv9`^/tgCYdrB4?8@ud҈zbUrkz(sU81ȏ ysUQ|Ebe *v9PKISچk=GUt"yr2I!iu`wMO(f)zɴNN^2ܠ&ou)YP>42p@7^Hyz?_ͨ{w)/lu[ )qѳyܕpKP4nd[Ψ4SLSvPLFߕ˻P,3%n;QџK#5|. ŶS蹙 Q*l"Jh]@ͪF{΂ZԆk$RzE32, K追f`Vg.OݸIlfj&44hNZ*$_hx="\"O + },.Z&fMvTy.8zCJls+j` KC[1| Ni-c!35kYk^֪;I) A`fv8 UXH5hg 7cܬ a&Yt,C¯>dͱj#Іvp4a, :(s,.fZK6ѳ,Z.Ѣ; E!I׈18+ y=iF3{X考G:p@ɧN9ڌ谍&94F_ʛIz4dBά{Ɍ$j5\ăU0ƣm H6>dG15u:RҋE(Vg!hJП߼ݔ.qrDď0%>Ŗ+OL ttA~yy"&D>tw.^=-MXOϔXT Dȃ&\"{$2`CӠ22*ZڽZo KѨ\sDawzjR>x +o۽֓C P KHtzrO@V'e<:vM6fu]-f6DRL:f 0B6(l(Wk%[_yidQ,]ɭ1m1tMR.ߺ#Gs<c)ftn-Mf6mǮOB'XߘKH?N\1@fÉ9CAc Ygf2yr9nd\H~ff}K /3|!y'J16^[x ݪ6T]"o~8܏ 2|4{ Y_5@k+Մ*aaU\0F{b^o3y@D@c=`#9q_ϫA6Syꧯ~<}( p 2l*!:dSh$NDLaѣV*$yB:>>;;"oY,7+@ͬ.qLe!ZgYA93;#l OiDOt$|Gs(~H8ꑋ~`_38'V%à)2 €n& NHtlIE qRޟYs `f}E2̆x?3F - K3X"y]0Sh;J!wv_=N :RD%[ck"fY SnLȃy ]3Nh4:k=szkS^Fq ʂxueBr껝ѕӝ+/b̉؛R q ~ن@խd IwhzSxe,l[K^>뗺F \!>| 6 l ThzLx /A ĆxFQTx;Lgi8Q/L홇~Q)86 Iϲ&p7 ϲ&^x0 S`Dqsm>eqA vk_OnI|斴ֳx`N]&2lx&YOÃK@ܢ\7I3wZ+M'搜Ri)e<Y,Y}/B{L%f4ʗxkϺ ޝDXDA[۰,X+`Ay,]08)g27Ym`j +WT[ 3͆z0LzkW͂irNf:nT$ՉFt3XfD!s΋i\nZv:r(}MUb{x/.vV" ]/M:oMpg;u pg`R%d$UҺ@qeW *Ƭ\ʆ`QEx2x+gC?4 6LdΖEegͷZsxg"\P"5m6ZL ?v!O]"AI~Y-2niPw^b W!PRL0c.K{IIh2:SykYڐ)hF 9\Uw4 DLUe/ഗ5XkN){u2,ժu1/`Y41$x\gMәx9UxEި\t+X -) V4YXSo%J"U4 ߱ :²d,=ilq9<䛰p "H0_ amk.ݤo>#{iK\~2T6C#ba>gُ8=0i̐( <7[Pл`t#m15e&2H46zo骬_v~tkQ!Bk8GD4iNHF/( a98:?8}l=tj"4 xB\iD'SWxVF268cg,VtX07?v_6t/䢈kBި3wo~vYP0yڕɭ.sIAe8Ţ;Ơog,HU:*ߍZ&U?W?98 Dm6?v㿭=ޞnu[o샟d|vˈx1!fMf6Mx1gpB?=@rH޽;a Q^L־Š^Fc8zw͒K3k5Nɪ1u[^zݙ'>;@RC ^{wȝYף=uǧo0$ :{"-~8npi[9;_ulv+8z|eN.yvT.W?w\eC:mJiͿA;Þ2.6n@G'{)u(7m|nt_vWl:7Qڣ3FyNly"n$;c$6t%tYWqVh\\ƍ6ZiLs#{_^lxh}NؔXã3 ?|p,tP̃6e\,tuΗg4vd@ p#yb䤙ch (raG?VF^*6;p#d8}D<5[0TZTAsAr荺Cΐ-Y~uPq] A.{h_F}hч㈇øq%.P :g Wc]z[$0.%0-<":-O:hɨLGr`,E$ g s ddPӧg ,R!x҄E nGH5s [Cxo&j>~iHk4J4]0S& j7E#3l`2W0m &wo5#|<r4~eLYD/OEiM*S#Dʧ+ȍ 92{Qn5"G\R:p>+Xİbٔ~[ ]L8u'O~9g SdcgA: Ԓ ?ȨC5\ Ѧ^S3Q GvBH %¡CF&N^Z8^QjPVsLHݙ^qy!ά=D`xO ȁɅ2*gVYKgY;n9lyzo0rXm5"8!62+A'0,3g1/6Yqۅ5{bnףU%prx][K %~0!P<#ѱDSd4{::4г0f1փ@!pY0b{18pŸņ"PmCDy9U1t/B!l$24&z-Z0Dn߸%m(V %EK-Ekj Zd='=;&0,";I?:% J2a~^`f1 1)Dy1N#q0Pyh6|#jJlsCXeX;pOoU٣?AU# bWF|H܍ k"eoũAj)Gv$lu )oHDluBb3K-a3ȫ)1,S5! ljò`KbMs/HrKTC܎C*hLdS"Y :8Zi.p #zupr8Jd-Ȟ,:|5#gPD^6̞vOv&6ثH 5bc3)TO?}2Uon2>Nj۴78gEauw5NF VK18H;ZJ4O$(7}:q:ݥ\ExJ(2?!pii) W)4DAo. e1D_q B-ݑIVgD:*sxzrQ!x$x: ʜȂ3hP>+rպ)86`r' &8r ֑ŕSJ"(L M&]f)D+qdtK8 {ޒ;̸ \O,Gtښ:>JŞ{b,m3Y~΃PAQ;w3L``f9q̦#&G5&.Lʪv`ШV+x2Mey3qԁa 3C3e*Ԇ[%K`΅CL5#'ݞACD_.FL7Br\ 8TQ-vTaALd\ȕѣaœ$ͩZSO(˲'~|jr&iuM/K-Ҹ}aǧBFgx)X"pRA=OI%#ZG9V%nbpG:\Gr4 9-U$+?vije $2P6zq5춵6ܚC@T!5"U@p9f@3B^2pf60BPS '[hwfgZ)YAD-C<4'OO#N͍bU0̾=Q+JCDL %7,>Uߪqجr$,#g;Cy*qO`.$Zy[m6f&6愑%BBpmpVҀ3v" {3"$ObPDOǔIަjh#K44B}Xt)L<^l$`H{yˌ/ԣAzwKG8?s&fYx+o1tZ*^}'\8C6mU^ki@>핫# Tt8gi'I_ sYU07XOOYwQ't]Ȩɛ쟜Λg i>ߚcAr[wY?_} 6֜/֦_yN_cڷAܽLw+OGkˏ[Y[^_>~m-?OFO֖FAf-GO6'P}DwwkSͻ?[\Zp?7֧n]5ϩԁ4R8lXoP'O cy"ÅKiQe@"$x 9 ;a7*OaA/S>e~jsd#`ȩ){‹ .@a66X}I2B?7goECϗQz Ϥg,Nw0.{켁`(J'/vؓQ0 /:q׼6z/T "Pn2mQeG_?ѣ4 9lnM'Ǜ89Sz(ƸƜ>2FqfXlp̂&huMb@tD9^"v<,UX˦+~,ar}z1@Cxu 9dܒ;5 qʴ@CĀ%46uDPJUDߍIk忷]K|[ۮ=|+ww}V \&1:1 qd LT"|0)DLP|P B 9; ~Gdr?t~ws|Eݣ}]?xNK@.D*oW{Kag._ 䕕U;_g`,+lUzWd8uqI䫽2}{.Ogӈɓw/񑐴qrw<z:•uxD*&ȓ) p @5fgO1)TfN;WoS7D"FO 3#\Rgo)ۣ7{H"/__g/Qd~vff }xi|O/Q8/q:+˪c>Ovah{L8%GOM؀99ܙr+u A?ߑΡ< 1V9zj#橍 C^HrE4~ȯ"fQ*2ȧՅ/64} ?i}]3/F1)/j ӧxdTho0Jt.bw8ޑ|@ߞBh©Gya&Fhkn?ڜci/UQ]uo;Lj_3ʗV$0KT>K}?NN}Rq?χIw,`C-%pq,=˫!#a2I/{^I@j#evl/}y_!bԇɈ%1J>ߤA7@zC7{@D@x&0+Ec|zׄ[*Y}׽fcRf7Tbԥ`PBIYopF~ʮ.̀:ew'PQ/N^o>$\Gj_LRx{VbC"Rݔhnoa@YBMX"0 @2;~ۧPp2f2yo6MFAr jRD=5>`#c()kըXnUiB |n& W|SǯZ/ q^羇w2)I1MkXC-щ 0Im *djaݧrEaK󇭊^čV&s$"JgI|g hH.[0U@% >\xYy إd[Z|Z%K«qwIJ C/z(D_!k֭vVǭ>;2p8F[l+j\ xa[Ev+X˅(V9 Wڢ; ? 8! Ne;|eW{-ȏd T{$mj:Tu7Qj(5yXƫ(`w(ソ0ܦ,dXӰ},6wyR@9C$[[ʫ"戊Tp I7z -B,zT-씧4ӑ jV+~M6"q;D`$ #B/tVDX=2UĘt4l y#h}cs+=\; oۄO>ݠv/sEș(j#5gAGϤ"Rpz+Hy:KQrmnaɩaLBW\i Ndrmt8w^) (4 Q<5C``@2&(]jr0hjaB̳X8JIZ4G5.N˟Y"4jaI"cƬꮙ~;RJz:;מ>I>U)\S)kV"9= .Elsr׶0t[ ߓ_Nce@ NPs\JۜGea<ϛ8F*}2'FVOӾKY (͵L&ϝVfKޖ<Ӽpgs0f-{mz%H"4ϑ!s4Fxdޠ);I>|bEy*ҡIu:DzV$~)2PײX)6}mh9CqUJш)QqVtT X h #vB# YUdnjb ᑔOy:(a!Vu$RW͙;Gz>5'nn-}W*mE'cƶuJ'*]~$:P1)wMJyRЅ+G*;^ĭ6 .A$G )8рŮfZOխ:PێN$7Rg&e=<ʘhW,"x4m0 UTܢewqQ5TiLL~͑wt'^Zr!+)Gh0''cķx\ۯp|}èN9B!KO>V`b[ĕA̞L{Z(ǥNé{ؾLɰy$D$c i PlhSV-pP ,.zN iس|n$}RDB/zȭ-.$(Q*h^05`dN 0 g8fSBr-tURh@,@H|{>Nʹn3kpDwЂ.{J%CaA@ϫh DvIکh=1tlqfaݻ4&6 iK@ |p6$v/zdxNYF.[:HSȇfNQCzb D,7@c>`C07&wYvQ[eN\:VCX滃w'{yǹ-SfFOkN" },cP 1g(0m!tO\ϴcͧcہo~9<:=6w9P3kcܑc%s';q5^: 2 T[8ΤS@&PLV)z*7Ba*2{=b4?wM*Lm"3˄EeZM  `,ԹBb)0|TX7S~FwXR%sRb3 E&e,mKDUbkRmݞg_e}Mbw[ ;%ulv\dE8X޽}w xVQ<,(#~4Pet b,b4/s`)bڐe2!|8Mhtm(jݚ֐rο~Xa74wu %KxHa! }-T=Rq 0?'Kp}պ5/!@WpXŴٞ0UL6$D8LvAdglLrTO$U{4e5˜ a.0TL73l_\anFu/ίc'yA|+Jzxfbg Q0PJ4)LG,cEZ (Q#/}zh /~RGƚ(! :or)IZa2@b1YNfn9UVi Dѫ7?Lq7LTDZX'޷Pe͇Pbc\yEd`ο.8C8Ȼqky/V\HZE?ݮSWN[ϝU)u`څs2'k꣼)aۗ 8Z*gǽCi;|qrftOi @fΝ/w߼y/3cdE1kH&=J!":ҫѰ 7u1n7+յ$ ıLJq *t~[̓G;`@<2]čUV[I YI&+^. nm'>̈O'PbXÑG冴&N$,pDVF(XG$܂Ä)4QpLi:#[ej $Ss )a KEC@G+ -vk_2Dů.8pDF\_t藛1,(`fT+Z.Ne/4B8GnVLx)J-‹*)!˰RZ dO K_J?_ x 'RZȂZyVt:An[ x*:gʧ<o jes@Þ1ܱ&t!A3 oMV{TX2~&2Q?]`>%a)E~nT݊h$vIOwB@~29Y( c  zv۞8˦*OVlUޟןfrǓ06 ^e~@?Q5Â%io<ΌHLW+rgğʹ,ߔn8^9HgI'e)wx:CIИ%jяtx5ub*3w>v/;"29Oq$]ؗކq] ,P"CmeQD7Wl wJ[QRk*ASB  R4֏xt_ C0Kz?V8; 9Bs 'c<ܮL<F6$4'xfYm.@1Y(-.w.vq\g70r(y dLu٣ m 8[YJeWl=X1n^`E("Js%: ލԯ3wZ XVT1Q?u֜ӿ1 @\6Fjx*ΊQfW'8S?9t};r2Vu^CI*PURr_mme2Ym ]ܻDg -rr=Ly!3qiyYYyL"۸[=.Px8,suπb"pu*wxTj|yh&B㬭PT Y>tq`~upkc{+U&Jc/_"ʦmZMv;x,"kDÑò ?U^q6a=76H?[:E$VFnh(iXQ>>J'RPNpYTa 7 ԠIB9Q+^@@M-^褰_{U VT'6*U 3W˵ɯ(Q:՚"`ft<HH (afZ { b %.̈ [QUx7㽎Wame]eT7MN=~n#r={Pd߮%zٓ[0RQz( 8L>[w;xSɹ۬O CGx|,kڸ)C77鐯1K6Rb l2e2E&$i2-E Pr3vAeX[DޜdPcE6.^lZSvR=Jrԁs+Y",j.֊p NA#Bk-ALFtNEAtOCnA4ѮŶG_-~UwM*nd d +iHy;s %C BsKɢݴU{BY:Iࢱd߮)e? by ͖1Z]G5OG!gYUG7ak3wKeuoZH4kmMoVVXmP|PGjC(~(q]$JkfU\ n2%]]V?Gmrйqk pN&-fHh¢KJArBhu: oqY ZvR(<_[UOō~Q2u̹sӲI+cѸ#I\CK4J1'. tkIQcd}dayVE9LIVvxj(V "|im:cI˴*6qDZ5˟E>8Q`L[$YbeSiVq7HXTyEΎ'Z)N$>,d5dYoVh$jd[;f#$cgޙF߄0tD&C_ U:_r O cWQb I([-ׁ` FYUWbYN/kI{cQ>Q}NTInTuKxHJaF-Ҩ~wymnYqEJ0Φ!SJ9 sNXpd$5j.j:j{&jb1|jUp0lʊ8ͧ:ŞW7'{M>'|z.c#RHz;±TQò#7p Zv3GY7~Xf_)SD5!a1q#sڤ~N?u`geR͸!T @pRGdY#xlDmLy#]Zhσ5̃ Қc8RDȈIT(\ 0 f(1 k@pDH<8='A@fAVu/ <۵QyPj!ȨHvY[*m?2GVP{jQS8нpM2[JU4e?JF0L@{{Ӊi"V7Αsnm}쩭sV9t./( V"Xٞ);j| 44g9g\ d#I:d[u!\^Y'Z_ܔ C+CR}8y3W.4Ea} Ff~z@~3@PBeˌr\~3F0qQ w"$ģ{>>a+xվ^ q Pw!H1`_;KdQ+?1A ^\J+hHPaeLUqqz'gIڣ_!}oSzI:A7ܩqhmʧ3IR,'6#0(~pAGmm|V/Ƃ (ԬPf%1 #P O%&4iq}4: \hqnaR\kB[ W9ְ7Jh8J\aO>nE2o)H-iKxvh-"s4Ռ{7-[S?=Ꙟ^KfМޟ&fVY؎$! 5K8_@F*0o&3hii5z^HE۪抷9ڵ" ÞKc~!޹KRY>儢"58ttIy$ [|h$%rd6) ١ "fD_rj* fP M?3@*t$#S>^H>\ٲn7TrK*ܿҁJgBSH_+Qt̝& 3E$k&@֐VUsml 2_e~a䃉XN\\ssbJMS4W,M$Uv3tEĠD1STQF(O@Q^Eex$,5>i,5 Vl8VqH)SKA[ؑxxtro)rtN(R{ha#܁Cx'O>1O>xma+J$1FmhVި`cn٬ĀpQ !$_v$NsI3{aK.H-+-=+D$QuDLt"vMHT%{Y L/d'x^֖ >*J@'L;QYi?ԛ/|V:{IOc!߷J)Ħ/ݔLP`  NEƸ7ҪlQێ5F4 rLT4ta*/mJ fP`P }}2kO%Ƴ/F=J/FcmJ}&a>zsFV΋^3[*ú@! Aei=`[n 9%e u"<9:(`e2"gk׳TPotP?n{cu-ai FYxaJ8Ok[YwK`"hްlBăƕ}}|{WF75A%Қ`m/ƛ(bNh9`*yX4CKZ*Ď]t+ 4 p5;1BJb%ɖ67E,+\ &\M #*g&,4tU[]xG(gybZf6b)&_g֥HaYܳid{{90!31x|qvM2ǧ9ܓqm!7uR;CT*JRT5iR eC$qxv͙wb$Tv}Wֆd g=s(8~.Xw?ޙ}7iOzP:rP-x;E̙,P"79^!e"tEDzCCx`sOSv<{~di'h=xlekJi}Gbm[mPRu7\jT4>YSm)" }^_b"RATEK>:Д7>\w9iMdKވ>M_(I e p!0'Y/FɏݲSJL m%́G ;`gxk\"<{",Ү|._.SfDyum]|vX/U^'6_m/DE-|gROFT/cG8UۯGn,7E 2ӲAr*4Ұ\0벓9?:S)l֕V>Lva[p:~۽ҫk+ >vc0mJu_ln_LSIK͵\~^ (=Lٟ0P ߬xO) ?&ݠ;h_^ Ea(VKRyU}T@Ɖ-Ln%{!*"l.BzR(5Jp1U|dCz7ޢquZmj![PM^aG~+^W?=L-΍Q΃ti&>ZR_^v:X͡BǪR989=y'΋^'{Ae&*V՚e#B:1@У݃=X >7g~77@GZ #qt,?W#V~AU;> ǽS??=>UbbrXy(pm+1v `3:Ea ddkP $=E+n}KC "qT}z[EhP*ԏOYMY{|VGU(ҝĪS a`ck o}+#>(g^3j5/ޘA..@ yxl7ɗap|ɇ0eQpRLY;q)CĽE.2 8v]:Fze/ }ȺiݶPHQ9- ,/4($>Rυͻ6c:fLk O HOQ.jۂ["<(,yٻ`pw[>pyB/F&=sl/2S:7Qާ}OBǎ% gI"R;1D\J%;,~O1TZtz%an3!ڜ]灆}'r@`A@1!8l` HcF`k^;; K]2M:[sǎvXu6@v8y\mڽ]x˰g9:ZʧxzVs2^HD7F`^5uI;Wa6ZyR"<y|?B}W5& }z]:H NV%G&„2M\_g^JA,OW?w"~Hl\Q_P%%V9w4n`hnd+2dgLa~,h6Gƀ .j0b)=O}"] pQ2r:s`nV$TP[${kRSlvp4P5% ;j/+&=eڽH/ Pl_BӨ KM~cM"a9.%B94X] I_$nbNߎY*ϠLXKD4=M7,ڐ_07-vPp$RHP.y=1}TWՠ {ܱ璛%BU^hPI<6QQK qcљ3x,u#hHDfz-.8cbx^> e\Cy7JŚmd݈ . FSozb6?:>)%kNNbKHˤGD/:) PE(:IxƧ6~H,o\Wۏ|9;R'D#hI޳F= mUgq ɶExUh,]gHt ot#= j qR}.hnOJj/cVBcvDQBmH_ʝer/2͆s=lyҤiV5&Uဝ(Rv8$Z#FL=:ҋy㎬3U͝zY-(bU]I*K_%%1t50QIn2g&fUئ=*Ӫ 6nfL̝GpJxjÄakH WFt"Ni)LZP9j|3*xArvt@5{gf0xA ڽ\x)D *q,3Q+oyk:0oѫ;sSc|p|Zy-#Z?@ m>q%)\F'~AukoOm*hՍznQǻEV Kr `J7$jyt4ه !?6<*898 ~,:QWQw22;B19Ҳ>I51Ҝp1$RT9Xm[rޞ\d' nPHoWe3ըاW-tHIŘIpҀ93. EOj=N[KHYPG$&wIJ=!xIh/fjӂ(KSlc-L~4R̾#M/Uq!(Ƨe0=)K ء#=dUgWxNsXgaW7DB(ѵW61\z0Vۥ2]JqaZ>@{bljl ]e촚2Nr}d3g"!|MJ?޹Fg*}  [̓s"~?~F_O-ZF;)0Hsc+vH񳇠J\{á׼Q#4>`,#1rmװ_Gl7%-XQ .(*0Ҧ9YC }ڬl9VԎ 3{8dk chBnM@eM- q9c9ڙzj}~q$G/4Xʄ ]cͬ9@|D% KL:$Ӯ8d|91/;s;/MfBc,.9mTʸV&r?gFe>Q%k:Ld(qqQ']n` kfJ0@{)nY1nF4fIX_[EG.PcF0_F1((radr+!0hVQm?HDX .HF3Ud`tK9%avULDiȣ(MtOd 3<ΓL?9?7YeE~D.dO4>-g@6ݢ^fdz1E#Ic(pCi*Y|1_ɠ XI }oY}Qe̋AЅQ$1Dr.MpFސ}C7rR%A G~ѡWZ}k+4wn#L$ $<ҷ-(Ǎ3c *Ī4jOhJКV,i"wre|*0 cc 莃2-G&ᙣhM}MO*}mNX<0ڡ0b' xlUydrfbg2 |Ւm'p㑫>'h/51zl.=L܃ Q7nM)D-k^`/Ķ5Tj≡a;3,h"7,S_e)f:2Aj~ >miW>//t6w~"=kj5]%ֶąI{5"kN:ceX2iT2H׎BH~N>f;^\3֋V5k\KӴ(`֚bz4,2 73y>nNm|/SfmT#gpeO5ʲqt$nlCӇtX^^Dc-rfY8 !Kk| rBe)L ,zKYe//vw]ަXbR%ieK & DxKց D)0&&Aa"?LjTLHq՟D-l!: 8 )+T>xqA#k~%I=G 9GʙײM'(-3V4Lߩmjj /{K7R_,$cwON'2D|m;3GySRm𞐐W gZ A k0s>wƴYfKJ?R\UG2P$5!,2:  -c j\8sAV}wPyA^-r$pIV %"CЉ~ oOGl> ʐx&aӠ398iuh 7&E@^-n2e~W̽7?2J}dxUUsrRWJ)縂6 .t y@F+ {+a5\gg7ϗkG /5ɓ@$Oűplig|/T(ZRҀ>i}˲挒&5| uTg"Ji*Ad j"22k .̠PC[( ;NW*1RaCq[c1&ye 0;k6M2_yS]\XlVVv}ۘ6b,o.Tx%tuхK1$GRl# |.|$RFb ,QW ƷX~6VL4W{u(hq|)g_-.##aW6>GMA~bLșa/zOP g\k"Ef4I,M\Ւ~ n rN'/1G7A|XL| H2Q`Q? q]^h%%}3<&0-4'fʚ ^NnWs1H\ E\)ze5`_ؾhkG=][s*z}@'ȃN~RbΩ-nO4z&\ 14]3ALZ)Ch pI*ļ&ɯj$)Wc⃡ 8 E: s^avO;w 5mY4,w4Kso;{8mЛxی"-=Rc3ާFo(z8]B&~OeZP.ȓ4v{؇GÑÉ;8I\3z6QL{$mnhr$ #mz#wPkxp 48LrjBWvL(_oj 6@g;%jdX!"_DslR넿7?cgˢo?Iyuꄧ)>!q'To/S׫oxw#gc`4扊q "+B jn-7i,dy>.5yO]u0λ6u[LJ-lP%si,RA2 &sY Rr簼ZzQDKS"60;.k*בV,I̱u8זd|-M[;Ճ5om&jO8o]lMQ&\z#?q3Cfc1rh4Wu橎Zt2WlJ&&vrcǶmQA =+5"H.jz,KZtyyϥ{_ו^zd rSXG+Pǽ0,hn=wr\z"3vf2\ r6_La"ד)y^bƱ<$sy6돀휉 >z bV6F愘$HٌчiRp9!Lu|Ec*8SuiQU9 ukel-%6bkix6@ *5>q"VQRܦ]Tc2u^278z c ǃ;,Thx1"ι՝4Lw*=[0iw^tmqk"uu1&.AاmҺ6Hs_܂)LS1)X/rIP1`͘&O 7P=ofږT{;UwgN,B ZۜQmY/3ǽrfy%ɚC;]Pސ :2kE)fG:N=yq I3' wyJJԤb ?pw"H_;$wPx&va0u7[awVi6AYQȧޔht3j? UlcWp3ݸ3۴Hxk8EA)41zAw=G˲ GJ!G4X(ze@b(TsQ|#R$M,Jθ8pvcM>` 4J)X/Ԟtv8*!MN*U\!1yܨFZySX} A^`÷A ۗyj!\===>J1)e9 SdNقt0.&&4K놩Y)7wNUU)ۗ|pN)t?G]W(F=us w\WA)E5 ZJc!{ŲֽNjI{O3̔&[: Uƥh'i6ba{麼L="%'?4øfw`2NCH+F5 '[. _S(;J!{Cʯ4bN-ɻUHӿ> yѴy܂z|2_pdZ60GynN5zAϧXXyN!AdcIҚ2 cj&U00ƹۿ0lx>b^TEl:j$bGַ9;W E%}.̶c^0?Տw>n%C{Rid|*P"QCzbwX>q1!m Y0.[oMZTJ2y$@9=oL.ZNCm/a@ .e㍽*I /[^AmP**7oM FQlٻB6d¶Z#GR_l%D]&cĜkWuEe6':GWfdnZlT=[d9ʎM!sph+1z& ^_ztKr-@Djhn:M%TDx ?>YTa_DORrm$o*Eʞ/VT,V%MRX"fUڀn!%,8o2Hrq΍cM'/#e%2.Q5}mKlT"l$MG=vĪ4Frܶ;/(BL^8JI&)dw˄1jTIiK:חC} pdqz{'o3O D ĝn0 C> %PxeAc혃KN'pɾ k^ ʄM>D ;bXB!|`*MY#{6`$%ZO--L  <C,Z~h ĝdA(JܠUM_/J\~^҃>3¿Y(vq"/zAvоnQJB}()*`0lˢ5_L+zr M(#E`T9!2GB}оA}^k%`}>=T 1׻EXѠ /_G6zB gpU ddkP $=E+n}KC "qT}z[EhP*ԏOYMY{|VGU(ҝĪShX6EyͪJX]Z*'Qʪ߈3_ϤxWo,{ %6Qk*di|uN؅u`Q:V٭ngT>7^MTro{iVW \76RZ/qQ^{@/g׾8F[+L~L)}eOOR6#T6q/R@!jU^t>9oۀwoO)ޑmB+('kr/:IJQNݺjyus{a['?NOi[dQdQ`r9;lj4En|0 x㝊R%-4ⴂPOopLW+3mQ+?n +,l$تHQ ]6r ^L¯xZ쥂'\F&KޫA]oSěst HRx jXj:Pͧ/"G~s_{}>Y 2 =61ŋ͵ܽWNzqALF&#zg#x15M)ӖR:lJY+:q{Ifʱx1ڟ݄@lV~.0-X$C E4n*QJʅȽ x F]&Vh4F[A7TÇ޿1W(q [!0 !u"/U$`h; quc+?/ K.gb6L힚q_'7'`z}h%]l6"O[X6O=9ivO;vK: p'D[P̣wL%}jmVg5ӏP *r<G^{ t~.JbT&> ~`N`XcaJ/*+u˚XyX9^+{[GkyzW}{7/5zV;<ؐ =< `+M/ ?J*Fֻ1o(c2\SXl`QVm4GVmmQ&aLx{rs^mX/ W8Rv<ڿZ,!b;kP߫%"w*ҁuzJtEU(y*!!Q߉k<謭.CpEȯ] R:U(8㋾y?ji뼩 f_mu:@XFrS.6 W+p4BFh>EJ0nEԽYt:|S=U'Xup5(+}֛s2YkZRwY>VB=tf++Pc(e\ǻSǠM4_D&^DclaB)9̶B?BMd+{UqZ\ 8jiw=XgMG~{NzH$3`"SGh\{|րxloOۃ6ȷA [?Ͻ kg՝VanS{4ߵ: ]uP|fJm|DÙ}7vt`W0Wv3~,?H2݈t7x@> 4LJgt9 E@l7Gny!._}'p['Pi6V>m;/HqVK0٧42TЖuVs|*z=~9>"^ I H) ,^O9p|bXx.^gk2|͞#&;GZ|I>.o1%Wв'=u? bG|[JE"ֲ&C)8ޗyl57$PT0\k.9 ^<9 7@O#>u,sdyqX9WG;3_U; x$tT,gW\VsztW-l)Vb 44oؖPA}Hc,D鏆j27Up$q#m\59AټH =~];sh͝G}hH1Dmq'gӝOsZ=;U%Ra?:S?t"fM>RL*sNj)ڊ+pvf wP'%L$mtΑ^F,-[ia[sUSlfpBl& PT g_@a{BT&**y٫߼RNQh?]O(w5hюI HF+x$ԯZhlzyul9/qg~qPH~w(~{wChOJZ;S)an+S_vD)+S B堒DL<oo ETK#JJϊׯ.l*޸撪"i*wG!Sqv{Y OcL8aSAe/Ғ Ma%x4 JwֱTtZM;I3V!Suz`D4zxm2m8]aTOgnVnqatNrN;3KLi))_u!>欋'D =2dx ,}=M%jN)qCXUr )zV&U)w*t*5y Ux!]D?IA[~~?}_}6{a?}}ikzrkIM:Q=KTݯk9t zziNR\ao&GJNsݵހNˉSlٹ JoJSJ]s 6rOJX25S?U!Gr?tgIC|E) ڃͺ{T{P޳U=Ugc4=(@J!&'J<7荹0IEOA~07W;{ ssZss?:AC&4Mƌ뛫\Xqr Wk x5,aK_Z׀utޥ@a6 7l&ͨɛ(<zQaBG3nP,t|2/7lG9s_b4H F~A "*Go9bԡ;`!bY?m8W%|| ~ OC9:^"aѨ_S j"ju[ƆDE8= F(E f0e$(rZ>H 9hgt9:OwnɈwt+5Fɂgԃ@v0Q1{&!';#i'z](~jzFɷzaB7b8DR_&-o1DZD؟y͇E[\B4FWbKZS F‡D"`B5qӆu>P\P "~s"*[A 8ѾjE7+AxӪuw L&nLL{aNtNapⳗ9gB܇0TWҰ݅Ӿ&[ E+,Yk jn ͎8[4(p#*@.8wV~99k(ڹ~jCyck򉝩>i8+kDXhS uH 4|ۼcwvN7\%%JJ%/b B+Q.".(֨asܡiȊߺj C I* o?ڠ =F18II %QWi8!9Ύp*I&>t|dV5Es_fSb< < =/<JH 0%ZEŻ[S y-`j)h Q(iY WhJ9IRڕjkk|h'o4 ^+9|!)i=eyw^ oa8\ )><51H1'$HZb ZT͟ ' &l0;}f0sU֊p ~|E.c/(^~B28GJø^[|_Ps}@,3\2N]ڈgIvd{uǧ%d>zɎG?W0>B&jo^Ab ` aN8?VhBo& ͘hN嶐@Q~1π}x/ Qd3yi+{rBkp ,pa׾zS:Â|A`!'`1(u}0@ 4 0 ( "E!T4xhh)H|YXyh}'rsMm] A"f:%L{->-rΖl_PdjqlCqў&@N˃8^gEA@}Uxj*k6/`JYyLt: r: @ɁlѕKR6Z<XH1y8wdnjv**6s`+z3Yg6Nz(ѭv2w-gtK/Oі7U[a{ ʥtmu7ew[Y<Ě#zb&mkq\qȄYaqivq5)Hf0MSgO0S-xpeCԄQ(I 㥤7]{SU 7hp4VkpgP (VU Z-e'|6d{av5:23 m6jOOQn}TʽC E=`kvIveȯi9-0߳5;ĝ>\I X{I,U.W9of}Al4a|sjfLHh73hSc;|:a@ŭ{q1mcK,BSEC#CXY 4GO)#>@#4pE)BQB5:߆ӓc3(Ғ螖36itdA{l֛ϴYn'qއn#2.>kvFܶ'"- WԨad@EӨɥsKOO/޼l(_ B =8و|EA0dk^s:"EL:z\f7o1GHlO[ 3Ai w[dډ@3<&as>kp  H~nK Ql'p3ŁuZ^^.rcҭ0zz*+Jgi*BN-h;8Hy?RAV)g +ٍ\ӱKjtCelnݿV 'SCU#a;h O-Q[FCMξ_}&oG/Kk3韴uu_>r_˭}̹kbO~O)3~\?.eVS~E:zgX_RL*U[OBr&D믒~\tO+ 7Z,3v3=?g_[]XKOOɸW.*EZ]UAN@Z)_yiR}/,Aąvr_iZ>uȻHS8ŸP879&["ԛmc/ T._fA9DWQT܇ z~I+9+`!JT,C>I€ԝtokzUDPVcPMxo r g@_φ.nANgK' mNX_etmK9.[kDN;~V8^|›gIAtO-V Oq6/&-߫$,g@Wk㣃" ri8H}FWPnKj!N{ٗ%g v%Ƈ/dޛѩjXORjyc͒:RuUέPuW\K +o_"k7.Q?w}P3Z뾤0K"]Iv"1QL7DdH2EC *R+hNGavBEC-Iuiue4<^NMZ4%=u/"p[1BfxЏ?x-kk?t`j9K4gQ96Fxn$.:eh43#ᜎ ##[;k`KZTxG!9&rG>׳)d;|zK6 v #^:^T< .dJ[P|[*oTyRv|S#F]j1hu&"~p+N6#s̉vk[Py}&g4d(P?ϛb𹼰P{!-,<DU$"  zzcmҎ8bPmd}edP_.YJr`Bbc\UX~5~ nPBS"5&-Y6مqbUDhŰNEtt0@a%r}!ruxuWl5ҭ\2g|s/UN~EZI^Q#psꫪ`059'$#G#0rrI\XJ7+G[USsm'觸]GR"BES3gՔ.ďOex!G0{I&~aiy~=돸 6gBح7|Xm$ 6縧+.iԻ C\Npql $r2tb$@K˩"ulT uSWx^ a_blfQ<^}"&CnȦr* #̢sENF9)sANMryh.dP |Ca{(V%*Rh;`nDT>^s]Ц <>FsIJ=orzK_Dv򸰒%Rd HJ<1*YL$}w%c>+ PTGz̋ IF\a\BxL2~ORYE%2%iʋ $"4gB|9_u\OCWBs*:sh3gGh#xK%U݋6Nv6j?ퟠL?|"R/xGUX"щp+l}@vl\A: 56~^?6:V s_ܦ j=Y,S\a% ?-|H/6t2gC՛P70RyTU+JiZg&)VSbkjR=.Z}M]gxKaםm]U'dxN=Qw*WԽU *ߧ)&d6O;T{pXOA">Υ?&aBB'ĵ;BŒ2{P)"hoh?S$!!ERUѬj}) 2nFt63\K JT;⨙@㘥@`,i@t*фzO 0:0 Pw@On=7E0ݽwI^ aEwTf@n?Hpʩ6wjSh͉ш]JqUQƂyFWmx/KfKyh~>N.2=^ wb I=8ē CIu/kt_w~qЄ:{Mz{ 289c=DAfˆy&DI|bqqA JB 2E#͇Y)zHzNx1ۈƜ{hwԞP6rΒzNa^rbN>7 N]vJ8(tIK@oy{8X .ߚqWz O?@UG/8r\G7(g\aĞ;mI OtHvD ((֩xahO "kgIXt#h#cf {t$Gf5V{xY5A|w~[TګFs#6d?:>9ףt7k'Dz L3()҇űoR15[AZXL P2氫cʱHP'|x`2|6@,_NW^+2xػ'C?juϙOJwx'=1e0gx'= 8?v\s٭ԫOk\yD㽳jrZ* *> }-ٽeJ+%\D8}i?2A}0C@Þ=AUg={PC}P{6FվUG+͕+auPA퇹O*N.z2 \뇹j1k8<@;U<_bnv +uz~X8i@}[X=8(o?G4ҽ6j|Y|TW? rkKr(oo?}@|T,"5 QMm{LbAzD1&wicF|_/gS|&,R{ǂYfV9RzR.2VK‡AI/-{.oė˅X1n`7@ÅKPotHHywn[B'ss]-~l{,8; Lp{4ݏ'>>zg ?"ӷ'UNTv%b)f?MgY+%擩Nf:L绣Χ&i|Xd՘ަa8oߝpUFjZ>t>QK'{.-Es?QC77pd >[ .2i{t|tvh+ %'YI2'MI1=az%z'L$'L$H"SO$GAS3j6fsw. :H]~)+/E tz"N.1ߙ-Ppl'8vwĩW*PeMc F@yUN a1Ko86Zڃ7J-D+4Q Ņ~yX~qG\ns[zAv t2=*"?Ď=?yl6Jx'.EN.qD|%F?Y` Z}! TzRr9, 8܊`EJ! YRR> |jaD3_o/&I~E c4 <ş[zC}!nVIw\WN*&}>GVE:VN- EIm6|úuRgqtDt> .TTtljʏ\fDK ,Ra:atk׹oSre Kد`uϬ`fHjFz7Wt/1Q 3 `'sP$+@OFÁjN Vsq%pN =BIY"%"=iQ~K' qA:93`i@ޓ1F/rkF}']<@]!vEI-ݛ%30Eaqƈ4959=—quɘjQĊQ]vxzl \ԋ!d+H-`9iPP]F@ٖs,{r麇pE :Pb9#S .vmZÀ"^`]Ʉ4' 2ph)MZ~D G:D$Sa MƼH.V؅$S?}E vDGlRFޡo%#c5 dWc2 FlwZ0#I,StZ\wGwgG{~=t ˾>, CYiM_bq8ҢxP%{]a\4tjPfg *0EgJSA Api, dR/XHx$,b TB Tm1j%mU? .j~^KN~7"$ lDhy` E=r*bܚ@n1/h-rsŬ&gR/Tzp! Cg$F"p?xOuApj)~busvg=owݪ`px%6JKalJK+zbKl^[ei%x%^Aҫ9 '՟~<({|WO7-?Bsjl?g3y<fsa6:wd ŅYarI84fA{͠"S_x) S:.W2~a'wtTreNJ^*O:eLg_оS41JKoX9 b̗Xt)YhY=/`د}b0Y! R 4К}JbX" : v7bF$CwdiOXgXQa HhoVkƨ& FZ!tߍi;_[|3nf|W*?OӁ@ʫCk=L꽳=l.BbG!o 30cՏ6/082œ̍%a.ݡwOt/+kƦ~wv8WVsWBF.׋F^và7^5޿ Δ>i,/ɋuzr1ǩ/`' @>W{X{O~uxLer1JcQ j#VUۢb {DQ7ӋS!Vt!ʈIGz Ȝ%Ā +ކ!:F*!J\*>J/F<wj=ZX-l&:C7PՃU͉>|=HsYNلo#䥔a ¨DL'CYDqd Xdz6f"REP06)c6B!X: ]Źc5iW98NI|Cq8':n?,6 ی`fM0ZVP8wKU|܎ؔez3;?sE!Lr$I l#b`-{DOXѠŒK]B'8Jfe-}Ob}cER*)Ů¡#r%X,&gKLGOsHꦽ`ġ(2>!)rbL i*E&a]6/֜KBc 8g\;`ABM 5+5N=<5eQEU|V>r}KTSMTBOFkdksv/G2K5b:"!ҶUpڄ-Oi덪 μa&f/`80cx&" jV|Fs8_4ˁT;k0\zݒ,d yRv (1hH E$VE$x$ɨ`>/HA~Q2nH'30 2Ld͂4UL@53t mp]i/.,f 0 SJ[_2N^HJ榒$@&Yɨ:ilMCgrXԛxyl1&k`kccR{ėkݱm^+q?f+)j}hޖ.* 躧R2:ElR pm4yI\S ˕$IH~2 q;uAZ0g9a/@291fOZSo^G2iO"vnQ0+G !fJޞ0>Y2ȱ$IRIEw/Ŗȗ50c[\@Q63n<%Kݓ43e3w̺ydA_;aC&m}Xx*J^j_krqV=r]zx8+?zXOH{Z_gS O"_RYP ahyseONf0 LNa 5X^ܼʬ:f_iI5Yo0sYnaŌs6rY P\/P`EbgQ/yj><df'$%p{T³{2;/bI)`\D`Ľ&͒oz56~ʍG_>6/ bve)ð`:[ ʥ[Bm ,`a#yfv|Zڎ~vG(N {ToR #2Ӧ{aj٭grr`օqۼnNWF#'Ƚ! 緵c|$Gt|{LoV+?u+bd% DϿ` Իŀe!D7ɛ(M'nm޵vb'(M6&bv8AHv wZJ67-F eʢG7^F] n|߅꿼گ֝:Uk`BKk őgnnq6fs~$?%f:4 w{dlHN!nMFv7K0;(..ZUrǗr AP5>\4-#lU|ϓ |;x՝ǟ&j>[l\Zs7VhtX0h^C㥲H^ܐ-LS9 ;>/j,?dcB˙[sz-:ě7QBVD+eI^]C50>j'I0gjkaӉ㘤ܵIA)'j<龎8d %͍KMXge-xwY\F4µϛ aEaDw Oz'=zfIZ挕Ԙh?<>b剬dUc&Bs+M}q7?sQ0 ]`5kL2*_O$q= MK%DjLØpt[؃IdUDXUmGϱ97mv\'2i;-jRW6_8 °GQ\Y;ˑD Dб585C `j<حtZ/9;uW;!]̢EFDG$Y"6ט5MlM^~#tz`k",}pͣ>2CwwR1M=WBP4G &nI75 ۿ$ܚQQ{f RV2ĥd{Zq9 Ƌ:?!Z aRaaڌ6kо0ZU$Dlf4i?IO.A}0eC:@MXM\@wm @jkԚMZЦPlh5lRfR @hulb'a EOA~07[ 竆|Q9ُ V~Zǻ;@\_~Tq5#0 :9xyy k?T~#XBMU^d"xQ9|C`kgop0*wԄx;w"`>[@:ߥD3W;ڮm7UM|\tMŦlZk궚+u.rx ֫nӳb-D@A𘮐T=vw_w2Ҟ̝o?_>K#PvUv;[9O0e!|dx|Y1HqF=3W?#@ǧgsc ޓ_aKз!ΝXj.#ӖM-?_>_[š0a0j^ C=BtP~DїQ IVyEEڊ RG:Ѝ篴%bnnGO߶AW,]U>~m%y6kbufWOY>gZ`6fs!q tǼ6S.fi9(0?⡪asᓺ~co{C`@*;Zqk̵u~gnx75w`O:&9nG$S֡!Ђ1RpZ7+fQo!5V Dj#j< Nj-´^$s삖J$dzHaoE9Xt4SS͈ 0?!]!O)?b%VCE!+`0oxnG[M%-kpB]i/BN~nDH"Q`#cRDOqrxQ2уyLϋoTA+EB{נjn^U\V/ '/ph&`[LlQt:E=؂2\"Z"LДق" *H%#OtdV4I(?˩t ė)(Dtj =Dl"kX_ }5.߼9︝C?hW>.؋^u:]̓]i'-~MHVKrҦFGI0SaԪ2*:b]`Z" P.B.!BI"+ (X]G:EV&'voài>b? ~%K 0׋&L&s9܅ }ǏY0|QuLRXb$ՐReA  cQ`%<#0<.Cf_*P@8bAA_?[w?]aKhтj+*}"ZO˖~٩>f^h^ -D'VH9Tzbў.Mj1FJLhJ M"5_ ιQƆKAxGeu #rՕ?4D݀gzE} Ȁ Bt9ob*hztp{@CI(:^QҶgԄFA fT|.ulgn?6"ed3&*Jq[f0mZ~ S|Am`W^.͎<̎ 23 >LgF :ѦtBmn_յ[^n%4:xAKFVlBj̼(v;R]s8P oq7Ce<ߋڋM[-o='chcj\؜}Ow?o͔ҧ')}R*}y [M *#фð -ǹɳ!rehNԇWo*'bA, ?R~F`c຋ͩx{p??s$uX$m 3Z8 ;S`CAtlGS8)}y4WgOi߫qr<ܸWNәSq=eW! ,5uQI7U۷mQE{zaOA1|4xĞ׎|mzG sN{͠`=0~ 0]ecy=jx{2> A7tZ[:ȣՔNX膖xx7[z((E}'1qk3# \+bV;b+;u".#2\JeIɀ2H 0玛ޮ+خ+ΛΛN'Umy϶'Yme?߫1ד^(< @K?[pjd7xK;:s㛞?yosPCiE.t-rpޱ8:~~mcCy7 xyaSK>s Dp<3A˻d~ EOM7|Q'`G^da %]kV)yA;9/vONve0a`n_ݝAn[*}*kt{o+8 ]=`="ǣa4l"A7K! ?ս/!Ee#_@h +{{; X2+u˚XyX9^+{ZGkyzW}{7/5zV;;8jr3OJSaa#g#/+yKz?9nguiu(vŬP4NLZHֻ^8Ql o65jF#{j8>j:ۓ+jzsDs-yB4foװ!PS tJ+Uokk;aWfZ\z0o Ы0Q߉k<ꬭ.Cp-ȯ]}uСH:U(8AǏy?ji뼩 f_mu:@XذZrS.6 W+3q4R+hRb pMVzŤ(K}s!2YDZRwY>VB<=jWlfKKK#eiFᖖwfiLLPŽ4,12(.s 581p->{QŅh!s)cZ$ EMi^Q}o7>m۰ l6̶>l(Vw?Щ2ͼ*lԭrc+1]k\^ޭZq1wMV;WD1큜R&XGke+UwL¸ry@sJݨcL 2?a0(CRQO%Cl=, "! zjTl7GnXVvo{pn_/ѿO>4ddtCKK!g{1\Z[K>'`p=9S~aTU*{r|S[48ߐy`+Rh #Kw^oϟ?m˗/֋؋G@}'8:[|m֜}3zj#[&I>k>oI)Y2'8 bg[J%@[L<*d`cggHAA)^ꉶs"9 >< _iՁ eG 7Xe3W>W@;3QU; x$qtT,gW\&ҫUK78zhk6~ 8YŒ{ՈGs`<~ous+$R+IrFqZۉUQ-.{a xh SV_Z‚\=|[kT0+)9x>>fF (2aϡzC^gG;ҫF\^_~ٯ /nj$>:[#!~^W;cg&aYw;DKr *WHSehT|$sxP|+1C ķ |PA}Hc,D鏆j2p$q#m\59AqZ9yU#e#ZU+Ks;1&Yjqԇvt m0MTN6}7{Oy|V?YVwNkU '/orUYK$) u42ɬ͋;Y[X*>(ϸUzEK& T+-9?@+mr q7SxB]=)@u0i_ICcWr]H>V+BߩU ܐWOd~)%H>d g'ը*ۂ"jϊׯ.Ěp*+i;ѪwG!;q{Y cY$$ݿ+p#o><U!2kf+>xQH^cOY XgƩ7^"ATzh:eвSgn35bDqu炕k^eƭkޘ Kt=7[tpɢ 1zŵƈzZQGhH1^<i s{tGow0mK-Ӄm%2uRKZ_n~֝Q''MI2|-t[n꛵A O[_oamWO*JԤ y` IUOƠ7fK{W Яe cP'hö5YKrtg?pR5,fECcGU5f$RVu~3ףE{uZ߾$.(&ޗhztSHL=BgHXޟBf;;1;H  *Hh=ԋ.ޏphg`}p #zHٳ?<{v}EEX6ZGAkwl'3éG[6U͖rE_6y1֑O6l5ooo.I#%AVp 'uP0)pfisXZ ;eǹKvƤ/6JObݻO?1ڋg9UaR=>)}T{P*߳=gc=(@!'Iͅ&~o?|RwrѓaoD_?kDjqzvP M˰w1c [V7f'2fbt;@:A`=:>?:; [*P9Vm@XbzZLV#sxbq`8 힚Q0 s0ITrIN/WV_(N Uk(˜~*79ZM[ io[xK|PlT7VWwtl vME5by)'o!fW̽YSwYM{µߓBYa2X"VI'm|5'kS&OLXF8TTשSOLO~`R$HL_cf D"\-G{R<KĜ-@|m_&\wncos}5+Of:Lfsa6O)wzbnk+NoǥڦD*&]$&:~rx8 Kw码^'!Jte =H'=4T(|i0eqBs3 I`j Xb`P=H7S/&XIVP3*,QJ ( Z!7`kaX̩Q{g;"L2$ B-*Tz}S]C?'zNg 3Csm ?PDw7WmL΢tj\&4 xej:pl " Lш` G iv 7D ='p!ƺxl`8OI#..VXXhD4'!fyj+9`z?x6^l)>L鼳l.{{?/G=ġul`tuvIh%a׽CPsҫM CUy58 ;6jS\TJ˻D) o3SL:r;a}53*Q]c|N *Pϱ O9rj`,cmz1\@ǎFq=]:4LEO\ h`G  $  #0I?h{Ճa7PߘAu8֭J u%$;C!o\v [j3~Z (~s gE@9< ؑrYqםkgk$'"' Ze8jN:F.67Ux[\oIXHgQATJHlb) [uW~tؽQn"rcVΐLb1]8L`!}PD ;hR\J6g?=l;l.|=)0;@mfFkH&"$bz ;Qs8bkڒ \?^hykyML\]s9S|v'xBY1>~/s;| x?7y?{op;Ž,{Dl3%FCZKț`30Z-3؞b1NY, 0LC*0%mb:͵JqH=`p!7Qk('.mx H~918fy.O7肁Ȇ52z0?xAJIecIȸnN-\O=jO30+pC_6Z+ dkbڲh4,5=Be|#z6ʫNZbf%{ ;"<E| (~4 &5|v]w(wsl+;D|ER$ Wl@H=)NE>\CO*ۃ=4z)KTzPXA}7?I @ _ݥ )&mDTbQsˡ AQ($}A[! CV؝J#A"mTO5i!Hd}Q`il$/L@ApqćTPJ Lj_&!w eAEqj)ՍH놲!Y5!.'2Ԕ.< )u:&^9pQnJJ}>hwgV3l37 JZLM ^5;:++8nzxw<@\.W@j (5.[usccm5fjgFXE9~cLL<3gl.|-;Mh̥SS_pώSpCnxȘ PCg~b]Ǿ>_Ǫ;M>^'Tg ~]\y23܊s vr?Sv3oL; \Z~,,,e  :{-2o4avX#91Tz+ԝTΖtxCt.WP+} :4&- n t?V+{UQKtW9ajK,f20q+!sPh+ʍ0&+œD(naڏՃsD/+k۫0o?EJB!nm \T gI/ۢPT# Q-m;=ZAϿ26FmY^[KOyjk3+|̬0 +R3:!.sV6' #+hKg( ^:a8ГqRNgG?r$5|y]I8Pڐ^7`_s A_OmerV1 *R܉ H{Y@֊2@мkgxO_23 Bg n^̀8mq6sASOz0Kuմ!T{v/"2'S!Ef$1.5/ 4%dY3>&mmH}cδo6fskqg$N>ԵS `W/^{`\f8\ }"5va ~hǂa'(BWxouQ . _`1ގGGR;Nǿ:ZT})iZ#^jjzwR?娤i8n*[w[9-EDť7eV0{*i7&aD;P2('NpՔICb~"*&g;ge'ˤ7C΍)R%P dHzdnk xO쬦&"Μ%;9R3ewP5cI.u 0j3_y9&cyum#q;zl?܆UĘP}rPC4xx@$S4OBT>hp|."HfΌYM49./lh &k.>'n_~mj`UE-l'VUI. "hsTRݪe5:A5 I#MT -r.[Ď(-^|e[f&5N#lJ`ur1a.5c\pm CCXiKcZ%yU+vI$q2KvR=}r>$X@*; RNnR4qp&=0?DFmrtpx[u 0XX dm6Ŏ jjXpBͫ u (!NjЊK u6-g3g:L0 _Kg o֛䞀_ؾ^s4ZA=9 }DU1,Ņ/9*v#” fβC_>."G)^G#n(g)~y3,TxZD`K,RC)ͮ'Y7۪Z&nkSdu}n&pfVҷY40n}tQ^}QTTgM쀇ρ/.bE X&G /GQE99s DřFxNNyqQ*ś7s4[#¡aO6ͪyֺZv : 9gfD݁8v@8s:UTuRVYcD騼*  Y:Mgi9(䋔4x1KyUb+:rŋ^t|4[׹ F;G&͓-E7| ?71^ $OOs>a@v ^fS,[^d~߁ ؎yԊG^T(U{nk>ޣ+c(I³q[|tc| L C0Ŏ,aN,&wm4&Z.Oa10f^LP=`*(>L.("ɠfbKBVܪ&6_I %\4B ﻤ^eg4yۓU1"^߾R.-HC?lK;#6_|wm#683?#* p;=7Fii"Mi\~EO_l rK,-+(Wz5gA/i}Le67xw~&9 ͇jc\Ll?'ejl7w0]͍ovq/J]\OME2R~ԃ rę.]t<)85S2  s1_k|hƥ6?گ[A0FG8:;8WNCZ^[wգEGi*P%u9f9:V?Vw*DƲQ׋hm]J/ɸ+(-VJE6(K8P!heQDsb;,hV0*ԅ(8ƃ8˹+h-9>;r4; :_Y 1yt.ƘE(@4@Ua 4F`{.[a!QX`du8EUP #c Y|ãƈwii}MׇE.ߪ-wvft&btCXP2MC20z>z8 ~8'j4l7C Qx Z,Cys4$Ew}4A AL ]S!Wɚ DycUz!.Z~:υ'/4v#.CRjp5eP膗WtuEtBAڼѦ[n_E\xhK+yme'*}wZ9jsB(~SM]0bލ!V3xfT!C;**2]DU@[9l<lkOFvS3w1*) ʨ=v>TXV?Ca6bǬ [97wt2G*t ~쏎 /ő0)irCT2V\7”ڸT?O~c{2Z˅6D!'lysƤ )/wy6y>=ޮ6IjЮTۯ'Ma%ׂ!y*]I^?zC)$'gSsgVZG'^E͸2]\?!U=jDzj\®beaQ< ME9 Em j-x]P~ɋ`(߅[]X.,Ÿ<RE)o`mzCi!Zz \N i6U{˪}<ˍXslki`%9?wqWә:YS^[!,Ki' / ʝu'_.%~8\ G!NmdWssC%wiwf{lCgfҍv.aHƻcl׶@aTÝ36_ܺo 25i.գ5[ m=&v E|`_H :q@4G%\Ca<s6à(U($Ipԧ\.P(uETQeq!n(ZH0Ɨ`bмj}] >llگlӄŹ&|( Wt(z76F8i1 WJP:f7.!hxݍ|8$k.Z]~`';0Z cD2V6`98[f )5W8^:bT% IYlnsc 'ш IÎ-"< k ,ALSnc^vS )ºה|OC`Ԯ<]|8.G G NߞDNJ3SbU<&[qoCs!/WFt+ ^nLp`K_>|>jwDg ciId)%|OI&_.4v"\!(hv܂j B>z_ NA8Byߗr[tbb`u ҕggNxEC?7Wn$ 2GPsZ40ZQn)I:6cڜ5 W&(o~Ļ Exo^磲.B޲rD KkkUA2.A5JClz=>REC^:)}@j^ Iz_X++.j.sddq2w"? с9+"E^PQ&sQ D. yR2 #!_h :?SҰȂC7l_Q( %C+6..Ch)m9K5>IϜ=E̔b=짃5~9P#9w6;iRI1k zީ xakj{jY OJ169wk{\*E7;igWIV3=:We, и \0saX֨Ipl-*ZsʙlUZb<)KCDPAq$V 3.5k.LJT $kQ|$McSp(kr<#qiD'<977UzuVsS5wQ?Y*+ H[?$ݬ:MloR(\.Mzt+drqLi`1}}bl܇\^vLB~^.x&{9XϚ4aܲ#&vǟ&Fׇܚ3b9w o#zMFCNHmxSDD 1ӤYP (9T}̹=Dr/-(/8_zy̏#V.յU.o?' d2^ ,D.VV VWV_e{~NHM$a..Ay]'|LlGȤ^==-|RXzlT[JRK".]}0f g,U3*KJ[>Ӟ];VZpeʰD^ĐwF熲}Vyw,%q~w0y4hД0v[@f.*#*E;y]t/N)ft@56_yW}g?ob;o^^q?p@~;+7/Wv)g ~]ZL{G6-xoA4=f"y K`}R(kuw 晚] t)s'FRES Qf0¹oެ>/l{vôQ PׯW hmU5~"ͦ,"E1ˈ r"uHu) 1S,_CjKsAFh5JkVVQ-a44^5hB2N@KkӨ0%( %ElYO*dxTZO#b}!ր/eIRi-aiXj f }/#ޟ\1VǑkAz!fn)VP c,&(G]V 20H$2 JJvHPC^PT@@'ш2|?܁tM]4N 3Ž8(\Nv{sOPhQ)iQ43}/v$5碊AjCW5-,{w$" wŞV24Ulv/B6xKiGL(TZn/P|cB1\@BEApB5^K6\G'`<7XJNMlG|O6+jqoɼ~_ +٥ ߠcs ŨvU98JnMh|J7%YE\iw滵UVr%?<,"#RRGD׆@4i[nZou3yR8&OjPнܤ 6 Ē#)v3nЫyv ZT{ʶFͬMͺ?XI#6kl6͐*69Y_85;bP%EA; ֒_AuJ $%wPu$DI-Md(yJCfES$?%R4.|YT[GU}ծF;?M­*f^/dvM(a~!ZnYumQ&W̵M4F'`FRV%v1J._&ʨi m;k8;zRݭW  : 7Y?askGr>J Tp>>q%S8dUI`e#4+S7PjYOn_-kyΖe=x9&i.^)!g"0 u ~ɐgERA>XDBD^/{샫BђC<খI/{1X$n8PamC:2?ߤzY}F`ڗ#F=tL]˩\ϿӞ=u* NV0q 5'؄?ZW2d:i³!*12R91ݙ{#>(s#zO! =A\oyTXẍ?#6jsx}lL QYƥXO"Ti۝ϲ'aLO|7v|l|&cʻ#f{.gC;I)U9&k [kdg jqIeVAoo Smji\:wP^W J& d`)AaƋ(4I+}R?7ןQZ|1$I4%%"Xk4@3_ҿ/)W'n:xbv&6L:sOtu;rnK/t_t'ȱKuQ6a: gXO8hAs tNzh֩*tk$׺RO2:#߻b`YI5W-ȹ r?)2֟*rp{<gdLGR;eJ»6[g썵Ƕb2ME=ӤN\ gSzWbMx1m\Boz51<)o,c <NDX^! jURAd(44ƍ)p;q0%sQdzL/*h v8uOx!:!F3 0DZĀO|͉*c6!=B=aʂ|wUnAEMt ӱIbOKX5]*rHG%Kd> bړ$E/ 婼Pb{$&۝ON5SwAb*mnnS|&9+:|gHc X+͕+:}s[-q.MQFi/ t87oZdx|!)_Ea]zE,EIe*c_EWʟEؾ{CwBWDKB^%FW+J'$ bZ99X76`rE1_n>T+{ ]p^*6e|1%#;醊%x_e?W0T^\`=d2ӐxUC4//z׾ N4ds-o tyDl$q%0Q'}(ӆ- h{2.`^'JmFӅB%e Nfd,!͋Z}cH"[)WQ'*bٹßǢy7gs7o!9ŨȎڟQ*ٯ:޵U6LZ6JX. Aؒ MRa)=\ J,H]$o?4X*IJ(f~֊J #μ q.-'o&SP:Gҩpt KEz虴:ؽ%E1Kc%]|vB\mH*] cN2~eXwPK'+@`7(ܣ1< !#2|Pmk)MJ Qii5I9Ps嫝H݅Z=U\h}eD!wB6˙ n~IE.fwP5Y3L|]O9929"(͑޿X{WI~c$A苢j ($sΆ~d2G!`4E>^*wjϥ?,$=S‘W N:=4DSSp1q*=dP2QSpddP0zV,4\hf6W&EK#/Ɗ`q%NG蓳Q% ls˛S9B`˛֨{o5H Z/, Ӡ QJr QieSjAQ?wpEErgZ}\]OGk͵Є]sv́թubX[޴X~_&#a%l'd7xXfy<ԂZdɍ>k:UuԲz=ZrVl,\UUv_|¾ʢBR !,z 5TaW7-ve_W)JTҚQUW6@j˭}gʠ?aB4 D^Ogw +f[k%f.2h1R`i *,( *"HE7]IBV27mTBE#(gnrL1uˡD:j$u &fvzvRמxi00P,F.#q -a؂C-":@큆&ڶHةMca?1!k| l (;<:f줎/:l\;ʺ{~dZy)e1Qi_] h(gBM#|d-OO;$(Ԝ0괤Kog}D89zI5w_ SZ`BjV^s*Tn}=46{61~qAw(^4 '*{[w쬑hKCjVllxǤRK^{2!VHҵ8~Ejwi*H5c E$ I2?{1pzlU-@wWq4Q>rAsIUhκ''?^{|2<V;qϰw:$]R۱ )MƖw|tCLpX18k`elw'$)$Xz.T0_9n%qpH^A#`X_ cOnc\Ehp閡;A4;b:uG \1ZWywt|VY˂jUeaKڇXr3s* oi ec XcGJ 1i/)UuX uYBYĶ\ Fv)P̑&V0 yTC&oѨq8lӜDaϪr%]HB=.©!L7Fb8 Ic1"Ak|Tw #AVP 5)DWtTfmiYm.j vabXU@ zG3*}̰Mq+bjH_p 3 %eBE1^ĥGR-+]Y=3Ηxƣȋ)QPӽ  '|`Q:,zګԬiK jN4O2zc[{H)09NE)C K,,m-lv'7(}{EZW;8Di0')6HeQrH 63j6ya1bjO]ǂEgjO_U~hݛ8C%l|-|niTfni  x? !3R&]a@MVÑu1M,_de%ܬX98Q.V`1g^')ՍYB0ꇉР ꂠ82 fT4 .ybl-s#Lrd׻@XKqZ:%EYzT/ s^H8c6Iѝ:*oGrϻ }# և87Tiq$p hE+o2 ?~5 wpe4o&+}HW/:!r4 KA."?e[gt *!1(#n,9|Tg'Gǿ?ic֓XONOv۳$ V Ulwg4|+k5U2U3nEEotyOLE90pYA]u8cnzD|dhED;^vޜuۇrBMps|ttid5ʿ}Z:ՁgkjzVzr9O,n&Y&r zhN2H ;^ ^z}tWi6t2OTxf-RH?&mt|pIv=;׮t{x8@=x"rz$ `ҋk[bK:A}}! :F"2Y" ̮Ex#ދȇpCi:a9V@;EMXPݫhDn!uay(aNGRa]u`xK^Q` ejppGJejCy Upnhc|CrE6QxjTP͕s$esoՖ\Gml}^95kLm]v T+Mpf># ylw2鋦Ku?[f_:c#xZҎJX _ δSAP;Z?|r_!d{2'n~ Q/%ZWsj*یDMKe6~bY J;ƳRfyHnc߮D/<ʒ=J+SUTi(Qj'Q`0&"$LKҴ1Ӄ.UQv|f!Gzv]zm˹ڮTHA!zKa}sdu?_~Jш*F#f+vfRy^LLQr&4d,b5rfIE8wʸAvӏ 4ݱMS<[H.aەֻj^̻[?vԑAGGóoE&Ym JTv CtjOXgԘz!JKڝӝ7Og2$ȶ < DJnJ5sp=++6˵s~zYe59=Z(wfUYsW*+My9*v1;;c-PhOZ|(S!AY aܤHs>KSbB!Z<>\t㾦rG֌vt[VqS/lK'[nFn"IB0p-'Y;儹l ;t"+V=u젃ԚMQ={:,z,šgNrW0k3܀vRY}RwRٱYU MƌP/BHvz$ɺ˗Ho$% Kh@E8sQ"H{@G|3/2UP'.1zXsUzڶ"Ε 57V=h .#ԅ%cVeE:n\ 敟Ze{4Ovfn섗y:E7B2>Ϟ2?q= :]SR!eL|sPLv(1i~( .uzb.vI5@.0LME>VCE^gU8;[8Sd- B,;Q֗f|mN:U➀-qn1yހxRdYhX!rQMKO`|24:&q5du&RRehUTFEp4yNYCnG`0=*b-eRR)/yڻ[Sys*~N))} cTcGa7۶q_X StP~TpJ a}٦}N` "A?&]Ц4ս&*ۇbA.^VpJN{OQ؀DI(f$ѠأtYd*X;r z6)%;!֩Gjzcvߣ]04I zeafY.@?*;h@Yinsbf!qZ;RZ¸@+^ :ґ SԒy3f) U\Dyi DhŖ.hS" 'S6p*hqIT$ƻm },HrWɄu1zq1WȡB-lMl˓]].z MQYPF{ϽA̭.DŚ =X+:W@[xoGBlKNEQ7/g8Bчw=ž[`A20g JˑSiH]5N9j|$OYNl4"z %x~5GQbK7 ruIrIIz=$ʞt4Bwzw;<8X?e*R3ְfgopnp,n8cJ F9׬%%we|UveZp+)4_{gݢYH &إKil&K]"|UټfQ y,AwJNjsacW.xs{ʼgu :(Nj=>,xhXÒKpj"LOߙ co~C\-[y} DPZV7@V&44BGq,( ϲ@N?ȗ:a[ Ln`-T}zJsqb6@4cr<w*G<ӭy[y0Ky"4D Œ^&V!(攅̱Zًݿղ #xY[nlkaʎ 9}3i*+?C4A6KiBˮO)f"-JM%|"Gb˦uE U#–ʞ](Yn&9H+`zs2U]rJ33Tt_FQ\u AnܕI*n0&n6'nnZE5TL:U&j;Gm"Νiv_Oڇ^+"+DxBnU 5i\#$BNkvUpΠoQ+X6j=gela~0/xh3Q@SMMdF=UE3g8h+t; `$VX"FȺPoaT\TPrye;nU_<^kt1a֤WSYTG6(I[\ b~CdE6FJFP*p2,ȇ5F]y.]b ަ t&|J~LT ȹކx~ '\?G9L(_)!4޶*\["aDiH6cTDzO6@I-Jz㪂jC+eQ3#'@wZJ[EDvDޜ"N[d3+W2ƌa27Q>IG3=ذRU{7NHQ$s6ͱICú#XLl"ƈi#J߭7 d03Sc"o3“Z2Z'+R/NJFa&bEk2n5|Z(. 7dqEc6c, nsb~c:y[8\ctq%j0: 62e4gh?(F@#xwuA;I ߶n>ŇX=C <-zbʰrmyB.b\e Au2);B o`t5۩@ \ttW^EO!Ja g^V.^Slֶu^ʜPAo/ omɹRW.#6~c {UГu/'KuUc k`sNvVWʋjU3n}+η^$Es+4h| Quo0z"Q)С0l~ e"{tR~hܢ%6^*L}H}*)2ӡci1%?+bsrItj]8_ұD"z0;13Ovbܫ b :R8ΚK!W>Ԏz6 #H4>:(ne;a &vr=?Z 4Aɗy!%ڧ_> SbY~.T}(8\UFbyRs:spBqJKQb[=\sP\_E8܁+A\i)P쪩5ғ9m;)v)#Y9YQSϢ#="ۑ<]ՈkqϤtaYOާuuNIpfoE-Z|bQ~'Yb llJP P%왳:ƶg4i8G> 3aB QZM"{ )Q.Z)8@F9s|>+u~ݢFͣq2W]JU^< Βlkd϶bDP8iRMa#5f3[ZZua`<fxhșYmv9h-i͔#`fȴ3)g>)]aJIr%oqqri ߌVY$d;A945$dߒE'ڙEL]\ 1B,]؞:ܫڿ89}><~ @)c㝳םý7{4Szo}6woА?^؟4nB٫"QtG#Ozni8" V(wFA"HJkWAh&S F%ĩ'7IYV\Tu25*ea s.HIr-LN{2p bOjCf'kېKN? W;9A7@MO@$g}JYUu rp'Dj#??y\Yk+OQ_JFo|V'=Կr&mǍ'wcQ7NJ2tV'u^=INC)LKM› UWvLYy>9u`[ J#uOA[s{P}Ff}5er@PV:|-ܹY m66I@r}U^h 3P v/RZw5BW jH ecQNI>o iWhKF q|Q89`U+F554g{ /'p EE Kow,F׀7vd9I ٘7ʓ#p9>7lkͻYONNP'߅'6+J27Pt'9 |J6q8xҦ 9o I~ϟi+M2DkEQԭʆ-uIp QdxX]ϫ; D+ mnfƈ1ߓ.ƒ~aL|SPnxGWe:z0. 㳗L.&s]+,ÐJp(tI<̿5bNi`00+xI5HU#65&cT/웂rb= *I!9CBgdDGY/Ui\B p(QЫxKՋ0? 8,_jfHA`p`rhSdҥ_e-ttM/gha. J{ 58bRhM^B|HVO РvP+8⭖: p)ok0- F݈SM̬M)mךZ8֙"G'~` Ĕ.?_]T:4E}WC0$;_GK@˃28 y.ҁ?wJZ9灹2]Fg㎩:^aP ~9R{k|ذI/_j!BzG?OL.A5Ym|Ixg<jupǥ?a酱؆u(%:gObٯT'MbFٞwYkY\&浿 w_wL/>hjC0ϥ8&74bI/(mǨ+WOJ! }YIZYzvʘK_-P9a/y3Z[Rh|?}?E?٠sۓ=|?}?ock4Z֦pxEǾS 3 &܆8CP) [p~$ 9ܯI 2msZ}^Cc=6 ^hVv` P7g$;2.o'AGd1Qq=^tнE:c-Jva~X1ea/䮐D Ll@k@pn~uCTeaIZ|`°%8ankfS X$YpQcx$Xɶ7 $S^k!T0(AOFc2?<|~VtŤCpsW6AG.ꎭb7pl2j;Y \h.=D{nLQxe|yOхywXaj3i"<,ȣk S!۶X*Pq]+Vh#92HWy?<5+Y4A}3:"q*;HDW=@YQtTTnF1|D@hVaH]YtTݕGA3L0ϸ;cy #)Gc{j:JpP\qj-R%n|JI{^:Uؤ'O_]Gw*4&ФCzhRM=4&ФCzhRM=ТZCzhQ-=ТZCzhQ-=P+ B=P+ =P+ B=P+ =R:N=S:=S:N=S:=lPA=lP=lPF=Qk=;azؠ6 a{ؤ6Mazؤ6Ma{ؤ6Mazؤ6Ma{xB=<PO' {xB=<PO' {zzz{zzz{. z. {. z. {R]K=t.ХC{R]K=t.Х(AՇ.УzCzQ=G=УzCzQ=G=PPPPPPPPЧCzS}O=>ЧCzS}O=~V& %ZY|D]w1+ܺx, N%/&aS+ʠIcrb;\I|g) ØaxX NbZɀ-GMT QPVk,&Eax, snLX{Ot_(>9T| 'q{*'8 T^3v-aoK֜Oh%Rf1Z6R~87fhfၐ(t?z Ol(0u3T)K53"X )OM_>zz{#I2 -#}8 l=YhFCT5N; ^P5V4i_B0fb#QD|4'o`Gb)=``]Cд)I&2k[q֔e/P+еGslk8>d|y M) issH1lLW(oWw~۔h?ؓpC^i  Ab9+,*%iVNac2`@0D:\%5bfNmcYne|-Eɾĸ(o&M6k3:#3 ]9= R2W23UڼV8rx d*J[{\A l؝ ~R;%3uU#0@2wP"g)`fԺ̝l~pϡBbCT:x҆;ƬН$vE ]qN2De)H[p Q|&x㤍TX A;\̅'/r2"1ɝ*NI- 'IA`ow2pT$#x^l׺.ɤ*#bWmתv$= ŜܤͥҪ\.Xi JkZA*[>aL.h>6l Gʦޯu[(C2\N[]״e%kw dRI",i;ZHt."MDZh5)?B F*؜~B@gCu /wJFo(Dpn\8jH37!De 6(͂mrZPղXpUj?M}- kk^9Pצ-ێ"6r̀*(-sa6WeQ{º<:Yo]VGn*i.A謥h1ED SZ)wS]{枭?qg2ʬ~p*e0KԩjK[B(HD@rrkhЁ;3oVy}j;`m ` kV0;V'77<]XL 8Jk% Dx um)҅.Z-x}{!5;^"'5aFu| +eaZ= ˿?jM3;lZ;VT }m:rK W2,˗!960"KX#6%)94zuEŮq2@w_Bvٳa>qyj[8eӛVp`M +i3mDDse0o} Ʃcde8}hv鼫e62ۋf rvEwSЪV2DY Q-=f2rMyjS÷Q>B]gVmD70<˒XCE(O_o_sue=u)(KcA}ϽrZk^cuZyY9 !b9 "f ^q>kT"7p :&_ NZ Ŧ;1QC _ۧRiC@ @[NnM,yKaqfxNZ2 \O dHqj^E%:\J8P V``(p|ZY][|bwr>ლdL wk[* _ޮK?h(H\wӟ$W*֛gТm $8 :$@(UQG Rh|ZS&t]PB@A%uPUfѵB00h*6Q% *P\I[5 |?b7Vk$ɔs5&EB8Qv >8D7j\F ) RSnwR9h'N^kb8(=K$=@iQ!]mďsN&eL jy|٧1mGiW=6Hk8Yj6;m]SBu_lJEr֊/^n\SFZ|wa-!EC@boW䚶֐iO^dlAC-@ֽCj5:\6|RSݱKHWGNVٵG˭400_kXמ&O3H|g^-gTOG.+W-x5!a4- 3J,8V ^SyZhdd +d=ɞyl Ǒ)#m-5-cnoKu$xjƂb=)6@c+pXZ]F/%g4v#'+DuDV5g#`HxZo9]喍>9=mn|R jN >_b8VDSq\F DP3T!tdyk{[r:6Vi͟o{tͯ"n"cvm55ۙF87;Ko1Pv E bVvWOd9dT֙"h1}y2+r5jg\` עst><==@QnG1vswX+ ;5PA픴wy<@ZY GaOY#=#Q9qdTPr%EXuY_ܲZkD}NjBFCWj v櫎ㅿYoIU !UO ~16ZKC>uZ~@^1R=0ځ@ HOq>m˛5> "VAwU`bEN[A8H &bɐr_} Ԥ1k;G\G66G%9*h*#@VQ4:{ @_+OG`)~аAp$,ĖN,7琻dIYxȌTg==K)- Am4ӆ*?& Rڥh[.6o8N01 CmV z8/U*5N]_h{ ?ɕ?+f3Yk|?5KCQ@=À|W|WoT(l vd,amߛ~ NM{NH)NfP>ۜ pB( uzdtK S/ -H',{G_妣P?/kS7(Q-_<'^dh.W8a l2N ?_lN=r¯rV o y>zZ @>'Ģy4z?NhF̴0 ҜІ;~;@N)~ب/}s[\fhs8a m2N償 Ѡv '_Zbߜ| ꯵gr|NE8i~ЌLi9a9 w@9ai?':%)!'SVQ-_4'1 <:p 6N%e*'V1 ?_ ;K8&xoM@okOuJ-2v~?>0+Jjh)W^/Rky+Dz6urݕu4B+J,+M[_wfn_hgWf[N!|'/x<} P?tOAuI10o?|`?#/S8-Ql /|B}*OO^T-s/ k.1P^7>|=4K#A)QeeHPtCƂ;>d6M@2ȀؗU34U3iiIh.`Nasj.opHOmH^+ 5aKHDG=JECR?8&:" m]C&;@ZGjXN:d>9}}~[kjU 𐄻gg{o^t^켲$=i}m4{篸nE$j2uo>{?$٩t+?Minl] ]?K9{j8v RؙFv "zRi~;m:9cT?7.$eQoJօEzk"KGĜe\=ٟxD ̏=b+>~צUΰa;5r8I[Ɓ;ڏÆ8:6\FQr 5\0lGIhU9mEG.88YΫ-[u.B*/91UO %|]xYg\ {8m(ۮT0**_Ec0HmÀBsH`:n/^I#-(oY<:6ʳ/c rE:3k3eRRR*Јn*-zـc`N8{<0kk0l#XiaXNƒL2Y˅v|V]㾃M1|8zKo"7@ >} =!\E{F ?芭 p 4;`w77.x20SJIEԻ㧺4![JSp~1UvCVҦvH"*Z9t?"U Kxj3.pH(p 0Xvn-x\n38'cB3q5p( H J5$1ctW' P}#6(<W1Ҋs xf˷T_ꕺi*Ï0IbJA;uepҞe"sA5  1)T(2+F0IpsB1f,,d[c9Dq5Hm %>jEYmɘnFCc> "<::u޴^N{FaWJ1-./9Z;hW I҆ޑd$6&Y勺@PO`TЍbIDWp@TS+Эށ<&Ʉٴl)5ve\!0BRX9u ӭ[,_񙀚ËA0VMW[B;,HWk,Wٽ(OnUyU T%c>7UpNx Nt*+upJP8n] CE3LӹRU}@.ZDN׎D V%:D.Pk,_q⻢}yzs֦'+oޞ_i[E%V}s9EOjV_KQ=E>_ ,svX~q5Mn%=150-$ @ąAP\Pϝ}

~~st !7 6^UpڕߚT&՛`T5cOGf{@~:psXnMA]蛦H+T&*>U3:;j+5[!G%>h7U 8 mLo60z1UM!\^k G6Qcng>$9aGuoUHJŠfB A#oU K1V*y[f Nv_k.[~G2)U!2`@'GΦvpNi _ tyjOB Q,yH0T@k+Ij:vq0QL/Hǰ<2*\ht>=>hԿ2sZ8(4őTqv|^NWhi ?T-Vć<*hE'B=n+Bh(_k?~G-lQ,Dfrd4huǽ?2bȎiq*Nuo/ ƭ]9%jՕ7:ҡ=egv9/&l#՚t:_H|c2lMeNsalZ}# 禍s}<1¦4-ݜL j^(qO.C1*޳TY[7j/ T۪['L9}Z\m;9]IV97\IA[#o=>ot iз+27 9>F#+}XhhU{ڥ I0&djXڛ7:К(v/{<%X61N=v#y{߇~B3wrAw.lK⢫te!V`5ŬԶ*e^*akulaYM9Zo s!P2r q?i?xp 5`j糵ʃ 楖rk-1zzח2떼#`C̖sYNI7a48/~dm[|ϸ2 ipc&# |y~aFĞ3+bHba z.|Pik .5daymbd:5}󇑗LWtg^Ud[U"NjI7|<p%8q@$C%l*1 0|,* 37W6(sR͙"ǭ^7eSXA 7D*hr+urm2g-f$}2씹* q0#ޑ'wVFE~MT7>CG}Jfh!>)x(cPs!J-HJH}*5ee Q "JnevMPY BFOa#nbɞGJΰi%1Sqf-(kvY;̒k=Y3Qkf:!:ĈEKs|!m]>:rkG{;ٯ,>>f>`}lyyrd"L9\W$x#!JMM%eT*_34GJȟM=mmQf/\vgu6ib YɅQXG^ISH)\:kͪ`^ӈYF!|?/fa+_8/-E>p%K3Xv G{>%t ^ #ZdVdZt}=y^XZ}ī\UQ *oqw80cNz"bWաVx&b7>#T !mHLCݜ}bAzg4XhXɈ>LAiG!e bJ'x%W4)וNѝ\meX֑I܁0(w|=vg>qQV茯Z:;)o":|\1MPQBBT04U1Qt6FLc f,ʓ>UaF(|۬[?JGʻ>=Q5 gk+BPoXlF($B۪·b27#Ң?'*7¾!i-G 'Ojj/}C>?g[4K䁎ZHt+Dt̛ono66V6O֚y4Ŷ?ࡖQ^%%#8<>'7;.j 3Kmk_ eb/w蠏Lbz'F߆p]xIBT[B_p6\PbwL%C $V"f9 Tqp0f"e@D<@E֛w̖]tLԾ 9eK,gԛhn:EIی[vWĸM5+9dB-ݟql8 onuWsUx6NY(YܽR ě3)5GX R uM="(଎K^yY7_{E+fv]-S-Ysژt^:I8픫P;y:ø,cjQL%q4 V[oL ]oRltE k'W Ӓp\+68.q0vF*im\WQ`QCXdmw ʚb.*ʏz@[g ]{7{;IM''W误>}`ޯ_/)%Q?֥RI^^<| D0h%zeCr$; bCCoq9(| D8:vXXOL?5%bu'U;FR6`y=?Z}~r|tJck{?45 Rư@ F|I3m/Y)VTX0Y{utw*,}nt;˽/΁ N S~"niC3lAkBNzgGM#fd-.YO]Wlq{ia_€4G/}e ;͔^c1 Gg7Y/ֆ*#Jɑ*G?VI+ś ]V M.aiR/*VDE#y%W=}L;ox\$"gȄSЮ) 0أ"gKSgNsg"Agg&AD :qd^`ntwZ=PsvN$챏_ڣ׋WURF[xde~i 6,I 7[ZZZ]alhM[7 $2w M{0qxG^'l~bPɲS͢I Çs\';۫Dh#ѝ'0$"|֗m)1_!8u4Dn"ke>=* Ru`TMLwkZȧH,qIK@ECx@IC5`J;A@=NpRzwt1Z:qrA ϥKV/pb17-?ȁeV Mh-,rw+a<("h[ߪ0tÛk` 6% g W5oVժ@Dj_a_֬(L*taOﭚ7ߣ>EEޚCrQ+8xؑmځ&gs|=|kmmoNWBZuZ )ߕw5<*ٸA(v á499ʗ&զ()m0q@f>5! ',kBJ3fḹa\sydx%Яa4bADV >Z܌u<ׁ߳On%uerxCKWN oA0+CEj=ѱ%)ԜоDx Pl x+H2[eM[IyFӎG,jw]aP-x-qhC˻,P<yUq~ӏa} _[{EtK1҄_ZJ"WiuҚi zG*LR^gA o=B"ޑIR6IIj5|B"X*sj!k<QFNQDAvJאVy]ZѯNdr}@*o3IDn9!2#2>b_B4wdK}z_NҪMYDա sk|>Y xWX3 MT~dܣ#>QrڂYEUX m^g*vkoGRl>pEGpDrR1j^6(f#Gҹ[J<^P_g"VWrɟ2/_B13l>M濹4h5葈b2Tj*wD-.oU_^ꪀjiLMlJ)Xʫ^.VAdʉ &r]0vNw=Öt)}T`ڤzz -*\K36m3TW9qչ41dҽbxZ.% }$UhP;VJ+i2nK\D ZJJ ON{$,5#zՋ8 ?jNc]Q3/D~,z^͛{9c⃴@ڠƲs ы߄ #d8 54]L<^U%lyZ&mJ8Aw5=VTNUS\nCJ!`KLjC\?g@Ң'W~3k-k)ա%`v[JzX_~1o[%JC1_|Jp(m%ӗS9dArCKC7} qNNM9C84$tcExzfjn~8RqZu 3K'G!O-ggj/uյV:F?w?Zr J?A?Ɠ8~҆ >G̐AϾũd^:erPhI ~n))(^ȯ~24I y;XfO`ے"0}! zot 09q'N)Ir |Ri슕^2⨷UZ|ݶSm F)UJj$5l~m2?w`V8k.,Խ=X?u^uP+uCuP7mGs>4Ax)h] ',9k}茣& sEe@b$9):|8qO`VaM|z}"+H bފm˨>'72*!Ĵo|r%6O8J,يSIKYiVrɊEINj]Za+󒩩):䍩VdLЗQVS5,aĥRiL6x= 9;F:,ڥ Jt <ս9eّ"Ljfj@)p/,GR;{v䄸}@3#\-0mZ7, \r -N2f^ ,XkѼӁM@ڜ".\Ԗ,ٳA% /N4;T J; V9p.#6'lbf눲udAad.ѺrL/_isacz2s&p5W,Pc˨Pc ƧpІ΅'t_ H\fKJwU+G{S*Eyp1-C @, ž3c'B{JpstJ4b "''\bǮoڼCpԱt*傤`Qt㿟y.YvJn\~ݣ[};il% *3R7J2 v1^dW1kIf 3$UR WeCIHK]zNI)t0߶Mcy-A-jzyj:Z6mkJ:\O"=} a&7N{ke >?|s6{z5B;PnSql4 fxKT!^w*F[#heU;?;/vD)_G '}+bSPrQ=T*Zp'C5Ogp"|-Eg"F?'P 8rsLy٧PT?jlK)->_F/Ӷ#*e1*UBNFnyW$i!ak"rjq MxUR9X*V(d]"w2\AhNrz"`A#-i0.?^zger]0OJVOԼ&7MU1Z nasrSR(}as,A.:(Mo/00|͠ԻGo0;#Qӳ U Gs0S0(ghLͶpC-~c5LzZY_MMewO:>8?jlNOfxWB = 19X`!"jۼUx`#s7_.sh]ƧxE)BEr7K{fܖK(;ױr7DY  : ''foA$9|%^Jky@pF[/ZŹ2`j|䒦xoޡX_̳}FF2#lzdBBm6vg#VV(޺Gg;Y55hN=[/W!0<4u/8Y2K~I)Â` (#9 ɉDŽxk>KpgCumCfbnF/ :ma5~iOKp]FtՇJe\4ƳlDBѭ.JRYk!k+.JΞcj57 \hedqZdi_+Ըᐾ." !_ =DvFTC D*d M5Zl3TA@T^'F‹v$)bb8b'/;NXs/煽Og#T.@R#Rp иPfpgm ͐+/Ep V\y):KàNww64W9j_b?Wo+%N[SJb jtm7*̜m`Ifr^ӊv+*a@xg}ZjO鹐ygY{}g \6}9aovXž?sh\"?aBf,?.$v I,|ՄwSV;d2jvpF oH!sK#EIќfܴe\KfX,K@f1eL䀯FJOf<ґMmiGhGKZ,$ )-_@(0.GLp<ɭl-qĎ^e%RK} %⛇{~t>&FYm-̼馈3 F|{i#+d8X*/w!+jWN`D 5'eɹO0cP!FA5[~.rlʼnm`Mi 6؞e ԃl, rcA֬BǡUB=?qsVȩTDtfu%2ZRnT̫qޑ$8}&>7$CGKK Eҙ0^HBg۠T*F(3r[bVVǹGq)ydT;d6zgJb3 =f}84n(Kx"ϰs*bY. +汣y&%wK3uKq&?^!Yx!job1znG'g2hֽO-:NIG5e7m6&ktk+ht(I[12{j74¢-.t5! `4!?pnkF:oOϧd-5kkc@HXI Tic1s,)6g*iҊu@Q~rbhI`Xnc?y6D5Pq-.zх?Hsof?Ow:#%)e3Ϟn5y7 &85L%XSDmrORm e,/u>W7'iˍ&"$'+*p_CK߁}$xР?.hYs"azyA0BpO[8&S^T}hY0eDC1F5;6X!:5$q t-Nq0f@ p>k"]תF0h*zn;%~S΍47)n:"eeX)wD1I@Y5xp Ylq׆Җ5 ## < z'v_5T7 >)'ylhڛuTq[הS 'BR ՘~JHgK t.wYi_-/ow.\^_~K7w~=vXW{xvHQ;d݃2gپ;rNܐ٧Owc4ŒA7px=L yF/,@uK0qt͌!&f[t L'Ǵ X mz?:gDAxjq\i2h8 WBtyWc8"0\*)t 966!ʗdg. xM+o fT^viMڽ?/U h|`=y[%:|8k?ۮ!l Z B@Ō9Q bzA8F"dF ěBAZ?bN \rɌ(T(SpO،cE'JSqKMZP.َmz }qolf| SpV$%PNf~UzTя<CU۠F(Ÿĝfb55Eٔ<'&ooQf6 :J>@Et6$zP vh;I-l!矌50 d-n]¼ <,1  I Z,,-QéɻDp.kǡmq_ @6 3p~ʰk;4b?xS5abr!' Wkf~ʶA}oI2Au ;&`T$ozN.l.SEzQzCQtS N@;9X(쫄Mړbe7 BP9& 1qOvDХ1I0#SPyd\$BH#{DB!=(|A7׋%H밃 'hw (!`c,"xL]N.Qz8/ԡ#4|8 0=s`#}V]7ނSs U{pt `pE0^8y`+p.%l/{К2!,8 iLY}ԡ"P;t"O p]1T&27[aoy4Y㝌:KP#s`^ ?V4ɦH"}dH+\^wS)Y܆ 1W8 2N@Qӥk)t ]3]SJ ]q9DJTPjȩ,tU&\MWÜѫ/̋Ͻu7Cq ֔gE +oS'w9:y)&4x|xv}@3Dc>ٶ&@Œ$oypy 8xq6HN?XG?o#w] `>3`@00jFX, Qab^8KZ ʺOqg9$NjsܰWuH~᧝CU}r"vOw0N#uɇ^hHe;gWG't1:ׇ4;R,44FZqJR ŕ2 կJgDxigj X<#WsֿK NF)4d dXp PXC8w~ .HW͛q׽XJ0as΁WhAO:q'^dAR̮ BfXS7N\˚,mZL APl@ziEBK>m1h 9E8CycNx8њ"9y!F8^xMnlG`>L˓wRMN@<{ѐO`uFZ~ŷ(gfd|Li2u#aO{W=0v~nXXQKZ#?%mtyQU(j0lZʼ>TUcslu?bX€>lηV,KAoUf,wֽ#*qe5B0g,>ſ& yH}+~KaUŊ~.=z@_A83u9yӞ]/G(P[줽\uI.6ct\I7;?VkCx=`l;0=TbT0bN\tʸn;\ _G(<-EE;A0%r2|HT@4uZamC"Ii0sgŃ,08/:oرɹ=rIX_kڛ{1H^Z2II|sI[Nױ;n [E*Bv`UiAPű\34?xҞc+& x|毧DG c,EgN60I2J0j  :{>H\V h8\y!^yhΗU@ N@&Y;tg/kHY53뒔jyK#fU72Ύyd%1VQE wQD23eB^}a]"'HlWbE$tE'Wp**TêdM".bWPB]\tl|TK94r@cSlmHM`149K(hӿa2>d_jv(>)3~jJ>Lz ڗC ة>_V؃_NLUsOh՚;rMсAkn:++rYL)qR*󎲄I".4M<>m*uLL&T'P=̣)r BgGpBiC{)rBi;QS^([ r+ؒvrxkg11:ӡYyi|*TZH.}m i j<ޭpލ7f'/j hH82]߂6Z~Q~WşBU8'gJqs9Oe)GIQ=4Ů3Qmu.23e<}%.Plm@'sߢ09ΌC d g'G䮖D*,t85w,ZNF5>pu6МJ#G'y_?jp> >}SM;{;L@Q5ES6EQV'+T9::jǔQcM7/)SxNނd-b8J69^88{}WDN.伦 [=-`8(b^q s3T8X#5oSZ WRVu%I;oh(Unykl+>+^'d0d l UmVx8Փl<pWUi e'NqF,;=fzڬAV[s6 P nm#6J8~wdW(sԫz[Ɔ)b]BiL=A+<ŝ=IIY6|ȪjmGp6W%LysGk#ќn0k(W7*,lq MAСju} PK誵 ղN}eRy%m{(,ot;>(7"?I;x M=RnIJ<'Fhi,AاTHi)+ >*Xt"8 pM$^/rS+l1Ow~%H!D4TVHem >QDI'&@ax# 5#Ù#gHu)ˢXݤY=WN~5Bb4VDgG $ǃ߶WS\?ºŒ"I|&pzo+ x֫LYWtUZs,q+fz—TrQOiÞM8![K[zذU}Y)h)q,clŝqb$'M2dpk*ji+lwf􅉮&æaZ8P-=P>W>@ ҋ7]AC.kŃaSXĺu҆\^g>R|gUJk|ʨP{'PǒaSż?~;dC1LҼ _ omx򨘑clI`:<;Hhů>}2ECxQ.2"d#2M1aН^eȡ:ȶ8֥{o>g1u?,yH4ޱO Lr `x嫾$b78ͯԥ*)A;N*{ڀOչŠBQtP::<&X(qE8t6hLNQ_ez24VHֽl½T'dS}GIh :mX?=T }SYmd Bhzfz 1|k1]xO vC\߲dev*6H_&(-u6& ҕ&jdjsHUzl-Ե_j'5WjhFZ?maj©jF̲ώ `ͪ1R/E1Ρ0 Kg*ִmXruWTVt@뵏OM-ɲGH%ѫsH< +s0m1!'mcfb *vn'Q<);"Idq]m8`ثݖ>o[$OsTYqG K}T҂N>ЄlC<1;B65A()J̽sJtΑʳ9Sѩ_2tLAZNu]v Sͣ2ۆ,J*#Or, 缸Lvbm8c%qW(Z* a ]dWS 0zX5 '$1Iѓ6u {UyL3Zl>_~xzij/lv)?YHڭ$;֥jjz8{bphZ? -} K\ȘP/_rH_Wh~oh ł4ו9\Ɣ]#Ie#l\^jJe*}[iF9e_zu(/C+Wf\aQguwxaldpC?A\"ЂF؝Ig$ш҄cgB2UЅu'† 𐱦*l3xKkgg)$J,b D}'c*%\@( ێ)SM3Wٛ\ qد䍪֡D UT[L Tq=s^Nýܛ>va"?-@qSCVcCs+O(%M6V|$)Ȱ[QDCylC[]Kdl[RCyj.yX0Dp;DTRa]<ߏuR {EЌ\oi1t{0"{M@ۼrqآIIإ"D9pRZK1r5C-rL0-e8=L+8N'N5 >]' $CZ^uN߷_4H,{K!Dc3֋2m{Q3XuD]ODi PϠEB ( v6D2WZu¯Plۯ5rc%ўh-S`b:j'Wq. D:r_>׿kdOJ!3)dwIZ+G[Jƙ&7#"ovNS}$6it {heU2ͱ?6¯=ŕF_B̓" `!8{L6۲ ()5;}[.ѶRsjk%cVP@QAP.Eq| ܦ!P 1DSScV561Jo2)PZq4Ew*lCME^aS uqnkj*m"rhP͂{sCңGM@%fݳ8IIm< Ns^ȃJIl0JIa:kt !gL:3,Qɱ0o3X rDi":P#uW 7E&96%CJ@vfEmǍ PM!ǵ$^R,&C(iJr28E+C8%BkpQ3䄈g20EVlO ZKPR6mιjIe;D6BoJ51 ̥+B!ۚpb3VB/b2?#79bKKӍy\k&vf>½% I}x Iɱ ?7bY^Rh*$ny2JJ^&/S(ն";E(i%ö v2o 泗 i&x8B30a j6ʭ9Rꤖvs H㴗Dz+ tab8cx];g>An58TuEUW;lbo;ϊooR+Tl $eBa۫;9=;Ha g@g|0G"D bVJ$ 1YF)юPY T64xzk)T;,zXR8Y1~8 +;n avsY xWsFBlF~QYB!_k">Le[;4-Mx;\H/3{(3;z BML`ED!]̉d1e*8`<(].*` 8u~X&`O&4=p8 Be|jXQrhx'+ai8V3+ódͭ9g}K_|F)MlMV2'l/'fy/ u~>re3{"UqT˪ϣbҊigd}ש9dICIJ?Mư#U@4RTRQ Vg/mݔ∗ GH 8B;'-.!+ɩ^{.nBv("E7xL\OJ FP=&JBޅs,BrLfFZnFn?39ԖqJKR9#5/՜ &S,Sn4*.Ofӻʊqws8g2Z,w>s e"M/j/]G)R9I qU}FnSޤx_.if/ R3V4j @H9_U,G䪈U,nn="R||z:Ԉ'*/OluiK]^by}ڏ) nH),RI"_l6DB><5E0yd xG)r`´[)ٰ]t ddm`-$Hyݘ] 1pk\ uɒSh*q*(vFVVAS0I*U7GO4pM"?",o.<AyOΖhzh3i6[ Xkm4W^Ɨ~ $?Pߟ'MۍFwp {ݚj4VZf˓j;Ku1m(:|.{y؋@ҍ4<لF+v#Q|n¦?Ac7H$tZݑctd,VNjot@FxKZhwe죓,ZE7a/[" 1a7MhcdF>Fしi`ܐgv9qsۃvߜz O^CC'W;'{4 6w_Q7кU}w^+ְחgpX:<86tځh{;/ˣwz9`OڻguhhP~{Pp947;p\Y=z'3˓7) `e 5lK`Up A#*vtEOJ9?^ϰ5 M9,›hk8K<\w{a=uG }/̛q4rss}|4`}x>,7d~x,Z_Jrk :T^p%ra5i^!H>A3]اϝ|j&z7M_=`;` ]t9->NSnM4ME=ț[3JGL̛$ > +0Y;<8ct/ GgG7B Ff>ӝӔpNE<-=IQdpJu^/_yh꙱H1 >? 9̞ShQj ;$Xizp&ɗ?k{|S5A843088 ]=\H~|uoMN|Sk<1 q >iqOx /򿂆XHuu\1(s"Еq;$2#?N05АȾ$=  OfoAYp˂IϿ0Ύ:o(ܛ6]F}y )M{"=uϿG@m?GS>A%ԓUl?u3򚵦ିןS8ǝˉL-. G˨Ɨcv[ZS,ZV ϥӍ{K17xb a?R. ܱr0 |} ~ř\R_3#ws;>ø@ `\Lz7͜>>~oo{{?)vLU)S:_-ȳBA5˨: /D?/DT$#Nj#orsF1j_DgU:?#=5mN /`l'o(x O[O~ǰRȝs 1n'6x0@n>y~Xo95VmA<\ ®!?n>{ ?&?0Պ4CIѵwrc; ! !Dmcq_(H #S"dXmsUMuFpx4 -MN @zGdhʊA׽ O H_$f>eeul6BtpiFļ82ɑ<ֽI42y}4yd4^s} {~wER5\=O}my9c~#p=ڋ>|°` 7[9}meq0p1$TMעJUkR57{ݳ;$qNFbN3QN*Ϛ/a'Lvaj:<|ɱũ6jU cp:Ѥ8ꘐue }I|:dVZ؟;(qD0~v5F0:6EqjU]6z{~Fo[jFrM\FޣgeÕ.pb~V~;Aޣ8!HLCDA8>_FbmOrO+ FZi`Vɟ~_l>?ӓ ǁ:E2oHm]SoSIZ±F50A Mb*lpJؙ?E`z/U 8?k^л/lnzŅwMkrPu+Nq A8JPQɹ`x:!5ӳq_Y_z8߯{$OTo>M`ϟWWZKI ?~]@K nNu}JJ0~P+(Ћ1=xaǢ=m>|Fw@!vᥤ$NY?~ 2xnhVcùuv$B\0Av18~)YoUN'_.ōcڴ.C zBxj_6Vsw#ثu_ج{H =+ݍlktJP5ZF>.JPcktnp*mt}?{k\]o%5͕zs46dP'kfilr''+l^7p3єßfy4e7u{e֣)~lZ%jEAF&"o{ W{kFi]][󛫨}9 `%x*Y-}9{B7VIimkMVV"r'7[}Dj_ilfGYkk<= zɓ` f 6~kjD][_W Y֓V 1c53Օ?PYEUURQd'E\}mbIweDO6nUf"Z> Ս^(dmsukFڟ=' փF(yԫ+2hf/3E6V6V.z+~Vb"J~{E .6{+O<*mCOMz=uizDo*%e/0@ : SEA=)T9ʒ/~soM56юlILd 0zhQC<|zノz*kFZx]md%{#eSp[Ԛtz=޳]ՉRHvs@Wꪺn>agzƉU*i S~X9uNpƹ G5Rzȣ}yw*"N!hiU:Rz?#O.{~lsv7ƢWZ;Rp 7/쮼:R{KJM8etuǜՏpc:jpl>P8"]56_SE..m./U`KKfr8*Bri0 PeF+J\#oyd Ŀ,jVҔzM8ƝOmZ_ x=$=gG-НGu XH$Xc5N6a3IcWs}m}u=m)BPغ'h'\A}}ir-b*Kv tLUz~.$D˰c]`[ybJ#a֦Zo?\َq==MPjz]sCEiAsUѢڠ4%Q#ߘTТhL0GVyx{|JgPw*N#%a.;z{e!h*fp?AcDS6;ޖS燧*{薏I-4MnB괲NV3:W|` >XR|ݣsU&}F6_4a4Ő7<сMAtr,7s Z i~aW8~rÿU VJY㷩٣!W$!u :.%ŏ`VgeJEi$5seT,M^J/J_oڅ.3J`NfMԇQ؀jP* :BUl6l&0@:uЧg{N͈= R*`lgގ?Ć/81EwqSߕ(f-5`hp[3:ڭFk3w %y,Q7KbTC#%qBe7 UvZ䘸P#:)HK"fFc4B&ZGĝ&6ܾ9tMM$+{j&(^ ,~R;'DVQ޼*Zx"t!CJԜU{_"|R+c0*l''^j;d]}iqЇ ~X`Yhe!' kpI:*Aߥf|;e?I31==` <3foZJg Q@3oD(*@L](жC/$eHE>{oRSJz4/X@Tsf$ AST!e0j!0d%l ŒDJWd>n_kRRkBBqOPv]1r2)2#2"?a q< td"-RtP@]#"F'q P&4fa[HLË|᱌9dLj;=]U@/$Z Q_fw{1Z5gR!!U<qHG#u9 t1Q 5 BԥA*Nb g#ଡ଼O9ɓ AE7SF M``P7~ġ#<%Iҗ͒VLH[{̞>-C{*W7t #ŵƘ|8{!KH,O{Gqo^UBPtvAG/j |=,?LxS G|=itp*F{d>hTޡH)4K mKigFY#`JS -g%Y(a',A\)s(B2X|1 @ =/ބq4 Piq;һf~v9=nz~?%r|(oƂd~=GW]\6=s 3ǛpM'Q~ {竭 ?5Zq7wByzAbh*?4{45HnWndOv#:17/XP*hAAg|u^tC C⤙Fm\bJ@Y:)j3K )ntJ;|~ZMFv[זQOʯC0L$@.:H 5Jupe~KʠLEgVDe |PU ̆XWgE(YF]rSA73ݰĸU9ܭR*LNa͙dmqf|B |=*TT#F%MO$QEER"~6F,4ZdR-ƝF$S!ۂfSW*a>+=\NZtr4_qSsZ3׺Sc,KUoi^uI"Z0n.x: =I: WQ/nW FFO|vy[G =uב R'Z_uKh/-ol/*1^^E$JY;V~G+zl>:_vt}bNSg >K%8/Is(~kq|4{N2J(|)ʩc$cMơ:jbXh47&29 jo]?EGśVO;{ΞYf٢׊d_ڻ+e>Z|:`'Yn#6PnG$,e))lEѳ ڞ/~{R3GKk5Ƨ!ߑ $ .ɲ{_\ߑsźU袦&@4Xsc`mzs3NgؚQuvTG̣È?Ly+j~eap3i mTb55kЗ:w&$PL,!~U;4%OkS)pJNf7Xz.2t2GAx #٧GK]:wŃ-keB/l=2iR +q7e&.w&Gk֮WUƶ,b0.&Y ,8:R a]85+"PCOlu Ɇs `Jsjs|ҦYl uy?ѻkO!y*cwX(1^ (t}͛E>~\e4ˢ7LfC=\U[Zmk0 J.tz{RT$ a6dUA8У [,{OBPN(lU>褛5@M8*=UKZc$8FOe66Z`0TSK^&sG?珁 OhFCCɿB/K %F1I]2$0)@=;3鲵yRFP_£M4B~ s10p6L<۬ۇ{>Ć?o1s,5`/ۚW4,=q)dE pA= CN& Ht^mD[mKrƷ.s4uwdJU=SF ILiKrN\d=+F<{`)mU}hHޫ\WUt &6i^mE&a<0dc=3y;n~SVish !`iW?|S%d&s @tZԒ.Ӗ%wU>Wlg.Om>*#go@tA}F?"N5$SjZ[z.}XOg9UyG?ҋ1 C*q"8,ՠhO)C->J Cp+=lh kPڡ1}p]ALZx`j*sar‹mC,,.<]FmWwZPI)d2 .f4s+8oFGJZm !|̔l$Hg1S͵|qNM se.>9{ G1'~R( =9^b*Q2eˎdtXjTow%< b )7x@zK񼒱/ABy"S5fk.Kȃ x8>z"KjèH.a/m` g;RQpg`fL˫}pޚ4Z,,VY.Qߎk~WlBZI^MwS:u5MwwhHϯWL87{e#qn6Gw$@^ٳW;.ڬfm.Q@"(4K`bQx юT/_}1l |2%9 l*k e !@Lٔc6~^U5;ίT'6V%< On-42N-TsN-!vkHʋ91RDLxx ,anߌ3MDm"<{u-lvge kEەJ#8Ps_$D\L#H-IWmL\Xlkd61'tZײ9P+%1~́zk!eW"Me"2S8 xTɣ/D'uC],6t`mӸ>)C?'EJU~h|IRt>*hG[K돫d: pgbpD1gVupD<3aEECtymNj0!NmxQ$6EZ4n^ߵ*.U@/.y| 0 ^J@1&K7bԈDZ+6kZ0FQY+7⇐Ff6Q[:_Gl?U2DCj$@)E=u;a(;B0 w&Fr!V+A9\;bƁ2 җ ޔ=~i#3b$ؐdmH(H‰܅7.=/i)Ze)֬V>w bnjLh[Oe*˳sJq`;|mW!dE%=+ 2A\? 9ͩZEeܥ8X*񣠛"L1СLM\cBKe*;rSI t|Ӹ<@@ &@x>?QOd+g<:k(7^:QAeÿ|GSq̍I'[U:X$5;. (hyFpm aZtG{s wPIm؀T ;z.Sqg*n\/x6(Rcƹ*Xfs۵N(1cE{hxhY/>~#d fZ+Z/R/x+/Px$.(;R)1ɉ)F3)@bNOedmN:)~&Wu$ Z~3=P44;>4 xo њ;=󲺒iUĢŞeZFNmy(kL:=u%V T!ZGx(qNGx&5DuݯyKh0czE 6BGp Nc.17{I2Zm=R.,ȍ;:Dr{[WWWDKE m-PjQ`VD;](Bi²4g/ N[b>/h҉(*úI[#悹P46Fao|X2m+Eb4wزiM)Pna^hqcs9-^0P2SJZ jGqbC]3G>/$ܐɀ L&),J\6 I Ot)5cs]}ff>"r4~cDA_{]u@bTHAzJvГ+o\3@ pN)Ѕ?M *2vt4z_[Mzys1D eHNlTD7I WMQԏ} .Atsl)7?")dRN>Ɉ28Q6+Zq/\:e6N67!$(,dpò"E(_Q<%S{;Y_ǔzHW~ LACNz7ה˕QH T.VD23lUT9v0 PISP]olr2I O/R>l 삂iPE1~ c:YbSHÈa .}NԙS!$ThFE 1ub*mn{m*]A!r)[qFg޾-'p]ɓU25}ӱO đϙm~Yj(/dYՕ+R!N[8/.֌};m&gVb<9B\Qxb.pSţ]-SC-Qbߋ{A[/5yTmn]!_} ȭ% @#滰G7=tw':[k^]&J'7~NZZSj!47yw!E!O1^b117wnTrB e9X9rR|L eUǦq;tP2+ @hNvl2*:Q(d yr 2fLtS$ [K~pn1dTRnve`+'F>=X۠8A<ϭ.3w"|QZN:1':CMf G$SngN8m|=Ts4 ;8o5ٛ,dfJ[zW5vByg :FK+~k^Qv`Č tNFOK3Cg_NWRJF $K[" Bz(qph ²,&iIt7=Rm7k`@/'1iã R,x#ekJ;""Ee)v ^U+c5 N* xoF{V cŹ)y͒~Wv룼PYk,73=CxDv&5Kr`mg 1<l !iH ftS<(t<cot߄E!kkb2%kjLGZe =7H(K12D$SEHdXNEwBgaqF>"I%ϝXhE-V΂ 8\$MƢB'~?ܢ퀬r7A*izV@rQ@/܌|\~8x,E(^F¸vk]%jbw< 4[J-ypVSՐ4:w @/:8C&;X 1:`پA[w> Ujj<[|-6L|4uf{$^0qjELߞIj 5.0h%gIR};;AeOp޹֊ŠG(H(P؞zrAwUY; hM1Uë< EԴáCg3+Soc Qzy)3 L{ i=?5-F-25H#];B {O&<0RS'ѡ#2ildMӎW:_ŕ,,}X4^D+: F  nO#tfF 4Z.;Nr8t'oLgGW vL-K- Wv3ڗ:dCtH8|sv֥2˞[ٿ!9e:#‹Ac7x7LG<&24V9tʡ}h4зt8sl _ |q|ec19~UbĵÓ]ϖAml?OD2` 0TSN`";2\ _k*3(RFyCVݫ{ S0nyBrZk{joathDfxVgW%VK-"c0v|T]]}zТx^yT?nIT9dLnqn#}1`[+ ؖAB.mP6SC_JDS?)M#w X[}}iBLiHbǜ\,FWneI4 &)v`֑BQF~Rqcfcs_:~;8r[tSGḽ#OYw&.?K@|@irњEY8>Ϟ\k?R8nldl3cMO?֥a;ĥ"o4abPv"&>,ąĐ54bu P^JpvdzKO&6 3 (WdePڨiWtor5@i,$A=QrB[ \~lFtUj<ۏCCk*U)~"bD }J<:Ȇ:<^ ΓhP؏٫F4']H鏸+>$q*DQ7D!۵₏} N\h{SxكUW7^bg-'}Eݫ̨XśMˆohftƹ,U #J\d6钺Y(~x8c[{C4$Tɦ cHxX@ #Zc&/9ZLkSk? :fR2Ic_ Fw U"?.hEe=3A_ 9X,99 @b3xIhmc>($u6.K3g +ZS%Eل@؝R/XC%lԿ;"0.s6ڮBN-|E(qxEBV(+_  W]m&( |n|OėA^Gږpj bUEjU!VYjk쿜7Yqg &m"\„t?Un.ϛΚyt"B:'YouyI{ƙTiBw*{jD\8&3[g&w߸rڱN]Sh6By*+ =E}{䡒Z۩S dW^F/(sOh$lkX/o'x-Y_K?RcO ]D^|1:)t,_7E9?Iyg)c8io0 et ̾TX D2_v|}#m91A珠XƏMWWWgPyПޢAHaaCofrq?P*r躩~^}6[k3#BϻFVMEɮϒi8?M ͦ }\0V?5LT` (;qiz.u]dբP,+]uIf:QnU~?ʿ6%;̑IB;qrYuBb;zhrÐ?9JƳg%viGT2Ѻ.nqIMR YjSGxa k,MZ껊,. I+Aْjˍe ;Cl9={۸kV*Q󎛇goS.˱!hKIEZ1rLGݹ]S*rA 4h@ G~rq~tzloаQlScu@bn.BF4bx[J.m$i."߅ ao9++}y;JMN&HX6(Srkb,'^ԽӻLKZCS7"M]ड-ؑ䁧z[5 BےxC̘|mMD}v !oǀWd|y[L?xSڞ/E ᝖N[ DR cKtGwBKe)sF9W̗yuA0a8ihȘv҂-?i-×:G>Y{>跟xΟ7;F\omywMU vU*;V#x^:BWB7z<O|i`9lz5XWkE8.a&gc%nE?h{N9{L?Z?EXt2~NJ (&طo?휉ˡ>)BC{"wFYCr{;z5i XP1sC;?}sS {wva[k5qrl;GoϽ5Ͻ.~g)@ГãwGp{<&xrx}t|t3v] v❜z'5^7=`}Pg]q\5.J Xy.ocSh Fu~y|svS/ϛL㢁mTmJϰ K-8i~|}IμSpqze/ϥNkc`&EAG-jd*z]Z˻+UZyQ+ֽa&un}׿ڼ~e>$Vyq0L>D=t>ݠ鶢xo+#~ežXb"XI#}>/g.4>k_kڪ<#Sn1 "|]7O{}OMbIJ'Q'[$ B4b/Ғݜ1"19~$pyb]nlʼ 2p(EtLtp#|c^)7U sƵq=º]XuG똦aU2프\HՒ8=oʇ =vU-:6,pMG*Zqe33 WE/Px%RQ͓Km‘KBN'&94EFo~nAG#Mϊ;a,6S6w{;K߭r?D5S\˵v-6oy!_ []# +&u|%x%%_ot<@ē]t]O- Bɟzr~PJ/}N'R5}#1-T++ӟ4ЂL|' 93J}:-CQ՛Hu#%!z|CwӯYg|rSߣTY?v9fs8Wa)5C7%8]! tSpPo[uP{޶,yHN7^apoG<`4c< ~M//\P:>pƛI(cPclGa "퇖nf6E?7t4N OV%Ir(WQNM{%_qC |~yC˓@6gՕ1u KhEELo>ܟimNAiI,`FvϠ._|Kedw }; 8]C FW(z5;zaW0DeeD@9`~a(SagD:AЛQ~ ,%}2R9EXH4eVYcb2{ԗA=օJKQҙ \ ğ 0i&|?f,uP`;)zz7R] =7+DoZTd N`O%Y+gp&C?\oL:WzP$Ь  U=ɞͧ R@ӛ7wy LPPh(O2GY-cfUH$RTOyOu{{ZC@avWߩIXW)~5O2ePSFeD5F*HdeŶk$7|)ؐAf+beFS 2 q%^I¬, OؒSc9е@8?:<ӄZkfI|*K6_"ZձN:MO:A9wq+Jei*7lX JH:J80ǂ?x[ bд_uZT)klP=~F 27j:y8*bZ"\1<o(Om M7Ӎ/1\Mأ'L ޞ`(3=%/wчf'K5x(eq%xvX-]`4N}){Ĉ\tqK( tIISrpӹô3M4^wfeڻ3۫.' VEO;:'ZV ::4't)eU#4=X]gYf\-_RgGqL#*D7,x?NQ'1 PI,4l<υ J>Y/:b .CL)pth5vƓj#Ma>[Vr҂Nüb[p?MYL_J^:і8Mз4E_p>,Q9wM 9zG9: 4U'94Ē;Y[!}AQ߿{=I0c>0|yvqSj80m_fFNz|zC_zFs2U}G)]P;:$A< q`L); L(4a||KuhL@B OhЂ|A6(?`z /a($Bw,ܣPGx0?Tw61: AMl0!Arxq%ԏSpƌ&n{-l [P0EZѡ` &V+[1SuXOIɫ{G(uYGyo`,0]B{ syy l24DWh{8?xw]y5>y0"X~k|?~Z}qx$S?ʣ|L`< A@l/0s7َ{3QOf~~F%9=p,-ޣ`ƯOK9fOgaו a1r-Ɓy&z4Y+L>/V̔{*Ш1+lBtŦ1+j"ҷ_wb{Ұ 8$zy4tjٖ~kTݔ,4l؂nsr ,gOcR(h;,!ݦO!wUϋBJ| ;S5A 569^5)&c#iE3@"#I%-+>R.<)~o_'4 0:-o'*| ɵGQwU#H>!'K7~DCA/6~,y>%hrcx$ggr`<=}o`|X EU׍Ó˷g_z7YVAAu pꐴNMxYr`'bǧ'Æ=Ks/&_KwGxg{i+uJ=?ҭn [~~Jnb/#e2 %VHCӛ7|+YրaoWn Aﭭ<~A# SN^)?_㓢>f~5w3$}*@qnm{COZkȟ ^v:k%et3]'-ӳE4NfO=r\!Qvo3H̑ WCSGi*Uv yu$]O1sqs8*XR:lK%VV&H{g:yAxt`co|=uPXz߽Ԁ]ދ 3CbvN=3 _=~sL'{ϭʣWS+W_}:aRQ!)ה4Nk;r\}#`:.%0m'FĢoEn GVzwvtr:?<;hb˘br! [ib,vS49Vγhwf\5:-#yPgf!}ǡK&isJYmS(G)>vP%u Cm[GI@@ cu3޵c#fڟ/ll:QzذGq1#MyG)md?&ucpQHx'DЁ/wsm$LǪPSO'y(_É (eu|6N7:t2 :}[1&cU9^*NY"?؏9#Ddž3= [8r1ggmn{M9Z^XZ]Izo8V9SVk/蘫oyWQyK`GR>=RДnr͑,dWN{ s4u@ "' ) @lo<ON wÏ>3ݨ8}m Ȓ$]CZ({ (Onh٣+ Ch!yۨ9tGDi`d@-ѯ/KƘ-zVF6JѢpj#JW$Ο^% *5,%*VvQNYǢSDXQdcy3}6ύ;ט^9sj1k5Sg7Ml*BTMD&HoCO Z6I g5Iע4 c#6 ۚoF߅3vCI*)5RR0DRzcm_C# Q$E2dLA'/b}0`}Ҍ1蔽e|M,H0LllMxHpV||-]C7^>؞LR|Ԋ}y-հMꮣ \z_ev"PbƒqќHbTI8KfX3ŋ&^-k$/\DZ_<k @\dxgE&1aYG+Z5TajRޥ=O/J6)$t+flӟ a&T5c6"WUs=xUB|mGUB̨v)W1+ >'nx}nJ~ x"ԏ"Mؖg4j̊.l$Ef'dILB1(WoC^ryCIO+'#x]$Vus%5g/-Pd/+v֧+9=};Xݯ;ev6Y: ~6)u?}x6u2~~s-H a>b1Y(aCbR5eZ$<Ml FA!{ꌬM)\;:ϙ%qm3&k&U[Qfz0hzRI1­As7W}dN٬J 9HO-_&%.ŸK!ε:RѼhFO:c] $ ,{ԝE H`ޕd" {tZ`yVc&< Ygb4]#IUM"jsݺDReA Ηg ڶVZ2(.99OOQ_4#[ߧ:L~:?2 ]G/,amE+Fk=\3(09-0.09-0k#s "DG$THRkCCw4/~8;/w!0N}tMw, <Ȣ/ez?C nʫG'^uZ.vwO\jnʻDW۩*zVi>J%l޵ˡ?SnRp슴-uCʄH=yC5w1J\˜1é?!OhۮTM0ɐ :EˡvВ eŷ߆߆@^𷳦kIFa_ _4,Z]6=9W߰^*%u+2'څ!-VKm3H0TX8D0:$,}E7jDBEو%`AEy#bT7Ja;; ӐXhTK'֣LɩŢ A+:Md<}+",'^M& RI<! &OCy*;`[~[Z%WO1(EnT>j򏚼͉XS<2>7gOCh l6@X+oʛ Hy^YsQL Vu~@Qx8i!=P0ڛcXX;ML[s}kͦ'X_~!ۦ|ԁ'u(ubl"а6 qru3j{i1z]Q^^JTnB;C=8}rEsܡpڬ-{2{o`MQ8x)>PxB*r%;?"SП`^ |:uRkoӭcJE$6ٝLQỸVnsMd.=wbwۀ _~0 ?\!f[-x!a^չf ^mRޮ5//L{n_ Xӻކ4-Fxg*l%zjW([q}(2C*g꥘ޢ ]N1=|,d #KdRIJW=Җ/U[%-iMAjR+<,\b˒z8[~gF㮊9c6|wv ;̓T{1G1kد=q6].yqltѺg-;^PYEy>nXyp6`vXCxg>Bxp8*:u=>M+]Ou\5'ժ8(Aa{XVuYJA븋c_Zc m LUitۄ~佸"٪A%Ϩe!dOzAL |"](^D1 1=E+y_ՍĚ1]9GkE^hWIA^Sӧia`Y]h&^Emvv cR?פ,>l;A=)EG|O㿚ʴ=ڑF@Z͓CFNa e53V$kF=+ExRZy8܍<ꨘ#%vL,%zELGV9+ƕ7'j/%|VgFksg##SfNYIy&;x] 2(Z0&{/Wگ%iߍvys!۩yl[S,0Q BvAu~2<4X KL1kݛ FOwFEB!NJÎD^`g+Ü \>ђ2k&irJN \Uόq@:H1s|hH/Wy& 3ѭtvZB!v:Zv^/x~)@ Wl7suhtC(ȹQ$T4&Mmmڲm7oM ޻SB8k)b'L=sc̤_Frx%˿j"zdbSL˨5'ccF.ZIH3Ld9?n24$)^;a3SEGX,#&x a0SϗJ4tBꏼS?9/CdUw1>D*;'!߆S,&@% 3`C #LcFx+Ɠ`Jڍ@.uh@wu5L$![R4όM~j+wl+]WIL%QF9/,Q̊Ks=s8MQ{|\88b e@V% E".R3pY6 5HreT>$i1sjf[RyӠf9 xVHZ2փbt?b&OCNtʺpHʼ&46N/"XbFB~x]AÃgϢ9.`yzaϢyTa7u>H\#yFp;̀%`=xǃƝ T̒WP$l쌠yHqz+mlxh8o&3JXÈJ"}5I yi̖n6KaE{U{;P'`6VPOQRLf 6L.qDщdp>٨k3"UĦ2:̖i:4Ba8ٽGQ(*QwW,9!%#ʧYޢ"gM}t۩9LXe>6WY\%vgk+ DZK/K1b8l%o"xw]enhȒɃh3 9}jeM W.pkCJS;W=}e9؋Ý!cj Vo n5bmE+# 0@Ѧ0EE/yQlʁkNPLOM\'6kFb:Tx4n,%\rlU[$ c2o*̩{Yt ןKU1'GʏN.B,_ BRqH.,Z4;(`\lѮIU)vl2ЩEi*vd{H0Ker:N[ Vq %0]dĶ{(\!9w?jgƸ ok?b77[m/Va=ށ9e0̂z5Vz5>y?ҿ{Q.0L1c1+qRȽ:~ٮتþfGH`v|YRBςS Q_{>o]y|!a8YUe>5`d,"q2\ 2n$0iX 9;a0r` !P芙ЛPQ×y %3@̸GQ0q0B:;q!.E~t}A߹VC? 0&12S^ze>4r"[1>Lc+֮;. )Jj" .7DPb<hCx׍»p>U)"F3@P\4 ,˰O-p eqD$-k5F4Qv`yr>^z]viUȮH jLxc̉W4eڔnE$ZH$/~{M}CSܕp)m ϧ#żq/%o Z?$!\uth<o;}/qfΆ}C UZ-oUˏί{ ۿOl=?8BopjdQ7J!/@(%F߱DQ֭x^gx;Ϟli7wffjeEB/3JT0[YPŁx0 @4r-")~}䃠!<}ֽVV;w"B}1ͰQ@%~n*jMf? xոh=hopyqx A3KfIcC1PYy%4>8.\0$XkԬb4a+>[׍YUH%bH^X^F2&.m{J>H#P|=DV3 \ =$ʨ'%j"~ GXxo@'rQyAd)0"rƇXL:,wƠЫ+]IK 9#4Gn-K %/vT*l-aRJT# .Er[}ʪM{[:ǣ"oihT07kexRs,>e,+ø񶬰ɫ Y,DGoeRLY"3Ơ-E6/[ 5HLWnLNb;^Z'7aZ$%k9RZ14TX7ę4x,QEt>єVo"OqZR$97*iDfz+>%JX'1~x8>oJba#+HleMpQ'Jn J*3&GI?46rsŦo@{E)%(*T,B+[`5A\ ׹2_*8O(p;zg.Hs0D$livPh?/]]2]Ò32ar8i⻗)BތP7=8= %b |-"vNj/M<ɘ׺xbpU= d#Uo0g.FT? 3`PuspU晥$kSKD<~hZd a>}"Hjߢku;)\qG(M oe@o+[9>+^^T/ &|[TXK6ue-Hz΢=).5E35?)q4..Zh;nbqXK8oXIFȑ|s.OsB1>0컦$0b5Ec0yr @4j7!/8V]#&l&Ш ,)2$,<.+2-XJќdPJKJ8'L[FjXfƸaJBfzBzyhꊧ ]lF|Fט*bÏtDf$LU{<#)ؒsG]cRIP8dok첹\X\_'S^6Ѻ10P.0+eX PgkcA:>nE2ʋ:e,PwO+^v[9qui$ Ks1)K-2NANq%}Մw?/gn 2^#UXOY|]#->.I`7@֪;ڣ_GDr廳F7\x"toPdfeѴJuwadm hyK⇳f𼈻oЛ} ?⿕}] A|wb/p @OdXBӥ0h )q HpFak xt2x?ڠ Yf__3@~ WwsVV sB7Eh?|B1f{LƳ;`wB^W߂@kY=<[zMo+=oT?lv= nկq!Q-]KQ-m~mn0ݨD]wEν2)l>¤'\f\%{g=8w˨khhμ`4_]}զSr7Wٖ4w>8-^s f`wP4gyyxk4*Ϙ'DNŠP:>j@I'`TF2{G P`?0s9Adhv>5Q\=?(6G!b oG58DԻBc lAp}n|kgշ`x1. cmV8?k3ߣ`@زEQN6SDcj>Gh 6I<ٳwit[sQ,V53+aN:תּt WV՞8Xw; D 5|-"%?>[[n ]ֶ`NZco>cHTfsyY &v#ڻ>9oKPDbv͘r4C߮$VR3 Y@MJ-86hfڛy)Ka{ۜ Zil2dGۂ` #t]`0I0K7zY!M P2lIu? (]uvM m  g>ʆqс(i{s|xZu~lfZ*FZ,U~<4,ojse.wB袙 (bSHM{cgd K9Sn##g]D[a0Ixk'E[8S&?! 8y{m{[Z57YBFq\l;;:\ֽo'rb};ÆmXM)j=筙}zgt~ȏxjE8v?$B /w;o^t`DfڟkE!5R}GA-A q$R+5CO4Ӱf\U!|DIW 7[9 ک͐۲^Q.=R.w3p'/xOa;qw7Dذ#ƨ OnPP/! W 2| d4y(cP9c5^vG{@j}q՘pr 0Ze>y`5#bRf2+rЌA,CCP_hyV4?RYe^.'^plU]:p"#Mȓ1 }\&l2a_ ~Qo*hqƅ/) ft|ے@+!3jτ)bsYY'2 :(BIҸgMl"idJHt\bR|Hg|@J͒TDDgvWg5LuտE3Z,G9J[+;d>?ܤ`a)] `x|>ںN&t2PLw2L(pB}v=TJPV%3%4JLmP Vo<*8}g/]fϟlvsP;>vƳvԹG`O`l8P0hCp˩pn#d\SJ>t1qc)yBFC\%[lX,`A)f e q7v,(ޛ7tٵ1vWKtwWZDC> @8Si{_E}S\l2 >0j(lmSsCJAヱ=2z4^`!bQUL,ESGfCE7A⎆ !H~b hvPfPʕn@&g_ h,t +n'TWtE]ekxrkaq &*Rrwdkdj2,J;^x=q]ill\OjPa]G6&`0ս[^bw-G{y ;-$ AB&~2jV\耀ժԭ hGq&wD)/1&]FAQV5kAߪðg:=)$ z$Q)|N_LɈ:mɘc&*p &Mz!#&?'ɇLܦ.UԨf hIwc#Q Uqenf ~|.(<6B lfħ3)T!14LX^^|Ԁ?@;,ؚvk^ῊjΜ4NRJ?g!DFsr7ȡMD* _*´Y*/tvF;t/xK 'T;ť|," 8v0 DR=,HÀl k}4QLN| t;SjhG@y)*OO.&NJ)#QjUͩ3Q>d>Q\{I~:>~Ϋ< ǩs@t~EMV RI3InN.LQz&nED[ `~}%0Zqt/иQCIѓJ]1F5fŲ: zg|N48!hrDKMp 9%15Q K^{klAK39æ>]sk  DNр.=!e KYxO˟nVؑqſtg?6Wʟ*Y^qoNy5OeK1?ʹ<5\1?F1O֚[&PtTRn;sr.K?$2ƋoҌ:pzD+:w:-;MVLʀ)y얝8Y(doTJl4M% \a'r0&E.kM }} YE(jcӀnX%WL TdI jvG%&Oٛ-t0h]M,ISzmwxS6i[+nENPӡȠl54n[)p>jLJT$geDAkOO* 켴k+ӫ$犩s]M@YhM鞨{svt&.q TKQUշo# 7<,L]'Ș<xB`R\p[1Yʩ Hs0q033GH fT%VZx:U%6at0y9@)Į 5/ YMR{z$3GZ <to}W xUhPN(;d(i'1 iX$c,ڃ3msd1 g_桺ﴦ-QUaq%ɘލ0.g8h2]&zεv5v6j޳S\Y2yL_r*oD s8 7Kb ɢB Yewp#`Y@+8VNcXEm4wWip YqO#VcI1,nx*Y Vшp}Uuu/7C9E7fOCۉTQ)JrP95[ھ5niR瓖B@ MaEo Ch i/bw͕2C&1v|rjNˀSvE@ĩ'~Տ٬"mY=N!iYC@*juuaZ/ee؉IkBrT,\;[Ͱ>-[bpU*9c6Abw"ʶX쏜/ ];%S<,>e[zO c_'|-D$I(Q. q+.htNs6Z;v_sl~qxL~Obd@(#aj8wYR׭޼ȕDʈ 8FFB^qn3-] }SJ\3<2/̭X7MوzfB/$ߨ-BX\A+_!RdũrpO5+(WV u:rMlȗX : +38sjdqmu\ eɍ{c8AB]hV|9ƍBs+.O^\za {W ?pxkƯ/34[[,'3M.N|"%|LάxkuC\ŻdtjS>k{o*bEp!-e_T@'"{|y<,,fM#VUњI!{R EeU\Fj 1]8dqUΏ?iņvFpL~hryM S1E,9,,D>$ZmXLt{brnP`&q/D_rmFuZ+m|l.l5iGw60QD42^H!C E2Ͳ't'mZB%AL6x E.FadNaZ!G+Cm-W|ŝ?/?49ʚ!dq]Β<'?a0Vv>/GѾ|?S,W`۔<Ӧ_5M\9mb>@a/_E!)Bg{O/S||b|_W(خ$ZWg Ϭ9cPW;>jp֎e@ha[jeG͢~oQk"/mokgkQ! +0῵b4u^M y cEeEev3O'(^}w^d<ּjEV>6)uԍ ?1^zc.f&;ofg<|e+޻y{xߧvL?$")r(bܛw@엯nyBbow8kfm뻕z{ݨ5QLx;j;8,]/D `>o17.n֚(j&hn5v[ -o 8$[x܃T۩::l47J;|8*^}UQ@)-'^&J o&E>syr~~CÆFMkK[:<<Ώ?k)yA1FyYlIupAet>Q]4`*ձ>9P7Ӹ<@x P8#j"K< x{';'}btzvxzqR\O ͝i)0U͛rO\y8a4'5jS$;`+;Bӓ֊otߞ~7u54Wxn?ܚS\8+?;KY_o.S/F8<֒#:hԫD97:^hs/-Al_*uxu|z}yZğvZZ-3 7:b?ƋS5"c?z?@۵߱ضQmic~g-vU:pwVزV;SvrgZe.uJMJ!#|AsMOS[Ȁj ԓ #i4h@jF T*TTMm*V1#׬ J1=p>F KPBgY5YȣhU1jMEn#i4PO6# ^Zr5P&%PR5 $PIbl j85c[ysK(fs&Ţqnm#i4PO6# ^+fv5vr[vwM6B w@ [8-c:h+ =nt3F0aĀ#!83xI ǖrēO,0xпR ї=ӒߗqG?+VgW@ݐs":@@4B,,R[\d+l)ղi%TVx<ڀ@y&ʤ>P'2IbdBdB$@"%ȤP":dRLh^B@ 1>zI1;$uʖؼFbZB]ZBW#@%5ӒjZRKK(i^BE#@1-yI,$բVPJDb*QB#PB"@:%.PPRJA^B "@1-(yI($5;AbZGB*GB @%6FRH^B @1E#gxI-#d;Z+QL1ΈУT9h[ĄJ.]FD0ԟF H%Q좬E8aT! 8\j\Ҁ0nV_:KW} XVu6mxG*e<'jD>0gy鸹VGUxPTڮxY(Vow\`ouM3Y*Zu{k,jfM,@ _톥'A  {F 9<[ OkPl7e1{i=염 E71oHqJXa!Ax*XCO5|< b^y j[*̪^Sp<+x,n@vAN]7Nm:lZ*y1 T= k0Bt./_ oj(h%׷9ΉIy0U g"099tZ.eCgԺ?!LDf =! (I)"Jf^=_6rT,</XOk"nJ RCh=s#8$:c>[Gq Օ@ncHHi# W1ۉ yFY\.&Y*sa:?+=K_R-oo;k_~~~oAS`v2FJ޸Uryy+ᄄ_lxrkmX1E%u ,;]pޒ"4 _~-yStaњlhܣP2u^@BB?|/GV8~h0v^\;wY\u⢮$WCK-.[\@tq)Y\)vj-.oqI;,.Z\ܕrt(\\&r,.yXRk;⒒wX\Pӵ+2 ۋgS 2cq9haEg_\rM'gǸK?k ާp$9&:SThT[\UC2) eXB{bYFb]L9}T9e M_E8nX<,<{*^:}vf'# Ԝhl#*"c"6c]3|.]Tk[WoU*~XBJƙ K:3Pa5-%Oݿ̆RM9rd@CmndA0u0a1b[-?TóB6)b "N}7-j嘸hH^폺[&'$:BVb=sQS1%RÞ aXI50Qxz;ȶ|11Oy+G2[ޘyo|= 9~6[iҌ8/58=h͓/~X) 0Pg1zjD@ P0}&Ʊqpvz,7q}3e 9r#ZpST\o] 1=Z//~T2#`z2"rzz1Ԫַo-ljv2κ:7L>{(RX pFzT tA],zJ`O p ZP8?(:Vx?6/aqr>4t_]b+I5Z XCm_}VWʟ~{y\=mRګvkwz+kow6Šz{Jғ{Zoo/]l]U[}"DvY*Vjv @˝n&w`#Pwݠ]IѽvS;Sk*T+[{^Gz`kgο=(U_tbU;uAҹNCMA\pn-خlWJ^ VZu#ovzةrWmg%*;~-èlU{uU)2ҮVjVIWk5]Ea]wj[jueVw+jgp\ݩV;jj5Ɗ_oINu _;vW-v+r'cUiUjjRL`beT*2Wp2*Ζ.;V+r-X 汽[2jP4m!]^S䰻٭(rtvU @>GaAk=EnHe3SKO;վ`Z'/zw*=@O}.+Zʻ݊){=UnV+,X n!2eRG$h;~kW۩*2kjnW`՝vyB[mU;]de Yȷ]Zsd+eT6ւ^}UFtv5w+{vsi3^mkxbzy[(bPU`6nLq~V[U[lm=DlVv $*6WZR߫+zNYVT;;m[ftzj}/.;^eVmsثn](aޅVXΎ*ᲽWm;۶֮MU?RٮivOդvhWLU#X(2zXjA 3O5hsשbjV "Jm&Eɭ_J~mA=%T RX mU-{ZW-a%v~^*^.ҮD >ϖ|]ZJTʵRwDorYQrowoGXJ4[DdXvkgP rշegnw+m5@%Cۻ@e(Y #Pvg V֮F6L-lVeDNmlۭ]?.R*Hc;^]aCe҃ݩf(^tVU-nQN6L"am@nS :AWʞ[wvjzۭwA8ho{  IABot*.e_  -ީ߮Gک>Ww흝F =ת.SSR Lw;ha2Ll,[ [v:lUu%SvzսNNP"iׁm. rUl[; vrjHVÏ)]_j{ bzS7c^( 1}Sݠn'(wczN8\X0\([ZR`Ajԯ^ î^/J Up:w`HZVzw*+ TJHLM(E#|u5-EOKSR44U-EWKSR4u-E_KSR44-EgKSR4-EoKSR44-EwKSR4-EKSR44.EKSR45.EKSR44U.EKSR4u.EKSR44.EKSR4.EKSR44.EKSR4.EKSR44/EKSR45/EKSR44U/EKSR4u/EKSR44/EKSRWK4/MKҔ4wURJ(i` )iZ`(z NqdcCݜM'1R-%c}<`6t@.8g% W4C3* OT'ZMZH%.ŚQ2y/~[ЪYJq@IUTmB?S&V&X϶í/q6c9O ~UUudw&P\%2oDٞ!ܺ8mU0U麸7a6g%'eDc~zuސf|C.MxWȝٳUܓǷq)D{)Tn:v6Ĩo*'s)7SX^ƖU0ʝH'¤­`BEPЉzN>Dr}!Hbp(ywUi J_TJ:_f++x+VWpL(td|doaХ(تб:?CN{36Ğ Ѯ|ϯ1uί*/F-3|WF6d^˾++ ľu*.bBHT]H .s1w!cdX]B@盘7ϙN74,uHHeOf72Ldf"1yH[,3=p(3RPk!Lwtr X*6|b- Ũ'Vئ:JءjxgכORc# ~v]/b'n%ZqwG@Rc3Q ^#Fk3cog0#IZfdpk .V++t]U.! [Ryn=$"(wKίCUe6 #BFHׅ*H R1\"sʴH"Ub"9#?U7?uX{Ew"cTկNGxI}6nwD" ffXM趎NLj};jyQY6 D{jZCKgD&̵N $j bŀư/ԥ][k*{LsҖǔb$8Ӌ|+/^!PAo1ƸL% i0̃0E^jki-& nim׻-"ُ( d]e ;DRf a}+ٙRIWp%Mba>iH;PJϞq2 X+߽̎>#] f * 1nSL~_.jeo i&/;GYbD.X;.@sݍx#gysň^28{=I21I ;u{uǠ殲v Ln!Y/&H')զ$&qOᝃQ-e?csM3M`oOdw=K~5"%`[bb|*Sr^tZbMSO uˇƇDjNp%|8>aN΃|LiPG/t:wv: ;9;@;fEwX08AݱhAFwGƠAS;YXP5R;JwG&F#LF(nN#F$I1DOguT;9匃9ӫcwJ*0 zR BfTPY\6@󙍽׆=o&^3Lem!vd_kw( F6Kav\Tsv}ߌ=\.&g͈1 zkߌ5os%9c u6"9z3r'&Z@ }E GZ?F 0.ep[!zq8)Y*j_tA7kDg;NN9<Gm9"LnrؑK@N'o!+T#ǖ0jQI$. r{|:!tOf糱-pF+Gb X((z?{v_vݠ˿ZqO!`ir-{m+7?EFݸS#U{^g$"1πr9S}UEc1"XYa>=?InF@(dx$Qrg\^BuRr:?Pm%F4/ !q(ebd}|wܸ@c]DT\፽ U6Vs-Lݎqg3 ƠM1!ŮO~7􇠨tll 9OxڂX 4@Znwvvրu F k|p^e-Y0KK˔mPxσ?GG&U g_+eZz㍂w~`EeF66 C/T [5O'ct/ڜzy6GCֻЯn }>1q[~{L?=xDNWIL?kP⇦w~Y&fy5eNDzq8>YyttB:k~8;DS(zrp|yl*}w| oͳg}stqWa)@b)c0%kY|C?AlǨf V9hj:_F"6)f@Vo8pzY;O$[PgAFϪe;*0|7BǔZO>'XVxֽN fCoZG'͋T 5E y'y)yOڮ$f)FewOf& -|3mOþCaN8pgHŞQh\?6i"v= 4NQ 9HȟAp3LI"D"qK0#}Nef6VCX HN?@ٮAd􂦨>IfXҺvMzr烙FZ4]?Z/.9%d$"VbAZmEG#5jۏ{PA-<"~1Hv|Ӯ$*(4qdƸOAsv^r<L/z۰\+y (0V$H1VEhyHo|7'z/ }{$`72CS(YQ&4 G 6mŒ| k6MY-vфFlɆ/O~pyr{0{Nw_}[v%DO/0(&Y]կd>$@FOJDʕ ^eݑ;m6$TnszA>:9? q`SK{^6Ğze6ȆT0]ML8jlz0^~gQMQ)S?˜ yZJ2JoI>1.UsI~UW9i't)G8il7.',bKUũIN\nǹ-҈-,G=%[O:ڬө[-ɣ|Q&igS:aY'$RO\,B].i ͣ.}Wւi,D?ysE x=j{rA^O'ƛH'o֊d +ޑp6JDF̉  @ө#*B5T⚇d=J'h^歓**w@#(~`k XROzͰxvb3vJ[G-ڝ]r~(KGwy))\ju65RV."N1 Bk_aG`!c*_l.;g~P &9#sõ2+ duQ?Jeb\Kq_ A-6v']gM_i1{^>CMFUƣ E܍ٕnB= D=F$~΢t~ HDa̓h9I|cg.7CK!zU*FU&g*^D[V&ƾ%6 {)0gxTUx_A(%'.naGӧOXȩi0ھ{RJ]˪tѵ=1[o읖M1]9Vmy.iA'<_GQ=t[KSQ` 2)^2XϒLiy$,1e<ό0R/qŮ@}QĔ=UYe1t<4Eg-d֒Upg]pI{%X3;OgNPr1u&9dd(p(w$Rw{SVzD#]hsx=;Vt(E >Mif~DG؟q!AI#CQ@ۧ ;* x> y!F\@ʫTU`W]6uhH(XBil*p&JzJyв@#7 _|CԂ ;]ga?D_H:e%0Fh`7^X.~ InX[- nD3ՍO,-o HaȎռxYa!@1~oUtÍWykD͓KhKWk4!h D(o s^qE֪ub]MRp/2Dg3s]{Ji=z.rI)Ԛ_̘X㒞q_T\0B&Qc|α8޺O$AӢ@>/&?eL–gyf'5bsfBCDS ={!lgqm߮ ?D}2P uze:!kLϠɇY{XphC}`5J!G3ErDfnl'IT% = : k A.WMg {|;Yn#bj +"tIErDsۍcS] »QÐF;Ј]{DlUЁPSf0vs,V2r.EZH#2U0h) O*تaņ3׽g\j]["D˰?}Nz-hű"&hOG>Q ?og???_ v~?"㠴iGq0(D7hunD ~ݠfpt.;% [QUOEzV/͊r170o57e(+j\(`9oRo2k$vGx,,XV.#gE%SwUKR2ď' ^Èؓa`fFR1WuzUUm>_ֻ!i3Ia(ZAg+tƁOʈP>ɴaMX4t\8#tw2W=^`KClENq*=74jdbhȪ: &YJAJ{D|8C{'@(|:šI}afEns$FIS&5= Ql~J{JxIPTA"9t=G"A*S-PÛ@ol[tY>kǛ?z16fט bt#j#OP!F,݌D3o Ȅ$CT^-VC3ջ(MEnA/݈@&۵fP5+&'r_UJ *'yVxxiE9KQAojOZuݟIn%9M<_]kqL>q @^}To׽8 jX9[+hkO`sG*r1 ڭ``3YKQ#VqMpiY73-^yHgn$b`:*:yz5`bDI'V@%^w>O5e GEόfۭoe5!)iuPT;+7O_)FEm&uK]qcyjD5wF"C9E2ɰ$n$TꚈ5mЕ0MyLMMq-Hf4ʷ2W~|3 Tw߁8퐣Z)tIQbXʭ:T;؄8^X"f6:1jkR˶ bMQo`-z*2Is>P-'$cχ},B=/(Z?ѭ`MX>_Pi36凗oߵ~l>=oJr9'%T6>?S,cACb?e+ iVv+q9-]Mmgq]\R4DD]:$IvZ2}$R)1U=]è[=ۇp4Lͧ:6`٘$x>kiV1ANbml8ُ=R}ɎFyI~4V:*_@?񯗘'ʫ-V%. I иd⇝~=ATgtۛNOt4Sgn@*vIrdISl^UHz)|zyҫxVW[4Jb!kr/|[Qѿ$*G0*f СIoH ٘\bbs. W,Ӻ߄gxC w4GJ(qJF`x3;y\fK6 voG$goq2OzC Q^:: Kp^>!Z]ޕx_*wv|_:ZR<^2qxϨ@=5, iSS{I΁Lݏ $ZΡpJI.V:*~nV%!0G*E: H)kc|5 2J;nuS k$ixb[FudDb1RXJLǕ)!'>u?VQ]񙧏7JR EJEǯ~X) ::? B.N6Txrm{;nWv_f'C6s/iKo ޭYpfw9>Ɂ?M>LL( ӏxI,K ] e_O[g-. >ߧ+ѕB"&Go TAr!Bz`W6c]qJpc Qy.zEKWWWmNLԬ  0"j##aDuٝw/G)ΜRXIC^ٰ}F 0hpM 3dTx2;@Drn&`Aн"Lx ,| ImQ8A-3t`Sb֦wu=0ck8,5V "1n&6h.22]vwMIptpA>.)!,"`1oC" yĠuK"S|,gPI_`pGM$%l8xaJ ޻ԃ0˳w ǥY)\qЈRrGIHk;FZ*57a()SX38|}~qtqy?==<rrOpBxtKW:縏B^7o{>s4[sQ<>#+9)ɪmJMI%}-ʚrB/e?$W:NyGx\VU m_hB,>r0h+w<8WBB#}{$FEpAs'`#[M0o ^Ե6xs^AN[(/xhM(6vqn3Z%[}}OC h3>}ק%b,:dz~,( VڗhC( ^`B;1]0rcLM%34Q X@o!sa [N- qSXtuGhXw:f2J2Mm)8&O^+z!"OS|[lNdnz%uz #'Ro;ZgUܰz:帯f?Q}%}2QE[ UT j͔g/ŝOu| 5ЅBe e1# ϤWD@بAWW9;뛷J䈒DgeD\Itjbj135-Qde4{B9Gy=*u{-@`r9&N6u7,RǭulH_&GLB=E9}]_`+a6ƻ> ]lqEF{u~i,.k"rЉ1ƅU*P Cݐ vZUu\uxARvuK7:}!ΪОcK֘B&EjÛQJ㼉 L}} TiZś˓C]CkҀGڌs5ߴ(xk({Fm"l)]w$ry>0715xJ }A3֖ T5 ڥÊeneé_EGޖ)0ZRƻwMX(;P[tR$7Ǵ}5.^~Kcq,U840e2;_$(fi.hvAA~X]Ggpv՗෠3+wSlD[VB ӮsIWϡ'yϡ{z/dBwH=8YH>籶rohtu5R-O^ @3*xiG7r`I5 ~% H٘XOhgGE*;?̦s o]9tǏ-q}q`0(U.q'"/qybh/?*!o7Z+&cr } z0ړYX{a~ʋW *‘(:i\X0?݅ Y\(,47X䃷x>X|!eW*Z5x|2waacݿsũnu5 yg$; ֈ<7)RQWVP@ y^+Ht }%'@z+G\i $O)APrSPoϏ[_ύcPpMtd}F`܆. Ioul#X2g0OTF^obLW(; *čzԟ2>Tz\{=cD紏X2 ĔoicNKC&~T*'>M8,Bj(1TИfOyC`v$G<3dl⇳f]m27V;4~2ĒU,6HB9h~jq%gn Io bJۤ 4>fY 3X 絸@ noRë?:FDl8$_:)6je]QYIV9Jx@M*nF:Wn$x f9(aEo_)xP$+JW]n_9$h4ts]o*[ 7//PK>,͋R8hH?MZrb2ƍ]EtVl"#j}T3 >BjQ:&;B>liNZu ˷++rl0G?4iq"Adl}w3?%CSP1֓U9Xisa]ްA.3,9I2`?p7VlTG4<;Ys\ HZ;J$x>dc$7; {hWVri#秪́3ʥ8H ڗ^] 1 YJwH<`1٫e@[^|Q9`U9s^ucg)ԕA+ {ТmZ-([8ecywrI2u-6m&aގ ܴ rrN,eڵk(p&ҚH`>4yG@|:E黇im=2B(]QEXbbDe"┌5X'N,vp\p \éȉIf"]`<=*W+Z?" G4 o#:$-+P\+/5(p9#nn^3GF&uTL=ކ_5l׆U*oJbfJ5ʵb4^vf%1OKIɱ'1ǂ.]Ȁ0Ax8xf!\ʲ 7='b[3(r˅ȵoOqx800`ޢDvy*cŶpb^ ޥ,ҭQHDvW3L!Z1$(m۶E7c0xwԊ2UH2]eS Aml#/BrwDQr<\|W$?Q:N"$~GƊIbr%n֫­BFB3ƸAҼ[$goLā8SڃhLSU*u G֭Ԧ%^u 'z{y}y8.ւs ~0K\j/T.55|%]`ۦ"IG)zzOZ)eXt1y39m5w9YGnOcpoD3;kXr >KvkV8#[-q@oK>*Z@,ȕS<5>V(zԜϵ~m4"PhS}B?9 ׼*UcBwrN2a4'T)2;: ۊ#Ϙzư:Ғ;KsUTqC dU⥤9̚0cih)M\:y9[aWܼ{`ΙҹXYeezEw#_aCE*^n,`r e4é4 " Dr`2K}[OAB|Ar>O$)P;7a4M?@+CR@h/Xf= 7׷rAzH,3]KƜ 5/}>ߛIZ  ]l2Ce</@Kti`TS՞n?ӣBݛ LI𱏊EzkM2Xԯ JXU ]v^]yfE766WmI,RG[/C1䏁Q[8[/t3Qt~K%r͍?C9}2 #޿@T>iHYtm棯8 <@f]zAKM?ϝlnvOpŕP)џhQOBHzd)]["$drʔ` V0ĀB DLiN<0R2`Yڌ<yQ aLsmAGOo ʦwծ*n ~wIan%+ပERWLJe 4r"1{Qh$,:^]Ql-ƸW+2 WVDhb5hX\,K4 OòX*21br > =[Z (0֬\f6p@": NwkʱΜF^xHCm@Rv6?π)O{<2nQ 4% ˆ1iqlP-#v;”fq_;3j<>tbFdL;7h띬8e;01qπp0rNŻ;bXTD*n%BLXt/LP/e[xOPv.*e_Mߨ` ɰ#]&1X{`c\6' adCYC4[wC;2up;e!Wn)\8~>e%T{ 8yzz1wEg;dc^|)a_6LX8SB5P ],! z83.?'N9`}C6YCgmh':x!so9dji `d%fZ8'vǓ qDt^N m5 ~O/sr$Eaes1qԫ|[!F&("3'w>DJL6I^E=Lno<@Us'ոѻe1.ҍQeA[_|5v|#+'ؘAht K*t<uF;m3^>1O[` @NɍIxp}BFi7*[@Sw`T2S`=ةÉ? ^豞{ ]])6+T]<4 D,+۵VTG6вR)78ܘ{z|%@ʳhpt[à:(ןS9#>NUOU şʪ9 ({"B$ߞPKt HwJBAh8>9H'*|i*"FHg=&sԖ{:ql j6DG0s]K FSoU qOp> h1DX@Fq[AdAqM˹P*[D80Ju/yI"gPquSMTBq<]zūiA[)X4̲ @H /qZ x!# ;19% lTȔWRʽXX]n0"-od튴X&'RS+ҳ3AL]ROHơr_k1yRο|qtŹ{eZz7.v9i^yd}}M>FFJ~ .THT$83cc*,D,vi1EzHo qVȽWłj8yWI' gc%$,-?.O@XYɼLĞdZzѴMƈ)!EStJ |ԁ4+.9βE;}ߣ`!_)sXt4{]}Ӊ b#^OaiiA1dWn#в.*}h=r 1k̯uv E.;0Mk+7. aiΫLpZ@^1_ 7ZhƏru5.VN5d5..Ff#Z.7ػ`8ڌ3?PE @#C9^5kS:?<=iqhu=" qUfCڒAlnX%P6 ƬbVM;>ӱτE*cVJuβ ;A[@SQ؞͝kEB$|Y>LjioNלt"M°|BAALxX W{(]C֏^?hJԶtu \°NSjJOƳӴ-; t]SMphR^Olo +ޕUv6 E܊#2LH\|O&;5H8TƆ12`8jd}Iw# NaNN_WT]H9A;"$ba =9ݲSŻ +`3Ȭ!%`,S!y=6ߧx0Z' ϳq*Tƴ3.3f\L0Ǵa.:~Ě̈w3%-vf%uZ?Ԫoݑj % ܏ND)|Egi;["(s8`EjX|Ilc / q$;'jXRkԒ3Rž G]ڵk׮]B\v]W?DB;Ùf5,no4K[ns_O7`1cVlx2CvJPut 2[jsM$ŤOX>J ,n)@%]Z&<Όl"™WKY\<*h̸Q.e-ʄ9u`#&(uz~ @@#Z<"n[ml^ǫwigWg\5aszrA>s9Zp{V~81dn4Q锽z?_|;z+y"d!*!p}/z.9XSpQMhk4KTzV(s?+j'ԠK<gI}V؏I?vfNV&֏,Vʧ=lTƳPR騁Bz?l}G+k)3+I'^XӜ~bkx'a=DZaikח1'Z^O>Y{#@wNk?s gb,r0˽w$^&u9 gޭ KYl,9&*o2݆AM|J3zZ?bm_5|n>?˽nn龖8usA#|wmX$HMy} [I׳ZnGv|$!g_)/)Rd>&XѧPhbdQEXk~'/u,Qԙ Rxi6 ٨,LBPSNzD$*d0=M%#Yi 42YqO'>E07^q~_iVyƯ꡷^iW"1JUхxRoת-}[jVV^mBCa*NNkм@;6ب+ojǵo{Tk׫ڹԽz#ϥ^5czSk7UP7uZ=U0f]ƖZAוcrRyCJՀޚ01=f;nhpn* `[e ڵFKCeWVUl 6Bфg-QU8kc jWQ;- r UMUmb.St}W}'-Fx?uQ?ؼL{D$Oj'#UoxJEjNM°aީǢ2_5ΔY3(q+-)&글m Is }RX9))bZJP]%#Q 3cZB*6-Xb ձ[W P9:m} |47 [[d8!kK43]$]5PufbL| EădnMi/K?޼\YփKe_nnf_o&Rsy-+~ډP>`hfl={pEۯ^x8>J@0L?"G"jF1v8uJj$2I`1;b3!:"t6dI˅dy-`V)%(\up)f[8?yg{if.Hy~氀rWƥ0%O7HHr-8]ҋ9S +*D#運mkbAF,gqҿ u#gӦbOR%`9N+Սs.2[$0HDF%u^dhU=: )&fۼx&~ohMzL=pL3;vzB0|cӘRn2 C'9MLsu&3-.X’7p̘=h,S(#35#{$IoܸF}49LPa`]7*&Gqbk2RXY'$:^ui* "(GMGE.ؽ`8)>yʞ> m*5w:7!o)^􉼬HBAȱѠ3q' 4ĨN q( s"Mꤗ81D0 9L+~0K夈{#ESpEB,X4)[jY&5Gw# KZVv@8JܐFI->3iCNy7%܍xG*bc#V&y[_$[DW$[y?+oie;Fg. 0ө?]!yv G:uuNrD`Fl4Fq=x +r pn'C.l-vHTZOx3˛.eй'7}(1;Xe4M3jyߏeEgRF[f?,7^i3p@1GHpuC}Q~wwFfhPXUʅiܒ%9EUN62 .>n?.{k |ڨ;BDUMǖvKkkd{xa3.&^K7wd!uhxcN`G9bS-k^B?k9YM)NCD ]5qwbجox#ȕ}B'kx 4R!E uE1DPz3qK\XXoI3b.!I ReW% fd# !Go|Js v;Ao6z0\EZձ2<N*3q.yxMox~2`S>^ ψ?AHB#6FƳA-kg|zH0NZ^PLAbYrqhҊ}lʠLfnś^2F$5bG5w4hCS{üE8:E|z6Ő!k5xd8 )PS{ aƁH v"@"vh"P w,S'Q˃.:aOo}]$Lҧ s?f^t]͉gqHKEo1(9ƄE qE"0e&܊#"-xY;^]4tYb\L֙͢Gp5C;AWC.& &c=A-&QHurLpwyg.#cE9 xD\`B }SL츊j_4Zk<$ymŽf5FrvXR_螥j4" IJ6Vn:Ha&B "Ԥ`Dz2}'%rVBTӮޓtA Gx Ѡ=s r^ %KERUE|5~5_k㉹ŰZPP_&]Cjy*ňc159{}"Gs[Ly7<: 2 U kA_eN2I׮ĺq.9!ڷ]&cwCQ%3qj< ?%c,jl8%V.<g?)ds`l&spO؋~@<Gf…<ކ5 >1k&>y:GfM?3 WR=ӛ$GA9r#'Փ`Vs'O~ cRv[4sؗ ДI:ĸf2ϳЭd_d-<#reL~ Xc' [6*yz,=]>>&R즘-Xcxt~( >&6'R%ol`bd@lƍʕoV<,40~,kqmDM%_!ĸCޙ 8L70yM!3[N&]&DaK7x!Cv Δ~D`61~?NI b ʼq1&H>(fNQ4g#8hY'd;xISBzvƓhJg<|!^WAѓH!_\ygg選9;m`WTiEo%D:59?qT)1ߞ!^z귐޶V4BI@d}){|҅TtR\CX ,xHEeq K(W>ΎtR'RMq(%e+gQJ-WRY vonLH* . B8Ϣ!$:ca`VsN Tqh0/F[ѸsTTo5:`ˈ:؂|Ǡ%lzR7jemzezo 0eևybC$C/yӃcU|>hsQC]@_}00 e '"KڃIJRƢ>k05WP4ۮBlUARQD&+Eg6ixjk`wXˀGkGbystNR<uO:sߤn)n6(T+)[b;ܸ38^la.lFcdȺ!q[Q;<^9|@)"x_gv_ԦL{?ol)Ca8V94צ?]=Zr瀎1vΚ%6f,$Oawp( t1!H>(K$3P7eP(֒:S;4Z˳E V`* ے$Sn<\ `D8zovH?W?VNl4Q锽>5ѯu|dR9 ,EVڔ#D輯՟Aqxp+5;O^Rq3_y/,AS"Z5x``,k)^n!}f>W=ꚣG؛ljˠȨUӣ6Wjzf正=l4 xBo^H_=ZJZLI{j'ìKkлtՔ,09lKMq-p*3dB L;aewӊ_g4I\H a)^E9СvDO2BLwHj6J8vNemYY;q1ņ?nK{m b>rK&O#:&\.qumod)B$;_b8?ۉsG?Kuem'-;*ѐT-RB`2d,,8̒þdAL+rK!45sbA]LEU Z .9]K. T.Z1:.T[">/*~;S0lU?mHL//w'oի7?S$n>~E˽Iݰ{8O me!H 'DߧڛZ ӪTsLOa~Jkɮ_aX?\{b]^>_ϱ?vVKϿ~X/X~wm?/'pt>|%Mouvٿ]Օqf+«snP.kzzj+oO>|M_['^8^¿iz])h_Zgo-HZ|[mC_.~sRiW[{<_oߝo뿳=~[PcrExE2MͿl^q^qQ8M&Af`2{ha%D]W7 8T_x[?|xA8x@@hBM4\CzWrx? 0>OoE#ӄ#}Jp ޵,^ xMB9߉rAս nhu91 XP  MnD]>adHҴtHQ1 9YȀE@u8ܒb-`]x@a]SrKܧ s␝xQz8(`} D@P5 !Z85@Zb]j~wÏF1C_.=Bqloo3pY}Voa,.g"[zwa^o>G_/[=~_/='2xE?WOmo~_AAAk z0x>]H UlD =?ǐ++;9WhWt_tH*tgda#( ScV~_mk^|2.-+5FuHv-Tfq4W$2 ( ]! /L@ Ҡ2 M&8˫%-RMR?qT4*{p>"j8xvCJ+p0JN !Ի'ÒrV5} ˺EOIWS"2$"ֵBP:mJ!5ec/ >x̚J\CMtI$]s ѥX(i5$\uk]k~$[M|}~P%2)bE}ԇןxsxQx?ǥY^w{gzz+i#%TJ Jk80pm@3X ,OݩZsَXrtp}.Iw _k/z+#\YyRk.Tm6c\+k,]fE&Y)f~ڬzwTf}b򿯠EσWHHݗ/w>_/*"?mz!Sb*^9b>=e&U {!]>$Z~q0+N΀9Hb_ xUwR t({9 ^2t6 pL Ѩ3 * e!M{ 6 bp,qQ !U@M{|#;yLRs=hWp: F|bwkp`Ut-#ey=uQާ \OwS:_hGI(eY[ F! ]7S Ub5t8d:Y!N_ Ɂ!C ,.т5S= `Ѧx6fXtQGT@iw@p60p60? #( KAiۢ"ƹ-{e?*֯ݯ>lҭFZN^kBqnO2+N-aB4! /&3 sl; b>='2!L(/S<1 k@E 舩uFz4 k+ZҨJ|>x X%2G\DO- s ;K}6qtr]L/nA#,bK" bSϐ򒉚8a,TH$=D'Jm6XE4tJ'KXHL @ y} c[ yljn@GQ`uI<iNwHjO0 <ѧ\&Z($_GݞãG`RKmliQ֢wldIj'38d tlF#T#@P~-I.y&((b8V0e~)%p.$, :PO1#f:\ǧb獟w.վPv)RD9v$v6##@dEPɍO9X){jeOJL ۦT'Mb[L/e2YcgYu9sseLq}TOadSo:ҨɜHSg#6:qKȃIz&R!$a!3P% &.{kOy*Z9b":e[fNf4aA |f&LQ6۔o?7Mn6f ]3>w⣢QnT=åiK)o; ~;p#r~ {OPW50+Qaъ(ҽh1|F`){?D9AHEYLt ,u3+Exu/>?B)Ls}K0f#$>k@醥gHr]c.hvq1,} S> O0$ >yՃ Y _Q\"LY%uAj\zuZ9yjɦ 8T%gCcAɺ4ˆh*7w?\v'DK1$y2 x759G:b%wp8PBP@ H [pl^? F%HއBSb"vǫ8lݤOi!9b[r42`H#x&a{*.پl LRX2]%VdS*c9DBN&a⨏סzLZs 5IY,cJifshV;G*z#Bz:$W4ř&Yzsf.7 nm1zH,fUU5- ́PLaD19kK;9 S 6sx;)Iz@mK=Q .I)!ۍ׋&dx!;`9|7sNxtbjoqLkK{5C쇧 2Nq\T8LG[p h"j/.]ąydžF} T_ ?]e;k] wg1KiE,;i.s^?¢ޚ2QsQ̬ %bs5AR-iȔ(oz) t"ϓ4F< ʄee\uXn3tOfLVfp\Qqj,FA>c bK(6#kPC4AY/V2 WG7_`jj 䑪3>WtZ]Lx7w$Gx S1=li_6oxD/bY^O/ u689gXwgܭ'o|$+StTҭ_)y(fN1IQ~Z=֙Ul4mgoȭN>f#z>;qhkNr.`-/Q 38¦T"E~֚zׇX+yFo<17,MkTnU7pJô?@kgUAl]ol6V!}W~/)4^ lzCEtHMh_v/QO)sI?<=\jhby!u7Ƌhj\td†BM{E8Gu:fB?V&1¥cʛ//zFȺ>>(TtȲ %*!6 1{t SVDij<,<XeP g+[qk>iTF7W8 0Kyn'_EVV~c Esy 2Op֟s??~,{g?wSL>_p/JӞxP·@4NthVAkdKޛFЫVּY|GqVx fF?! 1آJ=˜ +OT9%=KHwΌ;41;fgr4w Si+ _ ~hOct\IOy2GoX(`)ln; 9{Ű+:NSp<\8:s]R[ 82?&xV/w-Ty`XTVPS#t+ ,x'yAۤ^0(m f n<`:+ |3N*08T4\c!OŘIbބBsu0x0^9{glQ Uth4O|Ќg iX1?&jFghJEHNX)Fљ a7@ˉ`ԋ)Iϡq<7o»om$kkђX2`lGI7cԧҔTɵ`A_nh./6h F *"׫:kыZALYɃwI($ܨ7鑒_Q HG cNP4u[V, +2[/KhsS +YE(s YCeVUw@:,;%\m0j\aQfۦ/fR&uY< V-V1I}PUb_(t`bQ=~^ ?r0C~n6 :~̓0N#8y 9QlOg$2qh`i x`N1ekxjֶ>y^~]8h'N& JY[{,3ruSIylVNёJ3DWA8V!QrЍ&@>ߪ IyxҟϑsJ Rz"5"]gYSLqˠ"J>Y/ZG(.Cp4N,aҢ* ՗ǏY'w *;MKWC~~c*7)G&`744 ػ\˹`pbCZNU$O?~N7z1teO~fěFm#Ȉ4/shNSY*:zll*XZR~gtKeCN?ÎSyIy3*0x?9ʗJmiP5;TUA6P:vEvY8dYs8 s(>rCiޢꕑutp{=rS-F$ #R2@0NrqY͙'$27( j tpv {Ç'o$fy `^t  : @5O{•P@xH<#(+ktDAhyKl?.4z?)kS1y'Z@O-iBbjܳlLT7t:D$*i\<Q4Fw>GJT+8$B,1EhVBkHڗ ?EDebyUtX׬Gdg@A^EQXrx" sp:|{2d3ULg+J,c9rW#Qg,XqXy?#%ّ ^^e(S𘱀OLwl17.712p5y:7$WmiGj`e5#f'il4G Ѐ"V&3Y%95Aҋ ͝I2ys(CKɹA/a9d ?rPl 8J$=fTN'<}\;L|3:U-.v0m@boʯ#}Sr\trǚ-ˏٙ%'*f .g腛NK 3?'nӦf_)i&)sNѾL&|9|ͽ~J H2 CN,F/.H=XI[z T]^@0D p!L)|qf9:OpB`o(:m#m#>Jķp8(({X+d&.Ϥ35: o%SexMrbS@CGDǠxy 1w2fpXa\g`d9'7UhJ2S!c, L'150GTJ^r&%`ru-gO85k.}CjkB^R&s­o4%t_30?UWԕ~7]4M `_/,ʪ#=y b/ (6r;[|ɎG;fI`I3F6ZpxY?\NkJl xuciԍ''LrVA/y?KRm$mcx^nt47tEOX8à MiSşt M z [gO|oUǍƩM2A|)(KDb"ZM7,YWNm4o7#N0c dz:"b I R]ܜّPvnt{.Zk8fsppurȂ؅s IW`uvd#'HX障U=LPӬEd:S5J8hc^V?b]@jbakP&;YYгx;ΤpuEyÅ38N`M8!PhDZ^ aJɜ@zAܝiHv_yuu .qD,'I?_ީ9;΃[pW԰`W"taFYOzcayy6-n F'=_\=̈́r7/)g, b'z3Ȏ`*7շ7Ճv`^෾Udd:ttqJgC9`t@)yCj϶mo'|-b8+'ϟI? qIpN!6|1tj;&cn8  ӉYOEb+/Dl`L ioiٸ,{PAGRw"Γm 3#û<)1c * c=lɋg}aȭ>EA̒ܐ7 8&tzNX wWJҿZ|ƨPßQh&$95%zQ:)''$Sa:c-o{ߣhP5y7W29?~ļE "(&ܚ@Zq|N>Yf< Ӯiggk։̘B ͋( ?Q0Q,GnUN˧^t Td蒓2#T{&X ,cc ɌYGF]^R4iRD9\0t G9L4#겍#6 EX{Bwdzr h<#qM}YD[@<08f<_P,_.7J58cP)G4`=kupyWh Uaui'`q;'nv42SҤLj$3 Y _lfEXh (PLi8K|CҊ(aap7DL-f wZ,OóqO#9 "5 m-݅?g6eo~u Y&exY=>%RM^eUvtdUO[UQ4HnjW$*Q BL-w: nVWtY XeӢ \ă%ľYUР+K,xSQ؈~.k`5rmb;i1j"-@`}v#VPZ` q9A cGģr'J7z[v{P6ΥRJN}oKiD#y fSljd` mVZ"ҼoaaD޾?: y7-OtNȅip8Al|V󅅶V30Z&Z |[sش:!> Szrz\iWKL?M8c.|r|"ZWZɬ?WsԔj+ '2frG(6.ht.BrϯAkņdG 4F Cz$!D S0r=ٞ⇸yj.D#6^ <;Q cm L"xt!o`Ѹ-VtrEXNcİc/HLOᖬeϳt_YVVn4^ddB-UKYaXE9^$Dtæ=yeE;(+fņ:.kxq,pr{!&g]*SQa ʟA.I8PIK;k5g} ۤI$S_VlH>=^1G@3p~úm}ۀVmB[n"ǠRKbm\ 7(Ig7$Lae:\FlΡq;IMjj EԤ7~P40ޚ- WzpGEC*`e]na d8J,4)hz(E^&yM~_GI孲 W]żeRɤL8yW7>j5oC?lV\?kvfrE˛Q6sv\cLLJlnnn9{IO1 JA?g-,~5ptMkOEel>ū?_fPVnٶAWWLƔ[x}cפ0ԼqaGY4-58 4*ȅH(FQK0w\kBGC܏'< G6}6[QǺL3Q˫,dDFEBDa(8gdb4 Md8LyzǽZ$8̦d2š-u iᘗ W,.F%2č>.-x{7ǣcGCV9a,S1|komx7)9pZScte\uL ǭE*_]r_:Ӗu<7`p &ҕ`@mwp^.Fȕ]:TӖ4ѫ& Dd?V6^ZFݤRE>5GoXw2"}`;K:(aj9%߾2#p &d΀mRYdK& ܸ||@K%=B&~5/дaxk _P?ЂY0,~%@_4C%ju^co< `KNf峀)qro{Bm +]O^ wN06p\KRd(P %RebrF,=ZY|?FU?`k ;%H630s䮻+޳p0,`L==Yn o鯀àl';wO N;:5륔tZ%\ƣ pwlHdz VFB$ ;5(ʸ;lm5dѫ tc(1Ye Ku$Gs.-QYd*H&BȄ[ 'A8|y/Xf:S)!l˭jllZinTg1 Uiu)Qh[2$ٸ\obHXDP`~z}GQjjBSY:BJC̥SDE!Ve)9R,LVՎF*{9r8pjFkC*1ʭ^5NTz3Re('UEBp<&VjUʿZ),,Nޮ;x]ğG=UؒVC2TpT"PqrN)KjD=-wgcVvv6CF.nz*;)31us)^1L-x4bO2ғgMBʐEg ΂CH3=Vi+\r9~;(")ץ Je-Efr6𝂞|歃Z6P[-G%ZYn狯Z0+(`U">Q4͉ͬ*4V*Sz|9]A=p34P!|PFwL؂ԩjw@~Vf 7vymHuF`OiFG$e+h](,fdظN^3Fg@b7FDPHyl}.Cn[n|Qn{_M/k^D'  =W̓x!zi1+.7^,cvUfv  M7,B&Cq4(k* 򙧪g>q'HYM'J׸; .FQ7P")̴ Kl~QGx0E#Kpk'3H\c(m+z`*)?!$_]}+BEbj4O3ԇ3ոed\%Le!Z:?tVrRM}]F÷XVG+R/SA7 @T{KD6T~M|P6oAq2T3*㳦OxcСcW;{'<$(B_y8&stqu @U3qZ VGW$ua]!-cm-#hllb #} LcvD@CX+Xl @9t,^EzT%.? k@Upp$"u SԆ~OE'ݍcʀk]px>hktGIjC8*vvTO*_J8dnY<%F/|kPǁ 篞>F@&yI::iP(¿"|nw [ϷT sc+KIRROu4A!'@H ? Z4ؽG \9aS|m҅я*GRN'%@e/eCAa7kFk cw8vP?ʻE<:HO-9I~v-R钐[u;YZ&Fl3e}ocTً&&EH\$ zByYnp]"h =Nm BZ R E6Y8מ<( iǍi4$䎴]B*,ѴBųʦSЪG\*p&gs8{Df8,Qep7^42EWZ4Y9|۬-EEnZ)ND`h%1}hՆ+/"ZLw;hͷ8O.|:*?}^j)ǘrFlĺ0ε I`od6`$Wa[D`zT}?QD0D@fM؉-iwҬjo}4UL'jS",Aٻl-Pr̺#Q-z\a b#$ rvFfJ7ޜ$-o"t <0}˝ e"DŽ0(`ڀl㝇ڝ&ES(n/FsR $j ]/ȾġE wF*&jUKKQ^L+|b1H IDv (L`?{[?%_1%vt`,36űǎuYj_\y5:nƸv2ɍXԊC #$ʢ&ikaE!_ L#\gA#rLÁk#5b?_ -Ns 3ft Ewg|2C<+pM;+}c$ؤq݉0o96[ؽ_H/OH.V!(y?8Z9n>DZ8voq8H|#ߙnr~PY0 o9vcwƚ>~S86Mٻ{7щww7E t#JPϢmK -Iт'ZX z6[K^ wejմ83e\c~rg_C3gꐵdG1}KK3LJ)2{D֦ g`muUY>/+e|*c cF=xIp'z7v }\0A)h./B3+-y:bLnQg*q©YAjL!)o2&(t 2Xf.G *=JT"lR=)==fVtE MmEH}PG@K:gFQ\9wrڀBt'@fUxN,&+$ob%5%(5FM[VV;(SS{,2`)j,|nL QV nW'F(Ğޣ̥03{@E0${]` W+ b@>8}Z˃-a5wP /\~EHr4:RQ "Ȣ+7B_w]v71m,w=?7XW7\YMM]  C\C^ 4X)7c~=DW[~ 첊zBK{p '`:r6cq Ke֒7 e(Nf$n#B%+^.pgkŜK7"y7JuN#F4q%dWFjbpRᣮwQZ8 ~O8`j% GcB8ּ| [ X{cC>Ҥ9 M8%{$rIYzOV҃ȫm@rv .;8nF`{ eyW!HJ@^V'y9i ׃&:M41}qlcO^%P],]AYetwn۰$k6Aq3.d|.-̳;5iv.='_R1=;[k$IҸ$' L7>y<*7fo2EXB7_c8?:!HK Y}!¿_ b?_g /wv쿾=x0z0z0"2J_?.-6*)>aq 2X+{HmK.gkw, /@JVx[4Iß/ܜGw񟶞o|95<0  :eA ]f.gE =~w4$-]& v)ӡV{"V8^mEšgq#)jQZX[63,djN6keϲzA0c;aKEqefwC2ʺ'@]^zm=베/1л]St -pu${EszeQLٴ3BҾcɲRu r@ A/טmRmeu6/W{NKet?$ļ?.^>~)i潏n70;B&xkḵ\8^\6ZG1 (}̉|y|?@f˽vGZ`oKVTkt;DvvY:1_@{^yC710v㔢;`;Ť3g=Qh~?RGl?'0eg|l wp3k?g#7c3o NC\t2Z,@Y+׳?;bVS`gàMHvJ4S9M$3/" ++L=w{וlǕGW$@‘#v"9yh`Gd!a zF:Y'w שhL;'Y4ϚähwPn4(G 2AũAAubL8FD h9;Pf%MiiH r`@9@s !:3N⌦✦4O$aE VK$HFu"5ƌݥ"\i ǔ mpd:r+7nv1|EJ;1&c+ UL+")XMTN*.d/0I;t[ɔ|=G6Mpy\wXQq0A PEJ1)]V$JG AеJ E> 05F%ғsb6J .(!lp\&PURR LF3Dj21=LG Y^ȦWtA8'aRqkH.@?Dr<ہѣQXcO#fD4cr\g5RmcyNz}nS PNN8$ZIs)y`X2k*i|c@0"aU N6 )ͤCERg{@:c"R8C{d9vtuNHS0fƓž*MOw2]~?0^a[d`méNCJ`R fg2BQ¥_c5T{zms jIL.>co 𜲆%j_D LEĹGSTxz S%ody\RgZjfJ~&ѯ D65A!M,0 oZ^&a)Ni`)'97 o $p=s*vq4ko&S$&O,"xCy9r18YaBN9kzFn$Hj,.C{Oi* =J%J>[<ův]9V2eNQXJ1& -f߻VB6u"q&VL7;d@TD.(uZzV@6XialZ'2\g2։1Y[T$RIYNDB$T#5NֵC&ޱ͗I0 XLԣo*Gljh6RYaRj~ _Sk` Q񼄜ԨNe+Y]S(jo"1`O$ i&كF2c̚fzr k)0I -o0" ߥĴj٥| S9*J=Rit?ډh!)#VHl1qTCkJ9G_FV-bbۤRӮZv2f[2#)anzaFFbte}Qu(#UMrc%HhsG dJ.G X5~B{!0aޚք&Xr1C V@MTn0жv5#SsԨ糋 x"P(h{vALdaZ DVY-h`Si?No-#C[ u;{:+iOUߴ>x7ڥ\9"c'@p|L<#ډl 𛈟P)x8Wz >cY, h_l*=Nwe`p|՞+.Fg9?ue&hØ5x3w_%pk|d*y%ϕ4ŁW(5z %Η<d0W$/.7 _\hP]ECh ͫhUC_$㽂]E;C2^I3lK%M) IbV ^Vюu5;mDp%`4U4fo=+hВa0\I3d1Zwn W27eNQQ𬻏Ih)2[zKnZ!K{KQ/ qj p1^aķ9bt@m" q*"4fiIY9a3.po[؊Zѭ[Z%W'K{ED'VJ22[Ɉ8H*AW3I1.lwKe{hMvH>+hhEC.VW0a!q༥$}nv-{*/mMq2Sܷwgx7؟twp?/_Yu%ZE\}oz ܒJ 藶[׵;}tmVlt$;Zh&!)0&ݗ{tU!_Cu/[HTwjRݩF0X~H^l|jlq4CqUGXY\ 2;._EK³%Pe !ْY|de-]DK֢e⠥_,K]R7ϟ牌{AtϳḞ/7w#o|4? :lb>|o4ie72.գo1mWOy6-sXkd;=-NTcǶ&\3+flRys^5Z^twmdl`5ڛ'ǯc\S׃I^;ڝZV" ]+'HqKLQq;$eYdC[pˠKL/{,…. F XhO-&웰JGn; YiV[UtKlm8`Y1{ wrMSPedi0<(E9qN1}֬zbk{z_k{/z liJRzk0b}M5w V^15H=QDVyOӉ7C4{D|v|t\y*1 PƳ\"u{<<>P#0#WJE^NػP o2-TN6{xlƿY|HZ=k { J(4YX$Z%va/ qvKdu=#Wk e@ >yI'J1' +@5مL RҬ: :gJ9%sN ӎ9X7V--pfON6*e_ eSi̜23x^;5jN942ɶlG)"\&MNvxeE\VZ)R \n.V`ݓ",YeK2y+"B%kd"I^> 9G^|­ur\]@(h@UiR]R֦G{|Ҟ+1w8=E^8̐E~6Wakp`OݭͰw-뢟4iWf3(68Y)XsZO?a**J9an D;<]KY ܿw(1TMÉY UDTݽr]^B-ӁlpNuyx-?VpyPerYcn sDB--nK5uEn's%XGic7], ϩ?穈{J_TV=FavNyoU~9uzmy %rژX~L2sYig,΂wV>&@gƃswL˫例PwGT>$X]Tɟ$$VnioCzSЮ6a%?,QPk[uŽɣ\~p|vXtM9{O Dy?Ru>pY-'p䰻BKpK%ugɫ/wxroӷq߃ޔuٺW,/wunˁ@u|o 0{q]ؗy+RFL1r`!A!EJ䴥S=7}i90;!ݺ7ʖ- "Jw]1q%Gmy)]nG %t%,w)S$ˁdwU)yӾGQzeWYTqǽMě`NJKNޝ:{xuW}͖:=v}>zq. }7;`һxo?NoM_qMW@pn;}Ǚ[j6yRr 0ýť{6M>$=2RoS֛,zw@%Ƒ耦f#0j1_ 0z; I*&t:lQ/h՝!հTb竀Tcp(]h}5Zp+$Ye`4 : =\ ~ׅG @TIBk39,J$5in"!GjwjSCH+HӪ_ nj){jJAM enp_P;Ю6̮ / SBʹj32W? f& \F=A2 +mWB~ ͦsf_}-p#$lԶj_jnc{xU89q&N'-[B3m J@vpw>qāOHw2j0#HY;M#5$m bwWAsshWYb+}v76̿+ĤqW@@l4߂~`ppO8]; '_ 82X> Ow7,ўA}_Ah0ԣpE(j*wu<|-8pH*%wk?=AQxx+MG1_ \^l 3<*}-!]=Y]-ǩ9=+9Ӻ3K;57vg&\}=8vOlizzj4GtDw_PXm+Be8c BezN3 yYzW4#ʡ'IՖpJg/󞠇7 ;AN Lޠvg+B-m7jW |/|}I5 K{"9৆v{_[?Qѽ w+518?u]}(_ rj)5i_zjNEr@_CHW_%䬏oZ4.iy(/qa?= 7 }cKM~0 F il=ڄ*A'S1Rwc@nt]}}Aobk~b{k{mbfJ A~?'!L‹˩W<(y;[[Ke(zx c04 ːzi-W6mW$0Z\a^]BkeoCD)^ Ne{l ?Ƴ8*^zfpp%7ćAx} {A<(S utF4ʬ8'pzy`5 晵UVҬzG믵꡷^iWCR;iyc7+vfmy$ۤ[W;9=AFƑwRmʛqj T kZћw\9zG&kVj2 Y=hZ]Aު4I-+*V:kœZgmQq7Z4V:+X@CmfVZvcWVUh 6|фg-QU8kc5 ԫ&V&̓*ְ`s |Wy,76zt녷lm/^z}Ou//kV2]Nem@iAFs秛kHR1ŷ.hVjul|fZoğ?o0 YK/fHtKFHstj$R]wu]˝tZgoQ9vƔS /N˿0yo>>_>z8'kޓ,sxŸmT+x6+hh+ 19݊xhi4"ZZ%{ͭ?V rޓkkO {8D i:i6$%!F[$&8t=He*U9v=>'#Dށvvx꡾"q pymB?6xC8Oj xI4ރm> *xMܝ"Pڪ{CXTV׆"Ģܥ) Mv9myKXNU`  M67cX!zAߟ p"8# W8F x S;߆שW۝S@[oǍk܁3ۆ#w8~Y&w{\oŋg/R}q[kvn{]^5ۭB`8!g)neD+S@.­Йz/ցE718 G(kt\| N@9fؽ} kdW\_5\Ąɵ4*zG%kVjۋ f/o.(ս|Zfl4[@@>J!8t@;-{#ժks GMir+(;<<i[߷*o1l*",|ȥF"zuvgLY4L)Ll2 PP1_Gx17 D g8ءNt\ } :?EB}zt D"sTnUz߇^o$;OCCOr?GLjZ BW5V]<q1ML'T#2H%MC.]=8Z-) h'szz3`NwՃ_#QR)>In8S]vZ>riMIAίo6a>.B{@ N"$Y0m]OOtDotpt/GbЀ> :#au ʾ5(ʥ ,j9XfJ7LPJPf\"n@m 65" $i\ٲWdpI ?E %'X O񂽪"up[xm&RZ!T|Yw-n!xM$q(bd3S0 %) {q͠nA@Dj.B*D$C2ł$H7Jrl8i].fIa|oh,ި8w.f"['3 sc͙PYo"El]@ݟ +2TFbpH\ΚU՚"TG^?;>F ֖ĄZâߧGtVƤѹQ(jM^!dpOC/5|Fts:R^+*NϺ'$(%;Up?심uwN)`vhVefK4ijF_k7/Wǜ[;I_/wYM@W[\]WWW=OTR |z[OD?m?5wRss_ŷm*dۏ@#՛<`~Ig1" >=NH PN_|ׂVjJU ~TI媎? 7\ѯ8v4@tuO'n4eUį-l$ b~PlVV &q"=,OJ 1^7=pwZL BXPi8"A'|̻쐠$vs)0j^9So'5ZmEu%S:Z]m7# ش܆q6VñBKUR^1,hMi(+xQ|7w=Z~4P+D j׸UmBgZCLۅpܹG'&2P#mI4,cKXpSZpM'nE,n)6PD O>&Q5U~aGoVArxt\y2wIi&q RO3Wv`'ylvjjWO|(k AIt0],6Cg$k,T+x;0P) ޽1&PEj0ps{MOMLp~@JV(xcF&*/޻ 3QcKt/l? V 1Rœ4I#v܎x#~dvD^-]u-l\Ւ[%fG@yl[Izh$o~H<Ug_3%[҃̆V *k{R];V]htbI/STYװNO+c '*h"e vr wq?u3@#YtAN.G氹c30k*!d"^L @h@v^xv[[hoIvXA{2悳 !0Q^0 vt7XukDތ}R&=d4N"vAB/-0pLBrgss8i9`;ķIzKhL+sFqt=:}q6*(V2Gqa;EAa'Lo3O'1yn$͑-P{{A%A ϕ*jV;B+!JIyo,[/"cTE; l FBp4F{(a<>`+`tɏw 6Њf4C/P p[ + a*ip9 n4 Mq'\Q͠'q[w-y]S騱X鶂n0b#Z#z !W&\L$B4I@3~b1 h\Х͍l)2 7 ?هk׬zqXU̎V,H10pl@.޴XAYA\p}#0*a.}& a稶QP8*b@p!IZ wŮK/f k;T@^J;LZltiL ǧofo-o}8g9Bp šZ8Y^LRn8ӖkmG8Ho:8@M>\ @#`bEA ^6Ld,T:v |ԚYs@kk gp+ 'Oa3qitՍXi\H"}&sEϰs !+@.AhuUYiDe$h\fp@ e% xxᔆ&5TG4 zLo4h% UT X˰{ItP.IE*IGiO be\."I]EjO}3 wo@[P(N%>L6)N]x o}('m՝֌R)w*t)XnRf8VuՇ{k^,ҵ/߼_`q3?E&eo֏1FRv sR9xWDW쿁,j4ò[7m؇ӡt:/@S%?y,FW,p0XnU5 `# <KQ\v PNK#n=ʃ-=k:=sj?my1{G^17抪}YSfѳ  A71}l,A! F9#UI, =NB %"̍]BS7!j, &EFUb1 _6Ăd1 ٵhQ4lt4 ǯLX#i1S,²1T0.]Q$|䛆)\7ʚ;{LcoM K!)zuKt]85M X8=kcNƤݵh9|va`Xn7DE2 PZ8: nΚ RcU6\uM v>xE?+q yNJJ/nJ{_>I8c ,=xvBu(9S*s g:T›o|//a&DҦ(dr"[o^g:b/I4g~zAwNlﭷٵ7E$JhQ)>{Vȍ]]|kA5=RA0.”P7 b#O`q0@,z"&@Q; xSyJzxJo>݇/w|Bo{c?f^ o;-qqb+-Y8,Kk_Crxˡ(ɛicudzXwD.&]MUIJ,.P2Z|H[q#? gȀ^L|-6 )hcжr' UgF< !J^'OK;ºTy 7Ug_аpsl=QiV/Ubi)L'iJ*=3@.GZ{it\$ᵜʣgH,5%qvm2鼺j5qf = 'Rh[Eማ/;kJ9FHš^mdA dHG>QpWz>Q˻*<9arg؝M4I iffb%2\֋g/,oq!=RFfڔTc#R4+)U+"5m!@;ҠT6Bp}8OR:|='fO4 HPPܣ¹6F d Z K`jO =)%FA o]i,]بyjy GY^]Dq aӳDZ"> b??2em~h Y^,ҩ1K17%9|{UfpL-zfO*T;۞{eA)Wd_0f;+\D}| HaZ#7/9ZQs"ڻ|C"ɴt^ΒhMvtNJGDn `@/{+{h? /Kv|zT&}D3SW!ʭV2aTlr*ڜ襞F>rRuo8t<ðqFmják)rE\nu "[f^'3Jo)fx㭀4ja?luZFtrCPXP`lK FKXot㠑Qt5zjM{`0}3:֑p"(Yu6a\&F$! f{OGoʉtxi(&yնr*NVx_5:6l ]$4pA~Iٹ|?(b[UT)Oy(@@a>z^b 5c2{Un5qL:. GG}Y Ăr`@eU@>P *7vETӠT(?(ր>bdo9s V)@*yK9>E0w%$$!V ұ?X>\[g̹X,qDXd>=oSq\§܏e91zzk' ΅\ Ǝ݆S8jt5Hח{ 6 `EK68굡hn _Ѣ^<qo <=IlrʇǿKo3F78Wf4ώDQ꛳P_LlV66y/ؼuءM4FTfTܫTdVO l5Xl zŽw >DY1QDq zO>P;!fّ=;a]q§ΟL|6uQZSP[/f> UU:KoGp0K02]CW&}<8y]+8P&[xu7werX\̲id̓_- ^Γ%A-[<ڙ#N<7Xu[Rb{,EzlT^#C":W^L:S&0#6h328$ {AH@8h}ݐ `p` )=\^QDMWbK7vLA!@VS<$O&@iz@,)Zj: eMޅI6@Կn,PFH3cq5C/.fC^r؄DNi5 B>dJ0C({\v= CGuC-K79g<  NhI.͕\[AIB d7n@$-LErMi Tf*5tjXCb ʒX94/.0茣XІ)e*V cN Lt,d"&)ݪ ȴ5:A;$UhkjM0!\ +T.W}F)Y`&-Qcӱ:$`m;.fTS)I zGdQv*F-(D@Sm.¨;j-C4b:n7|v: dS* M1*uJ:絃h//~vC\ ).@-&X\P^ZrRҳ8QQ~ *}ɨc5RQ9{T{[UT&A^ML^ 9ֵA:|U[1Q~=4 УsSW;H̤k"=xtw6@}E9!*<% #q5\WQ#Y%W\c)Rxhs ߡLXzؿ WpX{k$rqS7P(P* i:jyIquBJ 񟋔@,K)!l!_xa04awz-&{ bm sg618(Hݞ.g^t5yArcىplLd4W_;Q(QKgX?T]5gYũN,a;>{m$-Mi^|qGAU>p2Ov25Bq;߿WZ?_B즾@ 1 7LC,֝*snm89u1XB:o&Z W<>Q;z<zZڷ|yAW]/Od[fWZ[$0&O㝹#ϣF0U汓۶8nxF9 ^Q4EA՚JZ3H{6$wjqf6lPmh 8YÜ#yVȗ{闶7ťe4%1c7Kqk0,_ީ<4<ɅIz =pMbx4Nz!3QMOMe$uIe ؒ.= mY` [5zOF2xo+y;>Hyy /8X*-+E2˪2I~Q&BA@lj{u]neC>M1 !,PB^ TC?{"ZE{FQb_sdUQMȨTz")-k2ȴd Մ$,ZDa^ bigrQ M \h fRDJh8݈0.{sQmQxVJqhAC!/x/|("^jud~<#ĘX fqe쀇XhKG$Slݤ(fy۶bX=ТK)wL]b1@ef+ rRz^zte9@U4-Q ,EaYՈ@H1 yETY-sN #ɺ@L<)d";Mnٸ3C#4[Rkۨ-SJRX˿s8Zx/v-KDg"nYj Hk.s33$ nsWрS7dK쳌Uߓ #ln^%9lj>|pr֛C(ڎhF($SԠ'_)GMNF D@(SJW<&];Q,ܣ.Ol&iF)٪ l,IHr)"5ʄ9l'$zԘIÈ,Jr[~8=&' `D $7&iF> )8V؀ j> ip#T/9n g˿yAA5#}ҕ$]!OF*&?Դx3eU1Y3S8v;#O`^J׺PJҳx[5dd/;PrI`6Mʓ 9渊Ck˾| ugCQ&YLRҘ,%V\]a/:x;;jJ͜RŖ;eop f}Pr6.GPy:(.\nO 3q֙ο.HFiC?B "2dztv)2΄)h&7d\OZ";y=T(=M4h~]Ɉ򬤶 /,QX󵠌lf6 .TNFi"܄@I=7uA Sp:y6jvaY%.i:PDQNl<3ԟ1k}8X#zbFYSpɭi&I>_SG-46dD8G<g>gvNtܑ^T|8 yqWRM$7\2 CoEG`9UROi[j=њ\1|BכҚ5IqZѢaP)GX@LMc1[+p$ IHa*H6eO 8ڑ5FpɒG<ŁζA4҅pR>Dgj5>+[H3FI~t2˺Tãa1t ]2G> H7,`-X.FScZd˓zLT%G 0 ST@G,$0 'RZ"q}n*#$yŜC:`P,hI6[ !U̹ma UR@Fqt{2歹VIz 0g }$bxdŹMB6E\ j2Ci+G!Zs Uwd(Kpx *F$)d|p,Pl6]g>\ǕyqqZ΢G N3ua}eX;~׀mV+;t+jpl+(+Q9T0SA 8.EY/-*@uz:/5ؓӚ/GiLY%ٻPs$uo.)*).e]2aFSNrɹT`w}i4 8F#p8 z(<Mߋ@HKfŽ#eM!$- ) o {1Hmς 2-wa Kxۂ)syt$ 5艖90ў=MF٠#'qwt~'-u/"&v( &%~su֔j[ RE sy-7y r@=GSqك?#ݩc?KT xh#Ckq*6i%A9e(,\EUiZiJCtJ|Z!HSq#zC in') c69g QY$%~H+ػNEIZjL״H@b*4Я9>nOV;PJ QVO%8}qc^%|FЂnKAI!?5oj ~KT1zn@ypX}#}+VHGm;ȆN 3Uj*7^teXfi_´ ȏ\6\XC;7#| ZGYz]xAH !7n'SBrdv#0jAzU/I^ 1̏e;%'t?X _@^3ԁmT].q67[[|+.v!Db[MZqz㽔b2zb3S<\ F?Oދ(;h/@H5D,g1?{ڱ0Gq>sxe7"lz* TĜ؂<9%n2K>;ԊM +=RStL/fAy!MQCpEش*p0I~ l/E.'mK?:xaӋb 4OV?r4VL/ȍ>lxlV$ñL[+ Þo)fjA~|YGaٳa:JbWbFfTZ&!3=/ ǟJ"5y^ nǟ6@M! àq_' WL趧iEC5Dª3mz47kk߅'JrZAk\NPW >́;j5T bEsYɭbQKihYU-XO)9U$mCa'U-LXh^Kv=MAX&pT DX-=6.\RIF?yD";PUĜFx.ajr9VjE~r;UaTLODA~I 9f (2-BM<tiitGҴm N*U-ٰrP% )3iLHe?XZ`KN ,|='߃f t{ .QiN<ʔ^5)lM1K*R3R*Nhzc/%3o4X8YDrB8w(آvIyэ rBH'%e&\'mCJ)w5 19~׭rk ~w/O.m\ LhAjCe#C`DvqV՟kEř/|5HR@sSv3 !(}V~1`B!L> zI%F5q05Pc#QC$l@Sj/bT=g5+Z[G&{Vy͡M3 ]Q%VxQ4tӍ e61O6A% Q4gWJT`5ە 4%<ލChu{HlN.s"g^\+4tocP/D@ GIJ Vn@e ~%uURߒ*,V, V3tjK%Jt T$(KcP&bo͖5S7$^#-yhfR'_YGMl]1J|)6׳A_d$8/2Y`86O0L-.UВJ؍,ܗF̈́l[?͊kѣl #w> Iu悐Κb$`` zF+GFXFGoZ?#zT3bRBF$5$8M+x_0Du}Fn)&P]\2WZ$yz9f"ؽ5tE 1n=mN+)0S4m{4do>D{bd!ٲ-KDb{7yxG0Hev糿u\ɲlf-{WWWWW pƉ#F.Uu~ gp&0 W,gݼe:bM^PHw=oފe[A0fý5-dN Jp&y\'H&NF*+.(Fխs}-u{-l6Q-%:97ZF:Jz_nFbh&'[`SyhBhEѯuInta#?n)0W (ZC?.Oͧzi%1GvD^D$&x%FB:_U%[O/Cm.w|XZH~8hjBZƳn7zƳۀ0h&u=b6V0Ы0ڥF1X‚ F 9̬82(y$#S̆;hM*-}t8 DH@'Q$qmM\ٴ*E#Ih#N\,Ѕ;tΆȗs]?L"TXݺ ,\W{Y}$5-EAI^ -VuzHGf2)=wq;+9pYx7u^X #\rJ)!?Yv(=GAєCqe| bV\2(sSL#ȋc='s#VZ\ҤŒv`hl4k/Zc&pgtC#05 xz%۸˩N@έjَ]gs׽IxAڒm^0C; ~al mQ?+R/3:$Z Wʂ-.9eNg%-wÜie{'52C*/!&ۨF58.7ñ쭊=j*4"fy5&d p>09cʺQ>*>@*y}ҽD+a)cYAH*>%ꃰo/MUxwTNb\D!dx@Z$5 A{ Bl1(pi~1X?_M;N# (R \r\5LjRl,P]5yl \ 'KeI2Ize?dQgiNֹO'asO"0@E |Ԍ.G  D39tn ޒ ڕP׬!5 eH'N10«$$4ς6N/?Xi2 @d`=} H}\zЅomgD uFaG}gWG<&2Qy޵h^6ҦndZgk?H"HvVsӫӃ+ai{x*6x 'E,/rip;mnJTr}2.^*SOerH`aX){ъBk ӎ+>Qڅ'vc`#5΄Rٍ\L}|V)m _nHG$qZtJGIl!eojR R 5R@:Vm)j Ycy"4e]/Aö sAkGx"Qk_^p: uqF1'WU%WJ ﻖGVȚ(Qs!8;@Bˌއ ЉQT\46+i7`)4a`fa47ޱx9>ɑLJ6uTՏڦ$PvqФ;fosI⸈ OimXRG1*,DߴY1[* YYѨT{;˺ŕi:}/蒎ح"FtvlI͖o=L Ј0$+1{-">7:GSTYe6b(D`J3 bTuLaSt"$<ڝAs$t5" |TLq]8 Y]m55b.xЌW>TNo_Xowͻ94[ؔgQX QwK9*#,k, lz+snLI7RPВ=<79B-tn2z5|}-eMR$KHZqrf u5׉)iYMn8/o oDp`E} 'sYc2M(eSJy Z~ƓcSKR^ N&έQp)bGv#J{ @E\iVӵ8jb[kPjoXQ4 Ā F0i%) l6>Ŀ+R"ÚZ02n8A΅~A aE%U=O!ߩ'+%i``Reoʞ >$rRvz#*&&g@9T\o <#:&ah;b MF> ?I5~.Yt|pe)2'){l*'̚MV7wY|hzuP7Gƨ \6_{ē nۀ%BQy(wcrXTɸ~+=K/LG{ QEkѸ́@;MlY,Y1YQiCě%rNc鳹9) G|vl}R8ZPj=1;hQ쇷RIg7jl0g"֓XbA'=]>J'>H8M0xY|6Н,ơ:mVUjUSKG̾XCg}YnT_JC9!؎hٻ㌴f"ʖZLggMtshX>7ᮐ d4 '݌؇:}r[Wbc -/=͛rn A)Sd'm[.E1;Q!'.1N4!O۵w_i܎K4dPe)"R f"]irY!P_2/'Hßy9͙ O_$܀k{TU@K8DcV2`Jj\c!#=R¼JgLsB< I=ʨJ9'{MvFOd~fk ~ZϒeobY%C9Q)l,vL),+C5 aliΡB ʂ0`%̢!sFCx=wߑDڥ#fݐl #.~U.ݖ ;Zq||}bfBs5yZ#҆~h#aż#C>8S,Ԣ Q藽Gšv=`(eЂVg9*(;sAAp;NmBT/_0ƭsJ'[3mjm{,|\s|<Օߐ/ַ1a Ƥn͡3DK;6o۠91 w!Hgbgia-N[--猑0-! sc =a$8^U9jUi5f2Q-Zαa5H~b?CJg+¤C7,1j}m4s*aŭLD[&\W0ʄfjT LS~8h)l`TDž9`4=SsԤZ![d Fi³NGIk$ӈŚصuXAO0g!j#[PPȈT[T( 1/{.Uiv ;曦}RIբ8YԆH2fR۾~Udea9 iC`~Hg )(, p*ێvj>;>$GX 5z6#)љ(~pJAX'B8C х4*}d0 b⑱# @2>%]'=eO:{%aI j4HOD/=&Ѳb&kݔ R֎^}+|I7jնeId潨!&M6fQH\B4 %^WWlΡF6y G|eZc8I,E{nlUN;.#&| B}P:"UF'E~i,61 N=Z@W^4;kbԺ[7&mAo yIrB,V'j]RB4nՕ3'j VJqɴ!m]zxKQw8JwK[1hŶ UEp >`\hEyA?UBEphPʼnxJjcektTgBӨڃ(_!4215V7 >Y쑲~ %Agða9Gj? ^qIw8b=~Gb?МzOI\ ,"!Oa4*?x0}b," L<7wxlruv2`Idkғ ~|A PJ ˻1~3/:|AlInMmؚ $=KL\AЗX 8 H"c~ֿ6,B%9R.sƅLd bG#hP$quF#70IЗI!4 $.+ }n۪&X(#V0ֳQjV5U)[z@Ubʴugx@p{'7hLzfr@IoHyO6zbpoS R6OK$d 3+ä>(?NNkyM=d 2ZA8QjHxW?2P|D=1F} LсBSJ[Yj.,dim2KJz1blZ0,A" W][k|o4aSЯO qۯF„\f}_{ I KpHaXjCx9to6An'^7z~ߩ GU7 as¹vpU>hL^Ț,=.إ֙ Bc,`Xյ,m!6L-l9]ҁi]̢_vL-"Hqa J fRMD; z۪LISo`ZI*UjN6GV$S(R;]Evq{&mýԘYHǙToMŜʩvib2}*HIngsԔOF&H)!*xW"iNNOrח+A.#@biZ1:՟U'b}ӂtڮHGnz)/̿g#rϹ3$R2cMڀJ7sy[ªMkhkЂEfs?rvo[يTnW#|W! 'Ue(ѕ.1|/%[hHN/Yˣ/={sL_vQrm} r5cveyl :${S}WXMKI\'H.?,XYf/MRXpÅ99](JUeJϡ2Ny]ӈWIT wO>4~ivk8kZ1rHF8b-̹8LSo#fJ%7[]&\+wϾٶ`ftX)^)o%ajshi [I%D߶%jDV ޖpWFW鰯nŴBQʋk.*0"E`TVQK) O5MƅmmKcy5q O!NxdުD? "UOqT)Z?HGI,.Ufk$=n1A, 36h-sBgfƥ ԮFؔ=l`ͱ4ĉǵ۹[hsz(,Q=J@x5l~:Wz֒Ir12 ^*nDZXj`'cCeul뼀4UZ .vs.Ea1 ]5k6vq']Ǵg$Q 42"'RR QU~dKG,mAh"kz5ɾd!o*[nRw4yҨpg߀@ڥRʘCy')|K[筓Q0WUO@VaKlBQLɊsu=nA:<|MA!pLV {c˜K+""w%ň,U,RDB F/ Ӓ%^XBrI+W_k۳Ľnh.4/VG] Gp:Ԇ{V"!_]Z#7e{3%rҌѾ#K+1A7j5LdK>hd&4RB|7ˀiɑN )Z9KeeY7F(0NUtͩ`Ƌ8L j#k2g+x2xT1[pQS*Z)vJ<;S9h!wԪ_B-I F7 S.:^;d@~<;qJKO#NDK4,ZؐE+0<"{ @R &D:zpX}ݩvM{E m*d.57f:[s* w=:ݥ%!V^vL˯G.J~@%'`r {X;p@CXP *4~i)|ǎhz$ ŹUhmHGô*$.wjT 3 eC' Y$}Uek/qݑl~RZҫ3rQe"yI`܅~pv{GQwI'^dn˺5BÕ ]4:DeO zzQ5h<6čTaba@΄)׏]"qvք h11U'S L8[#9p/IC5skuVpFPP4i]2F\Z6WDedJz+K{DTP[Ab ,! Mn4*6USI\ gI22m (z Uu7oxJQfo"jo+գM/tr\IsnRV˥9Bk0շeX_Ϯwީ9Fef/rɼ*EP_1kфyX⠩9"cou }'fJټUh/ܵw.OEۢ15 gw9=L L>@5ļhA~ޢ8B2$MDCl5;'5h#EټTs7hl_emS|ǐJ`:VVQ%mQe J,#AiѮal5x5_͢:LB5q/E,e~Y፤rhKi`M#E~IiK2i\YRxN.zfU`Q GVHOsݻ(|k`͕oNC DDR,ys ׬N?䜹q1'#*;iݷ"uOIxX|xS2I("r bDMAgW9 5g%cǨaRqQq>+l°|2Mx#}zalB>dxmݲЇTU;L/{1pŚFp`a*+WuVKGWӂef 9?XY!z`1hd>niͤ+JyY=vעJQ{+ ȀV4oI n@!jrx!EŨW-\WÄDzp^R zeW\]E0ܥs붆"2]Aȥ%4N32]{,UDԪ \O3ܞ"XPnjlhÄs>)kcQj9m#ܐYSAm{W2e\!݆od?3d /lvMb5m]LoJ%wtpVV=vҷ^ gIWY {SᴱvW )zl9lFq.| Fh3)4 MLE)Iۺ?NzB;gYyU~'Ie&2}Չ)Gl<+TKʙȬ2ݞH-s+o$,4Hc]sPXxH!r%ʲv^8S^3̖'.0aN┺%?:=lĢ]r"d ]q"$Z-Zk]y *z)"'o ˺[[%ra.n-,\Ȼ]{u{0,b0"ypuo@XE@n0}K+>ZgWwe*0طGc11vf<|tnf 2A:D0,ݽz ^l!{icj,*2/)jhISΖbE7(F|呣O!ql-JȗzE/Ӟp&"M &٭P4 8s֎o&6}AcqGVa)p"b Kr?bAQ@=`Z8\lXęH2ra)_s۸ F\OZVM=IX"f]e= 33kj'?MbbJtJ$ڛ_.{_h52 eyfhLD }]"] ;Z^|w2C EUBua-1Bmv=Fē*J^(>^Dep:m5*t慷kZsv?pol+T\\O98M G .E_ W}=dUl[> œj(U,Dj 1̙{(-hU)x1Ơ6^Yh]@H.S0(2 *hSIm:Ff`0XY(8 НAaX5t!9Ua^j< b-؋/[4Яg"AL.PPts[` #=GF|)]rs~\{IT&.VT{J(%ӹcA:MqRT'v=:,K&nX5'v8jȺ@;wjC&kjo>>͎vs=r1-b)~)I =A׷C vsJ 9z^k^](]!ּxZ^^BcO@A'q&lɠlJvJJ1P_% !|J]C˺+(O!(- yW%(k~0EYsR.+L4yǧD׷Ejy4]ePϢEĈ1獨Qh\Åg:V9YRfN8W0zr tC8?mw~n6ߗVā.[vni⊂y\AmPgUd]=ZmoHslL-eφ2EaoA/q ~IivP!m6 ?{o ]`qL lm3LҜ7Mwgh6&kaiO*wow)"&+?gIpeզ"夨-&Kja,!>z7zNO'*q0O:Ct牵m F䖔;N>z6ҥAK/ gb^x)`1{V)M*X6DJTm0?zyr@*'RʭLQU¢TAU,E#\^SAse~/[!L`=_h=2mm>0ZFۏ{ɿMR<<6*ە[mF>3膦$x#aJ&I} K,! 80ƛ8LC QubYSK `Q0 d1fqJmr"{G x-c)c)-l2bq&2AÙ+|C@0QxFE+Q}iؕ0{:ګ^ǁ?!gsAz~Sm|S(jWjcVG-zxAj]{& B{>OQVQj]}U?cqXAݨZhM7Zo hӫwX:yp\qm^=,CsOc5PPuۯU_c8 P 6wlQp TU m!+!4 aLhL B^_{5, 6)CyiO[UO-yT\a84}xKZ;!Yy`]xG6-Gۏ*ϽͭOw,> Gx?N/^0x`~F2 pqyJi7Y~P\db)`%۫>֨SQ&;fQ}} i)HWgȞ8 "S%)J40 ]I}U& KtUI՜*Q IDAYJ rĒ67JΔa0%[kT6ov5$vMPBKڌȒX]BlPt*H,7r8l,7_Wn~6bxdT엾Vy? `qRRyr'W+ϟ?_?l[8PyiCL = a@r_̦2TBۗ6zh6< &1oeccN{e̟\y20)ko_WWb6;+(>J[j~3xٴ!+ a|JKѨ!#iL!*DX=:'>(=b G UF[I<i s޲ˢz.+#D#XԊL#ؙɛ5" cfP~raLYx/UK6g Gܡ{EQt@nCxpKMPUo hҶ=#xM( ba42 PlEQmk. +nl[(#L=R69l/=:4&8F]hTpp#ZU71 Lw:0.GNvgeBxgthrHRgs _MhHm:<AQ!: GT-Ön:ۣF dY 1T#&~Z`z,xߋIla~ rq n`܁ g(Ii.1=i&)%齪j,^zЫlTŠ.c{wA@ i 3JtuQ#D.psz(iOҡn 2#GʜBˁK+2Ыׁ <!k<޲ytm;Yb%+"K(F!:.U@vF\;knFR|Oa(}wCbxMYLQЮKW4_A⠋n3ZZC arL)>%8t|Y7!ThJ~l #*'3BpUvIX[_U̯(r2iLe{( z9hIԦqshK9?,r>Ւ/l((&yz e%&; Q3Pr .U#g1MR5jm `;!e@,7Yg b:_pZoG>CoȼyEWEmߡ4Ѧg[d^aɶ%ځ>t]pYc#RڋxzUyH勹ea#A LS0Oņb6C'5gH~edy3;xCHKyGb~\58fe,E|2]g#fU %6xl%MO,R̕J#:R8A8:)m@FST 9*G;e lI(y#uI50IL{l;-?gO]w#vZSqbsԎ`SDŽsTO/ joh'E#ME%T;3}1$iFГJ. auKc12m^ 6`@s<O̪e^ ir`Ckӗi@"6wHiۊ9L -S1LF7OuVsʡL-ιGjoJ8.0n:XAMu{Bw7],$8;+B+j@1*jYVtj? lUC_8'DZTzR=JbkO׆_|:k܀^xIX1+8D)ԻJHRpj X5)9jQ=9}sGfBrN#[׍j$H]ᡇOz!0'ijݫw62<+MiHLgc JМ[ cwAL* & ElJ"rs TkO-GI\ڢYk|o)]m`8A]sݴ uHD|,«[ @S}9S~l4C2\s\_/L nCƆ 吘1.YPoFz8dVҜign\D]ik$TbҞW#b^\0mNVişY e{Dc^'+@zNqpKD\¶dx/|KѸejGB=VCɘfTT#.&Az:Hxuz8ʹYYU+cB!Xq8,ܳ).!ӆ~턖݁!^qmڙ[;@[@ŹH3Tňtg!inxG+46+2_C%19|?At~+?+[)ϭw?cOk)l?6'bP \>[6ŭ!aS{P1 ZLJ-JBAd TyTocWs^G~~r>@l?߯±Jpqʪ6޷!S1.- c2ot g%?=;֝ԩYw|P;&N?صOvW.Tsu+fOVhU7h0dc$|Uѯ*WfՖ~|Xz|Dz|_m'_=կ+ ;SLB/bAJ8֮ǡm: \]-nŐ֝l_y9Ļ^񴇗(wbV.`F׶Wh|O H TOF#k( <3xIKžeo}}ѧ@ (C(/2 : `okr :-b7>ƶ/U2$І􃌻Ph h$}| +M6u1 8hc<گ:+I42K,4f] _8A)0" YaenRL`n4ARToގ;V ƖS'[ώ`]c,c/MHHil$>jz U/xj@oau@"("٤?aZNJߪ^`(_^ԻĥJ8xp@!t/H!_ j#rk~!ׅMm.x5P{MȘr * >$O]FA0vCQ:$ =̄LGt*BaS WLLBQukF}E.8ʄiN8П &;RMSLwtzBR>[&r&oJdf>B9;?#+8en2ٰNdA`P 6is@'zC>5y蠲Kv6iw%N'7>{z{4T hTN6q^GJfGFD6C^6(5o-)>--x7o+?gw(w?!@1S:r+qʸEuԧ"p*69"?'nrκ=oc.OCØvR,ɀD I"lGRGG+w1{xڨbmŪ_S{=\yi?pT=wasѤR h#N#%ƍڀeWqUٚ^0Z.u@yn ;_ Vl'JN6 oGLCB8m<{Tymp~cA]댡S) Vӆ"ҹXԆYV6QIC ;!f~]' ^ZTDIey$#hCiC5t9,?0ѕۂ2qxi~F#BK {0yVDSs#W_acv8Y +&鲠YIh |zX=AVװzzM` l;BVUa,F ӵ%<߇Sfܥo@L/LRJ3Gi},o?.Y~kw,bk/FM&)UϲcѰDPd^6f#gPa-1f,MPw״, ;.K8JƆ.R bH,`cB o֩:̦^{?d,=ݦ#)u\YYݍc8e-=K[9tfS+N|+bwӚy aVks 줓+K++#9Ƚ[vH}s̜xv6zSnYi_GӾhLlg{awuQjFaob ޽p˙y<˚SZ3p)vs^NףMӦ DG'rB QRjѦX8T69܉t0+}B6 \_$ksԔ/39(`6aknJ':NZrĩiKңbhzn (ge△<[ёNDG}S奊5Ɇv\G::exSH_}|[{o~l Z6_s;b0,h\^,J\Ulc"Y8aۂ2zkGGGkWY%L){OX$V7H AGɏ_MqyW|y*䶴dܥƕd( C }!tUV/_A4X.T3/͈iqcv`}voyګnt\ǥd H)A76MyђĄ}qqpfjyLSW"v4,ҩ϶7*ߞhR4~}mb4AzXiTa_2o7 -?7>Io?_nlPYwwZL-6><Ǖ7z_vl~@kй8'GlT:rl/fITJUTVjB$}BnryZ~r"sГ/}OBJ|翅%0,z8i ͍-VR*ϟ?_Jzk/pǞ/zmr/x˂3?$(|n/x/ Py2?++W0-x\{Fm0QZ?Lԙ6 [Wrm>_N{\6gMas#/^"+i0Jl`٠ KT+>BnPi9!h b`0PQ#$ҏªZ? g|H  i8U+ULU?-Qo@ӪWbȓ~[ֻDϧ#7qot-:"Rة|tih &QAU0:g+ZG0pnO*գZaUR$g[ sKvPivzE0vp z=~(l/`]^`Ba}֎c-p[oG7cxs;uZٺN俯&$o&_vGOʊ39i6ᓳ iE1{g,' kdOMXu 6S e_Ap  mfgxsx)5Q!?y{*V׽_O~ K~©ۿPAV+|y1Qj ?ayrᄄ y]|o9\]՞i0Ps(]B$Г@.P#KF=~g,c}OȤ)b9++BR*Cf`Em;4hc*EP'7'Tk֥ٕ=7TkVٕ= V֙YJnvX}8!W6|ϝ!d_r 4e-IxXtx'ҧ vG*jp [)hΥ+aZ2vdVA4:/gzRGm!|.(7][0Gϻs^'6?,\!pXj+!|NCT;jQ;leID~ D$QggiD]tՒ=ƾ̅+K?D]J녓/YA(&+-gv'N2<`w<WNo0%`'$Bz+ fYJ>s9f2b#xN?RٿЯP'Ne`tNRzcks@@7>b0&W$+uJaW E:mq ._y>N? gҴ^tX/+jELC=?ndwintP2~o:^Lhz,s6 9 T?E`&Ozxֽ[I4C%pnn\0d҆l$^!06Gх{!cAE_VQ+JYx[fP0f">K?|ϝ'_O'u-@ꍤ=! _r!Iѯ`hǙ@KX UV$?l6_U~̮yDMlpQ*=$ o|եD~8#D%;3zC]>mg8cG_?<(gD"<[{scJ$/ܔ1z)7N%)^)i85^QFbE(?=V1+[]^.uR:LQoPçd?inpޫpB1ԩ@AK>%=DG^FQ#^E-6FQrZx\t*'Yn~zQ*em*V]o~uNYs:]!:`[pos{+iSC[|]觻ޟy37k_5aGD57㱬u2MIv0G'6,:B u)SV671{NhB&aA0"{LѤc;VjsDCQ7\hJaMP*/!Ɠ_yn;;;ǯX,RpUkIfl|6+3FxR O|y˜\/"XPoRbMM??~Z n~F4KUΎgeY)RqwQ:[E6v㿋 .rCe(a.Ezu{+ֱo3uRksu?I,ܔlx]{8˳ٟ6y n)癩JNKmy:xSY%/1\0PQ/)\zUU['=zG#v߁~6>m<(H1:}=!_ٛxA1h8՗8YnjƂmc):M Tv0J ]\fo-i6r: 7ntr7TW@oG~cLWY5(oU~0K7}E4"Qt)yhA0&/JrѻbZ? 3IZ@+?b*7c|xv[w0]'߳:#O^aQ(pC#q N 5%y@X'@2I`Iq5ư.Pnw6qi0M|akhBmDR}Y13|^n3*rĒHQ%vld3>|60 q O2zB`mz5eGV֧^0g8T:=G zTx{&'GMitxKD`f%B!Ã1]i#bYNIbڲpd|z,s* KcI"eaEAb}ڇM:<Vdy! # +d]]_BFoDXe :/ f:Y xr-pւ cxY=# F/n uII)nJkۏ?[=+e9q:5{ټLmlf@  !d[)H_L;7OA>|m9Թm<[U9Iέ` ;>qC켩Tqc^W RF㐿z<ͺZԹ #K9q&AGo1]KThƗe80ۅ+ }ZF1-ZscWvƹ}Itc-n)p.?"xi6K0jDGGpcTV~j¨6߲pf0ɘ#fVU} gLr}Ö2aJ pSP,>%6zuA2}u}2h [f Im%2{NrQ, $tjk@Ƭ\=՚VL%' &axG,ۇM;nsN?}8`ʚl+.:{m XEځA Kx؍f)%{DRx d_ғm7Z{ *^Hru=+dY}YԴ5lgf*t3?3Kew64ŢF-J jVZ$)}]rRr3V:9?'~>#H LpĬ93 ^#$Vu5|sB;Y%"V, Vr}4:XqW>^I +zxRL.LFJ6C+-7zeöU2ifq-V[MVW1+{2Y8b4jAtզҫ髙a6 T⤉@rSC?U+kjF&+'inMVZy$zW&1jdb땛>t>Qz]t)Z-̟_9k.+97mi@+xRsیWVzQ.\JMH+S$|luQrgJ"&X{V+lJK,NIJzeH)(LʓQN)ՊO9QkT&$: @#MTy|{&ccr4$v7S;nfSfq4@R31\2RZc!a0 FD/W)]#t{OeO^ +4ҺR)ó U O8@ -f$kl].B*z}>Qo?p|hYi _h~g->ww>w>_[X'~?7^ٵaDy #~ꇫh0`y6=h;?=Dq_6+);o/w[5פO~}<=n%_27X6\]H .SGMeev>FS"YrIBdoӿ_~w' ?}Tymn;x ӀfCxs1f%CdAĢ+:уKFA\^Պr1PF0?~?{.績>iyڮa;xz/O*{KCDGu;c2V \ ΩC}v2>d9 bbLõuf6wLTMْCcf&+]Yb"K^{Ilq!K+>CмҴ4VF#V40X+&(j;QKn[^J \R?Os{'I~_QSf̓V?\=4.5ɦb)W` J0.I#m^@4'^pD`|rdvMxqUU el;B\`\piQv\WhOŏ`FWaO`̐Ca麾r$:Nr@$3ZQnr'#955[;"Ip$Aqh0M cЍ7_0+p AJ/>҂WW@GPT](媑Ԯ؛.]Х=0ous~#Ktf0H Xt}T}W?:="HW,JkKDQ_#yF~X8՟H͸GX7cV.7܉wWu 'E?zuC> ,tLTN*^25 1aLn#~QW;ogVs%Mh4DT/>@%V,k1sK|Fu,l+Og/G?`(x.m> 荹O)&X\Ӫ6܂StAZͬv O.K1'Rauǵ~v$& PS~isO4mox5'jjsj{$BkDEtn]e%7~MqZAcSNRn7-=ac9Nл6DnzxhtuiB2霦4ŴaM4w !l29,ko6޸Z8.ݟ.4'Is ^{QRZjx1;Z`/؞~: 4㲟jok*:;x~s,;IyówZ5=VVk ڲ(c~K8OF[ԋfqT{㚵9lYͲܺ;}7c Q ~hNT-qG2[*= [PE#bĨw۽Gc]PJ|=O' 9a)'Xd$&>?]G16!@YzAlux-t jc[fKސI xr:Ꚕ(Qi6IWƹU&z}rE>4Rt]kQ]@nhԥ2~Q4B#8zyT㽕Hzα&Hzl$J XVY8D`׻']+!4Qs+Y3>S ͓se:@Xht|Sb;!O*f v$wٸL=a!rw;d)9rs’+H:CATDl!%A|x1Ax!(FW:8F bH4IF0@${i!zgmsXqH-2fFgkEA릭|6RU$T _Ձ3;(Q(31([4'ڟf1X?_/X?#_^acx߻OTɽ`Q|^lx}8t#Љ;w+{fʃF]ᾐv- 3 |oeP#nmeK^A%QP^x 1 Д;RBs% !%'i;7 zwW)y3Vvr˝*O6+)7=mww#IǾ-u:`䵢r{W#v5(Ы@ )7ۏѮN@wۥW0Ա9ŕ /Qe"ydrA$dpQ65xr8xCB{~W,Bxv6i5|#U9++# +9ADHփ8rMf=f*0-S84!R chT,OAEYl喔J߃qԽp0DKdk&kCI[fj\^ fÏ(*VܦЄlFY x* Bj;^yF4}tv62A!Lj6A0FWP Nypt@ !vT(#؋fI$<Ν$OC a SYz!v!n){*o)|`3dJsra3_+ˡXU{=%:Abph$p2Jܰy6Q'h[HOcek <J3@79S ñ0()Bs&g-3 RNPӿ>< E3 PIIg2ٍ*6TE@ mI[b,P:f* ,&BHKHI '/G~tGJQ/4(-ı9fN9i٥ 0pڸXY4"Z=5 $(M3|ֱ"LK7P>N& >)ň>sfb:>gAI6QnDe4(FrΡpD~8`iI?:'IN" ͷE2d:CD9T`\n~2@,XuQka(D|s`~.g!kV-]sI.#Bٮ)!5S*pj6˟Ltp=0vTnN踔JL `x8Cx(LrzRuV)}ԎgӅ\ 'T-[a]dJ+3 >l{Ku̗l?L?Wl?&oGߡ?IZIX*~,ϕG';O𛢜N?]h405>x+H餱G A=|S-0зӰ_?9^Tn3M{U f`z#/h;;7-Ys즦ElhA[ΉiQxq{0u/6*޸4…2,NxL7&莒JLěqtC ‘L`{9N]q:'+w uܳ9J:K^2 >LK,lֵuXC척 oR:Ld1Wmda"+5@.$y !+3xu6= a#tNeo~1 ߑ6W` 1N !6_eݠ"*bԣ j9! Lj4ڴ~R`kP_Pgu:e hG#:A^ӡ$gkr+ ;$F&SwՒNch 6^K {Azd犕%ftH =%Y#>PCr?!,7ʜX펽t%5]) , ]0Ó3 wb3@%@5OO-ʙ+W|3[~[^, D*~)WRͳ[JNf(3ED^6~ē)Φ4-Gp>_pcV)ȖZǗ`)'3ca4@%v@/ ގ|} 7 4sHUwVWiw6̼Ȋ6v ic9 I넕[gX}Q9Rhw r98E礴.}gy5Uqޟ6k-_GrH<2`}&a#.N <{$z0[5:E{!U<yάeeRCv֛~mC(SsaM{V[w'+|݀2 &*7R*QDJPȸK.jƊ Q4x;?kgA1cRM\Jhx*"aWb907\4 C˰\?UIC zi &NCI/`;ʰ/SP^)sMj" \ϔ~"xoMi]᯾CB dxBaqj) l^&D@hۡ쪣k0,V>7 8Ⱦ/::2b)\wQQKvBTJr@.$ .7|[ (%u Rbs05|x$܏v_|mg5ĭ %\`scr NJQ@bB+Dg(nZ Λ8a|O0șMztf1\'+Je §eL+-M-_gRjr |Y48SoIKνnuX3:лf'V2 *zV&Y|Y 06T>=jFN:L/S &P&xuN]R>Ri?R#x {+5c%0G+Z3 EW wKH_/$9y"8Eޣy+exPw>m&KB(?F)cD jo ̈eL%0 aiDS^xm@fX mKH_'C8E0+j0ef>İFӐwcҬ?$fSDE[P$nO~V:|i&uS&$?#$x-(:,&mD!{HƯm<{9: Ĝp15c䨨fXt[lr^>H,2LMqmBT66$ib_J6m*XCq }=w:5y&xM- JgiL¢D 8wFTTm7jŔP0ʗ v2.x`=Z{U|zJ2AH+̕}*תDrET<ߨWrSF .x$ 2F/E ƲICvcf TYM|wG%cd"S d? Gak&x/\Wjck WO%kwϳM]@l\!|iڛ&pWDoSV2ߺf>77:+~%|3 Ǹ9BE\PX`.լj1T9^:/DmO[fϸrQ0 ;m*_M9"HeHb8 ~~-vt}Tu{v*Uz8D6`9 G8̉53LQ﫱05L0I=g_2uLFeSNnƥtE0gN~ Q}z.PnՃE>LKbҘEk]/Cik$P%\kQh i,O`2dzqR+qIȂ )2Rugg֪KM}%ZXnB j\rUG*24~U"OwA291"(;qK稊8+chs;_nָ/tSwuRwĮꟘ"s鄦͢H19]sedv"vM)c&ҮnL.ڍՈgSLhˢ"3<<\z*چ1O`ݶ t怮I/r־JOl\p 74u&ŬB H˹E|z Q>Ii.^,Ta{W*O>IoR7o%@.],?g,?3ʼnOQ7JOop}V]Lz <i,|<,`A *95a7vD&w2[?RЭ-[i-dE#~Phdm+ uG0/ yN`,BO3i$FvU<.2d GH\Ң*7>+(pR3R!rS›C2~24pLȍj̀2mkk Ybhv~h)wLnq0Yq5oauI+8^ LvQCo{U4UAwz+~%^ 펯0x9eCuT">Xxo0vbZ'8)Ƥ(5B)~=?|/ȧ~<z0 ZUiD"2֨T)-I6;\\wI<,0_ >"ވP1 BD Cǟ4nWTyo1o8TG5+ *hb!Hj Y_pj9g p25B-z V6j8&ٔYܒlhd ]YK}( ]dkΜ- 3LAMNTxP$MFЁH7@4.8+2,N&%γ:04XJάL2 l%}mwZeywV;1 {RfYP`hrOwl>/&8CA=Ld@dO`8ct8DT9@<#b6T +Dkh~Ajf ?Okke BY zCYn$9DDi<4 J Ӎ mj/w!Z]&ە3{⃾j{< 1JZ8M]%eVq/<3m|Klrߵ"u=|H >#"]0bWo%#D!h{z݌Y] e $u~ɰl^!ǚwTq]]W(1H/\D =f4kJ"SUǩ ( Vt[[[[ woywz?wl>UQeFytoz}r¾JW# AWaQ\/q z\U0ټ@YSN?F\oTavl%UObrY30C}UCǚ7ɎMfڴDdT¦AݍL}2=K(Ob&ɛML+`if< 4H͙g1IoR8rK޹CܡIź8cUf1{x(OGt 'R;1,6PC=@fB_a-n7 n5OOj~Nq 6Pm#O(UfCjGI7@-X;#.gh01s^Ni eXJ\Y&V@UgZՙFmQ*2rK4nЪ3q?8.hE%w O*:f$EZ+苮ΫP|V=+=ױUzRc  jT MI8Iig~>oZs{bAjizoT`։Tv#S]_*#є=\}?}Yf';.R)WNVr_O8.2 l5G ~OT^$eڱU(JV*s&,e5dʦzg6#-aasyjx9kDÁ{JlDg;tև`ky!idmz \/gѾmsz2vW7(ڂ]k "Mk[" -WgY, ;񊜁4D쪟G3VT |rk?k7om=8dIϙHʳcf/ -MRH%U$d+="NZI1?"Dgм9^;}Sx/ aǝi **ޏ =R"Lc^ }z)H (3caBj?(L!(>8"vt%#.kNJ=X%QdUoU' Ac,|zϏrvAכ*4Ng#~F(A0.C!.Ko1x16xx\A,n ޾7_vomAKg/Ma/ ɨbO:f!Ѱ̞B;wfNmMQb,1~n߆'A줥g,hFWӟҒ$Xhl e#ֳ ,>)/f٧9%8Dž9VGlDʇDb/Mh( K8 Y+ZCkPL'bPvN$p]rS0PL`SsI|ҦB5XaE Ŕi#ss%dt@+Ux5 6jQ #krK@8`3UE)B2 8 6MEPt,Gϑw h?i.UXic`-)a)'gmt7yPE :N`#BO8fh$#ȻΉc"d G~< xs9Cx +]d>is}=-3~9Vل)+(XHY8lgۥA$+^ :Cɍ/_x'#12~ L@=*_UAdnR(EC['}V1?ߓ.|# GKI2{j'=J^p=&R-AuȀE5Z6XއmRH7d:Q-PښYlڦk*T͘a.5Ydœ̂&%n.^1I8ml5xN97 Ɔ./Q *No0I_>C?ș]:Ӥ(tl# p< ]v6ɮ!;aGԓ_/NjlȖ@Jby$[.|d 6UH9 ,+:ܩK,#e=ah" -˪ZV$O a?*+.BGrGi0nejmPyDWit#QźYRbZ3pH RCՋ%ᕠ'TVn9ldՁ] $-1G({#~(5a M5;'{W/G/ 9`=eP0<:FxIg6b1a0dC*03? \AG*lRs?pL..NMr eș-[ZH;M[<4 "s''HŪr㞗xQ2;i/xH흑(梴S'3RPafC%GW''H""/&$))S#glr>ٰĨnj}ACAf'qKEQ7mNC%M wቐ7Unw6q"DDeG4Q(K%H19 ;F=-g.Ep2U1&&]Feq"ntՃFuzMUQTu6ͷftgFE7͖S.Bl)[uyyݚDQ֣6V?cX{=A rr0?U[zxy@q,KaŻ6έspdeou6"gy[[Ӫ@ [x@W^TYKڮoAqb[b2Ψ~̻3'kq{`RTqw!9. V&WY/}NBΟwXp|R8oߝ盟;;Zڈ)w(4}Ϋ$u1)B$H. }=PqTz !f) YV;j j{-럾#T2N%iRʰ清Zc_SϘߚ蓷=-Zw,b[;!O,X`U?DAPʼntINɞ?G!zV84#ƞ"@/$M$W)4|B5JZsa\\C>E5}z Dul='?9^YO4)m"!bL5h 2Au/a5QZtЬ~cA#o3x6#ͺWj;JI;jҐ1"0NBרv7s[D~5aaL$+ y;LYC*a]yXRS{hX%ť{`gWi2ץr/{ɇ`\xu%bS 1XאHG:GzD}ɲT|Iќpԃw5DpQNB QY#v>&F&b6 [;ūĆWm&nWu Lm%+fڻc4X#fӀQh5`=R>WVq7[TKrM'o&z3²~vA`ԠuIݪ]OQXڗ d5@N_in6[ߴj'?jVV] z 'czHz|K^4y9pE`ڴM Z[/[#\*c1iJW@MKj[v>%q=8\N'?ggoo60G} N0S (L_̽d<^&X[%0Df؁7SX1.UTYbں{wvhvaƂOch2܀ܫ!YD ]Qz >LPpsux(nauL0Xc&KY3 8 ШqDMx~l*QW;(p8:MgAWn S[ yWьJĵ("8cv@hfUmY]vgA\L`l(/^ͼ@4Vtt L%b'jr[n#;b\JE?V1ZL߱DP)5!ܔ{< j|T /=(q: -8PˉO(ʜY;pG͖1DP!{J=Dhڍ_dUrHe|?פ]4.K19AGy5z`AV pYMtsAEג,!G1BZAq:F~ وPߩ4iFH,[c fwA_5k1>QvBͦzP>=&|lx/=qB޲MtUtBEz€_EfmmQ?;Rve_Τ񋁞'I.% J)3pt 1FΐaPL6ĭ*V AG-L$,zMq(jg惶H0Gg>ihل^GT8!&bQ)}ۈlh"bfا~ p:I0'Ú.tBoxcu$U!>Y$,;2h{ ˠpك;K?%/{ (O3K¯Eˌ.tjzNw=z^屉%ͲY89s.wm胈 {FE8jOJy^K':"iyޤZfǩy1t/pPW9p*U.dAd~gNl#C "KBP'iNzxBsZ,FU \"nQ7ѮcJ&/FeZ}_;x??5{jg]XO?> hI<}t'O=_ͣI" 똒Yҁ!*춎<@iK c vM@A=fzO%D/ULلc\w F uR9bTN()d?9Lq\56ւ jB3. <*eTweX^My㊗ޕqJD<Nݢt929J,N,Hޠ܁":pbЛ<+ jyS{:O[{lw7cc2bi3(T\Ǔ#N7kWleN4K5$ɏiMל]?e8d+h@-C'6;{'j2e8䨹zȾ:[ۉW ;VF vICHǓ3I+) Tl=#E6Bw!=t#~8 .&9KuZub5V})]uOj0Uʄ4}Pt*[5&~':|^spb_}hZ$ *i P F=*o#OlFc-V47_ ߡ:.B)%p}2"8̦szβ"LB^СvANQֿF)j~ZEo5uM {Z)fcPad22Z0WvM?8eO2ٻ0QX`ƪN`Z"A Wnh,]HR,e:  V{cH$Q`[[7AΤ#g9hŴm,%1QF+Vއߘ~YC6æ ]u*}h⾣vjbQŗJT‘GT46|e‘?&J]ek^Y|>yKݪ;r%{7 JDwZ,޲*CRRjq}cB×n4C%JjM%1#44h 9*cέr#ӶN|J;h5\,Ӫ%t0z(F}e 2+Sf!٥ai0k㗺y,DFP,um]BrE>HR:tRT26ճi4? -J&ظP}[D܆3_Sg7dͥqKgMsZ2WhDf`D6Q.i قڒY)AAcmjWlJ= \.J ;ዔ = /U8TSbw p=`Du䷒hJ+z$eu 1-NcNFÇRL[PXo6.rk7%:wfJD1b,H%mV`WE/ |6(-7:70UmT+O?(ӡK࡞ya/e?em.Ӥ7;g;?;?/p -*-}yt̛Eڧ˸2rv r|ob/ؽ&a@.Wm_="_9hqVeΛz׭d5KjdۛrL?*>xeFx ,%#)XţagRűѭYXr]SVrhfv5Oqd^9{wG,u/٧ȋzT!T7z^+)hV1cf>g֪'"%Oc%V_si$.=T_xf~ήeٸ̾ToID吉?ZnFR*jɴ\{1k[8Ñyx =QbQ|"}}r_Vޮy群qmMp?/~&I2V5jyͩ7NNNVo`-њ Yt+vKfa? P>F@|:Ɠ';[|/= lݝNS@78l%9yLCb( X\9ZM>fQLdj/nPb+i+ ã{i@mA^:A턣 ~}{}D%D<$K%*NNmu }jd8F]_rƇ Z:Y#:l0< # 3 ς:e)x@:phM f}8mC*ڕL|dtAMR E,U3ʕ zN;#i=C%::I U9yyU=r>@8`~'Z{/ɳ {M<1b`ktJx{w\=YzTy nsGFrJQBS/wI98F]΅gUPghpEWr#$GA1۫v8Q=GxW?M< pWab%;f0td6bxAuYɪemds-H%>'~Z e7_!(Y ]Jdb~{ax"c֮ nx+~z.貫ʪz%s;|wIfav'M%5xeN|*):Gx!+3x䑷$#tI4 l4d0~8ڻ) h$/UiOxJ~*Nj%-iNؼ,%@:+UߕaPɫ/ĻkLL.H,}^"Lv,Π&+Žo6(+vgU:,Ք)DEQ\9WD˲G@#vToEP v]QlL"MIb6DxԡYgFk2Ob:)#Q_%)&wag+ iɺ2;z}G!9Q yue -`x!\;ء'OX:vuefIlFBĹiwM)r[5AjV^eEʖС+{ Y=`cKQ/렺W`7!uVC2ί xU0dp$4RhٻHά.Ĵ&,wE5IhyB {V7'^TA^\yխi0F#1 >Y;d 1HoX|JD5)g"0 3;&Ã)28 d9GфN-NPx]:( 5Rk,2I!fOݑ:6wkLO٢t7okR,=y<ƗqcI\1꣫e"`1&W,,-2{+?O.1 RĔtSĠ+[Qw:_7TR_o| }^ԉ^7V=}oX_&a!uFM` CK_}%|7[*2 BZPf\y;7*e]}y(!^N_8[i br}vt}]Q0H~߾Fd^9r(:Y`;PDvP`w0N&D } j(gN֖GyFwPu 5y MݛfgLe =d6sD*zy o a<3hFx ́|8 I#!m RlUH>榻t= l= ʊkUw0Nro5:AϷU*=y:hq0ӯœ}xu2~\>3Yeۜ^ sZsV( lQx!)(@;nrw+WS= RwJ4ߣ& > ?YSD&o97nU,O8x(ٜ*h[/Kx$j_ W6/&狿U 7~>a$Rdb9XkU؍Zl N``<j WK)2wB{!JzP+ؔYhmõ}9$=R0~O.Gϟϛq~gM.}"s{̟)[.ލw.wY~ )CT۲t :N?y[9X9󳳒 3ԋyópRvnZ%Rz  [Shlso2?l^<[<']bܣ.wu t 刎r^7CT ^FlPuCrѪfaB%\nଔ4bעx;A1M-P'^ry}n!\pZE~l 1pi[ɟ]X_mɠLjh EZ'4z_:&i,G] g^j564.EJEuYȆoZJ+=(?<U4[g掶㟶KtmASsc|mog70.2+Z8M-}1/n;wyX]dž{A@hKlϽ(0|5s8İ 5|*mGɜhH9vȾFA@թ6ޗv۪N8gUuo㨎IrGWeQY1oJ#^;j i#:׵׹]V#̱좋nsS1&$BKt6HD؞=J5o-/WfOjnwɩ}ȳ@ bv#ܨc<ݓgqj'IlKf؍+A-I*o@̓|Ix 09$}*a:x9&HE鶯z}CVEq4Oh+u< m Zy$پ#K>Zib^|VZ-8s/ӷ/ kU( a8kT|.,} v+CȴL.x& n¼@>P)d>jZ6_P?=oSȊ9N$6< Q#6Kv0z#9 ^8YdcXMe:Âνp دIϜ_u_eP{5ȸȮBxF*W)󍹺J+XZ pxQcj|}bqѡ|՛<.^}#eYĢ9vKgEs^nj<\d?%55 3Aݑ OLZEKϱRAHL΄oQ-sщdY*w֏RNq0}sr%`N;V@RQB|W#tTmR)UoH35vO̫khRY+>yg 럂ьM~Ӱ@wbf[[̎ad;9Ѽ M #QMlfm7ϐL Ӫ",ҙbSG@.7 Bs g,vT 96VƠY(MiJዤ4#慻V"Ü,eXՋzgx/hudGi=fM^IkOrKIIPcrC苵%Kp}9YղC ov7e'{3J>>/ĵBℙQN]c݌a^z9b~U=5)ZVp #9oMЬ M`<0}yK9zhUjc,NQ.$U|LeMK=~K2p:y9utƆ礐iT :vKdBZ"VKR>VڧI8W}7g}'/G Ȏ @.uuKB=qՙz>GGs31jCێ(r*K |~!gv~+s]Ӗ9äٳs s]焕:HʗE!(]Ɨ8ڋSFRN*ep|,sVtQɜv0w:.?*fm~``/ ӭO|2€܅ r a@78 Ohq=~TyNq@T}8 R;~T?M!he/aٮ?+㿕4Hk;0fsJ޼@ ,M/xD޽{Ǹo_-$ls {/b d;,-^?dS$ ƙ#j$x hcD|U\OҐ*ȼb^S1&)UiSqUtLr6%Y{uP2uNTFCV.G $^$=7j|?:j'b(J è27{uULT>+>'>7hdsVTz~s+ryfqi@Lv 4;WȒ6$:ͩF#Fw7Y3ǵ/hfq1Sϴ}tS8~\S,q"]!ڟéG"vy{ۛ_~SɊkjPHﮙVK̚NھXj6{:2zߌPE!/0I̱{GQ}{Dp{rGɂy!];e<8V! ӏ@~D3ߠz1COCm&u%'C4d0\mSʴ}jًC`nXq8؉1q~+i:.΀ҏɔ}o5Y]wm0:{|<<8n8cb8}ȧ8b6Z2#>l'OCa>_Ede')* KP8{kCʐùjQ͞eO'ðO s2;hUK/7Gvxw]W1Uk%s^r{` 4]:P7A54}Irh-T!wV4ǽbV 6n8nc( ( c 3 54 /c{QCuKrċFlk_lqӣNr vŠMZOJ O$#qCHC1I!*AGib]="cX5n\b` = | DԸK $0 N<؍A87L[Bo;7~CX'wiz'v'{T̥*2?8O"F/w @ŰGk` +{MۆAe&۶,Ս8tTg^e}GAN>x+2%52E7/WkKD&?dY-#yvOWUT`:|ʷcU&Ain=xx.n;_VB/aq7UB߀I7 piY3DzĒHer0g%eGt3`|fgƒrFq$V_E;r G6+*!QFD%>qCǭL@[籤Zv]4wb1H_3Ƃ:Y [2Bq[* jbwIoͿkxl5n"=9& }̖dj o;x2%o}+ҪڼhL1Ed -ӭGGe߫F.&zz>lF)>Ս'O=ϺMؽ/Aq M!ޜ3Έ'qCHcNɷQp>p(&"ً3Q4JN%]fM(+MƐ*DO&#[M 3n>/5&Ȭp Q0ۊv3!#o׈Y`Em+\!ڇj54%[AupVZpGiQǖ |tMUDHp6JO-ld{e#E9hf96~9P%Q`Ƃ]Fh.MK ftwf+Ԁ5ѕw..fwy׍!Y߈,:JCm$d#i)-S}|Jӭwgvk/;;?Q<2d5c>E&BV<:m8;pbwD~*-[ϗ}YOz!,<ݮ$}\/ *Na,l-#,ac9 A,LXjYS\Qذ@p#oרxA9?A>'R^w'G]^@NGw0K+l’`PF=,{wF`yDF'Q'G[2Tʇ >_Dُ~בm4CG,Gpf$}%}b)}BKd>(@F7ٿu﫠W* cXKiNשߟ4ש̛rM^~/>K~ i?z:3ޝ?BeĂɯ`,vgn\ w_80ݥ&H'﫽PIv 3 E]5>;nI(q h֛O(>-+*w>zy!~b}v MLO) y}sWpi$r}1\ߜZ_Ng{38 nmO/\XnT;`P3FdM"!p|+D;t$PX |_Tz](>Exx}72 .q8aw3]K4C@_)aqy Z PR}ubal c<ˀ6П=0ܞ 9tf_p4AB%3+R|Ghˣ, ?9#| %ܔ *m<;D άp4#99nc?"Xzb|I@[޶6/06̢}(UA4Jy`_V Nb:˹muw(nBqr BO[SwFwFjx^D ?.lo]d:>>bEzaW='yƏ2;vkKմ?*Ԭ.4FԭAamxY2uŽ?9=6G$zS`9xa2sR>/=8hgH)}Җ]L]B sV$" QUT&9j[2بl9;Y_-*uf] iA"{ЛY)o;[}6O]JH'XU ';6Sa{ce5@>p֯%@\1ֳz6x60׶5kLxQd$ga4*8:|j,l"Z^vst|vN*-BvBɍDUǑZG0}тU2G Uv38 Ӭ̧lJNzr'W{E.z9mdl #B>9 lhRҊ00:!֜z#2`Mt,2qFDP:@nz[)'e UC!`4(d\\|>"yӿ$.э; δrL錈 ˋ@S2[k_Q8i/FڊOHL Qt*2xX,FL.`xs {G FY\,@ K0~3IZE - ? 0̵͈Gh;dSDGnSN]AD{u4HHbƺ]:MO#45ߵ?e+72CΊ4g2 Ak+BwhW]=4s{ዾbT}m3n9'G:H-DK5G3Z@hW4Ԫ Xloy"XWLr'̮3 \+ggC&Lީk@̑7!o'Wsj, \@ Lי-KkHˎՖi@`MwZPz`Ffk!AUC2:O8q3@^. \O;JCuBDT sYx-/*nSvV.`wX^32i -#+KUj )ˢ&V-IHdKBED0!Ғd#XXi'󤫱8$K\~NꜼVq78dM^:Y١9ߥ+37P7P51p1|0QN6:n[{y%zH%CDG,Y{BLxx3M1T>j45skHZTS=e(g1wf=\j^>lÄXQ X>izT@?5xy>gsVDE~?2"?>Ϻi9(bOuC1f3. 7s,S%W#Z01 /Gv4b؉ agڈW(NGuF'l[FsIJ3.9=2zyA^yV&sİ/n- nŭ`DetШoq3#L\;nG~><8nQB 1.Hۇ@ہˢa8i[x4Gh]`0\1ǂb(~%EC9]L+nlPNq<@`?.ûn"6tܣ#3ǟIgzgM9>θN e\t%6,Ք0Z}~~VSx@9 P\ k0@JQ~"-PrGs|Ku̔?0VI@0$`M``vk1ACUwwfw~D3;`J{G+Q @ykhvN[p_;3%v0hC-j؟O9Tct8nAa C9*3\'@EExLfaL8h#"b=ڔ[>irL%[`nA%Y퍂V"a0zʝG4bE)҆`l`Bʙ> t6^!F O 1ꓦ=$)m:bfa܅{˙"R#rjc ~azc\mB>Rc `؍?Ц\|bЮR-_knUʰǪ?N6htg9áӟ7x&TL~!$l@\cSI OkKH#LlVY_NG [j/H]TR(` ٯ*j/%XYI{L8`j䟨(f6 kd߳9>8םx u[vxsGbUo 1 2yv}Ϸ!bā#4){O윁 r3#ύnȫH*%ڌ 8z@4²Ǵ\c!n%\\  xEH,>fK3ڳYy|xT@ڙfـ%߼<'=̇T.Bad]; ڒ$dHG)+ -o0ۍàI@d9N\ˈЯ y ]cۭΔ2Qi0m xjDpZ>!x#h8K E Lt.™RT$  # TLPIFZEh;#x&r]^ ]\8p9爮ނ5ӟe;2EdPsc+o_ ڣB{leDrmd lfN #ژYڰ0!`kXl\1@72 U E6R|s{7U)Zh;9Y!uBA Dtc#ZVf>Ai,EVM_TRS $O=_8eek^+s#ϭ}[ &WWיp'k6$f7AťV(G S1V=TBF=w= %Zk#GU ѫc$5O6ͣmi^3}'8&Fc9le0G] vg3;Ö { )Ci&!mM$BdSxÖ ɍ}5EWs>hlmby!<"#K,,qh|K9/_̓R|/KjCsE'`x| -td]ΐ XiYh> `fږ(h:-45Ϗ3_2A6Q#C%5K!Yiǘ,P'- Ě1r#;=c"/.by9%Q2U-UMruGŲj/5^ίڰx\*CL+2 %H:xSMz= T[\V )Vb/6,ҖbtȲMqǛCF=ς%eD:y%!E&SD/ŒMhsYkʐLl8=$~e(~c3DA%Q_ud&$:5n{yϦUWOK2{o>H Yܴo ^9`u;U&{Sl `!ϸ0IשC8ƃW]:dElI/3z+l)t\ u,<:\` ;} )^Mx[ ^͑ժyEk(5^W|B*EІ .hh([@Wtg > %͈a@%A7Eky"g8_.^ogVG0Դ.?q[-y{4N+LA]_%XC^RBx]5CQ2AY\_ ̬Xу KO͐J)<<{k2 fA-)>ՙ}=$>Ē$;Ke4u{@Ultg$Ed P H4#}8;/uPxm<6(1`nCth-Љ79v${œZo?`$cڇ)ġTK:9NS.9|s!%jϸK^_NC_{m pe-[/xعgt:f8LG { ,4oVQN=ATk`[z38Mxveiz}8k=|HhT A)9l ]QWwÁ8r k_ U9̾qgL05A\"wIAdH)aŵRLf'iMiex>I״eTS2J$,"'tccFi_̧ԍyX!E<\IS$N] 4uI;/NB1a+#D"OՏz+ΓUn'Z%GkR<#HV,ћ|A|1^ob!0EYATbXV#q}ᥛ5Hz <0 Fi 폎/KUڿ,ؔRZp^Dx.p'bA jA<.'Ñ})Sҝ,h =g-"rG2l;6K XFDڹg,\gPh n$>7,@#psSu]--?hKHR:a "Y,Kp? P^hV, -W# +{k"!um"I&4wkZ]lBgD7wcZPI5o9Dsqj9q'109=nan7d) U Q=IF+u|Q_D!O.q,û+c- Fe8s'ҧdވ̉B';v M((πMHh Xޫ=H1_~vi#r7ݎ4͆#wJLzgv.ulsQ?h 5FI Fqpш$cǢ0:lf2f+)ЖNLZIBFI!,~|@/u+?W3)7+xs#Ȝ;ƫe#I+˧DOPcB&P/AΎ$=>Oްw &RM=xuh< dqp3oM>`!*˚@x W{"RQ>5GX3o3 :\!;=r4I]3ϹakCW#֔=2Vƻ;җSoqQ;1FNoB/kw=tG vgLbkΗGKǑP%kEl-Zµ(*ȦއÃIbhvu` g3t=/ΧϨG̦tjk,q﵊:Hhd uF Hrb_/<\~ӘxvJFM]}Ɵ> h+>[RUwsf])JqW-M\XK!Hٰ |R:|GoN'|F3&APM SeLz'jr,~?4>)J)T#1 %nkCŁ^lDYqhkEMz_Q[ k *p&ģw:j覰mKM!C4RPr#SCt;9 λ㟏R &[+rt}G7Cb| ԎRF>r ʏ֙=yWnkaD]0]xaJִ^`8d74rG4z8EB@[^KIsJ:umt[L:O02&n Q1x;U,i6E9V@p5Ղgx'JnO>M<# TOYA90[I&etw-yIriߚ&Y!-wcH_#CZ\z;, ?ko0YbUȹ!2 5:[[[G_>?v2U5m2>Z̗ &β'2w-q )z2eI΂1? R ,AY7>]q$lc=7rW_#)zS,ABE*DltgNUVz*CH3$gzCQ1Hgl*rak i",VaݣmgKb2=-3JS@=9]W6!JJgh웹sY\><{uJUOWIYa- ]XWb@rKUPIs2kCeW~aM;z6z{YQ.wveblNf2<`No TSV; 6Rbʕ`{L3EYZIusO捳 TpEXNUU+QI8@ {C@F؟ Z4E~Ka`,0 糷g2&vK>@ldEbbCGPp͇01UUakwR;a|5uFل!zO"1L "mݤ$Tԋ+-Ss%Z-Z5`Hd5Y I^;׀wY+<ϲ2aO"n~ޥiU-鍱*gr`vza2toWU" NBɁ,$OĕqboVT F"L[?}|K`| s)SZpܟhJ_kvpEr/DH6 6(A n?TZˡ% hq&\HG ?|]͡XD^mJ 0\~.܍*8TyrAB%sOiCroLR(.4jab3+/G @UU長:QKLS ,vr|(g|:Oe}$ΓebƗdՃiA~69Qb%3C=wԱtJxP9(WGkOUD,:}h':JUPDe* i®rLjL,:wJ\A-[0fLf&63Ƙi23CZ4h Cy>#p1KJZ-P)%C8x4) bP&SD}ֈa@g^|I/ :Hc\Fy*AZ^@WHTh5BҴ ҫyBx(p{9|㈪Tpn)Gs֕7' U:uv܄PV n,cZ5GGE@>Y15ŭ%H@~B. A78Sn%ozآF*xfëLd@DTջ3ɟC0~vHŦוÇp|__lxH)Q 5^l܀ zOqӮ1;LF|in8.%x|(sX'R( R$]&E .t%_+-¢TꝖy62TI;`C}P"JtW:'"gɀ]M8͢hLDb`Rl}oK7`~"۞mgxE!I)-dqq6\F<РvsƤ z"Y};))E9E 9> R|Zzi=u\#wbXZ=Yڭo|$v#^;6p*f- 77"GLG;1ƣ_U) quh?˨KX=`yPx)K}(Wb x4&v;/]s3~IrfbQ GZ[GQ-үbM,C A2q,t/12(.փٮUM{ƸzcA4Y"8$Xi>_(z ұEDM!KSbdK "a؄a[/t' =GvEd'vT8NX݃4J LDr(JHh) SRwM釹<5jHʜva3Q]ٍ^팫IDꐹřдXIy Ҫ2DAHU *{OL1dDcTMΥf&(V8#=8gNܠr`aAp`XG_NͶ̢DQ4_RB?| )>|)PA|G `+m{O>,Mcqki>Tpg(#g PDYP I #TUzh_ƒQΞxtDή0EH_=䐟!&^6(!寐w;,f6YU9}_AmQ@߬hB_DyV)-W,W3pةDdWD>D{#؃+)DN*r*&`h6 Mq0C mLY B/o#~g n!dתK^E#2B0@$|#+C ru*FNo+G4{$( MD}yshVp`}``hP#ƢlRHTfW ' 1dո9&e^Z Ib,CtP령sz佰^`R xuBBxyrbm2xq ɛ{dsXx7R&b]U|n$46N~lAgyPoiƞͦ.P$(4S.pKZͥ6͎܌vm&)Qڂ%q Xs T%m,KEJ^iwɝ"{3"|àyĝjL9rIlp“cdp憠T$8.{6J3"7A[7Fϟ[zQw=eK:$3q4Kc<Թ“?<',ٖnnZ密bTaJ-_tHR  g;(-wV{O #Fl8\k UC{sanPodd:;>PZJABըmLG#δ;ESc{%ԀCI!ϯdj:G;aL* ǝPBiODt G3)R eb> {`%lқ,NO H3Eg>G '6sߔ&͹mœIg-aE^N>ME6iu-2(yR-ӦgxVktQt5f:P1%U`L,ѵcc|Y#{|up䬗cxA;@9=~6>o١Sk]t3YY?c}X'OnhP^}S *$"QȐ'닇Gw")*$Xzc>?0Rq{=lmnNFQ2w gp'sĶqLh0GFĔ%kpKG;3#ߵr.fg AVɹyYT~)àqBcnB0^ eC^&rS'&aX{) +q8,~8F`:O71 #@ܐ PSb1y>?{NT:­y5`(*xQs|"QCW:jE~ U3ژxU(`o{$B YxaY㨠K%*-|Wĝ=F~ZɘyO a؇%~믩HtҼ/_ S3]v7[mG81Siǐe 9ڌx]{ BV e ZSyD"4>z.z&HWB{ARee`ΒȚZ?TE)aBEem?dVCȨ_YTL2Z?QN. a6XߟWd>l;u,5dmf!> 訾Tolw$lC&W?-4xKlT.fky0)擥jcāx cIX\"޸\3;=}D Z:B;ލT1oWTb ?a0{z$rv~nhϏ wbGCדYTuch~tFI#o}$~24pb3Hz?AM3<S=XW1R hWG~5uN@G\OfwH3QINSMZ S @MH ;.R/ztQP,;2P! QSA11$:3度[8; Yݑ3ṍٷh더M5S r?$ktTm۸+蛖B )Ȣj aEc,$M )Ǎ< #G'!1y-|628J{MLϬ?1w8D"(N9[ļȪ%bOdB P'1FF,h7PZؔށ\HE[YE+K'g rbntcL4ȡCUd#UG+ycF VrF[^@B;8< բan4)BL }g=n 7 ~qu^A Ⱦ0SKKj5D>dJr[7a|6m[f$+<,)< d@j1LCalMlS&Qϑ"W"2.-b0}P(&M ٳo3Z{>W7zpeIa6$]vF#%P_ 6cŴ!ֽN W1VBRxonaw@/G]!qXEŢ^opKJш%|=7DtT8[]}9=Fw-x`M&ӾCҌ^l<$N_)z1;un)N yL"{y.WU)0ý{,!)Uob$V'k@z G!(6$R4yt:et,3#+|;Ç`FlmN*kI>_X].0Q4}`T#RŇ mL)Ȁ2#_Aeq퍝U+lD2qdy$KKq6]ͿCbfKM_gWS"P1FpnS@X6_[3e "p۔qJĕ[reTJggkX];AGы FǦyxBCR8y+%E \ܐnDFQF-OQ )./׸TKVVncܚllGXPӄGUDc,{c3}'"mdMok & kw uVW"Cvy> ܛXl>^XoP~x&21;9e0l~:,KѮ+ eTh,֕=\|藷],CW!!V& #0uqmCR5XȒ{@p #B*@v0&\^ B'l Lzu]իz8d2ƐX 'OH:=ld56zrĀ ;Bm͂qij30䨽+@ĺ; ÄezӯQN"E- ꦥ*_)4[J$s|߂I6zJ0BJ,UdhV0}X9iDf} RTH%T\aeUFT+-S2"tlfvbJE3K*Bc~I.U |!_&/T^9`JT 9 ƅО# G9eȧ+wF;KHB bdc ۄ #Tq  "dHxgm߃lE@EOKǘ6ɤ3TpuLgjkPפyxE1S;dI+/aZфpn!ސ趑 LY+ "$llKe Y&P?٤TV Sa+8NR'f1̡5_(rOw[ICOمE?$Ān.?IS y#1r-0\?&%X!D,' )- (Q4Hрi\I& 8A V'xhVNw eHh9 < D_eXF|<-;⡃C[)J\GY6 NҠ !lkiE<!õ<  +Z;|/JCf ;<:8/IWMj2C='\![;uS_ Vl2P !xn߅ -+dz)eޖ aŠ2GVްD GT|~9bR+%4|Jϱ~arU}N`f*9?pb>&.&"|U9pX ED)8_|DCh*i6OVuDqWZl4[~YϺǿl|so<=i,]ɯTpICswRy%!諤R%(fG>Gl ǘx1Fzp I*ݗ;`O8}ٔ/HaLXF#mۣƁ6j>x 6H1$Rj8}wn2̄SΣԑ#Mhڲ8!#eLi 嘝+ݓùbH&U !ʴ_WXtY3B/Ynk`ZK/{w/ ZPPUCp_߰ej4U'`~ f/2>*nNelGk.6FBmo=ꝉz4  *zr߽VqCQob{]X`ֻJO#XgV 7ޔc71Hy[S`ǑX)ܜa+ѱ#sN9#̰.*s3#"jKz< ADB=<ׁ(g*coGw,t <V'aiܷ3{? ,7`uHŃ>i D KY]Z/4\x'#NPpjh~%"pŞs07YVQm[P=&jr>Su@ÒSxa8hq/0o xP1 ]a Ir$$qy{ ^Ŝ$:VoZPosKc?#bBH{zsHOJ>Ħ8 JVᏠ;o$FaSGPQJD3C| @O~oKwx2DX  Yb%|MFÛ\R^D7լP@"U (Q5pd'vVF.|i GL[D||a}:dD !+W! \TOLExN68qfq>kn4:]w[/̑=)_-M/x8l4^Dzg *%'4=3QKeŢ{ TP&O4?w(]tLL}nL`݉˓ [Ku=bsU~9k8/&ݓ7?;Bg3Za=tdӟ;FZ_8[3m\W2#(@Z-W:#Q[$+($ y्=BH8>jMҢ`m: G-O^:%g>ysGVBNϜ'1w֚cs2LI‹1"ĚhVFq8,~bOR=87jttѵg,;EMgm8C9iq29@EڠQb녈˂  "*fQ!+C[E6޼Y^N->K"Vf^: rx5uaUpT@3q0L^F;؅drHQlȑ_ҧ{lolٗ;YiLxti@MŋrĦZoOh&ƞN:?zGʍ68БD|_[sꂯ=\Қr1+]ZbktZJ=p(g#Fj`y:BwGtq2P&'.&iKֱs 5E+GUbZJP7nī6}i݊׃)&uc7&Q{M3 I%$+]oU"~bi (rx:?h.|=,v)31p5GtZg[A&Mr ( _,^5X¸%a9 reg/I97#"^C Q_׵o]jJv9 sQÝDF;P@RO:1CyhV}w!!dwu`yC7ިFL:_T5抽>~lE!Tmeěd[TawҰ!dlRY[u"TgH"T:=?^]p%; <4 InCai <UӮ kB@ւ|9cz* T nC_":6gsِTv'2금bE*[[,%B=]*EPUEPCaUW$P z*ȢO(5Ð QtF?A#>zΝCIIVWz<@`}NPjé|BgbcچBtXTt"]uKI  LZ0k'YE8MWcPaY.0EӴJr1OG!NϑхO[f+bA^bK_b:}ctP'ya r [UB%~-cOMCu+ R9_ڡC*eUTg!6 <<Ѣ.IC4 A[X.[uCld*)Z$d/ֆ:>Sp ։=`]0ԝ+-Z9d@}kF@$2ML! bz"r"Q&<],C]^ / b2B;_iت d D)&^BRIļ\AbI>]dv_N7(լ+vpƣO4wGlh(Fc(Dӣ1å琩9BaLɤ vu2cmE6d|bFӾ@ ifQ[fCVA O bS Y_-bOM/9 }9#HB` 4w>6%~}SZb ?Ͼxś#$n{e^Boy+M5qDl) 2AVE}|Wwݰ"Set$,\Jj`-kAq7xFo}TZ078wԌc ?ƕ.GƂH%™3>FSB/#B!kK:/aM@Gi2bk'oB_L7WM9ze.E<1>ob댵ϕpEf8X !ôugLEs.c}1>\Uq>/e'f"k p9`m&j錫+Ұ&S|{ ֑3VwJfcl5qD" 2u;S|٘czƆoc8;6ZBD;Xh-BA_xr0ݩOx.ݢ |d!w1bdlN3도%w aM(8wTx0<%!_FALcS16vS dc=lDD p.i ,%vw%_μd{Ÿ s9?XQrTrP6#g\LlQi2_$ j+kYoqc~AK1=:WC9ny#]S)ߌ{3:;v3NBlLM RX~=;,RĭbZbr_@1Qx֑SZTOG0mFT"M4Di$z&SE!lN_QWBe@Ɋ1_Bh֥ |%5[s L%8@Z XN&PtS :)ORxaj* ))bSY\fSXWo"%gQA`2-]uoC-4]wi^NChM$Pbt{Zr8upsۡIDdFkSRIȳh_ӫ0pZ>/kgaO\1^73'5Yy>'9 K)Evԁ#p)ڝR&Y$ "tJjkɺrV]`W1O*kؔ>oARQdI#s< ޵!/crEI=P ReY $}kٌ, Bj弬AbЍ4ⅸP!`M"u|R/|t8c:ܖ}9ˬ#[ȮT9 wmBlZs so_c-͙{B)fZH$3 ?& 8H&){: ]k_SojM90ەer+и&2Iݰ'm$ݤkAYb.ZhGkS!q3Er] `sIG ?$H)%[aL*uR䴊*g!ɩlЎ/EUWbL*w@.M-n"]bx7(z>66P 9ΘxG?RɨeRƲݽ#7x\8f,-'s? -{ V̹2W+wӟ,c3_q(nFAuHƙ78‡0-*ODXtai$ L !\ DGu60c#AmMԘTY \n?㔐d/^ ,8zBqR~NJP*r*-m h׍9U\9>|d J ǖm9$id),穀=(@F ʿh\I?r>s*@ط8t4~> *d>"x{%A0>ZoGK3AFeGnw6_h11!0G>2~N8t!~=cS.rtl\=,2y33/p*j['~L]c`ǃ>NxѭZ 2&ƒB$F_oh_p~Zo^8$9ՠг9P?)RRQ&"B]J0YI˼2 C .cn,Y|ع HdѸ*C%N{MG#%¾d??/rF8QOɖ4 AKp]| >,.Ӊ?!@>v5:X͂uc_ 5BW<1jcM4=+Tn*|ƥp1V 䨒䩲JxTZ|b^J3Bkd\Uģ3o;q_cihjI47sfߍʌh6qK$eEki|ڭUSPW\ tL'L:& #\gN" ΐ"-<2stPzD2j4F"W0RΓcVlKnUȓiAL7soZHvr|jes)P"G==]2hwi-.}z8p / (2FFS ! ִۋUk-Ա]wuaרCsY4c;N9Rđ&"gSlt\!k^!_Af`gZ=(wyWQk8Cݪ<"FuIDƍLw ?H*+ ơva%c OfnpqJ(*Qʊ"@ rxqJjFH+hv1}sỗ@ȴ^ϺӁoaY홤$: +DOoܟ7!l{Orϖ>GDH =ޟKKRq BI˄t4[E%E3c0\[OpY%$h8Xv M`fٸd|.$7FEyf}^ppd*?/r#XQ}K:EqmmUO{wpUg#نn'ƉD> ˋ4.JNl@@ A Dk Fn3"q2J|?FG Ogij6>wy%>T-"'*Y\۟(}x~}LQeiIr󒈬 [8KZ?2 }kT` jf7&<_ .B4G2S^&xG~otT"JCTZfRb!m1{Ov ~[|#BYL:dѽ&HkBo]Q bF=lt >f%#g#"ZIeߝ k=BO4?zu|޵.PuMa;`Wd!TJt|ޱfn;xUF,>lG79N4HQm| WrA'UtnIv!0pKHa )F,L?` $HRGPK b׼:^">^Z-{"_T>"r[Vmfc!)ZHv(nֿD X%:s`&&1Fu-7 U0_YQT~~a]?;kw3.3 ;%F #5eHƊSڿ̑ݨf=-SzNqht*H6a7$~=5| mHr Bֳ@C~Q5"K{k1M1iz .qpr$vXLhוƔRg Œ2}qD)&]{ dٍKhE( qSoݑ]Ǘ?;ES`QZ}G1ds;p@G" =2V}U$sҺ2Q=#,h~^Y>oQµE8 ӿl &: C%$/F̽vaϣ}"i$j X8z60Z41 qV7Q v1ڌLb!=C'wAH)q=z}or|g֮@V11w1#|N=V) x~tc|1TehB\[aN1$Zު0e/pC,xRGIa0 s;D0^J+$[_@%}hw6S64!Zo9wߕrE9;0QF,1|av4"P5 ,# )>JVZ935) +i^e5BһH>C.%yl̜ v`C)eJ6 $k_Vȁar;g0&+RQr+$N٣>̺dZdYP.U]cH+;%|uWɼIOJ5͈T,ёEC@ WXN]"F5RD &,%vd@f,Y%E/0c˜&Ψ>$%ѡG321qhi,3]ڗ ăR%?6uF9~=cW1vɕ}*N'lϵ0ẗb׆)DOdu—ܢاR#"Tog3`s@olKtsNj3;֫sTƾ\|wOJiEJK5nERVY՝kb+wf_AU~׏`HdMYxu9WѪ$0EǼRL-rC[].@\{\$4G 0Od/+d J`4_n|06.ˎm5$m9h>~1t5~"֖k.n%kMM\Nm>YMXhhs+3k ȥ*aGʧ=O]h}יFQM4.BtThpcɭAm%[AIc[+Ӛ&S.^qIw/N@i2}#r-8SVK:zuP=|AkUjoN-SG#6Ѝqd`=G` .߿aK-j@ 0O=cr69+zUߢmHL0ȧ _3X:Pej%UA {zg >A!3h穫E,nQA~7Fx hIs>ܱ;]'6jbl<>?ꚓ"(]fHg>G=h$~y aR1Sld;%>hz1'%|5bH``!jOBX =sfqF*J̮vM[@nz%?qKGf6-9ə=mgl96R`:+E;1G5U&R4i0gv^XkYwZh'=7%[ )rt_&:Rú\fdwYbbBCU=WBZ?w9C^ΚWc[/%]tuƁ΀ozLd+[1]J]EE 2u:z79tHdO˙l 1z5rc|U2^G!p-8ig *Dm×wGP%B)B^8, \d`.7Gψ)~TDG?LUő#[=7{ռczDtwPj Z-p;Q!G ;IW s^m82gK sIN?󻣱))L1xJ8$fa:̀/" iw3u>xscBpUw910St|RG\!ľCɤ]xCC,ABSţeioR[BJ R š"UH |FvT'kL'Y9X2DwAa-[c)-c$DO aȄļD#fG\iҲe2tRX]Z\4 ? |8t'CcncQ{Τ,Ԧi9P8Iyh4JqDOŖc)cG:yєt7Uk²Q6KLe .5XI˒ 7 ޠc'1d*'4 %ލixԻfu!5PWNR[[% QAUjP$@ )gS#校)Sea`uWS9Y{t,:L^'"fkнoJ|ST"0Р+/:X[F0µcYqM4[| !$୅liNaf>)7[v7bJ(4!7S7c!pg|!2q~ly.9"Ux9ٕ~.D'C2)͸ mpũ(cdq{0 W=q78X /ŇP/{bf``OrbA|S3(YZ, $s2>k!WC "8iMQ\`1/dUKВ~2nЅ%d=TX!;|vqƝ՞(beLϖ]qΑˈ"ȨmOމژpVe- ogmK V veJV$L [Ebj&+:/" O/1t!д3¼գ.yCJP{%X`/QQ)V}*0?V@;WLLUaUta:!oZL$N-^LWa cq5UcucJD\[Sp)'ʼn#:1inDСypplfkGh֕zȭ η|ycO&tP-[ʶ@zn8fL*X<>::mw0N! ;d]R~LBESWz(KWFI#Ր(sR8DX?ɋm. VVYO2q+*! w;v…/| *2X~pupXƔvnvD{/}80&$I^~˻l:r ΋_,ch@K)dMhūˢf 1uR6 4ƫ *~5E5Zc~9J$nAyܳA [ avU0l2xub ->WY r;D/Jk 'GÓ!HkBEt֊FÆ9"RVZFe1.T =.|]MHkPX,`\NpCʔH!rQAq hN9d-ZCOgȇЖk*FX)Mck'K%y*tf8lƅbdU #@!-`j֜Tσ:FmilDLWXm֖Z@}v,":= ztL8 bƯ ozmta7a(lN@]!aɁz5C_1סZH;Ј{GU4zS+hPjH_l>ʬ(9ލ2U㰐DIb}A-NsD !Cmeg֍3HOEͮ;N8u&;uBcش[8F+.NbeN@I>j"^taqu֡;d2ӕmIr8>[ccƍN\^0}g"'ӳ=k3dMcgðnR ߷aol_;9GT`UN0}L\C3MKe"pX]q40 8 xbx&& ?Vf[3֥{Cq} A*JceMEGZz }[^ 6A* mD?ʊ,dSi $+,x~ĦJ1ٱޱISBJ|c&&jn |.ցt} =#+74L`S(f"䵎'q~ e&D0ȊQJSTe4t~\f #х;dm6t@z$< IHxHC&/I=,gH8u**!d73oNvIP6l$fCc5M`?#QWշ 93qf+[Bi4٢'苸8)]Ȓ7Bڊo]$Φ1N*B,nY!٢0Uʷ_챧bTbk[3~ XڕaǙnw譈ɉ 9 Sg>;k\m`R|$xZ4N,N?LSmO=z P`ԤEBѽտMRH\$QŽ#E,:vCx)4 &]h.  I}뢙|%/mﵣ )uV+e쁠u`dyP>_(Y//gX/?y11ӟ:ײ=n@t#6IR*SB@}D) ̇d(dpJ Ma n{)I 4 v(FfȬC+oI`&hn澱 8+}})]pI%Ouc5Bf!vh7-͓a[\f]$auȞT|+CU%E6xR9 ֓SZ%DP."#{Y Ԇ{&{EŤJkD/K ;k!= s970<7dȗ/5O/!chʟ[=mWwXHAK1[]ퟜw{VNoQry) ze7_Xl0U60 ]LЈEQ#%CDGUPDRzD1 tו? W H/ڧ;L-$c os}glO]P=bM!|9q. 2>wcPx_x5GmGR#,[~T9n <MaH3Hn(BlL8!FD T<V^Z$$PT`qh'gzʳ04/$T$  `[ ^CUx'j-,Nk1pE[eFC Z'=7 nG"];pCutA"N^~#iCPQ༵*b}h^kcOu{_9췳=jutlq6ck[RjbyrtS~$XPy|tСƁjxf@>NaVg& F9=>h vB7nk`g941aGoG6uBʞ:9qwcj3p!$@-jt6V1ցo@?Y&nV; bi/Y 4&ufcKd9SwoC5Ry0/gɆq4ȤtuF)̐6du"rsQ6&HNAiۖ[ՄԿO?VQXrWJZ/jOYxw@O <: #0ĨHG>>'"f#<^4N ̖DtPD _[z#W:Ni,);q| Hnj ysjAQkōGrd6,P" pW.*ad'k}WOߓ+XNU ?vʵvX.` !gwkɯiE<|D@knx=\P[kϭB`)J3ހ6 '=#CvCSOdgJ|TES.2&p&QziN .ET2մLl᎔ƛCp6WΛת]=3;}o;dӲ)EV%z$cJ< y;V3o-#ip`YazbH0#N! Mc!Lyf֋ t [(;nvHpD<͖DrGKCCfCu+$G2?k'< O )KyaQ|UJӏC%eOV15OQ.&tnČ ( Wz$tvHp ,`؋8E#*hC7"'-H9KdL.+h fGS1&杜OHό1xXT>ﯿQP`7ʪ!\(VnZ┸ш:",<#I\ă˜ǀ┚P*,_UC/?Ո.z葩 C|| caFAKXPPSǖ;{"ߎl#1'8A Aj?*\Y<=>/JQ |?_\?qќ o Ud; *)X~/S#e`1BUC `e3&7?HP˔#Cqz}w`;0KP_}j0G|KpJ/0+;k/Z176khq}GJqW  a4!&_>3è\ЈG9ogۼ?I(<=>3OŬq' w5i PUCTc83&ql$)` B]1xW +Jw]9UwZ&ѴRte9y7ζ'Pr9>/ALc?8=X΋Ǻf廘[6ʄGzCKtɸoӰVaWz͓ٷfq&g |asf$6.v,yHyЍ_-a.~ZvKJǍEMq)72AlwE,nA4қP`F@T^dҸ]CZ3Wr" gY9}p^KӨu4[ީi\b(w(hc6j1'EF_w˷zv[]T]rnpRc'H*$l1;eI lȝ:#ƅCaBNplZ"Yf( 5#>cJIKr4$X 7**#+7:&S k]ϡ$9 Ua0̙v/`9?ġtfsBX:g٪6|?9? $ ")ϰ ?ѹe]#bm9S"NqjY:RlF! _3 z oQ?G &$%-eFD DGh&O`úIJ$\9,GaC D`rg@5iʏ9 y[mn8sVVOA1N) \EZThju Wzu#C]/dk]O`SqE.Yf8޸DrֹTAɩRFiЈ;1lQ5'BKpUŝF+X(υ b  +AU6BYBk{obɩų(a/L1:V2KXf??lTG51DXCr(%)/NZSOH?i@S7oHgv8}·tw;=?h#[p 0ϗ?|ON_ON__:QP:SfL{d5怶Sj5"4P6@zbnYp_>-3J4:]g1a%FvVl"2ao݋jG9Y-rwV{<0<:x/VaRMU;. x` 2ؾv7g>'6 g0NU3YB'#OهwS2&Nߵx.ZOO8ųll̰!@ á3E׿@IOJab_CK{H3)/gWC2&z MM3nJ )*6)qa 4fҘN_ɍeB*#T `F`$bc(eLGF+%nql74"Ѓd"MkJe5ss'6@)V Ffhb ~gojyg=w2\d2r0`ݏH'lK<2>^6$1l g#2,2$4TGg`;;BxRŕ\c*=w*_X7ߟuntzO﵍)躃d8U3W{&KfޘFf=d9'҃ JGVwp||hSO`ЗFiZi @eG`y hȆO{w @V!(xs!OFؑ;<+rYSg_H+EX ϘG_53?Й!;kRd_<<4JIbr/KZ !BCaNqAE!ވ[=mlNƗ`Ӟ e*XF\3yTM{1Hdb+銓 l2( HdǚDlO^')MD/*e w#8h酬og g ~Nil㷧wMԸI3VmUx[S#z/fEt$ jg|GH5*;sJhG҃&fQ.c{ k|d?!Il" +w ȗU/'zp.=PWZ&a[m^3V?9>v%HArNxk(;rͺ<(9Jb^솢Km]SW2$x#?$e&K7\Nۧ9qE%XJ1Ǯ!{J~Ԃ:K=/"c W=KG*x3(S e-Z;0)9 6K\hf1(ׄOHǠ .cRLX w>8n9usFNvd5w߾SldR$_d_~}|'8R5ɔD5 @SM[b 佰,N=0R`r?tOzPt5*KP@  s7 ,(ڰJġvT &u!ka`3 >FPrX?Ye#zz8מ~޻ej$kdU~?<=}i?AAsk/j#f%xq nk +7w?޽A۩|-2 YT &9U2r>)Y) < mW++N,,  jTBQ߬[S63 M`Jf*d ht g@w'Tj]-=I ?:΄|||fU9ֻW`ŧKd !@dqÑw [|qdɛ_^0qgLI;)RK;|@cOSrr4.|NDTPncm6siw$[T9,3 Bv`yc<~ .&=!067*>r])E?r? 55?Oɸ1$lhecjzg߅YYC=YĊʗE^tP7{ y?"R=X)G՞?}U?#xR=D#,x(cw+5I[ @ m*f kx!i8Nf2x%bUi9ba?R$l}Bru7ZICi G%2,%z"g䦴Dmq-셆ucO]br3EN1M&H(_2Vɠ\5Mjx鱶 h@I\t>jR˙f w`.Z2HXλ͜_xnO,8 Z~y@.;T IwuκpOJ>x&t ;umulZEl-L.x;a+:h7JJgԋ-5Ʀ@S1"B> #U} S?YaRR%*Oy}:/~ Jm_߆O~~X͓'}렟<'5Q'g_@1c2&Sr'r-R)P[\ 6m8sJUr]*.ϲJ/>|Cr<OϤ2u_+ܯ1B |w=򥕅nYc{8g&dPrM0>Lu(>&vNW#pqл`]ܿ:ȁAe-z@؃}5G14g b83_i^}M˨dz[xmb|g%\ U0Fs943`(36ōKL-X%(ю-r /Ŏ@BkW. !%#e ]؃Bkԟ_PxK!| *L*=;&m[M`; |f. \Fx|uFھ{lnKNKԢ&/'ggH$`b'puBWn*H 3ȯ#l4tQS(Yy# a@A*$bO0M頙y W& 2a7[ @sduEN&8 ULM$Z4asK4zD)nR i8AEq?U4nWIjg4!\?U@N&?bj-t3!P 5]-T1w!=KG\C(b@dP~Yh˽hO0\+b`f"S܋Lh@c@[_#t O W5d#;Ӣs&Fbh>/f Ek[k6 Ԭ~VL2<ZLsxM10(g45Rb0&o*q 㢾/S Uk)>>rB_k--\3.mox5B'OS- "V~ղWวow\MG@Qpfl1W`}.(^+i5oGKDSW9)$Йעs h&s4xV' ,eDv(/2rpENDFm UkR!Ёve1x JFΖerP̵+LoA0"LGgώ(Π<;,ѝ7h$5d%;fpͮ`5@0FjBSx9$%:H+EQclv6uIvسh. bRQ8iX䚾cr Pgs8E_t2Aq DwC4qk2}6!/ݸ! g% RbdKpbmML ﹁w[Us r97' '~`e(_@Џ'j*8i cK2P{|Prve/as5r?:F)٘_Sʗw՝rm^m@ su|Ln;K7|2{1*J0sxWV2o& loxHРe}B86i +x5MU<9`)-c)ݍ#k/kEѴy(bv;ټ WW;;#jE7Dc'՘ v1Xb/CjdU~|wЄAziφ?xQHfkBD{Aly9.v=|-ӏlp>BRBVɌɌЌospC2\gg?}6pp,DTc8f]]A%jŅ/+;"4,Dg(l0 ]xSnӬKe1HPW~ר,Y}Pqf-) r`,+ѹ()ifޕ ̘_Ψ5'SһЕH@x>^#jz&R3N" Q[*h{ex83 '?FԐNzvFJܠ}#xQ# mh WV**?`2 e&TNBp>фs)k/~˿M%w xfIx9!B PαgheM): wT?b F1ƛHIF69<?k7Z1>ެ&FAƞff}SX ,,-h|KqsΝtN) +)٦w> ̛sd4Yd ̮"bC_:yOajA(\8 WҩЂZO{8$ T>RFn,`4z]kvk׶+fڬ7[vA sN룘9S;]¿+ܞOm`15?MC.׷Kr,^.7NNzҮ|0R7 b aEe%^+5[fh;BWk5ZZPB#z&b,39 50n02K )oVQTfժ盵Fl^Zʝr5_yUrvo*kfبFW6^}Ro;B=R}*tQ+|{|oj(%X҆Zۉǂ[ ON`B;_B/+Rn46`9ނĩapo? lS7mx[ f@%*Plu:JBPk;bT/wbcW)a7,\З` ba`El J:5X<{1ϳZmhɀC 6(3rԱM^Pedrh~5*8Ja!5% @PK *tۨaW|g}a3RaTEG(< 8k[(KyLmd K&"x;OPJAnV[vyY[ەjЬ֊^V/ZOD!j` dW$JJPcJF`Q-5(q :E鋉Bh /b{ӗ>}c^vJ%\fPccT x%ǘ8lJڐ7NnHIa.hzQx5C^JmʸylIq&6,!FoR7|\-z~5(]Ѕܤ0€熛57W!oKd#(!ܰϺA<$.2>$H>pE@țpo۝B\NFJVmEbJ!v_+Xp${%~d{oPQ6ߐ4e}?W XT2bf &ҧ.|ꍰ A ;p+4U2ŕwhbsZኲ=QNҨ=]}R2;? gCCNC*iSzpAŌL>G a"]cigq !(jP Lm[, "dq5Č>P@$Q̥qN8"l߇}C,@ƒF Jzܮ5zUoڝFKJ[zoUFˑS9ͱ;GynZCxt싹tɊG4qocgθg흿޵Oo1,/(dAykJ5<~|NE SBD'<' X +BbE VT_X: R}+wQu;Bn _]iBTj5ɅցW/;jQ*/p52vڨZ| P3_l|(@,ԫN( RU.[{jTJuj֪k^(wBЬV PF$zW|\mfV(!nX-lS`L`t mOBBb apM\ A B TkHP¾< ok(ǹFDU-nmʨ|F u@l]kf'mb^.Zv jSkץ6تW:Nը ^ZU bb'@;LZE Ch)~yp/Тw< -)uYY:JTioc7W7 *֊Ro- j(:^߮BF]k6^R }NP\GgXZ?3۸oSf\S+K( .H[zӬmQ+ ^VQ"Yb#xBf F dU5Өje/D[6IB\+CۥrT7 O:m$YHl7+|YlTRYn76'U-:v}v\r\lNQ*{pBv{.Rb+[ZlEXrQQ\ Zr7'Y&}Id0vQ.Y@֪V΃$uN=_/ -ZlA2ۅ nrWhVEifGB*4bܐD3+#&ά& l @dQLAsdΣAYoTR#l@į^gPkoV4I6z^(u ^Y;zVVA+,ׄo@"%Hۗ*:Z21]8Z\qPge PBUXƶF R.īzP2+\Zѐ!Qtxxh^(ڒ Gj6(Dc7ow>K8x%(] \W6uIMph;cFBTkyT Q* mCƍ~sFDkzh]!l ʒ^1[!8q) Y~Pkݒ)o+.yeT( rл^A\pE>~plCEҀo5lɾklgWK$mŕX /IQa\0Q`)6s`dT ".# 1]s(4(ZwmMȪC}c+߼1"Jc))GV3p-bJ6xZ3, Ҵ,,K2FЪr\*[hWۭVq^4JJ'_*FXiQwy,OF8rq,ƾSi;h&g_ X^R^̎,(Qg1HH3YP"mzнjQtDZ jTvX._{V2BS,7K-@F'lNA*ѷZEJu4?]+T;ܡV |iY4Z4E$9}B1JrkcE(=R9-?52S4 lE4R3y9aDGxv%i\jTUkK5C-;m1MFX-!qՐc7 χ|#BEdTZdim>KjѸE#[pg!BimQ@ᚊ21BT \~z8"T(&B\VoaiG&P?/ K#|P+B8'ʨgz 6:i,=ސeغ1*4D q$dEs+Xp(nDB2XcjXÖ6Ϩ’[zyV09۾xq@hVKF0}AQk4U7ی/dp-d\0ۡ(^S+ b"b=9k Ж5a?Cn@H+{^j@#~6Bqn&<֫]?o9^Rkl׶۵b]J (_oTJjBG8kU_5<:BR)iYߢ3)`^lG$4WTS o)GA%FMOW@Y PBX-`P7V ,`@iU(Ե շDٻn$O35%O}w QN6[rғ̊Dj)ʉ}A>%w@jtH㑄@Wz>k 4Q "N-o]NXTL!2=`?_{}?Bh57j0Lh3XYRm+ G,_su~u'pE؈{w)h|07ʏz%ݗ-̡]P:;,ZM.,Y*Qx(?sמo϶ײDYgYh7^嚬1/hGu RJ7l~VX ڨDQ/G )()@$fPkLT(Ȳ PZՋpQ[W/Lf+4@sdٲTy ?`~V.Yv d < LZ]6]LFX3H. ^d@߈Hn7-_sk{sbͨgx2*qIELGf'.s|פ3>YW/[8:>`kY|W<*-ᤫ6:'pbS4$0ƉT\dG^#*E߇7sK8&YIqu{U2hC9SgWTS- -ڟ V]V*mʭ+3H6+q b!w8:8ߌ[p$@38^8 vJ9XlD:QdX ByTfEnd8ő'6snG6Cw"cw@O~4CSt4?Ǡ"ݞ\oq0(8G%Aɏ KdJ䟙J҃=0JPrF츄$`RAIdA}=(ͺWlGJ.;pA?#ۃ.GAF+S&p^( ?F}E]PpqtH>HKDrv۫z6xUc. YZ # ɛȼ4NyNY(#bW$X \sB&'m*KI:9&ji|2NE[&c6 F +h,(:o젇1#R$-U09ce1^N$O06r3OFxpxM!)NJCV(ǹLi1&ʙeyql^zPMH$ ̈*Z3~S*MG, NJLB3%C}dV J "C6䓧1k`82kǍ>U>ɿ5 Sĭc,u>ᾦ xoGY[UW@51w;^|!T֠ſ>Tli7@y&eC 6~v\.ʬcՒmp'^3*qJ^spf=JHDMМg=n*-  Jh^[ 3_ ?3"|||@f׍lVAYPIO ɫ$=TғYR2d~d+^l&kA$7#XL^yѽ╋~lLϫNY"0!u=E}# 4C44WӬTps'r2*6n_xB}z8:zdH;LJ߼([+Y}V?GJE JdRSATAL}S/`\>@v|&K1J>|wɛiRK)&~Q9-..Ɠ qq /.񛎋ˋaq?,ưP7|Of /5/g!`:ms1 e C_+N&h>,'#DL+m97OeFB&s~ۨ`R G)?O`7w1DEpL^zb yBFLw˸Jbkdã[?`vXnIc贝bgHߥbxt~+ywRP ^{)?Ĝ6w %dEtPnPjrk{ۘ A1najh6`v&h=dasw=Lg[턄A*о4inos vi8:<<*exx߻(Ga ab`cj*R/VpNV/E{ŭ=dR)yf%j daV<K T%÷  =m L'0]VQY]:;$N Xʣ'ú;Chs ܩݥ!4SbNLpv _1c9|s0&yXܿЮ1t[.ӘÎ Ug tɃʘBlN\7ys/q_Cy_?Nk/| L݃2p\7!28UJqkfTi5|Ӄ`#܆t>_6|>!5ڐWUe]H{8PQWl?A"_KKۯw^ӯ|yoJ~: }2|G=ŻNۡg|}v;B(HΎi"̈́0[b򹕯lG~8򜞵?CqM6[\ 5Rujj }p͞Z_1TՔ)PCYcj{n*^ĹfG3dPPӻ 1)N-?']cx7\ (v<'^W|alqK{9)?-  vd Ͱ1u-p.DX+^zY & ]CmRr MI W})648.ǀ0ѥcD + +̹= ys,]ŭ)'^eĠvɞ^p4g LA{+dv_?nK"(ڍag/-_Ip'`&ӿ5+\+u|7fl]2HMH9nM-VOa? 7>pPG/蔰3EbM*/& <]awROϬ~׋g+h k xm"L'/0tբ墁H+ E}`ʪ 3tLDRT0Q O"5)-2:}i]N ?P:oj=02q^0&wܢ~b`۟atq,8JP36@u8p|^G;Uq{nɎ֎{`TIagßD3vGϭjv_ēv A'tcW+g<FNJ̧n: l:؂sjy_8  ez ~1_"g )uaӉpgI8/# IAIy>2CCELW6?lR|)Bq$ٰa!^=;,Kܲyqav=ZAM"lUޡPq֦VӦ$THWy+d\_Cj=#54>#]&ʃm*RFjQNjXl*(+}c<8l~TTH4Vï?~*wc \!wqp1Y׀G\2!#|n +T  ,h{ Oz]~8*l-:SUg10O'm|A0!̍%dPCD wd8uqXe<[[D7Ŷ] ?\3s"lo;L']43w)t*kUZ WMVެ_ն^|6e+.^0'!?Uv/Nx?nw{?>3g:L+NWʛBdV;A5& [b_^bՍNy-4_puae7Zp1^;y>zϸ L+EH``߸5ٮȲYի_qZ< 4w c3^weØNśӹ6{rηL8Nq}F -E,B j5 WaE :VP MGiQDḣ@ۡ;!lKHT vCAxCI9"!޸k~gwŐHCkC0Mo ` aXF@BJzhI:o&88fQg0SL{ THWbXֻFGCZYHBUI;8<; :k6 % vH?nr'JRVICj 1^[I [2*ó leu4@H WWU})/\OLrS'*?d?OvbNP[ !yLo죮o [V ;*~VAڑS.j5 tWܻ]ֳɅISPG߱ҟT-3c9$# =w<>ܔ[̓rYz-`JҽEn)lßPZllvxsq,;<:DLG{  b&7F[]aVr߱.2.$|iZ` Z=zܝ2υұ#44#Mj$a(,qswGl73.2wNe޵Bxք &A6 p+xh62YLغ_fh%7,heXhA1-TsYߓ½@+`@׼7W]}gpWTS.Ix'0^) qgNXNa &YVbh>рf*< ׈+ 6-V,F 7 ]%Z7G劕YJbfdg'{H _uA]/1&/l[J"{<_.JDCB*BRߴWk>uZ'LxFC'Qf~g?/Wv27[쿈K wF\xBA8TCZ_=\(>Ku) b M.`U{sӴdG>G8 tkXp]!sN 2vLnq>Ce,67C@w5~|d}61g1N-N8.ȘJ 3Ǘh*-R"̖s+@hlR59"tZ]\hJگ,c`"F-x ۋeuz_J$iiScPŋͭ>|ث$}@Dӌ\~VoqRƀchxDªpIC蔞 NT(<[J.nPQ%e;e"=?-a2 E@Ƿ-*+$FXg>0sED3N ~Y<%r,a}{yI^( Qޜٷ䉒{feߧOIՂIq/5>hu=Tu$dgTp%EU!x9<98J%KPhKJThQAL[ *鄲̤"A{'OÙ R*MBU*$6Q/:$j,Qi(-9XjD7#n4'""(LwtpB|]/k)i7 `=YT]dWcO*1cO'XՃ Hq%b:+-pcBprq,GV<\ '>4҉'9J - ('N#IXE[cNACc`+.1Lo:bƱCc~',ֿ!!⠤igoP{ -N0M(5:>͒;$6yS C4[IPK%fW"U4w. JNHm `0̑/*Lx`>~Uu1+$ 0ʼ b^`2Jܱ}Ҁ=L0QKgj3CV~D $WZNf(F=$/:&a)B8p!_LXMS#/,"eEEɅj y 5Qςi6n7p|J["G`SL]Շ\QVa4p%F5Ӈ:M퍊TF:W=,qx,'q324 ¼X.3e*м/>F=]0Gg.R~i=Qk:ܾ??6='/oo3o^i#)gHQ^' 0*z.Ex7Sfc\5WÇfֶ6=tA!jA…s|S, ߧo^67ͷkonϕt_ob9r5Y<30~&W|Jo{q=hZgG{;+h5\tg:Q@i(XKr sYʨa).d@wIqD)K@I=tqUGUjCypZ0aT9$O ϛŊi}[);oKk1uCyپhNNglc$^}i\eP~TdX[rކ]ԭB{J`5Ǩ֠:["Qd<"z#6e=7QH;0TxP8n<MJnŸz(OV/ ւAіa0owvZu?)-rТ"SAth9#D#r<^]|YYd 3_eL9?g{kq,_%nJᾈҶ|Ώc(@YGuj3emm?g\8-EfI9g>uZُ~??66:O0oy> ۏĂ_Xߩ.N5nΧEvm[aRiauO?+倒,(o>$ os 寠Cl~iv3@Z r|vCjXm_8 ܬHddžH%~e'NwFO?c<Ƕ1|8?gq_g gcf6 T οOYq~WfkG";?!T`_{1?st4[?g=V~ͅY>'BuD#}y ,^_^g,,_y/3r!A8 3*\y^n1`1azGVL%at9V$k@R0`(܌S%OD5 0/أ|@vOr ;Lx25bNXy5< *M4У8{]?Ia7r3҂#[8B6Qacf,o;JB @ce8i:!wȞd_B q"vHEo0EHX#/mrhi^N\rʨtGfNj ,Rh o ^SzîD^o_G^V ;k[t PLC$&^bf֬jx}h|O;w k[!Lv#Jf^Qr3/OOj3?1wf_[hf^o.=tHry["߻%*hہQ#Q6Yr~5ŊRUE)f+B@} t|g6DwT] [rNMKg gysksc?g/\ߟ>SduP:kmsO|ۯ?6O|y"~ca .M"|BW9>/_ vI>ZELP/o=h_ؼfn닻"mG Y 9̾X "Kq'ßFN~Ϭ?oyfu"BDAXōͦݫ'"d>T=OʧB ^US21w=(0gһKFA7Aǽ`,̌$x04_ 3t'P8L M;'>+JES0?8*NR!q^T^u񟴚9᪵aݬסw5LuÝG҉GAT%׽θ(z++uDyHW FTU ]*+'qհ카^yjc>R|I$WkEKI פlA}IM%Gdeq~q/ 5u'Z@ºA NiPbwC' EoBx6ny/2H1i) *VTc:MZ].K %M@Q3Khعk?'UϻjϠ{=0!x#A_dzlcT]6u(WcBa֐J jN rKEp\DŽ'AY_YOطUK8w<ԏ1qpU妫( @ k ~b *mV ?t؇o35MFyg&ssdPYՉFKcq#|a8J ?X^?ǧlhwkY> ׷ Yc}sUsms?g?0{mZ~b_C_1_77_k[ ~q/'G?U0,ުr}[g8۝遙>r Eewt{"KxL7^uTLUx^劰+uOɘaTL0J7;)]q[׫5_ }Ű^>σj}˦${ǧޕ7>\v/q)e'NǻhGQeO #j ۰cY*=O@h^÷/pTuh\[4~q Âex P Eu_C0n<ӔsLS*S6}+EfVw\9pf#PtmNǙhdU>$"䫔 #*x&>%Dv#,NIGIR^wu>k Z^]:>{gQ ʋD~do̿o^LD.ʛBÁiSxvmcqpH@Sd%~,,/bɇb2|5 .;Ҟ[u7atV"G\G v'*P"Q\ 41\,xæh zL&i/J7HrV`ߐ`kWaTg@c%^>+tK08Uvp1_;7!E<X/ci@ռp44DL.)XWhz56vzyYIs46k$kil ax!JhHM=U(EVt=O1O*=yUsCx&󎹐 +&L daߝ ߃`[!3F!;9;φHN\Aɰ^jüpՓQkW4F@rM\@ RL&`]V)7ca+id+S, i#,dVFHGg0X7 eZyVez4I &Y~? n{ EW/|FMZnJ} d S* SD9$_xiLWȇR?^a0FVu^F0V '(TzĆbx328-c"aAx*;> zALMB"!>S=lǞW K~ o25-Im<"iN ~? VwMo?~^Dŀ˴&uNu`l`R[CPddśO}tPe9ΡWj7L UUİ1' /A, X/njWHɸ3xd; ܰNS ܳa[4IRir, 7bd|D K;55Ѹ MG3Z }1 yߝpXVYRLop{kkcc 1cP7"5@~AcmP@L?=L!j'U*hxYkR Q8;()r ZR]e QoK*d:\ /ǎ !1(-+ķ a-VcNFCŦҏ;&es~ɑU3IHoHx8#[\`t0c2U ⹖9فNE tIвQ-eIa8x|zBsKbD5yUZMUr9KvȁF-l[M<CGa89EH,w $*\B !ъr/4WV;+bcVܢV#[0E:)kF;Su]K'} .W~³Aj;A IGaeGT$V QW@(.0P<7 $hIBxq0*^sIFl Du%(#NU.DF=,7{6NXVe'r"EGf$GpP<*=\Xi`+"^V;>OOG탣 {!v$PQQlbZkjd2=ͥtá25jJBHt%p 5s?1c$-Xm:]gSr8P@qʇGI}'dFHA"BTȦΚ qjw)Ϗ४J -˚5J\I{tSVKÒnY9£93tW8RX4F0In* ;ASz?wڻ3捥d&v+[;xS?\a4[Eut?.|"@mO=t>׎zã%h pL qs L >@ǤGx9. *wpZN'cGO$z:ᬊcRu{ GLѭX{")lzp> iPNݬf!n CF&^nYMU.9ɗ0YH&U@D`tvVQ%ڨ\w}=K*X%ZXoф@D|UPxP~5TPԔ EdK:@۩) O; Й-A>ݰSkԽN,nZ 2s `g(5G'0$t#S;wZ7p`Mm3%Ftl;<߀r]G5ڔީ=j{Ks#2wLL,lFj={*3 s5>Gy5y6!۵00۝Nt2")guȗ fK% Kit:؃0=ynvneő3mGϟkU;rsF.t\Vk/=P`uq6`;Û2(ό?~oml9>%{vӻ`n]F tfqQrJM |tʾV](rzz1%򖃵FߗA@N#9#^VVdJ?6%d,)ۄEQ0 E? }a]LRm_^͑60d 2w ln k<a#-QȭR ?#??v~CJ 2c2S[My>UtVvqsS\PC?GӶs*C㹊1u!9.]Ydr_5!!sZAnPUVsFP t/]˕t4)Tĸ~;sq4ZkK ho_+Qcߖp@Ž}?obE- )7 L̘Ud6cʱh5 `ի1 kSqGA wrW#^%av1y_-mUx(_UI}4)fR v$$8a~&% n2vhÕUmh+YaN{C¾bٱMc0 8&jH<$aRs|&B 0nN&0Zz^*3喅oL_l?2 W66^-?˧Dz[?12&Ý-vʹ}[ Z 3Џ򀸄6։nS (ÎZ{`|-.m0F!-$WKVgMQ(1(*=n;Oasٿž| 2B6w4fO1H 4 h}ϻ@5s<'@,D'.(x;R>+n,PoE`7Ij6* A%LCPfw:1V(*Md<'af\%rngGvfx{xTNJ%#8بx*P/ JSdt|Tcܱ(Éfa[r:mq?%5aOH+!*5QM O0~ T(cYuyĖZ=d1= `8F'WFTؔUI<&ޔ~GꪸLО⚘_rL@DA1H_߷vyiMlW8-S9} k)UrdBxDKʹt *0'(! ̛f1.a.Kg|#F,% jv }N,3Tl;v~vM=x`a铬 !kD#-(݀tg~܆}U C!jdpXq,e[C1:R>ap(=7.>Ҥ09u5-R wT'*6#pBfY6{48AcLeߋilm?lm,?aa>Z>BɶcCmɭ- 3eRloίɕ]FT# ϯɀN50 5˿My4fV8J E0ْ<[:78,7?Y,pܔ3@rm oͷ{Uv|4?ےkAop[ Ha۾I8T;I;jY E-:5~ .4 %fP{Ѳv?3Twvwc}}Bg4VxN9B?P.`gBdx^@iRt++R@ v`F:އxB^ cح-AeRH@-{arQ'ky[Қe/1+VpٟA" k, y5D=V%4+$a\-8)+s]: oQ6H ",a޴ہ?iN [I_R3 _NڔE5a*ꯅF.A ͭ„g_Syi%|5=+$,#仙J̅<.zH]}KBfQ ]b@JNKZk4i{IҡgI_{0Ergƻ7L/ 4]_N{@ab~2"D`tb5t4/00efkTϾ3Nm ,yj3jcq,Ϫ{-l⟬{so~uP [灾?򵷖;&'b?Ӳw>xVv]C?+6k^?gFcks{c+oZ=g_kO"/E ͈DXoN?|hey?}R& XbD1FIa!x z, 4F7뎽GFn,J<^U9 1eɑ!D̙ԗj|[>h,G$v)&SzLFTQz KN8U™ ' d.SdQtGAغ,K b3I"V[t„4Đ0 3w|'c" unlIR&C׼X+5QХjꍾI\CM9D鑜dc#5%lR{*etН1>)3} ghC 5R|%TjW)`V JFuz8xF!.^(7I8HHAS9`+ƎL0>].Px` L﨑CdpG䫆6r@|x:f9&GS؎'R< f,-Q J(Cpf~w'^:$]v:^ԗwHr.`V]!@wpL;\Ym??sOT,дSn^oc\/^xk. >Y% Fh3UG; 5hz&)$ԡ90< mq:4̻!?`3#ELRٯq%6qR)OczQWjL q|?PSqi+_44 \AYfrBj Wur} f-_ٍdawZ w "'aW}[ >sQzZ[4ي͹ 0l44߻AYޚ6vYRˆ!A"Q[Kj?AM \Vm](Ƴ%;fꖃRiHƬa XGvhGWĐ͠nr1-E20 JT~Z;S(g*f5+0MH3 qz uSh J {nò-"Gq}Ɏג26Ѐ[ƨ-Ie?G,:y<Bp^8pOsk- zDž.o,rc_|ٳ-g]W@Fqi'K"'ALN B>p͔1˝xa_*Te Qr1 BY793٥(#Env0fs)S-1HǶ&T[+ jқ.-++j^@@PAv{TkxQ^H2t\>k43xqT>.W9Yg~X'B yg_ K# #xr^mKkOڬ_ml)s43> Lr0ե0;q \p" O&T*hxѨ|잂a4w8qXt{5v`aӁk($F9bm&H:DS$4_OO*y,y+.&O ^_W!e`UNO' M-OJbǧ*qRlś%sV^)=MC' UzUZFVto_tzfM rܜ57Q˜AEjmfΧlɰweh/o2!keL`cV.d~'Q7 iE2 Y6t~a6-adD9/U+7$ 'kbsKF9j l>؜a\ŹɖNK8]%K51X%K`!,$෹b lO[nƫ϶7M^(N\>p]Ź/YY؞{"b7m>a5nΘ.Kźl)Љ=R0֭&䖧\:V`,!Ahu6Sl?xYXrd2Pbԃ5..[E=ۥ\5WYe\TҜ&qIRD.`YXN[;Jr 3V)MT.K %+Xs f[kC-I/pvQp߬`"m*k ',b*3ƛc2P* &ap%tl.{?  !Ո/8P}1&"ξw%gJ>w (($+ BŏɏRx8tZGeHE6LnCR 6T`x8x(UȶB."HaI0Іe%Nc_HZFƸL0IE$;jn>g$`D0؆@&* %ڤdK;TOS4&-jY6ӏIR$(`u@2Ar8`H76IzXOT' G?HǤ=? (*4yk Dwua,g+y+ܭX-rsăI kf*~#hs $ԴiyψJ,=W"wBU1?L[gJz_{5jᇲc UHsXI C[u5m>zx\垢'<ݝ+ +hpj5JP)'Be~ATjkRlcs= l^Z^\0sTĪul!qju/**|4σeEѥXw 劓nhT5X*v]S}czCg\G]XUh~o'c>Q;'v;0oN(RCvye7W=wl*wkvYJJS( "SIi IRܞRg}Yg}sJug/3p+s+,v]pl2ŝ"ۯ67#3 63gp~(9%fDYz׉hbPΝJFoV$29{,&Ca \ǰL3eY6U/@${3MT҃Ǔ0 ([Jx)t#ٹT O⃣pp*/m/,俅>gO+@[x7\pV^Qѹ[  Pn˺ܲ'|y]~?O[G`߹QQF0Z$-k 3rB椹"&|I̷ Tn1,yi10__x|Th& x6^#_C:OLqqG#wW(P#]4D X2u)1x^A mxB9D,{AR ΐp=767Zs!=gbv~{ +âT!-zP|H}Dfզ?@iV0 V_M55i}FXyarKp#y 8i4UJYvuL)<`apA};1U%htC*Oጫ uQȹ#>G TQsrB$1Mv^c'4>b8I{aL)uBW-?;t~^AEQ>D@.azA&sxlnlhVCYV?}_&\p۷d¤L$NtJjqb4!H샍 ´WBaP1_rźL*CTc;:_wQov(̵y`}к'Eni 7SZ_ I&0Z1]ILx{3SuRB6uF'oTݻzGHwra,CfGIA[`7HFA7Z4v7V6D݊RZTWo){q8!y{ އ˰]яP. Hth9)G;߃ܔk&i8SxÃ]'s 7|BzPMF:.KWSMn0P{]\Aac"銗1t$땔%Ѧ /#^ӣv}zw:k[+\P4QW=E܄JQs )aVKV`}Gp}Z4Ҳ82y9v$Tͷhys,_KV_!7 &#p`&ۀ?_Ϊ*X5gD3v|3nd+^qċ檉g,"fyي`TƤAt؛1Pb`q׃È(< -ys}G'`~hT0Т %pqzAfA|!WR5W>@QiPѝc~P ^:'{gj oS58>oaNg'P㙯%=J;:=΍(gMb,4C8"ퟜW9h|!pZ {5yP;n^tPM4N>ۗTÒEY5Ywkoc,KB[H~Xɏ'}l&"/3M9|g۩#m#d YLW[ocl4zW^ƌ ;\wE5UOe'T@e^wIu|G*w p}~A\|LP!)֖J0 QKlx'cHD[!}#,/]:P<vt}m MG(q{ Oط0e5#hʐ10i׊3:;C}ɷaӪLjv\U#F5n$8* {"5+ V"1n=)' Vԟ H9$ٝ7P"rе[7(6J`k;إzb^KV Uqi50^n }y~|10s|oL4b[hBr|D3l8#3/^ƦMH)x#2?&a@4%Wo"PU1†@K._E+S]1s |^묈|fBs2 S* S'6ɢM۔CDQWFM؊96 DI *Rnc)'LjJReIjw#Pi8W:?! b%R3SQ%O^X;:].{ՠV_Uר}Ϩ3)w*'mEU DrN#s Nt^t.99!E\qIJ5h' ѥW{%>@T1D` B8j 7G9Y\g{G;ܣMMHJPv$v׈?1/Ӊ&N0$M#p9Ђ~v^P8bתl>"Šp2T!YLBQχc$ 5ɜUkq9wGȟ`5D8D,{\Zf:O?jND8iTE+@AW7Jq]”Ցp2Ti)3Mh0 J`yOVxT| \D2Scu/^s˄x'A} Zͅ=P=zI7jHӗ M0Jw If^)<=nlēVwuَ#uUL4wPqIL䃒en5{JokcʘBEWM/=-|{PuB`i M<; J}.GRW>%{0?ayL(7{* EwZr&W#U޾|yssbz~Y7y"=IKSMXC<%(}f,#c0c?$|14-$x}phc[]h:V?ǻN<b\APiFH&Hugd}Bn#l{`ENϽ^ afiTqkYmjz~b8;2Ɏ]qcD[pϮGw(Znyj:QU8K0"&J DhWr5i(pb`<ÈA[2> v5emظ YV¦P7-NeIĤz^ #5ڝh+e/N*bpxr]g[q&^|Ȋʝ yY̌bnhyCyweM=?Zt0p흪Щ90ϊIQ>8莊Ƞ(dž# &!{TUưX<3# n:@;PdyRjft|x-$ey[--tAA}Ӏ'ɒ@$2l M\$($Iv1"Fθxt"+3*bSW> (0['0C<„/n$#9ievF3!h)Wt`B$My%4&U_ɟaxMS䘇y`_bЊ݆ v< ʲLB:XIG]ax6f|C tj*ӑYA*ܤF6Ge0c?J)aPMv'c'*IPcuZcħ_e+!֖_,gv *=T\7ptuJq)Uӕ1HC ga$%}U%R:n':Q]& UO!eCvT+'PWI@NF)~>T*S?9搵j-nTy )7TJlyãz@i) *3*. }U?. ͑:/PGXRK^ac{k8EIa֧1t'&2dbO(mL$x|&!`vG7' >!ֲ!B7z} 2EI?(Z)EVj(i)ֺN+/6Dq8& q7ψW ”(ca5R WmRGڊp%&x¥z nI7aԋoS`(|[gU՝@JR^f$5@USq-ew^r(;6o)>̷\F }/;G۬UG'?NuX/: ,/3>Cmfo?a9>a[{,ʦ50<&o(fq؋{10Y^uAy RJ/TU|֥KUuFvyz)U4+xA'5NNǁ25li\ڽө:*|t(hCeuUI0tـ 5M?aGـO6smk?gy!,.h6"ĀlSE+~uNZbQQ%9 烄=\5FPNix(>gIS/…hM=UA uJ>/&(hzf vT〕w@H)]- dmC/1i@c[R`AE{NHgԌ) .`ռ!WA8Ң(A\}0NڭqkOk9NaB)Na>hMۇ]։⧤5dpK{`S7i011szyN dNRrXRHAKdkirf%2g !}foV@<9=ϛ1 Mīف 8k|k1`l}j3aL1ImVOkO[;]Z"t[⇒s>B10BK R=YFA`9m^C Sꫦã!/P*`@v@(~8/HU<C=$eNSVoŊ&h8d룤;x@BeAa& $nx6dKx'oH4b|2Q*Ikԣ,G+ܾ̫d&+r@Kkpw4x<詬ɜqU'Z$8*b2C@ꗾuNjED N{+Dv; \jtVkXXՓ kxqG$.,XIIwbU^/3B/|9-msfG_\ |}!-?OBh "6z,u )9 uىuZ脞O=&[r&=2%2zM}bsg :A;{M=Ž ̠F=OSC(wz~ JT5׵V.cKY>Go9?kӧW|/fc Gq'wv[XVݝlE4 EJ“0G%O;"[ uC&FSIQ".4ObU&ւ#Y0ZA`c9m;-L D`]Cv"V\Mh89Nݸu#K {?ciCNS̜P0}kp0j6JR"Ar؏˘srOFbХg^g4ux@w'4Jq+cW$l1U dBPlЉIT0ݤ\2H[;m+L9/ "*"Bh;`,=JM_+_WX[iDA&;,@DdyexX*Ъ :}/;WmH6=4¤c&He=9:?J\XTLr*mPwƩmj.@?WY޷X°ds<#)H ͌*-| .B>NeFӞlWF͹;NV5W 3j\es7#]{U[ }1tC"3Z\[c}5] xfʬ3p3Joov҆Zi->Qqn{thj7`eJpr;{jAlB)Ɏ| -!IN[<3!)X< mF6]wzwt~kD5X#jԟ2Ob7 S&W4QU] `vC_6Wx<F:I<w ,/rVȩܠՋCA-SJj $a4z!H!HcJu|ԔLJpŤ)[K}fc QW'2Ypsϓ-dQ[+)SNPPY9*Eőw魸<0)׆gfKdNjd" `qlRxv1BcuKRA,Vä9Q wC-)cN'ZU`ժ Q6̸I١Uגd$*`ҋ嵤-lTaW$PQ "toir4Xz*+͘І쒁syp E}Ԝ҂fbE~W,tlQe{᠝BHY&YP՞]\uo:G%IydӃ)L!s%YIG9 9y961XDBDнC0V S[˺ȯNstHoc6}H_d-ƍ@) rp/ӾG4ޒ%RذԢ L[%ٌ% o@3Һ8h*JcetG'-L;v40~+‰ab/LEWC؏i%O~?d5Sj*61JH;vgQ Ҧ~kVYe} s]UIZx/:HIҶ -U@`F{y1# O=zU >t4|r0cO[ XT  h: '2jS3 bk/shyYؾ:T lkJln5f4_??7o^-..ؗ@Ehޮߵ[K zTtv`P9ѿJK*Nj>~i.ʇ8hƙkAhʳSrTb$k+$蹣A'UUvx41ƸX͊RcA6PBIr>C`DnP"-)et-F]UN 9;vHJRT !? {Hsc.ld2Ri̞#T𖆁TX7_9jJC*xxt~iPF>!DspXo2VgS>Z%@=N}踷nQU+DK7TaZ ؕ8SDV1]7XO_\a,"@2^˨KhCd ~`5Plj8x_%l"=(`-! FP =%&g827|-Ϧ1/"P Cm)eCOY4 g2DFu[-+5$sSGsrkPfqՕÆѰFM肙+\|'N|OwB*0o}СkM.0z~bF4.*:pm,5Pa+ &w1AkzY-,g2\v| c+ejġ^h8`Ƒ̴myei n_XőZ5Rň$k,)e\[]ſǵIgʋ$⫈;3_YG}fFW͒励3qW<>晃?UW]$G_̊*\Xq̚m>)h65 1삔۩ji/dnI$lNS͆T52TcJOJ>CVUwz :&W+U9B"hư΀WV("UC 3XղȮTU9&U[͒^;:H06"dHD 2Ltb[EnU1zUM[T[Ĥ Z~]x6/ qB%eSXsd}MwWY]U!]0aH's@4c-6]\{Y٩5F] 2Y\SGׄJrrpLGnXO1Y#|ÜL=6<@g̢l vYi$ (o;UI%E`ׅWtIFXĬ5)ectՉE ^(Ff\-=(l8'WXb& Bfl'ۆDb#nznb{r~ɷMԥ*dm ?]ItTlvQIu8K8a:Ԃ6"O m}~p4u g&+sMx Y>%փ必~BBij0v;>1ȚmN]eJpTUG ӖIz:@ 5)mNV%gd!>T!Z7 y>S"BrCK9pzF9AIw ab(A,JrT5' 2D@^;"33;t2\I(Bb)J%C^_&DΣ}$q| >eʑNd^CL syE4ӆIdA 6. }zw"b~(I|!J,{X]ar]%x$y_dp<]#Ҁp)H0z٤T!q6 GVϨǂP1V,%'u[qQlV1c%y*/x/IU Xs /)ݫj PD"\Xjs ;MW Us~\1'; #cKv?::~̎|nD/u+/?Ťxn/S$F'B z_Մ i|p"{Iٿ':HnIs=ljRsqLNRRIC~Ksv'r乜7 ]Awir=< W>@-'/Z73.>?sWbﵵ9>e2ߢF P-@X5QNyo߶Jz$4?UXD`R((66?Sh86E ,P&St|eZ9˿^ljURϒOC!`a7aUL{ee+vkkL­ ]wæׅ4; DxG5~^L$‰Y Fu'tN;?5xV?^_m _(0=& OOARqm9hD,\cT$aG,w_Leb.]9Š}vO"Șyԅ~x9X͒U 'WyUŔ^Vot ^\ pHru1TYNv a/0@𚓉h'2=9{4'2I˜̡T@v4E2?rGmjz0'eLT>st|i Lm~V-Y^/֦66Z3@l  `o $ƗDdx 9=;>uk<\9s1Q+F29-\*-j EpX&=@>=V.Y n@,5a϶-H9boeBzCo ba VE9 :Y׍6uY 8n4,d$z u9J)zEt!LJZ k}:fX@$ҐVEKJ휵Ҡn/ 9Ibk(ajK#FPD La&Tx#fSV>3"HnStop8瑝`o[꼊Jzi{IZB@uΐNW_"Eg}[kIf"Z/Qxxxއ[‡ox]޽*v0&6{eՖQJ*~f A] ~5f/yi޲6{%8%ޙW(N#v3^JXM52=%пe % GWq:9$Ļ"\+)8͜`D\|~1"if?[ Ru?MgwXvB52=+AiG믽}yd|݄?F'Gq)s<~)Kr .pځ*J5[IUi*O:PC*Uw?x ތ2Ij((qб8ٓp(Ȭ΁v=14HiRu t 1D2|-Vd|<aE"!BRX wʔSSؠ æQr1J1*pz"Ƃv &ehJ:`:RLAN!Sy-lG`]ه](EҗV¬ҖL)‡90&^TM 񧡤͹?wڻ3&ԢKcJp9'QDx8 9$~yxXG;\f9foT B /hTnb]Y:qpwx;JjS:+dz]wR dCC ,v[bt.8kпI&b1M%. T5Av$b}?f3+$ *lHHơ]cLub-xqc ,}2y9᧡:ʐ/Z=* !H|4d!U,u T`/C%u ivXJMB(תj"i\/ⶈw9^|nW"ϳ|B , e%6-)NJo6*uġFJ1>jL'KV%)ey17qHH١15wD,Pė *Cr;4<-$ߧnўx\ҫyGR |#u< (l`-=H$MP^oG0$:r2ĥ̭\׊舓ϙI FY.$8$ID&^ulow)%ginl,~YcW 1,Dӳl0%=DQ;&;ߣKtCOp %juI%\aY,\k(hElYJꇃw/űbjԽ/Uz1T/Ǫw~+Z=ߛݽ+ *銽9 ۵C5bǐToW/$t kB! : Cpv&`zGI-ڻ&ZM.jQB7 Elvejd囆g\IBGُRlj>,:I7z'cWO[Tx3rWtT,{]DO+.ФQALed5+eAB# ('܈HL9iܛh or5 R0ȥȦ㙱)a*')5' \5['OF,rlxd P1Zkf 58L=)3vгh>+곹 `|,*p("1sչ,҅|+0F^(9l<+_@`}5鬟thkq(؎Z0<+QRʛœ3l·Ym>`xg Sɇ(wSO7xZQh~*AOdYB\E7Rfi[/i6(z88p2vf]Ʉ&M`/סVu%E|G@jA6e%~dI|agb}玍zRrl6?],tt]Q:T:gg=\ȑfX0ЬQ=@)^Nlq;5gO3^m˼ϫWA]BǏ;L~јvre^HvV19E4iA+OXpԪK)Yj/ m?FRuáZy [<%yDЖ50VHZhL($AUgNk{@^m vrRl=xQ|>99:w;'{wnKbCa80uΎ`P4oNݩlFQ;<3^_tdlDTbu^QMw}iuIWZfq=pg~MG?rh"#8ls絵J?FAc2Gd,oRm ]&¸ y>dgA䀰y?FTV` G^ݐ5l՗1 a'qxQS'QTM'G {aCxeh3u.  ˘\I?"z; =C* Bb+G'ʳi88 1Bh~1)t?Fu/dMс2C+ypBkq6Nj/D{GyǴdV-%C3e&dpjY@ݸ(&J2rVq(y3KT:‰V9c]~#2|ۭpuHUlw1ųV:̌1wWnz;Wˤ9-dH8PvZpu,PNziœ&t%־S%+?+ b?2)W3k*8ڒ( 7K NT'iò oBᒌՅ`3 䵂5ҏ8A_w08PVjLq`$>FlS݂.W?AlxI1=hJxtЅBrTV3L 77t @#pB8fLf%{?MnLB._1\!BM`q<}lGn"@¡[Wд 9AfdA)i 5uH*%$HPmxҎ:m"oe"bV(bOA]])ɉ/Zwj;ϫ[E x-†g4j)%3JDh+f2^f, YkT041Mv+/ oAPDF$=l%80py#_>M,>dN";>Ə"{}Cc6`|qsUAB6NyEH0՘d"4-v޽:%pM-7úm5إ8r.Q~ $̥Xi@y;V>_S-nb߬ s{ Am GP'kALj& lrƌ py'/rpm" 3?'{2U==)WyҜ5)kM2sfe'Av6Ψ:'B eS"eR0*lucԼBT1JL@fKVpE5g Q1RO3ph"$!#e]Nױ5Xd {OLz5Ӥ卑j >5;9yТd?[#q0dcO4.a%Tcr>7!|w]x R١:;ld5L?c k8$g-R2횅%Tkj|BH=Px>M?8 Yuf`XeU .+!%F($J\3ؒO (UK$E{Je9pH0HoK贚/~i`Q%ӌy1M츑9PPLP d5 1v sEZ{A@.yP0%x:PL_T)h-=9ஈuI,`:^Tut8BW7(HEc@~0TBU *] u8C$,G5vbVw4}Y"#-)dr}= vO5 R8ӚJѼ_uyGm~ uE1Z{*2wo= 8:H9iF/hf/>?4U,o⌒8B`ޝ0,*8uMb@҃;lea~C2Ɓqz˜B)%%I883 )#z$'b\uX$05ݣ{fxpOU^|O&bLr!tZ0bE=M]%5+ <F3dy`|\STi;Xce Z4ݬp5mr d&+KcY˼aǽREFA]К|>7 ݞnI 2kmsư6aES:&Y*8 F2r~l3(ZinA1NFwXK֚5b</E_5Ǡ`xk)M E"T7kk'(mD$ 5[/)PuHq\dAdbW66rKP65-3nCE,i4)otJ47!2hS6ۊM)"ɉ6t/{}+sD)6kۯ^n5?35dl.2.2Q3 ܟ׸^\~|o|mIO@N.<+H.}ϹgTd/مtDZhA9ejvp~zFe_kL`t_6{,6|I"KVp`kQ (ua)#"RۭzVue]gk_x"WVP w믽EqOmt8[a#_^ߛK_^\S&3C {Foc {6s|,`}$<(^@i7f_'|*'pdO$|OO{3~(q+go-u%{ƣNV.?KK9n#TAUh TX6kTrӠ詽 H=iSbX1ǿTPË}-lHߵ[?;=h2fc+F/)+D;7S/& ~% @"*oaD.T :h<^?v[*\|4- X[r嫲i:wmxo۝g܎@dހcA?Jҿ4lǷJz> !KNY%.0{T6#zBIHBF8AEw_8a^xK^TnC@lPF+2Bgޛ!>u;gKK9/Nm7Z߷;'SX`&o*~F O?g+OF1x>=gX۷QeBׅ _vO?bo QOּwXK @FpZ.߷0[Uתgcۘ%(ֶs|Hpڣtf- eW̔Tk^5_"U[yU`N.i $Q>5wlV{!Ls! !M4q|^CcqcN "w< /ȿAR$^GM` I9[&tY)@ǛNN[.ff= '}mQ OU6jȚ63kn(Uebh4" ^d3iCY)_Db4ѿp勻pb `wкSĭhLF|DZY@m/۫X_h{SąNb 蒯{]D&U$at1Ǥ&d͏dy8=~^m`عANZ-*U̝f$w*0YvS4b_aUhA9%Gځ3oIhzGάṕ$yQ9|SKN1~b̸1 1ax%6Ѱ(]f9bur٫0C{t!Į" a[<t$ +r3z,(9\ng9{<0:sQt/͈ߠ}ٙBBNv{TH(= ֲuBtxTA Ez#&Fx<!PR^P\ -3DzypҎ;EԴ xp8t4X*4**0T~.`R78 ˺a{| 8^pBV.V ڕڭrK Fo,)wbKy3+\+)bQ9U:k2̣ƻ=L"G((r @[MhVYg"6Y'7\&{.dzROfC;$Ui5IE~蹉Ѫ:^=R&!ϥ6՘ՒvN}0!(xi^= : $ecD -!Ofp\Ïrl H񽫐Nφp2YC, G>&tM<]68,Iw!% 6ՠ!jiUk}?)Ùb8Cs%э)[45+1}ֻ +˜,(d9%ԅcmu<,nu W~pKLpJ)^߯8e]UqA؃Z'YDSEmȻW"@;M/_f:9΅`<^)+%apc$3ÝZҿgx_~\IQ*j ½(5*\Smz֭7`ͦ^"bLP008^+a7\<8,0aPA3P肢|D+6@(=U{*-깋'ta23?XNɀ5 zH Tb|, /HU a^yx+tr; Po!]WV«-Bz(]&O"`<#PEhC-3 fFqjp2PHƿA b+I T]!^3϶ sBV$zQVE7 N+R[D9PM>ؒ.6Ȟ1GM"5\_p2Ha)Ŏt|P ЊyGd*:_)2 ,@htiӪzv2~[([Uȅo>vs1nUߤzmх!?*4OYi>b)}:=1Z HV/9@& nƁ#Mh6W*F \VEV(:k[@jXMLCʗ5m8]xhu QRCq_e)^Q ,h< ^}A"DH:jx I"Q1+[K,RGQqPMMlz"o5ө<BFX $"RnE(R%ǖΥ:}d?VCǗ"lɁ H+WtX@Eꍔ^yJ stzg κ Y\j:mľCtjGdyhۤ&3H3Dc&DN1.Eeşh TI)Gk%Gnt\ڬ۪Lw>uD3^Ӡ RmFclLL`7Y`Ԓq;Fʑ/GR.RSH"xͪΉ!3Kjx֣,YU24;[MHf|g >bU5{JT^q&ǫ*jC1pQWIӒ"F fHh ]T/ Eg PQ|G&1ۊJPXDGɥNŨ/5/QI$9Cs ٭]WV7\i*9 t^^arD6\a`52d(j?PV"6 j稸|\0`^/[a\п燥%;(Jj)T&rn'[YXs+2K$AQ^> +`=ՔShn~:aq>D7hLAߣPE#ms@e ;fO;$S\BFɃJ<>ƉHjX}SD"Lp"'wA0-dM'9tFښܹD6$ xV5JgXl1 "0t ȁ7$,V0_rck,gV-aTK3q`]o"f|;3X?`q:hCxBe-nX4Q~NhOh4 FLu Gr#UX~-rN59*66wyA,K=e) XtxkR!Ju'>kML@:;<>1MD3ǒeTVWiFVGU{%DUURɢw Mgʧ:6:IʏQTJ `M$]N׆Fd0=h)\J IP="[\{(:EfAeuK-Fs9GI.0ۄDqㄥ(sbu1F(Nso3j:3^7;er -Hn,Yy[j DmJH>K|XZ*0e.+94֥qT5A)Gb? n*VEاՃ"`x*A f[gȞ b`Z[R幹ʏ^XPfUla54.|Odn!}0k4M"@AڠL^Is"|jxi'nE:6" |x AD OӾ˔+ ܁[b`зњ'w-,=w5Ml^I0ūqx,;crʑCr]k/IEM˻7Ҽ]V{bH.QPUubUQ/9GgHlNmY>@7|xwp|v}dV@L7e\c,ؙiY4|y*H[A7^ba\e%sDSY_=|'Q9@F`♎]?]\D/쓒.ɋ]QhHhDxK\ 3 g47bdoZU@ļ4~ 8?0]8A)fİHaO~R#—<F*gnxLPy\q)͗)S>gV_IA6f^jm9>e)[HF9ƽ~:ˇ 5?&~~,DCKOI?%ž'6mh׷-a=Yd)`lctթ`U.ʼnMH=д&kl5?j–F@ݩ~@q G<;* z!=+@ (ʷLKb1 %cJe& b*8鰇{0խȹc{/hruqMڒACdx Q;I£Baun'PVzJ0\|aӥ,dJBʩ$R< 4MUykg8DjέJv^ZT-,ItoI_͋ˣ[UffAغ&aR -ol7<."Q{hm(e[Eňs̈́9vqY{$VPSztot J@4䦘@V%݄iN C Ƃ}+ϲ{tb9;XllEwEd?_I3M I}"aɋ, 2f f0!aƒu` i^9@g5eQP} <ݦ{ڊNolHAmg&1.*SeDjKr1Bf{F&LUCjY~\z%,O}Oh?o/ͣs~"quCt_RO6Z<:qxSDs|"sC.?^p|^+( @t<-K3#%@2Y&i55!#iH~M2ku c: ޷aUb<}FWE+3Snei@pD,:҅JB1J@ ͆I|"燭q` .v4:>T6]ovv)+ۮ{x'{G;gWN<]%+77GV*5׫j^Z'Yz4x:78:WܨK :k~cqll~Dc֩Qߤ9h&Q 7ĩiquj*3?=%l P@f[(E&1ADŏ7AT" EݨNrATLUehaƹ;`wH>Zv&36lP|Ñh8Jhj}xeqw9k@6H={~0ċW]]>:P{v<ncLn{۪JN2ERuw&Ϳ*pvڪ`5Z }v~rHZY~d,& 3c7;?p%WbWIܝ>?hi'ᔹni-XO05McM Li Ψb7L!.+t(r{JzeDpvӆѻSGJD8#Oc^sM_'1Ќ!}5 ׁP~oZ[$WPDeF#вMz|C0Ht ~`RԓvkWW -v@=(q=öj:F# Y-Z'm:e"ɻO Lb-JGqW;isx]uF6gTzo挊eu#$1 --9hHD}d#HTpDpo<2pϤiJvиqs\;#i-됢l ^{-^H>=;"MӻE0' ~lИmh7EpL{qw_x:^k_HΦW? V2}CRLt(٭OAby7m}` ."j ՂsqzR ^9Ju"q8,l|<ZV!8( m4$ґDta乗Nqf@DbyHSCl;8I3yH*YбC)@*G^5ߕu P.I|҈AIMEnʴ3?Y_^~`{ C R !Dwxp<:9XF0HM)0|'KեP.Tm8N \*'q~dL)^6N[By|O0ZAͮc\ZR~]voOn⇣M ;Y]Vs~fJptVj$g?U 6h=s:<;?0(ʧa~[UN ܭ+K5vVx5Uݭaa0fvVqY@܌m@MIBӆOGgk7 fTg4^!`(hܿCQ{e2J&Eogd pΏJo4LFnDL퀏ݪxav핦ySZ^i%~UR޸rCR/1ڶ*6eX핮o[Qkwuzo,cdj~g{ՕPOK\i_Lz=EC'AUgy.3 w#fmlm6_m,쿞3k[=l_p\Ŋ-af s:P{;h R"\ΰiDѯtpOD 3W#0iv3ᓁxu:q´'*9RSk7p9>%8)5I$.EA7W@UEu O^  Mʳ3?4MFN*9rVs!=ǧD{5w~bB[sGa a`19=nm,3JLp-d?= Mk C+Y(MosԓB8O, x .vjͣyBYa^=+)ľQ0ʊB *g$k f\u5tVȯ]󡳂~߮f*, 6[ꉻԓAqsg˒jsUSMYGu|OՋ6/gW"k7XI: xUoJQjwt,z ۤUG o8z=Ze]g ]#!ksL cYڵU-,+^(ٰY%),uqmBlびB4VEb^9R&Q%&>:^+bBG5qZQ2%遣XxWiQBGQkOE i?tW]؞S 4^@1M^u nos⿽Z>g\7 pqqǼ8~i.J&8Z%Z 4@ O-4?f[g8N>;ZrdǓNZbI.1*v"rk~Oq늪uF3nf RH' k)[WI&QgWScB>uzI%⤕`d_1)4^P(SN&FˠSᤱIβsJZ1ɮ$[_F'UΝ v=u^;@)|I8Sp1^`b jʘO ۖZtdq2$q+1$j~>J "K)^g1gЂ5cbcWCr~9kD6*>E2TUpJTeP}tE3RC"3~ǎ&:|:OڕH7z0_a P [ȼ  @ЏV1;ù2t*4V25\Tu3>٨fƔE~3$L|@uF1K;A/UdZ>~S]! (lH~䦩ߏ"Z&Yo;9'0/'F۞vnۙ+ф" L$Kz)J@ zhAh8p*B!e-Dsz]SHxKoA/R„bŽZws{ $Aݣy 69d{`B~ J=3OhE3s)ݣIHv%Os_o7HK?$hEd,ş7)"20AB )}dĨx T|N/._dpI]]o{D׋$K JB jyS˺heV`G%/yȃ8+G/\t1P>xXybUBHdys߅j|[* qNimvn¯l]IkX\BҌNڃ aQ$4*{UNXvL5B[=dF~4|e+ NHvl)$'+^Q]]]]]]G7SD8QW_+fq_GlMl`xP: QLƨ)sȲ|iK-ZםiC{Bk("KP0{p<&9͌U~i^t9/0AUMv菒 {"0xd_C0qŰAп {bAt4]םVAlizs#a1(jYVPjCI}\:NK/ R)[qފ+` 2^i1`(^IX`AK":QF,/F+T߈e.j!#Dǜ[E6/kG?.L&[ϛ}IӮ@f͌_b_(}sa1>T"$1凹 .>gf/VI4Sst}@䀐EIJE؝mg.L8s˶YMt.TB9Ŋ&q;Ƀ9I@N2V/E!-`*logW[(Wg^ifkɆx{fQ0&c:ŷE=aq4 T!}rfjDn%wUo(6X#~4b`<XE7AȾ?`\Eovp\iN2 D79 %#,^`WhsdD)?:9lEq9y,e1Dr)ΪDF@ ˨r^-@vG8R\;č|Vu /cRg|斕yU x6$H۝VVʥm5:;=aaj oR\w7#Mu 55 }PYSݡ3 `0Zt՗,znʥ3X׭zV0oM܊| +LQs]?u^gz$?0q>6)U]hȩ3s.Vo._1@_ Z@z7.΀odO#aN:a]j`jp(:Fqt~=&O><`u˅2cSey~T6LAҘpxu]Ꭶ1[[k>1OPq^v r{y.ۡ ˄ oh@3R+l5}Q`(vք7hg[붊$9]ԏrHj(Dg.߁ OܗŒa>{x]Iz U[ Bڢ@, /6 ݫpʧ@ \$=/?jYiˋe@㠞k bw nۣׯP).ZrI|utUr]ya,hr?wx`%5'M8b&t~24{ Z$%hDWVņw/`nuмë׵L8*X!΁;cѻfۑYK8b< !rkexqq,; W̤pЭxJ2~MM|0 wVB˽,68m2zvky%G0qN[{}Hp*Rg+H2b! jnp`eNՙ-“4n!D2̯GY,D:L ^G 0qJ3Rß@ `_R6}d ̳Pim6}ODŽ[z2y24QlLx~{vv-jaXwr)Iԋ:Gx:#YԟT쐞(r[n YM'$$5.D'{Xʗ:G'U:I֐}ax qq< }g_N<7WRQ`,FKK8@22-}ЛRvec$iPuMLt} eb@ ͏=OdöZcH =LXuMI'mTvQTl g{-QݖRH zMD=e1um\=2r3YǺpip#C&wU|e2 ] X4(YsQ r߮z;6Yp̑F { ߯)Ihߣ>Nv>ʑ`|eSK䙺3udEw Ф*8\u| ƨ79f f?^. ?̽!pnPabxgǸ^c qpJ`0HIB#6K.{G=\O$xًa];@r gKKGܳTg\nvH>{;L^h3]VX`FwRBzQF{wl|8W0uп;TœJg9E—)G'PJ_,.?[h+uDf4M`r%*H s.7i "F /m}@{xWE҂lkt+aY V &rCUm#&{`b 3+oʯ/S2hpK50Kc꽅VⰪp_x'B&q03Q30yB~j_ҟ"'̂ D*H&+rѥy*^,'$Wv|-V? l( A܂R]-i8=[_3˞38'ߧ6h~6>m{]NGK9c$d6ZkYtJwO掷s}^ /Ugۥg۪:~ p5cՃJO(C&jck=zqgÚ8,tSa\G$[󎎨V:yCz:M<ȯ'իpT-/[ &oIm;ƟC*^v{"'KXd{{?#ԷѨޫt)ZnA$ںc-wE2g窷^nt~d.*`$mr ܒS/YMzFX#fei)֕5t]B8 eFH0[hpi7ZhI?ZuFz롴[K f1>6pFمF5(`yzG^{ݝTʜD 9+x*!]$;2J[h!J~i;F۩;wUAxT3~2Ť;emi —#I bIM]Ir eriULUbXZ5:|8*dq B ޳U![ ϱn@sǶ[}Uj\EWGg B-J1kΘa`| n UoI'jHoj#2C#4BT8kFFV$$RdTm8F߀ɢX&evg~^>>8΅q^7St7 &xVh:d 0M>Dk3m _7 XCU.['w'6afB!."ǽi [P8+O( rb&X{F7e櫸d7kmyx5YNC2 ˈ|R &"&5{ͮMc}$ewu,o]Gi*qd]gS_D8ɪn -Lي5lc |Q4i]GӓJk҇Ίu;nUv8.VVϫ*[;IHbɨ|BJS*/~h+b4ݑA^Uog,kVîCO4jYf+ 2L9f!kM?Lr @R{ft jUbbuuǰѐ~jrٴ?P+:ٿWL`J\ފtkii9~U/)r~'U~,.|jXr4%9i^OUDQ@x|$o0Y7= [+ꢴ#Ν(_{+D#Qqד4Ix=JnOPXFHDCd5LH;LtQCƝ'fK̈́CŔ9EN։zqכ'Ε&U sg{O_'Ie!pl`kwةSz+# Zog 5ܓWld0 0MG&x5{q*lrhXds MG>$4k/ӀMΛH7#m} GuϦ07YiE÷´q{ʊ6`s-a.( er;\2?5{K7V (TvܓbH3frvL͏mތu(*(;mE][ފ nvT(rM`is:Eƒ]v^O[*u#d%-h2'1n>Iv=K@>) 39~!٧Q2<^q)A!J츍 ya[&{G",1_7b]n~ ɔΩ|ǣ=oNMA*?%嗓$.DU0>EVŒI7! IU@a1]}"M͸&bެ Юm ?*|~l"Rf6$N2ZѷRt{I~iHv <%eds6ް>D q8<& |h;<_R;ɛrtt#@Z@Ml9fK Ɋ GqS4 %5@/=f .G=02G{AcӤ:4Imk,s<އXf0lܻ S8z\iCE5jEHSֽI0Þ6(Ixhfc)fQɰ>Kq%+k:1&/oVɯ F-iVͦ@Lfm#3wcgŶ.b 陱qBKǘQiGdQ^' Q/IJP KcJtx:d:l}Czw P}湾vryΆ^Yv.d lww1 V-GK͠ ; c*̲>S* 5lKX2&NS iNXʐ/IEPb'briőjkm FGר_rJR^C rjH˟!lBQp7AU`)r!ZQrDa &BROW05]3'GJ_[tU?Q?NB?#(vXg%lEw%f`?-1fR $ vL!%MiBͣ(z5Mү>=#Mf9 Z6ZF^w9 굠nqM`8z&a%<ք bxU_.!hc2q9ŧ\&v<#od ~Up Sj>b|pg'̕ly:@j7(0b( eP؄ߞL(9IyXbR1*桹f]bXJ;̄/q5):0榈XAD9($$DE7I2[B@a_q!FQ tŖPYvoĈ>5dZsy V`ZmĀ$+BٺCʔ-aKpR[[{ۻOur  MrO0칞읥%¶nqQ\9 ހ ֏{Pa+`\>Ui]LEt8fʵjRiJJuu0[IRi[wi*H5PX sRT &7T^7ۦ dv- #GnQx^T-҈VP} @T%DJ#OW@[2P7!0$֛'y^^-S%&uB :b@Q{RdjUAl_sL#])otӵ-d@ޗmZBLh "touvaK&ʓA o\FU0= 5ȟ֎Bn m9BH7dħ`g]wqy^ pJB:Qpv ITye -DgɰGa[B?SѬZV"jl41o4q vz)NVzFup(~>o^h&\?o,q w$ ^e]E/pK/wݽ匩4Alg&k rhRcB^OgTɡshj 1Fk:gt=7\l?7Qi3awD f>Y…)3KeG(lrZ켰6y\@vbhFXVYSV0[uP@صI B gn+hˋ  L8w`EX_U~XfA:Gt LUʰ߰:6^Iooˠ 7$q;,]8ȫI{;TM+_T^vs$TgwE8c(<q~y;޾MsL!S΢x uOs^ng#[w< }x/e4: w@@tw; ZMi>stT8F~ 6]pj[ :Jec*5zy$*)0ZE<ȨnW2z`&R nw]q=F*L=U+M' OO&_賐7y~S'.&UI7@vXޠ8Wq,/k-E(g<=JoDCXBx=2>@Lu>P{ξN0aȂ0S'e)&PLL]P6½ YDsoX$AT{Lٽlpn$^XyD9 WJ2+u:MXTIbBYDT'tBͪ`|LGSxyOO!߫KGC)r|.5mu<) 'ڋFq5 ̀Eq}i[1''@ɗ~֓W|y'ˏ'. eߠ>;-C-PDohX?7U(zU50|aj e~IIOjnP]vʨW ~[\Wz/Y# {a$Fҋ&~Dҁqc~'bX뷓ယB;h1E1DhAwdOo Se?fSt}`/py;@W>/~ܸx`ʘ`R4o^WiMDlI\W2; ^R .{݀]$N&(ݡ/x8W֛oY)>gW Bܯ,4RXAx̢)&pTBCbc\R'V<*> Rןt xY Mz2I|ښ>'X1z?6L/~|)ngHߺk|Yl'<>?_X(yz _\m ymaeΈp y+L7N]pQwr+q 'ӶA$.K;W˄U $+|WƨZW5H|1?W}|Z?Q/n忭ݽ'k|Bק(pOoTt׵ GO$E,'9q{x"nčσSy76(p` x# R |D)ོړ}ൂ}?jD,w1x ps+ 2a۝+l J Dt>jO_گ(I1u.9?]tώG$ jl9rY&_~zN:txu5wHW9wb2W~J5*\[M՛"y~8\UERAǡҲQkTTgLb^& vvv25>ޣ'!I,l[f,mmnlo{[;[lf'qp7O6zxcݰ[\^ߢs&؃Mhtߛ#a?4;Rog|~ s/DY bͫ`oɋ7q8Px{^úoLJ7@|.#_.wz04C#v`BذbGbWV-Sq=A,w0:ʁ[ca0hE`"7!"xa8|T =lt+Ȇ Up , С?7IK75G٘k B0hp;yX0D46(2[DNQH,O'% Dh2$?4qv"iKm: HuJa[˟.;rB\X]eN/^{|C{Q b4f@T3ypFGWM&o`]SoozEo M4 4^ī@0C!<ڗG*}6$b{{wc{oc?twm ?=K%T$3ञ&p L;{ vg(D!@@[ 9f1dn ,@ްQM\M,HSUB: pn'3 ,?XR^8t{>&hWᄓB<q݌Pb`zvڱvlK [;& x獃}CI=S?Xl7~h .h#Cس!CVmPaN1\0 B8>XVH蕭-`zX%i=xYTU=-ԛzYew@5te0LŲQX8=\AUfLGjC;ӡ!/f=t: [vҙZ stNM|t`Hof: L =" iRAf:eg0`0LGqtHLV)tba /e=p:[^ZgzgO{`ǭLǭ {s(={80JjZig>9Cs@߿s[倷\S0uW`O/Ib1R$WVBɝ>?>0_^*qPUpRL?'%9gW'p.䗷- +`H+c+P\&hBj.D1QRԞHIBKj,5`X8{Ӻ<~҃Qsi jϗP&-ӖPy8gɢݣ"In xIcފV2WXhaJ߫2)- .~hI(&W$] |WCF}I>*C;xoE5BXM`caYCFi)HJ} BXVΘ9 tFU[.}3V$NDEXb{fai?z|]A +Њ aWh 0#+y)K=Y*Jj'y\Yz81^J~|{^ID{IM2xz3pn/Od~t\\~Bk83о8z|/e5^4Dm0aٰg3윴۩eF YhK,b+=>FJb\t4 3Ȫ߬{f_[ !grYk+l6oOvLpF;My /Lrcݜdďo{1GzUU\6pS'9hVGHF+VOQis*aJ d䓞 @ầB4g>O%2 iiChN,l(x&S &O`f̯ }ʣ/Y;2 }MhMʙ eAV`S>&"-x,Y2-9%Tә>n8(oJ3 FQQLHL5tOHO`޸ V؃d[ GHK{>n"ѨtVdE~wk ,:zU uAcdmW WwiYV,zrz 2KvķB|i݊ze'G6q"dw[6 { £AADɋPfgQ:E.%D6K2ng{FNa_NV} \^=7)| ܋ P4pK͜]jR3gA-*u6 ql.8k* l|1kVaef0'ƂBsl Ͳ)W874Ϧ\6 'F͵)l1+/3nUpKٝIƯ l;I+xMι楥'%x%^RjfV(ѹx<3I]\{a\waupms6ǼKK^tY YySeZu@A$7$rampYuy jNjkzq݊ɠYm 6;/*UY%?%3AJB`J"/@KRT Ry#J~*^_}T1tGsr;% űrTamdbݴIHK@BSs}.2ҕmW&uڵSSyǮ uHjq5D0Űo )Lx8›LpJL*UkGGTcqutN}ѿ= Ne'xoQ8'BbM~\)Yy8='WYQ3sAd鎂/r:oϙ3R er F q9zs!ǖڌ&޴6mSmzmWC.q0mC-!7*,mJꕲSUi|˫\ѕSUj^YifH 2k ˫d/=+@*J{h d.U2G Gwf2E>mœ!8[{ʪ+0 ^1 xd '^΀HΆէ2 G3`]v!3d}I9֤bbK ]? ƉSQ,v[C "UUxMH6zY[&!t^Hf%=&F `]NBVck,GMшK$̝Sj&7'5pZuq6mdȢHJ+Nt ҶH.TlyV?k~N?mw_\^ԏؓeC@LUBjNX  2DNP e_*xKO*+h^6ҟ 뮈͸+O‹]LBHQHd ޗЁBCYHSj|hLjDVn1\nH1 = ~SиFfƑp4AX0zF3F$4Au}!~*ZzZuc%5c-,yVk4F34 V\Yd8qTJ%}4USEMZc_bZoX^wØS^=Θ"_;"bQFnC,qG&YV@Pu١+eJ0{7P,p=$D\d9Ar )HcfDxRb KUe/@X*RC0;"),;fܶr1!5C3nA Z9-߲tiN|@kr59тJ{y^eZ*.T ޞE11)tQ$f@ΌB`.[,v]c ZJ2\L1_W#cʡܧiB[,]..\X0_./kTl>0ՂӯC2)MjxRۖ)Qc>1@yjLE@qv`R6x?&{{Z@9'643~hdAD"??xJe[t$UF|{{XmzP&<\ؙҭ%a:ϐ0h>9,J铡 'elMy Ǭ2Ҟi5 +~ 3[;0z#NKpnSNqݦ}ߒﵲ'UCri2` ޣdOh+gv&MPǺj MStI$UZBbqֳ#Q0CЊ,T|P쏣a N{ R5Nc1~b-WX4QVxv-Ur}~D4]M#Yax&1WhSJ zXDQj ^9fz:639We z4Ku L&SSOkQ-^lP ^VEAmQGtC҇/%k.'ll%4Ud⪼*]?yy}DËZk Z{b<[ńPk?hbMq6Aug 8Tkf4/۩N/穐N +C,3bǫb& [,Q([KnTZiIqL.`a>2\|jAt ȵ1E*12%mfŢp, trd|2!*`^TJ'`+\j\u< &HK-hH{%̌[0 PiEZ;DJl/A:׾\ YЎ^jtX%]vҗj~Gba5\iJy,$3m)ISHp>ukɈ&BG鼧C %d4\RX+j.rRIN5 Eۜ OXʡPswφеBIQk:2(@/v3B yĤ@䢍@SC]@Re»4OH9Ȯ[չ`S)WυDnsƸ-c\ND pc[0i}fGNs;Jq}+a,s&a#\LLLhd/eF@Z+w!}xQ8,:$u,ZXGZL„|*NKޘ-`[p$RĢvKG MjYT YA*+\W9!iolKڤbXZV-sh"b,إ>Ƕ45%,Q idHb1 YV,5\:ǭt#A>O@$zI"g.UGv 2OZskf%!uBс:`x":%5h߯ZىLB˦,ع8,dQ7E~8o6:E.}@Lb),Q4]Be&P`. .kȯH.,av/Ğ_ߓd_>2fOoqٗ)=_}}.!g6rI4SD̕}&!=zIAAhL_I&Ӏi ֙ 6C.:jJ'lF._XЋh!o3{IL >BQBSZtcz.Yo$ a}۲?(_5S|fBLyH"N5)#9'O$T |GYcN>[J 4>퇴hK]s_;mmCD^d7Xq~ilHɑN6mOc_ XU3.8&XI lE#cUʹ3+@5)H 7Þz$&RQ$,;&ΩJ>Ƙ[EIƟ{@ȌP,2i.E榣G@q.T1~x&>b1N4t] Gm={JJrϊWbZ -1 2Ō0t,# &/HR5lWNQ? x0~%f &L*Tgaj\UߙtU J=΋(Hl*\r Lr2a..wΛ# 8ܓV9`JD9V)>ա-;*o?ivߧȂН kVQX]b1y)sC/W:Z\ŤJE-U~h⧽(O<\>HKoHQ3X#uϴlD%!HzINwz (U#akJXH(2Uq5dtoI+v|@O]h-&8;eS1::HApE6 8%΅q =NjL!16؁au۷U(lG~n[6rDFǂO|CluY+:ޑvF4hPK-*tx8nSIpr!bZNkYYf_cL^?_ـm(7$0}'g{wsgsgzlkwsz?( ;Ůgxg9qxs;Go{sE$,6;SniF 1{eeBKtJU1 gugSb2Lm%;5"`3ه( €l?rq xGq#qh,%;^yySkaIzO\kev~L95yQo{o_k{& FϏN/篨"Cм@;^iC>QIsb3ZϽǩگ!e;m^ֽf j/GimՏ:URV 5\B;P;^!\[|i7IVOmtS԰6 mWj|#5hciӪ!WW#rMie[TZ~lIm6x@-j8HeXř@~^ 88q}hgYYyCly`(;ohQ͐Tp\Ep_]taF^6v@Mosm+vX+J],"dF40T8Mt,/Qc3o@ZcGj79} G6u@䰯X,1$tsfpZRTk-&[k[8~S;8|eU=n:VZ[0Mq\NLQ 0l=K$e}Z0j̹'w8v4b9ZkTB|d/ MT9/P&HGg)Ϣx\LǗ !M#_1@`dбj0Ļ$1G$uj`t/)_)?Ke%nhf/uik^cJC{F% 2v⃯4;r)F5! u(}A' {;t^ i"g&Z ц[2X %l25bHBrfvSx|'a[k| kϳlNV3oѷO'Z}morx9}vܛ\Ew^n͌+ubgu!FB%YI(G_E-Z5 e o1psMu)yᑒ_{L}Z\:EUXDEhS] ;nF+t7l'fPNin?9tݧgk#3zbW40{l)Zez= Z:GjתR;ͨkUꑓIt}eH~F[hXxW$'j?خ͑B^bvtFt7ZDﶔ`.Bg3G^W9F:FdEP <{E`% {G8z9|2Pr®kӞ_3_ǟx#ol'|$?IaɟX'!6^fEz+SgYQ/(*Y*\+`.Nkv^?nwZ $DHun\WIn92nUHbS$3<3w_rM[OW| _Ix~Q֎{`ko0a0X Q޻l|IȦCmy4יZԖ'r486q6>m Y`G-u@b[t'=}ODAz9-}+X>mz"=)Uo%d^96mˋ5 lr*-Lk2:e%b4uS# T:7[ jwY +N<NAlb1]Vw^B׿l$P#ѥoSVT]9}D%Yr|1YT%3="izdc+L~Ђ אy}Q#[r Kc ꭭Lf=}{MһDIՓ/T ؀cy0/K$0&1B$%/D3v#F?Ltu{ޱ<n39nS9ӊ zѩG[__,ӽ1sRީz0.ioM}_oS?B~PwDZ;Նr ?yLyO֖xz怢8{3ʬP.%bڢTx*ef5jR$uQM:mKV@@NK2[Xy`frkVJQ^R)9NG*?k !9͸k/;0hƨ Z:5`.WwE?t[kQMAOVI*IC5ӣa^; PD!qR2޲G=ͻN/k{U `1Rnxt۽ ̹ ۓ|h?Gh#s'<UBGL(%\Hd5i~xa1gw#$u0(A+kRϡO(M W4" 6W9 Ke9C@<+M݇~bCʁqҳb3VDt˗<)O&cI$w$~f\ $?܌?b807ay0l#V38 0 Bd ^5$7S8#MJaB8 *8OX8S A(YI}P*)ʌ]!Mߊ>maى`įCZS*s߫@*ǿ,JfZ<=J0*% xXUQ2Y=~M%}FM!ъ>6usiQvd jl)<]FE릨NL~^T0}hSjK;a>U\dRN8;:#z?5 +Nyf],4QcQH"RCMeR(vs,, %43djQuxWGtwIL†8ېA>Ώ;fq'c%#*'9)@ gWV`)8p[/S?&WyGe/ҍhgrñ/ Lyٶ޵1-'@~O("E^cHAW)߄*mH+m\Ep6Qѐ#!_K%-ÝO:\*َgg^_ ZUxfwSkwrʔX mNLC1{,VKF3]AO'vx{E@L5.|q# ]&2и*&ؔ-J;vQʙM0AyBWя&B; ]-W-W=jwH܏O>SuS7WXLr^/f", &Yb)%a^A|a֒c鄡WbO 2G__㳀ws(~=y<Կio1GR2:C&$ރlN}T! ZDfӱ}'a*G/NAKdm'&?Mמ$}|Ѣ+ p >DVcCc>n4!՞QayGDa v:?OogoUR.v4XΓlҖ,eDi=1hAzUmC@hcn. m(X%h!|=A֯x FLO/kc0јߴw!fG-7*kY"CC@3Y_BוjWFR ڑfBLx^t(*i_,h4M`=[ϭ[?g%Etf Dڄp̊|Un% UR`]aXI$) yfD]֐vRb!(.eHD鴵ڙQ)U4c}$X$]LzÙĚgMQ7C! %B5''0:VLVf_ƫ(RE2f~B53 kOEIkz}|7cj&{h;T7ķv y6+Uۯ/;7祢[E5YTuoog':Q@0A( Ӂ/:[YڢT!Q૲iqylbaf\Le b:߫W]~ѳ+rtDsWTnU )B\n)\in[ ֢oj0ŀ࠻ʋ=V[L7DRZ u6(Ls4@簽N'èMkVEhVٳ[U-ى(P8s9A% y-gDq@HU[Lp|7l,16ic95:nj팇C;c`w|ns<I8HaQyhs,LES~;z:d'( aIb>>LX*n gNۯ]4h8{zKw"Q5flA2 0Kp.ysc)A t/uvOXQQt3E`,u{PxeTRBu/*omW5M xª5%[MrVֵ}Od81C!"I?wnQ]dR>'z\6w+f 3>AR;H}{ȉxj&% DU./$ڈZzWl9K>gȥS,$s_MDwyWSZR `!%h[x)Hn[+U~CSJG$`uli~t:f~?~V\? uFM ~KWw绀D΍%*"#xhY2\!XRZhInvnn'b,$hu-{#PI!/O+eeQ,$IM:)!J۷o[Zq~ |N|x{èt:nUJa**|{@nUګCe_g鰰C$k/Bzx?"86 .czSxmsvr8R},J5Ib?u.~쮒8iA,R%4IӺJD\íNjlYNSz퉟23Y&]}ME[NWُ*[RۆvpUnjWD_HQ_>xa/E@ J"=4?&a^=s$)No?gtƈq3:hf(tNH˜6N@)(|g>>[pZgxgˮm?~xsBX(X1o;eM<u`Id#$W9  m&{Y$ܮ0WuQl`Cr,(Δ]Fx O-"y߇ F"9BvJȀ @ZhLt^  ×Ⱥ-'՜y)*kv)ۆLZwSt"5,#G s9)x!Ag+CYdr,% -miP|g;vQdm cjU860a8z4(9÷Qζ]T][-S:YgmT:P7;[1L^r=dJ$`Q(]$ƙjb'@1uPv#?Uپ F3RĮR"5Lh4`bDi bHNc Ld""].>H%{$ݴZ"nUZ/v{WԕBlsEďfZTI%R\4Ӌ qJ"S(ͻ-ϑAXh*nR%r~1D? lZ(枈n48:bO;SKJxdii6Gͷ(2mY`ɮl=v?KlKk"Gk]Fv**$20> Xhc($3 ؘZb=WD.R֦ ӴzȀn2QP4EРB!yq޷T΍&_^I1f|}U>s}/2?(-S诧_/Ӝ_!c/iṣ->gx!k 9 a8\FD(ÜU})}Ąc 4C]a[?nƟ^I DԐWߠ n6Pl-QTwgkKkob_>y[A]MC;Z!X_N<;+SUT]VJ/Y2@6fZwq!A S1wwܞE 7)-)xWPdO ?[Y%IHd{ok}w)lory!jCq!R ĠJwG>DK#lʾFrIbv}z; %ٰBX=p)Tq"|+\ܼM zM]cgu~aL(({Go8wY҉s-+8QX`TZrMa[WMآ }?{69E.J7zRB0NΖP-ݛ ($ bvӄę m0G3/מ Hlm5Dxa;1 dINe1zމX-(€ApDtpm83_H W>- $M+%٣cuZ$dTw~2♢4UO 6w0%LJʣlanG:ÞmAXm,<hg%zhNJ48ۗ,Kٽt~v,T4~ .ҁMivaɌz;jh"+B#LGx/ ʼxX nỦ螦7]2yO}RFl7EsRfŝ]R~Gb$/SyK, %xl{ᬭ0x0#}kEӧNj ?VH]ѷJcIgՠ"F!?t |R>+I0j 98@gHK[*;XS*$@ւf{@Y~8ǥвGWPHhBuAᄃ˥-1/գxF'u]QMY.^ksCSɆhĭXt3Gdgrà|tZ,l:1lR 0ȩu _<ѰV1.t, )\:õӳZbNnWMc)T }70v[[_Md2KjUt.ӮK.ZPd,1,kN3#)72gFx`5RM\Ng* f"@xS+ŐKP| ʺǟ*ɼ0f)$/"$;=BRC]-WwBi: *D7X5" P}zNjՏvuxcZnh3HjF7?1a0Ou0j&!ܪ/~Xݮ$p"bFqs;8fia8CX 36r dԿ@E^WeM|J_MſςZRwSE +NvKUm@cMT@lR=cWJN:gyDw//5qP/]{ pxeD2\ZIi¦i`VEKbhI !ӎtg3711H 8;I39թuį:N+i[]u~u.%HSOI[VeK qjƶ%^ګٞĦNV*W)|rz+NTʡMeR 󫫵g*V[d~;ޓg/2XeRpfIrfv<%?slmg~͵q )%%u tiC#d0&fbHY!-hFW ӟƤzxCQWhSQb6H ͭn7adt)%qkb š_}WBa7~Tqw HdGG@Zz ccV/-ܜIkJAUl#OY_J؊2W~L_hwytq\gHumSb5R! . ~Z߀10ݍrk$X%T>C&p׈WYE~KSjo~ջr_b<~"gswyHS  W:G$lg8[PK!yYE2s꭯Ӭj%"Я-%%&3#oNp(ޢIѝAN8VtY0 OܡN$)Y&q#[haO ~w*-z< \uQLa{:qqz}r%82f^v;̂[p?wb8GD/_ g,;ZqŽʴ>X\iĠR{pj$b+h>Tx3%"!RS@X睡fj_(l4[odoVp@<_,艿gy$7Z>i}yQACnڴ3`4fYޒ.gNRe% 1%W̮Qx|nLyeq#y9[R:UP=HσL<ULanռ^k S]S֗)hJlIȵ?9WymJꕮRp^9P g~6Us3_g1oy-̃qޮ:/'6SUl-*jvҩ_JNԴBxdɱ]rԒ$UKdx.j4iZ0 @^Uf]UQL,&`ǯkRSUjΝ`Cab Zs TnjQ3'h[m֩Vk,30nԳ3(ʥֺzk.2=GgK7ߠ@l`d5>Ib۱\+2{2ygD49߷onn=|LO2xx{xuRmlol_sV/f<'@Cr=m-Hʂ;\x,n_~H5@o_m|wO75>~{?{9AN>ny=K[y6̘q 0JвY/6429q(p%Fט[rMB, ΌXSLIڗ L & 5N %hbC *-PBW&U 0gxV1pĔF(znz]лmIK<`ԋK7f?dLoE;eZ@#du[cXƫRiN6-TX49ǤhrZhw`UY l[ aqUXU~s*I?G($/x{y߸W4giGk/l?_ wK|2> >*sI>(nHȷX"6w6_ 4~糬Ľ~{ߗE zdLqה3Ծ| osSkwҟ_~w[`6o#gϞ7Co=}?ޏE =i---Ё hiE탽M{w:ͳQ2H=}M<7DZtahj3~I!4i|TsW(U:>mW!G4M$848 `һ 0kR;JNz,:iA!E+um1? pHh"q>WGRd2vr|T8etƲՖ:m#T% !^Epi)S{o>Fo2>=)$u+֭$?1#y~2虲<{~ۇ7nov/6n;U.E%e!^W5U[-WZD]Ů>nā?\4@m\Åh oBz [ZjXq@6>d(딃?`;tH%Ɲ2`#`qJ b> pO<'t; E R̝욙dԊfSEfRE:J1ixM>Z_L7f(q{mMeu᛺[oSusI>}ϓIdpxuR$ \e@trT}~zZ~/Ǎ;CrhFb)TG< qB\,}]j;@d}l޼CQ7 D)4{g4{3俯y'׿r`̝ ^Iw$~pd}`@Z=εG_%шHJiGV %ɁYP |Ak^ -G^GV JCF 8-CL?e >1%et aN{R, С?_G)-2դm^ AbO 0a<7{3-e5c^/q|gV?1,תVf õZbw|w6cV]Ԁ]ր\.mj q8/ZdvgF%68⍆KgQOo0Z,, Le~@hlwN{l#뭟GaV-n{_^D5;V#{|C,s3E|806`Clߔl2k1u4 M67{xufkx:h7f'R`_ >@8H[&N;.,HNp}V8o>FTQ23 {y>g~9a J(S_މI ܍a/xleQsX'w^7hD= F L_x9?SgP3b4Uvl/o诃;0٬z?e "<01@r!hRoBQ,{Z)J; % ~J&n/ pLY(0W/\~JJ@55%)%c\%l}9[q"9wNYcI.b.g}a[(wX#&brXk,NCW*(Lh8ff}Z L`VF =N~ye25)RӢhĉ\gf3o6b+s&E8y["b۪XQƲ;𿦡"ƭρ!x15H46^.cSh2W![coC>Nۗm5E Ӱ_lLgpe8VY96#ՓLtw%`h;,,9vFyF5? | ?Iqǜý?www|pK:w&H#X?6^Idksmk=}vo=kNj|='O r`n_7Yzs1{o6=|=|=|@3C:M_L}N>ɨ;gof<d9fѨd&Q]01"w9Oo<'$2QO|.C6uxUq_cVSہsѫJ[i?mRɭSq\UY5Cw7O'Kw5} ɐuoy#6$\6Q>)Ӷ*, "Vh-8յ]C׽APO}wQ8 AO mNC"%w#r (&u1"vCxe;b [u|n-=4w lpKR#WN;4,NhX*hu5 ,.>[&w ǾyKwxsa2!]CTupmRW'V2C^5C}Dz0$(DDeop L ԧKd9]jYCw[[ˏ1ʪA&w";UprtiBUSC]UwHӕ͈TmSVW' k U5*k j4C)n]B ȂW&oYy/0e$(=2Fˆ&zT@ŋL2JiUva'wuEc!OY}K][ P| 3bCxxc=f}qtN-7|{f~j ^c9}Vy˜LǼ!l]=z]?l6r*mrc磀䇲6'iGoK5#PPk Rfz7r o=mƺ*{~+nmz0*Vȥ g2:FlefJje\q[%2==+J:{Q孝KHx}a'_ ڰ@ݔO/2}1ba?d8Ic/І*dI~9ڈ`&ĸ4u"n"ҫ޷>,7M|*h^ ď'tȘ&- G {0y n&x[t]V4\ɜ>tfL< oXZr^yӁ{BO6ƴؽ St5]=l~g>ӎ2+Y+o]XmKPRr~()$i颁Nޮ<*^7VK7G*) Κ]VMGNsKljzThe{!BVmCvhj2/@ O٢D;O}9S)-]O(=>^幩% G~Gfv~ƥ>B&OrPRZCJVkaRkA9%[~% c`y%`-0dyE1o!_ ܻ{^Nf6n1 (`{||!0 7 $sW{*'''b? X̳ĵ03pY;8^Ybv9F{w}cܥ,ûQ_S:?a:NA@SI r /WšUeڋ)XChhE1|CՎYpNs{haJEO^4Fuvа|;,(aDM RIUqy9mHom6åsyw cS(ӲPa"[IJ* ?Y&ipMI$VarxkPWO@Jz0I~Vw8ܳy q.sqbJjB+ڠ$L1_-j3 V=Cnߒ@(Rk哺h3F79\(09[KXPc/mY`КehgJd;C|t|&2yE.#b6rIi0ei/>*=+eR+ *x:]p) u{^$);W0: ,P?w8x!'H%P%o=  y`B:uTQ4d8;7@ѵ7cGp%zg?1Aj /AP?n:9}V.@^ktkǭYgcޙk(w Pq):׎b~à1U)ktګ6{B]% StZM{]Zh৲zN+yV(ҨD /W` ;d2*kgu屇>C1*2~(Rr]:(f\nя/vHjϼ@Yyv>x2ҳqށM!3۷!O**juܱYj+ZeXTs,/Ϩ" 3,z8b +B\CPb DA/ \}, VL,NRv-U'\\(!H6-EvUon޹lw;K`O*lJ{wLf4%~G2,;n<L_㺽d* <_Z2e\JvV&A8:q;<63[;k|O k*E IJ9*txNJ3DiYK6~bmT; q'h:MpHb#D0Pn!PBzcEn #J[g8Z#գuxݫ69DIL)>5U i&{ H~Sx Aj6jmM@YP3 6ceX$bfejYFcITC^?_jg^ЫV a=m} ̠H?8R|Pu ƦkBXnޭ7a1m֩1\_dƧu.֑[} '=-U`,ĺS9g5&ɺ|l&o򪸄Pz: p0Ә+rZ y>z(^)H0r۱9FThIP"{#DOf9Z!À=w7F8: ^(R"GNmYJCK80I#*ݸHJD$^NXvaNz"$3sE)Gj"deυk5-#}@KI[fުLfp1ǽ+g2$< z:z]b B`I*TS yL"|q&7.?iRFaz,W~ ٢:aMXҖ5El`| KK86^7/d+ځ'dGݜ*cy0Yx'_(Jk$O/G!w,JH5@zD' ~}4ϻRĽ:lԤ4Fg[l;Z1;/m[l{$-ؐ\9/{de˖Ҍ%⠢ 8aës 8Vo(@X:2G,(mt4 .uԋ7\/1Ve#/q(g}:"j{q$g +6t/2*1H,p $AB-~WصZLS<۝b~P(I9πFpgi, ebM[~BBFDVY)m9V"*`k[Ӏדu ]("u$ݻN^]}6dY3vzYovaUF-fpӪg0,I[P`FzӘȶ=UȴYLwW;m7 ZMMb.Ƙn+2f-T9%Zj-łK3IL .)MSU"?}U^ tR7(E:IVNt2;"3]keD_T.gN~e`E!ɫ?~^QU=][>_H| ^mUgb` [3CU7[JJUibe·8HKXQ;.} .I#I!XebZ.I`PRD7:!ە/އ۩gm+"N|^mힰ*L{7Lt%d'~ ) F T$eO =lTy^/xJL[☣\˯HQ_ q vr|CM=[$?״Z-ҫHۙ2wљM;$3mzhn HV,Hl aMZV[r/~~/$& 0,VRX 粲#l5u>@U,2^ci婖Io.W ޿;t>Uc dS8wRA!`_p,F& 0Sd6d[{Ioc?m0,JulK])_ Z L-M{al]i ~OP_I/[w胯UJs?IC3J=Ʒ qI+ݰ q9N[-jߛ>SY7Ɂf8*<fg N3~ cwM9 >w]NЇp wDyoiű&dQN9u8ep2 αR2 `V&VRb3%f4.i, cڐ=nۓַ֦V\Q$' sX䗍}JvrODbo' n:n\rKdRjŒV*ے|8IcB"mЋIR#vPf3i216̦jn9M|)Y@uk]TU7 jyGS'+ , g؄'fv6@,f Z@YCL<RT;CgVZD&v쎒H[굵V+0+3)MJ8|KCC @~>#g~Grʩ1l*{7^q6*SOwoxShzsKUn°["zf3NԁДf$^U8tWGhg4 z# u;1 {6WI{pr sbB#DBzқKlPm`s cÁls!k3u ߵ7Ky-6C/ +W[t}nSm5/Ʊ1p06OLvDؤoDy ]#"X huzMtB!A gƖ4TTOz2P,щ+ޚlI-Y~IV G`#oߓ ->MmKJ =%:/0DbE5@?z[&X _ns-_uͨձ#̑ ڦt2]策9Q,* ̝Y]QS%V[ݣ63T", S53’"R)U1y\C$o}2_'`k-U `Ҫ=2ѐ / Ax CU xB-"EPIX%-ϳ> !e Y8a %D ^Dd-߾h"#=h=lTվBAR@XxY$PsCEVp+"dJUZO9w*1K*Xy4ʁw2 V2 LU-maD_Ѽ`S$BFŝ@v(:kvдVn!Ke?m")>by1Zw1VHuFnt,C\H$¥|a"!RS:67Q>-F(P$J惎Q7!a>$) =-f.¿+(*)Z$HVP :![&Q+ܑf[;[; Ms΃y=u=ܳjl tt4mH`Ƹ=\hD#,I3 z<#Ei2oPx;[FMO q'Q`]gJx ub|OAVQv@VQ*w doa&uhg.TB!C/^)5bzZ4b= 2!d_Z<:P5;".{X;4QX!v7 Gw\42C]φM5$؛$xmdkgwM$~*^=SyQkxߕH'v̾[.Y!{y&U X)P^.tA--q%9CWUO͎TK1r67ڻ,"X/vZb}V,]2a yӑcL~b(¸> qP(o_Dv~^S`'NIfx9TH{qU+Ӻ~j}]=Q9~|"Qwo T,(fF,96}wG2%Ч^j{OtG*r1]ԒMt~43Hӡ [3?꽕KLIݟ5'uIݟ;zq!!Iv{"Q:H& i ~/i)KIVɋ'BqV6r",1jnJzaE-h`I `yV,`p[c#s|<WU9LTRo;i1f P!Ȳu{iEwvY^ͺf%dSR6j]H֩̋ 'V=ϗf2.۝uҜzu0sy#-vjOMzqC8XRZgѢ!-*k`tsumDrY$ z'}7Db-D2#ͶdRZ*i,ZZTm ^ WKV1m&;V4JfDn b]88z l9 sYWAp4 + `KZÖNe業H:4G%QbM"Ras%*\7hJmKaT䭞)"M'R뙡J<ɳ(AhxOdv0Ez} S6%2)2Xbqs! Lw3?E0"g8)[`s\XgP)c)P;Yڞ9$Dlt*o72J )2u-+hoŧFmҫ* ?ONΤhco8 ZWoY5KwFՃ5w9.xqB "/bg]!|rla֚|3ۢF v5.c?Φ9QR>yb`0#`rK__=-%>9HDu++.G9O x akC1.ZSvPW ;1, Pmb4Z<3hTQ{#{nR}(789Y2^o/8cߟQjh&AĿ V&BuqGSJsKZc)lpN9}f [5KYXʶnorLTUNxvh@83@E2@k\ } `5vQ+ 1/6]Y^ #6J\0GOyeMʒb\M]cL@rTɚcJ+wF5i^'_Qtq@OGeu]:Rjq>v8S X,$e `v]]Dȵ0 ѢҹduT,4g2U4H_*iq`.,n`'cT.T* J!?b(.CSGP+չ,V:f4qe +OMG[,4_84د)PsSҁw(! (kD ^SETItD+VKo&\ܟQm߭ƈE FV:#\tę7knF(dtMGÛvKL0., 18Tb`zʳ8ى7 12oU$wRq]-w$Z[}ϩF[;'>BFnL9(\ezig.&J.0 &UU|4fty~ٮ;"e8=+f!J#LKUaڰŹ_<7Q8+"?PSƦ{gryryv7h?!ן0X BV"jj$CN0u ljMaȴ;Cg\!n07{<8V4 oga_lhaZ[bU)1ձ-U20Y^?_~r H}lnnzֳMok޳}oskw{/b3`,qݻɺ<})]_Y+ЋېI4x{1%5BZoWڨҥ'DrܧVəüXba0ғ Lt9I)aǔ|ּ ΪVoht" LioC mlg-(@`i/BxN~ԣ<ݾ4r|<īA8k&4a. ng;`'$,6h 2XeTCKhB-v|םx0diK^+fއ)jdQ*fʗ?B,Nb]//aY_b++^0=YX5lA+::*GmvjRE i Xe٦p\׏sٮ=Nffc[#+k0 C~rilMqh"ڗ/۝FS^5mḒש}eUqNպ@Kj7EPwMHnӘI.fuh[1%X6 ciK4755zAL'9õۅ؝bqOYm!pvf9+|M#}-|X0Q->p|[E ,8٣BDFh\iq>gVYS_(5cc+k4M=$X|,ymKpҙ&UqAEmf!Su6f읻„2YLܦU`pԒ,7D,vHn &;4kfA znJ`Xh0&T H7t[*,Q)f) $`L81LLJ\jz6$ Qz,;3Zy >z[A玌sn__;G0)+Z)Y?i֕lr1eҾF=dM.f^kAZ'G;/vI ^#ٗ+6w7HqɤF~*ƈsIxo@N:菒 [WC}  )zCrDKTH#*x615nx_qIE/ &_}sQ:Bܨ]O]sTУXq8Rmp#d&/ 4+jI3ȍa |GoE1q.87n;q8x9ʧ5|R8mNzkGfe^^jAH/cR?eBR7c.~c3:!ɕfeiIl 4b`lsT[j _;(4Oݗ'nG ryUDxfJPz(V5A*c2fqтM\s.:Ɲ[MjY r!Y X _ߙ8 tCQ9677) zOY{?(g{ooY6v_bO:MP]5Ub,wEHKp~_],8>{&V]ʖ_ÿs>ʘzcp"!}}+eX-Kҳ/4fyhʳN neķlijѦL~:py.,Vihg"Od-b*j+ޟD<`!NnRQY}toPYm/r^FŰno$#,L2 ˘0M8i_+K UM 61i UFg4UL>'ʏjlu,HAchwt`^ ꏞM@cݣZ]랷_7N:#P<;=m6/^֎~:> _wUy x޼#[JCb[rdc`f״BRԒm&g$3WkS~*ƤMp?p:,`iNU<Mz0!{,S☡pBGd04sݥkۊ5;Zxbgp#Wiܷ$$r*pOg$6L.X+61`"|5oGRӳ:)Lqkᴋ-:) R$r }2wsu5sL Baѽ"e@ t|s.~| ێld>DvQ̪#$8[V}-?/o|:hoGkV0<֢o|!j~F_U(iwGs]i<eʙ_ϫ/`mZ¸ ԋ>0_l14O=:Xʆ_l?P*~ #gۃ:%~a'>O`c(ϩS7M4^MvDckx3J?ȕ[mwɶU !d[.Ld<$؆d9}U;z0㫷V1x' `󣞊ng{4YrKxptzFF<6{Wѣ Ys3?Y|5 >[>_/oѤjО|1PH:eu֋Gin9 z]Ga*.4)%{#L#1d2%)8k<{pfxƧ\DVFka Gnk,|[O=Uc짴:)']5\&hJ1y)<4qZ t;7%{7Qm@׷[ӤW~ /_t:&mжīzX6ukV8je {U%g mw|lNʘQ93-ƆaűǕ +I^"Y:5lX1M'W `M#Dй+r4QԊ '8zɸ'78r.0Q{~":z1}=[3(N]Œu8]bkY!=,lzN!Gio8ޑ@Kn|uzS[[Ut)46":|x!g6pr &FC{!hbL3f;8lD|MpEcrh\+?W-:Zq^Mwlktl Ab`A/u2uM~Q42cاɐ@l?}O08BzQm@ح*g3k`\6=DN4C/ևJZꄗ0)4PǗtymw t=Xd5>#Koɪ$[ƔI"j'Œլa2:%HK+˅$}sl9B!֊ٝ.`EW>xfӁp}T+KVW;Z\_BBfT!Ĺ^~^b@. )Ѻ-h(W~ &8NyY)b\c!zyc\w a{|̗8\0騾`栗U8zbZaF&11Im$FÉNȜӀ:B gH2&cyp}t)pNd=ܞz'>SIlĭ沺驄Fdfx(71vLgdk.kH\QV6ҌF)V>2:ً$PGߠcЩbDEjlS1е^Why✧S"3cN5`ce2$n֠aKe8 '|sv3qhȘݲ42ȃPQ 4Cqơ}+AD nG6|ZU|P kYpJDXر׳ͩcPЏ0IGHŸEU[4ܲ/sMEޠ :V݄2,>)PM+m3iGjX["M9v^pl+Zp.- V/Yn9KF)A}sZg+8q[7-+|j{ǃ8{ptfCh5 N1c_Qc}Lc\YxGL:0|@俴dyT$vqUK̶-('}m$B6JGsBrѿR]B7!6 _s _HhQ%Lx-y=a0 laXZl4*۲AANic581c+ER 5&|"F@;ET2Z+rE\DxpXsu5\ܾ<]ӥ!A oVDP3/j%4pϔT aO'x늨[(ͫO@̫3Ƥ%z3&dB&M 8"܈a<DnMĿkv7uBu|cF-{kek}"{m)*"uHU͡C%=E^DQ{ c@<4L TEűV#wVm?V-gZ֦O666]|???V@QfICH~?OT*OcowY ^UiNN)4Z*J^v+.'О(akSI Lz#:Qtp&$垉q z,zбAxM!Ğq^WI3{]E;i5o%v5/C vC؍Jae듫=kVµEſN$Y>w!V ȱ/HQNTP$tpJ"2rM mưs/3jbO8P c㝧{$}?z];g9ŐIpѐnKBwu6NE:K 0hvJJ)'4P+`?}O`-l'u{xt@M7QlBE*TGVd?s q`|)Y~f:Ę K_4Q$p,c4pzbQ5:&\#J/Nۂm 6!\G{[y!`Pf?H]bŖrӐy0Gv ~;iOs"f&oj>qrkX}ntݽ`nac;7NJϿr~Ѻy:IK:O|v˫F>Rak]rsBHwq]OT*;]GBrUtVqi~(gs3CR|N?+k ]|g!)hx3\Bdr[[?ZRR@yOW%g$4 Am<ަA(u㛎cvU]#E9)Rg4mk +[ee kbQG] THS?5H’vii_M!+qȠ#1@.%MC@ywM,(CZdv<ڡMqs3W2tuՐFkECZZdll6AeUE 8z-MI*fQ JڀP q>xl91֒v63zF<]+"/只+$gkf!<@_itLtRbƌ1‚D_'50q%_V1fA]8d=,;6jV.^=ʪV['s-.?dwP]9x&mW_u`VsH>UN 5^59Wgd$f>_]]]_-;, B[,5F|< ԚPd H/Git?!GQ:PcO&cI#C E4*`u=0jI/&y59r<&%88zy&Dh۪אmTTn =h=== jr U%:_>|P9uv˨:Rfʯe/7欁/[TPGd3Rv%EcɜXy?Xzucg~P?njz]E*uJ T:`Zܥo6+g(Bʛ@0bJ #;LI4 AČ%})+}I*F$~fy@œ0V(8,^KQ^gˌ[;- VW" N§hvݧF=,J7G/vt`c@XZ?%γꍣh.Xrd8[eA^zet[Y5u14ggcK\jBOT X߭H98݃CgfM*Rۈauu' W^އ D1\Je[,u 3IlyԦ8 j&y)M-W?&KAeEM@\ 4ޜ46d0E Lnhx@4`~s37HZYj4 bljn1!r2F t!.W8Om/v_~wj?ývp(Gѱ} "v B0/g5_y3HB{@_d?wʙ欺 V*+{GD+m ԋ\ְ"LMք^}'hYNL[p^EܸJPd5ؤ5ڦΘma}2PչWa=qmMl}q*7Xښ%7hpqkH}8Z*S6++pԥch@ ND|wFd\\Af;8&L4.8%qp# 9bгhrzf%44Ԯ|P[ݒyomՔؘ2_Q!L7^a$}0d/:z| Tj 5ZѯVWW ]`) UjV7r*Tz}=:2,G?<4KXcZ?X`c=8i~ <$R{pكCPxTekN  hyj,Y z*N2D{(+ւo6 @.}"` ,%no m3|fDkwN> Bx"ׇgع'6&?0De n۔rېmY4ֽa8(EL""%^ZNZ(F s]W^$etR-?KXpqW;,o"~ZG 81NyEg@BT|ێ\s ֶsH /m2a Hܠ*wDrij]?MDs_=s% 8x|n!Jc 1(đ ]zmZF+&@CW58 HS8A ]y{;BQY/.`Fwd{b2ɅX  Ϙr9Wž1 W3&\g-dC$'[L [͒h?u9,ysueg-W 'Ϙ3F}Dno؉1Ei<6V^# h- CJ|FATFM0=Rq(A<jAqk/Oc$']_䳸k `Z/N~V⩐$)Smj6rݴ~|.> | x;R2pO(ړERѧ[_מ/.>%o.| ?-?Y_|k3_Yom.?gkkME6.Q;Y p&˸ctySCVK)tGfw|t|z6yZ旕^2K0g:2xK_:nZ]w %>Ky,1 g9ͭ|߂[!ӂ_G|Q!MZ(ĽT `hG0I"N^ !dsx;q _{.8'˸aVy<q ۤ3o: {Njyq+Ϗ!`8O='à2_4'{vibwx&Ybu~I"F~~@qi}%J=F?M|LC){qw};#޾&xIYߜѿ~N?FWNl5d},#qwcdpNNp>ȜTGݳ34wHAߎ' AFm8ܦe9"߸ RG:B5#/dWmq!4w>gM`r?V,, Vl"Ϸqҹ_K jVf%ܢC<2ra`Ag$.B̠Hx@jᙎaeepL}>8Nc,M|B'Vw8@|=h,BC8%Cp /i-Ahߞw3.Z}=}VZP$t٫C^TCх>{`a Ft$xSg޿3<=Z\S v3`X݂zLJWUR9F Lmi*4ɸ&L[}o4!mcTUeet)xcސ{KϿ`1wkQ_٩̒8Hx&xdy|yЊ'W?觍j% UPt4W]$l+ih6ǔ ~)bW2&pT?F@ߎuжk&3#n#1WءZc^jZqK\>;KFޙq 3;N?G<&ſu3+014V\f4Bb#E&_.lX{{/>O{;~WTEi>C z+(7#jw߱*&su^~X_ pZxpu %k _4X ur/3W.r11S @FSVN5xbs(?hqaO3 (O)آ<]l~J%_6Ma@9ƭ^.9M cKhb<Ŀ?jCHWsfVR)x^@CO]Q_cq:HI\`ƞª+NHW>8ܟ\ ԕO m @!PA*_mr "F`҈7^$ ByW~z >Usʷ[ѵsվ0V9K݉-XWwwǵ{#06MĺUSO,r`Y%Z9&WBC+eE;μja!Ջҽ{~y'0jZy 1Y`"`%w#GŹ= Sq&{|(!XSh Mћ?u7Q4i#ȸ"G0_M+}Uƣgdq#jVЀ^'G<ވV;y긺+2g=\.%_FLR Y`2

R}EJȾ,_6# >eio`G+V {'પ" ` m~:‰Y٩U*@1QZPX\j,\`ܒh90xT2#cRԫRcRˌ/ɒe-52|SFHcht*5 aگKҮPf{%]^ש^İҥ lqxE|+)=u1ϢU^ݿ @B%WÚyC:xK)rYuW,)1q4WAz11S?E :D^}/G f&jjsD2\]+ʯ o6WʏjKAh_Mz%BcndΘslMF\SƧ9ǧd|Ε5k|27w("7*+lpdUo2U6kWwÅ|a6e<a B)1!|x2 F]T~9jc3d{B>;1]_gf]ՒNn^N9I37~LF''lCP~>bZ-hBO|ciUOQqFOk,e$e/y}H`&Tѳ]+]x}Q/mgLFNж0~eC4IO#cZ{YheSل?i{Z՞)T55"<#]VmL,wc͹Zp .o aPCH9Cxyob1ӘR,:ᗊᥜj!ŗYt@wMk χfpbYSԈ52B$jk25-n e~Cij!ٳ_m O͓߬o0 N}0:]dO+*(/c;JLnMU^_ݷD tʮè8M^Tձ J |34O.̸ v3~,}N"Ie])8H"Od`b!镊ȍ'U4ilaE1 2f,BZvp;]2V|JJs4Z121GrJ7茾7q1E9V-cl#,k],>i4l JCL^{pxg=(:CeYhW=g<\kRxN 2=h]jDb9uJ]NEG4e6U¦LFO̪i] e.u02l\-SZNBJDâQ“Tcw6:8:kajSO0f?rh fhMQ(?P:" )`V_8l vpDv ;Ws$當ĠRg&QPGWw-ɼ?e9m.AG8emU8(qaKqIp)K={D$"' HލA]ig銕BN0^hO!2v{yL%0)^ZɷsI蓗FiLvlN1AEF}2挵XR~Q<&CAL8iA=+6nFrD>W=͆c|yp7 ;N%rh}--@WT^u5EgmUuOrHkִu-zh·"ΓFrɘk a=mK r,RxY(0/F,6aIH"*O>*6PD^0']ed؄dcrP\<-'"-Oc,ɹ{|9r bG]8VCnZ:jfd` nb*hdfe.gx 2'Jw+Wn#< #+b3 d^yGJBjU)Jo(Su^H~rͺ:'Ƒ2!Zc5TFÏMbJC!CˌZ,ق)~L9m^"٤S)b,|P w!6'ex :rIs&&rbx!Jq%c~&ߥN9ŖN" Y!rsOAS ,tC%: ֑Qqhc0R=ʃ{:4۞ +ߦ/ V_2:帇n}1`tz9HD07cBFmdnBlr_9ϲ 6MHȍ5Kԝ_,S8zpL65Z .=!>=ü(pNgoN4#'ic jA"*{,Q7yy73D(Hkq w>GM?X9A7U/00ICwƗ{ ؼQ`3`[J楚BWKZL?2vT= =I:0`8J'λ%FĔUJ:t^(=ERȸK˻`YLCz@,}[ۻ%}zsy8q<=+(ފtY'&W#nF zY 14EDseup}<|ш.quC;U0>RUe2S@L6k2E5` (kun\ܨ Bە_@켆x-mpY؋]2Dp-vi.`"Cx|e+7UX1Ao V5A W?e.R9"L"!Dtr@n ԈY Mbb {>iQ3+)_hK蜩mdaب0ydorHf5Za. s_nzAUHԓqOХY2Ves!gxo1|eYT|3 ݋U9*T勵 @Y l?c"`.! 5D3#/\98LǶ =G2YV-YIVѤo1G GM ?U(כD*@6# Z ҕ bt;;~4Px+'ɌhrқIB 1ЈΏPb{L|TZ{Gzmlu6N2R/pt'W x,G%US(@׈Pk7ݽ>F[#%OfQ6njNFA&60r =lޥU fIJ*;4U4EÚ4[axHta~s?Z=K>>s{4=%Pmj*>,3P _Ebƻhuycohus{ek{Itў O5? =/^:{M:Qwދx4+qk}r0ሸ%!së*L87H"<w{dzD[kQUnJ0\T!q# LiiʔFYhVq|Aґ9 ! -~]_y\_-IoVbZoDHvbth^b%_SİSD=.1f1s-?xd~[ʳo4-3g[8Rqئbsx8Om1^fr C)kCӊZ,Sߐ J) )brtܲurV+k+8f#AlSSl1̢hw'"dL땑2ukT-k]W˛M}hȿ獡7Q Ǟۿ/¦:HzRPc QKhylw Dlsa<{݆Cc{(:4oF>|F<{_0PtqoO#~ D[xH"_V.2_iEǼ~swar )5]E*5gBح: μ&ARq֟?W6V|]| υLO€d?koo| _;IlL5 X}:""$P΀3P wEj*r Q (QmD]DFΔ@g'M`*S*AkodDB*q^EYs0Qm5!5xOm7kӣڏP *zΒP7iMRMvQo/7?>=4t7KEUDLY:#2.g8NÒm[Bj{ٶUzӫCVN[fc 0a$ʪ `sn3xԌЄoX|j,_.̧/ɅnLW7W|umssAgA/?!8K6>_X\ަ߅Bo50rs9ϳ4{>Xc/z&(;YΓJܦLkԊ= )i)>*m@j }˖Qb١WMLR ݲ/z¾ oYhۘ3"~1&,/0 tN1V>hl4%|KNw[xJzb}qH`pU<`hܱ ڤ}͊:6Wӫ!-zI41օauc'Ș+4ILޠro{(kDJVҶ8nUZHu*I=U^Б3^ E֜W;_ i:lqL| T9w{c=Tv0Tu Y8'1-8| οqaM8汨z=J(Qd$6?z>p2wSn*V@0yȪpYLdN%:?ܧ4V@@WMu0S9# =xfuOA }xZ@cLW+T/= HIz6'È'=fݱy C(K6sOqK]DҋC[G'xcIG݀b.d^{QӀWJ>rsXCUÍ40!wbr& ?EO<e{eV>Ύ!!ygEկBqtJX[CwL9} ETv{=g9[VHW/6.Hrqx p&g3R}B5n XR1 v5 Ku+?r?4dVE| l4.q}WB> 60b|NlV.^=Rd#u}G}ej9<Id짯0Ƒ( D4F9w6V2ror;%:.d%ŖKy]\Nӑo&ۥQ_ePJ{g`=eX ) jMnR|4^8E@3@2ELImն6>Fwggh"nاzӑe(II3oacZ1ĥt\>/"ns~aU;<*a? zݝq_n )|Yl:` a)ޒ7,;=Qt)v&,V3_UYݱ@ SwsH}RJc ((& Ԁ0:ֳxP50NRdjIUyʾ'9 %сaY0߮C#  E^F]%(S67 "͕kS75M&D͌.>9Ј&>889#7a _[jg-z|LaZ"s.= WLo6npRyiWf~G0힟:HOVlA]=zBvJ7O1a]=۫YUY<")Vr} }=5iZKG݋kdhn?=#%y0B/l&8D|G5J8λ4OuQ`_| *.RZaZ`(qn-9vqڔ GKL;='w&lǼ C&}Wy)Qt|iԇ:+}p/{42(5dsVǥM3%)8IjH2`hj+j3\©򜎏'P{NȶVu<{[ugi7g 6d Cny Ng6q[F ?7XR7<+á-.%6 3w\D6y.ώВzob)fSȎB3cd1RA9_`Ήf;ʒ|UQ,5GP0AIw:3%(+(7sqÖV!t[џBϠAFӡ\領(.CnhReg`i{\SD2\-0@NE53Y9EL\Qj22c S պb2Y3w5kvyw-mr`Ѧ=ty 뢡bף;\|mr8R q٤ ь멆(oκ r蘒j #seD`g. 3C'.Kеh_|2! NCfT[ OR+"M6^[B,meSs)thw!wF!CdJs#v:2 @)Ov7VVGNUDi3Et{̓TaUKz+gUF zFjE! \K 7h h?<~Fv`4Jx|arĺo9 -ʸSxnoi)dqҠ8uGG?4}l)ˬ&Q=S"Ggيny_m5wYa"vk}jw&Xdb4˚u/ uST 䂮ݭc67" s\OT%Uܡ {5/vLO6?Y"""߬ooGKp`]KGLnFɤ4.WI"{W16g- iom0MrqX5QEu% ̌gd'l˗\\>{ǟmng7oe3>m1secms O7w(*6/o 2l@qfd~y[_ު痷i-~9 |uZNvHsy5'c*pm V_ۂ;>/`^~}}\xC<{;`9ÏѣpFǦ@ }w Ǝ#f{q,4~G0(vX ;Uy'aku V\,\7/p7q7)i8H"w7;(Gphdi$&@'w3(U]N㫡'oi/>a~``gLJWMܲ=NykMT`qk D=WXcGgp vOm)rڠU0/8 j.M#Nl&p"4O6zB > | Gn?p裃 Sw2G Vm]mwYd\CG_(0َ\Y`ey ú}U;B0㫷V1yz?=# _[?ƹZM#:mTFWѣ 3?TM[[Z\w)V7᡻ ;,W:<>7fM{mm'8BoW֢o|]$r>~:Xi4nc0d<pSň#sZx'L7t1N@8c8T5" !ԖVS #ģʹIQ;E})Y.@q=OGk2n}떟_#{ѠO{L=3)fV҂&pzgYp<L:2pqI1zaWuA; a;:ujoY'օ1Z+2wjt=iw%8ӯWM;0C谵lIW&6s<CQz &RCW}F!tc^rXUeM!=`7 `|~Z-. 'X@$~5'cQQH4(4hB:1D #ʄ2``= = ynmV^&^fwQfV^ҧXqB{)?`ӡ`&?HnN>3V78[[kό%tƖodo]h~ohwC/֒νa|yy2t+=g(W]muWS*PV]EUAա|唅FOh+ l6Кg'i$f5DO 1O"J [_[XSr?AnnOwY.x/p>Ο5;`_[E,? AϚF++kkkO_5( `Ft7\\PYw2cL~y0g;:ގe ˜{_)d :YWW7]|߂[wS6uo\^C[M_( SBy进*nXwg?SBw7gA.;`&+[ g8S?fld.gq/ZK8ik$,  gvO EO667O,迻, ZpA .,r}s߷;<~X~ 6n C[O<[mh?t4w7v{W; zZ}lMnoFitX @^{?Og*AN4wR`yH8n_FT$ß匭66ù#:H#Ia .!V-Q>g;ԳjO7A'UaЅG?px}"QfiPDkni<cs×n-;, oM^1.V pqwaoL>ކ˗!Ti( snxE2so!z8@ Ӥ M=j5y < 0 Y;//ݱd߆襒ؼc'6ɻ±xW7Joґd}Oz1<] I'M/8cw8w{wtt)1"NȒL{y;4)yzw"Gk|e7A;ÿ/jVNԏlEʼ&"*:|z::71'q 9:eW2KJƮrwTv &$E(MMGr]Hw89{KZP`i@~DW_Sd*87bF A?x %.1}ЁۅIhEЍ;tp"iWfU,L?3oN>;_E;, ^p 722lÃ@v_w,w;NRj7*Ti }u5 5+5ڎ ̨D2C/gLJWM$_$^~@e_?CǒD>:|JmMPt|IpU\.͐#k8ɉLEBXB7܋ u臏r+A晍1\{"$t0s]mwh8?2F^W Հ:+$a.\vxg3>\[xhg]IUwga6&qwn-?g-w@zgX9ǝ| 7Kq(X'R07U?WWgR{^Y%:y>%׏[B̲y;OK{Q(0g$N>Wյͭ}}A'D?Z~LJ&@s@_ xN40!C`Fe.=ln㯖@%E34ӳ!>~O;=1;HM>MfH+aۖ`_7_59뀪 ~0LYk,NQguN9 $c*Cc!MMX3Q31G3Q3e‡21G2&&LL%K죗胗cCK%%%%r9f;b9`{p%J,|Ho&DVbUG*qJÔ裔AJ1]cPn|XVӭÏ_ڟ\oIwP$/;@p)7?˴=z%XvEѳgZ>/6k#A۬m)[| >d 5cd%{'>;n1l|4eboe&$4ՆG0w@ᱭV su#lsJږ뎼q 9hj=cV0)5@MgTW΃O*`\B94 vŔl)'_O6rN>q/o'۫po|h!2X&<˄#R%OXt%OǶ%OXtȒ,y:ʬNBrHioaOG[t\K'{T GZo36kYtOXtO~:b1V?cV?鈵VOǘt\ӟe#Eufu!8pm {vIpSc q;)m~)K\G>k fa :?ǏGbbkwk}LV׶6=ڂOAG7$P$P$Pۑˆ@}xe mmonXr!I%2Cz̟8ϼL  bBc \gȽHs˟{JM[qs$AgZ?M! sosOyBkwow&PQU*tу={+ Wq` R7՝ 9ݓ_h?gpe q\Aάxf ,+[O(=ZbǼYKbl^H,j?4ܪHw{g?*/vJ:U@~śju/oto˖ZnY]@)_ji/K[TO)7IVWt7x9ţ.r}YCFZ+NJ&GF hi=x_1TftY_pƣo/YiN 6w'pQ4_ g搒H?ĘPɌ a 9ʺWuNGwPb4=KRfljɭEĠ;L +W>8:8^:jY#Zr]"cvrKЁ~.܈ ۯ9)+>KPqp ŔѓnG?z(6w;"*?]oܟS֦$Gf ]3^KK&.J:Xϩ*_Rs_+\SmF}"}>Q5Nj-QiLEr,W;Տ#5˺*՜2tY=²T@N^Zv/m )|׏(;¥${F Tc{(J:"Lri0WؑW8FHbn`ST@u~9 2;@;i?tnґE L Y-HO#wQ)I-=/FGo빦_9ejӸS~76hW~CXJg#Sk-6GS`傫c BXKI]$ rDHEZ,Qy m\`4lF@,3 [Pw?0g.:Ӱԡ\a%t 3}'Fv=-;;MjSgiT8p[vviA08>h-z@Wm{~_#JLN>{QEr;AJ}фy5J.hUޚajxāDCENh"͞fdm;}\m lrUB!ȺqLī_2lĀp M9w(bqjA2#" (^wzZx ^QW]giIKI4 ʳh&:ʪ}Y xKD>H!{:XETS qfV-o1 (]NԭWy7*}=FD>:shKL Tc脂B֑i(,\a`f5,|HaMz:i<$Bnox3 W 79l0;iEA!njYRudH-z"@5'mK#`o -+444C ,#8d6 %߇9E4`9{wn(K$ڿ9D&Ouѵֈ[ f=Ki.j`dAU[/۲ՙYB iaa9^D4x Hh9[@`; IM:R!%ADDpO(=,~;=0۶N З(8H\WfɳeʣʎB;̓< =N;i 1,E8䴗WllvZdn&Sp'IETS4n/55JA$KV42E) Dx2s3g'oxc„/wOŧMŃ#+B >ifHŇ3BUz m$wN.*0#f 2f2tҫeeKX0Sn[v$:yid{e~5>S2^3i>[|_gBFJVfNaKktpa("wa*\C_ы4 JEQ۩¬!<0lUwL&雽)r'W#'Yqj7-qdV#3+ s# }" pi;䭫S7•J4ux*NX6k zGZ%uo~#)8YS8ٚ ؉qK%ivə0恰%C|QMq%V,l@=ybyRbzѝn  'Ӎh1Ĥme(TٙW*Ht"m@-_=23K P&:H̸3'gRwNF@dX!2,#)Tlj8.K2uarJ0%4`V < Xy\%4nAIF6|,%xFV(+g#EcLf7^hhy.2x9]̰p0b(ߊZEp>U@|۬0<5lԊI-9@ L `$ˆ&!=Hو#&yYJۆ$.e 60U:CǑs7J/d* r4`RwrQBq첗*NxGŜ(J.8%Eި,>u=NWBd tE&K| +rK4 RC;س0ls{툍 J%bM{+3ŧ𷬙W!gɴX7[߶g{)!+zUe(*WͭMQ}Z/{R2阏I.g!*~ݿ-Ȝ3$k&Z0OXXLAA|(><t-u$;HPH&7oK)"=L؀N Cq"Qw;%3Ny3i›r.(=@o)r(R3g'pWg;?3=0N#.|>^ʰQ$V>ͲgXӨB[i|{ֈHQ1 TtV$>UmR{3 )bt"­4BRg09*#-.mt,*DE*Bma(y|E&'EKmqQf8] 8KzrHBGN=,QS xNHHK="ߞE" ,#MJL-p') |U7oe _݋6V$ߘ3}?ᨂ8|.7[yi&ƒq: \}m)}=};*(/1'N)82tDFlK"1E34#DO ׽eO0/}fS]J fN [/&Sk< _+,r#jnxr,.""PR`)3pVJi|n n'$1B薊oҊ>N3j{3rVQ^g@kb@sF 6M~|+N2T*G!y[WyZ>%qu>qRZR`WRۆm! ZvlQ Qx?/4TifIO%wȝ"NTs$Ps|@ĺg(Ky@r6ȻZJ|fyW)p;E8F'Nvg]Ѽ .۹9ڷwY!;t)#&e-/;3WB^joFʙEUkꎝMI, ϕVIfLu%|>:1pxfrGX&%(_ƴfǀƝAjv noa,EdM3#zTRv(}f!|AіOqCÍT)UUpYWTe2sE(g~,r0èTbor`T/Ǎq3U ؚ!L$5N@v5|oH ZOAs`zdUZp:My JRgXP Ev@Gģd82ӣep]B9ızf˦Un8NHQ i\؃jtq5¾FCq}٨w"d~vܿDͤ]_so8^`a>hJp0↓WLaorcH hN=ublk!oYzU1{>ʱS2x @/;aIhՖ أc¤f}`Z:G 9](%.(`K2*f-\ N?4@(63@[.xLcL+an:h)flbvGmA4hp˸liN{oW# iqJoo/ҕx ~;թlKY<ɰN`c|}^" Yc!O|̂{Ҵbs ;%ॉuɶtbo?8 $"K`FgiapB䲻d0X)KɤaҍVeVB&5GxvAJN?ͣp:e͘w{7DLJ [ox(˥Zd|Kp3«̄/ٞ#̢I^1 ݊Yz Mh6{>&6J*k,v7dcV`\Kl/fAiX]_VX][_ȸ 3 (-áv@-iY'In[*zش3mX/%;F(XJ}:\+g \7NOP~l9Lf,%eAYBn--76!de!:-)Cd ;>?%5;yD!!L a3H-8@EA'0f ϝo}EI\;tRB"g& 2e7$E}u?}?q4/ȝ;KyPr2H  &#E2QQ è٠OٴCɥ~0 ]K0(]K*z-Gߋ ]vFNDT!vt02M=OcR 72aNѕ!=+&Ecwɣ~>{i?Egvkf0}&iC|$qFE]9M6b.":,/>˲C 94+I9Ӌ ,=ZN}^74CbA<CC TW5?oj4;n c:h K3=`RЩCT#ab5,M^uTh8JaqYFZ4`ԣ@WZPʺܖ*Ttūv~swJ* vQ7ԟnju~"/xѕpԌ|AHx\>PxV<.vEGEd/@ q*KP x,sR9jT19b}X9@(# i069hBL|DNV{I#4!^"}5Tk^a%$ H@ Rqkj9FI.p1.Nͩ|}(j Pt9V:A{qҏR'*Jх0<%ɗ̆iU10NjUI*`AY9;sv Ьl( * +)뇏Vj41-lPyj+`ÇKA)#ݸU[5'\WPnRjɢ yEcAn悚Gӗ2 lOњ|Oz| S]VAouYD0Łᴟ]0,M`u.ǭf l P,J-E(Jc^ACr'&I9 0%Q-y[o܆lDz 1`Ei]|~Qnr{"ջMR1)"kP6*Òuݣ%Pc;of~@Dm)TA|Q,k$o(S8K>b`0YL!;x6v|*BrA@vUFH K`:AtUCQX(^TXLBJUB b%wpc1k漬HEte焫P Pz<Ư|&QdD4Q1 #)`ƾY'#X9 ؆FaNLҦPEswV QdG'!0ϓhhty!7. l$sR 6DOb&VXQ[ ?cƚ[A$O'3 zkrt>TZd>?yP@.k-xL[I=PZ{y۵"_~N6iL<'P[{"q+.c̊$UL(ݤ%d !vMA)waMm]X9V採˯&@'e}6b(LVgl*GK ;1(t ';6QpvAi҆]ggmk U')@йʘa,/2'A/̚}"f|BK a!oBjفr /6uSmvIE(5 âYsC5Mچ:P6,BQT;MdHL ao^>1"E6ݑh+e@T1'Z5h~5|[[qۘɸ5xBٱP-O'GG٩^eQ_\úByX16_ͽa~4-{e{ F@U'|OdFj-'8Y_ ׵:Ex$vPNq(^Vx|0ಛpM%fXN#W7 /q+:DW< L?f{)i%6%]#UIϞE]25w$C'uO92 Rzfŧҕxj _Y>~ѷ,?u\|nlmWr(L06 %}Ŕ<_F'{g`s˃#1PvG*:1hF/Ktw ;k`KG#B{GpA@;P,}k?}{vz N_Oio(5X {ڀMX.wvp|).wͣ&u }s*u){ 86&7NXW6VqA&>~}uJ-חG&m1\r~7c93Y_OݞײBNY|caqA 0:D}Vja@[(6 S+NsEnxIݸWs[yb9& /iԡ&e+;%0єNQ,J=i0z Es[(PD;6MLw9ތj=+^dTHlT'?g|==|dDSGs9^`PmWw0"NeJ$&ZOkoy,1QXΕ+h{Nn޵8zG#,hq3LRuycxklCʍ9+9\`(s[=kTr)Jo\6o5;aME=c4g)`EKH,tK[x**6KIK0#V%(ANCп@ ףNLXXԥ/9'8xB[Y FI(7ETZ/DdڡaWK2m0~nXp\TC+_W~P<}*JYeW>P>uR#*HX1rE`L$@s_l>t$lX4+? ^0{Dx_aJi=,p)F_HZ~EX|2U&d~mD}n|E+nODaCV_v^::r{ +px;~m\632 LXNG! D^=[}u 1hDUB#0jA~Ai3q[ HynzЗV}zז˒]eŽ3r{gȫ8jxtpE!?zk} UlKhuIǍWhR_^nߢt-4c^E6T%"ꤝzx:Nce6O#{rЈg"Uߣյo|c Mp4H@2Ͳ#٣!N13+frWz@QBޜd #P=$ Jl;%"̙+ovbӭV7e&]}~-'4-jf讱a󘷏ײG11*v9T9_@R"sxyrP%d  !Bd3o*n08z6ElX);#ΏlN3{׈4[@C@c 3((+(썷bgV!Z,zcfCS0M*daB\D\zv9PaWXVW_lFɉ HY~U%"6hL(C`'&GHͰ+8Y4"ɵ3PDćq-&UUrR e{qQqL jA Fc~4sD$0&$h"Zi-wb=I~q(ar&&A|Ğ;`8+,A6nk^Hʃg@T0*O 8VW.hίU}CmA(y_j C7%"PupS_dx-m7dZHjYڋqmt㇚@ĉ6%(pR%^Y% a V;hif2AE((R1QkD{0GL|qbdF2*\$FĆ, j51ѯbdYsn8bՑhƌLF3z*pnj";reyg>+%d~OPPPNovZ|H'\vO%K 7]d Eȶy;(}LI> i+\3Js,Njd̐‰/YK% I-ϱs s $P!bGT,?lXЍƂӋ@j/[Q|%%>;I&" h,~Z`jGeQn.uYG씑=.)O ؕ$X.TᨛB8qȠēc쓂ҫen n^ᜥ2j܁ 75+g}lH fT9Lɞ{̽:3 1hss9r0YʁS,m,Q,M1Pъ|і?!kk|9 8ϛJ˻E,|,feCD_ JP|. e:6j7]kge =45̼2m6F.iq}*4t^d(EO{\̖kKY*VtActI>Ǟl+_z;"S-v,vfXdjg $ؾape8)Ug|,9ޱqJ|Ev Y.劒i"ZjڛW&f8+!ЎucKu>eY 36SG#CI9JMT@E|RU}KX cTB* Ǭ4+*+_֌" C [z^֤(uh̬ 8b.g-.ݽ," =rȶ%P {)ATbHH$t~ly 6}sOx]{уSaS&5ij"ex@Ղ"3ȴ2dⰬb?T&{i,9#▌ rQ_e$*Zw&U [ppk2Rr8$S([؎d-S؍/)| zVH"o}<4ӍÍۃEv͕V:s /WȆ[?0|ELpK1111T`/)sKqqUz.DdF`i?aPt@4K4jOi=Q3`GV(sc# us6OGӏbv ^9|@ Q~_pPd;)>>Do~j:m| \sQ7Bxw{C _]؂7$)zIxWi6C|df^7]_p 1LOk4P>\}w \G81?G1P}wc0k,q?߇AXtk^<5ZɏE/3\[V̏*T<\C/g{ߗKg#?_r Vgᆶd` [Hf dK/2kJmp|B[Vv8 ަ}-7a/K ^FH$tŁS̪'D^D+P|htb(>ޅ 5ڙȻq /'~Ìoy_tƒWo^Ƭ[P2Vo6VVz5~4 QVb ~C-{yO-PEWFR(tѕ2!c t}ڠsm D}oU9Ŵ<8~Se}*l仃#gT*zylΚ@e; kÐtQ`7`s6!g*vZݲGPVj;8ͳhn5{]$0>Qv^U`?uj zAhRL , i5a=~b>xGWa. NLݯ69iIqG|E2qnj[/,gΝKFٮ>d D?*~fQzA%20M`4@S>?š-I|k4BD0yM{" 5~u9 }(vLɢjъ2`Tg]@>h"ȧDzeIjhCDz(f~-tP;\߯·T#0ǻTi`:@q`Ⱥ9f_F-8C + H+XHU'gG(Ax$׊ALDi?ʶXǟ׉; \G%uRP9XEyd3qfvZE) vcEY-uB]͓nJ,@uzbY709E}d)DsgjULΐ[Z..&qNzYbl\+F‘XL_{y9w9oѹcWwRv 8LK[w4ޗ'p 2b#ŽE/J-Eq̜}Ne6a!'y˿ۘVeH:\oX <Ж)X_K§̆Rt4*[vK [DIxaP.9Ey R4[7X4X4u*)',ӜK2e;YC&g`M>PO8_L) ueǽ)Ah=I{X 2#Ef/'Ɯp&q'P1OϴYGr;Ԣ-]O:4QUQ(r]q]K.>1;`idF˱ؔ[(w?_ ;Q>r,e66X= B;u7R7L}L?}~ uxwFK%u>k ikTr"5p|HƧ/3Z Nlq8 WEFD7r vd\3ڱ˒~B2>Sgo q`|!#.\SO ep`6ڗ8 ? v,򮎇ҁW@_ZjMsxypؤi c1jv(zK/Iy‡p ƭ_?x -3µU v a6Xu <lYs3.)kxu>Sϻ&uü^l2װMzMLoU"!A+S@g@"=xlDT8+jD'79XMx,|pG]_+^3ݫ5an~q. 1Y2Q -8myv}EfL!lA(]~DI2?2)b#)EA$XLpydSW~szq~!s_T]xCFӦeWa+VBEѨg(6Z(V8~uRBf[rєSу~sWϯ`9vQ{n4T~ӳݓݳ9>jXz8Znwk׷ΞfpL;&[I9C "Klrf!\uߡ< ֲ {g?S2ɽpNY W\D T,S)QDLQm,!#DF#y@2ԓx-#diu1űEc8"'-i waPBV_xm=[enZp _z20[1k%y K;E3& .]?0!3x  Ek0􀋡mB.T;O'D u4162J kYvȑ}#;|HNҳ1U- A!^hQ{̄ UTԚռklA*_AՃ)0d yh  ~D`rkݣ3jfg"7!3eڜޜ)lo}Z橌pz{vzf [ ڕ+irF*WepP^ٛ#tէTn3@MLL.Ƌl2L J4OZ΁vr cɁxN x \;,毤6PT+G5~}pC !=P2.jָ5KNX`IJ2sVi`8uEK?hD" iD8_8ϬV Ys!Uܜs&Cn SBKT+5G9HvZ|]'C6̲w@Žx]mg vKashf+V͗Y;vpmd.Gu;iq_K‘6"oξol5bV~?9uffN&.Tvȋ^Г0GqOL.BNeWl$C=t>l{W%_9iK5w?롒4g#_`ޙ7@g/3ʗ':JHG#[ 8[jwcmqw{QJڃۗxn`->ZCa'hmu{s:uਆ JrSG\hi4˜,ړ8p @~'z@+-ӏ{ _8f0T.j؊-//98kVemo˻4@@]R$Q!K5|Ј \޽u,I %. ݳw'0‹] o^9l eՒ1qa#k9P#,hj` 2vKGYȒA41;aGYoXa0sonfT؏[K8ȁ* ݮRǽָ ~5G߁8SYI4X_ѥqVtQД^\t.2aYrg%,dL̀ϧ):J7c`"\}$;& Tb%2`싳~U#s Dkq]F6$Ҝx[ քV:-ϕ'hcFnf[, Z?=**5ڷ ^ۭᵭU 78Օo65V7} 2Z_`gnZ־]݀E߬&kumo֓'P7:\Y__Il=Y]Vlmo°őVz -\,5>J\! Q;A'4\GLr^l\)"nU%؝)3#i\|.ue7D(\ȍ(}YyG]wf@9xח#۞݇7ɺ>_}C.Top0r'=BZ0_bcNUҤ{m ÀkTq(oDKvd{LKbvB7 iψtJ$MzAznH=;ccHʍhRYgg"8d _nWMXf.7.kI&p}6tCQI8⯗~éupꙹT6HhbŌY5(p/0IgLdPޅV 16;֚2֊ywb[%Th.0/lNG 2ɖ>4Cf=*Ѷ XKHmL~ LL-V5vjH=i|ѽŠWR 5̡ monĥr+Bbf1#  }^&.]ҏŋy6m=FcuX((i ֡cBcsXlyzvr˫7g͟_Pmӑ /*W򰐾 MmUN@si-L]œ{2Ѣ![t+W Z@ -oݺ0bP/|}ӱ4e޳~n*v ål":;Ir9'@=PJ_*YWW>\ Έĩ0.<4S: ̽lmJZQ9" Ő EBJF;~7!՚CɘG TEivzȜsn#A'Pl[\ >y@Β@٩|s51侱;G;&тDݬ깜dT-Q?M+:,'L z R,HH#XFm~w/D~o[0rے(,SI_vP.m7akLkp_@"'/kߚSIO)\nEzw )`49S,UXH`-<2}JJ"  _67ğjI)@xU)Cah47%6Nݗ9iu8u rP460CmGn}Y2?B^QR /9ZӋQ(IffE$[- X-N xE( ewvh?wL]G ` s8l@ѝSybLbbbht59| uL%AKMMva_g`yRpdɇcɽyNEb$#_F2:NҜF#GBj_v(*\׆ c6<T(b%tlNywa7cOPczB B9 2_;d\wt̖ћ_Hb[d%"!>- #b\ʑf)Gd{>CQt{>S*ÃZ 8WS%z1۹^@ÂL/B!]nܫt ?cseY7"UNuTw('> i]eGDZӠi CW::4-:s٫Vz;VgU..0<& ךX^;ICI^D.W$31ːj$ΫCBU6iLbXkO#\Bnׅ}05ԂC,u;*G⌁ߩk8-FޜI]ٱ 6n.@X0,?8]O26 䐘F U7ݨu0rB8-yZщ{-&9XUid4P ˱q9~K6\xU檒7Z8l4 2X8mL}f!C?ZnxFyF΂҄+!ˎE>}"(־npcb ڤȗ 50Kw! 8 /X4Am v@&dա ΨXX 4'~&CP#ftБ}~@kB!-nYz`( Tpk,=H5'p^PQ?RYn*K44~͏LsxYSC>UzŠ2 r%d1˞S=FES+zgYW^rE:;>*4wԬwN*)*$.T<y LIB?jy{7Gx?@iJ#|(.B&~EԈ_Iֻ>^M0ʹi* zluiGr Rgဗo([}koVuߚ9}+[ u+@=f_Ke.q7VM8ai;pI#7Tl.%o+"ϜD4Wk$Ѕs'/{_+Z%`T_߲泤 L-A )CmeRErV 4T A]d%"?>}յB` Zݝ[3/w3IjĂ|c5˄:=8t(MImsD_/Aض4ud*nZF8"{6Zj-9,ƾbӣNbx;VTz*}$Y|< -9y}:cpc~#ǚ4R06|`M72x3 p1Qgyqg Hcaw5~3R&#zlN# zќ :[weqJX ElލYt NF'M*rr|)fɅQTt ,P8N3+ږff}ȏ58@ͱVsDN?ɰ-/K4"KhgM -cqm`i둨MK* F VeH,}$7dZ3M99V]: }Kk:̙//>"x ]\DH>#jڔcU55 cFС^K}L҇Tq^eY_3ۈ״>}O8}H"AAovZ gET6q@>XR|9YLVWe-ŎЖi-2c"xNAD VD$Lbc=_i%7 Q4265//l(|2A1;)) G# 4u/ņJX$= e'n(L5v'7e9d$ϐ:wIP2 _4vML=FT\iX x'0%?ˆ;t 'Y(AK9!|D#?tJGlV]ram| *G2c̭Cu$`-^^%d2_xiͅQ..Mde_A"'EȄ$ T'7-^glMe* BH]tAdL-<,7r655z:pTFA:?~S]a : goa;Bo 6o ΦR6l(ɮjyiGSA(tlW$U*\o+(f%u8 q0b{qU6E)k)dhRغqsVC@^54׬\ ;nsߪF I/_ORs(QS255r:f|S\ e'Zcj]M &NpjZ (br*ѕOC! ϑY5\Pq0V˥^jj8~z_'SW x`B:n]͊'w*in%a͖Y+11o#~3g ƦEXDyG"Wuu&νȒN(f[MKk]I{?lTƾt}(ӚDS96=|Ә1aя:"6fyanJKR'izس4ӗ:ZUw,c0.:gbϛ8L]gcwWvC\GY#PM~3]+8^z]xX<>z <ɤE10Q[D0aޡ8xP`-e+w~:' 2uOmz~LGT"pRv;RfOY[t{gV EF#ڪu1 xRא)&HDLg#7 JSw.ǕsppE?sl40+V/ֱZ05Ҟ)^9߸qdܫfPIP U~#E:ÝJàٔhjDpyp,-`1?ԆtC״97U9OiS 劃=A7t-=!U MnX#mȍ3{0[-8I\"<=$n1T; J![TtU`'=04tt"NPƚWy˔Òw\Um 0߹oToYUsIL븹ЊI(Nųe .v(#y`z#ZQaoU# <DbuNYcrTT  s*. /Dd^2U 2jӈZ 򔒥0kq1n -@#\ُpaTw;">'A:\Dpfm2xQ7m[e>x *JnGd7,aWIB+i,&-eIkOh-z(`BSmCSxIQ`%r[Dg9veꀅ$ YLmD`>B&λ\һF/ABhG(ؒyِl)1߈!D;\ My}r^O#]붣ƅ[82wjx62TJ+w-< v1Qq8"tqDgXEmfwr( յS|TcrP_Wqqצ* Ƴ ^xXyOeR ZЫ+('rO'K-{%rj̆۔y$ã6Gc6U8Iq[PYxb h I'SUk ptsp 6<>%QcUt/&cd5 MNmcDYtdG{N^BۘvU':|;1UqnfW}Ǖ #,^xXGb/GJ>{&/  Pi~ Tk vӳݓݳ9>B%4y|y6xN\UD f.2Nμuc9}d LIFiu$8W6E5dKTg;Ku @$3ƭ d Q^2⍄c#cI'_b Be+Xl[T] >bCwmcqAbsw6| r8 kH>Rx%"MS0Yv]rX({>-v-Ah# Nj+1AkmENfɗX :4)g&jcu[)w n˶P4NV(+$r/8E ͈[ƜZwIY^2>.ˈ ! `"_R4L%`v[LeΌ9{2^ J?QstEΪ)G^Xr&-ʭ2 T mq,ϙYgZKg\II BFt@hR>X$8& -ޜ6My֫p(tf^+bH,ٺv{{G(OD@` ،m&-m $ԒgZUn dDHuU}JH=ʇHDN0mr i/khd `AiR܆dAZ*MBELE/KY¦~9)X\FO:CiREAE%?[}j7Jq3{/4CN.h0;08S v #H *DzZvHwbcE)a3،y(|%R:^:ȹ/@FCzqq4ebWh`! [ ht06l T6!sҧ 3 2cP7ZѕE H󑭍)TƌX1$@IQM4A,(,4$k`Al a(d6o`A. -`l0fͳCrTȰS ѣ@V Ca/oPP"~ȨREB_*%g Я6h\ƖJ\ijKd)܌ pԶ9j<@#'X7d0S0@BJ$-g9,9|p`1fxlLxa#PPStB>獅K:ӛGy> &\nHI\`"F 'ՠ/h5 Tf "+E [D益ɫZm_ J,?0ELJZΓ8HQh q~xne>aNvM~Kf˅a@\蛧2tiMIjr#R[Q^ԔS!؅oKu&gQwqGkCʞeTK&Z5dz}ͅSݮyyV|i Zr; rxPr TݎQk6-q>ߤU7q;ܸժw7ifk_k7w^U`HS~qeU"c,g &%Oo"U{16]-lV PqEZ\|f@\&RZ>DF \"@\;0s{2%H{ޛQBTlMIQ(yhxJ$>ʽ~xoe5aD ԗdr(j,IPz;,L,(+D)NPlz|Ax'OZА"G[~ F] EHQ=zy\ȀGԏܞd$ov @!R2NXqgmj}7}3;\$-J@|E ηX<jWŢ(^e+rVHH>">˾Hn Yzx?$ON5mv"reԽ^h~EN==4hDDK|,|]BrUg3mM~d 1 JE,nQ*[-nUM/n6 7],n:&~\kiOT/ g? =4]AY09pZm= cw&p[q5qQAUd6W@q+ͧ&^+^-3Z|d]x !~M`77)ksL`^Mr١LQj%t%mI RCLqJuU1r||I>#{OШO"6-/l`jcS_paD&I}g]TdݾҁWeEZ?GU __[@qT/:!"G~dݐ.34rkvh[-9BP1У{HUe1-Eedx,;4ьKxqlQ4jB(~oz ISA#^5OY&[kŅA**Qyq-|^%j*DĎR'q͐vH*|*xS5̭00+06Q59[=]ApKilKfv_H<!)^! >a0Ȫ**R",Pܿ1_^@y8:댚D`#PF`);TxHoiFDϖn ; R}Y}ߧ3`iޯ/qM/Ճ,Z0TgeI͋ReTVtY D5Z(,Q]_L]hm5σ(jnTUuY"7n7o<<.J›U Tz-P# ^!yi ŏߨUًN[~rDIo Zڗ}Z5 RF1'6AdV?*cDLcm3ކ~nm3y^Dnx,]]O,.@+^*g(BznDy,Z(~$7 ]-Esus ø*(ƒqU,FqqS +vQS%<%'B~qԀmZ0MA H??9Lg'M 0.w0fӜIWPfkZ+TFE6ƌ%5[19}a zɧg|=*y$#Qo)޳*2Igd!E S$$ˇ31wjdCiNQ·o.'Cyk!`D9x,AqԔI{eգ ՅE$X&̐8%W*;SKΑt^S(zjD\W֔nԠ+WQHVm?s= mM"; &f kw駗/ϲo SJzQpU}L`>q> 8:a)$_?.`8\8362Vx9{c<-w#6u.! ZA.ls]FFV( A< oH&_ ,2' kp@e`cI+7 tMɹ\mPR  )WUk%'o9>࿁41l޻&PILY0(:]0K Nfeص5p1ԡ%2lv/Y?ЮEG1?دp+sǨ(gf"0uVhwPzAqF]%7EQc)`mn/ m&5:Mu9dnijr วMWGR Zذsr7ތJKkg V:|SU`{!R_cLP(W"7 º*Ta]G |Oi_bۣ]%ϝ, tan>}*Y6P(S&iFxlO;c/~a] ܟ Tc1^Y+dy?\r{yp-^&GfV&QN wvdƳ&^Q8/ !M gh|񃴺aÕ{plnpS?܃}E !jwHO"d~*^n E!xxqa8(8>T 6j7 2m -8DaM:X-S;퇍igޱH_lۮd3Z~:88UXA  tLQa|nV͏w@':OӚj}aNL>Rڗ Y;+SXl\i{?Uho. ڛ XUswn'1vj0\-7|H`l?#E3*$]0$p;c{̠a-i~1BȻ.aOR$Cxsެ槙4` h`Dt)̍o0n`$gd:"ՕjѾ/{&dE-F7DvW jr/+Y [TT+FU>dl-T"qK[OPE Rj8cKY1 0^;p Ex•4`դDpZ6>2[6uWHl@b'ʡaP-k  ]@1 Kx PΩ#ȟޡ[ vb =4ٯzN";KB{b;ޥNMZR?pDc (2Iq+bK:Wca603(T- BkVW4ڔk:='?;$yVXi&znsJf$r\ ,&-jMElCYUa9B}6 % [$L|Rv!_yk`qǒ+CaV$<f<) U`|ٴbjf!l fՋnHWCفI0UK,is:k%W"0p>,[(zSe&6AcA:#9q-QC8GfL+Txi(~ gע^eQ\d;_C2 R^|UZo9eZNq`ow{N I@l4AG #rnïgdrEq-t(d<5'慟wT5/fEϔWH!xeskiM0|:1(5JD y&)]5+P61 SH,V0t=;󃲘Z<tX*4ѐ5\FUJd5CK X0{,X)PqDVy ٴxǜB|PL!{u7x1G l::U0dA2Zd[3תw|,4{Kc0YtëҷgJIS JXW`݉_3M(]t:,t @?']\v2"kmN0tH$2~k#na/N،}콱`VHl?ǀ_u WKTgr N ! {3%V!d)G6 =nN>9QŠ2髮ua, ß|I#@e4Ă[FNl6l1$v*143, >$^y2e-^X x3 dUw`)TX\>ZIY[qͨfUY6,~6D/MWN B)ck'& \vSԹᵃ`ggYYoS %@ڡH#pD :Y`/_l$$kie["IsG:A"Yn%GHGպKPN- iU: e^0Rwjғ=܀d~3,^$^n.p'P u ;GG B/#sי܅24@”J;|? ws afGEem빚1||-ëAg;&@fΠP 4e$31%.Ri$i e-(.[Hc17!;EGݤ$$8!ωd=췢XJ?D?`)kI=Ŭ+l].1$-H3дRҧN g#"::dwHgۢk~B3Q o jM27D{en;&#>s4A1xx4OZҜN`&I]twQ~6k; zďe ћ85EW!}^5mnj h\1g̡~:j?^U1J Kub.M"(#4S\doq>Y)t$4Z3gV 'k!ATM@Di4A XsKΣ|G2W!6\1YcF-V=:K#G|rZ( SDT$G4fD Osl 10wm+ͯ|&Og{UAbu±Yb.e!'#`:HW4?n*maˡKIXCԔD]KDmrj,DX%=##qBߍY6#2a+>)e$<8+<PB)=[ VjO[s +ʯ%^5OBeps|I,d(xP[q? RC2-m$OIl hb Ye+ulLn*j{ Š5p t1=H\ 480Golܡdz(vOKkxG>9x4ZՐ,ɠEj/XM!1|Zpj9E:P䰅xvnbϨd,z=֩n֪bJ( d6 W,?^wMN%CS n 3:ݟFE& k2O˂#bspG)x=B6 '0yyiY+e-tͲE8$D/,qJXek  )3/%3;1R-a _tc ;dLu5vv5 5P]Tר.(ơv(jEv(q|TjZ,&[Shzj@,vegn_xF${nX\]Mwdv[b\/LȤ/@Y.\fg--Ӧ]SNm$73)Kcuti@c9#p]5YD%W0đPJaޫ9L-\G'>5(If>{bϭFG 2",o~4Ȧ5kzaE+ର`oou?G;Ȟg"ܗv6c$2/s?Ί;#!$6gzWΞ9n5>d=נW̒}gQNFcɬG ;l%!E{a R}/>Pz{я7*a*@~/7]-Zmr}U0`oeI{Z0i}R%TGDLy>{.QJ &K_ HBt"zA+%$a)gMSQ<L`[qXmRp&4(#_ +,182@*-}rGVAk6ώ•3Mx=p|'Š0@QfH_4XWUb櫞9*C)7^S맅[Kɩ _t+T9e;aѸ_h .T /2[5[\Bal#gȧhvEVIMW9 &cPQ̮؎6@^pE^@y뻇څt'vH&}ӕrJdd@Gk~~$m (!c`x2A)uqw\b쐪ih&Z?oi{"p8Y2-]>Wq%fb{ Mƃ3' /4֐G\'y>A{P΀v.A8ͷ$t-+w!{֐7[n_6ݾVŎ0iÂG.S1ʞzm|Oc?,ϕRrul5]nf9{^* nK+Q怉93*ʱZJ w9$`Q<( N*.%F4$GB3y;Ƨ`G?>/ŷ Zt]e1+uf f unߠ[(b@;HMPN9-鳪 旗kHK#Ϸw_>~{9*cTo<&HG"k4:/0~j#1VaIjM%+0 g $6$6mZ` DzCTN iѶAQIWX(sF* B0tQ:J h%8u |V,F vB9MMl`V aƫڠWL&jBhu{h'pYѸ 8WG\#i`z@c4r$N4 BY-{Y釣d1S_tB )\Fw k#.{zKs[z4kB)Rqy"e20g}W Ɗ8F_VoEJY;yl=-$ k25ɩbc-v>58 ᗗ#f[^a7ެM2.KQL .qpQ6d'fB*QŘPjoHb)j(%wxC``jX VG@+B%*2#ΉR;A聓"346X Va @j9TsA߰tjxFE CXYpJG@+=߷SXNF,ۍhH? p˝ [,;'2.}o˯fٽ)a*W1Z74>i]ee)gSl:8/dtPu _5nꂱr$vV:.*0s^åi$#]A{rj0xJԸ>Y^!:;F}$XhNjojZ:8:wFeaWN}3&B2ϧ*P yl{2w5aOyoOX OQ~4T\(8A#%ӇC(C8ʫLKJ!U#45M]Vb\E0I4);En)Ih&1wصfl hBpT"6 J^iᄟ91ŮzfcA}2M‰;Sf. x*s2L%)?mJx)f8𪊷"9XV V"Jأ DKYK$4攛 .r2 oцw!6 J%xv[e'eV0I=N<8?htqo t( K|F@dO~q~ h9`g/: hYOD o \9OC誈;8hUF~Nh+-O/ dHV0*ne=UZBp%O"sO`]&LlYW݆ذƓX)_ښ'#w] ^VGVk Vd*oa;J 7}Sgp<w!V19-aC?}49'GFA)OI\ptA.߭4_KX! Lb c?ҙH G[ !w&u0L L &k;9 Wk tUBDnIsGFڔQ<6}E Ցb?\=/$^BS<0bw2{lο\r_ ]GRYb؎9V"tp-աDm,JYոͽ=?7v? >n뛏eW_7=X66_mξ\77w76_=6~E?~}~kSnU'_vw̃ ===;=5cx 8_>x[=x tpØN D'kkڝ<4:w`73~^q[%5HX>Z<{_q?ԁ|г=X_ԁ/+Ϙ[e׆(MQ9yٻ gN6~|<ԭO l_ @WW,c-?5P1_pzݑA9NKK$]C[t2.):(Yz0_uv6ܝ̠Ap3mɔFcKčW^M&RT!,fwC7;~A0٫twC{-41/w_f/^@aA택hߴir={zgw{Ջ]Ӽj`y{sݣCsݣ!33d?`CfLOb~=?05>~1=>;Bk=B Km1Ų헆;̸}AFΈ0/8א-bCmlfSkm{vd)m=:؆Au}wYZ3u)tC~_AئifKº6TLV v3Alޣ #>6Sk |q=GWo%hgx2Ô-?TVQF! gcf}CKN t!]F9K0 O\>+F[ՈXSO3Z5&c͓A~W4,'Ĩ0H7\<)G vLņgEۮQݓj$=MD9?=-`%}#-D"2W%^0lZLLi;f4x %c]79L.r܁_Ua8ޠdH'If1b`%1,gq]F7B . niS4qLJd{(o#n,B8zb]zt[Z8؟ߝ/Խܨ{n_*+)o&gNK_;޽ˊ_|a*ECOn߻UQe+~]]W]ln+&׭ޤ &FM,Wm\ݗ`B1%i6ZsK993Uf\A~Q yN6)617N6X]Ps߬ҭ9GZ,N {)E~6`AJn0y؛grwl RF:hJᖸά6CH߹O D64ZޭI -8'8'бV(,~o~ 5|lӕ۶P€:iz9x-]/0 {W0-zbR_3Cv._J3V!6`ݣ G8hAG)IN|<싮F)o-*ݡdi9k)ezֺds+t|*-D/7{L焝dLqj3ϵ6F]1Oڈo;13NG8 Lkdfv"12pr߈_yyK }X=`(y(ޅf,u+V#фn-4*ͯ+07}EƧ hQ(;ƄE}q;X"*ôƝpk*b/_I8B(?fΦRGCs<~va"7jQ[m򢪤?{}1 J,48*Z aɾ< /U]#lh?#?PӃ]ߗf;L>䤋u-kniφnAa`)>-FyfxzuR`jrgX%P2#c2^鸤/&m,)W]E{iww^Zw! \X` #caO_iXŠi:JeVhs9L݉\\@? 5pbQ|:$f;:-!j ŹÀ֩UZ$\oF )~BA X@ZCe{8XTN< Urvh;YH_o ֆG*!tǯMمV\c2vU/MHJP8{@]$C^/^A~mAvNAaiaosE$(p]@Q8dz(o[GDFV߭lqO1tLA$&Ɋ EYw_l0 ^~˞Uh0pEGI[% qЦ9jVVH/stYXsE>H܆~oZWũayd+GxYq;z₯LmKǃa+pEv~ s4 NzztVt<YK]3uGw Sʰa!6%8R@M>5]MEfŢy;isKk}sLf& AKL<~@{-gCJvBz@{r d(զ萴#X\dOD`$JTpo\ϡ*Z3_N$0Z !Ԁ]Of-ؘvhH]ag 27\]&J'52g|ztA бj?J*V/.hV,;?9&>bVA i;ԍ#AJs^®A׳o>'H#j_V*[j;.u:;嗷!PfS+yƤr*EQNKGpO78 j}'- ~[r,* k~AuS,$JAh0I`A 9]0P 66Btl+gr&1%9QBȩS3 8CP\u2pӡm S~᳭ȥ6mkg>gVo4sGP:жzHtF ǭEr^ dtWфR&C)ݥN~!x=okW0\Bf&w9;9L v #`,²c,D]n,> O6  ,$) Zqhε wݱv\\lס0}]lt<^a @RqQ - b`=z0^;+  >č&Tz A3 hAɟO_4+%~,uP' H@@6F-IL @_ A+^Xs:FEV,K mc֔Ч4x5"Kv"~$YM ?R"G:!8!G: ۷iMp|TⓌrDq) ;X`c&WFg]+j U5zk#XQ56 zɆ,[_u~T距:҄& *eJ{8 ~mQyzy("JŲTP +DOrZXhT\A%*%HlAj5RT]I rY1&„[ULw,b_Շ 2QJHP*5cVX&+ƄkOՂ!O/ճIR>"ChdnJՙ[N9Ͷ!ޅ?Qdqdc 6,$:4.9elWy!w!5h2+ B%׎,"hL<-h .Vf^25|`&3jƟU%s}߾;[ϑɸ3# d̚^bmˏx{0T4^ ˙!K̓8l;x%–g:Wi~ؾC-݈k$*2T }Yy@:-gd-=R֌kv+Z%ծf f:Wo[J~Uw{o6ww( ${>wG&\XyW,ek õ$2 kx iS0cOn~E;F}]=MY[OeMVI3q[ڕU^> A=""M\ 1mI}5 j,ؕQŠodw/Ep|[Wt!!BKѪӦ&kX!Tzce TPCﵹX^^tĩW"bNj- N üX(lUүTPa|WnG  AS %8!٬|3Cs@Spk*>g`-h+ϧћ csvB1T}rpy])AXA`VUʿ VN\y[.L@t=Ll6 vVٔtAs@`sHm8Xw*La',ֆG,Z1S 4`,;,f*bpfSƥaѦF D{*r87RkqjuZwln8VYokn;k?n`u̎0zwɅ.1E!S*3>lkic!-U"@\7"SIsXc fFPH:x.0+x LA DG݃ MdUB0SXqw:TZ|5iS̿ڋTV -hC6Q%blmdkZQ+NdRl]$WL퐈M%5ըsЂ Rw܉(<ߛ'_SbJ pVL$>/}`4`g% o7^o_YB*Crr|a 7!.ն&$ZBB=fspYHͦ,YuPNA 7x3wW ٧HR p3},[(ދu!X݉sI|ȨimN8H *j-BU'|xDBѳ|0ZEXGh^O`o,h;`iC9xos@1l"5G)vqbH*Ng19D .)O2 KL+)Ęd'wN'% T`gʯEMsYso*z'2 Y/_W c H-|u4О>_ Uڕ>ۆ^Y4SQ+ -}\Zִ&ӻ> ShK iu=1kƣ(gGG/ _7ȹI@t͕]IdSb`*>S<Ө-:3Fw#IP1sZATIp ȷԒIʯթ1*(P 1+5}B%e?^w> =w魒bJK`f"WkV{[#rmE.AikY:1si퉖 v/$ꪐhe t8 ½ Lgb~ F&|l(Aփ)@iɤ1f,ٛp0>/;`*|]wOwܽE ]we[Nx2 .L)C`~u9NT}#Yoiͩn5!4DfdTQ1 "fCxD> 7Ɇ80>1ʔ,?(0<qaR믙]emM-3(a'<ԮՂlֲ‰A'AykWf-VE-T5 O4²T}"udu6[ĨA"j󆏒:X5'Jn8V~O9{cF Pk14tMZɣ(\V_%ۇ!)vt2rS ふCwP@1|$4U~W=cREX h>Z]ҥY\:#:Ol7OQ\ȷ5psHM Bp' NSAVU6ݬWobs$ ?qXp̧gsd4Fw޺ j+'TpycQб1 `l{1+P\*ŰS7@]Ti[d^8QNuaFЕtk*x+dhQ Q-љDD#y*zQܲ8a{Pt0G ֲ{;ɐʖNE7Qpph9FEX@A'k,FmX07 ~H :Tq[V$pR׭9ODkYU:a HݒMLHBe;r߰e9 fau_3}wG [JN'ҾH$a\JYXm,W: տ;d$)?V_>*pϿ_UgH%~~@o$^"teBfAUy=c96dt,[.aGݻwϜjk>:~uw ![=u/#w1qM|5\r̋`sw!MzL½̏ Dy6ZI'3Lond>z۩zVUY'j>xvt{= >ީ^/աkUwk]gom^gTiAwe^W^zӱGG&G`01{ل rDÏ\j\3L=g|ߋ.΅WAVl 5?qpW9?$dik؟}x_f\A ..տ>5X#0C I"¬:.yP}[]wE;(/@8_VW *+,0kf|)EJEhX~5oY>އ ]%|@me1q+0ht:F%=`YWbCs<\_wglw/~z-P{t`>+ܐi/W5-z>::8qϠA7RxoeהFkvU9ȇeIΆJdxi1f{E>{2Gx`n(`rk/!x7n"ЎKtL# q:xWfe3X_YX`qS(LiɺtGW<,AYSD̜v3w9M7=@96ףt<UM>=KqȽQ#-v1qgmx檁YЁ4sZ, oj+^X3],HvMh@{^YOE (8F+whQ|ƀݛ!,ex/Zex* GfH}݀züM55Y0\JAM/цـSt@[e9zvf7l]:q28j aU匠,Ǯ%"ɏew.,hר3-P3 rxFשv/Tn!HF'`P'|Tg[х_ew'$#+rNY\ T_}/A,̝>]9Q zXO KECl# Ïȁk#ߞVHdf;Y#^DCO2'/=wR2ϟ~1s:ГbNZN3%dHq->-\GWGǯƸ uB.de]z?YT1#ˢ(Asӭ u7UK=3oQt_XʅOٖ N8wi:Ce}m$0.䩯Sd&"^鶒=FX]LxAjZf=ER4)_yҊ}qݝ$^g}y=U RANuyWe-|XݭeCF6{;רrI|Rr 0KT69MjIDh"9 zF:e%Ci@^غp~ ܪc>FBw~> $zE)giBw¿-s7fdQP 4 9E=L,| d, QErԞ͂m~CN77y~,08A4[oy90uH3 b#R;(HH=X i#~>%E@QPNd7Pc C{f %zm#RĄKlzۉt2*ީ-nD*Z40xE>^ѥ;gۨv2jk3pEptYo#Z+8KdC갍ڸ KFmSz:XZBek$^ʎjȜ)~ G) #B E4V(u. 8@-TR\<6&e4 b1fh=T^/$5(:6$m~\%% )b1`nDu[("c2;yNy`:賤P{< h j'[iEĎ8&X=I8m H vn&&yS6Bķ.[6}[|^.0Lx+' cVn>F~|55t .: tݗQ+˽mTN ,žs镼5"ڮ \rd/ΌlJZn~t-Π^Tΰ%˛-xzvlZZzjHt`89peݍ Ym(hk HɛUͲH#(Fo( +NAxAQVO}VCx'Uθ*Tu%{|%_v8ܻdԟ $E2h@)"Ӆ'1s-m٭ E/Tm^J-!n[/GňI⿕M){[R0&˵철rPB3}K/*ǒ[>+l-rފ˞8v0?z&{w^֝dJ@K?\6/&yIwO%6L0P3HkI0dћN ԋ6fܗ00 hػG^eip!GءjF˴4ς 3/HJSzR7WQ̣l>iT 0yfM̪qWNF]QA@?0q1ѝkܳjЈ!r]>Bhd a4"`3nxR^>$UY+Vz8s.8tF^THw"^`p~ycN ~>594; ׮ՐF& yʖ`8On\"u> J%;)3.oZ&3TNx6&_\>!!"p`\v HE㾫G72OBF|g94'NNVxJ M7ӢL/s SKFbգc\E_I X_D0'SI`MзE?Xv.:7tPq4VTr24M0"Њ^$ ;ѾT顬!F{1:r{wq!}Q("ٟppĴVӚ:%;o="[k (_$IiR-L$p I-~lU}z^lXy;5%8s<&&gה.Δ}3k'7ݞBE2KAi dm5=qZaBqvQ m5WmTò:Q"譂ߕW@t]rFa&SNL}^[9vʬe@<( XI ǐ\ tlꭆ{ۗit=hϮ=N։(2?br7ϰ?CSP)b,!.CxzHr.ċ3`I1gڥ%QHE8YDGmZsHX>+.&),0U-+YGY:T,0ŇZa7{v %@1-e􉧕/ KZu3̫֓nŀٟʼnf/)H}Hc(k v=_M  ɥAXkҗ(_UPtΕ;wBGbe?Vcj;bA0PC^ 3N W\uBpc 1"CCg(7ķi-;ɞ%NiudycX&XI*[z {$")E`b 1jvU iq)f{K1݋ bTN8԰{V=TVy}wVPց"xi!ޑUUρ)eu?׿n#ϤoTb&\[tߙ[ CUF*μdY7&GEb؊%0IVL 1 pTmnxIу4{Y5<50:{b+cUVv<*zv7>5 *^N L &^ƫmh*[1fXFV\Y<1 Ҷ_^[qA96>j: nd8!{;" EƻYND{AI[BȐrܸ|OXա$(43GO?ttK38^v3t4=L`b4>Ձ -l,+ xxWL"jXT`l+؁{+vt]@.gMs;'MOo@ߥ9y=r&"d ")s|+A*ȒZ_!tr ~͑g (xlPADvMQ~ ]A1ln,{@2Gh`B c—x%0K\"x{&D˹QI1='&!Ƒ齹x6'T7Kȁ O"rQ`87<3M)gkNE9D+-'$Ba)e^їE#cn8}BvSPoiHrw+<7 (-.TCT%Cd~CfmZeέUb+^X7<ֽؗ}BL*4!:ǛL8Y<Wz([X KZJlHGɀ9iqҎc} QPQp~HD,u.X]O&WעjrY yN鑮he BeTI5 _ꊴʙжnvX@y3қ'>ZsVD/rfEG.!'yo2'=19)r2=ڕ܁j-G<Y{'"zʻm ˬ1=P:.!m(0rd+$hoZ=|pf)!VXմ7=ݧF$_MR[.D0'H@잯 -ٲrmKv}/IVuƥ/PQ3Kݒ>oM_-vjn݇6*(0Ajg{AdYa *J%)d̦l0*J̉뛖PjLK4Ěj-ڍesf*}tvBЦI+(cR-VxK)2f ARlVjݿ:RJ>oO<@JQNƣ4̜/m9)vO DžI7Vɶk0UaWM&_"Ȩ02rDdcS.ߒKj+.ov$q8Ŧ\oա4pJsAnrDW>dN64z[gbZSKJ5z>TTm^g*ZOh/ oJ!P6wv@l1ZE&jm*M#h jpT. C'z,to9 c2Tie,eEdۏb2˪DfY1j,^|,GhƮP ]2Ib Ad ޱ'=mRL5q-iU?t'FZ|s#-MxlH> -"y|9R'#ݐXQaTKr4'8V%7<'X"m"jY[S#L( +'Fbofq'4BcP{'1% vggYC7cb5ȧQMN[Fx,d\oh(%6uNb,mj++ک1gIL=STXۤW| 'V"rs`Uu} ]07! fޒ" ƂKɈ?lI||+QeYW2x&C? EgV%rKfuڶQ:*S!wS+";L/JVgUZ58߿w[m]F)5& %PRP',a;!J _-0 tgb$=;56py pl* A\6MaoIeM>Z|$uƃM,9Rqzxf4z㳧~G_\66(!m9t>BB?ٸж65r 3>V??x=8.qqqHT q%46$QD5ρ9MT߫vnjhYƀL.@E*Y>'tq c%}P$C&흿u !XyQ eO<`9|æ hqŮs1 T(^Ӂc3+yǿFy 3 ]'G?v{NeS>^E4:11Ml'fGm`YԭL*[*Lʗwzi A4Eip}(S'Ba`4 sb8BP?U[qcjE&(oN=҅;n%Y q/5qݭ'a<݊J!DOz-1p3xMoK 1 !,(ӻGfB],~< },Ѹ<c!7UY;L[ +M+m}U'w*G:ޒ[vNH=ᒶ cpw#s:uH2 P! aSr`LSz4@j:ڀY:ܣ*4[8;0cmA"m}UYx AIOSkl5x?YMŝz]N0PH'n![o3bu+YV9RE1JgAW{?vpu&VEQW(Yx1 YWK,RFMG?y>V"6MrSH3V2/ָˆI }e.%ve-,4=J=5: /0{ [w9{0rVÁhR]sHx=zRf߂PEq%U!gH|JRF!w (04&ʭU=W+"<`XmU;0t@*7+tYL=L})|4-[},#87DdJi:[ 9Z 'B?\UFG!QKA,k-+"?%V=Se0^4Z "y\oR 䭣䓼|ɒ{%7>a:dQL;T/&տZh!ki腬 mdIQqx0۳7iWt 金FP҂a~Vf>?N ݱmjh_4o Tfn> ^<ޫ=sl/ؔԃ4@ 9%E\lu)&8٬ Gn!c;Q>du |i1ld;6 QhM$WX{SS*ٲΊEe'.,pŖKپԪLӃw(a}>϶ՅO@RR7:? ]c B͚`ǩgIqSk5Gs9O)fy`lU0uC°N60MT jrV֤F^lP:ʏn\ixH  "HJѽG?|_6BԘVhX@aw~sO (ɏ쏚CgRYF:J#o# ,v$H3ykwrw7.C:a]cVFBkfX.\\ v|K\yWEvB粗p#S ޲q/пe2b,(eWΆ~a|ق7їK?m5֒Dž[ιu62T,J#  ްo4XՙaҲ}O̺v\ 3tdh|mH;0-HA"X1]Ʉw–e |.6B4H뽑Kxl{݂Qx`Awk aҵ'\UNBɀf9w'yMsUE JmfJyJcQl#s-H1ԛKdǁokd42ϫ̫9F^y"lSO8΀Y =|P *JgCK5k~Klj#D$:u}7a?B}@X#!fG +%7X=DSg2`݁xmL(語?_hh31DgA$'jBJijb"{?륝UOYw)/[vj5 [dQx% XWӸ|;©zAVEd;:(0w8TayQZY}Ir&NPU8QN݄H9҃-'xOY*4H7*)U0M!$%fEVh$`%Aߍ'Ec̀ QQ L,@lJd"3_o8 ko[iuNIW]dwڢfE x%^ Q1\CͷZvS\5Cti9J\4LǦ,6RJU=ZQ*? K#dfX,  8C(vV P[(A[I:?TԦ `VDKN!8GN"P6Qb/j5tc'pU +XJIǓ) ct䤀KX6)VѫÔ *6ͦ^[MJB[X~( Nj.К\X52_fBN } ]sVi <X3?_y>]j??iߏ_v_>b|AI٪VRxr Tc|5WV9YF&O鄼Ά~ӆ+9+fqۑ[F7G\پdezRpR)xp|zjb ?B'6ImfW"o\֔V3rT ‡bͯ> iP1e<5 G[K'Bx%5GƇR^%x/BwM J--utI *ZMolmN50"Z|K3nV!% W7>#٨=#2|=wE;!d1~N 8K% c,`9R~4Oq<#"kW&'>"~k`kPtY̮"Aye6>@,O\b}!/?!-ZcPk R!+{dSzL coa#5' ʨ )gnHuk[&j0V?)o11HmQ4b0Ş8N_eT:oU}8s4aTgr8}]]yuaiP%P~TI^ )ٖ'Fgb?Fou3_Z[XȎT#w#m=AlNJ(z+jx!5lc8-=C%E_;(Ik5}#Rm&Qkhk2NƆ [D>- p/'47wr/5=O ]- }90Xb7^y5jRfwC7;~Avw;m^vNjݗٶ~n0qhNvo4 Fx=V+]Ӽj`y{sݣCsݣ=C ^0;2cz^n?}͞_unxԁvGf =;aT[~#܋Ck;?Y63Î5Kz6 6l ߿ Xh}}u:L}l4Gv%}f -j,m6T6;?.\fW7o?f6;˺&ʟe8-a1مKmQo8ٷ>;N?4W}sS!Y|> 6;oyfjz2KWDqpkG](>c7.PcHCA=>%l#F woB9P CğԆ(aD\ Yc'G}il4i-n&CpE<Oař3L,hϪQJK%Wŏ(?͆I4+w "oSA'ndqـT@#eo6LM^ρ(2&w< <%O阃(V3!ZL jjiHCDb8#\gSHU ǥy3#qbqfnRB) PGB jgd(LM zkLkwiiJh~DoHB`))")ϲ-#ެ NSbY~KQ3m}_ rʬַoWQQ`׷O_~Ic so*' w}2xx1*w>ʾ[j᫄n F jnI,N׉f`uNR:,hea;y >;J5t@gb :v#N>RlWc%?'?|pc=x/-?:%~~V׍ |qBXa:$eaIlbb@)Do;6M:QN=íE8p\\.go憃 gË Da~ o朩ۗW%H aw|9@(aMxrE#fwR: :zࣸB?|7Eǖ>E}3l@$9t"'++4{l ˼erz8E|%~hнcݢ[Y =G<0zm78* 7 C= CrZ ß?FՓc0vg\㝧2OrKlXBak0sٟЀso뽝@k*۬;N 9MH$„ AlQ ~W[3z8͝YW {M%;Zv PNA9nA9C}WӢo*yO%O0$OS]9d^BBBױ[s[%2c4͌ o0mJsG.\ r2r4Ej;OFbL`EvIӒ}$ A68sjU=8BD(ڱhv8`Faڏ5ϗж`8 HHHd8~|׉Sh9@4}=y >HQu@3M !2M5`8E_)o*uldy4œLP :ܼ@W!v#8vdz}gBvg{@c4́L[r:,q@@փ-, uѷ2\j?q?>>Ydt hEauod7]E UMZz/̝̔LygTrCARE^Cv3.'[nSALo@UvXYZheN!o$ $@>Ki+XȖ+QrVחڈ]kУ.^G(beZ 08:T+k(zY3,}|V>D_8@opFOST,L F˟Ʋ^]õ ! 4xŽ@Ϸ<4ijNc9iypaHY$ ZQȇj ֍AǦ֐ &)T̹X]Mj`X+ɴ荧oC NᱡN C>mn&z0*4"N nvg<䞯h^Lvê= vmT~Lfcliqy9ðF?1JZcVq̣NYTDD%?qLB4GP싡"çA |r n|^Kq@cM A8pp"A oL[ 3!4}Tqq\3VNU PגOiK|R EOZ54w*?9Zp&Wcmsx3<$& (zʹ>_[oy$ ~ m逪#oZ>j,MH;a }%!"F*iQ[ɐ(lPFz=c6H Ь_ѪTy43 tH-=Ur~bxެ]吢i#x<(.̭.&DfhGN Ղ/y; ^@^i(2ٞZp״W/#b01ʣq%IMye= BZ`N>ޮƑ0G&H9E(SGI@P~T+DM{7H$lk1x' P|I.%,)|T(ȱƚLSjy-՚uzW-HAݶ}w2hF9/Ź9o"֓3,+=TpH-~dCx>Qtx'ڶ c,,n 2e M-7, K@8)}ԓB @Mo%}m|,cA@% NWlRK jh%l151YLamM+ Y#[4 OgMs_,yOk4W] w 4'`$_X~keo(Ɍ ݱ˕,vCrl।tpF)76XoVuG\yzJNxj 1)N4`r`Z0MbC44n"6\/k嗧ur\ ic;c};FS$z\jjmѡ)RUYut%¹H':.F9>9lЗ!5r 1<߀p&rcY|UVR!!˄r?ZՂom5U*J U[4v-2IByD_2 q^||?M@4b"o~qxu%u& 2TG)ULBݣ#8'F^jkT$J5Mb`;#+110[K 5nc}%\_0at8%&Zś&S_:vʓiqo8%5>W̶[ǽ9WD,t<$}_~Kc8BϜ+D)ҧ,f=0 pڊ:CPڶI-^ֶluwQOL쒾3eC*0d2E+?[z)YUe^pUR "MK*PR;B"4Cm["DB A+ ۤ%kfVY5ۥ!Of*5gkיwL1ka1R%;ydkTvTha{8+2}<MeF//.Kp]-qqu$>v^mTL 6,V߭<tNv]s~Aj\tqb䦍eiLsxH=u?3$V1.  ^bYeP@Ri x BmQi|Po!SmJ[ϴY^b&~$U$T2/JJ%t aD/}&Utz^1E0zh0'mz x$ao8z*>4N<'dH8-l S)0=@H1aVDnj7OfuiX~0uDm.w=(gi?f91L-em+QG k.7h㭄H፰EO F0gFg둌Wupiz(.NOHkS,DPQ:|RX^'s0<Ӂ|M)L †7mv=No<a"7<^4+,nrG01:ҝ|kRpcPErSFgBIWN' 2D.&۾g"YZH̡$wy(x ]O.zSX^pF*Ϋ>zS̩嬭@hlNjS2ģR8iq[)HRn/~<,>Z|a5>H!l[C!O! Xw e.@z[h8~T-Mh}Έg U\,*ߠ % hQRDaq-FQ#eY' b 9-C:_;~oث(uJɼx}~hx/ЎեX(R0' YN/!>1DUuPLyrKN 8fI>KZf 'kKl6`lWџY'{FEbW5~FЬ%T?I,aB|:@2z3WѴK ITڪUh pm-up ^~jֆ1dlca$)0s/fJ lCG_9]SЎ&v!cw"x+O{<֚i?z() x.ͽǰ\>l(Uf=E \:1S8 JO!ƅ2}{@R!Jk:.Q|L&ॴq´N2CltϷyK8;@۾$ (qk%߷f$w6X嫣&5H^0?d.4G#ڙT׍€хl>5cςj;tI`c9,R._@=G5;:zaNljLl!bP Ui-TWwEN>saQ",a0OY/7_YLE3J[(]8Êb& uR#2e:P6Bz Cf~0PdYzKt>'@Pܰvt:*|Q&)AjSCrhArKF Y%9[u08mu:jFѪ\,۹[cKܲ a\Qra=TE&ɟ8^&LE슚'@`(o$xw͌#)Gne嵙+.wwcs|Ɏocm>so~E 2uH2bn:!y(Tv5]Ƭ81"B,TF0`uric1ӱV KnVz @:E69 Uua 1]bTm[VFު먺tY7QtV)icu8T)Z#r\Y !Zff+#i'ԺKb@kaB,<ˬ;l N`#P'\ٷNЋUzx %^i 30gw?kҨYhN=|jyYBl%׌J,^-526sZRUpYxJzvS]cwB^N64!dZNxЃ;DW;;'_t_+ jx:>^'Dm&7M mKBF`jkSD(5y\\/FK%Q5l5,kQֽ3k6X~ȉ]NN8pqYUNS@r0kB*bca1>I@_+_$}tT pyQt kVM,%rv|ew<@E5 %/!}`Xbr _55j{3JEw.SOSU<$4D@:$0 IJ+H i~Ⱥ9ۘ_ q\l}_|AxiV.bJmVo^u%о5˟ JMToE9Rqt?jlȉXŋvhDt6,FPW;Tp+wK^x굎PY3PBc}*mx6EϹ\ ;xZe{I3l)aIE3 y=M1qc(1|WK6Qmjh&erLbJ|u<$WKЩG\s.h+ `:7@ǀp1I,OqQiJjW4{A EezB3Ts?L}}뫶l@c}+NI2G9 P ?lol< |G*Ǎ!I G̏?b~,C=.+ϘQEBr =~ vQ8|~"9-d|V6IbD 0Oi$ SLҋfJM.F`ҁM gEn*|d^+-WEnw%$6~qu[k& geDV=}Qv$6- ƐO{ќ-leg`O=zH|rL;u˰*/Xqy/CKٵ 6<a'Jy^g(a 10E^ fF Q|ZRrjNcl (<$]Q5W5uzRL1|b/Φ b,xG%1A97c 82lK'qA?Q#.2ʬEbsƣ-tphA/*oߑ}i`a%aZ8< dp$c4lo&V8fQ~q1yPvݏ^W\Vu2eJ H B|lS4 n5SrGh:@ORZr<9ptsim2}ֽ2G3ek3paaUGxؠ\061"TEsWz}n޴ͥy^~p|#Mw[YYIL_{va{2w#RVԖ!͘&^mcXac]GGR6KHXGT|@a~_3{×3]vOnN#Ll˟-|~W V}g'踼u! g֪e~WGxJmsZģ}pE\/[;:e|W\gKw9dZA0)\9x403tp?`9'>G 15:nRFe0(llfAႧwhf~-q LtI ->O9:%$ɟ#`4q/.f_vS:r 45WgsYᲭRt$Sb:`ĥs+͓9 sA`#>ܸfJ̭b@` 3xw1`쒲HhU Dnثaf fgP]}l-D5HU{LC"ȩ(QTF&ڏ%dIQ>1#3S E6+9 ي 2:|A !JYU$B8DߌPX: ]q4<(z($WT[?L}:pU Һx k-(:ݚAb2%* \!` 6/p :Ja)9bJ"7S-i]s0xUUd4uGD~JkݩC{!@s]b[Ժ Y]mYJ<͐  ?GAv266,d Itye0`ϲ(ٖ:;m8>>4{QR8 RJFt<iT Nb"@grp8ߌ%nt`?.=ZȒSwpLdrDZZv4s#rㄍy M!MH^j]+2)xNBك F0Egқ  >Wb%$6 (?e< PJTr+!$m^G2kzXΒrq= Bqmyb#F"o@y>0l)1<=59X;1ʮ{:-zΆyB6Nz׻l3~g~b::h|.1ub 0z\;4*EJ,Ahfe-+V*1Hq]ܷG@G4]%?@P߆@p4IAVB7dͨ iч,JnJi'm?vU)|1:DuoKp h^1|\WW$h*zU׽*R "yK8Ԯ>K0p9ig-wL0=Sϐr^%摷Ǡyv-/إ%\P{#@ DxüCC&\L)p5s (Yܜs͢w>õ>&c 5~{N (x.p2o2(gOĔl,טIC-ah.Rc"LB+O $ |Oٜo/ O_?lff跆v,;S8q;lS6eL{qsr.!]6btIcy}LK;'gQHMY:^Kq299x&ò;<-GK~,Lc' @23\CRG"ARy~J-ɖA{EsuA6aPFhݍ-L\n٣axuGh8uI] Wb$)ހxZ[u!3XP8"0|Ն5a~ZD@2\҇c @نټĉ&9d0Mw~zC !`7cUcc{ @,-'d;3?(ソ2Mv3Z`▥~0oRFN$J{ϒMn_ dG.c4נg@W~Y ~!;.u*&^oA+!:ŗ# 7lcMc59lז s '&Ϛ6+|B"΋nUsTg\!Yp ˄DdWhϻ*ٱQA!t8zcGPA!aqY$an :ٗ! |T> n <]@B;2?!& Ei(y#\9 `;01;Tw%Sa[t~qdVcLѿsvuDMЙ ' 4X3C>h3 ;d4ȦWݻs̝g2cyS|ÅW^#oEi){ܱ?zGi3Q1:m|zʰv`NIuAxd>Ϝ\E{14:Q 5r?6~ƖifwPݛdȁcAX+s:!xߙ.6 nF̐? UNq-c r{  mɋ l ?4ljv25-J|uwn3o7yHłwSFva@mܧpenmsxh9ZXo͸8X8pHְ.8KN3u+儅Wvf0sڲ { `<i|PлOa,iohDr!?]hG % ׺y96>:PAqiw`@zj|2R0oaM=t|f+2 uxO<#ZtuKm;줜bѯJ'n8@T YRF ꆝDTa۟4. j-1VJ/jqu! 7+#2a}`m5O0.EޫdnK$>2*O=fUdjHL1#Ƞ'Y k:`Ӿn;_ Н-!7:EꞮɿm^ 1=L5.,ଜ.$V5%:@ysjrT>0e*uY-hFNlY:UxK9f;l@pH+O|Ǭ-Jݨ !h5P,nX_) N϶ZsC=wBȁ: ~qf?p&6}OI;3 ]iw*݃j>  /L҈k(KR7')RqRۺʗ7!3ɖ(V\klޥ"bJLyNKu*AW.,[HDD ^ Y G iuA|+-m jm ,y'2[{25 yWs^ 5J|{ b #-[UFUMwzGm4Ŷ[ .IThu~nuIG j6ǴVڽUJt;طiF2Uļ?ٴzԔ殶V=AxX&|%|REHݺ|$TK+ PpU3.Y~Nh cB G6LZfM;K*¬*pxg*EyD 6f7m@5ʻ  l6F|<Ƙ6hDY,ÐQZ!j8xÑ(HA89%Zɤ3X`ΎX bcŶت,fuylqUԐou[NO\H7 {A81½=:]k6%P=rA0GNbի4/,5SUrd%Gd0dS*V8{#$NP+ZvoU%[ ȂlQCWXׁ2$z?/5U;4K-^' H /IFJkU:ӎT/@҉8mHɎ)D}?#4ZL FȠN0milbE1R"7;4m>J{<쑐<;e7d[dȸH c\9 VzH-QXJpE(NFfZBp$)w-tP3K>Gw'0,ah.4z@&XapR+[U]B{K3HX#-wJ ";acZp7$h 5=QYr|Ypaq0cb $GC5dh1̱;T(:CNp+Clע> oO##_my蜲DÒ,s}}W׹Zg3")D~ZH+,pv}z%#l#Ya?EF`T[Ɋ`ukz \ ,+$waZvkd8E37 Fjj)̰`*Cu{m_ Ym6$[Uy\ܶ@C> ԇH#`KzQ' Sjc)+Z<41@wU(J`yZa: G-g 5x~X*˱M󖌭rDȄ`1*9O|[`NY(> f(R Nn9n15y@W5KcT%(,OJ7|R Qhnʔ Vy{>s&]:杉T\ ee( h]a$p @OH>y!M ;2>$@cELIкO3BvвFBD#=cVJ+PsRI`]p++&-kxz"t&\QA^{mF8kLc"$o72߳ש!!9wg{/; /U{*BQZTISl3Г姩.jȞBs!z8wdfL81P\:j*@4ֳ"pTg-M)0d!QGPG4 G7b{jJmd+ ">ldKHzƉ.C%0?+$%Rژ?au< l1lhd(_EP[QBi1Cv[l2@ěnj||fn =vA?wlyBc1Atlgk/PĜN8>^w)F~T]L bv2܃ȌbӼWFFP֨ ?8ul g{@hV߇k͋`OZ!lq꯿{N_8Es`-?aC+CQHA Vx!ߦn8)=צ];/EG4n]J{TSVh0ΤJ+"#­PXQ=71hW Ps9)y7dF(g2tnGdf>qnv̬ qĺXCN){%,ʎׇًݞUү#bm,fQHHP ]o,ܹwS}7(\0U,2M)6 ̤] 9"ՌGÂ|2߻uP.b.B_ݙ$PJ*@U#(s养yZc-I,צu|`w!^剬\G僧cf9{զI 7OHkeDZֺOYr}B:n=I܎jT z̰Drv BꊠH@fmrGf%pu*7ZkÅa.ٽ6ai0SG.ն&oxR_0+֫xdXA9]A[sMh:UϯGOXxs^}3o[Ho!bae(gBNUw_ (Kmx'׃^Wjx޸=nnCնRaf_P)X3f ƅKww`D%V|T܇.JdWdCDJ!f7%}љO; H|vۂU6T 㶳[v!*:BpNsvˮևtVn+\#ʼ9y4` L/_!%,Mྴ6W)Dwl3a\h?t 7 | JKWQu5u&vH/W[VO5ĎΈZO3 %D0,{ iȞ=gчE*Qʰ#zz`1+Șd%-15g^ Fwph: vr&.Qu ,hXJk`Mk8:>a^U~ a.LfLyRU)J$WY6y }||@M>N<dF'ϵ B\(,AjUT{`E0<_-T[aTTmKhK2~{Ƒ&AT+@ӄY߄V:IYu>LHRҊ-dYyJ>5Du3(j;gBʦBp9wffsVs= vpxw qli*FO:z-%"5;kzy|ŵM#*RIk?pRqo6)գǰ%.'~Bpjp-T;u]Mw::@j!ǼBآ}$$#4窷C!cT%)'E` QHQH1EtM>a(+=S{\Y8gB5è^ ȡ*{SU@,5CaUƛ t2 05R^x^nSjcKOe8V$r&MD`?jDL,K7-7SL")Q*%l[_/Vx-mM#|Z%5G^}2ۺnatn Y:U 0:( V4i>Mhꞛj{"eO$dJ@ ir;0єfE_4azTTV ӿIt?M)H(!YJB^e]U[liGW|~-C8CKcxjzʉrG(]xthx.fu6tf:˜cZZ䤹q= \Yxvr.k>l\*ḕZ6W5ϒ|Pγ@1W8|bWR_j1g' RIڙSukZWVV/osJdkoga J!RO $fMi4 ;)noⱕ՚L6KMVV3hp'"9{ E'LٻjLqĺxIRSXbf:';( ;ÈBbcm%r]tqvwa'QyFq1hA`Ps"Lr˶%nNF&ߒŪ4<3E %*Fp` FjK Uj_UiT`.km/68aYuDg6vj DV'-_Z.Y,cga"r"Ol\1=bCS7(yՑ0V+E{s XQ~Q(ؚ̮9e#lUc^Z@ƙG0hhŋ_n۴rs<^'-ƍq9Ž@["J@uARKP;`&2o*fLGƒ蹵t0|&\84\(x0UP|} w'ڹ&X'=Y)| QCv aHPx0j$~3SwT_Ar^ט2+I>޽2-HUu`b^ v[di BaglS9;\/(,t> D9?} @U1^=]霃#߀sa.&C?1  U*51$P PVdH#] smXpvZJ?Q`-I۵8HZ!iPΔd'(i2T/%o%R(61O-5*t&uW#wPug#8bl&&[ޞYe9:g&*6:UlŤeb)ٛz0'{lp-%j[^MoMAmqӄPݓȺP6"@(P;1J?{ޗF-_}$A#ݱ>DIӊ9$C()g:۾֮3s&t}k+c-V}51kdw y;XϜ@Iz8YLdLglC)S )oYY4r&f M{64jGD;:/æ!ݺOr7S=s|,6v"صU"E.Ǹl_P>KMIҕDw/>żzy@ћc3ۗJ݋J6n9ǓGN]{C$^s?7|&ϺBM*G"v^3Vl(л:d1HD1@N3u6X 딿aGjZq\b+v"&) wW`90[wѨ e88MmɦQg,dP:% V5U `u_$İ/T/uϢWxsKU X8gKM6TNM(7W^xB*$hgݣ~tgjK.E VlhˉO2lK+VmA?쒣Sѿ<&` d:Kc)4#4 ضP9˪iTQVviMn5&ȝT~^p10#pWƝWT*Z6|)0^цqJ}ɈI_qՋ 3 aJJ#_?TGd5Aժ2~_b$+D7e@B>A:_ Zj0>-o+I58F^m3CLq-s,D!@ev.lwRrȬCgP`,G Ru|1¶֠5Z{~I,˺u.I4hP:F$ Hɬ"9չĵ)4$d0F;>9ZǓ)$/!8iPXD,ɹ*wG.0ı BuSP`rӈ/7E-B33?bq@dѵJ$(lcӢ0jz9V]~8͸׃,>X;i*f<-H?aS]bμq< Zœ+bӨ0ix!dzS |"Gp hJHê0R՞I<4P^v): 1T Jf8mkMY烙tg"f 2299+kL9kK)fH5n{o.9p77cϦt ҐEM4Dn1NðD*ppmE@TY=(RWP]Q8FOj$;{&&DzXVД sodPS# G0 mNHAW`f9ؗ;l iujuksOs} 2UqBY)J dMh4K3S20?"kz);zos!LXEaH`aioXy5X;_B$(RdCjC"L Cɸ"Z̊d@G}bYGp/F&v7fZ6?f0.gd&6!2\eYEQ?9c? O·TB.Y6PTC`#10·4]MaIlCÙ+r0/Φ:]myX w`x] 5\ſ2z1NP<g&*'^diHB[ wgM|5;8ig+΍Eq|X?.Qer^P-n 7:Va-ѥG;\1Sa#>Xkթ5& L'D,S# c8 ~-t|zmg 7)ZŬP(tk̬8l~^gHY  6C[71[(h׎vޱzI=q{ٺ/hSeVaW&?v,r}3-{M;Xwѝ"XWpŁ*l r,h9<gaӎDkS Z,#7E<qyxŀmAk/$]&u@]4c-ap`Y/G[.^&pĺ&1>Cui.ףq>m_k| MY(_ ;1  s`w'sqZ#G%#Ëe++ atnu #%( .=[0K1{4(} %㣺fLxd/ËY˷XfcgJeEo(sEr096x/eJuS t'^Fԗ]?H~:ė'm Q` M@^| ^Of"!3I1 TV/BV+32fDL015(Wjߙ~]XvMF3BHEc`#Nlv(|Aq #m;hFVYKzK[,cVo$`uwQn՚?#-aPP"e` tqeI_gH(ߴ#?^Q5KƗ uR Ox1/=Ϊ/-]ρ1U؞iqf&V,T/+"լ~, <٩Eͫ蝍*8y6`)+搲)I&ܰ0iQ|s<[mt-#9qsuH}SpŃxUɵeuc\ PwU\l{ ^ iTg|&@d+|x4-P%6HT #5X nN9-$r't1TtH):2Rް7x#o}9^#(`~z \ `⹞m`rEQ/=* 5ϵb2ޘ=>loL:rPJ5P|SP2 ۯtxs= CHJ&b6,[uAɈMI 82tO5׷5\WP$f͓ Y'y~ a+Vb'\zcN"?IULpQ-`.dMP87Ï2 Yv] 0n)+A[B)TdoYjeU@a\^lvWZGɛQY. Bj@0K98Iy ڃS*Z:Uw`X1g-FFRI\9U5CKl 5*kZ:ø/PW*D,d _q78_Ap(-/K?-Ǭ0XQH3Q΃[lP\t HsQÃ#8A:47NA, CQRYAӒ8:t8tG0 \n=13rO,j®ka^*|IYaDk.c2gg|u"@_1uhD&q&s:<jUGLVbR}|shuB2G48숶⭩bEN›˹(hd溛7o%4#*6B{ Jb]䞀ٷL邹V;|њs=K<# /I_ZW.>n)^Ei.ɢ#Ovq'Xjx ̺-,gOAɬtdvx ceɳUS"!UH(IKj̜ ϓ1_C2CT(>S|_W-L*bP i9IYRq"̈su1(%O9xVRړ4= H>,0ܨ{ćI5(,4B#iTi2{n:&o.k[%V;RZ="{٘w*E=1F ]e)w;(}#JFtX #VGBCV?)t ẗ ZJ``EQuL&0Ou)Z~8ӽgtC6OLNf2<޳Z2wP$FS%C^ ߲ /f㝌@ُrVҬ+鵩ir;zxx69糈M6,fBvI#Oj>+SZ`$7s_sT Ld^3$Lq瞲e\/aNcL(hFW` -J\nX|@O5gCI}XP$\P555cB wd^`TK+h"mG')"{I󉭏:OTxԊd1TZŮ>"x4ײ:UZTMn;@hVk w\n>B6;I\ip^Z4vN){9eI/6,Rt76llERٺ:QDh/fp^zуk)Nfp@0PHXѪ%}z/Q\QRɨD;tр2&t a&e"(XҘɸkaE3!{ Iˎ m-,  -k>~TɲA5N=AV{᧐u57nc3cGlY*U Wb8$;F.+&X\ٷ-\YM-j5Um55O$]}$sfϻG.\|Ϙ-yj.a*^'O7Gɵh'1ɇ =K :0rA WeL6o&q]3Qq!@ ́%QæS"LIj뎊m{Kjvp-$Z0A[,LeA?'PX $ii I9s dago/ٽ(4 w1._@>i zR4.km_"eeVu_*Iq)0ֲC֟H-N%=fMDj}݈6 ãBa^$.[ey9c~n֐}pm$ve3T#TqOUQϲO`ԏ˚3z;n4Zs9-t q)-M)y0*EG@x&VAyul{fHBQ͜˼E;@aH=Cu*Г>p4鴴a#PM? WC$^39 }>~x7>O> ѽ>677zTnEwW}$ڬ>nsDg %>P=O&M>h!JeIT)G[+w[UajR5L% aw#*X)4]lnj7NԴ"Ǘ4EΌ9Jԥ|E `kJ]c(䙩j9Mǣ$!K#2;sr6)v[C#=48Fs|o.[~Gfh "5Ygz]/[okGu@ћ_vJ WZc0fٯ4~ŏj^kWݨumBC{WT%9{м~$fU{A/ZzՈݚQ55czQ0xHj5wj(tE{ A1ŢAkomBoGhy~PˣlnIc>nm[kհ6, YuX#p ;l`iPA4^Ձ֠!Uh͹wxܔ:v~[!)C(;m ֏`!*>HQ>t5Tɿ?1JsW)\ vc8Xx)g۠q!kl&i7-WxZ;*dN p:8tjugg!P@BONa%'ӣHMvZ&~!?DWk؍0~GC٧+0f#"eO',lszh:L5gXҋY1{ߩ֞#xvNN|{ ŀUQ0 H홝` LtWpKVtL6l0L6*Y(LQo w2 E$FFƨ(ch'v(1p*p( Ib(&2g݊DH3RDҞEAh)M;D=ed@zqLT9RCi1\t=R;'xsęb3w1AQ',3%gmzKt@`xeNUuxk5 Lm88=ޯ#2/M^\Jhc%wR3'5fD.N\n`wXrVT6u`hk驮R׊T!;O1df䥯mg5^s,j< ^0CAj$.[bU`(67mXYFmn9zlNy(=c'69 Dȏ 6KrU,}́F2VҭO$<$ _ؿpޥw8sS U]5[&y*)8c{ʲ́wFW_~{OM/`eu|awP+ YFM5 +կsK$I$v`w/_V!ZGN6X m醧p5^4up8rrMQѐufפaj%aZA`lq2=;ghi/ 8tFuTlzޥj cFS=FIX(Ѡ iǠU Iݍ?* za2C{ ՗$8C^ӬYv-} T bObRuDIVUy̓CSը3\WO'pALOfݨ=&p|}X~S.ScZ 3DdR:YyKS%( ښT(mCܶpܲ6 ق6xA! ̦-%\nIIFj$:6E-@DMM{tz=ʲe&-4XuS2RF\#GP͠'pDU$D+gd:e"aСB$8t3 ; @N$cx|rU,~4ӾA\{+5Qˡ&Qq֥zok4vWnCjأj+c[ta;0mZF-j3XνM馗=pG?xj}6K!? fxk%P|t^sU~^t7kV]x!{d(4JCYXݭiJ<.FWrҒVO!퀄xh,e6= # !b)C@Cfٜx  8~׋lT.3BD}+guaj"!s(nCG #k9*3k89]UZybsh}kߎ I\FK +25XQ2:==yΰ~onO+kJѲ)$+|Ɖ'rsg9ӛe82tWK.b#ǬDK딘#_}01`3mHNv,bØ1y:Ak1+#NoX#\2Fa~=mPްW8Q?ƤHU1T`pHrlgZ&P]kvPL7/ÚW Nn퉄0q.O<.ZúF!fT6K+.L`V-]ٶ֋QN)uFr9%ɄǾii3`♺ ~L8veJc[ǪM6S`Q9lifJ&m*Y]W+/?΄:{"6[lۀsxeJܺZ`YNkY9^(x1 9nFt/ظzE wͶ/K~S1zh@M2"^&ʒNi JX9a!-$S )U/d QqX-!߆o R}$MUp\ǘ݄!ޟT/cix3^-XZSYvb_KpV]Jpkی}!6k SSۘT]&WV$x?Ӵs<:d-&s]tM KRn3kSI$!artG[cDO|}S]3pI`9T^z0ɞo gj'n_ߪmLL^l갭ᔸA Y֠DA@l=|h#}5L<`=~zoO8QuZ.eFA|E>A7I;L!yLt_c`fon^aXӮXbHiN|_}q[Tج~3O,__ʥ%vO&ޒW^iϔqA\e{iyͧGpϴDm'vSd(8M 0Pۄ$nݞ&>9N RQIom{R^B} t!!*=x YMZee+3HmMCZJdMU90ʸ\siJA~ s.kd"j/ί d?> XđSƝz?h.;~7m8*I-4r=>8?ɔ?͏ٻŒ P <!GJOl)Ea 3"FDKZ˒_3o =y]zyvihG?⚓đ0cB?Gm?|>i3G4oq{%r*yRPKL(Anۙe)!ϭjGq@$Ͽ-) DGji֟ƨ`'D#Kݳ[ѭ vgm*,wjBۦ~ߪFҮ[)Pk:DR6UfoC!Qq1!v]n0Khk'0=A64}7%D"d|0E Y:O3S6gLء7ʽgݰ t; x2&y~Gj>r:O%gagd-?h^;B_8 x 8cwv z>ۀ$ǍVAw4-ato+ Kf]H2KUQ1yop#T,I`R07^#5c o<ѹlZےTF~Od~RO8h̼ķ;Җt[oxd),(w^áp\('Dr3Aw̛4x9pOr1Όi@高3#9NWΤ-@'E(1^?vxm|Pĭ{03TK$A"[3]~}SoѦ N_r8JyZ/NǷG$sbRd,3+M.18L[ȬR:` Kq 8ap)M >deǪG{.pٜ=&d+֛?+eGk̲]T& zdrJ ˖T݁|&61@2@_JͶIt?ԙ8n'ڴыWG0Rpf"a^o=~lQz[[E+dX$vU7F3xW5OMq\2eadw\gړT~ڠQ,_k֎[C |uxW!-oZgRza>OKyݩx: _.|G"/Wws1m^VV im~P[mHcքpjzbdfk86m"s$֣ҫAI ͭKa3LzxD)@rH4P+~gMS32$> /yׂ7>#cOu)ƦD|v $am(6g_J)W,Zsٰw*$ёWԂf]~QJz`.ĺ\!,s'[['f43}0/ûٷxDɢ9A|k_m`usuYBC٨|C3*KI+BJkDSzT!R6 cZ>~Ċ#dN;`v>aI ,4e#/Ts9eF D's.pox2AHcqERff ѡ쪯>-XECVQ+.- ϘuI\x%Br}2Nx.3QX =@&Lzb XWØZ@n"("2;3%0aDX -dY@RcK*,rqHps, )lbbyxŪgylڔٝ$ˇэi:O(6$lxV ^teE2hhHˇ0Zc? PARv͘Sb#&1ZrFHK6@`}y:>dK:QCdzi }HF5kd&?Ŵ/q9'x/p)xf~IɆ̏_Rր|z:`9LI'52OFEߦR((6FNwnk~׬O;􄓷~՜f!F3 QYC@խ_.E܎B6 1cṽ" 8z>ϗ0UfQ>O۴&q+y"'OuACE2HiE},KD $7@{;m{mNqHswB(قC#uoh@gdw_Pxg ~wdd񢌠Ȳh e1eGӓA?=D2zJ.pŇI/%25S-%jj{gQ_*h %cؤ>l$^!ΐYd[O'^2œѸ >#i{%mn/1`'bVd((1-Ykޢ 9w1X6hvEBQTɟJL_'c Mg8&^5_`$ 陫Ɓ J?gKp8G,Qß79zs@w4:`w~X~֓O9gLF =1535*ԛz郡JZIj.H-ɰTypMnzBvd_,JJ# "K}>0,(ɽGU~+< 'O'ʕ7ä/ $v&^w[Ȼx.;qLݽFOe׆U>,Eub<\^)6qRpxKA6H]3FҜ& Qd#M/Puě6صyd`_ .%u\7k]Pdz7Q {SG. 5;Wb) 'LF$(1,5ABƣтO^Ձ4EYMͤz[;j5^V򨨧Q<_bTW˲i!.m. dƇ 2B8|{ h3K]4Ju  CZ:`eDD)Jޱ9#nA}idIpR" T8JϓMcgRaf8̹xFLO"]ffK݆;Ȳ[Hkye9ÃCQym-f%0KH/Mhqx1rƱg.І-\=ٿ<oO`X5me5AZ$@ u/i/9{?SGɯcW>fv -nyG.JZGHzYf- **F,qZ<+Iǽ'քlCe)//ͬ?4_ox9K#!'lRhҞ~^q^%n#u^ips;zy1O<(O5o@LDyߺ *L^+Til >A#me+,i?R\b17pӔCO7]1 a@6 kP}L݋> Dw|9mXo,s` G6r|!gb:܁)$D (<K?<3z5()o5nAܫ[q1,h(XN-mjq(`WEw`ȅ)Ǖ(x/2dEqy{9Ϗ%/L+|4)v^P`BB%% B Q_X$8F~R>赬njDlSzȏ؈{/k>4KG4t.b^Y"SCnUª)?ap154ѺӐ'LN q1 o'!˃$Y>ɪyl%OƶǢgLZ"ȆEܔ[./~ֲF3`Y70< hTaL>Lv>FX f۹PL]p=.yk* ަ p/?Ҧp)LNLc#E|Ǥ-9$NcruqM}UE-bC=Y]U#JEX*E]ڔ^rh˹1l 3KM.dM1lGZ0z.I'&cș-gc Wq3-,b@=}`H_ f mG;ql ugSEX<w!RS4(MTX'1%301Sgug:nkh=X(t>5)$9OKymZVxQb>E"<.mՆ!aYtdTi{E5\uɨUw7X M۹2'%PYhs BV2;Jj0'mE a`.Mb1FjJ}4.uf[ZbqcԦt$ߐQcp~XJ[? R~ +'Tl^ٍ3`YUPxpԴ`*Db=e 2p UVh[ORA%D2!mK_(wo)S@B_:Ȏ&!{9AU;՝Ɏ>,ʍq1bk('(ozDLe_ԥEUg4H^~*{wqlƳ)E8-wݘ/P:şϘ͟V4P­ឬ_,ߒoTTacNzڃӽ63u1]NNA ;dOx+Ś->wӉkv~[i^.  J}Kƣ5=o|In,E9Mߩ|w'x]in~Ƿ S$#?vSZ:HҴ24;@e-I-(!܎U@V&h_u9%qP`sJ%tlݶ*arXh50=*J]ē%1S ݅AI'TZ:Նho6.›8`Ibjx( r :םހ[;ى9Ag 9紃&Df2}g@v4:TI4ppW6m/A7Y.΅'׭QϽ>]lSy:$k,#?˝Ǜz Oj2Ú}UQ*മn N]LlԮ_T+foZ5réBL(q0hƺ`;J=OuBw/cWFOt4^9Fћʈ̲!Țil#zqsB*̴QٳHj1W\|T:Vܑr46 xedђ,(9'ߖu8,AP8Am%e=WI&L&8:4"Hh˹J爇Aw(fm oi#]䰦6cc)vƎ!.;%M5z=}xi?;hd@K"$/ 9YOnUWFJ2i3-)64^JrɞY G¶#s,Q[^XǂD=6#ݼP$\Uc3SEJu̽ijTt*"q|tV,kXZybnnj™M7V*SK/}]+?7~+SR/T I'yTnJ A[S WK1LG Nz="0hd %ōeeVi:׸)+\椽Qa]"݉ʹ&gs MnT U ќ#Gaw7n%R ?sMӘZapiԻ|CB/Rn{Kt޻ŷf3Kj W7e_tp1G _6%e+H b[w[? I*C"D/bfb2AVhbU|͝ĸcRS(gĜ4F@ Yr dv#&8MbtQLs,mesKdrU:YlCXg[?[+% + I&aL!%!L~:}mQ\^qX{imkByNO.Uy/nn2Ц+g ±8P/L@A\CI$`0o Fg}S4\ QZH\I!b>v EZOqyW:]FT;!ǩ{FR변@ƞ ^ՊP,r ıD8CmWJInr1L`%j-7V|+zY΍a-2 6Jۈ \ʒ_2fYI#gkb<3h\ jy.<Љ.>ߋ7|6Kת6b2` .K#wQo->48{iԢ|7rGOӉT 84 ͋F"@P|mV=nWyL1 %>P=O&M>,IIFpaON9||WM7f{: S; nD8+`[[CtrBӎOǗ4w G۽&ܕ=}_baOUx]Q|ctS tv:W ^O}dB$s۬ߍ Gxի( f?NZQem2zstn}7Z5JTk"vA3GPh՛۽klvMh4?k{oy×Ah5kJ˽Vp6 q7ZQ55czQj/#k|S٫W`G9+5GvC;P,ڭ^u<ގ`V6ؤ16J6, YuX#p ;l`iuTA4^;ul R=nJJT;kb-lڄfunםo TG>,\/{!J|H=n=؂>$?H;2_Dh?t?8n?s0V1 9+N5t+t:.p縇SPR=ե rm}\Y4m x ' v7XS<5')Soc%-HVV@ q{R6[Up%!'VN y:pYgq>}cU?38w?Vy>j=>@\:YTҕ ?"$w=)e'_2W։*/G{n̵,5ͯ^hPgӐ+\ ⷏sςg`x>Y!8v ׬ np%֡KU,p9G䯫 [Bw,9{,4qe"bI, lo'(;  խ+{o?7(j$,n-(i?.( ĿzQ<٫M#!$]VH).&!򄄋KipyBE$TBE$,,ΔxV6AOETSn?)oA8(q:6?^a6 +$C,_o"I ёb:Fn[wʣ_QcT'/L+RL^.sX`_Gqg*`HAVխ+5g-}'Uʁ4N͹F?:#ۥ.#5t+cY/"%I|"OؕicYZ,sjZ|z΋:2bRbT '⢳$aT`J8GËzX9LJ[amSvjЀcCDpB!%7qh=X"H1q#O֛.I)"2q/z~Vjb1ŃMGj(DqbY0wףIS+\p?o6:G2T{>J|@PDžcx$i3=@:PnZv"dó9jր>oűD9 Yd3, G@/IFMkk^/,>!)+3^Nh`B^!sPkLKF}G!VB:u.\3&υ:YJRFJ5\Lw(0ʵ$H[bRI ן . ҃g@Ѡ 5HHVa\ Q$wNnN5#c8krxnzG;5VsɝR; 2K'^} Ou U`9¸rAxܥqlHZKMr􆅌3 | 'C] A +5:+q z S:?chEg3:F F(O7Q49865n1k\I2B޲+@]0Ibpe<rf+|ݏ+D^hRV涣SkS"jF}ЖP X‰Ėy}lrwK$#H+u9d.m*l#P]ɝ2,D ݙh\:\oC8Tu.]@Q2d-i583exFbdv-Khk ʲGwbΜOZi>S0/dN(}^<&CRǿxsp<ת(7Aoy&$P9arwjCIiV+.j^l%&3P s}^bQOЊ{ܬjfV[5 Z-GYE3N #}<>✖^/_ h ,d3K,A94}`/eYA0m^|(C[K{,1q;,ɰcEV,)N/ǜ Aι  7j_SjC$NPatò$JFpXv(Cڦ cXw^ ~ƨMVcu:niUț?\4܆f7Yoo %NEs[2!s\3h܌FѷMO_ȝohԟ|g'zxQ `e j)ղfX:X @ӣ.vQ}elJ.(o(mloUP]:~¸ ]$%6x/Zw''< ILP%ŵ!mٲF5CWUrV汿b](W֖4EAQ E .\TWhmMGƨYVPgFȗI29GYUWÞS+ʖ̈؍"蹭2%L;V)l0^&)#)2=dKʎSPm=?rU}õhBT2'm\U{#λd=ym)L3rܒ#53##oeF{;,YTa{*Ouco9*&FBBZrlXx\ }ʣ.pi̫bCq|1YҊaTb32yEoXr ّic7$_x`3m%PU\(umf]z^*ċrK4շG1pЍX5guTAp VcKJ(ꈕ_!u=P%Q*łTj>PSw-HX{U`])gt&B\Z䕑`T:Ǐ*ѱ' PnX'U(O:X_>x3Yr=ʾ3nqKcN2Ǎ+Ys)XE@i$9砼 ?޽eOℛXnCID){ (DM/GbU:2u:҇٧ylG) Wz$qu mb}WD#bTY6vH9xsdtsxpV] VU)Pܧ[[0BMОM$8 5(0"M M`4Ṛ`#6[oJ kcputa!G w_g>d[5Md81'ic.9AD1Y#,ge!hB#7H*|vGޖo/ #3wH \~Js,WT/eEB'.{ Τ9ܬ$?!:-u%Z>VH3g{߃mvV^x1"g:kML< .D{22 jX1_ހsCrՌ1jḂ>S >e(a,ndrY󣯋6\Gd؀Dy3(3Lz}"JOسwtʵxrRz@_A51Nxc | E4IU?r-J2fQ[aS[.Z\W0frq8f·,}aY#|YuE .8J|f*r"3K 8`sCz\3dQ_;vCEyܵI(E*ݛJFGwo42^x#\D65Yb NLqUWm.MN:zWB; >"{$ R}ƌR߳V*O8;=DТG܁A"%G® ӧmjP,VBN l1@,>H4 BݛGNkBd|ߴп25v!q2㧸mW_&A[ƽe\p͌5s'p8IJ5^bA~{^IÀ>Fi.wX 1NGuPPax9S2Jϓ頇 Qa2=;W b9biVSRGIb]jR=cL~_-:ʁg+2t^-<2 sf~ro8k]H:bˢ[6Zß n @%RJ5Lm,o>bF˃pzFao;@Sj-:=: ˄GBӼu"lOЙٸf{KnQ -` )$@$ӡ7BU[z =iNǥtNChй֣pU[<׹@ (3Md|A+-yc b&J+Bqv>ӄnsQ NicU7?ng܂0wvݘ$[%yUMN8hkTuugrѸge.I{By *!4+m/ԧ=ZYl;(9|-*ҕE8E-LaA|:6 d#+qUXPd";$tК-*F|Vrr9_ShUi>& 'Zir"5Em~dsR3-nP;$̔:C%05Kd-u:܎ZwιM#QT^tW!y M8%'D+S~0OC?KF1  =܈nSJ7[GS#VFY:4.Ia?.*`%)~J̐P~qV}mJtΚ<JESo|`f59tD6^J{5G~]bkp*ʄܠigiBeңI]N+^N* yT+ M%l9AD~QD#Dei]섈3&9Kiz.Yʞn9RMw<0Y#5.@œE溲+W!=Or-܍ L: -qj"M.-)iFr>./em@ml(2p<<6ْ}HگNW|s.UtJ,eW,-9n,Q9OO5=DC 2"1;M3M<U3Q-×Ew:pۙz㜊 ba&0QρB%rhJDT?2Ry-+&E&;@,?0Bj/Se**E46_f#lY[[5 \VtU7F-3?_NJ[Y T}W^4S:JW:܉Rϟ$5l8/vϑGݐ04h{m7v;oe0{7rNQ-KE 7_6*~]{WBu;J(1 -3uǍf}$DK3Is`tL ?X?4Exhn!qNTirO}s"j&1ă~)NZcWX#}'񊝑ge:ߎ.K=jn0632묛Vf?64]d,wl@KL"&9'K5BDs[ '>~t%{8>677n=o=hIY}Zh܏a()[by2oᘜo8f`2)픣G[@F{$ĒkM/+V׬ۄ63/iIyt5E3=Hh1O8p&Mǣh+ЈR8F%y ^/]IPsԨ_k쫨G?`m?2-}$Q!9gp>iP쌝}w[lk}q~ a-24(Mznoy Foqw_1%'ZUE~KXVwW+MZօwZ @a]ڰ;ˑЦǥu٫Tn8S8!'cf`-Iuij'FEJ2xK+AH"QyT\ Ca?G0WOHj^=yDK`.bg(ԁPBY`hym,q%[u{5DWE9M_H)OapES`=\IEJΧ)'="71: 6Z*W>Wf8q^o&;/J&D>llBIpc@,oF]mb znc%,Se,'TrKKSZ,̓]Ҫ$5ECP^a@zqa+Ю ;9j֢5@Fò vf5|=oPkTfN^YޗeQv"u-kso 틹]IEuren&6{l="}G_7~߬WTx(3E;>[D`~0'"5a\Pޗ~H aV8 ZdBBZDtHfTq05%:K@+6YMmB8 2KHm/6;}`5Qoٶu΢9\@_uL`6ZH?:6&J^Jп \̛uួi]oZoʾSXWkG㢦{3.{xU!fuz[?D,Zݘ&r,8A7QE*0(P=* JjF1چiy-R26,ؤ-AƷLdʐ))Wщe؆ݴ[gK -XrXͮ"6\AKmQ -J$ྜྷr-ld# ڇ݉>P֪|r?F(|w}3>*'oQӿ-hQd7tZiXSEkR.XwAu[@i=Cc-.XΣuQm 8~;m<e=IX/{ƽOQu1OT>}hr|G_T'g=?y t{jd h/3 ϧ ơS^|5HN:`{ 0#+]ݴCQG"!&0 qҒ4?6IMԢ-10C[I/Yc+0eTÃtC/ij^{Z0e9MAqg| YA 9cTA8龜`$5toCQ>:nppKzzI鞵tH_UwQsL т`؀Q\Et^Ex4LC:ނ&vHV!4j.vjQ/zˎm_XҪ.@D5/`Ϟ?6?VnSc'G!,[_֕Q QKTilY\s[:',c٫J =gLd\Bt;%*~cn~ϟDA߮on |;(?wpt8~:iQ^@*l Ɨ pAw{{TX+ Д1`b9b_Z-FAhED/Vt#.[S& Oqp^5CG]cyiEb> ++cwqUMU΁-3Ű4Ffb?|@sڵt>Z2d0dpb-Q P6xŖɸt敒E7&f+'e 5RԲ ^7_Ɉ / 8x 1l (JI-V2 1~ԻtOR*$˭K/+\Au|=O  \A+h__ld3fʂ2HOֶS"Jԧ9ZYv\mQ $xn gw\I訐 8%̼U'6=94\x伩Xse200kG |RNnPBXZ@?eF@Of̠?Le^q,뽗-UY8TR=ڄ{w sɶYvQLH?wh8ЌsښUJӐ٢EMZ V'uF(8| z]HϜ*i!Bsu Kz7]pB9fc梪?jݚ?|Xʅ LqSi%"o.l+Ǝt?~?i2y;= %%xJ<Β튻0M(zM3V.ey w7p 3L(̺_NSJ8'"Fu?" c"=G-=/@4:JY3qO\ނsz?j:aJIz6=W\lV`49)_:@~a1i:b+@%(,*q紶hP2Oy?Ň=F"皞Ex->%cAc12{ޱS+̀]{9es "6z)4*S6:?Oumb˪Ug7[SGw-M7]>S'pш(haC$MswgA,`Ey`v?^zThKBNuۤ_q^=Ni(#{e(yDY0e܅N,zR¬hٖLhpbM |nv>Q:>_*2d8u)q)Eיܾ,UhKǜ=:KJZL~|:8zTt3})D ?J_=x-ß+ڿ|;(!W[Cn>n=z(Ar7fccԎ@Xy-/cٗ1W:K1 ~xKh.Qe=ֱ k>BѓHm2/bf`KKխOp ʛliXw_Z*l2=?7UvE6NNO&:U8uvu@"Ӝ$`b wѮx03n 03#,g*gpfl^c snQQvg]q~ٵdk[o蝜ٺ8G˽טb6TNsSv_[;Cqj̨О9:5k3gmQӟDա?ksg|]@G֊8rN{N EއVNϸYmϗN-/{xn12]Fvkx ӭ1ǸtyFDCŜS=k#4Dv3Dhy(Dk#0D6/Q2_!jǘ%Iyx1U!ZMl9bA=ԚG ; <*aM[ d&HSg ͵ J^.sάA1&KfRLm'G/!o'7d?<ܬ~y?п-÷7XZr*LR>|dd#m8WN:/S"+|5W=N8NDҚnk V\|g р(OrE$, 2I!/P1:n>',۝ǀfCl w2r_ʱ>UU;EuzSeGYsy]ujnٯWW1VZR,US¬U]qv[q{>UYSȃW}D+%5uGYUYNG[Nb^уّ?zk \w9IDv&\CtvgeHNޣu\cv̠ql"U_#% 7a]hz:>זQ7M&R.v%j=q+Q c@w+ȶ Y@>oA=NY$zNTOW`$$bRI/ kO[L_GOe=g|rnqƸ)T [U]+/5~/G<S(49MNz[u˖6l?j0j%ZvFAmWꝐ1Qh7|dѿ]v΀4tYv8ܭK#8[uM6[`Vy| `.m~Qrcg%p*kDaKAVw(K`];(3F,A&KS_ "v5)iˈ*CuKt:b7V4z>D,Gkktϱsm ;ǃoCˢƵ1<qo_bW?mk Os`sq9[dL Ʀ8cZrz#km]ZK텖G,FB@zNj?}8p% 7F^oc fޠ[c !G3u@>^ɝ2-z9/3TF臮c%07Tt#zB=ΪM%6YlUwZ%4! GyX7P ^9Sy\!|Iߺ^$ 2-NgIY&l F[PdMd 5$(T:C4LO%kM)&W$ vD#Zeݔ^1)Gdhsd=-H?&)9"8%fRJZ/N2F{WξjжO=b4K63pM{39 ɽ(̴CU1&/7g 3nM.01#rjWF? @hmܸת)v,P#m&1*LpdZ'TR>SD]^O<5>(mX͊0fCyOY%ev( NϷM Z 0yyIv;%FW#BኽzÞx^pqkG<` lĆ3|;tz2w{ɹi Sgfg{OG$ξKR"fEԑ \B+ޡ%OCGEBq :à 9g[i&̬ ZC8_QGoCt$778(UAa\ylgYq.<#?^4$(6 TL5uEzP/^e0ܽӀ "wj;^a#43r2&73r]Z6OO *QntV6Q 4 _K5"7Y<-E\' ·mu2p-tRjdb5BY;ܠB2QQ,#KPmUƳʇ-SbTDC~)etQrfڲ8,=,{*m nR):%`ti@)_'CWQ$XCg@B3 n  џ(I#$\Q,|x E4kK- 4病XdP^atR~ȇ74%1m8tyDH7vEϬD xzg,v}%tClz'C!/v6DR:"kу!wҊzlnظk+)GLd*SÇRCՂZNznkp.<Hoi{*ĜyhlE <uEg{jgj8ℂX|hpYkFXb֐8u]HE9=IEgd1s5`ǭ(Ki4*T}4ȢhY )'"-4 vj :׎o J) tCSoLMo{k{\Ke^ Ԧ(7#r%##3+DB搖=Cᩍ_o= 3^Y_<[?3w*;ffG?4HcV\u)|)\9Ows z Ȉ;%w ]I}hYX;AQ*:8J.f"xX2)_7v*054HaZ Z1jhjM\h=v2҆5] 7g.!vWMrHe昱FMO qvgk<5ܮ%߽M׼3ٙժDN/Ʈ?׀甿e,1G.c'C염[# q*+{\#)TƲ@; f{WeS_ +ObM EyGBO<"[oxA$ߪ$u}/>)#fIGpx"ęb\%&i rPuS>'WqO8@"!\9xW7Bg('qDaT;R7J'S^tʰC|:O< 1R6 H\tx91!%āot7T>!Ghw&O8J6N2muLK888M깭HN'!wֱfp%"[V4 :'ݨwۇoZWg3J1ˁTSmxi"45%%n7Le9@GgS|6a(yƫ+cؤ#1ȉ)Y@GyŴ tyms P*:EŮ.l3=6`qގllJRkf {i*i\5Lg\dy-I=7_,ϸ 62lga%wܞzcW`yO8)\sm1|.C?F<F-.\xH>KH ŀw':'"_x&ǟ z냁 `JPf |L6 ]t`+t;""01 #! gX2< oh4OS )$\LΞ9x|U&1ʹпDoeZ+M4g)-D qt R:= N g' ><;@)n;DeXhйf^ A;#ԧ }e @-܋?W*؀J"_ă5tXXl2,6FܧE" &5ߖ+LQ?xtw1.2jfXbZ7uϤ#nS01uekAֽWB:6 Mn{q (]Q@g@\ʀ-{:^'17 V FW0ѯf-T,%;G~ ykѫݦ./{;vX76~q 7.^U?::~ QPuSC-a tx+A{܂k 5%&k]v|<5"~7wUhKQm=@h Ė;eb2?XNxq9Yg gpa? =Hm|9bBEˢggg=^([xGpcHaI"?vwС&iĀ&/U~6q5UdÝr`T }*B%e=hkڌ6=}ӇEE|b\,a<'(D7fηO+qh8;—NVq0ލ[ ?M'׃˾I%R@% r AV(O$^ e)ؐ?y۽íR{IbAoX(h]n gKٗAsg VCr= #^}><3:`50NXdE,Er;5%4!ԅXqFyh( 3tQ;/Qic g;_JqdA YzP+nnL~^[\BCt: j^vߴVZՎ^->5 *#e(4Z_G )d- ^^JK~8\%$'1P,F*kٲ'"UCx,(A G=L >\* u"L1%afFuLl3D?]5t:Ҡ,[tܗS8b 5sSkFDKDϨi8QPcҷC\P?g2nP[k5PQ>pp/-qFn1}ڋe湺Dҭ6/#E0!.J,0MuXw`_"TWŔ[x>;V7{H 6X߭*> XC] )d灃f`Yx73G:t3㘛e;/!׵~=Fr" FZk3mnހ^[Tݽo޵Z?Vu6C6?)\-6gxE_=iC&h} yp|\fیKF`A2qe֫l-)\Ƶn`hƵX.ؓJϭ[t%xV,ګ(1csOO67=GO^Ζvz=4=[)avPo:\ ;3,XFS(wR?FϖW},<de>~ʪyؚ)?H9F7jǭÃZkov& Fl!3+Slz0^Zc ۨRNd|^m#s]nv'$]oqF.5%LdpGϤQY0ceFL=nhC딊;tIkLȃ {zPŋE`~]mt:ML~A)~y-/5i? Sn{G.`U0Ǔ6Zrj5U;o4NBtQuS"ȅ }޹\*pw>ut61ý?aSʠl%(5k_^I5YM1Q`zu3*C ,Bp &•=Nqb#PX"=[rk߅e[নO'i?p_Tn.EvB>8뢒r)w&]Lw4D'MTʱ\Gin\fXh ~0*8UX{ 9Ȏ$0&_hK x[*`ՄC+8NÂ!gyO\`3 |0'f#5'e̹7ZWKf̅ir+R_e{n kYo; '%Qo} Ԛ:fD:=_ [镖T"wBtKЪ~ӂ^.bdB_u)ZcSL Z.Yz|k?y󕲖^Nt[7cnOu\:%*|}wғ@ QU0]AUoXLOP`Ƨ5XO Qi7=^G-(? # D#Z2z=n uA8hi*=4 /Ps\'\6k_ךjlGiam T1T#4d,O[{ QLŔNXdf!NΕR' EցeP=}Kw˵q6`B팼ɡŶ||vs8DO)ɕuVPrU%0FCn饥ӡ837H0 E|yr"Ek=U`m4OVF9Sr<:8pJ:;i(OcwlL81+$`8 .;r@I7OOWʄ`֫8$>,SF>=|Z&a]O="mRf闖ܝ]ZbWs5O`n쑜z̞o:W9;SY`ȈCMxFa |5!\nS&"u⺎a1T< Q5zC #KEaBdSQ_rYxڻ]m"NͶ.r2JS8So\iG*Y&g^-n>*ۧ C봰vQMG/B, k'f&cr´ejl=AD;4#epnp~h#qa Ǖkͩʣ-K4z BQ$S+F`KfѺ^1IT1K^IW 2W=;b;e1IuoZ*_kY:L!ء-AΖHq,X!~f= \Oݑq7ri #=.Lz1eplw&GNL)33d,nIzfQME^3`T^:271`ݸT,m|..b N\^\4Qj΄$"OOS|a"v.z(nm&VbѯgHLjt\*ashxpP+}.G(P꟟ꈞF+qPo=y@B LP2J1PjaiZ==lzLۀG}zbwGzU3KStD@EӔkr 7ҍgVt =&Ӯ*P',%sVxhcrٙxu0Oy+Tœn-[><zM?8Y#Yc:\?Xo~BȞ\,M&l4SZW|p0=NgB);ѝ00jW~:\)pBCo"Cخpk~$.>#Sb)f;h^r[3KԬd6z3X'd\Vt-iJIIw tgri !Tj{J:dT C+aB.) fo룪(VDc #*h)S.+a1((1K$2QC%x.30\5JT9JI|).%f/Ŏ̈́)AoKmTaT,ГYDԖY ٜyv,hNJ1TcLD =L xHNĻ\kI mcSeK L>j{ {.5HyNҚ-o9^^\߭P .#Bf)P=1-Iѕ >RݝV"He$P쟝 *o?M,c&F'g[/9r-,wDuhW#;|dYvkRӷdfA> \͹,[t(7HGԺQ>1g,qkq|@[:wl).P -?H&CRDUt'ޢB<׳_#̠^nbWy?8䬐4P l_xpJh |0==6iI9[l:%;" @-<3)ܪ3x\5VmV >:dTa_4=> λX<d{;7h¼PYk4{a8[l%# %cu/HV$翁f`+Y<FJ@1x9\oQ %,X>Rnг+!Lh8FX|m!$xQ![[cܝck\ GƦ _ݳ} +I =?dTjN[V$[#4+[|{gӚ)SgƍڀWGIrq1?{;k%"{v0>We1eNfNPB$Q$ʶ󒢆UtڥxPa[1_yDцhҬ&.ObrSgྛ>EIm!Yh+)eēƍɐedM2mgOΨ8֣'~')plVWł6ŭołϋʒ#'UY{lI'm&2> X؋K'ƌz/P 3^S|pSB5/_{GULW~Q[o,Wa*+ىݔxړefwCh0"ƁŸ KBI qyBggPLHM7,q"pش@v" 5YYQ;dJK>1{`\mt6k:)΀YMPpPdi9vq@U;,0y=UHCi>/4mR]$w1 $ pQe=n!`7({hJ|APoXL-lK}4Lxɠe)Es49ՑϜw6!_*|q+i_`Rx&0:V#RMO&S$*]85AcTaɠwPHErl"_W J:s3 % P9#N]G^rQc  K-\$qb(&A_^7?;D]w.Qq^,,n. =:%DGbZcYI8na>y)zP}CgDL^mCÃVt&H̥"A{3r@?[>ZA-y0gdz3/f!51,`^2S,qk~ &qĔGR} ine .^e&Hؽ)9YILD "6DFMxرBhprq\M%گ$/'/e-9d]2MpQ3T%zL.)u)ӗG2Rۚ:s(ṃ>nd &m0K1QHajTkMmǟiNFh;Ap "HQi{jޝ 23?ERSCuU A;Ap 4Lc%` U0cL{i@ LdX. ^:)h\ƓsdXN8F^v;ȝN}?S} _~C)*QPSǨ<8G&ɝv:f9GsL0fna&^h9Z$^Y.Kӫa`z?*?xXѶOR7B6>n`n鋳ptaND!}4FrFGQ)w)9:nm >+НkvkZd໦y :$3R')NNJ~V"7U7p%zvG/%ơs)oŠ2}i"%3zI҃5xhQi6,jS^SlQNxP…/¡3si20j?,Wc0qWJVWRc Ŵ5J@4{ȲWA=#FGVfYB6\xN2q;.Tꊚ8$d `65)}1Z߅:ۍXlJu P_bH?x`ԣ&.gZzIL"k|:P_MH-F_6mWvZ +^8кw 8=7fBn("wI>nGf 7?ouwou Řc/"E9!'ֿԟ$iaV%B]6%>SmC+P%Rɛi-8h/ZL^:ή=P#Y {&a"n&٪aFՁCX(K>2&8$y-I7&?:3;d^٘-\&(̄F :9jvNdBéE*!\Kvkip'FEhau)\cIg6nk`_tM5^~ufQg@M*-s-wPv}I7kеfa. HbuBnCh{l8n:4NopzYLi? [`*S:B؁A !SI=KWX጖T飻D-Y)6 K@ ܕ]clѦ`%jl6 xi^$/H}&3R%cq;->xzO(jj>lаl!vTn`iYz$b`\ޔtA\LG 3і '8 jyy:Of hޕkݭĶ9Q=[ʏD Ÿ|#`bM FS)c?=wlx?O_#(䚨8+!!"=}bGW Y2Hh4-g* aĿ˵ΝaܮJѡ0:nI1}q,N V&E|>%ݘy0QN KEڧ*c=K֬-I`6z̭؇j~Y!vֻBؑ d٭ORлIauiTb:($)Yp[~g4ݿEKѨa]V)l:Ɵ{,zUBjABҪ%cfkέ]jvY3K{:u',ӓo4b'WU9(6WУFr)e ٫Wiw2BCm.KFY]t\_״T .uKj1 tǙ/I R- {XP3]A]"զ.;IU=#3XK߷OD9eJa$FL7 `*G,q$ wa˃Uu AHA)ԁGDpţEy7)xE)F)Q& 2/gvƘ#)̰+= @'-;pMsjb;l6z.9#g|$5 )9FeoK5>`(H?Y)cVp0e)ZT8Ua 4S ɘ:\ DOWj_k\yj,'dxߛ9HR9Mow@EKE!YR%#YDﬦ, s1M,LAanzF||'[ܒ4)P@?1憙]g'#Fqo.nhm%b瀁W\V[p1d\$v]ʝC2oFS yYsMQVMj8%gS=n#!aP+n{c?o?f T/шujģ?F<ʯ ,֮qRK j5=e^7 > .ӹ9u.O'2'b'Q 5GO>@od=-h_RU i154p *#(Q@1\ ";kSSq !Hsd-X`l,T{LHF:cԀ7]٢jпG{≢Nd̐yԃ1o:&W<"xh($\0%o"@4IJ&2[g!\u^#Vr m*2oumMZԡ@/p՚95RA@o{ru?{DA]2/`uڃ4ðg,"ZgPPN[ٖ55 @%/Z?_6ǓVJ:{s|0 ߽yYթ1tj:p$EK?Iͭn<Sk o.oxyC5=Wcr`eNj+ %7+.]5FRPH$%3nK֑h$k]sVPh $Hj{h˓v sNcqz*ejU 7!)~j䂢SzFmmzdyWk/sLUz9T $% ѵ| a{"1hCIJrS<-2un+$p 4Թ'3ky7="8/7o1qz,GoBKK$L8v9:ΌgθkWKe+fLY^ƍͩ7Ҡ:.w2^,"OLJ:sflgyL\R$Vi̺ȉ3Yù?W":$߸; Zor/J usx`:ɑNkΟV?s܍gYES%s ԡ-A9oCYn+NeU5R+~HFWWsplw k_ zX!X4.i~qz#N-K[mҘcN]4mSbn"&Z+L \y⽨K 0_9Cr`e;HGihɋZ-ldgK}%fqS֤9$ t8Ed/#Z>Bf f^ΕӒlb)P]d\fyYŅy!eJ֡t{)tsV)/ex Q/~ aSЧdlpb7a;gO<<e h0sþ\9\ne:pݣ p^(Ƅ!d*ԢM-kG%g~l`R_skO /,)7T`6`se{x:0zE0/wW&3Ecwr@{_5"L S-™p"~>A_"q\]>eh .azzA2Qts[ls9T~1[?9kQtf[f N$a]pLx+ 5h͇WZF yߦ)-1żRCM;RLvN\;xP8m2$a`]e7ۈTi;f'1[8M"{ QTJ='zZJ?T rĂ׽->XNQRkF|_|cTri٘-G%+-X sȄ?Gn;:[~M2] krصԒ.` 39l:>'+ }I?e%9LL)y5/o8s&W>rTMQh\ [:h8|P}*\8&3DMjCµ5M[[nk6ib&q#6`+uᚡyv=@BngAj*\B-QRitQ *cAְH'kjR^۲Sޭ觮~Jk誮3[XaCgeV$\{_o\s)~-O~TNXdsdѝx ⫮͢\%B#?N YH%⺭口ۊPhʯtD*pEbП^\%XPE$Gu9$mB|i::/r8*b+Xkp_Y;PI4Q.`Ěᬙцu2m=iŜ!z5cmnc#:4g&@nXץiH4LQ{5hcF ,Q7ӨAF>/ըQ;ip 9F 4jLTxFM(\5j߂eP5,ԨZ4jTFMֶlG,iUw;-@QU5&k4jGѨ >ШѨdnCvר-l#N5oC_| h.QϡQ ȏQnF 5uQ0?F OޟWQ4jGhh5jqb#hd~֨UԨ5j=jԬhԌਚFJu*iigLfg? 5jvrFMAQs_G ۘQ2i԰ƍ4j؀¯FM>/RFYHF 5j5jؖQfbp 5jfFJ-QӨ6H["UQJU4jzmvtΒVԨa{Q 5 QþnQ\oI] Yp}ZrZM4j?QZ8[Ҩ9aGFw-hԂFr\ Z85QPhQ˯tD*ѨEkbП^5j%XPF$GӨ9$B|i:5r8*jbF-Xkip5jY;PI4Q.5jᬙѨu2m}LjBw֨1FjjhQnQ\WEski5j85W+QԨ㷯Q'FF6&Q qLiF *iN+MhԜa9_fרj#i<0F֍5j<YL5nQ~4j29|9r4jB5HQ,Qö\7Ө+^Q33 Wj1F-AEru=ixBWQk[sF ۻ5oרU}uuzK5ch̊kkrݗk"oeQɏj ޒF͙l#>5oA\|5jtkShrwѨa7xZBEZ~#PF-,:_5|Q,5">F!!hkLsѨ QQF4j\K㭨Q%Ҩ-݁J5rtQ '֨/g͌F-`|fCihc5PF4jnW?PFrC*(]F'OQ֨5X?F}>5j4j1Qdhxc5GN?5jVpTIHuh\igDh 5W?FP{IITFi:}ڃtzɃ[cccǏ}>ύG)js[|Dml>~Ƿ6 %X_^a>$OQ޽>`='bFIe@AfiyLh6 J45y} 9MY. ^^6]lCv?"+Y?J;F6X+=׾L;s~G頼&g"%vIQ@ROJwz=I1=3~'@Ԁ[ rH5H[Z,N716pdn nԽy@Ƨ9}z4 ~"8qx5 RB |';{{QuFSA4d*xLY2\@cl(BѨAZCBAt(fBelo47UpOHRy`Jؓ^J~Lh9;G p4LV%+oHS}C]{N {[쳴RwߎYfQihHpvo<$i%JvTаjDjZ''cuۯ`j;:Y^ۥ Dq@ €rv-DQ[,&dqGV H. `_\?]ո_A%k$7X^,,I*@JRkXm{2r2ֹLݡk$`xz@`mB 1qI8(Kx>7J]? %p*IwtC}KEP;GA$(i,Q^IA4,p߀Ƒ)y#u*2dx(2Vk>UI+>*9/:(9ԤsJrel.&6Aٳn lD(q#ydՔh$SBkpǡDF IA&dKry< P#x6o 3 Z;jF1Z9WaexD=Y36va.۳6Xݤ=oyHc6+alLJZ9op'n>y8'}g+>j࿏Z,8hqoA׊f?K?KCȕٴX φ=Y2 G2"娜LG`6gtJ!pT_Nc)H&wiO'a"ɿT`t8A>Koph.g-19@`t&}<2\G9;JF˦bh (eB1U"ӌҀ^]=]*#K#X p4Ҁ:I ۣR ]++q*M w~"*2p*e @wIxlv kIHz=Re0:lAcN)蒧:SOtl٘Yɨ cEzbWprp#Y Ixl irRYYXޟ] %a;K]ZV+Cr"5kU0EK!NЇ*&j@<0:XJ14tm\\L,%54?ʦ islp%YN\VKPí58} ޫΣdtB=x@~4Y  W)uIos&(Zm76ب<3M+2Zq EntA!#g!j8X02'I7ٚW#8Ñ GGN\miڅ|{I?DY!Z#^)7FNl 4"@.D :mbT&Se<3 Lվ:Q}93y17ll9uՈh?*ZI02H|>7ÝѫWG# __X4 `IQ6ޛf[ʷKtmX!:PvYo>@G5g]طQ$J?XLwt.8.6O;yliBQ$x% Dg ػ y0ham_Fcji2uI >RRFϷ9E~'ݲ?FݿFXot[]3-1]{:j3d~EabPJZZ<\po֣`yEE<cpҝ!iPAF=נ8ze0`*UXf@%ذw* LgcSw#@|X#Pq@1rq2syPs=XXoc1ii!??BȒaXGhXҒ2\QKptS kK" U-bdٲiY/~Oca=#mi 60:AX૑VX@ }/yILdц9,yFLv =\&n(q=7@`,uS u&[Ê$OfOU@yn^_7wO{fuԪ/m7T}HVH7P7+EQ@X t KD 7qϭ0i;YaͰ& ". H,@ Nje+"Z'+uL wż7'_w_uS )ҤxV|.P+ut 6v^*ji˄f",PYUϷ^P( 2)]{~^MC`cK@6M:a}`jEhx99yKCncy''ҁ!2Ni [LIx2wgbS$ @͝&`i'>wb=8Qȃ9f,u!o%l =$ٗ! jAK,=x~V{ cy )k͒Ɉ C'Fs%ԪvaHJuva5t̋b@bI33ɉ49;ƾ\V<ƶōa T[*oF+w(p~ YVkj}f4D׺UQLl."+.V Bƺ7>: 2V=GsҔ~gOdy |41o,>p'?{?b37mF;`N#"3_0\)&IjVBH-6aEZ&!Ko~~:O{0eHtP9ǺR1eEPL0A!FhS#|ނ2I3sxZnqYC=Jv-jbWΕ74uy!|0_E zJe"yꮮEԁ ©\,F,m G䁶 Jz1F(AI?s7&؈p %ݗ8=0`n +=nMF3 G'z?L 4p/vlV fИ(C 5<}%.OKr&F o]fIe/)IX6J/$~̀3r4B"\(\cu싻ˏ99N-,8DB:W]WY_jVInXU'kND\X0bKr$@r](]e.,YRxsNxh=0$2咍>C ~UtKy?Es V@D%."}&hoGp!TDiI,(7*D,[悵qj"ټ4߷9P;>~&' 3T a6 m0!E猥x!guw>*_[q2c o۹–%%ֽ t!`hΕBݪj0ɍtdz;_CЪ=FYR=u^ҁܽK DV kHް=k"Y"@u1$R:_ 7]v7aykգkc/+uey4ppc& Dk4R^C|_*Bj‰a70K'Git [0i6^jR"'fmV&WS4wrTvxtផ F "٬+y"=9GL}1%v*Xͦ4hVKDTmEi% yᅕ#g -:.'Dp7ঝ d{LP&LW*;]Ptfnsҿ@=o(˒sU4֭ N\TeEuK6t`/l+(<%{ҁfɐq:!eƾYFo3ȘwA׸~i EץS]$*CY̥sRh'0D-D 8/Yz*#q it&]m8XMksd.ZcF_雽uhlӷBu I}2igG8VK+"MRv8y|@'^gl)}FN.0}+̟ %n;Qr`"_'+fг7ZS.jESp6txif=HaO fo'ei@̀ԞQ@9ˤܔalԲ곎I Aa+OEĄ}  _T$zGU.. O3L,ܰ $,-4XLs,.\S mlJ\ (j>~po.ÏG8GəzL!Z "0:7Z̶W |""\ 7n64#K>H%#:%!)MfRT߸ ?Hc c󬤗&qLL7 3&1Ȇc` l4/3 d*}VM_'Z7S?wU_3 `x CZ(0 v| baI Gvn9(%ەY/* TamGmt`!E:U{L(2|FUjt'esW!Z@ή2*?D}AhU0l`V4'NͧO16:3)}龕@I!U/64X+r==DMƶXk{5?` A:|^$ S9b3lֵT5&?*?1KA{z%FKio.:ڛA[$#ycRRn=t h[Z#'Kp!uϤϦbWgK _vN,FiÁ%͏e(ѵ.OjI L_VP%X" {'7!7f:A~KyxDF67Ňh ꕐ 2ڬ/@;sx.sF> Wp܋Ng6]c.j`Q啖eD'Y$ Û[#dFT,`e^ѹej鎑ނ:3$^+TTrw#\7לmk^R[F=lǐm|qt:NWY9o-b{n,eXXh8eeXo0?yv^.#4j"vNu25t8EtJ$L-z69#|s?;IjzɺĐ^wYQȕBzZ2Gb,sňJu3K9ot_>FW4&Dhl{>NzƱPa K(J;!t8s I!Y;M0*@=y70v-KI~cATk8zj0϶*!Fd[` xD0 yJW?F-F3o3k@A@a2ƑQ!O(6u7"3H~Z&]\T*G.=IO^SEcmH*hVPҊppZܔ/'htn$NFW2+\5G0`ຖq0:YJ>\'yx}UI0ߛG#R^mHNiz^Z%/=eM6h0`q,H!@S;HcCZ lys^M_ CYM`|m-PɾGcvqe4MXruRI~6:i X)0 KnFu sNu>Dvuרz~=TkS= qbDh32$ q&[3TYV팁 2'E ݿWs;]9M#W1׾W\!Q;R^m[IbR2Aҙ ]@o| )'g!Ee*\p.JvVZ [r:8$KH(G($YE|~zQDLjn苰xsulDZC걢!\\ J\T.DrEx,\d4>ҽ(K %&pwM~Ըݚ3"@&1,B>$bQ Ƽ3Dm U5<o؉@PbHkadZ1Q!dh%bL$:nSVX۰"񡾾 ~ A\YP=YQ>+ssϼG=3sX ]SPK>cg{ky6EƹFwpU'W̺-d8: џ4.u[xZ kx]9.9V%'cǍZ|^BǕx#(笄Q!  TJI0iIF 4ZGeO?MF]:)q@!٫#ΒO+E\Cw)ais_ 3LꜦx^>4 ):lb-ζ I!@7nZ#(LVmPr>zǀ^z '2ڗ=y= 4KZyki뵚spҵA= exC7P`̾f 0dSGb)e(r* Iv%#Y e F c ՃKYK(,')Jy[5Z ))L!{`@[+OY!MvHR xMf#$(%sSЯL% X3 -% 8]õ/M4j bY N]H:mK gˊ,B˄ȴiӌ0*S86+!CU9V"8j΄vE.n^[H\3Tc9EsfA$e'w)^9GaG8 &Tъ94tFP%G=Vҩ"wJ[p# %ib8u,Z9WIG JUԾzKƓ]o`wR1BM6T=#CKWu4 ݹ6%֊dc5m ȁ_B$ᯤ ޱi^z;m嗗J+S۟3ےTmkҺi5&JfodöLsCL/SkؠAnuݱK9S Q7%Yoyԇ^}b- pnC)05 *:a4e4-{{Ps|DMwm>gxzeqo6;|pZ:jP 12&Ks0Ҭ->MfTI y6MPQwt;0e>owJH-Kg?"Z$Kךꄱ؊nQqJ@85 S'*a~+F@\֯~؃IĨܥ<2LHNo_g%]]R4fBXz3_Zmvch1`ÙTnܦWMQL|`jK(Q.i9^akD=Nj z6cxsxwEGр_%_a^m'F6`qbSwwLpgeKFM}o ٧]hznmM pEp9r|ea;yAF)- ԆW,)\^;|a 'IJBOնd?V\(ZCE]Ι_xs.ԉL/cǩ- ) pKn;cl&d,҇ENUtW J_\N3>&(pʨ-,,I;d{\|,Ǹ%՘ 2'i(*! zWj4G3.6}mV髐$6[ʻs`tҲv޽\8-\pÚr5L%2SYNb+:?v9%)7ӆctY835F N%oj"rN׫8k:v[ Z; w_kѳgX@Y\t3(b/w_ .ZB^n.ET<4xH%>.(/_])*kcf#4 쾆paPg\mn.86OՅH\TV],\rHeQi\1O6JtAny . Į5u N' 0uصuj8@Q/p$>] fʗVxtx}7Hn86}txSy\\h/+|t^ !!^!oK ܇,,͖W=M4m,pJ<,~ :)7Ϲ/`9oPG xWY]w4jT$ft/ṃ0&faLGml=U?Uݺx|ՀRIi,1ѯ{?/몶7J=?Dж=)_':"F@&.FE@py:#.h$y b6#G@Zx@?~BRubΐi 9`C= =Ӯ&~5S(!IfN,}S8aՄWncVv9[Y?;⭝Ó1%'ߓiNkOAАmpK>44pBjv;D>CPnvTu=5cw;hG-:~9hp[2A? ={@1j%k?|sr|`VoNp/ZGcԘֆe7jށSu, vp͗/Ml Q}s,uj9Mhɍ@-j vmM~ tz~z~}M{g@=$ghi: Fw?]'mDʲ $m0uO& pӞa1y&>:vG vg5 .j⩉-ny boL@t~]PE~ M@hC#ŃΫǮ665Mo_\G'nMX.x?SYLYrYr({ 2lSl<ƦzWO>Q{|?V_HUN̋.Cv,XB^i5_Ick9&yٞ6yETBf"g@0͔v*e=GkprHqoWz 8Up>L;SHhϜb&.r;S|&<Գ405jۜU751kW4wW^Ն?h bx:v-^[(t܇oNw+(CBm*#?+nHDz/i%0~xu_ 6>_}l< d2ٸF1g:K)xJ@~xl1%X/nQhBTr>\.^]tRwA%^m@Pą%hXFfgO'vYpb(Vo.G;83LZsh;SD k3gg:0PJC2Hhڨh+,ZJ6CG/@hᔄnPw"b3ܿ]VGñ9\p4vNT<= pQǽ thCtm_-5 dccE.`T_V$NH|d^ ɲd2 ۇ&.:LˎT[)> kd@S7Sжf 2ÄYl48G!~w=!=¥Vkqʹx5kXrS#:9^Ih9Kg\(YC, x]tB+綖<"'Uouh謫#Ȕ%̌oCzX |k61!뤰rQxB%we_b|k{ى\'(NQCπ .;3 JKyd{KL+;OL;{B=(H- ;?y3^1%{R]z8.<(vP6@h`\7mtg:>1 ` c,DӘ7^2HU nNZ10^pwL܉PԕA5p ~,sENɋ=໏^ X@3E w>F>;Z8U׷bY P2re"rƅ/ j{/mAmJI+N'H[8CjtrLguS }DN%lB|),{)N~]Yd\D3_Y: 9SG,gv& M#E QTmy -b ӠL/D>捾'u5Tm<,Đ^02G{x%`CeJ$1+GrFS׆d4:Mu4^1c@oFOe1t>ZH2kf'0pƻaq O.z䚓-/hk0@b*[#C.|N[0~':XDW[&K1VnOqu֊+|4üޥOFFmwD,%{׿w\ -=S;O)#мraݣ[T9rmx3]A?%XwS|=*όg$$0YS%7'<ZL\1p f$dTE/կ*EE&J r1a 8߸|K8ha:LnK; -Ayv v`\VJ -c,]g3Drߒ)R])5:\)N3֊FtxDkWUj=挀} Nf:ig;^mK*w|b"JrE7鋋[$@ov1.vJT5$+QC/iZǦÊks=6}o(]Ąڶ"ה*TG8P?_fBlo3(Q3F:Ej4XqK3r;Pk1\uQ~&@Vzʹ?dKKfj[}2\ V*amVzV!5S}%lyݲr<YK\nk4 :SDגGQcưfx/ >Fݴ1R m/앫H͇|sF'Q2b%r.kN)F49D!^nJ݈kyY7!VGH955.'9SZ&iCxr~[4F%#p8GVs`i {v&.e=dCIYbtBЈ߼J .g/~m醋pžu_SwEb9S)-t^\h%q 㜼(ϳ[!CshjCvE?`Oc㫍~+|F [O*_|͘6HἓW -xu;s}? I8|T{*)O @jZ^r0: 2 wOÝ6K`2<&7D8!)$ue QUӣp<-qЫ?a9(jM S@.Yyq2qpvC}mƻVPjpP=»3bƃP=Leӧ%FgLZrK r\ui UjY mV7uY}`B)D?/iN}]NӋxTR3[5-vcv`gd݁Q8 8Ѓ 'acۇۓ6" gF̀q e9k , 1 wXla-B^, !ѫ3IFw^` w#hcK#x- 6(ᠭİƝ\AI쨋 h-QMΆ[ϦF592*Zgk#f᎛VVpcD"7FgT談[?onW yY`}YYS< ۙ`Njoj bs|`Klwz=?2Dn=9M$ч J0X~ C J"NT¿f)9,ۡOrO΂31FL΀^fE}rFioIg GÜ2+s=(A,Sz6T׵eՅ5dmXNdn9FNyy2P'KS@ әހ$UY(?z;" 0'~?_-L/SOƬڤÅq7dr6>N8m@F24E ,~Gny%0/U*[C%qOV…'mxJ.PAE2!8HP_C,)Kw3~|Rs0a7kx^ Qwr$SW=$ڊQtXq8h>"PE;HY<bzݽY)8Wv2¥& 1n{9"Kh]ў1oqиtNg~'L^a-j"Oioo^mdr/d(D<U9>ĹC]p1I0 F rAG7d g pCWuKk~7sizm1*pc~`\#BFNyWus{ RVcН/OPTIYVڠdw#g2$S7| y5 ]`,r}}O65S63y<#ӊn,.[-Ҹ5!ʄcjq~ ڸ?xoKSO)h:(.}Й p~L_y"[PN9Pq>l mYQHL* rBSCNxs'NjrQ_@(|<1bSv3stPEROXV34gUI?Eqeg2DI2,LzB,0:yhTqB[5hc0pEA-e)F4O`:>0iIzlҋT()N!C Y`>W)kS{st=>( m2c3BjdˁyU5}+ `Umz>5V@Pcj}CE, uѸф挤0c-8 +W8CFX~e 0۔ CNÏYFkY[Η$6і6pa'A,~o?i*cD eL4vlԨhb#b cF]hbĭY iYџFzFEځ֬@WG)eW6=|9Xs/5D ^"}׮ΏH uۅcBr:br*A{s#d?gXk'~.ۓ%e#ZCp-1Ac-e hļ>>  3`$kUG1_:_l1*R Pƭ)v:h'a4~L }b}`шѰ!dw)wu| <+5Z2_] tt6@3_"41̵kX#?"8|m]k//pQ/l n0.z=5_r{<7ŕmvX^C6z'|moTfzn1)y̛5wNAW2ăÿ}$ IY6hM?e3ɛEO˰-iG8m|ǀaqJ-J0.K/1У:2gÿ4_}6ZȀ9t^â60YƿFcef Ji FJ؄| b=yeIWփ>ಁKGӱmK$=T~A~?v49:'0%I?vz! *8I좎o8\y99~tiR-e4^Tύ :6G5S~h@F!dO[umxֳfz_4fGD6JO;Sn~_dATpS Xig)7i"v(~ޤ"71b>9峎bW9C =29v.8n0T7Ovn3u /q?.^'>^'.^upRה`*ulE->6!A<$<];]:]s:kMW㚮itt- g h5x4Ft-FrPq$]_bCt-jee_t ~ n=>N: .:t~]>NkgK'swwwwYI9:..9]<]}6Lo|T7°_'; qpvuL?:4R*OSe/4OϿ9?H<ܣӃd^&õ TSϟ+-pP>zs@ԩ1*ˀ;9::hTPG^4qvw_ۻ/v^ Q'd_V|ˊOm>H}jJ_N`t|];vo;0/B0%CoK`m|jtޢ $y~U|])ӜZ1aGQ4 Z:T@OxꯀN[44r4~z}r&[D7T hurvfOa(+_S O37ӧqTʭ "MRhT)zrnE;?y0j o@y\^&F^=]eV Tn: k9Fjz[ %Y96OkUrԍ̊R%W4SF߽?k3RZSkVc[è/ьíQz\?_Yۏ9G]3w# bȊb7JL 'IPRW&r@c%Zy43BbEߑj QΕ{#z:Hd;/'Řڀ;8:a>78< [<%Qh0K'pdH l]Jf##Sc `VL"c}C&:KIttw=yOeC~űz ,`Plc}Og8MZ,Zt^.">ԫÓ1N3 Gs-1bL$ѤG9I:f?-zwͭW7X^tޛ<45B;諳FY K5EN7V@O㇏%=O1t6fx4Q H=|}љt,@`F')ZQ;oD+lJeȁ4ɾѤ2q[| H,aR80Q쏩h/ŧ.Re#o|5T]+ߦo'GoMkR&fk7BW;'Vc }{ׂwHq1j 3@u+o#l[Wr¦2B ^VtUF1&rzW;=l_sc.-['^Wװڨ8tTφP`IbIğEqZwG P\ߐ*p3QDeS@]D@obyV/h[U1JLiWs?ƝԌtjWs;m,SD ]RO77>.x5N c|,Im2 fpK{5'LI_#{G{:ob-o*q-t.{D(gI?sA]CF9C㣿F Fq;n05vCH *ſ]7ԳJ c!m`/iM'+1 |$4Sy\ OG.hlg3Q\3C=ImJ]Cȸ4^tƼnsmLF>)9O:!GCc< t8s{#('ƽ.7;AM 18Μlos>>i?:0_c4\G46"n_5&4=E8ӷ /^iϲsH`&CVC-A.QI^j5R#GeqwG⯨ ŀrk>ƝBju x0lf['`9=Rna4s'3/``^˓ 5dIú?PhPG= $V*G)ٰEmA WR.~= a7_7wO{RS`YuD.N9vjZǂ)e,z0KKZpBPK|{T9%0Qnl_#mU+|F.D!uf&f8fO';?np.ݣWJ!D 46O讽38?׭=7 `UgJ>˜+dB:1k+ N4khFN xB˂UmatP M?Nˁ}F4з8yQG_x4#KJ,?ٸ+_fOY|%(*%Xv8L.qWtYzeG "&$O'fԝAm"'?ڛh 22ǣa ֥Yp\|TVݻlќ+Ow]~Ԃ6P~w3 %F ^ȊО!/k(#"ېHвCbU똶"rdb-R76v\!jt{2&y}9'gN66b}DXX-39"fIZseX+_s@0XBTa0v񕜷ţY6ᩈJm4ow&NU+ll|ׂvZwV+41d*)j'PSC3q\cOPK,bf},lzh ޝ LIOicFa$Z^"_4CTL`6ٸG;6 U3Yo!C~ٸG3!F crP?6j 2 !A+ȅ?i!7= 5Z(x% E ohݱqnstcl/sxJS'Æ@4pTxVߛ?8ztIzID&XZQ\f](p&M:,]w]q_ GDfӵQ$Q G~M{߰ٳ,J, l^վꎸz"l݇Rh>EVX4 1?Ճ>f^1aW)W 79FxBrbu@֛Ó}7,k y?,MD z/׏ra]6{ݢ+4dz@#hΏaY"U8òaO}(uϓ0 "4;Biυ ""}ל磓22PddyQ3ʊ"HK}%ٌ@^y~m>~b?U3(כs {W7XڳZGO]\ZhB_+ˮZY(*Z@Ƭ2[g~ќUg:p܉شTfev^:BL Ǹ,ΎŪDVz1ij@H"_WLDZFn:Ч,~0W, oC_ԥJnQkmZD|)An61WO)ZCRDw-GಙGpI3ucwer FG%.ڇr x|xnt9*s%9=2i[sjCi*LJ(XHeR bj):`^B<2g)]he T4\60\9+k5pCsY:=I OAo]xnU9R>fyL[-, pvQ{Ez1j}FHtЋ0?ü 㨻Bdg^q&O ӇԚǏEEn'XDx637 D~Iͯ*g:Ly%kz* Ъ O;AZ;/z%e>:v6nia^MW,6yP[\jr"/J/Z^sڼQvl[k\\A6,Ӏl_ݣ{M+%72pNPq8 WƸ1#wMit6c3͘.icIAz'fЬj ěPeaM⎠_#d6sKsxy>v&۔zd' EttI=d sH"O*LP5)`FwUsy:k>dBbdF|nlݎػ:B^Ys SN#+ CFH(SMGc0,;n(s" 5[4hȳ!Y^iz'nBZkp2FC.𺧆js ϽiQ*bR<sD5M |krcOA#>GOC~CJ3k"c0f. "2ՂqRxm$vAc/u/X.<0jAZga 1M6 4heAz!1ݿQh Nݸ|4/~~cHSߒ1~B,Uuޗu} ysJ}(g!Wgl4u"aI/1uRlĕ}pڅhY6Z"? -<>-y%纔~GJ{%+hyjmρqQ;QF!Dru sd~~jKf8~'#}#jf#R%"98߲@To)rĢ9+kx% ,dSRvE/Op},uɕ7XP1Z[!Kv[rqu%{87f+_!BA݊jwO'S5sC+Rj e-}f4qDxvڷuͷGڴ$Jܒ&!S Xk'p;DL}GfsR%,/P4qWEDnDIg4bwssSj@ b?AV dV?~\0~{g3: sB:yKH}K?γ쐬 þ*2zcht$gM6e3'kLwz!)J}Z- +&[ ?ɥВ"oL5I|p?uMV˨5x^6j_R3'6BU}DCg#jvYCɞCM' F:?$nHƕN4稰-Ae,|;aͼ815 2 jP8}I=@+s8βl8M Xn3|+(?$lZʮ9Stm_OE 0 g:MKzὩIN`@ j?lIGe\gd^|#:4]',<d>(Awȏ6[ܿe8˨]uRŻ*p<)yrt>\4d}[q.lK5AF1߲s&]pOD@)_K'{kN'esC lՔ-`q<g|N2/GwrjkiL9ɮA -R|nLZiҠ DȢ{͗E}s)Ų#-Q`e A/^0Ze?Ixdj#pnz|' ~iqG6xveR&MfGqG ruIJ%<{MTuGb CqJA=]h3dHIH +@ZM.908HnJy\a!1"MhhR 9'ַjb(kCFF'ݫ>gm,`nwt9$q]=iNE!tՆl;r+cdl$o -UsP9A,sYRZi=Ojg\)_2Ʈ,'\Jsj;K'dTA\RJ狌&ʜ Io?iIgƸea &,[4 CeHق{DF 'שT'!CKR!HSߚxXrFR 0Kp8*XKz{R#v!o,2Ѻ*~x&&w+*>LKڔ.ҌUVjWCXl+:5]9s;?Mounp9w81,4Mepb(SM,#a\!Uau(J,8&_ FPcg)OoԬ>gЙx$ٙ({tq 2XJjP?eR+";jz<<ɮNi2^hɄGAlHM8QD8MP%"kGA6\b\(쇆h?LCR4fHE7Np}pET'+;LF@1*JY2  >N g]ӊ<*#mPQnY{&Ҏ7e4A"p*˒vAȈ_J<0'O@// \ ((*^aeߥ6^s<a?T8B=W$u>ۣcTrΎgSK5A!7U0LY* ҁ.`zHzw,Ϸ$k;5^ϐ -ˠsUCKLZ*v_&ċQjv eS#6!!&BM) '{#K֝bG_ݻ/DtNgS"~9;;Bu'=ge+G,^OM:tMQ6W@0n szгN hɨ=7AGօǼd8o QeȏKp0p4ʹxɞ٩+||qq $KH;u>D=+wץ74 R弮Eٷp 謥 r\@# z(M4H^ZowQԏ2u،e FEo>񐅭dXX, Y/̿:lxJ޺q4 >ʑ9PO5m2UpwwH)(tq+ТkReH@,ş^,&4v3愪\B:>=ާˢKYe)T]>;5a_bכ/^ױ cd<7"@F}[i2E3#HJmֵSHhs+q*Iu'(n|Ji ‡Y{oZ\ZWo|%f~>6CTu/s*)E'舲e19!| $G<ȡbNImUB:0M8s~ҫtzӸ{l "uߋX7c|:TFAiUN>wY]PXctDa! f9\$"?B'rB$5!|{cpu p#dI`oXukPkQ `\VH fԭB&$#Ŵ1[ Q+ݏttߋsİ`vsDCYQ7_7ވy9}Q~jB席g _o:8<~kqMl:BR4atNb@4zK,v*:V6 F E>D B֜ŶRQLJBPJd"n X$K)NS?Ubu\n~kݏR@閮awqLA<ȵ) 14Hhgî9uލҞZŇm\s61?,[$|d#ɎQ$c]XZpwK LZ̧."ﰫw,v٫WDW((<:A8&ZHp CvOң25uWM+ (QBx́2ع^Ǯ$;myR UylGB ;vMC ղ,DsZ|W, ;ʉ:Ŗ+Q] bh@>tb@o˷z-|7-1&~~vrw:NO6Fv˸Z#]hU-Ar0ɥD4sIEN/ 1L0b?BN:/@|H]ٕ"ɕ-c!%h m94Wf& b:<3^HҞ|p8B0GR-o;^Vq 0wD1,Q&c6'QXd>V&p}J0%y^6"i %J]<$xIqTt?)L8 Y' t2Wr6b$M,"c(htaM rGGja(o m ‹*HhUڨՆ7Z__'#~D Ei%PpH\fH "O" +9]Z8SFd: }oJ)Es .&]FRVgة5~^MYygi5_z3t:IOg&_%PmHmcoz}!_(:9N-jl0'x@>cy\'ia{l#zrY'|LS[T'XL7-ܢp+geQIgJVKGOby டfto EB _qpg/ M(Q }} j/-1UZiu'ZDFgmt*篾oU=xol*$,K4N }~1jjx`;8pM$븜{#/?Åѫ@};>urZ̓jo,Db_$r/^!9X^zpހp bbe ѓ=amn֘AMʻ=ڸ!j6:7Ǒy1'r#A;olN1,ak_iϚ:cYl @9?ǯwzG e ~}͙V[v1^?+4?j'}p߸^ore1siiUѣXBun'I!.Rg b?=(H5M.վ_SkTXwŁK^WNu"~"ZwVi8ac { Չ m٥D;h2`uz1Gy'ɇحۆckaO:Єa-c_Rծ$>:&ѳI= a=NgǽW;Ԑ7X{XWW ba9˳I1i{8R|: 5fcL *07Yt{ҽa! ~XA,]x28y \m6j5Ԑ tTmZ=34F#-}x< nZ{̆ 5.cK:P]uCk˛X@rQ1IǷ.ҷ6p'S4DAej.vlU f7`-"p,ڸdcC'a$"Amɀdjz1]i4iYS6$n.Yin33K4-4rd̗݅+4/4?Bv5`ewRsy,᭚԰ƨv֢O<("U0̕IùZy7 GͨGb ;2Lٖi>Ȇl3籐/ Q:rlY~mB"!;uй=V{0+h]v/;Qa_K֒s Ԧ&×l B 2f=H]Lؕ윗x`8mDso$iޡ4[-_W!y``F-y!ec EJO8w5R_J:J(c6#)Wgz-K!*VlplDCʛ,QAC*M@֧yCIx7ya O s0'c-Ήo( A?h\žFfAUJ&PbE[#@SkaY=b ϕ{-dШ=zL_>@PNB ̣wIM dfNĮ9;Ċ䃱݂dM5¼ATNඌXWkWEnáN..:/C 妣t 3hFS˼zvι9hH}@&.f'j {Bb^3bg%iGyg^PGĎ,s4ArCީB[ж:@kBcǴcn9mMLJ;zCFھ}K Ee❜6YPΊV]P.gX ؞h:@s'~ej!'r-Y&_{ͶX^Wa̧_nlvYGq4kY@ 6dS-_&5Pz2R;7wXhsWg6"Z,.uifhi]FI*28&MsLW`Rqoa-6?jL?YVգV,q4z (ز1|S$x&z gDst  Fg})M\cKR$A56\!jK&j{O  n6bZW?- _tp.0xPM4X#1k~:l8Mj^D -J.ӌv$fvx Ƙ {WZX&d֞m ͍/p8F_y^)+7?Gݭ: )g4 bF[%%$ 6|41F"/ˊ"^ $HWK]wLG%s90(X%@*9tk9IȟF?6>˶-E(bc\ ʗH{j9.0IRd14',A~bJ}l *Hkˎ}]f#=}H6I a\ ^yari=6xƅMz ]b@{s"NֆByYx04ADTDc1HEMs'k_R". YƬ gyhE @Zj88%eC$ h(rd?1 tNŭX+HnUf+qn{* K@pli.1; RB;Aȧ=2Bz?%b?euHeb?C>0崶Km `q,C  zF V1HaKn%BxOtNշ(Ry)>,Kh#SnَZHu1=uZ{c 7 T[8j$jpdȑ5)j`#&NZoe hnؾ@D"QDj7Pu4Ij#R./el٘& UÈ<%p1c<5;:] G*tC@ q2,2mFQCICDZdX MH/c0b]`Q 4RN1m%MoD˹#zɞI^nڹxhyPa d5.ԳZE! zQ僚Zײlv=SpЋ,!%$ѤBpҧv.d v@oX}/)-GGaJ'~X16bH#Jy-L-LXɴ g%4sMϼ1/[mj|[e]k:F{D;`@q ~B}Cӌz

J >ʗnqzF6'U܂V= ʢW} ևUɨXBeBYi(ɤ(Ouk ~+v_@wOk22teʌh3Sg%;g*ǯz?B/P&.[G隳i鞙ݷWpHIك Wj [q^prHƢA;q 3$k60I.!&qP1&"*QE!v0[ 쏥 Qc.SA`[yaF27X#tZ@:'NKq0\Jr*R9NM :R`jn`gA7!<CR4d_2DĬG"PC^xe* IJ=d,2k\̲}0d/ibGZ272I~tڶ3</K5{9!U16sҺָyښekE*#Cm!!.1}QSVz=Joa)HJ!#Zf~B9 ]Lxp< [Coy8baQi"oSH]։!ۄ@$U3-Ha4&eH򪟐14.I7/TrAb6?,; h?,u"xωQ(Uh$ x`?as,gJ'Ip{ALTNbLb^X{M:Ubn[_09eǧZW9 ] HBhX/ yPMPE9t+c ;M2qZ/;<i䴋!wX$;([Ž9%v:G&՜%q%w%o]9rTXn/A3坸niݕHdL t1vu1YxW?#Ƒˡb̅-wqsn&ϯz5&qByrݚҗmU~j%En+V%i ='öP-M)QFGe}0ߥ ?v% oj,3nx+Jeڿ&r MP_.h7n.1^7m̒ u.Bql RGa4J,)OuN%ѓNj F#ԋф< M{'(=VSt3ǓXm [ |Ӱ.dgip6U(Y/$vip\ks:jewU@n[SuTHCķy$h>ׅh'$FUkH`Q5h۽wo^69֕|9õ˞ w6uPRLxH9 0(0z2[a:1ə/2jpEeB8%Ex3n?0@` -dAqOVVؐ}ޏ=$Ǽӳ; IY\W,-zȉ4 *HYdIѬHZ4p9&#)t, ?#<\M!J%$j} -N<8 g U9Eg:ETG![UH9< u N_x,rXwrF9ۋL2!72lw2_ݳlÜ^~` 'O)PSdaN3F ]xNzlJ*E[lb]WwJ]̆)65y>4'y*&9 4GcF)Ԍ:QPR)RW(<+dގq~*Z`%2S{4k+-(Si]?VF/0c2vCDk5\KRV4 l,`Dc$.b"EP^:h;Yk/163OAvomv 9}KjR2[g!3GDWrv-V+b:.>"v.Ju7X|M)ν} yN~XR+- d\dh1)?"YeGY@ʠ*T^QL媅 dg-E(Q}8Q΢m @z\5((xP>$ Ctj[+*JYgdnAHaRU|qmj6R ҚAW.Wآ<"1gKsc! k_ ?Q⺋[U^ys?hbSJG ж18gPiY5i|~@<ͅm*6G,=Hc6~eڃjӍ$v]%'EX-KԳJB)_kٸoǶyl7i6p7i6c"gBΞ@ӕ~w ¢U9 a;us@yN˹}F|Xt[fY-ƓG~~1}nloxG[js[|Dml>~@ m`([be>$ec eƣ-Ѧj@E%?Eaw]VTl~7C6ԽN&iF@2"YW hzi&79(7 ےz3';tWlR֓d.a6'S9K8podWqҡsj6Mu|䇝VuZ9+jp:V;xkdy~?[j5_ Fw^CNG/ԫfk{Ob">TGB!wMu /ZP'u F2{Bj vy99>Z07'8W1 Bg =n@&,i =?:(j /DmbkP*cP;c 6pDmB3Mnםo T-߁F Ȩ/{_;BUUX1~`t̀AX~z~}w)>r@U,>!9|$<'3VoidUJ &C(&~m4C;BF)ۿ5vt9I^{݇'?E%J@IQY'n#?nw'W@v򅊄rUaبs"72doƣI;qo->ԍd )%bչ?f/sÇue;(?-Y.KvsX$7> }QItzQkOݰLykhX<ןk&_!q x]T[7V6Y/GtU럣%4,GGыa٧!:㇩#j]Pier!0 œ[;~PYzWB,sdY-r/QŞetل/Viybڅ巫*bR Ұur8# ^O ??˨c/?^ۦiխZmlAGp N᜖ɜ_q* K4q?9սhLC?혏LJhͭ߳*|{|{|{|Uݯ5k~]ueN~>I@OnAz"|>lVl}?BxPѴEPܿ{'XEqaJ>&śHPu$KWo'SrNM4F8: {:Eq:SY\_RJ 'Sl'!]ӉndwPO~4r((;{3YDM=bȭܶ-I+u!enBDwZʺ-qճJFQ%Q3elQzLKmLEv:Mʘ;U$_[ )zw•p9-7` Un6yewÛsBǎD.kVGgL2#?Jh' @Q =c.kw(*I&İ(4aLg &05ok_&oYMHVvM]Ɩ6zc"gb1x9ˉ$L\:X1G1*eU9ЯoR7py0bCN>-<ǘK̲ŋiO\[x#rP‰|9Neb-b\MjɧwպfJ0 /).}Rr`.uQ4R]4Pl2dW^qڑ(9Wn"ߧ3Xe倃i|^ XTW5ki&(ۖzrJb]Tp=bŢ^ebc7^[4t=2JG1չ,^NBmǧ Ǩ!:1u="P'gvQ>@LЛꋳ_#:KBYPjԶ0$:i\ GgYt4I1㼕1?"HOuD%4H"`Ϙ8U7d1H[2Hz$$d F/ݏV8K!qV06;t]M=p?!j}SRpq&mDttPp [#@Tڄ b񘌑xѧ14DRW N#0%VHZ'A< Fxt] -N-og_E5#~U|6e̱5LFl hM;ƍ9hPXi`Ә#2TsNُ8fkK<{  q{x"9Y٣|Gݳn9aP^{i|9`6uꉛBA ?l?@+ [qz,3AHs@DOAD ^4'ǣ'T hDGh2 DJDJ(LٙxrNӈ4$+.@}JeWby 5:*hb3LZ)$sƇ9H*k'F<523L% I[[%FoN*e,eD~5 z,b2Խ ZQDZ4rYޑ,XPvpX`B>۰s^%H&v6~c.& ߰E][n-=UycUXNQf)^A$F+r{(vh EVԮi]n9jzRށH_\:aUZE[ +唽f"wj<5_] U=\H\<|6aɥRֹ0* fM\i-g^,윻<9TMY{x=4T㔘qW, i02?" 05qjejl<"(#5";%71 .D}]xOr;ػ#Q% .T1 秈*]\E_x[薢v4ዔ,4BBԝsX 8  sg bj:be6eHX=DtpG芃Y_a,s]T)4 x3xJgMPf%4my(B}ko:y}2;eԖ2=~N{ֳdfA[3FuUg1BS_]ZkAn h˚Xg4s4}l7Z#{,CkDRdRmk}cօ7"(vFэyevG~j܏|fr.\ް[$a%ԩ_s$gMO녱(\ހՙ%Z9S 4ܖZbhw!U`L LFԞ;#uf,~ØW&٤s&qz92XTapw $&ƚuvRkLi˴~ףGl&ï_zQ TID>}V2zK`]#s|ʼn&\ExO еϖ\3;g=zTS>g\}2¤XB"7zjx O##fX\TKZ߰Cס4&[^T:Ǻw;88lBGW젹< DAh5aF7pnN GxEE$!zY(ljC @Srt UGS+q q-nn *K7ik7+(JpcM Ln)%*(ŧHmQ VKUg1tR-N#Αd} 9r:zc4moǬ2u XV[혃+:@E د2,Qro+l}.]ڂbr[Nנ@N{/Hy X`fFoz`.'K8yL 蔵ЂˍL0AđIV,G )`~ѝԛ6pe!-pyՀLs}{b]YN7Gk2/ ZguO۷ < JYR`,BvBdV8:$MzEE5|=0gH8x\0 V$?,G _Yκ}l]8{ >LǭbSR^VU5KHS'%enW yfp`2s`R[=).[X=A/,Co<S߸m-51wVݬ7];{{'S^RɱO V%EV'@S9Wk.@8܍vM`e^JTċu"sdGj f_4pyaCJO9@sL6^{a꠵tKE9d0 .B!ĕpC)^#n.1M, V+LeJ܀£nLvRK8*ahe _D.[ +`R*j.r=e͐ȁ+. E.M`Qɐi cbadeCOGR1Qqn|p ӅXd- S667bBX Yv{, jZfVct1 ՝A@ 0[04+j%x0#5a+rZ'5/p0H 5#m%Sޑsk()0YPrJ(LԀ3ݏ֪Ymq(X㋨3‹#92&d l I=]cd᥄NUA|)𨾑pHwA_x5\VmJ 2E4w6ĭdB+ l Umd$¥[Ht6H2^"e:٢'b"! _Sᢞ/d:t*p:%[XdUrGW$O Hg8I$.xF@^W# 7O0T|[7_6YC-W#_ `ls=1$:71)$}Ki ')4s6%Xnxk`9"R%’R :)R_4t61ęCprað;[-g1z<1hq֚i Լ +Kj!B@U}?sUlAqܾC ԁ?`, ]jwzyµQe qb/)_},;("d'(gÅ2Sх̍]RQloAw hMִNlɤ$~6V&_ iAxW/-=O}l%٥mfvK-Cl},ݓs"\Ye2Z #TÿJebU] lfm]:~ "{ >"|0aU"l)+x"jυ,9HC 7-]& ݝ_R~g=]ԆQk-ky:f7( !dc\Yi Hd턉PYrpz)ئQH?GA7$6%T=y[ Ko?vuK}aF,.[@q8鱠 v #`b1Fl80O^QPB8V+' 9)t/X|%y%/Y SېV9g hh9%F7Ρ zoɷy~3n*J"S9@!5`T%#~⇟by]Y,1_īZq _\A6f/JE !I0D û>t7yIJL^31HD<-/%S8!1Efv#$ݳ2Ln?._hG\AiC:L>40x6QmLOZX ðn/sQ$Z$9 P#aL%?QRLK ]_)UHsb@N]H W;(~{Q"-kT>چUȉ nyR0*r#u¤z+\4)NŽŮ4ji7A KݙHmhpm iʱ)pzcM GAA l'|)3M]I{ ;l(5pQ1{4I[CNiEug<Ù %'8L7 ѡqq}e戽{ P#rD Ma|j3LB+~%l.<FN!=;9l'A10$3SdVyfCRF\<6p=**COnk6x.3*nK LJo@1 i&\ {G;;]s{?6jȐK1Lק|*euthPĀkHlokjQI~_tg4ry^ *RfG*VIKV_ %4F;^0Q].,gՋQ拠Bp{@@m4ej:pj۽mMt.[/,e}L1Mud/YT㷒j3:9CD4 4ܰ C 0{4;5Stclpgx]׽ȋ[cΝ@˪cblF5̞à9W1lCf'{.n2PL4VٜCnx!#0 0Dp QIK|2n{Gx2¾!2;8tAI۽&({ (Sf]%B-S =yZ{Ұy=mY2OQ+p^ґE^_l鶃GV7ydU!Fu 4iϷiC+E7e]Y'J$Tk˵ -VSݴG!LZY/c`:toU}Yg:8=i@MubK>$]4@`%x4ܭZϊsg41, -D(gUP'~!4z[nZc{QWz:[ o~>y܃iV+ C[ǻMu芀 -UvV}7!RR&%ܷ @ 8߃lo7-C\py%ddfa$Z ! nh-ijZDɧ>8V'. V[] A QxQLc?dOr -S*tnM rfwg3NG,< :tYNjY|t*J43`^'QlTV Ec‰\MA3FWkT_ A&F y _wI$0^U)ӌrL3FWH1iܧݧ}1>WQ3y_qEΉTes\^|& [ DޤV^ܝW0 rY pwQYx1AS e#=9Md ό12D_IK$GYWS5MպSh ղGb_t&e&j488xٖݣ5Xd#e>T!;㬫dfv"ơx=ݾ&9 83nF%`YSL4y3M#;hVjif2c9fLg蕎l*G`+p >0y cż֑*hl4(  kT*IZ l,2`qa:Nߊ̱=/I 49kaQ]kڽzki6eMu_rn{ڙ8B$*j*x3q<fӘ´cqv"2j2L :bYJ"SnL+J}_4[KȲ aWR+D/75qΡ ty\h8l L^EǾ 6A8?6]k qI4SQ6X^$ zӒ*{YuràbɻGN H=B-zGFȲfo@ L yn$W$ r;ujO%&@e[^mۤ嘢G2Բ, ʟkHG̢B`}0uYY;nTkv1S,i] qF"Y9.$J{(aoVZK2NAgx*,D/q+ q YJ`>M(09)=c S˫J'q>1j fMqYOP5 n)jYqr1Čr=bb~bskK =[$=-d\LAΈCCb,[qLwI@Oϔ$OY[hQ L81yYw̃(cOswu1R:Dl=/'?Ѧz_l}Id @ɏO +KLΔIOb%); w$l<+CHL80r,RˠnPKBY-OiKRb WxDqHn8=*<^yO8(}7Lg~VƱǿ9Rd6>gGvZzpkPp..JՀ 9UVC-UWxd`0Z} E4hx}Widy Њϭq x&N$u"09!*LL4y9^gCwsAcsbҁiYN-YYs៙y]EIZեuCFOdb(ъ"b,sN-Uʮ \B>V}y,;1U΅3-i{շ֡U \Zt =ceo(AwM rtā$'=ix*q D'P2A( J8b6^;6.G"yoo֖!kC@*ğar!zHI"p>k]+l*^ A?#|QVݚz`~N:Xhô_e]_ .sZ\lKݱ,N-b l⎟LOیխ"u`=r(QŊuvFJyZ.+5]tٖV@w]ۯ4T{5Rюԡq6RdD(m3vtȴb64-"h4*s>/.hՋ\9'・d+1ȍ*US6^pGz ^E:D7 踅+Zy# {&:U?9YIl+H "ޣ:tqZPaYFvdvsFQv`=#qLpb[*F&%wª hSk3Y[.6TLnd5oeuSJ R0Y'ױ[$'ѶS0. +aOb[NCp&RI#ˉ``!'>E54??47{` + ݓe@LSUTC=V8gG AbJlɕGqֈHƜ_F$.YN`< F#ܨҢ'θ+7agYb`>xLg5N˱ANi2(Vl\g̊ػ^qwLh_?)-Ø3p~+ /pmWԭjA>_#lᢏ[R1t B-R(OKd .Mcc&TUE8%wLVGm;/ɍ4ZZQHkD8-+#F&l3Vи5Ve jFLe*tSDz6KRfZ9t$4,ĝBJ/y" K4fJbq ee& l3A `YҺ,-#U$Я)$5_ w ܔW)ܭ+.786}?Q}#9}Lg#R`n贅L)} :+  B<}~ŗe)_!cTlIV>ܾ\XL nS։֪8GJ^jm7vL#'cp3ksf?x|^K4gPȳNdj[#gL Uc{({~V0pt!;j(mlqp6< tAM@g@j= b:BrvӥFvKNiw aGȯ|iG#H .I!t}ZoKʱ?!k)bj8aB+̼!tL2^b.8*7cՌAu}2 ֯®n iw<7U Sev.b;Ur ;(KS: v9ܺVO 9is P󧂻1nӻ~x01k9ѣ?!擙ك/#s.0RU׌:adgL1AQc|B:`!m_N{nTApq@>U,`\C@K1]`oDmSʙTT*9û,y˹7 "tbR$9|vČy4wT$3O2Fd~hl4~?2 @w*YlEK f%Zէ | 3Tj]M,sF E9hi 0فҳU`r5Mi%X+ q| D?RC&`ٝ=:x&{~\)=V,,۪uP #ow|o9x»=oZt6udM@y{|T[IV_c;S̓} E p›-{OϦϘ(_54?@E%mϦD (YHM/pģgI «XIO%Ȁk+?걯͎J]X#{;[pk8.mݵ?骚so\\Ney1f}F|LfܳTð.VaLizH8p;?b0q3nQ wG>;Ş!RR+kDw쯵y\ }{d1AYs(geBJ ;u2ՕsP5}7NPH3]U'0B|=7Cл肣}seX6W~ccݠ1gZDTTXG[M`=%~x:b10ˠ 5(CiV$hb,چmDŽg7X\ &x>{ \Ž`ti~lqcCD/Oѭ9p @,ԟH;QL*+18j4qu/f8=rjZ2f`|°[*piVt/c#jЋ&kXɒ'v*F4^D"ۊP@"+i2I`JQLqV3gS$fVJ[cNG2$k\GHf[h ~#!K޻cX9/-bOژѲg < !vuz*/-+ZL6X daX+JpLcwT$]ZuꝓPr铲ݎS>w;V{ˊ3L9PFa߬]*qۗn)IϝBQ"sQҖmox̴OoL27_Ox0ӚEpCF'*Zd '_X*.~'x(%2؂U6@~2hΫ BG?g*sV 2|\&7߿o٥[0:+ :.hv0&Q\9b]5cȑ_ U&l,Ah<7/Rb9̑W0VKb7aŔVrьibn: Η-;G 's3ir[k7Nc`%X ?'k`ݗ ΅;FM]o*AꉠKuЂ}6BtLE i $3z3ϝUP&_v/E=L\gA;D/h48+ݯWV֟>{^_(0&YO;CVWy%#{fB?n@_@&,ٖW2|EY~Qm5e[ CCY]XˤVikߺMgm=Pf U?ơ=쇡'^o[p?^Fpe,ݤ3T]P+;Ru\Cax e$K3p0+iy<7#K Wܛ0j"e n%\XU\J-P&""^V`fƞ*,6^tp""n5*&@[d`%hpih kI {Ը>֞,6FsWWKMdIOZ'"0Sf&tİ%lC*YcV!Tcgzg?.ZK5GfLL~3qX:dUJU?@oq1@yDy\Q`Ϙݿ4ciլM#g̦H6-m`Sm.ʗff aXqrE˯_s/#q*2P Ғ~a /ZT'_pe#wD#3 %W0YXN!|]wkڇK[g[hLk*ږ7qh[[u 5uslLW6Ֆ f'B#IATƣk) \z:hN ]85ui'"cN.m|r EY8*͔ dŧzaq4fT`d3fScw 4S@_`Taa~+T?x=WVppa%"ڗۏg F_e<~@w-؞}t}M/a(Rۣ֕/GuaD2aĥeRI)wxtDO` & K +axO<Ė 9 Mv,#Sd7)M|c`…xpDlڎ+,am]s@S"VMKkҐ_&ϖAZ;Msw?~xI{V RfV뫫}Fu^zT=]=Vףjm?!5$;弧T#ol0a{~1JցZWk(Q?G8LdawrYQ>rϠl|P+GriP2u%tg:d0:Dc^$JT=NFC⢫.dBfܧT0nc=T[j)avv, ЌW1e:PzX'jvGя&܎%܊7}`֌ncaݍAchys[:hmlEG&4d=*[ oGk.hs1l^5hE!ӛfxیT0*Ξ|!`NnF[#qtwpﱹC1ֆeVj܀D`i蠁kylbkPw*@C\!| SS?}0xK<% h8dqR_;_P%o&xUp=|yHywy;rp?<-/ZEe|~8Sӏ#'n6/.ĭoκcJњ~~(jf;Ad»v yZGI5'TӼA#r2q=0]ZFjy7QhWqL4zG1Մ D,.Ċ2 2qnAr]d;mt6P`yr ;\C+H|A(X_P4'p}Ό##42/BGG!1%K&wWNIys&dʙTpVttQ8)D4cHnlzq=/Nl199"E߯j įk-f8D[ilZ'3Ru<75NɺFWq JNJnPY+kttstcFGrAc.Bp1,Q4BцG_sZR] hWw9&_-*o /G:h`},|ay-n ɟ`E9勥d+qFrQmެ???Z}%p:jKRxfRb/Pzh\`o9B9vΥaZٳRL9y]y&6;C,P UȮBR4' MB-BEQ'sJit.*O>i\5m#i| lM%ׇr/&BHUO?s9@9 -TFB!'[;Q ]#[Nyj$ʸ-H^]ZtUKn`Px@蜍xM~Q(1!# +AyR(p+L>o]V"<Ν? X 4XD>ç&0X'^>~*&1cf{- *Dvy靄gD.xpF =$\)?ZduN.jnK.ȷ5TWvƤM B`bd] Q5uyX)%d ՖS]1 %_S\jrE$R{Lxj. } e jj?ruUҫs9lȆrL3Oto3 elGX`>W( ј<?1x+Ecʠ[ô_/[ywAs\þ71jgS]}#\fԂ=i)E# ZC8\Ih\  .33~?V7)GCVTJz#ҢĦҸ9^t A %SN,hS $4"= \'9=b6U_AYhPJ`Q;l4 ]BPWRg47ô]Z}eWj Fi)ueu"W T`\P!"ۈ+MnpȠ&K]4]V29,oHt4VGJ5}Cy_Q3͠KV<n4æg]0l~FyGBQHc/Gl)c!O{YuieFxUt_2B4p$ɨ;;0B)v tqfYHwe*HqoiS!勗٠"H@!;H-Ӷ߲)^~5l"UT q|uxtpXpOiClmyh\E{e()RHO?1zH6 aEV>g@Rr3P0^Khzu3 #=; r6=˶ lI7$%5W!v5«mri=LF81 OsBg&uXS:.(/t~p?D. %XQ0q-̃]qx\:mlЦMFFKdu1MquVG z.=FBK `O!Sc?7o)9E"].]TFHRYD Bk;@O?p:ri:1b+P%-r>˖W Tg#̚P^[mV7`ǀk PondC2:\ &D=KYKl˱S *r$]Fv9R {[ F%$>$\I Jp#QUMap VízE{;MxI\\T5}RInq/#4o9"mk J*)BA^u$C9L,]RIB@er'h۾ sr#;#ӥf:5(Zzs<ˀdF"$:xSùS\K%96rfVz2RTe"dY]X@t.8 l(-@\?< 'Lpj_tJ]'E‘l葦$:ҽd~r,^ JƷr"q dQ),:q"׆oؔձs1"yY^E2G8rT }+j,ƃ.Z C=h'K}Ţ!֔_>1F0oҨ/:xLg.׌R,*/Gf,T%[D7e%Q}zrJI䪲26}6a &@W44 P27n$<Ix>$6EȊtI|)%]Pqɋ].Q&ʱػGc ж4Dqu&nt% /F4m+Y9X3Aᑏv7O657/T_V݊qaz5"`;~E*F([q;R(=`ND#5W]2du'" QX[c+Am?TR Lcdt3Z݇-JS-36CA6|ͽ3 v{6+qV<u* 3a J$UiXL=B5+%[W|"pHm8b\ Cӱ) ,Y sjožZ}Xx\o9 h +kXzݐy.nUuiY9ۍSe xd";rd* 0F F8rx9I+ Ih1 Ġ}Q__!} "l+lnέOu_R/rE_<_M~,PH\i cY H{o[ w64󁭮pĸJccrbUF %} S͙UhZ޼^HOѤ9ZphV7x=R4ГVc 7QgZ\}ՌqÒ#.7R#7!Ģ+6Ӱ斒{v*$۾]rv?Y'CuPNW%U2x`3%'k΁H:j']v maLj$@10<[Me #eeȫkD (bKl!!$sz,Bl_j?*T7V>lJeN d*-˕<l:Vˍfqx92*;MxA/Ky;m:i2ɦ@QնSI+v2F4hκ]iCAZHN[ma2K Y.N 6ޢRkӃ4\s6ji,JYKNZJ%(l;R )%UbxDJpؾQufT iu0K3#<3ʝ$ i JUNJ$ޞ1*#r,[EfVLh U4@-*XG}QmZmC<|7I ٵk2VCдcEΙJ)PGuH,D2݊,:@be_u_jp(Hឍ<+߶on |JiT:U5 ?0qa 9l}F{N}iK $Idbe0.l4+AMg9crWrFXVl%LԱdP3U67 ·ΐ'uK='ߛxPQr#U65zKudzIڑ>Y޺!hN^0G^ %\Nw_ Rg;%(g&d,ۉ@vB.<M F!/6G(D&ЩR$Q"bLwUg,5{ w,l!@ +츒IMhN奉Ԧ ?֤ɽpQVEȯ,OhZ\aIn6%m~MwXÛ Ws;'CL97+up]y_S4QeQ{^O{V( pJ=WnA Gꫂ;ͣ3j<4}V[]q{| 0yX0e'ow4vk'acwwH]+fj 6SsPJ[8me{LrR0d:O ̙Zm COo;6~[XUZ,=t=u8۵cݺʞ$Q+5.nz7,x,>6r.:svZfj'c#;ny"G;xcz~UE(ճu烬z". )ez 5Z-ex1>1{hh{8q%k/"GFX31 .*İb v0ZqU9ETvYWt}l0*_JFLb\aӂTo'Z^{@LT޾ C몞2)uY9񜀜F|`$b;wά$ ,bP=O /f6r>Mڿٻ ]|>jL"4QlG/9L_yLHuW:t" u_{R _1%R,i ]">M瞜ǾgBa6 α>enVC`L Z\oCӜSH*+2jXܢTenmal0BRm:_׌#h ,B驒HNZM\?PW,Cofȭc,p(y[BdY9t.t5`y~QHmZA[M9E؞:4\ksErZ~غGA?М{,Ls:x:86gf)|MٲLf&Sb:RKzsJA*$0%l_b._,svBnK%>H]to#f|$!wd$#I't)b M`O!q<wx UIg .WTWRZt:_O,yS̯#e vWYQD55Օ`a߱Y~?!_( d*pQu1JQZ$ hλdhn]#$I;HL)? g!7sEJ)eLҞg)vlKvRNk;Չbo g5ƊȅHc 'ÜE*xaj -)5)-6d69Y1&< ~˝V8V$ h8TQ~C}J$ e ^5/iBNⅅN0zB/gl {V/=G(·WOVZ u($MFUzh'&k3C83 V!ddRsV<R,[T9PHe0A=Ji/ۜUűVA {-QMe4}DYutZdj2?611  ?#` 1y%wUC Z&S$impN AQF#&&J:4E:%XW$[\%J*QC;q/j-[xCe\2L|v珟=^y>oďwGZ]_]5[wY][_YjkzTGTL!(vv'0Έ|CKRk)~keU֣>8L %ptPrϡl|fd|#Upk|2}ƪD5ɩd4$1+81ј` b҈::`\4|v8>>ŋbDSv,HHWQ#5qfwo8h>܊7wBv;P~P7M0qt|8؊Mh4{*[ oGks݋ͽ5czӌvw ?G; yD<2%B{@CB;P,jo!pmw}fux{0![ֆeV*P܀G;{X=:h oww66ݧ GPPT!| S^u탁[m˲,E/|/ӷ$OK`Ϻ/^~"bIx>=8Ω[b {p2^if<<\ M|r@;Z+9 Ay!rT-8T4ЈYʮ o<ɦˣ=u0ڢ2Ar| W}orïI ܎( zn'U4FU:8+Y$U}AT}Vaײen 7 uH9[ IuX]r-"%}(B(f u&$jyK[J@|A33T0HgaI}bkk+kxl QtgQ*Qr%%t#mDom@ aG̱_fiϚ ;ނoVp!BERe\OYF/N"_%ܛx^޴&xڰ0QfCMX~]B=9Ưr>M)0$i)u=#h3S<ɸi+nf&R`] m1Kݘu'ٯdj'(u_0S;޻n_|cz8vhmȄx5 !3!'w}LQv"J4?I[L=3| 0x H)0qzq!छG_߯2!w͆[N0*եYxov?Y kHV܁Pԇ#gVHO$Ӱ W_n4j@&AK2mÅLZ ;K879{*)ՆUNSrҀt(H H+mv(Lz\Jn/#~Hih͘DrXqX* ;ϼ겞JΒ13No˳k&meShׯR2B{`+&?ycn2̉5@dhE؁1K0'jMQEwEs:` $|5;a w:]$[tUrA++Hv )Ҕn-ICg2p2иťW6KR&/r\}hJ;˹Jmh姫7}De_N92;1৭=ٚp|dKG`jyz"-S I $i6+i8Y}fNސ"BNa " |1Jv4p_KF"G}}m?TF^T7)a%nT⿧CuS̹Jئ\.Qi/0ߐ}mwIk_ *x[_6fb&?g-*y -[H}0QM>oQ*:)"o$gt4˦[v#J0k =d (n"w`5)m- %ppU$˸)G%Eg % EI;9:o\"G`cŞk ݬ)l~/ niZ.xSr1NMRtx&=$(KV-qGbM8ʕǼ '= a{j0|Bj31$5l])K8VD*^ƑE<0yfD5]3%K$t#4w5"b)ϪRA铿8l-"Q<έvwaOl֐'Z;qZy dQdH&TI/`cM>;uQ\^ /GuL곶^΁Td[:vVs߆$Rx$Y.͹a2^ ze$ Zdc1]cPUU~+X YiekwؙV2v^rB:;>lnKntX9"mE;v8~ESA_$`G\,K!A JEM[S.IL7@s 8}p )f܆#u)d?S1@3gjšI%h .̱Xӡ, P 4Ӱxp~-Y+ kVx,1 nV\cDI3 o-%Ӱ@=. D~[GgkS%O!U#lsyX)!s4b H Ѷ3xHX ?Tf|Y LP>:.f@rcʫ,Y36{³($9Xf?@gWG-.t?W7BU7-7rL̶ARSWT:ΒZT9>'uE;h>wBJD/5=Wsb`c9UGy/l)k&y<2bTnOu<u<5U8$H I]aIj1Q2jBёV-DkAX`rg>O>@XRgG̨3S4.l;quj:ܚi!'VϏ);AvY+P 3Wu`#[񠑰TgsmXu9 sSFpwu.r% k.D=fr$rƷnCuoE:,dy9FHߢDBϳJ#),0.%=ȢBLo/J|/>}a0%Q tÃ%hf^db TfҰr(Tr `-5ZAaSZi]! ӂFSU޺WJɔ_-jKfPFa]znpO|hDyݒF~97azW; |#zg&zM"&v$yT.%/ Tr%&#f)痿3TAIXm.* 8H@j`AdN9`p\p afeW+H#tf^- Kn~Zmŝ[+ 5hܡ6pd]\_#N^([0۴oU?[uu[S$Fk{NjnQ[ߢ}- LQ8 1^Sy/I$?$nظQu?_-Y9<y|FۑjD"J] lOWhԺJ?{Ϡjv0融1:QBF4ZH] ,,/j˗\IB:4 $z#i#U,DL-K$B.@zct'aj6f^Z|@h>:SONCCHNHbI>*C"~Bޢ/iF,QS_ҭ 8Czt1eT8>ODͱ.57Ooo70Kôф" HpKYAlzm|T ~+&1$2{ 0ŭO ly\IJx1ۂVLpzC gՐK* /H&\i:KaRHWJe|h?$\AZRrtT:%y'$'SfnOu9`@ V*W)1J8:\B+K[H^˾?t8I=b×VdWaʍa=AğP[{XE(pOD!go"SFy%AK+,_t]o^MG @r\碽ЀjqoHV"vrC~dьKOojغgEZF"FWjQYeFWGϴK kdW掳^Y5:`"GGTNň G̍~ PʷB[6r[sД%ufV뜖7yYk<(155Yd*^mms]65ޕY EML=nYt∄1],d0[?ԍGhB/yEq̿X,N-%<?g7~ ]tUG_ZgYy5gٖs1lw<+aژu#9sUvƹ#2̑C(hZeb ] z2{o!y~kN){Q+VxQ`ssAFN#Ψ#|e> ɞ`roY ?4V־Os͑훶_W[_$K\+~>+{E9E+H֜O a{ ~9UpwݳSsk*BP !"ڃ^5Lx^i cB:o>IC+8`[|7D>8bg ϑT! PǁT <u$pEs88/\MRXk Js*w1kwպNG|IIc N5r s:48I+;Ӏ(4Od۩ITN»:l"] *7*m_ZNpS{;}+{2L$)p|4~Tο--Y7{,{ƢmI[ڔ-tV خbVbYØ/ezլByV1+4QVY/bRf%lm%_V/+wi2 Δi!0-*,WL`_OotqyRE$5K&yv'VkQSDNN.~L)%(gE:>!uőmj&}pSQ%B* ﮂ|(iOl.U?Y>@ᐙ5xAG AUPXՐ1UGrS?D})p- *,1./aXaF`Q[6Æo[ݷڸȖ63[H~=AIsD? wBOD7st\D *~Bv%\943Lq^Io2;3Vyg[ktp[?5,CmұO˯/)R_C񈑩0H4{T!2QaCYcԀ/Y*%3BXLp vw>|ME0*Dzmip%:xc#.h;ȟjz<]QK؝VsU]Nh{hb/#z SHPT PRX-DFiWYGÅRř<0x*<hnteX9]6eCs0K,7ϔ+w]܀2) jXe3`f-~pcwD񥢩VYKeV+f˸d62f<̽/[pO>lZ%fH2%ґk ں}㣄(|ZW.&?'>"9uw (nEwCaf"kJcԔlCv b^l7Ύbbo"B̜rS)re/p)vgqDaH)0 x(BI*!i(Hq ŨSIKcֵXo=1 ,ܱ;rh$J]O'g:ʇAȊ8w,ap#%U4hY_(䒘%]\}/Tʩ .* )x@5@*v@z`TpTUP k^y9Ąۛ%ID{o|&Y?kH0t* b;DFpQQ )S2#֬m`1P؞<+8z "Rȕ'M9&7R./D4ׁr1n i- qfyH9y*`ր% ǸC`L#JZj- u0uF.==@ա.IzcogxX_]nvak%t~PHĪbB1 aHŏ dD" 1@p'qc),-W|Yt' 7ˌ.m;ֽ]e2 =\&+RNsy<993'"_<}8mTE,!zct3Mvך$ `H9?H%4?t>j]RB p-I]񾒸KQδTZ +Ñ{ (wB QQ( `!&Ně͗u(添}nVL^'QC*d. ft[UI ?zDs "^+Jr:!Xll=;i3 3r:TsX~k,l^au* <{p:*?)ֲn{t. 0 ,3]3[2ל1Xbf&ggZ-̋;,x*%m6]!tff Xpۀu:>uy,9~g )=*Ir*/9)S?:䨊Tx* cu ΪknCRkAbf`fnaB}-=max/+'BV  {]dg@c[޻ J>c3UΒIYg7G0?5X"QMSKFk9&tCf$MGh$E|C:h]j=UU/͢ȉT,4rYwygM[aEI65SsM|t-̗9 ͧZ7^fco#ط8Q|jL9AbApcי9t^R3a8~R{oT/c^1Uc}ٜMBY]^H-|-eS:+gr1Bj{ϾCfIui)=_;hIuJ?id@H ,T5mIN T)#д`{3ZQ78IX&kqa1W#,?e{+|4pLF="'l2_ piC^WcYzVøhfMQVMRi롱euf"X/MBV@yƑp<9,]r=:Yfgoyf4*##ka"z19p))[T8F//D ^^gL10-c+İT9.2e&3mMP_jݗb3!_PW8~Qb^%4tn!c%Le-_Ճfy5WR]Mt6M; OR(g^HGes8_K̔)Ef_&is7z:>4@%L)D/Z*F^=;=TI0SPkRJ-!5(l68l&@vq-2tˎRϭGqL7VT(>Գ4u1.lV5H`흽g{?nA /Y*)&a58AuF C<>mp}ܱ-?ymm7L'#g5ǑC(R,!-THo1&|a{EuU=-FCAےf7T#Qf7KY"yBUQoarݲ{eOWZ@(jRQA-gܙxu[}Q`ύ1C).(+y' S\D 22` LY }gSAĘeA\k_hnw {)7T M4t} MC} .-PByV|f/<˘-sn]{z]j$? #f hs]j[jfm)H`cН@m6[ƨz&,.oipZsU-\m8OA* W5A#-$SAEZ 80 Ƚzi pT/0|FG*+Df{䠊cЀQR!禯<1SjIZ߭tEH>ypwy"NlPQ_"f˴=jmOuh`Ԇۗ%=oge4fGL/@LN%AtdrOLV<*D@  LeQ*@Hir;K;%64R2>-*Ǎ87e7;N*e/Ndo42(Z4͈#wF=e*H8B(U*(Ds}+]5G4%Qx%]TУzJM\sF85 v/_Ej}gUWW*UU:s agWO'aO F}T>]_Z׫V{V_{Z[GhQ3Iƭ %y?P,=O&&?O3`Ď-5qT,WWawQQ8:N%'XkN8*_ishb778_aR+\$}Q32tϮQyH@5hȳ;z׌~l4#DjnE~BLAG?|57w=nc!ݍǝwAm`+:ڇ}[Ns ߎ76ƛݝi;G{E{QQtiF;7Mln{*~hw+0@˞%61d=vLxxsUJ{8:܇`bǻG8! R =@&GKIަP>:h8oww66Xw*@CP;)ĆR5QZwX yA op%Jp `"TK﷚oߞ4xTP=JP=]N&62f *vWKy JRTP eN+ۇ\yAx4vmB&Cnn6Ν혍l_qZ+!_pNWB$5/,rAH3nqޭM3U3B.iK! H.(|żBɱåpB=S=Qq&'^ONaeIx.Y#Z y=@`3oaL9>kA7% 1)GE3s ^ɜL~|U' YcMG읕^U~MHr ^r'R:d"+ =e;%qbe@QêZcgl)O5 ;A";tyxtOocFQӜξlc '^Ѹ[Ĉ09I.&Ż%>{3%X6B8?7`W\>>Vh -YWbB}Fom? iu_htP KʳASF#- 4^(g`(UPv?4$#^x)ˆKU}""8 Yo%R2@/f Q8b 䟧|u<%D=SE.R;p0o簆x^\HETWop4{%\'j3QpegQ$b1 m{d łA;$A޴ ۗCib߯HQ:̑der#7\DrH !p'Gw)ѢuY{R=[bJ4>|j=FX h8eEakl lgmgyu{Ѩk6+goU6k[sgG..o?|ZW߼i6WVj곧ϟ5WV[[koV6V+7+jc}klVWn7k+k[[kZsڛZiss}{So>~+?vh; y`n=Cngm>mn^|ϫxl<[fZ| vs}yZ\_[yVNk+볯GCuZ9\'5j:I⫵fEjm%tͳF ]]{lle]>ۍg[mux]_l4C6L^}Vysk Vjsfvfft4L-И_M8>0f|_@f_/8vhF) 5=! 'ʢ~:~^Afpl^Pm E4ޜ}ZY~ =ŅE2 4U䵳Ao"c5Mޱ7-HOnuڋy.%^t :gT~hl*OꟶR9,_'pH2NɎ2Amp TWsy$¹?NGqL;{P$lk?uTb Q P꼳[m6/V3A*V%+'hbW㏼ʸlqA4읠ڀ= ˒q~y./C/-oZ)jau'9_;]UV=kUƜyIՊےt$bhǦ$~9rp؞Yr>%ӻ Vp𼉖ڧtMȸ"вS̘[i - O6YN&7yak6\0gOJC{5GN}EKf&/J$"4xE?GWhaO7X1Ϝ2]qez|EiDC@+CGg_O% 5;d_@7B`)7gId \)F 'U zDɳs~V'eϰ`uT`[wj!Y􆴥 dzQIJASz>xd\A竨m4n3 T">ܘ*UU2 f%ըl pF9'q ?W{M=d˝Jy5 HGzZ q ygva O6%Zc"j,]up]v^$b6i\3券PϟϹ7Z >hA5Q#Շē0p˦^":tvP^՛'ׅ]_R,SEޡ"fqK^qƩG \̯zt Ix6W~ϯ w#sdͩRfLpfwg 0Ixc _nѿ7lvit[}db[8B8uiJ)*YS^d1&5Jj/.8Lec ,&LuX he|5g[bOb[}Hȋ"Lz4x7tJYJt:\ѥ:hp&Pշb]Kn W:1p,/lO?[VG}͹Bh 4)JءH9YDmR |me6kQnXxAS9BnGMNBGۢG=4#a7.a}]".*yFhcjX-Pԕgl*q h$l񸅇.bҹV=QCmIXA){$m5G <=/1hi|jV4\o~Eg{iGy '݆ZhPs)U ~16"Q;I ol-ş'Q"E)`Nג.V G+ IZj BM-ʃU,X~ H7],vQ:pc"ɛOxzv+ܜdK+$LuoCw(RFTPՔ:j)츬Nٜ3a=3'54kȒJ~f#>z]sooudo>Z+ .gJ:2(߻MiyCSA}D*qIsUުfD589~;Fзzi@T~|ݤYvuu=Z^VfTWc H頃 Í-{Q؀I+eeCOwRhHu>|9Z/0%x·{s#Έ/Y@N;Xrj~PjLўɍ5C.Prn`WRmAuG߸ KR<13w -w;~s{+Ia2?z@1yID>}46b& RtUzbV0ls\nN%tAn*hяAFlƴAu*j4w;AL b1G\X= Ggg梤Ѱ_b|9kO Z^~jߋr;_U]s`֓;i]:IM+V$&''8!Z yJ+Ɉ( TEϵl¸M'(]#BϠg H9?4vѣRFG3q7,I{&9 h2c TEHbzTCmET&U H5nK̤RBݏ Oiz|+Ĕu99jE/ypaC{,nBEV](@x0H 4.qCQ1 rN0hÄA@0zz{z pǍw!P;n8;ȝ[Uf9VsĸDMNknINn59)Fu& DaMeLZKͣ2Gb JS^C3x]x] + @?V< u},iYE[q[=(Ou ;ѸN0[V D?]ĩ= .ʝR8xfXv@;[D\>% Z.Ԍ\[>E~h3(wϡZf nfԈf#$^:شKfWbIV!+o[%UbWx\Oڧr'I x(L^_0âN'z[VO,vl8,#"ˈR2mTCAi !UJQ5T1R?>*W#u"ZI-1- pY D3ºpv4 |b8y#07 `ƒ}8}~@Lp՗y8ԁ8D˭mf72kdB׌bXp472EA9lI"TN$BTέcHb(j(/ #յM^_&Nb=m7_'|;u'5{V5~wUTjGӐ)4i)9hheΙ3:f{bs38N2fp42%P-hH[(H4U麕FڻY?SZ}t'onlH*r7z18;i;65X3N46]d{3N+&5R/H $GQ7#QZꙝs홽s3=r -Z9qDoz:?3sowm]{JmαU|1Mnnү6*1i 2_Qq{GG_A } iCNv).sJjFSjӿKʙmqQCru,? cPp9 Rhz̷ųJ w DŽ[vc^9>vh,=*9âXwBW\CdžnMUO<F.a<|6(jώY[Vmc5Ko *ӋՏN9y :XYUOj͵h5M{4uOuJ)=!PD/ A{<i]'1tz>7OoT#3@E "`H/ `vDz`:٣1T0lXfE 6,1$m7TrxPҲV֩Vo.O]j+9!Ҷ c8&/+O?ʦy ϵ6~V U*Z5rݪ*QrԤ4XK53U.Dèғ*)L-i32sݒ'E-4L6UBS,\W'# 3rb~ RxzanrQ g88~b4zR m2VfUnU~2wLcذ#؎ٓzc6}*ڏ=E h61dPq7Xa(-G3 ^>V3h)Ynmc8' S4xcیbĠ/H%ח^ $+ 3Y Hl!N%6ESfP~owO2 qI+J_$f$4k_vNȡ̓?8h?o=vqgէϞ/o`!Jt='*e]tsK)kY6;8~ɶ}?OkOWRV~Zb+߲|3"3"@V/jLG/7.Pm?=AKaZJk6"us}- ;%ɦ]U%ơMIJ)*nMa{Z(omZ0jU>5 ;D;Gdk)O3?S@V+ Wk혰>n0 #F9 5M]p?$;u;S{?;{+uR)k^ =H뢸4fxi/)UcZϪg@' p°V!$p}Uyy:'Qq({hS>ik {I}>kpAEh'=vxҢ/8P֗KT N_d.q\-,h"e.ZS/i|]1z5z54 $g,2%sLe+z.39_G(,V ;" 44ZIY kɎvϊ#OydQ!/<u9CkfL(7ly|u"*'ʸFݝ Յ j6?|yX;" =V 5=8S9Aナ:IL? Q|pp2Nȼ ʊXGv,r;8 \fF#+J9x_8do´SroY0r\6ZfgyV] Zi>k8OS;Xf3>CBaM[ N7̨4( M 7ywlv.sҚ~0I'5{,aGCV7Tۮ&܁[ELdjP~x>dZ߉ZgxDuе@-StWq;+2y;g *% bYVS3[Z;,CqYҮ\riԂ rv*GneY7{[Y~͢ k#s,c:z sRug)݊4'4O?E\ ⼓Ś/ؾ lͷ7z÷QEQ(O T7G?FAL}(cQաI뎎-+[n=2+ʾJ-ó HG@G@ăz? ]sB'mFqepm,ڧ׾M,ӑۧ˯[ř4ȍ/ z}ڧDQVvUT9Ui`s2SɏjEg״=X}Kd*F!eycP.fb}V[$/-mI+YZZ̠ jޠ)=hVPL5`pv oZ(H&(?fVܒJ"r8zV&׋ܸ5oqݾxv\ Cڴ`6ۥ +x{Sl[f=7jdg((cJ>p*q,g{U' z mRRݳ࡝ qϯɇhK{cM>wnʡÂAvlzg-++f>"ON2F颕D-J("$zL4 2}:AzeCq d94  Y({RGSF͑= ߶3>9ljr/ Y AjyCE)#i'*1x̰y+ЊGdW>t- S52(P\bpq(٬WW(@NRI**F L}:˸`G>z#Y{$Ռuc] TkjeNYݾl)o,fm ϫݷjL4x3boH$%l.e;8Qpތ)3, +þP4;3^l'RXcR.fqc%GJ>yܬQD)5 MIR^Q PXe@s61i_g G/pFGJ`n7^] ޾&S -͢`:Ϳ%'2ΙQ]ס‰-S`Hc``KxuBɷphr4@Nˍ/6P ae-qSDG-$fW+2XzXVlúY˵!Y4upH_#ٟN:h­K 6]p$SR̝`o+#DۜOEQ6=Slo7~6GU4A"GݯayrEFƢhHbGMRE]$T{gXX[ć<.A lJrao pڢkR7CKyx#9M$4w(]J?aLvW1b\6LQCȢIYsC!1b%q!͝nRI8Xo긹p.@t DG399q7ļ6mmiiM@g2ioNF-R.#Ŝ~Rn)B%ތBՖP4D0*q@| 1zzCIzI-9o0AiQ󦙭YI7:=h/UdCUJ2TvCYujZ.Ʉuˋ^*3f\<{bjBۻB췯.;GfgL;. F }bNCoV6ĿkzkY&hlIȳ HGNs( յw@ބU(B0v30DP0}*gg#r =V$aB7sF偆EK:M\SêӹuJN=XCٸO؃1#[Xt˜$nE'il'7WA9jwl܇d>Hsқ:7L85L. ?"||/6b.k8}ŋF%p7W+(<HITwуZBOr-FnmwZ4ǒx'KSRu368蠱w,'{;G2^'K_N}~Nͽ#L 4ݝƛf5~?47w@!lŽyT0-}!\oq\[}]pz;Ycs4f$Qkò`+P KznMz4 bvw}̛ݧ GPPT!| S^u탁[,U}pEy 6|jkU:OOOjϣʋէ/jt9j~F%5KҺv9yy攧e!NJҏu>g?KtحOyRGH'8Ft?qEjjwg7Br/#jPgA&ãtMRd+Ȃ?wx<8sQ9Sr %궼kڏ+~e,ǞLN)ӰUiI0h>'Ңf24kdJZ" D*X0[v2WEyҘy\{vwRE  끴aC<)2ꥤ1lfdLKt2fy(+;T 草-0E^)0abd-ߊ |%1E$BWckN%p %\U PQ;1'O-C0UR7d$"D<k3 >T3C4^~i)x<|dJ%<+EnnGk? 4C8@ 1(*0c,x/ek ZwJ&W^\l)D]nI@*XC5'^>2֙;fC;9ӏM;9ӨQ?5X%@yOA%Y w}+ 5{=9~oe+rN$7}4]M.xGz6v#羣bwZ+HZZqާҾd XQ@w f*`O|Gp@l4Xd, j >w֍{ZX%zPUy:m@tDjz׭t(Ov~>+DMdUV'Mݚ?uOP_>Muw"1׮H^!e=RWMŻ-/+QOEoz6Eϗai)CllBǗh5Ǡ犨>4ԐHzSh_/ cs5Rf06zHyMY\c^4hg>9 :Ά!~ȁ3ehC%G(3'*'M!.?3*08 4s3Ԃ}x d|9,|3+d5eϒ:M1dމM ;6%QSǟ9YKUQ|wzJ$2&F>Ԅ|S{}1wZ@ *Jr|[0nwϺY]+Jg S{Frf|qVzeedyI4G ȶgp7ܖGop7U0\?vE蚮h ^kX(!"l,𯻻KpO|j=-}n,*N)SS,Dt-Ưq|걗Ho|`xï& Y-%j΢T\Kې.ݥKŨ::ړѨVwĝsu "D$8 Q7~>P26e'Aewm57+ns9$Tt՟مs: * V,5)++mZ2Op}l|ȒrOH~I.NnI,:{>27LjL|И鉛i" kQd1B2*9 @s2Ә W٠M{h wT}2jNAb4^i ]`hȕp;ᑊQV-4{XU ?>QsW3ѲŚ;'f0\a8r'i%,}45A?~J_>ԛͳ4In-}=y>[2|xI'_& 2|9drm¯%WOw0;I@]JϚD1|Ĺr-8}V7ua"-2P巎/I!7o*AfS=5kǼߔ";HؓkP&WC+ ;1T(I92u&Z{t U]P"p\ȥPpk]]΋wDp32YjN1* >2қB:ù>KܰiPkJXhPCjAv.ݨCWԔNjtȠkY6T)Z~>vkMM9:tyf4^_[JT{#̻(^q;SRKW8F.5ŊG(씿,7?>bfX褧mt;6$AƩIe~=gEWk8*^II:AiN $N$xHyq#Ҿ >tn ݎG8%qC7<EK 3.i?*M}1oi%>rkz(|gͣïݼIA|vP! Clw |56=jH8oao{6Y`#ClbQLߛ~6BSjcworafV{`ax)/4J^tl><:ќ?:Zq% 2 ]wK:#ĠrR;0Sy9fp?gc=xCseb8|nE( eɱ׹gs)&rcgCG _>ҙ'4#>+,HΟMA+*<  eS@|Pp/v7ï<Ÿ:rug7{\Lc7vWf驄VxA1N!n, Ûl!M-\~Xkh=DR }hȑ3IO>O Ϋu~yY\1vm.&!@w^@;a6=4zc_M0o?_ޕ;^.cٶFM>=kܑtn{|k;vo{94vq;wbsSSۚN ,tpAoziQzN4LFrϴ*| Z,kbYrZ-w[D[kb]  z_%젓82aeM0lRIE9iYm>0 K0#$vyf/_mlA6]3qUO^W-k/'h?%Ff&UAP%:czZlTޜNV2 0: ,H/r#bP1vcoHͥ}aD#:(N@5.%piHQĉg/UܕsE[|Q\KL(=2P vZuP -x 9툫opZs_e{ [_~ދ&loԢa=mϚk{>.:I+wi!~,/NjYA#—HW7~;|_js i&H<̬9s}XU0iQ㺙zR:l4=W͋ǰ=yrS^mq]ц{!7E1@ vtZySиP$d(AC*>_3pdd^@m㬜Fq͈EL~@1'Mg_ۨ2:ro.=bI]'JXFT½ӎQ\f] Cj/hT.̰t8&=$diRʣ8fӕs3zrlsC8\Q+!Yz0އO~.:DW''޷hpE ~2]W J.U?+~]Tc8z)`6<@ߩ"Di)Grf}F,\3buT+'ݱL/͢( _'H Ŝ,hUro?Clg ]| E,1M*SeQ ̈́`M>b~;5!WYe_i5cZ;-|;{zWV<~dк9? 0s\!S߹ic|o}ʺM'sZ@xm71S5lrH LtY-&oBf2EEꄅ,=Og۲Z'L+4v 1e( +p9y[߂ϯ,/imxl}Qѓe5`fpuדsc<4 _ Apy_mm1gZCc2sɎT[^pќ雽1}bbGE,M~",B{l_y(R~`:1w\8c2y}("d+?`͙d0a߫uwR@wo۞Uqq.UGEam/;[v1fp0]ثb\ $pwmȧո)?snǣVQGqJggFl %3[J; ๭ZRP-s5Os'pNZĊ,#tn؅}OEP]HuA*oNl]٬4G&YCKu49Q x>|,1!u0'lNnc|aj0q+ .15CaM1u7b"6GkskoG( ##=A(Vo][xu a Elƶ~a'?,Xnfrn#_ v(SRd/j<% o֛RRͭQ0Ym?[RJl@t6B T4 `_se f75 V='!zPoE O=*Ik9;_ %Be&Үa*1TgM/Y1̐ETaX&_\D(ݲL,<6ǁ߲a6, *Puţ]3|8CAl1u:A0\Q\)%Q1jvkDJ96V5ѳU'mAINΪ95ȯ#.4=`n g/sFws,Ox.lt(:@tJ~^/Hچ+~h!r6QKE>/.O=,tPw .1$y'c5 79&TwtOC |HN M?Nv::wϟ)3d 1My 'qAݩ`>FlQC.O0LQuhЌ l?ƊH7GZ4};_ #ޏEHeA DM0cT[2ɓP/V ԆjJiKKSp L&Rc=<=;Б!ʫ~0MO4cSq:@u*ݶ{Pޔ?O2nhkGFW57=\T o:9uTP[N)yGꕴ+o!Dt*yxsH!NO ':bq(.\' 阹V(2%pCAlXǽo/6J;+IDJYpПeZS.ct@ <[ e&3` rV{ѱ'@'5|Zv(xMGԤXĈ g,#ƄH+tn\^FPٸ_hb˪;]wNM"y(VB"Tv-J8kZ ˭pqWQ.h݁pees9 3@NP1A;뫒1ų.B&2kHաӓbxJ"2fPI7w'ŕ ohX~b:3K֋3F"9N^?|@e,g-'b G=GrIt|yYMIava[1Q.Mg9|{+I]L4fWx=_ L^~L>־WB}O!Ld庬ц u|IL³u9q[qu1|lkFY.d*Žv91,0s=ڷL4\ H.AtLU:5Gv seEexWt~=XL=?[> IL0=BZH̞.l1dvwX!)xp_=[ǒ\G o.8H6Tϓ0 U1{2+1"??Ǖ 4`×T~$lQ3wEnZgK2#+gP*mmH/@cȘ%nPD1B] lq-2qqcC(mLNdrvhw:/T!('R x%ۧX^-Ni;up#u88:aYqU53W-\!;;՗zAף-~"6K,e>*Q/V/^_~ZjR۶'bVӅ*K)nxw<׫́ s3"ϒg2d)>Fܳb6HL4@N,0[cAl0t[ z(#CUaC#5n9{`ya}v򆄡/ OKdavg;Y~uH?H1\]<[CTz}ᶎ<}sjwOtu4,Md/Kqr2IfvFy BYӗ=V22ʹ\w'%KgL%v1.l>Nz-N bmI*oJцۃsX?=Zp^b$ySq@Ws9O J"sdPy~ј 2l_sIcs9HV1fDsNmMQ*@4rM0wyX:2i1"p.j/ \>7*Cl1`NŖ`{dT¥_IncVhܬD[O|[tȎ/xgKqHҢ3E :aN[~3i ȒH*>! MX+C ,=4uLSoFm4UAY:cZgh`+OYȐJ ]ID_}..0)SL],Y %~ЄR.+mB4,@zq@L~qrpy? 8 biGLpt_-O 34{Cxj+i@$,+VScs Ǣar6ceg z yc&Q5mBR؀΅԰MUU\fˏc牢otlޑ;#kYW#Io(%:چ#q6(miT\ .3 Őʝt,؆-*R:/&GOC@wEoed_4 v V󪐗E5?2NoPc%j&<{\dJtf曚q"QSVT.&H*HYuţJ##]*zk_WRcD_q> YW 3KHE&!Q{Q|8fʷ1 (rAt3 y[`." F]ƛ+p 1`AbkL&줜 A8R jhm ^{je4&X\W}ޓ 70n՜ ⓣN=I%W6 tB႘b)ީЏI%2raߟ3DDjT!gIzߑ+'ǃBm`nrϮYtp?c$*ubm1V/ !c=bҔK|BҡV;LڵTˑT9SK;Wb]e8nSG6c+͞Jw+/tZ8$ֵ#~::^z!È!="?%QK5eQyw ^/ +3?H26 w{YWs**X]Bxcq ng%+[A-c]m 15پjpzEI#t|3? mÎTnHAgώkyvpx`$q@Eږ#ء*~vUup..^9uϴ4I̱Ē5B5oh׎J奕7/_%-g@*''YS*\uRtuif srHS'O  :Om%v sʸr+P9Ͻ pkrw I3Υi7 !~SB`7]5T('؋y#d ЪsN"p0R;gI0j ĺխ-b\L0JĢCk2&5g9t>/ &{=%&۝T=Zӳfu3p${O{w^o'k}G;ȀyF|E>B T/pyWE!m|=.T.O>>tgl&-78*PuZ9+T0L\ILoSbB䬒ڶR, APtʌOhXSX^bBe ?4QO1E8j2RΞ -.Yq9_۩ Y^xY5&{Eס"cR $ [l~?wZL:FZi'x|X!^լ:˓vAl&T5k Sݤw ی``t([:2[%)@_* nBO`e#rFKlnX>dbƲ9z=ǫqm|Wk909{"Nb&]RJE6l~r=<9LpG5 77zf}UR"wvJHiT;ʡ5(Z跈kӽ{)>t L@]ppdi2 ηQ w24U9f >b^vv̓g Hodʹa*Uʒ{)'S.9 @"ăSYm#1.ODJ4~q8U!9=8ƢL٢@:k!mC4l1!%(rn&E#$a^'JN CRD3NtCQ0dxl-. hrve7:^,[XskCQ{qˍ=N*O۪7%„\'H&uĺ'U]4#aXo_ (W:,bS^dsE@q7Py9pt,˜1D%"21,q^TՄ[)}&]`9̻7 ir(mVn> G7i!& k2D܊ .[Ŀp݋~nt^BEpDARڭfhb!bAnW~4: gfgnYZsbxsXb&BYuSN )L+a4fT{8bP6Rj8RN{(\)Zg1!^Sawc >BG9`ȝ6^5XKs$\A @ =El!Dl1QOFftdrV:3>mus-aK{#uQ"j_lDBO hxJJu:^_iǪ31Ixo:>],Vu ͎rףӮhurl{! 0*';fu`C +#1_r@|V;9Z5 7=rRcE+c^Ԍ]XscgpzRV[E!/Ow7Q_1 `aZW&8kl19ͧ̕H `}ŵγuh+l%+(~G3"j9{~&5:H"?2 Ǚɏa4 }9(F֗uD}dv; Iߎ>spz%[ +aWo2/?-ƈ F\LsQI 1tI҂綇,glSyETH)ivd6xo?$HNv "V˿w`{݋#\/lQ;㈥#N@,\-.adāE./y`=#/FEhFw6Kܩ&G235fh:Z+gy*ƍ8]iu _#`NJt.+-M#0وTCR%3Dg]JkH].uf;iHH ڴ1&oy.AP>sPDF(]0~*K0?e4m˹̇,vVR6Y‹;@ 50LIWoQ_dpFy|ىnAH _͸ Rf& Hκ9 QV~9}-vDM@u, nJ826!(kZξ}L$,7Rח|fw ,QDFO0rp$谓94.]뽇[lK9`B7F+ OP `+|xeW5 9 P35By0B*L#mzqB ߲##zz / {fOfBo ޔ$%ΊF)'aSa.d;3E"$C!8as }fP 0` MTu{exSh2<Ia6O*]IkhĊKY 믺dy^I@vayY/VatQ(,+RnYPIKD%&IVn΍ix7iT04i8LKNzgƞX#PVG1[LM >rwHztcY>_k% c:J8x6Sͮh( jF{hP(sA9^34V|c|N+gЙ"sy}MNOP.a(BԎ\e ql0,$׷ k5/Jރse'( e#y. s &ĜԦYL|6z'ᶘ\fvMg.Uȹ&ęW}fI6 3 * /xκfR "/jKs:L`E A%y0gY ovWrp3a!Tq-*R,a\kYdg9͢9F; V3cIz0NJJ^ѩd(^ʹNͦ{T'dy̷eĝ>+;v@͂ 3Dx c0]2!o;sww^N!I,@_H\iBiҲO8W7'8E@5Ӥ]0_S*Z(d"U 4p Ϣg"_Z5 *iY<gJIM.O'wjSiH\nL7Iϋ 0?x}hb"R~ٺ" `y67~< VBODyԍT3pa_t@rH 5NaINhj wH"i";2z",!e޼k@w#zN끮 tl WH& K߅қGKG:Ÿف3U(E4"w'lw@5 (7 W$kle8ׄk}>6SN &>{2ܑg ҳkNSTPlEC,>|Oggl7rQ}(3 E׋ 1ƒg;\!륃bNk9([Y&B6$gfȍ2v)tf?l2Q>^=6DqK԰F Ȗiز8SλD*NP|wfkPގE9Ih5 \Y\v+l/V!FӠ I`X_6Gޞ}IR`,lLN"s-Y;poσMɆ]OƘ9t\3|iIz\{y32癅zֻ['i~dy=>,3>Mh߽fG;ɥ߃xgoOp r{_ʽwv[;G?zO ~4yHm9U7m7!?  `E#(,\MhQ@Z6/ аx1C*'oaCWs'C{\~ʋ; Œ0}׷NrGPY{F%a\B_I*e!eh@$6׬ִh3.O0; 9ulw˦0TrQQD>fZ.~ XЕី3 cH 򘨭m;P@A=1b@=:!f. defS^8jirgF*5Y䛓H!A\Dsd8rɶ (7nI=!3w=7]D.Խrw ˍߦB~ [-wiFm]s[ nYiު1|٫V]@8FfFj=hޮkl$2U ՌEp A:yA,.`ѧZl*a %eVPgC7XDSu}\Dձ x_ڕJI%}b(㆗2*NXm<~F}e{&'<~DGqXc wUsqA bFs/pZ׍ȡgc+JR*3e=m?%/:L^UD0`4uKZ0 /t5u"68}^M,ՓLZp 4*fGx96(?8`Cr |c̓|I#t84# q5Hv7;eriyxL|j7؁ I2{b}κUD~ѩ-KY͖_dܦNV'XJsr-kMA\>s4۰WUE0.vm9$7+0L"=<<&yCh6͘|V)0lsa|}( cg[6 sk&D@FlA՟bpC6^FrPXET8zvُɔZxm,Ä́V`ʨĥCL1 pOf :T4)$FYL{OgA!z&7! D]h.K5J D$ أ*0;rEW.szff8Q~gF,bl5SثFcea0 7Z"R- \֒*J!D2S|9gyI.)֖{{mj~"nג1EFg5sċTh7АҮ֎ ´>LZ?;6ʓڪjArx AXmD0^Aunz) N'seUY'k nM,=O+Z'׳(/Gm̉J#%Y,d-NCxy@OITEB /EhtWnFS2)M{(< ֊*z~n.!&}&m#}KM "eٴ۷?ϰB)4N͙('uÙe..&pN)`@0A1u7 }³ߗ ɓWK'#Ə0G{Z`x8{-8wcԨ,A\ hQ'_g;#g\F\ I / \4aCQAx&-8D ?ǟnrV9 [>H%|G1-F:/P$$jMAǕ f\aaV" 8sn f~)sMFv$lr A|`!H9j9ެ8.YqC!(ѥpr| V3_{jDˢ6͐)!L̾_9ߦB8-*3)%vIT{ .5!,YCЫ}|W°ht:&oN(f,ܙsy0DoqDY‰~I:5J[O6hy8p-(EvY|G{SX~4 :Ư-8cU^!P9m_ ߏAV QZLMdWc$ eiuо}xa/Vol(>+w)]-}֜&7-9b#DݓlΗ$R @V@9x%}+cR&3e$& h> <{֖IԙnmV_޳{Y(}C6"M Pu =J#]po]O7jE;{IK%y" l x$\u`LT>z`&@JVoH䛏!cឬ;:vďd-Жz~*d: 8BK(|x/^{Ξ7 7ibZyO֚pAAF!?8N)("ìs޶g/=%oyL,PE:A( (F{%ۛp·^Q_9qwQSɜfkhp ).PN̏M9 ǛOw_mX~h jI,;S#$0(85Cq&$}?-ط3Lմ!sВBqW&WIU'Oc^%m&:s7ui SxB,/!]dŷ!g9d^r6|dqb(Bxgͦ}kY<̨@ 9bM6'G9%L]N=œ,ɍ~HIuJb!aBfӬZ4:kp"Xp^N1xTd :h0qz>J=NrC>)v| ;sۈs?0ߏXO~s)@~%tْCE^'bZ|y IgL7 c+jdSc[)/ 15xvI4mi0_3@-Of>[TO.˱!5%L o 7b: <6 ΁l;c }5Kɝł$tdNÎfc!iP/AnZt!xGs+6S~-''r[+cӔ\evK5d=O 1H>pp.CGkuDϹ1="fz4v#|:&3e@ 'Ls <3rhG66"42)&_4w<7An^zxqg]LCa,1]"0NRT}*H8o#/im0Ekt~]]xrӅ#oqwt6.`rznOO,cxyݙr5M$Ғb^M qqoIKڏGۜrh:{^|[j乼`z\X (g_pA8_5dť/52 U\v6]nnWn.]_}>zR*ڵnuYmNDsML(뤧jQ ڏl"E%ي(U?˃˃yySu,ce\qKK̯ 78DcTBСS4A7:vy"-ky-!**.xد>[O<՞w k :-sF~y6ք3d]#oG|k5T~TEѕW91wB$^N~o>b.kmtphn)=o=;߃GЉ;/mCk>V8?0e_rays} cmjtļŭ}Smoe}r$Mi9cu3 #i}c$ŷ쿍 a!IuDP 2w8CLV ďSJgx'\7~#ܐy|׉Ve?]KlY=[0?_14.7C|+s'VKr_Ə͝x8{!6<6 N<1bz1/#C_bߖUK>}S\Ibuh_Jk0}@ lzA$Y$|~0w?~g =඾¶_tGSd\DZ(25}$IY qtߊ[Oq* ,&&iuyYMKOlƠu)ށ40믌ou:6.OK9 \lI56]'s@_5lȢF,VAS4b2C_2P2j 2L'w-!Q1{ŖCPTM%qwn#iaM;8_m?<^Rv|u~};{ t^ƾ6{uKKf^?fܠ-old0h H@=-3vٱh2ƗK>_hmn? mևdgϾ+64V{$VHTf;"fERCzm<i CF*ōB!W GB֬8GKi6#,DbB `g7 %HqU$H΋ n E3-]3( j:|*ÆЉSDفa rGc0帺2{ium:NtE\E, LI͵]}wwT*{24*/ȰBPqEA ƾ>ʈ)EP|/~w }V9* f'=4\YԷxDCIG O4g*df%12)ӇJ`(_D9dF>2q YlѦwr4,{eDG멛ab2e?w4XȲO*){S.VIͣw4fzumՋͭm;,=|f$8_S- C`.Vj)i7B0q`D5P Yapc!n4[д5؂=, -X'lt7I5̠$ 'z_t/٢7|ߙrbE?wMʰcЪopV^ݝ#jl|A0ǓM$F4/Օ DB1+FzȊw^_w8ʜ+65@;+N(U JzyP}4N'sW`@wM╊/#^3^]FSe#Xd9p;0ezrg(p 9m4|kA?:ڽw{Ǎɚ%]6|\8AE]-4ã cq 4y#Mc'Ts/hkoo pσw5›)/) 8*ȉsՇ6|k|6b asBn2f؍zpݠ9 IMUI'n?|{tl5'>a}^H <؍\RVda6sКD`)Vg:.c:̆g JLX`3r[H`aǔE h!Ap14f8*6 4;/Р.f>>fF49RtUZ.##&ej,(}/9D4M嬚4@|'/$L:)cSka;os#5v$zx ͗pV3{(YT府JM0RrSc7.C`CM'hlڲ‰gB.tKL:U̲_s=[68vWC<{e|6@ܷJ Ԯנvƶ ] 2s4ǡKp~tIԺ:1*ggc+@Hbab%z1O}@LSsgҴZq`5sM|zTqÆt؆}G-m,BL|3*+Pb3omDEM~5\%qƪ "QcL-R*y pŌl>TPLJgy D5|UѦNj,:Moj9FؚZ@)B)MA5RX"D}>zj+l#%VF\ H~5ǂE7pYAmIcPýhu=畁S4wwOBݥ0fW n 3|<}[ tvv߄RM!1,X  ѱ1ݪ%ay˜2[b43TD?-0y Mi]L[4j@.b>СU>m Uߤg5J(^q~حN_0kY~ ,`4kk T~f׈AmZ﷗)QOrǍm͂F-bvZvO_arm%|)1`W Z3oC޷OY止g(S(~C?ǯٸfկmwwᗩI\{TKI ?S3ί.^O; X6o||NZfmkAkeS6]S>O7xך+.E -" 1V!7,*0՟Y~4X y1Y\STX]ofy6O]FhBOWlr8-AVK-ÿOT#*5GG%8RMmݡROJըǐeOJr>CGGc">opŞ~ɗlԝvnzᑝθ~F2Pj@k8< cbSv.Dcs#`RcXϊ[jNnA=q g< rҡ&a,/Eq@/Rl%vl!E񦥑N[6 tiDց®0 A$zhjѣz{#^"LSi6y?^ ŭP "؀,lhkpX(hl-!q_8ƈ0o0R }w#8)mGj`ԅcZNuymm ,vx4 "BI3c*)eC%H,D\S(te5Z) .8Auq",g[\}Kv >K*>CТ$I!W9'WΓ~Y,C e0{!]sKf_uy^ JCf׸Qی aA4yX;J"I0, ~N0l[sE",hDyp@M$-kO }~9b(Lr 1,) gtS4_x{1ׇ[vJL3&=%+ꜷʺPf'%8N^cv7[ ,x%Kd=  3)X85Wo˃a6pj`NԯmX7юc-LۦT y|cmANr=t;K|Y ~H\R\ 0( 3l(j7+,pvIhE[dO uSy2z%Fk5+Jj|:7Dpwųͣ?}r61N/~p06l6m9ЉFѫNI xsHs|j|zZl>ƼӢ]yKr Cp6:5w%o)){3MÁ37lWG?J9KQ|}>G'w+jJ(y'NI}ے݆QZbC_a$Vj,!:cdC[QËǯ}[]΢() \w"A$&X:9FaFfgO#T([@eԸ6:}Rs[DHyD@V;eӾ|%l9;#%3hcZ9Kzt Cɠ 7Yվ8|NFq!Oq%ퟀg388EoNs#1 2ޛ>Cd>({w7Yavo%Q};lg^濋9B3_#nWch,/e0he f-G$RڷlVh G)z=~D-O50&92hɩ`??>nf4 %,O 8WUl]aP Nh 8 4-Gib<]p'x*y=qk{~5{}%sFdIg` l'==;񶆏|.2Pk/] 86@6/U|ObjAZ&:RQ*cV4^kbͽ b+ڍGv7dlDfyI̒?,y*d+4IsAMӂoirFHAa%OMp K/ @fi hs|ZŰMQ%yG'V ^$=NJ]s{BZ)Olx,N_Zsf\DHG)q7.$ݩ> "H^qcc&~fgu,RPN.5$C4I=\F2Rie2xg6v4-Ʉu=a|ê!_R c%N+f-deE4}Qux A N[9 s+]:v^שge@%e]eJ&8VjVqr4O ({{Z0 Ԝ}e1~͊gWrb+gW8Cs]'d7'?~,=u*:N`2rzh{f  1mIDEgMDtf텪]MD|{xy &ܭs @W xu,FaK5cG0e_ haKj8@VGu=Co(E(\QϗI\IQ%j& u ,,KsSAtx& _Y@^Ih8̙%#P{uv~EW헆 ErD9w$H?, _b9"A/x3r%TFV#>E(5l_'Dx.6۪ڬ|D}Y~e})`w)m?YpTrV3D5$t&}})7UNpAs-JfW}?|m ŸR076*Rs|3R fv):9٠ǔzJ[ЏdU XM&rH`uaS bԤ;|pJQ߈H}C|MFu[Ȑ'a` 3k30mzo=(ly43΍Xo$l6|l㕾jʯa(-ߎZ:PQeQ!?]x#2eG϶Sk#`azn6fk.nY|gM{6.a`FByl'xѻUsaEWX3r..*SڙV( aZ7.PjfuZ neB#@4t Yc0}3evm}1Ry{i'ީ-t =0n+.[G ES׻hW܎*X-}`[ 97Y. F!˻mDB32H@)s%).B-VM\nP"*Ыb=!58zaOb$)S~v~߀\e8i]-p.c!У;3MqÝWVbQhQ¥W(KBw%W?e6#/lH]>DoIZ;?Ly*'zz6ZWm_$2+\,ѐ*Yg!%L^xbbP?s7JtQءZ(+1G"\ai?&pΫi_3RcJ`͛TO6r;_?[1=R%~b K3A𱚴xӐpI (UJZ&Kiv4nn_<^jy5؈3- 75$e&tCBL>Ax饎m9w/ͯav"GгKOMsp3,ײYU^Zw_A&GDUPRj;#d}Ƨ&m tYdGOi'F܌!}xr:b8Nc:mRi;^]oj'1Źp/DRi W=d;iKDa)={dc"jUKX.`[WVyYNP8BfT}.N yQp`ƋOmLnG[G6WN"W)Wށ. cW "xS93(9F*U&6ر OLxZ(-A{o儤7ćź|uM,k"gR[}IZMpw| d!lzaNw>Q;){2N+wOAzӀpvx"5{]|RSnj×Y `7.P;y:Q{P??UEi[{gSeps)t:-&,jWqTQf_>oE5/+&Y='TԶcQ~ߑ.sweaKp,?4Aɸk>S?qHzfڬϫgG[*ks;*NCbV>nxrsqKLƔ"yJXv2PgKIX)@2ИFUN ﭭ%C3 ~gs@ ҌUsfQ*!2Y$bB<{ᅄ(8[ބgqY[Ч|IgYͅsiEy!#Q-Ka%WhAtYPC>X[wSv{@)nU25r4#]X[nዪ.Ĝq0:%\]9Ak$򈿞e(\RF-!2" !^.~rh(,aȇ6Hr^c ۦuԳ^`$zCߣʕo Жl/q n(ԅoE5R|!:huucIK Kk {=QW٭@VHOxo[KEÞ^O뼸6FK@3`ʬO2%+΢~L#$?kTBAY(^!7,CU>˙D[MFrٞ3\s2WکZYvp]wk(݈7:RϜ'_CX#+{Dx@?śΔYo1˟CU_TPxjYbk?V6U+\I@~ἪЛsRh5lN0'j/@?hAx2 2[0[řiSAPA85:6Q\N ޞ'kTftx / Y Tta*Q~ ]1B%r'm _ X({/_:' }g0"xg:Ȣ{] t>GuAw$'WL 5 'tk?kQ/Pd^թ9eJ,!πl#(Y1HhG3/ O*ɕ"Jވ8T(^=2^jԍ&鄢 Q1]],錨9'D85}RI}gVذ/fi#Ag#ڭ+FaYSm/JF:aC *Bdӕ_d&V!1x; c/kOv'*IH!V)FЊX˪Y0rei^(ߺTفʫY8gƎgk[- G ] s!cUpwK t*U?Ms6T5=D.ظ7f,/ǵ`H?&CZQ~iH$!֦ &օ +rlDZ+ KK_PY >>Dl?/ʙp>{e=Pv΍ʜ?_v|4-FFo\Su i簗eaO_lDOrk>oj %OOcO?lWqy%'ڲof3 \&A0 Y9.1=U䔲}LZs 3KS#x}l;W\,@%+aNƍg:fƥC9),{3ScN/Gͬ|k'5@(Ae̽aLNZ\@qT.F; 0`U Q"4y2[pdH|A4U*P U)+Z:c.шYnd@5 w3CƲ\*@ ^ZCH̲JjE "3.a 9i2 |GC&$!VF+R6@.rAշ-AͶ_q3 {k :͆t&vηɷl$d0`A\^v,M( C2T#Lqſad<!y|&V,%wH`g [uU4 ԎD6ړI}Vd0q Hd6d?)K<;Ǎڭ{7W\ qg .Ԑ\V-T)U>gmj bYkvMK@-!4 75RICwqK4~>v(t$%GR R* /TDJ{T&'{c),4nA׌jS +zAv9'@5XQNz˄ġ K3F'7߂`>1y6SϺ0)g lqKa /VFpC^M -wMoTQ> H$"R:N4i9"ޭϐlVeO,Fլ}` q0$$y&cAžE d ttڕ$ne $^) P6 @~O2OHmp:勓hיnb ^?o#WI)k @~| ʳ a֔T} O,6^+Ⱦ)/s`s= 14 bBLt"k4Bt<f"ɛT,w4 _prT^#E_ Rhm c1aJ $^I%-Kt\biF+i# # z%FeuuZ]c׃ Ck^N$6A=u{c>,=hזAY_g7#C-h٢0W\0]să;uW[Xy6": D/Bem{y9/~ (?oxPT#vKQ&>y!oDvSZqM3է?2(?/MĽ 31A)XV&XA(k&@,Wqcy KR0# }id+@ QM#Uto~I/db&װVC^k;鬠Zr@Xq֟;[/$ Td=MM x `nmG͎_\j zKrqaD~2jß?_YѾ~⭅0@p|- jS5Uh|+{DnЏmT%iG?rdT?TyX+Ѵ7B kN+Jvkߎ5)Wȧb}Luh?ncN'O6mDizvCݰ-9m,UT%qt,ՀMebw:WV*sP~n8R5dqpN7ܝwƮNRsR!%=G*P`O<,'ǁfq J\AU,͒PcI,Zd%5-鿝>ke2J`C>ђK|% vlDh1!4D@KKnک7ݔ&ǖubh2P6ǪJ2P%Sܜ8~a.US9lIqb=!}9gɓK)0r5lM-%KB "4YhâIRD``Wxú Y34Doä>i10#-JK@4`Shn$F\yUŋؐVҬ@es#6< f=1sz*g/Y67*'O.J唪lĬ@$KpeK ftJ/( >JXTIoT;HNh4yeNƆ1_ C^mϘLo髆qt0ıuߣ5P-[uPr3>0B3!ak>^_gd73)E]neHsZRrb``I`ySJBA*P>sw+`%nqFzlٴx9 C]!9#FfٙfeiFvqR "7Y m d=)`* Mu5 XHqIeOR3Y=* ESx4hXpk_!ز},FϏbc `aHoğm(c=\`] Qk%n`1J3duQxyϢ m `& 5y9\ YZG0 Xo`/<ڸUI6TdkFf͐w+ {̊{,stVGRˆJt&; *#2+Ժ0wJG)"kN*-wtH<]ya.&385yn-j#Z3>dùoZvDiܬO:kp4~-mى0 @aHej pg:&†ϔ?g ۍ+֋Q?>H1ɸx!X`js9\c˝t-jDCՙ j]'ׇ3a `췚(?G#"abL\mi<1en!-0A|w"rC,o9k?pcpU(⸥XS!.۴߳({457\9B#Fށa J-&(ݺ#;B%` jМPpˈs냡4ts;h#Jh8c(Abt>b/;}@LEᵻ}ktyQUcW9-K8SLht,eq>u")ܽioUUX {1@oud܊*ѶY Cið - ^F}X^:(~^ IO<f̨_-%Y (su/؋=kC{;;ô6 ?hCNƅ[ FKgP xiTeآ^ ޕ8 Zfd58bE-./9=;e[APڨi b!J~ۭyx5p" в$=Qn?S.-9WNNڙ2;Z`ёg(ز ae}S<o6km>V+% dW)!:Wxe&Nm4QkSg=4q5cz"Cuc{z@s ciH3 X.t lu# R91P_&-fAb4 ).."##1+{7+u(Cm¸ΡqAlq#OLϬv\F4k%gu3dv@3290pK(:ڍfX i*o6~!nQ _Լ_W~kg߅]MCIxP C!%BqТ8i܋ƈz(`!KpΨT\ .zÝ8Q)78 YV׋Gn HOҒgk]?ηa &sR$pKss*Y9(08gofB}2J>l6Kz$њ5c4"ru%SNL;LJGG9#bӮuvK='5۲'Ό2ՆO[`A#D<[] Pm+Z=msa6&&zJ-'M2W\Wp/\_LblF@o@rUKb^ɣ#G5ѷȬξW*> aK{NRE_ƽ:6{Pw]otҼ. q?00|_ΕpM,>T9:$P<>.tTХ5zal|N硌A;*"L39m*XFԋțEB64駡<,jJA跑iz<aéK1ec:!0,cb`$se6x@ OIp?u%/;N|` /DžEqoqDz=Pܠ Ӌ)fz͖jr/A#}|m9䅍ZI[[Ê|/Lg*5jHvG}B9L('854*L+#O ҬLas9#$1l={n \uX>dM$f&R1COP:gפ,VCP0s),P]MQ!bTVn3b-&d:Gyqz1ԮsZ[dNCli0M&2Ļ4L`1rg 8C/0/$3:4Ot)g,ftEor j`jQioPb\~YjT 6{]̍3hnDv ~1` }|l I6)0u5WJ.=~٢28淽G;BiǬP)!$eOCnz95¶~͖)N5 `ZڵT/_e{Gzb413c|!4ID}sA4<}j8$p"}UY~6$"ADI#!_VD|1lL9a@5[49q:g;e#j3-RBG}\S*GH$~ẙpyIщ@jI9|ŖWF0UXҲ 60Si(Nw X61)icDm ; |<-*<L,XBof\i9"GB4l< ψ-dݙң鰣]TBxKbaMQ7P[Ae7ۑV>Ens/%Qz>*AzkV}AcXIhL xo!)6集UnF7^e3QhU`^v\/+KLJ96͏׆RẲܶEAඵeU6_9Ev)|ݖ kܮvpeO\nEdxA?HKDlkuVl>@}j\ME`U|N|R.KwE"4\9x?lPse{B4Dqxd)&S\x;Efo\fӧ|TEyR3eY7ēbIfc/w<$ _ 9x[+hRͩVQ䞔 _Dԏސs]0xa%ל:i嗰E~zX $C/y&ǓJa!^"e4sS@@7]ںxd9wr˄37hڷ5#7M*gFJɭ-dԑ˩B7-7vlJM8*Vu]{NكR,\,~XfC8O^O'LQz ɬ I'`|dBqN8 HۍޥZ'#Ɔ11\X!Ͼa n1hӪ@Ihcù ^hΧǬD%j^jQpvg@9~P :;pP}9D J$LFqzA$f,A mz`*^ ;VK{ v^C^zuUe R\DPXZu`p3I:UÆ_.Dq6_b9] (jfS;ЊKJ4邲'm9o7ғH\ri+//r*Ϸ*U[҃ix'vB4'L`C f%$wgwyRÎa3氙7 U.3r+06\RJ ̆Pq^V1#ƍ2@\J.\C{ÖlޑH_)!˄lQorzLo[hnߤLm׍ 36M[x$,} '~Wu fܣn&VLJ1̊w@0-U-Wya=/Ch6}P "sg\82cxybcQBGr[w ˍ탃]z-- gkf94ܧ[[Ox/BLٗUIcM,{^&XTxi˙|)b,.Q1uK*JGn8E l q\O/V9J<8%P>*@:91|$w$I .Wsbn;80<~G73gO G(LB>8ylvh  ljޓLg舤+2zˍX9V+ '^v)[1un33|U@ :\{q=E; 1g掐{ O}*ԋz>Ch2ֆaA. BHu-c ͪ+¿mط}-F;WV <z^|O.)oSɔC _X+Ci'ލw5 L5՝0A}@t#Nβܩ&IwEe\LQ٪[3wΆ+Tb&g6=q$ΪC1LD$1ϔ1 -fOxlbxQ`I2&JX, vPKL;kNp (SAٷxr[X3by o]Z+Km*=OуqvҴg|2:Wdz8*֐]q(8lsŅzΪ1|䇷yT. L:ڌiP߮R2 TUXz2觿;G(/܄An攥@retAeaFaȈTQ/y)F X<z~LMgwv+Q*5Dpæ ӻk1uGo=~M5QOYuZb NSExw<ceQ$G%Ku;֧ |NK*|kyP݉E.hX^)Oa)5I6f"}Vhx\-<9_t(>fr.g]u%$aĤWH::1 #0L;>\+2?F ?+ ֭uDǰ_]u?^gsȃo D fzl-ThVvW8s@Q1q\"N J4b6 œ@tABtBcϾz}?9{tH͋/<#e <P);Tyʖ7bpokP5A 8+bq8mUn;2Gycf׍_o=j($7nYyb=i'|4BZ+6THrː:bQ'w7})*9R4QQ4zQX ϰ7P(/oUY=-Na=%8\cLhz) Tt0"\Ț .˃۞2 b%:W;Y]KGyD\WS-I2ᚥ.&U[]3F Ee"؆pƁx%ѽ%Z4SG$KE}!ݖzh?M!ƾrOq?NQ̲|l2GԐlI 2j[&!H@dz31АZ vmdWcy޹uRJ^[?|V,(\W3_:2XFHMAU/nkp(>s:%| n Zj_,KݗK韛n){ A7|{@qP g^EJ`:4eq8VɵqefPBVCMVzmWjZ8aтhh_K)%5tPpEl:+(]$YkIǭ%g咦l֚miqc(C;[-{rZ<`%X3zmd!I hB <^oRվ$rgoer#EQ+⤗~sr Ch?$2`0_:X LV7oVgcf<뜨Ut0yğF!LD t"plsE1uV NlN3=*!Ez5=")FcX3Cf}P'2 T;ԛԞW~LI6 ӀyG 5t{q%*ZF$[de?~ݔ(yUGTК6x#Qh[\x1*a'4`SpO?dt|f6̚9YFeҐ{ hr^fU1}Q"DO.tS%oۖQ~Neu1Mo)WM?P/0bLMpV5i ,̇垹>c][1{"4ulńk'aUX[vcp:JxWB=*:]I< C* \~ĖR7{5kº?%[.C=*Dںh*j®DTޙ>ާ ۪)@KDZHzKCE@f@qPr v?p.]S4G>5omav|E>+}tk4]:d-<W//??۪ew94hxP0hiPAMja+O6H!g+O10=Q A <%<0]fSyZ#VN,^?$z]V7&R%(JgK:$]AV%Sy'1Ґnϩ+Bv nW~29h\bS5c: HoKHυ7 } cd'Јt a7P0o )WbQ9_\7Z=;7sF&%x-[\spzsw,n{E aPN;:[Xw^K$!/{uD#| 9)PB:4|;bHԙ>mJdg$<W >0uӍ}H g;w^ [ ><:~«9nmQRm!Z"%tWoVJ[}YX9Un S{ aiwa0fB AF46FE}ט Z\_س&e6Aю fM}:nՀ+,4+K~6%Pw'|#9sROC)J-0UwHaF 䅯$RФ8O ,_e%UEeH}Y{JJ\+\7VKӄB~hT6ۉOJz]$.lsS|2Ƽ3O7J>.yLwg[?oaٷ:MV\rmpFK?. h/ï92tl!qO~%+蝹 C zTeHִ6,Kl5͍ZY=_*z 4Z7mkRp*!)wﺩFngD#/($fX- R,{_fH@R#SY]tIR,S䒬TYU2,O-Ȧ؎{,GۿlJ)j6"B]Cϰ'z UHJB%\yE= Mqy (pU`V<gӝy \b*:M~lɸH%q558_4w8 5F'>sExtZ doNJBז ZAv|*v^eh4^14?gi̍Kl6]v^ Y,ת=r%2szQU5Af5aLDW6߫g[tn ^ATgV6h!~n)h[d{fGKz RЧoH-b[M}C|sKA;"fsy%@u(澃B? ?ʏ1IFT;9k<݇ >`q*'o;SY#k7槭Cz~uKR0~{e,BhU&xEstg{Aۋ"#3 y+|LFzꤘ[N}igwM{^7C2b26_9GA lw5JM>sqT/[|^ݝg?A3*+Z>BGT ۺ+ -…2_\a'O J2 !Oj?0Ƶ -ѯc2]S\>jA| d[?..8\}w"U=fyL)2؆ 5͉`4~%dჲ=_RF!wz8ͣÝTPvi r"s_"/u{˸:'cpDW mŇvc_wu5fv>5O.knòu'on=f$0;./E:~d!Ϗz qU9'@r` TQpQHARXQO`F^^ar 0=/ +LYAm]WSx0^Ip'/I5p;nHGZ=wUC(akO#(3f?~Ox@fӫ#887{uN٣j÷GWo6O25W87qzt{|eXH<(UJ| I~r.8+Ռwkb/{%"9|e9{Y.x)@W// ='*xO ?n)\IXNIC=/va+nWn+R7kEE\V?K֤<{[*Yʣz>[?a ( iK ,T.kJuey1b^Љzc#U<,-{ҎF$D> "؅43:ind *N+%Ɂ+nCQfQ}#fN鄗2k bOYц & [ru 6cNz_+9q&x:ðy+!-8.ĶW.QE9NqU9t:o gT-(s\9vDj~\FM?V%7Q5bV NU wd86;ヲvLgq5@ĄU&0m7e0_-0z=M l؏y3Sf[mB gE 0ߋ;AX!ݒvv{h-y>0Ku R,u.N_G5/ lݗ]I떄ϣ4ʲOGgb`4lK>BKxE')e8E-!&XڸWv;mxJo Fnڥa]ոs,ĕp1WA|\ D#̊%~dmGшRm04U*L[4tScrIrsʿv NFӍGثv*)S_ȬXw~'-%X.)jȡ$]H&H-vBD-AGJ4<ſxTLythȐ%^ NI27U*xFiR)5t^"oY&s-  h 9h(2zO Fe,DqSBELTQZ k-f=RCsC9ϢNRv_ RJY|x:}JooVMGJ%9yxu|vR3=b`%jeooqw?"tH;4.X~~7ҋw#Fߨ6l`t[J&̳Zý ;N?>DTDߚ0>@OR;Z6}_A} ;w[\WTQqH0]gkcU(8%j)ę-ZV"@j1;-"E ".j@yJkWTd(&CX8<:{-r)t_('?O7tnT*mi?"noWkORB=l?Rߴ(_!1SR 㕥Tǁ8+ꋕI~&)FQi[(ŧ_FNPӡaK lwz܏\T (NFZ^e`.2|ƶ|ZADDS/$ͅX ɲeP2X ־y][ xzpmF B/mUnO_X8 @.A%J@? Y1 ;Qf/#t#;QPqMfU>~Q]5䑋8;`F5ͬ $4<;O7H@Ij@ -]qL)8XG2U))>JQٲ!t@e !ulnɴ)0򑙕rn5V]R9nj,ᇭg3FA`v^뤣N:z;35gW4rmSY;&~>[}^0ΖB']LkRI MJ5F\gYg wkXík!$*۪f`;6:('`nj׽ ylgkcC!~+k 'HaRWPk1;#e~"Ԭh 54l/qZ̰Kfm0<=ܳ/pǚޘ=(sG1c=Ysh:p4V@'AXiH铹;̌ᱞ]sE!UY'x;WO4,!@ŬB/mr%u'wPG[Pfv@;[L0W/۬IkSvN_t(ʁ3Qaw }>ʡVv}">p$bJզinT`:#NҚ.6+3Kf~v T6u2SV#,-e|缸 w ܰ06?}|y@ȯ0 "Ҫl9nn\8`{ȳ/n +Tc]l:>[dNj&"B=!p(BZڎܻ|},0pQma-WAc2#B< Q@\@tf稬laNm9Yla3,ztqԀc>/}f~cr4Lh .'zϺ[@ȅSG v-}<0%Xm+!˟c A~tj钄$ 0WqǨTAM1mH@O-|:P [ 2pKvᄈ@̮:Ҋ7F`hC5{[ nj(߶`/UalhV1:R5l3=.O (?7 9>6᪛SP!PA^t3&>+@5#&m e%FMKLYV[B|Z4rfӣ|Cp/Z!{MSjN:ohw3-Fy3v\ML;?;|r\ű+: lKkMo+r:LBPIzBFBᥳmlD0v-.5KL߃ 5sv]ȳ".OLIH(eu7NlQX =PYgw[^W'|魝{ۡFդ̳k'~&R~PTرPXxs˚tNFk-4%s/r9c&A4x'7StΏ,;_"h6%&=X}gexqAvh^{gdM8rM-B>oF~+TKF&-Qyp44qboS)`ibBH<ͯշovqW7{r]l'No{qϺ{YM;^WT >̬|=fwNBt7ԤEL'*VXYm9i޷ߩ̨x'ͱR b2(^!3xT 'ЬJ7VF,̰ږRG吽Z ᦻU駂@>^b:9?lC[E ݽ,fjmrJo42DMYk3 !3wnRh|A4cCD%¥N (%6_nDUB&I85e_(~g4~#k@~2 Z^戠2F *HA/9|&{.mTΊ 5Y }i:A K .:N4{9.j`./cȒ^s#qIҌ -չيrD: hŢOvuQ*'K|G.waF .xhWz )@b?!us&Xcd7nMgSbs;ّFQn'wJ鹙$'G)pj1#ƛ XO'{?b*C-αF X#WF'țM׊,6O˩ZQ[lӧI y0dBVKOqvhqY:8l)Ӵ=Si8$:PSX#sw\UXPpBRd _T ߂R$ i0rPRTɫ)*&'&zsD- >L2uB99ė8;+NN>!d?XH/as侈] `]J!1GY.ǭTWoQ1 !Gnv {s9ny+.n ?pv7k>H0$m4y[*U̗phIMNrvK%"RvzG߮X0r;Gblb~OY#l۰kq׬s @nMԻO~iSGGԚN nܨ@X߿e}J+4059EwUJts%|ڊ8 m'uQ]ELNyD@_ N0MotR9"H0`>YX`FD 썙lG@7j$p./񶰙7mS1YC!r;uJQ ?nd3rGBqۿ%!VVlRΣ  Hl)33LǑӨ'lVpc"KMʂkVLiA&BaTdeRr7& 6nTcs֘ScĚdr6|*ft}d;G k6U`gds!zNp5gU,+屋R6XDy߭/!nwJP[i5 \Bd, 9fE"L-VtARagиѽzBAҨD–yv (nsPCl:Q\aS* {S;FN &}d;$JGDq ,rEekQkQbR/flPlV'HuY~5.I71 ӹcۈ{u)ò\7%k, ~U/%iwmr`2UO*_I"79ЄU҂BzPrZ:9k^yח)2Kʼn?TiD7[, 8+ϋ voHHLįۡ7ڙZNk*SCWsDl@-g?H-[PY *S3r'M-^~^BіBm>^XcDb,/5nh QxT1GO9v!$+`E;'wOqѮ+bw^Eeaxk0|7G9@4=OHa5ʥUXG]>}B ~1OE,f=fqCZ¸b~{4MkMҎ2.I2OCE@5z`n14l댖C{3|1s>1H4~Np3؋B3qEfK[&WerQ^օt1ǶQՉZS79>vi['eJ}uMV$ Uj`A=&ܴb˜Nft &wdvN@N1įom}}`CsevIA-TBÉY"5U6vX(1@pA(p|CQdJ:5W) + R%ͭdAoܛt`pnU6X[wtݦIb~K}rm,z BJVp>>x蘦&\E/у&D7۸;K. `LkQ ;ESx8~a@锧N ^{>ɍݍ4ZHyAV+HRPk\]ÉIxRGxS.*B0|ReWGV [} bo;YԀʹ(򾏨&Ҹn5Jq+KDp|b^? &09!7u wtFJ"pN 4 EZ:B-h^'Tg*R2 !Żr\k=e /ɕ&Ҵ0Zm/rӅe$>218]8k=7Uzq,67Hp)y"tFI_L*jd4%Kgd|V>^?/J0tu薋b<ͦ #HJӧ^if^%Gs$ .5J {i :K5'+8fB6<էn2*Ik6Lu#۴ĥ=(5 &lT3+#ꦩ$0`+XӴlWZ'| Spzoi!]8l{^07B߅g!XsBBWkC4 G cm$t|v87ShþT'e4$>JW?l QC(>Y !_ qg~~oO+_6 7*dBjt\K).JXKṜJ뤒,afk+*["s55 M'{ϊ-ʠGCS%7OQviKA%bVp 9'`?XL ʼ,V(><)pF3QC+K2zq2<ﭮ'-ӑ:nZgDyo >I5vOZ]j?=2^5*jjO:O6yeerG]B dm#b niZm06a6VfM!QzNII~쓄W:|CjН.PM&%%5=3T'悍$8HvY; 7 Z\h.O} |[ro<sp<_nH5lZ]oYbu#7EVfǘ&2`6YEE -mCS1*#]h1Ffq5&M|$J)(iH fe:op-P}r L̟ޡALQv3\L8/60\i9P;Ψm&tq|uݳ|sB+Et>f(9L ZHA[sg0uH+Ò%!:b-.3K}do"B1ʁz*GHvYe}vmq +~^BnĶy\Rd5xKAQ zCSiieRDS*s=eoCܠmN PX"+K\Bs6S>bUj{,ឺj'u6d7TPl\:<[>fnj`rh{-) >i)q1Ia+M"V4y S:[\M="p<\%P0;єWKŁ^Ł}HPk*^Ƨ?>-G3B9^[1g|5ݲut}En‡ob@ܥ]<9x.BQLNu^IO咴N7h0JJ -8 tQr^k7\;RH5H!U`zjD@e4䚈sJjJ)q 3Żl1[F?8ͣݭnp@Pt2M2jhTTZL+Fڰ[TN pTfGo;g/fx2A53Ћ6_>yzwHz0>/<{ެ,?cak8| J.6I)1dĊ9ec;8[SQ?>x Y@eT͋ws59rnq4f bebkJMBRI5 _BM0mm4\ūčF s-]G2-V vw^fN owXKr=cg@K0 Y&j3NoZQ3L] J;I6ҿ|xUnC#Bސ|e] Eɱ/C2Bh} Gk/Aq9__k47eNx82b>Rppw|\CɐP]Mˌ (iz_y M*O)ﭕtԔs ^١c9~jqŁ">;b=z+ Q$ ]_V} 1,t6ge\ɀ=`x34.OY߹$&ˋuݳQyw+@O|`t9kQg@v ²9@{?4V-Ty;֊|}b\c(tncncIK4кN9Mآ4q2TR" ܥ_ͲCRj^6[|='hTW\̸v=kADIGh->5FXv5Q?O$#pqS{xw7~ ;)E9h3>j>.ɕAr6uö{ kĎH\~}D7VhS;)n?_j/uuDqM۫ПYsvVN!^!^u!D0U3ksEދJ Xvl䲯EC5|74n˴%D ln(l%='^]ULg8+c a1 |#<6fW41o9=`ov>{L끏6x&:pU|~~śO}Əp& E~`mP Ӌ 9XnAO.,|#_mmp'֋y:1ݞ9-~Ro}e6T@i2=#,$_M/vۏ iuDv;};;wݐNlx3cndg4姃ㆱׁŮ5Q*l%^z9_, ݚHQa.D3Rwf[`BIYѰ/ hCGbo>iSGW3cFR)׌Y}2yF 1&LL5.)z6b%UI*P;)e$H>fS~YA;Dݦؽ6馛oTirOAJI4=]#FD\7E;CL >rG;DIʁ}ЧW^hnAE` VcTYhS/]cx6@Kyy3pgoD6ٖh";ҝMuGRg&p8v(p*D3MX1Zttg.v$~j0q#V>-=))dK/K&>{ZO(*u]r?Fs.=keMɽ4Ƨ}j8S29m{;XY h32.b~ԘUᇅ*s+;k ZeMNrS0?K:g/YeSp?P%̟a;wӇBZ +߱L֓cI|=!Lfp{Lb'>1sa1g6>Qu@4fF2AE W/c S3bzS IDH4q8$M8 D1z@uCݘK6M0l&)Tj 4h $Δ,4Lg !ȁ@֋ۃ#N(+tVWW6҄U!Vu[mRP$OFu4N/3k. C Mu5\`>tnr +E\fU!ƒEjm2"Ka$>ׁ`Fh:HF\c5 ƒfU^ǫ?[r #(8h^k>:u~X\Gڮ61ј< PpCBwd9˿XP:e̒3eܾM nyq6s?W9S;tm-zkiY9=sk\t2;,k&i^t|)8C-Э󐊶5SeŬ$Bc_AzuX YI8h 5M* ½4ÿ^4!,4qQD}]ֽp+_H5 bZDw,|mu@H.˒[?Jn6!;5٧So vL(Ld[}an~ڽ` s>0cp,1~q!Yz>'Bn6'I3jr6f%[NѾx9b)3Pw-JT42S3ir٠VAeԎ= 9I">!  !D )DRtP4@)[;V&?WL q)jM"`e**ZꉺEҨ;jhHi AG0QۈzuJN.i" CpS1z+I'ݲFQ1lc76Q-1A OLxTPҳq Q$PZLT<=zu3 .Wg$0dZq]=|jPI:]S+=zسİ\J16ׁS p8 s_7 *!&XkޛAUybh9Bvҩc[k1Mx#xʍ `|pbs <+.IE@!"钲<5Wg՚B&P}87B,EO<])|ۆGZ1D>.t 7x 7l~΁H*Ωnt~gk%i.'(zC;X LN;cщO`M}q<\ԍÛy ZJ5-ne} -F>TQ=/iZU,Pc!~:^5 ?3[b$C  =z7Z#Rƚ #FTunQoU&+{I1Q:'F]lF ˮIq"5hN?2h~ca.qY,@bTMG yb%wXʕTx ez3/Ȟ {7so™Z `\Y}9(.X9nб @Z5qUCS`,ʹ5QD93>>F4mk쐳Ǝc;k"ؖfMŋ.ӳ L˰oEh<Q*݋6mG_ӟ F}CqnOłbL^]7_mDͰ-U5'0EᐤzFg 4Z2Itz<\IT (}p2O:Xg-4S?+Y1 kGyD#'ߟߗ`1+Q N4Eoi& ק _#*>+W<={* BuvkQ& ,10Qj_G[uHUU~<4ߨshBQuRՖc165)ju(#; ž#{G \M&(sc^"|VL*$8kGl~2e yN1.3~D@"r}ex呣G.m"ICQヒ6jac>KJ7`Cnd1oKsOU¥-2פJ J"#P~"\* ?d.T 8{ןߦ8+pSkN܇ɹ_n<Ҝ߿Hv Q }Ǯ1OrqR*kW,_ 6.^k*ڪ UaD+)d5Фu͟D%IR8_[%f&BW`@{HuI )$iZn!9SF](͜\iEߜ/h8a@n3Zl闠}%}J) 3ԯ9<)aϕ9K"Qt9/% ~xtH&CNyhpVDXDC);D5T?%D#vQ^G ziINtN&d8i+uDgs_6PXX"b%,OAh0+"ۉi+ 2N?ojveer|z Ziu$Ή7q} 8j un[E>?_wh8Cr3~EBK֭ƥsi%0iEWer[{޵o[U.p]/ruϺ]vItUY_⿺lbٸmuϭ ݾы;R7|vſԋt_WvSRґ\:`1ދŗTu&*>Ϝ0]NzjU1(2yհ̺0y|1Ȣ*+\<\A,cq;m+

-m}r1T4XaYuX'27fP)2lp[[ɴhR;K4Cf]]N/⑺+qV 6*  n nR@i¼~:^W4^$%;KGȪp>OU!ϫdaAIza=ЏVNOE .dE(RŤ1TH B.z1u!0 K׊d3dB1Kʮ ]y:T5s?g#?E; 5ՈOC7!G*XL.bp,V Uxq2jql IW#)$:eq[Lv 3Z `6~}A-͡fy ;FBXSkS5a;/d8HwמƟtNF3 7$"fL|Nk@:i>%_m%z#?|`/wf P2LqL` = Pn?;<ؓV3o4TTpbl3[r#Iͅz7\~s7s'sb˯hBJRqOYh ϠzĘim*w E4a𗤌SJ{&si *@ *=Tg)Ńu:/OYSUk1Fe&(5'aP(UkJ͘2tڇV";A_,Y9Lwî&3LWZP\S3RKe\)&t[AyzHZ}T^Tpse)'ڠXa@>՚iI"*rsU74GJ6 Lmh^"sX]cA{A9y ۅϤT`Xik#>ғNjLٯV[`8l lڂ My8n97 "^G8X B6:PԛT!5I_@Ǫ608Nk;NY*ng"39›yش=WLa]Py,\ .#4L ce,Yhh.pP^ =&1` EDIvVHd1LBȐ#HɈbV3^W8O&$@f-``{pJ~JbRG(ɬK gkYZ5T/ ׎r89axeSsȞqӠ͡ U Xm6w~p`3&[$-@.,q l"~ "T罦#X*xN*!foƗgRôTs bOiVD:\[X`~AmO[j$Ll@j|mrT܆Ņ񜠩PWKz27UD& O/U.iϥa 7<~;fƚ UpZ@"R~w*& @0.׃$Ih&5e`<=u=TVo _Ǟ! $ѐ@)v +C>:!XX зo@"Qf{1|롍4 X'dlBZH޲vbH:T,Kq%߄Z.c4A?xE9=rph>K2oa6Z~b!67S]JS}G}} LFbap9fkbBnDIm*N{~n#Lp;氛Apb7+ r gGKƕnBXu7q`u!{ Ֆ*T)ybbnȶa3inJtNN!u ."pw-qnv[3䵔X}Tj6+Y'R]Y8*r!PU_Owt /FwwK O;Xqk^A2h Z &iȶ8Ő*i֞pܵߋ@ɠ =)YOCKmnwAb/1΁V:Ff2:VXjʹou9S?=>@!O\Ýɚ +' !_e]1RdK?H(Ci%h5HX~A9`t5o29D _k*^=f\d[C-3Ci.f U:6l r@$ L%P7٣u0W f<ǀJN,MJhA1xt .W{ IAIB&YE):>T[|y` `:kgV^Xs R OL¯tT:Ji[A*SMNJQ$8}i>ra΀5w=z`pjespQ'u:ظ?ˆ{Q"~wsR̹6V[yűnE;BK ~KWW8Q6 P`!mNK|zYQ% 3PB>6.gX@oT2(m7~"c"M#mUec"^l6Sn KɸT.ˡP0:lAUl( 0eAc59C8Hi2AЖd<88 Kx:Uj`Ś8/E( ї G ZTXi4qsJeЂD,wO2Dž1eJL%Ƚ0p~PA|rƂ#5uxxUg?+W~6.uDs;1@GbȷЁ"k$zX 'QSyj#_\Х?p|34)Yq޿;B1F#U  {U95љo ԫF)AN }aOS`IMŮx5nusB/. cHoò1qa5{ x$wyl |#  W`Iu.k/%D㽡G(0&fTq".,Ғ #̈VRV-xvxAH{ׂ┊<DzS5+ZՂD*rrM05U^`(b_<`9_'D(1^tf[`!«rCEnpڇzҒuLQ!Mٽz4dq2fgakг,W k%% u)07T'~|(_Ӣmz$Nys) &W\PFpV#- "H`ܹN`+ e/T y}^@+H1Uk$v*yb\x"CVO]Ҩg ~v9ۛe% 9kDs_=J1ޭR!_?`e~oL bHJ ?CDWBJ Y"ɠ@2A좖R& , 1@?oς?~j@M9וQZ\:ؙq`: 85s2_-;R9[<{&caI$>qyVӖohF9ޤ2_o~c-qA3 2!Y\qh9 Q'pHִu>Mčg@4.ak";!]b2䷄suD2r٢g1xP!B.9_DWP3L _ K QIBJi-Q 4ĨDTĚ3",WAbtFChbl'oKbHFJWs7"z Ia31:VV/HTvjQ^R P|fJ9~vo}2y!ggaaa# J6$]-r\Rl,0]V!*F!IVFXL.gvZdbŬMf0yz ʉ# WDǓm.ySl|0LӜE9fфɵTySh+϶Ձpҏ`[ YlUu1fWPQCp|s# 4ԲpV7;]d O6|"nho?P;`%"=\G[Z_ W\BMNcKQrT:P1ؘ%/;}tI]$ эfJDuom u&&VB376DӵA`gӸ];"$`}vh#0x5~N6Ps(0s;ǥзEϓs $\3jb,dž"Kk[ `J΂P|7^;ojGKJ$IS}8t,mk}M$g}EC)mm2oL|rë {O)Gd,iIh*~çvo?8șIB餜?O*wm'Q ֚c\m99Z.wc씩yAƏ<4(+hj̈C[06_uM`n~ W3m]!~C.IcH<@IΞkK邽 ^}W To%0+n׻أ(KGyƨ?MV}ԅӦ%_VP'Qbܒ(|(SYLg ɬ4Ok0EDQ oB%(C\rE[4]YR;)X$%a-г@m`:sD48J$Fcf~&ng&z Nj>A^CМ:I5Ym]U ϪJŚ!~TQb:q\]IC 9Gߠ ;|Y(|e/Nhp |ixbd~à# _\V]& (@M6M4OLk"3z'12BaScss52hTtve4aT]&@!b'E4 -mt q ZF0d OVhDi" j Nݪj0yh$if/A}_ҵLl 4 nFż ',$|i@Q bkryNyji[c7J&ɀlt`Bi( ˢee|rbyI n]'eM{CɯIYP- J? EIzOoO~gT#uQb$4C(6BJ(B+G$sxՒ$UP.vUds<oH%͕\!CQy^Z0fPXRBNJR)RQu~"s`Cʬtdp*)$\ϛL(#sR;G q\"%B+"MC4=Or$X#zxugJ$g9g Tr/bp*')ecR=hV]."g&}ۡnG>eo 0r< NR 1x7=G<2~x7 ΍ qh .M$mjߩi.TzE :>=&1.k×,eǂ풕Zŧ3MV|Azd )g&t1 a'6P&xquedTnjmioWWn|3]Jt 6|Yj!umu6f݉86՜b#;7 *  -eH;) (D|府(D-Ry)8-#?ώ~ 6{wwny&kX ɈE83At^pyV aS[%화 Y]qi+U=rІbz,K64HMbbѤp#K^j4 /u%G9m5HK(tP ڤb1r:A]g6=H Y#肦A@d"O;/&o&'wDPKizdsi,K*M [lO_gSQ_&&u\WbtI A,ٕ4a#랥lxk`i+˘:MbdEĶvGZU⸸l }RRx,'ڝɒ$ݭ>KR.đsZtnKQ5-4RX l-XLxh:?{!J8QGգt.N絬>h(PVfoX +!Bŋ}6JeB6Rf4V|˘h RVya—fʸ $}i_IeѠLm <D+nDRclֈlkܤ$Y\*^}wA{u_\txW,(GX@{6oA XPHwD_!u-Ƭ1|N ![mLd;D,o MMm08f͖jZu0ںfA+@,qB:d߁{a1юykbzhe1!}ժ-qep"PxCG2T0g3K pp X+RKg8 ͼ8#.uEn9?ܯ8%cq'9ۋbMyBvDN*iQ"#\I+1ٶNE,O\5Wo d]n(=wu#v2UDcTJO0r޹ρ=h 2? 504Մ'jXb6kvdU7DӤ\GX,^c,?ZK h0鿕+8c~FO9Nu ?,а@6G\DJ" \[qxR`~X4Or>J|L58FWJVWFxW~:>yk,kĶ ^"{Q& ~'4 hzNh!!_;渠bt$ Z|' (pۂ/,;|~v yƛHq 9Jt,Hw߭5{k>k>|ϯk{k/"?[:gK-(ɳ5 9xyt65{LĔ͂OVxW=`FoV>[{mn@hGs*.c4"z'*cq=y$Wi~D5 И.)dp'тܞL\>P)QZ/luc'cަDv_PjӰe>Fu}q5 o)E44WRNx4yXB1>i1שzW"5悎8@Pf%cib)*b(P<ǺKOJhf61{*$4낺xixT^> g 'X'|9{7oXxymx iR4i-E^ ZQ3 -V{餯_*$B[8+MC-%GHH1 r #R&qVI~2G6%&:74Ģ:9H(dC/Hʦ6awBGY-Lhƹ{G"lٜe@n\CQn`p ~wu{M(-α:뻣Y{snT73_Dw!}9jR_ŒdCMM0|[i(y/F4D}L$5?з;.p/-! D"B| K;RBNq n||j!bzTB=nĞbDCkXX?kb !!vo%>| pKXRrVȯ 6M@bHYqUdGP7| l+ah_w Jq#,6d3NleW"Sc×ѕ@MHiPo,K1$d3DSlC:nT1!qD`bGrdʂdBLu HPI*/XUiN a:{D ۽ S1l.u9eR̹=V35gnc%Hk ax7p'aBV\#9Y[ ^ i>ZAa̓vr y׸W5OMEJB|&|q gYQZ㼮ru RfU8+*E0c\/ =ɒUq! "*5 Rĝh Q֎3VX L## U&$x> awfr"ٱPFYJHE;(%z<@NT=>]8*%7zP};hg:yUSk3D`u7cn`<h>511p5L[”,y 9-P4e^>;eI@`_e+-ALvUY₆qL? E5ei/¢qYwUV}Fra5buq:\Iwd{C q{Y0,F [WxBD7>QWЭQ/) 6$!ZHL#:e%QqNrOzaճ !N$]-ѽ,)}7XO~f_.-`z7iVEA=U+BIeBsC]rP@_a0.:^#N|), | %%؋8L|UY@XaX`Sg>%!/i(͝Se¹P[.-R! MIu.Ԝ!z4\XBX!9xXjk'xFhF9yTFq 9:>rDL / uu͏tjs- <jJci#T Ó#7af8&!b\bJ ˈ4Tc26"$ |2ӌc!ࢮgww!#(h:(Q@VSqX>N(+DIolR36|.br\UeW ӏiDx }{z'/jk,6\]wϝl=ߜEKY}LF}}0p[~?ʍXF'6 AcɍW0+ 3r nINLJy47zqPG3%+rؽСQ_2RvPٓQ9;B/Kʹ8gV|qMh8х-[n–UgP<%`9S>ǖ-ȡ2:2fm,AU{ck_Q[z–UkTlD"mHL8H u'V. !uHJZq+5GKuY02:[|E`=pabزW72I=4"%,DI$)Gz2(YDщQ92WY;pzڤ)h$@ Ҩ&/V5 A੤Y(sjL*]e-k\T/ZM"d\[4'Qk+*%Z 5 x2W*Y` PAđ' Ʊv.e%]Uґ]t421P AVsT?9Z&GE:JW?źQJA9 C2a/B~-pZ.uL鎔J*A"HCݧnR~)@Μi XuE$q]n| c#PH!en"EƲg` mNg xW;poh[vAre}H!H&6H^fl%:A-״<%jcI ,6>!bȐGQjOahCق{zd89bn9I̡L88}-ٱ;7OKgͣ.Js>}NCh)ziQ gɊ3_Ͷ9J< BL$=W+w;#CˑL 5SC{Ra/ C~a,xS'jCHzrIBdeuC&.~:dU͈ub6Ea L2 ޺YxSJAAq:餔uŰ/S3 *z{ۏ_cPz N/=Gl6gT$FBcC,|AZeg9TI1EcTd?zfg(ԲUk81ِU3z'\|.O3̸ egb0B0i W@-Y&Sur$;b-,"b᫺eOͅ20իUwݕ<( K}]Db] m=.`v%15dҌF!ut>(vΊ-w^RdW'+KoOv^7Ҍ%+WDD9FiAj(P2IY!<)!Zg~uf˿ǜUN)rS ⯍Ao6ҫ 2?}2rH@ 4 5=Eixtm %hVjuxS_&,Y;u0}ph>!p.Z P⒳X1$U0x= D9^IINXj0W"X)d5fɈo?&i$u=LZV1XOin9F,/ţq09.[[=H6%U(b7oIԲ+|f(R;yWPH{ nmCK.qbADn8B3@_౏_ ;cQ&ى-#|Nz㈸.9_ $i䉲Wx@tB$1wt4bzl]X(0PኘKpqn騶Gq+ȼ@F @(+PϷ&6G_Xs114Pzjmh8fIn' CB߾|nFom9lauZ0 jPK!ei#IE@uBVOICaTƋo=% 6A ٔ/;e˥Ou=u٭yZD ^кoe9J%?V{ʋenNN}eMmyXHiB5cvH#lR )uk㐶qjY}7( C {Zw@߰<:[׮tD,`LP2px cNOw/ûr9Nc_D8: яVwwl7Ε@xD6x(j ~Dȑwcos8n'}^houD;9~>!,Gww,/ PO^5,kA0=OFjO͎~lmGM:7>K6?| 90 <|."W1刬HMm^e\=z ^@8?v?tP4 Tyɬ(ɫ`]RuSc%sN^>$vϋ]7 Ie>eTgEyN# Ӥ@w̱eȳNg[R ue`y?0/dxe[%> V֯?o4ѪJ#NyszU[63O%|e|4侌k%uy zZT o[lNpwU_h:(E4$xll :]gJHUfݾuvgT^z>Srr|CHkt_hCʨ"weyHWU1JѡĆ_Ӧ-CrʳjX?\~i䁠aٞ%gtfhjסb>Uf` Xwſc쌫,@x)?9^,< ka4k.q2*%It=N,s/:Ͳ1%l}U\H#L.bruR"fVQ)3q H.0&(QwfJ<8lffuA Kt CSq>zj~݈xA[lL2w/8Uq0)V,Hɞ`! sMߤ$,\YRZ܍@,Jz&a!mdJkơ_C#.7yKsn J{6\ؤ+cɋo |@C݄EzsYHP59A߭v#4+[^%=XS1ҡS;m8-DKgdMklTF57o>/kmPLJ.zԨ+; -٪:>VŶ?)6sN`(d9CuUOQiGtK9|ц)iqv ^q@hZE{W9ܼA%V6y]8%4(\$DB<, n8@)ҒS. 0F`w uT]B|-pl8T&[0XvXL0(B 8#e:[*}:4"&nb60gmXmJ8_9)k[R+C|?Y:&HXG{Ϟ06k"R.Bh@xWZ³plߞVpBO &ނ\H|/o]M _oU_^Xhnd8IZ&udRHcb*&a+Nt`ɀcUUӄq`s$z^S6{Mmo$=eCEIKԸ'Ya+-C6r>Sf rphFZ& @Z x/D+E%Ɖa#2{pI[LwO+5uwRQ1g`. Om>|&e!WLU:x4x6x<+][ ],c(UT*7;ja.06Du4^tE@}:~d]}y@wem-o1&=K .uK I?@\Ar!`YsL>x{>)Mkʫ[w[9ލO:./l' {sDA;PSSCp6p>!h{K (n|U~ /ss d'zP\bsmAtѣѡGXU0㹻7XoxU;b u]4v!z'3G/0A p(YaqF.#!3HN}zMVY eo]PpQ.OՐ+낪ܻfN-J)A H֧anLct<%MBj=Y$6hNQi h.*]NO`^v . p!tf+OHfE@JMRL6q@k=&ȮY_#s38I6"{&2|X2AZSzvo:nT:qдWKG ȈsٷW#ib [dnMu/*YfAޭǬR[}[e=DDI#6bx.*߀ɛ _YԳDoiXa]w΀N[ -]qr-Q'-qxMW4U2BV ~ P :+wi-7 y] C"4 # P[;QrDn?ԜƳ0KGh8$ rXMh0c(8P6Ֆ]i>DR/JR LdD]hD,1q C`􈜬 7^ch &]`i\:͜-ۈqW̲[Ⱄ:N&Vu+EXvZ!?NbIAeUZ-[H l"Ej%]XB+86NuGdǽ7H*9tT*Nsad$.>*U׼3D6z(%qQ|N\ˢs-W SdD?ڿq?X5HgTG A`"Dl3a;&>#9:K3FFu*oͨ ݊g|>ڹ&F4E[PߋILBFs9%$F}(ʎvoAGKH*V]o]*I],'80fn1̩Y^wg.[w oUUWEPoTAY )XTh&f<q6 gBmbQ\dZ-%:zT4Υ=kÒ3d:=Tp||NS]uK͊y8 .J[H{o^F0#jSߚ km]q ۫ӍDYaWf'ttZ )]7`oHOF#,m8@i*Nc_ޮQ سOC i͡P"a+9eo`Ug4[:5.oo'!+@萝\HX_]) $ubC|& q> aºXXiFEŽkjVAQ7{P내^$'۾*Xя=sPW9Ư@-<]8p2@e- 4턴mZ=x.*K@VߎWe)BjCsnj]Zrئ2Y '<%% [ ҖLJOPW#y4xrفP(b ^J( G(|b Uʫ@V D \0)Q6M*|zK9U+XƨuxjA[Tk'8td+MC˵ݢO>O4y-nn))<+ ֪5# E:=nn[VL08sJ+ة@y7tҵV('DكAt[߰q[pc6>hv( ]eH?==2􂘸v^r $,v +F!UH-־yA&P_NqSm.׸P/f)I9=2#>73 0r6BI(p8Q/Oj0E\lo){h}ϢEQ)NG {\GM/*w(KjA˥3cm8mLU,+JzT̬U HKpKSKEb$k_~½wДjlW:&}H&edTؕoFڶX8xP5axiwcd͍Y`c.鸃Č]AMeӌ|+rc4vA˵]Ur|'kܫ|:Nψcܨ㽞ڟQrӉk^:pr3]ꋃ>gu\b!_@Chw;UO_?d1ǩRJgnGYy^9+ uI =Ig` L_-p~sW(@k쯚1AShL ou> [nvm#I(|GgJCRmɮZmMْG{|> h%z]Q2%RۚDYrMGr㻚љFriKuEG#1ܽpԧOI`EjA'H7,IޞAy`(5rF>٤(gPAVfe^" qb[/uT2o9pS `&DŽߞ/ug'k'L=XP:r*_}O 7V~7=L#wSwS: ME7Jnm+ސ4ju?5#sa=t"B01c&? nTnT'ZY m>Ė{{ξkVI5˰3-o$T<>>+ȳYS c/.) |b7P(uNh֝I[ RVL^'bDnniN--+5,Ɇ]u~ s5}שI~*w x_y: jfɉoJ`2!+Փ%qVpD.lw})zfbο]na\elx8î%Xsƹu$%SҐ!)ѵ>~J/y|絝~*I{MФY Q^GmymF CF_~:[[~lt'tbнs5'?l[P2^ڍ2}'@Mm\IjYRZ.{9+dV5\AU❛B|1T򹪢k@qrU]:u):9i3{{V'% ?m-D=\aкK%:*ƷZjdj2>^$#/X:ج+dBR[2]k dp zLB |UHaKiT42JeXB-\f±u$<-MU/M/WUHqݞUṫLόȪ|D:/Y@@!7q *^9iU=rcj6n"7r%‹[*#_=1bӼ+K? 5W~VM~KcgL9l,si #c37ā dyDI3Z? nS<[R*Qԅ1Iri0n|Y@> HXK=@O4I`dnc }U!se*\Q { NzCa2À8Xy3/ghˆe,9CT7Jd՝9L#H14YPՃɺx_7-Թ~zܮ#L޸ah97$7pm]'zTG 0I]c3&x:[#r8H\ʢHk85TjVcL>U^"I$lx!37䂔bԃsçbWp"Z9DjbXꝉvB龒N;eI9VuuIuWbSSnvo*i)e0zϪϽhy{^Di_WsfJKuzQ(27[D&h3&Z@gVdtDTRZY!^aIkw:C +Imos1[8ˤ}-XЏǙ6.|ꓦ;Y @$ш{Yz͟MhaT$xghĞ5 rEz-"QgBiV3Xh/j *۝-X(anBCPSZXŁtE'yJdiw8F?.Gr.A4je+vm&R6&GOZDPl( G q=nn G ݳ\i+a;!RNDYZ 9s}. u=c7wF,B)Z~HĖL٨fk re%`M5M#׳j XoE.$~?ymz+n >/QFO8R3 (y'G7>d&i-%7K"(yX%֍ =twa|8f0GH]/Y6ri&mh&r&=.00nK\FuMbYߛs#lX̕r7r:j`Y){0`Q2#*zVAdի~w&f5c DX\/"FYG}yLؠOШˬZ?-)sx~otf8P'6w]6HELoΏ|-Y.nƱ#|2;=JSoɁ6֢^$X4$4"Q)UD?iu:~ҥϩ#Kap _ԉ{XI]PK2m%"DS| jM";x壹3%ݗU 5EYB@"zI41ӌDE;YeH,Q\xV[N.I<;FfMj?s}Hl,\5&5e`2>@AvOT2`灸.YZ85\ '3,lv2#CekT./ruxP֪3=/YhԸ*t'BL2KUհA5腼d/DpĞtWW߸‡9BIVz6+?gFܳutcVtaW6@SHܬyLE gݟ*ZuW]6L!>MgsqUs ,KNNـ kvsFNq.phBDCfe:GMx#!{׽e9< ᜝@3vrgщ!,BXT^I/p.(|&2u05?%v 9Cwy3ێi{_Փ Ox'4ÁJɭ._!OX"m@bL6V-=y_5dq/sg16_I=?mFCztߴBݭM7??ԁh){Տ ߫DPn2w!7utD4bsm?95"IWsBf.6R1^c:‡;wѰďj͹F4d&QՇ(`c5ib[’s( ev[g4AǓI/uv6Έho($;JIGÃxbFλ.ߓˆᖴC +pF P|>Š4n:[@יlZIwN(Mj9eΔY#@$o &>2~ٙSŗ)H9VT|'اUs +ab3Zx( 6_2l,_&K@3u"s=~$7قQZy;y(1by(!4['Wg@:k ^SO pKyz0rEAץ}C$n`X0OI^ @~rܖ[ѵ~: gb=Q'iGLZg'odfM 0{dLI[շcg)T6G0Ev8$䨚oIM?-M K`I<1=S9YHIab9@ GP"a)fF6iضv`]bz}.pP. xS2 قneڍUv=K+i_DSĀx9z~x>N̒Ȁ# Ǩsf[>9۲}<`\Bw.-Hy|:`?_Tqge#ʖgU vDkz`aEJnE7uW7܃:T+s+Ol+ 7>,WCx0\Nay׹> ˕=Vެ׫rXY(Q<+`X'x2+0 7; /c/Uy*z+On6a*ƫ\٤z>{ ôJaTI&]47(p%儋pIq kܜD[cϱB.VxZO Vce _?lQ/4n^&P֨#0 KCЮ`"AQҢG9!F_iH.s,V L*PUW6<xtMJ7@PCԽa]Ny흔\at^r $Iً ]╛!Mk#U/0N; q@2n8>;z-QS+S c96 2wMc S`̉ĸ b})OkT+H$U%r3OUȮ1|. Q_0hs[6|gHb%ƚK'[,qLLGx#Y<=]P^Bnvޫ_]~%l7rm>$(JRۃY\wPPfŽ=yOrwwcdF6"O= 0!$RkK_Utʅs-+uKEED5&VqJj I؏z)g 2`UD3Dܦtʔ?&XܖrS_;ArH@F81rèx{}?z:A3@٪Z5t%8៱0vL5{x^Fי|h-Eⷀx"1oFڣ{:>H !+s:AكFoJyb}Wu z[ng2 zְڡ-IKK 7UY.R5}v:LJ xI2*fg|dInjTnr it򊖟HW+$<Ҧ/P1KMpFN ^lUB0}p o%!Ѯ[ڶqeUXͺ*v.rW=c?tͼBa3!Oy&Pan6Y0.Iy~O_җ{ WVFU&7Evxљb Gr {ȶ{dh֞/YxXX:ri^={{(wi|&σT惧@#o}?DWHZ̓-=RtPSlZ tn7A@i7חH-K!l_hfXO˜VM9s({gO ߓq,(^+(_@#s[lIC+^Z <0-wFM:{g3 k9bRJqVMJX(%W4= Hҡ`nm`-{ΠM^,m3Pu^Kƀ{'QeS(s89mWaDJ"1?I&%Ph+=jKuti~:A#@v+r" ,LšG{al=AUA4>/ɏ K]Q:zc$z.XJewG!t_qDB^R"YUu<0qț9F6K0`M~uU3n95pဏ?Bjv\7(& gU 0a7q̩Q?o4YNSYFaT@\W`BZgOfN<7ƥD-ksػt~<%y z5Iy+Uobk~U9UUqL?ݎTuؕfvB Dgfyٰg/ElU%;u$ʇx!zN9"X5 ]weE|]w(0TO|R0D `"*lҒ@3T=ATmCL<)_hJ9jXd 0J.}Y۞hc.D#1H + {X?l#*mڣIk?Eϡp-/̀ 80[?K&I@@HdZC @* k*碅 ƚقZdmvk)@ȰOMZǦڢ`PH>q>JkI .1d8§}h6;;OKᡚQF\}ʫjp4ɔ`+u V(o\}r &IiXY 4q4bq9:j>SQV|(LAPi:k-]ONYfIm-z D pA>q2ⓔr ~} )/Jw0`d3=3J^:!21a"Xn&*3($_F3"4gʥK% HҲ*Gj :¼м6lKTlK G>nV3$dȯJ-:c %ɋgh՗< %ġ )'L酙77W-,d:5i0Qm#$)(?g!F :F G n`BtlZPIPu5-. U#_%.i/劵 7n&^0iM^4,*q?SPĵ.6Q_^咓( 96!uT@{5zQKTZT1S"/;F*yDumG'J"*-M?l%aO@rairwa:}K<$m\A2TVZ~=zo{JD0*жzU]FFI6S NSu.)@;~2>Tu+ŋ^ {k3,4#a4"۫ʼnVVwk\9Һ&,"鮈_~u 飂L^pxC&kl`h6xԛhpY]@^ i&U*&/q0 &`(?@eTDs+Kaܝ_f#X&L8HJD%P90m{A:Jdۻ!XDzh,XRf=LV.>2EV-F<ݥ%WgX}<b Rs^d H~^Y_k[kN d.SI: cV[+:ctG6 NFW5,z!>1ƥx;x;oWvTbFc:&"7'Iiʞ4n?m0N_^d(F%#"LZ%a4L/$d긞9f.Oeb-t:3p/i,@c}C3y!r(.e#\ #?pc (XzTyuO|Pr'˙0?y5X{D]ˆ _~O ^ۚK6g"0ql-J@@ `+„U3ӟ?"|lp: F~zDE1eY=H3mTOEaȆTgBMwn?Jdw*g6EVUUV 3ﮝnBj\۳qwYEFpoIyʍ,*W b:j9OT Ơr+iװXp/]2X.EQ\#$ pɽNA1)l"ٖ,I~? 9- N(G }ݐ LEl]){kYU珜^?RݨJDR&O T9rFrT(VrPJ$h4J@%~YdYg@gD4FX J::[KZ` R7K|6O Jq;\I,$LF7u]P!Qy+n4+TX!(/H}`(}.\!&^45]t %/P,Z% }^7c]BP-W`MRp :,(Gc lL/*܁ g!˕dXgw30lBzB8 d!scXtAi|j̴(?_`}FQ<6dST3mDY NJd1Vb3K4(|ۭ>Tܢo44"FhH¸Y39rÊ*=7dA&&.b]:rm*IX67O' sEa_KUŸqW uGKFX6at]9fXwRS]g 0~qU5;!,dG4^>!X R|{~Ծh?04.gٔvg2HRy4%Lf}Y%gQ= F:Dew lZϟ.77hj"?v0 pw#%Ok72= s$=dǫg3e7-˦\py=l"ra`e;1&݇@`ʑ2>lfqbe]EU%D|%7G %}ի޴6l~;rD%f 7?;_<=|t8tPotw<{w9)S hNpHr>zwxrt{Q'X9;|̏#G彸#QK=FAsdh@ܼj7$_P )2x'lR!8brfrk8K<^3rt}%g l QI*GӏQNt8wD>2s|?^<"q!)tCK݅0J 1() :g8EKREߔ3{t>sO1nZǣ&QAe^T} \ { gm})t?VfJna^KWYܑ ֜ܟ_Ev9;̕NݛפXkwjY( 0IDŽKcvIKo^<`5UMD쮔0Lredl\HtcCѝc&@| }y<}dP ToU,[V]*ѳu nYi%r'v& !NjNc݃Ѝ|Ӭpi/(.'w`0#>x53$4g*VgS*{}rzcuDwi0qdٽ " &xVr?>R ͳ?mOQJ}pEwl5-6SľxDc6u%w/h$oEnyDq .LSL3,^M'&7JtY2C@)㤚"lPQX2Uu1^wԹ)5:"8xi* XRzt?4[p TѰI#`$'=':pr Ң`h0~.ՊG\Rpz.Z1Pj^\gCy@((h$9:sU)2'KRpzyXYE# K*ٹUZN|Rڥ"{>@;V8 Kj]R@. KV6p]ʹcT 8t/%eJfA^KoN\{TV 8Q+/jMK8c?I˜q%G1+%U[H?UD+XMUà/'ygPf D/V,\IX ,L*FWcu7̕r@!"7}eGI#R0F3atPhl TRPp5J2O''׿Jm[࡛ҶGM G]MK<+0c%Z[[; fV:8xؽFs:>LoBaA{kh?[z@K{xII&oj,&iڏv[7AX<. j,zm@r;Um@m<&;[YX}1AׇHq4/7؝'>=(]n$PT)+76ph8#Lm-dz&iD6I|3ykTϸFȘl da4ǯ^&ۻSs{C6~]gftxL }s%[4=_ErfNţ3l:bjݿdP^gb{\{·~yRuF\A=X1Z?Kn>DQJr6_)"d@7%"/7ãZaEHg)i{ƾ#'_EQɖf?uJ%o'1=3Dt`'T(Uek%V %&%u zìiRޕ NF6l..vz#\h&ġU(5X28*hZ1%̦ &E,`'/na0c0A-Ebn&:c( rH% _\YCF|@.I N0č1 Hڳ@+?<[}/ CG7/Hp%= 5؊) F\AgX%(lreS1,)ǽDs:8k R4\מXu-0&Q0Id'|ĊS T1(n:J1:Dl4 Ӄ a)Hb'3$T?ӄҶCF'1q(fx>/Rg,;'8g41REHWc6sdr/C0'!!_A+”R` J%]9֋#MYVGr:}s[ZZZ,-:2F J{F-0^6^hϟi6J=}[:ZfZC/h)dEyh=Kʮԃ.`R`8n$ޭcc)$ͳd;4jԮG  F@{)`~LB(K-Kw339L0sU&FOoU:Z.)IυmrE(GzpƼ@>UR;?oiҭW k&ݭ󧥉E72v kݷn]HN%{"NC ˲zG% M8@#Qb=5.Msfߎ>ON7TOMIyp4rɈKzTRx&&Ƣ=TYŌ/eby7n:.O\V?:F1 Iw1{ٝ)WxA^ŁhR3UT՛{|tKGၑ1FuNlB=IZl|@lFW1b({P[QVJ8sx8N v+pR2 h$uy_vUçr3heH7KޓwՂzO!|ګ'{2EeH:u(@ʢ׭y8p$bEmaGi57JS?^gU|@6 G||B_ 5d<5 j1<]48J`/2e8uBs+@Q2Nk׹&I9MQ%TEz`Fn擲r.)34fBIyJ Z܄j1%֩6NFp,qA U"\KK2K-u6K+Ku֟ Y6P徴7juwc黝5H~~yh`?NN >K(I47;/)rCେRCjz}M=Q1CpЈj 1a_' 9tT`kux%X_6\p,s#G^`~թb&0|T9N~C)TJɃtZ|Q*kRuSPJOGdBqsgUHgZ%0` j@R}ZqrZ]TA`\ b4qj+1tsg(,t(F$b?jUZ$W;d -9.~,y`AZbkmJɹ̿좿Jx)p3ojSs>dR?*: Ĺ+R/ipGM$!u H>HS?skS$}uߵéjI~YG"W3JyI1+^a(g6JZeSc-{^AI:fhB!Ww͈.Ë4rTrp_2^ tPsS# \9:*F¨0ʝju6 =Qj[Fܦz^ iqBTS-o;" 1ʆノBU1w cWV_ \ߍjTdj6{A[JablK,Sbe|>b H֑Gͱۧ&d%BޅVܪ} 8|Zg1Oi][g R> MT5.Yq$a#D$#uUIˉ!ESA|lT,&D"cDqK-tֲns@d H#_ȶ"B{Qw2plɝodK^!c83c̈8bTEpHy^0,TϐTPn/Qx{+ˠӈSmf9J1BS_~ʲ{^dcs;F̫j%cdsc)bGsL-d88|tXEUb@X 2 Y`2* +]qz^Ԕڇ] '1ъQ*{ yФ7=yW{-F>hwu KFx@gd¯4 F)c"P*40dEhR  "rћAR~{b\՚+L%SaZs1jIίeW; \,lZӳ ,Dugͫi_a@+Oa0G3swFXݿ,:e!hWjm ["M.ěB &ؠ ü]rxF:L=M@G(NWo>5vQ*Z)ArC-V{nH@*6}efp12OS|=n4*2R|8̉B[o ^f9Ê$ =& KnQ@y41G+WoZξW)}$ː r5H\k(In>ϻ-A?Je-:F D}"}~Vԅk无4* EdQUג9>d8-s[a.ݦ4@f+K^8p:BUFNUv/A$5C|%h~"[,4 yp{DE΍GNk,؄[2R\aBq/lg`Hu6BJ$c0 fr@, 2 %P)#& H q1̭6wdʢĕߗΆIdOrALR= 2W;D囸w[e)7rﴞ%+{4GUƜpv<(rmZJP. XN;@q}<<;:.SǺj \-2Y@_ sZC@$ u/<%,}Zc՗y *q})(VS&y*JJiD^H&ػJz(tS9" l)cF뇰r00iJU G'Y!՝m4—WVǶ\xX+SI%hu_M_ u - ^)0pJaA̢~X<1QSE]= +9 "L#Bڦ3. lf`)ރFlGm%RSoA6|v.vZm bp46\ 16d膡GJ yΎA23ejV׀O'L5XM)QS0vL0J-6,H0]"Ɔh"L׻DtS Enj`c>??;ذ*ƅ؆/`m>&e;xu%3%͞ Ёn7[h7c~JW F`UnYRam,ΫTVN6&AcK[^䇲![†KO&-xr6MGqF 3k`!XeeddS=X?<̲6<*N|fػfȸ0햔-bU׉Oil$WןIԥ8>5A])AOtp&{rVqf9U2hl'~V~S^O` 0qa ZHN~;ǀg0Z>z\e 贳a!#GI(ї !*~y9yЈ/ujph!gBɁ xܠyw?' 䛏ZJN[|'?r嘶8BzW.+oC_r[*,+=6Wޜ/k{_D+ TI<KcKnu`UCP T]ē}@7%S4F2_Vx{$ [8#!(. au@PL%Zy(UO0Lq'9 el "ĹcGpFEitzŢ̔ZAHnLwsFQL2׼l$ɀ\OV O2ZH>1 j 9\x)uYJE =Ŀ/GVIJse^9S·}b-?")ֽ pv +]-!X{P%Ld.>2*gP.pZZ/O d[:YpFg kFP29fL`z6Yf*).{^ֶ$TBڃXIm~U}/oqϴ:UX}&w+b*06vٓ4mޜ{]J㿗\!Y v];y K[~:ˇ\{1BXMi4R=1ߋ@^eWy(G+^d[}ڽޑ ֊{ h,h<WGmJtlA|:<5EùYGUs'7TͧXԉ{(>;Ab5n#OgX궋UOR|nID%i1?XiŰXR,ݧKW!?SRu{ҭ]<ȳrj.^.!Ї}ASshYvQB8ZWFT30="zj|@e@ kP=#?脋(yvy1{hegb ҝqA' *oR([woYezh]s|P`i kg_1v]>BBR47]g].d;r[(? <և\//_/ӗf> &psQ`YSMj _&/ջX}kkY+\0ݠRe>JwJh@Ì3¥Fwf!]k^d}ʒy;h[z6UeHm0$|ꄹ~ ym {(\12iK],ElIzX7o6+eMUdOyRN򞩌Q,ԞAp&&؅m4w@r<s(<0"vld2cAș`~j~zVT)+q@Rі_r{4Yv ԫƖ4m Ly(|cŽ\vywF laXd(~Qb%iynށ$J֦L^֏ k( Pin7}' %ZuGpK'[~8UǧN _~GvfXq>71,JyQTqۏƩFK#DQ[T^ؗ"gMcym-v_=DKw(S3my :.GwY+%K\䣄' C?V7\UYs!<|[CIrkZsm{_Yx`c @@|0&|!:%S|l qHȮ!'c*/(4ev0Ry h*nҍn6̺aɍf]y*)?_I?.ax3S9CyiePA qhн⺱=%hwSmm !h)P8NI$5pr1eNR wE =`HG~rj`lp^+>LZ@#41!J>oD TZA4nl|C=8ZH .h..l;dMR#IXOLR0Զe&/VFWk< O'V]3DB-' q8uGa>Y^x #.' FAX$$%`45^]ǫ&A~]ĭ,x60,«a{8bS8#>X0ɬU,a`-5隠 qD\ε,t.!b?ԁ璀): |ɆuF#{Ϡ{vҍ; DZ;vO1d)~4?q6ZƤbKl#rJlChDFe4dR#vrF8۟M ШmHUv|+9"ɝ{[($l,SǓ$7Aqͤ ӜN3uL𳷊b4 w1sK3VRV]3chKYXHt($& o w:-Z*k ]Tk5KhOAHeUE8t"tֲxFk?=\|zP0۰ J!Xpq_ gKbY_->~Ꭰ+3*%O!DOanF;=ȰwS߰!rv*g9aFvt)eFdCW~7vIͱ5mM1k78 nŻ~re^!&#ĹC蜨dS Z{W{qdZcֳ1,>}:.GmXGbܳ,6S+7"5c?䇅7 6 &Cuh9tK>bȣy@qD1<=+ۘڦ{y ]>i7TNlO=D[ Xze&\l J-d/>/D9)yg7HcGk0s' L=<iגre2gnYE; m5HU^pdBSR^/ d`$ZI(Fx]$lֵkZE+Q$.&i= 8uy% Td Abm4 }G"x(r\MEJ#/EV?a.&\إу ]љ插ie {m5hj)2W^z^^_ʙa"&tC&0*UW6Gj9tǜ̑-ElR@3UVc,8<-⣙:T;ᔚlh.JRcֶ$Pfb8WC :Qx`):caO)C} >ךqF !:/\JːTK_tNnʑd'f69 M2 #h0"'<'tv `2kMg.]%e #LjycJZm4暧5du 7rȳր yRX1^FD0B Ahp XjXɍ-~.`(K\2rJGt;['*1m /-]ϻi/@ؗ)J+< DFZ%ɞ?i{Id$.r ^kJh?) ~šH&vNdބp TAyrZ {MӼ #(8); Sd~`oiWѭSBPطDA uɂá@H%LPb۝{ se$rb-Exb:^S n'8On2|CNG2JeI 8'[؋в'dOI.I2;BY+1Çs{z=E@z!{:#z 5V{P:= 62#uGD^xk-m$LjtRUx \\EORNˬQ9](ku LI$dd2!;~%F6@KUJ)y& %hx>Y [^Qe.[eVD, |U}LEb6|osg}P(y Ӿb'^YaTn%v^8 wUgԢPE=_67!" U!'f=oگL" p#+`s6 f!M]g+6Xt F/P"w k̿+lW˷ 1Ô[2ǦڗMz8PBl[ .Ur?nL9 /9} _ҖU4+\3)/P>c!mu{/N;UhiM=aд/,4){p],+ ~ǵSй;Q. >aQ¿oFQBb(k?]=. %NAmǎ>ƛh} b鏶y[]\$(Pxa$E@P#օ$ڢ>> 5rSdr@hXݱvRetV J b4| }J@{<\dl>gy=  @Gb(ù%yG9R+--={akm%M0U7l|do.iCe#9|ut ?& U8Kw}"}kn#'gꗕDp厱/_@p+mpqٲ=S !ܥZ7,~ }:DyB-: mFӣ< <OIdDN8y;`e28ӓÍ-oQx`ڋxhUq FL"$AJQHk ?Ӛ F_Aپ |ۨo%Qy/Ęv GU^K.1Gȶ7jG#JK1{D{.34}j{4p赽%ԯvbP;= >xp>9H W> ̿= ! = أrp#n" -@t(E4HQof/An0]/Fw$}4 w ;Gp0_'[t(7I~=`ԣrj҆ʸm|T1g ;q Sk ZT0F 3ɽ_XY,g dD/̑t%l| wFQÎ>ָ 3&A4G E"7v/U 7T 8'].Gm";_egK ]X5Àӎ|Z$ \mBsACUmt1{l<56P%;lj@#Cw0%=Gy@e>~op4^ ~ _מ<z?1;9DO ^QG(@ZCЇְἙ6 _&Z ~p~p~;x]p3 ϿFS.ovb^ccY8ȯa310_<@b{ص_,A12su+rw^v͗:! ev̓i:=?b'jF]8 tԛXJ0OlѡF}b uP V9!DԈH92w:p F`*lmm$AI/v -B 홒b B(VcePX>ĵUvEEKq zP: Ff}eAA H-Surc&!@bC}CIΣIszŧ唀yPiS+,s9(1X54Y4|Lͨ*{ކˆW*~ @%I$fd+)zQ& MV`=l '՞ 5.RRTL,j=qVˆe&f~Q^$ ^ Kb 6^QSa79?lZ=mL n 8.еJʇ6ݧϥ [TԖ[hsbACX' 6yj! z21W|D~ - h0+[n/&8IBb' :tìܤ+b 6YR#ώl,nZRy:bTx:%oJ֜# g ;9;{NbS[fEhƭ\W^f~< )ah.@T{&cQiA݈p ,ܱJۣp~EWu9콰"Pbk .xlFnzWy'1v0ݎnhbb;gz ^'G& ?^g8~;̐6r/2eLm p  'r8I5~׉ HLl8U,%I d4H(6FeeD)/a !>X*YcApS)]L@?p)=*B}-U(H/; wk ~ ^ ;]Ojn)&=U2m6a t b~xf U-SzX8F $C&T0y~} IJqHŋ7t@U"4R«-{|,o|X@@F9BJ$vN#KR2^:d^2+Jzbԅ䐢8:j p $H X -FcB&WH G [B١ym@xaH'j1e~:$ +/13K'V1Usk!BV"n6J8O^?9;>8ÿ8hi6g"F`L,rCt ~|1Yٸ*O$$O)=Nf1)✛U?`.HQ +p3bhp >psk#naS_[% h^1ߧ-}oG{@3gR2uWF18d@5+(=`kGbJ^L*NwSFZvoGOup[I236tqKo'Xڿ^pK6zҊP Rv>?P( ռlw|%T]H%N*DZ qݞ\0rɁ =Y [Ɉ;tJ5۳x`ʆCw.i}g}_BȎړyevMb1F (j 0iν/+?5ZoJنDY[jcPUG e1x :z!hv7ʌx2FvWvV+spzZma^V{rNy#v͠rq}Zn+sw%7Dߛ/h}vMF:Zc7I\ԢAؽ^"ū?V>hw;H7e\̴R4my WM)m$ąwXӣ9}/^r'Ʀ;`)eu8[K^6xwk7a2a/ :lc XbӞNF~˵zQd=筋fhr/J]=(, lt7UuPR^DaktviXdvE"t:$NxK#fqlE )WccGT;;|<#VS'2+^kQ[ʍh0fn2m0nIklOy=}l0c@L$I&H9'p_ጱ1=7Ŕ`:ǧJ( 1>-ons{aafލm+"CϦnxݙ99%H.Zn" t i /'Jz" 9Uj]/d `􈰈3zOS#< 4gt2B P$p noݫx&#[]KR \=/_1W*}ϑGu-hיJŶkATˢ}nE #74'>,KّV57lgrJgf%qs4x>,.qH1gض+36Y=0$Q'CN sA, /}7t3 7Q R\TA}VsUqG ϊ|6_,ŶvA Kdiudue<{Pxk+WP?5I"0w:m?\XaBopǹ-懣yk Eɓ%+k,xrMYtB(I.CrNHU>,u^,f?D"9&bF kv!k;o瑗=,Y5|wy ˴%R jI}B \?QM"E`֖ wX|tS'u}5iؾ܅rE3ֶy+Gz~\GISH"}0wVX'a_ ,rNR2pJGMݧ[3ƥg9/(M9˰n[[G~UnYƇs9vmn#Ƥ'g'D h/'2xoc|Ƶ}=rˍ|rfۡ=lw\ûMf<=,!ޤwLҢܥ^fVr;ysC@cRЧīIArM8dneY j;9%vͭe1PM\K]pE, ЭHv.cILiڥFVJrTq\G   BGѸCh0Wa:$q0;YIv1X]?À8'Gڱw3 ˢH/7 jZ, /ԥq_8mt0_XmZ>'Y>7nPEۏ3o2vC-G?{އ{=6/vLn%n f0/1`/W1Nwv@V7n"bW]N:W?]a+nM( N&ԗz⎦0s> ?#vgEvVnգN Gީu:7 ZT"q`iE "wY<[aƺ +éNZyo.BҧD(2C^*Q=zTtzwTOBG^O[=]91 Vy9pqNޞνE.`Rxg?Gz6_#ܼEV'lmFm{Qgc `[.?smثޔv'+)p8s/jm~/[ǺQemK(I|++'4 F_mq,n9Υf/mFH4;VC;\z/)M[82wS! @ˈ7`.XE7W:f-`G/禯` qz)l>FrcbE ߅)1P8ešÑk M|X9\-$7)./pw Go\8H@& Hm`k5LGA9gO߭~lo?3gklz?X>P,#?=/>&sg[TT;[;2ƆKFqOF rN:kl5j " (-|QfD$eR?N S?:D'Y4(k=#ɇ~ށۧ'דw8sqc@٠?O>||q>?ۯOޟ\ yߜ\w: :gO/;@z}?i~9;t>7Ë9CgcQC-Bo?}׾l簨Χ8s Ӡz =GËS|8o#oߟ=>=<3zԑwN}hLE -9 CWmhD?@l'd៑0MM,Y&_ Cn/ЍAsz9]Pc8_nZ'=+Rë5<**jLjkW~w:n灒M'א[krM 94|d8ms V'1'%8yC!ܱU;Ma8PB7Oe/ k, T?ueA~^S޼Ys5`40d߿rzX`vp/&ZAa?֜d2SgB꧔"W<.v 0&!*1ywpZ%)iKЕ`ʶGOa_FEX23c@?iCּa޾B/NL $|♦2kǸ t˟׼07D1T?{F\C*WJw^1@ɣ=~SE4p ߅w~'ʻd~XZkt!?mpVz^ŗn-^ർTYs|J({E=Z΂eU%L)F`sT{4f]ΥKꭹH,q-B|{0f4W9Kgo@?t{Ctd`sd Σ k@R^[  J|θ+}\cYn y6Yf z8QzїWř:F8t##%Jʜ Laq" p2[SUN1!SU Hxi-JyLL(]g;ؾArs6 @kztth^x=WrT\tmfOԨD鰑f8}mzE:p-E -A!x]JM[YZ:a8%̪WK+aK/#xՅTуHXS rnbu"7\~y3Pz爵YW7lSmմZdJ{],zPòQ0w:%jSЯ|Ze kRks (s#Ekm<`ڨl'9O?E.uP%&RȌ4i3; ڗcvC[7 .E6Kב1A]÷pܛ=qlGL|]$МwT!دDxTn(+Xɾ7cӒ%c/e3+MLI& D*Zd=h9}@h'.f?chcu&{d1 RJ~Wg 4x (:eA94^WVA1dJ%*UrMnal_̾5LZK6̽D5'\@M/v6!&>s8|^ >1? 蟁>3],E_5$Fl9~"ŧ._eggb#K/Q֙{I{ 8$CrS>UpفbMu H OrOۆކxK4r1Kw!4:ؘ@݈Kk-y4B$?ÊZpCE@nTT@K=o[CTaef!!r&W W3bS+OY5dG>TnZq Br՗d9$x;V$/Գ!TmSM%B+FɲE]B˜>$HY/A.%fTF gloŭ_Xeqz7kp|L`hPdQ? r|6ڱ yzݔ>Òeר&Y!eD|YdK\)HH$[&֑,n[_",K3*8z[,bmBϚ!cKu{)Tm:N ;IE%"J! m eUy 𕛧P"… 0<󓺆2;?k0n`DaTo(mY v)ct9-4s& cPCIkrjFcZ^5N ˭ÝmE&SK5$ೋ%^n$ 9׏M2ӚqIY$ٵ}=tc.N 1`\94` -&pq& d>L9`hІ X8 f i*tA&>^r @ϒ`]s( |+^sS,GΦB}&lc<ߏ|LX(JǪ#4[ ߨI];YGbSe8{O(hFvi~Αarc 3冱,b$0g#L #1|u:=뀪]x}_| %?^LowI1шY'!KnTg!玨g EdƷ ek5 n`)b&ȗU 58Jdn5gc7E?8FNs&^0@$g5u|h 5c% .zP>%"yTZh+3;Kf3#x -YIjlk* -UKq֫3NÐYF3]>󽼯X* O`I >MZv>`!a2"e a 5DG8Ţm{&QTF#\TA&[ADīZI4n`/G8l[ǂ&-zY6ev6X_̰K"7ԖTdBrpq#T6?UZ+)Aܽ6i$o%jK̍7CƘ-׆~=5Z^v`= 9'9`FI4>p^#%[`E{Җ;NBO/[k4Sf$E?މA# 5uCr+6MBu5!#Z2ܐ+N*g sRC1y1鲘n#%a)I3,9wD;4t7zѬB JPrT#ɺYy VY&Ԋ1;m% WM'cgX/@϶_Grȸ}ohlGCdSO2 !SDyCONnRi`I!PEUrcգ(Ơ4Ȇ.L!ZK?7(K ?};3;qD͛h.pZ =tӕBBڸtwY(F=5i3s|n'{X~ Y珡&mKgR؀d+dMMGr̆Hs&QX1fVoL %VFN\O[2&ϓ.H.7B$=\SfT+<h'1G`?r>f}D䶆y1f-獞fJ9ruBk?jS+n1C0muVNYq5+{~n^IVQzcuͳ7:vXr;eOpSpS{na\EkTDAU&`&D#K$ 6i[&Qj-iݝYF㗘7"3'<%2lJN J3(v[I8w1!x(cD`KNjԐ.+QbjK71 >iڐLEKO<|8p{tc^)q*tQrqm]$wVޒi6i+]R5y s43[lzZ%g3&%&iOz$*t1{e(U1f$R,= 2Ɲ `@=#NNq.""h@ CS<@ݪLz 􆰋='-[_M"6g"xl0 (I ϐM2#:A"e,WSfPCCBŕ|h0I k0lal(-aLOݻdzI<,BEҳϊI/jCq )I"f=1*UTԧze~a3"c2i:vȷTG* ,łl12H+n~8+̹W5rį Y~=36{!"gKĠna}?"efܯM{L =Bv|P gxɚT)@𐹁Ũ}Eqh (8TWVJku5[ 3gX" F*ˆr+.ltmx05 U\ً\zgPђ2\LJ2"{[][#+ U7I>zMDKg(IHHvk7 SLJ5':=Yq k`ԜSe|\{ޗ<ߊWJrezYC}T`.\s)S17B~`p~7IuUq1OKI#h, V\lW(̥Zd6US~!+SʍhƫƷ8N[#WX/N|(;GTV'3>X,NyRdiAd\g*D<&};Ͱ<Ldua-xӿ'HK,(>ZepG9$1Jk yhSFn'&~ђ ]`^ZLUXHJ. YNUytmj: "&ēm !s!SO9ea>?0t_Dq'$>'~HOڄ!f5Q06.YhP2XчcIb)+zC`!%R̬\J@2X`."f[Q?Yށ{wwogo?/G;gP +w447FP2;{N]?{?ˁ/gtS2tU;9V_ ,7kspC]=z? f[{>rkGɀ7[c>BKߪ*\FR3Ue0z);|k] }jX ں-g}S&HOrN{G $^NीjS4 5":ah-D+KSSWl*?d*?YJ2ˆKP]n6Xϔ_,#A6qY1_*AVf]bצ_oԋ@,ځ~S̖%*$2 S81F MW9_MJp`;U5FxW 3Un~S*)2ڤXwh$uQǬ(|Z#Z?^gl촶Z[;{/￿!c`_9Y&-0 ܞnajQ4OK:g{`܂k;|M|cwM0$!@kEQPo`<$Jl`Ͽo4FTkM8b^ʻ3 |"q,YІ-dtt51˒rkۓz(LD:qY$ȟ,Fu"ב7p'AZvxpj&뻐fBᎈ/ތHO`<۲v=1Fѽˆt5@ c3>{/K>z+=ڹajư1b?~) $9d_32zJVD救6Uб>Ehoҝ\3RRV- KR3mgهExILT >$- ێ?vY־7C2k]I+D.~Z-7q{a*_D(,?q43i<dW/o}/T-|+}Y xsɜ Psfg69|]\/c>ںION~O3ϧ)b;E̝"voJJNJ|nYHg֨qGWf+;jp | Eݬ;K&R{hhVhDzx NC: 4ݗ_M_|r>`V^DӠ3 Ҏe0,2I*IóbѼ 8.$g`Cg3ct7#.ٗO&&u\Ê8*s#j3]z=ǟzw67J1\!{sH:sm@~YGQ[DlPO,2*﮶iQ"]DnԘ TϿcϝ „c @쪪A+% " Uw^sAMZ׿i {=O UmMPygz.f4_aZjF:/lYY^۫[/Upl<6 HHLUB댘5y9fӱ%>-ہg1Gf8>G7|)-k;av+`ѹB:u"C42[Lz\= `Ҳ^z;4i؎eKs@*DurŇra_O ,2m +99,5OJlZx)R n:䁨|kꢹ hk̿y6f=@zZn*2{V.UL_ʲn6TZr!1V5¦TًB"baQʤ2ƾw15hRƩpǘIlik5=75(RU5W?+]O$IK/[`m ,[ ęKdcY\39%zՂ3?" ;þ2Gr{.PʀT0Ar2ұ\a=߬A7H2$oP%2|VFX7T[ X/) N_|1TEnYt!ihYJ-23~I2et_8ҋd*M#H;Wtʱ|AUİ]ŕaOz՚)8݌ Nx&3„h#ikۖͅlyw ;^Ibƺ& -p"M[(rI 5Z (Kx̤le:#va~e$VD<-o/nyWc~uD}ER ֒c)` )G )i>d-jZnO bS0tk_nuFs^bjg-6o9/!hhs @ȏzy9B6VcKi8\7g-?:3)G FՕi'#Ziu"t ēQ~˶ b_QO:-[l(>jhڥ|2U?g"t\5hՏvY)>G[q*c$̾Pf%Z~}V{} |YxM킺oyь;s4>uf1.?#W -OV#"*eH'X y|Wh|V_/Gv bnvU]\e}~܂TB9ߪf}ʗX}HW=80/4agU1UFnc ĐJ%۔UǏRy21l)FgO%PF2PEW3x"2Ù>+i[p=%;|U"4qodW?qsuY^VJ} >w';қO}X|fq% [;Sy$ߋTR:.3bJ( ԉANK[ة6;+;Ro< ͟;=Wyo(pnpK{_M/y_PGQI+J{bGU,à%A앥i"ifFQ,UQfX+m6':JENḠչY@OnEb ]X7XJ|}RgPS\D:QNh9iI$?vW}h0QezW[耻TM8- J5E]|P9S/y\,TV"ZVv1D]Xnhh?\.K%VU.2܂u !DŽKb'κ$migؘfW|:זhVZOwg4(8 S 8Joxe1֡/yZnظc9Mi6xCS-jSi[Dޜ8!3qf[,'Z3# ,hcU4HB(F"~GSb8Vyo "+whwӮ8j&T¥EɖT*!aI_c5Heʹ{&YZmbgPO*Bz+2?QKc!F }Z[b 9؆KF],b}-Vi%Zʖ0&V x#xI8ZLH|^5\q4ehh"u$iI<34k:o^0 zt٬۸o+ uTWfORu/,þ?%\)-?3M%8bnl΂2UHUKᮓ8B$ʹyR}wfLt `N)jnOn>OJD`9}NSb1h`j]\+< FXZJ hveR_6HjTKCsc:ÖjIlFg;ҹHIC맳3Sp1 ܸOлR~|q[P-oZsWF0+qdZa&Cv^>_#OnZ9 WE\Vz)3_7Jn>E}^g6IrNpM1l1 StBI΋I{Y ËoqpnY[f2BsUp9+Rkʚ5uKlc@RKp .A*CN /9/]C7j-ձ'פ,6pUIqU^CA_C 6Y2bft=!O_1ąJLF=l8IĤ)HRsϐ0aXL\RW\}e 8>~vKXHPl<:X"k11O7R5߬~ 8hwxR#8F~"G9SJ]ŤĤۙa$>W YTpM M3Ud+\էYiZfR4 E(XG7 U0NΰA'$d>8NtX)lxdڃ ^Zmkwe; o;>p~qҒ>Bƒú.^.ޠXVV ]. mzio6%6Z_݀lizBw1ګͤd.PNyg7@ Ұry\fŴu*IX*ͽrc)&ھJjRػkN|;`KJ.J!r^M4- [c-4ݢElfU_R'1.~g*93$w"ZFB/-*V!Mt R*:LVEDx]~IFsĔE>[{+_oPKR5szK<#ΚIgiȱt#pJ?\*[2&t˝c\Ve;P֎`a0Za)IcY^6E6Qznp^+N#]YubhQ""!Y1KYUܨ"eSGU)\II5H"mneUH bD ep F]1Ď.U]ek*.7H4ˑ !kBfֽQ,먔ot#@x(?HKlǤѲ4-Z.So$+?)M?QMJ%Y8KTց oilB$} ʬK:#V#,&hh4PC.%|9E]`of/60=! /KYؤ4+CevX0? `.VKԑnҗL9Q cT&Oe;(չզ4[qua1V{Vͻ0U-afϙ4ܭ^sZ29MnWS.QJM= q~c549tv/ϻ1J!>]DH0IꥋP,C,m3 kkYM"V߀?u/}`$N)yW~Er߰(bQDdQI},pڟ6qJ>Rw6W.`R;l2nw^/x_r~rz8׽N& Y䜡{5" ytp~:s֜d?WQo +{/aXь$pȷVءWc 9?4~ը;ƨX;.>e&'*WGN+k`NuKν$=~0!^04^ջ|W5pe/j-{W)zrGdQ"Gf?mh3Onckkޞ>vOAzlm?}%o#; f|Orl4h<n8;[[{͝A>P Pɨ%5ZIpmt-dk$?b$~ ʍ Y{ EPIhOqp4` ڝ:^:'FWK:=OLU_Ǟ-pc+.;7Ϗ'GGZ9#9o|8x}zqrq~=x#m9g0& zz[z'01;şp8qӂ13ǧN >vޟ_?vޜ r:OEpó~q1!՟k_t`sXT Y@9im|v1`n/NNi⼍@}Gw腋sxSGi8{81acND瀈m_C +'?8,? AF^:47yi7/coMu )]J/R Z'Ӄ&i) qs21|GQ5yti%C,zݢ??豘Sv0I|ഭcNmVvqv[8EiA ac>-iuyɵGũ%M E%f.z=S <~^nƙ|y_y!{okk$0\Oz6^AWm[jUsY|JQUʹkOgZ$ESv* AƦ{1)PD5}u50p+Jl+eMеM/\Ho,:fݗd>.hgDRQnZZs(`Y>cg5Y{u}S.w:X:ٴx ~ԳD$Oct5 Z'bRuNV|Թxګt8I-}|t}m~%xrlNUKeˇ|`ٲ}4fT=Vcc~7sIVҼMTvWԘ`)v1pMW8 7S8lq%{u+^?ۇreqd\ZJe;;&sGtY{FEe'ERArɄ Q"mQP>3u Mz:o6ӦQ?j{񷥝wTiźwnY|3bDZN*1yÙPD`M/qigD%Fyџ#V!2z`e0u ic!ʝO˛lYxjMb]5K,?U gX|[勇<O&}8t\zO[dZq1 ~pCP8QX>K]S[1BY\.&_z 98RI/#]2m<'Q1O%?ن5&㮈BXfzs`"Pe IG|XлOnC{%%{6*2$vޖf[ ;ϞO>^=s:LڔTY||X[@Gї8qx (||xy؞Y ܃MZyy@-N0B#~A5CM۠!|Va37*7@jI!%Ɍ<'#>VZ.RW?c' ?_T\ݗ+rN1L{1F:N3A$}aC`^-z_'!LQ)%ܬr2B.7Ζ`6.E'g}˶(k=k Wy$>SU w熟% sΙ|>FQUVB$jV,(SR֜W-նZYN6PkqF(H3~MOTflkp6j=×|F!~ca.ŻjȊrys>nCd^,,Ts ?{':ba]O#"I&nbekc7)I)L0pCVl;.RlzfEYR{L=N/Y uaY(7.0XL>{WP18qzS*4Qײh+i/#TY0vwU^`Gv(Gj#\Ն2Ú  F_mU'J_C3'%<>2hϪ3/=a { KPiʝThE4I!Yk Arb7bIX#U&,Xy3n\\&^vNG;S(y葉$5M"xq׋4Qٮ؞MW/hm]/R2xTH+ҥK` c.S[!5@IGEO9k/(- RӀ\ʢ~gr$+#mP ^Xj4cd*{4=n7Yc=@QIRDŐʗ:ShC%##nm=ᜟwN6Œhf\j.'YkqjU= wb rZ:g.[uƻE Üd!MR_M\R]rf2AP 4&}hnШ4ibQ#F&idw?N#+-E^Ls${u#FeKQEa3(lp…⑔}E! QE T/}gho'<@0@ˑJ#'D/!W?0&ŪSmE?|ڛEu5Ԩs* ]0-y̪bn*b,`+W5>H^\xdрE㠋sFERG `|i(@1u A#\)vO}|ɘݟbIJ>pވ:Ŷ%̙,{tүlɧmU*F(⻚+=_'U"/Fg%-ZQt|hU$Ԑ\S"0Z%]\ud8IuF/vau |Bp;8. j4K}1$hh<e* `'XsZ о]:Ɵ@5P\.Nuy-)fq汘ZX:pcy}VfU;k&YJ?5OMVwjAm*iQav}K$X=.hdaq,^B| s hc8!{^$V1C^,)6n1(&oD٤QM@} WRlwYCDGxZjHSo4DY%OP&_114{UO F%_f/wRB[Y 9H;*Ɠe̿:bQm&JZz'~ׇ@nSU ¹FK)ߓd"&6%f15=[2pFn'\RωubDBߥAMPEE]|& 52Pd=QYW0O\3C8u=Y&b_55z<m)LZ|6}wJLՑprL%j:XCTYd@[o}d@P`5RX ?ȞQsԮ7=%8 d32:'# ,Ayɖ`iHyVY2D^/z%>BzWz#9eB|{/{SNFc<9-|\dz'3/.FdF0 ?f"!.*JY?!D]/2dJ}]?獌ͮ Ui+i"d^! 6f/º̓H:%zX;S΁ݱ!ɩ<.SP`]݈7)^!3$GY4j3jv'BjFA@~A7 ":`m5[j1$-5֖jA("u߾݋4,pCVd]暴f> Y~fA,r (֔\a"JFbׄ3Q Y&-da"`A망==Ct29]F4d-5n5靅nW'gMUr!O[heH,姹+re-A1{fJu B0~ X|@2`7 ωohi$l8Ÿ̳h ơUe0_xkxYR{;EXQS7%p}\pr(nS@z4èKذݽ&^FxY}]n+.J|nBj4S 8؞-F d*vYϏLଲ=H,vTN/Â%O9&JR-V|+ G$N"p" D*'^,!>")3̯RtʩcP",^3~LXfc ީES|q{K޺Z%ORO$o,?PBZǐsTIw0=8[QcZm, h>f5, 5IB? Z&kJsHQ )*jP!YT GLV%˫:Pd{ PT&kW2ux(r=/@U*=FCP<`s4BmOA%MT"2Q\uSPAGSN`Cc̬ܳ+Ic%BKmg/k^z. 2a6rq9t[k6O7'Aɋjb̸w**9@O1u^U[*>Cu'Ek hdm9$9в|f.e%?QFP{?K'p:=ëL)}o{uhx$a- NDwZZ߭͝ږQ');鏓eD*Qn^VWIHln$jKxf-Tq~Y[bw 0^c`ljR1ؾj-ۉKlj1MCdz 3{ yD0?[iIi!Fŧ[/ uPMLzuE9]CTȀOalK"kTlo1V.s2Gӏ.|rPAUU &%Z1~q~ v[º;(sr{(${Cz4_f 2jE 4Ee6P1Έ!>>#~ӮW̚UYFfu:Z ½ a'YO6ᴟ$KO}v?-xO>C<1Q:q=6&"YJ~cfAǹ6$-ȉ,P?.P圤ZnOT&B{R֖M@(ŒÀގ h,G$ 46\s  LE.dYFBu'sWH d005w~ pɽ;t87FaeʸU@PZC:ڔ'6gQcUK}Qݬ,29>p#NVqI Ⱦ*_+F~ڸYj<۱偮^wMmˆ!Tc`ڀpLV 7_ph& Zc"ύL9HB!-@V.{+>VfŀU(=ۛgNp)ljl73 p}h6;5bj*@&Δp\ _fKxЃ=6vɈ p1=vrpµȱv<:"f;\8&hk^ I_I,s1ggRG}<>9-2s.܀81pHh H>VT%Ln{ovTjXEk%YfS)2=h#!nMI3E}r51Ha'~6՛)U\o(oR53f7{}iM]|Nfoܘ\tq~^s%wV7  jJn&Y4 I|P/̌; ܠ~814QX췸q %7FRuH6-+o+GፉRSL3*"\$Й&MRG:E-3N:yT6yf)2[ b8hО |0aeF|"Uv Yç!M7mɿ@d5d2X/KK*e7 { t KYEt<:͇f0D${ [ +;g}ʟagZ+#!hSH0BXYT~)u} ٶ\꽌4p#erN9!&tŲ RGFYfA#,,b%(A=Q]uQТyLtq|H2)A %p,="O\ɑ Ɛ֧}e40y ^#hbCa}„# (~ V%O\0ʟjڂۊdH@jמO M:ڋ>k=w>B(c Cbq<*MJfKPzjQEС15_yMF*OgԝaWQk۬ny_C݌!Asm&ٰqX`jl%}†>(X0tPzփ| ́a$Q[ :SQ/}QT' x\"B~jpZ"LofQF#%/ŀa[_F턣Ldʆz$!\2Ac]?1Cb19y!E/\ oG(2E[8 !zԜ8ճp8 n|)C"-hHRK& cJOEo#?;M<4S@,pw̆Ս^wNR[P-?s o6A BFV&h'LU3m*l }kO ]aD<}p xi{9Ud:P/s#)|̂V4~ou0]Q܍1>:h+0XD/:(W؋.Qov%~(TzRO N%ѻ9.^y]=j8l*A0z>U;a0/VJ4.ѼxFwr7Z!iQ͚ 520ʠCjiUL``!,(%p+2O`/(/z]fNqpGkX ʷe!.9` ftA}V& LX2_`لKs(%eD P[2FlQ57ںqْ* J|/ K H3qxN֓l8Ѡ̞{)3ZVTIŋ843#@Sdo [l/W_Ttm <IXRNVʠH4@ *V,sg+OAIa&!?P(w0( M hxs_Q~\Zh/,9`;(ytuw !_ԛL OK2ɯl$u=ib(Bc_wt8T>rpV %!c\L)ӸсP02am,dwsN{3=[,'^?%+>'F:T̢CDD3$0u|GYN2YZKk ouYYdH'up5\&sI)O`, g\T VZ.";laP|p\[ ȽƎm)4J\z5.)Vy&2a 3<冴]%S _49ވ'm|/a$'횅(͑  Ա8zԆ:B9cz 膂^0 b<k* ѓp%Fχxu|5PФĔڤML&&I/%hwl5̾,z+ٙR@@˅?99T̞$#8~=;4, ")O퐥''tJ$Od_Z:BBBQݙ[~# |`#ڊ B¸,%FY^ju'z256P6= [cD]EӏtƜ:^lQƕ`8RxK#jpB7`PdBCkq0j7ͳ_)P!xiR~]6H2ݦƅqJNםWWjֻ%Pƽs1-~\?yiau=O\] >BjUʗu]+p0:^ Ũ3|Z+{rzoFxάh )ɾObaX\1uP.\ޘ5s=-l?>_ͫeZ0穳y֪'vsO y]tK[=KVo⹞McmE>TXj,0ܨv_D6ר{{NOUϪ:t*o=g󋋧UMQ~ktGmM՜zoYIFC: ·3Nnzsz{U]g% v]XZs._L9|Տ?3=~~>YŸQhr?]؝%RZ"M[} ׫OnJss_D}||\43u|=w]:J~rƃ߹.BkԞ.:{bX,ҍ;uktz5|ݥg9K7.NkS9wtaH= UoV8<@98Ͼx7gSg0?|$L5~W7 %N!шDro5wpDGE6̫6h?6DP olJD.pQ.~LDe1*SKCcdnJI.@?|F&.Ǻ.a+^مk5M_kPkC 1ԇgZQScupP [E1ְ*&YO5:< OR7,"c*%"/{gO>a4Zܖ0 @zq R#6?d=pߙ"Y3:yOx}9 d+".q@XF;$aT 6Sꃧ:`u }K+Qkaѵds`:Ac2e x&=A!.lC¦e`OAV>_  7v7|Ylc[Ƀ7Xeڙ)⚨ @pr`#q p4(t\!EfG[zm'8^7j^RPF%mcJLqvS̮63W|ٿ9k禛ɭVQI|vۿUߞl3{+_@+}RBReNy-V<IHBJ]Q= 88ɕtDgg=~S3tQz<+}Z|<}]\ǟt?F?~rOūyx7M?|St0IO^?1Ҁ:]fHTa ?bсx #P0 czgr4ɲw*MDXrpɍEW$1#L >Wg1a;'7gG6(aPEZf]A2xu  ߻8,(@$dz?|GJj" k(AB;4ZbC ?XqwzU=~9 Q4+~T'Oǹ$')J|Sv9(ޘBԉF4z&I)øT̘浛ES𑰲h݆I!gHRj ;j\r HF)bG## (/|ǘqBE;fBEQ§JןzDp62ppeF#$!D'{En@,*l rӀ#_Y;\D66$p4]QdhQ@\PH6=Qy }<جBRehl4Fݲ 2u1QfGSߣJr9(g{:@k|eQMҞvlARe֟4H!I7*duog6&ON~~ϟ߼>Dm?;XXLhNv|>[Wr KE*}$o7 ?U}ڬ9$+uyT)It'=\AɅ S9Sc@_FI7&07vwњZ3˺LB-'dBof 3{GYVQ)8fi jrРkj&i5Χ;38 0\XJ`bW5+>,˂~jrN5xJQˋh:&%wb)Њ\2̕ąHꝓmJ&56W&[G3K?k`SD&ZXP 劜>$&.#`8jB>Vn_I qx^+y9ZkN40,ԶCΥ'c|Vbp'AA_ft6Gc kk޾i2\SU^o]|ڵ ʃ ZL X)ιg!I1Qt%ԫˣEpHQF:?.POṔ+n@Df<yЄHEcER#tk|oQ[6">{c4qomWxY; =J;TaɡHN̊%]#x>a叆K[dz3jIJp Ӆą KjJK%(n*L0}`rtc8;$:b2[Rq:)"1S1UBL,#S_J14s&.9TСTV5 "VlK$#߶ZR0 \ ^. !`wpe'iͱ⸥+x66=Bq3UXMiPJ:QM㯑Z;ed0ʝ5!m<gX$L u)V$~]߰xZv9BLk )[~2t,; 6[v>BLlt3gFOiIꀕn&Y.hćq@\R'M7%Ӟn4|"NYh/tP碓ABY1̲҇Gp[rm XT eԶHEh@ /c%V Dc$g=L(%yc%a\^,\Ml}-LeaSP8w|53b jfd:zٖUuVʴ5`vh?"BP #n&}79TdS'B{}{TF@9tavݦ7h:cx` -[*?7sB7퟊<䆐vvkVN zfή[Sl˘8x''ڽ:|A.P(tY4!]>Yh s?/{ Rb- #l,'E֬2]b//4Sѹ/kUtM T oxOsUp; })+N|) >k%3ܒAc=֔]{PCxZn/G+MM)>hjrvLDEPxfČt Zgö9zYݩxN%5혨:U,T\Gu8tOqӆ9_en8}Vh!n5!WVm5--UQSf1MBRw chDZ*'ha]jgbܷ=7gu75CN͐ c?8d ֞$dlX~ }Tr>-[unCXr5=j߂H0^Նs2!cĈFm oYt4 H&H<mŢM'C!SS yDVSa"ҥ4ޫ # kkq5OD/ ayR{|32:T 5|(8JR1%uK}` roh_1MZ,]<+XzSa(Řyg8p6UCUt05T%br4sYQNjeؙjbH̹kuo2kk mjX3AD &+DZ Ar1W?OVĎ5F΃_c~E nej0]>1B ‘2QN O`(Z@]hwauO?/ƍ-|iI6=(j4%!m 7hD6$4:s"/l }N:< _{^* wDPӐꁫp \"yXzٝZ (0  kPuRu4}'= Z?’ŏCҎ={]"q5q:x Xm`O0L3 >3zB ԑ' JG mFu"ja戴Hk$4®-ϰX80p}f"4GZW i1}+ O-$'Q=rIቊ˙Q xi5c$OCJ+Ev+(֢⻭/E:zy]绻www7IOivlG}^\}qW  !pm?} jR;LJi g+[4s A{ ]Z>5W;2m-pib}p%6,lCǷy# h vt H FF-Ï/ڷ$}4˧4uCYZ9cQD<,sy uTU/STL3#ġ-B<e'佰@ )Í wVQUUߏ'Flhz;G:%O]FZQ~&`v;Ky+,0{5v"("Ek IQy*hc bӁRWnhJr4 ^q0O+mG&,[XdJvS0޻tS=Y'iyDŽ!-8btE8wMÜn)I6װ6OMҊ'p~*sy#^gLf}+kK4rc7rК~v߇[j|־ӧk&#SGƁh|K LvxL6;-}y $Vlf|!\ 0Qe\ hD3 }!B<ՍXf>RD1bP; ,pX-_F 4; C[o2kCd*,#%XJ~ CZGHuYW$o ½3Pܒ9`:v/3!5I^^EX.o{3e Vp q?Ȥ_Ү]1lk)sGLT.n (y.6 LA/[{}[vKuS2%V!1 oAq&,M&w"H&[)qىSY:7A*<$='5 h$={i`W[tJm!nB?ut*Gd0[b0*ԳY !&:Jow,C`)>K?y1dƀ9tE 0 B/z`:I픃[)fǢZڮ*Vv'6,p ჌SV`%вn1MD=+'Kٙpj{+x[/Ӳ98t+#2!qQX/ZOU|<."Am Lb("6uw-%sh-o$t'f,)9^g'r"E՚UAq&Eucުhz>VA\ mvݠ]x YF|lY=fJ:;}e } m[|JY3|* \Jv1Wm]Fϥ/jǍ kgVqVBy (ۜ&|eV@5H4_&wt||F< QO|j )0ӤWƀgрH$/s 7={vx+,{;tDi8' A1czG24iv|ö4d\[%:Ex iMf!M{G'-hO/[֩u]ENJ,t\Pت r[KHjMbo#I ^"=9xVHIS6JQB`;I<Ŋua8g6bz"[ ]]xfa-Ҽ=(a@7\B{]/u`pge\oWbb΂1=+Ach.@< *|BV޺򭞍EnVXB+ DһK8JŒ1"&ޟ*d@u_>}o>fǭOg}Fh IUwDbhl eSsҋ3LP t8xARBL^yww2ҳM|"hv=ea}æ0k:dn륧`oKc)y͎$\U`a.q&$G]OpͩuOo>{;`/d\T P (xRs7ͪw" &cT49tViSfDmHRjХ|4NU*)vv B.4{᥃*G:IN{՛xB*IvӜs7j6!? L(10a8pB_-'9L6} ('c`rGONp!Wq5Acf5Ѹ Z%p!u-gi 0cO9:^\L0SxpY2-6u,ܠH3&RG"vApQ~)äTTR?&2C~kLlF*Q#`V (A{~di- rdNY{1b]}ЈES0 qn3xA e۽]_4$TMOJ<4I'>E.G>cĐОd0.Q S c'QbVȇ:Gu&ZYE?yX誧x3#4}Aqhyк,\b<ѫDy arTeƖ&esϙR4|:dBBt)ʎIٿMz * ;KAԤ% M.RWh*n5ѻ%*مꭵ7jR`>?=XS~yϟ=!_c8= Ț@0bkh>WVsFCi!M۟k<2CKcd$[w?0X5b>& ]m;"'$3Ie+9R2fsn?\󝃐*5jN<1y1fÎ(ՆٲD4S#Fy㜴^(zeL< l"5tyjtjvPZSvpr̥na,ȥt"AF7:/ {!&BE{%-P6jF#xf[?ql"GG %AI7Yı`نUY4sr8{NˀXg #:|?]|l[ln}d^), iS q8.)Χ!z#|#W ,7|hpA#xHiiju u)oCNI'9&b珤]X쨞E+a_#]:uad3ާw]ZA%Hn8䗏`Iq: nyWcoo(>=~B8 /p8'Xh8?{k_0o=` IGP@0$*siœfϧ=r4_mxcEdZOQ6\b 6z}}5GPŨa7ʹ2Phpe%T,R7PFqDi<%bvfg3^UH#Qf ] <9~xMگwgσwx釋7.~-}~Gh2~xg~zw[ ||ޝ]~ߞ]|xs~>|G;;ݛŸOo^h?yuÆ<7#Oߟ#՟G3Lw8?}sz6A2$xKRI΍%FL7b{\KҤF .tTt*܄S5LABcFBT,G[ڝi dO:Բhv6Oa59Ÿ́%]*HĢl]XQyD83S [vy$/a%v(+` TlY;r]:  9&:gMsP@V&Auȗ"w.X: _7,w1c@Jtʝi헦L+ܣ]^fg!EfAuP_|3O[3#Eۧ.FVle;69G-m &I\Vj@f:N\'Sn&":$_@6R1DcFpH|ŕJ9x i{6Oճ22=+t-8eqm\A VYA KZ l-XVg%y܎?wW"ji`/wyӧGGޓ6}u.Ɵ]:WIT ތ3x5It>~T?\Ͼ}+7 rt/~'[|x#_z|c8hX6@* =~><{G8)iI~2,\/?d! w\SJ- |!\jtQ?7y4Ym(1+3V8뢍'O[ `Tg_=Xϗyl1??m^?ʠ@XyPO) lVpk^ONF7I줝0~-[:,_ː6Is'GpN[}PCs'O[7Xj4=J_iǞ0KXRrgkXgZ[k\k,}3II+m4;'ϸL[ds#j>S:FfYu_M'ϞvpM{D -`lo`mHPB0WχlVr2[x%W;HIh]ZUE ` ۦ)\oz,+Z((R׵UOl|9; adPBV圑\\~%ڦ YٌЖha]?y# jr ^_|m2'Gytgi6-9[7|>xS9zNkb\d'g T$4txVom3^gWHˍ~st WaK{nN⎎Y*q~9K1x,`]jowmR6w1xJOltKBSh9(D{D: <9|"0=#,EE.^ʨWc(wꥹ?pʳ4ӨL9@5 o_h.JaYʒ]SF q"L@ >$;F}Cba$&8\nc4޿E2n#px.L 4o! I4QJe%Fh>N]'[6G(W֥^&K?yR,nUːoO[NsIuF<Âm-xMpLòJ T<`AϪ<L}~sPnxB2N8PAJTmlNwuET4[ s8aB:Zdbc&~u|3 r G9͞/~_aD_n~wYpO}wu~M;l ;jmeFw,*Vc񌃯ng"ѿ_Q}?>A*sʤ\GhCⳊW)CD=TO==|ɓV=vUl݃k.tiX:љ$B.otcT%I7yѽaᡍ|spk1QW[{E6l#m~27fBfݛa6aw`N]FԝHX _Yr j\Rg;E|yޱ 4EGE=rԌwZN&rNv=?^U31͢5PV>dZ\A'|p/f]Hͫ)^;= cȟ=T_*{Tw*)x{NB۷^6" xQ!jz-^Uúw'QrU\wi&O2׿zfZ{İ 4:pϝnӡe4ɽ8*+jڨӌ;\L_PTQ"K: g>Q钤7`gniT<`h:LRxhNiB?)t6[K@c# Ώ|`/C Е(Vݺ;݅3 W}v*:$?{MBihJz+Pf؅:ՃAW;,8 (U-a;ԝ?(\id$ ɡ}O9%Z/+H܊="[XKXhIb"YA.$ݡq!tt2lqޯ HPhO[<Jam0k#OxxU?rR7qTˑ8OMnrL+e0c+dWʡOxDU+}M9L('\7تGVӮ: 7Im]e` $@Ť#)>T5ojO!G o.)dF N;lid`Ӗr]7KWSP74%ؼ" dXnUhn*K\*Ww[(d3ﭤAFȑ0\˱jKbK|@U&KKS*J=vϿIbUb|#5AGqQ>d/cQ%R uB[ţi]Ϥ W%{8iT% ;tv1]8k~Ѻ,Ch +:JFD)\#52̰?%Mx.Tℵd^DHE;u]ٔ!TyE/-hpI3\HD$<$\ 6_O${Us݅ЉOLhOW\*gt-u:PEJ헣j8/…wM"?"~!2yx\*Dn|.z*ұ3TY_ܑ XpıVh FSth!A@90^wFM {x ^7$D,& $e(Vv;nFc SoI5C3*U`hWwtwW7Y_9W$?)$H)a9bTWt[ۡvru8,X)cTms |iG˿ޅ'g R(3RKbSW\0Uzks(4 k:1P!ŗ !!l- +?)R"*-I"LYDo uU9"Lhi];Zf)%f%i}0i=8J㶛OR ӍY{X@7 񮟈NѪ'HIgHղsk`ħDPFPT9m/J^Gea^e-JT)D!Rdq)<ɢe)hKpT 'SAȢu"K#74$ɣo8ǫEcU8]bާsvJ㴢 Ka~ےzkm&/Wɤgnm=uo_-ZagK.īIav'},G<<|Fe"ՇT޾"#B?Ag ahĶ`KahN !hQbx%t8,d6Մ@.5>ݫQ0lSY ߎ!{4\4)*J#2r9xn␝i?`B uC{bFJlx%r&owB"8RzoPIB*HA7oY㬚 ]ShFclcxMcj5&ۆ_**rFI`2vPrU- m%p-IgϹL\;ǦHzau R w )P,G{ђ$΄dk+9hdT D ʺӉOĠ[qB;Q&O*cF)C9wx/;2& ΉVdi\|$,.j2@H}.H t_.OhkWxRy݇mvn&]4I}p(.d±`^pZK]+NOg3m~hة 16c =ü5$^(NSl\,c*%BҷrAp! A_bvXD'@z[_8K a!h89? vm,7ȴ CPj/o}&M\ZsΖ#:Ya`?$]ֹvBĬSv vcB0(*@zෑvgeM,@w M_4Ljr[%_iS4 $$B:0aoJ jY5D~VHV! E_ŤePyͭ=R;ݱV,DᮁmM:rdmyh *D46RhLU].Py50Db{PdqtQ%/aK;+YЛD[lqG[ uSc^)~@ү,@, x(g Bp$1e]~7r:rOA%t2gja.G@^$\F6W9a$;2tbz+K]J~&Y= ޥz܃z4_ǰ%ΟtEr%[|T!IΆ ǪjrWʕm)ؤZ ! %Bu?zP3ОBMTE[VΉ_\:¡fq#[Ilr% )[ ;7L>O:[ TÜO[A*m y1dQy M_Ci]*PUpCaLf}hJҬŮv)J}.DJ/b}+bDZciTq<*7w"r_#]NpSyvK9utNdGUʜod5[6f5DBcL5IV$;S3 ^\+R4B 2%;EyύHEJѻa/˜ug`2ӱl* ;}p8057΢ﶾ}v`tw8._s4EjrkR> "4@ ׶F̗"]i+ S`% %Gݍ83`yjN$$1[&RC:.++ݝJHD\ ΀D6}ʒԨC dWt=By1BGMg͙RQ<~Յsψ,!&Åq WF^^Zˆ±NlFY_5%t\E, ^nThmZޖL'U0b]HmrQLZY7=씳GU[hzޚ{`&sNq<?xakt\T>&C0$rayfLx3as^;C| @8AWbE4l.+%|5ipq9a %ûօo351$H{YX@XY KL~AJoHLVS ߒ,Y.d)R2=15iq\j)%drRk2^WBqI@?oTȓ*%'fG"'ߐHO\ ! _QZ Ȃ 0<1$a&ѹk,/A( ш*K -22"9U;ṕ=X-s*N e>L xkTǞ.W iYq|ᶂo@>]s5ye(vx0Ϩza\u㰔X,7 6#]gɾ^lU:JD%U.U[/q;ku+|Ͳ\ym2F, &"ߝ޺] V y$@ 4U4ݢU?@,2\NjW}#[H'!XȍxmH`FGln Y[ ==[}Ok|= <7dxM3fP۹{tm8 }a4|Ҏw1kb^OMpPdhUR ~6Mg$uDL*v rxFEhW2c4x؈* 3'hBFR{A2K|`,xXIЂEeo,y̓/sO_IL:6ŵ%]{Kԋ Pc.)i1s Jɲl SaIX&hlX=ɄjmM8AunD <}5(IyM4cUFqԿ p@LI/}νo{Z-QV+/'Ua}UO.ӅJ9 Z@Tw`6i̝m| k"Pņ CwZGù?[$Wj۽C눈vbL ׄ̔]DV'H-a<@aZmi'ڋbkE+6pNw].Xׅ`5uTJ0괆Ah> tZK9ZyDa KÃūCeتM4xkiIAD*'5m뀹mDTSYeo[*J01xJ:*:ݑk=Bӻ΂OVl?^J`"UL3 [5G+d ~eNF!jRQ%ky)gK"Fwrf{#:QQ;FGZ/ކc<: p\" j/$.?v|h}3$";LgQҡⴤt'K/A 3W=W|غW5b1]`.ijҺ@VqOV# 42'Z@I%ˌQq|": EѸ6t٣14m4^ ONQϢ)̋ -qF^>O߅%jI)sNEJ:#sdWܾSd@H_Glô%Ee(`oFQnU\Չq-HU( 4 2setյj9@jf2 ]vFA{ݒb1 fI6|KLmNøԵh} kV[?g,E:*(m}tUzY,۠FziM:(۠q<m2puiM8I-0NZ.J*ҫ* iE8,E\^@.7v\ Uj\gU@m &bhWUsehaBld#s^zJJzL.]@>$)R^; !8zǑˏjG8r5~5)n`PB$rA*od",mDvU>) YO; lUܠB ) x?~*mG1f^^#ށRLՋf1Αfuҏ5Ü*{2^I4I5qp$2g$ۋkˑ] @/LI2MT\<&iTBm0ړ:9D #/K)6V9= D)gK].Q^9f-=s"j"/7IqwۘCQ,QL4tU Mꂂ@6>PU]SrN[SVJ1j/`A]w6LQVSbbB%hmLXuRDi*ç6 }#:Ռt(2DvJwAtÈOD3+ݧ K> Y߉P(>݆LbK2G@9p/f[/Noa`oo/|ÃakAM]ͼq2t80Ueӛ/ YGXD7IYurˆljI×)dWGG6 7%ѨQ%pj(Hw%vw , L,cK *[IS-W@/_g^ N>1%Dq1ڏU]ʥx/j>{l2^u܌n'g/NhK}T$Ωid#r24\h"XUDߪ%6oxB85,l]Q*ReDk{M8a4~)?3cN/tw" "}h!W]Q] 22dQN<@^N엠B,!%b4nTN%&sZJcT]=1Ѧij940Ag#H4X5XTr!ڄo0. :%ee3;=CFhN$ޠ: nv.^}b[/:1؆V߼ >"htSo|#v`MO/ WC2̏6"O\l4+'Ҵ.'yσaW)9pQ>{H%z|Ʒ{<,K8D@He*q*ReORנRl\Ȓ~Dԕvf&yȍv&O D\ c@D XCg)`E>o;(j׹ĹqBDnGn685J s([BZh ꤹ`<ϸ~3&E6N;y4kUxbO??E" k-MGSwxLiHG1j5C\/7nBwkQM¸P>ωc\^"6`qUwxI\3?HYRۏ߿9ƈ\;r f8ZIE๚&T\q'cPWFҌ*- \P m$88l4`p{l0dd0ѵyTR H,j9R Wr?GGO\B0#D %^խ{ J&EHXbo4\gE!5%65 l%,^yy,ȋu{pTni1ʛVd./Y޾$c8ruaP*@r-.ZG[R!OhApU2=z`؅aY4B~"6so'gٙr J'H B3dTJĐPL^G`pyX$q8 ah*]K}:{qT8Ah&@JwI_;4Y:śMlÎ> :]kw j-j|( yLa8d)l'ķf|j@҅%[AN Ŷ`L rXf22o>;;Mn9[?;kcdĕo5}%\f.6<'Aw[!Y*!J4++sX5Y\2h/("r9 LR2u4!NT8Vt(F(E7 Λu(Ob,BմP%*-:aL䵐m.#M"2T{^:>}v`oos 'ed:pe˟[o 'zYD2󧽿dh~QZ30D~/K`}xW*O_ |t&DT$)iT{MZ1:J&B); ˬ*&vbkg%b;k2'5lh1Ӷ.~ ax ZZIμdN3Y"6{NJLȐ=@&Ij"\;yfw&:? $ 6i_ ЭXj#4J$nk~3q#Ta}HI%)pl 4ba}p^as ֞+)9h.׈0R$"< 6?ngp[u}]Kb5yhZăVvkCE-,plZb2Oyժ! z! +~[)S0s= U: Nml*.Z ^KN^`__F*fp)ϾhY)km!Wnks0 ^ߛ7s[G$:~0{ LkɥopuJ)>YY% :k*~bkm& %\ZE`ETϲ SHI}mx08l72K} KRm"'dPPw/㛼Z#+|I=1?:9ʳZ'*9#a2NL']:(J6iqd |}Ma6(ֻE[|:_8{tЉ79mb7401bz\wt,v.tJvagjS,v./WIE˱ ^|WC~]<S ]B^Q5w5J??lm($csPk_|Hw{Q_( `l}vvDnz~iܭ|~~pݷ/Ň_zf|<y7![E G'ˀ&x1D1B!vz7q?O(/uN'wR^{{ԟg}.1>ɼMH3<~>`&Gݾ1sT`gnjjiS~]ch^ToA)dX"w~akfʼn OK:Ǥ`W;IToܥ$7b#J65Xw9oZggi M:P| Fc ƧÉx25h5:j [#E 6O፻([a&W}Gx7{vu/3XdġLIɱz̈́|gsfIbr/|RL7PB}x(kM6xqmuMqLHarΌ!O:^)?2j:}Ѭ#IAY6 hy&\quf0 wE\BsJx_E:K{27`j@eY}K%=#%mwV8EYb3fǨEZX6&x SR]Â0P?!\O86ȌR@ڨ,KwݞKe0爸#"Hr]l܀=PO4'czm4xxXUwKvZ,LƘRƭ IqEdQ6}A*_CqCGrÇo\5 Au?.u:1 s z#;<Cz.|fk~ Hnkn>kZ [2G $YIXbƥcK:]oB/|r .׍[*7 藡RH1heQ ƞP$]*ѫ5αF0k=P SQiY>dijy@b)pY<] "=PlF;xkd~ ֣paU,pb5.Zp )6Azϭߟ}x +pEݡ\CV(U YQU;M*?:PnR+`uFE`8IG7\-.SY XMՋWVsD݆Y䎇io_/,e@ZzN11773UȯOX=˪7nT^:iߔHR,$w4_Guq1,2cikJUc ̰'ESIӉgEhp4h\/G()ADXdh`Cl1U[GAHvbGm]mk7v+c[W])mr0*VQK̶Vx+ҊF5MB#}Qҡ Ur~V_LOO| LѶ|>mPa|'vM,'".JUENl^H&v44YM+]-5hekWҌLW3ށ\םi"fëd@ے ]QDaDPF) X8e":KZ|O3|fI͇ )o߼ҖLwUZxΓ1qtÁ3O~8 ض/8m"8IѴBfx잏 m#[b4ޭ]}0 d%HJ nE 0]uh:Esyya] Y,;e˽itT[ Y9Yt QR B#<kMxx8%8P~ajEjV]OLG,g?ȍwC}uo,xDǬERr#C8ɀ, tea%Qg0\z;H@r֌^DbJs\"|AK;@E:J=+3&l} A΃'vmOЊTK—il^Ozi8"h{KH))}mݛldN mʇ}rĮ/^1x =OFjt,zXrMl(t(a h:Bۮvx)6̔D<ˉ,s ENkp\4VGy5ĨEQUWTT"o](H"&)s(AWb?Wf 9~T12ws{4>G%5ʆ׏SG%aEH,guME3p`=$RW]9|>'޸g>43kш ŭ= j FMouNuӄ~7it8Юm#8YRҁMʳ|Hpcq:Ss$[=KNYu1S 7ZIyDTF~VH MD%G'}mTu#}h0`ߒ5oyǞsBڤRne^b=^/#]wu@}6 PvZo mֱ?ˮ[IE-H.^>!B1Ӕ*$6^%,X0 wEhDIkI"籞u<`v1qqLp砝븓h3>X^Lgo"8n*90Fb0}> 0ؗpD\ LZ˜c!u]<ĥxNlth[^}sDFh&܇lie6z%9vUa-M׀Bx˸Ӽ/ -, fK@x\`:PN1 ,Qf*o,DD!:8B:w[x Ԉ[L_k2YW,܇(7&2T]tx405S$To NI%XΉ5I~y-c0Ӈ?5 e>5*4E^EޟA_ܜ"Y*m?H8pcO'=NB橄|Z*$L ۳B*[NC$ |yWEã'p? 2҃Ѐȕi6f g%@?{f{I"gx=#y@2 ='͞Ϩ8Ka'IZ,ܠZm`jP Mɐ+$5|I% ݵ[iTR?ISbV#թt;tǞP~ M\2U Ps>=r0"bSuӎm E#0I:j*ثe Gzb`7}~t?9{vgyv9Z@.yͪ0W@2Àgd`dȒNϤ~7gF\rصn ܍[/b?ݽ?H] 'u@^޾ -.\ Jwg} \DaC!]mOX>G{ նr 键^p ( L#Yd#PRJuuo//H!q0ґ(#p¤ ۇscBTxʞ2F rc'6b6yre3nèH,K)Rx\QfG >UefYCI.qp% 6|Gy*@{$3p]/[_h݆_+,^:VR-YUU@2í:j"8Mc.,"Eh*]ljSU> >>xírZM) ^* p)#ygnS ACG{" zÏ @:;<G{^ }v N緯'ru<8/<+h_ ^<v@ Ci$۲)RC{'hʎ[B@RB">v椮Q=!-49B^xer* 2~pvuD:#P`!Ҥg0DpF9̞y{ ޖ+Mzv5/*s<,u6[6'*I"a5&Q./A˿ܥgNɴ9Ty[*SڇŭdBɝr& p ZU]wD:틒Z%HÛ_˅Kr dB'FW%P&DPT(j;TYZǹH~da1NVx3UI [AO,a\m W^`h )Xm/!&/YONo E&fjwEIy2cÕFu% OeN75{_EW 8JĪ!+_kd=F( sϼݖܖe )+IݱT4 ԶU(zFΠoCqZl_m+v?uhNChaӅOBxyEd#K5G'[ĀyaPOI] vO^'S}~d+Ӟ}wAUkuD+^1/E&@E%<߃>/?7_UB9vǓ5e-Cx|o!)#? >rwG/}7QE~qE٥ K89PHOۄƋ^6O(6nÙ$Px.A@i;6#-禢-iеNK(B Tgg˩`$\Π!EϮ}g%7叔.Bm;Īhbx vl>Td$hIZD3&Q݃RY{l97I( \"?Ng‘n'V{ 'Ȣ/nMOoԇc]`p%+WqtN$񏦄g'WS~2Xr10-y `h~CȜM_5&zn=.7LoQCbp5%ǮYt9Gg2kb09f>]LZMIK"%˂BՆY}XѸ[bRⵌ%>N姠g2/$"EBD¨BPj`x R+7: 1e[FTxF-\EuTZ=B@Ҁ3ƛîV LyʡTi ͢+|Eq4=,wRNei? 3۶U#!~yMeN+Q+dګ +fEbAYIǺwmWQI@a-®Ww?o c5wu[&Bbz#CݭnK]f Ē/=}em"k.jFǔƽ,a,)5 ǐ S>{G $wz{o}G=GT /}iN_VKt(D}$_p[8]NK w_{/O2]lb_x|_'ikGZ:'xA{$o]]c-ɲ1(0+uoSw0^7Q?e\(k@ ;ȏ$)3?EB`S/)qsz8uU?*F#VV uisNqڌIfXCiPǶ E]+5HHu8i4ǘ*Ard#LTtb4}EbljtMS5/Ixpt G>im |Rd_s4"y F(&eaGio>i@$5oL 5YKd_v\_BluC5iK_a8*A*v0w,@O-QHf3~2c%kޣ䷻]CYL$)ō2R/~0I;ϛ7;}2 e[DT {]L6UU@x0@*;ck^H:TTh!$J'hr(#ό&˔#v5q sm6׎j1zB{zPftcԀO9D5A.ByGT?#MpBpsqKs $q6^)]Pk2g䓾"."B k8G|uאZ1tIѷ~ @LDd# jLCqm #I;FY#5{;n=𢯘Kc#WRTۥGA޹.E ]*.I\sz#%\,^cҩ{Ħ(fκ:5IhbE4#GSK'מ뭦&%`Ge\/"iҲ2rkvڂ3vxTrAĸU報o?paGVw) TQxP6%yb>r:Ol6 (1.k]7eT*pHI$P*}6w✠T UoX!$ݬFS8"=C';.nG )TyJ|XYi \1 K7 Ґ.{x'|ҷZ\эbd26m//BKf=!zyw!^IkE^]y~)G 4¥ym]kxSp>^ 3t l~i` wQP:yGI:Yۊ}IK&zW\ȁ$p^[fFu U2yo0WJBm]ޣz: 8c-I,bja ow6Qņ<Bw)S'KX~<Ҵͬ-bWR@9_fu*T~QYOjy#(0OCCTfbĻЩ ` QfX򀆇%+âXgi%=hfJFs6*l9)]kxi 2{{ )?Og逃XZ@ xsW-lia؈;tn-~`yUOq3U`FH+D$ A9i4Nz$o?N6G)CZc݅t܀W R㴳1cr P/oӸ(JU%*m">ͣnr^x *L$'՝b@!5CuX0#RI|1,, |y*rBUy'Ji:߅i4^9laDD*^h'{"5i:hcvhN^k@oh2F\4$n`kCHkhfKv}[r[Ly!3%2EJךN>,.]07*F<fT tFcLK lv5(a@aӒG9*ՆYBd&Yhsϻ:Ro ~%HGhCޞĩf(1>ӛϬ +sug ?:qRwrZ+p O|, "{Zw2mZr 3ox>b ap[E(c>f&\E1aFz_܄n= Ulo1 gt<~hrQgDBx^s܋?*D gG)Ps W^PS'؍FcsE gR\Mx;dPF+dy - Lx9Jp p\Do{uu!&m)*h ZP`+-&C@Tʯ u-^&#H "p55d ކ6`.8'[xmA OBwzSU]jn)Ub.<)~ LAn]3iC؍x W) '._}M\SYP}Yb?X!`U π*@)(Q,"H_Mٖ4 >jDỳ$#h:K0':F*mZ2ԓXSA1TBKԣcZm?j\kkV'vM@ `Wװbrdy[[f8L*MkP\^"F 1="!b2w 36\d'F-LQf#p&W.7/c$INBAV_RcF&+L8df, |3U+-%I V&.)n.+,ҏotTLŋAV!5GX4om86-.^aeF(җ e|pNri2,_8/=z쯶 IF7E]dt +m*=%\5޻qu4<@<߇xg$9c  [hVBQ7}UZBoπT }.wYy)5"53ǖٞ%[?XƷ!ڢ'\z Ѱ"鍭MUfzݲ)xA9 0d6rtJ=:ヺd=x2HdʷXO1Q[2ךC^kg č,4^T_>+,-`.l0BU6NX />)¯^+O2z xs]kjw1 @t)=hltEH<3%6dcҀ=}wV _je Ҍ a6ljR|jAyǂ k&r;5K1kV(#3`J`jHx"g@yw&RUeT;Eawp:%F^=g_^b{cĒ?,ѫgq\xxV51E糾Œ"+t.7^9%)'|aͧ+f€ A^Ha/b G>Ϋ^d@mu!D= %]^F=V5U/:^gf?EjXHr"Fv,B~wH_2=QaiH5@8׿ N^ڔF\N[3TC;X*V39KR7˚i\8g<@~Lߟ>:.7Rגt_6G{wH1+\ >>?AG? 4>?A{Rí[??JsnNb ;TYTMMPϪNaWG*CdMY&xCK ,/8B7C zZV$6zoipr:9ZO]ɬej{])ɫIb;%&JTg k[߅L^GďMlM\ hD$'|m׸$ ؛O%XS?D4*t|-dXc`BUԹ. ݞcZN93!lq8?2*S6w}!U|ԏF]#=17@5! p +Wf\NxW1kV+FUXB.VU9aC1>OZAA-EeO8;{+yޭ;_ŞbLZyOt K"d v<@ɶϿp>f%A[Jfʏ K]pG{vb|KCs%(%d[FϪ'# W:q6.Ao( А9Zٔ :sq:5{Jx<M3'm!)`h0 oC*bZhkL\1^F/Tc]Tu>bwk Z b9?kYb6 |Ka|]S`i'кN+Kp|*Z3$ O;y7!O6_`KScU_CSV0 ﶢd̨~,\9; V<>xrrx|t//A3z^0+DRUޭ 2*G2:tetg@# K22îTZP Q\}M=VR8FPF!D#>,](gNS4ܸS.~mʏl4*e8o:#fTh˲5 "R&1Q&ˢed@K6BT5.J'ECY؋#7 Qsh6(頧`߬-*œ$fꈊ Iq<.JiBurkǼ_lJ;-@W'LOHNk*I+Â|Fr$PHvZ%(b\ s:,gZS u-BS +i 7( 2>&T03eJDeSytCjj 9V7-<;`<`1Mp|W!zSI 0 =/6+b:iݟp׆9Vɳd+) !u$U$n*֫zHiNYVGeڳ S gPב:f[.nNVъ-WCM Ne*D~G-' ,2UR^hZuuj[L1IUqƨXZJUTi[=}r4+(os"^/R)/+++:u!?QTF&~=(2X2LB@ BH9ko<[WFEGEO(<ک*`MӇ+F2kV)q 2DPl2b)0TX(G T7iˈ xˈ/6k_Tb TaxCW*| :\Pu\F5N|K6/ "$ \s Z׊ v 'vR+mwOØ}nKDUuSƆ6Bu r>':pd-~h u($WqҟD`o$N^Y_]>,]h'KHZ7,۝Mk_\wbsC 9k87&"M, ?t^bp#F'3ϫ }4bKnix,;z6SlAYU ( ^Hm1=8 5,Ye_o ,W2oKun/ I=j3s:x+(ѩ ݭ}M =vrTk/^F0ub.j H"_lAy:6hI{.IVt/kMW^H&~XSj>NAx-ѥ_08cpě&uMv.%+_U,i8 T!]_3wlܗ(/[ב]:H۶xLkOtƦ9^m!\f9+ \wEwqqRtIhĤ0\Ry:\e!aDQʸVˈ l9;{ƸLg$|Ҙ2LCZM]ݭ c:)V݅ ïy8VT->TYqC*B9iR9W/D|^Kѩjp)@C޻Nb2x_82q׵SiG:7w4N7{eFtC%50;XT?!0~C1l]Z{:sub]sb: Un|21}aU:*;@Sk) Dt>2g E 2},J6 z R~;?yOF(xi5Χ5FU#S!n@ P{%sLN~:6fG{ >.E,G?nk0Ry9q .Ūlom8!BCZ~gp4pBseT&}hJ^aOrIɡQ ,m{Um5+27we0?b^up^qP1;F5x28<YpxO`p88z/(E%b+GS²*uFe1c s6Gr`T8k5TZĿ=Ag~ZVK#dMI[|ѝ*[ ,ewAQT9~\-UgsZA܍` ]ou\]Ko*>:bʝV#WZ݂>&85,>[R.s溴%)ԇt8/\ŴmY^N~fSZ١*:v蠔wq1Mbᴽ(!`kʌ.N2*ORBB譼CNgW{ tfE %! _A]zS RZXS/\S䏼涖u߱Visϯᎅ#c=><{HIkh1TĥmjCsĂg*qw!hӾnĖ\n&g2F^a:U5ciQz%EW-@xCj}|V:Ec圥˶'鍪Aڐ*e*;L/ì;$nF#X  i*A.lJN&Oȓ_[M/j0\$!,I3-/4bM^+rH^^֛_umr#Nr EK[ h:~s%HzsuU[y ӸN| WIltS+H m\n/WS9-9Q>IkSw*~;|,Xd>V6LWjx.8Ciiz2JԓN\J^?cxJf,zdɯQi'ꅪɽ"$) XeەYe%)%ځln=F86y_ġfl^t^aw=s@;8 <9|B@^Ɜn 2zjL>Q#^] ^ʘ*&gFҿI]㟐̨#Ys47"B 7?97T^W1z"-0ev_2PT5Ok njH p8FQL,du%f` 2fCS^y$8B>5&O,^V6nXh2ދeˆ_-ڬgZmVg#[R]\Um Mъƿ 7 tHd7TZ (ᶋOQ9hp!eH.'u#9',TOغ?IΟrQ _rx 2;)4pخ86P2TP ,2QUO ʔ&pɈN ;%IWV]A2VK=s㚐55&XI&d7gut6W- AKC%Fj(`6}*DIhmd긃­]>n z` \B#>Zգ`Q*2N 1w L@F [E&:F$[k8]7ܺ'F /8tVўtB*EG{;(g𸯼 m@WP#/{Ommd=8xąe]0D(d6PbKVSv+تց!~UZ2=^'ZRnRa< u>-QfVr ($OQjKm/:.8QӍDgmQ]vr5մְ>Ag'f .g]P G0JzR4iz3l֮DNЇRT(ScaBG_* *Ơ 8q?PYw8/K. 7T*jA#mNO7NjJ-VÔJ0E[tuA-F04L+տ&i'lnY5[duJ uT;;ON(Pv\x%TZҪ'}F !P8jQw>X$#c; T)5f0eniUQLZ[5q  hQwY1v'B~saJ-'yy m؆<9߄lkY* I'e0!pEYMsOjbY"WMrW홯\vDEN` E.Pfk%<̵)PIRgdUv7[u35:,Emot|c>)3z쉨L(Gڒ"r[kYVM?e,a ] STm,J1D0,q-~{ߖ^ ˳?o_ڑ[as:(֯-WdQBd-8wECF}B(i oljJH7*E\f=!K(uWe]Wsx,%Q+.bK϶H~\qc]'\Lha5ք%s2NZ*D>ѩ4(ZJhj-T,֣?y%'OI|3ɡŔwJgNrJHC$lXa<9@ށ='Ui—XbmNcd顁63Vuۗ7=)7b;*\br\L.U%Ҧq΃vpQ׌[GÓYh1Zti:V݊,RvxĂG{BxQ= \mH%*&S1c`2i`aGǿoc-iԬP#rS5ڭ&+ںusb۲E)oH8 ^ABtrΣn#Y. *3tXcQQʆ2iUT(H(%,ltzm pC*ˁK󱴑3p 9)ƹT!aq+UW ׸rA]ϓ1Y[%#̻g0Z F8A矫GWgLJr ˟E%fEz&G]V㜱cȒVTQN`yU"vFpK@5EA'o$&.:8".ܓ54i _ WҒ+-zQ4ȕ YRf'*!NSҵ|Wk8,·@rм_nW'O1uDŽ#APvYTey%:7|$AOF;Bd >κTF#qXkqFAi$3ņYY^n)ĞKQ Ce0U-4tӪ 7rʇkc{ש5 d7rS ~+me7r>A O.o{l^Ҩ kQ @/ ,:#:L*ΣJH3 *ݾML:?aJ11SG:R~B]?`L\IJ([t?|Zl!}$ lŒ6cAݬR߀~+0O9Ut"傼)yY d@z|*X ,JH0s';.O؟pU"!^fIzW By&R0 ˬѳ'6} gr^'cT󄕂8Qm ]Uz#֮mI-6Og- QPɖRT^u( &TgFb&c 0p.Țk^F:n @vI2y]3*Ju򞯝8Ӽ$}Zx[ vN=aqbڇAI[g@ VQm% TDXEwLf>=VHG է\%\ڙt]|/ād^0 B' cK:ƼF{MF;Q(E.u)?q_Q pP_aܳǩ7$Ɗ;+Un.w4% $֊ioP.!,3IU*-_cp;ՓU:qBuO&-]!ߚ?b`'T.E*4tٍ":7 G|Np&֏RlYI#W8W#O7M-*[E$2DSUfa:3א|(@oXŰtC[ێԨRpN ݞ '=X0a\Nytu.Z+q˪zewwh -Ȑ@Cܞ*QcW5N!ҕrQؙ'9hbWo}ڌs{ѵ&F0{Xqx*ygCN֨fEV#r(*^7~$1 祱Pf~Dò[ sA"O\.̠M]MuFj Wդ6~U4r5nvpꁈA2 & owTA{'ly$xE)CM8n'|'QHAU/+2.vˡN.67LL%Pe7ŗn,,lq")B wAn!ł։CkՄpBT{q\sqdp&IAشo2&vT"IjD=|Mۃd, b7obI05Q/:q- g^U'"kb >>Jb34XXn Rm\YU*k/@nt h~ +_J!`ؒ(]xWp}\FQHkXMNM.㺘x'0hg,'(-;0)@4N/ `e6gD:i8TE1mq:V}z|Ӽ"U0>g}vAkf̚xس +<]. {ert>5V0iV ʻo]^av<{~Gޚp5Fَa^&EaKa Y#_"˔8T_!ȹŔB C|2Pk!p_LS< f ^clme/83:0i,JߠDl[v B?MqXH S |\&$"M@`SM_0F2Љe,W hDjӦdb8CD80 ݄.ENͯ1_ף$'v",Vl {wPNs:"@-mkeO5ɶL܇DdKr9t<]V{)=z%C%(8VXPjnT!+{_?8 !<{Q f]?hG { )?|B~U%-`/؆h8xdwhԓ&iᬐ%!/XmzP29ѢZ1s5K2 ԕatc f;ߤ|sR Y~Z@_rjy_%#u;ҪYYs"fiG Q0nֆyo9!0{2Uj$3CQE99FXE (jWPZDec~8nc|.O-Q4ۧ&5PIc5Ãx yNp^eI%aB:,Œ]e(@vTzU.7!f\gb?ST?n4s8bF.PVQ*ԮԲ!ReQ(T$ap7,KeNj%"I'5@ _hdZ8ҰZ Ӵx/J -S0+y*ė KĨ<[UN0c1l][]:V+b !LiV~l[8M$!c6BmH62RT?IRp*meIS.7$ɣW^ؿ J$U>"fS+hqh8FQնIji"٘bd:W,gƲ&7>SVίObi0>ZJ -ߞT"V)ipr5G(^gQe7v&sc\o0ivR˔.-?o?܎xE6>nR<:]"WnY >Z'didkb S͡Lc'8.ŖεzO?L)O?V~~]e+&8dDW ZH(*Sm]Ee]pqB'B>^mtrݵ>/?cRkŇk5Fili9/\X253w("׏v`+C~eAV0MuPyC^x=UA gߏHzo:aqO#״!NCʲ+~@x ٮRn+#k,J _g:[e u?g ^|AInJ˒͝Z2O9ɕ pEv0$wagaVf#ǫr-A;)yO9@QƇtCHMLq0L8@hB /s`z`^K-bQ[8oKD>0s+6daK2ÝҬv+o5O~ _K&Q 9$)ꖳ}i+*N d=CN a5`. {t2R3}ExcMx1fulclą9|#vX}6%I4m-.Q߼4ǒ8?i r>W* t&fTc*]q+?^I+ZАQClL\p >0t>BVsh6Zپ7OO&*`އ=Z (#gxDMEv%oIbBYNQap3~JA i)I!&"'e [%:}* ($cVUψQi,kC9q}EvpWwE76/w-,0fAHVķ&77]6DmtRi40YO?ΉVp`zPK{9VN(j@h uHؤN"`&-TE6*9\m $2/JsKW}E~sePDU&d4nB#tz%X >9^Aރ>|VMԯʣ_Qz--78'8`6Tu~'~DXXشpLpA Yzx,ҋ;g@QߝVCjv`|( ._ ~_9j&QVnu}H=ZoUMz=;]p 6@;@ 㽺Ee%ǎMpbU1ӂFx*.#I -XR5ZeNkr2N " h3(=xiy{. V=hs,e ,.3 C F~UWOH/ n+8CjjV@+rMQ(_aR@\:MXȶj @;~DGp;VS,h! kF_#EbDEwn~GjB.,oq>>8eaNQDE!Y~ᰖQ̇pLf8K~EBT([` SX =ZN.$o^FP4"ȈUa2tZ C/exZAަt(7l0;]|(iOS?sB@^XFQd d>q%0.d|HU*m9^(ZwkdxGSic㌭YL1%QWwShX<UnG!l?WtW#3"6cy12Ht?pTZYX5j.8Ӷj򂃣g߹>"sahB{OEgN"m,SQ{xƜ"*jDvToo,&!(we_Qʼnax-kQu2 " eK _ ~{[L&Xk om%~)Fvb.Sq\ Az` ȆR<,*Q:ϰx|)\_:n,*LE7D7k\?xi3۵1 8eyB,̈| !teDMG}iW!Sf&N_ro 199߀W(󎰋A3p쳾c$DPC#Hy`j"0*I8>kv$D:/7GbލXԦ#TӮS\-}XzPE%S@ ",*"3L%f 3FX>9`q?W E`K$pޗE7 K'%F,3;ƐæqLvR()a 4M-ޛʫ7)Pk(M.p'.s/)bOWc@Ѳxh>)G4'pf:ք'URsO Y)4!2 X;e? tm,|֢^ p|yG^K $B#*3p>mrrw'D&d-ev)M1Wڇgolg)i(UָsIFĄ˖p 2Ǔ"NX"JhXL\ڐD9kd :8JRcwⴡLsj/p"=<ӾgtPa]7ߝ~SeO[w\^)\ 4&j DV5*@(H8nJ|_zdO(;}.ez]e3^~|^1r6 m_>ѭ=\m)sR^0-g%530B˙86z:A٨JX$T¼l<8><? c}Yјj^4m rFs MJU9ƣU_ee憺PX`=.4Dd:IYf0.D{T: bK D)HE3BN;Rß^|zAmwChaw,CңߎrEç<{a/hT]*Rgn[oTqïɍ^ETT錢2U>0zr$X%BUڪ(r^-U/.Bk~蚝`Y@cDJ\HE@K؍)չ q.zgSjhWW!(4a}\[a&V¬*YcA ?EcQ{ ﶰ49IropO݅Ӄ/6}y峆/oæ/|e 4A 4a 6UVxVm-<YݷeCh`ﰶsSW7qy\kod5.}y7ϟ|~ZweSo,$m,! d'!7%hYZsc)<k^8bHeKgT2۠?S2IcuY54$ZRLceʽz`%,9jkUZ#|GUR]orΪAxR164/+@FKP$|HqPHfr4jrqrjGE\TY` U”;Pp$pe %pq4lXDcTim#Y(SvJ$%R]۴$%5)P2%Y"\D)]fwmĉ/9vdoaV%H[.dUsaH!_^[WPI߆(M.`,qW+HUg كT WF)&Q2;N5%W,{y|+!=ZQ%MZ:0ۥHggy\0JHc",Ur3z 6Aϋ!j$ J eC=-ol6Q9xI؝|$F= g|Ux{M3%*${o1A#(=o4J%J׋(\c2.# w8ŋh!QQz9ĩOoLqpz4Da(-oO0FwIVD,,ͳOu~=ڲac0S:D*Е([n|QN2^2qbd`l)Ⱥ/Fp,rvP94&N[t #x,ً9zbj,&&UDGA`3Q25#%&mF{% xX@],ef! d@3Cˡʨ/E:UTi+ZԀֱa s g&֖6v5pF&'2Cm*:m"\I8@,7I՚@tA f**ZXά e!c뒻J-*:'^N,jD 2\Stxq6ank3@nK%,:d0.HYrgEňO I?dG :a0IR3W;[BʣW?GTl Y=b6X/lBu0VW%;9 W&7=XȮnFnz.\>}{hI^V%h' 5uw1w,ф[J#;#0{6 'ܑukC=2 Ԥ;Jܓy*fө̬ \hRNV_RmR(FF5Kh|JIqP٦4 6%I,WrElB.viJڕFb )}Ee4Uh/&Wsa%.$amA@rX&\71ٱaTzHI׮)c4z""yO^L{ybwP:vю" ! I?JY`jNT [*gțEAVQebFTD:?rT›EW:U@~}|2r.WbtGRȯX]2 *̉`` 44\*7j1N) p"J8#JkT/ 3`N(M{D%*1MOg|b8ςcp,$B9ɨ(Q RS^cdnÂpCr ;chSҲ <\ K2&,%S;Ir.lX7K G\'bħ{o*㴹0%!\ݝ5d\oCj!wL _)={`)8.;S?Ɏl:JI))p, dR{09<OIj_s!%#u/CF2&%v5ۥjA$2d%y]3q+2c~=>&-ށՆ {G'LJv8e^eZ"NcfLYBM! 5!e uC3SG`V `CI$]5G-( -~)bb[bc R&|׫Q6Pӊ!d$)cǯve]$Hp\ӭُl1`r҂r 0F\GkF!TNcNl/a;F ,p]X :_%`R)\g&8tQ롄NЗbb;btAWd60+ա`>K]&쯑[Il&+o-ކ曽vM4F zjZ-^;Za8j210u>o7Itf_"" ݈:)4Q'f2 )@{!sMx  $$q8Gχ{jynrfYb(ex|TC@9p&d CoUCOZA#{0?VDn鎍" [ƘrAR2X\')P6);毿6G`Abʊ 5ہ zr%"!XV|1IR9E1X~ɤgcEL; ' ]1=n/֪ N.sLb OW tA!@n0hӨr4\T`HDsuW;Cz'Qy`{q}S' 9$ZT(0--.4qQ*^|uGX@>u|8?Ki8(p\Gl$ iz})W0Q5/ppĦŏJRQuk !Dk8}v,=͚;JQKdf_:"=jjm4U$bPuHK-ت]jEZ-2ʇ9ϩb}h:QjIjHB&9]̒ ֎5c 5lIB)r#%J:w8\trgB t]$`¯&ZHH)ӊYͩD/,*4n;c}}[smWK CUl($LmMPt_fCwQE4GHŹHJI=ѣ G3I,Џ=ϪQ*B!~y7C3ׁMd#4Y\##CCVDs" F/X%j*e.\t: Ի2 ^sȟ7@m`&.C`ؔT5W4,>w<6 RHTs%,~X{t_Y:b[zF{bbٷ6('xUԧ;/a4y`DO+YY˽%IQȚBsa\$\vd"sI^fʀ1&2/mshrB){rR Bjm!u/t, ȌjZAHlɪsBōyV T=bjhr#`H.][ BQ K!#i`I1S7c <잲!+iҼYJT~Eeab٪&~g|^bX=q˗-RrglIVm\]6O>2WNOӯ煀'rԾ6S#V6ȜO{I*Aj .llvJ׶^6 okNGyTfiXe#kO:4salE0o79Hi$- Iaa2QX,3ZSlV)ƖK3hIR3RFfas@ItE_wTߔ=ך6I:0w; J[_b+Ao ԉDXOd NИ TԨd&Yj>G!⺊'B4:o'[Y@"WÔ>l6XnQ}? M7wvԿSjKqXFA>ݣ$-LdS V5 w=v|O>G`UX\\K/n"=w.< ,&̍9K [\XrTxKV\eV!.{ȗY,S%D>$ZT=R c"j06壆6HdfQ0 iX5MQ")m'sHcp jrͷ٢[KH8Qʬ/@{d Ό:lxAè9ޚQE3׋1&kCo*zf$~%ys -3aQ);n"VhQgAR'9fq*3 Je8מ /mE2fA:AKTIFb^&MnrrHTCDYl4sѡ[w* t4i r+V^t薤pOuDu="b|$uʚ:"!TQR8݁Ͻ`aVܟGqJqLǼQb&2eܵ%%9슗Iȹx4+&(feJ^7F.܆&wvaW y2<Մ0#]ǾKdSȐ >^#z&G! icW >B9_v`Q/oэ@!`6%%Nu3g(g$ˈb/KX)K8Lw&vF)[ 3 W|R>Tʁ2hwc:2e2*{RqY.YSd=ԩ0C] Ka 6FapkNHt9:`̕Il LhmTq5@)RN*1*6 #ti"x2mB}cF(F >ʝGEtvm `Y=v%ԜLȒqŦt!uV2Zm<ݓCсcK@ۢUzfFU}bʸqҴR*edQwJ*BٛI*̈EᆿC ꈍb¥b#۷(| ]MӖm nC]!t_ar%7VQ'?q³,$5i`I ʮA!\WRG}f#f3KKbB]ʵ/X:Maū<*1Cʼ ڗA*B2T,}jbF|RXJ+H~XXF s D0!9s0ZyLgW}4W2L!|27OM@bѾ&(:2z%"l)u\KT?(V6hFKwyiR`by\-Ґ87MD +:S{2ʟi H񹫗"VNU٫Ԇkީe4(62N.K2x a QeĠVX#[Iy;:XlF[7w|Ncs0oÉ nk9~p\SM?q ^,̢E_$~>!iHAqsX:fZd~PdTPQ~p3S"%IQrҐkp'i$k*7a lr+zxqTf5u? 㮤tsj}{%! 񁙚%5BZyZњʵiҼr+a8 #-8aBT 50hKtztp 5le@K:ZҚ(sF&ijQⱊSu?5\Xۊ@KΕ]Kwqy,1So#^wqѽx]~VY/蒸GJG$׎ӭE0f˴UǠBGB(ş0=[rJdXb򵂨K ʨ+0 /E?ƿ5U8?Jϒ@y F,Cfd 58?nP*X!ªoSAwB@.by#h l1Cҍe(%iqD;T?eSGn'W9R(Rƈa稊jlTMRz}ss-i٪E(UCFSqB.vdcNLxq BA%m'&[|ӏBBؠyY#V!Beqvܒ]"EHn)=7ww Zɼ2JX ftlv]gڰ͢cВ|tY9)hV*S(?sb &βpS6s35aHh'krjw\ug.8+GNo R-\U2/(cgЍF' ݾ2-qNjv;=C:gz+:G"' ˦Q/Rai\"KVzXPT&G}sHA-` Tx++o/y xpEɕh 0ȅ)yQ1r[yV:-q$W0dM)F,n΅P9$MA>8)2nluC_WE` ,lJrcKAseOMޣHRE{aNj;LT<a/z4 9K#9LxLeҩlW.el|Ⅵ[vôƠR4X9;"i/epf:8 Qlx7.(rk0u4 Z4{T [;, l`qiu"0\d;)KvePPB%A5$w%P frE5T c>!.YЫ)쑡: iR=tJLbj,L@jkB!U6e]zݟv.>DuőȄ( 33Bۉ:_ .] *2,dJA1,~Q@eVU#X%LY& ;5kXGt&Pͱ ӔAfO.vM+4,K\D| nQ؈`tpkO^4NįFSUI rʣP7Nd: pؿH9A}(EYQDSz嶄Qc'ZbPT)qNtzG0l?+IY䁄 FMe>J3B[v9HjHRZą@t*6jX󨹻M˙SM̨%2**9M]7U^q< [o)6"*'o"_?chsX7,a|bW8v"onjN^Z;;Veg$l% [D@+01}<$Vƶ ɏ}Lt+ (q:E2\x+ՙ}p ~ǰRYYF阶eMc3Qes1,6tM^dfqu*3ӂXaWf8ݷnEϠ/ȹ<ѹU3"KI -?I-O5TSऋGY| xik;Ddx< VW67U0l{I59Ml6:8D1O:@Ѡ()E 24{6wQes`UjXUnA< ]?e=ƒ"Ilag|GF~kA  &)sL9{ʄ d#FATDU'BZëȿJY㌙U@i"kB\ziNl1:|-Zhf$̈mҺJ!RA"JQ48sɬFm+,1)5YT6z>"|I|udJD6Tt5;TK^hR[ [iF ue[Z٤|J]d8UJj߽Kmw׉ᲹB2'!PZIq?|%I %Rdɇuюe'],pko7iE㞷"$S6$ >VAXl}t5ba8TAKۡƲjK +P IEr3мʐHqvѡRJ ݙX)Mue Ø*F tJWv-4Q+*HY+-sߴAo 1Y㸔Tx-@$ I$"Y@Fd?⸬Y^ IҠ^ ّ[-T,[i_*`u-~O1.4MŸ% 4WQB,k2g.U@%Oߓa{ W/unozIJǛzfXSq,2ЭV-.(Kz&l7hIQqг8 {6 S}lދIG1o"Tu8H•HF&dāeP{)MUQ A.śa0-J)ì3LkUAAVuYϥwRAeZFȚ&+(:X~b,7%ى܊ͫG,5I(٪|SR9ң d.*_yE1XJGɲ5 s;d I"#%=0.+8%EvFb5CROaOB)ocdϛU*VLS)4jsTZHP!vyE݀h$XlVBIJ_̾LfgԤ K W.%#.snqDx3qzz)z`H5)@m+%KSC՗5>uQj2)J':,Sz~WZmRZ5I[qH&BUP“͋D($Œڊ?52qu[ͪ1&:W$|$SقAV*Đ:qiGAP5WAXCh\,KxƌcwR_GL|;AғuMrK fmVO0loccUj0}~*gGd}^3n.wNf chи^P"k8&δ#KE9tfL5߼KW3BtgGb_`ASq]? 4IkkIs ѸBQ>Y[>z\Q%^[7M.[|c4*lgF'QKj",7j`čOU27r_Z|.G: :4N }"&<moY]OR!%䪔y)u*}(ZšjǢwc<~, MF0}0AJIBL# z$P c7_ݹS6g.fU7;-llR19֨[}:y/<TjEKץUX U+eܴ8ϒ>M@fՁtӗ^yv<%Cb |}ΫSE$t/6J^S\Ct@/pWd%rܫlьy͇qC>6$ X<<-ˠcsaȮ[(&6V0vmPp MF+<&ɢ ɴUaq[G39mkQcT[{ C?63&jѸzh3t@k<ǔ64)σEif8NY+[f p.P- 2)<p{-h3:6 `]pH:SNFlS1RM~{k{eH&-8!WGv*oL%~ ~w<w|w|w|w|w|wҕ$1Z@Z,2A߭ƒW㒓[*qnW^>}.mCC_!v%v:L'lkiNX',Yt~* Q%1_Cl._ҪRri-ǺL~wE|G>{pJ|'1v京|o[ w]3E"P\Vƚؙxc%Q[5\VJv` f؜eV+A iϹO&dܙa9^E6:4 ZX@\=xbQ/b{2(BPB˃D m34\W 7<47?ÍdF_G@bLQg}e`T6\  cmb]nVxӻxG R'Ʋ˲]M((n)-u㘪|ԏڣ!L 壎r&:mikaM"]!ۈQ5 4lk )&:ه1a8nj28A e$%@\@aǛ0mZLKu=?U{$zQ\ ca3՝(Xx[`3xSbqR1 "UMX`ľIׅ]Ho^a[IԘ|TWjVX! i[j!pv?iߢhT 73hGE)ێُJ g'`f%c@qLYk.EʇV]T ۂ{bw3eq`{@ DYBGCpgtj)[/#VO^(/qD_#W1Z-rn,H˧$.PԄXUx0Pns_MC4H:WjUMRej0C^ '\쾦 $_̝MQ( Hhp54l ?̭};b*Iζ 5Lx ƶe3/^.A0 xV=/nEL[,Z"i8MN U%wEvz$Լ@u,_tYQ f:[sǺ q@b@q sfHU77i򨥯OeujUM#5z۷$ 7}u:<0:Gn@!iݰTnvɓ4Y, .cjF8ܬhiZO{!LFd u/8m(;Ũ(H(EV=8[Wq~_ZL8EF?&  ȑ%N/d\ LGѮ*c̜ٸRʻH:HhQ͑j] X /kPBPlOEzPR1 eIO iePTP(HAX>F[$1v梥dl2_H-d : 7 "(`Wt%JPM6#&FLt%m(%2aլΣ~v-JdmK &Y߇>)eS.#ݐV=w~fUYz. ȽoRÙv#whEʂ/i]D_0&S5Ğǀ$ r ^vt<q $7O}X(+ d]idMe5o|!n\umPE m9((aG'DDǦG;)v,( :pxdWq/2A ]W3H eX*q(IPf(9|R=>ߙ~9$霳!؞?'^61{>9" tl85 ͏f.h[7 i?2N}$#4p`5Hd}/7FЄbxV: 8ȽxS۞M/t:hq L.!1aur 9DpQ]]Z^ -!p%]Iݵ<5Q) 8%& ױ0ꍛdWyL=iyj)f=M_{N xXƩ5K,po8nw_ş/[em\`o ,*o2`̀伹3ωfO왿qqShB4Z$'f M,zk fa'͞/&X +MbanPh%2yў90ddk!g=NxgXV["7)EjuuX[7ws qvuU)ZӦ:{]a tE˸Ī@v@ʋPZTVzh gѮy+)!#9 /fEPx , O|G- s-B?ao >/O}[?]p/[ѷ Ysnv ҲăgPo 2|.{(V \ ҷ[ yuc,q Um14HaR#Uq؅#u7* y2z} -\cR%8ޭwo\\."\lQ\M\۠_Q L >]>1O%ܪ@lݕ][;͜ᰏxdWB>wLxݤwt!t !#@J0bUPYpAjAI)j R :I2CDŁlư?^Gb.qu1K2e+*NYe2DMsZ89< yM٪ZzX4OnDgv9VpΛp2a;e}C\RIyh2 ijWS p+g7`gxsoէ%ѕhʌuY.{l;;650hId~^C3tZl.d>'܃n ;N>{+'J_0Ű'ODjc^6[D#HQY|lc$i ced|).ɔY̍gL;Q;lk$s;!ʢq'O6G.jFd%V kҿsKwѨ#F&)W'J}BW X Fe-QOTs*9Z[BZo@*{ N7-\[q碎cO({"ɳ;I@;wX(/^#Yw$sx@7Q$qo:D߯6^e-/4 D PV`.\̑y:]scu֊~@VQ]yz,r&vڸ?|vX7t6WXԷ}T[7t5}o(Ds9|`DlE/]Y퀢%{&>ȴf+Wb9Di({3 zJzf񎆱uׅ-cQi9+摹/x\#~p"#&1`Q Vyoͬ.+2VD{= SIY= Cl}V)~#H])̏B%w5uVP0>ဌXMN&&<"#3dRl͝ɱ6 pxrQeeF^~ 'ctn-eUF3Ї::m  ȆA}#Q ׉4E$ vW:uf.w[tQH#ǡ9,cqt1[:cՀq| IԎ}b&f`"o禨{CZ.9Eb?Dއ[Eo"oƃI6|Nl+sW*F\궨%e {PTc0 0&,s%, ldz˹`p'+Eb \i, `\2/dA(ŸhDV(= <>j{ {u- 8s (k5`¤9/72nx9DA۳ # ,ǭgD|w\L{0ҭ,O%,*9DMsWư]nS: -e3/Dv@'fc^D|A0Hl]^ݜLv@|[8<{H} ρ|rJ`Y^_?>o4.# VR[ f3xߘDԝ l<.;)YxaߟzQyi yy^Bsz|ňA2CE6ސ[te7qsD_"2,)y.PJܙET9ѱHA26~Q?w% d5JBSߺИ@V?$!y!.B>ݺ'N/'d2gsi#mkM+>7_bP!Q-fu6`)Q+@8VM~͟a%L?MωA,e{ h%Z p@+÷V4Jzp1WmQ51Q sIvD&8c+&A:ŞLwln lخgX\e#lJUB.ZA(`Rb((T/ѐ+3볬% Һikl"}T2lW YjAŚ_)`-;u tB:$qZMO^lnO(\Xp=+bXF2i|}x4$F" n3z;ڎXwv cMc5:pRF[LO;N0I%ZxE E$Qg;AyVф**:m<SDEJ#!@vUo19PL3Dt{SN׎|\e1 pv$qc+;3 *6ŭ,a"d\"f}7!tIv% E!&d23d,Klzg}+_%GN\(e* nS0,(>-b^ rSqMeoJ8-"=݆c,Ab\`i]")yQCW30Q~ƊO۲‚3@ϥV@=P[ѡD|T#UR; && ]u,!4bEȗX;WGh?ehFԓ"6I9gNi ;,݂ }Ah@jF)I"Jb$1T]0tT_zr([!Q'%468 (WFF>> pS_;( (qF qi@ݤAJ\PRٸ4M3  en*ڤ :.rM@u9y&&4Σ[ݜ FKl21ЖwdeV xE _UW) $3pڋ 'o;IBTcY+_f] S([:яs{)UwG>{9]=훿m䍹̳ Yr5_A`0&q"1)!v玠T8FzGP]r?"lyy nS3Zt0s^a'FOKCX0!~ N䎑*G> 'k7nK~:P3\M6{+֤GEDZwXbku<(`愯 V:~sE+`hMkHgkQ%&+OʇAEx;Qjbj]] ~ښna;0QEjGP/{4nN Q qSy]˩E^LD (L;-/.nӽ>@5٢ [xzU1wbpQm+C|GKXO;noɢF: +Ca9tpucނd \D\q0m@q]Ps^y+(ϥjSBHEs!.{8e9vB[ ŏ | }kq3h%D2ΚghD4diU"wszy0VdW{D/w>s P1#(8=1^+.]ɚϊwU*nV{e˷G2Ķ;b(o-B^0ҠePdsG/x9xIðM땱oq!Im|s2%ңZ1)/a5=rGPV&9WTkLaV%p6VZjCR)Qp[B Ye36ZtSD/R% `!ILLX[עՈe)"͡Q'Tš˝ LOxAeut7{9o i;PSbH`da%#m&[YʬA cd ?kctr]@1'D\$NY eAM[)jX"Z˾uetY܂'zFD[祕&م*k|?һTob(.,GؗhFr>5ۤ" _TrTjQ[JExmy||BX$Cq%.Xnr}ήLKlX9cuIGd)44bE ט6_t ';= LdSߞ-{Gq">b5k`lc!w0LRFbE$3`*'!C;'#|._$p徏ejdN1!{$x2v:7yǻqKH6I0A Fy v-`CJE }XؚBGܳ+D \ߋlY96/\gDja!4O u] *+>_FW`؉R2ĩ%RR%[ E!lU Qf.8ӝٛ/Bdf,7כ;!ED ˣ^t;=lt= f'c`!~d]ۃ㧃 mjG6OJ}5]ϥRbf}^2Ӌ͂-dn d/ZV-Pk^DIv[Oh]a+r9"aZG*䛮h$73 O0c𞴎ė}&aT6tV9OE"TKW:rSB'7ϸzR6V[ְN_ݽzOLD=P*SMB-`]_m-B ֳgS'铁۫]N?xՓaB*;\.{秛&׾woZc SeD`|HܬK~B.7-p!]6{:_lt޷$U%ia{OC[HQP(]̤ͬVSJw&,Bo${6u[[a(3?R+Ew -o1heѳl1-0gK{,GcYԮ!||tͪ^蓖D=m@ǜчiȳb0F(e/%BP;tP7)hÔ, SF#%` (׀bKIQ#`#ge[l"obYX}\n E7?F8NjHa%m ޸ ;AiuɫZ dIc..(F#"17A4En,gQzeI|\%`ʵ#WjؾqMG3\b]Ww5vA>;z&eHSLv/Șç3v7[^hj} :T[aNM)$R3$ Dڧ&6 fǾ7}K;!-(B|YNGmp*0!徚ҢR@>=BP[IH9wmd\\; ]A(!ߤu]}{YT/[ӿA#3#^]MQ"OBMr^{ݟLb1$;|Y?ܻFbzo7+j$<,?:qkCwdO(~BC͆ 7P֥yvS_2sE8_}Z%(D'&' 翴6+[~idػdiA)}:MH{\Ft~/3@;%߬76[s@`7 K/njOaur[p&q(aᱢbx+A%Yl'l` LG赍OgݰzbIkQ}flmG{,{oΩHb 5{ &F.;Q.(\ÙNeq]0k7}ۛF0BkP”~Dq D噇2&!([X8 K1c>"*ru>X?Uj[Abo-N S_5 5П (l*r,:$g7Q5Q9UL=^--tDeၛ9Y'  /TVIj)[5LW. Eiվפ9cOll fDE$6pLQr)Ē22zl3SQ%ʪ\942a5 Ԯ9]Ebuvl >bdsWRE(/L}!y_>m5JqUt@Pp8$.j-X#'ҋ,v: =!D$124b5Y7RJV(EIӳ}Cs]VLĺ)Յ ÚheH$Q{S+DW⭀o gh?P虺dq̗=pxAve;AeWΎF|w bdDU|_T51@fEh.?TJp1#!5,&A a`}ڭ.yxedt131 i*xH|z("UI%kq}$3bD E_ͯ`Q=YTzGr,@/ej\WVJe&1&`&7ϘPPD{6Mہ5U&SWX9r;5eX-&F"{X?,)jP+52^h%g:]"u[˩}>wud8f]39/L xCGБR}IyYr`ӛƃEG$O,87?-~'Žf{bz{`PŘ,!X*(bWQ!y0(P>qhc:C;;: i+Li02Fc ,%x_bDd!\ UDED sHRQň&0AIֱ*EJ,~ܔA[ o5u"҅lC2m"h`dp(l#Ey~-W糖֮y\ډEA{3^pqx><͓ns]f |!(/zOvk񵏾_G\E{BfD=S@ ˽DNO$کifѓH2%qFԕ5-d{Z^QT ѽ+^j̑2kUt3)^P_%<6̈́ܩ!f2{\A_N{͏7Lr 9]&:o l~{w$ʰQU buE^L @z(#;~gv0)62ՌRNaL.^2/'C%8.$&IagL*Iu峱/j՜LD\'N'| $,~#$&u1"2"( F +0 ּ3ofFP U'4L `WXrTאa&DZ.03 lj6I{Dؗ>Džn#il}5bTȈ'8i b Q#]q`bXϵpR"ΨA6V J6`V˭` >QS /3ȾTT#|="gߺ^l.P!s)KD'E&2@ɞgiͣL25J+IRV"6xB=G*]ӯ5 ͬzУ](*e qQpXk Cqv6mzcSo w mP"dk=JEh#c ZQQc"u0eAթM5d֎REݑZ6ȏa``FxېV@ i-m=+zf_0Ͷ jg|$zkű z {g4Jg+3z'f'JpƤMJƾʢ6+1iaR^Au?1Jb .mlu[TRq^M*`F{_ή>v..e0K.{켼|_T!t&W{2pbU~b`0-osj<Ǽ폁B$SVܡ7-.]mHyC͙rZ? ,薩MxA^# YFNq ɦ(DL 9v?9kkpťQ28^"VMG>B?$15+T:㩌/{Rfz}'mN.\<# IS~q}_UNZ:yhHrrG#ѣ{QPQl$8d$00#RVmMӟ1N3A9h,BZ$b%)a)5uC}*O|5ll0oJ׬(jVK*{171gSd`- J!@"Ӊ8{~LȔDC{0r SOsXUG, 6 %`GznѣMee8L&pi"KcScQsΰG^K=1$)l\M̻#oɃ?^u/=A=+ba,<#[?kzUkq1!Q|i6l!#)DNKSNT)] @P~&ޅ]Nkʿ+.vS&5ݐ(f }\Ui5+HIE2fiG`i]zk>K l%"9HG}ǭ]Qgmae >)!6 q̾[/i85Ռ!Ckl'}O˛e)K2hVaB}]T/{e^_3mҲ7mjxvz?9zyH]XЛr&UJ) ΁%Նv2j%ȓ}ƅJ 9@ױGT)!wHJqC۔2IRFȗ4PQk-Ǹ*g+d2&2'dہN$%樃LE EQGdF"x63WBoNnwCiϟ? ,sqw>?fFcfߛ5\IS'(YzΞ!'dJj[ F$jIX|(iYvC#.dΤT}%S(MQsv&?{Nd-u6?آΪD62|b)Mm}Cs)Vf2ܒsSuK RGzrMn܈aDĨ R㢸><>Kjfޑ_1r f+¤jɩtKjDjir_D~#fqI80:gк5τ{=m#:1Wdd2gx\1c 5Y?S\g,?7i[Xk(t;+-Ol?SwYLUvkhxp(Ȑ2H|Xx^SX O?W.Y{pٴ/ e8J /Qބq:M *~o.'ns[v[W7. *f x+!V;pkN%&;/R.8 X$5'ҷexk8H5[-2E }7v,Ha^xrjô:9}8Ѐ9;6;6J1>_E?i71/Vmq3XmcϴGnYP^\iVgѳgy/kڅsk6aQs@N"&0wH]R1'0/?7J#`H CU@2)4qԨJs1ꖭ\{ջivM'?=#(͏rZ/?J`!C;vƏ[{oe(BU2~J=YI1UbI?8VEgH,P^*4u3Tk"n}. \STeƧrCeJgO)i: !T9{)< D ^->9 tnx@9Ј BzWIS,آ\;UKĎ2H|m {Tw%gD]ϙAWh9,5_]$,VG(fs̽u/A iS {Ah&5 R6*+te;1ZD""LMCՔDW < "Q."&!Eb %>yMNGJKPۆ kP_!NrT p#MIeS5ڻ05xMC4]4,\*c}JB6H"[R {+rsoLXr{2lvyÍVZ״#/_*"Ak 6]j;XT\iڹUҔUi3J"9O٭fv-KC8p۟ղI~/]HP;(x%j"&C0d 'о C[r1MyL<{@ N{j6wJxa2-a -BFo]HaD|xR|*%ď4jvj]yLJi;2me|z]j%ϜNE8Y aa/jco3+/X2̧ ! 2DZ޹Vd SUmEKˣpCcS^Gz\dBCٞjAK12VT1øBF;+ʠ's~U%}ر:"PkQdPL%E(bQ tȨODv(TU(=㉺:j.mXN6*'#s] ~Bp:1~(3EOn\k7%@Ur'2oa4sDKb{bCRx0O :v3N&b)BɮeH6b$zh tñ3TB5OAE"FLtv٣CL%а}u}zuv-TQw3| Z"V,69OΓשeYD3QGl/zx ]"u&yBq d(afՍRu|S[p$O%da!:(TL T0 $*e @6ei?sJEI`[N;dT\+Ȝu=*Jb+.-}jÆG3W#i#j{;sHܹރ+ mX:Q. ?Ƭ]oj95V7'=opع"rMKJ6gQ98&RNPOdHͻIj,J3ЧiYS@; y2 71*;2gnE=bfXYI{Ր[G 6jäׂLM1laokO8mբ8gf hܹr^ZLE늫4u0×<-2FL0"4p ;ogs0 yģD/@&hg;6]7C:0V^#+n$NcUIck/l4ƾ5wp jYtZiZ7a~5SnQfaXkTt4r+ t~j4ʬֈ[²j7Ɉa|-HDP?XetK \ W|Sw['G{G''' 5q0<=?SLu"eM ZѪD< +0 :/e0d#6jTS[^_Xb{SKѬWl3!Y =alie襨,f[0xJe=2ձ[3ły]bNH2=yU-Sft/o w5"AG{ _FwGwG"XJV~*~X̧>j6T-Tѐ. iT'DDvS>>cdrQFܙIO;EHq77OjZX U@C>T4'tDb} o@}%m[uGdly}+ 9 R q)zd CD|QpbDTbb)7=x `̮賖#^kvK=zŇs5^ʱ|w5,BdIr†%Ad^dG}B"7o ,N9/B$!.\j!6{d~Gv>t fKzY9?mnƀ~o3WD񂔇;[(nzC->buz[|nrĞ-BwPN }s9ޤlr&.mڝY8o޵Iڐ8N^nD2CkUoO'8M)] g_FAf`XVFx?Q6˦ang"ቓv𻢯aUyW&5i7>=o.bs,δFCړr\<@b'y5-Op{3r`s o%c>v2=ż15cD%qp:uyu^uBznp(+ot%K xfꍌ)FVx@ʯkhTyrG5z۳ɠ7v#]ٳ50ӾY:bha"|+Uĺ AףԳM! aĆ)o;v^ɆޚzIB(w{b?wņ𗿜]a⍊^=!>&bK1#orJ}'Lrts4ҍQ 4]}5lF&=M]IY27КLÌr_ڇƢvC;xTGyT< ͭ5\T.޾8SC=*@ t0Qp&mz0gagoNKdm}=yk(^}"oR%L@_Q>:^-fvƐϮprZpfZf"`#FA8z ` %I'!*\!Qd :) yRˬܩ}%j$?k4_ʢaoRV $, x 5ƲQ6LŒd+7[Q\lhCj;*Z bcX[J0Uޖ<xnkºTFX*Ua4rAM8){@ "x#)FgEI&XDB@䁒2Jo=S"6(`M]zk<'±Iz&{ό y9A7s!,6(#)CH^)Z뭛s{|pus box9ϳ, h~5[wa>jx##K.ܧA\`$8`<|Ce荒ijS*Mބ/o]ESwo//7yi!@Nn\`w(ayZU{̪xFk7_Ғ Jh✉? aɲ3d*,% 3K04(o ~ QݍeF=X?Aews3s-˵{&Tػ ݍ#o-sTm]xejQЛ9v01xqY[ֿǤ5 {3`a;"}'6&CI6L)tƞ 1>úoDy=qT|5Z+]dP4h9&}\Lp3sx 64ilqF?5iQ~qSnD Mj{3>&pE!5)ee+w7RtdJQdsO!Sk=%.*7Vɲ^͍=ٷykvĀ~̬›u&]3gf{wO͚"oYQMrL"OϦaMew~jP3kTq'ݿIҺ8K֍{]$I>@ڱ͍RҲ)D2{3, *Q[ƈ|]R4]1Z?ATMHn(1(FZqJ\t[tv MO8#[Hv"[Q*^`qTo.-N-kvΌ;X._'s[W5v;X*ߪZywfxrmK_b[@twhpS>p[,l$H(X,3pM7 p*.~Q*!载w"{lҼعZ(=Em Gƒ)[Rc`@bDufl;o'i\`)pnNV.2x-cebEWɵfl5Ψv=>~=dc[nO&u4C+ +k;yy=i%E݆+KhKAL ,CqUZgmUb,6e5Ar0ֵ֡ܙ oi)oL9Ԉ+̣'Yw2Sb}sTPEҩ㭹_s5OlAv_m spl (d("<\:ٞ_LŖ%Z x*'i8F)꿼ia/-W!aB&E\~s2o:l/=Mw%()g%L 4rK;%^YƱ- fO0'{4s}04ig0pãl8dDC'Ȟ#eE7}4DA0|;awR֥vX!#QLy43/.ՉdԷr# sM's 0_Ԡ8LQ;\ Ll+9U c+HWz\MÌ_KeShaIŵ%A:} SnqHSf6׼y@I}ncHZkwX`oڥyoߊ+ط56S,dZK:_׾u7%#Qڨ5}vCGbKkȒswGQIЛ^MPr$X5(7N쏷@uQa?N+IljJIWy'd'+ϱ{oGn ݽ::hw1vװ $G>hT;oPN>Fs:'7N~jwA̓К٤,il.zAva=mo>-z ܥwEϸ^|qv~f:=w\Cc|`y|qGꞿtό+<x px=}켹pqg}{qsy5a 8轧q`Io΍7α gw}~zPvOo8>^]gw~[M f¦z>v>pzOssj^^=vqӛK|vp>\;<=+z ~wF{y>W4& sy΃"`!+yKt`l|%v oV/4_L4L$+4qNس܆xXf>j= BkHL1~`?^' X eƘrzA[=_;A/[qfkAnF19ѿxX{!>Hw51o߂"}{O{JyZM^_ ) k{)ku^B>rz;wePVidP]bεi٭LboP#Cޟo8~d_ Su u:t_N@ k-1y{.SO>,P# gvFQ҇98C|=x覴P { _LAʊN a,]W &pZrQ@ep)=!wݸ&^6]"ٳ[+t#@ q@}ipK̾#99fJz~T.QC? 1fҘMbLhb 4:M }m#&UF2JfzW^*Ld%F1b?ƞYhV8zbXƴʠAB=7eJl)qd:d])g+ĉ ɀT$`r<햌.%뎔\d2.zjc ꬉzڰr_|6{lµ{>lFxr^L=oD*kO{Tμ6fANoM A|\+װg{=1*/4(<-wvB j/F Z߻.;5AA;_=mބJnLҰ| (=r^jMW:i;WF/~ۋ[vuHj_ۭcEX{7p!MPyc-8p@xN7;46hWL+fQM@E-K?c(2(xjOன xMSFKP\|&;sR49[I%׊Vb@df2Zބ-.6uFJa-˥h{kh(L /fM6} P7IÚx)*z c{"КZ4g8 ,wI|yeI_-h\& xTI{V8`iր5+\cmjڷnyJ+9[L`Y2~bSԫxЛedB]Lbc _)FoVۆ(S$]9hU;l1%ޖ]cU؜ bqGJ/H6m+C|G`%E&F"L-lx">8S'THgQ;߆'QK ` #-ηPgוnHC"[YGyh؄Q(+.Ҕf$f:[`;6Vo-׺+uBrcvȝtwVG0Sr=ĵB![#ܫx2CF]ѱ&iX)GN'`6_]tCfj&2<kn;&/bs0'-B8hD{31 f*fFo P TV&C$:$9KB4ݒ%tK<-'F܃+3y b6m4.JS=d G9vtN X.6H,W 3}Rӱe `2$OMNd[4=ۺ]n"#ډ3Z+dJsw֜H.LL%,qDT pi0>:׋WnL=t'aCo^`ihAĀ%w5^qK 牒C&| HЅ7AS5ji!g;l E ^fKc5}Z*ˑ{\.=$H'}6aȶ) \.pl}>3ħ0x?ݽ?O={7+'d$8'rJ3$LɡN7wdL[gS<ԝxN)_PUs"bK#ϙB \|آX=7 vθI+B/~L &&Y[01wKY } dg PtEHƉ"h̊6wxb5.3]˙.\|D5Ta1(mw$Ab5m(vYO9N1 OU{|:nԨG#exyDoBҲيTt塒HpX !6ku%E{7/uSkJ›!/`DIgjFwdl{Fk;] Z^p50a / tx+IB,0Bz?~MQ:>HKs"2"BwDΈ[SüSSa1U ^5Z.\KE42ck{$b\M" ZpoG8Ub={z=+\4M-cX܆@'h,8ا$cA;*ޓZAvA,]/0BkHUlӒgcIUWlX*_dD빍F U*pm{RHl0L)TDѱ b:&S &jb)U#Kp>Rvf>]m9c zC%ʒ `bV2{K IwՎ}HL ҽyxxh9w $WXX ' 3~g.\&\\먂\S=ـ{wp}n2ߥ 28{[xH|C.\Z{ ݻt>=5r|'`++޹ރc o'<]1 0Y h&xxO([o W!n#J\`Q8"xk{zkWՁZAѷs/c 5/@&~bv4]$8R-= &[B2XTR})Z+*|P %|hIs<0p̒l'J8n'AS/u}Kq,Sɻ{ GԈ|y'΀| `+R:Roұ@`~xatZG+QSڌK4{jkn,a % 17[@f"iMES3>r*˞ Ɖޡ`]W*nhC<`.h!KMmX !Z8 mecBZ,\NPZ@ n(Wx}@gǤQZi}9;`p\ǨJ|4G#|]gQ7KAtw@Fb r. Ffb0[b3Of"p}*ha^KyRqo(U|7}؈}s7,f Ҫ͹_4|zrOΜADnhiFTC/ ޛTjRsLz:}|_E[5/i}luJ%|6032puIX{DBj̧G$ &(ȇ>Z|l1r˗EAyApdD)n4 :VW]dĝ/1Ɓ*Ɯ=Ǚ.DM.`)/*eVff :cA;QVuxofTC09ݙUϊw)MTXO!FOY#nWX;jw" S%1s-A<ȇ|~kYb6:"3:‚lF#9Bp4_!LT(ZR%c!LmhupD:E#VXl¾/@qk߃. )/ޅv MQ"&P46)h%|Ҁ30/ 5 Hȱ2N% oSϯkm+'+!"‘xCDr| VӋh˞q}Ӎ}b0NwJۘM }i䊬t6'H}31qݵ1y4v-,QaD:\1O Fz&OVH6\PAFE=ӟS(^IFbi[ae9HS7eT_d6#/¥0_d"w &3;9ڇG߯WtdT0X3Eg>|pR{2d ഐ#ِHfiHsy_U0z4E1'Èw~Z\JED,PNPQX^b`^sṽJ^ tdIUqhV=r9f!#2A\;[4WY!!1>ZG&%i^vt*W Cjdxp֍Qz%܌Id?ӵ!Z5'@XU2Vb}rlg4:hTãB&F(rݯ.KHu^v ^~e\7Us7X.ly][VU" ;/dNW% '@ *ds3.gQh"Þ:b"dJކje(Գ@9X'L&~* pcJۜbV:_;]~ yE `L!LUxơq{={vi+|owh?Yipoqj_A!;\Q ?=弥۽3$f eb;y0ne`W.! %aqE|FGU߱'v[=;f s>( [zFUy5=qfFV*+{*zoVeGV6pN wf -kF*(}{{{NxgJ҅&bUyطsay`91S]j+I]rwc)oà"/v&㔩LG5xp""|"6[ݣhI`5$;lW%nHl y ZkdP lVE/q~Ggj2 #CnR EU~v1A 3a) Z1_P=:plyxW;1 [ )i[,!oH`ϙE9E$⊃2m.޴NNrԛGSgGϬScʪ),V҂լn{83_۵Э(^i`s[0%2ャ*>U|Oe1 YIӢxʍZ@ 号8`0g)Ud/YW.jn#]74DY493YJЮlcV04 E:pp4KtJ-0_+qWb{N\9]A\veJ/Y-:`o.zF:;/+{~@/G-߰pS .E ?£*js:*0/d@jȐc >Bse2rSc 7Jb:}?~.^ >͊MSl0n"Fs{$|T% H J 1Wy䟅WϪC7۳eg7+n6r`ڹj-<{iXأ7)rqW=P}a^R/p?yOE}-E$(*k(Ij?TL!xPwWL%\f}&f8eE~ l_ZFT{ וda Y:#Km%٠*V*hUKjrN4تCԲqo4_1nJb,f kyDSv,(}w QZ\( 9$ã fb- a w޼3z seTq, E񕪫ii3@HQVWtUIHmVIH}_&C*+fhaIK_ʗYݖ<-GU z 24t$Ϭz\t7^*k5Ę07S{Rlq ,?s]o|6'AKXtQ:j_ͪ^UǒĮB0A0Fk2mڮ J0*TU_]qele:ހ334{߾}(JIkI+w^~+gu$ yvn-rs딵9ŖjmƂ‚%xQI'J[e9J}l'QP>VF BdpٚrۿƝ 2*A&_86;oqg}T61+Ŀ4.`ƍ.ZǗy ҂%R@}2YMl'P22tBl2)FzFz^`NYOT wL\ r_4SR`l]]vBl>=;f|Vr=qLw0Rj0axrf'};Vj1;7 p{ f)?#3>s& 4|ˡ[fdE(6k4vߑ"\ԥhiVr%!uxyr*=6>vͪ.'9^UK6(57g2ɰxYFۡZV/ݙK\PW.V֕[Ǖ2[U`7]=jYgEaU!ջut$%f`PUkj?ExfፉU)U^ű.druk:@4թ,e܌ýJ)K{+)-U`4IyMQ%Ţ]wcПW<ؘӞzxp.MM:I_vwT%i8pssQ\@̔i8V)4RŮFyJYSn 5[q 0bla.d%^9pJI*Y3e+vUn mt.v&̭h6y얾@T"*$U0}n\QD賧*1T7d\݃^؛#+.ϱB WX-0aS,'Utbg؊E ޚ>(5JYm݊|}saeYCR 7TPrڇG+Zs7ٷ[)Qx` B.,_(C{*<*etno}VZBb윸hI"Om:豙0=7}^{HMȋ:Y0QݙwFclMOZD$Kԧ'UL)mk9Ӝ0D.U=WURV|wS fԆZQgu+6kJ>  34&7:Y SlA jHo= cL5m@Ij`@(O̿sbݹf`|xf>u"< MZm_ z0Cf>c& [k= ˫) T g1MX)iU-M  11jfd  2_ Zg6 <#{0sL* Z>3![9 "+E$4%`a{zp' "i.$٨t`gvo&r rdF0wcތ#L xS`.>Z3j'm s/ @ Y09\)9Q2 _§N˵״<\"`\Mj ,^ҦwTBvFAڼRuzI j)Lv6/&\\+Vm-W{N$ !r&H0"O"LK`!c;# #1ŖЈ@X 5hچN:vv)m=-&Α \0\_Q8RV]ma$&js@L\4O!]}ꝙ% zȕ6)KG*n{3xnwb*C{4&13dWεe5ckm~ZUlR?nfhi9Ik#![ \o_D{ܑ2 5ೇ7d)ҷ /x䘷CiB1Sg y9}K*X00xk` ^`F=#DbvG`6}뫉4nЂ#߱X&4›Ftj RdKƢ4"ѣE"^IYNdxUfyN.;h05&1kK pOQp06$6*y^> J&$XqKgoDcfkh@ _ N2<l8 xY EH;}k%~غdLXOBeQ3h` HTCm:'n>V2h?"8Ǿԋ"E 5t8f)o#lhL=`o[38KG9Ηޢ*}x2K$HYHd-+NpwR,i(Г[aKyvI"} .;@-ND!ZA tւY@0gM=E:4$xd{D}Nk1A٦ ^J4xob_HI(Hdso9e2ܛ^(C.{˟pF0AHO+zhRF">:ЦAh-Y 2x77qgu!i db_d֔ҠCAF :ft a80E}ts9( j=y"u"V~E# hx$o6H..9~ko_~w@`:%riYzo¤5,<mx65XYEJ%^gO0T3!2Z?F D fl. @XN1IJ<}F M:?0Jm#Z t`K /pMҐSY,r +#Qj< а*1[e_7R xz~p[Vnjې"!UV' cAD6$Hgi2k:OmPtCgpM=)={bcƳT`4-˶1PSE7(7D[ T=H;Ȅ KADˈt;9#>#2X$/1ߢvSVyvTd,|۴bdD0d p,NRSYB$.$OaӰL 2lV@ٜДNMEp*LᡩI+} ao27j}2*rۊQ;YAёd<-QDnM&FpJQ `Pd =!T7bԮL7 Dظ|2E9YhĜ#`yy= ]hD &eAqmFp#xhH.<`ŒWF+"Hh:_d]:'k=ou'QeZIx4MDM!yZ@, :WrY5LD2Ś#&/ִ_FhB1YfaqyA5+o{4(l ,H K !Ί? c"QMacH 2Ψ2 nì SH0NpC44aYV 22m;QƮq޹rY甑eaޮhOHm :GGkUOihYa#!\2ra;GZD)+ߒ(W Ɋ#Md{H 1iff UDB8z8?mI*~~kWadca=;ñ,F !N\%]p#@%R:۶p Ӱ6ʐo)ݫ) 9yu)L@9 䌩9"G- M$,dx*Br;YЍuFܔ^ȷla\'3~B4qZY+5..;['f %1I_ H;E 7x$ `P ҝCK6cQz=jތ>vnsVm~?}][^!`)R1cd_`[(X Ș=xaU p~ OV1Fг%T.Q㯍!:afoEZ&- ku]kX`c읹f2JR ijAW/ql2UXh%C,@q_F8\2 D{cmZ:ޭTIFmvUZf\EȔoCn#>*eOf#DSw1uM2-JbwEϸ^|qv~f:=w\Cc|`y|qGꞿtό+<x px=}켹pqg}{qsy5Psye|~yc87ƇΛ۫.gw}~zPvOo8ť^]gw~[M f¦z>v>pzOs6@ ګë.YOo..iE\pGw腛.<'ީEt\ј09`Ӄ]ĎϟP^?& 06Ыsc nC|q3ZBkH&TaIE ̐*Cg Z}0zh?Gfs;LVaHde2Hɜpj cΒӪNjnJ ;ہ+uˁ@&n Ed >N1s Ok5@+p6`1[qV= x_SǵXj{ aĺV9e(>LS/\Tu*<5^ixGʛF..FsG@peCӌyʿ5]WSܐOuwb70?|)D3Q{F3koUq+jEog:A=WLd$}m_xxc;m7JXQFn>dXs,@>$ĭZB@!5s8h7XG5jXItɪHP*Ly{BųCಝc)$jwurJO^uh:\]NRquӣv;?Q]{owYʿPF?nOTUЄsUi:< #흓A&́!vCksEROەeYĵHtТ 'u]og؄T@c7F{EjmÓCl-cU"яR d\cֿPR@8N12}>ܜo"7AT{rMux*2m]ڵ·뾟'DRo>ݬImu2Wǰɟ]Q{mdh7e^CL6(^t3j[|zwUf ݮ [6G!CfjRL'TkzEV{K\5[۴}3INqY/ѢFUEU='߉wD͊@ kkk`h>ch؋{i/ O?E@XHe+`o.n;AtqaY*yCFWŒ&3. Cΰg X EܘK}Vi:ֹ 9ZC!U ] M9kYY,͚O*&okZyo[Z|kcz:lG(laQ :j-!݉Vz@'͈\Ū~7@/Ow| =`HP{ٕ' هuTGD,TsDd>=.eڧc#Y-~&_\ '\x%v}hIF\NZ;LH$.uR  敔s]{tTE5#*,D%6"IH H Mhiұ(̂cx(GAQ|>AYg}Qa9gIT﫪_U}}v%Rd-սt rS.Kt}@#wLe)ϒ:yYb&&,2ɼYIyLcΫ\O*e::k޺qavY% `_줛q]ʓLwI+C 'Y X$9GV62;溚ɗ ]ZHq\rfyUPQ`@0{T(nAzH͢h`z,"0/b5 lk`u1zj$L;0:{^7%3[AW trb;=Ut3j ?0Fgi'p7kzf y`}9/]'aC?oɁפ?oIޒ%}oMޒ%yK-[ҟ?o|H7?oIޒ-g)L IMx %%9x3'8Gt} a%0 ?猦ںjQ# ɶ_Q6z4j!UYRUK 7j3,EWO!rE(jJS5O^JJy{bU=R\FBxs +C1tH q鞫i`mh6@qsjґNt JHP4nET:FAZM@cHE$8cPXƛri^ ^&L" Racds}i)"aSL~V FLR1$9FBs0 X&=-d~9PlIF6QK#sԬo|CsQӷ{tL o(sO5kekDaF6K[buܓlG&lK6P䰨.p,{ph\C•s MuTӭQձ=l AeKLz P@1CsH dk(DH"*8R.bK#885uk0Zsl vqU*gJ0q43vNvveC[|`~4h0D( XfCQC\*fht@ģgTNqqQӷ[TNaxеA " QIRE]HR6*dqq=*k=VH}`jQCsb)N[o() P+$(: Dŋ؝jil[Ikb2l*!wS@K&hI]*d3\\T_>AjWn2 JM"jI5&];M&[WMi.cѯ[ |^PZR|*Ue^ K]S4/GlU4li:I!.dUYװq%!eg&Dt[QH'"7R\J714%@E_$v䘮*OHuY!N+0EB҇<1簶0s`[hps+ @Q!ӵl! =fb(c y Cb1E֡snk'߇*HqLî+@@~Box6%CkRh% =^mKVװ^<4Ech a&{PY%;2})D@B{ΐᡦH ņz!MOhۤcaD2(s>j RBIhCCb7OM2FEc9U!MLAHD$Y:28)IJk t}TxCLEhcO*J'YdM,SaP EJdGT [+{S#S)DIK2F B9,EՑ{0-E+ TG0KN !(sH3M oy#O&6)mIb@7Q2h1]MdiƎZ41u Š[m:MfFK]٩# [m PF!S9ePVakA6\ĦIQ}%K rl #ZM6&vwpPfZ0%n3zbzN01APnPp <- T1`ɞٮA΅1ɣϢD4Q4Th'gu9&SY!<%Du@OO& ]ǚ{RyҘ0MK+>bdr/:frR؃\Gq@I>eI( cӝ_ <ωRqx21J& *v8훥(P-H@m`,iK.LbСI93p;77Mkr<4mŪhU4`rXUKBULb= 5N|фV *Ŭ36tVKtb,E fX/G>^J0Ngr k+Wq5#/2N|`KWDd%L{5S o\(xJDX{jhB21@ mvCl;̯%, _4̘UH_4 7f(/b`S1g!Ҙ]*lUMHruK;xD:o˚@(R]a `dma 0jrj~OHfִ6l'wP&HP #53LHoٳ9˖gFm `|sB#YxcS; e"qS60.p;]|b = k&NSEEck_|tJ!j]';)~jkK^hxdŚopbT,χsO$7=a!b:S2_LuXg(0U CPZBf;(&R-\N;i a鿸HY-9N9i ssQW0t$Y\v$'U@jq@G&AihmaC,9qxi[@o6R)jC 'Bn#.72Jef@g%Grj̶R]@^°gT4Z)@o:^cqL5&PBQ1,**F\1@L,$0 +)4*ԔE`b.6ZPG6)<"%tU\:/Zpk@QT>Gk {5-Z-/ָLHU]:?\ y=jb3?;OYFRԦ*_TrN]jpXb {\{KƧ9qf}askŖػ7s%Xݿv $gM[sx'O({ٺ^ѧ[1ٳ':iqj~Ϭy=k>f }~)Ku?y+5k>?=}[}OG䈪>0㉶?Owo޽~}gvO_~u߾k 6v Q&umݡneݡ.5B˽S@+{RDiIYU񯇸]\VUKg?MJH'I+*5vDQ%#K˨q=|c!%SۯSVcb7beο'T*p򸩕lC\ԔWV1d;,CE5=΅jf ךhtHV*7n/~T5 5S)V72^'j6G v=TM6͵t';R- VpUS.>؝)y3ް뗌_9}왃?߲f^rcݮDkGFi+w<nWe]o8ԓ%󇥗}Ol/dϦ!?Xcoz~LܥX^>tحs⺚1el^㢅\?yӰ_n1!K6np1[m~R.}_ݾ*1N&sߣgڐ}Ycسǝ~m<[\?7>jN]S}baCZ׿r' 8.b~˪㭙xouٰj7KiYK?tT㘧v׿CuLy5~w˦Jt<;Gv,ڒv~=˟|eKf6~Ϳߥ5^n?$}|ߑ;UO䛇|N|ț]ڣnqCVp[;7{yO]ѳޛG\?{vچƲ;偻?j6^ug^?i3ǨOG_]>=#Nζv={KM|Q->pը;;aiܲXi]{A;7ݩ#}+?ΘdOݷ^} O ڿ꫓/g(-3i[Tkٰ-)芮qD.+u~,^W]b@C5Ko r-P:NDF|4S\r33-Ys[LZ؂vsA,MxtٹyJ%etJf~ 4و~LjNga SϓzCz# (}ܤ9:AT:~kI`Ґw3Ŏ!iyOe4}#ݐWb+iٿP~/}&Ai{kzzճm}~aؚyёs⨜7^О={*.kߐ^5WlLnVYOLu}[1ϕ>p'~赮wF3'6Xd4T?r~ymF|$mԿ^+oz$-'۲"i܊^ٯ|נ?^3j^ w~t_5Ok3W|0_Nb߸[xkWݫ-O16[3 bmkJjmyJȢj| q|L6KwKI'I"eq6 PH'h q)@0zhR^v|*&{0aڶ0-&#{,813r$>xΒB:$Lgfp0N7i94?MB}bD:&'I 5 1 cO>h8?Ng]DVBI99]RN9yQ2R3E,9~U ccojAg ZtKjwA <*v&A1%|2 h6!d9ABLΨ:2v|d|1;7, 8sÅϜ;Ҏ5oJk~= ɶy>+ fNL1fQ r#8g/&7IЎi r2'ʌ#,3RD)Fqr|Ղ|*^n"Ni<@7CƘ :)g0!Nԉ `0Z$$)5/;+;7N^x0/{oѠB1 UO3;q`M̚}LJ:;=ahk}[Cqzɠ5&J l4H:$g"VyC uI3GDC p5f3\VVP<<<0GLd; zLdٜf310l^f3_p^V+Za -V+ۡn7`v;zq=[a$k 'B/am\`WQNp;0 g xC Dj"|xP+G#Jpő9׎kCr#fB"؆z~H ;?\qPWRtEn.9VB83`dv0V CXB."I6B@f2dI%e)WTGH7X9 tc;rLf9gWvʹU,F'UQܫUbrQYQF`keepq^I4=Dɇ-jшjGD `Z!xxHK-ɇł-jGRޫ%6֨%xx9WgwX FQ8`0HA0X$Mo$6@~"6ͨFtVDцsZ3mQ0mX|;CK\yOFmFJC0ٚY6~u$3)T!;!"tXUn7fN`wR2D,$dI=W)Ojl /o("]I!wWNDȹ حp m4$\-R!#0'g,vrd+e7kgTvj7;.hak"⫖HimABsw=)Ǯf6qВm)Lෑel;o{ Q^y+J)g&AlM4L9JFB~)jmhw**z9{("FNgn%áb(0ay-R f,ѾR 12Mb;HF, ltWl(y3uTkyFJ9D{K,DvMd%ɸ2l=@+0/tGh{(悵ulGRE5µio;'\3&Un%_v$he\.x+ kb *3'275XqK*޲#*]=[Gm֮[GhݘECZTn*|uħknN2{yA8J=jC">8Z 6qJh BиY;;(t햴xwSf4?tmH Jk%*#90Zkw0ݍm~V \J"amK0KL&robY,=Lʭ=BB㏞Ri%s:/"sLgPi/˜@ 3!6ċ;j0!$=8;1/Re"yA̼T%A)(,JNR*O fT_I]*b`+<͆ $ ,ÁGdWM[,4RoTvdiNiiHhdiiDy1.&N'Hީ6?5eҫ j>KrҲʘ&9%Z9T)[`*{` Y] V$DZTWctUKX.Y9d. Tye5E$p4# v-(̷.VņUmQ5̇:884j'= ɚX{*aIC2ݦYAԢhܛ!QLD\3V2W)}h CzfJ#I֐ؖ˹~zTYB}F+6hFk, *D@7@1*vNԮe8>/P$!vSw?nigPbkS&cJ QJb90÷u܃%f[)"LSY>~Ƹך~/<곏n>~p^߄ k/~]W#EV \M.;RdMQT4wzcYEgMGc +m, 44]'V:\3?,_z4,nZk Ց){v?P䯪t,kM(l:R]Z;񑄅<~OËn)zEϦj }g* /Rs>=yv-0|ӧo5X~𛊸g6Fy; ?]Q,t@#xs-bN,p./p{gYӻk|n1^ryeԝ=%}^*~[>r)Wtl&}oMQ/ƜZuߩÉE yp?n˛w[h}'P[z7nZht6z'l~dOu˃{'ιbXoʻm|f#V[?臔 >Xs5TU*ZxS~[T⮭W;=9ce<*=]PW>>[tM^sHBacJWlS/o _p&ԞMeڏ9'y;wƓg?(^{vGk2g[-l<ZȘ_jR[ ZNӿe?]{$S\ȏ|Ѹ7,EsӶzv_k j֡JyHW|UÇĥĖE60Wy./7~{orhɜ/T5+XXZtt˩mIQT:JeڄeiҥE4nG蕬ɉK8pⲛr~+3n w[?)%$&x#߿L>Omt;D76:U+Dn(E_bwI/nιaY/Ni޻oܼX k0q薔ڽ7Zml4. 6;w~RvD5|)\3w@i⩡'u* 3K.pyMeʒoJUZJEeѿ^jLؖ<56fz0*yGӕOşyiQKJN\3Y07U&Odڍ#@Ν^-[_>dWqES{w~}>+>\7X[1@|5 A G[@jͮ@"ҏ,_`KE;/Ԭ |q[xU0xWڷuM[wzܞ_Sے77L˚Ҳ%=vmq%n))kwvVՔ߱ue3O=QBƝmfR?靪S8rϫ~K]8!O~vl}asޏa]qw^W]صq=vn=K6M.+++KLPsȢ$nNh}' 4"?+Up>p=/+^\I|u=?Ƴu{}ԵVw .}QQnעWwҺ{2 ?$\|@߅Y++qN"#1ƥǶό>)u$Z mnɾ_1ǜrYG./*·G=kIM[-[v^tqw\".ؾp^O "Bjhfdb`ޅIqVu(.<)NVƩxո eB >b  j7 >]!X ^[w}B?z)bַ{_[s65Y^w~ ZK~EcVBCdž"-pE]N`/.X.rr~d[\n_Vˋ\_\.]uct P 3mu[G?wNWV^,I(iT|Ty sY!sFH*wyZ@T"U|TBT!y՟NW=]^ݟNJ͞\G梤QHa: OApv}?~qa}]=^z57t|e_?0pG^g|?HsN"~/p-jRP9Nd(}E鈠 aSuC"j-t/ek) ~(zr/g"_£괘٭HHu;rc-mND4\ 1 aQ>O& {ee1Xa5^㼤^(F)/>䨓2Ge>250/l^:IQ=cpsQv3Xf]$=QTf'H2zШթ*uT Bs:J'W^tԄz5`F=.VyZT ˸"z:T͠AUÄ5mD8AE㬢WP/S ֜|g{?uZn-> ~զFj:%|t(:<]2=DiJsIRpRb(bJZG6rQ%\Y]K,jwn*#jg}o?U~b~Jړ^E"i1Džg!̷̧E"aju3b^܁E%gp.*igRw1(GBP!NUҕ6zVrz/JB&{)vU0%: དྷhF'ՎL?\થ\ y7^({O! gQ8җ `P-\P/Lżw%3Aat,=oW:Z& Jۜd$3%!;ңې Gf:U"AM-G̨BilWhBl+hIh龄:]s=uw<)kWktbyKew8lZ2 ?`˧RyRʣ2y۷"9\wy:*_Q5G>6}5xO`jx NO*> qKFX }HHǢ=tSB)෧p)\LIn+5̡?̐,`)iut/̛_."[|?P6#"?7H]~X:z1j}8L觎󉈘)٢G^.zƔbzV}L~:YL_^+YbԕN6y~ӆY3w_(}͹3N:;+ad9avSN=TFSO :`=)$T̪bK| `ۘ' xXq6fRa& T2 y8xZ_jNnn59GX2 /BJ?Q̓"AJğ"yJ5?8?'.^ 1Oja*Hi, ( &[m iO`B@ٖ-iægC`pj>4Gj98P ҊM-( Ri5Ls(59]%i_rDܵڲKkHtA=~^HM,H֓?\Ѹ}~G(nx'~DpCnvl:?VpRm+~$pRQ!(?ѯ/!z?ۇb2~ ;iOO0B,y쿸:g5,xz绉ua/Qg4t2UcNh4(MKiFըܞKВ hg>L\1j6%4AM蘉)awj.CqE%XIЀ[%N4)9SІd,3[E4-*}.RsE I j;[ si`uqš|t ̨d5v^5eXm({ 56( gKS7!XLx?.S?>8gq#"99ˬ%cbsOH9]|ghpE&?"ꋂ:¶8uHuIfhe= W6-^٤'7$+ˢs->ZĚ}"bD"or5G.)3ϒx wH9k)(+u+L{%˰^cqMMk-nv=S4t_3Ѭ/|J0u"]&z=>g޶M|ִ ~C%E1DqDpr Dp>Ǿy9zݛCm>kCj*/?|2򸐯d1&[ b'+E*b!*LC!Tn}Jo襪q%.JĜUhdn̩gS%d$y%I0)0?IL@5׋/sN.L>;9Ԏ;uڅvAhM/,Fbm*[dlM MJF伓 vgODP~4*aK'J>+qȰciu\:lu%EutOWC҃&EMGZK׏9O1@~િEu֟gԟdd+dK4ԏwHv:^VxBo*cӃ:NJCӭԴt, =t"UHȟi~ռdӓL Wr~Vs|[>a됒Ow$;cٟij[gls ?V4>}.A}"Vֵ-Ed E⁘2,[R|i'X$Y*I(mҋ1}-QFхR;Fy }ҬRcEbvv-$q(M| <O8OvN~Ξ6Ҷ%m@cV~a z.x(s,>jT`x@ڱpC '4ڳFsA%FhEڟ~@h=VCɩ(4UbGmz] j񋣄ӓFʥ%T8?tG:Z@.]p 1>X?V" I 4^KVq]Hۊ U؛.éG(vN<~eӅ-5--=x /r="'cP T3SۢJ⦑V4Q4ѥ|/\L<ԥ( (M8oRZhDE g}EżњŅ85Y!8)QNOI#Z1)`~Wc<)Cm?M4~8}it?w+ůW.ϔ>d/?u:reva[NE-LSH3O8gk}RE^jE:&j,UH%RC h6-I9_u?ېV %EYg&ѱIj4Ua,?f14FT}yY8 )[O˽_!ɪu:b1{ce;Fhvyftwto<,oe{N se9]1Mbnx^aq]̩-.,y-$νUZS˨#& 0(ib~(K{ )軵r/Skx^TwXbwke׽i}Lq r6T-=ٻ;cw{R.p|9yro],*钯{ׁ7BC  .CQDb0X1>}*lrH `Vuj[o30l Npeˆ^ŵP梛6e(N¢Kq%U*؀YX+>?2_Hu)pE`4?ٜL jڤhSZiCט|_uYY]J߀, pjv{z9z=Jc((e6` a0 %'(Em ȼ\h˗mmPYa|d 7*ZfK.idq IJ4ܻ%tREEZIJa兏  )SE^a^ygCӪu6 XL,Q/aer0i퀻z>m-bcpa5M$*Ev|nv<6DtM>5;I[41tR-@L lLp{H#XZ`}[ǿ+n% ]wHMi:=RޒZ' [SFf>crI2Nb΂W -,@ע4`ĠIR f,uŠ¿M[u 9+jK3u BY(-"%6w|ޗ8:&u%˚uo4 :;b$كn%p (*lPe5 dhYZWaջ%łn0S6=4U=J-n& e-CIQ-Q4@A+ܽƥ|ttD?r<FEy $&/:01PL>Y,#(Bilr#dJ8^=?+7͇69qɚj!6|a)GL^C%W!Gc}fHGW~)Yab1B&VqkܬFMyOr>|yEεv\5bDGjdWEYͽi6gA=ś{@IvGVThd6fvߗ`@CK¾ntر63]B^lعb0'>0B7Pk Z8(- f5<`3Ou9As)Vћ;BQ0n3-C`vQY2n˼wyUmT["Z5'>~8ܾQ`YMY Y- >O }^B`Ś ] o4N <`.%h%Vh`-bC\z)Q.bFUE?Mm(<9#vnPRި#%MZ)/̊ r18ygOi^:E+LHK˰W1h ~Ri7WPFe/ŖV+rTaHY4 >C_qZMw92`\ LmQ]T7=rr IK@}c"YuެKK?h9M@5[IU:Gu zKǒaFT3BokIj \)EbK +wR79L`slo:ͶP.z:D.u52*,fgT3]/[i -ꑄA!5HwtS*hg4a&(!aٮ|Jǝ& lZMy KWD- $j;BMņŰe%nU8D{Cjq[ ,LcE# pUQbꘕ.flb}`\?e.ҳ8f3h60n- )81jg& ;}TIHsXqQiQsu5Xޱ v{3 "ng NFXq8K[|Rx:mB 8ofrKjjrqb>x]mlX!;Dm-Syy [|^)#&d;fGʽ`&&(WA{dȦ0.ElBe 5ٍłles QF]X~]vA쏙.sSeaKFsa Ht4lƻPPlA+Usf31\Sg$7x`I\3s-c*0*_o߽?W ˈ~݇͛o7_/u[=4 D6 .Q3ྪe kaJ-CiEؠxSDH͑D}.D5=q& W:djw? rIӐPGFHF%B:RdJQGKÈ  {i4N4 H2# %xDZT-j" EC,syd`Tx&;<ĆcDPwC)bp"LwQro #K̈h ݘ&;Ho\ ( ORmv4 G0r=@%;n$=\tTN\cl$TٌA%;j>NP7)gH۷%00@D옊PqXUԊoY2jə 4 [=;.ֈcBTĦ\]C 9()P'Ow\8\1Ƴj+o W,CEa8ֳg-ˬq[&'́ =ceZ3SC1% xl``Q`kƭ lӳNRQyX$МfbwuL7A?4SS~=L0ʠ)$׀a;LCpT$YYCUt-R#vF1AŃ'D^_'-|VYBsQk9Xu^}yj?gILtKER*)u.;?`R?S~gnܔYXMl΢flp?p #G@}9j,>JmAKlF7S3ˍ+S$h'Ӈ#nd@howpP|8:\|\5ٸ6% m-Dp`f;ՙ9"Phc7ǩ#~Ac" >/vz(SW=Pp/|a F K~j` .ˊ{h H#&~FH N}=QsjfD q\UE.{ ̉1qOH_7O4,8 ]7PG`;,聳Ɍ*1%vѡ̽7YPpn0KB[J1!_k3<[_"j}0Od,aգWVefЩI`WCgb#3XK{v} b&0gqj-AnŋG"weXMLhf'Sse0B2kFfhŸO&Oh-t11y0"$ag5Tx0P fI$4M4ĝi :ɏL_-}ҏQ{be44 >rAn .AR=uC+c-AAd̟e,'(&'Md!"%^ͳ'r$F49¤yrM.Ug$q{;Ds绨{ӭ*S5nȦۧɖe2В,Z45PhF#^+t\րT!p\l2:#/}Hb>+gL8@Uzy`^UȨ}z%*ugV<}/ n є +%SD取>JScp(b i@QBeTwl96b8M*RN[J\@vԜ`TV3[eU2/jkZ3TP WJE2~h″QX($x4*'p#`vqbdF˲$$CFj(۽c@ S&;6aMӱ_}E=Yfe t:na+t5ufiOD=IW m'Ya26}!?la8}sx.93 E0:PI:ciR3As-NJ+&j$\Y=DIJ'XLc~q]YPY^!< !DϦ2yY6Qj0[dwJqҼYwh$J\!}3 ]oĨgI$ ۝ -fϬd.rK\V ºZ%Se-ϸȮfDFf!N**vQX'º6h*PC+KA\O& h#3@ ds2b0m3Q,?ǞRPJLLC`B ,lAߏ Dm\BD:eMɾQhPSڽy1*^2gLqfqT0+*Km@ blࢍRrt"X$qRq]]2x7d 4_j]m2E56s'z %^(L-4ꬪ%Ѥ;>+|B#M&,)=c@MHXVfѤ]=~TTH*A[;rmK‰h.k=Z GmTtq&CmmZt\>0SBƲ KEpi;Qο0 s?Lŭɪf'Y-/j dy";N}~q<"Z0@pst3.3` Нz0|I.̫:@H}:%̐>8 3-՘ `y5:`Z\Gm޳Znf|OS@$xG'Ƭ]R3}Kt\f=E78w^n;Rx!'/5-%S'}.UvHFFĩL"0~DZU:x1m 6ӑ01f+x(QmaC⎡8p Cn ARq<FE$^LgͫYJ{B*0?Ԟ>j \`,PUD2sΩ  = k(xӤw@47ʤE ԮFضDΑ [GM XWmzJu'ڣ:B ӡu!Uj>br &ḓJ2ȀvxlQ[>$݄war?s:X_U|-9: `stލ͔:vB:NFAh4dt]LjE*f`MQalXt͒ -g2 J~ZW]GV`nO2LhI҂i`RINx]N;;̸u^L3h r<\4SCJ1@u*@s~6h4 #QAƜ~X'BÄ8EvscݍS,ɽ=Q]2/:ff.:R_MYӰ_K.vvRI/' B@|lm,fк݌a^+$C⽃>X' .F;x(Q7bzm E7 ѷ+[ 'y"tZy@~bcSZC!>Ov1#;H% f~yP7{>00l_тZ2{9|Q4La1T!\Q*Z koŌjGF#Y՝+ h1{~ƨYJaIqk` +d&v?> j4ec}`E`R]wAji0mי1Aܥ @SK}DѬ K bt)t(#ڗ, Ⱦ9 ۧor&.]nqTS  v( n'-vEsEk7`RigJ ]Y6h7C6=ܲǚh{RO { s-*]{c˝"c#w)x/#B+@0n1Y aXҼʖcC+AT͇<4-ː %l;iR֡U@KDzHN36&F6S12%hBׯDU,M1iL/&:^A2p6 %=Pou40 VO{Cg` d;Ms13fvU [V{$gbX V <{0$?Ь1##dh_.5rZK@!iBԮU\Cx G4>0C'3`)9r{[` Gfjuߤz: (G7Ԫi%ʖ͏%94^\2kTe/b H :0rꬶA6w6]"e~Q'#JA7`EWYz'V_z.' Yo2PSt-vUH^݉'mz$fY"z;Yyv{#W;M3icMԏ!GLV}M< p))ŝ8\#5U BP|Z@1z&."+iylm>t4cŃvP#,Wt+F|X !)`i /rh{e$ Poԫ9\ dg][ܘ Mś{, :j1ų=yUL,΋>/@~, gF` F %]>v͊RӋuQN3#P>":p{>łofBl4p2_WY{:f@b2Ś*c:kF$NU`HD7X[zzn6%`Jr,cԽM]b"oS@GںLz)z'cs*%b!`D2(+E ܽ&t\ws;nz1vX^E lt7Jd۴ƞ*<fav@{ѮsMk`y6MS2Aи^׶`P Vr%%FTVnW +L FlM`^FW)j.H]⪢P:nIYN𞹕=;JeXa-C޹1vkHt$ojDFӕ5 Tэ|" q*e8齬2!դg{zQEy6{Co>+1Ll:\tr/PCtnϓ."b<Sbso6VI^6k^7P`.7]d2v'>? `qۑ:;;G,lJzg (+GbdoH33.8謊K:%s b.@bS[k xӈ>s>kooTA! \fy;L"\n> B%^LFd|Ze}:5oB !Pvi +7:OvUָ7d¡י DfT1F$ `ڼ_-LufU'Z5Qzv*aUȬ p2-zۮwv1Ѓw9`%hU^hxĶ{f P[" 68>wv&+lf%@{w' vo6a9&&KGͺ6M5ZjaHD/fZ IdPB뉈%/O8$y/wv޻Ke7jeȫD~jnAM tN[pְ.!^K YTv#.RMzvh0P6//9gBO`jít To2IJN16S LP7_w 0r'(RC&hJX\&(6VuӹAzlRm2[_p]=e` 7%dMV< ݤ4 )V[l!`֩E[:!^(U%@%ĻLm2[YqFl]׺/&*J/`A+nE_XByPmDo1ϒ  mkPY9 q2] |xpj>Д"51zO6 )JSϰvcBi7m2L$`Ivd0:KM|TD 0ɿVO cPLF&iuIY.q&{^!ail:j{Gyr2IBna|۲wc ^a/c`gakc*Z)LZ(JI7@p-3ùeŗ,?<_ x:hjTыx }@)S ;tuMv8@J@7EZ1VdcUfjC%_b)vqLV1)#c޺Fj8C;-yIYk,&@Y6Iy5N$A^AB;,A-! ^l z yN5Yj1t*VKHa- #l=Bk}r^h {7z-B.|,oܪ"pY@-R!1XL-B$4ⱥіӹePWzÉ#I|R4oRV*-[mZ5 5y͡p<ŵ`@Fǵ^lŘI"K[Xo1.s*nbl̻4ZxؔB Vkm(WNQ$G/E&lpW%:Q-c ԾWQ TMТt1;@=-wҀ}qA~\aSxbTEp<[KfۼJa}}&YzUlmh[(6Wm;'3*%Xqi=J?lXbR'zj^ӓ^H`d_bf C:7#ɻfR 5+=XHyPAyWHv܊|Eыz`sN^^ZV%0-{YwcR"dϬt ! MT/qϬU+1 D"iI0pR,a˦Kӗu VgnqHÙ]ǃ}rb?'<`@FޅX -v8b?4EA*~(ߦh##IXOFYRNJ6nv۳W"h,;% Eppjƭ>QC Kʤ%z}v aӅZdB;rQ8t7tt B(`,ʓr\R-s K v0WR@)/"@3un3Hlqz\M`nVp~>xIwVBb ,x[=f6txE19-Km dy { 윦ίE=qQ{՛K{/zL+Qs&Ot*ςYBg lc0R툏cF|p/OO &r y0YV0o 5apȒB'Jݭu¾<܊nm{dlc 7~te z;f:,njjB<_aדe'WȄ`dl (.nU*# v>!qjXɻ+Z!섶XܼMWxW3 0L`/!d)NdYau=T*6Ьv.OJ di!P1sԸhii7WgX;_aa_w2X9}L!𢺓Tlv/dn[wrK \`,q'8FLvڡn{Scle4<3*!#0GdFh<8Ȫ]S?w.i 0<$݀t5Ip?ũB͌8%bZA&}v޸‘?\5tD ,tTr mt: 9A(3,4 'X>%/P=\Љ?{4s231_FbY@MR `҆dTO @A*~j^^ ܘZb( N)PN sIr# e 7,p٢+UoR{I0k!6>˒ {;^홋;=JE<7ʎlG϶ uPz+%kJpUrJWN*@h c*f`7l"3QB@B3t- Ȏ5IF2mD]U;t!M'k̦hKoE|xcf*^@LـvgtspxYC%!>%/tt}ƔSm4F8ɻrxvӦ $J O))$KN CL X;Cinw_P[n^)[E@{d7iG4s]^ 6gL =l,Y7؜pP.Uwik1۪BF&L,SSsw,+sÜ&(4f"iyWr?#$2\W<tfv#2R@ _}7,ܬs-5S>TZGOM>(o'kš#˔a݄|@,X S#Y NO\+>R?TO#/,kp&{Q׭Btf@JN7!'EOōŠhZSb9L&Me&%/; ]cmnjKg#%vwBhҡ te&GYrazD^6E9ػgH^|K-H3oRFa۹lV=dP>6EfvIkM,"ɖ7pj ָ[$B.8.oo Ӱ gV"z&kQ&2 ۔'Skf]EFL:WߍƁ[&N7m )k`ݪаpuV@Kc+]1T!q +%"BlF #^ľuڼcr6(Ȫe&ɨrZݦ+P g$ -9xd$o%+:Hބ˶Ț71+Q!pTiULЀ{.xQ4*C,."cMJ#|ix~[btdH>RS5z&D"R [9t^RGY"Bi ̫zo H(ђx$v}Zɵ Ե*3 Vz:H&<;O3ʔJ;";atyo- :UN,c*YlXGe㙻e`X+F]Ks FD`ݬipU׭@* eI!]b$sr;1%3շ<[SuJb֓,ZnjRk6ϵESVO!A23*Ͻ2[@qWwP "Y%7m7N%b-Rs*-+$S瞧놭VPOXl8ﴗlUi4Sm8&SAjI9Y® /_![4%?_~+/VFًOopbp]s~-'!n~Mxy7YyVtGdQ]n)n = p.cVUnd5tѧUW.VDI;I7/3j%@E} =YL É= 2RؔXE.~ A aUK ȞJ8-ёB m/iz2{PwhY5te>KmsE` tc qeېuy~R[ݖF3'pqvg 6T=MԼKy pT$pȢa%Y̛l3[ksW,P(bW z7O"ձߎΎ߈"]Ŏ8vEujntz,2vn8սvє5*hWXl2a3·o+{ޚ9WCf\$CѭRvv4UX~YОߌ~M= ?l|nJ[h͗HE[PuqE̺?NYRČ|fha`=o6C`v0 [ROܳT1Ygo :4ŻZYh{jۍAәH,Yi +wĩ}xZx$tFS{;K 橇Y5idD#Y]u2)wb^F #&5E# FWnK#IZZHA>5(Zf8/#@1=K !|:'ލTFwmʐiLV(} .5, ~Y+5u) ꁸC{tXJ%eZZ0/Zrk%?XGyǴ` -Uy^tB7"l[9ݼ 9^[.%4'SL( hx iתoH "Sg`%xm I[cWWzp^UY͠tk/ծh_qUY-N n+:[Ho%HGI!>׃yd%I ϼC ;gp]Zj]Y(+-.MJwS6)v)[}8rpdWE3W[5fXVW5OHqO" WI`}D y lF C>l߶*_;귌jld*רlJ˱ΐbx S)d7EA ց>ڙCZk1|)i\ŨsWT!1cO[i3+۷/N=͖2o~|ˉTwUUb@:kW_W#l,R4xĥ\+x# +ίqs;BwGauDxK` ?evnJ`#+-n/![Sj^zЬb}'nס6`ⷬF&l5v_˧I;VM tn`vOjz=Y ܎W+Q!$-f;Ԗ )KP=#vRq{ SLHkg݌ح,Pdž9B2`ջ΋gMhDsǏmgsף!qJ-By &Ĥ[ACľ,œX<(C+Ҹ!VnPԀ[ήI0PKLh׍%ތHp*˨qx?=Ǖ~$=Z0~fNS*'Mzfݽo/JLun|w1v/ ^yiJ->7+vwwil2] Ɵ!d}WVH p\ jͻl΃w`y@B=eAlJݒ7ltfe4axbݞ9;RoFC׹0(5TØiA m-D%I|4GpSoMjf/N(OP]SvIV?"Rm%t[!E ̼7j/xk+zTo!m1j}mvRoʏ߁Z4$3yU$֍BhHNn)u4X cp#vhHpKϥHƻFGB>*ɏn;7J +L NRRI*Ks\]?HKz!X/VB6@$Ū}vյ[*[;r 8aZ9v:I2rZVi U1m4x4y.kKE"}72fA/-(ӏKn#r y?ʯ:sQWG kK! Q.C բr뷪/tk\XЯUmD \ߋhhŰ.$hh13T h;#4e>B$Q ?Urµ1o  $ HV91@TTNTKkf ps j)'E-yk7*7mF?~ h+dn+nE:8 ӛ!+ c7ІQMi+o0`\ΰ i}[\c@rFSr Vܤ-߬/#1tc;# C 4h99NLWUsk#h{[mSn#ZzH2 xeУ|JEOc8j؏gJ `ĸwҩjC]3%2]WP`rH]i*T85 =a%uq'读-LmՖS=M~:noM@!sH [gV[v-v[1Y|[@u'D 6g4K]5˥ƒP`0k@r8w@/"[Iw eźBWj1}%o ٣]B\ۯ}HBF<ۘJC#iߊ {[37 T.+("-tf颡rt t1h*JMyп8 TFjпȧW$) a)"-O-ȼS(|?w*H|%AZ#AVnQg/~Ax5G&Cn0[7 NrQ/e!sSFɖRl[B.qS {ctKq]gjӋ;}6n荠|7"w li&7;Cr)C?tXqud%H tv:LσW. mgOa'p##&7{%@B$}PM<->7W0"KR̠[aa)|kaG¬!X +n~[9ree0j"OSRz|< n~D[9qsB7IuI`СK$~R;S[%&rEFEp7Ձ9}ٍaݢ)De,#Wd"!y; [gC.MH@v& %sk!iE3C4=4k#Lm5:-@VA&6Z(J)7w^epwÈʭ75 FYug0`sy|wԋBfV^",[GfQDD'c翟tmͼ}`'veK1+Wn 7yd wPk M72CUz# Ջ " !Mh7(e/Y>N\_h9)ݪ8+~ym>![twkSA֢Fj~5P4M)6fwZջyq6>DzBJZo(BR¯h[EUw.V trttԙUUUQؓ5{zt)lo:&eEv)4 0]!|zgnHnjƀPh7H ǪtgBhPRnw^B)'kN+ 5tB%dStiNB)PԿz`owAk9nV:oapa`6LZ̛EAǾ].k銫3DZ|,Pp/\d{?sE&Y&&R+x,k͙9*}#UY:c$xN2t2Y'9<~4ZQ'J둤w?ӓpE#0h&z!MS3ڐ&R"n jpHo]UEbk{nX˒g{+я DO>%zwm1.KoiL-* 1yp6R]ƒcLv3mƼuRc1x9W:U) 1nOFI=.w)&n&J}<قxw߁T d%_qנdV}7Khy3 d쮧0v3#l]2-*uk,J 32TMm#戺=-믳12MRʰvbPQJf :0791ѼIEȝn J.qT,~H  ߵBzA&*3 5 7Ңp`f 4-d 3S&}:`Q!V/⊚y Qֈ}y (~}F^a(:zn˦\8\H#JwDVQNfR?2oaAi9=އT X,~;=}rLى7HI<=:۞aϑ~{[|vO!g|lt@t??Ū:ոԆ~ Ƿky-ݯR7P8!>vbJb:)~.Զx=ȹnRM͵%BBn.w3G ՘L"M^Vu̡\H;9SdUG1hw*TȬzfH~ (%Eյz\Ϟhq]AN]SOc,cN5j7w {=CG\m) eӜݐw]7<m $}JlJ:v3+wTkUao`\*:~|"ՀNC@,#}i\nM+7xQ^FnxǺ?Xؓ,i_AA !$s;o: -4.mұ^wB,u 7o?F+اԗ8Lt*5ZCjzd0]Zu9I–9DqՂGzpN7љT[t^fgEܒ\SǏX;)fއݏ-usyVWt: f|OvweT+[Op-*8U(\>Ӄ^3:"O&yr'avRi*ƈAO3Y_"-f9) ~zi 2T7AXǸ߁<$*%Z:f$-1dF+WKo#ϜFeVǓ7Pi!UO崪ZX&Sh1.F]mJj*.yQ.BwPNGֆMdsm{^_<wRB}heT jPC3 i"EP5ibQL-gPtg+ۈ[R[Fy3EVk 6*{~yf$Z yJ'\ߴOC&fm ! abHy[H+=<I3vj-=ژ65<݌ qy3H-ʟͣ0׋[Ҡ?o87 )sj펽hyfR]B5ƤQ?o-Q=t#P~iM~|h[70(?+'n3ګ%䮛|"5Ẉjb^8.̶ oO0 כ3?u ,3eV Fi̶e7d]2 .4s^[ 3=26M޼_G1B1}Ե8*i,MƵ߷2mV¿ [ke ڵt>FiRB3nJƌ8g@q\j<{,Bl6q.80.-DTM5-O8s)z/'ff-^6^O7v)r]{57g6AY:q\NTv' DT3~E򻑳KXjXffw(Dǭp/Vï$S̝.5h,کV-qwi|\3cί1RhnqsOVᴻƁyᛙ1=w jtmVqw4  `[9.mXOj*1lsC Pe_`usif=NcZ=}n\17O{녻I街j2#KF͙qge^.ᵾk%kľcW1\!nna+S+v<0y_nf+ݖ`¥Xm.$9k{W_8ŇK;Huz5mm:B+ *f^S;]?\5㏥Y5Y}ߌwbLUϵOy\ ԏS/z[lײbؑpɟJo n2%KS08TMӻ*;€fnf47ZԌVq[or<6.M45nq #x0M(M&cf9ֳfv\-*LZ֍0nkمCm5cPwvKFb6=dȆo?}T3Sq[јqm9n-VN͎ts%㗇Kc>^O8YtiK3VۥnN g?ldL:"3' Iaf~7eJI1ig8)/!!ZRܘ.6:wQ(Cqc.^BFU (SOf7\N[׎xa(mfeZ7\sciʺ&9K; .K;+KKn+,7ǚ^couij.mʼժlF.?~yaԇ;8s@8r#%h7,$.$wDղaݼ1lFDQ@r0+R}JK P.Y3{){L!d&e#FyS#7a{ =~mwl)6M8kx{l@cWsSFo~lM.T؋M؊R@8v}O險#W+0ScT+VucN؄zQw,U#؟ U?}0ww:佶1ů; %ҐswXpCai&YFq$=2XY>6/##l&D=icLB(#bs]ignsLov))/`dځIS[`FXpچTقq9 eFn7:"e*y)[ }T.&u Mv$Ӫnd]ŒĹ/^s׾'@,Fi=o2fu!Udw^\v`me7fW2coz.{Q9LVjIbhM3ЋkhRèvRL$jLNao:-ί};RV•Ľ&o0&F cTiXdo,t#5Zyr Ukh.xNΖ#}\!lTXf{z2=ι?  agϵu}k3C9̮`ȐO|7*9CK!H#xzc z<4LAE٫fT]V6s(w0o=U"m?@7< 6wc,@S;\ i1x&(FCF7=2˥i8[h|+G׍+# {fdQ罦m:2[ `objq/00i۰żnʼnJ3}zyNC^4W|W<445O2^)q=oՖcGh3FфgMP3N_[\7: >Br:Ɂi\<˷忏AiS>D7FC4āD[2f޸tPR]—&Yy8NoZq<-moZ|Zс Ŷu_NA=ƀ`_{3..)qTAWP.En?Q~.ClEsl:r*^އј}+2>@OKw)'II-d(hX&Ҕn.kK+v7mM{L+VPtXauWx[w챦<;`u)Su^Va.a5-2EeЧ{ٻWcʄ2$ yj/cbg`3+v͇'-[ԌJbđmKc[V!>p5Wy->#_ $ƨ2?V~x.˃̣G5G.o/$qyئQ7{ު8O:Ucx>ǃx?ǣ 8: ' ypX zpt07yWU4-U0fT1>_ غBg3 kKSyܥ;q8'ΔpR=j<~8}[6L'͎kv:#̾<ٷ8.evZ{Z<$!y1zˎ11;F(o#c {v#c}1?FCqxN3ǜc~K9f]))9/3.;Ruvs֤} v%1e,aL\b6thYX ٸF[L.]k׫ c@5Yꅱ }k8J|\`*j~TEkeK2ɑ8f 0JA,W5::P.F3;V3Ocf zq[FN4㨞* xN^A:pU,<R86ly:O&Z2`5짪m'P^e5'4nCs6n^8aUs::0ٹݞ/ `/snPR 61O%g2&X*d+-};O^9@@$l6 K{?pW'vxˋ7>Hԅ׺΢9ɕ"t$̓?y,ͽ>S,z!>&vDU$g'b|㄂bk5YBNP6J!Ew.<61cU=|vɇ'Ԑ/d47,m/ש-vQ(djDs2SSQ4_2,~R>A*^ ~2d@YsP2'X қ"hx.+Oi]sȞR8" :kƮMB\zgO%"IV)}qȬiFw6 l ZmU xxb A/2'EXDbF%N[MIëP-g7TFWL!J_ _6R\R ݰY) h޴ਆȳx`|ȷw(Q;9ቍzkm{U*% ">pHCAdiL‚ȆNǸv5ʘqCwJ¥G vۑ"u!h> Mj8l(ɲ_%>Dfܴ|łNqvr]e7*Ӷ\ݍd-N"ln@|h<`[Lf`R.&2㭞Lݗ<`],#˃.vAO䋱F^T/]G^%%l3n+X6͡ Iw 48:8d-Q#iUg[Ň  y14iXRp:r&=E*yA~Dۜҫ牾 Mas$ ıi3R`"4j #J9Yn,}pu'-e$,>BUę^ۘXf_ ʈ}"XwCl![/Fv75}15>t$kQ"KU1 Ҵ!^:ǥd5PH>ix..Ю[EP55`qt9SnB3]I`N@LST~=W<Ͻjw &JLWd>(kUnSRsRt5j& n)cFJ.:j~E|##ktjew`85mc|Wl'=! g2n҄#H@frew B~?b&-&5 Rfm*儛= #v6OXF`w2Tm]̦jmLY;tBu./{XP/+Ji̕8uBK7rYT7b\BM9{6Fbu<& #>1, He`Xb2L r5֝c:JOX >"`mK{ wsi/ۘVgLPH7VX;6c&WmpX%6[ɍN"І$ajj3]Z nk-v-O0ix (X\M AɣVd%K0eė|ʏ_/%0)b.!1E! g$Kiߪhow/HdMN"SYdl?2^ OfY纈tF*bXuiR!5Oש3 DW. 4Juz'1QY'h+x}]vhWCB'wあ͗Qu~퓃RKDw`'t}gU4gU!yit$Ӳt ʴ$ lA$jjd.F 1G|M7hBJ`f6ZK i_m#?"ԲpP%kҖ2dG)pW c ky~ Fë!st%!x ͩܤ\z99`4t!2IZ.$#H=<`~^wsS+6A : Ek(h6p^hM1Ir 6[o$VwRto/{ [Ww+h`+ȾO2W嵪a5ddeŒrWQsNWlSa Wv)efkD1DТzm+q[^yMIڸ;bQt/_[ګ vw_ܬLo宦x/z~KcE3P8[|ݤkkff$޶A5e!i xZ~3_WxT8YWvwj]K(? |D Onf,YtO=BiRA›7ntw@: !Bh,!̞$AT m(zU#NUO~ B5q[˕hsTuR8@/ǒd^Gbs[E:*vE9[7F(OnjTm4[r^E0Cb 걦L1]W(kF @N(aܩ䟋X0mE+[REKTUdXDݚѼE9|F]x@M;MJH;۔UhVEbx &u_W R\vro|a=63fBNBI+ X4 2/%j.>֘A07k޷(M<-+ lQ[*hOlY(+"u9d`Ѵ3>ү,ó@3˱qZj}jɳg.Ls|.`J ږipYBQkpiKPq4BpQ lIJr@Vj>8 8x*Ӎ%E/&aLa>}" URFU޹uiʷ~`$z]1fYC6N>dLe M]pڲl*CC9'W`tN?XUfk̪uWHPR9]]V^6<)cKsff[qk,#1swE7(Pֹ8&׍ xmS}sX(:M}'*6kP\WѫOZ?`GC&o~pmnP gMXQ H5&+c@TjMHH9%F^xnjQ-6A P'¦IJC1eqM'#{K&d!D!1ur uпK$;0 7杸.CrRѱJyx쇃64RpL]J ui.-ljmcq!L7,XsxT `՞ZhJW1:Br֢l`2^#{loV~ƿKQ[J'ϯ ^U4b [jXTG(lmG/#gGj#'WzE1&F zTC,'7}K 0ʷX視q-P5 vIMUQ.Yt׉t*\C]ټYUNKtE#y%nN07Y@,'^|#gl^\* y ]} E7 Ί1&d?-˴Kk_e%țgؾ`@#``O {e13Φ7#ݍi=@?yL+vdg(!3,bt7q Wm: h&@JUQuQ煢f`ߒ2#"N?R@aPE%uXE_l@[Wta^Eqbubw& cj܆/˫nQdZ3(T?Iཏc=gc3";])-@o*hnyI:BY~(_CYvP]@@a3f*'w~e xmc0;sW3h.gwE!Jf(OuD~OlGӨ;fw$Ikbȁri`3*#Mr\I=,Ax8z'2#< O#Kg|>yGFrp|| x#_l~`AGn>L#k/?Sя~ d͟g*?juJGՂQ ᨛpTXxTc8+74zG툳Y\qиx8jgU69;*O GM~Q,rO9<([N2/01G'=vQA稞syy9*UNB'GM~QQ$tPZzPe:*8+==hBJSTGՃ.QC먶u:}=(Uzcd:fGųuQsAvT}{T;ɝtug5ݣFQOw{ (UfOrgڣYA;{T}P-B hm%/=q@ʓ. i;@~ҾCuPEPItXeXy-|:%9N*T9snN#9L#聟t28O#Ⱥz`h\GGD';8j':ۑ{w'ޑw=O#x4>OL3Ⱦ<25#kN"]qarx7}OyGF~'~"?܏#{id'*Q?5p%8*<<(#4 GŇ:QGAsAdzq8n5:jG口JIOA{SrT4yP?9 UWJ-'INQOA{SsTyҾ9tw:=EgPAQQ}Tt4z?:j%UP)*y c$WT5;E7TA͋ku| eKwM:l+BXuԶ:`*\]Gm؃fQ]]Xv6;ˠ=(Վ:lOmGuQ5/E[wT{P;*5}GExQeAAsxD<'Ϣ9~ӨzFO2E=/W^el-2Og΃Q*zT =I> RUUOJGM׳NQS?Tj{}}=>(>>uϚGPQ~|t>?U_Na?$+AA Iry 80r Xcr[ TO_'cuWJ8Gr|) xߚ]01(6[WխKnj k+2$0JnBtjSI!B04Z?ļcӸɖ7ɏKpzˤmTi"HwT&;g `9[&Vd&Ƭul5c>ڌ;!ڼH#3[t`tNMM6.bJVڼa|)9QPf} Uj˱|vPljTt4=enT):GlុLXmJgپ/c..9u^LoFF-{:w:IE*)p]JI$k#zKxxYuSf.ڨue5ѯsW[`V[ED nI^!YN33|T.XpgifVu(d' ɏo嫣 ޞcsHHHMrMf/?)#60eO]l2#+ eKyE*#)3Lyxum\+\P|/#r5%~PRSU%Je)(b=S5"F]KYZ5|Y7+N#{mbi_*gC*]wbAgē1AɺTfdlY}uXDڱc2+׷ĉZ191-`@1\'4v0G}̓g:Iܴۗ,MdžӖ;BeTyVu(Oo>$[ge{0z{6Qun$2Ì* ex׫IBMڍa~j 8nI4(Y*6*8C'Li a2DR+isMJ. tȘ]~iđdV?$֌x Q|꒐Z#&4LE`5/7(dDŏkZ䒚IMoXBhs}q̱VfC%V'Z+Nz-'q5ʩDl]_@[aE9vIHzK1LMC\KKy t]_j]7KY\*ϩB|<,KǮ34ri\{6\ ̖ypJ.Mg+Q2Xb!F\wl`*K ,KnJgqT]6ADH: ?^~6 תĮ+4\z`C|D)˻^C2jU`;;J|Jo_6 T;7=ļEn;%nܣ#q1#V}0NToB#>>?T,jfIg5̦D^ύ\QS⥕l0|uV6I\4@]+a7yX?Wi'rp,86~ ލ Y 82dzH(4]θ5G 8 e/F) 9Dq 5ƥ~Jh(w6ƉAd*?3Vvp 76 Q<9ut07OIj,AaGFoW!Q;7W)J@ JW Z e3E% f;P6'Ao=pꈎa ¥P^ĭԦ^'VHE sx!N|&Z|(CLa;mui|N{@/K;z%|+$%`;En`  {" ȨvIpI/Qv[T?:bVz()Y'࿿Bs ƢsKiҫ'}ֳI${T=>h>rjGݣFQ%AQM{Qg|>>$?(*?/uOGRQzKZoS8J"tإzD??:W7xFZ!&Iv at? Zdx)S8UcI1{uP܏" J7hBhsy^ɗ< ]X.vŔvi} <x浹ʧ-i*k31l!x znY,7Z\QƋFsPxh"132_>t 83:PX6RVy+O,EvZ-hfꬮ(W%`\?6c+Xa׍$ΒLo7$L4Sw؍TB$H OzRݝ8@#a\vWs.csf6*W(V,PWi|!-emm L,-rJ8/nx\Ź?2vI"1_ 9vHݘ1]\}_>+`xj<n[_ɒɮ0l[C&O%*| M3 `R䮷T2뺵+$*k!3gkgCN!W488@k~;ߴʗ%FBnf4EiܣOOw@N@M,s&T\Ώ1}Rft2ce[o|u=Cx%x].*d\@-qLuDz`B짂M5f D2E uk [:O? @jqGb^ֲ0.9V9V͡Szx݃#t+]3ut+9GGpdTb ZT'{0~>a} %K|\{F_$XXWtSZzF\Ǐ=m%ߴHˁ,CH<)cF/5NѫU}V4gB0mI_6s3Y.iY Jn2" jX]}5yN >r.PnWXqS;٨|{Q}Z:ŵE$ߧ75!΄nj H'\ ? E-G7ꘗ2bACX8(<,# pF|x`]%`M Y+KX |5o-ZYq`<5Ўw-ߜ/j#UЪrl;ZGy } QTBrpuc,x5/ ed'5FfzhdRt8'2cvD}=kq?9-mڔ]W>L1{|#C$DC0B?uOw嘇BY:dbR[A=8PHaw`z1Y"'4qߍV~Wtn)dyo[>`h,us)KcWCtyx<9ONFdk'f_ՠ+ p5#3i%S"~}+}B6 x'hSe9qoKT]/נIV1`'m }opyޏ4w|?~4Е)SSCcǮ^}=g,uJEJ3,[ ;, r(@iJrY ׸Rx-\<+/,W`8&Y]j50j@`q_J"r.Ir9T(K>FCY.C^HCŁZJ!~-6uXeV:0{C95qv7f3si[Q fe ^eܙf rP#j/Ģ"-;"ZF,(4@Q'B믉bGEGQQ)qv 7WmaY?XFǥ Iݸ}.x-H L$f"ds7Ѱ=LE`~a˖YB!@3 ׽8]?MA2 o!=6̾;) ídO)g 3)=;&`+AhGڨ Kv$a;RLbVw=StT"3xY+D s>h{WeR`^KQR&&Q܌p3c19bڱI-qA3&՘&C.hz&X.ݱEG L )0_$KR+GfH+5pD} zc_]ݻXo+Ji; YnM[SBR ]2mw)'IdQ'5UT ,j~0 xـ^cÄMU>`7XS%cqphvGsA:/kSKo:W-"}ڬyh@X%,_:>,/{#>}+f.9JCsLGW e5dSl5a34j aNj9".u͹,LWkw͆ys Gj9f]$ PjK(\d!b|QO E[EeXE,!5h{PfZ҇ %ؑ)mZV4qoV cKF/pqQOb|Ilcg`nfO!XjP?Ή}]G$#jxx]T#Y3ڱᮋ1l ˼; $Xwp𼔛Ӕ*Cˈ6AyR:8V5%.+۷p!?hfn yl^D51WS'JĦ;AY4̂ LJusܖ nj~K2-_|,ũ @:^T[8V!~X%bl/$Qknkz%j eBқ wѪWG)lQb( uz;JTȎe2gAgw$ۃ|Y  4w{;HEb{GY Q,"x>HGyƣQ( & QXK'Thk/xw`O 3Q(vS{^pWUFY334bx<0SdB %7"6CBԥ־ 0l%pvaêYmqJs!?o>x@ 2Er|K[' 3ƙpkl)m\D#mb$Uq7k)tM"cȼX3KBH!eX%C-x{3 8Bۘ\!N?a2o.bgbݤTbX3llPIo0yHr["\~yNÆzz[q;OGi)-hҀMo7b!lWSPiQRV&Ut|Xt!2'\*X~] ?\q$8 >D&R>sԜ!mK`Ap6 8.jzI_mtHх%N?4VElXq6*zH#ziw0NU2!~EYw1tDpH|;5:0[*B+-u}v7$ӫAs3i&DdߗwUMF7Vc.`<.Qc yjH_B\IץҶ 0zi"WS/zh`hf\Z;M;I))!9"g4$ݍ6s׏IsmZ2>eI\^K GhTHPL6&#PCcRٍR^^ZW`ğ'w"`n~eD«L5iTH?x[srnm ?dP^ de2Ԃخ α_Ωc V+ n?֛YHg3> Fh7b<ĂC't u֮}MMkP !Ku)ɸG_D|@-G,#nrbYt8^T·l9 #b@jWr# M8,]H=k[2+\E8/'z'+4h[AD2S󫋂kczkH´xE@1$S3vMp[@KĒaP޷No}Ilr>Mt͍lwtˊpC;^n<#"Tm吹ۚ( Sqa֓&eYk%N'>~V9jAiF +4u@iXRG ccڕ H2Ijo‰KGw̷vN!*EpDO&uzQ,>vZR$a"n_ያ/H.!8c7QLEHTuuݽ %&3Ԡ[>N2TCV$&duRZZWlȅ6_7nQa]4Ŗ92z^Za\uw9hCVn<^$~؝k qАOrȤDsn+KZuKbގ=fD Cwm%V|Tޖ0 uDn%gVcu$C|(Uǔh 䰺a=No-BqlGGwT.ԭ ~rOnnkQ Pi޽!f(Ned(Ab8'hhn.BUeARFMJ>Wrln_͔4A4ߒP{P~>-'r %3mInUzZ5BI1D4.^U0"mthuGNupf0LTqg2 *Ursr\J:VrBI!5=T,4!,Г2SGhsSKN(T7]1@ >KsW%g[hTjee`[ ʗG&MNV6t)\l+L&y 70Qw]+D? Lwe;ߨx 0LXO0"  +ar cڱ2LYI.qq>1谤WvJqG'xT0Aqf/ꆤ_szg);;d'FS.|79Oa8AgsI\VB.nA܈W UkԵ6L ۆIpÄԺq0eoܷp)u2>}DD$T{p@]=+2;8ieZib3b}DdݤVdZ N&br /߆]#<խuu)P86si@gh Z1)Ut`ݨ8i38Q ^S^OCBQ=yN3) )XN\#ti/ HO.zY(Xy&i'F a0w-W<@*53kYգ aJ^n0O|%Le)M^j޷IS%~&`uNękB2kv*7&O'2Xz% f9$=$"5ݪZZE2d i4=!j0%k7yk=Kazj3 7axKG1(Dz<h|̬bW;nIW84U-7=C1D"2 . izq$nĉ#}kA:vwLѫ g J/^XS!`-ΑiΫpGz9=d^ϊePs-yv"q`X*`oT\ `kHdϪCy@{I$MSI AicIԊآiFi ɕ1=`Ո#'_D|} G vy4V%)v>FyÌ셕LANJ0b1إUM}beL0% 5pY+J!(t5E`N0;(dC.:/$AB0b5M":38 ˃Pp#;7*¾,NXE(j?|ӓlGB#aRVZ?U6D*[i )c^RAכ8iwLz@b!!LRWiYЦ3Ze\AJ0d<pzDzbP,AS/-,>oG֌$%rodZZpDMH=~>n=_gy|>Ĭ+H!j~_lkVyð6hvxoT-G 'k31ؚ,F7Mv{8IN`""pt Cd,N/ů{7 vq;)F"g,=%#duF9I OMjsƓF9 2N L/S+m h8 -`5US3k097_F]@]ސ;Ũ)#Pp@J~ 4%juҕss8䌃YЛPm4>\U3#z , ZolKA]b y$kO4 ЍW?,CA{dQ$iheu-pbEXP3 O,_XPb2G5VW#J:P5D:3o!")U؀ "1-WTTU@`ߙ~UhF &87u٢ k'DE= 8w.= >LHf3d5Gg8(,?;o .7 Axo\ C *hqpB!Wa9nAc8 tt3Rm;`,y¼wG !z ^q!Cp |:_@ه@~L?!*6l"[q9JfN]L+)dlAVjn0+n%nk7[f Wrĕ,ƕǝȕQ03s-s9N ]"M8fd3^G+YafJ0wG<9d'd2d=WsjmUpvb՜ޜllGB,N35|2C2O@lcԋb0(e0uF3 K 啍Ġ骧 ;Sd"^(ɔ+ DBq$fp4ˤynT\@s9`$l&g"5Y.H pr B>ʾ ,&58]C4&2jdҗ34ݽ3nd' rEWн~^,I:jU{X5?د'Y;PL y@୴0%=Woghevgo0…I:lWⅾ/һ)eB5,37Cl3Y+FB] _)n41bj&@qƓt¡x7$$L@o`Дs E􆫈BAF"rL'as·G6V6 K{h1htc`wQF$ЁTN+<оX-L)̻Ugժǡ< 8+L$ #,pA00;Cp8C rj W8٣dWZ앃іM.V9ͬ %}%uII׀|NQTC69Xp0 C@.5 X!%<, `T7XXZbԬ,MiA=W J (ڽU|X).N)2UZ$!BJ*S~Ё8%ACĀ*lѵC%.Qq|Ǡ\XO7$1A,u08 $X+!alr\xEq6=Q0%?Wd.9XXJcupـm5&$NEA''TgIrε L4pd$ #, 7Q|uݐnH7 yK}pHN38$W郐vn&nk,k#֖ǐxccH1G4%;&hik‘ -l/&]Ufs8@Ur@j\dA ̐ffHs3$Y!P {Qݶj@lyήuԐjjk5deh[+\]C^ [3 \LIV/+Y ̽PW҈[:ɔ}URXiS(FLœ!!Ct%xQA8Yf1uW4Ȕ28)vRLh s؀t] kЇKzllHL60Нvo4.3f &nRFܨ)#v`['(=$CЦ$zS j{e#Bj Rݤ0L$4xRŬSYJZmqAd+ŭV SmG9b\kؕe#Jz ȟFq,"|ֲ$ôdltbjʖaXٱדgo0_4wFefr~ͤC@foyI0/}t͢=#\H\ iL)Уj{Eq".Q,l%mH4es aE\Vb9Y8l)BEzU"fvƧH3Y$!$@@<6X-A^c I$ɪ vw0CNIV=1^5 !ȈdHbBw2bFЭ YVh\/#n!ŧ Yk  ^Y+;c-ۉ[}ww` ۈcjqj*v"ti [\P +-UVXWj+T}h5Ĭ\Wz.o vH|`<{c-)FƋ^]v.፵r܄;s~ݽ ?VZPj#CeWFTg"kgΆTGVR\gjj.S&]FHOm:R徑/L zIt(v/+U g@Z6 (_V$=_Uɳ7PPDAhȥL3)58opVg: c Q6)TD tewԞ|ACN1{ ʐeD߲jyQ C+t4-IB'l7ܨM=<֎2?$0YM䁠 KV X" {3F#"3~*@FYa52 p%*+_?UEo jgqw/ܨXӿi!DdR,E2HvosDAfv<7̼3lP%UOH$OGR Æ:KՈj|5\O32Ьը[ iI2x8rt/%ND9 pX1RL _;r.]^Dcr!aŬ̞.Tx*F8S)]A8WS)1zDGj\Ժo:Y}2@uXq52.=UUUD=UHij0%- ;Ĥ+aNSY )VvwpndA;{Qr"hݍQ0BiFёH(JûC;$]%G4C1 [D[M&Bgl"#r]A pNΪD%N=<2+=M2GIdWW0'U5 MEd5~r>FhaxVonG+AI*>Sܰu( UW?{njW̌lJh$bL ]H3a(d j `%  E[z‰}SVPa)cgiyU?\ap̛L40ѰV!2y9 =F54;!: a,'_.GʲV sKaW$l\+gÃSp3;spEW CLV%zmVՃO*P>\mFC!N P滐TtB Q%ZR(9!dMꗀA 'EU4BS|7nTхzDp.#/Rx2h0%Y th |7lWr\*"- W bM-;{B"Ux%tD<*4@|E"TVͻx\-W*jns8CdaH RhPhJݤaa5MT19'2_Sՙ_ڈ-+/EeF]NJZeo[)6, 7, RlnXnXnݰ4ްުcQ*6y"<ʺIB咏iAYaeHBĪ UjC@ ^@uX>ɀ L$t~vD0(홅m2 V= `aR?Y]| wXLiXtiX#t ; +!Ryi~1w>$Iu:zqj OWc$q2sYV3Y1\ָl@4{*7!/ ls+>USoAafU|Pu:=z<4 Xi!-jk >u-0HH =*ҼCMO`YR-wa~H oS!['H*eRl |v0 )5Ƴa0=xFJH㋖/:;1){3ѐ? ]y =lңR\FqrQAU,%X&#qaqˈy#eha慙-mE w!۬{(ZBU/ldGd `ա7Ě6FbUСWXQ4a#E*Di*$vvߙ|3@NH<_SSnV bj }!Daѭ ״4:ނrb_|k+XMNJ,Ųl *ѳȶBPRQlYYU`ЂyI:5/-x4EtfmEͦ0"AeognlNtH8C)q~pBТlC4еX"%>hIb Dx^Q}'B[ :)BR, SfB4as(WYĤ1,]3o`(gw,Q(|”[%hXTMwGKuQ*bMZ[MYA_qjRdGq( wH-튵kku6i^T6_Rί_z$SW $JՎ;cPQܑ~ hqhMT o %2'[DJ@n# GHt $֬X:[Mki U_wɄsw)!Rb#p 0?9B% ! M³aܶrh%[ZyGڭ yY zNV%@=HUl0Tq_PI/u,df"ؾMMu [endstream endobj 952 0 obj << /Length 65536 >> stream ~~<Ë$>ځڀrHG{ =.iCl)$f乹c 8=[Ԫ@ɪVH)l5PwO*<olI8[0N"CR;&֙| C˙մ7]ӡ%3s;ʦ=˘TM*t Vh"sY0* eg ;W,Ĵ !;]xآŬ ^xho(V$GU@ss G 14I$ºԒ~}HòY^A`$.4C9 Sɯ'=Ç NuFH[W$M#-y^cUbܯhgxSwD4ӍOUq6uVhJʿkyU콭g'|Ā)uSзEELzzi_'\r[&cb2s{} r܈~\)ʘW:^)AI`;ʎmy(TmKl4BAqE76';0<GaEGqcfsv6nqH#〗v̙K>bɹSE 00& &kKhsb1E2'oNs?H} 'ʹrPיO@X;{)%A_e =U8쭨Bb4^z1H;XY]6UYWBcg<ڝleqgP{R|DXm$\S2.A.Bbp)(3XBł3^I"+y G椲f) #үJdFsP\饊'tlvsaơ 3 U;rqeS*7 ЃZNn\c0=6xl۶m۶m>m۶m۶}ow{Iҝ+WϏ9_Qe,1t4BhB`=ozl4=i2b< v@2GaDƃ&bY 5ȱ "\I!feY lk!Ǘۉ*`orA$2xP@H$̍Ye Э&,i;b"9hcK7y_hXL{}Эs5{ C55ޅNm:%"09#ܸؗ]ƈ|)&ՙ'kJJPP`x@7R_)=g&I{&|jx]t/>jQ!lj6 I9~üA8g-Z}DfF92 A`7=/89kn 5rtU> )A[D`~[36X60q< uIK8=#X{dEmOtl 3 x,N}[eJ( W@9NG0vr*&]3дžDO ި)J&97!y1~f@$ ,դUs ܂|"B3_@ ճe!\!сzFj^P.p=nHH `;n b*sdLVSBo20h-EU`6TC[xJQxbd0n@X)U;-ɩQdZ aF͵35&;/vz̫P |=FTGP큉P,W܋M D4.LU=3/ɫbSѾA~0HL j5/k$y ٥V p\7 + t߷ _./'H QلHB]>q,p̹;/߻|uW"QQ1Tܑf1JUC1NE޲=vvYܫ UfsӜ-ڐ9:6D[ӝ `xs&c4pw~*BXLf m.6ܭBôTm>:\T\ ;|Rh&Q+N&W^~羃 H "PxS1`簟 ,ws$\9ڈF"ةJLugc{9Vm^tZ$VfH\a66ON>߷:y)&YȲF{ j$gشZ,c:W'H%)~<>ԝF D XrFj#*V$+\W "x5k]!mHxwR`G2M09?#6&MIRzWe APx^o0vL L:m߻5/r|1ixg+6Q !Q} q!wyZc:m=<$=Q9) {F'*E-, 3ASۑm%%`%$u=94~q(5iEV$l~3[s<`$DѢUTIvB` L1QD9 Zb9dMZ&$"^߬l|k R6iS}{GGi84=<"Z1)gip;93Nwdz( -R$ ѩ_xq ˣf'Y?-QhbO`MH::@9͌a9Ha:šLNpϦ],4Rv')ㆷKp1\*1׋ـBY* EccVCY%m ".~~a5X5CIQǺB|ms Pt`tkP IǻzWcJ4VS3ew_VW;mlO8MS)rz4;ش.D2iRe*V-C5zwI zBg8)S"xg@)&\qz`$nMt9{`8_3(-Y01i  6C챬$Wok 9b?AXdCwJ/aE0hWՎyZ>㔟 [k`lZc Bؕ[o o>I&Cc͠_tEum~ f\ Au;:o#My@-MMboDXPϬ7kGBAVdY=Ī9l3 (ZZwN7Bc` 72*b!l|>ɼA+P?p(gvϑ;Azlz65 +5BbxІ>1+Q ة>EZ?TS,qRT NjA@|v֞>fDR̥,zI $0՝Ptu%*D.HI p0@!j:O*s4ZJ`#Àk/$jp#ݦB$LD2*@Hsb=!rFMƳ;k3?V?xm[trUg54 V1"Qv۟]ON w֧N:۲VZ }*Iѧ3XK*TD]K{0 $8CAm qH%y 8+Z2Otgt'0.cҭ$B:E EI fgR{RXJ-zXQl^L3(0 3PSgdd{HUrҀ>g9Ϊ݉DYQ2G@"*uJtR+e8 b3tB}%Ɛ&-Z+BY4u Cb#W]3k,m:h%r\'^Ȏ9ر+e be"ғ~$Ke;Adg>]}, 2R p*Pq -o<'rF; h*q^*l@c޻c; ”LX{(V6JD[3ʱ2E8ia卦6LKnbS(pbb QNm,As"I67(**CǢC ?I](YL&cx ɶAkq| ]yu`eT2S# t>F9])}.XZ2:uUUH{OmUb5K,H-#b:DFAOC0 FWP`sTK e!%`X+]ze99i<%p.jDb>ً8ʭdkLN ) GH\V\M7U,]!f %`<4""Y|h ][EI;*NzhcViʫ! t;uZgo 'C>[97 nb''Sޢ &RvYX# |o@ȅv ?oXPk'L!YҨDC(HJB&J$HnM8[ @`2QsJ>nnQ)3FDFn3Xݫ򻐬E H𽍇])]j̷gL4}^:V/ EHCfNډq%4r? >T(m$iL_i&va]7[S4pѥzPDf%ܬJRӀq6-41;u2RE7N$, +oɣ|#C[嶑J۞~P܌Tn*~s9_Xp;;uV0)\6w')O۳}x2ڟ#>sg}p9şёw?.{q{էw;U*?QsSEľfOw Syvw[{:krnAw3mwy{_}AL=Oz~q͏ qK?-g!{+W}AWKxOkWo{<c?+/y}}Mq[ήW[z/?n sŸ>ξ<{oC 6owT=ck#y?W=^Ξ/1 ?N7,_qWk41a_Ooio̩'MyL7E7+}ۺ?{(6s o?cOާ?uWxy_wt~￟Nq̱Vc{o=7/?|.){?S{:+\2`<2& 90/> -k}]=~L`:Iߐ2]wrhK Q&z2a.=~jKuu~^?/ouv9Ca[rc/]-אNM w?cWЗ|l#]/;[mk~==?]mowțx޶z7e^0qwݟ[v{{O|Bo7i}mGIlS[kmkwk39'KW$ wQw;WQ]mƞ7@qWyC7YUkQs|a {;//'#zYfGe'y]sIoK|9Jw//wW-z}iߖ8vWJ#IbNf o?xUa߼Oq}C#/d!n/[H%S ^]f]_EW]c?S6Q]W_wouK 4 _ym_H+Vrq/ȒZKCJou7Ymmu/҇rp9azwܫOQggd{ݝ~mc|yu׈a~Jl[w%M|Pc8 * LNl!Cp]f~յ@%{ko_te5 ~aigdO%5Lv%{cH47Hߝy}N.¸(b@POjl1qjʝnL?] \Gn$)ϗ[*>7w_|;a#}B>dпE1M(6+H?'xZ]4ީ' 0{ q@(2s9_O.!!ۆ@tsuI q 'xpDY7V @ zpqA? m)obˆ7/.No^gGJ^\C#d 8p/:\rɽ~tѳQ||Qk\rGǖ$}ǖrb˖XxrS cf58KTMp~LJnpît{~z=/.GȠg/Qy>O{2_Tš!B(kHx¯j{";J;fΉ}RGFGQ ǞH(@~icE?.+wQĭ |ARmU"¦~^-0po֑ciN^poz^-ކEtcL7\ t=LaG8fkL1_o?x#o.wxLuoV5 z&}[ (N(:|eSX%߉a4Y=MO(%>.gR2[+/{=[g3?IK:=o8}IbGs|yz}?W^?gww_}yHCE~CoR _Yn~ے}O;++YuN/u>_+qkmuu}]^/+7;#Yoʏ9Ĺ2Ks.Y216m޾(nkwkVڴ@xQ~,Yx[u]+vUoDn辺 ~KepKQˣ25?f|DI\$c|cGz{vyMr}>6V5z8t#m;++L7ˣJ|>.ixk;ڬeν!2:z|3^?^3{p&OOvw d Z'n>]x]~!9rw >Ap<o_4xG>cϓ;x·|_;#'?#W{;zw }^8_Mg<]QZ:}aFGsw=^;3w_ߎy4y?gK>w]Uiq%yﷷfqQy^!s ?7xe#7."N8&tT/NBѧ҅Bg]B$xIo7]k^y[O$xUo2qxp-?<( xz0 >M v@"_!^x_s?w,C9Iލ Qu&96I3HlKCkf^׌Y8Ӵyœo\BO҂ S&vnW5kMuyܚ~JrKfotˏcKP$.|6-Q^/'s !f4`CDs BE^oo9QoXoYeĔq>vZ柆o1#n<܇S9<}X7IIf[wwlx B-.rlHUӃ|v̽}K%x23ۧt5tFk9ؗIE28VYco|oz$I҆lԤGP*E ޶s |iHS$^՘Wʍ#4jrdn,JGywn'Oh_8Vyc PA0Jʘ+ʟ>`7`_/D0q+9m |5L9oZ݋h!a&AP֑'o0-%ߓ_} 1\)1\Ѝ} ΍ d|k3ЍG߮K]-ûOd0}M9wgRN]ǝ;[oES- tM8PJ2د =Bx"v^zKnQLJ#/V!l2odp4oqDԽw>`1rn>|,sy2ꊲ-1_ڨ 3{2_z(Uxaa,z%BJZiD({+B~뻸FIt0gVEoh"q<]h O="2 7o\S"pӲ4'N 6ʣ"lRWSX*{J:⻟˰^Ó:Y],"$ӵ27X|Z͹Mw'@za|!Go -)<XqJF0kUcnE \1GY`,4T_-a\)/] m3 =G_䷍QMJ?˼jdmgv.?'m L71ϽHA}3H>C ^rqq[g*37rȳ2ڞihŝo2NBQdIGT_T b"n/l=kk>}_7Trड़k ^3SJ * ;IOZ_WS(33m`XvR/}/fy]Q1v+ 1q/6cԋ؈(]LE$  d7厫׉SkUgX.WD ~]$⧦RNM8C|ZS9bEgsʊ+`' ;c\hoINiu5k^SŦߍZ0 988j;IU[ScE;g#V*y^^qbZMjϞ~c^b]N*.12◪"iJ'-AW(_Q\\uֱRٔ9U.[s Dhۏ%eD=I bix&}$N yg^³) ˗HA*]@1udlvH?g:2!v'/^1ׄn[磱^c jljzcUP&eg|Ɗ">2rvvK-a~ڋt*_w,۔MWd-xZq MrbW>-#o?u%_/ i3tPTibݠFGdztq$lcKS^QmQR 0C%cRG|љ,zaUY~~>Q#%lB*i 8ʗdu:/fޡq\ zkJ&,MW;V%Xa#ʗmvGOa#M[ܫPZrMD*~4 {SUk$:Ea&ij^Q| < ClW(\Hw]P5]x倗I9̎1nu2^CWS%vkNn6WTj 0' $vv#zEb[dOe O.9LJ g^Kuu1Z/W2%~}Uۛ@U*6hˆ}E+WƵThE.W#4pL UEۉq7[z$53cܠSŗ)U.Zm*!n$YCFZO%n~"/rNR֪nM P 9|WYݮ T2-n.u&C1;#Šɛ{ބA˅9q:ȥp hS{w$s *+Fu/H_Ih/@qocYL=i3*'2mC/ū\L%5M ^ST/[YUWM!n0luz|hPõy# LRK^ Pfw`cA|Z~S2l$ҧb-$Q:5B<AV}*>ʹAFeNDě-jM]ZC9['I+Y4pz݈*:ݛy7nyO@N{HH[#5:(XS{>rQV1 xgąSlg>t4UQ^mev^J!̛NqQSUV7Ğ(rOũm/}0WSּe=dzaixjWRdV")ϦC2;`vJ[T׷r&О#QmEN!$s>5.(;b(BH0ك[ǁY1Ri+ǝ֍myUwJ$.Rp n{ڝ?Ij"ldLu >B"B0T#ٝ$p4@?as!3$(L6Kuq>cOKHC i?}|sĄ[KR;$QLy] 8\s'/ZKDu{7Kԯ\K=$$~;*hB @Ɠ4F$oT~^:(F2.{Ԅ8smG?]EQ.ϦAX>|}W$zݩ&@_5䁥,+Xѧ% }YlP3/5w$jL煺׹C}c~KVL3s$M1BdmiR< _ĺqk h?06Nڋ=vH 2Wy&D98&@ C)L^OV&:PYA9R29҇:I`X-*eh/ZC!MfqMiiە+VNK${$q>e۲y腢ɇ7 kVA&a77PyGKChk4 xRbiUw\p/+N"?+a!qLNh9eNF12hH__4X3"b?O( Щ٩QM$1𕑛" ̥pJ\D5$iUT$y7^)PV@s!x-DѩL }l<(j|B&uYBPк dٓg[(2sഐg_̬-&dTb>sjqToVP|0CɛD!$U:|p> ׵`.?rSzCcL cWQ>n#cWeCfEyOW {7$z[IT1zs|yqh#d0p\7e<·0ax t?'cȮSJ7خ]q?לyiZ_gמaOߏONܼ7<ӱY7;V5ЭIeo[r؉<3`='{+ a;c:x]#~~X㰗 _ n1>\a#|$i2Dx& \LUX( ?3K \ffW?`<B^ռ)>,19@&@cq7; o]O`_t<$_s<IJ'28]l/ЗCO>C@<~w%xI)3-+;%&^t.q{쮟{/*yӗ[]ݞkǮǠ>A˕y_OI7CiOK䥔| TXx2 ,)M'ق9TO>~|׆ʸ%A¤u\A]=忑Khe1D,Лs̆:dD} ,kfvD};!`=:MN)qZ_~[;C(nG!ԯiYhIukZV qxsUb4o$ jHU#KLv]gxTyUTcj$ !uh D3s+;ӷh8q^"BprTK%,y'cz 'g)t8|2*PwZcδ2{X ܊Q&0  xU^U݅T48SBbMw|bbãp^jɑ`ú 2 Yp+Tdȳ|lǦ<:V"*䖇bԚ2S֨M # &HRy&[h^ҽiQvj/F?0'KR)~ Tn4:PMZ!P?U3 ѧ!`RHkGF3L愴#l= l+$.SEIl\,PjQiզ_s5HhUتîBerxH2~=h䑨(_XۘZx$N Mg/YXDgc(r^6𝝙ǩQhe$ˢVL|/9,tǿoTjڣM8(0x>epSwED ۾D("&׽~y >o7P |)RJbJ޶eW?5UnX(.sܰPd` M٠|Dq~ rp:ZF,喯z6k@늿H0xI2JeFN #5N)(#29m@8V*GoZяö:,xY@\2\q3ZG,!sh䱨 y^ V($ sRSóɉ.QxLٌو#6$EVDA[z\ BOд^l`)݁`.:B(DFZb#pLpz-#*|YL\tѷ20=>~lG,෧7EDUBs}p2 ҍa!'7Ƣe7TnP8`Ci  L 'd/:,#dj=}૓HssrOuq/%B?]YMq{{(p& xv8.|]wJldlbW,kdJx)W{PH @ND:Ƙ8] $< /6AI:/yay8`0Q悀jR +yD@ڠ3c@HHؿli'Z/'ռ@ن ),e'>Z;}xbhUJbmadTT1 H%?B3hEFcc$kXT0$je!ݐM]sBW H;_(*4h9#M٤)vOs%~ D Ay9QxBob9{6-R%z]#e0[B4XV& K+7x1VȁqFHD.ſtƠh@cӹ L]?gTҩEk|167IY/Y8zO"FC48 EXW^$t[ǒ:S5`gw})23sg=Tn~;4))Dq=6I XfdzԬM%Yz M9cf/j)Xjs5҅7a?4xRN#֣j82DQn$;Vju!zȋj{F`vE4ZBe YJi9.ž,H@"OM@W`M8ѨGfEQҶR!3Kf:q󘊮~~VҌ/IK͢Y3-K͞?ы>l<-8U6!sUpteߡwy ƈ'$JBRf4_z]HK `""]OMnU64f+.h(k Her!?` 3`f TIjY| rHH=\F2D w;m$v$2II!<̩οxAuR QBW;HF:Why iQu ae욊KX#u*`̠@֤U>:=mCњ5mo01ɇ}0`%f2ư%kg5y(ahc^VS4aȢfv?ONU.U&#z?}ͻp'I#: Ͳ#ú對JNoY#rww @9!>&4h~(vMr&!X5S]"SR!u~0~[amhnDE1P=6]syl![~E(&ImД˶}(WlrK]f3l@Fh=\l?hX@a>@KMOz,)bfi%^~VS[M{y!1d0 _ɯ ,j3pptR .n)M)ҰyA )ڏB8$6'+=ӑ40FOxƇGfpF6Z"l!6v0{K a``rKS8LM`}nŃ$3t$Td FPb.Nh:>6O{PZ:aNduJr)ɚIb!{m6^6QvL!/#f?y'I#daYNyx 2jƈDl-.fGQ (_KVB`vG9djI0q5$STJK\e䚰%yu 2 uy[mX.v趆TnHrfrY&+H@K,|B]~ѰڟA%P p1=X. Je%BրI^>C<.q'++ ^&L…HBϠB/,B|{FـuczEX5;nlJG TV;L̴ߌByuCLFIVQG9vۛؠ Sw|%/GS@ߝ f-n12lvoFYVz-zC6gyYWH3bz:/VJ\P3mιZ3i te0d1N' ؜OAF C0RE@WL>tA1砯 wI(kF:$,xWO~B=IΓ?*AFɜ #2Ka;*0輀? B4![{AP}UQ3뺜^Z?!wH- VMe Չ,HH4UGtO@p :^{02o~ ;HoFqJ |yd%)^(H3zaHCy%(i4Hoޥ%f2vH _/$1Ȏ9$2|2'l*}68F-c6=`pLpH??2i7 H4+Z$۬NrwV`Rd dSdCZQOwwIfP L`!vIm3uM$A/{O*\~~RL)f"Wݶ@Px4բ NG|s]/@K9@ bGN-9Z" o 5y`~!`K ׭/Oͭ'91O: v76uO8ARz!r,o_pe 5a[JL`\ N0Ͷq\ ޶iП|*3nV^ҽ! }U'M뉀~8[s9_lUğ <4vAt") **OMHoDS .C~?/d쬪;xa ;*Ð'o@1_ P0VԽ>诧`Xڍ$43qoy|BA(0cFn>*̬&\[AFjE$I4Ҧ])5XTty8S!(QgbVpf0}Fv̕2]$ $2>:MEW8O I zrήRX)Յfhl4 r4[mSNCpJf@VgGWU-lﭶ=B ej٘JxSexƿa|_i4`QJ Y߽߁*NgO^gg?/ucϘ6I'K98eO.Q6fC {+T4{T!H¾eƦT E%@t C`yxڎ%[H |C:WKys`{OzNʹƅ*ڞ[vtSuoXfm4w^3\Av3>'"A^SG7J}/k6ĕ?1j$ 6"~B5UBcA@%Aʲ*谒̝A{mDYPҬ;`Z)Zm%d@FOCE )j;3ҭxOB.UJ{o~ءd7Nw볩?&4 *W T;]KS1C+Kf±o<ڡ-f 7$Z3 qCf f1fG܉C81I~o!@cHHA'ñ1mmZƱk$ml, !W;>DhGK)hD(*AhHu:|^5rmyAzEWeIsuHU;J[NTd&O v@t-oFElxO+`#Gva$& 0L_و@_nÃnl>#ӵº6$=quIpq!>k{h9:T+V /D]L'3iY+DO}H FŬF[EW60E!^VRRȘA_XHd>ۨ i\\=^ ]dde* FRxvt7M ^TO#P©d+T<|**V ʼPv Pxۨq4VYs^,9o>rЍbyDDrl ڭ8"5w Oy{釮YT+VA}T.j%/WDұT'qTʊ-2{һ:3_lHŢ^GOZ`^/,dzQ{ƣ},]b>9o{J&@2'x!_\5@g/^޺fciîG E"m.'c03֚bmf(y[{ja5VtjnŘz@HK3˙VU GX= V4m ?ۻK|&xl({zƟ !*L (K_[ɺm9 z:<4.s? d: 󬧦!q^^:BRֺ`U^^Y]e}W%}5`ܮ|1d:$ɮ#x,*+s.XgJ'`cg,#Wh pjfXQ|>OB?7z0HlܱIHjV\p@޲QtuB/$< 0./jEL튅/9@?1 hg_І0Q\L#4m@O /rz 0$u|̏;#P`JuQ"&4K`r NfǙJ`,X뗰kzr2s|Փ4cDo2?LU9/}-ԡOfpgꀛ8zb[k$Eo=[z$<C7W}~Np"`p* ]@T 'atFPdqC5)Relm |Zm%#E:yV R Nnvx'ʼnXҞcgailEe/ab6ƜT@PhWAr٩z bvK?kv tZU՞$WC7TiX̷6s&x [Mf-?r-%odXM\Ho- {|!ifrpՠ&.̑>4x8%9Csǐ3Pc1xuO 5eNkadHz/nkk \h:drB)W5G|2CDMdH3bfeN)2e{ 2#\bró:Sg5V9|hɖm3ͦ8ͨb01xUjmB`B_a%d"@e0q ;@sfHM RTC9Mcd޳ԗK;#0PiVx:v_-/9X=MRŇA~J,ò--!kcbz̀YVmP a..]ZQ]5KQ UZYEV V͎HU;7NImU,5nt3mN/!5)9dkt1/P~]i<Z.LvZ,L<83L"[E ӌA5>һPu%sFѰ(2Au{{@]^Y9AMZT-SExx.ض.fCm/`9)-ڜx40Z-S(aP XGݯJbTe+ )g1~4[jyBV+>u6D<,?|۰ʉ|^_KWmm,Z/8"B #|rtX)Vǎ $-O|>@<:.fx(xfqSRWv凣:@W%U+qR87@砄W)(yz*|rS4>LRUq$Å -AÒ"gW/W˘gSv\zOQc 68v*UːtJۊdqHfHA_qmXvgp ѝa4ʩhta.WYs =A_0a5~g?B4`":` 7uj2C (E=%9k _tYʐB~Fhԛ!LթU:g~> 2*vjă X[>΄NEm#*0NuMlOwg&v /aѸE?gӾ 1-KE ahwRe(Ԩ#H;]yiNB9"!^ka .V\fzR AX(@j IwrK|Zf-Fw[95B.]x\k'(m?gzzЭhn];2/O~jt-8 lZ95ΐ+bs%Sx/=+%t~S# k>vFU3!]m`p^;gKu/Pm.$l =7N~t褠Q=3B&sOlWt!,pc.jI ru9n5&)2t'vN)y^G{fo|a,t dof+G h@TJ~m``#yRS btCQ&rhsF?eLd?TRJnm-Pagc0_ V쏋|2Օ!+$8Um$&.7LLE|iŪgeއ6tgq} .TX0CMw5ťKy`z;1f`YEB)Mt'E I'MIqJlǙ-!Y&"]!Yء ",AP@a@gLa$Ys;c(Q(1A!9[`}c0Pf1z7LiP5gD5p lFRm`>; ƫ c`]c D-rۃ e0m<>e;N‘7{d"K4 _>< PG36L'cqĒ1N 2+W"ڌebHui ncc*mևJ xG35SƒN ͆~w(s;VJOԴ6h(]'%Ȁƍ#ቀ>KEB+KI\b㗈@P Vy*"`JzGdQRZ}=6Hƭ6Ge HN)Xʷe(GBO/>Lg̪q6G΍[,j0, x#qˀ5dc~5~FN9?GRUDa(6 od?p6Kp`y3-wؕS 0éJTNvM(-);BiG/:K<]]Tǘmw#t?o2s7^5ʲcZ@}?B|=,t|+R,!W7Q㻉)|=,ήBa׊Q>_zAt.|gzXI|uZ{7jy`+o"ދFJ)NLzCQK4un> ORoi'=$];TX^AFzp@sMM+OjpnA'M1ElW->&QDbH,쐻kMCdjwz \6G\)=OZ=G/ 0S]YلD8nڸʲ>OǦ'g׿餐_pVIlCdg*vTƴʳձ-XՓ'Q$t˽};Mv_~5-h 1TH .a/ސx6PZzc/ 3Zcά F.ATm9x8yvwa;RJ\[7Z0C>~ƃ*mmeO(k'2j83 8IzX|0T3x"GH |ԁ {=&RpAgP Pg, BB *uVfAu*hr 21CI WC;F>ic_X >vVpζDS4#_W;3JF͚w바ݻt/y/T%Nt”+#OL [sQLb|1g)B00'9I+fuJڞL<%ľ:,93`q:ϙ+tdFkO|Ξ}tf;sL3MZ&hND7lfs gbV hM>@o}q\~{ZҵǤ}߇ \vs+}m2txXWDhB +Vd}f,3ݻăy*Ŋo,xjh1DˡJiy=nµ7&$[g h'򺠗^moO/BpHQZwؚ/ ⪏dJ}bej=ۻ*3nVvX ג5sewbA1s;,ۢ酀袈 ^J~:MncO3IAj]w/tگXW/x0%{.v\(Y2MϞƇoΑ\Ĥh_v8>0bV4P(f,Bi<<[>Cx1Z.'fڠDM6v^4H9 PbEM4Gsq=#GHFxM`t1lXsȢj)"T|іnM>K7Má"!7 hף 5I [DWvcg/B0Ijkqq6r'CQd.ki("5v_EzWX(;0 I;HC)wRbRumR#8柲/c$]ОS'mjێ!0z6@pF,}tޞz#I؈;XZ‹J(ȿs'e&MaKP&r&EWqCzZY 2[͑q Ik0im=BNb9,Rƞ<4S 4—TZ@\JAp-`=[be 뉁iuФozq J|2,<C) s:,J 3@_r%5E(8h(FRDŽъEk Mw@+7jjC܎ (%N0l-?nr~sw^֌^1gCV|$4k1*˚"kz1dĎc0G5Z[1%SFJJ(.d}Z3ZF([QTFH[v-ǹًhe)v1@%PӋ=5D\ZI{j#+0gj ^Fה;HxB7{y[`@W0AUO b0cee7m c} ^kM^ ^oyczSjwz/ ]D u8}TuΎpFèxIP<@G+p=_J^ {Pmc|DkV1n=^bO=88\A3G6)ȇgeڴӔ>b KX-ʙN0Kʪjs hxu6J7pϲY"]M"o}5I&QqL # ,Hn 9%~=cQKMzp,zpoι(+J)Ԃx_G)p?tM:xoAi Y{ĬtQ:@)ClPsdQo#Π;كhR7KT]=OS/ qa:Y'O= daᅲ -m޴`" R@RnoS1n ہ #"ѹ eAdwJ}X*#X`e g10ckF`n_,,eOH;yII@&P%̄w3߀gIփo߻(OֹKJ-~n2I$)Ej|2v8X"po$Q'L}MmA[ޡ<"VeH?&WG[~V\)$! WQH*@ y9h0(HfFm6hDy=P9dۍdsDr\#Sk˔SG$'Ҋ~'pT J VivO׭[f3RnW&9?GxEj҃ k`Am=L^q +,m)T f7T kWY_a`-wv{R7| ԯf@"@Y3WI-{PmYZDz-D _150&ԫ'_ +xH7oq7p˔g#]QJFg}GQpbJxE@g3"5نϵ%F%@/VmԊ0Xgr]o#[0B, Di(4: PDY҇b۝_϶n)꣟Oz­f<ίg"{ۏ[& .̓W4 osZ[~WNw(W.whKnĸP;uE/voc[oLi0uzy(zPrW:Jkl oKic|@f4@#Fyˢ%U\9i>AIcek'SMn*K"@Ar<Zl}Zo{w9֖֖c+Ju6&0؅'m,e|5um:L복s&&#HB_crJ l=dJq3CW#F>fwoJW4_Q+ꓒb8}d1nHM@?Ju-P^9ٛ$iY(b}(RQm n}KNW[ŬXtѩ0 G%Ta~q؞4  ] =>= ov : [6ҁ+[ p N}Fd`߼'~3r`XWG[ ~֏pCz[ΘtpM_JaB(#KآWh9Hy\V |ߋ " ״Z[{A O-4 ܥV4|%s[ȣ4GV1A"AX3XAEf$Q#i\TiCYШ{#`#9^@i]e49#j`4NDv|m9c".wPIXoVy31Ӣ8?]ID[*s?Eo8O|{ y^旼n|ҭ *^Ӿ]̕*m:9 g'( 8ʒӨ Ӕ"Z|pfI*@\ Vi 2 t9 %ؤzP`{^^ + Mp} ~3 MVy`碀blk! Я  7+Gf ģ>?RM0='{:A#4_W(}g[ץh&@Zׇ/3qOÎx1^z#vzt132P_PR5xaph]ՠLV\el-&*YuWZRj^2rX]'j5skZy]緈NCv6SΟJ`MSYQVm6'x2,Y:9^aY1*`g 717eB (y@,1q W=yN_4BhєYdulQ_aYve+^:jgB֒LGeVNUHɭ΂bxLV%t6bFU=3!8\ (6YE\@q&r{o]@,&#‹-mE,hZ>b7*jq=HAB\-$fsM Z%ǞWn);˫WN#mɗx/NZ>Ǝ, .Mg,Zrj3f$\թHPGN#8Q@|{tȣcnz[yӞNvIPE2M1u {T&ࢢWkMn#Ht-J0[*vfRifNѝ:aeo$IVx*Q [ ׎3IWm\-}: X.1W\ ڃw%[T,GVp`DGAlBUXԀ{CΫn*h,Aol"@t*X[*խN)_`VSo_ ,M!Rj]e@/PfmۘXqXwiFZ[AmNAS7&\Y' F A^ ŲF/ʙYH,rQr"wa*')Sq%`hr@[Py:x׉2+ :(1 {pfI@Xg.];8sA 3Xnk v,~aF YO @dIpn+rg߹7ԾYk$( Jw=<@pQjC1D^,G~mGyK zF$A+: m͔p1iB9CbBj1 Ytl4'R`P^;˵S1 ֝ 06?&bGc /ă{dvFX" .[V8,AadnykÐm: $v/k,~MؘVG x."Y%KQϳQU);angl;-FF缬e ҨEk rb_qvc&zVg~,ZB&/'̞ܛG&<&ȕ4ψ]G(h2v`5%`Ei`->/ng|LBCjӳFo"ds%])k!Pp<""+X7ཛྷכ۠Ql{;2(G{36㜎<[,{/Idqɉ78jR,n s|W,[D@ve?i`0^7# ʺ-#jGW[&;-,*+kZ 2i9d`/\08'߆2Ƿo$i>[|GYgMya5=e4GOu|FA'mIjyg7ֶ+IqgTZ`m0 !*QoT Ԟ%'v:]sf BHIn,sߥ,izekb!~B;e3ی4LJص(Dأ"8PNR كff%Ovηpѫ KN-!nYOgB{{ڮkE߳jqMj1 QϳonR[dݭiErmhK&4 r*gޱnJ\]AJ}f58\,|SsG7g{ nQU|Թ#/sC.agYflNxԏAȓ*0NW3'.>|ƕaV`S,z`b-QKm--? @ p&=(:A@~ɛ&1jnChnjʉGRvÒ?7-2j¶s@`6:rZ6tTQ[YUH'Ȣ&RjS3?$/CUm]@ IV`n? a+^x0IR+ܾulu$4/m!.-է/7B:[6<̟3Loth)xOdzk ъV`φ) 0ռUkt42jg7= ʡ/GD4ۦ߂ [}.90f, ek3xYi HQ(bӺf0 ?oF/% ͋0ȬiT9y6a[7;Y}!kb'ٿeב#7 .2eyY"7K*X!6Orp*qQk\Ғ^GيfsۢFJZUC~dy ȹh5ܸQ;V6"%vOuZ];#I{a_8wP{Dvj =U9qg= h!nh+Ԕ`MYԝSZz'R~ JWPJ0{oժNH@vZƁ6|/MNb \Ydd~YZ sP h;Vk7+;IFZ)یwΰ79u"4? Y $?P+2:&9%}C=]P?ό2W/)De, hL ѕ/GZt3gF>҃[ISZOk&IGiJOn4Gq 84_JfR3$N@k7ĝ1 TVkrY0+|%{vHŝdhz[3r^LA?0.^|/d^`.e" g0#rOֲ,]/؋'u φ2^DN<P`<(!} 2R"%UG63cz@\`j2ZW_҆.$C0!8t{cVR 7 m3 7@~ An%s)Ge}R,cuG!u$*w\kD?|ҍ'uS;c?˿Ge>򟀹Фޞ9#;|$3\ƃf 9ˁ̃\wR|xtl7u:^f(/^[$GV$ڃ#=Kє9’]a/> az[h{u! =R |I+ MdX9IkS;#sl ؅ ͦ|~q/ó9ϴ#9AqDcI|k98{~FA#rx)X;YMKv( }7ct0&}!3 . O\LA@ ~"g)a H3,eXݪ3M־.رթ*SIznri[dxUW?UKŖ)jOz)" sT`&S$t֥o06z/,uۮpi7[mcWkycN  u?",pƖbK8H8ݹESoA|RcabW9[hp*i.b_z[!QIsVi)㉨H/5w\K&tY(_ |eXy-YXamIeZ:8ok]'͵A%R̈u#vkZœkפnb-{83x Ti'k ;pǽ5 n4Rpco4vNt,uy7_ԃqRQW66MZ&{daˠI\S!j!f#QKU0C ۨj+z|n<߯!]*؞>fU?&݀䝥ž?(4TZ+h m9M@UU>]jj,xMzGoxf5:^ZHklo[2&Lp]q9 _F_7/߂ZjzBO|!@Ѷ jz#~he|qj'aW,g 뮜ԁfOGړg{ ;yǡF p.\#ntD2'G;y"KL@Mjk:j&8cpTz "ZΛnrxdmivZEjy9OA*AI@[+rmam n)(}@ fm)Ͷyަ}MyvOPOr,-'5Zv(}n_ sMt9#{ɭzWcZqyZrhŅ/Z@>-Iwл5ҶFN@MB®3f /MU6V%.?֤P@E4,d z`~+6{@@oR.*ŴPlG]5-! cB*=P"u# #m:U{P8=էY8#\ xQQEzPox[uo-/7l`8~1)V36A|I]`] P;Y%ezWC:8V#K/͖/\xaJ`P _Y ߴU۶]߱sWR7AM-}kex򦲨5 T*|S'Vaz[9Q-L[{[6 anj㮭+y]yW2mLC_v9n٭>V% .I&W wHN 5%S.]`#{Gsu-ARk 5Dd/iprLO(HɎЫ1U(O儣Kp-.RUPB)Ym?U%yO^'gԅx~nDxXFn"Cl E;Sx3߀$ƀb h\ۇp'eh7?|Ӷ^ˈMVe{Ix<"΅O@DX-bZ&ԲVVXI?|AFډQ-Enn0s^ L@~Ro{ WSqHK8QPZ ZC) #UkLaWP#.2^Vȟ JS51dVLM Yr51ifS78kprnaRK\ axS nFcMOf熪o Mrk ZMwl};+ u0+K鱂..TKYRQU'Xu}sʳ9~S|*>]Չ)sb/ %i ,IU@gi}ۃ, jB@QN=.fJmSG֗+-Q%*(TU;Osd4hͼԝ~KEۭC ܪ:l~7-/K&ei Z/iʤj_/Xe3@TZeg!? C0_{z.e]I~6XuV-4j/n,scpoNf8[~~ 'bmccnCC %k ("s13RRX+r9=j?6: k W1G^bx}~-y?;=2`/"hז;têCU}@kaIKkm 쑏Kg{ `k2H3Um}e7E(z c5K[~v cݧ5En {Ziq,V7*&t?ŽKⅥ%@_uGwR. SPX&7O#V!z x &Ք͉.\9Q>S{T4e]@*uHs ̏-3伶JU#kfJSKu)R~Y\HR{[Tެ;RI:(MgT+וtbRN RnEZhx Y\]]XLѫİ,?+%Y1qE?B:7#'WMym~E~rUjk´\d&7,>&|@azPxwMX+c=Hu.$l1fnLC46r2ꝡDQ@(sj¼cT [V$AB5o2"6C^ A7Qm!TZRy d)+4}ݵ̬͝G{+=^OyXh+E93EU<'U)HU6+ڎj >Qjު5%V4-*bVʦflTV|A Jyl+Kk E0" :(= G}~|۱?7˨Xt|7ݥ#L+۶߂ 1@q/˹ް! Gմ*[.uR@\fOgs߂r,?6m-5_7oNR6~az eѶ@HV2/-H??bl0|q̵!Lܵd|;YrF@z8Unuq_] m>"c%PJ͢'$Y@ATT:jrW0o t bwmvw>翚4:_r^Y "9Ѯ`. H2a]*l@tBвt!<~uYuP*-9 $bT@/ON(2? R@ >­ =* C 1m R͞emz;:Anmo=(p%j c^=Wz['tIo+Їk):1P4gP6&hpel"XsÇIK(iH<9 VļWO9UOM̂WD. Q0쭛 H:E'm+/umߑ}tzK "_f`!oKphA1m|[\ɯ,QeaO} ^J`2R8 i7M#%lq.驔ru%CB搾e5/(GF' >u J=(8 p&rpD靠tg:AE5A\ɢ -0b(Wa/uwj"5O(ܲ~ 9"Fm1AGobqZecQEn4IYs^$ 19$݇A*GWG29+#,s;}vmF"D} A=x7=z]zY}}ۖ/|&t&68b5)^e~֜qJ`[,KDAGRMH%ڪ3 \xܧόQɀ02 \Yޮ\ ~tCxp#=>^ѣNҳ7:ziSOJ7h*=D񩕯N)tB.'[t~VgYJԹ\b񋖎)-h*ukyQjEiGW~3^ۊ;&V:-vaaV) ;@aut[)BC[^cV^eM_hkS6:ArbXmLn]\sq3,kA*‰rZ/"[ ,IcoQ (D⽥Ys,j Jw٬ RGq*'jEg98H%3MgZC]V<-r-iʻYFXUrŨr==P-> d˶R@ +R6?ރf X}[o9鑕,mkADgmHPKK5ۨ[?.{ž3cU3V>CXKi!q'㍶fw]Wg):T ~sN̺:],#˥Lnm {m0c>. Ed_9=,԰ُ Ԙ*t,_mg+Q@ REuxNj"A`ǬrK.gqئY[ ֆjuU5\A"%@"׵p~&ݺۥu%}X=qc[.ע`if}9Z3$RQ=^lZ~?쮐@X1;T>nr;dOP[ђ(i\CY  weu9o} f:0Pdrl˸+}Dyg[fw,ڝF<5a9{&p`*}3.ƙu4׵.i:1؋3۪$[ `V\dxû] Cu[]K0u%)+=KCe,G685nxuN#0̣ =hm \Q~=;1=8y{Mj"pc81m8Z]R|{5ڣ{Ǥm޼( U^U9l6^,aKFJ6yHj}ݠ5 v_zrp+rFi,2wYyaHyXsnx_W>„ΘӒޞz~_wAȖ4x9._V%Ֆ=N5X~yM^/%y[뗒Z>۟j(ҨEm$b ~il/a@!^Ao~+uG_wqك,͖!RFcCsþͯP& ?n:qPڶ̘(2bTAaSejriK,lZ}xo+folj-oAlpKmZWkd,L2[-cGVbu6"[fYƲYSükw6Uo'e&}4`8oڊZD^z)P<%5ȯp~C T5/K^:jdu{~c@T/6Cd4nc :V0r8M X+"ki9ʪK+m8VpA=ZINw:A͸#r/Xz•AjZׂKcSaml@/1?mil[ÇGџ+(έ46x,_:97Uz>G;=}mpk: a63}eӊ:mƴԧ-!Ў%.ZŕlKD챁QGs|ƻ.i, ` \pjO$\Fx4̙e6@sD/E<:L?.-qÞأqRcߝ>dnbt0X^.I|7 ެmi198E?bBTSVVZ#-?t۵adfx]3ٲf$4;5f@D2o+.:]ar<nq6QGl@cj="ǭ_dI qZ|x-yc`!4e]r ~^`7 ƙ;N="6guQ# Œ GF>. ~3[ReԴn[X=mƢ0uuh^- ?͈މQ:(ݸECHC,0\ۻqx,/E!nLQI„Za"mnf_qÿ}x4#~7"6/u?kIfd8QD1A_ zU"9=^od8Atki#8]U6Ld]a|(JoO ׆1h餍K%ﮩ?7Bc߁ܘEQ$6(96mBaUa$R0j[O׆[X{=>="+Q3wi#ϧov3l+oMu=:FGt[Z]`n Mwp׼-:^v ]_rG';͝F7#4ϗbw _Y:Iފ35Eiׇ/BqܽDQ,F;ŽkCS'>˙QŁC6א!dQ .XduڣՐ ep؃v| $+hVDvr;yH z |KC\ .H&=7p׺jѽW8w \b8LTҮIEA JS _=BgMfb77a@{:x(]̾8nc q0YQ<nv3[0}x4П6zQ{naQ3pCC8uHuN5~`ݷS"~ >8'u:|SCOY?A sJ?G5cvXwxMr~SE^H Iw]lצW* -gj7a;id\F|(of16`Wj4ɖIh@4N.z]ku"Z3Vb-2'h61feטe֓{pƀXeLtmP}٘:aˬ04S ZH<3v5Q(}Gyضvou=^R2MVt f/l.6 p`"fnR}njM1: a|x]٘-cj,Ĕ!wspL2&7v hhW%LL*]Y,.u\ݦi<ܮf郘F<7ŰeV1^2ksQ^nkڴvmk/cQa׭~GNHJ>FQIU vPY̛\].sh I..J|8+۵j6HLeܯ\nj݌|#F~W~m: - 8<6/Fvm[} 9 ʏ_j3Ư;N|nWNWA9V۵\(cת4]t|(6P_ŧ34|__&lW6klҳQD՚Hv9;=k_ 5s_j )'V*1/#on_n,#2NOGW9_w/_/??_먎&vI@\ht=1J&έF$Ւ( kE!Jё\lP]-N::t\,qb:$5Q 䴩M2Įs'PMXQL8q[?xUbMT!wہvF4`!^'5rJ37oaa?p#yG/2+-КX\_FjɨF}& [-.2R]oVL4 JP`ZPG|M ҁtgl~RVlbZA7ec[ƉLG41*Gg!$'ƺa\HRz㲉!7Ĉ]8q-ZR&.̈́ Py:qM={,*5,2z:jbk:y-X R鳊~Ҷ%IYڄ1 haX4;~_dʿ̩ʿ _f`MR[IMP-xoB xG9ƒÛ7R__4B뇰g$&hO)F+6Rq6˓ xG>̃ x9RA&xzBIKM46Q~h~5[ו0%Oʦu^+-6DfP.YfG 9ڭw#by⌻^5d69UBY/|DFRl F;V^ENsA]Z uVq=6ǂ>"ݖ *.Li ٱ&''ґVs^kk-P@=簻mlx,wl*u@6AQ%P,WcN>r?H+v̛}=$UG&FL=7GUE?yHr͊t fU-l;+bٸ{a/;*SAONˆDN,,SG:l /+Łq4GQ_k:=kNlal168o~&rfZL@Me;VQœkohI 1ho*QBP.#/8E/C27#oc h+Dp4Ρ!qҏ&`U1^v#Ea:>?U|3ʲǕȞ'L͋/o ghU/ j5\1+k@̶D]$fjk((B(PZF,i^ݬW$ud^]2',ߤW1*m4J$_V7U-ز> '6q}ԇ:RQ͠:.X͢&s6իf,,XZ~C֢jaLF?nhPEmd`yd0p$< XgӸ*~F&ߘ\S:ۛ(F08յllYrFe^w^~H/\56zHRcYx:ϣ&aMZTq߅v%<`'5bu`)@Q G׎4;,%N}kP=XoG ~ 2c\ٰ>uxGsS8R ejlTlh_7tn2R8QQ\8y<04ͨGx!1dKOz?_D+ 6/p0M3?Xb9~cW7a;Wٗ,C/ ,}M8 *ZZЕc3B*P}U~025ͫD5FExazC+mz|*PjeB/hela CShU:j,W7FqJ m㵀l3^ek%} p6l&uN1Zf'KmVΊ̈9q՛}+!+cNXjҳsZEN&q1+y7WQ 65"j;;z/ݰ[dM(Rj xB~CwMZ O2L5Ä=܊(2,FYFjw]%vKޒQ! X/$GomP[y, xe2`Й-.pBnG$PG2i|гGcdӘ*9Sǔ cP[#D ٱMsłWGВ ,bg!Wji\y,DBN]2W1 1'uƴ?MlƎE&?XkdZdÌsz ڞvN0Oc*uxMfO}WṟCG&vaO#݃_n.qcݻV ӷL ]֮nO9:U-380NvTI3cM6 nh!D1I9ڝWB(zQ!JHbD>K[ЕofyH#L/?\w2cK9J7b$zwS~ͯVX8Q'(MYoXGtV7cd&H#?s97wKD9)%2vc-ʨWLjLTIӛEvwIh"Alˆϗx[ B фT`vɿ.hF0s( nAS]?"hIdj42m Lo1*ˌS.]ȡ9=K#kWm .w4fYʠE놅FrpoPzPQf_B[e@V`y)' mcuݍ+Ѝxu e%~ًf~0p|~6{6ѐ"t6dpÑ@' ^,8-ndT~Bt٘[qӼ=:^B~-TXypcD-,E֏I&Zy#Hn^FͭyߨKM^d H#25fE(K1nA! gX)CpWF)4 A7AM IY-p4*&ErsT& inpHikqY4#Nwa?(QWŋć`Ծ剆M8CTHtueHg),ƫF)֠GRT3)1vn z"IN8vhMp-<4خ.jlxpcCQiro28ۃ&$K{X,FCeh$B$o6ZsQyFۻ~@ΐ^~wQ@W6SN+PMPU50sԌ-WcJłDCL~%OI^hy UリP75udr]z2$4QsS>1E+_ 5р뇁Z{(F/)ƪޏ4bi{j͐ѰCbBԞW8`Ц_tǻ@B\<4GC$Oі*{Qmϊ3VJ [J3ITSZ&t=d^OpIldO3JvCPxo"=k:dNbD.ɚDAmz5f4 Bj~qi|k[b\ J?"YbĶ2d|9G1/Euz46ow̳OP2m*YGxNˑ9lP qf7nkʷ&UcBkѿEƣ o7?ru{{bf@.V{q"H)=~*.3<}q>CPRƃ#y ́W7B0oȅ^".?z jbc wW]q)yU36 qeHb H*&B&O=I!?yEQ)Gm8}< nęnԕ4HiO.Kp0rߛAd.|WY0` Q*=&SFGF'`ÁJMS;VDnL! D7rHG?X2r0X B~q}C2ǚlB h ųZ6x >Bc̒ C}-v̐B13ÈXŸYl暪M7:fU Kh߭r :i, X8*J0 PZF:l&F 4d0x3"dp@iX?!å⌦U̬@l6!ծ̛/?V/'1ZX/NPjr := .T<ڎ 9? y% AE*MNl8gnFQU`iP~o8vULkF>Q$llzHQ8DȐ Bi+=̈QzxnD؂r 飙W#I5,a[MtYgA[y E 2*t kסY40j*i./Fc+NA ,&FR\B?l\͕[VShFC1n{]EڲlUEE $%|5KFpmbdbWwnbF =6aqg7uEpd|&(fitd]Q\7~%g,Dmɰ*eeoFuzq5תm"7ycj-A!MhOK W9uDz/(!M0"jP QpJ;'$*FOy@b!kgbl*,aa&Z%#61tW b>6;4ɑy3^r3N]ٲLzQ! Uv5tSw͖ʻjYkhI~F$(bAiM³`a4>)jjm"j^Bo?܍՟TuAkYR6q1ӳqݛ>2Xabis{)Z=&1N܅2$0i^4)G!Ń>p& |$y:#z0ŢJmjLMkF?) 1q*>pCƷ]^O).?^? 7eZ-GxyyǾ|J>B zdңF&&8PY@DN !{IPE 1VǗ8z[}ŀ 15\xD=hMx~ Yθ<<2G8{sP`T^\q3*&`(a4Bhlk9 X֙^Z*(%WR"*MdoG)v7}L:~ڥ($ aG2nO}8:W GCՀeGEDU}Zl{{ӃE k/Wx?b阂9CB_}ب@B) ֓4= o&ZwcPB5 ?8Pc |_Ss*}˿>_mNo~_7?_]W7?zmwo~Wۿoq~OoǯĿ/_~˟o!}>CWoăV1^ !mS#5SVY+8ZRn?{u?ɍg7lD~U`NЃra5Xho2shzb,3hB8†nia}f!8Y@{$_4}=n ǞւZ;'^hTRIU@rҟǵآQbe>~%ܛ=^ PGAjʖU2Z;(\Ȓ60ɡ$7kL[pkt"F[ $JkzZa܆s)YrгTQaNMC<˄g_/Ց<,v zGʹ $:>~a<t7$>Qg_NX3T{:J^쵐wϔCNy:szv)Z=gNs+aDڦﲭP"fNрl&px$yzU+BvT_7)diՙP#b;{=u9M~6 s&P R4dʂ+i2]q׊IGJXui`TBiEwBuRTI0Hd `$F2H2=V0q`n{2c_q`\&`q^M9L,ϧMQP ]\ggfLU٤LLZf#hл*]n%G6hol9U9"tӰhVe4'T{oxk8wb% / ,J"LY*@RnNn91 *fOT#H VG=# [l&wJ΂fkY&{1 %'DS]-,^ WU`z0,PZNy}7/% ׭ F?؆F߮U E2, -[~EbJ`u81[8݊2#aG9u&`3 KHNk“:6/F ȁO}|}3R$Yu:wEN쇦3,I=wM{ j= STT}0Gjό;Y#Gq NԏovMAWDoH 'L\K4ɜoY͟׺<\qFs繨'~ kS_L`%AwMFH҈*Ra6RL/㤨RDR&Fhvx~A$kKD؍+2 HvA]~臖AVpfЏendstream endobj 953 0 obj << /Length 65536 >> stream xq @ǫT<:%`B{˚\VG<x]QL`ڏ \s.9kB_>p&PK:oS$};/7*,wp\a Xkq^}YeeIȧ jڿZNRaT$ u"/?|x~~w~S?-`Y^,T?=voϻnϷOD0Nx ##2 wĆC+B>|GȘ%rvϏ#EwŊi/'bd-|W?'jdFD8(#vdM|Wfwŏ8v^Đ E+~N$,%l$y#5]1%'&+%ؒ[~tX_Lɟar:Ϗ1Ye7]q&k{"M;XϏ6C|WIxqbbwĜ"S FRE߃+zR߅S@**ZyK2ǫs#V-~̊}a;n1C¿/#V8fhRH&KVݹ޾ 'FBTE(+6˨eUvɟ te H w[16-4eUK+v5ӑ?`Gi&)2FV[[I8sQrNܻwsz@O_E2uکf\XV$0MAEKS 悅$U-2jExh@PzyٴN:zfIH,p2}VkKfY!d'՜v7}`s V=r_!b}/ҡ/>!=><2lU%z_UWd*E᭶"O>8٨ԣ_,YMITz9]]3X$XoS4or1/%hx5LfUa;M$Ml.Zs&d畬 )ՙ֤,:B.&;;(VEڱY&5PKhbF4EـESWĄP7SpqF*פ*˛a9jomUăgn#KX@_-lVa ꁉh@4*x킼S/5)>g%ҁ&]X\2?C$#(^d9DbGͤ\er YkMpBZRE<Bc|`S#PyE=dM?X_0FυXr5Uڍ\nTv`aVN$K2lv454&j-A1Y׻n]I3g 9 -ہ ߬-wY{VQ#\Ec5sp)'v3f>Xj!ѣC+Xx/u:X!u-4 ؖ>͇"k>qjq$!8Y4ej)X-܅FMw)//N-43e0m_E< 32yU*@y~oeNJl_^ƵXľm_mZATjP7YORQ2*6WYZHHXH[+׋`+>K)*ֆ3b-jnևkrfY *j)x-Z}C_}maJNuԣdO\4!9(pim<*E,Pco@k-^4?PExc\[n҄2i^pW PZ MRuxr2hhάW_ԓ AE SI@ 0*|ٷR+_NEHsy$]PP!i<Ǒ{4{0۠~+~}AVaCp|"wv19c.g==TSFWN3&;@lqS\u`hýoN-7^+~7_MM7YMوrLۣ"&U&H^[sK:uZ$wx\L {W#V̒ΊVb݁O4u U l] $/9#H@Sj\*!8wsq"@aB|6uL~!{-\B\e]uTYH \J\y!3Dx`-GEkC*JN+IRs@\GYQ(V]ulv.>3iq|eEDT7^Kv w]kpQLA:ʰd枕QNpÃR'u<;5 2}Qw \BeH?oyo9 eNC_^>U\<8G}B1VEHsRj*}amS|ҵ%,f>%35n+Gjw7`i![2"ʼn6YJ~ȉDW ;֊G1St('tm` $v"16@.b;+jN\_/\'G}kNk+QcN O`4ouQE;l}.xOZL- 64(j}F0Hiy {k6g,q0PAjOGE^Q%J38"g͐&;[bQgd,,<,v^$BVa,0&ђ/#_/ȁSEm:i۫nriòKe;\\H̸O5er*&$U Q'FjRSk9}}=,tBX&L֛WWgC rL+/?$Hl6HSo5R_4 iD;tDyY`uTNg-*_:6\W ߗK7fMp^?wb?~(+6WŒ/9j][q5X$dPW+8IH8Pf;}j??}9BŠTY O+H*b'j4SXDe]/8I&.^Ƕk.Ovzʳv3.g kP\`u',>m4ablą? E~fQb#صRBdT+G -Tm yERHoZϓޣn|iBވ:u ^iNVW2ٯ6ʶaT`b VTJ5.O[ _e*īfim"JѮC 294%eG~[7 pzQ׬ig55swF[tj潎 IB bi4?)x5p‹?a®'B8ۚ?!\XY]؀T?)O0P@p2H Z3]!gdDbiQtZy{WS&Q"q X<"H/"k\? Oɐ ٚY]'Z=kcș-yJq_sJîT?9fm.2XF0Ta>H(nԓ`JV'\[*0⒤#d*VF1Z3rÇdXCiHVNo"|ɳΙoJOF$Vm7^WM(8AB, ^57e|Fl`R:rx4vN+}ڪ6՜Zk쨅 b*ڬO6ot!*iм-3.hު(zŊ]PHWRT*[.!7UV' cDB|5`'[ÞH(KJ':])}0Bs,Ě97[72xJlfpEml=ʫO+t&Fa z9]&ꓷ,[]LE&52f$w̧o),S=MNXSgJ|' yOm' A#ډbLj%=k1SUNt5ZM177GH>bƾ6_߰*ͱPhl F tY;?`UC[׆ϫW[|POh܌j 1W@ib2S%e:eZ59Z_вd ֠. 2QZ;\(%ö,dYbA[I/]Nh( ^cf+ɲlBHtZIIj .8!EF'0K͍ Yr5> &rDw؆j;pQZrꨥa&d&2y5ϙg%]Ee*]\$P+k=CoraX2ݚ̕*RIc_{ĺ?dE%gß˿? ?Wt ~$ "HrKRQhxIQrPH04^56Qk9ffIs5&ލHf'Ћ9q'ͥxM..bW?PV0D<=>m zbٚf,*-B]F=*D1uCfq}O+1#x ASlgLFT>ޘ֧23Үs#Q'Z``8 _HM0,R)BΎUE/t 䎤U0#]%%ޙC1d7[Z&ѠFTRcAEma5(jќ94S* $Vh7(MVAVO^y@WZ=RpƎPQ9a[MmKNgSy2kyrWtŪ>TW5/+1hy8-Ek)tV'֙Q[S8:TcdՈnS \W(|N'ef>)44IB<3b#Mm_vdž^!2:ɸfDA֬Xxkka\(ys7.UZ|{iDM4'/h3sd2Xq2BW vajGHװ6B˓guOM˗{NH} #UCNU/?\f >k"Ev4U h7m\^Ά8 -!E *b!WvYX4ݠh\6Sgg)oI BW3rIF00̨Jx `oCJ݅,^!ĨXK.5bHQIbwGNF}Z,:hK dk-Ĺ|qW/\^7 9Y]iIxtt$!rMЌc(a}y , ?P YH\VuM`H!AT3HF8zf=$ ;3- 7prjkFHbq,* h=vge{8-iJ{@D7J$"Fcv`2m2i5΅Ql8䷭dhg'g*}qAhmJ^ҙ Ȝ=,n+@,JF-FbBiyyKaΏm0vMZDpϲ٣cY݄o0+Šܜ n`;4Pz±w)9yYLˌS!_|5?f͎!҇".۰gth;`gFX@m_yCle92fZ[H9oxLH6㏨dkH@/2cCFSsW&V6n &H=¢׵^IbQ['BY}N<5CݤbQ#NvȯWjƎ/_ԥTVE3^gNN 0q!gļZdn|DcwMeL&5j^Bu0'EV_*UcÇa<1sE+]jWFB-4>%Q|#hB<Ĩ٠ 5\8eq7vo phu,K Jc|g]h5ʪC3`7S:j麊Y8&{*@3+6;D hɕ[xnJdq=YHf_\$tHJJAȅJ|P R6.Z; 04e`\[pmApTC^(S1A{ښ [P\1y\2Ű $ð0KﭲږFO^y("Ч7H M0"*!=/-y;ʠlAQc-;=aFR+7 t/[3JjbwDU:q=};q#C½@&mQP;hH[N'id]Mo<{_vmbC)^];Uh} A6?rִG+#PX!K]H6 %[ؐ$+&3U3$(+m\Y _l7b㈙vvTp4;,˂O p(rvDv@Y3* GdvBVs.$ܱypC)!.*YźzW:7d#}Eס$d+\Lq úN-njF+ M՘ nU`ֻy@"0Pl}.d^Oa+{Fe)T4V'MMW3⤲ !f:tJz!<\~41)~Q@"nR*iض{ ItUmQP#1KDoʪ0*HD{FpxWl #$){E]X;BKȸAd8w"xfWaKGg( 4&+W9|2nk\/(el1٩gԞT1kCQTUY3DM ·16%!%F<]K͌S/؛-np ETI٬Y& 72O`3`V)+i5_x˜锽XF @MD2ڮb T)p:ˣDtI'. $E>7mj,&k LW̠ΉvOe[eNպ%ؾ+ޒ~Qm&YNʼn˪qCB%"ʞ>phZj97I,wLk›v?ї&<.K&2eR+RV;H^p.#ˈ*]d/lj\pnp*D$|& ho1'?n6-Y( 5BӖJeviP|8*/`NT<~l9+<[NkMtS7ӏFR`8m$O*MBV ZMWcř}`[T$q\EFH'yBkɒٙi"W..+- wb|U,Fb:qhL@;B!رbOz]D8 U n61)7- &H+8H:jArn81ceܞ K!/,S'gz{Fn8e4*T؃t>5ÕrD37B a_Rpj n0=a2:Puْ*١VfnU*G_ rrjRDmS.L]rކ~8и^7(F2 j1!2`佣]$ױ(A= )U8&dyzۊYwĠ-A2rjhK`k˟*A'rmvZ|*hQ{5jcFI]1K,8SWIT)(Fi?\|WSEjBMq9-Đ_vcjFAD @iLJ NJF&F&djk Lvr ?Ϟl(BDq5V .x@qbFtI5åÅz(vR7v Q=.:bFȠx JoF^b=h<@*L.ƢG㦏aÞ8#w8qh9b47eS)fO^E=O:{;plv3b]_X&p!gV=YP%q ̤r28N rjGGQ?L~]FmpWi+/6Tx)gі{#K\)h*jU9ѵ'nk"W dzxwbsV8f$p4@!;A@P kH}@\=H bsL1;Hs6 I '|&jA 5T 4u +s ֎}6GN~F1qMRJ\)ɹi{!YY&6C%&$1Ss7(6"[PL#9$6rvMEw'(WiE88[ R[/,#ЬaF 'r c`!kPLuzndfm3'K=ffO*(d8%.(wʢ&;](ۮhGMr6FDj4#ܤXZqPH- fTM\PSJ\,R gʘ/0M4'EhΌDlgJ[vG R%;9˝Nv^!#y8:3Q2%9<DU>i< # 7\13z|yF/Ɩ g:C]hBsq28^* {-o#^ }%NwiW~TτchAӨ fDц45co}rgRjT8V3\U0#zL ߠKr (^M254\Cб}PCh6 >Åa2885B 8eH;d86z#;lj.P6C"ΛZ  Qc' *ѭFJj!ImwKC}A}XvW Yvb(bi@kXm"抌#!a{K5ϫC0R \eP qQČsJ8T9ZŸ́JM)q#5@*݃%>#1ʓm,1$!WBrrPވb'7sokr=}Gx;t`caCjsDeɁL"V2g` k]>2WƊA[ 1l %iW`4$_vO4;בe05P}ikV̪@d*ƭ"{1Z kjgN^2ڍw' fXRǰ}vM9h3~ G VN`r#Q$(F5.2 NN $Q|l2c>h;zFQV)޲4FRӺCYJ8Uݚ} )`>X28v`㫰Mdž頌4?{1%zX\*kSރq6jjB^+sT:<&sS44~W`cCnb+;qwi@p"?Ue4!W2+YHZ6m䋎 qEUP' dYC3b"]6b(j0)-.^'x`~fÄں\XuJ C|Ζ?\/E~nO}ix  1p < L)@9,oMhӱ./-{1S̩ƩNA.\ݩϧ;M^V6w>c|&y_^Ad7ūt4K`z'ytcwYaKxlbL; zѐf%oo= ŚAWۄ޳$p1g+Z̎o㴠ְ$Xho j _k?~wʡQ ln`Xwi*>"ABĊEd}q)ܠk-FŨ=jd]6zWȪeg"p]t\+͈zӲ֡9K"],46j˒G iYҶADՉTmRj)xhd >H>ҰʐS⸵knYI04Ji.}4Ku~>,'9i2NC)00vϊ^K(Xlo276lu3M*0:Mo7j\!K\~&UU .>8E`[H]bVa'H[j{#hcc(ʟ"\4bX6;Qϝoג|%" No̱@E"WP8ovZSQvSvkݡ]p>qYQcag5qբJSF =~j󈇍humvBZ5o*J~̳NkҲY\\x+v$su>YЅ4<8-\;/bQ &IrX,} $+5-$oU8^vFVi]u[(Le=6bGXMR,43K%1(-jgЖS%?YR51lT(i;}=1G,*M1-͡)ۣ F Ga)]pc`֯]= ZV-q{Xd'-#(Ho\052`\8l~ T*͙g~Bƿ@ezaHTl`kpK7U FY7G!0\s>fw.% .=e83;rWHĎ5uR f+% .KMW]-FQvGb{5twUTZ˔,~{&~: f( )=@2W_,:UO|E? 5@snc=G9o7UxO E7|s5H Xf,  e˪܉͘'i)N#T%aVm~"]N<nOywɿIxqŎ~lԵ#ݎ5e&4M̼Dnu!PDѴ(p@CHucD_Ñ.h'Va]be.oZjOk NsDlzU>ÿF.D2pp()ζ]`e>uc̖4=[Rq%Ʃ@}@b"`<*ʒY$+mY 9`P7ҷ}Sa̦<2H{n+Jqȭ,^'6HHӣP%1V+FxJ۝ʟ\n_G"hFNfft+HN7xcl TUK,ѣFM; W{垾 S(I͙‘̰=L#8Y}5X;Ki%՗mKpnߺσi]a5UԞR xZc'+.ÌQad`c602Go$k %3b>.%?SƵ Jjw>psoL=ك)J6;?B |*Eܼ[`FTrnY>+)e |SF,m-:~_eG=*hR͕D:{='(ǣ{8Ε'U0*:N@NK+A8s3]ﺃj;H/* ꑺ当S{\Y))!(by{g06wv4T;uwVE_dP d֑LɌEV \,RxZ/i H~&{k|v-mKLLp_%b_Ifoqr f+= ҍiGԚei ; jJw?n|*ʨqki":92DǷ). U6V`kYl]n<-Qwqua_wASK[;eJ֕ny# U%_AMM k^Oip# 9'?| #Pr)&1e"1\MZvg٨0 wcI?]Bvu_FAm:s/g/ \Aj| $ɒt>ğeu[)xV+ Vr :W,n x`xS~A zl<㪒;ۻ#haxW(7#7|[fE/)fϩqaR`[^D3lHi1-*Wnϑf6EziqGAK=?H7V͹tWMb3nއv:ģK]FWjaxrbģ^x HLPL WQ=ՓøiR\q6MgJj$wY)``<0s!#Pǝftڹ3{f#̝ 4UO8m5gլ`?gOz+Q1)wZ}*9A7ybSRL>r+53fX[tTE ~BJٸEOd(-O6)Bߏv`kdgz\6֨4vOIm5rڥG+n;eqw,pYɦyΣI)07'Cĸu2t7s^rAItX`ϙ0+&I\a-[s\-:C` ֍qxAV”f !r}Kg޹Cn )o.?D4W6z^| &惲`)ȣ֖wS -B:!˳^$G0}@Lӳ3Jm6pBn1`}+$RAFg>V!B zuKP)AXzv;J% &Qa_+q&,Ed+H ?`/"\|+8@QUcEጰ2׆h.mz2AP`WIf\mW9;*GQ$[e?jfCIQb~ ; QCDG}RΖfk}0o&2[a[ ~0h&w):r 7X ~jk>IiKmdќ~( T.ʚp٪R Q3J&ɖ8Od9Q6#`W9*x Ll󛄖vYjKŔ^xf]ԔD.<+k,T/{F,Hϰrjbv[ Wܞo |AkiyUY w7L,VNf yQ39 djat3Q_tlҒbQ /a'1ۮ{eܧ));v/U?Z3V~u YǓ;|aP&=tVP)@SF$-S= a/ɥ֬B=SЄM14O]ΦuR #ͨe2gwWXԐ4vY] ;-U܉lƘAW0Xo)x:oS`:e)'7پg? @q]"EOć9pƶ,s?lhs:,6~% 75I [i hj QUƶ؇B90EO+φlߣVO{$/d@4 ^K}lW>![ :Jh/vC$I'L `17?ly( •xel5a%g#hK$yGiZܜT,GAEG)dFx =I l0 P^.]d "+"g^N܀9Mr!Fbϼ~2^4YE">°$z܎)M'v I+UJQNGz(VK!9(d_Wwg}gI:;;V`l65@r}J]`H6<@tYY [wϬ(RX"{PH!xBe5WW6?`\+ɂiL쬟NO&g(B=KL1zfzM`]mJ O0y%DR)h! ΔD7CA=Z(2سȌ`w^pg`ڑQaI<⺶NVQPhI0>TUr}GU+TY$ړuE"MǶyO[0+c}=+9c=ʯKǕenw36~w:F?i)2ҎSWSc/. \=tq$/)8Z 1 ( ڎ4O3H3~)5#T~ZM̷VS#e2ˍ:/Sj% ,u%{xo)S:;Wՙ[ 6Ҳ]ݏNg_Gamm]߳.9Mu;Cp"[1.͙+@\Ng5SdA$гTŕzřJ zrH{f|xnO_!rC0!vzdF.!#r-vs]1Iqz a[wa9Я˼#znCr3#C™f40݋UΜTɛQԩF;LSlR)g`/cRO*)quv=|4Nlyl<LqV6b?F]1g9p'mc's҂8$ݏJ)6j ,z=\>-<" M:KX2J,>.嗸& c ~v,n@b~:C1y t3Ӆ>kw5/3(]gnZ|JOiB֠gsv_`C٘EGOJvs $dW9'}TW1|-K`WZCo\U;OEvvABOuޒ(eXv-ou^ኌ,sp*v%Rxf ȼ[)\ǯ\Ic`mKn8>N+)n,_BQwKZ/zu)1[QvhOA۱dfOXQ{iMFݶy~xJO>*wd95\$@7I028݌%% z^5y\ZhKy'L*ĦOǞ{n"&N픴gf6wz̗]Gbc=ۤMR1.)n0<-w sqCZ²Εjϴa$Qp 釳#29s;Y9cL]-޴.ޝO(i?>b+lJ),!iL ~h=%skm}%L4RAyb#e;9#{:5^".6GDAvH& ":fxQ a =Q/)'clO~j٤nP+W6a+1T있m9VJ%Z!WDxjaf0u͐oaaBFJtY)֛R?Av l.~ȩ*@RkCVB%u݆]ٳ!,,F{\e:ܨ"\ Z!D'G{jnU]Jc0`dW.޼c"͐'Â֧b`*Εgt_@h)c0T2\!)aOHy0Lc'B5 Y"c0 )mgR$a(|?Qs@Ox:j&Ab챴/fidZ2ئQ+t׬5|C r1sօ<]d~QZM?0J*tzE}eN];p| 4DMˏ#/賨^m̷uf&ipy%MI-ւK6咝 ]sD?&b+y_S(ā kNnktXBYT#%\ZzޑѱBn^k,.ZܑbfE:DXp̖%n`Z[Y,qf\j{WD&@C.T4:wB8Mdžš@kwP`Qr\fq-sX؎*aML$#φP3)J| ZuBo;]fJ/Rc[c q^!ڛxzEà "D*M8N ]ԡ{ΌIB-y Ǟ=eQKPs yx<,%w=mζek-&VOpSqMD'c* ̼c(j9ADl&R;gf$kH:'D^:S?^.NNkڙn_vSMmgzء;h3jO;j8?:!!PO=NQzqf&wB$k 92>\:{ׇc1RwD>.Ek7H cOGA'`Vt'ߕòڶB2^̰M58;w{IduZ_#܆uh&}B2|iN \fQgIe+_i*IA?wǦ je,42D6U«`aP];e0Πjz.JcŽ|,͡l\;uD^% YC8ޞ ibtgf0ڻQ oiWԈAi(pxJKw W I`o=w!x Jt=ESEDx3;AWмS>B`#$;&[/#r>P#]/Jog0<[T,!NULDHo?9DZ PNX잩>?WޘV 1%o[ͧǒ%TOr$/sOIx6b0AS>m <Mz{M Cb|\7&Ln^XKc K6mC }L^|W]Mw{-::#IN{߾mDXrSt'*XؼUިȝlaMd'Z0:l끚2f8QvI m|UX4@[[{l"ITBX3$FvݐVlm\§P^Ύ,il6>pI7#8Hi*J?>WС񅔋%n1dV`r7?\ټM5rNs5>V7)[UC=##bABP@&?8{V蹤JbrJRYv«0X/d~1ll54ZQ7dk q[%x!bh!IH2hTwҲ]ۣy=o\c4*:*iscւOAC=i/gA\e' PhhE@f[;Sfqt/""w`fJ?[t}_;mSB]x| Tm2 !bgJfS]d̍wP6f T(^n1I*"SCaKN{,6fw}x޺ ~7 R#Mjt1ŸøU86)ljQmXm9#_[NEQ|UQy(A݁ϸeJZ$!~p-*Ã2Fx%yq5g0HU]OAf yZ<0,}L'axjW-4AR\c4.IQ8V@`L&I,K榝-[N7KE}ʻ9j %=C )qM3y!=e ft+nzᠤRt{F!(~iC~1ɍ>۹FU+Uו2wCAWZBPE8p%5pu Awٰi,nlx0E%&Ʀ>KرR-G,ڶ?R ܰ">.p4ⵊpaH9.]llזcX7]i2(N79l1jH"g$Qr[B߅ }miv+"fVM_4OV2tX6 F$:6}~O0"ss4C;>ʉ.sܡ$LI21l~V+3s5+hX{zDh1W#B|P99{{rUPU?}ǶGST*}H,ђ붍A+ F)cϩ oҳ{pANT?m?OPvUaJVO :24:2~fi=ul#_<g%tg"^q<+&+)yR,̖J÷xSHŮܪT;-zL s NGSuNYҦ"ЃJ"d$Dq4NFP{ h5DlVǷ]{ng+.4Ҫ[q@`MJ5. +3,.0h6; / O<&$p8rۂ1}TAʽT9Ǿ1A7[k&z5R%`wXnU \agہJPW&XIt! ӆ%0*GO?A]Tuf7nrvA#b)%=we^5M.5bzKy>㇙y%Z `AKi]#  Ovc ,cBڡcOհONIEX|èݩGdsUOlgk8T9kZBvN3 Qta+\tژƕ؟V8h5PYjQEm11$X&_%{X?#5*hТVUOX|ΑxiKޱ-r/KPt1ֈ290K{-༿ J Cݱ(ϔئtս=gHՋx;qW-%V>8T3#Vz-H1_>.50]mݡkl 6*YxmY:܌'r9 zGG_SG_ D}++xt^QuS* Vb?4MN;YdFdx&n~W#jq`z98뗕~fm_{V=$Y"y[$]'[mx׈];w](XA"ZqB ^ɣ=8 ܇,N,4@NhUy $ >™*T _b7mor'aO7:#_.=Q)o'`3i8b/'t=lJ>a6Y_vpiRťd{qs \V-NzJQ)+a)PM1˺.$N=G 5M .-j|vTnF'83 AʝN;-ׁd>sRe4nW3R#IiM >%sB~)L L*Hƿ1L4]A܆n+t D(ӳ$J:ȔůV)$=O pX3|w%9< `Sf*Пf N=3)maN1oe]D<8-.=$%Gl](=+krr6ӢE\Sm=72"G1u/זMbC5S6k5Jͱ'~C0JClQ~e>,?8_~77#2_e) ,N/WMOP#㬾5MD "6v(D0dCbpuϡسSveF+AF$@kC⇀lfesM/]!@ gjQ刳RYlz,/8*̳5޲Ro5ϓIvu#o&.Hq< 8h[SNcGNF-+P;U 05ΤEATF\|3j _ ro$ew]kX(nwwU-aC<}JL 3#uf90s^Te!0o>P$7r.b{)^lizޯa qm)jUtg曀-:S'Cq%IY kH1N H۹zMFe%{ecXW!^53tc>8N)p|je el(G2BiDRm[Po`]=?Y7t޷RB1AIRw1ڳQ$9u]m`/6G{*ƳaSG6Ï&>i>ܒ6*Ky?+ow1syg1ǁ/#h;P/9$m{q[FzXie&:p7 Rn×"cI ܌҅ǓLbiWIMf?HcPsʣY_>+,hbj.1M;kr'I5u|F 0{_R]r30|Vܿd.!l:*#aڌ[ݳ8Kb#^sPj63t = 5{"RÑr;~⵰ΝRu<8]fLQaЛ%ůݐ@79gWӸ R 8=AmZc*̃XrdvJ=v /5>;DZ%$9Gg|-i)$zN(mn>vuO=ֺSx2},Jl6˦^sEHuwp*haAc[R 4_:Bޗa)%W2 xNNkwKٻ2sA.P{m+yUA8b5a0tY"GFiKt$p^C!/mNFvQ,*W= ާĝ5(SxG, ?I4`eIm4\j[nt4Dw5{Z~rקw ԴnHSim}nTp\>I&Fi!_ib/qY9F/c ꆴS MocŋsT~^_ѮsO?s) ]dW}]x wiB/qtEypsئp~<`W#V;7͵@ Mo ь$OZtq3Pmt`<] 1DT*ڡ/c-3cMIl:v!8+IJ 0˭YīN،G7R&ǾC[Loѯ56}g|`ժ:z#^WOE5+cV we:W+}mAc/ާL!c9(%:TxhE<+p2nŻ:C{[:fViplǐL~ĦߥQžD&^  as[Q\}-2`ɧ:7=PhD)i)vg ]NAlYgd\ yR|o=.^\3i<15*(R.|* J9°I80iƥM=0 c p^iYrnJE~ Ķ!-3~p?Se;iBt̿6JqJH$DnfX/UlX,{S#"p{S/"2iͿ}䑽՛c5eE&P(ѢfDTUIRVI ThFeRf4) m8֦FO&2"(2˖έò $մ"㋎@㧛}g"doK]t(aX^y@i9u`ICDEe¿`QG,:3}V=O1wV[8A U5\m!]!5I·9B]G[`[\l-xb-1ޥhSԑ 0W>ӵM.qߪrǞ>^a$$^Zc .;xނ6ڡavڇ8AC]C0VB켛^[q@z4eXE'vх0=ׂ*3~ռ< ^OAbT91ȇAV"b/J.\ LFDP=PYշj2j5*wz-Ƅ|IwF!HSVr%dACDYD^ɚZ^C'tmḗWs~l%<(6I mr3=pZ 3#.,[*/}t?ja "ުtDP4 x9zsvH_z~ ?mdJ3x/]; >mI* ,(x$K]rRg{*k4YE`A(o )TP:m~><!fvRs>ʎ#b:.[c&˷ ?^~9buϭ:p9܅9pQOs3lp'Ac;$ sZU.z!zVՓ0@s۵JΎ5b֑=۴UܿK%ܠPWxgvhݾ.v̪{VRGWcfQ%z`\?CpDm_ø_V#*fd=fOfըGF3`0,d@|rILL߬f>6)1jˣMSƯ,+UV*V{nyeC_{;kY̰Ul }/PA(oj7M?/&}_`\e 2huy]E'K]e^i'68yMA[ D9Kḇ&+'3 H{9'OLu[}!zIօ-R Ds0Kǵ|Z~-z^37uAJU ~z#򫢔Py$+֚:>ۢ=iE#t3m J,W gyގL2s0M+U_ PW*n̆O t0Wf`^)1Ā\qݫ5Uv?'=4 Դx%r׃{|t*3$!pH7>2J ĮZ# P׍Oݔq[@7~3ҶNskY{p{ȐBkzj3܌/=|^_O+ieгҮ.D,Msh4aiN!_繽:Ie&F&I{ޤ+(APK)k\w*ޘ80ZC!CU)xz+0G- B63&Nx<8V% zѷ- ޷Hx_-iʇ_.d<*-݋Uga;{uub_x Q{hi^u 8]Yu\5r1̦e"Zբ;K̊PwSW=@O3YTOi.˦o91DrYgFh(Ί$]H8iD:SB߯t<-{/jhMjj ;b{c_a)i J$k5!0}j*m;ƒ@rmPCX fg&M^2Ep[?24J=DIsFLܐ7~8pJ#=c XM!cԂWB`]C=V2i U#xGw5wWEj cXy@ѭa{5:p>lެGkmqk-7]u\6:GN\gcJ0)֡b-3nw|@_e5xl 8E5N"-0}5@JG΀L]_t;պG{,2D"U)Cڦ-/]_`]lx5lh 7<ZA mMz!wj఻< Ӥ,:+/PE-:xTԥV^JBp+d?O6e7f_HtwyyS.;zwWa0,l#}N? -p(b>~୭5]4Ds+z}A_@-yQo!x2H\ M P ?ءatMKCp51Ah-IYsxi\z[xAh?1(>ڑ>Q6w4=9KsOD:4>E`a-aUv"#%+qCťn$H/ \gׁjl,<ꦻe_Uuӧ!Ft^GFQՄ@MXϭty*늟 RCt^z}xwufגXK?4}YBçnΦ<{hY|Cpoy=8C/kݨxf3g:xLZe{?ffx'2SD"dILc>$S6 'BnEoI?PC?o?Ͽ[???W?~O ZNo۟.p-Cҽ(:WLʩ+?w⿵1Y*!]hM  N+QXk*#߀bKB.)3Mt/ 2&2*-9J$3Jgmq">?w-UӢ E.8]Ȃx89mMZѾ8:<(Xf-][l5%_!7ǛӿUy~;b˦\QNL‹>++}_m@Էh{Yqj8sdj|~|0]"Ԗis~۰>,%x驖7lwwzzZ} HhqMv0c]Ѯm DeelK߃{yLA $| R6 ݁:Y/d߸/Jkwj׫?^mV .Q_,P?>#e(SA@*o#U,ֲ C6 z]左UQPR@+Xq(!B91 z)3!6 IP6: S1Bq (^1XRʹ"TےlU*XVn0WhA2伓Жr㐄'Aj1@SPo*o|z}L'RH)7.ʠL븉b5k>[z;fvCeCJn28'h +3}jl!Tb\P^1QB PY0!>9EʸٕX3YA(nי9eTd=v_MB3 %{lHh&jt}}hK@ Đp£gsI8k) :0dV-%Z⺣BͲvAoSU*;&[SohAwB13sS4 _z49Q;T[!G&ΜD]tZ)θNˢ9 JU#W7&< s#t#UqmԍWxѲ !&dffpOUMp+ !l6oR*PhyB{f檒LӮZh _0f11i'c P9G&jz|}V/=U̼<BJ7*H;J&3LPk `z**>Q {<`/~[ÿ+&0KaN@̩r Ld v S5im⪍#ZU bw/dlJE0r:?3/RL&j!a|z:Yp-CKRk^<8u+f:`V^{W0doDTO4,oUchҚ-Qf(X*I^9rcʌuWs_*JS `tIFy#-fBr3S mڮ*;>X ;!_pJWػ5Wbu.Z]*LVbjW3="J$[@ہ1;pBEcWX[nvNm wMRr74~FVU"!E*Yn-U\|8'X\z\" ֵX6WkĂ |O&0pa=ńQ;(2D|ĩ0S\[ICA!2uEn<8O<H-,'JH~\"% r/wnO™IОq/֖e=n'4BE{thW!׍IukvEeKF]YDݭ_dB5jsr@R,!zdθw&,߮t\hƀ9"`k*^ύ.*š0) ՜=x.\!A¿*G07]9Tr]`aֱW~2rcP@]PEl Vɬ*eM"7AdhBs6"e ѷ4gU7>Ɂy#SMaHt1"#+E1Iԋ:h PM1(B CJZ V7ӀJyx̌*@ɭLH ^uPgp}f@ #Vhu>7WlR堃 d>Th9U *^s0rQ˚SeCBAe34ȧE U͓֫r.% h5_4+jMAy=QQt-It0^xQJ^?<&²jfCInd}ɶ%UPƈa1;yXEޭa53ޫS-Q7/ ̮)} "᡼p<K1a6o!MC#jV>!mRL)F䥨M4)r`K}Qîr/ Tv<|+n#V_,YƏjjSg4{P%7QlXogwCwv`}b_kƠvڼn"zG(pm%B).aF>S<>U%;f]jӳн1IMTcx^-w3ٗNk﫵cs';}lG*3\xp40l pǻi.Y.E]vj3":9DQ:gBRb)e;qt{dmՇG%f@Ɨ&XU=r%@e%3lXp0:,B+`@s pIp|+"k^RdmGvnU)^*Ӳ!8I^~9W[1,t6s$:Nfb B kSrD[-2ՄA+QM|jK]-jٗU}q fddo{4jYS lmF!k҈j%䣚[2 UuoBJ ZC\BfB":s]9}'@ R75"*RӤPWpCbhJw͍T;%$#8L*to9."/ACMӪw^ƅ/ّV'9FlJ8_b4L"7;41w46hBy$)ipFM+u+Ѻi15/ 6u9 n,4R1 @\ ަ;-- ڬKh/8Yɵ6kƬ;z@Ϫ Mȝ2cԠn3$sR nr CoWYDPk몡#Ͼ\V6UB(ӄQ+? n).ȫA B,AN;Zi2<'#f{<s7ZRM"Mݷk,/-BMI[L|>@ e:1h`e UcP/kIB he,otC ж.栶$X^D48o DiS`>ƔCGMR*0hyo<T s0<YY VHm*@|v%[C 7[͉fE Qs`KJyH%n#mJ%!89\sӐYR|>c"#U0zo7cP(p.*̇WpVXET~3z\x!KJըgUGP뀖8W7%bb4Y*O@WvAV>^/EAVE R =@:=r3/kjupF+6em:gXvT-)z3>XGr-8j-O3ZӠ3( tc:+Jv6wjݻUi{N%+mdRt=2RߣJr" hx+$u$#U3XOn isY=a%t.G@易2Š!!.Cgǩ˲Y(4elY_mW5=ŴnkmV|,H8HPDP6W.Az^Q4&f67 I&A"A ,`s2BxLt]CJx*먗B, 9Ϟ8s{>9ĴS20B8sQ=jB(P PI5XT$p5=H'}+Wj-dØk0稛>Mh.ɾob !q"ͧuSڧ!Rh^Ax,^A@ԮԮD{O(xA6)#HS,:hȭs&d:=!6ᥣ3 VHש0.6ٵ3xQ_I%blO&E3AJ[K}5k 5b2wP\d[2ou;_5a. aXIJgťzvN zY^lԘCY Q [%,& !*=VHI IqWHmʕP8tA_IY:Ä1PPRu 3}iJak1ilDƇsьTI 2$PA9{\*YUvX>Lxm;̒X2߄bʔ| "Ln2jd 'diTH 7eibV#F"2n#Gq䙢oMSq `:FX 5څ`G3́8KΫ^ LNr##0)9K܄K8 8)-A{F:.Qگ!|8m4_uer: oĻJJRost DH $6&FkB}hLySgbvI\n~M9H%bvgI۱EeUd.-`;T0p#9hcpGIFzx'_CP:pll _̔wu|MH">$ax@) Y/J5 o A]GfchRPɍ\81˯~ DoD}cP.p~S:*t%:5M&CmBȠ'&ʎfRMeN#T@!M8`"@E2gjF"iRIQEDYMDzAYY+3)xD`^ 3Aߘf!#J8IaA0ePV)^zزRX.jUq C8u=ؔHI&*`Q pGկ)jAPQwUե ^/:lRВ=;:pnjTBIV\tqyiTrabx xJ˕iVҰc8|1Ŕ>Ĭn(q>֮$TXC͆42L ʑA6gXnQbK_2\RN!Xi`TLM{n mZ+FA+Fl}R]3qu 4B|qOwT"9ovp3ʷnKVT^}dBqg}uȨ:[9F UnMnN6;97$qpИ"܆43G ۛ| Eeud&2-pf7"n}qeK fO\; R"ؚ>3s4 0#v/U tЌɺ%($C84YCWEހAD< P'"K Qps-e 6X+kycJfC$[NlDhQY̸ȧM2{cMN qDfYD8=݃U2UhUl;[0 !@)'1Q& S0Ͳ#$}`BȌ->.<jj/`VӯP|0 ".wuNc$ǡBݣ;s1øIQ[ D~~ u/7yg*dڎ5#c :Teȱ!ǔ\4Xq_6BqdksJ_qsG6O!6۩k=~rbjssM+ONw!HwT7&1 6/yoz-eC4#%ȼ>f[R2#l"αiYkiQs&u2KkJtS "W8Xe׃5+;tdppW&`Jʫ1TEbI5zǍm. fxa.הYW'UF!n&W3c?kUu!5fPWDZtL#h,Hx,Fm#} W!нW{{vQKT0ST(q+^J7J pJE/B M0erG}ͩ; f:I)(ue)@ 6Wd+)Ř]]K}'Ef(r>ƥ4-nxXWpv ]"A?(/^=TVУzѵ7O0-O*fG rSQT{gŞj.x( fKi_:|H*_4&% K9=,}T)d` ]WU5M Fҗ{FX}h ^S[۰+CE.qp|ƥQtM )T؍W;Ww<6wDk4ƶbc\T'K!D!ܯjU=m\%HfR ;v,5(G[Gy2p gMgSpT@4XJ0:;"=zőJ5U2ć^l2NDIToA:i߬!N[9`:c嚪 j/R :1(-Knc\8s}sl ϑbgGG0n|1 K+Q\ sXLj R-(< ?Avk>Oǩ]R6xsS-373-Gtdc I'mدaPP6u^rc!`iWVƸW- fu2 T )5S$1VHZW8l&Q(e\ț"2+UM*KxjƜ >Eoy &fzyr5y ވR F  Gg8 dve34 S?e'ttd`_N$Y,@*0ubLU4IX3{|*.5X gIG=v]aqil4*UPǐ)۠%Mіk*QR"d",Yb5:ެ8T IN?j[׎l$0qQPCRd> ec^g-_LNh*(۠7i\Pt\M0+|*F*~~XvTUl^h%[jȨ czk(7mI]I;ئ#\~l'  9.-w*#OE2Ok֕XZR G``Bؔ]/~v61I8ix)9ðFN%LiADǪ1xܵS޺*LX;ŮD͜5Fa{ƹJR:QNehDkGʄ rGzTS͈"IIj1Ws L^8(×*%UL|-GԑTHuEkeifM0aT%4blNsuME-jhM:ǚAiLA𑀀 #w^*"Sxd88lSq|ki.wT{3B(=UZ6nCҤq*O ivGmԣɓ`'C&ػ(Vlu("JoO[@Q(Lň]#@QW&>KQyX+4/Y >BiVp'm:-\q,\@Ԇ=5fha͍1/uM-j4gPqD3@雦OPAQU "JEo|GI(KVLG "ydJ4Ug$c2"y f,X=Me&T$ىhdDR j j8 !r?1-XJ B jL:GFWrEuP ,k 7b;t]Y")_X$S{-3֔ݗ` \e3^ȵp(`ז$4U\ U/9)J&Ḡ]fPlb|W6}8-&&bҦ\AX\C<c5<*(WWQX7FJ+s65ǔLxZ?@lETEڡuȔy;SUH;[F?9ѨoxF8Bm5 RT=Zm<2pՠ+Ekg2 Ue`{RFN"a0ڙ|[)$ЀSxDS*QC`#iDj[;q((ru˄0. 9[8V{;\VkPyemkhO=0&YUTֳ7:D&'{ќJXIԨVTH8e-ڡjT¯/P# ;d:"5bӸT/#uq| 9 5gը)wKpi. ݺN<%t<  1LC(/+"-R7TdZuGh k_Zuk`"֎t*^92dM00eख़˺v{941^*$D6r򠉊061F{DWw50)#B LgbfmbS[W?Xt){4:eשg1='GV䮍ql,: ]LlzZN˗<fthׇma9hZQLWQ mFLjm,*8Q^V|ʈFU7 JXNΦo[, Ę%8~@łrیo:*d^X5AZ|"l0;zn: nǹ!ЪJKeuY UZx29αkQRW7rgU2v|򴹯^9ەsU_تjđ&cTan S SGݣ*&%4%[\N+A`#lAUT c<J{)y]%:G2C&qG!3S#nYF-gi˶С$dҸ:52Hr0!E_!aLkꮓwuheIf;%#0d5hukltR);TWQHKpȤ"qH셿WE<ʃُ8DȷqF:UTUke*jUd%$*j4rïCek!w4F%ٳ̬%=v:\0x8mS&Ԋ!Z\sU!16}ܐ0ndNtPbsJf\KBiNz`W=ei31Ζj\7:BlK xٕ]<pкl\a w4-SL6?5Rs1a:Sms73ڻ %5X>5" k~bDD:N4/.;|oE \vi>P#!PbEՌt P+{#66kBxEb7L?9CN8k:ԑ8@ۭ% sw UQ_tC|*?ٯ&QO{⬣3椪2t5ZKP3#H|%^[bQJ-* PnqZt(;(as95=dGW.͉V ЁD%J#x1?Xlସ!Gl{Rqy9TF79ȇ#"1ki"z9 _\7rPOP 4Ĥ_Ճ E(P34ithi$ 4?Qs>yX(N"baء+JXp5 ifE+*rѸFWEnjsѮg!hrݪ.׆ CggOX&cQWYUa:LʭƍVjSyC[1ir-M.[ YUcS Ο1[[~lMk0#鋽6eA )e21-8o&&*^Z:C7݊TiTe(I^vn( \)H;AWuKcBM:52 ukF.DCQ]B:0Q2J0լ$B1IAzMth~ 1se4Qz!ӐII@DsBzD^yy>C7W~^B 6FG2 sQ:wEZ6l kKDwb7Hm u!DܶѢWF][KpZ"CP ; 3Ү̎!];\"m oyy7"y(=޳M\XLJ:7t!e<MAV~SY E j ɦuVu1N4.Jn`5.1!iquܚV20NdO^bk͏AtnO֗ur2 8jY)Вf-C@g"-> X'h__ xھ]<j^Ոw3: pg !(bk#6*66 u* }Rhb(L~~GlkFR!TB r1Mt;vD:Dž ]rƎ +Gj3=G+4΂o.$N&}* 4 ; we^c|#]?6fl=?2y{1N{inguG`- d\!F8҉nÁ]݉(-laxtpS:۵|{ϸ佮=yŕ'^u}Y'N<;{#e#ܻcwn_}?]W;z䱫Nǯ8q>W^u#:zݱiK}{ȕ{'sx'Uwևn~4CT%cowO^uʼn<3vw+ON+<WVb?xv;H*0?esm35 JL٠qeߚ+j=/Fq4̻C@&=nߎyMn>bWO8qtezˮ8?Ѭ,}CSQ{;=|>{ЅmPnzPiH l|#r$1S]sW5*Jˍ}PPGϨ·ld] $̈́XW!G'厊JMFTt+FaԥRUHPcMZY2|֭1r2["PE6ړ)SrZEn#jY'6󠻀s(ZyӉދp5(Qr"C(GzP{RKްR9EҰM9!bnUeV7lDXb(j4g~ c+IcOp{$f)Ң\;+Cd!sJ!U+kPQgZ_q,5H׀F$i-H{I"}MU;Tx N+%d *"uF >Q0 z&b9`0lF sVrciUdA"J:V5t7G1M#T~I_X{!(҂?&R vN{'~[U9B8DгWtTl,M ԦOԁt7T ZZ N5[1o ^ݳКLTDy} ! JQ1IMC( Mq 9 н6g YT :F!m1ɓ 'OԸ4ɋڶ5e3й$/JDV&ܛ!!!zׅkRorkKFs@QZG)GVҞ,ppe/uxqPFO4 DUj&`jDV'8 ?$Ů 5ߵxE&w 1MVi 3M^~|3&q& glP&%]ː~jD6xֵogl",>FXЇW~g~62m?!Hu0G $ӖmGE$jzZ|:5EhG1)ż eSs..cjCQ8E꨹!RQ=ԺF,qi-5( (/ik`}" s8 :_H:wy3<HJF"J2)R_c&b rO_Qf?/d+Ԡ>53<ΫX?}&7?6C0f2̕*,{fRwF Kv;.{]L~{^=׶g?۞PrhSIqjg;cndX4у /A?˺ VM@2, IuT̛MCx :Uj;x2d;k*#bhLL, 55IxذfjPkG-(> ~b)#U㌅UM9^2 Kh&" G4A]-g'mj>Zg}B`+e*pT]|iոqc\ټ p,y6=9>ch-9bCu QBdYA! /|aeɇm`J>LGc6kD6cSGjMB.F'YQgyPhDG̪\Pjm^ƂGXSl3f!*csGUeV"Iϓ*1ˆUh3%1,`XmC ~v*[1j] ^A&*9ףW{D.NWԧ?}ƔT`w{oa9YHb݅@!8ȍDnB9(?ۀnx[Bu⽷XZوNxHee97;$(#a9R@ƳC{I.ƅqqr_o+ubՅi\[H'`jouk B-sJ xoڃՕ!L ĀA :qQd=lClsP5R~ۛ%pJ椇d-M9#9m#яDt,tq3ҵ416k l'$.k#lrڕR谰Y83̓14 =y}a4K>H#f# d#\d#4p44kV@#L6-L91Y<1j4.ccC p: d!}P5pd&'rj&wso֜֙\뙜ZsdhrhriQɭ8Z``FdaĀd+k n ɀM!7Pm&$Lrф y7R[&DvMؿ Vh7mTuCݰ!CqA9m\x ǩڒ',9զ1;^r&sG{ Fb?].IvssckOӭ+#]@BXma T=/̢K(+1CY4|t]$t9#k1Jf.RWnծO)(CM0” A`$L;Zk69K8ulHtYCjބng[5y̓$ wȘdsIc6{4z"XlQkrm~ay5m+K{V/"=ֻ̳ im#_!jIdW*Sj#SVMƱx+]Sa6ǚǟtPXznӘHנݳtpCA ޠB@fOf )@ª$70"t `sIVJgI _Jx团CQHK2 uALk=ǚ?0Ua7Sَ&Әm(4Нz35d2pnS׸fSNP 4kpՄ[0Uk! 2* ]g1͐AF5( ]0_Ƅe @kB0լadqs dy1yKPpMH2#pCZrae$JSkbD@f61O)V嶐K m6owiMl!Qikendstream endobj 954 0 obj << /Length 53114 >> stream xӘɞu -)%_ͥ4X+-mT`]JEX&IfOΐF(!Lv *bupdЖ:2OfYS{;Y(Wp@0RwljjJ8)YhC`w-qX@t}wޘ9<6I[5%Η+sWZI݄oغ[s57s,4x"%5Nޢ!'(2.vM&lMئ{m95c's0E הZFb Nhy!2:M(*';=4&.@qI:U°#+!j8 4Iֹaͦ:p{F&B^Ndy0{+B&&CY /CEV0 /:v2^=ݢ6 ~c"[]`%/qJG$%Iw jd0*&F!R9A&\3u A R'$P"vBYcz*R*+mNҺt}7籙$ b#J2dVwPk'wB4BI#)-+!mX!kYk-rj/tFz&hޝF`^űD-_9 1r0,&7FX6W`B .xÎnD\;=F0ġ'a)*۰^R2bs2H1ѭ,{3cOA% Ubŝǰ&j muQD"bDkg;&iq3YK|Fspu 6 j󍵣Y* {s$'=1X;4Ҹ"Rq _jWML/iP3q0zϻʽc'/?v ^pHKjZWo4DúZoPJVj%fIRp f{#V!Q$=)`[ k1'QnF"'N%6|8%Y"# 7sH]3آi\YJPs9ISϫ&7,$ABuM@ke!iIdw`A2@$2%I9TDgY}'ܗ(VrU{"A;W^Ro\ ); ܂AgB*R0j_niUUc%PRo8ƪ}Sc{XDWHnJ뚎RbGX>-:B V`EON O+Zo⠄ybϋ[*!%9(7kSir)-[tCUmҫz-nV!"eUU|!%cJ<d]Tw$!$A8&;b.4Sh"d!E 0XI#lB\Q#g^+Q`S#or}k8(sG%!_XeU'EĮML&TgHBٮryCQ Shv9GO^uţH=rYgW^']jlˮ|ȱK8_O^w%㲓K煗=eW?vw ?|ꕥjZ]j53ױk=zB܏IpP.| 7<WZi/<몳owN>^qSկN9A+^GK?/y#_GxsyK_kN9<_+zϼf)?{3N|W"j8'ޓ.j;?>/K_k}̇?)9e҃G]%z_}y_k}n?ns흸[˯M[{H;K/߳/˵Nn:[/y9Wy;=p˺حg$|5پ替Y nыo½9猻}5̋/~۷WgvxyP_pC/>|p[kJ=.{ĕwou;[+:X 9k{ι>wvVzEo\'ŏzڳ|[ =ڭ+:+f;Ͻ/ŧoo;)VvSNG|ӥn.}ޛoyOȶg;ym~.8;o]?|#_|x}GM-ESj|_G-?xI?Dg=o?5O~wlY?]rӌKwaϾ]7yG7_w>^ 7׿͓>g)׺}/5G۾ԍ7=徛W˞{S \?E/{ѵ6z+^7;'?k>ե>~nt'~U{ en_}+z~=¿|6S䗿u}z/y;~W}~~c.^:>U_==wKG1]?մ>7?{/ aBD3|y7GvNz_}>kV7F7֧?^Zwn]5M{3Wv!3n߽yO|ջhpny;}?w+O4[|;o?o~a~tS6e>z7~_ן4/.n_-׿#_#q?[N~s'/~^~gc{sп?i wa '_|jm/Ǿ/>!ZՊÏ~}ϋ/F ]q2؋k~:@n+{ßiZ>?.}8<~_db眧w~/w|Ez?_rn_86L;]w /|}|.R7~]/l]tyf5O+/~wm3~%ocᇫ}8YώkO|~Is3w%y廮G=gZ@;+ۖW>^fw?D1O{_w._zGV?ew#g5c+Gm~&|ؗOģ}Y.<^5=ןocS>58~Me{>X07#o<2t; vj:/{~n/ە;WՃ~vtf~㋓y=&_USz~v|?Xnpl~SKm~'j}Z}8V]9yt z+ {vo6ZHC~vOznCnm9g{Sهv}` Sin<{N󜉋7=$?zy=GNks;?] ;}b6;7t>߈G&^ХCt b;ߚ.L|RY*.tjGΙ3gjݦoU//ok~agVP6[j6ljwe[e.~μn)v3rku;wvCMߓL{sș ɿge+"ڛ~{,>kwó|{<{f{CK_]ek|uOanX|EA_}c Xѵ[FkSNdڒ?UWྜྷ?xW_vf͏=Clמuu6Mz[_|ϾɶomFx݊eyMv9Юs{gݖ{طWSV Q>϶ܳ6o:=;o㕯>5o-{˯ؒ77nCy>zW<~W |z#Z3fҌy YKQ۶m/mۺeg~]4֭^鴣 +9䳺^>&N;-zŗ_}7xz_{ys?I׍нCSuKhs}&OiUzI׏߭Y'!-Nn׾9V9mό $IhR͞&FǶkohV* zגX|9P7^wmrCܷ$M5 ԻO\Zj'Fhq;6HRGv{Y96*=lG/yP( !Q\L P0@Uggl~ 0ɻlD =#* B8`ҌLK $l,5U>H~IT,`>AP>#JP.${&l.VG&Y@ĩ%Py8+@C$r8_IX.r3_ >5HP,aZQҮ B?DI'Qb̠=KV}ɚM TR :[\ler'."NLh>L(VB%%Hd6J&LHa"$<01&ԻC)XIւ@a@ CJ8tdbnFXf(:-{$]R c]E{̾A&u@ci3qb 3ɎUoc:£y]\:UqnO7M'0}z?j h7g\(8w z=|W9c+En5}]|[:uҸ{>' r[{ԱS8qBwuM?#ϏG׿S#Bs꒾Յ‰GΝʟYwS(!ρ ']taG֯r7zJ&C0WK!y^q[һɸVm3Ftl⁰#NZh"ޣ.|xv+*u퐻`mo+낉u&h7?ξvt\5~o?t!殪!w!7}_}X' ?T彍gu=h;ɩk׍~1 s̽TjnVa"h Gh%(^>ŋgwz|gOY9.?~Ya0מ"y㡷/#~"ߪh+<MN:=_'dF-Y񤼤yBg슽W_`> _>[zn0퍍-OCκoӿ{j~{ATy9h)/Nq-m+TgS96{&q'^mt}E7lhyܜ[z]nRc}%}eHW6Xmi c.uYny°75~:wBzw*֒mz_v]=u ;@^mu+ zu_wozL |+hw<Kv+Ѐ=cf?m bjjO͸[Hr^lM'OKdBKԩ>rU3т;pazUS cx]ȿ_o q{bUeWhOLig4/T3;޽BF{|w/]8k~3kT"<lE1 X -U-i4ޚ*@^@C10VZT'HqܪIt 48DIzS hk=kԕIPǓ L Īګܤ<`qcQIPS~0@&BEXE:HI0@ .I8І Oh'SsIKVK"Wr!g`)0ib~QO (cdl V%*'/ȜP@<䤗 HOi_U-`]lUhP̙"Q{ LZ6-ES4Q( ЬJUUr- [Ջ6ֵ smJw=qrA^[m/D.LG3=7:5`X%@@R.0Tsc]odeRcyr_9 L2۴ۙ J< CQs=)^qX "ΕY7&:XMA˧121(؁@\B7 fTGeSF0\40ItȎO:ˆWi "UYGbAΒ0U$N&9bƓ&:m R"%Z)KF d(epZO R\ȵRo*,oCi~"h l.@W#Ov* }1 K bNbHx@$ii%9%>~"zcp^-IWKT/Č]i%H$FC\բJ dR6v̓4qͰ=eu1O jQmn 33-G9R ʘHf*}@V'v`щ/lZ9RPo&dTWĪbEqxvSXaڎ%k [_*&`3# uE{-?8Z5K`j M^D"!ˇrbDgR1D!5#gޘ.HLS[nLѮcJt\6Sx XPPOIZ2HJ 0خMbƹW0fLxb}ir-'x{J}X6"RQEzD4% q2pHɧ礲sfdz9ҵ#4j|Րn HNlYTf%~d'e$uU5&5ЊvnDY]RE(K3ϓ=G|ؕoE#'::7!G8KJ31[D ㊓h2yqH|3&u5#78#̌gCOCI/Ӗ.==U]8PNhrZJBہ,23c\-DY5~RUT;r/{׳L^: /mZckJL fPt#Ժ "VDҠƌa gq$8Y c}Lb݂K H“ yAgɪ ?/Ŕ+jZkZ,f UKH邉&Aadzq-'88Ս%.w!M(2í otkrI  f]vXQ&HҌ/ɒhl b86,fUdp7~'@$$1g|u&Wx]TQ8gt)GJH?|?|`ߛOq< E|A΅nRѤ`үM'8jmRMk_򛜠ܯZwzT"W.S '?.pT#pmp/ g4-wv?BlX # ?X7h\ؿs54r Ba%*EK"?δeuyEYc'*.~ ^unq&Q(_y' '̚zGo H/6i7SljE16МaNu}O>$?[±E/.tEE= Q~ق:N_0xo%AiM^Wz%3)H;+ [nYrr[eaE\wQ˗͜3֌5 ]/jw-Hw7+3dTh쬛 DqȎJػvAp6j 7手[lHw76VGNԽP'AVV o}~<mD|Ldzr-e qF~?6j.o"oȵ:ONz-XU,^P7uҩɅZ{Ȭ~O^) ,6Pi;%s1GBWlzi-\߽0߯<2ݭy6I/&wX<];?|az8޵⡱~r97ȟp˶SP{q7PĖycɞ3$w!޾wP8wa &z}雲]Ki.:]~ ӝglR8ݙ_$>N%o_V3(~gZ:;Iܤ}FS"lnŸ.{j{Lxb^{808fQfjq߮'MzvY< (ؿut;u.酑ok r-_\\n7=쁄li0w ]L>\?m̨q7Uy4~MUhx5.kK ;ޜ.+ _Έ S({t/H|oǎϞS+LF>7WO.zEyt7O{ar0זy 8gN3ڑYOκ{E%yߪ.q$ܰ^s]>6ޅGid:Ka;KMo6h3^?.ΞhLΩD_^C>$!2sGfa 1>i7W_M?#W/ffx;wkZ+>=ș}^z\=ñ7m\:U:US[]ꇛTүfhݙ\S߯um})8 > VGh$h'foA1(BgS7VL I $76c”^K*)0qF/HI_W{%{gl' ≓08Kl8T)8j[@!: C 7zc X-}ޢmQP%j]"g\R(=Bd|e&jD#Lc6iGB_# X&d%'8@0TRi@,@IZx?V %@][j`gm~S)!@hY83.-5:sbJ85">0ެ ^a:urp,eq~Q̈ PIs  -?\:GC,a ^\@GÄ\o#,$`sGqOꝘ4&qtS%/c;Bš&7"m`&fHb.Z'@@[\ rKO=(e62na{ :lZhBJkސF_lqE)P* ^.'"!bY3$Jގ8 F'+?YeY"˷t.&|*@y -h MQ~bmr`r%ԁqEcIc^Zz l/Gb^R:Ht'Jx:p+GqThЏ)0Syg /'-JNs< dpgbgxSc~0&Tʈ)kV:3T,n8\0)) 3tXin!Lw(̴#rg?ƿoЕMW*cH&Z$v]2?6]1o_s@hEyϛƶ:v\_2?;X^G\pAv9x=h㳴ZgU6%E>nSz]E"w 3N.e?ePe5n᷿vEXiluIrVnelBuz pøEIv,k1NVE?|SBy@tV;Szu?o=U >Eoy}vׂߣ{\h*;aޜYjXO7n\.\8/̝7ei_ߺwk?\QnЯzꅝ;w2zN{Kʳ(ty,ɥONA[ [A˵GY^ځ@?`zleԒ;-4|(3ŎjGPcMkduڢ&-̩O.iîC~ q䰳M'%7,=t}“K:,tÍ29[pq >uB>D_xd K3n%v'{t$޲e3.(\]̐zdSr]f [w\=cP\U_*Уo\=*ٿv_?sS5M=/}o^0N/5,}vӽ{Ww@/­M7ml̵CG 0e} Vߺ"GW&VrUO߷OˉL]SY]̶<`QZ_=7eг/*ܸo>2J}WO{wۖh3vepǶljܻ493Ltyt㾯OAI ^o^f6sh<.&Bw;y>^K[[\ Sh}4<j5o[qp;pr)l3/( /?Z6Fi7>6X(z''\ӃBI\惥Wm{^NMx/6>9< {mU^m:?t>vk'֣{_vC'Um+ n{o0k |u7~``o<\w|Poha#gm ͹e97 5]d.uãbATXJ|pTyrBuܣ)O([ugm3ޯV?8`{6]ۺnOO`5:ݯ_yi+]vFLN{n]$vaj7 SsN,VmZp. Q]vXyLb  J X: $0] ޙr B Z8-|s= LO)lKa&)W(Y8G+6alDTÕ;r2>cxH؛ "A#c5sIš_[ "X9jIM!_N-Ϝ P.);‘pgΩp s1fe_o$4, 2Q.,8CWeX0"ddX[A#Vwm:7X}q `*2%pǖ=rBy=+ے`oR0U(/vJ3#XV?/1rsP̺,FJa V`TvqDk <Ԡg O@&nP #A nV-@jj%&ekkEE%12P/wrWZ9uj 1E;ɑ[ kBfcidR1|XV!gtL G]W:ñ(WPz1 /2i KS;qh<2*O_%@s FDQJax?^i$̎`5Js%fc1>1=B0x =7?ai"(V3+)+vTزvz61}?9xam#\]?# s06+ 1/D^o\ f/w,xb k j.ВyOUQTA 'pDd™/ͮhHqjQf&= e̴TM} ;P뗕G4\^N<}M\/u𳼀oN;W(N<9an.~^(xm-"!v~B-U^/N{uӀ:>o~ELݷ)G\0zR@O9 *Dƴ _n~U]~w~mVQ1$/gCI L/n~1];O9-O E*cr@Zb{l o՝b>J{Z'E |75ԩw7͂ 9^ppz8gSqG۞ Shxm˦;]ޝN`9]0*C|l3LL9]r Gai79ci| ҶuɈ+{gnly8;FN~D:zcOD6gm߷k'R4ϕSQ]:wCLZP{4 ]=tQotsyz0 E='ع|ɴ[OX6ơ3>~]ӟ{)y__0kf-8j46̯5=Ɂ)6oDgQ*ӕk?j[9˾U›r۹+r[\z?14䵼odN+yӷ_,ŧV>K C[={g߾\W8oosϺ?/kr_{S=/#N~mbS}+yڳbΝK7FX@eEۖ͜r _m-qm'~ndw_m=Cxd~kStm>:'oL+b+tsT=.RApݫ@/U(ݾ|_s˞G]?=׼t&]6+?ܸ2%Ɓ=[V/{`g\|{ |lپm.?~`nx1U|_ooQx%ϼyd|  AF@//!8YSHcmS`r)""vPRRRE*TqԬ*pI0Eˏ\QJ\zN.0GX@k LjA=E"˱Us9~,JApwFK-+rgT "VNY4|V]1b\iPXW1<\O ,O[qhڰ4C''6 LMYL ۊUP,ħ," B GbV8UM Xƹt艪fsRl<2P)'n"5a/uÛQG8&Di/=pۛޅj^1iFag:ΤpR:Q\RRvVgızHE|1 3>.s&6 X#E'0cF)g)S^\Ku\dD Y8G%y"79k+!{,x1(5؊s/I0-A=6ޘ`}8l#_5w@K~`*?XO @T]k!RdK` it̀`=$T! f9;DoAޓ3, T`ƭR)SE`jՌdi("Y)R)EtiZHe*CYפE* РH$쒮--ڱ*|jkPp ,Ir)W6?B&-5Ai: QrXڃ֔ [!2X@6t+QfiEH2+UZQTr.hI+d(K"AYLD_("O QmTU L?IUqd$P%]KDN* a$̲ T2T<V2V "IjRQ\?qj1cSgxqS 3Y. :ee6C]ˈʐaHuX2GiŅ<[ |RN` 8͢\E1 uE1s|[YI$?" ^+Y)):bU`]$ uML\MLTPcȶ}-IY&vۧ<Vb)Y !G +H!rwdN`.i#bs⍩;j۳B-)f2kzV 09;P97fO{ hfXX8DcȾAm GrŜQ2Mcn ƙ]49HF0*ó082'sJ"g?DlS ڛb>@a 4t5/+"Y5c ?U(B2R B%QS3`lUM'ZXmi*[e|g*kke:A",.RA LYXIHWI6WjR%NJtg⦎˰&KAŲ$zEa"jUGɦ{ β|P+ "c6}-˚z+d=>,$hnP.wifx3Oc&av)p*; yG"!h{&l%BHZ(+WNVsCMO&˓ψUmoqTdÇlpy9BI@tc~jA~Biӧ膐i& JZ,SOeƇs](Z X))UvNqIه!^% EƓ==# H$su(b(a-+q;w!( "䅱P!7 x/Dv[;|= |#X-9fCl+qKqrEo Ml5ye; " (e^:pǁ@9(Y.7ґ:tB[OTPՅ%GWe8 eˈ6Qd9Y!&^P}^NR!G#N̺Fa ' @ &~Y$ t\,1pdžȓDbGlYv\r@JӅI۱Fne:^'&*NfZjYAqvPIb!OGq=3$:-!v-Z*q$4*D~u9Mx48 }6 G^:Oj)!;œ`^N,ߡ^t؊1I|芘j5T'؁s(Z 8h l'SH4(Vr\D,“x6|naw}8wW~TP:uJOvrWRr#"%F6T"݅$9%Q-jgxCT\d+Y'Df%f"J+Br51m)uT2SՕ2Q ta1&?TH҆C4ͥ)5 4#:{%u*O8na :|D&,qcx R&7XNX΄V: Al&l~ hdyrgX|VB3:l-U(T\A%E# rPF5cc8KcQ1OԖBWYm'ЅG`,n}cڠr8.!~Nu,CZK5"C8r&@H4`d6Pn8eҡAB'A:r쵅:UG؆C;;@7OFzoDcݐ'*F/C]*iܽ hW UW-Eш2{NyKIMŎ"RU"Y$O ydɉeJzrx^Ŀ7Vv|LQ^8l$ʇx;-^(CA&d6i[; Z& >0,5g򙉝r+E$) $|d@@=DnI?j;qLjj]bpl*P+K#ӈ6tK̾uDǮن$;SChh'-h~.SVN>e6;v ʧc=\t3Ac8E,|ٱuf= % GA- h.®нdHJHfE<6:d?!%O@S1u,{*2]"ra_YΪcV8> {Ǩ&avay,&í#Ó` 醳V"blΕpEჵjcgTSB>!6(1B=|ѝ90lj /pct<ˮIaAiY O+3(My$1,RWYĄqHt'lY&e&ȁ5fqzޚ0kfڲUfpqu9V q-,T֒ DFoI\N5ZnluLŕ1!!dՕ:CER1v BYD,N%F^ck?|3o?|;OYTǴKsH$J4zq#aA[yK|3RcΰoAW2MRt'2?4ՉF/&ؘڱkk"fXFkHRZ- =th dL C<$c[p%U0^0YsBrĦO10f1jҠGzdc3ct~ B`# 05%q$6{=ar@>\HM1@|FJ2҈NX`.# q.SRΖJt2m:0;1$(X=&h Ǧԩun9n[JPNmqN_q/$[`_eyp %# zL)ItlI@6YKRn*쥸RȲ>D@%Jq D |j'Gg9j\F)>4MhqFrKc*zȨ5 %@ʔDFw>ac.N׏ d2c/6x_i %f0|-mݘRÁ[i'x>}ƶπ`^`CͲDc:e/m?;b5@)I{R$ND0EmSLcc+ǭF T`EI6RA|OYp3ŕa HNFKWbU;@2\Yhh%kvUcVAFBi2,B T_IK3S\c )ÂW6aG.@a| Pcg#BJC @t(Ċ%F"7MN1u;d:݈#ùB̅H" 6U%t;%:|RP|o㹗g : )X q3*iWm- ,)䤸h' Gj ng`k1l<^cgɽ"hMUB5y *vXI 1d @j:tܦJT)Rlc+F@&!?uᙄ % ]a%DHJzރ&*L.}"6fergP%P@#Gb_="t8 J+~InJs/fE1lHŠ)I;W\=9ŧ[!R2WC!8dI$0àW|Dةo()lVQlCRMPW.qcU"6-3FǕ(ADg # F'G6 Fؐ)@+zN(c画Ah'wUeU_kq$* q1tdzU1M ZqY&nꂎ#zQc&b`kc:{D<#%frey{SL\Vk:~lJKM+WkUĝP_1jg̾+Kjy1>o| ;H>SҌAvkeL9WXdvZ5 \HiI]t=1Cdo ɉ憎^/΀p)Vk,y,'HX:P9xTKgoDVYP/O c@iL"L`=&0D֕Pdt)QS<k]LA!G%P6zL$av>5#"‰8{3>&nH3^F,: @i=A5 Sk41Pc Kf{¾:pf8҆O~%=9L_+b` BHiS^<;{f>)uτ`QK!`E!O̔8iLv7 V1ba? 3a%ٙô$x/˼FҾEK+X$!/"P=OZDd_EX\qO%1~sS⽹1o1\&:e4HPQ5mfg;f [R9С!D>>vai${Ӣ:s 7Wl\5We{,y:;'XBgo 2H, &SZ{ 4R;m(Zqr`SJiJpwH P! BWp\QPXT0'H 5.V|f.Ӥ\Auɡ-ދ P;.c/v1ıtʝĊ*XYts%gb|`*ƒNP7bAjċhVa (JM7'ս"E~&VVr2K_)钜T+{X,XI`NN$EzlM02ޯT錈Y# Q/N\@^=paZ቞ :=aCbx%JbIcXA|<Ek>NqX{\;]'¡ 9^c\_g둎y)09"-_[XǦr#ݥgNx,X*]L^1pƮ]#ȪR4WܼxS;L GqǾ}s D8(y!cS ivY6XY9O59$D!T`J(z4%D|bJ@"lƀ.F39Ƌ0BW _&2$o=Ulij#evSF$L\.X-c ĆI4/`5Prp;^pTFȠW't܀&|4сd9@_%ёL Ɖk΅+LRՀ$Q+6ut`4`8ܼQin{KV (dl@rPBF4Z`uweur g? +S* ᭠ӎЎUZ*ʔT:)?RݜQi)tU鄊'|CfZL+.n OrÉi(Z[o". U OkLME8Dž .Ghx%MU(HpyfTjg?ɉtM6 dLdiŦ:t8*c /?O;*pO[*T8, [ԵzCrXDCǹO&Sx c2x=SY2+Sg-A^j"p9#B|*ERcILYE,ʝZ\nS+d-s8rGoSXWم\\1]k\kT@i~} X )ʅ( r–D>"y6 =Z5c\/dE8QO0aqEV(qAEB!+?Tp=+]EGuvE7SW7/qf3 ٞsGp qVG  rs&{ٞXI=hVvE_s!ix2rƁ4[⁼~MJ 9("V!s1aTIѬd7CI^~L)-3Ip * 4JƲC9DfEf%'$3BBI*Cթʝ'Ԩtߢ\aXrTGViR}*QdNv=E&ċ R1,Er SLӳ,bNK\~L9 ']Ɖ*>#//:M<=3vMBsU'Dk'z'hOB,> 9dYH|=@i8xdqMB!2Ou L;Ć5a_#ǁe41N4QDL.[sHc#Br("ݍ-p}~9m^zސ\pߖ-9"?wP/4jkqF!U9|~Uk^ixSV?V ؿʝ] غʯZ_nSUKEXS_U[M%{)&_P@:5 ,pha5e;>ii~E7W8K]6N,*?t>WSE~x!G*FW: uQ jL'2p.Ç k*wʂi7O]?UngiQ;oc:)$z?Wf!/rc/ԏҋ?=Rc3I/VsbcOf?}ؑZwOf,zY/l7p7e+vGmAu}UU=֡DYdF+)K嗜?ua0K$V1iVm_J-USR=R LS.֍8\1aLm B:Zg k̺g˱Nol]-bgQ8O喿TzK}i>tf͈'P}ģv.L!QW;X}#&V\ɺ?N:E.'W[N>uz>#7Pu urWK3MǮjmD]ۆWRMgUG\U !@𺌱QHG3۾ͣ#sAf_ҪPyd =ۺkGZIF)hFtJ=s՘5_-uǒ^FTs;87ez3]; .j NILI„a~WlK dy-stNO6Wb{U(ݮc3|+[#R=mdLQO`> .{o.D0RcLh&v/JƓHnmc=ѕd3jv~x͙g@r4HlL{+ܿ+ϒ`3XKԹbXx^ͫD2_W$3UƏ<`Sw道AU[STmO QQ󵫴ѯhxNV%FZ?j/Ձz`vž+͸>7#w2;(PASr: hi4=}tM%Q/dFBL*Q_LI@~i@԰!o "s2%R?PffLú(R7|wW~s<)]ѾaraP=1.fhȃp2 IUA0qh dR0Rj7\Z/ P%Y*aE|U*͠6w;x.<U^ԟ(T| 7/CRh, hہ"׷v ˨tQjm;XF*^M]dŜ0%s!ubO) 5_NoLJEfaP*Ў1n}Yg?s.;S$|{N#ie62yv hhzC v^Qm ւSw ;+e>$!dgo!#ّ($+{ٛ~ɝW}q99}qj`!:A}9` OZ)D҇AءWVE Rô.Lh^7m-7Г54S'rtמ1nX*z)Mqc^g\2Vw>]N}ƍa8_+'lv%WPb%x(4EL9YF]w)5X_y輱gIo|KTZMʶ e}D"!md--_y/N×vX_lrɎm8M$SeާwwT\b) N~zWOWάHP{c$M\Z`lyHuyL4&ҳL}>W9yl~[uT}紂Ri9^< /B\0H4 |]T$f ^#4"*75_LP^vKe5hVo_u+RݜýG7oYt隔 'hf{W t^~:4TJWxZ_٫׍B$ χ,󞷷oŅZ?u+>vsZthR8\Ĵ*zGܚQZ[pl  Tټ0OiMLЩwԆpY9w*M\0# Bjg\M4g*bܸ1q̝oV |'J 9{}0Cj7pVU0 `z?}~t,޵܄P$> F &77YnJ?95Nb‰2[Uw8m[j\Rv:`Җ^f֭V\zMqt+ӎDhav3mw&Z튅ar)Ri>PFl(tz`dq"}[w[+ Cٻ'CK>׋V^lWޱn e}am@?Ɩ)D]Р+B9ɢ Cǫ~7^Oي|GiIRm_EFb6iѴJs(<}vd6rfKQσܗz{p.G.?Es q1d+{8o_\%ٽүĨYfv;Z>$WV]z—xW TcT2KƑnhJ 뎭v 8Wگ}pneW:6 5q2MA7Y lcq&PX\6ݲ|^g ]a$ӧg#cV{>b4=̳q'cV6M?3p&Ÿ _] vgYTQ\0\h¨rlC6yy;ߤu7)ؙDƕ 4º*! | iL͞}|sQP|J]lV\ >n̋ZZ/;:;/4y5Vb =ق;sV3n?홸~S2#%1^,˺ɓ=`>tlC*a:P~)uCCkҬצR%{GE؂n'e28םbTzwزOdI}IKΨЫ{}3ع1 IJ{m{@k/bTm;lJD8쑽.Rl Y㟝]BǵЈfi\Osv[v3`-|l=+!IH)?gӝRƏӘafݶ3%+Poc8mlJʠ܏C4OlςsXb:LPO":Lx`{n~Q)etn _ .Bة\yz?S59OS8w[K]6,y2\ښ9əWNϲ߇RR; ค?7.e6D3 ;`5Pt®=߿m=o_9T~+ xY;L/U勗zj)&P^h~>1As^saeu%dT/_ޘ^8m# Q餹9)x.̽< ^C̩cښw/we, t^8$,瓄"MOrqȼ]P(yJ;]6zs?7C T䯬^+:nqSUZ9X M}+:7nc{4Yʿa؟[HفH/X7U£ߎGP#*[3l< w8yF\#*]:!}AM{4[k\vŲ)zA'cՆFb[%+K:c:^?m^M}ܬ󩔃C5^^jkV{VM7;S> t$z7KeAA 83)af̠ry~Sm֊}4EV'%%G{kSؒ ׎; ~7:^^5PZʕ 6X[|:VܻKQ_?5ڶ!"( 4D#rS:`m ] y'\Koij1؟Mgsג3z2QtfM_3-n]yɮV2T=yĝ+gY\"ßҢ?rOv*IXrHϡꕋ}-Pg5:oy_[+bqv6U*гuA O;q+,Xr*VzKw0O1|'+ƌ*yKޚ\ڰe`k6;C L b,uW&㚮 Ը&UTIU7!l$K.ZcES/_\g]#&TQ9>RLQIdҋFAAO-voNLr{\,F qvcNFI kX\w?;qoiD7sH6s_lhw[3CYXx E[I *˲*<~He~~ZnM+0TО$yt+"6Wua 6o!1ֹm lɋ3fKMfeE4-7nP0BW/&F&5ސwo]v6INF-j"y51R*$ -^Cކ4q~ >HA8$!KVX’/s]wt;--M|t0l~їԁ//S? \HmhK#"Pԝ؍?GL`:Fr$h hYf)h$rBaAaBo vh[[[ob+oz7i*Yy "y9_4i>BC޵[J:qI\tK>F"4a<YE>ow@YW9w*u+/+zOV~arXкY{gK]56aN;'Nv?d%H.ד[GzU'eP|gq\޲pHm%7#o1 G tR_f  $e63^Ɗv{Sq>` ;w K&N:A *߄MCsugEBp[Ef^"S>ڡiWg͸.'mT.$/h']0pz~fG1 iYd?}偓dh,QܭE-Rc.s>=.$>Z3_[ {L115vXMvUFe<##GG~_^Kﵷג#0_Hri40{~ƺ|Ka%5ë|srJj/R7 dI$7վTlLB$K4 {s׆NiVyIW8%~ԡӪ+ۗrЇ\W%Kq"on9[x|J&ut*Ǣ.MMAc8|&0f[Z{*0xMPhP4'j?m,PbJ{l-/m(HQC_6DҚj@ϵ)\%)8 -ypr3kf/v:lڽpUhb*SӊnNMasifxH)c^icڶZt.WzsR }1$wztJLq+ ŀ0!zBY|Nq-\4ѥOV 6D KK[C$HG>&s- 2& VV_b@*&zg:ziK%GK6@mzPUP/\nyE'U6܇<,ӑ*S;OcrF2suE\ogb(EGSo,ަfs]5I[~]<5{SW#N 3II6Źtɜ61s!z7yK^V# Y-mU0WԦv]=8a2IʧORk6p`ɔwI 8 +ˣ4=֏颉ӤeQ=vxvSK=z-'Q=R kgfDBZقlݫ#4o,hށ> uvt le"ѧ=|i^Dj3JFo(,"`c4]Fk!:c[Ɯm!vC 9_XS}"zHOĨO pi%%b|wx$^4oL,VPuƧ ;FUcS ;e/+Dn]K}m/Uף͓ DC +ߓb9{{M6yc1kU왧0q(8ԉHX&Ib/}Z5?*Ns9ǺnhYO%GDeu{?ܑ>GR׹tig`+G~t_3I}\E\aB>nؘ̿Atpba݋6<p@Am`֚9)&_4Nڶղ Q;N!΀jT"H#v/yvs,qxq)*S*^=rQ: <QVl9mz'.O( TĮ@5en-c5M(7goD'pGV˓zWCb& _[ nzl4dωYocbO}Y_ :Ӕ݇(֛^NEI>4l\!Qз2w1|#6{]Iv(T5d9*W1 Cx ./Ô+c\Rp#@V^hy* zU:=]3pj](CF gvݾd, όp@t+ S:2^ɛmNψc+ ؜xY$O#d"R/u1&;ظQ23[T]T~d_ /0) w!<a NG2>OJfiE.rHf_ղv<ń?~]G{v0e"k>fLoZd:vpYjd;d4֤;3z5yl3bo _,Te6.xt 3TOBMm=#';in<(CY׌pK+t^0~IЗy ;*$-/"j|8K"4E#_O R?SFԬB.kxLqZO=EyD;˱Į;)]xg_m)#bO^ye\mfCU{ki 6>EP{ =pim]V7o'*5.;mtOw|zN!Ew24i#P#pD 06~γ|zkB° wMu{1NV&z^CFs gY=^Y7`2RQc1-KrDJKO^4UuR\븄zf̟ݹ\+#=*cpX3JLytQEؾU鳖)SݹY sk9\W %5w 3-yt8HXG0{3 3ɪ0 k%F]ä -b$OZ8ySK}2x, Xj#I0:bN׏q5슊Q+<0m/^+d{z@`,0'#L F7OpSF;O a,& dgkG)k2 P9k9t?bB8>yuͅj3qY;=OQz1];1N ˖iK@M◚Dk3r oz2U˷=n,z7= &TwNs1LQD jX{"U+$ zS7h-NoOLIےGI>]%狓P˝~1r~`5[ľ'ozFŒVvIOL)#tܪ r5K5{qG5yXRY4s9?yQk6MC/^|IchRI#Iys|ޯܐ'eR} E9^vͧ+UDf8]=T &e c;ֵu³"][IJ0BZe}GYL F*%k#ty3ɀ5I~MU {LN7Dv^NQ,Sͣ6O}xh,^>SV{i/n,%A#.9B+UzqUG3ztn෦E.N<˾!?J!_nv?PW'T%iUtآ|zaK)`~~L ~孑FHOo(trڶMS+zh2šO:?JN5%vzPXQZM|y[wof^J+ eW-eOzE NOuuW\R4DgSMr$L&v*G/eEiny{WE_NgW"7<4-0p䙀47!%FrK)ou9 \e USq]E4`W;W:< %vDo~&x)zCĐ|rQk/}ΰ> 踯Enʃ9Wxw;1J=X=®+ f ȇy RkKk4xѳ }JL_:Ǹ%3vv=ĂZ\zG:mUO1H}^f10(ٴoiֻ)ooqY(Ey9j>+Mik@Ŷ{e" 4|*}M9$.Ed)m;Őߏ| 䦽BS1]z%|\F&!jO55_eQo:ϞڝANүws]0vF qq$n q(dk `Һ;-m>|e8ѐe2MV=Pažb5fmiI%rйut^(mzxN{8LYLU>xTUUZ⡝O"_h?uM> 㩵TzN76m}vmY{y+]#y>|)^7 }.U^)/hWȽnz3*m5P_&P>8(i\B5vHc&YG0YaK<\- cmϽ0>evNL)-m]ԭ)xV<_Z5,W҉1.Am, \y{ՎeKнI,:FZҩ$ku"pb_[Thiޗ_{ h7'Mc {8GGD6t] 3m4@gB)8Y, :B aոlD+3Ԡ7e=gs)mc 5w0+eNQW(cr=W50$=◮TYRce7~zEOU*v>)P>9I9D- {`T9$|d~W/83Ed=6*5AKnFvünӗkMUg&wY.=Qg0\qny .J 3~GǸ޴7gjΤ;u7 qee1"P︵X9LNSZg9~!5}Y Ql׫.hWF{ܐsn%zJ&!uV=v]"˫]`:,rU-q_N YaNW.̂&]?51 f*~ˬS\/mϩJJ4fžLNN#^Re :r^A>× Ň;w'q+->lȷ$[/@l6(JZ{5ckmdeF2]"/Fsw>Ȱᘪ_Z^p1Et9Gd!Sad)?Ror%qv6!zH86oW߅+>Zv'M/{B>1ra4)H?jwHwY/o?ڟYŷh;gI WrԽŦq g[қv_,HM_qrr!e%Ί|(ػ Ch(Q@`viYwgL_ezGqՒd;GCR7fi\eIc)\+P@IEt;:\n]=Ùt,u,J$D1V<[l$ J?h.j:KcyA6*\|áM^&]=Kg>M?"ղ cXZi3|H5V#ZT&OTvcrGok 6'G8:^N2-J&3٧.%*i|MpR"E>ckP>H<<{Xu~5+p_ofUL"+8\^u}`M%$֖VR/ lʦntYՋjusU]yh.~CŽ˜ď#õx0KpI*{rQ@a\s&U~i 2&>pK%϶v^4 :;Sht8m\TЋ8dU\ =D`(T V]'qMc{W\l^Khbp6M\O^|o V˥`dVz \'VńT vYVͳ*@v ˽]Yr1 GF$/v^wU{DT;jRv:zKOY?P2")opNbEkYLC%3ڹbTr 3H{u%*ENJ6$@WMt<&`ƩLx0D^>~\LA`1ߎC@p }%]R%->/>\zdRǭ!?vtCam<^!tGge YegS[lq.#,">-}Y1'Hc0졳W\bq!6̘E`LUþ+1E:ScwlYt5b(WR/'II(1t73ԕ9J0#-)c|eҡL%\&ʷOv4@No*5K{ AIgPG2z_`X\rp(] 89_eQʼzc5y? jHqyC 1FVvFz POH0O-ΨȭxH# @yPF+GK[~3!P$N|\- 2" p{Wo=;k%#FMFnqIFne#(wY82y`PC}[-č P'N.*"KzTMƅ[eIU7iWҖ%b-g4f--{ޠRx**2*e̎(߻i_nX>y[Ɖ6[Q'+ER*>9'{!!P8JzJtPcuƪ}&~`y2w{H5;Z)HV|o(A(o" ệ/3Ȟgb=G` {=jl3sN=z҃XW]LS\ٟc>E>kJ5;{) "G(rSZ9ʘ9\|Q,- F\oͧwF)CxbBFi|\ 3~Uzt!1Yƭ%Qo JUik/33՟41Ԋ='@z7`~c0?a>#:m7N(͗4Sc@dH:. Ʋ Vd5%sQV||MkO"zeI$X_I^ ;>SY"۔t-7=4{{a`DZ5ΐ%tקzAƾhĵ5ʵ>%8XQ zFy6 JS!_4 &b3곦ɵ74ʒ9xϺ}=gߚ]R;.`I,Z{}KܵSniO2?|U:2Z~3mY;anگ{V/l~x+P7T\Ktc`|Z؀ p.0R9ͣ!1܂0F-J\-W٭7a %|!ixQ`+pzbΩ!1yݮw!gf^4'jNj(a\Lh@ :;Q~$kڃ"Qi/;eIҒ3Mdڒ]Ը:p&3uIu2i,{2yWq,Q,:S/4R?Dgb oLE#`La%!XHMVg:SPn>cP{/a\`ě Rq_d/`eS.E*2_bA3Nb ~6${>m C7%ߐև)S'sw㉋cyږM)93t1",v?%""nʫӉS2vOx`Kׇ4&K*N8HY2E*6 "ٯ(!{Sù-E=vlبV[nؕUu>GN`d!$:F#9$Gd1 &{[mʭ! K Z"|rWM ]Bhi%7h+I01ca8 *?PcWK M0rPOdaƓaH#O$)?pL\0#"oqFHҫ'bENs߻/XщT^Ň(NU]&w t|ajhz^S3BA JR&ߗzȏȭP%Kjq&/׃]Z} aMaRھt_2x~=Ф@dbQñLMx)&X$-WG6bs/QL:vV?^Ī_a7-%IgW9czY}V)aAm%^:_v;s6aΎ])M՝UtiCSX+Iӱ8<&y:K;. {DN<ݗ)\zr 94~eGן'5'!@:,=ѯWnþ,6wb;b׊d_T!L-.l1[Zt宗a\:gBCh3LguX*v6 ڴյOnqbn_mo8g@?}{l_ڔEy{Ғ殩ޑ3Ƨh\C}&Va֗ߠI#idLF<гbhcG>2>]/Cwų@]Innrc-LjDO"5_K-BXd=])(?DM{PYThP,zH2ؓmORX$Z'Ë%6#Yb¦mZ茩WMyȁD.7;coxwSC .^lj}Es#i ӞDzSbջ[G^j|OK"P Q QjִiQu"gRFL"dhg0Kٱ֖pS0ұZ24&3VwQd>I/TGwFJ[@#JnHHLbQ~60dPɿVϵ믴SmL]!j\0SU6ZJxG8۝ o_.}kc$r4! H&S77R=(CМ)]^;_ϥ=i!S6u$]wbe [7v& E6;jĮ~Xa7Oֽe1)TtsX%lDAh[ꃽЬ-s:kIX)]v[6n5kkTG"֛FUɖ X YĤﶺɣ b"`^/H\+:9u2sEܫs̻;\hD@JfBȰF?w10ϡQ;^6JB SJYNFvf,zi0_Sչ}3J?/s0-¤G#Mx9|^ s[x=$>'YQ/ʻRG"$VT]mmxZMB} ! %}}Xa\g'~=1g- KTUo.: It]1SQ`1 t[ET "$o!C|F=7zo!C~F=7zo!C= t>~?@`1e1e1e1e1e1e1e1e1e1eQ_Ng3 E a[W4i PA! x@FpCHs0$ASQfV(F'Tb䖲VfDz6|qD0 H g٣hY[?` 5pS#P/8FB!| o@H\ !_\9)pпbx HOs?wZB `<i <`$_@ Q:?:Ex !R(ct0(? O"o( z~ʆ"~ C"!BQv Hy~)D Q "ġߒk)ê@(<O0'y0~T:[ ;oHH'֑#qa[ #ʡ@vpl0+8ʩ#D墀?wzIPN B`H 9i7 i_rA oX '8E[-+ߎ!-@I!Q&V؊~;cl(7~e@OmNGߎOO`09;/ؐѡ<A!8Eփcv(L}A7'_MсP> t<(_dƟ Q0 q×oD91 䁡u!GyDI?~g@T@IoP߰ @TpA Jm#yai 4Pw8s IM8J|_M VaW 9QZz7 ֍aWPvb0oiP(_Ds(E~S=G0-p! J_:1B1ilðPt8gÒ!3 ;^sCǁ@rgOOvIn N >Nm?#S2Ѯs};ɂM>U6@80}ț6šܭCf'?s#]4nU+n -FVS?u׻ \:P(,ѧN볞Q]9 @Es`c".bW%_AQLZI=2?R*UU.zqw-\.КNC]=$$(gʕN=2L.I0oЬ|"yMkMGwͺ5sdJ[ϧA,F=3O"X6F1"v gHea+~Y:' gHL;r%/Q~ k痁ͮ)*RH" E"|7F*uߙ40OƑ-ra}~7ps퐕X4E80lƸdj@TٍSoh;B}t3nh>#]dg !HGUJ  ^"F<(yZ-v,i%[pjµҗ^X^}Y»cʛyCwE1rCElVKvENoZʇ2 ,2L\VQm-:7utz>y:X"Q_͘&v)сҦ@z=PlNðg|u#gjw=<ImPL~e@~+}X#LKz),Z\j<˕S_rU `3;/f6υD3Aa!"ǖFa!:(x_*٣;ę\ͬs}Ʊi`pSyjAm>}.C^RGDzlj,cU0 ߽5mҾxEGȃ{O&ڶ=/lC*h)DžݬI8۱Gjtk0+.%tP5NoQ|_)Bm /E|l W.Uϴ{˲`QHl etz0"C*E:/v. nC,5Iq(ST&6|TpZۤvq]H|Ċ?qttzJYwD'?܀Z[;YgE[(n@%HktEGU@/P9d2t8v.3nF佮4 3_2Û j;%tzs\z% v870ISPjX`qĪse.fuxxTA1j=bݕR.&^.J/d8}Qz|c='Y.O{65t;iXHCY4nwqW +ouP4 H $!]‹}~ÜC7gk\:[?dhVH黢e<˙!,S FA4;'^<5*y'c͡vnDf@{͑ZH[;1-h7,x4,Y"w'FRH*H#," bC0Xp ˰%lQ|.gJKR󯒔P{טP=oA{"l;>Ym|HЋHre3M` i(WF4`>p .2֎>HU EԌ FᴲT1[FhbZ@ԕY˯]!qP bZTZ%;2cnsFGG}K)X"{V$b=PjT)m Qc)t7ŵt~o>|[K~xiZpD{C+cnF|G4 "yd,z"EHYrU5 푳 M]Oc|= $=xBX"0iI;|-yH›$Wߺ6ZKUY'ɗղ_{zWvT$Gs^_8gkm%LtmNPZKa)3T=*2:}*oأI("ǹݠnqN qq88k|5>g)))C)C)C)C)C)C)C)C)C)C)C)C)C)C)C)C)C)C)C)C)Î)Î)Î)Î)Î)Î)Î)Î)Î)Î)Ï)Ï)Ï)Ï)Ï)Ï)Ï)Ï)Ï)Ï)#)#)#)zO'I$w(p( @` `؜w`Q:e`O`<}8 +AG@ ,8/!OP:tLدo3[1G(z 9GO")cD 6Î 0;F8BN5 >J>}Qa(qNb@/sa<}UÜGaa``E9'0B W> ` \K/RPi&* ;{ 9 o(R (D]3 iK GxDu$$x@ $&RHo6𴭁 [H0v4;jCvvGw|УƇx9tB9' c|#?i#N Qs4(Q( <ɏfz|Ao #\GT П4#N5*@\ߓPj * ӷҀ*0S3Th @;D(Ψ-Kg'T|K;]e}+߁)%M긤 B|I5 p] )Fڽ 6G;y&0LEeG\"|XP]6Mny58_f9{H3 o>4V}h+Dܵ&s,8; "9vYKŧ8t+iuIu#6mփe.Y& i"-u~Jz%_BKḙ yǴ_njử,3l9,{^*5So>cDi?S ?6~Uw3Z(?7r fxCS/> \1eg"MdG%Eic5_ ĥ_qꮦ%[[]p`B&pEŘ_]搗W6G(Wgoˡ яGV8Ta}4᫸ Seiٲ!¨CENnPWFr4UC?֚8Ļ~ #P3@ fM5E@f}>k6,5oh^rRχI,$Y?_yJ9 0ח^QGaV|ZYŻ# ;VSTUЍ5u\ÛDqџ.c*Sw96ʦZmٖL;g.<'{ڂS?O Y58J5ƌn'XCk _\+M9'xL&OO(vqgTʞNxT;n@x\Pby, }2r0lsxQw116&sxM VK^ J猜e]׻V,j˓J3Ю.F5*2V<3Nz7vA"ºgIp#{Vm^-C44bkj1//bG2j(JI toՖ<^ Q5L?6­^ebՓ=Ce͝]kZ;&a46{ᱫ֕YE2#-l}%(Hy *pqLM6&˺+1jtTֺqŕI M, - ]RqZE -\T\ZjD|Y6:kڞnw㛾/X>LhU^Xi5.;B-A z@JRf,sCC!&*DS:k83Nԫ-nh]*zgz ڂb\#qa{O i{rDB!c_oWK9ŰxD-5$,]r:~81Uf𦇺%xGyua/X\D@_b *K3+dnD-SbW#=e*L]6B]D&R-01BZq|>]K7럦 %;n6Ljwtޓ/,c/aQ|d+[ 8, wPTZ0yj\|BK< +wqB޺>-Jܼc@(gt~E91Op]q 23J<_P Nè}Ј&=kZ+`fUj3 j|`&tH`&_7yiah$O%G^(&uklj C%YPLMzlp-%KCUwyvvػqK/ѼU D UcLb9ctp`k'Ϙ7KO<'X4bxIM*~EiM^f&]N Ԫ)PIZM0 '-F0lMA#Y#RG)MFnٞ5N jVjG`Pc@L?70DTa%JrRgXyl]nJ.X5Y"r+|u#Ӗ'!gĊ/}*9uoUlk %iN̳In~6AJ.VvU1xxr¬)7*/٠ExnwέSIQ}E/ KsnGI^v`JMQtH-3j 9z/EbU9ԡ.XP:QpիҔxgJTab|I5t,ѵblI*&:=.A;t(JMFy WI.(wD#ywo<X\X g39^D|C_\\it{gT%)CYX)2Rdaޡaefy0Y:"fD;13;+5"|F_7 Aj|J3rz:(/1kƁk.oPaR+V3KacJ@BPQ}5qu`ݵx`kIpΊ#)h\Y}bT Ki0kcڐҗW,[ye񡞐J kT6U5TZatx82K;Ӯ^߹59C;Áxy5+3L~VU$[2:ώe̳U-J qІoP>U R+ƻ1`w"F jX$Tݕ1֑YRO$4:sR!HJACG{&QV?h|Foj+qDqDy\<.A ?cDDDDDDDDDDDDDDDDDDDDcʠcʠcʠcʠcʠcʠcʠclb6q1 x\<.fـlb6q1 x\<.fـlb6q1[1J(þ;*"@s ?j/F쨽HGW0Y_` |oyT\=}Gݡ '\bAA< C?j/Ni(DW,6oe;ɂ@Ndz `F[,&|GY_hwoe;*ɂ!xNL^Ad 3l?/FhIG~3?OߧQ1Byp0⻲<Ȃ֭u"GYpg_iO>D%(ƌo@O 8t>BNUox )!~GYA1GYG5 Js-]cBHb?zJ܁Q-_>Ji( @B@ߛBPL)R% c zV?@O]J꣩K>u xT8O]J7KΣ^?OҕhqbB_ߟv:C5cc ;GHOҨrt}7P.8@U5p"A6?_6qiWUCi.*_O{ҳr>A<'g$I?Dz> P(?8HOrBA0w@ G-iWYCP^(yb"|;gHOrT:1 O-_in F9hE?ϿaP#a???O&oX%0U |O3FCQdGSvLuO#oX"0`'i K&>+ s G2($0>`Q(C ~+=t= sT}AP;O;Faqg@=ju?O{Dl$5q0\NB;F8*EGN[?xwb~"aw~tIǻCD A_y'N]Yg/k?x'p艸9m4'^ğ#5tƒS 'Ă@?J G6:  89aJП9F5&:1  6h$l? ?>1 qT0 dyaB$ʱqa<`į;B? >x!BGGs<O@<-6;D0Dw4 u'MC>9 |4 7DVw(r4xmZ w(B$*n00O͟&ʅ0/L/߰8Gt`N& Fbs~ɓZ:e8oZ:i(G/oj!zdt>aEixh |"|E*9مzLq$!-sdpQ1uJ)HgGw5ăf1ٺ=Ń\l9r7{G=p)[a!1_ FqQ6Wr{J&Q/Cp~3])$>ME[e1u`AڼƋ癀6ܹlsv7rm3 @*[sAšf\u3WXlæ-+>c!~Mqt-3uH]XSzvR FVvyjss՞4'G/N:09q#䋾i4Ex4/IX(_]f#.Qh$ 1AҌ$Yޛ~83$dZvBA+ICj.I,xi"d*ehC?* {uEȊH8q<]YQpV8ȓ/eHcQ?Ϗ-v'=Uu\.V1>ΕK֠fMEA'gw^ſZuUSD K30MfZQ Frz tZśR[^75y];ӳɽǚL\R3Dfo #yW>\, c$4jG c7Џ F-%2͊I)QwR1[gt&lR<հ'mE6Z!| E {/5GeTS!?1BCk6Cgƪmˬ Vb1)$Yj>)"[βqzG6,X~.͊LJYЮܤ9QW]II)1,s:nOnHm3M8TficeUVyUnxL3Tr0&cDns  Rw8xCME4U\kj*3ofYM|x w#Z֎#M{2uPp:6LC>P }ѵne5N;%Jϡ5g2SJvOvy域ҿ{J[< )nR:lB+֮"@l#}Z9q/Y⟫I^4^^e@Q[^&"xfr<퐬;vk6ƙ_oZH?R٫!qu܂J Nh|ې&']<ݛj~o_F^PB>'fgp83̣oMKZ6vf CI~Zm45g\seh\.k=gar.ocVMrᐗ7DpGv!3_|~4[l]>8aV*+rVb`RlO. x uevsGې?E˴ı^}5xt%a⇰ʼn"%a^VqXb7NhN$Nٳbg0^;LaVLzMzn{fPc}%JFgb%vֱQ8Ur\}¿ UhxdllL8[U11:6x4_f@Ys퀏j_[΀A?^i'BW껰KF P ,^h@*lˡer/v `ȳת]L?B΂WK@&((8|jŽ[NO4}:y-a|Jj\TٕZ5 %~\oYUqHc}wnWoJ>_xL VG/ >P(5m6VnJfU\%7VK6k|.!hjQ5X`;@ Od܍wv\Al}KPv4:j_HZ$angnph\`g[I/O+#G+1d<ծF1^{<=oveϔ^e~tV&+B~U U _ٙWio.4-Wហe{*W)D(T#ꑿ7~#bT /l'S)GҦS>;aEѦg)bm`?)6+WEL~-u)_=i׫OCi1?jJ[lefu6G;ιl ?RBEˏ?xKZ˿Dz۠{sb8~sMuz,ʼCnՒeD)|8̜yUf( 5-lljmy!bٚ\-4GNeHRb.Ht3{Ʋ ?ҷ1T ]Zkd.9aͣ^OKsUgIU4_83%A6[!{:as<Ӭv,>mgalOX mñ^Sl/M5;>Ĩ(E8?zKd%EyUKŎ',;B-UtUZ; .Rந)/MP!|C5@͇ j>Q!A|C5D͇ |8BRO%M)MȤo;.N*#.9a }GVtuDH 5R`bA:A (Lb&e./BXV,bI;rJ׉Z "8M(>^:]'$-M+#Ӗx2NIz6!JbZJqMWIgchcBH"te2Ҧ$#!' HڌI DZyD2Fy AMaBh,c0tud<ȲѕŒ iKDePHӑ.@A,eTDE^yY}SA|,m:/Ig _tmH#>HĆ Dp ;Ǭ 38'E{'2]3Cf%X ѰU yߙY>N6]~Q((a]]>8: /I!:wS3?vRPg7$ ӿ$hOSg"uH j:1! ], biUg62f`ʀCba@tæKY!"B`2^|l:IO!x'J RY]3muGK$ v&h$t$2>0T,@c3¦KDԩdl\)4ŕ:u"R ٬,)|0."DzA D& L'D Ց ,DfE1鄈t`$ "dHd,BDll4GHbdxd SN0 B"\lj=QDF/&*D$wèBN_jzqXA9Y:_kT2䣭49[G:X2GfR`QlnCwKmR-|}ܭ/9>[g>Uӱ)2pгyȺt8y/ၲNԻڊ~[Ԩ[Fd̅wKI>jIh?1B.!b|~nrd`&Mo)v?yœf<ލ ?P \NSCJUjl| 6_[\SסP >.lwA|i+0*2.SއkHvu7w&"NLDG%Y`ƷsC|6BW !n0'ǂ& h-R9m(z{2,a[Uۛ?5ٹ~&'<&8Ŵ+hݟ.(oo:@4+a}N$AlRAҩ3z[Wpr#ǐC!z2uTϲ:0>:bx?<0>x* (I'}Yk`2aPs0 'A|,p >b* u C)"\c\ヅ({HZ&# 6;=mb|0T fczF%8l9p$j*,2S4SZC2鱴Ac+6o׊˝M]τIt]S6{dsʕ#iƾ-Nj|⼚䋖8(_O_%°-bfffYh13333[d13K=}y;pDIrgש:Vf4׈77Jr5|0<)^쫱yJKߧvdrՔ=iubeN*+hAX)c֟XR`-!yf=Wz+RRzY]go5%RWe-O܎۬o HW Zzn_q'Z8=ָ6ji YiqceW(ixpY1>*f,S!O9`n@[Q.iaG51~o4}oJ}2:YH6n^Z;1iZ7FiسioJ ' 3~'t~$R~:&_xN ]MGEyA1H^{54h LvhbDy pߝ~RڧvuQxxh*Abq M(@sRp]t`ͷl̋3}6>ѕp֟<JŎx1mP~BႧQ`6$pI`ӱ! O"rV˹}0+ Et]eMׂ#f_+$I&y`m2[nǼ]C{y !AӼY+PhQ/|gM+ֆ1_ y?И%b1A킔al~(/Uhi.47yR,3 =30`mq>f!=xXAM4VG6 )ftB %% ͥ9/?VbE[J\4׶*ރ9R5 X0 ) O xv4 -YXqo~L"bG"=D16 >+0`K@Rrc+_od6GIN-Bvi`lI{r"{Cȹ?v?WZKkBe{Pj}$nO,ՉP,[ O@$$͝'n/] ⑘G Dd,]u\HE/!x bNs+2MvȷHw ͋X,l+N]OiQ%5 H~\#"#)NwUG8l_ ~ѷą_M6(IU-G~~8l FcIˌHU`cHѪ0aI-wv#\b[_6jkHڄ!J뵢zO L7lILpq 6m=,gU[u[9SELҞ@r`d mls3ll?sc CrHc8-f0. +]Diq@1DlhuvL<}Pvޓky:RaNg Gq AB+N*+ey&k /*CU UZ5D't9Nђu(lu1nf4#fwlD o6.i[ĂSX`(YVRfѐxُA𕧫#ʒ I~M~zvoT n"`=w=a&;;_;f66&VwTȜg03g}?q l Bs'X[],? ϿO".::w/"f:w?:z_w0_,OF_~WgzWgUhb snfM'K8p|Մ6ٺىt.Qݑ;8JL8. xgӺn]y m~PPI&W-JO)Ф9Zd ڑmÇx|s[VED?wvyeo=s7^K+ޫ^|;D)WWEB<^梜?M6oVXz_-8/Yx=n$1f?Mt xyɷu“+&T /&)hj?[6ۉeI`XḒ^H)1U{}vKgQ*kfhm +ȫVSGZ5P).sGhrc (Y` 6if@ d:hrTw~򒨶Q5 V,}ȑl̾T=K9;r鵜u!\HҮd,,6i1"k$cݨf،gt}yXw Y4:||ڭ56m)yшc@cYZl{gע 4I)V*njЪc.g Jf`q_&Ռ ۆ?z/q3ߡrs]Pqư⑃W-maylri+HF߹\1B8A$9 ƊnK0)VϢh}͒.4!) WLpEpXioi(a XצMu EX$Qg eQܛŷC̔gz׼̏O)Ze3E;iM,L~-4{cv8od=hnGf4}C9 ;ZjS ݸ.uBPKf~ Iۻa @aJ҇#em`GIzv& 7ҜF,ZXP.y+`)'xxx8[k$A={kXU TݒZݤ*FM?R;FOA2?V?vZ@H&'5zqȍz.B0 vįəq +d:Ѧq 9@ ;"W'u\':naXcOtm_`#5ȫe+)}{&tΦ#+!gpUW)=GCbk)Vq_ǘP t1Βg5"{ATDul(H2v' viG|o1IPeg!n:_`MwYߝij܆/ hTE|Ch8Rfqͼ&Pv, q_p ,K}d4Ec8g@ .˃尠2uDA"74i^1^I2K]⑸mr:*$KTƔy0!P_2=כ&9xmv*>h8A2'ɒ!'C(Ȭ/ųZs2*NS 0o/n?T𣄖K׼|jx#~*! h&`Np18(#6WvlB, BE(jZaLk&f;Jg#,J殽%B^O0-mj=-pv&=FNtڸiGN0L qjyyrSŶdvcʨn|#c bm7LF0Cv4igM^M~W1msݡW[3,3ȶ&zN}Gr;2cgr["+ʨzّy_8WA2gdD9@2a4ڮ*;ORו>nQ\Wܲ12'nξ,ʺt7@3<N9]_]^R4AS3m}~]~2* ίhx}~YxuHgVsD^<śqu 4Q4o; O .P*uֿOggcէKFb,Tp::vu?_\^GPJZH;Z|7 Ok +#Pim}F>0l)b;f=x  ؝ga5޵UxJ;y1L luF_ps;9= ݯqGYNܑVg#_jt,PW vѡ?JKo ?5m0._'fE ]zqGŘ< qZy?ǐ5;ȟdNl5y7A9d`- MekJ8Oɩ%iT0Eի |'r£FNIޭk<.Ξyg[AwLkQV="+y7鴾  nWx<q%`n.Y~|^tPKZn LKadec;0z2yDxQ\dZY-Heumա uk~{c! ,6wiZ)ר+;%!ep2z;2B-IiKNB$zGkܞ|*kzk3"#S4m,.Ik&RVOc4s9}*18W)> xmZ4xf6bw) BN<="AŤn2D#1>Oi͒2E]s񸘚yt 4U}̍jAQB$^F2(1MR^hhw`f7h[g^Æ'|Xm ASGVifNU࿡1e1n&O~[@5oT(V{=||6L7BIpmO"a7~U1k,P%[t!yqbHoO\.p,yߓ>"zWɴҶt4w 'krup3> Bۄpƙf5A'\9A /QRWzpvHt52"Ukm= cpDTcNXnbmC]24pcJQvE6> {s*+1 9YtJm"!=SNik%+.ZgbZ+ܗLrXY"42(QxxbOm8BPՑPwGC۾_eCBD43}vsH hmozlgq8vжRZ˭_[ @lM&MfEzb~r*Sg6-Sx^r . ?C9x+;˛czT`z%֞St%eA+S)/  nA ӱ7C)m L]TtSHb6ľlfa'\u "kS36M@鯃<`.|Ԇpe, \T o ;;!jtK}iW[QŗÚĨ3JQ5du۟PGdGW 1`H4u "F>tsj7v&|:V)+Hw *Vd10"%/x LԥxȆV 0ǹ́fL4GW&BH`\,QVvm3^i_FlWح WHLl,FI#hb*,|[4 ,1#/xȨO-k[^l>*^N113rt ]nUh<ަ$dSkҸf*e总 &:|u!*$x'n>eA9uw?l:`=.,IZptǺC}ݥ7""jaLUY+Ъ"q5^x^mfOh)WǤ^ބ뒐y<_Ψm~5ִ#ƮaX%WlF:VL2(6@lhS9+}$DkU^=s51Cl<5۠& #Vjy[h"'g u#4]UQ"wn^ɥv?bhwxZ1WMxeg4jB}MZ);j%r㴉xzIil?ʴ )'ϛa2IìJA{fhqW JL"wڜyE;H9'I} gW։ <]-[HX hǐMDs,~[ #& \9\g1qQ1Dba)[95;X5.ǯ'ɯ?S?~#n0ٵ&$L1ҏG$dv 8S8[ Bk_K{3ߏ u}B:!׭cĀ&ԚƊ8%G/mnKL=?y:2fVRF?|{22GyHJhL)1Qep5Zzr _Ƞd%LfMGTW& -飔)L3;Rzymm64= *djK烊N^SqLmٰCޚ$Y>l>¬d%ԼM J&'F݋<ooY쎴& gK1{[MXwxtonl@XPp N|%_rL|Ln|<[^R(&σiެhd5Oؠ+ky(e|(<,t q|@+ L ԆɪAV]D]aǺ7|?`GUʎxs}jUpvk dجHa <IW!҈co8-\j#Iz⽘oo/ FM#raH~ .X^CހiqSFN]%Sr S-3=; # #|a4M6+k{3kkYDԖ\,:e??7Dj"̙Yh̿(:y02w=󿩘K0Ƥ뀎N 4{d虙ߣX~#s? 9X~+z +{ULe401q Pއ , &%ҴNߗ Es[yxq!"=<`cc"K9*L"X{)(rZ)RZln[%6Bpv?Yp "',i!'Z,/kZx5zG6z=̴ e~?`A|f﹓8G'2k|nrlze<^ycH@~~Z,A( S!o2?V͍up~`Mk ES"@$މ-SV<۰#Dzb?TϸuZcaS0nqccpqzP<ҍ4O9I~_7N!  xBQ!ț!R̦m+  }Do DEP[E2|L<*w-t \&X%ZxUJVkvt/b;a<]=}fZWE,D I=\MhoV.&9xQ?nٔ>vFؠQk [$|;ՕŸ5ݞG |t(0h;珷HB1j٦3Ƭ?S]Bs{Vdv}`&ɷ]A.]Շ'Mĸ)x,5k^Ut,'Z¥{Jv!1 \Ԅx XbjoOޚzư,$ύsrmMl>-@&14,r "S$"24@փ]RQx*C Y5 g%#i}+NhgL.]5-N/ObPl$α2ڭ+kov ' ykl8Q\iNKw)~ TlȈ5 } 2 & 0ԓJ\$VvTX>>x **ݨ[<<"n21r$BHx2$vIGVxXy{E:}%B:苩y0[Nw \R1w`oM]O YiJ֩vpݏ :ܰ xHkNIaVK1D@"wqNL N/ w*m}B珤ƓӤި*Z[>V K*}%mmO3vSyk̠Ft=CK2/kzF(f`?)\x%uQ >ϯ`3j:M_˛'V4=D.v!b4iMynHni٣9v}?xQ9Z2x(`2e"fm^JoK)\%^$s1C%hzL2R<=H.χJ^3C֗RB2AIk(nRAPA@Uilqdy߶-4ٞLá~tSLJ ƶP16Jеs G#pl\/,4,uy2(,2oۡ5v3h@.%9dD ERZ{ɤw?58I R||+}$ 9 xv;:ڍ'37Jܬ~'uhy387,SŢCZ[_SLu4 6iz}忥ᢲ7T^ZCἿ.Ԃy@|*VO/tu}hURcWWmmdN^f PP!JdGCLWT͙e*6lYݐ@Tn\ I(dsM 䫡+&i/PQU[ UD]#jQM[aajA])Kx,(rJ< 0]ɎR6or}GB.íy voW 0/Xs蘲ےI{"m/\ J͐ml陷h%Ͻ̕'" , RhBnd ?tm `MFӑo&*n50:0/|D/SѫcFVfF= 5v\i4+;KCljt2J 0k3Blۻn,dXQ ,S;Lb 8QI # paM&u@^) 5{SS:UۋW\hu@q΀݀ T"m*q7+Y!N5Cc7$bDxuXBs04 <L>W5 J ל} 8HaT\^;j'~DcձFtҘc[y)ޫ4.i,|z2 !uG>JmCuk=qkNNڇ>pYsY"<).B!5l֥fZچT'dyx6ެ0j•R|f X~N>3K@t~|eA =ypLX'` X]Z?KW%T'"UJI+-Z@{ʻ{γA+aKP8݆>t./ۥ&.vK*GLh[_u"0" $6u=7j9#D}:S\̂ݒuFt2p%L7{ʕ>w hGu/t5vl~ s˪; Ψ1&R+W"}IIwif( 5l j2̼GydTU:REpf޼[?hz@ ̽ @]@MkLRԄ^Dzs12o b"f CvaGH1^lo#wټa̹gXUԲדZ#I5WJ{zK1wnL$ 5ߠqm*iO>E7*@Ĭizs˜،Xْ}B-seocxO-EM@+@JGHG;;J [~瀙v޵f`a0򿡵03а3SZX~l\ïIiL[z<3ۻ.У1@ѯ-uW!{A9=s-^.r+XCBhqqx )M„#|ܬ 8;z2yRO )F~Qn7Q@zS3-a[hEM?ݛsy`DBYgz~jOn,V? ݎ:j*bk7ynì4њɌ\Fٯ BRRoNߦ{oе̊pD(.O_Y; 4ud;u;X={zej#Ӄ!C^PP}@Vq/m!={xQ\(~CŊEBRJ'.% H\4*[ش_" JS: A =.MzEs =ŀi WEi#oJ°W =IAĥ*"iR#V}O$ UR$\+㋮/d׏E.9 x9xQa^"Iζp\bsv [Ju+EJ3t3f[y o ŠPÊffN'˳% F_ckCsh,{8EPf7 P!ģ6\\l ?o|Kf%Ǔ[ҵMk֒SM "[/+ rn_6#gM4Xo~_wA8_.N,jQo0c'i_|50S8&a[n-RQ!8}74* kxYn֕']Bwbw[[ocZ`c= r5yW = 3=3㯲!Ff_c5hYLAoKYF߳VoP1tQ)32аWH[D_p1tE9`Rm;~)ukt˻A5˻!_٠R2E<,?? %4"OTLJ 㲗-DE4P'Ԁ(mG %<$gխiv=秪GHmR= @-u?5cw)Ohxώ{#+āgʙ+b׷ڛ.F"[k+ ^$;T /+wW{*f7H^jHa48dބD6NVྦྷ$|"e0Qt)̵0TP 8ѝjBRuhRq:ttwzjhS5KҗI6.4jh͋l9jV冯yQZl8 W$uRޭyN%9͜,^[Z|( T8ʝ$ mZPcEsgoH:&4AJ+A4&i{ƒ"nhU?[6k:q@A 1JYDh|ș5]3Q9?펉 bu$;sn=}8a -6ܮl[o2/OlM^.գ]b_ZCU]e!BFx 6њ͝J:u~;$C㭽)Pw9cZ>g!E-/?VY!/ ASb v4}[(3I<\)a_,z ի'i -  Ȇ@y@1 !%{_@]CGl׾A$D;-&ƆA|md Ҥ`gGߎBTXk1֖]$n,VѺebAҥg#':l/^ ! T<V)$ NkxLӬ qsJS#J=S p=fP bkz{7UrQs_[n8>;.^>]["Lm&f|2O`̕8Cl~n@w`+â'>/"lFڮHaɠ_錀J sgNN>XYEIO BF$ϱZgKfݙ]_N\jJgbUAc|D]?3L md997U呌Zp6Y*FB~{ƭxbPd<6"WCy߿~9@? z؏no[/ p=P|`(d_.ϖ\L wʦE)ɎkuRU0D(ipRĆNO'4ϩ 7=tuur_Fc?=4,osNfz}N{1 {e'\ 7 +zզa~šD13#߿7F:F?Uejh޵mĿgg= wY~"o]wJCz"ok;'G'HO|$YVg ߁t7XX_G^бG x%r:t8Mv=!z=j'qNwrcФA ;FG6<Bi"0GerD)S)y1 (G mŖەPb'FCJ"ew\sbm(/C^|JK~q7 0?l>,o?;] /vy"(d}/EQ;(f::(recgeC5~&H#;A3օ:LGK%~!mz-t8W A&31*F5n~7 g҂74mPn=P{nic)rX}dDmK(?$|Lբ)(zlґLw0IF|k<[㤺q-CX;M6buS]GKzMQ0$QdY-[~dv5C T쟌\HσVY,\tynwD -*CA@[d]d0:fmܤ dʌ:iWw[l*Y捙/G34gʶ94w艑DC0?U|MmH#S:3 Xx%$}k*oN~f9vz(ߍK&'{h+ o(,V$9zɑݞQ#iˉp&& ,3a?̉@T{|ȐŅK*y^uF 2w2+ o@+Ղ$K{_R'ǂ5^[zHG>70)IТm$*H s S9|*6=}ݎ)ӍF7BWsӣ" p.?|pu?38Cr ^\HwFV:ضtlsgy7@<ɭ /s@5@,*IT0@v'9lĜk(ohJU+7\"̗VE8y\khb3 y4 \Av&YQ@;0!1 &fT`2yi6q֕)"gӌ\?.v~U!?Yʅ#m Ca1P)c}V; g:8gS9z:m,Iym`řEE M!Io-zM+L*wP Laq}WcᝡW\Ћ֦*l}d<86LXe`1#tc^xK4YX/xNu1W-lR}`PAJz}"{@"2yq9cl:.qb$g(+bg!$nXL[>d2kuk]g#+}UErJgV"Pj䌆o۞uR4o[Gm#nސM;ie (p T8[o= %ׯ`QivԉT*+׼Nl']]׮Ew0>cH0ɂkKВ#WQMkKU3Uڟ= ~\T] i#EDpSԖ|i@N E3 })|.^*s vX?AL汄rB, ;, E9p_//ID !-򗙤?}wZKEح!yީ[#S,f\(1"[Sˡ9O;G[1\Ph, <}BС@K#V*6wG&W{}$IH}ʚ^M Z en`$o*zsG^)_E>תh! ԚgU ׫51Sة$WO4u9;8䣟 LP8\H5MU4wPZ"r:vIoE%4#;Ȗ\$BBg``9,{[W~nT)oTM I2 r>] <r(8@6݄+C^8+Wm~Ynف[.^0vOROwrsL,C=^Esx;=pCݬ4/DNqmq.gg?MЁeE2¹UӘEuԗ1BPidMˤEX?9)\_$ۉiEJC1jY>&!7r ]v垵˵U~}Ⱥn 0!.Z>!?.+x Cu@q ubҢ}ÓOҞZxw@mN =X4Я;je<`qXM Wzh@@Chа+X;n[28͎` y|P)p*$]W&y&$p ̑Dy.RwȐv2zYHOS)VTʙ+> 73ڽ}1ÐI!O<W8_)|taF !>}WYL҂gկO~QP+ {uo6?C.-M"ddp S;! 'ѥz|B)0ۮ3bm*#X/9R9_άyi#2Et6 2+=*e1(6CnyrLLD@c)"\"…ևYM MiuCR&Q{}`FRxu}mUN‰s$=l./!f7>Уy=86 +<!xLj_Ɗ(S~$GW1aL3NRr0=ӋMPBh{ypUl|{-%+r (ՠciҀ"gP|O"3У}~RodƬC|"4W_? >8[țaBqk;-q j/3t`xB&S>11x%'b?-X˧t+>cT?!|C7p=FY݁Jv[kC6poRPwƟ8*?ٓSxlX1BͪYTMÞ6أR%B|8FOkf(.ҳOk5?H>vPů5$".C@RIxuV)"o,Śu@sb&@I{Cy,^Bkl\l3]KK:cqzC\סt?8>a$j*B|di2П3FT䤠K8LVX ہ;[!_~j-V i]!B[*V[Ƶ\N8[Yu*jUNj6  (bhcւ7R!  ~"TE aơtq5רgKf *ɡ:u5GcD3ޜȹY|CA/,mr{;B#2ȿ,)5`lۘrWh<Ӓ#0*It=˩ .Iɤ־*)zedx$:ԮNB~i^yA ٶt9pLu-n.woBԩG# [c2ZFI=Nof'3Ǥ_+ƾ͢/5%zRrߙ7PĦrD~0Bq̪vnRO}As U پvȶאg6[ h V}6%rDhsmM)`,7K]!܍U'(PP\[V9a5@ɀ2Eݏb/BPݵ "PvD+xdVƅ7xp\/q滷cc'4q+ QaJ [P v27I%zrS&,upF#OA%qvrDoJH*zOt52CRrJ;.Qs;>oIuIB_ڷk#3uR /~n[{->_P]W{0蕟:A P6S-6+AbR<ˣSF8ry<ےy`#ۧy uz9m#F|XYͳUcF\ ,SsfV'TU{낷<^g 4jVڈtyS'ܵ7tԵw=?=IF~JA__ԟ"wt:vWNRa13 W 8{gh"|$foo3kfםw|:7^}Q:f_QT\qJۼW9uP>1Sw4=F'ߟ~Eh&sƣkıuޡmT- mic,to ~}n⦢%CC~g5^rۣAMj[".!YYKKL+4cE>xO9U0zr -~N2 'jQtuS|O;sƵŁc{=BN].h&ͫ3yuK(k!y=%ڎ vCw#틔'9:zRE3-t`/SBچР=[N,8 JLJγ* 4`_.J'ֲn{M˖Di`Msz-0mDUI7x!,)Wx=$Ѡx +ʘj| ]/UATiӷ (/,n$/~t%= "̦FDD]t~03 ^ Gvig^} lPh=|xǑzI%'! fԌd{BzE΋l{K&Y^7J\3f~DfjM]\˯ &ʕ#x)[,騮V\]n:NZ/f`RVE$e$M%|dx5~FfEw''` !֭xQL U=ҥ6Q$.\, *h)OҍS"=٢?2a>)H}hÚ<,= y:E:]E.ksUWRWދ.5M x*7iWJơ0$Nai{Kicک$'X C>!lgyI\%ݪJfDuA{mrtpj3yT7]OWģ sosfHOի}w0\ ,vi$zP$aq2XO=*^E6/d)!Th< Wђфl[W#o>]E}KZ(T%*VJ 7wpPJ@n1+VBΆhJ/%Zt}BYF[.&*bӾbMU'KJLs|ڨʉ·/|^) WB ;$ieVR> 2u-Sfh~mR)6g>K 3j̧%Sf 9NR9v٪–iマ<ӓ@ CV)3 !)49]`a6l|mM=Y[yo@ ZHX\֞O=Tᙲ+hPIvU-daXo;宿^|5 Ωj߼JJ!yk(dzQ}ϥ #KiΣrl9cuxag yQ;G0ؘRrW]MW|oXRWxlK3+b{'i@Kܱj`8; H h}%nc]E>2䕥q![DݠK K_Hhwׇc jk&}% iwB]6.G{t;.w^+:97]0tDH(LLzy/5m< |nct:j*2H7pDx|'MR&Q!&u0>__Q13ME0GB(vY#m{fkz+RPH37PY@ HpzƋ G~sxEp>ؼ&b>-($%^/4Nb8UTe)J34Pt%wpAPO9 Z}OufZm,B+@G+K -\Y%q;*(&x' 8Ma)󱚉4@`B'tsPbz;PvkާCCh@h3FH&s9%􁸊AMy%9HN&Z >O~>v{1$0yJ@_3S/O4Rx OɗNF,QuZ4WaP]n!.*:^N?q7˱ F*UQjĄp7穭%RN*?wM;eW~2.vMŠrVU'JgaJxI}F5#^q',^n6 XҤ|8}߄&difr'6og*LYx3I Dwس~̝F1b>(5( 4''$z'yxbĉiŖW.6eGmFS J!SJ35ITL50&\bË4NOԨ_&l!3`ET?U zNdeMCFoǼNCYQ(O+,=q :_[y\bidQhFb40h|O01!D:s+KG&?MZ"<<E'GUF8_V ZK27EC1|ӕJ"lٚ=i^=nrP,.89J)=$B$nzQrb;~E~\C+a].q7FAIHLC٣7Iv FC6-%3(姬jy8(C%ӯo/ 7 V_''x(}:,6HD;J+a X=lm*(R1=].Hv:OR,ߝ`YƓebYRdnaOĂ ^=!9$ʖ'EH8*:h.FY?|g{ErSr+1^:T>;Zë^Y)tM$%eDh:VB%yV!mOl@8Pt78g8/՞*Wo%+ŁS/[%骨N7;=6Ngȓd*,ba0 i~Wt,{ Ч8QKJǒ?KcEfR $«7 aS0-ضI =Qԅ~;쑛3Ĭ~T枹zʹ%0[:qM tŮ"tDuv҅T%sum~r 'wkp=O9,6 X R/9݋+CA񟥞~gǿSzT_y=A\JX#Oy~J-xV2, p 1A\GsBM.Y,?n@Uu즡aQ(j #VL"(E^[L Svx#Ha -5 {aI膈R{&26A-șߚr\n FfLeI}FZ+ӎi+IG^zR(Q2erPhͅClr$)P5ȍk2|UXZrQ9L7[]W;tbW7H$'IM:ֿYƤ =/$DI{v: 75?DxYFeLR-Fk|yO#aJC⫍wc.!VS RFdٹrGz4Uluf7% ʮ:׉8Q8ȿ-RYQ# OVUW\W( 3! MW&3suVmC;/٢п_ީunul;GnX\v`BZ`4S-0еIՐ~PwW߃ɳKݾCeBJo,}w\e׊pWF]Mw2}6UNi, dP$!,rCilCiwHY=x_@dv8-]`T)r[uaÑzE>5V1 V4A}(ddC~jcxj8, fF.VB* Ąk{W\ kv!)G!锅xc."P َp3;!Ex #E(IL.<0TuEpʱ tz <2o}1 l W.e>Dу)AP&zee49@YBT_ pwxrC 61g @QT씊MtF.P, JҲ%4O>qT /`Yy|PJ+PlnB2^R3ct~Om%uY6ĺ7T|򐁧%m2Wb DB6_V|M0wO ۼζ:ɜ1 #Ko,GUv };Ɩ[/%/"Y"lllN;s@z \*dEKaibp 1] WQngdQ9xIT hݖc(̀bfhjNvC1?סV]@鼯6&Toj\MZt:gdHh !JHRYf:JS2sH [ KOF` `KQD`lTtX \KYVܯ\Z+RU}sõG-),cLJft *c/AkkcNu!Y{}}iL͙=8R!f=U:o͇G|x #)$3kIomƣNVs&>uȝN>ad & 6n7B=y%0iʝ/dq [>5KX ٟOh |\ZOQHh uz^xLUMk CVFx?qP_ŶT{t˳}!yl &Έq0݂mƊpE-+Ƭ=՟fsɃglb<n(r08kCi|ɕ؛lmӸH)sD~\ s iH:OYCF:AU#mN["p?Z xۓ3m`@`*8U8F," Wnu<_M..M'娶vvw4GTbg´WTIAXU(6(RA^ oBcaѭ$ul;m\0}˜qL[fϱY,3 l-܎e8c`ҹa25"]XrGLW r$I'.ir)y?A֗W+@{So:h{ 9єsTj=ygLXGuXesC(l=ds>_^tő.`9H$ `8O?8s%-uR`o(p\1RiqL  iWO`=b1$annIЃfw0RR{gd7%PLۃAjL_L{?S0[ߑA࿜o\wY*4M|zV0NL =[K>$iw'F&TVG$B392e]C)YqJc1m:`G?ͩX]Zp44ʰ/D!JmN! d3[N]XAI7FmI:^GT?Z 6LE%xRqQ@ #+wƂbqOНϋ8¨m{m@A1;< v 季c8bM̺PvZb8\"G.e QY?d.xb%O&XS3AK?rs2A پ5tߥPfi**fmkns]Xd8,[E2 }ȑ@d:w @3rD p+f&V0II\B}oq1MxAZCN4zL %zGk[ :~-_䭽b1~5ҽ,^ݑ^nȱ糔33>[6EJA(kH ufij|*8Hx5%O%VA{ 9AMve3s#У/)~ݔC{pܸAGlQ}{dVxb1uS%){x/ Xz 9p]dP 8P # I2/qS$뛕D2bJJgG+[C}+G_b02`+ucpsb017uv0vd56cz;#52RVkb}'_D>k9~39)k}'d cj_ 39kiŠnЌGaC㈎P (ܿQfI Szks _a0*ԄP#TG}/y;,OgbY $jdW8dnV8PL3f[Q2h%5]wž?X?jtGzaUf\'Ɔ: 㾤ӭp0 i,\/PO`?kD-);/\RCuy8脿*^jY4ynAxu11T/>uNPQ'D$˽DkŹNhKO_e+X ,Eē5 @S& jTaa^fX;!8B1dʝgH1{!ܫS3YKJb]b!m,?%8\fpd1@1T:r'(X+g#핳]y]t C:T-}jHE6k˻\B\F=״ѳ'=;VbF2"Zk_bdv}+;= Nt1:`ag}WZ998ޑe 0zXcY$1߿: /*_Q?@/7f`cgagjNn„1CkZ |=#R.Bg+$"̝ @_5r(OVuJ*g}˺ uw3|:^$԰uJC`$sqA`Pv?\cS+_]Z0a|~n{ޫ"/#ڜE3,(P.g3Ζ#Fp4z'2EeӴ_/ tu5}`vÓnI&_ 8\M):~zr HFe<5%ն2^hh T"x"_%lx?hz_I~ %@<*s&Xo9 Ȣ~iAǪ\T@7Tim^f}R9bnxwg-QbLrTY" /Qq/U{dTk uU> &F`-&dsFB}F^c鬙gh8kDv@J(]0JvJF@rPh,\=-5 ṕۗ4&${䤊7Z-K[D^kw*Sц>hf6O{>,Gąv.fԍNçʖI!C#@UD2ZT+ƀtv0;'C}"ty lP\zNLƚ` FXOҢWMv uqnnYGkۏA.P4nlStbVyg| b $;8J iL5a`Q7qH mU0}6g7ψcq~lqʴS(Q]m?OOYpjlz"@^ {¾Tb``XЍ]$('0Y`)rV^jDzoH{a5SOI#J s)4pIaڂ{ J9ql3xuSh31.hLx# ~K9HYsnXXz=.~2: !OhhYfA /1 ]= !‰?w\2!{M|bԻh|- Xp0 "~roͳ]*d͝r9F?cCUC{ ܲg rt1njVn(#' Ww[kɓvPi>$Ő9\{L|<7>:`bG 1F``߼3Lut!ֆf4+ɴ+q3=bG L߽\~&QA36um2|;0mm!f8pa>|+Vuh $fq߀FA<^HE갥d}[3 AgĹ;G}RP]V,Ajg^{K_\C;b9Rc,&#T 7LI`?ss]6l]b-&D$BSҧep@]:Y] GDJp^|ӟfWgp܂qاq&GIf+Q{ 5ίY5Xv,ˏ 0Tw+*oqNd+Ϫ.$(^go*"8$0H(cRkK7(`ϯ]^O"sw<!-k Q;L C8_q|*I(!tۈ{8:EHSTH[z!PP/"S=>Eӟ>Ap903ń\ܦO̓w*vn"1+/ffgks9_6#{|E!øRB:4Zٽ4KQ*?{v _C :CNn[0}uYyUV\!ӡvnj CH)иR:,B+WÂ%StS;=Ϧfsuћ4bbvpKF6SjiMqHtznO|gؖH,l"K{G+ɜcLۮa_R>/.} U cLּ@0\tܳlԈEd 㞙)-HzY޳!TV*S}'ӥm }AY}sY4h^fTLVqzfd:;+X h|Eҥe8ǃ&1JY#It礋 )3}!bXC3ȇ5! 0 lkEo}^7w lI]Q SD5x){nIҍ>vgx_㏝5BN lWo`3f.)Mnzh'3\}iV3_$-#:%/G<}5eDN'PEƮ!Nw^-ZW{c?ʡ*`Q"dr@=ZyAg;Fu ~咁r0j9Ԫ2fRJBa 6~Y ^AmhW5ͩ69uku' QP'|l9eJ=' 1/!Y@ThVeM82p1v剢:X|܇^&\zP>y[Z;yc@^LD5ËV"?cipުY^B3GMAˆϰ>޵tTl¼eA<;+眄sj' ! ;+=## !_c`gc#@;[;[GcRm~\o+u vz66_Н13F%&|f#eugg~O`G:Xfag#њHtƋgHn?rFII+dUxbbcQ=ĕFd߮.A-cZTvNG X%m ri"k BM!P}SRewĴ´E%1&w&UG: 1sP rӫÕsζ=z@tN!ǻ ՛s+g{e+]o$֛o{O:w>O}sM3L}ծ IYDUuNjcuRclFh^x/S-FuwH+SPު?=̊D}>9UO*כ| CdѰt1iMMί9U !#et.ʝE:yԮAX~;RwL5R"AmC߯S; bYWAg#քj /3TDSޤtQmyx \YD:?oSBKf#DpZZ:帱W37ѮxnS.W$vv5@ay.fb { pƖF}]nO: ck}dQ e 4hѿ@܀XOpP# B?- ДNd>eqJ`F5̞v;\47=t~y`BqG#90^bżUyD5u%+)M#v3_q.d-4bh"0Sl * m$d*`Ѯ">N/]Z|1>ѓNGto7aF+o8y=Eb(Rv_ qGL1F\ul)ؘfGT8f5ho֦H}cVpXRaAa$5g\+^`^=GO?aYLI8`R@} 'm6Nj\/S2X|IBx6rkPO=[`;]yp#Fe C{CwebdC{v!kF*I9aMk_ ER5Z=S'Z ːj˴*VqJ'&c?IMV-{ŝYX}_NL'J$kav%vႢQk92s.U:GO&C~=VW -^l d(B.rռrW3,#Ezv:nH8i&X ŃOc]]̱RW9 yId 7 ;4Ǟ1$, da.8q =IѐZ(Eh:ˎƋMvL&] L%dȢK`\Lc ;5!2)+u&`@3%=?Ifnjhd< BpAቇ~,_*&z_1%r|>x-&ƚRyZQ_=§H؞o+ͭ,QEv|);u\pBm-g>2qH8)@>"SxtQ>}Dh/1q­ Eꮻnq5t\k|d{a.[Oz;u+̹2$!U׆Т۟jtIbҥ)GS`Vvux4rw΋!2+%{"Pr?| ҥV}!K' mSO A B1"g|A4&GܖKxz ,~(\|k%HW>EHţDhth|`j_0Gn"/FBaucPpDO9ɯЀ4%LfJ&K*rrMDLhM9*hUB)G|;n]CmpHB싧jVM(8"SFF&}k 8K^OaQwa5Ȝ[5Ȋ۱8x+X)uDzhwPw`7MLy8#斢C(E <:j%<.PJ˄U'1;!JJ0 2 ->ϕ_Uq|EƄ6,Vgk(}`@F"hl"88 yPyK#?V(.Ggt9[ʾj!~ .zb¦p-y&M\jciv7Ǿ%O^Y,A ӛqŹ .?rkޑcrr/U8m*)9"SAZK}Ԥgh#hI^`n~I[!oj&;Sy i(M$K"7xl2%S-,hTʝLl>@[$CkbmF-ZV`'F;yXiWZI}]ُj*Jr'@g` C`L []O0QgU5CoۼV!wpwp~Cwk I 6?GUO߁'';:T%W:T88YCs $ur!wćjF :dL_\5D VO 7dT15a*UV4l\ඁ ˌi@#xu3?\tM _GzLG;ĬN&iO78,3S Q,`+S5:X a? rQRt_ZDC; +XޙV}w HWeY n6BjspA$-jT0|hṄ| J?xyBHwZJo;.ՀPVklt"n|5-EǠj1y{\xp?F]S-?5^~T 3N#n`pmI@)+ "8Ë\+d{kk=;k=^99ޡ9~ҟrp-0<4 =3鏲u mmQ#WZo1o|%*` '?#;矩9~aCمDSG ݧrl |rpMXbnz=Wݓ-4j6 cRHEȉd),sFX,jq0'0:\jbŦm+=0Fx⍓.mbY"ʷL⠓k'oת9Cl㷏 –M9Eۓ푶pgW #`6h($:A_I 2 MKl@A)?<FtF!$?^տ#yI<+PrB!(w9{`[g'ϭ;5c'e'6w!6l c!!Wjym 3d;QSFzQc SvvY~J3"CCE7#epx*1POZi<`M1N΀PܔI| I YD"1;d96N6EIٰöKj}%UN [dzO'D2:̗H/#G*E_Kh̀X+(8$>xכDd|LN7M`Тo:H2!(セnU,k},s(b"ahT/jfG7j-]QJ_+ً'7=nx'?S̟SdEMLF&p!..?e[@ [|L(󷣵w0r0=l6vk {"^?5G]V\Ϋf%Pr3M ƭ ajS/3[01 (Ǣ:^i#3í"A>_ N]Y*=;{x!:~.NaN3ѴmV(ʡ[ \_oO ´MQ= y6ǰҙTސJV;P kF">6O8R 3A1@E;(Hᕍ/kY¹܈յ(hg6uyŊ VʲMe$A_0(vXbl#fGѯșe?M}q1ѝJ;ZFb9g^/L3| 'E.ѸuBLKY4PȈcR!3DM}n_,)CTC:g|)Ws+^=&tcm|~q#V,^hz?g$=wcEY+-[rg+ŜyOa9!GwO !7p 7+!٣ R'ܻ#h{p:)u~)Bɗf7Ϗ#6FKϴ8S߶ bVO͆}RNt`i[.|_=a1* jYa Yԝ-%2i]@_Ia2t:cK}h8$T/ҞItkH=kOʱ (.D-15'xi.Z,94lq^|y)A5ZDJ|`>z/LNbԈJ=d#)@}J8ShLyϙB-uEy<4 ^7:Ŕu''tm/L} ]^UY`C2']߄yi:W .*_Cb+ 6\jy*}M"ΩGuiaALjK:@p~pf ~`0tj&멢]/] \ r"Yp@ĝc@_rMxwsleӂkGrį+J.ڭ$@~|2*)ۆ9txR6Y)'uXay Zh8]DKڈ#+ R4G]Do!TۧI7">"LCe,=p \1rKA"n#aC]w??ֶ[.篨)Yh.l*z׹R A|ʫ ?ya9qjټ*\X]wWڂZx- ž:bW1519x'^7}٘Of*{T}il(RH-v,=~G0l(NtݤRm pdR!|"~!W$8 ߷egw T)E! iƍ*#-Xs_ @)?c;87]'NοÔ\=?Fύc3,zwS~Gسrsr`߻l5g`gdgL۩{~0zw=#=#czݭw@ ={fNzFwg!3#ӯ)d~??yCz"wuٙ9(Bզf #s VR2*%E}`RhhhJ037^oxZ۠'G i!9idyluԳ_]1=\7t."1R0u.iфLh$Ƭޘ}dGWFE~(D2N_7Ǫ[|FmWwnOGc8HSޞ1FcW 0L9`ZՑ83㌹`S;?X页%I$"*VD_FT[gMoB4yek^Sy^~%H,@W'Y d.axU9hD )-vsI퐭˛UϨD gU ,Aa* Z{׽ݠeϞ@Md_pi$h.)cBP2dZAWļiR倮eq 84M¨q(=WJW9|ߓEm4hG1hG<ոunKe$u"hzP^i<Ïk ur iGoTW596)hz.(Nh(QƷ/~dޚ_1`AG\k73WI2ѥ,HVlPW4Sf/]?n-T9$>0)2@1@Ľjd4k擼kxCRg^|ud]Gh'3zl״%~Nxd6i|5ju C#oAUczSb.گ!\_:Qmb!e\Vŭ2)Q"]#b\MWjyTyIg [x0[vơD^RqQ$v=<5^Rrt l=%sY&X_oLs* -ᢳJXB+ÞTi< Grb MM251Y,V*ʢ;\Ƙ''hiXq< .y|Xj@,̠~RZW (sRaƱJc.{Wr%~m T>Qݡ:.AK03TbT3D0ы ޵aG V6q5N%BF˦g#]M^Ghh/rC*֋XQ}lWZ:~ WFQ9Op ,$Cq:+ׅrPpHq?ZYKmeeFx1^A}$]D'uknfH)g(-VL?ь{ +EV0d  F-JyL$K|D̚yNYttYQK fP U$F W~7i$ BY[9 ♷bsR Xt }XUD:*ӵN~{c$FZk68lߦYMôoW=Jpj檕 9 QΐtR J<>]K`|]|z>tC%:X{c (UTnID~[Nknp4fM}4%8C kFWA223MSj]S[m{,"k w$ZzM t{Z~ҪMWZ&aR%djDX $Wk2h+3 7>62>OW/!bֶ2h|L WGt{1X9c*Z@~6奚kT[g|niZ_G'Z{W!8s$bmN˝ni;1;{4e4WM|~4b"]t8 @[! gEr?O:ҲVɬGMe>Ѡ{@_Vn. ddGκ ¤p7ȻrK d66ԡdF&-trTX MO)#+u-$ \RzQ^?יP8n׿R]ggV*%!Ho[o0_m, Ν͍還rwx/aq0xЭ>]Fg4\XqOQZ U|6a2*Т:" Bj֐k&Chv!wvBwv稤-56^N =(P!<-{Fb?b0D?Ozo &u;< R.YAĢcC@Ls1wOӳ H _Ў{/q GAM-.Ʈ^KA[<*,0!yC`ҩ،Q"aKJ]}rSQUBf"E/ Dj@_Bv$D4< (:AcYDNq[1t_fD )HmrV{Wq%_"l22[s&㐱vڂ%=zhS61}{b 3U\Վ8ԶJ[SnM$Lp/zk89qQ9H;TaMyPH9X&ӂi7Zfɲ'3,71t$I`;ջwz> J D216j׫#l;^|H\6ayiV[RCʾ1xZ27M*XE7.pY|| ]q.bP 4SJT_kn .1l":iRLnQ=uE7:+t< Q#TbȔcꀁfkD~:8<`ae8蜡RﱑF[:TZbp|,ZvJ&RZ\xMۘޞ'A4ƨc`'bVXWn4 #;05"XMODC䠌'n5m]|ș)4Y1s=>y!pۑ*iQ ,@MɄA0nj 0 *"bW6$ePo85U@ڦ|ɚ/zX1M?aN dHs\L_Y{^>:{pikVhRU"Cu ZY*<~[; =I[I 1rmh܅j}"(>g;BgA #>q2$W%~}ȕYrŶ/yj̠slYܠccmwruQ\qab&}lhDL9ے'Ų *;[Ltjd[JѴӯB1jo%BCʹv,V/R3v*.̄[8,r]z%4PR’ t8BI}v)^ uo\QTuɏnj f.@DsBB7^³|d°P^OZl&P&[g]S}֘o{G+1,u`h5xD,MnȬ'sZ4:եOJ]P gzY<pIk7`ݫޖ䦵xU(~!g3a rۉgm)&5r5>˕QVcOL%*~@]h{i,QywwN_28f7GG ogV.b@|Dʋ \ yz~K#"m}>}3y@UFsxdgff@&Mz%cp"YN˖ke`wٲ38t]{6f6z6{{~C9`dgez`-]{_ ;-=_l3v=3 ='=5A]3Y|`b1Z`/Z tB8 drD޺Tƾ?ycRI\ 1DZ CA A̡ g҃|ѣ'FjiZFcKyS(2FU@[N嫽gMyx~q@d6*ƚ7N{WKpK n.Tb39m[ˤ)N%p\Ƅ#+#@<3o8dDY>@~D>#8M|$$%6MmZ|̷'ubE*vgEѹ %d|)ӀPY{q SJOb mm$ Tg>J}\8-4[B>: <7D "vh=dnة׷AV1(!ч"=W*}C"W"NBk3yF9Db&KCf8";B $Ԧn=5xU(凋ElMiCu$/`*ПNR"4H6Qݣgh@_t}tdAVד%K.GY+gEd+2>z71E$[>XRaLGB+&.m *@[S]SϷP m 2~U"}I=1sny*slj]? 7tFhNL- Glp?mtH,(F|??dj%|uE;ACPh;!lťf?VZ_5i2=x N2L˦/0VΝRwF7\w60lH2Snm~upSjv8<<% j\࢘,=IhE5>+U3ƈ tT wxtPce mXRJF`z>r}qF`v(BռZ}ʟ(P/ _5 ֏pzQMva'r]W= 4Π}N\OpgxxRF)p]HInk`0|EC3@KieI*ڦgk#2";LvQ/Hb4c߂ #p@ v,=;4 8=On$z6bL(J F$(C'Oq\o\2Q!kJ${"i0bPȁ `-\LZPS]V4r)wfN HT6`AiB-Ļ1Д"G'd5"N\5v02Kr>hq+)o̭nwRJ#z,ޫ? p1aNYD0XfgBe]Dv[dvOfc+z<f)cC, VIԶaH#أ[p@RBׇq]\1N-i.Z~XFQGR0TȾ9m'(Fq,E$ 2I8v`^hF$>@bVm&a}K7cIZ^S2|)r/l׾ ^RK#4.31 ,+ͤ :{p xK,?9UbvYĆN\tBu*GO_ \"qA锊!99JSURM!}ǥвs|*w dt6-R|qZZ' J:sep%QPff(R)x^d6sܔlQa+Er}ՁhH,@U++R%zUЫdIj3SHoP-_@>~&iAQ ܾi.eg:\Bc0ZI, w:R&ԅ6K=蹷ѩ:sPN26**s0Z"G;)1䤦UNUfv7:,T9^"bͺ{f.ꏝDr=:Ga['|jb9*Mۗf$%OH,b$t땿 !`H\9Z`OusxXbrz١#'{%J'9MYYac5`[4"HV#)C?Kezk^%=⬟+ih$H"l<<1~0M!o~xGt%8@X'<({]<1KT0dD,XG$s*Ț㲁 9H^}泙.?!a~MMu6x h E)Mg:A_-\]= u \b+\,,A%ӂGRtf7k'cbR,OB#=dT. ?7dH ˌ}kg86XrRc\CJ n-(z 2D2))6Y|oo\뀏mEmE\RS`8k$#{R4{@+AvP'xyS9BtxDlx^ DlĬP<9Ve:73QZC$-Hc"~N9Y6r$aqtEhϫ@O`> _N:z9;6p[2 ,HI䛕gXqݎgu>0Qj X2]\7 ܚ/*Z LO,OT;??|P}[Q4hmK΂l!q(Swik~VݡW{49H'tlϽTxN7<9 G;cvr$r{Sv3jbHh]}).}Sfci]n1#lZ)n>b13_sGjkұVgρ&k_4N5¹A-Q14o /= znL}. ਈze}SZ8M?O(_o]< Nj>Э^Hv6zhYלE 6dL~yR{m1xU dXU:7;Ђ #K2[ rJ/'(7e;%̿Eg ]];= x|Vw7]lllU8>Q,Lv&6?e Ug DqiQ;tHHJP #%PNo*s]ٽGۯf!$L@zH7VavXbBz|L=0>^LZ?@١H٫Prr= uoSnrK~b񩝅SV ӭ8ֿiH!p8&0ĿI4q?u"fگ0__V]|J#,h$3Y):N3k:1F P\ KhBFćzy~=L1Dȕvi>"_Rp fx,ɁZ1pdȾTb,DN2tfęYYգV6BRK)H#Mu:CX*FGYtC2>3;P?WuN 8?cqActyjZRd=xǶ$8U YV G;47]r%= >}P&&6 (MJI_ǗUJuNG ‹뗱B;S>KIH ِKHorH-; ?mٸpފӀxg=O}ޙڱp4o݊n1i8TK'A=7-jUFo[2 ]tD =X(l3KkÇ+g 1=ů)oOgQGp m)Wϰg2Ik͝ #ãm"9ס4gbkG;gQXtK'P~>jKL5/…a#?,弼E*\0%!7rx'wj.D[aKVJ;2}lt9H886)i=*tkؾW/3yz]XܱNR 3@zZD9v;P>Bߢ߶wE(߸(ŤP_EtXs0¥T?[(#$v ~#QhkRF okk;0PsJs&+ѷGʉ4o7|Č&LyC߯pl&Ǝ9IqsL2c•E|Yc(e̔F=6yE`yT'@j#~\ӄnQH=fX q27v[o NĈsK yl+c-deYPeqE˓^"G{, ^|_w.z_ОTE5|Ꮃlp/;/3, %.&}^;l e[Q,T ç} .2dnWǧ)_Iw_4,L47Kxƿs a{kMA}q ^7Yw| gGg#P ҈$zJ*U# ȁ9^~oqP$h&wwu܋ԇoOO$a Ҫ@[+ɯO0lȘ$>L**9x?hmLm=$eml*״tiֵs?;z,^??*} ?hpv~T7grCƺT KZ.x^qj(l)O&?$UV׺@{CX蹞V#K|hlV`߷Ka*y,ԝ F02<,quIS))`;%! };rγ\Hܠ4\@ 34sq/ݬ'WB/1;q.12SXXy_ˤ7Ԝ$;I2+Τp"'ikڂPsd?2E2Q?-j^ [ ëCpt@r pU$:GHp%"@ҀUSM0skEO0)|VT3X!6޷z{ZΏ&5m9]IjjV}g 9i̦>p$_H\^&جSϣ?G5*vjnU6_ji&+J졹rH~c:COn)2R\+~֧ɚ]#uyׇQ9L 0e'YyzvRxJl&nO9[sE8L :A:]~ {E+O7Z_g5[EVuvJ62s!al7FƉCRɄsN %-?hwFJiYnubh] 30fhiHI]:z'n9VqqD4M E@dt7EdKNqAel@GR RTsҥ#7rWeRX> U2K%'j6N")i8_JL\ cGmj uJ:79Vy Uϫ&솓E! ٗYxAV/ 9|t2/ѓBһh8(*|RF2raz|lY9*AN@I/ջ`SQ} #0Cn @&FhP1 ժ)5hag,%vV˨ɊL1` D9,wMJEc=-c1] FdA"Ne^nD[tϧGlB?%RVџ]βG=KJxKb4~d25{ST>wVv #]Xwm[kxQs3MBa+Q" < B*{X$s 8RvEpsD`^@'^252jAN*7ՙ"F. =k= |L^/Fi-T .G6#)UB%.c<[YfE/f^nn[@4 |bGDbC(yMҬ}0ՑTouUXzY[ZyPPaf'_E%!BpLA[Rg>u?쩥WtÉ84NIS\ @:*R+rڱ`,2i\l  Jh{`XS2I& =|T8N_TCQݓU#P~'BIRmqzfuCN~s\Q0~ʃcFȂݏd#-T4WSK1Y.'.*\FݦJLiz[W9yC@vEϭr (δٖhXυ}TMtI[4 ^$=~q2JoH7Q-U{;?א޴ fYk o\)}phĮFf薆88Lw-N ]>L?S)Puw>(V=: l[ 8RL+[p1^rc]:a 6pmk1T7%R譫Q(DF]՗B"8dʅ3XGT1xFAy-ȗغ(.8v&Duy LAҶ%y&!3{ESKZ`h~4"'8IY fH7Ҵn2?ҔB%̓o[d7ǫNH\W^!/\@ѐ^7*QFt$R^@q!yP3L]@~ҀSr: $E)J$GgX عQ wL,9R H(9pfi4)p eJF4t J^̕O@8 4֊<ߴ?Iv qm=[c-r+'X'>j΍M V̋9lv)vWWʚT`ʉw-9.@݊]3m[-mK+i0-`BgբI YHbgP-&{= mѫRtQ5=K o()~.edZODB3M\ RϏuQ-(JgÿLad]`ӯo91U_Cmh\zṆ̀OHc2#vk}o*VA?b\^cqU_E2]" /ejVW Q󚽭n1"?ec@+K eQe|ۊ!$Z:I#!Ghkq a~H[TH6W 2x+Mڪ`dڧS 0XK!+9S{IKfV12L|ptsL9eŃؗ:$@m9^WwM1FNmɆ"'/b\dzKvPR/^pD&o aƐl\Km csՙ&J2eED16+X|LY,gTP%WqC3Q ~V9+x/mk A[9}؇ͪdb.Ov$c &M_CVk gwחp|zW7/r@9=`{hOluA|([M}ª5C&N͍8Z'IG`)^}PKn-M: $.>!$9Fj?Wa&Vp hmYldkZtledn ϙ2x&9q:$nfi[8[SO&(_dfp1jao I"N9Hn3Du"lɶYf,T+i]@z&pm]}hWʳD!^ ռXH/4kRTҐ˯0q gi~)[ N3RKؖ-KJw_eWѺb;򁠭HZYCa䧧*/r-umɣ,Uu~F@-w7 >i.t@ m eo5@s(^~<)Hm/keeMU-a'm@"#YSJ 2SFo8?D+T uح}ϪlyC5n1(b2ԡ}5O1d7?'dO%DhAZwG*p,eY$& I"SUeaH*٘ Bщ< H'B5$e\g[+)aD[A:4%,e`+Ϊs`WT!V-A+ϔfi5U\]]CggnȌ5ygF=3=[xLL%{=4Y9FM6 ٭D[TӀq#oO9@ Ul)q >nqC= {$pEɪ2ָb"_͜$ *s}륍fo,/Pykiɚ2c#q zoM!ؓEǪ<;{;O 7c 8i?H$7;_  RDSj`v[^ Ob+S ^RjPпgG-VF6$AĹJA;q{})0NoG wq71svF{WݼӰր6cIٺ.*}Pت6*Y?K[T1Zր1)cxeݶ6ƶm۶]mەbURm۶m;Գ:Y{UzG뚭>zc澛;la&*VATsxFҒм~dRMĔ )3@j:ےz9XVn`6Ne >a!Z"Fdb ,{:Ng"K#Wp;f T{k s S83N Qs{_&Q8J&,AJ}C0qQjtmB!%m&Sya D5V JhqVbGL,<@\I $\>BAP`fZg # PٰIm3DnC^EE t*p#؂`>['x-a0Lj ;JH-$@6ϸn]˜CPva0^УcK$|/, F|pjT G72 ؆8#8; Hn!)R -?>ak1g*|kN>#Y7TռH0!F'8b`?bF='u.82v\rm\C;2j_22r/^0Ѥ gʨjI<=FLiZ&> JvMA8Ҭ*ʄh }phӼ9WMKni,󃬖o[rzq9 76娩ka]׹ b&I?G̛R2#{ ƗY*·C'QdH.c(vjE$PZ9Bak~Z1] -&ϙ"/Pce -aF+SfpbLkJ`|t$ ]C^f)h-R*z-%vRQ k_0rnICc&a'Kx lBEmVkbbs!}SIToگkOh)ߘ[J{ngH?3?G&O0X0L̞ &ϒH|Oҟ3{FF:FD UsLtSYBOd>k$HNbp/jGj/݇ լƣxvT {pB8&*sy+Y"}$XcP r$ikQnepg&zwveY$ENkSij6y((U|kXjiI?2 k֨Qx=~zjD5v7{fxE:^8'*;{馽u&V56)/:Di|M)g-DyF>Ѐazoz>p\yRJAK0v)ҷMԺvaD˧Z+ff5܎Qܗj3z$ʻryT)`y4ק_=#g2nEމl8d^d"Z3Ol`\Nn=up5g3. Ol?C [?ϩ`YUdž#4HF bS^uP_QA qQCO1l5sq'sV1r[SpW٪{կݒUZ0,Igbԩ@^Y;XqɻܢRѵ\ |c0WWG'E!Xu@Y3QQ!'gԫzz; 6;(,@E!| )za8S6a@V;P݅L( YT n3E'WNȃ-bd4DlDcgU_ iD˲YگXy g, Ł[KūW?4/Fn՘V@j=Sρ'fĢsaYC~’D5Pna#U7Â"@9fl5a V~cv2"XK$;Lv(Ҳ 0zD*BK쀬 (ŻOg&N~y8g`:]sM?0#v (QN-p43M[T`t"ΌgVv{ʃC<rsrY?W"I_=|E:3VQT=EA',юҷXf24A%PV+'Hٗ$Ps߷ ClП { /?`yr|u[1UUv3ѱ2|ƭ`:`ROYXX>=~fvv:O3sp0q10pcCs{ix9`dg3>t, ߏlVOfȄ?WDo cY٭]~ EIڋ=%;vE^Y߶ogPD-8lKOrmey,DkՍsN>Ԁy$_cj^>PxJKb4 2ڔhq7F'!晘Cmݷ6e)$M]AV $g7di>k%)׍o~KOw>[Ʈoz>wst>/Z{<8۽N*EBwxil2f"J#')fՠW̕mQ-1]<̯lRu,-Fq~sf0MbCn#똥QDᶙf_N^`;&>ٔ25ۺX@o:rMnh& [;Aub*T ^F ݡE)GA,5og9ZRif/;0ӢYW0#CÒS Fav 1n="KiZM~"Iǡ?arTSL[ĄnҰ=:wZ`M:?(lﺚ*|/,h85 BQ{f  \tOS[~>vqao-h `<::q6:V>[h7f+';TNnwO8E*\pdrׯg.VU6;W#m_)֨3$&Օ #qZ3Q`3WqZXŠwfx&,/"qdyИa֕ר*#w@TLL-0 "d 'Uz^gH^JF;-`L qW st$Vh`/0@+{_MlCk M>zRbA:^PEblϙ7Ѵ |1Wغ~YKIul"O*0rʆZRFj@,/e ܡ@Sƍ5Hy! GX6jqG0oPP`q0DBW*`@4Kƺ CS;N D *!0KhN 7IŕH\1^Tw R>8?w.gG_̈C%y#ɀĚ:E%I k>M0ޟB?qEHK"dT膠iޘǙ7]J0gȢNUGb੺Bfm)!޲ag% u&בPj_:ZJ \rݯ 䬸E+d#-}}/f[2*Q!nG¹q la(+R%!$(nj1>NH i8޾,e`*Lc7=۟SAෟC@ Xxڴ@xv(mYs̍)@4 ZGT4" M J)e?Wyl6D9j aBsӭ]P4Rc.Zyk !M8 \* l"= RHKRMƨǙq[~> NmFhJYEZZo[E3O˝C>զA!y8ވw(DΏt$Ku`tKH 2F;vU!o{ԾX9v 1-zsH"Gv0v7_xGFn` dY+N!%E8$QJ}RR.p. Vgf\bRְׇ#=bDi6s!Y'@w[gZ<#`#\},#^ V%=*s<4X>t$ b$HMZߓ)bȭ[m t6K+. z;=qܔ bIh{;EMnS06pdKRz, 4cw!tgp$kfg2G=AzƷGF=?fQ r~7OG oGA6%x񿑧LSS>72q0}@g t,ꀅs)NY垟baSnㆷ O3Uad]:մrywj\3Fd8a颲sB>9_K .7e+&|V#6v/dR{98ZBuzI `7Rʖ+0'@g>gw=WHO=ofypn zB&|Zi3|T{Ń٩to]<9[aPfc%fSZc=Vo王ri}e 1楫;ϴ{mI G@ߒErKB^&E223i+5"z ξĬaR+lO÷^*T MDvW³>dc9gQ\*yS8>"L^Т\ScR>f]Ne;inK#|1Pȅj.dvˇ 1xBEG1z^/QD wh[B3ldz6$a% 57PE5*Dm|qB$}U~";pGuZ@e cpEXrkc9.RTd2s4 ir 1QNE9 )*J?~N22Ks&Pe: ДJ}c b~ .bbRAj n ?l.k䶖Xkty5`q=͸xԐ s(+04>"t9@FEnë!4v*rgDXU0P5  Du?0,KVnaZ& zOroKՄ:CiJ.r^6 ~n8yL'zN#SEj9PwUk"@BꪸwYѲŕdt.y6 !#=uilT\7ҸIGݘjѱ}'\C\yQRd7Pf4%jMrȻdqYKgqը@82OE9cfL⻲_Q6muȼ=պYj$1vb`K*N[Dݜ>X` UA|5/*ϐlqq $ή540<9`zU3Kd:;ye6 ;yȢ[;x@TaY>Am xX>A#16wϝvX53:9 =. /_.k')ЕGGYiG{,N |3TcA5V.T#ݧ&D|۷Z0b lo^*"-ޘס{_J2$+g98$6$9$!6d>uI|8p ad۹v +]>A~&3>qg-6lZ(;4"meoln߹1Bҷ9d8^H02ELѻIy62 w:ܽ흕AJ aʙU&_s-]d6֖F)遭Z>LK"lM^*-xueawZ&"I`zx-N8sPBtٸܷXeZekǏqf i/ؓE2znl! >7y_WyODyFi/2 \(ӿz4謚&܈/ءL&݂"0XziYC#~ZիJiZ5,wM2reP]C*:R.VU&!}XQӬDlFYpK9Xa.3f;a\JNpR08 )tNE&W£02c`zsq (&b t1eīvːҰՆ0xL;Hǚ +2j$Hkio~}=e5W6TJV+liˍ`<Ѻ!BMsͤ&F J]Ripjth~ :Z_W/x1h WqFg5t%>iLvҗÊ&-4k ,ȍ~v+  V M}=ۋD e_ }]#u,D璗Ja^2fA|yXc^j(D%1?vrx1ę,MTBg]2U}hr˝J62,;J&VqzYp ڰQ@{3H4>4"QbH%-XM3孰TúʳO(* &V-cc[it>*P BXLS-mM(&u3fy-( r4sr1f]w=6ԝ#o؋ |\\7^cpq 1S qf`XL0H%4 g@Ch<+ D!cΧlOLNe$|k,efH@ 8cQ$9b A`z;A̰,9`Ų A>6~%Ki;VvE"F?S@ɏ?^஫<_>7 $+㴟C|Dn>ll+dHmQ|ה"o:^-C; "֘]^C⒁W}tx0/RC aƗZ}`M)*} Eh4 0/Cgnw&iV( j ]2LZ$M W$@?^93"p'CX"iAeKLMM^/RbG^B&x;YBҪ HZGA}}MLoN;:'69qIVdtx]Tv(Б>.2_8Ch7/K :!^`hJ]x❓7O^n[3>?8hOu껠~`qo-_t؆h0pGWOxKMtsgws =H) N{w򪚀ㆱz U0Pii :=I8y&U}䄐v.'(M#&E~ 1{ ui,\b0^:مH%I@+ۉg } +\mp)C|MH :}tZ['|r{R4!˷i1K1mU"ztċ f .wU KM2%Vjqo$4=T\ [렌'tʀ7^ĝH g Khߦg6Č }kAr207r2oP?˜N|:*cE=lt,̌)=;㧟Gק,Lt̟/@`(c(/ӿ|mv/ pA+نmh#icq{ Mcf@z8 ǛxȈ0@Ń=$hr^ſsKH0ZCe| Ź$֕94rctx y=E\6P-+9k;;iԭF gk|۪ڷ˵o?:|n鉣IGa؉hlI[P>"W%3|f  R `CNyضnDE}aQʞ@uq`0tA.Kjޚ{*!< p. %Vw0 %^ p"dDlrO挋I"՞tia)WV3piAن5_SW]>!e*rIu1Senrh阘켃Y̪::_W)s Yϝ(ıdZvpU1n Ί‰볆@@b(hXE 5>u.1Mhc#FK}`3:]ƺv';.9?-{&3ͭ5\3d7=Ku- ԋNF<%=,`B[ AebëdW`xa#HqjYk 1l[!2fuirLDrDY%TjY9+irx+U5M,?PZ^R H6=A6?zܳL6kBsO3* 4= [xO@1jLOF oOҽs#Wp+72(R<@4bsIйn`q~X%mBW(4~A.[dĴHU6ހcƐ{y9Dbf#^MÀ (f[İC \ Ѩ DN.;hTuڹzbSO~ yx)w.ĺ7mpS~d6;?! ͭ[s đ{طSЁʏq:GL;E2MD3F@;B4_:Cja?48j5InRbj≯' #_)l.qTHsL LwIJ`@T2ꢶF$ (*#VCb#O̠E=_y xY;i8pp7NZ8$QELQ\ΛEw**}Q ]PnYt1d/`HB֗AH6SKnOnpy"+b4hz.86i|lᨈ0ZYA=,ezY}NKcG:ՅœbѪ]`>^N"(]B jC&ci87FxMT6=1r͓{ϻ;^{ 0:l5 v7HYc hPI֝z/nDqϤ+&ttv`D0}+d-gKԢ*{Q8qpXSsgT7컮]<. NQ=%qٛ= /x6bi1eo &%X=[WIᦽ,ѱ1N\q^ Jm lKm#\/@$SBH}nQWg!VAn՝NJ?oGT3}؝{r}`׀F˭j~./q;͕bo'n3JGUNW iÌJ5Clb(CʨzV*u}X-ղRvlۊ 7#o#z :oRB8.lo%fINK8<[ o D?uI'efz3{ `e-U~ ltL Ѓ [[@Y♿T`}^]i E(0\Ob'2#!}D <ܟf\t&0<3n,) J7=[O#!S#ɣI7Yy0^'SC49lJb]v2SG{MO@?h3S7m񁣹#kѽ@Fnnswki]o-R;e%؉`wѿ՘ϊ/w\~>kRRP&w])20Uݱڕf[R嬘_e, ;\8iy;bQ00D-b٤ v|.GX 5-)YFj%^-̷#o&%]#v Xy>@ QBH!D /ק%c _4z7p?hl2O?$e# g3H˻̔7nHyOSp5 8t,d^1 eH]g|vk s=9mzNfz4=V`E;!cq[>ѬݚY26x~tD5rX|d9NGϗFÕb"_/ o/K\PFM)P\稕LIDw]%J\ED?4t[у,0RdSx3T݄VB=lځlJrpVsE#rVS9R*cE7i8dk8T]66 T+4O[i֭ټ%=M-WP5cu"ݥAQ>ccg3_w/B;#Р.Q )>=YZ&Iw6N^mz0EO (l1|ňǾb9yOn|PD* ذ1n܊acCe&``"P,|1 W/NzCUO@iPDv \OƫIyW{z\y`3`r}sg"UњWf'Z - 6Hqj&/BH# jQnt|GE 2zw:կl~ "ұ"vۙo})aV@cﱢ`_!Hꨕ׸1\9I̍=A ]'K @7 Ϗ& ?Nw!r-̸Y4@Ы}sEDRjkZVZsT0r,Rio6v"|w(y})ٻ>݊71%#6.FiMd#1jeqŘH/(/ҥ_D3*NVxãB2@[MwzT @si%q!Խyb5߶'~eeW'b^'~ezntO٘9X?EoZ%ktS{f:FYf:O:љMԞ?۟PV;`M?+`OX@:`cfet&fdA313mr ]1[Pt ᦿٗWYdxi\уXk3[ go5ɚ|[ڄlLu|)֨b=},^ӛwhЪ܉ C<4R_}_hPkUWZ _ \^ud!X H?42uIWRDDLhDYB!>ye, uf9,!Deͱ[Yt/<7@P l:jV0lP7ImL51,SR'a F[ܗ4;}%ǻ(l6%E [}h΀J?ti! mIA-@kYKSfBtx#tR/5 L?iwMcM^=Ȏu#=ffi ׋醛>oѺ$i@C?9{K¢ŔeFj(E[ f/mݝ*w̅+2ZbsN󔾲񬅫;i:6& vIL;<=DLMsG`HQ_F@{OsX r)Mܲ]i I7 ;I&8\~Z .`.`ZoFb[up1$ h=3+W;IYIVҴ-( I>J /% Uԡk_k[eYxd(گ| e&`kIǼ‚&e D*]=ҭs9?j-- ى-Z/I 4 \ǟ*R7=).+l bһ kՀ@{bH`2lCt&u$X6Tv (nX2^%;gP{k }c-ܿdgqUb8 ( gH=Ehd JXF oP|W}.L[/<ѡGX"@r‚p-fp**{P^Y~yKjB#bz6U38W2Q;JOZrҡwO?Bb\V,z5Bk33/Ph z~D饥XB @,T `7hSI!ϴQ1hpG$&l@m)m4 7!k$.zlFZc$5>j {PDNo/(q Bs ՗{N~0W8޲}LmŊJ"퀖cz8 v"O46-W\N'ui+j[?J}[¶òߢ8Kk^ DW\~`<9ov.[5@dʶFHkk4bתT?l'] v[D&`>ݳ`e1Ɪս I,M-V<mN#pp~sx p}#"N١ .C僾Ly "RDO"AD$LF PƤ( Fae*vM|$[`vJSbR_&G8A**)D;11auXo+1j|ap̷ۑ`+6؎/6A3[َ!14΁W.JȖVQDr&{gݯۋHIWPr:-jOCa?&ь.m\'M<ߛXt]ler/@1;`hƇnO*6${5-΋x#q Obv<Jn*ʗKED\i`𲿃廅B)„nFlt~N 96Ei1ۢIf$.0*Mx⍁뷯jWV0gKXj)M}>0Cz3!L-. ji5J/7qD\7 x,і7bZ]\3oսYv*+ 5@%cPId?ITCw%(ρf&D?homРڨ$2_R8E\L'Zv=*%fD䙔؏1=$)FaX ONG @YZ=D KQ?6:L$?0=Tt0[cdL6(ʲ?7`46ю@jd4 aI&<6l^ePv31SBO98#Q d 9T*3@p>H$މX)l` P/@'J)}2&V}EQ.Fx 'ѭ(ЩDp:%o _jہM9`4;O+)&Z(Sf>5&'\Wy5a$K R{BFhZьQ4~ (p*4pa(ôv|ʾfδ_+c9BJ)P1C\2˼-r_l\`,V.y +ia ~sM5ʭWku")MGeUdo=N/90G`Dva⬃3rCSNˍ螒%pXV#3mZ"X:=Ln1'aLmR3i63u_μ(0z/MٗG/5="lBބfzhV_zj** ץ}gCu6/ 2H=TB YfR@Rmϲr"< Ѿ}&w׬ &,TsIr3E.I/d n49֡>CN׊#Mµrbpϫ[l"\m״XcI}6{Ztu^L+FIַ_EK)],aԡFGkT;Spk+J fWc_,SlE-skOaXāc^(/'!`*&+Onоթq 1G3w)6-}#3㧯uyڏA}?Sq680_݊\|H%jF :>NTYaF*o&WTF,,~ QDl1ȅ i [OrQ&7^,{ L~Ic98tScz!fy&&1״X({ jx@6ِvVpTZd.PW6֚wGT"yz2Yn{+nܱQcs}2Iګjۜ>v?O")=5:U}!ٍܑ?kzd^Bas JpmvӃ [ࢴGtWa]RK;j%~de,ř&d${wh^2H5HcyJq.uWֆR/ټ:zBSPm(!}E ؃V D{и-x ?k[8>bdǍ,rFKba"f׋A[yJq͵,9rJuW~uĻX!£/-rzZCXtqS0+ :'\|#>el,l%\>W0=,t%G\T{V:RVLZ=#_EPտSrHd0kr6Ut[eC8U; 2=HK(~O.?LB: #rGM" 0Znp)c>zNf!hJLѨx͒W,ȱ >ЪVNۻ!/ Pkk/Z; w''vڭvvnPOު۞,ڏx ^w Oҋ9nďvϩ[b99⨢ )YB~!vn`wnlq_d2Ġ^`EӕJIRF(0ex椑<7LQ-4 ˙GNXBBWr|6f1,)*<~UA~2w1q'uBRRy#5`]FV8rw\E8}Te^4UH:/Fn"o~dH*SH'5V TL!%l> .# <<( fo P( Ŝ$,SY826*FJA=SW2|:ʝ|vSϚDL_9!lGBCxC˯.+`9M =Bo^vߕ<ef%&\.馾9 X6M( ˱ }SQRZHD9v EC Y*͚ 6!9U?ٵt8+]5NHշ"NiEE`ܫ+ysԝSV0bnw]ޖ' L=92=bYٳ_jA!']Ǚb@G:atNKD[=e Z@VA˔}oy#sԄ'o?fc&7įdF;c\ QB^a-2Fﰼ-PCXVh&wqtFJfѤxs Xʚ҉3^tEi Y)ۗ# $#2&0^[ _[=viJl(sI [&G.-`(:\h'%,o$F0pбp00ӱ3 {W6c4V[Mۭ8~n߷YX߀8~jDd ~7tLf!=3';맽 LPO>{O+q70%`j |gdd=R]!jr't KuMKů&Ds 51Of鶈'& [l*15DFǛ&if/wL3D@bAE3;7!54ۖx4NǕ^]p FP⽿–UҐ eRϕ0P* +9˜V^m)J/ƫK$J03ETC3J|Y T2 JӂYUoճ̻԰U1aFBHXk/!yN; )\_ ;ɛ :/CgfԇzOI濅p@i|gQIH>p"'߬X0gҨ)*3zIH0| ԝ[]^J+b-D_>zXCyvV맡=2j!]Rq1#1P-uNHJ nfKm*$N9n81{A 'vVC&dXw@:j#DF+pK;FO+y0~0d_{$D  g,l/&Rs)Dǔ$).k!Cv}LcxOkt/ #Q&g($Dr Pؘ!\Ka` ,1k PA) n<@P <3fbm)M85W e*dz| n[$MRU 9!]vm\-({tA^ɧi]4&Lx6X&Goiõx[rabfD.r moIR]1 .&fV_$TJTCF[I9KEž_46 x0Iډ#mǔ:Gb3bޛ̹ڱ+T -v@pTΰ!hlE]͎YUҥ4Z3tnE,{WJSFe 6SQ_=ĈS0JSB8J=nYoc 3P4H|dbKxx/+C.F -ͅ7Y{Gg.>R3WXK Mkm+i}d\2ws+)! 4%?"Qv*`2ӏ%b2E'0G_@~}yޡUN,Y""/FgV ~LxDD矏Y-p(E9}=8QmPxa&!0P_`5&K=[qѦq|Mo֟h??(?9`=e}!2 V3!~} :`a`b _m, ?se`D??jk+ x⿃7AyAy逃ӹ#Ê3êDUʭl-M zT1#>yvXgg0[mB>IG}Y"ƱGcwrRKP#-ޖ푾5p/H(rgzyLJF P !1܁9feN$ruQFc3yZ[|b0"ߘMnrC1&]z|ow!Vexr.qqnLm*.CA!]~qv[Fڗp>fHZy N"kWd6]9>ˠ};!` Dg4-fwrYmo0Uh^:=U@5Qn`֨ym"f{Fq[0Lq u/ȩ )uUa.K x9L*"5hsl +/@dƨ/ _klֿ\*S{c,ؠ| h(+1bQ=  e*BAUw)}"?Y 5?9OGybZ"}r< %_w0Q6#쐷 }p( VS9TDB>[}]4DEWk%hȀfIbhEPLt)TKCIjX PlӬiHe2#AoH93-3otn[aNʌ*ј5@D (ءԋ' +etpȞSN!-Jlt"MCHhQ^QN@Ij{nƥ3̷BDi2>?FȡCQ77 ژܷd7-5TnRM )AWL( l:tV훕TG|EG0df.@LLaB?A D(yajyEv9s-=4u x1HSR# aZD}hb%GCZ5mdaƠ`)KWK/fFLe1*;ce) 3d*a(^uc)MeTIO#{ |Oũ̆UA&\•Yc~N\*Oٴ.9vaɃb.Bo'ah& fv13B !f?%GR`iEԒFK_KCUytVّdnR [d;@ɐZti7cy5!j]lnիFyLfZ9JpaʝG X:+ԶQNQ82Dq4nRJ `40 %( Aw[xq@{\iq Ԓt='p%wS]/KЎE5(OI>VAv0=R45d%,[ A%]HpEIq ՞Q$;y֙(_O]b}@ ΃L;Y}{C+zA"^VŠLV !y{pLcv@1y698rgҩ跸o1f0RB-`ԉAw*o8P fՐ1DkTReޜ#9]0e *J aŎ~ !s]_ d5Rp& ~ u`K sS.BQJWi⸿;} j+ ~l m vۘ،dеw'Qԩn gtӵh̏i9.%3xuj^ ߸z~ cUPʶp1F +Đ8؊@;ο"jlj] B w`8}RKg͹#ID .+&{ijaac3Bb*D|ƑB B/ ͝Ecȷ~}z{,GZc)!R׭*nt~Ż;3BŸڐJ -ON4}6T8ڷ%1;3ӧ_1,VƑbD~ s~ϙkK&ΤM=eg Ec$ׯ68i[mM7gB`_V0̌BM~qőڙֈ!$ba&͎'߆ ޶nܓxl@ ]q骓 ̅VܯEh.KksB[ ,ik tיS/WޒrJWU[f5SS…n$ i̫tn*x=yRF/s-n6XR Ёfq)rcc0Ш ձ9]o50NߦCRm*?ܑe7CHD%8<??-nq* m>\9go(OfսI6ZWXs^9:Y[f$(ހMRHƩq%DAqڴ urLƗ|m]qrQ#XFϾ&tK~X;ӹUt XOIU#y@*V戠Zc#df2$GƆ}t 7b?5ǝGTe w9䍯2 *KG:0s- %M)-o~'cU1)^G3}o] |:hɧy'|-a#&:?C^:`kn'/kX? 0>0r"nYjHʻrK3D*Bd-HJ߶LnN(#DdQ׾Y \ Et|ZR~]6>LMXs rUTGH_|m_?6;}Og=}43Ϯ裰]6ک獿q,uJ9t!pRꦶxrrSxʯs>VԕxG?؃0@ * _NG&>qxB4pKSs%ޞ»W&e&@8Z'ӁY5f=9zAe'8~jL@~[ ?UL`#ј{<#C$ޗK(|hë\ oKs/\s<"tg)\VuEP Y1ӡ~79z Y*K-f?F3Xo> 2.Rn^%A a]M|4XB`PbE*.N_ªk%k{ؖD5{WS#xe3V(xd#@ oJSr68dE˶Q1|9aPЕR>rDcIO(Vwg'N[L#&3y %%^.jgV_g,T'ei|eJ@g'r|P]A3kTybZ,:H@(TFzBHB* un{PBj^(_dDKA舭OLK| @ܯbKW\ؔ%#P',vҍO879񴔤z!! @*tUٳX3dW˞7Bȷ@3D $Y?ԅq#'eQ°Ys%f0Q6({j9+M9ELƷdb;=0m``gОr3 8'E|r44d*{]罔-Փpg4= R}ռ*R:,d\^y0Q)8T$YlxFcЕ<=#ϫF^#h^`?幙Q_m^LF%NUfZ_/^X:js{I}Q̎|4r N⅚Mc`IÁċ靆9EW$l dp- :8-Q@ Ea7胏~qg`Qڏp 3Yn E*PĠKPΆOi9<@+b(oX,¿e m %ETN}Qܜ9zBaZ o]h;<;u7j~_ l`dao8ᵄ$FiscԎ/ʚc-8>س?A01/2mSvꡪûcŬOaeb>#ֲkpD|8Im #&'$P̄c}-:p$D7фPA~1n,/SfNU\w2F#4 %l'1,qwGY8y"`/m -̭ ]=(6t(m>ʬ(˓QL8% ?i0{/_!A1w֟J?|lccQ^a&f4 a/%:YޛB;T~jD} Z @2Tq ,FC- ?֚QFȦ ~ !{T>`LѬfْX_@.eĖбrFǴð4vF"HEiٖ'蝕)IxpzI>]~!7,7]) 7^9gW[ÒFЀmi:LR|׭hGN} x6˒\Dⲱ|㯘8Ze O_[ښv8jw`v%j@BplÌnG .xJ˜cA _ L:V+&t.khߏi?P"0G܌0;QVn݄x %[.ufl۶m۶m۶m˶e9{&9s'**vf/re\yܨ ׋RbZ9\W!'dA]Xc+8ǂr,0K 7~N/ ]['[1vKvnlanjJ-1hh(.{H]5Q6^nM~[>uXykymͅ 9ת% X[sCVC9D Lm_)4-C7{^&{foH/pgVd~c~alN1[rcCz9 mǾ=M= BEF5]ShT_HK6gIL`LJ(e(-o.<ϕBV:L\E^.JA7_\nb,[g)גXb]-uit6%ߵF-}-gP7c#<;@ylq+̓C=ph0#y=Ib_ LGB92EJڞf;w;}Bڛ7$%_|տ"z2;6jX8ᗢj':gqw(Ish%!ǀ*X;mS%AAwg(نRP!3*~t$E s$~N&"υ;d{{Ҥ^0LP泬#R"Jh!_Ruw+_&3$O69-Ȗv0R.(+$kVYRB@ 6d=*z־Ccs7ֿ1R T\_ {*:Ԁ4۽l+VLYg1X$qxL2kE5pSWhnSĩN9g!qgB -wۍ̱A-YRA/c%`vSrju,~gN1cĶX `_Ip "T)ef<.r/_.܌̘ cM'J2{^@TwyX<Vbqs:22Kro£|2pb̓A*rky; h}_l|o#𼢤2 y2<^,v^ULT<ҧ^NDEzAIWi1dázU=nRyOusьς=dƩg a& r^)`l;})HC+$ËJMكJ(b8Z_]@mi޴e ef’:{aԥKʊԖgJ<ܗN-JRI`jVoQUKSA0O 'wXMSsTDzsel 5DIs+W cś,lsUGfN=4ąTU,sxMSΑE*j]{-=\7# ~wj0pR;Xpkdtv.)dN9Y! uv! R+^;hboo.ins?j0:^9=> A~@~-M 6Lܚ2_f!9`2HCoenQ''W\I0mv , hWc>:ÜJX%adStIw&EtHw[o[$Zѽ:얧س!j*oǥ=huO5j.H>hV5,u]}86ĭ>6O]8o[N,t9i)rW;Hh1~c,ȧABrf#9J$܀w*m^ƶpvt$z @~n0Zlc-Y3U`t~P:,O۴Zshk n i>_CNE6$)u%HP}PY^j%;rFVT^[VFGؕj*ɨU?D X 5^<|JAZOdC+F~n•d~yÄZPk<lN;wgdJZZ)nߢ Dc:u߫% ^Vγ sai4j즵ž!qt:XRQn<fML5HD2^ث fijpT4Cj`܌BC}ِtO^TQɾ"[4#dQvoVaeR銭"㇨:,4b5x0#% WeKׯth^[ ]:}߲]騉U/AcɇҋtsEK`Y$B5|yUz<#{&=$u ,ܜBN7[B-ou1˭|3/ZYzǚk S-g> ?j j1()GPHtU/*u7¡? D T0@B"Z{-ocpZYza;nK7Sd X|T?3 ](v="vL.]?% I5wISBR ˢ򐇕l_H7i %^N2^72 ǔÅ uqec^I_2e)l`6t^%%QUt8N3!v͟!9F7j.\S퐕: %qczS G^jiB@8IvϓgӚeattE.+;Dn4Lu1}norBJ6KpmCy`P,Ys&;ڧߵ{.%i\AM@C#"4=Jv(J'JFRdq{'/qqk=oYLvGP˹VAf6|j֙R"oEj:Mȇ{?XQ9r:<)c1 =d1ބE[;{#nePxj~ {*`SA`R60oK-ubc/^wbR[܎š{fhrآծy\uL+/gYErcO|s0.(d81yiu`w/P"VɁ/L]TIymᢳCʟ&4iC]։:7׷E _$ ptD{vsEoG-gfOq V<ba lf_+ Qf/(eC? ? _3RӲ~OzƗhiXؾX阩迚aץ_:cefaa*?W,̬_.`K倖+<_0~1w1˟g } ?oV,UqƔTVa~_R:> tذG\tW$z 0Bc"`)"?qf6B;Xd  B(8Buovtcƾ~2=ݭo'{gv1Z[>>  =9=yU{N/wo{oo/=n: nQ?)~H>d1B+om?epdJ ͂ꛣMhRk*h'#$I5:aMQEue!GKF@4+ j0n]]l99$T8'0s!Wߴ˵m-Q묎d>(2ƙO&O-"%/*D``Z\6R[y.NLj\\fޚy%Ta‡QLZ3N&*}ʹ^ M^9]`dؾXyZ <ؤx>r!(H(пo7ڂ ^ޑ؈Mtp1uPBH:vEꪦLa^ ͧWYQO\44k? m^uһFoa5qˈ⠡ṳ]L_Xyya$Y< sBzM_X[XOvj#kYe l~wچszcoJi$ݛwvi(MI;W8u+װlv2 |h'?BwG&G빆$]_}ѻ 広`N;M*@l4O(=Ќw_c,fkʄ.\czDBrw^wI(E&W\%qY]knzhK-샖^^z?aA"ݸt:swh#F/=$Z'#0#圓wjl7I 6#QPBA,*~ИΙ1k*|k^N@.ǪG#9N..8{@~,$kHW{+ɾZ„g{;'%9a*suFl W5K{Lb Pn <%@Ȧ.'ZBn\g%]խ99ӼK[=u4Z'5K)Qd}}?io*P8,B(:*3 2EӺ}Q uh=휽hZ_u9 "@?3*U6ʒ0a1-F=R:-!?l7/"k1k0v$ ʃ%ty7\72q%3I &tM8C+?e 3o#_k?/y遻Д ״ jmOew^[X:`n2^%8u5(ː-j@}|_wp7¸ e‰SLƵe% #5)Ñ'&L[[ ? 7C52ҡs,QGZ$j~;[Ϯ_+G.3V'm9Sp8Gv@^F#'pgwCFKA~cg,Taڮl=;aܱB5a"QJ%=2QмHKl%z> NE{GBP?(Ni@HƩɁn_em<5ƂeDr$H6ih'#:ty߱MZH[%[ojg(Hַ8H% VڂCڇAB.y_i2$ h></o0$?n8}k\ϓA8e"u͚#eeiR13oD';NN٠@W}(jyf@a0@!Ss@@PW ƱJ@;o6j8+J0;_.0\,*"xBsN<$&.["E8B3mJm)'K/ V{>hV̯ЫLݺ |#1zG 0թ@, }m3;r1(&%WDMX]:EVMaa ]HqYd}j}]m[0"QeчM4ԓ͇3Cǰ~=[M Lٓyko uܵNSbs> 8>MּM+t,LQZPyqCƛŔ]Ӗ\^U2&+V ˧3 $R#3EaYaHad^#U^k8gg]zkg,YvW\2ύْhfjC {i@?KfA꡸$#L`N+r6˗Ml=:T :ъhF'^Ufc% ЇOHrzX5+E͂làݙo@V\jomJUxPV@lb #h2I~c&qeQ:$Wڣm< j~ ٓe>NOʰ>Wƨře4򴵖J :rcՉf#s*ڪlQ@8:1H ?lN7%T uvraxc&d_'jN/4 « x:lKњ$3HBY~H^4&'I) !1f'p͓.nxSu`wBS40r{mgY8y3Ҁћ?9Iqlt0][p#U߅2kS=daz墕Yd_ٵ?7w8K54Ag8~ff%5VE! 28`"} PQ|.^%D:X!h!/;$26M=þZӃQ7׍Iل }N5<;X)J<3QPP~̮[+ڜ'wo6xkA"X8P͘a`QMM00X"8( ESu/?gІc:wkѩ/ %w<Pz磓Z3NT\Z%{@ZU]ܐM;20$mʛu;H+9;#`, !-Dyv  !`Tݩ#YQI5j[rVP=eo=.~)Gʙit%_ae`sO?X`0;M ?WLt e_%#++5˟9=-_P?WYԴlt_KtЯX/_:fac|eOFx5?Z$_6y//^?Gej C^oM+?AЀhTFqw5{Fh!_2!5jЅՈ =Ifm] ǯttK2"l$&;ڰf镑=^ܲM:@ -?B.kz^O3$ Yy<[5'/k>o_k|n&l>G2\p(?w5G\.<w;&tl{\]iLnj"r|P(__4WtFjPC'%9\.{'⚤Ŷ^DM48%͡Ac3R3yY8?no}^%K8J[dc=8:-+5}:*pwxy_S%ö2Z3!nGeCŃDvT$RoqbsocUQ\lS$l%@eԐ~}6ګoO>< t?u+~[s&!-Ms#ff˶Pk9R O^s Zz{0XF*ׄ>:.KiqoT"yd-(LN,SY904EHTΝ~ԴC].i+_eGxul'Vn Af 52#]o]7yηv۸הVB!dM&14ڤNA[sCCQc z k,ΝMtYTdg+Jmņα$ 2&oZ˂.D>xӢYvtG(/SSK&ȷB5xFnjXO0*D|4#F!{$F^9 Ych(W.o6^ Km(̻$H^z#F6JG&t@v }^MAXx͛7}:2siYnfɼ8P7Aضhme;{..;$;; 6yg<K14 {Z(LA_|氰^ĩZP" ^3 v/UpXμR]C"D0} |2'rC3&Bc,L炾6Xhh,uĝX~tt! tEOE|2Lׇ҆$0 腋YZ=`lC/2 rxAtU-OM˫;,цA xp'lC]m=;)l{*w@Q0laڈ){O}*3.Y@~@ h(?l5@Y@g{hdRaB$~i]<حDөo@S6nZԝwVwX_^HrcGE~(p;̡)k¬ սq-,\@ES\CS'*Sb ~Cp27Ļ7hډ!GD5P]p͵k A ܒ#攘< %&D/~Xm@z]v.g4hiڲ\qi$bf")EPq KR=$e> 7\fC]#F-SoS!ܒnXeLduhq̱ȇkV]=c73JyߘRfjy$nt]o?bi!^U ]A0 ҨP=$1̀epoEaz^YL؜$mݡZc3hN*1Lsns5?ؕϛ+q)Ǽ‡~m:FPCFK¿C:1bj;4.|%w1I[~19]ĄBrD 3~@IX 5)%3/crB`ЕKԮ?GSYnj6arxpy_M+%F/9.6279l,N-Yp,bo ‰xuęr[LHƝb3GsQV؍اi__+ׇa?Ax9y(.Dm L2g Ķƶk?0zn)} K:HeMPm1gRr`9$->}4osN"q-peftUEQ|s^7N7/T0'vb[-8$LSw\TeV=) ;0I'~)@!vĴ#7'[Y', 蟆Ǭ;i{ XnH@"+|򰿓ZλKg=pmD-t5Ɵ tN[H #˖*DlVojSirO5ibM\d* aEYC^Yas+RF1Z9'΋ XN4;PQҼ܅3Jr__2ޛ3[6j΋(Ǣ TQyy$V g{B.tShG8=t]>MIPDz.;e'&s~;7(f檓Wce\;}񼋤*F)tj9|aWjz3q`ڑ43 4(]G 2eғ=3ӆF*qϟĕEXB.hيsT`1vUg1XBeMKo5>NI=8ZOAׅEiu@w :>8@ tD+ f1*`M#6pqZ2Xjg};7 %= rCX Qҏ/ ~{ "Я`wpfA* !\cCbj'<46T+Id[|ﵩHB E]j0ӶΩ4w ;~v.fʐjȰM'F'HpA7F+M ̓:횂gvdʝ&yA@ W@! ĦBnWn!:d,`S R7<9oc.%ʢ\b%`v6)_PQه " (%J\#rK}x\LL7 {:4MXA)Hr/wJQ o Ԩ9J7.zRP^=~fm$9jrM2Jѩ$]J\:<c\Z$P&Fcb/gǬpyk6<\Mgi{(K 0~B=\}4࠯p[:[Y`sFS.,-91<ڛA9v/777n9"̚oygp<Oop&)]n(ʱ>yЃm~DPExdSYHؕU/ Hemrx&PâDfÄ0y?dT&ßʤˇvUݒZܴv%eˁ``@vV* R'RI%"h3J,Jja79L4E>OqP4jpL1^o0X7n)WH"b)'#͡NHca<WI6ohXʳ$K@lph"KL&ҾTE 3Lve@X]q { ]áXO=g{Ǘ:phw3P֧S'bo[(6 nJu}>rJb'/&r,~=;+2*[T]bxM8."x:лxu0X%VJ+CԘ ֒BP9h"pI8A]^}< tuΗ!0t!~2Sʤj>l-`hV *ò .Nd_pW3  hY\0- ̷&z2m{4DG=xXJNRwyuL~%D }cf1,is8'Pn śxSAȃFOMNh ɹR}8؞CGrDyPIfx g?&#௖6=܇Iҽ3HCRv&gdoZUFAHnv8bX. ٲd}Fca'=jq8H`@ 6P͘*g%}:DFM7W/kÇ4GDÕ܋z0 @C *u9ִt[S[-nwzvgGT1A><ޯxAKX=B%]`|53Pľo*o<,A9͕e=Geڋnh>71`]j% x#ol 7"H.tW\1&ݨ%!F64JUJ/Ft@1֋J<72XC_yY TL:-CbW2jvBA{Vlڷ"BؽH UX5gѥAڑu+-spCu+SpУvPM >>?^r~-#mj+×d=몪qBq)QɲӀBBdfq|}*9BV8P!֮4ꂂ_>jSx^j|en| H_Bja((73_L@Di oH\oF8ēHFS*aL*t#9Tj MWOi7tڻ(N/ `%,KeUJ*ˆ cl`X5scH2)5,.BX.T)8@|,1>Qv UZjj;uWO+VO<}!UeKkU񺾕K Z?頟U1Ro _T/>fz/MIu ަEcy<'*:>+ڽ(b^@ PQ{ qpgD}"a7`\ݯe΂Ѯee̜q" M{o8Yܺt!{ BjCY|7f":Xz۽jLѡ[g fщ`HVH$NF5ܘ"Zw(GcqKIV!OiY2Ámg}G5e_[U]m$8,__{&q;d!=f'T$զ.[>_tRh@Ml=jbc5o&6DMl]c>?Fǖ\ƿR_ƿfVFV:< 20t69c 521udtl,l=JW|',_Iꯃ14266s4ѳ6qrqk: 0>2u $?>O㵙O"-':NmlO\hx}]n< A?շJPGIYGLT΄iDzyNɨKx9y\X$iuunJ8Nӷnuv??Twv=N.ʧ;^N// XԊL@NP'^4Ǩxysb{iG2QG𴗛Jjb0RMyW!qaz!9-Ƒ+D6xrL?YՒV&΃ "X@}qҫS;$8鲂y݆ c w,Ӓ%rn5 8"zK+UyZm3̻:M=WVh%]|?m'OrJX[QXJ "d[U3:n^T",R=j _/  ^SxXl}+r[l .>MHS*\#`5+k0{P0:^K5V'%kq7*]u:Jɚ /%Oo1`gt:s7g3X-}/z3\鱋NA"ja.M?cjЉIj)i@K:{z鼠t^ n8dw#-FvQ,}Jl]nQEvQVLs4(֣3,='UMفxSbnn.s%6}1; ;n7ֵ.$jg]ͪ.,èDV,o?/<'E:$DŽfF xg]!O3k+6!xGa =쮭®e&^2$܈ z6b̅$/3_Hh ZD̠-1n&9p[nI,5bĪ L|&wU /߲](Ih!N/]}yaBHb@Su#rte_k9΁dzǦ{װm.7bF,s61КKLVdՆ|yZ?6}.xt'  XM¤̷l~pČҿhrSA-XG'*zi7_O8OmuiGY!K`&*= X!_a~L58"qyҡY{$y*l?4k.s F͞9:_=LJᅐa fIm֤EDxaNBG ҃Yq8sAX̬L feHײ<RxiTѣpP^HIa IƵs= .7G s !KBT5*!ݮ 1(gы| N#v/$M7G\k /U&|k4rĵEn4hI <:HM1b B,9~ k[+L~ϸ%R"}ct߲.kGnYptK S,ZO+u-w gd![cNѸ#YA[bLrtM9owD%/z8jx0e}td0XX1(4Bf+oom<#t@<֠=ѼF~YQ*e🅚S%9p?NJ EޠlT-vo*UA? NNXYW Wnw5SlBs&CII0zlgˢˆ骒Kf+>&GDӰmjX>frnP$7ئ- 2t=86ie6T ][ЋbKڙB~j`rZՖ# ÚjV_l",tG"Soby/ \)NiQZi\\%v=Zb Re/~)Q~~HȟaM-om<#I~L.3 %} @O>ACvOo  VXSjkէ\+Qԏ;+,޳ \ ^a8Wʎ}LeTt@/a˗1JK.',C=m0&Ϧ~{yc]yHɵE뺇PsSGS,-}R΍zrQo`?Uq''p&o6fZ?*.Zh'* m1: L5[ Zt,01F6jz/KZҞe/ךXiŒ/Lv8^m_f/XCOO{zWv˘֔5H%(:\U^6jWK`N+3iIY8.DLMbfS\$q]nsQtBޘ2ԡ⳱EHy֪=s{rmJX02˳[=oy22r?yϿz.ӓ;y_󸭳4G"6-ʄX4^rAERc_YGaۖLfYyPQ73ltDu6̭{] fBk5Ihi֟ڶ4ZUf͋4EΆw%~!2k 6}l"{ȯIԶãfKQcF qC꟯IDH"J7}tQ(\V"eH΃Kټed5GiTG9Kms>%tM2mEguSJK] a(%b"VE&n:9ױsyFCY32V4z#0$UɮBSw}Xoi5kˎWXN ُ~Z@!lC, /)зeeš[ͷ6 8u?CsYvvFMV-tMԐ5+Iz)-jyp,'~tC*fB$A6걉ITe 5(ٙO"g_]# hKQH1h.g8^-l6+T6-ZbOT4@rF@Ȇs ;}+*}y-}|Ju2]5'mvѢkHݣE'ѹ9t]STJ#mWشsCA6?ӗz *#jvh (%DJL}'ڄA:«M83 UD+LNqoP|A,I[c2 P,>~>haOO iF2'.JgQR(vF*>*i,EJ u_F9{;Q,]ؼ ,8 5fկ\Ĕ*,PY|}.g$B`+q22pA;)PbO {3R=)E^dMP!Q&Df@3;1^L(iu9tkaP2A#?ؚȔuAK׃]}9YLA37 VR$ D)@$;c= |:ޖYW|T aoK QXy[#@snl Obd.rIc~!oDuag?2jĉ2dyIM6~;ݺʰ3e7uag6ץ;1dQRQ甅$@28} WF'h^JfZv?ya2Ŋ}Z{ ?sdMԔ߭ucef0Hqƺ$6" fs:gNrtwP  au() g.XR멒ѡ(("[z;-+:-LW5'cENUo|O$2LqѤ#m,cUc~~\ڬT5QSڳmj&uh4 [\ bCPjZ1]uo?>lypǺ٧ׅV؅:J{ݦۿۛjZj;ʒnd`~kE+Pk[Z.8MR@w%'o_wGyxCT7)dAx! ACAW(p 6"*R-ӭ bjI+<_NpD>6[Lf[j-=glUJaROKEʃ,ɳ)tbCm+ȥ ˔e-Hsl~jNKcbKC G^C]QzF}OR:zybC0C`L.q Z7klanƮpN` *OWL$ٸ{km% %ЫAԅI/6VLsLh+9u 7e, $r:*]ɃeK>jڃyaWk@Z"y".s5Gvp3Qcd#x2vuz[N z'$P{T|^M#Bd 1*]y"ҀEUs{"=0HtM>*ծ'/ҧ '!x7kD 뷅-#0.$7()Wh$)-[TDቖksǸugfEg➼`ńu5sEXQp\xjδ ǦKIF3;Ȝ}=E%B`k@kحүx(8 vDshz'2WEJ;ub6|OxysVy4^D Ⱥv$2nd|qW)6DnLDډ38PyX湒u?g]l[' jڐ*]ZY3l-8z+1Hct;|dƨ45:ipRU|̵ ˋCV_H$9$zAFd,hm$8 :>[ϑ07i/"56a"(Ym)%7炝 +=So •hq.X& nzw|H_J_&aX8c]^EQȇ%(n\Zf{"s3ׯ]T񎿯-jܢY!KO\ꖅev}n|6p<|n^Db i`"ɾǗb`gsO&cUٺ@j0XemHz$7Ŀc۾$ .ijC Q`Q/GTC6vZc &o\Y%of1nG2<6'k) 36UΝ4]ڟLTe]}wdHPoN ;92O=>LoAu!tЈzN ]M s`d_^8P_q/'ᅙOz??%c0BGz:6~/Ӓ҈uY#c`eچC-fOEΧ\0#$wQ]P .vo/ysV}V 21@!bV8b|V?xyDJ6m9te[bT FvJFrzVU(Cnz 9r4AHyJRUMR\x䉫ZgEsJʺt%z +Ksfxl"zB!쑳 )J(ں3嚃K3mݓӰ$ܼ,8;)?L;EkV,"_3Tk&aD졮z;d' 7sj-@M.j[÷,*.>84 h0j3Ix5bAt|P{?~ʂޞ-].V>\}ܺp}<>ZƓ *^a*C%#t>Lujg77HwOybV Ȼҁ$ZIK]ȿ .4!;EeF QESM!isKj9(y_& ?*/btH +rA ps) 32\cf2P=bzNj5ivƿL4D,NZ_m|s-/Z,)c UHۨ#ifv qs{=K17pBݧ^4nFȻN@ovS(HQ Wٍ,Z.]6M+Ȗ Ū,؝T/k |n'cczc&>jI(B<[QHP j0l`?E:3BQ}yRͯѾMX͒뫏~5o ^Ik {:O`? 1, {Rh#|%$)\WXH'Hmv-(snmV;HXhSp&r`OVfr;Poʙf7LUR@Rum~vHe̦Pa۝Jo#ȘgEY8ZS sBQ2q9 K>io$/geX/!/4:(V7cN6>>0 ܣb}meܮt$?ᄆ1k?t\"8{&uۊ5bGDg1+K{&zZjFfzLtUK3M?_:cafR_'NvLb>sHfO\)^;.όRjGDn0V)e+b #DN`s{ւ#()8ݵ`6kgbi4h}s ܺY.iBtGwFkt9"ٻn:ܒ#Uէ r2֮VˌeE/o;oo'woݰ=Z'ַG\ OcvnL1Q\)a6ףcr&O2 tC "-"2+fNOh ~$*PR/?fߝ< lFp7 /3+,7v2l4*]%xYh'Xҗ2 6(.~^p5{`S"t5rIauZ`XX ng;>reZZspoEp =fL `5HU"Onf]C:zyGfoBQs}5O*LM]NzB/]TUOmťW^E5kCk yGos-v -dl$GX膜KOls LIl3e["mʰ@Y`7ĩ{3(׍r͟?\%70G6Qi<@dhh>:ݕS^ݖ7cznY9WɍTNi_'fhR40hf띞E I&{"7E SM@R?1zН} 8G6#gD^v8}I&v U+E»^.X\5IGT̩=Ґ#kl}? z(?_ n[0~$F kfk kˑbq7k%]>4/&.s#&7ďrq|3/5\So*:~t.yUzYN2#6U)0Ê-NW.!^pQ& Zv%11v}s[A|e4Z\ ()}aTr1<{_r8Y>J~’ʍT hMie?Kzh0qfE5`xiȶ!Ɇ1k_qC w-"JHYz=B G֦:-Ni5s `]rF Jcy4=Hr)11'h_+09o$gd'W102qdcVƃ4#;^WC$5 't$R?Q$PnaHzFJvk^\{vۋT)y&)e6"(yԐe,adY9Q,##'<m$>~+%^B (!(S .2:0\Q_*PT }sR($ Jkf%fRjևozizIFlC1 JFOհG$v{6¹4#߉ghMڍ1Đ( 8)H'}!J4$ޘRذE=)Y~qa?v lY45 J8"g̓3x<^'%[cJia 5.V1p7RaB`>K=l ob*߶N%ʕRLqXhNVP%ؙ?VH)KYfan-ɍΌ챖z#tOp%Y s|d2 ՠ[:pÁd?Z7%z;g~vg~G]Pe.0Q1}Qe5Lr1:kw  Kߏ^ ֥Gº0:1 _-e랆zˆg*pJanz2TFIIz8r=%&Wxj 59vO*?$)-Pm~MBlȐO=EV.T+FYmVv q qQqayyORqx!aq>t~/|4Thb8חJJK 滧_UE؈gr_-oˆ}3۬x):\&->0X"͉z{1rOlXd)}>>Pq-*(89Eºg%.y(1~晹% TAYk y[EΊu[CUqI pԇJ Q N߭C|xKk`s?kM21`֝z26LX: ide[sunjzII^є{&M6[}w҇)Qi=~Z{9yW05 %WI(x4|s@艩QpVTة7sk慨Jdkg3A PVn CYO<#,,4y6 @IRs1Jӥ`Q6Aw-U|XS|XYjMCuZȠg/|X#1 2c#YޗɠU[gu[,h'WLl63Q*=m(RAwpaw@PZ2̷ j ?ha:c]}ۡ3%g1e߅!υF~pIi)[f4=\Tw4)%W-ZLd%J4l@;o.^gt40,hd~ .ݯ>*5(R pޞ0I;Xl rLBx}L#92Aٰm NLl>ڣKfV\ NeC: xjFv_3zp s퍵 r!H#t!䳢tziM3IO0fxRYŀ "w{DΖ iB`aCFă+F:`VZ L8)3I6gv rK! B# l~{EІ{LvbmL&ˁ_*a`,ޯHЧ_dȩ1[~>b )g&+` d z߭֊ "#ܬu{W4{6=:5Nn[4nbUK&x|-鄡-T.Ñx]B.HKy/BpV2.j(Xk0>@\C1axI>LI<'i&%yìݱ`Zюk8sR0ekr)~Xuո#%u$C+߯_&⽧ևح|` rD:>#,OI ]P" Hhάjhh:WĖdPLS w'/$qi<55M?4  ;s]%õǗmƽ{X4q-16dz$^Ey,/fN $>Y0Rkk*?Dg4.5k$fdS$ >@aA~0opfa cT iY^"w?|bUmi(A˟OA4֮:͢e=G?GFĽ)!|hƌJv[٪i׺|B%Qgfk1GǩJ+$(Sb"#pbK jK^*5C>4tĎrtQ}ayQ#l1Ry_kr%84"}{Z3"Or]>- vwt38P8Y]HwHs`'Hc}:\sc&8M& ߣ1^v;l- 7ʾfJ)ITfsG}n[.ŧlڠA3'~Nnzy-[5eӆ l,ӚiDėCفjkC}\GgLzXgZ`rMLn2p)ljyE ;ql:MMSA:BQa7u{uIY٨YPa=?n櫭[|逞Ktƣc`GwB;/pp$~뵇wPgݩul˪E<(PU^_{&c1r*oH E%A χ2ɴi$Neoy{bs B!*cVh'4-Ginu'W/7d06[:Z^QN3GhGG*6S% q@K#aRxr^6;NFsl)ZޜdYdH2!HbDV3ed)2z9OVͨSc3XSF֞I g]Ɇ$W+ֳI8st(̋փ"J;4H|ZEФ2%(S|ME;}o 5Nb^_XRGfB ɿH\?1S$IOnN5 |4}}7œT\!90{&EPPI:!uF՛ު^ rH ow]3Ka„";Qb*E@&2, zNH / %lQNjI _N cʼnYQڶ1"| !͊*9\b M~ `f`2LjYv,ɛR.FLLSF5RMe=_=qEeD3rw%u`Gx?1ʶӶm۶m۶m;W+mmZiۙwNU_N#[s3Fģ޻ɹ=c" WCo(sBw*ӋkOQU1}y҄&ת8c *|- cAFV0[ S+n8`CHXZr:A#UM{-5ȿƛtbILW}4$_ [{2ƃTEPRؔDv\(b{J;P/Vu,Q yD1VmֶCo)dBU>d _yN&U4RD\ץ֤&"~d.@]-x3a\i/g[5YV $rs{y!4sG10 ;v[3-oeaaU%{l(-W/goNe'yn*==^mB=w;\O?-E}z%H/ߗ"i"<‘D(m=1V'K]/80a%̧ zB0xb03{QIR؇ag"AS$~q+6=4^p]-f(/h`+V'8QqgGpqljX6ƵeR2] b2ZTi\yY^:3Ch?%DZ%!UA\B$KSEk9|n,_ddqyn 鼤#ulH@BkPWrJE)P4בbͽΛxo&-ל-#$T5'vx Lb=,gWkaPmck왺}U@3ҩXh+8[$goGy\fhߑk>ereۿ Yx%;J@%^{8Eh;P𮑎- \a,A獃9&( 2Ydw#U_ꭜZӤfZ\758V6Ni~npwm;KW2JЌI4εʽ~e1CTD*páQ o%85gVCF+CpyZXX^U. *$6nQ"fd?֤6ۼSc-mĠ yoޅ ^Z[O[5]/o6Ќ+r.OY۞;ž$.ymِuYx~j.q I! M\ui47Tj>Uvno"grXАk9=z+Nϵiecvʁ-zsW+>D*rV9CWMgop;/&g(o we,:x5BqhW );%k:JNlLJ v4pMByݵRrrK%Y_̷`O^/ %@ yev!@RԾ"WKpX ,aA,X0Eo''`. @&7G&4D;2 \?g``K׿ 2m% $gO}|B$W1*vLɲ9,[6FuWO=:XS&LBo|E/ (KCn*~<)Wf)}udlBkljl 9\qd5A{ӧJBAK4φF6:Mj2lfW_/@3YdZ?m&E/7eYĻUH3fplDC3Ϥx-1TY^aW:Kp"pg*uPf\Kw?Q4*B@0(e9_4 > 3@CFK` 1#=[p27O#ڀsypvhgf$&''( & 0RK\oSiY"|w~"B9 W}tP]*iSm04E]՘f%JujsdMxYـ&euC<_6^)JAւ[;MCoHX//xxo}&b+%/ uw(}6ag?X}x+EIL_95?r^@Oq92Jp2OO 6֖ĂzH1qJ@[]\;-M9Y %l~+ȩײB\a*A+DoVh;yk6a0{K|Qyu{qzrnkj<% 9CCbtKbW)^˼l%~Go[' S<ֿܲxG,;cӏ f/ Vغƶ5v%QU7*< [KwE#o-4ȣs[I/BMҬOZ_}#4+\UTJt?1|ȑ1fkX]F%=ԽSari(ֽ89Z .iC}yU4C<#Kёj_a:bX*h<$]žL=s&Y.]ЗMA_S & +rw&O> ,.+LheG5ROҙc)6]at^FH#$zF7}ed\L뽅XpqQxUgf,GHdЄnHb.$Z>"jH{qC%^@;՞ڰ(4 ^^({|O.@Wr-%'y ՔWFjZ8>/AQt2rjy.XF9b(N&_V\mx;w|ZlN k10fhA,X J&s67+gɭT9vL2Fb)_r^xZoe {91Jyg<_܆ Yw<3hU#Na_b=+٪_xьsq!&*x٨1= M=3:%-`+>DsUQ<3E0Y wë!~pOhm1wXOMiZȟKx̶pr@dJ2gIZ 6X\QhLӡB7Yirg./XBl PvϸcqkYbn&G(VͤQ|;A@6{ RX)][ݲfihYxZ@TtnvFb 9ЗkddwͦSL=ϾH @+0sP1@O?o|hM5kVAPtK<_|}tRC Qae3&$^ba-V&*[|ʢc.}LW]*a` GlFO]{iڗ ߖ  [8\eܽŬ ^ݘCXv/OH@_nނab2YEʈ\I|5# ~H N*P-fdp=kj'N>hqK(79,R5sK67 Ԭ1i!9t{1*`u%I!j _-FVL =EMҟ6GFHe9!Pz φ*4~:SQah@U0aLHdjXJW@ Η#%3<8#nWR;6F)n@B_%m-jh >@8 v@~صF2mk7be72iD'W7渓bX& ٖgFl_Uuh5;\\텔I%߻Il(v>vQK7!9ܟ<Ap`A?ǥ_E@.\濩lq<#'''Ҥl *L,X KߙrrmiokGxsrOjM·^@9vשLx"PђLOf`ƴ$$qJm 5=$|gn$SWV/%+u~}$Ky%S$~lk`J|Ų˼//gqaƅ^Al/ kֶ熇CU&AWuNU~ D ^aqS 0[v:vR3y y \ eR M#&p_P4 2ªZ٦$UeTDguZ&r\(Ǿ? )9‚T^SI1! ]ǃX:4V%PhGAafާ{T,z\RA}h*hƃu# mX0%4dD4G.F6x5O e2E: SXUc8$(P`wXmj"=ukrXn|\{ y[T9LšJQ $UZ i6eS.R#t߶iSuToFL ԸӬ# 9;HkGE$y}\q黝 1b:u+0ZUF|?U$kUWHkO*XX/&褾QW:T z>>6t ΔaV_rW3ERW's±2[q;Hwѵ{^aսd4)Y̋CUUg|9 MP47:Un r g Qi_&-0v^(oa :fZl`BӢ,"ak Vxt|ǻD36Bg+S+]Gzen0e.Z,Nܣ,a[!o*!9bvw֗,TqFbOSn:2/X:]V |"֙e0闫#_=U J&b(Z47SK/-̫M[#ق֞7^3ͳ/o8#g8׊0g?}mw>P=|n+FnG!㥍R>f -06]Xk'Э6bTڝӈq-|baML`712Y4HCˠ+OC !6,b/ 2f+zlh h9nDxe?8¸Zdy:&Ƽ{en=L&uVe+BWUPѸ]vtR?'yB&eKiШ !Q'#g>8` ܐ$lGđpZb\e"~QsJ (;_Z1Ko/z83Be_?4W6W_hwV}\-6>`&V@YTP<6U[y 1cZlkN}n|h`< G7h%64h] P<"7uBc8RFC^w&(N{͈)J:A]mU rD$ {sI",+&!吲{.>[+v3HjEO-u2YXG|\EFnudm]iߐ|ș8cԄ" z貴[cL 0hA|4;)RfٞX )&Իx &/<Ю!M 0LE83 ,ljI vs(C~~@3=H\+L+7)GB1bDkGo3v{`7E0*Ԩ0q|s!JlO2N2?TY_' Xj9#uJSQ rPBiTbcj[? ѢLi܍j˫^a.1}AE>▖#twY4K> S`O1=cՒ*-B7`k?A3;sk FHhc̅ 2f:7X5e13a4umBє!m-cFzUfv7$,rFghv4#xgBȑ0%~ ,pռ{dI̽.71 \eIJnK: JAN iNvUeDs%g"3=[m}X NjuI&FiX6ʹ:[_=K_j$~ PԔ>vÔ؛~}Ս@T !άYGlSlQ^gږ Su <^h5v &.ߛ5%K$+@mf0a('BP+0e2go'^j]!%)f=~U!ܹÁk4- {C0qZI=1­|7X,XU; W Mx% {tl5F;TA B0~dvaӳc]mCvaLۥ].yN%A̅c3'uDwBVЛ$7!+zޤ4jae&`dfdߵ)A}gǻ7ؐZƝcx ^g>mmn)~$B(uVT1 At@CAN<ԔI7yGz2!+[_WGؔ-qژgb(|ʎOx/:DV}gC5oco7l^hkj$ ޮ&M_&#=qrG_oiUgOO㍻`_ϡƌܼ_˳kV05+#X<#f<}̄P 4GdADdj4oǜ *i΃Dz27fYB"_mwe깯fa#v<}b*ST@@2kJŠ?iLj廖|Jo=ӎ?s"h=pB/y}r]ر[~,Ju6FP޳֥wvcf&;|ְitO_f'MVVD5<_l +Ch5a N/sn`,O]5n$7FhgAN9+~¢ Ȫ"xx#w6\y7VRd_z 84q+Y\תk/a ajYD"gE|(UkZ9^Sc!tS \@zQ]ޗ,!XPŕ,iC+ G}B/K{B95V|:ؼ=Ic [oR F{9^V}i1,ئ2?M~B _=gY]r S?/#.z) wU?Ba 6PħTrMC#RwݡTu@w(I.3`0*fnݝ NQT}4>hT+eҬ.?)u Osc|Hg`eE[,M ^|=\3O0y>#;,((N#t  -`fg6/h]jvPӗFdxNNv]l{r@yņ -QAw3,k-af_B®d'-_oJ2oTuC- 4gXXB+?ÿZLC @@ϒP6sR 14a)n 4wJWnsH0zKO: H60$T!כ(q`+ jm)! z:{V~Scy*%WDعR o eq=CfBSh(d)jP #9Yܼttgj2QlT xFʖ' !p Cud)ru}LGǪ IܵGmM{*5oy}j2̈́1# /CTsͮƐD`2(M`BI(l u]໐~3P ʧ:s |M @ P"C'9[R{wӰ+qb2&A/ +MDC-_p@IQ 8}. Tk6e^W'cxq5w/9:RysO.v&%%t7R= QEcΎ`/zKu*ђUr:&9:D ^<w+uQjISkţ[J6}up?hħ I_z9}v'w"C߅,5 5gm|>:H_OwoowOFJ-m~ʌY&'w[wnn#_:ѫsd,Zg U)j-Ca|JBɕiQ$LerB@B`Z )PYl } q| ;Xxg[]!Glq:̤ц;}& "Ҕ [M!MLIVT}{ Bo~ӻY{.m{< ry=Hb9JW:Pdi:r1A$5,6~*aAYQ/ĩ06ʾF Nd$3 4`g`=p } og!{1c.ZN;NyU]^f%ؙL_m^dytvNJyKZ~\\ pYh%~ AH۷8+oKP1f^QPx^gnʛ|@3Ami1(vLn>2-Z}m)^9M@c;FsbA1B `1 [# ʚEsti$f*1lMG|n=~%_}-_ֱm!B:{$a(Itvv֥ÛE7lW;+$UQ.[5e:OuŹNgGf $mZd]59p2Ӌ(I6| Bq&(%oq$b.6d%ɓlFF:ǦktZ=1U-!L Wx/&8gZ%BXկ1 :,a(KJ%XKVۅ\G mJTNͦut6ӦA:oVo1S1ܳ}6v"oVIYLh9Ӯbc`5ͭBDx<-D$ /JL >f}PzIB Pk?-QwcWyX _. YZFO8p94יH;3jNMHcC.uU6؂a&;h" q~?aͧEڪj4Lvh\qc`jl+w/Q)nԱrb`ŷOϜhѵ ijQP>J͗yO."`eL[c%KR |xV쒿s_, Eƣxl!WW@~N%痢?x OFB.k864 |,d5S ݷ:?-yFW8Tip Kx>rjIIr1ESx3db *J}%xӖ}`V(RODƟHqW SC}  ioc{pI7J~&4x@aj w(yuQC0~Ę QڻOZȅ!pѳ394o{>Jf ӛ-ob=äo<ptʢkDZ5d"M4R+sN^ni&+ܕ^$.9Dиo.-(9- yF1#zoI{bUJJ8WE8?olk$8v|Rz|xd~R??&Gy{qr}|?^|;F pYC[< N,;Ĵ$5={0_-5"H'X#gF?bjn10K>L )[J ( ٛT0dc3@G L|%%YE:b\~A@Q{2b$K:fJ !0*s#6kc\פTxN &"a[B?aG˼Ӿێ@r 'sry@uO I9W&ߟ C':/Ṇ̃IAJ O0/^I k7B~MF0 " ŒUUGp1t8tInIz[hdbEJ9 ##.[6fDW.FBf@P˫7"Ayll~y“GG}$"pQ?}|h&vV.Otf#Ї>i-u_:. DžyhSV2 70LŭĘZخyY0q2$bIV8ήTa2˹.IiӲnZ\<*L$!nI5GŘ@ 1 ߹N$S>rY;0Y}>rxpHhe"M@ .dr Y&%|!@V=YK>&  wr&)ݮo7GpŜDA1g;ɡW絃P瘺(,&k"pGZA&w2s+6c{4nj [dnOibޭA',4q w8  3%EtK\ a"$Su09dsQ8+WOjdwWes6XZ&*_dUpZzlN7db*8Xqijr{Ѷ^õ\<w7@!8SIr|hŔ 1@Tv?gT;"é}w>-AUE|xT#-N~g> uV^DLtuxynMWKi g#[bQz8uL+ 7(QA꧉ian4p:YbRp*=!S: B`Yy^jd,E} ^`NY$xRϬb4MtU˫sDkyL6v} ]1kUV:v:w} ]'uȔk20R!P[-Kb`yz@mB(#Fׄ؟D_Jb6v;N9!*'T=eXXF'@-im6W +q\lKyTÉu~ Ϯ|)%ȹ -tl"ۿ%.q|9bv/ wm΍dI8I9fLoqP?iz}VEgJOr!1 Hpg֚2T[k%(MEћ^WKS1[XKVo܆x?-fLPɊ h@f/ip* V8{wkt)_& qi(XD94:9dn40!l[lt|V.jZ ~y5%iKv)ʡmHog5+J#DiBG"&ܾQݔRBNkd),,BGK"l{gΎAgc !F46a4Y+VH TUQ.NɟE]L[wi2ܵaj3wx6\~6ap,Y)V$10^tjEpxFv푙 'cݸQBturr a\#hZOa^*}Xv_C2<罨ib$!6&%~ Y3HroԽsmȤL.)ԶmO V4sб00001K!N/B/hbioGL$? WUolVU)cS]cg ^fiI;!uYHJZ,eˍ=X LF:]y @IU3Hjr+Y|Q:skäW?ID[Q{5l_44w֫f0^9't޾itq#^sE33-gKw{ }'Gw69"mgn*x~p:rMƔi*9` v`[E?XȊ@`pcsy,[Pp-i$I=WM2ÞϑZxW,Nf[(ڙU5eG;_oalǛrGs ѥD^?s%mrd5jEDi~9к@-ԝ5.vJ fdOe½;"q*9Rꞿn6>OfV‚XA; Oj_B/z6hު̰ÝBxn .F|W(8ko+Y٭2 ~ :$J8xitR ʂg+CLD<~A?'-`v F@ e> PU xp >~Mbz+*SPӔ8 􄡽1vnlC . ~0dODZxk,0EC%o:~EW_1sJK)A[Tia}Ûa +S܄M B٨ ?z(΁s=+U4ƚBb oḒL SYd@'ָD"T!a%CcmR~e844zLHl(YXxgFZrZ@1#NBTycd#,Dr\qD)/0v jmyt=Ȳ jp p^(?~zLF$<_5TiyA4'aǼY5"%P\'~:^ D/'8qZю{* :Sh^oL-Ŕ3vh㲎!˷f~Bk/1d~]l>]ZL%t_S%S* A"EЪtH%T֚ɰjoEh!vH C!1/>X0ƪrr"ϲ'/4iӽ1\2BO\T+ )թZ? T:X3inG^h$v.3<7b -w}'ߧq78w^isoLPR^6QbHLz ꪋ"}p:o8 PjG%(ZoB|* 6[ÍwR9;qa0" Y6~H[UOw5(07 Nh@X/2`JM#LDhsol6‘B#^!G;'th,R>}I`+&3JUݐV ^ĭ+wdO^V;J8.o+8n fx3d=qg\\M.n6kh ? M9v/4SΉx IR2 62LLægcw%W]yx\r?X=žmT ѽ0n8F"@~JšG`axV8cm?n5@%/kM< 6U-*/EREqQ.O|3[^`NsE֒| "^RΘz2N+6B|i}rL^Mc/r/i\ah~XYHÛO:Nӯ*j [\ndyfTjΏf>ǡYib iҏz_W49<y|]84ˀQ/Ynz [.%聞ߢҁPyU>.*(I}W:,Pş|U~geKJwnµLbSiQnRS7U3p8PA897M˂7Xɏ?ız=ǿ`[5o{K?gbcef]4'3ÿr# `a+(,,t,lR 'lKyvGȞ|FeuǂU` E4rUyG4(:#~=31q2K4E+>Cf3{Q١Z~^o]2fD5^_oO+k ̢Cu>7z!ETR@74&r,Kni1cF` QgD @EġafNS |HR^XnhGBkA"-Bwf#Ћ //ed|BA6+E4L?M͒cZJrSA؅Jw# Ő?h F }k`O2Yj8Qfr612 qb+?_LۦQw!gȍW}\vͦI.x)LN"GoU:+S)DHoXTRbo5Frf䴔xW=JTK44WӍr%*b *H0)HqDPl@A2l\k~ ]9=\?o:J㰠|2TeOihGt2XDdLg0Er%M W5.7==UZ<10gLxɰ0hB!U>/R&2aT7Д/ͅqCmYZ/:@9[%$+ AW*6*<wĝHSUlq`i[l.s'a7PL%C@ ((݊B>xĬ-Э.4Z$g}<<*lɬ͋7^f!chku?2ڊf(p\ּBݲD^7-!c}ܬ᧌K#{vK]o,*3gx&K2c@=qhC͕D~ d3))3Z%䘪|A=kqvj0xbƒԷ ǿ$Lx r )'3Y):yYE2H}(({*"-? Ǡn鼱i{Zz%ud),q9`/+<:Y #1P tuTHH [#d,l}uAZ&ٴ@hs ,Q1ϿQFAmb 8$Ɏ_*1M ߹bccen#iD{۲'}x_*J `aZ9<=8rB~$nFҹ]\-C˗CͳkW}횵 l*2hmWHBOSaZK@U@B򐊅_ SvroE >D4"lYUМX Q\k X1Id<w19\&7cz܄NprC)R`msi IdnJ&H:BT ҝcY?N<58\ )]ܴqP_?= vAND+vU d0XG V. zȈr%C~P˳ !աY[ivCs30]!*3Wt&҅Hثg k4U 7֦.1_LƉm. n]7a A9Cڂ*Za( P^٬h<ۊdn*b:~Z}աŁ=a&u5]ٵ%F0) XCa5_7X< څXUlZLPߡ; 23v+m!&]BL:af|,|^op?=䴍MITmٷFRO tuףH%蹎KD f0jgǃpN{{_C PP'ȩSr(R%J5<˶h >]eؖhH*+Jstj$h#h4 7;.2-ߤjYV\הY1FtB41/f<6pOr02c~CFiε/ AbD̟>{D"ȶ  *5q;O.IQ f54 x/WXD75DjF䆷$fkS/'VLeLQϠ&[x42eDM՗4du,y$U(q 9{ဨ9e]f·aa3λO/,tDUz!I*!]|duoa+.q@<[.ƭ9A `$<rа3A5i4W3; li ٗ<{23#\B}x`\[e.>,2%O4M3?!K˶!L+WS†_d*IÙ(ڸ.NFIXu;h~od>_mpܻОJmL.yQ@]1}F$;_! tSKD~LE g3$0^vp a$޼p߰*3fZ\Ȟ%ɕ4<R #-mrT5҇!*C!=Ub_Qj`Y!Gh=<ܤ;Ftߘq8( 3,҄Qv(7O 6_?S)sK'Z8{&:6F6f6N:&Fvr10s0I@4K3Ͽ!9x8?t,r)ח7lW=ӓ"~Ni\ O" TslX3SC"i;j:4lF$ڴI=3R&)PCrN$X|@tN"F'#Zp|is|F,323ll{JLLY ax#ױ_Ѕ~πmtAWQb2G l^|2ׯ0ѻnZ[>,ys ˵0>t3ԖK\,>sU1/t/kUbFb%uNP7*Vm<#YG1i/ ŗ䟲 v8i "fJ~QoWviwN20tY-_ tȃpf =?1cmڻO*kjS"TS֖OCѱiB,oSdODV~&L~G^z_ɛʍůK̬K-MgT3U>?V{ ]Gܘ̈́U;XX XK.G8bJ ^6:Ibչ;ȣ~5hS LLC ju䳿uC!@dN5N2LH~&7 ɧjTm{rV Q ݛ ."eHkWT06Emr̳;M@HARy )77ed*M`G0g23SЧ]a4 -5e0sՆU?'y><>oT;  ~0)fJ.c UjPػr4Ot>? ~qY oFq:P9#Axe9 /(BH^p Tu{ql4!4)Zw8c5sO3GCz6$-x,s>ܤɼ ^D )Ee%T÷4x #h\D4g.қ-D\Dtn82גHt-9liB_;K&>Ns!LRHB:5%JOM@_< dM/yDnTzg0[\1h9->8_%Q(ejl%n|^3BK YÁyF4|{}X* `kK!Gɯ5s} \'/6W^aPإ뙎 ȣ11r؉$]1yP`W2B@bqxp{>+$V~u^hp^#F/0 *qXp=$C&{ A`@:`Pphq+ԩc69H tNL:Hs dPe K 4mʲ75\CiVl,vU")֩5Gfj 6^h֛ >{ʴ7|ג;cнY5CpcjySKw] 6D\4ԡxʀ/.3w%hD.XDZoTP\W~ix9tqK2YW"q#V6ލs)f` Cf4-?d|X)1{m㎁Q1 E[6TAe4/ #7mpODxDP慥uIyo_ _UV8a 5YrTu!7_*8t|3ęG5yܸ&n5$Ox8x6 $#4oVx̮j.Dtc}HpRF fA_0[`P[ c] *f{y831׃gT,E){1x,-O0g<~ǽxy\:0 X-t6_^qtڼxc}npdοlب?M:z)Y7<ˑ=b-qK,z7h37;"Ȃ >,K`2RX!BlY1Нh?"R˯sЪ!XT[wOEZ5S~}5w`(폂tڍd; w؍1':PMSFpA{R6t {:֏fڬ UF)mJsr+k.gU]L+1:5 ={_P-@MXpDrNsJ7 wL:9 gxGB,9{nkT 6llk4wS页^Qҏ:hXH TVԛ|qX`ieuLZhd?Cf?Qi=4@4m;(T0).Z:i:%:| zc 2q1k]߈WY{'Ҝ8,EtJ**_4hywсX` &-r3pꌃ F DQ+4(G%EH0 ,Iq0(:>JކY !29R'|RJ[*q^dJB Etϥ\Iv@;?jq|'A?gnm+fxEmc@`9<rܩlR<vbbX LsqѺRz_}Tj`ÓjowPB![2˿<3SGnȾ/0 ǒu)L&IQ#~tkH0J7{uRiR?ύ[*u >C?z1b$1y6A0, ??%I^IͿ^T'>T'T$rΜ߀ JoKXX9 X9X8e/X989Ykult,tlMſacgdGƙ::FSۿv&7KN? gadcd 3v mL] L_`d_k5Den[uw9 X`k03sq;t om±m۶p+m۶۶m۶:{[T{%ɓOc&{k(N" 翟GAlLLd Yڃ"*o{KZ X|";D K4Ã_{tnȠ@@fRB`v,,y^zA *fy^ CMz;]o[ޮP8AnhcNx8$wʋG$܄[_ɜobX' 4ۃQa@ !ZU1!0ٍ&ݙ͢ qZ|A&fw%M}UO*1ԑhcHǒY(Yqӯ%__*'E]m}é Z}]+E3 ˉGU[1pYMš2- l_l(|qlw/hX0i!TZtc5/љLar3WblvF.zt O0 /z#pD&63͸mk!kҧ-[[8Z'JzEPy:d]nFi'rJq% 㻝  OJxg2R/EtP/H` 7EVO UkC2cEw#&w2$}J:ӟ)>1h> 08gL6YQ+^ڊI51~Tsh%~X:|QfT$o$k(8 `~FYA ^J&}f):N +!.(p~etAlpaY "ByNz`v0f"kg|Pd4XpëyV p#(TΑܹHʽ.g)jASa90k6ԫbH =`M3f #C6K]q7):ݐ쐷d1O^}cT -OҽA!w<:@8 N<9xAث唅2.]‚Ɍ'?ɩ ]`d_l(~nenT10 Q~t%cќ>t.QIc=[Rb%!= t)b 9\q 'n/_fJHtaBN5k^%<ߥTqYs!O>z& ]A*ɸ-\d_;ג ~ZM/k`9a>v(/Lb+E˙ɭ>yULU0&n1PLTD(5V'opUf-#wCϹIW_FE幰3Ee!d^?K܋c CZx^BO LB;L&1ĤΝa;E<s5B}[5e-3(i6!`.Ef>g<P UZæxe^_S Juywk&4I&pU-g9d>-- n"~6D6BHOC:&w?x]x*Y%! ugCIɂQ}yWz(8Y>鷮vp;֛OɪhWؔBZzFo[$PqDey5μ%nyZC8hHTh)73PлϮϙWβ~0u"s1!c4- i=%&}ly8Ѫh׸6+;XDmplgTu3\UEzՀPB+;tqf`v4 %D57lf%cc=omSj2>.߲pO>vZ ]I493:di[Q5AMbyI_ک$FY%nZw."v7*tFScDӚwʦ27`܅@C`B3VCO$7$8aç\{^S'_Oc?ipބ/n̈́ċ̍PXb9=Sn&BJ4Q%g!@#;K=j@\?z2W a&=P!͓={$jCCv<-B zw@Bvmxq/ҿ_OO?;$*Q81YNTi+[J$cDbϛa E$~Y(@t #``WxtC3WM ys ǙħiU]Ou>Hk;ʪe3Mi^fx8^cGmniݻ$b"Jn{yubwmx:{;:{;x[kt\n {:d 0vJK5T2+HA:vwuq#kh bYƀI}4_*\&F[WL;pm|hQ#hM8&@ EyZ(\3GKV2TNW:f&yG;7$\ќx&yX̄k'{gI HPWtˈԒj^- ٸ9-R6GXs%VJcZ6"&\|?0/2;&nNOIQ˕Y#)S؄(5Fm+wm3*bik*@k.q.93? dҎ^t߶(N/r]:Zi/f y0eOH^~Sf&"i3g-7jj-pc(JSfyA DCSbo-KR P̭:-4E a$ɐs[%=R\A}BoJg 馜CT!_u?/1t۴]w?*E л}4T]! Q4yq>rE(mGw$ eWp*õRoSJ g`?\$kZ$F}`1ؖXXu'9O>v@ A(چB j&!p9ϣGG].!+vk." B o!+@dv:P[.WE~mR_v,F })!Q[89\X7 nQD"Z8#S` ,9ƈ^EFuZ 1".s݆@̦$R8lcr(>:7| ~T6]a"= (Aޔٜyi݌oh#; 'p4KqMA '֐g?g7[)?O ,mM6ِ|uLA 5s6$:8׳2ygH$~~_8ӥJҠ+NțE++L^i Qϟ~_T7dA0[̠ 4{tojц8&v#l^yƿzu /nǿ.}}|_?-w"=z._'oNjy{tIov:`YB/,M"Ea1V>\i|%#p2O£ V?]o\v(uPmtо %=g}z <.uV(4B+ZLe߭d4oݔȾs0{bHMK*ZP 4>or8[W)1-DCΑq=y%|k&q/\鶹ipH/|`j ʱ}'1~;`5}4vR 6]w2K鄒15W@g 3RƤCs#L*Z6^YpLE "VvR(S0$`=̀w(dJ(ڏ@ݝ>_O&x3`}JΒ2>~3䟮_Z^3m=&,! u%˨N +lI+s3\rXP(^c=es&N DՒ;]z@TbXLd# kTE3cb'd,م&qE8S"96L {JK]gFv)*--|>zn4#~64MhhÐuaylB&B+?ezVJv#T'hwFf sl_Gy.=Ln*4s/l4_$旄Źkj呺@3iٗHȌ 4P][ky`a"'Oc"mdAŎ>$UU>cjdBc@q_D0DQĂ#J?'tKUke;{SDuIdM<#Q{M豐+pfecAʑ:6@trt>ږ-e)޷H !:GSj<n,!c/x׸hR-o7>^LP,Jav| nb"8mMlAKһx?հ~1j~ G¸CPYI^+Us(V LJoɒV* 7ˠȯASI$fW*Ā `W<&# 0vR bjMd)lS+A٪7wmI ͣ q%зQIBP3 aHSKꇌ$8ꒌ³}B[D2a`)[V2w $)ZҜ#cE&=r*/=!& BM8V7|{)qM2h]*7B-EfͅkSJ T N!=檬.-(^ؐǪ(6[.Mz"|+ȜZ6b)C-5 $>+0 繙(iլ-/O|CyQE OyNmKYmrWIBMwЎ1r[/I|E +nl-!.Hd$Ko-"n1( Wj|?Zje yLDJׄ/M՚5S mnÞ%ḥYPI_kɑ({Q JBMXRC4"r4m܃Ii mIV攌/:4p#7~1dAAq,]WC C_RȌe4\~P?[N6`Î|̻ |LEYoԜx |Kk@"![H XA3he轢8G^^0Ue:1걍5mu`u@^rΙ&\4K>.ȁ-;vʴy6eht ]*KU !dmcH: <mnZUY^W<#m_SmqDQt;{:!ѿ -3E d z~ja4a e6^6^_ْE yFA-Hc o6z_.͕- ĽCkmpe脔\J(7]/0 ϥxbkc2HsVWvj4v UQ<po_"a0pHQT+b&K=ӉG1ūG)~U~"Y /H ݼv' h٤ckJԖG<ـ !C(䳉_eӡ-618}[y;9ʩ!'^4_"bf`jbW|V?7gB׊wOT ^TapT 6\i5Ze4/;̚Kv9!ArWOg!H0|DJR:":o@_G*!`5LJ'7]>tltY$84 Jk2>֊GWH,8&bs2$Pr`iia PjA-_{yI&em SVt(I}f QfKӚAk"BFGIOkB44U=>z HHNy\8:jàxv,߾Ū!A( YSp\8CDD Bfz,Ugbp?g.2^Ѭ(S6BI'$m'W6dRGoŁa1 t1ⓟj1B=LQ2L=Q{SqXM#0 `Lda8Ob|tAp9du b6tW@ C`d*2,N1.b@ ey~p0 /"ѩ|Ee{+.T[~/ jHf^}aQ\-O< ¼+1rgxˆ Io 83ɺ\_|ܠY:GbR!5L|B.Ȝt4fcMmGwώ+: 4༧>jḞĀV.ox?z(3Zثqkr;( `m0^)k^ \pDX|SHV;PRcMTX8ώ`BhB楴Z}"g;y4'^$EB7Tޥ"I%yE=g0j+xYG(* =p̗u3)P5SߡFj=VbpTR9糼mX-X4Km΢P p{P~H q݂aM+h=mC}ℕaa}DLt}O HfE,Vq&h<4xpR(Eߓ#"ٵiH'7^̾7a0= ._Gn3B3QE0]`8; 3Agս$BT9WVmߚ޳(u/5T-/A '<4!X`F)$'?Zc嚝s'4/شXpȧ_Ss˔1oeJȄ~?XY Vӂ#d*{o]!Vd']8ߛJleuVRkDUSpF(T~}}0uRrizu䀬l: Ukβ_%P QK {&M7z)FkSH\ o}g1HpRHu(\yxr*}; -P?-E7(( XXJ9X9@]+##3_1qJ 347rpбs40ձ4sp7;%dgwkGOLhVF:VJpl t,`gGWcdf#?Sf 12c~Tb̚ﰍ寐l8m*Giy4I4kQx0Ghw@B 7'uNcڽhWcZ6vփ?fjln{j2W;wKQaC1|3}7ovkDNökOwb竾 \{O77fo]ou<_/_[珀tBk~_<^n{z>__=BUl|aTnoYMf1Uf^8%A%nNgJV{8Vi'0,"xpɿSwhSڵ;^Uq+Ѭ(ipGX @2prʕ?t]|i&=p?R-: u):N/77x5m"ϥ:Yei%5Z9l@N20+.~>~r*Qrr[j\:9 =3ud1Q]o9\`X`g܈&Og_qbZw,ȅT䣛Hz0ItTJz#WK@uuXy2@ı!ts x}V֯$ &F&LcsMd(˝7fz][E&`^F411 z:>9 3`S4v鲈RҪ'dF3c:U%{ tlKOMr@+ ~K=' n31Kӝnԧ dyXRj/#`IpO |b,#.%Ȣ)@^ܬË8|?!l` ۟FsP0*?Ө;⒔Cb*vV6kS3 $K&"B I,1USnn=˫ ;mIF;^:t7#&'G YX"c8+(<1}ou:ΎVk" E1_& @&wUVkPo,ĶdRN\nv@?swMf/]yl-`TJC  |ɬL+/ѷ>Na_^ҐL~f0&A4w~,&#QգR5~0ou[ZM0#N2tXW@nt c8S\k(ˠa0dmlT,C/x# y^L0QE· *w]YFί*L:Å[d1NP@Q3ALqdQ` J HmǢZڇxPB)AKeF{8,GP`gj@`NVĄmqD/$a9.dh$8uxΣL!}:J`-돽 q ޔJO_kphAebX ^ܿ*r6nkcG,phl^¡LT d+2^6#q(așH.n9aL$p ԫJd@Z6w볯 n aF#]5jm[iBBgK&`֞٭%wȳSU*jˢ}P5YpOٿ>| }B; ^P[(āU0k6[-2h-:yYqMhdup RyqCu؟\a#r2#QzlLmOyk$qBWLlӜAQ$|(b+0#wErT$$KW T8Uλ2T;`)}6 IB36Y4?@MP }WF:Tp-L~P/\dSRWo"ձrB) ?)]ۂO뙝ۏ@ 2u=A8x~ Ff6ԴRFBtJ{C~`7eOʲ_O(HBH$a`V ]x,29kU^(Lz)ӌ춞_म?mǙo$}o]1J.,US,j]q =٠N ƺ,(J:wѮ-g2@C\VR$Gw(Ú@ߏRH_"-R~`҂G&8SbS!ؒTbod 9B@f+xCJdgFvC :G?@M /I&lQ2 *)r˦fDp;-^dK34AV}sj=U2JLuK+30H}:q(I9(ey&+1Cf>NUB׈_ͧ(^V@D?B;Plm l ,,aC` e?0ĸe%nC : y\Fj,χ  >vppgrP=p6 ;W 2(- 0T/d>H%2oO*ސI'71 n޳|vz5=WHc(J਺aD 4y 3װu^ "a.ybXS%m ̹ W|Uؔ  __ [a2_HdIymI)I~|;l\R1 /5MTè^*,rץy?ƭTC7k^nٚ` al֓ƭ*){ Aa0`b/0/@?Ow9 _|LlW ,LL0tֳ23q5 88ٛ9g߭@sr1YؙXX8XX88% BdiL"_l?BR뙘`7O0u* nX&wr{R7VU)E{/GkvJ_DS!8>I@z +J`_Fhڨj򸧱$ qF*I\,pET[Yo'c't᱀zNow'!lOǹ31ndjp2GbT5}uD4B{OŧK.AwtNv]qMsܱ}cAҏ) 89Wȩ±@ߙHjE@N L)+cEUvNzɰsj_sU2/;-EZ6v Et|8I.s4j؎RE!i|{![~8t U#-Ax&E6bH ieG{'PU)\dXPGaTwL1ҕo ',xOGH:+xg2|vJLxJxJB;W\"uz,a23,¸ߌ|tڤ$X/*̙3@BeQ4r-Y,Į=ڞb>lY@9rtW}NnVm*gshsj 95Bcm`ICH(9~- ^E$bͯq"(wVlk«P0DrW]| +O T 8SY@fo-N(gqp]Ʌ5'*PT>Na  :xlݏ({X VPZ؄>Z3Ga`fz;oCu#-4lv6y<@n%GKg@* ]7[,U'i2n''.BFn1h9^+:;FwzvrC! Z֜}1s$E$KD.EmOʥc1&A,/m^S: i]5L ܎#4yj8*ɬ3GfH܋ȼ/-ꅇ-QXAaHcl8{8`,ckU$ʶ y̝'TFLIX- F"3/J1-kpӃGE(YhEO (6Q #i>ZZ1<*|R )(ze4lEBY6Oohwt0@W;蓍]:lJ6 )"CFA4Rġdy* C$#8TR2쀯ã0;%@v OB`@R(No834daБTwbd8xB|/2 baKQ ]1Y =j@>`A$EٰEY@e?Jkqb@=eLZYwfpiu-l29MÔw,i+Ovy+Sblݢ\07<dE3_!D(ۘ<#͕d_Z,Os*$lj"tk3LԘ]JD=j֓/L/Q>Yx~׏3գKF?%з6%sNל'f^7Em@۰P Q^Ǝ7@@!10,߄/ Y[j1+de#󋋷lEjovިSN+𵋷/0 fK߀7Y>hЙkWB%G'S5.cQvbe9ϓ≑pcY, =Ƴ* ̺WGx-tx]Z^U.n.]PH>X$r;U6={=Kk C+}Αs֊}8U`"H/S GDJ3-S߿dվEYנ4ogfLomZF53?ڀ~J^y ғj6#myN`p&>Xs!s@Y :DHGړR!b Lȗ!!dC&U{2f'ila|(YcLCE_X,IRgtUc#"EWgȴtZo{.o |ݙ<ԡw}xz;v_P0FO uJ^[U5NK\eUwI|\6936;M5(3!9c\;#p<ΜrjZ#{p?:Ƴ@+ƿ*m1ݬ}2ai懸#JUʄW6k./PZc8\SG(ɼazK.ұ:R+B+mZVlWhvʲHM;*سU=d@aF ö N UȀ Y4qw}:u`tV̏9.7skU7rH`T?o_;Ӯ#.=5׌HhSC)^{Dmqyfa~gN6.Ì-Y&Юpu'-D;:d쫣X.3 o9]%6;!(Aw^TF~K+Pq:Zs]K;,J| y^@5fIjad~Wd'x{# b#tzijO_fH|§hB:Yv8vGZPOصoj~YHc5mt;!DˢNsJ'*U՗<ȴsH⧾@nacrkUJXb`Y'|ꍒIyRIKtK+k"7ܹd@ AvazcW>Nob31W+&x"ߏ…g M;gL9I Eo ,,&]/#{B"h|:C+EbfzwP} @tLF噔۲!#0[:pZպN(&[alX5JHasY98;=mϷ@n,k:=o;SjR1ȋg͘~ Zi]Y 99ġY|SZq(DX_Uz798u^t5д/ b$]G y1T;)i Apnfi?[ aPXT?oԥÏ#n gUٽ+`b9Ya]9t9TCjr-Z(?0½ uмio"P EP x̫N`]W,b.uQ겡Л5A $k2+~f|{p?eCyO)M YVnWA/%A>oc}T~ft rSxL &=4 )WHu{#1ۆNfVgaA/hU/yW hP[{ahig2 0;"rt yq7Aj =$YP6Dwԁx8 aZ&y φH!Z j̩iuz-3fÛ@6@-X.Q1.eه~*4}C8Dof+M?B k^y_aReTD^tzs=K wA|CEN:D@ڜl7oއ jٟ0!YV@aOUpVzFFaCU2)/Kпokhde__qæT~btu2?9$SsjV"uW.TQN\4y7 >J9?ضe:d]._ԃ,", ^^..dpD\]AZەFBةS]7_./Gd6Gkݿ\?n3bҽ:?%1o/mJg' e vӕLVΓQ[T(sZ,[S(P{D}nqeM"Y>'ݾuwae׊k"["7vAǘyg h,\ x:ֽ6Ф#Ɂ4NXtʚu1C󙘗[|Nջ{–`ٮiT⻀Ieiwc<_fżz,\򪽼v%ߗfL`p2Ƭ̌a$ Ps/8)ϋϙNO朎[)?0󼦽HrK[U^0KJ^8I6Ydђ*͆_kzk]XE=9weAOl&'H_h$Ɇ4騄\9[(?W d`B)2lH|RBH(ʼn…a rO1 '36'-8.o!5%+˦0kᇑPi.]O_`!|8O0t~3J`}KT >BWAĄs I }FG%tT?%2砫bfP^K`R{RʮP0QՈnyBj-5$0 2jm۸i_ǥ 7lyԍ?y ,mkF7fH$e3_F/m:| i1d< =ʡx&sQqU0ITڡBgJ 8ˤis ,zAK^[K-=Dկ <՚5O8$lB w_)؝4JOPf23(2Qf{LON~Bqzvs)g{/g3p?7 Yڍ"!t5$%ܒQ?h%VATqaX6%RU쓼Xpmd#9 n! v)YN/\.Dj%v2[j J;A͆7z_Dѹ*o= 2(T[`Wh.LD^:%Z}G]-='uA I4쬞)XHX)/ɴ ݁ A=D^? ߀Ej 4O\* QT4)Ĉb9"ӏ~Z\\,v"9&h3kfI-{tvʪW ^ࠇa 8m>˅ v4 "9ɔ=)#g<Ϡ=O?'A܍%^P/µ>|"< Q}?{< {gPUs V蝁2P7yvKRwzƟH iNl\8ͬߣfe8ecugA`#a OY'[(V\_3Y<O}~]XGl@ !;jAcQaAfF&ZoȐq~A>C6kue6{K)( Oۂ`,jwLQ:2 ܾ1 7 (8uR%0QH(;Z((`Te2t\-}F_C\Ӏxg;(tQ *F4 [1{!qмk)?])mhNϬi2AO#iv/Ǽ^?甄E>aZ9yGQyŋlw!a .jo>F5U(]+PءV?n]P5[7S+ޓ7`xQ_N,n[,s}?F){Afꚟ7n =kI2Μ1qEWZA;PL0W2@uAF3Nki0 $L$s<7z6l`,͕Vzr}D8UpFR/:q,Gh?+WqJ*]f>|L[&|oœҋJqT2U"2r{DVskK71&^JZ0.-GNıhiSU06KwB~#2QOKۡ !/]o2´5܁L0 Ba[0tO-(yQM!u|M8d$2+7qN[PW䖾B:8$xkwQs/|YÌ>Qθ=cr7G9<-OX籴l9xlcV.2Ni֒-FG|>'m%PE5t F 9q'a^N%ɖʅ!3<[]y ) >=5ȻnRG;SSᗏU[ghͪ`ǽZ<ӗ鷵;]͕n⃫ut'[q"Z?3s]TLܝކɏ"<9_?z}8d:Si~) ڐoYdJ n@vx sΰ_*ɨ.tQ2UaI]@oΓc7LPDzy}I辌TF"\]:ZSJYI{%'6!4mT)>hErsF]%G&oreǸ~tF.yg#re0T `*Ŀk_vWq{گw[Z(f< ". 8rqwe?Ѻuwwdh_Sze2?L3.VP~-Br5PsH ݌6[y{rW N a#Ivh0"b4t$#Iˑ'ݚ/y@c"t`uߠjBX ZxJ pTEs% g¬ݽ-ꯌw&9֊bni'_IHE +@Hd uezT%土E'Kfl'*MX6-_oB_w<Փ Qˉȩa wGXa:׭q}Cg4@p vliw,9d?J!RZ_"C\_rr4cl ,^VEiCܳP2i =(VzZD0!L]}ѥeK2w~s:D闐+kO=C Rǫ7t@8wcF^(FkU|ԩت5R(|X@lzA$2 $s-'yܑTpa;Gİx:I@]1>N˝Zҕ,>TJQ2$֘i$wF'FdGܙQ`yg_LK^lLi)Q"Xv/Iu\mPLJO{'kY~sT~Mۃ\4%5vz~r\^>KTۋ? mw[? fHFU|WLt Rg $mJx8 A NNz}B1`kc$/A&cVx];kLUca8`/Z(F̖5}5KAJ$1y4% pRz*U9Z˕CaG2 >S9׉iVd0gd7u²` &38'3 y(_kvÅO7 1טeՊuA"OU4?*IVWu;=|L^"~+ hp8?.1;&k zg~&)`݅{NQ`:"/ZT“gu R44]@bz:"! ޔ7I E}@M؉N=PN/۽N隕P h?6v`\`{F0V4 OΌF3%!*~H&w2N:A( PK8N&&z >TW +TW)܊oo5аiWEJte0M~x=zZlç}՜ř@.vmv~1f+&qX^f-L;etvt6xҭhr2w=Amqb@8(:0wf N͋h`i!0ҌA Ԕ (S8vǐ.v_[1=XK"8kjJ(#H(*F[S S 4Wq0 *~a ϋaolڳ Q'~u霠JA ޼5@C*-#^_MZ 8F,P- o fPj 2h&D3zeKV<9ʋ(!=4h|[z@0m$Awf @ xXBXzBU̽b2ӯeO`}~d-d3ir DŽ`%jYԶ[).ۈ7* a+XiP;Š59\tL Њ•=_Tڈ䁝Rbnu@>f) lȖ:GJ8H8Je yfz9v#0?˫)r>8 Sb#)+LW[peK?un0TVo󶵤5g' W& $L=}ޝRpb""MZ<yG&CM2+: flٽ%!#%$8t_\I,DaTLB"A5j퇧I`>%1OW@ɓ~#?FJl@G%xGvG[_ܐ>rv(яضa!. ^D z pT)U-9p \5[F ja]˅) XcEܴ99B=a  P?d,|w}[t;֤8MXO赾!-Û0E2;I,uӰ_ FZ Ss2̃0U"?R:լħ C**Bxtuq㹬첄8kY-R ʋʷ=.n:j?cq39 WzUY#:“MVmI}<g;s`coZԅó}cٗ/ksRAn@ hДK RwޭΡoq /n_ & =8RXRChzq=rw,!}C~ wσoR"?J!/^GfLniML^~ts 'w5 gsk@m@nK$q~:& 9')u$X`amu1tw+T`\mNƢU2s(5YWξAPe8'yH@C7Sqa2emW2aiv bzFfBCkb"_BsF,z `{Qד %?jW\!'tz&QPK=UvZ(bJB] ƕ刟G2[1ޛ:sC xOosI.[m}\gppHbD&;꺉ec2>k\9Ma:$`-<( xM& ]VArU%xֱc4 CRy$(Fj='˗\K*F#XJ[;1^'1Y D?ڇwK| łב77o`?`ZoZ,]Z,,,Ltlltl,,;#?8s2w5a;Ox012r0sұ3ub, tlTfNF:v6c`cmlfdhfcclficdA߬@Xr7?gcec .f_002}V i= 3T`Xltee ͟32ug4.?mF ~7Vz`2;r l$}O[.@:jܝ i&Mr~vb bC^ȃsk'bfaA:|ǣF6d\œ8Y{˛ _OKFD݁uW6~WqKk uW"5nMv5~FH6^w74O5 duw:*;vI_Q4B S{'cBS{&:ěJBFaqo8VDI:E?4Tt߹Lۼ]>.j)C;tdn/n[5۴\h23#"ၷM0۶ݱm۶m۶tlc۶>~ϷGr%RѽVy5֭켈]43 lC U5D&A5rbڿ8+okIF] 0W%\$8{v=FHLպ}c^,GgEN0P]Hj񼝹J*lrzq¸L]غ c04,~rN9@ -%PVT{T+6n(ٳ\ 7 ک.ʸh<++C9a^rݭ0lû~Z>zwƟQѥvp*<4 ٚ[jz7k6U:x=Uk12k a~Xqk㽹@/=-]7XH~&k_L΄" P݇=qU h*-hK4"hr!oen` i5P;XPvKYt%8{G W6%Rcp fRNc7EkQ wan#CnZ:h>]*)H90q>d$I]pQ۴hmNhe |( }qIwvaAuLojO@/Aa0!c`Twj|iU? k-@Ig21x/@b:s]f(kKomW 9?ץS "îD,Ԅn!yav 0YYD幃 5efP1.{lPbl5KvVy龝t&X3RzWܪ gqSݱ75pi h5#xCE˴ZI$]7WfAjN(Cqseҥ yȧ1KbpE{:?#U -cJR:"]jP*3*7\jW\b8` ҁ/XrLMGG͵&0fmx}j?"jG$]}XF4!i͒ŤnKz~{GP\ٿcI%+Jvr=0"[7J+.89]ePN* DQ;Mk\h1) /ǶXGO7AOE@g sv&̣.VTevdBʖD ҕxE{II6 \S0:}( s[{g&iT!9brƒB=рRFam4Rc4/`Um>N {^ (j3qxHϿ s3^B_(STY!oc:7!u^'75xHj35+"Y Fȉ{LWɳMV_y8`4ZJ;^r!pݦhyځ"Rv<.L[_"T1͡}iT&)`xI֚N9íU/BX52'ҎcyČQˑSjWQ6ߞ"D{tw9(BmJ{HߍuXs(RNZc%@xؤja>F@S>++O 0KHHYlcvwM[[< Ͼ Qo,P0y $ >L҄2}:ϗJ$dyP;z vWΖWvi,R)Rg}F,0]%S6wTXqa˄wuh_ ;BBthAA3SVqE$l΢Ah^EeX!g#]; ^:Uu޾(8cf3) =0%?r h`gCn1_gץe:;90ŻaJ|݇捽8-J@x7. i.n!MkfǏJC,mSYLp[(-! BRb@]0< mV3ZG/ d-˕& ->\݆[7[uYJдESSrE)ᨣ7xrRGcE:"yb<2*d鍉ŚIlpA'ts Jmt"*MtD(ѳL$ghëKඨ4[!^!O 9B$Gvk9=Z:C !PXh-:|/8⼱!urBQ6`R:12aqSr%?Rv?KSR_}82F~&)3;z >CnT^WVM~/+ ɨQ9-R4h4pbvWY8'A3/ׅYlRŸ0zt{ĉcaSGs?TM @DZ $ŏTd#u֖`RK7雩o͔,=X&~rC8p.c?B#*'a5:~=D9MqO ˏaXl<$j+/F>a ??;4o6Zy/HHF336iossɟgd#߈ ?DK lK?Gl)7 4 ?^_~#\2LC*`v>ez,Po..IfnrB)՜`S-K"r+pLJg!Lp*JD3uG),r͔n{jyӊ.#fg N^vqȽd/f 9_鳇v}r%V6[21wn@.ynwWgwdi*[!7Gbq/YǨQ+it RS/&Ƭb'%N&y0jJAGUFFrA5}.ޔMm 1dr ᲤȐȻGSYKB*xT!++e*|FF`i]w4v$nSJ5=,}O;G^j K5%tZ,QFࡴ=;>a..FO;hyK '^R<٘5f< Ty1LgdDseuШmT+FCz+9ta\y8swZiSj jƒ4s^H;Fq*vc~)T?̫Y=]R9ӡǩMx=E1f47Dž7n$#D{C< rMɘ|SL֥Xoq {7oc\-lz\ XCSRVȡVL'f;va`w g7G?.3p' 铄TÖ !"Y #ߙ&k|o+#+-  #;+:~c &Z6f^tY6b?ѬE2Ѻ[<MUK(d iisnv~~=G>2{98]8V!0COp\.x;=?ƒ.G |2jrK$k2y"Er6NRjP5^,џ (Aʟ8R0Yg˟~Y^SQ_hPsTk<+YpjURҬ R)ROVGˣ ZP=g|9ND^@w'OHpa.ƎϺРORmin Rm|[EsgV OcUУ5AHNUeINpMkQu3.m; ɬĥw[us6W&# UB̬ASo (\1vÆ"9Pty*F1-EJi Ʃ`;0}1Iyr!l0HpxQ ⨫v.qȴD&p." k5DARcLM0CT v`U>NcJ%Q:I#a& ψ88>ҹ(+5C*Ĝ=%3fFD!2xQd]PSo-VR J%&OL>w6`p͟l@G.zD,)v[-X(tZyMf*US2$ҪpQTOUI,+4涮LD; <_<Wwai(#JyNeT69\嵑uG vB:L?>t4km'pj8$K0cD}xԠV–XqN ^j%l P `)HUO"OKځat WNRs^YB{@UOu( Fd)H]S Ѻ\CS*?T&eu..v8iևQ@SϐՒ+ E1e,|# *=L+z!m㐁yev…b1rw ݿ]: հe!e G-;bЉ>m TxL*¦C`ߌ@)fo&/f(y%\?0W؎J+ I?&!tQEZ6& 6*UVqQtf`Go)DeB5E$keQ6;gW0Z'+=vwMlš̽9];uE{ `BP-kzL ~:$2Jݾk'xB.$}PQH6DU4Sv9M5(ldIHĉźċX_#{E@8FC\8#)|kf2Vܴs!: =~(K&Y$P?Ch`WsկfW]i#B?bprrb:r?M)+2́J~RXucŦ2k`\Fm=oIqAke4V|1tFB*$X%^oX98CyũZwVcvR4&ZzKvWz5}6|FZ17W8aH7L+uYrqHt}~ ?(YdD<`Æ#zi-%Nx$$H8ӧ)|؊~&Jrhݺ,r/lDp& hW o ,0R=@Y :zLBҜVJ9#LjPٞG$lp5~ 㜶F| O(21y6Moqo0 3=qPz"|>jk-l1טp٭OMN+4ʈb[&P}ĖxI$)"a-@hYyM?M4id7 ?.pXā2[mv]niOqE|Ɉ%hI+ӆDLm@;ٰ̛h:nA>,njv,vVPϚ>ܶ_JrBvgq;uLqH>;<>R>~ڳ͗L8ϯl_r !Fd]ܹ!1;ptB]k"ȇKPs9"`|;,A ?Xvc ľX;ZR4U.}¤T 8UȦvM9iwƝqHok2m mH`<= ˃G|pRr؅Q )l](Í7' cU6=ň1ŘBBG>! 𓎙 (H[wI*I%;Xy̠! l'T$1EF7jر2Kdf#k361y)4pݠKė/e(o7p7!3P7deg`dg#`b] oAlllMfdC_5,ߍ5bDECeED/%2Y\Վ'GGd4(8G_ϚzH(\ᠻ+7ʂH(kY3Q]<>SD>j9&an[?&SPN>;*#[~r-:twz:DLr,7vj)׿|ZD .b_0<>.ǎMfSwFA}%[ BWdK7|r$J&BK|&-9- "ϒLmGC+j<(hoċ/hM'Í:FXj[75 iO:g_`ƔDj&GZzƩ;aԋY_%[ʥ%PHm/1$ 0LV{Cmf Sv#ƥK6fcITm'Wa0@ݰ] =ӟUVVMR,54%qA#S\Nz}D`s5A5Gt{'bN4|'E0nXl uBi.IgȂ)f uJ %`eBtBpŧ@}"0NF$BG;YlxÜ-1yF3K|ۅHJPcּUcUvĤ{H@0΍ dah fż+9#"ӊV8FTLҫdx[^Vwd8d- {7> 2ޣ{$.SC"M#wDH&C%l p2%uiEsԙm :A.ʛ,>1=vC.xϿ9w1^8du2'$ %p:Kgқc~rsgb=EAI*wŴ^"crroy}aϿ)i` #Ta"m2e}TK3.i36` %mhj1ʫkRr$(Pk;U)$.F7w=|~FoJk /JGW)!P]x ~F0n`A+1Ă8hT'#4d ȔGNrWe?%BPGb儜RNB׍Q7uݽ<]GJR&hGks=HZ˖:?QI"5)7|-wOl*GTԫL5%Ҷs+4^J u%qP ~QuPGK}:1Yr[V5T'efnho'_v8TlCnFA<ggVioʕw|)ʫ~>n/qu-랔\Iw $V5sQdg+kY H_"HTűn%9#Ze\RN42;Txua_.uu GD꼄4轰 KWS5>>$jWgF*$sQz흼gZ3e?uY:陛Dyes:i.w9o\(Zl9,72x504Nj~lnsF2jvsԔJ$~dG2wԍ_g}辽 w3^:D!%47o[vBMwԫ"<^Y';ĆQl*<:`A_$n,R jZ=PxZ=U@W~Fd?%2kY :70$/.?hV~]^.eAL Le̢;EeF;::6/2HD@"ҫ0Md+ioHUꌚ-֗wԜtO9͹+) sF[(N߽f8.-сH2Ý[ޫ7&Y3>],gW p""Y5S&i`zN] ٘h5$&6jDAKm^90Ӣw|?IOoC^Ut9shЙ1}ֵ/?%/cJB騦F]wh+&]0 oQ,A;°We9[kq:n!ea X3ot,0wjti ?1$>~!8 x=S'd?2F8b`1#(hfhde#k``G8;˿ųrвp0c`C6̿A!D6oȖH 0[<##+Gmޓ_323mmY-O7\E0O!~>̝P3lϼ,^6XKlo$io"%% H"Uڒ6aj@Oz =ԟ+1Q.\\| ѻ耾2G/nu{V0NLS. pˢ[8?iL9wDɏ!4.ׂozuƨ4;0Y)yFENws5] [x`Wˣk@sO^8sN`(F ruLP;(xYW2r{9oq =F$2  8] j)v˥IiQ(@pʳ2ǐ2ث:k E. Reʬ [͛VMg$P:?}l{U'aYո^ډE6= w^}̊A3w5L4#**ls#N'8uѝv78̪֨wE+R 6f7b=R Q) Mf2_Hq1L6)o{dnI?3! ɨ*Z\Ѫ;:qޗ ^Tr]A}uu5݅.`"فAX,8lp$;c^>RL2o,*g U?W:N1W a  Vu˄\梂vRveXئi8&G\oje=%v?  OYj ]ӯXն\v3^7̞+K#YN Z ٰ g Ǚ=6J~t =O#}tf`24 .C'0&a^Bđk&D, {r8 }1BOҴum][ CBx)4͵5œaSr 1)2ĺCH?+vGNy#ĬDRJZm.08>t۽(KJPw!~*5O4.WbOV1jq= dZもq`Ǜ2|spD* ajWkWOڊ HpdMuAcʁY}@.q :|*# d[4|VʯHuzK*u >{t\NNwuRZeqZZP痾eUzz}" +F|"2?o ‰x˪xh_Ib>u>`V?nwNpE_9! 1I;zB8"(@x JKE6#8 (z:]Se  z{ד$oLޣF.f"r|DDA2F8u ŧqgNJ5gM< mӑ3Jwlq"7q;Qpz_wsER|_J5s]xGRj[Ǟ~c7mZcCL Sϻ.~:Oʫ@ˏ iX]VKD\*eO&$e9 LPJLP1)ẁ-9٩F?LyS$; 0n˶2\HK8I\]u:ԈEK@H˂=$اq2B.tO{"ͣ.FӢe*~JNj + HS dw?!K"pRjwG}@^RYLQ-v*6-J U/FuQߢҁ< lE8FÍ ; Si}ЮkNq__ Fd.-3Q&R:z!iUD|/ ^,; w[I9M{;j[ a Yu*-,dvn<)7yMBT %% ><l9`f CjsP[Bml,ՑL-lS I{bplg+Q{N-zg+wJ v 33ZvI.dm^`FRRm*xc qM+""*u2Hձe"-Z ͮgiF`F/!y(?92K0?u\3a9^zp`?L;0dyP׷;=8(ۇ*G~JIfe۾T+q9s[:?Ze|P9Wu%)s +T&X[RMzoA@ XQIDC3nhD i1VruZ6YR\,lMpڅY! Y+ITRbAf$26c~& w1VGJ$2)8NQaqʅ/._.4X|/NwHg%< XDd+¼%)}fνҢ QQ!aB۲%vo F_z+GTӍ),i6ރ"C9#/IL'D_: ? 5$PH9BpQ?FXhAAJ@DBF@O#w}ksC]g;߸OJ5o4N^_ '8_8?i}:!&<4H^Yyq~֮P"^M~^'!AuH +Z8{Fa R2I^˗.lCtut%Y) |q(m)ynҜ;/GH*ғ Xt g_9$k$倳kx- \fVO|\5Hz UU9Uݕ澿!d^;i*!y)P62H "C.` A ymT7 + p56A?chR17/YK}l ((@%[ʿ.pQ# Ȟg긤Q 8(x g_/@)<+ ֩Ҫޟ vf?JO+1JZ i-Q"=+ o>; g5&f( y0h\5&#[3pm^Oc_QQf H(˛7qG?Q+?E%bKňBr} QX |k2]U<t JIJ|an*&jNDbCگP "xWH)nR gȔLCp%SuE{':S֥u _vq Ft9gnSrJ%ojΐ ױ@)!BhOn3t %%̆6G1eGgvE2}\KM@DH -DZgp8iyX\J3Ћޡ ߺ<HZ &IKqdorGZ C*܋O;lںᦊQ1Zn>l<sT Κ@)%usEs<*'/._ C-6DqYW<=fb.Oub1I~S6{z>u8_MCZܳ#&+\Q/hDbˆ5H 8 TfЎ^۬rEs/K-I߉#,TIx&tX;عf^ F՜"s$j<^FC$FRMgyuMn>80rBr披tغB2fʬİ˾SyV9g=^ 170|B9)3MBӭZAXA guPP5lZ6bqxkV*b/t{5<6tOtǍDaSSdkD(/J=4߹]./̔$&XWlHRhvRPƺY\N@(S>F!?xOǼ7SFT Or_¯nrUQڦ5Jx{eC % ,6*l| AY+zb g/) UX" ݦ*$!/Zt8ݔ=}DꈡB ^^aPG؁M(xWЮ\39ҌOlIGjq`\# }8#χ㉢GFX"%%$ x!BKookWg 7p1"?V:JC W2`%dP~Ț6 fg`e#8uXSO92L `̝ 0@j<=22O B*[<=G5u&= =XYpBvBPS8WF|_"7S̼.6FA< ҇nRv( ̣,#ѹMg}:6 @KgG`ҊMޜp- ɣQX+}ja}PQ͋=s* 4~Aϴ'鮄^kZ^= gy^\N8dX-YTؠ.$Ξr7}.{\φ ,8zÚkA<Q|-Nƥ8>2 cW*03ig2bZG]1ז ?)jnK}.P8ͤYD:sDtGh6lgr7i/M%O*fMM̳jsAP؞,Thh]]dMnW!=anozP|BݬJMdaQvn+8x>Z3f%ҫM;c0Bb)sє;x֌DAب̑yw&ʲրMđ<`;? B;$^A]ebq15%H|=u$Ru\ edNhC "pGVu('b)x`3pI6sZYO{5 Je 7+OTG;U).?0v0cAεJ{? ]B2(ucI˹(n[xuyGy9ksz~ϰmCPU$TpGVi,LrΛOD?o"6e ~,7} (T6-#NI'%uI%Zg 04 `|3/_I@Q88<N LFgu|6zk~:/j}yt\̥@4/0R쎓D K^Rga$&冓&8aƜ4HN'\X_󼝢c>p?Ї.PR!E@4:8EǣJNe3iՑd$ EpgR |9Y6iuӧu̅m>R(pBH$;y6>( nHt׹-1%J9tmXKrj%nr"7KMBl6'옆GΊSn?j /w-Z ?EQ{`xbK(+'iNP%?/*9Gz=&(g#uX [uĔ8qt_,wӓk3ln@EfAFJ8L:6+kuDyv8džJg?lrmh4w-1J>/AÛfkқ r7E.<6r@k$BvxE*?bʶdoI92ND߶/K5 ;+Mr04snl~ȉb>^aO^9dL$5رf'hDu`.seS\Q8g5 i֥Õ7U@:9ohY3;dBkkq߾SA?\@K 1.KprOپɴ?``r3y;j00_6"?`~'e@(xj!҈'y2O_.ޤ0Iv*)Յh~&}%3e t]@U\&xK}u]A<!F, 5Y,zx~Kc-T_yta k^}=I5ƕ%f#tC ڮ |lcܧ8>ԛyj?56N4r0I-#닒|BMMM!}҂HBqsmYylv/X h IeP}F _,~{5ol7ICD1ර< BT t s Wa'UZ7>](m,KDN~?0H/m;Hr/qR|ێ[2  Ͽ)J|vOdyn8{ 0tY`~X^zГv8S Nav sb{}l4A^WN4/g=x1ӿk< +-3_tJ{<3;- _2elX[2זȄ,'kU}Q/O+<,&>fgKgv;̫EIPJls`h;RҖFLMo8(Ɔ!^xwrc(A kkkKΧHsGk{_j5'Kq/6TWG4sϬhGGH4-/=EXT5gr8ڣ 7{BQX 3XҠOd1;,N1.tDY-e6+mXLV.~CK."|SD^^~,yyŻ8/L1c.XJFٮ>ەgkɣPkn'B`Lez 󫪲`vb ==bw-mxč"۹~ܴUfSκj+Nfif+ aMB!J+E SE` /{5#Yf2#2漢/!:ۯSGq1kHt)+sE31?rǯED(V-O:%FԜ(ۺOExE~4|NQͧoz,cAhCyX#~oT? 'ACݹDX[c0ܱi۱KmX@ͭ|N˨{( ^}ťu0nc]ܽ [<9K1;%kGbzDPcf$c7Pȷ(dg$1n>K(j XZ chZ"JI\jִLCemߙzV.9x!+ WIzKOD0&$ aZP$ro66oէtO_Xj!:T[CSݼ٥_"(z7ƭAf肅~l3lsZجV~3ZEw;E4z-^χ ##TFLAVQ-wT3de8YDPGn04)]'$ o0pv_S)+Z3lHk+Tm}<)hz}VQ/$Y͐D{Dq>۰Y ϒG_qA/~5{R!j:e,}]qy]>Te2~ec&N)W[#rUSQ/HD쟕o }DK]U D_eąQQT mn#SJ9F Do< @ ɨ^qb;^=+'9zF)lYV\} Z,(ƣg_?BƽEPZ@m>.kU~%nvJe{>^iavy5&끳j[{H∳49LD~u=:]+j;N:N{NđG^T;ݳnxUnsց; jl׻V"~DFWh8mJ@,g&X n˅USRdwuzn`F0Ldt?"-`CuIs V!qa:ɒrL ~ ZлJE4Q!jr4ڙ(*ް6b c]GxS*\ZVPGr4?{FIڧ@K oC% +W=K-oyꆓ*\͹Qj 4uAVl\ 7e`YZoFۀf,a>^D?'yl8`$utҭg3d-7շLInXKQue˛V/_ jT6"2 1תD[s/@EG:E(F4o/HVY۷IoQg`I|eۂX4ήxfr3C7Q/JUG::g%̜C4 غd?KPuBiʡK^[QvkA[ VA3z@*!/c|OufjZ2zB lO)],MopJ޲I55%A tTO D~,ЇԊC]w%$*-Q })}qKGY>X U+@M#<@"^4{д'0a6#*~ߠW^ѳ=tZ]24&IdGK DGӓE{O6Je֍0.(f"3/C+$oh`(j ߹J`~-~& 4`,v,KԠ֬"4b<M)7`:L>R%5Q]Xn9(%)" $B} C.K5t]C~4LFSuXV`d7>"D g& ԉTtKqՋhA86^h(M%J8Ɲߘ0s?]=dS?/G*ᗕX2eIK$X̅̑V*bܛ%?7xa~U<߷SfĤ·XsV"ord5r6nR QTb`|?c?&JǷPϺFg m}p9pon)6&k5Â2.PHؚyl.Gx!X`Q }e첢v:yJF~bRɏFס'vZZ7|z8("YZqC["& مQGF+␯Eb07>bEV>"CZqz۟HQџ4$@ʜ#1C0  Fj]gv,eh.l]mTc3~y"RHӭy:d= ([m!E@NTײ[ҴWuUQ2TG/Q9A!H{EwN}s׿憒* -޳Gt>l>g JzށBլ؇*=㻦vD*(RRuS)Ѻx8$$j|3J.qn!@֒b8;)-ϣڅ=h_h )Kh!0kFvvXp$(Lؽq7y֋+SS5mW_gCG6[$Glˮ5t>/o:з>_\{<0;^hCbfK4Imi @0mA@^johdǠε ~@ 7Lb<%]]n:,Z"e9V3v˨UI_&4 $_w;Ns- tr7…1 (*dԀ @>8|jܼ4Yc\Ku)I_wX>?nֵ+RےΩ,N~a|AzG1u>^}y c@aTeG "`S gJ2zv?eɹ3f/c= B*GBaEdrD{"fktMˆs'B@fg\hGPƉ d[ݲywoùI{,.ChRGMB+5>͗o.̓? j׆iR3{#m?gb)\'iscJ%r:Գ2ݞn7<,j'ӻ&~!kߧ0T4~ãQG89D_ns2esN<39&ӇcӲjnčńu= 0NvOSRpafnm 9e^5ׂa|[4; ^t*q[R!aNKl)rtaQܳ-"'ҁ tc 7?&He763OզوZj3b=ҧ~6>I-+vR&~5Qej*S:Q0t@T# !-s#Uu.bFA }mJ ܣԟ:E'H*W7۔VubNoo+w":я318Ι[887+H*'^Y9K#w2);!*,Vt.`Q^L[l i:7R9T?^=8ܾ~S1q~xRvX nKa۱/?sg_{f\Ծ9jekP/N rp:)~~f7##6o?![_4(\zG!X{.EU5iuUL_٦}2{)I8L>;[uNRpoBFumV?Ľf ;Gg?,P<$a`g mg|;3D[.r@LpI(@f}e*_%ښm5$yCMoU=F:F i㞸>A?Td6֔ѯXP} ef=]H=TOi"( N#3VsL6)qTU0T|dPaM\υ]DO\mu$?s$)*oGv"[Y@#ONpKڅuu']+Q7P쑸T5 wa$;JUBqG\#ҥ}Ly_1p82A04-Yv Rav(B$P-R]4TMy[ Ԃ<]N<6^m$9 KCvxofz(!Q]rko:2Wķ]SM8#@(U(( cQ1>#;sTd;9Q8i¸;w`\hc]Tw2g( \ JH$+J\ - \c0$,\U)#3e )V]DgzpSb@y1>oؓl&N\  41u9?D-S_y"_9[C~q0Te?5"$U^cש+[v>*íMm7_gXh|<`\0 y#Wb\k&ڰI K\R)Ǩa: (9JjMuCBa?R@F@S)0&yc~J8@*u#K`v*=Z@ _u61XL0ә \7ɀ];$$| U+& Q8n{V#i0~nPi>k2 uEox-ꓡq%883/h WL´S/H]'F 'v$&Jo;Jwm=ʵC')ŠBfChfk65h$z2 f{03Qu\GZ}zfyWLc40;̪3TTh%6# m?)*i3iˊ-w|y"6qe"6Ҩm7UD]s/ "#٣=𢶕%$=]f/̮̽|/CVdm|~ ;nAv,XUw~H#ߒE"-ЈA! ;ֻ*T6MNS=Q!Q <+>"V٠U)ÐN1 LSI|/ L̆!듯^p𬵄2|-b8H zcjģ -+I̥Hs#Bd8*{w8bVc/m?F8 >.Ucފ54={xɢ~S 6Ǧgu~r`rsqrh%}sc,ַ#.5rmbhdOΗB͐V趩aִ/n 齝T]pn{`J ]I)i[.f  H'H^"{)֘\>Ϝ>z>h1xWI|T.Ʊ_^΢ ?B9*6hrju82/>YjνR]AK'!ۘ"gKi${C#Lj؊|Ln}*FIiu rJ5;1B^yIVPeS0y[4Q8h?}R奄I2SlVfS;[-C7qJgJěp#u*> WNV{*aϝyxD~^)߈f-º__[ADS*9Я5GJO4g%Q峩3iyƳ;AKM6GL3g3198d:isI 8xf&T}aYoYlBX l6>0 pD6bG`m*i k2NSWPH Krq)f4<&qL6h ]ZJ{ҁ 9+HZCNCJLJcП_GIiʯlIApӡ&梊hŠ@sbz%٘4ECݽ.ѷ>#1vۺG#@c'u`I!M WRhS*g%SBs!8HA:̓%iК( ҏm9Hd{D @e.^zL'.05q.|]=^pn֭sM-bRV~Tq Svit9u"tz7P(.d o8YkGbE?QˍH|.No$ZITka{ب8]saLHVHaI,\9xL0 K&9=7fZ3ToPmEo=]4Td{x (nALqBM9#ʌ\1c-8@~UT @fxKYIh_G-vQͦzId"1DTLN8)bkѷj7$egV[4w#uD'r3-Җͦ.` .|\E1`XN~Hclяc_|?jc,*]Ź:J:3GrCr-x*t阛9_>m| XU/V8s\$mrگK]yypEpϫf4 ͹F2y6X '/ih,ihS6OI_t"{8k7\ɢNVYWKivb\Wąhtpf (AA ׺b"^|{Du簴1RRq:{v9yk-AF⡰+6 X`ҭDe9uHefev}rAxu]FIy a3AWa /P]M Rjw. :TmN@@?LnKxBpd%(:߅5f'-=^׉y(TeDNmy&l;  fIqF˸S@Jר廽nwF%'@b$`i,L<x>1n!o c$w D<$!!u EoZr@3g͜fAf?#zl.`ьR3" p=6``%U]<A&?X.\AlfѪ',1&kH׭C-Ҏ%r7W%L{G۾v\/+Zh!̍IH-=5׼wysݗأjCyدlk/VHCg15m=8Cib#ċ0L^2TNff(;M??փPLeaUk\/rGW dnSӮ5tiiRu,M;—mS,~. ;昑F.0iZ-6(Gf*9  P NlM *mw3G#jǞ@/Ql$SN{{?915iPM>Rt! Mg=qUa&cKA:G'ynu .b/W k,`ėT[Z0Sr*`c+jkf#tyF^}5Ͷl~Lh):3 ʂrt>[{.N|g+/jVo&H[Yl(wȕ&E6jJ I'9qa6QrFŻ~ =$Q̀9_z+V]C>9?U#yFYVaHغ0Q #uFEwxYﮏ mA6BFPY]+xYAMjiJ\T.Ip@KDP u&A|:ōAv+n\X oKwYmݡ(gV\-ȘؠTIpOLKLJ $<(x~VS@cHԃyL\_2G,xT7tCXTf`A ي#1+*gˠ7R=W  y!T$uR#s@aShT( 8A=(+Ox1f/&λJ#?FWNC~/Zj R{a. U|M.vyT퉆c&xXpl2nȝIe=_&ٖz RGn.bDXϯLM_006NGp/z !b ە0:2\ǭN€֛!|]Om,yص_!kCoK+0"cna.=EقHo%"Ր*kSJm4ǨqTIv-=muD|c ܢ*9M"Jt3">Sث7^ jTo=[ .$aaۿ$nO<>nj]:6(ng"->paa4Mt^G)UvynIz3BCv=K[|uz\z6KSá' 9}z6Kμ:&tͽnT7/2zZX Rq06)Q㙋IH#Q$*nGleC8ާ7/G!gu6chvw/Čs8\<;8ByF"M:QWXqk=! gZ$1!EJc33>ъxJEwqK÷/ |r9I*~1e^//+mE=ڃh 3VZ^#%G>:vzxga5zQ$8n+C ˨&Ka^+{qV 0#C--aCQqM?Q`Y^Bil@\hizM ^Úosj| *Mr!D|rQ䖐l=2RuTbx#{ԧ\$oO 7f9P7@[y-61!>ߔ0GS3Nʂb!b6*]ae5*AtybI tr[/p:PuIiבJnIh r%橰cm:~p4p>ӻ n7Z~lWМr _&Cx6f#o3KBxn{h%P/S&dEz(UB_ܢA㍏{ͫwTaYF^&KFӦu 76Si˫E _9 EEpfmSxk":( O@bL^,rl}۬5Jl!r+`K$+ ˑ`Ǵ4xЊq=XYJx.IWb b-d<`&G 3^YU_+<0L<֬ p(i٣HDD.a˧΁Ff&bR?|":߱3gK`<;4o K V- sC<԰jwWs<ֱ}w)p>t4EUA\@73ӕ U.bۅa HE-+HkںԦ,%_o0Vo(*BLJuj>k&73GtѢhT<.e$ op6>c#x|/4}pC[NgJ Ua1w-MzEnB]xe=e|.h۟Ľd$qƐ08C7 tUu!c)^ jܔ}Q Z F$r/Wa^rعP^4|`WCCXnUu18"CӚdw mYo ys޹ho}#p^ت*=aIQ0B:G@ƒ[qn8D%a\֋7 1 A,~!g13<ܘD{K4#=d5[`)fHUGAAЅ=''=Ac_@ YCR(E4 j1P{hgZaq$¡v+>(߰-n[-p:JAQ|W|yO= ٤!_`&5 "_ Au¼ωDhWbo׵ҙu]Ý']L RGM2a>7!*V1 Ǫ܊FM.art"=ǻDieI_k rUavf3idp 'l\Ѷƃ*ٺ 9b1rcCd 62,%2^Tʂ^Cӥqq3h},06^ݎ(`cI z;f̍RbHddOIа1ǂ_6XT?ºQ6 d9 ŏ9*L-i$fuTS Q7%&%qMsXx mg0_ᚉڥ\W e2Xߒ-bl#*ռ&½PsOcmc_zliE6BmxBB(>:x:3倌#CIւfΞ ;hHdDGPTꍚx{:viUʉ2`ׅhP,0ɢ4уK釩{iLhb0M?!■x1ݓoO,=`gc l -;ǟLO?=Y!LOߐsuj^H|_G6'xcF:aJB74(y|-X+^}6$[q}5.})BZ͢n + SZQH, aWXՏC8;=(£44N=HM힗wMK^(e\}o',L7w.ǧ{=./ aA_S4V-:iJW6ɩ ka ~I=.~&G i`Ֆyz\=Xr9awj.m\ǮݭYPZIXJMPcv-o չ}WkSr| ƒ!S{vOe4ܜ-yB-@34_Hfi@SfVq%5djE^cbjeU"^a=:N>gZaj>:c?VWcycq6)_Ÿki:B1Hf*i Q[aK2`bBTއKa<`I.Xv<3dN:1YqU[q7qPe7Lc+G;B+RA^$ڴ†1UEøLt?¢*ą8wOHwh$Mz4aYOj:dtQ6- Xun2>s8Jhe۲$ ^|^ bQ}e]h<.\ydz"81u#TkӺzղao>iFz?. UX[#8J@X{' L =.bʡQҤb7O@_hp;|BY}2HgKhcQ,heA%Vb+ sS=mFTFgC_P̅:11%Ӊ.{/%O0⺌3.ǸųxEU# ++z.hveG<ؙɪhz>=6am1qJyx %Z'__]pz`uO$YJNJU{279&ՃFF;TÐ( E(7q܈TfPu I,3I2_(B 0WaIk,NX(,6L'Pf..9Oâ D{?C3P[%,jκr6ED'<>ˇ=瑯H GGJV7}Xu"Ť_J Icooxmurj3cQ iYHV@ %W2Ģ Mv<9"Яv˚N|bܠ|q'83 :qJ-0,-_^{4~B,gF aq'd=^~'FUS¿!s{v#1ogYkKEz㣠;o{sz.?U0T_EB0U_X78'-wTO%SI5OOg^:}Q 9ZѨ b$ ;O=^Zj>Wɛ?B(t0z,`=g=xC]lkͮ3Cpm%-l s]E(}j{6=RMy]17cW4l_uV/2!<Ǻp6'%yF ?%덣A n_5{¯Vվ./́ߛjɬHg:u\R.-݅K6XUZtsLy|7$(}$y"<&"|u9%>89!?耹RWoHF }7 'ǁNk Ƚ1F`Mkѵ"& aա7ƅsٌ''a$|i'.gj rg*җ7UH= mǙ`ȳbƅu| w/ cAlVrĒnj 㑼/:{fenǵVE8?1L֧mPTD!燣hDzIXl6xCIx )P6P?QB% q:~D$.I~u1~_2 oJ_E V]m(poya~(|È!^}͒/\aE8LӤ8.i3Uq!XJ7&yes G3WXč}(pz '"4\ٷh-KS6CB/ T͔1%IPR$ٻVC9]Dr?XIV)ԙ5Ӧ] Z^H4Q*KwoWujn^ɺ'$+TiޮlZu(6G3K(OЂgC iLACe`g=lکNOKO&6Z6Vƿ~HKOVy:;Y?wG Pi9YXiXX8hYY?sv4u25qt[|$o5MO̬ ,, 0'{&fZFeYX'sYG3?+Fdm3ߋ;X˫IsiYΎlX%ua+MWg#Ĩc~ʏ౎m_<@;, ?$pP,_A.ng))HfJq bՕXg29 ]Fݑ7oWEҀ磷O.̱2ϥg:7]m]mn?/nh.}IJk;Z߷ӽ-84Oc >0o{=< ueho ,ۙ5&l&2C)y H{P_tsyS_ĈQKx8Y~xƜSJR]fJnW]Ք]#N~n(a琨R /u?'\)D^1,M&@6l2U*R־yyraJsjlxߺO8K*<O0cSht*]OU>+uAud eC,08пqBI\R|Ғfa;VKNvv9#t"h4$ѱFtos@f$.; B" VvnF/-^(:}-ji`jpM8]灄^`*(h?!-O kX<]Bb,f S2kx23fmV܆k>C;>yW>X\iBU7ZplpRTê )Lܫ@ܯ|9_Vʡ<ЊS\G n>ӗeN5o,Uv.RDTA-B%.mwU\Jx'AET*8[8ҭ}DzD i"E8}N-q?5 )nPi]Y;bwaw`ʿfH٢4槇qi8la LGWl>']>-섯CV̝$t=tĶ+ٞOaɛ5$*G 8P,0:bY/yoUA]P?bv~]lh\A҄<d{̠嵞^K)vs<74k>W΄@|NC.$CM$cRpAgbdAdBհz*|ܰ$:(0s(SFljJtiIy7JG@߾ 8.SiX&OF ṽ%[s];GcN4`;W]6PÚϠD^A]6g%q(F/Cs݆7V0f)zTP#6+ 5 3?F>%iW%gG \CAu Jm!AKbWIMȏ|F3 ] Uȍ|tˍFK&wxonRe+Uԕ+gra~UaI~0sR=LZXtFUn`cO> TpK4xtTJlc׻ L԰lzR'@)GHA[lq/_uFe̯_T*k:k?Mw:<;@֡WM>};w_§L-8MRtxߓ{*4DA5BׄŒ&lw KVt9yrmD E\3Ta gM9y%-:NqT(|='jXX(PB5^@GQ>>>z3}Mq0pc=?wC3rnhq>'l)?9 Ĵ',՝g9wU8@YGD8CR$m*j3&/е0SyeJG/PZ6ı`ؚ\9?,u($xpn{˅-${{SIhVNň&C}J@]V,:@vQ%vџDQW$9ߤH(%玓=wִ|H [ffCafCaf('E& /΂JR, ,`Zfv66eDҘ>4hAyf?]o3gee f1?:`b`& ?gf}T׵~hhD!fKXOO?8d`cQslF[)ՒcM/*KIpڊ 2Ҁ~?:@&r;L#^jt4a<Eaa荘z;W .h_aGǫq,{飥D䠦g=`S^eZgGCxLْNW;gTyOG.Fa1\}}[ /OIn /iS YiM;qI.xlV~Mr WG@?/9 ?wٕcMNdDiiK)Jx@k!_/x;.xZRQ{QP2ue A9b-5T1r $V v.VeFq#MA.~& 4TA0oFVyڴ"Ɠ̦J^6P\sI֤ZbIL99mp-I_ NmT'MY6AZ2`ؽc^vC .&kZ9VXD$a\SJ>co:AdƢXƔX+Jx,$p] $7Kx);6H l,BNlV/ʖ Cc%ab_9f}On^dψId5<9@d6i|.u$P uaE.X{XshQ'Ov{ Puv`}ܜn.WXF'?r53Xb0 BTlƜ,=(ouZ ZCp[WqJ,[+2oal#{.bWsQλ+Lm}(~0^.r`1>K\˂Gm? yՂlh1JS++J9iG` ڱiŸե8>L,踓+WyR$Nt&WvVMGeHoi>L (;Л -ՁV&ıs3P*Z2)0n_|VD H;I)Ø71V4 sk4]jMx 況xm@g3AC\bQ<ѥgRFe5Q LhGյpGa8l \ 6\@ )R'h_.?M&sLUɚiT]t8^bƯ:>#yiNĹ2t9`p}~-XQ+{4O ~~ S)s ; RGݳR8)k̑[)g VdgVc c~T&)r[k-X4v]Jd(זE ^ B0.Q!bl7RW!8Gs#8C~:!S__eśfD}TãVIM:J5Ǥg9HjeᱹQߗgyeE`AaX{:j2%%|QE.@WڣȦ\d5r&IE"DB60t?ex{j0Vbۄ50!Q}kֵWw׽7W~Ds)NGZ*nm%?c|z3%ҏs`V{#,?~\78Jd/z8wƒ7㳜53of 򋙙PeoIWq@:|?uѸ+ saxRIS1;0c:1MEPR(B S$6űõ(5|eY,`g3kdB=geg{e_`F ?q" 9eu_$Oky0ҳ !y96^4e ](#>sC0WsyeC'oI[Z_@~+B?4dvt5wv9u0EIJޥh>$8\M7~;1u ?Q9,qr{u<^ 64%٭U.m#& ħvbbJ.i"K5[ҳl:iF9_jO B9s<{)%UnӴ7J|_3^\bgVX XCϾrff-ꓵ^d8FwPR&=&$VSvIE353_DU1;n%B [_ OcRV*/r` ́ \Aw7VVW Gڥ2v@zĐzoj*Y}r(ɸm-7! !~ `*f4 .Zsd#uUZ*8ԝxQdKa.۸XtףyQOPG!OvԂ8BD 'Cq֮b{_%Khs=ŀɫ1Rc!Z04hu+Uol 9hyC4>W.zPT HpITL{LYń/UIf㪵}v]1;WU̢ŭZi0Qv~&ԐIJ4ɕVJl %A;8gJbN4&xn.(4m2xCpj>WJ/чi9Nʡte1g4M$dX k.3uh C0I 5( DxsͶZ(=S8U;n~=z0K `uB7_FV: %d~&FlntƐdn[ e6B6+JK"P;p㎢%s[*lgptyFk̆r/qPp5 M92c]B,YOۧӰ163r`$hPs7 W1yL]ȝ5G(#4H%yYR+c& h5ʓ e4x]35O&.K`,÷| بe47CnG\~wwu>R.ǕlfL SXү# .PG2xw?oWJg|W.3DY ]ĵ^ۥĦ{{.@{UzHVvoQ,3N*P1)4/wi ReE&*W)K-߉Cy$ٴn$/*8wϏ0i6ޤ +ت9};հuzl5t'1"]`V8'u%ʈ؟lwq#;Gjg7MhşRX²!eoIa?Ig`fW`;-+sPeo̠k9" p-%HdغJ*G 4CPPi&pv~uwJ7cFk@Aץ&*aP3RQ|$~>Lj 8ZxN`}mOUÖ7]jDW~1v #3##jsw' W'v0+jNuKU;;Mٶbi#CY:'sh3qW-V'fU}8N@':7 RҭW5 ?OAAG x $fY_9o|V<[kZ|Rx3@hG쓲 ChR", шWn,.XbX EY]5w |C DDqE9yMtyѝQūQnΛwkOF= K0g&5lnPbe66I%\J~j:B+]z<@A|8%j9FMlgxG6)*HBC^+8Ӯ4]7D( cXGo nM2zNAK(%6vS${7P |,cimzYġ7vns"a 岭Ӳm~Ry`kFL]n3G 4h!.LT`i5&X}&Vƶ%݊oIO]G{=&[6syWO~Ż78r'3quϓ7Ve$+Y_׿8ge{Qp7?0; 'yn&z Lu D#KS[]Q%2T?PLҐ]alE~w AopAi<6vhBj4LΒn֡7!4Z4NvVNW>omUb6i<]ܥE )[l+ՃsSZ8:iֻ4UTrk؃w3LD}j>5@۔;p-KSe'5E~HoE0+p)peo0/EOy <ӿ*g7cfPmy#h `bH&\VxIIsTȬ1>=х#MƆ&QM$i7t{gMױv&/W)%* &Τ@*0x\CaFE'>/w\mh`kWƭq_WMּ"gr2$^8`u9)ʩCa4]3{2:\NB֕YqqwN,MA +Ae=14W{^Q<{ξ>2_o |ڣ3T|7vQeQ!ŢQ!vp.e>ăfkS: 'ؒE`'DF@=ҨBFh^Enΐ.sFmR e}g;E+kʨ<^ݴ{Y>:wo&rk24gWpyBjd4LL{kwci1=*`q1ZX7~q#ڨy^3\aH/=-:NEcV*rݳ;O%7ܝj"h Ŋ"6Vz~YI\F?pY}.?Rr`>W!w v^s)qiS5'(ɻ,H<:jP : HRzbr:<`3yF0v_Eyk8o v'Z 0W[R1+V'+f֓ŋ OŰ3 3Vfo㻃{_-dg \UH" *UAAo  OoǞ  ^Zk#yv2=&k n Z>k>ŐC"̻֕5[Bd j\D{ׂ߫*g9#x"[*SJ `XearFqDwhm}ۺ&^1T$"> .&">nqX C !|YHfI}X$lmqj/o _iD;ojbҐay ksXXF a!P@/@@9#X>(v(yd,y>dϹ'Pq{vʰuD"~<8$cw4]SoDduw纆ACِ;Q$جxjqIj`k⦋pS:8-13F{4g3`SFr~,j4@vhC}>] pHU :l7J׮Ox{^F6zAdADJƶ%O2"r?l^gcqijmbr=# 3-#na?3221J_-ۿ:[ah4t߲w}lrY#)/ =@Ft{G"BBh!Eǟ,vD:^M?K<gH47 ,2f]ץ2lz~dT!7w-91i4.b2wuýë;R;T( Hz{?&\o{{w׻+WLϓN G[j۟:1}Qg-|֐+_!3km65{jrj߷X9!SEOWmޡN @m쮸" u 'JG)bD 422w6T::Yqnqe 0lc(@ߖXygJ7=yKK_]]X{hڻ7 k` YP_ݴB t- 7Qy-=)]|`sj7WwYaαZq@vJFqlP6=`9b ZԶyA mQc~:¹-!(0>#Pd=m~ %(J^>sS E= ^j!gI!ScRͱJhJ[,3c ԫ8jkJҘz9!35窎hYZLRIˉޞ4r#7S> (oL':E(jh3䪖fN1měKFsM?OB2+!PCV 5xl9+Wnmi0]^6/sŝqDX4 {(>NrYgW L:AD+kUX9,|EPQhh$+m#8Gv[:PH@sVMx~37nfea' !UX [V& @+Eޕ{m:♮`Xs0Cɥe}?t۱VÃf{wkз] E/QP T8qbvp\"ZQAh\Rp/\ b}_XER ~R28\Io„@iE勍u@a ~%fܚw#J }ۄYiLAISzc$rm?r}oʈE;eL:k~&9Z0q(֢;2fk   Ӹ`ա+0/#xK D({ۨ/܆"GH5h?DM5u ,e)O{dqKdQsէ}D|6,++ֳNMOe.א)Z<|\L4vCi5d62x (iy1R$jS c,+ D7% 44e=c*EUy)J/"/>w*=`7-d 4M(<F;ˮAx.j[İ_Hg XO3_Xq )zAumKU>vIaz@`N8s<a#' q[BA{x0K؉ M$!FJ S4 s,hٌOΠ! Bw+TWŤX+@w9cl8j2/j8Zvl2Z2UP{3 IEz t wdxa3ӑv$*a^=\E.q I3 *LMq!I} op_HDQ<- cN[JNʡ$>ŠkcxBl~VA#3 & & d&uÒyk?蕁S~Td! qp۬t"Z_i('|صEf >Nُ,tW1qtwe4b64[mNyE\RD${?Ȕ<5H^|!hNK#钏lv&/ZD o =w߁6o .<pEeŘk÷:z}-* G cIM8%  5V!\][NNs ;J0$%Tb~o/wE>OfZg–wvuM.%WiyTE*c m=__wq:oK|na eO#t}>l_ID\_0 ;ݏ\^l~l-]X;|8qk6tD760FX͘yf,oOi^>?*盻O+EQH*3mfE)=ߧ3{uno&뭔U}iļJt_'``,dsݙ0܄l"y-Wm0Y'&*cAɭ玺6u\ 76zWa2sSj&w'cH[.‚AN0m̌׻$Qɪ)7 RJ8ZJN&M5Hj^}qTW7MK֨yH*kL_*G6aY&- pCQw/fAQėkeU;nXH2 Muz1NJ݀e!7ґ8`ޤ¢p 8-)hA>LEށ`e2> i|Nǒ%_!?\;F>ۯ9=RZBhk,Lh+Y3Y, PB;Oe6vP%Z}=)'白QrLK\KXB`?&$ǸT Uzn/H1\4){ H h~MT.3mFn2?XW\˵[y1{m"~/ D@>T%i_ O*#[d$ Qta[4 KX^LD3u9O^s8dO s."'`X70J[s!C^ ͥc0&Dn֤lx I}[,Z@Z@3[!}Wua-1ukT(>o+ }: jGP7FvH^%{NX-JOMF/J$:!E̟_dXnv+d;.44K.OnHr?aZZK;םp?j(eHtGC&,BKLz; JERʽ3Ҳ** b!vF/VZ .jw ViXnXЖ [ԑ BQl`4̥1Tp\,>8Byڥ<#:BXtkmE@W$9(PuEW~R1p Й+_`s(׺' vyFSR w^ݗA.L&1Y%AOz36>]„vMd㲚.d3<Ȯbx&̳`sEĎ}@EiA L(qK\otͰ )ϿҬ-zлkHd2Cգ9Lhr 9aU{}'?<d& egɭ}*S|.YPq ^2C~{= סg>)YEE md#5FSP*3C7zw 6")ІK}lR!sߔnZJ/oU 1/wOz?>(Jy>x餉'Ty&mk`3p/mNIt&tr}?ش|e'i=ŧM$0] L5!W4qydyC0!}S8%\O2:q,jwB`CZ(BѬ/=f8>&v.ز6,Ny',JPwnq)ǥ9 ߄^ƪL1ܨNT$.5)qf1.jtдQ;IF88Xդ})29ЯÙ'\:dL :vIdj Q j.S?t.G //e&x>tn1VCTuK?Fxo!c.F/_12ҳr4h8ՐՑu99X8[Z{Mom<J&ܟXhN7oߕ #6XQ}kf Iؚ]W\xq#*GxÉ{3,ɒ@|ټn&-x2"?6 Dўu`aF6 S0jU>^8Eq͟kƻxwx3ƫӣ G.bkX ml0z]zL7~{滱v@X %*lŹc;g#*K.Kmd,]PP_ryDSgV&hfeP uY5;9mP%}{]bjB)NUF.aeh]b]ܼ cSqe0[Mn#GzKu{Ă|V΅\5K}Aʹlswʍ-ٰ`R=]=u 0\"c2KM!ńE:&] b Z]Y$ ,Ci$U'Ǔzep,XC,,V:r!9EWl)vs7vDM*R=tz L |86LɽdFZQ@\ZXKG1#Fa2䉵@G=Sx9+le&R01L*C-9 L~7vNH *VPP(X(:3-\\=և03NlY.Ʋ s_+Jg+tH"KTix(y@heL+?ޅ{;ƚlo.c,AG&Ydڰb`T෫^6 Ͱͨ&㗦,],=rlvb=?+?o!}7/` :vw߷Bd>@}3)x[2>OG)}c ? kqrb^o#5_0BY5r1jЧeicj_ŘRG%grU7EU?eJic6Q0GEL_QVe4ڪ6yH'Mb;~l6uYukG|muʆ 1Cn{mhn֣_Gwv栔jX{JՄXL*ՓJ3U;CQ7*8g7~ ׋i¼ 얬҄i(R1ݮȄ*2yT¼_uccG=P~!6GX1xNKaxu{'3Y.I16ړ'#l9il,*SVER'P* aiH{#|E//4Ȭ2cݻKj)dS]d-NQ2V/̿5 d bBs":MFCž ( mMb 2_y'׹@bB%lwXJC._'${GT퉗rftRr_bK݈ m1K .OUGvCXh1>~R(cMs+7hI 1h!p{>+ಊWsDtϿ>n;f؉;F}bܓH^]7/3-5DNsx1>P ($X(Y;c"2IS/2,mY`-8 t7MCpI`! wn-[ Y{Γwg7̚EurUʥv|&eՍB|>*&\Gv<[J3|;q!Eg}Q[}lk GSF0Ka:(8, SfGk~:g F # *-dvW_J"ѷU|D lƚG%Ūl+f'H%DloE/gs(*?tۦs!LJu]$ƚtp^j;{ kH  #ä]9"ʼnrP'Ja|CU!q%Op(n30/ydAr Ш[P`P%_etRIG?.)ߤ>|%PxCX;l^$eǩPd=wƿ@8@8p55kkzpp5kkkk׀7A'@T > ܏hc;mGZy~ohsrPA@ Epl0opbއpp<@*0>7x4*?U\C oA<77GwCB_r@\`(գG/C <>p@_ik.ßkA!T\e 7878У;gK] }mw_D׆\<;B`I 'Pko%]Q 0q@@Tpln@x8hѳ27еԶ[bD_oAq?NP=+F_C?*T@8>* \'PTl-@ Q9~wf4`?P k+ n^7DX<_ɠԺ06o.Ooqj!oG~h@nީT&-c:mݣrzHVsz?gyU>@-hn4f/+!bFZ{ ދ9r/齚7۪^zu^vWh^~S|NHzba ?`:RDm=_< bp&휴/<  lAj0nWs!Ngl!xnY',gqkq9 ^vFþo(/S,,H Օ8l>6_2q܉vrȺ7P7S g6\UrhcQ.7-o˼7Yj}vy%z~JΪNGU!,C|,WnO$UOzwOTal lQ7GxWA>"7%}uauz]w$.wd_u&ʀ#ʼn$D)Jn%tT2З|s״47}o_d_)xK#m+ r`nL60h"jU6EGK1(-nMZVs)4)c_Ƒq+oH {'u&‰{h˪v"zwWqVHFv)HGDMzjx>f& K#][ YR?F_y1"Hj8iyeҩ̷jtvf3/g+>]'+se/;j d:ip+8_01T-k ;V{󹍽P qeAoGaDe?'*DW|AyYД(;aQL]OxZضvr!fboqZ}ܦAz\}|1;1Fp,,7]%rŸOs}yckNjCĕ}6רG#1 t!ft%HA K~Ipzf *DCE5G&B,8Mc.N]hOL8-JEgtO {=W >E?0ϐ&"L4gSzr}U sXh'|ߏ>߽Bc7s+$ |j7 o3NCo2 ix2W3%r?JzۄO$5ef˘?=o@{6|nڿ\6*ئ?<m٠`g)[.tVhDKm8t>peϏ+78Xp`6lL:+f{(JFL?P &|:j(Yno]o `I;9Όl< "lB gSsј9P7jP h"/YĦt4 m#$d^EQU?m &9Y{m}o P"H -{6fݐA;uº1"i(wOI&3h "GE,"*Y۩ꓗr㉵Gި5݃ 3FɣO lV9󗒸}lRhj ܺV>nCU5k . 8@fU믫Ζ^pyx?($ykk3=GZ Ѯ22%8KkEiMj^UrX9s tq94+23ݎaľ@kzdzSFb7ϋ&\&Bc=IpaŁsleShz(\t$BdtXׄPIeyz)?fw<!iSw}U( o]u\QLm+(bo {JbD5Oda %oS[DC2dj,o\1|n{ZX xʌ>n{9л1JVʈjǟ]AؙNS'RΗ@T΀'߹"eC]ܙIvG#:ogaEP25MP[`oiW"b=~*tj+nG^NJTX cf?חvk Wyr^ۣssYd_E,T2Ro?Un!p8p@'.%G^?h%i8ۘ‡4eGbp179|䋴e6cJ\T5ubo o,19ȩ*:| L~`3XKE.,$ :ZL1γ ~GV?NMDO.bǣ>CMr [SEu e&m_y|wyvvvvvkkrJo92'zA~V'#p.N* =BK.n##jO5h9e@Oܐ YSK;[G[m)jXƢ1s=Zv.Rss89!?Q@V7 @ᄀ= px5|@ Bÿps{-?[T`rW@ T8Ig8ј  Y_i7@  qR=.?M@9x[NqAP xѯ p/R<7 sLP濷U!ףʎmOeGBM syv?m;QI˭(v%c(;FL@ il6aXN)f""@]bbO%@,CƷP+aRFM+懛խSHoN,pwx}5Vcg샃a椛Ȕfts[nGC[j_hJ`oB] x*Tc=]hM7k4<۵Vݝ[,#蜻jxis BκEEo*Y=I012"z ?~:LQ7sb!SǩW"R7i¥ɪΞ؜]J}멻YC>DBB4A!h1C4HqCcvj1)7=ʏX+>J,K# NFѓ~^`i%7*\Uu{z% l5k%CśʦiBdvf&kez ~2·dNG #s;.z5 =v/}ϻ5xцN1_#yIjϠ~`Q!f$kbh\-d`2}OS. V@mwDuaA!3i&u7f;̍ u\k!DdbJkqYt7S2~ygq>amqR62z{Y+ ~ÙטcD^ T Qwnd!Lyb7'cο9[;. j4Ln^YS5ܶW_(Wwn D߬O#U/LrNfh6ԏkzWplGdޭt/RSt-lUu H}i|!?vh4_~# %ا]joMm3wMiO,X82aӻ9G̼'M\xٌs nݴC |bnO ӰL9$9v0OT#pMjaLI'MUnGA$2hH%5%JH3}"ub7up-+Uuǽ1T假Q}rUۑ;b%cvg?Gl=\mцC$5O[}7x^{F=>˓Qٽqp/ {N.p.&Ȭ.̎Hn@ p%Ge_eF ԙ|7 $ɣ?N̽}^ʄ?ćbI0$=AvU<ǰ1g {Aɇnv7 F`QH8Ib[䳢㍊ 毀oa0r@ gٚ; Nw% \C@& : 'Ŗ Pov;y0՝:Ǡo%#s9 g˚x%1} 7ۨ \0u vI̢ !fa{E_/΍c/e0,wġ, 8>߆OQeWga7$tHZ:tn2D_&ÐjFɳ3T1~AxffY/]~5O_ǥ26qSZ%ugz^xen[{cFCmdL-xLѰk:OT01 [jo+ib}4:fѾ'^Q56Vl.{%MZ|VuD$_[\^v޼< mNx.[Psa:p^T67VVFw3*6^hxoۈTNE^@3،FLfz3[!M-ef$-lcE*IP~s"{lybDƍMh*ocVR aEi^iH%H]N"IfIB^!a=vŠXdz#(뎙Trfkb|o NGe0L5xo!p1ۤ;2 1j9`g؞Ig&Gw`?9L!N81àoE_fÜ˧C?ҌF"AR/8H{T7{J !g}=쎔~(KZ!6粊h `τe!ݫi<1HTțpt.E/pN(46Lά?`' JGOWG4r \&qE ʱ{f&aFb_Ň?Pִd87-\Of]}2ODqBf".'tɏ~lld؝{p9E b"Fʱ}gAԋnZL,ٻCo9E2zWJxdIPF }t&A⋇\Ǧ]3= eBF'̫9\X ?FOз\b!֑z' ObZkQHᡟu9Qa5xK fDY āa[Ӹưڅ7E"t5\|F&RˮJ7?޴[/|+79O'@ŘoӗJGq <?5^a0a$~$>q`T( bhw&dYw\饈zT^z?\0B %ýY[Kc/-1ygX⏀4$x+@ߥ*C /q.mw(8-CLZfeUoOt4_0Zpcbw8,߁v7f&;% bgqCņWpo0Zql-I/ e:mkT|$<|RC: Ol[y9NŢϴn9)As9ju+ߤ8W*'B'A~=[ UkժW@([C|Z˗&4Վ"¬q&n/d`b}.*3 DE.JxpuQL]V@]n>hzlZ<`ÜV9kO_`.~]M*]?O ҽKo>bjK5U7Ge[0}н+ymrLƊ~ z-[4fj )< !Qwe,9WB~WH!- cf kĆ/|}5&`@ ȲEEJ:ŹN߰;) 61G` z5$TPAtfuH(q9uK:\kBWrj_ˠ!fNx5Hc8&y!&ӊ<&*[r/h"M=] 3;Sڬc唐=iYuT OSr ]ԭFOx7%$:^]i{ʮYK6i Oې؋7H , SwpE(an?,,|ʏUdyi_gb'olQ5 G3@\]`qONa w;*OU^9?ynC_~Qs^ǕڂnֳA$-wQ MP\czYteg LG !xɆ }n/҆=w*GֵǍ_Bx%Vj706]? )W)q>e +o7 {^֗Yiq9lFgQJd'rixvǒ/B!EtkL7}7.\+D/MИ ̂0V5 %@> -4=14kB7"NSﲝgh vm "ĦTx5 N{uPp5A{$DxvSl$ e!Nm“u*7l׬_8W6OqH8_$/ +!WB<_/`Pw7+M @'q?*RqspC?*g"[ wtxG= Ep<Uy(g7{47C. 'Q1Opsr'x)p$ _7:@NN* y [OrC~^ggш\r #YWGr'GqBg?YWޝ ǼG%W-5dmuĥwq asѺg־ܳA0=k|DZ"[!=`h{v9 3U>˝*`%"ooN%Qn͋Kr&NJ߼ܶZnq8<A.OڛlnOGΆ앻z"НN'*]셾7j׺wu*d#q.\z.͙fZlT0z`]lBNNR`fRL}ӼVeD43jJXK<ijo*Ԋ Sl6SB/j&%dȨ\^o/T!fjjOI6֚ܖ-$|뛳bom_EK㎛MJgj7?e.o@j *ͅ8zrOQR\l ӋŭJ2KxD l&s8ԧ< C[R%D @M蝖(TL6R`* *:iJZ"#!t&sX>涞۬,rĵoiE3/'P1.PWP;-_?^waV#<b'7=VUi ;3cVZi;OA-],=NL9sbXb0sb9fF= KFIjح)՘XY%N$1[kv5}7=Re1:G7˦$e2R=Re=?,4aaH_J;I-f)[OKm !G/b'o(OW|Jh7psg<1FbfsB^ׂ b%+=34Bj x [KDAA>|t&11o#$XSu<_T w. }A8IbhuUЉC:+ZB))L*aк#P[\UXL 7HhRҩʡARsFuu:6 'C?X31EisfgQ' 䎃T+ l2"8n3{3Sߜ\):W3Sf.}`Xר++Å=D> Gś1R %Cp6A4u⩜Y awGM'pVgA| %yUv+ftg]ɯ5E0Rh)B1hsǦ) k®~>֛zq.aٹDj{t"-H(5&mZtMd0yh|Sŝȥ5+%8ӁD/"|GƋQ;Pkw=~5h[%$K׷;;?B8x*IsСAmi~IvtgRRЈf%, ( d3[`t9i6}^E3knikޢݫblļ3V!'uې "`h>3k _H֊ On ˈUWPeD޷8χd^ppYihЩK syIzf\iQ PgU&=)e3[%OqgM~f3v}p=fC`tvP텄 ==DfנJy8{8LQ!aeJ|eTڱ֢ La%dTLK+taޤJpeLA/%Qb)Fa9תB*~& v%`[ ZK=b*F A{lCYpHASvA.G OG؛g0vqulO{ǙL;]kc''bZ9/Ff?o~y='q]G};/N/E4A'Ku{*`\.?AcUQM9?cF  2rITz"J^ۜD2 6 _T_*1aR4L"Gzvj1[4.;==%ġ~μnj7$AOd]m=LE(̢øR60W^Zd#{I?|pryغ՘kMm#,:Νψ 9&u`QT%Ar1Q;|`å?3<>1c/!4+[ 'q+# 4s* 8щ= #5K)'{aJ.iqjܘLEn(Qٚĝ|i\S P 1Ϯ$_Ʀ/J&1mC9`T"q+э=1V5 %po>i~o]|mdتjDf+Y"Jg` 18Ո' Ҽa@]~/&ۈ pX'!d« 4W2#wX4̰>9}ՇcHa")JtnFDgo^|<ZG+i?4+<"'{a N&,27 )@@+ԡ#ٗ̽dAЁ ؛m7T^陋{+Cntڛ& `H9NayTzÆ^)Pȩ5pJmۧ-IPQ. z\|3JAi]O" P|L m"pOq;JmY9c)UrG?r+R({&dK,?ϗ/gHKYe,KVG)81V+y.tBݣ %b\UakESa$iES .s}Oum ],rshn1Yf'u s1#9?k@PoP: !|\) g' mZk̲~\)t *eh0OՆS2.^ZlQvI )5;x rN\>Ȑ7/rFL@ 2~ϷA>sɶ̧ +_$Pa[gɱo7q^`LMP&y)aR62:2Ew͔6|`ѢȤZ$sZ6<Мtɮ?(!a~Ga2\[aW 87_Aڀ~yHrNǟQ]!g#_ M[ݩW<1a9w00;gx;fیN{Q=S8ӹU3K0h0N,5^Y;Mlt# ] #jrQoNKHaC3R[Szn|zՇE!Cca]Eӌsƥb6~<ߟw+h!MuㄆVr?Tv"vf|BMrKS{/Ǭum4x8ϫܮ׻*|K+t;1M5emyDǕfI竽u^]rIKxί< % %G?MAy237">ismvƢ+&Q ~Zh&5Ǧ+IU ހ $KgĨ[S]_fF s+ /l8?kɮ&zyNvKҺDj"D"N1!aV1,~M2x૤6EXRLEQ&q+|2 9+¹nHTApjw].;"MˇJP…%%^(J~&E Gp) ^RtDo+t̻\(zQh(#?? }2(%cql6Ĺj$)LMl8_,XZx뀲z\S9P>4x'N&%]Ue?SpvϲHXX@'4SjL L?;SQ]VWf==|mٗdzU;m3wuԠs .YB%ӷB ęD:;\F@DyGQ &S\$p|)5|gXnH~c?C8QM~'¾YʌL/gA%̴@8.<ikrK:Է\hq1ˁ^WE_h؁ZVz ˿ 8)N@aZ%/(WM!%F&)e[P ѤځJ=S{r/R*=șsCI+f}U i0-oHw'W*eAւ=]+$2Z@7OvԨ^D>).N3c/[,-5su-p1V\#Yu6+{.I`,y>̎xzF%z$pb7XSXቱW O@ k=i|ē4墬Ca;.\Z$Mowf!wC`$zn%y/b~Sjzۯp_ǯåG2c&8&ow@vWFotusdHKtJY'ҚºEYfLb5Jvڊ椯&?Cę%c ]<#+GxOn7ub(3щo䘌vVCeS#NgЛŖ0L1wB^oƘ/v::IPɰ`7n,k}<TL# |P qF̬-f/ӻhNQˢN^[I,hBГHkuڼ^H0rLN?P8I֒~Dl &֩c*MXQ*y> u``MP=}h^>e 8-"ɃCz'1(u[z#2۠ILZ@ s73d9BNBOA+;ߡ7u]Y"YxPf~LK:2lO2}DGV{7at걒F̒}582:r@XxsH+j9'`D aiJFTp Ș5):3dVx_=U(8 E8^] +x=5Q]rhW,]\Z!ڊsMQ4_-isɪn$MQVµ $M /4Z>Q/'6o6H[>m@?Bopʁ=Z^jU_mwSKCeaثvMeWwlyKN"u l:ߝVzL y~9rƿ:4X?jS-U9=ӟş2%-~?ğp! w7J,>pTONyB%:G D~=xO\|W(sk(?PRJWXŦX_apɷHo]5"n/`@mkRDr8F˩eAieAO5ߺ0:*.ӝKۄ)g%gq^~KM@#"O+t zd(W* 5FϭfgD'}E5m_>425ʡ$Cd3Ea1spuBS4B|2CB\ڵ[ `q7P D-RqO֜<佘 c 9SwWT3wB_&_||MODnæRG-T6ґl0n.keWZkьBBR&OYdFR:ϭWw‰)?ӂj8HMuPT UAN^yX*t88H͑>, {+<sK8 kpf0$CŘv(QE*ڀK'?_^-u!"FJ0oE+ YG;>@8dIШ l}K:CLnKfsGv\&\jH 5 庡ny&HX5a`\Xo]jӖ־PɎ]˷M&񰚈aT)ov]C\`!XiNz3`?bas'vS}'&R ؁bs&[PACljFuZZ_s'(ŧLnv σs\iy8)ռUlʑ.-?ǐV l"e Šs@ n/.EX8+oV‹ǡp2P+C5}]2v2 IK|hdJ^{R7R>%BRx_$;GLpo}Ar|5 %|XQ'nZmNI໭=_|FzB8ŘdbRq b*f#{{q4o""4*WU/  7$4}U>+AI]8d3u6q<o^I7 Cի-'%'F+yƮ}kwDߡ%*Dm%ϙRQx[6;W0cJffio3F(-O}M!IhtbYԢ. U&Ŕ`(ujj}VUU۬XM- eg8^AXoL@ S{g^`ݸe֭$wjp6Z?o"*};(K}]&%H, tgb7SPQ%HѼ &0Ǜ3#?T֖c adeE7>xN%~?#ĶfqYg:2=; ?e|Ôum2N$nH# Z{X#ĩ7Q&=B$$lb5mG+9d%_1) IѯwP^ohW훬 &GfW Hc0,LQ@#(Z8F֗7RKLQUlU{;c6$$ _aq8`,Rc~wyԫA=&%Q+ayhj/B()JM=hmZ;pɧKi=5)u:<(kRŤgzl|+ <} ͗v q<^NC<[=}JFWV[%*Jz!xSDO\E6lwC=ծXWM7 ALS ?]g5 e6PN~@N ǟihYڛk?K^$o,O_M8~6!43_]f) ߉@[} op~V oYs< B n.E ~+  #prA?G k$.R`6Ӈ0"SL`LEN=#0xkUcd_y'}jl H/ e#V~ F7t I\aedo ""A$sKK>lUžQUMĺhߏz~2l3wխ~__ADQVԙ6"}-N |/$6.9Y~Ьz N: cS8XMqgcG^*jFZC"A[A,gN9UY~:VxAoM%c2|oj8{[ `h AR/?VsL o%-y GDY`-bY&|&ŃՑz!ƴXgHn皏njʴk_M]PeZ;+GZi10 ,hH!De2mS0W^o:DX3}W7h[A@F[Ėܛ`+p$\=P`=A":򷎎`6.PG⵲ݢrPqHjU/Gy/ c7K [q"m^%կEU_βH]ʳkG,y&I7>(| /'PmR%mG-o75P3,!^L}ힻsZVܨ^%_Ҁ ~MY]t۷pcrf i5N (KyaS~ U 5lULd f{J;+)t?H յR/]G ^R럲(d&x^g;jiźZ%~W2N!I85Wקf5HVr+ vaoz5!B~!644FO B]SD9^Q%:by OY ˭hEbNQ.h}tQ}uYM<ԬLh%\0 ljd=6j(y` cDɻ~, aAՄ%ϵbDie[G\3Xkrwg66foɍs?m iMVŸ9C]G[-nR7a>FhmE!!j% VS[ VsPGn<4?f8 tDC|'dC主4Y"[0ii? { UllqN/ia0$CHvlyC[{o@ !M0oXFH{*/KV/ /i(e ^{i`jarTsz1ԉj9FRD7>aSr³( 5[u*d=͈"f[6.Z}P[W8lڏ>M&@Ǽ gPV$d~MaD@H'i:>l~%sD(!¦Sx-xs o:#gZg: H@1_oߏMlîjI)\w4 ?v)BK2!"QoẨ꘠.runSTt -c'1SDއO!H~.nviqGj* j5#yVNMZE71-s^y3L{wo}}^6'x(̛1!G+{,Jj~<~߱嘎5*h-=O-<)/x<ڛTcq[:8PyEN;@$ bηIXƈ٢GC%^p홀6 mwGǻZ(J;AZi4^Vy#]`ھ2XTk&hb a e^Pm'R9y'ѐ ʰwϷ' -޷3܉OYNN>[!rXD1JĘ47N4 I> 9rh*4":f*3D9HxApEyV#N3uzyH*Ak~wHNavf,{V];S{ՖسN27_yJAAUzūru$J{͇8[>(%rD}^RI1ʺANF$%~?|qOM'WqoU&vÛsO}ڬ-3=TK_*[h/WrT;iTƝ: ,tff'Q#zzW3Q{I` S?;nAY\:0LaZY*2l%t-BC] av!8J^~@"`;.-Xu O0p+AE3jeQ_dYzXQ)uz%E;˭aLF ni%]E0JɓԑDe;o(`S!Uʈ=] q0!A R}}kac46u"oJ-}ir >/Renx. BD1J6s@@Vd GYR|Qp?EDkAe'n4n k*=.]#y7̥aa8z^u9x*G"|ir Wz^VFARm[xp;U ŝϫ]NMOL|jePstײ$NQn&ŗ#1o$6h/<=7kћB:Of4Lj gOGMM"Qp/ITyb>r[jXR>=.ah\^.+3x=pi6V(:&;!iOkg$䩚*2m1=^UAOdLI2nm |1_d"ڲ㨖'ilA*sZƗzLqQE|5?Bc.q#cDD@*ڜO2|*;w)|ۈv"Mܽ;yՂvop((B/W Cy|x{2vMu,aG󃅃G!o!/zҼm4:T=ᾚ$ |je Hp/[say\}_EX7SIUT";b/\ѧd*iYc*Vfcq:Rq_L;*o+?seZ9R{°:'5Gw^*dTDYISdf\7*AVW{elq*d:b^"<ϏYpNC,o:jBafwӱ%o7i mMlٜ>^ z4CI,X0 Θ =g\z7cR,T1j0l#=3">(R<Q?h/ U C^;Zk-zɲ@$uO|<i/o||3K_ɅHzCR'"?aM RE3+k4aȢ^t*Xl$ȮvToj?S"}ʢL2$8 1H mz}xRyG^6ע'k]k-4h<ΪN{ŲH&:-"n!ķ:`g9!erC88\~%rRi'=mΉTjtp,,vk:(s#J-9$KVg*|z٩JԞ ܣJČD/?/[Y{}7z5^qAFQ*|I]#oUH!P̎R}øI[G˴B4wK戱;XǤKY)o;D+wz(랭l0h^wKɭ jl IaǴ-6:%jOjiʊgU L>$}BXߚMU<5 8X9H8T59ڒu:GRe» QzU2rL4K]X(3| Eg)~MX(|$$q!P#MRK8kz$)0"񞺽G|l: t=#bq\jˊw'2Ws4쉺*?d}\b%{Ef8e{?;ǚ<5΍Np(M:ܲR!eo ޵CJÆG=kQ 3 –Zت7`.$ 38IK͈] ] nф ǚ{KyBGo_$"vm/Z~Vn{4Ćgy'|ϐex)82a_r:W?/戼hE+$;zUb-]RfI2}.{w,vb\ր2!IH.^L ׄIV̕T鳄|'WJ` w%|4^&zk[Y/U" fXg5o"" k-1"!Ve|lF_/_j澝"ްBծg$>3k~ɋڠf]HWUBU󵿹Fy)iR bh6]Uh83Ɯ8sQc;8|o:oluDWcr{RkD1M ĬrQl\4^H8TO]ePO .&20Pp3i!^kv}+-C\!~q< ¤QqҪ['qs$zfxx!urƚ'9eX}91eΊu.De* tҴlhx!؂>hU,9^q ~ ) uST0eëVS$'x W% pES9*qCߤb:B2t ;S+[Y (f:5< JRBnyԫH^ԇaUTK]~QS2FSN5܊k FȰ7؊st,֚6d 6]w r֜$%zjT\-SqOk 6jߕ+֝ա /3IghlP-SnYqL9>(جUa`6=,3mxm! 3\*$vQ/W& /s+aߋD_.}2;mr:C e$8 #Kُ̍+gTK>HidB Lw|!7"' S›I)ndu[".//G #Ӄ eƲ7 {ܔ&MQ掵{29y=M5ȯ5HuM%G+lb <PJ( ;z#E{̇.5ȱh.(~m8Sxy˖[KVDU\!w%WJ;H 3|ag@ApZJ7@AN-CoSNS,W$rc0p3"y)8j%>/Lt/ x4JGCq 5 lZ^}(*貇$cq_h}HLlIRy2Ώq[ijwJailjPla#e9ߺэV 79=E]Nh߲;?c碒'_ aYbѴPk9Ke0lpqK4(e5(ӇuPAGM.|>Hz롑3LAXLwa{E#L ӥ/6Ц 9 j#Nia K9ypJQkA!hEw(c !oAӰ7%Q 5?~{8 A);\<[4K9M)D < ? < Y4wٮ_❿{Q.* 5Q?*xwxxzv|I [GDxfsJ*װ0*%nMB^>Ku|...Kq [&z,ilFzOS%><ɼR:Z-:&1ֱ Py{016{>Ȅ.=Φ)=,$mmnvK7TcakGee+H( &Y 2ͤƩQ]dt9aAKQ`5&ǞʱmHVlvRߎ oz4w27_ $>@# ! 8㉑QQW`\(  ੡>\eM 6'1A cZ-d k @.JЗOKH(~}]ucgEJU =P>ݺ͡[70.>]}B/hVԧ>.YF{mr/TЕrUe bR%.~{a`%#{K)NF|&΁{TmIn I&#ւݷSV<,6l\j"ֺ">̩r^(=#zaz'Us+l`}șFt#Ңf"ͭSٛbY&Bp H0JDi' rΪ6@Pn u1E:B'c\Y71X Ӌ'MWi'x+'<,8M:1MQA0x6,s}t PT#8+/yGfQ)0|-϶a>ơGIhU-XYd pDW\OCd7Rlwe*pBq)lҭ[EYM#18Na5iKepfC]/'fICv`g&로~:pk֭ӢzɇYy:ָ+;0 ##r;zhA1a[Oo$'rQu潂9}n/T:nc<$1Bq1O(6B3ݏ1+ WDVg b^j(7۸:Az5 Xt-mD}|3śW$?`cؐH?v6 Y5`(a>0/*xs'{5'ߥ?kzzYaw*4#v_>m[©6䙏@3¤82? p t`,;ϝtetL_-: ;Ɍ泘xia̱5}m-܌9yz1t^C= Ij%Dw l?orlH:gX$OHުxzlrߐB-hUU_я;m+U3O'/QvGkIÉM<]ev D#,{]M-FKlњZ>_͉ZS`ۦ'볼$egtXmpmFt _ , I!6y7 )mƒ\&JvNnhWKiݷLxUl~+ W𚫊/yUE "~~1%Faj#y R};rLĖ oaAy9}r>+:{2( W <-75*E لl6EQRНuJ Com@V^-z؄o Ŷj.}O#|ސ}wǖL%bkc9h"C@A?c|AFjNs+!nN'{z wB2~ 56[_l#H햠)U\+kó"sTo6Wh:B r=MG(M:u Ԧ MWW3P&?ofl-M%MP\K^Jyg~1hEwϊ3?t9X{*I\QtKMP%Ё~o/ ^ .pY(9c xfQQ#4µ×1]dP l((M޹ύ,v#q%)4Ji<ͣoJGWv.Ү@1g e;0׋ q'7sffPdt|#ح[=XVhҝ='\X fNDKE~|?XMx@sx}Ng Hac|=wo d(!HTIӬ/̌aw-nQ]>m<{'~Rc7A$߮|쨞ez }5ٸ)vAjìNw;֕.2z;35QkW[ug> Ff@iŤXܮ%F AGq EZ櫬rOgtLv5n_$hي”Pu$j[BX҃v|*g#~q_̶w^*8BXqV|dp}j@bum4CF#}X9mнrd{J=tO58;erXbcùV;r~!Ϭgl2(=#ZQl)۶m۶픭mN)vUe{w~$WHo3 aA7)&o Q,ܰ);'L7*-JklBApd$ ^%[.L,pb HeGmdԷkCY/M1 U,N<\WRj,(QP ]V!Wz&̺S[5'xjϧ;_!y4=dRZwh0ct0:(o/R ^*)ٚUjmxާ&#YH8Q]!t3$" 8 5{gɀˊgb I JW r2|umM6ZtR2a[E9&Bs5&BPo{DE6eɓ,/*+&q)Ή h 0 Kg]RuOWH Ñ1{bBBE|8L9Sކ]qa8SBpꢜ"nf;` |ƾE9.[hOrV1CjꁑoĤ: ׳ 玤3::wN!k3/'pk"ɛ]=jzw`)zrvfXg<: do\p8mhs1Y=\[([!X`Ī<Y=dB [ֈ\C{s wrvڨOm>s\5Ȅ>7j!Û aBx 1wdbᕳMǿc`"qȝ9QUvc+l`cL!F?pgp2clx bBL u]/:\N6dŮmvޥq&t'86T^*3) [>u&ڧovb>z[F gϊaU\D[Xdt P\P_I^ ]! +gY*Ɍ߈0L^Q E# y 8npnЗ`{Y&a%7oq\{(v5%7DBQs۲kĪ~7q{Z 8dLB'7`A|,o#WoW ];[צ7&pf=NvۣH90fMb?u~ܘLU+(_9A (f[ p>5)E3|G/jl* 6=bkυzSp3->̮<6(ߣ./E+p1p|3j'+(Lu4:[Ëxi2FFAZDgYNfXg~VyY ;=.8@/Knmd^- DzL >ӵ 4v===>˞Ft$zԽi|2:RXE{HPub?>LjOT'~18ESp-!DˈEvF2js>GEzTXga//?X>e,~9%/g,Ȃӿt/Y<+/wTd"@A i4;-ӇgK 9h~Eo~ I/w/>Fz?Gg+ lL=NU\"׿haQ׳a`fs>,ߐedeۄX1^N~_jS@Q7i&~|8c,Dh1)'Bhp,owE?8hS'22 Yzdn)cJi TFi>Q~ީ0X+&Қo:{ܯ4sfkoƘ{rwĄ!JbCP򿽺2f[ڰSjIނyTeJ2#} NVWm(J0AwUkʝ=,ajm-`ms9x?+\t+$&dqTX6H"ؑtSTS>[u;@ZN~ .XCaDfC%0'E~/e92revKmNx5>;QRF)!ew_ƖW-(":zE4x!''Dk2EBdca$"QO |lmG i/*l}әqXAcƹȩ׼MoH,oP3nȆAKOj _Cuɜ0JZŪE+EoKej2i޺u~fq\<儝G+WBm a le"]YB;X"$|4e34NŢ4.`ruRXrS+y 5i~6S|&4*,)L Y_olYu{jjE҅:H!LGL8:|-'(> ;'~dj}"8#3_f/fp^xݚ51iQɰǓY KCg֎Z0$ n mϧ  %چS_bFxŻ@'!ucހ6~zضǿ mDc9sp1+˙9C{T#a翧fO@06?j<nA 2ŶY !^rړ{$XӑxKhFĂ[vS [ t/nYQz$Fbvvz6] Ru!%j5<>@9ǘ gڊL<<n0 f?Zv׳x{9j1_VohfTx~AS9_{s}S{JcyfW}鴛{G1|9i}Z;Oo?ҤGNjݭ~>N͑h?.j5_cVaRw')|s C#&))AYSbRppTjWpo!0 0Q:՟ 8 G| *P;5[N zRo%$DDmTcPeP]T|~>#y$ex+s[ٰZ7B@”_]5>;s!t0΁8ϝw6&_MY*K?<ˁt" {`Pz\d @ⲱƇfY qd?K&f[@W lھs0l}7!U:~P^̸6fg`7JDW^xL"]?>P{G9[V0'jVY7+BMd@!v&HɄ-Om}+P~\f{VOUiϤX~j,Ѐ 勺Ư Xps#F"#ճlgN2JVru7hXMvՠ DP/md%Rf>ZY ZױjVU)``l?zOV]58ދ5oDV@L2s9z0_3) N87;j l@A6vp0% z@5^5#.A$Og{!uP.5x0ޔsnY-/jlja>{_jjѷaä`d?09g2!Wۯ.}j'FNKIC|d!J~|e(Dp66)73h++ T$՝g *}YL%]{wtt~Fxӳ dʆZQ=! Oۡ!?>oySHzWo:,Epfāݨhi{[I*Bh.*8'qф$6k[S]^~'>A@4栉*YQPNԹ [_b@h+QUwԐE?G y풽D<Z q1ޖiHӞ):"O"!~A-f2djsfFMhf8]VcGqm'°gHdn ޞF*ZW0 zV8x=*};msy{O٢6O U?%]X澃z#<װ+RoÑn q4P!~˦USW?*C&/"R.ojta#]zmFx:Xˇ>;c2Rw/u(&EjQ#9Däo(ߘ%9z9atk#n:yX\07wXNcwTPf31%4rϵ6/,aʦx= ਤ^j`DrSR7YP_#e9)}_4LZ甏,%*aXVSs32wۥ#ncnnTRoI!oVȮY`cmjj~)kt]>zL#"nV֠7 CC~0a-嘎>t\yH캍4Q Nn9ZDtec{ncDpi*F 32BY_E&//|^kٸ`'SE;~?}7MA$gnr)=Z/"hTɢtdž<6>gP8*evBR ۈM~VU}'lNtPJ45S 5,'ReH=_sy K. .=<|;a%:[@M4DcClyo8%G|1k_=A,7Y}BK|/BNþ.ʆ̀JBQx *b:`Z?K(Plߘ7#_7ڪdM̾d#lq J G~P"/)ژ܄J&Ï.CH>WG*&ߦ'Lbs}٧ "I%lTkBCA >!V(9KXGd ènU=^")@IV^A˦5g{%ZPt(-;P{6rW=~ 7#]oARlZ鷼q䴉1 7OLWǘ6+ΊyШzK\BSXFFi;p t\Ĺܥal䬧. ڴ=XV&L`S}yi{>шlYV0&JaDZ /ڀØWVٛSJyc"2sSsrJԸU>w>sNi 2J*F0,Za@~ EkȮȋs=]NGbJU)bx-|S`벬m X2M 0꽲ylūU@)QV,tsU0Zw||`c eVH35C!v3 %`XYpdx̀9=w?j8j1e_4E{)T3X(ۑ}Mp3l'`im-aP1\I0Hb`61;zurl96B,p=2˷nn맇/#KffKf)SdPxHkZ{u;9wGWl>eJNuiL/KmbIR=mf 1`9$#B:5Y,]d)l ^Xϋ53E3i%`exmv5F3ʼE,Mg=KqKbKn*6Y%iVJբZF2鹹L6ӖI؀G"Ix %:X 9~t]))!cl/B ; 8(/URbFbߵ-i|P$[҄)+d%iDMGBYu U)fTeZPbǛ1?ϗWc`WYH~k\l/ r\1 qL71'ƥWIkgZx\^)|Aߒ #ܚg š?;+B\fXjldnmVh*WN[E$}vtߧ.C=hquaBWMdOg*RRY)`_}Xd'kԡh@5gkz;bE1AE觟bCbℨwC;CN_ C$%i 1 7i ?t [5Q9DF+a]à$0G ė/06u6<ޣ 1m*o^Ҡ qbw6PBP&&a)5r$Y;5B1+؞ qL:B{OZM{^naCI#!HP+Rk3굽 UY߱A9?Qy\ 1V 1D(( X;n"o)L A=9JKt,,„7u \lx`gLHv7,4JʹvfjkZ3 2 KK!jӐo␠L `7XF^K a恹Y'DN\(ik~'k3R 䏫ZLF e68$70+"mq; Kka*^LuQ(%Koq~N$B%1FP5jazjh֟jO}ecM'?0bYCSN߮3S^%u:: [{stXhwv^O#mWPm/1e6@RcoC5HAto?-$}YS$f+I9+~t#'{jhteDGZן9vV?=?;wV##=?31f_|LKĀAAr ;-;_{PF'#s[[k?=u& ؇#X8>zs3ҵ_ ~˱H+;+-#GIL?TL#-<# - uSޏ01ҲT/>hefS^8/IS,I/&% Zć $]}ijEFXXb"kEG\ QnDG0Nma{yg)(YW 0'U͐Jx! IifmQai˅h?lx:>dg$}œ㓙V:ccwap?hzk!ma?)_V*3hIOW<u?\TqO[H0xrHXcg{/{N5 ,PXAqv6%BBTB*. + }*Y [覀Qr!oBDx7;dq-SIqSFu8q { Y{+GnKw344 Z5i>K۴ 49D;gzI1' $$-D PZpwk gf"D`QRL&t UuFwzfnPW9~1"5M%Qd,[L;#L3Cx.hA9]U%}  "{oʱNq6]^IٙC^ 2S8kc)WdZEר((ke-f 5lɎn B YHEMdgLR>kړ%XZ??@HCYIAVR%jTFT mk-=/OV6W\4LD%,թ\xοJ8XvHceN??F5$!@"P&{N^s3X4YDxuVXLKt]4FbqNOȢ%CV~4V&Tɦ!^Uۆ TWֺ:dΐihD\c4fqB6 kך!`$pR^4?x1M eOs3jf$*CvЌ&xNr<6/s ;6˶){ "āH󄹋ET.uޒ8G~nhp48ƬTٓXm*#=ٶx<뫎r@[Ngùy{\.umd> ,@A;ZZ1~Ml-W( =w7r10s/X|N:Ąq јPtr"ylF3Ia.JHP6*!*8\o&_ DQPThbOIzD]/wxjӯfi;~m9DJ>4}Θ\֧38?6Iɤ=meGfL/βQILKB;ް;ձs}⛳x"%ej8!dalס|H Z[] jFg* ÷7=7m9ҁ/'cΐڙYR=pr`%}8dn8a)J$_Yt FHuۈE8Ly 2׃(@U ]>`5 2BMDP`KԖ 탹Ȁ"1sD#rܓ^faՎċʠi[»pOš I^SOqbT>M5*3b-D!AA\%\]̑sM1}Hias>g"s>VyifpYϭ8gE?>w <ĝ;z|_\8ʏr,m4l̥ZW섉8Dv>REӁ^ Ujv" NKJǓدM*;<+Ws2x %L{yflsn׫6s`XKUKgQfYq}X؃ո{b ]xE=:>b,߸J>!O \~P9Y~BKs~g{ s>Z>}O%"҄)x9T#ݖt|>=XʘW[v湍|~ !R~LPH c`$Q~ؕ{a jhJN]'8eWm*ceqMnzoUFu2Ze1I<͔ȟcOq  3ƌ9Hj]LP8I ;d;48oXȲp`TM/yBN;!6!g-Gv]qSIƃh_;AWGnqcd?2T+# Zۙqtv`>Pw\ڦ-;7Ok=^>P!km[D#,/brOqph픳`gEU%~GiG +5Oԉr _tɤY5%jŀx=iBnz<)/oYr1ujXhnXT<}6b|6~\u.UIHBI|qQO{eVusi $46Rl$J+JJ6Ns ]dI9_dڦL;Ias%GS X9š8c hi?Yi>8x @ڮn\q%3DDMpnպ/ '!Vi`cO '/[=q_5}X{|;>^AÞ#1lusQ,̿)`agu>z̿!ſ7_X.9#dadP3CKi3QEO>v%xpKJh\P}xV %G2.Ȭ '6NN1N Be&Y$X2GԍwF%r8)Bz̃6G Q?a.y~XN"D2Fw'/^ܜn-9x|ne1"UNG hs))A~QOql[/ss4\9B8Ü]KE\Fx0ʩx{e`,E rg4.hU:l9=Dd}By W3zoN0˫z8bP5[x^ZzV9S ŧPH4~j$ޞh8_SsʦrSRvwTF !?܎,+غriPso$(2jcZ&tPheI+rM[O`?AHl.Bs{k uK LH\4}nśA&1x'},C@j+]g,\Ɇ J( _3>mŠ_Ǥ}- r877Xe *BT⦃Pre7B&?Hȥ>Zg*L~7G$Ş2m`D*md4anS0P݌<~YڹN:|[hv?:E yקmDn4oRMm&K3_7nw\}gu ЛqI%U3{-15 jd;Bi8,00f@ yj{贯Y}/ ;9 )Q~@z {ȰܤӭfEH'ރ ={}o/V\+¿eo3U;q ,, yK2i l'npĜƠMqxUGӕ_[ZCTc/cXOy#UV^߆.?M*~[Yn7ar}"`_5?oTXJ;]H2OYLgҭۣcR^6 RЙ{RFYS-땥Z_,../d_AۄldJ28mu'powdf {dbbef/ e =/-w{GG€,L' q 33Ѳq0 ~0 o* }8"+oЏ8hYP%D_ ~wWoCG_z`|dba`P[nwjreK_fGC >Yf+F\Hkj&2~қ &k6Lþ~Hi٣-dgYBz`OzO!(ntqG($󻹅V\Go߼̜]8۹p5o.hmuhpIW&7<ٖvnvv^vb@Ę/tdȩtdL}+:<\0]2 `iaʔxä3LLyi𙠞3  ɿbahƾQ[:u<@ !tu:RNzE԰CH)+DY!Je.X["`y)Y({N: 0{2`TqJoXx|j-+uv (TS5ZQ^C(&C> ]B6IW-~nq9:'rXW󪩟=zg^Nh%I7K1E$x= lGX '#gyd"t¬ drv]qP dǤ؎QĹخ^M0UwC>RqVhanR{p9 ʯ !PTjrЇ;&E<3R9$0jt[\e]%90V'"Ij/BXUwbBgkhiUS[n 泾k/%\^Mj x^q}YNsdz]SRpj+ pFdIT99W2ncߡxx WA@e{]6j=CsK \>ay:a~]j2PM-1IU ZP+pX=|Oݍ֞:[ܛ`=br-;.ض?JZ%:.X.~طMlCᵭxC| z.TJdtxPPϚ']&_ZrĚ#nV:sT憕'L~F 40DO%\UG *)$#WUA?:&}+.4K6 1%kCI8XάQ5W?V?aC l]* GmD],`I؋1'5q`=˜iQaov*ɱX4JG4]jC}g p)#r(LQ0K~>\h+G.3a}5Yk>G]‰px۹ю,fs 558QB2v =v&C:[5=n- QٕTy  ՈR +/\m(/>5P./xILwJr&"o$ 4upUUŹf]םȹ#yҌ[iKaAC8`*G04f RhW||'/]򈯝H 0xnmվe델|'Mv}ؕAR%4rjWxѫ%w%ʟzk 9tP\8iZf۵^>sC%$0?0E}#0 -N=qq'3C2{w6X.9uVXx8i=I0_S֟W Ji%A?k8ij8^vi7={T ,WXO1A nDLj].+/_7S*w#_ц#[lFr><_fOFDy.I1F*Wtoލī`v3M`3е{/#qٸN\;v_+h- X̩:E'74>[K:> *@ "1/ȴG.f"x% aj44TVy-dFq5F디jf42_S!MAlTp==w0`>?u\ w) XLC"$X`ߡC?nvx_ ;VPֺqꈞɴS̩R^nεIX֬/8#jOWj s]qG7yN='-zoPVe >Q@%0EZ1Ԯ[%y$<5.ֻm.u]{F/cNFc bl"W}+drZop>']~g?. >ه4u=3`oGuG s.ĻSa mb,+m {{3ҳ~0)`duQ5oŇ iYٙ>dBO@%~М/S 6vk?.rcYk!`gmur2~e3;lwđ1|6KOCO02r::5=]Oސy+|&kR*D\]TeGp>f'3rCiIsbLBF\1،~@_BϭɻC` J閱H2 Pir7{tJmnG6i)h?)ѥU0ceVBVSXԫWPf'سSU:*ImPI|P P.UAUDrڪ|;Z6J,L O2Gg'%^L- *>V.z+- K sWӗu*}a4URȒҘ{ g%m²2 1'_Z96ޡ5d\]ntfߊ\ֲ& V2'2SƳBc=q~)&\7e#dzYI]BeQ_ ^nm"R7) 22Q $UGO8"JaEeM *Xۭ5mI(sEV*nKE:SrTgO+ ̡`k&ٰ5#$kɧv&d̒*?Jᶾ!M@{#NBKv 8PmŁ,A=4i%skGcʱ TvBL|ME? [gw=Zky%i/4aˆmғ{V`U֯1* ާ'眎Mf-c)YPLr苬PspZ9+ r j.Kt- RPXWKY7hBjD%EMumab}8_ 2߯.<]՞4gAJ(9 =+$n=PWa@sD7y+zST8ïzVΈ~+. dDADÔQfR>W> W h/$5PYB4E)/Qh[E'DevCb1{xoX.HD)? < $p|O8lu}l3TSnUl- .+-]7S%BxRkya I~nONmᏣrS;b":UEnmCzh\rHtgKR1o쪯k1 b' u1^Jg KmL1fxfYk*wo)C;\,COZdCB—bk=bUb{EUɬ'uK+ KCGo9A j@@($| yP!V,Qvhe{8DA!''yW! bش^~y&fɟKe`̨:݌|Y%%ʷK+<3ʐmQ!ؽ| _/k<.:Y{8;ZwA}FgCsȚt Ys>);gx SwR[VRoX@(pH3FZt GإR[J*KKeL7lŘwMO `] _ؽ+^RPOa=Wjʮs$ϭ5cLȡ.scx{XNECY9%&LO?ؚ+;wAd3'ǥi#"y^(~Áb:D9QD[B#G HuY`rlae}ƒsw+l7HN̵ j1q SA8/Otc1עPѣ9uŒBaACiՍ[Tvu8Ĥt,݂9l7P~#X[F 12.#ߨi9?J.aYk>^R%0BS5Q݂1@p-N.y41/KS"θ9fo=|D|ua"5A]~E k\tH| ->QM=k/6 3x}쥴W41F.7$"KL喚̄!f)B:^^vIZX6 .v'_ti7zc|Dr3^jF: RaӺs*$9& va&~G=t$9Kڤ"杌Lgs  w*;֚y%4;&CҒ« s5wT*7bB5O4; >l7r N٩)@ȋʯδ~Lʝ7Dj=^x0odJ3T5$Z#W};ȡJ r[mqx.CkRR$}R؏oHU311Ą%nbwztwXoxmn,os]{2KD K?|' _NQSmW}W玭@MQ.I+3nAFҧҗOa@O> W* {†GCSVYCw'guV #|n_cuT8#L%˹Oiճ#[[<,Q&:OiĪ8 g*fluIֹ"f$@$7RsAyDis6r7m YwcW,+~-2."40+aKݦc`yUh=T#|p6Y(AO9ӐNx<7J˵t>;Mn+ mxaFzEJZ~^PM;-=$9{juh4lugG6DRnVKI :8쬍ZUzj*ۡ`_C?? OBCXX+:EmpujYL9(%xg씒ߊFB)A~UVdQՃ!ͭ'$;酚YFjB a:<ܱ?WXjUyTo {{?Lvf]pjByʉP'2d 'H4[ r_]?#iSDkF=)ҹjo9M̷[넁 e5Ҩinl& % |)`c\$n RizU벡τ%61^uL!d}@;WD@AUzI!;Fiq :f n3"= pX_.,WC_I 4*Ȇ>zJABD! $~CIGwK:KI ),30l%x=_rf/?KlG!~ͮ19T+Ftt>ތ4RPimMw0m(m47p &IHvF8 `z{v5ѳSâZQ_zB1|"%Hȅj? :e ˽1c/!m іPOJnX)Z08Z |hHpP3eDzwqYXS?fb%uNaVθ`j?<4P/^\NJ-_̑r* 2'Jlق%3a_hVMD,mF1HKQ@,qşὃA_G.e%(ZTM0IQۄnI1V~C||BW棺0N B3I )Z8[t?)KX=h.!{eIBKEeP>@ Fh.LWc(PmKk$3Pa-^O8szUdg7Z㓢,Il Mfk]A2kC$$u`|ed2M7]1lSFVӳ ߄*׋%ny0ƛMC:}Z_Pcڌ5sWKՇcݭqԳ7T yjɧ,R޺ ц>;mJ9wH%L7 D\Iae(an|#+\}bR &V"QlR,dV%XPLɍO`P5;GST5>(`QA b V&Zff_@-J :n-M9~MkddLkhŐZ89z H0ppp3:9Qol >>g堧`(7 CX?P̲YY>c0+3oGLlL G$2*`f``ho$G ̿~76w*`ap0;,ʿj}8_Ij5?ƺoLk !/ǧ UbXNՎȁ"> OJ欝krH5 , +_T_ ]i+c^OAC )#3sl~l.iV%'.c VhyQ]#jfXmy!k/4a.3D@62o\yuI"f-Qo`~`\m'}4.5!{bxUL /rX.DL4iU1/|5G6ӨDAb")B.@Ŧ@PUdR3`(K5kBdN,m✘uᱨhS;oh*t%c^Y0:2B.Oj OSl2VHƲpe|)Eۧ ͭGb:vG^ Hr1ͺ| (>,-4 rLփ^Xwƺ1Q8 M;*:ybB%jVG/eTx.@Mb[=rN@XH}}Dr"^( @sB>ϺbRȥ1H.QfdL#YԾ`|g\#ђG=l ZBrKؗ܎K I,枞}mr{s,G 5/ s,iNbQMBJtuk#h[gC7tTs.vl/$p| > /;4Mw?g }_/Ip;Wv8XY{ڄg V5QXg6ϢXId?^  5I)kt-3c[ud@}Шc+bIbe| 0Mn<1{ZN }tqUS  &~F, Hg˫ݸ¤C4dO%[_!< Ȉ}={Q߬f$i453gBVg8IQgt7:ij[? J)Mu^ .F{uC/XyuV!z S`GmxCEFq ݉.Do!1~;5RE4f$3 bRR *bF bl:ߡsv7qԈjԌDSkxzL㰣"tY @,hOUڝ>enq=@qMv@Ø>S\q`}( |J6^D &f[$ޮWO }8hg~o)T^wrjra@_2}mIڎ9/NCQ$ ɇqk ; ^TZw9*T_"  C2-0XGֆ!բ#6a^o li.}vs$ %! Gl8xN~y'OlWJ=ڭD[uWDfS } ⑪ӚYy~aPgŏd{yNo^ۦm7{au'bXjd2ks6[MqAX!\1>@jacgi(ѣV0Da"BH:ʩJusA/z<~?}i4~MCU--raN` jy6O8w~+X=|rBlWX0nZq1R=)SU+b_cCmSCHo<[,,WsA裘bMD7v*흛9lqiz#sˆ:֥pzNC-q>^{p%x 6}#5!Xϻj*_糁94T DU7Lj|%cWR b8bidܶaM4Τ*;R% OLg0GeMLW5} V6M,C& U8fD;P@kQ(sP+]5k}k'MP:4K]]nja[GfA.-K)@61 ɩxRʬnoss{f BcɘOe :+Biz}$R vc:e/:MԽvyC;b0}bZFzP92 /vƆ;6'w7O$g7H-88~C_@ e=`l ~@vvNF\qC[hXy`cgb13j?Ms2qt\~3Ϭ?_m<6w߇ XXi?Hac3{Nk XTlW`kߓu{|/BfV_ȁ0q{6_ge#9cp2UO{rW? }/:X00020Mf;?Kހ/hh9^Vh%5d5&3q #(DC#7" A.=N쀏v<WhITֻ,0)K,CRV50N3T̒4R9X63һOxWu_8Ņ-6Y &B]mH,iog1_b2w$Pj_hOjlqI#=׿"1b'RH"jIWY*EdB$})28\g}WbWpqp׮)&krxtXY$'vbm'"zLfvaf?7Ѐ`z W9L?X" q'\@dCpO]ّ2 s8I j_,|ƑB]ȨVAny@)/V/4ϝ;YpdNl8qElÐ~բMPDY\qtuѰ(TߋP|D"ОGcg*f䨰T? #"|UIX>~Hk=E-JxdOِp^+U!zpS,IχEI*uPh? S=4ЅU 0&WJ) )eV@mwAdrm^Il GKOgC +4dxmZͅۋyfQLV"аs6rsfb*?.v)F6xFm6xf'@q%AN, #.: jj)LTu4/N85I3VF, t; CT։řh4YmvA涝2k&7RK,XS!栰V~I;962AB.cBiS,M+%2 /OND f:vVjq僙uS`EJ:ȈIvlk47RA9[Ӏ|epHC`Hè0 Àȩhm=Xљ AJGKu>ɅsI ߆CFcm (?ϰob~ %.fhw Xqp lc ;TGOTbE_ * S5VE5)"B6Kpϓ#ލt nP3S?S\ir8Ff`ST3S9![dk_ 6Ѽj~ޡ3' s3tY%Xp/c֞̔lK ^J^$ŕJ>\.:eI?4"d)v<Hni4AN3z2mKXA܁8n=y4d g69W #{ѓ8 u%iExuuI׃{%Y1N" Mf4ŒߠuEfК2^ȥG!5բx_LEm:Ml3 %~`%`hm](C ^M:F)Gb( LWy_օţ-iudRy-}5vg ppEn(Q#4YEUʈ!;7֓Las߇Ef$Gӻ>=ּĊt2v*V01~B&5Ɋ|xg}7;![lvnВ)`>]TO*GڭdW'߶bYl}pBG(vcp$"(ez. aPę =Jfpunص4U???! ^R\}(6vq<83XN'͐Y &w &>5~>\Mʌ|km})*H,#uGgOox>  6P /l0ߒgd`KwGL~k'^+`~T1_ĕ `"Ĵm ^4A@keuNo1_j~X^} cVZyF3C' )1T((9eVWƒ7k&8 vJtorQ"NCݥִu0U`qfKr]O1D! xf6JC  2 SuCr:zӚ3uv!hl`,t< ;zET;âc\ P4?'c1 sp'F&ǹ9wZaEj_^dѧ7*G SEA([t`5Qk@#zg.j2ywQL.RYsR4I䋦##yFk3׷jh` "zAq^W%7a-ip#07ʰ*p\̆x-X6rfD w`;1F˙Ȧ6!%Yw(6t^R}>pN{$6{A^7#d>ǰʬ'e:;~ZN%St;g^S(p&5QokiMݩ5b53*;7>Th|>f8t%?K f a嗢!_} 6YL:+K:EQyYO6jYYe+1MG?%D^NG~xD<)~ٔ=80$}n{ёLs>la6̤S~CKT'o1FCޥX=Q Ղ ,vDK"}8$n1+UXRnri#R}v6[mS:5@nFwj[r@4,qly>|=ELL:<}}^</ ]UGS]Nu6W O: lfKyXPGG[=Ӄϧ߲ӓOM씟xӯqa;ǔ7zfMh=Xfj4?Pѹ7CG?o5,+yYKh5~6&I+8$}GFp5/գfwo;CHT #8-İU,RO=/لל->Z>@HOU]740yQc\)]>{]{dpX@.D81Ӻ_CO=3EzzVTȅYGH~7f)Wmoy-`.˝ g@]䄎dO!H/yخ~g$2Qq*3ެs.43 ?;qD\[~-b]c5ǙX޼ՅCS$>`p);т8Fʽ)afS^jɗX3_jaLP*Q8D[樔!&veK |P.:g~v0BĂ=EH,%,/u!i~MxL퍦)Q粂̋4*aVcNoq[c "iH{u2Q y =\.4uU*MJ=|Gх-ڝ`7퀆gx4.}PeoZSJ~30 L~AI~(+Q7ي@ kdLj_t"r$qH&QW7;^cyn{ @9U­eA>XW@QqY43f CW+)1/JgcKiE7=Re;ڿ5-~9V~g+\}xR@w4«OjeWxCr݋ctx2~% :)7BzL?,K3T59h} ],ꘪ%<Ց <1EIƦՊF?w޶w!6D\R[`d63;\5F^=7')9+ ϦwWqǘ"_jY) )ZB"Cra}91¡)TIRNq, KVmoD ㇙£{-JaX0 3 0 /'3蟴|'+XV 7O $:O@OX`@V0#,,`gOVV3x" p 8gQxX8 vk,*XLd,*ll`g,*18"<XY)%za>~`W_I׿xΜ2>ʬl'vϢ2+ ;g1 Wa}G"),&>H fpjJn?>OGʀ>O$vVVp3`{Y8@RS,;#bf{Y#0X9YLdy$g1 3۳jce'_ ,"X?=x","bw?g 9xWYD=ff/ggOK1vv 3Ir@vv""`ce'k/$t`kB` mڑgBVfG :pqMξ̡QuTCaf#@NsuBǍOXЯ-QfDn8cF7tmeߴt '+5 $%g"-$ doͨdmMDٷ#sQ. 0uG1%~CGYՅ4]fٕe/e{>q rVWm$7bۺ/ "f5PG% @p2aPQ7DjcsChQ)t/LqD-8oM~ߎ|'+ɽ;zqeMJLS2? 6!2A>Oᶶi;ܔz7WG>\A9 *U%*_PYf@XxYj ~ͷ908c[T!{~77sG};mz/r3܄i޺𧆑"VIrR cGw=[穽NM<Tk}l1)abP )g^rdnB\A1ºptx1]lS/o k>Ot҄W 5?ŗ2} Һ+3Ӟ 2`lK4ы sn_Mf{L\D]7Jfnp4_l2kJݤ͟pD&/t(82&}{_7]5}]Hoo^;^\E)Hl>,DmzD"BM@fNf!H G@YA(H_PY^ t šEDUa?fB*d%4, IMA^USaΟgKt٥+_!%P4X Tx[C*Zȷ&r*6ZnIj~x9 |+иC]=(h\p-*g KqWLcu56[(i<&C.SV{cN\4&}e;$4İMKV1\q_nBwNCӫ ǖG_f5rxWH}1y,0WF ̢/X74(OhS*:$VI~@3]DP/0p g4ͳMYm{buX%^hkӢۿX.* &X,Kw?8oƨʞL!+?"1Y @,W1iџ7}5gRgǚQ5HXOCSQJLl$:o%AU5LJJo,dM/+u&w鲜Kx|SVOЄ,GKJ/1I*—L ^ޭ3e`*aɮԾ@KX7+:;zTFIԩr$O߰wƭ{d# 'Ԍa2}%0 54 /fQ¾[b遌UNM-s+getNYM=d >M($Xo!UMh4^䗮LKϬ.HHaϴ83 |0@ qJCZM rjN]PA}-sb\b /"@yؽMXM ʩxʾbl#am!#y=PQҔp(BXLآocR>X"0_(:Z,uȿ$rsA:޲9X-o0P[+!Ӑ"1@EB%n’+G&*TEX馿:gkF.jlbF|7;Ň_-U413`p[}j̫0Os.#MkJ/#y*!&9DC+J莻ywwaMݓHĿQ8LT^8\IT^8eL8`X8O ĜOI ;v̜OIܔ@'$x?!0%c'; 2x?WX6V3ؖr89EO+K3YDdSD qJdzY9@ 8_1YDd* 0?Is`@,`/@gO ""+ |Z ,o tWqpb r0]g1Gf"k@4xY@)`7# W/i;Xf'87'I r;4,"8"`g,"`*x+O:>."Ӥ@fb"Wp0b",fEkG&LjcYZIڽfaϯȪxC"C̴$I,+8&?;r`oކs{s{|sh3Q%n޶e΍cGe?̻;| צM7RP4Ȣ(3܃SSzcF%6;wklP&3Pc0э"f@¶QOU&VFo,m` n'>ky%}mB{EA`|X+Fb ][a R F|Woz{_~_I~f=]tAzS8Sq]:E%`|E)2MH27KX Ŋ-\D{&4A6_ɿIU;+9%)~Lo2 bzK.?[ c!P7z)32ot]c/t%+oisHFS+Ԟ)ypG!rg p|9Txna|N|‘“׌*G5ӿz);wR%TLŋ6h"8fsϜgz N(I{:!7~-50nq3%dW˚'aM€jLAVS&xŠ ^fЂ54шTK >z1!RIZ:ξ pϑc/3tۗ:x\p[Cr>eJcmo:v'\2üRRΘZKʼn$ /L蟣g}]i$ ka@0̖KJPHGp^nJ+HO:߹="h4d ܚ;y;+Gwo?'U2sJ"c_pfqD(mkW0GDn&2c#H5SK; hla,y-}ª)X< _8N)hCFU?L:m %'ڻ3󕟍Meu۩ F$aKd5ǏHr .rpuU!e,9CʾڦbZ"lowRW_RzgWUn M(-Od^ І $ok B<\KYYˆ72fPsbrx ?}g 8P׫\}ltFΡ=aw XSG! VXV%1 zN5 f帤߀q׷utT25? /*|HX"@UWY-M*isLv 7Zvy6 lPx) k꺜d cTgs'*d.+/p=ڑɗܧR"(%eo#"[zeu8Y*>5gZOWKoJ _*tP32rKA/-)7|p*tyBZ&ҁ?QrHTGs*^\=tSԤgWhIwf&s'!ӘjFmǕBg^U. S?CkIxpDtcY<dKjQ<,+ 0xb/NJtde+"U H=R_AC#=]vFk B8퍃4c}ӎ1و/,\ƒʜpc;}ߴj5E`W$CY  !i]Hňa& 5eKZkLg+O iq^p_|9;=$ϣHBފ0Pk1_,MS5M{Ky:KjV56 EEUv۫ @pč}c{6Sw* Uu >"Y(7 Y!INMv2qNyPrԾSطxeS" /|qp>9+s]D6(K|3{]ripr'}kp!8|"|$x +8HWO6'bp0=8 D7@'+Xqp~ D7@1>x6G7o? YLd5ߟ1?<@`O|W|"'DV <@]>Q` xփ#,& vpQ=H,rO'˃g1Ep3x&x< ,, O+p< g `x{lp<;l<㻕l<^|" iupv%"tq7G9)_!_}џd (-5l~ U҅rY !jB޲ˠg }7&O >`7+aFu@3㍉9T$JORqCئmy#qA e뮐L>U`Jeb&8KX.xMv5pZ0f *s[)깊F0ւHوXՊYVBfm_c\u8HFeƌ3Y_ecæA2K;z鋽6OY '-;kKhuCIŜuXSyt Nn+?/a+,`F6`bo3ط~aDȬ6%Š>MO^)I(P݆ZI8 MG.6PŦ$8:gfz5ԠL`帪WU.聫|)C+cz  2]+?qen&v_9=K4D],,rŇRUť JFgwzJ`X(2&ULua0,sZ8 G f\ %6Ŏ~cTfuj/Uh}ml0c.N$kAwmA@w] r}->~RTX&yGWb oQݸ}D.t gK畢\TaȚ*?NAq"~ pC)AbDQC<7z*֬!=Fŝ6od<eewm|NeAM{j\ N4[O/.+(5|T9\nJ IϾ~WOdoyU&~<5k vDžˈcퟎմ|.u .i oŷIP\z֍]kz7Z:jpSzKLU " v SˆM*eB[נRhym3L]]S:Qrx5`h{fvb* +Nv~(;ӖHgBԦKPc||| (.r*L]2>M2fjOm4 Q(CMMoQU.ūu cAT7@%~LNTJoqi1bK{/_g9Cm7 Ç!B]Qpk@~m _тk&ԩxH[ :G6!.nTm\uKSkbfd s#fX-=~4"4@n|ߗh@L8{/_͇:=gghl}z"iuc:qe99P@OD̀z D`Dc 4D76&pbk>x&'U'}-z" < D* h= h<OYDdc=np>>X寰 OD؁fNp)8'}lYDdeez8h<  D`c'}<`uc=`b~P#h,#8|' X`i,"f؟So\AГӈ, r2=Fʠ'9YxF[' /*[>k#hLڌB/(EПn<7Rnk'Zay4LeC\C玄Ģd Us{Xuы}hwW WYmCF:Y6^/g=7 'z**Bq[l`j ݻlU/\?>8_޺_7l#eU߮_شyTb>2m߭ Fxk2Z%a} ޴BC{^fUZfGlJ<|0?ڦqbҳjhm a",O-$0, ^H[[ #E8|W&I`zĵQuUbhMa_6*BG*@01 U\giś5sC7 &q@]ΨpjUCM)A}kX'2oHA޷Z$k{(H`W]"oIO r/o !**Ipu .6MZŽ-!t+N]QJ+YDQIG#& r;nQ$*LuMb+޿%lFu*ꍢJ3218W,hIg!ԕY.J?oqxiLFG]iDKgXf[X{Wr|txvRn~BwRY&JY3kù!~V vb6!tX"LntͶ0c2ӻm9  tTDLp;\TnaGq_^3{v0jRE~SԐNWv3&XU>XWzP/PDUãCLZ^HO`{sIecda&׭*%nDźK g@)C1Z_0"2?Agy9=S@["m'u_`Jb&͖5e0"P :j n?"~L ?ݸ*@|_u>r&-; ]|Q"{dbJECނr3oCq~bV}seHQrtPbƞĖ쪮@DY[%HB:䔰}uYFn !Ȝ%)%+ ?>&:7:Q] l$F&kdK--g["M9&V.ҩ#8 ]]`*hns`#qي~~ {`. ϬPA$:{)T 3[6"U#_#YrE :v tQEuU9L`@C:m˟'"K1_<|Uòrg|XMo,Q/&+Wt>JכKGRׁ#MmT1C?dݟ*ZB3"fftŻ'N < :}ik%#L3$DW_*m ? arDVP3!+3gk^(Y7,4uNY]eW{kk~Vɰ*Dt"BȍBbP q ]xؐp6Dް'&`0&vSB5M,|ʩ-uuX5UVwiO#N_{K.M'r j9ywe⮍w :g{F51zb'LJQHu7цġtf/ *4 f^݇v1X\ 9'!]=9kI-cR(K6,B[^cvS$_*5! ŠL,'J&llܰ%4:}!:苐Ŝ\+FC ڷ/>MLL^B3J IpA'HCsَߪyTz-so@bBXS,0^@xϗZwp"^WDlVӞ-[EfvPqSK\Yy<Ʋ/;O4b_AxV66R'Y@ Dv< -\PГS G[ 6Iel[ГUL '8)Y/&y/_ )vljg@5ǚ~xI6g4qMQs.2 ol9_n!1Cv3lݺTn"8*moUHV=) mH6KtC3.$} V7OnKIdE}tJ+8~E\XSmV2?tmܛuK޻ӑ=jm_ʴoהw])^'XC8<>|B1>.#M4Eꉀ|'mxjԛi5ŽL@]MV[QaUgL} 3)y2Z:(R.2&NRczzۼ^ Ya:Wj}msfh ٩6l+%꾾##GrM&(R1$/{Y+)޶,4%"XkjO$H}!7~FiAAO$ XO+XѪUB8d'zl{-̓u2PA^"[F:5KOaK_;kb&A(DM+q2շ0ά<yb*t")NrwQ giWo |]2/iig kkT+ #"0llŢ!t=I:®iuW^myBl|?xyu~’Z%r'dEKR&&eCĂu5;Mld[!-ƪjsVЈ8OiF A0FQfGv~}L}oJ2n\21~^IQmc%8x0G/̒x_"wQU*pbm/Gm>*omLKA&Z&/.{jsk\[[a D_>bn>{"ě;\kpy٨S]zmMv bTL7Lz@|}@>c16B‘Q6ƻ73ls9&kw0zYIn75'.ZW KiߟMؼ3x L),(TNUvLIυa$ (r܂0mBձ=iq|2nB,pJ wWx:dhb((1(g^PY4F|^,6(a!jә3JQ[imhػ @ihArkW59 14L,ȕxcr֦q_ŴPKS󅹥L ]V·)9 R6TqL+clv:/uծNuʭ î}&UF2z;R8HETޱ=_O9:;bM%8OCEd{'O{ҝT'#B2Aݹ7Nb'K:92/Τ,rHN8C@)z#}@vtV($66)c0e^iSјfy㤱SFؠ<[Y#Z]e^^ -aO["^d> ՙKѺCqq(~vj=<cQz#i_zY\5 Dc~E' \|P S'E_s^I%VW'ϛ&^--(F_cei qG0̰YAӕPd vkG!G~$];yy/Ǻ1ሤ;1X!a"_}xu7ۇ\QjUU wGsۖ+6mmoܯǦ^*ۻJIN2l(i)9ܚ1g:ޅj}{X3$rnΫ9di+EvcoQUW{j$|R4TqW@Jru 8+v@ w;̗e`~H1]He5U j+RV00hېkgܟd6IzU6 CM{Kpb-ѿb04>D0L0MbY,G$[qL٨?:5'ajG':Y}ȸZk%Nܖ8cgQPj lֹ1#R%3.:Ɑ 8X@k=X:|-Jet9džcx7s贿/KznF!Pw9L , m`n#>TbqA؄dz8'7\gL/%wCv8¿!U+ ҽJBk[ص(|&`]u~/BEjKQ#hxFߕ l{5yz?3FlNu&he(ghc2̏>AorGk.SokS]J{ZF2.Vg䦾0]qSDԘIk@N }9e4wx&@~ ~8rWꈍHԥP {ĺ^.Įw,x+BjM'u"ʍLw_^j?K?u9bLNX[ÂG:?\NF<%x|`|Yrh oƘb9 q[[2OB$9!@n' Y^a͸34&$q-Rז\B]Hhhc)MO]!/hib8l $_(77{ux4Y68?0;?P`(b[5r2}|Qӑ]:|pu8jE1㖮Ut+Suwao`/VHdbxVi$v*:os": +e1~3 skO";2d 5вCehKoK%>]K ګ?3Jjrh&+9[&P*vUV^² . 6a!h/Qzo`%kyЋN3R3,21&$!!q]M&-w _練6Ifh:xU1==k=ggWvQjQJG*T^ v{kwՅn8e݌fv4k 3.w?o/8D:@x+ PT'tkX1rg|(MI5X,9EIVTǍGSd<-xQMy)C )[KƧp5үȗ(BZT-yl3Iiz8]ZWL26Iu]wd礎rqup &ua^`ۼʏ&ٺH/"EMІ϶9R(tz]zv܃*t/7$u$_p;JsTյGiN?TV49e08(0$d^n֛Na/vBEb۪c7q*nz1]b);.)5|r7ow +Q_+ )R/]jBbQ }Cm[bܨ 6p}m "Nc3~9d7j/)2;1ۤS=8Un ;J-՜;Jd(Ɖ 1;@A&֝w=[X,˾!JWY~!uQ_z OI/ͳrx% "UHxtYk+idn,p}=Z&_>d>a)`!#e1gۛ+~5ejƼKA1XYW'`=8Tgceb2v'SB?7}&ј'h2O3"'l)b z_yg4OzT8P ԰Vƴam[`Kr6:,XQ԰/8,&5Lu<A|~ /65̔pE} Zw1k̼;sJ-Qu mNx)b24V=녱~qD$?Z&dtC1[b*qmJkP1y \t\X{Irez{2qO 1% ,,(qjЋ'(}ewͤ+PSd5a" Z,7%ڀNs;.)ղ=MHK|']3T 㿚jE%QlE{}mԀ1ݹwi{2DsVr]\s0BW*š$ Ƙ&`zxѼVM4\  .$J;:P֤a7O} f)e݆Px+>@Z :,M .gC>%ޘԻО6h KL"w;Wk >0zdWQ]H<_be-69w驾{B]q8VUܰDC\L35!hj4G}u}Tu\uĆ>Ƥk7Υ ?BЫ_yQE};sLb,XB[w!t3dʐF 1mL[>Mct4 @'_,$á!: ;h<_Z.Yr_D&ID!{'iPEatu %ˤsbtnW 7ѾbсīӇry7 FX+8%JП7dFC89!"s:w@&/*{5ڄh=YjA}Bd4lv fC-UNCl\Y6%x8-@)DŽi[0ninQ;ˆë\kV 9B$ EHs!f*=NOʶlF|+lz,(36(e˧(.>ӹ_kǐ—W<?j/U+$!Z'x3mU"L!y?Q-oNF&Iffݭg}wlv>RoY79_ nz K1%F3 D.tiR n;GdC.푫 o|Ua+JY;I;ĊuDq"kiD.2s BomH2}.+FݢHQ &*w*DG&SC:4KfFZvJʷYiLLi^APϜ}9}$GpO9j´k!#a Ǫ圔$m A{+K}nuʸbҴp=9TYp PW.1E}C<- 0`‰PZJQj~fCWO_MkFɭEGa@bp o<%2̡Igjx 'gqt[YhlVH#pd eÁ7Ϗ+˲y҆- VmGCjVOg#:Zs7vOv@eCA阜 uKV+Id.uiJAVRCx+"u6:OfJ"[f{CɤJ,ϴf\ם"kD*됲=em"FþAwR ] LЭUK@vf¥{h>N*ciEL65L#0_ yl^<)Rk!OoӛIC,sfpTx\gf޻UuMDZ7K9]3's/KgdaMR DaMPk>%>=?-kL2:V%>Kٿc5ډN/sbm$%YK< Auvh蔑pF$ Qoܞ {3#zhsGoNNJU?.f|;`5jyw/?L>wOt=FUfR/0)TBOiůzF|3:ʒZ;(:lzK+mbdw\+AemN@ι#EQn(*!Wtr9Q4`KݺD7r$(HMhʹђ(%\o׈D9&H2ʿd wB| J g[كIr"EL*%󦜩G/m,BWa(1epqYp@kN?c;g3ңOu ,>/D?W^JU/><\k# H2'9CdS(4@fi@o̸f±eBB)2Zg!k>RX]wāܨ kBnCdS:IYDfqS -*P|Mn =zM_߈˴Y֧-ŽD8ϙ~b̽A?j[2e8VRbmFw7F ZPTBO-7QWc>.;+[b|͌TZ]~=/':鎩u'+:dc 'w#WkiN#-6h% Ten;E;wz9ҋbv -C/ڂKN%];P9^E-<Ƚޡm#)ktFt\A8 M J(fSm+ajOgwzedӌW/7d.hxxN;wd]͐2dv2q#w5^mM7>4R长`uėȢWV礦kh fFKQj+/jS!XYM3 ͐$Kr 2O%wG+$F6 ;u% tO=1bbp c6bqğ&6p@DoH|-8kWlAZZ$~"%10-I):mn8Ԟ;T3, pQIsJz؆v QKO=#|7yIL!<%}(#O>RE_~C0FiۮxYSCW}-56R^ʑ>^R`#S؉cC| NJ"S),fTYi%Tz7eSag}B'=Kx`՜,]zf ϱJq^g@'(}y3rɥW܌8>la@rb0$~ Hah2G1r{ [J +hLn|P M>fbxYNV]{5wp^%Nkʊ+O#5_5^aBg_a*qcϢCqNʤR ,Ӑ/T5)Ef-{[􍓰~_+`q UrȲzix+Q 4ĿR|YU%ASUWJۂ-O.}GD;&WKo}}] u{._)xxC[JBF>)JP$ T %?*Pf&_sY+)Z? p;ZδT65bp#S~s۴KX5tdѶ"}!-'ӠRk-%=(ӻ='wS pY1a6l0ޞ2os٤oY1qʟW.Ey!MogӷSeHQ" SsU^0[ b<]sg#qHMlmˠai&kD ֑Z#F[5:-Ĩ o,8J+ѳ!qeb߈ZDydםK),@0V;Z(B6} sD4МmZi9OAgw b (ü$HjJK5/{Nߜ}-{W]>Ccu$zEkl{~tTZYؖ1s%n5 K,Vp"{SawqF?Jtduz"kȓNv<\VR]H3#ƺ[CAcZ.e*;4p-x31U%~- ~Ĝ`xق*87s9 ߨrfF &Pbٿ>;|G R/yZ>:jy5Ww%yEGMt{y .A4J`J»h^.' &v7_r[txe}w` i MF~mC6mXyot5!ȫ q3ҥTjH8$ҩonE  > Ae>`cbLgL,ͽsU'_=o}T0Yʡx= wV(1_mYxemAtoMJ^D!Ť"ŅsFDhrǢJ(E~AqѦGa1ޭɾ )164 )T(Z >Yp7$d2q}?]/Pךi+[ ɦaD;^ 4C$i$} uPy[ aT';*t?r xXmDoԯtZL[:篹~_q^窢&6'cÀWD a~{R7ܕW0W+W'ٷ񧉹` VXVvL#'T <q` [X`  ҈3(`bi 'J>~;bɆ5viMVC"9!yF[!c1`6Vu7bXG)>{i >J?`[4%.nȩe9}Mtmx7ҒqVϷq[JTsq %hsa j=t-IU.c}yO=-8L@"X4h!18oa|ҶoD.J MO]zblB^nߩpWC˾շ(C"{daViݶ4_ LfARSwV+Z7$vFћж@MA%t8*o!i-d^[\ڞq Ֆ/@6ݮ?mX&D]aLf"r2gfjgZ]n=\㦡0 lǺ觑Q-;ߧ#)YڦPFm'MS yĶSg4k$Un$ Rn˛t&Γ}QIƐul:jyֲ&% S'&BQe\TȆz&p` 9C:-rrom5ȇƞU;['.) k'_4 /߽YWG@Ieg0^" :zw{*NmL-5%b 9 ?WO;u2x k4[ˊ4f%O+Λ>҂%-u،y=nJ7*܄.'ûF7D 1j ߬R8\Hhjh52|1{'dx0[d7<ű?-WR|vXҙJ:}W±'3Ȥ%@bڥ=U[d0a `ێa* ;AOO Lz8ʿ^Kmⴼ@$ՅNprDɋ 9NVVx4{z/-,ĚlRNyI*JG}L`z1"@Y=;MFW5_{'&5x w@5gҎ<&fmYy/@ٌ>W,6.rF܊X/+sCz4ٵ(bnr]K#_'ڸ׽XRAa´䳼|LAI46ݟ}/:R7,E[s q s.,y'.[g'h (mAg Dk) cA Ȧ*/9ĠQwTw!鏬}xC[žZ'dtH,^?_ȬU9YYުBh'콾o!6iq@UM>.fN\SWl-7ki)Vt8^?aU2uqzB ]"ڗd5Lj4?C*VEf9U4b:% 2-~L̾2?rW\e_:osf5'c~VΞ;H_aGTs3ȑRM5ER YMi諾z1yUV̆&}ϑLNVº6\?X`Yx`A­9p՝bkX-#WZ#wjuh?(zS &5OW3)7J:=s@ʳ eBq}cc5Z^gOH:iRiNA@oB>TntJ3T~m< @#+ظSGz6n!Z:5PIX8{2/ [sv/[inYqk b?gq*-•KYF͸(#on̊6_~0\8;ej)aG;D?OՃg+'Λp Jrġ^Kz }Ra uک&wfΫ2d':=|bn,Z7V%eVMsIV2c.qp;F@m~ ʥ038RCiʔt0ѭwt2a_LL|v/H ,93.9׮W~}zؿ߰*SUh4Q~*a׶ږ};" ½6vC1%'<#zډ407ET.D^(s pzk!"uHLPSؤq1PG,aL異WOdp:&β-c[r;Ł鎂0L3,aJXUعm!n;sk!VP!:9_ 6K] 8Q\0~'=žk 00>-jOf9D}_ pF!daG 8_Ȁ@թ}ӊiW遺^1cX\;p:A%)1=6mV,1kELJUk*P{ 0 *>e&8 1i ڂOC$1E=P8AsmY dm [K[)S&ˎn\݋ʹ2+ Fs|_(qEŻLI+_e1ҙ:hWY]n8>A^ ֣26ɖr ΚvP{P 06]hoEx56a5\uTe18>؃lu'ڬ J[^?E9U+#'[At6_{ۭh!'2SFp~p=`/a$_& DaFd)k25vlUnZ;io /fU*^7$I(ʛBb{ߡ}ez!1GCS: Fwd U Vm\i^ޓ ~gV+l#D932}[SB~PJ2$%( W}ϽڪQyP\aps`y@8p:i^7Ǘwq׶-Wg[+;d2Cv4P/G~淛Cׯݭ`r/EXʾ7{Um;FŶ͊m۶mۮتv*ɭ=v?Isε1񢚹_Gw 9nEV\Xpr:{g8ٜ{2- wAN6 [)?hy sF򲝊RFs ےAA蜾PĘN)"ZQՓ2CeZɢ\HMNrDnX|ז dM !WOE w *݋qDI@DVWwb$+R:Mo1+9 / 6{myb}u֨zGe1\W(,j:o~!O)8~ Μ]|xhi EXi0}]UX:1 uo UR`*h0&pQ:hr&nKh" M50(yÎH?ξz|@@ K" Afvg*$c8$:(a(˄âVṎ;gd.N0CIWpgBqj C%QdJ)_oz(ABa"ǔ0JdE֢06y*Z?)Us ޚ9/UAKԳL{oAwkT#}Rj-boMa<LO++ʁe MdF*դ4$(~8Lrs\fv%5Tc߂ִ~8'?Dk?jo6m钑YEAAl 5 M1Ķw4 @G@++}HTHy]5ҁ9`|G?WG0p] BRc6. ë`H2YWqB6{) !ȟy Rc6͇5,-0ycջÊrd7LP$2s5좽̈́e A"rMNӸ*A\a\b@{Gíba660]> ̭).LM ee-b[haQdNՏg6&~B`nR7r"H̡lSWN֤h"PA\r޿#A>wQzFIa XI͟O5;:B(#f}Ahw! @~7$ *<}> Y]:(J͢;A|0UF!}Uq@7㎻V]h-QOb'8MB?nzisA(r9n*54"މ(;p%T/W|(r67^to^ 5EmЈ0KW2M#u:5W$`[nK(S췼lyC$8)n#"0E3H>m)$(]]z4suPJIGnZ[E]!X{ ˶a;a6|?z~f%_ܭwg\^>.W G&-r7V_KFf]/jP˭8}(4QP `$2UP.$+Z?Z:=pKۧ"<wd4PR`VoݾM3@Hxp.sm qwfW,XӬ.wX]N]/4rthۼNĚAY6{(ALd㦔n&m} X #ĥax{ kwJ-D Nx`?P|gH 73þayev+QZwqkDt+,(,| hÛWΉ; U=6"ucBY%R_qd| o~+|;x-5эS1c5Bt iO+̝I 6{!Es} ocǬcʮ~{ U%^Pb.tet@'^ĺGu)*΃Ofn|L 4&*UN _f!f &WGh7㧹 [f7,+KL_ J5t_XRƅ ]M)1xј #s? `m 5[JnSd4m &>Yw/v>*gOw𨵷PonU-l!XKDc`tM ~le>XRfqzpl+L/5KH?gG8Q2x 4r r<{LyieoÕȧ@#k 89.հhjhD-DmNY_d m8{nh>^4[y08xŇ( [\JheՆ42XiiZ}bCd .]'S"Y XL29N_1L1uȌ2Tj 3Ew8zR( #VS떜\z^9_O.Rڲ&8b{^NޜO7𜒣H일.oll.'|>Xs/m Lf¡euQow/wC ^,@M Qhؠydr`ZN*,TZTpᕍԕr鎑::s/[oyUk.0ǏƘ=M:t|$[vxPA ?on+GO*:$ wE]Fq, r$klNWiT_RQT{2]0^>3͝JW bВ&caN{:_row1ʵ9=`hQVAșVk 57yVx*7kQsja ԜF(')lT0|XNֻRV9ErX"$س!`eT0 p} őPR/%| ),ƿ~^պ{{5eN5.if[^47Q t ewƆ/jبZ`1ں f%t'J1rfni#&vei'YYcKZMNrX=_˅S̜dN ؇r_I*8 hYMˉ$:'-Yغ} y[[|kc"DVO[D EiBYmiFn+ėBNdպ܅}_bja҄Y?T^(a2B՜ =PTHLb&zV.)"|6S0Aů)7ě1f˦J1D{ l[ F/rLd/_SZy#k1K ` $6{l}J #f)cQ}2_В,&I(g ;{cPrƬƊ<9?kA7X,OV 9PmvBN #㇐ggmUc"@P532M}:Ā_^y`Lc>[[lrQM]̈uw^v. Siiq:_ \&gw{g4$F "u`˶ǯWk 誰\ "hc"e`UfG# \juQ0qƞӳȗ6;=4JGoez{>ck@ۿyljOu'T=M;(KW8H-ĭ$' cu_:|I^8koaʬƚwҗid*`ڱ&k5|J=-ٰn\S 4+E,@Im'𯨻$LЪ1У dFrF5rS HWco͚)ɋ wq[OJ(o'Q==B%?:n7+&ہ-(Qn}7&q=m~ CvGT~`- Kf].q}l)JFg.~T6ʰy~2ZH\JV> Lv[`(J>It7i´^,|8J:^I0 eۙ"KPHEAPs(l|ZI/Q#)ϡcX(މb@3ZdM>+sJ"M ~e!Qb$l#i +ƈ36)(p<%c5/Q  _]t=_ȧ Ȫ}`x;T2Fljy銬5fGHmf+;PAw:n3 RuD<\1D$S i[> Lk2^"s|oqJctZ:Hpih7 ~S1ȔL0Lq/}͚8"3B%y"dGyzI܂tJQd@t)jlŎTVSG.0;#ZB_0}9g,۴YF*H]qMVEjYQkJ&"9uƟ(-BYx<;f}Cssufe ,6(ݠp;nJcsﳛVbn a:Y,c >o.n --m/Gn~w;cScb9i^Y9|>˖ u;0*/>boЦ2YCh_s>flh4kۑBJA'HR[@g)-!ebuLYOT[>M0ܵmUVu5S셩<7ts}0$رWr2P^eG|aVނZF_dccv@s bů@#&HX6Ѩ*TN?GdTi51Y0 jol],O@$NYTp]QmIUep c[!nD}t*v[S$od5[41ɞHHVD KtiN6Ԏ1vAj],iRҘ%)\cbnZ ̓M?BuZTp·$8vXs1ea?ö`ŊqrC2d+8 +Tl)kvh` L~$㫦;;?ixֱu2`&>E-e{5><%SQҬ2@Z06c^lګ+q,6j^Z8:Y+LsPF "y04_rOz1ęb%}~3v;y[Lqh ՓRJ,njL%3\]qWfR6@ѩOktRh6`C2_u:^_1'v!L~Xm-qpD'^[^_7U;iHSa H.9l%a"P7{^*2dɗ26#B ! 7 sߚڈ 1F2иƵj';0yOG3 U0ef*!+N)EGz[O(LzۯɪW1TӸ7 ]+`]ܨm9v<OeQS0;II+ pڏ@M FhTW^LNx-eeשU4XD)3O]DGݭ rrZ ;n.U=arCsYf/]>#T^߈whgO{_0;- )9`VblOEb+<Ո })®A\k`)/K)`"Q`=a3F\o h']XoqW\k-c9B_0c83Rkk":h-",^w1'OjsUn4zE.0!މ\ ""+lEق:\Sڈ뼨Pp09J)|(\ޘ+-"[w滟Im* h3 ͉p 5PU4~Tt[F2QRo-^!!ךࢃX[.%Ẇj tx=qH.RmƬk[nu䁗$`fgD\qHWY]J {\qUqyn/߬G3N*rRql!jnp&BF|3 d6:" xa| Q7EÀq7٤0?A C%陚qIϹic OE)ǧ_$xf%g3=n9gJ諹s1A`zT[NQj0 |#!Y[GE|Ә'3,f㶕Bg3b2}iBB9vf.["*玏"AaYl}kqiJK bT_'G6}$ $ MF {`1N7&2́Ɛ߻ 9c$mO_\$AB]Mj#}pğ)z_/ HGXƓ0Ög]=Sm8W2ŝ~}(#hlź-@rԗ%~Ok$qү0% `OGZpJ޲۵YW*\@V1:BPEAVEۓKRċIټB& 5$nW:;2.{ɰ_MFrd@rz)e}9jtT{Ӕ͵j 'Dy\Mho2 ,&@A9-}ۛ="YY Kg5?c˅*K=)F(^ȱPEs'Toq0 G DT Vh8~>*U:Dȯ|RMЩd~ (ݩ7*2pM3 ="ru@A۳}tFp"WLɷKroij˵^z_CS-1t"ǏhNۖ['|OYJ 3PFysC_4xQoh?; q wMW'r-ʳT#DQfߙRR~_ +]mV m{AD  sNy%^OF& % Zț¸ hĐ<mpKvJ ffŏ%œ<݀@+j|oh@* Q^tXѻ cJ7_ն#\haA-. 2h pvۣC]OzbU#H5sj$_$-v&5􋖱MXZYMx]?~"^r+WˑLJUb\|^75pQAK8aw AXI"-"4Gd~V"#JMjJ. $2팝ZXBhN9>mp_znPo+e/C s; [ 5_ @翤f&O4Une\)/<$)* ʬu|V_F2"rЬ(%r-?ΥFrܺp""oNE%%J|jG.Bx]97GF!fFc2D}%h6COժu}4wR L!"jB:N:ڊjȈLC$`'-3RX <!$O\ L??}.FR#+r+ў;mRl4U7HotU(.вxaVeʐuCWʀ69$={YmWh}lDM(X-(΍) Z\;/9_8NuKKOUNvrpj'gk/+_\a $!rݍY)A\|{?>:qxOe:EIV c-kWpӡF<}L5ĉ[G΢>MS@!?Dž(ݍ$G2| rw|[Y7}q5k" j!txdR"PO r邷x~y"=+LNw}Ĝ(8V$PqELqoޣH.s>u3jզ p?3[/OJU63*ԎI. 0X-b]gvL1[s 4ssXq*諆Ts&0v<ћeVLTT5,x"A)ښ3s6#A^[2(jBi-aL9Q mT٣C9EsI$D0 MVHƔ>v! .,&V# &\~ۆ WA:o{8+KtoloN9"Ăݦ 83!BLx^{r/왯tԮ`f4^N8QDG.9)6GC}ŋHYU%iaͺed Ê3TR̅(\Q qy>JG 9^9#/5c1nUL`eu4xS"Y& ǣ,݌($JSG5>-DtBOK ?)ķ3=}O]8˗(4JF&"X-فR_v>^Zɑo]M ATCbmAM 6m&BY>H^>^<  ǰ9G0@z8nS|kk:ϯ {;VnY_U7 -tz;Զ ~%?0>҅hV0N}JO#8D= Mc? Xp`&O iK#GC_X8c'imp3p3#?lœpX縭.*' #Ki[UZ]o{Gn* m蘽H7|BG5M>9dBk%8{L +>MWb)3Br3ew9Qi$w溶CR!)罽>]4:Aͯף1MWb\ :}0Y\AaMqpcGهYk(/BxI }$\Ke7K0_A^aF*)QJ[קyFEjuȡV#C#0<ob?p*2i%EG:Pk]bf}{048ء@1Oh;1~P"rR”PG;m<-#H4H_D~spxbwkZȷY]C+@:$}P(ʖ Lͬ B9\S ~MmXC"_a`G ^oT! ō&NɈ? |ckgZ/Y*zoy2ZjBHiϓ*tJ; LoY < qp5Wnn!Sfg(>zvདu^qYY3X^|#t81k ̋ߩ-.ZE[̃[s,_%[r '2MOjBNt5Pĩэ=6Hxڈn)R]ݘ>b&#QJaiгQhy `J]\cڨtm .UJ "5wzBU.aYRe&Vq)!7[ qdY,Zl淰׌ɼZ4è@)1vE;r3+0iuo\F։/Щ48[#A0p 3m:U+_6eUV3񥁄x BMt%~d.3M3Rm˗w`o`p͂T2Hza=I=!f2n+ێd2렋q_ +;3=_WWFNz;%߮}-=3r BI?;vo3ooƿnofs0Հgf'Wr'?M@Qs[bDJS(M18 - V (IK?2dQ|y. >7aNX!M1JJ}V`bW >G(#\/nT |!g6=rG&=IDُ\zϜb%9 įFcr}aYHIɻo LkݝbfLsr`™6}KLj^=$aNd[FV(^Ctn6 T-_픪ac}E zH:PgtBS5϶\]?v=(?/fe` Ibg#* #0zA S=+Sa|uX)wqXlS?pJ\5VʑD7Yko=E (b1MrIHgsɞZU m_],Θ7))y[;6Eu%UkT34O>vh"87)wXaK޼m *J&ע-O@h!b*3|'zq)M-<7+Ϙx`zGVѦa܍玖h{Qŏ鬤2E 9 Ic!N-ɄfuA.+xԆ nw Nf٬ooRͩ'Y*+>X,+s;*Bk$T4x֍9dy;?u0S0\I1ޯPtQ] 6hp[S v]85+bR<jH#đK8`K"fd/Ɋ "%x#* '%ۯ(w9zşA0vW ˲@%(H@ZDzvõu^4Ta9z`~av?{lMHJ"r#uw.VX}p.`xdGB>eC`|R6;y ٢gҮy q5uE-F +j#VE4]퓆!PŒX=(̍4[G4ɏ-pm^e8tb:^| `j!ͫu.s1w>pPtS/|B˗_F/VuE OrXlڌ_&=l1$GTwX:00VOK1EB\92 "m< 8!M0+axV3r΢Bwr\b=}lq %c{Ő `^UNYNaҊ .j8}ǣA|$sϯZ-P P_hxftv˽LqR~MQ1NcWfϒ\"lVBFCFpmН(qfi%'OCG+S5W!pעtdB ; {DI?+W/Tq],%EyrvgR ws#fEd<Ē"(l1?Bt+n Į braKb |Ԟ$#g:>]B Wn#ErRIMַE=g_u[E}?}#&3^S-R'|̝dUG`$ߑIb7$矇lW =&c~o,L) 039`bdfc_8X96]Ɠd&-!جܬ k1sf7Uޝ< Z{ UKYT:̭x=! B/KפJmpi^C6a PbRn *Q>sC?Vc1EKZ8StwmФS_99u!{]XK:/$J+#P8K3_%Y0|5#٦)27UrC FjY2,PCo6&C#c+ɹnQZPU9hx˱pRyPzWnBqO3&:l&gb2񴞬)Z]E١r?8;6d0"}hc4N=H8Z+)9sz"}Ϩ]g?O\<|H$m"Qd!P̺4arnh>++ƋDۤۻ6)/Hҳ@3άJH M2n( B-LOǎ3>S NF*y)Tp,r:HAiN%t&OX,yFQdd.vt *8\!-IOvB7 k;0a[ }W" kHʹ>c.t(ƨ⡡MAf~SsqKF#@׼VثQ{e&{-贩BQ!3͑tjb<G O1^u{F9 cR/Hv\6!Mrɹ\8&Vkv]i//OVY0am%.ڱ=onLؾ" &l"PNZoL3EJ['RJE 7XxKdwV\JZ)69ٕL߳\q ~П|!ʯb r8Xr[wl8 #_fȯ\Fbvf Ʋ`>|1U|LGVP:n犾X1:xk9?̿ko[y}m1eX>tOYlإYe=rlv,~8;O^[]H5G=xO(5w~?jɽ]2(l%q55.;f{14r^si9sfmۯjNZjF%*.ʁL2DE\y1~7SFN4?+tjH E=4%[V>~ݗVşGZy/{gy;"Lf'{kjGnsЗՇ=Jv7#&XB|;W(_;b%H ,#dpjްS4ȷA6r ֝^OE@5{HPK.o~QЯ) Әlx̫ Rd}hhl=?^o+)R} 1q\@K@k`i f?z٠$)tj;ѴRזLdgy~ba٠,Vw{QX/8KuX$. [gKٮ]Si,}XaJ6K\&ˍ_`YO[6_jhì!#sW(t^\i\b~I9_HuLQtLԌ ¬+N7\-RIf:Hb,4GzZ&0;?!Gu>L߫L-&Y0}h\y+UCJ]բg IP}e-bo.BT"Z'A`n]GSI+7J:o LQ,z,[m'x q_+ p& ?$_z;_ Y96 Cb NoLLXX}~߄ DK)dgm"Lڗ v?ZYiPJG6Ǐ{yX+82[%Jh>? JӷqDRl^bfjG+qZK+eY3$irɗFX ruxPpMp:K# %瓩azp7ߗ<?H/(bz>kc ,XYk"!x=p; J_)+[[;5d[V»\mewOn*YN]wf'XF,2d M\+oMEV߱wwߟ2DnbȴfπJ-v{w̛fxӭ=:)mzF[ko|fo| *JP q!dcm0ϒ>4ZJ4$orZ"L 3B}qCYs}?0sS5ﱌ_A+9mAPa@'@!.,05l4U= %J5{wY?"zH$nST"*Y6lYuRŮ晞n o;dJxbE~@ ˜r [I51~LHv~`DT1„ iJ"߷d};;n^_b1o}ϯ*,Ѯ $>Es3XMM!Q kʗS͇!k0_1WeFbI&w}.'yu 7 xD5pEfh2+/ciB@mƢD.M̴ɮGgɳt][z+1G{#11USesQ-3_ᚇA4&_(4Ek\}ZlHŵ+`N)bsɞ-;tЊ1"ma $ ]`N?+hu @<׶G+UT%͇{Q<\)6[dK0F%)fwٲ}_ w㌟qhx zpVO2 2@Y2Iւ5o/ hG6do3Fv:B5ݿ+9*eqJF霊I'IoFEw=5VZ|Qypa@2cwYY*ث3G&=Lf"_/(7#'MZjڄ>afO1 QvO>mߤ ] ;ܭSLСRlQ}zg+l +TX3f^5wcBQ|}ОE=(MKԌc mk:  ,`g g>1ê,cjk.*]jQyS'!r[¶,rlVU!Rn5 e-Lȣd2DD}s]jX);3l1ml `+xި3l39R\U3 DE.1}زɉFptFGMbuՕ$;Y3Sj`T'Z? ۻq4mc!ޑ?pP Y=j[L5%|2νcy%ų~X"{:/"t]V}Z9ct[ E?d9.Ӌp_ʋ8ziw2-.ErjB}{Uy1-rg e0k` k3= 7]#Oa#$.(|*I0rn 7U32vVخXƒNQFlOL,P&x9ثyPB= "E) U_3._6fi.4:g+ED)1?Zc:^0.Р߃w{|jZmf)г| ѣ<ًK:+De1]ۡA1v [(W]WfLADdmsocx@x݈mXe{.𵡚Hyʚlsw4M 285aW ~rS1ImЕ>lDKX~}MxmM~, I<%cw)`OakI+OS&e(-h%a`i@e]fÅ HzI8K0=y}<½['-D[rxG@IF{ddKãiz 9g?/gÇy2g|&m*0糟ΚϏC myFEBFɴE:֧UqEe~"_3Hkk`r"V4~s̔z70Z]/[t8}{;?_w<;vlVf5<Ϲq;>I>ѝ l vT{‚h/_7V7סՖs È+YoQ{A"5xSP|:m_62:h~vo+kKڟ/gx* i',. wV}K%6 \Z裝#K$۬և|ב{Se ;ih9Otmϩޘ(Yorz+Z&0]~ yAdZ蹶iJЏa5pOyftkDQn 5 -qKHrghyKyxmk,w :L+VR>Xd֊{799ĕ]{ȋ^#՜#0Q6rr z)Pyj9BJ5Φc :&J˹"691B 0^%qK]ofAϢUf y;~nf8ti"eB"ֲфX:X JIň@gz׳@|~yR!܄>qKWOZ{ہFg.~OZ m|jãQga4nCb5CӘ ! &YFQc:k(հ9eajo(2[ϻ-YhXM Ys7!H89*PEB@w,uІtKj"r@\Kc6X;5J#e%kݑ(H'pwII,'y"W%$ί͚9@ ZTϢRn MpB2=7,?i4%3gmZcdIafIeEwۡs"Tk/J)J,w]~ޜ]Ө(oJ-ςזTfXul (`0eHC}UK0Rݙ Wz3WBIJ`#kM>?&C"#E :?,D04搡(M582KGHgvAXڲOK;-%„m. \7w9Kn3Te r w)a/3J<&"M'ư~Yo7rFvEB\'7ݍԢi"@r?dl(NPl^F(Wb€`ȉ޾+&EKM)YeÌ0OYSK8,Mv`)Eg {7IpDg 1Gvmb*q,Yi@*8Ȱ)o4>ia?Jd'] a&,M V5jo^'d#g 3=Cp~oT! XYAAdxX#o-+_ X\HĘoK4!ag agas}tR+-(rRx/RM{^ I0* 0%rt 4r[f}…goc-_W~5JOL~+i)̝N!de)-\l$r=c(wZ2Q#'GI9=[q|$LcD5׹~yַt,kg%Ysz\@.ui8~q~fH&9m9A|lfIѓ !^q:kJ3o/;sxY![5s K6mޗhĠnk3Y2V&(3)d=45u\"KG^U'ieGVB:j@b1a[/-0#J~:`b2?i N_aOMK&k6>BI9/o XvTB)q ;PK3qeGN}) ?aP+=3%$/rUl{o"<{'$kZ_`qi0:t~ۜW,/IVxiExѼ,4'Fu׀Shn#{%넲U4?g7RnG|Im8([Ͼ!;*aGƐUʽºKZ v8܇A8!N1&QJ ^O|JR|0ڣf5(,mY !ye3u#v~MЫ tLCVGy$LRi&u\ EMJS)*rlXƽ!Bn<ᦻ/&R<َ%b>K 2g.:]bْpBiPFYD.\\Y4lشԷQCK7Ӎ#]Tfvߟƭ.lkUjnxѐQj9+HUSLVdxYWEӗ2E GPXK84jxf_|ZCؔ)`bٍKږN+eOMǤq)3&!"P UXaoX* }QCoQq=XTƘ`(y2e^i" u2Gʪp vqr8N \(_a zI$)iahwڣ'\A t[K:5Kp`elZ|D "R0U?~{ B?@C^KG :jj""bzMkf_XiAx]٧85,h KaI!8|%>hw,LooXZ4],NVHPL|`?3B}DT!@^zϛzAц7`)0"tMsvJ,ìd8ɿ?]: f?% Lxt 39!Ğuf2D*Q_]\XނMxzkm"S1Po~7!rG<]5],bH(Q'~9rrgRxV |x*I!)Au;5Z3|D?8CD"cd]Ga{ o_n6֍܋Ԋe8Ňtclv2Lv}ũ{8:$ctg5sg\sE/_AG&( /Zhihi-f5bCKo|Hٿ19ؙVֿ$ 0q{쉄u[>r^>)󥜕#< ԲBĚmvd" )Hh{dL()fee1"<VH[a5ojNߘ-L6|?"αUw ֗:?xQ"Kcm><ȍG_FrmVJ,Jmm{6}]=[>^A(^Cxr3?(2+(Uicnn-|zOc#X'('W| -S(uZ[Um6OP7XR{y/RIy/ӇIAvxmdCϰr!ћl8FB ^UO c⮵0po5wRe9G[h>^{,^'Ce+:wxeOaJ-pTtsG-/%:oq乑?qj6V))E\e|=+ IM)>+57u_E;#v_WD~(&j&W2)vfτx jpU#NjQT\'Z%蓧I1ڱăxQj#rMH3k jECF~ʐ+o5C I:]<@7 13~~2W.:?:GʟUOPhmcχj ݇;ȺQP"6]>nIHD҇MD5"&E2꟞* -rTV ׳ˀ V)!dY ӜU ^Ay[^P*K+!3Lr/]oc dcO7+(ƒߛ 8tbYzm'N嬿44f<JP{/0n^Ѭǥ.f SBlH6~OBE>46r'C$L3ӯ v n·:kK%_%*;-\1xeMǬ%'ax_ %%LҬݼ-HJ)}Si t;fYhP~&,5BtpوF@#=>[we$ڊ%r;_]fo:޼jc($n˳ ׎_[X0u|~N8 K|ơA#w.=ԕ|.I62[  Đ ^":]O|}t0/,< aMSNe-wL[G-v9nϋהLeϮiӨyPЮڋڕT%?W82:E> NAkCWZ魸O(FI v-0ert=,O 8АLXpc#vW_2/j"c5͋ڼ铃eGF22Jb) \A{Vmi*TW5< \a,W6.(}Şpcv♷d,eǙ6N10 S'nJträ:8)1L}((̘KcPI˲Wk\^^!o([)8OÔJYn\wM&[S]_i}r)i.'5f*\’Y\ $Ͼ t!S4OΩ:psH-Ba6,tD&l<7%ҊfD^[< ƁxDȌ[R ьƴ?ڿN*4x{zn^ЋOj1V򲣾qO+8e:+A@\dG :ewD6!HـHK69eå)~'b]ln{ k<Ƭ{˭ZlM+^"h1~ p0Gѯ> NZ]lLaL/*g}]~Z9m2sC;p3m(.pa.#.ne\!-Xia좣:Ra&{B-ӔjXz/)vG4}5yզLwލK%98x:˞Xŧ#QF{%o|K9:$C (aE q?G ȟ"]3xC{<8({ hdjSתo\E],#? ~ɡFputRKНOEFkDC`)>YQ l/ >>0qìۢqQ' 08iFA_(s2X ]Lm. kwNezISψvW2{8qٶ- ¸C{NVCsowDy \ke1F&/}r uP!S$ t~weOGd@'(&Z?׌>m~pWǵFO8FbCA2 Eh.6PY)CY-5K5}Zzs ΢:h韌o.:6.~~x@\ˍ Ö<\&(h:ObA3oԤ'nq1gNVo|NSB.b&0{ˣH= e>PQ$~ώ }H& |9=d{=:}P7Zkwu <~'Hvxjs_|.f_HENt 'ɵm#/<@ꛯOnk1LҴ!$$ăxqL!"q/+o(?Lcf0LN/L?D=85DztvTVEVAHditWhպFI^| k(&\1&| <cCEyOLYv7c}v/w_SCy;w_3+GA$ ԤbYiY(JD qz% Q^ƫ'Y8h$;Ԇ@-]wJM\IH$ l+#<]Խ@JS})Ȕˀ[_^WC^SZM5lI,@w$D20`֥8*8K OIA٘%t4КGFHƒOZ6!QQ[%Q|Fb'ć 됦#UqXۖ#sC%C*O=2fP\$) G0E(9sƽ6WY>Xی>p@ ¢`B^9|ۺm~8%<̑t+gJ2X:`cWBeVD?G鯯^_^;g}:a-o I6$a%D@ȫ>pz 2yFasjQ'^宍{rm}ך#۳yɁu.vrK[HCc CR%"J^Ǯ޻phsSIfLd L#P lka-J JӪ:X|NufϾ18gF+L8TzOHVֹ ^,7b"!I3Y~20^֎$ba26i\S*n]0.lV5æcov4(>Eָ5r3SaufnŭUt/z`ӔKpJp CKv(Y'mgwdc)ԠW%e(M꽯O&B[`NO%|xc ., qՆ̎KK-ࢪBw?| eUoSh˘"zm_ҏPGʐGd/bWQ ?2 % \`K: n>ȲWu zi I+q E? rL_#eDXtTVd '#H{AzUDpBF7<6Rcp $n[9ʸ!L3m6,21eG%`띕ޠօXփG8ZtѺKʊ[PcU?J _5`' ڵ B%e5̀^'6JtY[]\6&p 8fv3Mo·M / pq,˫4畣TbzG"ESܕDL+aQ_t-ܯ]d3w<`Pt\WOW?*=\DNV i:f}Y >vgI Y/cЈ\OYM$Y$ǻmId]j>'CKWRho%+qv?&/9}] ]'2RzXd̹CѐIh:yin 4Qm }C+ldx L(ij2+(6 9w*`ײ z0и׫P(a8Dv1Mpal[D "i:pqz~\'iZ'C02e黺}*Hb\mR5$XHnq2r)CUi4寯+h mY$]Yo~O͜9*.2?`h,5a|}]):6Vc&v 'M豈 eIiq梪1~U%ܳ<=n8(`rYC+]+c;7ƐJ2|z>i7,W֤Bl 0r.W%YEchr 锉KGlnCRr@X EG|^ALA>tjѻ(#d&D7T94 |_m_p1w O8;~,4O=o"^r^\&F𬰳-w"$E*HSl L G}m+.v|>CRD|Uyz9*R%.7&;($r"WMR0^ MCl/ڻV[^A}/uil[C:A:Ya'[5!k_B4_+2bI l-2O@ o rKeS;w^ĕ$j䔐* ? ]dI;p}.AAKAo9 wlt ߚKp #+3wͭtfCYMujȫ!t)u#T"PXwq'S &c枹w b!?|tl]c$HbZǯdy(""rj`D]Z/Bb] ..Gh0W5ܭ+0Ҙ,ϟyx X% Y詛s+7wFF+gUs.+O7Jkx/l)jO9N˫d#ˏe($<Ps>ԒFIg3f;% ¬!22JiA*#R/c? v˓%bɭ 3 X(8T4tm: Ơ\APt[$E8be\oHޒܤ# ӜGiHE?'VVP84wj s?Up3W5kĹzˏ^ck,X2ޟg"C2v֘[A4 $Sqnoi eFO%"K28;+G>\E_R`yHZ[IƟ)5k{2\3kNyӂFa178-Hvo\ǣ]cj9ZYX8H: ~eU:Qk]}uWV7rJBBt:t'*Sv>c8g˔/dzt\^4 u9Fdt_BP 1ZLG6dDI ?",^16G%wij鵍.ځ]'ύtMUMXk-lv{F.K L={'98[Ѝ:|p>;UmI-B>1  S_5`6뤹#3 bށG"R욦3<һ$K tjy,gIwFH5|M'N(7@\Y(G8s<\:y[x*L@ ?Jqd$0V9<-ՂՓVDĶiqMך㒎bK0ϡ{;iBj.r1Af8*˴ռ8Zl`!OVW[fn֗ djX؟c8p1X 0BG3kxTb| 7:'7\=UR-yؔUiL?U;.V?? )yib lfAz #wBg)IS~7XNHmhߡu%7M*.I[R&!M8 %yÙ?ow68.d~Bnjՠ9z-EDF(ơe䏢4,!Y)'Y. X`OXT4rRrb'h#PuqP7m-WՏc'tc^^Au,nqAh]>#o$Fpuhϗ^˼SM^pՓxPq֠#cN"gE>x>2a]hzծI o1I*Q^߈~qVI0iccbB<45iEP΅6ZY[̬)ԅ{@?}3a9i.mTp`qĦ9Ĵ"y,g .Cy唚Jnrw`/ZY(^g 0aσו<כ:W>o%gǾwv{ bʓ/7r|srS^oarrбq| 7X8YW}wl ?fFV:6o9`bdno [(+;߇Cm;Nv.׷n 5M #'3?ΆTP^'"57p!?xɖsh3ߤ }KéxJ_G2?UG)\"cHCuH{!hv] p #WGLJKWwLxhB$OKWz/WfٯF=MH3nO ]]xb2-ĆG)x[Oړ57M\7a!x '$G `) cT,룳)AhJP+j*Zc% EpY(?v(]#C+rb"1Z*e1WvuvJŝ/tLNnBU8&y+jSAʵ6s`i$U0w˟t]*'C94\4z)Ol2L*ඒOhE7*eY@zLRM#!s +lvbdiT6=J_|iRz2e_ B -)O%EU5xi$FUX4+ Ry\MZ HEA]k̛**ŌC4U;I "p"zxmv)f`ח%^yK==1 ۶AΥyۂU+/ Ю `]֖nlOQJwgqO i2歝YcK'"[P)~B ^ U'R[A˩1=覔Jℤqf('I+d)b.%YP9Hub>s3?wx5u(v?˩ @iݛRn=Zfȩ! {CmqR?'ys8VB? !6̵M{j'o3ג5b=?~j"jm<۰?^Egmy@@ @'u GX)A*Q-3zv ǤΒ=7l4\v$]Gd.dEI!~œWTwMHPt%FN{K+ ʲEhLDhv8o'G\ljө<uw5ZA;d'~k0aXFgU[!g2 .mNg{p6!ӥPDsHms7]Bߠi!fHYZp vCjiG[boU>$2,?#A]k뼊&=-n7`jrYg:TßȌ]U 2 ?-G5krsZ7@0$]4O)#[t"$j%Z l1LЗI5%#`}{>0  .i&>gwIG鮜!p38wʡB e(I9Hx1p>^Lj O7yUXS-YAtڦYT*(S;i X I586ΑmҜ1-kX) Z$Ib02.WBF@-ϒ:=:c[RV2TH1L$V}&X޿)湍G}uyi-@&/#K0@YH^E \ w$߄p$pgοQ_/o[Vƿ/Ƿo;N +ߨ tlLwgfߍ| A]:_;O8CvoYƝ`bcf|2;b"Odz.ύyfe<330cs I?7͓#)MHΑՃoġ^Rq-C/(f-32<^2^ *(}<Ҡ.=(bsoQ;M?ͱF@vMSgzWꤝOՏ+""iu_]YaT0ק~jߢZyu4΄rv %;4 ]#uJ"RTsщ!N hD˜C%1}tϰ}NUS} :JKr f&IyVLеfbR|@Eﮠޏr n:jP9WMbH2e gםib.pHƌڙ-HVaN~O$ $Oݝ_ʽ xLV,uYfiRu%=CĽQea#<9aPmqN=1U?aTqU`oH)ȓD VGB[!0#e=\kS1?<+{aDO; &Sl+ȕtPy;ԖyDL7o7x7$Jqi moS' ".ѐ.;3 AcPh2vʞDu=z6ِ$VOrxsq/>!wJi*zQd@8qm2` !(j'#FzB{4 ϰcd"ܛx>9MX0|ϻO[w..$US;~-*UBp3֫lfX dl>1)-G8E8FrA4YaIn6hGv}oyhH^TzIXنeI2A!_]gj8AV ?ētyџ b Ԙ4}BLolt" F ܺ]Uh.Qq WR#wmFxdD,67`JGIx-P!{=֋;r6eRBoj!-T##]q{NS!F`jcnw!fWfdB|T#9s|^ZȉRuRzMtR)5F.O% 85&uXes)%l-묔uYt37}pQe5\ݑm0(`bSrmW`ތ ]F+RDģTZ=>>v榕3˚![4p>twՍF)#ÄӇw4ܧ7s+ƴOwKLWW'ttTX>X:%]=C9! V[ G:WVEDs"}{[Ի0e;G_Уx/;%: rf( "-eL+tڤ]F ٰ')nb7Ln i{c 7v/B&|vPdf a(҂z+epUÿc `_ʖ{$M7Zy I;?n/n⮥8ArM"Ýav4_*I-ɫU߿VUxM+0FZЁyGL]8ښB (( ˬs(::auS Q I"]V˾x8 P6 E]|{/3fBhqydN*fQ_~=DCo#緐db FU ${Vm?].9F+F%?/VʫS7ȓSU!W+o" *Z+%`HZȆbu,ί)kd{?Q{<6XLmwvm"Pv%Q :ǰ< =Z}.̇}[u I"`p@>Kw<*܃M2! 320#߉0#f\be132|ck[fNN:FF/0311mC@pq7--_߰~_h00G7+`'b+VƿErQ% mO\ hHPK[}iDMFs4hVte)͑QV%H"XӪ`ne1V3JW-H'Oi+T!|}p#9>ck=eqտxD:;8;]n*.~kt9?m _iT?(Ǥ!(E&,PPLف߷gRoa0Jdq'z~g4?JMlTk:osV3DCv=BhG\]=.w0ڹ{R`oi5vI6QA] /~v_KRFW ]LiZ%TIVt"2Pq%a֛)lz2p"5P~&$95)td@IF3v S{l`{'Z;ѱ kpI2N^+Y]qylɇk8R@G}-׭PPc}O{T` lJUm!DZhSvN8Ҝ <>Q@nP̸Z7$hn5PEU Tl& X=Ij]Y]El}| od^Q']'VO^ð*e'n+EΝ?Ru`;O ~g;`y\Y8Ӝepu$qsk_hMe+HC Ec&oBfujI6@fTSM_W9 vIAz0:U$䊈GX6mjkl&w̻w1ќm)xQ6k`o{ SBmWx!Rڡ%~j6UE|;^dsJ5 EEQs碊b@{Ϡì0ƭD s[sWq=AfѦfӁgi'tᩯFkR`O~1+<-%E$aKG>5VEH KİGҦ5;cI$LJWB}0U .M > ,!aUz-:0V>֕0Ь` dvAYJ;8oiv=78Ѐ;HH( y֝]<6Doԃd]#]_HygiJ4^sُQ<PP_' :v)->YQ5G -08eUGp{8N bS3G;/;cV`AHN?Ʀ Xȝ;eV̠C"GbA P\iP%-X"6A;PHX\rGF/A$%4;ɠDZ%-c2 IlDv[F&&z3nVWZ,B->8!3x?^\;+~?h E)S5LĭӲkO^/;XJ22YI#[(On.z0&]wiҾR]5mS z3%LaѢy/wak,Uv72`sU+ƆUEͬzuw@0 3oP`v+:\m0O3_a^GRjht~_־҄φ)r[wA5=K5KZh`pO9 7Zl JA!UҔkݾ!4ŏf|(,b )C b^-I{/#mJƦ7 /2Kӳ]LpdO<(AIJ'U>͋x1c})_uŹ H0#IH΄7SN^tO3K`h$]` \#_?<>!(T%A`>CIX1VpDhR<8"UOEZIK]-%t:.xiNzqYY"GEf=s޺5&<Yeh9U*uc(K3xe]g8n=bW:a7 A:>CIiN{uF#kDd11k2]̣?bA9:aIR%ȢPaQd]Iv#~ A;2B0iD*(S6hbhL HSJ5kt\UGxd]9u%GO$c"[ώtrؽ_cu Y&Fe0 1+ްk=H+x<^?ׯhnN}sBdNinן~l}T!vXCzX|aS-ڬ2MU>\Zrqچtڟ\%SsZPty 9Y<5L,MLAa{F{F6w@jTD[c Et qéHџ#S;ܚ;rщd!DoLrlPO^NYk. J;K19UOb-*R*ή\6y+pAz52%W9C55܈ n6q6?RntCJIM9NeD1Ea:uf7w zQ ff#'f:YbxDW#OPVO|@>E`BCzHˇSF{%~`B"%ؿFs`K`#ϜIo⦵WeD p7W~]YFSK{E;qbq[lIP\c>kzW45Kg;>N@ڶyM[ 6LulV[Y)JrVXy]+rx+ )]cQ/"P;-}g3Z#`(H[F?}MZ{xȐW9\l0J"YҜݦ6퇷Byi4&[bP0#LWD@j 6q"@Ma=q %0(9ݮeٺ{5<~y}du:1;AuwTn4(mٲx;Qek cc蚎k*ȣAwe u{ J>GQN& 9 ւH֝`6~aV)HTJbڎC 5dxfE^,d$ k Ȏp#"rF[HB@藻9BI SN"6*88N_GWxcxnro s@ΥH)Rك Bp{:GoV~5 }Eemchy 20b0cD dzXB9դK0@@ "*5*Y |Ti .$9~vrT/|Gq8vQho@7'oWbf#-j{ 6 &:VxI;=~sk +`T__|<62dx0.Q[gUK-m2낦DT|ۤ7xS붥/szX!N0p΅jKiwR_\ђTg EMI ULsrH {< 9]>G|Bs \o{ڃKX7|rTC*S/uH$,^ovm7-_yg>uH ՏtSqqp{"GuN~J&ЖN=?'ҩbndr9G+i7ZFڟk)`—6HqhKFmM*Bɕbqln'+8^2K~D *6 G}KܜY:*^K#^C#$.Sq]wə}}aȀ74\G3$U so5upU{qaW/79 6P%]7 AVPҳ%@~>U/bq@ku ٸRljdC f9OG&V^epә-Hsn65+0%8>P."Rgs 2QD5)*7SQv zlŃt)H@Up^U2 L:qTٔy8W|]0RהJDp}\ f@,&d%@ ⁂ ?ә:D E{IeqF\ t " k[^x T"UNEJiZtP-l+}"7ÞiÕ$(TSCGݖ^qykr e1hJ#pI`-kO"q@Q,-D}*df}TH?.Q'Qe!ވͤXi0JګhU)\Iktej] W\T85˗/S6jVtNݧ0ӑQD7 l#0߹ VSuo+:\y錷Gs^'Loک__ ',ϡTKi2 &XLA*_L@Y W*@m(*yLW.;dVou -KfЏ8Ώ[boG#_[$,,mk"$V_iD Nyj5"A!}͹2H4I*T\VtFF':%]ѫGI5+G7CըLF7oSN؉PS3teNnwt},gI!'Toww~\NәI Pw}tvO߿>L6]jQ[*m%ׄ0hZO_1,A`c"E nkdjv;I`/*IjJH*1#bj%YSe\Ww57Bޕs:j&_hKwS9fA,Js$5 oz V+YOE̛;7n9ٳ($:mܫ.]QHoҖW`oy-*9<>Z҈N4ЬFLP WsU bH%LkNϺmV$KW6ƿh%}Ã8 @goKyzNQ{VQKĄ1!dg^+va=Zdb?Rk:"HumYhd/ ʳwYW$ƻ((HTC6 ;U2~o1=Z{]l%Q)@W(\Ev~%#nE̕UczMe JV `pd8ikjtjb&Z#1IhL=Ēͷ,?c$ h_͟.TAh&(X?:s% 3dyE7 8-`}h6L:h''FƉ]ɂb hnJ<.镶H$`Fg8?9;ks] 63p sA^ZUS{R)7,e QDϭxzs^@ %'pOekĻO.=Ju^(CFXSBBը#*5}g_5c I ~F|>(bx>NHzX(g]] ((C߻ٖT!Oo+`+vAlAu؁t+nrol<ՑQOGƂ aC0%ѫ}m^]Hlq8BH=^))P'_Ba-Dn=Ƭ=~^,7PD%܍Hy[SXд/nڸR!.T8bG C,wT6nr:rf9J$_.a,{l f 쥁} IwprҾ4urBܶ,5kIfq7@bFsuȟcSrx;:E`-t%j\DIVy%Y,$cYiL32/\ZDh C>T͎]'h}RsC2}i]ꉻZmKDW_p!RVnrpupr:.%[I\?Ox,tQN 3p LXF<>8 [4ʔ`LG%dMD1DTV 9r,7r(+ڥhz&߫*VSY¨AAƘ`פa|'sM5@193YJq=QmeS/("9967x+cKqEwU!T&Z4׋ W`1zGAVpK FOqvu+f m\h^a8(<>Er\@Z8!R+q&$2yj 2SɻH(SQ)~vFƓ/$\;J*# D!}^~g8Ԓ1س'_gN6KMLWTQ1Gb氄{ sYsH}^{}` \=ax"^4o*'l!G*Yqq ƄdCt*̚㒰mpDo?7rO6=K/ թՎV wD$o^Oi؍h+ 0qbd͝3sH;YY ŻWNE&7qpВ1n 94{e琉q_̋gws#5  ]U֋'/=n5Z"tU_|ӻX@h><&B|-9[_ӱ kFv孔jn?{WB~uJFHlwt*MrKιp`y .Ã&m~\iNa%=M7TŅo=4 JKMrf܈s!]beu…Nׇ \ZXBT[TS'~i00tpun~ Ơ,)/Er(_\G\gZY:LxY*#w@ ۼxo U=Eo{-fgW R#q 䋇)& D23jgP0c4(S % 3/` o?2Sdo2:Ukߨ1]11;>ʒ?Pԏ(YYI*,%ZrY5hڐ(ROU_#W"\_'_U`?kLGcл ES+҉wj/19 E.x )J@fLX׻+~2e !IKX2fd:=..^LF_S(镱~>`D?} L{%@algΝE%,.G'ZXPfSLp2>J $ V=d }Đ9n8EI h<e43ݖ+/idvijfJ?I>6hs$E)WbދXWtH7)NJS= Pt1s_A-T9g\ks9t0J$@3xW"_fؠqU$I>t:H6Bͤ4gXШ:nVt(znlĐ"8I5=VrYy5ϓS 5]饲Ÿby%3')&)meg/fw {@Ji)1'C +@esshmjN{h뤖'6)* Պxh}8 p(ir1]ͳ!3mFlN@kyY&ۦE#26jd *ihĖ$eO [wWzR\ecIpIUV"Aɰc#I <kJ!{@2Ȥ*+̫ Yil,Q3dja7ؕzkKH; yW̾n1ZV4{e ! c8NT 3ӦrW>:YebA[ +I浍S^ 'C=([>.KAǜv# Q6iBRAMpgیڃjZG-be8z0}EYGe< u0iSJZ xH@(}$z 4w_3-?6YJԺYH3B aiܫR=e⧤%}C $AY:HO1ݮ@kYܠ5HGԽAV}cQ_, ']?%;p`,kk?_ ̐W/Yݙ`u !.h {tɇmM1Il47Md mt%o2IxM qDwy*jJ2G)xq]^+~"+1I:onZsUi@-GKQ ôҠjj (e#ϰə#F23E$u;`"̕NHW5eАqltG !6mTHk.JF:\0&<RTt' ԨQ4b <0BVV$qÓݒe'-1=5胏:^cސVױIR(o*H51PT :_dn'/^Nfui[(".5?S3$tW80֖c uZz>C6|hfZ{;*”2tf\~AWTGcM0[zVI-u[߼LW׺o9YY k,,t}|w: #;wCK̬.2nϹ>tH>pCfPt;6ɺ=C>qdS*a1z {%ElovȬ+CE^O^4,_-T}#6xtaQGGk2;Ӌ eռ2o`C 9 D(6eFF0G/o)ߝR`SJ^#R`GGf-,*eu+Bd*:J/qV̤O~|uo*R8-+k3S [8?MKS*Z2(\-:mEt'yb>/k3 Ʊ8chVvhwW}I.P'bQ ;$].v|$,CӃ z*\B=-3+cbbG&7pX\6 .B}5^_+_Z9GKc|6~f|P6L$U;/|gr} EL.w:K"R)8Rw"}}xQƨLD9Exs -oz|,v⹋ REG,9dt]Шgp&)7%(=wfxS&PZ/er$-0vA' X\hB(b¡ Q{Z%Y\&b 6Qzz2CK'V]8OL kDqO$@Q{ǟ:.Sw6)gj `ѯh˧tE#/,';~G3]II-`GXe]ԁcM>iv.-4`Ap;=ۆݗdLV¯l$?R?֓^HG[߸A62Č&O>mpl@! 7@Wo|x&zjZA5Ey D٢i)y@>8㋛(xw  Q;7ב72e25>tyXTV?s#/i&Lʛ=,=nW 0y*5 +|! cGHڼNf(9~f\|~#cy*Xq/ j„ '(UWXaGK$e Y;o&wiߦQd铅زnqUe]{1VrrbWfHF$-Mb g%\kLR[Cщi,-u?oy`Lva\= bխSAQGf8aW,7v+YƑzK#AAdG[kֿqX98tK r&:&oBUXY6_W;I&R~7]7}WOq{3i5[IJ6tR_Nd#ߝ1Z!R AMӢQwraGȫXu! !תy64Ĩc9nލ3C%J~=C{avD~%TZ~s:?_.WB(&.a.=x*A%7(" Y8ɒ n=$3>\#¬ p6 y$ʼRRcp1fJ*kB:9 ?+puVuWS~æ6Rkd<V<cV,G4CG.JxR}^K~l Q" D'~^hMjPƢ&_hiq'?'=?a;kG:~!u"b8!efaD<̃-vu&KqeΈw:}G &=)xԓ~߀ qJ #ZؤUגV .޵'G\UrO|[‰]c>G&^{~jw|={<I!9ܿz4c跒SJ{(HD+#ׯ'D:#(ٶQ}dyѦ6(WaN+O[h~[3Zm{J4elݺSv~ᾊc8Z䀺 O/k j|,@ U! pToI [rC{[/ƈ굼:/4[M 'SÎ::URhTėWlM!EaȠcWPrNAUQͽcarא1ޔ 2煰:Lϳa̔XZH SzoHޯJ6476\ _t1gp?y:X* *e?Jan몉.ys 4 sI¢LSu(V+GC[I)ؗG;ONU_A!) /m^U>ͬTTR^`\ i*R;q>IGn5'rDf=( Fo8O>|<, ٌē$zt+'k 4 }KNwhJ$ Y"Twi]5X1/x/r|W\@-!Bh sBmRU{*SxSQ_%Ԭ99!0)> YAQ{!z,>l*-&[yFj"?]/*Hr,M7]#q1~^wkcyp/9qW&-T_ruFx0FV~*cH+l9~* e~uX?eW$] +}|ȡNyA+JUz<\@d%60T} XrY\ˍ h%,Nlr* F:9"e,+%VnmCz]D 59Lw^QB萄d#C2Ixy*z]յw.%SJ:NL͊9fk& ]16k@aG` xK UFseXC5|e% mx kS>waqu-ؕVM!EWh(_fTy'~f+n5IMCzkyoq72c~Ha㝫zOb5Z[/eEB^(kڷX\wVA?~|FP_nӇuvfdp,K IԚLW\FlWXl#t×iHpjaXc)L|Z@X&` zx$je4=?] 48$9oP \n ٿK@ƱGnt@@iK su<T|#X8787"o`pVIb/11?ro>/E~֛lDo@2r y&˾qe<("qBæv$$d^BG}(L̄H샌U4QӆΪ$ OdOOooכEm2s(vt5J&.ͯD}(n>w՟W?EZ.AQ11_ޖ>ft|?&.~nl!ODibgUvuY"ΦO5G ;܊W:LO%s aI)Ld&(]~ZDZcD?!ƺWpy^ RfAE(-V/kidwtޏգ,U{>pG泛Q S( l2G Fa[聦F0I"%@"ZZzKU(6o@͔߮ >Eik._[܊Jyɥ s_<3„y)^4|j3]’JfvŞ8b {ԐKAJBvhQ3%ڞC?}NƖ$>]9 B"!pTwD2^kn&X%E_Ȏ+Ÿҳ8$˾[A*.U *Foo epE'8V?ŗhd6Mi9hܵf\.s|F}Dԛ+(\fڻZ[;;+jؙ-@%,MI*pj[78焓RJ2d/!Մ;C0VIA@ޔJWJ{8m1t%~+j "z*$"be)1zG~i ]}RؗB…v 99'A ©pb3H&|0卭N3y+R>n8)ZIXPU^ū>%5)>?m Igꋽ`}J@a2ϷC2I$س=s E'7Ci~bS;}կZm姅 /wl<໶1uiL<\-|* YBn8H lᣬLƱ@__S>cr%G-Nӏ &WuRJ#@ \sGGx.o~Dz'YxrSO䎵5K8>X?FJIIzRz=줷_M|ac#25v æLf0޴#ᚘD@^^N3#3϶Ɍϫ% Rm6`LhC2?%Rj3l_kq3I5̤mbWC)ZAΝ/͚,٠-/gge u"wsXQ1&mYX2gu fsS_e 嘭ۘr9*#@ cɡy~zN݊Lv6"<6)vp\P8*AԸeTXd`sҰjk&3V6쪺n&۹Ne&>>g>*BˇG?(j\/~֝ _ W(Kr0*#ƚEoD2Aa4Y#N .#  z__:ז2ui{(ў~:),x;Ib(}Ǵ*=O=s, b w@hhwdN۽drr %Pzw O2dE845z5t]XA~(-97-ͪͭ[ak|+6j?, e|ّϼW.hwt:01zVaT-4hꋞZw|~`d4 -x|J!O&yǩL.nN(kA#?2("T#u\ <}6~L?UX<39cG(f+u2)j.S\gxD/ĵ6oxpщHNcy2lɰy2鴿yP{y2lvFӵ{.$jPgU$ތz_ 6kF|ɉ,GWELD,Dí3&A1QJ ^6,;H>܄2)g4$X1踚}RbOw?G剩~ W-韯\m)F<"Ox[ʪa&ٙő!&SfF Ktj ż#.O8Լ((`GĠ ᥇7K{V,t>\fJ'H< Ɏ56-Юwd2byA)9\f$jh]n[Z6u:4 F׮8Vi쩪VQ5i9*i'{%揎T[q~>KX%Tn>ۅ:R|mĸ8>C؄2]G0PoK"XꝳSG˅Tf2mЅQhcrsu2)8,-[&rFO_E4;*QCDv'bޕρk{H ,cň='&4bZ ֩='܎GPkD@}R1 6"z6氯k %v6@ p!߮(1ζb64 (-K"#B3^qBAA&zgH|0-HL_y. 6ˀ=u̿ LJZ9reAq6pP[cI܆YUe>k|T9=V!i$_rhK <Ғ^鱶vSvG\!+_mR:keׇg֜9)ڪkVBɰ1ћaXnpLuk$7f9wcǟ$kkd^YW5.!<銞.S>kݥĞ|DMG_gv`kfT9WٗD4ᑶ0NǶmӱضm۶m'۶m;ޫ}RG9κ*5ƜcUL$8OB\>#V ZjVpVF>QcY-IZRNnSlm7." m݉h{6KQ9 % SA@EXC{"b9Ϝxjyql"`>"Ш@ҒU;9~6ܾp(ΕN~78\~GgyޟC'<ᾴ(*1D/Stz~ӃQeC(`pV[mNaVko;!d: Mh[\ҖdTH:%^,O}7~AuUM4+ГZQ@Z+;p43wqd.㴨Xfԇ>0<**:+*W=! `(V=AZůdMe5Gخur@i?[—1xy;?~\j*HZu`3绤c@0cL>e|(n}ܼ7^]lkX.|/C,FfeFi!vnRZ8T$,̬۟)BSqcu εzޤ,[b|mi]8'fvCӆ_|&B􈒼4s8g);wryU(w!,Isg[$BSEE#ۢ,0n/c|lμhU"GO8ܯh"L迠4h HLhWUZ&֯\NK ,l _4} Y)_:/lr/YigWLl]W=p}Ň]:nȰaaJ*;Go:Ds/IMҁ*J OY}N9$,/Xjma6 {IFu^hT%ոGͪ蒋@rOo3 ~[kB|1lCg`Gcnmq7"Dlu}89VBcKbiiKz9iL2"g끺=Y<6ts~fޯ )@)lwv֞,$#>a%,i8`o7mZG!JYVo-Mܝc ['!Khzk)]<kG)ݘPCJq{sG:c Ă3SZNIq@Zj*TI)b-Z,Z|о{hd{ulAd%|t_d>#¥QFnK*Wj"048ΉKP(L='-*)'+O⚣l=L p&= AjE0/:eF]G$6}cq{prnfvh .xYgC[^m5 m{aq5KMwvI%4>Y!I>[_!}VU[\W3-4NF;/ҋVampuYu0:-%|m'++h<иyDJG_BZ](2HzLOJ17n}U6D2Dk&X䡰$~;ƼF 4EP '--O7a EyUꉼ-j?GRdcb%A؁nD $†"Phad߈miSgw@D:QtnӤ ᇝ̓aMq4|FJaPP|hi3נ dftݚ\0SݎK-  䃉(0q\k>,=M~i'\{:r%=d|1W dw+ڰrڒ~p ` 0Ji<8`zgݏ{)"ٷ#YS3|1ThL}b{fH1=\;ol<1qݱ]xR.(AM:c7hg?Ѣ8)ݔ,uz*]w`Na) ћkFi4| Guf#_18y:3 "lD1Jhլ\d#|J)51]<|=8 F,3XP5p׏Zݨ|78XͼߣXn Bі Sp==Fr?$h~|u@=LzR/0 !1J"\s4.) 9H"xBz(fci/9pkcoԃ*.OsRޔii=7@E2ꄔ/U]e%߹LųuEX\5h]&|f-u5aIFe1ë9\R8[gк>՜XY gUoPv%yș:pD wG,w\dpn8 J zDZ.\ E-AGn{ТTb%t *u)mD \*v#ȷs;1-%2(td]h*W'UԨIBK{)d٤͐j/c3UfAc:Q3beg)F5MC"qĕhǯhVnmv5AW¦v:ܖ\6$@55\) 򎬃a"qLʆ!g-b1,|>Lʉdɦ7#:#NP<,%%Mt*"|Td A>}c*gN@ft쾙Ԟa C0S0nKc6ee=nE܎}~簻9xG E?Η4^ۚg_wLk:Y# jjwA#е4C:h1od/Z ;J9֚e0(~+CBz\x59 ?rkqfĦ/Fhgo{YgD,ӑoP@gX@8? 8닰?xt8Yx7?^v dg#ߝiB'ףw?g?ԋ??^%NxK9 d[4mڭ6#ce<&~n~tfeW6;'zesbyM't=H#I Zw^~s()yj[T;ڃЪ&g2 0(a [OQeYo-"aZ֯yaiy{{>y9K:Jm'Me~vvy:znnqrꁂ I/,kDED9G!"V:L.Sw,WZ[ĊNp|)~ KKL bO KdNs"QZ1'Hȗzy6y^wTUZޠRQ+h\2 ,`d2kūP7Eж_>< u8ѦR;Yfͻ)V2 ȳ+= R2%M'Z]]o9<Ʃ4Pi<4 0˯qq]A 9\bӀ zy<3Pw)\*^,{0*#_iHr0'`ֳ^W/ '65#3b8 qwBΞh ͜<={=,JR*׹{>Jf#y6Bjez71_Q ]a8l ϐFM- ` B(k[6TtRS%qh 9ÔU:ª'SεeNVl['zbr R*A[9uKXMg*0{{6M.5/#xX!! Y`=zGnfq!̔*MZ u:r6 ʴS/Kkp:1WM0@}$i04V݃!QT 'ʙA6!:Ss[ yC{:iw6gF%@tS ׯfҚst[̈almww#E?i^ 4\J'.X% ʵzsOv$˪(%%ZIdchA|%%nutVt,37Ĉq $ȑ>0zo k<_ihnI/OfyH8,D9@*@l `[ŒmzZeGo Z@/璁㴰s={i\o=$l>3F1Ә7K$d[XK@[5xMi$(HD >$_h|>ig/@یSn*_D7"F-ifc|A(r(LG á*۵7'oZ$eYO7_b9X&<|gfҌth^8I􍶧}CDҌ%, s7 =֡$ysvFbJrM[3t Fcqd.u ]7PJ#^ϑw=捜jgkͭx*OжP2nC;q A+{wNz֛;nE&! 0Ԏ˾9 t]8 !q07B=-|ȈD8 /8O]u{Jq&!T`jR~8:|ib7gW]OĝMJV7CN2N"enu(z\ZTdZ$ais[J:\tpIr>>s&> NX^T!1"&g S"XZe/!00e>S6Pty Jgv*Jj)dY=ҭ~3zgXNj&~t*,wyޚCMwېm1>_dhۮՑc; {CRcɅMN(0SmU! nd`Z9Y=8\*?/nWrH2@ y$Nk1\QXPzqoSe䫜?j-zwmK ~-YxЭ2P3!y)/I;C߳5v@G\\܉)uY6obp&Xvo*LͰ<[N,cz^rhoFlL( { GmFM*cE^^R ~a$2z{{"j\r\!RZ.8q3/Ɓ|SYM(8A/ATV`XchJ|JZx{X;k VR,~lizJ!FH}?za~ܮΏSp /p'^"r3_6%UC(c|HЇs@ .I/Ԙzz9. Oz~̩.w2a׀8[͓~ %i dY(?_01:K?_0ҳӲ| GuWh@e/M*G%PK/s00~UuUVǪ'I$8"5㉳:ɷF8}žnqʜ݋5|fe8/mxy5K7:]Hww {5xAH.:sb<\78]{t%:,xwZX .(";A;T-Ը;z#=&TN IkUeGFLV {w ) b"gs+{$fdm ! 3Ӓ3+pD ļgV=F99pCӡՕҵ\I~ "? L *AR-e :qp mI&د}*Erɼј ߞe w֒)^r_rDe[56+-jՋsM̦HxWJd!Q0ks̹g/zaD(ӱ&4VKQ5Ed(*[l :w43 Q>?<7#(VZ|1kjCiZhTk s:˗}h[ 2?͔l/=9վVUl0 =V-v 1' U Р`(mJ̨:4rv q4M,;7/>0ޗ VšbP޸GqԠk'5-]$XX.+$ns)8%CBD]?ޑngzϬ+O/oEAl?,^;΄m&êcJ N:֘>accچm[@Ί%rd/'),D g[Qp^tPDڶ{K3kNk,)iSgaZ$+~LJbDZ!Xx?s4ȡ iՕ>xh]Է +k0Ywѝwf|r9R3֦hUMmkn]X ]<^ ?nE`a y:^'' s2~%[;2=v1@b*%nN4Ks˜D s,Z OËFoD߂v5IXNۉ s27q:-LI@䨯޷[Pw11 u!?S23lW04D]5 jtnD@?0h)t]J)S0]wP7*@I9c/x % W{`&m ?w^JuxW1q~?կY]rj&BIx&''ʜG?ٜfhD t$$ jǞDb qNM^D$ǼB@ eN6N^G:UuCaoS/8\0}(Bc:Ltvi+)a(]{Lr"qZv|Q*''p݃CCj(g'7߆@r#2 f1u)1MM~(@9z Gg`N^݂S> ʇƚ).L^'KTDSV#0\:J\ RGWef + >|Ŗ8K_j[皂uP@4R\TedLo-vvuEn{> 6 ïUN[ MX)ߍFUjPDBmn>ksqg3)|\x|nyqe%BCIC7ϞëJFȇ$v0Fu?giRLBx#P q .Vthȼ:>w:lSlT5?Vwb!,ҩ-й`z@"}7Fch]`S޾8rdOǫ饛%|߫^?(U- ʦH X\Q/E[ft\iClzm}z4PDpDrT,!zg%jK ah={U?eNE:, f 3FRRolT'Y5F߽ 2hUk%x(}!z6ZwaEё}ר塬.;ݸk 1>ޗ`t7~QJ;J GaR\l5f$$\l#k 9D?*7$x\$ \=&o9dLX=AW;k]#[bzȱ&_I 9 #=ec`Uak}jۃǥ`:l\uҞws͉[.vdwrGmR9b`_8zR*%\[&6k25fȈ㾾$tRTY-c\my'կØd͸]~vd)ؚձVο:.Ng>q` b9`Q -yج 23Ѽ)iyZzhH ׾(L`>֏5UOK; Omnkr 0019F~O1_IHf }6yO*]5W1W0NLk%-yS0bjhЌۀ;NlLK{ i̾T.d: :?e4xzMOajK~,_>dK1IӮW0rQϪЄ $9# :JR̃ 8ds{jQ)V5FiDu*=M&\2eK|.?B:oFV7vO*FxC /Rf@S],>5dwnMϢ&ŤuJ 4fWGh֤`7K*Фq*CKeo}Áji4%zpTSk+՛q$hHI|!x70*!oܬ''o0>k=DPxz0l@k#۔RH_?c+A+<f)m" @yV-6feFs\QtZll#X.tA]؉cCςQyd`tPבzH4&&v}z=liG}׬BɬMQȊpE$n<,> Բ2ԠJO?S[cC |1DfQ(=f}ƅRi宰3פ,fRa>C@L=..6F⋐Ro-2S^XcȐ2\y[vmkt.=%.* J!0ߖ#kpR+K\xMBvF33, 3z{D1nXk5^J2ҫaUH7!>ςak)@W!W`^66z YATIWPȅzWG^@V\gЏx<w+CSyF,1IƃЩt00υ78ak@T< :E%()(4=c Um\S{=!$m0CEֹ)H'F@J?i0Ob_bQ RQxf0f+9$尟9tkܽ3H)-鈯MJq4X<\Ocͩibh ~j}.q?>O״a"tWqnk D6g#_lfcw=ɾIQP#By^ӄ.,jrI6Txe\[$S,cHIel*T>I"U+]4D_9e2K!ոZ,pW$xP4OV O΁fL.[6m%eܖ6OPq`:yoK\qrm?q֠fUN_dsW.=lgC_W uM8Hbc{;,Q^RjRi+Zq=uuwsk ;hDd>ÅU CWm8k0wp|PݪF;3KxH[J6Fs4 O4p3מVY:vED ¥$NRK4XfqrRѣ.QgW梡-v}_ѭjbbrgHqpw{amyבg BpBh[+`!ZumOb|CLZVNcJnS8C:gT,8fp , . 1 ܴ%^[6lW4JC_mT$P ؝"1_{j&4>6ORcN]9yjΘ3=:ρŅtCuDAs+.Fvk^u\&8B_$HskJzf@j%:@UE1ܡzZQʵSU;>$붅I`|Y@ ]/{xjSޡtAr/+?pǝ)3zT m.Mgp8ЩT7uF.ˈOk^LV+O|`+^m1AmFc-9M TkJ1!軟A`{< DgCK7؜[- ZI>^ djЏ/Nd$v.kKE(}y臧V(̽WdJ` za" t'2O%kPXDu Qu;țaUxmJx49V t;E b==*vV \ +ctũ^-=ӟ:mUeHA1&Zn{; ciGt8P#Ls$$rA:v3cG7ÓPD~s(T'_=^ۥiL ",6 ڭ~1^=R16,أB72)=p_O0xsO=YGBO!S;?Q[C[=vSE$[䷵UM]rwF+E즁%Jtヒ(d;yI WH\h>2z+8S[q3I/fr L%bjFbhG)jo9cky  >5D(vk\(Yˈ%uq!%1'_0[lik+q{ս+5=_Hq܃Ќvr> N1.p{ Б^İsuI& E`8~1 g&:>D((ŵ3K,nf&{[+tZF"#iѠ:+G?:ȑ4sv,&n-;d!ٷ`z ׈ԫ2x|= W>ir.spfiI4l|gE00\ݐ4!NBtZHO^Occ;<%љab(PHzI$I͈$K#NyG5TFqZy4|24@AoQ2 㠐c ʹ7ȣsoMA\kQy4ϛ`2 C߈ZRzwk߈5b%*e0k}fFüFzODCe4RAùn s2O~BcW(+]ȝL5Z;lhY)WPRSŊh1LRWKvI~YċJĜh!.ŤVdߕZu(ȱx ^76MA/&^),]GqfqCͳ *H]eoMekOT))K1 (ѳ8KE7] 2+S$8rp\}mah&[TG/E*}#\|T/s">Gso3V-վzhoLa3c2)@0<L%ij捉Qių0R Rf~P:wgR̠+ "_g5C`%!C=G  A%NZ0Á5n>Q2o0qEϲl!ae_x=N6C9ac oQeֹcKqg؋ fgMtOAb65{qB1t7z! ]Cxў'`}ҴkqĽdcCn~V.[sb7,M<$H<#as.D}NR AĢԹ|r.ۗ8C?*zϱ &pBgz+!?g7=9zx|4j}[=p BXE&d;E[Ys"m|3,BJY@ިܥlZMD!JON5aѼSUMݲp7hsQ0ِq 0dC=6 =#n@ތ7a[6T8x/vE+?'WoJG1eZsZ7Kgeo{v^ږfx2-_g,onL/%,CSH>A!c̗,Ξ@A 4{k8{pW~/২1JtEnRxaNm87\Aa1htIo,(^ ϻprm{:55w~`ЂD2uz>=n,ݹܝ^İ)'ĄhێQ[;,::!0TͱM1 X=`0i9M0s<%sx}-H}j0]/ud6jojk[U ^ +o H @rk uk#'<9{u%^:ߝ3}%{.\B&FJ H[)M"WIQIaO o1 FtsڂU_JМU"Ê3oL#q hhUPzgY$3WQ¡Gɾ65o.W\8эNB} CuX+&,j4 ǁ)84.0a#($XqS] Mii/v]u<槰6Z'W:+%7_nD)j bő&aA>?,+2|u}LX*eOwSOs',.NzYN ܓ#`STDl 酣wA}~q-s9U+] ʡ4.F(GXB MպцƝo :klFUٲ>[~h~Nm9ojDtS*QwG>RNS9`3mg;#[]d:3}ck}u&WԤEX NWÐvK}iCi];S*rT_u(z[=i'rĂ1 _DH`Rp`pzO!kެ a5ZVV`Lɬ~.=%9 +kZ6Zȃ*⊞$FN?>$^"X=Ea7v#ݎiK7j4JJ,'kY6[%z_ޱ-rֲHǒBeK%VOA>s#tz첑>1yB仢.*,YG<_&x_hF$+=x,Ll_fe#~3-WA?̋_02U:+O˸_+z?MR'dgb]VW#S-qΆݱi2R)$QBԘ]uh:u^<<-1C%j("aBu YjiBW']>aV>J`i̺ѷI<+CnԌ.Eh͍qNV(+r;"A^םdh)r>o2>{|ZrWL*:nN:Z>HraPo!G2(\ݟs4iü{ i-jlpŋa}֣:S2qKkKzYFL<P!T'2a[h@b$S)Xҩ w3S҇B2,f DF]Y(Y=pVM m8noQ]հl# azԨ5dm j+]0+cbGK ƭkmB7]2M;ZwH,RY=X$6{ |t"X-oυ2,sЄ1r7+/xtgL2v<ԕeԎc{wUˊwsv+ {y .U8)m6Å}wb Ehd;1c9xT ӆ7!08" vh3KaE:8Ra:l>=.hZz㕒mڽUh7h›+f aWΟ<*Ri:dMJdžQ;j&xQm+l>KxwEn+mؚm ⤐E@C6Q$*Ma2۝)K-ވNF ԇcXIDzI]6#9Eb(վv*ų[m{^lz9mq8ZNcULT  BԜ@INrqՓR:K7pbFw‚AFM6 ̅Ek̓` 0x`7=!5{-HrmذĴT-nétz}>C91$b5ٚQhr5Gxlܟq%Hі[HT\AA(F0/g}&p]\7nK0HR>\ |F`y_1$*8rX[yzwP} jZϋ9Z#6<9U>[QyF^r %m*Y2`ֶM*t(l坯C=ɿWgi9?~t?9[#HKH.HYLYS‹!{zTVi9!(c$s])Uwy8 z> wQץntyV+h;< eHsB;WCR -NpzKy?aDnFaӃ$wX2]=qIΔ6lIAj(ٗ\9DxhsH ^[% A uDK@̖ |`O0¢pLSoCF|A sFު6%EFCv 6X 3oiUzd]obFH=08[)rUKݢ gRiņ RK$ڢ!`>`i| d`)qV$aYց3t=*k@Uok?ӳ,q&{;0̻3{hg!JhUFրC28t8J ʖɥ /@ghD^w>J>!i{?; 9PyZ6=%>tZӿOMjuX-EzP7`FKLD {ޮo ~ NO0arda3uuzLR|YzBRzu @c_'eNƳ$:*8hPo1%O9" AMo}:{ ݈} uV%)TA~@v"3fi `FAs(\Bu"xB$@j? Wpi;xl90h]ŸL_eGRg'lZҦ#RyM%(Tv:=e:q*6/@o SG]2JTa6By1/L:g}^%|ZR9lL*T3%+|{iג7[!bv0H×01B:5wmkxv^W -pK SmsZ^^HCǔ={kABܼܶ sG*+'H@ J=aRqLCb/BOȩ?&1d+{g#Ax~XQ]w&B;i\<|J BZL}mI? &9nZp"MtLɐ aZv_: xpSsaqF*pU{B#&[̷OQ 61mFtՎ2lU, Vqfqrۉ %6x[w_ǶvnC%&j`zŋ}{aھvntPUf- ۠ v1 QtM%Aj=q&3j|@ Ѥ={9W[26p@98sx41qVG {8^\Nj&OWӚ09 Mlѕ##e(?<l֞g~b";Iijh2zB]We,Ӏ2kaadyp]oeY`5`&>\5=Fq?J|W=+$ঢ়bܣ`Q: ڨIM6\K>/2xR~Тwݥ(g52|7U(q{GӞ䌑-f/d(,C2_s? _ __X? L_V1!G3;W2! ?Jྼ?WL!CB'V毦2uz6|•^P^_ !kA&h8gc*xlBt34q%/7uEń6Km=__mƶI=_O"جA*sy2 ou|0Nf}[?׳=De)`5,m2zl'L}RQ:캫nӳ(G]"ν'N$ 8lwń[=|eu#c̤RgByhbE Hu/MC)5ĥ/mlڔHB{p:Ӷf@PO MI3ᘡHơC\,4(5&4o:9ń"$ I< ;L\Xx Ml+XV1){EEX83|f.uCX?m¦FWW'g[ۇ]l/ r婞/i!ͼI b)7K_øb& T  ~eG QmwK0M5@vI 4** х4Dwj!ڵxXx ݆Eђgt-."Ɯ#-V/+fsZj͵upCW&eX9&냦 0Ky!OJCsDD` *)ڃp~}O@YwXGm?[E]ݚ-tlSA"pW+$Oˠ W5*b]!C2[Kҫ $ .Z[Y r^;%ƌDy]׃eD[X=Хt(PG4O~p\c^ /V}lixFoBF) yGYdMvSB|kf!,pÉwb$- .EZfZ"XSbwQ}JL8M QK\ye :%ʀGoQ<25;IA.Qr6p$9ΰսW-콓2r>3<4AyvvM5q,MR7;ޅ -ַu>U|h.iQQ^0k76{"?4O| fgPw$^. 4>C5T7)Y3r:>x.c d:i= DU@p7",vyPM~&ُ%eƎo (C("; ͍8#Tp˯ ?ĭh"fK=ׅQ_PT?"!Q]=7@K9ݬ;o/r:_x#V6B.Ykf1H5^QUidð5)x$&JQ%! Bks!8$*Ԯ/w ݭTϤVnwgllDlR$`Ih^i`E]]QKY+T蹶'3Y נ~3ì8L˺&wB7Ꜥ̿z9^'z78@T{ yYu>]&81ĈutiiaILSUU^&lEZ2)E]/#? lc=ygj29>=7|xތZ7VtnK. O]uT+OĉSYӟ&I+$}WG*ySV^\G?-yl3hW)X` 75JΦb카7UXDج,nbϬ_*o4-pt>FW|WZQ nï &sMiUYH;[:yǺӲG< *n C>.y P K(G qZ֍HH-{բXA6UTh1h5,9xZIY7`Kf7iSX{JCr_$KmoȆR+[=0|M{N4χ XhC.:}`&Ƚ >%'.IǶñA䜳gq!$KzKvS"$ع6B7sm,sQ=-A\\>J|B{Y]S E}ÆJA@Mz>v4m3,-:yuR3ƒVӲUE]:@JoQd2Ҭ!sN?}zw3K{MDv`bH0(HK&lS 7P$ ) z=R9 3^@90*NxnݍGyJ\btLnnl-RKkIzxE,f v*{"D>yPQUhXj1^*~7cXK!i, ?- )l-@tߺ$dP$r .1\Pdiۙh鲳c0y܊ %q8 XkJMl.l(. Q)Hx,!ҏ^& 9l R#C7b%.S8B}6]N16: Ĥ{9| IϘa 9 r?/5zM$Gix\m͵>-MBY(8b#-1ف(6s2tF,&gTj}΀ bGPӰ>$TS8x;>*D MMb,uohgҠbe*>w~&t0bNle,fCTQWDHH/ c5bBjT)oLYS6T76*yPE˻Ks慂lb/\UtɆ/u5'vn`zm#Ȫd/J~17g tcR^(#xH.$u֣ =&&dً^q7γJeKt_WqKh`@.>n`D cVFe HZ~jfmkM⛽³5-p+^bgq!4mAn\[([Mkֿkw)q'nkOلG*(J؛H"WBወ֯R >`s >cLD: xULe{/ \>fG~6 UY\e؏bdf0DC$!zQ*)6ulhE}V8Y'VP8kǝ^Vo Sp7vЗSw o/JEsB2 ) q|}_o.~@5h !ÔZ1DXB~cgˆKȨސP"xCEb | %G<'kDnfC`H_bl!=uPd7\(XGB|\})AjǍ:~QP0VAwSr`n\$t%Nh'za |n몋S t2qwwcJ0r8;`~O ar$CKmw+U/PPOOLlzݟ\F=eJd.u?]d}o4?ƫXSsl湋급dְїZꑉWG @j1$ T*ϭo:.=1Cvՠ^:(9=#"$ G]]B3E仺y]t%x2"¨uTYZUYmxjt$QΏөd쏖/:%Q?Gyu|nDfV^53QFy2wˠC`z(S)hiui 9)7.oWGxxaBiN̓ޞNP/m{ttanX }B"+'ˬo5]<2tk qM3@3GB޺Zj:z褮x "ő_oB1XNnk褝*V8Sr֙G;Iv&_˫ *sy4Ϻ喭.ƂAeG 잺 MNe;1h vool!M].E^(No\ds.\@1^ԑ4 f]`!Cf9OBP`m[n He)7CIK7[;AapzDy% j㋿iG~T~s 0$H$=9PGb?+w(wVJգwq}+Ly1/y$#BU.%>Ct8L'ڼ'Z S)lؾ;}`{lS9fg1zRv]#j}Kб2"Kzs\QV&jőȴOs]mjX' 朔ijKgS+> XNU= |`klaUoiKDSҽc `F-D15"ƪN/~'ctAUQk2e';3w'i4OAZ ηi+G\rfed 6r6ŕI"%?8DQk׉אAձe= ƃ(HvU?\1[sMP;mnEB-hv%A!{УD@!>ٔHNcT@Sk3~"kťރvMO L\ū}ʪP`,{)C uT:eZfBөPΏÙcʛ4Ыh8y:u^i' ݽONeJ)F=\$k2j2R(_U&(i/HXRy]X nrPaV?xǀ1ĆtÆb_}V i1o9/9i.Kh;?4soX0mXn֘plHL% 5j5LdjXǕqZnxb6l=^λ|'$qL{aPj/;0my*7ME/lWF]qm1)]T"~ÜYFRGs eZ7BzNO{;^Rٟ,/z6 v0G`뢂6֑<ߙGlSgطZkAb~L-x m%>www .[pwn%sd=yϙʳzju9+%"hOS`s/w]P=[J7E UK,-^~ 9x[b1؅ݶmYuO4k&JIEYiNURd+HYtElmrSSzvI$)߈QۻfSIi {p};ǵ tgGDa-l,l2z`o&fL}ӲIk^Hm]g 郸Fy6ɶ 4"vY *#PIq !mYPw5"Zf| 1vݔIt CօGdp1W꫐xfwCB2i%{6gGp5P{;WKG/ NݶN^b{&ֻq?Lcd]J!jw㳘옝pzӟȴͳ&͘CDQ·/N:7@v>sqi)+4.Cfth]4ش.胶J5AGr ASDmTo{^jJR6bwD/{F.㐵93[{b}SYyv.+uFe5 $uʰP 6 t5`k?vstkȻ"RkOպgjf.vZp|(D6M0vk3~mNBOF[_V&UrN[^bP$cKdmzlt/.*EO)&ddq`noL~'OqA>0X)ǘXH SlwcuK!(XFLܲe0lY٨V_b+]7|YHVYj > ;rI&*9OO_yڸ^fsf(د#.Z3q8%atr d8d(&/7R"_ 4d~>WWj4v"{ȑ瞯}*&"cl6:tӶ|yteL9 Pڀ&X}ء8a*|=6 a5&T7BbFjua\Crwuԁ5avR &ZR ;na\@)*ٽ2=c__@S_7zmdM$4FwgD5aZPәO}r|\8;v)՘J |R,,Gǜv %&1XqۛFB8/Ƨ0DF RCŷ#6>y%=dX-M!TFE!a<;R@dH8. pBFo9i(ꓛ5*1dӕa @"LeQq)".,ϔ{m9l[)~ XatneR6yJ'__^t\MΒ0TXD*@|gKX@cOyμ 9:niJS o+ zA&YJ}$϶MrjܢuCk>hZݔ6]/6=x 5k 6KAMUQK|8_hظd{Է18ʕ\IB* G7S,wRۑuХuq<1j%Z8i#ʞMaŐvN^6^4Z,iӒHʞ<=|c0<|/[`1[]vrUtbunO@Ty/f 74w,#NI ] r.l_OuZwcev :JmaDNoͧWhD?H]сbN粻DUq-r/|ˑoGQu<-N]ufnI@&!7 WU;#6G* KU7.]ʾy;-wp`r?h'F_@ e Lio| _-^Վ%Zb\oBy^j+wTʁMX x<ֿ0Fwێ5RwZ\QSK4F7BskeM=é&>YiݑVBjR8my_Hs䰻w1(/X%Fd I8!°]san,E"8FmIݥ:/&ٿ(# ~밦wJz -ҾFaѥƵ fKG:9=/b4u3m%*zaEWЂb|/}J, 1 ji߿u~Ts :RKے`g%ŒbeH=8?{;/ _|ucv_\ugagf)zvfy8bO7>!-;zfF!`'$Yv֑>ee$[}E`lr Gƨ98Cvw i%~oBRd%6Aѿ#Cb Pw"e@Zu&^#̫;9|]>cP Q-TWVvc%$j+t$VΕu%=s+#$I^df7:˃!9L}Sϋf`$P$y X(5b+2/_\д)I)I)I+g9 D)$p} ԍL"M|Ekǂ͑لN(UIbN?1n뚳{p%uSǵay9:\;rm&oπNT~staeIH1q^u <XjM}ӞA2y}E8n'Z0E/H'OFi)wLbC`]j}+Xa`ަ ߨ)2PjMȯMlf $*U(.<ȋ>qfmygu1 +tj&#R$g~ 'T*.|R!\(wz"ieVU$td}vAڈ1M.F2޵X\vYk,adFgiٶBe2<[AC`5/F!")w9;[!-M\2<Ѷ@\#Ҩm6|y=N,#?K+ .a`s?x ,셒3i!XXإ0] [AJ\>&qҩ&rxbp9C'9N dO L]p p羼S1]J@h/ E.q1}'(W~mJĖ8/XWz\ɉǭdus]%GưPAEiUV$3;z'PNE=NFG-Lj(AGY1`e9dt!箄6]ډUFXks.fا4-錁.j[(6 xM :t;#c?uxZmj(v#.o1җ0GC`KjaX:>bI)tG,XAL ܇jIE {,4.2n.xdO:Yh\O~ U616Ƽ;_`f&u0vg4MZz ] }%F&QÌHͮ?}޲oҎ >_. _8NjTiŻ.!9%g}DYiPNo2Eʔ;V:AT]&wk CSY'"z532tvhO fmҰr&uEp3M iMq !o@%_&-D,!~=J.n5 r9<#`*y,.ס0:c&!K/_|WdHNlIn#!ZeaQR+. Vg\֒ρ6W+,*&ֻUĸaJ ޏ'#'ܧ3teFx ! 5˾t\̭ՑniY-^G|>M|y)(1r3j>;.0 UWD^g/h5Y6,mN4tIe $O[r} Kq(l3+Bں?K z[AK a!b;l=&vq61Ql`9ǍTEn|ҞOlRb R%SufÍ`8u? -Cu.% Mm?UNq ƶQ>>1(g&"Xy\y6]2/Rs4@ A֑ݚN~ݗ4'bg▥8uڵww_4u RVvk8I*KTT(0ª]\_z \RUr}NHkZN.\V0կ3 :iFju$v=^R?)/?߶Դo:}thD{LU@Fd6/LPֈ%(X c!w$vex ^O+9E䝢:.`3̲Em}WFiC>PBb%'CJNmǀHZuN?*=RQR*-܊&9jDamhٗH,T M_[IŦCtN6gKwMȴ9'1K4k:ũ^&$=Izj]%ƻR7HŽJN!7qF:쩽.ʚ;/Nw'S$Z $YL ı>0 բ ~ XR؍Kuc ¶{C !\_Y$ۜoe#Vf];Yqn;Lt.6r䩖-ݟâr˶"?s͎8&eilYU-kT.awpBo<Ήr=`緒 #4~pad2փ}|Sl%S(~]ȏ%9JܒOs=D5n C=$ݎx-|Zz_?b誃em5|Gp* ~xu0}0e?aFR$VE bT8Hpg+ W`Lw_2)p yk0}Ln_1 f~9F4o!8 F90[,o`7kFw geI80;,ooV1&ˀ7lr2-0s6W_7-= [~G䌌̿ ߡi 0nvTc6_'9[vOh^eg]ʳ >K;-!uKPAɇ 鷺QqJ~>.쀥e1+lB5@l!"ĥ,}2yO2*BȠdiYn/`}-+r˾@˫̵+qi+)o\Û2sƬ?SԍL5t9:[OFO!t߄YSN! "w+g89 Pʸnmo9LMSmFEOaI<]@<4/h)HY1&T5>hV!X%K@tMp6awbr@WEۉ_C\]\ դH |+zv(t j3Oe(,zKJŭ),}'}2[G p) /8dCgh$+JpJi}2OGҺ$ICAd;pW q絪g/o϶Y\5X ilH',1qO jLZ؟yX *W JLT^'4˳nB#slt G* hXgtU1}ylt.FDX7=8ѽP{n%\@=7%#Z&mJ "U*%xzvW[Ԅyg- b%+DB\֜ICTU S좖WXbVv^^Yٽ~Y={0ҳ27-6&&7\[ ~ˀ7ȜI/{z&VzC, '3= @c3`g`Kj2/;owggo 9z~[LlL,,[e[Ri&ngV5ֿ'+-|HsH5.̋Q(-9`tk%䙖F11haEMw I7Dt !äldoAV29Bc _t-@' vP/fiԇrQqquv<b_g{1&&q+p΁5 50.>XYYPI"z䑠4ܨK_xY"8r8 0F>^;i{-4.{OU5>?(> ñHgntd~"du*6:`uK]$?d=ăWx X~~ˀL!);?7ւg:1 g#?SoŢoM.&osm휍MLvFFo0ZL -l.f.6.'k's;3;[+7!#`caD~~V?,o!o&. [S [ g".׉[N.664`oVQ.o ޚlmp702YalVϖY[8MۑŽf?561ѯN?o;Y]Fvo{؛dfag %&v7)&&ӷ6oMup8 `S[Fvor2uS[L輁3@ Dbq@ dry@PTju@m L᯦?gdaadhbp5~?`0`0X,Vk `8Ng px>Q?juuڜ-M6V'&˛-ޞPok54pzM95\3wp qSkclnP+RR3 ?8@yQf7MscԜO*ɯ=LoMl7&6Vj/R;{al6޺F 7s{q?rZq8|x<ޔL~2|S:{hl{Yk;xhbf*c3mTS\_gF.omp1s~Foosy6obGmvhn`m\t׼CP!'5>' @P &"E,'bQI*#H9@Wu*.(/*kg {kTʟHUE릲㛦8ڼ5UX!G?`ɟMEeů2*c2&obUݯv? _BpEO.u!x٘8yD3f"Vf![N{l={6M3_n/(c8 Q8CCMF=>egwu.h.~j d]) iv0O@ Ř_q ݼe_]R/v^"^I_,twxu~؇zu7:]q}>dy@W0"6o@qD)5 I-+w,a+(1\ׯJ2@ P7W >)ld$$& 7E# UP's /v\$M&Y@@ԨͯH?ʁ]AtA?:[ ~3|tύ|mWgH^ch.AܛTNJ^p O d VP&KڳQzSUZ[$Ԗʧ}u>mzfWpT5}3|w0чi9 j1!Q&8x/!MXȐ\ľZQ.,>`$iL@TUͽJ+MZ3w}7 Q''Eḡ(V!IBZm; iLuƅQjݘ"hKCp<*@rmp/ժ&GHZ›VU6\~I]\nc4.4BBf"_TqlL';"<{6aDB4mOV op=o8V(Q JjE .;+=<,BEpkIAQ_$ϕC1k znNӪѦ|*+t;I4v]^|5p9j _zbtcӱC*̓kwM3ޛ/΄(p-oh;:yiĎCG%qosAj KŭE { V$rH?9YT!qO14S{X2CfOf*P)'{ujkjޏ$bhu{LC_/nkp\%ϠL0y o'I *z2(.v7}tt z/i_pMI _A9VFp[Y.և<#tS{6_Rr#>oF= W*a1i\ŎcwFcғ22 FI?] ^^&U4xAV[{~ңhkpL0t( I;)tG7#ja\ /J҆;[,nRb+1w-Y\?VB4j"r %'Y|L#ފoӡ,ydZ!I9|pݏ5N4GQtY# qkM|C{_X$08k:z@E6QSVC.?:&}wc(k?"[䡛Թ&"p NGǮD5'ne[}:Qu3bERJ̵ߍ)SVTP~\}b=mnҠO?jaR]J =!E^mPwmV|&8F~t_MSL|{ PjܭJ䇲RmApܘWřPofύU A/e?ґ0B]@G} qy#wҫ y Np:H!t+2{Xx[.OV‚"*vK&C6k xG/=xZ&^*ܲ'ͥzMkpP@;JeɲwNg ~qh98Li]ʺRqy YX41FcyC꩎.UynDk]mK2, C^P]]f> ]iȣW88TP̋դvOG {R WۺJ~cq `9ȿ_@-@Vn|%t֗~vș2$,-㘈bW?h?g=UIgP% ң(fWjWI#U4o-'3%JYt#MƋNMق#C=!ۥ&J<~Bl:<ut`߫xvL;X^g#Lt?&n iڌ˻}ƗJ6%aAD0{؀8mݮ`]; lx?b򂏺0l -FݛtBO;V$8&wH=W-^w^^^DYߑJ@NqmMM;"|֥v!46lkr$ ,+Ss;#`J$Dj^>h6b`N ƔN\€Xa+w2䞫}L^F'|xA#lf.F0Փ]l߾D;n]9JM;bl[UE,utAbC:j~ɫQO  Y|FGc̊FGO(WW,s?yuRa~nc[cũų&H\؁26@k>eJ^x1l5M7/RS1tdee(>kNy;YX7[lq`uu.f,EDkƏp,52EdsG}4ER- ƹ%}Q(UIs2C*PPYK}[Pi;[Gny QD`r[T.u-RL\ji}?kSytbݲV*Nng2+sȝ|c.:V)x/RH)Abc<NX$Zb7P>TR\dAo;qc!a$޹Y=n9&d7km]~Hw=4DԈ2{IX;E;-F*$•]SA|Nձ JGAwZOb`NbѤ2DY8Vama凋a vK\5Fհfz's 2TVm4~ؒv-_gp e Q|CUO!]l?kݓqx@-Hw Vκ=7Y\'+^ec)^P`,m4KgG["PxfW(ӃZ#6][&2y@VvoY=GK-,ؓg: I'Ws(Njt"%? z^ވA9R$n$6UX:2`>ԏCnO-4 1v`4ӌKkE$l]k˯ݷj3OMu*mB{׎k(L]7UE2 T%Uj< CO+f,r^ec/'gG؋\q(_4x^qk.{2cyg1WC'ˢq{Q:IM =ZM Œ*w2@&:v\48)5@z˕f: Ѿ̪wwf}"k/؍<>SeK$I|\Aڢo賌+>diD <c.TfV54HSZn=:?bMo8D.r}B`Ѣ?nXE+Y]LFXML'6=m9%j0F‘^F6I>wsiu/\$چI%^8:Zۤ:߼'v%jkH,IoTex)#krd>QR|sܩcC8`1no- {jxEY#d cd^Ó:lcs9ZFؘoGi+@ٞ#~黣xk/c"գ@y9Ms[ְ\V9̅WΟXbGŗc$֟V6 څs_vKGܽf.VŞOX^`ãaNpus3>ә`2Kw\]\+le:@6U&%gG#.n+d.)*c2q|V,R1 zUGnځ;ѹi?d̓khɎg }n2ڮߦC -Hx6 wֻfE >ʔs9 Y (PDR?֔qp2 `t,U,2ύkJ^h6* nD5}r"b(0hU|P*ܰ\U/ڌOVS17'zĪ&upފǬ@o;&!K]{xZΒv#6 '^ڨ6n0R<(;qxcdAF} =I[j.dV);8Qن[qm"@{$k3+mNNJ"ť6G5qn gEsj\<Ǽyxyjӄq?Z+M[.[-8ߗ/|C%{ ASF&9%,'ڝeT)]APS %$ (e\6˜~O<4-_KnI6BxcɲJ`q9梯a^U/:0e"؝p58+rulVuԷus\\D:zYp)0{z u/(a؅e=* SZ ke(LԳ+c&/aVN&5(CE5H3ՅQe<4b!O>1'xQTH>=bP֎'ŧTlG޷c(#]~{uN@#Me;K{Gv>Q1O &A;Ӡ=| `ҡcæ;ς#7bLJ/*iwJ7K6Wȑ[ߋ1S60N5ѧ@P=5FWNtW|T4︈̻8LoEgEvꝞreù{c1ԉk+!g?%<had66{&7]i_Ѡ4tGӹZ>sS}!Ŭ_~ߖ :2b]yRh7ļoça=/0ԛ 58lio_ SqvR6؃vwLsD+ہ^ %hOgbȣāKzԓ{S!-2уV(+s'p#;kRaLg㪋A2؟ȥG |wG;t ;-$$ZD:I/P7[uOD.$Cv }=$ m+n໨v҅CX=5lB2YYWK,˧qwULG35!Aat6kԝVKkitj 3ZjfPg$3FG1!D,9";$Bq*55quZu #;<ܻ0<ob!in9-iN}?ZY2, \8  NrPc p Pr1tEFE#ϨG'gasG"6v?N8Xaj?CWH^{5kkc ;:!;kc:%k[g=Ɵ~1q2rws$bb9HXg(; @^ ͷf1~yg9Igk #DtoBq6QC: @u3*G5#+3##'3ϰ"3'"g\2?@ƀ31 8330qǾDyϒ?K4 l =)6FfGOqYOT]gOT?C'(|n%6Ŗ$Ղ v+=A$XX[uu^UqMS33~g8b.tVMd"ŽNa,׳txt&TM僚AbacHP^a@Idk6J ]#>%IWǦKb@x؇ptgf1r)VS#& #-]U%2)F ި$G y(cۃO&1.a7@ 9Cb 1>^4P[Ylɰer v "dט3y R'2w+Qا"֕54\4 bP 5ziAp{/-Cߏaz^ |w`j]YW:[.2s|J׺XYbB)|ȋ/ ^51ESzǮCVˏo= v} ^Zj#+tj;L )D}cfʗ!ul6*C.f]0 ;iAeFE<2uvHOyU "dVge#)pim4P8E:PL8VՕv k9qe֎ii'.BzGgKWB$0g <gN9]8gwM)?od! #A}³ԍatNt>>VՅOB3mmlmA>?_h<,ϳ M;_һ_y^u?@djA,~&.t`lotȁ`9~[X INSGfdǭWI]Syg+|x?Y6Afb_sׂkAklU"]kB_zvfoݓ2H2N&2,řՏdZ74xbn2^>E\v*v5\5jY5CO,ֆApdռ/Vbx>+N*W7߮UFޑVuտ*.D;gv{)\>}>hzבOϪ_{gŘV2Mґ-1_̮>1jɡ& oc.Ʈ’}^g9\5$ł*.+68$51r._>evTxfadkMv^8C߷د'7 x>Z8 @đ5L -Gm $-;JݝUiOCJ{.kb64y ud]l3Vګw^4>.1c{4A d]>Dv`S|tmzU9evj2:Y(mP/@㩎wB=1`*3SwJR#A*B Ȁ<oeaeh"fk/w> Aͬ*Nq9.NP bQY8)^w Ey|[h-M&Oh]җn}+r{v~ &+]wY@`i"xu P$gQo{ QsAK9Fz!\vi- 32'/K*.0aR`CYk?XLF'%Ӌ8l`w>ѡ[}~)?6h+>\#I(](B[q ` y9iNi?+T+hf!*Y&vZ!~WkhD8H.-!9FB I<\43BPC)KrOb!.1<xĵѨ-=rc$33,VRO$ 1#zmXi*Kwq;nKBivvyt915&GiG%sαy:B!7NF^ X/ =cdMLnL!&,Iw9 y&N5OfE"U9 /O"Tk{L껩>-y4{`%X;<}( ɻeB>۫Ē'MJ ngUv)KcMǫЇB^!P/r:nƅdNmU4'dY69bZă, iF=M!~*qD%3`H$Aes&K$ GV˼hV -$m. HNhen '?DXP儦P}\\rRoq07?:3D :13H5e<#lN;NKro)W WOͦI;s{F\5nыJ;Soɋ:ف%f7TjNJl1Ժn9cǒ[#،x OP̟`>u5:O|b!`y~@O*5U+ Nb˷]N|o$xZM!,Wn;sn fVe t }z>k 3-[S"s E(kC IUo@uvskNVocEO.E]~_K= {x7ݲg.q=Vofb9trE ߁ 45%C:}RV4A7 Q!a`L%8> P9g*%sFd񇝽rjv+koK8{3KI㴸LCG"}X7QabC6y%qt0!ߏΝp[I|Ѩ]=S @H S/LA{{u)8v|" &8?0EepA2,L3LZtܕ3K7ZW pM}t1fev5,5 @41 ̵}7zϰ4sdh,rW;dpugXо$n5h AV'W'0( *G}]SN;pKv]ɢ,M_$I:pB¬\;ыqց 2 |t6<؊,D#|ܒI)'7&) 6 鍴aQWۨ!:v}];L˖pA^$.Og7- ߍ8 CbcǗ";cZ%[NH#69ҁ-`@xy tVxTi?B:1LխYwG!\zq;2"j8m*{N WڭOFb|)3Nqm6T7)hfXqMGRBΎYű:ݥNyg7om߳ OBs/n8XaHKJۚKӝXh!F:d ,@.=n QX FˆPi:7ut_0gB㬗1'-'qFl r)f~aJ38-vY&D?zݳS:M[gr%Vy*Sn6 &xx@짅^1+R0ȪL&~NIc#`#m ՙP` )^MjeH}A:9jc{z~L`\?[w whv O:𙬡W&~-u&c8'Wm[*[(<ChfEv;ĶCczlͲ+bZ0͝R2r+<Ѣ4e$J3M!M\kA ;w ruX>~#pE[d$^ te=Vڒ3`[Rb*2FKf,KCey aYvg&<ʸ( i)ۘ5C5pG2:d`q#O5=,y O8a1iGN" sbZp5C̩Vqb` d0 yetS Jw|]  nSwqAs%h+mp;,/hsaurG(%t+ n*A}Rx@}Wo(I_Ufޅ-i-؆W)/PR)h0Ct4>}~6#TNGoݝe!s^fԖ: Cg\Űl_|@h&.CoTZBVvD/4U Y Wbmp<?iXhlVstww3KR@v֋ӞwWcI" 9pJ%DC@lNnU:> a6Dd3" p (!AbVud4~(FPqX^/cߖB`Cz1[|e ;F=!8EFp:}ePA,V1\Ɏ1ؐ3G9 K?%) gȃC>d dqM@W0+~;ڢfk}/i٦!>SQ˓]7ÿr$/LH(I1G~ѵk `f 3cȌmH: thW;C4cbN• ~d[@OVP)E72bvh]!;Ǫ}iArjh<$|s?4¾yأ%4-&>#Q7ؔzU*SisDNDԫ+A&ǬiBōEMx2[(.P\M !zeˡY!?n]DpG$S;^4L0]V _U  aB cpA(ɶ"*QܪtƇ:Ӿ->C !Q6J4=$o{,.omMt ?*^ srcR(gB$7Ü&ChZ;+p+bD _rx̝ l.xƶ擢uT)a GfZ%Ŗ*RZ̟'Q-*aqdc*7ⰳ/&4 Gφw?}Zj 7)kHu`Ė,1D$Sxߐ, | Z@tAriiHFdHuq}i+,R64ƶqM%*B dIcFrRPa~e+ NtX_Ǿ*ys!3rjZ ey(Ig}H'fqz4lx;:emqwb 1j5Ayݹ 6rI /t(7Zg+vz؝(߽pg=8P}&B5鮞tAb>Y7Sl#aIX4_s^(W Ks=:1`qMVK)բ:LQJZ X,sPst-4=mc;.́F[.^}8:,oӲ8bq:Ofy+/5a\ =jD0ɱnrLZ(GS DԄ =y$k,'8 ߳Sq,c4 1C[2(%"=B t҂,;ɍgpomO,Py<=k %ηw7wme[]hTEjU ϻKMu2,(nM} , JuScζZ{ˇ :{&N fHi@,R'f'i]{ϛPhkL5y:.+EAzeɄ)S8`iS*  ] ռiu,#BZZa3>wWW r>CzRB' % Nf !{\df,%BTh  t: H<y]+TK.IMb#2R+xjz×"; dê+p/=yb vR٧jsYY5^V6EG7uܷ;9^8OP^ax(.]ϨXZd_+pfl;jhA~ >D,dt:zybut8۝h!.$uSYHw9*FAhRpܗCb#u˙jV-0[(Wنe,51$΋Nx.v*|[J&-M-iXe:Op`cP: X೭嘭ע{:QW%ߦ9{+'-ZSp} u *x-jHH;O;1hp] O)3N5S{->(/3JZ&i0 iJ31j66brP=qHm FmwG(h2t9al2LӡKh$}qپl/EPz#] qtVo+&Fm:@ڪp4J2qXҹn MKrIJGv'ddEMqA(oB_􉣬 Nv~]X ͖GgBW'y4K}p9}M,{vsȿ%030 107WSdd adK\/0O0Ü?p # =?D{|kX8Y~kسצ`FzK6?AKLlۿ35GF7bbbbbba 1Y$XF3j%2uӺ*-sR}Oe6QhiHJGYאjPcI(ȃS:˗Zh__[!zxY<ѻ 'e~ċ#Rqզ"@˛=O$ľؾ_@Fcv46wLx̥ !0`rbbMb*RFj?`HD9>ʙr[4b'O&)|DR(%4vc1B1Oԍm=fx*,C:n%G> [UofzVwGЭ3_7x]\{Y|oݢ<]-3ǵkdJLNHq,=-syˋ.=M+۩Fi{V'1 PS~3N%88V>Ԭy?$*?tIy̸e^51[kuX sK~R7^У<uMqQVv}hG.d+\cjth0=-k3H\@&UmTҶOGgֳ퓥1_ 3F4M(ևK>F.p=R/ٷ+¸TEvpJ߽oXGGȔzbogCqr:(~~Btk,P0^rAWDiIi\OGm,/֏2"n٤MpU̅]aXc?O~KBJt">xe.#|fᔭ_jM~opNrCoh'i%6jُ[vz4ᇵφ+T4k  '5p$}JE6%iR8X˓q><kLcPW/5KfՌD28%U V{UYs윧Y4FBUUG)ծe0 lE˹o{C@g"+RHǛ[ fZTVQLN |54`&j ~^k|ɷH[rHϽRg[r&mP`<4åmY/zx[dmؾü/r]Ӎ@t ! d1yz"+˭Hc*#.W S_R̥lv~>ҨNrskf<{x XpJl-DD|fnK$UŒ6Ȭ\>7-.-6}XbC do5^ԻA_zz=G!\9K Ca6lVImL(.mS2 ɏsdU)~޸;4-LQVcG }y}@9{ Hm! Y%2["mMsEye RkEΎmˠBNEzn7sKkjf#ջc BA(EcjCK:#̣8v&e0h4/ fƝ̔+hTl\LE-%Ue܆*'exs'ߏgrˉ ž &bUd]36rҹMJ@~ Ba2{&?iN̪[SA9Ea.@x B%3VNk,̟0jz#*R;矿bidoSZQLMEFIVoWߌ!Yigd Wl(?QLVϔ D̿F F4C0CYY2ç?5vfßfdf&jP*$PjRFn_Rp)4Z ĸD \8' 6iYSӇk׹oVxNQͪ6bt:P( `Y ,7I:8Ux +8P 8 @ PHh`@}PPn ;;߿'A}~&ZΤL{r#m5"njQWPm+Lb[%!0PRU@II&P9ٴWz-%cfmjyNT84AGP}J_xcߎ``_NLNo>Po;`> uM.kHYto~`Cv|љ&\2/}p:ml‹gPdLa&e'C͵5qsyѺoz^ W|ϱٰM~=T'ׇɍ=9I`nB( l5D@߻M$oPOcEfuNwW> ×!y5qyķv3+vajPo:d $S&!puS "/էb˜tx#{ya؎!AjsJ41ZǮ1ţl?{O0K&WzdP3<% 8wiGx6Zի*ǝk3m\^fV7 >/y?O@דY@Ҁ~޼v靪S-1VBnP)yܒWL\O&A 9<lTȃ;e / N2` KݯGZbک'C[KdO7x9LOǹDc\g?W|]f]GL\!:k6{*3p-1Թ_>cK tG/n\A*#?Q~K1221Hy7|HQ*ld |:k8oc;. M;rSŀkP I*MdoAV&0XXMn`t8ȝk*wOIPC"2a3 Ewɂ}eZ ^;H]ݻļi"s!"Ģ >Vff*@!Ώp v(pҗi$-r0CK]5F@kCj^A𮬃Qу3,,|SPo9Ʒ9#VcS{#jj.r6{29`\gxˁ1*n:5MaE7Iy`,#H"kg,I!?R qC#2p|l@ln):?[ĸa;V"Y~D=İ)FEj7ִs閖DV,ֵ`|ix|;8Έr0 FT$ >d-pTx*[>r I>䫊ug :A1 @W*{{3g>U;ѼRc1@!8&ySݝH%dS*>eW,dr1O4S4H}gR^p4v@|k۶m춭ݶm۶w۶m۶m;sf9s^gUZ"*}NPm-%At ToB9@{ c>)"en mSY)1gh!]t巾"DHv:㯧<Jv6m٫W&yI}uE\c DDe!tդyDO.HA81Kyp5Қzd\@ye`+;߂+/KAUmhJ+}XJUV2u9%R'[ n) "!4||=ef4͙bLH\ƫ!΢n8BbVJvTsWzL1n}Z{{l#<;.ޯsˡD5^5XK~Շ0hL7zш&@4&ϏEe}Q8t&o+:j|' r5 eT呌1met[Հ0NHlIm]\<̿(Dz`8MlozSQ9K@#<^:K9i2lI;nɻ5K;fFrٙY1GmdBEsqT4x&Mh#f|t}%~z]G$g78- v(ySELFLP~Kt6u5 Ea1K.3P?Fd1ٛxwHTOxw7w<=%68ۋ@I~SB{3q>|Ė#vCpL2bH?+`⇅g ͤ$ER^BlE]3=ٍfXkJM#{"s<&Yީ"sM@q )eח{!av($],l ICcͬ⒳0eeI˖'NN5R!t P he?I7 j/xMEu< &F-+ՒuS%z`™l~e|Lkcff$S9so(5y(Wϴ[bh42KK7 @ ª\Me.a$m[)]h2ELjhu(,ZL aEJ V(!A։2^m,TX{rmA񋟧WW'lq^_gջv:!ʑ3ISL'>T Kl.i Hj*.*' X5 u辤|Or*9eɅV$Ckm-tFnuAfq 1g ,Wne&{h}3~Dkf5-xTma{x$[}6뜿79LA"v法(<5,)KÕ$tdFy,&GܛqmYh4LfI-o /@Ӄ3a(pȿtF仞Q|H;[7 HÎ4+<ں]oK9Pn0I>Pt&!Ff $ 9ڑV3M3/ gBqz /!hΛ7oc3ϴKmTó7}|o@\ijnLmԗp$xB k;vbYT*u.,-W/f+$SIҞmyk!ΓE3@BN9oxiAeh"wURWa 7HŤ3?%hr'jMaa U*L;|)@OŃd"yniŒ?m K(7׊LQ4KeLC2' nXC=wG[zD̵9TiqrUF R|x_̺knN:Hl<\_*lwm&m& pDȯ|95Q̢ #XT/RΔrW91ܴZouey5\a ׾}G7tUwZ_vxunn0"[[HM,R2ZdK?xWXuPN1?xe/i'+8̌WXT0]ѩ:/YT:9Mf32žt5ٳP^6ZާQGm }'XiQ 7 KYan\ >5{&<7 %f;7z:8 BxL.qy.;=,cStVgg=!(Vrת %N܍CN#j=O/sJCg^n~5+ |&R7y{Br稁S[YҺxrq* "!g~T0PG9 뺔ɧA fBa9;UHPжOf9;:`G1i4-Herd2d #2T^ K$H,xrLVds[]|寥  EqW]['PU2b>f ye[=Y?$%\$07~Pe~h7(d.^1h&.e:4ۥ҅!+*!uB42aU۶f4.)J['M[i:`>pu}~eiX'jml=pFم_؀*D~ '>W,sD~(gF}btjRM1c'A7SE&^E*] Tzwc\k]%(bn"?nX!R}ܗzƩ$Jlӫs,Y;4w`-e^?h%IlwA'<4@**wmx.y[Ѯ ڤ֚ęZN0|8Ń& @Qcت:AP*vK=sI[8oK HGK81`œ.f!fc%m}H~JFxi^VnR$jfumj<_"hc~3cÛt *Ɨ ݹYkջj[b{AS|'|sƫQp+YA݊XDOc/U03E|VQB?w^Q@_ E{I2euy߉1?( EyM7þ*}EόmuI?֡yZԛ XO(ܶ)ë BjdCzޮ):&>-c,LUW 3g ]6 :8/y,t>fivZఆY40oj~WVC41NdHcԷ~Y{@֔!: E"Ulڡ(oVɩwEwI)ORG:tW"R[t1am8%`F:G;hwoBh3*'cNfHg9)U|6P HRFUslcgɳQߨs7 6&RV-?φqw3oU+_D9WsA3Zqe=Y$2zR>w:70kjYލIڥMp+&3bS-7K wSsɇcwf5;4>q*^Jud26-R0J օ>yu05>%a/4\Z?C Y#d G_noB'% b1Z$N F`!? 7Z/+/7 mJAZw9bC^..ov̟W.4s& e:XmxtXա&d60avbtanԩإ2c8glJy$$qw#.!>jWG$FMčjn؞S-YY]Q~J,&sφ{6%%/5OcѓՄUeH.] Ј.mw|zط+wDz[/!> 穋cpO[ ~]eiмšUk'8$S!9ZST4/߫ @H"P ? ]NpL{BX :F\Z4v_ͧy ƙb2 6d>8aYΔ&׌R0U⌿x28=ft`GODeUkL|Q% 7;#Uq> jU._H$}LIY`#n.PM %0 .܃)pyԨ&qdF/ /IL :a+#)A䌯] $uH},f$Rzl/u rlӇY0wZ>,&~dkD0_zKz^\Czk#cݥ5hx#oHDgЄmvy"J<%kb@:?Iv^ނIl-mYj,6{@5J<.d])#q.*pVҿd靎VbO $IݬNX(2nWlg4I߁ 29)q U+5}sjZ)w,myGw2 _嬋.×wN98s?/!xRDƻan0Mx^et II^t* ?W+9r 퇃-Ȃ?扛p.jC*^IHҺ~gdŹ, 2yb"ےA3B\>4|155:p R>Zcycұ4V,Ͷ_b̈0؜ZF iȜ_r] Q=[/svKf5_uXȠQl\/:}\ (0.wyKwEb(;mNJ]Q}_~on$ +iyXOB%oO\hnۋyõ>`CC̲y7UZ?ãǹP.]IJNQ@ B+T4hzXE/KzsxWTkVT=7\6ڄu4T+1Isy+6爑l|e#:>Iᕲ6鵙icn-32Xna.bD"*M>[Á[ ,Pq0.$ԣ<4 1Ϭn>t|7]tR}QhaRn6o" 1EizR~*=vaY>3f\sO# ֗G/AqQ+(%W$.#"P_ɷ$12WAIl s3F_ db<"1Wf&fmľm mlmt(8 8+)ө]/әЙҙљYY9999ӹҹ'_|MyczUeY^ ;G=ڪ+=ӿ9W2y̿IWob_'p12_-e--gR4k.91jB7v~IzZ<}m=?2=(a$C9䰀\~Lni1OSd5#%X %!<ŏP[vAUc~&fW̾ ykY  `G9zjԣN<057Ҩ{3Əbe7L}=e== x?-%߳\cwܙgheyRZ"S #kuu4UIjP8*`/  \}7U(RI6QV1_o|}5=T~!Y Y9YN@<4VbegG o8*&ϴbQo. @Z9;]w\Gqp$czq̾<`~|U~V8.+//q0JIAnj쌙 Uen~$p)F`F8)j?|U?K}n-s8~H)^+b|\ܳr '^]CF rVN1j{d.z{~kקeUOwvE/27'ntm^=sn~|gYC~̑G!@4V? gNJHؿ/{4&$+@YցWbU([¯O-e>m<'_lfmӈ\ 4Qn`sydSI1@2pi Q K8+2x|RC3"QJC<+YEʇTƑtבK:3T UF|Q6Z=$]$V;2;;|ǒ⬕BGs:0ն {x$ogϱب.yp?lYId rN b`5}g4*.=\~qwGB|QSt;ifYT}y$=vNr)ԅ-㺉yBKk3'7jHyV'h4,cW/C6kZyV)kxIݤ v{zWΰ1T[LIkYZ,;b'1_- S"6.`iƽ$FnlP]sNϽUH;ҸoB%}lFqW@oG֜?&!0KNL!,0w$4fulof3 )߾MmŪr)6+'Ĉ,K:x>.$Y$>WA#17,mlY I CUʭm N5P=PUiǦ+7"M_k4d{-h2AiDWY@δq)ŸLg4_9}ؓRUK$8R*nν=pO_ 2fWS fVۖ4F;~XD }z3rjd<œgs[maOG!B~fq2|84rHM& {iC¸y;P BLgB1'(,Br#<VV䏍2e!yHPTM6y%%ֵ%3)dϼ +v/EnF[IBh)>I dV?WnP4+* kx"kAsq7='ndS֞rM;%g~Y 1Ēel]F`F%f&?f@טvv.9HܾLS`#?.Iq t)nq,Gt` @]$M/YԞ/V]TNG(,)/ՠ4 *grz2fY@գ@7,8߸5HcN<˜ê)7Ϣ94<m"=9'| <4`+(6KZ / p9݈v`btLE&ͻMtӷ-LB65m9HP8,TIW=^@#y:vʚy.,A}{'Vf"?%Ы-Mgn]u KiB3T Hq.DMA?%viޮ' }eYxۧD.qMI L$eC]{i>< >GW l%B6M:cf j(u Lx}q4ލKf#1GٽXԄkYG&cgm ͧGb ?M'q ,3\e /^L{̄;TK_Z{N38 y/"9 5Lгo96LH|OW"Ӻsq)aM@ 'PXU2Yg;BAn&'jJz%:$xlW*t3ݦՃ Y +姄 _'1!G39>$+,#ONӶPp\$ǻ^!&gרpm-C ͬ8$jι@{™9-c@"C[F< udp{9]y㬩&ĻƓw+c9b yF_:̣"JY4ʥ%Mmqi]3Q| KKA˨k|ѝZ4/ riվN=7f|jH:cu^ d (*"RSeݹzB*ϡ.Qlъ4{wM-ԋ67:4Z> .YrS)g 0oW,W/YIZ>٬x_,"S7a"V}|KoNcb$}^Dh&`V-c^11tLg<:0hVc\4f Ih>2 :K"~+D6vBe14rRv4\|X4[pFkMŭ3M]s-aL3 El_4,]\H~s𳎁gWf:ͥ~+.T82 >ªS:shEמ MJq.dcDfN͏V88W^j"Ls09J0Ilsx!FN S ׫SO:*Z/ܩcs"Y0-L¯n Jƒ%ٗܔ%yz*D"3G9)XI`8]/i|sE[v%RujHyTb8y[&X:eh [dJ;NKO~{7j0ed! 9 =m ?u,^&'hPgju!i r=75OBZ'*w`LI6Fr ZXH3MJm,LyIOcb`>] 1xmM-bx;'+$'r#~6݆2iySj s( #@m.eT`p[LT#`昿hӘN D0+;,"SJKi mn&#2)0gdXꍞ,}&RL|vqV3T 쏬L^wUF9d0֣R%ռO.{Ww.]Ѯp h# 2BL|3gkDᡨ Ԝ%m=겭_rdy4\Zkg%RK#DķGԖ:ή,`EfZ-N?:XWzٿA'SKىlQgV)M#s"(#+|vx^`z,Yψлe2*i:H QxgHj+UaEt_|; T7律:"86Γ %zN-:N3H_7d#WBPꔆ*O1~* *|6=w)c~e2,BAMG=!KT5g4 gfuPʝẒ{5_HP Z3ҹpz NR߽ӸȕÞ1L|~ 00N(E΀,rJ^ouA^_]~-oTN 6N֙tyRqT%#p-_z]cs-RQK2ڂYD8eFoܥ;L5 qַ +SXݸ烱4HLk+Ub>/i >V9|B[`aj'kԊQz5?u㝁o.O<2Q]دU3]t 13"DWZOvQד4s {] t09z-댕3%nYY&cz^*h9s6wemڔxZIl9vAe=|( 9ᢍc ω>#u:ZvV&C?yZZǁ,D0tuh~OQ=A,aCtlNW&FBd yw_ U+~塧~K涧~jHTna]%?qw vvԩJILXjɽ2(d ~Ӄ,<%dHjH ,V>Nr!hfMMr.^'oQmcj(0NܝvKӷm v?;g*aB3%Y $=35XBxqҢ)^R{\5E^+w@xXZQ.jCG ̊|7'txR$) ?-sKjԺEߟ0$i4FHq'#񁿽f90Q>9،ayo؀䱵 ,VJ%'xa`?/C~yc4Mz b< |U-$w|.i5k{8`2Iթg;蛤g8Gz}cl.F/*O,[H,&0?Rw˭'aZYߞN~Oj*lŸ/R*1h\*٪vN)CX0.Cv"aq 71tFɢ;M_v` KC觬 kvdt7k9Do~E26 DjtL9*(d 0V֬ ay(Xg<{mW#B|D>(lNpá-xTt=n >2T lNwɹ,&] M(}wb»*\D ;f.=^m<<[TEl@6Ȯ= >ٮW]$`r^Bcn}-WL[2|C haѠ6k.*.u_7kΕz S4^sPGY.vea\UDj,WڔONJ̰D|S%g3lj$"ԈLYr ǭfڐCt[ӾD# _"Frƍc1^X,oWK =l룶7BUٜ,͇Efd΋Gl@ڸSt~GI_InE&M8E9a*3Θ OWg䶲bD+_,LlZ}jBYY. u(ǩTD"̅Gڣ~✕dVbфmL#yjG PMj8.=eB?Ú]e\)EJˠ|Ѧ ɚO)5ѦI+BӝuB|i&Rk3aG*ɰg\DM,Jً-|SwcئeLq<_ks5R=Nm8/aa[G8QZ^skEj{?d) toLzWLC?pCR>|*π1\ F-v` h;P!(Hrkwb9h7?;|~*wJ4js2rjކf>!8:C]4{5#`k2ESQ]oVo6_f [xW$"@3Bߜ"BOrA(`+y 7Zo&q䂠Kť0sx$a!nzbxēG\vq;t担27a8+ ة؁vj~2hsJHOR?j:GnElW*2T.ȩz4(ho57$= ݂`?Bq:BY>(7:%'JQO=7GPO=;;|PbRVtlDcS>4+ 4@T{ /]i̕UHEA ~=5(K0{Uy,#"]m>Rs,l{s`%;*h`p#X'+^h6+?C\:Jy5gY݇=p`Rɶ E(H]~_P[5DkF5G43C5Ww%kH(&4>-Q) [J#'T蘦~~~ ւstLf^zgV#}||+X*YdRQLJ]Q[GBoӹdgߕxc_.fbNgld$tv6V&vNC[kkv5sw40v1srs2s06|.t. lmk ;ڔ;۔SS;TSǢ}:9-,%tsssh#<8:C!7##y心п(_jQnL:n_WW=;׿?;-`fUNJy=>qX?os֪R22V`c 2гmrZWɴXn}[Y̳jfZ\vp}[4`~7'5i[]=4⒥jhPJpմrlr,C `z`h@4z~  t!CC[.l] 8oY,uǺHM e&VVtHAOi/=37 `e4G<ti顬V<-B;+_J7l{@5@?~@QhO >@\_Ce;f4>ט"^9~_`W*/8qjM`Ah ꡱP~96}_kd]FT+ϚL5ZD|4~`?✯;kPl|I*~g5} gزEE@"삿~?Tprd^ff},]43 ;Vt[>9ggyHO1(3Uht!?\.Fc*c A2o1ϣӸOSl͈GȏU/ﮫѬCjuS~Gy!Xg.b!#;(dҔκ/M=];C}Y-ߨLx Vر?0wqP9.<@<69;BU(9& oRio7̿S` >|?mMn4+C#k6\xk::UkNxTCN=wU"nfSfy؄*5bNKsF<붪I\ּD}n3TVҨ#oFzL +YAp]eJ/Q {'6hc%#epJLODV[E%U4:مVi|Ғ]([f]ûWj~?:frWW* [#F;%ˏ bW <=G\n/wb5VYi>>01 bXژW1gטx:J4&˪È%B$8qC$J &o՟lKk1Iޛ/kNeoF^.I+;f̥\-wLucFyR>Q:$ז 8q{I%1ܸG>ܨFdESD_3yqg}IR<%LW/l4Y(T)u,'e;߉duֈP]nvĽ$1R1)Rhl.\5R={ =%Eb}=N y}'*&IX4-;+G4$L3wl*AS,0|bwe?(g0=$?ߔm # \]9_VzSAwJ51p'[jv .} 7Gw׹3$LG1{+1.py/A{ زۃ|]GΚѾnN֝!|zBUpxdn9z )9z-R¯7uopcO6Ih9JJbsRY'ֱnVȺ^{ij|b04{_>ÒC4R+2g =eq]/!„q7)p@P\KJʆ$%^lHZ͝D95-3τrN5[^3:VXT**S ;i)Ťgc>=|H,_WQZZFwUɝܑsjUӉ?0KH˚B„A~~/>Λ*Suy(nl4(n M3+V]+H̻f5\nFex?Bݮ[Gx.tR|&9ZZVVIJX jc,?=Zo>& (IhEh;~]Y(޼mgml1t;ʝ6pO#C n1+]d( ~|(6i P aţ3Ei85~nXyV6 /դd bإf~% (S=(N7o+'Ԩ:f$CXYWˆRnY6ژgjmv_Ԉ"NݯXI4#MI@%$I|ɜA:.cCQHL qJ+j4Kax'?@A;VO}gs,iN:ZM/YK}G!>֍>< ۜx\ΤY[$v}XREC n2kGe-1J8^Ȏd hz[r6zߏA\#?,Tt9r;ӭSԾe2|SJo~?;HR)kUSJs5SնuZtFKn׶=H?#yQ6?E%%>@RO(< y"PabC n (-y=ōnȃ.=n=C4}^ t7=yEF+ 򕺺^tYDfDF;^ VN֙HΪe3bN٬]ca %o൸rrĵnI"r>>ua= t*Cs>VzUXGYċ֊Ez—+_9MͥԜgݝ=BHLH5ZL$^`nM>|p?Z" _>P /G99y7$qWp\{ڰR{ݧ o܍>_٧r<|񏦇OȐct7w ar<{$=:rsJO<:?|ܼ-7rC5˕X*Pޏp!~[GM({aVڙTY/K8z$_OZȲ2,E-n]&" dL-9w՞̞2뱆FdzaoSdM:\.ią^qf)s͒K]\Q-ֻp{%j/Vjȑ cD>Qa-赢Guv>,s*vcX[o\܊xgP!*ѹgxQ|6bW = ۈLq$c8_}%/X]Q N#*qP+̖w0;}'ciG=p^;԰N+YpH#+׊Rb9FLWmNub/g'qPY~W5*ޟn.Zn"_{qIi̒}C+ M:"E/n%32=X4 _ (;wp΀Tp63 ӈ?YaڮF/=w1{H&[2[!J _CR0e9մNhbXqa`?o Z(Vw3h.?2>5g %O72(CTL 6o}:Otq!5Ohs=-߮x3Bvhda*"[u@a[Bx[_Я7r/G>itGjTԚ7.M+'-_I("OdݫmsUyF^KG᨜ 5`$aZOw+Ā5aoXVD,Ql vD% bsZpOFS%*s LcG֘#Ѧ&_rg;д5rVTSu3(;S{Q%\NєQO{q>:y#@ ñHYv/X;bf|*&?=JxFBDgO̠Ȃފ.Gs̬ʿfT* DÖ:6z6kF>gTo@EP^M~bw#Rto4kje]TSYFdSƻ"R2r}tŧo18 #NAᗕɽe&$|* %w Njaai97{w}37d!G  pX`u Ea}THchي46=bPhG՗ߌH. ^DwEL~N is-]$5u慦8n8A}B%2 -v̰w eH%pQBlY{آ/(e  ^.=b =GF2^7$Ѽxds*Ȥ.Ӽm,# 9\iц<1 O{eEiy 1Y9SßǮ?_1ɿۉE9I6` AH99ZIz)i<3m쾶:JQ (w$sXED؈ؤhC5ѥW(n( !D`oY:0=u.@,eZ#Ӕ;eͧdYInu&3C7TV훮&%{>ij9f6/<9 E'!ni)9ނ$!P̼2&||>w{>J*zs46V_Kj7/^&I '9t=5)znHW[ḉnJ3k{˩y/nD'Đ*'5phmܱ m !.dX!JAMLi4r6eH~glRlg*4HF2Epw4U)̔;g20:ҹ΢5".5L>-^EYv<"+^%̣uF;A jh!) |[ Ha]Wx;D{x*DA!z4 a7Ӎr;h{6Lo`,Df~}ɍJfl҇ji rhn'ø3!2{Ӧ@HJ+ )]@Z/ ̰!D=o/T.G?U s@T*7=x^>4:OW> ɭ;. z!x *@mw}p^PӇ =+tJk%..s&)dif݃}C*Wq%*SSnUu&C}kxAE@':}w9=P٫͞uK":\bDZf!Ź߶Z} `S@freWthT؀hL"}꬟J0n 5{eLr&7B? g974*o|&+bnƸ[V~ t~Ua5 Df.mшKVjCfnֆ)@M PŽ*F~I&j6W_wKd{`֋-w~k)O4(j>>񕙘wKF AkG R} ܃P&HŤb .6=Digju|}H'F $)~G KY82}&=/RJnN8r3 ,uQm|xVw7꣠S{/rW~Qߣۮe!.1`(<Գaq[Lԓ@Tm97u`Uxd{wo!m#d">ruRc]Z?'y,tL`dL:w4n܀Y$#x h1fAJL+/L:J[>!+ŨmJԗ-hO/̪41ܲma-"z` >^ӳJgЫ5 [Be9ܕ`)eŖ(Y#]()YIMѧKJ4!yݜ#96YGpwlwAߵ]@~I( @<;=q?KVo3P m4CGQQ5g xfo;:?@Mz&'n`֐͢߷+klΟ/~?ZលcAQG5%|ex~Iu_}Z|CJvz&ZvS`v~~ZO\c5ox|B r{N髭rm1`~<-BP{>Xz֟ L5kyN7zFRQW'[/~>ھi3;Y|ʞ!hdEvwO)RF !ؠ{'&@w M_ga0jꀷNzf628R8r6BV'ޤzz~Z>_0>.cڂ(h_E=i.e}c"bͰUTe;FqAEvj6;e.)lU4ZwJuGJ18vΘ$-?:.DJd og!\cmw*p 4v|?^'Wۺ<U{Qᅉ¢ErR)vsścUsQĀZS>b2|nh^ď4IGy"dXv6[ UbtӤ{*Xn>inm9ݣ `~-x}^v$<ZOn6 rb'{hy#񥉕7/jъ6Sh/uDQG%L~G7Xc=:LbWLHoi絖@e Ĥ6@K/".I%o^HPLg6T%Z+IOے^Bb' y]BkO6i\dxHj\:E|V~gFTCj\"씢Z1QDTW+򾖄+zg0*'|zBLh֫¯]r36T ''/7D؉Lkue`5DȔߴX>uU˒?XBDgwe~}v08ƽ =_K C$+)[vɟQ3^Wf@u!y׎+t<`P%J~@2 4]u,r<=9U#,}*f"lUM`"8H'/2~b:owjh4bָc "]n*ↅTsG0k~j|Q=7;k:G`(v% 2LXkg9saRڤTtYd~lȭQ~5Q i2Bs ϼ2]YZ쳺AѓK_ƺFvfSVsMzJ&&&'De^)'^FO^=q>|/EtY8(ңʝYBx7)_Ap&R$4V`e>c[/hTMzٵʜ0Sw?Ek`9^=YFP3Vr͚LJ<{C[Qzx΂-~l)k }G2~(Cc\ୃS' (H -2mkiFTOALRs mBLNPpaэKˉ6|-O˜ ZDz;c-`THOf=.iQإ\y!:9)"9<] WxYHWK7b?n1[M[R1gτ/±Aw)?܆f$@{/Y䞓|@`ePSL`QUTebyI, Y%V02Ώy]c/ۄk+8:i\F 8q$U cu6pvnEyL%K')@#+id)xҟ4?pF{i3jm3 ꊸd|69Z^()zo>1I$#]fŕg/ pk\p kǓǿIppK-}, Ẃx~b2I3cVH^աs fJ=!ς\PP v|ʇb&1;أ¦np(|K >|MϞuo0Wt':t<㍢UE57"y 47}Et?9PHZN-l_1txisuQ~E&>v3*0oHL re8]A3nX&>+16"l)|6`$Kеǭ:=}sF;:&uSAE&˒[uⷽPEDan$M~&wq.8ÅVHh X#:Bw Su;G!'b{6}ȥ)<[{plv>ZrН1D+^1wJ&w ȋ~ ?y~*0!!hHo 6&UFg*=QHC+۳[8lAwP΀_̤(&` |WJY̌1bjG,Qu=ttw ? #Nbmsm<0JH0— W *eH%x8(!A?ΞDždB*n;Zz{%W?, ']fe$}2_^AnؾAa{d,RI#]Xi+?gfEv.J v   ` @a=-lVzy<*̤*B-*(E?"qQ` 4cUXD妾8h/baVh-B}ABxʮ&*%'`1i Јߑ]d` @'LխrRZ3hMt6Ňċ=')-e_]}(j0N6n)K7˯\.A? Vwa,kz/O|OSE7bO$XD$3mF#Ñažݡ A$tdžIգ&]4<0& Qܥzy5W`sJ^/uV!&\tK9բ%Af1osߗQΧG dy$1sxI]ع"[ c=;7_\ fr:S% !uooWIng T쮓,c%QibBQB=mS^>7WKy][$IZLfE*Pao wB*ƴ ~'Wd*h>r{W&Cv^&Dq0dQ5ׇP8l~(dPEDB+qb)*/2y^|4Gm-:챏3$p?+#R( E%q60 vzQ:+74U1˞\w} T{1bva{4ɫ+|qf e;#li !ÁI]9c茠gW J N='q:I/_v(x 40 ۡtm|Ng`.q/, =9sۈ6}^`$=ߎIaGkJyb(s G: Om@x%(EE=pSfg2jŰ@K#5IÖb抏se Y1&HFg88[WՇ?آI錁lS<Hd"NM9 "D\.4E;"Qhh䰸cuq=B V$>Lp#@2) ]2i^$c#W?0@UBw9ABikgo }K]rv*֞doM|xcx܁("nE Kɘ~Pz|wZFIz /=e>a'xG/ldg6@DӸ1׻CExH|̳hO"۲씍/[ѢMG>`ץksC;d0DjlPy9tiM" tc"oNki"Dscr agMz x!9j\Jc ι:HI]hXB~QISݷ Dߧa*b'n:߆ 5zt "ּnG2N0/ǡ` X"s48`}G7w N۬dvCylؐ? ~xf^ۋb32fhrQGKD?+>硑Yr N q@P3_˳^*e.VrW,+7fG\ Ow.< QFK L̨Uq/d0h6tzzZx`02x_2\$x{ l`Xh|OgRf EE7NVJ I[_/™eiLRt8W;jiz3͡?xJi?GDU_ BTFFXLaF&k[L{cK7hSz|p[Ⳇ )nk? N"^sBC^AlOA̜F#PnXGszEVNy(4pfH`,O=5*|[û4/*Z}߰ =鬄_\I4#ˉYUiX-Z,Z xBf&}ga1ǢǙkuHq`[/%@f}8lX =19?-3;C#RgNEmhBQ]qNnYQ]m-Psr&A1r#62i.KnM>4) DJȢ8ьo:~I*(hr}Ҷ'wuڀiGjo_Kɒ[e)g4z$Zm̗qG~W Ur=??k\I\![\C ېWˊ3'`>T_aA/@Ap႖(MrPU*Y{Y OJTpU jз.AB=l d`2$zSc+Q${Bo+cpɌŲR5""(bJ40t{)Sˀ FyŶ+:DFBڹxg90T$U M˩L*,0i]] l<Ŵ)C=!+^S;v{( ZR-cw/LڊHxtJ(zў@>Ҩ}]ܶCqIBZ\NDJ3:)u}";IL׬ sc\'7Z@ #KSn,i )vbq "C4Nr]l~mww8>ab[Шr~s?`rW`)Rq5w-e4WDB~"hS '(8TfĎB}=kwXO {W0^'% %T1ሼxr.zPg/u[èփ*UŚH"HP9gtQ?Wy:r< LXν$3ɹFX-:%o֭)2cXx$!]Y8/ErxWΦ兂u9mifw1g*lm&[O: 5 PEMA}|ÞB"]7w*u XHt~ g.gi Cp^jk ЖIyl ^fJ%PÞy)Eỳ ^\4ϐ]XM|#R UWD 2}EP10r\5 @'|zIu@Y<5 *g%7[5j5\请ȮMZyGx4N!"=ex@SQ=n}д{ܾNIJk*qVyf \oo|̹5RI_ޑ/nTRN.7jm"ɶT# ߠxTbd.%Yȥ 3s;5σ3ӣL۝dmzI5ƢwXQ]YIw\5:`odJΪSW20 o^E"x\P׏j4{ //h Mʹ17 )1*XԥD&xoptwؙ@6o~}Sh .kٶ's.`d` VhhIK+ZJ `W_ъO _Ɋj+YNB_Cdſ;ظ:[Չ҃%ùDBodhlm{!ϰ WX?#U;l?c+y޿ǿ9@9ؘؙ j6N.^ i꬘llms[og癩^U-u15Dn`9ЀdkCcsjYb s[7kBBD'FFT6}t `hh0888 $vfQŘȏ^`ޟ[9rhfm]|udkn/ld^U223'dY]U:2jfFM- @k\ 28+zW61?/)}{x& tV1!I~!}S}+Yh-b+t#o͟^❽l~>~GYY8Wـ~Q?4?n%~1:?= ~3`h-r~NѴYWհN~u[7jqc.6B)gj↙?g%'\nP*ursQA2mT\:HOV6 2*:";z J6qkr): ׉߰W \ XPrrx`av_>,+TXZc:}Y潞تcQT1$NzґWp>W_p5\Xh!^K.Q;yyk8ThNƵٹX`Xզi-sXdmDBt#"o]RynrjǏG"'# K&Q94ȏM̶ c }O?.&K=z8iKKWZţ:Q9A}ȇAV(P Q!{QW߳6^a!ņ20gj} *۪$ۍ@F^"q֏|pMuԢU5Dc #LpnD\rݴ*\&}R:-f$]QeAygiZ60N),˩q^7G<U˟, @w VZ7&ҍOJ͹пu;-Ot!АSqs[Օ~7ukZ%#Njb;t|Ju<\͙#n+ºy0)l=VR'mڠN|dq|C1> $Kߏ&"!!owEJn,7.f $ў4SM:!&f ۻmpqOB4ΘTcsr5lSΜ޿M! )v/ԒvBd):1$o(Mnj8ПT]~EXR3͓+Nͽ'aCİgJӯxW:aIkqe.K먊?x9)[_)B"S,tH `8u eYf%AZ)M%yÀmȊ)  4%<GM@KM0֫4{u?G^j3W9z,-#A7;>NTDwča{H ONp 6Wc4۳X\(AsXR:'}SvzH8T $ybGe5-w{Jb8-)UTc&7ɷ(0"7½qz`M ~})ZA([$ǹ!Vk;4B~MEL{I2v9idACbmi -+=oNOy`FƅJ^* 0[_k0+݌iBFg[Xx8's)$ ]92|`cVߒ纛8N=OIQult ;y{_VK 3U;Pnek{>x߃H}~3Qm+Q5G'>'p@5w@/nzT7?=u% Y{RԥXv~Y K9LIgZY_푄lp8"%ޝ!x OYr<щe5@C#mWb4=2ȴ^hh*rV7޾v ߹mMZ4]i5G*I70UJF]( |b,y[1]C$5K Juh4ٕ}`?4iNb7Oܓh7:1iJP?cݖ6r. @-1^ ?Ug#y^b :({ط@ιCVhxz,=QH͝ bQwLs3q*5R%VHnI5IT&Bk^!2K*w4~8nZD&4oHcyr({ΆbIw/N| sSw ~ yB}Nڲsr{!wqSx7adpRmmPݍܶw&LLK3"tTmv-$Lp(L?L&Jwqs0cu1+4"O55SEj/&k떭"IgQ{aڎ/QhsI[eۿyF PE ]̃nf<AHeP2Wdwu!+̤ } \0!sl7\wK= ,>s$w]'UMO* 6SB?Bjje+Ɏf$-f8 lf]W<`.˜}\y|D;İWDpfWXԅLbq&ZDŽ?ヽU/AߞI޼{w[R$Fi,|lPҨ#abQ # "G+QC+Eq@D= } Zb(}ˊҴaU Ōr*'$E7'Z׌+F5^Sd)hrhiຢ@JR]tK5D-á}RhkbH \d礔uo_hMih?C# Rm9 D&ԶƒǢArU>Nd/&l&~zh6YtQ'z`` stcb(Rq_۵z=p3RAqq6uu}St.v1%U;LVn`lEl)( &hT1̣IhEkLdJvSBHbe>)?a+iĔS_`8 b0c.U-{ǬYȖ$p)ֈ s`bM &ylj,j Ұ .iX[O(u k˨Ƚ uF~M},Z3#?j:Ir+Űu\[r<`N[h"ØDâ~N7W[͜?!+*q|=s֬ )U| )2_5t#`?ߋ]O=iYȮ8Ѽ"{ܲxzR}uѨL u`@~d'iBjbf "$aNDA;ԑOƟ@mفFgbwC,qKJV_)hRjyf ̦{E|L \z} }RA)B Q<hnƼdԣp"EΓD8錟PJHN +:@;CSUx-yIHGz; аrww|A|Zy3 Ե5݅υrK2 4I\ӱ5{QPAcdn)CmqcPj1GqNl}A]^Ugu]`ӸٚE"n߹\d-YM6-/I [+ Tn7ZfB %Pza={p=$(;$(x=ļ?["i=0u-L$iRI+A**ٲ\zY#;`]YJBxn 7,RR@GvooZk|Ճ^TUƙE-t by D~5fU9ᄶs2b!%5:Dt8VĠMPd}}@ϩ.#$–PX}_3p> v>&H +L4D஽Nk,D ᎗ҶZĔN^"Bfq7Ee+辯 tcpC뻋1l@{Oӕ@hwa,^vbeʱRjA{tNgvKs)&[790Р ׅ뇤M);^2 j{tq&ꉯd>ݦB> 05k" v&"HHbE~8DFk?R wO{౵s(L-/ԬcÞJЧڲeuRʬLR!¶ŭ|hi|ǾTMny9ZkOѹ)XlN(*%.;ޙ~ _/C%+lE:>E&M,3,3lw6+҇sBVP<әP-@ImEClII<kv[3|XLv1Eo8EsbR^+k&Җ Co{m"xQq(t)xEM{[:nO.*"܆2JKJr(?*|}ÒZ BB(fiHQW_Yh|q#+s3D&ocp:NYd.0@FM qO,. q+e6LYU n/o8o3L@,ϑupNcy@PݍۓmEi,Q^3Ky-M|6 FPu7H)ZkT9+\ {lL;tmǥ.'AMaT/d4 R!3'yPr8C+Lέܐ@Oܪc#6B-x'2"aJr)|CWhVС:T8?J$18>TѭuakAXK@[pġ,6z%|50:eJʒp[{z|~Y]:B'J/FB&2< 9;׎B+t3huxbdHrP+޻ s?~zMvehDUt6ЁA {Lt5_Go͘_"WUO=WmI1^Ɋ0Xvu_(OWhSi6/=r;cؖ/ܿ[㒺Gv(!E-8!7HvC!Q.B1ݔƌOk+=/3Fɑ"iPlM0R%_6iu+6Jl:t-v ʽxwz۫Iヲ9 7".6~Ҭx+ uĸFl0;X)>X `l70߹PEM*fqlbd}9^m4H##WwWzbÍmTsg=/ASf y rxwzݓw'I6¦W 5 7./Aꢿ5G7B )X`7l>;SSzk!tvX737>#M9A{3qCݜd3"b   ̀24tV#lؽRwP93ı GΨLbtOPݦwQ)Y1&1th|!c$KlXY VJ$$R>uTZ*G㣡I EjFaz ]I .2w9-Ilh~^mW $xOQPPťlEOЉ [Tjz"'`7c)s* ƸdŰWvG ѻCX9hA MET1`vUB|VϭnwE Q̻zBpcFXA-:rs8 |c[¸vt`@}n&yŊWioIh>~#}Tn549zgsz59?j/> VDͶзDGufjwb$5LR7hpvYd3Ug=Muw3{iIӽW!S|zyNR wb!;)wv"9+6jh0ߴm?ۙf} |jfOX]`BBJFTJU^`6Jm47aah( X| nA͵ ɚ(fwD@FRϐFƤ`F-]jNO(vD*fnm>03eޗrw7B-&Ow%[,|`4ɳɺ ^ɷVse'RdjFH ȄaXl=:ju>˶T!zJ>XQ'.qf8L؍w[, Z2g OH8yr#X _kv#}KX HoH:-gwR̷ fc{T0*_-E84\*N bEO(>$_0*_\3uaIVcNz{Ŕ$D2Ӌoefjb Fj)5ȨO &(\Ph'mS3kM8^Dꈶtj7^ʠ ы>uB3Mʬ%:-p֞ (oDHoNډ+Plxd1/܍׳-4L1ݴOtp}βBW3mn4ȧӽ9GNqCYO D>>l6)M7\pNEys]fXgWT!ΗZH#2%J>,PpL\r=!-ZRDucZwR? FXټ: Fŧ Su02$E٦#P#&Dtj lt`DCJ+2S:mHT;i-ԟm5/԰C1Q`47>V&ȏC^>(^aoM ~91IZuhxC0&$><XHح}:[ǀZGѵ2ɽ4Kw(9Ěp3i]{d5T5.Xe9D>f?lPn$pD ~Q.*2fM,ƳB1t6)6$mVvKHak:|k 7]vp\O1+[XDYڦ>>(u4Fc7|:8EfZ`#fg1ǃMo7-G|$=0ԹDL6B*_p ƌq༺d5BԔ7ՠߣky6*NVm31 |{ly֬u| i95GGH;[_*2急'0v%\!{Дv߮|u+ug,=R\)S 4[[Bo-98g2nBa{ÝиAbYWK$ ;j0A0ʟj0(qvJs3KPNZU\_:cThi? 7=%9N] 8 K" 7>^&a۽ om}HsH[ Zy-v-ND6q@hgBg쌺YLf*ΤbZMRS؃6\&1Hc}Nў+;Tg%"5&d%Z@Q6Hncm 8&dWuTyOzm6o[-tnjp R~Y*FE^$+mOuꆰдAB~&)ÀEzg H8jok'-EJ͖LE?E?O]l0z׽/ Qi1 |cά!/eW=Au!30H{ ,{1&;e EPU] h*uMd^t'qPiof"G ;! @&V0mnͳ2b((#$PU۬dYL7܆1/PS*D8 >\Royl rI . z:-W:<5{Z L: L b˯Y2ݖvZd!W@AGMG`+|MQEJu(IqմzΩmz]pw H?~! ws+*bѵ{ie(rXgˢil缧ըJ=]YDS)) Oqr#w@Eiv.@ dEb. &|p/ڲ7]BZO 0trgb͂U11.ѐQbOJN'p.@6aBvv sPgq[ rAEѺ [A埗`(q 8 B'b3ªW!zS_$3vVɲTY3{b7ؑbLk}n$&q]hXTg.ThX /6XaE< x!ͭ1B Fc'ުEA/aֶAtz|z-ZI)DpV:qzU|o41!\>^a␈8Sߌvd+h ܒIle9۫W}.o3/ض+_M Jߑ_P!,,T iD/K= 6Iá6GlT$2ٍbiDgK{<.g^^˫PMOQ0lh;Eu7#%pVxsyJBbp|Oag~1?ds:E 6 AT M/jՊ4C=_v {&EE)6/B(h:+y/;$SU.HC{/HL5?FztQP0nJܜp?=[HE?SzoplHq^pPϼ9vf{|UՄ۾}ڶ=u2NO@e)Ew]g;fQ *K3߾jj֞'0,Dw =gؖrKyZQyvP6QvoZ.%;30IPNpE\,N§ zPBJQ}·J E -?#ƴB8g'#6Vv ϩ}b'qFB 2H@>A=@3_ϩ)΀G(~{BX\_/)a&m +y$ueF KԶͼɎ)?ǂ2x *߶5">+eU?ZYt^PB' x s;>rKQ}8YSx6IŠqsls: %!ʎdneoÅpw3:yƼBM I`"Ad;~z2qc]SnK H''j<)v$Q*nhf<ٯi ] j:?d* 7 1fW ƐO"l5ޗL-Ttb6Fp`p%@ow"OSy6=]Gu@= 4P>1e 6\J R!ggwWvde%d0 m̻@2MLFDz-_c?uzǰBй_>O<-۳ ̠)[ чyAc;{"cK}Qo퀕{nq8e2vy6fCە.ča$K)Ka80&Gx&/׸V @eYdB:[L0wKmm7*~j`NZt3CrAbL2~¼x5z؀%&=d%eEso9!Qn+zA EӑiJcALhkTSb/C:C5T{+ݏv No[UtsUO;h S9/*%O 7Kjc:)vIZpc4,(pKi!j;fdcݛMri$kA-fjsohqm%: n5l{pY,g6.CFGe7a$2jwoJ~BpZ&|7T\Z![ ^  C!sˁ6NIMnGؠXn]J_VBŵJ X+=ɉՒjNz'[a;0x9ij35"1pr=I@a ćUө'{NXSeWYIfOn )Kt_0zD^`z Fq{`{Ģ9z`r+b=JƮȔ)TD#<mta0>#ZJ9?]щǁ^ .[{Iرe*N=vDq4szch`> L!ThKV#6Ҙ]a[h"z8p}F]/; Ry6PS6N'!icwl!OTē6Ms(5-btXRsoBqnqPCU9Wfmxlu]h.J{`wbVҽW&=Z|pNԒpp6?$-ݤ: X:lxӂ H~%6JE\#nEuk"vڋڥtkU >]NuH5ůMJd]wWm)?g8T˯ TH>D*H MT.Khj*ePI_wifVvQ6>,࡚ɾaR,DK^5JT*%/p,,.2,_ S״u$"  ?e|%WB٩SqJ{uXoewbO1onzm`M!4id>tiƵU.:qX;%2J ң|:T֮HZfR~aE:*Z/Ư`\*E|!!Ƿ@BS&eI!!X|AC‰Two_ŲJd +pܲqz\/кhv"f+sE&oqϳNC;! 4qYXVY<ݥ-NDfMtbGz3QXNyiK1P&΀:6#U~ 37xFBUᖍm 1F0~ݓqa7L|\ƿ-Mr!8?wkʏ%QY}Ha_,e?3ppCڍk70Gz6ϤC~0v=,w[y8 PcAs MWI:?J令 3+hob~-,Ggwj;7/=tGTM n'lFG#?/zMBʢYo/Jp' D1Zt;eڛa!|2a ,s_Yvo1$Q>1{/F/\L ' N,'G^<](CQtK#ЈB~ gt QϤ靂{qmjRVw^ rs)py+Dy]T3r]Kβf?o/Ci::uϵ19GS<EM4?\4M>7 Ka{ӍC8(yRqr6hWͼcKV41dxX˪eCHDJ v/-YKeԴm  ס֢tBC0:'΃-$gX,wHst14ϫoL_.,q˺ΛmJGӗgKØBlH3+qůxgfL͈S #sN uXTg]tVdm쳻<+av OZi͊AS9Mh[#L[yΘ z`•ND:aod+ScMd8_~)0q4(hڻǫB2\u\hG" xSS ɦujJ3Ggj^WT<*,K!\Na~^m#]۵jX<,)n>ikI#7 ө  FU-' ;˯~ab` PԽyIn=Nwy⦈'/;8vV+jqogPvh } |vK9/~avi~o WTwpB\d $y@^iϵ? 8,0兆9tCWG|#ilz0<",+˚I,"q 6:ȶ(9Y #Fsӻ-I^AyG/r81_t:6B;-s쏾R`dϘG;!C]j6 rK ?Ż[؛6p=J9~eE3Me^%"N>_s^&T?lw柫)QEmh4T7;MTw7 Kh*Hѽl鑢KíhV=HL R>׈{b3]kUf3ڝG:~3-2F] ڏ;?2C[U{-CڔNN̫ɼ8/ Tw+4; Og-]lI8X(1Y)3u|]+ ږʭ%Fm (J6Ń@ª 0J}e6y PjӺ5$ꗢ0,[ؿ.ci:S/[ J./$dm 0=Ne?YeJ6Sunyi ;6%:-3'ՔRM9+ %6NRݸ*7tu+yo(zt)U\KV|uiM ^HXv G׮޵ΏN2쮌M) o1+6Hulo(nb#i/!GV~:s%Դ^41gyReL"Qf`^nª/@я_`Z]-Hgpv#"Q4dSN8~Ȗ'^)Sy3J2,VT_=fGbbw+ԬCHwa&y긃\;Ѭ Qy2=ӫOvFjtMkWc4PJ O &ّ jGw% ;֌l-=kS[:Iat.МJ_v;h{csAx $5,Eiu RS Sk8@W7%4vK7"N.]8/8 {8}dԿiͬR| sйuBf0$D>C'wtGA}ʷŰ @R3s01p:՛qf,8񉵋5>5eʩ\  I M%׍;H@i|1bhs*A[;糕BLrje >轁WtXWXQ3snPQ{$qHI 6 E#{t< d^U@ 3P/G/\j/annW? ?Gw'AFjˣ֖vXA("Sc#h_,c~n꘿}@O$r| $?o;~?b?^Z[R;s@__>6 ~;am? YM1J@ ̿Z`-,nLL>֗mNz#F~3ұ57=[:F~%j%~ fhk(s/z P~n.^S~-DgVpZ\=\hp^zA9Ӻ~@9_vS0~߾W%_ lmb~QQɅ{/{a~bpq~*>j[ -ﶈY5k&l|w VB}Uzy/QXcon]Ëy1VSx*퐨eⰀxc)G5l"h]E_w&IMx*rk}I@}I_{G+]3r)b ,$*?o \ $޷ $AZz* m7 Yx]'$$iLPeԮ7M BߑMpJܨuJedL~k!;B]f7fאct\Mѓv́ ,Pp|a DA|W6&f>Mqkd N ;܅'К>4gհogXa3jeGφ UPmEZE&7棇\.b*щU XGhPnŎFkV?4o Eofh:+u'dd*Q&b#˜? 닓oҞ6Gzށ{x7qmX=4pS4wс? P'gA-}X w^ތb_# *qNyszPvB*R?ET rpNѦTu4Ŏ5u@kgO.qd+ !}Gkz-.+oۿꚍ3 kJ:y:9o=J=wO>a`:F3WZ:AW+8~4'_"Ygc@\TꋋLEG0:5jHSkCUoh.wB՛Sq&VKc8%w'6]:-5sBlϽl8g-KeȈn\KJ.E[Wpޔ!4CJX`'B0 pNX:#PFٌ PбZ{)gДE2'ҵ˓.iѲ+S%qK;מkʱd8;a,a5Va]ղyAEN)IP1 pZy$vqyS!^^~|5 U՗)b_y;ΚH# G{iǹ.-W?e2xMXȹF1>v$Oxl; Zk4w_|]tfVߔgcl kw)oHRwyfg'S]˿C(J5=Su˱v-ZbY0L}9q|˅Fzᤕ,g0~{0HIQZ\(EK{J死kɒ:R Yy l0XXt(1ӗqu<*vi0"ƱL8c^5'8AS:Qe_?><;AU]"Gh}N0HT?mS,`4P@w\IOV"HF,bE-ø0` |LzS QJbB0)ʑJ| 3JBhiIR:UG.M tpgS82C>s:+zValk^KG&b 3g<(eR.j*VqK\97[<+;Ի?Uk w].'Cs"sh+#36p-*ʡffLٖB| [j̐U}|_X`= cNj]B(!/=YHnߙx1:S'"[a,N~Ҏt <50{\4" I=Sl R$\4j~E"&vN2Ѷj" ѧ_3y= ڴN!"*6WCQtKMYXo/T-$4/hs+i9 '~X/h)*rjJM\7VZ8#Zh&dd9\͠Z'ܮSDz-r*+zgYhh³QAux9sqf簠қ}^͇ÏK|͸i`?]Kx*a ¨U?~ZK/Ɖx(O!=H{=Jb^W>7NLOLy>){^_B9I31*:vN.C&] Vo}q^A} G2Sw =8 RU~q0/}! f%C BS pa]abq#Oi FHޔ& )?:+g˥}Y!/09*xV*:fg_:ߒciNgs$XŒD@M?=+k>wH&4CgR(g ^2 :ܬcbjTȤӊ3MAc)\sU* kS}hH0pyi۶Vpn iPF WhnRHl Y zσő8-%aoZ ڟL?ݡ`9xGK׉.jdʮH;ܖ$z pa)7_U nPA}a ސ,B*@NA",@DZ{h0, X^Wmx&>5~fOjȋPo $Yf}mbC>'JBƙJsҲx2''IoEQVj`lUr7|n0neCq* '!"tp$(mĖ:UM8QMmd ۵'|;AT[+Y7(C /0M^.R k} ӕ_GItMΤdť 8d6\oR%?j{_e: 98X?0=-".Hl?]qҗW 4L:3uv&,$:W'=j8x|} ؏RT^ n =@BirW1axt$E@ øPS_*cw?tRIcSn9 w{UOC6*Y/V)pmًOYo6zOz l&Dc7\E*e#9xU%x}s.eFkLQu:"MG|'"*G`1uHV|$T^L4S=<>!<ۼJlW{E-X,!jS@ )-Pmgң}9ch*Tsa u}F@qXb:$q] tT|b?h9}+8܇?̶H~i%NZ#R ;=\%8E*VB>uSoeģ 0ak3݊ʳR(>Tpqd@*;ur񛈯y_l"C3:*2L]?oN$dX,Gh:AHGW ܵ'S(p8c=pPWˉQ4%5 W Y5^:\uH07Z҄\WܙXfr"mBQ]ؿ'wV%"*{M:S}!u< ս k^z,%nYth8-:P+Fh{Q<:Drʥr[@Bb7ФJ6bdEl]*djP5t瞹/6'eNHjZǢeF^x\<>ӁQ(A#1s?|@t=qĢU,TL6ۙ_A86Йƿh()ײdl'kQ8^8. KN$|$N4=tCBX" a"_C 2@{"*V9ҪawrgкQk:Nm˾cT]#f\ x>GōHuE(BBO{6z8HepY/biɚNHbS3MʡD!@j;A>z opԗB'h X_^sIX['΁!9 4|i[B0dka‡5 V*; KM0Sol:'΅VH`*hI I,;΄ƩT}̧x|Ƕ%-#vtKZQj]|U}->!&`Y6JL *Zl> jh`$.@lFrtE& g`,͕ZSCU=:m1Q;Z݄ #~?؝QdzbzGe(eWcYPtl}|RڲQ/9ty9BroW|9&K2<ɽU%*60uy-)h:u1lr$=?q޲nQ.v˰ItK\l3,d0 \c0ZjC4• 0\sGRn7,qUQ@SfReZhÝ`&"U/vcж:Kʲ팼B]MmN&,p2Gɶ5T 8qh6Sh4 'x]b,} aL67⴬x(e8Om^f p؟/e+'WJإWb*i[ˣhŽU1.> ҵ8> X, Fu P@]DH'{^ E(X_e"-PڈOGxΈv>gAj `7Ϯ*qy1'DU2DձC}@o#T Vdp/f.W;qGS h8iexAH0rC)ςh(9G%7@8[m&hח{ל;Ng0IK-ys3[>/]NFLK-/_qxKgtʩ!vxk;|rb[U=t 89B($쉯vH+zsa_WM42p!͜Z<'N%Є4U<1j aQZ/'n sÒ(P(+abGvD^)ς3LKITgmd9=) D/t/p^$W-ͪ|s*,>5Ja-}6ARH_$>&p)筅Lx?>,4w34C\2BKvPp0a~tMk_)<@B _=|\Xr UUN~fV&o)f> ߅IL!ٺ# RE?Ŋ|ڶm۶m۶m۶m۶m{z33Iv݇JNRtKMYŇTK~?ˋ@r U*h>h" yWUR1_&~^Ϝi磊 AnHGc4l5هxk 8q7a,o^]*%A3T&VRZ2:ep_ءUc9yy9D!U$H30 th\in09D3p60wzdWqŭsBHDu "QS…πdIb R_RGoR;SZۡ퍹 qpЃLzLΩD"e=^QOWxƠ*X"罙byvr ? Z^mymkt;@'wm—vrK gG.é5E9R|h1}=42k̖? ZéL Гqfb1HE:2:VId$lcC=?M@hU`Qҗ/Ue2K < ~ǯ#+_qȤs,Uџs ,& kuMLL|z@ t= *஍&u7RFB,MdBo;f] axY p:z91)bC #Vmz$ C͍3qi]r:ϩmS^JM)2(ih |u=[hlPcjv!N%$JO uW]\zT~t3ōϯh :A{PQd&{Pp!._ir Ŋ)-g:z#†)4Ipwj|7yH (Κ$K̀rpVG+; `QS#ƇÂ$!~D8@֢AU2If?WӍV?ZD-0 b-/χ&T.LsA6_X7l@3uIA?Ya9O#'ax/`MWw3CdWH1Gۺ}^];gJv3I#]Nғ'oj>tVf4\cf%FU=g'D0Xk%Ĵ3r$$҉` F,a)"/:BcRbs Kj* ɤmË 2f"ecRS!=`?؀>uT{m/{uU"3A=NT!BnhDG₠,uLJD{0G- ߈"$-t )/OysDV٢-(،N%t RpVw|Ĺ6sAƙ$ #\i}?$jZo ݩZ4yhbp}sm&+nU U\^U*v+ҐX3޳Oi@ۺeҷoQ%< raCNcny(r.;G4/)q[+#{oYνT/[@n`Z,k1$"M~[sI%VJ KcOAI=9TeSۛl&K0]z"+g kFFPy;bJrI=f׆x9~R baY˱Иi0ʼ@_3#Glm "6UMKdF Y\:GFK|To2yzԽ1;=Ij`r4EET|+&i QK1! ja" l =-U+ : X/Kt5JeڑHS2Rˆ#~j(>|3,Q3Ol.m&%_-_8.cɷ} ,@DSTMw%&%,r>;rc*zgNYPq-I@8fUI'H0F-9.+_N+YJdہr6/n,8N0xw֖2mgjl*BȚ2#w:Lz^!T7a6FyhW kRt r-7M0l Phu`o"tw3mZ@ۇFϓJpN)rƤN *kt:-kL ; >#Ŝ47$ 4{}3mC =6c~%>B X1ɽ RVo-di= ⢞4w-p+o [*dldh0NRSO(?Zpr%N{$`x&!CkXޖ9@O[ޖAm֩aV,4u;Li_!=;|<tsI~FT)O"-anMJrJ>J\D,A&xJGٖk:!(#1`؉ Jj5pqb+*EG8̸k0uʛS>d{]FN"Fd҉ Ɨ8 2Ƹi./I|7Nؠ_\yeZx 44pwRveS_\b:韒f)p >ZE#Qi$tj⿷k•#yتI*pk|A]DX(x!΢6Hou-dF{i)m:=8/"6Klpt,R${֊S?4~\`ӳ_ܷ !- /;E 6cKK,,1G/:yh*E*\nۧxHC}!Gp3LJ]床`SDKSvzESIOZ T٪4r!h,(1)^V6(Ӓ^>6̀()&P)[bsiU |+HSdִN') H+{-ݦ1W[4=YDd@\\u .J6 (OND+<f/b\b  yZ%d6b08άc6ljڊk\t,iHQ$bX( }{چ͈lṱ5́zso wbdu r|Q0c,7(^wvU_ns:0kZהiD2EseB:R09>4z׽]ɸ^Lx_EmpsI<'sMŋxlۅ#  ItŚ.cc{Q[ QW3&L K3~{$d]e[,Z SAo2vs`7FM|0dAf`a<<pv/F@šbl$|zA3Iѱ| wmkidL sD!`y/[%NM_Y[5)r;uO"y%5$|bSCO1_9`形K#[c^ (C!W5a-j׋vPmldsVc)/X_[+<<)7ECUg7 >gJ BGt"8y >B$A7] Y2(tTwD͈4ibrKͨn\s)ם2Rb8gԕ _+M®b)xZ8FىPt<.aG EhCxnSңL/EF $;#!]WAG󇢬]8ΖlWHr.Y$S, Pp*ny{ش&-_YȳfgJCY2qq,%r6+oҽs)CYg8n$ d",3^d5j֘_>``NW6N)ЕQd ;7^8'$;3 },lUڂ&ɄC=I|ꭹS=cX'(kvl`hkt<y㸟 `SpOEƉ]Vr\AC\߻%rE=* г2;iFc{o|hsEBukFG>Zi,Uu#7MA_Y_v7A9Q (>.; ]~I0=bNcF0kxͥC E5EޙE nYgpn9-. R.omO[cqNf8@J@P Ef- y_=By#q oGAFu'|:EF>Es(9hLCoR&Bb7EI/`f}bߡQ!(FXٸ9f~{Oq4).g<"Ŋ(]9$ |Y:6HA5vFY[TB L=.T%I 86}hsdaSHE65Td;^TYcG1v; sm3edAZu*ț iD.-wNp*oFAّszދ?)1w 쒟0Vs46o@$N9 aIekev,[ &g݅ =ksfВ!DXf62Z7Xv@=b~̴ȭ6t-X(^9a``eXH(Ɖ*wyaէ+_EGxS`t T/H/jl cN Ovփ{wy܇ :s9v<4uuncOKn w[ڤ6:` d ڂb0__8dt+oXƟf0nhYmktbqkK\RAY%xC'Tm۩K4:u*%*݁Ux.aQHxh#_$kҍ:D1YІB3B . q<%{<0e`RkSy?cչ;_+'럡̓&=Ey TPo[[D,ǹ&,?ˌf*9F1iICꪓ1ZYܤSmipOx 渌hPRzZeuzH|:N Ĵ3$[4|qv%ɃTg}@pbpk қtqoVfI7Z /=U 9@rِo<.21$?2feZS3GBPW-T0d֒o;rYDR^ <^sDNlOOKΉPU31﯊ xd>Wҙ3咗(*A3!$0}tZC𦏔_DPp94t/ga=I1$^:C1GŰEԖI3a )gqTy*+ ]03E8%z' iuZ֭gzՔ./Oؚd(|Af #Dt Ϭ/?>]rq )ZGUsD~T'ޠ/E88R?Y300D)[LE{cl}2*yJC+136 aઁ.) \Ţ= xM];σ+ :bÄu%fG_.fL[4;:_< (qmie.A &0HٗeZ bX{jlt@YwiV-(8@hv4\Ph'j+VVw~R?$d*}Z5m㗑k60ZTLb\pǧ+FtN@ԮTVDQO1c sZ '-kQalf8e?᭭SPD`mhe_z$Ѯ!Q,};p_d =Y5ccGKk]NFFƑ+Y;5JH3.O}#5z2ȁA--ȟslm72+aVR)WW.HGB=A{Ή Uc ˀhS؞[3b9;Zf靇ZJ['qoEGc8k˨IጛWz$*ko^BZ1ePIc\vP<屛ѡ]{X@ \ ij ޮ5 l[6_.󿨌S4I5Uhsa=j؄RMfaj?*݋: h,{g<l\)1S&-MM]'Ԑ$|_U8m Tg?4xnBPo'⾓"ܫu%c_u sķ⻫M=L:2E'}c žt1~7:0x1uZ=J~vA;>&PcYAaAI*|_DjgL>Pw`#:uyi~ #@P>&%RF/[w8"*JPW=9#!G-ˌ3Ndǭh2+NZzlAK쁃Ol\JSaWc N)Q^+^'hCN̟XEثt8u5m[r=:=<,USqzhm^oBaLV^q>/7WB {NSǫ]}Fyx!;.}_zmoe/GMJx'0>`|IO{`:se63i;?.QFnLgwɮW>RD)fî$e*;Pqi~̈́n9qRWϬ=@ljw($tkBUKYQA@=j9Ss[AUyrǮn 920_L"wѪ޿pREO&4ap bb̦u30BLW[Bg=ghz_[A{:Z v^Kmsv"a5/aRPcޮж՜6š֛Wg <:7ۺ˨fxdAG\HU=-89 iaf挤k(ў =5qo;V]=gM՚qsvlJ\ˡ} KN yIV?qϣAm-V ӿ)\ : HmaYy>:A3?5--^.׷L36-*}P!̖ĄXEjgt]k}+ZrGgD(b9R򲑬-+xBN[U [t< ~jb>Rβq)K/+ҪӡS}L2 "0{߾L\Qmk~Kڬ7xdFgaX?"VgvA3Pga/py 7ʥEλa v&h#tCħL`> L 堭 HSF)_ fu.l3fw [`L~mDD+m̚#+He+F,o54QOt}C-oڑRϔ hԔo= 05td(ÉcJI/N*JgZZVv΋NY^ XcI4j/q$ޯ6M#Ғ4o@Z\8Qו.jguw%.*{n*Æܡ(_ބGDM}ڭv'DN0lX'K"'yo#=(M 4sХǭUЁX8aQJٷA712 _DRcT tTJUEFm'MA $Q&c\;Jfd)W^Jf%G0j3&EP aWpR~kL_ثcq_神sAws]j~;&"!x .y+5]8ewzKݘ፱>x-H 5?o.J2̘{goo'%Ÿ<%o]ő O2Ө\1k%y/'yIﵐ#/Em9ԫb JS􊂌mq/Z KTlGc6 d68 Ț^ԩ8g,8x|PP/(yǬ/ِS.̍K37 ̮ȳ $dۭ%7W&>Ǯ,߾(R;q{9)L`{ix GKB;W&S;r" :S8x[ ? ]3ӧFo{eٴMQkAg9aaXt4J07Xj  7T)H|d fW_6uW 7>`q9H\:AHI3҂Q3BoSb$ێ A̮K%'QrzudQ OO֭; B|qa &b>[Ty$seS@~7L{fy5[U AtdCe2~lp]0ީՀ`dUyş;8~%J8ZCK,/[ >VTwcbێ~,MRCfrOWZ".Zc$cBe8q#Sagr} DL1*}7Z `xϮMWSd1UlcjJu;uW^GS3iXֈ{h$DLJN=|{G(hߗ6а} !/Df#*)%!?&f.&K2%g2&rd",&!&207BL4q76/Dc;kk%:G=vvߔE#;Ek'.U%(O?F:U:5:u:#!]lFv&h{S/>s~2c@j#+)92##=#-9223*9v9boRJXh7f&(*rJIiM ET!?a/Wι (s3w_}=K+GR)k,ıL%9ih#wkutΟŅ޺^f*Pg H:VO¡ ;z3X~FAQ݌ޭ_铞o-M]_1H3+[ù-H_kdrMǞ+_& WB(k-R>PR7ι$_d7_x[ogWKpSKKw̽_@-_"ށVJp@VϞ*[~D!:_cF&N u; 4K}k_+_wO;)GߏOZޡޏ@+_1_}xz 7:{ t_^;aF 66t4G]ʭ_BK+ӇX?̯m70ʫٯ_?Q+*nT| ^EѕB>.ݽz[ɠMRܽ۩׼f1#U+oB;_皺lg1@iϒ 4L\6F.y>I^p3N \orm^w2aCe\=onBLL<۞[>⩈c_̋x!wʏ /Ih3뼹k!qå)́32{!VUAc*'?nP7D]%`ز9q;3_Rq&H+ഀ-WSOh\<˳, gjU_o۷5SeŇe.ZChRd:ԋyLQ  eao1aQz0}IEy8Xk 6Ⲛ~i\Cv^UrixX>轱w2f/OzyLjN?hRiwەIMX*P;0eGҙ?_y7d/e_ j.-c 3So8B]00yY*š8dfg[.%ڀ1[z(pkZnSP"~rttWvA{AZ2Bu#+9e93|Cؐq݁Ȋ:%V׆Mq(kSX35-L2RT/ukcbKW8;Ngn fv~Y(ٗm-8tFIQ; 2$ dW&& H u]z,>TzIIӯΎᲮCc XeHY|̗)5Z (U/ܠzʬYl< 7J 2V* >Q. D}ZŎ_M Mjw[}y``ۃ^{j?m-/#%0&{3ik< K1roTfn+)C5!1x@NeO!w fÓLdDMu~ܗtvP/hXQW p+8 ["ܠQL[)bSPt[uc nQ"1 Y?P9|ʫ.)m!/+#8#)d:tz=#3]-uauDiz@ձ4"΍(-,qY6t O9Zw{t~QC{`VPPC_v0f)}}Ccy9l2r|)|{՗Ns[Ei'6F*U o<[P9]'d"\wɴvތ-j+-.6Iu0sŷR ۈ,tqj#kE?GOv~=aA?Ao/ƻ-cqe}py"Ou!])Iz6 Q;?4Lt C5>j~|сZ٣a6+lΛgu)K.+ i+ Lir7'Բ\drMk{| 4@K;Ju-*OZiL'흒XI7>IKS/.=R#k"HxЀa] BT;TiU+~0M6uuTZES:*#7hu/=qNmu ~8Ԙӑ]Fx݂7 + .Ft)k8\d=?n:1Q)?_]@=SvZ+޴ 'ؕv}DgJ2ԚVȝ7mMˑJg~:2Byf>oa0%d ?a71cƸN;9WhE4 y*϶, +-?JU*RO⨙C6-Z]R;S~3NnMNs=!9cxTk( (/*jUR|0䞙Y@kvz& q3ksvҏ{t/?!Yi䆆"Er?\hgjb+vD9KN@#څT˲njcK9`7@օ)3TGYU-dn3#=C{, b@W)1l3"ho)Gwϳ2eu_岎n2liy&*JvѶZb OPz.w yc֨4c1P)TOPS>ycn+5\5/kZZ=C'"쏪6;Cyl MoלQ#"^5lT@x6EIR:7i80bm)<C@4]Bs/Ҭ%Aw~DKd^Ԥ$?!r9Y}o 64tXLTiޥ8$2%A`)"/ҮO*$|5;t_|."c|N,pmuU,W$=ok*L ;53Q1}GH[(%/Aa,UV-VuMԍmB$̃FN>M,H;@X$XUFkzF'3"pŪƢb`v Sۿc2s EZQF cȊ?gP8\]0o,6E+KVP~/s9jȠTY̘0)oG>߫.*@J_v f&u(J U&cbi҃55 r]3\\{5u?X(r;,vpX>x!,C̍X=Q!dQS BDS̉n#H{rҚu a딜 <Fܘ$5LS0=Y#׿IoYx !DxZYB AU6~ ͠+׳jhGP|vƧY*[-pq]E['[t?#$Bذ`osA\_[ GcU!^`si΍2xajR"`3zY36E;eюfNKuGQTkAlfWHOV!$;hv%5] _DL^U \~8P3 C1snzGo͎;>C’;~^3G m;ֹ>kΑg㏎ G\S:F9)pe[nZyDxp+k_UA"R@Uwh+XBr^B8[j9 kR($ïLߓw 7Yq0EnYp9+h`CIW!ȆHiAHI9"+->*=rTX1Ë^Ы?)ĎqD*Wsف*@7"'jl!猏ۦaZF";r{A;J {q5Zٕ4ќ0U42h< <Cdb5yy]ΎgխXw!۞؆q.0$c |hm J$.lw~UM#>+[!ϻfԦ؞Ϙ? sOϊo^8pQ8QWYx ]~SZjܖ⏢H\ع0ge}EVݻqV誈EQyԡOEB;-禰:ηZtRsA 1IlT#0pΥvw A2֏,zXbFLW}tPOTJ+!޲Y+Q>ILSb_Pi="HkR!h>M 7^2|OR3/ħ~35J[Iq Y8 |ɳh7BԏB)WP7Nl$5eCA-V']rt\.:<6bH}ZZMsztInkɾ;tn2[6:510K5QX&<=iܝ y7 1 8:&TY3d[O{]wާKגBIْu፵qL&1k8RozXZ,@sC$)2't ~l dBÐ/X@>#~C,SoҴZlBD(r;6MedR)J\?6V#[i߰K3O%ANy-^DjG'hme%*9\Uu_:]8; ,~GLpX}ISFo'6ÕVu݃`m^OXnVY }#(010*xvg_"B7z"{(Q2: QIa|.a R̠?u ݧ_6)ZjYλVqj.U%+?yH5BJ)rM1fϽVhڣSd6˛w^})' qnȗ#10]; z [CWśEӤ w KF1 auYp`ЎGN޿x i=Ƨme~AӬVCw8{$o^r0צ]˓S#.;,\r)iж/fTG`[$gyvSEc#ЩB#QJ x( AiDΧadOk28 ?Nq fP8AÏ\mN,Zr]m)I A*%qCߎO,=BEmS@iH+ fOZ4|e-& kVВl wYtheЕ%/%As-Kc5/щ[O-&d@e֡A 2Dcp 1D5+ÙDZhm"txe) 1D{M:w fUJ2o:]C3;Y% 81߰!s_PKFiߴ\0uYdm=BY躞/'M?a)h[ Sя0]XJl]évIno:vSV`%=Ek<7x!,fw ~v9qǙ 𘷍6~l ഍? ̅|/jIG/][g+ A ⚐#yqz6Pto2 yi49' 17]B?_Yk/*ǁ> W@$ 0#2[inz{T(ƼG6Jȁ99ɂ4päɱS_/(!3ϗh5 >q2X/{.S\veu<T !1:T'9YW[F+[HzE#K>x6XkaNdJTjCѓQtN2p~:lkmt!|WE:)=&(O jڣzmHI6(E<п@ yA' [[I ~5Gl- y=6N/ CX>Wt +Ճ7P.XW3]ޣO't(oaGm_0zMwA$1)Q ΢RawCԠk:ѡ^蔼ˈvj9 9dg.od>2/\)f.iල`?ffVWm,0.9nKU |ϴEB{A|Rɻm@HG]w(ZTُqO>!D b&6ڈmk?#m9zƯຕI@CUmp%Gr}QBE1Uu~:Gv^^̶u>6e+[$&W)Re^[U[2NIwɆK.]W٦QX0<9؟4AyH*;&.Kzfz'Ei>eUAG]{jnOtRV$t*90YyvkbMWHF<;h$LjFxf5?&@wpi1=m})4#Wf2cm{"+#Cyhn<ö~6p*\llQwQv7cG5`wTB(erѳA$࿪b4/*n;n> Mȳw"Ԡڅ#O"O#? C"ǝ)IOh]hqu BݙbȖu$|@T')|[a3zD|8Gnnp, $6@i ,<єĩ4^rFSѫL~o)LEcTo*afdG2~oj̉О !axpvzc>\.BhA?ongf2Źb ,19N6dZ?YG*ӻrѐD~]:j3x*FS2;f0p,%|R "0ۣ LgXS8nt֕' sZ>2I80L ͳ-#hg(4!bElXٗKdY'Ggp'fO-8Klk 0*YDORX$ozT5b*I8KQɂyH*$paF;K#ÝH7jl<Z*cL mL.Hů),qKg{ճ`xuਲ਼bhO4Ӵ^|37r+u%72B1'мw=ܚ$&83UhdfV55a'oԇXYN66ӎ;4GHp腾r"^|Z L>6 rFC<{" DCrei}-^NpqDaFݬShd"[M^I*T(]z Ok!jmWj!(\2Tg> :-׳=4F'Be<~'ͮP9rX :`e`p&U J̧gu|OyT e:x+Љ_W7 g/\Ziz̢QiʸL {+_i F/C]"Lv5wh>6Dn_mu"bA^"TQo1/py8{ >ؾ̾_"&ꌛ ExFgp?/kϩ*|^jǎf9]SB$qW&%d'jaݠrab ԁvP!x%͕.~a2(i./'e| ,;PpyS^d M~gaކ@S;sQ+2ᰎB`jv?4.:aO;Dz+9o'M\E6<]Hm[gC뭑Ks4|JkC\q9ԏTqɽhM61kBm$}xeۜe44pDB𜪂R Q5w_SِiRY *A<pēeaY1̈ M2- Z30Tr 7ZoW篃E=![>;ߞC=3,G q!h|Gqz_nWje2Ʊ xG :hM/ h6T]!i2;ù&B?##k%radJoKs`ajPklTK *ک Zw@XTA6L$(I{ ucT;u VQ,IP5ĜֺUhY t{0Nyt97O8cyY @E:2?+W}j jh,٨Gݡ$}Oyi ha 4ٽx&'?^^nL ϔQ utY5 ::U u[z,S3n@U#T.uBHab(D^[(1Ɯ:HAƄ}Q: Sc~'QX-k~+(~^ ؟NFج #E%o?#[%X~Yا;O+7mHD9'*vWz;0ۮmo+h»\~v;;, N8йɂHqҀnv`Ā_;EfȬKwpab70ݽ:8#m0ѮG[LPP,5 lDuW(D8 H78]6d_93vh1j>)nj:{],6.'ץ.++҄"RaHo37X d^e8M0@}uFݲ{Xzֆ_i06xU7ovEMO(JQ i}~$H+鄼0)ȟk4P4 g4O`~v;R;Y\gMlYY/qt?w]zQXte7a hd17>y.HTO:wX&VdOִGؗϓIAL>ǸtchOR߂"B;sɠŨ`m.)S*CR%dWR~|p{aeRԞH=-WC\NS @yAHzC(\齨r-gIgM o(v3ɦʫYC|ߘ @bߏ*ZV^qHOGNceV1)gy[>?ynQb9=L‰VTyGt0zT 7!-v!"dʰJ}ɝA 8hMv&(8qW_w3 8C jF. ̙<4*sUA#/5 |+$b8}QRqǯ1If;-{ LDX͡Io+fn`:r.i8h@7Ci[ 5/_9K)Q<_K>s{y-x/8r@^\Q1$yWhT>8~"$FA{ {.;x (ݱrQ(/"9GZ&y y>')!g8ĩ¢3GNiky^xRY}NBM)vqW9mܑ$:`eH&䏄I6ihSvg>c8Mr=%_Ӆ< b`zK$x {z>;2 ʧ-PqS>q WnB']l5K}o=ʤfS}@_(h'Q+mT oN%&8;5(fʍN:e@{HG4V[DPp"5 r7=#_gQdv'|Gu{NG XR%%b?wsKyr'pc~Nٙ :&5\vcQz?Z l=??+dSD{e' (`qJ(c>fU p)#Gsfr|nتiXt\3@tF$w"8ڊ?ycaAkRK#GR&A(wteǘ'uw[iGj R &PxRg ČS4~Wϫ`ϩ Ai :X R }eѫ404gSҙ,^bfe*z+,p8>ѶX̍~{G-P""}D)U]oRCb4NOÙPH%tfp6S(tnTHnŇԃX-J8悄ׯ˳%dA41m]Hf8Tg}gU]nTvr[3hV k'Q-4~Jޅ틃$UJ,tR9J{ %9&Lζzc`q6ߍGRO~xT`/hޘG4fE.Fh#k_%ix g0Pv:TLU5nk4\%!R Io%cP_; =@_*!73)ZTIGD@ Ab@ *|U`kdx0|>nyYse-<0.2S77dqxN2;UToci a.ۯhDeՊ9t/ɞZ:wr-~?tlu4B)ew ghX}*9x*>6dNӉhR"r?ꆅgpE"F8"6% @Lq)s?<٫niD$eڢaRd\!>W5n'%2 a_1˞l#;.ЪH|du~(Lb۔p𛕋j:^ʠ/@?:oԉǓv*uѭn6AV%0ަ}؇~ ʒaq,cGȅ ֮?-@)(GpG=P}ϙ{k+B'.Q^ ؃[ǎ1 #bmvL{// \[{0yqt]ϝ ք Ş@nSЬsi[ XRY᧾K(xYaH4`5}%x3M nls @q"ua+l`_D:Pnq"ZS}?^zƥZՌY f.tPՑ%!_5uM0]HY9rF+U$kTt;I}=Z{-|y>UW^4Y]d TG<,"= åXu&ҦUuΛIKx6fʸ5Htf}yB콼׮bN?B(Ba k]4~@Epk8ta5^ /?:=Y2O#m[[K,1h̡դ fki4g4 Ք{1VhQ^TES2,$EtW䧔NdFݡM&_,Zvr\49tB4T |Ve#;YX]n9:,Ppl:MÌ KU?db < vQٗ|I/AÌFi>ʳ>stͫha9Ys_0:?LW fvoK$ Z,Qo^wWyH?`{Ԥ|^=L9:x|1IpcH}jYe^.n6Uw=25,3/s+;kXKy#IUOn2n (¼<G";֫YN0P!B:?(,vPP>ƿq6?qr ZΜ6aNcrKHuRb~] 'O:i`S_@)jzyͳ =4h~P Ǹp˛)!YuAP)--{}Xr2'kjx(0^2U6q{T(oe3l7:=$|+TcH3,Ҹ5VU\3 }UD1u=wg&{:J33,dvs@#  ]59`Q0[:id./OD1Dx2%t-=egd$: 8uWd&A(u>QbθbGgJz2K)ԡXTޮ $dg{]6%>*N{C)h`KiL\c_9?7IӶ y8oղC} ԇɷI h* !=+&t`[D_ZӶm۶m5m۶m۶}>ፊUUcT}3MXcx#x% Ss8:xuBݜ!39 Be m *Vq 7ؕ;א\vX,0O@\.r6ݘcsei9XQb׸tSM2Ax o $Y\ZC8 8.+ m\qƕPRSRQT760M_u\qQo:.#?븬L22}\Z regW"ZЙZ}:ouiTZ㿦/?3hàeadgaf111협3r2ge`geegcc1 vZfGϿWʿ۝j[jcfegg9˰ W/5ʿ]w[_cmY[Ж@[VFe`c``m&ʙ64QV[8n+Ennn}|dqXMt-tX4]Tv'(K$+ N jɫ)367s2bs S eNE y:q/lBB bcdLjzx}B?Mm.Mo>p/mb3LFH3B*`RrKjjk[D5NOD s9=|FՋon ezm`y 7` 2=\\m|bw[5@-߻S)SdlNuKm_zaq>UL vMz YPUw;C9M s&:kzJG{軄EHLLkWs @{҆1)F1o3eKlJ6ocйO&FHzVږ'?iZT~ =e|d?~?D@??r?s?ψ??9?\MUUuYo=?uF~)Q_?{6`O=o?nr2hoE?6a]Gz`tqM%PzWjMZؘܚg,=]~IOA[=pmd|?֜,vZ~uCk=![f$*m]܆Gptb ʚWU'LY㏺Oؽ3VtPWY_C$c3+w}kț^mDm8aV|D^ ΩQ06 2%tLQGeއ6ߧrV[ljfs ۗ|qiR&l,ZvR}4Y @P QD+&VlSy\6{q)@ 7dxjt󗮎-X]Ȓ\D] =?^%X:Sg^|sqmMf%.sb(K-+o dRGjMn7G/Ņ!;x f>l^ՑkJڹC1C9ЅBq4@#B1Fs\ ˦iCZ6~&K9vwC5K}K~^>:U,#Fŵf8ﻍ7$A_Xw<mɋ΍W\6̶gN ~Bxcٴ\#GUfgZNVBzD!xv /W#8v6\sa .P;vF8G<ШÈm#ce z@4$%ojױ5RZoFiR9N+j-kê(=ըhL=a8j`sR})?tZK/n3S6A)Dd=u#Zll Jx0Aߏ&MOJܭqcA3}#M=ڢq:}$4k[J?1GT򭌚Aho$ ~ owC3hܶ6uK2eY.T1H+VڨץTbR"|l-0M!vl8Tr1hҠ/0Yo-yiNG-vX!>HSK srGxDWs dàX`qL3x-~D LIg%"U2&;13}!pYV_ I穁x@ s!qnMzm̏1Eܴ|ҭD\VўOYq:h[\%¼UL+^CHqD}v|A˭4:(F//he8,|  eXqNqnj8 uY {,+~p}r Ҭ&a0՚Wm I?K)A}"P{m.D (RIGo4?s8;kT7$?qTFsg^)lQĀ/e#$Y?گc1}o14ƶ[q\~fm^jq]}pjߤ=^XS.bH(hNF3N^;9>oꜵ?=MsVɬR yP@jZ5.TrRQ* UF ǯRVaù&BI5.<7$YSat+я]@2Sx!;̮ 2;'ьUmJ\֖Ѩ!wɞ˨kX]6C-q'q|fѳ/WmR48zÚN ׍ImT-4jc'4F͛3 E[v0MGؓrtW05iY(}m(<]_${bšJcCaԯԺ ,MZYr+o1A+ 3`Tj`݅*Q~ú|^$.15zM/C{N4ium(^wo]AO3y4&_C+7rerK}:V5p='*d/zQbVQ#U{_4bL͟& ~LE5!4uO2Nܓ^|p;YMq|Z \ L]Jp" I8$@$O(a+Θ??/#ɡhw]X \yxL,Ҝ9trc1 L?i 's6;|j#VJNóa0{I{3mGiD9Nsf "p9TE[9Dleq5 %.4 \etXry1%2" 36l߸dCdM;F %\ywc7KGjUG,<["@\)#aQ{BPUȃjÞ{bׇ^ۈNFDt *2US)\# VO!/`/ Ȍ0VKRtI3[w>vnHj`a\:$Rx<./d _G 6erLZ>]Sq|.+`I^w?N3h (j15ou^(4υPRcc0в==-J_+C۵& m3zء|t{ND[8B4亀9L)bq1aϯ0p>y~wA<ѬN Ϥ?وgPӮ诀 eZܘ:1*S>픃&YU/yʖ{5 )u#+,0:R2QΕ)Y auݳ;=JUYtp;!aIV¹I]F™|MD>(G)BtbJMdt2&i]|J_ckס*9†w=^ $O+wW?Cߺ?itl/O hb8_~ _\ ]̰1H.%X0\Jn9ꊧj?hgMrɰsvnÎ2@reAG2ފX! R 4ahC/F$T AFzf s/"HO#K(Nݪ7{ovY\.Bߵ ;8s Man8@.2niaWFV"Vn9Zd'z ݷ[M'R7+l{b]c˧ѥpiQ : 08E5Z_|q ηD$jV͔<H ) Q%Hx*SNd#g_&& t֩T>;E(]tESAC,&>ف~FXd*b`vUhe=fZ_s4sA2k1QXv)ա] ?3n , ۀv`+7(~rrEH{ĊؽƲn\Z| Ӂ3Z#2gOڎjYa hP㷕@lnsyXjY`(|RK`fܢU̩@t鸺qׄH hဌ}_pUE: XZ j3s}Wn8cD/\V:Y V5o_p6 ݞOntgU`] mHFp>VT#}<#ڬlv7 -5Ôd_,$(m^XLP`^b/<ߵUZ{l}+_wM!  =0f~x;(aibvⓢHEx fS CQT@6$A-_$!\luaB=_nۻB;vKӵ yl%;1}ԅM329;,Nh" G2L VW_j6 ~ڌyOy"5Ը]\Hf,%=Ǟ~4)pew(c63V=bE'{ɿn\)׀(=Y{$@p~{·&*qᕥjk.hgAbتM@\Jj $/1g:"+c,2dj%mx Z}Hq#٠ E՞Um_4?H[[cC!ޥ[پ7fe74WRssq;Y?/<{0:LDxQ9IpEn/~sj?JR XoOhbw͌,ߤcaŮoZbFé2o Ho G=Iн85\esBIV\} iJ|_kIOQUX~\vs F9L v;ӡ,'䠠~F_4;? orؓh@3a[o|UX0P.6(8shobZ^P|/|szvąd]|`ւޒ3|x*/|%FZAaBlk!pKwʆ'd-|pm3DʪB7j ~Xdn7@;37'J*OJj& |a잦\)-sC/0s=0.>j-oyjg 1-PsUV 8Q0PYޮ٨H\ IN|3]jRkp^q_ 5F/f>TK 0U)P^kaC+Of{zIgfcM.)u9)7FYSSGNy=&5FU@fHw;[p#}U\@jO14$8dOUJlPK0kjUrsPt!ʱD-IHwKh_L&+l|2j H+81&~Z\ r>MNdD]%N:,j"=Xx_&]0֐OmM9?XхGX(!nA*0ޤ/Gg&Uy~@7=B% vvYq^u-b%Ll)u8k++kѢ ?.eO=IH i(<8J8@pxxޗLNgo~ݥ%$<ߖ5gĪ8ʬX٣p."?8[q$4O&_5藿&W33Sdݚ~%7cCTN]gL"]Zqұn4/|efx Q=WW_[ި/ÁE J b` rrA 1hؒPBعvCJnrOw\7~Hy>~zAz@P +b+o,ALJ{h¿*ħdlͬ ^ELB,pZv6(!+AJ,ߑ8[pO)D1+-yi~yG .Csqa5E$wLf& n/8+ݕ05RnՏ"ğjemvX 0;}2̙Y-Ifec'gW=bgZ faX5+`jLC!8c{ PCe~RZ>I|bމGQOe .8ӥxUюdalEܗEy{"S"~7{,C)h}MS0a-rqIYCqivQ  U|k۝[e6Z=k:> zCnКN]ŦqiKNQ07r-EDBJT&GAb뙃3c4I)K\+lzJ?>̌mmձcs1=3XՈ^19$'ōX,2uՄWHg'X음_4#6 ׽ܾ$O$.lT-ZW)5D26~ì-xdoiVg|Յ*! @Kw%t?ۘStZcB~q jsA̚t١2MtY/ʪD9 ʗiQQNdXY|Dgu@1 c wڃf~d&3px=Q{S&_&kl9RS0gk{ǻw%$GjLڵuU&ެ~4 9l߁3)#>|NG)%] $\qhcޭ 9?yVD2Ӹap"4酴u=(yDxNh(aRT|rȞKO; ^-&j0bkF9 K,}% v2lF'$'p/$*ᗔ0PvA/, fT\8k>0\?,5pBy1>$릗*u+*& ~våRt2qpPUj$_qK<0dL,:رngݚڳ/`g[Qv1_G[5>Ri;DՐa?"EuEocHrU(f\Iw:PAg~Mj:EײI޸_|nh5+ X@U r h#4C}F-ތKg>5#:x}l,s| td.-_`}`X.nhꥏZKyZgゕ|ogaMz짧5=>T5mUOTmNKg·7/ 'g2_tVb`XБ"ik5>M™#]ѻ6ezI qŶn-~=!r1u쒘g}ހjQL7 :>v́Ŵ 6y€e]V|:Hi.#cs9l3Sp7B1̷"S=xgcaV#dBe^e~A&,a Pد\4ȗLeR̷joɬ3JЂL4& K>;=Qj:e֜;~9Oސ,UO,Ne8ku ƢN| `SnjT@-j?mD/m7QS{fbo4q]_*IV:m!!h'GljvICZN).XmЋ}(׻Er\K Q:.@/.jO{Y[Cn5 sj DE.tZF rNa759'Of/GӖ\vGW sI :^)ڈq򏢴&cIqĐ"i ɛ̤[-@z!x}OY3`If0yTVA:BY۾H 1 @}DAkM˓ܘ<1=?~c1oR{ۓ&$I8M xiCu4IYWqSAzTBZkP 8r!;455rB4Ij4daQQ5m\0c۠#o0 YI?1(32l"o\noWR\G~&uUI\kB#j0]k՟SzV{D&O@NR[$g 䡇DU0F٥'BJLVfI*|C˫:4+҄lǰ+ >*3p>'fCs7l+w,0d=[.cK@{JQTr}'w06ّH]bq'B^E[TdhH|+ !։ÕN(ly|L|f!S*u-X)%c2oHK"PHŃUF$ɏZn瑣_=Ij#fdCWX![ Viw_LOc`c#_ߋH9@ !Le6sX7֪Zw!iCal\(*+5 Gz. 8y$d/$xugR2O|L:6k}fi2hC -f HscR|@,{0TBʑ<%Po,]Ƀ6zM'nsf- wJ]S,RMid1hεP,5]8\%kJjRdr\M9_[GĘ<(y4QQȩcLj&Tp6HyݏE&TwV~h9'\"7yi|J.~ 3#aCzYEþ$ ZC#Câ%S*V XY~{Q'",j>8l%PO[޿=] e}D)6~Gp2G ,H(!TcN6$EՌ}5?/tc+ &1_ "/ =kSI'ÜrZ]©326Iq5G(1Ql;}A(&<3Fk٘3 Q2(*CDoE>;fh&Pen.Ѻ4k!LH6BƤ3:qa$UM4ӯq6܃Kʯ"d*LXL׋~R{h}X.'oCi<|@=Lr$C,ɴԄCKRҤ[͐s>^G{\?nF96llF5AD&Ma]&wIRq&ߤ6KMU i-J Mp/%2~~G[z}ꈊ])xx\nLmh |DƠ|EՑD7 8҃sa:b~>Rv:՟߉ n~˜9v#ޛK$}h]RI P ,IJ,V=jgגc[qQ#к}, >z(rov[D/Bvhv>@A-nӜ^G?qDQ5Beͫ6F'zrzO{&⋠t\g`wn"L/kDžָp,stxÔad#lb+E_r"g0xF:;#YOA!(\^$?xӄMT _*ofV#X+CQX,[?U~~چq&6=|), F|B^'[pAs}v M?DmӽoK%zirMM,X%/Q1]eXK@ :,ޓv$\6eTo}lq&BbNP{aZWIn~ah<KE,M0i A폱-jn򁣌7"Y|b+|}Ir*z;Ä~oFx;Cp5tً|^V'CˠAgS r+Rh5[f"*w#q!Bm2e%vf#=D=QJVJ bN=B rK 2'',UcTNa飐 R5ppYM1AkbggGb, Zڠ0*ڳ+-E6whM/|>lc^QfYHY( wgud:?&*xCZ@ĵ&ͮgk0썪VW }$z,bmU.[ Fsl;Dׯk^?(,dbhpo2ɱ]';R W?}ΉFx@/ +Z7\69H= ,kVVbqj.a( Mi_GvF>U+nMYh]?ӊڣI/Kbh4\戝꯲eJӳ?B9% ]!Ā3 W4R6xO`̃Ἣ` g-&ý&juWJl+kNRYD[pw^0T g;zpQUUsuHRdD6%" W+n9β@^7+k4/ o*Qu(^|Fa֗Vo,7oad&4uUʌ;<$ʫ2Sĩ?Jr,@J'_ߛ? irRKnUi=Jy\s$Dkeedb kuqUʹIen%+N.o`q۷o@٩.eõ)'%EC1XTc%#!Bw oݺǼ1\jnļ Yh=9BbVq.AY#qs[4+D*~k!řR]Ƈ~XDVU+{+ԥC yx]كiS Yg^E~jq%[_bEP("4 IFŘ|@qaxY+L>dY]/8 [_lsgL}-pe2$!gbq~1ֽJU{5@t?b΢|A|D#vmuaJ0rL}{M%FLGud/]VEcRT( 봔ܡ*T4(Bt}u-&3b@m(&N O}`M>2zuVQD)4z.z4G ijmwE6FAgKs9HQ 8R$2eLHp{2`z ť)nɃ'3y79GJp-$gEpOaV15auZ*^dH=3M=2,*I1eXmWY܅OHt/%_\Fƭ{όP%B=KӯaHf:g0 8hoj@+-N=Ko#aK@2HF ~B2@5 o6*IqPUJ\} ]ճeFo3t̽1>+ tY0\ GW]܌Ҟvϖx8]rx_TZHL64]Dsa*>[!-戣h" }A^O$a7v%u5j?,Z؅ĻnGk*!p\tJdSlvH퐾*8 ŇQADJYg(Q Ib=1TJUt2~34D5}-f'j(Md8,OmIOBE 3o_`FxR(hW2+4|bќ>5/6'g{y%,Aq(0qNД "BbMPQ6ܗDEͻӳon-JOkz,K pe4 /y*͞hٮP/ꐤhX?\?½SS{k R;:uѵ  {tć#Bpzi7J?X% rGLѳ:kЏ FU}[sy'ty1IMT.6~-.F35\n' IPdj`1pp5m}3wXg}%YAAol h lXC?a`sO"xӫ|Z`L{-Y7@ZA/AL@d.?}/pu fL j~}_-'Q}u- ^ 6§*ŭK5W4H)d<ȯg2 P3=SUT9]"c+]Xƣ=0Y*B<ϛV֬kٶ>۫m2j+w/_T{mܮ4Q&iwI\4‡HƆ^=~jEXR8Ƥ&`F\URL\W5QOqn>J ܟ?+Wʬ[ =gJӇ51+!ߛ+5\ TklK:鎚Mfl{ֱbH9LrV3cMd#\6 u1Zml~#_ź|K=23{e`g?_,'XaE1aQ*!%o5UY53QTLKHvL M4L,. ]M9=bdw+?ԿFȍ7?QcZWcp-LMM F&NZs661kˏM,3g%=Dj+Yڳg>-hJ" YaFV&F)nTSKs]MlgsZf[d۱XSf; /ٲcbnhrxJ6Rn~)L?!#=}}m =Hi:pL@T(,,,9_\VWG`pZ'/'_o@Y1(&-04$+.O,$diicR%(+$ΐJt?mi_V0qn@ZiW?ukkZJDWzԀb~sۃ7HlDHڋH`XPb#=3Pb~iU ;kѕY?+/t`=޾}WYԗY P`rdN%\.??J==]1dHlH92ѿ1j1䇱g`ofupz@ȹT)zuzPgHWϘd8|dkI A_^s52yl; =:ڼ| `DΩUCxF݃?#Kx!3AXT=֓a0ujodpsoI#pNg|ۂl{[RW\P^ѻnT d~z!?:3:1C53y&L,TRnwuW433Gj CĵC52 ozg׳* j Pc"y㤙 m[c:bsx{{ued6bvMQ3m^fr󍫣;g,\ۚX./آJ H":6D (ꙟǖq\cr?nk!ͤZhf7q]y:>'wjLj32*;8վ ?Wt_U!Ƚ]*EE=ҮSqGoQT$x$#ze>tͼ0y7#ev͒/N gB֌QL]X,5]%+ JLF-X PK}g9]W)z&B)EZqֶwdڏtJD3jpZB-nDr+ Z'z߷8X:F/u󪋜ڴNZ\k Ckϔ$l1Er ,Zx!2v~; 7/( 9(0fNٷv?4DAY.0E~Jݺ~sKw{^Mܢ| wП+tרOs@#jI_V[7ǽ{ Aym..ظYTRJTL`jm5pXCРHGMK}V,عH-Տ*wXl5C96~[Xns0uQX/nk(ڼP=HduP:fk:Ò-0M%Lbظ X_Nw2}#RR!GTX,C%q3~ > ɹ?Vi,D0q r,tHav<-SԻi>(=̢DE?lOZ3~$o93e@ېP'&љ`[Jy.Y2rIHK ޽fͻ@( ,Ǐ ~+:uQ%ac6lb@eJ5R!ZT _&ǩ up"npS@Ք+Gbb`B1Ѿ$}DBK?r%zpTM ГT5^v1g*y~Uի/JU B]ߟḁoG̹>ADq+[QvUv#g'Ua&υdp^hV)(PޟY݅o3Ҽؓfw鳕߅)(g=yUrgśOg{PbfFce[.] BH>N,ttjP(?M\+/3 "-f6'/VY~[kD/:F2<9DPЬxߕby35ki n◆qChE:5 _>A=fz%{ c6UgB8ud|?Bݒ 0$c-+|X/幡Ac!D|drMgjzxe'(xcJP1B~<ЍxQ>qIbo(^&]`ti%EB%Dm %&ޔNB3)u⁩]a9vџwFz!]L#EcnYie"p%<8eoD㊸U{V= 4P7:.cJ>(̣w"ҘzPݣIHk~j$IK(p.p@J"Zy-]Y>jãw벚X񙷻q a6ȗogF9.5ryGH=[+-׊)#?8Žx`A9oh@M$'|-*%V[uLV(вaL c#m)lY  zfK0w1 ҏ36PqjOoKD]ȉXpݓ)r[6G 3Yb.g;cKV#2\XFG g7b,֮vk@3qs=XTOEӑ=%*y/Egpf91 L͘axÞSKx"!=Iv;{B+Gyt+Gm0U05uA]:mI zcf wiY)\*QI{+U30HfJAcDT25'+1 X&MXK)3^ 2NP}& UOdBugKkuEQ ;I)A\NFk=-CZ# ŭXƠ@M(=s $m>X6chdQ8#:^ Dn|Y^1;з18Q[$z%ZcW~#IDSM`YE^qo򜣀_ hI%}JYޖLE\ OcE4%e[v+ȨZNůt֛Do9}1]PdOVi:NsPhە mSe(pFo4 zs6/@7FCZfLjStGъ毵OOch}sÏ,_ f ~7>7Łrk5'eJN$fu%q#'ux/ G)*Ƈ/aWl'JoU?u(0TGg%G PdrrA£]&hG jh Sۊ-Vy&_ZqK!7*n3TR>D#:Y{Ӽ ĝ=Jki8vGjM_7=M[T$*̝8-j˞X0rKH1#mD4D R(,?`;<3W즨`]C06h;ID{4*9: ?FO} hCϙtR6^Wty8Z*D'-:{>q4mdN9UJWHFn*Kiќաd(%y@@dSȨ%&cWYn%kk"m|VFi{~2zk J۪*+w\XW݌Ϳ^YD͖1'aɼRtPbY[';5^]'IX rA?emMCeC^尽J?og2 BLzdaw p[ōY{%#L#UA=Ť WwίbkO#@QaȎbGEX6M;I+w RP ԜӮ¨p*LUҮ6}-&&V6&z.}fAVyx%b9&XG~ u vΦ ]JI'_@Ϙr>M9=BdQ^~ZDZ!+RSVJY Qܑ+)ҧŰWJL~v\a80U3A%b黩7G Cs4v: ߹QU=U%ַmnCҒ^hzT+-X 9]JȓG b&98j6[ѝOκ̰!i\^Zԯ Iƌ5݀?k@C9AiNܛתtz;ZFaQaG8c=VEMp}Yݴr:{ӴeYqyz۫[h"`RKD_hNDU{.4NLDk aZ@*<E WRT.\}ӆ_FTe}|$c=\=NνKoO], >3)W9VA'71D.ǐf;-?, ˑHT;.]gipo>- 0 LXt&}8#57.k 3?L9Ҵ>zYerℎ%ĹMg6](JiPW%3*b:V E, <o;PP6ӡ 78o(J 19^38y<9n̔O8mxiˋχ@ԃF Р-=,1:*M]PWJ^EV)32U$%og%n5=.87@ޤp.b:ѕO4q<cnl}],HsFbfFBz֮;o|*>R ~TÌܖ3_AXNDdS994өI]栓t:Ctsՠ_B>nCφ$Oo!uUƞޠ~_ZHuq4tO RX֭LDqsZ`xy];'yT^\7F@Qڣb95EO q0aĄ>ofRدfZCޝ;NI(:H!L^/X`/!4rhLh>:2:s"" Ɨ ']2[vR#J߉=wqhjV((?d0F637wFXcD5?\d )Mu5,tXt%+B"gq%1*!<][ej2w&QYց2!#+)'sYy-э⸮:m)x~s~Rﴞ6%&L**\LlNaӾz`7k& &[d fW`<G**H.nK(4ݴo>o/ʬTWkqzqh_ȉU3 @S¨ߏA9 ] LֆBcZ EԜ,1qa, p<# ߠBDyh7ݓj{xl\+uW@v{,mb"0^p1uE nX6LjHZNǛϼ/ )洦S?8Uv=8 N UT/t^> pg_~K@3=&зU+!֬X)qWDuX1=um[*i'G3ͼGLdn0)p ^~wIFVdDZg~!{$N$7X )ILJٸP43Gv)%h/Kz6(VPY֓dVUpSDB|C댑p{'2Hhf p LTHW9]̹TR &yBt96/ʼn1L̛5{HCTłenD; gy'qn;[#|u ' S#W*<]lJe;fr%lczDn6890帗d]T i$܊aja ȕ'*BN@Z$Sxe: R,IμoHц /AJ}ڱJzT#ݡazyt #xx]Fp#YGw`|o i\sti ^%+'Iwc0U,#Hb(|*Nsh)dǽ7 H*"t:KF8 bگdpG<6WrN7jx.V56ͷ:iL:料YN.e4Z  @گk[PEگ7,8m+dĝ? 4&g>=Ak%!{X1?p!"iHHJ7!dSRSG ^`/\'wڰWȨxGQYoft+C|‚5ߵ Mj=#Қ?Kz{$;!@5qm\7E_ѲsH/sV_MCYt{bcqI&x1k[ׂ<$*y>w c് &0)UG<=珷csCHK:@wS꯳iS"˯ 3t-@ !fdOl,t_QHlٮl/mIs!X{$$:T[O)4ّfNxfGtγ3\[QͰdxJFUc p>UĬ__1B# 9lxJGCu}gOCO<ś>ht z.,[~ zx9)tJ&uW6'ɅW{-6"Wko! xFjͺHmO9PKIELxU36Z"D&Nʐ0;0ZHjZ13x}h<Jyj?#%Ҭ;˸?@eݸhUTgN^g [ [_L>VxǛb~.77|lɂ:)$jf? $yQ]: U+S"pUz>O;7J34 ĤxԖܬֱ Xٵ{+=B93N6Sz ~eB][;j:62ƨL_XhsQ2o; @:*a)Cpr} L}u/ZXk1,%TeP I/ʽukУk ZjcZ'w)bX2A]K͕8E|l7-y2]tUfe.s`wEf>Rt>#c<Ъ P:A5,H5m>LB=tP9Ma0{d+H]/UHv ۸+ɼidʇ?"ICI!uUB}JQ ?wyr(N t3xaJIRd6^^Cb-/V󚛖FǐFz*^Ag {D<" IQʷebıY7% Z[ߨCS#O;Z9( ~v!MRw5A2]ӟ`J]03L}fHOqCMU:LvI$ɓD9Ibs>U:'?ɏc!roQn G-!1A:iuZ/%;wKv="dfl4nƵ872ȎT v٠T|NH=V(25:gr:Z=R'h&sT<;ғDZNnN%~-IJ3MP/hqi5 bV尥GzT0P!dWl<Ŧc/դ5t.>PeBhH|D~Q}9vj&گQ{ I6𫊰kƔC]DU+`> <ج|TL *DSCB?O&:+IezÔ\H`ծ\b>sDПP\rznCeUU D).# Kg+$>1w2`N܌ 2V-]ON چ(Em'Y'I3.qTw@hb 1T{-)F=9г\l l%hH\9wQC ]8|=XUJu$r9~: Ժѥ{6@dX19d'nġ w{3i_tQXɢ:@D#N2gf32m[BDǒ# 0=zNj~^  n_DL?N[9$gBV\+2r/5mFJAqVMUs*$&m,Ct[}eU+Lj%[W'@ 2> 5qOCM1 rUϡR7V5 8-50`i;W3Z&8XD 8U1%*(mUP:T.f~ #}p6K_RVzұGsI?_gv|2ŖkՔ\]57Nkp21zJٓf:#R.i2f`NfeCkْqaHՕ*JΫ;D32yJP`r>i.J DUUx_Z%t;q 6<ڳS7)@> "Do> %ДMG³=MŨ-%:b2͌)#G^`JsvQ(<`AP5tT;tւ3o*.^T8DS2\.v;h޺} fӇørRsYl l847O.%>Z6Z:b !2H3!+ ;X+6ΑP{]ch(PL%Sr:/jZ|!*a|m-]%7U#2p̩쥪N tֻO.wkVٟ8Oi;QIF;'HwP] +I_4D2EZqu< ;>'^3FO(vBR!,^P3 vuYc5hl+tHMqƛK!n*Jj)\36FK4לA\{?|>2Q Kզ=wn ?G_!<픷e'ʣ / i{t1à"}S>ǎb>T/(zs]oFdҁa(+/7!>(Vg^=є^te!6cBXw ש۔1yt2I-CMɐL ;`@VeשGڪh9p{OlRt贱o)RuB )Dn3j@G%SZ29G)V^j93k(v#<肗}O4GxzRKzƾKt#V/DŽ<;o` ]$ںGB{%X"aUbZ Gm3P"Ry=keݕ}#:??XZl?K&3 *όߕ.$W`]ȇ7WR+0s͜Bpkq@ o2="1>`/%i(3b+:KfvYy\hI?k1֥Zʘ˅uq9:ݑ,'~qh5Ři)tzm~}Q.FcbɊr+ZA HF~gBe;8LLސ_uG l_-qUn8n.E%pD?PMskA9Y!g/ؤi`iy'X#nm.{\Q!b$(9k!dՎձUNIEr+V%1Žhe0,TvY^[W)1v=KFb߭")T/bw#%iǡ\\5v!erC2`i]l,a7tՈf @%k !Y)p_П _I!Bh5w)5[yxl[KUTtuRdLjIy`UOnd @[&2%J9gNThϽvbۤP@aEyhX`+Qںw 4.b#ؼC~,㛧b-`O@͢=R\ˮRU~S#fIDA䱳P3頶#E BFSQ P2 l^Y߭LKTQt zx&i{<}"7W)cz%\*I3&`%_bNٮ|J! K_a :s{4?եKW91i~ە9+R}Ϗx )AV%.C 0@dGAF+4pO1۲ϝ}Di 2+1KVnƘyDsއH,4>o/\>*6V83T6ETaһt7ZR{UTR+7fs:ٹOA TSu`G>TuVFdoLlIF2nܓ7ƓkGG/=lኊe1xT#.O H`}#Eӟwu:L*&LJREP+s^J})]d"`$m +JMqGMwf2@mŲ"RKP!{|$#eדgN~(HO:`"zaH?C] TbǵqFuo}@eŷJ2WY66 ý#c>+&PC[ _\8(vg2lmzh\bVrten"$ YNJr MWF>v8NE"#K>'KNF sAEec$i &FZYUfV:D-}5ݫ9 ޑQhCeͥ B:#z`-ʧa 5{ء)!c?s,Ղx>h65D?q9>7Fe`)7|hrզbiQTp(g=M)e@ꖍb ̻,ƚt=Lei>_Ms~ `'$k|(F3Nn>99̷J~ ¢>u@6 BˊdϨ4 ܀ E(&&p [;V.-<FL1䏡{Fn %AW0yu6pCJiM|Vڹm8~|!0b|3cxm !ޤ::JR8Ou Uf!ӛM}T+ث ADcFӏ` ؿ.gih 2]'X# ̬ q72Spӊ~)d0A6[8ރ>dZֹimϱ^49͝B.2s6P=0ϼ oTnG)hK`͌{p('9q>9]$eiCL(hAt I ;G w~p D]eouJMLpN")64&}B>C5GƾY5q"Eڛ1>z]pe/%鉦]ujYib(gAmGgQvægiKhV,9҉ YcJAb0Eh;С=^ IX F;I:>/nrgS?A eZE"š b*-! D;湫ߟ%o;ZztC芽_ AvZ^m")f,8#m|e@WY%Z;ݺ&qTiνsv@zH1b,C=PᮓGJj ˜JfєP ټKhb3*͕yrs00OH<aןMI1KNSڣN:7<s-w2<W #\R3-x[l`Glq&00|70Sܥ O;shVFߧRw#q{If>@>&/|d8xs1NR{^W2U5'1׭L,G"W'o!77_a.;<'Qse*J(Fl߶6w4~)UKfA?#u49 G@?Y᭝LF%ESփ]SL|>ȁ<=C|byqF́1t}Dǎ$Ěnxa>01I:Sbp.?Ș詞w>,Rv!oZR8t<*UU){`it2jKp m їS ¶ù'Ƨ$LPR (_ 'IZ]5Aʆz+aWR0Dp4vzTM桌iF7ূ/OIʘ=&g}x!X>)lxjCf?[Շ/gX'Jb/4TvWlxӔ"M/+^9<̀T_0.9ujˇ 9_ۦN,l(uC.{ܽSlM!:&d{O%6FwyEхEPm#uz T3?Et"fnY4BH2f<$]:{o+}|8@EԿ+F,{3 ҂K3$ ˂  Pip)a$B~˚vFb*rWgLϗIo{^`wY]KMQcJfLcy)'_ VfHUMG.Oyxt5X}PΥܑw+̗όZ=x]bJ;SfAUA$>/d7~d@v-_Ө:Oh[hzT/ ˢwY!0,*1->5E|:YXEm=Z̬ }?&TX4'ѧz‘gE)W%"ӌ2ճ)Od!b-CAMQL$)C ?-[BUxa/u[%KeCW]!KvƊuDc(rܛ 3%ݩbS-~Wn:yKp`X[It.%!ח<-f ^ D]L&yOp&)\FuNAH2XZt< kzcdLQN[ lj?JOV_A [QіXUlFamh$?84+b%1)z-X9Pi஗\9ؠO’>r:+2{ 9&UWKᄏ ԆW&ȷq:'VJIɓ.ďO{37&qBF7;EiR3Rv&tÓd >)hm2,"S0'BDKT!ZcHI!+[ kPkSmzh:M"0q&b-75! M~pD(ea+gy{o=Sъ'wvK#YMԽ(0_l3, Qr-(#FaHwM{%ۑ(\D*DgeئO-amCs4}9 U<@!4'pJ(V[X2_WRU׿Z@AĤLEU@ qgb}?YA),d8&Je-t E?"-sOm{ tߑSA0 ASo53ߵ AR̹c ^hwMW ?d+iLc߅XոZnBЊc_E40n8 N9X|=`J$j]<vMJ1m"+ 5NCǶn@lk$_"fOg/vW7#a 'Ϝ1ͯ9Un"SToJnƟb(3(+ OF݊KvÑWl;g wj bl߇`oO@ Aɀ .؅HFl)e7>ͥղsIKrru.;vtby/`i_ ojweEt>(2x&@jA|Ȁv_ y!eJC u?mˋP_(8I3!W%p>~ŎGD=4?>Ft<g\ *1CΌ3?Y)*"Ri$~.jF,>#W_<&7WjSpO#_ 1bKW!)M5D ~#gjaLH `#+}2tJ=8NHPR|~oF% (勇<:2Qh_KK'[s6ik6Q ֏loy-&lH.Y' EoU_xhFF8ԛ,>3t5- ewx.pebnIIB cPoi-2V"@' ?fVtPcBX^\sPa٩and[~'SKH{w ZVT>A#G/>욃e#&$ Ļ^!4 '˾*tStmߜL}zQ#o' hqpKESn5C1ұǼ*{bqϳ䀑RtOEn wK!4lX#8, d˲aw78Lo\>qp0EfJmC[vP?2|֕ۺ bCû{HCs&閃On_%3l?'RRJ~$׌@ <> s.H{FEJɣP.`"({)6=_C;QpOs:"Lsiso*L:Ny%%cޠ!(]j}np̡N\p$4/Z+ӆlt]__>YNbHv("9O 2{j\5?i?Q1WI9+ ~`ؗz-:CX%lSn jwk1˒ 2i>Zya.`ewnʷZ9c|~o14#s=}ɽ` ^^HS]Ke/q$Ɓ|6)CF|r!Fqs]"Y.٪;oNs#>3YV8mڟ|4dǏ -RFSҬ|ٟt o}x`O roa|ي{  |^>gwP}}1v߭)=ҡyJs*=%IyOQ]='qȰ*j`p7yuDC9|)NRp/OBW}݃="*bOIzJ$L1wA:+/RɥGtrTL*ጻkmNg0[EE U kL*mM`|N )ǸeTWDb Z6@ٻ&Pɫ)]Wxp8~^>רڢJx^4We9-&bSKo[0qE]izX>2ۡ/ؼMõ9tKeYAlR!7gXt"cu֖ک>DZޱW klx}cs,gle˭&8[2okU}t lj烞jqK7"g1 4Сl=d쇯c[nSvM0ejU'5̏$Mo~"Ot@P)Qt_+#;%]UhR`:ˋ ;K¬f*)(Dwk.~(ei_u3XX3{}٦o}=^]c-Gkhx&m.`kMy͔7:&3M]B`8\$6['S_Mf;?*PM\\bC->u^][X! ౑A/!dAd#Û*S&v\m! ߹ 2dl5▥@HtH6jc:+TW<|s̋ 3+UcU‰˾Pтݶ<"# r8qڂ6g?20G<6)D6#D'$ t;*5Pr`1\.Q ބR.$Xt`Q7$Q2g^GzS`'c$)D'_ $|Z55 [DzY[Jꦜ ;l6;7p#E<&ߑi ׆"UAW>@BGtk:nm[]p#@ԾsxTXG:2|ҜqujP KXh6QYm_ީ7XI}@H*î]KzbЊ2*w g&nƚ :6(`0pcZœ㮤@M= k`j.ʠ%}7tfE'ج+58[u~g-=qbR-)=c Ykh:vZVZ? Tc]e))J4VDpHj0lrԴbnFŝ묽x?I7YqS;T|h+qЊO•>Nf疟k|Z?]wm?L=s|~GSP,ipŀB0Ii  mc{A N Bp%Qb0IzTl7mo vz Q\L'퀻}TٚHj qTHɐ龍w((=7j'˨'Y @u3+;Vc|! Nf/'i *,B)\QoYBv6d}@YEG4^ dT4+beUS*W?wguCq9‚J(1]L^~A/]”X;Arj=f".&9r1,u>RMiUV2,ɹ)c'oƥrUfH?f+]/ȆisEQIuh.?.q{r:BqBMcqf fr\ F)"a| wDr.fvdJćU]Q,Y2-|ymQR4T̓NCF&iGgKtNh?WW!HS)%uS*:sஉZ~v h#l^ ~r,QiO'16"̩.8Z Ė ma(['5'j3l1W8.(yY0ʾoqiLkm1xƃ3儔慡t "eSĜ{# Bw^P CoE]!G7S L5SU[=-LUGuw04Ϭ9%pC|$Wvz!=;|aR云Ehbx_U=>FbֻO Q4r' ]iq~MVm(^'Izy8Ճ}sf@$m՜ #:x>R{K7>6~fXwxnmp%oK>kKw}Wo$?+IL{XY [/h[:,:4㯡홹 {-WO O3]m{iI+oTDQ6߰+2}'V/@t̊^YW6<SG^p]\w?_D__^^܃ǯamk#3 "?_⵹_]e_Xх;;b߈~7;1irFi7edPi3#h"f^T噡ڌ_KD\dCr ,E?/ ?t0FVǏGolU_W)c@7pQ =#ѡс׾ၓG7z?X\:-~i?og"~_O{:~aŖf0f( W_w ; ;k #V ǪIL9LZ*[ *k,Yi[oߦ"~י,k#aNQ'ulBKf:袡 N߾scwc?{b/ֱ{VY+;K AJoDW;w?Yx ~8ھPdXw/[;hYJh|FmEf[Em|0#"x]{`+R+(5I)IJtKu&j1QN8jAҕwcq |K v?x6Br8],11zfX.6pef^Չ#tKr ]7Zc"zf!(+ e 1[-NX6~BN_ҾЩ p'͞QiBؗVE.IYA#fhbH 2 ͗C|E(JϤ,\ZFov(1v>ccq;a GvYŇ^\Qٷ:o nbJFHYvQW04 vV%Ѵ$]Ly\2*RXbA8ݣz}4>?#d^F/ v/on'ס`aB^AGoRIoy8 \2i{ʻ'7;qґ#KwE҅24ZGvQ@jڎ|vq<ϼͤJ5`u|Z c[K qCЛ[dRrJɃO?)$& U>7~}J1"Y`a VY*L.$pzXJ-AO؃-i׹*?$'\䮽7=}- D`<aXS"ћor' #m'pQ 6xnʆ$>՜ER(yz2t΄^٤ŸoxkYN4bZ⠟ <Bi);ҁo%. b{cĎ2*;}=k5֦KcmXEF N(! 0 wκW ebwAZ9!_`RǀN Lhܑe];bGdd܀eD\:3 :WC[ӉUSkc?;g(l%gswOŮJsP~s֣zo]*lR!ddkb2wf#J8"h3+ne\k5,) ӉW_Ѷ˺w.H"C9@l : % [#?UOr7?P9@擳bI'5;\Fes}$d۫_\ UERtA(jW Qoɡfbs.([s /GyDl!Ɣ @/0 {z122Bm:[m o<ʋ:;sh(D;g&aSË́B[7s1\Xx0HԠ1ϱc,7&_GL 5MBY[ɀS`IE-_]J}QH7 u&6]K/h1 Y1.jpeUnm.wwԾY/PYЃUp(n"\1}xS@WjƤ$ue)8O4N4֛e!wXM˜.-daVKA_5g7Rҫg2BhMYٯG[ k|P8ɸEM*n Իȫ\ P(umwJUl连VZ c8M; (iqΔ_ Rv}ql)]#L޶.iezc:a6_V*aOrU{ yKPrL Yzh[L dFѐjva=#Hp>}fI=iYtVsO Hzk)AT(l3Udq-@,e{Ki(_Bc™[+n=^Y!;NЗ3>ꝿLhK/C”P>fUM!aR/y m݌,x+Q]VĽ/4T)\e ,yGԍ]B~K3+\ I*2B;4(tL@+{o8p Bp(MšSԪ1r. e'5bZ pd }Wb n@VԚ:۠l0$:E9o !ORth&hWdެD" XcuR39u~@^tد:p6E!,xCa,$SFJ(zGw*8 Y-GZf/?#::|\ 3lj5J(HkL7@v[:i SSKCl&F(ŭ-:DzA?-.!ik"݀?VEzsxFDSx.; z3~\0R\~l Ksg^:Ɖ 6,Pm&ɕ}l#7T sx>?qħӳ7uvsm\6Si3dNH|˭HٝǷF5gQB58lx6&BZa` t̓";W#,ݲe%w!vIbY09&uvKѠm֘+zE?VE"z$~ke@m=֏}iY>o"3w7 0֑mwSxDpV& ܍Jx/!gi)3yiuTaqxHw685 ?&ԫpbJLX W ;+~E?z a7C7 ;Dv:Lo຤m*rUi/͐tNW:;kxf] f*h)R4#('LT,%k J ncpG/$rEzdq/aZ%FD$ssԶ>u`;<3Ko?'5E r̄: w59 Ȯ\d94^,1JF"4vxdM*c-o*)2cmL:hOf{T7쑨s7.8@nЙ r }kWӾ&-v3^3"vUwbwzuRn+܊~8ZNcN0Ä_O@M#<ZϺWSj ߧKE~š)< ckAǀHux`[Y_;EBVO\P1̺7碈8sJ鈪tK ¸S 9' 6&! |ň`H OS'7}:F?iZ-7,4zĬ@feļ6.?6 ґFq%#̐z >H^-[T2=͌SA^OXwA'dX_v"+VԠLkv:-59p~!sh3ZӒ[]ˆ&kKhco|L(GtA" smwݘ?jDPn@3$YrNkkTB0Hm? pٜ8)iJ=jDԏW$mNDžkNaڒlʌԠT D~7?,᳦G)N!ƥKV Ct65:w<}:ZߌI4/~&Q$Z< UfP XYغx =nVo$WhAE6I.Aom/uaDV*)(kӆ6S|a>Et$ S(N&C`8E?GKܩ`wQR2?q ޴MHGV8XPnDZX5YHUj)3Jy14aɗ K X'kpU<b#Tp-ނLR_}yVN Idi)!D}Nn-i|̢q$!;E bĕI|^BIF`+ur&9*r3LjJޏLgMBF1x!,ۉ {'ގ9J_R9Y!!K;xoq L%xׁ&wMXuKۯKxDNofeR%@ztlyB5,i>Etyh(*:%٭ z3}GtLH 'w ۶>͟o5caMQ0ryR{eCjSV{c}4C>8Wdtd[A#q'Va.csFj؂uZTI!D|C6([s)7[_mi W|XFFn2: N( ׎2| fNN&{8);\gPcORǑ:#E<<:/w\MϠ5/nT5+|cFD/hѵ0[zr»Y愆#M!m%HS_IWd07Zwh{±ճҵ-m`5f#1.aӫI3 JV+~fl;' wl~T' E)d!˰ڀ~Q7d#Znkp[~b eU.DQMo؀rj|L?"TSH^{xf't"V,+; hGY hews|xpE Z>1xzL p8-/mcReQX 8>Qq&dW(H\TJgRRdF \e$\-ƘԠʿ3F+g q>7!G&)W]UTvuׯ ;hycmX)U XjUS<3{F]־ۃ~b;p w~l!zVB-J51v$wj%}x;ΩBUӅ4Q O){Ŕ區xQāEe@nfAre7Y'Pc&2@D}@eFQHKZQ>t8k7L ^+jכU:BCpVP/1ϞB xDX oIJ5KS87cv0q`k9 &zYR05A[зpIn`C/ P*V>%,7Xg_V齱C h<BYp`oji$D ;OG6fASхs%JSTeܸ0n3bVv>հr@( H!"3\M8' #2#:тjj.b4h7Yu+z,>-j{2:"Ѹbin4/f9Q;QDV:Q$*YBz/ZWP:YGAAТ t7voڗ ?RxV5uR"iplx@<5| 7F/2wx vՙv]'/2²FvMhLg &Ѽ a^f{;.*-d6AAXej 11y&,h8Z SpH~T8&k%OR-U*8>Sirq_]fMvCX{Y,("o{6s` iֈ&Ϸesl'3'kb\9[Ti#:+Bz%JB('?ƛ.Ad=i ii04|,.pv(ux7Xz*GkE`HȲEdFeT\aK|.}04z5bY<^8䎽5.HzM0ݏ%]9Vn]/SVf[B̻^a estӥTcbⷁyzW͢fӜbE٤]rb n0Mmruh`\=Ht@nr"+YqkƟC2LM]8 vu!1SՕ:%z ;0^do08--hFafF,B^XU{΀}=e(H6D0hW&((m^ ߢڿV ϩMI'+qx/۫oY!(&Op' e|yp=uG ,)mq & R6fHUaX֊4BrI!úDQ;*r)5GZrv- S9Y%jvN|\R'V1̥īYГ[!^VǭMPޘеyԮC~AT^}LD^8oȟg+$o)$7 ™<ޠ3W+cu w)Vm<HdN(q6$[$Ƒ42B2=߮U(";(4 G"LdN,FIJ6sT.+^qMA2?fdH$AΧQH n7ב ]:`!&dhH6('Qt B~k K4h8=W/Mkn-*+ A̿FE2`ːhx*#+1sf7I0͘6\oi>zҧq8s!~,VE/"uַ: t"EQ+LrHGKr7.uTs^JF߶Z#\% ›a.=:%t)wWFđL$jZސc.4g}HD` A>O wߛ-wTjfrմ\;(tzEQ=f\bcxK'F/#_$J~$2-a(¨=@֐pDؘ:G(z.E&SJӽE*Yx(>@]JhKUjꔇ h3q'hBnjk(ٝa>L xC])lO# ig||eT_OM#%"C.ai@Qo9B0z$K 5ZHݳ`r^yD8֋kJg}E~wΌ< s4F=<>!:8l~} 6/.0b}K;S:lSܖHb}:3c͢w,:_`/s%#ïlƌ"frBYc ?=[h;M@iim2t*I>ژh4^24ۙ##+l}ߖ]%I2<]}{1NY!(L+J}-6|ip;hXtHuer7B@@4y.Y32; 1,_I3֒;L *џ(рUgX0/Y# ӝў,`|8ȭyP\`n `)'2gc%S;1#'l(BFaPA4iDXY*d3{I\cUς!OyiW KR/Ȕ_UѦE<69CX㱹erͣ@5ޔQXE BԱSXO D;FJ ؏];[R{-7,VŝPSM01ڲ\:Q9`T|?eK;<WYhN=v5S1IeZd (q@#0]ݳ vZXC}5/{Dyq=ƔAk1r7Yn.Veޱ&+\<  IQfuކ_2K+v eCTd06DnmMW׃q.fÌ .|L,2iFzA*p ۖyySߵ DVڋjn5$@p 9;~'-V4S[gBy`aOrt#A>߭ 3g|BB}MXiȼ {'#7"$k-za"SNƷZJdXh͟vL.Q v[W6%*-!f 7Y^kQtlǺ?ߴmC!d|}.~6/ܺujrXeeN t)m:"ɒg̴շ!V"ly$Q5Rypի|M)܊ܛ[,WTyTT/xq9J-uzˤ$-:eyA)[^kXXh3@Md HE"Gz#gq,@ҩvq*b-ae9rRAVHvatxUlB/0E.0 G@H'opP3u\GhTẊӥ1SJAnV.UH(rZq\l1b6!B|S%4ү&6a U_dK$5 v] Z2%nQc&hWF8kZ!;ŞaQY#"\ҵ"6 h?%lg՚WMgRas7Ǜ *V'7#qi]s6E"aG phL>Ɩ| -޴b7L^ Pܨs-`/۬=nCYMFܭZiΞ']4,) _ Gw")ÁМ@ĽԉߛCw QfzʗHb[_r U-إYAz}~uh'OC6U%ըh$G|$<X֙nߣ٦z>nNC._u MÚ|@fO*Uw yoӮ#ݽe8/!O&AO葉gAq鎌O5!NVq(=:;:Kc[ Lx3zfk|1`^W'?Gd b"k cb^/6  VozV !g.EA ?vU*}ܒ;ip,} CV#$_F P3< (#r>-3GDVwlЀ{7(8TGUTaj\((|v* Y.IE8YɪkE #$h ElwH@@7öQ])-F ҕi[e,FհL{\d.]M/^F-+ 4k. ի.tVV,3O7ȱ5Z<2oNz26Bs.=~bhN[S^~j`a"Z"8uC u3%Sk{5)o[ "kNZHa70z} }Z J}hRH0頮 no='|^, hӌfa#_D\DZ6'QZ"O;ǁEQ",dJ GJ:o:?5>t8%pԏiOZI7n0|}_ g Ǒ7"KR@i򨡓${yR5q8d#c ~,KY=Z"U8^Ў@:m{8mN@30(v/M}|q:\pZ d$|=;/+hcB"qc@!w.Os<Ӕ@{,_,x 66᫛nL$7g /9|;\,;j]=Tjb8rP tB}}0g1gqaOSB_1mP"q-㉺GZo~ր6p+zI joW|qov1AX5fp86CU*dţVݐM₌:I{͔A/>ơuTe DRR(;`؈bO~|n! JyrPtMITIPjAܦhl2ֈE %KjȠ͑fDxh`ĝL~YD\]hLg:ECJ9Hz“0 `?Nd!5-{ quEQ "\kG>7vnbsM0 c-BCXx  g*;f5hfM?>pdQ`7G{p9i?+;VQd %+-GISK n)7{UWD`T)2E;lO^SMEƒfS:G)(ּqζĩ2Lg; $pFa:ޫf*3Tqպr\ 2'S(njS9ȳ ;J|ֈvJaQm6S[_`^X`>Ž[q|8G>>\JAt ٔ+v)cnlK#(4U{/Oƹ7!̝Ҧ.F o d/GRzJ~g 4nWG UGWݢ\9k&?DKadmϵڎJyIWbneyva֚H+ZlfdHh3gMh]5w{PdX4X4ROd['Ke|2hx㪁U n|Z*l+c-\#4 ۬"6}JvYt_JD*}-.bE%P#)(j`TINo|Xz.%τ7 z9OϪ##̴4;.毟s)HoC[7i@Nt' b)(h oIK}!68vT3f,& 5ƅ`댤z ,Tx֯Μv'7tjG1ט5_C'a4;Cv{EcH0' M3̒ǫ.'IF_PyMBH87ؕGh8CRcs2H j]Os i 1;}uG;\#W&z0B".X>kW.waxǾޱWfLPCb>])@&W >Z1ފ <5ݸ$;2#cYR~WVPbf|5ioܝy8UmKJ)dVL{8)cF"̢zJ2ː1!)BBI,)CQo8۱9j9ֺZٻk).i/CiW"wᕹ1V^tu/lrǸ/-_+")~(}nQxj[Ә)gJN:RbriB2!E ~c簡_??epLOkFL[|#j#hwfdl¶+쎒dR;Ƅ><ʨnKC놧uM(/>zmE +7,ֵ\z & TZ;.vfx1Wg|xV}z[ ف=l׌ A7!YD?@} ;^to,y I%^0.`v'N|qx]Sޑ~I]w@VvDv7Ƿ$pIU0HĎ)'qvm'^!LQykowۥaiygyMۆ"Ox֐/]#Y3ݭѱy/N)-" o|)Q0/ۿV`d=]wm{XtH}s1f3Ջ*ŷ|XؾWOU/ͅs`Oa Fp vKֵ/0e,k'|H[;^-}a{U1VdQ&PFNKKǟ=n:^V$\^%\So/5(E"+V6ͩ=oVݵ!tiEi᭸6-d ,?97B}g2М8YxxbdR3aE^gM\˪f;]4פWujE ͎Yam˵ q/8,ey 1ᰜB IXݑ',$:J݋n=gd /426`M] +,D9"Z{mׄ?|:Um6ˊk7 lMWWU_=MAc?LzK]*70/\G20mC /qc%.X7t]Mƽ\~NаY4J{N]I_P쑛+*k8X3`X:(]Ω?ËGڼ;PxՁ&fW;(`8AuHl`:%'9(Ҳ6!Q-ۅd@vM OM >=ȡl4埩K~aԠFۇ˙?_|umRq!u_ fs+N{5 #9`#㶴{"U4+pt _.Q➼ˏ:~ga~ Մ=r4=,nǾS|cN| /WMui O6o*MB|SكkW+];p'}>ci`g^?yژ)0cT8{)o_C+^R…C^8yTUվ!`͹JP; )+rD|)HQw@u'Jv]$S"dKj}>wz .r | Ƙzo]ׄvfFNE® s5o<Sћo\k­|SKi5&jo_:^!}r©:Od!~c'.8Dep0kE _Ы68v lCە7D/<}s銕lJ`;`\WiĢ-zӞ;)\Zg^9Î]fw/QyP籆g;B"WT+&_׼g\]:Ωd\bYNMA⽒cPĪeG]C֐8ߪځjv?#$kk'a#qLIet=IA~ӏ m>̠l1Z\'&I [ S~m^V\^&\ҼHdЫ֞Mwe}-Z5Q }?P$^犻56*B %Zr6auQ ~ Z[bၓMDl[S5?dT#+] %IGm]oװgex89-bj>$a߰JeAň`Iڹ{b"g݇A;{֭Z׵?B:nK[!!l,|4me__xok'S )["#eSO)/ XbQWj8pyl@s'/eӑ |gg}( ,ې{%ϲ#ߪW,1>/]{<藍EEOݥ_<2UAֲ5[j>Gh {n:Y?}wf=ӕ\{3h|O=" uIi9;,w4O~Y*G9!̒mBe5Ep"pQ}G{[I7"%j'ezT36]^wkڒLVm.TԻF?oTPҨ"+T7Z`˭"g +S&5vP~¸un /Ȧ|`!wOJ|f𣢿P=.,vLjaq {k5ݍ$5Q#Ư%|↯ϕ`S/sl&o_Ԋ[e%3r*|NJ9l[a[f5ALcCW\Yt RiՓ,u|ģ*WxGH*l*fj@3  :'8k[wP5~e X,_갮YYw}DEZ{s'G;YM.|gdwr/s۟dz0ƵCQ+NRGxr>>`st_&3B߂=d>6?MBT5/۳B"vyU1ץӅ+ݬ[V3|-;};}?f\T.M.Rn(K,LΆhY{XگPQřùëy!r]:'ν⻵">VVg ;`KϠn{m=EX^$o*3=ؚhsr5cB|CR⋺U% \4;u_5UP걸Gb,#AW$oF{=YoɲM=ܩbD /d>"4zE ~]yjE56Kopы|%d3lE7mvSIC>tM!*xtD(u/8vBf{-棴 vΪ& njt_7J:ݚkEN_]m9`zkEݛm l<;L:FŅ0/0H< U빜L}IbAm˷9め\gz?uJ1RK /V7eyV[`sؙcYShc>O /J7zL>'Z~GLHhjYM/;& u߰[06RD(S{gv4Me=uEV?,5# 5&.9]ۣ 7;`hq}>22,zEgs_Ӧ6z)϶xs 9*lw'&&ӏ#2?̿~HoѸ@#yBsշ2}gxUF߭1BL}R.%N1 +?|(j? w>|[h u6>x sxأUk]R)\<^hsD΀ ڒf{Ko~ q"|Q`Ƚ umE8$wpC]+"I NV%ǤC67s($O4=J`hx<튥=϶Z1] ABɥݲҵuYҮ:8I''#>㣸 *N,PȠWP2%4g`q߃$ob ^fbrb]A| nYYqSb_vL畍JS귋3 [8(ac".V/Znk[yŒ+޵t(fA5 mDeI] j8h) 7F]s~iҹwoY= mY{)V(b=`W˾j/ak4pS٬܂f֚)]R[ I/݇je:sDh䔗PS?#ڜUnP1EuvM]+d/U fiWg~vOp0jpD; tW 9 l+?vLp"S<5!b rO PJ:   'H H(~b?90a$s `7kP'4~dTpO ! IAixdAvV(+YY'd!Ytiq)i7kPxAFhW964< R0iLI&PIFy2Rd gcCjӰ8'8D@IFN82#(;82@qL(e8)8Ovlp¿ $!H^dAa)@"P9Hڳ@$";)rmМ"!$8Dќ#)xki@$IC@B+V@@b!  pb8P#Y "i5_9l"d4Ӯ|28RU S#)% A  $mPDDiW4' N@'S"@vogf #@D@ng˩#"b T1 2Op3D]rOeHgS^JPΉvCDKRߖ5:LK`[KcfoFm*L4ڛ٩/(S/`e\psHPgb=V@ym3&e7f]i[Ws#QsLf(x2Yxh^9Mx9:'?9es8':ǑsPs qT qJ#iG70%(+g QⰂ|&T csZAa򬠔gsC(XAaVP(XAguN:WPh:8haмB9A!мB(A!A!:BTAyQB4t h R@   +(#(@WP%(@#(@GP*(i^AI(AAIt%Q%w4HHJHBKH$Y蟹gs[rKsKKD !0DDȥ9H뎎D|(4 =0{0QzfN`*X B;GQLCA0 c)Ւ4ӡ JA0PpL{`*-A] REWw :xQEw;lBtq&Wu<ΦN)2p TTZm!*)ARCJ'ta#jB4la#F  ˕~T04pjK~hn" A87:Q @D0`a`k{~EYO ?A4a$H *AI(;uLFr Br#:@ ~d4@:$RI Đ@pH*UX͜/T^1^U4:Ry Ҭӹd8P9|: PA 6)HT0 q): PA 9-@*V8G@O|z@*b)nE/>}s3ߏLOۉr1eiQ6EIʱZ?} @mJNg{θ;]BP("TtR y0¨UETʩLUsB_%\|UDU;'48UB" T9_Q*NU ԩJSUD:UU& 'TSUD:U1u ,6:U9ubGLpU=rzR$<Г"=Iӓ*'q =Iӓ*'q =Iӓ|>JԪT9wNhCUB":Tt*9FU }JSl&JT9vNh`hDӈtQ%4*UN#ҝhDЈFT9JwMhGЏʈ~T9vMh辕'5tjP2PJ5tjP2PJ5tjP2PJ5tjP@ *TFԠҩAesB5jPQJ*tB)#OrS^<ßhZF)HN R(HeDA*TT@A*TF)HN R(HeDA*TV{S)2 NA*˝>utRե"@.Ԍ2 NA* R(HeDA*Tr)kD%*JT;''-px5+#S429T ͩhNӜ|b 4RhNeDs*T;k9Bs*#S4`ޅTF4iNesͩSќJ9 4RhNeDs*T;'4МJ9ͩtS"МJ9ͩtS1dY]pRMF2 D7A'TN*i)B)"ZTᴨzSћ 7|dzFWδp UJBU{LQ BܒPP U8*T(&dڊ$3Ng*T[.bk(SS Lq~dD8enQ t\ 5pjVլ`PbU8Ū@iA|TQV8` XaT E"p X"P rp*WT,àAYM4hf ATk!T"dN*x|T.P d%pJV,t)s:St&6@gdՃLQ=,ZeN],~"VSn)sSꓥP`(Ѳ2eeŀxVFtWe/f ~y0X>+sW,D?h\Ӹ2qeŽL~ƕ9+W˄/Nӝ2;eY* jqU/XS2b,e^S2zZJ&԰,eN ˘x VQ2N1m*P"ړS,F 3ѨQ;o\M2aD昲3xd^&9^>lSLkTR^hD{yhXwUs>ة]v[?v>egG^_C֖%=@IVDz/ r0eQ,b>0RJY<$}t 2aHU't;hEF:5"h(ZAbvB)=_0CGwt8ݶn-06]( y0ıFT"3T(S_*)x㘆V+|k?j]' ڊh ハϦi5s@Ni'W\=d5uZP[n`;g|8YS uO^|\^N5OIb#x|oɻwY_yt"sDXXpT@M] ب x Ԥ ogo_7AyTt^!\6<79 xYejT-') K;gR̵ ؇g9;h\ Q[m;x6q xuDS+j7-9F:ƒgǓLkOZ xKp?O,B%څ%ϡ'(_VGWt+,=v3*>Ot8*5ޜӡn=9!p/i9}ji%WKMI]Fsˉ!|DձvTA.Kr9_N[F <, H0_sP7Oӿ](qg+bnmN6ɖ>rN&fryl>9_6jYVΖM?}6YN.g_-{^@8AsU¾\*FcE|{ʕ:?lz>,No'j}I4!Nw [uU7Շ@\$eb69r@VF4T:X]߾0zVfβUg"v X `+:{A&`Х+4Rz]j7*FQCU E%#FM, i$V*4THSX`]A?ItH֘YKK tAmliuP"y ؅)~("6,fE0d0e<0oPolQ.O*͉sK)y[VG@b23Y).ˠzAئHQYu騡-(`:UhŕMUosU2hL6. .p>^ V ػN06X ػIi!T{72Q PUo qr]~N.VH*X0DŽ3`0<̃. @!4j`eSs6%֙8 0W8}t)vRK]Qe,`Me0hfU%C "JҦ|@<-d Tջ:2٢ N~v$kl4/ W%iZS@&sԪNV0.@/O 7Td6/TH<_)>κ*֯6VoآV5>]ADn|KaZﲔ6| 2[Ah.uEAluԁl}IەmY _iR)ٔ!b a$Cj!u>NP ~u8F)8 r zk8IXfQ*͂HOpA3dZ ʐAɊNkiZ/H~2UoNdwrj(`a3P]jmE4`Rƻ纶NrV#*M} AQջ,#X0؄@j`E' 2;w|@.yϪ"ʚYVt {kVvVFz\K5`A:g~V U29 եh5AC$ j2e jZj &QGVC 5 uP.S*G ΀@u]P]p.5'OÒi!ݼ-Ӡ󥲸AC68K꧎VX6fA?+e˂H}Mz4ԪAC2jACmCD.\OuV^ )GE^y)oG_Y*p %: ğACB: rM ʞ i *4T7ACR4T2ۀtU B)Xřv6tAC.Q*iPC6 FqH@% ްgKe5yl%6L^\NO柮્IHo*|:p9lzg΅ͫ5<-apdsE^|MV!̟:=]09lro0Sś R` @j3 cYm`t&mB:Lr~}Qİ4A'<3v0kSPFm0u>cMYRRc0:5a]ZJ H44hEeY4+LUg'UcR_rC/\<̕1H~΀ᔯ-ො\ULkZ*3ΟB9P$BRBtUwVؠRrBT~/䀭^*OOTǑs)\s(:;|3Y"9v=b |W:E1uT$QVq (y$@#sA"oJi$B4Ic/8 =''MQ-#(;삕ⳠbRZt.v1e&ûM¬[ɲRT$JQ$+BX)cE*e=R&Rޤ Ib_!V W)4Z_PhIzUb!b%/VbK!c%v2VB򐡱ҁ. FJl!c%;Vb c%d>VB MQXYR E#xJ&oy%6Uba4O0tT j\Vs.Ā8~a%V0/UDU)E.UgNWB]H"4vJ.@Gcg ɖs٤8y8p8[Hӆd|V@|*b@K=;C"6 Ʃ(HX]PuCՅ%3@!72 ͡ee+$EΑű>Teyjq[q5pC'!0% |B[{9">a00yP9}p69@-oX~@Fp@7Z4rLq@s^:n99SD'N^Nt [>/$+8(a!xa|-\9-\9WdoVi_zrS%Ys5#q)=XXQ|nb\t幵j~u1ȮO=l/u`* ^_`Ҫx8;KvNb+*ѮeB@thdc wV{$Q06mT39ioB'21P/]ZvȔj"sZ-Ǧ9`rE?{%Jm1ZNGUFx-uy#{TF2ǿ)i2E;^MvTm2F?a5}uX~R'uj%Ȑk%ԊO01ed ꕑ>ҷ +@{@22o\ \FG^ o}BW}E+}JZWD+aYonY4VO߀dUd7$Y7$FdF5eDfhSFd~imAˈ8O-~wC~u:: \UGV>~B?Sb=,hOC))j44aϤ!J4qO5ۊt~_"o}E&2}5&¿J1k"컯4&½J5k#z_fmrF{_J[L??LH>QE.e;&RZW(lmA@/nBmLYtnjpH QNXݪ 7;Dۧ=w2) k.Lg2]evJM Q/>O2c|L 3eJ 9Ҕ09=]SwVJJIt!QKĶz[Qܘwp_Ms\Ie.])v2sJ=!JY p#^-K!ӲBzh* u"XXeHT>#!R1[7(JClR*#z=%B{zi1>?;E}GZ\d_}G >;Fl'^<ʶ,pTO Yˠz ,PeEn5ksU783fn *IɠhGQzÁtdDnq ʽR4xưR'гKgm~?ONc%lRpPL7i~"s`xQ0=ma>D:+[VODfo^w@d|8N`0wyOtJaf T*ʁ{^ˏޖWrDS5]X?Qӿ\d ^MN~o/ zݟ%W߬Wi~|5;So)DЛ#WV9-ߡěwbqu|5/?¬ /\v0ij䣭p`{)>O+ޫ9K  `EVF`iiR 4a ?U)aY3| )$>| W)#-K7;9i>6Rkrbu_HsQl/e.]JЯg yY]}pXq|-=5~N8eRA,EYZh 6Gserd[q%[JWmY]JDau*Xo)Y]2wpXU |,0|KV[U-UJju:BNj.7_?!'n'aM!^[trlʑZ 85|LGAWYKZ?` )kVȥu%u-Eo4{J`E.: L{ XX K~d\|#k@v\y-הYKeR' \iʼR^v _r~ێI *+yڎ^f`V-^v0m_TʃBq+l~dEWer#R,rO]GEQr*_э;e%ـsF*%*bkڬ<Lk2(2|ؔե8J0/S O 2ە\wD|m&UH^rv.u%ϛFJfʜSJMǁuk +ZUH൲:pYr} RY7_NOPR| \/[RG*ř$f2K`-YKzkRy^9.۠!>P;.ǡdWJ(1oʳx% y)W[7RWUuI|ԯ\Ҡ"?1WDW}rę,.uY `>ꂟSn-t|ԯꜟϫF+NUFqYj{DJ5R"g PM딟`oUm'RRg3fʢMS!.Zsr3>򥦧f8 _-$ NKUI[ gNV@]璦5!WHC-„*&/am[!O8#U&2Uo*&{hx&2zlYfZI&+M FFSHyՔ|(1c_-}SI;@'Wq9 ukikj/R>4M '粐gЯVB/F|ﶩ9-U!\e^׊.U(- Z'2*Wt|ABo+Ϋ䵶,% *qZF=.뷭#s.Rκm#-g$?uo)K}Kx wtՒ EėK~ryMl2>ėJ~ i ~wҞEpt&K%KW3{t<-_G*:WWuU)wt Q>n%|r\o—ʹMumi)+hzFoVV7:dmߕEЇ5Ut%#Wڪ:>9eSO_U?{^< ?,>ΐ )5u6>aUBY # viR/\7K!1^!'_){+ΰYq!Rr'G[}XaydlE&`Vpd%04N{v+3*[)/Y}"x C֭Lԅ_m XAc0aO|Y%3(B sO 1i#ia[G&̥ΐBY1i%b+\3d!_]GߴL=aK+Qi!lY^3vD BTriRi?ri/ B2M|>ZTq7Pm"(̑Q ha) uWf_@w" E[ -bwۥ<b :9E)KQqj+|.*O<q[˥|.lG YG7k6_|z;G݉8`r9n4- _b>VN0BVдxM]P78l5To-lYYnVr] ޕW# J|~˪|Re-LY5]u&ou[&|-\Ȝ6j>EY} CY9DO ??U&_"B)0.EϢПH|p[ >E|o]PGU)*B5]/|]rݢ[5|j|^v|A!5NO2җV | U;aBU'uZظ{_+:6L}-3ng@|Za/<ޠ`G%XUQa?I+|f+GSZ)R|]j?[ @a#`򾮥^d<+  k:o. >qNpTYѴB?DH /u.h}n2~i |/q?ke6׈-q{ _*iSJq kBW"NJYS R8TWʗz;+<y4R5-?e|PTR%NZ0|M/Zچ;s 0*$ut#0~|j:CVUKWk%*"\1lS!F Ux*_I~j:~W¾[[LU>}_G+[]¿P`9e¿G! OFliy*u< GR+|rxmx .m b-2\E*aܷ_e¿/Jb]V e ioq^D{<^D_\PWo6˦#o.}Yy*}/wx]a˳LӮ*]i+t<WI~؄ `#5][ ~޳u >d|]h l̇Y-Gs*k}qbaS#F؇"k:RwPzK/Un q_ BB%vtwu*|5_'cˠ,bP\އ5#>#źG50d5"4{OOq8oUpܒǡ :y E^{y᫒1I1Wɥ᠜W0?7q ğE݉V}N$aL0iCCĴパNx&{@+tHNj<&㠸LeDEӸ{@9iC9,Mm+ XS= <641_!@yqO`n lȩ_`B6aLإ&|cY.%1xnBvvmVyer]uVi!YN:/T̷TPw r3@.`&U%`?S3PErs D*G V|ú0} r*`Bo/0 #E˹ a;s _.vF-/"-6%L&b 3yS |jZoR ?'=2IT"i/ĊvN)xmBcx}~X'rCyPQ#rL5yXDѿVsXd0)_V 4 t,ľ&nGG뚜NĽhsN(.92]xTQB/ƄͼE%LWx<k8OW s,[sv۪ jEZ L*[B*S)Vr\m8}u$hr"U ̀(jBhkp?Z!KTeq7D<5 ]L%2~݈ 0`" ]b0i*a#m䵐 =vs!K`E ~]P2O(ETy1Dȫ1)b6AL]qXAYY >D]J-+ `2pU}/xMf̧/~e JJ}";q'2W21U CЯ6#X`BGd^m"bC0IWiyLL]Tb.xj=E)'A{V5Bb_ܨ1㒀E>9('sbC_ꙸW`,1[-2B]LHbKFо.hʭ.hZ sR8R繸 jņxWy+ ?TBY:0̆8ֵ21ަKHYJM; 1PW훔YAwB0~5yYk[MĶ(8Bښ2V*/~2Jyg4]*iߊSE9cvїB̻.wQ ?i>Zmږ!0C٥"^vy.\ څ AV;,0G\3})F-\  87Y arr.1/r|O)1B֭<@ %:gS1OuZbOb)r1[vД&+l%D_$7|ϩy;k+>"ėckD7溏[q#^E,Zs= [ї}ijN?87'4#BBw0WX 0e9.J)}}?')KLX*s '?4r>[g:{e%9 ,$fQ4,̣.䚩2fV\Y]"\8`r TEKaǩ}i$q e;q/ oxR!ddqqN{-ֈ3l]H ƙޙa}7UxEΆmx&ߚka@oЕkeֵӁuŜ7.cو<XWoդFw#1X[M5be"_KD2 D,!_brn\P6p4m\졑7nJ|Rۉ[ִȕ<PW7r^:\"Lpm.~TZ% ۇm!>@9cV:!۪\Lpz)v vN+Ю" uY.<-QKۜy%]%b0W8&1q0u\xJ l/'r]n&sw <7.E5.9EqXs; LxW"/(sOP|bÉ) |ȈO)`]ۺoL75MꟄ7ygEj&&?VPU NjWenVe`ve_](,'ޯ4ȉ_w2GEY|W4VmȽO+Z#}V%I׈8}qoL@WU+@_D> ('`kEBn"1+ev8Љ<˸ bBFa#xr6+u8: Sw^eWQ Ru5 a"D!s)i*EpY X-LLu"zq'm 5Fr9D7?>qHx3vk# po oXb_,';e!LUa_a%Ag3_c2${Ǜ8ZYƵ |3X:׉8}|Ř}M FE9'2c 8o}q|(JDLe-Y\Rݺ< mRgX5>(5 ">*l>@ *ˉ010# 4 !< F22^d|Ak8f.6'ޘC-QΦwjL *X r39눢]N `rm %mB?<bϺ$&pOݱiEYZc K0\ۥ–aC 4 Pu#xWm)oy &"C]c`sM:>0~1M+Ni9/E\#B]VcNhg8Fw&r7@Gh}`xӬKEToKa>>-B6z hw&x &5큔+<1f4ƝJHC Xu&1 >,afCpXߗL1aM*d| 3 -I;!q\e >,M Dޛŗy.=q]`¯ 0W  DLS|RԭEn&yzL-hP= OuVw.9o/ĻZ_dI8E!|Bz,{lj5m :k\xK؊>߻99kf"BDr3C9n5-"@_']E*I u |o SoWȻ ޓE)c6AD&T:/D L" (nj Fo5R[v)P;xeTG+B9Qb>L!]BS= ֕x/C ?B \žp[grN{8wy@#UH w+)ee(' ̕my_rOF;'xs{e+rv|DU8CVB^Uȝ})Kм\F#7<&]k|\ʍAU|UPWyCKď7s^;~U%①R>c}-|E (qkтYMIĻK+2IGukyw,xE |?J}B4̜~N 1B%n@z>=*B,`"=(u"ze\Sx g&P6d0q 7&B݈x8q{lF#YN+o@Eåd9aj0_,s L΃\%iߊS^5pZZ09|w[Q,D8kO_~;D,,¸A,'|rDbHѤRi0B4fH])M.V[„]).~+Sqj{vUaNY:*\%=< x{idIHo&U5|,YNV9 r"zH_/„GxGaBN"!^9„lL;r5Y ƹ^`) <^;: nԲ?ykiEa'5" 262WN"s$>SC8ms(>!-ˉ|c7&nSqg`">1 `o˺rmraoڢXo db72^p#8Ċ5A|mxVn9oH5BoEV*ƲIh3o 9ٖ"vx+{E[e>,=X\G hF NA%"ٗVU!Lˀ\e]A瘕IZoxLB{LO AБ=uYN[ 'F4; m׊5-."|wPNP,.M=/hWG/=!a\^a|OƗYWER[-¸FLfTR(#:8theuO>p[8¸ץ3fDlOQW)CO#0a+Ŕ rCS竬w;LL,ˉaY#^ƾ3VY+|h Z50LEx}~LR ;|c &Q  M|E>9 E\|(OC7+e0ABީ"Oj0U儎 04ľ0z; ]QX5x~p20) Nf{2yEw8 9`5Kpa\5G*B酺" ʉ~I;0*hI0!#T] ݜV+@5{B&xkݧĝX\{ ط0SD ˜D&I!ujX8^9&0uhW;E L|+^+D 8ěg0Xo;.&w~@4I)# Pbčo2e:kZKvWgˆ߁P%,wy([|+Mn:.F[d4;d!y |ѯzo|<{߮V[G\%ףiYWEyt)e=ξI/7mӺ?g﷿}Ë9/gOgb<[MǓxlO_S0 :wSI᭯&G%?rЕ ;;] &׿yN>|d$r͗7f^49\]ݬ$y%'_/mr|(ܬq,yLJyhӛ~}9`v\o/) 2r6^|]O}old'gqA\WզO~o/㿫mr TMr@g_&Wcv|v>+_ꪟ2,XsoѽyrËw?Nwo%~!ՏG/*|K@!E^ v_|g0i'<%"Wϓ?IAgρow/KCc'>9b?Pw??:_&o_c?@8R;Mt> xJ0>fG6Kr>}ղ曽$z;.o?>~~CVvu9^KKX_U}5YO$"5dEŰ.z\YӋ5=Hlޅ]ڀ5 Nd|'K%U L!.9峯;&"ǟA.p"}a-5C֝ ?On6_AU}Cj6ق<榫K 7jj|uy~xX4y.{D rnVɲG3Zϱ~3З~5Y)3chiX?ϯ$?_̧v*Wק &Nz H[b,٨~( SPEbBrbj_ks M)E%f+%cb26/T}:Vk`94E!!=|z[6hI&)?M.3n'g{s'K|Tm #?]Z9=^7Z8+/A̡T4Bd?Sgqcz/v ԋ ,%-';ʆ Nl ߚ5GY}SĨW'#OiV[ a_>YXExM U&9$<\ؽBmJUah'Ko@3_ࠐ?&jo6߮%&YZ!m.,EI|!7P;-ʗ)H$PZL7 ћgN@9pA+}UY=dVJ.V?~Il'Oվx=_rEzŁU6zbaf-6[Yzu1*,YzbDňpbK+T=CcITxnqZb p"ő>p⠇ tԞiܸ_\/@OF"{7(Ԍ}IӁ:I9ۇ) l<Ҭϯ 8 l3VԿ1'(p Ӂ\:ԧ/wuFCJj: O/aXϣ_TDvU=Rv8mj\~9m|Oi_ǂƟ쵬XMfМRB bdkFu{tq=7+9^NW'NVךHȮ _7[KS7 oq0Մ95z{ <>5Z|d,87fֆKjn/I<{ 5g[q"Bk2fzJVhZEky2W2Zy,d8?2tS <~wOF-'FW zi Vf͗f{cș?nj|}(aB$/ 9E$l?Ubp$+V{"nIդ凂VLJJga\PޛިovI|GgGXdGǓ;tsh6^lBq&5>Y'` vOc8|3,ޯW0VDxXM=>#GA*թ!1HԬ&4Z`*Η3q~ĩhX~ \5i"A|C(U[W"Om#hЖ ~#TBjı[dqZC/NJ紑zj<uKi+-: =ē\>QGi ެR~518cF8@P6j%|(th5FxZ+IL>!埄8ٍ' k읥1i_+ '܌T6R7|dCCZ4>m Dp@H'aSPqq ]ǒɆNLX46fNir[&og7h]4i@RƱ#xI"c#}+uhmu'p:L\1ł#ar׾A=j)rK*yfCS7GgQ'&4|+S؀B`W GjXЙvGAY2+F$7 f_# v%SvjEnqbJ(΁K&R =hӀ V WPW1$*dvy.䣃cցJ"뛧\  Z5y=wN=t2=/?MD{ɠ^'tNy׫d0+juNn=vQE JsGtx( c4paPr!&oQoƃMG%Mv-|acF)UIa AkXÁhlٗ-'j:'*F焭bD3)tJGdZR#gDpgF7-_ w k+8 _@:ͱ/wi/ׁf=ֆ Ι\ KBE<f{g Lk*E38jpL5[͕n4.ݤ_C;]–bvWPi6Kc5YJee@u&MhdM=C(HpWN 3 $s$}N@LYavuQlFi¶~)߄(c,wJhmDę5J9FR4n{Ze@ӗOCZze0ܰ|v=YtP6,(4P%׶!Q5Tg}D7ӧYUu'Ç42~Ɵ7Ogi,K9~?{?乾 Uz28y r﷿}Wx_Eok!p'/ A>I2j/zm?jalRjaɃ{qU0Y]Y×oMs,)g:-^] _%9VSLJ$̷D!Y_..Ubj|2컿e@퉦ա+ó|Nހz#6F`WAgy NM&I mR=ҢSϯdΗ/F|9:m\S};_w.d'//i=遪JVw7Wɏ9+~? x{WC< qSэ훡%d!0pXՇ$P¹uM{ځ3?5AB}H'P{T֨L:)Im^Yf ɹm>&W'9OsT }\,G[,=R 6H5$FWD7Cf~zJWWiLAeON?^Z&:_N' E~U 1]}|xǦz=A)AvP=lUb[O4 \ ZP :c^9ECep'O7jJ|wkLU@TL jʩRLA,èQ,hRjZ|ɷ=O\/YbF!5XIZ0!dXlf!LIǾBq{8O /O`rd -.`x: 0!xFFJZr gpybe(8 N'W p”Q%Pl.x*(%o& [~=_O20Cy_4_ ^<]p@-kS{~z~rs֯w~Z q`X{dqEAtg [l1ѣwN#%Tu"Z W,\Ž!pv.e+Y|E ߧ;[+.WV*|vT')T, âDϜ 3kѐ®CQU-?WOX#O=ᒈ5鉨 %-1)J9LϳͶ.@W6Br}z5AvqGw IjTۋbvbp|L:`X޲hOֳDzw=e^hh )[Wkc$Z\F$pM/0^f c1=)>^|ػy' KeoO_~Q-w`Tǽ{uWRU=c.8(`9#>?Z/ePЮIs캦okaz3wFT+D9fۣ=X(xV';+=`,>Γ'_H.Ujc0*L0:[; zotEp Xnj/Ou4z:q66‘g0=rc u1={f:>'ԑѐX"CA5=+qXU|zKGjL&F}18lx!k^(lqA<[~9?Q/_mo5`F}+ MLI  itY2<>BJ%͛~}= 4d>ҳs)5͌= )ev~xb_zy-)+3Ha])5NbF\Ǹ&/C=XO2+FݞM`o E1ld4z!M#Et52JanYQՑvͦ`L8a[숄'o۠}ådud_`6em(ڌsEbK(NydIB"M *RoOz6b!}+(9y/Jb[ofOԆj͎i ~FfC&NnQ5?YLPAZȘ?L[h bpoV:lN# _i1Ѽu2Bאg?V?YP _LTݒnH\p#oy=54>~~?X8EҡM:(/Fs4I;)cԉ 3W qnL/zNv L9+փ0Mjǧq7HcxEy *2 BUC}٧UC)b;F@,-zr5h%!IՆ/fŸ"[]̡dAjvqK{oN>yBTWr{dB,7ɫ `WL!o(o?HʔI @f)S[z@[p[l RUE\KoY~OSGڝFÜ3&R(~%qZ$7->! lNj쎠QoQ$}g{nY__fPvL@'}1x{ ͆5eZ68mOPvHOYc כ qhWS;S`,ܱy)(p{ZOA6?5F80 1{BHVW6G܀MI5Ek)-W`A [c%Y|X)ri>+* >;m˻q1Ȅ\PE[ AZC+3p{U= ;cI~jH{LDY'P#;19Kԫ+[BBc|ޮ L1,ĉbnBkCWxN;(_D.l$!j{XC6:߄AoKcxwv>yPwv~w'I(K6 gG+uK8am+􀨓byBQf6 iVZ>j}%:=Б{ &s' 28Gʝ6VE&c:P296[(tAj1/7~; Gne-K(ooؗ/8^``:Vۻ[#gg"sRz3.V.,kT㷠ؒ<@+4qkxtK‡%f|ڢ83 8$#G ov{E7>#UAso1q^*ySo[#]~&X%um d e##=K bnzb j>;yU[=JuuPvJ?Cڋ/?׫C ԛ)&[LRNTw^b7~9+Э)*DMRƻeB"j{2Y'XG.xn`x47 (Rq[/Vw/rT|Ǎ^p01u DHrzbrOR c>Hz9n[RFڪ_ރ?v=M1 }o1z>*!+LZ=9 WYW\_j9E$؝$ }]>ySd)=CէClcgg0 罳(lƸqY"ƒ,zႿlAu´A9"Vn=Ue'a+ 񑔚rs2=r:>{LH;:DN=b/0qeHpĿNOW;IQ`?c 9F~ݮZj>D,jVUqK?ٵtN1_]"g!'ULJ:XP6:S80ojt~kiyy_FeoI5tgO f7酘K|m#E^m &MD1\LEO0Cbű(ap/aK1+JE*)k^]Yno蠮Xaj.{ jo <1Cl&22DDqiRLx,㬁)nöQ343D44ʄ aE5#m0RK}U~:@RP,= œ$)Dl8@>jP<׏\zUꚏ+j=WdOF^ְW0 3/6w:Ajg@JBˏFoZۣP кiFm' /yS2M^0tYsǚڤ⡀(g4@6i![9LyH~Afi`#Gx;g" h=hS툉bNq}NCp_ tn[VWگ|Y4,Y ?gfOy'ƗC&WExfC! 7X* Qfǯc57kHP$/4j1(/M sRbcN-hXxDuc:Kk6ۡѲCaj>N>~"`gUHq,jqձLt=Aߛ|` >I,rZ'b\dCud9uuu[|v:Y7-W˧߀WnM]bd;f㠢C,(&G$׎xHlD ڳ Jacs/{U2p)ceӦyzdOʲ]s~)xBd'o2ȑ Ȼ[DPGŜR&X]0л:J&?3 Uvf-ot~01|Wso&=a ~Xc|?#ƾXwyN2q g) qЯj "l4ʈ3PЙG8WMTx_86{&̳m.Pb^ .'Bv5ϥ5gԇ@4hKF gU*@{N,n,Sg;Pz1:lz4+G1C]Fx|[v!&oŧ2Q'nGH(fotcMw;e[wA[щWg4oK #P,+Ąʐ8Q4riHbݵd#g3/ uoU_|4/w .:$՝6_$N8  ̓ǎ7QE&WXo rOb-2Mcׅ%1:w 5裿+ vRq ai$yh/Άҙa0DLȢCُj\W $woP /WqX@vrMD`?$r{$yb`6 [`v9͢8z ӄ\J &y\Lc@t+FSiI{/JkvM S 4 K;xfyFhkWVW=e;.br}}-P+}: 6X [V(T[lV(82_ʔ_`TaV6&4@}`d ѱBn'9z`f. z{0ncD*t't#݃)ňÇz}MzDtKޫrR/qL2GOŒz$m( PǯVTX]=Mͯ?Ŷt'[G/X5WJ v D͡tƇ&)Ko/;a&މ'gxB!N,b疐ة߉d hBw*8|7ŭ *kM&aCt  oŤh@#|.Th:FcyQTE/7'nYuo/yL_ E$yUYKu5Bҹg31NueҦ?'ܬb0iqq =Tda%+S={~0Y?P[oto,Q cY`]Z;;';sdxz1Y.Mh8e!kd|b;qvNSX$BjƇM+֫'7X(?P.q.a/>"2tN>5zgW1? fj) 5. t(7Fo:C0Q_bJ^]/g!)k +`]B6qc/]Bc>Y33%Q} EXQ6V-yUJҝ*b˂1 Cmo?M?J3syؤ-Ƿ1V_"41{(Q'kza#B+B|4T֌Wi   _J< ҮyϽ%A/+?\_]ƇYkFqVd/X4*-Հ  iMaafE=)YKOI=#9"yNeͩ>7@#oڵDw5-g+"Ul t?:ML<|#B@1pw3 >tGI}w=t@> [ ΢o5QzOI=Gfqp_eCCY ?#S ,?kshw1?MU}!`1qy"󫝢ϖ".牐'ٟ_gzR2ð5] }_Xg|m0[nYUyaCS|3< MF|Q{óM#f},b%CCnT\@B4M1T@eWV@;˕aoe:#O^Z=QA 4%7_>ܳ}"s2y i` v`B 6#j޺H6>9Dzt>~Ǿ}~}П_ "ƿ.soW06*va؛ aoaR]s8]&rh%]:cɈmA.ŀ` !(QZ j}_xS@:o XCT>WQO?o+(/10Ve_p ݵՓ~+ޭF݅{ uԚUg G9â IIRLmMh8!;=4jnooSk4,aټ+0k) q`_|2D %fEBǍ#8 JΉhvgs~z656V1YU,rqAq7,EK5 _w8Pvrs 1'!ݔע *j(3o8&~ݢ'w6^8( ӫpa3]^u~bݯNP %=5NEdvء橅Gޖy.WcФY:٥L? \8m6sIe K?YF%y0L)ugXT0([kX9/Mq ǐMqzNLJs>GtJѺfJ'ox:ep)sv\Սx#&/Q >aFxJ^M'3] լ|4{h1??џ޳tE#:wFьt";wO ÄQbڼK&.YZE/EF/~}O>ycgz-?~!,qmƗgg '_ M÷m\!L҂{MmxnCݼw2a|܇hm!'QRKMf5Z$YꢊK^/Y2d~XyP$^\QмPl-omM?ҷD q={!}I˟O_?p`Ceq)&|cYǒxH!`Y36U89,h*s싨6/B/YgCu\m]64AՀ=InDУb FAo }=] Gl@ڟ-ޝ .Vzʑ;6?7F۸ Bfh8 m/5ӈ6$v3س?ܬ"/NjA} tre`50| C/ m.a ـI:_ lWRP\%HdH:+R֑GQXXY^r'﫫To3RϨZ77iڼ:U~{)Ud:qy)ʥ+wyrPД>|K3ShώO5uPTDF5VhtFM<ށ̰fqI2OE[9[-.Um& xhLqա͘W~ */0ۇ7 hqeѠa =SRF] x~P.ykǬUWЎ0],-s۱zh~fV0;ЗA 0Ʌ=UcMJj{O睊 U92t1}ɚzJw׋zryY/1/4%>eoj9>xd4Aj[5tBylB9OHK!΅br9_0?1vܼ&)n"47(sj;wkdv2Ob]%秚^iG|sj~Fߒy};ԿO]0_~pM%;e5X'Y2NVm5[H=d`WgmHE)+s—D qu$³^mկO8[b΄߼X|^-ٻJ'XFNqU?|9cZXt4EfuH.FέfN?e߀ smyOP8CJ4lϟmu*ovT\6o 5t į7 H8lan P>Lb#LQ#MSm7~On`bKsa2()/>_ '9RF|VMgF ;)oWx R8g{+'T j 4G0Cd:(:+=\ȭ [g*#wS*S/T4bkk"VRڥzJ?Nﱿ̍vߟzGFPݳ#Ϳ@ 2˓<Gl~2>>p+Sh<ՆА+ئ~ /9c/ĂU ~|>ѳOSN>#},x?cY^e>XJfdދtB*M d:zxX:4O=PJ /"oIC{*2Y :/@Ҡ Gszm~Oj9Z)R?+RחWsFo-fCS9R5?_iީ•3DMʩ`jņ Wm'Ql^;B6Px>[5* _զשSjl"NֆR̶0Z;:}:mN>ݣމ66 Yoe GeMmهncf!7jq9heC}'e: TxŽ'A ~0!>;*a'_ۉWSFBC/^\FZY^OaߙK6۫׿!TYpC1Ek/}>Ff\ A>=fK{{.)9{"BGhYyމ1!go$d8l*؉VveO[tg]o=+D$n#mondgb6wZSM>]~ooh8LKMmݵ1dk[BnP%yhxnHIlk OQJ%W˸0ɷܥV={k0SJKF#N55!LBK99DDtQ?o!Q#Z˭m;^}m]xrNU-2$NP?lCAxoV|و7d\e*c N2֋18 bS#&O%|.)P(b\EJ]p(j.Gƣ΂ldQ1}K^m# 0!@,sp(>͸>,!ڀ'\ytZ&Pe&o1% 4t;W0}+FIQE3O;,pbםAT5'~"QZhV0؞- h]؆Yf3᳕F$XZHQ=g{ٝ`3FڏtHP t5`}/K 'yc̡c6,Ynh86Oc4)u:>CH7_N'eTy^O4_fHA睟7n'.hbg`CRΛDx}A;w= `s!-kM283hXj$PMQLnXJ>;E\;ק"Uj{UpOƞFÇxƥYX0nYqDA9=|E%*:2>Y t$u/#R $QpZ3~cbkep)ة{8:wQފ!ۂeeWȟ%< Ll-VU/I}nһ(4V׏qWg#⵳޶~;6Q/?|w>] ;vx0MBm_( ]Яe*IG,HL  ]dxr.MzCYk6?~7ĄGCܢV200n&Yj.b#4<+D8NoP{n5cg>P%dHEregj,VDud~9zM|A[FRPDj[wЌHd>(FO.Ft~c6CdCdQc# x׊,* =P{M!mQ!#G-L@/Q0[-x֦ G686f\,^7rU 3Y۔ΐLB[A(Dќ"v0:&SՕGjQ??#5GbF$p<ԏP5)$߁A?LR4ePnf*$x/+=)1Tۗ5$i;9v^eA΄Hg9o1ji_r _Ӡ(Elo%۹jo.RMj'Ƈyf{PTt#@~^O_F__/E>^|yӯ OZE>r]tQ/QsJ38n/H(9 ٕ#nPd:^(U+t 77 VpPaMA=Xf(^%\+Pַ& zw|Q#{d5 Qn"W*t]1Qבã14ΐuz}sNx <ǩ,(?m \ ~۩NCX; YHn/1T'f4S7QoJnEefsYN6IVcr0Գ~Es9-Vw{#\f‡:Tӌak@OͷzkȮx~Y!QBsگ{|QT `$[:l7zc܋VDZW=(tW5wލY|J -U]-t%iAԶho}XcDvs (',GXG#j HF<ujڛ 8L'K]CSp_ AJ:c>ox)[yWoca2%DĒB?uv0 ܺlNZi 1AFyoo\{a^ɨ2*}%CdbPW@=:=8u8; MYbXe͇vݺ5d:YE㦳0boթ@}vU&m g>?]\}T>*Ԯq|+QG0S`yVl 2ܜ2&0m]7BkyVh!h%R#S3=k-{#?zybrq씌O'h6nVv ӏ!a8ǿ.yrcT&zn?=i!/]vBI2oCv_9"\qƿ)*Yp)m*mTedn'hs;lsڅ4'kcRu+Sߡu(P̓ƬX@OC}_(ּ q/A'4W']m8KK&̢wxq$,1#Hf7vζ7ІՒTژZ.$4>9^<&W5답p;@ьK{?J٢Tŧ6TR oq{oǻf=([c*p`qU̝dC*gs"Nu?|$72؃:J1Kw!֏}ɛy8^OFo*{ i /Ϡtԡ+(gbӉF.ypkǞz.{bP8rYy^3ԯ4Ʋi͕Nx'$,e]L/8=BοHrr֣ŋ|KG_7[ЙS+=(VW Tn/8M(6o4,^:%V(yo'P~Uz |L?3wD"IPC ^Zdy-@/-LH:|ٸJ'+]g8Wb[ 2A }흎<#=n!кjݜڟWb3"S06e KmQ#;ETm 7?L]e嫙mcMdO =l l}rۗIbSķ;Nҗ^q]z(HH=prh%Nyc;/)'zGPyzO?HZ' w[5cHH{K$Jg`Q'IR6=5eCFcj7hiT5`:O5h#6_~Wտ @N6 7g),֛fbI:}<_nh[l͛dw?@Beͧf{LEYuk klVkF᧰~,y7{f#@Y;) tNKe; Fm7 W;OCrI61QA^F# M.LF&bgsq.&j; -&^i3]9wp  %o_%hF=\_YRo{bUbLkiZ1i\Ggϒ}X~@#LFϣ1͛fX_F v7_s]Cs*DdlJD;P<F+Ĭ_{{4?{`c4"m{/&k5j]_=Y {4RC̏L iF@ 2|+hx4OttZ;!&EuQRV}+wp5{ œCx(_}N/^ߋt{ר׼V̍KO3ӎu;(F]k?.ibt{C#͘F}Խ,Hm9WQ8Vf#;p|a`Ww$e X; _?y6dO}/V^́BnїnF>9U/5C-q6;ɣ!_~?·ߑmX[TT5fƛGȔߓd1#ҌjH!{!. y88O ѧ)j|ut|9>/f !j˘<s>So7W@?>#Nbu ltu`# /fJ85uoB/M[YߟU]O;ǯ_XJfw)J͚oLGb4IrOt;^E 3&/y k"OUg Xd}5ޤI鲅9a[C;$X_M  |j$|in wTdw٘ϣr}N} F[(Ӹ>=`9QfYq~>tqǠ|.w ロljX\`drf>Z߃r}7c'&o1Mvd$ %>Q+ݻ,oIs|"@&[ %hkq EXQpT/ V[P j6x )Fve 'wLpTK h'x0,5lH!ظ Hz@}1Д#qA\6dNOOI4G)e:[{݄EpVIwZ?Sk.хS6g'o+Lc7OVv0mkp#@y=JIcxVrN0rMuҭfukU@?(c ؏!1oʆk5@-ul=rGd{+1`N8j z7V^6Zɤja4^Qe`g^nn6?}@6F3 iSHB+pX|=7&k?L~ql{A&~`%U6'H SmSIC--=vۃ0t o`syp4z6'|wCc<(}k!>'ü@n 87.4pu5W +(Q_xʁC"')$tlKjp Ԑ$O~/8h/YJv=^vz}Ubh0DrlF[G*LBra;Hw5% pUc#F3WtClN;kXRlR6}hu0-u__ :^I94c_?R'}3a4sjiMg.7:{Xi0Fb?c%~^r۽~=[e'1li7*fjdM Ĺp9 !Ȭ;Z }ٜ^1b̻Ϻ&㗷0r JUTdzxk󗴆=hD1 YӔ Zyfyܬ6ނH/"a#s0#2@cx&'>?|E)i0FCߘ_x$aQ # ?*B%`߮tQZ@";q=/[==ӏKu _(|;PLp [H,|}η[8Qc߹_8 V ^J+<="z h֮ 1N@ |J0|r9[6q{V?=dɰ60U#=q7,q1䋍yBp2yic+6zL?*QO?ՆG笠^x͵"Z.&u~$>V} {~M yNm|y􂴖ye _ڭۛK°s;GChFF+O(0p韪_J{?ϜX߮l~}&CsdM}+1o\9@,g?d_ZӿX:PE_TH]IwSlR`dN!b9ǸoBRzwޅ~gO P2x@ h}dt|օպ mz~<ו 7; Y t1sw od?L(BMժ(4*vZޮ.'K(2M4{Ԧd Ľ҂T~:@_0]dM1)Sok$|5-u_+8AIN؟-G怺?]{}TXtCi =5(h"gطO4x_____!w=^Ϡ~ d  A2@ d  Ar@CrCd9 Ar@ 9 A @PPE @P (A J@P% (A (~ @V A*@P T A*@+_=d A j@PԀ5 A j@PԀPM@4 hA@4 hA h~ - hA Z@- A:@:Aw A:@t `}@>t`C}@> @p 8?GC@p! 8C@p! 8ЁCR@v 8G#@p 8GЁP9^9 x9 x9 x x^@^@PE ^ x^ x^/) N̿KjBaQv W|<R̫Fxl+~T^[8{r cCP4TaSI#\IBBg%'U_D]zLQ"r`:-sc Е2*Ԟoo~GܯaQtVʟK'54 "Z]=ޜc+_ `DHD!>)r1]HrSgurfŀ)z)۰9^9;i]JxiʺQY)pJn[3W0#ύuXCDtdPbnA׭GgV}KcIU55r#Id$iچXW+{J@}MnZrT GQ|˻;s^Dҽ|q-l7EO3Jaq&壑OZ"׫=-4:[./Yo٢ ?1*5G})eSnݺ;49žGka;I1g0JiĎFCsC!͒rqt z9BU1Xctð[#> AaUŗ:hz4r#QáĄ#;&N~7fGib:rb7LT$OJ%ġȉH˽N| )"<@;xI4n@{C0e"S)O/%z$'c1(yXl e$ 6I.}׫x_=y,ﭪa 5/?w65 Bҿn/ a:1Z'AæE 7['r}οnBxM뱞bÌG*i~ "dXÒc;,{gyI85J3>3hS%t#L&W!xwf"(vBسz z?Žq Ͻ+0!F/p hܜu-7L>iW3= c'dW忪P13ڹ:[P #u6w6Ox*C62F+'۸~\Ue{pWMO6^Q1;/xgd-NqT4KfY0l<Xu=Dt|;ЁH,[nF.f2K'^a|8Y+?ʝI>cFe,ӎ % Ȱڊ{ځk4UFOAIh@m1|=[{[4^לW&Dp.j|6& 8.9䔇»1R=UZfD2y:[02 dtfWx bܰH/%nzU/;e̲^)ϣ|8>U58;OE@yk&VMc٠AUGΟwn Xu#*NBL ʗݎ=0'Ay?j~Qjd !NB& R؜l0B 藑?7{e/OcvԻ/lkq~J&06`%DgYȸCRY&d^=C{?><_,S_v'yC\C&ݒeTZdS'}? ^ n) ɂY>)}%y /mt~ 4wb={d6FP.Fh(87`.4$>?E,Kr|vN7*?IE 3$?y}pg ndnJp%9סTYu8 R9 (aӷ`B8LQ"ht, ΈLW1(Ba>Bo(!DyeN3/~2[-7AA4iXgٯ;rIL#e-6۸jD}߬InڪBvp|y}.D 4ZG+#5.^V.I;v=Rڪt.b8r7~٘ҭOݢI04 e< (xK*\nóE="ņ' %>w#>whUYV<. K:i@? Jk-a^{.Z۟  NS^<}[ #; * ތ$T !&8 f O (6MPK|XSve n*%^u|guwMZs$V3L|@]̿A(zwVCVGNN 3j@HBI觉"6@7_᧛v+@A H$gnmNKۀI݊ K>hFA Nc5Q})prKd2U}K.^̸S"fMi_zz~!ޏ]22gPA|V27bXxKl;p6mXahPv2QD;!9iy[GutP{‹egq2όBiX/ܡHHsBp>xmL=1]>~"(c8xNe>lPX?.8WS u"îy{ 嫐 .Ec(p'.kT5njZNaO'K?pzws_o}޶Fc.3l>J[X۳ܱoٿS:YT_)Ư9`.UșeAWj  oucD?썗+lzϾXxF,G"rN*׬&sE+p&;@5>-j\eSL u7MB?!:w*/` 9,l88}\oP|‹ȔKrsOg<)~>~[.>&a!_gqE+tIώ3sc/`n5]:;p쭁1†ZZ=r2|5Խ9)h;aIָ_f!u[K.L"l0*FȦBc\RpGl6ғGtGK{Uf$S O:KI*>PmX({ ɢ.Z[7[C&GåYhbV#W\:YuèIGu5yI{˾`?~˙y>ob7igՏb9y?Hgy'o1d]<ӴVhu$/jkm *O_t_R۝W+<ƷI<[g7a l.otأo}x BK|}Py,ʶȲ͎ES?/*/ 4QVY*#,k݋j}^k?_Qsxt?uQghx^=CQ>?6ᔋ8 fU; %8ZEUm%dXw=><|{ o6#WRb&{iKΝTugAog0הG KSm86*2Dٽ?jQO˧EdM"K49{mJɤH̒>ϦIdNdZҤu=aХn'i>kn⪔^S44X'MyV$erI<-WmJ HIW@Zfa`܂h*NI&w^{ՓYFyU7Sdf3.d9wg5œ[ڹs[|kw4/ W&ydxV?n'pr59%f]+0*FE58Yol> DG5f$5j/YGڔ9o6 YYEA\cX?`.: O-w|SQOH P q"ܻƲ;#xL/~AyW72a.!D.~Bk$5WgM}s#<4V㏗׿/f|Ӧ_o߿"x ᜏ̷?udάӱCrnv<]H%;ᡟ@E~"A]+Ey rzk۾QO)kXBXϵ7 #5ȥn tO܍T]C0yfxDvr]ȿ ?h՜+c}c |uk4=AOtpd~:\Mm= IϿK įV_K@t{ W|1o& _D+~ŗݯv_O@t W|A= %A@:9~?OZH]~XMώ 3= T0FF~/Q&R<< LFz'[6qi? D>_%}̀_ϧ;&k0#,.0vu41%c/L9Lo{<ڹ>Hv B(!1Iш=$D]O US[/^>96GLr6^E+lB|{v]y=um6+o`;!&Ϸ>QK^thLӀ] BB#K]`V2 v,'1E40=*1Y++2tpO:Ip9&d\"N4oNKP~0wx|0_N7OĪtCϓYP&K,;˻'?'9S {VKyAL >FjgXsQ ?>|Cz{Ԇa*i1Y#Lm5Z1 {\h o"Vva%4[;+K2lM7т܆`z6$pK3`qv8#sl 熠S="U^R5"%nFq &N綉RST"w3'qMHZ \ށZ1 nQa + G {)dã#=>ŕGo3[!)_Odmo{R?qĎR?fLrܗ`X?{0xMm$wn-kl:hLqEWqYL/!T9{X6°F4"GPmENPp>l#{Xo߇#i6B. -`B၎nWU:aW)H#JX7/> V .lфG3?e+z/^?Y, k$eǽfk6?(g]=D>$|a><⃖vEl6r6nI;pO=U范~)v-;zO?6CVYQn00bkisN@1,Ϸ)?*S=or8\'$ɸVK%v{AX_,=X\+5ǒ3ޥ'Bv֮}CK b]e/;l͟dv#G`o$D/R =$UP@n,~F E0)Nʀ:g{ۯxhmj}$YģgaİIh`?P#g|f3;Bˬn2Vx2r#[@n'Ӌ^=gb{&׉fCcy==]}R脅?CMzֽ5es+>xASSݮ|6{RxGDCk힨<|=[ ;RS$]HG$*tB$-v}:dΎN1w'͑wq)!b_}&Qmi!1̵^Bn6^w׳&eYUMa;s[Q4ExRӕN$o4ޣSC}sTZ]Xkb]2Gda0ŰK:Ba .P$,MAsV&`o-J"7儘VGK)i$㵹[xC+D!܌=^l%S,Lcg]h{gF2{:6:?fAVe@F^_q^@[Y7MZ頢Kzrn (Xn93ͯtM/^@he\!66衄X#GȮAJO0|/I-4+#g ԆbuY&li^fe/[mvąL 3h7l`P#?`A`q\߱`-Oբe`blp\wQf:?B_ѸG/A`|0_^ KQ'mUycoo W75+,XnAeƸns]r$Yٮj!s>7pK'FT0a1n 5tscǧg w6=ݑ?ߒn ?Ie;ƹvmaR ">Ν5C.i#{6]loiU%xXp,u ?lpp_D/콕9C9JQ_PSJ?nijyڬM|p(^%zێ0v}*"}V9r_qn^:v8 C'f]&6"ӥG\޽zܰQxnkK&S>1o젉 g֤s/Y} aofYq W$xWo Aꕸ+ t$&a÷/)7qϗ3Y<1&𽎬2?k#68 q|eFzhǵS?y7pKnT"c+㉇e:W:/㘈7V H#B= ߣ1 ]ybW=F(1w>F~ s.W/CoHz~*ԫwsi 37.j>CN&.Q<wI,O\AQb".$x0Usp>;Y:(`k}J|`Gxd_v=_mQy uS fߕ9s˖-\-$VC8~ӬݣGG'~1^b5%5 |jCr +{ԼvH>2Qw|ͤSK"V$VJiђY9AGf %βa憬ijD,+Ӧ3k}׎Ȓ?g3NSH} +(PeJ]~IR޳62"2"222)(vCy|̠<KHuƊھX1h] o+worEpdj O h4Vpόb[3 6(&+yx;O&g!c#@@ͳ0UX$z#f5@جAVt}w^UekhglxPvy'[K<Z^|@FeX[c)I1NZm%pW F0u]*Ʈ }#wj DBaLU#ڠ bx[IwA*5[1ОTL``>g8 RL  ~(n=@sp-;B5V7>Fe` 'Y,l^VAa`m[u'< Iny(ih"a(RmAEh:.`+*v-)= :4! PY0`<+Pe*ʻUg63Sx/)<"2 c 6+9[}X3iwT=}bOL>ׂʳe`x!ͣ%kĻ(βD3bM mZ'9Lz l@n Qm1IElhqo{ؤ+(oފ3i+X ׀o :g(Y82~i wA@AiNh!sH?Ւ,A+ڝbɦmZ`w~@ZWH-`qd(2C,A!ߢr\I]4Ƃ%"~!€M%)&D@wEQPFPec$&DG%<@h=h ,{I#%!^/2hê P?hQ"ռ$1`pAD H)!ٟɐK0H BdE8V$qAJ\xE1TRf,oJ- Lf}R:HQQ LƚtbzFXA +yLx=܀bl=@F=YcTa}5G^R\B !g/hu!s# cp[' NlJ#5 2I GpIBrBEh QS ~eEEēd I!ypE@~H(K:EMrR0k!6A%8yKxT1X)\rr>6O%*>2[lmn;hx{CW+#-ܰW v? ^+ w)5`pTQ5qz0@4m1 :.WփAgĕ^Aќ0觍uWo ԗ9Rkcs'_q>R+e,m@W~Xmx dxI|eO⓮c5)u|>DprwӀ-&rS7os|/LCVC-ё@uV3T[L\X2qS1dqs's΂לQU\4Lz3_ژpE 1>ϑe?_q+'0D pn{x è,̧e :b㨆+8'`.xDh5~A ZE<ρ,~[h@l4SL ѓ ?D\t,ͷFaiG &1Io*ca& 5Hk NW< q3ɝI33\Dk^}QinǭpChG~uϊP[:3 TQAJ(|MYS@+thCwg͂Oͪ ^U4Z }L $f2,RjƯfU0U@ԇB :ûXG0djNFʐB%yj gvDhN* ;z}(ϐ^=0~4`@K6kx-a귗  :v7(IAdFRu'B0;NC#W;;Bh.#3ﴄvb Ը0Y]b${ Ft:5& Cb85WȒ0iL&&eCbhw 1}(f\47%š(IճY9^&%."RCLمՎ p̭wG‡<{i{0K.!"`޲kB'tRS,-YW$6"ZX> `N ?LWeV3@-O08I`zYxl^h s@T4{#;Ρ0 ͛t `@•TڮAV əQ&ƽcH:N&+7*-nsm7jyM#m`Uxʍ5 <2]0gxp3o0Z'4{(<\(\E~']Xk`V.`H|lJo6 D*s]=`W,NXks\ z=T D>2kٺ˩\eBі6˫ ,,̧bzu 1sQJO.wXp6`\׷p5FyK[ե ـC5(fGY,I$\-~g+rq'@X_ VUK䖮2sSjsZ^{2dvpNHqoR;_ۏ\)xɚ6Qն\Wʘ)U59[Q{ŀCù5M~Tfӿ.<>qSÏ,7j.~\mԵ!spvyG%F"&b9)!P8H<׶LbK;d(.C[zc|KpFn[ݲPN' t4?9ynwuKM|npq66)wE6hBi-%mپ瀳)M ?{+hb1dzg\גe FnՈ(݆5UDѵ[Gm9INJrx'e N2|N+"ʼnLAp&\km.KϕN1:/" Ko߉&廈Squ:xmíe2J88G&ܡEch"Xp\X\rVkhe18î|:yuT{lm~m] ^fAw(.V[Tk>C -YzL $+稒_xx!sFc7$~Z ч.ZHonc7z M9 C L.b(*ǬsM!_3ɏL\4D(B!5F>xa#8& kZ:]$(PцbD$hi" =EI ""{dUe`O vo0EAס7OCF ~3xW/ItC YOvW/"hQU>q̰$(/s2|`0UZ`#C Uוkqk-‰tח8vM՟&熋kbބît yk0C9-0܏$u֘T4w(+^ZFcal]vG_<g$芗N[eſ?h_,/"Y܂k:aKe.W0ǀ-dwpɽ?n>z}@{lխ| 2uR/?G3F=2׌8YL9,T*/6٩ |%=[bth(ŝm\Wf "mؿGMj'GnD@m۹;Dq`.ݡ0Ȑƹz\˶n |y<6n^|<׃Ω"T0QwM[DV]qLm)WWʕ27t X $U3)Kpw*h;2$Fy?8T$ }󆊾yEh.ЇlD59܀ ft`mBKEMP!x< 7(^.2E.@Ug?P!L^5"-tѺ̾C:^"FdsrAXVx 6VЖ]Iw-RW/z+aWkd5qKZ!a {:T[A2%X 4v FmpG1nEVQzMJ.LjXu,קfL`tXgTpN}h%rƻQĔ[F,,:$p}d"KEl .q>.An'+;@/!^qy8Nڄcqy8eY X6(%يRr'x `08{@8v;T}/jU YOyK`*;x(<)r?kYA{Rgup8&\M+-o-V>TWvUa ^/ xESZEv,헾Eغ5"==ì^ 뼫NqwLE`%]M&G2"<ʪx {͒+tCm82Հ.^#2$]l}&2+0ُݾʊ&x cA7c&-JprS$ J-¼E8﹇~HDϐ-Cv@;90Nt'k#uv<1qW702^Y,&q~aQhnqQ)hs qf`i2}Kwwy2y@e`Db¯PY t:[{$aeGb,$!~p:NeBw>DlZ. ="071NqՕ:$|9S81~<.؂x/ !<2L2BKbt4:®NХ{JyEn~m_^K뻜^!+K1NFck006s]fc2\'nMko/Hmm(tW9c YghW 6_eY(j b,~}|wcdC}CH;T'lB燶ߜHv_Vcawc'k޽b#T NsEi 퀁sn,WNdݑs_UE(15׍! PEm~z wQ"vstJBn]W 7V顾*LX J/l;Br3DCkO# N HE?L/Ԫz 0. "tgnnЏ;7ǝ:bw.4!M8㒴H713[_FGo*F|?g[sR >Yoi49"zt$[\\<í̥W& )!/`#I Wضl֧ޛ%%vw.,! pmr wLNUyaa6F b&6T%>T%x6-ީhnc;lb8.l-n-r~mfc1xB7@U{p\'_~{Ͽ w!.y?oC;R}$?n m~w|u?)]uGf;-}`dүמK ^gӏ\,{X{_Aoɇ :+a>9,˙%nCv;!!@1h P;? #xM`:Fj%3u6D|oVFhA,JR%UM?3 :~RckLZk$WI rmK$~7~@?7Ap`Eű9wx3#pXd0 }WH!LH>Ŏ`SM@_^Lë@.F&WvKU1i( c AS٪ʾ_V%K`3oL?ӧvRI`#{@o[ i=zX|O+ӵՓ$G)8I멒 \ OA7( }o}g4|W&~u/qb߂]\VpY'  O*rX~@|#QA~cpB/![9}$ 1ARH/R\ &/L ޾~/x>?#׻(% 1,'(j˟?p#tQ|FOAMƬqg^&cQ7t$D$a5Xz}%Z%M{*0/@(ξ~ P;Oߊ,맵i\/w4.[G8,&/چF,y^ 1,TWgK6*/i0]Ho/|v#ݎ%:yxoP)rpK8̵9$6s6@&MtԀN w('j|rU =AR}9ÍoEqI*Ѿ7 OỤR#&2gQI&Ԛ%SY6NdF5n~~/Z>q.fj24F- '_* ÿl$O +f2%df[䒑wp8JA欙M%ԬK͖TsPJglV$y]F fRj&y73IMTK5;yDžK|?g IA~mZkb 9Kpl 9Yl%Z6ptlkbN.@ެq#8Lh^ts]iA&9kAhȬbU[bxi]nu.KsH¼z.uv͗Vg-_Fmh6tN&|,Kj)= %m;;z,jPw~eh$CyV41'M Rhg( Z{^K36`5D nGfIM)Wb;-zZ~TKsMAͳT:ۮvn6/Ά0{E GsZh)Z:+-ƧK)Z{/J:ikz);L <$׍ķuA Cy>oAI;KH*/vR]Q,gN,x ]\s<5غ˦ؚ5M--[h&m(k`Y]_t{eL)KeLiN,V1&J|/0tRT!R>=/ G, j>ԫ6sKl^/9=uTP^Q/J%iFFa%v2Vкkhܨvuӕ&݈-Xhfn:6YT/IcX[W_cDxNN(ht< )R[CNm, ƶ:\sG4SX{p\%ck$&YNM}s{qr p=ϑNk2D.4XOZ!;.ʣOv4_'Ѽm.C V2Phmza-QL3/ (նN/l4ag͸hb*ۉ<KvG MCČI#Ҳ#JIbtPi'dbBQÏ@K9%u =3=*S5tzT>,)p\$+|9 C:Hf9.Фn6vc~LUNXԊvMvMzVub@264fR\5F]ymL՗ +FFTFa~=^ڱy<͗ `U׫6Zi߬ 3^I5cl*&T- WBu܊X|5pjrJ)r sNEJeLru= L^EWmR=e\ɧVKΠ֧UuzI>uSTyb8*>&qRQGv2`+KTɤZLO4+Ou|*I,ȉ Y~(Z9Ả&>wl5'/ҲXx/˭Nk928 q#jlHOJMvlf+T(\|q[RO5`YFj5 mŔެѷh8eiMw*[QU\c jģ@ en:j0+3CC6zG%UoCeJ>\:Uk z9znBJ>.1+:X$^f?Vkjhzr\Cf!:jSݍ-#FOSOJ=Sʈ~G/Yrz0Mt/ԌEϙqE?^ϧiE)jl*Y:(AB ".s(}q;-&J]B#Oz,9Sg :D9zp޹1f"FND'az+WFNy' Ǵ='w.LO"E|5Y9'>8 `c^V'~u1j*<>@GSB͜$w`^p9 _8Ώ- p*830ׯ3+il:(?~P:|_|>2꿎8.2}vq_wEeCN4$#^ox&9oǻsC#qUitН]s\p]]a~ ,Odx/@pc&J'Kl<'2aN`,D>G0?s`E74w]GpQ\u$>nM&Ra*rR?ߐ;qX_$ļ~|[DKS<3y D_G~Ou1R} =?X:4)/*.?@F%Q1!@!^FwcO_,!;|P ^'U{*C&A~葉ۧ:gB/7m! BK5o=`ECG͌~#w?'Ο7AUrx,bW{v~,÷$- qHFxH"\OS ?AغuH5{/k܉{!| O} &?8T&DQI(-Z '_٣w#'-ߎrDH1J7a_~Pɂq;HK< ]*6t}""2s;Oچ#T#^s.4({y71]>ǜ>2f ߁Ơ}e/~bmE$`Ru O0".%ZwCc;$q`e.s:>X!Q;~Y >b8n~}ˁPߕņ ELr2xʸ\߭ͻ;Ȳ8Ca= I-ޑ\e~8zY zQWc}͡ߙa%}ObX Z>ܰm<~sO0 o廭 Ppfe\}n$pq{ՅŤᅽ/c5^1LyGRTIQ-Ƿ_O^5U "@?ͻRP#( -B7!¶?6^8RuCNg).a'uS"-bx>)]s|򰦰wSf V/x}2].z&zȌa  -brrC|>v8X2<3M~ bm5>U&!tf;U;zs>i;I$h ? zZ%Baߐf2{n/.f@ ᘓ0|#'5ހ7! }Gg!%"ЏyOuǿ.|i2a`}KJHvzAл-8:$N! XH_<О``ĬT%7P8w" *Zߧ؎ߑ?;< Chty0cN̽B/31`fm 3Ȟ7Y1p ?HSJaH s߰ yDHP ?*> gSP^2D3Hly+\]2b86!'B=+=X#K>0gqV F/ 2J} ~D}p,ř!p:]0Ho-Wvw Ï!Ҝ4;4F7:WDH?ƑVQ"} GXzV&x?FfKt~5sg B&l\8$D LHQا8wyw!X* ,o2f_L_ GG4pjAhd{ƏA>OnCJ,/=4XV>'"2|{X>tޯF䩙PXh0qҌq?]_|>_ f1_`'_yrb#g9/{}W5sI=:rc)YOSo?\9= N >;^I93~~̿hɑ5ώB㞨׋}ab"L^>"M<ӡg _׾ޯ% ;@7Xi!Iqp<˧.d4q  `>ix8gpxP{_+4+O(.u%8v: LcoL5r9,ُ9~?*49Di,=_=EY?JLj;pxYcœcPϠc4Uڲrdr^] g}b XpE)m]nECdޟ?W>>c;<?B- 6#q{_^tk}aYa-By'7C?{xX,_չAoyLFڧ`w~iiWOci&>pI@CGI,}:pC1'6H~ ;I?<O֗#ȷ=% "IF|S0yq"E 4ՠ ~|A)%S^-"~OzKHĿ;?L \:.~!\mr߇#lX=s2~}qa]>X%dIHz“D|YοC"SVWD̟%E4o29_r$n8Z{N}e?Ba^. m9}qcV&!vOï{r+ N컈S 0WbQ-$qľ90 X$?'<_my|dȀu!M8]Iz;wzWc!'ަ79{4Mfs#IR~`@@Yk:/;j5B?^ l'D㏓pEJ?_&7D*fNvLɢx#1уO#95pDS90"*z%3f!Þ&ޅ>2?w]|)Ra.+a` קf'O'ApӇϹ=O8=4TOϧar: #䰏C(I0c$~0&^HUץ>Կdԟ6A]˟6Lߖ[5̿[liyцok?Ko_l3)+OGM?-q3?"0v^h~?7hkf+l33dvO7Ӆ?IK(4+i^k_~?s6N?kiAgM-s?w]ܧP_绎my>_{> gl[mY}αmUn?Lc(~U;8Pk7M ÐcM `Q0F~0_aɚoa \MQIq/r73ĿG)J^> ;L-#_roL'_0Ei:M;L?p_D1Fdgߟ__޿'I{'I{R寙j;(R~-c/??JvgB=7 4e;o̶b?  6,¿T_DqU A0I|},_/+'>ߜPbzYߓܿ0YiϪ)TQ _2.(8PA`W'g˿9ݯ_k/?,~839 0<0~ǿ8!F$@kA5_`l !k~oiD%?Vh >//gd`Կ@:Q* ZBB ~A/p B gC>7FM##Cj/H"3F~F%;u(d !I4)37_ Faꗄ=~@`g|AI t e2+BI}/ &Bs q:9N~n?q_2'~^~VzGtg_O!C>5 ad0Sڒq_G9LL!Ɋ%?ٓPhs!J?|qjXB_~] kH4KT7JfSl$|Km%-5 !)Ldf};~4_kP4j$V~Phi$z%$~*S>'N(Si$ѡO"0_~vƾL4FY$e`]2^هHW&:x~~RPyAp&p)Lq|}g_oy'Nץ? J|pov/2?U'?%jeOI4R_~?7CNi5AS3)9?q'Miz>7owLf?g??~ _W2!Inp<_<$o}F)?'G~H$%fkOSr)yQIjIZLo45;|~93nDpNi~}(-U⶟JJw}.2˵1܂^ÑtGMU=P{߸ma3bR w̾Kw;զ WkVroո1ۨjH͚ U]=۞`fL{g;*6ji@픇P΃ku68k[. iYi`x ?+~PSeh_8fo"Nopd/r!r. a螺L[n0LSiN)ګ- 睲v'-<l}o<Ш[9f]w;J)\5+foL`sMKFmxs-0ê/bv3To9'4Fc$tiIί4a{1ݱCbY6=B\T=@^#M@<|cƈRb/Q0cÔ41l6,vS_}ƑJ~ʅp`p2jmpcM#2KbU=5̇k?;3HA;{Vr!6t8簛KͯufwN{']B\=x#nn*z@;#ܴs'KHUxS 6lh4ryE-l^C4AAW/Jʂ+卉' :rDŁEk h0}>%i7}0uV*=&rpnqdG֯f ]j"Ϭ~zҫ9%ڼmvү.gu O0Rr#on&D|Jq3ζi_7Dv,ޡ;]Pt[nL6ITy޲!+-UN 0x$8՞A.FVƍ%}Zki!u h>v%Yh7" FJXr~yXXL1B8."c]oJҋc|ZŨ-uO}(qfji?^Xro7CBE*?-vZxUr ["Bױ]GgIob_e|}6F%\#[[z5Hs5h(7_L«FeQDR&&ba)ZWydto9ZiL,Oڬ731'O:WycRSwH\;k7ƣ S2Zf8jV-Aގٙ+$y`p괱3ޙtlwCA_f^rCj7  E0s4|? \e/1ΩčmƸ7a$KZC=Axx3L4[fc9q@DLfj3TJ~{ҼP^j yَy2Bz`}V+%л7 Nt=PAE^t2N<EIx,/S&7=} KQIni僲^+l^O^gG1)g$W>ηF7Kglţ9dϝuGr#դ p'O]Es0KF6zTWi96}tʫaѪ0*å "N-x *^N&_rJUЫl؜6wnc#h*@|X.Fuz)=_-G(NRh{Uȭ1mj4gX.3ύռ^i xO ^]‚w߫TpI8 ԝlld-Ñ,[^Eu=ΪS]U5YhzSy0C >|y}iĻG`-׵ >< >eCV݂n[0"d}L>n>(_4QR?` :ta <~и:cX˹!j@k\t̰=__nt5νފ~>srv)NzUnN9q5 Q.j2ki΍ ASxG>ڦԯ+]'鰘زp?q;mK4uZD2Kl5db>_ ܧ& d^ڤ[yIoQ;j_+v)cBT|s vubrkAHnZdFJ'OEۍ`ҧw빃 Z[ \ХQe;1^RT=fOC*Qϥɍ?̿qz׊#V|e0U VԜj-}*=nK:yY#R]rn#R1ӆu XoqwJz RaZ ίs}'\WR3kwXz-zFvi5%~ȷjv/ՂCEb]noc $uvA>}W^UlE ]DTb3Oܪ Zò;c0T8s0rWڛ [Vkո6Y2^GB~QU2R,>4ga (57(!ܑv䈁mq秗`T\{+vf*5ݒ֒`lqWpQp=mӢmXѓp&OlԽ+atBwV*q7vfǕF;4j0 \o9t9y_'=3-0lX%ܟ YdFT4ZOk|Phĥ4S^ٮNNrE4/]&<=.[N*x̱h;l DO5395e>X3Z)η~yClyno َuJeU${TУgݪ[N+5 ܽ>xu.Xbktf8dOxũ?fw;ڬL<.Xh%O}aGBu 0z߯Oc4Lkke62`: $gխYD ~? dp^ݚmyAWiz=m/^Ru:]X!CcNn 4A?RB/m%3h "U.3<%JqJFO0ئѦKL Kܩ3v*f Q2K'o7^^z&൳Q-BdR9p'V‹ ՟,J-n\lXVBC[u6] n}ASIjhlLM#jv!c 6q=JED6H+'m8vH̪nz_Q`J3Vae2'V16_9Rab AP_LgC^xa" US[؋ kƈtƍ+^g!m4_W۱^FVP>ox2+=c;ϮօC6Xs͢``XW-1>)AHeAxN5~?C69 e?'9:<u:+Xo39|]?eϊ˥3Kd:#vZ=\Z<7]PDgumv$uOoHUYAi.0R,;=>7ST&8=R'X_6TunyK4Ĭtĕ0,P[yr۽79'~k7fAhONJF,i<3Hv̅Nd\\oIȨm5@Gr=>VPĀ}IB^+նVrgi(Z/87xTk. ɵ>,`

ժ$_#EeK@XRxf4)[=G:0K!sw3FEoNrJSM9 tA~s僿hƨos Bg+>["b.kZɺUy4|AB\'G"ڪb?n]a}מmW$z ;%3ҏG>p^UT$nl;;: q\h& ^D 3uU3Wt{ƽBv\~VPz!fTպrGFZ2_4E8qh=a(yqЫ#xϰ\5a4\Ea'AUҽVORh` "}*Lϗ6YmQ'e /<`f#a 3BlɄV?*-Ů~lbyhzK\|{l{2 5?CS[U^cn;G[ztG3k6/S 0^oO%sol] hׁ6n[cmTv;is]lТܽVE:*/,j\8D$2AMnf3Γzr qV-ٚôۻ͔TVSQ-+xm-"ۜĀ[]>YU_ jX]Lmûf T2Сr:z5#vJr9Eð"嫧&T-TM= L"02j< N,^O+zqb5ׄ5uY2e&Z/^\Ԁ.4d)IoE##r:qlEJkTK 7n3}}T+OYQp6h\~I&7c2d2ҪP1JYX|AŊ׾^*VLTZM+o@S`ŴidM3D|BFXl;W~`MgĪv" ꌬ㈚g}5^R(D2À0w[Nk+t򓪯n {RپD Uӛy}Ι|_^>%?I)zwʂq.Hmt32arZ3eڡG| tvhI$y{끞 KaFuT3{ ,E"ܳU蘞zpÙ 0_ & Wƭ":8<0+ &Wk#M'o;<~F *gs[Ɲ򄽁!s]HC >Q3h :qTLS^2بX =75Q :FJ":V//Kۛa|Jk[4,;hZ6p#g S@\f"wBYѨǎj KM.c&Qho#l^G~G* O֞oeYl-vv/7A @N{Zwf,.Nw$~ʘI4BG4Vҙiu[Xn0-ݾW*24י=UOԾ :n|\4Idha.:t pA3(P8m.b 3H_.{ecTOrIrtNy|uHvsgY::. pfTsrC6rAwU9mmzXe4b.[~Հ [(SMBŃU0B`y; Wfi̬; ";S6%miyqyDQF5g8~ArBm\y[!<6v,ծV!36 R랸ٚ&{Vך:.AK݊ծयj }ٳ] _AH/ҹE5g~\,ov4*E/UC>ڞ!F Tuo OӜTbdE-y;,-%0J:ڭV7ێkU)_?]m:'ä(+7^J/m*i~r!2fzKh8!sQ^!ubG#] O}=Fc8[=h9Ï Xl9,Ҳj:? e72FSqsbKl`J*JLGqv#EL_@Թ(ws5IEǍ{HF+ҐU*ʡ&Fg .pէl/j9ex])kR;A$F:r޶rcda-CHR;W,rfl5KxgFbyĒT3*Y<;2. )$GObx\Z>Ou/ mz5ޠ6pxfMX{Ե zp/]?@g:Ej _aKvE+Q\gg=Xl.3oYy4=ZٗҤ1Dg֩ !::E썅/ypL`Sxgc_M5ڽD/>gD4 T+ZFGRS}wi]B2a4lw$e>"ի6/ \;("MuPLMgT~Ϝٍh9G6کTc(} nZi_G.pOquaY'`P _j;+c).gŖkRޟu/$bK]1i~!d16Tuu͂X(ZR2*`:ow2F*Ƴ_^8}>DNjRjk? j0يyü6ֽ|v517j_`53j"pIcTEqNMcc[VƤ8PgO^\qilC [-ep&1wzyk܉(7P0<)ge`=5z]I-c% ޝJL7ʪSŨQ4wgtp;jsZκ 1S= ɶ2Qzz5w]vB1:~&fdIEU, Rj44S,Jw;2TYil76N{ "Y-ݝ/ 3t+U?<GYp셧Bf7@6ky.Remvr|'PO ],HkǙH=_ue5 %וֹׯ)ˉrJԼ~1H ?]rl6ˈAM*vwVy6.ՋuC4>ofGs!arl2Oe!Vll02 òzJ8݆;1&q}2]&r'/k"1f3,ud]f6L_fػa\C1!q:l7B icld{\lv50cc8D+Tc3EL9V{7m4&CϟٮUa餑+]e+`f|"R|ްfǓ2BȂ8̬M$H/js4 s3O[7ow?nϋɒUq^?i6;<\7[3XcԌq'>0ibpf4tcr80 C]U4襎*=!QUW dn=mgrZ87W9R+fw2K`zf{m o'Vb Ni^l;z/ R@j h2@_G4e1wNh]^Ä2{Vy^#Tl#mo6mx);w6dia3OuvpXh]یEZ|j&Rc@Fz|N Q5d^ T <L?s R:^յ)aMX'fR9[;/ti^n>]Mj1j #ᣅlkݬ<;o9 ˼PWޡ)ndSnU, uRer) 56f>Ho:a|nfy)8ܢvV ZVFQRJ P/TGq[z&ul퇎gWҠVm/6[puDw^+ޜ[b'd<ȧut JIԣ_B(:!췻HVlq3^έ~,&|qFK8cfB^+O$-JQ2RG`U ?{G8Vfﱌ ypz—zK3Ah `rmYToJ _Cjodᓠ.Z=꣥h܌E`wiG>Ot3]TK'kr!hHE;e"#o3-{Xnv^}Aք7#Ž*nM_(LKbAk,֔3^Cf\k LQW<4Vr Z ]t?eB ]LT ϹZ[4Ky9`}H@rm1ZFfȭ==_bwawr&i뤪} ªƸWX 8LxkLYI*ùQұ-?{=J#vp9EcV7܇]`rbFFA>APw8nUr0L[ΞjAi}U1!4I>=/afBqddGL;{~(`%ll^JUZdOiz. |~F|+9vw{s9nA(Ϝh#|yVo8,ĭ >Z`eJ7 mۮ 7;x $Fޓܫw1\oպ}&؋Y+ڿZ3N:iۈɽy5e_#Gܐ}ms>a5}K$SN?K~wkm0Ki`Qj#"p|ogZ+ /h<)[܉Ύ*1O _Ŋ*4謭gPh]u\ĒnuuY͂B+ͽ;Th͞-?³."_*P=4.OK.7\hq$YnxA=X 粓GjЈiJJ-<ݚ|7)u"!󻸽dVmVaWas:fDmEwDV^+eπti//W; r@о PK zXTMu ,Yr Z rqjJpјl~M/n[&q[cr6FɲSzJ*4wo>r՝WJA7yv ۩xV4}:\, 9NfV/$-۱ů~EggWM5e^`NaN`W.je2ʰ̺CQoKuM+wפ]F9Xo/޻R'7Dؼai[h8e&EB6 -N b95%lyZ)o鸻 z ap7DnFuK%SnALC N@?A];ݲFƚYyܜNPNo47لԱ3hjޡ"0p۬ӜhK%]DI|EMD1/ga^4cI;G.櫷R<݋::r ;w.eUgʭIՏȱw#!†,[@Ztqxcl䬦wY|ut;g-~"b$*d,Fa V5_qqqLό?Sڑs[L~OC *MSZUȈmToۥSYs0+J\l%`npUWK =M[yHb-c[Az`/ qi@/#oljm m3cҁnMg'I.l6~v)qxj^G2?-={r4Qic@V#SS2ƚ 7 U"uÛA;_ Ԃyɢ{D taҍT1#n&%{&HVNT-o]<\[JggٯbY鲘ٵXD)S=1^Fwa<^qݱjY^kַ{^(eݿJS' OCN+>׺:_ hKhѮĿpj¨6.eo?Slt\e pĴmO +#lTB[MKT7 l|:^y&YFb_Bե:5Ͷݦ5'?˪SW.2+)p뜩Z} `ߋeWJY[!ֺrmHAbxSh +׭2rJ7Ϗϭ_/ŶqwP/:Wz^},e DMrbO*h~wŠX²=JUlo[p8k;@`Yx,Q.;Ip{v%PMyEҬ¥$]/FF_N+!KB34/|^P thU7< 7eSum;u` JdbYEU {~SBb~c1G8bUyU/Q.3#RG|+8o&F04/Fb N.4t n4 Z m#<0b0ZlAhU1^|sIE|ToSnɤRy-'v 3/&dlkQʃ[TJ27O^LxK}Hgh,^ VqPf@{ ;ǔbb϶X}m<綰je86QrfTf\ݘކ%tة77 2l u\B了'ϘOذIK7E ;S4)lO+݅\,lω L: ݽu&qx& QKC'ϮNxoY"˷Zq|^LjrXcp)Q#<;qߘE=ut^ ꄣ6#}%ӨCα3 Lĥg<:XG#=U0Tuya"Ft`ς}NgZ#r{E<Gd5Îx[[GZX_6sfh :o9n[5 PHT% ksbaQ[&<ˎQ\q=\Z;,ũidrˬ/5Oo;Qp+_D&|(M'9;yܖ^)7C$=Y VvWys;mkfPT[W?ҟQҠ7XnC7գuٍ|`[jyrGsRbȳo5&?Kv֜dPV.SG:ho>3ay#/2])/cawZ9찆KA,b/]H^v8z,ӕh龫F.U8͍ere/.Bc7!WQTĝنh`C*դ"R;D6c )6 қ"Nva48hae i8- _^g>NX*ەÄ́+ឫgSfTb-%QOh~J]@"?WǷ>)֐en 3½g;$-Qgz])yYnnZw6\X ^kS/%YK/>?lpTҧ5e]Aag_ê,YKc]IuRpߚ}؂]읆̝{brG6uqĪ )%=&oU awӰ;XCҫ/ѽUIzWz;h1=l(:^nT?%ٞvқⱅ;7M(-ȾC8DլߕaW5g3drYI,6-QcOZ[Af]5̹Q!7, M:J5. Z6֭J!-@ugDHk_;B!zB4,d~[Pfu.g4^=Tkmt$ƥ5C1;q(e >&Ț|f;㾗#5y\e^r4eyu" ME;,;a^3xQ WW;wjɆw4NQ}_$t|J|UjcZ _N1@x𮗙96.}UРĽ#>DPOo-DOݼmSkLQƳ_n-wxl+V]\J- N׹S.xAQ~ݽTaiLBH%Z|jE-&$nï`.:1easDABx5NYQgH}k֫{gWާ;J֝՛Kͻ mGdѪ/%Z ȫgPXFn\Yf =Ɛ㏗qgNүku6/kĐ^7 e_!9E kwں{)>x>շpr66GZ>"y&V`3ʈ#Lk~0G w7nƥk WQN*t#N$>qsW#虋V°b~*:u^l Z픀t+t->̠vzQ6,\PC1%zNt&g?X'=`ZKWc28]hSOvA`3xnrX:_1$FUWAo9R5Ën<aLW[C&I>$]Z`8}]nݻzy^}w֩ [8,3n۹[G[™.B8.tܑjOw޽Jo.;.q5D8ϯ23JN7~ݿzn=,E9D8+"hS~!;/C!mo9vƑ'ug:GJկyHz("IWR]L+UA CrztˈVKtŕ7_ky7۶?PB?n1m B`Z]DqF|vћS%/7KCgϖh F邯"~%|._ ǹz6$ Kf,B2'D } =j$ ^EN:z h:xò!{5 '_>"$ zFuK8%)3-y*&L 5i2t>\3'-ySX[[mܾ :^ aɹ4ѯ[QW՟wG˾&ЭmizDR~lVG9 9Øj|x`Xdڧ.PcJܬkw qy-;WwO뺋.NU){2~z fZ_y 2.tIJ>˸*pQVʫ.00ҮFVc>c$*~}?(g2o.\n\8z ,-جm4>j*s_2XEVWZ:ZLO_F*xR߶q$CFV$U@}kDwˬ<_7{.a*0:౏)\W3b캕Yf?x%G8{=Z҉q7cVôh\U{ЙҨ:-ҳqjk ~=(1(n2fcq)Cc uV.A[IY^|\UGŴIK!9=Y&}Jes]-}]쯾Bx#6|ώy!-0t&Q)[-jĽSR+v?ӻ5@KA`=nA*0> qu<;k멽gKÙRQ>3_׹ۺZd~"9t}VIVg~sWQoKT_+?\{b_OY$G#;jzxN'~%y)|y+ 5;1MggU:.b$"Afơ*hZKt1tTאMםN؟Ƣ/QL,xRO34r>^Mp/tbs7:_!ޟDZWqO5˓ҨZv//([/#5=. ys=_5gq2kG}!]#wf^/84qDOypґ7V03 {MgN/Om9~mf(l ڵy%<9*n,t1z_#..W;`4;ؽp41&̞OG^ȮWN $A~0qHl1.YF[NYd{ͭb2V|#+yKJ}{br~&B28%EU6td=)o 3鬩'=JJQ3DU1F{Hmcq+mzdXr0Qӎr_-0Fɶxަ(ƍw5,|ǛSɹ\(%B!w1OF |<4vW^]fyiyԢ=ߗ".Zo:e<'E/Ȯ3=~HQ7Yedܿ+q̕|Wװ0jD'atXRh;?=n0F'FtGxJ|OE W |S :1(jj ҍ7ݰ1XUDwVHApJ3UCa+Ji򺉜&3.;=(«MK֫NaԭnO)D"9<=?iDx FgƳG&.qhNY{Z]`ӮE"AŸ`OĊ=o}oa<jzV*=R{U7< ?RnD1o_|b575ȟF۠#-}e/*4N-oR#w5WTek{`˗sQi6X7!>j%xz烹_~M1CZo巧y &ѻ3)qK"mO6X{)cغݔnƲba @NADY9έso/;>+}/]*5inh3c f'G:n#渼vz O>p5Kp7k-ċ!rOaEr|۸[W1ޙUYWue^+Ga^ԲkQqkN$4Q g5Ӆ@ZȒٰU/~l 7 a[ZVJUR ʙY'pcQ ~oEԟ<15bum0`2C}6&}~ޕrvm`ٗ]z~ݍp|R6nOg [Vlnf۔jn֚]S6U.8ī,cCe7Sܶu ̐qvw0_݁٨|I$ H,Պ :>WI[\Y Ѩ.](VڙC\w|/ng.?z }*y{^ҵ- Q}yϿ$<@#ASH4TTgTAXt,w\A.FY ;W2HҸL`\(6 nCPi~ 'OT7)ȡ*Cp1ME^? @SR me85Eِt{f1'aȊ.wXҏEuH? Rˆr+ :\0:VQ`}\[D CKNaתDF6yGm0bcnBԘ}_9 a.bFN_o Նxol*M~L>$!Ɠ# 4?Р~j3}4ȡfY?}٩ e>& 6ë~G9I#+BRO?fi|+JWN:#E뒃ϝ~/+_D/ '.σm)]혷˪y]0]Bq~TB,=߂Ƥćz Xㅡ8"<[v.#Vƕl$RnzN5)5MBloHyU/ԁ1Ӫ@9y)/QmՙIiZ6.VfCdrspc䅗SJwnھ~$U3pE -#n\M|4$[[ZvG桀_4/x8um1k7"ŹOä΋?*+%WgwOdkM>N{5ڃ F WUgBl()7nl+aCu1v B!xsIms᰿FZ-C[ L0% eH?o{%[ 9cĭa|VjCݾ ̾pgs?SmVR[0z |z͟w)zJ+[ p1Y}X:JzyC#x(`Uxݫ,O\Mg ,o3Z|tkw|вxLm ,)]M6^[L!Ꮚ#WlSJM.05FEz llZܦ`8s7îឲBxnt=&]/]`ȲUykp"0t?7tIPY[q Ќ~3\..je`;*#taP)Ӵ#E^8Vf >Z{v+>O0|Ta9, >$n' CԻ^m!ˇ6ay;j*׎?\\9c3&omYoWS?.ᘉUsS>&D]an{}^G7U`kj ξEcU,R=tºAly(UM3)a$kb}cl^g+Xف ]|{xÿ(Zy%D6kj qD]γ\wDk7vBѣRW_Mc̕kME~mNN"-H)zz[E+ GdD%-eA,^KbuQC+l\:dc21Ӡ~-$S曋KFW ko.ey-:6%XO@)?ۈ-EUux pT[6EfͬEPa{||-_h`崯9_[XVCѷ(ϻ뒩7l`>-Q7Ced8t³zH/7Ć<_:(. dkq>}R;ƣr6Te67]aVs3d0Ei@0@ujF+Xr:u. < fWWN}) ÿ3Ko~oڞ䱢4T|Eh{u]Q̍D6|H+3,ZӞR8 +e ς}ua:1\j1fEloѓ0ۍw% QS{Ҏ0;Ȯ5*U5 Kv`1'g Nin7$Zr / ԩ^jVOk++5[/_wm=yLx5q0W@iA]1Dɻ{8tpYH73\ {܍MVsPJQmm_>g?j9B's/V$ѰȟX"঱L}~wj.ipVn=|fkEObyh{q Z?L ǭW(:}Q KzYL: 薍<%WRv8D9q&TW'C">\[kug|/rrT7ްcWcno sAXR7a]|ꍬ5N;Q>OuvGNv}6y+hv9ꪗ[{i`j@{30DЉkf>lFVWuvaWY?Om#d,[Ymïx]|zYm ώ4Qp#ˑW Υߋxjo?ۓIhb"}cݻs6XzN (|7U=~IG |ho2tO#ןk+y@f}fGkMoֺĥ -D`3XdA_Z4tIwȗkirrR}pr j)s) _bSq~p C~=ܝn򍨽,z _oyf\ >P_t>С7ld0PI¯7V##u榰'Ⱥ8Sd.C| x9Ž jŭ1]EjԻcΔz'9F~AwvVXHd{Њ"-ߵhb@CH6k-tz>z%-M= 3o ڏz1^G-{J7li15>]ByMpeqU4I'.e[nl0:w"z;!oR>G79+^XBWKt6GԶ׺nn3ANꫤAsi%ny A4]󠶨{~KY'N*ض2Xo$'_Dg/aqWgsIC棣׵ّ;V@pbܬ^US>M? ũ/i2/%ӋhВ? {T\Yۨ -dCG63PvR/\w. ea%)Tf?k#aU;3 ܢBXSp:oYl;ږA8!ܪ-:MPYk(#6bFxޯ9BSȡʜvRf5Q*~X]Ko']|Do~ o鼃҇М6NŽO@> ٫?iu2 GɸXԺFdAO]7cv*d =,;&\}M44*f JEca.:4$7tĀ7=[#>aS` Uiv4^ WΣMY z ߳_*,UqUYZnns<-?xFqF# D8{h!Iu.{6W1m:%)kIIKh#ZVYB`Yˣ2;b(NN]t)v{2ܳXp&Ģk~NimgP976q\ԬR(`iT-@nPt~n2_k 8Y}Os7ć[vי#W=ܝ-p(Lnhe(m눓ƍ 9`/kxkv^dW qL|e!˻_GFk[čнH _ո=>sT"< $3i/a+̟b3ZSR۪ Fl@l-Lc¨5m幻sln,%2 |VO'vdW8v^0 d!a3-ީC;ӝdZ_Dk5Dף m/G<{9gTM?c3HO/:yn )?Csޥx䳱r'T {ƂY_˝\v]JU/yL.A ;p'};9x %ٳw,|hWh֭c8w:W7A iaCj%XXiq'oɣY(1B~aE]lB^Q ekhg輜 v*m ǪEN o vձ n_]+*un.@z0,S0/a5PZ:scM8b `;:?I?CoFϰA@pkkt3=]״e=p`<:h3TUKia ~7d/rqo|r}f_xZLw%~DH+]$蟘k֦BLJUD}]t>`3Y1vqy<9Ml%@;7[=8^Xֿ"qKVth0݂[!۵=$p̏/ԓZ*ct&*AF*$Ϟ}y$-Z=pK؃;ܱFkG@}ׅ]}g_fzlO S1Ny$'Sނ>ى[F?:D 6 >W}<&NS%cPJhoTW}?Sن )n~ 6U#q' 5S?0e^=Qa~S}RHe2> m;zI%x4!|_eguS|'Ttv^}FRySPœp\MSR3zr&QMB ] QuY"_}4:p{qeĹ@R(jC;8bhF?f<,UƟ_Wny ƥ wp6C`j2W8d~AZU@E%}l+=~lwCW]skd"fxo OC<%JT֠LJDY'fo[̤TKpaNwf4f"qE^M_{9jzZi֐͆ZsXd9nX΀9\ j1=*?i`-X;>BY_/ܢڀA6%xb5\M?p}z~*1hP)*[p~|mzvǵ5&B>~%y |-'.E=_ͽbfohhz^@w`2I:kg7*5|/X"YwM˭"+6n't݆{kk=UtyC6nUk=C~gKg+Mw9CBS{i`"gYnpEE /^ ZUyON:ː/5ѥQd\_%y#ĚsAyrP)%D\3l8 ϵRpDaphV/Eq޲Levc^u**ј Ev?tl0؋Wvfćôuy=_zn 5Gy.Ikp쯫n8;ڵ>0MQ[-E}?;`AJSEky"wQ:P4?a֢2p663aYm,5RPTO/&i2'OegStZƮlr EHK#̧VhadvD?+.t]]ڀכunL}ߛ6'$  FJ3xb˥z'#3dJy`.@^)M8yq<ǖ"-A~RbucoG걹.Va4R.Ϛgљ-ĈI \i.`Lc+)w?us-f=v[hzq93jyZ˜P,f[9L՞E~ X'{qN}iLDnr&N̾۰_Z ̣Mj@upEGankh QcwϏc:qw&g!H2dI:nJ22-\;=dc!`|۲A}fqjk6+9i"=ltk"9 t_;"PawLJ2!#35*Ϲ[>졎"ׇK6Fa r[\SQ8r+"0r^ JS<@+ghmnUGtٖ7,aʍXϤ O՗p1 Z*KīWK#Qd?_ OXl>qGMO^pp(~T2fM~~yqׅ`L.M~:N C;RWN}|)27̏8C}#{ԢPWMzZX;-)) ϑY2L)p.*16~E}=rw8q<:9 R]dx f4j-–9ھOi>Zk±.h$Gm-?쭱j O0ǥuNQ mZG jOEekkvGx7u.2{XdPxZU{Q-B( HrDo̶;ӻyE}d'jZd'p[[ɆѼ*Ho?&Gjީ*U,H5p-@}BlPsa=Qw;(NyT͞ɒoU]Oj vGMPMXV[0W=㾽6c쀪oOɷGysn?n퓖 'N-bk}1ZyQγxJ2l׃ꅸѪK{ Ϩ\n{=Y9`h#`&N5-Ƙ5A?H[3zuu=п=@5ʣpLfqvĭ39%8LW?m#=UACzs2tvZn>4ݏW/t&ug%Ơ <\-\u*^'ˆfcZqC8,Ϸ3:/IcK50;{Y=4[_ZGvQeݙXEvAiiYfsA|s]S>~-춍Vl?.OSbs.GuSmZppis/|~<@yػ-|}S÷ a9[Md.#q[o3Td+/J f UgH?1z~ϑ :oLm, 0PqWvlV'i其BH0Pp!$ݚ>ML17og'}#w?)Y4co?~l7e'P0)IG&kvAwXQV͚ͨm^myl%f!)E|T70„M4T7^^*E(o3ƨ VnY x٣s ހGA\^_~1~Bsyibsp:+S§2ׄ{s1_? "P,|ʝ51dlRuYѾOXdu`MنL洔]joc@84g~]}zSӴrp.KXi|Z[^yYœp&̈́xI]|urX}H8Γc'4[X-P l{Qԓn:7p*_9_LmjJu]-ƾKv9X/&n<;e3p/ǜ+&')[xcyRm X:~)kOWs/\N3ޔ)W05Vg=/F >ڼ:i4%x*ïiot2tJ28\CRv;-w0_ϟ06n}jkS촾 !;yӞjsz\8xba;ao ?(gϴ}6ײv/au&I+*cɥ`G{<~jFI0*-4{S?{=LiĻ\ ?*coZK+Nx~Tkۚ٫omyS;gr# AaY.AG!wq]St vڴ !n _Po bi #O+ٌB)]oo*-*0Z=*͚UN5+Gy.sFŜxrDJ˳HåPZzh`OQUR=mW\e6L3t=z9* y&yJ0-.b1=QwUMQ?g,y(ˑ҅eh[[ث4 yV=Lv v&F󼅌9VM!'=X5t-?\6HT/Ϙecyp6-Dt(-Ke{73 q`"JwUAfe gtņR3 {R5kǙMJI9U wkjhA[sE[Sش-ulqVtvq%?J93ܧje`U#\=^ojo"N"0\(7DC'c7<Vq~2FބQߓ:(Jze::>M+]+VeGC7:LS}Wk͙qMʩ0 PY6tRY'R ϫ7N+ʸw]1l؏;V< v-7\{&}v #(a~YPs 2>9҆_{)2*,\YU?XAAzbnIe%a۞?)`T;j[pN.4G%) hſ޿잚|V\݆)ָ /:;7v̯_X6c7+uM}"hB_ -!pXz7'ۡR ;8t5EXL >&n>406rCjzޯ'YxVEa#V7h)vmy/A88j%#"jELVӼ U|_< /_OnLN.[d}vr VSp E;6Y";`iQ(3J+)^s샟k鲬5U3:幵ji=Y?res >I½S/VA KkmMyedΧƒoώ NMMr>^ bS&( eA]*}`VY^Wd?Λds oM%$yÚ } 0$ 1fҋc~@C(Pa_N;xֽ=Z5KEO{Xn--t={Ηܟ5xL #sxtY44SG//+/:ou~yw[(FY|Cр5S^A͍FF$m?ۺNZ,7mzchpJ;.uNq/qIga\\)̉CBNI#ҫ/k|(jM`a 4k7}ջ_{ s*f[_|`{ݬ߱Qe/̜:W⾷`+edj;Oڏڟ/oTT$"AFd,/_˪vk1?Oj-l};oےiOwyXh[4'C!O;Lz<_iY*|#5KHwNj>X38]$G-Xb < x9d *J|i=y?8b8jm;,0Ke4w%ʳsnBвb=P Tߺ%WϦ~IC:q>I|o5q'kTguk[[b7:;)= ;Tu{M\<~Vւ:`#9(%Orݣ`J{ƒAvbmLv/rw:FDM}0UQS|sWp9֨/ݛ*Q{1i=eE?xʌ̞)rO=5ʹ~ w=$.oÐm[WV/\kttŽ C\`Yqhb4Z1ܟ2◞˶3شs=RO;~z~e|=|mسA|h],]nz(ԪM{_uך=׳#|F&`Ft}e>-x3S ܪZ 9-9gel,(ū>فŮڢ{`Ca~g{ogíd({թt-~P_ZˋT, 4 ċ>?<nJ/Mُb{6F:3%9/uV?ѻpt")?X*Xj!;` ;A&)INEG?k2fptD_g-h\Yt]81\z5akJ^QY}_c%Y FN2h<-{|dkc1P%hC'ϰv{'6dh!{a)E;Ewu1˭O !h*Y02Us ~}[޽5yv<Bȝ狹إ{oo{:,%M6~ -ښo#cj~H;@ծи!HJW1;73q\/8@m5~\IRIv+ݘ0azN>(يMKs,+y_8CiXlC&/{N>Sl~ 6j&9rUۡ -҄s(O@?|/ZX>D.??Tn!a$<>_w𮕢ms?.=oЍ抱,mg>GMd3%mCm/f M'ѹ>TVn'THB™Pwf;DoYbv`{ ?۸5 }/lCweX&W]c{Y\Ձ& xxdr:*ާ}C EUPqPL!_DnC#a@۲J* Ok"g:xEg;X'<8-|EVI~%x25TuNv`!Vw& Zd]fx}ORe;fug6[*TZ6nɛX\##w2i+%\l7Ҡb(gK6PV!}ׅBCu8$gTnW_n4`vU/ +w}҄71z~Mּ)5|'80U OQ2}d?O7_3&ب`_5qW],ZERj _ 'v.5ØS1d7OpԚ%=c6q-֭ _xU>%Ϋml"I?ŀ}r@1Ⱦ6 j([@<ཚGgȈc*q_iQ/861=Y[h>kD>Hq)O~,%%>W|ڈqqMipKFjYmg'^!ޥitYvOVK\׵# GϵT rJm|Io@ݗ\0wj6V"A?xVcE]wkʪM'=ӤtnlyMrZ"*4"ߧ?qEo`0sPQkê,fG~¤׿H5{w(X;s}r?>&a_ Ou\ t ٠m<i EUv򩀟"ߓq=:|/0#2')G j%~=?vn {M*Y>yx!LƳ c 2^9mTOp8 `hOhc^AJ^Rdήy%OkWD<,hykyxq`EC'`.7ڌƤ ƹ(O q 3F?HR-]qDi3H7D#N.3gҥ~,oo0G>{['I'`+mvFD7|MHNq`'/ZŊyoIwc]` \xj^C ʛd{ O|Ιl9wS1bD@ZqJytD@ٷ:pI Mo? -qԎ?GJh ˜{[N-kKp23o㮯,{8W ERf>:[̇c{\c0aA3g nؾ 3˩[׹kD`Ald@V]v xlfޫ^TnJ봳3Mrg;"OyyA8;/OMvD(q'.:&1OWۚ7}ߗqYo"F OaZEI|?<{WҦF=2mc\kd7?Ui+ݿE/d/,鄼h`c0DrLPH?g1JS<ݪ 'Zx{[J-o=ϧkWEM 8xm'&!}k+Q}];3EaE f8'i0Vma97V#F:g)l5:fEU.wUw5?#8v WXtA3$K5Mu{L/>GFA˳5Q8|t {K2fg0-όKn {E4?/UO' ecQ.OWc5) WcIb M([|WF=wVBvK_~?gk||ِ\)TM/׎vƟBM~+hS`i|3"_>zژ ~M{/ZDCfmpx{*j گrh#3- h0qwr{;,3}Q@~}aSw-W_|LN. }=Pju+/']Yn5o~/y68HP[(_es q݃,%>[ [6;-0>x0LӅھ߅4=AM[`9|M jicG&IUEь*f20m`*Uo2(K+NW6ޭճZytNKDx ecZVp%p*TRB5 {2B={=ħS7CUġ\Mu@Q8yMa؄9l{;Dƿ)_æpaqxUkXٝ}gFzǽXaGk ޷[q`xcgptQt<4kojk.oKbrYcv"]9XuiʏE)*ЉR63x",g$pZoIgۻ>/9(ҚvYgڲ$zګZ 8*Cl:wrLM6 _ξ>MYPu;.PZv{L0*芷MKζ҂aSkRc-N.'= w`јwγ3L]ܩ哺>7*o.z )}oruQ2Ety̠żh[:>-\y_.z`-( fa'#Gv/44l@^i5.z.{[G*D>Bu8`>;"yHq!TWF4Q3{MAww:%,3U؞E,~=QZaG3OFtE[+or)d4*V Ub">@kIc~ŏ0@C13Qޤr1c7*Z/Bl\֦[QY<[V?(0g`$ouc_ߦ2tSJv੓2P $"vrZx;t2[}|}.nuSLqSkjf@9 -FhPzp@SMc5QS`ntap }.~WJ:eިIuvO}sB4O tHٴpZJe;5I'Jǎ Újzg>R:?- ~b>ޯ Kd ><õ ECߘn{"Z8k0anRw=4uU {zyNssAWb^j%>3ܩylc %P!dOi{j'6I,qsJtꀉS}e;kM$޼Q (U>0M1yX'>X6J>Sy$GLf 5{p0ҳd~uGnS=GBQ.R/+6lNKW/C;h#Ftz@1!r0w!m1ƜUVMZѽpf>Ar-)p(RNE݇$#G$dvsS>EJV ]hE[ty| .Kǂ螐Pb| 'H=|\yϝ[5\J_D9, $޾OCL]m6p{i=uVjF͕ ړ$w\&6!L[cҫ$ hvf0?0k{DCծ].l G}_ mc}wٲyl#A긺:!Q?w|zP?kAKd*̀`>DZt5V0A GCn1F, KVSY%Aaz8lA0k^>6t|3zZG V~it:/ T?;߳ v^2(Uml;lGd.wYI^oEeJWQ= SUڼ=ں|Z<ln)!9p z27ZΐF"gnټX7)Ncχ3YF;[vo NHcRXn%y&!#9v*0/{7}"8{,'{R[f-~[G z*V<9ye[ʬ4/5*s"RQMƯpy}x:i'B"jP:3C-?q^E-id]Cm' d9z(Mi47N ѣC69RAsiOEڽ-O$y?~^Uo"+F*O=x!6|G]"(;j,Ow Ȇ3 [^lNbu=e}pNꞣ}xqx}F%ikF$}9Ab7:@KniB#yBXi{tGt/b.L(}DYpGsMr]~ů2Ʒ`,=r۰MV{3~)u~_`̉G5" XAE'mdZ7{f#CW¯t'OozSO3ܓ'; h Bt&\{8h"xpwڬji01*yݯk("Y rzUomo/&=)ќLY>B1]蛺  >U5֯+å8 1Nb-`]R321D~hɆ ;357Vt(6<ڳ\9,}hEV䛕{3 {jnщOβ68{ ṇ k&4%cԙ #J2TOy/S|~Iq4w~aM}^#JEds1x.+}!N躣;MjyfrSeȷ6.ME!o5?n=42Jk `;oe7=; l3?,J,2JQQNp2梲Js}^59' lJXN0ZȗT 8# |.ϱ>2qŏ쿨.ټ}s [Z)qu:%(_θ>i~,#bzY_}_ֲk?s "y6s?JqoZM6*(g5NxK[mH̯TΏ(>+ zwb I&gYs 6էSKμEy^'-Q]m'o6kL~:a`@v Gse,s5J?;J] r䏾:?`Va aiW~J~ڹm,lSo#eF㓲Ij_E ZY*h޻_ʃ\hV\ņS/OekTJ`-k+%&A4ԛE8"?N1q OHǣWgo:[8UTW|?u@x'Z~m:U܏R6+k/"'K43 ApLzߚ sFF_I.z"F5kp/=l6mʷ{+Y6"!d2bWf8}%iei!Ѐf?0_Źxj2Sʜ q%ř56Y5<rKT: 7v_\s.{٬7OBGŵrjo.k꽗ٯ{kꛆdOnH@rD|] |Լfz!.?Ƶcj(Ց;{dg%`m>,R\9r ֦5'_fؼ?Uǩ)ep)gwӻU/W_^ۛfxYa؞>BͩAv8lz nA88iq]wWldN4õ\' $}P巌Hᇵ`S<1J-?Vk\} @65 z@1+ҭ7(YΨ5IlW~np n4[/G@USyer{*f͔~|:ioK$oe'?֍@t~6ph<*|ׇ*6]nMl]Fb6a!/e}}UΩgk-*u~*B ?S-} Gk}!1/U㜨2_Yx[o[p NnKW4"mx 35^5Uc2 kݰ=@IKr[E;A[r9[fפ]X|w zv(_s0z _o;29_Zmv:zȀ5 ]W#0ńɞtDr\)pRe2*#Hľu vvg8"c>/azoSx֋ŵCj W!պD_^mɹk꿺|-~;rFU(:V=ysD'VOac oY3dcY7^S$?*~]9Rk\d= 1 w+BH7.Qo?.2ݲuV ѳÀguF>t> }O4@pkw+eCfw?fֿ~Mힷp'|^w V~! 4YnGNY/P'J_ظ\^p~?,|,6QMf ܀Gpf%ؼoue(޽XFsnqpt_7bTeJ-|z%:Q#ˌu.{mcćdXZ'%:Uw 8ډ)ykMPtueH~{ X5֋O^n' W*_ [z;ݥ_ʇEr9]&MKofYL7;} k&xQ;̐oct؞9g[wU/A ?#$Ipsϟ<7Y$_hٞ%Ju_)$=~؁ WrɎO#Xs<gn3|Z;4y_>ےQSV?5%YE9:+E=`ٴP ~hFzm$ەX>ϝr}Y`~:TlW3mֶ[7@&}N jfYU=+]< ˺w-m3WlMުMO tQAP]T)v˟*X("gm3*(,6M2֔Û2=)y`%n}3͆w )Yk5GQл[]Y#{ۚgIpR1y 묞W;ۻM?ݠj ~MuRy XG^"ԋ$ˈ[qOXlBA,W)4ӟ)Af\ўKGO ~Hi_/\=Oi~>gOM')UyXE6bB8n:?> *0"7ϧ`)~UY_Nέ4`k)z$1U@PkrPLoPs)+)fn>٣4wOC]yUp2&ơ;67#~wϤ2Һ,@)J>ɺvό`R J6~܉~ 9&a%P5 lw: B(m?f]3fZ=;{0Spؑ }NĮ._жd@=(o2P~:kx 9S3ZNj9MI{|WưJ+z$.L˃A]H/ڤnT%^%U\/F=A9^rX]^&s\\K ,ԅ(-ˇQԵeFpkc7h3(3͗ BӉ7Z^pcX \>?PX"@vjW5oYuՖěE i &vNfqͥ'u~祿UNţЌ(NVyHKp.K턡uȪpOPT\}V{7kwNt[|vK)rRVkxncGLM R ‡Wrޗ{ @(4.m}}]~ߦ+ih=/_'aoӠ?Y"mkW U> " ulxbKVsrYkd[L2NL7[ ?< p5-yPKޝx@ |Sy|2O ܔTE2{"ZŲ5$=!zYӔ*; I-UI/5,V+{.埰-oYӼ5dEI^KO/ ooۏL$Q_ F~ (6ÇjR7ظN?ܨD iU!ƨ.4nB{n"mkc0Tם$d #:tG86/[?&ދvqgT]`ZEnw]$cyǨUl)oojFrG@ Qeu6ҫuAx3𞝎%E>gͩB};Wj2˕"+l>}`ַA@{vIXk_kVޓ?|y4G/! `ͅ}. 7#(g:cMn ƃjSG5xrAjG->:@C3d}l6'%N=v]K$jz0ҚJ3g˛M ?ѠyݒآGhge??[f'~^Y[&zTxʥj#{j}]UHlJWki^8g6_#dnuݹ^_=ԻIn W׶lc(sRsK._RQ/C>pb;>պ۠ y-Y@Ճkdㄮ<_d(mOtQ?*wpxL.Fc{:\ߙ`u:SCh>)q~mi e|y b;kUh}ůCrtAe_߄`\6jl/- -OU-b[xmū-NChM?a5`:ѱTg*&n;,I G.,qZWzeaY5$;]]xl~cznI)26^y(՚ Zwv|wʿ2:h߃WzHh/҇@lXpl?6N4~fCrQH |Rv0/8+}3؃y 03ٝv~6M.% .M^>Hsfp2+OqBzK|Qp;RX&PO 32wT-/_;‹|ᷓñpR]˧ kGkqq6g]n>c{tZBǙ5{\? wwg,;ZʽKKy_Z~pt:]i8XmuG}щ1m(lc>^'u]mkm+Z j=R*N/+诤1Q髿_Ηf5١_ga]h,VE:bnJmsANLTj桫c7wdimH괤(=/s~OzK>EMmR/n9$@-xhtް±*|9IT2TP&HKp*u;|t ʯ|0o~= Li[zigk9GE\J{5Qi&}|k6ע1ơZj@3iֆJQ@>3b]̈{ oY7pR_,C_Φ}URՓ2 /(Sp<hX TܴG}^PlI}:M ~QXAJF|̀5]7 /%{6/)ajaX7pn@> fhUCCN=.nܒ\{0 =GĒcLs{_dsY;Wf0ETS|Qxᠱ1dv&oeVZS(?CҢ/ͫOtxfA Ki nVnl=y3iphJ`fڥm9ڢŸaXRqH ޻)jutp`*JEȠ\涮]\`ܝWWnr\>ѧb[T GN\ncym :eh}oZx+C+s&:WQ䟆+-\=%|d̴)NI;L&c69fQ-l3C;NI9Uxv>,!M=^a|<)3s{3?r9!8* 3].ۻ77ij۠%nLtt V_s,^Tpٝgm84׃wjQ#-e=d\oR6EX۩`w>jvtH2*er,wzƻ0;1wMĪrs/~qB03}awn8ݸ3<PφUi!ɑ$2S#LkUM]&vr@IY$ab*E""]rM2Ey;Y}oe1?pש[a4ek8.mexk.l44w^*,_.װ+ӔHo"}r"OUo­$ae1u0tl}Wk}I,p_J$Fa  7?&kZQVيCo NH|8~~ ?bQ@w+t=hji 5|Pud1>^3)펮Caz|4m%xn iQ౰)F̢:ΒFA:3I.;[:.\;.<6<$Ii||0{#\/J7kVaKf~vRIM6]+iɪ L+wDngǛwTߌ~2ގWaɒz CWu4e⋟uO q0$b],ba[bxgKD/LǞ|n/ @63-ꅡx+\%\{٢׵^J8EyvutSt8i xKY#yzye7~@ =o&Mx\l<{WyaۧK|Z t2#Zk^f%4R5SUYv |wDgPlؗH+ґ#:0nݥ`px|&.j}*}="d@ SWȂ>eC?0kS㵛~߭ɔrh C2L@6rdvdz/J.S;:Z]w%noaȿT:vJCU`j}_kEyL6[UVT;L~:):Ҩ]3?GZuHZ F2KĨET`u2V:X)ݾԒmou(EMy8smH{6O -CG&ڔ/h-{e|y p5A5_"w+rO׃ITjVB0L6=NOR8~5Z5W ?|^Ns8 GFߎZCx_K34͢|wn˴k@2^Do}w] ̩!-֦owb=̘v̡3agL?:̏'C\ȓ5g <|5{!h *q.8sGbj&{B'G?a""u|欣{*u1Fx?_V2V[}ngi7N>F=6Cn}fjܮ|/!w. Vm"K!gSd]'g*>V:Qҥ ^R_{oFh}`׍_ίR]͊쑏@rIA',1ѻLRI0Uf,EnRo+?MdW7ZBdTܟ^ߜgCR1׭}>PHifwh X>Oϭ/T#دQl2x^m_CojT}uzaPmkȗ?]r+C oMՃCd,I^O+#hMp@Zb>^\Msbo&,7P-=ng|j!79=EstP.WJk_}2Ux]nݔqݎ)8n xVy<vmAoW~`آvm 5_CHozM :>ܫ:9ݯA`@w w \%3ܡ8W-6(PWwjBJv'PKvpWzKj'ޗUHqI#.NJy /ty @J(uAL)KqG; 0}D- #sZ27޷)$g_P[v ̈́3X}2uj~\q]7JwfsM\{ԱEmSm8g;Qv8%(kG+.1 jop,Ko iGF7~~-Lsw7Ѱ6oτ"9/ዻ|0L(VHplٝ@yv8A|mN_{s; *Tvs.PdFWʶU]!3V?8݊5j:EO4RIc+*`F" :wR|u;\5^.Qvv,︤c.mQ*IRmK=ObNV{sDGgjT9ې;0J_ , 6DEPyxoznΈ.,$Gm(9fS-unq yOԺ*2O[,&*VhdBvFydlT/GWoI35,_㦆HOD-w^ U?ŲU1jՒ<6p[MF.sx%< 5}zVt^MV[v#QFbA#w.)R~ŔiƟ9m6X <,3En|RnG7swWdu)%QqzۅƗK]FwXKySm;VG~1-QG]7s57o\ͭ_W;4 kL_Mzpڊnl1%wx Ջjl~kfG$U8dp=C ΐ 5’ogIug)I]_ .ie}q(2o*֖ҕw9ɒk{y~0m>Á9zX.dxQ8ț.:_MveސTRlX=Ӈ5!吪Յ7i ebhD?>==fA^{L .TW![fg_ :&SF@}z]akgE϶foqrZLBqݶ9o?IݽPKG.6+ImzhW_^]Sy~5ܲX"kln|}~ WֵIGV#6i@>q'03z{:4Lp|:vŽdK|otu6[yI:ä۠n}8d)E1Ѩ{ݰ&~);M*7݇,2wFh]|f#NIi-} {n WE1<|]d%l㶱,9z-EDUwōBP!)|'=-:Fs{MWυtw+o̷6& shkn:fvb jY] ۢRs,=5siV{x1(!+9d&5p:_D ϝ4?bv/58LA~_'[i VT#AT2uohg3v3 YJEFY/}:Nmu$skl^2}ҥbZ *V({ZKD?'|5-pxGf{m 4YhtV/<[T_@v~SWXۈM$5 DQgMo>j~5\xSfwx1:cܗ[MY7p}5 L{%M~ÆW>fˊ@tY0}R_k.NẅG6r{=_^oGpU =!?YqNڃN"jl9{gf=۴0ƒI넗Ji x{ACz,|'G\[;ibZ] ~ĩttV/i9W_fm foJvpKZ”UV߼^I93&Xde$ߙAH&#p`6Gt 1Y-kﻵPyoa eߪVaibM Xw>n!Q ~UKxA#t rWE΍{|?:*bd]l,vON:R4IW`:?)n~{B:Cwg Gbra z~]%c7ulZI/,;;jT!1>\>Go.6^>-M5^~$KGu j&QLZ(-7"LZs3-,~{ɯJfGv9B8xDBw3 0G N:uҝ#(煴?; 8KuZ]UO-e Emp*K꣫ wZij/vMm-14N^ӁϻfMX/Q]1lnBooD5Kd|>M wfESn➃|WG+٫}h=vv8{԰er@_uǐʱPc﫽J.3U'A1{W@qc2*{}HjY:l|^$N K7pt_ӏ*f/glBTX%ΤgzLX1hkFnxU'1_dT.8MZܐO@}>Rǽq#r[^ٝUgVUrb_g{87`l'w7rH^% =c1tvfؐ8ˁ/F=)PX8Ok. ꂺ*_QTGavvThضLȑ~PWӵO9ZNRHAsG&^]/ݧ vC+d둗ڢܐ:yٽMcdsD}'7ݡFF͏Eޥt8+)$ )ó$أ07߃J/o2߸tWFti9IU5) zաCF?+Gf~G:[e,?t]J zgq4Yq7p`/WQ_loFJ;GN8Jڴ)1 ?4{ӠG$Nն:w9T-m(t1I3 @8e/=\~7^;iq ΄M)<o~ \!t沮PơzK'ΪnuiS/´_'ϲ݃}3Y0H3!'`ŷ\W9{hx@Ҟ]ո!Ķٻ|aBpF"{ \moqdx/2\ ʬL$=w`c߈t>sA4CߙMa mv>.u_ow_+#FRw"2e=skV~@ #tt34 7ze^/=ت?3H2.`mvLMIFwQHc7I]Qx_K;s]/KTLdi}@R:yurFERf㮍le+! f1NAG5얫ebNZKjϊWc|_e2_`O+XLSɥP\?Fg~q4EnYT f ]y?۪BeSc,dDvV ɜUg3,br7jZy9 pIPeOT&j{BYnx%P),\~rͪɍȊW8B/F/U%:~:`aicQ稴 3Sk5V[z(6FKo`~(DY|O{0VQSzawӻoV*Pt9Ӊq~J}|=$.ǕSٰyjOGeM%f ;0C?䫻rWcTۋ skA{5ɶBhܳ**m" EVr^ar xoXm+:L/Q4躸 zͻ8[wD?m͔'vfEvE^iȠv#=ޙ?HiZ n 83mtYa˟^-:~ScsbGaJ~{=3F^É48(`| mV^t|t-Mƹ]:n}DpX:7$<v+$rImop{$+QbU鵖VԀ&):MV(֯/:-Ȁ6 0LڣCɦ-T>B@PoN.%0Hkק˙mE\5vީhMъ$;}?)t)=z6Z;; fa?L#MV;vԊg^*VO ξ]9gTؘUEI)\RZ.n"o.ߊ,퉐/hѻa$Ghr;[y&.H8y?:tZvre}(vb2M x}Gc^ʗX1vxg' ɸ8ܽzV'R7O >Z&^:=H[13XT+ZkJC_.W_פ[#7E{9Ù{@9\`cckB&>eaNɠ>A5dTǧJUF`ӽ!у&EdDOnR_l<~P^f[Nj `stw]RoMM5x1 ZSBdsceuVҢB>^7(3s>~.{qE<|z)G?: ;\zA5ЧtBesK$kP>8wmd'{541IQ*f[wq9tKKq.ܝ}>/Lcrжl?d<\I961^03:UvezX(G_nmdЄRQ9vd^rk3lվ3Q:BbˀpCB )>OdAF)a k3Cg^wRmK%Jg%DE!-r\xƉc"HVZ8eȆUSFd`UŃY h8C/Kooi'rr+#⨔/:G ΟJtj@}Nikrdt/fbwNtOfo[ϙIܖlg:s{__ټ3sO1Z,2z7fKx)iVFVMUa%ٛn'22bAi_]5e^xe^FDq/c 5..*+kٷwF;#q`s,)~9Q}d ~$*XZDsJ%̘R L}|^z(m9}*wY{;߅lRyW\ٙPߋ=rJk/8JslN83dǾyJҤrJ)]\1֬{ߕ+7ߕq=osګzbUۺe?h>^X}mG'e09[t%ghLJ[|4D0~E_5y0+=ʄʮWNJ%u%QҜ6x2ږ7D"˪bST{aA;8٤ZY?iWXkΞaS@ĆO <7ǒWO2D26M}h _j_;_,Onp\iu<3n>BX\L ;G10vʢ2ͅ7C(GZC\( 6ypX _5n&&t5vV?%t4~hssoɬ`hF2#{3?,!q!{Gɻ c;eyݖ/κt*>cSW&j vYʷ{å"QGudVAw0ĊXvPR7 WߗUw&C>]@dj'Y0҂$uLp2 , LmyL#7Tg ||U{yVP|_ev|Ե8Y;Gs$˳{|i$ey9'&\ \8l2'^ekO&慝Sȋt wP=/oE3x}=څc<~t,aPb585pxÑ[\}jtd"׈ZmÏ83v5>hް@nGhl*$ }9FlfH+"6by>߬pitjOq1`c> %~׌gFS phג>HF|<:N*law@wjl9NW^Fqn1lhw:x^S`01 }v'W^:6B Ui^TI(i%LP2b`[\h\eXX#C5܇3Pt|Ugs 'u>^1//&OHU=fvLk94i/r:ѿXp@P]ڝ(h4FQ\Y2rgy߂=jۄp\tK }:a(n`j6MjVӳr"Ԙuexeu542.0T=Rm0&k=|ʮ>]q,L n6+v[4jWO4wk݊%dic\pOmZ]{ q*cZA}WO{gI{dlS#} GJ|޺)=kP3蚯UxJmk.b$cֶuZ_*mVwN1 0q^&DnƗ{h[Ja|4cZ><+C:fT //i&|(fIJyPnʍ\ lz)ɀR"` ~UԦ4Y?~QI>a?2;4>~lr B ]*?7h9L~Ԧ KU [&OоG.pzcmo"j,xe_݋PTRGJ>A).LQ'p3bں5@)F 0 CH/U럻ٙ}mL7Iu.Mmy0?;n+]:g K-(i䧍x9; 58b4WJǷldrcw{$8[L6nc:h*aY@zI7-d@7]uĒxGXed2/] 3^^r vJ XYrI q_~Ulv pt}ni7iENORb:1N#>0b壯>qnv4Z(lpi>sp)~i^+1(#ҷNGϰ/ z`&R;*`.Z` LC>LQQ~yj|.:b^X4ѦTHY Z쁝L{$tSG>r9sʭCngK(uZ^(3]}o WGZn^iujOm9.,y5T9ιzH =d9'7 qP=TPog{@~zzwZ͛8[)'l4FnNrه WIPLFsqORnJTh~ l/}\qk"bΰ d/iVF}+WW,2*Uޗ$f<ә8Z~1}ײ*[8PMvWiU+:}'[ o0IVx6knc5[\ܢC7K'b5^2_-NH"y Qr).B^D@h."aɧ"hu<1ճ+K>Axa+b2,Lo$ ̂`gNGyP5`iw MT9ovCT]fDQ{aJT^vWкS5-_\^ޭ6/m7Xw؊ hEF=| ֜6@c"緬U FW-j{ ͣ[Dg}IQ.Gcg^de+ƱkϪW/2#WI:|l'( u8RfTvc'timf\+8hGF]Tx2X+v:,/HXE˃BN˗;upcqɂeo7^]Nul" %aY[ ԧ[av?XЭ'u/ e+ {sˇg'XO{V)ۉدvVNZIb<|yX6ʮ\>5i-CR(R,wx֑*O=;t.߮9Ŀ:}Jigy7fpefV]?](ya?FՅoiG)ɣ>^Ȗr,H,i}je_mfzm>!FL#WJGϟ! Ƣ~t)-:|tXVK{/!|aUF" KѝԹn>tU=;!u&iÌijd0|:W3^Ė2ޔ5n= ކGKjMtnXץnuK5/55.O F |D c.)uv9yh_&R7ɏWë/kQ]{|Y{R^ך鹻Jifkq#¼~hёz-)o}j"9|ClUk|CsZalƻt9a7м_贎1Ab5.TE[`x*n|5vwh{{ <[qdžP])Op^hKFBl_ħ{jT9&^IKKs0Cx37bcat(t>m #ݗ_ccv+jFD%(#A]1. riP/w1:9Y)W :sFfa+ko@,pK 궔U}v QdIʑM Vm8S|$?[9C#rmDq2A-uMvLYa,d;aL&lؾ\OA=NFZn,K^+*sHZ-`7 h:gd @]5|cGg6W{s牜;D7Cr!#Ǔ-==ZY^`zWa>1ՇyEiv|muHt0XGUhޓ-;Ͷ>BKMmz\ûQt اQ9;܏'^_|Fԇu6}ݼ:=\{ߞ_B7 `5\C'UEUp|^+8\,㻭_{g*?Jihj^};@q QɝSo0;=-X^O+\by#zz%Ega%ԑ.{F>ˎzO[€|/V7wÍ/[ 'ǏVzayk?S{>.A%6XLǟK9I~wL@Z)kmᥝR[7gTq\v -bY5m*QsiWm6ʺz72n9nJmpfp{t\.e%r0zrmU+7%q3χ(szOy}T.Q*/uNF/3B4bsN^4}Ohɽ (Xȱ8m{EyV$"ՙ5nbI `:cQ+du(5\;Nc->2I\F*8y Ƶ ƼVw*8[cw}ܦ?bHX8W/7XcDw٭^#Rt~olH@/>V:^_]g5m߄^*}(R_(ptGʻVc],K_JIy"TqѷaHt=sOHDM1Ix#jZ_ 2K<< ~K]uFknF4z_e0]d &+ݘ\>%l깬WۍVD6* #I=M؛ƻT}]Nm3=#IԢ[n|>Z_uHѬs5rp%hOzjO?94xu7.j]/gh&;]JaY)Gj3u/Sl ]=~W^'xA6,!EvȦWm.ٱ\Nzw5>^>Ͻ]ޖ`yFu ZӚH'VWzS} `UepsLT#۪aN|1C5xj[_Jw{=k[sCRrū0Ȯ7MwEߣ{.jZTjx0yvSr͎^&HqJ_vߑn~j'1~>:}jEz/tmM:OH깃,Yଊ I*0q4pO yimG` z+l'[zsrynܪV O=ԛAtUoO:]ۆ^}d[ <lLm pOZ/]5XW~ٰ+'H}ө%-vK(`U5&o(תᴁ`9D$1zGgF+8A4 44(C"d*MΗSyZ?Mɯm\]ծ9RGe5} |3TT 4!P˫O+sn3"cr34cRo~>R)rywEMG]WDM_+j?+.4#Ӊw?dqnqNl}v6 ne6<_3ƃ|A^Y볝S 5;1 R9?}#G~HuRӪE %[j0~yM`Z'jϥ7xkIpތ{8Ё虏8ͻݛdoVX3 =kݎ@k ο@xQYtO Q;~]O~-ʠB|Og}VG10q_rݙnd%O_rvPyelTcf% tz+G$nʖٕ\߳MƑt,sSD$V(19'uoGNz0WbJ)^L@־ 8=䵿͆8TeDsU3}V=k=?4Q[^l)rɮ(߾A("t~x~c?}ڢWeSe0ƴL>VNEM;U*_3f (8.F. &2uy8~*NJҦQoZB|l5ݻv++V܋kds"%Hp^=6hc7o5@ftԱ[wf8png4ݏ= rFm랃RyȴVǶکhOAH@Tyxc_|bs絇w>R}<ٴqTr|ϮKbvժUxJ0VDc=8;?Qn:,ߐ>]meWkOB)oQp}J8o9^TnҽZ ykLn^m ࿷ _ &aRsH<W+8F~|* V{Xͮؠ&l5&O$Nѕ{{)@jĄ_}OA292<|=al?7k<7-oKP`洸sct})oVƕ˲u@#26ы馿O4}-npHѱ|7q&CRBlщuYow#h5tak>\qSq̫c7߹y*ߺXg*mIGTr22w/*YpW~T>˞A$!l(&q1N4VPKHQ0k= U[ 5rЃއYOOKs/c\v"gٜՠMkNP#"T;}f! f'* j0 Ra :`-S4M?+(-Ý+in ?֋k,"KϟzfzBѸ"~m9 znq^jg]۔ԯ >a}ZU>h,2{u+֪}l[T2ߏDMvbJ>R`hBW]3~-7[ @='0y%&(ȂYMO] S ||[ZaN79mׯ*Zh6ck 0m%ĠbeUcB~%@ē#5i4(+} #R7V6G3`6B녽D̶K!+=lcHl|KOz5x0 |;ֹ,|6Nvm`M:ؓݟ/X0=yĉJNߵ»F;'#ZNƋ~cCu2B;WuƵ`7I|G>蹡iߒG!V/郙 dV27c|:ҋǓm]4V:84~jG&GG ;òJޅU߁T[ר׶%pDzPX>Z>|Eܼ3ѿ7XA=d52S|-{'quޮRldIk'@jH)M '"\*#L` S R? 5} {f*q[/HQ;Ǖj3(iÉ{emׅ'F2yy[w]֠3Sl$ C4-r2Uf5SgUr@kg'`qm$`pʥ2Xg݋l]%v+==Oa{b{]a`Z{ޥ*_Ȅ 4yFMX4Hc&t+鉳ku2Q TQ&z Ta<s r5<@8mG@׶L-E7UB`X"AERK'.>$lKU(O+n ⛩SWOXSy棛Y}ʹM1'`Gu`R _g_;ndr>({kӸHl9[qWɇ.٭b>YX֝~rx-TskcO ہ?]qAA=^BkmGYr{]F]:v;=.Gas9wFY4U[M_l&@$ҫ}lfRKzZnsy{.̈́.P. 8*kI*ՍԚ{0sDHv)W:DD^~2,Vܒ Zf_ 3s-Yس?'z:ΌQOksuIV3 3D0hs(c9?3Az]z!赏6_ \5˱ݸ51q>`-)ԶEoi?;{t,(p>ԓT1*\>R -7_t{\zn87+˝^6C#akWNȸ:֒k~v p//ڱot wl~Hڹ4): _ʟ}I^ַ~w Y>Q[7Q{ƃS:tW~ʻ"e* t-b81fY$B`'0sƂ/JL%jkyK?ؙpաd#;֤+0f>:khq׶y %"];zDg&Yv3`+˭q4ن;-ۡZ}@KV}an2Qt]{vc58*$g/քpvg9;^/ I}K_Bݩ 9|.42e+=&kɟd1RBb_={ۣh.eb.Mz]krkB&V/gS+qv"fPO_7LY;CKUTc }$Vo9-玨?v .E۞'i`h)[ӊ'~{%gO_!2#ϵmo{l's-9L' Qގ&6[l\s+j/uL@CE4fueB6|=LFd1>[up:/X#ܽ_?U؀T# numC,0v7av7{xLpxWq:^6wM( \#QOzN祥t02a= 4_}kqf:y]d Fo%r[a8v ԮzW( ;ޡ.j)/'mMӫW탸Tn#`J(< q`<0P:NIiK/ _欨{5FfʴܯZOL  8= ^3q9~6l/gn)gRٲ0sDƷPQM$>־;F?f ./l@R i98ٛ=H=J\N` ̵)ccYժ>a‘j!}IoK⮇ضVw'TQ SJJ1]^b OckNV=lqC r'^ܡ,r#BY 1?`tsHYI?Do1TYsl8?u[;Lu֓4cYd~AܺRZ>;ybUpQ%jpS6 %VW³V[xFϯ1My50^x:dOh#$]i\u׿R)U{?B8SyK-]kQzWp30GslBE@K'-e?miiI˵[(ϸ 5]D@0y} EMDݍxlOntޯ)AX=Ig[ vE\}]}v,W+ xT:)˱+Cu铦'yr~}g)K~Od]4Mc*uTB߻2YGޭ}n;sA5m+f[C@mX0-rr+*ۭz]&'2qp~|. O[;@m/:Y)U4j4}dJm5 Rh#Ͼ65v@r8UKE <ձԓ*?}ekrH_}e8=.w&7WMJo-mi]F 2{믭TDߋx=J!FP}E+Ϳnj5F,*ht[2Uo#ɦ/CVwXro0x{ m:~^F'[5`.<ĂU̸K]VMsQJ7[Po(R)K T`TW^ϊ/B>]s, _~B3(>^o5Uwٱ-w϶?դj3УE=7dPFԳQ<"7b7̢i!jE)Iҝ]c!i~_I:]Ƣ+ưI`B$}*CQ}\"N3ݹCm*X _x]h ZZTWMKe8$޾LHJgBQX6}ܿ\<:v7sNA~<,Ek^nm` 6B@/Z6Nl/oNyrh/vZVm qʵ)iPjdN5HX2/şWCL+)zM<7ƿSa^̬dAwZGf&,ǣ{&+e5 o. =\JW=jt-`qkuс9^xz%1Y6LUƹ}?RwPQ=c.tU˹)%Sg"cEt6X{ػ~;WL_W35> G;"_U_r \,%6g[uwߍBŷG>x ߲bl3UWX[K Q%s3jʕ2YOxK WUv8gwƯ >GOnb0\q]]&gcWbd oJZG[7IB .߀&6uB-2 sW,얙8ǰu7kޗZZO+yfa"ߋ'jl8hcēN<<} msZ !:HD"$FZ0"0Viho^ o>zO }iq㇛e7%?{ȵI]mWjɶXW+ѦaRA٢-rL n'3i]"Zm\jZ t4~(s=͇١3Y)fB7o& sei4#0λO23Č{.(lyKm`@~R*vk}b:ヲ*(鳽+fn<#Ӣ./Y*e#UJG za|8w[۵Zte)yBT}]Wpn ܄ ϻ";wP@jXݮ0g 7[>5UcI&[|Ro+ nи9Y=# b6|%9Fqd^Fq8YFmO8;=@?b7R}@БVZvgɣ=/}ӑsQy~yj-Pg=X+0rWz6hO[_*,ԭ-oz?+"PD$p:vN>P.gg˴wy-2- *>.hfR?i+7D>Ek[ Ȍ8L^ϠRzY|-q azt<|܊d|9&w 漪"-Zg߷kE)7pJe7e%޼Mv/Wqr:.Rgż> {$~؏c|?sa#fO7uW&u}Zy~}N9dTRm%lY"C|Lfr!QXA[Cb|N[~һ4;k\Id#X ž( 7ԵV׵;֎ԒRI:2F=iDW`ocܸ_9v/auG/a?.ZlA]s(P%e dS >Uy5}zpY?hu<ąˌy~ {p}kOI 6|g>@"dM4ďT;XrgMV2J7.Ò]E7(V+Qv Q kd0ҁhڗlnD1"0ƱZ^* \4&6Su/(dWPϞq~ +U^6;eߺ9"cv(GYk0u-q(|AI6ݯRNFm޷in;$S ϨC n#Z?οkKGotʟNйN@l%~O.%> >$'r>QEYR;ߥ'׳^x^qi).T1g235J/uF=Kde(j+es9€%܎gٮ!1ʲdC Ky~#ɹW΍]SU4o5[=xiAThlSnC"/ȨV:W׬O-<ΏUh^ lt{ޑع:Xl>GUZnCJg9ٚr[Cv(vs 2Ҿr gDOkH߃xm Vp[4aocتzr#nIlOUI CI)с*ܻ1%H#z2S#Ly.vvyfE`,z-Я.țUR9טzZw 5'A-˫Dn|k܉S_$Y 8AQ~O)3PX|ĶE Ke*'/Ǡxk "9`p`~i\.KyRiqZ_1/%I7qeG`s{Dq뛍zmh'r-kwoN:@y]ʽaԃ9bċ췡rt.SVT;ip?ԫ-tl+e-O +XY)Ukr{g'qm? ~ WrD56f-;)=}̘76<[ywt~:}U&ځ?dw?RX{ħ]#o94ˡџUX6*mLWɃ[]xb^_AOSߖZD~Btf]n߮7Rv^o5Uiղ:_c*>>4K^=epn-̢_wMkvgץn=IOsASwҶyWݍ~ȴ[i*B:l"BQVA3F}Ucfv]8|iOQ:O2Ox?|JY7o=Z\m94p`qTlz%oc*7v+֘:_wlo'3yR47+5.QH௄XNd闯le6ro)W&s9ḥMh`rO M0Jw]Qȭ Wpz Sb>CW{:4/8He#pX.ZlBa:TVy6;cHD  ̜e슓Dٸh f/Xե=T989!Uzd%tDd]!ՇmLV4Ń#$qۿ3ͨHdoq}Lg:Nk{f?<-X&ŵ v2PnCglW{CgFTzb,{y/w‰gԬпtUZ)b1$ɠ3HVtA2~|KKy%4[CpăפUƣNޝSN/x+\N/Opw*nIQ:"LjHqŮ ґ@]ݯ;v6*^ܬ7T;-h2m[1ѪF  rT[{Q:K l!~p=p\(bH'K{{krJ5 =")k)S_&VG:U.)~`hk cp^ﹶX&u;c]p?jm׹$o@ '_ ́}'ڇX^L΋x?D#nXRb; jGFWqFaUtLힾjo:9:ʨ6)\?[zy} Z\`0lOd"299tѮv̴7G.^Y~CFcqT[j{ 3y*G\7Y#:Wq",pS#c78O`ɬ5g.|ѹIZVa n5th1Ec:wf4:eО?͓煎J"DXV/҅YEOB8h\NR *z mW5**ɻm v*-1ͭn٦ %3rzmFxܱxhGNyLźUMQvW}3yL:DBta:崏@q>r[AemFNtjQ~Vc;v"^s0nhVn2zSf_+X 8k.`Oϡ-vx8"vE!oBt*Y ̭̐EF!&cZ;%8.4e6slDBB,{xWhAQĚuQ$]-!xRpD.;Z(vʗ-R+PrZ;vFo߮[)*-yw>PKf(IaRߗIu\&<&muśP>(j[,Ҽ'.x!~x9x,#a*Uk$-$[j:pi؂ ~9` ]=/- s/qؕg*Ы߶Ye)ٽY*sT⼉͂eZ%lp7_vlOszD?m^Ҫr~z5G;4}UqyGh{dޛKu!ֻy2.Ɨ :jF +ϠEd3GJ޼E4gbLlDMn=~w[z8Ww2p[iZq$ĭ ȖƳ~x!o7IJ-;hrzKnQrw؛>lt >[Ϥw S̽jdbĚMRw*/l;&kxfHO Z,JZ`}[é 7N^(*~Lʤo< 2Qj1badq_>K1 yyDi|DSq6g#-[ĆJڞ,cMߙ)ǫDob8k uyyY.IXZws>| EWn^j4n;Z+m呼f3(#NxݔKioxH] .;^aMP/] ؚ 8YdlUiU?%CZ(P0Ac7L%knƭ#y_fjnӁU0X×i}Sk6i\9+vx??Xw-]8s6~Rar:@Tߪٵq'uOnPR#BY3 2nfᣬ>%?dUU!u+vl?gԏ']˘خ/ת cjQ'43ثldu5pC)~G|ܮ[U8?9S|w{k~}lpE2_ !,Y5yX.Kgu)S?xpfh8 *TâS?1ݔ[  gw T*i*] p1Sכn]1JFYNj,ҭ|-/O{D4-OOқT[0cv "b@9dfs@#qZň}ݥ ehIhc:ǛTl@Voޚ9?qOK_lNS-d~YNIzJoŬG{)֯UVV?!j^Uf`$LK½`G}n3D dp%C{VaYKu4Պ;탆Ɯ7ݸ0ӤߢA !q8|ZtَTj9:;.4<'ޙ8xҿ-t$Y:-W~*;px=8שSKy;S!6ڂk!jƆ3GI]a?}w.O5 FzZШ/ kRt_L/> |*߫v")em%5jMּ-;{Q ]/㐘}%ې,pcփ {i/K.p,%5tX:DNx#[w~TFJX4(YР34,t﵌1;?t ۜ#dT.ӴsLA]'y}Fg㫛 nZd޺\v ft)kgkt ׷Z~nui"cbě~hk -7ϸF0i j<>ں^";.}œ`9M"t3cu_Ayԏ]{L:q'zi7ֺж.K ;R95MHVs.3soC%XT&5gQ/I 7+tw!U$Nb~7 rn<|m<ɠ֭K|!+\oٽ6pj9~?z]>`EOJȮ&8Xv>Mq{jEu`ʡ?o|+5^'^3Ѽ+ԔZ[2|fܵd>~zs1ߙٱ"Nxw@u;9_ JtDe²1Z<ޥlj>dx4[Nc>1/a."]X O?=}}hܴVx Wmȅr zdq3OG^~S'iQYz]̎㌟:oVEX=e;z:'kbݖ<\6cnG; ۈ^DǴV:~־򿅧dX`tl@OL6[ Qg6);xe7m#҂ VSUr10ߋZZPx?>$8 &=,禊GǛK))ojUǨ zP*(fr4]~ _Nh2bZoF߶7xD<=IY:%T_Kv%fv({Y>j+^vYt?1sI=wjK%u#]뒪^a\1gGNBٹ#Fa2='=Pbv-n. }E݊RD36Z3E 2r\uQmvT햛ͯ9:гJI{:T&[ bĚ7[@kLJ}(aM<!&6=J\r0SHmyVhhP&o$a$UA¢1IC]èϘOޜw ˷wձZFܤƶf52y.FHo肔OA}e N\&)7,)얟yx9f1,++yo` (U魨) _A=/\zpX/cZ>ιo;Sun#jh۝H;7#uZ.~K_>_^\]^QΚ K˪(׶nD 5S*qaTf91Nw O+s'Za:÷M빵>|j$yl 7]&{e*jD6D 7=isFu;~lz?S :?@sp, m;2??5T"f^2^ ֮PqW4>̔ g6SyTFTlf)/[ti$>k2ma(Rv ipZG&ڟ%JٜI 8+Zlj.H4vnqNѿl9K" }?n[ 9OK^'Ofu6cÍZX3sEP@lOKDyqo-dֻx\NBe޴d\6ݠ6ޑ-KKl(sqa/a':<|+.鿧ӛ[rL`ёpHdԞgsCz٨5;4nvYd4Әgg})YDR`2{t0rμ[pMN(y5Q)_;5.#%;ω [.RG8bM)#ZniH.ϻ1]#λKygHg 1aƀ|;DeMJm9t1el; cO'u1ǵ'rw/O.2G7F;v&v;+}mpNw^c -ŶtG>y8C +č.QF^gJw"F kZo6ʃǴmk4+km8zђ 5zՐ@gƵq{]t_zȏ èסt|n6ɸb|:UA#5}yQF+S6@=$#o'&mTH'-^w2DAk[)cMNTX}O.̷%05.\v[{~̷OHciD=y_Eq`P~(Xg'`T.^T[UQPjuT+I5;\-#/ICGEdR))R:ZU H2k9lXZxY+lw\;s3)o'`I e{7{zh@ɱm ^Ҧ/cvz9n<%iNeȗ 0hzdJY{^8Dׁ:Tj&8Uɸŭ| m.qB@Â_lS) YVgo7ǻHCՉ|S^ԧ O>S^ޤP!BniQK7&س- ?Y=IV#&3^n_*yq $ ψi9b~siN^>J잼ְ`Cd++j K60U^J|N7}}G.I.}s=<_ꒈSיjMcw]7 5H} 6Tt# ?Fsw#7{wxYQoB[қYI(eѰ zqm&âβXB!Ę`I?jE!LJa]^f^YWfmKZWೄeTyR$Zr݈f'EQ/'R  Ғl)_w +^RuF8Oy42ٶO#!זMn9}w4|O wV$#cgCz R'˥9OBvCa.@Rگ'k9ԉM3'Oį)tWxvkV"]lqůvOSX8I~?~NU.K;Y̑זN*t$j#Px3:}sF==H߫sEB+7]K&8QD8r!KVas[C`R_͆cdr>;++?_VƳe1ZgթUty%ޕ>K h98k &#fe9U h}ξfm#MUJTa;i^ n'B4ĘZ,A`w;͢_iWH0w,$I/'|ѕ餦pwX*EjݪL< 17\>QLΠumu#m=*//!hu+cia@ V[P1[[ pٽVi_^ţ$Oý=Ѿޅ!Fsy_ #lu;ٳ^RY-H cA6o@yuMfkiB;/Y_)nt.N`wC!I @7<)!rYc<j %Ѩ0Ęaa> H Ҽv4`P Ü sk}a`\zcͥA5zUssV׿sR@.X%Kbt>#'r@g:6ppcV +q_3zɐYy\-unUFMWvp&T,6Kڃ+ Ӡmv,{ .sZ~mKJfq6oRw*1OCi3{"Qkȋ9jm. J)}uoyK`X{HLOJ8ZhVwxq0:Ydmn(Ts?Nfl6K^|ch0(ȂWB7]OQ5PlB 0r;8k?X=`6_V -I:6{a}]@--wݥxߨ7EQЬ¯!쮰5z>p czcK؏w>Oh(T@NW]/N/Z>9dx=~ZVQs?po^냈2"m-sF$a/Q9=^eYT. V}g땾}Wd[V;eWuT?'o'lO_}0|7S"Gkkg ]MΌF?ХeC譂v>++0WNBU^BLd1N[2VˁU|E̞:Po[h+ ;=NF"!W^91#-9:}?D}b %q̡r_7Bsb; <[mч>mbCw?~Z5kmbKVr*S~[f<HL n^ag=?0xyqΒeIOX2>Ofky;F<SLm?I!h7Z"Ծw2Q캛9~{@S%DʪtԝI Y: 55؝lE- s~wRtsQ'?X+/b{a9qjti8봽b?y؜k3D5(sO)wgKK>TՂTMq:ײ=ۣX9Y/V'DUWpQXl'eG]ޡThwz5Mjn ͡α(y&qRﱷ/G'o\3`1OsYY<.ǵT5vqj^f.jW A{-`SF |5u}gP*4-6U6뤼JFԹ;A\Pu7޳}" |F_;fIۇ54Vݭw ϘˣvA~[Bf2jCJj.EPM+6TxrT7A&e {Izcu\h~i(~ [37pn[1TW@5]eSaKP$m2wZe>f45\҉kW7e\Es}-[mHn9Ͷј[*ktPzo`~=<.u;֭Sno+H[{ Zǡ!2xs2{6ݢOP]lu[L>X^o $T+Ykqeo@]sK*'d%v„mXh>`p<f+;5@YzWlШ,}eWz˦_oezw \⿵m:T÷8xir;8\#!Pu7'G ;\B܍fM_N â׾qPn,JƌT͛&aV[aG#'䴿%|S x`վS"cޗ!b>}1OՉhlֵj!!xo=Xtiu7XL۪:ek rݽtx/_d%~foVQ3ޭ6Bx$[ueQDܐ@ d;-˟~I[qxSp`87K=;q}ݏ0m-?GT;.xR#LrrJ\b:JRǽ=ҳO{7MGFnkC, 9FhS;g߲%'oHLwƕɒ42,ѥ(jW)U-Fl+f;wLMF:Io8_3**BTN0dUDnVBXKl-/j:yM.AIV|\yb@܆]fZR-~ '-}֧$ǭ0ݳl'0SɌ+ ?D߱s\rIS.T!0Z_UyK&"m}Tj­>2r`N)^du:+ՐI `̎h9gN{{ @*VZt> zB}Ғ{ Μ WQ7?|Ϲn3 +d6kzq;zabԲ2Ʌ8byI͞u}ȕ'eǷM=%1]o0J/j\'qLyJڇaIkӧH֦@Iv7P6[PdPOc/s[0oY;7[YS GјOq[\_.㾩OH'wn,٩b wk)]@7-%6?|t9O .SN >dj^RwO 0D9!ӽWz>?h6%p:u<'frܮ^cjzX:X薯OgݍGU'>3jCri =+}Om}q ƟF28/ u^Ux弙B$p%]iSnH$n(SY zY|:S]"cvtm )j֫SԱ~~0;;]!d܀vw\Ag؈E봢wljE|9~*w r~%W/! ɕ+MqĈJ4qq7}U0Fa*,FꑝSD4&+ns<׫ٶ}Ku>xm#eTvʯ ,XA=*;L/Lvr.f`$~t'Uifɮ;N78`VQsnrsv돛_W$a9bzͪY)Gů{1Y3객D`T߫<$@<%-+w3U{5Tbn^ &JR?znNJ[v:-H^zHR j-L*?݆laGs[W/7;N %E=i IͬJ݁_3[K16qTlykԔBpboT8q)lbU?u[ՠwONNK 'JwV1V|>4r><9OiOk;YqnM5yOKtGGd>H- nnWz:iJ Gܶ?+N<={pLX/HZIUz{WY<1P3iVPY>if2+ϣU:@]Z\@q.=UI y w헾/o|l/rc3>0O!,ģչr[;Vhc<"RPcp0zG&%u!)*@6 Sɺ ;?Ak~tHω#)ͣ[{zT4SS3k ~ﰜ8 քojIk͕̍6о2"Ũ֎Z'yo,]y{g~z׫cĵl|,uOScy GN28a`' of5$N "tuQ2^:JΓ){'a5v2FQ\^Z 9)XzI.#WafeXeVꞳZK\)p~nNxByMr>[^&ڣE-GljVnUXtU!cCЯ޶|{<@֭2C{j>[RQ0V-5HI_\lFNKmۺ,<:p+ wy9r߼<*>¤t.t{u6-6eDY {o( lӞ{=c{{TO͕O˴ƢY4wXGҙ7o>sX?lS<Ǥ 'gh;jPЅ$ٜ Ѱ_ zPWm%2Yn.bkrhOq;.͠>ǻK͋hudUsۅJ;d狸v$= 74V2xa]1&; jWwELgsx@]R?p6pGFd:us4{Lwr^WnBFf:hC]Z/''6 /j^7':ՙ| UQݜ3`=@:_b̈́Drj2>^"l>Vu{5Gmoy:7YFpruH+N׆qɇ/gp)vkN8wle`MtѼC;7fYc0c$,!⼻ bG[+ߛN6q{؄f:+&ĩgg6Zc{:=so;{ֲ۫ I3X1cZ6j8ө(jIm2}Q7լ#"e6"w%FLq Np}TYc lRtCjFK9KHwIѡC)Wߗmzυ(tC]kmyMִ:Q(Yи8>{Ŝ-oNc7fH: w9`;9DkzJVsJ88VWvD޵`hMc0eaY,O͞^SUdrZYs Kʣ ivG4Y>AWWGu/k=)x  _q^:+e?yS &.n;Exɧf 2{ƿ! .!.D4m+T;~JgH)Uwk&VB& f7e[ʬ't `\;]>$Fށ9t0} ncZ/ *]&tN\Z%j=f_nsK&AY& (}j퉈K:)U?ј~l=Y1>s[ؓoŜ-Ya9z>ou'GR9Rh%ʜ!|-V*7X  lڤ2~wޣ2~vZTg&{󈾻\TUDuDwcPϐU;保Vcmx,Wžpئ2Ty:"Gi0+{Te `RS,vT{Jb չٶZl26V 4j]76ѯ )G2+͆p]aF2UiO,IS~VvcۨsY[-F尿TG_:~'"ۗ[|7]αr%D]f{)O(:EH/nzf?W s\ų^{Erm<(q,p%̩QKk܋d6 9Er|iB> (NpSkB̘lwzrO?;v'6l ^cjAB?ꁏ]DI{b?PP94 V-m 4{mcu|`ꮱxrToX_ү fY .'ΣWFuƮt[\njn%mӉY,GlLy7Gsp~*kUio[#{pkަ%hԴsUNi5Tzj#ʏ@chf ڛ9K&>P}Tn Ar2\~Is- [* ^ޟVSqB۹,ށJM!u|+wVZq: lǥ{^,g:rk>s|Cfpm;62v]|:ˉpG 6ݢ%ù5fJϿӬMrc.\?l, FiO=VtÀ>r&Nqwܯ¸3<nahy%PcV :8]HkN)o8`&]zZ5}y|8I#bQ6"^i i }WQǴCW_j[ X)WH {7cF(wW@CCykg=y4>̔+KI}{5F: &>J^]e r#T6U;42UqR, F$|Qh ٮG{ï\6g|at\{$q1z?)6p.Wyu Izo2t^|cnlO{`tna6{Bz'glpi^Wik#^,SCxw/le?XJ.'i' 9]kWg?櫘1e3:5'Z9dzEg6QD,UkWGwTOhz׉zA!%3܌=#Vs9R-MA[EPX,!imU$omXy|;o?\v}'V@67&>2 Re#:iw"[5?COۿz%C?[FI巸BE`Wj&8q6o P \Μ*׋Fع\k7źd MzÜ56h{ Qu͒ wH/2]R+owwp7N"r}&HeK2kXG0;  jmgaua4 okAGR?~|&%~ ?TkguIʺz ocu|LXAjRJRyʃV^:KiY9~aŕ';0z8ޡ'_> NbPd'-[K/1l˔r~dB=U9](9vkjY۵?Օk\Q5jKUCj9=)>gg|)hKz:nvي?XǩG{ =ӡݯTo)YGn余6&g[Z^FGu!U`.gu7ᠽyBs~?+/p q}\P ;igYdw>%t=NREq8!q?Y 6x:#c!ߒbWDݓ,VHz_28n|]r6[‡"˛ָ*Wep=ve%'ej~Y.gQZ YA{Wdi}VGZk:;wfI} '|R+dY3}Gm\:~YJNίq?`g|~!9yn 1m\OUVNUۓuAn4h2y,^"ݨG6ZFU-`޹߄:wu(0Sr"e7Xk~A껖>۸JmÁOQ%^#p ~/(y7p~G&eB~{֯SyJ/gs+])rv {WW鵡Kduh_߮Pz`:0^Ӈ3BM)T+§N e KڝO/TOP4m>s`юWIq4FúdsY/Qga6J\Ms<;:ѶgB2mIͿnF敋;s4DEԌICi&W[Y!_Lyv yJy 6rk488UFa W.Z/&[?\"2$YkmѧNM4^\Xl8T}S7~W z@a:44 ݸmtZQ?p0%<ِ~JfZYw2UjWm-So#T3dTH}WX$ G?!y]6r^ޒqPdiGɊB+Z c&ZׯQ2;t~5C^?B={r5;?VJ]ň{<Gӽr-Nc ((X#O ; u,nHyb.)6plk=]D ,~+ ~f_yPfCOaX!28]~ =ǓzՕs'nw.фXd%y>,aWB|z6cǯm(O/Y[WOVgJ1Z=-ǹUUR2wp޳%,kn Xٹua.7Y.W3n tP} wJpz}.CtW>[omͬj~RkIhV#MqsCуO̹GYmx^js(u{G͖&9lJ>EvXBnA=$2nDL6'f>?JH<s>nZpKg?,Ŏl5+o#o-nJЈ9Jj).:V'Rjq]L$)|OMq-Sn( W)`bΦU2@p(sNd2l`-Qz Re;f}XUeWH+Ī1 sޱD6l^ry/Q{ct 4M_ǯ{5Q{5z)Q FؚŠY.` Z6tVPf}'!Ob[̎L 3{Z۾\z̼0;(7Is9hc-5\]>\Z_Cj;мT.kvNW:tii8B̻qYK\m;'>~.˜9v%AۜA]b!ӻJQܭZ;h_zcUѶUM+Tq]'mY/4ޤKP^ʶV:ʺ\3]fu.ʰ٘NI:_ 61MiG؉^ߵ4" @]`piܓv-0Oz:ث%nNGiG߳U`p[Xz6)}-jo!n&k<oOZ)sKUU9[Mq)2_eoҖYd2CjKp 'L6k;Nz4'`PǁAM>Fv- ˷|kIT+D; $K Xv4VzIqvm`i\ J'r9Ҧn7G]vco2Nbܢ][k(HQy kkЭ/ӏaLGtŸ=rYw"i2;D; RRaqNڕsRzf-Hr@hߓ*MșiؾqMhi&wݎiݮ P8Pp>{zieJ+ͯBmi?HRYhc㲫ۏ~GP^Րuhbs/[e.7Y=A֧!fB,)hȊ <r7lߔx;8JA㋕ǣd,i<βK紗ǿǑ#rwKvO/H8Q)>Ͻ'7yxrE@4.zvGPjM4,.j`l`$=}NwakGt .VHVN#må5v J jҿOb:t?^#phFΆ66{;_[%)@mԮg6Fݏq<=Uy~Pup6P7r4QN«#Av|6zOOL7r6QbVj=wg!M:l8 j?Nh.;Bpڣo6>`~Ӎ5ʭc{5Ĺ4]`f:1`qW'Fo{|]Ej<]^ W2j^[ ;Ҳ/Nme@قш8LzLqXyF sRo&h NmY<DMM =l11TsJe"vckuϮnx) P~y}'K4} D j;~ݖnA{(ˠz۶=ēz)+pU0K!l͘\93]o>Q )sbڹ4S*:@,]>Fb۔<ƾSYn07m%h߽99ձd=66Vj;A<:]ڝ:SP$#X>ϙ rC,AUW YEU:q'/FL OGrI߭;k6>#1B0Ӌ0Sgܖ˙fv{yfj5ÑY$oi=\̪nf4;o"+'g1Tܷ3b:|\4[TrrMR wZhT;HphP,Ppqz# FB|6%9z>v]Z|) ȋ,C/ԫHUwef۽aܦWBbzݏZFx%ĞtgAm-,&sV{ΉOj&wZɴ^ OoٷkmҲSB2酃aF[SRUWNډ]6hB ;8e&Ι ^#'c;)՗HŋnY{yӣ"(sOB>ƾ~e׫k;yY P&~;r D Y6LF|:Mv6S"7%rt-ݥix8wN'P4y4VHzX`!Vj ܻ3Eb$9 `Zw.&rVBH!\\K m>-+Gaiw6]3^>v}: 1nzu"f*mXX'YJbCv0`fy՗yu71dۛ*W eN7 D_lQWC`ÅqcI;)jSܚh.JߛMGbq1[(OieȠ~" MsUa|]Q|¡6JtcaM<{+k.޵kXCvqcqb5^ei6NbR("~m#-a%W\t`[S+ܩQN#}==2ݼ.Cv>H򿓾G*+\+Q G7Ӝ_a;IY> ס2-Ik dq OTրavdzba|r|xIc1߾Ŧ9'EڕHNwH 'Pmi1Ok#TaLȱ ň-FT>}; @gAQ|l7b̻2 V`VTPD4zmwc<;LF:X dT`t,.t0/0*jn&tݽ~}-LF΋֗ۨ:(:q@}:([UAk֘V#G_3|S"oy w6娮Q$:6,}F,D)_h\m`0t 5F2M|fJF<޵#Zsh.ܖ@D{ "rȽ?)}l7ggn^tZB?JnA;bzI|W(fgpdMqDAyO:Y{T={toh'Po&ͻ;3 |#^E\T[j_oeߑY߁g"G4sU,DmP8* RdO:SUYopJ8%| A/Ѐi#^?ȬugyةZI7O]U*&TR;G~ϟ4k~ U?@"'qkoP 4Hj^((ۢF˞b3pEzCϱHJyը$Հ3ةދUDn=DV^"8@,)[eum-l-5fwŌ >!V(:cHt!Na.I 6w_N8k9Mjnj]J&eMډaAeD~Fw%hg,z8͡4èzZ$r)ll]2 -fve=@[oExvȔ,zY_jy-X׿x3Vޣڕ5Q5 0ΓAzC?y^#Fǚ8#O ;k<CT{(I"f-GqQWxIlUܹG vcc t"+bW&6Io. _mp/,]ehZ[RJHӀ3z@P; Պ8qWu`_!f7*"g/~Zj b`;_O#1,S+uո_-?RM_w)DXn(G'<SֹwJ vldˋm~y#؋δ `ZA@֮jYӦ3/"{J# /\v߼wL!y\qs,x5%Wd\2/LXkW8 B6kTz-pnAǸpxwWgzUySqETg|hzs3a:F3'] Μd4=7`=(f\ >t#_w Mpb׭yH頵h bjs5* *U*>W}ܼљ&hf=U! ҙpMȧ\so4(u>OxXN'mP_N]s܇_;5Cդ]S?notr4+x.RuZ^oy(aW}}N=c$}|Yʽ*J+XmוCQk*mnbWO{NCX\יMEUN]l di<4L2l ̃ΎJtNyPzoץ7~C_eZc;Wr= Z`?FEjQI՞foÕ)S7/P:po@_TmfA.yƺ_5KߙaJlͮ1|nCrxyBj )ۢ5;jM,#T iH'חk1wE?0V۠Oxt̓twCg/|Nn.OFg=^l߯c%?!~mټ8lAݩ{Hl~D]Te?: zU߭af@OZ]y/3d6i QB*칻~jլۡkHu<ձ0Uq{.͜=owǖ+b%1멛j3Y5/l?^%?xt{WX@PGC.bww1/xSv>}qvoΦ́+ע*MՔZ#<]56opλB^h%:yq3;?(5İ~8&[43*Ϝ5ItSe0{8\Jtjo@};lMk67C;7g["ɍ3bFЪ͚Udf?׀nHji%]k?YAFeMDC02F(wB"^^E̦9L{v*]qv?+ҫԌ8!G IYc=/(X!R,؋yHyؙ!:TjoT{ӯXAoڱTHۜz s GڲM U宝йUmj%mi|3uŖ;h#ZfĀIօ qÍCshOxDRq'b7u9/pt4.ܞ^&nNܤr!y -b;OKꍻzLY.1*sKܭ3w|eWx7pLNbecك9AI S\)\$3 Se-mS*4Rw*BxrjXt}-4źoB0`ݘqE7͈+=WN~tƲAPޞQ¤\"+\݋|e(S'\1YU݆|jj 3iHt#Z9%+-ӽJ}qawg= 󧍥)1L+ctK}j^G{*A,qxgЛ4 Ъ𬀞 sֆkIӔoU9M~Ut858~su;TV/yn77+]DrPC\i'{JxTWt(:FvX^~ʷ`3N鸴yo/bz^e'6ňIz%}v̳c/6G2/?%Q(?zB Ͻ?~5F{i#h1JѢL'C_k@ۓ``>f7FYy_m\iE4k-2jTPߣ}[Z :Sׂ͚,ȗ[zWQ&C2կ~ 9i ɣ4*Pt|Y'f;ӡP.af]pZ?Ƽn_G.M3~ /Β\{  כDL u*#0}@n؝BWeα~{ť9uBg.&9n˴/G޲d_M=F..Mu;p|=#iAۺI) tXIF) B|${C+V?Q:la˾WnlζFum:i.oKi`@HpDCaݪ~7EV+ @1$RN+d!>K#RW?ڦGwj-Ic[-LS2 w ϰΞ*9 E(ۂEZ+@`&/|woH#nx=:?ro5?z9 _fXIR+2L~KH{dpI[~'sV^0ioDVVGkf%-;Z(BK.Z5v DSXٌ%_6aEו=|Gy9V 0LJP`4oW@cT\iGwd\sQuجz #;W$t\=ӨO3> Y _{!'"As?M¾MSv}.e򭶛wi}5s[]=VPt&Lb>N{ (_&Eky*cƌoR3:e/u6Jl GӨ}k¼H],(Эb5;"e Jƕ?hNúX6@Oxf ^9X$v-t/d=0goO^fsߢ]NY`Fڠg5pSiE9o@lӣFDNi x_o_Jv{@jf7Ymt|Cͪ6gL.Ԑ1:d=l Rje0Hc&DuǓLG^+hzڸ4v46`7ynQja\oZʷc|BMiU'%g+Z5;흪t3A1tS~ɃO2,F:%0M44eAt]KڕꕻS}GH=vRprS,E6hpMAE2.xa6WMB\e.l,æ`p?{ɩ=fe/1W`mE wȦCsijŏ9߼ğ>3nZ1<-F3}cLa[HM! ,<vƒuy'/Yn߶’]J<`.SI#ohL҇95e}Kr{u[Bף\ŵמ൫{w@?P'竱[g,p1mi9M{4Ñ >ZPM~K FEkjS?_=%xwVUp.@Dmdٖ/鷾F^ecH7-&՛>޲`6 XOtxFMJE"vUNRP26Z_'0U_Ch5l{a3AܼçVe4 -ru:S $C~)|wtCs'[UXr8M!5[Ham\A3Nγa=gȪ!{^;|U: 3?+{PiǜI~݀'O#Ye|nxVHP289-2Nߎ=REU<V~HBY1 >DBfr.^s'C,rozѭ2Y1b+$:amװ%VRAnoPgtm5ZEf0EyMlzjU 5s]ݼER^1tNQ}5ggTjtM#r|pԽE5 WO>%Ձ{)hUZsnƙ47u͞װ٣da{)axeJg }Gcv[>R;J ㅈH1೙F ʋ^y\r;zfQ~v ]U,A4}8hlX3 iss4q{I^~[ sf *$T_G_%bIPڗ=vM95ױ^]wtp80>Տ(N׽LKnml&݆(cߪ'xzo $K<|E,x{+2/ ʽgػAnJ>ym{)ՔElt  {n2<@;M~}֭e_PQQ=>l#]Sd|RH;i.aVIX;ÒBהP~+`uW&usfD&`x/B(n=^x/y vm=jɉm yG{nz~+f_J)}#WGjNS7]=e˹R9O2h|u1&#Y3X+ l*Х|6VjZ{9nD8O՟v0ldgќ0[/f>Uv(4i]emYS1&[p(#o 7Ni}v%f֋%ói=tZ 8J~kwn]tb\j܂3:Cw<NHXЬQ5 bıis@??=Gv]^+d’(&A?&qI 5>G4&?b'jH:hTt:^ >7K[ִ6(K:n-AeN2eZV.b᫝޽pGU^ԇ:x1_ۜ[ܹx g#| ԛVn1jujYiHW /c>tc6h.׶7>͞`/$:"%3G.(ƇZܓaEV;٠Ԫcn8$ 'ϣ *|zm#qΜk]R3*+F>\_>MS9cU++l(w8|ht'!;RV; Zz/n3?hY;O0.v}!AUĬtMfIUC:#xMRU7mB3-Ǚ5#n2ŧ#=']f֝z-}^#d'Ye}j;Bvק3"IwqE-GdP10ޕM~ ϧ[?K]!qtZh{YaH>7Pj32zM~sa-2^yc}z.Ó{ xuW>Ns 'TIJ3+@0C*KQj(Fc_+7H[*͇0yGw++xܐ_8p^*T U54.r͙5,wӬgl_w@#H#n[˧Y/Q)V2)YX"H0+?~X"OUm Q[FIy#]0?AiPY]pl#Y:5yv8\*=;O6Kk DS9_=ygR QpÉX\}9^A\)+a]K QVn登7,{tAA / IA`׾o}dK|@#ƀ/+_N^fB,N4 .6Ff')y֜t[ZՁ`i^)- bՅ(+bakxv(w} ;XLVuCl-K͎Mw.*fRzqv|?pdy3[rltHؙX8si\6^KWJ{*6Ǟ^[=ȯ"JqP:y|ъFK}0#b-Pmh?]2@2>ĕ5޳} ΰ4T$܇Gy=%GqQ;ڵ bVd$CPcHm &G-Xn6!d%{<9gv\(ɒmm}iJ{MT~uGx{;/BZLRcl\S[WD ~xfuKSh~fLn/kuVi?W{8pzrw..Xtl2;ɯC:3([$YW{H?nfHK%Yp9nl/vG~˴j7Kg=|qVג+, %%1\ T#jC{6^^P+L|pV0LxE;!j!Uߡ:!Іe{kkf%ł3ZaT~7ܷ+ 3$X7^1[i+`/RCI٪4.-w?46}pQl>j~b!ܩN =nϠꋠ&H\P_b'&F2es#L;^-N:=.BQYD|#̻~p}<|<$bTM4=mBxOivq)\,۹?Rh( ϒ!q'͂&]Sv,QDpїx}H7[o{zQR=]]}7Cu[apk(Щ,DMnVV+bidNX8:=&cvR1pֳC/`Fg$*NUhQ\M0| A;QP)JRd{Yּfc{ST=%6]=ͭG'#3Nfr"Dk =Le&q)e7}/MW:o#0ҧZŤr%t*ipe Itm jrU \NS% wS.7szVH0L^jrl5h.7>f$ƧӨ4<M3P=N7Q!VS7Fg h?  |;(o2dq~_G>w40K=w`1^ziAO6dՄڐX^<LZ2ETڦi>?M[Ơag6Cnn%LYYȝkЄ:A9 Ğ%Mu25stK}S[Px6i5-KkpO5r|ckgCf+j1=t;Ow_2.ץ#D8N;̛hpYet͇B053mƊ+5gD4 ߃u55L6UJr=ь:- ྜ\w߼ !Tm+YZOÄRC XQZ hN:XW޲] .+pMhDFgm0i*'oTU2~R|4 f 9.ىtT tgF!WB\8ֆNэ^(:-tf.VB:ǿ1]qUX#X'K~RF>0z>zy \ߌ6qm-|A."{d~qp-FuҹuNɃwЍg~ƂPB4p[RPE֓a`џh:Zp">ֱZfQҵ8<6D/vg{K'j<,;R-IIbj^eea SV w'n_:o7 V-_(c%;іWge{26(F78dtHh_F]zIQ |,ztG+9OXȳ|KƬ ce*Ojj|x Bڤ%' d4ѱ*t[tԌ?]Z^~?%K-o\<Ӯ8A6M4 t)mb]G.mØ| u25$oI+&cO$̧QZ4=sONTm+zǾbޘnپֳeku*< Q,lDj7d8nշ)!Jޅԯ(1y/;"tm7&Zϳ_}u0(!^&ߦ vS8.@Z74MWOBR9O/pׇ E)z,2Qcvǟ_Sa *.ͬCSNO̤f^+dj9q9[ϏwOCj7by,v l/=3Ob;B8YjR05GK"eM-2FȈOaHE]q0"C3_&[x{?K+έBJF :G.?.#u-9$K a0z|O[ꗇcKbqj '4|Y=ʊ[_Nb'uwJ蝜 <^ŁfM09@Y*MaTug;"[}~78_r:g3KF&BU~iț5,8pkp?x~]8ߝkUٺOLC.^?oבZݫŎ_hҝzC1l];LT^;kZ _HJyc|֮[, ovb摳Ffzm|m.>\{4ne1z&8H?IxbfPqܘ_Z_םa`b$, #@mEQ5u)jn=7]!.>L}aՐ`9 cП4|=tc`W0 f7>Od;Lx\w3ZZ5y74کh„:ljx޵^%^5VlbL*e8}ǝpP,:5ΖOKr7 6]Dux,sRUvm⸒[qF0Sx -M^e~dZ 2F~ʀhN+LőM۟d8h0Fܱ_ݩR?{ &6 }b.bUU;!(u49ޣ8, Usl[!3o`aN^~zΕmxK/8.KnJmxr׺U'd+ Y{-ͼe];7ko6?{zҎK}$ޜ_@bh̤3ћ. ^ޝ_Mm`{ޛĜaLrZ|?7Biͮ> ZɌֹc@qΛ%>tJJ]MߛX, ߕRG^xJ 6"k!h o+ ی| Q'ڃX99JuS B6,{5ޓv|L4H,m Ҋ~J_=nt}S:@QEl^z0!oFFV&z&6:[:9z A&__{r~^k <e0|°Ƈu򍕙N {>%lZpkm/5jݲ7678*cO7P[X X(APm'ϭhNs1stM8]L7Kr])UWj=n-n3cj+oteUH" UOp>4x+˳RRԙuI8h~&mB#:fabmOQĞ[1%{%k/1S7ػjukPN~Z,F-eo?j׃l0o:E寮Z}|[ߴ)] [:/1;81*L:\l:oG`H[cD7U.2e.MЗTNkL/,n5EGM߸*+92Ns[Y]su^{ZVk[7jzvNGU`qȍEi-w%^Gbf(zi//Z|2T֣Z[^}oR(4<o{}q0Uqmi/lokWHIQYW̃ +,x!XHҷCȍo! ;0vvѻK nǯȯ۵1+0&$kmߑzO7ۻiג{zVk7rgahFl7sŻ=>[*}V)NzؚZ(*KA' 6w$CuwGPNyQ|;P=9ߴ#<9j>F'y>/;Ox=3u j,?^Gu$d}vŕ:#-!M=bDKVsҸ;'|pX2ِM#^WOu},МSfĴdM>6%rJ ӹ( ˒:߈uڝ^_wPFx a7}̗U`>4;?7{n,tWדD*q+};—tUmo$PgԞ_Og>GK aMg0~4)<2>a[8yRٹkQ:,?V= 2Wr߿(U SÛ u;HfAS~mSdV轆4|,gY3>r%ք )G6W*+Եi_ ~mvl6]Oa9.Қ#1^C[<\ل=p%[=+Pεl{͒-Q_sT }DFFSu %,57ivFFw&о>tyq>6[7j'yTX0WPo$~+|bM7HOB{9zL้/:[õ®..#}+0Yc`ٙ kx\+C`۬ߩ0]~;+z_F3SZ5|=7y n#bS_wm,p; q7?e-ݧr֞FIu1rЦ3(Ƒ(xQ檞_K{3]iDtuF#9g,zA>o{iiW[6Vu=jJX9.0qQZ_+n[?&>{Gы[mv^JW;[pid9۝I?꫒&ٺBsڟ8W-}g-c->;xޠv\ےoީ)BGeˇ~H_ϻ8Ne(Ϩi%xeu4Lґ#{m'W*r:|5%.Zh1l+Z| t7jU @fL&cZH^Pz=8R1ZK[p\?{pK .o4k>/5OO*iQe?yszsPefQ}? >_/q]aTud0Q}C+谩~`ۯR&'Y%06/{߼.)_YNG-9vnŝoҫ3;X:UO }6xwZj~b-e(w!ԗ!ʎECxOgNm6wh;CTvkݝ:!Fb}PPN:|۪yTmqy_>{}ͳ[3l4P m圚eLÑSkd' 1pP)*_~Қu:ufs!7y8xGh.?;̬E4<|Ѣ|xH~B ?Zgf<--v#J|*m>;U*: g4}U%~J+I5 +ėU(n{c:o-4WW.Jlev{A TlOlt.buo=<ԇ_i7^^ZEଣ⢋JH@xWT ۔PgmzjB|-Lc[CCNV*`Ys]BG:\?H@ǝhHuJ}6Gӎ8Tfk\T?j6Pj f &?zonƫڸ/|,WR1^نdَutEP13e\?'E9AwYwi#>woQ!EH`uSgDnfG\=[ީ]2UK73tZi6ݜa}~ixRe7X'>POGG$ӁmJ*5v~$IZD~1orIƼCP`m .i]&;Ɠ*P?8ƾ/*][86nq5EA!뻓K1ZɻRQ a^2ٽ%`;f i'n`O CG'IC>ACNe@vZ9<ΘgSUOϧvv=; 4z<(\96/ê_TaLJ~i٘Aۧcul.s^lǓ ͞*eF^%ϊT~x|S[kȄߪ Un@ϱ JnGUKn0Lϼ@ w8uk;wx[= NT)ӑ{wJ>m>M!2ycR MYi?Qd"^aO6uҮJʣX~|0nY$׾jNs[Ú^inB2Wǧ&:Jv JGF^ŽܳQvoϗ{zΨEePb$?xռ+LJ֩mZ&.-?)0}L3Q:*PjA}l rtXAm^)g:mJ5l2:`vv [=#:J;g(ø )EVwzNv{%رss彺踢;}}!\< 38QFP}zz,.cO7(4/eZ_G[R{1r&wʁa7b|S|]&Nl q!Y~.!i5ZC6]ՅxwO]%}itz j)|s)ѓ84d3ݭJ" zѺ'Zxq .-R?k`e(4d'<_5xb9>w30ң; L*Wp=:aKK ixmC-vk=AiT$<^Fto >;>3D2?|d>`u_)F@B`(J>S</n`?]]5]BTZro.82h~*=DR*לS2g>ͣAzە|ኈ7Q %!zGJ@em !q T?M}{W3y__ƄɎ|鲆Zv2ڣ Mh̳G7Uy@\ =j,F~4DQ}7Slsz2^A;-+=9l ƭx_gh6 z1tԨ^&i g p!g&-P†\9 ]6.o-~-TtNROH-%t0|齕뎽8hFS~m%us־쑩5g23v>N(&qr} WKE?/wi \Be8ޤdA=0,(qGcl{S>PsiLmJUR<ǻt*CM"DT|kO,3χ9gm^&g׈pN{֛ ֻk.I!x_ͪLfH]Gf·k'\E "_J]ۨ_VwҺn0ݏNK0ެG\wj񾞣˹i#)|+jG\}TQAB`]jʵW?;m׵; K(@V>6#`m^ YAʻ+Wp ^N5mbџ7946Mh54<*fds%돻Iz]0iUBlѺ E)o%{U2| `3ly!3u_6 ޘsy'eWa`^P5'R.Jzp [煮6nTv6ԵH{0| NχPϑԺgG~ޭ(v^0(V;"dÜ[`}d 55!8Xqr"ʿCkM:(Hٓ 픨Yܿ@u-}+jGB?{ܬq=56ν߽v#@fw3q[W۰ARٿdc6a,2 e Mc )ã.%>\#ujyŬOq>=?݋Hvȕ q JFp $rG"9RtT*]zɂVl|X8i"z]>)eSʭ}q}'خ_38c8uI'hMweŚl*nizWi]?爨~xTc}^^eX 63tLK~Woh7 *g3+u ]Fw>IAƔ[^@wIsCvA W\J*~ wKхvctZ7|MZ%&w^TWbmhQٝ.Z^K - }ÙdՋjO~ ?NJ3\=|T9 S8Q/v5xow{lOpe,[5zOT^]'q NXbs&1x㷐%+A |CܹFբeU>'xCĥTPQWD#{ȿ]zWaOJRB}EMAANy/Sex~dSlKµ(\‡zL,X׏ր 6.i XyQw5[0Aq˸Hco.$3vR4x R8@9ي} ?ڧsu5_EG77@r!G4Uyl<_Pނ~7 V,N>Xu:w+A?ENSV+1nA>ME6|}{cc;s Y9_;Ńλbj?Yr :Ŗ7nzJܴ[Cx H='TG챹 z,cϦfHƒ_~0*؎ w;pf#Xݩq?RΔI )/m #8 5 pf&s0Mc0Yt_r|9`z#|tS< H"y3IZN6Al*1J?Fܠթsk"*I߯rFcka/AOzVosx<+/׳N'<Mx}y͑SiVj;[OEijYfk{Q}Z{/#CAU&|⬽h^6_]] IO҃0m۬܌}}]~[@==},aU=}>mj%)Y_e}0εƻoʵvCFVgc6eow>Ž&S2rO )]_)ӽzo"< ]wG45u:ׅ|j GZ: q!S9m^;MXMi:@}8]# @ky⺴`4&]_Whj;(up%D/V#fev)0H]d c:7GϬ/(yukQ11Rb"l춯Q`B~- PMEuO6!K"{7/;> F%&&[6C 7'W~~ɜ*VЯVdKbXUW7hܼT`piDŽU `>7ŧ*ś;34砟5]F,>a#@^u=*R ; ɷ?ޟǾZYWv`ӌo&7_?z@Y?&O6 =4{)6!%|BseCvڦ2/NMO1J*jO!Yk {@pSJҗ:wċ6)ixԉ{[gchVTT  Iz>z}-OpE$6g:fb_ޥϛS2sI D|7-?W9~9=*ס݄ |7M7M`WƩ$b]Y,{ i+}~X9-*΅Z!wTa/ N λyoo2[*3%?$l\8t?y+fc)Wn(6'aD~^  XlPe vc)9b \:"VIW#ɧ:>'u+m/I I4LUHFz~4H=)@G$m6ެYϾ2^PDe">RpA=sZO˥X)UBs\2^J?Ad> <[H}۫4wԢ۵^gڡssŚ+kK:$?w4Q^Jg{D3h5r)'wiIAmC {oQMGWSYnAPW_u D*2s6[[Hlv֤vcH+ Pבk?Pj)c@7&btϛڝz18VHVb.rҮ̢4/|=0+<Ԝކ-B؟Gٯ#w$lp~+Ef)0ɦI(0.1e֘jo3ۿ`xF )p:Ԇc06WX;LutA9e}W{Q|xr.^Lǿ3Ap|Aw!2NGYTLWJg>-'3r3sPo2iܸ΢HuFa${˕dz_AVޕ,nggO41}DlY%J$%O+1u-*hE;H^)b*t%1c d[^7x56磙5,צN}{4|C-Rh\6-@.>RRkY1Xe?SpXg[R>ךYXFȥ3kh-u\%m^fx6Mi0RПW m$էʔ=zTe?N{[aNGT/N }uH+ r nO{(nJkء31^ (&&z FM[R=N9&)aJGYu~k~}?~k?x-kړ|m:+N彡/cd7lyog`)C-?ʢ.,:2-?nӮг%K.9͌ڪO_ k_um8j,PNx]. ;x4v-ઢ= v9:)ְSdfp:?_yz}O x+KsǗelMvOgnvD*(?K=|k3?Xg]S\ՠ/G{9[/%)]ޞE]ZxoǕnTvg3qv ST587:-צI6٫ˀ *wRƗ$쐁I?ȥۏ|unl`lN.,`WЩԍ4u_ PlUEįt>m oϓ3"Ϯ hwcz;J֢~]fcrqq ~819ZcduOb3_r[D\W y]<ϤWgcӌ$Z^6G#Vjr_C 0۽A f׃!U 4uaWKŨ7&[#\0őI9#%[ᡈw|J1Bi*o*"=EFGe{*Rn 6̧G8g:&:3Lvh%/-/+HUàcggm+d{sڤRifEcgo?]6Mb V-@o˙SZA3rF7+1[J-TeʳM΂u8ձB^LNGf^M<@L Up[*Io2&MȤөhRع8kϻq'\ \2/z~Fq"^K))T<ܮ>lh3ȗyVz`S%ۂ^@?>)Ј.y^[v'44OVakY?w9p'@yV#`Ur8{?OmS˯ڦj|c}?!$@R>bXq:r4o߼ٻ+Ѕ;-:Kcy:#BcV_k :9b}a>Ҳ5Kz/ӹ ~l9CĶd)e>p/3C- SQؕױlmk2 ǝՍ~f"1aɀ!麑׹Un Nh5`P{+uh-75p! (s.`eP+/2^ԷS u5E;?O6%i kT+i1ovJP!D=p~gqox1`v!z]@~]u ~6%ȋgڏzM+jF; ,N>@$zA21ֿaʉïU!5{75-ΓXoFd OiF\jjn Pqǧ-%78[WS]J@45,PE!u܉I+L>N)HxeVe,^A9τZt4{vlID)U9D`m!b=S nAnuaC~5Uh lt67Yc_9Qsvϫ1賌kxU(_by77pYliehW,]F<'{meko}, cq= 'NLL]/B4QܷwgkDJܞ zSW%PJy9˦SE3YE'aW2hW|@ BxzD~I5! ܄:=̳j]#M36-rEuLv[&|6pj: 4^5-1‡qE֡%>е 6H痔Xmu=2= Qힿ[n=JmL-S?~j鷗AΖ(ȈSq>6HcARy`Xª>HqM^Eܷ"W _IE{ՔFU;(_9K1~l맄֣Q6VIټJ#ؤ{wu5"Knf-ݼ߼T֫!vR @9 -W/W;sę&Cy?[j?o[>_pk2J'K]nW/1[MTQ1AG^vJЪn|}/H G7$u?פoB=-Z2x&aLп'.U3'Ӳkވc2 GF)fO=&21/=Q_4皡iS鯶#i`+a{74kEr~2c=H?qbrB}3=fa֠w_?|n#{ߕq/2qYX>.|YO"eiM6vi#^2jt7,6ӑ<r_FC^¼nVw45XPU^f\p%#UΏ%kx%w" }].ݴPpOWjh;f%4c7|qzmm|ԘFD(WIц%#꿓un}ؕLJ|D'٧=-(pp7`4W^Z[3锐]0Nln&*D|Mڇߺ\N7ζnIEE̢u*:7wQozċFآR&f&q~ҨǕossAtmy0š{}KBFSvkck!~:ߧmmfw zkQ4 [Prx~#Jk2nFv?FQNmsoH7Q^7S@Їri{:(3e,_aJ|ζMӘ:&f5[}#9rxǻ]z'YL%'Fj Di1jovu[,<ǃeɗ&[Y 5tL[,v{d-Ew-z_C1<0NCXxY8SVTU[]^[5 ~WS{僁 "c凥i@oj|-cݰ^8w1m&<MkHROιI]&7 .xjC0.耺Akyw_g:Z5o޽%5ƭXIlVA"uɢ/g֤E!Bk+ rD4ֶUT>Hnx_ە=$胏##{G.!3wu.7:WDq m#VZz"s*ӣ(AJe)=kލʕ-UK/F$MCgfmNuw46ո]ȪgM7syψZb9ztE\s N{-0}x*p?,]ǃUi֝5fb]5MuN>6x"C$rotoT=3Ev^^VCP-)rVz< vV_-GVƴRYtwm$6zlMlYu.-ɯm'y1rX2ϢqkdrcS:Nc-M-fd=Lס=GIgzj9LbEhb&l5"ĄJi1NZEȩه] C&iqI*D~[XTH>J޸El2oNd)r{I>flv\t:R;{.;ߟsxM&Twyq&rGX{ϛcA;?> -C(](2RsFRAU\(\A|h^!C%- jL* ݼvd/dJK ]ٿ'y7{ߺ즪`vs\~y08K ,.܀Qw@m _4/]zkZ ^ v9 *O7F[9>q*$E}in4ja]@[uNy=>w2] ]yksz\;?փcAG%xzE.-(~l18>oWuU|IN8e s,v+Swi_־N@_Zx7jnEo X$Xj(CWl󌘽^/R%I59^ ֋]2e|ܨ\U~T/DzȺgﻙ'cnc6kTܿMpԚ'S#xUT/mPҰO2،;xc~qJNLei5K\\"y,b=-^^jowxV]joap~KԤnaV4T/.]$ZUmj*vpјޓNe%=`]HW= ac/B{ܥhʵf+ L ZdP5a 05)P8^}g׬K/ўdqѢ͈&lwp&\-6~ǕY ڳsQ?e=~p;Cd=tk,p wZ+..~օzI=4#7I' ݃=t;K`Ŝ_&mʷ/wlQrZxG6+5wm+IupehdFDzp3jwa^G\K1Gq9 RCsn s6O`'I߷P('#dd0.m'kF ]:HxJJKfx32[?IYcut-I\r])tr_Ԩ4X7w8?X/_>n؇[h&ݺt*WtӁMucߣoqل=U3GM5fe>~x%c0:s+yv챣BK=ˊnb,jLrdҥ끉'm_^U .^Ţ >0u%nV w&M:u^k+w *WPo,[k]7E:؊߉tͬa7ָ2)n^ޖX.o/6ϻXe. t}c鸷wŮ8 `9mZm1yӻj/j#"T܎2R֙ؕƴNsS J\vs[d3O{LfcזA;Ok|iusNTUu~5E:ֽb|'iM5W鷢;mG M}/֯#BH'ф(/핟~v X x`}-n\4NN\0ϴ(i u=9vi7x Ӟ*sՍ<= FU ˦3g=)7BFɟoW%4hKζ L೒Fۯ^p Tt= G}ԥ\F=M?J%da5܌o2vC9#*~@j5vUmHyAG ptPB~voǢdwe |>VUavŲem]B?"ٞ 4 ctU0e~wCVֽmGT鍢N&f 脟,kۚO2?f&Ũԫh5ޖW';fvrua(, i$4:UKfepPJ6|i~}mfeEa7QY(6Fڑ?ؒHY0S|{xs- =`Y?'g9e噏ȋW]@N -0 ʪd1Wvm*7o{+/}Kmf#//Cp>Y8d)˷MoL,5hfym0ul>Wz/I7B1* /*9]p3Bn-mqͺ̓+/k,e;nV]co%$^`0_6ap.陾&4%0g`_. Cl*`9}4uzɳ5 j+aXgM~UifvNjؗh(flxJ0]!;5Hjߓ9y~K R;9f4jO7QpOVN}KI(L ѡ 'l ɾlVJSa`w^IrZO[s7&A]5Pix]xwOa7I ˡ57M E>~I/Sg+>Oo6˽򵲐껫r%B+LSd;iN7+3f8S_~+*m| >;bA~2LR̵>3|v). bub}I?l<$A?HK %>²c|KGo2zllh~gtnLNi3^g>~/".#&wWrp;X)<[ zzUbm{;)=:^)C̳,Du\!k(uj}wQyּZ?z>\'dʬNnTp Yݞ\1'T?ncgU6[ GP3{P]\K&QDh`ΦJTx^'Ʈ;)/47"b*J$GS &ŻM4`Jv 6 e|īC!kk V10ue=~*#) "vi' VW*/Al^+@#o_JװUDr$|9okJT10aw9+L#]}ͽ5ޙ.j9:#ȌZw=>,7c˖ݸw91:%h_xxZVlԇaj<_Af}ߢWRLOgsn TXۀKu\"lb4[ o#<)[Rr kVz"]~!*+)@owNP7U\.2!j UNovDVν{uZ0񩨫MPcUu zvwg&^%duVXz|7$uFt'VCo#um ![cQ{i6 APaڑ'XN6[ 蘟BiNVvo-OϬHJp +젊ponOMTW+wGB8>oͪ/NP~ìRWK5+?S+Gkq "j ŕ#_ n6#τyVXXO'D>1 6X,=i>W8*mY߉ ՞Gq1bd]/lǮK}`.CD5{z@>SMDa3iu>LZ썜;nJz )\#2?ZÏO?2a<9?n~4Ws=o@٩͸ό{um!3o&QRm~XAT d2#EiGU_xio%*W¯TBI/zCpvh*{VŰ/dħd!x\Zv_a.c,_"h8՟%]'K8:VԚ燋*v܅o~ne)9ۢ:/?Fؒ![1#[C```p6fL0kpO2i1O|K#{"[97lv%qxk*:6. {8M9⌾}Y U7vg*_F\vx_VDY2Q{;tWs,O}qv4.)z;WӴLѾ;~櫯 ҸHM<9۟im4Y]r8;nY]·.%:bm!l#\Q“3E y^R^L4*a}V /9` 0eX;1HA D:$XßoehM臥,O kVI 䍼/nՁKn NSSVn`4o@هyT~9F)s҄d Oݏ-Jz[VEv?fs.!CpKiIP%z>;;cj0^]Й  -1V:cLyzU 9uv۽ꨏBePPq;o=ϛ@G2LֿxrT1ގm{*)?rVǻnQ2'-^<_f߿'dO(+h//J^[vo9"7x'>'ީԁ(:}(_B&CJ%4RѠd z9N{<MرRnN9n7h]jЕs^qyZӌ<$:>’G Qn;\Hv0OΠwuMBGǯ3-V<ѭrZK&Vzo֫ھB*Uxo8N)\ʢ;":~fTGcû9mS!}B A~q{>.xͿ<-XA9Q}٬ENBaV׼>biՎ-GM >D/ଳXըPImel~e]HR;]y#^Q:M؁Yt'SbɈ(kX^eSS.< #d=nv\/v NMS̀G_/L߻8;oN]-eGCd0C({ opÅ8{2אΤԌy|aFVӐٶ$5& iƣ4MP$}`*).}Ym~ɿ4;/Q8wurzL ,UfTQ 9An;@21vgj'!(Z;]oS_Ϳ6;W?"zbt9 yrS;R>)9#tY]+6_.7RXprA^K2'`zXCp] a=g0`\N^?td̈9aY5T!nLUmW/{kGQk~.X6 Βe t&-3KfG`nW,T"~9̖T.1JrfV_ePB= H "3MAu)Q ͥ=dgjXc@]ɝ ;6gճ&0:?̨f@4J|.k|ݔ˿OC޸Ha,=M׹b|1hEQ\֗iIܰl[uӍǦ-;~n:=:FA}U5nvN%4+>Q5qs -􎋂FW9}2+cHXjƙ!tk0R I{yi(bQ9^ Rj}ɚ{oG+KV41gMEk9Upͷ*ˉ[fO?ԑ;hʬcy{'2_'c}jkbhr*o.W:%߆\oO);B;ȑ2hl9fEQeN2!-Sxƚ( 6ʓD̸oiuz۟\g>1r=z̕^k%<Z'To7RE_ zjϨaH()}?A"Kd9?-YmC8k+ХK╞jgoi"Z)8L+(\tioj}&SESub;};>&Reгsb7.ՕM[n :ѬV:=]i3Ufeue}ԚRJ]f$^~f!)=V|rB2鶎֞@ЫxtF6|hY~MBM.x|]605Ur>H{>f>go{}U#!n$7oMtf ;4'jad!w3^:^+ ?;\Sj7SF$SFlӉK$maRN`Rp}*|<bqFw['"-{g'1 j}HJpNJ0A8_N1.|;|f$0(Nٵő կZTՙTmŏ`^~gHx/:24R<7HO LLG_xPu TJX:s|5_Wy|9L_Z:F0؍=} ۣz" 芦 I)ȕƫ[`bѬ:|oL>ÜsUq+I2C6q,W=g`/k*wejnԶ$?~$7'+Zvywԁ;X@a%.QD, @ J 3Xݎ)~^^CzmJ&Z*{/ >n,љ$9Wb7bRnKF5|!h`y{UԾy;^v+:oB`ݵ@3\^dem*O2Xrzkv,p8fZd)J[0y xSDvln7 : h1ZG\ o1#uAA!etHwln[jxvP:Z,uy4mx44?ޞtG`X/2l$`џJC'dU~N-{56C&#|J ppiӟ y۝-ғf 1K!wS_{Sy!WRW!]6AQz^L} ꉷ+1;hw]d"Y}ލ zQ=dzŒw%Ѱgo+!ab7 [7c̞Ew&G' 3wQyNA\aQjr- 8&vJWXG3; h2[7P.sq6[b|ll5&X::;!Sq׻yg_N5VLlܕE/c4>+Aj# 5=dmG7@hHu߭5eGjt2EnV),CݲOo7`ڲ-砎l6QaA&LcbʨkޣV+4Jw_֮6Ye~]C\c{ޏI:+f4]~iMfO(wW.O:-XԶ>yĐw%y=xRa},WEQ MWF!L>1N `B8\O7G^p$#Jgh;FOh2Nv@x kA vݫ֬8C!=ݝ6.~:߻,/>7c8@GO'<7p]oʆ/k -quN_ݾ)@*)hm8efU"ɳ3@^]qH 7aPZ#:"^]և 6>xv(?wߤ{`AkBg~:1]s(h*L{媻l[ߣ"zߛ#9i_Ήfs:W|s3:rxUn[ْB)D}|+ʥ%6zV]rhӟ<;fۼLꙬ.=YuY{3.> !23lvj㼏ȅ1¢+YtZgn>fY>&Y= mH{%07c5aZR'Px^%+sЯ׼%yuw:f#iacaVn!?5dyH$ʲ2n?4Q 4:X-+:y:\o^[MO8F5ϯ3w;f[ |m b?%7k#F2f/W;tփ!W'9 DM߃*QP7}]_7ݑOO*,fP 3'%Ag3Z=A hOy_?= cb'xqj?;}^Y90Wh2|NҸ1y\Eesq{Ƈ?{p*ٴ7sv!;[~}UF4j3Ӌu\g7cXɷc_Cw5ۦ8jxq {J/^K>}1۶Q7ҘV('/$Qn2/L@HrY~u"tQ ?DF۵clwRAĺwļHOj|\cgߌ#%IA&Y1C`ݿ~ PɃYuģ_^}2y_KS챾A xqdWh29mGn1m> ]UչkhPV %Kހrz9X!4lfuw5O$4K#I%/fΝZLR㭚v> ?I١Jv& {c4>_8t]W@/=H?-iO~J{nM'zg{NN,'{wQ3॒H%?p/Hv-4NVI)Qy=~T` }R=>=1+T_GJPs\FxIɦŘ冂=c܋\i4YNG`kCMZbje8;zd:\.Fwwg.-jPp7.XXm}1c] z;F;(O<4Iʔgk~xP{KI=v__6ióDъl >;r/WY7Pv-5\ȣeHEZp̯h+-c#V(f˗b.v)-vV(t;qKbntׄzOi7[9QIA lԨSw94CB Ƌ$о>F- XdȻ =۠=r`Xx:Ay| ?p,Ngc kZ΄٭mo(l9}Rz׬[u  p*,ȗW?X׀s~ov;vٳ/2ZF[>d䐻c "CneoPR| ]w7׿ML:Jh'̾ R++v}\|t ;؝?nƓ7N_g}/;m*kݳ`ڀ?~I/bn=˼Fd,]MƔi뾗J3r0mlw+M!Ĩ14?"j7'iD;eY/Z89,t P_9+wӥ#,w"=i1@Twҏ*JM>,{cibobD:M}+W:8yq=-V7aO\|E_ Xn,ڈ#` A v'wjz$,U{g<.=o/zLU5Ap Ͽ#(BǥܠZ9Xt ; 4@h0Z*&< dߣdiHڡbo\ J[<9ZG ja<&k-Yf^1E>N`aa6n^"Pt#.af^$n0JVdۮԼ'SjW#6'O~rI"#G7/_iu^cH|>4rkmsR5yZ?$,m=rnzx>Ctef?ru\OZbR'b^Ө{+0.bV`˚%Md.euhh%&qA ubJ<]06mVsE= J1v',ZhkA}F=g_\zh9Z1c9X}igA/G+2qiu2uZ/}ükgŗ5-֧opW5 `8Qq$|D4719̛c)w#w<37Ȍ^|1^rxωE_T$;M-hrls-(&r =BٍQ%3sZ;dɹ#d;Ziq7-=Sǎ7T_|m@7McRj#^ʞRanOȋ9N~gg$#Ȏⵥ*M8s?MS2NU^=("cd9YEc]7.ӧ4B7_wHZ!ܙ9+ȥ.C ~ Gg#"γ,6;;-=k~/^/UmAٌZ&hM͹fz1[ֻq@;Q%Mu)ipF}K[gJylmIGՌf,Ht*-c7~S\"do04xd2ΗINMxIV\_J5`ļYL`p aԱ:R3=ª6RL}kM͝A_k}9j!b>;?2sARGʝı!}NaW G5f +jcL kGbrw3 Ml{ c=OiI8;Jg[j=Ur2ZӻY ^Ò/eE<\L͏v^UK-C*6țG*\Ƽ7m*D} oζg= ciոo?R0 "qD!hOe3O HȔ^\GHҋۺ~ kYtHa'Mj12x#r9oNg`fa18bǮ33̰3:n:opE!0뉰b, =F5(=Ϡ"PݔP Ntlq̥C2]i1>7S\{7gzw!e]"GsΡ=i}abQv+}RչfW*WP;Xμ!pooKS^^~D:~ kߏag$*MS s% \j;Fvٸ‰1紐}J$ǶJoJHxF1<\KȡoE'|3^+"*e_K'b%#׻y/v&NS[έW\/D0Ztێ?NeU)!5R8|GdϮ1ګl9vyX~Mt^_>]]md/Fb^0\7jHpz^  jݗ B#M֍QrX_B /$vZʉ܉rГ |XZκw(X_w`0_8נʥ~yv'F@K vIsWK?KsxARy<}ė8:=$/rsk ڽ^\׵/Y<~]yM7e΋Ѩɍ~&*=*pc |r.scۏМG95ݛd흏|X+\]S#;Hf>g/|U ݣn4.iQL0\9eLX^ٶ~A?DN,*.%?#z+Uɡ‹ ~c &O[rTY=X~8 i='ͷR.E bwyl+ʄWSCsrTOzҹCy>YŊA -(<4jǏ1޻_vVӧ未**dct/ |آ>i^j#3nuѝ:Mv4sgukXT1~0hϫ_p~Wi"oג-!JM>.V1 *0 mkE&X$ )M+};EfP󢼱|N?,~n7:0Q1??Šr(wJ<w_Wsvݧi5˵GMkևwDY!Uĵ?`cIabp}gv:6ZT}>:<{jw_l ;@չKqIн,`J{C703@:h 5ѧ퓽Dp U{})ū,}est?:O_{@ߛl@afH¯B+vJTp#s*Sj-7j6d܅`GĴOT?8Ѭ3\Q]pi6*oJ,(O"/|yFolu]ՙURsr0 F bN:^M,盙zmXwW{! ;EݕvT?X7?: Nks @ph;ՆSEy蕟N`\jTʨCBqdVS"e\`4UtyҸ[>uwdVT5T,xX[˝M|tN^6]j@qRQC<"#sѾߗO}`F(Lmc@4jay<KG<ܧ/G9G+tudy\CC7 =k@A3 r}ڮv .);z ȴw0=z z̶y+? רuݍ;σ.c6 q8}+t^|=AiT÷=\Vnt)SӍqn@;5>8݊bGDd |Af󩲶JA$9Akrz\"_NuXe1snnmTm EK`}P@fD]&Nk/lj(_hQbkAٸ.wYMٸ*c5u} #JN:nў S.Z'6&cVS~Gwfr"]mIFH2-=\}17n#J4)ɮ:`"VB=M⌊wvIrR;lXkQLtxكppk(:dWT3[6鞲 Mfw*IR+n<ӫOߵ[Fx?cD^vʮiuNi5Qڲ/G"+L&SU3üSfw}\}Ι9!^u`?Uq.K7nrbf7TGX/S=u.wJw.͹PPh浚D O_>(މ7Espx8Նp?"r6G\d<_~UnY{oj|[N}\F\Ⱦp tYǽP P}8 ).~ۋ1w/Սֿm6qb"M{Y|Z)@k*EKK;} LM)d6x=-l.<}hG8 V3ݟrp|E<"F#L)^wR{(k̷|A3xN`F<҃MN+jt-I]?Tiᙟ0kt :9ց<+51Sy=rqP?kᛲ6ݘ$힢uJ=5ooø}i{MF ^w6T55yNl>Gf<~ MĬ'N.?쐖1tu5&TǞg꯵pkbLv`fvo=u=T9 Wq^p7>{6z]Xdf>܈|9 nF_aɽN'R pmǮ4>?hNۻt^|_Gw'm;};ooa5|eU<fuJ<F͙Cyius^%3-zl}A*)ARg-m)b֗Iկh7%-)Ebweߐ֪*г;޻1\0ꡎc/7݌>A$׳#7}k==N}gTG0uxx求+RMPh_m߾ڧpN6o1=eY裡{F+VzE_ ~vN AB(chhk5>+)J 3_ W/@免T?v=ҞaҼae@tG5eGņDCѺb*5ԲzxA3OoyI;y|I6K5xn,[7d$p8ʀRvvony %Ñ3 ܒ#7:wOoRJJՑgy]'$}@wF!! H*1~r42"[{~?ވl Y}f[$vitZt4ARB(8~ڷ=?"M: +ar9oFpqf(󷷾. +jPb|fĞNJG.2v^o5>ޏdtrޫIÿdx.џ P>s[jUT(`gPFq{3p4ށ"eG7֗ے;zLx=t-} ~ n[n|"%4={z))on9A4:{<|c*9{l6{g n4WmqB]A<CG 6pn~Ρ븜}V_oXx:\@#Vt\*rntz\kNzʁvwZsiƈ=;C}_΀a:Kn 48 y"/dY]=Z,oVeYMY^A~Kb9˷nEo`qRjus~JE9~3&L:)p@Nr~aǛQ'Wu'Z̎Zݕ]؁̇;@_= Dٺ UTd0oʔh V[0T9[drV5UG(d:okRz&. !h&}ߛƵڕXzŊַwZM;]ʊ⛯NkC'or9U&|+1)^#ΰ҆OnxFn4T[]lSҷiIpJPlpv{U_^GBsg~ʍ~ժޖbuoL- ~w{*:t؀?Ǯ @ .p=9ƾ fwjI C.uvFу> x߭泳iNQ"ON~}κb>nWぞa^5u&Da+Er6z :4YƊy!rk@D 9(2wE-z%Xے:ЏKӋ}=h{5[5LՅ`"-οD5riJm@Cb@Z&|o~u]]xoPid ul"ll%Tk)]\2ؤnuIuc8oN qrtxrgߚFdO5w9ps̝f0"!1.o{c.mn&/wGE+Q3W(զ#fKBe\US~;&/8g/V/G`mvRE,AY-&yO-0~`8?L_&bcCa[:`ru,i:rbv2pð){#wżSg ͹C̩Ss ,UHl"' kQTpNnЦ#>_EZuٞSO_䳌 p?Pv.}w45hf gRm vfI$!={3D0d:9 cAE't4H2S.UFZ;k߭kɭ3g?*2f?$_ҡY=ht[UBתv5vL|~?H-evHoh9T%oۢB@mViW-&L̲)=?ˍ~*Rk%+7 p*'}P7vUs{ /a5 F6:l9gI„sQP4+PVU_7ߴj|n h=:쮤ν~UwևOM\Dۧ leTe Si06W::yB+nN垆ܝ5~Y$j*  X`t?5.):udGMˌ$u-[l9H8We]z+="mCEK nK`+o1^Aq-K)Kr!>#WώBܱ&Nik-a!iˆv^0=]!,s15&^(>E[gD`^½ÁL.2BxA2k}M>fXCK铆+cj%l3Fh SSAs47n:zJf2ʗʃz+] #?Eiyɉ~}«!X17jNƌLuڌOzoҶj^-;{ FhWv^td1{{  D-XtC^> beS˜$_wctS!işm A;:k)~:Mv(4o*8jѬd:ԃB?(dPrMeAxk //Zh_P-2>:=ӜiI;7)kmt}}m:\JW2 dJQng o h1޳ld4.wS~ЏXQs=Pf 4t{يT+?yjzpIeҹ54c-ꞹnKh$,tfxtp̆^(5YR"%*KȚۏ/;(˰yk݁`@PЖ]wk~?!Wc2љF>MK2^+pBjl\qT*[l1Xȧ9+Iq"e@,,9C7=ks?S> ir[lu١I뵛3oU.ɫZm Z*86(K/U804i]X~һszE\6b>~69x{3~َi^HptrYZNfN صp0[2vEYFҞ1豉]Q_q~!G[kUxZvNSfM:GA/GI^/XiW>v98F[N*~~`!wuXs6o񆆕n2$~cljM:C)M Ÿf5lőYd;-j>O!>Բ K̻DZa\_D*y֨N}d*MVg׵v ? ~,Myz_ǜ^mKќ/ s/ R}tg*5 gąڵ)_Z=+IlC^?vᣃ+C Q">oWa.j c&c2 ּ1w\P'.\Z@p<՜+,_[ GX]}rziAV:O#JTmo{ݻXfrch2¿u lfA^1 ʸ+ |z:$夊d_U lN~U=njg)mI1/$q.l)TrՌ^tsYL~JJ84~'Ԗϊ_N;lѤ謟qQ }QrVl$6;mC?|zKFt`u^r'ɀ(Hi@᣷7.ac8ElDAz5ږsk~}ؘ*)W LYw2c >cL1[Ne|Lv|7+~-~,\^QS'Cf'޵}ecHV5I”'}wBG@:@)VW=ypnGֻ~%?uDtjQӸk,Xkt#,ܟ) }=e3`?z8uZVl( 򩛮}w?ZfKXetX3! \۳j4sp+T,ӽ^+?٬5 IYxQH} 2 N}߼;5lI*,kA=;`P]/cbupy]BX9[|fw][zc|fэwC<7Qru!P6( o6đV`_Sz }YFqr-M}p; pܕFVͩA*Ȫ+6m4=4el+aŘ!!7MaiԾls"6rI.ja!uyc,qdHI3o ̗Ը=UE]gfN3n km&9_,-m@\&Jp2P0<9QJ͂*\yءt~[cC2M"þh>~˅mQ~{Ru0dy_6sX;K뀫C1O1;}&W׽Ϙgƹ2*}~qq莤ۀanɄMkdF1S;AB.h|>&%{ >ʎ׏ʪ6)|]]o١xc>jǣז*v2x PCØN2IVoAs(OCUsݝ[ӗֵ[vlCͽ[tʤЃ:P|zȯ9ƬK EAQ·MUu,oWj1)/P_γocO6E{WH{c)gtKh])j^S3ί/|BI֚kUZeG1ڂD,1zl&۶Wg}r&#,+Uk$WCAU0GwXMjz03Jv8mKI!r8W }騛}YN6ߌ(2m # `USW#fpvw}uQrI''9K":i_?.G O~oẑ?6|-9nt?ڰ%\.Hk5:>˟kCrhU+r}e2snOG`.oſݕGTmU 6Z/U8v2 ct׫v/M/foO~غ,!oHɶ"8a]Z+xlqQlc>T$>/`,6|R֯^HnR㖡mcy,uVs8 k<⚗%N f]px)̾x<HVlӠ/{WW8mldE"eͽ]88ggm2vcӃ4n%:P[ur,.d aY^ݥͼnp&. _ rsS!X| ~GI+ N'G4g R.rA1〹<ضC/c\+Ot8q﷦+CclJlF::fVfU u^%EGskڳ|VƼe >~jFĻ4~SGhS(cw|;(:y?Rs_鴰Q_Kbr6m?~-\gï?.!|ɞ\j[CiQ.Dxb@c_#/-4GjQ_;YwTM/ŃA;˙ݹK1'37[w !)8p3 NN .ǣ؎|3J#16cɣ" -EkTMJj1UX  tp8&WzuV8r5SҋK7PK SLj+8T sQkN'/),-BdG7G=RuF@ L\ǘ 11l4+z UjwsEk*>:ckOuOG*˽K9R!`*awYiLksɤ2Xdz+fe`q*HٖQFʏv :/ Aެ

ߟuE'Pl?npI\WK87@ޞ;{1o#*&\%&}BYSpGP/yE#[^8NavJ\)8cG#R/Cpڕ`td>i<"PQ}231JVlm}>,ǀ{oTLb]E-ӹez>;߳W?-E.$iAOm>?Rx.y^ajg{,Vs5I.y8An[zڣ+1|oFص0 x ~܊+"5V F\ȉ!յMR?U=\7\ڦ{+E\NiUϬ8Z)QЉnbF(xl{'[i_Nlg|ZfI_)r1>xo{C!ܟ^7w=Z1zi=2MmSǴ,aZ~ t &P>I"=EHBhA?ܜ۾s|ll'Ԙ]Br@⫸͓3rx%0iU Z0G#z K˰Bɽ}%{/--:*m2v++ޣ*`"Skmub_Rnk/eʏ ]S-dy⩨5׉f\xp^wb\$@YRz'v`b4梶\U~M@57?%gb'm=k{l@Pn4_^ܙfHZL%ԗq\-紽P@i-F"o6,0 tGKR \W:8QJ{㹗xP@ JxJ*|V>Vfzp=A{Ii\lFgtyƯmemQ]'ط7ݒm "UXW{7<xj^?xg y݊V?X^5[ϴ,uj3Ah:̓-@{8;y(m T"i*R%?h|#Q Tigo6.߲5n 7M3nLn~a]Vf7Ѵ3=E[9C.u`V0ף% c5Rh2ݔaz9D =vDn7`ՠ]x8r-&Du8r.vWa[ixh/PEXdЙ:V4>:UGʓΩ m$00/ǒ$C9YnDx|T-͵C/DQv(w_aNk~,sԎTvfdI!݈}%0U<έmq=kILzmjZ"Gr[V-iT)1?֥ݝF Kp>dG @ h]Ww4q`Lcݸ9Уd}<^|tzd-kgxK-aZkx#SMԅi]q.^W[8Q|=~6G.b+kTzjg˵ 9LyemxLwtZ%cXpV˫Ҽq8uhOOE_N~dA~^nvj;ً:MvM IWSdׂWqtrd?e+Ǡ\5a2]1/Η֔}#h*WzNBYЁ{ ~R[5&?SX+~ĵR`w;u>U(%f_p U!By?ҕ90{Ӭ{0h%P+<^ `vfxyha9oWҼ5֝M)6^ZK&RCq;8j_kr6,D*5< ->fٜf6nzu~<ٴ-.k~kq"V}fpaݏJ)Cc_^ۀa%6wI&D4xN'%\6cmؼ`ǗK$*zgZ V7%@N>Iy)P'Ce0oܦR \ҾV=m;#_>GQmZzr2vCy495W'e_hpiA髭~,b@S(-Yݷ>]% p"t}tw7k<*sdAu̵Oܓ77a’tF"U@䖵!ަm$iWVyޟBٽ;qbE0ju<2.kSH72չzf7H E3M;z2Y y9;?vǨ6[cC{S;M_`E*zS/o1:OX<8BVP_PpGu3vx}G{}?rə,;Ϗ]N*SH5gP[Aόwu)2Fe:X;RWQD\ "$MN} =I>-T}b⸭ѩOڴFO3^"Eo9xdq;DlNdnCn~q?AA%"}- }fkE{CXؓ.!rc?l\,4 Ǹ չh;ͥ[]~EfojbÍ\ߪI+"u( о Иu.`Ghz/%K`^ctnߺ*Jt΍&NO\V@nۨ4H>g$k+M50h`lf0ovnTo}@I^=VyϮ'&%IoP\Cw:Yg%1h@3~38$?0'yXk = o@xy2,xfȚEw_t N܄{4MVT L'+vi|*5'jNϚz3YmaULN^1g. Ln.b~^~eoO$m+5 ΨÚƋfO~ѱ ȣ͎dZ6RN^i<*zpNHXL"kBJFpcvU(ف>iE%W7[ĥ)syoU-۩^ŠrWf|XѡMf8d ;j\.xs؃cej]gi5|Iͼ=؜2 siP>oWgKAzYJЊq86nCO/eͳ#X逳U4/Wk.؈kJ5tzކN?{@a Fo-ժ`T'khEAP%݄0%hטV'Una}* VGS<oRky"YiV?p`$Gn} oqWhݹZd_ipGopx[Qs Us>q{{~'(D\U9KZkLVط>W F9F˶"hܟ*MQٟZs=[яJkgB3d|k_*_?c#m_~N΄٨57hyz1х K73j;;Y#b)1AnUꋠ;hf>}vY`VuJSyupsZR]uxz`-[MQՠwܘ6Crخ-n?;k,LBF&7p.3)!%) V;!䴾PGk_n8Y ~] V˙;RTYOCQ >d9zse XchN2\yHXwFWwATȪ ,и:v½f6BD=)h(Rq Ó7~ ńu?0՘&b/##AfT^+uF?9ri$ZGE~$a{M>d=NRAZ9?pu%ȅҬZY@$tjCZ%n^A}6mR]OfS%طrMg}qnbz<y팫͘dQٳņ]Jreܼmm57YSZc.7{0l'B>Wͮ .(=F>ʄ2=hiivnq派`cr3&dæl޾ڼ)Fo0oK pc.^=QޤC 7ۑI Mr;fݚj [KV} /sdJKcռR^Erxfx o~7rCzM=g2-;7ɋiB/k"tܸzy*b1+߼',;:pdsVe/SZ63PEG1ו0"D poٳ'RaHFO249]*n wѨ#5wzzk S2gW[1|N2٦z4UʂV<좑$^yKщXb~@Ұ!'Ƨ>{̯xcdf`&OH3jնd>w ߧ4a=N^MYc ~ϸxk>˵]殶+/p$Gݤ!NNY`*%|91Yr cl~(̀G:s&?e{Y>dZfsJ |9z2{/{҆lUJ0@&M WEf) REJ+kkz\vȹ$)y]i5iLrd5My{n9ez{wؗc!x/$?ݙ6gAm[NqZɓ\WX铣bͩ_WHPo '䮾[to#V,{ɽ vt́W8\,^R -8崫ka2mܮ<7]9ԺVex?H+&4׼sGN3)u{Uˋ85x&1Jً:aGy_.kx6ol53uU53bjovGN~)'`oRnu7NiR܁J5[-ozDm ;7olgL}Sa2 k껈rӷd ]=BJi?wtvy܅b#EajvvWrh]G8 oјE`{?fbӸ~y=utoac9)ʴOUՕ+~.W}:&h5*ֽ? JvDM;֙w` :7 ;cɕgKEv;_𶩞/OEDosu] /S 8vcVT=6ծE}ImQٳv5I z?f`Wa/RH'u錖:)BlPd]qvD,~cZ.tc{q%OUl?^YГ{^S}ML6?RlZ-'@/Q{+mwb"sT*Woe?޹Pe\IJ={ ǯ+=.oYP]OWt;:ːZjZغ<49v3}YCa.wMg3Ugj ] 8a`wA|HO7qS5Wj!#~ȃ)`ݭXT~,*ya} +[ʀU U=w vn-=^%cl(E=7iR7uӫ1-۽0yP RCї!PC%Xq"yEK-erk+y Wo -89љ?Jzd;lutzrN `F Wbݲ7q.,0BF!]L7RU.=hEvc##+>\W^+.C~,^8~Z;,+yL|ɰG~,4nؠfl4̵b7BhG _V';̭6 ZN0.\*/Su*WR.k^;RPdt@%N<ʞllIφ,C.l+=});PyX mCǵzV0Bt"0y*G?Sl:Ҍ_/r/{-vN7;qj:Dh IU/t(8D3%Rrw~MҖO5@gVr: )oe+R1y&)Z,EUzQ&){7.l41޴>"ƊF :Wlu_VvJ!7q1dvqYvgC`l-F !OqƷ+գơ=3 {- H޽ߣî] >K|#؆QV?RhqVvb=pBe50yS lV\~n&{B4ͧ_t ħm׆*lVu(J?XsZGfK{͚t[>@^ʮJvNSl\'!~Hoʺy}vr}TGSl=H*@ʙ4H["rO)WX-c I.65y w;Pb?oB\m?CC=Vzp4(L\drrjϙl#Eʩp0Zk[ȻO:ڋ5Rg8f-pXejq6Vۋ&,͝3wNt>oR*ՖP,3CJ," )+&v#JU-m{ѶYMm׈$ǭc1f4鰣 CClWms}][e8wvw-540ڎ5ҿY5 њmU)8Sթȗ߹Ed@=ɵpUR,e,W nz{+N߰9bZ͵BJ=pb)G-ݯ3].bcQo~`t$< a1-v|/n_g=}b x>LpuaVIjJ``d)qo>d,4qxۜn>+娓ӋBv~HraI]K RW67 lكQB5S?paXU~ta@. gxn+- m8#gҖr8lOc93K,ߧ"] @)a_{FЅ'.nw;Yhqu$rߴ)#Ze=%n.Pq8n/<Zx3z5v{.mjI,w9LURۓI$Q=6Cġ%olXU. W4cCʰxOn`X*ZV IQh>CV߮[$kQFuZF ]jw2`v׻$}oo<{b/w,#:4ֲޜۈRSnnKR=y9MbD)mR\*cqXv"aVtdnD{U渌ObZ">Z5>|^(J|YTQO]1,?)MIרּ0kamz59Lq1^ @ ygX-pWˮ_$K}EGH S(iWy« )>;QuVwsU֪K,.im9Hsi֌Kn0?޳=}?=R+}&)xFX78VJLy-'}YG.`Hj<_3s7%WrRzhcwƫF注ʉn'*-iZgFW0FY>mo6i`ՋŶ/8yer< @% q0+x.]aCwewY6Aa})ꭢڇr؂ 'ڦ\}#7qjet`cR0tkM//kp]𚥝c}Y] IT$؉;޲sm Nև ۭZTtrk̝D}Ę򙁫G@ /<Sf|<[AkVf҈[n+5hEhnE%[0rUˮ \ȁbY++& M%~]gƱ[oc7Pe2Q">JhͺC6-↽5j^ xu^zaܪP`R ޞ*ON%^=j|57W6W4)n>37.A[ݷ:8Gk" s^;X48h`-ç,ª'%'D5tyb}= >olFY_[L{_5XɎ6fttS!0BW;AŌڣGD=q&8i+}>{#܋E_enxk|n' :l}"3Pj%cXuxQj{pňLp0TPŷPO:;)ږGiRY Ӗބ `XÚ@μ|<ru0+XC.'%/M29~x8*z/l!U8$&}ޝK\Z᷆O{FN'n, B 6p9~?PفV bRPȭ>Kc7SHrܙ9sWQ ;e2tퟄY"dD[;/A2jA:nVVlG] TԎ/&InyWۼ3ow(<@1MΣ*)ާ?&0VtR9`d7i@=y`Ҙ wKs-Knc=I$8nB>>d>1*j1+,V?#7']ogt8+j)dMyk\}W="h8(M8tOis?{P!WD%nmAׯNދ]xI\Ž7x˨1lYsjoncz囐nPVOW`yAm 펽 eMmyC!bzLczvϋ|(a퓠+q#ZU:?9Bn0TbB>B_@t0Mg-M"8Ԑ>8I@ u_ؖ ^?5`?>YzւW.Z֎=)MmdND^ptAsbz?;Se4lNr-FIc}dw>v<G'5O;+= 5Ygu #_b6,.W?q0%n=1 s3BEjg$M7픲c;Z*ꅞV;@3"f뢉@a{$~ۯ8VfhciNPưA "~+ UП "V¶ -w+|8[~^J%V/k02g̍ٴ\9Ձ_ y}~s<Ϻl(ɷ˱X>D"=5ZP ̖/j#sZ%\35VN+JjiaۨL~#yжt?cBZz;B[Q4kɻJQ^[^c)DJίY@~*sn:=u/s`[fqY|˻î4 jK{XOYޯYKɰ}/z0Ht9ZwvZyAgU̯Rc:uʽ"͆j[c  Dǭ UbSSYmNr4Ԝ$T{bQեR\=~[O=sOn-mRYnm ۋ\yev ўi$I Ȟ:}yZI dNgo,I[ϳ m$hvǏxyx(`֧c 06s;OYݡ ղ|x(X7$+zp}xy㹷ihmRXWW7.߭cP\_:Su΅?prEW<8{/ɖ?rx^/ǍQQr,IIftbpzCf&+y =ɵ vp lmq7iǍy$]hRG&R+4M$ƗpU||=?mPcǡoMcC,l׷1Ǚ||$nj}vp^}KO%2)J<:Vts+ rp,Pk6a@ ~zW։5˯\4 dy覔B;v[yͱaU_K6kI=4zڽȂ+K u4YQ[č#sU{]G_pB-T h{~]pT>h}rYiAϝm|Թ LR1k/N+MiXvI[9v9y(RONKq6KhkuqvPmx%F#5ؼ.n')=Isi)uigsV>h^y|'Jð/Oʭaz _tΎC30́"sV7{FlOaDC$.RwVt):!o=FנYEcUk\H!~O=QƷclŏM ~':"P?T {`/5iUou L)^<~g_q=~*YLfrp^u;D\w5'FP驲_o(&3<53vm9 8 x0M֔r{*acs "KkߖZC/B-5LlR3y{pYdc V4]DaG+oA>xEpfբ/Ppr>:k0H 嚂RnNΤr5[(^v-![x/ײUQ+wuU|M 7)JЛEOW6?7)bdse&n{R>g-CWbW *#E(Cb ͕W[~-НRhbL]9lGs4*4qۊťƺjMVʑ~OjgX. c;6NzdOVY7r0Kr=w_ C@q)*[ؖoc! Dy>\`W}~y'~cʍya>.L\oW ׂ_XsULgaqo`L|6l~گjVˏyAҽ*3/Z;],2[^:wUG[>+L]a"xӭZ}@kK| %{ٴBo6&^m)Srһ5.sDS=0تjvk1X۝=`{t.*W4lr&x}^JCђ- ŐqFGkpPHfC:kV:(TR@'ɣ%it#|l=S[ؖo,L* XP 9 3b_4vɉfjWDe>l:ޝJ*Jq_u$̃wli8ϦѪ$K/"}Eœ(l5wO^PNS!t5p8^Pk⥦LGL`)w(q7D3o{}XA៸v|e+On5֒suy uVGOhSٟ-[4tBX>) Ůc"jw#>O4~ĝy6,2GMsWtbg[6m;V&N1K~ch>.}NeWZRmWB _g1e\{`tBnef[J.#wUɧ_OMM:lgeO>:YՁ8anNWeo[ּ{d <=x_k'5A> oPRrW;-k={,kb?|1͢y7Bc#wO~]AWG֍t :,Z9 mm)7%Eu| NXk'fL *'1* 1.}7GeOjsz&|SMIKz9RYCݻY]h9i%ѡ6euLNteӇɩL isc]p,A.jԗI~Jѓ'c '7|vAn _7[s4(&oL5ҩN"|:ƱpS*QHO#V?Se4?tnqp:|VXj~E?XG:9KWd,0o#gx/T  4>( $S. L%;K*Vɏx^D۷9m6 xώzg~~hx7jW76pWިj~i:=C[0[]uJ;΃q=gwpe0ehN%ɦuvmirJv.9%"FXرoOXW:=Lk @%l[`)~tn>ߚ:FOi_Iw>38ޫXfzI .9BiNQ9d4&@o J*6kujCiᖭR[+~s_oWG%fox {,8ӌLw2,K9B7ˏ fvɞPo.G'-,@bu=dy : On~=شEGYkKn5O_7-u:RX̜60f~OA>vw,:huPov pϣ0w0|׺AVP-g;[!t6x5x ZOy;'TD*S;^o:\Gn{7ї9Dw ?+轼hPLl|Xѽ+{wtr8BdϕQIāJNCCP~ ?Skn80^h_]Yo>44Fi\_DċQ]3֟猺&__d]ͼ3BLw叏" U@MEvɗ 5;vmdϖJ/4|{f\Z?(d,qã^-Pa~u$ME&+u^{ތq\neJt__Xr.k ,R=o6پe'і(ɴLMSwZ0iu?ڦfʹmؖzwm83~8WyhmKzͭS%^i49ՙN]"qLNVp[vwsb; N!*O[۴ݒ:T3Ե$/yV;jV,6H4_UGfp0R^~huS*2yp#^N)&1*#孧|LjssRmunve#z7Z [펹ﻝU];nAhQ$uNLiCȪo`5ټj2(א>?Gؙ^m*hݼTɵA8$]w}TzJS{wd׵<[T_*ik%_QvNWw %d9<'Qsf;6Rr>G/1.~-TrķA2D@Z1_֠d9m׃jN5q,>=lwjs;XVLw~wFxR{]^g i)rsNzB/pq{0h2erܝ&XU>/zHMZϿk)gR?v'}T!7&}^[ s*~:FW!Qo7Or-Bi;՚ׅ+| V_L(An_Zmˎ .Mϗ+6-F?շ)= IǣJ^(ZWybr,_#dG~.a׆unս \0(tFX{~rY/-%d1g괿vaIPvK8 KX9x_\:>x_j\_&H֚{՘-<s_ A6u>{:pCg9-*Va_lui+iYO}{)ߗdc"TKh,tpqb%t)iW6jDO*"5)!d$6o  Lڎ/qLMWFۛ>v+hgFՅ10Lԗ6o:ǽ]uVY4;]QS@+E?]/6JXE )OtO<*@ mQrd]K!q8k;s]L ][P xrɾTa rǸyLs/"t'R}mWMf'Wrq/5^jO:-Npa>- $r Run\GϷ`M1b~alU_<НVA*^>ۀ$mb?__7>'ҡ0z}RX9LZԄ.zap\Acs:<+ si6ܣ[D\WGWHJr&t>\HFn-tK$3ϛ_9(춎FTR |xUuZ2xY 2^L}]]7!iN^FV}F\8g4tniW~c%rHiOeV퉋0>芻zF7UyxTz-1S)9ʊzŌ4jeZ ix}Շf0ӕqDS3j&ȫ>8wY>|ϻe{_ִ~/y R0od]"֍xc2R,'TH_!< >XG4!mc ;Gat)v`ttZ5qDG:z闞L,[tϝN&QEڣm~D䶕d8#>4ˉ^;nΏˍ.ȱ\{K=̷h휭v9XU֌Q dkOsܻ>`.X'%jҷ@ `n OOr=t~x1g>V5n刷i Jm΢_MW+.EYG5oJx/'Nf1 KZH ۖ v%.>>6.wSvDjc]{]M++_yI,g"\~yhkxM֨ފ=^v>(}.zϛ 7E~uWYi~'vթt?NoOW%Cj:m )eVq3kn|gtƛj[ʛ,cxst$<a~_n|zԩ6V{d,WZsyx:ôQh^zuP&VF]"αKʋ->gWF*s|y6 rϻ:{YA;Ϥ?U3?~e}p/Ù,V{}LbD^ ljedO{fmũb"wkuOU+>W} -7@u:.0suxvLY,-m|1$7k,7Ο#>G{H ~L7KJ\v?DVy otFo00$DTѦ>_ OYhLMu{xI! ʧhw;u4߲X*5=(@yQ=,׀)6z" vE gS?zYU);+0PŦu02ao~-ܭ^5#.Xm64g_Z[`Z{im+_Ӆѧ6@0g6Mc{.߀7,7qjkb{At<\z໊_ErZ5"*rNgexEUp~qU7̹|r(~y VWzI ='~#潺c/2{-Uu?@UZ7Wvk3jTF\$D=~{þZxv>_ I.>Eݳ% .)W${k3?0K{G<|ͭOp|bB#s7kAИL{|}y7WМ$2 /QM1:"b< u&kdNe_k'L7y gס\x6%Q2ۊIOs8yv:Xq9\5@v7qgH+G6dgavkq=p=gE.>O4yy'Z-͏WZ,h \b6ΗʴCb}XoF|eMV4-jUs){|&ʬep:l~{1p+)3njw| dZw/n1S)9:n'7_o m:W9s CR9Fr:xZ>|L0r’s;̱7w#C߾<cMXzJmZDţ~/h|m(lպk]y9%Od\V%5K }ᥓ!u7/I<lyjYԨՍ#Ew'i8yL6_3ߵ7u6O'򢾫_* [-t˦c9'rF6င9\bw-+%rcPo} iɥ aݺER:4%+CFk"矟"{=h@Pd -9G^RoKo &qWT?Du3yʤXQA@i ew.cZK/ =:M2 6Q à1 >Չv|I Aú߯:Ppl*у7 jףPg^?&}Ά>nneYgꍹtZLM&|\׃k<+w#@E!fz MB6XEJnvjmb4Z6N^VbÔN7jglJÇ=""݅eM6I?`]H;Py+*J ~'7lEOĝgw0F˓T_DsY0IkS@j+>=X~wyi.n)K^]kCI޵eV߁? +h۴:/?}Uz)6Q.PA~R|mz3\W1\ cξEx2֕' ,BO w66{:\Xe2hĥ~w'kěW x;}^9Fisb=ߐ+j<޺Lv@u@xs wi|R6eo 35:.}2EU4O|PSuu3`4P#Q ;~)]?ZATxF@~6ńyzj6w\ӓ..}C-%uRG}ˀO'%&2̲S&.F}/)lFqء+NΈt>`D?IjʤGn3j;ن{׮aҹe=Ώ%W'ӛ{S>=+OڟcYjo{uK&.|CEXvC/zu=;o)&qA<k7hhq嫌_ZcL$iהdKF iERBK1jƯоtӰ@y/qG3_oۏbV|9=j8sft GR u>rf *V\E}iغ[p̶t6B+_bOd .-LI56~f=3~g.nrȺs<|>KMn\^G{mYJHqRnnJ^qx6e!YD_|vl0t.wo4}aB)/Ԣz s aKksK=% rg-Aֶxg;71)xn1|22ʘ;pʼnZk(ߪLg, ٧7dd~U16=EqTe߮pM*9;:*Z˰FͽZӄKn'k {=~ߧ^qY.毼=$`p-N=yJ?L jZ>B8giuz\dn+#%K7{o^Y%f;~.FԑN{p ]&rb[^"=j8Ŝ;ۇ?Ht&aUnH}&5C 86Lq\`ʽ·?jb\-z̉%{d>m+qر6&h5(#q8:k?W=8įUnoYU:D^^!';Ci<Cp7Hu~h9?+z+ޞ/pm>TVj`a=.4͝1F<9W9=duH5YH>yEfv3ܑsZEm\];g7u~'E7KRa WMa{~LwYz剆O6:]T-yLw0 e7M9+ 1Y%/`1Ͼ1no4FW}Vnǚn7)Aki8LZׅz>w=2~{/.i86=߷Pt]+W45mxiZVM5yTn1k|IukBh@[xvׅR%rW) @ʥJ@׸C=Yd0mVj尛Ґ.T @aIU+mW={t9|ksaKdW^%3 F~:xU(Պ񦰤w<7~^erjmJmhguҦ;g4AIt.٬kZҕdP׺3C>{^WHt<1 dG&F\twv>] hr,A |*JMGX!ϟIU}bϒלN{ |u3~tUJ/.V|q,#ᣦ̲ct3_Vt`٦jwBPg5N}Ĵ4\d%pδ ޗ]55)<sq7b&7p6\u(Izڬ[IVU".mMOvѬ zc%-Ƭ FK懖am<.ˉk/^V.^s7vkިVU*qhd,RI?M.9$*z#CZ;i 3\k_(kKSr$v*IP^YD`Rq:rhd U_ |;qJv/7;\ZH3{Z2)R&$g3N#6Z}7;޵i&䠎Oٷ'htgÃu$nÈd{l(_QnA'*d鞖Po Ǖ36តElkڧ VcZ 4?Y ۄK7~.]觝c>@xA!ٴ+4E$3]TV> ҂יvl}rߥm7ܼ.X[qm|^TTnQkg9):'kRcbȌ?yODyb sgz(g :'1(p ϋ8XzOnw+~vx͘Rv&7w)D4%!wiQ8w݆Ǡ:G?iIԶG1Y4ȦS>"#U'ե^yR2LZuY#^յLR#/ճijeO"3^[OS]UX>K4 !|Zon5D1kԪv+ϟT @_ ղNS"WQ. aNuqϦÞ4#M+~Yv9>YΝM^.[N<">w_qxZ֧ۛMm~qtݻ>(pt r4t_mw_{7+< 6 Y$`NPmO?xR0twS #lf8Rdaj a^cy+_>k*yaXw{1f`*/Ö؂JpbNg9y&uK* !nzm^YZ]|`/֪-2?eKgK}I9װ9O➧Qdwnx [/?*tK/MP2or3k쇹tk |*6dWSxvuuɨBM3oyt#Stە]I*pV8[kf̗ /p49~nw^z6[{v.7}t{QϒAyD\/:RЙejz RTfhC-߭z>(FwtGGqmO<~gĂdE}@v9{HްQ~68r^9-6%]f45yfOjv"©zl+F3thZ_նEC>UGXe;9K2c`af,0uyϦԭBWqſ ]<_CreZ5kva9sZyh$]VCws#_W@Qp+jg!FK?[W470/2ZtHeB![>l+}qQ'&m#b^wjY_f.}].r7 9^uM=yՃݪpgZC/q8;.kY@#=d &#\nlEeF}D!B~.PYݮ.:E]D~;vxLnjW!oGZ46m hP^O.U,Kp%A  L[GFwyrOR}j장16wta';koFOKYɬW> 6v3ܫ>G_F|0H]bؑ:-Y0 6Qc6:Z:ֹ\劤 uX*7\_^C#X/* x:|jDj+F {w_N38b ]<9:lչNMw-p q!j"r \?SgN^@↹'{ScR/$*cuiQm+k|;>iMvlvHRava6M]' {q;FN"rkh#6~5[>p5pμ3k~RS4l9YEt31蔚L-OwN@#G~ΨX7%(&/\t<,K}QIFȫR4N.Cނqy>E_j||g ꟧p9;/lgа60Wm*tC7ԲbXuy=M+2 X,tb]{xOnE̢%|݆X^k׻Ҏz^ms1 HQ.SYщ_&$mWwBsaUh$ TzdƢЦl"\|!IcY9 <N֛iG|Kd$6Yi[]Qʱl~>4ÜwARmퟯhGmJ̥zyVBE銚HGSTSyv.v|'e7E}dC%)_,1P}. dq젗,grG+?0>lYnu.JFʗG| :}(\,zMr$}BM>.8z=3pi|nwzeutNn1[jX樴~|hGvKP21/Gdw'khTK3Ϡ?P}gn\6-\,rWYtv^CG0֤sK[D=vha^fʋE%,+b%B,{-~d*0KFj QuHS]ih5}ٴ)m)+ֵ{.G=ը ujy;hsI[INw*r beßT~lKV ˠAOToYk>ʂi _l?|%=6V$7jIgRy'5M>u\DMFԟXC6t/wB2)+ՒZ57LdNnʸb FtIjCr.L{;f16*U?3A1wuNfjIOaj K5`e_= [K9{ Gd;Oc4T{0fD!m~W]m}T!DN6CV;e!ҜwJc3| &/&PY^Rw,k4x1-m;ܩ7y"m 7dagd@w/W|7V`iv81rsGea,z09.Xj]mpc݋~\beʺ=|now9ѵ .K˱l4UWFZ]k\oWMPoAun7k *W^>ҿzA\&ti?`?z-^#x'Q{~5QI/Vvx>O/xl'˭BP0h^=̖TVZ*B[q9Q=z7UNZU:} ѹoovm;{W&ka4N/ypH6[O7Ok6j5ܓxIӈv?OkO}IbU\h=F*''x wM=(zHWdTu&T&∨ NGnMoIJ{{*mqKȾEoVxd3w5W/pdF 5?xqiwsޣgbcw%ڶr'zRRETⶼE6v괂q$|UhkRKマ'ES^NGKE'.9Y<>q.e4pxž,nKbnf0q/#Kl` U2J M:&:6\aefxyW CbWOrC]P9{w2'D۽`m*ñw0rjPιDUN7ղm_\<ՊPu(z 3ēnMƋ}}jpN~CЋA{r~Tdaռ DO7cHw{oӏM?YFxDԧD$݉-w:~vRc,KV%"^]02_Z^0q[/և'&>B|+qKxNKRyx2Z rf-`33!M]+[.QM( ٤Sew׏ǎhMߓʫnlntW{ݯDFӓ\6U,` snO±gnםjuH1W(}q5hDp,'.eVu31A1v/+zLk_q<ܠΝn,6ҎjFWz*΢r~R4q=Bv=Z+δyhP?K!O XSj*Nw}?{Hh@@7|ZWAF Qz[UwEtP*SV~gWǭ:w#q+MT%$z}Cu8ʶzTLc 64 ʂPyL12\\ <gЈ린dyC1rEs }Fs{Sˉ"|8v\=촘l~)O'곓=Kf]\u?LԋR*vs|A o d|UzŸˮ$n&=NLu(Ox.t>hqK<Ђ buFI\m7!-7&tWA.\/~2myf#vxP)4)Mr>&WyƬ.X}nEzqﶢt\{Qܞ+|~9 x@H6( =qqyھTo9>ۄ'0SkKKf/{j6QKf?8˻Rv^gį=v^_U_YS/uc8vޏ +0VKHdqBca+J.n yKԳYۨW<2|MT~FO+_Ta&cTVWvx(X=T8_u}>,Nۃ*hyk\OXt.r7mPǼS5t?VD'g#٥%^g!ȢLf\;'@j.-.=_V<+#6t'Eߪ s3]oh/T9|c3?Ku;.;6@*ȰWʭ%W4Ar-%VVw-F{Nll3^0TgvKyMX7$AmSMyTL/zP{QiP*sqK"Z*!]?<=NZT5 ^I7L,ȯfz\{E1\/-Sul>HӻwR!0Iܡ%6 DWvTH25: +* >T)4Ov٭m_\G7!~;ՙD.#u^/Aɂ!v"KKrT5cnx2 Տr,6)~uEz? G煺XS^|^݊i ^uְdʣX' HFǿ6V6r颻_շ $+8p$F2\qME{OcuSأZTkuo\^> /at7:ݾ ϑC҉$뵘im-;%r:T>;jVu?[oNK>lCU*f^SyNݛ\3ƺm-zs?&VӱW@F7h0]"敼s+ ? mz;?A3UӯKcڭ`'iZm%h5G XtjzDq[$C~i-&ϫW~i|p#ۨ_ •^)ҁa]#^B Rgb]moeetB׃5jj!|LE6t: >6J4u8k6$޴">ir|Pń>ѝmLUwҨ=Vm4HHwϨn>l?J|ӈ|r^zemƷ\ϢAlVͼ?V:\ь"j xGn]ܴ@%<Q;=25w8zħӼQpY*BWƓ'Ymx(@5QHu4]#F+=eħl?,"?¦Ev:^#:[g=r1.m[92GV ?^J= Xv]׸H|F)J#qx.{PY@o?كwv9wBxh%'nVimcӓyi}1ۇ:#jʞ eK阬=}- YhqK3:%F/ >{;zg^#Se+p䉳oAbͺs]~]iCTI8t0p3q7n:&bdR#v89+闯;"Yw2rxZ;tP嫋?klat7"}}Pz,G2?_eUH;5ZDv`$}sZgr]6n A؃P>Y/ x%~((N|:nozY-ܛ}1'WG3pz2ò5agX+d%ijSѲQ6F'W1a.O5]}Jimb[q.υ"jķz6FTE'_4:7|;6d7\Qc6ٞ@q%=*I^!x6iY3iأBwm9V*8{Kn;n$ʗ{؟e Ym= uw|b4kC6VJD+_tV70S,̬lp" i=x/oXLd@cA_y%>GbCܾuk-cbulޟw`֯ja:ۃ|7;|+ =.](a/agV]#rb[-["71j;^$EP>=TI 絼F7|?RIPnj-*[ fc<*"\!6Pv&1VT.a7C9hP^<%h2{p=Ք0i@+[Q=Q?E~UrߍyiO`{+A$ Wl`C}TMW=l];9Bo߫48_!)7߆԰Jl^,.]>iupcM7 2?[Yߺƀs_'<~D0#X$|\ {#xP'm۸"Uwi;juöhW8DK\H_%ٓzXкȎpQ38SvC:̄n7ֆe4겙{9i&?B8ݮĝI=zAE# l֭VB.>zk.K&&^P<ڲbJwTKu,CgˎlqbĈݮҳödS-<6aݢ9A6ᨍi6Kx7sʿB5J8>qb87h4- yl LQv 6?Pi#R-aKG/(ad/^Wm_C[gۥ X#UjAcӂHjyY/ ?FVt?Z{ajsEo.j.g6sykBJCDasm@|C}'[ute-Te~آqȳo1|,Dv%[+I?$dO㕨K#Zqe s~W/O@o,z0娽Z^&u+˳=֗v2ZTo{~&k4|љ|4LTK)_h,Fl7lJ]&]KJfʡ/+3,o{7mƒʰMzvH+\[1n_).$mGn38 /,0StEx{ G:V&&^kTy3{'_|: Ugt5[bd bK";K,U qz*eX6&4tGK?Ҿ5 2bzGq/k.1 ""?;o`YP?⧪֝wUkƝ%z^ד3ܻf^M ΟƦR~Q1ԅUm +K~<1Mگ6Cu*`>Ÿ6XE.Tb+_6l*)[6?kk8~$nZ6n+YQRsmIE}XL[D}wl( O_ΛV]A+'y/zo}Cw%v ߄rvR-TH im m'ďdw7^Io? BFdެWҸoWhЖa{ÜG^7T62AO{]I(zK1I oi?)]s<쁽uT" ? l poHEs)irp(hھZ{)v,Ҷ.4Vza~X- IĄqEls4vdyĥ<TTz3gm;>‘+||k0>=GڵOʉ B>j;z6pu*<1o^8mȝܾ'UokPȋycdB!#wXtb~TSN2} mlӔSn;|>,UWk0FD_o;_,wx}Ɉ:tջН{y; ] Ǝ|{1.* |g%,Dguzͩݩ!yS#pdQN7ױƒ((>{l馨 OaY-Jz3^z? yd?~W+xzssĐvnڀT4(('䌶yՏPkێ *(.~,2*Tt*'&z>|Q<%x'C Uذ-lFG!H.2l/mn15Z2A |^4&# |_-/=Ezr^tD|%Aw;$Ì%tQt5-G`ugmR?~. C+odwzF*G~{'7 ץ67|K儠I*mUܯj>F/G)bK_֞ ,alli漉 I'IFxSk%$8UL)CƂIUR qz= -¼}:xуzxֳbu YwяƪTrǜחI@gmf/LgxviBm9yC9 ^̲8iqMVX+izf ;zᔟ~IXa@S#ѫD*;w#z[k0+h:koSdT![Y]5V=RE5}魫EvIZ;R%,َb:{(GK?%p55 CCwl֫uEqɗe}lx4 qWj*jKx^k Cʩ?<2!msGvCcqvGTpy.gc-ōZ&w)hʚ[V~zW㌑`j?Fvꖻ^l]W<ǺG4hsMcv6c HC@|--D)m[&\7+yk)=ҝKx~k?x{T,?K]w{Ieo6S|:*SG,Eh&UP ?{h;?J==ǛG( Yֆ7FЋ7# { g*ay{*cG|DglԷF؉lܾR~jƺY[ul?h;͛"vu|'1|pΠn(9|zmj uVXA}Hhz@gRz4e@.Z+NIՃ 69¹>\?N Yuޞ;i/\6":sӯ+gs)uM0B=u{8POb&s outȟ%18JT \43)E.ҳiɺWjSPRV^ *<V,5[9\ mZI=,'bpcpVyoa&*YS.AiK;b1%3{űN;~yd1f̕i*#3|Wo~efhgd9埾3xEyVdcFqǻfeA$mYqDqeutpHsDn\u۫yqdGpA/J^)v!`|-}X&?|hҞʎng[Ɯ'׳Tu٭O|+ .0}S},'FfDo[J_M.x@tꏲ㿮"e^ }\?#-P"@TsjPeK -J*V5WONF $"1)/\ũ(yu.h6Պm}ğ_+]܌&/m3pZvg_F!#Wt` NQ­/vvyYFE`"N:vOZ(1gt-_' Q&%9-CGS^Բ㸋FWU Q j*_}fn})#oT%/=6]fxx@} dS?js5nh;|͊@V0'텒QJHJ_RFq>aR??M #R>[j&DzD[lq{<'_`^q_nJ{X7vq]^*P,%d?\ 7f" .(@U])eP6IZmEvzu,:r^%k38!0's׼ACk98Q=lk^Wo+nc1m pPfog,rC/SSf;bʈ9o4{xu-yx ~q\A.Ӟ9;n7ӀMӦYbu,A]RVp֕*ye C=wREcӊ~~6YS ( 6qv̺lVJeFVpќ,Son2F]UmA`,VWVwYa|^pt#0◖ʁ϶Ŗk1D-Cy~387$1myo]^it,_@,r#~պFnF/Wg~.!2 ]JI`iM} %e&;wY \~]B~Ou&vMwmބEAeƲY>j8?F\|x(ZcaEBgdPu:ju@g=>da%9_soxsntҋt:텭Nu$#p dSOV6+8L+=s/aT7CS? ߩC}hba޿'ŋ%XTFWBπ@ʄ# F+IUhw}t񣺨52 ^f `N1':bx?&e5dNP.~,A{-nK(-}q' 7x_78`RKƞΗ cQ _L;o}V2Zob3 c2g|=kz񸰇1bAB-357$5 r)V8 OSiK\U^Vk`9lzxo5s ,<,C{A+oY%mڽ .+u2IS} s(&n14x7Dx.AI;S f߇l֢;txwVUihkuW]w=[ˤDFrt\f>W: %-xCf7%wtmT0,;g=!gK'[ yC^98\^LjKB֛=>[YË"/qO hO-+@(2s9!)<ǚ.VzV&R%8 8[i]j j)'h{/lv)VݰՉ{^G{\_[0fQ|'*ytg uz>y5{TKc]Y H"ė*8rt*n :Fag% mȩ򘧒܈_'9OojyY帶[U?"m>f\-?juYY8 Y|4r|a 0N ^/RuηSv1攃hDIZ 3vNwAAr:׌[0nc(=6=QYRlSmV Wm uQ%Gߍ;(j,*_3^;B9hK\=;ЪaPL,kϞ1*p3Gom? qCX41l^,?z[MuVjńss: M_J^&=R4[{L8iv=8gGX)] ܪ\dʾ+:uq@'# ^s{ rj0?@+Z2vi´=j5ϵ"Z~CKUry޼U$l_-G?XfځZ鈠X<`mK 6|q5Iiۓs+Zu>t"׻G )ljԅtD{D օذn)57`ݒԥ1qse.9^)9&u~R'IK(Nl_wvOW'_ä +•|e4/a[Xv ISy]5G`-^[{|z}&S>]4g<^0;< `Fїsϝ֨M?n47;~,74puJ3-]qcn?Vp `U['h>GZȊ|rbWF\bXv0yy&M+-j馺 7`k&aۚ z#Y⓳,KQ$c'n")su7~Y2 d~^Yj>H燍:C4'&KxWao?w\*Hۛf+_Z L6Z,l +8BW41H-"wjݟ ;[;x!^58,. /r0jNHg8& -Ew6߻t %faˋҳrA!4Kth7Je*Sb".Z7>oJQl?kV)6d*ArWy/_;TԈMI Ykڣ/|0#tࢾu K^:#jqTpm#m.D D |n)!~YIVS6MڽO{>8\p]%lHxkiHE50}e>3a,2~ ߬`ϗiݬoН1$Od6Nsmis{[x-h2|gz P7LR еwJ0}HxKa8LsR_fd|DUcj`v_UcSJx==*oh+~7](EILjkXv$%߹W-|NxϬӠ0q F0ebꟖzl} j謽= =UVq0f̦*ـ,܌| ˆf9./;>ƻh& [K%R܆ջ3V:!=" Qוdi.p~;т_,V T^RSun=nv{J$h{\OjjC_''j;nշ-kF=` Kwl)+EqIho@F5ZнvDZe ]gQRݠl :퉁v7,пi~rӈT[omJ|չgN^$/^,U` \Hl} .n}" 5gX/a;헮,c5z}8Eԗ87׋?eLAW$3?YAdwK^մ:0?X+MGIȨ ^;k1ڱ"Gxܰt]2 vw$g5J~8v ~4$sdrԾRYA+7vZH:nJ,͎C8PUaz-A!rS!Ld {LZ{J'` y>vSE~q1hmYs"?k{ ߥE1Q7DZwjKU/Q`3T>K݇ZL4pW$d{ڽV.P,lþ!y9/wcӸNcLJ溣!W^]k)V+^j Ƚ} QKθxf QMy_>3Td֏K}a#OF0k٥*%VIu-sG>9C׳֬ٔL<'5 ub4ݪcIFaukKZP}z;Yf-K#]ꐼ@ߴqr4?Vs+Ix`-!1 UnK|>Raځ +6|/Yy4t;U`seϻ[y[/ru JpB<+x^w(8N(=.4>l:Mj9kcehc 'XeN5مET]CuJA_OvB YvF"^jc2YbFVg-VTv(ܖn翤Az`?x>W%]X.*X?lhYI^:md<$jus^ٰu1Rq)WwoN7NOaBS Şt$FZmOds_&*Ζwy=6#HH] O@`lt!xI?XgWn4Yp"k/'Z_!C]^. th}r3X>g~z/6UIסt%#:o_jf@q}?5"Q@'B\/A0p5_6 r9 uwM ˴aj%~$.ܒOpdprk>fN?:9}`~.ؓ_z*딴$pC 6dAW \^NTgf%aI#߼Db|} `Y71xZrl%WboG5گWkMa8b|cyTMߟWz7!/HJ~S@g("ZwHP"^ңe :Mڻ6L^e4|9pڇ.G$Vh |ObQTؔ1)ҫb1V^ F2!yL;>T gIe} YsEhp`s6ߍfՄ4ZgNxF}?5g]!Q)8!lL.NseY[c~CudW>EI䀄F>vUÿ9M`*GVRze^]0am lio!=ʔ'6p^?h-Ջ)T1Zζ"C*39$qrӺ\yҝBn=lCad$k7eE[QiHŁċ5]@Ya#۹e(g'NMWƭW]4|vkm6Ny#k>%҃k՞]Lhr&~>DXdvhkhn{ L2Y6sMdA۔0dl(tSZe^\h@*~I[-p0:աF6\7Y~#Ԭp +mŶPxNJM|݂qx775xZH4*0}-??Ӄ1nop?촡K?7等qGqDc#NN7tnk|6jڮ\Gj$%Zxl02tk3S22x\`sP}Rt7a:S|<%Λurҍ>$o\:{ڈ! IWzUقϑ5L7o^]62G0.mJQgxr^œ4zc@푥ptF*r:J=Ѧ5o3u7KYUɑz,Ôb^a~7E:mӪ/U.+Z6YgʳytK/ƨCn!?-9͋ܵRBAk f!eyHj`_Z/-|i8}F8axp {b̻]Ŝof`>ηWchJ@m@\J4,Hl=M #-EN:ePidDٞ xx})FfV.5ԎmOܟ%\cNx EăzAn1:8^ڻV\U=s& CZ}/(z\e~S*2vօ33I3*EFwۉW%G1 uxnf*ٞѭQNK2elZ<D4x!@s:jY,d+AI.OǞHHolby#FPdp]#|vv:Ŧ3e_ufS;n:VuL(/-];IƧ d١턡gM]nWƛRt<YnJ̛uj?x*Q5u3mLkmͥS'?Q"a'5h5 O6x`*`rdñpg׺ʝU'~y7j~~Jk]`5"^Ne!CeL*v/Gp=,;H8dWɣ^>{@m4'p^lXCf>Z:0!\:*jc [ZK]l √ܩ:*Eo]+i0|O*8J 'f)U-΁ډBrw=_&h7hGpV؋BcX욽|'`xwS>@D=*_O cɱo l8IaQHYfmj1˫]CtznfH;X{v]àGOk Z28I֙Y:uZyO[*=j벼v޴9O=JBn@e}#9I V0۲,:/Y;Z7iY0RvKl|Q2 Ag~ճnh.R*L<]v xjye yŜZ][~U[WXPnۭӲ?hbWuɲhni'h7hzh~\ϗ g^PVÌ]g {y]+;_Yh1#E+J_ϛ\"nwfC*.UN(區_@NPtZ59;.+gUzl?8w^][6* >mBg Jmq7J"nG~(V[OSTbIa,omGs,_EUGcB%@3VW&M1Dt)~RҕP8ý\Ϧ|7?Y-f/|Mk|3p8 a rpiŻްAXs10?X/p ʪM`[{>yЕ6񘁯e.M'%Cj{ kl-][WeB]N-'v{tM0ւe?)`f`GS;C){WI&q]8>]{P >Mttwc6^T:{4ͅ{h @`a0&pugcɞXcmWo^cyt2~cgO#6ۚƼl3\hd!׊\捱X, w\:WaD.[87ywN=xWϴ?gsˌͲ>ޭV-I ;ayvX:Ф&2/◈5?4iN0\m4|F;O*Mi$'z!XMXJIHseNzͦU_';|OUxf䃸59+W/[KӝZeǽ\eR}haW#V_'+`(fW&Ii;l`%Q؋CQy ҮqQ2jaϽD\Y]?=ťٖğt?΋GmVuT7"6jY`}C,Y_MJ~L<y!aNCaЈq6Q5϶\:.AdK\w؝\}өVjEee*~9]Ŗ!j#2s^(= 2:!"/TA=,p[to(h!Yo S .屭ӣ`њ XÂo*ga3XFKư3M\| ܱQmn4Ll6< > TFA[5Č6Vc.pF3NCu2"rدIH:Ǩܖ|:a)2t?-tqu5GI.*v/Ws+cz?4Kj*ȼ3ecO U?{OH \7 purϑʻ.a%ʶLjUװ95n. 6Z'^G!j D(}C Mv;Fٷ!M5c',/ǭ>j-jDGڦ`NtIw/$^OKOR7 C]<_GEyvx(*}7bP-kUeVj7wh:ImLW<_' eqc`Pz%&Y-Uwh88֬YZVeNx`;3n-_ f#iZ֫ fWF}PwCڍl)=x6$>b; j0r)4$Q->SZ^ țEpk}y5ooy(܄! <^OӱgA$}z8;01ko}iK¡^oǢ;* pl4џ~J>|c^y ;>Ym(iNG(!JJ VEM4;`2 Iu[PqnK1KGl mnCIYtKZz>~䐄0H8xItscs00sз0d]{5=11'/ukyH^;A[1nOoZqdWvG%gSZRa7,t-A \ŵP"J[ OOjbW11z/Y{@X#p &snF7Gk1Ѯ8*MjQ/IYm{6W cmsh=^_mmKC|tyWg ['ɐ}LF}q8[VR.a_H7g=5˥HFIA!.g=/p<(iS΅Nqa^/1wJGhgB)cJ$-?iovXg D9`Gv|L򋄏,Tcq铯 jJ1wVw`cccmrm5(i!bj{a^1(&"4ʌ rVކ Ivt}p_Nށ3~&(/'+v&<«߲X6ӺSF%R8@(5-"׹IrY yKi$癪ɓБP>Gdt'm(?pCn`e*n;챪k vdkݞςFngF0WW mHlҜX8!m^G6 s}S%9:SZKzH`fWy'oh5U~^ΛLlc}H>H7:f19\h#fp+jIK m8x@ceC .ʭӦǖsǩ=}ru?:1d-)[lߨw=^GЫ3z"ޤXzkIh+0#: > 7}[9$Vj|GSsk:jGno^\k[[ErkDGQGQ$s\[lڼ*7왭sBʏ #0Qlv3tFD( Xڡ~_cYdB.b*\륧E%v&wޛjJgtl1nrۣ緛=T37閇"dڗ趀jQ[%s.FsQ#;rB}J(w nkiZI9o! ӡFc;G>/O+0U ?"ޣ?8"W4w c rU`0`F<8[øR[C'(pA4bu%FP Mo9ƛyp(B|~訷G/P XwI4o頨Fyir4`[| 9m#WTJӥN0ůAux[dibx,CL Ƅ>3:xUmߒ)Sd[PxS[>R]{\؉tS0ݚ2c ̌1kLT.{tI.K9{Fx0gc6AMZS+$InXB4~&@jOgUGyW?"Iqn,^>GŲ`^ r;nitf8ÿf"uVfU]1e7 HZvWG?(Jvuߵňu߹<ݟ=3]hPnMlmQΘR\"ݝuZ 3t"fD%\ulk^:׶rScS8C"wߕOmfҺ5M4h(py_/x/:U,zZ 0/cY.6^=c ׊z2 #dʢղ󕧰B]֮RFs_Y6{=@ N#x;D ͽ&74頷U<_ _Uĥy/+lLm+b w*_1c s\zrY+]lFc@ޣ.xg.Ȼ";2(W.qQ*[ϥ!(FϮk^_Iɸe*Q(`DG[fpHjd L;@)$- %1+wػv~Ay0̡kVM MS}p5^VreBh+WϑYR);%YskT+pݛb2ike֚K/>>bmLxէ^p0h&L<d?hrB6jʍ½ƺs0`[9Fp ^KTKm}jK'<9t>\,ܳ2}7`[sn[ |14.C(E X띻B H 1 r j/gK? |K q|'/YzRgk*6Z6?\YbD0v`<&O Rawm;TcVI'Z֟}8(߭wڡ%cQ\۳s.>qn],n+@y¶+W¥=VKAlX*\>/S3)+Ê &[ذ}gsbovz)h<%cZV"/y\x9sB>JTHcё߾sn^f Rv =iG82[7Ӂ ɖ[iͳn!c,A~W e}_UTu'55Z({,2 A g k;nu_ )L$zן2=8Ϗ^SD{[Gg&NۼǞ,9㖻B5svģlQN<İJVl)PZR˕mO=>^RU$MLǝpW^ԩƉ5ɀJR0-k<ĠSߣIJ OѐՔJe>s\:㯴w0UˀU/MVy2`Ӎg#yNY=fnx$dGom]:Zpq]pCy&[_@Д)-T $D->ͰRdXܩWFsW&9>܁qow|tTi[ ' H qv'o'F7ڣrl?Ϣ6KKi: *UT}-b,,w*JZ'QgC8O<4g#+ytl]XΨ<97,Xy%w̍i=#/ڟTw/ sXl3}sklȴ15F+S{(Osxx+i+j8&KwFmɍ>ScQ#LwMYoYj9/1-֊x ʽAzўG$ߵuef8[!qccp?" R|4s6T\\6V򳚛 N޵7.b :l)-RY0C5VLAsyP.P@w'lkdjZ*m Cs18I_oFʱ %H`_!nAQGY7θ>3 :;nПwtd$46^>" 8sNkyTSMI!Hd-w6iO(:ٌ:G eq=TWp9_C_*ϊXiUے:Zo};.d1XKI?WY/8ŗ؋d贏t|,0,mBFt7_~͠z٩Íʮ(Q}RgcZ=4IdUA&Vg[ I= eўF"ɝXOO 0enVC=z/o6`u}bw|nu8 fzrg^^Oѿ#JzY8< jym=CƬ墼R|Caě >&=>hnBCCON]4SaYL^h!X|qZ iA3E:JŽfㆨq<;78&˻0C>dXyQٛ6ͅFC+zΰ $B.¥ÿ́I`ỡC(-aIqe Z lFcZnT:IuqzxP^aV&:Gj5J{Bmj]p^r^00sk/P1|KKf)Rլz.ѸXߏst؉Zr".5Cm@R`>0[6 5},[<ۼTQGbe7'p>J3>׻:^l[[3Z!3B6ziT NMX4N̥4ql!XMWύbJ㠥K!s;ʣƷ+ZfZDeixA]cszȥ' {1ТhwqqJt+[iH'LJjî(ތLu{lZd -QYzRu)m9d}qDJX0uwy֡\ʫs2STY5N={^6/dStHRŁ˓^K(I1\-k~>[X l}Ş]tҜ.Һn>*ߤNpeJ\dj DLbvrL8(AX77b|*-LFKvA*#4,g#6LsetӔ^Fz^OdմRT֣[ƪhW  4w{ImazDpr1iKϞukTfnsMpfMZpjT[^edo(|{UR] 7@=FEI "!P`kDߒe1s3u?%w; C`ҵ4wfй-E07Qۛe3X 玺>K[,DP)Xjqen^Q= 56YW2!Da+$yܰ3T<^[W9Ha>NmKMw@[=_hqpˌ#CcPx^Rv풟zF0|>Zkd߽:Έy죞b\: Bel\ܺiNlWtsY<,f{9I1}bTݔ' _Ѝ?7e:ܤe哣h| -&6*pycdy׳g+WokrYفDtչt1VxUtN|֙,U.cV|.Y5O %z(1.n)ba}/WJβA$BSݵ*A-ں|X *0Rh>p|Ȝ!v%nCRY7 n]b'9`Q]ثNH rbXˇ2Eʴ>۶5XQ5u8P6rTx JĢb\L5c?K UF$|,dL˱I*E:IqNI`ԹUn\' < jDyxܥ[D}>2a`ڃʂ(\%Ks8u57јu2P=6MUjk-mPi-Z6\sJ`ʀ/B^PF-D 2n0SgpUy D\_]i_):R}$O˟}V~\iU"7}W~-/GqNǜ_/!w' mv̯*a,`φ0,7ҮOO}K(ʅvJOz%b?8nL9H⃎Vg[f]DW7k Sōx?Xφau!y uA⛅LtgZ?g lviZu,.D0Wj0~U[ϠiQK۲۹Irڠ{]3[S?mZ6bMp[/sz4\VQA]F>}qeV9(y&TӢRZ /vmfXOۻP]h\iN SZSj\!,qj+4,hbnxE9SPNb-iURe~?]|Z}LpG[˱ru=nRY_ߙ@+z(ضh< y!޼t{odIYyc_o"ߋ^v))~G7Ja;?OGkq颟f7ܶժ|ME~ 3وQǟu5f^ tI-\EPsɳuBON]z=Bo,c%(x5l~sӕg*䃖U@O vVցP29e{_ޣ2)HabK7*ݎ&S_@|$>DQXmąf92Sx!cxbPrz(ҟ`f)1J~wR;%W㼎x)+MU1- O$iM:yZ+nG'_{_*Cj3Cv6Si S i·TA&ѱ2?@^A&ԓJs%T/?|Cg(Źhӵ`08en-fl/{i+d+JzZB. xc/’K0"8*^?z顰 *WLW;Ȱ\# wH;hFh^<.` x(o*d J8YIZX-n㈜h3vrc"8}hgX8&FlX{KB2*{as=Q:`V]QG,Ä\]e:#MB*Զg}]٧|- ˲vz~y {~s@~.BVF)dJ!+@{õKQӠRpx-c=6|g~\mp{m_2i|ңb XDYJdKRT]=tªۧRmSVI9WpZxR2V /fLl!N6Vyl;sc^Ysٮ#3\ ȥnX̺hjGj0f]8UTVN r1}]Q%3 -};UZC+AdYQ>Gjs 14g>&=҃)tGPѫ6Ԃ,1^-169dlgxP'U3hB4ԧ܎wT3e 1I4ofJ*G1z lJc}ڞv1.W[mv f=z\Tsp.8lozkP'^v&WiN`%o&q7KQ+s骇}9EvNq)!"=)8 Lӈhش[ d͝u:T 0ڿ^}ɲ;ج\+oŨsm Y j>%GjSV[.ϕve0WavL QyhUS%x7I=ᙞ?s=1%6䑇ģO6ѡ=豷;5'{Na ?<<F]Q[cOe^'Ml:MG`f#fpatWyrzpZf[7/|87W|ٰ%sOEZ|JL z-V}VYs @oYK"Ki1LSҥUo҈%xHmnЪQqw_t7XHߓh Ukai>ªD*&E{I2q(ʱ9E 23^f)(?F!Y"4?|!k2poqb\ƓsyS5$Kuӆܴ*׹>i6ETF|bh^l]sr]:3TF 8/m¾/>fRq/@ZZ1/wc2Y..dÞ(pPƒAS2 ә)A~݁ cn*4:7</vЇ)T;]m֨ n?l![*0MJ|K06 7 ,ڳۏ":k@^ ?i%7UiA.kz IVy9Bxځ޳oǼjŏmyy~:RQ6^f%+^x7 E?ACˣ|7L"7: 8^ExXŔ^XO|ecR)-rsî~fx<ț׿ճ&(_;u>yT\>H{n7 iR `]ޡ{KCȝ>'X9dש0Uj6J<:<_ID\#$[yx'߆wzUi΍Z^ktz/Z}fl6θG xE{q8~m=t0)[ OgZc}x+XUnHK͂eJ֤*^+BZ|Vk`W[ϽgՑU1XȲ6+MEWtRXYFܨqPg ۶ŏ9)q{63OhS/UQPg3!7ua֗aLٛ3X;4G|7zX.cB{A ka:ڸĚl 0N z2dǰ:j^;/ҡظ+֗ sٛ`O*1m9dQNӼ1L* IT{hz8.љ2Zx3c{R]%\6iʐ9=⣆-;j ©>d:-!!3M-5 ~KP I)GZLoJBڏ(-7B^\6]paܰr! weyoV> ~'w1nX c?061 m6$A)boF)ohA,馂Ք,+FHɦ;Z{ZjJa]7v[f¸T}eVR!8ov0;=ɂVVXh?bh'/Z,ogbՋĻ6dB_5-J惛q)D|Ӱ\FYut`g!No5M}!OZ%ABoy}ONpFim/]/U:g TˍdlLs Nw4+%8wΖU,o|p/盥0aڱ ljsM,`߉}qlXΔWtNvV6?1:ڬ&`I͎u7d = ߗX1S%yr̾T9e)-`|;贈Vi\Yzz+}SśNدxBձy3֐F/GDOy%3`7ϫX/6 nkX[H7{,/Zš ̕uiӬjh}s^b an jIW.:4?ξ'g<7QQ5z؃F|ZN{oнk/I𤋮Tv﯇B >|2k%Ga\ P ܌~6G|6(.Z;")S~nvh͟ZæDjQD;B\DΕegP7tZZqK[˗X($5:O\ ًBuZ@q3{ ;f)gSZv`:ϧ#f~:MF0:yFiz fe!0ӯXT-%>F) z20Ţ'_R }1 ,tqJ)|_| 37D8Dpw1<5_b=~VWU)P:g-j_0H>%EㆎkVX VYu\kw>YX_ 3T0GT3.FdƁe(fTcE#*&>-.ƇSr^Zyru|L}<[L87h6sP*  ⅛[_6Ll?pwDMds,x8ǾVȓEKL\ܜWutUi0 Ư|5㬥Vs>p.380O=Fc-S/dm>P8?;g~V\NZ2FŶjx|'zŤN홑W1I5M2j՘ {a-'=o ph:K^N}hxox: vK: 2ph 2e379~+rҥP ]x{+\%, ng"algrpkv۬}vk֯еLnBNmթ9m=u1..^ ܜAU9vڇq;qAv†'/(ɥZZf3_lWfE}#[Du۴ KgD}Ѽ/J9rB?h<޺{n 6 | 3Z !w/e?JjEL^Ւ/= bp,qf!ڐT)tCU<&GmN=4J'IwG2Z^;Op 1MlqhM +vǖH#xii 4Э dc@n7ɰp+I†G@ˢqmjD/_ +uc< u~+h?Zbeӽ<Ҁfy*W# nio5huEo`U֤g֑!l˞ežsyY/s)v6rP3wXa(uM V}NZ{#3_9&XI-/ ̑ nVT6>-_8^u6r_N;BŐBD:Kiȃֲ٩!vsw$c? =xuDoB1K WJ[xLQb4 (rWWٶ&c^" TS\} v9'c-+}<پӘζ/]>֣p"/mt=ԇ,u1يjm^GU>ߙyTNz${ D{<=sy+2(,convF IVZ qǶ}P:QbJ^>B2Yri9ӅiˠH\"û'.mβȘkPsP|^RW&&d[nm͇݅տ.[hoЫKT`ﮢPq2V5z;-h]s?_噱zV볥Gpnu0YZ{50rXOBGncJjBrҧ Y4mwzmR0'^B|a0YP\7.!Xb2|[F(GFI">Ek5Mp@g`wG&\O_I%1i $KsxtQӵ{[䮨|;O9 kՒoaI%R#iύ[#-}7,kWI[I~[N.kt֞2tln|8{=c IpI`NM1hePjem4I+^O>];HM*%Y=V;lZ[s-^2My.vsv#`(d)WM+jpgJ~7J eLГlUnY 6J7̮eniǤږ4@뮲iG[nYQTǔO `yP@TNzwVbuSoM-gh\pWu up-"f= Tn«|N_Ex,冈W[eQE}6̖ºQ7݆%Vn(.~`l0/C f,4Fy8 m[,qm3B5+\lR[~whLJ{LYND\qviVv, `kka0*is^-~v7j\\o_XO&nz%IN U29xPۧr;v;j4PQL>g<1Y$?7yP| /|_pˁS1rA۹"?+O7%XemS17:_a,ym\{lnp?sl]>-pCH׉&9*$SB+Np bvH [K@W\K \jIG[}$L󇿔>%e|8~@Tǹ'=&k;-JhCi/'KrK:1+ު`oh ZY)% e삈8׶P`;zeѺ|~$;߸ ,αc&t=gK9h6PYG=dPsy`UIbn6NfCM02tuSBQ1F|\un쪌};' N|4=D],|ѸGJ=>cOqfF)U&z6F}ܛvorGo Wr_LM5JBV;^ ȝU/apQ%θnȭEy=$>8T*c9Wxoo0/,T„]RaoX|TW_#3$Z60n,:#cAAOۮDlw!\ٯ㩬^"6(Ik[z`5缃tZxzy0N\FK8}ƓEm7O^8*KGAfA/v)-%F>"KS+cޞ`sFylh=Bar\F*pz|p#AKM`r'X\.|7h%OңZ2'|۝!AM ߅z] M+Gr~sf_җ)7wjU48&F/`$g9"^m{*!L/늺E‹RݟVaUIؓohRV{.ݦ185{.nAzmiKQVvzv[YyB6_i pYUxQF":"`X_R_.SdXI$^ZVOie18q*=V7y=WC^:OaRex}[+9SY=wM$66tDpdfಂVTރvRuXwD;{B -n_[܇w~5Eq\g.9|{V ͛zkJ?*mcܛϓS< 㝊*T9Uu3Xgd]?{X5'"˴wPK ʇRNޞ.],]DѰSxBOIB&jF|Œka<Zd%*s]0~MOC~*Ť_^}t׫]M.*/Ei9@4jKgQ[/krm{=]mu=h`9 ҙNtTf^Z~?ߨ)4]r|se/y`E9REU 3m =gyĉ\fnbz+>S4_7DW2*pfاvB..cu#~,ĝ z @{ǼRl.\k"˒V_}rdlf|uVu[!D\6n x*1ĝ텆U-ͥA23&UHoz.<>f"XZȟomVg݇5$?X-e(bT#~'֣x.1)l PH m=@xovP6Jmr>Ɲw\" Gy0}y7~w%v6;+ry %pz9w;sk7_y}Z4ioX>=yn{tPWȈLuM3/&+TNiwҏ _znb)2. ZF7*k$r)kʮNwPv;]uK)Mr[.Qǥp+@0 ăI!Kgc@$_Ilp-t&x9aሚmz@ЩEAJ&kIrd{-gglگ{S*'JoJo/_<֞y飸Am)d;s n}Kk2)qa- o?#hZ _*=j7o%A[GOL"qJ}JՖH|\vvܻ\c ܴ\0 Og8S\җv0AxT;7(ryL:H3!) =ɣ\ԭ Ɉ/[tp<-εۼ}gWp Sqp,@ՊTZ*CUի\6Fhb-Ḓzp W-hŤoKI:{3GGJ/=AAi"/`Bv1`N\~q#-9Wt`7xWQ|{n.W/6m!f)&I#*uLLE5SIATck-u܂.8oͳPeLjzGX\_lfFR/%=5* ]@-˘,wO?W#eʸSHNcX^zvJv2|IZ/\=э9=Ų)Ɏ:{+lI-ɘRgv!( Hܼb̛=r}ezMs3 )v?73NNO2qBδXY~uRG&:~^OnL0IHcG6I&B/y:OZo YNcB&GZV$/1yYesUڭuԍGGS>kq#bE2^i"B^^ CEڐ=E.Wоgsa 4¤.⭾$ѡu\їMxQ#h_24BxD<9ry֏|fO9W7W75l?u߂זaɛ aZ:hn$ޜe:_Ͳ!6tx,w |Sm_X4f rb2t{ٍ0fx0n?078‰P@0ٿ'6YS^dżl8??# 2 }/??u6,2鴲26}Hq>7f/b'y폐#r?8suaf};de6?d9~w+_|BZ}$wڙ~f_ioAܜA^ǖ2t_+;N~4/QeW ofmq߫?A~{?:~HÆ[?mA0?kAiw˒tt:F!md%xv~ޒ-~iş /oE$gdžЍ!MW;v׋Ilw-PH˿o4s!n]74 Ḟ !y?Ÿg8[ӺאP:?_jGP!?ى#?чn?ԥ3~Mÿȇa垿C+>,ewf  vV4` ߒ2vnc@ t[.4`_mƿ[Vm`gsDün#1/w ev~Yy_(iؿYtuo=D;vۿm.nQˇP'I vO?(L!M^*{氝_&OdҖp5ɟd/IcқHwiBA`{2 BpnAք6Ҍ3WXJ2RN9=18&4׳ )N冡w3nj0ث*3rgDf.L /Oum614Eb&y6Ym>?e 'tl\lE*N|e#z,Z3;Cg7ۘ˄R?mM1FO,~ɛ 4ZkzJ6SB諿 Х emN=AD΄paGߡČ/KǾ-qN&!gWn|41HkD?S!ߓ%-Iib9߬2w9{̮)Eϔ:cTyu7`lqߙ%'h6%L5~3MfG ,w {sQ[d*OFrX[q"'6iBgcm%ý 4kySN>Bk&8Ooim }$iO=FC3D[%X* 3}SJ] rA ~ߘ+8kv]jГy@"X ;|(pN|&t+TfZ $ncSO" T 腶/.@k 8N/{']-7A'~}>GG@t蛼T[bX@wpؼ~Q?܆RF`epUV8?9PU?6"fNŔ=NBAPtk=t>/ۙڒ~-Vu4K疙1L]1;uhd6k~`xTgk`/e=ߝ\-I 5Ũ:S_|I~0N ۈ}95^]7 4r[Ё8F 8w2\eBB'?_?[E"DXCOx#ܝ -w^Տ/.Ody'EF]מQOaˉO^~ ~AHʭ8mqέۯ?= [LBȉ-_ !,(M^?dt{+s*cq B"FIc0/8[׿,< Y( pvO~Bua#\BY6 QRcPC_ [d۴wgv7d f4x'p ]?m; a"^| E4Yi}񉌬Xٗ$aACX8OPz^X٦#_(ߪN\s&ֻ֜Lj[)9xf2luCF#Vo__ڷmb5g&5wO b:I?D ncLجd&La+_&h|%.Abc?0o&dPZطX`AGi?!뿱M3MZXE$J\YZ?owÿOuk,!k?~Tw u:D~h&4:1}Jec;RхTq~*2ҿ]_@[_u;m ݁DŽ}su2ჶUbM?e쇁iHBv~83^;Ǡ?x?UO=l9sv$<9d$ì-[!A1JHd?aɈfO@ӛ^潹i;N=T|ok7R0zH~#_N . no,[bKDo=31%#?ovll5mzB@̼/_)YHrtH>%3#?@? 2sNad?SbҾ[NW~q0hZ}BYЄ: Іyy1&g2t~i@5ୃIG Բ,Ǐ%n0Sw~7s2 ʷI˚8Na؟VKI3l@7t51x[5&OGq{\>D+O{tK|~ 3eo?=$ 0]-`/ڐϭa-lazC!ݚnʯ,n~xl&k;/䗲KM& ]ANlw CtϮ\iɯϟ?7ϟP.ﭯc/\pP&CQlVd饗ZN Th? k#ZiT[N l-U2gner 6F0T Α$ʁ*E@= b6%IX.r3B p:j1mZ٭k!厌V8k!SW+I9F$540`”KMkD!5+SLr|H`(1ZHԺ]Bt,-1iFU;VX4zޠ㭸n漱bŦP^#ai& 7ٖ@Xj&:}p/E# zar'=+Q˕VfP` %0RqRiM$op؍S}Wig*Z׈[|jS-t&1Qj oX!*p(֨ tVf|_`\JLX7z1FUQD"y6'TWJ3EqcMs *7oUT ji;S-)rʔ3J$ 21kh:"ၔ "~No[Oƃ4򇓰 SuU.  mw00}CƐqUøU/0Ι|UpӳI V^Wk2J:=e;BAkJ`7410A]eKIB 32Չ2a5D!XNacưҔjFC(V0`qWA^lG)9y#Y*cBaiduL N'oj n`4p3V#˹xq}`ʚ=`IPhJL6$D^TmK#lm"^L"dL`fgh556f:1L( l 3웑1 Y@E^7–A# ) O$qLx2 Ad`0FJFy)1*7;-U +B5(S6,9Ш`LI2?!+DI/⨮*D;b\'n厪~t-+mTJ˭Jwܯ뽲4B[c3NҼwPH+MBBΠ[K6 E:u,G$,8lQe3kNR|f Q>YΨ(h_6VP] PP?pe/['B`XM`LE=Z-bĺ2|U%E;UF;F3zl 0TKԤiLaLУT-_jDH`pPX6 L 6c+KZ,Zքd&!1$NYC0zK H;:JqЙFr&lLd2v:ƆNRqFRckR|b(C;7ciy:Sg3ADj[ @ЈT-̉}י2IF&j$_U!F'TRmWxcRL#M;b tkp]w/`ŦEy zHi7>,V)oh,uKR0ىh݈'L34S@H]v521e @=/`Z8Ż% N)rVֈM;-h#靠ȡDrjN 31$zE R`Sy)CJjRW {cY3:ыOEF-1eXVq~fFɨ?7JvFYZ-/깛d̋IYAո <}\xsZ*NkO '3R:Č4qk[ WA{7Vыd}Rhe\ E#zxb@-ƥX`X8k@IܘYR Xcyc#)åBa=rl@c<`LMc'+AKN1e tl)+cnl%`@O!8+,BTr W5*I)BG^Y=2+ bln̠ѷJFEuTT}%ZD2>JK TXFs]WԇjU6;S|yͦeUG>5R~|]cc-Fτn;oqëOE=@3t VclVHQ 7ַ Y[j,} SըLVR>Nf C['ZCST=uU\+5ڨa}iX߰ЭEN;1x J+Ս~>R{gR26 aNڮZI[JDz-«,ؐHQɪϻN1Y_x Q N<B,vC59!AokS:Chw{Э(ɸǗJzZ1=MB:yB/t}~@]f__dzyUb3-nB`4yzvqڤ1f$<; ,yf "ȋ$gbg.7El4 <+Ly\Ԯ&yX0 b5ʟ} ،9aS "P+EfR]|ZFYBIMd%OZ>ߚ`ՒhE*Y\ۏz1V*ZLeT՜ʠxeWK/%sƯitB|ݤW^ HrBE|ڎ<9 ys@jT\2䠽Ul˳٦i|4Og`X.mf?hzmt7g  ;Fp>"]p$쎔&"A|{s0 qJ؛í#SF # ̩ Aw^3V3 F{n adZtjwߴ=++  O!&)<0Uvt*90>Gf{!z:]wKUe]Ñ8"8]3,neؙb%B]4/ J\s. aduLwfp) yݺWTiw;=.8&sx%s,>txoQbgOPzJVϷ+㵕< `C;sUVX9X0 vA{H% r#Ѡ{w9rI%׸;c"G.cUQ® `<\xcp\pY*4 MPixdWIԬӝ}S2V.ժKLFN"@n!^G3?8zb{7ޚ~4v<~ e$ i!8 a$m3pgh0ffqS 1ԫsy&M#:$@x#! "Q,a+H#a Rsxa+H<#)"-A|E!DG 82C!Vo_{9 E#;B-9 ըϰoH ϰ n.GACv;:芣ms)HpdC\Gp Dzt ̑e"mF2GA#wn]-\v;z??{Cϥpy.I{ W_.>>`"9;( Kt0 ؾeѝyG-IB5r? z^c.ݙDz eHڹB%b< +{I(XJd/J/! W2mP {sy/Sv !Լ=x@^["7SR$0]C@Cw9N#r>QAXmTyHuFO$4Y#QKH+u8 !7GNq| ?z.˧r#؀7 +7qAF l[Ӕ=6|sFNOIm$<ナ]ވ" ˓F^fJŧSsu2GmRsH94٦9j "4c^f ,HB7a/iccm-žy@IfmHKA8/"=$yddL{h O)HˑfLN<ٟ;\9!loq"y,?w^"NsB C{'mD</gg`|MaU~#}=HKIck`ENG>_7;}|mu\v٤(r:vHNm]dhJgAyJ_m 8s>aV}ȈRZT|(ٶZϩj9ͫچ1 ]R4$CA|geYFs9mpq4B8BT1V0׭!:-xx*yg;`f\V2f|Z=?ϱԽguF[ߎkj\}iSm [y58{?\y@CyrV ĉŨsӑ1^^ךh~mܼYwXii{3;?L4 ;{ڿ)tr2׮F|oQ㩙-G?wkhl۶mc۶mc۶:ӱm';9sΞw{sJU~Ucs(ߐ i_Hgܳbž?^lr0yߑU.z>?3XP9_A=ωbW/ o5?o`[c?joqPTRIw`#_WKmwp_LKۿ/W[gѕdٜ7m?z1_O$cjٹ`GM8Nw{{& hb=_?֋wWo1&p"=Z  |V{7﯌c_k(ٿx'ȑU#vS13pw7;;z-w5[pKwgk*ŸL=*_Ww /ߎ_y=O8"߫=d?OC8~˟ٯ}W~u"9Αja3&ߵ&_OMad# ?geo_߲2_;89"γ W#Y~XfFQi 0R6-,̾<2aцފu_aͳWs'& !#tp\nϹZ݇ϷQ_L[Yk#9;=Z[%=-oizKM' 59קTkv+]57Cnʖ3x[t=az>ߧXK.G)>hϗL~[Uؗ|;n~ן 2TdKgS[//9(ٻSu⸖̎s=oy~\e|<- } v{ާ.v<]ue//mܻv.mKkįuǜDv`#w;_>UkǠ^^Va&=BڰͶ)FyWhI~ -O^'&dPG˫"VZ9͏l3͟/RW]jV.g29*]WG^1YzC(2%lfgk~^[~.-Mwv[V>dAk/W],6'{vݚ7S|jҵa2uؾ/sW[1}õ]bOsjOvo{oK7=鶆{%މ#eQ0Mݺ^nz/w[0%vunofWvgYٟ}S[~e ͏\Rgu[of/O-~u+gWzUns[zCk qvqN` ִ{sn˪.d-]vjxmŮKLn}[coεymõ޾~7@U?4\-K ٶE}4\~!/~{{sgogSݯvKzϟ)~ޟSݞ>XqMn]\󮾯id]YC<~y 'yOe_xtGR f,'>S]VաN}A;-ݕQۋM;m3gCMgIҔ ~=!hP|o/FzK߷x՞Q/yYßٹF/.-hj5+Bܶ-c4Ei^oqFvZ)6k*jZiiyΑw}lk,D *|Wg;x@Ժ5-5.ɕg/ߓҲ]|s/?T+r!">ў|^m _bՆgνF I>SB*k\k\QS;^27/OEl QhB.v2g9j|){Be-Mg^mzZNlo5c~nɚR)-F @B}_[AVcًvN=ӡ9b9ki fÏGFji5_8d/@0 _ h]4|iu;UROXz JW^V w* t~rS%|7M]{$ҡrX M' 4I⭌xW%tL sϣn![VYgiԯ]wi#MVr2GaAѧxA?Wb,󻠽/OG7og.'k;wgG^i[U/âN]3oHqw}W>[{KuyNYco>(բ'ayJ.)ͭ?,i#~>Tg9ӛ[QFDBG"Rx8EWU<5#~K[q ^M]s2mi`цg1@[BU(૒%]27aT7}l*a(zӭ[Gk/KdbW45Joˣ$;}p*j˩کho,L00V4EfвcU7U[J&+_xAQً=kQIp=廒)ȆtBy!rQ3Tێ*W$ZRw]JV 1(^:U-eSO.ɼAf92k5cҠAѽ5yL&ؾ,o3=/VIM[Z>hߛ1K!·Q ?\Y9eI'6{ŹwC ät=/ l;h q/mx8:R4k8nuT'Hif>vXehK*7 -gɺSDU!f-!Dp.3fQ? &0,3r_) tLw /ʪ|MfSu+k?J"Z\qUhf ="L 0h^.F#͏]Q WK%G UЋl7 񼪏/O}B=YzÍYpĹNK3 Fr-x{p-)P ` -2BQ]k3s!j% m 6Wև%ʳx[+lC)wJk͕EhHR}҈ErE<ԱB&ٵ"NmP0.z haO_غ|pYv-7avsewR8ICd:+O Qbnv??Svh]JKRNOLS&Yĸ8ПMdiy˳ob%!a5WCp-z2[rH݆Q6D|ѥlJ 4T HJmאȣ0Oo޲хVz=U{Owuـ́{. E0N ׯJE +dyZ@{Q'`!x+)I)OTJ} BPF Kog@Ą]DoR|vhKz6S6 }$D"QWR}YV0$9EilR2>\F! Gp5^+.:^ɇH+m[.. A7y}q^Ҁ NgԢ=&gl-Z9V 4"BJ,E Y0=%KNܲyZ 3ЊQ_϶-X;)A>Y9Q[juIK-Z D@כWNF;SŝOxr}tck@e^hJkϴ^d>}˧p>~>!AE ߾+b/l{9҉?Xb8ȏZ^fh3rH]=xQIbO1FQ0S DIjx\VWp~ mr!'q)DyqݚSy0gVwZD3~\;z>bYHfƂ Q[܊Pb$k=CF*Bl|=g[h:76)6% ɷpJ\7ˮ:"|aѢpRui-RY҇<~T'K/LĹZJjUbn** D#*YIYü2:bM􈩴]cghCn\to _+Jn7t@yuŻȗN: tWz? >>q#y{{zJM%T0 #ժk5_|zЮ,-"nCzYt!ՖsjdjV{&gnAP8W:cYr{rhOp^;bXG6s~Uk5`QqT-Ob -ăˡPFX)7> KZ6@d`ڋ3QyM5FlIdꂘD|`yjISD(w* =+taƭdq[q[/w(Ȼ;DٱY2kNcIz McI<֯l+!fRJhIҕi tJ|;f{]DG?Ӳƫ2"HC0 'ā9u+EN#ъ9\Pʚ]P*V%JMNpA* My6huWȳI h52| E0ψ/YQ>3O%G-e5UE~fSЦ*V#5LdX~G"H|o|( wm]TPȏr7>jӌU-Nx )D4kHL{RQ)g96٠2Q/RKO;r{ݢ' .f5ƕp 9pO5R,n\5]BAvTFmsA\/xp+1sOxߐ3~8W:Zf,tlT%J\¨!qtA);.2wlHo,.A pٍh%wQy zs r_χNe';'+'_b)Oj!Qt7 *&^K"&\DxJb0f6q.禝6BLHbUسAlUb"ѫ(ıkEkG7XmI4CbAe(O=\Hv.DכYY9l9˳ͤ6F˪kUsot}qN)4`|,bN{9b ge£(7i,*M_lxr [wiyDY^ܸ_]b efslƿ7[_UϛZd&.Z~☰ {4Cў70oE- t",`cgT*a+/)KAgeswSQ^dXx* " ܏}8 "ݗZ&?<$9!=gzc/&B |V^g5x1KfƞPmm=I1#zSA8^Ej9$d{ÞlKT榎xZK]rh]9ė //<M&s!+c뻬9/߾gvw^;}-!G7[)\:\ SUw-ES,hTIC /h%P9R\&TaH{E5.f$B6,YTbr hMY^fĔ}<48x&(%ϧsgpv$ϿNF"oՂ{cyYJ`N;q(|GN2䷻%dLEuiwje{[˭iT| qOWfVE+$qK|)J;'L(^sB0\e,JM3:409yy] ls g8pLLFa ~B, HG/5OK*TY*ŞL0hZ &WׇL0*HfUj~3s!GHHW6i-k&'`$=&Րv盫m1ө)SY:~E9U)W҄ý5%^C^IMneRc+n4cx7]Z%JIЃUŧIf!RI$tZ W,f2hd}-qlZS. ~:WbDOaxU5Fޓ \:UՌFVګ/#&a0mA:x.E]|=nozsZWroUvPa8fubi#0s xZ\L1 ^m z #MF]_hTNj)EֶlvZʫUUe{f0vӀ80 {V-V̇&05-*1AҀARν!\4aidK^o f[Nz-axrFyJmSPC`0@}ADPt vR|<^~Q3!,nr=*TTn`͸ve=YMtLt]p!` b . $`;zRNtM@ìQx% X=9V.R}E𪁉#CŅ'm!bv7ֽ5bOo[W46Bg>ֺjn -ƗEԀEEZ I \ki}rtvzqQ@=]dfz[\RhC"k\U{ EךO䣐ZJXb|iS pFLӆ?3:3~nFҤ ,LdB &w FJ(B"a7 uˠh5@r,NSOXI1@}|֠ئ$[$es;LH"s#ψuc9(RDIBZh8c&5}?`t\<2*4yfN!Ey*eA*o3_+uÑ/ 4Jtȧh#3E&^Vnc1 R(\h ;dk%>Hބ\C7Km u=5 b0pЖAw@~W6~ 6لV@BVE`@lvzs"1yY$1NLԃ䎌1 K~A& lQ#k7&sBh֢>"X2Cf2ӡi4Ò;ՀrK4ppQ )!,z/j')(*(5 "2&= ~ rZJ둙W.Bg읃7C.Ӱ!c+4?EF&cE*4_JCH.s4 /uIRϣkJy:ecG5Gk%kºaH-Kcm5mјEN P.Lֵc ME_T̍7L]RkB+"+#?m,g1. [/5,b oKg*Xf"l2M `g,pt Q=R`cmwmT`pKbKJɗ˱ޥp!Q3QFOzŧpW7`Q̄~#t0#A3zxQdEJuOX/AQ&-!knhP3'Y6jr&{cSO#6q6B^fUUH+:zg9WeVb y/.0%R%  h͑bHyYoIBvV YuYڧ'umR?련_Zا9Kj#_""&A :?0&=[~{ms)cey76 Qf֡z9BB쇡<$dwsVJjnVŀ%`p[8`ZsS#*PJ-P*&kٴ%W:JK[9[/a"K'Hi#HQ&b(Ⱦ5hiɷOt ֍>A/&8t۳lc 8CPXefd>y@N-  Ne7.x;mh^D7_W0@leŲ+/9Ꞥ^'lP` S~pؙ:JYZ:9 bZ6Ωr|*խbfy\񨅄) &6n4Ŏ2yIFFѫ&k<8RX@?8!j-o[ڽp:;XkmA ^ Ӈ*xNT1ej (d#^b=.8$o 9,FjȌ9S![,=[_B9v։ɈwgǦH/SqY? <,~]KgE3EV0|-]$z%xo:{{{y0iy^{F]e FmN!qybԪ@rV]m9]I$.X|2^ׇ@ábL-+} 꽴;4Q"b.Nn1q2ҏN!.Ŋ.8cɞG/Ra0{^H,h,0xaP0`#8] lSF y78 *R9m`ۨ$g gyHch+bƠt#ip}M$gT6Ge򥠠ځ&P[[ b"guQ..WBBf/ aڮt#VNrXhP4Clh;.&*m S% Q391@^LȤFw#m!h3%4myE.`:Pa$i(t&UC/Lw> XYGwco]Ie|8hYDL ^4!裦x<kӝS۾p}(S-nLю8I*`"̼o a#^ܮ0u^rV_1pƕjt,#/Ж)\!7Fo-I"rDTDkl֤Q5J )""%ؓ<;<@%Hxuu$exZ iiCyZD)6|]2h:Hn]U8K:i|q :Tnoa=FYB%:')r;nG(Cvj{iCEV 82hƫ:\.kOlh2+ 3[+ o[Uc`Z5ɦo(*x$Lgt5H7$}F _(mRENgXK۠$YGC/1FƬ?U& PYt>P vcl B" o!r޳YDH ]:!pRhũraɟb&STT")+<wnC)"YQzRG!ƼF̆ӒPke4~{h/=kH>4|6Rba(J+J$s){Uvn9Q%+[`We\{eڬ+xlO@06" 7DeF!ľ;#FDP|؞J'j}OlƯnh<«&@<WL|JC ;)βT1AD![. `q"ANxA;; E yނ( i FRי x yX۬C,9L!-0Bƀ@B=u4 Y6-=N]t+`B"U)4fdd }C<*lgpb.P`v/ׄ(@h @2I3k;DK4lA&ȝ/Dnhe&2 a摦=iJN& BLVp=b9rd=}`r 拴 x D$-f AxЦX$?YdpYg- Gc;P Sh|7fcZ˫ MXBXslG y].viCq&r/sMhV@ɷ(+kq:eHt'r{_sIƱY8 R\}7)~QPp^ S g.[.{nVg mD,^8i8r G&6m&\+)oY>NtЍ! \\F;kтN]岒ԠdAÖ$He"YUF:o`e<08"S%LOl;  ZUHnpnq$$1 N1}^`N/uPp@OQJJ%HaֲFҚMU9J6 9ȂjIi2P'hxN '!" Д0)|q_yr׿Q'3Mk,Zl{ qX0\:_,ÏWiZ0TIdgipXZ.$<0=Zd͏478 ;L[p,uKƧ7UMh˜<>]_iPNjy2E`D@DtSF~.QSÅTpPL4'\SN"ߪvUYЎQM$A]ǁE%;tLEnweI=tGw`kw1:$p:nf e:@x5 D\nXY5mYȰ͹~: `Httm.lycD*wt˵wƺ}ٿq䍎k$,46<E|6 Ϊf+FjY۶ ՝^B^ͲOJW`Ivrl}.Wy7u(ˇyGU׶Z}] K:SUen>vtH5PڎK8JK&$7YmMja'nGsCV.̇ΔWxZ]{f֌yh뮺l*Ee/5" f r@h0{K0'OJ/b@}DE݂6Sc"K)f NyZ%N֪syH<$53±! BCDH:}yE[+e<t"#!N ϟSI㦅(\"6|i7qs }mJ&S#5"b)TT!U q}mc%l ~T?ڤrK6kʑAac/1 W912؜0+OW)F"wKJK AXWv n~iI{ 1jU0?\GTZJ9Q6QRsV:~HlD.!pF%D&Y <:z :B1H}}A>ԡtFDiŝz"~ ӻ(+Fqig s>E4-iULw_PQHQLWp2;^<Cq.UPә"+ eq*b-GDz-W$\Dk7q=1݁L " T_M <.w4)GxxFS^S C aݘ|st{aeX86C@Q10QL]iܩKJ /!W*U~OBKm}J&&G'_!xa(P:N0+@NYGNJDN`k痛E/~ķ@m h%|nܙWW 9f̴9rOG& l~]!'˾v!K6Rh]QWRC ?x;i NK>j.Y`Zп1?j AZŽ*OʱCSy+BEkp+"? TA4lPV gY"8t h>.Ĝy_E X1lq)Qz*u>ØgO j!\~z !hqʘ%_#1D$SȈ%wk=-O͵`7t8G~lN{l\u=pZN.ZN}'ԯѓI\By\b,[Ae:,QDA˩Ld */&Pf_'@ivp`$}5t2HHtY`*JvTrqeLJ3GC:\hd/+ew, Kete1 ~wJej30Lp^&88&ۺ ܐ˓hj i jOA3iyPkYYΌdŞ2Fc~ H @&44`1J ^u7QN@n寯D;b< [q9d|5׿at< Wzd Sr_D @az3,`A'% Ćv2Ia@"z t`*8R^Fc٨@REPsjM}"#V"Y)9R{qvIoq[6nZ}yQ֬`C Q6nUNh?Hwn)odiڲ`p͜i(ad_HseM &-啕vűt8`캭L]\ʺRPk. ɖmGPcذYZ|R ,8RsI L遀l3 5s6FIW\Gej@?QlZWX: 徜hdu%_e#:V^i'L/ʕs1izx'3V")B&ۦѫRKeY{ s[S'l@2l_][}S'Ouu2ڈR8oyPc h I25ŤzRCȘCz;jT|7{y'I5>|cͅwMLu}wvO{ΫG[GB Jw&,mR.otJDZFWWB ˏߺg02L82xIwd6褬3}} yW\CKc7f(< [Wszq0gb xJ]V` ).wy!Œ DLjɑb]^1x=b!ʼnIdv`Q$V,>1g.3XjLLy:/)w:s -¸5 DߗPHDqYTnRxx-px|g5YIC1=IDF83}e1E^1Y̵n3p[5{fBÆ{uà@0vA`=sm;be pGs"8-h#>090j]@/QZS\{ON2GY&>,.> 8>^_ .!hF1@5`4 5SЇ=RlBKIk^y(IC X \nLcy1Dbz ux2E\rQld."OG] (KȬ" IpGKճtsMTPyL .W:e[IH+U;ըգ"a18]鲄%LB!$Ʒ܉ 2MZi;FV)^.bu@]~ #:G_*r/5# X|Q(ܨ[TOZ*c?/(S۾yi%tFO@eFB`N@DžN|/Usk ղQ|7tl+)6`&y1S LrO NFƸ9꬜۠bFIR) M]B0qKE`2ꭶnEZ8@@?'4F8&~mn#f6i`Uƺ6w˽ïe:JӋs VEi0Y8Cllwl4/q& 8:m!'^Pv & қTXor[.l|^m-xa| 뛠z3HL^ ,~Cʸ Tp#0Vс5vQk _5Qa1| iH@H8XCQO}Ld971*TlӉ u^D|(dYJw(\^LuI@IOHbL3*ef.j3qjj VB'HdZ)]X?YHP-PGU֎qDo=Gdژ؂33U> -?ԉР|al#Jdg[6zIɛ)mtRsz.+lz~1[ td9J+ⱪ ِaoP-.e "Ԭ*RO|& t#1f@8ăEJmԴ|M|J₶u-29auf}JNG/-sT/Q.[E~\+_+,QIR&cI9Yt;^ڕL諾|ߙxZ,Ȇ։ǖFdY|PI_A$|$/:7UÓ<5\Uϓ&[Ď W>`R)~ѹڏWqݲ2܍prsΌ@- !=e^j!'2!3FpHA2 _p#U}~l@5 XnM"fMSـD`$[#KxO;/vf0 uD$),WsF;zV_؇%,ߴ q0揟}jB{ d7_ɩ f[{fV||1Wvf Zf0 `)۲ge\4 ܏>>uz_,@ΛldE}ȀE>HR>ɈŹA'Dqم.pvft○ y>"5.{/EP{{ɍ/.SN$C *#^\+1=YBF}qvJX- 0OT6V}FsSwYn+ `KNNy">qUai3za{\1G.~}-2u}V(r|s7׌Tሜ[پ 4@&;ja,A6Jh|Sp (k&PDt7g˭ Dž/Mm`kOXj+4{q4iq2j% lF Z%NhV5r~bԥ5.j ia@tӶMn3ҲN5R*=$ uhzㄐXkp3Zҍ0ȥ1ү4{{51JZ̦^iЌ\_ͬ`H_c^rh8z}KÏ}$0:! YU*'ZɸjlbjY$Lp!nP:G&q4(ib c\litݒ6Uc5fߣO"cW#*5.rfLDmWƒ5Ak*IncjƊ P1vg7 -!.|I5'9 &FlƢ%cOdu)]\XbGy!cǂm s~yө7Ϟ9D!q:o;ԓ ",{i CԳ>EB4F!&iP!♔&hjӛލ,vTZ6?4AXo`X=&yƑvRņtWQ$霨vF.ޟm3 z7{'Yj-'a@C񈕂)s.2o$[h9)e>Ti: %إ)g=ibĶ=;n٤ʓ&Ɣ<6&`8RG`)$~ 81+_p)aeh{f%v\9ypZzL{r޹3 C>=a5q v)(v_M 2ZI):txVkZ7hc gByFVs v5N^n>0G=7&uNHLiŸmE(YxmARP'rЪahr9bۤ{v{K]Wmz)Y`3d$nPac1&.y08F*@uk,RCzyH27Y%O'p9?7I_{ 5}6]1rn%w?mi,b:ljnG8?(#D8B8sp R0ӰԤ}ZNw*>|(ot83^.gNӷVp+QE$7(ٯƋrwpT0i3вǝCw@[ sAN&84+*v߽$ `⼸t/#yK%nEyً.bb6GaN5#C{R&UX I"?٫8JfUP 'BQcY1#<(  n m1;ӦCİNHeD 1=#D\p;ߕ=V<Ǒ7YM?Keډy}3ҍ8x]]w4sN.p ݵy QPY&-\hEbMN}:ȻUMͶׅDH"ce¤tp L%f /#@TbPWxbʇPH=(4o9 a(iSiՆeU(-ݱ}ϵc$ZVgDaUXA 8K{Px ki6b>5EZ> (^m*֌(@O1{E['|Lf&O dMãNf;JeU@$DB2zW.\E27hHQ֐@Ezl*NǞQF=k=Z {bBV7uD 鮌nf)b;bաQi|=SvQ!49}UNX٬hJ|ʚ_d(2FƓBbZV 7nЏh+RVj\Cg|OҦ>+>RW>!~9)/!KnPh8]GZN8 r6(:e'$_0,NU2愗&k):>jZTB|P"~6 gTtguH5OKV~O bqNU\TDv|?2cCEʻyfx 1ňTM%莮 a??sŠzt)߃L )w 4~p{0:TY)Uo|&>1[yl>:I  ĞcL+F]6Q$LoRk/)̭vm׊abk.έTy~V_=VUnHXe%ۃY.jT% U7saÂ]uz#,L Z)\3%UÏ1~Υ}>E%˾hIo_yQc6_cx)㜃uke,sYܤ"upxȤ)dGˢ/H|:?WFz%Я'bBQ%W̎1otx(.DdTyܔW[eX A_׊, 26.l #d ɀl#|kѽFڣadUǻ3_yW3Bp^Fyx_<Ӎ(˩M,diHबT20k%aZ52}b0)E"`'knA $;q tN@jtQ6B= 2la]Hy.fzhkÈ~lCp\̔&ƔY6/RFiiW'W'qn{ڪR,`M^y;gj%ot"q ~ZCfpxu7b_<Øs 8?[ˀdtu0Ws.PCA^h|l_4Mtȁ9GU @ ;dR8fN43u6Ӄ5 Q%-d 2iH<Q(cG!ؗ@r ڀo;o.(x>L5;N@jhZ'P9:4H(_ Xwec[EHZDY\hF u< m'{ˣ1iD(6uMMTPx\dXEo<%r۫cIA! {D{v u9\(*M/4FgTx֛_LM_"SH9Îu߈o٨xP/[#0h+m$ZЉ7"vr.f$e^hymRzr29_L\R+jAc;=jP:*@V#dbzd(sPs>%ט%͞ƙEeǶy d1ɫl6,)\h.@ =D}M\) ܗŇlqEQ g.bi%42\P->5 4_K%5?QPLL?2<8ԝN 6t!}ddl6JіcgmqᦘJ4042p'kWx' i>x [ٓv{9ÀphڼQ.xC$FoX @WTTt^Ocdj}YdNOz;vP^b±+xl8`B 2ʙL=BN*٫*60໪v*jj'sS${T G:We&F;1+"*l'Psgc4^m1Eĝ5˰\g/]9 3?ax5ÛCծB2)&/'׊C ֦ŠLHGHNtoq A[dy~ gZ:p3O`t+6}-߼_…q. VlP_s`RUⱶ;&SHsej V̛!؝Eb?RXc@Tq>`ݵʬe崡6uJS{.߽Oay|VYTtmBnhh+GVQ~zJs{7_%|!gDh c |zaWFAM(Ƥ! m;p3R M z/˵jtqТèy9]PnS>)p$ybWJ^ܭR[H":] @( uJ:paˈYE7`?^nlу $B5K4q.X{)4Kw™r׮N. 0K@n{soFO(omڌ%lYHܫ"LRg@ӱB_nk@tSNpKzx> hFsVl=#5dќp"Wc[~Na2V gF`=][) yO%i K_aqH3mk~TJi>z?~UŐNv_Z)2 r R)֠Z;XK(! Y"Aȷ l\=Qria#!eA6YzpȎjՠj8}Zw=jU/Ykf`$|"kNE =n`ņ^!ck@w3BƬsSuVb뵶rD&[Z$f%=goS.YKù 0u'HQB2Fyfo}Z k]Mִ b,sR:U{ d4K:`~=CAYk彛La;TpPQ2*K R;jB^DlM>P N^@ }Ev )q- `nՉ;hMȭKϐJRǠQPPA&giOXԳMmq%ৄu;ZJU'>g!-(KlO7-Ubd!֬z9}ܪ2!0mIrKCp󈯽w1j ӄ$g)uRykwg xĮH^MJpVfQA84_Q8v2fO@~Dv|C4{y1iw1+wZ*\$l|tXL;PT\%x#vUۈnnLK:0OCc!=>?TacCFY&N[_'\v{1)} |/H`?mHr17g6hw2\V\PSHQ_ܟve1#VB05eC;Ջu $2D%^Nf^BN_ZObS?oH;&ǹ^|Mj7 lDGچKzw+jO6#e;„0F4r9uwW4\֭MBTfh޶ׇY$qH۴JuA,YnbWsq{1/B|T '7 ~%7ҧKcTRN:cR-Yq-WBl%/$X+>h- M5('ZTZώ0EYM\e(L#pC*67YsY<CE޾fo3 S]ŦK:zār9U)~M>VnB`uq:~#POY @' ]i#WD ln?XGG܌kf\VӹiGb 'TԸE ˯_th yL^ARݏs"9(}<,,e54n:k{3I`GI zIbNn#iNmkKm+xzՄ:qE0yBH k4>8UAƂzvaÎAZ& gGOv|ǻP1%DGȒ!Zĭ)zbƵg#&pCO*8jNYi5'Zxs|/[M{[,bMmll@!&+BotIfQ@9f+K؊3ذlD́V\hhfRn&x xP5yYu,f9ο-B8׶N"H|/\HEQZ-^۴&t.Ӻ3 W-sŧu=<81t%WYErvGyW]co5!f[Y]p ;R 7U:բe;@n ooCn;' `sU>KoM/}Bܙc!7y ag^u߅&e1I(FN5h] ]˜1 W W$0AM26M ΛMJW7]{cO왁 ;03by.f NgnB禪D4Z_NvVLfEDE7Uu?]9LvO֚߯J1Rv,^G¾{@[A$^}3 , xwC/DAFȠS`TkT}ɶljsRnTp,R#rv{zQJ8[,<ocg)k땡dK2馹1vu͖7 $iDS-XW~Qvc.3aBz>9~>=\[TE!(|9a'ӹڎlפ4Oȵ2A۳V'ib8v2s_ vx=ZdjaM|J^1vM%GJ|`Y_TP||'r`C1狭*ݻ}A>[tD&hN}J*AǾ].k銫3DZ|,Pp/\d{?sE&Y&&R+x,k͙9*}#UY:c$xN2t2Y'9<~4ZQ'J둤w?ӓpE#0h&z!MS3ڐ&R"n jpHo]UEbk{nX˒g{+я DO>%zwm1.KoiL-* 1yp6R]ƒcLv3mƼuRc1x9W:U) 1nOFI=.w)&n&J}<قxw߁T d%_qנdV}7Khy3 d쮧0v3#l]2-*uk,J 32TMm#戺=-믳12MRʰvbPQJf :0791ѼIEȝn J.qT,~H  ߵBzA&*3 5 7Ңp`f 4-d 3S&}:`Q!V/⊚y Qֈ}y (~}F^a(:zn˦\8\H#JwDVQNfR?2oaAi9=އT X,~;=}rLى7HI<=:۞aϑ~{[|vO!g|lt@t??Ū:ոԆ~ Ƿky-ݯR7P8!>vbJb:)~.Զx=ȹnRM͵%BBn.w3G ՘L"M^Vu̡\H;9SdUG1hw*TȬzfH~ (%Eյz\Ϟhq]AN]SOc,cN5j7w {=CG\m) eӜݐw]7<m $}JlJ:v3+wTkUao`\*:~|"ՀNC@,#}i\nM+7xQ^FnxǺ?Xؓ,i_AA !$s;o: -4.mұ^wB,u 7o?F+اԗ8Lt*5ZCjzd0]Zu9I–9DqՂGzpN7љT[t^fgEܒ\SǏX;)fއݏ-usyVWt: f|OvweT+[Op-*8U(\>Ӄ^3:"O&yr'avRi*ƈAO3Y_"-f9) ~zi 2T7AXǸ߁<$*%Z:f$-1dF+WKo#ϜFeVǓ7Pi!UO崪ZX&Sh1.F]mJj*.yQ.BwPNGֆMdsm{^_<wRB}heT jPC3 i"EP5ibQL-gPtg+ۈ[R[Fy3EVk *{~yf$Z yJ'\ߴOC&fm ! abHy[H+=<I3vj-=ژ65<݌ qy3H-ʟͣ0׋[Ҡ?o87 )sj펽hyfR]B5ƤQ?o-Q=t#P~iM~|h[70(?+'n3ګ%䮛|"5Ẉjb^8.̶ oO0 כ3?u ,3eV Fi̶e7d]2 .4s^[ 3=26M޼_G1B1}Ե8*i,MƵ߷2mV¿ [ke ڵt>FiRB3nJƌ8g@q\j<{,Bl6q.80.-DTM5-O8s)z/'ff-^6^O7v)r]{57g6AY:q\NTv' DT3~E򻑳KXjXffw(Dǭp/Vï$S̝.5h,کV-qwi|\3cί1RhnqsOVᴻƁyᛙ1=w jtmVqw4  `[9.mXOj*1lsC Pe_`usif=NcZ=}n\17O{녻I街j2#KF͙qge^.ᵾk%kľcW1\!nna+S+v<0y_nf+ݖ`¥Xm.$9k{W_8ŇK;Huz5mm:B+ *f^S;]?\5㏥Y5Y}ߌwbLUϵOy\ ԏS/z[lײbؑpɟJo n2%KS08TMӻ*;€fnf47ZԌVq[or<6.M45nq #x0M(M&cf9ֳfv\-*LZ֍0nkمCm5cPwvKFb6=dȆo?}T3Sq[јqm9n-VN͎ts%㗇Kc>^O8YtiK3VۥnN g?ldL:"3' Iaf~7eJI1ig8)/!!ZRܘ.6:wQ(Cqc.^BFU (SOf7\N[׎xa(mfeZ7\sciʺ&9K; .K;+KKn+,7ǚ^couij.mʼժlF.?~yaԇ;8s@8r#%h7,$.$wDղaݼ1lFDQ@r0+R}JK P.Y3{){L!d&e#FyS#7a{ =~mwl)6M8kx{l@cWsSFo~lM.T؋M؊R@8v}O險#W+0ScT+VucN؄zQw,U#؟ U?}0ww:佶1ů; %ҐswXpCai&YFq$=2XY>6/##l&D=icLB(#bs]ignsLov))/`dځIS[`FXpچTقq9 eFn7:"e*y)[ }T.&u Mv$Ӫnd]ŒĹ/^s׾'@,Fi=o2fu!Udw^\v`me7fW2coz.{Q9LVjIbhM3ЋkhRèvRL$jLNao:-ί};RV•Ľ&o0&F cTiXdo,t#5Zyr Ukh.xNΖ#}\!lTXf{z2=ι?  agϵu}k3C9̮`ȐO|7*9CK!H#xzc z<4LAE٫fT]V6s(w0o=U"m?@7< 6wc,@S;\ i1x&(FCF7=2˥i8[h|+G׍+# {fdQ罦m:2[ `objq/00i۰żnʼnJ3}zyNC^4W|W<445O2^)q=oՖcGh3FфgMP3N_[\7: >Br:Ɂi\<˷忏AiS>D7FC4āD[2f޸tPR]—&Yy8NoZq<-moZ|Zс Ŷu_NA=ƀ`_{3..)qTAWP.En?Q~.ClEsl:r*^އј}+2>@OKw)'II-d(hX&Ҕn.kK+v7mM{L+VPtXauWx[w챦<;`u)Su^Va.a5-2EeЧ{ٻWcʄ2$ yj/cbg`3+v͇'-[ԌJbđmKc[V!>p5Wy->#_ $ƨ2?V~x.˃̣G5G.o/$qyئQ7{ު8O:Ucx>ǃx?ǣ 8: ' ypX zpt07yWU4-U0fT1>_ غBg3 kKSyܥ;q8'ΔpR=j<~8}[6L'͎kv:#̾<ٷ8.evZ{Z<$!y1zˎ11;F(o#c {v#c}1?FCqxN3ǜc~K9f]))9/3.;Ruvs֤} v%1e,aL\b6thYX ٸF[L.]k׫ c@5Yꅱ }k8J|\`*j~TEkeK2ɑ8f 0JA,W5::P.F3;V3Ocf zq[FN4㨞* xN^A:pU,<R86ly:O&Z2`5짪m'P^e5'4nCs6n^8aUs::0ٹݞ/ `/snPR 61O%g2&X*d+-};O^9@@$l6 K{?pW'vxˋ7>Hԅ׺΢9ɕ"t$̓?y,ͽ>S,z!>&vDU$g'b|㄂bk5YBNP6J!Ew.<61cU=|vɇ'Ԑ/d47,m/ש-vQ(djDs2SSQ4_2,~R>A*^ ~2d@YsP2'X қ"hx.+Oi]sȞR8" :kƮMB\zgO%"IV)}qȬiFw6 l ZmU xxb A/2'EXDbF%N[MIëP-g7TFWL!J_ _6R\R ݰY) h޴ਆȳx`|ȷw(Q;9ቍzkm{U*% ">pHCAdiL‚ȆNǸv5ʘqCwJ¥G vۑ"u!h> Mj8l(ɲ_%>Dfܴ|łNqvr]e7*Ӷ\ݍd-N"ln@|h<`[Lf`R.&2㭞Lݗ<`],#˃.vAO䋱F^T/]G^%%l3n+X6͡ Iw 48:8d-Q#iUg[Ň  y14iXRp:r&=E*yA~Dۜҫ牾 Mas$ ıi3R`"4j #J9Yn,}pu'-e$,>BUę^ۘXf_ ʈ}"XwCl![/Fv75}15>t$kQ"KU1 Ҵ!^:ǥd5PH>ix..Ю[EP55`qt9SnB3]I`N@LST~=W<Ͻjw &JLWd>(kUnSRsRt5j& n)cFJ.:j~E|##ktjew`85mc|Wl'=! g2n҄#H@frew B~?b&-&5 Rfm*儛= #v6OXF`w2Tm]̦jmLY;tBu./{XP/+Ji̕8uBK7rYT7b\BM9{6Fbu<& #>1, He`Xb2L r5֝c:JOX >"`mK{ wsi/ۘVgLPH7VX;6c&WmpX%6[ɍN"І$ajj3]Z nk-v-O0ix (X\M AɣVd%K0eė|ʏ_/%0)b.!1E! g$Kiߪhow/HdMN"SYdl?2^ OfY纈tF*bXuiR!5Oש3 DW. 4Juz'1QY'h+x}]vhWCB'wあ͗Qu~퓃RKDw`'t}gU4gU!yit$Ӳt ʴ$ lA$jjd.F 1G|M7hBJ`f6ZK i_m#?"ԲpP%kҖ2dG)pW c ky~ Fë!st%!x ͩܤ\z99`4t!2IZ.$#H=<`~^wsS+6A : Ek(h6p^hM1Ir 6[o$VwRto/{ [Ww+h`+ȾO2W嵪a5ddeŒrWQsNWlSa Wv)efkD1DТzm+q[^yMIڸ;bQt/_[ګ vw_ܬLo宦x/z~KcE3P8[|ݤkkff$޶A5e!i xZ~3_WxT8YWvwj]K(? |D Onf,YtO=BiRA›7ntw@: !Bh,!̞$AT m(zU#NUO~ B5q[˕hsTuR8@/ǒd^Gbs[E:*vE9[7F(OnjTm4[r^E0Cb 걦L1]W(kF @N(aܩ䟋X0mE+[REKTUdXDݚѼE9|F]x@M;MJH;۔UhVEbx &u_W R\vro|a=63fBNBI+ X4 2/%j.>֘A07k޷(M<-+ lQ[*hOlY(+"u9d`Ѵ3>ү,ó@3˱qZj}jɳg.Ls|.`J ږipYBQkpiKPq4BpQ lIJr@Vj>8 8x*Ӎ%E/&aLa>}" URFU޹uiʷ~`$z]1fYC6N>dLe M]pڲl*CC9'W`tN?XUfk̪uWHPR9]]V^6<)cKsff[qk,#1swE7(Pֹ8&׍ xmS}sX(:M}'*6kP\WѫOZ?`GC&o~pmnP gMXQ H5&+c@TjMHH9%F^xnjQ-6A P'¦IJC1eqM'#{K&d!D!1ur uпK$;0 7杸.CrRѱJyx쇃64RpL]J ui.-ljmcq!L7,XsxT `՞ZhJW1:Br֢l`2^#{loV~ƿKQ[J'ϯ ^U4b [jXTG(lmG/#gGj#'WzE1&F zTC,'7}K 0ʷX視q-P5 vIMUQ.Yt׉t*\C]ټYUNKtE#y%nN07Y@,'^|#gl^\* y ]} E7 Ί1&d?-˴Kk_e%țgؾ`@#``O {e13Φ7#ݍi=@?yL+vdg(!3,bt7q Wm: h&@JUQuQ煢f`ߒ2#"N?R@aPE%uXE_l@[Wta^Eqbubw& cj܆/˫nQdZ3(T?Iཏc=gc3";])-@o*hnyI:BY~(_CYvP]@@a3f*'w~e xmc0;sW3h.gwE!Jf(OuD~OlGӨ;fw$Ikbȁri`3*#Mr\I=,Ax8z'2#< O#Kg|>yGFrp|| x#_l~`AGn>L#k/?Sя~ d͟g*?juJGՂQ ᨛpTXxTc8+74zG툳Y\qиx8jgU69;*O GM~Q,rO9<([N2/01G'=vQA稞syy9*UNB'GM~QQ$tPZzPe:*8+==hBJSTGՃ.QC먶u:}=(Uzcd:fGųuQsAvT}{T;ɝtug5ݣFQOw{ (UfOrgڣYA;{T}P-B hm%/=q@ʓ. i;@~ҾCuPEPItXeXy-|:%9N*T9snN#9L#聟t28O#Ⱥz`h\GGD';8j':ۑ{w'ޑw=O#x4>OL3Ⱦ<25#kN"]qarx7}OyGF~'~"?܏#{id'*Q?5p%8*<<(#4 GŇ:QGAsAdzq8n5:jG口JIOA{SrT4yP?9 UWJ-'INQOA{SsTyҾ9tw:=EgPAQQ}Tt4z?:j%UP)*y c$WT5;E7TA͋ku| eKwM:l+BXuԶ:`*\]Gm؃fQ]]Xv6;ˠ=(Վ:lOmGuQ5/E[wT{P;*5}GExQeAAsxD<'Ϣ9~ӨzFO2E=/W^el-2Og΃Q*zT =I> RUUOJGM׳NQS?Tj{}}=>(>>uϚGPQ~|t>?U_Na?$+AA Iry 80r Xcr[ TO_'cuWJ8Gr|) xߚ]01(6[WխKnj k+2$0JnBtjSI!B04Z?ļcӸɖ7ɏKpzˤmTi"HwT&;g `9[&Vd&Ƭul5c>ڌ;!ڼH#3[t`tNMM6.bJVڼa|)9QPf} Uj˱|vPljTt4=enT):GlុLXmJgپ/c..9u^LoFF-{:w:IE*)p]JI$k#zKxxYuSf.ڨue5ѯsW[`V[ED nI^!YN33|T.XpgifVu(d' ɏo嫣 ޞcsHHHMrMf/?)#60eO]l2#+ eKyE*#)3Lyxum\+\P|/#r5%~PRSU%Je)(b=S5"F]KYZ5|Y7+N#{mbi_*gC*]wbAgē1AɺTfdlY}uXDڱc2+׷ĉZ191-`@1\'4v0G}̓g:Iܴۗ,MdžӖ;BeTyVu(Oo>$[ge{0z{6Qun$2Ì* ex׫IBMڍa~j 8nI4(Y*6*8C'Li a2DR+isMJ. tȘ]~iđdV?$֌x Q|꒐Z#&4LE`5/7(dDŏkZ䒚IMoXBhs}q̱VfC%V'Z+Nz-'q5ʩDl]_@[aE9vIHzK1LMC\KKy t]_j]7KY\*ϩB|<,KǮ34ri\{6\ ̖ypJ.Mg+Q2Xb!F\wl`*K ,KnJgqT]6ADH: ?^~6 תĮ+4\z`C|D)˻^C2jU`;;J|Jo_6 T;7=ļEn;%nܣ#q1#V}0NToB#>>?T,jfIg5̦D^ύ\QS⥕l0|uV6I\4@]+a7yX?Wi'rp,86~ ލ Y 82dzH(4]θ5G 8 e/F) 9Dq 5ƥ~Jh(w6ƉAd*?3Vvp 76 Q<9ut07OIj,AaGFoW!Q;7W)J@ JW Z e3E% f;P6'Ao=pꈎa ¥P^ĭԦ^'VHE sx!N|&Z|(CLa;mui|N{@/K;z%|+$%`;En`  {" ȨvIpI/Qv[T?:bVz()Y'࿿Bs ƢsKiҫ'}ֳI${T=>h>rjGݣFQ%AQM{Qg|>>$?(*?/uOGRQzKZoS8J"tإzD??:W7xFZ!&Iv at? Zdx)S8UcI1{uP܏" J7hBhsy^ɗ< ]X.vŔvi} <x浹ʧ-i*k31l!x znY,7Z\QƋFsPxh"132_>t 83:PX6RVy+O,EvZ-hfꬮ(W%`\?6c+Xa׍$ΒLo7$L4Sw؍TB$H OzRݝ8@#a\vWs.csf6*W(V,PWi|!-emm L,-rJ8/nx\Ź?2vI"1_ 9vHݘ1]\}_>+`xj<n[_ɒɮ0l[C&O%*| M3 `R䮷T2뺵+$*k!3gkgCN!W488@k~;ߴʗ%FBnf4EiܣOOw@N@M,s&T\Ώ1}Rft2ce[o|u=Cx%x].*d\@-qLuDz`B짂M5f D2E uk [:O? @jqGb^ֲ0.9V9V͡Szx݃#t+]3ut+9GGpdTb ZT'{0~>a} %K|\{F_$XXWtSZzF\Ǐ=m%ߴHˁ,CH<)cF/5NѫU}V4gB0mI_6s3Y.iY Jn2" jX]}5yN >r.PnWXqS;٨|{Q}Z:ŵE$ߧ75!΄nj H'\ ? E-G7ꘗ2bACX8(<,# pF|x`]%`M Y+KX |5o-ZYq`<5Ўw-ߜ/j#UЪrl;ZGy } QTBrpuc,x5/ ed'5FfzhdRt8'2cvD}=kq?9-mڔ]W>L1{|#C$DC0B?uOw嘇BY:dbR[A=8PHaw`z1Y"'4qߍV~Wtn)dyo[>`h,us)KcWCtyx<9ONFdk'f_ՠ+ p5#3i%S"~}+}B6 x'hSe9qoKT]/נIV1`'m }opyޏ4w|?~4Е)SSCcǮ^}=g,uJEJ3,[ ;, r(@iJrY ׸Rx-\<+/,W`8&Y]j50j@`q_J"r.Ir9T(K>FCY.C^HCŁZJ!~-6uXeV:0{C95qv7f3si[Q fe ^eܙf rP#j/Ģ"-;"ZF,(4@Q'B믉bGEGQQ)qv 7WmaY?XFǥ Iݸ}.x-H L$f"ds7Ѱ=LE`~a˖YB!@3 ׽8]?MA2 o!=6̾;) ídO)g 3)=;&`+AhGڨ Kv$a;RLbVw=StT"3xY+D s>h{WeR`^KQR&&Q܌p3c19bڱI-qA3&՘&C.hz&X.ݱEG L )0_$KR+GfH+5pD} zc_]ݻXo+Ji; YnM[SBR ]2mw)'IdQ'5UT ,j~0 xـ^cÄMU>`7XS%cqphvGsA:/kSKo:W-"}ڬyh@X%,_:>,/{#>}+f.9JCsLGW e5dSl5a34j aNj9".u͹,LWkw͆ys Gj9f]$ PjK(\d!b|QO E[EeXE,!5h{PfZ҇ %ؑ)mZV4qoV cKF/pqQOb|Ilcg`nfO!XjP?Ή}]G$#jxx]T#Y3ڱᮋ1l ˼; $Xwp𼔛Ӕ*Cˈ6AyR:8V5%.+۷p!?hfn yl^D51WS'JĦ;AY4̂ LJusܖ nj~K2-_|,ũ @:^T[8V!~X%bl/$Qknkz%j eBқ wѪWG)lQb( uz;JTȎe2gAgw$ۃ|Y  4w{;HEb{GY Q,"x>HGyƣQ( & QXK'Thk/xw`O 3Q(vS{^pWUFY334bx<0SdB %7"6CBԥ־ 0l%pvaêYmqJs!?o>x@ 2Er|K[' 3ƙpkl)m\D#mb$Uq7k)tM"cȼX3KBH!eX%C-x{3 8Bۘ\!N?a2o.bgbݤTbX3llPIo0yHr["\~yNÆzz[q;OGi)-hҀMo7b!lWSPiQRV&Ut|Xt!2'\*X~] ?\q$8 >D&R>sԜ!mK`Ap6 8.jzI_mtHх%N?4VElXq6*zH#ziw0NU2!~EYw1tDpH|;5:0[*B+-u}v7$ӫAs3i&DdߗwUMF7Vc.`<.Qc yjH_B\IץҶ 0zi"WS/zh`hf\Z;M;I))!9"g4$ݍ6s׏IsmZ2>eI\^K GhTHPL6&#PCcRٍR^^ZW`ğ'w"`n~eD«L5iTH?x[srnm ?dP^ de2Ԃخ α_Ωc V+ n?֛YHg3> Fh7b<ĂC't u֮}MMkP !Ku)ɸG_D|@-G,#nrbYt8^T·l9 #b@jWr# M8,]H=k[2+\E8/'z'+4h[AD2S󫋂kczkH´xE@1$S3vMp[@KĒaP޷No}Ilr>Mt͍lwtˊpC;^n<#"Tm吹ۚ( Sqa֓&eYk%N'>~V9jAiF +4u@iXRG ccڕ H2Ijo‰KGw̷vN!*EpDO&uzQ,>vZR$a"n_ያ/H.!8c7QLEHTuuݽ %&3Ԡ[>N2TCV$&duRZZWlȅ6_7nQa]4Ŗ92z^Za\uw9hCVn<^$~؝k qАOrȤDsn+KZuKbގ=fD Cwm%V|Tޖ0 uDn%gVcu$C|(Uǔh 䰺a=No-BqlGGwT.ԭ ~rOnnkQ Pi޽!f(Ned(Ab8'hhn.BUeARFMJ>Wrln_͔4A4ߒP{P~>-'r %3mInUzZ5BI1D4.^U0"mthuGNupf0LTqg2 *Ursr\J:VrBI!5=T,4!,Г2SGhsSKN(T7]1@ >KsW%g[hTjee`[ ʗG&MNV6t)\l+L&y 70Qw]+D? Lwe;ߨx 0LXO0"  +ar cڱ2LYI.qq>1谤WvJqG'xT0Aqf/ꆤ_szg);;d'FS.|79Oa8AgsI\VB.nA܈W UkԵ6L ۆIpÄԺq0eoܷp)u2>}DD$T{p@]=+2;8ieZib3b}DdݤVdZ N&br /߆]#<խuu)P86si@gh Z1)Ut`ݨ8i38Q ^S^OCBQ=yN3) )XN\#ti/ HO.zY(Xy&i'F a0w-W<@*53kYգ aJ^n0O|%Le)M^j޷IS%~&`uNękB2kv*7&O'2Xz% f9$=$"5ݪZZE2d i4=!j0%k7yk=Kazj3 7axKG1(Dz<h|̬bW;nIW84U-7=C1D"2 . izq$nĉ#}kA:vwLѫ g J/^XS!`-ΑiΫpGz9=d^ϊePs-yv"q`X*`oT\ `kHdϪCy@{I$MSI AicIԊآiFi ɕ1=`Ո#'_D|} G vy4V%)v>FyÌ셕LANJ0b1إUM}beL0% 5pY+J!(t5E`N0;(dC.:/$AB0b5M":38 ˃Pp#;7*¾,NXE(j?|ӓlGB#aRVZ?U6D*[i )c^RAכ8iwLz@b!!LRWiYЦ3Ze\AJ0d<pzDzbP,AS/-,>oG֌$%rodZZpDMH=~>n=_gy|>Ĭ+H!j~_lkVyð6hvxoT-G 'k31ؚ,F7Mv{8IN`""pt Cd,N/ů{7 vq;)F"g,=%#duF9I OMjsƓF9 2N L/S+m h8 -`5US3k097_F]@]ސ;Ũ)#Pp@J~ 4%juҕss8䌃YЛPm4>\U3#z , ZolKA]b y$kO4 ЍW?,CA{dQ$iheu-pbEXP3 O,_XPb2G5VW#J:P5D:3o!")U؀ "1-WTTU@`ߙ~UhF &87u٢ k'DE= 8w.= >LHf3d5Gg8(,?;o .7 Axo\ C *hqpB!Wa9nAc8 tt3Rm;`,y¼wG !z ^q!Cp |:_@ه@~L?!*6l"[q9JfN]L+)dlAVjn0+n%nk7[f Wrĕ,ƕǝȕQ03s-s9N ]"M8fd3^G+YafJ0wG<9d'd2d=WsjmUpvb՜ޜllGB,N35|2C2O@lcԋb0(e0uF3 K 啍Ġ骧 ;Sd"^(ɔ+ DBq$fp4ˤynT\@s9`$l&g"5Y.H pr B>ʾ ,&58]C4&2jdҗ34ݽ3nd' rEWн~^,I:jU{X5?د'Y;PL y@୴0%=Woghevgo0…I:lWⅾ/һ)eB5,37Cl3Y+FB] _)n41bj&@qƓt¡x7$$L@o`Дs E􆫈BAF"rL'as·G6V6 K{h1htc`wQF$ЁTN+<оX-L)̻Ugժǡ< 8+L$ #,pA00;Cp8C rj W8٣dWZ앃іM.V9ͬ %}%uII׀|NQTC69Xp0 C@.5 X!%<, `T7XXZbԬ,MiA=W J (ڽU|X).N)2UZ$!BJ*S~Ё8%ACĀ*lѵC%.Qq|Ǡ\XO7$1A,u08 $X+!alr\xEq6=Q0%?Wd.9XXJcupـm5&$NEA''TgIrε L4pd$ #, 7Q|uݐnH7 yK}pHN38$W郐vn&nk,k#֖ǐxccH1G4%;&hik‘ -l/&]Ufs8@Ur@j\dA ̐ffHs3$Y!P {Qݶj@lyήuԐjjk5deh[+\]C^ [3 \LIV/+Y ̽PW҈[:ɔ}URXiS(FLœ!!Ct%xQA8Yf1uW4Ȕ28)vRLh s؀t] kЇKzllHL60Нvo4.3f &nRFܨ)#v`['(=$CЦ$zS j{e#Bj Rݤ0L$4xRŬSYJZmqAd+ŭV SmG9b\kؕe#Jz ȟFq,"|ֲ$ôdltbjʖaXٱדgo0_4wFefr~ͤC@foyI0/}t͢=#\H\ iL)Уj{Eq".Q,l%mH4es aE\Vb9Y8l)BEzU"fvƧH3Y$!$@@<6X-A^c I$ɪ vw0CNIV=1^5 !ȈdHbBw2bFЭ YVh\/#n!ŧ Yk  ^Y+;c-ۉ[}ww` ۈcjqj*v"ti [\P +-UVXWj+T}h5Ĭ\Wz.o vH|`<{c-)FƋ^]v.፵r܄;s~ݽ ?VZPj#CeWFTg"kgΆTGVR\gjj.S&]FHOm:R徑/L zIt(v/+U g@Z6 (_V$=_Uɳ7PPDAhȥL3)58opVg: c Q6)TD tewԞ|ACN1{ ʐeD߲jyQ C+t4-IB'l7ܨM=<֎2?$0YM䁠 KV X" {3F#"3~*@FYa52 p%*+_?UEo jgqw/ܨXӿi!DdR,E2HvosDAfv<7̼3lP%UOH$OGR Æ:KՈj|5\O32Ьը[ iI2x8rt/%ND9 pX1RL _;r.]^Dcr!aŬ̞.Tx*F8S)]A8WS)1zDGj\Ժo:Y}2@uXq52.=UUUD=UHij0%- ;Ĥ+aNSY )VvwpndA;{Qr"hݍQ0BiFёH(JûC;$]%G4C1 [D[M&Bgl"#r]A pNΪD%N=<2+=M2GIdWW0'U5 MEd5~r>FhaxVonG+AI*>Sܰu( UW?{njW̌lJh$bL ]H3a(d j `%  E[z‰}SVPa)cgiyU?\ap̛L40ѰV!2y9 =F54;!: a,'_.GʲV sKaW$l\+gÃSp3;spEW CLV%zmVՃO*P>\mFC!N P滐TtB Q%ZR(9!dMꗀA 'EU4BS|7nTхzDp.#/Rx2h0%Y th |7lWr\*"- W bM-;{B"Ux%tD<*4@|E"TVͻx\-W*jns8CdaH RhPhJݤaa5MT19'2_Sՙ_ڈ-+/EeF]NJZeo[)6, 7, RlnXnXnݰ4ްުcQ*6y"<ʺIB咏iAYaeHBĪ UjC@ ^@uX>ɀ L$t~vD0(홅m2 V= `aR?Y]| wXLiXtiX#t ; +!Ryi~1w>$Iu:zqj OWc$q2sYV3Y1\ָl@4{*7!/ ls+>USoAafU|Pu:=z<4 Xi!-jk >u-0HH =*ҼCMO`YR-wa~H oS!['H*eRl |v0 )5Ƴa0=xFJH㋖/:;1){3ѐ? ]y =lңR\FqrQAU,%X&#qaqˈy#eha慙-mE w!۬{(ZBU/ldGd `ա7Ě6FbUСWXQ4a#E*Di*$vvߙ|3@NH<_SSnV bj }!Daѭ ״4:ނrb_|k+XMNJ,Ųl *ѳȶBPRQlYYU`ЂyI:5/-x4EtfmEͦ0"AeognlNtH8C)q~pBТlC4еX"\c0=6xl۶m۶m>m۶m۶}ow{Iҝ+WϏYF9GPg!n4%⡧; @.  εO)ԣD܌vvo&62x~f<=@1Z7\H[P8\1NBѩdpxOY)D ]U ^C,4dқdA})YQ[*\VJQT!^+]dЭ⨏ 9JJc2jCt++{J kjgdjh?  ++38 P<L—$! KdYZޟ.|eCyHivѱ1h 5[\Yx(P5Q&AYh0W.JŃRmn#/AH8 ,{Qi$j톬lrp5#gVsz*c]e 9{aeiw*=IT<J͂h9La 06Sf[+cp`6X/#dݢվMD\5D9F*, {Lins9ohWbNX;Z ߀&%_3|Iyn7l( tnvOuYLI|E9$MRϸTh.m¼٣?&5kB]_gRj#ڮEpd_u~ uOiТ9y;Σpk|萌>v][ ٶ3/dJ~ʇv|d:@Ze+zCA!di!mS'Ůʸm4ˆMvP c{ wxʓxqˡ$[2Q@tF4DG>Xa, ("Ll*utZ^ZrsMQ(SG 3kgDo4LSπL?$]ƅgXc c LOMDz/c\ ,c"<XjmHL}$/).2:pxbHS8Y^mmM)ҩB#"b &1[;`Q66zK$8a0).9 G|UR%a< <*>a2EF͍4hp@I20X#iyAis4A P8 ]zglqTUJnsƘr4U|aW&Vs)ĎːI$cWYRf (D $'JpB짦9!ck5NnUfNr] EK$,wk9UZjs"Cֶ~Ơz3$Pgn'str DA`Bՙ^@5}*9 ]`L {%M'@ǚ îEW" 轥@V;_":bRAB3 98Ht]1_LgHEh+*p{^umx6)bُ HJ &Q]o?dCBdO Xz"\>P6MHabXEBCD 'V]NyK[4 wM?Hon8 'vЎp)Ǹ>gT[ʿޏ^Y˨Ѐ;AD~𮝤$ԿF[(4lCE Rx+8)?2EgBgЬeKTNT?26̱ Cɮ4u<0WN =+RA}ZѰ'QcZ= 2qؠ`n( b:ѓl$>-n1C$.X2y+qPйyr)jQ!lj6 I9~üA8g-Z}DfF92 A`7=/89kn 5rtU> )A[D`~[36X60q< uIK8=#X{dEmOtl 3 x,N}[eJ( W@9NG0vr*&]3дžDO ި)J&97!y1~f@$ ,դUs ܂|"B3_@ ճe!\!сzFj^P.p=nHH `;n b*sdLVSBo20h-EU`6TC[xJQxbd0n@X)U;-ɩQdZ aF͵35&;/vz̫P |=FTGP큉P,W܋M D4.LU=3/ɫbSѾA~0HL j5/k$y ٥V p\7 + t߷ _./'H QلHB]>q,p̹;/߻|uW"QQ1Tܑf1JUC1NE޲=vvYܫ UfsӜ-ڐ9:6D[ӝ `xs&c4pw~*BXLf m.6ܭBôTm>:\T\ ;|Rh&Q+N&W^~羃 H "PxS1`簟 ,ws$\9ڈF"ةJLugc{9Vm^tZ$VfH\a66ON>߷:y)&YȲF{ j$gشZ,c:W'H%)~<>ԝF D XrFj#*V$+\W "x5k]!mHxwR`G2M09?#6&MIRzWe APx^o0vL L:m߻5/r|1ixg+6Q !Q} q!wyZc:m=<$=Q9) {F'*E-, 3ASۑm%%`%$u=94~q(5iEV$l~3[s<`$DѢUTIvB` L1QD9 Zb9dMZ&$"^߬l|k R6iS}{GGi84=<"Z1)gip;93Nwdz( -R$ ѩ_xq ˣf'Y?-QhbO`MH::@9͌a9Ha:šLNpϦ],4Rv')ㆷKp1\*1׋ـBY* EccVCY%m ".~~a5X5CIQǺB|ms Pt`tkP IǻzWcJ4VS3ew_VW;mlO8MS)rz4;ش.D2iRe*V-C5zwI zBg8)S"xg@)&\qz`$nMt9{`8_3(-Y01i  6C챬$Wok 9b?AXdCwJ/aE0hWՎyZ>㔟 [k`lZc Bؕ[o o>I&Cc͠_tEum~ f\ Au;:o#My@-MMboDXPϬ7kGBAVdY=Ī9l3 (ZZwN7Bc` 72*b!l|>ɼA+P?p(gvϑ;Azlz65 +5BbxІ>1+Q ة>EZ?TS,qRT NjA@|v֞>fDR̥,zI $0՝Ptu%*D.HI p0@!j:O*s4ZJ`#Àk/$jp#ݦB$LD2*@Hsb=!rFMƳ;k3?V?xm[trUg54 V1"Qv۟]ON w֧N:۲VZ }*Iѧ3XK*TD]K{0 $8CAm qH%y 8+Z2Otgt'0.cҭ$B:E EI fgR{RXJ-zXQl^L3(0 3PSgdd{HUrҀ>g9Ϊ݉DYQ2G@"*uJtR+e8 b3tB}%Ɛ&-Z+BY4u Cb#W]3k,m:h%r\'^Ȏ9ر+e be"ғ~$Ke;Adg>]}, 2R p*Pq -o<'rF; h*q^*l@c޻c; ”LX{(V6JD[3ʱ2E8ia卦6LKnbS(pbb QNm,As"I67(**CǢC ?I](YL&cx ɶAkq| ]yu`eT2S# t>F9])}.XZ2:uUUH{OmUb5K,H-#b:DFAOC0 FWP`sTK e!%`X+]ze99i<%p.jDb>ً8ʭdkLN ) GH\V\M7U,]!f %`<4""Y|h ][EI;*NzhcViʫ! t;uZgo 'C>[97 nb''Sޢ &RvYX# |o@ȅv ?oXPk'L!YҨDC(HJB&J$HnM8[ @`2QsJ>nnQ)3FDFn3Xݫ򻐬E H𽍇])]j̷gL4}^:V/ EHCfNډq%4r? >T(m$iL_i&va]7[S4pѥzPDf%ܬJRӀq6-41;u2RE7N$, +oɣ|#C[嶑J۞~P܌Tn*~s9_Xp;;uV0)\6w')O۳}x2ڟ#>sg}p9şёw?.{q{էw;U*?QsSEľfOw Syvw[{:krnAw3mwy{_}AL=Oz~q͏ qK?-g!{+W}AWKxOkWo{<c?+/y}}Mq[ήW[z/?n sŸ>ξ<{oC 6owT=ck#y?W=^Ξ/1 ?N7,_qWk41a_Ooio̩'MyL7E7+}ۺ?{(6s o?cOާ?uWxy_wt~￟Nq̱Vc{o=7/?|.){?S{:+\2`<2& 90/> -k}]=~L`:Iߐ2]wrhK Q&z2a.=~jKuu~^?/ouv9Ca[rc/]-אNM w?cWЗ|l#]/;[mk~==?]mowțx޶z7e^0qwݟ[v{{O|Bo7i}mGIlS[kmkwk39'KW$ wQw;WQ]mƞ7@qWyC7YUkQs|a {;//'#zYfGe'y]sIoK|9Jw//wW-z}iߖ8vWJ#IbNf o?xUa߼Oq}C#/d!n/[H%S ^]f]_EW]c?S6Q]W_wouK 4 _ym_H+Vrq/ȒZKCJou7Ymmu/҇rp9azwܫOQggd{ݝ~mc|yu׈a~Jl[w%M|Pc8 * LNl!Cp]f~յ@%{ko_te5 ~aigdO%5Lv%{cH47Hߝy}N.¸(b@POjl1qjʝnL?] \Gn$)ϗ[*>7w_|;a#}B>dпE1M(6+H?'xZ]4ީ' 0{ q@(2s9_O.!!ۆ@tsuI q 'xpDY7V @ zpqA? m)obˆ7/.No^gGJ^\C#d 8p/:\rɽ~tѳQ||Qk\rGǖ$}ǖrb˖XxrS cf58KTMp~LJnpît{~z=/.GȠg/Qy>O{2_Tš!B(kHx¯j{";J;fΉ}RGFGQ ǞH(@~icE?.+wQĭ |ARmU"¦~^-0po֑ciN^poz^-ކEtcL7\ t=LaG8fkL1_o?x#o.wxLuoV5 z&}[ (N(:|eSX%߉a4Y=MO(%>.gR2[+/{=[g3?IK:=o8}IbGs|yz}?W^?gww_}yHCE~CoR _Yn~ے}O;++YuN/u>_+qkmuu}]^/+7;#Yoʏ9Ĺ2Ks.Y216m޾(nkwkVڴ@xQ~,Yx[u]+vUoDn辺 ~KepKQˣ25?f|DI\$c|cGz{vyMr}>6V5z8t#m;++L7ˣJ|>.ixk;ڬeν!2:z|3^?^3{p&OOvw d Z'n>]x]~!9rw >Ap<o_4xG>cϓ;x·|_;#'?#W{;zw }^8_Mg<]QZ:}aFGsw=^;3w_ߎy4y?gK>w]Uiq%yﷷfqQy^!s ?7xe#7."N8&tT/NBѧ҅Bg]B$xIo7]k^y[O$xUo2qxp-?<( xz0 >M v@"_!^x_s?w,C9Iލ Qu&96I3HlKCkf^׌Y8Ӵyœo\BO҂ S&vnW5kMuyܚ~JrKfotˏcKP$.|6-Q^/'s !f4`CDs BE^oo9QoXoYeĔq>vZ柆o1#n<܇S9<}X7IIf[wwlx B-.rlHUӃ|v̽}K%x23ۧt5tFk9ؗIE28VYco|oz$I҆lԤGP*E ޶s |iHS$^՘Wʍ#4jrdn,JGywn'Oh_8Vyc PA0Jʘ+ʟ>`7`_/D0q+9m |5L9oZ݋h!a&AP֑'o0-%ߓ_} 1\)1\Ѝ} ΍ d|k3ЍG߮K]-ûOd0}M9wgRN]ǝ;[oES- tM8PJ2د =Bx"v^zKnQLJ#/V!l2odp4oqDԽw>`1rn>|,sy2ꊲ-1_ڨ 3{2_z(Uxaa,z%BJZiD({+B~뻸FIt0gVEoh"q<]h O="2 7o\S"pӲ4'N 6ʣ"lRWSX*{J:⻟˰^Ó:Y],"$ӵ27X|Z͹Mw'@za|!Go -)<XqJF0kUcnE \1GY`,4T_-a\)/] m3 =G_䷍QMJ?˼jdmgv.?'m L71ϽHA}3H>C ^rqq[g*37rȳ2ڞihŝo2NBQdIGT_T b"n/l=kk>}_7Trड़k ^3SJ * ;IOZ_WS(33m`XvR/}/fy]Q1v+ 1q/6cԋ؈(]LE$  d7厫׉SkUgX.WD ~]$⧦RNM8C|ZS9bEgsʊ+`' ;c\hoINiu5k^SŦߍZ0 988j;IU[ScE;g#V*y^^qbZMjϞ~c^b]N*.12◪"iJ'-AW(_Q\\uֱRٔ9U.[s Dhۏ%eD=I bix&}$N yg^³) ˗HA*]@1udlvH?g:2!v'/^1ׄn[磱^c jljzcUP&eg|Ɗ">2rvvK-a~ڋt*_w,۔MWd-xZq MrbW>-#o?u%_/ i3tPTibݠFGdztq$lcKS^QmQR 0C%cRG|љ,zaUY~~>Q#%lB*i 8ʗdu:/fޡq\ zkJ&,MW;V%Xa#ʗmvGOa#M[ܫPZrMD*~4 {SUk$:Ea&ij^Q| < ClW(\Hw]P5]x倗I9̎1nu2^CWS%vkNn6WTj 0' $vv#zEb[dOe O.9LJ g^Kuu1Z/W2%~}Uۛ@U*6hˆ}E+WƵThE.W#4pL UEۉq7[z$53cܠSŗ)U.Zm*!n$YCFZO%n~"/rNR֪nM P 9|WYݮ T2-n.u&C1;#Šɛ{ބA˅9q:ȥp hS{w$s *+Fu/H_Ih/@qocYL=i3*'2mC/ū\L%5M ^ST/[YUWM!n0luz|hPõy# LRK^ Pfw`cA|Z~S2l$ҧb-$Q:5B<AV}*>ʹAFeNDě-jM]ZC9['I+Y4pz݈*:ݛy7nyO@N{HH[#5:(XS{>rQV1 xgąSlg>t4UQ^mev^J!̛NqQSUV7Ğ(rOũm/}0WSּe=dzaixjWRdV")ϦC2;`vJ[T׷r&О#QmEN!$s>5.(;b(BH0ك[ǁY1Ri+ǝ֍myUwJ$.Rp n{ڝ?Ij"ldLu >B"B0T#ٝ$p4@?as!3$(L6Kuq>cOKHC i?}|sĄ[KR;$QLy] 8\s'/ZKDu{7Kԯ\K=$$~;*hB @Ɠ4F$oT~^:(F2.{Ԅ8smG?]EQ.ϦAX>|}W$zݩ&@_5䁥,+Xѧ% }YlP3/5w$jL煺׹C}c~KVL3s$M1BdmiR< _ĺqk h?06Nڋ=vH 2Wy&D98&@ C)L^OV&:PYA9R29҇:I`X-*eh/ZC!MfqMiiە+VNK${$q>e۲y腢ɇ7 kVA&a77PyGKChk4 xRbiUw\p/+N"?+a!qLNh9eNF12hH__4X3"b?O( Щ٩QM$1𕑛" ̥pJ\D5$iUT$y7^)PV@s!x-DѩL }l<(j|B&uYBPк dٓg[(2sഐg_̬-&dTb>sjqToVP|0CɛD!$U:|p> ׵`.?rSzCcL cWQ>n#cWeCfEyOW {7$z[IT1zs|yqh#d0p\7e<·0ax t?'cȮSJ7خ]q?לyiZ_gמaOߏONܼ7<ӱY7;V5ЭIeo[r؉<3`='{+ a;c:x]#~~X㰗 _ n1>\a#|$i2Dx& \LUX( ?3K \ffW?`<B^ռ)>,19@&@cq7; o]O`_t<$_s<IJ'28]l/ЗCO>C@<~w%xI)3-+;%&^t.q{쮟{/*uӗ[]ݞkǮǠ>A˕y_OI7CiOK䥔| TXx2 ,)M'ق9TO>~|׆ʸ%A¤u\A]=忑Khe1D,Лs̆:dD} ,kfvD};!`=:MN)qZ_~[;C(nG!ԯiYhIukZV qxsUb4o$ jHU#KLv]gxTyUTcj$ !uh D3s+;ӷh8q^"BprTK%,y'cz 'g)t8|2*PwZcδ2{X ܊Q&0  xU^U݅T48SBbMw|bbãp^jɑ`ú 2 Yp+Tdȳ|lǦ<:V"*䖇bԚ2S֨M # &HRy&[h^ҽiQvj/F?0'KR)~ Tn4:PMZ!P?U3 ѧ!`RHkGF3L愴#l= l+$.SEIl\,PjQiզ_s5HhUتîBerxH2~=h䑨(_XۘZx$N Mg/YXDgc(r^6𝝙ǩQhe$ˢVL|/9,tǿoTjڣM8(0x>epSwED ۾D("&׽~y >o7P |)RJbJ޶eW?5UnX(.sܰPd` M٠|Dq~ rp:ZF,喯z6k@늿H0xI2JeFN #5N)(#29m@8V*GoZяö:,xY@\2\q3ZG,!sh䱨 y^ V($ sRSóɉ.QxLٌو#6$EVDA[z\ BOд^l`)݁`.:B(DFZb#pLpz-#*|YL\tѷ20=>~lG,෧7EDUBs}p2 ҍa!'7Ƣe7TnP8`Ci  L 'd/:,#dj=}૓HssrOuq/%B?]YMq{{(p& xv8.|]wJldlbW,kdJx)W{PH @ND:Ƙ8] $< /6AI:/yay8`0Q悀jR +yD@ڠ3c@HHؿli'Z/'ռ@ن ),e'>Z;}xbhUJbmadTT1 H%?B3hEFcc$kXT0$je!ݐM]sBW H;_(*4h9#M٤)vOs%~ D Ay9QxBob9{6-R%z]#e0[B4XV& K+7x1VȁqFHD.ſtƠh@cӹ L]?gTҩEk|167IY/Y8zO"FC48 EXW^$t[ǒ:S5`gw})23sg=Tn~;4))Dq=6I XfdzԬM%Yz M9cf/j)Xjs5҅7a?4xRN#֣j82DQn$;Vju!zȋj{F`vE4ZBe YJi9.ž,H@"OM@W`M8ѨGfEQҶR!3Kf:q󘊮~~VҌ/IK͢Y3-K͞?ы>l<-8U6!sUpteߡwy ƈ'$JBRf4_z]HK `""]OMnU64f+.h(k Her!?` 3`f TIjY| rHH=\F2D w;m$v$2II!<̩οxAuR QBW;HF:Why iQu ae욊KX#u*`̠@֤U>:=mCњ5mo01ɇ}0`%f2ư%kg5y(ahc^VS4aȢfv?ONU.U&#z?}ͻp'I#: Ͳ#ú對JNoY#rww @9!>&4h~(vMr&!X5S]"SR!u~0~[amhnDE1P=6]syl![~E(&ImД˶}(WlrK]f3l@Fh=\l?hX@a>@KMOz,)bfi%^~VS[M{y!1d0 _ɯ ,j3pptR .n)M)ҰyA )ڏB8$6'+=ӑ40FOxƇGfpF6Z"l!6v0{K a``rKS8LM`}nŃ$3t$Td FPb.Nh:>6O{PZ:aNduJr)ɚIb!{m6^6QvL!/#f?y'I#daYNyx 2jƈDl-.fGQ (_KVB`vG9djI0q5$STJK\e䚰%yu 2 uy[mX.v趆TnHrfrY&+H@K,|B]~ѰڟA%P p1=X. Je%BրI^>C<.q'++ ^&L…HBϠB/,B|{FـuczEX5;nlJG TV;L̴ߌByuCLFIVQG9vۛؠ Sw|%/GS@ߝ f-n12lvoFYVz-zC6gyYWH3bz:/VJ\P3mιZ3i te0d1N' ؜OAF C0RE@WL>tA1砯 wI(kF:$,xWO~B=IΓ?*AFɜ #2Ka;*0輀? B4![{AP}UQ3뺜^Z?!wH- VMe Չ,HH4UGtO@p :^{02o~ ;HoFqJ |yd%)^(H3zaHCy%(i4Hoޥ%f2vH _/$1Ȏ9$2|2'l*}68F-c6=`pLpH??2i7 H4+Z$۬NrwV`Rd dSdCZQOwwIfP L`!vIm3uM$A/{O*\~~RL)f"Wݶ@Px4բ NG|s]/@K9@ bGN-9Z" o 5y`~!`K ׭/Oͭ'91O: v76uO8ARz!r,o_pe 5a[JL`\ N0Ͷq\ ޶iП|*3nV^ҽ! }U'M뉀~8[s9_lUğ <4vAt") **OMHoDS .C~?/d쬪;xa ;*Ð'o@1_ P0VԽ>诧`Xڍ$43qoy|BA(0cFn>*̬&\[AFjE$I4Ҧ])5XTty8S!(QgbVpf0}Fv̕2]$ $2>:MEW8O I zrήRX)Յfhl4 r4[mSNCpJf@VgGWU-lﭶ=B ej٘JxSexƿa|_i4`QJ Y߽߁*NgO^gg?/ucϘ6I'K98eO.Q6fC {+T4{T!H¾eƦT E%@t C`yxڎ%[H |C:WKys`{OzNʹƅ*ڞ[vtSuoXfm4w^3\Av3>'"A^SG7J}/k6ĕ?1j$ 6"~B5UBcA@%Aʲ*谒̝A{mDYPҬ;`Z)Zm%d@FOCE )j;3ҭxOB.UJ{o~ءd7Nw볩?&4 *W T;]KS1C+Kf±o<ڡ-f 7$Z3 qCf f1fG܉C81I~o!@cHHA'ñ1mmZƱk$ml, !W;>DhGK)hD(*AhHu:|^5rmyAzEWeIsuHU;J[NTd&O v@t-oFElxO+`#Gva$& 0L_و@_nÃnl>#ӵº6$=quIpq!>k{h9:T+V /D]L'3iY+DO}H FŬF[EW60E!^VRRȘA_XHd>ۨ i\\=^ ]dde* FRxvt7M ^TO#P©d+T<|**V ʼPv Pxۨq4VYs^,9o>rЍbyDDrl ڭ8"5w Oy{釮YT+VA}T.j%/WDұT'qTʊ-2{һ:3_lHŢ^GOZ`^/,dzQ{ƣ},]b>9o{J&@2'x!_\5@g/^޺fciîG E"m.'c03֚bmf(y[{ja5VtjnŘz@HK3˙VU GX= V4m ?ۻK|&xl({zƟ !*L (K_[ɺm9 z:<4.s? d: 󬧦!q^^:BRֺ`U^^Y]e}W%}5`ܮ|1d:$ɮ#x,*+s.XgJ'`cg,#Wh pjfXQ|>OB?7z0HlܱIHjV\p@޲QtuB/$< 0./jEL튅/9@?1 hg_І0Q\L#4m@O /rz 0$u|̏;#P`JuQ"&4K`r NfǙJ`,X뗰kzr2s|Փ4cDo2?LU9/}-ԡOfpgꀛ8zb[k$Eo=[z$<C7W}~Np"`p* ]@T 'atFPdqC5)Relm |Zm%#E:yV R Nnvx'ʼnXҞcgailEe/ab6ƜT@PhWAr٩z bvK?kv tZU՞$WC7TiX̷6s&x [Mf-?r-%odXM\Ho- {|!ifrpՠ&.̑>4x8%9Csǐ3Pc1xuO 5eNkadHz/nkk \h:drB)W5G|2CDMdH3bfeN)2e{ 2#\bró:Sg5V9|hɖm3ͦ8ͨb01xUjmB`B_a%d"@e0q ;@sfHM RTC9Mcd޳ԗK;#0PiVx:v_-/9X=MRŇA~J,ò--!kcbz̀YVmP a..]ZQ]5KQ UZYEV V͎HU;7NImU,5nt3mN/!5)9dkt1/P~]i<Z.LvZ,L<83L"[E ӌA5>һPu%sFѰ(2Au{{@]^Y9AMZT-SExx.ض.fCm/`9)-ڜx40Z-S(aP XGݯJbTe+ )g1~4[jyBV+>u6D<,?|۰ʉ|^_KWmm,Z/8"B #|rtX)Vǎ $-O|>@<:.fx(xfqSRWv凣:@W%U+qR87@砄W)(yz*|rS4>LRUq$Å -AÒ"gW/W˘gSv\zOQc 68v*UːtJۊdqHfHA_qmXvgp ѝa4ʩhta.WYs =A_0a5~g?B4`":` 7uj2C (E=%9k _tYʐB~Fhԛ!LթU:g~> 2*vjă X[>΄NEm#*0NuMlOwg&v /aѸE?gӾ 1-KE ahwRe(Ԩ#H;]yiNB9"!^ka .V\fzR AX(@j IwrK|Zf-Fw[95B.]x\k'(m?gzzЭhn];2/O~jt-8 lZ95ΐ+bs%Sx/=+%t~S# k>vFU3!]m`p^;gKu/Pm.$l =7N~t褠Q=3B&sOlWt!,pc.jI ru9n5&)2t'vN)y^G{fo|a,t dof+G h@TJ~m``#yRS btCQ&rhsF?eLd?TRJnm-Pagc0_ V쏋|2Օ!+$8Um$&.7LLE|iŪgeއ6tgq} .TX0CMw5ťKy`z;1f`YEB)Mt'E I'MIqJlǙ-!Y&"]!Yء ",AP@a@gLa$Ys;c(Q(1A!9[`}c0Pf1z7LiP5gD5p lFRm`>; ƫ c`]c D-rۃ e0m<>e;N‘7{d"K4 _>< PG36L'cqĒ1N 2+W"ڌebHui ncc*mևJ xG35SƒN ͆~w(s;VJOԴ6h(]'%Ȁƍ#ቀ>KEB+KI\b㗈@P Vy*"`JzGdQRZ}=6Hƭ6Ge HN)Xʷe(GBO/>Lg̪q6G΍[,j0, x#qˀ5dc~5~FN9?GRUDa(6 od?p6Kp`y3-wؕS 0éJTNvM(-);BiG/:K<]]Tǘmw#t?o2s7^5ʲcZ@}?B|=,t|+R,!W7Q㻉)|=,ήBa׊Q>_zAt.|gzXI|uZ{7jy`+o"ދFJ)NLzCQK4un> ORoi'=$];TX^AFzp@sMM+OjpnA'M1ElW->&QDbH,쐻kMCdjwz \6G\)=OZ=G/ 0S]YلD8nڸʲ>OǦ'g׿餐_pVIlCdg*vTƴʳձ-XՓ'Q$t˽};Mv_~5-h 1TH .a/ސx6PZzc/ 3Zcά F.ATm9x8yvwa;RJ\[7Z0C>~ƃ*mmeO(k'2j83 8IzX|0T3x"GH |ԁ {=&RpAgP Pg,W2(H@-Y,pS鵶d *)oq/^2FX[OQJ6--Fam"QyU%x\q%}K&{ ;LZ;k=z7{%ߔVnEe)zm8Q&Z;YزXGSd6 q}O4xWpZ '"E1Š$!o8U'7 xtr~>- 7b^=Qpu`a tmΰUg(|>߃,i-?Șmy]=u`LwYY*Ev xP?orWUXAcP>xKl;(FcB1GYme͛#; i&C 0M/ۗN[E]h#0^)5B}Nnk?0+-#[ M,'YcKxwBbh@M~12)Kަ.#00c$9@ _3ȵ:#:ݹsB1 DmS)g,6.Uz;I t38;{?duja>2kӠRE~2;) žboO2X#3fy@=hWÒ0[J@8Y9P'ŇgT7lGG#ҢF:hQs? ő1 FfZ 9#תIX=ƚ$5c2m EТɀkJdVN,G'\~q2 8> ,F:5Yv:W|-"K q]>Qeܞ~~` yσs$nC5?cwj193ϠH%h4Ԍcߘ+9dXW賷W~AxP%-WrAMOֈos!i*бą ြҳl  X|=}^ȧxrAҙ^~5aהYM݋gi/B."⑥d11%zctj0]05.q=;Iu0)5^d ̫tFK~-68X(hZ,xxzq+_{W=CZ{Nͷ EeB:ޠԇ#Y2>%O9FBǍpKEeYܞxr+$!=d ]l4q&(ӉT^}dGڃd ˏQ apj,،YjA$FaDލ_PCA$?vٯʅjMj-(YޒFDx3K?,`\$3l]> w+3b/d- P{[30gMޒ3רz[uPdL - IdjXp{-B^f8jʍx\H΅n0rljczy xRj{$PbȵnϠkpCב2+i+}$9 s|KFYܧ8p É/y"T24n'RnQ.ȾJk:PL)6,7u 6 Ϗ`@oAC<f.]i?3r?ԧt-‚{(3ǯyu:@zԾkYqy"7/~XP |j $?SQSؓ5EhzsZԺݍ‘Ny& QHi ۱"eySr>X(;0 I;HC)wRbRumR#8柲/c$]ОS'mjێ!0z6@pF,}tޞz#I؈;XZ‹J(ȿs'e&MaKP&r&EWqCzZY 2[͑q Ik0im=BNb9,Rƞ<4S 4—TZ@\JAp-`=[be 뉁iuФozq J|2,<C) s:,J 3@_r%5E(8h(FRDŽъEk Mw@+7jjC܎ (%N0l-?nr~sw^֌^1gCV|$4k1*˚"kz1dĎc0G5Z[1%SFJJ(.d}Z3ZF([QTFH[v-ǹًhe)v1@%PӋ=5D\ZI{j#+0gj ^Fה;HxB7{y[`@W0AUO b0cee7m c} ^kM^ ^oyczSjwz/ ]D u8}TuΎpFèxIP<@G+p=_J^ {Pmc|DkV1n=^bO=88\A3G6)ȇgeڴӔ>b KX-ʙN0Kʪjs hxu6J7pϲY"]M"o}5I&QqL # ,Hn 9%~=cQKMzp,zpoι(+J)Ԃx_G)p?tM:xoAi Y{ĬtQ:@)ClPsdQo#Π;كhR7KT]=OS/ qa:Y'O= daᅲ -m޴`" R@RnoS1n ہ #"ѹ eAdwJ}X*#X`e g10ckF`n_,,eOH;yII@&P%̄w3߀gIփo߻(OֹKJ-~n2I$)Ej|2v8X"po$Q'L}MmA[ޡ<"VeH?&WG[~V\)$! WQH*@ y9h0(HfFm6hDy=P9dۍdsDr\#Sk˔SG$'Ҋ~'pT J VivO׭[f3RnW&9?GxEj҃ k`Am=L^q +,m)T f7T kWY_a`-wv{R7| ԯf@"@Y3WI-{PmYZDz-D _150&ԫ'_ +xH7oq7p˔g#]QJFg}GQpbJxE@g3"5نϵ%F%@/VmԊ0Xgr]o#[0B, Di(4: PDY҇b۝_϶n)꣟Oz­f<ίg"{ۏ[& .̓W4 osZ[~WNw(W.whKnĸP;uE/voc[oLi0uzy(zPrW:Jkl oKic|@f4@#Fyˢ%U\9i>AIcek'SMn*K"@Ar<Zl}Zo{w9֖֖c+Ju6&0؅'m,e|5um:L복s&&#HB_crJ l=dJq3CW#F>fwoJW4_Q+ꓒb8}d1nHM@?Ju-P^9ٛ$iY(b}(RQm n}KNW[ŬXtѩ0 G%Ta~q؞4  ] =>= ov : [6ҁ+[ p N}Fd`߼'~3r`XWG[ ~֏pCz[ΘtpM_JaB(#KآWh9Hy\V |ߋ " ״Z[{A O-4 ܥV4|%s[ȣ4GV1A"AX3XAEf$Q#i\TiCYШ{#`#9^@i]e49#j`4NDv|m9c".wPIXoVy31Ӣ8?]ID[*s?Eo8O|{ y^旼n|ҭ *^Ӿ]̕*m:9 g'( 8ʒӨ Ӕ"Z|pfI*@\ Vi 2 t9 %ؤzP`{^^ + Mp} ~3 MVy`碀blk! Я  7+Gf ģ>?RM0='{:A#4_W(}g[ץh&@Zׇ/3qOÎx1^z#vzt132P_PR5xaph]ՠLV\el-&*YuWZRj^2rX]'j5skZy]緈NCv6SΟJ`MSYQVm6'x2,Y:9^aY1*`g 717eB (y@,1q W=yN_4BhєYdulQ_aYve+^:jgB֒LGeVNUHɭ΂bxLV%t6bFU=3!8\ (6YE\@q&r{o]@,&#‹-mE,hZ>b7*jq=HAB\-$fsM Z%ǞWn);˫WN#mɗx/NZ>Ǝ, .Mg,Zrj3f$\թHPGN#8Q@|{tȣcnz[yӞNvIPE2M1u {T&ࢢWkMn#Ht-J0[*vfRifNѝ:aeo$IVx*Q [ ׎3IWm\-}: X.1W\ ڃw%[T,GVp`DGAlBUXԀ{CΫn*h,Aol"@t*X[*խN)_`VSo_ ,M!Rj]e@/PfmۘXqXwiFZ[AmNAS7&\Y' F A^ ŲF/ʙYH,rQr"wa*')Sq%`hr@[Py:x׉2+ :(1 {pfI@Xg.];8sA 3Xnk v,~aF YO @dIpn+rg߹7ԾYk$( Jw=<@pQjC1D^,G~mGyK zF$A+: m͔p1iB9CbBj1 Ytl4'R`P^;˵S1 ֝ 06?&bGc /ă{dvFX" .[V8,AadnykÐm: $v/k,~MؘVG x."Y%KQϳQU);angl;-FF缬e ҨEk rb_qvc&zVg~,ZB&/'̞ܛG&<&ȕ4ψ]G(h2v`5%`Ei`->/ng|LBCjӳFo"ds%])k!Pp<""+X7ཛྷכ۠Ql{;2(G{36㜎<[,{/Idqɉ78jR,n s|W,[D@ve?i`0^7# ʺ-#jGW[&;-,*+kZ 2i9d`/\08'߆2Ƿo$i>[|GYgMya5=e4GOu|FA'mIjyg7ֶ+IqgTZ`m0 !*QoT Ԟ%'v:]sf BHIn,sߥ,izekb!~B;e3ی4LJص(Dأ"8PNR كff%Ovηpѫ KN-!nYOgB{{ڮkE߳jqMj1 QϳonR[dݭiErmhK&4 r*gޱnJ\]AJ}f58\,|SsG7g{ nQU|Թ#/sC.agYflNxԏAȓ*0NW3'.>|ƕaV`S,z`b-QKm--? @ p&=(:A@~ɛ&1jnChnjʉGRvÒ?7-2j¶s@`6:rZ6tTQ[YUH'Ȣ&RjS3?$/CUm]@ IV`n? a+^x0IR+ܾulu$4/m!.-է/7B:[6<̟3Loth)xOdzk ъV`φ) 0ռUkt42jg7= ʡ/GD4ۦ߂ [}.90f, ek3xYi HQ(bӺf0 ?oF/% ͋0ȬiT9y6a[7;Y}!kb'ٿeב#7 .2eyY"7K*X!6Orp*qQk\Ғ^GيfsۢFJZUC~dy ȹh5ܸQ;V6"%vOuZ];#I{a_8wP{Dvj =U9qg= h!nh+Ԕ`MYԝSZz'R~ JWPJ0{oժNH@vZƁ6|/MNb \Ydd~YZ sP h;Vk7+;IFZ)یwΰ79u"4? Y $?P+2:&9%}C=]P?ό2W/)De, hL ѕ/GZt3gF>҃[ISZOk&IGiJOn4Gq 84_JfR3$N@k7ĝ1 TVkrY0+|%{vHŝdhz[3r^LA?0.^|/d^`.e" g0#rOֲ,]/؋'u φ2^DN<P`<(!} 2R"%UG63cz@\`j2ZW_҆.$C0!8t{cVR 7 m3 7@~ An%s)Ge}R,cuG!u$*w\kD?|ҍ'uS;c?˿Ge>򟀹Фޞ9#;|$3\ƃf 9ˁ̃\wR|xtl7u:^f(/^[$GV$ڃ#=Kє9’]a/> az[h{u! =R |I+ MdX9IkS;#sl ؅ ͦ|~q/ó9ϴ#9AqDcI|k98{~FA#rx)X;YMKv( }7ct0&}!3 . O\LA@ ~"g)a H3,eXݪ3M־.رթ*SIznri[dxUW?UKŖ)jOz)" sT`&S$t֥o06z/,uۮpi7[mcWkycN  u?",pƖbK8H8ݹESoA|RcabW9[hp*i.b_z[!QIsVi)㉨H/5w\K&tY(_ |eXy-YXamIeZ:8ok]'͵A%R̈u#vkZœkפnb-{83x Ti'k ;pǽ5 n4Rpco4vNt,uy7_ԃqRQW66MZ&{daˠI\S!j!f#QKU0C ۨj+z|n<߯!]*؞>fU?&݀䝥ž?(4TZ+h m9M@UU>]jj,xMzGoxf5:^ZHklo[2&Lp]q9 _F_7/߂ZjzBO|!@Ѷ jz#~he|qj'aW,g 뮜ԁfOGړg{ ;yǡF p.\#ntD2'G;y"KL@Mjk:j&8cpTz "ZΛnrxdmivZEjy9OA*AI@[+rmam n)(}@ fm)Ͷyަ}MyvOPOr,-'5Zv(}n_ sMt9#{ɭzWcZqyZrhŅ/Z@>-Iwл5ҶFN@MB®3f /MU6V%.?֤P@E4,d z`~+6{@@oR.*ŴPlG]5-! cB*=P"u# #m:U{P8=էY8#\ xQQEzPox[uo-/7l`8~1)V36A|I]`] P;Y%ezWC:8V#K/͖/\xaJ`P _Y ߴU۶]߱sWR7AM-}kex򦲨5 T*|S'Vaz[9Q-L[{[6 anj㮭+y]yW2mLC_v9n٭>V% .I&W wHN 5%S.]`#{Gsu-ARk 5Dd/iprLO(HɎЫ1U(O儣Kp-.RUPB)Ym?U%yO^'gԅx~nDxXFn"Cl E;Sx3߀$ƀb h\ۇp'eh7?|Ӷ^ˈMVe{Ix<"΅O@DX-bZ&ԲVVXI?|AFډQ-Enn0s^ L@~Ro{ WSqHK8QPZ ZC) #UkLaWP#.2^Vȟ JS51dVLM Yr51ifS78kprnaRK\ axS nFcMOf熪o Mrk ZMwl};+ u0+K鱂..TKYRQU'Xu}sʳ9~S|*>]Չ)sb/ %i ,IU@gi}ۃ, jB@QN=.fJmSG֗+-Q%*(TU;Osd4hͼԝ~KEۭC ܪ:l~7-/K&ei Z/iʤj_/Xe3@TZeg!? C0_{z.e]I~6XuV-4j/n,scpoNf8[~~ 'bmccnCC %k ("s13RRX+r9=j?6: k W1G^bx}~-y?;=2`/"hז;têCU}@kaIKkm 쑏Kg{ `k2H3Um}e7E(z c5K[~v cݧ5En {Ziq,V7*&t?ŽKⅥ%@_uGwR. SPX&7O#V!z x &Ք͉.\9Q>S{T4e]@*uHs ̏-3伶JU#kfJSKu)R~Y\HR{[Tެ;RI:(MgT+וtbRN RnEZhx Y\]]XLѫİ,?+%Y1qE?B:7#'WMym~E~rUjk´\d&7,>&|@azPxwMX+c=Hu.$l1fnLC46r2ꝡDQ@(sj¼cT [V$AB5o2"6C^ A7Qm!TZRy d)+4}ݵ̬͝G{+=^OyXh+E93EU<'U)HU6+ڎj >Qjު5%V4-*bVʦflTV|A Jyl+Kk E0" :(= G}~|۱?7˨Xt|7ݥ#L+۶߂ 1@q/˹ް! Gմ*[.uR@\fOgs߂r,?6m-5_7oNR6~az eѶ@HV2/-H??bl0|q̵!Lܵd|;YrF@z8Unuq_] m>"c%PJ͢'$Y@ATT:jrW0o t bwmvw>翚4:_r^Y "9Ѯ`. H2a]*l@tBвt!<~uYuP*-9 $bT@/ON(2? R@ >­ =* C 1m R͞emz;:Anmo=(p%j c^=Wz['tIo+Їk):1P4gP6&hpel"XsÇIK(iH<9 VļWO9UOM̂WD. Q0쭛 H:E'm+/umߑ}tzK "_f`!oKphA1m|[\ɯ,QeaO} ^J`2R8 i7M#%lq.驔ru%CB搾e5/(GF' >u J=(8 p&rpD靠tg:AE5A\ɢ -0b(Wa/uwj"5O(ܲ~ 9"Fm1AGobqZecQEn4IYs^$ 19$݇A*GWG29+#,s;}vmF"D} A=x7=z]zY}}ۖ/|&t&68b5)^e~֜qJ`[,KDAGRMH%ڪ3 \xܧόQɀ02 \Yޮ\ ~tCxp#=>^ѣNҳ7:ziSOJ7h*=D񩕯N)tB.'[t~VgYJԹ\b񋖎)-h*ukyQjEiGW~3^ۊ;&V:-vaaV) ;@aut[)BC[^cV^eM_hkS6:ArbXmLn]\sq3,kA*‰rZ/"[ ,IcoQ (D⽥Ys,j Jw٬ RGq*'jEg98H%3MgZC]V<-r-iʻYFXUrŨr==P-> d˶R@ +R6?ރf X}[o9鑕,mkADgmHPKK5ۨ[?.{ž3cU3V>CXKi!q'㍶fw]Wg):T ~sN̺:],#˥Lnm {m0c>. Ed_9=,԰ُ Ԙ*t,_mg+Q@ REuxNj"A`ǬrK.gqئY[ ֆjuU5\A"%@"׵p~&ݺۥu%}X=qc[.ע`if}9Z3$RQ=^lZ~?쮐@X1;T>nr;dOP[ђ(i\CY  weu9o} f:0Pdrl˸+}Dyg[fw,ڝF<5a9{&p`*}3.ƙu4׵.i:1؋3۪$[ `V\dxû] Cu[]K0u%)+=KCe,G685nxuN#0̣ =hm \Q~=;1=8y{Mj"pc81m8Z]R|{5ڣ{Ǥm޼( U^U9l6^,aKFJ6yHj}ݠ5 v_zrp+rFi,2wYyaHyXsnx_W>„ΘӒޞz~_wAȖ4x9._V%Ֆ=N5X~yM^/%y[뗒Z>۟j(ҨEm$b ~il/a@!^Ao~+uG_wqك,͖!RFcCsþͯP& ?n:qPڶ̘(2bTAaSejriK,lZ}xo+folj-oAlpKmZWkd,L2[-cGVbu6"[fYƲYSükw6Uo'e&}4`8oڊZD^z)P<%5ȯp~C T5/K^:jdu{~c@T/6Cd4nc :V0r8M X+"ki9ʪK+m8VpA=ZINw:A͸#r/Xz•AjZׂKcSaml@/1?mil[ÇGџ+(έ46x,_:97Uz>G;=}mpk: a63}eӊ:mƴԧ-!Ў%.ZŕlKD챁QGs|ƻ.i, ` \pjO$\Fx4̙e6@sD/E<:L?.-qÞأqRcߝ>dnbt0X^.I|7 ެmi198E?bBTSVVZ#-?t۵adfx]3ٲf$4;5f@D2o+.:]ar<nq6QGl@cj="ǭ_dI qZ|x-yc`!4e]r ~^`7 ƙ;N="6guQ# Œ GF>. ~3[ReԴn[X=mƢ0uuh^- ?͈މQ:(ݸECHC,0\ۻqx,/E!nLQI„Za"mnf_qÿ}x4#~7"6/u?kIfd8QD1A_ zU"9=^od8Atki#8]U6Ld]a|(JoO ׆1h餍K%ﮩ?7Bc߁ܘEQ$6(96mBaUa$R0j[O׆[X{=>="+Q3wi#ϧov3l+oMu=:FGt[Z]`n Mwp׼-:^v ]_rG';͝F7#4ϗbw _Y:Iފ35Eiׇ/BqܽDQ,F;ŽkCS'>˙QŁC6א!dQ .XduڣՐ ep؃v| $+hVDvr;yH z |KC\ .H&=7p׺jѽW8w \b8LTҮIEA JS _=BgMfb77a@{:x(]̾8nc q0YQ<nv3[0}x4П6zQ{naQ3pCC8uHuN5~`ݷS"~ >8'u:|SCOY?A sJ?G5cvXwxMr~SE^H Iw]lצW* -gj7a;id\F|(of16`Wj4ɖIh@4N.z]ku"Z3Vb-2'h61feטe֓{pƀXeLtmP}٘:aˬ04S ZH<3v5Q(}Gyضvou=^R2MVt f/l.6 p`"fnR}njM1: a|x]٘-cj,Ĕ!wspL2&7v hhW%LL*]Y,.u\ݦi<ܮf郘F<7ŰeV1^2ksQ^nkڴvmk/cQa׭~GNHJ>FQIU vPY̛\].sh I..J|8+۵j6HLeܯ\nj݌|#F~W~m: - 8<6/Fvm[} 9 ʏ_j3Ư;N|nWNWA9V۵\(cת4]t|(6P_ŧ34|__&lW6klҳQD՚Hv9;=k_ 5s_j )'V*1/#on_n,#2NOGW9_w/_/??_먎&vI@\ht=1J&έF$Ւ( kE!Jё\lP]-N::t\,qb:$5Q 䴩M2Įs'PMXQL8q[?xUbMT!wہvF4`!^'5rJ37oaa?p#yG/2+-КX\_FjɨF}& [-.2R]oVL4 JP`ZPG|M ҁtgl~RVlbZA7ec[ƉLG41*Gg!$'ƺa\HRz㲉!7Ĉ]8q-ZR&.̈́ Py:qM={,*5,2z:jbk:y-X R鳊~Ҷ%IYڄ1 haX4;~_dʿ̩ʿ _f`MR[IMP-xoB xG9ƒÛ7R__4B뇰g$&hO)F+6Rq6˓ xG>̃ x9RA&xzBIKM46Q~h~5[ו0%Oʦu^+-6DfP.YfG 9ڭw#by⌻^5d69UBY/|DFRl F;V^ENsA]Z uVq=6ǂ>"ݖ *.Li ٱ&''ґVs^kk-P@=簻mlx,wl*u@6AQ%P,WcN>r?H+v̛}=$UG&FL=7GUE?yHr͊t fU-l;+bٸ{a/;*SAONˆDN,,SG:l /+Łq4GQ_k:=kNlal168o~&rfZL@Me;VQœkohI 1ho*QBP.#/8E/C27#oc h+Dp4Ρ!qҏ&`U1^v#Ea:>?U|3ʲǕȞ'L͋/o ghU/ j5\1+k@̶D]$fjk((B(PZF,i^ݬW$ud^]2',ߤW1*m4J$_V7U-ز> '6q}ԇ:RQ͠:.X͢&s6իf,,XZ~C֢jaLF?nhPEmd`yd0p$< XgӸ*~F&ߘ\S:ۛ(F08յllYrFe^w^~H/\56zHRcYx:ϣ&aMZTq߅v%<`'5bu`)@Q G׎4;,%N}kP=XoG ~ 2c\ٰ>uxGsS8R ejlTlh_7tn2R8QQ\8y<04ͨGx!1dKOz?_D+ 6/p0M3?Xb9~cW7a;Wٗ,C/ ,}M8 *ZZЕc3B*P}U~025ͫD5FExazC+mz|*PjeB/hela CShU:j,W7FqJ m㵀l3^ek%} p6l&uN1Zf'KmVΊ̈9q՛}+!+cNXjҳsZEN&q1+y7WQ 65"j;;z/ݰ[dM(Rj xB~CwMZ O2L5Ä=܊(2,FYFjw]%vKޒQ! X/$GomP[y, xe2`Й-.pBnG$PG2i|гGcdӘ*9Sǔ cP[#D ٱMsłWGВ ,bg!Wji\y,DBN]2W1 1'uƴ?MlƎE&?XkdZdÌsz ڞvN0Oc*uxMfO}WṟCG&vaO#݃_n.qcݻV ӷL ]֮nO9:U-380NvTI3cM6 nh!D1I9ڝWB(zQ!JHbD>K[ЕofyH#L/?\w2cK9J7b$zwS~ͯVX8Q'(MYoXGtV7cd&H#?s97wKD9)%2vc-ʨWLjLTIӛEvwIh"Alˆϗx[ B фT`vɿ.hF0s( nAS]?"hIdj42m Lo1*ˌS.]ȡ9=K#kWm .w4fYʠE놅FrpoPzPQf_B[e@V`y)' mcuݍ+Ѝxu e%~ًf~0p|~6{6ѐ"t6dpÑ@' ^,8-ndT~Bt٘[qӼ=:^B~-TXypcD-,E֏I&Zy#Hn^FͭyߨKM^d H#25fE(K1nA! gX)CpWF)4 A7AM IY-p4*&ErsT& inpHikqY4#Nwa?(QWŋć`Ծ剆M8CTHtueHg),ƫF)֠GRT3)1vn z"IN8vhMp-<4خ.jlxpcCQiro28ۃ&$K{X,FCeh$B$o6ZsQyFۻ~@ΐ^~wQ@W6SN+PMPU50sԌ-WcJłDCL~%OI^hy UリP75udr]z2$4QsS>1E+_ 5р뇁Z{(F/)ƪޏ4bi{j͐ѰCbBԞW8`Ц_tǻ@B\<4GC$Oі*{Qmϊ3VJ [J3ITSZ&t=d^OpIldO3JvCPxo"=k:dNbD.ɚDAmz5f4 Bj~qi|k[b\ J?"YbĶ2d|9G1/Euz46ow̳OP2m*YGxNˑ9lP qf7nkʷ&UcBkѿEƣ o7?ru{{bf@.V{q"H)=~*.3<}q>CPRƃ#y ́W7B0oȅ^".?z jbc wW]q)yU36 qeHb H*&B&O=I!?yEQ)Gm8}< nęnԕ4HiO.Kp0rߛAd.|WY0` Q*=&SFGF'`ÁJMS;VDnL! D7rHG?X2r0X B~q}C2ǚlB h ųZ6x >Bc̒ C}-v̐B13ÈXŸYl暪M7:fU Kh߭r :i, X8*J0 PZF:l&F 4d0x3"dp@iX?!å⌦U̬@l6!ծ̛/?V/'1ZX/NPjr := .T<ڎ 9? y% AE*MNl8gnFQU`iP~o8vULkF>Q$llzHQ8DȐ Bi+=̈QzxnD؂r 飙W#I5,a[MtYgA[y E 2*t kסY40j*i./Fc+NA ,&FR\B?l\͕[VShFC1n{]EڲlUEE $%|5KFpmbdbWwnbF =6aqg7uEpd|&(fitd]Q\7~%g,Dmɰ*eeoFuzq5תm"7ycj-A!MhOK W9uDz/(!M0"jP QpJ;'$*FOy@b!kgbl*,aa&Z%#61tW b>6;4ɑy3^r3N]ٲLzQ! Uv5tSw͖ʻjYkhI~F$(bAiM³`a4>)jjm"j^Bo?܍՟TuAkYR6q1ӳqݛ>2Xabis{)Z=&1N܅2$0i^4)G!Ń>p& |$y:#z0ŢJmjLMkF?) 1q*>pCƷ]^O).?^? 7eZ-GxyyǾ|J>B zdңF&&8PY@DN !{IPE 1VǗ8z[}ŀ 15\xD=hMx~ Yθ<<2G8{sP`T^\q3*&`(a4Bhlk9 X֙^Z*(%WR"*MdoG)v7}L:~ڥ($ aG2nO}8:W GCՀeGEDU}Zl{{ӃE k/Wx?b阂9CB_}ب@B) ֓4= o&ZwcPB5 ?8Pc |_Ss*}˿>_mNo~_7?_]W7?zmwo~Wۿoq~OoǯĿ/_~˟o!}>CWoăV1^ !mS#5SVY+8ZRn?{u?ɍg7lD~U`NЃra5Xho2shzb,3hB8†nia}f!8Y@{$_4}=n ǞւZ;'^hTRIU@rҟǵآQbe>~%ܛ=^ PGAjʖU2Z;(\Ȓ60ɡ$7kL[pkt"F[ $JkzZa܆s)YrгTQaNMC<˄g_/Ց<,v zGʹ $:>~a<t7$>Qg_NX3T{:J^쵐wϔCNy:szv)Z=gNs+aDڦﲭP"fNрl&px$yzU+BvT_7)diՙP#b;{=u9M~6 s&P R4dʂ+i2]q׊IGJXui`TBiEwBuRTI0Hd `$F2H2=V0q`n{2c_q`\&`q^M9L,ϧMQP ]\ggfLU٤LLZf#hл*]n%G6hol9U9"tӰhVe4'T{oxk8wb% / ,J"LY*@RnNn91 *fOT#H VG=# [l&wJ΂fkY&{1 %'DS]-,^ WU`z0,PZNy}7/% ׭ F?؆F߮U E2, -[~EbJ`u81[8݊2#aG9u&`3 KHNk“:6/F ȁO}|}3R$Yu:wEN쇦3,I=wM{ j= STT}0Gjό;Y5#Gq NԏovMAWDoH 'L\K4ɜoY͟׺<\qFs繨'~ kS_L`%AwMFH҈*Ra6RL/㤨RDR&Fhvx~A$kKD؍+2 HvA]~臖AVpfЏ endstream endobj 78 0 obj <>stream xq @ǫT<:%`B{˚\VG<x]QL`ڏ \s.9kB_>p&PK:oS$};/7*,wp\a Xkq^}YeeIȧ jڿZNRaT$ u"/?|x~~w~S?-`Y^,T?=voϻnϷOD0Nx ##2 wĆC+B>|GȘ%rvϏ#EwŊi/'bd-|W?'jdFD8(#vdM|Wfwŏ8v^Đ E+~N$,%l$y#5]1%'&+%ؒ[~tX_Lɟar:Ϗ1Ye7]q&k{"M;XϏ6C|WIxqbbwĜ"S FRE߃+zR߅S@**ZyK2ǫs#V-~̊}a;n1C¿/#V8fhRH&KVݹ޾ 'FBTE(+6˨eUvɟ te H w[16-4eUK+v5ӑ?`Gi&)2FV[[I8sQrNܻwsz@O_E2uکf\XV$0MAEKS 悅$U-2jExh@PzyٴN:zfIH,p2}VkKfY!d'՜v7}`s V=r_!b}/ҡ/>!=><2lU%z_UWd*E᭶"O>8٨ԣ_,YMITz9]]3X$XoS4or1/%hx5LfUa;M$Ml.Zs&d畬 )ՙ֤,:B.&;;(VEڱY&5PKhbF4EـESWĄP7SpqF*פ*˛a9jomUăgn#KX@_-lVa ꁉh@4*x킼S/5)>g%ҁ&]X\2?C$#(^d9DbGͤ\er YkMpBZRE<Bc|`S#PyE=dM?X_0FυXr5Uڍ\nTv`aVN$K2lv454&j-A1Y׻n]I3g 9 -ہ ߬-wY{VQ#\Ec5sp)'v3f>Xj!ѣC+Xx/u:X!u-4 ؖ>͇"k>qjq!8Y4ej)X-܅FMw)//N-43e0m_E< 32yU*@y~oeNJl_^ƵXľm_mZATjP7YORQ2*6WYZHHXH[+׋`+>K)*ֆ3b-jnևkrfY *j)x-Z}C_}maJNuԣdO\4!9(pim<*E,Pco@k-^4?PExc\[n҄2i^pW PZ MRuxr2hhάW_ԓ AE SI@ 0*|ٷR+_NEHsy$]PP!i<Ǒ{4{0۠~+~}AVaCp|"wv19c.g==TSFWN3&;@lqS\u`hýoN-7^+~7_MM7YMوrLۣ"&U&H^[sK:uZ$wx\L {W#V̒ΊVb݁O4u U l] $/9#H@Sj\*!8wsq"@aB|6uL~!{-\B\e]uTYH \J\y!3Dx`-GEkC*JN+IRs@\GYQ(V]ulv.>3iq|eEDT7^Kv w]kpQLA:ʰd枕QNpÃR'u<;5 2}Qw \BeH?oyo9 eNC_^>U\<8G}B1VEHsRj*}amS|ҵ%,f>%35n+Gjw7`i![2"ʼn6YJ~ȉDW ;֊G1St('tm` $v"16@.b;+jN\_/\'G}kNk+QcN O`4ouQE;l}.xOZL- 64(j}F0Hiy {k6g,q0PAjOGE^Q%J38"g͐&;[bQgd,,<,v^$BVa,0&ђ/#_/ȁSEm:i۫nriòKe;\\H̸O5er*&$U Q'FjRSk9}}=,tBX&L֛WWgC rL+/?$Hl6HSo5R_4 iD;tDyY`uTNg-*_:6\W ߗK7fMp^?wb?~(+6WŒ/9j][q5X$dPW+8IH8Pf;}j??}9BŠTY O+H*b'j4SXDe]/8I&.^Ƕk.Ovzʳv3.g kP\`u',>m4ablą? E~fQb#صRBdT+G -Tm yERHoZϓޣn|iBވ:u ^iNVW2ٯ6ʶaT`b VTJ5.O[ _e*īfim"JѮC 294%eG~[7 pzQ׬ig55swF[tj潎 IB bi4?)x5p‹?a®'B8ۚ?!\XY]؀T?)O0P@p2H Z3]!gdDbiQtZy{WS&Q"q X<"H/"k\? Oɐ ٚY]'Z=kcș-yJq_sJîT?9fm.2XF0Ta>H(nԓ`JV'\[*0⒤#d*VF1Z3rÇdXCiHVNo"|ɳΙoJOF$Vm7^WM(8AB, ^57e|Fl`R:rx4vN+}ڪ6՜Zk쨅 b*ڬO6ot!*iм-3.hު(zŊ]PHWRT*[.!7UV' cDB|5`'[ÞH(KJ':])}0Bs,Ě97[72xJlfpEml=ʫO+t&Fa z9]&ꓷ,[]LE&52f$w̧o),S=MNXSgJ|' yOm' A#ډbLj%=k1SUNt5ZM177GH>bƾ6_߰*ͱPhl F tY;?`UC[׆ϫW[|POh܌j 1W@ib2S%e:eZ59Z_вd ֠. 2QZ;\(%ö,dYbA[I/]Nh( ^cf+ɲlBHtZIIj .8!EF'0K͍ Yr5> &rDw؆j;pQZrꨥa&d&2y5ϙg%]Ee*]\$P+k=CoraX2ݚ̕*RIc_{ĺ?dE%gß˿? ?Wt ~$ "HrKRQhxIQrPH04^56Qk9ffIs5&ލHf'Ћ9q'ͥxM..bW?PV0D<=>m zbٚf,*-B]F=*D1uCfq}O+1#x ASlgLFT>ޘ֧23Үs#Q'Z``8 _HM0,R)BΎUE/t 䎤U0#]%%ޙC1d7[Z&ѠFTRcAEma5(jќ94S* $Vh7(MVAVO^y@WZ=RpƎPQ9a[MmKNgSy2kyrWtŪ>TW5/+1hy8-Ek)tV'֙Q[S8:TcdՈnS \W(|N'ef>)44IB<3b#Mm_vdž^!2:ɸfDA֬Xxkka\(ys7.UZ|{iDM4'/h3sd2Xq2BW vajGHװ6B˓guOM˗{NH} #UCNU/?\f >k"Ev4U h7m\^Ά8 -!E *b!WvYX4ݠh\6Sgg)oI BW3rIF00̨Jx `oCJ݅,^!ĨXK.5bHQIbwGNF}Z,:hK dk-Ĺ|qW/\^7 9Y]iIxtt$!rMЌc(a}y , ?P YH\VuM`H!AT3HF8zf=$ ;3- 7prjkFHbq,* h=vge{8-iJ{@D7J$"Fcv`2m2i5΅Ql8䷭dhg'g*}qAhmJ^ҙ Ȝ=,n+@,JF-FbBiyyKaΏm0vMZDpϲ٣cY݄o0+Šܜ n`;4Pz±w)9yYLˌS!_|5?f͎!҇".۰gth;`gFX@m_yCle92fZ[H9oxLH6㏨dkH@/2cCFSsW&V6n &H=¢׵^IbQ['BY}N<5CݤbQ#NvȯWjƎ/_ԥTVE3^gNN 0q!gļZdn|DcwMeL&5j^Bu0'EV_*UcÇa<1sE+]jWFB-4>%Q|#hB<Ĩ٠ 5\8eq7vo phu,K Jc|g]h5ʪC3`7S:j麊Y8&{*@3+6;D hɕ[xnJdq=YHf_\$tHJJAȅJ|P R6.Z; 04e`\[pmApTC^(S1A{ښ [P\1y\2Ű $ð0KﭲږFO^y("Ч7H M0"*!=/-y;ʠlAQc-;=aFR+7 t/[3JjbwDU:q=};q#C½@&mQP;hH[N'id]Mo<{_vmbC)^];Uh} A6?rִG+#PX!K]H6 %[ؐ$+&3U3$(+m\Y _l7b㈙vvTp4;,˂O p(rvDv@Y3* GdvBVs.$ܱypC)!.*YźzW:7d#}Eס$d+\Lq úN-njF+ M՘ nU`ֻy@"0Pl}.d^Oa+{Fe)T4V'MMW3⤲ !f:tJz!<\~41)~Q@"nR*iض{ ItUmQP#1KDoʪ0*HD{FpxWl #$){E]X;BKȸAd8w"xfWaKGg( 4&+W9|2nk\/(el1٩gԞT1kCQTUY3DM ·16%!%F<]K͌S/؛-np ETI٬Y& 72O`3`V)+i5_x˜锽XF @MD2ڮb T)p:ˣDtI'. $E>7mj,&k LW̠ΉvOe[eNպ%ؾ+ޒ~Qm&YNʼn˪qCB%"ʞ>phZj97I,wLk›v?ї&<.K&2eR+RV;H^p.#ˈ*]d/lj\pnp*D$|& ho1'?n6-Y( 5BӖJeviP|8*/`NT<~l9+<[NkMtS7ӏFR`8m$O*MBV ZMWcř}`[T$q\EFH'yBkɒٙi"W..+- wb|U,Fb:qhL@;B!رbOz]D8 U n61)7- &H+8H:jArn81ceܞ K!/,S'gz{Fn8e4*T؃t>5ÕrD37B a_Rpj n0=a2:Puْ*١VfnU*G_ rrjRDmS.L]rކ~8и^7(F2 j1!2`佣]$ױ(A= )U8&dyzۊYwĠ-A2rjhK`k˟*A'rmvZ|*hQ{5jcFI]1K,8SWIT)(Fi?\|WSEjBMq9-Đ_vcjFAD @iLJ NJF&F&djk Lvr ?Ϟl(BDq5V .x@qbFtI5åÅz(vR7v Q=.:bFȠx JoF^b=h<@*L.ƢG㦏aÞ8#w8qh9b47eS)fO^E=O:{;plv3b]_X&p!gV=YP%q ̤r28N rjGGQ?L~]FmpWi+/6Tx)gі{#K\)h*jU9ѵ'nk"W dzxwbsV8f$p4@!;A@P kH}@\=H bsL1;Hs6 I '|&jA 5T 4u +s ֎}6GN~F1qMRJ\)ɹi{!YY&6C%&$1Ss7(6"[PL#9$6rvMEw'(WiE88[ R[/,#ЬaF 'r c`!kPLuzndfm3'K=ffO*(d8%.(wʢ&;](ۮhGMr6FDj4#ܤXZqPH- fTM\PSJ\,R gʘ/0M4'EhΌDlgJ[vG R%;9˝Nv^!#y8:3Q2%9<DU>i< # 7\13z|yF/Ɩ g:C]hBsq28^* {-o#^ }%NwiW~TτchAӨ fDц45co}rgRjT8V3\U0#zL ߠKr (^M254\Cб}PCh6 >Åa2885B 8eH;d86z#;lj.P6C"ΛZ  Qc' *ѭFJj!ImwKC}A}XvW Yvb(bi@kXm"抌#!a{K5ϫC0R \eP qQČsJ8T9ZŸ́JM)q#5@*݃%>#1ʓm,1$!WBrrPވb'7sokr=}Gx;t`caCjsDeɁL"V2g` k]>2WƊA[ 1l %iW`4$_vO4;בe05P}ikV̪@d*ƭ"{1Z kjgN^2ڍw' fXRǰ}vM9h3~ G VN`r#Q$(F5.2 NN $Q|l2c>h;zFQV)޲4FRӺCYJ8Uݚ} )`>X28v`㫰Mdž頌4?{1%zX\*kSރq6jjB^+sT:<&sS44~W`cCnb+;qwi@p"?Ue4!W2+YHZ6m䋎 qEUP' dYC3b"]6b(j0)-.^'x`~fÄں\XuJ C|Ζ?\/E~nO}ix  1p < L)@9,oMhӱ./-{1S̩ƩNA.\ݩϧ;M^V6w>c|&y_^Ad7ūt4K`z'ytcwYaKxlbL; zѐf%oo= ŚAWۄ޳$p1g+Z̎o㴠ְ$Xho j _k?~wʡQ ln`Xwi*>"ABĊEd}q)ܠk-FŨ=jd]6zWȪeg"p]t\+͈zӲ֡9K"],46j˒G iYҶADՉTmRj)xhd >H>ҰʐS⸵knYI04Ji.}4Ku~>,'9i2NC)00vϊ^K(Xlo276lu3M*0:Mo7j\!K\~&UU .>8E`[H]bVa'H[j{#hcc(ʟ"\4bX6;Qϝoג|%" No̱@E"WP8ovZSQvSvkݡ]p>qYQcag5qբJSF =~j󈇍humvBZ5o*J~̳NkҲY\\x+v$su>YЅ4<8-\;/bQ &IrX,} $+5-$oU8^vFVi]u[(Le=6bGXMR,43K%1(-jgЖS%?YR51lT(i;}=1G,*M1-͡)ۣ F Ga)]pc`֯]= ZV-q{Xd'-#(Ho\052`\8l~ T*͙g~Bƿ@ezaHTl`kpK7U FY7G!0\s>fw.% .=e83;rWHĎ5uR f+% .KMW]-FQvGb{5twUTZ˔,~{&~: f( )=@2W_,:UO|E? 5@snc=G9o7UxO E7|s5H Xf,  e˪܉͘'i)N#T%aVm~"]N<nOywɿIxqŎ~lԵ#ݎ5e&4M̼Dnu!PDѴ(p@CHucD_Ñ.h'Va]be.oZjOk NsDlzU>ÿF.D2pp()ζ]`e>uc̖4=[Rq%Ʃ@}@b"`<*ʒY$+mY 9`P7ҷ}Sa̦<2H{n+Jqȭ,^'6HHӣP%1V+FxJ۝ʟ\n_G"hFNfft+HN7xcl TUK,ѣFM; W{垾 S(I͙‘̰=L#8Y}5X;Ki%՗mKpnߺσi]a5UԞR xZc'+.ÌQad`c602Go$k %3b>.%?SƵ Jjw>psoL=ك)J6;?B |*Eܼ[`FTrnY>+)e |SF,m-:~_eG=*hR͕D:{='(ǣ{8Ε'U0*:N@NK+A8s3]ﺃj;H/* ꑺ当S{\Y))!(by{g06wv4T;uwVE_dP d֑LɌEV \,RxZ/i H~&{k|v-mKLLp_%b_Ifoqr f+= ҍiGԚei ; jJw?n|*ʨqki":92DǷ). U6V`kYl]n<-Qwqua_wASK[;eJ֕ny# U%_AMM k^Oip# 9'?| #Pr)&1e"1\MZvg٨0 wcI?]Bvu_FAm:s/g/ \Aj| $ɒt>ğeu[)xV+ Vr :W,n x`xS~A zl<㪒;ۻ#haxW(7#7|[fE/)fϩqaR`[^D3lHi1-*Wnϑf6EziqGAK=?H7V͹tWMb3nއv:ģK]FWjaxrbģ^x HLPL WQ=ՓøiR\q6MgJj$wY)``<0s!#Pǝftڹ3{f#̝ 4UO8m5gլ`?gOz+Q1)wZ}*9A7ybSRL>r+53fX[tTE ~BJٸEOd(-O6)Bߏv`kdgz\6֨4vOIm5rڥG+n;eqw,pYɦyΣI)07'Cĸu2t7s^rAItX`ϙ0+&I\a-[s\-:C` ֍qxAV”f !r}Kg޹Cn )o.?D4W6z^| &惲`)ȣ֖wS -B:!˳^$G0}@Lӳ3Jm6pBn1`}+$RAFg>V!B zuKP)AXzv;J% &Qa_+q&,Ed+H ?`/"\|+8@QUcEጰ2׆h.mz2AP`WIf\mW9;*GQ$[e?jfCIQb~ ; QCDG}RΖfk}0o&2[a[ ~0h&w):r 7X ~jk>IiKmdќ~( T.ʚp٪R Q3J&ɖ8Od9Q6#`W9*x Ll󛄖vYjKŔ^xf]ԔD.<+k,T/{F,Hϰrjbv[ Wܞo |AkiyUY w7L,VNf yQ39 djat3Q_tlҒbQ /a'1ۮ{eܧ));v/U?Z3V~u YǓ;|aP&=tVP)@SF$-S= a/ɥ֬B=SЄM14O]ΦuR #ͨe2gwWXԐ4vY] ;-U܉lƘAW0Xo)x:oS`:e)'7پg? @q]"EOć9pƶ,s?lhs:,6~% 75I [i hj QUƶ؇B90EO+φlߣVO{$/d@4 ^K}lW>![ :Jh/vC$I'L `17?ly( •xel5a%g#hK$yGiZܜT,GAEG)dFx =I l0 P^.]d "+"g^N܀9Mr!Fbϼ~2^4YE">°$z܎)M'v I+UJQNGz(VK!9(d_Wwg}gI:;;V`l65@r}J]`H6<@tYY [wϬ(RX"{PH!xBe5WW6?`\+ɂiL쬟NO&g(B=KL1zfzM`]mJ O0y%DR)h! ΔD7CA=Z(2سȌ`w^pg`ڑQaI<⺶NVQPhI0>TUr}GU+TY$ړuE"MǶyO[0+c}=+9c=ʯKǕenw36~w:F?i)2ҎSWSc/. \=tq$/)8Z 1 ( ڎ4O3H3~)5#T~ZM̷VS#e2ˍ:/Sj% ,u%{xo)S:;Wՙ[ 6Ҳ]ݏNg_Gamm]߳.9Mu;Cp"[1.͙+@\Ng5SdA$гTŕzřJ zrH{f|xnO_!rC0!vzdF.!#r-vs]1Iqz a[wa9Я˼#znCr3#C™f40݋UΜTɛQԩF;LSlR)g`/cRO*)quv=|4Nlyl<LqV6b?F]1g9p'mc's҂8$ݏJ)6j ,z=\>-<" M:KX2J,>.嗸& c ~v,n@b~:C1y t3Ӆ>kw5/3(]gnZ|JOiB֠gsv_`C٘EGOJvs $dW9'}TW1|-K`WZCo\U;OEvvABOuޒ(eXv-ou^ኌ,sp*v%Rxf ȼ[)\ǯ\Ic`mKn8>N+)n,_BQwKZ/zu)1[QvhOA۱dfOXQ{iMFݶy~xJO>*wd95\$@7I028݌%% z^5y\ZhKy'L*ĦOǞ{n"&N픴gf6wz̗]Gbc=ۤMR1.)n0<-w sqCZ²Εjϴa$Qp 釳#29s;Y9cL]-޴.ޝO(i?>b+lJ),!iL ~h=%skm}%L4RAyb#e;9#{:5^".6GDAvH& ":fxQ a =Q/)'clO~j٤nP+W6a+1T있m9VJ%Z!WDxjaf0u͐oaaBFJtY)֛R?Av l.~ȩ*@RkCVB%u݆]ٳ!,,F{\e:ܨ"\ Z!D'G{jnU]Jc0`dW.޼c"͐'Â֧b`*Εgt_@h)c0T2\!)aOHy0Lc'B5 Y"c0 )mgR$a(|?Qs@Ox:j&Ab챴/fidZ2ئQ+t׬5|C r1sօ<]d~QZM?0J*tzE}eN];p| 4DMˏ#/賨^m̷uf&ipy%MI-ւK6咝 ]sD?&b+y_S(ā kNnktXBYT#%\ZzޑѱBn^k,.ZܑbfE:DXp̖%n`Z[Y,qf\j{WD&@C.T4:wB8Mdžš@kwP`Qr\fq-sX؎*aML$#φP3)J| ZuBo;]fJ/Rc[c q^!ڛxzEà "D*M8N ]ԡ{ΌIB-y Ǟ=eQKPs yx<,%w=mζek-&VOpSqMD'c* ̼c(j9ADl&R;gf$kH:'D^:S?^.NNkڙn_vSMmgzء;h3jO;j8?:!!PO=NQzqf&wB$k 92>\:{ׇc1RwD>.Ek7H cOGA'`Vt'ߕòڶB2^̰M58;w{IduZ_#܆uh&}B2|iN \fQgIe+_i*IA?wǦ je,42D6U«`aP];e0Πjz.JcŽ|,͡l\;uD^% YC8ޞ ibtgf0ڻQ oiWԈAi(pxJKw W I`o=w!x Jt=ESEDx3;AWмS>B`#$;&[/#r>P#]/Jog0<[T,!NULDHo?9DZ PNX잩>?WޘV 1%o[ͧǒ%TOr$/sOIx6b0AS>m <Mz{M Cb|\7&Ln^XKc K6mC }L^|W]Mw{-::#IN{߾mDXrSt'*XؼUިȝlaMd'Z0:l끚2f8QvI m|UX4@[[{l"ITBX3$FvݐVlm\§P^Ύ,il6>pI7#8Hi*J?>WС񅔋%n1dV`r7?\ټM5rNs5>V7)[UC=##bABP@&?8{V蹤JbrJRYv«0X/d~1ll54ZQ7dk q[%x!bh!IH2hTwҲ]ۣy=o\c4*:*iscւOAC=i/gA\e' PhhE@f[;Sfqt/""w`fJ?[t}_;mSB]x| Tm2 !bgJfS]d̍wP6f T(^n1I*"SCaKN{,6fw}x޺ ~7 R#Mjt1ŸøU86)ljQmXm9#_[NEQ|UQy(A݁ϸeJZ$!~p-*Ã2Fx%yq5g0HU]OAf yZ<0,}L'axjW-4AR\c4.IQ8V@`L&I,K榝-[N7KE}ʻ9j %=C )qM3y!=e ft+nzᠤRt{F!(~iC~1ɍ>۹FU+Uו2wCAWZBPE8p%5pu Awٰi,nlx0E%&Ʀ>KرR-G,ڶ?R ܰ">.p4ⵊpaH9.]llזcX7]i2(N79l1jH"g$Qr[B߅ }miv+"fVM_4OV2tX6 F$:6}~O0"ss4C;>ʉ.sܡ$LI21l~V+3s5+hX{zDh1W#B|P99{{rUPU?}ǶGST*}H,ђ붍A+ F)cϩ oҳ{pANT?m?OPvUaJVO :24:2~fi=ul#_<g%tg"^q<+&+)yR,̖J÷xSHŮܪT;-zL s NGSuNYҦ"ЃJ"d$Dq4NFP{ h5DlVǷ]{ng+.4Ҫ[q@`MJ5. +3,.0h6; / O<&$p8rۂ1}TAʽT9Ǿ1A7[k&z5R%`wXnU \agہJPW&XIt! ӆ%0*GO?A]Tuf7nrvA#b)%=we^5M.5bzKy>㇙y%Z `AKi]#  Ovc ,cBڡcOհONIEX|èݩGdsUOlgk8T9kZBvN3 Qta+\tژƕ؟V8h5PYjQEm11$X&_%{X?#5*hТVUOX|ΑxiKޱ-r/KPt1ֈ290K{-༿ J Cݱ(ϔئtս=gHՋx;qW-%V>8T3#Vz-H1_>.50]mݡkl 6*YxmY:܌'r9 zGG_SG_ D}++xt^QuS* Vb?4MN;YdFdx&n~W#jq`z98뗕~fm_{V=$Y"y[$]'[mx׈];w](XA"ZqB ^ɣ=8 ܇,N,4@NhUy $ >™*T _b7mor'aO7:#_.=Q)o'`3i8b/'t=lJ>a6Y_vpiRťd{qs \V-NzJQ)+a)PM1˺.$N=G 5M .-j|vTnF'83 AʝN;-ׁd>sRe4nW3R#IiM >%sB~)L L*Hƿ1L4]A܆n+t D(ӳ$J:ȔůV)$=O pX3|w%9< `Sf*Пf N=3)maN1oe]D<8-.=$%Gl](=+krr6ӢE\Sm=72"G1u/זMbC5S6k5Jͱ'~C0JClQ~e>,?8_~77#2_e) ,N/WMOP#㬾5MD "6v(D0dCbpuϡسSveF+AF$@kC⇀lfesM/]!@ gjQ刳RYlz,/8*̳5޲Ro5ϓIvu#o&.Hq< 8h[SNcGNF-+P;U 05ΤEATF\|3j _ ro$ew]kX(nwwU-aC<}JL 3#uf90s^Te!0o>P$7r.b{)^lizޯa qm)jUtg曀-:S'Cq%IY kH1N H۹zMFe%{ecXW!^53tc>8N)p|je el(G2BiDRm[Po`]=?Y7t޷RB1AIRw1ڳQ$9u]m`/6G{*ƳaSG6Ï&>i>ܒ6*Ky?+ow1syg1ǁ/#h;P/9$m{q[FzXie&:p7 Rn×"cI ܌҅ǓLbiWIMf?HcPsʣY_>+,hbj.1M;kr'I5u|F 0{_R]r30|Vܿd.!l:*#aڌ[ݳ8Kb#^sPj63t = 5{"RÑr;~⵰ΝRu<8]fLQaЛ%ůݐ@79gWӸ R 8=AmZc*̃XrdvJ=v /5>;DZ%$9Gg|-i)$zN(mn>vuO=ֺSx2}Jl6˦^sEHuwp*haAc[R 4_:Bޗa)%W2 xNNkwKٻ2sA.P{m+yUA8b5a0tY"GFiKt$p^C!/mNFvQ,*W= ާĝ5(SxG, ?I4`eIm4\j[nt4Dw5{Z~rקw ԴnHSim}nTp\>I&Fi!_ib/qY9F/c ꆴS MocŋsT~^_ѮsO?s) ]dW}]x wiB/qtEypsئp~<`W#V;7͵@ Mo ь$OZtq3Pmt`<] 1DT*ڡ/c-3cMIl:v!8+IJ 0˭YīN،G7R&ǾC[Loѯ56}g|`ժ:z#^WOE5+cV we:W+}mAc/ާL!c9(%:TxhE<+p2nŻ:C{[:fViplǐL~ĦߥQžD&^  as[Q\}-2`ɧ:7=PhD)i)vg ]NAlYgd\ yR|o=.^\3i<15*(R.|* J9°I80iƥM=0 c p^iYrnJE~ Ķ!-3~p?Se;iBt̿6JqJH$DnfX/UlX,{S#"p{S/"2iͿ}䑽՛c5eE&P(ѢfDTUIRVI ThFeRf4) m8֦FO&2"(2˖έò $մ"㋎@㧛}g"doK]t(aX^y@i9u`ICDEe¿`QG,:3}V=O1wV[8A U5\m!]!5I·9B]G[`[\l-xb-1ޥhSԑ 0W>ӵM.qߪrǞ>^a$$^Zc .;xނ6ڡavڇ8AC]C0VB켛^[q@z4eXE'vх0=ׂ*3~ռ< ^OAbT91ȇAV"b/J.\ LFDP=PYշj2j5*wz-Ƅ|IwF!HSVr%dACDYD^ɚZ^C'tmḗWs~l%<(6I mr3=pZ 3#.,[*/}t?ja "ުtDP4 x9zsvH_z~ ?mdJ3x/]; >mI* ,(x$K]rRg{*k4YE`A(o )TP:m~><!fvRs>ʎ#b:.[c&˷ ?^~9buϭ:p9܅9pQOs3lp'Ac;$ sZU.z!zVՓ0@s۵JΎ5b֑=۴UܿK%ܠPWxgvhݾ.v̪{VRGWcfQ%z`\?CpDm_ø_V#*fd=fOfըGF3`0,d@|rILL߬f>6)1jˣMSƯ,+UV*V{nyeC_{;kY̰Ul }/PA(oj7M?/&}_`\e 2huy]E'K]e^i'68yMA[ D9Kḇ&+'3 H{9'OLu[}!zIօ-R Ds0Kǵ|Z~-z^37uAJU ~z#򫢔Py$+֚:>ۢ=iE#t3m J,W gyގL2s0M+U_ PW*n̆O t0Wf`^)1Ā\qݫ5Uv?'=4 Դx%r׃{|t*3$!pH7>2J ĮZ# P׍Oݔq[@7~3ҶNskY{p{ȐBkzj3܌/=|^_O+ieгҮ.D,Msh4aiN!_繽:Ie&F&I{ޤ+(APK)k\w*ޘ80ZC!CU)xz+0G- B63&Nx<8V% zѷ- ޷Hx_-iʇ_.d<*-݋Uga;{uub_x Q{hi^u 8]Yu\5r1̦e"Zբ;K̊PwSW=@O3YTOi.˦o91DrYgFh(Ί$]H8iD:SB߯t<-{/jhMjj ;b{c_a)i J$k5!0}j*m;ƒ@rmPCX fg&M^2Ep[?24J=DIsFLܐ7~8pJ#=c XM!cԂWB`]C=V2i U#xGw5wWEj cXy@ѭa{5:p>lެGkmqk-7]u\6:GN\gcJ0)֡b-3nw|@_e5xl 8E5N"-0}5@JG΀L]_t;պG{,2D"U)Cڦ-/]_`]lx5lh 7<ZA mMz!wj఻< Ӥ,:+/PE-:xTԥV^JBp+d?O6e7f_HtwyyS.;zwWa0,l#}N? -p(b>~୭5]4Ds+z}A_@-yQo!x2H\ M P ?ءatMKCp51Ah-IYsxi\z[xAh?1(>ڑ>Q6w4=9KsOD:4>E`a-aUv"#%+qCťn$H/ \gׁjl,<ꦻe_Uuӧ!Ft^GFQՄ@MXϭty*늟 RCt^z}xwufגXK?4}YBçnΦ<{hY|Cpoy=8C/kݨxf3g:xLZe{?ffx'2SD"dILc>$S6 'BnEoI?PC?o?Ͽ[???W?~O ZNo۟.p-Cҽ(:WLʩ+?w⿵1Y*!]hM  N+QXk*#߀bKB.)3Mt/ 2&2*-9J$3Jgmq">?w-UӢ E.8]Ȃx89mMZѾ8:<(Xf-][l5%_!7ǛӿUy~;b˦\QNL‹>++}_m@Էh{Yqj8sdj|~|0]"Ԗis~۰>,%x驖7lwwzzZ} HhqMv0c]Ѯm DeelK߃{yLA $| R6 ݁:Y/d߸/Jkwj׫?^mV .Q_,P?>#e(SA@*o#U,ֲ C6 z]左UQPR@+Xq(!B91 z)3!6 IP6: S1Bq (^1XRʹ"TےlU*XVn0WhA2伓Жr㐄'Aj1@SPo*o|z}L'RH)7.ʠL븉b5k>[z;fvCeCJn28'h +3}jl!Tb\P^1QB PY0!>9EʸٕX3YA(nי9eTd=v_MB3 %{lHh&jt}}hK@ Đp£gsI8k) :0dV-%Z⺣BͲvAoSU*;&[SohAwB13sS4 _z49Q;T[!G&ΜD]tZ)θNˢ9 JU#W7&< s#t#UqmԍWxѲ !&dffpOUMp+ !l6oR*PhyB{f檒LӮZh _0f11i'c P9G&jz|}V/=U̼<BJ7*H;J&3LPk `z**>Q {<`/~[ÿ+&0KaN@̩r Ld v S5im⪍#ZU bw/dlJE0r:?3/RL&j!a|z:Yp-CKRk^<8u+f:`V^{W0doDTO4,oUchҚ-Qf(X*I^9rcʌuWs_*JS `tIFy#-fBr3S mڮ*;>X ;!_pJWػ5Wbu.Z]*LVbjW3="J$[@ہ1;pBEcWX[nvNm wMRr74~FVU"!E*Yn-U\|8'X\z\" ֵX6WkĂ |O&0pa=ńQ;(2D|ĩ0S\[ICA!2uEn<8O<H-,'JH~\"% r/wnO™IОq/֖e=n'4BE{thW!׍IukvEeKF]YDݭ_dB5jsr@R,!zdθw&,߮t\hƀ9"`k*^ύ.*š0) ՜=x.\!A¿*G07]9Tr]`aֱW~2rcP@]PEl Vɬ*eM"7AdhBs6"e ѷ4gU7>Ɂy#SMaHt1"#+E1Iԋ:h PM1(B CJZ V7ӀJyx̌*@ɭLH ^uPgp}f@ #Vhu>7WlR堃 d>Th9U *^s0rQ˚SeCBAe34ȧE U͓֫r.% h5_4+jMAy=QQt-It0^xQJ^?<&²jfCInd}ɶ%UPƈa1;yXEޭa53ޫS-Q7/ ̮)} "᡼p<K1a6o!MC#jV>!mRL)F䥨M4)r`K}Qîr/ Tv<|+n#V_,YƏjjSg4{P%7QlXogwCwv`}b_kƠvڼn"zG(pm%B).aF>S<>U%;f]jӳн1IMTcx^-w3ٗNk﫵cs';}lG*3\xp40l pǻi.Y.E]vj3":9DQ:gBRb)e;qt{dmՇG%f@Ɨ&XU=r%@e%3lXp0:,B+`@s pIp|+"k^RdmGvnU)^*Ӳ!8I^~9W[1,t6s$:Nfb B kSrD[-2ՄA+QM|jK]-jٗU}q fddo{4jYS lmF!k҈j%䣚[2 UuoBJ ZC\BfB":s]9}'@ R75"*RӤPWpCbhJw͍T;%$#8L*to9."/ACMӪw^ƅ/ّV'9FlJ8_b4L"7;41w46hBy$)ipFM+u+Ѻi15/ 6u9 n,4R1 @\ ަ;-- ڬKh/8Yɵ6kƬ;z@Ϫ Mȝ2cԠn3$sR nr CoWYDPk몡#Ͼ\V6UB(ӄQ+? n).ȫA B,AN;Zi2<'#f{<s7ZRM"Mݷk,/-BMI[L|>@ e:1h`e UcP/kIB he,otC ж.栶$X^D48o DiS`>ƔCGMR*0hyo<T s0<YY VHm*@|v%[C 7[͉fE Qs`KJyH%n#mJ%!89\sӐYR|>c"#U0zo7cP(p.*̇WpVXET~3z\x!KJըgUGP뀖8W7%bb4Y*O@WvAV>^/EAVE R =@:=r3/kjupF+6em:gXvT-)z3>XGr-8j-O3ZӠ3( tc:+Jv6wjݻUi{N%+mdRt=2RߣJr" hx+$u$#U3XOn isY=a%t.G@易2Š!!.Cgǩ˲Y(4elY_mW5=ŴnkmV|,H8HPDP6W.Az^Q4&f67 I&A"A ,`s2BxLt]CJx*먗B, 9Ϟ8s{>9ĴS20B8sQ=jB(P PI5XT$p5=H'}+Wj-dØk0稛>Mh.ɾob !q"ͧuSڧ!Rh^Ax,^A@ԮԮD{O(xA6)#HS,:hȭs&d:=!6ᥣ3 VHש0.6ٵ3xQ_I%blO&E3AJ[K}5k 5b2wP\d[2ou;_5a. aXIJgťzvN zY^lԘCY Q [%,& !*=VHI IqWHmʕP8tA_IY:Ä1PPRu 3}iJak1ilDƇsьTI 2$PA9{\*YUvX>Lxm;̒X2߄bʔ| "Ln2jd 'diTH 7eibV#F"2n#Gq䙢oMSq `:FX 5څ`G3́8KΫ^ LNr##0)9K܄K8 8)-A{F:.Qگ!|8m4_uer: oĻJJRost DH $6&FkB}hLySgbvI\n~M9H%bvgI۱EeUd.-`;T0p#9hcpGIFzx'_CP:pll _̔wu|MH">$ax@) Y/J5 o A]GfchRPɍ\81˯~ DoD}cP.p~S:*t%:5M&CmBȠ'&ʎfRMeN#T@!M8`"@E2gjF"iRIQEDYMDzAYY+3)xD`^ 3Aߘf!#J8IaA0ePV)^zزRX.jUq C8u=ؔHI&*`Q pGկ)jAPQwUե ^/:lRВ=;:pnjTBIV\tqyiTrabx xJ˕iVҰc8|1Ŕ>Ĭn(q>֮$TXC͆42L ʑA6gXnQbK_2\RN!Xi`TLM{n mZ+FA+Fl}R]3qu 4B|qOwT"9ovp3ʷnKVT^}dBqg}uȨ:[9F UnMnN6;97$qpИ"܆43G ۛ| Eeud&2-pf7"n}qeK fO\; R"ؚ>3s4 0#v/U tЌɺ%($C84YCWEހAD< P'"K Qps-e 6X+kycJfC$[NlDhQY̸ȧM2{cMN qDfYD8=݃U2UhUl;[0 !@)'1Q& S0Ͳ#$}`BȌ->.<jj/`VӯP|0 ".wuNc$ǡBݣ;s1øIQ[ D~~ u/7yg*dڎ5#c :Teȱ!ǔ\4Xq_6BqdksJ_qsG6O!6۩k=~rbjssM+ONw!HwT7&1 6/yoz-eC4#%ȼ>f[R2#l"αiYkiQs&u2KkJtS "W8Xe׃5+;tdppW&`Jʫ1TEbI5zǍm. fxa.הYW'UF!n&W3c?kUu!5fPWDZtL#h,Hx,Fm#} W!нW{{vQKT0ST(q+^J7J pJE/B M0erG}ͩ; f:I)(ue)@ 6Wd+)Ř]]K}'Ef(r>ƥ4-nxXWpv ]"A?(/^=TVУzѵ7O0-O*fG rSQT{gŞj.x( fKi_:|H*_4&% K9=,}T)d` ]WU5M Fҗ{FX}h ^S[۰+CE.qp|ƥQtM )T؍W;Ww<6wDk4ƶbc\T'K!D!ܯjU=m\%HfR ;v,5(G[Gy2p gMgSpT@4XJ0:;"=zőJ5U2ć^l2NDIToA:i߬!N[9`:c嚪 j/R :1(-Knc\8s}sl ϑbgGG0n|1 K+Q\ sXLj R-(< ?Avk>Oǩ]R6xsS-373-Gtdc I'mدaPP6u^rc!`iWVƸW- fu2 T )5S$1VHZW8l&Q(e\ț"2+UM*KxjƜ >Eoy &fzyr5y ވR F  Gg8 dve34 S?e'ttd`_N$Y,@*0ubLU4IX3{|*.5X gIG=v]aqil4*UPǐ)۠%Mіk*QR"d",Yb5:ެ8T IN?j[׎l$0qQPCRd> ec^g-_LNh*(۠7i\Pt\M0+|*F*~~XvTUl^h%[jȨ czk(7mI]I;ئ#\~l'  9.-w*#OE2Ok֕XZR G``Bؔ]/~v61I8ix)9ðFN%LiADǪ1xܵS޺*LX;ŮD͜5Fa{ƹJR:QNehDkGʄ rGzTS͈"IIj1Ws L^8(×*%UL|-GԑTHuEkeifM0aT%4blNsuME-jhM:ǚAiLA𑀀 #w^*"Sxd88lSq|ki.wT{3B(=UZ6nCҤq*O ivGmԣɓ`'C&ػ(Vlu("JoO[@Q(Lň]#@QW&>KQyX+4/Y >BiVp'm:-\q,\@Ԇ=5fha͍1/uM-j4gPqD3@雦OPAQU "JEo|GI(KVLG "ydJ4Ug$c2"y f,X=Me&T$ىhdDR j j8 !r?1-XJ B jL:GFWrEuP ,k 7b;t]Y")_X$S{-3֔ݗ` \e3^ȵp(`ז$4U\ U/9)J&Ḡ]fPlb|W6}8-&&bҦ\AX\C<c5<*(WWQX7FJ+s65ǔLxZ?@lETEڡuȔy;SUH;[F?9ѨoxF8Bm5 RT=Zm<2pՠ+Ekg2 Ue`{RFN"a0ڙ|[)$ЀSxDS*QC`#iDj[;q((ru˄0. 9[8V{;\VkPyemkhO=0&YUTֳ7:D&'{ќJXIԨVTH8e-ڡjT¯/P# ;d:"5bӸT/#uq| 9 5gը)wKpi. ݺN<%t<  1LC(/+"-R7TdZuGh k_Zuk`"֎t*^92dM00eख़˺v{941^*$D6r򠉊061F{DWw50)#B LgbfmbS[W?Xt){4:eשg1='GV䮍ql,: ]LlzZN˗<fthׇma9hZQLWQ mFLjm,*8Q^V|ʈFU7 JXNΦo[, Ę%8~@łrیo:*d^X5AZ|"l0;zn: nǹ!ЪJKeuY UZx29αkQRW7rgU2v|򴹯^9ەsU_تjđ&cTan S SGݣ*&%4%[\N+A`#lAUT c<J{)y]%:G2C&qG!3S#nYF-gi˶С$dҸ:52Hr0!E_!aLkꮓwuheIf;%#0d5hukltR);TWQHKpȤ"qH셿WE<ʃُ8DȷqF:UTUke*jUd%$*j4rïCek!w4F%ٳ̬%=v:\0x8mS&Ԋ!Z\sU!16}ܐ0ndNtPbsJf\KBiNz`W=ei31Ζj\7:BlK xٕ]<pкl\a w4-SL6?5Rs1a:Sms73ڻ %5X>5" k~bDD:N4/.;|oE \vi>P#!PbEՌt P+{#66kBxEb7L?9CN8k:ԑ8@ۭ% sw UQ_tC|*?ٯ&QO{⬣3椪2t5ZKP3#H|%^[bQJ-* PnqZt(;(as95=dGW.͉V ЁD%J#x1?Xlସ!Gl{Rqy9TF79ȇ#"1ki"z9 _\7rPOP 4Ĥ_Ճ E(P34ithi$ 4?Qs>yX(N"baء+JXp5 ifE+*rѸFWEnjsѮg!hrݪ.׆ CggOX&cQWYUa:LʭƍVjSyC[1ir-M.[ YUcS Ο1[[~lMk0#鋽6eA )e21-8o&&*^Z:C7݊TiTe(I^vn( \)H;AWuKcBM:52 ukF.DCQ]B:0Q2J0լ$B1IAzMth~ 1se4Qz!ӐII@DsBzD^yy>C7W~^B 6FG2 sQ:wEZ6l kKDwb7Hm u!DܶѢWF][KpZ"CP ; 3Ү̎!];\"m oyy7"y(=޳M\XLJ:7t!e<MAV~SY E j ɦuVu1N4.Jn`5.1!iquܚV20NdO^bk͏AtnO֗ur2 8jY)Вf-C@g"-> X'h__ xھ]<j^Ոw3: pg !(bk#6*66 u* }Rhb(L~~GlkFR!TB r1Mt;vD:Dž ]rƎ +Gj3=G+4΂o.$N&}* 4 ; we^c|#]?6fl=?2y{1N{inguG`- d\!F8҉nÁ]݉(-laxtpS:۵|{ϸ佮=yŕ'^u}Y'N<;{#e#ܻcwn_}?]W;z䱫Nǯ8q>W^u#:zݱiK}{ȕ{'sx'Uwևn~4CT%cowO^uʼn<3vw+ON+<WVb?xv;H*0?esm35 JL٠qeߚ+j=/Fq4̻C@&=nߎyMn>bWO8qtezˮ8?Ѭ,}CSQ{;=|>{ЅmPnzPiH l|#r$1S]sW5*Jˍ}PPGϨ·ld] $̈́XW!G'厊JMFTt+FaԥRUHPcMZY2|֭1r2["PE6ړ)SrZEn#jY'6󠻀s(ZyӉދp5(Qr"C(GzP{RKްR9EҰM9!bnUeV7lDXb(j4g~ c+IcOp{$f)Ң\;+Cd!sJ!U+kPQgZ_q,5H׀F$i-H{I"}MU;Tx N+%d *"uF >Q0 z&b9`0lF sVrciUdA"J:V5t7G1M#T~I_X{!(҂?&R vN{'~[U9B8DгWtTl,M ԦOԁt7T ZZ N5[1o ^ݳКLTDy} ! JQ1IMC( Mq 9 н6g YT :F!m1ɓ 'OԸ4ɋڶ5e3й$/JDV&ܛ!!!zׅkRorkKFs@QZG)GVҞ,ppe/uxqPFO4 DUj&`jDV'8 ?$Ů 5ߵxE&w 1MVi 3M^~|3&q& glP&%]ː~jD6xֵogl",>FXЇW~g~62m?!Hu0G $ӖmGE$jzZ|:5EhG1)ż eSs..cjCQ8E꨹!RQ=ԺF,qi-5( (/ik`}" s8 :_H:wy3<HJF"J2)R_c&b rO_Qf?/d+Ԡ>53<ΫX?}&7?6C0f2̕*,{fRwF Kv;.{]L~{^=׶g?۞PrhSIqjg;cndX4у /A?˺ VM@2, IuT̛MCx :Uj;x2d;k*#bhLL, 55IxذfjPkG-(> ~b)#U㌅UM9^2 Kh&" G4A]-g'mj>Zg}B`+e*pT]|iոqc\ټ p,y6=9>ch-9bCu QBdYA! /|aeɇm`J>LGc6kD6cSGjMB.F'YQgyPhDG̪\Pjm^ƂGXSl3f!*csGUeV"Iϓ*1ˆUh3%1,`XmC ~v*[1j] ^A&*9ףW{D.NWԧ?}ƔT`w{oa9YHb݅@!8ȍDnB9(?ۀnx[Bu⽷XZوNxHee97;$(#a9R@ƳC{I.ƅqqr_o+ubՅi\[H'`jouk B-sJ xoڃՕ!L ĀA :qQd=lClsP5R~ۛ%pJ椇d-M9#9m#яDt,tq3ҵ416k l'$.k#lrڕR谰Y83̓14 =y}a4K>H#f# d#\d#4p44kV@#L6-L91Y<1j4.ccC p: d!}P5pd&'rj&wso֜֙\뙜ZsdhrhriQɭ8Z``FdaĀd+k n ɀM!7Pm&$Lrф y7R[&DvMؿ Vh7mTuCݰ!CqA9m\x ǩڒ',9զ1;^r&sG{ Fb?].IvssckOӭ+#]@BXma T=/̢K(+1CY4|t]$t9#k1Jf.RWnծO)(CM0” A`$L;Zk69K8ulHtYCjބng[5y̓$ wȘdsIc6{4z"XlQkrm~ay5m+K{V/"=ֻ̳ im#_!jIdW*Sj#SVMƱx+]Sa6ǚǟtPXznӘHנݳtpCA ޠB@fOf )@ª$70"t `sIVJgI _Jx团CQHK2 uALk=ǚ?0Ua7Sَ&Әm(4Нz35d2pnS׸fSNP 4kpՄ[0Uk! 2* Z ]g1͐AF5( ]0_Ƅe @kB0լadqs dy1yKPpMH2#pCZrae$JSkbD@f61O)V嶐K m6owiMl!Qik endstream endobj 79 0 obj <>stream xӘɞu -)%_ͥ4X+-mT`]JEX&IfOΐF(!Lv *bupdЖ:2OfYS{;Y(Wp@0RwljjJ8)YhC`w-qX@t}wޘ9<6I[5%Η+sWZI݄oغ[s57s,4x"%5Nޢ!'(2.vM&lMئ{m95c's0E הZFb Nhy!2:M(*';=4&.@qI:U°#+!j8 4Iֹaͦ:p{F&B^Ndy0{+B&&CY /CEV0 /:v2^=ݢ6 ~c"[]`%/qJG$%Iw jd0*&F!R9A&\3u A R'$P"vBYcz*R*+mNҺt}7籙$ b#J2dVwPk'wB4BI#)-+!mX!kYk-rj/tFz&hޝF`^űD-_9 1r0,&7FX6W`B .xÎnD\;=F0ġ'a)*۰^R2bs2H1ѭ,{3cOA% Ubŝǰ&j muQ"bDkg;&iq3YK|Fspu 6 j󍵣Y* {s$'=1X;4Ҹ"Rq _jWML/iP3q0zϻʽc'/?v ^pHKjZWo4DúZoPJVj%fIRp f{#V!Q$=)`[ k1'QnF"'N%6|8%Y"# 7sH]3آi\YJPs9ISϫ&7,$ABuM@ke!iIdw`A2@$2%I9TDgY}'ܗ(VrU{"A;W^Ro\ ); ܂AgB*R0j_niUUc%PRo8ƪ}Sc{XDWHnJ뚎RbGX>-:B V`EON O+Zo⠄ybϋ[*!%9(7kSir)-[tCUmҫz-nV!"eUU|!%cJ<d]Tw$!$A8&;b.4Sh"d!E 0XI#lB\Q#g^+Q`S#or}k8(sG%!_XeU'EĮML&TgHBٮryCQ Shv9GO^uţH=rYgW^']jlˮ|ȱK8_O^w%㲓K煗=eW?vw ?|ꕥjZ]j53ױk=zB܏IpP.| 7<WZi/<몳owN>^qSկN9A+^GK?/y#_GxsyK_kN9<_+zϼf)?{3N|W"j8'ޓ.j;?>/K_k}̇?)9e҃G]%z_}y_k}n?ns흸[˯M[{H;K/߳/˵Nn:[/y9Wy;=p˺حg$|5پ替Y nыo½9猻}5̋/~۷WgvxyP_pC/>|p[kJ=.{ĕwou;[+:X 9k{ι>wvVzEo\'ŏzڳ|[ =ڭ+:+f;Ͻ/ŧoo;)VvSNG|ӥn.}ޛoyOȶg;ym~.8;o]?|#_|x}GM-ESj|_G-?xI?Dg=o?5O~wlY?]rӌKwaϾ]7yG7_w>^ 7׿͓>g)׺}/5G۾ԍ7=徛W˞{S \?E/{ѵ6z+^7;'?k>ե>~nt'~U{ en_}+z~=¿|6S䗿u}z/y;~W}~~c.^:>U_==wKG1]?մ>7?{/ aBD3|y7GvNz_}>kV7F7֧?^Zwn]5M{3Wv!3n߽yO|ջhpny;}?w+O4[|;o?o~a~tS6e>z7~_ן4/.n_-׿#_#q?[N~s'/~^~gc{sп?i wa '_|jm/Ǿ/>!ZՊÏ~}ϋ/F ]q2؋k~:@n+{ßiZ>?.}8<~_db眧w~/w|Ez?_rn_86L;]w /|}|.R7~]/l]tyf5O+/~wm3~%ocᇫ}8YώkO|~Is3w%y廮G=gZ@;+ۖW>^fw?D1O{_w._zGV?ew#g5c+Gm~&|ؗOģ}Y.<^5=ןocS>58~Me{>X07#o<2t; vj:/{~n/ە;WՃ~vtf~㋓y=&_USz~v|?Xnpl~SKm~'j}Z}8V]9yt z+ {vo6ZHC~vOznCnm9g{Sهv}` Sin<{N󜉋7=$?zy=GNks;?] ;}b6;7t>߈G&^ХCt b;ߚ.L|RY*.tjGΙ3gjݦoU//ok~agVP6[j6ljwe[e.~μn)v3rku;wvCMߓL{sș ɿge+"ڛ~{,>kwó|{<{f{CK_]ek|uOanX|EA_}c Xѵ[FkSNdڒ?UWྜྷ?xW_vf͏=Clמuu6Mz[_|ϾɶomFx݊eyMv9Юs{gݖ{طWSV Q>϶ܳ6o:=;o㕯>5o-{˯ؒ77nCy>zW<~W |z#Z3fҌy YKQ۶m/mۺeg~]4֭^鴣 +9䳺^>&N;-zŗ_}7xz_{ys?I׍нCSuKhs}&OiUzI׏߭Y'!-Nn׾9V9mό $IhR͞&FǶkohV* zגX|9P7^wmrCܷ$M5 ԻO\Zj'Fhq;6HRGv{Y96*=lG/yP( !Q\L P0@Uggl~ 0ɻlD =#* B8`ҌLK $l,5U>H~IT,`>AP>#JP.${&l.VG&Y@ĩ%Py8+@C$r8_IX.r3_ >5HP,aZQҮ B?DI'Qb̠=KV}ɚM TR :[\ler'."NLh>L(VB%%Hd6J&LHa"$<01&ԻC)XIւ@a@ CJ8tdbnFXf(:-{$]R c]E{̾A&u@ci3qb 3ɎUoc:£y]\:UqnO7M'0}z?j h7g\(8w z=|W9c+En5}]|[:uҸ{>' r[{ԱS8qBwuM?#ϏG׿S#Bs꒾Յ‰GΝʟYwS(!ρ ']taG֯r7zJ&C0WK!y^q[һɸVm3Ftl⁰#NZh"ޣ.|xv+*u퐻`mo+낉u&h7?ξvt\5~o?t!殪!w!7}_}X' ?T彍gu=h;ɩk׍~1 s̽TjnVa"h Gh%(^>ŋgwz|gOY9.?~Ya0מ"y㡷/#~"ߪh+<MN:=_'dF-Y񤼤yBg슽W_`> _>[zn0퍍-OCκoӿ{j~{ATy9h)/Nq-m+TgS96{&q'^mt}E7lhyܜ[z]nRc}%}eHW6Xmi c.uYny°75~:wBzw*֒mz_v]=u ;@^mu+ zu_wozL |+hw<Kv+Ѐ=cf?m bjjO͸[Hr^lM'OKdBKԩ>rU3т;pazUS cx]ȿ_o q{bUeWhOLig4/T3;޽BF{|w/]8k~3kT"<lE1 X -U-i4ޚ*@^@C10VZT'HqܪIt 48DIzS hk=kԕIPǓ L Īګܤ<`qcQIPS~0@&BEXE:HI0@ .I8І Oh'SsIKVK"Wr!g`)0ib~QO (cdl V%*'/ȜP@<䤗 HOi_U-`]lUhP̙"Q{ LZ6-ES4Q( ЬJUUr- [Ջ6ֵ smJw=qrA^[m/D.LG3=7:5`X%@@R.0Tsc]odeRcyr_9 L2۴ۙ J< CQs=)^qX "ΕY7&:XMA˧121(؁@\B7 fTGeSF0\40ItȎO:ˆWi "UYGbAΒ0U$N&9bƓ&:m R"%Z)KF d(epZO R\ȵRo*,oCi~"h l.@W#Ov* }1 K bNbHx@$ii%9%>~"zcp^-IWKT/Č]i%H$FC\բJ dR6v̓4qͰ=eu1O jQmn 33-G9R ʘHf*}@V'v`щ/lZ9RPo&dTWĪbEqxvSXaڎ%k [_*&`3# uE{-?8Z5K`j M^D"!ˇrbDgR1D!5#gޘ.HLS[nLѮcJt\6Sx XPPOIZ2HJ 0خMbƹW0fLxb}ir-'x{J}X6"RQEzD4% q2pHɧ礲sfdz9ҵ#4j|Րn HNlYTf%~d'e$uU5&5ЊvnDY]RE(K3ϓ=G|ؕoE#'::7!G8KJ31[D ㊓h2yqH|3&u5#78#̌gCOCI/Ӗ.==U]8PNhrZJBہ,23c\-DY5~RUT;r/{׳L^: /mZckJL fPt#Ժ "VDҠƌa gq$8Y c}Lb݂K H“ yAgɪ ?/Ŕ+jZkZ,f UKH邉&Aadzq-'88Ս%.w!M(2í otkrI  f]vXQ&HҌ/ɒhl b86,fUdp7~'@$$1g|u&Wx]TQ8gt)GJH?|?|`ߛOq< E|A΅nRѤ`үM'8jmRMk_򛜠ܯZwzT"W.S '?.pT#pmp/ g4-wv?BlX # ?X7h\ؿs54r Ba%*EK"?δeuyEYc'*.~ ^unq&Q(_y' '̚zGo H/6i7SljE16МaNu}O>$?[±E/.tEE= Q~ق:N_0xo%AiM^Wz%3)H;+ [nYrr[eaE\wQ˗͜3֌5 ]/jw-Hw7+3dTh쬛 DqȎJػvAp6j 7手[lHw76VGNԽP'AVV o}~<mD|Ldzr-e qF~?6j.o"oȵ:ONz-XU,^P7uҩɅZ{Ȭ~O^) ,6Pi;%s1GBWlzi-\߽0߯<2ݭy6I/&wX<];?|az8޵⡱~r97ȟp˶SP{q7PĖycɞ3$w!޾wP8wa &z}雲]Ki.:]~ ӝglR8ݙ_$>N%o_V3(~gZ:;Iܤ}FS"lnŸ.{j{Lxb^{808fQfjq߮'MzvY< (ؿut;u.酑ok r-_\\n7=쁄li0w ]L>\?m̨q7Uy4~MUhx5.kK ;ޜ.+ _Έ S({t/H|oǎϞS+LF>7WO.zEyt7O{ar0זy 8gN3ڑYOκ{E%yߪ.q$ܰ^s]>6ޅGid:Ka;KMo6h3^?.ΞhLΩD_^C>$!2sGfa 1>i7W_M?#W/ffx;wkZ+>=ș}^z\=ñ7m\:U:US[]ꇛTүfhݙ\S߯um})8 > VGh$h'foA1(BgS7VL I $76c”^K*)0qF/HI_W{%{gl' ≓08Kl8T)8j[@!: C 7zc X-}ޢmQP%j]"g\R(=Bd|e&jD#Lc6iGB_# X&d%'8@0TRi@,@IZx?V %@][j`gm~S)!@hY83.-5:sbJ85">0ެ ^a:urp,eq~Q̈ PIs  -?\:GC,a ^\@GÄ\o#,$`sGqOꝘ4&qtS%/c;Bš&7"m`&fHb.Z'@@[\ rKO=(e62na{ :lZhBJkސF_lqE)P* ^.'"!bY3$Jގ8 F'+?YeY"˷t.&|*@y -h MQ~bmr`r%ԁqEcIc^Zz l/Gb^R:Ht'Jx:p+GqThЏ)0Syg /'-JNs< dpgbgxSc~0&Tʈ)kV:3T,n8\0)) 3tXin!Lw(̴#rg?ƿoЕMW*cH&Z$v]2?6]1o_s@hEyϛƶ:v\_2?;X^G\pAv9x=h㳴ZgU6%E>nSz]E"w 3N.e?ePe5n᷿vEXiluIrVnelBuz pøEIv,k1NVE?|SBy@tV;Szu?o=U >Eoy}vׂߣ{\h*;aޜYjXO7n\.\8/̝7ei_ߺwk?\QnЯzꅝ;w2zN{Kʳ(ty,ɥONA[ [A˵GY^ځ@?`zleԒ;-4|(3ŎjGPcMkduڢ&-̩O.iîC~ q䰳M'%7,=t}“K:,tÍ29[pq >uB>D_xd K3n%v'{t$޲e3.(\]̐zdSr]f [w\=cP\U_*Уo\=*ٿv_?sS5M=/}o^0N/5,}vӽ{Ww@/­M7ml̵CG 0e} Vߺ"GW&VrUO߷OˉL]SY]̶<`QZ_=7eг/*ܸo>2J}WO{wۖh3vepǶljܻ493Ltyt㾯OAI ^o^f6sh<.&Bw;y>^K[[\ Sh}4<j5o[qp;pr)l3/( /?Z6Fi7>6X(z''\ӃBI\惥Wm{^NMx/6>9< {mU^m:?t>vk'֣{_vC'Um+ n{o0k |u7~``o<\w|Poha#gm ͹e97 5]d.uãbATXJ|pTyrBuܣ)O([ugm3ޯV?8`{6]ۺnOO`5:ݯ_yi+]vFLN{n]$vaj7 SsN,VmZp. Q]vXyLb  J X: $0] ޙr B Z8-|s= LO)lKa&)W(Y8G+6alDTÕ;r2>cxH؛ "A#c5sIš_[ "X9jIM!_N-Ϝ P.);‘pgΩp s1fe_o$4, 2Q.,8CWeX0"ddX[A#Vwm:7X}q `*2%pǖ=rBy=+ے`oR0U(/vJ3#XV?/1rsP̺,FJa V`TvqDk <Ԡg O@&nP #A nV-@jj%&ekkEE%12P/wrWZ9uj 1E;ɑ[ kBfcidR1|XV!gtL G]W:ñ(WPz1 /2i KS;qh<2*O_%@s FDQJax?^i$̎`5Js%fc1>1=B0x =7?ai"(V3+)+vTزvz61}?9xam#\]?# s06+ 1/D^o\ f/w,xb k j.ВyOUQTA 'pDd™/ͮhHqjQf&= e̴TM} ;P뗕G4\^N<}M\/u𳼀oN;W(N<9an.~^(xm-"!v~B-U^/N{uӀ:>o~ELݷ)G\0zR@O9 *Dƴ _n~U]~w~mVQ1$/gCI L/n~1];O9-O E*cr@Zb{l o՝b>J{Z'E |75ԩw7͂ 9^ppz8gSqG۞ Shxm˦;]ޝN`9]0*C|l3LL9]r Gai79ci| ҶuɈ+{gnly8;FN~D:zcOD6gm߷k'R4ϕSQ]:wCLZP{4 ]=tQotsyz0 E='ع|ɴ[OX6ơ3>~]ӟ{)y__0kf-8j46̯5=Ɂ)6oDgQ*ӕk?j[9˾U›r۹+r[\z?14䵼odN+yӷ_,ŧV>K C[={g߾\W8oosϺ?/kr_{S=/#N~mbS}+yڳbΝK7FX@eEۖ͜r _m-qm'~ndw_m=Cxd~kStm>:'oL+b+tsT=.RApݫ@/U(ݾ|_s˞G]?=׼t&]6+?ܸ2%Ɓ=[V/{`g\|{ |lپm.?~`nx1U|_ooQx%ϼyd|  AF@//!8YSHcmS`r)""vPRRRE*TqԬ*pI0Eˏ\QJ\zN.0GX@k LjA=E"˱Us9~,JApwFK-+rgT "VNY4|V]1b\iPXW1<\O ,O[qhڰ4C''6 LMYL ۊUP,ħ," B GbV8UM Xƹt艪fsRl<2P)'n"5a/uÛQG8&Di/=pۛޅj^1iFag:ΤpR:Q\RRvVgızHE|1 3>.s&6 X#E'0cF)g)S^\Ku\dD Y8G%y"79k+!{,x1(5؊s/I0-A=6ޘ`}8l#_5w@K~`*?XO @T]k!RdK` it̀`=$T! f9;DoAޓ3, T`ƭR)SE`jՌdi("Y)R)EtiZHe*CYפE* РH$쒮--ڱ*|jkPp ,Ir)W6?B&-5Ai: QrXڃ֔ [!2X@6t+QfiEH2+UZQTr.hI+d(K"AYLD_("O QmTU L?IUqd$P%]KDN* a$̲ T2T<V2V "IjRQ\?qj1cSgxqS 3Y. :ee6C]ˈʐaHuX2GiŅ<[ |RN` 8͢\E1 uE1s|[YI$?" ^+Y)):bU`]$ uML\MLTPcȶ}-IY&vۧ<Vb)Y !G +H!rwdN`.i#bs⍩;j۳B-)f2kzV 09;P97fO{ hfXX8DcȾAm GrŜQ2Mcn ƙ]49HF0*ó082'sJ"g?DlS ڛb>@a 4t5/+"Y5c ?U(B2R B%QS3`lUM'ZXmi*[e|g*kke:A",.RA LYXIHWI6WjR%NJtg⦎˰&KAŲ$zEa"jUGɦ{ β|P+ "c6}-˚z+d=>,$hnP.wifx3Oc&av)p*; yG"!h{&l%BHZ(+WNVsCMO&˓ψUmoqTdÇlpy9BI@tc~jA~Biӧ膐i& JZ,SOeƇs](Z X))UvNqIه!^% EƓ==# H$su(b(a-+q;w!( "䅱P!7 x/Dv[;|= |#X-9fCl+qKqrEo Ml5ye; " (e^:pǁ@9(Y.7ґ:tB[OTPՅ%GWe8 eˈ6Qd9Y!&^P}^NR!G#N̺Fa ' @ &~Y$ t\,1pdžȓDbGlYv\r@JӅI۱Fne:^'&*NfZjYAqvPIb!OGq=3$:-!v-Z*q$4*D~u9Mx48 }6 G^:Oj)!;œ`^N,ߡ^t؊1I|芘j5T'؁s(Z 8h l'SH4(Vr\D,“x6|naw}8wW~TP:uJOvrWRr#"%F6T"݅$9%Q-jgxCT\d+Y'Df%f"J+Br51m)uT2SՕ2Q ta1&?TH҆C4ͥ)5 4#:{%u*O8na :|D&,qcx R&7XNX΄V: Al&l~ hdyrgX|VB3:l-U(T\A%E# rPF5cc8KcQ1OԖBWYm'ЅG`,n}cڠr8.!~Nu,CZK5"C8r&@H4`d6Pn8eҡAB'A:r쵅:UG؆C;;@7OFzoDcݐ'*F/C]*iܽ hW UW-Eш2{NyKIMŎ"RU"Y$O ydɉeJzrx^Ŀ7Vv|LQ^8l$ʇx;-^(CA&d6i[; Z& >0,5g򙉝r+E$) $|d@@=DnI?j;qLjj]bpl*P+K#ӈ6tK̾uDǮن$;SChh'-h~.SVN>e6;v ʧc=\t3Ac8E,|ٱuf= % GA- h.®нdHJHfE<6:d?!%O@S1u,{*2]"ra_YΪcV8> {Ǩ&avay,&í#Ó` 醳V"blΕpEჵjcgTSB>!6(1B=|ѝ90lj /pct<ˮIaAiY O+3(My$1,RWYĄqHt'lY&e&ȁ5fqzޚ0kfڲUfpqu9V q-,T֒ DFoI\N5ZnluLŕ1!!dՕ:CER1v BYD,N%F^ck?|3o?|;OYTǴKsH$J4zq#aA[yK|3RcΰoAW2MRt'2?4ՉF/&ؘڱkk"fXFkHRZ- =th dL C<$c[p%U0^0YsBrĦO10f1jҠGzdc3ct~ B`# 05%q$6{=ar@>\HM1@|FJ2҈NX`.# q.SRΖJt2m:0;1$(X=&h Ǧԩun9n[JPNmqN_q/$[`_eyp %# zL)ItlI@6YKRn*쥸RȲ>D@%Jq D |j'Gg9j\F)>4MhqFrKc*zȨ5 %@ʔDFw>ac.N׏ d2c/6x_i %f0|-mݘRÁ[i'x>}ƶπ`^`CͲDc:e/m?;b5@)I{R$ND0EmSLcc+ǭF T`EI6RA|OYp3ŕa HNFKWbU;@2\Yhh%kvUcVAFBi2,B T_IK3S\c )ÂW6aG.@a| Pcg#BJC @t(Ċ%F"7MN1u;d:݈#ùB̅H" 6U%t;%:|RP|o㹗g : )X q3*iWm- ,)䤸h' Gj ng`k1l<^cgɽ"hMUB5y *vXI 1d @j:tܦJT)Rlc+F@&!?uᙄ % ]a%DHJzރ&*L.}"6fergP%P@#Gb_="t8 J+~InJs/fE1lHŠ)I;W\=9ŧ[!R2WC!8dI$0àW|Dةo()lVQlCRMPW.qcU"6-3FǕ(ADg # F'G6 Fؐ)@+zN(c画Ah'wUeU_kq$* q1tdzU1M ZqY&nꂎ#zQc&b`kc:{D<#%frey{SL\Vk:~lJKM+WkUĝP_1jg̾+Kjy1>o| ;H>SҌAvkeL9WXdvZ5 \HiI]t=1Cdo ɉ憎^/΀p)Vk,y,'HX:P9xTKgoDVYP/O c@iL"L`=&0D֕Pdt)QS<k]LA!G%P6zL$av>5#"‰8{3>&nH3^F,: @i=A5 Sk41Pc Kf{¾:pf8҆O~%=9L_+b` BHiS^<;{f>)uτ`QK!`E!O̔8iLv7 V1ba? 3a%ٙô$x/˼FҾEK+X$!/"P=OZDd_EX\qO%1~sS⽹1o1\&:e4HPQ5mfg;f [R9С!D>>vai${Ӣ:s 7Wl\5We{,y:;'XBgo 2H, &SZ{ 4R;m(Zqr`SJiJpwH P! BWp\QPXT0'H 5.V|f.Ӥ\Auɡ-ދ P;.c/v1ıtʝĊ*XYts%gb|`*ƒNP7bAjċhVa (JM7'ս"E~&VVr2K_)钜T+{X,XI`NN$EzlM02ޯT錈Y# Q/N\@^=paZ቞ :=aCbx%JbIcXA|<Ek>NqX{\;]'¡ 9^c\_g둎y)09"-_[XǦr#ݥgNx,X*]L^1pƮ]#ȪR4WܼxS;L GqǾ}s D8(y!cS ivY6XY9O59$D!T`J(z4%D|bJ@"lƀ.F39Ƌ0BW _&2$o=Ulij#evSF$L\.X-c ĆI4/`5Prp;^pTFȠW't܀&|4сd9@_%ёL Ɖk΅+LRՀ$Q+6ut`4`8ܼQin{KV (dl@rPBF4Z`uweur g? +S* ᭠ӎЎUZ*ʔT:)?RݜQi)tU鄊'|CfZL+.n OrÉi(Z[o". U OkLME8Dž .Ghx%MU(HpyfTjg?ɉtM6 dLdiŦ:t8*c /?O;*pO[*T8, [ԵzCrXDCǹO&Sx c2x=SY2+Sg-A^j"p9#B|*ERcILYE,ʝZ\nS+d-s8rGoSXWم\\1]k\kT@i~} X )ʅ( r–D>"y6 =Z5c\/dE8QO0aqEV(qAEB!+?Tp=+]EGuvE7SW7/qf3 ٞsGp qVG  rs&{ٞXI=hVvE_s!ix2rƁ4[⁼~MJ 9("V!s1aTIѬd7CI^~L)-3Ip * 4JƲC9DfEf%'$3BB ݻ8}!E&R[lY13fƾSTڕҮ)BIiQR+|>3[{sm|s)zl QK̗$e#E^],`(E~c:*;| +̊x ޜL*vciB'S~TqB g/l<[ЪHKɷ. L^s 3X?UJQx8+=突V;Z|bˌLi*3}GxAnX@6eI8EsO[YKݙW;oǫ~An Yzk&29ʫHSMLQ}j߳ZuQwX: w bB3)cNTN^s/`N Έw&?0~l:Eji^ǿХOBԑ<[$tbĀanlS$gEs϶ Ԟn)K,1#NξgWxTӣ.QJ #zv :lS>⑨K/S4R*$,5(VfQ@ĩ[*k+=1q!ɮ],~(Ҳݻ~pJUJv.tӭ7V*8>jo}ʇ;ىw,{D;2+heu\KXO%ţtNLyxk cJj?흔U;[æ}ԙ|"P,|^˯g{X{{źVӝWՌ޵φY:YLgZ5 T@޷31VE?6` nZZduui7W;~؊˳q˗R:jꥒKZޔgEt}Աۧm!R_ .֯3cqMfe>^6c=^Q8摎g)\R>3EInDn~,7s1nf?{{jށK]5}^jy# 0v4>e眵'Xﴰ<+.y>I? UKb[h8{9ϓ"zP5/\}_R,qW |w!|Y/洈nKQ}r/D6Kсn-԰6w R[~Off{ݧIUkF6V{=||C-zɡ2ǼToҾ̗{}>*"*\­$DԁS]VX~g 1IF/IuM?>@͛Bg-ϘRf֢'g?X;:*[LcnƑN*я|+~)sɴVճ/k^}K2Z8cBϖgYnh(ٹssЧ:E"=_]yCO\RQdi KH:{ء9x9p,]!%͚co=Ωoi9"]Ss[M~SoNeNTЧ'X-,tG n['E/Rz'=07۝ݭ,v.M7=^$6̵K5Ko묮qs$-}ws L{ 良V]9xhJz%~V"浖5UNLx>=a K{ׄ[AL.;xoISu]kBFdՎL"3h;t̝tPNd@,Ώu! ,NK>l xB:~)xGwӑn}v|PhTaX-lam5&K_R7҃Ev6%ȼԮ.5#gr81fUI_zD4?x\КF"R9cUBοկ}6NdE^;t#_3}rTq褬'fDRJ"; 'M-wڬz}}Zi|2锸60`)!|Vc* h*d״xKqV˓IҫRճ-~YEb^ mL=9gL|ޥ&L&ͤlm톳IltA&d17]n4ƴ3oɒ }r*;{<EKWhkQm93 c{2rƚw^N7m-atXDBM.vZrSQvLpƘM x[nĨ>Bk^L{uwhSje>眘siΥNvWOq;yOF?kXT͖:O澭O[[0[W1 l_rsvvS>5 jj8SA;3f˷tkQT^D /_(뙑mBscxKE #EKΎT^OM)I5GJqs5qaOwjr5)n\ҋza1ːWU4zƗ4 K_R 6vh%mufVY䘒BNZ9% pSSB`ɦؠ;0k7ݚi|TzŻ{!Fk7tkXvͳϿ >}:|iV {5[H\mM]~7}^E7[B D>~jZAnfHUŁ'Myu}Rӽj3=?Pjd̉P\е[Oq]ۂ]:frӋ~oa̳ ],9UMuD~X*Z}W{MNyQ$.%Fx5u+aL?#j)+O*3CwNʇ~xu$7յU[m䭹ߟ}_֩LAEެW K[&lS/iQN™"LS^ٳ'^ ZL{ӈkiCDPym|$9ad:]n0X~L?ajӗd(_v8t]ގ{GkΉCQqJ.zfzSXq_ʳ74&bU˛λe3I8suSֈ.<~x=>ީE4\!ۧ鿮[ ahk+w̫[lyfsl0y̅?)篾Ƒ֣ŚIc3R̦gϷPړd-E vxx{BZu#}j m.іѓݓYXTñ؀O7 wS']ڟUQzĞ?w9ܕ Pӝs#YcEs*)M/TZbTC:Enznt< _4BlZ{~W?u7^E:I3L+VF0$|#?u.u߶c5O[}) u?'vYڽh#M.ZR-}qM\xB㺔Yy>wR==ǿfVwWՆRm(_0nlw^no cZ.. RVA6\X1dʛ@QmwԘݧG *^RT|Wij]LCދ΅m=M)[hJ>C 1=dGםhZg|3Xb喲%pvte'w}^Qqx>s;!,P a &nEfuJ-]WRg ;ퟷqjԆMdJ] TZوwk5o~B'P(R3ܚ.[.u~qzO/wP_mY6Uю>hˬCy?+b˙&^ZBcmʓ7I_:~Òi4E|Y6z|b^ukZ-2ns+7q7"YF Uh|rz[q/}~wG Ok\wQmCV-uA]'{Ś[![4UEi%fх[ˬ;d>Ë9?]ć-+yyʜ U[H]VhcG;yGB;w8Ϣ{>j*&/lnTm^t7.b6ߣ:}b5OyKet=$jqsQ7uO5!1qq tom/|gmNIgKܶpޖg) %zG3vc/ǓYy-#`}73߹|n^ v,n1 u"#*^cchǨ.us$ɦv7?Pyf4V>6vr 烮m!G-/u^8n|drvR;>TzrUϮ8Go+y$a}9顮G,m_11xnzɧt5A1Ǫ?E[&:@%={Ֆ&JZEPܜI?`yCc4> 'ʛ7YuWNacz.Wc!nT&=9U`o#褀j~B-?o91s7ԪymW㡓WUXohoFwnY?T5gw/ϰ.v|kƜ^o_kn^ /WO{Bo9fy /Xu<#☾ aOMz'Cocl]ŃOz=Ã$ KNm{ޣyKv"r)d*8_ʿVTf{W?0yvq6XyƙM\`Nk_HTZ?Ԓㅑg(?R? lMNodStTԿλ(OOr.QH'7NLN,: wiZWcڄN=#+:n[| DWD$]oZ%گ_*ճ;2r(E]:{{Ry3 gG:)lw]=I5XqZ'q ]Y-WBlͷjwJP W5erk 7_KjZ/ͮTIWM{!αGQK6dzVpzKVDe3Wϻ͐oy>zuRF([us?е}מˆ]RD/_ 'ȐrΘ 53oǹhȎF#*M-ϖpem_{v]-YH}{FLZ[h仈 = lg&o4kĬ1 !g5Nt)|6wOdXonY7nfoAÙE2wyQˈO͟8{שm#Wy&%}4m{^m!TJt*7"FmZ'~@N@sw|}5FҜ_cgc1o{GhKGtb>~Lb]^?뻍ղӭǮu*rJngG5^ 5yj3hLfF n:M%ŏZ'26[/WQ-MPĥ'.y~ ?)4H%ۤRkXܽj΂ק_g#:6b9^c7YK?=ߡic^xIreγ^_0 gE(t*D[7o=mx=YN轕ߥߏYe`LTKHdYoO:|hfs` _vuM ߟ,1~S"լ:F3!C[od3;ZwDm~Z݇2uɣ4J%o*#xg_'߾ի0o|Q >/MoAȪ 5C\_͸1e59n[&%[g!G7VZ93oΟvƨC3oXK"vͭO=kی_i% x3@~+8n4Sik.5^[ߪ9I|>zIe+<TT-\u ٸW~n0dn+/XxIZ&^{\{TM::f] wr}&xpK{'@3*W22V px+KoeI}+o.m~߄sm}dL]<_ Ï,{bdvy|4u.䫙F޹uyX\s"[2H.tW*>| ({:|cxA'!=W̝ثd? _Sw5kWN_rĕ}f_YJ9V['+rIrKMZq7,{ٌzVԲ]N^WEyT^c3RV刪K#΄9ZU7eU* jsXb҉~MgOPI |{]fqH0|3Fxwwo]EL̯dX8X~]0)ljUorݣw]PYጕDm& ;|Lxi,kwSyPzpB>=%"x^{ZPٖ/[^ w)ÙO_H_b*)KdƯ+~J4Yřj _+6}ڝ_;sOx-swkfלEo %>[~ ̏~e|=fU}UZWLIg̘(뱎/}LM zT߭)RnWͣ-g=PYIh3j5oG};}cb~@/?|)n:wWɩ,߸/8.g4IBad jAũֈjN+~\m@Of*,|ӺdBX_M=d"o>WuɋJŏtp]ӨWۛ[U}vN\[ƔM ^%Pޠ1|uC\Qlv56eGĿؠٙlyk9?@GL!o'|0}4"ȗɞ[Vk-ۺ~Œ-ZX)/Y⟢FkEoVj?a9̜hXե[nO~*9{]x;nK>YTr쑯@k#X|o ?-0@9DZFk4fDm?s%VpRqT9g/g>/TT өṠAp3WFM :؆Bz52vp8s.ywpD|_]ֳq@uBDwB!=⍄=-s~T 8R"Hn>oGΊ\NYZQanWR^/^ ~K867Ohk1|5M< ?@*qyۭAu>(c|A۝Yqa(Z}L]v}kK3VL~O򜊊: /3?7Vfo\n œEKO_P_qWTXER<5OwvCɌ0-TnQt[b!(iW Mm^ykr31ZRƄSq¯zjLQ?}-5KLI^êڇvɛo ^ZI`S@AYSDsG[GQ+rJn&5Ix%zcrmc3poϩ^n.5J1g NBRwZ<oJwHؒ w$𡳷-MrpZApŃh_jx%\`܃J<ƥ7k4]F/%wR7,eG͒EF­Z˱E=!^|aXzfGW\z0nJiVnQCM%_-֗/p>\zCk.t.Ok~V&r6ʹkk]mCzmu{/]+%ѓ=V~sZǖu~veKL57^B ͏/e}WwqQ:7ɯ }hogAqJ wlH:3ܶrW̤usU__}d!Fqkibӝ'>~9q.a#;ϿXs`FC/]yfK|O[B5_jX3eqa'RA^7{'9l>7bR* _:qME-=/mEz7PVCm 5$7l*YH7X3m+QeMQFuզc6xj_=^ݨXxle8b64T#c— Eמ3%϶^?Mx8i6{}ΒMŧ|*h}Bv׊^8 %8y| 2]VB|[Js|٠M7$|gGXwJmb>X-./\>zC9}˄ .Nηڲ&hڴ/^-p~ Azo'wo^2~$ձ,NjҞ.Yib9Vs7F"O0F#.?R"X3fS ݷ/m";M ؖ٧gF3o?p.ZƲxV֦.{sҔk%6mJ\(q~JZSa{| =zrY>㵢\!2#G?:Q_j\T+1Iϡh?N 7z1zz2 c }3er8dvܕ&9Tֈz#>=Lc8Aخb[ד~lSMiKț(?N"8tnCz*sFϷ _0{Su9i~rېe#vvmF]mž&M+>CڰBC=%gi&?-laS5Ox~=x?3*}cLl}; v^;*0is,x׾bbd~νxKۣo=iNϖ)p$yCq~Ä}Ү%g%u<\KJ)-Z5ZgU5O>zPT3'xJݓ/)ݣkIwĦBJ*ɵe=xiבF1}3ͭj[at$κ0sƴH| ~rłR\9B'Jf̛~q3ݡ~l5m{Bf9܌UkyfãrȆEDr۳fæ^9V!Gݶmik6 _]aCA}f}wTzN5ㅃD.vn':}:p }t[ҌeXpRjW߾<{1[sEŊϩ76w׭uբZW\n4s& gNfֵF](ur;tsٖS_gYj܇9cN5q/ \o٪NY/s&>a_i)Vv/^Q־29헷3"Jv\l+#\ڜ߾w Hmy9"WTj9+<pè]p~x^|F2t/ώwx'uUƎlwGްܰauEO[^8|Đ+y8w7 /ڢTI_w/%^5Vלk ݔ崼`P)Ou%a!~Yc 4+bT _rk,Q:#rծ07( UPk}BYmϮٛ?Yclmui=91PÖ6 h<}2oٔ-s ~yCZ+ b'.$_)!bgb4#K=E6';\8T6^0Aǹ[ '?:zGɘQkSuSզSugw7]nf7,?nud_yեW|r^7*A&_,]]ylPngv^ޟe=S^T\ʗ#Dr-Ke=>NTC#*?t&pɏxǂ[>~d=-/(bḰymɛ{|YPqLv"l7XRjys)c{WșyӇ1Y 7oQnϱ ª/&|חw<ܞ>>{F'{NgZyqWE [c?.ڞG_G:ɴǏ ›2 ^{tY/ًP ]$r9}udseҖ(\}=3gTU<-Wx\/^{߻Щn bxwtY[j]([[(Te[>$hxW |sG!|7(_77[z;VN}qF҃W{v'o??[;2[T}ZoܚzO|) .i17i |OY^'2$v|2UB7g](+q|J:c}@Q<+λiNt͵6 ,|:6%Qx.D}۪_l/-ʢK>yy=;ߺxpGŎxc1>뭡t]콛i`f3^'?LcKVs +6\*x1H+̼tɲ:= JNl J^-j}23׶#oIf ︗L.-|'! d9WH>SO9Y}E-G-BsMtbqm#x-y’kwjWKjY[šڈ#:mytZ9]fÓD(鲸䣁 KE$N<:ol#w~3uH\h:ei:BuGQ9`ݍ̳dq>q˒' m׿Ipʂ ;(鯴=lIiu %2J/M{Fk$~B*m0ܿl+wmsS9`sCK~cTpFb|]ܖkbK]ɶic؞ze] vsOIh{&+}֦g 45}<20W{fvY問uȾk)%x#ۖ 7,u;?++%\m(zC`N=nix;jSdJr |pg~塞Q 7 Vhh{q|*v+mBF͗^)v)lJHJQFVzc~hi_J*;`Nv^UsS=vUWA|3~Pm{WjM[TWy>_]N:;踤Fmׯƒ4:-ͼɯ2v-ڭ;m>NfI(Y\tņ/5gI_1'ROK*3ɩr7vpB |/|XnزGI l6;O;wMos|8øҢvW@gOb+: 5؃Zt۶Ǣ\ 跌 ZSMdIz[Z|l߹meš.IBn{R$+%{hI꭯\nbQ\ 䭜ϋ ^L=6JTnd[&Wb h^zx?ى賬cG\Z;t][_{v7)jTTzctFrٌU|IVw󅴋+^kFacQ.Ŭ|]GN 12ܶ=ӢN&v]:^Fwڰf>wrZ͕I_E 2+FQ9>gU!aVGsntI./;쵒ᐴo}):8mS/\ZnuO~X/wo#N~Wk+J3ňO1P'M行s/NKwi^,:r"o5}5U♷o9*J1mby&R<(6Jrj^i!!6Cϸ1 T-F*gJ0L'7}.6랷k8ϜEXVs?T' y9|w1`v7+woXozP,i{Gֆ SjSkvW=;.O[D%fF7NEX;w?)GՄb~kdAvL:ZR,|r>l =+ Yh^Ҙ%k=d-YF~}O1ZmbR.;|XJv}_TmK)fc_ iKi3/}ꄀOCǶY/_,<`W:eôrI^+>6a4inX[Uvl ؛I|s3s)ϝ|m7#F,vgw?LKm݉O D68mړQ"UQ~Շώ>zڙ%'2B-vm:Dz2o|}ZM_(ggsB*AvGo^~[[4WOQ:N|ugxm3V|rɾ>W6B뱜 7;{XXebo}ljoe:y%VΞ'fiJg)̎nΈ۷3cTޯiloFsMϖ߱dLAsʺذ%Ixo=Hul[sL֢3"*p?MɁoi-S.jMȲ7'vI}+4q˭m+ZGT7Cg5o'xL5:LfaDz_կdN <\ޔfOxTt1{ǂD͒VH}sA;2&Sܵ"-@PfqU/6Mf<Ueha*Mh*:!57myG]rUGj{O}zD'Zک$rWە6GZ|`tOݽ1ɑqr؝B_fn]x``/Bᾡ4ѻOc4sOUդ4do[m#ǷR5qeji ;UTͫ$un}޾Vߦ2vguH2#K:vi6_f5z3 []ubh̽7~z}ק[Pżުd9+rz/~ 1ޝjTd=/uQĥg-ex? N +畊wa=<-ŊoD<28.+q "ZsW&ڨV9Z*3h N̰WqƞմuuߏztJТ=w YӼOB5]RyʮSVr*yOoUȜ7vWDz:ޤCp f- oO/ʳ(m7Fc7)߯dyKҾ1blAGV<6gc"qvnhӽ|0SV2/ (a7}sL,e}q kjfL~[{I^@'|]ɀɫcc7K0KG{DxVj^qAw>t8F[0I?Ҽ7y,{۽xfId.y%^uYwfv{vys&'K~ }bsK:y%)(㡗/}n3 .4D|asus?eZ߽y]w*2L Dx|.=H3'MNj[3k\ue~qRr>RDZ2Tf2hLg[l,+a,~!~CIN^'^cyR͟i\Jɉk *~Ӽbꕦ,=D5^ZG3/^};]KradZ4_ުL?Pk\#in嵱S/˱L5l+׌ya}"\ %V=y|ĮɖL"-.byE׮"/JQw#You{rb9j_KWXvjh$zzΕ01 J>N8r׮먦wܥ& ܍hH$ɬm8;`jq<ȇ-=y$j]ro/蜒zݛ+楳/]L*-qPK@~̩eFy,[&}RBp=%u9i*Dž.;Ͻ+n[{7˙|\Q`|w-1'zǿQ՚$pUo`⛨wMO09Lzlj)S(1{¹'|gR)[ƞ)8HZ9KL)/8xNOSݑ/qc6~L!F6y 8N4{V֞qC(Dv}X w6ZśrN er ?=|wѯ&=j4H:5)6cT`OՒ.5`ԫHohP\i$׎O֐M0D,i.c6}J+xܼ>ۘYg۾{:`ˣLK>]M^[q۹^چuݮz"f8nd*-3۱b%ݎ59wao1Z,<5&_p)1;'[;6 ]Ӧ}3=3&7Pjzuuϳ},h{MO.{@e͵G Ni 茹`+b=gƕ [-3ߔ<=ңm.LX´`cdL%3^3]kMZH )u<FO}89%6|>%xQsN:{/iT8N}S.(_[J ިs 7NirRI3d?Q)Fo' &u>8e~ WW,\j=^c Ǩ'xT(UeK Ov^̩c/?xU-')uyc=M<.." |}PQbcx2(<7/j[SVTFx:³ơ>³Ḩpy3h28TFPa*#Ceq #lPa>TFơ:8TGPa#Cuq0Ḁya9tz㼩0ơ68FPi#̇>|0#C}q0ơ>8GPa(.\Ra _oqh0ơ1840Cs*=TԆbU i Uյ8=S$.54eLEUE#'s>= ֆ?L[g*?WEU9WQ=5@YYmؚVR_-دcj-*{J(ZE;:-htb9&zZJF*Jfjj&FfJf&FښʚڦzZ&UU4TUԌ̴Ռ5LL Vd,D5'HKژMxPh$m^UD'*T`I+xR~%(_p_M Tx5 >jPVTWQTF$N_/?C*L_}k[|*0  *N!HPJP gL aPY8cY0 5q8 ̠Y8&Ҙt+~$q2ΖEؒ&88$<ΗNx 4"0I`S<Xd˛1鞬 ?h!_Ï$(,ox pd2&3!8/ H1X?dH, q@{ĖQh8 [RL<22%8{3g#;S='idYq&?FV8#KKxl35739 LkcKG ks gejgi@Y8XdYmpN8%bSbKShႳ550ڙ;@wxt#™YC?9ۀ- fv6V=)6$˃v]#6mЭMmlXy=A@(֦(LHrdWȠvVF2l1d y$P(Sƫ#AQICoU5M X`inlkO QCT"^d&"åмpd&"xPQIpA&$}a(`I0d/̵ ̤-`q^%J@X!~!N42\Ly@C֙/!EE\vq^t!ΓLVL`Ec4:pC`"ǂ+$ Yt `Qd"څ':&7\d:)pp!18"H$lcoq0DQ`4`Ӽ8=,jdܨ@*G&pX:H b4r @zAXP1_i,0IPҁ 8 }J?]@ tiDq \0#o\LE&Qi2+KGb :t Y,PL_  Jm=Y\ |pf`@ pt-Ky HKC")DB RF%C@5x2$6s- 4`!c ۓ!(yz Ƶ@Hd*q A@P GT\@"DzTqAX*BQKMK X0$y=RH$*@G  >d +l*0^ j#4,|@EF$ԋ8@`p lg匰?ԒP @ƀDFGc~6EdS߰DjJ;>z`q@0@W_R$#ӈt(6%X Zzsq ?JO`KNϽtt_ /yҿpo{d_z zL`(($}I(KΔЮz,dP 3oeֈ"|׏  3=5$יpD-j4о@:1< $ @Lz2X2A`! _v\ _`B3ւƫ Cˎ3` DLwZmAǓL`CGO!0t|),R1lWsw]#MN JIB!@>2x QT8~5:+h+xlL:5Fk E! %&u0Ab`.@d!QM^? &_1R $5t{Sc\ J!nĭDȀ҄=6d:@B#z34ziH~ڑsf@qzpv@`0I@'e1 >ʳB@;,g~pA(@]T2H AÙ[;A3,F@(T[glb iP !/6 T 45Vg8I.Pd qlL8k:b ID"p~@Qzx/ˡ>0YO2d vը!#Jz!ɢIhZS|}(TD,q2f 8`t^-82 <Pd0L">6pEI%x1W)r8rh!1D !C Au2N2ĬKF;itLYTL21 N2H⡈q EJglr0Byp _W9o 8@QqJ$)%g-=7]9#j ʤ=gFfU@?(_s hoąp:OkI{ CH| r[ꢦ0t(&0>WSKa2$'! LmL,V@6PD|YT!y ;F81:4z=t?%HU`-^kz FySI~\ 7ñ#a axM@0!8' a{q%~Oqfe4 `B00؀Z7,KFEibWa0!3Xa!6f[4Ut8v:{+ @HX# |=TV$-;ߒ`2I9P2 gc(pY.)4.w[x"J2 $3Rl+D)rX,iWM!LCVd$ah}É &klPQ8c(jtqq'9\ n.`A$$H`LDܸLEIIY䡥?t1P o-le5d9D+u0p,j%T책o= DNJ S]Lӈ@2b#j`{/n6J%Q_@$Xl=P2dD$M9]3$Q |F҂ :P ˙ P;C-wO_щ.#p 0 6G}v.b  'bK/u>̊Q#V78?oʵh5Ƥ$< zG}+&h³5Z9mz s Y#42\J028H*tۢ,.1< -p. U,=ϑl$ $6I$Ģc9GIq6D3d}Q7ZI8$ؐ$.clmdeCY^ACk k  5hZа}i IL,5s1a9t8$נomnL\\ɩ.W~-V8,_q-aH 7f܆ ?ǂ@bCm4!skӲt"Pt~.WcA&I?q\{kX#z> ރ ϱ`b|Ȩ0HCM{{F4U#Mj$x)~ a RF& XvfFԼĎO"gT2f` 6Mfx1OtG "!1\`6{ ( cU&{["s(GpG2o5HPopH 0hecJ^K`@`q施Lfݿ7h?xؖS#nACRوA*rp`ptgDph^̀cм0ƉYv._19QH̸$H˙;q~"6pw,L!YDB@L1-u"iYI~dtN)=HB_PFQUQ~raCO# F wّ`9`P7[FOuK"`n8;hIIu3FgR Q%i@l$/0 +0 su۱}j,W}l/}C}fGv'SDGG™,6F$VTל xw$74|/wSՆeؔFO VH\:Rj\c9$utkIrP5y$̎FdXtFOX*<<KdIc3C/SE9?f<191a.vMNƼ'6h3As*x0̀vs-hc%NcY,, o1SpH/1!RCNԐQ!"2B+<?aa?S3BO5XG>@Q.3JR(DD WVꄪk d_}EENFw}',{-\j[-3us4|lm/jYYTAA[H@V::yaX{9BP? 0|q 춄`WJ!q^`щZCO *=r0W< o=# 1  5TBdC@I3lنJ\P: tU%q慭tn>1t}8k [&`&U$*;`Rq l\_sχ_DcdzN.͸1" , + 3r(NP(0q3$6 x,#SB9)kC#R E{9@eRgp%Ck tEn* #(Pnp GA悃6@RCF Do:dS=tNyaڈ_Z?#@# ra| _?MeMvE@`Iq(AWR/?vYX) e2%8oOQK !~dK_WMuzXwEFAKK][AYBclY͉G=t\:q1&0ΞB%30T#whMK"(IdO}I.wG+r FzCl 譬4* 76| 9TU$3Pe( ,7 $Pǰ"6{tRËHA38UTG)/)$.[KMIIKM1$QJ`2f@4`/R#BbyK*+)I _I/iMx\ z@ܘ'%U޼7" у?;eKr|p7 CbcRɞ,3Ic2}7_H08C1\(spA$:/&D"Bx` $xfn&2({sEX 4d$%BV1Ffn'Ki(iMr -qdcSٸ!4{a:ї~ Olp~DɹQ?pazd9U$?2BOk# lGFnj?f{$` ߢPa}<8*b#4?k1)&'}WQVVWkg?Pd A#Gp7#?0E~(Щ/  ?FCN0e_>Z: yMݗ4P ~ `W _b5O_DHPa"!  !7 &i!bZO-:2ӇDZ8HJ:rh%X{~=X`D h3 ̡v10+;',96FoT;N$*U>2$:BAc@-Q@҅?/w`O@shNâlZٷ3cNZqN`FL dŨVT-ܫ] g}Qx= >'O&>v<+ iAƈ[@P8 =G2s.o;k޷Hz"oR`QjvQX|A[8b'Ghml"}8 .z# 0 woKt l?2v=d1!5iQxwƅ55u NTI7#ZU87A0kḦ~9g`[TϦC"ZRK *oW5?5a^kcf.(xAtPI?'=ۢe +vnU]$ r/oY?9[ 2nTfXwx4v F jdК (݈J(h-R]jX\)~Eeד(<`6K e yG~%Jc3IDx+ߍA"eʆCceDꔞ8*uǑ(^@&elxM9-n0@8yT/m/qdFE8-*ODdɠ'PZrYtʮbvT Hº3!`0;_@DTd`j0GB#M^D;hUt:@.wpA`Tń9D a !+d)D9uĘڃ*|h& $N:<FLP Mc]=SB=8F7g%}.RL"[Zs4$<'T6: @ dXhđl3zhG6`+eyxޜHTqCJ!%X!QflrfMϹ0۰e_vÇ!!{kX%C 5 LGT @pOPǜ5g(Ѵu:П؏L.,mHo8 TJJj+~ks_KWtaJ۟Q__j*(+''w|x m Bohiϥn ]99Xe` ^ߙ}^!&]-B 4>W=~"/@" @ϿȎ) ̿;0}8kx;ѹ?'B]4^ng`jHX^:sEobsE^"kae"ȋJ PGi֙D:Q uĤ5lַ[Pz1Π,z'L@Ф @2}Xa  T&grn `,#݂ /fW2L:B R֔zMm1Ē?&̵@{l\NW@N>vH$ JK$/AFv^dL&&mIP^ZޖFki9v¯:/li"D6UB$ɤ$2BaqVVf6=d#OÈĀ6^"mP ~~@ي}ZIs?_,Ng? 0!b†d_>uCVIZX㱊K7DA)n)iæ?U`Htxu;(@:-a1+ts CJ9U4j81(2H+' z(3/p'5rÖ\7j CD/o*'(4:[{1w5-(@S*ŗu,1?2a./KFB <ɑ0e~ ,??4:X̂EhJa{^`P *7!>Tȣf3;7 8@ fX thC,O鈒+uہ]T7HV2DEʾ Kdt}u$fAF7; Q5 d[&sC7;7Kl:x#EUIJͧtX?\)BW`r"-Y$ YD ߲҃8^?DT嬸PpKL_K¸&:~c?ԂI{k"$慆ؔWcU [;eJD1C#1Ɲr>h|=21)Z EYG!:죂Tdp:Ë@"89q# K!صm@]2r[mMLhᬽ?ah #s8_/<с@OҀ%ʹ f#;G cE\r~?Ƃ~?lm .=T.~O g! 9B@]?48h㪰r,Ou/ "a$-D\ ŋN !ߨ wDO$ @/2GJBTHcD:0b.F/ϔ:R+t`d{quߜ00 $:9ŏAJIШ_W.CnLla.QؑUt1.,aZ5 ^ 3;[fL$LW/m~-r$ 1A pSз,E)si0T{ce}{6v`bKNa@O1cC >VXQmjH ӛ9&j~ץ:@- a8Ⴡ&d݁eb/00bh6r?^ǬbzT`W凔?%Otw e}F c C.wŽ/uHz($C`} Ȟ%`[.<בiHDgNvt?`k~b\*-]̿Y>&C߉jhrm.w4s ]3 WaՍqOO&W`(4WN]ǀ4AvHz3HI%x<(,x4{\\ś/$HcbMMNB+!v7 "s*2dC^9&_εhP wj<0-8IM< s(8 sf,V)#wLsREE`%hhq$- VtA @C) 6!V\{eHE֙>P&$pPqW~;v`\o m? WmQw<˃ Eu4eS`I57?.{"L$ GC'nv=P1_KDhPF͠ja؅!\q9=y>A,Dh*6ŒDI4&IRF0Fi>?d@>A 265pi g1E P'N#lOA?_lEhV-UHdiIulK:T: 2 P}Q5 'OL{\{5oDe}|1 #5^,v i)8`hxay, Md*UA ۖ]ܭ$^uFM0ĕTY;(,er#0W"a [qxOOLAE(!D&XcJ)\Nc$0EMܹ2_UIBݺ z!RW%I.phӫ,N*Q8xEm);LAzB,Z'Kƴ""Vo0e^&WRtEA+b3X% ͧpqŗ( 3d _y !q's[H [F-+hXsd%L4]8bձ)"eDP.wiT  X6y\FՖ֨ӷknY_8 pX^̧m淫 GIbI$8A$qݝ|Ȁ[>Idh/e(bYAqmmcHlaiH.ŕ]mZ6j;,n1؂1PA="+b)=ۂaƃqd8 t?P$sτNyCocIrvraGBwFd )ucU~-&¸7b ⧖Ss>@[֔e`#)~nk>9Y1Èkc?F .;ۛF+4mGK(G5lEBȎvԛ=t7$3 rM3L{8$i|O`_G񿒕¹)yF 8ЄZۘ$0UH=ɪPcnM$ j`C_gK&ua4Qګۣ] %^,ɻi, (F97$R!ĵZq8OfS|&(ݒP#HJK2LKp{MLlnbbȮ]p;99>=K ąjq8ʨ>4 +Xe#֔$Az:oj}@Vۺ,ZS` FX!FT&CE"8zʈ ¼J3Ŷ W*&|jܮ$SDcoT: kk?v9PHAIHvvT;WT* Q;^}sP7@5%SSضl :zAgFnBPvS[h6 EuFk@a.B6 ߽,vca68 vA9#/>8ȿKRi ֚rgY?6;-hͭ%Z2~࿲xV]dWecLuZVqWVMr߻g<isޏ{~2\)hĽ\Vl[o'O[~xeNtg^<J ;]\L'A>XKţ[:ޚjm56Z Pox]s܃kaMovݫ6҂FZV#EvWi/?AT"ՃX"%:Y He;&ŶFd~vKax3zxvV/ySh–zzJU= [W.o2OՁ=~qc;z'?{N]Ms ?t^aK/;1 F޼?ft~C (1vOmP>ϫB#_6NsfX7'&0c]D z?б{R =1n"jՖ~ܗG ]]}Cw8kG0n%HDI;D*t]|>_NxD)VE{AfB`l|W,ʉC6˅؍\T;%M4IcANv-SYIUYmjߗ@ZmxMZGr\{ϲȁxiB{8LQNOW1_V0P6M*fmh{nR W*bdV31ݩq<[x#5HbZ2(9% }\U)k^|] CHWȞ?gzWczV.~CCCן!˽Ҩ|,}3[hۤK뿐p)pia[YDqan὆lm>: cAl;RT,'}bBʜq3U.? ivBfѥ ȷ& zӬ̇%-hy PɧYQE gq/+ 5hv]z~Dmn4Յ#rSY% >#K0i/v ttF˘:)Wj?y[V*:|.oy8,':j.©` 8CYC5ҁӾ4Ptg憵#\NA9}3i\&Vǎ[rivp:dmS}v{{{JMOhY6I KIr8?צsSRwP_iଐ;Z=aB.'R!ہ:\ k 8ҁ|cop{qg~Ɲ& ‹05a)kL6!=@FJt5 jCxr bnE[9UjfaV LyrΕ7;'#*CZLa:E,? ,"d_pxD{Ysהaœ{ݿ%SC/mk-܊ܜ+uP-I1ߖxOl]G$QbBIYIm2Cժ=!`[LpkL_ `>s_-ko1w$QwoO ,+f<:;S3ΔuohYՕF7yw֩bR2FQ_%ԯԙT#Rj@dQ^4 d\Osr A;ncu4>W0zAØsC-p iЇHmD#7AtbO>sf,?0k|n<6YqD85 \-}xjßS0`0weukf8{ط1a eX =r0Q֤hI;K(h!)((Ue|i ge(Z(9ЬT B^㥒rYPUr(bpb`yx#D&.lV<κ*+^eW|aVzs7j|L Ya?gouZC-(U- &ɖ\4Z8fgI;hl .[2r͠. (\`q tRƎsvOoi^*yUloT|!5sPod!E!6"P%\K*>%!$KS6u&\cD- B"̂!D]=-9,hSL-P$Kv21~dKfI8b&v>ݝ磂wAju,*@"B$y;L ӪkA GPh 7ڭf4V4"10j6?l_-tuYTS'`(n)YއR ~Z鉺"K{[=M1E tuM!\g~69l>e埿0k L!|` [;gYK[ݰ,QǍ`)5 : f^yv48rs8.-:U0f1Ei*]!!OqN "a{OM0$_^T6ϱgW6gB:q%s9sX9欘X.I]!vg8.X{%UW!(Jpr.!Q:ȸ(aKÀ]6䴡sjopFBƖ;"\9EGAi _=%XLnҚ(@s;14&gup~p< U%tG)*UBZsGfL I9)D8r |z.>:[y*W@?* {$luU8aBnDٕ%Vh?2 @nAT+YNxsQp.|+Q*b"횑ՏğL~@zx@z0AzJp+ȁy$lֽ~k7 Z5`,ܬo(vLC><9b|KT̅]ҏĒ,`O.).hδTO걠oj>2,Qߘ .r)lIV|o+et+<0bQ~Hnn4g|nTJg(C%¿.?Pѵ8ȔU.zn׈}( G:uPWa4o ė羈@豬3Jq ` ž7ؾq@qR\x@̈́<4;fgY HWmҗ7;m8e*R81SN%P}0A}C,UH&/HyW28>sh#ܙK_ ZJ/|f9UP,˟ˈZ(U/0mvc攈p[1sef6􍱽 <ly{Tj' &j1ShËaKQ|>ʡN\*|"EfbʩY玶:[ J̜)t ܣX< he2 AJ6Ԗ'ʲirEM2ĖS c oOa3 N׫L]b.?07J TDX׿̶Gfs棙Ţcj҄6.IxzH܋SiHLYO*CՙY΀wِ}ծg,Y"Ai϶qjegwckn~{[h0vot l&fZİsXrz,PEK"KSJh syKDFeASE&@=, MP6oXKRnPV3)No(+XYDVdz8 9+k5Tpf_$GG{`!Iz@^ ~]&DfC qbJVR#?MVyo#S ,mo՞y7L2֟MѴ#jQaiʿ5?7DM=q>y|Pmz&*D(AA$.k2STN/+q\VL1uh|w5iY =ysΜ';s`*NB.1ꤹLS#\?x{5{9R E$F\3gϫzuXis׈8`&wn}7H_Z_owZ 0$-)@^tfҟLˇ]lyBKq\d8-o}p _$,b! ca`ty~o?g:Ewc:o{c{c~W]_8=PDdGeo_#`}_S,wu6S*{u6SW$P4%`8nl өCd9{ IQDetf 7 k`LmE׫-$߅bw$-Fp=5"!zf\i  "9/Ƣ{SJu ϼ=wxzjɾ"E>.&cߞ?@yV)'zS3S-Oo_ڹ釙7n>`՗\_@b=p%e`vhwҽz,H7h0Ґ6\Þ4{'*J}R]'*WYn鎣;xya"3h@{P5% G2;ɍ(L+0#6C{!P-*P_p~7Ϯ?H$1>$\ B RMڠ!_Ħ_W.B$5HM緱IB0hp2\N(9gʦE lܔE Bc oԭ!YwνZ&A.CޖL] u/ͼ.4pِi*K{IY:bkX, Փj?V:F5?5p?oSlY"oA*=h^kZe|^jqDT}x#a<1w:}0 ?2ґ5VcApn:G X6nh.~2^@۰)mܷ k'ЇҥӐubp: NB /gJ *ҟ޹Iξ^<%%8#/h@GEHsK@ ~YpEcmmm_=\@Ŧ2ј!v2 H^&#;V3 qA7c9 {W g-5"}ʠgq6E=CjBB:ONΦhwgO6K6v~sΣb8J] ~R\q9@nFT< Hgo: HBk8.)?zs~̋^~' *[7p*5 ߜ;|ĮܠjTas-)Hh<hkţ`UNax<ٙ{NHc}gVꁴjPEU՜ϲCVS ?V=KU+WU<#CuJ5(P t6?9n˲/ 9!Os*r%.4-v_J}Tjq )aɪmOXjLg c 5(m#LMy&?&+>=8[3>V359G照;'$1S M;߻rw7rӳʀ"%msl- VJla4jC9HaCܫr/0R,f=^XyriL_ z!nfR0cS,cjW} cĮ5 x&)VS$b)qүSɻػ>WD5+G_IZVdFXpgt}2[ |e8=J&le kW/.}`F& LĄo Fe\y?B|TN3Dn1Jvb@'{f(E6Sbm!' T[uaЖ[+PL6rPY* 31oi/bs(ZϽ6ut*l냟HR] !0Z$Иt LҭA! CߨPd#9b}.Axf@}E*4$MxO8=I01 H(MDaX[<E 寧Y r嶶7[V N%ho=~?;t@N/L; a~}`G*(0p6 ڗ^vvÅ܌6M$]1{Cp*GYjH0!pٖnnq5L~D;B9NÝBI(|P54nTlA8%qYS0:?ro6'K,:Wy40aGns/OsV,[q[RI|AMiMŌ 5"|{v'w#zS)'^`t*TI 铟&Gp,>mX{;:S96R(\PÐ,sf;K7rhq&^I&fٌ0rݩh \MX7*+J]!K˵-Q6I+,*ά< 1 Q/$$'\e7s%9 M#4Wi^ Y22ݏLڎv5+h,ѡz|4pPHz}絟n8j>>wĭ,B/[ݐ ?0^H͉S"1q3Ϳp>>,]ZtoC-[c!Non%aF;̳FGi0 ׉`HgAx?#"u:|xVWxu>Kl \O_0=pR~ )@*ak 4Rh8e%+m&L&5- h\/n$HbY O /+]N4 _w_x7 ԣ: y j/HK4C8" QbK />;L'4|[KZ&947,ɎM`׹2răbe=Thx8/iP?1JOl8m6A"-vT"heYǜ;}g.)MޓEB8N͘ˇZ@ Ѝwֽׂb\QdQ8il +Ǯ@|q͂ۆB 1VTڭb(ȭ άtu&!:tT_T 5"i;R( ڡOf]cΨ`gdyY4mJRG~8Dl Jh&=ͧ{Q qeL3ZDV'@լa}iA12,?` CĖWh[(dAlP[mZxce?ǑJ/ƒ|zǎ &DTJ9hzG wyٕ](t+MևC o ;ϦKa}zC6>/~H<)ixD#S2\+n?Lh1&beO %̯K( `'3ۢmg9C+uћMv>q}q*R"d\KO!K.o$m֟XUvxzgsqnXvDhTygq-VS75JLt萁e"V볹JAdI(+H2:U{);L(> ?Gw℞I m""M/eJLz)m*pS&DXL"ٙi7JW6J M#*ZclZ! 1ZKЇu~cW@Z~N ^.D}(u3O>AwC~tvkg牋~~/?4_($e;oiq5{x%`[$v%[;⻗'wy_Ӑ<]+[4&VQK).P䷪Ay1h>eo~V#(" )ɐYؿ 'BF]DڂNH4&\"(ZZ1:Hzs4uR]e8}-(w}]<GY?T8]:-qxkx6Cuk6(\'>k3A]f pRAb\0gwVPdl7 KOr`E$5hs8#en\REP?m9inK5*VIP9q!kiD>;@q*Ne3jol;[;<?yj뇗Jt NQ*2e"ɒ6e-yly~5avE qFP1Q\k}Zm3m*Ue,k+ڻùs +Py۪z`Xa^zھK.&RiU(vN! !܎IAr! hisa "O@B,P|£@<6KQl1C9̎L)MFc< DEFV"<(KGꓔ3|W@66:2B\b{8q()m=pAzo^ {֗mxUG:Qs/Č+۸DRef5 (ϐ_hC +'M{ѲU<#CAGI,TW{.Lbb!8`=E:{DC;EN]:7\Ѱa'b*5+uµ5Y&e2s%~ D T, . =NGjQ>ĽĠ*|zp#Z,N1~v>Uap.VIb^\YwJMtKYj 2`\X9A _#WdI|~J0W,'%~^0|Gщh$1 uu٩bKBUcށfɜ`5y:AFff?p՚+``KL Tm4Δ\ :}ݱJܒ* 9=95Cu_D`\ |`N-&s <0cR)t_$!tZz^iBjPpnۥ[}bIM;xS.\Z0y:cdX؆I0S'Fg{ u 0#uD\^+&u(h>wܷqai`ifWxh ;8aPQ{ @聅%JȰ#>r|)J=v1ڕ4]\zlm`_OVZΰIgM"bû~;;4!=^Rp%dIS+Wx`ERW+@vt4`3K%[0z1dH> J[rh=6źY\!3Ze`p-ނLrcYܮX9ލ(L_F/A߽gQ큲t={~{Hu1֚D_2b&[bk@{ puz7քHEԒ7#a>c8ҝ}B!S^'xNW]5款 F@#T{"T\hvCNu j:>~vO3ָO-\ M`kolnm<-7Րaԫf"V 1r/jqGE8m7.mrXz,nҔ^7Ue`7ޔ#U$]P* >zlԥ)w4+₵/hE9҈)jp/㛉OIEUU e 0%0 j|Il =(]d]]$HjWq݃^te #"RF [x\\D3K+a0Dq_Z`,zg3?X}ԛs>U@몣Xc{{8?NNOc< ~>|"\/Z])yICq+?&;AFUӁ ,{Q49iii,)S;Tfm<~>\|P^6ªz1XL5Qfgc9%}Z?zŠKcauȄl+(L_;G,;( ~|{qkb8}$O~\R%^H]RXD ~N+sΗ+y'g@yLL)IZ fـs?tO>rt˴ <}[3)yi)Cr{2QT:V R:qH!!G/I<\`>@I ކ#=U9U۰%ڢ%Ua1FQ\κ/ySٞ19 .9_K4 #'U6j7iaIJolҎYo-ڋ֝.1ΙGDCB(Q!u7e̮_Q+xJ(JMI:Ax]pi>bUhKf06td7*ֈ3]P2n+2O 2ٓ%uԍH.]!S"x&N,ԝLuKMTN)5ȸBhG*=3QM;[ )Gzw+7vYnoI EXqNƥZR(":2VU^r+X0PPOx*m)3kIZ'b&ѳvޝAh;d<7\]:b%K`@I0-৬̡RaɇDJmoKkrޏ[{( O^v1-Z_ EQI,XgE^оG=;e Kf[;D'Gu^#fk%,JAs&/ d*y>e!?[>>m/T"`^ gYbK@yգ偉m(O%-} T gX \6ȉl^=` ULU%? "(PMjT5_wv_+V ucxaKg㋭]v!gksw߃g E"Vʼve,ieiM}}c{{oQ8wWU>f9hG AQOw |j~Jy\z@4WUKo1h1iÒ۫4o{o^U9yۋvXBgo3YӊRni-D`B7%4"_@`G,,\LwI, a\[5^uٶ6&jLac#ςKLZp@dC莕*xqҸ6 P6s^(ַDSr|RaK J#f rBwhH uzt) yJzpdo2bܷ9.r@NK/V4ʒDiX qWם!(Y*"hZ;ԍDK$j[gUxI4nPIof)Z'tMK*&9RriTR-n!R&l$NJ-?Ɂ,wa&#u|نÈW0"v/A9*@ Oy<"T~X2t-/K[vg{=B憁BWUT}~|DAc}+3CpZy,eU+xKxjP,hݾ|{ ^{ͱ#` !\:.1+rV7'7 ".&{2ssgxohjX;ѳ=jSM>ڀn`Y3/Sf,$3!;1akR[!.3*Z+໮&zzSM϶+rxPqxSnU:6jT<FFIθlNPӞ d.5{;?aM~?snV?=^·O3{7oni=ml=y{/Ƿ~&9jVU-xNWGA5)Fx01|B5 2?"7Ui5',hV囗ߥN8=<‰ ,H!$_mէ{Y-[uGzipݲ)BJŢ|{QEc7$RmeBW&,P?r>7/|㸼8{01!' r^-d߄io6y7 憪~ Y6HAť d !pw.-#=b  89(xx@vG?JcpecU|H`!ppV\\4☠^?]}A磉-F$j"fIﳻ֤]lo70|a {tu on&vp ϼVs;;2/krY(IB(i5qN" ?i$!BQ$&_N uC 3Xa;`7QC -@Xc^ ȍBoE$,Xdb'0ZAiϨҚz.X BsZGmc/؄6a*1E1&ecP0c`& Ԍ ,cÊd.50+C qAsHR ȏOk( M8G#S6]y7.tC.4%Caal"87SY/jt,@}S/Yv}Rc/k3D pKh82L#;AL3M>8ѯm`58=2v&Z\[ >= 1Ϣ+IGJk$} 6\@&Rf's-]s6Fjˋ@cC{l$'f^c[d~Y8x>--!̒S:-M8'ä,̱%QMSd Dhq!G u<Γ٣G*H0J#ih-OhpT 7S5cEsm]xMSKHATy;t fee#I! SsNZ($%e>ٗyƓ-M6. JRǿOͧOnM4è0&"I&3yUW3?8aS:f8N%k",V;x>ƚ.L i}A, PBbpY%_u|Dt8O@AA͋wIimZˣΛn>0>PW'2K5TdGT|[ fD^B תPDLջMbU$mWCGgu{vpw5F)&& ʙJ,Ɓ0jKBRTy(Ei{G/_;%V,3{9"~Tk{:>ZJuQQ+r4Yn EJv x<ʑ$G;Ja/llPHUM4Rpx#y˩2Gs”1>l /A911csۮyۛe17w +d6щksqĨ!"#-iOCx2 s  vGs Rcmn4HM{?'ۻV/0:E糂/SZg3}&sܼBt%`T࿶'ۭ**fao"uv)D^bKeAPvN_{ LLw3?AKcĹLVс r{8AgL&/;7I坃Ѯ{pa V4}S6l"RN@Fʁq7ڇy4 ,J-q s I1Y 2 &wWF5~զR 0#GePg~ILd?' 53ga޵m`z`{ 4-9(/t/3A~Mt }Ӧ} oQ=[8 S 5pq˟BGb$Ņ(*c?-jR*(0i Pt<4jeϻcX>mooM7R/V`KE&\x|> 3cn]1Ou&hKhot߆Vf42aKg\*.lhҊtG B Z+][;3 K:JIhӳ s]]"7S4R4Pi<}]#MKПѹ0uP!_흨7׈m0mהkL@\7kUj<N b,ʶiV gX֢Hۜ|}CQg9ACGG:f[mgv[܎ŋĄ}N Wo.ꞥ¤䥲4+bBykI O/jE74᫼(PPk+J Yv=hAqZ,~NS< FJ%ލ`f6%φ]]Ոq/T^0!H\$~J}'8TaP q|3ƣPlԬ/kZ"a3 qF/tuoƛ;YQ^3f!ho>I3gUuSj"xQ]"T IU;~Tzh^9pd  }~og#+ (1uḮΈI*O1t6(4 ({?"(]*c@3 gtikd :[ O|po_ 1cӱ_8J rb8̀$NC#M(oPfp-Ң?* %҉ĸu (DmIKֱNJIi/֕f oid21'Bbʣȯ-cz>g@K|g("ιt,c,%q9S ۅvoGd1sE`8 fT0j{ry0%vJoK$Z.Lha#yh.d]y?t,YC4>I7YkpKT[B o|]@; }0QlcBdW9tjkWoͯO_ʆߚ4gGՄ 'B|l%\, XU(8O1qclx8~kLKQ Va YP>Ĥ*K2 b !ʒp_AY6>.:%yk:VYםLCr3_ c1 AYP  Ըz?,$pAx WXg`2r#f,ӛfibPQ nVU:/K>}E@:]sWYy~+^FbC&u3o $%e,g2^KlZ %N,=VW?qU OV<5B9(pi㢰R?Ӣ8Ҧʼn4Z8%:[@/9?gI`\ |Qe9iVN.gXAV&p9Q9YU&FQ80xٮ;XְR|ǙmTk *ZVUQaɤ7nM=j.*t8 wqV%.%k'Nt$Ӑjʸ %u:lL܉fu7x*ny|~bL@7͉k~U[ V,0CBa%끘Pu JhsOԊãwg$-Oj)O٧hj5K+~($? ^lҐsMB^"R-28:PӐџBrV@rJrA[p"+ SAyu4_FF}˝kPnDEI ?Dr<㫧n1{>N#ϴ%c0+{-=rV/Cl~b98sV`gSstR¼/´}Wwʽ*[*[y/,(M K\/~3:KQ!pqkl{o+2۪T޹ȱԠR8bm 49[F ZsybLk&H Z!$P#p9fczTL{ưETcEYXT}y/I*jPTQ&*"9T lE>gS䞏eXc6WѾƼC]'7(\&Qѿ+Y:7 V~ u2צadB]dY&>ZV_P@v!H)"+ʝC>W`9Q\Ɏi4g YR|I :$WT遹[Ey\\8 \wpH^NRZx]&L06M"Ζ1`os%KʑeeZu_0jXZsU7l^4AxW>.sX>E+R}]qUPQ)r;+sK!*aF7Gj(=kRJ^Fx$$eOKuyc8: =,%?t: LY}tR>@:^UhO4.\.˟(Na p\2~ )YcPƕIN=LrQ4f㎅ػx"lipjy$EVh݃= 'Qv(Q SB̂^DWR[\Mĺ _kp 0ket:2UWLW^9Bwx%D1gxJ]a@.y /?WUES,]O=}h);c}VɌ"ଏnm(rY[N 'A Bb~xx`q!,MN\)I9.Ps]BҜx2r:9sW䵂<4,s5uLZFs:x4!]&BLBž륫˞.姓Yhx['n6A~9ip =G逊uN%iU8exXڛiY` 6+a49\ 5̀ԣY eX(!L"L YL:J++pY Əi7NR{cw4݊YK⒨-2KԪU "3oy*'{.^BB?̩mօ(f+gY]f9q|Y0#5шIDU>y ŀOE[t7̵Hy"uq J%]ΔLti+TUuYͼ \4WCY;KӐ>$E(bpc;.P$.C^p^Zȼx<\)ԭ0YX!bK\伐r.FaeQ| r*\N!>>>BB~06uwq?id,5Fs_~gpwn[;3S|S3{ xMb cϛLlvpcU>=NXʀ&\`Vt52r]5;O^ Ex?Y{ ރ\MW&= :|-:m-;@bUX9wj93'-Ec*-rsF L{\!LTE||Z r!L[OW+.hʖSiWnݷ+6MZivM w5km#ljvBa3 7 rhrzǝ'Q^+ɸsÓ-ZWcGEH: .0)w. )z~˗G_cR!'ko!̱ZK2*r\K Q,4 QzViO+6PSD2e7"G"v.HZW'`~w5]?m@cE=0TWPzB 6jZN5)C.?VjkN:G,=H?U9UjrgTMe%SKHuƖpCr祥r\ :@G1WI7 ~}p˱ P'hg;I"if5Jl bjZS{za p4eOq?#/t=0-o 2n=a4@'\fIx *5fk"^ai3=*U xuQ|䢊6 ep]lRu%jWO}Pʑtѿ(vZb &BM7"2G^"Pۛ[;`&e -W_uy=7Ge ¿#}3r<ҫM}+0Lt}zWktoono~HQFYjZx{ϭa<=Ԗ3`Y>4GjwOvymwd(S@#S vEn?bI3)̔v?P*DvR-zkceRbgXxu>G_Tnl2֩3]LhR^\d)\V>FNIUk<#u.(\7N1۔3>< SsD9|4!V# e)(R!6UUvZѓS‹XHɞ&6QiKqT 2 @q*_i"ʴԠku@z? ԼPeӊB0&K V֓ŏ~qiƝ|wu-U4ݍը  ,{C&,o[ȝV㎗;QOhlKK9<~=x[:Xf֋ /m,U1|;u~pX{i;$4E E QY9Ei;^%4-GE9/VmC͢h:&HN+2Brߛjģ+2d{ֳBP2qd`su[V3wl:|lFϏ3C"9 G0//FEXb64DG9ǦV"rE)Zxa 50<*[< vVeCI/$8' L;bvŔ?<(?YŠQ Ndi4ʊ<3ooY>@>G1sVt!_=(L: YEr7'7 k7z..WG+πG rD#f"Ek35[|gp"fv h{ F*ȧ[÷g[ SAZ˸tRgasޔ#3 TcS!1-kzX!7. z}PrK ݋>0yII?e^4@""vkêeEVy_?j |N!3F~?`}%Nko7yF!>>'rEjj: X@vح'3E[\!@?NCߒt3/7^Idނ?7m=}zeG@P>Vl%o =,AK'܂zF~|laq$ѱ2lw݃=4FnMh2;ki WK!2/bLYi< ^Cx x0g>Kx}3>| zcSajr,2Uǐ+Q~,vxvInd&רּțbSUBa|UP{pPG(2$j>8j?rl&gxi~++ ڒMp}uKbU4R5_(pNfk@x|A 5]?pCh5-î^-Rָ7 T FM@M v? L׏:5Z-Ll'H5n)i #{j.є`܂2@TKq0I ?y}df1FJPf.TK+]T200Ƭ'H͖o1 G7D+iD@BQc!@PxƊ2d!Z% :l5`\:#J{HY&%!9֠/b8X]D2@- Y`M9[a[3'LR/R.y!(S L6X*e*4Z sQM]Dty\?J gDtar8'M}Zل$'1κW>05c1% 5'oM*̞9[ _Vr5^3k\4N|qytoM#MZNz LQu}Ս]Ex6α²# g:ĀB)l(Ϭ{VZʁ F RN`?e4oOQ^9z)hmݰ6j#p(jMh(q]MB#F-Id4h:kQB BI9qұ= $hG|?_ͫl'AVsq7vI`?HLH:-&kAGc3T_}8ͯ[hNC ? Wū02ՒcߛS,N+Kowi *}4oL')UXHbM/G>EyŐ bCd*VP? j(48IN< _u%Pf3| ƶxxH[]Y)b׳7 53_|1Hz! 8:!^gF`n@p z 8PSy<Ͼه*S6[Ɂ|D(Ke KVCo!"c^KW'fY:r#&eHiEvt0Y?|&J^?[O{ƃ>>O' wyq{]_?t7[͍4W1f4?[_i xD8Dׁuf?Ƿ䳟aO9־y^7 mw뽮!VYt5(̳'d^ 9n SkF1䣁5:'v 8sMбN8FC۔16YcZϵ[<:&N>;6,qu:r,87POAR(=0n<m+> g98e!.{a ?@ 1q6%p?8A|Fu Zaim^ٜ8IL 0L=\ {gRR/0^af!ο0Bz@رBL8ކKa;4<v߰"A6q*>gHg]&Sdm}5ѥJžT6_eWU`ꕠfbMw m!琠A-W H-)}q>5rsR=zj|<Ɉ{52zz)7 ~;Ơm 2p|ছ4/v_t|+5?94IޤF1YfF?7 o]3fnܴծ9m2,tKs|E=^S @$LY?T17@';DN;}fl`#ynVX G&8&P{0H"RTyDY,,3A^ ^SP1h5n(o,(v!)`»/I4ȅxZ~[Hm4XToGUVYRILћ&K(EI *`lZ(y9 k2nȶ>NQirmk3-yYMg^tK6kS#Sd,Baj0x:!ʼ0u,7Ry%y7F3vY4{̚ )k`9asq*RƇ.ݰR\*d 2-|Zm3QH  ]Q;ʞC.ʇ6.?̒5\/ˆ#ꬍSI}cO* 3>,}LMji2Ȟ3骎s7P1n7`&VE oNSpÏg+R4ԔkV\<3(Aϐ!z}D=$ƨЙ'5V\#B껌z~#ꓻer lq ( M=[afͧIBuPϲ1\RPHNw`uŞ+߮\f)=eշyBd`xivϰ kzT͝OgqŖwLW_BsQpf0Uhw\@=S Lb _0nx=4'YZf՝b] {9EP[F+dGg,ھw&/yr1 Ej%$G,AY{thP°m&̂M. J]y%UJ{0d*T 9,m=DC)/@RaK gl IH DS֗IxE - M*A|?'I{ZX!^ahF:B\{(w?hB P²84PezU_ZUI$_"_Fly/,͇R B5D}$ -L8u9#\=J)A'7 ZjĶ/ZaۮRe_ Q{_Kk fv8#֙ge%B%d\'*E|BVx3*8\`j(yG>#&b*.]T7G+`C@YL5{bQa˰3,,rKy#6O۔F1 mHټz L4Βm3 "Iёo,iESRB,&`>%J3U}lT )b c BJ+P DoѻA@ ~Sn72~As^fNzx +rF01xsT9O[J(Phg a}8z1߽i'We,W23c3y])d;Yv#)$Fպhdfx!vQ_R 1OVM n.U+u&ip]^4M+3M>dJ+cQh0uy+2eg'5ip# Lj {5ι3̂%#VL/Dt:euvALyW?Z??*c(B{.z {lF j]i`cje3n;hq !u㨭GC=}lԭSb߰h9,rh@!VuFf BJ%Cv IͅSx/Cc, ~릏azⷁ BBJKP}W^e L0r+1{~$A-p`L !s.k>hD̖!` W~fz,0$T 9VbZn*'Îƪ]d3LO".M@uq;tBx#F"؀wr009_DGE6>"'v@2*am\0tK!qչh3|SD7(;1OKCaD5!tHk܊swj&Lú%J$> }HWBNaHET"giq%ɊBZsT B8P&,ZI^'h-sVgm/t 8cNl JMI,t~2 ]4eJhW/VRҩ։ZFsc):,îq$ &MuѦ7-1shOɔ>[9mv;WvsVF|Q/ >.zƪzQRmZ$LcJ RcAS+<̾q}8ڬre,IlбR1uH'"ReDC"u:qd 1kÜ[>eۧ\y@*6Zh%T'0 , uPְSxS$U:9"UeS)D;] WCHm|H bo[W'G(Y~O6p\(s^tǪ yVjU-ɲA;V{eU+yVb.+FȒIc+c.19NOv JõJ.%ڌ=a ]&ҠKz#/?Ga瓞[{A ^tޕQ*w޷Vb8y;_ p5qZQq(J"7ΩHcH&[7p YxkY1f8 jhfvC &.-(JF1:;Vp:HH% 4Ek6#ƛ?'߯[Ӵ ۞9_kwO02۹B8n<`Ì"+KO:oݗo,O6Zy')P,M0݆14W]l×t\;QDL0uHEX6WVΔvʂޭʘ~D6%;Ui?YomֳM(sZ`8P;Fؾlx"Wk &¬t22j^(u/z'aȼyi]TK|?e"<]ĊbU5zQA Ҥa'r+n"6!!%Q_!8įFnG? ][҅#Y1t8{\@V3t&F fiRL] 0݉:ʊB1 (Ede g*? ^>O$~:pKS =ʬf"V/Z BA~$xY udeB]*X&~"e>QBZ$' P7tF %!!)3>:C ^[*~ 'ߎ,#qv=;O7ۻ {qiu︗'m?}~u~* D?NƽQ}7Re _"T]1PfSm!3'VVpr re}\D8\Z#Gbc-s=kdH(oF[^xnMzY|] $CCB!v8C?a1Q:A+y[58XjhyzW<(kQ˫hXUUaF$yD4F _Tk5pMgt|(y"Bh>Qr[x)W0j hj{Q/NܧBH' ?a7t֓#GBg@ӗli(ט_=:볠=+2PfT! M= d+a(4 ֶHaxe25ʧ1pW_ޝy"K ,0PtHtf< (~2=NWˆM&tKCG^ 4V^| ҄i[BK  霙YY.8 `c~FSXd;B5*9<>60S0(S U(WpS8uH"ja?TeTYq3 p8YIjDz)0: G!pHSe"F'F'TQNcsY%[T˱O(r01lV*5!Kުd?GEd6v+Okjh>5x)|վiW -pu&8TjK8iyZ(0K1P%]XrEfhE{Z\++TAok OIIVZkoҩ[Wzxxh^#HHу)QIq0)RoxԚ&Qd.]QdfzUSvAΗxV(3*Kj\jl$r8œ}A,9Nz>}~|E@a%ͼ SYQP]+vAQib<=8œC^& h,/UdmacidJ\2m/5)ot##@7P P h0e DXdyjjh H>$ xWp- >v+AFC] R@otxXXs#GG#rV]UjJNڡj2J3kuEmƸlӷg4b&EB6=Vk2Rpg!L'O%_:>ͭf{7,\!mL}~6JfD05rv[G2HUOW6~%B~Fsb8ף6b K8an)G+eOp+XK+NSV S[ |F|,j'E+m5HQF6J9_\9mڈWHD7`q0S)1 dqDB8+Jӭs8d(@p+RD&:M 4'3j^[Ws45BɎb Aܢ*˅ɤX1jtE*+Rx\1 @I+7ᐿo~,+[ Us0"2X1B^_ U?&6 m)Im0 m_͚ jJ.\:]1#P:0ˈHG*rC1q#D^?(A8!6n++67v')^SdITXf% 1 S{{KfgSe<8c0M#z`q mh?AN#LUn1+àM^(p;8ò$JVbX`V6V9὿G$ɵ?0atRjdJo݅4ǯ]J3'Zqa3UXYD]n:ك7^ ㍆ gtLmiJ$$]]Rgʊu*jsf ڏH֭"-)\ vŊZSxE/P`b !]I-qBkHRք8>=W$~lv3V5VGϤ؄ӌYRB˚0Id$- S *:$2Cܥ_[eSȪr\u)4d0_2uz]^l%tVe-76-O0]Kg^m%:eėUqī.mRHx$PS-kNN)%iXf^hA)ě/*XT8<_!7C KF  aH?ZOvv -˿Z_|:G5O2pIni* cč: oum?ī'0,)LMI0D'#^dC %Aċnٿx:s5PkHȦhOQ1#Û4Wuc;z :]waXuMmy㧝Ã+het=gޛwG/÷'ouۃӽW7g?Akón/~@ol#z~9<s8>7~'{7uY:<=xf{ߡ ?uSSݛ3ڛ. ]:A3 KCXSnonN;8o_@c1=v| +usz^ߝ$rtm8W$ЃSXhpnpTHAt<m`X67NBj$1Wn><{ (7'ÿyYq߬(TrK s{\xW 6/4D).9ΫCF~_a3i| x x|%?y?W}+W_5' {_G1(^JQ(BՔe@5:ƵaaTC%ګn]ci%VG:+Tj{߇W߻w9įE}_ruN_hxQV׾oa80o7iE#`!Fw5p2KHWse}85ڟF4sښ 9XqЯ@no u +o_W?6y5Z[~ƭ

VXؿH}>#E/NBb)&D~Dn^fnZ8ۣRBYЏ2.-_NVu3CK޹n3ߨNsK6Y~"AǩM(M(Z?W+/U!Z1Ө -*ѥ\ w56fDGx]~ˏ\9@h82^@_1;̈́Z %K{{vytذT[Vzٌn[猪iNxj\vzX(V,77;۟dUb韏e6?Z^ &}pO~Y/[;[Oǧd2)`y?aPe^%dkaSQt;Opdf\ ,pۭ^>%TX,[߽|J_ m ^D;o< YG˧d<}|J/ǂPLt?;[;[!^>7 J@@@UhC>76m=y2~| G ꫕W0&f^{%KWӗ Fr!Լ֊})WA n_+"U.WoB38H>U?WY絛VV VZk^лڻPo`׏J5 /L曕 {?QpAw,FWJyeiVҿO+*Oj sj+{YV.•ZWWE H[8V}INo-#nyV} ?F)j -&+ \/my]o>x5;J~o8vּ_=~(|}/Ļ+zނ~D6͐VqL+_*[퍬՟QpÕhk߲% p}yկa5P~7~j*]Ei3~>m{OACSS566&c>٠ڴP&oo73 ՜g8^| Zv?$^f?9yuMv#w6y_/r[^ka.p.D"CJi  삹r dJ`fyƂm9wsbZ/[k5(a{ MOKGd3a\㷇G{?=d]iŀ 0*(H]0 Q߱ X0V"A*_4W$TèǕ g+^Q0px>|$;{;/=ApxgƿLhcSdYy$U!^ѐ΍wXDG4vp v(PK \tiNzYPyW: !BN1Q`qD|Hĩθέq_apQEa[W`-!TU祢|^ǿW% 1ҭYAuA{bay;ޠ÷Js'Ɏ\yTGiUF SS(XZ]c[7RHNE@yDP #Dp@&r܏l.*ddԝ@?"T-e=pᩰHjݠ#$S.SxB^TSU"Y9Qj 6/Zwi`mۛrl#,q -(]+#+˶6e\L4]0SFeD4J7,(G_u=yOpډ=T+h]6@ŗJ0 @G8rQwQif&|7D%eX({v%g0 3KڀU_][5' d|AJzɸw<\d7'H{>L9bo<=|WO;8?g|RQ)!#H(}ܾfZ0HN+*&=506A˜!=[yt: >,VaCYqak0G# <6 GxOx<˯,i3P9M׾ iik0!l{W!^dz{.\&M4U)jm~Lb74B#)ؑVazU ,9ȥp9):\{t{VPExM}+t_ }],A+(tp{[hdtQFh+U3\+d##h]1ҽBTJVӗ5oo=}&]Am# {WX Z& n"tw+ K `_G6~Пt7{4C \5KBBw)x-#f%Û ఊM(ao5TQLX_3b߅yܢxn6䙜,l I6(A-i4)\v.-%llq RB,HHT/b&w1 !F 0MG4@RK]Y`!+:z~1MI6e:|@{wZ!eRY+@`.41Ûު2!Fꖠc񮂏^chf'!DRQDB P.\l$6OVT?@Ъͮ<6z>|yGA=.T>tE{mG4!Yڤ?A#?s e%U #7qIYl[2"Y-?VnКT4Ƚ ~H?(vd0}9J} o˙r ywvIFo4D.QN\(SX;L z:w7j:,80f0 W$IUy4Di^C[{|]QT -ʥ̰ jdb\KB+ X,>1D1q6WuIumcnvp8*!MD+ Y}tHx *=!gaq]}y΃zš=;[qɢ{b2?ѥ{ B#=pXа&He@&Mgyg1,[mifo5mb^ o Yoy$藀ge%!LהLT3U ltg )wJ"1#eܣB(<@H MPr]ͿPbE(~ߏ=E@}2yLنq/xc\6.1l%jCޞ1ŲqԼʖUE$3aD6 r%W'> >zׇx[`XV@Ȟb$uGTa'5Hd g .J3 nMz(W?9`x'M _CD6-.e] )$!HňRsq`lzÕqq$~-'Lܪ'%oҕP'`.Aʈ:4`=̾Ȁ.L3:dJ,I. Z-m?ȎhS"^4^֯<=) cjl?B{ךk%njmJRb\"4JvXЯI{ N 9 ApyYjkR g  +/Ժ^iPs՘KCt_w_nj XV ޽D7oC.A#Qp!^F_e$G_daP !(]pU{צj]((06Fwy {AQa|ILaTN\}r2<{4xqFe#֙uy[|{'HV< ˨ 5 ziG?JO=]M>nr6%n(Vo(R*!\A ~6}woL2Cڪ~j%݉.RQVO_m5ef, r%8-7řNEu`"ܺ>thhb;DCVҫVX*|l!4VeYbcPYg"A@x*0Fdya[T2FtwN_`Pw5=v>Kxg'1<º`TLimChCk' cH*ng6c US@qQy eyXj "R 0 SI7#kACۇ)tdas0_sۻf:.^{pQ`Rr2dF%Qǎ(&َm47ВDQMUG_˃㓳o^r ~=2T=Gae:ZӜ-h76luKỈD;QX1+hn?0PfI2i R;N+Z(mJ\McO?qA`^ 9cR;0=A8ڝf`0FյgT, mDv9sn"9>Pa߯\op(< ohͯgJW;|TMOϩʂ;jޣW{ߟt_q ǵbE$ Zѯ1mߢ.jaB3c AL[eY^07Y{U8ֵfr]Ȍ-jtu߆Ab1"X51!32֕I,;e(TscܟũIS_ F &iRI V T">谿?;=8@Ctv~SXF;l=u| ]`0qqM5d%Dxp(IU',pěUnUN#cT]&k"R-k?`bE!LW =,EFal\kJE89NT`TuN݀U6үa)GX4l[`2 ;*JM x/RVvj`xXȜ'>C1%KJH$u4Yf2iABZFIz ǖ ՊWqYVIM^f0Z۫֕LE$3GSR-+Fj"!V 1ړG^n- ftRDn|(1{i%N hz?2a;]MC/6gբq2{QabEDhXrcE@㒖<:/cmLS}|yd:rۊ'j6[TAr@ZS+zԡTe(5V,/̙ˁ "?;~? _8Ca5<\6AoqZ"nnwmw͝ݖ ,xn]7S(Nl9L+۹1H Ћ_ϭ* :ө9"GYQ78mpMA-~d[9~x y6̘Fi䄣#i/eI#(-nE-2rDTo2~jM9"Ff QT@:m$73-fnۂ֑=g41sLw& F:k^L͕l80X`j+ %x2FX㡘2ö(tۻynsk_1!lX@+\'C0Ě)Gd%A|| Y]]`'|-,ԓ+}M.G'ܵ 4bK>;;L pcQwãVtW] v;N ώXYɫi { Ԝ{.3W;>}0|C{ճy q3Ef~;Lx]_YN VB ׿!?N8 >ELM;АP3& e \1Ʃ@V{o8>ܧ;~s|=L$2)Ibk?Z+kNKG/PV듛ح"yO-iU:o+YW{̙klia}ZKcP*أz ;CGg;b5u?AxL@}p(<.4}|rztV=^ 3ǺT5'33l;3eHk4Ĩfjt7N-H%<<:;d&"$~ y@[+4`Q5ԷoOe)Muf j,4ۡf!(U3?:8>oOޝPP>L]Fs|(Ht PɯC lq] ݟu=9 .^~ffK?M,Y|$hҟu{oOfk*hL 7ۈ(zSdz(,wDc{4nf?ïP0ɂ8dbX4 8qR1i,4v.EjpH9牟]FҬ4fxmKpzL6o _!Mg|}B`nLW0ERwC*MmN״)Ƙn+Ih7 w#H?7 l6 oB@7dN~kN:c ńؐd;Fw\+N_Ǜ&3x~$x嫤%H)S6Z~Mcѿ" ϒʮH(HyTe3ؗ!k#]Qu55?1G_͘"R|A@i7yW+Dx(4Rh9%XJ" ]P"7Iwj=PCl/0~ 0pMQoYLṼc]Hw /x^<сo6߸BsM'[.GzgdŬ#ǨE60HsMubPʢhR4b)`zw1@[-韆|N6!|w4<ifw>zht b>s*`y |+2Y|Xʤjy6Br,_lnںB0Mj ABhuslLz镛Ȣ!P'DP}_ rx]F[~9n׿; | A.Фs4Vz}8ѺoHuȿ[1wq=z:y{Ͽ޿(JATf^E$Im5GO,Ft"tfB&Qi43,ɀs/z|ם&v* y;jLQq `oRdGE!1)'s<.C!( H+C(d7>eg!G%7PvBHm);xMmwZ؇jy\CbʖDG},u]LbWgy[Pê +y@q&/D!%I\oܻA*rsv1vdB_/f1hG6uHq-Ѫ_g^KNI#GhI+ȡkScE`u`YLЂ1+^ tZ-QorQ)TOQ5E@T&Fn˕r55yPnװhB@].WhfrTn+UK+@@EPjBuwVLI%,8ȃURpe|pNI:`Bk-c(TXx3SNx.ێ8K|Y.:<-B0)h] ` yUF!,hfF_f]"k4f@R"2ī#]b, >`E9EsU$TYna27-eAј)z| e<)iľ\,Cӫמj2`k5S#O.(dQ o%ܬ-llʐjIqՔQ1Q>-:<_#aؿFw|Җ?;C E dA}Š,#,̯FH#y[V'naa'@ѣ5'Ǐw;]f+X <1zx8~͵>f m? ]xw @2;P7]:K:bR>M|H1}DOSHv3(KÔ< *8-%>)'}!VhGEZ{A!O,&|MܐC&KXЍ-^'0лJ2؉[[:?2bWa qv.O^>$V_F / '"u6~ផ 's}K>#MBe%{܃5_5o(n/*rc_b_R욗d#S5ؗ!s0kƞ'җ-o r=I{XwIދ)iy1񞢏!7N ."^ %(GP/"[ kf^4e -#Ԥhg][Vĝ9拿>\|dъe[b98<*R5[㗯N^E%xx,z>Ρ}'?=U@zb@T R]zow60L6P4 rݱ_"擽xk9Dl#;1!@v ֠-DAcى;!M@+X/~ mqJٳ+1^ dK(ڞM BUB$r~e'q[8݄BmT[r8/[ ԣxj@cP{g yN5K ~[8|u^18BN^POG]DBt$,*T^@'!Q⛃x/]A(>I9!>fd`IғmE(d1EC` W6iu+'(|qqMAcŝeDT;tzo6<@'k,`P7aP;¡#*nT"56>V*UW*6eQ*OR[u -y^sڅk|&_}\u">6 8 ,h iib$%J4*I^0?G:u4I:Ik| S*NwJfd2P $K a1o1T@*WFޠ"cSQ&GPW p7cb>Ӿ{̅:1ݥ!JY*>Wݠ:s 5Mt 3AbD~zE.0Y!DŽYI&Zi]19Gyw̨Jr}1Wrȸ3ud,蔪W8 p7xWq+ȵj" Ihm>2\Bޠ:')rD'~O0HȌH(bFgfRAi.qzrKlS6['# tKPٮ,(Ŭ1^Kaw ){BfV -μpΗUtĕ?^ S]w U4O .ݙtDUNk4iIw&#δ*- bL:9M84 +VgP41X"9Kxþ.%0Q< y52")?`,_4P5rNY=t¤e)VT &w%oSxA!2"s-:C2g.E=;U#SI+lq|JeGH6t*?{rGn]mNi~&a==NjNR|xY݊X|dK$3m}eW(:BNX(&;f'V Me8Y=R! :Wɀ~NfUn $ߣHЫxjz4iCѤ D{nwޟǚ\R'zJkSn#0OAΏ7ݤ(zhgb7<钮:GehD|n7 "ǩ-e 'ThrSO/߳o c>3-WZhfl,f'hlJOg+,ѝښVS:jn+عҵFPڶdaK(-s^ 6ڌ!foFTSJ@U,GFB3+ j9*9&Nx;G#DdSX+ª?ֻ~緓| 4uo(O~ hqo*zK0.Ȍ 8Ĭ۟NcYA+λݼw]yw{Ҋ}kOtu;U7N<"OfX8d'}De8Y\'P˅<h?ǂ\'Ƹ. U-ا N\:=I3h?&hL%-j/׶m3 Nd{oo?gȣJyk H]8ԭT PZxGyTb%??QӉmyѶ!AO-쳈@d[k XQD.;e$>C:U%A dK ͣ*}xuرNtK9!n9^fZmKe o#bQtl%*5WP"a |lYynn?55u+5uTzٚfvE:\߅03UU Fv[ V! ڡQA“b4[yum-fR_@]9 !w3H#sDMGwtn:w|<俆5='SOvE(W9hIjFZيR .F9FT?hdRo^ 9iGF"tMKGQ>%{oF4şBq&>130dC Bi1n!ߺtu9v'VK%$J:`lv72>Uhx(ބB!͊/Q @kMlod xZq?@,vf4?P 9{Te9&ǐ5|vKJǩ4\ MJ 'ZqŐ mݏwu.Xf 1(Li*D11˟흒qG"HrFU% 7)dX )_OaQt\1c4>-:Da`\v8cYq@0N"2ѓ 7"WKB |D^VcL_-5KeOa&[A>dXp([ PPHPF3poR_a( t?Ijk'G&ɶ Uޞ򱠉p*?4iJ0dIq2Iy,}O>C2hXD$ J}m9̱M ,\ q&o{#dFQHs/8\Z5>(!sF PRiӠIk,HCaFZ/~_{R+m.Cf#cQYe:bt2qq&m;@z1~8>zMXOvB30& NQԣy[0*bmɁ8<-1d)hphJ)7>Fb5l͓i6K+$b^7zqghWKWm3;h}qyӑbFZRL(l}l霌*,P7EFKw!X꽙1>{=[R-d3t{s_\2Ċ)LDS߷ h"L% l2'ck+xbzv*_]z{NPb5 PrEy̺JL!q 8^T/kډǰOP'Z?2AlBQ?obqfk,9`l,Νx4OA~ R@杖xl͓i+K,sY\b*K_{y=/;3F8 s<(5nȞI>zmRU2RhD&{s_'8/d%v8 WNRAfIo-xs9WҜAϩA+A1 >p)Bބ.؁h:Std:$ҽv*2{s_Len͓~T]w$K$Nq?;Q#ɩ0 O$2ghC\TK.X}qm<N?hFJ6nG"2["/]&{s_}4O~ L_m)фdBug# h|s_DwMQ^-f:`NhڲS &96ds)Ќt;&5-zo~MC8f)#L>' E2BDr@u_ghO\DQxp7,֏*J2ٌ'|s셎MAs MLHUr8<[&НLOI&f4{s_gy?3ӿGXJw*#-,U̖x_$8}4OAe✵I?/K)(%[}eZ 铋dNʞ5gäD5{^ 61S1? N+6"&eȜ̊lɄ*H(df G71\JFЗxl͓i;hkl=M/v; JVMcjWk(BFdkACu˺ΡqУ_6W08BG2g@f;y]y}ogk LHaXl8!'9n JzhNI[;)<KZ1C>dcə։lnּ)V8 ;KVme$xKD%gTx3Ld FDo՝hs7sH|U7:h:XXTUՑ(dV"w7hw1Ǹ%/k016Zͣ G pIVr iG$2&>,!)n0 ȈV*Rn쉡(ds£9$lUҎa:C6D]lE\IDǛ>|z[OXN =:_']b\pm1e4N#9bȗlFc<ݾ[Fo/Xx4>9GP@=U'# JvcOn \t[ի69ú^bk= M"S7*. \#Z?MOSvEr]ƆNcסxH=[%Ɠ;# E[Ro8b7ÃHCk}ݠÒVk1`sĸыkj.۱_>q/ދ~Z~\ F߀0aZV܀R[ZUj? !lB#60=[ z-{3rlc A6CđiYO Ӎ\0/AQ\crmGBf!B%ҊЩ>kr wРYI Q姲s'HTfPVFs#d4l#o[76}q̗mm7X)IcA_ah%VzfʃۘJXU\}n[jLMnnB>'Km/l⇯/sL&ݐQg{M8cid5@L MzA v~.S ƯD"tʡ 96NI)nGp@_`xYrw@Ftv ,̋~Gc:qNL5b^` xl㬂LÙ1|l8(reR(aIu*|V]9EN!t"0| CY=qxљȳTV9঵ xF..Q[aOQrA_[& DGI^lko*H> th<,|hSFfs`}owJkİ L:Qdz<ܒOZE[Rxab,ڤLi|tD 6 c-޽1m dmbMwZgˠ:2qēiCIϑn?EH7}y2A%9%zRXaiW,7߮@igø]c;aa/:$fh*q/8i""3|*+<ϪD4Ew7{w>GBma[un 1e uCz?p ,ZRjovqAe(ћ4%Zn]c&mrFm=o`:vԌ]#: $ˠS#h%fED(t4>v0PKm{##v'1 -uY_ ؚt,S,+­}5::\:ۇ~H'*AYhs~]-IS _ L1lZKwvJ!^in6?҅yL7պWyBE@P$줚W&:k/~;rZ-Bn$Hfc%QFfRN MRiYD%~n.`85Q]ۥ]J$yJD_3͈A;>I lNV$~jFk>/~~iլFv0(tF) f2%㗝Hw9}~W.]\J*}vSm̐fɘrh1LJc.fs~x ZFыiO)EoVşZ c/zfZ٣;t*oq"q.M_)|ד*PC'#xakDJ,_Jpyb`K|o4cܫpHњ"¼KATЂ%Si~ϽZrsjl9y֢7e\UUyLH5u& Do 2nx2o2ofɑcHN/1XaOi8/, YyK| &m #\$4RfM7 JOh`0hax$Nn_[ O}i>^fO1c/a֣EgUS"c}ee_j?Cb,bE,oYH!^Ob$ɗ0[^j KXQiev S̑p2DZ s#[x!:y( Q;"xL"-؇(:EcQ$v$.y8 *&T#{J,:aK12_gÞ'鯤/GXZKdUpJ7橾1)') <9DNYQ`ZQ:"E4q£* {<#z6B6Fl9vE{P,wCrNkQG|.p2xuSKcDF8`C:+9 z=Y9X#A"\s 9&N7j) <(Gh df=r]kOHJ.!}K18PV/ƘԃnC$!SC6 CQ:3)fdрEa9W达*\-q&B;b\"[z)-.63Z$ Y]VQ>2i&!+*n9v#M1m`Y9F MJ]GMΜm{JwZl_B@ J;}-)Kti|TJXë"V)*kTLCeHfjȹ Âpʖ mVii0ICT;D%гG# Pw4+I# g4&C= ɁX1`ka̧qηnbX ڒN瓰m6cm=#O2x^nΪRt^;fbɄR:;ԗTآngp`wd$ޗ!NHg]6Ղ\A ZghոdedY+~M4#*8`.r MjwߗG!P/"0*)-o!5NA 0Tl`k@RNx&UnD\O5oEAÑ(I$hׁ&):8`(8whboMn%{ |̀F@I,BITtQ4ȿG2m.j>G t򭃦c| m@Z\eVy-/ڞRRZА_ș D/>,!! N$染X^R@2 _koq{탪-ªT5%G>{hCE#'ׯd0uħlqt{.̼H:FA0 QmK:%=| 3ݼHSМY 't@k5pd.! 5$a鹹T: NI@jVO3Xy?$;3@tZG)Kn@s;XQ ѩ@X bz10 MOpyeDf$Ym[nny6GwLgIQlF 'Ӎ=$U^#a{ e%41+\Zc'g soBtOmbJQCօ{~pq^sB Ll!^xznŬ3*kC ."3+*V#w/QJY\nygE.sV5Oj*M|ck4̻ʸ;2yj *"BzІ U9_6EiDW-13V}Y!y/YWLDI)sDhLij+,Kmet.}HlLAP J?Pʩ^&vFhf |'OmmCUm#L.s .2<,E )\)|iP`$s:4dn:ׄ+Ss:@$8'@uR @t?IuėZ;,&h4'%/18|2#1d,)q+vhjRl:PمʂkZ[\MźA$N1TܓRFPUB*eD>PT 4<~ll sqKOZ5Q3xk^rr@7nT6i\ܥk0sFw:ՓlP׻5 Y,z͆~(rx'HlCd&)B'6n^wW'yGspG,ByMi;dʈ5tt4u>n//T, 2ސ2F1/VTssNEKXW"Zm*+Xh,:^hf#mx,RK#u<*/CVi -uM tO4Hm8O:&6vQ,X 0꫹a,lb"L^2"% P -(b&'q-_Cn z|%`hnp%O'}^%b52=%7(}@07Jm3Fs:6-\jLnk%=/^^.jW[lm^`Lo7Pjx!Ogzz'pgȁP@h̊)2*Dӆ1vTJyՁz[,AȎvPI[!hs̬N KWT `~QGubbv;:fДfgHP_tmzlI%NcN@3t/ȩIGZ)^t3ْ@|o1=:1vA爿~ςC{_U2JH槼F1VI}ƝMka } ,Ww` ~l~Տ /R]z R XU} 0(olr텼;G`R \-FG lS)z%Ib(^ckhzbū".gRhTslb:j-z$IubH#.!B *r,Hjn+Ҩ-[B:GUkp2GjeUqMZ‹߫/U['wY{2s"hX"`hfZtGK!88&V7xlHyБ0z?^1zU 3FmyLECtI " gTwB&BCRg ~4]rf7>]׈AMa8g:9n8-l%cC#P| [+HR®0;_eg{4 M $bgq`gH&+XXR'gJ%DoHo@ۨyCK8 w,UŽ@ya63]FsX]aspሣ#z| f7գ_6WC;#ٮݩs7!hOY,Dvc='dD6]b*pj2[#qr/a$^C$P:Hh{ אǧI8Zˆ7dE:tMg8f!X( ϟҖYSĂY ?sgtZrp ՞ԗ[$$;sZBsQY4sZNY\@F&.’F|%Ԅu0 1δmMR+q [P+cprv0j'y:.,WXPGnW:pn5Vԃ^*s:d{w@^ s'A2#+7ҮE>%,'Ha qcԘBTߺW}ٺqfFsS$]7 XX88'~Y,!D-6e 7Ij<7ci7tK^6ؼ,_z$1 #aTF*MD $RUyݠ`^q: L"llKgqc4+̡d6 ߗ?~=gj6Z-ơCHxMé̆bYa# j~WKb['pP|Ҙ߲HxrGhY d3GsCfFމPuB~Qac3iB5.AOj:'k雛-(L)WzVjm=?"ߨݬ?Xnd*"kۭϥL_K$zDThK/_a!6ս귅\Sj,Gq{Ƹ[mm7Ւ*. q4%Utr.aJVsmZ UqD%Ӗk}yfƱ*䤤_ZV0KbMR ߔ%La"Pz/$q,oJc(F2D[J˕-5gT!=YDF|uzрG1kA(pɓ: *j(́rxhXѼs4Y2*tXh !lKzT:.Hs]`8 .BTPF;aFcb,vAե-4*hLRԈrZxH_geE`j #K5Ԋ4`,zTme !sy0h+4Ƴ=ZrM <iY{[|[A vyJiaѬ-a^ ?K-(~Rs` ,fӕRi695e Oګ9/oV,S 00CYK//{z3"fAA^9< '75`'rG^:*끪l<{KkF31堹[fH_ܢāLA|4ĥjMXxl-;*oäML<$# Зj`m J%O+ӹdӭO[ZiwY[;z8yMxqخ`w0>U_`xݝfW[@M$$/TɒV2g{8#Omݵì YY$=i)C I]]kg~ZyE^SY-V1Qa‡LWXKKK@/A h[^z~e@ttj #"{zzT=ź:ڂql@u;B ?͞W>0 ^儖hmb*е9"i'VlD*qJ43vʿWyXo,;q?,vqX.5M\tdCgܹOsd: ES% Lwj82Lxx'\9K(^$?{Xgkin z=\fnMNHLmqO=fY d貟TU;? y*0#K=#ފ^tdGC/33P]P؟ǃvI^ch JS04l^;B3be8z| ie/9`̯ 맪PPkO<=q.`sա0VMe#zlMZI] lD[ȔZ=5y;wJ#R Jm!eJ9Fgr-vF*Y L9J$dڌ )}@9xRP?@c J U P$_͠En{#bN,\'oOss~|EwRm IDv%5Q3O&D򼺭vOlu3[& ܜYȬ rU5Д;#6abTHҧ`D#(|^1i ך [x^J@[ Q38tVMϔy1kLny)vA>N.֜epſ3o:YJg-Y,Ġ5}3Evk-GcL2Lx"?Y3[C l*ѸPUCv)UsG^OA"D=c/rPS~#qzKBY.354`꜎e:_WȠC_iȪ3Vw|29"dYT(@fK#}ƘLȞšddM8]Cv67]=+ۂ .ޒkլv;6vwZOw7j0 Q{b쐗uN+ì}LE^bPTo0fA`i#sEtD]Ff 0?#GTQ}GdҠyt Kmq֯=e7z R55 uN9`9 Yq>q㖝;ۻ/1Zṫ 2 3crΏS ȤdISW~i?Xpd ͇$X؛ 5?r(A M@ }B<2?5 a$FVz^詨Ή#/- 9~FvkkcW oZFMóhcŐN~@%iբɢ:, t:T-LK%ayG[u+ Ή|h☏2͘c9YW:3 Y2 <`p ڂ.T-@Yxl5p k]LĭhƏWJ`m>uoHԣH-TE=cި'Q۸~8vB*`$HFw a\M} Y?iF DݿC.p#?qxϰX0ɘ|j]Za]vZrm 4LHm.Rb ## :FIr4@!P#dF7F{o9Ʈ%wV=yW+Qa3z[g(9fm&N#v%E:xok ޶pq'ċ 7]SX5ndJhņu>u/+{So2D>u}^Խ{Sjk>uO)>uvCp9rŽ F\FסVCihWKQ8<1LW'[1Mdi5[d dpb(doR^(}_Kt}IɚB3I;e%KR@ˑ!.B:߃M7T%K7 1/[zILCX@a'R #ɪ)Aq&K>84YُhadtڍWC]ZI\0V+hEaR~^ylEb.6 ;hx# x%EH"T'jS0Fx?'c5Udm= Ն lhA^ZtWլlj?>=ð-x6Ql7XHzySUS7obp#iE3%54P@v7"F=ҴEs<Z\ß-X~3.rYd=iŰ:D Df ?c<ەsi5h4wm/O+jKB''YgW ~Rɒz o/-dLTkWzN @ȉujǫ Sk4I0I/Ϡ=hW-vj0< ¦ޖU\D5 ̗rԸe[mFu:[#Iу_DcWU%ekCat<" ]֩iQ {\ "w֐4BE U 7菸QkE-<_3kcHOԿIDzI:_Է_Tf`|^FCEKK%eӥb{'NuIhվoZseůTnit6]H+hZ8rЈkfdQ `$: Qxny4^y|~>Pq//ېgv0 _,5s g7zuFCA!K(LWa 9Lw+ϣ3]Y :% ?:vM?;K\QE_;5ϡMэ,֍Ev}9M7F$E4 R vt[XŠYut֊CZ(2|N nO/GmMR|MBn͔EM$SORqpF2M1%$byɶI|SdkK8sM8Gs蒢@=sR'R-Bw'4ύ_=^e,9b",x }yR[",nq> ֝.}I4|b?s__u2oa;)sn&OLsgm霗 ll77Z?nm~ 3ɧ`k}P*BRd.=[+^U^V|CL!z7yqY!v9ӛ_>n_ݟ5r1'̰̓bs{|>Ͼ 3/.s|R-)%?,q]2?3ƟBʋLڥKk| vi?K_4vipڥKk. ]\4vipڥKkcﯴ|!'3<:F#sL>8ԃP㐼Aba<]FXAAT!&^;B) FbgP'*QF7I8BչlD{LK̜ps(<hkIk|Qi4us..;?O"cdnQQ؋P#hAC ]892nZ47SV-9ZS(12D@pu 3F`iu;?&~`bQw ?$FH@BL8wqZGDHΘˉ[.rk$?/*5'tQXN =h:!CF7@ܛ0Fg^ Xq,%A8UnXơTY~[{T#ǎowOjZ+=j{[;+ @J,{*H{oohN0 `) П`Q'nU0p'Ih;0yCh 8PėF→4%w WM $ʃvg[TЩ=IJlgvN#rZViA9~̻~lߎoPȊ 7b^! NH`"X2zFlw{1dBֿh}ʹN7'A6n8RԷZ \y^d1Db ̋&UtYSw8jYrԲ.iЍ;䇧pqoFgdP%[\sĒ5TKT/Y됰J 9UPߋAOjE(L7plbjʊvxOoR1UQԮ9 osRam~n ]kfN(Kw {Q= Lj SOMOw8#1NUyt=qF%e\bI!N`unݾo1;/>aս1W%9é- 97<0Xs"5MgD0\tjjc}qՎs/˹XL<~ ?[+84QTȇ o`j~02CͲ=[c D< `J}Ro(:,͎foYI?-XB{QcO:BAeuo;{m:&Qj}`ۀ5דbS$"Bq\HYr[Yu߅]b1sRɩ슑Iz$x|ƃm`#P茉9Ϛz42KZji\Ǡ8'rȮ MtF7 &c2RmUgk\hkb^ . +p1_׽\E\Z:1 8[N%oп8wcx΃IUS({jrLf9n*=9GDžh¢TLTWh@UR91s` -kNRNYvT%ntq;iny|p{ o;9bfe5l敝 &9qLzU t)XMS"+Q& XHؙ%~Hmk+k+?9!sNpv~g:Otk&{3lRos{Cw^yqCzj4 HGBs**jiBiI]{Vၟf bl@WxSg߻2^r2' ̗Bt!G3,> +|zXp-sk.Vs xN(N2A+ 0@MQn]c!c9V?sSۄ[ż;ص|Y} kŸAI^<|1P+ gg^t 8&KMfVSogd`E60直3֣ݟ[O_~tB29ƹ2I.D&2I H}/%<|nv'$DRQàjllfKxafk/ɿd/ȿ74//ml ~b)=I%7){+!|Woh=|8a4CE_[ ][ ][ }%jQBU`zb;[O"8 "sS-]s8EM6~ =-t2/f^[z9w З WyfژM3/^,ҩ̓K{gox"|{NmlySņ"pu32W#X qoi:񺰬%ܦP%\;N8ڸ<'ܧܽ؞[4+ފXj{^)6e0wK50h <|FURgE󖕡|W?B_n!8/Rolsg^Y'lIMy {{{{Z2L]:`8C_p$y--G']4N#9It̜:/ ?=ȹ8/vn_rѫomLioOOm>9H(fKj^RR{4AV;urr&_  e~CRq:G!^ xJ1qmx;Y(Bc Z,7cbŒb6+{-K^IvZ,'tpF莿]nSuxL1߭b5qZ.2R|DWaw0b/NUJc B Լ~ð 02.SMV#R 5ѽɝFl.'@qC#ٱE4fo<`0Y&Da UQK pg FpPб*a}LPOhk00?"RM߹W|"cH8 & BxQ]&#Q:MՋFz˂%*  0D}ބByC93Ko`3VS|qg]@- X8sh̴XXS`>,o$~<-ZV҅Bdwg0g[㳗4wi0!kj5\ 3 )HLa rr0ek7ot*Z#YPQML䑃MP^u(2TxrN76a?#޾8r{@54oa9"`7ՆLG1 ;67>LF:bN>me(z #wYH *v Dd-9xi1?$1pfˆ040gNcX{.[.u1Z|XzN.(x 1m>_Xod$u0}8Ya#;7 =c *o<\[!tN-;ЀP zMI`7nXf-008N0f7L4:* FbaznMo>l?`oyӍD o,^}ωt+l a'V{NX9ߍ`^?Anٸy" Q_a<9{ Y0bk=~>?˯uѫdу#Y;ݓ7ܽw@ =\HaI!(F}C=o72@yjG~|^\D*OzvYQYz1V#iվZd<ϕVX-,W s?ہڗ?|rCΧ0O׷W%R<:fk!T&m4Wo9٪WA`ЪJ7-qyPX#X'ݘEHC" R{REØ!ꉨc8R}7ֱj?oZAL(#e{$((3$8G,bߢ$ةrtv]+ 9W~G]@90 lGk-=R{<ԇ| Y~'GxƧ^ @|3 ,AϪ'^1Ê#)}͑P2;0rʽ.Dqjb]g30v8j3'QCU {xf8Flo¸ ;eY=dI+_f.CUopP#μ]4 ^]"tPN1_VupiUD6C7 I #J"_*5P K,krZWQc5w~""AȼPEW@%XOw+>?% ;ϟ66sn>{gB|̴zbo4! J6 GePIR|$p7OXX&;#X'8h!@mEa?guPaZBW~~dw a5c(n1T`gU-v/`fR˻lk|ˁ;lIlAd}ĺH?|-J4%5X^KbA~@ EgX&|Q`bmDb&֡; _!Z{q %|je?lǼyKлYVW׍M2՜l0 X:[q,7̳-Ax$>G' >ʹsN>+"K|tܶ& ]<>89RMr1TvU,4'܃`ފĢr/ `w'J\`7: xoEཔ+9B ;͂.ג s;% a16wba*S QOpO73 }?p GPhwLT-Rjq/oԓ"F?d?=ςqO5/ˢi/u_xy&lu̙> ^';* a vU48"w}_b/g0x Hz V*׳l}@^, ~]Zoz"bpGz$+^IA {cPhTS r؇GKUDkӜGrX>?&"lF@nRz S:xe pt4AՃH{Eie3bz.@D硨_b.ѵUHԳ>Ex6"z;r!qНVU5I; 7F8 _>CK%08*eSO1Ub o8Ln G_W h ?]'J[ tQR0*,AϺFD&6jG6HgŋD,iG.Z s/VOenE:puZX$8bEr*[tj2NKr=&u$G-xBN}WɃWOj0sH%,gt XtfjFzb1Z$9GjU ;b*O]x2TC}4OA~tQYYBe9|&UҠfQkϞ^Nx aeЎFBEWfVn$(~1cvs"РE%>]Ƹ kO=YCKQED U0F4/3/՘M9c}0VͽLt5Uk ͛ uqnެVF_D)]rsruq۫ך%CAur"%hqLojk1,MݸL6KOZF|%݇,˕^f;FB֣VyBM L4D{B2EcPLtQeV#]Ú4pxWK@Qet"hZT5tD2Qi4uGp: {h} IMtt}uڨީjbC;I ovGn@ٙ<)*Y*!R̛ZI}<ʅhyaŗt1 (8A¡q:>(#9dL^&ghCF;I'}@$RzڞӨcFсYG%,7ЬQH`$"Zu9 t2un7RkjnQXD! e Tכὣ9ICߑt4JM`o \de^P wT^c(!QX&UsC ~~-9{sZF#_>knu\H3f6⢮*1ŽݧLl KYMo@Ļ^00Mfvx|$h+&j+؂VdZ xعu炪jOu1uyhocv/^M e'u nnċ~ )A2SELXI-Js6voMR\-`}& b!bsJB:'={g{6I۽͡?KЏq'l!i|Y"X_z#l};Fш28/~կ"&Tyv[ !ޝ6Fm&js*bqxNo"Џ#MG_˰IcOkl"kX8KHN"@ҝ1nP$2gF"/"&_H2g\}y6N7m?M Ngtyߐf݇t[w~i^PCl S7'6TM|/A+E+mď*&b ;qDV3{u-0_o8yfd:=S϶܌wѼA Z6wH5BwzKozmPH`3G\S<~[qTñsdgdz#c:sL?!b5l]A \Iw*-k7GcѸ|x }S;fƍ:؊ͧJ?7R}P#/,'y,}V: <D0SŜan}'əmH~F$ÙP_.:Nj)T%y;?I` Z. k&АKAvKuX3KmCx2<+A)QWb1lζm;pKgAէ*va,8AѠ p0,EAG2+R U5<`"y<<{`i{ky[+^ ڣQe$}RÇÊ<ՇTw{T[zwzkPJ6`o+kA:3y1Q{š>T8qI{c-#W*+vHs}ia&]f,Z L4MtV.aV[2 [D Xl3L1ݴm"yz᣹Ix߰w,.bZY| ?$7m&kTKB[ LΪ^vi4[˿VI\`Oppx2d],z`e[i~e٩wrRUUHɛ)zu*/kV-5& l/(ot9vu_ÎquG+D3vi@F0I]kzQ' Ԫ>jyGВMw c_+Ɠ }a~iլFvȢߋ^@f2%㗝Hw9L:>U}#KKR[dXϼKvINգ_6Wj5qWP0j:)H;p[XzmU%R0d]'G8#1Wܐ6agTsï|˩ۖ Yđj#z:k_G];>M& =1uH UI5,Y8m2OgA n.e689Ơ}͉|`~#:Y}Y?X~cG7reGN>~~sR0+j}3"%EW`AWwm^v/Ruj묩HY+~1 h\yᕤE]ݜ+9@m 8N|:[on0-c1YETL|?w"7}$i&dA) YTξ^rj_*9z@)@űLC&>uޓx\% ^uEp/0uW]y&w`$}}N\6=|4cɛGAb0Uz qo{x< Et3Ewf!i68&%ɪWRZ8 `G')^(ՉUsz]6Ŷ:e,>=P&]ǜ@@$ rCgeġݾacQY<#s7| &wث&~OIQ+Bz\ NfF(' 7rpm)CY>P)&-CsR ͇pʎ9cYEux#gFAsUYWQ6x(u&q[tl>:Ƅu!/!ᚉ Nk_&&0fcVUsvP>|$Iǟ VuE*T{6Oϛj3_f?4`.Ϲ`a2A))%Ȗz$#z= G^-q4+@n6=IwT_Ē.f̢H&x;R˥z/JP|Y]*67o`zڄr!WǞ Y #5D' +>qw Zaund) ?, }/~/^./ӕuԐ 3|0 lTwC`[hD+ɩ Bhd|0y^Ċ䨘0TD3~F3E%6?M h˭󽍦XdcAQG5HW0VN(|,K8ڸ]@<UإQ:}d"5<0}kKT+O(D%Gݜoꐗx^=7V4&I+=0f#O/BLpJ/Y zȅ%, dpTi# 8tl49x %ߺː(+YqS`gF~Ӳ0ݴաqxsoҴ:. cyu/֎{i$-T)r[F$ƛCHsI\䖵` ^$G1'Wrj}q@4Qh|'>$5>뤼+sAu`1 B0,adePl$)J :xfLt4oy:!1Ql[P]#չXrĞM9ǁAʲ NvWF]cxmj ]`/}k;%L7ߔmr\zd%INIE3c7uv}QoR4EQ =2>|xJml!D=Do]?D漤+kŽM7&3Z*)ZmbE,,bC^W|hи %'K/4'  Eb; eqkc3I߆6Fvx_xk/˪ӏMm|`;|YK_o-_y a\J֫;[/0tęVP \Qd6CGswq΁&*EevwĆGKӤȪQv.J]UJ@dT˙LʅםL*Yo/a=n5wn7q=!iX߇uLʋ/*VlɆ`/KG:}rTlsP4~GhN:i[O}*~YEn[tAZ(ĵDifTJojKIjjn}] Z^0/(-llpѴ~mi`1 itIw`M"UXDlRg,^wݢ:6 :*զH+Qp6 7j*q N7 n5-M}tt+[(\)O1LrF2F/|f\J?pyJo{\fV/?5Th@gQ^x?Z+5vzzѹ:8ض*dCU2~.ùcWc@?77~25i!7?ra 2_{ kt:4ӠAǚH*xGb_P]8x ]zY}$LD~&} bC'ufau5׏8yD?$ܘ,Yb[OY.'O)16$''|a3+9 @f`D[JIk=AMڸ,$R%лm;xioSAWX7|j>ڄ0ɣ;pGIh׍&`֦Im~-&鏺1{e90I8)3W`PʪDB%_\@p0ܲ'!q'PgѪ1Y(w$mt?1>,g!D:D-DNg rX=:w%w_㯶9?eڠ(ҎG>m_)!pR붢Snө Ri!,𴄗VC M` EGNQpP!(z!fmKp R# %:*AUuhJf(^IHu9ޞjݻ2B{b: V@@CB_|hC!G]N !"wޠ[|ntvD5НY Zo3{[&Q4ĠK+fHZs^vA#vh/#o:JQSmsV1s־}t^Sݟ6ISvP=&;_{&m}WdS[Omo<`o}`_V[;7/+vv-`AMe:]R>RO{OuT壭Է[Ϸڳ{πQؿͭu`=6Wy@?X^1$P>Mz<v>mPu8?knlCok1\J狓%02:P#zIo_UQJֱz؂ a|sU08Xқ3 iwWȠ!(4!zGwƁj|8U;[&~E@?o7Kj}oklq?Cϱ4X6~tpTm=R?ma93MȖLHD/3jcҎl>|$g"tt),:G'X,-X' 늺ouJh> ;}8kl YVyY@oNp8 ߎf 6g2,tIN +ʙՔl-t[w+! &+^Ie(]Ὤ {WV)KW|R+V ^Hg p:&{Ify&޼s2C}Ad3w CĿI+ݻk]N*y2e)n He$"kPZ( \ "}Wc?2Q?zO;I/P[: b*zu2Iʉߘ )S`/;tәJFD2څ`ȉ, @YTd蓀wuD"tv>$ҁԵI0ədA631Vh1^!N,ڱ[NڛUIn&{n7^W0ZXTi+8ݾjM՜;3wa"},2-1aJ*eUGK`WC@}q_u3r* yӯˊPa4#dԫLP\Ph,( 4a֠w{I\^m%/ <4 N`L8Kh\aӧgg1}߯ws 7֨79|ئ sژc FyJBaBB +\xfsD?-N\JP(ͅ}|8*?qa씄"bB37)$ *Yu)\"7;q16ckwQ 8@ Nڷ nY*݉EnXH(kPbxj A%0W@ja ʃ#6~MtZ$ d u9@et95.PKJ~?[xd ؤۄMo`oea{dP$bq|ʶd+WQƈJqUK ip4zQʄT~@`FNè,C]]3Añ;H۰&n6^d@b\2(-Jq{IN^dy4T[AOA609x@'4[?7L}7H~I2w1B%vG#g4VBM/n]訴@&8A!,rϋ_>zg࢙E5!@Lc sS6MzAA:9Ԁ :v!#@JewjZ'hwt E>E%W@yt ܾM-NQW#*h׳vwr"AabD ne)LP6{\x tIMVH73t==&iy/١p_GLdg+>jc0:gXדЏAH$Fw"ni>QR-cb* YxnS|DmJ~x9Fb*Z> 6{c ,1%Ib '4H>5O=la~X h.y0  '$$G M kZr2Ss%Ԙf';dVSOwk.sNs%Vɪ ,г}n>`'im>} ʆ|Bȅ?;'LrV$y~xΣ a*0A,g0Ϙf,P>;I̿ZLP-ͻ l;5?б#dtC6V'i}ċ{s0?J~IBMLx1ah7)pr 97$äWUՏ?批uo*D}ù˽$VfYN)Q[{X7Aʼn* dksN w[{7&Zw{ >L;ة*o:~dl$;.?VϭW3\ 0rD瀘IsWMh# Q DHLJ}NT4_mknNf%XX˹㘗tRܳÒ0p.)fqG 2L~-^"'>ddY92kJk`7 pNj@cl1H> !\2gX Ai_)} NĠ!Q]+b mRz%CȹQ JSMԍsY2:ԕxBt#4F+ ?գ6AJ]y-P,lofL2D\ŢQƹ=q .m3V@ Cu%Tߘ9w_o䚿8D?m,2o'VШK Ϟ?QC>&Tq0uayrY]XvNDw{#(ˠt~p2ա 6t, gCsM<"3Κ=/~migY}c$ayXq{o"/'RȦME٩oV\;IIG¥ODơ&!E#AQrX#_aSCػiLg|26ak2V>diӞ ,d15Ɨb"Rf?p<ؖ~OIzRƠ{T/PHmeaƣUAϘ FFZgjg]8C·$!F؍I÷QYOEO:T=,XgtHcV_g4Vbf[2ũ\F}1k<ѽ@r&OaI>nz  !ej!u<1 _OeaT =j{OMO< KLk,R";tWv+ncyX Co +@j 3]G8L-GZhO) sż+bgD{^j:§pKжL0Y`U ;y6_d":v.:JG$`0wRc4&R dj,X.CKQVV\ƒ)Q0>jn m}H7d[g6;QrBs{84k KV&)&fZkUL1F#GE,yYիC5oj;ZG("þL/'Y]ev::F3;8~XGPM]ҩ8_[9.iyCf CSY_bX+%sY%8R%UᤃαIW)ZCq1oT3(1(UڏF\U9 (z1!`;Q,vzvc{4kkId1 ɴ@|E^ WJM7ؤg|&݋[EOklK44m|/LF "p/.|=s(^E%yq~FbIVe7bP+~`͐&ĺ2^o2j1U,8b$k؁ &\ʛ?sv _,qu6=uf~dĨ+tN4g[YXY,ɻL3"Rfg2["U/`3=Q,CFQti>Zh.с[Wyx}y ilO\O2r5fins*_IλܸVMm&Va I5!1/teݏHdȚϚ׳srS.9)/7%ڄp>ajBG8s][-nz미,RhMG/u=|,˶4c;RREfZ?zw~WʧB;R]EdK9MƋ1ZEhvwLi1. tVg*AH؁6:cU|j,WR{Ӗ 5V:|L/v4BϠ T,Z$Og[#W̶& ܍#".2>Kz H:%ۄJuֵ[^˺nI 8ݳ)Zx/E7CƸ&_xkgW? 9f=+gM|̷Tb43df%cτ8NkccGqbYYwaGS[w:Lq 14>.m] +zU@S@WeUq/qzIſ s8e?%0Qj"& s"d@fZm9_JAH,+\dWRRԯrR- z< -E6(!j3h2iܶb-EdQ=`C'wN@#4rރ E@; C)&T>ShR p _?D}T3wjZ{OŬ1H=0=`ኹDיyf':-љ2}C[WcTٓ1_ƌ5\!z^)_qg/pՓsM`# |:5y4ɠ=\cV!kdD|`>.kŴ1#9֧6EbB+Fm'cGR9PGchgIy_tfɘw%v%6jēl6^i\cT6E%^sWnX Tɮuy-{Tu`i]+k%h4"q˥\z])dl̈fЋ׸ VaTެ\Spj=kdqƙ] '_>̎ɦ$qAbOoUQ6&D\z)r ݰ JHӦ~zJodJbs_.ů5],kcᅸ<&@POQۿ+?`$pjXpsHO243ȧ9}-Dy;>=r(1\lTu^H^;iP%^,T}v|]„+FciXZ`/ ϼfME!WDDT}Bt؁cI|+ǂbLW uIWǗĕŃח<1~_;hn^yǃMtw}`맫bkz՝u J=D*BxE>'^WW'/j9iD(8fU$}d;qh%8=kc,p t>UZY OnbB8fT?a3N8 xm(dƝsF$7x[!ttDpqWcT&j.s`^c* .$IH6`J3 a8;)^b!]Q8:yD$[b&EڝK O"1D艧 I\ft6jCC<n=Qn,Sn`|%lp2J X\HaDDf*'fraL8<"EEs|mvNfukjZa6ƈMS;"rsəE#0%L)uGCcNc3Qt'ApEd?-1rcV5=såځoac/ފlt%p ;-; z6JFy:b \|518:rI'Zm@ a4|/kֲףiA9*+_B;[_Z_ ^@ Llx?fyqnʄq} #5.n$d [#>o`@ 8zIF_J-Ͼ QB̸4n&j9:G &S?E\rn#;J%ś%EFU*It!mC7?EqT; H4N .ݓS9qB-wUE'㽲zNo^O~뇣ZxGT勣9>g Ga;yNE]GcGj=IQ $ZhL,YE-ƱA8?G0}(o;/jwOm=}𠂽~Ymll?y\VC[MjnNTx]u+Uh`{g{[Ϸڳ{v Y;Ss@?Yֹ| paamo?nr5ͭv>mqe Kzkosзd(D Sl#zIo_Uۻ2Tr#|okk砹E3}3`p7 ǻ;g@ޯACPV??iB:t`oѱ8psBjx{ 6.ykIR{[g+yj~ݧ34jZi ϙi*Fd@'}YWCS *.~}ܧ @ڽ1⋸&bqaFDT4VEEmZ(.߻WZ/ m~{ۍF1jKG^~|[Ub/)6wT,x>' wV{$9Lys7Apz!Waj^6mϖ-&}lԗ*UCqUwm"0Bу$[iaM{|η6,,,LggBPwl8(p(&͍X`Bб=yѨg.y _wpꚾ(~ojqRk;i۷oX^hgduڄua+q1}GՎ|% gp'; w(7aV̈%zWUր?gw{U}_o(K_zLyXx5M(8~"8)ui.oD醅CUXUZ%<@GUnAnX a_qkygߞ=5D-5p^~j)T_y+n2^+sSZ`5NOu!wǫA9]e<ӅDD\hIAR=DvҺȤ#ΨLDԧ{%xM@DT TfɑGaʉih 9otLtN#Uzb5Y*(a+A8g}@D4% 膰tma yDuJXĨy(nNbN( XVBP<"(6%FO4¹ ! D,:.da|m6`taν `rIbkyڀ$|Kw8gxa ^~t~G<h~qD |ɁHm 10}ɖ}k'jm1`@ Ò9aB zR>#~u; T&FѨ*.4ЖPj'Dtp0:%Or T ~m{!K|⒞RԐ*x /s1F0ʌ/7RK1,;):Leҗ*Id^5۪Y`^3<gO!ؔl l/22NW(0ٖ!#DetM./N0:QBVfY07*29]sf큨66PR!'at߅~!abo;IEʖO$5f5\dYMGb6 |fdx:ՐHanSm1 xޜKwsMf0-"df$~ g1]zѸs5XÙ6!*yNߡF'Ȼ'a8Ŏzm]eOΒa4}[;^({"WBw$$$$$$_N5F2@ܴ^ɐrR'Z򕰓r@^?J$m"qI$Qix}'?5[0h\;[p?{q`Ak{w1]H$j#Nx4>*lаv" @_ﰕj¡h_MhHڦ1cdճ ~0@Wb)-iID~1-8 % DIPr:G-ܻdB￰uB9 I~p҇a[}8߭6UQ*L*4/}W$5ik_4VW|leeoɏo?ǏV++۽p mS|' @u;tTyVe˛p//bV43ʪ}cYgC/d1tABxY:_$z ,;:aofwqؘډFfe3ܙZF pj5<%ϻ)yI iL=0cVc7-H\272uXfRt/RI%Iy!!TrI;v`jK^zp+Bô Ivcj}=Լu?a 3bz=S6W$ey. <*H ܼgIg= {I ^Vp3Ռ{גpIvJIQ+O.ܰrAHi/'; Բ{LU4xtEȄL̇' ߼xF -@[oF+8$`}$1Pg~|.MuE2lAYَ^ X'wr4@O4]m_DkZ ErĻSmlpd¢[m=znBZ4L{n"'Ȥoq;uAX Ç` ť,-9Rl,E;])p 3RIx;R@iMk>2yY/?4+6C*QVy*$GTi@oO S {-\\mcMk3 7*Q4Z/Ps޹믅b^x# U"?Q)3 6ݼw2:mNgܝJhn&fRs4-o@ܐP'lʷ~4'̚1?A?wrMUq#kփ lOqc9:FS=O&?Vxi;Ȏw;Wn'Y*zm7=W&IžAܶb4? L)S dcG` k18Ad&,L>gx2ގpϰAް0.L4cU˥,ʵ>4o\7 Oh, 5(.Ǩ)&g4?@{ARTK%UoLJ̍@,- sm@h7Iq{wc}YN#zZߨr&8 J_( >a+Cb,%tNwKxn Fq +Hx I8?6U{{sv#O”auը>HQ~GT6 eCE>ˣl/M΋ VZI-@ \> tG?q CUy]ZQXr]6=;}l* F ڗ;cyu\~&]b\Ͱ}g*_HCIP RȮW'̶*n։ra?/T*;zyDG+F0B6p)6m<ل5!~ |ޱmoRۺW㙈g5JnntŮSSc;`ĢtN45H.H 6l2ƇT/ŀ3Q8v;Z]RAG'YLLbvGNřQg9 F(m\-a-bےQ6o7kK@?"S5yά³"tݓ>:v 1;Lky2!- n)&=`VcKƾGd= V:O~Ыܮ$ 0(ːtfTq+.rQf?fKt ˊ{P(BEMۡ+uenu-ޮ9? 7!&S;30)JZ-YmJ#P:2%쎶|R Rr&*JIk'Fs;;!_fRq: ߘ툠$M+r-@]@TB͉o:B3z۠e%emXtfuMm^WM(ՙ58^5N^V6h ­I#~Im;NN+Yj Ai%{N_yF)+m6H4 ұ梬,q K4_ʊZ!15!y&_=W=BzϷ`۽;@Tu}rDNI~KNR{t"Ȍ&N`KF$+<2^F~_t9V:qe2iUGհU 8H?-[JA1󤨼BuJF=A`Ƒ]+? SSwam&C=:- Uŵ1$Ўx Zqv.nrΜ B;mCf[6n{ ]Q= ӓўD#B:&OYSbYO s ;ʳX{(Fy:D7gYAi"18-$AS,Ha8?bu;F\4k?O>ſtg5)V1+#N2aSVJSFΧM;=X>9njJ^2 Ծf5%#c7U'b/^cPUO}z!Psvj5!Zs/=tkrGNaD xq|!bC !)$@iP -hMtlGa;@u8tL5-nf+ b\&uEn2 `M̠&$g򽬉"ъ]jm}l EbA7QEj{5d~@\VpaLpYV.YIhLJ.r GAx3RSj ndCtjK;[nH?$B2MPMW\ZQ >f_rE0V#B i,;\JI4hDbߧy1NX<7?e=meJ- + aPőM_qf+;7g٩m{ E)kl%-z} :na4ARxskȳP\/ɕ iZd=قy[#ƷܿRUxBN2AbK\ J|/W )<3se5!8%@uӸ"21mq׼`he f)KxfYB5Nf({eR^^]ă^wD!{ЦGxGE&_6@6s Cfɿ<{p@t2טO[ j֡POo !vf扆eLyŹ4WggV3ڗu7m4 }XH H's`V)4?(-#U3-:T\hđG1_r=yk H`f@Q"F}5w|d^mDJa]gz,j6톴^)= $} Q?:hH }\n/J\85n(Kyu&ڵ+|޻7)'k>w]Y 8xs>\A_/Z_*WNU(A3|* I|Mʺ8,c|^ 8v[W g^XdXLˠY7n>a5 E q ]}[¯GaHPHfaU#e[}`FAf1[ 4'}=J- i_lx{ۡ#:x0%-c Mқn8PB"#rPl4LSuH;*G$[ ,4MjJ "zU8E]6~Lub"2JVk@. Ґ#!GWӐ#D| V($*͹, (eJ#kު[r:a-&aлZsfTs4j84wf"j Z5ch' 9QB6wƬga %HH9)R|.\ /vKeg"ĜGY4E:a8Mr K.]-3}nk&8Rz f׃. 9PE\oT/ /kM1Lh@V>,9ݱ>bmh8%H+͠remؙb"pPe($XE)"cxM4DD/?ePVٱ cXECH å@m߹i&;6/rsg)%ڟ6܅SGN jRpqAW*.ODz L<=5yeDκ~&e8::U/['t:ߦoY,06;~K#[*׻rYUn%Z6ReWZ3:G`(nɵee]٩krr3Nqۋjև9KG-=Zݤ e7g^,G>ɤ~O(eΪ$\#;Xi>^f]`Tjcr_;z#!|2IWO;çQ+bR"`|bޛ^ `ȞՃ,pZ룢 $..Wۏ[;;B(Puf|ޕ4ek.EXs`)U @T hqп%E|)[$b@?'1*➏d4lkg2ήT(T@g9kd#Ew[}OB)Z}^&0=83*%#;"}t{M%.n3SoШN֌}I+fONcz(*¨`tֺaozYqPzNpd|#7dLgL}^ ?d19~e1  sQEbIؗU,n9udbalHKAlQVu\SU5<@.7CcK$&e+96} pdT}Wn@2+GW;filωL6iT%糶N@ D@3PAYHƋ}J\fa8NXIe%9D D(_(=^wtqu+EYJ^-bZ)9=f zaoK}]j8N,y.+-Ҝ=ǐ02. /$@45v88Gr#@Wv},'3g08~d$S,,]S睒AI9?{F$K"7`{}B*@1}7J–=0RUfdfdddddۑk܌3:LI3[.+-ɷiF%t^iD3˭ݍl>Љ]heuuP TOn:YRz!.0]l{%1C~-Zقw_{E`т(O. ڋ#cDM|azz1BEB)ʬR%"z\W੗z \VOчkX^֒X}lo(ns92O&m}QUNƠeU]:\c)l %TU!3<.X-M.3 ! L&qoL%4^-N9<d:n:xip4:Il t`,zp{^w2z OШXo6i$TLhw`ݫfsvѓ` | p[5't256~J[Y1h^ab(;p5 \7[O-*z_Sݦ>wߓjRi-~_&9sGcz31Ϛ>6LNc d&XgN$_:]Ou PZm5UjNkk9s41+4`ssi T{L^>(>8]PEXAB` Ah]vI&;vޥ +ZHAwfkV`A+C I՜0!ڲ|-9`, 0\}OgC[O8~N1?qn%H?y}p╏xuH؃Nt?\K29{:Ūy~XJ?Š7t,^YZ&N=`Κ핻Κc񾬚+++voxcN5:\9sNnI->P3?a"DHsB7Yr1qd.|ۆs 0D'*~\ֆ4T$N;]PHҴ+6 UQQT*"X,C1,sF7ޯVB$]qtKW%wB=`NGR]o E0o; -:M;wC=/'9ɛ+ =0K=t&^8iM)C)Z][>y?>uq-WN9 VqkG+8bԥn(?54Wf=\C~ֿ*fOPKTx6,3v:܁p~T}{sօS={|{!=u)_v)_lx@ oq*o#8>/V TM<$(Թ:uvoP msN6OT^[j?Y4`7V=Co߶i½m;vϺ/Sw_s6_>2n?s36)[=z|䤧Mfs\[gϷf bUTK e3Zz4YZ/BK4=mgpC=D G~)Ӳ~hP\P{FoRf4giHfǛǗ0 )Z,ΙȦQK@U,=bKp!?usԻ~ kt~ĈDjGwJ"ˁF+QfGʞkrr`f]s Z!i-mȎQDt_R O㨃|b2cOْ.W%[_!e ;(Iq-jd48>V;'04;<,m-na0 jq#er|9B;/_LT'n4K4kB*n!?V ZئɧY2͌Anq 1BʸƚΫfu&i7EiF.櫕zM4^›# S%ssOq k_}2Wo3=!P5-,xmLggVO%Q@a!sY`_2Kk'w[?\?[OQ^+Gufm\?{wWo'656?Snlew[\TxxmP䄔gd0 ''9!######wsU:qN^ j'61߂9nwK#Z(1̵ɘ4~:p [s*Z5d$KM8Exѐ݈蠮1kd.2H"E8ǰb]ikOk3 "'7vC )(!FF9ߴ7ڧ#ss ]TZA"zA?N32)z!?AŦĐЏyM/t!mဖaC8L(\n|Pcc:P16PTdo#sOS{#H.Xt07~ޘGc!DwrDNY> /9sKs P3r1gwSd{LЉ*XAO[Ĕ9WwGӻ>x Ԃ|x;Dբܖ o3 #@^*[mmorѵ@Tu҄*9 #F|B&58Q+-8=3gjf!NfQ$eGzbMϧ̰v |ÝC~W/<)|` }O`Vyɝ;km t c:4@BadV*(t¡yts3gD7YSM8;̦lbćvvX 3Lc\2GfF*Kȫ~s uV!!j)l+%X)_V79,RgQ ) *emE)q LJQG3=Qj3XJ4Q]_)Mk4nal|.39?g0LĺhL(X u=mmd}pq}nGo߳G.YŚ F:= krO:h+b^\D:ҼM½P} /L3i {LN\ron]Ӧ f|aɜI:^^%>(e*qP5,ь>n0 M 89 }46Ug>8v&ͽr=ˮ6-)9gw#ms>y>vZg<:gALv I`DDH5Lyr=K'KFuזJK,!eQ#(&1O?Dntoi`e!n:HToD(&D㼠C~1R'B+lM63lɦ2/Q5ht)N_sk9RvnSSOlꊪR o0t>ou^JvƳ5OVDr%&dVSa<~b)%EldYLb_3o(% Ngŝ;wBID1Y~Zɩ)GŨ|YksΏLFE/==KF@߳aʓnJ㔙 (ZTt 7f0Oq\g= ẖ:7C!=eM}z#667`؜Kjk 6haH|b~H[6:Uu" ɲ1ݛFGpzCs$."[)̉苝fpbMv^s2+2:iI7^"ГP젯3+#Ӆjvqӓ?UMh%frkŀ)턄Z<"ΞV e#M_aEdgRhhSk mm;&))%i_QU]\@8]IWwLf[Q6I(s˽>u>`a54/;cT6)o.N)ѺE+ UǕcCbS/MS/W;СlCoNt,4B)iQLFQzFw2^x, 9Hm0<7HԀ{!ϔ?,{1wtvteH|֖jx--J{M4׫4,J:WވZNt7~#S1o <-k( <{<})ܒ3a62qJ= xh(㡝=BD?K wD?` *ZN7 ?g(9Kvv~Ğhv: oVxMx2͹ouӟLfS]Xn(!2ŊV98lRſq)&Grxp+M=@JgtT}0EpiڂR^occ<2Dg@6hT)C)cm.'ۏ [fWnzdKjo^I幸j }sRo9X[M3sc^P4߃e6>1ۏzԷO׵|bkv#tκTQRQ2)F.tuGD[/oU%\e8uԻ`t}[[( dhWXy@%|K-[?h1!8 z\Y>`aXXJoix󫗱ڂlcӮvV{]0)VeoU5z 3q,35iO V;?zdX"QεYg@`h\|kE:fRupWlq{#\HًD`[7-dՕ>1(ҼhZ yu'}ȍ HJjxR9ݫ 5UUVQf݄:=Vӂ$ŲaH땪 QmF!J[~.5 ̉ naxL._uiZusK+uGEwk2'TPh<OA1k߂1Ȋ>_Pt0PoXt#|}l&W=fNN 㗯.*8f}֥Փ`( TeexuAE X~nLNaՋ2ͳef.DinGa 'V+lfOX$3ϥH/KEH:}0yZ!\='3-gHv171`m"DҜ3~S,[)$vc3r]ՌɜF r#{ÚK%OUyyHkmkmkW\ZJ{>CzqE2\=u{t}ٝs$"Aj֞Gϋhl Gpq>OxSk4g?mAyB%!)jFG k)tpL.SImL,+%lR - x)N~A:{?t6 5ogR3~m P_wKw k{:KfMLfbsi[_a߱]-sۓw^GkSPꝦGg;77s_ щ?iIܺeMQl}[+G1|Ex0yn-"-h­^o^<=r~~R#@τuqaXDLcN7_Vu|s٠_zz;좢 &݆Ol-(剀N~}]W{ x}&$ HwOw7uc-gnoi]_Ng;>YuYzZOv[hR ]?֠?Y=Ɛ,uI:~qXz60X&kCu(l>ĖVN~M#1Gݔ$*#/)Q;su`1Aa9El nm)B*7> 36RvXp\u)3;NH׍_7 NMr/0Vqw(2Y 芽_Od CK|az LaMXvp. yk]DSGnԄf:(>?]ĩyό~bC8?^u}pX ^RWF'm}޾y67O<FNcc #ٵvv-ATIj )#xM7Ӂіc#(?ƣv@HuHBP2E _)h0N@^ÈR-kj|q~>Mfk`' BD(%E3pl:ӆl1)ejOɶo-8//cDN/+u:6<|\/მ_?;:U SwFKJ3j(S&M_7nrǔA%S\il1ʶrףuԨG wkpFݢOEC%}z;֤`a0W9EU^x5"zuyفp~f#w |rTUKb셚~щ e\t"xW0.ص 6x?lO T듛346a*MJ=-[,Jd/nYnd̄GM{V%v]]#baǞ\"/ ?)'"P(?CJÝY"/Թ٤/<\}Ãxw@o'%3$ ٴp%/|YlM٩jVj)8|^PO[mCe> 7M>c| "G_H^kN C%I?yoF*׃_MFQ=<⏏aQ%Q5%m Pb _|gѝ# H=C:>2y~} H?f=z!vz'ˡ6S AkXӕ_j)sä2ϛ .]Ȅ_TBTbqrD\saѨ}zvMejHmUL(umL\D۷2gp4PQ)N=A EJ)g ֝Ч6]<|Răqhn^Ji ̬*!F&0l7(1 I/r8إmWmS' &_uiB-Q']ˌKμ8cm*$mWu&d8LPpTac"8(*Aj&k"plOqh[Bsjn#P:Ub^MStc%@0jzmObH+@9眢s *xgGmqhLm: n_NL^xhgqti\hw7<8`#Qqٙ+rn*5n^.'9q9g&n1+k"YD[$<0h-acywjzCh(|ujϑQj'ndu Ӗޥԋgr ~t\,0vT@|5^:Tgg=-".Rqb ꊴyR3n802D .&:x=N(/^ZZˀ5=p?[y;># vg) f^rQkDY+*Մq607 |@&%F{1 ƑRQ"nE2J[XO?N.K Z8@ҏ/(cN̴$J V̒P _KGcr@ Iϝm_ȯhlnwZmfOǨ&p:|He+?1™q OoM]}XsH9}@= }WoEzY_lFL%>/`L=XO9^^н|"#xFNuwΜRZRi1Gqou݇n DKrƒ ]+M%^VѠCV=[NѥC3OjAGZ24}YbsCs8T^m~fla(vj""8 ٜ] r7.@)=kG?$7/<"3p)+75@ָյ7vZOplSߖP%#3,5~gsQ?qs&qa&!2ꐙ`{1=)Gq- Zs,ĐhzȦ!ufZhmAvJ&\B&YD ġl ^ <92\*cVd5 7nlߔ|l*ew{lB 'mi4dJmfy23-4̂T 2mm>i!a c[H)q*B ߵO85h/,kާ7wVڏ#: ^L("\D74|C& ܷWT"a1t{rCٞm+/s8> YzyɑОahj؋$bH3z-OqPCx_jG T2>Jڰh躕|EG?XfΜK(P"z(\ CVnQ6bR8Mk!{;@c`2¾I6;Wh(U-f|)D,}I@i0]l.,*[:Vuϰ6T>4)ݪ56~+lwtj`=܍a8%CҲy #a<:w PU+?;^{ ‹0U 䢞Qly# `gp,f/e S+_2ᒺ J> 2u0k8p T W {M9H2a`8Q5 C׭錗U#"AᴰxTk pH=Hq%2DL\)}_ Tl1Dg@: ֤JхU!P@ZlCi9r6rJ%?O/ƄWWVog=ٴ)=+BI)u t G`kC# y ң9,Z)#%)JG^;'6Kj`{q Eh IUzp6E?% Fd&q︊РL0f'ғ/R @=€~ Vu@,U =o4r Ϣ6%fr6_yi*`3G@e[2v&Sp$Th %k~k= #?7_ jg{PIXK^XŊkzZ,-V?c̩t\9ĵ )|`\FV369\N$emW5aߟ8@{w5lDLV`]+NoL@?Ӓ!h'Wڹ:z5 GX)ul' #͹nUkp{pMMe0)It]S/q90|ﶂ)58dR$7 ۗ)i%]ŝhbBx2a@cy8 G\ BfGf, -c "q1vC` $'\[+HXd!9 Wge=cd?KK͛9]{BKl\.I8R[҈VQ$' U]x֥vX;-$c]rhc5͘4?fv sYannI2ĉGiN$I2 *91HtLƌ$翠c,߇fG}L֓H.VMZZ{[{kdՆ݁n7HbTz.Ȓ ,L<5dh>q0! 14MI씪-udt@!@R"swi>[lj&VDZ%/ o ׬,m)ϒ'U4_ Sg}JH4%SA}oPbMSTN $ MK/VDx:魛˩zjr 0-7!!]N]|J^8&$,~R9P:l&e)$@`zqvӁrNP-`>1;~f"ێZla:{ pQ¨1M{ZeV?$c#۞ kRakgٴ|^TĢPσvr:T ;B4MؘNW6A.3 {dƢmy=4OV6&/ F0Yrz@x g#3"x9[W!$qe->q+! b,&@^e3vN ,̔|'O5ȟ#}0'us`'F Mtˤ7AΌݲ%4!$·Q B~Z 6%s+OԷ`&|aݼz=0'g O(G@ YFQE .uFndq%&clpH[؉+(ec7`,oe*giFdh ycpm'#sdu0)K kjzA$2;l8ï*F]ccMldOJOD[C"16YÓ䐢Y쾁"LԈ)D:hnA5 CD3\ Ō!:x4dHEZӬȑ&%*̮N%hPшHRRzn֟\hM:,.q܉;:KlU9XY0jàaYzh4y|!.I(Ǻe;`+BvƵ]"+d(e*h֫WmzX01B'pk{\tST|(*hcspfm=6BlM 6|SGL& m#qV5}L&(莡aḱiaQŮ5Kqٸ>h0x;qknltMQmsqN<a2i`vu KӢݬ`T\~QBSchk%-whHGu ^FG"s Xwdo\:@nmZEEق#͌nn ed%GJXht&ԉq`Z@_V9O8]uQȑ)<]cK3ҧnvr~G0GxwMݕ)+*a_r\:r-k-Yş-+}5[[ͳIvZfhAV2:g8v5t1G,JA[86Kiј|/ӭ4ڮ$ouDkxD ֥ãK,6}duQR@2iIzr}wEu˄CX9a%s]Fm *4vyU^"s.mxMQa/el1{ŝ%r" 7WD&' ) Xj ;ƻL*ӻ  ϖz7Bl֑.~Ҧpo񾙠md0T}@(PSoUdB9g/$H @M ?:Mf&Kf  /r?MP毓9lC>$h-kZ1Q@^2z֓ {w}+dh"@`.D28\(\ihOC)Obz1|R:䁲iN^ѾGL,|݄<2z81{-vFcğ(>Y)Je^A=XES]a-yP}P}\g'UHdew);CHLJ%&~4}ݝFhyly}VZseKp]~%Vlm.z,ӄs[Z^B! HK<юgr!8oLO*Oyc D^mdgfHb^Tms5μP^#mmW-q:aټX7A-`b7 LT<"jR6?Ëoˀz#6lwe'?}ԾE{~wQ{gުj bAeck2l34E\ک499&/GO'{5uP-mȺ\nnbe`cE<5>yDP)e{=2E6gᄬڨ8 Q㴣0[ز}94ޞpn0'FGIoGHEwd2ʶkT:S@IWdalLdz `I"VqAEݩ閳I`#+/KL̵O~9dc9Q- ILJOISefD+,@'YH>m9gD§Uwehz?0[yIR O7T%6މ9{f׮l`7*9rV2<hͤ|z/MoM_ڌw&9YXƭ~:_>r\6*ZVn\fҽoགྷMyL4jT]3YҌv|A@JFuo'f# Ѕי{'(`E:U[7z±`AbLq:8yܴ_y& ݑb j8Q7=='-b<`eѣx硌ĒJ<(|U\$zNh_\Vs%` 5 %3 pZ7O$S,ޛ^~R#.߄LJi vRFuWLwJyU(\D [3Yk#OZfNȽ(IE__V9: Z>1]zwDw ku ˞F3_Ebh4Y|b.'XC=+tt+c^ ԡVu(PRI7Ald?t Q!_r3֙.*!90A8:ȌϠ]#)ߑ}qKiD)>wR45[\GzW0Bfr 8Ton bd ߏm\wD"NXWW-!gc.v:ZpqS@"Dc6l*8u{i[:3-4Dzn5sn<(0*|h·ѨP&P1d3GH{%=bExA?.;sנ7@?\+VV_i>96OalKm;w A>N {հ& `P_ӮtgF`5/ψts@2-Ye/;?tVV0^֘Iƫ~s  ͐\0vZI+-Cs3փr'siz޺~|P _){>iJ\)҉.OOM9iB,L;;7 mxHkN(٠4oW:( b[ă$C 0La!2$3 WԿ@]& '_tMB qg>RUem8pH~B 4XNb|:ǩ sҮQRϬxFGNt73wgGނnݲV^۽|OܒNGԥVs,ą5'<>._$ΦH",m|y0KA(r$+U5?=H'?lh={\ i:Iy҄!hCIg ft &2&mٕ#83P\F`{y m%:( #cu? 2s x 2_KYxxkI-):C"pR=tf 6æ #\u9:Z Htuv檭9qD#mѻ(NI}a2&v}['8Vh*ZUWdļS( .oykFS;Xa,?w7$Rڨq kA_ gKuiZȊ^-;۝Ԃo@B21ِsMV Ժ|L,6sE LIS΂6 W_h1 w}X{c#fm&k~~~~~~|oa"`v]pc{݋Mc:KXjG^1e#Ӽ:1a)G_tƟ?QY) TG͏y|>].Ҷ.ͽ[S)2>EI\<)НYu.c5M+nS\wZJMbd>U[~" e0}ŀG!TJ:2w' Y8|Uw4DەC 9=};w: oۄw '>'ib[y6ա 9S]lgsmCdm,Byk8#jg vI,_|k ՜5Yxش^JܫOy"NRy`1ˑ-V+a..r\Ix}-ղ̛f! ~?qc LKݘ|2ȴbOnLuq!}ޤY=[u= µdMtn鋿Oڴ;M4udLr2fct u٫nme5(6%.5Te]yoٲka^[2uY;s6f m#vC&xݎϨ_ƈܳyknϿw3jИ>\ #Іzܷ 蓯dnJ$OSa ~>y ͳf6;: Yxݻ!Gw:/B7 ڍFvAѠ}O W6*5?ߥWjR֯}]Z_$31忇߿{jn“i 勍je;Z\'MV#*I`[feyɸ F)(o>OO@ a,ׇW"t+PcvQZY?:Yb u/rvejDp"D,gK߭pmy%P+}1i]aS@8RroJ\V+<q_vs夊{/pՕoUwMT&q\}a@w&wy<n*T-ruʰž-_^O|PU~RuM:az ϼ)Wmη$6涁"wS9>dT` p{/:IF P"a$/6 |ӮD=VEB*7x=F1YhN pI +>vty >X2'2fuj@pSCރ/mݣ71A??7%[ [3$XspME 7,޾*0DjH"aTb8fAf7CE2063ۣyKN?4m/3l3wňU#KFvS8ctdb`>d hq,]o^p^HZh toW%xd m- wJ5jKV}wj>RRߒg$)ŽAԩkfyd>nB3!\F}c?M2yz|_Гڏ/'Of6) A IFdk&%E,|Ւ{L3ݍ2(h6p`0Pl[&IiByݣG4# ʹ|*lpegnL}Zó8?Y![d(5Ql1AU-B<~R n\ƽ|*ǽɤ磧b)a(VW$i Mp:Ml>Nu x;nsN2? ΂ K95D6?4:ebS+p 4y[S)ilE&w騛bHƈeK;n(ݎ Gi 7縟| Εǒk>((ʼUSa~+D++K,hk6  :($k;1T? ө -A"2؜SIOq -E~΂e=WM<}ia6{%[Y2) vه2(PD9ǕNbuʫ$7K@OIK! +6U~'HKO˶#.S&҂URܣl|n>ēYviXL=*XF,y#2 `4O3nO)B_<(Z@hr:$] n3fr29ZٟQ#ϼG~rZ#lv,X*d8diے%jtSfB;aNAlcNs(~k<Ud dĄLzᴅ^u- *K)D-dQ촎KKK3̬QGOUz#ٗĜeWs5VXn//ݝ~;_/0E&|%ɹaW5֐khc=4sN=^;=5G8)6Y㠭AwK3P_` FrqrQ/z]j.`}W"۪"*OQ͕k^U5n+/i˪{]# ˘)}+1o+F]$I7t%Fط [\ܩܫ$eE^jgʊ: (2Hu8~;Q].so9p3OM]=f '.ШqeaALjBsǙ!,ݏB>48#u.\6 YNci3A zQܣ(&I8^]b+o2u|z`Pqs F4Cȯ}s+i#y?rN}51\&BץZ4K{"NՒ<]Y[+׸KuGq;.3|)T z<F1n`e:vꊥG}[i[@+΄9OZ.sa@/FAhovF9U QBc1(2C(R=9%~JPD336?<Ӽ!ONV'lCF1l| t8OwBk]>@%q,W,,~u١z4&Nv|xYDV7k8mAf:Z: |+L"eNJryQrf-7v?arHm*w=lK>sni LmsWwăE‡^|YZ_R%1Ne>{t?Fc`~bP2SUZqL +c61zbJ"ڝ'e{+GAӒEܙc`Y=_Δ8s_ESAc,":JQrŜ{ր/8`b#y56`v4xR ݘ45O1Ѕ8sCEOQG{~irAW:0N&d|(qH4?ͩCů@ST1fk0]%XC$A7'brMV  Ev۹Tm䣪WW]UWs*=WطƚT^l&AށGk&FZ%NW=QR[i r:r3}Z)8 =3MB6SrQb +Ť5jLC J|{;([Θm-CD.{ddOӹhͰ-?XWM0A hMۯ~>c1wqj_YG,l.x<`7Ht$1]:RvRQMZ0Ft~!@>pj[( SH{^#6Ϧ}yrE)tnY3uA‰NA!SQ K<D$!/"_/?Z̽2f<(oƱu$FS&*P, wMR,uL")Tpc!.hkw=6uS<'y??kEYhAJOS@\{OdN-8'èS=  zi٩N!4e'( XqfMX]eLA1f-{r悎!?^ O+c'VOӛF':Hh붟yNۭ(M+쨼t5  nzD:\g)nr|\kxt~u%o00RENxKzM^7^4`Y`w  ޑc*@$lj !O༠$DLHXwU[d VTe$Zg_Gj@ǣU G/ӛO. g8!\^2#ۧa q=Y/aKV1'2<ÇIf^|d@2Μ0)Jh8h9 iMD_@R ,w+hkQwZIcXo]X)gǭV0*j|0{M$v{vSt`ΕZ%Rd>FGVeNzHukڊGGySĊ~mGtK$e5)(xY\FXSu@I)8A1=DqI\WK+à6酦wCtJ5)B[vbp]kSʴ W)1`x)X17Ϲe7Tw/*M0DYOVT7{9,E6p}p`Ce" Y% _J|ƩTfÁ \P>b@py_*J=ƽ O# ]Oa2{+DG413>#]ԒQyttE?I0?|xM7Z\T kS'nHQLϨ5բzՕ:T+)oWV=M> V$*TJc,_T&ѸR>ႎ;ds)Tf|Pv~7qvӧ+'c7nIALDl U猾lhsZ#XSoaĆge/jmwחhɰ} m/_Pl'}3L '^}ɱ̡8~S^f)P yVÉ0>Gh'3Q,(QjQIQI=/9[q %/?IY`.(,ڰOZ'nD~k(3J.PHjuƔ8r?UESNq,mp[~S9gd?QXy%S,o<9Ňt1t|2Ǚ櫫.` { !*8"ɞ: 0K7)O;T!_:`*SXz[ŏwֳz‹_wҧUF΂֯XO+xӓ^>{Zkz=q\ @:f_SAj_F3;`^lpcP+J4.c8\é&0溷B*_J҆"NTnGDN#IX!fMzݣq'S ~VYv&όA|IBÍݝM MgH(W>>{-zrvax'w!!"k$9 :-oQw@NT0 fq"uNaUWy$:mT#uAB]7L Q,`vf25 ;,şX^ecvEzx?O:B9>8tYw4NVxWZobL G.9xH 0նC grR0c1)|g$ųYT+ʡnXG>n<OָhG1)(42!ΨppK߹t['jE_Q{Qw}tqݕFEWvWڴ+ *`CZwg䠿K'T_ᝰl_ߎ0%gfԊ=?yο84\}WY2YFix4gpԾ+pXͿ _Wfq:6?V+Wo?~l?Nxa77^UorՀW?>]A:pX[@-~d΂O"'R,T0r;"VWV_̙"3Mԗg*L:mgOw:Ya ژﮮ7GD+2uPFueѣ*fGQoZGWuAWD>:Q.N?I"J Dk'ZyH$ \siEյ.ԨV-:"0nw/mX0Q.6V{\k SLX2M0r4>luv6;b0us)<@ QՀnF褪*n`ۜuit^k@N5&@ ysL~~\ EXEuZפ)tg@|CѨDom:GK1D=zb`jQڎut5 H;9\BX)|r-1X#<. FTpqKNq ~j7w`r]ī u&^"0:%b54 te+İ FBYqWP0hE3MT3zK YI 8A:Ə$H30wG|.ZF"JYP_f5JGn\ ĘmpW :PQ$̕;/-=DF~ BMS8蒁kkÍ ?qcM+f+7ߏ?+PB5jqQXli0#Y KQu_t?jGp뢌Б7 ?^D Lz_IdO!fyDQ l뒛mM3oƽ ́sy 1>A' ~K%բc!JHLGpہdp^D,Q~d0cSh?h1#'6]' H}㿃1|mfoSB`%d!V.pEe$ vpHґN/oD`#ثH~f8P{jū o<>XP;/7w_omA rP9ޢ>-Pjz;ugw/jKl^mlGh^;V8ݍ[KhWmPKmoΑ:Qvw6~f`[;ۛ8 ȃ.Wۛ;0,qP Ttz1Vff 3s׃Ýׇ귽-;jw`{9 ` >vokW;{/0fP{p H "2h ԟo{2 D p- >ۿ7s`Azpn@˯q4Y7~thxT(pox%XcQw- %c Vv W*d"6nD-WQޮm81K:HOz Xz6_!etexg|'U-@kQ-JeaRҝ u5#FԴL"/h)Qs'C7 'W͠ouGX9E+?YBm341Ɯcg*m\qKꪯp{>*[udʚx(w$_BҪZZ%hSeqasv44e>-7%|KRS;fKpxZl3tQ3E]AJk/șBU24iϩ=KJLW>lNKFKG+ݕ؃V?S֩3lA- ӲO<ę#eճYil./ޔ|oNG.I"(-3kDY :^o܌n%;=3mgqFTp>F*z2:(M{JdDn^ W\\5V'S1)䲩p5Gtc9'x*eCnjQ~*4?AjrJY,j14( dޗt{s0'񻡶D yVr: 9.MYӘ6t'owgkOoCewp%NTl#Wi ہSr`֫$w>Ժ ;ս'UnF`oL6ȎĩUtn &LMK[yBáWZzjIwQԞ8^eGeo媥-g+w6OGNDy9ʵdib}Rn|~{'f㙉وF:nvaV|h01xUԚ=zI\#oMxj6:#j[=QZmڋOYWWy:OtbjC(4n_U7U{U~ PMoը=\|*?p V5"I Ža>֬i0E-' ]88/cHЫ"I|\|流.k@Nf zh4 PMtfA^δsڸT[@qA7*4,?}gFA4Ayy_D> Womp`X Y-[.]7ٮ a_n߻2ariZ໒n"e -֮X`myYจ l2h W^zE ӫ"(z0wfYۢyg~}|Sӯ]6Ç|I6/!dm@ z[ @]R43"̏63K޷RxW!eJ3M"B ϼ.Q=?s;j !hł+ a` ~ .}hi&'!diI^K>9>cu9ɧ=-8~Kȁ螇FK ˼3kOpe`hF9}npJ|m(^WC<S>.⨃W'nd:س5e<^zy~WzpbQ(*ʽXʂA4O;0hP 5KE ` κC47(57AGSoZ>ݺmVzױ֤&O$ 49L4iH: ckA&ԝ |5ub )GWJzp|OKP+;Jw(U>ewŧ7Tq⻺ȴ'XC8>3Z)@ow $, gXcqʏoUZxG]BDC\ߟ+wXY1&Q.i6%VWW8PGDT>AZ _Nq鵠:{}8 TvGSFx`+[u# ~:sr6/W|Ai,,i>tԜѮIFEF7մύi1K]EWw'2;mXUZpV3^.} E!o0`j.4z /+2uwxQN*sɿPkbixD E)iЂ Ч{/sD= /0ԆL; YKPԚZ|(tsr|} N9UN?T31s~Gq2WlaU>=j.I/+I9fLss.Շ. Őik?8#`$n<\ϡFz.ӠYLBXbBocYjv\ii=+)(QFP ! )&Cyҿ Dp 5! ß\ dՆhg6"[˽߷xE_p럑v:f4C`"譚-Pc}Q2~9~]]Ld!fF*4h)Bi-aZ7-۽%"uC`Ex  e5v T*k@=5Pn,낯@4uML̒c` DAl=څOz~Fj^1 v ʣKUQܷc|"S>mDzK xAzfu C*`unhݾ!ë~36:̼T7u|΂rU揭^K7WVgXp+}5NP^Ӟ /㨊7-IFa$/l^?3!xi~Pyh=x ] B"L ̔ Lc_x5䃆$-&/D)KKKfrkv̨wiz --U(]HZa8n˷Xŋgڿ`<#-iFi]&ܜ9w8]ͭ\c*d! % sG gq7H: ?_X`ppdٰs_ACˬ!rhu1հX 7>ӮY _g]o}."{"o{4.' IR}o3P:H옦 iy L\9C'{YmMk mJ@](@H Z#Y 5K&Vkk~MlN:[0^6mL"Q?ڂI'"~v~s,EbЧ(7IpՌ_ 2|hU! ("JfU8v+?/,T+[̩VAooCCM\GϭQ6XʶN[,Հ a@f_jOE-+)ֱoT5M՗m7-܋incHT L*iT0tEU`rEH e}z4"f6qh&( \8_0;3_o}<,˟ 9w 9_A;YB !LOPOF`6"ҡ.}n<{w`q };F3OC la`04lY?V.M͊SS]mi&B:׿%S!sbLR@ ,Ԛ/yz߀w鈪ZuX[{=%77ya7b6gaN*adf{LeoY_mEY<ڮmqcgI6٠an-ؓMa\).z"&3 ؜/X҄^^3}eUI{Dgi+hD؇͠}Z }p*,7y@1izÂ/䩆]ؤW؊s NQwkZe"`&Tv~R0u #"b+2IƢ=+Cʄ{Ǖ܉?,pc{:{Pm[)`ؕM1n mlaygĆOPսV14d/V{qpGB~h OR#Cyu`R2nfͤ]iԧޒV Sѕ'=wugDh7ռ&/ B }^I?ZkE`h ]J*\]Ld0>LwgIl%15ɮOڄZ+w R`:ayl?3Ӓx;^2ZbӁAbXJlR bwu3i;x妋9Y?VLӧq.y >tk<,&4&4ɋOOWL 7""!əGê{ʃlz,?nv1<x޹?(.Dx\)XFꅨYʚd%7⋋3tl`wp˕P־+U؛llܲ;0 $j.Z\ڏ*i WZ]Y)(5]|t73+~:67ܽ~yGDS*U eK'l& Mt&My1z2t#Ɔܼp`e׾_J]<{75k]+uN4V9ZӼz|W*}~nlG3^?]4a> pLj^.na ]wD"K|yJݯmN8rRWw4/J;Q:y K2eto ̡:N C}G<[NzhL/X߉FGMw6K!F`gy:"*%/4'1[&Գ3oF#43nJ ]h>-+| m Iji`IIcU4r[r axo»F?P鰦8[ $) @Puo7GI'+$0iG -a2;n_h xeşzL 踻 N]/x艢suQ5:(w :1%N&U1pƌ~s!JeVѥ!>d=QUtI4Hu8 z||@ETjK5wIKywLJ3vF 夯xolzzJ$,V˒Q7e8v╒,3*52Yd^?{g SgK#O`dLx*"C/#8 ŝER'6@-5r9oޝY?'=P& ~"&PSٛj*'+IbGJX-\ѫC+`U?Deb5X%iƜZdJoscRU٧GlS xm#vr>tiC92#E{},7NFY[N\LtnssζKW(%T9T* gv6B5 ohHe+qOՊ D5' Gm'je~i)@ 2hmz+ mʿ]{_} >nSʆN5+~Kת mMD/M(wtR'cjr9i$rȗ04HQlQϬ)#jZdjJ;}ݓ옄%tG\(2Tɂ#]D4#M$*6pkK3A̠O܂7L YD6 |嚙Bm¥^V84K0HS ԕmJ#[A-uEևZmR;[ǜ32FN6vX&+MYO&_y[ɼ܋y/Jd] .-ҎͿἠoÃCNGAԉeA"j`Ope'>tL9P勶vi-K8!̺uq(ʪO_06_Ӕ9%҃sMW%-mNr#XStE@F7ww)|R{mL}| {{rs#f|F-.  K^ŷhW78]R).w+C_p#\-VWq[`5 Mu \%0pvo qSH'^(rӁ@oճz[kv)cKm^&X#ޣn5 |?;v?;QFlD7я [M L.b#潃c~M'>;Q $jVa]n̚gMZ^Jܸ5sgި:ȵJ%YQ̹ [E߄ffK/Qs_vfD0 zlBچUvc8ZtZXTo265ȅQ0@%'.a[-0`(g!~GūcG3c~jPBtok':(}P[|!;9 䂛O^O:ȊT]Eeq8BM]#7Z.Ӯ nsew:R/HK q/=L_}j:9\ <~Î{2x H$ Ay1S%(=Ue0őr!qgf1,'KU zȭ>eH VnlE؋MB)%/'.6[\&YXhyRhd61JHIOg'{9s$Ln,/#dL=/Kb=O&`{41.] 5b#cxDuz x;YY@}vzFPd& uZvhqHwo!xx@wW?p xEE ={1n(ivyirkY[P"AqpWlb;[~sZ@t>1AqS -NB!&B28:7zU4N޼pFDyDMQ/vxd^6s NJK7*>Ϋ;CtSV]etۻ|Cן5Zu&Дp5\ʰYIV1wˁ*; IAv蜍̠_U `M/9~lCSF/4@rcZo7c&?V>Xc#)<ѵAG7 7 7 7 7 7 x /;k=Uo0֯+awt&\?o!/Zb]vUW(ube7(D$n[/0&$Ǘp0UCb$5r#>ވ7x#>ވS|dN,Ôrh0JB8إ%$cTp&y6 ߶^v^@=vIL*ؾΚ;cygS0]ϾMw]Lht^-4X;5LL|el:>E'| |z4NRtHNZ[hR[6k{k^~cmU, 3O5vDR[mM${ Dihtq xe+ 픗mKYnwT\C" _#}|RT,b_\O/ TRT28EeR񈈩ߢbuƽaSTkw$:c7A8n!cZn>Z;j#h .fnyD'r%|R{daG K|`)[p.Ѩ}Rj4ީyEc| 8 5}=ȡPWڮ]Fb{4MdRI-!Nbj`$T笳0ޝ+lF潞ϺN ɼP w66/G>J@seK<[t2 uAyׂ,M_da9``| d>ǕɵֈGLe*L$IX)U )*Ԕ;&,1UbmvM)~3MmQN?3_ڈMW,67k Fl5w^;Jy)\S6L 'g 89S|~j_~-Qy|l:ƃbq2ңgrBoE6Vzx{M]9#ֵbN2^=^4 ZHP;B5X_:;_V48L$sQ+7CIM#<9𺇪EL%~ h%jE1% v6LS,/vƀ=beeqxlԪ\ >^Ypf?EA1Pvk{% faٛ:G'_<|PAa]t!C"}F(q=r*08)<~зi+z|ndGzW[~WSrJAg%']Eܞ4B݄;_Bi}{->w0 TU@}+zbZl3w'刈w/>3Y6dfZQ2^f[mxoEcX„Jבrb48ň861zl豌WRB>jLnejOȊMԭߋY_XS0=ep48o0&gMhwc ,&p |6F|_n\h1ipdd .tR.i"%9W+glރ{Mv7/kAmpTحw)w,O4 ӽ^ (q{!t#N+擉UͮqG*mU:`tcR8(T$(oP€H 4Qz 2:QJP8OTC|حX)N[C>xwZo U{x*{1~ZY3 Awku Qb)nA-.7jVaw:G%);t paHcrEs'+k*MVt7@hg!ec7SVPd cWMBթZkSc{_ˉG!>X؜lC+'jQ{*79 d'4B'sS_ _8M+]1ѓaFwN-!L&@y AW@3/~ro~l>d[/h: pTCcV{E/ᔆF1lsg}NIIiD **ZĄ(hjo(j0)BTwκR<gM.90mf^%ڂ`'[ǦucIߗys0_ &oΒ3Us v Р(n{|L_-abcݵGkk[kNFW|F8BqC<-5Ez)m h:)firZ^aթЉ{4Jf :uVuqNڙ*)s%eLB";ѿy)ovHA>0Ann@z:tM3/g n>RX]Ij]ޓgG:g6Y^/(Jr71xF=E*D/ܜz3 (e Vt @LT>xrA.cHs+0\+#Yz`.dr{OL^C14"fԟG*%Ċ]76qr~NCctl'֟<1'}Ab VĖCѨ} wp%Ȯq)η\khl]߃#Z^* @XDIS0:wb4fb@@%1S_ )Eme˂PZ,0FM,akCMmktK.|Stun\͊?Q;c4^>%e~~lw4a ':M|d4#cNL!MiC򳯘 +P1Ylvf\j:@ZiCe' ?< 4CőfY53q 27,o[j<@9DЛ5sH)2JA6}a#xt;)<ucIKF|^\2~_iEuKRtm튕 ]ҳՙlUz&|ۺvw]+]coʬz[Lh}-#8piW \v.з4>9޵CTNˆZwh2/0>Z=O]n˱0._']x 2<pk5@h$vO((_:#NS,i _!44 $(cY&潞QMWyY;LtE%pRpUۣfw1ӟp1iXI&r9S'ҋLc0ke 9劫sɐ1 틍h8`6:i%vsgDvtPEWd,Q2FJ1;iYJTn EyNjng3RVfف*r ?2t_#syZV[a oϼ2-[t593M }6 [~X"˪ppL*8:8# 2-=Tu1ETzЮT& lyUQHەcmHE [\`kEH7_v:ںw`QKYA ԔZ'=p[/;e69ICf]OO j4F'.n933т'GbA[Ǿ 0'Ҙ$<$ ad ,63Mݓ[Õ9B0=ajj3SԼ|Ѧ:AB5>"gaTh8qv.n(~B>n4vİ83r4{3cCKnDtώc9J(&I$IB4agykiܑhh˱n'1r.3Sg8D&آHBx!GƤ"?[8'tE4!C@uKk`T&,Ȱ7PHx b,U:;jbUW >! +c %B7(1@IǮ#t;+%b7kPc@/S"1`v@0Vz]m#^<p 0-da"N`$ 8W]DkBrp o'“$ӠhT?sQ-P 5OjS&X R`؁f06C5 bkŸ[dDYԕ4XOt&@/^kwKPxU˹W⾉NjDq1nnt!Yȫ"k+2&u{ёPn9?ו>b ɩ v)V4763Arv1Ux-Bs<9l&5`| jU m1\ R"="X!o]*8?AbwUT"KV_z6!!f;YM yׂ?Fm }x6H#V~ݒ-rdl"ZܥqRweݦ!ӳm [PipE (pokoM":(mq|op' -c$.p>UͨpŎv5bvi^Қg+o, e^g?Pֹ}Mk>e&59 ):lv 5od/=}G% Px؛|zԦ1ժ\4ō'H| h޺"٢ A5kژW!sᴬ3lyV,qAV66G$rFzzܴ|4SU<1\#QvƌԀ}ԦV%]tTa#X4Swnf.+)%x} ͒C,QsB/&?rZ>},,g*FMp<"ӵ,Edֵ%~lhv]EkZle- aOư1}+Hyez[D[ O>LMSCAʺXmwSPOϜcM y9-gYFGKvJgFcT8r@ת.aI`,"},M` OC7F;?+JŢ,5.yZePbUdSՅvBr=ꪪlrRb#)fWD-r#I}kgY)cDŽo9vvVrq ϺgŐd _,| "u@TJ.ӒbvcζdALkJZ5&9ksӱlR9{qyNJq<G9&lxɫuThE4Rpٜ8:6I0X=@h6''H h#ZA3gsp`ښ`eLd֣|u^k렪;)} !'!CX1{=rMA%'%^mJI%>Uݿs½#{0tةp+zlC!S4O@К AP ,%m++8t@gV5&"D"A:˂^$|Fp" Yt'h.9?AWpGH" _r=:5nǀf&\`EG-݀pѫP_ݹ>:+C`qݴIT[SZzӔ>O NoOg亖RFՏIz :VbX cR/j#\<5nȗYIJwx`&Ǐ}$' ?Pm,YG;U)NM7;nw$Iq&y;v41|*IU%Ƅ4c*\uNʏWsr7v[/Xb'k 霞ֆ#$ T V=)kГ|#%/*~8l@e"5!TXʕI EȓDrE%{:Ң2C`hLe:`hB^4/*ӭ3A` l+abeCQƍ߿O q {n|mr@h=1 lSI8J#wW|ݍLwX hi.}Gy.0&TZ^K]SWr&mMڊYr#!EO$j#T/'0?MA\ V\q9xNb8GJ/WJS7-)#"ᮝ+Ǿ%z:|q6 uB&¿*©@`@\ ;|]]E^7stc nmp֩t ti!2r .EC2V o#ŜVP0?1Xօn9?Cpnrp986lh Q|ioα V'as^t9~qG2]Hv1ʓMUv„l8%vq'Sė*?m,∨٘2&EOvj3'NS@>KCNZ9(>=]}JB!z~n*{bY!%nJf %q[5 a4/a+EMx:=$)Rl9E21Xaa+颷~ lEg4G ޽0ழm/t]{V]>Kh@ )]]^@<@NmMh˩X:<*.[W7bw+ >Bqe>dRxMt-eןk &DiN :QImsqFZp!|]=Vk^kt0(ߐHr՗8ؾZ!8$Mkٞsscscpx@HBJ8 |޿|zؼGKr#,.Fh4DZ-72Ia5#cԶBPT,"4nINHXC+fE}BliclXе D>S UBe_Iat.˾MP ɺ X čiF_G5(kZD-[)t=jrmGǿG&+l4o ~@A1nk7xtGborG,.oytX^ o Xd݌Z#wz-Ѻyz` ׊dJVW*5\7tVfN)`E +tBjpNZa8ϗ3g;nA] JJEQ稅|h"41> 0R%qHmoBA!/hqhB6Ӣs@ !a`jQK"y_eG>4hvٔ\6$A]4++Œ6), u+KG4}Agir1aGLr t>U!-E9!G QH*?i)#N[|tDURi#_A[2OQlJϏ XW/^d!3=,FZ?^^F_ጕ #߮޿w_34e gWՉF6qˤV[Pͻ cj%i3iغL,n4;Jmۤ RUZS?%?H~ccgٱDW& 0Qz!3œq6kyK9ny/69ר.n3^O3vvQO,cD!x2%_rIW$*.ŅhT\T}'mJܺ+:VI\c)6?eZWB =XbFƁth]pHtʕզY!:ZA˛?5&6#]Ԥ%Q"vb h1oP-Omd`VE1fP; qjJް EZSεX3eS9 ne>`5r.d^۵:fɀ(ѨH/j»X)^*/N=~ uSݲ~T2ePOF~1᫖h5yc  hr`u^!ٗHe< Utkʜh6Rkdcm3+^eu.otQX+X 0E.Z/w64=5VFab t9wmOV7:`u;l]I5"Σ1A>V>aly츪3ɳ,@G0/'ŁkDz90=nXWKq)$'0^˘E֖%PZUue,WӀrLEIk(YHIIwJA064l+ĺ}'9$Gg]",">۠['MYcȸF`^["*'S+̊Z 8^:Ay@9W)[.)`"]1+謎vInθe[7Dt4-N-x*lF Ns5xoZ3^OZpF eF(_2=_3IRaֶۿM[NBC+KϤ"öh$ؔO\Χ7$aw,A2/H J&I\?VAyrϛgI |*kV|#jC( * m;$BNm]Ǜ|;;n AE+tL`/^S+7-q7m@ǧ}r/G-fՁwMljÝ>(e[6QsDCd9*xP3{NU=P֯?}B{߮l˚Eh th )uCEb,gٲ޽,"lk]3-qγÀî9%'ihh,iƅÔKh#ߑȋ4e Eْx,[Enzڭ kRE0hL;A Q;l' v?fgY&Vf8Vp(C9.|e0h;PTy^o>#^0je~^ma@:xiNa鲥*Yqzw4{vm#c[hCE;]E5h7׼3*ċA"j>j: De1'k5Jy5IhpĽșxau#+.f6f֭SZTgπ5iR!o`5Țda#Z%]wFo1hͪ*v&ݷc3ɚ*l*((8kHEv?A{}pН'';%PTުY/BBpZթNoQsMv"|9t.aen }c6+qx9:_V[-/oZk ܦqrֆaJVW]\:4 H.HMk`r6)Eoym(O0n]CݨN'f3( nPzY~֩blx6e8 չ(%gδ(< gidsE 3't&#1FBT@.YQl~GNKE (ژTkeʶ#]{>ɸ&@20&3Ù Ƚ-!~t:'טkI>Ȏ~1kÝpEƚY V0? Fr/ty&#r@vАFY99f.eUIptQQ@%GLhoto'CY%THgŔxԻ$I,g`Q|t) mcTlt(,hXRD\Oۢz@]f#HvL: >& &NB1"uiM&nDPX=P+_N*S}ZYÄzZMͼ<@\UuGұCl"1Fɵd-[6X#֫gQ *k3 8 ##.f?NT/()H0Ey.+-9 w 8-cĖ㴜3 ^ K견i:MHsSfgNhl2M.⩳oiIooHǼ Zz3K]֝'GėngI㪪f$gL5g]gGȟ: 1-EU PL-Lߔ(\qHa%y8%)3l)7plGA ݶ@`Lwy"zg g(ьB]Oz2  S{t,sQz"(]vb>+LL4i=4n +fh:F/@ٚuMwJ DI@pJSL."/8:#[+Ƀ[Z;D8g6n_X54?yjm$nkxiiYЈ}@0MNd0 +tʚrঈ Bz%o} = P ZBSP1/p i4Lb/:M "O b5Y')RP utCdTݥB- I3J )le ``+QڰqA`&s潂r#o&qXPΈ8Ť55 WQPrlW *N`x8chD&-xre(@CZ( M\)0 ϙ!OIAAz+{z͔e(vKaGՇrQ Tw"VHB NmeJV4' (יnFH-mKWjE6waD(5 ~ges䅗s5>WJQ+0G vmBQt F*gC.aJͪͻs.͆:AֆDvV ߆C MJgL톇"bmξa W$ܘh2!&vyw|a~5CO"6ϟ_]S[^[Y5}{|mh ` 'f}LnEqI0>np ``&Z'0[)Mp /5bx 1!-;&prp>},X~*.U-G9t޳ ݖ I2qxJ}Q)L{۱e?5BCj)gڄ LWF3"KݭFl#k볺 iayVyA#BoӥPs!7YiJ0=->F/֋>EFRE&♖. I)+ZU=)O",U1G/GA]E%hI}>BK "$ wӯd6xPMK<%S %,;}c3@޶o,nR+YxФYk\bP"œ!c 'qx,&>Nyv@x~QvH& V5Bs7Nӧŭ vu446ۙ dM~*"O4WpnSiRmW1~3RA>^oAϊN@ tϢjd5+2bR3cPK5#q`NP ;eT=SLj0{18d pkcEW:.=Rѯ4 k>tRR|+ |@+)] 9FNJ Jn 4R ctF&Fl2 h" |x{J&C.}7k:F R>AFJ/CYi3?gߧ23/Z3Gp C7hVJmBPQw<*9iڍ6D="ޏÅ]HhBL܎FYq7bgS#|ɇ~<얈/ tK;Z⩺Od,],zwT|ǯ|S|>(p;iX'㽠2($NEˋBE˩:Fu?/EwE=/h^//u9C`z?ɈAӁ{r}!ຊ ᣶(-N7}pC@(n!|#Fͧ%ZrbK"HC44gQ N1* ]G`7iR Dh#(EU[4 x0`kRbEa%ј8$Q G:[ӑf\hiU( tB\sʆñO}4wa((kmj.4 ' Eh%Z Uu [M+W.,UOq+lٚ"=<1k+ 7u' Ru4RK˂Kd^21&LJ H$4ݒ 5s.$yP_r'f<'Vӝ#~333333*>=hxlK7q2Hws>z]aUM`UaxU2=6`9F'Z-K((x_bu9{gQ hWF&8$6QpA:Ljŗ\/X7)9x J^.9(FYfL:D~tfnjcfRR2:moɕG0HoǸlQ 05ߌװv&W %^nދn&C8Rҥ&sIVQ*h" GVxa~pRarZRDW$n6SΛj~0lCY%#~уGe' \t@XdM%-o ȍBUv 76z9<_Yi9䋾bَݣ}#$ ?Tv2omolhR^.x i;9BCy[ax 2a\Psr+xw ЙG:%df2 =gt"?Cqghfdz"Nsl) 譂9Ų~qF*Шd(&T:Wb .Aą麛UVW"``He .0c neѷ D`'$P;qv\1ICq`.+ sbqԇN!:偄D~UJ Ś,!L8Bp,fL&1< #Дj!6~*4U|x9M 1 ]Q|YIF X< :-FĚWh9XS]Wk8UTiQbF$VM",}^$:Ǭ,)Mui%P ԉ`k6II K E[ N6l bu+bm^v[:X͜LԀۘLaJiY>6,żBzQXbڂVraAkܐ MpP 6891ŐT\g30C*pd앬f(8De>b ݧFcJl9_hH/@m˂!D U3[!v,`W=l#S@Fn i$fR7hHJ@sO*@`YI<ƞJsښ&CКc%t"@4E4U=H2Avu@u F>L7N <ݨo6Y|FP]HTxZ3F>7"V\OT9Qu n)Bc2Ij #AzXFMi S5*Q$"W#'z@H-+?AUUNPFl(\X&]&4:vPCg}f$ѓ;Z=~ !eimǛl+ s%:]`JSFށiFְd= 4[ ! λҒyô(ff`d3ܾpsaݨm '@sf[M5Uo}EIJfبKU~2cBu)ETK5eVƆT!8ZEsKXy;3T~e0FJ6&!4Z8HD±~f~+b : \݇g$9l dlA6J(Hi sZnDҦL605ݪ"@2EF#i|]a0Jx{9YXIh @N<-({pOܨmIBNX$`T4 a";{I^zM?p,2KVP14ځ٣`8`$,YKTǃ*DHB^m%v\ h1G8)O1\UUL9*1Sv(%f`OK۶dbI@R,7" /ɞ (԰ӍH$t桵ΑAQ{rx[EU9<=`C8hYBLRŰFu:ȸ"GMN<9c [~,h$cRܔZ#G'b]klZӣ /ҌRy8QD8ƔGr-Ȁg؋NzK.2Xa_t+]ȼ2E=0̢ Np+aqp,&Y>N[P-k36^a~2ݖiꝳk|~8.`*C245go%=oL# #E!fDB7}a3cx*(nd6RȋI Wf!7g_YYkUVoOqYR+~>=8^:jrAz,f:mfV\cOw{q,l՞'H]v]~-<$׼:nم \Nq9囻wcx՗г>hw?i{n>Ϫ=ϼK7yUO}3Ѽ5/|#g}q'#f9/k=dϪSv<{7Ɗ|sO9tOK~>oK?Gz~ѦՏg&C}U8'([Nٍ_m(鸫P~u[?{^'\wЅm|7-s{a䡋O$./} }M|-zԿl=/Qo~+豎u/Od;Ws6o`o=h[$~|^vrOɤ.G˞߳ws[ w>9ȥjg[Fpޛ 'ߝpkOoJ{Ǐ>w|tuYr}_cBm: ë7n͡k~rjD?fs;O}s_4kڵ>W;OvCo~=.uڿ>O⫗gk+V=w?/{/ǑC75~o}!pm{-.j kYMk79ٝ=Uz|xGCG/llY=+=vDw;컟c^cȪ^Q_=#㐱;GuEyK~\wݻrr%{Wee k] .x㺳bz~tFp~4yx?J>ޗ|M] \pOƻv>Ē>:𿟺s3w;OG>=;sZqRvG;|=+X;^}hvW?SسO/Oo/ֽ92}wo>^{7{z~uA3c}%'ܹWAU]^wک Makw\_ۻ}g}Ȇ{pk:7gzz׹g I^|͏,/8{ZS3XaOoxwŽN'}d'{pk?pQ?y6Hopչ{?~'W3O^短ycW=ǏحG\|Kb3jMv8ͽ^[8pBѷ8i;NVt~ՒI{yYSs{w|:7t?g&i>oKpD:k㬋icG}~7}OysŷNͯp]7mS|;.uӮ)?rƋXj]GWg|u 7uߧovVi=?}y ?*2JH%5ƾgW,B3"{%dK BBNRJ%K7Y[=yf=ss@4ǿ /< 򜓓nʫfpxHZ͵*ѧ fI.?Fh\Pو$_A9ӗhl {#4UP ԊDSc8#]U쩱4Hc|5x(3̋>T(I˞]['7Q6l̩Cj1ꕨ-߲-q駇5:2[ƾqEGUi }F'yuI9]:Y7I049ؚ|>NQ|:tLP]$:uJHR鸕j6/aJ8|ʮD7I6zy? w6u5{DkX0#gg?#H$Q aXɓdcN==q0Ld94C3&L7?ȧ%91W1Rj9?b@W̖TңTP~CcDSg;S>L{p3y^e^(bf' *IWp;a$sCn;VUeAWcld;"ΑaLJd=#>Tn'^/*j3[u'4ocQl}Śz:ꄎ #?HM tCwh55,3ʨTA9YHi6l;|LᏌëucMJ#ޝ2p9CW.TV 5&{}Ii/YNk޹chG̐c3'K*k;?Gu}Ռx?q~ӒWzh$帪 ~El#FЁnv!EaE=+<=79Ƨl1Kj\Zf~Wt+@;H-}nt{Aw;V]zje4luI=U6`DZ^G-l2<pu ;N*<]"u@ѓb/H_G߭8kO '/Hk3}zA,|a4tGŨX = P M+AE6?*B/F~#Ž %1'wA{P֘m$s6BDe_98U49(Nk^} fU>ǥ@TuʥhJכV05kE *mW-uzrm:6βqWfS_l5>qk|Z%3G?ypne()[( 5Vvm3lٳ(#tI܋ZvV|j<Յ%<;Γ;cX8ՙU&/ƚnJ;\;|q=o̊9RKB55z/PV]5pjX]ApGte`Ww7'eFP1B+3Rfbfܖt.rF.{F5&-Y[vV+֙ʩ((c7~t=vӰ"W:M)%>3ǣ2NUGq7}WXyR ҍ SǢ;Rsc1j+nސ/;ԫ}^]`#RM"_vOGK*jޒi;)z{GrgΘUD{>Fq*vNC JvKT&ϷB4/UVFբ[ue_Nڷo$(r1숾;릸)R&?IɆw6A.uZ:ndfar8TÅ7GM/ߔO)[y0O"JL['wTWֽT'44o +m>nI/=fߗ:G"?s!N}.6b9$ ^ݬ|6Pil{T- $ȫb.pX+|8+a@/T S/uANXަ8I_Yv  /+?.Eu_جެyu(SYbhHtY)rpˌE.TSj^ AՈhUV:3w5yuq LHx 2Vv)QP5-uYF֟򭌁|pVwnHpC;64aMW1$9;hjeDIˈ4{f%>'r%ZJ~H3OTω±<"c =/zx !*OYEC)&PG}]Rm h˷y>ObͿs~W! {Oq_9/.c0(WҾ=g|Tv& nxbJB2\o~ը(9K׻37 Ӳ߇Ufcx¢M;YZ>)ϼXjv-bg%i*B芨Ħ{Oψ=EԸ[f)pݺ6)Ke 'c#;Ia7Dɍ\Se7G=ؽio3EuuzbbF# edܿzpI.؏CFK\W6-}!Ia,^sĶ(Xs's: ,b*ߟ(w&);r0zMvjk­pD/CQʃU/WQh]/JrWaNSի%7L`Dݖ.iGS7u>JOB5CO_#T67Liq qNm?My&&a1O7 M)ٚw$)ҼUGA_cq>_]%Tѻ;E -ʲ^tDvc' ̭)9l=uL;osl 3>`H]%RbMUij)I;pݸ&%yyOa&+{iPTį(qQ}.Yxo@w=O7 L%B^7y˥n?Lp'c6 l!QhFYx=<7gr,OèU{*E;҇Nt>!v?HwgW1/nG]V>qst}nQ$2; hBH+[-ɩ̃)Tx]P@AѰӵO7΋yfn>aMP6gf[PhGqE9\^A]U֔uܳwΚ8^dкSMZx˅,6~c2i]"l.f0Sf+RrN,4oqS57 2Tvb%d^]IN&!}I1#GW?_W(zIANœsCB2L*[:)oڒ_t,?"|LJutX%}a4ס<vоFS;`#p+oA/[4MWF_^Fã-匩j10fo6 nI/fdf2f;.6͆C{W(ǹ#?U{bdtKK-Bjǻvlf}-Ӈ;oy8y q$µ46~,U~t'Uuu]A(S䝁$_ڳf'ÆA*8-pNys94Ȗ˳=sR~{{Xg.:k:Ag*(HnAצ* qh4^ )Ҡ\UC\p2Y5q'v!w37ϊ̬h$yoEh7vή]Oϗ_ g{w蓥cyW/#yY|4R~'t|,UY\3gft$D~1Ŭ!J^,g9s69m!_mO' m.i#xHŚlDfd\$j1pPu(BEKgn#+]3&و*8a7.4`J˳ܘ/qbB$]qv0EGk$ٙ:ejo~|<+Ỏp|H^.I~^彭pY+;$v9u+B^߇FF>)6k9\7̯UwOCq{!pxx{XwyswA.U֋x4HY.z~h>p&M\c]_Ѹ"YDAEW_4+N0R%%=H\ -x:jA+YRGväF[ xl9Iџ&\aێM9r@KƾZcry[ [Om~aڗƔmR}vOv^dSd%CpKt 1_ Tc *wQ=- P0ð AoL7-iR=85ӭ-(%b츗A&jOϔA!w_&*L+M Sא\"3dzSfI\ui}7C2fܓqkV"R6N`v-lnXr)5{e)e距llTL>לv3y&qU64}6<wN]MZ/4HH(uTY7%rYqpndȶ/k}hrnxj=dgoS-!nF`r}OOwEBxP~Cӿ0oUIG_(18W@<0{:.+hzMiTsnˠp/BC*.64yxY讑|'cFvRS`1$1@K;  rvRb#}s'=vp;MncIxT]l37ҽk*Ja\na4P+B\K-6"`P1|dncGx7K]w[LZegY~R8xIy^cD z.cOUOZISMzKU-P,Dxui7&% W󻨜c^]:\|I rb'.wYn.VpٔfirgI RS+~bU-e`i;Ҭ/ֆ(*pfgo^}'4S__e K" nq7lFfR:y$fֵ':\%Fw^yeZrlˋy4=CMP't+є=7e>+C|@E'̀{d{zs+㣏 :6$J$^++ſ'JW 5ċşzi t3CDt u\¦2ݟxd6ZA+'3a I7qt/0 :WAvP!XCM=2߉;w]SS7zN%;K7#^2A-n8T}j|ީZa\8lȴ5Ha`Q*|G$7D{)lV:xOd.:o٨cVq'~~>DǷS F7Ryb2pjVS>ܨ9jo%U`S}إ⻶4~ j;qK;M3]2ӥzW<996Mݧ|k<(7ZbeqBG0û=*v>?v^@'SkSFzm0Ț 6<=]>j6Έ+ŗ͕ZjPyltU=[^3ks,A;Xe:j9㧦uC#)as#Ta b)V;2k=!2b}JIVU*SU֫ ;$a3!_] -v@ov(!gʨ@{CcQ|(Ḯ`hsd0G$bK5,wwDKtw3|*Yޤۼ]jyq[ο4ʮv* , @WRhJ3Q}'-)͠+ߒTmadA:1I9~]R;K.o׹'#x3j竡(5uN͗_|=9sB=h 6Tbå{zF)SIWu/޾Fq( n¿doǎ+\USɿSRHIEnrqԷ@%Ξ:d8Igj8\ƁIuv]n6ХKչվ)uC[tۮ }71;WF=ӀGz̉bs1VA)l:/>?QUHz` G~9rq5Z?5Q׵=ݦg3n?֟f8yQZLT-̾+gT#hy|3RPݵS§ͣ 3aqA7-Lg}yWU1ׁ a$DHt}cWdu60ƒњP}f4l5Toe'QzI97'c8ng4=]Em0$hIx_~6NB>PJ; q jP77:z8s{{?O[,Yg#Wf02 {9o[|hʗGsQRiv;Z[͓0B#"61@Wmǝq-VKݬ.Z-T3>t;3xVHG߇FGs\6~p$ZDjU4k{LAGS#9Bo?Pms  m.Hw8b|ݩEMT^f[HyWE&f],$ lqvsC4LU!+ؐX3A4(S m58u$ 'eѐSC({ tf(Adѿ1$ϑ#(rz9zDVGh=|=|+.g! @ 1ҥUM,35mFW#桳LmVrW B P^U$" 3*ګ?/ULpg P[cHA[ A MIl)!BAȪ!^5ѕ4$  =iCO!lr8;0/",V$) n  x>`A~%Y$.O`^Q//0Q-',Ŀ"MwE?lE>^!ihZ+ ]Yw-",DxV)O`e*)ϫ'WC"+y/B+fYѲqe^U`%]U r`C6)rDTħZ.aKB)F L H"? /]p}?~[%п_h 4a@yx0Bky$Eh, 4I|j-Ա90 տU$;(KuXv|?v:xS2 BxgIZ1Ζ8W @W}bs_-Dl]L]:7· 4>",( w0ِ̰6R|) ."@"(7ݏ- l: 3G1㾏n9 Ka\ |nGF\ژEb-Mxnn l}@Ԇ],d``֡غ-/m8@a dp8fLw!8o X짅 &H0h!q PًN>dwXO*[8_5r,Vk?x8P]|1-AqxES9Ӷǡd'vXeεT GXƠNPkq@]+]7gf||W3SsN̈́sNr#}%aQEwVV7F-8+ۣ#R sD/N ~#Ѕ. 0x \4A\`hkF/j+7&‰_A+J,?j !Ew_UEdF&XG?Nn1r:%uþ /!ے${'wNyQv~>>Ar7>877ZFV# r.,$0 Ayxy`nnIb^ZTM al~9uYm}އ(˂!]~YDN[z ᅂѳ7A j FvA8YA5!@Q0-D/[( Ft5@SEC/ܦ`l\tz#j5AaZǭ 3[ٟ*`ĿT ;K0m ?AA(+ Cp^Y$ted/@ fs$Ȏa.Ic?g DB8y?(7pޚ'0Q>Pz;k(]@Y C0lAeBHo:notR$0d r; n)h%SIq3'Ix $*4#?Vɺ얂QrY*,d]; M)U2c\5y15FI̿U6 /ZZpk8Ao Etva;&#>8BB,bK [+JWzJq$U)ߢG܌@n$AV1 ,n# &4-@ tH׭-Sץ-ƞՌS.bq6{~TŠ?SV\.Fj$ ʠz/ [&Jh0[U lm2D\4˩nR%7ϔ`SJnzܠ(+ܠܿ8P#&pcV|I'/ӊV<`oZ堟+˖029m1>-*? ?ӷ/_TWRDe'Pal]JS"PO)A_^N^P⃗qBQ^gA`)A-pJ9a& zV#H|e4h-L@'kg~›f;0=XB]!藆 @c_n _qKgC'NpVLdx&NB:,֠cm\DMoC<~MA@a B`VSbh4]c1874Y@+:`sxFsp ~5lU@UY8{pڢ0Zp+ ymw!lEG`<$0f1 Vk c»%¶wFÊ+@b'63ִ̀/6%wiMFlp xEh5z,r@"Et97K1?3-9XbCS@ԇJgZzo n/AzFE < xZ\G/,@H#/ V:@ˍo17U؟73/Zc~4L~jZy[u\;mz?߿zc _4 ӬFbͳMݪY7/b c`V׭ɫVvzF&Z|kV5J/ZZ- BmA4a @85S8{Xρ0seB^݄WLC_lqu?7i^]uإg6vghZ[oZa_z,`LS!X3ie!B\Wǂn.xHLı8Iu*_ n `u]u]w!E-J`;8/,qL}S2nO ]6F۲'g}?BB+a7R94D ^%Uo w6)Clql܆xjٽK a?($h|șr>GQ$m1z k׬ߝeWVH}?\?o^;A?fIP\;2ssd[x|dUNBn젼G1yyǻclVj Vs^eaY׹Lx oHIY>97"zP1`wE5yhoss"3oԓc,_Wpt^R*I2'3 %sPSQY$:&Mǹv.ad+[> x@=f"7}^T[+hric5$}5Zا*jdJZ)8|Df¨չ>qpo-w^üw"zza_-LynR7*D7.)[YS2*G;|؄H*y2T%q84yi Kd~COu<ԉz#/lYQxRuE4X~'ǧ ^=4Tsy7Or q6e' tk@`Hf!"+^+5Mgl6N_"_nl:YZX]P .%oc6 ]&K[N)D o6ɽ`rI^њ(rgS>U_=}="J:i 1J(!k%4> rؘv?APZ II~i3 '&>7;y&?H֋GLyٔ;a6}>/ϮARD.%ml :}-!%-JJ()"%,I~Y!}*=|>{~+^9w;{[5%khrdD9$ȣFOzW%G$ҥ.9~#˨0GcUԍxڳQkC #N<(6]>uS Vk>1W&\uIH5,\͝\y Bۃ yM_{2CG\RcVqury*u,0}7q].Qjm-Z3Rs WB\,s]· o9s,i1FܫҠAIM7ncngW:~~G2k1+}?bnt/ f򥕖h _O80|jIW= h=rZN8P?~ J-f~5S=)M.Tp+[ 9X_t:V&7W,w~E}Ph.L,XcWě+r˽CEo j3k|{>dC;LhSfRޝh$mF$e\hiSLK>=xq=f! 7rhQ.5xKN.zTUg_Uk>ҕBnK01Z_3?-xucq¤P!2j0WiipqR\@Շb0a~{dG{Zv#!fWA%׀RsQVCy]Oߒz./ݦ<Ɉ#wA.CAZ ,+14E6jm!ݮ+ٵ.-M[{N."M]%~|ζ*zg YmYiA'Mjw]_jc6oYv06:e#LA 'aܕ3UuнwzL̯Vq}R?Jǀ:~','+T^EW4f\ Ty<`(ZQ9Z/BTǫS#?5(g|LQ "2保b,G?>w3VHY'RhSq}Q#_.,.*?U:Qŗ&=!b]0hw=5Ms(s3J@FVyS'0竷\s^7v]Ft&ϝGaL*`?X=ډu'Uүy ̙rmCk)VקwEGꏊ_Uh*gz,Fzwelj+UBEOi:[h+ں[o ~wJ2F_}ȭ^_ncs`MF>JEOn(s9̳>r![ot/PG)MtܨIQ;!G6eSy/~+ѱ(YF{Vɾη]rmMtSoX_Ȗ-In-OKhT%|5xgnze86ENjrh2/aȪQ۪0?<=dU·ЩOçB[{D[rd0ˬB}Q\x =Ea|lH M\uxN](i"Dд2%,*ǭUQbw{yӱG{J.gK$?[,R_%$sǝʽM9X*lZ!`ʘ& /*cL/2;b-3>MOgz4*,5o-Lj,=0lfͧB>ZT2b6eYpDoVŊt+2~b ![|vbk ra:BlKcgn.=-(x\{z:mυ,j]vnJ7rkŭTA@Гz c'|alA`pAk%ժhoYCc&TiMJΆ+uK%UNY߹VfgtiJ1JK_ml4_]HWpq=5x:}cǬ$?)lZ+`Q^Խ:dGO6E`[?F~~LRK.ס ,Qtv8HnZ3ɐ,~hD{JOOMK-fXdkEwzlYgYA汮{EO},ArTU }ս"aW8Ju0R3$O0mj㗢 lEu{|{ϓwG\Wp}:Ļ<^b|?!%fݻk'ޝ57I;L9KjnQ' hVqS ;ue7 4 f1I<j WW&\#_e9fjXrGbq}\n`-hJٿN=lekZY y(y3+7zSW}N b ڞҼ(uu5FW.9k}߱5x%/+wEiQֿZFƦZq\wOй<[-[l]5Vxn]ڡ!1B'åk^̯c?*pnfحca=EJQ}%6V$R~2 2?FO󧔩=sQ%h?IznI)AjĬҿsTmY D?&,95OPYjVCalFJHHIA22$Ӿ"lYYB)G*,! K*W 'A&,#+GvdyRɲieeH%deȤe%%GI,K* l&ER_Y2e)Y "C2ɤAmT+?X@y[JZ3vb0e9 9$Oc,Po&7YZy?G#d "W%34# (9آToD7,n:yd [1@2?? &&6qGb 9WMlJLxoUmt@96Anh; OSEP耿٠ܬ+B69z:z:9A@5 ކ$Y\"a+UF "P$2%eJQ,S %JN^p qsC{6EDMBl<=! ƇbOMSLHy`B:0#,iv8P=] r-~/,k,4#ƍXW'JTSx3]g.ނz!-&FC@/oNx_ 76ޘ- D@h>}m 1L!A/ g # g6~h\O'2Q)`pO2T(LTWp-v6qz}tB -82 v'B؄XD> {;FN!AlbǴ&*cxt͜=rxB2g5h\"xp&R6 d>)lYEDC44O&.6H; @!L= '(E܇BGඁsI6oւ#2B?;YBio):J HwCmGnnx&#au(ah'ׄ*. v5S HJ4 ,π HZG[ W=P a1WG`$0Gé+怭5(-8d:y (kiH „ǠPz`[&8Da݂f`Ý=PMf (c .66S..bvS![$p|R'W.%h(-SG@<\/x"`us}=A{BQ3̆5\ h] Np Fk{?n:}'|cHN Th,W"\?n]ֆ&l԰+o05T vc=Th # VB?7HI`%븀?4F:@;ep`EX7h_pW)W$nK v{Aupyic5"f-c NТ %B{8ugp=[Ts Vrb0 1 tei=,~ЮC85ۢ) >N0U Ю1-K ,( i`KJ`h2128{(Df)@dUK" Ħ QY|/a.>ڞyB@h/2uAVJf[AaKF=F4lR(]yڡ(\,WHm@toxC8-\y+ =o EAv0gŠſZ'B/#+GOTjp~{>EUS0Mm< Е9{@jt4~QqR& -&Lw..ɀOHA1M(N4+BCaJ8%xgpt "zP{'j%#({o~|zhQHw2?c) ň2ak6@ pS6&MCG AIsn#bmu0-!0;ru-EmAS\x|O䃝?$/g-T"j n y\}츤$c[l HM?HNP @Hc&l<~* N"("`[Hb- 0+ډHxh R`$%XHfT+o=R==cAt~H_BaíDj3:%fuA@lDTf^-~o}~P0>*a{U֟ LSN[sʋ p'AW]gBsa,Y;؏W rOϺO,Y&ˤkI`t>ivʹfbuԺGXM[ZK']FH$L8ĕ$D9?vvjzHmmҿ**xfFΠ4Ly Igk=_1h HO)C 54ܤjgs/Ga|R(1v+H6p:O9J1\3"K\ِ6#}FkΩC8!,Uϑ[i+e6cc ٹ<3#k[yCkDx5WD@ܹ6Ŭh]t.0g.b.Dt.P.)Xq9Piw>0i< zf6Nold@20HH#b  2LF gԅ>~O;p_( a}6Zy9 GxZ`(h9 ?C" 9 WjnVp5AW D*zW*o~u7;tjn#+@ FQ|n="vaAO$Ͽg#P"FN H&'N WnqMl#f=My+EX:@sR|:t|}c/w͌|G̈|G+S fB?A#fFS؁i_>ƾÞi z|?綨 l-q]GP# A4Wac/U,0~0glZ> OB#3i(69QRLoff`'5L0#! |202 >1j>1*ÔX:)7N)0*Isof`N (091'L̉il9M%47)Q0(9>G\!Ϳg'q p$gQ&c`FCaMAY)@gsxѩM# `" Zfb(a@lןQ8xrgU b& \ OUϳU38vl"`a,pj%q,MV̕; $%eH?Rr[~g6XSM|!?M:cֶiZbO Ѵ55=O=7psY|!+SD4MhZ:Wؖ hmIS+?9}ݩ-X'1cU]U_MZ&R}} ,u<󖎪n;l$DPQi%oWrǪz1NwBi7kZ%6aR) ]Nz:2Pmn"j cH6-}|}kU{JDHonKh0jm\B@}qZVcU\ M_w >Rjkzհ}Rݞ1}u\҉iDl5lvpB%ण8 CA7o~}Tn8)m͒GLO4>WUjr(AS֮5G'[&ōN6ne:<\bbPdCe̹AѺ+rkz=IsoF1ONlNQZdSMMAdј3\t3orҠh/ܶyg+k0̪bcz~q/AV?:5+I6/2p[I}|+!1ߘ֠@l TI#i,c[ex4dnrI|ڽtwYQD}6+D]Mr&'VK|~+:V- b9?|׵ޔβ7mr[6{\dHp|]o ƨW 9S?p9w!C>;hRrv(2]jxaR-+2ʧuݰw=2TPLxzl,qoT Hm+W%ԬO,j_ֵLͻ`tMN:6xx?[O{0ہt Ҩ?1+iy5뜮bbhup=]6:3K_v>&ϫ7uXݷ;/_ä\L;U|VzVN =`YujyNWBsUDCLyܬE{5kXuu^W _-2JъfsZaPY=7F/9*H,? 'R m{jq~MHmΔLbZPǘ#"R0d=v^&w.."4T}ln˜sAj뾮m|1kAP  .DSW|bi+hD%{Vh0T,>=mo%c,w`xoKjf.,ѫu)uvܯ0w*Z<7}Nۚ\0%oP:^['4YO/k;~ѕL+Iw ky kG[K9P ߶EcڶtVF~&yS5vS+NՉa; Xm),_zRSEAVÉ>moH/#Ӻ /6cB;>Mx7 E{VlQ,m]QrH#L;hw?l~ ng럴zrT!E///Bvdҋz V珻M۽:nmhT >/Y9&j嬔LX!ㆼu8kfAe:3/.tj0;ZX+yYra RK\Ѝ8X[lɅftWaDy![d^as@.;Sb1 wuƭh,eFD$.X~-HEX],DmQ-ln͈qhgblSWI(Ӟ6{ǏmA/Qv'qy}xTeƓjOZ Y1%? o%¢&(0KrkhYBQ bܨW2sbV{hF$B݋ e":ʒ:nًd ^#m^L'Փҍ^Y4Dٲ`Z!%y$,-YE\#AweH(W{wg7grҵ$QUCqjZR5fWfL KS6Y'=faڌ}Xl.BZØq>,:@ɳ 5i[=>\L<ܟΠGu֙KvqK>#Oa|֣UKŘ W,)|7%u3qO}*]PZp~Rgkҫ.yyepa;\QA]ݙfeӈGk۬KTK<1,u`[x}:uGke:KCC ~s{>_h(`wyP]>Kt 75ۃȾBv.oon)ƈ'Xd~&ӾgRHѷ7^:NrMh,*WI%, q}:5qU%?AVߛ5 Oq^p߽vyqcE:Žg*M"0 tjEqq},A8@a` azXo7X1?`s.Huj>=ԃzNTdl96LˢROnߟMkZCvRI.-(,E_0۹)»9>JdM !qJN]UJg:9t)A1wyhK+}%g̍iKǫ۫6Vh [N5lZ}C~pc +W&j;G 9Oe< -UYq@tDuBtT{KhO}Z ΙyJTJ Gߐ{fRuՁ D#偂 6k? ZRxFe迯ȝCBg V (4p7dzQp(KD95F³,+]`6gX A#(*vҕ=4L q$ VxNWn2þ*z&Bύy/UFt/mJ:ĀNgI{gݤ'ߏiL $+6mՑc~ќ(5z!jF۫厏Vs+0&.KU9 R#: qizp9gCX/sh+ьll|KGnDU|:|O1$2a*+U5kIaydT8T>1ǭ{D̈́hm'9zUͤK5;7v^̰_ WPB$P]^t ">sЃ^eBx=ƽw=;p77yYŢeH"=IRYQ6ܗncܪq 9Rt,cxZc28`$UjfըW!4P]uQs8anb>Թ{r|+'oaeibDdD IhH^)崆v-53 w1T"EC\=e*U3_X*`xNV)ǐB{0{D$M..B̩w}Ɇ%Ά=~ &ql|V"ixzzx88܎keOrQ-)lb~3h^=˅imXy[SR,K bDXʵmoI:YR:ELQ*thQ&tlq6eMտRoI2̭v9qLs&f ⊛K-S}C _zŖN79.}4Cgxz]B=!xx#N4/Hl} pMznh%:k%ޞYj%o$Xi:f:]$&#Kc%>mY:XByaeuKHVR[pȵAj?ѐ^Wws3"sA%:z!3g'bF:(^7 F;Ez[J"!f96xSlX1G[ᨨ+#I\K*BJkm3y=֥٩ҝ_lE$]K)1^Aw}]i,q:aBk>Gf{qoOQDPX]^ǬCv xa^LNo#nAW!t$pVV[!jFػOě|@5c y!փA>!yܙIJ))o-9yLlE, OK?zuXv& aacCF=>4pr>Cu{RhAd/ -8v !*2 LE)>SXU|Ǡc (8NjHJ2PYȓQ]Hh0KI$!c{qD&v%F9fC Z"eM4Nt&Wc2^]:lDh\NBDKL1 iӼ6Cg!P&BZ5x^Z8%rxmswÎUx[fOXPja[1>NaGWYJ/0YV\,?/Qw|~yxjwd^URJvğKLMh h̉>>[uhx JyǕtBJ;=<% j@اZybټF 9qSش$/Q1޲yvx%㫽[, =òAuUB(R|Y&Pfa15adB0ѽްY\ }.97sʗzT>{2D:p. C# -/P6'N{.gKIҧqa{=r܇EtvYRdVZVTS(tUyr7; d5`'$ Wu#)/_xr% lJ*tD<'8FO^ԌV՞Bk^'OgqTI]# M 1&W,zm2TȥVyjGq>GFQdS].Q^[59ߡxq#OVoJwMʢ*l1̭UG:Y&+bf^ }4R:6gRНR>uwsއ_ *MI'n8fXG~JaG9F'V+TcX榲US%GdTXcne0~]pػ0nm_* &ˏ\\|]F}|A77W{vqlAKy A[<[mz-(ms :Ϸ CM@[r.6p6xm6鲍}<[l'5xA o;Gx_p $w&7ɀu& 'h!q r6xvƶg4}C,;#26T?}۬rƯnCc3V0c׍TG 30|('ma 1@&l![/?#l^-<Ԧ6oZ !8K>"4ȷW(lP!kQ羭cE7fA۠#'`Tm,xaB!#m)Ā h;_]\t1B\e-?bUb 3,He6V 0b(2 "v<Ѝ@(!O }[r CV٘q06 Ɔ{ %b0HPמdp>qTWrȕIj|JlmHd(`g3yyFxgn] ^xu' vr)C8c5G:z/Vr=pMd9 Pˇ>n/bZ]9 DjFtE25v8F~ +_xŴ \À`u FA^m۰zk k "dc.*Kf|-Fzl]e},d} <Y 0lYq- 3I`'oxم &IO("7D f}bu|C8 hI&6ε8w7uվw|GL6~s#(@\" lXABKwġdȦѪ & ۸䬮0 {|l[T6Y>6BZĴ *ڢį֥]7uCۘj"B4 ZYuu; NَHv'վ|z2~Jxom~raՍH:Ƕaz]E&p3|OzDݨZW#AzUjd#Bjl]F/#/b?n>>Mxv9/F)y.w#~ᣳu/_"m@~|'"Ri ER'7Niiny6 ܹ[_&hⷺ_/29 $ה/m/6+_ʗM,$0J`-T fϯka?7 {(JxZ(c,u5^!ОU_ְ\\vO-c/5i8(fd-pMт$f(:ˁeno\PW+ GSsPim2/Ci σ$Z;sYt~=N@Gci"k%3 7d +4 \|phǾI HvNyrbv,muu:_\K7<$Еk3~s^_qV_r( 8-,RfefIksu5nwɕs8:eIGIE4KCimDRM⒨(2'GFh{~`9}@Yvw:eΑMW8~f/bTwsn ɪw^BNy0q|~o`E[s)=142w֕.wK{2 ur IXB|h"$Kqg{f..NN Ld\=2;Arݓ 3B5zϮMڛe^ӜRWfgO)c "nO>sNOhmkDrs:g*`G/l9}M93_ЮS2|tI9B W/ra/cI9p'Vk#{I@;%;ע_CzbD:.zvɅQFvM9Ws&R'$:4cYW]kJlGL/`bn~_nXuM\}A+#ONU%X? OcgzBNKaoVS],l^%LB I#ΪSt[@fş<kSiYqỗȶ䲍l"bpFL XE#%%$x4Z5Yޗod#B(ӑP4Ӿ,--TFM5L$K"[C"!KƒEP(["ʖ-[{͙FG9}]WtpnË$nY8g-놏Bejݼ_drnm<ϣ4ͫH[r+ZX!Z97&]ɕ}œvKnGѯ4%)?6~~/pBWeg:)P_yfek<<䚯c<*6P{}A.Gnf55*S7[x 3{]_YsN}`[._!3eF+^љ<*ۃr-3\RuOk6n۔䎫Q8x^QW}SP11d:g*}<(qO[}My٧4{Ƽ\0HYWz:rȁ~.˟]&_qꩮ A-Lpth:Wk2Kڐ5gQ';+/r9?FxsҦ_~7{Gևo^>Dx~/H\q}ޘjoJ.iZwpPƈ΋'[|ЊSZi;?%\{t#brcR3|=2C$EAvѽMउ?E(hwɔW,[+'$i]8u#o~65gإ^m$k\2sקgը`:Ɯi1{-ܺ-wZ"Wl8h׹)Pvsr2wxz$}l#vyrR= +9W&m(2;ʐH7z6yB GOow[}G/)^o^v]uȐZ$|zq&|˂]Uk)LŇY_NV f ݼ*v#/%WçtEaǽa #<'?zL[<>[ԮtйyJ@о#z=ޭ1 y]Yafc77rapKo_Pxzt8!2:{y%ЫnYv$ޯfڵ;sos!S>Dil{kۚ6adcwS|nQ%݇^^ ZtjҲG^2e.rYY_Hv^OSbIF% 8Mj >5ÿY{Fn& 5LKO]IG&h5BSwk9(qwXK 1욛cg$݀QI[+Ю-e}ϧ\Z%YZfҿxó K1z|bxr/-5o3NPsZJ@s91(hZE>zjɺִw_49_[ޫ7UoLݪ#Ȕe45.o/lmk›MKSZ})fCJ}] ž_晦=l%;lL̊rR.l]Oo֦5O\F3Sڔ8vUuë.ZUi졇 K,i6&˪3;TW枝;@>z϶;RߒhW`[nbKթoʖ9vOevo*&f?q{fs=^4'Lj_||PMt{7[*񻙱r6%#`#Ch{6X龬JyG:0gcձ6#Myi^nl lY?:8iuJ{Wn Owa>Yfs^h΅NzZǣ~~lz꒚* G^8F>sZM'dR%eqM2oئtϩӔYNuk۝p<ȝy%bn]kqoaN'Gl6Us] gORcO.z3؞i?i>֥{BT_o2;Ys2*,RMUП;rR> g|[J}_=:;_z-I^[u̕07\ۖlcyUV 7npEmdZ&Df ZY{ؕFvOQĝepg-Co,핷d߯NaΜؽ;4nC0tӠ5=6 &v\R-Q0ZKԲ揁Zg~kM sqޓ.6SOiٙ#.0\N_qlT՚gY-VU)3V%W:l7xy֌+<#<z!_s7&퍸Odwvbۢ;(`ch -'N$L^v( ܎U[sG:]k2e94EΊo4-=dץ,8m-1ZK?mXOP?#B kh\ }_Dʨ+D2BXR$H%( qpe Kk `s) ~1z\'@.88aGhKWd{<%NPT?pY,6e ƀP2BB$ L X)G#AnCA2 bfЂs?IID*kBE,`SCvh|$G~.e0 ȇKλx N{I(>j9A8ƄÆ&@Iv!NNf.?4a I@ÇkC cx`9`bcp`'#Byx>Q8BH鋝(V;F$8a ~&U Ũ<z-gKsBsGoNޓd6% (:MDĠ1" cLeN#^vP'kU!" fdBZt2p4d = QO~ӱ~v?lO `~ S(T2y0 XS@Hs yc /b!L ڤMQzh&z &ކ8{nF%}FbnPGRc,*)4 &f IlQ00,rW$.< );X EÈ,P<|@tP_bri TT,^tv  n*PGKW,ĀA| ;Qh)'kėQC\K}8Es'ʼn4ut;Bp?tU =ёfcHBr< :k$$ib8A|&J",5 iA*Vv U3mÃT3Gw]v HH:p'o" 6{GF9Ҙ\.o%:F@ a=B+...&b~wp)Po;A$oEQwE32 ς:R.;LbcJv*(¯rgr#ya6iFEk 65d5dck5c2+%ARUW,9hGw;(*\A8#e!Uu~T]t%R}"R >#\Y$ HA'w4yq'R3d Ae%~lɥC}FPf n&fհTM"PyŖ@e^X6^(,|76 3lHšS<1XPṔ\ )-?!T(aSfa`n(;$\0r,,bbsTG%oh7&ڇ̙z%jgx,̒0xLmq_(4H 72}a{8ll&s{&„9'2& #m A) ]R&F2 LsJ 2hoH=4$⸤@̄R * W,jV.:zod 삌5RDJM~~ "Db^Q\j.aR3D}M1saV,:mIt^DFF}Ni9jzNKd.^]x W e!fTwzPoKlqhD A=V 0 (Ԓ5LÔ0h1ǖ3}$qA q(!#k|ӴBWt. 5F ߌEG.ų"E B1Ʋڔ0d]75 7> pAG^Kj,6О[?0(eca.B6lNJbdA7sxB 843 BV:V|! GNhh^h_l@hx)x?aa 6_&1۩d| -Mc)Lb@5RA58 6$kgwB/i D"W/j.$[$`,q2{貕J9W!xHynI/r(!K>CKȤK(čG<ßAV>{4&$=UTn"%o9\F#p ڠyZёd ^1`N l]hʧ~/ [ӣyl%<JX1D-R6݀$d0-25%6M2&77D J1rSBJAMX `^to z`WHa1P .FF3cF . aaMuq[W,# C}]] ]5"WL >L 3li0`2Di[`ilHJ3!&Z)- eNވ~$W` R>4ML`3w7M6@O?BXmfC +f6S&fvȭo@^D!ҍP2b Y6钜|H*Kz#"_AiOAdp E`hhZq* ZQ&Xbo_avgWE8RC^yRZ&Q?N'ʲ3";9}ذ#wWW۝`e$T@'>S-\Fm%$*v`@j̺ .06=H :S{&rg\56X3`nV*+TX\@S$-l F͉Y ;-|d`7xBx.6#./ u0 g#TL(ES$AFRG3eT0 #iN'VMG@(` ^4i䅐dB'/w!#._HPPbV6B#%Qh//F跳_De{7LP$ŎN#R^bPnA/kGtWww__WQ_0 F?'Qzt}]L⨩ c"  50~gk7Ĕރt+{kX3ZGsst z2e𰟎:N1>qsAS u8`ʗ dN0.U \  v[&:7D\CKGs! kp"Iߟ ^N<^M,q' ( z47O3\i]ՅA$ uES(.*t_N/b%xs|N0zi75 ՂZBt0?韧G "wYgX|E@JkwYz czRBS?%˓ron8!VRE+AI=qC&QcL(zdj\Hwk&WM`|dSGKlS-bY ^pm0 )N;zXʔ$7N).Bq)lR>/* x'sjZEiu6)T } )3$q{Fx_Qu]iK(d /7dᯔ+djKI,,a"EX[~no'YЋG/JIi'['BxxKp_)C2TaG੠Dn(Qqp\hSCQ+VIM0$Bl KC1:,3RV1z0$$תMH%$RIY C*Q*!QXeGMRH/!hw0o~fwJ 6α# Q&OCR؊Dd@. IJ*U^s8ǕV\ݢS%b*CbKQ!pTX*U0?I%g Y^t\[_A2^eXd@0ٱsѸ%E[5NK{H,nbba!P,NK,ca %6±!xM" w" Bda D,DȶotB2MDu L[V:{ ε`L@[H:жJi { j QqV,OdA4P`/vۯ3^H+,}M/$K~Kqʉ~!qدhU#UIPؾI% <֤!p] e`=R!C Ӛ:S~d=?m753=o`/3b$]Qj>"Kˢtڳ]9i@gWHW脟Qe2cUte^ԣ*k]djyҭ~7K?zq+oᝳQW FXĝ3'g.VR-9Q6%~J^4"+h97>zTni?0(ҵ4gӴڞ:~N7YX1^;aYJjJKϬ|Y׫{߻zzgUÉ_hʇvn86e~3Cכ Vq'W )3q8|ǔMm %?zL3y)ē%7>?f>]h'iE|Q\P+7PC,"wlRnEڡ{YjR9?|R SdeMB߽*+QXN[}@&?QcK1G*bZy$D;dXD}%xMy?oT'ut>ܟ1Φ 'Ɩ^Uù?d_8y\ˑyjtl5 Ȗ-֩pf_YecOS3V`FBWg*{'D|ژ}MkI3*z]Xozل,SJ.Nw1raCWܽ9؞&Uo[2j|n֚)0W.kX8u@Õ'/*/IR= _*Gwŷz 4tn^qޱlݾ&=&UR9ۜcn71pNSe=v<df~W5$Yvʄ\C-Y7'_)IxIz>F.ͮ9#ĩt8)rc{ 8T}G9f[@Km1i=xaѡGו"H- %'kb,16,vkoBkMރӾ/Ȇ}bACB6_ ѮW4anEɪw$=`[W[x޿ y_Fj|̓){vߩkI\cyPC|њ?smX͗^&!冘ѱ5[/Km/حU\ oML`_œJg,vDlz[^U=0bވ Cac8/ & [4&NJQj!f徕 .<98 r*jHȮ<:jֽ[<٩,g׻UΡ1! Hn ,gT:RK@峠Zkg'LL\`6|jb)pps:eQSFž\4hGsl(}*)ݶ"*,yO8avl\^ΫņQLR@Ps^6ڈsyc'q, TT+ZY5k⻍o nky'p&0+䟈Au$=̠ C@a_J 1m z˯ 5jԼeD hm!^裆BhBz-nygھx6SQJx)%+e쎊9g:Dm7si󼲡+ +wz.͢B/a+ywд|U+i-|b̓U99S!Lv}JMd={zfuA^ klkε OzrnF,E"WL\KƏ?I%`ybiR q1gk- y$ bL~8Xf&<@0Py@X;}vY;{ZT< p;u\NٴC#U/Hu}U≚lstryt$tĪOc㭽gLl#aI5qj!xqC_Nc:^7foAGRW=W5Yh{=9?uX. _|*&)zиӅqtۓ:|FRǸQ3%|G[5Rk_\*^8Q׷A05T\cT]s[i{!:3XI)sZY-SϜ5v"dE9{l~O&C#gN7ל-Z4ՙU>Njw |$oZRGJ̴c>qjpQv*I_ִ-.uf-Zwn yVa-Qvum~E˷_t]f&zvOb4ne3C0&KdVu+SjA@  Zﱑ[JMn)N3{©9æZp򉅏9 п6BXRo 7͛[^^o]V!{|h3eȒC^0gmՈ >yYl{0xTp{2 =,cok]dFո%jcT'NfV WYOgHx>IVoזun jCuMns U>clVZbW<pΫw㆝]vnb;e>/fiǩプ^Yw~A 4p1c֍^%F_j2bCJ1hFd!5<`xC]C`“' /只{v?AҶ{oķro$kqk,LuLZ0^pex}G6}6*׳sOe舓`ؼqQ`Ylge6C[gǂ{5 S_rԣ=(HrG^Ԣ[{ gCffvIW1V u}7<^q6_itN(&j+@?ucJU2 L3[x MZbp:O⩫SjO,"RZtLlM_E&o_YmSb \ƻ^w޿(3lݝܑ9(CAMU9Q;նyI݄SfJқ ;w,Qj0<6 k42:MmO>|܀`BvDX<& qNՌTt}*ideqc* ׏֋`2G,_YbK˺ 7,K [䚓Wo#LC ,I.ag- Ub{RUc oJ`RO:7쎷߰'B| [dlРMy#%fК\o>($Θus? ƧkS\t2CFݭ=4Q3Awe{,Ii6+'e[,VLDJD-y#z~s|C[סJޱ·]X=m u) s3!NYGMXW{eTZ䃭{Knmf↕yjKⷮ,J|!aK#cjX;|pCF]f嶥HPk7Vdٯ"!ߝca>9=OɅޞ0`2nRCf3wDw3V^S[)Tond~/ޛT 6͂{In4YU#MZVNװQ1: aWGDn*Ed ыRWcŅɫ$H7{Û]/F;pGcԪV4X<Ĕi3wC} L3|e}6ns'3{LoQۭ,u0 ~zU.rpc;Vۦ+7) oj}ON̸Qsuga^{~i[YT{uCs]Q!.4'&uQH )Sof"[ ϫc3֪C7ˇ5=dBg(M>E@= Mv(#ʒorx(#ZY Zn4UDj2غVf V?{BQ#澾YrwCۛ*@l8sۑ)x&ūiԬۿ>wJFޏiWNMH`c]9X X=8'%dڎ X(qhF[]M[3D=x5LCNѯjY6V^߬2tDˉhQ54?0~cԳ]yM~}K6 jfCݖՖsM.xa貂Sufw-k~jk+.O'j.c4h|knw&xpuS5LγLb:eۂ t{ Kqn}7x Nx;H)GN_Jm7`|V{l#Ng6 YPmd!B ǻOy;{δ#E M9'{ TT$KT}vS}Pn[%d CҠmmp9d }mTjUV <(Q)eSy#Պ<gWP#6Zs&?<=߫f&-:0pamn׾kއKAz?yn&N7{{Jrȼފ~-27-?Ž۬c :j,c.${]m0Z4{]|YZ᧯ƽz1OBG_r#pcĽl_ظEG{{^L2ᏟlG͗[b@_n%7V_+ʔ0r&bXȚ/wׄԴ5\-OZ4Da AY>#{6Ꝙw.d_Pۅ=#/M wй|`l,ٍsAEkͧ9=Sv{w{o^=V;\^ľ -H1)R ??▚ gm*7.|.UlcQ[3ndds,^=ޜj2(R{1qj_1z@çFn/齭j,4d5|,TPͼ-ۗ֓MMGZ>s&~v?taI\E9R|3XprsL1B>n/:mޢC5Z LweutӁZ:>@QO#fc5ۦ#5LJĤN7z%w{tOs@!*M h*Y=K;xyU|t_q3ߗ]/͓i>M~cu} 2/69&wNX+ozRω\0ܨ1l`HngLZEbzƝt?7ϪAv%D +b^B北P>|n Ŷ=&W%PFW.崔goEix6{wCا3*fp'l*=YL{A" .\@6޲SCa ^\pl@|<`dd"v9+3=jޒtMaM8Uq[?>hK+_,i8ЫMli njx^E=M~Ќ aU.\zwhtkdQn$7?LٟX0lE2kE=t+N|~HU%G ^m8ӑ_Hj .x$)Ș g9Ůo5y70Y'7M`}^v}QFi^ Ӿy[Z]Ggȭ8 .EUg!6/({xmc?~2 N%QU-kG̛1=0ɽ{lA#(y fghY]V ]Ԩezuuf*aߴUNL[[c壋ҟ1f&G+ߟ>mέ/>W;>/,Df I犴-%<(vtIRO//Z~jooȑQTO9)v&™j>GT[B(s_V}k=LViSkۘ {:z*+Db]UB _ڀ @h8T!@eEfR%V! wLrpp>G1r+!>V}TAqP=Ł_<A}&?(!C 10 ߎE*s0)}htJFݽ{&t ]C ZP-(#J |RChupDǭKW˷vvt1K:0c\f$QUj|%VS%:lKU;@Ȃ쮃O>dP_N!`6G9^0p .c|A&ER)Ǥ8oC r¤}EW"P}}BO; :B s!_e|S6/7墴e ߒ9E.S%2º@N^b#Pu n`8 S^w0|iE,jA>!@lPgD*ͫ c|^A{Sթt0= szP(R5ԟ1=ȞuPh~T:(: \fPУ{e᨞=dB㌆cz`0Оc 1Je ==t "P=x@Q]yHDtWWOs,)~, v%5: _t/EI QhIDSL_9еk_G>?=G*)ꏦq42*avrdv2JT1+TjZ 1Og ͉(beHYU &U$۠O ,ב2cUΘuB*4!!pUΘ6b1M LU4ƕ@,4҇@Yh"xXλwCnd'](g]ruͮgEйA M-TEVY!Hy 3S..1} !uN*#+[(gv*fd`Bӝ"1("RD|;+h ͙?NOT}hQ{E M7VKdEU O$D Mj?ĎZ%;+'LI̒2N|Z?Lߎq(l.]y>U/( (?;{$J7(_=w&<4<xCb0`q{*ݿ*j) W)Of)&K(ZZ_,4d^\KH,O\TC;Xw!ZT9:"U.4YN閳jPΜu27+?e .?b@C{D[@c̥rac~ C@?R~JL_??Q~Zʫ>Fd̿0s#wE b[@8B`Y&vD e)bgh*`vf;"1~5xp A 6G"Q" jA+病1[Ѓi0 :NcU( rĪn_'w)/%4`~mXIZCaiaJNJPv7G iA{HgeE¾Sc%PX$L)3:BZ|L?%d?,V?̬㽸j9 %Y)ed~7N@+ׁGp3Q٭mMn> ϕbD..3E* &w(z[O6Q B?r e>ӳiC?9:a0],B#!Ањ;8t9Q?K6R:VzA04 ]|OV 7qt]ɯN aQ/ ӗ_xƻ;_U&d:D:aP3{:s$9&_nt~]":  ?5{%CBNWe+ Bozツ!`/ lԪ$ |N72?[y}4V;;A8[~Je_+wC Q 6Ճ-3)t)4B{ԏrw|׻\([iv:x2 pߟY*pG_ {?[~ȏ 0~/L!)Dt\>?ՁW?RMjpW.]Vg`PAZW5+t!@vd؅!{#{"IFy{:BeME2/S*a.aP7R ֎ X0& NteH1EkOnhdN 愊CA"װPWJ"SnhOWq$#Rȝ( XkA³prw:laiȁmLCyNL"AGz{p`0MS82>vFɌH1@ G-0ёGzyp>TOow >%?;=6Ec Ery(D}nq𤉭,6tO\ѦL=K哉 *R4x('mM; ߄)_`U'tB{;9=ȡ8.dDdD0_"8 \[aOf2]"#K q!tW,lJnRN F*h_a2݅/?k2YaqGr&1x93k H)I!R2D8{#^aPfg )\o2ړGu[dJh>Avbp=Ѕ'BwP#QCL6Hcp5\qBp8vD{b?&qc R.\L"h!,ۅigcC?*逑8J2.I"2+,""Cr/3'FI.1eœdnl ʧ\1Aa,X/-/C}'tg:ޓv|?o?a^ys_r# ØZlO0ON#<>ZZ(R!! at&(S;L,vr[@oՎ,<|2jG8w)]w [˿g~Ð0_ןuq8'8H`B8 K%YP_+_岟p(C/pPn!(<.r ؊a0Lx(!x;G+FVsː2\B1]D@g/w'mD" Poo( B2La,2+rq" ;P1Pg/G.üR>U`Bĕ`SU?$ HeʹSip'! G(FHJ|d Jx;KTO F/b/ ÃD|[Iax'ir Dl iwb{.K\0#2P# W%Xp-twy(a2+ d"* F x@̇OVݱ2 !=erGKLPlm1upHl'ӈΤ W-C 7NH+`D!Y,*D^~tնQ"Ilw[ƑIavD/!wda yb 7''q!!4+IA8JĿ]SS?(O0~P* v`A@=CJDDG\N+rK!- 0K! !bwBX S 1xTŇJQ Lt:p4pM`[@ <''R`p zȂ@ ̙ln2YUUf?F(ۘYt av 0D*w`!M;Ƒ%J. 3AagbVUuefMtw2 3W#LKH\%Uy@$vSn?2@h7j@8= F!{}KDnGfP O%?beoNc 9c`Hkfr)^6<WlVΎ_2jGm8)uuZ}|x5~Ei[4#pϯw_r ۂC rrZ9͝j\NlIgsm/5#bG\ݍ=tN9pt,-|YP2 Ů;{mg)>^hS8wA~``6r30psMc!"ApAl2s! vi)[3:z@sg@H_c?qwTXePY;hxN 3}z)"Ae@0gCIVU_\*º9ycv@7a-2f!_593qq8Ew0K0H{?~gYۅΎ~T&nۅlFa9>4xE vc1:QN cfUQ]| _mR/-]2` o<:m(V?X$_d>tTD3 ?\ia>/s)MoKYr\Kux3&"<_ 41n'"8#< YC</mQnr6Փؽ송)VQW)(vdm;ŞOG`tlpll g,m4?aW$e? p*QC 35N>ujw:^A=9(HUE"+ғt'EDY㥉+jrFd/g 0#[% xG'iƱa\8\%YD7Pw; 5@ba1{X2 w$ʪ4`8Wb%)KuD|w_nzh:э0|G $2c&w;7_K#!AKI]qj:%m+-KG֋h k  !mSHj<7fla~U/ݭӗ2'fۛ[XTkܭzq+}7a*szspc;fu2w)ޖvgBپt1rvVhO`߈@L}T O=g/ SِwVN?sev^u'JpR;0>G +hƯgX\*I^cP)u2;dt| /B{=7ɻ@i{O ڦܥ%!U~ @]܄ ҬzɄ3«Db 9龜EF]ArGi )6-GoQ4eJ"{B&!-cV* izAUGU]);u!T Q9ieUP.8EW"SIrt6=:-!;W PM<"xf-wt??C|-GOK=x翑?~}M?0}K]uUD?ʛ~>??{w緕/AꖪB({b^VaB:,G? O/T)|S#!2[Kh@0vW~GyCA=?i<+gBO ^SFi 7*/׶ WC~=#&PA%_rK% GY6 VCkukUk8Kn6\=/Z$nFJǣ/()Ug IJj57B1kRJz?6{/熷|/_?ZcM/kP#3u'!0 ]Bz|y[RЂMvT3(۴]bP!vͪz_Ae7B_p͎Ë0Pˊ)n>Xe<ѼuNZ](N>#56;`C_RIjqVd.u% am^E{mh/R $G).x은M)oCٻ,e9HrQ\pPM3)GK<hhCFX"h'Cqܬ7Q7i Sc=u40NK6Sd:Nƕ2oĐ^eafwC5|qA^kvXo.'`Vfcgؤ `G|x{h>^Jo7uƼ+(vMRC]`b2ˬ12a"Ն>DވաZNލPJdkQ>E+Rٲ3]W{N`s!SJ*84@Iu>Tq- WCH ̃}66"Uev;pGj'P:+4 Co7~r]EW=/)ߘG/vyV`y{A}!Ggpt;e(+EVQzJfzzD=c6_S=JN@_P|b67ۓSFiO7{5BPAFfr[wsLj?1~d:  ܘ]F%_)ee LuRWk?թb;KP;Qg>7j%WPj99j*Pc † |!A`F HCo!08TaC}F|CXG$4Ai`>"-P B儰(/j*Hly LJ9QC_o{S#4EE(_hd =cjl. 2Ou'ϼ$2J<ȼnG u' v;due^ۜNې9_GLC« iu  +${ 8ȶGf=MpU=d`0+f qvp+AGY!ECQ40fA|ƉwU4$z \:?[X$*X r=c}BpU/UwT/H>? ꅋd:k> zAVXwV/HC|V/|or#^,\ z!zaar =FѰ 9*34M G0aO{~DȘ iHt?M{UN ~0 I (uM8 n~DZ'CmQ^{ήo`AƗm.+6γO?J 8դ*NUg9zaUÃVۼB<N4c]dX]gY%w[8Y į'`䗷L")QF ܞF A`_ߜ3͂1`5 Jm$k;&Ԩ  ?NO哅'R]ьHf,}/f Cz!h 0 X2>LΓ!|&Ee0԰HTPi k6]!%qXx5L\+b& K1q,*h# r'ۢx 6]AwiVݕ|7'vA`gA:)<0NFdJ>_Άv,RGψZx{ Хnޥn-dC|M|DKB0,E B-u;"إv@Ƭq+ Qu?t?滲m̍* zsvNp*]T&Sul?srܩ!MKx*Q\Aqު8>bȎ G?h{t˷omvs8m1X1j>@m8>&`r ܻmr W7*Tn! +y@іp `v `] `ф0J[uHXLw 21. $GW3bx~ 1 BT`B3/w%NQlH{W % ۓۅ{{grsiq6#Q*9H̋ȼMcOn!tr ^jIVyq51}aEޚ``71KY NЭMV_^t/nx$E`]cMA%\`H5Ku'ǔ`"7⻠RAXB|BW(4o<#0i칠5 |/t1O#v"v:BcXTpEt"`}]q}!lK|4L+'N H A>>7 #Bv_vc9?Ҽ&|QP2[E>KRSSڬo%p&C4-hXó`m!+`,<-?[TUT85~9fJџu$% _syWfffD B19u!g2Hz;[&}khykfLǓi5JMyp\q~$Ųֈ}m5{3i5HәD5j{u|lUrWJ.;mT݃6]2LkN{i|c[zG`|x~C"8jwߺo]߷.F45ֆ1%{HLb#@wȑljňrmV|Lnj'3Z΍=P}vNM8zme ;M{m -?o^["N5u?K>u*aYo|.Bj]\&ӞՆez.0b00%v?oS1I)3{m_,]1ߧea„Jf6UbJM~.KYʦ\+} 2YIqWǬ)پ2Tŝ) [~؁l ,{UAOrNёȲY-UHwt+o{nZbIPl*[jU|&NpRFӎ# S߉λw?1?O3r9~{g{[[98Qn|sO2ԕ#~~WܫM[g%uj԰*7=?|9fPilo9.ϵub֊^qmTӝRFp#fXWj҃8*xLxVjӫdvЦ즁ޖ7jh:WRpy)%nfb5nfEwXqz9E})avHK.ӻ&A16&:؆d]3՜vZ_nVU}5݅| !7x32=S~2KPe"G{:w:X!CKB,T.iz÷EIޭz)'܍vb^zni:* i$'Ң/yԙp'|r= 1y99q_b|ra;2Ptdt7ՑjCtG+") ]sq~Ax`~405x,x:Qۆ5x,xu==JrO *.a 0-pv.v<AICbQ9g8Nqx[rBPA:ޠfIzx \oCil!zc-B=tzE,Wn68Li_O6Z_)ud4Am}F+m7<Ď}n:d1M>˰F򑼕ƝqF8C{Ж8 2t;`{B}mb bw4 {@lq[gˠҬ.9XT0 bFa\A"Ȥu.I;76h?n!Bڑ(..piGrJ;+_J7>J|#!|_DiXq#A(/헁ٻDm}`=t'2kߑ(NqC^]8a!zΏ?U Ay9}BwDԮi*sT*DnB^h /l$Hq[h:peQfU\9ak<$pa SgyIZ3ZXb{H-P] NkX!aql#, VcH4}ϮBh:Zˮ%|Ӣ (]R lN,M>אyHȇVȋ-ŎgJ8Ƭ&#O8ÏN ~թp8| yM?ׇOSއ-dX}ƻ AsT/A V*>S߇q>lKX3!z? i0*t"L K,(%͝EK!.A"B33lG>oHLBOUh߂DAG8"WX!:c<:bȠc8b|DT7E]OI 8PRc%*.{eZ?a`hYý6B"$wڡ? Plsas`nz^lX6ÆI'7\'~}i)M~&eq $^VF[OLv:MB_6}+KnZS8llsg:fy*qZ=;=fWv m;)Vx4hX)8,^8m?* Q<x3l"AסI]qWyB؈%(-nkk~)y:-)Y z{l+m񺣥갖} pԗrYi ӛ0f!u #x ?.1 頀{:QY3PO;rW~5[aV I35)ə|M91Zt{jLyz Oэ:flN8W(t晏oF٨.)OFS]qP)$͊3թټ!f \=?LKjNzM)4"ۯ8[3E>#LJ& ~'uv&2f6I엒ROZ.ߔ®:Mmy#(f!{+T_pp\IhvvSbی|:RmSjc4truFՍ^|xڕVym2y)O7^4g^2cH7Oӟw ?1dfOFuvY4פAJi#N 5cHD;aT_lvL>Q*ieL%h0g9&Ol^Gگܮ{|NF}맖xXȷϋVIhR)";my _0m{G=Xф̴ڛʹ8IU:F}7Ȏ]YW,nOl rB[x2nGAhYV=2*Wq%9]nȽ\^sZd4ZB%gtTL7U}/uZg /SfxҹQrJmqT,0l|^2iѲתɱXJ %R?.;#=nxTo< Q^k|f3-1EVź(ziӠg\X -3lLZ>-QtSF ҥy}Գyqb_Di5st2b3 zumz&j9gG8ix[-twu[gf/s-*TIAkLh;i1)>%]3&?Rզ\-qyC]mz ؅ߐfF w<#ve/Tu4d&@ !ܓrfC:~ C2j] .?̵7;Y55dSkV|<#s^= %R45;yr육^p}g" GhY]pH i3ZPe}1h*+PͼE5~W2 0r(m|gٜ;8?ȾOkw  }$To0lbA 1L1ϩTVȫ^|܉ srsjr> s[,A=:㿃2 J \WBe6 Hpd/V*4ρS9pxq*sBZ]9L~ :ZG~82q簐f Ņ98 P:, Q1"^c փ0FW|yڀ$p*{s9`\\N* 0X!s*u.X sK\sAhusAs.>sy޹ 4ȹ pBr.6q ڹTLWJ=pK5~lGn?fg0_^1D]ǐ? g|2<}7R1/~K1@H~ ~́eS6Z~ ; 3qb o\ ~ xFxrN l ƅhB8'F?:˥e',o!;(of R K"YU߆bnqS,?<ˏT#%<-?ص hkbb4/懇T\H<\.B#p{ӺA8h7IPùA;1G #hgy2G G;qQCl$  BdoA+ނboqK޲\G.rx\E]&\Ε9~)"z*br %C3wW .Aޯ~+s{ u[]ulj\ƙ'8]X%OLA&栉hnAH3jDcZ4lD}$ߛ+{>xDR(h("&>\G.#EXBu`qK?Wwi F++{UdcXZn K,LHaiSU?X XT 2L1g ڷ^( J"bW Z_ן7|#;WřiXyc[ۅ5yب=R-Kkq<(IRaRiΡ5n=6L$pAg SR^I%>=6L/zEI/ͫҋצ)C$O%i}]hᒸI%D<$)(u)3uI4R@`f若ށrRh|E%L0 i:pb@JT3  /gwb;b ^)q}A([ ja!G-ĚsP7O |(W`!;b] MI~˓F3ӝݟUɤ]&(>wͼH4f[DAէBF_*OQ !J.TA [!\0un5D4(6lHPaO7 ۬ P+rb%-B4 [5:հe^ht&"ZfS "G+<ƿ)(M\pA(RIu* mm>NIjXvՅy\f[\-ֳ]Z;8k3yRT⿀QkaϙM?>pIjB5VRP(U⃉ޓ&/+~F>M}fY%EKu)DU*؛>7ck"uy}G5Sbv/Qbo>7N|'1 ?ߝO @O|*}'bw>)ϿXO|J;װ{@Kͥ<_a>]ڔH;P#&$\=ej(>*%4{ԋDHJ J{ 4bMt8@x&  $PJ%&9$$~UTtw &_.#}.N|:(gGL@R3(yޅG5#v{z C8MaXBЋ!$*vaM+ZA{wnX CɭKws*JJ0ЪT=X.N;)r(9jy%OZC)@9i"1H,.%v5*%dy%גP? W t|ݡ1fqO; aD ;= >=RݣpxRJ DPy"߃*Eak: ~Ge+X$J4,#4^i>ҘR0w@}]}}ZNwsU9xٞkܬyFECT7 *sR_7!NӪ4X sJm)R%pբ%̸3A[(ONxΏ'P`@-[j+C9"n 5ܢ]J6V#əWsmYG1]qЎAeP Lt'hk DE3k5bϘ#\JE@::jy<pU-G.40(`}/6h_ {y>wl>nli&9^nc*ڛ{{{N*{a+|Gfʶe \{k&L  4 =N6t;cM!\|drG2h-(D ֹdoDL(G]eK3Xx,q$^|"q>&3[B pYEs=TAژpCs<@6ŏX3uκouerf*;jJ""t2& 8Aȋhx-ܯ'j1Yz:~ i_0L:e'ajO&F 51ƌaaSXA7*7*=Uwr@Wq:GDZAVUO}O@ݳck/:EOrdqͬ=k'*W]sc ZLsEW\5WWL6mb@n]ނ7VH[ꂙsf6r^p} @;KL1QE,7/T -E/GQf ",Hq>/bz2If'Ogξyt>6*MiמwG|s}rϴe.J&a.}oF2ֿzw͵u\9xuXn6|, .6zW ,bw!b[?v4C,Y<_?J=(IFvuvdd/(th' ܴMr=^FnFx ]bǃ.$:Sot|U0~P3N#q.}S^xaވ8fgZx֚ޑyT&$14(ݾJy+餺НEb}&l}J-HUE:{X .4^k!hw=bm4@Lǽ A+u U?>茜j|Hl+L9(qt [.5 1"OQ[&cV%GyoHLWbVyѐL(#(`ۤ(c #W'Q|<( p9|Z DJ#k͊[8>IS@6wpq*yѨT sL]~ʱ`($`UItR_ Ju) .l׉IVB40Od Q_j YFd? HcuY"l@uٲ]I]XD ~8칛va`N .J۳@ˌM<&r~VdJ> D@+97`E@sDwsUFgG:3V-&7啤HLs| pc5s+j|u+<:Io>!tN80MӐY?qG#jy_`?Z[7}[rev}C#Mo惞QIOqO\~ -ur!30kDs[+k_M|T6ͽ`xE*9XE+rrzVLng $TVǃpuNd$DmSc Q+Т-oA>8l,,6`'\ǺʪK#2j:4λx|\x Ȼat v1+' >}ma]YЍ@Z~4(hEcJpX|ɸ&GOp5aB!eEUtco":Q̣K2Q^T5aieUm'u t8pC&t#S+|Y~+s ~+jB(/p@سj.I)$i-Q)bG^-45Oouvͪ*&O7R`A`"WwOR$N ! u:ڹӫs:Ld&hԄ2azyl5f4_- hRX{]gz2!kCl͜S` RRmrJ$, H_%O. ژ"V]%U i˨\SŞnU#tPБh rSqܮL^r,X[]ÄlXˌ3Mb&Mr7gL3%zy"ìI5[Ŀ 6F~E[xԙP%Βˈ-Vv2?ۀm㓟f9-x3{JM -~P4d%p P;%p)=s"\nv"(4r^t݀[x{[/g?K~ K5g!C/3[^_~cZzrieyYM m_^gM-LKYߒ{ltX|Dy8d_dc28v>'cSd= QRPiL|eDeN4_ ̋HWF_:;!ogu$ь6Vj܉bz{zk*dU)BSwՇՌ֟BK=Pǩg`u@^767uO_+ WSĠE '۲rJ3/u]^ Zˑ֘a<4]/TTΡyi2:x@6yL9,9<&O:\.@7:j:&9o@/^l>P>C "K6oiТ)'ON`%[ mIUm)I`H[wv<H9{@<.`e$ŴF<dt -z҉1ط. uΘ0 L=f;dIV}2cit>yѫŬR}x _PU_9 Y׶_4JUU5l"l'sfCkHiPI>LX Եr9A  5AjH4LYĐMㅣ%ռ.G[;[W;}6 DQx M'Љ1#_*\,軠-}Y̵OI78U^x9;g[gnF/UT.~*{󋕲*,Gh,q僎D-_eu9J.V3[ao F%3 B,LV'5/P,\Z"db$ OxF <4fng^̹<Ӵ9̲н~5 )]\,6+9G*Kz\f]! }r'qgGм"ʌ[uϴX6`>b#ТoƤ5RN kLѲqVf[rGymzAb(>kD])=|vY]Wع^r`%5 ml:i$*9Kg{Z/lߊoX3ܵEX7.eD'g@e5bqohJrJT:S•ɯ EfsݖQ$8(Pbt!A ,fn:}6F=͟RE&L?hpxN 5{hy6L-r07J4j׌\b Ep r%]`vyuMպqX3iwYڅ#x犱ގQuCn/y-P 41T |ry;\'O7IHeʜ<~!p$i [ޢw^ {5:K3,>Y"fbNBP1Me+mN5oEN } qw?g?~aohU ?C֎D0zX0/tt2+tvGu +"t['OTa [Jq^g<;ٳ| M:NH Fk:էfrf;X̽|HV {lIJEqyUK;nq^Z $F$T<_eHFe $ģ{DA['9 (tL>T->|X.S,(*z$8oDi\>"eCBayff"a$%WaCʦH~)ρ%'‰y^|yQ(DI9u!lvr#$jΚJ.ҐP3iEd`j${II&?),KD(Җ?qP:B_@]aȷ0HD.Be&#Q6'aSt ʬ(iލL8vѰ)V <BU&}Q[7Еa׋#t=@].o()?PtwYaNB7͇KKNJdMR[ss&ӔI\F.NYb뺬1f46)ޞֽOSǹi&D|8 ˿*%g^ Hjy ͽ|}m__ZL TX#s: F:+3p^P$ČUo&:)trGAetr*:re;'&e5ɧ7!7Lkm!#kbWI1܍st:=ǸIDƎ9x8EtyOC67Ŝ;Nj'rٙd:i9u_RIkd<g_ڛ~u3/m{ERW I53__Kn05\_vXɰB@U<6'q,Ӟ+3q3ً,.|U4;L{{L2+4?Oݳ)wȚ+Kd:9390i4d~g ݟT23L*cX9c utq44Yw_zJSxYmV2M5Ioovb'\륧fn&Sd<]7>[Ȭ1WXά1WZӬ*Sz9> =^0s_69yvKWI&yfz:?㗆4/5/ "^h 51u 326?_}/X|J~a#/}Q" VOv 6kˏ[^뛇Yy /n|b_V/+J`)-qZ|/Z JׂO"[WKģa[aƷY_\/cG+U¼V 1V=&~rI &.ߩS>9УS VUVNGN;!VbqN::kI<< ?gkirx'r\B<:%ӊzJ̹1]Mw74Q3_EIoS ,}/+:S"6˃,9cE lK=z+jg#)W&nk}Mq(f@]*gS(mǮ23+:ؔ~y͘Y>EM :; uu;91N}ņSNSOeTߊ6q(h\.LyTgJwoaal<'y##dsFwYWs2~#D`hYd͌7]ln;2}eE67\pi?6.J¬籹in>缏'PECMYcNBp 8 PGJ2| vq>ey)*ds>'?,mXTd]!YTwdS}eٔj2nȊ)efq܌n Nq!MMvFn<]Mw]RH Se<y^lzKok_^%-}uu7c.&Iz1aᘻ/GUN\?@:b3F(/Ҡϸ4dya`װ"aNtw] Z}@(b#t%r}ifF(;UGÖx ñZx^{?]$uo}pȅ,c頶F?,溠dϕնޑ~9nB`{~Ѝjm*7^Bx@J2'7=9R>T;@7@ ix%V(m h6z<<`c,WVK0\|euj}po@U < $#@Q>P :G4z{ (w"iL9&PQL>b"ވC+.x#"A\Jͥ{{*( je2y`i8A@PU~X@ %( ԍ'm(^n1oUdzn`?z-<_fc:a|mEi~ {bUQ*F>>`]l$R0iKag{UYi?]H, #h\ݝ[^nBט5q?QOG:b>2NגM@\3/&tbdu:^tX U {Putw\{iH[/{fA')S4t6B0`X`{@tBZ/?xvZ O6v^r7.-O' -t-^SU:>H SL 6v<>Õ+Bj !=MQq4 .Q9I)cqCut\pi$iړe9̈GfUqb.e?,$-b԰lUp7ԊGOmx0Ht}?I!TeUze>S_Ƹ$@㋅+b ݘ c;DK:<Ny.,X%76:^9nJ"afI䷤Fa72fr6T WV'-į;&'?If\0cqa qYӂb^r˜F6b_֢"b%hCn"w.B@H>B_Fhf UĎ(SWa LPҨ!)nG 9wh0дKt KP V~C9}FJ^7ED`2My &p^+j1Jh]\QhȄY%6Fp(`: E݄%&zmâ~R눭JQDHy\V֔tam˅MhuLG9O?mܮˤme@93wwC/JBήz]l-7+ [)*'tc`O贜u ōp~rǤDɆT=(NZt`17oew+ &";x6a nt:ɟ=s]t~ڧc~'YT{9KZuv8H<)}eߪ~,TlK-b5)lowe*d͉9X4crI6 @ZPÜFTT`@g@8Fn^ \+[擙mcÑ)pǦ 椭ѾF8yOK=j46oi5}6QOVOUՀ$I0 ]X:H8oU( !pv[&[gЬ -pfRruȪ9xئGEÛ|q틕X෗@dyHB4&0 ::-un@2S3>XR%O hwK+E<Ԑ,‹J]oo>[_;|s:7{?l7vs$62*ʠ?+|֧%' ]c'07lڧ0<1\EnN׉Ѣ0 D=&$2 3K iH8d Wg s"'̇w_.^=9D78 Ų_kvfu89LB;\y2e'JU-6쎷s*A㳈N92RDGT{ !_ 4H> LCes@HOh6. G|,(9"+M,.QКY[[iMVBDsZ`yoSPlwAyq]V^[愪#2S eϨhVG_-~cKyB 2 )|,qDk~{8J{aQ(*ކT4q ウB훲0t.G-d1p\-4m6psIPQmW D#{kTrh0 `b44BR]̴"7vo1c5imH籗紆V`ZqO^FZGVdtNn 9K:@kɟ\T˶o{na*!7P0yO/X))D$JIFӾfR3* ]pK _Q<B#<\&c`vxnᶑ\r6Z k*2AfjPq iM3q8>.tN!Kwop)-5?xo :@%%V~\F_ŵs:\HWRg_-]b$Wת5,6 E@cta)>3ka/^L "T{,9F<5a7h9!UKĖUXQHђG!,e>=R:c̫x aYKm t{H\U6K)HFA ߗBqP4MF̑3{¿+8H0#/mq%NjLlema4x i/@mft[:B%UٴN׍뛡yLo'2Pzh;"XnU7nqaF N}YLk.Tάe)w'͸&@(*w฾2"@ـZ~\0"( 8RrFD=M>2 Ba(deҢ3Ajw3I`E@_:>+)F$tC&:FHIk^}B v,I7I uZ;:;X2xڰjR*NEС+ y:t;r5SH Z,]'ZhbTaYƹ ØS#SCV 3fc⺜֢2gm ʍnSfmάVͯ a7ulFx#c]*ؽnjؗM:taR$@PigǝsseR(kq_%uuTaQ"şl#06(u, ,Z* .9zp<:ҫހE#)'ޣHmKf fʑFq+O -MCmYF`(Ρ؟tdJȞzlxW3<#/ T/8d&;roW ΋Py&'ߧCMhݢKO\cYEܷC{y#wY,^'{_Vf&Z &D\*rS9 ?%SR,KOp?jUs=kqvL 7z^qDr l1{ I[dB;GLN+**B0oP @#)͸uAŶp۔)?UYAG3r7F5N{^%~O䃯^?BME m'2{{Fq7'k7&&nOT{W}olBKO%`>ZAV]юWbԖA)/wp@EW Y 2lOĉGjr~uE ԜIh!r!{3pqh晓I1}<ˁ1E1w]M bZ0~g7w)E1+;~=xtK2p!btG&<,Mdt].z3HRVJ19w5/ .M^e?2?|.oXùC Izr/ǿi9[n?x(7y{-5L:ohRd3nySzn˓.9K@K/G]V 7zt2Qsor>:)  S:TGh 0-°) ']@2Bj-vnt$Wrэ^-iMLM4E,xgd8=(@wA^Mqxgȑd NyxxQvaK!wBq[8,ɭn H:@ (3i ;F:8%Ԍ,{ѾeiD3^^?ݫOP쐲{FTX+ُEq4S aTFB۷ C8x]KǝSJR[&0aĈqI!سo,Ւ=qd&J=z+d E`GI21uNJ0Ψc^:0ɳ&KuFΑj)Dɀ&\o86nɍ'I c=Cm ы1qm9# @ /IPCӕQ f?T /V{2GWLQN7BE5׸ ;Vb"N::_0 %z mdx#7U_//&hJ:8 r+y ],+#sJЫG|:,25WMz imm!/U36]:ODZKJvAZ& Ԍhj(SS_/#UA_XUV8`xL)rW>W*#d*(%GOwعR| q Ԃ-I͗6lY=߷j.,_2״;AS29hX&4^ĭvaYTj4 0RZ LgU%W`&?PlDp1t,*Ir)eg [G)&|K\SC?E ?Rm6GO_^"?5 C޸יC+3)L9pU'wzK;5񢗞Z:?HF;UXS8u,z X6"^=\l51ɳ}Hgt|^tv^_}oxG4ԆI}& VhLnUuo\/W?xL*}^Nf)?WxʆW(L[1bnAh-|&Dm! ?ykx+vQJJO떇H*Y4d} [:~S)`y57 {"9Wjf(FN,(E" /on˜gmt +j w%t GqӁ^<ݛylB@L2F%kwhJAuɉt hn qhܯ(*9)=7HQ07ڣ=8&1]2+U4%\ERÒ]takYJќޯm|+=ZF8( z0+]? dd0*p4FA>@B?``|ETHf:i:|sp48&$c_ _ BCR'tJMvss@=v_!ͪfཀ&IiTQ ޿L@ i-2Of[cX`IqnF 3AMI2:몐c(2kDGD@_[$ }gc +IT2VĩlԴG 7>NsP! rt#{ uuZ>*qpT ./(=K"/: XȰ13?LF3JOqKw gG WEM@ ǎjn[b~qt6/Dдmnw;^=Xr[ޞqVn ׮+~f/MCp,&bO?UVWQ|FC0Tˌpc}"Y&ٚך82JnODT8UZgǶwPF70Q>Q,E}p(*X8 vDd}Jr k7[ޖE#NCkyQ񺼱 {@hZ yE;s+1ȁ%EV[f|f&E-c&s  |"-Ԁroxkv^C0Gt:Y+vM-@:'`IJ%f WlD'^zźM'NNrЮ?/&*ʜdt1U[w=ٖt2g ?ZEYw8u`]b;9&8TJWBP K.Xlcbh巕ӕ_^p^: ©sK y=!E!yl_,\$4.gXa30'k310OJA [X%f|3ۜPP?.l5}t 9z)Jo$1 "Yv#5*SԤcn3uvݰKDL-iBȆT߼6X_Խ|"/^%Ḱ%U9k JjŖ7b,T^+ Pa^J"DYdf9IR6bWIShI—L(͎,Lx8Jãq9Pm7 a@n#].S6Y ̝A]w~ kj.Q'zuC(,|0;x@LJ)}v" $-^w7~e(8 ; *FDI&MKl;/vuݭ:3⒭ۗc)7X|xbʅ6ƭEzlM~EyN] - a2:j v܄g^js34 jb:`Z;¿̎]el}ց]i47elɵx1(]dpRIG|&-FM XD=FOdM =-ٌS$ȯ_ӍX* 7%Ͷ]N{Lc[I{x}ݪ6\fO._d 8g E1D5֮.هle;0](OcFn6m Zem׆]v^t&>Sp6vg]a7 OK;KVvLvHxU](QC1wK[`Me[{9tB4CkMl'PŢCd8X7n!>Bo\n ":|$uIW"1!V=T%Eu=e=^,wNlKaS:UYL-7C:{)j d6oUG LnatL.pd\̩%av+ĥgAwFp0SI`T'7|" ʤIlC@ZEq0JbJ`"_VBFLe 렣:=("{y oOo(D[[9c hп˿W![ƅZNdI>U>6sK$Be|bœ(Z)wu=n KaWSV­^ma)XQwسK[&) -CI-H$IG|MV*6eYkutn}I ᮯ@;}(+l?x$g!EuxtrJA{{0⃚rXU8gh]Kh  9,)JL_+Ag/nLٞ nH)uV[QG38hNcpṋm!JeaD:p[`Qh^R (M4Az99IqvyF/4.{Cnӵ'Ҡӣ1Sk7 ,6{tZi>Z&J<ڈː U;D!="4M9']>;im*c>o1jdMpw؍Ssk94ö͏|}~q魧:alCn,=XG ClD0W_uhϕ-ԁ9  l%QFh0Dj'K{nzgGm3ڂSJThۿ0s)pi e1a]$=jaަYv4߲iLF-`$m\ԏ Gv<>j<+̍ P{?CvJOCYhã;?܈xV37@ "?pƷ5P`S;~|c>+m;d{!we7 {55AntBJhJlSlb,[G S+xcȴg*QՔC#S`% *YM(3="ʹ,/BB=Z&˯/D^W ?# (q4=ټ`<6FV1wo .2P%G)?,9^`PPxvv~G.MY}dbdȏUq^0."~.lknX6F7b_é_g4LQ޻3zU%#K٠A(%m(<]nۀwȹ,$%$w/I$#lpHOquʹ&HnX =kq U++Aob) Lٰzł7Uˬl$khpAd"o#-j\FJ(e7v=ވjvfpBk8|vYFa iUUկ{IUKsg&A'Z6+Z}q 2Gg3S<uq}N?vMNh,n/'{*Sb՞4DN D)q!ZH9-&D%α&pWZ#˜?;.B9u>21ڗheIIj-wsIUpe G]b$gýLx#S 618wnd%4Q22ShJ]߂ A_:؁m}vήqs@?'@Ц'j{k6=(\? = 0e~Qi}wg^Ȧ6^=&pi] tɗӽn{wjPݯBM@6x ~17{|lsg}A]*p})SUk{[XK0&EAC+ "8u.~[yy&D>&\dc);t@[gvnY{'"ĽKv)C6fw_Swoo_E. Rҳ3L_Ozw^)rRɱcQeSIÅ'h 洺jAsDn%.?9Ss&RRX֩.U2u+Lwt%JC Ao D2ask }'^]CIN 1^v4NmJ$;)gZF GJ$Q )fpGHoH >?ʶRa.?|zJ/qK Yt\Yl80ni->^VJU yb]GI17mnV6hݤm`e.i ~{k֔POGmH@LxW·JKSpJ 8K?uRpVi0hmЍKt/u hnbS~P鰤VT^r,7jJ tΌ,At-GaDð^ANhT{{aDV4vu/¬˵BAWgXQש [sL}$4AQV=T Z~l߃ycj'0AHbw)7P Qu+-:1pIk Ņ.u ]% IhQ("ǣVAC}'N?`!Mj6|i\M艘[4L'Abh/h*s~}Ҥ(z,,MvCg\_ ;b]ysiVuo~fe$)-s  1Z!I\^:QOӔ7#d1Y7/1ϐrep=iS鋱W0ymuYF\,bgMO;{oRzOjמn:$>ѱ;U="ևN27aƱ3X9Aió ge~ +uOo_5ߚ<7_o%\z4K߬%jr3yl2+ aVX*^h?>7-?x Dqul|24LzpHDֳWXr*מe k,;DZllت#{rs Xܜv'>Cs\[o/' O]'3¨K3@L%NrG 1iYzv|n{<׬z79sl0q4S,qSၺ>p^JP Gң%B#ՁHSt\t>S2S^ Yˮtha ^ rqL7JLׯ_}7&iiQa4>gHRzqx"crvڽ bKjq?l}`mahny^nD {P:XRQܢ̓6=)iƒͽ=D>|mH.98-,dꬼuL8=z6(y/n\D5H|bk9{[”+ׁ(=S5zP|Vt`W{R[u|U`7pɏfv6܊|Z'Q@y;^j[y{kIߌ :?YrVzQi OHG`qUidH%_(rOؘ)a+LpK%-v7=fG;&(k1wdjߍŜ#Μ̀Ufojl6D wEtXqH]6?Op?_}/?_|d4MKMXV,/p>c 暓yV&ssG; hsI"wOh4b"J h+Yn>+(Px]X^Zy`Cuo$+,OAa z2=dPYw "A f6D{0hג8c{$^3dw"ۧ׵׵}Vl ND^ >zb#%_3:pKk:y9|Ru@^T"}Z׵ Rw7x9:Q7BiEaP`iA*:xd&^ xmTh*ҭ@7d:aHFFh?hn[]H@ʣ{TCd 0~ TVlMyS]c\ fyg"3'&>ΕZZ#^| Mz-,6V:8Fa3SI==!\Om8R+hvMm^n( 8辺>DqQ-iGڳJc'YB KƓ1^(8˯ +mJY.'qlU UKs d P&c&u(:YuSuEalj93aYk|Xm&?{|iGe$K/_ݣrM#9Al RxhCc&[>]vP#W& (BLţtZ釁7EF.a1Fs!P^l60 2lAJv)j n46| ӻLcLUtm(ݮӖ43ԋ 9:#ߟ)ڢˢspeD' ֝0,oNl & Pg$՘ G >\=@ c~ p9w03yX}cD?FB_k|.B8e{ǚ.0~<^뚇ެ[UզG(IK17> )GwWW, /X^CX爗cUK=(5mriOcP%: E؞@4VV XёhV &gGKDZcLAC<G<6Ѡ󭒛fQ:e(TCRH̜# U5h8VHx,,pid茇(y-8a["9,1 s~ם1)D{G`TxVdA꧁J.Ft>FΜ5̷X݀U383D /Wro_]z8$T<(N;88JUk1$=*} `cZ汆AlëF:HeE7vuo?&/-Y|ТwԳ1rqt׺Fcõ<փ_ߓ-# #?lZ I-} 9w-W!z_Nҿlo_*\ROQdPN3C+i!N4@ao0³hW[{ ﶧj{g=D;jpGm=݇TE-Gc@բN/Wl7K'ng+gDwX#!9yQ7J a&R"աķukmjOkR #CȸZuQNIЕ%sbs!'=b9 {6]\Z*RiN( q? A低Cކ*.(`ǹ{g u x.a( [4<ؾygUѓ??mנ$p U'2C13~{ Qї;d4I  `@P1,G0WXs ;/v6IB=!nG3T 7=u]%x%)uE4I7Ox! 1VQDZ)w 4 &ptN=2B[$~R, %ꧭ_бu):Y@K,UHJ8ƃjhvJщq-qTRgPiSPܤriIQ/ֶpE (\82,b "(JK}*d^f̻yot_nÃV<@vU<wp㺽^nk߃g֞m:$ao`ꁴ_3.y1)"* 29؄V1SI^Z$(dQ%R^+):f%0st 8!; yqnJym~{kgsgwJ +lJcֱA CpX8m),0Ql|_߽E&; Ò5$v7 YVqPr$}$xY"w f8 "4:/6&S@2ɷjM#VU6<C,#@ 'Xp+|EXDUR\F`U\y0aĒv.EX R|]$'e/!e"$V =#Om?glnu ] e S'5z4S}VFD-#ɉ#lFWA  I׉^d@$)桞+YO?X? ߍ .&J_qQS72W6MxʭQ4$#lTKu* d >K 7jPfW%;_ZTMZRp ;Och6 xRA?}O`No7Z\Ussh]H`YQZ?$E \4 9ʑKɗ^$RMhP^2z]{B;Rה8qhșK+|&'_R21C$ ,9ĝ{H)K98x.%lv |X/yK_nWwׯf+FjfXEmrudB;(w0zp2  <߯?@ ?P! GH!#>j8rxEwt`9F5أBƴ(1cD76*#:jAc2kC:: 1|BL`M?(A#J=seM?2!0(({zt3>ҤLb}{k}w{wtwo}Tove{y,QHuPTig\Nv \k{A.3H:HYf<5fkUk6{)Ѫ7%o j`~ N[y\wch V'[fA+ "jH?hHTBb.6=*R=9N]>rO$^d!bb}d dTZ)Q"Wy gS2Đ^bWI"nGD,bѦ47*D7H(HI[+${Q~D [Z1Ki0rԝdq=.f%/fi&k?T q3gp:ir;<:r"aajD+gnZN1:ˠbdt-SliHW+|X(*eYHvQD`hvCtB(!0w&VBgV7*pN:4wP=녣K:-LQ޳qyH' 3/2r>R!9eMÓ1*9cg_XpZdh &To<84(܉Lht&sؽi Sr0G࠙"W :/~vHT4,yޡ֙w*($ֱ\bCJ;e-/F_Ud#HKx'0-#GN|D* EplKlMtgA 0ϵG p:[LBvGL3x;@PrˆX 4]tA,@'tD!. !yAk\gEꋰzP^/-Ǚ&z`PH8B兮I_nQ%[K?8o~[wNfɅ^V.ZTؚiXsVBOkPaq`eJF[(-@T<1 Fگx6q2!l9"ðkaJ,3lMQ޿d0/.~+K̓ͽVygϷ;/goՏ?MV:U2Io/5?xo@~<> =\4s6{U|ϺfuΦŜ%S"RzߖoLt,0izՋr-.k cx2?/?xrڙwu2jTRB ,<{k䮂ba@=+XRѺKE%m`T߳y*Z .u`ԬXf;*%6&K糗/hF gWg@UWJ!4s#bn$6XTގfv6(sIrF  2x:07rқ \C{x6Hk_HBYs*F+d6zÓ%Sd\Ծl%{v̴z$nmg6_o"f^_`P ]`a0d#ޭ3`avD ` NDO=n0H1t{s::/䤃?@?GHo)HuQ׾^8']I3pPN#azq_r0Ѵs'?v͎~<< 2zt^#̴]$0!;Qw0N/B$@:;O 4l|CIOӈy=DžJqRx ҆]Ӡe\as{w/F \-Mo(K #} xLU3ݝ6,)7~n&MQEi8S^+^ZCV;JRHlHet=3cCLYGh4Hj)HB[Xi' ^FA1+7 B ҍ/zh} 6ގ\G[t&d>V.~QzӉ8{mHFC'xZ"KtzB*t2vzExG<ӃtPǔZF .Lrfo@agX >guP~Բϯڭ<=$7'e&PW%x xul GE/U+R-˴\K\lYwI; wgWR^xc̉0)=HyJ-2C&m¯\4g(O`:\>Gy:M K\?tCuK A4Ozlт1E=G7J M%Ģ {s_gtH {c*Tdҫ澘>'۩w3M&dW~vFSaHy$e' E2BDͼ@u_ghϷ<>f)Nmv'>{4;2S 6bO~c2Þ| ITlw{˂s>G𛟟&^+hMo/γ}4OAw`FfOOʥ:w5k,mu0lŜwR?|lK53k1>bNXв bz>k.%Š9ȡ`̧l L+6!}rI ҊRlӅo=A})XpZ &),0){AlVLe&dgAƒ`6<' QR2ls_ghL۹\A[S>I?o}ӼiP>'Ӡ=b_ǽII?/eS*J>'m+GK}4OA~}4]@/γCͤ1N큸5I&'5y_s>'f^[=-(ŪϚK&@xo1 )!="8~y>L-ehEG7ӆ sE zqŎ ybYt4?ɘy ~R9JI-~28Yց#'ˤsϕin}mhљY"BT8Pv9Q_R2꽹/fuhػؚe혜y_=Kl\O˚!&Nc8}qyYي55lr)_g>Zd& =V$_Q,+SRF8]a,,?s6Ź 9\\TY}q+.5ԫP+*T!߰9ܕH|4q++Nat4>C@, U66Sb+J ba_raENѓ#w7`|@!]Vi.saa!ņlkɘK QanA뷗cGRMX1;†q5Cań374r'^q_Z8S/;?38 ]6DԴ]BHF;MEG}?+<6 &7+o8KbWW:T$F=nSo-g/;sW[`P !98`D3N«*/xH›ֈ#} W*-dcwX\j9fDwzr}'o| bqvMH^49S1!y>u^FǕ~FsM|eYw8:q6CW5/wwhVċ.9w>:i nOI2П:]YwOv] vg~FcxnKq(mЁ{K5w  #\ؤx(;4] y ;a`+/ 2Z=9 s3MٰU&KNm:WUǔp&~2\3]fF+!L "RR\7@K9cy ʢvNG, $FEHRg+J&*+͘" ha8V@v&榈P(w'gsEvUCgH"c=CU(Qt}qfDGwi=! }[5RtZpse(L/lxZݯ7a#H}}{m}sisQ{-([L p0W .f7] xYo8[ǵ 8H0ϼX\?*UYia>ZWj?#ȉ+`&[Z/E;2Z4 kUM_gbdgɶMlJB%Ҋ}GaoOyMccx>)abtSKU[cG"k lYqj:89x2^@>;ݷX:V9!=6䒉;Rb`M%5 }BMnlBǾJmoY|"A?^DF˽M[iwK5ӶOĺ`&!G$+;ªw1r_XsAW9O*`T潞TXo=;OP/aۊY j#!J=r"e $&)UZ V܉/<}YNrGV;v96 {/5>DZo*Ɉ}CfT!B|񈧅%Bb[r!bqa)"-NyR%5qN+3t.o{$Β.pSM2ix:ətʻk*Xt j FE;lO\pi.a{~xB:%3/™HqN:0\o z;,z E7Fł7e|6vwF_eѝnhA^Q p M]p1Д_^5 YPd' %nqtX&á;VCliB7S-J ʨA:Fx=):¸> 0X&붕VI)1 qVԋOUm݀ZJ*z 1=|kŒttDԴ8~0zGwduZ?b7U ':!iX [?H~tN_a-þBnV+ XVumr/u: QkTz+* Zù+N7СzUHc,X>+*7D 0}-aώV M!|TJi.5R c.Ob@g]vqGLS}~>fVſڮȢF j-eaKÎ_v:N#] rr3MC<5Sr9=uVĢNՀ1ZPq6I,__HJ{|!4@B¸ Ѧ3 KKad' /j^˥\Mf!I^iYqb-%G—dȳfGN(iQN#۸K"yٶ+&E4ą4hEϔ,NEfg+1jsSsf@39rʽX|1͐q7ojHYe-mXBoQgf'&M0ظ:B[tb˫4Ӷ$TUL\_̫Qzz^DUپZUKNt+,>$|e} I m$Dټ@D6L,^"*rCG@w0zlFQSTdA~TuޮExKO`آ c:!/~}qt>髝uLqu~Si!l 4\7 0bK2DA*(hϟH-f,mBe2fz[.@4q8F.MSU3&y4`u4qcD @[NZ~ ӥфLX EU=Y{Z5'8gQr&Ԋ;]S{{~9qMۆy'-OW8@6J:8uN quF02,VPYՇ0>Lh87v{`cf+jlT;EaahaGSv#ih2*;= Bၖ u}]&QP#"!19"P1.z}q1}T%386N`#uчA BSmO&VΨLr@V0쩀0u\"i-Emz/}`hgg92S22øYbbſH-D\\BV'! .[_Ɉ%OR4A)b P_ [}m} dxbbRa4*|1kЌw[4KNy:$4(ӉcKukbRdhqSEO9CW)5̕2PaPSODM{V>!iCQM(Ѷ~8hNިܭN? X1`XrWrIr{*7X5PY'{5>=V;~ |HwPr VW~/dlMP.UX0XAfO7ԃ*SFly% 5qPY RNA[v LLQpүOZ$% 8<:&r:V^F [S40J]?6…c6~9\x~[o<,վk"`wzu#C{2Zv` h9BSF}T^gÌ& YS5ܸo'kk{~jo}/Ϛ{EN)>ܱ6[ȭ-Ϫ2 )q̨  K '|Cʌ+$l!!]=4-LeRj2K5-П GA&|B3]*w-(`HULdNnlHH)7y%Drc%Dw,+Y`C3%i"!Gm"wVEoQxr3|7ْˌ3Gý 2W<sa#2܌xcޥ^fRXj& fìs#w#ji~@ş+dP-)y3j GsX0]n gY?/RcHc:es-jIoUPnLV@Ͳm pGR+ar{ Eh:TY؀uyيwƽNJ grC+pd499‡$)ͽ| =tX1zrwf>૽m\%ڶx"tВF}J'pt.:B2}NcjL+x8^%iҫ|` CL-3w؜Ao30=eOdn'% "M#)ےtV:R|tFxLj@ ߎO&^t'#Wt-, fwFEn8 +_BHlx,q#4L/xxzNoIʹjGi]VE@M]XSJǽb! 0E-Gz2ADf8r,Pk,Rh# cQ1nprbr93 +uf6Nd ş YOܢokZYƲ r7;REpV)aM#/ IE$j ^_Hroa蛲JXyf) R,a`A"骰L 64TsszU}3ETY|TLDCMo֩,-`9pkp0Dn~u(:qMldr E2\6i~c4Od%?Ρ; UE r|_8ʭ9EߊةTҞ&f>L&jB8N8HƩ(}O+Fm?iU(].l3d*qĤ8HhtK:`jR!pucX;5-,鿙ǛJHۭ_n_(?ÝMd9SyDZ/b @PrHw90 G<*ѕqꯣ9<_V6̌߃77ļ&*x)bRvR tKJQ)zY}&N{#g:!TOtψFt EJd=Z]=O.!Ud1xO($BS['*ӕ3ׂ]Dԏu<8A ^gwvHo+ {/^A-3ɩ+0!c?]IQl1/Ka# 7X4b(FcʨIYԵl6|oxRֿP TQ,b[/jOvE=Oo&qBрxOfan&tE"GXG<|WfXn;Ržz!nC9!#ڏ @s}^ _{R??l\ F]t(O'qӈүY+εg$ƛ& |f[YWZEL!olXJeRu %'vT-H`"c-1DQBC[^xhbᑝ`$5M:ѸG~ 1U#Wc->"N+ɷ!rYkS@op5e.6wUѷV"؍Ldy,U_Z2~aoF],)Ai^JX5 Ec̮~IiMKG ~t=\voLŴdi&2prn(܁:uܐ@^$ ]#O)@k)_ViCgHQ1:zv[Cxڃx|)3}νX‹{`N-q 1*BgHz 3ʱd'HY`y 3/bwwe},t;'NV9&Uoxz].WT/ a86jez(Ʀv(8KCK= ԇnRYxEv% <ũCx^v\y"RNE˨#A>>HcM5y&f'y|N;U|7!c5?XUU]TN?5+r+R^՜'~":rǹt̢L oW޽` }Bf@{D0-5M]2Y}Uu@zדLRBDזep xt#WAoHKS*= ݑ^\UVP-$Ȱ,QCWsz18byt7SvۤCe1 I!Έw-܆ z挑K 9NJrrḈ 9?2T;IPi`POf}p )UwLt%W_=T\aBbɆJUU(ao.Wpbw*72YWtyt].@8(WU (cx4lU'0tۨ.8 b]*.]NEυ79c9ԖBR/7v3 9v[TМN-gY8 U2VgDW,jx~ BG9s>@* V O[+'l0TXGt3Bm8_qӬ$ѿ{I;#Dn7Z 6G߃ {!I:n,zM8u/fEm>olex6QPz00? ¤UwY c hL61=(g〤3{}!>s(B{k>SQpAM |&omPϳuM*d>>mZgs![jwS͐;MNh0/%SE/ 2mjlR9EN&3?7 q{vxXnE3h(݂M`Y?!Äm=^ U]l}VbE bk:jkWu7Kw.P=ZO(}^$] .qgPՋ oG^4lGvOG Ƥ{ar!;Һt4hp=(ⰓvU%o |zE#0k[8x{уqZrR/R_qqR՜@sya Œ a0K`+rۇJ!ցaN\ᨄ}yoaq1,3A$`,uxQB.!awFT+^>^Vѥ2fhuD.UѴ4m9hKۿ1U3Y#aqtbȩ*_GWN4*]6I:!/:-,axa:RTH z#V8W"4sGah,c? t!3 t$mQ$ 4'Re?@~aq~PMjMS'/`ںP8<쇈Ƴ3Zq2u1BL EiT @A|, (0rok?Op~X:Ƒa0W[qFW%a _w0`sC/E߾ L I m)іο6ZZIh|G֟o\oaUV# &w'3X1-&^r}VvD |\[P9Ue \0n\_8fhVTMOKAruwD;6]|rg@!on]Ϲ9t?Gc d连G{1]n gΖY)&xT$C7ߜGI=Ǘ:\I|&Hsǟb^ )™ĝ,>5-GY,7 cbW)?\NRưCI7w6美XRN(-k!%Z%S>'B<dΎ'яǓfx*(-~g)ߤu1pI'X%wtA^K=X^ի$̾>]oc,>eYgLXd ׮Ͽ^0lN#Rב>ed.v^1vs'$y'uII|,&iLZ{{s'~0%;V, '8W,\Bsu'*=@쌃O@LGm2`G;pXw3s# G]x]DQ zR#ȴ(iTjXg[v}l+7g^'C\i$7GѠʗ+yGB$ꢧ@nLHq cHbOHhҏ.+Ն1Ǡ~!RM߹wLIQ JT-C2 $4 $;](c/;"]u| &L дN"hH26z@qG8R :Dۋ%&NCqcҀvؑ%RQt|` ii`W,"]=f~ {@BovM$Έno&{hijv7Jfm,9mջw⻸MÅ7aRJ8l6w:Ⓘ=?y[T}s@}w(yc ^ơ"݀zrV7S5ԃtmAZ^/˥kzo=݇ '(ۏO+sϫ<{McI&6Ja'jUyUF=Tf@21u/٣[TJOW4FF:>JGј :?xoE{? Ji(crqp^do$gaA7[UP̫xA[ppO n  |onoô~owTdomA8m-C [Fֵ7Lq-N5 _Vgr7:;n^]Po!]RP)hҶlk4*Iuv"tƘ[˹#6);s?xacM>M*hyS' Hq6^mC[Z Hu+>0w/l~["m\W& B\j{{F}F=/]_p7ሖYTэK(} o͝SPBTK9D%P")*{!z{Qe*oQ2'WOZg[Y$iN+,S^EF0_+p*eMY@z1a!T~F/0E~҇eQr7Xh~3ME]{ {T~PjcPsĈq$h3 Qu#QOiFQ{[zZIFZż3GJr%rf;2{_KMzeގ험>cuzja\T-~)~@85hFRMq>{&RQҽjI\o>T@yˮ4^okvOZM*4&%y`70e9i;O c'GrDU5T;hY,Na>Z?P% Ye !B'' q~>~]YyhY4 `OyU=$ty+vB+72DfWw DyHUUG]_z|G:@3,V'z)$As E9*'WPJ[:V ´?mK] mvxGV9^ue RrG,+V+J9MPi}q_Cv׺kpN\DZJyI#t1B3Y[-v0s7_s MΤh>B#{rWǡ0"JP,1M<#XC"O(p>2\/3]a=f<KV1=R&n'H)i6W?vST-O mڜ8ш"Fo42ZmuYP d-E]οS6|3 H wIM%TxQ(80]6CM4)Ku 'm] z +_awHDaF6fKIPQu%+Kky,76:\.Ѳ. =/A`yu8s^SmRd台%6k{0yh#ECgE+ey |Jd,t/kfxTRrIͅ >S+Ѷ,*x ۵~-CZjơ!D9N<畢љPF;=VI]nF@៩TJ`p^z͕,_S,c|i_/*8=4V;h4 |"Rizu~p76N]Qͮzo[@hɯSbkUܮpyTII7|Yp8L u>MmzKmbV _`"X 4p_5-@fMXUrx5]:$0uq/OP(ɤq7V:'_h|~qy[YnolkO76>{m}?{~k yydNz#|G|B&Ķ zK^ZL4NaN.;t`/`sU|LlBxdj^򪢔4 oi^>՛cehN[ r-.K~~^~LJx-U^wu2=3I]IgQa#c^cUKF.gIVʱ :%>P1HI2JW$4wcbg?9r)MB?$v)$I'ٙ@'(x ?%76dlo+l9fwr$T8#HlWՙ&BwA^ 3wj{@ϋ \<VUٖe!k/S`K-]O#=slD9*P X,F*0|d*lezB 勂)<08"qX a2ԋ!EnvZ ٠uXXK0~rr\l*eټcex3w^ YψhX-@0__тVx| h싋\dzEǒH$M`VVsdxn2[?=Iyw'@rVRRƖ/*b")>[:n+t#H0k ;HV& a>' c:ܾXH>' *9K CV@*h$ %W?I?/]R hLdpI5dQYB[Ω{Fo\ɩZ码'͓~Kp3z}NU`W~㚉s k8򗌵[ , >ӒrB%Lx:i*τ_I?dO,ARZ<U.Yh!J{(4dQȓ* l{Q/QJT!֘>+9~H1'](vܓIP2bDz̏Zïaн2<,U^N-hj"`Pԡ8&w_lJusq r?fӏ_21FIu}ۛSdqhtXPf`IP|Zd8ٺɪiU;[>-",Ŭ%ޓmt丑|h; xyĕmG] z mhbgxΆhxv57+1%/S4AP{zHFn8#gsȇ LFgQ /~ t L(zPo5a,; Y!! 4d|9jCGa)P<{QAs}$e4.%k2br6;AB%T  vY ln\yrI1: a4V/э /ltIۘq' F*= 68&RI3-@z>oLuWTX+w6 G1ϐN`48BAʺ KԻyZ̋1YHk!_|E2 8RH&kp>1 6d0i]<(æVW=7˪Uj> >XӅ,:Uzz`zna|7`#1Rs5k+e9٣=b.V OGl%pqn<{\0BX/~ ʴ'Pga3QS &@];*<%/=;>]ӄY?lI\ /BPCO6mdcr)<t3qK~eCv:Ė]ǟ X;J݈ƚu(F2Ha^j$;+24xwݯ3~Qv $Zd,7iq [̴hnROр~EZ寿ju%REF[~T(iWImWJ"@ept $`zfjN8,$v87%:  ~xWoj4~F6ʶ<|)z V><\|JRB7!<܅ :kp'>k I lZMY{4mEO K&8IAp3*/  Yngjc{q&Mw-NNUZQa)p}X,O ϙ^Vȶ}Ylgl3og+ cy/ [*M|hNi%E'vA0} TF0Nڻ{)0-=hR ϋeO 숁EgϒR1e'Sdo>Bj> `Ңp(E؎eEi-~px&6I pI7Tiw? ,dnh}纼fg[B{]3ruVfR0x v/b @:s<3f%P}h j$hGTNq+G+7yBm;\w==@m,2iWFfΐϡMȐ)3qhn%A2tpI<(`*QEz(9TF/(AD48QƘXь~ٍ)Bv S!N0 Z _b' aB.8H2RTS3\Irڒ/| LS>:Hn:{ĞJ]:Y[kO  [DHJF^ >}:<1`TR^׀ϼ~V}?걿n%"Mbif5]jt' ?W;Rp"jA磕ͪ<1Rw3#iQQM_ZjbXYXp|> Gp΁m IJwFy4pI.40ϩv1hwn`YjڝF≯:,6`{{:W_yw[}dqV0~L&ANK(NHH$ϒ$=y"؝ݱ*Kt6"`:-KJv7;x(@;𶴿mCo#tngkyT3"6ܯt,;{mیo)MB%)*6 wLKO;t/I {WCdVhۋ/]Ew|{ A{ ҿ_AB+b* @`|{2dC"y{d47 Ø4 9x٥pC:h@#)E^U2 6 0+ ƬY2(bL6 kE*RBf#Y2dWVDX xGiA.@| ~yA @1eQj2*Fdžh됾^%y vaE xý<=ͦTv*4}*$Ÿuzٲu(9ZQɅUbPo0@A%k^$3^Dn!')I]l9bwg9MSIJ_bcf397t=)k^\SA_`n bvE)YQRVz;%$sM$CGq"?% snep5'6`2 2 %ifBCtH^yh/8 (u˵Qwf"br 3|N*`>\Wh1xY mq1͌p]pYz7w{dUJ|N5"|QQ{4MdCLKKJ\J)685{a7Q}>j׵VIK^ k+$L `4PF / w{´n*0*Lt3^2qG("n 홸Z}F7rnypi)H hF": 3%TNO"銨{KXI; > Po賝S3?A}|K;һYCQg T:)TiF$$ɦ(Մ2 OHVS ́Kj/T\/Efsf{N>,@0,1#k>bU^4+¿ݮca$KA|iVЬl H흈 ?.-l0-3I\zdz7c*3BY1!d#+f-gN[KIؙ`WMUt3l2Vn2^|dn/`zJ QCԶ$ [5;l8Ð #KRqp֊;>.eR"hx)ER9W]U -VTnRmf5Te< dZRGFOV j;d~|IyH"<$T qAsh9c]NރTf*8Whj@ {ΛU:!;IY~wFIoշNQ݁>H|9Gy*u:@!wI\=oHpWq+%*b=; ~z;>W^ >vǕ562%Dxɀd-aƼL}s1L۔_b_I4.zBCes}]V].Q ;w-/^Dqʷ pzQkMEH&k"O]!vHȯx0=vkXWJbW/;xnж1l]/l L(ks>C9uC]8ZU|Y[q4ͭ8Meo"ޭvkAڼepm&\"eh\^S"~%o0=Im@&3Âf ՗L8TsƢe[Mm>ѱíB yYu4+uR1+RFю-E[J4g#C֐yHiNx9o!5]DG`:-{W 2iوS罆jS` 8Cz𒞯ؓP274piـεI߯tg]3@PsIV^# prHbnV!+8-tjhQC rӡ":Ŋ|ɄZRZ6g|"^on 9MC2 BH2P%=kYT5M|n&bpQ}"}"Kgxn\d B:!Kؤ}z 2Y`` w~zW#E@CJX))7H{I_Du/܍: 'UGP'm#=jn8rMSOȟP.A.c$%RD/t& nXM W&pZfT`l݁VTq;^ 5J.Ijd'`0H躕/K7,_A]e',FWG](֭:=zC2\G@hh(hs|sLIA큰B)~`_92Z9_`z9φerMϷ7Wo,s"Uzm\!O"d\7?T|x.dK."[!o\.ϼu\)f {̫M}X4U_FS2nơ- bNra1yFô;y@U#{ҙ%}ZGmWQmfMT]j-JNÔv`TrT=l,1,U%~Dy]jVDeAaars#ãZ 7š,gUVm#tje7Ʃj\+GԪW5G7h9jJ4r;M什4JTR:,F8n5&Զu\kC@8F*rrRPVr:MI /OL Ŷ%ƧU_;Yj YҢԬ6oHRw(L D8,}qoX[Wۉ`ZztoB&r+q=/wGj9u*raRq_ ;9Mѝ@Qn `EhwhZsP"d=0xL~%Mf B&uR'`YQ> `o GI4i3ɢL"U \B" l- #AxDG#ʄDhV/"}hM\5sBw_ ÍNr5I-872eLU8Yx¦(hBmrJ0elR? t鏮> d2Wdwƫ&O.é^:t'^T¤g"a~>:n'zZCo[AWe ߿'~ ޿WqۿFt+y+ 왚M@g,\c\޳x)@u=Ja*`!/ݳE\jBfOZD~ok4?+յXb3#{F:E]X( E@2Y#ô),A[Og@.VofRSl4N%N6͐^wE¤i6&K_uGfW-mm{LKfa] ?/DO~3`D"\ǟ80OrpyL , =a0y``T*Vo8G K(|mFWB"F:X .4Q3܋lnK7Mq X & ^_F/) `"_A[?ӡfhFI" t7,2ۻ9|IU{=<\p$TY4 502)ff6& <fN 3Ͱ !Ј7uZ& caR;8+n,J`69W?uV7w^ `c޺00\ s X!g$$vЁDV {0[NFnpXgr_ޞFm Rmmѯ!UU쇙z4m"ɴ[Op\BY\Nū'5RV/,E]_|'E;F e}6j踍'/qaZ-3G UkUTK[N'LG8ۻj7K6AA{.jZ 36PyL!Zm(T[t&mYLiRK}~*Ȏ7-Udǖ_ {-g7N t1F{s2pSw0ŝ}SV7> o0_Q.ai>+gՠIَk5WԦD(umd6=t+BS]r3*7*TXɴHʹJx?S/"f!M!U)En@m{a |lc& M,=Bzi6T\ ͶA&Ro@/?ˆ5ǻ0 7-GQ|aq@Q M>/W!_7-I\*IW2xV⹚ڠӽc[yj678\H}B'V\=_d,Na33\yݽblaI˒Hi:ՊMүZ!;Vl@f\w%z>Kȳrp⒛I}c_3{>@.i?l]uy%#;%tl`uUyDL\\κWInH=?rA- \TPu'&'N\F&BKWݔ" e5^awL̃gsv+wWhf+%(h gK# D# E)yu'#"Ǘi8O&₂\ E7,y!TX.f6|rtfj[yIIMGC;l4ZWCv3#Cޛ7q$ÿѧ$$@,Y <GZhđgkft#X3=Wuuuua\LzC"Akz!m彠O~2>F%QSp;0ApIKA<:;'isYHeLt:f&n!6H?ivqfLH!Ew8mV\@JE^sfkLf8< , = Q} .=jn МD !6/ⴜpHY^RFhΆf-qV@:*o<<&%{']C.SĿNΆ h=5C%/2AvO)Z|/ d`ȤHK5h64wdV+,&˅@ YOUq#7!p*v "C͡K*b#(>)1߀]Fk#+\ԋq0a>s0(0lU."s[W6Wt9!qm׉߷)flBb\Z {Ft1_~UfL9 m@ S s1(3<r8BbL1l0G.u9`d;y_GO)&^+zFrVfe)X#l/=q.׉Q ֖3@G2nqpwDtpq)CbbJBccZEs09PdC؏Xb b!(QyyDSsgyW} B0[s:~xMG:1'9R' G[j__F;Olf7@ꓠSK<#(n ߂+4uK}ZGwH8X 0=CxK*)()wTi}*jV\RjifDo&BoDzG9 *u,󸧭/MW/P? (Ev+i7qH GKu.!oXAL |(*'-6iz(V ‚aj^WlBȑn+ۖUPi(Zqo/tLA5NŔ,A=1~B7Z_+QWhEd0wދ^ n(|f<@je(NC?Rજ@m^ @Kh:#ZBwDgifϛg(~j:Έ$jueZb3}R`h`nOU̳^ŘzUu&Heޛj-}]N//|9EjWl’udĩUauO]"9 u={AmsVV2 x,nČ'PK"US$raWy~d3$lG7Iɖ%唫*1Clʉm1CiEg.3G\̂ӄUӐf0>:5w$0>DenKäJWRi2Ø,=ɽwѸA#v8eXO%/qt F:\FRC)SBS=6O({ІBg/ ԬV2Bz=7 Z,1r'?uÿy2u e_Ht1;8NwZ)qd47cfC%s9K8r)pާ"Mz a)W"Bښ*-{UZ)~ZW9)NDlXZUD\JX13o{wO2Nk{ Ok4DC3!g9-]X$")- C>Gݲm7!ͽg̎aS͉H;j%f=S Uvb v.SHV ؤLjΓ zr;&iWٿ- >̺) EeœsQJuCz 01#LP ,Ez8’nn NÌfna_h<+1-Hsnt_hcagE@RE؁0NUDKp02G 6j/&Uz|2Hjh$h0@QHow>w^_"+,Hn{V#r EH@, ˣEFsU `Tьqļ7uV.blQfeˍZFE]o!ՐO7Df';f$$d \c: Q^V ۰2uxhUo ^.yF*& tJ,6[̘A /h^OIr~x>Z~^d -aEr 4Xn+N-uJё@}hE *Fmohny8p"Z{Xchu-]CH,4Jo4;1L@D ,aF;mƝbj;zw*735̧N뀁s$",SUh~]վny#7`~hՁ9<}?x0tEӕtF]GP[8jBeWr}m"*m<4wx]y҂]ǮkVlngWn4W~5IyC@Z!԰੡QO<"~V[^4= ^ 2j&ߔr-.|əJj^3KSqΛYx]#CYFx%iZ: VS#;Ȏ6wdˌ[2<[~kLj¤6鍨f cn#@jS0{+ƜIxZ-cҌ^V_~P!a2Ky'$ EJng̈꺡p謭<{ki%K̈ y w枞_Ωm]Κ`ғgpwlm1c8i+5f;9/#ۦ<ԔӔ5%Ǿk ԬXr} 4 Z@H"X8doeën" n>u*FO+76y=k\Jh>$ 7U8r\ոe~k甖Y^x[x嗹WI=06O۝=>:[&lil T33h/y-DðR"ӑ_ {k8k+֫K ၲ4Dƽ]u$kW{Q Ҕ*`|t\ Iz~uaoԻ GtߗV Y5#ǨF@4++5F:rZPa v{Ǡ`d!ܷ%k8NֈV:i(th>ê6G6J2:Ն}Z_Qp'S B0>;Yzl܊/0eV9K?@E힠R651qk Zq_'audDOȳzIPEu.OsЦ70u+ ,5xuf# o$Gjx q'ŤcOkO[N>W\8s{w.ӛ.V?X"^|1vD_G|30VNyX^w(rA=V5U6S^J]$OQHBMbVC1_{hx{HB p>ۊ/G6wx)jxw/`Q$~1" 9.2kyMGټ=\5owqm#%F\KU,ܽI..ƀ64*o0Sdm)(<2GVs[i4$Zp4$C*f0 SQ!9Sy6gD^A.^8iTzYE}ţ% C!eL5_@oT*?dT6?N!+%c2xe dYL3VF#" Ytw(75kyroȈ1JWRwUrвs7ǻi;{Eƶq/m׬6bڻ04. Ȁ|.<H|7=hƞ ' ` rlMl1ںDPBWk*Bb- ѸK.aPh! 㔹NUHǖU}'C뭃D&9y%Ja8,QT/\{ <48]݄ROvf׳c[8eՈ* `iJrX>:, 4KR^2QkYeֱ\s_ 0KS^'[vON 9[:=:>V)qFtœ2tRai)zPRO`95\ :z 5i}/(jB7a m m_x(o?E JS!wE2r0GG,@,:'e.իx郔p8L߀ݜ^RqOXԎJyXW#g&qF^-`&U//.Rjawqe.sYadSC-2݌biL 4$oqrg}ox5&xHٷ ͂9SMCIdX KК j/E1Q6X~8]b9,8nM8 pFVġ I.IB`ђYP3[h%Gj2RGu8"y N3c[ٚ}Icu ȵ5yd*Nm7ͷp9!='Ejx2ѱ;t_pnJ<+c:"J'j/vPO=W53RDвTPǐ&:RH7M=dAmd<9 =n[H ߕm:ζ69Ә>1iT29D8n3}nn4Knq= KիW5[,ն=)jOEAf\9m2c$ojn_Z )vq(Ŕu$%\SjLnؕ66(M}d7iQشՓ'# n8,!F vMM:ұ{dU(?Ʊ{LMb$žrji4 @tJpEW_Q$@~uCU(daЫ gBL-R}~H-̏KҬ@^@5_dÙhJA伌 `Ye1$wk#chNu(jUcE/^GAVђa>NI}rk+V+,;+utt.V- ϨkB !b0V釅%tP#;:9Y|1yPɯ3-S+B5+&ze *y<b^?rYQO5iP(pFa26KJp ;9F%= Eq}2!3:-lT5݃ GM-nkX7>>&7bkHJg0GʍC%BaKQbhX+Wm g Ϸ7ls+뷊T1*-goEe'јM jHt`.(r:.rt7Uʈs>XH{~ӍUI|0|^dx>6ȳ],༣~u3 zO;*P|H1vld ۂ+E!͞E ϫgd>Iza b2˶EB\lMiQ5;ӚĶ}Ud=_(pM-Ԇjvv )lm\cjBvyuSn-#Ҽ5L!7|ƚw~IgGz3#X;u3YU8JfQEǧa?qwpN3#$l>~-* TTI0){/_llx\4H?|~`#fo}f|SD[t귂5}aWL')CT\@6J4rPay ~wBcrbrs\u%=09NWZ}yQ-'#$X"/+FҊxx U'S@~bn\cxWg7Bs6>r>m.%co#dV!8s6oזK_k.pGQ74,FyF8;3#>S+Z߆O„ xRy7(K~aP"|ܜEF0ƈ黽5ĨC\7.y^r=otilLԻQ{K4Ou4$#%kگe $Mrc2Q{_b\27ovmxF\41 P] d#M-Y\sd$sw{O(m!T}f6T ^4ۛ6雛N;I 1Ӆ7Nz=Fֳ3yHßB[ ȪFW8C4ޔ.3r4me@ٙέ!tZTzU X+OhO3 .LI&B(댼! vƚi벜9rVWA$veh촓8ăqZӶvt ;mzNVx?},}7 qxyh,躭ۢ.c!=LCB ʯ+ i_C#-FR_᭜ޭY3$vuch]ƻ lJyZVs]5̻:V20Wz2]cdw3DZ2~3gywʰ0;Gc"G13SOQô.{ C&bcP 2:M䥭o;&̞ɰR'Iw?fGu Ì.K.ΦY죦TU Cdr9*}6VJn>N5 sCnm7ok |]rZ$G33h47ǘ[2">w$~$LyYRih U2&,4@qD O8pe!LJ6Jr 3^d*,֟&%tZ3O­Ӿ29pЙ;R:frv*ޢrh68OYgUFOLbԠtؙS7IQ q=X¹#j;}w†Rh=O(xiJha,w0!7z3{=\EYGD^xz}[YmW sV 13H dH:Ŭ= 5TAbzj&│UPW$2Y/wn9z4x*pgzF=)J|+d8!Z` EtS379ڣVH\ "kW5+sSv#.`GIժ3vl"oixF#tb[Y?Vp==hLMP! ѷv6ePfYƭ'Km**=#$\} a`Oؾz}9`dTѻX^Yt2[,B+5h㖨;}G֧Ut#'{ctT[UɤK)ȿrET>=ld$K'Gey.QfǓBD{f I Xsr 3={z |DRЌ͓ւHPTR5SOWn5MYDe8H z>^J˘{}ϐtݤi6!ӝm7Nx2or&ܷtPyC2JhUӟ%T:HSAKVް᧯| IiD") N;}e8={c|/EȍxQ+-5!JM?D)bI%a2!OrjRթ.LY"7[N:BWکb$C@HEMS~\^@~8d1*W UJKb>ۏ~ g?Ʌ4RXJ׶ Jxqd2T͇ԗ eW8Ӫ#Tš1/c+1CWVk;24 1Zr,y* N~7 :ɹ6&Mw6<48/5[kf2Mʀ/X,.'۔j׸^ֵ W!h4Yf[HTѸ\#B~=9C2#7Z9ґ\zQz٬1`"]ˡd>a(]lR$p;d1WS ޳hy^;V܍ټ-> tW5^4Q ۭo M5U&i}GH >S,L]҂%HA X|ʨC,rb)f9EAC$]Pyɦm=U:1i+r )@-}|1'Z[!I4>ץGk*RW0EWS`=2:=qs.ln KtPḌ!˞Cq8|E9Sᑢ3WX@tG,-fz=Xqlv-+DCe=[6Cޙs8i=:?vN |AE-]Hzb![2 8f~i&"¾[Π[z ]'Z*ؓ=C8'Ho&Z>08:J ވ}w |$)ZEoDem&-ŃpЂ~X_v.={4ղ^(MRya:oi4)&b,#d"Qsk.Bv&/- /RQ&éV?zQr= d͘jf7DC/_khRF~\|݀oMsL;pUx.+TKT ږ>x{XM :ወROg)M7fɢ``Z˿Q|}ΙU<7s~ ߓ:'p0mrd75/TЇJIq҈:k\,,J 7QިACZGF"(ԀzJg -Mchv>͆#̆Gzɣ9k"$ı9̀O6n@"wtJ! drB!jbdlXQ04_p[#XP1vUJ߮Ldr=/gM+m"]$XCMZG,>aɨ_uMD茜sHK"$9:Qr9 Z(Ţu~ujc#ᡮ :^]:'bcQ5 r T轀ޑ>΍y4d؟.4b7|+q7ӝgjwm (нv<d嫠Xqp,T}fEb+`\zWVkE]EQM+$9!#2YO 6%5I+wJA 4rv|fn*7/-+U)8÷U-Ъ7aw-0g.jp{ɋ폮cee }~1ﯪo=vC? 7o MIIә䯰^WxM06nP! @.F&G(d4:.SFx 3P%IHzN1Zr_q JQqiAIP# `5( Swz]x<*pڞ!n2Puss2ͽ 8 Mhz,bcٴI<xD%lk%]PW &yAC}IKEF"/ÍIq9Џ^6ސ" 4,@{l ʦ$*N8`G2!l$ и XI8[s[ePؒ!רǭq τi>K|(p1ꂰQ1riK'EfpDgzHvcLK*D: Q o47z@zŴ1ƝCWiKI*G4xgwUQE[o5[t+Ž.[%$!%i uav*j1t:zCĮaw TσMцGab;8QUJ: 7O1=L%q Zx "L q[77AQ{%arca_͆- N!Uj=xf!F1Lh[ߨۥI>JkbLDB쀔ddgbЦbW4[ 1v;Q+BO\/t⳨tzQUժ). (;b"f(CN""2p̿Z*ĘdbΙ3g/]eЁpP7;QK! In.ŵ$1CCk:AMzv_8eNfoϩ=T;VօըQDbUl>4nVbQ Ns8EwQ @|ލjQA/B ꪮKMIpCP kv6G{ݶdv4:`\%4=π8"HS HK>p C`7.XǙT͎L}/q.,@;@2 :g-MB- Jh%cb]*mJ QRZ[$=Tx#l0$z! gPͪ 7uTaޣa7jÐa c ir}SF ]&KOb kkdofTlw"ABOlB &i%vŀD_0#AY~vse'Fè,tx{`K۵{O=7?0ga⦚Pܦ)k0ݻ2?!wZ%e@ lU@( N< PH啇˫?W]_oHe1j$l0@wM"yg/j;GT <@!pL38[3<8;Ode'_(ypţ{Ż>[Rf$$r̷b"t2Jnx5oP׊@v!^+# wVZeq_'r|P*($:Cz}8=vR7}r ηRT).k<6VW nQgl>;5e,.^n`, 8 zҤAJIJ|=i߭;{~{G% 9 찎B<t[Ty'v *w`ae: ;/%us,HM"c+]O+#4xK_'#٤Բ-|AEzMM,&dX^*<]b=y2LvC5yytD.^hjxxXnȐH; H֯T/w Y|COLZ_ .x@! ʘ^guhmm<|+tp2]D_&HO`uMNHzo}~^7{g>MSUبLT⺝^7mVQOE#.XQ/)ʩu ^[a7 G08 ȋH7+Xo3)r f`Sqa4e`vR0] ٥wֱ{z(ظR[a_ouʏ;HG?BRHf(gPmU8|ڸ+Gje}bx٢ #D#]ytEJA(CϤɻ qwWS"kU| Q__#f+[gN5R%7p`ZB›D V ΠNCCk>nBW%lچlbL@{/!|DhO6_l>Ε 4m l0 G;/ճ'G m}vh^Mpgx~hngx} 4vJ?Aߣ> x`mH?1QıX[ x;U{vwmmm}<9 ;\O>dAA*My6̀G;4O˭2쒯p'P|'Owk dBdwʋp@@0/lo4;^P.T'@ 1d&Ѩ/iH6wAՑx@Tcy"#;~*xgG $ 7DMv*tsgwABҀYޢv=h &~趠b 8A[dØK#/of$[Q`̨gm^Ppx8zѻCUэP!?HV!~eQ )0VWdLΉCw rp4a 0C -OM8ZX]ҁxo._lZXXSIH ܄uʵp̫MYy*d˕TM+,S~ wP#x fKǒAx)9Ȍ8iy~`"ٓ PŠ*ICJ}N3t=m7o-^ @bjHj=̧79dcwhx:l*IW. pc*VڃT:R{kx{Oɞ:yXd;'ps!:IVzi4EނaiL"ےv9.U37] 1[]>0x+=lӌV.1TOԄ22|F-tՁ튛(6HP<Jx0T|gM]X2{38(c z[kw]՘R|`KM.Rl . l Vs}KM#p;W V@NR")y(/d\l9}堫ڔJWʢ =!h϶ D+@>\|}++ *^)4TYV!Rp# _qƝ[AJ+ \4Dv*&?AqBh])V[Qzڣ$^$u+0[ w6whC)yhxh;Q-5C; C Am>T*iffƁF8؏>Q~3h"DT81rgzL`1s-Tԙn'E eiƒ':12P, +8}贩8 l>9N#{HpZ-d)=ghN܀'QUa斞70 I=$}qRC'mLMyX/5!WO-Ȥ@#/h(!SI!#俌oe` |4N9D.R4ew Q\O_tpGa3haRd)?{ofΘl{׬و1Q\Tm%r23DP6rn NjBq#n^aG5kk49W0 dY}J#]va _U.h턗o m];`4=9 #@ɂ0v'r+qmi[ NTðz:ŗ-a,!QE"rhLA٠uHM3`~vZʸY3T͚CD! ~4hC:so) u'Oqpݜؽ;un{4`\}7mwZxNj%U#8f:1)]_T|rsP}c) 0[ptިSKt1jfn D :X +]1 呚0ꟽP<'UJ_E ;q5N,pO0貄5yrffPQ9I9Ƒle>/'O"KO )^Ea G~q| ;ma+[[ڙ0#٥arl#ZTe>QYoo:a$}8$dz64Tl]R΀K FUHXKqgYR7#>0!lN 2P0l7S @?C{dtڷTjKV2n dWP$jC' ;mtY䉏^iF wd`j"!8[(yR S񱅊 .YORJb# 4Yccӎp~<|DbP/GZ%v"jvܰzZ"w$~д> ~κaP_w[D@}!?A EcJ>6|"9YV륛:e$h4eT7u^&F,Mݢ6SoʞܹFFN@ZgJh9!gHK hsȭI5EvnJB1G=PKZ_A,~7xSUFLUpr~^u>XɁi|t$ "]΋/6z⥏Z:&(LBzS#' .dl1XFvxox9<{G6g= :Kn<8 VkB-s5Mݮ!Lkx."E4b ͽH$1]/'Ŵ!T&f2YO;〜.Dww%%$B5F.)<^.X&BLWJ(M ?Oc2s9l`Sb%08Uҳ>΁M??I m c%˓Ȁg3:k'kTl| /hwIBKPBA"gvm웿`Cf1ZȟXv,S\f5sEKYS'[NұNuMPZ3"cNGVSPCּZ(N{ssw{oaA[^IХʭ_zEWHl qP첊i!\){r2wd7`r?K\ER2~`u퍓FJ&zAnp lM1pE9h~Szm5x<)9)WGޓD,ak4t/(^T[s8}%" f㹢K[y]]7Gzl&~]s5\^l?P VD؉l'V;нhZMI$XF%f:z["YBUlU׫ڪګXUiYы֦ʪ~K)m/ SݴUZra=,-KUs[-@PočdűUZV i>ͅ -k1ʙ*3ID2F̹@3W"M NŹq4K-fjIz056v=I5v"@t^pJ2VCڥv_P;!u 6#+ I#qvI!JH3,0^.h)t tRaa]fҋfT]T{e0z<73ץ DXV&t`oCI}fQDoa>P)6S[ЋK"ިϡ0ʡER>"= 0dtRKԆ\8>ifE{=W\1{g+>ٽ_.zixۇw\xˇq;9;.CU@ovZ3Y<^b PB$#07=\vKa7Ea8^8,kKLD wQGۘGxS_*^<{MpT-w,Z*KX^Y[^}~ux}W*1}QuLY߮RaU]7ZW(T 1:PeҼ W <@`X'PK(XC֫*&:D aP^}V?[yZ$+0qAѢ1FZBXm;d멝]er*Vj8>;jmk#*ZyS ZuZx& W*HT2@/"QU~<+JAKuڮ6{,9оp@Vua_.Pt6Pv%($ ن, D*BM;8vn9r7"a=^fm^vmGt7yWW8WQCSTnC $E6ukͰE3@LI7y0V2Hӧfuֱnj14qniAB9X~f2j^5i2m8\ @Q<ρ:{6}p.C#ߺR^8 δ~hQ3hA;ԕ#2D:WX +XE}dvZ:坑Dw^ϧ|:U%ՍNwJcwR9, t}Fxb8icLro'X 288E쐊50$}qpӐL8J6l㜊:nQp]DgTלO}D2ӸXjoi-4^|zJ>*Ce$|3:<0@nB-}[9zŤ;Q[.''[ۛO`S‹%%aB\7nIhC 2Df%{~Z}<\{p/mr#|lwE %lPԂ30ٻ,0#Pg{/::j;y|s3`逸8 zGF.]STTIkȎg8` E] @5e Ѐ wT-Oݹ^OΡ=e)64qKH*е*.zEtP/F]伢-nkYy5/^)8cUF!ap[[\g}=޷Ω|$ZEA(]R=dCdhG(;GL RBx3 zߌU?Nvs:Qݭͣd K'AO_ `z'iS@U~x!y/h8QAҤ @x'`4*GGAXW_Q/SzaQV{?R3蟃煃FiQaQzDvTokʥ9I󒂵h3%p9jw)rpzşcEqrlvlmCڂ6Тף#2m`YW65P^vukU Я)SܫƖwIܼ-VbXWORvG68/hN4z= `uU:)'$| JȂrpР_٤$rѭQifC=Ƕ3[a@K @ַNAX+E(PP;&`ԗOʯ^~-TKwh^LN'1_u qלqXW;M)/8,wuyCSZPjWÊd@r$I4vTzwgo{o$RfÍqzrѓbBs4F)8m7{v]$ͯ%ɺ}| Q|d;{{xtǟ^?&@]*YHVYݻN хB x@zT FnK7pdGsK8"~r?E:Y+y[Qn".CQ\F5˴7갸L[R~KoR_י(Zi-IZ]8!jcK]Mr)OX_h5ܰs3߃1f 7,±6ޘ P;1T\t!VS ^PR_\QX᪂CpqNnlWJNyzX6=svD['}m2;0P%F|H8nP/Q$h(Wm:wpPI0x^A|  QpW[/^l=)1cΏ.8T%=wkݡH}]t:~5L_uvE\h0;Et)r+aV peZ nӝgͣJݍ[ ҞTQ2I8Zq&Ȏ# 6]AR,7Y|@EUkҟҔj2vt@Ȓ[t2m)Fi) =h 鹑l0cөCdO "8KExo?P8 { l%V` PA5NCfL`!A{@BCLN׬R*Q6׭ah( Ȱ%:"ڥ4cW T6&hȮs=`/Y/lan`P=, A{(q[QWm'oq+AAyEN~7 v]hї7EsmPj {5[U JW2܂X{TC3%',^z :1曓Jdd a}صjVSMOiq"<# {U+g:y:vX4sO^ fzP<Er F vv4Ab9nx0 oQbhe*N\T6_B10}]4@d >I·0Q9W_ƆnczoD <EE4fx!<Hx'-)(eVʟk=%/[{ j %~+ݺ%*kNrjݯIuB I? ?n)w/ſ!wTjuhPT Bzb"wrJFlG;6q\9jFuŸW i|48 pЏs302`v9wWt4-h{@wH5 ^=!p1oHu(~#8ƧQk'0-E.yQxA:w_(o.\`V/bt!.9BĀqYb.U+Ƴj8DȎ~7GSW/˰M|{ ]0rM| za|Ʉ\{E_4ɨ>\F!Ca&ކ}7 &N p&F\>[Eh ]!Ϭ$ 0$Y*X(.f|#qQJU#f׺XDq%UVʺaHjM)$ھ> ڨY*Xn}4jbΞSvK +ʍ8TcT$wP]x;)x|1ڔ"J+UĖ R'>MnaMj& 3e-M8k">}NYCq" ?n-ky \@/O *p Hmm-"j&HMȰj{ձ?Klwc<~us`?Fbq@VZTw,O%;( M[Un(`_".e0o#&l_NXF) d .Df|e"Gd(`h6Ƃ:B/n9(q7Ʈ42BHXHBM %FF4N bvdMH'Bv%z'Rgi01w^_()R\ ܉cBH߆3t>Dz|Od6`[щ oy%tiOڨQE-nUVPоzxӀa ɘ }4!A> B,0)`~F'mz]~ViQ`[LRK.5J˙BT`CJ;$\6Xj2H] bf\4{Li9GGWiuqh*.aP7 _tT!>n> My<_f/=ƮltBbusS%6jGY75h.=L(ԚBZ<xR$%', (mDktb^7҄qghWHWm3;Rj}qyz-0;5jL!NRL3NXQ>' (j<.н7yX=RvڬoW4RTRڒ.c ˾CvN |!I O&5֗^\!EWxI B Lq]yLM @C)Y-7d,=a9,[L+ƛ4MCΞ ]jƆgJuJQrDJ[Q`&L2%[S0=59J8'>f$}qW^?ȯO61rZ%e-Ϥ8$2ޛd?'MflOE׾6H_ 3·&i@x$Ϲd{r$<>X2g(O烥`rĻ ]>Gy:O ֨ >8bi $IO-3gPK{9n͓~TqN!KR̜~v'¼qb I?G梺|Zrzolmp"G7Rqlp_gɔ-P2ޛb&yCW`OK&Rc~v䌊'9S )&ܗTIhk'Xv''-䎯IMgKg>'3i^&[,~4OA~E)'r%|˘ I&9ҦW- h͓~o~v8'y?hzLg_ghXF\nfONʤuSk%ӯi4٬t9f}d\R&%hHL#(#(HK9-KALfͤ#(uAsUc%XS_&>Hn9iY3)~6LJe_"uy?I|8 O.:bc /[`\鬘ɖNHnv5E!3C~_ѭ{`JK?'cI }4OA~}LĻL{s_ggSIm2)yAŦ$ٚtB@p_ghܢP2RN?QuҳY3)H~}q} 惙d?9syqR_d"/ԇ9 "h0p s_ghLKc 꽹/v>>' Va)բtBu1Rγ}4Oflqce**~4OA~￧#IҚl͓~}ps>GĠ1h\1l>KֺJb}?d% WsT3]IbN;|s/9IrH 4VNˎ,&-|?2 pk/߮޵Ku qޛbhG|jښROHr\ y";Yz|]3jRnܻ4S>'8[9n\&%Y7yv0m g#Y/GJ;tpˤiGs mhGy×|c$ⴭW:tVs&c&L/AVТ勺9K^ZaRЬ~c(0nNEҷKf$瘏QwxCX$[޴zժR EKH r]tIHa2XDnV"'S}SQV"9 'r|<@hW㣕ёVŌ)>"tLU*Q&fSi)Su"{qFfB /qt8ꋪ%0#"?V( #<,_ Ѡ*.p:ub8 ¡al WIh4lK7au ]}m MQ<0asQbvDh=!: q _~sRY^^2'C wx;_YWNC mD03 f&R&9(Ae$;A`qrx0,>%r 3? ]lV[2Lkr ۱m [:ǝ:7!N.„go1 邜txa,>jRv.G} FOTͮȹuű"s66.vāW^}U%up֘Ek⇹AG=?k7]vЦ^(Ƭ?M^WT9Ɯ}*GXu_I۟/X4^((?@рn 1^/iNL_ا;J Oy^\lbe~oa* .wf9CVt/hdZ-|ʓC]5v- ěBAcz}v„NRnÙݴX;p8p4c FT50gmʭ$m~>6> 0߉ |X (V|B B;qBr<%n$Zਯ //K@5BSq>n.!:y)ӈB JTvZ&6+DHV31y0D].۫VZηa0֭AAǪX[7Idn ŭ;Պ/d<inR`2Ü.0ੲ@saGベ%/5l`jgzurmKYe/_d$ȏn@,&Zpሙ=qϻBڲMݲFqUS:Cv}::ԟ "UoaXyAYAyR;Q[w"!5 VZV H"Uv-GNƴpFmD)Pb`JQ["P3:rY[dbb CہCFFV~6ӽ"Q9gÕٚ=&ĪĘ/xy>Dڏ$_Q'W;|ɢB5ɩ*p.ƅ{]7:J}8BwH&IR%_5TM dOxSNRjwԦ*E"R6 WFdm$S2 PK0ip,1IԌl^luIy6'Z 0\ףIS+nbǢ =|fn<[6R1 7 ,ڳKҞ"pS ϭ'r3 &/Ovb;pYq:ęJjcP޽Lj@ SSPNv̢Y &RzvhK#c'jR-Z/ nφCG\ĺ.y+)^sKU=34u-+r1pfs<r`Aj7Iէ'| 7f;jx\?q$ql)*Jk o9ǁw6RlJzuy\dǪeCgLЪOw--mTQc3qNA/6s Ӳ(qEX2Tl#=dƜ/&c! eX.u}xOBJ/^ƒG"ugoXY5\GՀ"h!!ıG' ӎIKL$`~3:ΰ C|ΐXG0HVX8W \j 9q, 㱈o-;zI$z:-5nv>/K_^8޻^|3enleL2[K2kY t&u 7/T C`b ?eᘿlt7f /)l><@z $$12 bAW1Ӡeb9'?~q /î /icz9ӟ4008;"u(jD -i U9@6T7+[^+ 1޺xw3#z7 Q? Bniv q@AC;vF9򢽉CP Wu/aPk鈱T^a$aUުڣ~7QkFiKzqXs#JiIȞ/Fɰ Ml#aV#bn1D dXr-`Jj9*Ӏ*.T\_>ys9Y<䛓I䷓'''l|䇓I͒c XKdLPjEsq1JR)a5qiꀐy_ `O c If|iǥ!.P౻u͛#.1kLsh2.1>zYM1cxd$5l4*.eq-Չ9l3QA PzZ27iE\3o_\ SjrzNMN(pbTq'PhM `4Qۄ R)DI𗈍i#0 45'.h2aBP/qB_ կRH;'ґF=YԮmoԇV`pU)P`أˬEw`tf+Q&/"+Ψcbcaztֽ МD: t$dk-$ǣzR=6 {*k V7N `_UirDtpWgQo;#بhDxc(#qJDͬ.R]2mu3Kj Y>8ߞ}Y/Vo8Q+PY]˳Q*ȻI.D7OqG K">pѧd瓓kn i'' TONVtS$9\ԓĆE `41bo%2lʛYr␊}=^ց`:kw7[G*;*FUݓda;9QjdXR;I|!ےc[XE&cQ@6qƯ! )U%C1;ҁ7aXՈaÖL7$$q+9-/qDG!zOrTwx+1Yش013b $2ډ?Ew 1(E~DAP-nh5v<ksj Dڦ`Ȝ! <ڛ11Qw |` |n#-rVpk fCYPAt : MR>8`xI+]1$_Z$iO.ꐡ}l҇q@"آS!BWDC3e#J*0F%asL>">ݝ dr)B]"Nazg{Dp>jn\}.`Ȇ[YÚymN!ĴP{}杔"WŻJ.c2[?cmALǦqH". *,cIQ/>5Y],Jú>U>dO=d>T\g#=Xna6jC~F@8cG'p~])VL?h0`o*dneSeyjdnx1C4VtV4Bi|}TvnELߌmiI"*:}Y9AVfF(,p" { C-ʠuSL[_$@)0s4e]тS2χ(ۄИF6ἄRe3<V4\]Rz=l "W߶TĂ2"NQQrřB̗-0)R5gQCX?WoZ.xqO#ר0ABn+(VH ak;8"$ nōʃkj,bDKbEE_͈ٜcrǢ7/lxS"7 2v(G o`z־?VV{g_D&K԰gbс<㓇mYIAq#)ީ5gC: /E1sgkˣt2 ,H[8ES/h)~.k3N_vum?15SV~tMok ' Z2g ̹?+9O%o;Vs` _ |۹`DOZ U$åQtp0(]45,r{5@gdD(|IT`~?VQ%slw=u6D{ҚzM>M&fp脱]_khk & jiZ<_Xh/|VrZ/7"}% B!$jm[ZEsRtJ /[=dXah3"L\ 1MY[4aI߮WN:ӏo׏t6(ˎ%ϨK--k ,؂<qE{ B.XJ7$c6AÅgNE ;#[cquP)> *VƵ6Z<* EN:e%`hLpoGYebhJGdEg4qDGA\MfaV(v%[8nK%^,-/<ˊr+]CnϷjYYcTe=>K-x]ؽ?b!7 0j[S,* $KT9/U{#Ga  `ZJO(F"Y-ݪ8GCT ڈ] dL6l >^\R].vcAL$c1703t86{b͓&,\T Q$u~_ژ]5,l]%C~VӰoOѿ_oWU w!IbD" ui$k NBbV8@J#rua* n&O[W?ߠu]B/p;= /I F(*b9l) -`5 ('4Jꏔ j&N29X#>GwڄwH4vNaXB/·9^(8`t [HҖi|sȢ?H:P\c1ߑ:tfGH(W~ B3'o35Á})K#RnAT27RyS/㘠\F\ݞWy<7&^5u*rW GLɼ4{K<(g5y_ 936>k#ы=dNb/0coĒԄgH'ɖ$Erߖ؆r-yDj+E\ N>*%n#%cI4sOQm}ѝ,U{'`aa8 4Z9'on1 &yj|'j6aMB{Hԙj/۲,&KUY-u dVnQ j1IS>~O@ 7vi^=ib0"n>(utP~?<һ7n P(t-uKyCyd01ds>,1/hi*s_&M~:>5Z&7Z+ 3hUFcpC7tXi7KVߚۯ0 Q/@9*8Y@P*fa!1h)l:RZ1{矿@^}'ʿ/a<_/f;*^WMc1m|'4 M?|$æ-tW0FMG ?޵V뚕 `?"+Ba8 X{aPxWఌ(,Ѡ8HI[h;-R7 @=>zRsGOUWp Q]M޲4\ԏ֠ÝZǮFD M$ck(DwR/ۏ[[^LŮff>v]h ?,+COiL|YfMrt.c`n`㫞;wHa.'f3Rd i a iڜb|6kW0]%6`k8ng tSr&n'l Xe-(te1)|uܻNֹ:vgmo $^)k߼>'ɍLVkk$-_K۶`6u_CYz&b(996;*@_1*Ǔ}#L,EqdRe4|F,\O98 VSڒbmn1m>'GyRe3ݞzD\}]ACc A$a _Wюp5O~.d=~NahZ`ED0 uU< kf h8/ <&0<,Qg,3":9̄i6wD Yu( W$(gS^&$2ϮlA]SZ:H7gUc•.ݩnDxǨQt•_US. z!lmW{jŽahCg6ԕoVsઞ/ݿҵ,SL>*?]&a ̑PYCY9ɥ1hseY yp}py{ ?ff t@%~6R_ԑRHg>C@Uα7߈;ɇ3srPw9C9g( |/\ٍ/IQ(Щhx}fXWϤ["qK@fEy?AgU*O+JZH]t(IA9ys̤0*od6[^so3urLIIܳ}Ɍ' O~Zӵѹn0C6>[y Mk8S ~Ziz@$>c.‹*V39_7X4UdRCiWSE}|0NY;g%VmJ}MiҞ"HoU7E " tS;v&:d$S#v"ċjᏕ5`0%[ 3wsZ.F\<}Z!+k+Mvv>,*\ Jox+Zr<8NTiB}RSBň[<ިd?rylɘ^ 0JWpjS?r9Z*w*+IJ3.iY~lH}>umÈڏ:3uE(^=59޽\Aϩ[ oM@eqn0og/Nd͓N0CR9K!kN}ks +j"w*bq>^}O'RӜ|'}SP. g#:~N sʖ]HҺDHj܊jiDRORܪsRƼ?hU>fz/^W,5޳uCd%Pruͫ翬5*_\}$kݦ/ $u{tyNgl̰t;])stm"?SӖݙƛ&2)E ]AUQ`50c3o ڜis4v"G(+xfN򁣙x +xI' v@?ѺsX{c}@{#6錆AX6yRCt 5v_[_3~;6s } .I0f4jlnkvsoŶphInW Z!Eư*.[jRH.›< ݹ0a˕ 1UkK6`Q+$oQQ_O>,:c9&y""e26gYiŊ~3[1c6q\?qy\8:΅s-)8qL?EJXy;04J0?!O$8l-^X?͟TH?'C %$/9?B" ,G&M#ax1Ey+(%dW#.ԮJ83&No٧=f)7;걙Q'8,O9>s\88RhHLL?@*ƹq.jDz~A'>BDnK>Xx 0ޟJ?!X O$Th^>Tq`?&O~ {Ƌupj#ntKB?bGJ[z2md xqO?vۃ̷Qu o鼾7  OoW*WVp`_Jv~SН?r"0%aûr0}pSfU'4KiJ_ø:6BIc,2_zO̦0y/Ź&'? ) I ߫Zx>ѬcfJŽi{e7n5{8;LO>^ķ3aYn2s;'sqn+~ww鸁Éw/J0ѮPT='G&*4{"hΕ!N {퀧0i> t{#a=*72F­omT凉ԉ~ݽ I~{-1뎋b(i|.Kި?Q>T'cJ-(U-tZ}򰶲@*j0(۟@]#15@+p_{k|l])cz!Mpd97^|Tȋ.5܍1D3MqOhbֿKs{O@#MK1KO{q^d.~XMsQR2T\TշPDgn|VbG TpÕ'؟~*S Ssoʅ!b6coEF#5k`Q%_F'vr(F$/f`8nH'R.CŪ*^I-ufR,BS^5&6ȥEPힶE@?U nĬ%ҁ~mɑ|F|2>tQƖ>KSF٦P-NiuQ߾j| c'5<lΦZ_vϴv z+##\Gpw.T2PrN?gqNO'3 ̾E)3SpR*<ԔN൹,2:*gF=UUS%Zc:?Ώ.:X| U34:Y=P\Tj\9uômuS|N9Ӊj\5!smNx:\7bN)抩sԩE犩s|oQ_KśCjHG>mϕRJy}N):bGk2/A!u֖Q}QTX!ST\D;t+=<LD\3R޿6*u>*kO6>N*Wj l^5ftY;\Ti\CuIJuT;|gNˤ9S\KK"smNx:t7bN+暪sMթE皪s|oR_&UEڪLK>b5V}ΪS ZL[2]^m_+ʇNUdJ绅ô&+.+LUeL3jbֿ"+~+@j3ҌϯJJ)ʚê3ͮ:`gV`d;W;W_~"1O\{u7ԹD1]9+ΕW J(& zp. Ur6E|*@ !e=2{n#aأvixe;,xֈkAHiPn⠚so=e%u 络Cl Z81afQ C~lM We蒮k0A"4ۍ Q KYofDCUE(kc{lw<SWz׋B/&7z#Dd.؅~<@T N'jE0GqWq↘1,Q/At X~z\1m<+WF;B9~`1sSĝ^#F=;(kvASE*Ӕf~Oޖq QR j,[,6Zi_j6^:g ""Z7`h E;Q#ۃn/47Z4{CSЍ`s R$ .0g'wkt=Nz?/!`9y6R5j8քVU7r2h [_Ӛ'Su񅀇T:}L[ÍqF}@ iy C@i|,?8@& k U@Q`I+:CK &#^8eh_f@O ҉ Iԃ$2Iz5 8Y̋˜@I0f'O'7nn=y|ΒACC8+>n(p, yã=a `ËQg%9Ҹ%yyXEFNRw_ $>eNB;NY_l6lH|%$JS7 oпFSSqwFg)mBN+vڽzΞz A&W88zуF=o*b$v`i교E%i™+:fn=^n>V['Oqwww7aӝc7|yp|ף#J^syo||A@^>ǃ̓C x{w9rIb@wd cpzCַZIjly9{+:`ځahB &hl){]NI4 _0oq,`5|>\4"zkI](Z.5< lyakD\v@IS 8@Q 7pSK%u;+Iyy6_u9 qלqІ*󡝸وSl^aV+ˑ,Ç:&˄I zgP 4Ji ,gu/zqA2]^]Z@{[>{?}G/տc EEdmGg_Y]woBm b Kڄ467e*"i[N΋,]\>IUdJNs"nQn".CQ\@^؏:,.m֠Fiқu&7V $U<)&}Ե{ l`ˣJB]=ٛ3gl%afc͌oY<HB2qNE:  ^ 'bp/ "[\1''U& |5"(LFgEgCѓ?z2pJҶDz(X JKÏ>0ߗ$ LD E~ ԚW!Qxí/62 " Ȩ8 Ds꠽;uNYܬWrk.!2{$}wm Mh2BGR-cy r?UVٱZx C]W/Z/sh# lxk ;5[U5KX{ꧺXUe]uoq%<\ĪoN*ՓՓ5=aU[QN5=g@lj>[9k fB5i!a,h sT8#Z|JtH  /JЭJFmMPg@\xkÑ"BLI6Gl颹BB|'%t]ZWeot6XTE_\pp 0,+w$pAZ]{[ϵ Wf'ZKZZv߭FPFiĜ#]R[g|i'iz}яt!HMvt{Z?]5- t+u#$RAlЖCBNs9#I-A?!^] %rJGxd2Xܯl=AX%) Ë~V "^^aaz%B_Gl}kGok\0oಪW֌+=*w :d |L2,˹j.I)y@Sכ~ih4`b>fM bmԷa C&&*#Xq A6px^o87l +44%Ra+SE^XtWm:,1K C޶RP{xBy٣zqR|f̕Y=)xd`2x/Xϳt ԻI 2,) -%˯!_eT-fpX7tɣ[@|WV0TGqgxB(zAӪV[e)Bq otA(ppN %PU8j"u_unPX`uhv`wwEy:E` 5tDVbV/#2j  –7p=eD5[wLv AY'Zm!:E!Uګ=dVhl< nLAj:WS\1ⱞ`vU,(BvssxDߍZlt]+$g2KO$jL{!Ssa9DA_ݵ㜀`0R_l͓~_1d\wy^§XGZaQQD+T^s.L1[WݳʂS KH[>Z8 UE=)ѩLgmhMi%ǝ ٤vX(I##DTe3K>˅KBmZЄGĘA6Y"'?HgЕwæ!  6ciEQoHݯ5 4ͻ,i;.3`GD\^(wlq;&w2FaDheOGQp0B_153bQiP m>>%]RX+Y^mqmr +=G51]F(eڀ NVX}UB\n6Hns #,t d*S6w͔ԪZSs_NYzvo-.Z[l;>2kndB2W4S  \\-n=;,^AG.xHLXʃC7$ =* ,)aHۣ6T]㟓E8Fo!F=HI&8Cw$NbzA $$H,Ċd&pu}q,W.odUT?RHsrMՈ_H 2UODOR-ԣDelQ+$xV+g?ɷgd@k&a*drQSR29w99!gNVfr;vy39L:2i%5:}0NZ,V'CҍNaѾ`Gy0o`͋N&MC%-8l޻NF7]77bݶ{wtb '`Gw&7p7oLb3'fr&71ix=?X[yǤm!- s3AlSF7BMC?V~E8LT7_@TJ&2lo:w̶=6o5~tSy~9v{_y;xx$໣РwH.PJ_ ൪w 'LUɞ^ߋ @Ii6ibJg5V=nl" !)rIwfs6ptkXIj WHSmK[Q|۹VjgޥUa9޷7=CRTȾ@|Okە&sO>Q~6hLl qZնӐ5$69 :R 8-BG}Q%?^-Tp24%Qp(;W k=ICE`ܜP'W1 ARp_t:J":YO~X}f_Buo83U[t΢TaI%1R .IG=F}D8kdJ.:`ZTyjH6UMe1۔,AmLj/ͩh1k0ѾVk1Z'd03Y"V uh<>MTWYvD4Ǡ۶52l-i멤e𑉡L%11 Sٌ*T|]K$v к]h#5٬8ƖvfqQ+lYyc%:j١<ϚX|R'\"H7U^_.y%(OD4ͯI2:.LPKqI48VTqs y/k?NQ@$F)uÓPc5V^s4ÛxA:(CO8I;J~X7f83k2*ogUnv.Tsɫ&5SA sU-|13WF[6HbCU0Rf5@Hye.G0NԤZzܲH-w[)t6uS׽|OwՇzZgh;ZW %?#bᔻUy TY)o?ӓOOHtj)-Yi5oi:gpC4'B4٠;D>MxGúx%HDXW}!7t =Q‚OG5ln79Vb> 9$ٷeV N3PfZL%m3kB9 %!pvtztՋ< "Ϥi\;竈&A> "m8I-IV+7/u[9+Jg5Q&`dp0&HTᎲSV C9o,R~WLSt?L'CHU3I OKq#[X$Y0>& \&Ɂ'EYM,{*2'#ۛ4gnyP4do$?dڕ]K(ǢK7n}9#1l}q4Si?Ix$)l*jXJ6 ,]QV^a[dPtj&Rq{,b| BPlsER#vώYZF;`UG^UEL*pL&rEUF*C$dZنؾG`Gi"1EEo51]-E)mT4X,KY[3u*&tt_o_r)RN*b鰪V{*?=~y=~zz/pj֩U܊(O5(081lݢx0:l]ZT e|G dQ *`a)ȊUr& GUX,Wa UVSL<@2EwIҫOG{ıFg}^v); Z]O2Qr> z5qԧLQ^c&kٔ#YQ*kBwcU^]YQxԙ)(b fݲ:fꥬk Q\bv.&tWxڶ9Uȋ u;x9R[ _ԕzRFmiӳI8 k š <9f=f]g2NCMr]rvzH37ǐB&>~mv >N78C#A[<\:;;*7v_r&btGh%ILnq˓ZIrIT[l˛C15Z"'EI%TB :;!SwUmSAboK?~%NYDMZǒ%o˧jw,9Fci(snK3Q/s/~;P`h,%f\Ze,.vͨ5`gҰ+kϕ3+k;w:ڽ6N{BMM׺++r}m!K_]) yBL 3j$=|Hc{|3A9n_c*j8|bv?b`E p ĩ]rHh+bp[ъٽK;JZ͎v(9"OY%tۻՍ14#!a3ra,e,E|AAN'Eۖ0yzqWq)7aZ'Q >Wޮ/c%ZlD#EkWhӮP?Q=$vQ8uVm~lAu<_߽o=vCoZ}J) ;u:s_{]S$!9,rKgH$Vp{w{h\\i+ajn@v.@m_bPvvJBgA$T)hnm9E>G]{U 6Kl]nt:(n=Wsw1 Iܽ4ٖ/PqY H-*<5R~^UU^=kn{M 79ARd~%I'$x+E!!|~^(%Gi{G]8ޏ.xCA6=CGKrtS;G}OpӇ?$\<p LTͦ$F-I'B:ty}廇o6P҇ç[jᷫfՃ58ՋGg,Gr> Q'S}KSm?&R&›*,6KiJuarUN,K*R七< 'W* ;^{qeD"@ XT|SQ0:l@arg##:X4aZoCޟ6$~E,7F*!/5>ƍR j,4*meJsi*+3rVD A__l>.fz3k㠑8 H-^b>z>,SD'5|l9rw@zGQ, # #m$o8 ge*pn:19Ct2&| mp谬=VX;;~y ]py;R^KXy<$* éV/pUz^kU x:1P.W9G?#" AԨVT0cw &W-=z@ JMBߴAE8'#~U\܉UZ_faWVfŅf}~@ۍDiU*RHEN,1m Q%e ?QP-E-EpZ3J r-aH_B@Bb|fn8mJG*!0k@J&-굟$z?<¸ &2>:qj(vi{՛#'SFI #MXYW $٣F!HF4W}e=X(.[QIv, wy. IbzLhEeNG' Kt!U1#I0"16%\xӿa5/_Q% &}J Ë{[ s|9H?+!>R/dL83:Uϔ G}%}!M~jp0G;4^!,O0ziR\-y_p[/t1wKsA^(H0ЩSUM ڇoR&j3x{o3i -7̈́l}̯Kc=sqF KdEH4 (a#,GgdR)@{PՈ6lbxz~wEK5u>tC rAV_RN~c$, '#%!=:5CK%< /*@4P,0ÞejuTɊo,l.Q̡ut񄶞XAxd7A 9QLYb (4H}UPJՃJ6 <ðx41^n+vVQ-<+-g MREk9AJ7Xmjc(h!L*PZz hsYLe>:@#K5(_!XSBk)1yH>V%PY2b#9_Ԝ誐bࡱ` ǎb(lahJ($/iゐZ*4cMeL]g%].yCCK1gbL]ja,"r&鏩uNV)[Uz0h; F3pDRHAYfR3Pkcyާ։'xMD1Y99!Hv9kx zNaD/ c'l!+n|>v?KrC-\-jkJVu讀ubHLFaTdG>^<&y!jG*Q&(#WpVLGu,*:d ΟS/>b\-l38OD{^ 8gߟ/=JYcIep>iMذRNQ%WPvL +/v |d@`KX oO)8I4CI>.͇4^Zsvivyv洴tޛ!=kY dhLX/fXxbS\c{o1}zKܶ*53vKب4 >;ʘi",+j/:eh ^q iXp J vYG)ؘm`ץt xDdtB%G.psЉݣrDE([ p^l%L݆emn|M7.=Yߥş1(4 tǁZ4wӉEC,ڤIU^F'5̈Tz wQAE,V|TQ!2~F~/?5 * Z;X#% |iry?(H~$_a&$ma'ND g4ZUݓ U"jO7FI&~G$7/ ȯ;C!T?$|CQRH8ǎP1mtʛ5lFV*'JO#ecFe3h,h .±>9;,hz&EV]@l(DxB}+suX3i%w0-6 VAVXߌyie"RM (I o)qEɘj@x~?Ko h}pT>d$zH_ܚW Տj Fi,/Hh1;+-ZqsvmXs2 :w3SdDDBqEJ~\'jqeH5T*I)hQ$5d)yT0KtPԆuJ  F7:cCAdeP&g慠c}O^4D hg.AW]@Y%=乜&" X>Hm6i@!Cx! 3·jXy^ߧiI41f2ďlܜ5 tk6מ9-_?FRA~>4ώ*1W+g^Smp҈N Tk_~.=KI$hjքKq .B֦3 0i ~g,_z@^pѬ[*U٪LS6G1 Wm2m)t:^9kIɇ@|J . MVL-^8qse up`hMwi9\)p}ȋgj){y*ʟ~nO\[+7\f^Rmf>TVpt-I+bTQ iۏ}f9MJg kgs]+921֜fƞ^hYi;źͤiѼgpz9y^j2>ckr+?Ѷ-{{[h` fquVk%$_of#4 IEzE8b'1qtb%yWgU@5֚*RPK:u hֲt/8lƞi -N.3ޢUO/h=m\-MǍY刦-m\L/!Y: :*s( t(0\ D V#K*s 6sX`&[OO?S^d.nL;E;ub`D3v/?"'CDGL?h4ew3!&yDz"y3}l&K ,4h;g_ $j@vBT⾐zN4'x7ŭ6?mnUyo x]jF%.:aytEduI-ᰒ$ w'?"5XOeR!+ls11:BⵁlIԏz>I0`C6*j0dA%^N"ZU'H˽13 )GO9!|_+`N^er&lMIظ(ʶ!{䂻XzhS5,Kbǁ8~#|>?~0jP kFg hء fw7KfAHA<6&h*k<t 럁 24c-@w{V'\&DV|6'Vv#qxZ@90%ʁHi"EoRpJQ>˄^֔‹$m=eNFf+W:=U{ea'`>璨,t /4v)W&n뛞P#։pܛojfus$lM ̪aA~Ӽ̱FkMd$ LQ~=հpy~M6ٝ)ȦrDlKG]Zs|0N]1Ԭ;RS_$. մd߮eJ9I".:8YЋ\80u"ҶHW`<ڴ{%8L 1@%Oɼ. gƕcxuKM&`rz"løQl2KBa=rs-jAXH" v{J׳a h& fDCbK4*N:~jb|CGt PICI Ҥ~/@L`}IrBH $2&Ha糘2+Ayvg@BrD<;ǫ}2@ ΂KX^:%ȠBY]h!j@A)Iy 68x$!P`'uVGb̜t=NO1,ZcS_MR]*Ή6)H=dުD*9@Qgjށ9y;ˍ[/ӺSSr E kJ8 Zdjfጷ -X_ Pt_0y0po?N"W f2ݤ7(lla0NV)!om~e֑zvaMMv< Jkk.l#JB/]PiM!kJ-; 'aZ+H~@WE0Em-;C.BYA>J(k9NLLg; `헬t՝2\GRh&t+Ns`1)9fmhp,_8-hL;HHW6C 6}ב b0"JJ4m_1(0֝:_Q#pQh`rA.Tϕ|(f\@14@=KbH(`!?V v#####_$G.\σ# Nghq:Nzp$Y IIYٽv*Qd50\k]g>>dxOߍ[-.??_H>hc8" F0tPS)Uq! (cBG/9 X;=CVq'1䥓ԋN3iv(N'f''g= ԙ͉_r*v*+$٦im jl۟m촷͜ћZf:*<(qxBj;/ :AI>i7E;lT7_l`nM슐kzù+a"^dsYL18q=>xNtꋑaRݽt$g\n Z/| hOk*R\u!MfƩdO7Z r"Jy!pGT"^;tHP{tò~Ņl .S C}Tъ <#3"9 "ұMwƣA{Jm`+'n8QWE41$ QrRTEDb*v8P(>D%+C(9/H\A뾆Ƣ Pi졙D}䃣/קr2Ri0HZ&L‰ tCBkDtC}[X 9ڟD c%=ZԹ%x #}cDe'Jh$0vOoOza,D4sz6"Է!zއ1sT8n<"|0a2wg`yH,΅{ 6X<#Ig;ZxztzdBĥ=|j2|;~{ئЁp޽` AaL4khE-Brb( ỎwH -!5 jSYM?MaЇ >m¨Avj‡Еj_G >"49|˰lPF:<:V ^6M#v67zQE=>88\bWhޢAs! BVDG yЬ0wZ0NNJq Mtg.hJUzKf@vKfBjm7n~fwKH;tM!o#+ 0}qLUwj4$n@Eüе$msBb 4:؜4!!1"غhIg3BZfEZ30Kh^-%wDr[ Z[,>ͽ} ;-2EHlHV?SG3Mo$th7MZJL4v`Nn5$jD4__l^?9A[IƺD!3P #). 놈0 /70 && "% `6ږd`lZѦvBɓ/+̉e#+}B>굽2Df&Iɥ'ycSCcaDY]Fx@N /͐P5%ieK¸[b2ĝ=ڑ\.(r ݒDQ? 貓X:CU3fXhz1j0uLrbJW`UU4$8OHvN9rUDJMVE7SN97}m ~Nle:̸'; ӹ3m֠HHq  nNo!wbEvLq'6h6}&{+}*iQ_B(33|?wLWDAyRp4F]qQy4ؚ[˽Zosu=۞Y0@S!ji#uXh>h1v;Цʘg *hA}@ *>-DՒA2R&՞MW~i]^\s?CԳf=BvU&WUo..-|hϓV'07Ь:,7}>eoG2pj?cԌ_p]\Nj.[}#:RK-fȦn_`x¤RLp)үR<"8:W6䪔irBA,t+D0T3λ 3jϞ3f84Fњu5E&#YK 0u+'Abd:/|Y.,?,?\Wc_k\\lgy*촞+>j?Ѝż7 /7ܴ]Z5 [-~7^X}{꨽|[vݶX)M Mwz TJn Ơ[{z+ lNv6DAz F]k ջjI"'bqPƭ qUX9lfEcUz'R(U`>QgiXJ? $u(|BLMUOUuV=!s=^/>ӏ7S\BU~k=)S@{8+}N9&{J2۲S%?rnw?΄#2/H~qfGH&䉠U鉶++Ĕʼ*XX2z1hf󍚃Y]Hm$7o[[euܲ/5Vɟw\Tw{^ˍWj{ Y4 ɲPMGF?x3Fޱ#-Ѭ?pxPT, |!!p3IJ~wBou96U{t WC^gHpaI 3y6V@HCv)xs}=,a5 "U eH~= |=Zg>8G/첛{m7I&g0fn:ڗfuBШAQIӑ 0TiHȣgHVߚ*הeԺDCjk K!u\P@‹PE` %[mmwo݂2aeHeFs@O@̟L0-CCP1{1<*j=%7̨0q]kՙv#P2GXwB{^i ݚ2F9?%O,G2V@oͅ&֬|W-#ro'SH Q; [~鳮 ^ :z9]ɢhhWqFWo0)ЦE!z2.Gx%!\]0BG/O.j):~:5O:ixt3D3ܾY--5J; oT:ƔB;$ꈔ߼ef<9=[K8$Flri4$kƯxp>WH݈0td[J|HtF [Gsl%h*^tV ޘl=sh'9s!0su8,FHyrpͮف͍XI ݗxHS*/ZS{abUvfJ@(i i4`>˦;)L Ph?~gBNǃCq^1p~uZ?-`+z1kmnErn--S5T455ih6f),U!kUsT)gWSol]+gi>lIh:VB7Fd Y@>>?I9wLtn M<v:X"N;үAmʟ,yͩDmކ ӫ kɈgkp=ȴ`{X݁{~JS#Е}@g/ khLCN' >pLUt4:=Dlj#)-DP?7oL`}$ LqOCWlBvW;rY VjٳyLh /}Qm" 5 :0EMw|u _YI(K,~u0y :{%O_] uA$*@,lYQjZ0NVP3d'~__wO:6_S-<7K/;.x0!Wu=|J/(FǪjLq?l`jحG 8jo6΢qD.8E21Ҍ'=P4bS-,6WӝJZ8!q!>ǘ}x5~)WQ~t\>پ&Dh_:b#(] 6u)-;EmЗ÷8Ap7Wmif썣T!g8s")y$g$XFrIDg{tytscp:n|dcsNڜ&0/K{R=I#Gf8>/Zu#PRT-c;tk7z(CBf&@%8֭⁜ë('21t W% "W y`$ ,a2H0j!a?' -.@x"L5歙({Ԯһş(%ZӼWB3iv%$J#kJ`\/^ɕ(XGĕꠦJS k?h\%16% ׋8 x]?8x8'i'7?tF*3þ;>lMT_ݼ's95Xujqӧ7v :8!{.'W%̢ilA׼rPL7ʮgl.=OsC_zу97E2Yn4J) sCԖ^˥fMP k6{\J$\WMȧQf"O.z@8s^4^O-c3幧K"Aoϼe6ΑCmk})׍2p:>M^8g0a2Rb{29 :qe f-ErXsID38Dzl|hykCI*pD:M+1  i],/-3= p[A:X~&oVuu6ãvr =mдgխ o9?S,܆B) f3}rұY(ygϖ"" $Y*NB7:党BeMk< C>IsD?7K>-g wJk>oe )iڵC KK% ZmmB^Zfܷn&lӉY>b'\+ۄA{b1R(jeR{[&\yIusJ᜼7"sL7[Ϟ?E䮊1&}D[ ,}TBrCJzh0b <6 l7lvz3*Yg1r^Dv߈{DI/~؛ƠrɊp::ΈYu/{EhYwD2j;U#N'hfjj9M}1Mr޾i.~ ݓQ=dp2A),.GCy 8_YO\׎MX\i^LqȽ0Mjkb#XR?tԻ "?z0m|̬I7`Dsn 4ޞ(ĻsҲFrieZMFisvԁtJi }W6O^lolmi;'ZH4=!Mp%H~G2TjL|⩳eJqPPZ + EA4ts6vZwN667h)*sfs\7vtÝr2''нѴ~4L>&DAS5c꧟]*-*7]fKؐ[ wsM-rMSV:;"D|qo@ǧ$XQh1N$!p I:Cߓ9 gi?)77 ؁"5GCg@=b,Gz35Rz|!{9zm6{%4jX;$G@JD9B߃ʪ 1 e,2!s8J^ g*lNrnjal5*N#d*vkvΘ:2NW{OaYc3~xT>{@$ L krFqx:ʦwicr A,ƘVYx^2ZSQsd9gynj6\7E0tkD '~r&(l< P# ^SSaj$ [M`;wGt|Uu|8_ǾL?9~ %p`VVV!(9RdtQ$Nghs੮tÙ(`՛~W$@bPT4s8wvu*WlA.=-!N{rg|Z |!RUՕe=D4Rh?v㧭-ã/\pl$ :H_M!; ֯Xq!1G!׌)!X# ^g [)tX'g&ã@@J9R{l5U3`2ޫz.j$N"?CUiZBGKrq2/|j'2qa1ytwȓdLp-e/Iw<ބEv+3>)܌ݘQA1mE6Džo54i NAI'JÌ!mdqF1SsB8 (Љ9qʠ&M9 g$-DaVG1nXjB'!04*]rbB/|'E埞<UM$I%.c"Mrrcw)<~l@2j]M.C"ʀ{Uhp@<ּVцQݰ^5V7d, o@'k!̈ ܮ@@1(P-, `,$X|Q{`XPnՒ$[j`2~GM,1& zޏ}Nz:IH<\ѵ ^Gp4'/;|xueTvy=?IP< vD4Ax Ҟg'$7dD5İc9ڞ? kqf ޭGM(.+e/ݦ2e|4д`r~;/N9"n%1l+V:%ķ1 'Xx=!}ع:4e ð|U0!P2N]Êp4|X-5;$`"%=/Kt29~[ROzIԣ!%Oۍv*RQ^xsw;x{_EO!S 2e IpVp`†a32)Q /ڍRNq~ 4:|r[g g-j-w ;(6chPR4\z9%KjqiujӬ_lpbeA,(RPCEU?>lS*^/ٍ^HǀgQ-k3C?{;QDwo)_{vg:P:KlCm5L,. M(脖@v{!_i}064DPjhYNl:<YoFݠ\\4sXB0G*_gO \5~FuB>z/O[>D'lo p9X=u ۏtz2 2 HārL%SmzǹdN7)p k6œsbQJ"o>O//cxweWTPHI ڽͭ0TĚQWZ]\X]^ (ۆl!<>]ҝ)'LK#X \Y4NK a7WJMɃ8I&ۿ_,su]? OSD֢ GӣkmVtg=(ܪ qU4A=e9 'xΦH`AVNn,?X)ڪ߭՜HF6QȾ/bՅՕmQл\6/6%:d|?x忋 K%~P:=DypI / 5 A^;^qy,%o@=pAB5Á)c>DuP5RyK4X[ rXњ1> |(7|3 $,NGfxMQU<8vF6hHZuahsK(c0q2N!W(5s,{mH7+c ( ;5 XO^ļeDbIhynP?P> S8N 8x9=< w{z6Ll&M|֚x~FbLviti-%<$18w-f$drR]x[K4wr-=;X$`OS"x(!fCeb"QwPeVbv)s5|`'^^SI:*'Hc}Q-a6B@" P.Dk_l4h~^&ߊ6ٹGdh2>`pQˍj\g- p:5@4h^Wu&X@7*v7^n|^WfnNK퍶U~4peZlԖ3QD1zZT*Y"Kfk;)MSo0IW3ChU5kAx]lӾ+,29=\]YX]LUs %o%[|գ6QW 1?x@x.uy)cp +Eџ[rON:7 7BDw9ڛզf~Qѕjmԯp9T5 %v^U_6%rwO=Ʀgx΄CY`Mζ: )+7>2u5LMKCnc]d.?"Y`|ً;j'+=dS/Fْd\]%@0NI PbJh[xoy$z`U-=zPߠ { PR!)REgTXDI I !>&L ^t5q1g^>'-һqb1ET+YfҷޑO{eUޓ^;DAac{L[3YvCp6[ /Zn$FwT|N'8I~~dE] $i B8 ʨPk=u·)Phthݚ`fܱ=}?3Gi$fce8 0fOO27ėiW4L]@('Ьeo)AunYu[^mP6 3`la?1  &pPs@O?gga \4 p 0El }MU1y ܃MX,v5Vԏ?ؔLfdy)foWd,("FOpw&.XۊpE$gu|+x؜< Rr[PwV~+כU6,Sc zP8 ^ߙbTl@Lюz\h>g90a#|Wx'hI][݀N]MG@j6_7^>W%$an*ln~ϯrZ>֥RKDEU3] XNd3 VV]meK5YTG1wbSϦԿFWik.VhUBZ~ ޥáఱIia=]EmꌔwHNJZjsHEv/ǒ(25矼/ yl<vb5{“VM(f^$ kw'K+] qr73a297L(#B=CyprBd+O&NIJr:'\Mm־yΗ' ruueMeȓ[T/y G[ "P~>ٴӗ'/ֹv".mM~'$0I><~emb,{~Nֿn'=&%jv9%G9ƫ2h>J,0OFobq8- }O2d+zZOD7u{cx(4]mzü|;/@[-gt量<AwD:Y*СKͿ+g_jZQC{/i2w>|ҵG|[(>nZNGma殮y'fq #c ÜZK + tdo>¦{ /|n}|0s넬v'؄u hT龓xQ;JjfoOC/7 GQ31lH6o3=z;+2>5aJ-4(ASG3ùV[pa&ƆMhP`rZ'i@,@9!*0+#$r_Aj_u55ryZWT;FÏْ*Y\9F64xAiΐx;E3h'x*k=tѤ׺hW;}w۴|{0Oӥ;tu>r>;4i]z[u W#p, ¿Mv &#(o6 h o#z>M#V\79OZnnǏ>w.,xix̪u>B-H7~aY̜SZi- zwhLV>oNvyC7i*\ /NcIh(;.PunZYw[bX_&Uzwo;0@Z&Poܛ̙ߡ˭/g f<'_Uc翶vs(h4i sʈx, \i_Q]}{d!MA^TͿ38Ln~Ê!<=}EN4$a{݊O֋]GMtt#n4BxXE+' sy4)$zG<ܥYZNU,*Ozgm ݓ{)dQdߤ-Ǔנ v?=TOiRqۛO0l'lEެ--Td.Ruv(YKs g%͡)Ot3\>SIIsɓO!WHMu*xqB P 2Bx<l09{/Qݭ$ l/:m:4"ۗSteZ_4&6Y6P{FH"1iak K `P5iyVP0~w,lWߢpO|ʎC7U1vV!R8F-A[u#55.g$$*puuYc镕I/;* ڍ/pwnp f/̳{C9aMy+%Դ,Gz-ji.D*h Oy( PN[}䵃c^Nɏ! XW]WaEG ˏXzkAYG> J^u]N0 4 q Ξ vvtXʽm då3N݀axJG ')Pz\cA/GuҘ>~i}$&ML@gWh-!I=r|.M7Kz]8 +GѾ&ݧa!.iՀ~)OuEN"ELӊIљrQyfC1%?R8֯<2{dTj.7ON;S/F%B"@!a)-^WxRӦ.޶ «19`L[,}H<9lxm R +gy _.QlA|y41a*1{o_p-{WQf4X-\\Êd vnkʧ0z.Vt?N{! jjo%H{~l;[7H_~2WM-I;ά9ڙeE¿ʒt&LM$9y̫Ek; ݓ7&hgo c$Fk5" ,(nѧXjszA!?{5@Rktq ]aHZc08jP KmAB;^;W,NNk#9C-P[06,5lN MgE/Am=h7d ͡DC|?&/+Y K; uijt+d%ph,h;fM}KH!d 9"?9}IHw^o,k, |{@Bwp䂞|Rá4U3zUjF-8ͳ%@@r>ϖrl nmݵkK8ZqkRɷ%~H:M Yq)%9%Ejkrd0-aF IݶT0OFI tRB璃L%uԔ{0sgȎ2` &Yqa6_,>Zu ĩ:AlBƖlkNYQL3%dv%al6EMjTê }cb$qUcvH0"Ovm{leݧB}hE$_SqV .'%2E4u7ڡ{shǔˍݣg$9olvj`H&P%_6:}E+r4Vp݊nO<9]3?NUXcp٭o3:4ddim9kZGItQ>:ЉC=#ܡ Qڨc\z% hK[ܜGUJ1jO0aE1{[8.۽6N6v]lU/$xDjk#- | ^ix'0~\Ǖq:{\)5QK@糬Zkg[7Y(OD*mjc :)J%cbRu,9w4jQ`0 ֔s{ ѿ_:yK}2ZNuNbWBQǃ:0@F )R=OA`qt[ PMz&B^ s'*c+*r#e"t` CR2>$WN ;zf0=EpoGԲc.piaC=p …'7Ko5ӧQ&CJMVKSo'|eL9yMyYx&(oK&R E߸Tv|LJ8aGTq]g ^hGF}j)DeZ=x)3 u%CC4JK̲dG^A|1uMo+ᡟ7xe#x8%^0":#lܸC-w ů%W z 1i!2!ҝaixQ_7SԔ±yDцR'2`pIst SyhǰW$V޴%iEwB<2}+&Ilesd%AXV^xC&|;x\a ߅fj i% e[K9{5OvIէLȘvj]Zx(-w*\2/gK>~ԤHfQO?Ԗ}<7ya^m؏2YkP-z C/U|_. GrmRlAk *!!ɐOIb[u RgHi\AB)K~a.OJYxI~  9|phS"4^q|cG\e=xuQgZ"!a) "Cunl0Awiq)0@9^39eL*^"dGd.])=TT`\F&4FK {؏ \CjyzΘzsidۊ>X.`P$%}3aЕPʗC3򗉦cZ+ۓpx6]^TәV<xﱷaWb Y^y_njEyX;#Yuaι E.t=%R_LjO<4reNsh Kd:1&6ŢKooRgB5t1(B+9mGKAv+p9%SJ^̤ FJ}҆0|+|Sk(xB7 6^n'uFIT)B|8s/r@Ep VO^ A6OaVjV+afl<-c~G?Hև:rTcEpԐm)Db@'gm.ɤ$ 9΍t;?g EZnR=ϡX3Oi09?䝽M((NFF! rFMhe[rR+Pгˑ[N-ͪ u-ͪkUrnM&匪s-eו*3D|yvꖖiG";)uG9 gEc\xEKygAfˈANtdP&gBY=1.㞘N yR7^B/Nj+#K q6'~flrY>ɪo3= ^ɥf˥u/w{ {?‹F /,;y\CRiLeR:[Uum- Q>UqLPAQCmaMj"1 ,vO7yiO51s1SܛfȓL*^ltWf˻l;="CR' ts@w/ +|jͅV]gK%ZIHccqVrTJg U Xɒr^3rZ:)vPsA48[@+(ǺabV|E2*n}>ȡemBkˍ4;ב jBLUBOlRһ{ui\5ˊ _\%ٻQWr!Ѳ ׁ mOHb*"ZB#T5oͭ0> %zj)L IlS3Ld(U}wTkWmj-Kpe4=fݸh,`M] # O87I)3 IOtDOm7W` fDMX ۏ1 6? J@~{/ɒŠ&>_iUOX&5v΍PHD./O8p72ewNXW=M=0l\;I_Փšx8(=KScɕQHg!JBO^ׅګ54Lyb# 8`.CV?Eݟd iFZNC3ӒP{Ըj*ia޲,܁̤2>VnGlw(@^JÚIhh[O&=&#U?Rc?Վƚ dzkˊJyBTќ"4q+M->b#Q9; ˱#e/눡0BK%gKQ H=%qT4+4ŌW sO=auôT zJY-U^5NΡPIb$9zv cǿ*Ѝ#s8<87Ȳ!]:}8&VMb >?BՈ-4ǣt3"0E"J|$#cAKQ) %ct> q] *(`8Zfl|p_=.HKlv{ x:Ha0a 0*%1dl`c {u;lT$G)UcsǓO"\RߙZ65\QnYx-h }@|`ae5 Dv!FzEPF#.0]9`qYQLx{a&".fyFP̊ qH_e^okZӾCժjTK?j?=Z *UVmu#UQ4ՌT83{fNN XN9Ob#;mKg{'5_AeH|fm%c`u, T#f0if*tS_əujR}l]_&j'C% @@®yXfrY,4d ={4_Lӭm_NΙNw2d3p#M]ƃP g`1x:Ni]x!w`Dwrrڿuu`8_gCW䜐,f8!qiO Q?^Ct8CGG?8F  zK4 o|y%E228N!JBq5}&wh`ا^ԏ'C ƕ$ zlV8MEcr&?@p pu B[N'b~-'k (bZ̷ $O1Z|YHOWڅ-ai;s*q WOY݆-;8Oe=b U耚 :<n  ;.EPpLSi?H r=] r0^_9h^.|'D<%`$uR[(=_`.B2cB_eO@__2:Q| Prt谜 #ԋZ5EL1I/ĽeTn<_@n:!8* {dmM /ll>k=?׺ONп%#F G^)*@}8܉q##qu'TdXThz,K^GNދۘY^?Ad{:A h$(@/%S3Ǔ6kc`=<#/>VW׫K/'_*Z?6MQƦ Y82B+ӽlCgM )"?g9+<2SI?o4)EmU b=i];r04EOrvI?oUHGdDYZDĻNNȬWb3Y shtWn͐NȼWs2/shBkG!Tf9}4OA~x4P;o>Zu4D ߺ@o]aSYVXzU3>\07b|@LA4k<;PɴViE :yhͿ)>ڋwՆj|I暸lCm\q-zHOJܟ._>ó$KjB?yBf$íMFmΧKm>d`<,y~wMfXS^?ȯK61UZ%t>T-JHIdr_7%)d4ų[G|%~"e4{ΡxDCfo'!y`kYy_WR [߲#]ΰ kELҊa#xSE&sOX5HSު7x{[J7rB89Cx+b8UiJt6gm9 3Af&6fB4Sr:yEaubsE8 kLIWty]%r*WVړ^[C#vZC|a>gצ" !&=vt:pF D!Y}kMiJj?zo$wܪTցb{&c~@ԂgB.m {#N,&Rh.m@N3'H}v@F *X5躖[hXZB<1}uGoUx7c0bFF7 ĒX69 (ĎlR #%-{ma# գe۞nDP>o!FHx2 H7<@=P5ZGo?BpOj^YyD"3l=B@AcD{6^ހɀLɩhX[ T;W&|~zٲH@q7b}cJ"Y|uZꂡo(Qb"2=8x}8||ÿR3f{A  TpcY $_TI~x༁dd |}cm$Js^ulka{U7fk60CP*NKu=]HcUV{D,na=SŸU>lAE(=UP>NnVMq)^7Ŝ"=}4OUŢLS w:pzNYmR*>'8ս潧ju9}Lυ{6>'[)[~`XϺ1iF[ԥr_7L/i'̓V3M&dW 8l=[cI7dƘ4y_2%G73N3e:ݝ${Mj6[}`Gdiv1GŲI?/(eyZP9}4OAwA}e K{ВtCXFbёolf^% D܄32vm/shLKyܜM0LW~] I?/6=vU;6d45-:oYp<8K}4OA~OGx_<݅Pߜ4bFJ̼~ۚ)QӲDkS)لtƐYIS)S̻͆?R;rT,/1g 1}:TJ6!;RMcpO6:g~،ErSgeI:fK+>WC2 㞃N \tf(4HnYs2gbTlBvdtÿݖ(I?/v e͓~fRř$sh(8@fX'i&= :BD ޒef2zN͓]T~3C^Fֽ73/W+}:TJ6!y_g`OlGzf(hjzFF,}4OA~3YbW-x>'LAzCef:oK:+>' IjEل̻j ؟3X,,5L$>7@Ǥę $f+qTpyzgĦ^$`Rb 1+NHuk-T FWecx 941'y oXùaJbu[!ZnMb*g!crʼnwE͹d?M 6+bc89~s;.~q|\9pO?-QsԼ)3CA3{jw(dgGZT'!N~uH鋧oD*%&ѸL6Y Qw橝뛪 VͽG Qqgv|Mf_t IcQFky q?A}msBسI@P&y-TcEڽF'D k7O6vvS> ]֦_]H:5 R}~Y(uMvWM3yʿNHHj"}9lm?k^_ÎW o<4^hVpz1:ō)kY' KnBwSMфGc DwAII {u/**% 9&j+TCnar#~x㎖-*~ڮv%΄qt _Ta@m  djBjm 4ܬ'U Wl]+q'@ۥcdp&r@vf.`'ӓVDqTc2O‡*4k ,Q8TJVfL<BX'4X/x}~n^”θ9q <GruB>idNoh,ț>K˄!BS 20'n?tEO'K d&>ZTT CӢw8;x0s:!˙u_B郕1edH1MgxrgI r߲`9#Du_) mce\%MWFYAMOO m /RO*Y~'id?lȚX(c)_<#0 o,y83}qZw1zhN:XٲE4 g.kӪ;j|$l3QBL/l5{DPDōNIV<9zۂO̓rNRzu$(f_e\Fs(}*SːTYHlF?6嬼J(M`E )QTJʃB+jvyEBDL>!Z..M/깮hJ/_Ya`iݼ3H݆JwkmDQ̺03'#Kh]xb ;`8g^11 T[='~J&q0 ԣ_۰qB-Oe~>~`ajU'4ΚA7lb}d!;Q>΢'Eσ. FAs—i.^4X_+Tqf(w Mc p䳠,PR,9B5l|~XZ?hă%"¼r)_lǴPgl,J?ՁZXX,_JN*snxyA-=(#6xfqȢT]+ GV{pȵZ`J:^}X+JBkws^, 'K蔪Kez\q-P,i0ys9 |nKܝ ͟NNd"SWc$xDiy/ "*DW%ۣGQ[5w^I1[zi1!g[Lw vD`LXFX@K-ONkssq~ݱ~F2'M-Sq2GKB: \0;&uQ-$ҕ!|5HcǛiiȵ$tE.:V+f 6_'諄\yG%aRZ!HLbAWBM#[ .X$xNeS=NӣHNx] ti0K3mn:)r)`<`$ʠu8g,"բE (d*H( Å߂ln~cSayz/z쮟y092K^wmf% _ħFMk۹ΞܘMF9}A݃9ǹEF ٤ga.F(;D#k'aJڅ`͔E)?02V.IQ-S>恿=P\bℨKT:}]g룠̟=R2}dWpOySEbqO˕p< OEVU&F3oMңUs%bھ&uzWМ><*VW+WQtA}&eH8理+-!AI4V ^B1gVNby׏l~=NM-!ָ̚|_V_\B3B m9D-wPVPGx݈ĽjR@~sj;_;ǘO]gþ` o/y54BFz<=Rw>@,eHEh dă^^8UJqGܶ`ͯ"-l6#>Q:RR?ΡIa|~=>Ѫ_:-Nh뜂=np$f\4Μ`a2lsȰ(Fu4 #{"&#V=`+g }6KkU`stڳf/RUl tKkz'foU7 rW!syI~po5ГNH97Z&uupxdoG/bni'A 9Nyuĩ?^ZnRJ;UW C9€h6k{?^^Ԥ[<-,.Z3k0xxmA>I+<Iݽ{+w}=}K\``~Wn7|U:ywt]Â{~}|^bK=q5EwLQ٬w^8`4_;/gt,("IҲn tʄf)&h<$1sC)GCY1'!M nwm9={Q<9;WDj! 7R;ѿϢ~ՎcJmN+@ B`x2.f?C@H;/yeץ-k|y0t\*)N_w!sBYPx)?z/)Ľ,q?yL3 I !nd"f(ȿr6Dty; G}L!#pH _.f\?9&NT Q3WM=)IHsyV?o}.?O[9K2wɔ߳ojY׀!:hF,'bW'/1\f-y k'Wx[Ϟh㗝{u>܁YlMbΰmi? d5Zm-343zV)#dVޕH:qQ0Q5O{8_-|kA1:ļ"c#O_83,' 4joEo[TzMNsw_<!eag 29 HlEWeTnqԉsN=6IueȩVE/|P3 ˦j}P*<ϫ>ׅ?6|>;ߗVɿy7UƗ8Ғʀ](X.Tn_$*TdP2Z-Px*d&Uj_BupђB:ŸQWXY+$Z¾p#,F{B57[VW V`|Vɋ퍭탶fo<5&--尸t;rpN_-/}!pT1Q@m4ǔi}'_; 1>-GO)KNwy5puP.)kWy0'aϱ5trOˌ[JBY`ŬU\&˜#qM hq-@"Vl3v϶Nн&숽#ø4ұ13uI۵5u>̨:V9& ALv?k]55l:su_^bPup+ڃ3F)M6CAU}8e8dJ&Iwfp+Wgql.郏Peȁ|2Q'pT:ILq]$l$ G9hАQ>DG2P8m"$m}R>OUSdA Z@F_uz1ic:iXN ħ; ,tmDϤ~7Ll(Jm?Ѻ`< I͸cz6iW6U t)/[Z ' !<`+Jϊf} RwT,fauoa3 ȺDxƿ K\0B/!C@'aJz~r;4bipnt>h|W6>zGZ ՏzgIRjE_5IQՒ%dF+V foŸX?N/1F>PJƓn(鵎!X#m:D, A݌vS#=f{4l3ᤓ G dG`|.Uxqf*48̦w^WQmйn* o1X-ɍpuj`q 5_ 2#*=5dfgA=GSVfb uXÿ6x GU1"%qG^:ar|sEț]{@͸d-mV;Ņs z~̓u&<:;WdG\5b9@)eQKAxwepa 5Q).y~Y{OWYt~#Vvufvj:?6F?>t7Rxi:|ca7ΊOYR"$W֏):qq|\?.}81dQysAziOfI4^Ƥs[34NgX& vR-]ͧPs?[{ s$iXMak/Sq' A;NeX2Fۊ8aymIeOkF҂O#ЫGo0B@lCa8d=0Rn:2ƼKIsqx5$r30Dl?!/ZV;xE;b˸qd]ꍌy/\@eaq/pfSيyia#(\ЉA083ﴏ~JkSW=ۓcd7~VCշR3O&k~UIN<86_翿|#e8~>Z얞YoV9_Xru\2"2GLG**xy Pq]Ё _1p &&u>I?/ؽL֙Y+:\y%;iN#AiR5PM)$oγ.;PF#FMε*WVnaA"7>'g8 bWGde1bD1ĥzƓ' `OgǥƓ3x1iAno8K0})KpVcp:N^O//m8OA%&ˣ|x|GL'?q$i$ɭ?`[ngM̋(L>p!X݀}811܋N%%}'EuB{5C3/>+dpViqMLL(?ƽy廱.LOehq'$I8,$1N'x>pl߬ϱ 8KT~MW'7#}q>8N؂DqJ2l2-_ q W7CjhӓM\f7my)'$˓N&_LOL%V.Np38ʂ@h,~,=̑w$|8a=@( hwB(CCxX)lн֋tVtGz5>TSĚuO~'Yq*Ol%,}!_]M(kh?QsfsC3YcusXnFQzXfσn1)fCJ7ȝƹwpX_$8Sw;[X'!j% dQ3X(zqGIˁz{=e?ОH+#`ʒD+/Jː\ᘇYެjz-EvE$a]A+z\ˆWh`{D\O2PI_bիbv[·O8.otwon@35 tR_uX<ub0KEAŐ0 Q¥.uX@ |yѤ77Ւ R6.ͭ5tYXR6{k]Aɮyejv̭4%.p~ Uyd]=e 4OX?~T3enk '˚ *u]u!rLM?P{-5h<:m `E/5R  >X߅E~ǿrS5WW6ŅQ ߲&7 ߹/ zI^E^ujLq?lQc8h7gѸN$o " <}j5"xXl’ھ*<ݩ]ڌ,Fs+5!7z1P0r4cR{nz8iHc/umw#ߏ*|E7ԮN)ll:,8xA67vv[;'ڇ/ IO+X ԸVXxY7! @X5G*zy,6͙w66OnMl%z~&ObWCT%Xbzj{GwH|i0mXR=RaYVum_Y-KKu1dMcisFyPXUIf:2cT#V€`6]xdmV _dY jafˣTWs@l'YdB;d|KfY\Ê@!14T~Df#?5M5XH"]S}b$D+!pR!#6_tyqw|I`9h8`6qx8 єʠi bE0DQ'd?=u'PnܥOX k qx|L\Дa)a6өZZ 1]kyq?dڡu`GDz 0(@*Ԏd6;{fAJa| 8""+@JSAv J҉L&hDNkfy"09QHtQEhgb}-*&$c#CG'4hf{5 s50%1w>8L}PhL& 52L5ndb/!63p9۶ >#Èvd #̱}Q7C$HG:!vO[S}|u17! cqǐa_j]s,{K52G0#mֶ∦c8ʏHk$!味W23Ei .<-/wXWTK :usR!}d_{gHg3N>J:lXogULѮp~`hHO9tZ-<\Y^' }AHLn쟫gh0O2f!+CqSI<^ߢ˽,5+zHk~0_HKҏ ӏڄqFU)Wu1mZ=h4l^^~GKDf; Ȉ!>?n{\zh3~TsLrdtLEa  Y^U7LoBKȶ!>c!% pr+\bh"adav`z;_ff1[ PpY, v_t 17%y_z`\ceS&DH$d)*M10Н..wY5 s j\ܢv⦆wmگ&ga=잽!a2sŻ(h YjC|J{Ly4!#.YCE2__쿘qg >ݓ2fDK F'1jy2Ily> O؈ڏ2g$CqklRfŠ]0KoBy_FU׾ 3m-3a7%T]go^t%,K'\kv*'F|mXZ3WVfyQ'͠;|]T^E}d>& 1 O]a͸ ;gnջwtc=:6(Tшf!^9ap>אOgo $o7?vÈ̺,w*iZYP$7kx.dp}t])=E͍hm_! sަaV[qy`Ukk{ w ˍ-k!<_lj@^ﴶ8=lmk 叶ZkNep㰵[JuI"j-n ]M?JP32eU>8?CI 驈WY1Oj4WmHyP֘&028*~΁uR44ҥAT: TyNYQr E44k@զ6r:,n͖*V:>-CtiXY c,Y#ܒ㎲!ȴIpa+BAwh.j\/?Z/?*8{Hk $zŴTARSޑ] JrRTTlJo _HwKlɻU)]BGgҁ~%]."QݴYM.hVUcXgYHEA:LОϓv:yyywϿZQa }gݣ<@aHrDf%<-vL趟B$BU҄1fӧE62L[ RLyw;QxyDځ 7l44#sJՇXR<ɝ)q;|[*aR?|VC%\"PZP?S}֞;T[;ۇ,din7jμIL5_~R'{NS3`z]F.P"w%4wxv}֡'{j׍߼B;HROIF6kFZ{|Wԓl"7VȂme{/sXMRZoldC(D9hU!JV$=qryHp3@+*+ހ8L:7(zJݗ#"ߋL(XU^ q_~;T`NM[ommo:PcѸXX/1gDz5v' XE_WF\j5&*WԳ`+ 'EZݰ p\ /߀腃9A*-; ΁ X@"I§1 _9o{GrxNw KtMh#-eC;랫 nqÇW?hl&<:[C1618N`>op`"vW-"ot"V׋[/"ovȓmnַbDHyw.7eD@_vHTHKb>jǣM\/mWu,5G薪3`? ln S}h;)O)I4(x) 1M mmsl c&)"קl-K$&@!X"P uOJʙ>4 ;i2QH flx`8 f9c``(V:_xa%(Ў1Xw6( А~lMaiﻴ^>{-. 4:|PAAƆ?HV~vZ"Nnl1 Q8p"AbLNg vV ؤJc/IߏI[-a#ASK* ꯿uǸK { &X"qB:=ԼάwR9CtE8~FQy W`~3pΆkѢ<>4B6w 1ddl:rǥܑ0NQPO1<nj\lr6{=kҼ۳땾 c4S|-d,Ew3=蛷 MA g0S8#Ɗ&Om 4kcB G#l\uhC^Bw$#I~EEG&AR$` ! f$>G )fqIb S@M˛(=`JXR<Tk6qȎ~d5 ;ݬ'9.Tjyjm3ċ%3${|ɤN*^5DX/ G,'iF#cuI 'ztktw<ʒ7X,u-;n7%]`E(j!؎ 9I&?鄼< ii96$I9G2NhOKԮdN8%"VΑK06U.l%}'1L*ٿ5fWidMA@J!%!5$w"P)HS \S!%q{ 8FhA n:M1rtY;FY\0`hYcf,f5=&ɪF5INv)dp9m0o)x)2Kh社KJi! }O$]yT2=VE5xRkͧt蕔ND!Q6eS Fsc<W*RFg6ԙVǹט e. T_ tՈT>Y Lߪ[ijt& bV&1q;M#@(=v"GI8Yjs%|%J,7SX]FO?m0Dv]IAGw0{/ux6Ex ͱh`(7 ๖܄w̻I/1r>f&OT=KNYS3uQř7zgQR˶ a39Q)ƿw:&k# R>gѧkñL"*"mv7ǭ͵O‘KI),SL1\r_Z##<8!Hl#lA9iIh=ts&^y;W=cg[+Zb{u{C^,YV}X@G'\bb^CӅqC<],vcÄ2}ӨKM1yOpx]}7LO8z~3cJ0 Gqc8UJ?tlxTO"&^0SU,s`G}Z3_\ʉguå&;D1:u7ʣns`q ={, ^ќ6hg@=rylGrHp>]CsO"6h@nEJږ'gǢwr_N @Iw~ԎN{vU |3 N_N@hkxlƿZ/泌 Gxx˝F1yjf]~w(o sq'SzA+&ƶL>{nA`Zx_9|.W=g?GG"oHRBg)NZpYQGUzU}P~_ȋFDO-.H1hc Z7G}V]D=~ pnk,#;UM.(pA(4o?mNj;9^Xݡk==>=~i+{/ź ׬tC/C ~:\z~|攞7['x3tJhV A!rO`ēݗ^K=t62?nr~:vDA.O<|~GĘg\9NWIH}<_=<3:A[ma4x^/Vf/Z!p_i oaK@gN#zٙ` a˫2be#2̍ 'Tav\'H@AGulGE.+Isx8o&M?iK7 S#ց" :T7a)l(0ꉧ'/4g.4{{g +,gD3voH^}Q, $;& $rػ aa6CT6Rq4/|;FS+\ @Y(0E,9~Ot)Apt[\;!bx(:t5M"F>*B/\yɑRQ9~,_̊Ґ|(W@>$)XC/33;@'do+^ɰ2{`]$/!軝2JSyQM0lز# β# HJ! ^2උNr!n%P!>FFYsbĿ "RMm:#zC%3ÇruԾV^"!4KЏ#$ *H"f@AqǼ@{Y9ٜ`@8H#6Sr23F 7F0CIeQPKK"lH ٖ򱬇@I^OHK'6P+ ^"_l7olt܋J .6(D,ƨ=OЦ7WosuCqU9sTc$=Y³HS `TLipqǏ`l qڀ0J qR-!Z%A)yr5e~G2`FKIݮOakZaqTur z^ A؀,{$ ef..*!gWYܚZŲ\:0ɮ83#RǸٷf83bTD')*تIDceӨ 1Ge@"u1|׀WRm)p7أXd*[b]*%IBl=.XqSdtWcs d?yCeDtRJ:?/W{Zp.m.eX4QXB5wfד{)E4& ^qJ&L]*qޛoG!d:#hACW-(voy)L( à EV&&![}9-PfkAgwѳlJmFbFh.q9Ӭ=db- ܭ"x)D(L8{ۉL x]@nC5vCUIq1ml_( ?l<'"[z( cM!@l[R&!LXJ7>w{xb4XlMB RGZ}42rx˲  6Πшl:&IL)S~/b%{$7{b.]EVw'#C zPaaJ\Foz1|[5V@DqmN &ORrV.CP (3kxiL*:zI&*cf~dž_6%vvO%6 *:SzAj#DD[ hNQቁ(wߢ!n4ƸfB7wI :%`j"yɜqpĀX*K_{OmE}',lVj )iFEAz=z\ 1,b0w)v^G*E.&sp_Ok-9' ^ M 2v~c@Tb3ѐKIIQ13sPdk0 @ZȚ/셎G8ؕڱ3b ^C^.=**;PGT Yd3:Ruc%1IMOzG h3Rfro hM,X6.(3iCIMml'Ͱt7҅8SQ$ l4MM@ߛL SH遉B6/M16F!uL ^ y'P"}bب5DR18}Bwsm6¿o;tU˶m6hʤ| z\$ |qԳ{I$2aWI=j\{a.'!] EOOḛ-o%򣺹>%d F_TE҉|Rz]*q#Qamҵpzt~pwi/&!?VFORiq) E$wvc /3;PRƫyKKX[d4Q2-&_(ƛCl229סY];e!@9{NkB1v b20ТIMٟk$`K`v`oNw[;xaK ⛤4^'"k5DiVA^Vz#vdR{S1:stpuU{8B-dfOԠM5(94,%3|. :` H|uJxnྤ`U9= K5%+c( b=EGsNzE_ } yfI3Sn !~ޙۼ\ -|#/vstWiz=Žfā3'͡?=jf(]R K~)07ArS'4{stْHV̚^cڇ13Ho)si $&?M,ԦZS Ry."ލI˙9%Y\-q0hS)7cԗ,n #m/M:KB'T҃"+U<^Hx(fm^şWu5!]'<+z__Hsbd66nJH6%OH1?)gcQGޖ&ń_uұq?|PɲIw {^VI11X)=)fX 7dG:t2ɉrbOH(wWATJ|xlF\@`0wb粊e%dtZj|H&Mo;}żOdMȬ!(ߤiڜ@va f\t9-8'2L5 ze6:5f78HM&aiQX){s96fL⹟}*2rO>ŪkY#iW92t#}Y;zAtA5;\d&wo]%RH_vkd_zоEs޸]qEs}:dK;0$b1.J4S*"0rCC!;t荔c%wdtGtwp..R8ޜ1n_r³coY[bitYt:,LC}x+f;19+wA@@O@lÅ=#$ɸ| li 궇o=V-D -)RJ⁧TRuwqטҖxK7: 'W] ;),hVnv_X?c3:8tMR6>́:/^P{Q9w8tN 0dԈۈqS'x/~IKjJfx5 <0_^3DwCt]sU@ތE lj%~;)(޺^޺Qw7S 1~5xa7 F[%t"_Ru2A)*ܥ&s(@a 5|&nm5z:w [reѵc1)e3@R%ru@'9dfHK0 v kOxҎd^qmdN \+J$2Eꁽ(6CYeQVUb߯7fJaw8@ȧ-뭵J=o/1#TG~jGq,5 ./?+&[7%!*<Fi  #à qk'gaprȘ,Vr)M\A:;qM&tgu7>.Rqj~&\Jf8m^Kc\!|r;<+cť FŬߌ8913'_+6 Jlոt0IԊ!tr4#_ xĸHG*"g!b8 ΍-\Kw %9%C6]0Ӆi!!VdԅHϢ%LH 1S? {d*kS~Q!7 -f*GN4/ppZ9S,zLjz7/,Q)FKq6/XYZB‡YgeYdeYaRK,958y<5,l^*ISz QLta$1 Ho-T9i^4:{|PEDwY}_Tv=^ǦMKJpAVEMI1+VgGq|/z FI)M>B h~i9%M"qkX' ռYjjKN&iS, xc35+/adݴMb%xV.F";n86 ֌iMȯh. Y]NwkcstJWP*uAAQGZB~m׶uРFs_֖xC dGa De!xGyTՓX{yۈdN(fvV8-"4"&N1#{Bk(c!72F?y+rk+1ҡb e]JkpN$yK2XT4[M9L <!FJ-9JNڃy<>욾Drj>%aw%\;Pf/5KP-PWqfbL=>=!T7!.)$Uro>mF8ꦚ6m'zco;|=<:3{qnq]hs{wRx06ON4Ϡx 3bJ;P2kЁ25[v㴨6W:!8.~'ߡ'ѱ}:KK : ^?q E>|\F{XtuI"i5v%u Hn|7\)3ڟx6+L"imT>{f)HР-G-e%!t 3n713 =ɝgH2틇?e>;;߷n&{C3>;_=.8xc--}JX !9 _Fw09SIg눃DwOOܯ+TWe6CU3:; ۿKǷnwƫ`ۜq˸4{{`3O*KvImKou3Ӆ/XXu9b|OZιq꽣]ɯn-E]MT2 - ${F\M\HRtG7@'vL+N)4ep$IqXl>9l|7~\;}sN)F2? "{8<pi$M;N r$[ [1e"C, Oymz /GoɈl[d~Lt44;na3ktk7M7h&d#%o#O\1V2SlK=sn$sd&fL$}ۙ LJ( ژ9g1qgGej{g.g3 Ѫ,'XH29ãMKKҹ9.*A[Bg1Ff}V8n\B.w08Ӳ",l]>i7V&i~CDe _WC${aiD<:C-Uʏ8nr~:=4SZK0iCr&Ј(ʣT:&BPG7;'LRÞG}t}qy-F@c_f樿viCw)?Q( v@H ѵcc(Dȯ*lvJλ13ϕ6SVtoK7y\Ayya~(#tqtvu' Co!mT%O| Bs=7>*SEgn/瓎Џ:?F` ?"'Y]5Wpe]MAC*`QHpmP #bcYD%rR+-EݱaG I#uHR9H& F:n*6 Byac9ߵt: Xtz.A_y=}d((s٩ZJd5 J_MǮ V>@=74&RyBix[E 縑@bNq}UQ@9*P Ц̮\)0$ā0nmӲdLL4b}^LiӻZ"֙[)|w$:WTt7>3ۊ9ٷ S#@- a Sl?Ec~b!&EhJ8 =$ye8xO.-#⌑W\68;M YCEm1wQ>N)njwne0\u42Jv8{ `l&[QT Q\{(Zj%Y84jyRb^ e a=A*R #!)c\^~>>UNv_nQYf6dM:%ߐ"iׇlyT*8Ѯd74iQtB^ז.\8~!lS\%gS8 ‹[CT̻d07PneYŋx6: 7@g@@בEx5,n/$E]ᔐiJt/%nIg\<ÖP_CQ(p|'hN^n-?@ [8:>11S۠3jO,ϾCuQ)a뇾( ip7&Ӽau5eYz킜gzo.Whn8sN]N >Gqg{Zg(RǩD0+4t9g:tLr#JyL7"RAm .8Cgºg!yY&PPٹ٣uYڟęV;6:ᘮTJK)_q?Z_¹ƺ: Y@F*"{c#5ܓS4}N|cOA't-?BM> %r8OiH?F>N''uM0:UBkTR☶;y莻MYFy]e޹{G=Fhq~(9„([ .+ɯNr^4@Os%>w$K U)Cu lB9clՂqUj@`ch$]S.I&rt%ȼc7S&HV6yɦr9G&:"Z(Zz%sG] ,lkA"Z]Zkkhmr;.JQ[{n~1y0 ,Lt Q/'evaxTp/f,cfЮboA !8(|.`[XZ8B藵"zbá<ߒٽhB/rZ8Qt'|J%=۱g%v$6r};gjX)(hμ. :,IlP&oɬ"?j3YEAoV@}2xL>ӹ!'&QI5hS7,߃:WҤ'9@OOFF.#CkBBPD ] ]2%QG/cNi2kDbѾ"eDN _3ʺhit9rR֫ '9dfD% ͈7E)a;סM"ʏE<.&p sDA8xKb[o˃,}N6\m~]T/pߟKvO+&('ؖ/H5ʳz||\,s+jk.n86jʊOVogTOWO+5Q=]k=L0 i?Pr{\xR{ +]j]4jrܨFQkJ2P,srSѨr-#Гw{>wo5@Fd(#~jWI"w9n,/jPbfz\:o#Xɨrig$U(/mg_AdQ5;Dhl\#}ـ%Tm+ڵ3kK%6fu%?Qp]4gϞӅSTN+Bx b{|E `dqjc'@TC͸孊O=G 6,E(\bFQ&w!(; :uxE#] Ct .QX^Ћa0@seQYmG#klgХi N؞ aR*6 RO2{Z!ETą!2i []Hl~.F$^oq=SS!th =s# oaluCp p0'94LBI&0.-C?9iKA8g ^\Pr `:|"#=}ڋ$SݎJdO9}m ||rދ0-x>|!~;}}tv oOv[-qt"v,"n,w^*{{ۧ{GehtW4`d5<~w;r[| Mnӽq|vr|ڭ] xǑaԎc<-AaGbyR[}ٿ‘?Zcy|+|\ӶܾF /#{6eB+iY(8a rG˘,vԇ=?@ҝFabI}(;AHoGB•W [-+N̶aT![Nv;&^" uv/ǐGɰPDk̏FMdS-R>.s n-}MbyA|)aGFҮ[只 kq}~+̘X0LDyttW::zBP{nkShZeht(0]>??kG`fPM!&wAk]J;sJsт9%=. |`wv-%m[%ka=nig4|\,4LK*^aea@֞Dc[g;i\|缵"ocuVk6[":ȢENbmyeYS{ؠ'$as̱=H,Au09=|4\uzܦS,`y΀2{WWwP"AE䎼z؏ è" [Qp]sZ]Nˢ4V>B1GM ZVᆲzb/9\2>ԅ/ƌcyh:z4@M*g]L)qGR+3㈡/E3Snԫ9)E_3KREmIo}eW*݃gfEo%oc4Sgjw!WnQ"PP= t(5HF??o9?WR%渦a\ E|!^F0a0 r{vdshD?TPI;^G>/Fc5IR =-nG>~xc#x cxUs D$3GgF]܆8H>8;<:E!F{fǽei5zEMw?g`0 V?̠ZZ*%?+d_kO|  =!$c-dܰNވUK(.bB+ |p D*qE\< BR MwLL(F9q^_SuUXeaC{,\]uz 8mp ]Z($j A-lo3F6̒+O_Q*?WU*o=ejK%Q= (t誈)^^EĸQQ0_l G)j([n$[F6[# m?sQFA,pfJB7j_ YNY2RW\U.*r!&*#q<x:IQ38QFZ&@5{JjXu0DܙMVp W3.z> dJޒ/ +ʣQRon u9r0B@d~t?/DZ+U9yt&_h[{^x<\8=y )igϴR#'e搕>8fg^2ϴO+ 'Ok_g$WU* +*Ŋ IdAaXb- eF]7g М?G Q rKSt2džI/\)Q[BtV i!vq$Tx´d@nf9Q}{uZ_irV`qr^RP"PIR)^ܐMEKVPVv0Q]j kwTG=UToO!Gt +۴px#HW#EvW=:K`}Rot@_)=" @>P `,@. Ax45o.ldr;S3/y&{f9;$ %gAg>thJ 'A`=IZFO's(]hj44w-IBNUM%nXMUd115V(a&P*bQՇD|%WɝÏlDLBD>ˉ*X{ Fp"$ Bq_R,sSeiǜYoxĢE~W+C$Þ<fHR|#;s1 ?{'YI&n]4%몞)qwQ@*s86MYC&]w*;'k'8D堌n b1 :lngh): I^ME}|$d2ʐU]^݉d\nxrߪS5jfWVP=97l Г$>aɊ;ϜY++_mu_ד'7N4w{ģ3g}vz!O1RX`=33%n0b}aYͺ.3 C-s C<. o ˁfV,yDG;E'%ވߎN~%Z`oBALQԞ> FbQVdAUowC 0z{#pt DnpsIU\ʋkxEqTpȜn῎wWxD/vgwh@O =kE [(H¨CvW,uE䋳zZ2*t\;V';!(ڂ'|AKo+~ z_5<%y)j߁̅ŏ?ڽZDR F ,1ra.<#B; $Ƭ||OE77ͧhKwy|&߀\PL*W~ Ík!׭!gͣ=A}LBl-֩!FLI%F42WG %i=Pc.i):1O9\))Shy9T?m !"kd7o[; 9mYM 3= Go]bT`ͯ Tzbc3nF ";C͇IB0~/kP {{?2+᠗o`V.q[M |7l*-"nrz`3UhBap.Eź>c] XԇOiV"hV%3|T-q'ǯgOy\&jlO:[rUvdݖ|]wm\Ǩ_ԟQ%>poSW9y7< !Dt46a\GG=fb_qƅ303PDw>06gd^!ka KIAT6$9ty'SrRVZTc.(c&󣸻㣙"fN%UZ5PNjv% *,߹uQߴel s8{`rF~gV_ Z-5_ST?>{v5u@zaQDlc) q Fmu?,*ڳzΉ o@5Ȓ# 6B v_9?Fb a?hS~4~c; E4ԋK(SϽ͟_B^vŎy~";aA&#8oG? u0ԫJ4j/YWW^Kbq8XUF/mc_kWP++~r" L8d&7xZMN{6DoLJ{;\.ѥa߁8 S㯹\*G$1E%mI1:W‡}~/#*;Ϫ:fg4_W7GoxIELUhDncܠɰJsS˛2K n8aEEZߋ W`K*?1koϏO@h~>pTLOi_otE"^?8jq#2#Z&<-BShzT}ů@J^MЏh/0󽝣_!xȳA]\Z$)xux o < &5=@@n!c 5 _ޥkyV_MTޢx|B &W[5AeweO^Wov`""%uRHAKt h2`L'PQw~{B9o/ 6@R奏b2{^:2zE* 4$}0M(t幊܂rc'>cm79Bo[E4VQV^p7@{G4Mq1Fmh41caFxR:0!tޱΉP%-'s#!}MMPBT޳yыD+uڢ`i<(y>REDF\t`_4`5D$O>:Kq7A)ʧ"<NtGt)pAڑiaYH )C0#/Nc-A׈1-1cJ8 @(C_lN[K !8$Y\E?vyAO9wMnAyzm>nW6]օ/gڌO+OR?_oxĈثFcuִrsQhi %z~I&( ,xW#UQ_5 5C`⿅֮8= *>L- ~@Ou[;FPpb2H-<ӓ5Qĸ@IQi-'y2䋔 0E2@^O"/N`j*@<׹k/ˢQiVVY ÎWix}z^ XVlի u#p)IOa7thG`#T * 1VL[=T̬8dL*B%#eb4oTf{#vdfZv3tj#K)ȈJNHXd>9< 6զ^\M@Qݐi:ѣ%6y+U* 6xΐ5T ֜15V0^OC+vCjUWxB)tP&ӈ-( nj*H -lh^0R#a}Q` x6  @ -` pӪROLl/8ԏl3 !wW`R &*Ϗsl7@tw ;!,6ÁHx5Dvrib>־g+q_s|ZLm>*?Ob]TAɏ242OɲPc6U<6|#= pA8LixJ|O2_2kⓨK1kd{S{&V4T !:dv5Z2Ռǣ()| W,.'r≕W пojCmƅ9j01N 03첳_1ŗJ4^{lIHxÛ+39Hb@+>ֲb$F3P)qŹ"Zl@dNEXԛeKՠіCzt׿y0iXãݔZ| ce86ǜvb{2[PWU!j]!pV؝T sfXurDd+5$kBIc/ʹ'к Y8o힞+B(Z6K]-<D3DF lqu2%Y$|$K%Bvv;;yD>cH~̋w`E^P<:wCE+ɋxx|X>N <@1ǚP( |/OXatb~Ef$q/YT(=$^@4ή\- }G'aŋp /(y-\_Z\DV>3mVzhENd01#T`tXwr ^4&9y%7{A֨}eЏ c!̗.J]~= O3}0j  ̜&k`-\\ЁHLg:UKt)}%AEJ`ܭD@vvWF n}r@S*"zxm8?ܲ$~$QEt#_ Α8MբbM^{(=׫Ȅu2e!%% D  oA 7ZCĵޗAj9>-;Xl7=n*tG(,G<1-%OXEb:**kU;j GHivq,c6j=qw+g%Q>l[ZqzsVzYÍZ䀖ZebĘQSKBu+(D41LuKeZ/PxYTzQNM}ŲMꆎ Ӵ9;#uȒH3=<q3h$ H o Э{Jų`0Bv&}A4&1_WQ[IJ}.; h-,˰ .*`<2^9> ~?ܼ:U뽐A7Ip#k{h,X};Zx{W be܉G<#,nA|t@/4P9U#S~#]1K>4Ql/'\"`σK9< }(A7k *b!f >,w2C khvzײ:T/062oa l.B#1)ZS)NNfwzy;~6k'z±ՋM]wh]~7Rb ~WhN~6i.NMP9 0$f"X`/ML[5IQ,*b$C)Yݒ#iwgi*Di 6ࡰx"ȱ>AYj+ЫaYAn CǏtd*mezwv\wrB(kh{+≯.RWNwߣӻbf ~LN#O|XʥUU$JSmW#gx eXUF~n2ѷo>e* CϼyNVMk-}6IIu=!f4E{x'FeB[ٚ.&_͙"glx#%F> Fn3C6dF &:`Ny㣝]œ41‚@ֵPaobs(B}IebZPSz-bͲ↹-8ܪ&}Tx/m|ˆh߿,Vh`**O0JxK˴t)kHx^;"&R2ZRD"1 iI妪+= z>JO_0:p2&<<@}*~3O;{>o/KVnz.Fo]1Р4!$OWiA$`̘V'$ =E\M"F?F /0 v?3?$_-tǜΏ`C)t듻xD7 fǜN.E| v ōA Lx9C]DORhHUJf$R\>8RͰV3FRdiiuؓ z>P ڣ Y6Ohп--A+ LˢOm\hˣMG v l t9&=x{6HJ0쑁t;qvP-0mkRv*m^÷{bxN. }ƩS(i+*7CCMq lJг/NZ0[-*)D"|R1Im9*w^(uhC_Ztdu8Y*A]Y-e%#QLqM{OYV OT 8Ĕ,eFVav!(ԧ[gɃ$m|n`4GMӖ1A^;$"EL6瀅$wֳl\JƔ4F(rv0=yv!fZ%Pd*4y?4~yPfoYA[h09tI0H4iC8O"pQrF@-x(IН% Wdg4 l5|NxHD]رC4J/KLIOP?ON9!z%o Uu RTq_dTJKPAGf1!%cŹRbLN"9tǿ:̛aëjcz: XTz],RQNwFaZƭ!"|bJdGOɀK&SWM `͈bYf1lnAa&:¦,Se_!ej4؉dpIê s,)e@`JHAP\ Z;G/v͖oBzV4Jz |oTezZ|HiPHk"S@x;> & Qd9_ïW$|}QR=,^(4x-H|LҔ+f :S+cw=Ηw7Iь7]PXOtJ'M5J*>&ÀSA!063_`@aF^3#ϟ(9HCAܕNXG_yŁrm A=;@c!8j(9_e#:e=?}s*5~(]Аn)lB 19`iE*4%1S#Gٵk#T]4L)^4`f%1V&/Úz2nY6sZ}avnGEn {CP_Q͐!7mtND%ۛt%9BXDlOd a&d mqvvG)Ed'-qȋ\r4 ǫ -C| ^ `D> Rh 5c{nǴKצ9)pLu1@ ;2"50 j179XZ"Hq VQ3) V* LB-!Cg{/&6$7FXQt~_e`*C: = G.R: GFj⩣r򊶐ɠMe BzAYU5w#q4/ 1=.#Qy;<;L~{e@p?qO~}մa4~)v #r+Gn]q 9mToFS<0aN^]!ף<>jtMwHɍM!6d5)K#d ^ߕEx2[Wl`Py:2L/)Ik>mZAD|#f.D/^H&.uTӭѹg_eECwd ;w+bA^!Q'},kP} 31;¥hڢRN<0#-ƏQA xFt9e䄔~Uc?Fu) 5jg"@ dž!__wwQCy@_r7AUx}ϔԞjN8A$.1>1& M"]{%0סf+yҠ:F} {Ph2LRŝ)0dFn#w;7 ZmaK`swn- Ģ%LtzjbAM9'~AR+7%c%779id$~M[wCw)x(o>eܬq6֬-u32M63^d!x`Pd8TO#)$,^a]nqZ jm\,1IMz/iG{b|x%<(+dS!{7QRne1H))-2Dz:VD\1vbC-_J1Y 0}baPF .cǸ}DK` o#liھ4hک܂ [Dje3FRH[lԼUBŋ2q*?>L!5 aD2n!h(@8Y`%P=x? O >pD [͆!HUG(-SPf$C {& !A k|%"kpl4~۠[^D:Jk:6#|7 ZGe0؇1޷z<TndҲ7IRDT[7 ''[v-q'iMs໅Lm_QQ&7v\wbpRþxdc"xp0qdT1)c{ro CJ΀ΏOONyy燻}^=aXq$`8ڱ8ee6:lHo#޸n-!IZVuSfGViɈކ ]hØW}>a[oD{8Jӽ_9*]'uJcҼ9k+Cr!Y܂Зex/+ DCeRx![V΅q6jeVpʁ/ϩѓ5Y>)`d(dwA`bѫvt%DYUv"e#ƺZh2 %ImE8^En|E H0YI\7jw]nr=ݾt%H~$yQ9=cKq$LTs2!\(}*L%PR829'$WJx\[SL#&YYY212-tѶa::IDMDg/+y$dD|l2\ƒwe /oʺX@ee0ʳ5Jm3A[O}mKU>BF 4*B]lhF6@u$4ꜞb4kjvDBJJ=e c Tx+̞ss~&wӔ3aoz9@8(zk)?Mˢ߱7\ Ʃȓ)Y;%RF\4ÅRInA)KnB:c8>DFЇ Pjϟj3KN´!zn&T3Ǯ =sv$a5;0Gdyj~3?s .Р1YxKVUίyb*(jRNMb\P\xmP9{S(uۤJ)V)^7KĨ1 GF36y|}x5[L QD zev:/Sfz=tB$06X`ia) }N|)IwY+4N 3A!/|0^tlODa=%sƦ3xٲ?7z-Z %F/7&!={lA™|H&rB=i+{Zob5;G27?|-i+;R^t'pSt%X(2i/a2aJvyneRJKFZ"Via+ 䘘cΕ/ve.xBf.4jNLuZ莓AxxB ]넘kL$a0RneB]V@5׳t@d}C@|l/űgs츄ڼ{g' ,:= F!,}|zQ Ansl]nk`eKԌ%,`Fb͈dGyc!MyI$ C tp[/4xM̻?wiƏy4mAait2瀢N&+QW.丒M"*5"4L ;l[@ e:Mc}F,,s Xd4W)cܕ3i[0xU.a?jR (y<&դJXUX1jmJjrGqZu9%bܦ`OwzIkw_ΛPG2*ne" 7*"@1@צXo8>2ZÀY]&7V4^ALժq*m>6^kCyKeA)"+BfCi-:EloAIu爫vY|2TO)qsK"2]%!-= :r?v|儇툢a'4QiWtE۹CKT$RъSYInanL+ /_5{ J}H)vRpgĞHߎDI+"ɘ~۽=) zxܖroP4=?CnQx5L&i˰(Cɼ$*N>lA"j>3iӀ4!&ܹj ѵ5eȲS|҄&Ӌ!A0"nC ;?!Ip(yBt`~{!N&3c2< ۤVJo) +yI1YF 0x@KVW\ .\ʢrO1'7RbLTqbBE&=rq ^'^*'SDeIꔃ|39Ršݦ٣j)?4N6L+b`.u42-C'#8N$߀ qhÈwWuM:qo$1S # =q+ `o3w!Ҳ?@}.!]Q')KY4%x";9 /s~(:mMdY焱5E'h`ꌡި#M3A/߫1yUZ'CEWM:ܧ1f'qm ܮe6wQN1QM?+ sCfvqIi[K-Td.S[ q3 n;|qu{pz}oNuVrm$KU*@>B{PxGx_f9)Au)COvQb4ݝۇ{<:nNn$CgY:Hq&Bq\ Tj^~Ѓ1(ްʃ3Q, g$By,E2G'No풠,Z;0&a0B,$#[F`mĆdxnp=;&Ӓ-'~U9UǕtt)Dᵘ IMO b2_lb6rfIQ;qS`}(!엩GI.wscNlC0XȯH8cXH(!/e[|v2l6E :3'~Ϝ|kN Wk~D:$/tYa&4R >#t>8%QC3@ik\v ̨3I׍LlD-0&6^Pz>msјΩN&8ʜ6 ޒ/k=IfQIĀ[i!}ct|#{>Blc钥f)/Ph}ah,x擢!89UL'/Y@5[d'{h$R j`59(%9^zt#eqЎyh*/bqy}PIJyeD-ɑJ^/0gi8[߅r(5!>q~,5:8H'A1e QvqcVBI?,+ɢ]Q"'B@2-&Pnp9#@JUŅ' I𸃧ex.Eie%t)է~|lyCɋk庂c1}s95X.7[I3g5 j*uj]\3weq17yC4ʥXնˏrK"?? ➩<aŎeu\cG|x}:=Ypa@C#2d2ϦAQ[Fan}{xczyQB,c r1^^"8 ⟟`jc6YW ןZ@q '6,;`lK?-ڣ $fb,p_D;ǺnAZ[ӑZs>$Ir r)N)+Kw,+Bxrg&eO߃-Qw|V* [/0e#?a:0L>+Eg*RHRsUr}zko*D̈gctg`{և/0 Q%'Ax;Ovw[FQV}UҮA]q(Q=/KeU\&yURՇ? @ؤ [_w u:DoťT"5E6s]A@ vqC xQ(s@E.1RsV==IF̑(י*ʀR\*cEL;,?,kiF1XMa4)[>[`J0,Hao5xѝX ."LxD}gGlQB3-Ŷy.|^y@ fn|%B +*[H3\fo625]f=(%C]$ L( ,2" ۉRamP .U>]sri Yd6XaҒJ|oT0C5m9ʮ.]#f-o\_ Q#GXGZcä|>R}'mw^m6>:~õ-,PŤ/``$HA<]E]ieGq5R^2/Y`=Om@Ns%RPLWEV!&*;$>w-leO\mq vHGbܑHz _ZEz“ǗV߃N J9jQ$ǻó;g''_vOw+Gǻ'ۧ{$#`z%C#Qv&YW$|Kʽg}ZSS^^q7zGuzg__W6r$-GdP԰> Z,jbN .P-TZlji:- f |&[Λd_HD(@SynUW8fCk G|Cd`,~aQ Qnry-a٪h|ZZO|+נʷwW\^(|j V1|n kZn׹Ƴr"Vm«B̲~YVD3n{X\6jFz}/45/inxY~[-a3SNZS5<|p:< 0LBhS=:vc?-)2@~aV!VHDl{vFYkN*tjvFy&-0$Jq}*0thdo=}~yy Gbi΋ݗ^ã.^^@ūo=Η~Rq טL;wSl.]606>1q|һfQ3S' +լo>̰+1VWT?և륏,T̔CB!7>02W S ^ Em1 f|ww5왬f2=Rm{ IcuөTbḓPRQ6 zYdӮFzˋK3]TkPQDJ~F5^Daz ws:ֈ B͖03S2"#clDF5wpxʦ^0؅ sseS? En@q0h񙳥񝓲jF?#SNߕ·Ñ#r{q9EqXyyt.t{)0Rm|34v = +6 TDӣV^t|OVN(.OS< 15rP .:0$6j.=•Rx|0_c$b7'.nvatlҋ ㇏2^tJ4gSڤ"sV̦ճ)MSM=vSR1/|$LJ 3zUHgaUdYX;)-!Rmkퟞq֝@CT_((%̍w(Z=m4 d`Fް[G3avvw"b Q1d"!p´sOˎ)#4bA\d[.5C۳LIv, ]);H FQ{c\amZ6ڠObQg~S(g7tŃmd)s- t.ͽA Jd/aoJuToaq5%E7%1MYhT4=)M ]טb,'6t;FDQK,"?OO@'?^GCy{8QTBUnSXN_ QA?mf{gZ<; qx@Z& @= @Qt42{` ۘilxZ)uVunct~|+8V`ByRlPJh:D'2#9mni(e (D`bڴi W@.J@.0{@qۥ%CZ210A 59Ar 2w@9X.(d+î_0Gk*;w0ϴ 3;Ud*2gʔ/4M6of܎e'2:?->926ϥ ;;Gǧ-1S2Xȴh쩭Mf5n Yup8dQ8R"(SuhҒS$m pvZXY/ .g$EIQ6T@H|)19(* u:o-`;kPN޽J4M8MêBϴyWO9b0@UxEl Dr̼nrCHQBh$И׾ZEx*cR(bb7d|R4YC 3r2:Բ 拔/SMvZFҳ~*m.(Je|iAwRachgфeкѼ]퐵X#4о{+cth޿NWL-ﲊ ۧ]pRTw~fLC$+K;H`Y({]g 'l8w 1fC/G׈;'j{=ot|ųn6fi\),2Ps]vZ}'ۿT7,+w_TѴʿ*ەF\\}BCv_9bJʹ&j +R| #㾖- selsw|a+7h¿Y}VZVSaG9eVUi~-<tj_pz~oi/n2i`3T`}=҅ƜOO*sͧ@$#|pU?4A}'v>(,ۮ5)b5l#E]X傒)S ) "e)^dH~; _6r?\6S>>Uugvq03#"czA[% q4Px)O;g08^A<4TO2{F%K<9=<>uw+善"^vT`0(05`X{.< 9ߞDƂ:NRbrL~̀m :H=TI]_"0oic@uJ$^3.}4pH&e^=+d.~ 0o#k9*OVPXuY[VΪ$YU9!ȻjyLn9OS `]awHpp| |+lTeޔfT1] yGkS"]J{7-SU`;,FĆRL88FS3 tEڀ0YKY1++PaW9L>QJQWFZ5 OmFzDy#6)bg]2 P=$sxO )6&T qL)wN4&51 <'Ӎd>8^d; !8 oPB$#g;!ܳяOvtA֜5Gr:V7>]f(y?hZ=rO\8wdҎ /J]e-W A61tsKڰVd-/8Yl[(jWyLz ‡i zLF6Q+JWѧ%>᤮ZB"vY%XJǭ=&.d_RXUUHd#A9 qun⧽@=x>j&mMgcه.F?lvZUn'b߿yN#=AѝI ۫cnH, K9BU(wL$&YsKH݋Ȼ/&x\@,bȴ5 {0rT U8F{i% Rqd1h vڡffM܇Hq:)G6+^x=!Hɔ{-ޕI`=4 '7:a46vN O.JTĤJ%kǘz;@YO;Xqɿ]]{*H2 _ֵйYt̀% 2@DX k~T϶]%j-~9j5^Z2:4 U ^23,7 OX%-*3 #)g5>}2i p, "gfK3[rE1 㞄t~.H )_`ųN{Pbv~оtXIql=#GYsO?_Na}?m=mI|8 N> e8IM9=W ΃D-&t:&Ճm 80@{`d@S'ZH@i!И}2dAl\.^s{xwvBiбR{#VH}O a<Y`pͪS=>%nxAIT}uk{S @-Ĥ6^aN3kX; j]3ѵ?WJ_^O\[;@GxI\~,?GvUŎUMj_+A{^:d7H_Kgv|OsWa3Z8}˄Zj!BVRk[g8'ro)纓Rx罅arී1Y9΢&aۮ1Mț`m(fƣI{,$e#s *|7d4Px AUVYm5bkKsj='4z݂͛7(ZW4?WWff3$چ]mdErv)QLX]iJR2sr I& NٳZmm:?]b#]ˌOi5H;-]'8]u ΃6g-ޢhܓEmEL1(>ۅm5 x{zad`#p^[$O<쵎ЁA9 ?)mžV9=F#xc_Ixoi`r9+Ǿ/tZ=oelu8*e[ !v# Ur=+@rDR)K,אrbmD*|M%)]qY~8X}?,ޥrE& >БiioL*(;z!4셾HPS&NAbt9n,/`R GW2|^*˹Ps M_ Fe1# q#;ɑܛzXt}LjFf]ܟʐ)J"&3@gEhZن]-/Ջ&;̖GY}]*TYg4_ȬWƬs3N.j&Nl4ZD ^/S.%3%^W.WYǎ+W45SjGo,'9^avR!䑳{LI<(hY~@xIečөt1.mv FЃH,B-FO ok)owȋok>$ Tu>ϿlNYu\7.LoUOWW]㿵 )^;R?]m>DQ6C{ "kUT6\]AR]hZr|oS(Aꈶ?ݧ:3Ɂ`b]f4ltt:]G,ޣ:#0-R( sm8\ؼz< ^ "SqK A}OYcw" =RuMc2.n(U]xfU,/;}}tv*mlIg范1 5T{:8=y 5/Nw[-'{;g'[KIޅSV|1h!wXNJUPK|@8^3QbS:SF@ "uՄVĩ"ZlpB+f YkJ =]:տkC%OHJc͇ " oO% ȰcpZƄb{2TR߻&.g$G(K h)f Z-$Ph>IIi2haS`CE9μVpƬ1dƄ Cq(N1Pot5a[ >jL1t ̷#+cuSĮЎZ jJI0<ܴ/>\'#VG_©;^fXZX5y_4-D&XE=0XVJq].l!sB`q¸|iokBG}T--SV] ?lŚx{t| {K-C[4a#~LlaR[Vԏگ0V|.=Opc1?]( ߰˵%`}%HG[kVʝui)+XT{,vDK,-Efm(6Gz}pQNI3D-HءK?CeNG݇E4,F,Ųa <4)/l7KY|変|}_52:DRDz#x rɚ;6ܥV# RUv` J .2),ѕRa>N:.]JAgb}XaQmEqe Ut)):1Vun!}2wBZZJ?)brP\HPKVq~UNV,p\Qg[fZX-U+ A1J &$ bx@EzOzҳ&!1c`}t6.\J^o>%q$JO.=  %0h)P'2:SZXP&9dN)RGaH|HEq"<&hA)gvjpMW1WxڬCS}୸܂2ʓFs@ɖ*DԞHqd?ƼU~u# 6pכk{uA^ zI}ǡd!Xa$JF8PK !m]u<\v`/S*JjZѕzD9෽=˵peun6   ]Q}+7w#)Ua{&DOdҨsǬO\Մl o3V+ܬ6nVSԈS?U@'/-Jp$|!<- IzYeIa|a7qx6zxR} 4R䫤URb_oҹ&x |lT7^p<]W#o5ZctPUcW_Öth@@Rb.,C } m-CD| KXGhsC[cnj*XQ&J[)Y UP m[(Uq4{_?]!Y]^ٵZGuյ2R_1۵%oo/z}]7ȎW^ތN{2FNv:M kwwrԔEwSrQşn4b?~o6F|Fݮg$# SǩP[} 7^[ԹD՚\>=j||f|4lȯzm'ݱL 9#tF|Fq/"Ad#2$R|9:9~/ G^S}pY!'i8bh@uiR"d!cL>G$ͳӅj=C4FS!z3!w'}l{ױXKB[_:ºC@_ɛMT@$4V @JbmN\otf;HR&סImj(_?ɖJ7oV"_.> KmdKXHBHJR+Zz=JS[BHЎP7tȸBLFxQ(eoO$X%=, aƁPM6@=fJRS \w6[[Jdq̔yUS{b?ӽ@1߈XR~9G(|O7%URon֨s{uN={}g"ȡ)(ErWP˧5n=%Vcnn`9齍xIr7`C?ԎAs-SC}ԋλc!uL+ ,GL0/$oOP5e1G¬3^ő7Z_ҫ+O #YВb2@]M&/|KHIqN y:]NdRT+:I~gQ4^凞nYkwdVgKm弗.&wX0B&̟Eɛ(^%;JV_䶓飜;U{*;{IV#r45 璚Q;(tHZ@כkQ'-a$'~m,4!Y+-?D%>`Tj ACw(t̹HāD~dֻ3_;&O\s5i-ҩcvtD;4e`*g/ӫtCgqf_ҔY+X3캑pݬgԗU`rV]%Z[{pB&`u'ޛ 1ɠTwh٩T#GW2y܊ aEWuZ_C, ȊTHL?siXPg7堺Bnb9WZ7 _VB_^w|9 7kئK!hyǘpS^*] &xo6Ʉ ^YDkGyuV8&dRpS3 Z[\uKae}RC d:94K.aCn)\^TurpӛWަ}JU (-+3 񏬉WZ +,*8k OoTA{Ԭ9EwAE8yLbå;f|VzL5Y<%?O\ctWnc?RwOw LH΂hV6"07OMCLI&0߱_bnj;7VGIT.JR#UwSPi {PE]7NtlxoWV߻T5 ?SWҨ%nTd9Usq_>9.Qj56NRʜ`9O AP!Jo|qp:/ޡA KYaXFD»ĴX~R٠Q@WdIDn/ C@64퐓DlĩM@R277"x@{'~"a}t/pu^Q.^& oQٛ;''yqʉMo (Q~͸$R3Fc^;^k9{"4V1X}i3e at'ALl '2+M%.=:D xC.4&PX"c_Ns*t0MO/Eխl~(S cV* J=#Ter7ȡ6QC))K%u-!ar\c9jU/1 J^TIAN b7gC>#Ѷ ez,8>xp49:s. xu h8tE#|AGk%< 1T `H/%q&1Q F Yn5@dAz#[UruC}  e?7׀*R&^?|GGg0Ln#ʚcw)a0-!ZB8u,6w#X{VKZ_@՞ ;o?\;: ]JF @NQ,Dҡ?MtA;y^ˡ_T8`qYUzIeRaȱ<Dž CWDOpwo#,:Hg)ӆMnQL+vӧIv${iu䈦jW+L)4cJec|(+c0'"eEMߟw>W{Ps?ωa( 3iw~ƍGlb #(Kc^Y_AUZTP$Ij1unb#FK<9 CJ1 8Ơq5q-FM~s;gMzW޸N#>#R: pz&-0#O&\;pSv!Ĭ0On2Ryd)E1+}EdWqaLG8TI$¼S+ e"v:aT~ݬ)jx9Hx4Į#K:ں!Eڋz;y썮x0 ^{ I=' %oФ]@xlSM~r04yOXaVHٽ' RVi  y4f7WȤWM甛kUiZ0l]N+UNYC׫ׅf kgcϬ9ޝ+&E6xRI1g(5guo 0WGjtM,bI I@AarEYGwhI6 k:' 9{;hF,0q^/U*xRp^C2Xͭ7H$f!Asa{U1fgx$Jږzx4V%(8[0ހAfmz̋~_WAx;A`Gx%["J%&zoE}4OSš $l9f )|I?$;Eu,`7y\8̳D<͔lJa y֍L"".꽹/fz>TOt7Z]H4!x_L쌉&s\\! OMI&Ƙ4{s_%y`2ƞĹNFZ:a̖x_Sγ}4OfڼfgT,h?RPD||hoҝHK'9Ҧ&%W- h͓~Ћo~qG47`ghF7GRu|u~ Ӎ̟e%-D&[͚lIL&[I64"5lI /~؟:8O؉FVZe]9+,7Iޛb(=G|jYuMI&$W\AW| dε,z9JINq_ghCrlziBqd7bg>MOBWS ]5Y"tv IצO2 #.QfT/!:n6\ඹT@7%Uk`=WHrY(Кų |'yvJJFa$F5t&UpsX8(3M 8&m،TqC4ؠzjg1> CUaЧ YTjE-Jfѐ q,~;5xIlH||;V1ѣU b;|8]C{Gl45JX\WUceIi(d\75M8x7b7:7Ә/.!jE&e?154_.LcsÓqLpy>zǦ^V Q{bR9V0MWFg7EWtYh.FXд6F0 =b)F|ᵱmŦxtkQ9E>x߼!ZU??MeLYXՒ \[|L݆;qo}e_}1yB22|#T!^ _,xR@&yUn=myjl헪Dw/vg; +;V , x&He7 Fk? @ Nq/ȡgжzsmrQFQ&UZQþ2EvooARVsswW xB)a#]^?CҩhL+G]a45g^X7ޫU@GȦg{ix=F2Yë+ T7 do0b8X3Zȿ&xK.]?v+ECÔ7&eC]vN_ȚULK2L)T}B_y+$Plejt֍\ "QWn_F |"짾-,ځ *1Pp+HJ9P9'aV9yBup -0-N mkZaɒ:qbRt Iw_P{ZEqp̫/tbt䬔/AwUQEx(5L(,0)$84j9&N:KR>}| 0 |?ػwqK089rv~F=NC^. ](cPd\3yp\CU͊S*gZ0$Znz\TMt xEDgTH,32=w4W( ksjxPj7)k[_s3'ꌧGTW3Z請K<& -T˪_V0Մ,\V,l|[d$tUi>J p&az7{ [:2yIg[!daw{nICjh 8V 2|GĴقG,c/9,ٛ  UM0u}rOSm5ZM@<2n΢8Cte+a35f{դ45_B郓1fedo?eJk#$TsPNdk"8*xmV,uBkf hZD?'j[>!GPկ=\YW+R`r UM'u %}&1Z #qنJZŐ7oԨ K:@Ǿtg 8wƒX/D3z7 ǥT2`0V '6Wu43^rCI$3eNn,#LW8 wb蔳iĉeIosڿ$H@\)b~NqDg8eYDwz(8^^ ;xI)3b-~A?~ >!1#1hॼ߄q8)iS1̊19VF7<'v#fZ$[;n'갇UMq=ceqq15:<07 4,trxmwuO!28u==G(hH{JеWk6Rq=$UWff?ʮ͂h{`Vޓ /J&7,v+OSW,k+@WEȐ"n!f ,9&6 ǹ#M.pt%|>s,^,_ndŜovN-#&(glҨ}[Y5AtnV[fDIOE+ws޹i]#A0 >Uxn>O|`9O/1smS1ssHI 6kcw%.}҉=ijѠ`H>ـD\ew4<+mG7Hvbwql1)I]ޅ{qZhC w(O's>8e|LpPŶ$r9Ó02n,1P n3P@1!37km6 yT5aQ@l2;!E|ug<0|K;:R 9/'ݘ Jr9AVˁѭ,PӲ' Kby WVI)Yhnqqַwn:`4n'^G BJ॑Mw=OsWℙSdMYv͙;%v< m|&?odޏFAIKK]{]+(gVXɶ.µYL7KaJ3lb}1*0\<9y8a +'U ^Duo)nmy}Sw.a;XН6 P  C㏚u^'tHLy>HFQ!֋7#FX?Q"m?(fb}s:ϱɃM^ຳ}Kw&)p*3'*'^%7DǭV+ E/(Ģ -$+N\t~Di nNsF@a u~JEō.:g# wT|%c\rYWcgaHTGؒ2. JO-E\eSLWtw)P~TR@"(b1Mw,2#_6ȟ\K:WL< jdLd0 zmXO%锶Q)ҽϤ/*cuE#jxp&o#ϡVKH/ 1&Z=הrR x5:?|׿p2 H奇Όsw1nZ\s^ϗx؟_*m| JX<6{w>\RW8Η]v ~@Lgԏ3G+h=ܞ) @wOB#V)*EfRRc/"^E%W=ߡJ˗ TnZgAǍIt".65)ks= ˧-Y‰${fq"q7쭻߉脺˾ 3{j$ܟ65_Zs46BG|<;R[3uQF3@Flci 4q+h,xA:f >:ɰ1:CCOO7wb9ň' l̠Ott\ ')tfkz]|{bȬvs(270SUrςxKe({t(>,F-Bt8O#vaza6Df AK_5f$67>T27z;ZL'ݳ04nk'Cڄ%:00[g!<geB z"跻t'[RU @=il+g¤,QR3dv]knj*1 ~B7Eڕ*7FjEc a4@c/h wT 0B!MQbttUh),f׋q[_L>*a"((rACFڄuX܊Q4?EQ0UTRأa$A/>O  *_,cv":a蘏2:XC47kV1z0J7U_8|b.OznI"mxNsPᎢp@h8*wKqlWHDq#kֆq#f[v$u։0EB`/J N$ pH(|Gš3.KG'r`XCQ QQ POƩz<>Gј4Eϙ4ܚH҇b.lc+INI ,WzU߻W̲0.nJԋg֋gzP+|u|]xTP^y%?pF"E<˰ >dq!.!%$zx 0'N5e^s .M v.`@&:(r`g&EI[ Ayf ;0ga f~fX(S1K-;x}%s*3c %oiI|Pr\~&`M<<wyZ^]vҵ*zѸ|} YVQ},6,tqŽ,˺ :̺ YTxSl/A?K~rՕOaq[0h?LM mm3O҉ֵMt󗉮m6 7Jѓ) G-'qN3by}/OgߔՄɬTSl{$IS@53`()nbqߍjbmy+RkvnӂݮquC#V?C& QAm씕t|cst"5au8uZQ-!Wl"~Ud8IgݙޣKQ> w(SV5W[T0QScw?!L2n+9^~< ;As_ER,@(hgk+mQ) (U+|UaWaU#;=[5AP%#~jsښZꎚVKׅZBk9SJ`1~T(MRW*4ivQ}|` {9 oM}hQҭa\rrjk2!فR/֠rn_ĝ/71.mʘ_efWM0W3(sz?v6%£??CQ"$K^'dvHLY8e'un/rjm{qIkk4^e/m[iCܾ]]vFF-I;ۀTeuSAv|%!E|&&nEՕwk27}6F8+ke^0Ob+ו0ѦFB56Ig^ApIj X!ݿj FiPhX ڊX_Gd_za!^1Ts r A 3/cݍ'7cқ2v7w5!$@c;C<+Շե28ZZ.2n 7$u,^έ"VAC7hȹv:u.:؟7]EYx, F#6r-0& `KI#6 m@/fvK*ȷ-vopm`8ފjԾ2'DcQ)҇ggVJ0WŻ n]mr,tLhP+ C^Yt2-F~^c1s~bHqF|b>sn&M%QyT9 0UQ7r?pLc{4IJ8:8: mN|;\iM NqYFmɗxAE0EQ,.~>>T~ݬRQ/T;&rJ8Sa^Ӎ BG/W4&툆q~cCd6BKW}ExW"\AѤ4lw8SKD*xО! ُ\m``V4q ɂJ+Xp?oFcmɩlnY$xFoE$3gҶ1Iy\7~(+Xu*edu=WXr?nKx',0PP}5BIҏ6{,Gؤ`4nEoM9}{Y;!,sO`BD"Rݲ:Ea}EҜ[dClmG3l`q;/~ c3a@:%fD1C8׊y &͏AJlHT$tsT*  ΡV+nfcŇntz ;Y ?6"aKdnM74ai˭ =Qr`SIuDH,,QQMg݉0o(zVQ:CFZ!-L%M 4!ZPc_pp'_`q$a{4ZqmlFKn`/*VaXw w3k8NV _[϶P}8.O|e .?NU1cЭg{k)_[=åx*3 =Y'1Bz~̥d?6"ԞQ٬v~m׏ƣ˫_Ow>{^{/y8)BMsbNBr#ʆ vؤ`2B.2AoItäk>S_P=ݦV*pP=Uƶ% #XӔ)׳Ɲv!xݷ3-GɍQ&W%[b>?zRr;%Q͢JKEZGy3(8?R_̟Jh0`BPxlKP-mZ݇*t_CTcZFw~#S#+KKj\'^TVL@'/VAC$%'hy(v/.;ow;(,@JܞrTy|;ܓy] #M ~垆xۜ+LD8j i], 9 -qwA͢V ޼jBk){=;/KJILуזx=ZY})8Hl}VTZXou 1Ð[gt㑠Eg3"@cF5t)m.1zX0t T3J%-+/hJM^EӃ',N>YRs|X,Nl |P[,&՘` '|iwNh{CTfp:nI;>ډO8j ҺLjb&@dS6KA)۷$f9RJ4#+K+I_D朅 w9 n"kҺIa4Ϧwg>q}~k~ZXMm.G 1O'4{Wߛju@ WRң)< 6u?GroFB`o'r IfwHE.`ѣku^Z ci:+vZr5; g蒉L֕ tm FЦDS*N8YMfW҉5 mžn򓱢GYhVgVMXʧ=̊XM<9Lp7Lq{YfumkH9gN7439_`p0v3Gp;A(kS{K{K78۹l?j 2:Ab^|depSso&Lg7.?oj>sO]ݍ{-Q֖?Q>s-.v3-q .Т!RxfNo3+M'&QsU6,Zu2L-op>h8'RpcDkt#SaS ;帊x]v27J~5X? s:0n$VCת9pJsIשH}& _ IH5a*Fy=Ze'!6!+GRRc#جa量fV>퍓g55o:.e4S6!RylܧW7Jwe6evE^P =of3C;&OORؓ p2i0y>ǜAcw5G7?y:jkvBL.Or-8eMNIV2ɽ7 ,triu:t = 3^//4^aGw8ilM1n翽E$h<<V64ߟ>|(94ͭWWK-SƸdTN8K=sYL>iRsXT$T֚S5s׳C̓-$?XGFܛl7K N [8~0aA<&M&E-'%vDž`|yuXLOt21WMv|be8ڑ7 3UpK,lCa)DClo*idFn*k_p XhΫ*'9G*U%y_4.a3ssL'mQhUSUhp> ׽Ө[k<| mɏՙ\\{TY9t0/n.yѤCkGHԙyL"6xR+oY< !T NabEd߹\[Q;m7o c{/vfY2~&X%=j`<:{HI܏8\Y]?K YWL)D 3O;^ -WK%‰;b-CNCJFp˵Nѭ#ԷabR`2Ӓ { 򛍭zIO(;t_|s6j~Woෆƿt>lO;jEB8ưR(;`lGy(Y5a8ZُV}Z_+[+O K)A>JTw0bQ- QC ݧ; qk*cX.(E- O1/ 5PF[GX.מz/v.ð IGx]>¶!xP/*@ES(&6MưSM#6 eJ$찐6^T,#_ c@\;fb2 nw *[A Hj~@;gg(4 uqC 1-JX;v`~pZ6°`ǁyna50"yb J}_KDDf=).h< zLIr2+VT j /J,w *ڕq4%3 6ja* 9uFc,V2LOe&_JU\1O_7P̝|X\,"bqM󯝀= K5TŇq=ȕA^TrH"~Ƥ& + vb35h#tWCtX (IcEإ["L]%vo9c7Cс10b+ฏV6lމ&Sxm> SZa'Ua0 1W{{;(qR Ajr!a [j`:`'V,_j'_*~@"71Q64#;#W=EY ty8 {V,-(\PH0͞[@稫UBk5f:DO?Y(,$L9 ??k67vQl[)G"RbL,XQž^aܺ*P3 g `F[ꆈɮ __ 0@GQm" Ғ'KaTNI+,Ӡ.ɿOuNWNRSFQԍSt>v?X Q;cm5|:՛EN$rIZdD(り SVN,m|@UovoꧻDžox5J_}H1+E/](6[؉9+A)-o9&mAE(^2?4Q;~ya>;oK3w7w|1ǖn62j<v[N.N3mon:YU3ZUr_' ~ft4'!p5Nl^w˔dxw0  5fBlmKm̑#Ok_;tY^bVvFaBj [!;?T?:}Wq4D^gEiSsޓƹj 8qbR';[X'!jvKM'Q 2uGIDߨW>D+ -.}F 0ujMO >tj{n\a)IN_\6.-h:%֫ lVJ`lU.o㑙`^R_Sж ޢIt EH#bF8 ZZT`VM5(y%7Z ws,CSF`L<$vՒTUM sdvN'i>4Qw[ VmgCD]A~Tx S sC] %V`r:b 4jt'<~~^]ǶE^IV#@WORV -ѳY] US&i B~s|D.~m{ {\n%.nr]xǵLPO4dDN8싷[(Hλ=~|@8R3 -ĝuKr|}={v:! l6wv6K˽VT&@@=aQC8:9 P{h^tӲZVE0u*oeursqmb Dj#AHu6BͳBn:nu< 4A!mfTBG!"[aFڅf4, A͐ӗj:/ C75n[E1g\Xijy<*vQ ˺e7VlvzaG(Y>젤 U}h[4Xi/ѐu) »0 ]#H!}/(Hxg;H/ -!֬Uv'nuN/.2и N;z]>7TcᏛ; _PVO~bfL7=Oqs'NT:{FYv{ѡ?Ԁv/ꇐpjzs^7w?QO{XSsS{ypX:

m@{v˪rg;v?a4 `A^ȣ7_l>.ͧ DVI~xtoh#OW ߠ:jZa3 |MzrԨDVR19P[ax0$;zx8q }2}m・a=LoWF ;]p)„S@yM&g.ehmњMꆙ7%=<VE``5^'ei !k0U9Z4uVR*\­hbҗJ2;&CΠmm*5!fԘ1y͛3Xf 䠭+"MT'f{rr0a{pgϴءɞswFy]!Ì5:?7 />|@I5J ^93icAͤa0MO!1}ͣyyGj/X֦Vܦ͗ #0̸H4p⒱~kr9X ʻ@¿o$ttSB@K,&3r2lc|Ywz rFwG !V,.b9M'}w[8*ҳ'On$mrTH״ן3 ڽ1aa a%Vd WcnD1NIk6v4J()rbR ))u6cC<ΣNiRN%[2AJg{ͿBF /Aܢ|daި+ٸ;ԶS_&`,k5ub>Ͼ"fkPKǨ7dy?m 85\eOu__Yߥx u㧄Ne1vR_\0;rgIL^ *8omx`lṺq%Yrj׀vhdkf8vW{Jr˩+7R*&X8bof329&9Cvji0 lѻq:k>2vKV>M@M72w30~]s1o=l/mc0鰇7%qے 5BUpB2:%ss}N1NDZD֛C6kss"ȪBi ⥎lxxBPkJRWw!;^\hx]_LmɔkΟP?aΌږ$8w8=%#SbD,̣˧5> 5GHN4{j2aVשĒT^RTzaI}k^+r3Ms;MX"sէ /y"Ɵq7 1c.+4?E(%1'Hs״2)L^O)~>e;<P/Ϊ9AM-ݔ|qMS˯wtE8qbv.WVc7&fDj`[ooܦ흧~8: 4\GSBT 㤑"/8atA[wsҮ99Ԣ*o:.S`F*7<'3T*C@ͭ-(Us/]\Ps(P6kNmo.iTP؁aKF6ć>qpS[JowZ};9n1[ԑD,z=6M rȢ3q5q\z^?np3ؤ~1 ś7A4eG쭹 A?je!aJI1 !5/N̂Vut}1a:40aE ]&41?X93.|#8'g0{ÃG{\!7Xrh2FU g\uqclk8+Ås?N".UClWpb:0Li_.kFȗ+C Sܸ/4amn?@`pS;4`9+[gFO;Lz-*8i@EsT+Ph(dذo|pZs3A$:Jɍ?Ab&ԠB?1Cxie>ҕ&a9aHZ^&'aY}=(xmmxW {i5Mqz+xtZSe-FPe|翌TiI!8p8 ȏCmg `^;~΄RwO.##韡Pm3MOgYKN𬵲zډK[%ozҳwO\^dNudgtvBN)ɹi%Drݐ  6yz0mLnhkd>,嗢odllfm(zg6m_U 5^=QuI:]7ld,2Պ{cY ͡5l'cϢe%zN.g/Io\ߟ' ^ADdjKdB vX:$^^z) pQKAsʡ,=v1qj0wȗ՗R5d(:~?҆f؇/%cdr^]-ߘ c=Lrz]Voh2_M9~, I$ Օw !AnR%!=>ǖH?gf7e[4ɑl~)(OϠEOÝ'ͳv_Pq7+0:1gfq'1ۏ<< (Fj2ҋ=3?bkm9Rv;0gbzcڣ2&P)+ K5Eǣ~$ #$p5!/{O&|g]1N Q 9$hۏE)( y/9jbI{xݻyWz,Ԡ-WK%(x>xgaqz6(ؖ1f  *Ҥ[GLA䞅n 9tiVU~f~U ٗNK^to\tF ֐NjnFZ`( [1"s Yَ^ CI0p.oF~0 d-8EczӫV8$WGuuZ1;$7Q~y&^uprm)-pk') apX:Ӽ&n ;KY6'q=#-M^G/ssB>?nqJҽ?wIV<׏@^O -FhC NF9ѷΏ\Q.hi:d6WI]c/;x@^/r3K]/T Gﭼd%Infڥj"b`]dJCM$E'S~u>奓T{ M| ȼONd׊_z07M[F I$gB8ՍdaRu; k"àJBI2=:&G/ /":nI 8LiN7EڛĽLy/5Ԑ25tz^][vɵZOͬ"~գUI°)NOSEsN16AtA(OMN+ +a<´'/0<̕X-tIƖ7A0%g_?F~Rc ƃŗ1u6N$tru_gLH_~2 ҽ$X*M6ZDD*o^^,~^oh'׺x+ĉ~N/f$-S)~*{-$cp6`h"11SVZwUd( Qo-6m\+E.G'&4q +1DlwqRt&7H9KYNe7$^?”/(P*cVW>пˋ?zQyludV:mB2D3u2TIvrrn'vBzV;!2^iJ3q[ 50_K8hk?t0dz-1:(>CR.;4a+u.@+BqAz6`=z':ģpW0$1 9/``ӄ-R7N(ak3NNndEq"|<{@_d #@tѐh!h#T[ 4:_r'g!bIq:)"ԝܓM̅p(crKUorjn[]5lМ8(K82>O1_i'g-VPf錮˦s+)8,uVU ]9QaNeCilU6J+snp ^Fg0>_@Ǥԙb IA-? cd'|?lt#'[7QuvI"QDL`Ν닋o?FE]45ss8p c6Ȼ垌G~;BQB6߿(rQ'SwtD"lI@2&Wu$(b0:5 FBGZ\UBs9AtQ4P6m9Ի`؉1ڰ G fxQ8,SZ @TC ѿ1wWUmL\m4{tfm CԶ΀x0-09Lqk87א ز]`Yk(J9R6.o]CG]\uxBV'Zr@QE ^ v,,İF`9kw[6zXk wZ㮥hsP^DU6VKOnr o'ĭW #xssz ziL q(0:"ל?Q8tgf ͺ_w[cZLg2U9H&/b4Z'Pivrsڹ|\ ~+b&,B4N'tO{}ۀ| *}e"z}0u5+եrP$ci)yNLo*(4̏ &wK.u0#bI屹ycH·Si~1D# DI`L4Wŝ9qkb8\7r*l%tjg11JEuppl)$D": gJ%! kO(bƊsu>S$F8U9ci.{EpVg>7譍Rz܆nrlJfmQnΑ0cZz0-b#Sgncdf؞p2mAxx:!@2RU/'NX˼]eDk;`sqRY$&_(1S )ơ6'dqLBmڕܜz" uSݨ@( Rq %8 'ƺ0Uss'fQ,=0s ]فsaˤյb 3G[?I(e#@h]~%;y1SD(B,>V+L 1Grv9e!џsժ(D=Eqbe ?A! ƣ\n_4ޡ@O`b^à/aWIHn@t!J͢t^(/D,)Fn$I#sU%(&4;ښxvPY5]d?ys@tGъI|ycñrT9" |Ɵ0kR|4"P5Y1kuMJO(1]|)OQ6₇c+J. ilÈI=ѷl mAP\r&HO_zD^GgvtwXjx,J 9C+ѡ+;*rh12 ϢBwj^Z. %J{`l›`+"^iMD[`i+`UÜ|Eʒ4l~x;fZUp@gxY& Њ\@Wm888ʶXnmiT_Ü=0\r8&/y@1*ϩDxz-͛bZ[,p}luª2ɜ(~59&nyhw1~LaҝenSs4 MH@0>ǡF_.8W9/T\V*r/;k#I;q˼LjϸZ 5ӧ,{\;B1+sD 9=C=Di& qǹ\[,ءSTdc pivQ8:9U[;bQpTb2CUQ?Ѻk8+?D}b5V^+sk)\-0DY +ZFF !Y90`H4ԶAcba•h=J,]ЬIV CtޮGms# Y= zlӑ' (Xb5)Q }7 ݨ84v09-iJmV31 2윎aU2ێC9`6Đ@x0e؉ƺ1)zWNkbX\ŁpOHë cCfCkAW/X6t㮁xaE2|}J;Zj`DeF+mZ::/FAt*7(+s{6'n |6p>C 6>#caD 10즹 M!LC Pl*Fѵ1 7 ~cLTT8yY;j8W]Ů!Ò)AW#cnGQ-_x|S( 8.RrRPB=H{̴ȃm hSa=/~Zz@nS/t_o7Le~qO>C2}>ZϟdL8sΟ)>{ 0Aj-ȍo57Ph|&69&I*F_-3ԍ{וzC )r[UR*Y~Ǻh{ݗFߐ=$S~5v,2;TY8<=߰d֝pSZI!Lf- pm$X*}!ێ( `I]T-PKn7V.ZDi0O􊧁Y;Vҁfyzn@6T Vy@oteo5n[ce9I$@Ba~),qpx NK1}8NB@]r*&),X dU/z7O / ]_d?qLs,#_H5vT~U<׿l=3|ENqaX/hE5%H|JyӱWhN=n%Aυ> =(_"Xk{nrC+ h ޲OX D S ~H@_"F&zpFs_!D{'1 љPFGۥݭB!2$ \ Tˊ6[@ӞK#o? &B2鵐B@5kxgmmvlzdM甀K&wDLSRWG`ФtM\?AFe4js9 fcwYIdkwH[= p豭"5L[s 5SZ_ )n.rb~G1&| lylP&Ya i%_,@6/ ȍك_(?7ɋ-<\/{!mnWt4°;MF8џ݃dTp/_T\]|5^ABV҄mZM[hxY\yj3M 4Xխ]O_u>>[O`+DzG í=g,kt t:)~kk;-A2 P e|CK߁oAC=.KsIGtqϼk;C8%;̛?vqV~&bx`bP(|xsɧ$_ ˨Zq7Vyku,,R2;C'yźk cKq9,n<"3uȮ!A6/x^QGw+6?"~ˣ_vr=Ylzqaq\Pp7,<  [ }'78-e.̍iG!Hz1Xb#N&}zg9MOI&yv36{Gq5MúH37uKf15.n4c0ϺlFdZz k-/3ǤfnI47i|fװOAL1.gX+l i1BJ܄0]1)R 󟨂_'D KRVv$5/WqO27M!Ͳ[+y a.y@ kL w%hX;N)C04 fW4?<%\JWSJ/I9%˨aOԤE/uZGccww "dߞ~[/~gAOpR2}qY(k_'V"Nq.o3ā@l o \l' Rᆗ F8-z5a%tww H拼i(D7YOstAj$"'@d} t6ϒ.~;T:%!^Ʊ|8Tf^˹'"g(o\Ȝb#PC, ϲS$Pb7gVo^YtȈPNhBc y!>FFPG?nQ?.Qvmx-q"BUڽݩ$eC@-ە۬j>Gϻg}:8ƟGG7.(|sgFIf/Q|V?Խso\k)v{OO_<-I#5ŧK}e'+uڿ t#rV!3m{7lt[s\ 'NܷkkȘ+h7Pq:T(]E>1⹄^zQ$6&^%R.IBp9#V 'Wf'|0PJxԅ>8jn<\oe 7btgDbf6̱OkD2 _>Дl9F T7`Y#Q{h^ yĆB,qK6H %<ֽﶖAzp3o-{bTbﮛ}mΝc@%{ V/¸,|%vѿ߬58Шm @#tK/a@j N R*'2|CN[;>:Fb8AgpD=8Ћ]gL9=9fӶw5..(tjZMu@Gܬ[ޖx/@M hDA.~ _սPЈRv2 ؂>ord[w7蠯\{uwܝ'agY;I #^>նʴ'ҝ<]֢_@,ڗs%6=(xHːD`@#Dn Qtsiv5fi߰%zhfٛ6ڍkg}2~y2G[![5=(,,Tqsh*KG bO˅Hqާ;ܽ3/Y?zšqiR HzD{.sz֣34oh)8ْh +ݔ6w^T%__vw_ǭ.?x97ַv<#~gJ2P?kUBTVnb]EEѯ6 jN\<\bLaNx U/U9=us6ao]?NZϽmP[>,qzRtStE4Oטr.n8Z=HqЩ|a *ߣl>WJerO.:ۺ\Gv\VH-/-W`<(sU2?۟/יvZ==\|c>yKCwWdcoKMGJ/rQM z䒙wa,6@YmHΏjȍ=: )^=҅o]H^.FYjs4FqoyڥGB77WV6z=s2Óf%(,3vJF7y")vqצ]Mݠ>uĤ"ϮOtp=0;0=t1kw$tuN0.{TI݉[ݠ @ry#^zC5ym'EPx܃ks'NT:d{F$ݣ޳zrtnErIxQR?U/vn'ip{ m">VlvYbޡj<_d"С!>m0@;v˪rg;vћ?XxcGϠzcut44G;6lc ߠ9j)D VP``37QNT6spKI=@mmBm=3OǃFw t`m:9Ngγi>)Ε 5a m`c&Oi6c%?Ly.Izmc3F$:Vܿ?uQzUEmq|@|yPoh`UσV ޯ?S ~~D[XpJucZ=m`/ѯag>oQt}a{L5X.#Za[yB΁ىq_g%5ȝ7`wR7tk_+]|#ctHfJ:^]Yr}m-U^D 9l%_~~ڰ~p߱cٔ\D QO/0;w&-EMC_7: '셼VH^n3tq2DͲ2"z [Vk@/*1FK D$G˕%ظ56C } CU (w=tdl 5%٭yv`/xa.Ow$ܜ}reDP:|0(cQWE gq}H*+%*RRRXrIm״8g\nϚZ!^j_XT=lMTQp*lo<^aMNu ZA:93f?2xVvwQ5EћEB^Ɖy Fnʬ{ȕ^xTvn?vO+Hvjhep'! a a9h+<<,彡)_*_6Au(hKh3X;(,vhW ސӎ-i*a7G{mM5˗dȎ,U`opI'ӑ#H1{݉į aB*,)ZZ#`S-m 뒁\P~+6B;S2j 8f=TblQ;!omr `,;R'>oߚH\GeBbFq!/~WZSZ++t(&`8inm_E~]__+dzqT p]ߟ`-/Z'!*/ ꓼ%h^8?Yg1+٫L 6'~r][@~Tj~ a29xĕ٬b R߹2! Rq81EDR$l):h' WqK&32O11/oDeaLM>8l\8{؊(ZSs`@bR!OI!/VP @7ƭS숩4eخ3\J%VCx5*9hh¦Wn@jy5?q;ciE6zdvp˰q+a!7g^vLO3f:[ G1wA R&C4qayQ,Z$!s0K%k +1Eg/xK;j ls<[PVmuQD,S’Ń(%")4|2C}Gq1Cg*7>V27ASqpuQ,mfy67B氛aқ>tF_idӅJ&!nUXJv$?a?cz.c>aKW洂cR̒7W#{s O&ʎx<sf D4(*mC-?!{d-'Hg?V}r<uWucY#0G0zT)*S`DQQCWkA)P<0 u;R' E aZ爫+HBbe[ dkE/jq귛IT98||R@q e2;+ bv! x"R;),cc)a&֓UMj(fA?6F {mMC4dE3$.eٿ¢冹'Ү'#\oʄ(sua]Er0j拚r/7|SmzF}\]/v/^xjZutNW|Z+Ui> %?a,"/׊uKG&ox@jV`\< uz lѪ~;z g4C)&;& &_']ân2Exۏ. {+mR]'ՠkuKTЍqʉ 'fK9($UGW TQ^)| iUuT]\%B,#"8PɚO.HedObO*&E퀇ޒ.|r$78鉎NEG5\L;{Iͩ79{WHij-|9=0q۞ AG-43#rчЏf I̧BNuA\.!9n5(ZɳapNqLVQ 9}&1Cgo4KwG4aDqg18l 3.s\8ǿo}7hJp wUy7h4 ꛐl6a;V4E+ wV:%:Y+:B ?"POA*dnCp«t4B{l"+F@vff-љ+i|ErFjMʘزas+jVw$KB'zY{X{+&`݆ꏁRG8仛{Ϩ[MC$)Htg\ߑ+Xx73䘼DiP1&"2[W=R-59\~76dږ1626 @R^% P1a_Z.aHPnfP'Ձdfh(q 9:,Wʫ%)·@TNF9 T㇃{\iU ˀ._;߶Π:Α F$[ #^AWV+èV a)jLuq&&kw#?f D@$mF[q0 ?rXBBCIIb&)$ SYuAde`@ȖI'=jELR[ WMR6hwH}\cj=˩PNՖ4QIf [-<}?Cf.IDoɬA/Ctӆ҃ V#[wWڤAê|MM=/ydTA%1S c<)ug 2 .F8HKK:8NOԎf!7(C.k'7.HsI)j3>bN3,GjŞU@FMjIBeBo_](*k1Um; Aq(b$J8/ $HL4ۯ T 3 xe=ܩ`<+ol} xGb?ƊS~gYйZ}$z1 WN({϶P]1|Ow.Y$m!Evh3eY$Ptn3uދކa0'+ 5!ubY|Ѭpg6a`^`h%]wCHR<`f׎k|vN':%.RA2$;F_Rf|B ̓b5g ̓Z0VLɼ 5@{Hl>z 2jdD|q+v ﹀<e -wk oj] Hɴ|',XYBvaNYPЦjiʊҫ K Ripssv,82_MSZ"<~dh4=Qj!e$N7VJLv3f9k5wGZ5E9DzM an/n N<3V9{J Bg1[G (QZ4^5厪Ԓ5Cnud%viI-(.5%ʑsPlϵd M;Z{fW\æj+B;IrIN j6V qEs&GI8v"wh 2ONw1O8_" ,hs?yEire"i@`25s:ڀ\5 2VM h7aչJNdE2ڶQ,ĊKjr] ==7ҙO8G-hx0QeU..gɢo,FC Vɹ+֗'f6(/o]\ O@tBu0?oN[f)apI vK"sQdP2v6{Kww)/EjAް GEbw78ĹI3&-.5T0)ҏr=T2w e<"LA,5Zѱ+vU X_/rt5plU~#AW5KtL'!r]aBQst /F Oć=XkĒ+vW@Z&1׀hHrOHx΀uKͣv뫯ĺT{ )Y:%.bad^VힸUxFUi6v&0H2J{V5 <`8l[@a4(-1B2I_v?T[y;A\2zYOj{{w7 P?Wp8;;Cg'# hCLLq2ݮ6 IG4X:hd5NnyL[ R>ˋa0;hH*uihV{E:~woˤ]]:ʫ=RHXMH튒-;v%nؼ?8|z&$4RS$B0{#^/E3lf=Ba[9u hWëi>^ W|X^2O˦z,t8 Ha2{J[&򬭭oxwA!U!|b? Zb;d{x.%pթӬOpO|quq+Z[Kba|M43261ͨ,h^S 82\Y0o1k~WƣM䌄Om8mCs̠S}C׹zğH140=@g bP57Aa+FԴYtJwˣRO` 6)]SJ$9lC;: r<]* k;vy#iw{E>g0̛y]ﳃ2 , QaDӎXgXɱPxQ?*NҊCeR4KJY%+ /w.kqٽfgnyT27o1+VVYfJП x=s[$*Eڜi_CWA4-2up+I=tMi!a0x5JvQ':BS`/EZT /зTwLlI)AH]"j*8OsZӄ]M(.A}6II[w|H \00b^}irj^E9_ag!4Cq.# ȹ,ӻ@;x*4E|?CQLv,hb)~4A0Ebz|f.5 *Gkg,Ŧ[rd?MhiMTczR%!rR@+%R;Ԅ]ylrJbqcއA,N>G4ցhL#I*Xl*o*ʿVsoU 7\6 YzA7D]Y|k\rL5MszoOU8SAeAl4TH"psJJ">xp"=?7mA=ڈLwICc)V/g;7sVc<'smJg9ۨI UsWޗ 2(ž J]k:g)1R].aԉ$w#0 WTw4iu1Wsmnk$N!VA T/ۡU,Umڟe!R)Dg܆H-G >];P^L'Bء 1-Ex7xzA7뜢!>Z\ۂquQEhjeiиE \-yL?(⫾iz=]{^<he֞#&fzZmuu ꟂKr3"Mr,@Q{u,;[ؘJhdzߥ>ج.YfqMQv0Uerʤĵ@ڳ%3 k GVex'eR&T0Qd.\Zq jk8a!?fiw7ڋNpEPH0;PʄðA !#4>݇A9xJJ&.YyCVT] zWCP20 )m@^ȫtamC ZDxZRѥ"BW:B#v/?!/A9?>qA|)Jd(}#+P5.9Xw&λF RP_m;JԂk­vJC&C!40zcəMO-u@LJzc!ܦVܩ$R j0!J1Qx kGnD~Tv:#{s [u0I!NwݼW'tlKbqMn➵`j 8bIu㸹>4T/ gn86wbbOn*~B۫s/%@(buA-.#75wTUĠl|.렰tѝ h"䜑`{`ݕ_7ِ0<whNkay/@X?QEv5P*Ƒ^/ww8E F%mXmwkNN[UՅ"W%;!w*b(ಗF&{.E񇢖o>s<|=C\n*3[jےۿ=ETdb/@j>8-er[d|7h{ꅶw;%FϢm/|ʡ'5{yD3팊ކ|"#jEй$JঢRgI3k*]zn6ڹi;>FE=PMn9TE506z]Z9IyH]`5|Ϻ8b*왶$Er8aV>nmA`iz#4t{PdS"dN懹 sɑ0譌__ȶ,cN+~}xek4 TlJQu{Hi}s!f%ݨRC`Yk8OGF("  rb@}_ѸSt= y hIvSgFdU~Bb ykCo>NҰ\wHJJJ -أ(l/C$ nO6s|<{A hx;?Թ,)L&{ijAJ5GŝbeZA8ͪztE^W_m~ mGE_E@ЗL8uZh^%Pd2 %2:QBƢ on]6anpPu׆5ѷX(24uBYH7hpj6!UBw&5qL-Ѻs΁uJƎ[taY; WF"`|tS:5zo-ҬG20Bb*|aQL: #yHDc[p`%/kTqD ݂Ƥ!Q Nje?d O͠c;P !kxR#)9'U' -J@-irq^Hvv4.0:HᵛDgЯ+XlEzMaMFu_g6%c+-XrF6y93ZuQB'$b* hh;jՖvB6%(]Ul~\cIߊ2w\X=.薨 ?N76 Vg{ܜTeDgGlcJfɔUɄZsgq"ϼS\>"͆0׌ӧIw-MS9 ßaSma3W_^m&&Nyc WGJiܶ;"fԈ; Lk'"U4ߓv*z1J:ۋ n]#dlEdw"ףּӇ!j"EB o=$'mr\}8ymݠC#c\>mnt a#Sl C;Ӥ`̪r1Tc؅6 v0hS i?uS-?fV:8bTrhk1dWc'h**NLZA8h ð2B~AAZx_ ڎ} R#AumgL{<8kޛ״ {Q^<ģw]P()(ʁf+膚삵Ն'px_ѱCAM:i#[ڝ6g*/:'7:_/&\J n Rt/S#3r Rttg=xPTNXo$h ;h8Q- Ȱ[B|]_~(lelPM#l{m{;Bz&$|L!:0J#r&"^`IOu}o$nL4%K⺐u,.͚׋ӇCc2,?Ag:Ӊ;ԅ@ǹ9RjgdpuQ㛄3bd=_Pa4877Ibla4;P.& Iؗmi6ŲHfbH.,2m% pbD&ͱ(KP_BCUiC̽LDc"-¢,1;ےT]O >Yi'lPߢmiF4ziog\RO>ͦ:H'^uiv3LpVuV-hƍQP\e׺6cDѷ*6(2B`X0تMV[Qhqa*rҭv7{G@ՠf;Htp9cm\Z+Mm :u!jyt-}U*ozmQ5J'`jF"]ygrV(=OdPLN[tBf{^psok2;Couo.HӳUlwG5olENGODh:Lz5 mM%hS7]< q+N4Mc( _EuyjMP [xe QcF)01%:Q\)ҋ{tLˀo^8j_OnsP)Uq¾KOo7n+ިrLhLUnlLf3n&OiE<[G-u7}OI K^6d10- h뫯e•xn}UYG( E6ފ+Nġ?fijm1X{W: Pð;F[/WK,jw]-`XU?lo 7郤G2rZJ ϕ7M.ъ暴9DVw]WOתCIBE@b uIq!سuEU-NTkǘRc+P_x]r  E}fQӉ-Krav>PW2'M./ 1g 4rt|${<6mTdU;W@R|j= ѻёe`Öz-Ru9xfyLHrC]N@P}}ъ XXuZ`laGQbٸNՊO.k~uUkS cʳN]SAj7%BG ~0QȄ.HZG( ֕O@MgNU$\SkPH]*K6klmN9/cAyĖ‘{:`]{/$e*Yl}cS +@!>OU: /^_)qТ_زhعۢQKoBm{]'S4U{^R>Պlm<;h)"H2nDVw&5FmjqvtOPa׊BWK9.Q%à+VڟRGm6~u6eurW ֯#hŗasoQlZD>NƋ?WUuA _XJa_` bv<2P0"iZotX&'D=͹ Y?hD)jwb4wbUFE^5ezlp8yK83MdҽHY\ QدOG:_$G;aQ&Ӗ7<]+x!j}*?$.|t15;^[oȊ]3nE̩m3D0E6|mՏyƀ·M~/ԲaB1X㭪!t?U?ՏUj!Sl>|y7FK+]a|_ٵdE"R5Ьmr%;'I D}LV2zsXxM0-a rDh۞B3 O/:i͸jii4jAbAl/vMofJ7fȣ_]9 #EeLh~ Er `xv.ы#ѲTA#))aMAg@0M;oT-^<B^ΌsWe5÷/W>'X%҇܇T)}闑y`ѥ%ģNSD ?y 8c}Jd/$R)t'6tCU8p#xf^ ufE H@̀(k4pnV 4l}(VEG 8 (9ۺat8"!~8W8'In

:1%5V5w6rR.+Α𺨹7jސQѽ^p^wUབ&]Jn׊1 ]XNϙHjaOUձS`$VCkBw*RqR`V";m¬ J;jq-@ G Rm `ZvӏX!o,0o_uȬs=.Nv9'K|?`Y'xTxUeE!zh$wrFGZ @v$QukEtދ^wB!#d8bbqx NblL iӀ$q89*T ) Px/)?$[,]T@VJ. u3B_"sZO%Ճ8lb (s+Tfgiux!\㭢$XrNOBex`^fc=]hOITt9>0p6ַω!`q5Z>dV%Q`UWrMdCڏǕiS5&)IBӳ8l:i+-7O@ ͶY߅wXcbKL']S-uJjm+,J+כݟ tl!/%Lcqiݝ <:1<s̢%|D)q :9D_3X&!Ќd?Z˓d lclcq=3 ZL!A^4xoGG]!c.w}1>퀄maX%f`9$Sq7*5_i%UD1Agֵjri8iyl7vvbV啒ىOv'c5'3#} $ž-ioc)}hqtsjes_)gWHC @ s97p+,c*#[>=&|8dуi-yz҅ `%'Y(ir+m_B#{>Zq^L܍0|-*܈7{x]F`ybSq+njb[Fq p؂w]. vScE,^eh6PrN4&I]r}:xk3tͦ8U[q N<hg<qWm1f)7)2QD zpA[HpW$&KC*eVs ̽L˼@GUjR/z[w%AVzZgR.BN5?4Fn  G&cܱ :6H<RnDذlD\" WAeyɱ0KQ Q>!Lkl1BlSn fc7 ?(:Tb+6]D[SXnMekSn ‚ɤ;@iqoY)-5z\}q |P; 󠱒팸3hK p RH"PAQy%XBn pXY~9[UnUlFtu1-`y.Y|spfܑG9wep Po~#7gޗ\IWCuk8ʝnީIM">D*d2{ á0bpw )\!h;zvЏjb-r8sÕ9?.56ָU~7VcdxBfwQK28$sxShk$&d3ێNPqjRDҥQW\aXm݄wLP>MLٳ*x4v*) =sL@9 tRn8N,eF0 KMD!e9/BZ* =iT}OVLO6K9 C?n{?StЃ,VԬ ҹXG7h/Ja\])wl<;8~)лFHgdT'q?4ѐhڎC &Z4ڒye[ھ4jͽ;zVL+gUV}hPz\Ճ)Fr[h\pϊ ~~κŸD898%o}kJ 6H8um`bxqSLTBIz ])g&¦?NѵpոX]Od :9ޛ+v8LbdiO.--]_<>6wo#&}X7]/%nNb Tt n$f;;_ rf6^z%wRV ZP WKàyD+xZ]rYTg^t2Nkdf?ikZK|NCz\_e}6f_NZ0nʕ fTip)pT .Wh=)98 QS2B-f5Vq.eO(kV[0BkzW@&td( R (&eq-)ՃϱgT8oqHݔS2\?Mq##} C<&;,4R]ZY>֚.\:zSj- \#͑+Ϋ>N( ^QBkV{^*pkZ4 h]#2 [ ab\ FǷ?:bbcN&(`X'ր'Tk JI 'w4p=tZ,ؖ-;ۡjF[g)(Cv4蛘8Hotc0% Zia vEVB&F2v 7Q~\8?++vŮH5CoRJ{f1zȣg#/:0)XrNN(N[,;|#w>wpW X *koxR |,$H_T) +#ˆQ`[IՅ| f!<e<, "|(/"(L":7Uʳ(%KA# ړDwDBǐ [a$ZKG3skF19lgqtw% VXK.9)Ii 0C)ELsGRׁ& cؤaXO[\ZynJa:lĔT;]\]ȥS8~ښq*jF]"dW"n7)x[ZӗB- CgJ ǂʝc@n(@dMmt׈qGIZ o%B(Zڡ'$[F'C<)ELZv)ja<~pңqd*`Jd<؏dI> }0QgA8q];"O:h& ;GW%> ybx46ݻ g G4*m -ѳ}sHsǃ}ЖFLwJ["iZboGI:"/$b;XnC~}26QF٪Q8Zc,mQbZ 5)@|b++@ ٪?ZӵP'|%WeOR͜NGphM H_<8ئVebSFͥ! xl hv*/ ܾA_gly\_Ðs~qLlp( Tv& jCŗW. ^tvH3 MbgO?;6pvfqP8ÅYRΗ $ML+s} $F% ,*f_ITnU} 86ˉB}؆?R"%bRc4ˉ'\4Db$쫨S@˫ kL/+ p+ [)OjbZ1|Mt\MťxMJ9K#zq %1}t3_Z |Sx-6˥3k;e9G}i4km skD♨ԉӯ䔠Ax:Fc;88Љ؈>7C>-Ht`ԍH>o&7kSp;XX۫5Vr ؀5φJ6 `سRJW=.d͖y1! V.M)GzMk+fSRK`L r6;u*6;L/o25i{m{pݟs(s-XŽ[ g)EAr<&N3,N11J͐ 1"ecD1瘏ɑ`'E~ےdUx>BF!&Bl`&X4 A3JGIJFj|oJafis Aa,(7Z_T8M^rJ*DžU"oy?37IiLh˸ڻccbNInIVPvة$,Cr^B0u[?LWaP8z-f?B0~]X@H.֟^`UdJy7+mH!*8^f:[mN59vZp>o8A+Es݆մ w훸,Y{%Ki,R,ϷQPRr4IY4j6{n⒴7QDf*Hj̹V]kFK[ke 6zƝpfrn1@vfhݾ:O/m ݹ`p3{GneLz?k*D eѨfͨ$+2)篔 {B\npZ_\AQ[[ABЫ6 bpv!(Tn."T ]Q'?TuSEeSMy8:x5Iou(?-i{L &q``e$kO7'y|䡀xuRRtAh]G`Cֱ5.' iBCY@vӘIRk*@3@0)[#uhKse 1V;mһ^[BK:WJCGOPcsgWVVKtpqzyu~Pn/-_\ZCK0ԕ5 X ڝ62񜟃+$Ĕp`=3o*,iHۮwB<&ԎHpT!_pQpWc#8@Xt061>>^?>Hpie'4#C~̯1ŐG}w0fY($\I';Gv}#XC0LR'{3Dhbݮ* EެAZZp+lD{MU@! bs3ċp vN^#SyK9tt( E[jT_ 1ix J{3츉{ZpMM7Y sC9N-˅^1\55yZ#ypD9;7HPؤHQmdh i=)0lYPB̷9c~ܜi +B(q$x#V9aE@)`%SR/@ZyCT`Acx'rn}"ql:Ldl5F0 F2%y~)6=ywKW'R*1O#c!Qᮌ(uJ) CB"YO%@ФXU*NKi `1VP HH#p>B Gb5MA$A-\nn:,`Yk}hQ%a})f`=]KI)U!05!Lwɴy3.`,+^-dǐqUÖ}~ÃHs-ni 776"xR΋QH @rk ;=Xk8Ȼֈ,ywpI! 5*lJ*Zv)7IЄaKkAthITz[=Z7ڱLW%!vG.ın-Jl1L8E2kRH@98 5@ .B6k}28TG 8Khսm@3XESr)E_Uctu,+N s4xBޗGy%yF,ЎSٜEc(F n* +F!J9e o. a}KSp\Z|dCKtܱpN7v! ֱʓ^zt"D<`[kx8S9͗%qכ+fD(?7!nHSHH&n+*k7ǩئ$q7vMk#W,Nl4;yZE1ka9^?94Q3(F+PA؊ }HU:yQ"@>nu;,/ A}BX/%L lâ;QC68ӏ hŨ(5o꛲цHE*n1VhTfPhj0;J(9QcHffVazj ;vG.ֵUA^ZEC&f,٪tj`ev(*>1qj bt+ _tYZT _>R 3%'0U٧]|UKc%au~,.%*mlQh4g^xΐԂ;.bԊf䘨~U+L5zGUj\ dx$k(0Gh l*D8M=BfKKW VvHm#W5+&%ΆθzA|vљY9?2\7CT_4}d(Db^,2#{RJ.gag7 ^"(0ϱITGIKIf:T4qeZv (Eǯz @f0=^ / uANcWQQdTSM&xdO-œխ8;b\iW2f/u(M]W2j^&)"~ *k -Fwjs˗ Sgk;[1w+a${+FrzBQ3a,P' 8 w1܎0 NElBI'+_&FZ'nֈ-n_<cD2(cKN,p*#dUpo48O;cW 0zܒQ}l 2M78%šK|Si\ةe=\Z$QMՖ VjC5f2P"hlC<"+P30[RSi4aGf>ryJş+Z{x2e!*S|et'o2,)F d?EkRkq4dئ dI0:#t7 HK;I9}oHɸlq׭KSc ވl7n׉kE6W6]^g u8xV$ 鱧G0}n~ I~]ׁi;'6n.ƢZG2"#Y{oH̗](oาrb1Ʀô9~72(~#82ENset){`n`N?Ņp$> J֣JSH! 9ZάM@Y#Y A#`2|+wM,J=kDA*%:ё(eGR|o6([[NDGAx}caڎ<ʛt7܄1:PSHY)Jrz>> O/j8 16ov7 Ūq챛՝׽ PWho{t5F 1-m@;D ?VF7'5 sSG:ћ韜 8.IpZ, 43_Gb' "3M[)x=Rȅ8hw)~}Ts4,GQe\UHy^ejG:ǞB,4^!\Ȯ{ǂMP M<͒BMt4) 7&;NO;pED[OA^ 33_%#(>&&OXt= ?ְ=)VC/j'(B(yaߚ6y4's!0ci\LbH}B@γz13ƞY.:b}qIp~zCv6b@jj s0>8h2f m2,%^^mr@Hn4f ɱlCZtS:#"SCZ&F"[l)hM{qg[FT2^\9]'B?x|<\[QWبdPn.عRGz6)@`(k(jZBK2 9w?#KdSq/)XBXy<\~Jft'˃<±^BgW4|}&jD"*g%n_9^twWr*J2,uY"xn#/3:p<@7(gP_JA})V+:Kf:SiT x]>hMPM#Mq?Z_-KHGkA\*+ Eӭ5sf/|BS6IJXؾ:aG c" UF(c`alO'`cxse>)v`d+hymvi6f&v\\7@ &ݔ=QK2/d ȑ;P#Jr1bCq72Z6a)V;v,[^^ZqQŒ L殢̓-r۬.u4`ɤNUEKmdT{d220HN0#-Oi*u=ީ¡:H-2imw+Z Y\!1E0&3C9DJ Ec*QDcR"h bF`asC&t衄܂q<g  xqc|vhyҟ'@Ŗ]dr>vhI%8wOr-90>9Ho^hdG6Z^tQmm .עw ;=8Aq7 W0d<$(b^Ni&w@f8t4Ȧ'A7/w#SR@N!Dlw$>YA1;jߡČ _aan-ʮP*3]4V*QPiTIc(KPH1#&}džȄ )M!0Wl[W J*ù-CMdur;KO)]&:t}+Qq'=آ-y܈dbՓW(4Eo{\yJWL9X Kɜ1߶N mn`n:JE; <67|f^ĮLjtE z2Je"YK K_gTGdf1|աcd.z"4m(øCd(8!N$\,;Nحx184r,)h0gm/nPHսY V?ĕ~NMK]OH jRfsUsR=&A6,Ι[cS|@p/)am(*d#ppJڧ°9t Si.3Mq9؄۠}W y0>؋FiEd\a<˵оӤ}I2AбK1ɥ^חxEZ]9%Oۄ}"=螟4js$elza3V@ynZܑd͉KӌcE"u*;`n@{$J--a[ OzHpA76xJ'{ ExRR0Kh+i:N|(!g.OKضqd[bC rT&"Un9<3+nhµ#x]Q|#5tse =* cJK6:!r̓"`VxDgOCӮ6H EQok#S* 6>O N]B{NIFĕyXɘ]BUbRM#M~%BbVZyOP{a5[#6{K|trPGT4PU6nDbE0;jݭGׇ?l݂őEVۨܠ$0pշv#,E`IM 7<V$!QǂF.UhD^G=8"//X[^\^]_IFLuL#SN b3l1x$#nlϋ1=IWkܫ_l26]׸@%N A!62= /ɋd`#Nn6E~AGJ͍jp+.-.-.<7/Nn%xRhXZhnU% ׀$@Zcc^3FM4S ֟xAj\ݖGgVVX &SBϏ< ???o_gB'R'O9q9qt|D~'h%ytvH&q e:܌Zn'٦˻ެuuoYsyw\FSҌLw j(fw{-ĸfh)^hBB0WFL7=E+ KC& v x tv Jl ¤)iYS)ZO-r>SRl;(n* =h[dc-Iڢ6#2T;m <_Ps؇sl #\ ҞOrK {95 ^3vxծ.W~88MT%[vz88Ũ]o0_͖^$8|tCnW|BcØʰUr:`/d-$O;I(%Hm.sc):h֗OpKi(I`(?wJN?`r/Eoc2{s4 p0xUFq@v\ 3qW4qWҸfj] C ;ګM [*3-f~ĊƞSf=lVfUJ|Ik0h*K5vnKIN$@X2!Wre+|P *<Nո{mU16Zj{ʼgfH!ՍToF7-Z2THhpiM?(fJQ?c&7Iy7qTAm?kMT"wcsRmȤRFқ8?= H9<7;a{=Xr~$ut4Re+L$xjKO7~_I [06 ь=NR*q>fL2£s±: h7z_`c?V|U@ H΁e0Jl8v]8uzɊioc#1)N u9̏5u0Q%(|gST ΅g'+5nielQ@yӖ!ǽoC9ga|>:%S5cu'`)̎9%! %>QfBBQuK!]Z R!~\}`.\&p ZRœmJ|p5I@) apy oK1ےe4݀\ȕo mF^xL l|4kqt u8yu𵓬mVW ㌾k w((铦TFC \oy4!lKpgvv)B&tgaFS 8`Ye_\QoF FSE?siJjt30 Ed9qfSى1 Zњai$CRPri\AHJNiX).NRX\S* &GDVQ8hz((; K[C|&\pн--$k;hlCm`hL }7Q7vey =*h~zwQ\e#RL䴈2NqV>Qwc=Xׁ[H3ͦ4~ӫ`,8I$'' Q~nx2 PWiy"}wNZNw^+ؗ|][ELsƿJ%%{k:TCak8:̅agpؑn#zx2N3,YDĘ}ϸƹxm&͓87Ħ3%(O/n,'_p]pO` fNl Z4\:='#&Ɨ!oKrgBşE{òB#$Df $+O/J&J㠅S\c/(]aR/ L!鄑U6 ӽ@R~Oĕinp_:顖qNrWOP=X.7&:Ihv(YrKAl{6KDئpY;kW(<^yBTxЪ`_GDpqx-Q[*MEmi!vBG\c1@PHU)ѓe&qcŝ-?[goZ\IKXeaJAsDy"ÇaQu9 /܄Rq!w,sHL4pAuQ3УָL[\`X,Kzc2HxMf.jH5sBDӢ@:@r]aCJwy.PŽ($CwIeYuuƶE8}a~Fݽdedk)`Z 2橈{S,L@6A𲳄1(>!V^̶<Kڻsi*} D]I$I|Mng 56)ݻнȔTp*Z{њ7=ͧaISmu }x 1nLeM!Q3OaٳsqC8չT5 JV,x)tE[ k+S+_t'$0RGv}EzϠPz@7azR߮l ̸-JE&k v̳)A38^y=7wk3:?z@u6_陋>\I9& b9}lu6i~^D}`F}!VpyƪɄuSJfȶl}u,:~ҽ5`;'Z3wV( p| =f띒?r <錓\G(M儘YuGGMZ7sҝ s2k1K>4,= F.r` 5joONapabϸRqaf`˘ȈC' qY1Q"+sGq"FvnC(T^nC*e*8Ok֬ ^i&-A ӗHb.\`A_Z˜6yMYcpث?vU&pZ p7 ;vmEIߙ'VIOOiRM)Jj@coƻ{xUwʴ7)=&fzrm/>8*IZj$ě"tQde]~_0{saftm\8TD >sCd36Tk-\F᳤͈?U>LM7aAcMaTؐ #$$^J,AMLߨW `a*w%vcNxZStLmOٻ;*{W8Lwwٓk|w}'ܙ|/H,ՐC)Ih =Sl^ j`!FqPpd s`,M*G$ge72zZ%wm|W"v[ #=x|!ݞC!UL2<%B}}ۍ"scL(I` j5S>h5"'Jld&d^Wk`kSE^L2ov)9&ʸGcU2 (C.ht42lmiPs FC ib%j:s: Ry ɴL& ŜD.d2>8DX,y& WvѩP ."ٻ,Ň$]K'L|DH 뫧fI0Lx3UieR1EKl ?Lx@SijʧzD+%WW\:,nb$h86`e` 'xZ}W|589pg0&^b9w`Xl"v]8}vmE𳲉扼붃RRZ sGmtuu!.X3cS/Bg.-/- "99p4Mجh\ϵVlG=}Ltbzsί/-ش ܦ͑a3 `8t;)8:ules{70Z?ىl{ƓFiMgQܮB<|B[Sz)Ru#[ޮs )n*mAW`n˗Iy>ڬ'X:"Yb;`7l[)>q[$ƬOIi=TjTPEm|ɂy2B b]Rf-)+5ڊ6ڨx%}֨3bfà3Coݙ+1I<'7jb J&_@vRV;"6GR~Drn\@"18:WeuVKr<>s*'I5㝀1lHƖt(W3B(x9š7e3v:7ĞJĘg(_r"ڸaВz ޟI#_-$IR,'=XYRL2m&z^1YǑYȝB$#ȱ}sqhG=O"?͖W@|G!0A*imoUvVmO=`ZTI; ) ϵIɡ(yh-1aHVOJ$3`ͣєRBk HZSbB-_ |aJ<WABiļW*9xze,J&g;ĺ&_5 uDi/T:݈r3ֈ1^\M2Rnߩ'.S]Q[QlfQ%j fQm=JW.N,.xri6ze0Zt`ŅW3}*=[E9$&M>!] 2bsŠB8 ,M03s% [SyL)h6], oT[m:jRװ˞IwG}㊍`6wNS$b6ѾCuv;eN4ӥݡQufkOڭbLDkU$ ֶV z!U0ɚsQ1NH4*ł`3j\.@  ^">zM4+a'@]~) Fn: (5>9ɚ#z<9AԦn+*xiPŭ4xb40^᪬å@rUOo<kb4$5FQi$e8#rZ}lqnԷ{ ½3RtUeNaB):CÉbl5TY׏#SF1=#T%2Š?< |n,qh8xfH ^{-=3[ۦSypޗqiP橫ݴ!<%- /lh փI`5ұU B DASzW0Ac88e%17bG`HQ]6b*htA{ְNN=G7ks08:@fy>1U!'H!#?`}G.,;\V 80­&ۻ+anf퍟hȞ}L=%Nɵ Uz ©|+7QͶ*fa4GWؿSuh. s*"g$l,;jWH0ה8loJ;Vj.*:O0ZG M,5H;6KA~c0"hwd=V,BâfoF1 Pׯ21Opz.~fX~,sGa K e|=ņ*I[ Uk\7 //,hC+hd.KQp5%;էYG~pHhpkP#5b>}h-퇓'$q&cIMMRz6*&\,vƥ ܝEJlLnyu9@t,VׄR <،jfcJ~9Wvj-1c`VrMV9|SF <}ʪ̉2EƸRb <a9mhBZO!f䀬asYmtkᚤu('RǖcrVyp2l=4P^˱N}YKw{>7` v3NCX+]](bW6*cnN--aZR»dRr :Y8Sp9Sq Mlu %(I_kW/6!"0FD4CJQ+I-pAAXd)WIH&]ƍ5L:< -"ͩ)F1n:HƙRiؾ̢ɞ$vF2H?WψQghQ!KnSq @b5W+ PoZ_PGUBUc޻ICk.î{u0KyO0=ޢI2Gf4ɢO̤@\Lg8bd*+"IK܀^FYXPj,PIfmK*ùq:25Q2^V8%jZ76BrgFqjl(|9k[AJ$N[5 9%V\#:P ejk9!P¬ -Nam z7Ogo ^ VO 6cƂ<1WCၼRg|K€fg&xzǝ2q9>̓^f*yH67iYC3=l2d,;'x, LaB<sC3zrn<{g 8Ccxck#1@LDDsЮ)?'+&8@q>P7dkg4Xkt.1niZ2%'0ZW&5vHV?_ν FK>ml5ݪzwhJelhm~Ƣ)X(,iQ%Ya!zmЃc< I<@? H!EJ#c|3ēä!";`~Db2ϤGhv15QbQbU|kG!n\Jf{ӯmr25m26Uk}d"bB=d yϮqTu)ID/}` L4'"839pu>/!KU Wi+Y_zx۬#,n2}e|[uP.,W:W5RͺAj[DQۮ"jeqa'KI0;Di=Ϡ0j5 Hq. R(u(yҹ 2υg1CauX;wQ 7N9yn \F/玄Z}#]lchQp}`Khu&?iG8n謉&QWyD=X E&lN9W RGj_b¬ *g̩)nӸ)^(Z,H'wd@J{h j ĐBP̌d4w*`Db}'q!Zhm>ᝐe ׁ.-^{:K3ԁFq(?{3\Yt! uq/:ItLBF;A~q]3\2%zK^,P-q dM,))(YdY/xo8>\`)  H#c$%wA{2¤bʳ7;G3 sKɑE:j':C@/ 1@:N&q!ڝ 3@@G.ƞF73C7#AMj&xxԿişde4Yƍ~6|֪H-i ^Y ť9.{Տ[ޔ`H%8 40R#w$pN{Pdc@<[6@E[%zB 4B>@Z]`N^ܤtUr_0+I?B0{Y pn@<Fr<^ΏCp0 Io F r [? bǡױxs k ե8n#>3+NN5gg.-$p CasFWN %NA_vE-A6ZD;3mf mOԻ!4a꒲ɴ-ׯYnSULەhBRB)~MXkDP-[mGjmpфG(Au:D:WH/ZL'iMҘ|4`bEXDz&u+ T$ ]Mv78Y>n=*YTmIh!N:qy@bJRG. 1C,4o6 451!N՚[9+{IE_dd5VN`FT/񛲊$c>܅ sO%Z)18`ރ.{%T  ^)˳ap-ml:_꒘1(kh |)I!O+Q7LAsT"DFH88Z0A`7V.3gM_\֩~l?-'DcN.^A3xt8޾ ^B#)^)|ڵcFͱWV} \ wCz2br~na!(JZ^,IƘnւS qr"`K<և~C4.0̻ǾIphA_S=']',Lrf^5@GJDNA)`DQbiA~Kz@n+M)1%(9@]IdD0~2|9w䡀>;b[G;Ʌ$:Skܑ$ՈCi&tL(vnSov8lRQJ/j y%w^LV8‡-]FƔa88$NMqWlQY2Kac'˜:ʇ_<,ĨQ0=hf;TPcR#8CβTuZku1-Z)65(gn<}`.vq0';vbҕZE"K+W`BJTsNQ.jQ 8z^RNO%Fx= /^)#z/|Hi ?Pz9n}ؼ^o GRn1zq'($&!,IXzW(-Kؐ 5D6x&sB]`G2 #F (rh #wD%U3f̌J2kzq 狝5vIDk)@|..篔 㴶Wfq NWjB&N)2ijv$8P6_Nn_WdA˝a7M*b u\!-Cv2gn@Km<ZMXNLjLMYjY<ض΁(77{8K㋧Wd r)zչֹ{"!Le *p(",Ҵ\Wxmx˲0'9D7L}4 K2<ɧEk<%WnHuܘzRSM0f,Ni覈j:UH+ZW|Yf/G]KV25G֧դ ;PTްcu-m_eSfN)JS%t+/<՜ʹlɤv<."|]c@ Wa}NF})g5Pi AװY^ŷC7B9υc|_.OW.ν.xY}^*y b;K嫧Me t:xEVȿ_ʅS*qF;#p$PevMG& I8%a5" oPv( "9QbRc9DHrHdL6fa*ٷ^'ӚOK6lueNeC9(Hz B@@c^S[Juk"`N $쫻bAv'0Xq|aoNBQbK*H`=b(u63ْJ"W`*#{^~L,@\:nJultrn`.&6L|y~C,Ljpf8))$M[h{[gHS`-伨>d~֩du}7,Q]vZdq!4 0jnA`**As9c22(J lWtBXZp_ VuorI=HX Q @2ZR5Qc noF<{+89pliP-]VpGA<;WN Tr#TqYrմ3$s/ҭh#jHQ=dia_T(LCȺbZd͕JPntVN => 0Q{U ^3SV[F>QLE!Y6aFoKQ^SKHg+EK(Pӓyy9bY9(#̱Rtn@z8:h"!d&S-qg GVAio (iMeO0'(lF BO kp@8 nu n7NY?S&ʬ,,_6%b,*S6+lF<ٌhd!8G6=>p_d0~s[0X86#1Z5@R5b+xrD86t^&T Dk{!+hETKS/lBlqFzP(?u<!v*$!GRd$%3Rf-ʾ{w/)9 S5Dz5ѐ,d( '̎f9%*P. ؼˣ{+&9sSȳQI cA>ZEwdۭOf&i+I6n6N1?[T"+(.HUlch,քrb1jA{hQqNɚ-FdEPi׺!8a|cgW՝ ڵ0Lg!8U"v ]@\R zZ#|M 3aW2J4Z0\B:>\IN!QlGr /=|xL#&3=S^-6sL:v`g%kç\ƠSlS'ױTAa4:œ9hB5֞MQ*̈&yI@_MU|E t@ KTifa.O/?FVj(b`2AK4{DI.0G'?WA_tF1Kp$Sݱ*n[%/&!_Sij54>llzYtՒ$XPr($T2p̢`quW V"M\(rtbi(jz2rLˠOqka/=_~#_(+/_),.?^~dy^8v`yI)g*[)* 51>WOf`V`Fa 7މMP^}%>ȁ [tg ʧһ?ifR;'ZX۶@ kSF+(%}> Ƌ|5Ds 8nCŒb4(SA6,Ctqc'/n8Mx}mo[q} ]AcUdq=N`tlFhC)@9b]sɘwH<9#V3АHdvvXjIa.^X:ƭ%eZ]>{WϜ%9F[@ VkӍ$Gw;UJEć9rG@nª¾|ZhIvA!D3 H)g?# cLNBHeRkOC\B$cf+d)XuWq75]i$ Q3gyj'm8O4_Z%"Lꋜ [-ݏ{ܷ t}5mqQ?qH\%KV0ǀpN0 J+3YC4(84[ ! xOK  LlL 3؃->LgiSaRT5蝰ш(ڭGAp \4QbAfahH] !ʘ'cfl˰*zHO*|䎴:~`({tu/<cM(3HGZHgJ"|Me^ >J$;d7v_Q7c:~qa3ܥC7w-ͥ%/o{9dFJ,qvqqdȍshz"&o|zz? 0,EN#%Mb2Qb$ZStDa*mix}ۆ ((4aBrLi=U3~Ĵsj +͊)J-=Qk)jXV##zwhp#(A:H|aE@O?, {(P 3VX7r5 GYۚdFvȂ{,O٩TvkIS*9i¢EYmy4{lfA;q/4&9;%4Rg0Q>3e΀+J)2b[!,3Ģ#9cEhY_ p#(s\fJcSjxXh[:δ8U74f 2ؔ%'wDH'o/Ę)vq;J\p rgi2Xog2K{yGCl./jJI}o_F)'"~(;_<:6f[ђ@ !8(y"a&l(nl*9/ow̔ j#oU.'qRo9 kTR)wᝋ<_i6r=rYc5VSdV1 oe{gIGX #6ldN2i׭ݨmH@@䣣q`2ՀDqDZ S(hS(,lHr)밈v}ْ8EI%UzsOa}%hvnccNS.%0zR\5->\ؕ%%u^aOٵ/=Hnm;d7"$pdUomQk.zk{%jc"S.UHWUk%m|qŅ:щQmۘ7+aMaUkVmכiJ B;M ?u%B'Mk3? *BS1>)yt3,':Odz wY%4M]2ؒxNdCWJe>+'8#7ҩA8dOs.`&EH3s\HORl>C|'h--YLsj E'%NС%BIn&I3aa`4`^_GOXG""ےZ)Czw-#nqChmҸHcu!HZ-.цDZ5d["q<uǫ:/o*qsprI z,g2sCͥo7Ʊ@r jB5VP2NE@,cw3bd}C'FSFNuQ+Eî-_:;U;6-uEID GDx䄑 ¥YaF؆`(Ie3J f?n\?{?RpR I-.F*y2Gym,]08m:< "KyPkJ'lHA@5t\\ef{n@dSt<Zx%~|P+h,﹏2 $,1%Α2pVph'Jc;8Ļ"Īhʯ@2- F8OQ &Vo,#c{Tr+ (m1JR\S YM6,̶1L\&OS Z<*PDy.auW>:f $\W]ҜJ]߉\<*R{crbHNɪı8=sm&j#}-TɕG'43ez0S<118fA0׫dJyeoR-7+̊ށ#:kȉ$_J(30j\?If&DHsik6 ( 4:F˧^9vW6pĉ  "!G((%gO(G{lvAshwL Àa@RMxOl / jafmzab{sFV+oou>x.mxnZN+e~[5ep%Vu'*HkF֣Fe/%MxxNHDf:A?9,m3I3zpv N;A wtV@F+7~x̏*x7._k .8ҌHq;P%6JIFb+޵(]۸{oCJVmkNezDhز4N?.M{d6Y=_j_YMg5{ZuSQRAKEIS$5\7")1KDkTuߪ%JTܑ sj]u\v-hBpmˑ@"lnap8LQK8{ji$\ k>7m_" KsΝu(`Z Fs1*{v(mܽf\c9)r_ !2 v*^ok.I.*\nI8t;, SBRY&86fݖF P1k, %(mt֠VU&ϱ1 ( THYbbJq]*j (>t|iOz_=DacE TN`z׍;f7n$i}ꀕd/eӥb : (`#B $xVKMR4xmD9&s~`ԊJ"ܮkMZS/vutr-,6;w#'NGN߱ 'ǂGON|t##O`N5y C^(=%0J>G|m2 ƃc&'NN"k| pgZ;{V'cŰIqy'̄Ej%"<ߙ=þJvlPII2݈댹Q }] 3s@-_X AYZgϥ|v^ pͬ~fl?`n 6l2hn1:ʝT}uТC/.G G)>uֵnTiu7aQ qi6GΎ% 65Uk*kݑ`umN<:2P5\@}D۠/5]0ToV]"=-&$>#ī¼64= %.Htoza-ʕښz@Me7M 3l۳֨47HmrS$F)?wV'J^*:kfDȤގ(?6Z0Sx6cENUenR n!rF8B{/To;{`e_\^zv~vn68'8o \\[Y <:?2/,\_<79ȸ Pvu y9}f~a~9"vxz.N/\Z^.^Z'1;20=anvp~:N=X9? ;uf2}yjZi/ͬXHrqnf]O/?7 -2KPJd ̥ 8ʥ3+VsKK+sr:XXZ527ݬNX x9siek~.KĘ .Z,3PvifB.9xK \]eYY]Yu(VW)s-̙q-aSWaW<s2`|Ձ`^jzyXG+f><$jA;x ̆-`C(Kzn0tavq5T?ȱEڅZRW7ÉU!`K=EETl!yes4O?-֛w#c''#X, |>`MOrRVjAnPJ>oO})0܅gV/>s~J׀ܹ㰒P@Eax$'߮4Yo;ij S#P ӷļMO(}I?+Dk@}rRw6/Fk(?y2'~}+8y蓮;yO?sŇ8`ǏO$>:@w?>G 8.BK,w(P٪Ѯn!?= L~e+8ۮ5$ߐoH*}Rl8:u8v8<]o\ka|cw,Y2L2LN–dV04aS ddyti6g0;ER7LEOFi.p|A$^Nx,uKs8.-r=qsfШDX)0ʘى4akT#*eFM=$9i5V`j|sWGݗiƶ}*~r*/aJs3$v:@3 fD0=3\ȾRt~K _o4[)xd L,po#w~QP&Gs`?qj>&))PFMq z86`6z|Y-*%瀪p =j~e0xͤ+un]mdz!q+$W b0n׫[8_*)^Ngܽ\a`ٶJMfh0fo9/3:ZmQ^fpӱnm0;JS+}8Jk[Vip|G e<@~hsi'lY&N18HK%Aꖪ/zU^hnC7Fi|辁[%R"X *mr&ݩpwa{D_٠neg$1t*j 6zQ??[NC;M;i]j~9!EE+230SdY9ֽ"䣼z7: "UǦ|xlW:Q6(֮lt8y՛7G qR\}wfA|< J5[k3b1*6E8Yv0/USP3C=Îp\)yW A.)8uY@>h*5J\Bd8Fϵ@$z$nVoJV^׬nuXű#01>;8/gd'}J4;_p-ڰLؘ:Aks3Ksk_4A|2;"eVVfiRY >nc8&%2/pERJ[4`*9Qy:ÛxћGfxrhEHp + kqg:tM[P ~e;V)By 0P.u,P8c z:fm4H3RAf6ABWpj~Z{P4aOO3ήiRD b(hjmӎ\WuF|ΐce\z"G=jӝmN'YC\1.8'*8B;EU]$h:F:AdM G_auIomS]ʸWz7%jsWu E *Q`| mrsYu o궨J۬!4b8n*Gx!ǨdIff^%% 0 ٰڞ]ڒjv/b۰\jRÖX.p"tZ _1jQHfu #42O7bh2Bë"Gu,nH[2ұ)H#3⬬a%7̍5\Y=!m*ͪߣuPLvdIq{Wx3`At`dLrSN"j]3^lJ&Z4F]m32`.8}"<9`tjV$L|DJ^+sy 60lؘaao:%=`zF`tj (o"_ `auʛLW2Gn; 0Ix[yA\C<[xy Q0w*u%ynp6)m7. 13V_=`DҲ"YT:loP*\0A9gPdP Ld5ֈ6<#o6~w~Y8\؍=ۡ l!C]uj"萇1#:H8g}d)#piT\ ͐87a<0p&fk<)c#X7`"@8hSq ^o.%ݖDD˱B"_'*fA{0 ZX1CD[b^Ñtu$fX?$e#Lxgq1d<[GVa;de&~ @MWmnAa̫8? kuWsHy* $(QZI +AfoxtqTD(KK{CH1E1}J'iPE.&ql]\eU[%Xk>IPx𝋬݉Nu*U/@.&41!U{ 8k'm0uKr͹6jsz>071twRacK3裂hxʙ,LGpP>Iv% 7pH:-'kcWJYI!_抡bUHGL~)x40 tQz/MJQځfUä6Ww$ƅ[&]n6QM١陹ᒮJPs(C9=)dWpYSVI4`#͆Y1JOnVd BgG q/(HObͣr5t.b5۩a p&@-z!GΦ qLZFP& NH/Aa}hH|Y6{L{{j͹1dxX VId4P:$qL<Þad(+vZE҉=Ptq>=/fq>ܦUil"Iա? K.莳Obm.Y!!"!a#,ҲKY IIC{(7`J֣VN*@gUL.uT)B9_ Fʘ?7U7wD9\|s ouj[W*ƢE] %$*;OxjXweDr-TMZބNrNַn˻sj1DJ~ݴK[ңj(:zupj]f% J(Wv1igl34}Yjp,C 2"B\G#BMv3$U:MOq_;Haqt TIFr8x5dב68E,c!&5]+@ zsgVfG&5|<3w٬>pW6b/=vOk< fFh|<Z Hf٬ mB=J WuVv*jнe# b3Jn3k6^L6 NmI0 lu:;fZJ/팆$"#%EW0< c/j MGܙ.RUV3H%MS?f;G4%^nw9L<{ sЉɓyB?n!>MvG}wĉ oΜ SGVF O}׎=8(|"|_ H?||c7)-mAQl襣G+Q~4Cc3V9U P!rP~!(j!xC8sGm@現tj;N`4ș?_xpP(\:zU.y/̉+Sk|􉝧 BfU8]x0 b=0/8 +4SG=3iCy0;8 fml;xdZ ޅs7 O?S*<3iWO?NFhɥvAS bnldE!3 Sh=ZBBF;I338*,2~ɇMF.\>YQ6 /j#C_8:|:=x+:yE)[j}4ї+XFN7]La@krt ? S5_xP_xbzlVhP, Ӱ4>6Е"N",䥧_yi}j6Y]"XG O>zmb~ [6vF%o;eب9jaq*\Fh܅ m~LUdxN<)OG WG'ڪĨӅ O'V)|tk%E/,x[ݑ%ܹ/V!F5>d1[ jŅ̺6"u*xVv$Ë>$y C:'y+DOw$/oUsS_j6rfν 56{ NEv (ϓ[XasOh#v蓖QgYs| ?\ _gVu: mHPh\7M]Hc hD0|ՇDgoSPX®8D( ),$ԩ'ʓϙb)?¸G.=oy˰ϡtWIiыG{o'/_KW6 OH QWef؉`.EHԒIԒ[N'ݏOOq? _>}?wǝ?>9k"8?2`p}'/f>lc?|$%#>#,z^Y(T_#d~Ad~A{cUvvp(-kLDRX_e9v ޔݕIW)F},6u;T_'oWv/<`2¾-|¥x9 ;Ӥ=V):":Xo}O?t{M+Y W!9#LL<&&/Rs;]P fu]Gh%2c#j †Imz3A<#Rcǎ ,~)pl@fcll5}v"9- Z̪n%):'km+WJ>5'WrI& 6N6¬O"'L '3H~58bu 3_Vl 5ͶqX$Zʈ׭g4#NOba$9:c5~p N7re-JA>znn,6>0Tl}NӅ{9'LS-q )|v&\~mYGlQսj #+IFƼ8>9FLtt+7"x8E xP\(Wn$8V`6 Px$6 C %\#}YQ@-qZH -jRP3GqL$F"La1 ÑkT#v >lCl8Q aQ܍L@lT:߱ϰ[~N[7Sw (%qI@- VW= ؾkK))Wvż.}fJKGvũn<ʌa,4bx U񓁠h4lKBkHrII#t p `R' a zezW@5t^&3 E]ώOfd^q̳%`f.L9/ۉXN-̎.ԁ=SƮۙ1dJB%NjQ X(݄&6b~LH!0?g\hY=v3{T*xJ }GM=b F| lW!;5@>+˹ *sbxxYx;E;gF 5򪳳~hgjq7-cZ{Jn! %EQߨ!h2pkI +5@bnBVsvہN%j' +ΜFqr^$k ZQtu{=-S3B-9%q^m%1W(Ai jƎ cyx'J5[]lT^.EhϚ#JW7)=i`$`SޡLZ1 f ! (rhjd8QΆY v#¬Z@J3.`)+U$j@IN "e#MҹXʈOg Dh`t8d+7 c=o[ML & ԉAA4w gڬ=9D4"K9mb&%}1Xh˦~K،|x4Cꝥ tIDehE-89WW Q:ȥ한&5B%HQKh:m=ɭEy ]h^f:vyG ˪l@kM/r3HГQmeм:,3K Fbe(CЅGցВa0HCq1$'t|3Q# Ctn֯ʹ&$WTԔ߅4` $ <ޑt)2Qs9.[{r={ϢI&yףaa%,M\#ܗ,M0D:zs8B|J1J0VN(B <]N8!D]slJuY2dGZ6vX4y lI͊nEe#3#&װwhVݱ(c)=r2aȘ{ PG ]4A`NO=9>**P7F+1še)kq%1F8]6"@Pf'2?|a^ K "~do$v\CmPy-Kdk,KcE'+M.UŹ֑Nˠ u-{wa;Aɒ+ߏԛ;:ڈ%')O۽Tz{BkLe+qF"QWSm%V0,:JB&Nw&­^b!wYG "lG noE^p6] W#XP0!Yڈ4Yi^ 3sϭ-,L/]9?8WVs2Q??@f.-/-]Z[N+E^U clb/HCc3gBbY1ٸ#<@Oƥ~7ӑTM&]u:^=fBkŚ%)#8Q覄 LieR9ZIQ>w23 uS,:fˣY҂Iԭw,҈%ɞK0=hGKbEYzJ_ʪDaT^Pk3hX-nz7yJhilRdJ ]f0:"\ʗC!_]&7D%̽cq.ry & b2>8 P&vt{Yڃ6 {3=1g9c ]!\aijyM,+ؓ!jj=T6!.iQ_Fs#8afˡCIPyyR/xC*ՙv'次Lh3l"7z*G: ${L5-ˈMyHX +?q3‘Zs/dCH-i#(oTP0NoD񛟣p(n7g퇘0T$r؁`aY Il]g8ޔeE(HE] B611\^L!+g0 ^üoʜ-$/m?`JNFXv(y!yaX{"RaT(s1ȉf2v欳`3??w\~DZaV RpۡqNOE| se꺓|(#:La_D| r b3rF'w]B<}@FQ0$>E&=X6zti/ C+{W uEt~=#!Ti (qQ;7鿘'7` [8>*jt3xBJ¿s7p1^,2|uz!s銻m g\  *Q$2cN%:N-1N׻܂y|+TR\QIA;e=DꀨP'?;gڭ(to{6vwhƗ7޼k5)=۹W㱟_@l5nEsP;#ŗq6~LU2ZAns0Y4ƐD7V/%0rEt2Z]@5Q$U\M>sͼW:I%ɖC 2643:]$X!i! ήlS{ yEk@hQ!.+CuȧNZKe!+&*;7p$آSCT jVXXjx>y NJԟ,g JD حE"FQZ =/d(ghY_Z`^R촢|YT V K͒r!!_ڡ :>OA|ƳBaCB].E>P2*2/q-*A3͈i4bהFtAb ]o ~~0z1v Ywt%G 0 ՞F&48;d-hT%i)b2 gēf"}&%&6+IŜe/'r[4WɎ JO7 @2N@ӳ +Ǵblx|8XxdbN++>%'JCl@Qđ| Q;7>wH{ s?g $pdt0r0ncr$"Ÿvr'.Љrsx y)-qhVYg@3gFASALyzl@GUCaQ)7Gyj~4:kc@zqrtVD͑feК\ Jv8h11;]MHAAb'm0d9';QV ZfZaV6j`-ø9!st/55G!d+( dDB&(g䠅,#v>ٶ;VB90AvXtl(?t+"vzz#z:ޟCBbw֦vVaInCimI-6$JZ`Q&WCPĀH\WOZFJ !_Zl3y.y-CmN-t6vBQn~"|KLMbn;v;>Uzbca_l=$4 oPTonAy`wuE~#qu)TP,va&P H6aFJywhe M!za9줕a0Z2T lt)BpB@8,\8b nۧtv_d:Bq;4[q7@WJ#ZzCۛb߱#ڈY _3-k wd՝t1K!;"L*ԡ4 u%C%}!v5(LEGJ#d#ْ8ޝHEE 9*Pd!muUcmțU\TFi,ɡVO8L\etx1Ok3\^a tcbKˎOz\zM᫈~9%L_/ފ~&_g|2#v"zxcpM^3&3&&]( ;K_?xۛ?oBrB3^ϼ÷߅ִ%n#x뷯s.T÷o_%x (nxy댮ͽG*@w[o;#o`z8Iq ~awq澹[_Wajo;K繡ggM ʹ?x?A}[1l!b3=e?z6,ul}pkz_?9}j[!`$?W?߄FO]~@qk/*wģ}no_o?x3&R]'@7BKc8ol~g]~\wwdw~-)B?Ʊ>~1tp43p`aB`!#nELKG2s3@|̝|kw~7e>3Sۯށj' tNcp{?TMX? 7+ LTq_|ewG|Y :d[r_wԸW,rujNޯ4ρ& xKڔsx1[9$[i$8΃o|?~㛿 C- *8l݂+𭿄.9kmW:}Ujz3A\,c$8 ͟(z- 7ap 2(v1EKYaZ[ .6Tg޼CD$}]"5 !W-o=~e]?X 3X2o+qH!l:  ڥ'歳2e??;شo@W@5 s`NŬ؝ W0G2o_>iv{hdߪ X!#Kb&m3BW!.H;.oAFC³ 4kkH,Nz߿4L ?"Xo 3t U}xHz ab7WHss5$bb!rc<)r^OAF:o9;ւ//'fCB}GY7ksB=>ek9ziDd~¼Ɖ/|?}4Vkbȹzj`vR{iM`-oIZiCӄ~/Y<Sw/C}G/8὿O IdIH;`o~JnV9XLBpSmapwr'W7.R,| vտQ[go_}G 0o/;P3T!LJs&{Z#UTm@Qaƭizߪ}̒O೯׀Q1/>g$~z@rB9Xin>~տ W*s VV[>XԗA"чe'Mm/ڟZ#F#_P(0 JXȚtC8֊ZN3LQ'hƎcCG rCѡPyg/I8q)[,E$v "/l>%ETeJ_cwHSx\;?9|gZ*n\S)A⬄Fx_M$N[y7?^McU S3kd4۔&0NwܔWEq`Л8lDŽ')/h…w|a{Xt0e<%~FOM*/ 1Ʀ `9.~k m q<yԾ @ ZDD~/E{QQM;)_~?{ ƀlp$w_^ڪc .Ij~D:q@wY7??Jmkb@=dzF:t>Cx BP'^yʷGWNՉNiX au";+KjVwuq&X4{w~?cřuΗ !Q ~r(GF{ĮW:Ÿ"OFI0TCw8deYǮؒJW fR)L8NdB"I`0,}o/@I+CH|70~s5c9H_~h4D$Z@?6O#Gβ`D'z<+,?TBg0_V!p|(:ٹ}z31N52cNQQFo^1\qO൑)Ļ #:RĚ3?ٷ~jV)uڍ6L1=_iϊ]hfom SIڡڋP{4?O9W ڿj[f3/H8tRHrP4Wn% `pSgeI0PBW&rPUjA'X s9<ى8;,2"xG7'MmN! :bC|sLʤf ڭHjpDr"$юUfiUwKlRF$$WQ"&rM4y^{}'~ƻ{{ {kֿx3;xM=%%8`Kޚ[GjA]ܛdx[$App70QCdQW]XaYEɓe߿ u;`0$ WmR@,u$k17  `e)gF/dqn1֨/#ST;*Fet?˝`;/d3 k < s? /&({pLxaN.aŅkhmpW[j6w+ $';q{P[4sL{#qw%ŊK@fMRZcDd qAYt`C( #?C+[Ӗ gv]koDg FΈ<838|Bֹ\g= ]|p IP'L6nXG0{ȝ{쀛?,*c7D=hg!73.K_x&AG1w~ܔe\oo+58 4VFU%xMbMsg c}ϗXw) x/zݳ`4M:=1*@19j_e4L-mT,~LjК|lj˝rETDv| ^HGghhfi&F_2ioR4NC)S;֯A.{GfS= G}]Ppt@C.cO\&ٌQ |/߆f,`s>Q%cաVzZ(;r[7AYGW`Htvu}9y xP?f-.">ocY`.b&;ƘI INb§K2,rd}n_}M߇jk=Ǩ}5+SYm}zk6L(1$1Wg1Ouq"k76!Ѳᄸ2ٕ}"lX_Zw hx?RT8f>禋l7^ oMbM | d`(Td-t\tuQ@_W6CLwglE;T SI 0'~,Dž|괏u) A U-궽x &h=P U%o($`%Ԙ#ĒO^`YFKشttI__"3;{sbW9E RM Իk`I5΍{@teߺr .&'o׿r$ xݚ~?f,a QT*A4Q Pά}JKH~1)s\.i'l4:>/wMBCOo8)'_LwCV< %) ji}koO%Nby-1s{_ƿCS] R.77?B)ja ?@qz7tP ܽ 7,H@}%H8 k/eKa9mʉRƿxoy eaE0Nv7Ix7;l!S($N&ǃF3iu]< ǂ!oo{ƎJ Ibݖ"V)R*eKv)^]9YV864[$OEa@Np(5# oEzΙ;)6L֒Μ9_s93oM8~PwN~;%#wtW~ƫ ;'?'du{VYx8!OO*'&;N>2 /&6$I<, uwp=?aEb ?.^ԃPO>|W{x]'esZF q?]Q_q9 pxٺD kQZ]9gӭ@hV %׏e]ڏNU:^[ҒܒK"NSAv^BWϣJs|I,wm%;A/vst1ߍvՇ ϧ'ocS;E [MPGG_˷чQx*UzWi {QǶ>xb'$D8xy/]uq @*ӿ{ G^,18<~/N~[%1|G~;wL'f~nZc8 |#;KP'+ԝon0\c9CqGO^Ą[N_h oF~Sl/Mrk!+ΉAf )bDŽ q[R?Ȁ-޻]XxǯaW[dÙ~("w<*w}ɹy.ӓ"x<=MEfу_?xbQSCKɓ9}G p1vJ0Gb' L7En|,gq>_ªeHoVwudOC+/` OR~\M \* ~2W صq QugWAFgxiwջ4sf$VojO MФʍ9JOO}L 2HL]G=܌sV(<-Uzׯw?Z~ƫx2t]I捾r1 OqQiE'}g3weey6q\ά~m\忚?9mYδm?.|@k/E.?s/XI,ag$5߯}`{f28[9 X[b,2岁Z;Vk 1uFx2vlKcgÁekpҮ2($e5[ v`u]Y,R`5[eRʥ|V(L䶃Uݴzjºi6u-~ݦT!銚s04bst*oX"NUvJfe1Y(nԷwjkղ]#z{|0s I5A O2\g({^1(A`7GphQp$ELf&F4ADR52!]|!i9@-j:=nk![Fhj [NstDlɤLPBx²?Qe [΀GG #Wvju< XY?g56q)%8gAQ%zV @4pZfJrrS?'I ۷أ P{Vl Xҕ%f״rцNaJu.ݵWYmPe|I*囅g[8Dl^fKսQrv *R`TӬPBFmkT 8nke(;FDeVfF%?[bvZ.J64Z!W/f+l^+F:j-ye3QNX2V.P/T\ I%M1ͪ{F_zr+ < `t/ԡ(anГ3`y^1vUoUkZfr]5*7aDnbJ|W4S"B[jV(VЕd;}G O-xIr A#ob:kx57V)jZaģV4YɸQ,0J9ì U# +TX R5Mdɬlf U@9ZHa,q?Kvƅ6kżY!W{h.ё[ƕTu O΅~izlsnmR<[m)m7JmfD\94}^ecvpC ;Dhv`8ۆ" k 0`փEf5HKr516Oux`rE!>t~\1Ydi`=>X 0m B1 . BLbX5( 0[Ue7܊y{r喟6>9:y* fOmΌؾObi$ 3^`ߺ5¹E;^AĨ;tg~~=,Ӈ}/Q7 xOUY.@/E;Z-_smD>AlQi}פȥN_!-we)(-D"-aڣ^s9+k̕.QvɋB&kXy64_ ׆kC|m|kCb9qRн<٭avBAg(#>>VY[2Ʈ "P =# n4R~cG>:lz.U Cݨänt̃ƪ7A>g֭Rv،kLzR (YmdJ~%Q?Ogi/[N;M%5IF(Th('  c3q# YgQLnmuJSu˂ݠ)֦ydwp6ACt)Sl pfa9=Dr&NG^`pdhJ4 9muRSzj/o}X=43b+WByXJ}nkZ/m*.Ű0K(VT|-N,"(Xek@7Z$i7K |9k_¯),lj"B KLa% qe ޞQi76_[z5Yp7y_Vq,zFcPLMh͚%i`إ{ Lۯ4V /O~I+,F#Q0'嗴V; Bo(H+77M?3d0}+en8'jDܰ A,о-N&DUpQ&v~Eyڝ 1⟲ J5{=)dm&h-uADjȪXܓ8[%Gel ppƢA``1zq:|9dz ,Ns<a}]:n*%{\"=u('c0fGRdeeXu.A'nl+k&_CBH.RX?!K79T,"IO=Җ'H2}5cOQ] i\f\69~r~L ]I[ @ܡcGw!L4G93I "ю֫ 'fa@K!ȁ/-RL2}O:K=g8S4t1S3LZCӰSy҉*D@t4tizti! g̩آSxQ)^< j YhqZ`I^!|w˂85_X*kvMSWaBkv詪n}a\luFYпlIԋD>w9ń-FJʥ%Xlj6RE5:jGc!eA#B5J#.T/k81=QIEF6Xz :٩b2kfXDp+ hW,`Jq DV&LJ=ÊFŨ+g$N<ۼ+@_df,92"z^UH3MEsp27ڐcߢ2X8GHJ"bG*B4}s+kͭPL]Zn>]#p ߅3'V%DB̾'p#g2-"{4  t2ُXl|LAѲ]fd Og݅JRuE 1^:ds€KPrw$y&aLh&Ir] G`R*)! `p;P59nJH)c}rr2d`Ha(&_/(nrpajCZ"k}2Zq7$M*x~r3*B}[\/t71lZhu("EVԫ&sa_#MMmM>YŚnتbDr]жϞ7ɞώz= Ymچ'%'䦏葐3J)-oN n"x>g VW,cpSXAuu*c |8Qp֢$~bRX膌 wt=S$c8z-K}B@xIȽ?}/ЫEvb4$b%z,gKfDaRSu@ang`=s1ԖVl+rd+Z^W>dTIF`rd2T5{-ʎQbiEL CRX`,=9OZ&V˻9M.y&H/9`\_Uk}@&Np2/y̳M 3T'ȳVQ1Eg_0kQ]2gV}kj)#> =}<8k@ ~a┆ -}SPϘuά_^_ ]T>*K~1<ƶN 8O'ϓy7'<է]'qH2(g?ǩ>GtrJ$` ksϝĠչ?~sOe7M].Spve6_Ƹ'w$imje M[ nwFn9_HgZ2]t ){'큡* УҔ jՅXVvnXCpF] oǣ JKظyT9,a"~]e*cGRna8H|^F7?wեL'0wzV"cH쭼%$.PJmg^|ۇJmbdEP WYLosNzS,ؗ L4}eDkm9sy92Wn4m2^}^ih<ٴÄxlfP$|Y8TKɩay5e j%/X@s:.^LpYf$k]ud8`Y󀔾L`4YP= o m `"DimCsp^%.d%zt` 1L"*Qd}Y!v"mı|RCS3<22D=,AlNvn'A?S^33 z :?u .N Z+3 Cde% }$i@If"zƖ5s6Mj:'Gd{D^v婰PyVfNʋU5)dz:gڸWP mljm AN•r<x}^¥|~7֤wg`Jh43FI1֝72 [yYy"%Q;aYdӐAK[K?1xBb՘3{P&U#h'B}o7w6-c8hO=;Ex4Ll+8fԛd9u@~Օm10P8͑[xjc*g&t9ŔpdB͙/|Zs|6f[_3lgDf~bWI^E[_oh}q?TI/lZ_|?E5殃N kxw}]GНTL ck;*BD8:DMݝ/ϱNKs䙆APUsG/1Aƹmt& %ʣ@vy~R L%\)DG\&GJs]DSrp^k1<~kCR?DdH0_)SF|ɷuh l}I6{g5:slb:Jd$W9 hVLsh1,Kޜ*zcw8hnDtD<`~76o;VINwܛ^8NgZ?gMi~DMuzS~[r^94 gnǨQRF4;̌3֨g{&qj[eƱ, ͗s1&9hOsZ#0*`qH>niOC N0#)ZoN_%BWj5i7&G:sOH=\ZA>B0yY9g󔕳9ʜmè9N$+3:uQ80R`7Hq}ùB$H-Q-O즓'*SzIPI|ʐr"I9gQMLS/hw)hv_}?uU)5^X阊'hs=*RcUMmΕQ-N(؋5oϢt6;o9ϾQ-&ۄh} vOP Y ~n݋гᇣ*nTE㧙x<-(}2ML-XivDO^%7VѸ MR|㋋TccH>og$~yZ RL)7_3*@hN<\mNWf\8S㸖6O/jjVQy.{ E`֏>0GNX$1o>h)uyVq0}Nb;qkwcC3`[O4ˬIv|T|fC- l|$t@=J“g%ٔ|l 0'O멽GW(9VY0z]` &fSSI ku2v^v+'ͱS/jP;ID$*Q-N+.Q0R+հNIA_`d,.ѓ!´rvlmB)fDLxSg-}=XڷwheI}$τfw;7cnTWLq#!p3M yįBs\̙S9j>Zr j،7$[Vjsuh͈ms6]lFlĝyP$ؔ; L6Sܞn+,rz7\ŐQsX';j3Z9{-Ԗ4@# L&p{ f\DjT/*ɔ LG֙v,&L"2gL=llG&q7&#f,FS Q-pH5s~BHI:؍r;شTjS6}64hErzIBws`kӊBU4Q>#em&(LOcG=ܛ8^N%zب"E2Wۛaە$sXbwmsyvucG1b20\m ?گ:^,S(7xs]2c1@Ҙ˿GAЍ[D;kjo& !#nr|t|c tv~Ϊ2!-ګj3fc3Y5?E{ -Y^`T* E`0WۛMaIr*O'ݧ9ߣ[4]7y~PWj܎J.%I{ykRK+c4xjT9zD`VlV !#ϖTQ RG!ۙ ]ssJm޻I <56Ajleח~/U{l8B;N xjU&FVZ\m㣎k owV[S=j?]Zݽt\Mgu3AMN.ݹɥZN.Uo{&8880Bd~\2Mf9F8m6O)_OE#IluVS?(O5P~b nVKoan9\\i|v wmxIe(^l7_6E^QggCx"RzI|~^;t+Ц1 0,;n߾l3'5z8pwn؃ֿv A_(X[&7baP}pP4@{ ӿD5k=9|p-.NǽC_*۩Ԫz&@Ã=sX\հvz8=:xHthPiN`:"^ mQ#fvtLiDÃ֦yy5ګ+ /ZC鴮yQ^]_6AP;{X<̋+Jj"ύH2 Zp?&=?vZmefgB*YK(}L`@Adn{;a 5x zSݴŐ]IFD\b Xn70QocHZza(>"4$I[!0+z}5&7dnyil8ހpiV"]xӗ\nt<`RF5pްs= ЕgPVװ`&}zS#kFjظrT&QVj%(ksyk@{d< 9} ,Un܁#)OvU3jbFͽ5Qs8fQ(M@FgP͂dFa4N{p%NDY*{]7'X oj&އ=+'{ ?;xoNO weOAyFoŇe'7{{'QoNbUOvN+2vbw_P@W%Tʛ*"Эݽ r.yQ;߫x<!P)b: ¢nw;=~@2IU;<%ˌmX#hŕWDBimwM9 hq,v*P{x@=n.Dw W1:yr\ANvNeqP}zSx"Z5ګa=F"H2?jg)$*a/d ڞxT;yPHi?X/|N~ゥ%/N''>;Ӂ2D4Z^[A`oAih=FX|µ(Λ͍=ӵY&B@WUp//&\ڈ)lK#_\DRdSQ[9rlPn.g$=*ir?oO؈VoJ#QҊsL ]N8rJwSb( >[a.GFLOoD.\ nA + N+Ժɤ116_lBJ?OY[Ii~&$8.Y.}>'>xJR;}SH*$n5vُ70I%JdӏV"~V2~V~$#%H#? '? - @ Q;D"[c1d61v11iԾ.nm}z ~j CBaϬx2ʞ~qN&"jD/LtkCy,3ug":v`q:Ȭ94L`O8O⎸za!pE8xxg?[ B%0"`r8f F) h}lAs0YrN}l&u`WKn0ɦ@?g@8$ F7McQ~QXO>zhp N)\8 p.…SBH˽ ׯޠvC:3\O;>4J?rtT=VBs<=G7D|<"0"m)||>%Kr)0ʯUkw-;@k_-N_>/H{'s|(RFLACA32rE>/T|I_yth|ۿozDk'fK5 g2ÂASSsf6b{F60 hOtk, bf'Q˴ԧOV qK Mܱ9jx7U|hˡ=$XjIx@,ㆹ8=UZc'NCյL_ӌmt%Y*"lIzվ{m;TʨP\Ţ\N.THY1*/iw~nLPBڭ~%]d+p&\~u$%jwmjeנ,*J<\'ǧէ;hF J2L_'֖6< NA ͮ(/66VnꗞX&%/q:_Nm ׉@Px7Yj3 ,~}}~qS]Y&#嶲Pqdsp=ԁqO?J\T3_dC'`23$z0>̑t\3jTgF3r\oTL{#βT9=+?U+S߇tmtօuŊ B ZRujVw^}HD;%b|2htiw~G3OTB` 5g5HeګPߛ3ͅ]}kKZc^+Զ8h8͏3_i3q,w ދs~M*ZL WJ/ќmLChޞq9|Pʫ cj.9f`;GL55xHdn`*{GEu};닛 T˞+о̗Y_|-ܼ. dxw}]GНTLK) l'!wTfC9ptL;_cS%3 2w7fPUsG/1Aƹmt& %ʣ@vy~R L% 'r *.uOyYho'ur/~m"SG +wj9HO7.?2 2>Atߛ-=it泼Okt#tRW?(e؃dM[1UϡyGf=Q|LC8r_,ߪ: FYPG:[G'&+ce<ÀG,%/ uogڥn#۷s nT|M߇3ߋb,hw> (s^zSq_+)&+%-IEM1x<#c9%`%|t;So5}l++1' '$3'8iϭLj$j<22gIbVEx]0gqnh*UYWk'aHƔsTxn'd!vtX$c3O|By9vNqocXx7^=LXM*?di>>]iZ(?T `< 7-T4,O!OҴ\1&J@#%e,DV+2FFIO`%f%9RQ{j0A|8d4=WLڠ {YJa<-FWKDIոW{)Zf竿WZ=f-MjT{J8d63̊s'jTb<47qQ=n@T4|%Fژ9܍ƞ> b0WhlZ>7/^Ǔc #Bx6̑阪j=i,4Dݽtzٍ?AYlgXscBFG2OT,i+S4993iwO}| 2WF MZٮ7?.OukAHr&snd:j'F׻i޶;1UfL3S;Z=ޯU<9>WoN߾h4jAuy/wH@3AxYbD$|{MT?7\Sa}Nk `T(zTZi|v wmxIe祍(^l7_X^/oGq*;./G䳔^h\}qgF9͇ KŎۻ﷯"̉2vo^+䙥.Tv@8NGP-f*U`s/\=Ž;㈁ ӿnamp:!TjozP})vvNjK\cnvsĉngoѹϋaX4(K]0YPw/vi {QD6󷣃L.`\H#6͋_C^^QVMu%͋8m^ ڹn߻a^]Q*VōynDT i77j{|] [H%{ B :L鷁a 5x zSCQugT^+ǿ &ZO$wЙl 0Iqw!NNNNO.XFkbF4: 7=#rXT.z8< !#]RAc$%t丂den]`:DPg{jxWR{YZ?E2d~Ր<1RIBUv^ =)1v^Nӌ#~%^.*V{S/c9i_4[NN|v]ehn_T$0$C^~a עP8o77nZN׎wd8 MP_~96;|CǯLYŽ"Sl;/?vƸHs 薻ؼ4<"͉=.)d8iͰi!)N*'Y@51[OΥkx^/v)N!]bBeYۭJ0 wN&H" \tҩՖ+Du cwK`NpͶ!Ln2Ei^79HTWw) W@FҦDl"hiC`I$r.r) FwX}UDxYcNy)onXONҾG\+Aqq1g&v8uUCzZ9#E;kVJZŀr& V) 4xZw%( ^nWEB؀0'%E@t~7'_@'Y+(@`Z*H˶tHUBbvxx %&4pۓ҆,ەғ2tŖx.KY)}10~#$Yl"2ԻZ]$^1%W}ȁ_}v_`lRz,ܸY;Pb.Y%$ƕAf J ,4f!owf%JŒQu3.R*rE"h\d#E6"]H"6."?q&]E"nPEHO/[*bMta<ƒsRIRW%a*Եr̵qכEI`6U\F'BHi' AUF@,䫌P`X(> )Q,We_I)s' O]fn(SeDÑN&a.C3 SG^]/e24'.m )s[ɱP`8\< *,ln!62#* N;:{EYG^X{ze6޹2%)vLML~+ (7KAE$Z[iyqf}|!ŭ򋭍i?7DKO,S̨%VESjq)-a5h\Ix@NM'Rtkѓ-F\Np=ziGK In J',t sY&>$6ⴿ:M8&>u+I.Q'F"u2I.S'NBT+5髎{PQo7g\bŹ߫ݦ\8+x;{r c:4n`[Ѐ01Ūʀ՟I#Q^dXK.FE^ UqcTE썪ϲ *mz4YR}d*yKNe.ϕr;?!x~{1jW-;DRVK/ܮz$Hɿ7.ץ[WFI{ %huA $!\4_ i ;nÈ/kPU*"cgăU\ _zDixpFORbr9=55RDځ  Z'4^Tu4׏ӽ#EgIELmP.MP'__sp2m %:aNF;QouߏМ+TOƀQd˞+/3kHoأX^(eRD{ץr ɗx;A+9>#0dɒPgeh7 Z&³{Q稠 >-(=Xx kkp:kFLVB3h^J("ZNǹ7@,CO5rT|t'*J~Ir>- X/|. ,㿟SoPL$GNP ޘUj!uJȏaW#}U{1Yι5E-U;v S0_EKV}4ׄ׸u+=U2.qii8h\VNs}(x_m2 mk&='-yZh*kNMMlH˖7|9VNor] Fe듉 U\H{C5;a!rb)MY }-c f"F KԨ?(6~`?Ai NDc\lko٧ ' FI3X"ρF#\__E"@[X 0wP>T+!>E84`!?&TJo;Jb {L>tRp~kv[t>*@YZ,pu,Zè0 SL^|nQhcmɑJ+v5DlqJ9oP{&JBnݔUrw&V"C⢨B, w`)u) 9DIL&#"xÀоi`j\sfR˽ovm~.]'iWuCS@-\O P&3 1͗P[ ;pdrw$bP EPQ2 qBr[#E0 "]h@^Ȅa@/گ]T^׶LJrELB6 X~+L 6u7KqM߀·҄ O/e5HYV;n EAtPpd mt {g+ZSp= *사a)r/h{Hb5GIM4a ,F>=aѿp8l! ̭øX1gdܝL80}lR⥣ӈF%Hdg~iٵ!{8W-%qP~:_qΣnj+HۙY]zB&]2_$̩9S"0[l>Ґ 79\oxH)*{ZRl/D)HzYU(EݓNٮaW}x(ܓo'?uBEЖil'޵+VWz}٧A``TF6T.%}!2b}4"qv vT<Q::vn`p>$:&>| tב&cj&p,D-%ƺ&p3Lז1MTaک.v|0Qf0\nп)nSZq,eZ(ۼSj2F1Lvۍ{KW"s$N GsZN,3o @Np` | 25E`I V{qW&1=oLVaE | ceOjm6<M,4H9\q<70*Mg@]m{3a F`Ŝ5kI.r@SQ<㒙Avd kFglYoQLh؎4ʶ6N㊶wA,@|`Nz&~ډ@[}*Hٯ.lwC̮PX0KrK0B"bPR[[>~Z\`nA|J:;>X*0Ip<#_i)t%p#V9(Q)!,W؋\")SFmg(zr"dr2 vr L hDz@ҍO/^-7wqA \Wyb#>&/\E w:mRmia[#@<rQ֒L@]ǚSZ%w3[OnSN,hs#3e;oؚ"Xڞv?st_i0VQ!Z#&eUsVj+烮cKպ;L["@D H⏶*)G 4@(W:xݡ:ki17\ǖ;Gj3!}NN"]0ըp95v8k86Ӄ}_F21TzuO7xp>T¥xwo\UGiS=Ę# D"$ϔKT Af42>ퟬ"or?FذMm]OGHE44th Y9=|'AJvn;?ȩl9\Y?RmDqBb@Uu^'h &x.2+.ˈokާSjn4.TA>[6QBBDlI"j em;|̕f=f{4S$4Ub}E$E#'kP ͕t3,Фw)pok#j/ ^j]xA JV,$U%/w,6-kFh3rڲ1nj4B+z]Y MJ梭KD2nkbV+bBr% 6Q(.֣ ِ6zP!(E[:)^{|, f^ @Y`J]cr!!"@ OL8M\^21]!&^DQ`]Z}AQ{+`]*Z*)= >`@)?` GD -CxFIah S\\g';S4Gʓ氱 qa6FĬ֧YL~"\XHIDhTOf8G$#c؅=% cXpDOU,G8fʐeZg4Y+CP]': !I)XDzUިޭ} `ѫ6@( _u gh;u<6T@ym^Y>ʒC 9s.ZGEF%lM~|a0OOSڌHn CC4b&ܱ Ud WYiv-VGZYqncBT+ [ZMY!M$gCbz"M/+pcz~i%Ӕ&Fz~i٦ /IwM(䠈tp#=8f0t3іe4mcʺr" Erp&T[LvP\;]Κ<-EJ *),ߦUo_}W^R6ηtgo]w0q-nlB/>5&"7K VfƱp7&YoŔN&{/7_B&tnWNt.佻];ŭ_w&s.ݷu ޶;vĮM]}.5 ݲ% ޱ+va7 v_7u]wu'wՓx)ձx[-sި_f80U~B L2, spt+өՖӱQ,[t͍]TNМis^X>K1 `7YÝ r5N@Ѓk4 Oɦks$ 8/ % D? H*$ ? NGn#_ qK3`q $ V2J;|H?MA`XC8&#Hb>I`8Iy -7a=O`8 걞CIU`XI -!gM-9ij#~;= ׯޠvC:3Mb=ˠo:N cݥD#h)ۭ/۩ڊ+a4O-TZ5(+rEf "eB.(;Ý:U!K@g\`v^?JxW}y9=eaF<#jx9,\\+W0 öID.au?[nV%8[- J %XLiܰJ向(mʂPmS8Kh#UYM/S)/tk IDy2dWu:Pxy, 2mi;fyjCȞV *%NȧG4<~wݐkDh($VkC:e{a 7 ]ʛٚ4 jJ8 4whNƫ ŸC[tg9ZK.XWᑃe\s%~}&-bF@ŧ6p7Ed/M@9OX>0xݵ&`cuZh0U L1C]{n3(orr̂ 0F)&-#-_CXͧc<|݇tʟ%Qmڎ6 6͂/mmO{M|mcU"Pꭕ<}>|+ ƣ"rz㮏VAvNsm/,2n̹7Lubu utz/CgVUv6<*7r(P,D[1%9s~NHkEihU?,kN|i(ɡ>m7__L]~P*`2q;ڍ3O1rN[fuGSZB5YnS3Ȝ%}}Gf5U#)F9]OfD[^꜖EpZ\ۊxsx [;;PQ2|%o4"nEi|V3iHOL|F"i2ҡC9/V\UR, 4,fMWJ +p4uo@sQO;` zn>K an}qzV۽*am/Y1 ޡ!|t|Y58A?}%Cx[?O/[-x"Q^>G*y+12eX],.| łb?p7~ŗ (ekPI;Vdi e~:BG.2ʎA](YW挐srm«1zŀ0inX|Nagۜ+ -kjEBha50NF3L>G4B61i*ѡ붵&y[ƺ&e\l?g:r!K7n&,RΌIb05GHJc,ٺz#ڞOȁtʔ%^6ȱAٳ2IγK_qD[[TSPnȫZ$]Hd jM]J)'TW6Ϭ zH=BpSaz'~aWgֵI!̤wPm$S]B`Y~|BaBtmwjl󌊗gI4+P?pIA,h}2B%9k ]E+rjR{Yds)/[0VЬ.K3Ov.ecY"c L2r -1O4o^ӱZ/%\~y))RԻ"-^ 폁:1 1#ݼlUmcGCh} /d`K%eLRdž%d^/I!YiE*i`&IML2r2[2oIǣBf7Ƀ3`b>Ň~Ơ1:;!Ew]zEw]z?] ZlSizSwo_E$??D5kR+&j_)c*Ω-9K:@Đď/ %F1vv!xc7Ǩ]s5`\F3D2B m8]V_]r6:Cz{nv쬖2lc?Jo@0;qH76,Fi%C1/PAކ<Ƅ@`_%TgB (MZxs" t\] \mjiN?ۖxG0O`-- W7 ц)S }fU'ϋ_OagX+wjkVl3Á='|o6vfnZI?"8HczQr|ՊVVZlm[;EcX;E4?kb3ǻ7TzxT=VK #@Ԇ2+Ԗ8HA_ώ+G4f+ѰK#K+cϪkeq\MeX *nTFQ@37c `2kIsbOZ(_Wgvw7/pX5|q? BH /}V tw"X@c4Sy%'@Kם 0i4Hj4 @#\w@A) Ɠw@v1s!.wDXx#Vd %B6je7/~ӡ/Kj tyZP[|;t"y?93)c}BФo~;dgТN`(KPqyPT&&/[CgU z8^ǰ;|rSfyCm*ֆ1$36;֣kϐe0z~Jk{Q;`[ՏAo^} xۥfgJ"6WiTaRY&2jG|eh#;xdO) rϪFZ4?6o}o̗ 9eZͩ~B Ʋ!xc8/DOw`:Pyl@"_?k #HwyYach4 lk(BMBx#eKInD>0s֨\İ}O<*4 J:UGvO9q/B= d%C| g#7=d'a 0K͙L43r,蝤F. INߊ;E,$U0aDi'? U9&9j %85WndĥT8|,_mJmrHDȐ{e 6He&Qj+{+_>%2?wݮ*3\qdgE#dCS%Y* I38-r'NVfS M"mxCEZd^R&#Z4*;Gt(jLN8Fm2a2E=f1;rв~ʄDpxhKe$ j WM!YéOtv\%l8賸T;0(Fol$a:rb|XA2KA-/8W.8nzbǽu~fZX-_/VjjD0h#.h'TrM[F@7Фzo^& [pj˹T벬X/G'qE%WmQ2I DB~Ϻ-x4ΟޕZmN lͶ=~Bݣk_(_ߨ~*!+M{VpJ؇uY/L.Z uȃt[Ȃə$w_㢖6@nMX_mvVnݏ_5`XjsnGŕVҏOP`$͒>(, 1w( RTFd YE ]2'BPgen+ ה18 1!5#*g&[ ~_t,CՌ% /!~*H)XRrI"DKS/%'Ē /%_J.\ti>}@"KF`K.LT)ɠRr1G/%_J.d8)hҴwf \CU:]rӾhMO:(ODu} I 4_#,3(>C)J(~/h~itJT'҇ofq/p?4z#w_ҲDž9}9gzDm]m^vWTerIy3lwZH1cT e\:m\:r:A),q+POJ}w[Ѕ~ 'Ǧ#5w);_zܣ]=4 i7r9x`n}juwX^n5B"1[H̒-S$g̐=L &R4 ? ķ>3jHMzyDjU8+~".b b b b b b b b @~}d-࡫>-[{)Jǽyn7r[5Nt"WLZ|vf;v_YX,UI5_0 agiÇZ̕G~|ڱZi/d;$>a+~ћA鬭N+DCz:V2m_h[sb8O?T g{Ӷ1&S*7REyyω+.p`#@ymOjH. u]YAHmőʂ;mQ}&:>8訉wG6N/}vqط2=^T}S^UwXpWk֠jH=&H9ۥL߹zC˶^)v O7O7J}Ozl+L,=1O9Ԯ_2a}V\:7*Hk+\-s{~Jv _2S]<'V/:ϗNo֖GzV %׊׊X*j4'KB?}g:ƀz}WoeXuƵzs3N_KYZ|wbm!n6:k k=w%V\ nX:0ZZ]]]]]]]R:ABq;Z"h~>;}xwYZCM?9A ܋6{),'^?᭝/g?scu _EhMWh$g/y&o@/\W/ jmx1.ڭv@曤ψgy^ǿde%POGK}Asٽ75뾮u[ٔ"\H9MẆQ&Sʄpye4 TjXHS,Л=,i(i#ϳ )vlD?8Ipp4BHj(jqg| dN6jn$9HƄ.'~7 =@K~QUaDB)|o~6|b^w\>.?kޖO6fJnLv1U/ЄvW5W/M'Hؤ Gs$T0#h پO"'Q~1,ATiΪ!mM$kzڐD ہ%FW]wYP11?"If연' EαG/3X_*o~ej?uMvk[B/FT˲WnS!EY.}[Zld6)P(ː(%H2Ƒ?3%DVM^#` qvt?ta?ײ?A-Q'@QdレpbS|z쮇@)@bbbbbbbXlJB/7wvۨ{TiUM%U !:x4`wbl#7ڻSvp+E<ӝZ=mǸO@[9pT*'\Jv*QAe_(m[/e~/)m\B<}"lѝZh.xagv)굽!:(oOoٵjl&Ƽd lg( :jbӨEE¼F"X+b D³7Ht `gjKD4Z5ifb,Քd~HiDc2n>7&9v-+]_ZǾvE4W_/BGqs Z@ =KI_H+=8\á.x@q幻PƽcF;LݣB[caC>=%@a𖹏KGVuUl c"yax!$#Yo),ls-audroUz<ߨIFq #nQ5n%nF/,܂c M5A1@a5r ;MU^΅zDXz ENK8}B<}$4dKx=&4\)#{<)KWj}*u= ف-+y9RiJCAX'個(=BCm\a}lc^|7} kx;hD4~SOy (BgKyԓQ> BEGyC1Ulw۵]4Jy&V(fX.`9&ΟHff'ҙy]O ,tI lQ0;mOخ#XbnSWN{ e32s[?@O[΢"?tMЈ"-ZRi@N,VX$hRhUiuWdSXK73Ӝ`>ni?dl[hu9_e -,[dܐ_]w4qx\db s4F|o~3W-,W#6+&bV8B~%$zp&f>kLeɳ>6܈0rh'}2E\Z2hcVsf_"A,I쪼љ,PY5;BlfZCXjEsWsIl5UrH VaJVKlcLŒv8>1yI |}qz/>Aʯ˿SF_gJx/v;Zt2E+Q9/Ѫ*k;k!+e֖[:i$i;8IxSUdYсya۽ʾfwMtOf3qbikI)a-CTe\pXg"-)%k_-֋W_S;o܃H#>xUb-̩mRs*Ҙ VVRYf8Ny7ޒaq"/ㄶV,Df%*.9f˘A2}28e?|7T⇨ڦmyDjSkk%j#Z;=shxf.eYɬ?2U{ܖr-ҷ\jրnUu b`/dMnWRsĩ+uRb F%O^G)#zi=}HHd@|D%Py!NI7IJ[(>41zLSi  iNXCq\j.lf[bclpJ$il$uNvфfN v6'˛?8{LƘC=/X}16ՈAk0~3%9V_L [OX`}-y,y,y,y,y,y,ywx/LdPn_׹>ڴ{C''%Ο(EOՎste.z| 3yAcf h>p"~U@$s:x=Xog!]V> vbW_LnJ'g&EtA'NL8{fAĞN S0[ͦĪN.{uObo!^ ɚQ["\PKȘ9Ex͞cqYʖu:hJf&UY #|Idϒ -e9 })0_Ax9Eձ@&Я5պ&xib۹"}닱gkio__~VDei n~7Pd`l#hRa Mb=ǡEG5hHHG}rH^7HT$eEFbuB@S0Ķ<=~;"P&OE=ϩ5;@ǝxͱ= =_\f6ɋnYYAӬ;[ea辚Uyׯ^fU "-R9R\(ļ[=X%H8Y-H(su %k 6gk=p=z,Uj@|e<6{nO^Y~ITJ3~Bc^Avzj\bɒW`:;p  $ln;2LR7Ẓt#`[ǯ_y<뒦._r?_h~+mQuS9*'}|qǠZ^|()d(b/YRl <.nX<ݨJ?z'B6| 4K۠zO]]4NI"?Rv!dEl"<8ȫRmtĚ-Cao&lԇCuͰ A3]?ۃ[<?>~/Û<ֳQhhR^lw[-]e qx_0 ;'uʛϕ&Ay{|Ѯl?()ߺTDyă4@9˪a,-9>z7C>hg"QxY{tm:kSG=қu_J|q-nKS`y2|H*S` |o}R?{(Hy_QCcykSk#tsP:*LE(W4($dTKY q!6wMXf֭Kv_ө%z='X`|WYu -mF@d8b_u^AIvKP$dB9$6Og(t=&bV rpoArR /)X~5}82xocWC %.S^bMz:lfk-I+a+9u >Y4.ݶP-MϻZ%g.-c %(BktŖQxk s:17cw~D2%շJ5A`&ja_-}2u,9/fΪb=_0EkSXYbmYiBA.*|dhIVZXDa&=_˫| fgvF:a3ɨ>u+-$N^|`tZ,O{77|m:ҨQyQT aJ 4ts?ܑH, v x*A%(aGC># 1oobUǩG|խE]zbiTLSEg2UŔ2 !W6 `ي6z㵮D+~4.׼ȅ(J*Ѻwz]=dZm&zPO7D֜Fl¬nk ͜ XQF( N{.ׯ * .kn4ຜvT}w"?$P_1S^"gR4.F Nq8DiJS*ζ g.[1Y+0'5L_n2"kJFz'}?[7覗RsR)老GQ*C[ %O҅#.K_Q@MNX{$L]/2~GNOЪ>yRy8H^X!YPaX=|[GRС7Z UF7 u<}` ;* .$Y=!Lْca.#0o^yu5>ǣyTzv3XX(^{05܊Uno<y|._~,~R);| /JsuE|^1o_~ӏEiC4դ}F75z(yzML{N$X 0dIw||x _3H MI"4DAJe zl_ dXAd28c9#_#Vt׭է_ν_Jn-¤j?P \risyf$]Kdr?Cc֠q{v2 k<0'rMKѐg./mG!] onxy yt8/OgpLƘ0_/#kV P+?bgXYW`yS͖>&PY (@6^L߱Մ,7;hI[T\WJ[4$N\ Q^$څ p.X `,\'wk~^uף{AZ(N;_fl(JZ?Wx󾺏7/WϪ7<\l)A ?`ա| i'*?p@7-Ti0T V:L+gwy: -/=}RKHq"YJaBW,=˭m\jJ\o9x `:t['3LJb)>St"0 : 4_ŋ(.?OFJ%}\[>$.N*-(4EW;-( kBc4kw%l5{i2rY:#wv^j'_ɯYqN=vN"/bk߯~eP5Yh泌VQ+_ޝȴ+#$PH?X`ս,3Xq{9ȥwo%,ʻ cx9k_\+a${Bd>|7J[: `\Z˲X}f9}E Jqɭ5:톇!MzFHF~vAq*i10QKwx<, .`x56,ts0~@Wް{aEьxxQ0Koa'90diE~P#FA?\ =7 Mo! ΃O ٚAq)N_i5 Di!׸L:m<~ܜ ]C܎X#QMl{Dv3h7G$W`s|jTaj9QNaws@4E-zRh9?F@þ{W_4֠jez\{~R{/giȉU3 _ 4L-0'12J@tIL#HJxqD;j#@3D\(oM>"Ծ=c1[d`bUħYQ (* "ܴ Ew ?4?S͞$nȦR7ԭFUs J`/(7(r-9☞)+ c㿛/6׃/ߧ,/:;s%Pgzl|lƇ3%e:+hbM?IƋ?6b,%38NbQcBBcgBc5qX#1#DXLJ$,Ha%BfXǐ%"&FfX2,qL.,P2I*В &3GED"dx2CI&̰(3B lX yIE>+7h]|f=(ѿ =+dDqҐa≳/#5Pϖ?v 3Ή *%.Ѭ /-DSZK4)3%Ns]opqϝzZ?nZ~u c\3a]z) o|ECJ{F=0Q\2N6Keɛӷ\)Z15b50(L&F9ՆuL~; ܋;[=@ ^FK=!` oJ=wT~|MX11X F1m VE 0Vn1b@SY=(`&ekd Kuc (dhӽ5Rm:RsRR.Y̺ Ulά-+7]^HBh6@+Ny0.۷9WͰ3h"5NwIXC2!f8 :K=CZc΋3 ;No;7NKv oD`vOeh:,/;G^KbrB fV_]Kv8޳Ɓ)/yPn P GIKF-Ypn.Ӳ'T)ЩNNXx*q(ask7sueGkuJ%o,¢@*Q2WP5 R*XzBj,[?^|-x3,&,M`d9_A8aTV*f5~%1u%G QsW.Q)(!6S,cHV$J3DSm}dNB$MA4HfЃ IAa0_"=1t oB 528Hnf>K4\0o!3BM )֩9n*i#7RvIiH+> P预J pԤ=|[WbHSV땣#E"|N LKDNAڃ򍶩& }nY*]ɫ~-L7>f:@f\R!B6M!1q?^]3ź߭NS;# !ZO&WXd_ 5z/ 5ƒV2mXxC(D$S G qʧg a1xA6%ه#Xlo}Xy<%zHe:,Jm7<4L}O׮ $dgNOϡ{J'8'f#+ a@vI ԎUfACFYJ,% g9U0,7K99PJM{rk.qH{1=Mt7 ]6tq!0׿SqdIܟ[Qnw<)$-ReSu=Ό?WLԌftC&3g2 O&) Ol#|2ڤ1V60B)$>jƷV!_td ~/a#“+4s&!vh$kĘaJf(j܏crW{yRr@¤Ø5&3M|7O'52ᐌ|s$)&nG>p U46ayxa^~c# {m>3(MJȒ[݌i\AhFBdqEo"Qz=HSJGOW <ˇ87?Y[d< X$o~u? bz˓7rӰfj.ͦLә&9 5~!.B`( lbjeGyiYPA0Q41xeO.bΙM 4͌ZMPLQ4P312oV ,HH<}okaJD(Ygg2_G2F4GU'9M,;^$3KmuzQ뺼݄Cát#$E* Nd!SF~L s^|^,//?gmEݯc󻯛qX$v_$v_$v_$v_$v_$v_$v_$vv}DyY=t\zjYz:(8"R`"z4zDaP4Ptx0K3M; ,ɾd:D %# H`H $ $dXR .P6MLB^ajvWEEx~Gq)f{9 z܎K2h$i,hj{nH|_~;ܣl8}>CW*5+Pno- 7iF <wn3#sЪkmߤ+=r<8_xMX?:Jkb#]^Bw;g߫[N F PI]ExنUf[sC"krCǠT n:L]")2O?Y9Ӎ& 09rL9qwIbonmb;9Ablt3O E =y%n'G}G^x,]v }ihs+tNi`4.PD)CDywr_7yYg\JcVGngyzkJiw?S`ҝE-o,-`# gdڤZ@0FBݚ恊 Hdi NÕ:(i[Ydַ@ڶ\AF18 sC JCWc0zh͘3ls@SF~%osQp,is=ov_P52JTk4No90H5Ny KRȅt -Q=/ ŸQF龴*4hm?3ttc8p!U@59]i&3eCI)h):g$3QXWvn9q/ip#6\xrp_]Or,ş%njh9&=fr(޻w-wo@Z$@^| 6͚\GN{`Z &0ҿCA.=i#[hN#ŸR@Ý~wժ'Ϟ3a"BA簜@i5Pd䲧Od-M_T5q* ReuS{/ʹNOzʴy|sh< dܤlwBU9ps}y0Go?@  ݇D ;'=ЩQ']Gi`ҝ bwFW] l#D QJGg_kl{)Cl}"6t;+ّx4%HSƿeEȦLZa&m`^(aȖrgvw6,??OYN y%k!ݝp%h *3]Org ]R,%޳j$k=Dy[YjRR;X2+;K,%ܚ|VtI,%d~ɭ,% Rr7K^YJlf)m\YJpfiqqtonPupg@$x̜-xd4]UZ}P>6W O4_0p@./ի^rӔYOqeKЦ`ѱ5]Qu9m]X&DeK{ Je; y/3L:~;wݾSی`@'+(ܰjTZ sFp-fߜ")o]3zfBc೐<}nc`{ |W_3~ >F Yx a._^濯YW1xj_NzͿ^N^e~fV H矫 D[,v<ZFme d!]I'~'_, Brьx)2xTkV+G>l`XlAXK ,D,(%n(-55.`>/[OnXoAd ~v@NRen2 Y*FvA eC7g / )7J~,4(Otd5g$Jybƌ&Ew.i~&3!8ZP.FV[r|s!o˚Ҷ$tvqwri2nŪ֌Lp׉߮e u kwl>SNŁ{&ook"򾦱 /1ND_ 5mC7iZud$*႓h1苽L~L} 6ǶᩤM՝l ȷ SJcV4gNƐC5h]cJd+a&.7L|-MMejXͩ[|25wL3[n\|}f;/swEi=wqI>fw 7Fusˉa'8-HDqgݫ &[OLCkTeRգE<|ːv4'rrϲ(>@H6 #͏vgKsVh>&(4XlŒGH KM1詣b:oKƐ`i)n-ݎϲ5S&ncl,|/v>-ֆ^?yob4smJv3: x('tJH[Kk6@[>,ga TB\,mK+lAAvptKM*3=96\ҖމǾޖqj/]ccEP9-\+f]6kޚB52V?kp^8C$g~ 2ALzGɠ+9QET{r]bT Yrn.p{H}))jEh:5,N_* kV/4+iB#@ULӈG:M/e^{̦]9gW/ih:U7Oiy`^ח%Bq H=%dxY]ŝޫee*L2||~xt3SFtNPqNT /bu#81ʷN-6g (7Љߜ֏O&=?;~xr0onP$Rt,3mÛ_ ~-~ix f3~ ?zҫhQVcV`0Xw%8!ÇAMU4u6@/;[^p՗Aa7xErx !aNgPRF#c '%1APb}rz])s΍9 X섦FxΠ{FjUKTnى_9˖q~<6 t{+/d%b.3߂W6pr=$(̌P8\#2qK ܸEN#|._R'h& MӀl/V?rU'r^*nRq?GXd7@.n\rq -[ Ƚ 35ݭG^)"Ҿ getP#(jC_ 4 G^([U>cȑP2ˣB{!/^L^:B2LC, #.MbB hn#`t$w4J 'sO\d{fIV47hxwxeU!|^[/| [X_gEQN_߂(+ذc`gt"YAYȓRXP}Ry(i]f;= `].ӵLwQ!x쮠o(/ZWAϠ /,v1.Ah.{ʬglfU?Gt6֦RW!fD/K'qh W7yZRi?&tMhfzL=Kc]1~vuaʔg.U}!]{N/#ج䩻5 )3x#8wǮw"f>RY^_G7Yz6@]hؽ^G==ySbB;K5.KyZ(URkCq#Cv}tm&ʸ)%HgՐe#X/; }WógP}пYBcY | ~3Vn UB pі@ǒ74 Q%__h6Jd1$`ASM%|8$v4g9~:@ΐVzծK 7Z}b~vlB- jւ( cX.R4qAKb Xf\$&BrfжBvUNm }0j;)!#7 ;Ř Y<*~- xk)PFe?ےFHo?*KcxCܻupk`46<T9^[mz`n3D Q<"lkfƩlM h*Yqe hX_-6a60GfU/0LsX#uM'x.EwIi43MZ;r^0%/RAUK{. !,>7 Ǎ&MQ;Njp w],, NGp UXYx÷. j];% jL}ӶO;%"mF-ֈC&r Gdsp4iF)fkIu<e׏}7p( \g?;n `.b,My*&s{ﰩ4/o]Ӹ`/!Q衺/b Z =[|HԠ k J\ iXBZs! u;Ս)wϿ=|q;52?2} `VLzWE#?()ۚEB6d_nFn_q xTwj^ZB|3I\ķOQOG9JO\h>0o2h3Ys05Y*HY߽hWczWcm;rUKXW͉WGdO,˻9|Ǒ<1X/uq&~I'4JVFSvZҠ0Me'6qHvsܧtR\t6= SJ,7J (B䪢O6ёF$J[1 &w67ܗkr"𻅚-9dMtO>lI!dh58LSF "$f l}3jH7(U_5?Ibф֠n]i0ޑ.5ai,P)d])o-k2Zs즇TYe7{5(L7l6g2Vo1-&=E1xА0V'bPLJHSҎ3?ŹyL kENT c!pҸKps+z O%b^D)*PF Sd΄2Z JD(J@(Jc.>zi_Qz] hKlrr/>)p;4>M 6>^C]˟OI(N:vgQ5e3iMC*TT>T" u?Y6H$?paBXvH4p-#aok{$dgt%ot dXHP^8h? w.FEr0JFSUof{CAc,ݎVh)5 zyˋ[MhTD s1z!nzJ䐛6JF!o5D0omz^ҠXP :. o%XI'^=hSۅ}4 e4p3w }-p2spK94kwjͦKg8d+[T7!zr'CHN)lRhF&jTq),I8gPu 1#*g }EQjžۈJsݷ$}pF2ێyS|@sumweC>=&h%ᒲ#5go2˪ԃ @a5* U>t9!X6dCҲQ^dDZ mOE,8LE b@S"㋜v\eC TT`Y> 3Hɓr[C)vO T~oGQeJ-C"і)4fK"eOtfeP`7`Q=A!G(N0oB?LUULxMŤ?^AO Ҍ!#2׳^0 +Q4-]"kG4.lP5hp45ckhiG7hl[0PVx˖˒SY]$akZ>mC9Ur3!X˾BaPG\N K6XS} 3ysxwb8^ZRp r7F/Is\JL϶4Z-Ջ"6x+Q Z'jӒhDAE~h~ގ[\ю#e%3SA)bv& |FN\Qi{6\6(RP>[t(# 9H +F@F\ņS YG/GJqE01:M3  0!ȧZe. 4G3Сz1UbJmQu˨X@6T G=f8TӏFU5o$K*NImQp4R؞!G\PqtFX/]rLU ( !+`>ݢSZ|8-<5# &[* ׸5ncC\CMۿ7rիֽB33.{5$5y5h/ os 쿡^IЋ(~d`ʹMxLϘK:|߲Cs.tya/͖+f V{0oe-_V`F! Oa#FȄ?V%W 'kd_W ,+d i qSS=AS r[5rj*(>;>3 ^4k5V֦SRƁ^mؖl[Lh^n{* % 6k pLi,gTte0,/mfGMba/QR_GF=*#TфPR?y^Ǫ3p#&.8|{E֑}){ئoڷ^2-ڌ:^\yql@so]ym&ZEi6l}80L8hq 7j;]wxu]Uv!&_Rn,0[T7gmEn+Fo$L ߯cN&|ҷ<7u~Duĕ;8:=YyGtJ/<8aBP5wu7rQIԻ'faU;FnZ )*CڥuBq+6(.8;d(hN;Ku0l/FSI G(kbHVIB<nMqzj+L1d3ҕb񊪷?rtlɾ01 ɶi^Y(7S5ۭ 1GVW&@8& N8og<84G|nkvdNT|`8T 5^{)AEb\S})4vWaލJOY{[EMs;u s씀z֨2@QQgzG(9z"Jď/Eaܲ5p,΋s1%'}?;3{JZ2[[q(vO]D1<( ho1 a0L<[o,gSw>;z7Q\ Po0G)ɕVK5z?ӯPL^I1W`\*%7X-P rx,c*.g瓭m+S@cz>tJcT) _F^>ZS>w#~}A}O,U F75^SR~;ȃNAQ悄lO6'fd3x< L6oT"lR.2RU(|E kppG2\X.k|.ڂ(T׎TxÝIlQvp]= %!\R'?O*W?=-9E{bn]m6F|: Zӥ% 6CToh[ 4T9 9LZIQGO AV3|9`]Y?wר_jIiKB*Ac ӹ>{t'I{t'I3p3N~0!lOA_ORC|PY:&^Пlj󬛤tCۨ`,@޽CjW~%>-쨊JNڇvO߷_?{YX/)MW׾9Ik -ǡ|a(a[ Qj0KLo{;' j~W&0fVlj0 W;b%_Wt+mFC^!o ^y:eĝU{ Ou .G4cu@h֌Qֿ\je@͟U(K߇#GxO=Gk\ [e5HXŊ0füFdkRцve{ ]asg!ORl<w 1GJ0U D555t3QȄѧ}tL:,|]l+˝\V}/t+@b@N1(2X.a)?sqN~F8d;KP7|Nݔ`θzmޤ[Uqed;I/gy>p%wHxf Ɓ"E8"*^ +dX:JZ揹Ey  wYjwmx)ƅA!j`"|Q v>8LjZQxa7,د`qUN[ZB*p0z\=xbq#JK8)ĆBt HcbT1x\.sj ( ]#1es825w w\= ( Ko+RYl+``X쉃z8 "$1o/Ss%Ntq5}*K_`8}Wt(yVG !  \ZUCNҴ`-q}*F5UJʓw?I7T'I5|R T'I5|CA<N#Ϭy &h d>(!վZmEg r"+^mף%8>70DNP%P _tEN3]\ d|w{'CFaΫg~&׋O>BbYA [VQ>K7Gmk!5!D)Gk1ڀєEէw!Ҭ ̜W`.%СۇZWjvXUXy5 ^UnpEOpދ~Fqg9aďguҁmI7,5SEp#FDQ1ȰoPBu#65V|(A)_XMo*%,h([w߉=?-3`b\֚L;| Q(goB Ev (*IQ9k56ʷa@ϕ rCm_mvN_Ta^Jl$,ȷ*YL)(]A'Ld gPRY 墦HOMr3$(fY.8lEO ˬor:4L( !wQ1|/] 3ۏÛ8 d?ýXyfgmę5ĦДjfڞp yt J,5NL'Iz42aH -2]lMQd3shLWRRnxNLTY&NgPhHa:NK\1Z}-I* -0`3qA;c1}yP̢L+'L 'c!m")thy1B~K72gn/rKH|s CI60CIvM2a&!ڽ>A''<ϳrZ 5᭒2 ` yrm\Ƽ1L N>DkұlG`,T%t/7Be Jf/%?Yo4Pdjzz1kPU)bp:/F9 e-c+Q(E n rn Ng2Ls6dU]K/ 59w)sOa2TK[ONm`zk HF|Kqco0Fȿe&w#ǞAQlۚkV,+FnWm N{HgY~rV̚z%Z~&tHBWiLVf%EiFĦ? l1eu[nasLLAKҙ\)qZ4kínT~b x5m,4%:W9苯.wI91,75js_ /R2L Ox-yw> iE LD۠A61^ӔF>_z}!N ic cb` Ώט_)Y-/PDF1TNmwR+xlJ-jx0xRxc#ԨIџ ;@C2:}*:܇ g6 ڷ!0٥r|30e~89+gc.ġߛ6H[IQgʵ7ƭQ|8] "V͂1t6y _9"g~x'oܪ?Z 4t } = j^ȉkA}T,j?OGk{tbŞ=O{.<]ys1vߟ>_a?ͧJTNM~5ݷ ( 7cf`%ɅqaݿE9ϗ9*WV9._crCA -,$a\k#ٗ nyPjhtfC9ali<33S긆EO6?e_ƒ1q9Cd~f5\aaA8UAps +~LcXHRoLVx&E6BQ$:m/eA_(-џr/j <=LoQ*aoT|ƫe$VmS[1?T.o5+XtlFMdG>ĕfHWr\P&4QWtm8dஐИ/[WaXjX3?w`BΚW  6y?j¶G;L#u9 6J|+f4S` ůy6I>^0G]t/_N$ @>Shf[۟GS%99al σ XJZeMp|>*z2脕XRTyz)2r%)z,qi-pU"|s:هn-1XC3}?}0c&2w:;<%hhWsmhx Ff&- 8*֬^{.ExHNIq{_:vYbpurƈZ+_Uc~($x$mI#| j3aB=szΐ6 @݉+q8mcn wM`uR>qN}%v4ŌG(1hqra^0܋GhROMoySLcz&W;PV}N,M7@_*brF6bӈïG7{Kyb&3z.P59C7J?+ %ESVqqQ&pfclkȶVpu]@?:i̾hkO#F$9# ֟8=֖m JR@ӊ@C3Lkcﴪ1ah| b2IM:0"m 5>u'%r$Bgmp6-k}LC>)9܋ Vjv?Us4X{OsB*@sV+LGyo[1lRVo<`؉l Pơo9؛]C෮62"Ab\:O]l CGbwP-0'}at^x#LgHd'<,W8|$&N_m)Z߹քtbM`u e}g>s/$V 1RDS.t.\59"Gl঄ɜ΁LVj`;G'd98P|KY e;OT̊U `MpC315D>ǔ*vw`u@1,4fw-0/vQU 8iiAjǀSEū2BlWEEɜ^ݞN$\M׸iLA0 #}*\ŐcA+ׇGD(TǥCy_Bw>'±¡~TI l "/AU_n7J$ЊI9X^qZRD$[P0#m`v{.8gY\<3p|&Tg?&Έ6ouus\yc< M\՚l gMVd:N2}GN8ȿŎ zV 0 9k5]` u 恹G(@:ذƷIҋtn$Tƚ~=@Kn;Ը x]zS+0ls u@i|H f !Y(QۨDpA4IZXZۨ0I\Z M O)2]oDrגnu2lJ~ ovNA_85Ht@zb_^[kCAh7*\ԉ[@bTiUrzIP_{X-%_;G1kؾ@38r>֜`_;π`+5\ٔ9}=^,'Y3^ww~jp*`E҄5 VH!N6 )e;ޚ[:Bmt1N4EdrpU.gM{Bω(Z/|`%|L,Mij/VuL>b(ZCeHF0Zhb+Lu9"mޘ[xO'MW<3S"l&+nbMm0;񲶐Rlyh\_+m"+m=~VZ+]t\)7sp׻R)/GoYV*uhDŇQ3g g - gIߣhl?RP^[r5brGr!AՌSMv"+OxάUVwC%S3EzH'գYj1f,4s,Wto83,N9BVkɎo Tjet1hg=c/ɛqþ1?PAhU2g|ܷ\:fU&)f77Hl Uj(i!myMxilWMN86/:52r@3b#Z#~Wdy` %{7|?N2Zzu՚A YX#df10",JU/( L9 bjhlÝ4uh_n"ǿ6`Y +ݨ&Hedir(~FAԠjo]Ze*`Oq=vMU6Lbh˓Z MԊ_ 5l[ͼ@M(\Op\mbq6cZQЀiWjS}Of%Fki$d oGpd/`ʥO3փqk:\0mVZP'2rmAZЯxV{Fučx؅ HzzkR# K}!/h[jjnKC`Ǝ:W[8_NrC cwZ=qkxnړh'?(KՓXs~̈́hraƙes5򬯬UP3G`30]v62l}'{bhx?\ Vu("7A,r#Y~ll+4rr355u*M,|EY{4ZD(EDžzQ`[-"?jl5oq1j9C܁e]dcYzPW^5#cYRN[* HxZTF'=ݵ'XSKF^z@8r88xjM)'JG/O5|dH$=oyT-W<:F~Dˣ^9jT;ˌo5ueF m~РraWTpqոA hҾ|Na=9PMHyťf9SDf(x5n̛k1.2,:sLa}73skܬL[k̴u㙚5FQ+X|k\CaH Sßǘ.f(w,_v|a_Cohskt!J@%:аgz.GB lטMyWלyP n7;)quGɀI|X3p܈ǪU1 o[*k,6o5tǍ~ԨLSh4G'݈6)^2kQ/Fbu#^sZL8ǝh_hUMp~M6÷t[I%0tDe{ml2̊8͊+*|''cGD٥Y,wt66F1-3 JxћpQy 5Vq:/x5`]QU7(LtL|@g#-[-▀&;֧ yefFϢh ߄VIV={{%VoWn^Y2tkXHzջݷuxTq492szS@*tq>_xJ-qiQհ񫢔gVF& n/<4"hJkUXV1M򶊍ǴFjnp՛ȂrYNJ@+[:LRتͫZ)״X)WR(0AOT.0{&5a'p(7HHjJUjU[]ּ Փ"$0[dkќcvrOd7Fo^ m} l6L<2KTN&xo-~)EhW.gPi>LjreL+-0 ׯ97QBXbk.n#\z+pK@IJ%Eb!ñ+WbqvႧhNWLG-$CVV2Oɢog.33RQX/gً/b(0 .2%\T&S vɞ{kȜX ڢe_s*fҸӥרX+Y<1܂|_hoPR!*1K6"+Bk]60c!uvG'ou1mo+;aV1W.CJG ]nyK۠[\i#JK%Rxt4p~3(H63Z0҈\v$QФH6pTJj`o!Ne^H1480%7Ȁ,ps*,- AiwNt3y(ZVTn,fWL~ g̀Oxdt.Fֈ dYW͜ -N缕dW7ŮnҲ=T[ѧeDؔMR[R!׿Ǡ`#ė`іMIv@x 0{Bb4g 1Rg1*,y;3UM <r:{{c}}GȯqhZD;NnmZwVR!s9XݪbX].oѽ-aIX7Gr630 0#? GLE8$- ,fA\NwB7#=bz,HҭƧ,VzU/,rp w6j[+߹P>YN][63CP`3+l!1C0+ڸd t@9nnҟYc1SW$X~(%VĕjVT$jv?[!kݵPa>VnIJ9%^zW0G. aJӶDJ T5]U@`LI&;+kD gOF<# P&pc;53f)a#x2qD9g̢86br]Vx[I!cġzR'A .|W_rE. .rs /9&l^ CZb/lqn`7ݕ<;Raoz BWqM!osV vN3ժkn%J8r8ekIS/Hvw&u?x8M;fXL]60;&@~0·>_1"QG7ላ>kcP[-T-ndpQ|j=)Jv{(ڨ,Ag58n0Z3w1RA8/AC+aog3~K''aG66ukAFFL nFn.ӂۨ="Xjxt#f/C?TQzKn&9|i;>] #׀Ip3uFk痍CV [6K=l.˦~ j >鈹/dCeW,eYlY}Ъ'bMl9|P5㮄rv'׀c?klYc?kTx-nxo6tllox"GWf$ρGUsj" 7WnHx,tV3q8[Z[?k&y1Ӳwl/h^@8*VpzbAԸ-tm+K96cn7YcKq3G/<>mUJK # 1[w@2dщ*J'P͝zx٪)s}Zy uG?ΜyqFX͋oomrVc{%!)Li6>ҿ>4&zx`j|~8lZ65zXtP ״ޕb󯔵 ylbۧn-9J2Gw,bPo`MDE8WǏe=0D0s2"Fz~t#(U@/U7QjJhK:YJqkwO\2rWA0,FS`ٳ]יmGo8ψdŘu\ Aoz2<@̜m]ٺ{uF72Z7l۲eq- M-C-s:L$w6tz0l"-7~ňVջ[-7;U0qrrKw{ ?]$^=/+EXJu\GGG2(V0R&|R=O*ANG؃ZK6#@ݻ%JIpsjYఔX$Y l.xFrsDe㍤=^3G6qgj6|zo~ @oT`!>ϭIƝ)J &cͤI\1P-X2KdaBPi|aBU#qZk*zǝ< Wd#cݲj}C;bZeڨ( Џi14Sjτ~ڼcp}vUٵnoW[=fg\Zf[+|-Cx[Q"Bs"# 9o< w#BZZ{n.+,bf`9?ILiQ"ZCpܪU@fm!níVUR%jՇyecD)F-7zn8q?4຀^w9#wFX_ap]:&@Џ(wč{IѤmqbb] *[Izk h>.×JyqBVSK)ITcR%n&% s|]4_QJOXBÒ#DzkkP]"c5Qm֪.HVD ȝ6k J_ܑ^ޥQ h0z9K5G_/kT}ǝAKz,?QȣEEDB hi=b["4"r);^8DžFƞ GOg1->dЮClgM&\Y׸t |G+4[*Ç^X'qU\lmvd8M~=L5Z060F(PaQIk@tJLf֮6{V UY0RBƽ.J0fHˏBQ#29~°3g=th#9Q>m˛:XFET{l.U}}g@v*riƸF/iK3ks3ޣ{sgH]dgeΘnL{DC3_vcx9(3h M 5x:_BP (3VS-jk߷,z_wv]YY2!tw$'Vܙ-ߚHMuއ6Ur~)zN5'yH8g)BuyJe!WX.TʊT 3T*%J?&q|眏.Vۣ5@8XA2DfSTZn^sb\ڣzZ9BFpgg [.XHLX,0JR!Zvtis`4i@%PCC|ax˲MNCRg 2 74/ ̜2LTGڽ)׉YJXx?vrĕr5uMDQEi`x1<;)lLYN13Eo'v:ϳ9p/<,q}^[d$ kZ= ; z yCKZ 2:^]:Cw`?~:#ߜMKP\ q|EkxlM@3D0d]ZbԽrCv$x)87A/7Eҁ`FT[joH?F]%yYk;^"d79mm;*7{(Z]6pPQh4ޖ9KZf-deIO:k؇l-$t8LTkut&*`K\]B@;\.&Պk鬪 q%7~&fZWwHr-FE7&j&*T^2NaISبߋT\-ζh/t84Qo b^] к ;> {2x>,{b2ȷz}XMžoU_%[( uq2dWw#I3lUs՚5u> Aߍ]'v;vBE<Pw<_JT6ZZmgVbeԈZ\/= L#{VGpڟm:÷>opr#7aW07X/_T;3.Flb.tz1`I~Xz0zWo4dWjj ~ؽޡo`u_7mBnב#nq3.\8M%1jv"*R_o-:'{GKCJ _;F*hAn, `$oPs, 3}?N>4bHf9/ƿ37&׺П7QO=ĕ{ {`:SF# Wl],fq}NOur0$}*SwEbJYB4b d 67baь-Ŋ_;lv"6,jꈸ#3ab6+*'fdhb z]4,7K%>@ HX,e~43Z8;^݇%77K׍t0iXpA]Q|;.' ",@mއ96bx [3~yހ.s/%0[LCi8, ١]+?-* vE RgW3Q>-GB}?Lڤ+_1UbFl:C o=ÔMml$ " 'fZdb<Gs& gɉl$[m-^ifG{I9浺ؕs񠷴=("5xxdZTJg/Ox+ ;ŒF4#f"S3`0P܋E:P!z?wZwĹ`dI$ZE%QR(7h ]5>.ӯOP*O%I*ՊxkC^߫7t^6}#n9d)]6/ūpvvk/8i!=tbyΣqE-Jaޕ~?Pd,taՉ$H.T]چQ`LwǶfaAjj爓h#}[#g-B`O&!7@4%3ngQnp>r$0<`uy ?wĖ5\Ǯ&,F]mb)Y MFJI A}Ŧy~ <NB`N2\mA Nw-*a'V݌M`Nb)c$;즩)J-"϶h_][rV !KcI 'VRQn)+Ť2os)+4tKiJvJ%KE%+*W衅|`}|'q x y9$3W6w)&} =̢SY *H'#c!5S 1dO_VD_ lYjd.BL2,Jy9 JO]S )#wד|LLHH:XҲ<=y:DzlP^C~gżߕv1PWG'`Iٕ3- f s{2pA/6ojd]zr Jn }4(K0.Tul_ou _m nHnbĘ*vƘcqx6 ܵ=G[o&,Al~2m$5c!iC 뼁ɲO= Iep~wAGO=Yԙ@RPJI=C(fAk3kX❺Jr3 ԕ 6l9Q W7T\0G$1&c@krh&+i\U;(@+׳/鋴 M zpvz39u3OnNlw<\E"v@C g jʩnVxVxWLu\agqUy 2/m Q56Oq˞y%8V\ٽv1p2mo>ѮvJzww+!aV^/oΝ[V8#[y}]/⪗j7R~pOK ^r>]Aɦg^2N׏K}S d i&x/c$Z;,kУk%Zpf ?1եz5Mz`>rPZ0ՖbUTYh})V!D+\G \2<vȃU9:5wF0ȡj] {[:LUƩ7jk\5*5Z4h_*|B\*H8x.U~x4HsF,A@j5qD1'w1a &4jZ HSH3VCk 2UO2xVN(fnm,`r%N|-s}+PRʽ(jjq͚fѴ5`S-/6]acƣjane>=F0hNS2uzBP3]r`;S|25Z]~K]4$gk^:A0΀˃H9!Vz}q$ݯ8c{1mo.9{f.v JˣWkwWg'_@~=;*HW`. Lfڊ{X*XUG~0czp5oV5CNh.iYJ?>1XIʕX"SHF-|@U\YI2qPakCm2D #jB-ch4n{MbuvB{{(@bvl*@q;PaVw%Cg.-4bS%'¢<ɲ u()pot+J}&_A1tKOT58 AwPG>L21B'mq{K+6՛rOާD 46 u/|P<* y_*TօYd)dڬܱouhsOs T̯{J5lո(Wr (q[ykQG;S1*?5DM/#j7@rl'ɺ?ʭmh zؚezC apjmI۝ɂs:@Q6 nɏq`Cv(8TU sUs> 1W˗qA_y8u""_sֲJM-_jZ|#u{[N .5I5L1ٛSH(0'k.Vr<|n `bDܪ1Вp>_vϳ$9DމV$_?>\x4aSjN/ٚ-:$NLN$7 V]aA$d `VY,C\Hx[NT(OouS}fMw}cR\sʲ-Vb? !0bp-I#r/0]M3$IP &V?hVD+0:e=^\f%dmx8_QN3V Kn9oӽΈ#W":4oCFr}3g[e?To~gG:]7$]; Cd$oo1/! iIsY i܎:4\B5bN3` aJE}Y9Ǹ 5+@fjsRbBug ~t/@av6>; 2flj1\a 5X7XxsnĸR vŸMUt] ~>Pu~|{fAZ U^DqR X}>e0n/Lf*#-?Ymtx2,MF#r7 $[.8*aލQ 0~[\9MUJ_rx|r2D%ө w'3I̥xv_&@ Ĉ1bB5t0q={L/©B,D6Ba\{@nO:zwI_o6(J؀GM&?I$h-0PrQ?% T̸qZ\kأBTD4U {Q-W pE'] 7t$ŕ 37';sc`w6y LrfKGC P̘ST8=+3‘Q61r&#2:n5RImH(h(7,N6>9h+D;R>WiaͲOyq3}364+Vi1M0,یm,Fk8DSn-,2VESn]XjhU8Z 2;gJ "`Eſv 5Ĉ5"R}1d©6"Jf +J[TŴEl!s)_/zl^Q)59 E g҅geD ?m@r_Ƣ1LJ5Tq@Bd1s^H TG#g*:դrU )J*le7$Fv sY( VF0( P/`ƎZ Ro$?]{29..EZT46S |\w!ƓocƄzC`+xnܽ}||w>_J@|h*2Aм 0cEwVx+#>"oí$HgQ ^VJJY2 !/yzSvirfgS̆xf󒻹bлԈp(&;ܧssGǍjq[7񈗹ZLjo~(lj ԼZ&DoVEe~Cv|QeymQV5l0iUZXe;&jRCНWWQ֔Qe kRw֒C~ k:.t@7[okη uj@[|rfh^SBiWּcMANWȕ3ǪZF&5?5Rp 8[gՖ:L:CbZ+[@‰=$_D&$_o-q;_ &\"TUsф.fJbŻĻI3٩5}qS4*zaՋ%cyC@jb^ D{rf$ VEy#de3qO9ĺT]uܪ[0 /`BшuR6|m}`'Ć!_1wvVֳК.U@#KfoZ4k=$nGjq1'd\RwxS|:slN ;wcBzs3Df4CӞu)T|:\1,w j-ٯdݭX^Or UGu1;V69Eiݼ)EyꈚqTݪczFg=Qg\Fk6JI=24Jt}3܏QJtxw:(Ua)I\ʰZZը" ,̕rxW7^۷xӸѬ)_,o֧_.쉍9N{6b3Zlj tJyyoH@.Np6F2W .M hH\6Yw֚12_kFRˇʻG2ds:0-d) |M4\Y ,gE`A8Vٷs<2i&H6ͤ; VoG6ݧOEؽd]7=;g]L'%f1|oYT^LfVbl&>>;$7QkڷTkj&ޮnV72d>ݨD 4}+8əW#2 W1d:>[֮-펻߮}E˲f"b$bR&fN U1;zҳrG@)7h :S/ #ƆrM.a|bY3[?doׇGMN˜Q' x8ɄpTr{UF*&*oasVwR(ީl7[c#a'GfY*~ɑ2'esi39a3*d8LMհB>ڒ2UUr? PEZn[jˆ2>85ZF\*8A~5w{''cR\ػª[͝y9hXzH58"px7i3tDXGFh90<{rp ƾ@#z`J[1^_p+*&̴xWk8O/Y-el_W ֝خ3lcd~h:$xq*-S2ڬ4~f-{ɞkf|oUskz{Wh$02Τs߻ };ٙ:Oҏ ͩE$TϢo?0𛩡T(cn9r*Wp&XKHim^#9s7Ifq)/Mff`pFHFZ)UVIJz/" &0/Τj s)IڠXVT"a^*FܩVg=y}xSA稽 \_@ʗ(^a FHm.s+G%yղgIx7Bq"t ^)c?/g6)ަvgE>|rpxfj4++P$ڭ;Y:=kE{>W67ɪy?*Uv`ےӭx[*\tJRɖCD>0~Q^c$|}  5ځoZ Xnm}3VQ_t?}C * ŌZeF}G0gÍp.|9 ]^K0_)bL`ꃳ+}# i~^wQ-X$tx?Pvwv;w[lo]uAЊ,| *T}+x$#T%Otq_؅ xomQI by^$1hx><29՞$nY7 "؎' bY^̺ "tK54>bQXY!48KF-^.T;oK5RH}x~i}BeݪwR6;ѐ3T _`Dd0HJP@M'ܜ(ujS7t"OBFKSZ o` LӊoPL[ѳ4?@&@VR3|]G路~:[zRk%)W#ҟ yg]rFʰ`id"%MD[9x::8|=>y}΄XnICN;Zζot'3P]iv߶;n #th̀;5zLTڋs>IC3{WiW>mkχ0ʼ+x=S}.j22"DWPtJEGK,ꮭ-C$-AZ H\ ;l-6l*qc}||x-Alp潃vFseM,LmHy  9Ɉ& #xFq'#Y%+d5*;OWEea^Ylgb{'/^ ndj3ZmdVK=UxgMlPZۨJ=WvGlke݃[D ~D9^P+?"=F {<$֫T-2+,/ [NRXRz:[p ]HrT[JMS^A]Im^O> ֥m\ /_C*G 9r#a0x=amql˦c*raL>׮+8s< -t޲4JfGG'H#dg~b6 keB>1'=^{x09vggoOXāY[=B!=\2#Z=TQPYz1xo0XVS‹gV&r@T =gTAsL\fb9]%u mrQN., ݽ6pȌق.󂌠zðhm1xd|N@N#r!G-N䄇ףtTU 4)ԇ)'OxJŻ*+D)v㭕+ZS,=*{љkKľ`þ6_jd:/1KE % u徨-f4O(͚uh0 D H`^G6\D D+Be_W 4}^yaAϥyJWazS(-WʹJC{9?19M`D2lﷻoSYqQQj: *' scKjzeS+ߟ'o@"'\܎-_s%g}T+A^N=k (q v#=<t% z{ ;WDD Q:%qcO=^3ٙ=O :89hIJ/@ 8$8h:9L럂 Hc-pKę #+FաbQEtHL``7]s̝|F[+VB:eg>W{+*|1Kϻ>;B*'W2]̕J mR+ijWH}J=S4@zWz.Rۻ_ߵߌC,+OfH?8?FEç؆qX l@Po !m3|9 Ap!Ķ# <5ûUG4x+Ն ވxX;zvbEEfcY:F0rU>JE~K J (D]d߱] x(͝(;mpxROPD4n+۸$ԁ&$mHj{}CDBp:b:Jd,J]{KKX(8?yoJL 'E:*80@qCTD˃ܟb;;Dyy'E3U@͖k[>kA<9~F!,)Ӂ|xh \فŚT0ʏ%kezvnQh}-6 檢F>НRl 0d&)~cdZ h´+p+%}oXta$1mٲmzִv<[5+Y\Av-˿E/3 V9<§fCE_,~3ޑ6Y-l`,qS=:n˯qW|qJBׯo݊%qdq/-- avK\LTRJLڛAMbS ,"B1ٗcZ Y Sr |M?[`V<1„3zFbSo ~ŷ|c l0C\f\xQ)4i( )MS@6ǝcߝJ#, LQ~xF)GX=qFL.\!8u3^QجuP.xa>3N͝"Ήv#(@ ' K94z+7u_ĆQ\Ң蚏 M eo"9W8˩F߻:f92u'&rֱl NC3;}`!6w&6[L$D{#d J!\;OW0G&q,on@Nf$+mr78:C<.u@jJX<&̰ڈ96Pzo+|-waA %_@(BUB }( 5j_y.Z?po\1=by\rhHT__#w.xs*:P51jD))xx]d,+)\UA&YU퍯28ڪIVt@h/bZa-~ >E ц Z7zRnx!5qLkSM5I.E(}qH}; /wwh#.qΩiYɌYʚO!e9z HCh_P'l 봐ҁO>ѣc(@wpUxu|^N`#rzW XM5M<8mش)EHΖZt$wd٫_6X\1nm' #nN( QʶF:HA6K,&p<) Vќ H,`l|}Bg9B"J[ Ӏ3J j!^}&;r,̮ 2ߺ\Za(KTJ, 'oCtИ󈗔GJc'Y)I :g:9m@7_۟Ezp]ӖI6ym" [Ψ/B0S_K~l ܟshSk $.KY#{zN܉R7wZ"YkI/ ~H\ڛ\[Wݒ.]{]N+Uf:.KJr.&+]J f*/t/<(fvwadsY~6){a?`%lbd@+PT 6K~e͜C-Wap=<|%Ir?n ő4U'&cA`s f9f ;::WBfWq&l ҹߪq^TΠϚ^%~4 b0u#VxcZPJ~#6o##U}#FSHA?:z  ,fy-Ur ِ:NAelJT/s_*?ȼvMZR3h\2:xO W>5]$Z6U h[mE٪B,\je AETVO'wۿwfZm=Aflc.7r>$(V`qOs$K<FSפgMjctzb,YcQ?2<#!S Ŕwߵhhۧ@#uaCF HV3ɏ{z&™3:_C\m rJ _]tI;HT"@R\Gs4*xNJDcKVhG2-bkبxQR\$Xi~17چp #>CY4pEJ5nqc=sUUd)eɱ׃#J?lF/e}vzEl Z-=cd ލ3#L%gI)Z($^x3܎DTd"r7Do~,Tyc F qv8v}'ɎOTX`G-[w\VWQ4SYYF<1zOm&.t4*" [QZ`/`8cbM3P.&bf8,}x2ZK96&&Ao4Of<1U\=q7"7/U "P#XL(XŹx*QoOaI1vk~-Il^˩>fCAA`mٶ$PO8`H @X+C 5Pl]y07u`D>j #z?o#mW_Kg-v ɢO\ck 9+H>@5u:#!5jQ p,v"s8Q-V YPѡw FMPe[q+9ێ ztd FZ3]նUW&.IW`V_/" vᣙ0A ]#1~s/$V 1R#h#xʅ΅ " DZ6pSdN",ὦF*gKu2YNͤW`L..ƪ`?&F2n1>m ytc,xLAD@*'VK\yɸƤ r4G"I90.]1Dɜ^ݞN$\M׸a'n!Ń``GT4!ǂV#*F՚{KVHB(!’0y}quLڗL(VXg[$x*ygrۘ{Dѐ )X\qZRD4 im3dz9kqfqX΀B4Lx;౶5ՙ6`-fay@"n5X)>DZF,}8ȿ NnW/_y.X.YuVA "RYBx aZ? z(肟r9)&J"W c:5S=~Fb:T1ִ[|x1}F:Xt|ovoJx9*9-Mu D]%_;GۯN~6?fH 贈#^ Z 6Rs~<+'#L~ȟd{9}vl( L/@FHbNX65;b̅gZT,bRY[HhhpDqN00LD9ƃ^0(dg:Z \B 5ɺ0F1Ơe?Mrs]&p|Q}!Ef# C(yO56+n|C!@8 S?.:Q 8-BMը4J9Ր&)*e1,Pjy~0|?R SO,vw2lY\$XW.2PU /nombbHɴ4-TA0_gySwk" P &T;L`&m\VkE.0.ҫ:ۆX)lzX\]"OfFC#2hmvzdBHFB8@$nŚ|m4@UCiȃ7ES#c85 E*5q1*},F_&Ji0IX?CNGFΗVq9ݩۃoPrJTAffFf `mlVGd)JXt ^gTkVo5rF@֬Q,tΨ@֬Q.yJr@ t>m*R)95RY/NZ  2`̠yzjmEo![LpSoe#FAY4I5Ohm7J(R묖ɯ A0%aΌ-BP4܂hʄv[z/aGٛt 82z{a#M-l{`M).zRu' 6O6O{oZ>($9tAra]1*80=TXTŰD)ԧDDŐf++lsz:TSfSѴ -8/fXp^-8aUU:59X}-UH2EJnʣ~{Se`fٔ!g)߀fdSIj籂hG1S. E@{-FRNN]Q\rNJqdP1^1bp|bY3[?Ë5Wazb|"ʪ1.mTi4)Me0t1euS sݳu)2PRrzj$arHdvpn DYVPq yn?H-M6r1rXV,dL6?&6-oD:oIJ{PbsFn{,jM*EbVzK#6 /B̟* hsHt <6vX` ؑC/Nʕө@[ ^6^@LfBd7s~4q찍]B&V>k $B^7bх0F,S}kFg\5 %g0ԙedF|3]Z>8c{ Tkb+IFAJz}u\Ͼ ^0:=eVop glw3ȟxSzeyqs胓&jUH{_ADC:eA/ZSg /\˼Z;pcqsN:'_V/My/ww-=y}xS: C^sFmhuOCH TF/I~a_wT;x /^ y~-Yil3^JĐw]obLxyZe]~Fy<.9_==w?vClU߂loA~L 3%%\?YkpHEݐBp~@J"A(.qW7~ gp-VB$?"v#(eS \` :?vN`淄:gSsvhkc-Kқa#vt޿dDY6;鞓_y(\vt:JpTw'. gݤ5T"_sղwGlke݃[ ~D9^P+?"Nz +Ś^}W*C e ba+I KJO [f7jxɭRm*5-+=^O07`lk 4xh5݁GtS6/"E9\6SUɌcgr$Y=I: Y ,B+>Q*)Ӫ+ZYvNd}@,{`<Pڗ,"dAҕJl,>o-*z$rGnztNA|,v`ڣHL(̽z}ˈ70%f^8\ݿ Jqg9 eÁ ;m;#Jn->J| @4AͰVfN9MϗV+jC=NҡM Sd<޻wG<Q'c\Vw --a! Mi$"Ry=c0u*ea!x UnC d.sڳ'Ql2Ioь"f)rjbrgm<7 )1۫K_CW_@/,1-~8߄S*ezvnQh}({,>'o05S-)t[>ypf U1 |3t߱Z h´+\W 936[ִ]Ϛ6ӎgf%^+hNe7u&! DyO#j!3Y*f0#m,Z Xztܖ_A'<i ʅx_GߺK&_F [Z9OxD?=JLڛAf԰' P{j_i%dm4~`h#@Q!H0oZ s:<'\M3)g+V f@l恅Ns!QW6mچ>OxF5EʍxF)GX=qFL.\!8u3^P9)TbКZ qlpN7|eE' 4E\%4mܬj* ?c# M eo"9WﰈH?B $>3oDE٩c{2 YD{yn3 93A6Fi3$G5'415sC՞փLuo9{+WP74fFlIq]zo+|-waA %_@(BP }( 5jpk*H (ؗUc:<IVt@h/bZa-~ >E цW@e{~*VBh1Y^1tzzf.<ЄP2.E(}qH}; /wwh#.qΩiYɌYʚ_IdȼS4/6eLEާt0UO߿|x*V|Iq>/H09D=+T&hvw lZ{:/#9[Rj ],Q$Md~ ڈbq!ĸ.h9mjOKo&PFIj+ۿR[.^"",Zht;.W @g/X cGs@#PEv +m/$ sLNl+%ExeZȱ`M] CYrBUtQ:hLyKrUs9,:9n҈$5sz-?/7e~,K[w iK$Jd)CX3' 1E.%4NyT5¿ M.KY#{zN܉R7wZ"YkI/ _qiFyԎ7BwDWݒ.]{]N+Uf:.KJR1Eq" ;BUɪX&,{Yu:-qRAWvujMu <̮PMsEU*8A#59KiPՔuU2oQ/G6ge-FQ(aCyZ@߀ʢkƙђYA* YT4 ɭTʵ=+< ŗwC?1(ř|g`߱GtBʶCP-*d1JBPnOl[z<쓩qsOA_JǞav6;i]sxww./љհA>sxW(ADC}Ka lPX&t6X<:iZO f9ɱrM\ 4ͱӕJRh0 =zis`>UeFS (t?@b+\D. g?~2e8,1t7k:O4xG0u D̡\m?uzk-S;r@5C/VX<Ǣ ջ3*A3-&v@c12'_N¶\9*Yw q1 jRedySatxiFq\I> :7xSG)Qؽ.[Ir?0x5%3$^bt(+*YX`1:ΙR32|1zĭu9M  lơ5'x1˒?I6۽9yu|t|Ͻ.{+oO@qo~e_AyclTNڝ~̱O of =9m߰w㝷U$fN` mcv2Nb/ok @ + cAS oZiʲs?8`,9GC6 |@CI(vmD@{q oB:일?iw Ɲ?al}nNq^~#x&u,{{3lC]VWlBp mxyIo#X:'{;'ZY6evqN[yZu{a3G w5:{cQ[Tٗ1GV[Hnf-OSrTdowSb&-C?-ǂ}̑kbXxG&ULj@I xRԀ'5I xRԀ'5zj猻k>H_+UDN|?J_mJxҾBYWjF< y8; bBy|^Ww?<{]4`977yMݻ#HDj&x`` E6Bv@*@M؇9fb|lUeh(@t b`<< [J2F3am{6{I#Z*gJZJI‡4NAmgPsQ!~/S)\P\r -E=Ć W(&.IQm%V\.1,CaT[(FQRGrTGGP 唗BƄƹ6W|}ӆ@nta#ȫ>pg{>m|%&8%~_:ea8]S\7!s::ttpZ[ y;HU>Xej/}ZhGCr^ ^T jYA~l \$VQlj$0uXTS糝S^ŕ^Gtsrv8., Br'DֲjYNL a;|,(M+{ XwiW/@a_[S54MR87xCN( K02zBjWZ2j)^fuċ@z4c M|X𾬭r_؄*X7 `(!~2oB0Z!0n ګx⺶k9YqKJ I U% 6#ʆ]I*5qgb<9 IюR}x[`F)Y~|ofiC F-nEC~=bWDRpBR*SBJfLC ǏyTX΃q vPO|9SlZ+Z4P,W '[X1b lW.J1Z_e糁Юc)u/4=~M5/f9Lc%T/me$apFM$ԆeGC4TWWrriP#I/=&!f8UJ%@>hlHAJIm854HOR10KRc/PS@9=HƁc%K#F 597Sff푳*$TN~;;T_KQj6?Ac;?Lz;ҩbZdb)_>v L|%jzTȫ¯FuP&3]i̹@)DZFLjGJsTX\̀cs\3TtOQ)w.pjeT~mbAȜ/t1vKc hƒĘmJ^ Q $^aI‘!D)B_;"1r0Z&h *gdZh"@_p+P_ξN2hBViV*UiPivu8c%ac~ECک ؞O l:Ֆk80*!wdzA?Ru咝}9h),C]_"r!kͿ*La6H(aC9 ٫0DJ_ȠBbˉ=|*0+F7og;o~|gJT'Ԩ0N9+i? ZV{Ti 4,^*5h)BJ [,,Mҋ&u=9݅Ƥ/ RmJ9|VC c Nv/LJ ?,+74r˝W94k~0J;Vʂ?b?G74x 0s&z|||||||;O% w-\ίTd^|00ݨ(ŦL@^nTI>ad dYs?b8, QN}s|9]=iwn,Tǚ~USqPD˚ag(>6Ԏ㟠ADjolE!@F|>X⡣MЙ)PA:#0 ķ_2W0.yyp'>{۰Bmڟ6bVm{C)', " ЗԦC</ĺafjX9NIxQS >g?Qӕ b1T}S.&:2 ]bO7򗐌ZcB3ÝnO O ^,4~tE6(ċ3Cp: ZD|/A7zY{b뮏Ҷ6;It~f8WNlp;Iյm2{:l7|'oXQ{G?[e;NFfN4i=0x_T =;5:ÃJI6!XDo7mDCOpL.l4iGJSvoJT|}tFHڋ(]$턶Fu&"Q¨=ōkE"\Dc2AUοJIrEaYr θbÀt+`Yh.8MG'ւݑEW;!E(A肠)))~/E~f[i"hD쾿x8Uo!ِ {)F#i(*_-OuԷ;%BvрґgR\XiRBBuRHa\Mio[SI6uDۍ1 0ąӂ%N߉ ܑċd]uQqN;{. MAJmoIF,3HKBFvaɍ#+ 7D+e%1[ و(Nzf{Y \9`!#_`+\s\7+1UG~1R~bIDI5Z(- EhTE u1-P,E߁P>$rx̬:smtD3\⊄=+ba5p곚%r,Aҿ:b:pT~^aBKgn ӉB]M6R1 u#5WD;t|F#SBibAP@x ^UpצAr3>uel >;[Xfx)k8#'j|a`Q~ Er0$ j>z6בmuS税&Arh1b͗,S$=fBY-1ԕHT:  mcS<YTWj#k~ W>@8Q78p9uaF;]F$H¡Ce8zBAtG:ʓ^u(=^'b~?74| a!(}XDi!3$Sծ][v0fIRLOxϿ'A8 :  /aD7ˏeE@if IJ5ޛ4nˉvH#a;v4'JRlBfQ.nְ`q.< |x Y\2;zaS53샋1gũ'\ "^? 7;,,^B²袛_a&a*Z EH8 FUqf)LAڣ u9-PRcdR xd:e\*l9]n\HT]M8j"'g471C^ۺW̙bnq6r/RHN5ӽpCuA;=@i0LIJ"y5} }# äwO`9v1i:w:n7 oBS3s 4~iyS%qߥEcڧkZe+Ę]Ю$ "ا|dH5WùS\^3͌L w6Q@MU !:QAvԑ9 Kd V1eİaGRS̭JBN j겓R58|g5ctYn~83諲2Т2vԶjJW_^NXr1JtE>:  \8þ(JACB-}B)wa<7kKҁ`ZD>@Uܳ8ѪйFe "&w/+OKxti!{ 2DE$ teмP2$ ;yGZ^8|z{ZdJKJۿP0#V?;5gW7i3 jw3׿هMtX(|wۡ}d_İzrf ?Vކf*B¤_1g*9!e&M^ t92&f&-}'ɲ?;˸l^#u?أtGiIfK Z_>mGuL:YFm]\JÊ\t! .abr!dg9v1ο u:kRZn,KYnET-i3[rC~)SO  y;~B 2O"3gY1¨fxQ/wzp6soL& H`ڻBMk h 7ǝK/tdk_&jv}%1^W(o#"Єzkn0R9|Ϳ|hOf $AJ}[xͅ9z)/7>}vnhSj&( |Bfb:wFTk=Th~g5sg0UаXxJ\E|i`@q.;-m%YM!w—Vt[]}8/@7^2XnAg>纠IkkR!//Bu|'M8 >ٮq٘kMf4VB +VDl.ң<a0ms0~c#0B'ypzק=YXU"R2@3"e`q~V & 0rUC%X E6XlĦOp0S.gcZ᷀$ 8"n 'fsGmM ? ؑc4^PΐHЕXzM(^ጘ(4SdgңƄ/; F)`:W8HLY%\ w߁IJkQiŦ:lo=[CàaF6MmYu{,ߺ[7-օ/ ,W4pD`+FgTPa:P{ogu, ~dzrd |zd %o+zC!"DŽN:k^LP W'H6$U]J[hv#LRt @#Ž> fƣΈC!6Qj93>>Z8oˆV%";y ?-Hsa w(-Xn 3B͔ƣ̘o3Bg!IP6 {77&$~D+s('pkYsIdf 5Bs0D_C!tCHX$}];ثV^Bsa<Ǣ6R$FjqWDʕD #( @ K[ ]^I(M[R!_~ AZ4y7~;o\#k׸pS ~( $޺_ !r2^ٵ[Bmq?T9/%>:5"d $$S~KheB5 u) Ep=pݠHd MK)8*?ROOPtp^[Yy kO{ |]+"[)HIF'Ƹ7Y~?w?4L)۵z)YK]UpM#wcs6y2zO R)+Ίȩ`a?3oR*X.~z5+y`''''''''[uzw}t#M+>b}tjh'Ϭ +'#b3w˄TMH֝Q9;ۼQV9i &JZkO8-%!eiM×iƽ| :(^%{h9w(Aݷs6W;#$\BB'ir҆HFlmdAuwS4s̀{1Yu/,9B&H&QK蟬\8)p3Y&pN3@Wԩf M6/ zt,*f56lLo.Oz!g=mT70<@uE"ŭ2M _ypX@, 3x<<`1)OHA@Ali*! 3NgitBDN*J+PQ _E!>Z17XKP<9aPQR0!L2xI B"dsZ@A~d>5`Xo9d^qRd%dHj o_5[N6kpNp|]$vdIT9QOާ/Gu>q>@n৽.K}g"Xؒ.C辘|h V(C_7{[ǽ_kߕ (FJFBGؓkωRRt{'?IǞ΀΀΀΀΀΀΀΀p 01GR䊼1یc`i0h!(C4%iC؛~T\gbїP q$o2Cd(¿@ 4iǃ t)x `G&1M \ǑJ*VIeio@@goviԄ1Ѳ W9=Ac[ U qc6 [_h(Gs0 V-S]U?@"Q^q!peRw>? J=|P[n`x{OjZw@}/3 HFd":Dh$vv,gw{t#y\QwMskw;{^)$ hnʠn K+l(5tpM`1ktw( kvuՂIOٗC \Ef녢 iÿ˛ދx͐Dyd P<fJ`u$0nyWueD,20Kpo6~? P қH\Ҋ_7zn5-WxKs6m6P8έ˸otÁ>jeQ8@1 6mC/Sڛ.&6voIα1M֝~MWxkC{C%~jo;Z{+P X.y@ ً{l+@+B5(y3DU/?B\yVhvoB6_ ֹ(6 DQb R>L.vOi>;$XXR\HF3B#))}7K'Q^ɯ,#sVVoq Iρ٬De[)erY^Z&}$% 60A H҄ [6(bj+yg[։#"Id?kjT, i#46OХWn1Kז5zLc,pk?>r@YMVR?u4**Ӟ[ ) Σ-c;31rȃXh~9n{&y&bu%1BXS)55pa)T7rL.,#&DchJ b7$'ge̷.c2֡y?y?y?y?y?y?y?y?6Ҁd$jr罓0O7J]TPHRjhcJ,t<]h_f Oa{%=?y"uߵWlo`pHm:kgiS[vhX8<<٣BY4a#d.ǝJwP)jݣ++i}@xKs{ < Wۈ_o@J-o ‚PXhw@t5WX$iz] Ucixiƹ? 2`HbNCaÏ#o)9RI6! #cyޔV:mL'gq^ #tqtBN۫^GNvU3<: {DgC\~F`nx7L^—Ϙuoyf85}(Q9/TYzH -brJSVW9ʺ:yQB6 cnWSQN٘LCu1rF6ᦱk&V,bZIg4{V5D ρ#0GXtgg 14h^,4TøbdD%qs" pܬ񥣙h6)!ZL!k1A$8g!ߕebWR=شJAkʹZktDPWHJ$tIfj=kHPȤx>:(JJ _ 8-, U(v{c.d>wȊ1J c3sxF>UN)ʴs׆F[Y-{  ;?~Rr~;gܣI=ŒHp OȘ23&VV,ί8s AiG'o}?g3Gɕ}%D3ڼxF@sMЉH-qҠN/_zԼ U3uF,cIڜҊJUbY|OЗ>Dixe9TT5hja4S}֜D6axH#8AXe$i27]38 ݮh6T-AU{{j=qm4nxzS9-W-e~$iI׾i0hPԮ&^46Md",83D+uG|1/u{Nΰ9 ŘV8b]<=v_C;}NfFIt>sϴ/k:=؈4d>e" xGh Qs#[v'1D.IA Μ}Gci_ۻG}|']hķ,..Al?.`Ia;b(parU,M>΂ԥ,#4 1SPwM~6{4M7_ڤ_( N̽f7Uk7mT4k/FGƐj4?t#IH]6Sn7r5@|ӵ%]$yKpT4.y[Ԁ ,t$!¹Po+KXD h.ˢKf$dhTIG't T1ˆnZno07pyEAeqɾC0ֵp|xnTcO' !Cp3t<"$2?j>NȐDu#A2,̖m*꣌`Mm咶م㓝흟tś ckAb` ۝+g^2<&-c3xx̢y;{1eSM)^hH~ jGOD'D w& ?fj ,G!rydJn0y%-̥ufbpY/+N L/f?"d} =1%ifɸ)hf5~R*6/~|nrDXA|eZx`tBDD(rJ q9Q@E[3r ToE&Uɔo qR-2D-u,G&y΂YEΈ,W9Y/s-mż乜tg:Igu;.2iJ9-[hk̝ыQNLI)ҋLo^dvsO`y~VxHqWh`& Wg!=Kj?X q$B2t:C/XÄ6dSk:1?Mg4FT[jބՂͻ.1P=)=*ǂ0tnԦ@oc4wHzNsX˫˨R}ܧC &OUN[¯&sZ)KUDs'oib#\J+S(pP?s]EQ !_Hzp\ +\ev×Ʃ2rڗ.ЦtJ[nBJ ^ɘ^t+A^ $FH\EiU8uE F2Gыx`G]A(҄t\A흼}w\z]KȰ CT<=C(Mf eeͶ1%K"MLɴkS!05 Kҥ as-.95i>;ŗ7|fXc묙Xhhh}%4etk1ZDo~B m _빳Y e~wzrbliaܿOyCľ%|ex hf9L~kgwÄ ݓ>DH{śB7y|@ѣ* *wG pPď^쭭5-<#6VY?(~K.تƯQ Syx'\/{l>*SIǑ%, 9>X?Y8TGGH$GYV~H ߻]D=̣d2pW:Gs1<2N2> 2= zx-DǗda}VZaqja5BUFS \2mq2 ` ~r|Vz?/v(NDMUNiۉz{ TzɅ“fW8=ʲ.6WiM`"$w]A2oͩ*ӡJœM_' *|=ZF0/k[ow !0#s^v^"%I|חfY3=m f[S %g'T˾ù Ͷ f\ @u:rh\Z-ׁ>:EwXjvf|/woa?b^TWF.992*82 Վx Wz=r$%FƎcp)[zr LJؕ.˳:dq׀N=<<8==yrkzG"Q/}t*L(C9yboI{ٙIGk,}Xsixͅ;yƂt﫶;oI=;X|FYV2 ֳHk]L6= _}{ %Z)ZWDOWNܞke?뽪^/\)3ܑʅJeYF}ɻp-u o3㽷^å骾j%Tst_L9H}=+:rt}STTVnblwKqՑ;.0M^vXh0d: 6BH%fgW "ѠJj.Q#T6_DpAr@pH@/;ug1yP ҭ.p#t  M0p_ ~aԢUZyN^Wšu ҬOAs[} MXINqq2KVltCYEm,+egLA=b}ӑY"I(Qлε߮'ˋ\(D |#:>p7M9|+2KIob¨..c`}585LwCDj3"Zmѡk@\n-0/oӛw[z3QЍגX"Cq~:xtE~ J]>j,Ir~] F`^zޣ&`!5xSLd\2bDEZJ}cKXS2싏11p4RwحaFOZD̨0`>Due5EkGߛ; :]A'6W,v m*X M #Fӓ4F2? |Ef\M J^@BIL&v3f,ro\[.-gY7ֻYxO/Nܨ# Ф+3PX8$Ba$ӽ/cUr_Mb˕b|Z˕8i$N3^S0+W5eyJjN+BvMc2 @jL"`qvЧMŮǕ'Wl|k@<^t-Rǒ«-Ho$2.]m]Iٽ"/$Yh?'I#ZZbۿcj` 4Rt+]\'F7C}[.3(IZ7 ?3v=!JPFPwD/uM!t@l'FdH 7j'vt+0Ӌ|p/u#]7<^I1B6+fӫxIpf*zAa.f2`ň7icw<&e(C\}/t=bPۇ2JxYbzY|%h(߅6laR͊VvgE`|d8RNS{<7bw6`3(No)'R{_Mӣ¶ӌ|uWtihQUtTF`* -(# K1Vb=O q|jטir5?8%< _slͷ=^mz֨q;趷:uKϥ->ę+<'} ! hU8 p04@$SCa;hqm :|?g )Ox% AxZ~xMAJl#YC5!5&O  4"Tol#Xw[:4AaX,Z8fv v!=J~/N^Z"d0#'C>}_*o0ln6a )OM^~"`ʉي,Ya<пdnNM&D6=Afoݠտ9J!jhiS"h#e"^ O U~ т`O*B Pb $Ory0ho0Fπ0NP _i:֣@Q$D_!$mfPްI0a5hH2*N0 ]4d{Za(qD %։hp;c(S;F> iX/ Pk\#ԟgFZ!-ג@nnGLFt+`w7OQqPa8=`~3{Blr E"mzԿmĿO[gf,'hu?c@ DJ5*>UZeve2{^~/cwu_K7PiasCTJส/").~g\`K&Zce2G&^qQcCϟrsV RWPhy bsCYd܀QxoŚߞ5F2Y|'q'Ft>tFӳ$KlLJFi쐘7;+Zkq}H[V-0:ǝn"fpzB dD_;ڿ? 2^cN}q d!}E& @ٕB!3f%}_z,ټ>oa]VgYz}^gYz}^?'Ij _'w̔兙@R}0G8ϭ'ϗjEO<ݒtd KDYf.Bc~fh$ OgS}GoB{s;ZM"^E)m xqUI@& !X1ntbUmmm,W~$x9x _lzE?K ],3?:(MEEƢp, x&dȕpLLhEp<L&PgB6X9mMhGr-"{c E{ 1,:E XUcM] >}-*9j~+. d9s68G!m7 \^N7Κ8C|/1[ccŮ9[P! ͤ5@yGd]j1Vrvl;vԓ^i입Ab$EQ{: nvTv?!I躢YaMCUqe匰;Щvv2*2.w9ne#(y m5[w奶߂Q;{#!{kylf Msyϟ<_?Ȋ-~ D\W/2|o;F 2IF C1kd %HCqiN9C~ ʳIsಫx +b| /L f%&U<܌/08o;1ySs i5[]R5vL]Z|Oy0<<Wj%ckkKӟĉ`o:-0[O*1ot;4e${B> |ePPv;=߇ΊIY w@5tK {m_Bo[Xv@mnCPHC7#fsubM` N=iqi ܲċa,+ЅzNdUa%ܒn@mcHiyGI[ */t@XO~=<%At-5olbQ70iX^;rpN" ʚg pAg'6A:4kbzVE*$>Q;fxpi;C,# }î=wMˆe^0ca x^2Hz4cL4ZZ[ ٌYU4ύL-Ve$yXڱt ͵ÍTf ѶlT( ٝ^֘2 w> 7&E1+w? 2DU<3Gw3QHMX]$5HM߲(Lt*73AiP- ѽYD).fkyۦ߱gUSY^0O!YfΫĎM)1,f33 L3anJˎjc27?'Qb4xchqd*lg&3SlPמƍgLc:&Lk&ZPDŽSa뒲`>6wM0Aρ}5b͔M%UM4&l=f8ZfڌRfEQͪ ?RcdM|x .] x/UCq8Ƙkc`2ߎ14(nMBPclS-<ۻdm eejT̸iPm_m)Q7 /36h`9s 014y̿5[^B)hӡ;.ǘa[TmDaim4*p1qD<3!thg"f8[M,VUb21B@# */GŠX K;m'de2~s\o.7M10~ǨK)a@B^@a/:x𷃳3YVl?$حΐ?yuOO_^?/Pc='|}yi^G)~}H?|-G|WֹS~8Z#NH 0n@mϞ@G\>>N d'-w ?=giɃ"3Oo x!OND! YI?Q/ց *x=(Q?9xzC-@YBK+I3J>hOFY88P ~'OO*0¬D\XYqpC"-^ֱ q,~JFy1 K?Li~gPqT,5o$ ee|o4cax9&e'L"'xPlO74RrN>H֩'~sOœn*Jjs$:?AM?cM*dୈ9'${JE d. |&p^#%49%6<4|&`Z4t( df7Ţ"'v1Mh hrEOذ㣿_^a|lvaۀ'+tWLIyXh"{IMFM])9;E+Geg  0 GCϿj,搑YRU 6zdPUƁ]'R d-zBقPVW`]++ =e커Fv+l^J̕Y ? 0!iTgL8RfP=Ќ쬠`@0\HPn~ t!~/гҏ>v@(ifnbvsvߚu,L[ioe6_26W ?Bf1"i.6[x\$V5/eKr?uw.|Þ~$CUfeנNi 5+Ʀ3m %.B%y'-d4:: %yG.2vhANM^W7FF mpM6Eqyٹ~X ՞z=NBVHБIld2*HچЗmţkt-[р6_7<8j*-ӜR=lt?4iZ`^V3ɖ8WHi&ZIU$VV!h[is̈́\ <\kFV{PiK]}/BqU\/Ar VχFR!]X ~O;0GbRG0%m !mD49g\8"hQxg}ua yx3`^69䓝喔&/:NXǻR| ϲQgc4g-Q#*e1꼼h'ހ M^9}_*ox?&z!yM3>7IKhN%mKDkeE¿daS%9Tv%?ݳ[1LƜP|$߆;Ꞔz)o9za!+0E|o";# Z_ kÂuP_$ 9~?Ђ_[+NRS2{mD±5y=HLURa_oo۷!k$@GRBSQP%bz⮅3iBxC$?]OH$w2ݶM^ "oG5W jX"ӤXfq⛛\\vUD^nxS B<2$A q\Е@ <Rx^hb4/;d5 e<0 ƓƦ3b!Dቊ CjݗaTEQ| Qd -R% 0R$A^4q# {`0r6v?YUx_ *.V4M7C՝U5lK˪("n7Qƫ8Ҁ2o:-tAQ؂M}M=nuwFoq  g#VMծ:ӡߋ(1Ÿ )TO; , f"m m*c\tA3.x(`,[s[V8}VVbS<`|X6Ta69`Zp}X05z{6Ca&kic,zrRsm k3S4He>43ؠ&{LdhZX]"=W{1sw%0P1Dڝ.651fFPrlCLu%}Em^ZeQfTv3Lu ʜ[aS~sGvMf[+fI~e3 y( =^A{Y1o`]T[S Pɍ\$+^n:Xǵ=q_tK8d pp4I4Sro/2 acM] @$d/!WzI"$]$_ wW@N;QU|,RnJ~߹0= #z /3}vp}oGO.>th:9dk.f3G";${( yM!!fLȵo"FF lR^)neF`$ Kl&;ëee %4NYc3~_i*mF{c̹cB&9>ip;vZذ%V0dav/w< !&|w!fƒ5j,F&|"9d؊?ve.Iڛ蕭έ؇n+kY015 aΗWWVe5/Cj8 -1 ?¥J0ȍ؊N{ˆʰ(9C& 7)Vw|(zƑQ*;:Q~ǍPKs2j)@5rQBc:QVzO lЭm8&~JYO벺<;ovaJAc(?MZ!*J;Y!/ b^QDLhDBF !( ?ߠCC: т(fS3ɍ%jPWT\?|57\Ѭ!wvQeuXʠEDZԲQW54ЁSHML`|٧0$EIJMm?^U)@6u# vgZ7 q=9xwqt'ųO 1F[Xe\6MĖ fQ] NZ?*B3@_b[.*z FmJ Ш WQ?b"3= 颎y?a,[ݢ:9h˟#aReb#IP0&9x3&EIҌCѴjXQcLwz\>z+z\p샂dgnSG5ּޡEj۱2D[kc%w!#rv 5aD+A~C+>6t/XmJ闎3e4ZǴϰVsei \.?e2s =ǩm1BHG^쟡S"+]?2ҋ"%*hxqڬY3 v05V%XjB ϗc^\Mnʚö%vU%t 3ievn:W0R2Mz V,> >%~gK%]ןɼ赠@7t !o%IŚ;=3k̺2|:sR`t;0gu68G#m# O)9֯ЁP cXpske7`&v&$y.҇?lnU#\<VhԜyүhUFsUi֎0iDj@Vu!9 䝞4{+ ȓ dnGݕ| _ W5Ć+Qƅ@lMTR"OKZ$t_ m*\8!BxWpGhZEto{f\G0mS([K;SC /Z&pF=tCWiEgKGʰu. Fg\7ЃYc΀al[[lKN}\e'4k TL}}0h@WuM$u" stYA I}3\ %-D H`w;QчatF 4iNKP jV>RV1Ә^DGYRU{gdlʙt T ,}%x cԝT=6T@gAl&\*ՍqPag'33{@&M=R0ea* [ƀ ~u!mh5lJqykX[W㿲3eJEr*duG9|oflJpƗhӺ  ^6"!ŧQ|\].&qQ#CGtư#}|j( h9m~6.s;ZR?s{H"rF ʴ[abxI&дHhV엚G8wE4';`U oՅsy$&KEлYy_]m%bfi&y f#)U rL !mC21MYKg!Ò9>/Rs(0^P0P& Y6K7UGL%mCGdm1ާ>̭OR<{cBρ-`wJQo׌ua:j`Y񝌻5I+I![-c;el2s۹\vfvȡ 6C8_GA-":=uLxIү.#(Gŗ5:ցq ЄU+:BŲc0FpUx7қ7U|}pS,0G~・~cphR fۜtB^|)Ps{:6|,!/#`^]uƣP|Ey(X[xCɚHkeUaY"^.F.5`% <7O{@Q|SO|Zȧ2"큰<{Aa*%)a<%)ҿXnn# l;aqPƒ$(j%1 ITKDZ| u^!-^_uUJlrN4XC~D?#bS_CJʨlD@&g{qaDg OIWk-!qf#wu 8 Ft5Ϯn ՁꇠNˑƉ*2qˊ[{g ܊'inq5bNn1_ƱaImNҼ*SR.֕^2+f?ԑ-JɽR^,Wp+o"^{#ꉠ]ax?;NX :#!M -,;Us:VuJGĦ|+4p6Aj1jQbʣuPt+b]WʊX ITrXf(],UT^{^z//^x{uF9l8Jy.B6s4:Yb$ɥ kRhIVܦmJݦmJ*9,2}VF#0TZÚݜP.!(] ]g !#~J5#Vw]euWYrr5D!QgHYUޜ:Cb!m]a͉=w6EDGQx1EģD#H8UX=Ƒq$b GȰ7'bG"Ƒq$ַysG"ΑmDR̚S*K؛ (N\JiZ)bKTS4TviV?KpKpY0ؤ~JUKJ4_+UxYkZiNUgUYs'k6 Q>R6~cʬ'Qgۜ23;e5ewwʬ2v2ueֳʬg+$eַLו+.ʦYW+VfWrB2aexegy7gYaZ[qboN%2-0&Wc+GƝzbH0T_*/Ɨ K4^Z6q8Ra0TƫK9#6Uƫ0gIgnUm6T2o90ũ$9U55)^X^XWW@bs4 RM"&UBbyLa!UV)LcWU2ݜ*Yպ*YUrTnkF6o(lZ?Za)Zv;"9R y"AmE*MVIakL֘N 5jkL֘1U[S5j9d-;5555R5R5R5R5R5,kk*שȬqY'NS:M#ќ:>iR^@:M5WW'>שթ1LsD:QNNݮNݮNN: Eh]aNNT~V~],ڑ7ghDdXenμLF##6fv~v]bu3k}.{gە]sr[lWUVeHWͶ]ch)vmfo氉6CMm ǰXd*,n~#~ofDE3j]eY~ͦ*%JRf-T* 3W7 C02 j à注bU\gT3$ cP 玱Bfef~ Cm*UƠF]a%'v6B6.`fA% DUO1rw|鳆5*]5*]N 6&08rY*}"U7|7PQg>tJtJtJڅϺ1;Pay~|]–B9\sPya AQ~j%9u(L8w6$f~LxbuoKP%kN3!;2cX2LHnFh K%D!aLTbVA\a.+*KD!QeHTU w2,u1MBD:Շ<|VE' |c%g-95BT_C>62ikݚS#kFpMZ5kd ת[5ju>}mӾ:'<<CNJt*T ɩS)$RX:YF,D+65B7?H/,$@n) |cid)l'VL~ <(at%0'+"DD ǖj-"Ҩ#''U`"DPyDt){ݜ0"A9 q( }3%5'q< 0Dmz]lST=QGD3Zq=@_DvQED\g6_Ce͙hܜ*!Bb,(:}b.+c.N-&%(EmNDaEEYbȵC/ys'/Chflv-lT%R%g'-LNDU$D.Q&U[*D+S;t"/%Jd hh/U`U"XV#m;%;%KԃJuS'0f=P&{|R\zX-|VKs pV1KyCΞ9yo"D䗉 %*׷]X RN qBث$Q=I>w$(8 C6]qI\$DU"ۨZ<%z_.ߜ;U-VqPQu[|2F5y0Ϲ"QGT3Fu]:ͩO+aԨP>4Tf Q'X#hf 3q'lqkx 0|=J(luINe z^Rb_/|SizJkTNT&uթ_auM6Y'$TMf D$dP |R*.NJoJvkT]T)#mKrUaD!YψR#J-QjR(RL˔B+B`S//ͽLW%vU!yU( I0 ՜i*(J "ɝ'cR B{"(;# Dq^ 'QTO)'eL՝ IvI!^PcĆ難 /LYŶ=}OK;Rvt#mi_DQ{)@'7ī}IaǺmԗy#䖶\ڏ6*ummmmm;vvuMڏ]:*j΋?8ldkT2kZm l`ѶSd]l`[Mݭq!71(eb?V5;n?n[Evd?ژm6ne]wŭb]uWܺ+vݕhSRwK۸UmUm̪.Ǫ6nUcU˱[զZƬRfVV1Tٸllj.j4ٷT9a1ŤWǚvṇ ,m"Xd*N-Dz lZav۽$EhۖЖۖЖP*mZh WhRXwfkVºK5[Zs<:r.G<.Ϟ6eꖶZققͣfl"QTm`A.ٸl`%XɡyTq>>rܸtc~؏5Ko[ ,vJ`- |NǒXvKWXnih?ژSڦ;Gꖶq YR-qlE6fK-٘E."MYɥZƭdVAOT.i'% ;{؏b.^l[ ,ENE6䔎l"Xdñ6n%Xm/6neXVvVq*6K[VU]Umܪ6 RfVl`5ju nT۸mm`.նmܶ-`GjB5ǚh v?ڌ=Bj>b6斶q+^v?y{AXvfa_G*#cRT]EwV),ZpʷsN&9Φm"e*);ִmB۴jmBti;vo ަ\7vo uoVBEEjQ+c~t٣NdmQXsK۸ٽ-{[9TQ'{[dP-GmۢK5{ԉٽ-*;T2<ُ =e;b?VǚS:ÚXґydc^1/lK6%yƭm=ԲyƼbc^1Wl+6U;ZqJWUmWm̫wjIUԩAqZ@E8LhV-4Dtk%QMmNj)mɈ~bVRh1-BT Wj&޿,jKP̳H2Uév'fR]x򘓩<c`Z&Yp-|8=K3t  px/IpwLujRp*\U[LVE+œ4dZ*5iR5a8T,eL8LdXC3X#acf$Q1Úh$ަ. ';RQ$ii6Tk4jRaAh4vg_uYf4u#%ڿV240AWE$T*fYĵIl4]ZeCy[NNWke˹vET=KOa q™KǦ0}eTzF;H.c~ڏ5tN߶c蔎l܄G▶qsSGcT3NLڏXrKXkni7A5٘)6njLQͼqT36fK[ɦZƬĩ]T=(, s^^=I5}}ͷ"xJ=7^ǜ2̽u/zvOQ:nVE2VL/֝Zƫ)'qjIKF$J3Mz#|#Ns?'ZRG¤.͛V0JxEj2ncRv_JR2|p8r>ȕ5,Y.n^T='7^9/i)T$5]b<2t][ڧ[$CN2>U&O&➐EKU8|eDrGm=ҹs1tJa{d?NJ[ƍN1e6fb۸)LB6nujuK[ݦڶ IY9<+Ylyyޕ˞ϻt͓y+f;Okے'5jiM-YJW=ܩzZS-{K{SZpiM+k5wjԼVpiM+k5;)G78C|0t:vs&2tR(*R 7Uʞ,d,Y^LNſ 'Y'ƿJWy3}}_RhQ%)]\\\\v—(,m %ØE:a-a,_X2,}K.K.Kw3L|].K.Kwv䲤75(7'17_ݾ vS[<~^5@M^Z(ASA"LYi3p![Md;qVVjs`5P//VR[VxR}_*M}樂I19R d8AY'5Pj_a\=˒T2,%ޒݭW/!s/1^J׬tRzC\ArW "WyzS}+%yKIw*(Xy˒< V`&N.ɣ!r X8(<.b]) 3*/( 4pڦ.w@Tr>V6VAqN %,);tġNܙq/"P8|]Ȑmt%AE[QrDCFZq0x\4l}e T\Dgsi*q3jIf1 zEϠ˙UB20sէ<$ xPFYZ2s<4?"Ra(|=5c_.B_mOM*@ OiX W DN>MkujtUuٰ fJj&P#8ΓgPQPf#̇ ]uZH^ %.JcE-a$& Np+oCS9[$AJ_X2C޺8+)kDXpF4 WDFSX+Kw+4xv^y9 χ<8O=ɒ1zT2Az<@G%"c)4K)~._YPƃ%e|ʯ[jdA%%MB_?^^ /juvjք^>سkJ&3]ҽ%>JH| q% +qe؆b\AIiFVFIM3|2,g* ,T6X K<ձXea^Qza),UZ2,%{J~]2,,i++vYrYrY˖ K| 0,e%L彁VF(BXxީ_d((BF^֬'PN 턾:J?aZ&a,y|{VnD6%W*SxY -K.K.K.K.K~Z5NDkX1| E<ؼevU+BBj"P3[("4CVŻZa56W(vY_LWrxEZ\\V!n} J~ʲcIRyQ_u_")tĸqm[ǧAmnJ?'_ ܑ*S(Lmd(72w_8e?2\3 sw,@Ϥ#cW_һP_/KxxC5@&2wMfS6Li" W& s8Ec?#Ɠg)E&|lr ܁3i eʦ/ޛߝM_ IV 2Y8$"$df!x6% 7-y)P6қEpJb22) Or!vQ;#攛Z9 Mf27e];K9(3攗" dF5|6"}eҠxՄ=gM]8;e2O bY%LcA]923K3df1lڝllJoJ];I`3L!v76Л2+oF ͆< )l4$1+kOLқ4]qzx e6ɊCO3;TB0jψbv×}=!jؔ"Xz_ e)HeM |>d>d!˾2i23LLM+\2> |P `jV)7~|Q6}AYLoҥgLmW^Ҡޑ2ّFXz M2ggQfHxuM3蛴%ٔ kٜE(=Z|x'"J_I_f<7%!N˂ ۙΦ ~zd#Y땸/5|/v¦i?mLZƦO+Xe{dfxK/ڞܝ2_D׷&ִ/ģR9 bE4dYS$d)f|d>îd?2 ;GfP櫒æπl2x>6}Vdf`ۗM3RXz BRIBe`*>=3虬,PgUL R_^ӑAm~vя '{Li ɡq3KGf(y/&3 ͛gL:2s07 ek!3:TA?iGz=ltc/ ?˿?UުoX|3 a~^Fp9[bZ.]VgUTkA*QՠEQ?A4@*#Ll)1F\Z鍵~A>l:-P+9lop+ btX_,NT)VM#8x?ku`=> ;oZ4zq{?|q ۽1T݀ a{m}?Q:tFu>'A}x_(hZ?AA`P&jwwr㳃Yw$?9~rx~xr||ENs]׾1t?lGiCh"ʒjboR'X[LJ+ DAc47;w#[dl?y  w[Ӎ ,mMG·~f|a1,iES+ .F@}hT)柶[j ZI Ie_C % 0h`u/^0O6¾ɠA 7nt5 HcnGb *V;u "jjT[mLhXfǭ 2(~k zzn~sr Yd'AqBitN ՁD[A?׃p:̹6`f:zF#af6ux͊Cy:=\|@(E@ =}! ہ`x+9=~8 MQP Q{(V@F -+Ig6:tNn'8vx<=u /NO~9|r$xwQs WH =8Ypr>qt%Fpxtyp|r.>?<'Qx 'Oqߩ֧XSrOB{wz~qw8}qlh`1Trp|=;: {|=>:.966GًCqw %x|ghZ瓓'D賃_`D: NΈNgP"Hz|qvHD;<1]ɯ@`;S'tIsv~z2#'G?N֯gf;(_ )H@C 38T{!6D98;.)f`/Fv,뭛Gh_Zv A8cr= cq{8nm9S@LF7Mx)y''d[AC޷0TܝuVΛKPg+dލmcX~į5<| oB`,VoH0~Dh "ױh jDr`eM`2ʬr0$GkX}a[r~ dDx-Vpi%dvx\s2>#8o`CrM7-@p{YkDe.Ư[ԯC/X|\b zm}:}MˇRAtq&vz`o! ʯN93VA~-|j˩%n>LZC].(t]AxMwP?CvG GlmQ8I3~D`d"NauAi !LgALhFi1دaA͹6Ɋmca䁁d jz;AC6f߶oq)Ԉً;rٹ =N;# !)`+])Ng"Lǎ2Ն"hX8gx`H *١o6 ( 햬=g*QevݶQa>.Laacd~'\iƘR8 F , |;A'5`$ETݻ7U5Z-/=6JeDZ];rH`m+~OQ8ǀBxęyÈhؔB+Qk{!Ղ&il#iɩ;N-hIP+?lnWlvp6*Z%؇[Lw?)n|Gs[,EX_4 &K{S1Ɨ$^0a@xgN򉢿`NN0 aUCA TZvǃNeν{Q`[^G &9^ U.g*ߓfSSgn^1p ͍`5Ǔ`,FˈFf6MmQddFPdiҔ{D7MPrEg`p15$Azhz؉P+=L%cAXUqAP7Ac (+=BF ,IY8 _߶]W?J|XC] ,C{׃cvG$@51 L0 *HCM j<Zh%ty,5)G>؄huzrY?bIZكi`Rp_r Ò $ 4wߕ>h␱K\0P0|rX,R_TT&ѐ6O7J4J#GtgE`:>v67ZX ײ" [pO^1W'W ؝1-EFgiPt7HbzܰߡT? "j?tz B eL ivy+%1(nv&` *u(BUXR30upՙ&3 JB2@j2+$qBL]Q[$C@a'*h۷kJwz6MduHYjjncz, :qURZwFbSu]aDgcG2Ul@jh(Ѭ=d!FKDh26CV|ɵ0u oi';Uad6Q|2Te̎-e oYjk66oiKLhdl)!i;=>.ۧ΄s̊ӿi% )֌6vJPDCoAT4oR`롒|ܴ{v[ |]wÆ7hr (勋<97O˭mnhKwtb,W|_ $H OOz$I4D}P@ vwXAF^&(}ml;( N0;:*U{|Vh uzlH[@c2Z}%< ֧A#&F}hW6v(_SDPpZk`K6']Icߚƃ0t‚,@nP)rVNn T-G5p-+EjS90 zZ\no6`%L^ \ CTq:J=;;Jx\.%E"g;)_r5&:I.@\>>;բ $ArJg`ջ\=M]-˫NcsҼy :0õQwЕ%A|e94E=#3 pK]C_=Ҫ^EgEũ݋sVvbsCFH BU`эSm9F-B LN\ar𓌡'  QAl >A^\uQ(c2suzSB5W{ #w;2E< <.*RwB2#ђT}S_AUA/2|"Et_t%%o+"!,*"-H hBH`%@SP!ܸr"( `яr+ ʽ KAᇟ^Hc-hk $_!V_2Ύ#M,K/*1&,iRKbSR9M"a%&7 _TN~$R *Z}˄3 nnдԑAPЁyEjezeHRZhdh|0vKxP[[ &T7₊n׳.޳ųԻe3G-:da11{W-URh?^".A~,8 9BݼM)w$}?Y(g4st`{AWl ,>j 7[T>Xjeǃ;DKnx_YrxMv5{3/y I`^k6rg1_~+B(;F#.c$&.֠DIi{$CO1qtMn"rn/,< +RV%h${~i &1`dؼqU6S"Y8!8LB&2U8Q{XKOR82 ~FCyXTtM86ah \dwO#g18Q- J?ް^ަlXf&ɬbd۽Jv}/roqV0 k An*Q|UV4BbjvjcQ&Q&#gHbgz(;p/65ayR)רɓM &;Ru#9EW=(%> P.ڝ4ox;E#X. ¾c(c\f2ؙ82Ϛ^|Ƞr1gX D^~ɫԂUD^eGFapB$OƑx:Θ3d" uf#8 V:_|%ktPn32SLQ} B+Q/,]uV%V %frHΙ-jYHl'-o:_tRsNt_L"3ͤEEl>?9Ջʼav VtwrBot$>F1a&~c1zuGrk_Uz/_;(w2\sP*F_Z%ӄ@̫[N=@- JM&ќBJ`xEm֪rsH&l X*$? JojFFᾟ5:߻ ΈVM^cxŇ A$Dd.:,/{0x"fᕀJUC$kiS)Rj5Psf 0#Ʒr$d q(ƑuHHF%r5(mm 2b{h l={En//{7h9boJw9bŰYcks _/e2| Td"щ狆fsc*eN/ì)W|ߪ۩g{/0ڗr??hiV4詘\dx4/;htv{~[CxG4Џ_}ߺ.K 7 _žz٫˓OK7 B_U?{ "cYA M1hCKzu6* @c)>hW>q:xXMnL^b8$˗bܡwDrP$ #'uy&'r2DX\o^ U8Q☦tbW" Z!}dGTn/-k ҌXt1Dڐ8P'Ob1- J0g&N/̛F8482Πf~ĂZbkbPsn:Vn惹%vOy#RX"xX3<32WGTjawVGBYւo:&샦U4z$FFbr1(L clIiSN$ߋO\ܬ Pwِ?QkE3 1P݁8  \NF72?`W(UѦYy~XPS (E[ZZ+!(yUn 7H(W֩Щ㚬v!/GH X̮ТP"`=kp",R kjXQQSW/56Y3t4"k0Jń3mskk]q"*u0]DOzFv93Ů)v6`;~nܨ`9xECw^HMq moQUht`Շg@62VUs2EL5[q~Q9Vvti\,*f:&YPy$rIWGSzӑ]t`1yN& %9$jM+:iH[?+/*)K@8K':Ys9К+?c|oh0 +[j9]F.#e2w]Ff57xGݗ7p&I@.OPq{T&$gWVVd%H +@9*D}-Wý= V'8K?ɻ<E$Px(p8:;\'Сpl/(KO'2? 3ɡzV0 2G1KZm@\?99| J?9i SGrSxF)<{e rHq- ܦ)LfRBcf7!# x#lrՒҹ31;&Y0D.Xc[YGcD+e{=ٍe)CRgB+<)ӟ[GqCU uyzNšLF5*cB,H &CG|; SKu6'P/|1$º9Xf߽ [vhɂL|HGXk`Ofzf2JhD4Kg g8]%7eҰeI4:K>-0'풮1d3%uŴ(\r%J,C_6f8e"l3":ywwH b3(Jb팠&hA:΂@N ݜ M9i?+8D?ԣH{R7X-)hW]|@-^c)adF⢁ߜ k$G:TL>t6fB\;mwt B}3 VKVUGc:m63{rKSw[.Ja0w5tIy;}"E578%一L$TEl?zT;e?;ormKr\e`.^9ou$6 3}f^P]Oh>9H[)6R< *]!CJE_;,Cm톥_.w\/8;N}KtD^.Aav[ͅ-)0.xC6/ưE;AV]=лvlUJ͎npe {L{codx~,xj=^j+0rZd$&KPfS*̞_9D˸| ˿+MT̓#!ܲ6|'Be>ݎ؄C`XF@4IPa;>+0A葑s#ksHת8ƠeWn)3m֒NK@*qd;,ؖO,gd|3bJ] RG׋靐T xUC <>taOw]8<&mLX$ mk?GןڂxŶ~aj |76SBiT.љ\j_ֵ8Učs!u5+6QAOlc)7J|y͔曌߹?_D3:+4_V+W,1i_?v&L;gWi߬ |-!>+sZR,PlNJEfV8a៦ӮD @'yx>L`E1+Z`WI+@+hlLo<ͯnӭb QW>9jK玼q=wGu }m-Fe'e7Wqΰ\gX3|uӚ䱴Z:gp9\p!z@ߵ&Ԛ MwZSOQSNfiLw#pnk 5[0Lƃ83IQ;Sd<25Ӻ튲mU_>[ߘ4GqJ̱k0'C$o-ngF:סVsn`Ui>>`xˆ:1  `Ao>Z|jD9bdkxCġ1Q3gIZdvQ{ hq+k 6hljsjCn:-uJ\ZĪML"F~ZI),SԢ:eSTl5xAuWdΩO%0$~jCg-9f  b-ɹ~fY9F-tg;=~?lf4Oи;z02j0$^6Gs#QXw>v]Hh?(̮ 0`|%O?1!Ţ;nȻLl /vn.1y:QM9^;ǾQ7`FGZiq\N0t>Z]9:#Pxak("o0gQ-x(jot1|ɫ8IYrnD5H@*t6c9纒] GvOBØY9~jȟʏB"K"($#fɱf8oag:;[p mUHܿĩ$qLfA#(di]f{MI-rIi&YYdq9%5ZΒ"5<4x77z,+7uM Qw7Eݗ\HPCpLFi8;TuB z c8] bɚ2 R)^؄oE{r; `lvi-6#)2(x! HPMPLRj``ti&f)D%т0iCڸtt&g=+ ݑg|Zc<7Zy- ~]JMzk,weYݡKf2yqӏKX&.Prϐ?1CÊ~QB"Ud҃3dOvTZlA4g+SIx-&Y#2j[ c簤IOo]Wj Xstԗ314:JTDf(Mx-ustN^ V\;4xZbbּ,/,\2/ xy5.^D]&"U֯^K!y7]P+VQJeTT@U+*R9dgKjU3JRfӫmh_801f?3 uf9R+(Jb,<iX<gxO!oGO&Jˡǖ@Bd&uħ7ClWNIctWa 9j-I*#޽{f:k^=V>X-QZWK {,?|,ÿ %*laKBĦ*ZY s%uMyV6_>PII -|1 }zq opoG{ϟϫ6;n'zrL2dXg(\*f/=ccZ/n\L%;xsPFvwj+&s5]eRX̛O#`YsB=_oU«FR:ŇL@@69zJ*1NTCח>[zTժp|}>݉T GE93/HY4n!BUnwQGy:85ܺ}7͚)I''A rȞMe9Ve7|w{69*[$u|AJEU 0>QO@P]Yz;}RO5$A'[c3ӲC\M/QW(=tdDÙ)%P-Ȯoѳ\T\Ez#־p,˰X|%mvZx;2 ؓMu6vF"zM+6(֥T.+ދI4,x H,A8nچES+ .F@`|^w?liA[jB:fwB[א3n ? ZaX` AaC2HntIEkt;-cLVMp Jmx` US sx0A AvycbR 7p5J=׎ Z7V9A,E!e!4Bfu?Qa-!Lh a+@4#թM\zxޑVzf>y͊Cy:=Mz PHhmk#\)ω%gưM$OhnbnCb7EhhYlO:fѹm~ %GU Οg'O;=7X>9x?S88y=9^⏃ӿo $`; =ڳ'E sDuv v3sH $k_a ;xCW!xv+4O'x`4҆4Ư  DpeF<`zxZ|t3A8vx AH PdA r E@g?T4 ht^o0Λ[AlBBzCK1T~yr8A%lxҙfj{HPfé ǁ{5 4sIokֻ!ݙˏQDUb*&997[ U zYD%[q&_P8L% ׾zQ:0RD(3|=2CHw52T wY`r#%xAn/MSy(r/Q0r4`rwt?di˫~7jBϷt-[A6]Eέ1nI 0.C]2Mq1Gjxǣ0=bDki}8/-ϵ` fBc,ЍfJb([la^ip4Bnj]EDNN0Ee_m2 ((тm&InD%O N'xvdّ9s< Or~!F-B2G*49J_S}6Ga 7`ѨeAc|Қ1$"u{xע-n:Dx/^ IVk9? %B7ӌx43&\,$ Jnq>4'C\AxI"E.xnqq nr1p蛲pE1Cdq#~5$hWE#<9M{3XXҹKgk@LH8V<9]3a, Ne7V&vC+_NaH9`4IX+a8 Ě&{?vIKDn)?`d6aJ&!V;m3-R(+/Ŵӎc<{%$tQۡlZf"Qx2k(X@sWU@yƂ4\= Dpn:tlߦQ"Ah8y n=^=7ZDr,TSr]?~grS-BU~-KRcxO7")'ژ$>\*G2|Xu 1k#4HJ\aDAf?BUVmv<8ݩc'v yfxXJ3zHA`"Wѫ= k3'_'l˸j`rβ6L om4wSОxwWD#)t&Z[,=VӭX ;yv0=M{Dz5?V.F_dp.Zk4Ty=>jxc{DO,ӧ\//GHOqM>.\Z-KhظV1pe:j} J+Ii 6=mmuaz[p5^1cmfܓaZ㇋-qx?PEoi[-NvG\Y-v}(eb16eـ1#Q($n r$́B^5Kz zyqh&wɍ?1k/ڶH35˾Ym%?zc0/.ԲHWҽxerO*0zkْ4p8Um \F(me bP]<3Y`aʅMpfLLМg.rgqbFH]%8iT0s6eQ͡E9&g $Iym!y3fr~a3a tZO: >L=7 Y%6_Tע;ՍCy:D=ǔ:m_R1`a:޴pA1/}{p땊b-k Xk'$8vd%/-5YBg#$/2<70ʶe 4 C_N鰝LJoȻV~0b')hm(^qxO>ecJcD}J֭L n9!Swof,K6^Ghfiٌ2a eUCbRe꒲F4 ds;I,9coߧ 1T/48j %AiNl2v9#3-6K6.C3,nf\L4'izLm. 4Gnw{$M ݛ2 WShjnvTsyɉ8M+-%e5wL0ɍXe*&(,S6߭9yΡssApٌy/`emޚܕSjKY:Obw#ZKsEz4C+3Q5;_sdԼ;qg4_|8e[(LYqg14.dz]Hgd=])!+$={V.IqM,K[UL$B-1i]TJJ+P^bnG<"sCr_ilo_x{I֋=ŷiJ;b/lb*N2!/q /{i^i\xz~(3KvJ.?\Ff(b ̸3=Y fphj Q 06hQo]ڇ\C&Qx{WFv([cH/-ȸm.ڞ~58L1a ; iLKKfT@z~ lFcJo/BT$ ? =#h}O7\-cuWҸ>kq1&"'4M99&*O~q_uiR @)u/,S\Ig9D΢4yz¢M,tHX9I bYWOS$m@-)IWUw" b9&['ra|G@2n&F۸EO ΏXc-D/qIJ4L/UM9:7eʼk;0 ,N]u=}coC k±q{bW'&}޾ec?Ōwr;u_ώ;/~^:Xbw⩲@qҴWY5 O1~8̋Xm}zKߤȸ? w[rqyOkp \]S/֔Xg@*;qpaJzNlYHٖg]uzV> ;Wml[Ѱy羐ujwZb$R)GA*Qՠ(&z> uJhK?5 ]Ǽ>lvAQX_/bq' 7 ˊ^1U,] 1h]&8]T v*51@ g7`[?'A ypFF t:f7 nЎаς'h''gwX?4۽Q;8u훺~-]ЂA#Хhcӕ%ո;68>_)l ($ `(7;w#[dl?y  w[Ӎ ,mMG·~f|a1,˵ QV\a\4~v oY\MZN^jj3n 7;_''faٚr c pv.YOTa }iH?ZqE$,usmp:z]PO;J\lG4YQ|(oQs- Ppd$@qcDe;`x+9=~8 MQP Q{(V@lT%,BCJe+x5m{x0 %GU Οg'O;=ӓ_< ]@T;R{~k,89 8:t L y7ɹst2Fyv)< ?ǽLJGZcO= i jlǓóOP}p ٳ#ɰ ޺,a\hٓӃsl$l6@}@ FwY!KdО81,2abp;?<8?~>9yB>;8Ftqv!gDcN/^U 8 15Xrrw!+H=EzB;qf9;?=?gsßat`0;AXcgP  O&Pk/YPJ:>zKijĦGڼā!$&?b0Z* /=/2I|߉`b5؝W4 `n,5(aRKETHvUu\}W4H>AмhxޠZ5"P |LGp~~i}tQʠr n@w6n>/xRmW.-c@0OQ eFlJ: fAn9&Z CwWTu8,-' r.' r~@r4nd X;h2E}hiNa=@A7hHMnpv`j|Pxx|rxl?H9C,vTuX|BWy:M)f@{P NuHBUg Pa(!ذ 3p!x vr*8Go[ZӉoF-[*<+} :Z4Źz汻}P+eLRMp`]|a]'2Uh`0͞.Ł"]x`TY[ZBaIqT$\^g}%`r,Z% X.!(=ݴ t"/z!jd賠|t%&OP̮~>; 9V_TM!!ZKxDh #Qy| +ðAC'腂7aVaU0G\B NwU _KD8w#,2FK.0q^5llCl[+3QXΊa'S4rk5ʫ:vN^'%y43w&6u~jl6KЋ>5L?RX|䗪Y㜬ӂ,^*U ЌtSp{|`>m 9$T(F5G%:58j3Pe,Z /hLuTh!QѰ3.oc*C y*H0-/qUl8W# %cqegfLAw.#,1VRQBŖYqn֣D2I3t)]p 1K6̖YJCDHCi93DRH)ͧXH3B#iלwaqSX,KWk9hàܜ#:5 1!a"Lcv!xvG(ns U*3e6Jlsw0uj$8M2Zr~XvɰKH4AԬ{ts5le^0o.҄>IiS8"T)OM~P 3cK$m~ mAx /deRL’FVBZJblj2=MQ:Ijk!#TVؖ#4nWL[-LpǼMGu+4^B2FxɐJu z+,q<6U &cZ ZR .$0C[Xa4$i^R%.y@Y=/e୉cȚWiJ(MB0ݟ\TiY/TXvO(~FADF }wv:|" ̀dUӛ,}c+IזŋSX9kUxSpI_j!+ۑ^v0G!8A@G d|} }a8 ܪ'~tSxA5ĵFt[<;CЏXD۩!1\CuUޯ'BSrhPX@{\XjE5[q#SK#|m .ʁ@gbhJԥ(+2k ة\u-0wao0רuf8-ζ@̮Jz&e9TWT9b5 ZG%@Dt~QqtVSWa'5z#;[!~cKw2 $,p :aCq::d& ߻1  39.'}=A<+: iR9^])iQiŷ!V(U+}wqR^ej(:f8 pd Y nS2dI8{[k.J{Hi]`Rk)3P<]sU~Qpk GM-`rHJ0„n;X:]5QPhzv%O=MI2Xڧ)O}`Su@[IBEE(# 7vy"fg4 ymV"/8 ƆSé,8dY~H8)*@UqP\ê`/*oF,0?f&47 ' θitN}=":Qɧp?$bnO>T(_n]>Ƌbu^ꢨgce멣npsawa6יZYt;lE ԴŐ8ʎkh"l>q$G~YbS˂l5BX\)E8TwMCFlTp!Լ(dlu !b cɀxכPgqoQ~~?A 3r E v}u$ົ%uzhpOߙA0*%7\vӠ2*/X^RȆ*1@Z(Hr}{ ZqI ~$f յQ^bKiX%VUX5RD)}Gq 6i/Q.q+AMMI3MGszC tޤ$I{M61_]Ȉ_,u҆X-ئE}QdG*XM$7ھ7Smcߣ+Ֆ⿉e2|_F/#IQ)G.l-}'μULSXag^bI'>R1&v* FIہ:渿yNy'sGml203> M[TJ0`q9`*F=*&y.ś܋sV808d\X|l|9gvi%_$Nz81/q8Cr&V!+G Y$cٛtL^yGUN9Aӂ4̼ t,No{μ~]z+E6 >O_D ]Cg8SRəϹb~^#Gf榅Y_잗wf̓-dQF`PKw { * q>jC3QLG_8J"=Kzvc Ë{?tېH\k{UV~D(̠QHL7 CoMW.wl+$r37ȓ5Wm|zBzJ7R $@sշ<:ۗjGFt($>x\d|yÿ m p$Ei&xXD@Y[RA"J(*MsFD'jTX Гeyʸ *[=dIlF9 R?yVb2zky \2/ 0su_ &n|u0x q=3!$8'4_2JAy"f5h0>xG"[U+ux-ևmYb_!Gu^4?y}&h.+WРVeEjSI UFh|!pSGΜ@qW"KiiWpA`>113NvL,.+p\AchyUe\/BN&"D tS#D^+bOjxX'c1u [] H=%‹UGv"۔lJ$cHPZa0FDg,ԌG:#oxf rJy]qsgǟ VKn_9\Yf#'Ue2o[- NӅ&Gţ..zj'ő/8R4xAIR2]q:#D@煮0P:(ӡZtip7ȋVOjUЏyMWC?Hk */ĕ0rםj͂oV `v>#$P%"8acsdK8'dX^f(Ƒn2H|L8.O1گq\fa/Dz21|C-tk9D5Ȅ]ܣfpqTC!g_U^X=╾Y8o)j/k ,! 0A-0X1X3z آVPҝ-8ISe?B(;-jq`}? e⥍`5'4Q-'$ KAIf 3 ʁ;ѓPL4LQN芙vk^XurgO\x{+ŋEL<0U3➢\Tუ1}0e( n(Fu+Q l:N0*(;7pF"<;S$EJHT1Ǡ59xY&YuS5i+YLl%0BXm _JL^PR[#WWBY5,Лb.u|3ĥ1K+htw1+y;d#PW]3*j/fcF* z{u_4-2NխoA1jN19bv\TR$ /dそǍ$hY:{'S ݢ:9:eA"qzd&Df.e iYMiOo"V qPrU9i-Q E޵ DE:8JSĈAyE\Ic1kq]fYWbS Ȩ0"fKw û_q!jY*L˓2Uȕ|:d ۫#~d:K{mO P&\NP׫RTl=(gѥZ&ȪA4ZЂ?xxtcNTdSy.͞[,ƂH塕"cVz~o;fYGaqg"O1ӔnO 친ru^G|o[&Z( Hy45 ||@D:d*D~"LbC*JҲ\Rt/]t U**'6VzҀv[Gx}0g[#*CF7N&)m蝴VV\$G&NzueP&6Nŵ 4U=$H56=T1_pMu-0ލ$ײrTLXnMW߮:/xps[78RWZV [ޥCQ%fV }ÔϹf;.sXLq? SGdJCALB3 xx9 MK27f0MS|wfp箠}+ڟf{S,0ӂ#-Naw 5*X%a{op.hD<"JFlٸf\ToScTa эo6 qgؼEJ^\Q~^4b6!ueB8UWׯ6#]Գk X sn2&R^r͆vXvIG* Kn c&oFSd, &y)4 ?;q#9@GgJ|ț{a˿O7CXA#tJg1,JXY~@-:V`e02t ].A?i0(D`л'.+%H)MnmWawT)O.HReLZLEi3Ԩ]R8h`~;Y6Bn41G-b鷿P=7o5aVrp"VV#xF{%q'):Qy| ȏsk0zʍiu->}>aLkW%jen2ψ`0<((uZWC%w7?:~~8}VLYO%m?-'ӬȶD=YgC5&j6r.&s}?RePrOud#O[/f%Wi ;@|ZH=?q>~M*%wZΟ bݍK?o ~Xs5,;&fR7.l9ah\/ه@x?l޾@+?X0XJZv>n/=aM-B`_a}çZ yF״IMf?|`j&O{_ӂțix -߳$oo۟7}Z oQ/.ղzVܭI^5_yأOX@эƭ p5T=̦uirښ|QidiSk3 J3~  WhhY@U.-tj얖gic4b~jι <~ 5@gT,/o l)NV6]?b}b:9bW=`x"y?KRωS>?|E1QEۜbV_@]^YgYYa/_yQ|:Q1?c,35Bi#./[$H .GG͗e^l 옄v)?]|_C+W$?xR f1COKoǢx&gn31uf ry)uA9}6YF4~s ]gcm 8k[6{\$~j{W ZepD˝?`yySyyE9T,_~P5ZkhY~Z0}m EC-SZC 'P^s#o2laXHD,ϙ}1C֑<6%glX=%)V to$[ !r˟!͹jХEUii/KymQ^cN-um|e 7pFo{iMSr<u1;7kH"sfo\**İ/0n E:V-Wz]^ANg]Zv7yFsMFKr1JM,?uo40 [gUgo o?L|o?Spu?ƚ{Unf>CvU`yX<{=랇uúa>{Mr?~YayT> lyS0_#Lsڭz dU]sx/eY%#o~x}_eKld+#=OV(0S`mڀq77~ NW&z ?S>=7OZhuǤ"1X5iCPv}f5ʿٳ?h:??:y:O]IcM__~_|=o=_~ 9OSNW3~g_ 4;%}?E'fR)YD_.[%Ğ3;~`SNqm4k\B'+2=}Br$șȎ˗g/vw~r8?O򳝦t3+ Wy8%ߺ fG;Z͎2}X;GhxaF9f1O?@wfM`V~ޤBA}g`N|@"~# ϖlu+BcPS"Dw?MkG6-$v]zT_dCn^lt:ߢ#WவݴV qh"| &g"F;b^Ϭ qpkZ\ [xmJBn;m:HWZJ]i+vn/>< u5BeBU|@> ?J{ mYo(=(aO8R5b.RECe Q"wJ)ELEb|1Nyc6?TFM˗%F T.=>V.2Fe(ZE4Vs}\͐9ҐXiR{Q-FiH {ޅ!H+:>R!o1$]K,s}84>,Ё6C(/5{!ujj 9-i +^* ? E jݢ_s#ַ|)qQ<݅TyPZEaZN=˴=;ꫦ6o !4%bDȮ_OR2ADCZx3ߞSNN>l{^bv s*b|!i)^ s9+%M4uCjtT#=5_~RϐE^7ϝ 뛰~X~RC:*DID)@ cV'*,OoY<3x 3I; m{ȓv̓ږޘ͵ iw ¡ IU.I&T_+// iսKsVWkHicHF8uא.I/eTtVxZ' L2u!O]QРeѡeא_7\]{ṚiaNCz!MC  p_~H)/PArwaJ5gnHia\/B9_~+oE6wi_NPztn^!߅V;y9xz!{.rv2yȻ'՟C.ƽr'f^=K3Owta.Qs]kwKMZVri|.r0DIG껴oӞW΋RDrA{k+Am4ɌlE;o7s%ج뵕dž3 ۑǐm9iU}{%C:׷Wi_it^}\~{Y -gFHvMvߢfHױ87tѬ]r6+30f}U(srOQ~[qe[ 4YC P}h- o멡kg}X֮8&Au(b:IqȸI$ESa0яqqy{hHr6Q!Mo/௔YLgL bvXg&{ Flhͯo` {L.iZ≙l7b0Vo(^Z36N:oT-gw-p;ӗ=GwxyP~fc;ScqbMO'swV/JsιBErnMsj}{3Grȍ"wErm5/+˻:16wC:yjY 3H檾 dXsSg:HZrط \[ttڞԆg9s%!mN[HXn?w0AM ,7ӹkm`vynhNuUYnlPY?Bh~{TַSGe=*;̊b$B6t>>(q(I|7fb}?9m1Qҭ'#3wN6H6+rXk.@F&Ee<:9~>,o}>;y٥ϫDi68S8So1͊vgC|Br;[>g=R 2 >>ƍ7#1~XkM~q-_LOٌ͖dz:df68Դ>M kJoM^JL(-&ack]8vd-C~ #p-cSّˇڮHv+jC+ x{ [xҍκr{y;{$f]O$(0nlgڸ嚼y[c;NG{{ ARjӓ5[>vٛ+aGcnaM ɘ68ye]W؜]{Yo v7J5\Crlc<i=[2X7B zvs3Bֳo-C6Zrg1AM[Zϓ<ӆ'p絯sVueNuUp=flPٖq** \s\K&Pۧ~>swVThsPFٍmB 綟zL: zzkn-$c!8ĵ;|hɵ=esFh={Ms;\a_Bn%)N;FrMikDur1k"vuo^6l׽q}†VMA?sg;H5jzSȴb6\1sAsiQ_6mu\ٯ\Ǹ \#گ\#iDwϳ{dݱ^[F#qۮFОFtKe\#*+Zo1۞Ft 5;9s.խ h"vv{hDwhm5Uk !{-纚Vbl4=]v!FqW;^b}&V-ʠ\֍P-ݵmO=]yh3\[+zkK=rm.]zMݝxQEח8ĵ[Lz^Xl/-wc*.׌=z-Ҏw)w'-r]jONeԾ\sGeo;-ovVU9=5eO߷oy-szw owSZN  Hv$Ƅ;N|rjYVc4h !?sz{6jc}+16 j'Լ]O:wZ@nl9.8tcvF펐ۑv5M>oqpͰsvr{>(l% [R&>>힗]s]o#l oMn1h:fGrwgܞ'2p͔oϮ w/S7?W})uovsw2W=[o_r ,o}mcYJݞ@YyyľN֞ oQ)l!^'un=%xy6.oFNٶyٙvlVr?n?x_zhVݭ?y{cJ;c;|lOrkg|Z=%a[:[ݍT`hn[_ޗc8ڱH8Q[?WΥ:~8 lFAoo[֦`O:wdTUS֩wF;B'o,V% ] -o[Cm䣰%}^vg?[K3UpMKݝge#k6 ܝe=~ GݝgkZ2r[_eoD4c?faKڍEk=Q /r?N;֊{}/hyk]Xm$cV疛4ڭvӢ~G3H\O,oO&&f? "0&#ZuxS1Sh"nwh {N!A{Nv!7g>XSڝqn2/;#4;2b#oCn^N?xSAp<߲RvRzYM#f5unF?y~6frط폐l1w<#[>B ZSc.ArM>PM;v[&ynrmFɽz0x6&Vjyxn*um$&FZ;4;#ikrn?dMnk&o~4y~M6vM6~ݡ};V+JK]U\iw!d܅<@rw.d؁=Ȗ#SfrwVB?+2Bq;ۛǾNw݃<.}]n܁N?{6u;8tq<-Ѵ;H 3+-OCJzc{ʠi-ɏ?=|O~o~{ӗ_}:nJOr}?|Wb0Lן>}_}btw_寿Nwͷߗ.6/sr-MЕ{|:D+  뭆{U{qyҖq&. $,w:]:UvQ:V:USTLO$.pե\ܚݠjܓ#ܕթ/3*g5uzƬ搦 r;밵v YFs5 fl Aڝ$fiH[H ESsT_4]aQA^\ ) tn^ }!>_̗r|)Ǘr|)Ǘr}BiJ(唍!r†_dH\J,:jX@bb)>ˊ~X ÉH}lV>*͢,zzpC@H 2J÷@HgRR*]SE>SAe|@> *U;jTQҨQE EYѩGQEoD'DR&(LTQ0QE3O9CTSeORN)TSe/͏RNhVM*@U6lUS:FU}lTSenOݞcc*FU,͊}eVS*[MEeL6JelBQ.; ]v$tI貓V.[]l!tB貅e tu;weAM.?*|@qA겍e6^m.'Gluk .x]lurMX %mkr6jߝ:O_OM?.6P5K%oC)>ǀveVI%3(a 38<=A[K" D6?M[b'J"a@YCZΈgkcz*.Ǜa%N #G2n3 8(YHÑPd9YBC0d9Y@Cry,c`c)*B,V}љb &-^ċxQ /@~]HwQ.ۯelֲ*۫R0ۦeôl-Ҳ9ZEeC4-e;lO6`;eoj~P*n XE?E?"/|^Rh;D ,"@YX!¿,eO@`ZuVc`L5% *̷|k̷vkw򌧒=k̷|k̷ i̸f\_c5_.b5] 06o6Ә!6t7kwؗ0Cj@m#̷| !0r26Vi5V5S-E䐧@f9|~z3N;K/aPgU;vrV~@,,, ,0xf {1 0 /Mi~)CW#'<  lb~[oX͆h H cXbX`X\X̫żڸrZ̫żZ̫ü:̫`2-000Bt0H&љ̀<ߙ00A`C8غEbvM!1Zb *x:<=ψ'-%?y!ĐZ "+-˯8 '(aVBYq[1asԎt4_Qw^v@>xcx{!03}QQ|%D{ޯwc-+ N,^ !^/OBF<쀼" AE}/bE 3 υ<7ͻbĤEA Lc|6cǃ!|Ի[<ƏV; s#>0$7jLbDo#Z~宕˻gqW n2P4`!0nUw޾Rjc !3/< ȓ %} |@6G#@H x$Y;>(dn.I$#bEt$\%y*c I$G" aɠq!pY@u`Fi66)!T &B 9L/%MO5!ׄ0_qK 1!Ƅ`]DΘ4crʘ%cB| 1&DĘbm 0!Ƅ]Ls1BZLq҈/ _"Ä;LpKP%n|[-qT/n඄n[-ږ0mK6w%,,e HYB,!Q`(WZ›,M&K(%$_b$KD% |TBdXrd߼R y y x x x x*FC%_-1 ^xkd nz nz nzJ%*Oiv o<11SSz%:ҘD||||||$j`|||||<=i ^%zR[¹KK8oK7v'Ku=AA!旫6 r r,YG43**llBlBl@U@cX|*X|*X|x(|yaaaaaZ ; 9 9 9 9UhvUdNN $PX;4CCƏFUa[ Vl k c*, T S @*Szs! SS"<*8FFE7Us.0q#7~#8xB$A$!=i±qʧʥ 薰 ǫy$n@cŽ,;+\h~>Ckd|983Kb@,7EcRINvGw!}xQ\_0$s oP۵!7\}'ws0adZ3(# OAxQCEHSxB$M(P4hBѴ*x<-bЭ5)/!sa.2w QPWyl635?MFAl~z<ԠIc<ptmJ޶+^,zeQtng@,**,h)( _ Za;0:`Ҕ1ld!ШFARRހtv]@thXg 8^u76E"㘥$,'(Jˀ" #$|*cYJ(׃ϥ Y.yO'J4(ѠD)wdO''v(/)7SO47ĀJĀ 2^$4Pb.4?=%ːgCcJD E tot7'pʁ|cpN5^ev4Sc6=,%bvXz}Bk_(^ndi-a%bEiv!ڢp`v(ڡh`)i2ڡpENXo<@#/! vzÏt@^FBτk7zݙTJAZtAG4b^$U!(!iʟP&aE!hlP",ǩ\1WTxj< O@3m D@1m D 7@1h $@1zb +h̳!$;`خC{ۚ`:62^bֿ~amW"j݃;L"upwڣ!-gםbe}>\hh3ё޵M 9t]U\o>;:dhC2vx Z"E_`ӭ{MI:[zyv]Q$`:v\ u4$#qIMBÏBVlwܼ,(!{|&/¼C=DyQCf;;;;; r5=( Y(*PC7DzD|vj+%@{(!{HeQ>鉢!{'±?=Dy;Q. {~;;;;;!c ~ ~ ~ ~ ~i1(Ô߅iA׀q8` DP9'/P07w}sP] ssrtKts@:qS\D@lr;l;f\y +ve;]~v.@1YqJ!YB |Hۉ`3$wDlarAAt D G H1END L!D ~eRCD_0P#`Ty|Cs!0rV& IZ2K C`l%LLL G~b> ̔u~ &&&&&&n0q,q,q,q,q,q,qҡEaYaYaY{wI T EŠq/'ZUқGJ%*QF%.-c(QD5J4(qHo(Ӡ%hPA% E͵(ڢh-(za [4סDJt(ѡDCu(ɣH6x|{[_|e@E|UîîǗP ߕeg\B 5?eԝ/- PpNZJD96D9S9Xy7~06JO W@>\faPAss 8K=l<.;+F%pN` p)X;D9=yS^! hŐ7=|0J 4 ȦSC(KxcO'ʅ`a56H<,<,^\<}<{[]ep I(=1P @9`rIRa0cHٖ-K{R㉶asؐ)WOu@;,uC0C]݁LԁL=. Nez)ʃL=&cXiаx{L CuЇxzxZx(?ۅ򨖅;b#īNc'qy=> c'؉x@v**}ؙ|曖 O.fXO3D %.,~H%*PBK`7[dVjQF%jC? EhAEmPAK[[dhPE%Zh!(Ӣ%ZhQE%uHthC%:PC6QGs=(ڣh=^7܀J (1Ā:e47Ā#J(1ĸiD(1Ĉ#J$Hj3 %M($?)@Rj e5 S4xZ<ϰRATŗa~DI-2ATDVj9 4#'Ii0pQ!ڭ )$27Z B[ARvk5HJuHATk50O )04B\ _ }ARk5HJ/ Qi($IGaR"ZZDܵ$ȻVtXDXV D ) қ0VjPZ B_ARVtQ! *uʀY)B_k@Tk H Iu2 *DeN[2jT u!5 )$eHwրZ:e@R4l HʬQ!5 * $Pր̺N[2X H IM\wk@]bl ьI!5 )UD8ր )BFnM{5clk@|lavP7!5 >v ֌smЯXSFgk@ƈl QgR`m4 cD{dւ F@hkA m-=gR(bgւ?ZP4B[ 2F|hkAƈm-,# c 2 l (!=#ԴglXւ{ñ=_ p % xRy WeόݙB.@4wiDPJN)333F.a~Zp[D!v]"E\o 0Q㡖r m"E|o89rA%8/AQ+ T -[m: Y55; f1 E(ѠDh\k\kB'(ڢ?&@7Q p,<QM E(ѡD{GMGM>&&@+?&@aZL@EPbQQQ &CQfDs#J(1Ĉ#JuH eZI(P"DBu p p 8n vZ555444.Nj5vwU歋z%Vj8"O^c7g>GG>G>G)El7(()d~8Ձ(q(a(Q(X/_/`9×''ʶEqP,趸dO|G+ƒ.mQ2s :`-Nj _*|%0#aݺ+8Lô:L4+8LjVVVp =hhrxiiiiÁVz⻕-;̟ü9L$9L$9L[4+=%& G]xnV`1[+1_8 F8 8 0 0 8 0 8 ~qt ݀ñC1I8$ 8,kTӳfƲLcC6-%`V:555 Hu=kvXاإأXXXv;8< 8< 8< 8< 8< n28G ? 8E 8E 8E @:a1Ԁ@SCvkk!tpppp% h!`pp`"& |@" k&!b` 7dR 1ybي-PJ|&6 6o$D 27..1I f0 "f ƴ鉢1[0M]# !b"f f0[4-CJ/Q6=%& C܄ +D$Xf!ffffffj4`4`4`4`4`4`4`4`4% Mkk@,@8R"=A'ѝ{q*"z,Wπ'w -bv\:?Qw-V֥V֤\%Z|gbaa a %:|]ݜ g"-ˈ/#2DwhR—e_-33"[T|~× _b`&ief#LD#LB33%dGgfyf9feD tQmeD_F_FģG"0ZDxt"Eģ>az4."D\9fDaDAJzD"zZkfCOчDXnFXnFb'l3"N\Dȉa&\3\3\3.1j6܈5YDę}X4f"ZjU*"K *"tKQ(3B މPDo"5ʙ&hJ%BcaGl],]#{CψwDHwg#AmŎXGXzF[y\KxmL*!6т(-,c[Ml!bu`o@zG bCX%T-ʉPRDf -FtfD^ڃhq@/Q9$:p#C kwkd0zG1GhP"#4)4e"#Te*耮PDǃW<]CPD0K ^%`I'BʼnDGpכUKNEsz' EQ\nʛP&SXSGG("#IV) gS!v)EGGGxJ*)B("|#L#V&uHA0PkEG"#\Vs i@a5ЇEO^{ Y]y,¾BEH}E( cXIÈK"T1dJ$b +@h%H&d`H*ܐ dpXV2 1$=e2F b@iJ2P_gi.ԘA2pPkƸ D ,Bd @Јf4F 41$]imf:ӈ["n5aР: wSqЭFvcMuH "BqZWD}h:{9 ڠ2Դ "Ե1.*ۈ+""VKOaR.['JIE1J*h|QEh$ z"T悺!BU($W}W/E(cS\txz<OUcszT !uG:4Pp`IC\D[Y G:LB@‘&!MMC8$ԡɠD J4(qY !u:PB¡(!M !u祄:4YmQEE/BHy*!\Pp(ѭCQGs=J(ѣD=JzʀJ (1Ā7CR hn@EGQtDN3FQbD%JuH eK(P"FK ©0x<-^H8@&D"$n Ih~hZn ̄AfB 3!rbFDD8%D"D"ini0!`!`t00pZLjs7!r 99pLD 4"" Ѥ@ZʭC B B Q5!r)IuHA\8&"j/FɾwBn$F*q؜\7:?}W.A8`'9"ā;!)'iD 䩚PM5PI>J21֠_ү4LAz' E&:mulaQ@EDp"}"֛AD()sp[4p[ˉJw"VG0^ VG"3n#ةn#VGpr"89Hd 7'9͉pI<ŊpIi[!:%iЯjߒ^nB$"\<7DAEz]45(hjdFMa'Q"ܣD0 Z}J7QHNqpb%]!eOR+F+HH: 2A|Xp҄ p尛/l'lR*U"W-Ȩ%Y\/-^c12KpH2Mo `0CL2 p%7FL2 p%`Cp J&uBF!8;^Dp!#\W2zd2Zd"\f?+~c3 md"X\.d!`ADL2 p%ˆ@Fp J& `D@FI"8z%JBFp!#X-~c+&^Dp!#\W2̝d2Zd"\Qw2O+&SO)B< O'E0J&Sp%=`rEp"GJ&S`E"IW2z%~9E`EIEգp%aE0"xZdJ&•L+a`(FH+6d'-B@M! i`cFL7.`0E"J&BA7EE0"K됂E0" _,L.8b@Rp#r؇1!"9v`V9Ӂ`FD3BD9M gN9\ȁ0Ub$x2 ^k@Rn3 ~l@TH$g6r )S-#ؖle2m9[)ؖle2mH Sm`[F#X,c‚#؎D,c:u׎`1F#X,cu 6co<P`(F0# Su.X,b@RKO炮aIp#IJ$uʃ`FlI!%R`1FyI#ľ$SI%#D$ؔ!ؖn֌`kF5#ؚl/a lf[3֌`kF~]p֌`kF5#ؚlfu lf[3֌`kFm*.!ؚlȷeI%*`F`FE#hk45>-JtF#XhJ-|bfi4Yb-*%`FF#XblhV5`FF#GBE#آQXhk45p`FAm0fi4Y,?`FEJF#Xh@tE#آQXhk45h[4 +`FF#@ta`FpC%Q kKRflV)צT jk5Z`F-uQZ`FV#X(aQZ`FV#Xjf .fk5l*%jk5Z`FaUBjk5Z`FqĖ`FV#Xjk5jFPfk5l`Fq# jk5Z`FVj3Q`FV#Xjk5pATV#Xjk5Ea5l`F0[#Q\D%Xjk5Z͈ *Xjk5ZNEjk5Z`F1l*n!fk5l*%Fjk5Z`Fq]" jk5Z`FV#Z)?L{D]a%d_FPt.ۯf\KqJgסֺW+;2mI,>Mm  a(BY 鮁ڜak[-@VX uX u\ű q&:X8N]'Fב/`1 EL&z^+/ cEL&z^D/`1 EL&qt0A n11HTb ^Y ^q Ӌp>x:-@h"A8 ,YZ+@8q>0N'̇{;q0Nz Ay{7Zh(# p5" /A8вڜERǶ$&ri(ݣ(U$͠= +YKB8uIə%a?b?B?b?B?B?_YI7wiE/@x$@t z<-+ӻ:B,݉`A'AX[u0렳bVC\9rvr;㖍dD+@X ^8 G$@$<݉kmZ'Jd)C9o8}"D "QAMe."1qpM㜾Kg|}ʉ%:cht$| $B38 p n]%BU1qj~P bz a8'$B0lh$.}PzN~dqΐ9ـ3n0J]%y#ٜ hCx (s}ntr u8':H:H:nB7PMqAKup%H]|q>0Aǥb.v V9l;.}3xMA9 Dު:Iu8AGh qέwwC]3 p^ZҜ6},6G } `mgZF~ +ܝ.:TKI'3x2'T˴-U-%68uǧ$|k:cNj\IlIItDӪt%/@:&ʷ#,/nSw6<30F9@< ok%a~XVa~4uR."DWXzk0 J,rB3I,Gk,]ز^s/yw^BxmnPG` ^E{(![ӯ"%$ 38Z*۷_ьI]a:= uukW,]ƫЪ]4xF"."DC4cu*q u\謹ݫ8Wat^Z|3XCXM2n/ol9{nSv*A<7h Y !D) RF uuCK~h rI~CoNIr`㥺~?y:&~8)] _Qr|D U+'HKAsnY:2;]$XlFX8FrrkCFh%3"D3\c~B(B QD!y{.ȉA QkyAK=!Ş3jrl鼟5([3*ժpƪ;w~χI9g*Zݟǻb HZeDYJMžs-$BL$@B{y ʉx3y!sz;uEb!&D ['pL<;B>$. 3H =MnR.v<7+`1A"*#B<3xH8ޱ1A" F0c-B4kKKKKqQ'i?BL"$@!ʈf Efh؏^ʘ| 'ܧ`9ݚ+{4.GD5Z9q1J vJPc$ 6~(a>8J%~]U*qt0Jւ J cűB1s-!GW EjwIa0|a>8F#χ!̇a0|y>n|ܤ~Xa>8V1nTc݌*atM!}"sX9q C9w"r X52 xg>"}xa8V^+) T c%(CD)BSD5h!ӹ[Uޏ*D_]XI+:ٷBo쫍_MBάUkFfdvdEj9k!aE'@x"Q (Bq "m U-̇C |hq>0Z-̇C |hq>0^/̇ |xq>0^/̇ |xq>p>:Nsl!xG[eN|;lnӭ;h1kC?߅Uw}f3œw<:s1&nWA ^c?aӟ~4.8WkRB1<߆t%A4m<>V'iNlc# 'itn &S 3QzۭJサ/s 6﵎'5=7UvI2VO:VMcЮMgu J)*eؓ+j\-xGSW$*+uG}_պV;*6Vتط*nJ~p{K̢ujNס>=D_q7k}"ZU,Tύ⑯\w*32_1^#^:ZP㭮pdT礪KP:לj AJK"|M}ᯬ*&k}riz'Q9Y*0qbX1TKDTi*'#+x8NO#tS=Szs] ʣP^#Ttte3x#3 CjNnӭơ[#[RCz}7YJKuGݫa;23s'+9kMB A B~xl EӏrIo!m[(@D$@$;Xu9Z]эAE,9 Xr$`I0'O~~~~El? ~,`Y/^Dl~"`E0VWq>nDan"}pTw~(u<]ڞ/w]}UKVljt +KzVjV_5HrXoOlz67*6է4,dz{sܳ{۪OT򬇞ga'wֿ``#4|pݒRgCg67f>. QM/>,]5uhvzYݺDjl4n(J9ЬUwiY,eu:plRf*ٌ :A XxW]޹^RSq_Uoδ|7Q4˻b5N#ie5V]sTsTם(VqŹN}ZuU{Z[_7GQg~6y6{66Dx6=l!φ=B=K}wC<XAk4D]?EexUcG@8g'[~*S*cS*'O*LZ<*~"WO;i;iUdV䱺; zz c̰U{;ҿpNըUշGh|e3{@FٛzU6-~u3R lq^9F"G^D!(46p#Xiv=7BރciepY ፵ӦI\?}~4ND!H8g*Bj (6z=g,P5Aϋd|*f24]qLbmNif-Tk9G9v4?wG.WvrdgLT-R @𕌯We]ZJrLp6 Q༖DMm:P!aE'@x"Q=wB/6ҍa'Bx"Q %߰uPF9QfG{qG~j ة?}mܒ=WgiO? ;7g^qn꫑Wg[ԊG]:. Ǖ!]:nμs[Ӫe\*UoM8kJ!nAUs; }_ϧ$Aμ`~d#£!.TmZ q;6Mzsگ3x:T|c`_])rw)@\8>K=\W6[#,C\v^*`=?Oup9qkq :z^[8\GQBKvǜZշֱjXK[:Mf@"Otw2}PRCQ+^߅$~WnK#s!rѓky}Dc={Rk-I fD99ܙDZ3x8nM* 3+56cw[x9uW+a;ǫ}W||89uk3Ɯv/^G'YtA.2[翘vdӰtZ0!E @D!hZ'mIJ+!N}VZ%c>[5i0>,*+3< MxKь ƙtv6D^mk<^F8n!qۨW;:8koT=ҭq TigjEnDq$nJ>UǠU-ul:j [֯x&J+kUY .WLW٫C6+x-c9 "6wD..@\x"DӪ * bЪ j &*cO6aǖQmq O cVjcH@VjYc'M&j]#0Ѥ6>apסEcIgF" (BYu,%1Vrw*itU;wV w[['2w* wu;w*ժxW$l7 2l~x_ca5q_׳XZ[A+?wbpLc;bR6+okN))rc(L5 ؈4Lx!=Yj K]TGwQJ^Q1rWUR4ׅ̲ߩjS4+ok'AW;lj#muFO\Y?(TS]r&\jn2N2"/,qpq񝂮!D_X sXK=npµ0,R!45EP]*2pqT: _1? C}/j}XY`jd~ B~Vwb:1[j|4qkt*l[Οo7>Y[x3-+VsCslXj4+C~gu+`1kD<V*(< )]8c{g+gZzϟƊdQ6o'U-+qYCe൮H*8,q:wU!_9,vZ$Eu+\E gTWٰFOej,{=3ʰy2 rZ="P\3S:zZ& Iz9\GZy$-1n3?ldQ&3P]*=YVM+.Eqb^Q:}y][n2CzNU8vN`Ur*_$l{g;XbQ|7`5ib mPŀkBX~)Lݳ Gzg1~+Nc%'FLz ̟3\yخz&^R2GVɒqK[yT%8Ss #:$9'bd4T=tu&⼅|QR驹=b9v5`װ`'.MY+Dժ qkU^ԙ*a߅.>: +76a ND鵎󪹻 >UFjAYj x a'Bx"$@Eq!c$ATK*r!UxM~g,d (AP  x;ka`ތ,"`9 7~f~3] ^wƵ}#elrw&E_CWe>>X1ؤ!Bb^"ЪتM<!Fޅ9? s~[%N? "u3>LJMت((((((($$q8 u9? u\V]qFږT!XwqCtuqxz!P)ɹ!:Ъ Bn#4"}ۙJ\!b{ðَvs:X֬QV]+p[+A40b?+ΠfЊ3hVYUVh[%Pm~ V9UNh[VyUZkŵ k bPGB"giŕJD\9rh$2ڜ$ pbkMlM%[,wZ儞sI0msʒ ?_NZVEUQh[ɉ]BbBJNZuZu[uZlV\kC=WHi}|Zi Tۯ+V6ٞ٫!H8J;a..}KŞxesz~!.B?."Ux{v.ʢnt~ :?=wFlZeV=UvqqCup:/{jW 9}Dm!j-=Z ݆BhP+Y" :q9={+i|%9iμf !!!h- s?E:ݻq "U!貸d!HX5) : 6NwxݏwG?ZL Oo)JX=kE zq~hqjN_G{牵}ۿŻ:HaZKVI~_x>+-_ue {~z=x:تM?M+bSZ4ejWt? cLʢXm"A#zZOwf0ŢкF虣Nc9z˵#7XwvNe =o{sq|ά&ƊMCv{sg朝O~O_3{k"(;d]I]"w4*q!nMp‰=ߞtB <&J ?{qY b:xoV:RzoVNƯZA :>F} ,k~SQ}( ß朳{g< 8A/3ws x w d8ws 6T^zfR{Y[ 6W^B{"x~05ѹ Di9B{A{ 3gjVQNhd@tR.K2\.aR t#1"[{xzG/VNlHa\:Y&47V0?=N>{ b81 vÒ v>{a}Z.qub njD 9p}^&DǗ${1.qLb;1A$K؜$K.qLz󏷓9.#)}c&>0L|`Kain3՚"nٻk < =wj x'~fr*&jޛ~X{E9"Y?P;'n3'6mj?9>^;6AsbXo3Ol O Mа{͙3v>sn3N4[3֒k!ܚ9pLd=N3Zia j &vX-4Zia :pAtX-4Zia ;pAtX-4 VK8pj zN8es2o]Kecf;^nAȞ+_5gѓXZs/k,r̟q3KPs~Ǽq8Gͱ%!BT͝SuephX;S{_&u:Tlsy9]5NWUz~GqVW:o|>T[eZQ$õT^T~rFz:H!i9:.5T@dgY8^*;kٻgG!n,Wc:9W5r{Ψ+d.Z:S&Tc{^kg^ׯ n<1ΠVa\1[m-5 U*qjWQ>QyG{nuD2܃ǝj$45Vt;1nw֏b_*}޸iB'bs+LgSyXުKucOut/QT^[kwqXZ=Yݵ|eVrX4w>V*KVmVS4 76qU^]8^YJz˱5o.nu=1b렟]V5?3^k4ojM4ZGTWo+.fnko+{ڪ#I9u?ֳ0︇wk.W,ZO֖52 xud<UaxusTnͥ֗ױ" 5է:3~e"mXY: G𱞥Wz|DUX'Ԟ.S]qݟp: 2: D'~'TeFZ5~Z=a:=QuhsvsʟTI_xtJ j/>.ܾ_ج]ԕ[i#k]̥Hza-a([?̍[- b=O9a2u`6RTڽRA1{muң55I<`uotW(8qhL}V`diu6\n)jll``ò):i\wɬlϕǼ9\R{:VUgY?xX5k̒}Zvzrb&m}-Q&[f c'UVtb>!:G5v,fR%3'Uubm;]UñF&F )83}w;#{c񻣯{MY `-  pc+ZW% 3:~ 8DҹU q:eHUUހNNBBg#窡g16pcuwTu=Ǥw~~Ĩ:ϗj/LW%\G6ѭ[}; }Y#O?ӟÏ^=oo_:}ӿo=|Wɟzg__դ]IM/D&g?|򣵨٧__o~/Oh> ?~p?7zo~7_?>pBGppp8y3m$u> y8ź/]<߾n s7Ma0wS @ma綔cK9cK9S|?-ұ>> ctU Z^!](ZOwWl S\TƿO?ϻ@][;}|ntJmtB+.ʸu.{(:k(:mp)]B!Soҝ6;Śg#EԎuaB^O|9tɹ!SsC (Ŝs~1 M9r.\ʹs*.Fj,ʧ2*N|ًRq4;Jgݲw#YeaІAmb}|veЖA[m"rNJqNJQgОA{t`w'T%XqH;*D֔Ȋ*wlFXw;ΠV ZdVbhVfhǺ5 0hàcwThXVeed{M[֠ δ))uvaBg~o.9[d[2xy6~3ZA YbYpёQ"81_6_ib5)v4ͨ01jrp è01jLK"abF/Fb4Y0z1^ Yuƨ cԆ1j3fԆ1ja0FmFm6Qƨ cԆ1j0ja,0m")d3]Ʈ c׆1hbTa)3?f@c'a4/bJu*הltb=ݱo՛ڴٱUZ*0{X&B(=k{fMSow^)kCy9%lfo3csqҮ:睕Lfvm3E,4mdk3㵙jFs]fkϿeߜYcexH܆I8rmgc-1uoogry4ڽ(g{2f.YvKy=f8h2f.h2J7ns2f.h2eϔͿ>\U3f>3L٧9܌4Kz>3<>ϼs=  L> L [59qU`|*0> dS`)0+l [ƭm4m2†pMl ṕ9p9pPAE`(B[~Hfԁas`;p92\p6G&GdS2j3!߹Y1SE3%L1cu7g,cf1p3ƌ1XXmz1#cv>`d7fb1t:fԊbF)fubFFUEZ{`ĚBLWCLWCUW{RuƆZuƆƆ~fpېaLILIeЖA3U&1U&ӡMw+i% _ )))p5TԆ4VRd0%!1$$D\G *w{g:V Z1hŠjÔ̊Ѭ͊Ѭ6L1hà 6 "ʁ}2fT9Z|ٔʗIauZMUTS]TWi5UzngЁAt]"Ƞ# :2~db+X1Ċ!&)U[RuU.J)ƨR Z1hŠa *vbLJsw 6 0hà->Q+v/'*1|aLj* |taS~e*/|ʇ*#*wNՄ\M\M̍97\ {;ˣ\fTMx2<;*)JoS.ZgM[PyVw.&K.hT>TTͺcs56WcK2+l2Aq<<6_u>SN:OT>S$Ns7O "%*7g\3+PKO+Oys@pOoL@>ř 0*_ޡъʗo|~MwͪVV9V'7Zm~ύ˚[Z@7WQ+͵y|RYbr;̳cR;Zefw<;se[=^s^٠KJOi'k-UWTYSO[*GHWs |)vy\-ޣTL rf5մ.,ߐs,ߜ g\*;;>hg|F<v#ߜgg3yslbڧv.Y3Rs3C)Đ<ͺy|V& $75Y3<)*k>orspG*7C9sC:,܌.!K0]BF%dt ]BF%dt ]:=s~ƒ$d, u{ww1!_!g;=S9͹1;ĜK*Bf!YE~Mu7ߜZVy^b%yy^b%JS[F6yy^Ƅ=?'WsG|@> ?Je_mQM d 5/Vd6QkYZtg̭Cʐ`[o|@6aF  UB*ZG@Y) Xx!bQ<A2(x?AP|cq(L<^vP4/_ zW7V&s8QD1N V}A3?L 7ZR̀O1?Ō03U Ns8QD W,jrC1CXL3Q̳DUϒ6y(aXqYs5QD1W˦H1?L39ݹ7Πkw봾wI 4cii}q(c6CmB7ig*ٞXH%DP I%b6.2XH%R3; 6qdv`q(G%&ZFlc_ug : ~'D>ڏ{T?b#3c03 ra\4A C91ϗb r3MF@øa0$45ah3 CBÐ40d4q6p68e2Ĵ1g O-M8e(gg gY~Fϵ m{Y5-uqݲUfξ 7 yy|'w=mFL2{>ߜ:# ~fnqn7͈e M1c}yMaq4L9FjyL;F_їS9FaN iuL.DU]UokU{ep.\ T2UL.SEE9ryzL.Ӆ,:ߜe2%v"\)"w!w!w!{wrVg҂g҂oBsrϸg,0i!Lfԝ%ӱ{g1oJ`46<-0 n`H  6ˁr`]Z050Lh !CEȎtas`. e,17wޢg5%{!{!!!!{!{!{4af2dCv9dC9d/C9d/C9d/Cȸ||琽|'facfdN7MwfGّp92䌞332 =#cf62qȨ#ۚEj#cM|ڝ#Hu>;jg}7s;"Huvag}n;.aG3;Pȹ;κ9#Ž_zw9SL哳5;oѝ)%g*!fOT>[lnv2i[@O壼5˿+fÖ{T>S,N38O?w{!ʧl*|DF>QSDM峴'lNF|igik찜4|YZ"cK4t+(X.&Ol>e+T>cS(!S:|RʧCkd3-lrG2b97n>Yㇵ*ͨ|6ٌg3*(_hM 37_-&ӿOayW=yx -@ ND!A"Q8g"B\p|8a>8N'·Ép||:o!&qos(BRVp!E "I8*Bq>.|\q"E!r9_\D1_QA%y5ICCӥA&is5Ix%C Pb?%C Pb?-C b?-C "a~F쇑(J1R&AΚnD1/QE_W}:q(x] ^`7e ! XP: ~8N~x^~x^b?Џ #|xWA^*Gڎ*]uzN j8 q8QĒXBR'InW'D= &Y>A=@Q}:y/eVAT ѽEA(p^Ww" ^zB|\Q*ZHRMIkM͛$髛Ч(ܤVIdj-Z(SkA֢LբLZ2dj-Z(SkA֢Lkk-aDkiwi-흵Ӽ6a'51JTE NDL'imFW2؏PQO|c? |h8 !R9 q# ı oHZ9E:T+EZ4AhezsMZ˟k؏^\~'Mat~%c; VIc#a4{.U>(KՇZ5[%͠U܊RUcZ-̇{&tq>06 |]W5V 1! VGea80+ jvccCI/·Uw cn8VVzVVVՊj6b?Џ(Cث(!,uRxKPƊı$d+ ڣAskb?Y~=v$CAړ؏Џ؏Џ؏Џ̈́=K{+Y``>^2m eDZ,E\ ;{yWv^~a{!hUMMMMv'hk(e8A[D Z'JN:q=ftfLH$OŞ1:#·p8VfLH vȣ;8,磷\l 0VYq>zK5]RrM磷\ҝ8.·pΝ pȯ 1GtbȣRpڗr<* })gȣRpjJ1>QJb?'J)]D)[tc+.cl~R#?ibB?#È0B?+IgB?z s!bB?$/u[ytc.cl~Yk؏2kM[fb?zˬ5]Go-te֚.#5 BGAQdr~' BG`B?z-E5t3n٤R{U>V퀯'*"3oI}d꒴)g5H$rZ.ȉ)g5HԗrZu)G臤H9B?$G!i?R$~;5]쇰)bƖg)]lOiUjqtf~5]쇰ObM!H7+c집~#f EmVT 䒱dqsqYkI~*kyUcT`n/#̚lS0k^H9y,r;: =APGzR!&ٷ:VUC1nkdǶv:6`IеUWc = |@8}m{~g痻z~~WvWuϜיݫ37VG;ZQb>H}}w CA$҇>H}}@. >Ә ֙z>磎>]H.8 @.8H.8 @.}0:OcS3Xgi؟:w.}tҫ ~rپdٟõX{o:?]S+ Oב^0:wn[ȞU)ڶ}Wc .USV4=bO`%qE}ױ? DCcBB+Uc|>ݺ;ݭoO:d`kѷ}DzcMt2Zs`bx>s,abi91s$-brtAk7:tA()]h7K=3K=lvSs;ҥ V)]y ƘfcL}5!̇"!iR0V-Ǹ`|_l}7+q486u4!:hh$O2l pf`>JҞ;[jƖ[ﻶ@!EtRΐR@Q)gHQ)]puk bHQ[ uk bHQ[V!t)]q..[|nACT F*|W>bd?1s'@,U Ft?1Vx 1?VX棷e|J?VXCU*0U?C U? 98W~>/6H9B,birX"EbJ#p)G*/RZ_LJu |q>vSI#1&1v$xN[ фŸiU&{1!im ѝ{;!DwcM.E"BtQ47ѝ{? !DpzK6!G mB0&r!t9M7%LJz)AQ{A:{ A.{yBqOT/]0 ~+?!&% QjRB%RiדrX?A)ESUҎ$z?!GT!;+T (q CB JAIyśTCÚ.UotQNtte5]G/y-|z9jMKE+# 꽃qR$_7#J"bBM%cSibD^!ckwZ(d'A1QKh1noV{.SGqe Bs 1*I!:#מoj(&H(ӊ.!!PTP!H)bA BAHA~P>!PTc|H̳ !CmЏ>!]awEZۯw {-qG{-qG{-qG{-qU!=8Zhq=8Z>s#ŻW5]+#`DNmȩId2 ƼĈ+mtIf0Kmtqt BAI.1rFpH9Be!1uŻ7!K4h:d0^ #ދaz~MA#F\ύq=7zn  ݊w7Y!bLVX'+7R z+eⓤ!Οx "]s+2l_!xlV3Yaű?C3Y!0R#̇B<6+EI9|>+cR جB<6+E͊D+cR#̇xsYv:+,볂Ċ>+aϊ>+hX볂ϊ>+xi;ڬxG B?5:[xG[|! c%, oaB?DtdVԑY8{q!ȬBy!Cxm,tL e|%5'N+ !5gŻpלLmE 2ej+V S[QLmE 2ej+XQGf5^NZ*! T bh)GRњ.· -dBrԚ.·pH B9t)Fu}R}R*q3.ŽoFJb?t[R؏D)]F.c|?PJ1'ݓ~u)]X3~ )]Xk~u)]xG~)]x~u})]Xs~p)]X~.c,3tc )]xuNb?kmJ1^9S؏:~W.cFtQdr~<^ާ 匽ޯ .E:u)]1wU t)G臤H9B?$#C:%K9B?XyB)]G ktv`Mktv`Iub7~ R؏OCJ1PP^7P!Ɩ5)]MP)G}&t1p#MI97qopSB?$#Cj*rdMCVϴ}3Di%L+gZ J5V}kD_c%+X݄:nt ~rMBoL}d(S߄7,=%pM:WK9 rzj $B]A=wXBsA;Ѥ½Mz!1un;a>HmBc|?iAA|fo;a>|wz40Gq>|w?B8>j^!z/5]? ·ڤ:7v[GWm+ز?c%̠˸'MrBtoQqA&l"$QZҥmNI߱Xҥ}VcբZIroKIXro|Rm|VJ㿍RmLQzc (h!!DAl ps 0! djAQ${-܎7v BB )eC zcK@6;5]8mvXkpjyt2 1Է+ bEoWiML9C&l߄=gJclRS8c.(19B1s9}K/ǼDm1/Q[5}K{M^ǼDmtq>oy| #:wA!{Mc5Bm0=c|jkϑaǟ~|po;?_Ïn|{8osWYɧzg˿ۿ/~ͯ~ ə gO+7_դ/OK34ŗe yv8d!5<̷?3!zcs*0{3T9 |@> Wy8s}D]f}H[{kb# iHU^yfLUQ*GX,SETKԩKڶmVоٜXBG@R)F @P7=2)0֚֔5@-FZYʵ#k6(`ݰφAli!$nghB gF kmi+s}$qux^? ȧ =ˌ򡃌OǼ4JT I.o2!6&9iKkcX#nx!|+m|@> -d;^kk#e}uկ;덊䕵| >h(>4}A>n[2$Ok4hx ]N><[Uͣ;x5|k}Llu?/? W?fCv|?|*ޯh=}}GcrT;5.՘H1oIoU;az߮l̋/{wD][PԇG`ցјy伇3L#Hdc i??Mw"񇓁rd^F e_ôm4y#H[>>qlF/nTyd|y8#Gid^BD_1$aAGf=ߑDF{oӴ7HEtȌvݘ zƼ)h;E倣`D1Җ0z (pF@=3wPл;UƼLyN)w9MOʛ-&:gh!75.g5{98niN5=I5Qc& Z;xQXR2ި|@> ` Q ]} }z\57hvޘ;2;1{~ƌ'bY~W|@> {־5w^kk/&)xky_rt; n#.//_ ߲/3-jEk]Eg蛋\MZTE\4̺/C\Ѣ\n`^2SEySt7EuS47EqS6EmS.)-*Yc3QT6EcS6E_S5Ңi)( !K*AY  r|R -:Y1&nٻcgh{*;F65eVw`uVw`u&~vkD`5"GͻY#"kDd5DVC$ uX=dC;k 9Znٻcl|_D^UeJ5BF(<{;5BFhػѬߔfjV+u0~vTfʰ 83eXE(STʰD~ȿ1-LC٦;yX5~D"ubkI_@vlPo;.$N*bm`[:e&;¦P) 2*S!:eZD,2k@A,cff^sXc~P\:פ0jF_0&qt FeިxbnT Q7l*FۨhmmTJъϨ"ws ɡlTQ5*Fרu`%gZ"bo}q%X~7~3 6:A0lA $ߨ{7$6c4C Fk\h09hN0 LlFsQɷ*Veު[vU1*V.vcUʵU*V٪,[UakUymyȱ*VDRkUdʫUaoVX"`u[]Ve\;N̢69nX)b`[ہ`ȴlԗRZEjFij Ta;rBA7zX-T΢P(ylaMdMdMO$YH$pfnD(P( (JmB^xS-JSƘ`mQZlm:(6!TE%kŶB-(`gnG:WP j_~]PJɭWp E4sf!9d.hM C4a& ф!0DhgC4sf!9D\TE\Tel(z *Ԣ-*΢,*ȢB,*+*?6_nt,%6 ! !8q C2Ab$AbS?xV  !c A~B!BP  %RB$tYAp* )S6d RL`@ gMtCVp8u<uviwvC W$AN`22\ñQááDtc 3Áw6:VTO*C{8:5CMP;qjbء&v u(ld˹kAA*\rف9(Ca_s8(9sP0sp˅l@̡u/s}|3ZŰ%O:U.} ga.:UDZTsLGӫd*U*W-Pϡ^5ҫ:zEU }y'*^%WyUG-7\;.o l0:ZzOowհW^ѫ.zmWy^"UR W*u^˫Bګxuy{]^WUu}y]Y~.Nޠ6 :͂נ 4,7 |ttl )A{WArn=E *A%:xѠ"Tg*iP =AU3@ud ڛA+~ YA*՛v'A'.>>9VZqqC{RuGXޱݞuG]L:QlvlQG2ڏuD]yQ>G]Q단 }]g?R >Q{yݮ'tt D݌E!~WE] Q˔+"jißN7eGTu*QJUBTY* Q˨oET*Q5 DרUdBT[TɍZDRӯ ~d۩.Iu'i@I4WTUWI(;>}%->*XҭWRKJjZRMKJvwTӒVMWRJZ;$UCRJZ9$U$;9IΓjZRMKiIIJZ $¤:t۔TERH*I"Or FRH*I#`$ ERH*I"'];INҵt$];INҵt$];Ivk'IvRDcMݶ}Q%5h:Ɵ-24Fyy,Rn`G7p mp |N!&D-jUE"Q͢jUZDfۢw[Fmmѻxte<:.!we;޵G뛜<],a7Wh0J`(Qf%0 0 0Laaaa2 MUk#}zuṃFK;ٲychͰ /J#C:prBuppV_m`d*ZR9%4̇•!S*T1NYQ}is&TcK1@o\`Shk-GL? {BOW`^e#fu쫪<;l%rnAvJhg+mۜıl%*%ª ܣea:ܼ;e综*{rګ2`ciMcJZ7L9%SNF<Z*KuѠ=kigm`[ؒy8xv<Z*KuѠ mƣy%?o8w=~cNvv]7u2;NG%vyh&-`g<x8p2<x8pI~?1 OK԰mM-vm1`#<,x، {>Z m>;ŗ񽯎T;j]+~j[zwu=*}{_WծEú:*o??}xh2Vx;uOjUhv+E}~5U}?x;I)vꇺU.jSýͽUwWmU?7YqЌ<̃!uz'0@:qb_w \1o_VVi[wE\~nz!iݝjxG>zT 6]?!}ݷlG':;i ד:#Ezڼ_o;wG`p彛E^;.^_Uۯw[s8]ջv  UW z\oI=n}^On]:$/զ.\_]m=u0/iwvu1x]yt/z:?]Uw'/Ͼ=G/~?N?)qw|o"8~x8ӓޣŋGg'/O_=99Wg鳳}pr_|W8Ͼ-~8~Gߜ<=9QQ=9;!ыǯ>zQ<^ON^>~'P?Oϊ=z{ƶmdaj VVR"ْ|K&4:v/v< -ѶYR%*ߙ RL_B% `0rxa\v! $lvm@}*Ѐp(q6l )GHy|A<<9:>v~"Bn +ẳHt:>ܮB;G"k"aoq8z8`G!?A#mBbz =GHã#0qpyw}vFl0~ۀ !0ju;«p΁GǛ`X,*9?&p=[8>P PeԠAfLz^ { =DLe~W Eu@z:FƯۭ7o +yй..[=+s'LgO*U݅VV@V.(WÝo5OoZo65@PLХVVn-֝1{+NN{2Zĵ?D 7i s~ں4,a8`CntG#X9~1:փIc 1GEw Ku29}`Uxwt *` P`_HIR-?O M?'`ZPq,pNBmS;p' |T%[{B~;e>io/xԡksoŘ^!/VYTՂ@jZB1t2JU5�!WY-в)=ӅN1E0'l%x:#9!>q5n m>C.%|XĊs' bğ˵`^/J‚ws{׻ E=, `9L'O[B:]?( JD 8AAr[AUP }"Ǡ@T3)xvw8 A-{p(#TKѕyz{n*_4`..Aur@8]ңx/С3>dkd4dBD` >,P<# " ۉt_|, Vex,;=̓qSkGFȄ+: =!|Y>c c6q,tB I!gTL; 4YXͥ뷹"~uc)p\E3V+ݓ'>iE%PnV=4W*r:#Su#7!gfsQaDW8G3 4#$ϽlϿt?GQ osF`Rj]ĨJ oṪ!2j "8LB6Lz hUіk`A2 v1Nⵊ)NTD%=e)aj iX R Q%&h> O B Qr0x|NIm%IKsmoB" )DD{+FC6E"Lj|r1MWW}_ⱳ^a܄B"І-s~k<ۨhkZ\T#G1ej}zC%JZ@*RCZMs74^(t-ZH%'O4lHElEepK(T !$Q|l⸊'LV4v\tI>!o쾉4 K IB`'H74>)I?tú|RJsH8|Hd ӬXZl|RF.g5Fh_k}mѾ67hߛG뢢xˣ\^=mue{0G:,Xqi8#q=أSzy/GJ䱇WqV ym(!e'O, .,"\}Vmy.j ȊTœҶn)Ror7re;BnC6fmF4T&ߑ\3t.;[4ht50/Z2:,6q;9@2;y'Q)K9߃k*AE/Cţkjy:XR7 jZab74 z`$# 4;7yhHkVib_˟ ׁRDۥSz+&'tJk%>}'4OU&dTpǟ޽!?zWlflnoA HCa Ρ*d8:TTY6LTTZ錱V[Z7}x%;*k\NCZ+/ppSpI0d5@@ ^c&d=:pgrqq]0 EѸȾz@ f+X9̔=PW8l@>}'uKi?Ŋu!#6_ƨPiM4ߢ-fS,o:Ea! 26 T!%')V׹!V-[xQp9b$G`尒QnVkkOZ?wI2Cnm d6@ to;{KMȖrL{9ґdݣ0IJ~f uol{ y&67wv6Zq A+A4q}⸣3Z/`5!J>Ƞ1ėA 59yH삕>?*jonjj6TۅITsMcA0|7a d!G!ث9X$8G≫ nRzkZȼ-wvpEZ=H=2j (~UlA[I!šǼeBG(΢H:x/UNi\σ퍭'߆P}#-P@:yGSaùbot+,~ qwnRT! :J8T ]bfzT&lfxqs1Ч[1M$c3x%jdwI aCCQJQ=EHgkQ6@Z@C 9I/n 4u6k͕ܰ]|ڸl`kX+Z V ;~  |ݬ(EcἨ<^ k_-+qpϷ->f[n^CћpU6k9|sА(Gu\8:~Ml4 lR6R]*f牦b/VL@mY:WNjLjY,(1tlBڵp%/k(5æ7| o{q}bFD\ 3ੱhhsp~]=+4WQh`Q ݣ%yFi,K54+qim6޾R} A%E =νXxկzO(j`PmQ!ebh@xDS} 3gLYXXXXX?4g@SPQY\7wY6Xi/SqKX'kM63gr3Y[ϝ|[YYYYPh:h&wQ<aaV1?`v? {N>{ok[_?X?4uiemwn ok[Ȝ=a z΅.SjܰjLjk[5oH{G^ 26oܿ뺳U)A,~Fidok[okߐR}Ykv>k[ok\΅.Mz;T[p'$VVCrY[XXX|~TaZk/9ݑ{];! (L? d\`@*tE*V =,rW7hLD^=mq33_}QԋlK拢1@nh 3Z2rv1V4Zm3J(a Ng5xwHZ?憣ZЂZjx j Йׇ]kK:QsXbG$`ZG%T+'=qdޠ-d9 +-ܙ0rsOt=_v! ާ0[{%: Gh\ И63vAhU^菸 y>=* DX<W71=8 br_-kXU2SiITScRw.!J&+ לQ.3pAW@Uᷝנ:v@A5&n7yX덽(x$qɕq#dͽ]aCSs⍮o.x SpKH>ɥOG[ܭrɺGbΏ?:K;FB@F؅B"_o6fVgOd֡;D Faԝqo.ہI2мgZ 50lzO>虺r~8oҋDHM~fl1z,; aifD&-Onr'=\gA϶XXWegtʘ |gY"*-fJ v`*d(=MeSJ)6DC94uNTy.e70RW \"i}Tu^Q遆 H;ӉzS9kH5<bwt|%4q;{x(`| fce}9O4~SL؜EdGZHZ*$ԍq@Ch#BY%ㄌĊ[ \wHg Ìs7r0w3QDZeImN7@%`nĞxʀ]NUT!#48P5VPΆnނdCF^4v.tIć-0 KeglS,z.7f3+L[AxM>}ǻ;s}W6b'v*eS9:EbvC\"+o>3 ݓu(i(s`5tf$ímAk?l6q !&xoPɿg'N&=[ق1s#sh{7ыE$薞 wRX+=K*WL"˝LWej hûifmPcLmڬhݵ!n[Y/e HلLL'@0>b1 ||VM\fɋ gbZ J[r9="F?O-4kR=x`Q3SUt&䴗G%oEp"u d1|dp(D}Pph4OԤbƔծ|Fˋ,J&)[U*r(wѥS˻ywu"pE&q(9Y] $Ře>T;n8 dÊtخlO,==`9|ջҠUIH=>KDh6]~7Yʲ&]a,Y\kPWMV+*[c76"3wosqq9M.:;!%ֲ0f4ieK3N`F>lN~34SKyoG4S*S^ mFzI3b丽+!Yk1ȠL'xX;Hq(~O3>yT21T^?CYPӧI)LRhXܽk_`!vNFO^_)[|L%|>}G[zk}wLc `evPj4 0oF=CikLi 0vZ,u2 ;ZiZiuwN:c;X닽{ۼ{Q`rũ9'UL:L4) T:ݘ,gDoʉ!_HU^'a9Sjc\5OoJ 6|~/(tjsiF4e/y, fX|@77);?moM8f6ݗbق"w[fgڠĽdL>^<#짼~mZv\g) =c@V+m/w൸UQDDXu&#!ijvL5-(͍z|#`c ?e *kTգ+a2kP ^c[6;a\YWۣwf{sO}#;)MILD&؜:>U"3}A&@!h }gtɜcM΅ m$,C?k6]|;,t=@Mazش6Mazش6}`I0 J D+2S&N#+ #ڃ>$}Lyx*o-!/TBo| `o/ r,bQ4|e/h}t^nO&Ҙ5ス27ir~Y EB:@S63@J%).Qz܋q9 ]KWNY53DZ(EI[+J}L||ikH"0ɵARL2@59nI (^/ bRRddjf6,}NI;rrE_!pcycY$b[*s]උKRq. }_^56q yH5sxsOcҒ9 >;K(,b@OUslǘG 0):%΋a:kq/x;rBcدwpP5dvDk:e􈸳qfK9Q B3 E]IFZgȅ _ _weA>,UɄ z:(9&AYfÑP/g; |m'<) nǡFzV |/;OkSw[OPk_c_ %P]ipGx}Sq?J@CƘ3Dp741\58W>3\ ;B Puvb_Զ^ - V(lw7~jdШ!9y`.2= Jx;5٩;Gd DYV=h)F$W+,1x掄9E:5麓b ecڛ!hh/D.RL`"(EòX _ GfGT]+4bO^ {Y5`㯶 wmN54>$}NTFi xAjpb"E9^$/hrxKSΥmKZeA[tv)b~CfVe!M]v׉cΜ]&[q( xÖӴD9pROwH`8_ܩㅓيٟosҥe-2᥇fZ8k'Lg=qNN87MK,sH [&64j}i6ObvW(C=I KKbwTN"HI7l.JO =W M9?5F2Cf"dNM͘MS= YЌAF%g(hL@SZ }d)5_*/|Y ~E}LDy:!1z_#e|`0Mc$tj+<\*.Zyv"N[l56Ota)EEfAQȪDҥ?'!8q:[eSm9PjG冐pȗLI-̑ԮCOyr)_b'tb 3,0!*mQ1]C c?buJ/[o Xig#wx…NOAnh9w{HP 0B KY`&r:1lt"ѽE\>F>sƺ~sm1cAâyr$ 3>vJrVg%i8/ݣ>NFo}mnO`cw~ί;vڝ_kw~o.oh{v3]ʶ*o{rOQ(- ?^p6 0Cd\>w)T:e UU'g>/7!g>7|~.<8}3f^q~n鸙o3c|n^<6lt豙),zgW: B ['nŷ@Yeb~*v?77*ˣ}z¿Bqv$§O)O;.Xx=NH8ijg Fpj(CyҌabk *\8SObX{TɄRLrq}Bm@bBM&)(hB@g?=C7 ܾ?Xi/?'/euI&!'kE$om:c! {,l/ R2#*[P qutp 13jz{h(PL]a' R>_6}>p" {pu"\WЏΠ/g^-t1l&kq˅T+K3e}|UFYVx7q&z3-uM|T-u})kח/%Byrz*:rd?ʷESUyRs!CS'Cx*p[d<Xg! &2hb%2)VnmRd+IפX'JdRڤX>)VBb%IOȤXI}R&J^bM a>C?nKӻˊ2$n=@R]] rqݠL:srjş)ޥ3"xr;cCOwh.]2(a_3͕//D O\;#+u G̷!VP_fTa-L).<{ϓ8_A}&9 5B]+(>g,-aj)0jheVґ(= ᗵY~ ~˳`+gޠSf *MgQ=zCV">S`tr94`>`f%=s=@+ gS;5)-uu}Ⱔ<; "p^ bE= ^OPs#TP`4Ϭ|%J}"KK6.>in=m==7dDzoqB\y2WLZֶJ%*ېO˛9Lygnuzzęf (f+s|d;{|jgwgJv?%fxM#PFU=ҍzRY<ˤ)3N$'W{d89m!fT:vh;GMzh1¼4<#q[FX8b2.K$Šywyc :Xj*~X`UxPdehlP@&..@d#QMPe}NY:-j<*jӭ: *{,RJtL3K^G}0EKq}toNojm#yo'/0]߻ N>a F8aD^/y,#/vȕ 80s}ǿO 3+W>tCcX-x㦿'3⣥lY gLu^SdžX߱!66.%]N|v5ZۧaBi{p+0WCc ãqL@]'pQ*Fnx`@o좪LI0F[Plшh:h_bKRwڣwzkoMۆM&;}odq/a:5&֐(%d(_PoӖy`d6>3ljI>X[ XnwpCC +=bC =bC !;2jCiGA3Pț؅vhwt>i}iuƭ?lLϷ|YO_%Ua~gʡ ɗ[&X(Uy_~awUZGH?ĺ{GG "GĺHc֡K6mo| ?/Pc{fA=l&(CЈClq '2i'p6U~l6Kiw􇝽s ?cQLĞL!  `'؞S{?a ; s) } .Z4( 9d@3kMwtbG mCtpg?4+<-C]vt%LrHg`lc7Dbd7D6DPPtdsfG0sũnByd(?qH OK'8Ȼ|mGz`>}9CWgj\jzx\ V9\DSOY!P[zvqST V2k;È8+fKZ(i™B48{fboiUy8f5bI6qBi=*+G ߇b Ч+~(G}KRUTs#`zÚB|켳'5ޑt,ghn>TfZds3't)я-~\U7V[V~XU3pa3Y1"nbG:Ga08==Uǂ=xpS21 SEcb _✞*_!e~s/;G.CбՈ֞c BdosAh:`wcfLBd Gō[ۯ~~_v߃ã_.f/{bՋQf쁠+ʻ3u4ϣBs{ĚLQB a03rnN{ ?1hҧnΜ$3DDTyA\Ÿ4ꚎiY*@al';=:['7CZUұGC:32|x8ijuܔցKD:p6ǴʏL,Y.B#ØLefO6aKk.I?}~) 7@NX b'uc=o=o7@Ji#_(P\N}}"?}D!ݡYh>tre*})'2Nzs?ᶽgN )n{l6Τ"k-RFtNث7D_:>A{U3+<3GT&5Q-娌lvt@$":`,LԀeuV.&2{@KPm4 O4BM*t=,z3ןm)ݞP4^Rlqۦ.u|[IUa"W =vsJX9 l(sXze CbYYݕɇZȱr_9NYzO8eaa wF<`X%nġLo<Ѓ%=2Gn &kbzM)~U*l#CuvTU!57@Jۣ2Q8O"X>z(O>#БͰ`PYbLGHtɭ^Dz<6"56͸B qAeK9( f*촌@>el3KoJ< j$%" Vqjϸ(D7et{]` &ǩB*>cň^rth`S0VԑJ=*81/#]ΓM#;%6$}'sn//S֚k_Kuu_ڸF0f#l`6F"-ij v%L4ku9c_;[bbI !!{q PR}eIā,J8 \ek\N)q^UgvJJ@2NSO;[R;iYЁ&mG20驠YXlvzNlLṊ}_΋J5nn׹/׃œnydcOwX(EBlKN@e5 1FDŽL!sTNBPyW=+EfY-!!xdf6sj`9 yI8U\PL 0 "@ۢ Q8EV9uӝ,& P+6xmN]4j>RK ͅzRb{˩[jb{k{YO`D&5i"}l+MkD&&7CL\腄SfN^JV"wkDyII/^B3y9V}I J5oFީ+Q=㵓M4αdygݱL%oL0mtpX&wgIEՕPWsya6{l6~/el _/T"_Yf6}Ϸ->/û7im1u?gX_6~x- *c >T8{Yد(?o4fG7~d`_(%]VrnX06ҭϷaFKFW2.ފR틬GAS(j =nyկZ?憣ZЂZjx W%2%"m>i)ݖ[mXC>LFGm֒5WV?xu8hҡf"zm *0/Z-\=7(Z?/(ZrrNV2UpN1y2MDk3:(k q0q2myC΁\/rF:pr%q0^%ZDD6g`j#xKzIR]xHp)7TXpoEV,wvd2#_Y4(n<8|KՉH(tڟotSǸmt<޹a}#zFth`{WnR#YI׳RN|‡&m 73뢳w,dYR@[X["$ʪPF9ad[@2,_TXɦW[p뛯 {+;Xb6%!nȟR6~eun:Ca,} bvU8Rw6ԧ@ {Dz5R#53Qd bfq8%b -F&~LȇacQO7oܓWWh'?6pukf_5v\L!=پ),0v;jwN0C3$*)|hGTD'#T20UbCD9=KL+ LKAlV]5fk0!T ɴ3d2rHCf~ 3>kxMtҬ3?(a8w٣#hR ٧/ ƩEI ma]41(-P%tdcvRm`28+SC0}+3ϴLMW!Sv$-☕w#s=)w#YDCTv75gB.EH:[jq^%Ԋ8[Snlxߦx?!6шȷ.#r#[-{hVg;7\Jyygp6J;qk'L}&?JI]xCZܤQb17ĝwv.g*sGI/4_c3EX}Zg@T XoʅwX ڋ\4x Xo6 ON<`xEܛtqe F!0##!Lkj(P[zLAz|%+%#@˘$[ ZsۭY[ָgknm~ߠ{h3gzDV gVzVtof;ișGc!Q>gbZ #o ]3< 3NnV<3NЯIu4'^/sP ([+TbI%, .5}ys\A>&4}?4]T0h=O4ÍIX]5Y3KJd\ %t)zn7y&5& q(9Y] ɘW2n8 dwJ>?ϟOzUj^:K?W?'E+,JJUէwesdiW^nkwMzXgesA^6YWo_dWjpXfoqq9M.:;!%ֲt0f4iKsj |F=n"͜iXK4'5E7LePUn7Vk35Mri4[ RJʇu$)8ݰ&)oT&KVg1Y,ü2`/XF[(owavNFO^_l|{/J쪌[P%+oj1ݾA*lvF@3DzDuv)R7'Ci L990l,tmKP̸7Lמ)5`Q T71;֞Ap8{gw;6wA9wdԦ  B'ŵq q3TA\ؽq/WW;hZQD H w MC&"^{#vwr{+RD8u^uc]-}] >{e*oRa/ xo__J;l4)֐tS`h˂{Z jDpl$R$ 2!z&MCL# hE#u%e@F 4R NCDƧPKԄ,N0Xa P60U5"9x{=4Ҫpa˦! pJfLơP"%^P8 eq[;}ʢڠF*"KB414 ^t6TE+QfH !V,Auo*tIe0 Lk="KAS%AO#3L kIHXcXK!n<6jW& Ǡ:2Öq%m\چGZpAJIK)+?+~r2$zs!<\>Bf, }F|/m{nRnltDgѸOnځ"{& …FtaEQ/ZB]G23GQmk;a58L!D`RE'53($vE;sEo߶68;wE$x4[=v5x7mf -1>+j;:U"ph;^շtsdI!M&{3bS$68blj&`qo]^M˾\\NFEZk1_}7.{;{L$1QzϽ>mwgo+Y~b &!PLwzs:+ 3( dv»^bUXAȩ9^457W\'5edgV%,uz+lącz0}4xFLu&vtR|ܚࢅ! ,>K{ |'O7>͊l}^Oz*7aoAغ~i6aɽIyO`hO>_^] 2¼`݊,]"O.N@$EgfnqK}C?wd^cvj)kSVՀ5r!/i`YSڍP;PGFfMvͥ;i睺ɹ;xhB \'P53:NRIȲ8dx~tsVz:NԚvZ?u"LNg!nSY h!縉o>?^œ&DN,+s#J'׾7i']Ul|Ƴ?qG?s|CdOf39RSLB>thfFs"%4L.Rign-ͱ3VT3fxD7Юj-Fg kP GBi:)C=K)(zߴuFss;yBB*$ɱ?M swoCHjL l<6E"ԺIR梘EVCH}JMK-sooAn)9RkCvC.{(%) "d8idJ~ QI d!l$1lEDz)J=K)Eߴ3oɁf5d8ס Ckdngi#rc%tKseerqa/_/{^]"nu*o(% 9qdt5PJoU1mw {<ǕcCE͉@:;a|Ѕ;_ h\\ǰaU9Pgo)#u;Y NLaaE3c }Ա*32WVYzI^:̼9ϩ5p>#m 1ޮǮ/ OY[2e ƵeIq/*O*oFRsGWa61s s ا: xqN{mCc{:fgicgD?McGb;ֱc;ֱc;ֱc;ֱsȇG{^nsq;{n0^oK6r`]?6WR}Yx\u DJXIr z:'GN2$KKkT[.>~5g>kYϚ}{ f_~~;<{mȧ=!jlH/'4PJh}~})KR7RrO"yl(ib'_C%AG|(Y7h#Ka~b#}.,H[5%HX)P{Z_/golۓľKofuj.jv{(>`` bp{а8خ5=νcE͚gbk ipa[bRh1i)"`zQ9h~0jaEci\6dPnS*6M } `^)a*ML}'4nD 1~Dخ(gYmMC̟B_,bJ`50ZZS0S'mWD1@ߥN+ : d) avflsHӥpΏN!1 a47_LtDrZcI%L #L-hץ+J߻l8"gĒ-FV4T⫸=ї2)ubxȂU'%9; %tLE*K> :۰ $w; Þ*fu&y-: 6E&Dz (\Q\A {$NlP zh*9+VDB+ƞW F\ KujBQP 57)"cq٪҄ fu*A`72Cz]s3A pXq":ZCƇ&6i~?xk 9;C}W"E3"hٸp ƀ$>rMq)|KSYܨ!fy +fV *H}lY3NF]`ha b[`vި p<&-FmV5"e.Op1[`zAIUI,UKuY z)|10P Pc"EM) EMz/AǔiQDDTOtMUp432z2h.nƙfRRsTw-@ w5ھaw.O%'d5WV?cPyg>Cc!zӈӎ+5DtJ N&DB^9a %7!>f4cz݋wj9t3)o_6f ܘuPĹDX} %:x@Bp 0o8#*zwjX\YteǧȔ''6y t*lsNiE9El;^&?̇3gOҠ+ЃҳXz1*WŁ}mQf*E] HpcRv_RNOi4)6aZ?#(hɦgAYP{ԞgAYP{! RQcP Ӡ*Xj{1'.7f /XQc̒@;a xzɅfNj)ѧEU[ U DT.c<8djT;Ld"T ǶH2Vn}TK@WHM4Jg}'e`_Ott^ luB$cIϘHb($6N  ܓ%Ů~zϞ?1$2lN ֻbee3C464QJM"lƸvI{Aƿ"Z޴1ZSI~f9<f<㫕T Ǵ_/DcjV6lvAm*! 7.Kq{iZ # \$k p)k.hI|X}fɅ1"m#hs @(6KoָaQ,`!Î~$.6!nJr ~mԃsh;YBb#w4̈u tqvn#p8x#K;}/Aݸ(ߤ _]" vq3LmG`:ywqDy+;cNQ3ȿsݦz>Ln/ ZY4wI{{0ƒlx%dlQBQB#J(wg/JCMEVrظftIӞ{waaee sVd$@eeo-P+: ե//+3f}i-Ĥ~7@˯鸥DzPò;.<е*P *vX&"RJId>y`s1Abg)x]sGomß Q3bAxsn'@43n3ijs%j䣞`jXvְ5ag ðӏNx.,hD̶ x3ss5|S oR2SܶOt'w}m+B7W  oxش,`] r0]h;`p* Gaʕ`9A{_,+ lvz(c/,/K! I-x.Ŵ Bϖ,T#:EeGtN ;1n)BY6vd2:ueW\pb]y,mݷ{jkխw'x|vϩ] Yufnl\My8ՠRsXssil9"@N|n|&;7GcfggߎF#66n_~|>v|f|~Vl =P9-EzK/,%s;GhC+I6޳]0Iy7]@#-$zRZef)ة?zJ]<姐82tc&9(Wb֥`C Qv Ob9[(szFʺ j:e^Bn1[E{}w /`ظqԍ]zk/<qW炢E`O烋aY`s|@k/bBq|NbjJcV-@z2Ӂj<3x?~+ja?XudGt~V^x\CC>&|FT2I"-Wǿ=ֻ#dO^-6:cğX*h^~بۭ ##XmC!ڌd;Í\D_CK%Ei'St[`UNp8 V)#}dh#z2yMW]<~ydQB nRoDI\R%GhZQTiϨz$Pq!5;"*ZعxlDS<-*ܿ:KC|&BLЂ^V9fx2!1Ku2O^u1_H3!lZrřMDIm<_!*SEhkgI pjCbu.EyFX)񔋀daL݊f]G,Z$j=5$Ц¿?:ju|Oˤ+u?H( P/]eU?%UmyBLQ1s{.!Q*Pȟ"4K8d.y 4<ji*UWs:_Ҕs8?KtH՜>~%qnqLO$lf& TrB n2U a2yS%_X]s2҆A+T\:0EfDzmH FT)Y +/v@AKΫDRꦈPy:e ,֫E x#t0DQ1K(m<'E?(ν`N)ǂx}ڑPu?o9P׸F* '̩iai: |B؏P:/2/JTΉk * EYr l(TLBvv !H 6P ,&jHH}ѡJobVi9q՜3:+ kܼsD:ޓC9AJScG1~wyD'"RNı?j_ Pb:V1$Hl bZ'Og_ hтaнPȰ1ƾ|٭3ѩۊ?|{rX`Vd"XRV@Nb*9ZYw_|z1N#.8SVS 0N1~GᢇRɎԥ3]m ԰N/J-r?Pǀ-Dyq;xV& Txs*l@+7O?čTUG\M?7V_/7Yp7w ^-Jzh" m>9vDk'%pg t;_u wTC!T)A֯7flFrju7Ÿf[ٟm0$& Il0$& {IrIfhҙ"O{^^bvѫ$÷Q-JUMkNӧ-Tya~E4;K S:N}zTuiPtMxƩVD-\:Kv%:+v{_mDTxmN@Ýz>Y\0xdV#3|3P6E Ժ_R+KwuЃeOѩ<7";; ̀qN j &X}z)z䰫7>Gt\<j۫H$D0J. D>|YEa`Y|3Mp48i***q$~][3){ް2ձA ʗ:AWiL.5qQTu`U,2L VRi&#n<,c}2|p0 w u` %f: Ly3X`ThqaZi%NC0`؁6"k;aסC 7Ť]MF3b"T\rclr2ΆYQsO.J1 i)7rXl\+f7G\nKd|2 0펦 @ȭzZgodVbO3Qs8(j@+%:H;O.!`Q:L!#WAM'}O& >{ѤOQHiB U3""\rD+%F7ԪSvq24QCk LBCG&y?=|/y\$Ke{| ߇6Mo6MoSx dq8G5-51ܻ*?j(1Ƽ QEpz:?ֱgLt\SPd,7BXcgkdQo!8TzU*Q~Bu8y.5ܔVL|X:戽f\2˵ʭ~xRy=Fe;{?.q[8_flJJrwY|I`0iGBok*N>BM*4<[ZNyt}V=Ƌxq/nm6^Љ^Ovjt~>JCNd28D45Vjt@iuMrovjʹA9Pm{[۩F^>LhB`әMc b9 7oQBr F{ݍavpS@`'u on&v 3LNUIjwt p~={ (;vJe5-6Z!Q L 4x4jӡM5L)P&}0:U%VszݓZZ~V ]ywLOBbO7wOz^킹8ۃWQ`iPoeyaZ/]LWaV1[ŶG+۠4~ݾ:lJr G.(WH"mkOE(?0!jOQhlَ6Z(yؐ 814]@@\pl wf*V Np# @O 4 WӃD0 ȵ _n| >yiF x L3ࡶss?aI&MYBa|-r50Ռڇ9v3S(fh%};3|f̲S_^Z]-;Dvj.Vݪ[5vnحUcj|ɲGq8j|)H_jsVn7GN+Z$g2ߒjNnb= fb= > V ?o?~Aa"{ط ޕnP6|/=?s|r_k I ^%xn/ JS6P5H s?n{?z' xQzhqqyn-jQ+ 1,;ΣGuxf#(Q{`v}PRuv*7iMd._]|;.gjcQ3WRn6jkv.7[{;rW>qT KZao2 >Ȗ󗼳.^Cȅ?Bzԋl X9eed_ Ye]y;#)SUm. aP )+rFwsj,Y #, Bz:lk j`y p  sDq4XzyZB9(K C*7np),7JM 2Clpx;mF&@З@_̲@r5/)Dͩ<W͐lCzcO ....;u3ⰳ #@!XGŰv|figXv>o~[jVZjQ]Y7B}g8km|w'ђjqqLo4BcT/bQH|S$Ej*0ZFI!LIc J9„0 ys a>$ZP<>3>+ P#CQ'6}:~2|O;Z'_ `=k=r ~GgemOY F烍7;((C?s?ao?K'#_oQ0(PT2kaɾ}R~.~b[G?Њ |(&hŎ6b~pS+%~kYBQ;Q?!w^D bIAQ.xpN}~SַÁa<1GiBpfQn%JkW*쩱jɫό/C cc2+*;}$:Z:Vd[kF),BFqh`]F?CE.ZR7<د0X#1bh79SF5\ZNiάY Zh-@kf)( sF3+0.7y_=,$RK*Qcw_f&:l|xQN ՜XD Od;TEB%)saE2G g!蒘.{6)n(\(βwAFW~Zt7D yI}ˍ i=bܱ[+YQnS sʎynV>UМoE,աNWIaiS)9G "(̞J^vA8 G)HFڡ^3_PaC^y0ʼnfQM|fs3\-"29gG`VK+뜭hMEL\Ds2h'XM6qT = *=8O = >{R " IUIRzǼ\v+Nٽm:`cHs9;cA oHjG"qX"r甓Z$d]v*4"DA*92f z +ft!o%cհ}o( >`V ѫSe-eQc8ɞ:B=^[ypytHxH,ՠwanA)?tWǠK";ZuONۤ&6 +#@F|I^[' -W|`FZ:(m0=WK?4z%2gA7./TV)OҔпc%T{ Ύ3 Ջ?NW%c&t1L~mw5@*[>5HJvD=CXW6T@wu;0\o_0iZ% ߿q:K6\6diwm'V(tz=1gK, и$SO z8Ct͆ف.B:0޸z(g3+v5'J!T1┉S K^Y aSg7jy$LS/T6QT1Q&XV`CU XQ EUӦ {T&y g G+t!" hx:oGxwlveSH0F\XX:U[ 9P+  tda:޺yain-MCs`TK:6WΧ<-QmUљİ7&o$,֠h ѫwۓYLH6q}.*Q)L̕(շس3r7F]Xi@uCOBW>́NSqU֗[ը S߾:{=u @XAWO@e KБ}uhFC'D9F9PE0@3ht~9O~JƖs1$aƆzA(B(hl30ph 2%(-1[zlQ2O". [No K BqA[ДD81k ȪA_̲̲ԼӤi4M I3iL0MTԪA'xˊ (:™QI7d)pkaL{2bHLQV< yνkfrUluE#CJuj8.8 TŐcs 1#>[Iɽ[0w)Gs6hj\6 !#XxImrvRk@$iF.d7u0;[Y̝xt5%R)#I8?L̞ fOS1{2ghdщ%'#([{A`7aԍ ovjIDmqV_]RBkܻ5Z#LUt'W^#d|x )pC,](t솑,qbmԿd9@ HVVBRhA[JiH/dCDUeܐvPX 0-(į8 L @GU:h@j20r̺p04>:B} \=8"A`e_"4 cS1e{e|( VA4~=zrRTO|k@wA&y Y RpUUmX0:pȡW;r o)-΋tzg]Gd: N&H#`#\Qhh,{NE\֎(=W:YwIXI5&t(BC<>ǢGߕG\b)@AӠ82a,$G;6hVts1?'#idwqN߅j$pm$jOa<'}@ǓxYKzB#'298:Or˯hI$0`ƒ!:0RG@gN\D'~NO2#sl<`jݨyʈPhYՈYg$Re8㫉He,2~d> [&:w/+6|? `w;v(yO\t*`}iSe`kGR_IK͟8ISp h8Pɪbss,xL\ /P3:]xUe΀`yd@4i8Dv~f/$vQR G9K åtɅp6هx,yJ!1fS&FMcPb{hwW).0pkGZKAa:p|2R?}P2[*20bMSu siU`=%QE8V^c$_(`d{9UTCwaxX 75`7Dl1%%jn_ O;=UAET#MͷAqA.jDI%Tӛx0rPY0X("RkSR.Ni1,KzȂZ$7l&=KX;S#3yrdL?oc/k/6|O=3g=g=g=g=x=fk{4]L;~C%X7}u~Myp9vx@šՋ܋rcU0wKddf2ZRTmLo,5Vښ#mT5`kX#W;{`77 F9%Bdar]`*v/(wUw0D1Yr!]-8AukpAǯ6K2* }@?TD) ^UNmh{Ly< e Rri"m0b(.al@]ISU8euzx [q *.eC_b @c8'8OW@qT< 6™A kb&PXȀ.AS"SJĎ,xoGXIO@bSKQfρ³a*i$NaWD@2$cS:*?<ƆxK 2)z[ 5E¤F8Ę`~ԗ8rȺ<0>y[/@uEÔ:{Ǡ+| E7JK$q2kl:h',z(L.x:vM& &񉉩P(edDR"gaP$OX-pMoR`$e"Mo f "fЕ(LjiA=M ,:gcYf`a)c@?VWwQbTcݿO׺׺׺׺۷FxKgF+}ǓIUXfbU=76^i%t])ݻL~MwrϮlNsFE*oK I `fP R|N.]53Tp7{THJ|74uN^*಍@[a"C\3nWԮ^mӫ}VGo0 2GwG5:ysdjrOlwШl@[u[u[u[𝺀w77v}5-1V[h&e;5M𕖭'nU yыRG:yu(ۇGEwB&8 -Bw<tDt^<[&[>,RвSU @(u;eN9[U|0N?fqs _)hc>{8< (auYC4pg>kYZ}VZ}Q[o& =a/jEg-iM2 K ,5?显֢RSׇܩWo(p4"o@`PkFޡ/"/乳y—uJpٍ!e;n}㳊x+Ƀ%nD=\¯: 17`%YJY!֡AZ)rRGGߺ= :PqzRRcy3Jnc}"#:ed~J 9"j<~~;\{>##h)NGqs>D./Bʔ23É$łԉ(}(-1DAlbS@~AxQ: x6F/)K,@cCAL$fNr܅j1J8IȘ"!c\Ec!ʀc&0̺ ^ {![A~Ũ.u6)u=:nE*F:V.s|!1 $ 3)IL`'USj8c}Ş F5 u['u['u['u['un@C2CIw抵blWǻGX50d KuCvTҺeNsTsI>]}H=N)Z*bs]!JfL$Ie%c7տr#H#SᨕATAAW)/RXH۠N+/wGrT~Y"뛊cdnnSBw"YG[N3(.ӚMǹL.)c,&Mk _+iCժL܈W^'@\ZZ`Og.5FsKʖpfm x5gF\"EQW\vɝ&OҶ1\_ ܴ0oooo_o6ې?x/0fy ⤏i@f}eF7>oEo]?邬-{г`8ἦd0 gX,XE%08!jcRlCȱyujxjsiF1x>3΋^gO* k$V-*L2Lfc܉MyDy#w.xm__b(|Py ~g@w|+=\K2sK˒{[tڤywrz+ GӍ>އ?SpD(6͛:w&[%rY>M@ãPd{9Dp@K;AϕіMwCy H>mh ;1E dUz)$a* `FzEHN6sN_/< TIq@&AWr&7s0R9?怱"QXwu]7t'p w[W*~jq3qAGAwhfH#cT%][RT0"nGHaKh6i a>*vF!jҤ]#pF/VHZDUgEƶս3C)Vכ~|fSRkcZFߥFG)\7@hw;vAw$".rGQ ];2/p91?y\.ID+RF{EX ?'^%~.X *P3fP9b\ "3F  N0K3c+]~DƻF[0OQHwpEo`7#ɗ٨ CKeɗ'.a4oi)|{sywUcm?kY~.:أ6=|zUc b@9U/-WX7 jd%c\V`"a 7fMkoi}'iƚ[tj)Y+Z Vh@ken@|2 =0h`%?LOt[<<0!%e RH?'];  @o9M"/?㙍7T/Br+Q|ȿT\Q7 BAm_Ud (XJâ!kV@Io賻غ):'(@]&lQhYP(HvQXKJWֳ2رC4$n"Y\ꮚ)Oonu~wh ) UB0m/o6i:&3[0ŃOc8\YQhpMn7_oo"k6VG* 軺(f]0i2% Jb|/" %* s A&Ss1gKL>SCCZpۄȎOi&$\Py|x5\Üusψ[#M#NQ I5Wԉ踬^ T鸬ΒR\^R6q "h R-A0T4V1ZU0R1U@$JcE Ti¡$SuTUYHrv QFij;&?w]<^B}4VU"qaaxWd"P|Z4LфZYTX=f'F(#ta@EJqJgTHhxV9Xj5D7@.fUIq!I%PS&JT=ۡ}F.<1NE Ӆ$Pg}|~حA=t/S.]<]e"f E:UHPc7Va3gė '-}QO9.:n4s^pygn Ҟ\aX0#p@Q O7XG;2GWw:FEq,`Є()Lּ1Ű^^ C~:P5L(7O _ ?MY 6*ʝNc lԃ~t'f6jHyT?QFs`=uO&'%D''IdcMcefk"̪Cn Z-Zb<d-̐C[]z},%[~n}%3O HVW <ƿځB4r'R:%$AIWb$"qb Hs9iYʬz(CA$%kČ l Vk<$ "kg\p?_^ԟĉ2J7B 8!V}&$T~(P3eBQ"ȷ)teכ,锞9U w1G_{,SX}wDA?8 ޔ@?wW.Y][Z ܴ#?lTow*fE'M=t]k\laY!:+yf瀕3)%"2U#3s _hHc˦AQIa1Ss͚1t@U dꅉ'׷V5\ ar'-fbWa= jp{l_&婢qq)Ƣ!,(ںWJ'$<,)5TnFg"5ۻNd>,xqkAjA't0Bۓpg9!c!`| =Y.)WJm^h{hoNMA`Y"lhX"~L(./.Zm$VB?Ke(cntS~ UaY i佌b #j33˳ы (xuaΨDI\{Q"Se0?9$Oc÷f4z4ҊGѨp;C;T4<,8Ns};w!!Cf턜qv3N#sťltaɤ#umx4]dp}vlG`5 |aHqa!%S>8яܩx$#`؉[cL@ - W*b ]?>4f$ W>h aR N1h=%+%ǻj{C3E?Ie1!};Zu8Я*!Wt{\@Ne3ͱʭVձ2Y)9]bm+Wz^:Lbt%hPBȉx*ѽQŒ (SGeOG AU'RIQ %1]θjݔV.=%uaP1=:uewPuxǵfS>XfwH0e2[fw)sZ^z$lw_17v׫>Y?[?[?[?f;΃2q}&1-SOK0;XŽ𞧥:`UKz*>'WP_h+y3ڽsʝ8M=@ O6 Ò.,lAkcOdቼ ώGD=&I2#)aꘙPPslceXM.a" vK1D)-[e)PƒA̯arp-8ԯNSAeC'(p a )؇;mm;$"V_nCt8{I)4Wx-Pmǻraa1"5JˬmG]2`Bw0ܗGO|IaN 7&S;,6- vf]g6?3<h4Kaܬ[.>QoO[ߚ&5oM;5^= h3n%Gхbto6TZPy0C1;B;J S{ۧcUcJ=1ž `+.:,wLF꒚A1>(^e5֣X"1lt858)95t<+yJ=SXņ bh|WBr<@Ȓz}PJPVT*)XR{2Y_t n%Uu'ppJ am90 WMՀ-٧\9|Ϯ4EDiafh y4K"5i :dEwE-Aݍ'PwLnMCF^!2j0ZĎappG3A'VV1*suƖ#lYYz&>蔉ԣ?ra܄"_)2bҺغغغ87n fpRU* AuX\r^{t#ȕ34I~dD~?;sG̬Bh8qzO86jvkP @k5yV2ei94hv{~%c5u+^zj46=<dg vqӛ9 ~D=zzmnr%"v;&RIT\Dcl.o` .٩ !y&'aaNF%G?y׭dJ-,j%&R]*,.˷xH3poO&_t5QLZ|?N$0}/Dv_d%+[}>lZN>zcomkߩ84`Jxׯz2.%mrϸYΑ@cnzu1?dFΞ2xA{2• _. {Q*20͸I2oc:,@oe%#{I+ˍAonŌs-ׅnm$͕z}%4k暵3XEוrH1cX*^tf*eJa0ǀ/1OF6S2!d]'i Ѝ)%X`\k>Ȑ\S'Hj``QJYf!UJt̉<]jFmZU RC=tP!Uv@q8@0K R>bHR.׃PC+hGmp{:"ZVU}s+@`PtJ>wy/R/TؽmIȝ 1i!s@#}x>#` (P9lϜv- Z b߸TM3q?ԋoةpk@f >ʄ %a`| L2~+P+XpN2W-sL{v4|+* ;﮽]X9ɟK_kUU/[*@[,,1NGEST6tca0< pj]Kn?x̃ F_MBa($keϰRP"3##?E;@T X-A%@>a|4nU'00'#R/I%0 TVB sĽdDpqbVZ),5ԡ*>RpRΔa ؇E=8Y#tNj gy}?˫;Y^a2wdr}?q' ,*7,< 5;LU+sw:_J]6\g~ `_jtܴC<$%s'2nidcG. DB&1eSss$ 0aȔL?t.0?x2"}+qSB IL㷨UBt%Q& _QB˭LUET}Uu;oI/j3G!0c!QuPcQLc;zBF: kr`mgPkU986hڨ䪯nP`Vã7-AhVjm= EZM^ݭ#pcόvSۅ +"aP"nA LOC!{:¼K)]Υ.=dM O'c`676wJ _ izoZ ^p Dk-OI;z89Nxr3 A$pq0NN"nr''09EID\Mƪ aRlhJN\'hHL3}. D2CiͰib%LMKRQkLpcƫGŒ&O8|fp!h?{oƑOQQ&Ff8  K2WFjc֨%cf߳֋IycO:u\Aڡ&9M *ɒpx$4Vc$j! :;O%Zט4셃qrNuzI EɠPuDĚkÔȍvYt]zRL~K8DE8)/[y8-KHel4 = qn۶HZƥ [lףsM4UZ$eWi*2/z~ '˫ϟ{[)X,w]lτC~_lU)OOāb@z3/ ꜆n$P誱{{Oh-G(L9z6RXND BpHj'+r,!yQ8Ȅ`%DGP#4B%Q. 6 u&QګdGf%>"vϷʞ~F0㸛yg ۇtUk\ttڌcܵhbѿ >xc_GmhǃGQP1E]^Zz&e aN_WxuAݵg9w恂*5hjaM݇{a [Z?U5&8L1@N㸣8:ziB6N~uz?w2N "2.9Î$}0`tLj}mU{؍O5` ?]P|PucMH( zKZx ">yRЯ1a!XJ^PK\p:4X`f/3t8B-$!(~%L r-!ӠJЩV yKUMP6][XhҚ4k~MEq Ćyf>i/9'Hv@U>W$&0JzQpWxӸijjE!rYeSArV\OD0Z$d}+</ễe܅vݛZ$U1 cH]H$nJJ*ZqA7&*W+v *H=FE8LCh)ك;ω~WI+ZnBs/L~*.&w,z}Fq˼^˼t4ҙ-xi 0T:Nmlgvӟހ6Cxxv!Uyc4c>q*1-K嬛WM8[ޝ׻G;Ld w$@jo%ƲOjފDe`Ѥ`Tpu`⋇'4HY4.*58Ca>u'NGSz+юwW!3&u9B>ѐqjePK@DG#05gAgԯ,%}zadm$,NAʪniI=*ZmqF*ZqdX.lhkaX]/e{9koťj}ͮ[;wk,RR~̝GߴNj;ƔJHDI%!E|Yc!f2-uf @7:vNPe *AO8d8b4|α7+Y)}PYΝ3- YɆ\Yj[z k=SYv3?]襾hiu2ܮgޱ/O S2?+ =>xT0ԞEeZj/kms']5^,yQ{OکoΒ}7M֣a鿦b럽WO6JP,ANUp 4a֠X`p(mi~GTbӸ 9 fFJ10рTBhǩވJ.;Z~{'p40.q,+A5=<6z^~L'meItЉϧ^xDz(_w. ? lx3\yb+lsϫ+6tL%*Uy8<0D]|:Q'pj0X1Rva BE(ٔKNX70;R;G.-3$ xO^w߆ۿ 77_zU+%C.o'Qଡ଼l.IRH-ayˊ#3r ilL uh j0r ߆U x@9k]jy6Q;Ԍ%ś^)08Cjb+Uk9r+ٙșQW}jynHe +_MӸJݾ%gJ|v]4sgۉCYT$F3>?9 ޳8Ydt|"itt eγYF__d(>ikCS^,A 4K<8?%mY^Zy4t>6~T?s?38@)0} ==p#TnBVuy3{"9PLB:H|ȥQ<(x\g|B bȾ3 ]dE11g uEU{x-'@qsu^:|\D})GГqϤYqhjDP '{[jR;3I\_juj!,t!NՔ*Xi1278G`\eW] ؚl|i%| f m>rgb .\2)@^W-i;h& HJ}‹O&5?)0 ׉_!Dwgɫv(Wa8һkzutݼ7۹=5-}-w p"-+Cl8T7_4:swldݱsGnD;zw˸A\D l+ nw֣7;lhzd}f(2< 2)`N/y܍S_Cԥg(UG"Գm%0ꦪǧ8&ǿؤ>36&zO: t혴#BAvH`^'mⲶ`ŴmC)6_5f QOi(Ckz&mVq|[{G!zGB;DZwN [E&dFYN(p&M5$#HRvbՊF O*s0͝$}\n}O !웯(@Χsq4sEi>[/eRE+!$8Sٛ j%,-bg֠56jLeAx' ,'褂}v\mwipY(n;:WVW$ŅBI|q 2@m]7?VE@Eap w8&k'`*84擈y1\8 5ѧj݇x^&!  SwIHw\7(a<~SfiXNc`0'G?(MhŽ̝kz鏱sM~gq|s||&OEԚ9Й{o`HRzTػax*}Ap?H'XÇh_~{]B be\pwl6«u$[wv5|WTӪi\0૘7Blى0?wp׭3\΢R2 / 9ȕTqB}kFa)Lp;tj[ m|ݣChK$h0Q1&8CKu9@WOzw#6{LLx0$Nje/n}{{wCu4 %ݱo}WYu4قov}č+ӑ?>/G`-MXu Ga Tҍ>:陽 9^;K5Pyx@"²AT撋:) 19ɪi^SӔjB|a47vw6ׁ/Zٹ66.|l1ͷpK=vptrOjFmFg@/ _ٳ=Ji^]D !MWKbpZnNm'T{7@|'0ʜɋ20l';E@#Cÿ;+ LW&D5񋊽_. yƜ[fcN327wr fل42%d$PDr L(~s0SNr|p_'+ҝ ^KkEX0Vc;U?CY M\g#V>s1Y{ҫ0>SWLF>4ExTF6ۘ}'3x|xuhw+9,k=P79zA LщӚYe'suwFyj%af6'7*܈ 1~5*{ 08Pӈ"aNܟuH͐KtP\ _ 7QoⵋUuA+ ~]}?SIaJInRb(1Ÿ\ԮtşFvp9gdwWDz~S4K<(#5QZZ ^ڸxk-®]kve-~kZkzவ^kC7֚!̡5j_9q^w ?tn 5taZ2/o,xhe[,_wq5Ez"' 'AGh!ʪ!R𿜬(G0oC|#@b2oWri<)˯9=0va e8{D`{=)XO:Xk/Rbբ[85mn"T㖘M@?HІ2JkQH|@;#Rco@]FjåKoLaM *Ai_Y72z +;&:ojZ>n75ZC;ӇC`Fͭ 忝D{2- >X~swg_#N- ܙn20f Bg".u̶֭ 5iޝ/qp r/vb $I_pVopl鐠q3T~8f`Lb:Yj=vZ:b~A mX}rEfŊb%-_,-قfit8=lsn:)yY-!+cWD)6O7z6դ7ȯUH.ՃgoGGm `?9s_3)/a]嶈G簆p4?{Ea${%^RL)̪x3 _׻m_č}O60R[$`g/NB3tf|Y2󣝿#;Ը iI+3撙U^l$O~7h:c_04:ň6A`- 6ĬB[z \o(%( {e~Dޛ,'#}Qji dW>Zٓhun~\tx7hr͡*MW/ \XL X8ߝn\#B_]BigKZ }pLOHy|a T\B"6 O`##x/m?E[#g'i"쇥lk ^5 (Z= m[cĕ%ʒsa;T'<%e`ސQ._j:xxgTF  V2 r=[LCxZFm=z˰00y"v!k3C/GTJ,0T(-P{;,-9ؑɲ<$O[]ָ^l׆zHMY"rŘbNK Sp=Mu~ќ&@717эxI!tq)<=]܊Jh҅kIֵ$N^rM7健k駡yZCv:aX6w|x@}vJ5;ɖ-V,ݍ>O>1tѲ¡}Eq8Þ͒DJ9;Q<|Z# jL0"QswvR[HssF-zbK,>{䗄D51"^(qx"HnoJo~z So_o|x%,撝!=c Ӛe|cӪOxD8]V j/K(CYn[\:G>=A}+r{ XIfho7{A0&aK&`f)q] 57RkL>+ z|}r n=-"NNKCes0_hJ.xU>wRs4-v#9:ghg6Jta+ Z.r3B ԕ˩q `oŐT)L!o'1̯3Ztrn{c .)| zCj ԧv16[T9HMr2"5pSu*)B5qpG;d9IGΛ\=`_WttB~UquS3+HT&Qr3M^2nvQ4#z6wwd (Wt]5_ rpY*ptvr {U~,wSn'tBIE%k@.$lK퍹5ʧ]4yw#]o|>LĜ#;΅[ r_V+֗ԩu=hq$-yMb'Pq㲳kV%tcuu$cOr_˱4Fz2i |AƫaYZCK (&bt4:bNBD N!t O.bءN5?_眵Mw7UJ98cg1JHӑv}I7Ӹ@!mZ/V=j˜,r'uNjhRspSP0]{Pny4W;^=XQOǹ<拺hBy 6g.\sro'7}wyttC_[!7Sqi{! -v;as{x rEoPg1I+vlu ]>ݪ/J_J}򸮊^Ox ?)8DwwԸe2X7^%p]GihwAw_vnx3ܭ{t'`2?ؽdS**Ӯ CIio nlFu'`N;i_RICQ[BRy$3|ypj^?>S>wP*@С{j7pzt]9j{+t1gK??2Ͽϲ3a>y$K+?O]K` ^T*0jyW6ƣ\rXEX>&*AbuWDQvbP%:-C S-)Db .[ Kn8@J5#Ω,j$ {px*^AAհN݃79DCxөu␴odޚLUFOrMB:۠mA[md|-FRT[\M3ApžRrq%y93}P6nmn.>*BД[(j\ G?¡/{Ny{i:V~?t鏳?9}O/s4Pp1x~$7 SFu!"|dRrNʻ%ܙ{Y03S37'8ȟ7N'|AO%̓~0˼lWTo}: lTUFk'=)cN_kFQ} pΏZJ1[Q?br/h+ZK==pυM~,9Q,JV!em8]EX5F} m'W\ZS[_=2x2:ĕ2YHE~G{Alu>EWN~:NjxXvXpe&4fVSNM'iL`g2-cqQ̃> N@wQS<, ?;~͕\Z>Sj7ˏĝHJ!U8.ޒໂMˬKͩL-__<^:r}CeVױתRss lz3NC&Z±aHl&rQrčH'[X4ȁg|du;`rx&VN`Y 05'C!dرLxux<VLa.V$9)cde!,,©Q?o<5 8O Mz5ӇR34Hs.N2ˊ0! ]!pNK* m֥_ Ͼ*Y6s~VFO`#UaUBpBKB_LPȞ6YH4\ECYEIf0W|@_ipUtLӇ ISc3,r |rs =Ҩ,NhֽJ{7=6W,6))ُ $FSN4 JLJ4rNtzU=␯JCRheqb *l`$"=aJCJgcRdjK=X-xΖm:Da,J GC6,DB'4 ֢Lq%24K I1"=˕i@N=/;RPF.&K` ӜPn*[$1efdGt%iAN()&J]N:4' Շ0T _."J†՟yAp]y%7b1'1YV٦uYxQ/3c@P%N7:_ JO"ÂNjǪ؅ těQk8 <|Me42LStO)T1 :W_<5Udnhj4Vڰ{GKP4hX~c )?sX Gͼ{Tfϊ$eV(L{6E|E%R1.c.X`9kjiڟLl2­0a9J?}J=IJ] GO)(ڦe ';pֳ`^X}: d.9ο怑0bcʗlk לnRuBV\#.1&7ΎQi)]ƜɗC(s+`(1{FjL2cR;YLJ l߅v,t/˄ņeDZʵb;gAZ7<$'d bpᥧk`F stAaed5jV+c@`*ɚ-h=l?o6ڏ U%8yauw &eY>s91x̑4bI:9mט+[sRل{.dTŪyF!WrKI/Ry_ :(8Nl/;<'aʣ`J\QŮ>$l CQ=S"YIzp">MCCc|uҶ[og̡wH#譑Dqi퀮XSg^oNGK-9^yAk\8oÅ2xAh&fInjoTWqP̐ҞaHm$$l:LL"?ҎlIkm ^sg\L=\q!}z(>rS<%Y%㏁N1:6EY,=~gV ӕڐke4iJ `E4Ir~ÆB2/ fa6B` r Ee`vNcg:Q6/Xɬ)5mխz=ttLZPE)&'ʗ%k|wu֎5 KvtEK.l+' X7pp'= oֳxšu50hN[5%pu{^ìCJ4rqPT4DRhWũ'J(jԽq8ແ+Tjg8[\ | tQZ6\]L&lj7irKK)v27lO*F.CdO%o\&Rӻɤ!R){ "w"=Ig wrT-^!UoGZ6:33B*.Ss=>wLؐQ>86<\fVIJqɞm@sAa1_XTO8dӫ5觳oRǨ^^j:枒Bo;Ӟ~K Λcъ l1yǂߒБ29!!&nU9cpMtr6ZIi B8pVTVS>Fe 3C129 ՟-Į-%"rz\؄Vۯ͕;9h5R}Hr2a޵ K޵`QR-U{(k qZD岿l>5b]KyVKbS`% tJ(=H-eFeK_qs%jc3<ӡOsMgre?U8Ez6[loVA-;y\v' ` `xsMne9xCNz^Wx~#ܓ7ouV_ِi|ãJN: ?IgU XͶ E MAoM3/yrMcW [c4h l9|ٝu%;wU:,zN`lL ~dʜ{GenɄ iH)w8( ~kX!f1f;K1|tUGMMUSl\W0]6X)+] \UԸ:^_M(WѬg1Q}S"Q"6ri7sǥ=$hՠG.+L碹`d13g޽{?O) '%8;u?GM( G}u6zAH\}ӡά.ZN$ 6?#wѐTǏk#pAr7U~gRzT0'!! Ēunt 8Њί:IJtGG×e)[ў 4C+;2 )t tq R!Bj|Π$rר8pMAxp27SnM'2H":]kLf\$'Qu)>d+Q\Dj:OIR&G1-O\"nc,/=}lu>msVLssS( f?7'o83f>SO-lMnn{[n_r2gz_ҡW{@pTnOvN>TՄ UzO+t> }t^W%a3&gnt ygwhW+}d$ki'vvwvEya,DDN׀0,\F="`Uߐms84DLLAW*akD-cĀܘʇ}QW~~s}29nI <#>7X+")wuӴfrcXZ90 ۣA4$HXsGl)"8pR,&DiKx գ"p1- +࢑Ȩ /فNX2&nI4.+=>+I; 1TRjkkH<#TPWh"D"aaƎ 5i8lR)i>ǁ Z'crs6-Z zHFNjx ~_[5~BL,7.,*Hi)< 3-kxCf~n^ #3m;^>ۙ&73]ўuvpNނ)IMp8F =H{M_,ȄO' À* rrK9ja>YfjP_dZ !Nbh+҃"KWΌt}#L CNs+ɉ&!44f6|r=0 '!4V ,zJ\0p XzϠA ?5tbcC6c?}W(VpZJC9'jX.*чrǧǮ ("uC# ?SKОJj5$yim`Aܲ_NڢN7eU&s $6?4n981-Qsrqs֥ww7v[?5PA|ۯj BL  WeEE$!#,?fYׅ"=:z!yR 2|9,[ [<&22l{:8z;m|:˿VŘx=%F")}[=1a`MH!Hs޽7V;Uwfge=_Iȹ7'! 6_m(T"ե# Z gP䕖 l[tQ GH'j?!!0,Ov`p7T!F: ݤ Ѓ2RP9X]/W׮v=jA3hnon|i^w=pa"8]>[ȡKǼp$)mde-YBxǃDfRL"$a?!l'Cbm-֬a?$ K%ơh($BCjކ_.ܶǜ&zY5Rf>a? Ch%#W|i!a{Π}vORZ>lH=iM}]!`l.MM[6>ˁǮX:ޓ mje >a{k%'0,FIH4:j6i?*3IǠ؇&JG G/IUUI|T2L:'ͮ{j32CZGcE'|,5Zao~ozqf\jQD5T.1) Xթb)K6wү&sKHdsN.2;ވqhK8SRf4dZaխ霆%RZK >I P:t(WWtÕF.۔fIuJ4!ixM  T/]^AN)r7XtY0hX8$vY``4h6x -lQi0ll/ G!#Z\5&Y(a4h\IIӨF1$J,`*%WI)CxC )F |ܛsb=(s-,OѿncPf S*<(&N-,,ѣȦbDt-J\ౢߵⰋ'2CP: }!vtۥ7(|#_ ME4l~-^^P_I/1\肟3]? ^ Kwb6 Wo sXaђ,Dn}ն DfIӃQh\fe2p~r4d*Ruyu.k(ӣ`(VY!v“ jA}c3nOɞ #vl#ywJIV>yPy .a zq'2ܡI.zVn$؎K*>:tZ^ &>Spzt=zX< t'bri e78mn9E "'^ss T[mss+u a)M_\[u(y7AM~J6_mTo Bt8ǩMwÓQrkg#P͠mщ cѧ1]*cLD'v,Ni*Q({f z}"W܎%slq`sdrȀmvy% Zc]sl]L;Z]Y:k8 =2u3w2][K _RbElYrl`e8I" 1msθe*%Mt`'^l rV6F#G䘼iKhRb|H픘VQYSjVlxw̌7!v8=[>b\ۺuvtﺜzٮˋq]l^uhyAA/p"Xf+(J+itۋt{#X1a< [ugЇam>ur]=Z^_vIG }3j?Sv(ץې[+>$\cFG?pgGe.uT6phe<+B>¡[ڥ=O3rnƚ3D{Ռ N@E͠,?=4ni!X5z\.,1M&߀u48x)$jxH@m]03KS$ \DtONEz]I+Jv_K5e} uukQ^fl0Ƨmȴf&(jڎgsk&E{%z}sWΨ]+8v|g-rSkMb]P;gvDܶ̓2$>Fg(X$@)"yj{3D*}Ӹ hTޱ%K7X $x! %Nx|Wq3q8˸:j6!n) 19W 2 "%-k2f @ _^ŢFy::3E4+?/6-py w[ΩlGN̳cIP?4tO+u9hLE/ʚqs*hVZT/tF2$_ƹL7(>c`捡 Q&lWVk'@vS95n'%^^)U'|oM^R}4r)D/L3Az C/YR$A^%p d1O: pxTb]S jǽrS/p?N"ON8\[FOǞ2iy_jp. KNt$SSV/jcWyE5JN\)5:i1v]NHիMn>}]VԬ0d\ < %sQ44HFKZ0QBDOi$\f]Ť`n~>*P5N$t{iV`~GNb!VFo4gb9U}&>3~`n7N4OzEH;O:Eg+qe.J9&߃L_ApNCuSOdB8 Ey a^xAQ:raPٴ8sNq4vEM:N⯞9ȝ.{`2;ъ~lN}d?y`L|>[ s^'S 7ӛzbGSwXczOGg0KoߍSHEgcNr}G=YԿv|zQx/%fXSaӌ5S`ҹQea*!I7+ּ33z{{͝1@fu$2ԑb{.zN6i4f>e_j-NB].Bz゚Lp]M\`S%*o؅D'K7o.X/S ?M5EIKoX(8&B7#0zh!SH-f3 Ͼ:7S`_y3 r7况cqF0~qmۢ|RR_i9UMpTy,IfH]ŸN#%%G̺py'! [g RFOCl|s◠^D5t^68@Ac=?9?qIo25`z@e ΒG;XzG%ºn~V#me7.tMl4.c)Y֒akɕ2.y(8?,f'ar}1xR^x.|^3@h?0`@oz8D8*K!+NgԖ?db]L|/Îc5IRƟœ43B UT.դqoZM[?5widǦ+q4Wyg 2΄(q@|7)?oXһ4vdPLet˘\3 6ʘOم]\}σ1;K8[ m,--={Dϟ=Vo|?]y|3Y5+ w|vr2=F ?S/ R_6jGxFq;۽p<-DnC?vI*IAx?N/%ߛzE#b4c )\zGCu#lDǗt0*Vd, 8R<:FPp1vV& Gk2#NG(o`Mjo榪U6niRw!V@uV7߬o]* llmbEP2ނ֜ v_w_wX:ήj9ToTիZT B_umn#,OsT wo7\ZÃ]h|xpMM}w> 0Y,  ]?h@Qq_C؏7͝&Uv>|{t ej}=: vNfɕ@QBh(ucoU )kk1}¼e/8G8$"Ƣuu"Wq٘@00`e sݏիNKWvsn,۹=5zh[iր:x0Fwnm̲;v͗HT|G~;h5MtM4+l)vh i:i~p%N=%Y7:gC<%> K)Ruyx`xK9o{c[aj<y{sHϞgݨ$I&֢^YNWUDs=6ڰu}_+l䒦ƾgIp7I;UzUOmjaxR!>iT,{!³`>4#d) 'WNF:xHPG'SOy,mdXo2ay"^(+D:MFpb!#xQ:`X:~ T(nPX`TBoڊS9[i+vlV^Z/sY}sK\7ލֱZ%~'&2c0|j .ѤMp5;6 :hK;tɚ:uɚ?]NË4It-P/:Q2.bȸ46Giz|I0}2IUmpϩ}Qԫ}V8T 03\ }ֵ BV#8WRi%%,~ xT+>YiUߐ㏬kQ/:G, 2I#n2$"4VO]C?A|Js֌:$yIK0rVS#8Cfƀ9oaIWuh!*A5:aF#!C0Cs;;4 h 65طBM^E'( 5n Q#| sx>O89Ld87E\.EA44N7Ht6rS]y`dݘ¸RBm(<&2YB4?2ftwlg{53.g";U"#fai[5kh"h gu5Q O= 4Y^-k^0tWUztC9 צx-[80Ӎ\Ӄcf0sT! /Fl)X\r@l ӐE >&HmJ 'VAr6;}#؂3!pW0"xҪ,V&'PEeEdM/(f,~Fۣ#P s/ 6F*Q ݑxX AMݷQ8K)rsr9y8o͜kȻY=ek0ɸ4<Qi8Lߎ̍IU)/*zU̡rUsvz Iap$ JIt#kxBf1X|6"油"Y^{5J?tWG5 3 }\۴&3(ݩFv9ˍ3Ψ#ٖRsf@Ԥ5L߲.D54[5X8X8ѥR{\C^iz] l^ =Nd;WMgmXh؟Rʒk9%nK` cērza>x L?!'r fdSG<оb)}drYI4^Tq9NU_C#l{٣eWʆ)#CBsgw[3wd`eqށX~DCBa@~bb/!EvOb`m-T?=\,L6iNY2MM8%.rI8 K}I(dެY0xB |zV"fDt%CSVdۗqBc)BvDf@|u/=0`HIשQ&z|]) bw^M~1s#1YZD \K3Q` X4%ɛ=>pX(u0d 4]d:Axym-goyAtX#EIݘ/9yѹSgQQA_EP0ҧ cg4U# `PEE,Q$ۅ?4!_P)3t&+ ȝ~9ƾ"~d%qC"ּl穄3d8;0T?TO:"p qw)j {o&rc5x4 UoPl>qBbռWTx_aQysrB{;t7QZo[ *<K/7+-e?` s~NUsRn#N٢ T چ Bds7{:YOAwUeUu!O%/P%o|173DLdLr;ta)܁COA-b2pBM%}N$(G)OE JiPAsW:&&Ӽ(uz1 r"eJeg˂A|Y7+MΊN ^Y,ֳl%]5|ӭ={ =V{b2f:s9I9;j%܄Z:>턃%sLG[L|\xRfkK9?=il:Yg4n7&I>\Fan!bc{s}'G$"_Ճ%Z'\@Z.ӭ7;FdQnp:c?Xa0Df.cg>.%IxW='mb*XdZ+<&E(ak)買WbFIΛBy8 qZvF"-jg;cc`F a!7 .Ȓ\SҸ_ۥw:VzUj8zd>z،H=MKˢsz"_j:Y,dzu ܼt9Ip9FʩVT1Gff#n6gz9EMh5]=c֩+wyeTg+o>}8>sO{nڸO{݋_\rzO3[>Kpo?I$~$WwojMhtrZH᭭׻uW^=4a~l3*w@ҤqA\\?9[,DÍ;TyF5\3Xé*ى1WU`L!XÐ6 G Dq .P!CscIhQ[%UG{JZYDX!5) #K;k9EoERiC7$bCBГ[AX7w~Q>GG8c8uEIzk9ѶfmiQt1m*lIdB\#gC `0669}=x ֿ!sLG*ҳ l0,0#Y @륧"cv0ZyP/C|) aϋ(1NԔ(,GBS#a-4Z=D qq>_P]`Pysn(V9?4qXm=km&_sύb.4 .(\އdVV/@2U+2P[f oIJuʐa00?C^O3¼j (PoEz30&?!=XiGz2:IRi>OEVrSg_˰藚V=Bۙ6>j]rfpns&*Zë}CbizaǾ4r[NoB=%~F״ilS$MGć$ސW1ZYZ .| c:۰j֭is ?^0M+hlB. zlAI"bprW vJf+"/[l$3## tB`F+|~io+Nw03raӃCԍW_}=/,|҉!eM'^ O!L|/zZ9+]tHxPj&vp Ԣor<<N#Q81+zҀU?~ 0^`=Yһ64J7I< ?^} 00NAx.3RMsEdO;6R5i )hÙy|ԣd+Zy" IJP`pF?AgY.`CFvvQo߾3$/ A&KRl4'1I 1CU.gH)JGLO'ʞ[&=å[D>Us$Fޱxnn1Z'v@&}'LmM+<=]p{mN"pajobQ #zlǩkຢ1G}ѩH<%5̍M\;FRV) U:v\=y4V`i[V$H!X2p*|P ױs窭*)`3g֯Ng_r/#,3uBW{JDTS-BBJԂK)py~^V"/447 eQ85S;r~oldvCלSKȲ7ȱ -4a\\Ǣ'f Q{IM9"۾ky?drǀAxt^+{w}(95遴p9hmn:q%484?1$AN!m'9hoپhHOTk`}kuWIL%}27K~1`zདo/r$ c4mD6JJ*כM~f܎=xS} •/FHĺ_aQb襭hMEn]#(1qGc{Ux6/>U%q;c,Tx>qubli] s3]{(4^%^(.1&'3Gu]to2 4pW! h/G6eNW<x]ad1;l?{ =zDj}޸͍?.! }66ڴO=+(!EA=ߔu)~fHt) JyNͶI$ o+7#v[םF^tZ I\i<=0p_,J\XuS<<xru8SgsFJ\vlWfi w!M!R~ 򳣒tXq0Hq453:D7YSk%yc"qP\փV/|{HAP1H|~fX!bq RnNԷϞ,-A%.8:R"8F\K:^F2",G>Qbl9193000ثAUW7GwgOBӺO"[L'$3qS& sHn2fg I խ\z`o.lVdU 0uCd1)Ya|JY¥v^B\ z)ȹHmf d:zesk׫k50Nӧ?xNx_\8lD] OafƪmBɡZ5^%]AstNh8s≘z+\ 0X"FꗏSMٳsa=Yi{srMr^3ra M],tTi1iiRp?}J-Crr7Ϊo_a!3Ӣ#$ m/͞C?SL KZִ-k 4t1 Fͬ]2F}Ť;qSj56b& )HjQE؏Mi||J8|A>g7":hcwdn=X˷1R0հ!Bc]thH!'GC[GutjoþL8C/42LOmJ][JzlɊe )l)6G_W:Mݙ6o+}CmwDgۮ;5[M86e w6v5o212wFtc윲:5NF62R~ދ{;[ b ^k"`!L,ePη'jf 3L>(}(C>L i[=Ra&'0tF ,Tyi?+1SU \qBNF'QMQEdpMy^s=ӶL{fڅ'tHK`hD]fdtx$5tQGǁ +$U͉NTDp ˩1B2Gm^Q{te7syS**1)cWr^ytE  8V$R_< :Kl1^N/`Qޛ[5^=s  ě/18V'/b79E iɹ(c R.*it\.P% l`zac d+IVpSVU?ihռV"O<~8Q+_B)?Q'_F%?V#_J!?ns 8Zx 4c8n\: j1Ȇ1FፔRV~wCʔr5]FOH#ҒUx7BŐhÑ+in8<\B=_2Ѕ;֧f"ǩkV KGof_u_}r/RrhP<ı#$}@ޞ18hb4Δ/9hSd4 ipZRNG捜B3iWc6F2JvM9wp Xqd=P0mO8q6gBu΄eJEdr%#}c%A2FM88@'SzŎ9O.z2@o uA]Է2rԷ_lRO_v:pS#2\9Hr|X[ Ш, z΋)]a"P5/XƯ^˥8PXbʳT& /8U](700g\8H.6' L8~0RZDؿhFif%0/傁Y+_z)P֋.S?Q4VU(vL:s9)^xp@S+˟T$P. `$!KYo.: P'fWkƃRGf 2vͻG:?&^~y>0::A>}~<T7ӕogJuno2_=y()V2A|IFCTKāv=(tzQ9 砸s`h0;X<3p6 }2󱥤E!7I5/Yw|s;K92;)]Y @JP8y=K̃ 3֊Feg#B|;J^cr'U]^J_Aç䴄:ztc⓿83둱3erN~3U=O)GZ\fHNU@_\{`Lc*(*@iɏRRBik#eO@nby,l ũ3T*N eeCnƬOs(G)MYy,s:dQQ﯂*6^|Y# T9dԚՔD81(ǗTS8% -(8c#:tfK[IS@G6%x8O/c5D3?Ky 61#9 :gf\s TƢ$ișN5َV\Ѿ ;َoQכ&`ӱ\`[,1V!0,)ߨ8!*Ш@oo3EJ"?6ݤ 'O43q} i ^xy0 ~Nȭ?4}+믍\Lw<Ic%}w2q3Bt5ɐyL`"BS)4$]f۝xYQ<3f}d0nO+;Tx72dכ9g\2~0rqoWL2`D%'-m,--={Dϟ=V便Օjyӕϗ,=SK++O-ZF ]I~೓1i0Ka'F]8v}v ^~c o{Eý I"p6Htn` DB;(&OȌG)^A])~x9 IF}|N"1Ӗ| WnZp8}v( y/vV ē>,o`M`Ojo榪U6nibM`e[0TAíyoYTP?Tj>Ċ8ނ֜ v_w_wZ:ήj9ToTիZTp8bַqoaxGFIAGP-|6߭piov}65z=8jpef܇046vwkhp|Ѥ.8݇oLCo`GX. 4RZ(@_}ѯCX[C x8Q@noUD0LUMdmL^ [h^ϸW!Vw]ԫXs{j=Xgw}'ҲR[x2Bp[ht~66,/p2%vWa7;k2 ;뱛hD7DS QKa=8|Çvw l#^w!弁 m0:C!OqM҃{]ع)粄UA.jEյ#UNqJ/iHCNEk u}}FP.w&sКԊ}Ԫy#~S`2ăBT ~T880e:#tKx`~~2wyl~Jn;E$I4xtp_&1v!X䓀д˪^y(>BCjAXuŠsles_@P2 {zpø YucRE8 CAd&Y-j9+a=A!t9u)U*ܬ cVJ݊{2 qYGD%Ԙ@"sOuՔ$50JErwL:ymtyjɖRѩ5Va.Ȧ,ܐZf@zȔzu)Kh ؐcTq&1sRumgZڦD`K8sΨ"BxqތcR994zG[q ǼD>($,>#aPzC\m:7x_ѓ0S)$!8zQd9\kXld~(RC '"MKFXP5p^&^h,K/1Ke?Lդ5T/~'!">"~Z{<!s2 zC&ٶmOh{m~Qf*GgY.v;oJ/,V#-bwF r@/}cKžfdON8dZe&N+2Вc$GLv"#,Ќyˋ$9ƎYTPo:<ȻqaN%IEO5.Rqz XK-_Zb/ȵ$r'H';W8= 2:AʋZm L%MՎWY;1. J(;0zǣDTxPx_ O{-[6,P]!r$H!$ yrJz gsn^P&7=ف5rv NKYAc[BDP̅:,xY@!76ލ{3JU|iŖdhCE?0W0#o[N-q1C_A'$NY-9Ќْ9'CKOq:w1hEׁo ue۫#) e4} M/Zvݝ! W77aU 0>LV~ <%XWvX14?aS,{[dqNC]wigomF혲'!c\ |m隁XE;1{~G=`ZԶZ}A{q0Ec;@r" R^C﵎!1ΣIvw {7el5%b!r& {rn  IZy^g9qZO9dsR5j+*3;UL#v {" :\7_KsR"&HL7 pKndk>#nu bc9.B:c :^QOv H78u#l TֵYڏ0B>^cz|w:ۯV6uw6 xV CXH BZ`0x e!WH) {IHNOW@ CJFG! DYcp 29nږ)ըYLYmlבHr?{wdAWW^U8jm7:pt[?lޭG̤0n7;\ՒםKtn}kʛpH'j#5^_di1fW?N]UKP5R:Lx1n⾋Xzϗ-=J9[JhFd `AqD"*(w9gl$8ݗVse.j`h dhF9 hgiZT)9L Q`:QQ!đK_Qk-"@b39h$Mq{U_㠖9.!َ VQh\Щ#m΅1?j۷ ˄MIkWs {8W=d|![ځ-1fz_|:HunP藶Jt̍%ٌ5Q>JTd:zC!a ;НD}y幋9No7l30A7` x[Yzfzձh^l$.:6(fr(rI{^PAˡꁀxd*s.sܵsNgmÙ$ꗐ G 6 ,櫭c96$},ynIy~3uJfRFQj$x-Z0ڀfF[Ƀ\='ї6.hg`_$AD2֥35ɠ{ ׁq*fD7ȉ`<909OI夦]-qSł  9: =+@S`2rb o*Eyԋ`ЊSbe(3wDDI's8:\5?[] ={Q&5}^lo"EyIsNElQ=ANղ!|Y+ V[:gthmvo]t ou 'gO*77``U1TH[DLy8+zxk8#N*_z9=7}^y]|;U33<80ֆދuw=vCB8'VBjR3,:`SYN%8_hr­hgS3#b7 p47 $2@v<2Rzu/x5N[g͹p h7幓 H[ڝPs I{[ ]ł$xH΁ѓӹpg"]Ȕ R ҽhd>}ktY<-|6ӛ^Ԣ{%(Du^r~|7[ߍYN(g`P/ aq4NLm4 p)QġaȄEFC z)1p9Mp501f'w9vO.t= |@_z냃 3tlZB Qk'bFvsbca=`0~q,D`18p4v#]ߡRм#a΃ٚ$pfJɨz - J׊<(u"'$d^Y=^"ewfN}1>@:_%`o[YMV٘XݴfRH߫'u?ɔĴp~5mW<^{sd_每茦T!V! ~Y Ǫ ?,UM>$k:<P8*+|?}I>Dc~#0X\[M؁3h#/gy *Ucq@7vcɭqH[+C\>7QwIsĝ0+Ȍ϶@wHc?,OU#r΁%s{Mu%bEt2dƻmk*?Nxb:2v/c!t>'kehÓͫG9.2Ncq<qr2_tp jD>BF6hO^/M(<5GB|R20ـ*:I*ʼn.,nJ & b#41UK)t%ve#@ry3]l 1+`_!F LUsS RrLk l]]4'>NF2pSwcNUMLh#(:4FIw| <8LKy꩜q_iI@=b ? [8KL/:1%Xy>(،I&L"#-1DNe/cUY9U>:S\E.k_hC=sLuTFS5`ˡugL&/ęrLȭѤ0RQ`AC<<+&)a*[IBGn8QTs:YW5>wRiHHMqegm9`81>\C6ĭ=}\r'_F/Əi_&JGf=^PO_#ϧ ۙsݸ۝WO(fq4 _bc暜^R 2*dй}̡Hc=֪͋A6jNA n1  WX7lo9}mS1"Ny<`7f~r6;&EؔH&B}m2a%`1K +iǯC*8{25Ti8KV0!#xd2^R(Lj&S&!8hjĀ)%oW)$KWPV ƣ zC,DR~;2}\ Յ<2'gaL@AI0e^$;4/MtSxScR O΀Lukfӕw  NKnDq̖_bqNbʠb"DR"pGTf-Q_1Iw>.~!y ,8jd }gbtzF'sQwaH?Ps6}I>SzxA;ӳ$ff&I?spwc1he9q{W\S̾ Rm5#MYXD <2wf$a߽ Iiy[Yߩ#ǨՄcrDhN/ZE0lB+I ^,H1^EUήqrTz{Mk a;}q"e88K$q8'>#' n9o)`ٳN]sfJJizi@GfC1s:C쌥$`w.>Fv?x d8:nɊgiciiٓ' })oKO+O/?YzV=[?t݃0$q?ɘ<e0Hܒ8@QW+(3loBAϣDׅ.2:j%D<)s19:h ' <,82eb$\q ϗKu:8C%1# /qY@RڡFY z03()mS>y} STw6í70u;C, lv{}QPz}py~:|o7.v66"(E15]s-jk{8O?5w['C_m71/m8T0sbGFQuT wo7\ZÃ]h|xpMM}w>hM4L(tE?ң:cf{MsgI]*pHZ:vw]*x (}^4ucoU )9_7!^|/{yԦvtH\'T.a`hݥw+p7rO=ֈeaw-^ഁ{0߹ »Ch| 29l#K7_"Qe\wK nwd6vc7;Aƅæupx Q'T߳γd؉#e>Fywp ćx>s>>a:1>GèB>v㠛7H2M)H,l4BôCqUk??7k;[pOBw_ptxt;kLQ뤺:66*uubUOtCU8X xݳ8z1%p{zJSC9%PB+vLо78}YԿZɟ' ;)@Ͽi3zuL -;nD*@̄2GGTF`W4ءSUS;4f R^Q7ܴŻj< K7.9bZ\c~Ji}*ks@Y\Ybh/6uKj=C[us~ '[μr4'sمNx!T'*Cس7ڛ45mu,jp6ֆihkcMmkdDA<>Ǜz좞F\CnrP?zڶ;pW\t|{']*4ptb7:ȥ"(#G(;?yQ`8cl8 gn5h:\2)pR  ,jVx_]wť-s9W)D\~睐Hw#ZRhybr^q^,Fe\+7\F"&ln4/M))a$?]4GT揯<}Z2OO=1D+1k+){[:Ե_-ϏO9Ѫ۳_pwwRn$PgW6ﳰ _[IuzmWxr;2?f~LuͲ\K)qCp@d?.3lQNxTN/12#q1x}ޟ_&]{k~/xq]bge~]Pw& iQ\H2}^:ʼvX%1x1,%Fy]S>Ta;gmcoٳmqv}ϟsO\9'S&fg蜢0ء~ZhP3 y1>_8!qKyO(H ˥AoS||_Qɿz;__q#hZk8u#j|$/LyM*(L8 O\Vz`cWүdp񯝚@)|"md0i<$:ķ⯺eG@T& e9Te9ȥ ,0W&ɽ+qa%!H_KZp 1TPUīO' bAK(@79H$+jv;0QoA&T eJ2SȬi_4yHP:~XfMY;.5I[[? ' 8d\i-srɥf_M)V;eW3Wl|aوd_r7LwC'.6tB X#SE@QIfsP^x@[s69"_2{74_эac{sH&Sʙ2rt&Vf}xGk~l~EIhahj&بmffvڻ?r4lN3; rקkXvH+]ꑺ"d1p%4њE9a 4n@+v/4XN#Ԁ]?'I؋u5OC)%}՟XzoRΑ3h 0ᛳbpIc :%udCVY?&7xEl. dXW/kIZ CߐPR?&@K}؇% Q2! Yu^G'(eTtp$i8\E*7ȇV oЗyW+}  ڈ |/[Q5(g$ s2*>M|(8 ^YbzfyG'G9MSh_Nhq#OjoBq.Ksb esdzJg sjEщle&H?7[ % rHIo4?љ\ hc'' q'z1#|Pf@>\7D'E,FO[hmR{*wZR#OCX"bw^[j]!O]\[r]ə17Չ/X?5turΩI6<.oϵ0 ӯf\1zl+h~]r L+Kt,=#UvKf[< 9ʟ}XzXRmL҈O8,O\_ W(/UTWV@kUTS:挊8ݙv. YcgK b%jpe'!/'J|nSZGPdƛQS}V4ߤoE<+&l:qzkk뜹vˏ" 7.DD^=1jBHLOoOytGJQ:>z>Lxw6'HjוO߯ʃ/]Uj&ǁjV#ˍ[/'S?+,Ȫ\* 0S5G*BEnZD A'`GDnW#hjf{Ҽy8S[8qO:Ry[.fncj+3J1oғ>{6~8Ϲ8{eO|J#h| O^}EG U,9qסgzE,Do%-?Y}~|+?߽w/u/9TV{wX(zr@S A|y/ _ ٷ\/vuiژϟ󿬮Q>zu/9?S~ؒmLOVs/߽]ߟsOw};_LJ,䋀^)忸sܾ{6~{^8^sj#_d?Q?zu/9?S30SɀՌV~{^8^s{p/ff@#˂<8 G͠[^{^?{*%or(2?S`: o =߽w/qv׽SGy{=ux*},8ii _8+~ L■TgU^up|30R_ԽkڝTn:zl5qa$Z?{̩L;?SwË0DI?lG?=yLMC}ù7N n|2B<&zJfY99^pkx3agw٤ȮKaڪKy -]Hvs䵃Q, T :Jl4T!"JBD{bAO'Ǧ$5 ?mdm;mU"U0hǝPgBge;>*ZX /b]:Fl<8ګ-Lat.萭]%yxn[従dV9lK*NʾqVI~%I<Ï?LN(ӂ9iࡷJ.z;#V\w ǘتE:$[%!^eV&=~=*&ZH0=KVN>=z٤Vd&^o& g>e RϭPB1QD]LJa V y0ˬ\MJx#+\vS*w̞"LҞh>5.JOa/ixjzEUs,@iҴ={|6~&?؞%Xgo+_oZϭP{mh+Qo{%z[=WXDZXZva5E[\;%RP;}K$*\wwp—cMf]aa=v;yI5EE(ICΒ?e@pNXx~NzABwڀ]sLZ#•9ƒn 1:J+sWQE؜NDA/x|6*C%9;l~BPE5G$kNܓtY2Dq*12uc|< Iz.}Y} >)>dUZyhuSCP]xnG 2@vm ^1G a&`07S:/Z$8 MVNCR`vZ+P=/H! =Tr'+䐽QvKHch&QpXZX@/&h¾<ۄwֵxTp v e6.zOȨu1afBoekgwL;L$GlVwSl]6풶YM?OME(d]0S-%D0l$>1H$urrI%BkQAZ^j h#_{"Ԑ4™g0σOD1XKˍoE h[RڗCxNRҢ8wc ߫3&odѠW,o¾p,w?QME) J6 A[n:9xLs"rBAY*!tum8m|%BphH0Z6_;?E.}\{DG\>_U-1ʧs9S߬)SO@bp|1]|JN~BOvyb ͟Hpgbs-^ @L]_iZ%%Z7ҶzBntGfkkyĸhqh!| u <> %ٜ$:"ݬB'hĚPwV\j=k O,\'Dݾ2&N.Uǽ.H=g1T gsM >W]RhՓIm1-kBQ 3@jHhw(ï k,j b^d)/ LB&ӟ>ڧ:r'KTW9Þ`3[/gJtZ*69p>B͸UahVk% 㞻 |>s7n o|.6i* Uɷ oH^ #oiO uLvL~Qd T53<7p6niNH``?"SH IRk?[#}jkJ qaMxx![ @!w șHwH4 Sgr7$NYbT^B$r l߉ripآW4AO(/αckEH^2JP4qv3N=$M73̏NXbwfY3Iu( |&4)YJ\xt{~/}lMŚA+gkn{d@Sh3J]I㦹peVo9pX*\+q[B^aU.|@~7m?63֖]ү" 꿷KTӣM{SӍʿ%ANgNEk{F\Nl7Tň@[n~ǃBUNJrxxX(}sG*] -ĕ X`?Ф"v!~9zh rҠ@L׽nbǝn*;+3f?|.Bsѭʒ^î%>:fF F]R(;o%j&V?A{ ΆS?M%Saf>5O3EwwQuqq<_\[N}z|&"`JEtQ xVviI=_<[zֶy]p[|CE:_!I|~̚ 6i-*jwG֙~E#y, knx24=aZ2wstܬA0W_J(Ҭ,Ytd#tvxY./D#+ET}$PJޚ&sKjwz'Su^7 ƥd."WZnXzgvP2 ~gH8uɯпߖe SNJhk6MqztMtzh4R!*YHl CΨ_ư8L44Dm1$OƐMg3 q:._dkO8Ro[@W2#8:H3 F R6&V㊻`ǽ}@}LMC\8wmÝW;MѮj-K8 vpVp钻_,@еRW`Eᅪeow5bd|+M>-1c{|3Hq͋jLNil\Ƣ'QJ׋J1 kK~T|/AȦ-v Q*ˌ]9[D! *kb<a=::hE ӻWjA9ծծvڕjWjWT[PkN~~f5xM-3P%݈&Uٚ :UNUԭtUЩ trunUL%=vNR0.Ӯz6a!;ԝO۝P*4_mL.0a.m]V>."K47;FJ/"ʰphOELnT\i E6I&IJfp z+=Kx%<^r&o`5:4E\N1pCpKM?#Oj? r3ZMC.Տ# *r/ eqU _z Zt?[mxVbqFcZ .t;hwJ*V`,3-`< yY/8fA}9`;ibv[;[ .^|Raop&h&d3@0T$>-qVHxo% 7B&STlwvzU>;uABt~ɝa3.Mjͣ=^ACf;/sd4dRe;un$p1q,8R :ޤh Mi=! ۍj{Z%.Qٻ.Mi)F)X<ƾȜtsr?C?YDm7'k21B I!Λ1 7p6LjD)G!w!}H&!;Q!*Q3wqɷzH>,yB9k9t$NOa#9(_..; #3jϞpiuUwnO׬Rg백okcEgRPtCyh(7v߽klkU6HM.}t|DуM&rYs6IHEah 6tu+!b=ܓ[ xDH@h-LT!:1cK55KLIMOj؜=7ۘo2s &+DFaK,;#ҰFiݯCN;E`{2|@WϦ)Ӗ#ڞTԇϣre$9m\Р*`j*rΡ Rh;4ΉT/d|"$s1Gز!0 {h YN EØ̡ZàUk}bw.29ԕħgQ@K8Y- ;arp>hX8Sg;ւd]eRswv/޿Kfw4e\;7H6;R{er*{[ێ= bѝc犫w;]2:3+[s_P73 _VQ At'iL`M8 [o~@([N˄I=zG gAZK1f4a@4/K.:O`v"QȜ qz܋//怜:}S3Bbq;]sަ+lJ4X>Ń ?p9T7( YW`)}}l UFchȮ;/_tk(f 3ԍ#7C&S|ȅR5#>N|!lUx4'ќ|&#-'Gٕ6f\If;j.ܫ*<΄M=.IJ"VC c l'{9̙,k_,IɓMoϭT@2_Ճmash`w?#ػ^Gߐ<7쟻;M SkkOoюWx_ݿ <]aԯgn=iO7֫÷ν)q` )G3q"ƫj֕nLMYq g? Gm FWϼ\S;_A cs7Wҧ XxshOvl ?8)l;K)}5|ϛvmo&wTk_nEްrF~p8BᏏ>[#*uq!Aq T<0+X°!B0#ќج^pPwL:PN6Vvէ蔽%r4b#,,7S㠁B0/N^|xg//UZX)e |oJ1~|WJj.3i}6Hy5tJ׀+t pg&IzV7IvP[=uT2CS~ |GJ=I,| Qx[KP~[Xz]{\xIi2{ 8$B,S0، 9Qeg,SQK6XNSg;ScZMirc5OYg8FcY aCxYhIZ[fSe:ٸaFo}`z %5zQ=*|MXu<Еh/4U`C'CJdk\Tr9a7T@9HT F$ !>"B쌱Z|3tÖdM}#t휈P(& d1>lx>Nhәc a ǚdž0QsWRVzj–j. r LcRDN.$_KǦgS.;57|.s9kY.˯?%d"%tbN'*ÃB@QG%ӄbZK"5IS+\nǘl?t?f!bԛzYZZz?{J6 ?ϖOW>_~L-,=_Y?4c{S#Е;>;9Ǣ̿FܿZoVBdxg\b G狕+_7y$j1;L>ѵI( /8 nLREGp)u(Y*jywUpكQ6ß:O[MU]?j}gSm6wˍM:zul^zwFV@uV7߬o]h llm"D'ZmoAN]s-jk{PU͟;еR͘WMj^C]v8lP opG|6߭qaov0y}wh GY02 %8u~ svo4w6Xt?HZ:=:T%ԲӤZ \n n}/b eJ%:r>c+Z05 WIy7:s?p>YϏ^;}6E̋LvB ;=gczk[zՂ~l$tk+7>[^-.>6'7 ,3ܓ/o'tEczƽ_v*o!e۰{D/௷ﶝ?;?Ħg?ڦU2mAбmbgHW{#(_E&/p֨fOէ{gݫ'љU]]]]U]oq5I@dƊWJR}4"gSB PV\}1Yw48z9GoubЭb!\7O-qV͝)ٱ%],f;{a;6foj~ aT~L&f6vmg##qfreUJ5?*-fT*uO=RE.ɖU._)RKU|2\9U)[,/*TMի9N-TfA.))9nH/w\ZOpNݒzR^sgH+Vu.[ 9rjg+['Ypzr7=trydJ0II-ܽ &|aWFbFOSANLFĮFŁv)F' @ 憾'$ .'7 Z~}Gx ChN85T%?[a^|QxwDwW M cI ]lNCHR=nֻWU#]<0 "p7G]fqhydDžLnW^ }ثk}ͦ đ޾0db^t!\1gy!t#'ŸxU<;[[78g=T- C)o(ϼ+qH2AtŪ"Fc~4/_M!@A"9|W@u0`ȥs♏$T̑K&G,˔vX=n7vߞ3ɔG-*Uĕ>>k)k1z%>Ľ}{5m1ʋ' aC6bUfZQ!.eK]&dμd†كg1o_JO7zN^Pzp$u 0x:4+PIV {i*9ut_ ڤu۝V&ggiS;g-AUEX \d'8p%~5u c4=GuuANP8(wZ_h?U]sh@Gro((IBe=8PZͯB|x> hilrp* {Vb̫sC:#Um_)p>5jh%r3Nf'Qpf-8_km>@6:0_>ҪX X\*+Hrx9$r)ҌᏮwR<*_#c)ƥ3[e@U4ڜ WsҮX2!ԓuTNk B8E%],W3gvpTt©{tWը6dWWry^m~`AިyqH:$7%IN97/61kI@iRbW5 Zɔa1! D;S &d׎[!7]?~big*= Ej|>Of@Va/.a_'=~B{,r!GBƥ` E9!N{gUK˼c +F:;v`$gۚ =a* @0)U4-YdB&7VB)_|TO4zFpߪX+Pfo4]a 1K zSQ;8^&z3:ΞƄדOFv 1ݳSbrȓ@+Z|@Tʀ!{ 0=~D:FLhM4?g<ķҮEߓ(A⒠{HDxŻo̬8ѼrlYo"{B& +;\U('e# pdNMN&1fv\mЪ*$W)P aJ\U'.2ou夥1ATC6c[/XF P>6tr\|`NH/L){v.ԱO r.d͹&roV(G6ޡ\eHd^B`s6(aףGkFzv`ddNzCwQq"͘9bX%UY;k/ 2GBuK{d1/@.w_}E|$zW(H0s/އN=v>8&#R>,wr减C5Bs[+K_?t61R.-cpK 0R$6*ǫCr( %>d,8xk5AГ8B_Υ Qn(j/%B$2SWoj8KiR7:wRLsg1wmg-Y{_v*RwW\#<\#5*#A23~2c1YWeF Wk@f7P+gAnEd h ݔk}S~RԼIBrٻ5/=/qy<\ۛ:u)cNo_A_O  \n16Ø̐[OyT'ct, D x9h`as g4CfC33=S)HrtlfOkvJA̸p3>լBnͨxH TBmiAӛq#ڷFf6ICm__;/.y(^{){=}NjLD R}jeL"tu0} d&BA1+ \R/[pqu'&CK;k~rzn7ڍg~L?]9W烦y(%Z}N J@7 Ky~t`kNL3y.$N N\o/UPf1%!+V D@Yggqec7B' IMi cVr`6?ۆ/D:v+dIjȅƌS9?;g<_m8Ȋ ޢ{suaFķ.Φlilmf8ͣZ U4j:[ky9 #aI ¦C-Xȫ9W{:#sqj'ͣMgS酎Eɋ^]]/(^}w듡Q@:nԖ^&}¯ ڿA9_o'+B7D)(pHK<YL(#Bg Ä *L~Iz&UH[DMbhS/L.E Pb6Leg.JKFɠ |,YokE~!3Yu*\>\J}N丿K3(.TWB9 [Y+-ZZl_c؞$> }XA#".Emf3k]R+aetUWN*וl^YTn:W(᠕ZܬxJ"΋K]Ĺ'!xֽj^"EL ;fhTeǑe+C/T+toyoX?'džoflnɋSZ{Ԯl}7>2{4͉.?0u|F%KsE@5/iSUg?ԝoq9{76ŒjSC^8q:7ըw QM𞢇=<}FڵbaaA8lZǘ)X$DTIL8m zq{R ewrդ:b{7%==n8B +ŵ- 5"mm)oӬ5ޠf=%[Tn2w̍L =1ph [M,FM{e+a׍χN81z0rW)qf|9Ŏ&1JH{kHh"6[>ʫ"&* ohf>p@ax1 y<sςdr4 ~RH5y;> ?23!DzƳJO7>ilMhnˌ5kT3?'6ۛ_6qkZ l6ZF;K| ;v)glNAO=BXxp-)SO <笈|7{9^@q??$YYbfD縛!_ 6 n~ n1cp ~n ].:&D|AV5#nJ~G11|/&zqaSտ8꫼q};c?QQgja1 |s|KQ_x7G}qԷ ?8G}3G1c8꿀8d݌ڶ/Dac;m*ڶtmllk?AԶ~Lc2Y;.Z|@2Սd◩?# N`Q>r̵Ljk3"mnyo5ųg"\Zrxi2Z3BLhi[omʈxgyLy@ng8pWx8K>QB/xPcxt%I?Yt`UPHejtynw@/>?fsc{q&bx-(!ұeρ0f@S` E \<՛ gxB8PrBOлxQKGb#%U^J1E}> P&h7vD C1|/( a@Kt§v?g"!6э>B=3pp(׹Zt+]m:2~9 }@3f?ng Y5Aw]ސʵH)*p#`@gΟb`8Xvt^uH˗Gi&l(#(yw؍瓢QӥbT\w~! f90#B3`5WZDoz9F1l4`2#G" =I$StrWK>S{No@ Kij)rqy 54;^K)xvurT)p?43idvARYg`eܺdJY(2*3CT)7u_4ԇ^kK&~c!s . ǰ@0k6mFHch&yl 6^T4{BʒTcK2KRzB5e.Ll e: RZvaNmj|[LjGp \<ΒKi!oC1\]N }liϳA!Rkơ؅L(w\ץPNXf.cE;U!?&>*:`e EK+".{a('\(k:8Fj'gA1U ALi@(TNZA'6?I"^:}`4.XB,GX؈$U/lmA\_GTT#:bǐk! 6BqEq&*B x%#6bomfl-4~wiRM I j&yk1c[PMG5_,lBt"wMll[&~&6dl&>r-mb헙m"J J =W d66&y2C+::s_F~TkcS=R=+>2>ome|ƫ11'SG>߸Y [k[ͭⳲdlI6RV2<$^^tG2>! aqSI@7yDxiuá92Υht#JoFXjM`ɠ `9+s7Y{2~TBOAN^X:qL>){!1tC06b2m\__μp| @<sw)JoApTmno&:֬ :C b8rbJg v>JIKkoӍbfc CJ ztQ`K2aSDkrc0&  ]&5N"!axqcei?-.j_ CUd ;i)͝z)q#'Gj$ornhay4'Y͌ȁmTtեTҚm.%onL{# ?2͖XEURb (iX%-m'PS`pj[Vɨ,D0PACݗf^?Sd8:ƻ;0ީwt>fz6AZqɼvx嗥vm At<oO)$^qYd_)Fv!{Z4]S^A&~FVym,tmJ뭬9mCR,Iul( ,xUY 3e1 E1BŎ*ɑ (!J?­QOF-.@aaԱ< 0 q֙LS1fwT=6*y7r)'ͅ]Q92_alk@i?((Y5տ1*8)+]q2O4*z5:]mfUmPWBCU#DžHߝ5zHq4EպG 2/@yʹ.1X+ =}G% zu&7)2J<ʬ~^G0X\tO ^q){Z[.f٦;h#";| jtژ,)tDR#{8cr}m9][#<ؔ`Kso!yY5LK&;Պs/if<(I`ܝQV|UmV[|I=rY^9XRא%L[~諸e#lR[bQ,CPP=n[R$)ts?SLȸoR$0]ۦ<z0lysK)YH0˃ȍ%\.H6qաeG=#} (%x<Ǔ$G8g7y6//xI7 uՑeH%];ҝ+ƴvkLpi] |V%LTCu?U&2aa755P/M 2fc3ߨ=Yζ\wofh k1makpqb ZPՐEjW yd;nT_e7V(kU@qw(c0 ym'Nc L^̍):_2H3Q&nG4w(^jعZ. 5>s'aL1,z;B3.ʎ:<Ȏv2l1hDnd `u8As{NeSX2fI( ]X<ЙH t{[:Y*E;ES5yo/(~JdQ%iA؝Wn m<ZUyZE& )1MJW,(reWRoԃ3~NBoK<ބl|}'N44*q7ц6Il_eFwYKP}dnK+Qx}Wa=u?dgbɐw&LY{I⽷;ZF'L6e= sOy?vez\+{GY1hGDTilN@L9b,"#H::Eo"8:p&z/3i w]@Ph&4L#Þ`>\QϽ4o}iܟ+a60 = ͌~dB6KvLgѲwV(M=tha`y*8dމ-kIZ<%Mue6 վ9.eJ*|얔Zz/fOFoU!GdBXN*$vVO2eR~`N"f ġ''!,̏}TaeJoEx^­|%so.jMQؽNh `M6/&$ P,Zo͘sbLb_56c;(39GXE)nu)R|ƑR۝LOtO8WpeEJ:P.r5@FT2o_FڷUI|dc1>n}_g]~h4_Faڶ=xGK4._GTyHxawP^)'۔?*d Sy|eu@.Jjc2dnɨ r(3L$.p'2-.x, ?SG6GK0xgƸ(1ϻBxۂC]0#XI̡?Ef`cfq _IYD7}l^ fIYD5R 6WZY^\L~%J(@pKj}(ؔ&4v@@KLz,'<ѿʷ-%g+4NRhG;FA:p:rLdFAP} =.-8#Hu7)Ka'@mNߦiD7ih׸ Edp/>-:+C}BmRCF ja.T)㏘~ k /?hϰH43$ȇL뤎$6>^MfKr9V %C_lÅ{Jic5R\|i~Yrq BR@`!k^֩0~$~M!tPR<;ZTkU 9.Rҧ(4 ݺc=2W] OFY(9RCW\+Es刑efbg\frHښiECSsw"E:<˜<񫋝԰~&)im \s(  :(֭l`pkמVw2 ->!RVjpV7`A9hԥ9r16<}=啴8V b^f<fGF4y8V"4I1I6g7XWք.EY aY6 #?)NSZ̢3* Ą~Sk\]6Bn=ῦgAmM 82gV` *5J4YfLX$=R+$-FV8p/?k4S 〞.={&)ΝHNڇb\hgGܨ >2rv `:#EMYa)IJ1h2eߟ3h#(3K'H&䂛4iCP}ܙ'ˋY|^_j^>eUIdP)5ڦ8ٯђX Gc)=s0jh { ,-mO*' 3Y2R&xYi]. R+k Of!%k?^꟪]nE*wMswiahQjl@L87#L4iiF`I޶tp00o wiVb׺%|CByɏ.S'}lroyeOd Hj8T?t@56S&(I3jvfYXp9ɠB}ֹtiJ]x$˰ ojgw.s8DjUx*ӞI&t]AdÞI _$He|ҘjY ._Fu+)ͤ5f߆44gD#?`g\X%*dikެؤOgdvS6f|Tq wdX#foW0oH@v@V76ȥ+Kδ&2$Q |&AqįLB,vfѱErƣ;-u˽mG y، sz6-@S G2eô-+6-M x>v4ZR 8Kb7M8BiV o,և{tBՍr⎋5UC|ugd8(s2.( ۾4f2SlɀE@ mn*Y^7te!TaX..5_B (:yXD6&/u.$ (^(rqqϘ#bs'϶P~w,vcJ19L&um0`S@yX NHQwXtKz&3ᶍ?C~I]:M>l,Ohpj$+3Cd &U+]Db+f:vdtσm|Q7hy+88۩4{c%e/GnD䲶}sn-t2"5ǪQ@ˆ^]aiB=iL+a3E7N¶?b6k'tnL;kUQ>v:[B4QFמ~k%[L(Lp]QX׊)aMa'O{6dw΁ה67Z/!":exO;>dUӶ@V%s/xl֑4Ų#-eʷ*c=0ʼn:EyLnldMBeIvcU͊ࡺsm%v= x|-4Sr|~:>ibM|Ԫ|ۢ1|w}:*3ZWAʹ4[7&!D%9~f)l})ctʑF^|*|]xC7PK"Xd-gQ -F0NکK]ܺdl@a+bd牠tugl};aOÁoD 6sn= &͹P~HI&wj A6p1UD:\3%T3R^~_AI So"Z8=H #meP4QsBJ**Bd,3@P"nC xE2G4=os'&0)ƚ]D =Ew] SKε2mryQ9uS~_0M1:T^j8YBj _ Ǧ=_}׏'@T>NG'1p$P9/ZECH`jD݋qj<]KAwX> @uq\gdr\Y~w44;A.=$'ZfԐPeJeZJr cRsP%r%F^-Qh۪ ||vQb,mQ|JM37vv<_ă46#3!rBnSz4[P2aR35v:p2Y q$x2k?Q8,wuuv!& ~&?ױFM7[GIx`0ʷF%XX.Z0Q=Hn4C9M}AJN6߈٢L)0ϘtvD]*O}&|$ތ7˴2Io˙C[0 9QXƒ@g^REE( 8 A3̪xY=q3׀}a7_+(VTU c" %(6bV}(7v"z  fQ͌όws`CH*UH5Fj{гF1R7[FT!sNmRn"Rk?CWvDs_ IRKkg.j"f,<[Q3ϒ1+AK JB A_5eh-+Ƭy-4b i<hE>5 q6?%{Ұu0CQ{42\/{W"Tȸ%1 C}FaX;Hinꙺ~,gb:ea):BDI…MnƱasEŒsXItL=둷Vjk MYpO7|[ՙT}W*+CuQ F#2b9%0g=cgq 1b&ŗY[pYZ5v*lWjŽÊQͺ*{=v'/V~y֋U)I,oCIȦiOʞX t}V3CGT0`1A[xH0f\>՜l [DU$P R=(bz+ˀ0^N}i$2nK(9D:3^%jmFPBA3>=ik'-5xo58v3*3Y\vҴ0h`Ns=X FX|>]"rbNV4o**uz*c?ջU1~3Tc)6r^A#F~DA>DR#I9Ji9cS#, #RE׿H$T$0]nKsR~ ]s.(LX lV+Vɀ>DIrԪxw#Y-J3 *M*K޷Z=$hy`P&T? i)C3ب4/ǯa% 'lMT0(ͫj.~1ӷ2a&vD4|%b!_Gj1ul~j|ftΘ={X=# Ck6_; K[,&U2O6;w7?LgFm cx#vaY) [lyjCFPp3QTؠ?~'gg f@+8+jso#o wksͯoVEUXo|asks3?SQ]Y(vv6=EJ>+KŸX9wO\{Ӿ#&C1ܞ#z7,x/Áa\8vlTI] I^n$]ʈP:(  LDuej>.\{r>\eM+ΎNE3.t<8`+1=!@pJ>3`/=TQAD8gizvtpO )*؋a0*?h{e:w/O㭜ɻ Ufi/ [XaRkh!uX-UjJJ}':C#.#@sS9JIKko@o4֛Àz2r/G}@C7ǝK *KSܫV[oL~UCK~!hUK'ņ8>iæ`0ch/Τ=J2鼃GBF`hSL ?zBm[Mɯ|[%,gNt$Dzׁ6 ѳR},g1V~`S| {`d݉x:]GZx( -FҘu0XT·t 2t(vo!_HoO2ѳL˥; & tv'}qDsU~vܥPGYe4p&x?a `|c?S{Wcwٹ3L[kzqqmP+ӬۃaA_mx"5] ~֝XpgУ{z\hGv󄽕[6.W`0AqYBV)rlQƿ]a*raw=#+57K])KO- 6%.cl#yD\`;@/8m'Y`A~ꘁ/h+,0 ,E{x9f?ߔ"tƃI;+赫:;3ە+N'@62(z𢑍 X: > [ƋS G#8=t7>W^{Yft蕈vdՒiں4el'rc "+) "΍^~c?17TeTT)4/^$ s`fachlç8xIZAҤm֒~;ODݿdhu If2ܙo W!\Fܱ==C,+nw>;o&x)mT*'niz5QZrS*кA/MD,QF.X,@Da.0JffӖs_ntI첂/;kyZ YQ|%L;2j´d(t)/"TLiVNjJ*P^_l K TwQեU>1X{z__iaXKY=QzLjL*nfodFoF$_\./\]1q YzYfE.Hp+IwJkKyo)ly xtbUlީϫAh0͈4Y΅$¹HE |{VW5.U'.ڡCME[2ybhGu4~jT+D; K@0tt# nCgxa2+t[git Gc4~mwd]ΈΓS,)##k$DuaEAb}IǮacW\ⴌ~3PR3wQzά6g.)LCiWy[ >-GE!8$7d4C^Tc;W,gz .D]3;P,XB$KpO{7fa. %bI 6 EhmA B Z,fps]挿Xsآ?xᏞ2^ufIVDh,I,e0D%jpRơw:]8o<:f)i͎%1!Vqr'* CwŠ'w7rI lԴt 5 =G Ib;: 7s$%&  ؏Q,TtE[C3:dF##b-ҌQ7gX0RrgmqS觕% afBj9tS x&Ou+a"76|/̛^"L H.w/-9B'+#4Z0Zi9n[C@"+!v|#(*I:cb5vZó%)9Zt0@dZR(%!gۣ$#\% |p'1nC Br ]c'Ix`ŕ(]aZd%{2u>xɔPu}2vPzNyiYzTM҂eiYzHx5X0܎%-b/Q?-:]g֔՜3SZh6\ ,Ð3~?ZPb=_)Hx#cC;H#2*=PvW;7Ȥ3@+2bأy;,oɟ'`~9I*NՑaffßLyllMRB:Dp҃h0% ՒMj|1J9QO"ڀѽ$ @P3/!<wjS < ҷ~oR"Sz$CL=H5h=8WYAhGh =݅_8:(-'O&Dy,ע9lO\aډj"(Yzj42WQejyrs o22P A~i%XA)X)gV (\A R+rMY̸҄fb/;@uo"B]W]&UVL2R෌kFb9˨,B$,ʣKHeZB/"/`oÓ Ba҄ЌR2+" |!f0NJl#ghf>7s fEa=@%zJ25#Gd0{>SdK^UJEMx&vq%D{#q~K'ם[F8Q P g=i;bf6uN)!w_,XR6/Exsmq72+{}z]=Q@pDQ M4Hz[䊯dmΩHS?DDZk5d4Enw `fqk:CЩKx_[_wI&I&;\['cZahkVI_Z6)>R=>yn'f(ăKQOX^ˠmj<"C5I1ĝ:h c/i׸cX8:G]xȓdL@ZiqoG j4n6=U 2q#93F<_$lkO -&0Mt[DA_'AHhQ"OP<"TǬXJLf20+J: Qf؏s;#X8 ~fю0ύBmQ#2)R>8(`QF^Pݺk7zlꡍ/yQFcH9Gw؉_t }CǮϞ̨)_3j`ak `iCAP{怞s5S|0>oj?&|LM)Tϳim4^UvZi_T{ q:ht%}p`$sK>U뭶!k"?#aE@ګa (>4*F-+WmzP+ZشaxƩ۞#zQY'#-J(cף^0XCp&<, |l2bЕVDS%D%9<?h*,C{Ӣ ^?kSu*lڵ{ڪ] Ԧ]{sݮ.P'r/옯{kM|뜧z)vЬWk{1^*6DWvNJ-X:VoY^;+*UkBJlw-ï}k _xjh%E Q^F%K}-H}[ HL뇫\4ߵpng `B"&X$yFH (lC#/P+%,~iԡW76twbEaߞH⃡0mD|TM%%!C:R±ycت7!vq5rKƹzC]ß Navgx k} |>yGFJ<:_I/SJe _p5 ./'Xfay]8SawsNvOVIHnRO^P_bow~['ZU<<|6f_[}?ŧ5{.apy$c;..9^VV:w|6V@SC;snHR,6pVL2`[v-SSo3ȁ{9'n6i{[˭Ɯ_X o>OBDN;$֨G,d476K%<EG0 JUw CP^5Sb9dך3QٱB"=Da&K1b!qZʈxPrT#ILL8݋xZoEw$F28'C[8]A5;Q.JJ+R @oɣJMRo]t.g˞X)q!#MQ5,O&%%`ISCfKiFsŊ3R+%A[Id7^.@׀] X qwm[!Oyd"q~6W G)>_}^+-+dZ-pÕr,ErJ-)W'c, q6Wn6כR_'&uj(Fþ۽AxD^vSAaj%,gU3+~ݎ!DBἛd`zfARQojŠ_3g>W{ۘgo~=?;+I:QIV9]Z^6O7{1'VP\_{~OYG-*'C"9\`얣 $+?6R.T5t MG|%Gt.#=C.=w[[xJPǤx:gB aH!fbAXgt a7sIG]1Japq9Q]/qVi cZW!f3]ɂ,H oRdne6-chWϓk M ^SORK\)$իeު]z"?E+ac(1{.yIt9F7 W& MɋPͿZOp@0Xde35>-NL6K?; lDHITL?~D]$8o'$rW8unдNHzCIh:-M Av) (օ u?? 9žn 6}A> 9Zno8\=7Kk[eDw¦ ~*@.ָ4"A]\PdT谦;v0/-gxYjP*nk/q8 [W "9&~DMg^;|Q &Lm" JCa<^=X}@e#]}÷ɂ;8Nm"ԤbƏ$v;nJًSQk˧.GA+xfR3S;"Y`)WA+X Ve뺮UOaގp lCqYn2G cS(i*헅Mkhvtl!0@aAw˛Fxj< i{*YaFassikX+u]XI9i(ۿ{˟;r@ ta+Jnt[ŖcAWRۺ2_AP zVZ.u'$]_ . WJIz]UoRU$0>GsHb< :$] XyVSOI-I*nČ`*!e#LDyZO*ӥX]"AzI+Y‰8AjP}RPE4pPR%(-!*CxQU-|=%#n"ܐBf g318tlvA5qMdz6fNW)voՕ&`<>} Ws[C#A;9Hk ,Ö_0& -Hj;`H/̠%% @V[J$5P1 ><@=MnF) MUa>| "o)͞QcNӺ YAD=[=L@eF0C iF 7 |BxYV ´Ƥu!+xSl8!pM)T1.M=3#-6ű:}b'IA@0buI]Sls$¢*.J~R?'Z1;H5XpV"@#.Bt ^FGqɶ3&}-A=ӧ#rRX~JANXlk|l0aoz9B^NH]cYڪ&va%Mˢ&lA |˸^PD=ZxNNE?`fmhm"B2ir]-lnG!GF׶B&moLnAͯ 빵/lo׶W mxy *)ȕY!^Կ~ըĂi:$bD!\A:maqEeHݙ<&J%(+%5E9lD.8ߡo.)-h8RT'2 -AO]0z5\BЍئʗD=c/~JVHFQy~912Kt'JGȸF,큔A_Q$VoUx],"OgCϰ RkU AՆTQ tRmb*xA|tNWJq@H剴&TWMՏQ"1|PG U4NqxE4:trgQDb9E1Tdv=Ư;I*ӡFmuӓvRVMd<&s" ]B yHFW \X~4)F-FWKrcJQz̴< 2HN5<z> +~!M(7޼# ENdK\tF]x.GpDб2[aS+j2l4ۙT[GӥJRG%Z>j#}kؼjGZ!x@u^Y5QW%_#Һ2s{c YQ?}+`ReKFaDYlhBdcUv@{fʍO ۽>BWn]85(ĖP Ugqm xB3Lvj)9Q:CG@Zr?$# [r5Lqc̫=mJe@|wz%;tL3ܣ<$MzP5Mh^hiMzK} ʜ;2)a);o~kk[kGOT`DD %푂N8΢CA|4;]mf(& dub5;M(MpsP#$aWOI~ ST~C,@a!B1*' 9P^PȋTg!{R;BO:CO@sMӀvN ,ĮH-ORfy ? @;*y EU<'T͡_w=0Nl` FǫվO8!qCۤ\e;:lP(_..A#R5S_*G!ʦpP=dr8O`f8өQ vۘ#єQXDo}mM~AaMުWtSFZ/+Yo^զ8n_U˕H;Em GM| UjIzY9(6ʢULJY+W=:>t~}?hЪ_Z]T^Uj-|Ip0GEV{ވqT-fJFjM~szYDxT<pebY0a ߨz:|Ҭ@#V+ʠ,ԬP^n//f["V98Tj u*ߪ7ISVɊbbV~@Za"i $2ְ _V{`+QȭeRȯ7Dau;.zʻ2ݞ;&_ d8j_M&'{0Mx.C z]X(炷s14}O 騇GꞐB7fn&[APߢ#ЋQJqrX?5z<'sn.ƣ)>AI$8ۮW(D/nS|ÃO`IRkkk)>Gg1|V7O_A _O;nw8La;ݥ[|0G!|VbI%/ =aL:\@pd`=@NC:Hy@=3L,AAaA!χ?m?ί/ܳA9'j^$oq&!DbV&ٻEx0]|m<_ڿvF.>5^we09|3vib=O~!m׊Gav]L&kf:ibh1EHofA+1 &0KLwՆPCśػ'1g#+N^+eDI62P>%,uy^u.蕪I&3hh=5 x?k o#VSe- ̯ zFWoVb M$.NFo{*w]OFәcsq9hfC}1cg0pbe{Hh@w5\?48┒9_bרC~±_w/:6Lv?x<2ŽW v>-EX#d?㪄61bK011Tag4aՁ;9:MTN+V6@EƮ5]BTd0)ˮ7wnj3zjCʣ iIRƒ逯ҽt֬j 13gFǍL|YO릠@sYdre{oZ̓ _.3"(o 8lMcnf*ȅ ڛW%Xz& ^Al5N i`Q<]Z&%d㝏" +Axx.Η J0S\D1.gͦ5vh+%Yl-6HA$H m4j}W[F amZzK|r/?.Brf7;$[Q{906WD@Ğ.d$#SK &v串g8>"(h".S"o`Uxɫ_בs9ߤ{U Ǘ k7rBhPz= (}K 牉1U$qk< )? jCq4e ٳ/S0|eςx ֔3:2G ){Z Hט>٩`~Rm@< ijCYƳ֑to<pH PҠDJlSxLdLBR$Z5ijtǎ:YDi",jnΕ͠"!-3>۪ƪѮ0UCV.9 ̷& JtgO?$BGBU'D_G\;ބ팿Vk͓jZYzV?ѧ23iag̙+8cf=0)I\1ITD&AƁ*7XW( Õu(5 bV3m 5*+QEh4s X;BksÌoKY2m)rg_֔l%H<[iobbYpWg<Ͷ?*jOJ|5?YFњ|M1< J_TcK~zpDGyKDwL ptt д:‡.ۜ-Lj^B͝G6:<#3jƖA|)5IN 1&|`!^2DA+%Ξb uF߇r"H W,qjwИ'~6t# ~C6kArdZx8V1zX[-A&ȑD3mwҜnD5wS|G8D QuxsS*67M2b>Lg! Mv9UB)DУ#Ü:X6cý%^NR=Glm?ǗPD&[#XŃ ڡb"E5@7vMU9fdʜ 38atUf@;+V~~K")I~ =;d$Y-gHoswkc?>}G 7HJ@:EYe[`5\5 _X댰{LN# ˥\yWb|vzq,q_n 0ڠ]mrQ%(eʯaN:~RQs=޳:*nXIw-%tvCބt0ٶ wDt4@aJ .i0k*iZ=u=V,/;B:r70y.qS 9cW?|]M&@-Տ.jrxG]twl!яG6,8xx]ӪۄK{Efq"'D==sx}؅ pȠσ/iR>F'A4`8'+/,mbJOF~0]7G,;(4hSNkû`M7)  $o2fsS^qAQҷe9!40 /nސz:p( Yj6(*&좱+azaKgvWfh{nw]1'\Xu5BdFs*(l[yuk:>ϪV]7b],+N?7z*ofD1)/ Xk̕K*Uq{ l;I] 10/F5lAu\QiY@W&VlMzEWx#K|@wTdnT%).g[7pw0mP-" xy.^ ݮɕәNxNJ9<@<`ۂb2sAT },heg30.vXR)9y%P|Q:>s UCu{F;w[u_ԗiL ŐP{E NtY/&*עۏ\zi=,Е`8vڼvr$VC<)+G-zM|+Vb DUkL Mf[;~YtU 3WE*O_$F=t1ߓS~z݅o1:+Eul P czvrt5h~zwBM+}؃/JOWT5Kk^w^\zzo*P7=emFwk7U]Y7Ig䮭ҏYF,bTmH^͍@ ( (ܙA==Es*D2@+s '%3k{Qu/\*ؒ-jDz,DUV{jlVi=c`mME6h 04xoI vEYϰG.] /0 d;tw팻; wȎ;v&l(lOn@cPfy0;wqo B4ёi7O |o,W#웮zWs&مͥ P;/Ns.9]ޛ Imw?sC'~;p(;Vy&A>v;xrg*윺sntk;EaĝP][;ک`ϭ?_ߥ9z!|fX_٨#~uQ-K}!ʕJnSt\,U:|N,a?RmK"NZEZ@}~|?$?|`X8O;S~n? ,?eVk0Ko?ՅZkl/8TISV#߰ D\ǥ'տR0F9dRGt.:χs6B@,uju9lɓCnpޔ l\谩+!'͌YF.2J Zbbj=[Ydx)( TN`b=(aF$3σmf)tspm9P0"_&{.e C#'ѝĈRēpHw'H~ւU[2]ŕYB\Dgms+/DXI*rͅBpSqqzdl3X#K}(ŋ~1y~%}ǺͻHǺUILJ(+p꛵aޫoYSӪ4jC`My5,Ql59eA;eg~?[Ӈy;c<>CXπDWaI #\\5{X e -5[N4+3w{tSOYE{5ĸ:2SXhwzY Wf`(;7vOX#3$هDKwA0nm|JWiγR̴ҷ25[Sl˞1b-+kB/nfj?ٺ~k;~ 04CY<.[u~pd,I:9HL! 3ҧ#0ŧtRS+luOwg d_5Ǎf 'Sl W;P;ףB r4]i/9Q3g KȝU9tk0/6`=r=g8ݹ`|g a<4W_[J_z8w?$ Z r R9aPͻ˾ ̶?!^}z_~#zp>q.<#}:s/r] O2[CP+ Ơ~;s?ژ}gus-ecsϧ^^+={f8Bjz;vG\re%bxl^,ko7G{yT/-%U«z(o-* 28cIntU|KeFZtΠ|ەIF!4yX@je'qCw,ۣι.nf%J"!4Wo*B"=dΑEAS2*\-ӒOLR^X! Bnaժ445 xBv7 @xFMdaʆS\ڋ(),aӘՖ) J %r$7tz hȒ]'?f(@F &^QD#G@B.jw8"sejbL1LDn1<{o:5;(MLYQ<%ȋ~DzMD|3=8g|)1aZ.j~ ʷ"W ZlVDnVZZK?!~*5Xu}\?>9毯*~1E7#XGʷ<|. F)^"gJR/gE)3vRYF=,=- jq٭jb3[XVteԨVYۨ @w\l6_eQX5;^ _m! ˕˽V6Db+^Lfj' ש|[mQF Q?“pD}пz:m5d2{J雽LF^U?od6]RF&󚎸)#knԋM}8#yO88(a ֓kb2r$Q b-6;D# B敗=fXX-`k< f,S3רnZeW94WVXNw2lA%Xhp=*4'8&Ux<<vꬮ!6mrR 怐Un=̈́hymPyY#f " 5UC#[iTT5n<12D5bfd5n<>༺MЬG+%0)-fڃ'k4g y>|v*͓7ZtKJ'od7WaAy=qAjUo\eq^B|Z_q^p q@/Ţ %FQhKD(du+&E[>tMX!Ð,BeU W(C&X]7[2V#[zkg#|5{LYok^>h_V/[R Mb&KF[F`SՍQWP^<ǡOeP@aߡ %q]4_ANxh`335?/y")L_~OR\c@f_OJs,LG7 xREP.W)tC!T~bR ~;E<s܈PQ0_?ͧV1*T]:"5+g*>ñ =:';}wr[_]sȂܳN_ԌU9u(Fea0fP;cro+@MGYeameb+UgRTT\6*âVP.aL?ϵ\P˳.6O*{pOL4.mi9솼nvw9(K  ~j6ۘ_o䷂37*LåtkI>&T 2?V| 1c*ۧuRf(i[;1f$"I#>X]@aC|0>QA*Acu.cKGSJj|l\֣~fUs%k:hgc,OD'磶9*Iq*~&/f[VL_^*';)`œz~SEs-Vyc" d vE͗=xCk"݉hsurJKO&*#ωr$])FN0 lo)p/;dcƏsN uCyB,O_J`f@E~| Τ#w`z)gH x7 bпI}XcTbJ1 gQK8 3s&h ΤWpWǴ{t߾r7 /t燆cD?P N$``Nx\K}婬a>T͊V"xPNW! IWW4]QX+V^1N"y.bGs$F;E\S*Z,æ/ʋ`C螝?w7 Bq:7k"9J᪄/IXηDHc[L,9#Kx޾1ޏ$XGjP5Nwd'dr|Hz󰇥++dD[$a߶K%1:.vvi%LlLT嬪Aw[/@ne{sڕGҮ g"7C;4̍qlrr5t{]"[18w%[Pq|XBGT.n9&X%"eUW\t9+ʋtXZ3U[z?f0XGLi#0XJLi#R0XMTt0nfH!tG:FEud t'za%0츩@7H\q !zCy NE~xdN`X$k9 %ލeeQNqMGX:Mpymh؛\YR썍!8>Xs1}yd:*^Vkxy(YXLPPi4 u/U#ĥs96%ub2%?O+V]>P#&p;}xU`{' 56#";8~?ɠ!vH%z_.^7#~W`{q 5=r3ɫviP^475XCE<2LsX4H*%vwb爛#zͣv[lU.[j`#l BAm|!6norH\V=z& "VU]NP\&P^6iP*=U.;d{ AΪRK0<.p3 nDӱ"}F΍&9+H-rɗ 6;)Lg`47JӲVV&K@ɘC:4=BD++6QmY(v#J|q)\ȪMЪʴʠ'%<;9BW'h|٘EcL#|o.m]mjҬ%T5{0x93'b|X͒: X=XN=XXEޯvd>Aq +Y\X1$a`A99%ȸsvzi aǛ]$,Z|0?FpqJ^)<ڔ=mx2Ҫ xz2]@ ds gԝq5a}DJȌ/CshYjHޡ wsXRb̼]1e[Qޑ=I:Q5jߌ'Y!|v f&EcQeM L\?_zWwޥxdSs_m|l319?ɨ <UaIۡ3_,ȷ@ɠzhU%^6ƒ(AQ4^5!X..X*ԕCϐ[QGTl^BF1fvNtݢj!bUwyMSySepаc$rD}n ',CCCKXۧ| 4oܩy3aGm(㌼, duQhIWBpJqد|&)1I_ :(z>xEVPeӸ s6N܄p¿d82K6ߎ} "FUCF##ri۲!f, h(Z@Kɴ+&DmSdҹzl+z9gw/+ge5\?_Y][*llml:B (ă$bN]z.W\BЌ bt%~ _(2s%6̤Sᅬm;= P2袺"02"ltjOakjiFfAڎHOYfkBÃ!KfcFY/㋙K?Ib|\vJm%uHkBi(Jx+~"44ⓩ=l9}u J/cS=7E'̜ |;~[b'nqlLYtGcFQy.( `KSyF"6mpwGfLVʛV=!I6@xPސwQyJ{Q+ w'/*QEı6>gj@W HN#񆤅K \KQbٷ~AA.cP?d\$`WDoXŐ#*h9d8YoPpc*CUg$fQHĞu[6d2| JTsr1^~D38 Gj}KLOWGj h7pa$>7'NZāxC0K"{=9&{c} ȫ3% 2,,D ~ۮ,Pܼvme.*bDP7M ܒJ踎5[/Aq%c u}T,j*\E=(t"ئyvT? e ),)Obfl9]k+ l AW%,VAXe`CT%iլ/ëWGb9غ+ ^pJ1ѶVN{Rb`8vTvB́b o?cw=tA3tDK2uA#|!)3ߙ6=|ڡ/k8q is8V|3v6pEdI(9VkC"d "߿(tUC8T ~?(mG{9Hq Qgk6t;[є+=f1g 2b@f7lQ습#GaMc@ؑ` t"X5rKtB-PӒ8ۧ<[Ϣ.J-\gxX-K LI{^҃Qu/ʹnI 1$U rܸ݅k 5ogcY?Ch@l՜w,I[XKEn#)xQ&$/ L`/rYgbf6Jb015unyAΆrfr0V$ܺ'J*]HJKZoX9D'K+daX'MYDR g' 9bq\QXc~(}\Vk^V(ZR-'K}!{^ ~})+~W>(S .ʔ?<3')9ƾFآ D=Jg&Ґj}'4ՎPRٝdM~5B-`#W`|w&YbO֡kdm1Vw:rC[(4` Wf w~XPdMVQ>KqevR9֓ %jDtq <6:5rV TyA0t _ (%'3FcN=Ѓb&q~zFO?瞢dHgLPnSIb؊?_+DD.<}R F8~ui!!+:=D8X"Q3Tp추 1tmG9$#m]jr, 1\Z,BL $_y2j7XиCZ-eꨞ4}4sR {CO%ajLYL5xZhW NmNg›FӯH)bWdmh8RG Kj8ɶVh72&r޺%64bJ`,-8 Qĕ=8l2oE^bTOGb% LaSHЩ3hvV[< |xh2Su2~k/Ero"F͡DG繘.%b(ae#Hz\m/A Y&wMO1 9#Xddj6&2x$wTe}9n:hUPo:“b4ታ~#ns'QgFARh9 \z^Q @vfEceb *+0LbaaՏ$.&>5y<]};#MeZzj\ց₀[%&ˌ" X+3@.'9]Q= y}tMX6ۧ$9j"ܿO|=hJQe&~#RImb/;XʏDq#G^>s>n0SsIǔcƢ1 rXqsD&CVȥ8`sP<J %.CeS +dvpDhDDY F~ t jU)OCڔe[vwhWݻg q'%]anƇq{T[AApds&g:/o*#: a*umN-z33v0Ɏ3w?<!m~00{XqGT@ ,?e=itS0B$VYtNd]7;s/+ "6TQiGűGijNw߬m6[qVҸP{-cu43l]ZAtЯcבT:7HG<{D9 1QԫyxN@;%=|4rEɶ;-[PQ `vMU9  M$owr)6Do*AڵI͓=zPO[2ps'gGՔԫuEҪ|JFǝ#}tR5QUNa_.!Fg!u&W^{Cyڟ{75|l1Ǵ?W! ܹrTJGE\'%Wg[2cCKD5 qbAVA9~jg-ӓzY9&vZFh M4D#Q6>x-ػ53MW4 ^49o8Dr'g=_C1!euqQļ4;ƍl} uƁ'JFO5l}AOonqfQ_󵒍Û>Oe>5Stg~1;뎝)J]e\ F>:`<yUmNv2t\0 7'T))])_)l۲dj!Go"RЛ@^~#"Uӳ~5+5#!>N㚻7.?9BM0✳5pH\"a678U"cNcSX:{~8ן9udTʁq`^{TAgvJO㱶:de#YUЏ0i33~G1>bar6-v@ʞYE ihN4TЗ愞;)G Nt޵/sffGBb e^ WV)o,۱z8V8a0ߨ,eڤ <(W@lT?` &S3h溣ژc\Z Gϧ,hyV+bum{}ks?}>F}爔7H<: Uc]hs^'Zu)t,i:xߡ/bCʷuZC~0ߺr&I]-bV]4[-^i\ ʵ,IXj2tVoU0];=ԁ.O| ymM"Ʉp쏆kQ|C6TLFa~pQCSЋ!1U5K˪yXzbSZp.Qu8Ơ|Bq 7+)X!~CWA}TjW3;{Bb̼ kCz3sLAوaP0_;tAEe9 x`G{a<]7é óawJ:Fo<'UoKcۢ^m7oNn1_!vA[@QBRX ߆E6t P[%z\ +:$^9N@c^oSt7 g*J$0x /_-~gP_]$G窲<`QXk_7+L9zzD*Uב1K H_x]][GfC}Tž#4zY@Sa9Vʣs0|Υ֧foouа"N'CbI6ϡ 2ٙ9W;=eL76b- ?lw߸S$s| @ߧ qVp;r!ʀ\9}4.dsW6tڕZdD@>cb(UDSJr4ؾ#JZ%eɈrBY%1yzd1[%Q0Q%7FȸPȒx,,YRFUJ>,)w 1ztQJ (1K7="#}:=aX;9)F@PET_#Ij5oYG Щ 4UPď6RQX]VՍQfnbߚE(+=[fĶ`_F`Bivm5( wb-nm=[f,6c*۵硢fbPQ,WňŁpјEU4 q4W#9;'vXiӃ HkݞXFv hpZP% nV|Ѩ`hevL<^K|{i3*ݛt'}(OƂY;VލЁXWaeTϧwtTk7O덖Xr@ME?TuS7t ɽr=>(={[;h2 bU; a g^é:\CQO?>sWk ~U sQ+=$X)rw.!/]wyԍgv|P2 CWk\݋.+MF>PIs_ڛQG1~\>C ~<9Qg6P4#3yG"Q#e[u2JO-t^9YLPRvҲdL$ŀulOj*re`1sk&NW^Π+Tfz~^M/A )c rDCe,mUІw ,8籞H=XÃ5PgV ?g~r긩z9VV$?E( !ÚzPSP"a/~rM)?9X$DkrC@] V_E s.Q8Q?g:HS2;R,mU涀xsbsQr#A|\Bgp3AE=t;}}gdb[cP1nm!s8sT?G'_zOŹ"u~}|&Ϟ?}?]Rw_ ?oo/> _ ~t}5~u_g~gzDa? ϼ߇o?^Ͽ`~џǟ.} //>[n'gTݯ}w=v?B_/#Ο߿0oߍߟE,<5_?SO߿b~oП>G?>S_f#7}Αg>gq?ޛ_Iӯ ~g_'AtO2/? O|ko|@/r~3M ??>?#N+Ɵ !!ϭqwm̻ÎFĀ\* 3uyooÉpzDܱUW5⮩&po @;/ƍjMB0?B|y~LE d'Q.{v^k m̵ւ kS|rߧA_"7,d7{@(n7zoNw#܍0t7{D3wC *e%d}z;;BL8o3@< oŷmWLD_1/L³\!Ϧ E[`ؒזT{ftYXv9 U~b'_^s2{"3rO U`c>{I0{Lb pAuQs)7x gn5.p݋t3^k,I5ml>YR)K% {lqY!ElHktverLˡDsWlqS(VF%|SejnO+Gh{ ÛtCp ޿^|o9׃ -ɈO2VO-a7 mY1D!&/7f0H(l0U$D&S_Tsa|aY&AeWb"Ra8!+a(Rz4U^{^B!mDuhAoq8.⯀|2AaӄuM{o idBqYp CZ>eF?iuu3enY6ijM myQ~gi-^]j 򥢔_$ K.*I*ɥI*eH*ԻeI*J*ɥI*J*ɥJ*eJ* J2 "I,X2t&˔@tJ,ot=2vfJS+Нl/7^iiJiuQ[ۨ=aBҨ"[..H^LZmsЩhiMP 5p$+"640ajSU|j,(AH\03\~QC2ez25,E PR9!H4.NS&:H4WCM"KnSw XVnIH֛jH+nNI&tďQ؇ް5Q>NHDa>:Dc&q"Q";;2[R8O̩e\(q}fB@] +iMeSn.Haj`z/azo;mU5%b?Z/N{6&!9#W"V[f`ˑX-cGRFy7=0nx'ItQ&kw4V U\_7k»\@rLTocQ?9-Paަz߂Xﱛ5HEw*y"SW{=ɬUX J$#)pMU7i.u1d!"VrDܭUH᪇X„aO * )ðȉÚHXz{LlE# PIMطq[tdXPN ~F%ȣ>hF3[r51b+F@D2s 7G@EISq)Ł䈹괂1h\4J\)X/. Eid']h%z}Br`6Nj}mL\[̭#9pd6e##42ae_3F@RSLJ*S/h@eqVn#"N Pnì> n:.&Y|;9\=yB kD?>&6Hci xC]Mxa?bn_4ˤ FS"J[QǀWK iQ\C?+0>i@zzMt.i2/i}сX&!Z֎Y" q\eOHhJ6esDѶmm]rL=ph0. }ϰ. [B" 'p#LH\ם -tW2C_><3-пk|;lvÀ30Sa=PIEEokQadF*)5x͕ Z)g(My0Q̱楕y)3ɬq8oCmG٪zN!*V`Qu&S` vut|Z=;?=:Y+±ū2 +QvFUx8^/T/W}vM6zݑvL`a1擿)QK,[% Ponhj{`&hGޫ< a>[ ՛:i1 t)܂%,XepqSjt'υ`rNfXWyď5\a'Xn^ X'7΃(!tk@d[=ܓ1:&aЃkyK [gOnmPh&Hno;h#x P+L`x)(_p22~+nR&2ǙB1\N?g88LYRqC> Hg[%$" \öڱ p85/'9Nj9;LF nrxwt-8dhܢK>2^#9k~RNP =bxK,ӫ$@^x潌2ryo$[z#yc< ;O8 ڐG6,O\#w&_4/9|.oCٝwD&bjSqD9Edzq܁A2gOF;C?po<`Tuv=cl},>n߰=.xcm8G)=@fqx^ Z1î OBq&ݠ yz`Vg& O=z 98O8Q.Oyϐq#nD@<$IRu'#W4hZ 18F~2wT!iHG= ZAj=(Z'c(tP j3@,Rt)zosé/H'2V':隸݌:6X8.~SȣF~'TsX⟔a.I|G+9{Ueuyڟe)V-ITiVY]guJ :(@F4G3Zg:+K'>{c+[mKt o)սr˹e Q^PA| /9|b/iOҥ +x|}@;ս#lFRQ]cTkǿ'Ŷ'gWXv úUB1 FW::}>S3iZǎ}F ,/7 Qa"=^ xz2xX)/NA6 a`VhrR;qR3,] __g[$6o zfM$7 dМK=v"2YT#1L'h25tTX'ěܾ0aוgCQ6 G} ?~>p/^DpJrxs1;ǟώw2'pNo;;}+^{o3gFlDzD*p"C ߮U`j8u1jfS%Ho."%p΁|/!c!BQ( toPsc[ u˝YM:uTbdAQ`W n1, op枎`0p&lk1Z_EZBYz9=k`ۀ.W@fc砣uӹbxĖdB8uz'TAs5 OA,O@Bob Qi64ݎ˟SWm³E M7 v#?.xP"F0m!j xpCNkҭ-aPJrFἺC'˅.?Sa- =v㇬,wK%/&)!qo#9t;D!h @EVBS($qoL,Y4$@/Y!bѐJB%\Q//c :yaaaM d؞CGIçs2 7:N_[Z K?K 4& DCYF A=YY6~ bi"2<],Eb.>>r o)vKPM ۝Px) 5 hfLUH߬6;:%rsG}EsI>*7IY D+tN`ڰd!!Wu6YYnsw_wwp.wvwԭѝvXi#OA蹝\#ST$[>aݙ{C_4YɎ|;t@)@Cӿֺ"F@"t}Go"Y6Lj5hXnFƭf"YnDq_nR"apylĿm9P9Rks؁4ccr>dN\%Z79+5ꤨ߹ȣAhrPZ- Ć}c@Qx<Y˦;]CK\:oVf,&[VI 1j8R߷mM,WZr^ 6kR"6{he @"O(BuE _ΰ+T83SkXv&LJCNu豥AR$=¿MORH;X/QOl 1|W zmH^tD7wwWfDL(e|cs5@d8ߦN d!p)BK PBJPMxR҇'{?'_Sv6Zkxǹ]DNzc̃hybG\@h^B`QL4%J^8):^7%h}r`xWmPϫ=yFVxDkD_xkIl'6d8, Q@q!E, /`Q*syۖ\Θ"IAr|>=9ƞ=(]\4 sYXm 4OԾۯeme{Sv̔gvʷf~KK __6w+[j}|Z1'W7E -qiW%O@›f\5x-G;u$< ąDĂC${!:TJ %Zj~^ nNhSz=Ik1` ULf>[\ӒcUmTOY6oIvYvfpiq_%--Bfг$1}8r9lVZ+?wgz/쪾?@tG2M'o.ݹs/n\жmwRt]WN\#ӟU\eO*/fI94'cx@kr]V،mX1d9NG' d)I-ߌ,!-booܧ㚽Zf~iETYZ_Y~k+奵UT֖L OutߨdOYwi7`ض{vE!K*[S[@aAa=xl%[ܯmJ/_dw͋Cx|^nņިͶYsoqz:eSY@0YlgHXH6|מn[Jh{V˅Q]40-bST-L_n-U|^iW9ꋙ+TZHyT)ZpmǓf[<>oL9_ӗ`3ݑw `'("sAw/@#b7wڌw$&0'7: Z 960x]眉pq>A B^뫁7E[m__1yh|Fh\^n )lxFc Jロ3Ge̓]  oݍvK@[qm4FzvoOڭ?'6/r8}iUNwq6KK+QLwe;bĪ~<{n(vuzT5zvsJtߣ8V)fzs>z%~^׿_ϟ?Cn:^鬧g9/ Fm9Y[^[Y_ Tc\l(-r)]ZdfQ ht<1{UEC6fsscrF'vzTȄWU>;gUܹaGu}#4(f.C<>&^{N2߶jo6v^Vj;{[J4F`pg5H~Rm[ %@+sJju{uFB'#>x+4lm?IXn!+qy|_;> -&"Ucln Z]v.E-"" KʞCojڿ#=+VWJuU#Q+d$!|^=cK/Eե%lA%Pג[hq؇vuh*;vR哸49'?>9xV( +dxGocd)xf Exͅ W#grX-ͺ9]?Wh20f|qr/0{9=kaPYs.b7Nq} [}$GH矃Wg(X߿Y˛K u2)%h &L`X/iXTyv-7 zϣûu𐞻S]x,+ C欱՗5Զp+uV)$"`)p-ZyĻ<Tl4nlxfQt:Km.l1YxbT vnwξwf^g^^VS-d3[|7g37TMx *Uk %iKh!\tBD>p12n*ֵC(PzmۇGՃ]eo n1Ga>8h})t:j-% b'g 5f桕$`v `.SYE'e"708 让R#@`mnx6 rcih }L)OH1H4^>V}jaC_}8RUg15E_շV_Acrҽ& 㣗 Ou?z@}[\1?{8Ʃu<^hxuոU-ʺk7%^c-?7"oXA yt66&1p+F&Ѷnlewуgd߅pR&;ǯ3O'Ȣg3z\Ix|8@Nx߈N~ߧoD`C=/M-R:]Y,w_;?vISsp xvB9'mg3Or <ȯ"g_'pa4\GcqU#ͬ/⽁hIN:Lv19$~w Uu8Mj܂C若)kAr 6It\T6]{7`s3s-)MB¡~0X0E$x/RJv6?vK)pvb&^!)rI]$ \e1<y /VSXZQF.WWB,&sց :G&q+&nloЉ)83_W<˾ `my_:ә?kd3Q-NcDl_p3N X啈ovO_CG.a] xx4~Ko+=YZ7T]Sn#p @8<;]lg3/s<ȯ"g_wX i8ǜi ?if/"os8LN=3ލ%t ˗/NlCc2!Os) e-c -ʘ8n0噹ϖ|_3mU`NV cJ:ʯC丶crKd.1eS)']dk) _a ݂r,Di%|"|S1ʗf'fW Cb+݂gyw_zTf?}:je'Kwk6˫_Z?TSn P??;lg3z?ȯ"g_X i'Eq|NX u##:9ŢLgL< 4@o_,O-w k/_ I` %mEr{fK H&,79534ЈIH0 q be0fx|͵C}@XK b|Lb(GIf0FZMx6 j0 j0 jzX:u9xH6k3;MsWC$M-Q ܊!Q[Łcn?F3?WVdUx?X̷ |k5]6yg~̇_J/RTZ}:jt72fs_*{+M ?-L]c΁>)' ݷ䟴yI,L$̼gߣ{ N^çbc*6cX--Cw[|e!oXTZW5)[.31sDQw>6,9>}u _8W%[wmdle! R(VOuB5{U^)❆TXXlvi:ŵRqiyXٵXzTb2ֽK ~UciIǷ`( LiLf0Zx͜XZa2@T$g0>t3Kjkks4lwBp. llxh23lZX*]X4qyCبE]ԡ.fQh-XƐ5:m@Snd(_Cs0 ˩30{4$_3ۜ-; K׍, ^8`u!{m /3Z `d,n s_['WG3'"A5 *ijʀȑ hH0?3,<ǤyIގdF,CZ9Ld7:H[ХG>>~?jۣj?EpizT;G+q:ƣ?g{h1k0 ֶ^W!98%Rzl{&mx٨_kZw /d|ƻŤ B'5" eьӪY4JHκ6lg˷Pao˅ˬ]ri#\ )\n˛sW2:(KY 0>|Zt1f &7JxN9q~@kA7a +(tӼj&!ˌz~6u{$DDy]-j?D"G'4kZs@!06HV mֶwnm<::mM?~.f?<_9HXqX)̽:ʥr)O9y(&ŲgqyOy{zw^FW'(|Eι;Į,gIjr|a}dH>N[c d`XSھ@UPK>heQ^s84"V05'L(N:i&+j.Hbx[RLN%6:8Ȕ0 f|7D#IuG'j+rע̉x7 P2`PI&뒴*r"0D(e-v2U|8(h&\L h *4#)mopf6lG_W?wDZ,wjJ Χ$ =imB{ (=B ϛiC E#wwQ;K I᠄6Us* %b/s(WJ`;muo;~;UҶti>s[fb6w߆eN'!opҘo2B7-{e _7x6DTyyaN/ɛ#-_Nmts0L(_tW$W(OI|}gg^Uu>sXz+ԻEUvb^ h6 AZ) qC,4J󍌢/dD52)q[HAԟ!7jc-ZEf;vZ Ą#N֊re"n8%;8U\81?رRti ϸ\qznG6}Pt;oXO"gaU4MW=]ukHbm=6v@8Wmvpy=PĎmNm^sIiViP4;"VnOlM`(-]n!ϸ}i#q<' %!mׯyTyZpűEɩۄLTiwnǹP|:I#7 J(4ήy՝A-zb !X+;,P߈0Z?l8&RF1STZ62|9"mS`o-ZIAjiz3vD+y5YMo4 o-vg0EO #N ?Mi{J42R&VXdǂ)͛gYIR:YSUj'rcR8 *T'>*ZO=$B] aHx˯TWnQ"6PngޠjWVbileZ$~pן 4~c?/4y7qkxzkIqOޭfQeYJE}o?1C]̅WX O|\O H@ CY7Ptv4[>zg03W*ĸ?ؙ͊/3X6/^A0c M鉐 }-Ն2.[ha|Dഈ 9|9/Er Ppypxj.> lz#1&FJJdN5SzgB6hj÷r} t򙞾}xޛNJ}tIT@xgw;lDp&6MFפa zx;FӠ2k括v]JT+俻俙7"= 俥TYB׊@|!C9S &zRdyo.g k-יgAr} *gX2I4eΧ) Q0߹x "фىIX,k yںPJE(t|72Ruye%&\ !od_)6E?fZ={P)<)x7!@n?/ꎐ^p1hs,{AF`>^ӄzDukɐV#:<QG= ό1 "x̳sJHvR,=i? _SA|%gT8ϐf-GVdVCRY -R1.U*kkk3.~i('TP£,l"tJ[ʓ1GfOl3PӰ7}6)m5{,8h=^8v0˱Ƿcs 1>S4xbzRhf:SM玏2X %ӆpe30af橨a&dx}J]x+ - `x"4Cעg]|`Gd=B!^HUuus[舘Oy"}UW}w1شE?(_pO$0-(ꤨ(oh|ĜF r >cy&!(+ 0q2rn? E/Î^ׂ`#4 /Gj8Zʅ78s)P%M|̈́JؗhFJ̰F([}|Ǡ8T!"k_{׳F]~ppzzx͚[藃sd1"/Q9$̣%h^3pϡU9vM}ǃ 4ųy{VPf dغt5_([1J;fXa5S6=cHPqC/bc {-cIZl y|Șf(RE)uOȊfB#'hΌ-!-owlXÛG.a1R-"U?^73&/0` [ &!h$_3y툋71-WF2m?-Q,ˉv#Z|5uU|/hjhR?CCӌ=ؙqs>WK?hl bw@yD1Ԡ\P( (3BPKqܣAa`;ETԽzxBc MQ(>.K%5Y_H%TXDWJ3y"Q,o;6Ĝq᝜U*KkJߝwS@fv>*.-1%cV Nx)NVO W8F| 7酏Kō+݁q-mUڗnӈQԾ큆snL813"1s뉒VVTG}͡<99Bp*|8B+bZi#g(h`/;i'Vė :h[{t[ot<~y%RсBt1gNd`sF  YY3Iڵ,{a_;w $+=BU߼=z/0;q͋x$&Y+|Bf6CN, ><orӇp3Spc Ns70=X ߙI"\QB>u[!x"Q 0 U%OL `.Cfhz `oM@ༀ [dOE?G Dw0E }̣HAcV=Nqg5 }VWć6a+cC4ѮYnmLkku- !~ !E6+ ք4/4 SJ8>qDmTq=^S%u+Wbco߬Ǻ)WsW9Qل8vIx`PAڐ44$d(8IM F}S)T]V5&ٌiRzZ&ē}Vj9Qm77 &pfZL~$E"-3VS@sG3VB3oOu3.\Xom'nN9T5/]WK+iq Kǫ57{zy g'/ô͟%G_w5Z'S3VV+x*rFek df̕Y*J Ev+dkƶ z1Q?1<Cv ZDX!qzaܢl9$yV,y0BF7K!!_IU>#(OMbFm TOsx<x>QM- @uD lA.mTR,P!Fsl l@#r܇`/|b E' +t,Ğ-+uI`i7d :_7.Ʈt$J#3БGb4IL@a+w#ȥ.!~Wv1K6dFf8lJa<1jL;VL>d-ۚV5[ҘtYrC9ID~fKp>[PjJ'UagcNِ-PLEr 5&v3ZW|LmRC~PW6 4F%J3 >~LncaA3Hp(}qi(L$ K pXjK%s`j:jvOE%@dFnS\lJ&Zk{".R);Hms6S$A7o&O ZHhVEqle&F-S<41#=-i_ɮ}ohLRߵw,8k;fʞU|._gmz#]D~LoQ^c\-edڎI Z鎊Ri '\ 1astpgo'Vyh?90~MIhA? :@VuwuDjzeL+c[_Jl}iLK/ɣ]h_߫R' (K-푖6Zϫqu 5nYdc&: !7agr4"&{8}i><&`V%L " K| C}'f %DSE~bwٔBV[gEs'V@ΈVTe+ɪ(w:x׽?`wMD[)L|i4RHQ/ MOPwy91 Օ 0uur[w5}Yx*OT}ˊ& Bam!8}&?Q#,5F~q҄/*–GL'ZJKqχ8oAԃ g/"C?nz[*ꏆ~>'Ru+(0c >^4lPXfafρ OLe s7z{y;>+ʶP[1xd]U<`g(N* CQ]A߄顴d΂n簤s-A2fF2 c|"hHZX?-}Rg6r#kSp=3`֚p^w7a7A q+8s+,lnj$|8<- 1ݼc5Y0(,q'd|||L |T'>$jn>o{C?'; nOՃ㠵 ѭPsYhߓ'*ՑY(VH9e}6 6Y+k=s7DY Ν=b92Ye H@Q<51Ə5_9#p[#4=G ZdrI Wz 5Ig`:c%|U| Dg$H#Q3H4~NZ[ru՝&TYf``X`1?Ԇh" Ҍ})4|aK:Yxެh*VyY;$–WZ{?cAwYF3b! 9€ `dO$B8XiST%F@Jj2G*dž60m/[#+Rw@53,f(xu5"Rlӫ-A"D*ƹIihp@,K23xOl$<5BX091a,!Wj0m^(4jӄz CFŃ&zlTm\َS-! )+0!K.viİ84#ƹ"Eͱ;W}`ΞD&hic8фd+< ֮|is>f#:C t M 6W?pϭ܎3af Hŵxr!X,~Ru'X!مŵZ&&KR۲ʕㄏYM!H9MC7驺dlI`p\806$|O߅2N`w'ָ4<)Cؾ/Zɚ.AǏihhl ]*JQ1hV)#5"m3Մ&_ASG FBCf) SP [@6Rwn(`3GX pKmѱ1s%"IģU^ʜtMvF^zs}tpIRJ{TJy$ޅ7@sܼ:XԒ%fjN=8 f>SpK®fVq«Ю#IqYثh)mloU0Uj>6cM/N eBpֹƾ>D* \6oEvc<}:ՄRzTwHİY?9G|t5DW%(Z}D4N `e'θ6 |Pcrx;d:YQ F1zaҶ k4 \& (ʩ8YYnb)Zh[5͠y_F>eBsk6w0h7 ZXVf4ɂ_P|̮{.o *e#$B&0 ˥_Z($G<Oц>򑝑>T` I}]Xs/(F͜:&)kZTc{C5vJ `STX[ i@-uAXGQB;_0KK: K%@^1 !k𞄃R4Zl}Sd lF77M,l%$Di"W53(NQ, f9LT ۾ ]1x Ed :B/Ӽ1j#hEWTM2^bNx( |0PVC^N̺|vꜻ7 #tm J{zL~j7e:ܹT*Zs!,Yϻ(;!kǀW m%U#6-6bѝf|؟bqG˫aB_Mhӛ)8 ` ĵwv*!u8թ SϟWcY|csA)t3d4٤ζ=;\)vͨ wؿf~KC>5z4WSaȲ;e{n@ϘMZNvpMuJ$ GMC6v%/haSj]Po:}h.%Rxy!DuzSu>=,aDIBg]qrPkItx'lY7p&Jya6bZG}=&LO!40FزԘDQ{,R[gJ9by򿡔ЍN`(-P>C y-i'-eӭD@x XrE8I(Oo__!%޵dK&wFEΒlЍ󱋏&۾SvuZPڔڸ{U^GHHLw[GC8$p'UF5` lnNRJWzyZrGU.F!эoR/<,,Bs9t!3ðےXu _6w{M/> tyiU4 xzu }&09.҅f][PLO%P|>p'X`#94̰ȍЈJ܍0nBWp$\`R굹lۚU>YeU1@@H8,٩>^i^ϤUcG5m]r΃Pp[Gd P۶ٮV_mb5*;K;88椻B@AԔ6+8:cPK2r HI8ɀPǏ?1q,fѐKu 5kr1ʈi ͝#Ĺ{`k}3`1o`~2mJhNK%gr·q\$+dJVOeWW* 6ݡS1"7.=kdP]cjDUb>I"t˕ITIHd )bAZ(i7qnP쯖-8FK) K "?[L NA)EBkaĦc+M҈H;%[$7ko&X%b p`  *RpF\fQަL4TӲNXv\j&~_2$KDP'D{R!0$X >[t3v-/z6ะ˵!4pW,n1- Y$ˡqxYg:jgĠ6הk\r"+q9Қ].qS'@tFh":mwu6ġcK ؛^1kKw񳏿? J4Yw_URi4.~iѥPA1ㇽ#Qjp"V KNq$NgT9 >}prA:W7urt$s~BD-JFF4S3ODv=;P]] ǁfTOQ؝yFW(8¤lFkH6* WԮ,U0ΐwp*Laz \Щ-M FDG^@ Ǒ;@N,2w]szPLdiD`Z[ۙWWVO:Q3d I2HחfQ6E9"TDF}X)Wd+(C$F(m[OL B<ɩ(=ω74q`hr{B.4H뛣@BRlnsԔ4jc1.ZK^V2!x$ߴ.N*啰T73]t_eTY|RmfUc+|ƿr,Ee夶< b=_\!q/l4RQ#R5]SK55['uԿ[N<A#0K'eۘXwGMOuԭ)WhY^#u"gK5n>چ%pKOz-CUZͱ h&7[äCŐkxl֐Hv+rE\v0(C\N׫P\Cv[.hL&- H4NwN.@Ę(E9$mFm=`-w4Ἷ`l7bȖ(Z1!!G۟cC/3uGdSjj$TZf?wrYwucՐZw3o&ݺq~PJ\z莻\*oKa){9Qk3)M%Sڢ2-dZy]UP\q%˻ Ok|/L /[LR^tZutMR1\eąW!?q &,A&ͳG A^ϡFM٬WuƘSa[3] K(opr(1 6Tv0"VUI؂ja~,m>4,4:oUDzŬfO%TfJwaldWͦW^ 5jyczӤ ޹;@/s P('A|]?ENp WXQ2S~.aր@zldbyMv#(تF>Qm OsF0޵+>Q.Rq73.~3&{73&ߊ?nJt.8QtNmr?\Y@Nw $gOJ9guyes'8a&c_c\zkriit+Qs :o [nY@u{ ğ+p˸M;!H':?ފG{dVhY 6Ⱦ ?6_xKʪueD+ /וr% /aN"f߆Y}x[{uS$p) Ҋd>s>TJRxPΩ7rStnWh=c/R~φͮݚ9B 94?k') ] ]y?̙/{%kr0?Uk+r#1C-xJ',#; Z)cwX3(%^ZxK `3WܪK˘qQtu KgR}W &o\)!+Q"E@OǮv& z%ZCs.tqii%s\HvGq+Nz\~yui~WJ:J-_x82D,QM*FǢo~:"w0o u_"tM-bw6+,_3;ݿGfgNdl%0B05+2?`ٔ,OO4O_~-1yx6Έ=`tPw;u1nu{L6y|lڗ~gmxSVfƩr-֊sOƙp{ bvakfF^m7nE@~O?_q޽DJ NT4Qrlӣl>{1jw$ 矫0ϹQf 5dዬdAhE h_k[@B{@w> [h0<+S]POV{AE4fBנZ> Db~/_*䝞XW.T"_3n~i?пO F.\f.a?K]`OKK kBnfn9 'W+q̂cvdkx`F6`S]I敖[n 1n7Bas;`).u' jOVD+_bƔh0@z|A` X;KY.uQ^ iく1#\nnj/NoFQ^B\-{:<#hG(bcy4 A} GӠ`kfP Vlp)QA@)r/6slu-C!FlhMnsul.#rAlI#IplsZ{Y{oGǓϑnC~Bh{\_Y|oׯwwxp[_6+styis{zzvmnu޷6# ?0sj'kc_] Wf-` -ou`E=/+Ή7hOۇ,~r$N}ϞeG>'2\ߚ_y7]9;ypYUo?ʫ_W߭yëWex⟥|^:~䷝k7]=r~.v Ms9si67>;_P)N%D }zF~DuBGy;SЇ/7wv 12ϣeRϥ͍pTlx#Ln$LZtɉi 4aJRHGC,+^֭C"7\<>^_}V^N1Xjk\wu铅7~d/`$U.]NF:`bs/Ӗk'6N/khC ,DOX=/N_q^ Quw^+˱eщ·ְ4ĉNDU ۠:"7pA&|M倜_ܭUNZmj;{;>ܭ7lcp$޳%>$";.I 9Nxt2fu8/(6۽ %yaC._Qq07)e$\22GE1 .CwH Qpw \4TꌘqRMy,sMϢ/E_,*3ZJq6ތ+c@,2ec)p@Y= άDLdC\Z! ڑS|M_ϮkStwofq7=f[0;[<`iлU>-*u,t??3|?n1@hƽ L8s>`@a Y: NI'D6? luGyx>"Kği  5ï{:K Oê<uȪHp DBřxpm|6deC :x+X>j34=qn/Pq:?s8cH"VUB 񣐮o7n8SݾA.XGบd`( @2CW[^Akᇌ8 fY MLU-C)3D >o.țMO&{:ø,A26YSjKЧ9VS[Ljyy.a44)qGǚj|.CmKwFGĚ&&rOܚb/HhePJI4i-!"6F߬#@_ዙsVAH#aіZjh^&^;^6:NhDEODE< |`l=*d Z'M:[$33SGiu3I?kctLFz wAydDpb4ru&ϐJ?H.m3"5yWs9i])UN[,싩|-ok6O C2s9 T {nx]=믠#Șn\y2hjMWs8Is;8(8%ⴀ̇cM5I FѢS4E<]uk7QWD'ESb~ .7x>ir@y{QvT*.pݘo[GWc>>ޭ#Dk7@NNpa =j 7S3fnE#WJRvnW~fgXv C ,v=x.`.B5q'cЗ211h s_N;"Trlk xyX5?mmB#!1;j:M;w4@%U6w=~a[m &8 EցgϞK 6"=qkj:W (G_Y 6oS)r2ma8b,T ZE"ƒ+ESbN`@6(G[- jq?h4oq/vq}K <~ "/ N(!,o\2xq&> jXIf6h7\s0}$n: d5U L:Ҕ)# zjQzN3  uR0*O !li] 0P}y{4g;y BP*J DDz u@ 'r"Ny]f5ln*+<#_.BA9u^Gҡri(^\\^a#"}_Z_*8 ; U",فl4yj|\ LN-24wapW {\D/:E彙 BDc(DC;vF4xN0=P8m4IVtXϣrOr[luAĶѦ+_.y*Az0fe]t=NK1&]Qo`'EGvU[+2tPJ,@H< |' .}W^ \\+-E\+?7:3޾Qtp}`UOi:a-0:_|0l;I5TߨH`5hdѼDSF\YB>jNSf9E }>NۏFůH<5=/2#}<ʘAG-N~~a"yu0ޟ\ܢWVZq'$3<؃R?M)v -Ƕbf͌+3_0>D,B< t>fvS2{*޽{Y'loMI Z ʉGhzD;}qbj:QٰPQ S.JeiiyY|s*T5x*|pu+l iz^[ Kٮpu8ҪgjEQ=p{ܔ\=8:_Z%x"6AN& 9[A,i=hlY{Uj܍m0jRAc0~NڨJ2B?c{leB/MݜK-FB_ ,[1Jሁ7R /i8|SHey [aUk@u[jJ{(ܰ;wWrK9,9t[~SmM&Ju[ss|k_M47j3y'&QMcj|fJ*62o+afc8> O|/'NgCgp"B1&r<o(ceCHT9u DǷ FzzRx~}pm2'rωK;܈]b| C#6 L6˜!EnJݔ؆;m%|"D ؘ \`ЈuG,u( ?)u>r ^ a;3|1 m Py%u14nc[.y\(lyLlb?u.ywGG-Y/w껣_xC+txtCX4.hi֍9ߒ4ΆT$Zuь͏~{,*/'uǚڋ"DS[hXA$h{UA3$kTĒ|Jc|Òv׉~S`SWFBa%mä$%6gtnvlI?~2~dI~Ս&"G"&_TT$<<"&g{;L*'| LbLǩj}^ ̒i!Oao.ɄQyou:R,hOyaT`ǦG=ͳFـxZ$2Wʭ\R^VhIҦjyʴH /nߕr9[gwK Ӆ Gv6*^U:̑zCFz :HX%b4nw/dFmnFnݽ4KȚOj=.z'ɦ1Y<#ʰ>}>*6ݚmlg;G%9n"F  ny:Dq.Ά1/^?6D.>H s+2G=DLz1R7A0 }H]o㦠甑l#nG؇ DÍw3!ՄRYY$jIRKMųI ^^ .xx1;mYQǴ Lq?үz^FqxӠlQu9 $@XYjxxF>D2`Ɯ'5D:*F(V"`h0C)r/a¨uN$Ҁm$}^~Nka,|¡KNs薖W4J<(찀5: j@ nvO;3gw6w gō~q6Wkx_)vloR`m ܣ4;'nT/X)FKIn?{ mo%}!ċռYtc4#o~5Pv̖[ l/f3գ?tg8SaKǯɭ,crl\*SV}FD@QƐck#9_% W,t s{s;7 @ ^ӖF77vQZӮHsH6$ N TL'>0 Orh㶢τXbB+=,s TF*F*F p`͟CDA;8=TWx̹p|,"n# ,je+{ݷGwa>S|?_06+UWg}:VLu 84߫F@cX^%@Hb Huj_͘^wϨqDz'0APS@7YUo4F Q59'敗ia-_?SP">:jW3f^x]vhLog#njt[~YZs ! Y-A/HSm:Nys~_{Un ҬTYC 1J!|AWI&y"zӲAfgeàu v (Z ~-O7YfJs,l|i6A31+k};+)5ib^tISf0fћv*Z À/C*>R_)S7/R<9fO"W( \q})'4=t\q6m2 Q&Bqm⊴ys23dY#ëC v>s/("(PB%B70,DG6.,{ݸA,ǘ27oz^M'V$@X8+46qnJTD'5հiR̩" U|<(xg RdUE³ Y 4F.KUEmR UTxFP>mm>E,v*YIUI4PiWPNES\0yJME|mT&Vlh«GȅĆX_<$yb+ EXQZ'()&۽Rk* "𕌇nIʟ~=?@z lN%$Ps?.G0#?e;;f$vn8tRIE/EzFBR ٘Q0D/5%B7G 9nAZZ ,oM~ s!|ڦP{$,D6p)c 丢qR֎o j]WrDa2˵z5c ?dzfa&:CYP*BJGIST*C76fA 8rp1[aї1S$c%>W$4(4fHD0ǰLݨ?Gfƭz+~z .E NerM抲8E5z JSH3YXB 2r \hG/`Dyal a>P{(^q ͺpb;#9?'n"S.kB [!cz["ЉxâRM>ye!.wr,&Sh$n0J f\ ƛ|\i~z&?I쌄AFQu=ݬljR![5PqG}IWꑼk3mu~>APc|:"st a<g)Zaϥ|+*<7y΀ ,_C`R)g\45$n5ςuzPRScxZW; 9*=D)N89B'òqZ G8rq?WqQ}E؛^>Ehݜ$02Bk⊵iտS1IYZ[^ V֖f?w̬}f>kY)s/`:yz*~""p Jz8oSӉ| 4F-,@n}@,{٬^lP}N] tx&^1̍rP  MEny~mžR|v9c ۝s(l(%+p [4gBm,rK /{Y=ßQ@t|5L(6 Ƃo޾٭`Ⱦx $*vg +(S$u0,^SD|n堠sɇea80Xp`z|®\#e΅s+,L讱n{^)1}{C6tT;yg=lz(y멼04`Rc͝N9MW~,x<ăOtm3S-]h9‰γ\ei$?\0 5wa6@SHPT!ÀOs: G>M[{o@5  ]@zMT2KiC&.ٰ#Bx;*6b %;.EaG}Rn3hwțB33 :#m*'r gNvx&Xƥu%H/T=tΉNUB$U(;^ PZAG1~1*bA,2~cAQY*=Y^r&2Db!!z.4 @9~mbx 2߬\*LP0/ fN܆K~a`ZL׷{8.X& .Gi9v>w}BDt5zvluȯ Y˙q5U!vcޢE2˧tStEG uGX:Y\@\&2?߇;!t9.p7 DB"ykXK@{[4Nt!uye,} =KwA6ZuWvJDK +W{"鑷kY8_P֨@e,@\ZY,bOA\_^_e^ף HUV#``iM]^^ TBK'ʑOfJ*`X3R˘YmANy'OTf-pe</P= DcKl YH@u=S`Sb$boKFb\@lD>1]Q~PXۗXWKV" tP%TS"HXA`ts1zT|\u=WN̊8b-%I|x, Ka׶)\4,tV(|^,B-eRR0U'WńYo,+ (X i\9[,sdgS3xO?3˫r)I9p& 4 wM.aM9~vo\<A !Y8继^KR6IumA&5x=<5~2!}.e/zYwMg_I/${@iW8.26+W};^rZ2/ t>Z*XN%ڇEGM[6^ \,^/\zp'b$lPyΦ\"_4a39K!{:[rLY>T:RNl !A|P:c|XФㄊbp?}EȾe&O{aӨcM6R|sGts3@D{q.Te囅$y))aX@.&=f#0%œІCTkHs %K,O\K%+n7dV!hz`6Pcz(>j^1c슼DV F" b ;ҮotU?PAj\ .2j9"FLu6*5% 軂[=\]7l#LBFtV{N,w~-ff(}icٝu'홿QE˶$W(G$_Mq*wmlcea"5TU "F-W#j5-ζL̴sBpT.՟H,?!6k8d1RZZA3q9:pR0۰KBI! pcf*7]KtTQҢ]QXiqI5nGu\*+kaOxXx\%3c h9i/Ʈ%]d9J7:..ZJu˿-xk>GW+'.nvK-q4uOw偷יurn6^l]|Q뻷vlV~klWvVYxiN~yN$@A!iN!!i,)!:Cȋ%.CyT+rpIgоlϛgnEǕhFBu&Sw9α}쳬5rQXd$%h? 3_^"q$*\A x,^Ő>r~+4:~̀GMC6"<(C񐑨UQ8=OQӹd/a,2d&kTAk&;#QՏz+ Lf9`2 'M!hE'Kt߃>WCeb`K7ٛwsCEȣYx!Mm1:enuOp.uQm7trgnc]%^B }f]VVwP>>^MȑJ[Ys +>IJ8bYed‰ 3Tb!t 7!0GFI,K New^mgۦӮX6WHWjcxJ8PZߟ귫et"jF>| E]"Dj߻t%޽9it݀#Ozjof_S-d I,ЦTޅRH[ ICh(q6 <(Rd>-sqpTxo j9nN(@ 9 9n?y E8J!|ENc"@xʶ cTMf [[@ ~Ow [f7V=`z6pu2bYaӛtCĆP|pVlJ<jCX/ZOy\l1282Pv%6}9.Xd75/)Ȉ;KJH}:Vn0q39@.RnnNs]+md!:0h! VΨXj1ԡnl@>q l }^e[̂  "():{j!ՊwY\hA "uvI~W ůTOc_V6HrFqi&!3B űEજvہjc:wԎgBPfָ$sTl'ZlJ?[ANP!WNx#/ sV ɲ<-+BM;_¶ŒR\ O o&S:4 /شh{F̴qpqJ% c FSLq؉1eV9p7T/\i.qـ8'cU| Ń.FRYq*{I=l{ad'ڬgHϔw i3S(aݮDq-/ (QON< 3_I*ᒘ0=3D;=np5 #<6 m.zQG9<$k#8Iv>dl\t"1K0`xM - ig9^PojO%uCك/z|1>zD^17{tfXwi<뀲 r$Nx{Š=9kto7"3M",x? DsN)+FI=ќ̭ @^=q̨)w@6) r P19.͆%;Ձb׶C; sGY =`'U]2C.;<$PsIqD,Ys@Ojf~-qa',$sqW.YGj=g F cFn縼Ts0ruzČѱ[.Ok\Y{?7Ӌ1Jy%|;bD@/WӄbQH"c9x?zۧ), >d#ʙŤy#*' 큒$ "%'n818/f?/qc~6ƭrx_[Z)?[g+K.Jj\ Y< +xeVW;|ѯ7lovY{9n-9%~NOs-O6>>XLq_dpRe&/YO\N(3 %o !t]-Vh-,VTR]ln]ܬG/}nC<o wE#,7HS'wKs4^R}+Nepŝ# ,1?Wcv KLdlpgk"cr/`m{k=ĢyH' s Yrz^_^ݬ#u~K. 80QV\7,s2jQ)~Jɯ8ъ}YCc E YBs/$.>a)ޖ$'q^*ϱyqAtPϳJ~US͘e Z6[uy.P///\zw<4/z43,T1sHF<ZHs&'Z2h"GL%&FֺV{|J+pR :Y0gDpNVaZ+nSɀV<+et5 YzbES: )eO[Ӯ/I!\rcMNj3qјIK.AA1ԜnVMHz_q>WV5"7C+os-@>d&¿Λ j%igZ;E(i; a pf%Ɲ.(7$n`2:*7-xdq j+kJl_f啗:]к,XP}m ޽ 9Fn l\ovJ}Yt«c1J/`>qQ / {OƫK1Q^HR1#֖g*#KpaaA2RNoC+ f?S'c)`Roڟ ADɈ6HD:2"K.og=!'S:w9YZw'<8;}J>`egE,GlƜ ߿FsFvrc?_4(iNl# A> bB=^j vCzAV^7NoaFUmx{b=5%lV%u|]R"}ۯPHƻU]̩y+Z| ԵM<VDayh|^u01 \"$V (Ξ?J n mO_xUܢ=y7C!gJL^u%#0VWVV?m4i5cq'} yxyp#(`y#eB;URol>ծQs)kJڙ]& 0mnEXIVX)^`cC#*S"tr3nz%BDNSm!%ADaXWTQuusT 1 mi nZTl N qX @#Yў*H /F2VS=wyb`zΘsԁNs0PM"@m.R,90p;]a~2~NXhhc7N%(K0XnC;9QNdÀ=e1g/Lxɤ0NL DAsʧ> )F qg /<ܴz h;3O#?Ap0B SMOl`D2м5ou='3O(@WpK?)KonZJ;NG[Fۖ҃f6i!ߴm{VKqdA "l9 oi|Vp4yȨ*`os}un_:ҀثP4V(5$*$,QOAΓ e.stY*ZV+Yy[J tIN@`*_md5*`@{8Sمy%+P}EmԶ VŁ*c^q[g< ț`ğ߅zuT@gsޱb syd-y+Ix8wF BșX_Fu MP o0߄oHsͮn+T# ն2'+r *^G#cڰ6CӮC 0hA`EA@E\q[K`yǐ7TJ;w):x÷;xOrO06E. _m`#e0`xךw(]:5_3Iw1w3Au*< 򋃡a ב]0bK~sr+d]2$E2:> tjtSDmd(]uMWE6Lx\UN?G<8cmBHS^fSku/L/+~4Q$aFB).>F?<UyP3}llxLd8qDzGďPO`H–d.T[HGS"I ,]C\'Ab'*k6ҹh3^E7tߕKۦ7˔ݦ̅CiD9Tci់D!O^2<ΪĖ75*Q9aY+D h0ve b~.&~gjk)^s[:iأ4z]I UA"{ID \g+OʭZJ,`C8*aK yMtE$XNwބ$j;iR&"TAMa j%̧)bۋ s#se!: $|fɒu2s/ae,e'd8YHUPro7pfh뵭txz_;0hhk!r.sFuߓ12 c=,/&7M.x9/ێRhjh7\T6܈pB .A3,Dd*In"5띻GbVG"~5%M$Cu9S*W! ²/>%0$Q\01hDZ'E :>)bs*| `g,\bxl2FI{v^t~,#BlzP7fqèku1+I?L nEc#k9ޫ:n&C)2˜1ɋB CR"ȚJ? +vp6? ?Pkty͞_P/Df t#?(pX  tփXcV3+|hѣa\$%-ۆ58U6wb5)}Q9*#R]@ Iol+a W k>3j9WQ%؀PBkE< j+B%iw@<>=@}e 3g`[B°{Ci&I9+1c"%f73,A ̡ Z` :+<| TqKL*>:9UMMmAuk`{u~f5u ҋoaDE6Ն9SQ!D`O C>sڴh3vs5ł ^%-',cO}CtF _B퓞7p0l &L/![#:ܹG1e$t[~P`/#U `6 o0-9Yue6ћA2k{LF B&ix`D)=$>249K*4 , іX٩p ϧ&dYy+yA1fĜVI0iLŌ~R$"7:Z.|lqn ~ ]Ďi!&r O(=nsDGh`%}"FLZEYkui`dl`f2<-(217df8Ujq(bJw\^Z/z,p/U% fW",X؊4=^zo8Zϒ9 #t}]?`9 U/$쒺);¡SC< d+ =^^927M<#efu6~*ԓ}Z 6d`@SLG*=O͐n2mnAX9 j `-MlA?P/ 6=/^A tN'\.bǐ5ċr&UWl=50,X֗XӟqdI'jmuk^oZď10UuFQ3lYVOS:-{ M|̀U=Ui\_/3]w- k_0cЏ`Ny\wJY]^u8č[cd~?H)̝ q8{bC6IOxks~pnn,淺}P$1{n/vMUQ2^Gґe}e_|t%@>/4 ^=DX.vHڏ<ܧ!;fH'O!X d?+oS^׹lVW)SZEKzck^ j_,^yV`y7_#$o/*9H80*p  Ms'5eN\[mQ7}pª2wPL]xV^+E8, WſOЙ!k$_#wFjQȎFO1s%_o ^k82K16'8vZ`kƱDlzU` M v6ģ0߉]"uL=7~gr*w`DLg!G]1C-S.hNv(NrM[2ksƛ5~umLD-c ;AeJD'jJn7{i8_d n̽ I,;Q?}|və夌2unFo1Q?uBU;MHMl9Y " d 7xi< ڸCWpܡ;w"-<L } ٝljv˞F:`: 8)kB顈<=\wz:kNw^C4Á @Ƨz8vz8;H -l}%iҷr8Zr[6\co*H2%l6A:6=A82 gguB1IKD "*Su(*'PQ)mt27/S{IF HRD8r޽Sj>71ϓ9x5&~f;QEU0߆o c^$ frjF'@~w+9W"vؕ5GTo+=4DWy68X,y\L,q6 o`,0;®wP<,Ͱ^l * >2K띛%7Ҵ~ód!Zw6IZ֯q4ZYXgjiƁZrtIOՒ\A&=Zj3ei ƴz랴i>=+mLÃNx6Քoc8KʄomR\79{:K 4RDqوxrcR>ܘ/S 8KnNҴ|cSOՍ~J4]rÃSpS1k%7LZT-O~~7e/"ڇxc)Ҁp獁 _LoLi5Ɛ]?<{ӽd)_(}7/ 8Kn҉99'EOưAi׼8Uog?;?TlGlf1nt38΀=H/BCE ݈W9jC:k "f_G1I*k{=)8S2v< !>3hX>WKO2ݳ^-턒8nMx -i\zRBCBSR6sq,GpN-a |7ωuCga@ 傡oh͇V`#@NByx ۑ>/!ls!f,r`y5_<6kD S8f3]<^rV0w6Uoy{P=߰Ɛ4gdU^G {aG} R YRօ;n,ka' `I˩4 L~ C $B[}V5p{CQ^QlU^V vc=^NW1l{1HE68)W[O!!j٫^yQ=P9_@s;9˧Ep)?yS -2 ]#^o\1R*h^|+bzn..Ng6x=%.UbTӕr|W\n­]=Іhlճȭmg<DJljt¡ʴZ*i0rh# dLDU RDCqc< xJ0׊>3e4>H4s4's |)ɶANQ%Q\4.ߘJndrK\r  6ݬSV!JO(W7o |hFq) )[d*lJ,jSR RPU`gAy VU0 +]X* )*j{;uq12&B>!{tU#c ws=nzKPo>m2Udk'LrC?*e\C+uZ4nD"*yqNVQ[]KVeeg/jBœo=rj x(㨁`v9~\UP DIyQwkU^twC:l !EsQ9Nro( Kꌴ1R.3ߠG@l"5'F9щljFQ--;(h[3Gc!> *)FGUi>ZMdܼ .{pU:\f]XjyHbry]xL2 9 m4:Ƭw&8:}kԶ̗K_xO:Eo;~ǽQ*KRϵwosOK-%OS>!35rbiun\]_y6=4b^l ,軃swOR\ f+P8+xߖ朗: u{ \wEf6Ϥ99O&_/Y\*+++rqiLf zk6Pm`!*0{[;99aY[/ASOҿ4?~ ;XNĮ^.VL#gS~JK+3.~q2${XIpvxTXY#לiLxRDp\M罸U"#Z x}%0y:̝WggmLCsJ)H<%8%J$]Tg:b8,T|v MJp9 c Ƃ=>CǍq1h݉QZ/y=hǡD*4gԫΑ;CɌ#M:8ݽ op-rN&\*)6>˛>tN:f˖pv *8rTJJJP5ESHbR5B?XʥB}a Gx!9Z<;B wiئxKu@cba9>LT+M>2sr0۟̈%1u ʍZ<P{ЈO QrOL5{@&Fs|΍7z(=p < AB>_zkgtJSYaO2/QscSP]K3L OW +d9F*eRrP1)޷6+ __Mْ$ĹQ-){9m$i@nΌ.i%,h4fV[;s;sڞR " iXxyCyŬtrxY @YIR>NE5,N_nQxsy2iڟߥ Ā9pivBV;1i8˳r!l#bhv$_jcmhb?5']NjY+UhVPߨ. 21!sX2QCp8];9?ddx4$|1+ p>LC<_$l(HPw5&K0pg#,8\ǵٛ_OO_g*rz/39T$||C9*'"fX!12s%T =`}#1vxsNdsT<]˵3z.0 ʧ*y*gDN6~rƾ]!B_Hz}a+D8|Q|j_CD G~V+ŧ\xE!Ϥ!+E#,O)DiTi(漹))7I.-/tPˁflɏd& ct$u7 _bTim.u>PxsvD+t_O!Cy= %BB'`\ [L!.nR h<7w'9#QR@H'21Xh4z7*y'OC,[;$HQ_#xJ%XLT:ck-! |V_f mbB iZʎo!(H[nY=u>90?&ŁM?i͓i ~< [%L4J$06m Sn>Gc맿?S9x13N3:IgBT*KEHV@ EP3a`P63VQٔ:ŠC끢%~[BY|)Crt! Q>3!D %Fͳ\x3džհ%].=S`Z}DXEsESÏQjy#A >re4DSq".'8YL:k_յZzg?x|~C@)(dd* !3K@sӢ0 ī0^^QKQxLՅy8X,gW M=إ%5݌ft\mM_]753t{ ︹Z! : %p[Ǒ!ű } l/>瓜k~_ B$A_ 2W4+~FDnADۿn#;)oIM9sOd_kpM|by|']< tHl,&X6 ?l## ^R2u(ȵom-7*/ zI%bDž.ly=?zKh.e^`+/o3݃TCfpTgfd["; Sybpu{~ޔ|⡞h<9B"Y(~Er' vQXw|r:vKG8㈁BK i`i+}:! P"eb2Ѧ$`dB>;c~&Z( r"z^U!հE;>9~ȞWQ|n ,W]c hNc>c(SS$kc^ ks !ڭrP D`Vhh4rc u>&^CB7# ѨA{1]ޫƨz+I6:v5v3 F㲐)HaИAWDQlJĎs%KQ)4P)IzF%<҇wO bC戮ʹ8*0r2U3Q!5#@'VܕaV1 Z=$7u%s-vxn'w۟~9ZصZpfzCəQ[n˄ a! CiI-A)6Y;l.,a[ lԓ4 x`hQ_lqo/OwH}srɮE A1MBh[5(s8'TAIk P͐E6 Uн,d*N@|sTqTвL|_6E׾(rbѺKtz@?;jVqZ#gwjZ'N_V+Umkk/y]o}2t{Ƞ"f |o{s;q7l%\yS\ >6Q=.~R/uAHhWH|RѾh  Z4_Y}p?F&"J?toViBUbZ\yqGZ;>STk=J1ȴgIb'2#])7i=i o(OxV+NZEoǔ$6+]͟BKNVVo@9uu6 &\i'!x8⎨x)gPlU#m=fj56S}a0͵ژ,}&Ns1LDD?ĝG')๼;_߫dI*!lv#i;W6r}<3c9DOn@v!oo2ds:Fhsj\7x.v+F fep)R\Ev5$n.ϩ*1ф5p@CdL^*/sP42K O9V;jʷjh J "ې ! &O^FGX#Vb9R+&cD)P4n kx.i@M :94wP>iu>ug>2K?MX}>Տzv=W/IͿ'lTkBi?ߩwj}'oPys 9¡X7&м:\bǥ 7rVѽC덟ƃ㹛EѝעH7a+ceP%%?yߘ&pn$0vBЖ g ]GAj2^&۟tC_z^iHz߷ sQ,;ww؈\.rOw樋=_͖"m)؇$OSo:y*q3||Y$^ &Nǖ\m2jo".6q0)+Cu]*/B,9=On 4{(!s,Ig&%X"iG9J{XCKV΋K5G Q?Yׇ`Lu;oxQD|tTit]`ꎌ 5Dio1+Dzbeh 9lqRs9ɹ>#˛ozZݬ5p_oR"NSuTxY1xw$T;D=1FEbO M`^sPaz0W-Ѓy)U`*s= ̔(On;@YضyY;,u\ku( (WAi3SGP:Rse10׶r}xf2~g2&=yiۼ g-3(OT3Xs|- "Gt RµUu!r_ÔQmrq-Cbݵ[q à՘񘝢Z.P g٭+^S 'ǚh;؁h#!\ ck@04ED oTt ?]kDK _ ^ pc OQc5ø4Lf}{QrDaK!㰱4ԢA 郀QĜ082o2Qk?(C×h- (5 1~(}w+xG'*'F]ՕMWB@ V5N")uͰp1Sזž'Q&!^(|rw Tç(N s4 pY %WnI[5c J%z9ktiv{|"ZFT8@׹$~02>|f\n~ƞS-_SٙS d)ؔLȞbAXd} (XU{ұSU+^P>^`*r1!ZbHsFc F@D*˞Tbi,|  r!e0Ğ6`?@" o2J82ݤ'6J4%VA"$郉to㩎opelڸƧy* 8(D`0. @8K%$U,8+Ċ2Cխ6Ɵ(n~(RS EBT%%C @EIއ)朻8) gӖqH eIV){RmlW3hhDy 7bO]B6th? Q8aʉ=wKKj!ߦHS& N~;c=CU!|Q%JDn(¶e\YFu8|iDO~xퟎNQ4[r(/ov /rYN١=$ T&^qunMQAlFI<0HAcRܡu'LdT!9 WR?0wj߳NK!Ah7$ [c B㔿o]f$>oQMxM-?S.+͹~;8wޏY gp‰S`ݜn+VHU&#Q/{f춹p!]wn;xFa o, aK:V1O)Qр'NUFjyj{nc !(E /O 2jrrk;At%&H(,꘣^T"/]Mr%o7I] }/nn^5?xǟku84_VI_z 4VJI7/7<jSs|䛡obi^60oI0AV\ql'] ;qt<̧Y _VCEB"j%Q9'pZiC#beNW7]Rw0FCka#ubp׻ų0B%u~욄-OЭ3Ze"TҤSLfaCB }P:aq>Ɔn79( vkہ?U,^*b אW{q&7[Wʃo|F ޔ\FY|\<|=4=C:~8|'3JN[OyiNn1'zdQDliz|P'OJ7nDI#/KS[=yt ^12P0YE'@4G}j/Ƕ@ɒnWv:M쨈'yy`:zfly}np++PHhʱMRҊ2KNR(k9}RodSjդc\&G? 9-0HgF1&gqdO2EdO:[&+k%eaK+.1Pp[+b*nK,E@I;g۴Wupxr ò%vjAf!`(<}?PA!xG4+V$6ጥo779ks! */6KzC cQ" vc ?]GTZc oqAa 56_AU>U7l+xb֩,>%xQ6},9㦊QȀ\(|R\zP`T sax8ƛb;ǧovXn{&P12 N^y Ɨ`1TJDĖDL8Iy[v˳r֒yBF,=QTqx|0:m o!x;Ϣ1m7)`l2S0T- mpfh: n M;C$m,ҎE鋨̵#C.e^P$>@GDbjUL )ϾUj?I.á)4N}Cw$"G?`$,ml9y:{ #b>ĪUG^Q1_ESBƑB "Ct3< 6=!!Ii;4 ixݱU@Ld(Lʭ0xm ZnE@!NNv)v͓'1I*zXͣFmCYJ?ذbU(FH=2*_ҨBЏjY!$He `Ev&,dFCHKC_}7Gi\d] *Mn+hC@!Fk iDg{?+P5įSnm$6vaGm2MK c3ɉBD3:DĨtʿ`2v/u Fۤ,"v{x=o_/,W,TiYnCzʿ{=[^irM hV[,I;EOqĶhB /+kRNl|l]rmG]¾N$%d[&c/MѢQI-l{8gDbWh}UUsc@stH֤*j$Pݺ_v6c-{wh;6N{vv [@'"xW2qnWVA|, Z6c^ވT4URI,~jl(;\}Yպ<¬|u:!LAg/Lou?x5_m2ãxSey aZr2[_{\6v3VxaNQr>`͠3cY.7+,cHFVmA9=9xwHUl|c79DaɜZK4p`(UZk~r.HT az9^T8J5Gmi7a;Lw}J%K2(Exa H3H^QzgU6ZHgоPÇ,I4D,3z?Bؤ̪}-T V$Pkv: '@]Fעcǔ H3%Ze#$U?eN [9\ђK,aG*`z.3δCu@D:Ew X>T$OBW*"Mt%b4k^C1 <ƕC4 Ї5+pױJ/C\BaF 2 9kYᯜHvhl]`oRh鼒O*Vxb#=*`Є *y{"gBp(d]bQuT*,co׌7LaGT^,q,xw ~bZu)8p%nۧݿ /r{y" :Nz%[g839+v¢IE~~;<©g#.9G(g\,6.ɞ:=n8be=m>{N͢AsmDn;"ʼ9!Fi(F7R9S Z-]nR/  ݹjϧn]>\ +2/WҼ颪l.J_L*ן拘e[n/8\ UAn bwfI$1hPBc7XFt@oǒEx;'fkH+JVWl9jo,)C7?RqI^ !+NBs|&%2 . D-Wwvw_nnÐpf2i!a X3 1qk:jil6%3Q~< I U 3݇k Jk8!4Dņo%\᪚SA6Lc:_V{s,jy(oJ+../Ns sB% ;;Ueo>3 ;.ڶN*~qw˽|@),"nNFGqaTj{Ng]@~^M˟xHC\|9y$#ʼ]F+G1m05? $яG%Z$4Vxv:36X|Eq󞻼i[*pT4h蛈L`x(J&Wj{ Agod#8@5(ܬPecpPԵp<6Gx–t$'9!z?-y}O~& ;nҿ3+fQI.aXf:x&YNɿeʕ94e}4x0d3Bփyn=lNV[j`^6[j`[h`d S-鑩V&k^cFFκVZ?X z">FL8dۭQbKU4: @+"mC}k)E_,'_WhJ;_ӊ滴o`V?p;}oT6 # /Xal4b"$*P/6sEȊ,`,!H7]qxOan< ,H/@x;[٤&`m˰}-7v}դ?@ZA-cgf ܆ Z_?׻E2;n"٘xѨLvCqQwiǻ'x1"BqBFelh 1Osxl^K"}QFD˘qa+KdLW.2]Ӝ5\ 6\$ C{}W[3ð? ,t%x1>"K=< zېr <8IWU<̗|G2FjQd1ʀXr\%3cr&Ll_oPB׿ɲ+ b0s}尶L-D_4K Wм y w~\͉xcnl?kT ;agc9Ƙg֕t0̊Kף`i| m;݉MŞ7 8к RQ!Et`tBj궅\X(>aCb [9 ӆ}lAF紩f_Wy.nC1e8aҳ,ˇ#!ށyi}xS8TbcqaBA}1xghjOZuu+2Dېas Dr s  .(jD!L,JZ-&ΒRFXdCť ,Z[,.fLx#WD~R]:gBm Mqewv2K8 nd/_ه8m>>Ni 1Sae&FHxſ;YO>f\BTOTOgƥi*.j>BE)Ĥ'% r5wEBmhorl%g>)޾_kz/ItO_2w ys֐L ozXP.׿ns\L1By:f:74dJ_NTLA% 7 ^ME,H9xkL!17չ]_N ` .'lߐ/x/0y!s6lRzu;{j׎oD#,K2RNfIߟ_زubll{9`䣔]pd琂φxѾŸǏ43|E*~K,*1 rʉu\EቆAVle!H4 ["SFEg' ) !M+ lfX?,SAf-}Ee)edz rF`!&wfQqHYDuŰ>d)Eee{``xU) (0p/;ޙaWVAAi'(7'JY kyd~ {e[h|ʁ|NCyC ai*O8 9UyHsT]C7.g.5NBq ~/b3扰- Xɰ<ʡ3> $h=lg'==rqjA\ÈHZ\-{ - F<XNCɷ߃>:/0‘I~mnfUm胘z_,:l D}2/÷Ё gU?(X b;K25TB?UG&KRۃN]VھWEK*ֺѬm՗LQ+Xfn 1#4}A Ȕ/+ p&{Lh߱+z\t^D*O穘<{zNƉ,v +Ki+uFVy 7HQyWf%(~i$WWXbX N t4 <:ABp:>TĭyVm$/{zZ<}hRhNWDνt*+*I$~rbVEȜ#\Q^'FB.&:%;x& f7GsP)؉'lmB󂩐|, c/]R1Ԍe(< =o[>? }v[Iє_Ls><3˥zT.A+\v^nq;-ͬ,ŪpFoķGr >j(9#Ĝ=OfK/IS_wAn̆O6~ݡ 6dS-?B.~?B[G/[?:MOsC^ v%jT__seO:zÇ=v˳';E]D|#;Hg'3cZw"V)3<!8=J"ׁ -ܸ3-uĖÆ, řʙQt` f9ġtB1`Da2[9~`sM8es',x&0\T*5Flҥ7'35x znLy6]Oj-dɋj u&qM$h0ZPa$opґ120Q"tFgM0#GMbws!Mr4(% r~XT$A T6zbdd,sr%‘} lǓݣ7FRC"Sݜņ]Y,+HQ++R?ܶR,+*EMRNN1m ,~W ;.>{C%~"@ɧJL)d[٩q9k5sv\#t,kayWqv`GeC%쥘/^ 5 ʊ3xCxaKzQ7/R2QY|S^Gmqi$I,D&K1G̪Q+*{td偠@C+;7 :|CdzSQq ջ$'$*+4;9hT퓪}>wQA1_3ۺeU?g** WMp:Q؁Q($@塃|m yES9@Û\~L֝7$hC?ſk6ޖ`h;M&nGh cfB2i2)cБfTj+9|^hD;\(ҳZ(zmE߱ԩx/8ɭ_sLJ_{@/hw ynxgxmef/ϋ6e2JZƷi뢆S+9=J9*t;yڰ*JA_|)kiQG~lE%HMkp.aKE/UB=dμUk̄Zc(Y"qgcnk>ӢiH\ܜV~4ϥqh[TǮle0VWq?jBxjVXy#ˬ<7B;X9Πe'a ЕFir݄ԛPc$kє +L]'S HJTo0,&g b)-9 ^&VC3(wtn{̑44ewh0h |A٤̾n|q Nql!wW2(=_It(-,"}\c`Ma %2l㩈&5z*(;iyZtW0hRp~l7ȫg9jsI~Σg`\b">dA ʃEZb:XsR_z"Qd{i|!jw켎7̹7KprH"C ?2խJX(FalahIØ"͵P^oDjz4ӏS!?J@x1aPO@?a \+} \h*)Пj 'L)p5n \M54f%q9_MIW mոp5t3[iig]J$ ,AKX$Cz/*#34Ja" hӲıKH2;^B 6Z?rYD#.+=waw)O+PDblk * S(Dm##ri5'u5Ͱ>m` X!J4 -N - cDC؏$!/:npi3[4B(?ItrCqS H`q̌FFq!} ‘(vn? N% HSNG-0>@1}"xډMF%B.7nʗRy!m& CC^EF"TVB#4y5$tb4-4zV^ġ8/Oe+ =;wy CN}x% ,23PĔC b%$VQS QhS@˚!6NI~XEHy3)='v^벡Р0ǒO7Y4"N-*x& 3g"XhmYxjQv@_Nd;@}su:&!Zz'JRk/:,n2 0cFD}wpTZ]\0+ᱳlu{:"4-o[Gyvz#gKIQz/ItO[|J\XJ x2mZc_?ӵ ] o[ ѵ o\0hn|_h<|{rvY󲜕a6(0F&N&k"gK>a.|2+f葹$:']o"'c=8Sy-,g}to)ƅ糆npZU{rSMMLm9dmGwh]_f$m=::<;U$hb&x[<-0ZԆݣt6ěƓFlegOD _\俪YI,ټ̷ilO̷ۜ9{6'os2d͹|6(mN6ao$UC1T7jZgg)-32κ 2 4p;Xy0@$SAP"wjP |o* DXvH&9A^@d>|(0@ _O2پ}e̲fc_Wfz{!Oz;};ySITr}/ ^pxؐQOSAI)TavRe[@~'#0NHK~yєv@_ؾUo]G/P'j}n]7}U$Y֬f1}{}]vѵnˇC B(ꃨ?&w mbPbXVKDXt$[",r/ܵO1zn)hC4T1e \qp( 7GeIŌT4Bt?-\竉;%CE@nY%+H\Sҕ+"+=URO!pV٤2k۾9 `BiPZޑ#!-UP;3#B77="uLOXB#Hm>hmnOK;lH5wNnlJ㜅"i|NMrd/-ښk4BTShoMgNcQy~;B1*_OY#jjR1*Xw|f\olVi?fzs1O+]Z_sXC_. ]~/0 \)_pS{rkK`w-m}a-=f_ds:}?GrQyeuu=Ty _\b71z_ %7심0{+`jҒz<E>_T;ՠv6ϊCI#G[=ҡ֣C͇\wl>5oxeie9K-uZ, z6\ebG\e=`u ߄0Q`o٣JYj`yPd56tkXΏId: \6{d^Ҩ!UVpppV 'qy޲;vVt/fI0VH;@]o% )L=<8 ӌj߅>"1"":"lQ$S%Qd}f7՚\ȓ.邟.cc+8Ow!OSw5I<3TnTSOxfE'`*ROg5hO-I?u?]t9Kt9(C?BC}5jcS7 A c>|.^/R|nι:̺7/}#}ћP,Ʃ)qV#q5HcFo_yߌa(h9i%_."&>Tڪ>#,eʲ ݱP:."M.'wKkURv (Jz^e63('}<8[j9,I?? ?j/]RO=*-tSOsVRBGj wC$zuEFa]?PX ~ ~)7%-Sy|&Y7)_3˵]31XzTt PJ"."ED|!4Z5+:$u,3j^ȕ7[NmeoόnC[0%za3x ׻v!Tʖ膿!l<jPn `9[u&~G3looOO13*vrYQOhHɔƞ '"߂Sp'G/wOLpWgz|Ԍ">a2^r.e+6Mϓ7;TnG|ŭxPD v4lPOe&29$/ 7`Kkqvad]|!ort63'nuj*<RDm&f8B4'ɃAajP4(lťz@%[諮Nu&A›/R'ӉQ$~7F9}}(::96qo[8綨ѻM_lSNMΜ|>}n.q!;g>]iڬ񚗧vз\gSZ蒢`… CŮl7h x]9EGmj^􇓁1Cè9P9*YD/ޟ1|`9L̓U㶽\Y.Y}A7GSHt)'Ãd 5Zcl9 ~z1PC0X @?2wrX+?yQ|nƱsZ_ wӴaqa.aU2ppri"rZ9:=~9sjB` jُdfAz/=ḥGadÍ ͧ.SWjr7m89y7fo۹ĆI;el goGSM)_74?&d02Ð+@/ُ-,ӲЬK%ך=HƁ]19xc WVmqr@6MU.+Ly@DJfbTG]Ͻ@` xHoxHa'O IC0'L_ ڒ3Eֈ̈YOrC "iR+mlZ3_5ClBv[1LDr?KA JwJI IpuA*7IXY|;<牁 ǐB CŶ{Eӓק=:J1DvnexNG`LN_M[.0 NdW%總:w͖ogPSSn=>9:mk Ƿ/N1(' GY`9i"[# z(n(mCD=ɷY&s9X9A}.m$Gbs&LmIP1q<!: f \45C AZP_cdL~~crjA< 6jOI zUSDb OOooE6?L9;pm)tq]r Cse(CP!t N&d"FG()+zb⡱R=@~pV,m/wdk% ɣ*s-_y~In<=A=4~A1oز\LjL?J3l,70[:M:O$/sq:A+:NBp;@u03Z%hZjdPϻ;PXΣBO#otU09_l^C{,6Y 50jUyjU44i<+6q$&ߧ9Ti-л(3bge_¹LJℭiZ|fuKIBEa@ra$gԜ̩2Q׿0+L_cvөO"U 48HmRہZl˸}i;Wfh;!iuEFzOjF6 jtɚzi0afH$ +_w_XQ-IXiS6vdAYí6)9r0-bT Ƥۘtncmk>ap&oH,78p`]FS"oFYCRsJsJ=uep/PNnTPj8 7,k%Xv%ػHADRĠĠ>ƉAf^QypI!n j{YD FfghR3eYM4Awq\G> 0nC~Yp>b8moed^g_[ t'ڐ 30$=I^SߟSfn4>HLtj TFD!W6MGoЇ.}î)* bҲv'loFMuG.DczȕU!9_ >8-Vts}HQz]}=#@g$ S#䏂)L!_@$9sAwTu^&!O={V }XoՓp_&SfxZ|'EsphRG\ܙϥębрeQ9sjF}sկ-ǝ0uԨ ?>6 &'ŷr0Ḱ;;@}w19Oy>r8|,J4mvY4h_ ]hx-!/{]pL.sw[Iՙ[^Q0YTs7C͈3?l~v[?{Fb&37UA5 yꗖ1@zm:HS[" ml#6rו3(E\HXЍi#ZΏ"ig2!N=3ttO"qP7FhZ4iTbL#TLC-X\W:qt7g3XSMd&~z]8d;_eb`>a'G\LytF0?ϸ.yM9F6c7~'?ՇmBӧf`ħ7 FXë{tֿT;hwzX venHe_Dϰavt04hW Xx}hg>dfv Cbc-^^KF <3\r?tZYhΡ_aO)(3#T,=Ĉ>J{:|$TOs o#L۽)ΜZ׽!=Zv|eV=iN^-whA}4$:X`F u̸z< CuH\܎Ea̤JRb5)=JY|.^~'0`̋fBl2Zփ1h0 |G<X V 1͘a$ػ#z$ӟ~ZLE[ 375mӎgmd{n14j<o*[j,2U } kM c4:\ ,kfo97onnn5wZj.I2[)3R D;d+I6洦smU}C.ļ4 3~d }\s si4E4юkoi3YTȚv D?;h @,vӛ%i|Z'KwmhBEF+Q& کSiNJ;TTe~~7ίSSR^/H;VoU&=2sI2MuIMaޔȋ͙赙P+o/7O#l+=;?82v.hUR&R+Zx80u7Cr8cFDŽDk+M{{uޭ-j"^|+_>jȑoPbԻo&9TLun \xSåbe%/~.U܇GWJaDލC/]TQ+*?@'U ! Ѡ{Bx]ܿ Er7N$640JL|*ԬkW $&.fAlcdBJ i7e+Aa[gt y+-?>}wlFz3Q^ԽKOgK2ͱd1l#&E[V=C*+sTy[Gi h %J)7rT^_9#]ht*[y8X\]%A]ltcRS GaNFtR:F2 u|1:L[DJ $*+*j3@ȬՐY^Io͙Tcc=b\8cќI U+UuPwhUoJP/)ơX&Wcy4h=(CAW`qո Ju.75ceDQAnAeb\(ʄwȆِZ0Qn)Z}wzQnկ~ x&K(W|<.U}Gjܣ%,194/C#Ѧc⌟@m~,p=)0%%*h1N5GwEB_N z#Br(}lM0d=zА7'A~q8a nj8]'Ͼ}t ̩bhQA ʫ1f[%ś7ޥX@!f{pM8l'*[yu~%6ܷjSKh1Ohe$[%ELc =%*ܶB˒Ow#Uء[˭̫USkhGΟ Nfr>ϳbYUꙜD]XW6;j+bk6ϟĻTaUϣbKtT2N^MԺWҺWк'"z~L-^ʫD3(jݳF͢ dm=dVWGj8RSJ.N91QiSk1=cMTƴTxW-weݷ1 @lLRau:RԢEkRh#T6TcHB% :9`!ޡ;fYPݱ-?T(KMӹLtâz7Km6˷SܾӹL;$=Jm&=J-ARQ26*T)#BEFB}5X^Óu8|VmfM͠!Z2cN|&ڕڕ5Ү U2YYe`0|m 4kYJ#=;_f9SOVмrrY$:\ T! H[sh.mp~~lo x9ǫ՝6AKPAhKbx>{HM ~_a,`ٷYŦ:íڟT61K[“_ fAj$m5Z ˩)JQ!+ a o0oϏmFΎFStџW Mi-_TY%e3 L\[E:~GQy"0\3֭X eVΡUQ"jx!w?gΓRtrij7]V9 '(2 7XwC49s!6 !sO:WvCU'o|k5?(-7,O^}Mr"Xg-#6211!Ǧ,"Xt㕸ł\*?D>e~&廲Ll5fڦ,Y+K9?Y ,ou6>C$}~EnwtgccjU 8N}x>q;;İVIu_IPZmXˑH~jWIb^b&\F%yҕտqsTsi L)q_]UcM(r5',r.l·| X9XX: ^K!Jҩ\FɳC=!6Bf}o]B*>L>g=j'֎==I&%$*=qLFm$IXu &j\-R9WG益 IMUP&Qc葾㎏A033!>ÆZp'ؒ~k3qtA7~6Qjm@+™I,hkL@$CjO%X3Ѧh҃nE b4:X\ CEc ÂPw nBqئr6,#@̤ m89F,icb04߹N$k)i{{ k\!Aތ龦}Wb(p \FmB$aN:v`KGQQXčդ `ɖQ˖{{rȩ2#Rh1ʽi' H.rnH-$ZH9d+:DĿ:(O[D+TwˍfyTO;|ѯ37`Ҟ,㴡".Ivp*F.yBJVx,d]|afФkڥGJaeɘ#7QĖc-o9ߩ5:&$|Z:Sև>}ow~GE1мLуx)ߵa/ʳ cDD0"cͺsͰ5&1MĪCVeIwC˼ۦL> ymŖ2)9IJe,JP_Z>J{]Q![yQuEȼѐ;A_/ö:N^N^ʜ`4Gn# цXms9p2\hm޷9 ڼ)Ez{06oa}1]yK3hsA"lSDLIēneh~:DM}c aҙul  a7?31Rrx3]3ld=3fڴC-uF}_dզ˗1I&Gov~И6d6Wl3mmMB',܋&QO(wk6AcMb敧-pruA[]F#\lPYVS&C(œά6=^8wj٪,Mi>=r$PLl)g||Wf{OKF׿[/6"SyՐĺͤORtps֧:և%}:6ۜ.9M8nq&-rs\p!| ~6Юvռ|E0 U׽F='NjKP{<ag63Zj(d\Ӣ?عΪm5Q}kB7{ f)VH;CWhGbj.Y?-NG y{$=z$tZv05$U nxazɖk1+nG9MjU PIGt!b40򁰵RSmsnvRI?3j2sOt. Yݞ雚b F*gmd1j=fT\vx=+[L<ЍkDB_r[$X$v61Ҩ_`~+WYW1%#CTLCdVAĉ 4)ٌrMY!88fp2:H"x.3QЏs"63FEqcJg)J&NiM``uļfsFJg*utҪΣuF Yxi+5Vn٨kQg${ [=du}8n^6Ka'0;xI޼ZWsb>%vpȠ"8ТvO} >Ҧ٪* A![V`I.Jݷ%ހhI8[ mFM(];:aXw3gh{>C?6q*MK \wA4pInW#?Wl`5;xtMk^5ll =MbN۫ѽaKOt,jnA}}gT\妗Īm.ù!5"-Ԉol¤#OYVoQ`0[ W`oԃكf/[`F|_`G6|7XؚA7֔@]fB-4,!H N2W6vr:,IbN ^gU-(:y{x co0Ẃe|u+FOi hM~S 2l&07WRMx{&j<L<SXex|f- ybt|)ؒR\.KrpH+vX[L->i $A冩0Yfd8 &,] y(]d| @~)!2s̛Z)J dS?g&/VH']_p:? d~k#A2߰$#Eѣ>F*қ&L^.s3Z|J?,Yq &X}6UMCH\':e9deO_7unu&">*^ rl !ѱdcA1!YAKB:?* >c-:6U]k_ |}*ce!,~[4 l$FRv aRE²kLe"=YUߪC`wT m8O5. ay(Cf"Peg@OzAF3Dm^E(] ^cw /'Lv.(PPnuA .\FRONu znIMot1Ydn\ i)#ɪe7v(" /a)DxMa/ 65bv&B7 ;%/Y,_n3p%+0|Z(BT]Q"؜-"ܲ^, CBSQH)_Z_jVpÂ42Q 9M:QQ~NTCzd-OfvaΝ+;m|FfT]}7RC~ Pnyp^{p_`/KXJ\F\ih%7_֙9 Z c$]"%x'Lwp}taᏭ+<='\.W zfÚ}Ϻ,Q^ IVK!yOG 'Y]GWBE@dN C0pJ%oZ4Eo0TIaucabZx$trgJl]c@nh 6Z|qz$9 H5{6  ImC;M`Ç.Rw2rAI Ӳ-haWw ^.(eҥcT3_EZҚA0Q`!N*'h"z|õIJ"`L@Quh5@u 7@,UhlO y?s`sq#!z_4i/ޑ:Q|8y[_!jQBO'8Al_5fAP7ʅNZ65)E|K$/`-%?祌NZi k٧JmZl?7 I9B %d՚ x\8k8OI'5COMLz|&qe22(G \R~q;|"^[,UQvӐz+ 4v/q {/&eV| &м³l]Ǻ?j_]A/ʤj)[2 ҄ ~Ԍ* T"z-é9xHYF{}Vq˲W!cʛT$q\g'| 6≼BESXr|P'guv@Y^<1҂C&'p"<<+L'`EF=$,o??ȩrՊUrўs+zCı洁T1ѝ}_]H9Z«4p/?^&Nǥ3+V//>,Km0/ !3+vo7tg0Yrܻ1a7ʕ!o5g jO'IuHs=֙ب?(qj\c7 0/(/e778Mmt;=9x6-{[?o%5 K_"ꄍU.Jƫj֙upIpH}4Jk6/]~77;[Fl/whE$`W . oZ|3/I1& XhH±ɰ|%fOYs#0?au & 5 %-vQ=D66{ CV 3>>˯D,boǰ0^.:@^C-|E1<ԇ\E}.ӂW}m> $(@J.tIbˋK{K~&h,)"LJʡWX ^auP}''Hl7|E&*OF+|VYqlx2:8d-~p2~{yڶBNՅ]q䄇ė)vKxcQTYTYIJ2UVnG* !zxc(N50gqdv'$mUXVst܆υ<_-.Eʎū/^Qe~幻 i=x xƟϏ?7jw班ׯϭ߶McK:zLv9HCNo5x?~v^]o~㵭{y4pke_wNkr" Hb +ՌUosˡXBț_aR0 tE+hjaSj+>i~+QZE2* qk`g'#pr-3_oNLŲX>lV l^r}jbBE%hY׌-]SkJcL31NX |ulvcL6p̅f 9XںRBI֭PRB[^j av܉˼a^5aŅ` NA cɫĽRvS'2cOy^"˗xb)=SkTàbUNzʹxͶvf骁NgMrߦnYaeKo^؟ncdc.ë:axU_⁔j\7kL~ZE9I&,䩜.iei^{ň{B6GRP\-pɡmmvRT0_Vؿ K OZmEQoTן?0wknwZo.ǃY}}._zܻzS?\_x].?z>iϯ~ٻywZwyzo=:;>z3u v]^r'=ZymUo~ms;ZlWC\/I\jz]AǷr3&NnU*ZͬWJҬ*vUv.7kvՄB3ݨL晹0Zn4kgkfb6,WZ|u{\ZJ{fWnjjh5#:r#\?nQx;<̿ng.;,r5F5Z3n6w3c߬PFq!tř]A^ Ӄاpz9`P 0( L 0= d  Y5Ӽ`mm| 1T}b/o&/0CG}@EwhAW^-u%ĵu|f~/Xdl~׶o5R=s7o+ɓgkW P!X&=6.^ޠԮ7 [32H;&+30/~?l Z[#bog~kMH{hJBB`bH cjtqmY)B bc)!8IsrȖ,z~}mL5,Νw>7nSWʟ; HZ!ޯw HV[ϵ ~ԧn~|Ŗ5aƅ5w@%`? sozRײ׎{MEve7/<t+Ԑ',ڮZr'#lYZ%wX:$[oB v`8B]m_t+ꝰwe{̉hNc%#x,Y 룴nl̺MBȥ.)tNq]`sZR}Oi+{G$Va?:5 yƍ?q?jt=R`kBOqi!ϸho<>CQ6?Gj >p0ie1PBV5W=ި7*#@~V6`+^4zf(׻v!Y-h~=Kv* ݹ'G/wOdѻ} (px8nz77Ȁbݳliz M0)z n-aGKJS/DTu"V[D5*"(u^$U.eMpxHÈyD(X~A{0(d[")Ɵ"aޅn1zjg1g㿐gw6-]^rf xڭ꘠1*߬?3㥟TsjnCx+䇝~{β:j;'; X LAd/z}}]z'W=>-BR+heB^OarS#Ҿyoٝ'Rp9qϟ&UNan] |-є8 Dr9[\m^XvƤI7`UVBM9gT^>Y%<<5pYK;sI^_^kBi⿛-<`* dA N> PyKv[ttsLvX[$ԓo-||-gBi8N=/ 4)[E>e /]w)[S gMkuz/ sEc70)0Bl2og^ς" Y|$+kIB}x  \*a\=8^;n\|l&k=V/.le;KOCT*k5[m Qc-R>"&#nf-|][Ny,pR+> @:f@C#8IN19w%j=g{"GcO;Ag'"#3Ўz+(RnmkM1+kWzUʁ:HQ7 `Bldz}4q= ؍F4p`}@MÀ2 6K;zq {/ױ 'B׾(4,exXÆ >I}ѩ7#4 MZFo#C%!(f7 $~bn(dew\a wXidW6"VDǒ?[_EbKDP ,|Py}gty162%_8Q6l9^*/Ht2i-%T/^e -qc__`]_wU<3ٺk?>(,d%BNzIM#8 0}4sk힃hD>UzYE%ulCdK|P<*{'ŧ}{km§F q=Wv-' p8p .Z 2?qYp]ŧW(Gчhp E)]]0>ܩ"۽r^-h S3Н.lgA&Y*lvC{n ܔM]r=VPm󮝃cX1q} V(D$f*yKZ3/yo&>T_}{Kw0@f9.# XI\ AupPmx ]2g\{iɡ-ʼ'{/~SSv'd7Aő)X};37Rhe3>ߑ_XW6;Ann;9*ƚ T }M|8 rGoW(>B t"28Ӌo=pQ:Np9;)w\ =qʱd)1#w 8HlNз\-z틗^`2PfpQL.*zd + @ۗ"9-|]8.U0~"i4lzn5 [}*] t\~ ((2o>*aM,d $0owE2j"ݰMT:@T B ^`4%Oj$x7J!08uH!3|+sM qYp(3 "nqf ;{oHx^ vi3,PlK(&S*0hvHJto؍7 OǩRY{'dJ7V_76v `k] xmֿrp0toM IR:/#hPz3c Ǔp^-%6>x]uyrH򨆨vW@Y稚vC 930֠5 q.-0G W$9$&[$e9FNEfxBrrY%H)fLA7@ռ޷h73NW^N/; ̣i__Ct3v~`{!euLԫ!_N/.Cav[j9϶.rܬb]C~I P!Tcv|dV(HҪekžm MI%;gmL׶:)NҕWR',=`ٟ/;(9ТҬd1@æz`_9%Ӡ*b- 4uX]B4 g?G%K9o̍m=y{8,s >bGt7g+fI[ m;!݉Mh2)oR Z% "m:kiKT{VnnvnF 5=<0j7If _WkܚCr)ICܵoKϲ,o~tB%' яcnCwiHꭢVjh#Ub۷Df|x$DϏS82aX= Qd :nx$ذ fFcDvoQ謈yWfGZxg)[L!Hԉ@ji3S|Jx=|Z) F"0|#G/vIcڐhU,BJfy=*_~DM{Y#qwA E]!(MA{@)"!֢nf/_هM)U㬁U=h48£wxH0Hb)tf7-!we~C" qY}nu!Z_g˽d9 Y},z-$ҵr-84~e5zsыb Oc9}`bi.&lbB%Y1$Y=V QklXkɹuVt0X4Fqc{I )\E/i-/ST-˨p Kز(!/ሎf[BG(_&"YRL@:9{Zr WEj$\^lFnY!y!cUfcSWh/;ޙQ(zIJ<2XQ?Y___` KdqŁ|̡CƓ2-t"֤S\|Ud|52HN%,~.S4p__8 pf$6qףG~(x@g|Y58EFxMGG'NMf5؅ǕՂ#`0*#="F\BIqDs,V%D"z+H /n1ļXxhpwsʡ4bDi>0V>w5 DNLrF&N@GZ,:l =Bc8ЀlVF",oaj{U+ Y[zݱ)QC%(`G+U\tRHC7pڿ@6q7K L&&7r C_̧ ۅux!07 ls:Pݣf܍EC _ԃ"RyNHWir'Rڡ<4i!P IJY˗CK4P֥8)G`H_VJu;%4P&;yꑕ.'6y%@!oE[(3}/5"%wɋWONE34-&GbkG_ f`D+ RH~Z!'Q 4}Cb{js | X/va]Y*v >e;&Jzg,Vʩ*eUN-8`d(MKm Y<+Y`\zL@ {T5<}hF g3 Rh 4y±ߏnB"|\xIbVGxCD[^1r}e CTM9# G1laqPbH6Vu!Z8Ej"%a3 ~n7x N9I#M}ՆCR(4fro$FOm0\pUR'jQ5.  Q-69؄TsG(z=da]f4CVL[ A! d,;vp}wy^Y=5|W_ ">TKnɐB壐nЁ'1oFJ?P(f5wBI28BfY]q]8K&+k aPIba4bX /d&lLq]chjLA(nJ<+_̖ D [nP(h#JZ-m>4 ]gm"w[Rbió0B#H91mX5JYӆ>6GpE{mdJYm>L9>/z>O.I#ur_EK ycgвۭ?4S3ׅ<ǟ;1\5t_3]TH%@̓_L4d"Qxk )^vwc,rHtlu+{E6#f#w[͏?i7O1FZF̒XPK@ׄbFa<0CeǯW+?\,=d5PΌЮbEvΈdB-cr{Mk,Sv^aD,qRi4ڋ6̒AAțt*#! LB)ׄ6pDJH |*LF7/v l$I=FWd ɞcZ±4wҨ:CFefgFY)n?W-X"طذ;{y{HjHrsd.ePH*Um+ŲR3F] p}8ˢ(> |govM{(T {v*Bq3w:Ñ\0C(3jVZa& +1I 6C-F}m遵^O|hT#}3d3&n14 ! '8j ,npBRzOܣp& EqvDoC%3"9XX 9y2:sk$G՜9=ȜT:%Q(٣G)'!*zKZr{HA6jŜxS1Łs|9Zӵ꫗6dd j4"q㑮ckh1.cYQҪf a"HnS?$ De[W|&h_}VNxTjOU8+)c:fkxL??w=hT߅<_v:&jcX34 H*m|@/RB1.0:!eK0Y6IE\'wd+G\;d{[Noޕ5OQ︮ GNG) *H*eY*3u~ВhֳZ(z ,%,u9 s;Ĺ St6]`hwMЛ z'hS&NFrmZ뢆S+9=9*t;y[R+JA_\&kIQG~lE[^Qy.a˃<$?FlqG`_UY]KE<Ӭ3F~Nt;,LgAˍJ49z%f5e>/bGa;7E胄x paOwUSy9PQcX՗nEZR2y/ɼ[XҾ797/4s8_5ge꽌-g@hnOBqo>ƿw9f!C:xƍݿ7?-4^`CF/7xM0A+sp1+k2gpO0W_/ISll)?#]I^^JM7fҥtC:`.*YՅ9Xs♖co(W9'S?5_rEm\p}ug[OoS')O[bn'RAf Zz')OuNw?{_O2D‚/pny]qoߊYI?)ȐZ=|&.πi ]{.H(;o*Y/WSgzz sO;>}s{|rrvT2Jl)4 gddumxSM&e誑P,MUw:P-]ؚXvL1ߌ(֜v1 1Кuj >^E 0Z}+:V Lr+Q#٪abD"y>8xh[尢!) MǏuėJ_D<\ we-4L>S ✻^N[f*m,7L=1b}I%JѤ5G47WlR$Qk='IY6+kaF;Ez\$5Jlu{RDB XγKrQd(垃ٵ:Ujow%L߾_Biǿ㿈g`лu 5AS!^ d,6JHӱ_ulޏζk_k9r٨ܟ-u6/Rx~Ǻtbʘ >j=z$#aCECx?-K7)7tY!˾g3~l:>d7M ҺG ]"$^d5`52oj=Bz`0_K''S3aL2P+7"d5ȕ!1S|V Ψbd N,9~OMD\__s?Fox'EYjR'IfĸS?7Ro_0w DDc Z0֔ a]c̿'٨ Fzs!OSo|Sd?q%@]^ .Mo[eh ϯ/p-  ?nBX:m@%`j[n$3H bKHR)kd2M%id. W޲ߛ00?-9ɲ(wl`;˻ח{L־{aE7\.xa_jQw| Y$qs Gh<7=dr+]7Y{hʺ% . Dә-xX{GdJmdO>|iz.}v[샑pY_WvLg# IU2rZ,yWOoq5ewy!}Ԝ%dCU@t,ߥRtSgIT#~FH*o fSܚGA|.Pr?i0g~E۰ w\lj"ͣ$Q h/ހG)\-wr~o)3t"!Jz,gYӄ3B򿄰=/޸t;-mיּÉEK$]-m^ kҦ,+BEtMPIukΈ{zN_Ӄユ7ڭu^yzx8.}Pkmw-a^_>~]P? Kg>z$I#6t;ˮ٨7o K򌧷Y!i swVʉ^$^'KSub\'VNPT/Q ||,B0r-#4q2B)&|-r|,蕊\ I҅OYIR`r@ h+6,^mr VY( O/'[nǦΚG\%(('';n)Yl,l:{mcyGgov?q$X;kj~hfCSض~o<4ʷqJ3?\XǺ%:>|}=Jq~RhwJ<ʻn֥ Yu*>4^;}m@3|z)__\N# B{6%x{tT 5Ȁ#?bd`j+/}oل12~7HYj7 C:];bt9H;(N!kTV:Z6#਎E$"g@,leZӽ*s n??Y.Bh 'ERHc8NSМZ2))% K2Ke4w!Z?ӳ}(} 0hV*<^MJǪX gؾF0dwkrl42"GSp 8NO>mE:n~a̒)1 DE0E*ԙR +O&qchE`̎ÑmL5xk~{7g5â b`$!ܙ̟9Wx!.Me >4״1}i4?0O@OԾ(TV7^L~]y#!%)αr,g~e.i+o%[ʥE~ewgPC\qZ]=SJ(a>9LmgydSJlCGP-iTA, P#ʭS}GQx3J a# ;fIeebZU73ZaATˢ&U5h^b1#/"`0M^HLObH"9dfH填d;) noK*>6DHL@EDaFe/2ԇBXg'w3麧0]!2 E8(B'>L\H y'˰>Cj\Õ5Ljwd$Sޑe蚮T '5rowVh|6Çsvqp}>9To)U/ވƁxw]7Jn3~~H]U1^Nߵ$wЯW>}~|to_ӣj~þym|h;m(=IIu~:7n5HhtȎlIF]5>GҔX#A}a|$(EHuLJ$/ "^VbBؐV[<6 _$¦;M! +s"G&Ic$.0sK#$'6#cdȳPҨgz^$+?6MDU UK $6r,+ad&b n A[Py-i8ߒN]\)?O4}@6D 2҇IAÄ8 g}D0Q2eƃ~I"f P)(0 ,ߞ:AAlSWԪ*7eU]yOnb)WwunyOF]!Sӕ#˺5U]NYjȒ^D*4Jl{euWMk(i0RƁhfQDirJ53"@6ʙ*37 AdxqT&j&^àke am`6 ē7p=Ku"7{+ro?{Jn're;so͝?7~:zlw?.|/?dQ_!C+j_}D~{#!Ce1M?tL]?T-FKo7%ҷh'0ɑ9n՞Ucޔq8)<6o\Tlp}C UrLKY-pyrY#"asQEEa/(/HOg织g'/V,p&{E|- iSx}2yk"$QDTi*Q>K -O٣O>6 CUiEn -Nݧ[Ke* ?^x e.gLD:Bv_dzV y*:|w # Xq-aQKeQ̈́L_Qr- 64O^^@lFApѪ[oSK}pwV{{rlF-x7 @3y%ŏ#!Hy~:j(C;Zt6Ìҙ 5bykἑ QUPL% Ioݓ)&ކhM 6w. %X_,K әog :|x/zWپf.IǽU웮ktM2)hd64z*9~ mbn>RO<؀=ɘdYE0,=Y#nae!>"5*UvAᣤ0qMc'֐R*2J#ʠ(Ɋcaz bA'8xz$Z^` P[5 t{{5f&6/U;Єұ~{\0hƣcA;GWYMǖbb!ض{У¼`^&"``Noyjb}x~'~r-n䃣6~d{<['Tx H @tB ؈E\0_"Q .K_$c?s?=! #\SŎ _۞C Ƨ MႱLnONP@,Vt#t3@D ɩP9vm5 BV[cw,qTH\ kzJn]gubXAC g ??5dJ1Nd=?Pz߳_ŹB9Zq 5XVtb8[љ Cn6mPynG%Vsw1VʧL-JM\?俞*__^+4^0Gg^h~dU čE1gys\?*TQX]^ _ʹfہ^dW.n_Uh-?aw, 7YnǬ[֔1"xI|Iuz<Mg#_kU >lERR_[̯TV)k+y4k=߈HGcΈ@CKL*:iIn$$ߋ2܌ȟٌ f8xWI0d0h+h:cvO`&ޕmA(eW,œү{]˲-Gtnz[pcnqG.?Eƛ0k0oh?w!SǂzC?Y,jHyOk~668:LqvOV]~ <O`w;%WXR)v9.%UlDI%TrG$Rq*ˮñ8:Ŗ^w; nn~tQspcͨڌE.VKwutMW^QWԎ]1 W˰G B]\`=zAw$~NcB]݃kDMX hlnɑ X&Y򿤂 .Pp:95Ru Eh+#k+tmŝ"!8nQ?x#iHc{9"4GNHp,I<s5J:ݞzry&l!NOx:>Hx8<v8|#Z1,j(Z o~Z(kdNsЎ}l|.3G$[%}iY#&|Ϫ5tb>05cG5Ëh|ОaX/t !.+ˡ1ngyMɏ֔q m6^S QM|M)L)0*6yF b~NR}Xqo5p𦔲0[kSn3kZō}Jn9YJ9ݩ=6׻| *$>@0{,oE+᱌DZ@?/ !K&@֗A9Hjq6Zi1KE4X >?H=LvyԋjLfAHgs] !Q lg#wɫxo7nW^o@%/̀xs0FQ A 槰ytk]b -/A:io z z<M4kt@vv{< <61_/'_IMDŽ2QFd l7}1hLx_d ߃$?/{%G6)_ a# 迠'FrD@; @A0x!?K'_TM &,Aq%8m6_ߗv4_큠(OT鎃p_cG\#Ir_d bHa>n7nu/[m מó_3QJyy 3M<ŽDCSV!qH"u4!w׼8uDBA$'?M<('?uGr> ]쇎'5OOGYG$Rea9 ?8$~p)G\]e*4gh戞`-spw\LASEʧd2Ml=)G+uRT550m@3c(4ο'/O[8!9*g$LF4C=hL<`7oNs˽ݰ׭ܕkk777ѝɒDnD/NE]G_r5j/Mm3([@Ҙxy|q'D i AG֔:C%*2ҿR+9-Rnvszm >VF#ȸO%ZRJP)*IK12!y{yuRYW_N#,7 jyZ3ppm7ח2L> %\]q,.q04+mpa5JzI"+;:.w |1,?'&'4c%,p#kyv^3og>^)O//# AJ9`/ DO柋cJRAQF 򽽖e$# _I)jIH1{N4fj 7f}EױHExa!Ќ^^+L88{@.toKO& J/m E%& +9awhZHA?ϐ*9FJA9itąr/$IOcLSn1Ύ ,kb(Z xb3I-LS /?:@~qQ,@Fi%qH!cS/,?Ʒ(`!HL:ixazPp@ʨ4'?%jJ7V#Zi\N- `BIzmwRn-q۟F-yo|p~>~*ΧI pd\Dhۀc5ZQ? 94QDyM?p8vػtq3o_D7 /O"ęvwǿRUT_awVܞIC59XdV*WV7fm~fܛ1{̤+Ѱ G%;E 4sYD SO0[FמrROɇT$h%ӒjVB(ixpvnh2.bQH2H-/{{=#ha뱪,nIX]c'vy:0b(̞>{_rM),z96A?M&p00PLO@I˻: ]\bsc4y?FR%gUOlſȳ:Ooaw&( 4Wm>ΞAfLp٫rٶb02-ZA `KhzmyR mU7Rk/j}Tnn){Unc~spyl.G:F7H <@9|mum}jgFkwxۆmpgN ($5I-<_A =˾Yn6(% W7q>K̲ͥX $dfql:N>l%LA-KhM6MF3G fnci@vaO,~@{^3:-۟4۲(3#gYӌC6+rR ̉ўϐ]C` n2,@ N*}qo @7Ltlم'OMyfЊ wTH g?Ck'/c$ɰV'3'uXYvT0mca! dQ&v̐iegB" N3os$3̰qľAaЮ=0vp̊KS|WLT81b|tx! ـu@!&4f.r2EiˌSJbuzv>fqYƭigP%yE^? mPi] ha!ODr<BWxB;'rѠ\!5&J!db@^t$lŖS @;=(+7ՎѤt @dpg1{̌w/jp,01`™警^qYH<Œ|ʐFA0A9<2Lsѳ]}vmYG2YJBdd܄IA~1TlEԀ#`fQq8`6$omߦӋ\ZWhq%9Ƴp.ҹM=@g82Ro'Y1`0 Xi}r035, dj=L52Ba ki6Xq7ttv |os ;Sry2lf*SѰT˛&v„UFWwDYiɖi=PYpM*?GY~+WUx Kҧr{+u C" rRrYM$&|7#H7#bL̟|^+Vt;m y}[WNj|Rbq +H:9,5ΟyH:Z{R'[Ftݶk@tx8ߡ (B GJ8dI Ń0<̵Ϙ^Stw=c߆9stsI(rha@`C(h:gh7K*{[tkh;Ì=RаKnlr 8tڍ _,2)#~ 8$8& .Rb |jΕͺ ےR)jQ)J5, med ˅J͛w8}0*#?O" |p^ "FPk'P UOח/r/Tjy5P7t'Miߧj^،Vv46nN_wܗVj9\ O/; &S.S^>3)JS5z_A %fKȀdmı~x?tt?t;& 'hR34sI\IA!YDհp3$)E-d-`ЪQ!O6+pY89)]X֎ Kk"3,'2|G ؂E>7){f4XBǨ:|8m[릌Vd.rѨx:I%a1 )Zl-EG*[.[T]uG -e3 9_|0V2h2]ʓ&6 ̮eȵcO-B3p晙աsoiZVՑ> zi\!G< 3 /[ww e~ѩm!1@j!It eq\)=ZBV ˷fi5 _2w!#wP!=U:E?PfQ Qn7(G ՛&55Zfdx::vaӹ1l\d(w)sӴ.Q:]N1l4u?L=vx-0.gǼT_FFRGy=yfˏ6VvE|6s!0_/]f̱fAqqW ^>|Pxtzv|.SO|Լ׸`s?[vfssg8~0DGWeh}ҭ2Qcy>iNUI8 SR./gV@(=ĘzǯȦ吹em6d.PLê!5r(V*VGo׷;۹8uDT .ig"!o/q'.N%;S7^ e^}77gd+5AǙ/.m]X9{֟r}";3x <(8o W7Ǫ#k|Y$$cy~!? $Yj!siAz"K1V{~[`8/ml@3܈חD/m@e3@H?$>$0ww򕥫˫U ]~gie .0lmm._[ڄh*y-l-HNBn--\ nI~26$1$lwo0)]XCk[n2a7R!HԜ&WC†"Jj}b]%)J0 ֍+K[+˫q2n|%t2M⧕+m)ʶHz!P3=Τ+W$J^(Ƥ*)7Q98$U;g wFqqjY JV|RYAt t못2{891ay%e6I}F@x֚Uxͯ1%y1\4,Nbڨ oCt /ss$틛AQ0`FIruyeiNXk5s="K7?%t[5kyv0wח^#wI:$Y\X$mReH$ϯml&rFcΙFTٝ7P!|H6q8]O ZWф?L͍̓kkn5*I^ɶ2Aj-\XcKtBoq_]]dn;O\d'ۜx\p͓(I!ckVL5 ƾU5.+46|% }/Wv}XZ$i $"y}l)IEdJnph)`~y R=RʮÆM¾}TieYqa6IO)Ųw9W1D~_F<iXswX#J,g 1FTI LҴ wJ^ VcTZ[KG)p:Q-aw[.˗WoGZjwԗ5W=û&Y9ߒ˹VU}D,b i/0"|!h:`0Fo֦ ?RCN0_Ξuad 44L!W-Ko zp:Hv9pptxaA}H; .:B|i' "7y~Swųj?}ʟV^Yx;ԯ=S_ow[/G0-|Zy;x3|9~鵧~ JsͿS>Gz_֟͟7}?w_~+ ??dsW_??w/Z ?d~޹KG/z/oMڋ|^Go/wl]]w7?o|/Pݫۙ|e/~3?շw*=}?>|VV|{c~s7nן~n~?gg/Ϥ?w_╏{~s[|>Zÿ?}SW{gƋ^Mǚ׿?|?ѿxs ?//zW{ޕSu}3SC溺kHfBSLeJQf22G$C3ROB4 Es/<|}ǽ{^:wZ)9:rPeǾQ?}dlg:E6p-[ 6i)^@t"z{:_i}8tY GeTdOKLzkh!d`y|('*Y=NJ<~g^E߮dMO4N`JʧZFehUѸۦ bOQKkf"]syx<8d jZkVOhkwRjmc:(KYm鱠KlvӰRAvӪ+ hRG+!lV̇q7mTK>H1bM)FQ_]̭4uMΧ w2ݹ=c?TNVj2DesG"휐\#^<1k8PlpTȇ];Q5$Tt2z-'kO9@[JSUy1qjk>wXLb|K΄y0DF}9!F ܦn^O~9MiRsIO h++tܬMd]-͝eAi#N"߬U)oΕD}(fvIЖĎ- X so{FBՅܕn.wF fGu15۞#R/M5C r<rv:Gϩ,2A0EwG_+*P*9HhAjw[8 V|y}4IQ<;R;~oFR~; Bj6?tOlq(]YJ,ܛ3KFm6'_ӄɋg ՞`N-hc`S g95vşܲ ߝ"ǩ%bjWV$S',>Y~jCaΟ-84fPyE{|yIY⏨5;8-X4z"q:J 8E#y1SఐyW݃'0TEjw$nxa ?gdn%&iѤzםe:tds.Qݢ ,ot4wNOOm"˙j&P$aB)⡡gj-a) sper s|.酪r"rG K|Sn[?_c8 E7+M_v|=br4Gm!9 &bm{.*4L;S}ʩC5bsɓ-NCT?<`0`.^#v#/9)@; 5tK71$ }vmK.9Dz-o96|=kL19ΦZ-c{pul˔<Bڻd.[qZMKKSL,Q_<#C-, |L+cکg5YLRx te)Ѳyg6ȕ WH8lW꥖&kT[ϿQjaO) ldYCEmj&&Ƹ&EeswtC9ז4HLYM@9SMOىeVRBr i,heCYsy0]e9Af"Hߒ*;P͑_2Qb=J(TAzNKViDis+!q%gmb4 O}LLԌt8[,n 5ShC"M82賛.C£"8;lf/XrF]|N6L֑같^oROXp2V ڟ)_-{zFd<_P}ҍD5@Yɳl2zTԼ޶޽ 4O>Rkgwr$%E:iN4-/qyQUv*CԶ=(dPjoj3:{=*GlJ-?"_YVݛ!{=MڤIXc¼XK{'A/q Γ:wT7^ U uˠPE];h_p]rg,-<;>7NDp 5`A>@KXwj4eƴnW=&24n<ˊ}?_u/biLQ8DE&闬xUSGa!,'#])U'sֆzO!m0}\B+d3rTo?{CMFo*TnmdBxv&;56+v枙evMOLE@{"xb!%]##W"L2df S3S-fQzxmqV ־8^hQR{3Ltr4NFG5idG78?xKi K/s@b xH=GyHcʙoTgP(J17 }b<s{}K.o?zf=uE?v]`)&oWTzcOl1Ji 0 HUg8a8L8Ku^H"lI V58B>veA? b`F'u:^OsV}r@Lڿi3njG]D 1Mj[ .Aij-%ˎ & P6='SD6͆3k Bh:eZ^LdKFj8ڌ3*s;)~soڐNPǬc>ҽ{jKU8Q-x (~6՚rĺnڟ7igQKssh,Ӣ`4)ᶶA^0&bǑ.tj%)v&/J.@ ~#|( 2ޱv'n+~/n `MOGKHnC,cI6m 4FHF???9>6g74P@Mߠ>$` 'Nd? IUe|iW3?2+ϓZ-#ϋnKd[v${ZA7R混#ѵnGS'y(՜q0ގ\hw͎~Uox;lly|m~Pt8VM7#5(?*Ua]G}^pzuw/i&S1aF;7Kl0gGWRT wg'Ɓ۽^ӫ5vFL1qznǕ ~kwǛԞS4OZjt2Q3ټi:~[(!D,yM /?"V {Տ,ӼU @ 7~|[GOPQQ(g#) HB`ŻI-F]K-WJZ񕒃 ݶ"RhYm xY,Wdˍ_>Y5$\RW"͑?oB^aTf2KȱE V˓8f5%>G:Gނ/x* 9v, slt&WfKqO@)|^;+beq3$j",\`yeO6 m^0B5{ CyeSUl{P8o=SVxfk < [>@ OytKBңJDl5Y o;3{3xJND, ǽB؅?Sx%nSu<F|_reyuiGRR>[|>x{` Wz-oW֫z{l֫z{l+z{lآ#2~eE3 lhK1HO6 cSɇ@zq#yӣ+)h(gc$r%#9F 8~ R7tdM)u RS*=)DLnh"*ZLCnXdqmZq-o-Pv>a^1O=*_ɯk!F#mbL%I,$k]/l>6|ruEwCI2-ei">m]&Z$DfRdlPۚ ZTVhEy^@g_ӗ39oNzfnm&?¦Y+r[5CHB!$Z`.L)k=U-AFjyh 2,3%2I u8"Ź-a/=9M& `A3~r5-alnkT#i0I"VaJ(&MZP=l)[i1&^s wGAvxZ,"gUX k25 M)h`D9*]pΞnͯλG~mn~rt>*/a"}etG)R`y~s#sٸʔFI_/=+ko[CRvrrPOM HH{&8BFR*͠ )V+d'cO²}*OC}L$LhJ"Nv\1Nqb]=(fO@;6-P mЦ5DH$> u(rKRI*|lMdSYKFzcs݆\46IEl8| I iC:7)~{Zj*&k<5|z RL0 Jv=˦a(hH2씔gii)Ms,Gz,[[)\pwK{M`۔ej^5ypfk4LªlbߘܙZ{bNb$LѤMSz5 yd$[֒d:s;35TMU3MES)U#6vNf0LX<}aqB/z@{xBa)/g2=RMSjfS7Oз"#;%CMQE>RXX%0i`a0c#bĎcŃZ&G0 QDD @ i`jF(.:bq"1t#v%-?IKՌ/K|W?W?:)fyOcFO@ :% {3!DRΩ?xœ ~5?c^tĹDB_"lBBW*ہT7>/Z[-9M]؏Ɂڽz}(o&'Z 7^|c/W-l, o<Q*82/LpE3ѵ?7Aq αcnR}+&6@VܚNsriw,rς.3{c52lxeƽtTnǟz׵' " ⊭$m6hu gX`m/K@PsԠ =I[ Slq,6AMxw4pl><Ʌ9 ҁ d1+וA=*pa,rM MU!Wv۲g߱ v&@&Z"* e[$""x7¶ռ#{Qgi%|`cy6Dȅw*e+iH(acS 5rt MևHcؒ5;H^atV\b{b^j(J]>;>&98IjWJY i&k `VsfDCu0٢P&=DX]> <+▧d /'x2A!"$L&פ|a )eAN)j^8Y/?'8K28zfxGf ГW/LCԳ2 w9}q6* [T\[Wɬ T u]\NNړ-i3ITOcܺؐ6wzDcm I>#ޑK6 F Nkئ S7tT$fvY#7dcZc6etϜ|B^lbx'1#2ʇ%ηW =W( B\% 6b}Nv !8$o,O 'c7W0AձׄE,ޢ'-w?׷b;.5%ڻ `rFasE%Q^h BbM&![bn }9Y9 *$YZ}8/U7t'W_<+rZܿRnܿV_+=~]qW+?ohS/tZb>1r$/!o^jIySj.T, lua ڡO;sX@ o.BdS MY)$3`x'ZBYp w8Oc|af#r6 ^̌ˁEB_F@Oק^j&i?)p җo ;Tgzu9'5^sEZ ?Z@N5 XSwmmJŬO^(ع@-g[س&6cSg$1!nW ,Hf4lMݰvi{\5S)z_qlP1d^ *@+0`,xc* 42k6ˋc*'@vVC'C=*M`{a^ "?6ijKC;;r{a%嗔_R?ƚ#g}^o܀Q՞ENae«9 \rC"]"iwrӣU NV^xz=Oۡ2`4n? F,!3"#.Ͼn45#k] wyBr EQhoI!ILH \w@$%6.0R{ra:mii8:P?5eGHAOٗީ*k=Vk~i6b(A0'^Jb+>JjJ ؀AI0̃( r;(ұ^ٽka+1tL%\XP APR<$Fe`@;yx||tefOƫWu-W]cEm T8:3A&Γr(3=UfER.Ds$S"2C cxkU`_ \WϿ ip|Nq|rn Z<ܒ3 0>&)u';k"S?"$wpTzL}bXJ&-QgZ $_ZT|-)8}1A YerG OC|Yɏ-Y5R.n!+y߶<-$rt$I@ hn @aA ([FP*.7..c ۱*<(5GL^LU_o= DC*OQESqp:**%8"6 11, ́Oq_F: UA9IEkzS"3y_.5PZ(/~V;jP&9=5T>j'DLpr\(5Fk%pN[m?5vK_DGIKw1bF0:fpm }pn _s_wVz&bkȶ;52[kϿ.}ߪ&Q޿ u}0o1I9/aj(ʮj]~s)Oy<ߚmt;y糓 mA)[)؂a uI1hK/6r_dSHi؞yχm l7x?k$ܙhZ:-(@ԥɎIt}2'wv)7r{{G{C?HC)B/r_*$d.91.?P{ "O)<Xn;r 0[%@pt}OC~ѵ%6"{W uz}6AKlw̻cߠCl=_Y(5lF[ɆیdzjQQwDn*d4*qdR%.[2b $iu&OߜVv7t QrD w+Yx*seB6eJ_kcU]a+!ߔU֊2cihvFjUz|둍i~ sfVpxN,cua.C~~`'k, jg w\@Vy׼xiY[V: XaŪo.wb! WL]w/gyC3cg:P2^I12qPKx]1<V> ``wS{]S!B.RmXy|CJPc(/҈4""MUy >!W: 1FUUU=ƫMFdR9ZdU>m{FbP/o颲v.[S|'?6u&HR+%?)=lI~j,e.Dr{{-$I/K1̉"n:U5Y1xMrt *=yH=|("˻cP8+#gϞ ßj|ⶤ 9=WW䃞 \;SŠ^aO ȗx{F⋜MQ*9=~c:ϝˀ!=%pxNxT6y.Pp} zf{,9Ei<z]$\`Owzp"ĤOyiwO䊂gTH"=#@|!W-+G ͛--i@;=tI) ];8炻׭﹟q݋X q6X%ybL69lJ5L"Cv!]t_xk#\춸q@33IYc `z(Z)>7CW #mWrԼdvC'I*fA3?5oq\S x=w|F_]yAF>IBK.?M' }vB7kh=k9(r/{fҷZIQPRfCgjhf>؍~&#K> 8O'~*Pš% 3P9?ߘ6BK_ߐa1'K9?=(7_R/(I/鿤y^ dt;7(]O՛-I Iwrn=s턚n ;Ncss@.תsVZ C;$t-_e2Q(I ϜCo"/<>Sf$lLL#$&Z8BrbpWꀎOeO{{GjՁ5P6j1ulL쑟u͐.T$XUZo#z}[bo ZFNZTԏL!DN# rNsG:%a7(!ڠyl!b+ׂs,shGYcC)Qo#Tg6cG;~If29= NڴZ;,i`3a!6lbX8Q!b_hocR`>|rq6vUAG~pyWp~䡣8w_?{Wܶ_Ṣd$T]vR}k%,I@ي3HGO 7==ݯj Gf(-A8.0U&7.3۞rW)+>KXew> R4 ֲ E똞pl||s1Op0ұ@ÃMw{l=v QVi.!KD.>bۼ^:}q=D Dql5FyAؕ3+aw$ >W8bovJ& gsg̪Tt>ypWE_D@]؎;\IrGB糁?@Ƭ랱 1 |o=+b1 ƦD%`Ket LժIRVOG΃27JP'Iekszz޽%U!R!tRM?9Q9/tbN}2[7鋿+ZTOtw 6|E|3?Ko+/_T$iS)~}BfHHy3S(KG9"po^A# l _ eJ9RwVDe/߾={qªF,j닋[}f`*[„f{O͆x ᡆ/ vb5I3%S60ښK >D}zsHrV"4ef-V5V9)լg6W+qDq>ц\KNhj$ i;ngk| Y 7j3ܔp>MZ 7h3, k$6?Jqwͻߠmij Y"ܕb6i#D7 mvT$lV>†L}_+Y `vW=9w<ʑE]d?*4XLS?֗xsoqv"|6IhutF?C!Run$oXkb6  8p,}x RBqRAOHMa#i L/MI"OB aIK#?6d?v=-݈I~-%@6șaB($Րk)]EIR}{ Ap<ϋ`Ӎ0qVQ࿟''JQ j u cclZZ\,Qcn+'er:z^R T2Se$X {.[0L;Wg12𳘜@Ȃ}b۴xeIwsg^ZYa{Ac3x]e(b?b-K}A=jz {y2]4BO>9^6| sQIo}'E(c Ju=V6J? DGBۆJM|kRw#k-#>bkh0'5{6 5%1) I"Og߯$S?`&Ԑr2}RDim)^g1$,6VXL 5" <5zS>j=aYMvn- Λ!Ah[1DV"kZ!e[FKUkd0ҖR -_MRdKֿz|ֿ^oؗL˒t0GcfmCO ng캆JX+Z c_׏}װNԢݣFo6̙.36wi9 2@m߶9ѣ?-אoʾ4G썭lo4]>d_O`e _'!{~(\?۴ PZ8屟>{w%@0Mh7ÛK=,#ADfjOݞWe?+2$%/-h)TYMk4[ K J֌adzV]U ԳYzpWyhG@51Xm{m! W)+ͿɇƼ%E{JJvw•t[J5o5%_ӴNhG?Y?rb1&g6- %ve0wả  wٸ]F|XݙQ.Co!V_:S(N?#WzhU9XĀ=ׁ>i/^Q&az.ӶJ?v#GefLO#M\Q)퐁B-f* R]3z I"G? _/MBq$(Nn#.mue%N?#WzOY+}3@.;&ǂ,L6`|\3XFz8^5G6D?Wvu `]7oSO#D?Z/ڷ,tk֨,0P/7G]$#G x8@Q5OuV =P"G? q=&sb`i)97Q+O5"o$#G?/k>6"v=4ುnş}`0 j]3Ĉ#f a6Fm*ò70nw $mv?$#G?$*7`w*p']K߀&#G?+_LWWಧ@k[ ma]T1Pv#G"W.r/,v\3_6wXed|utropO o7?+%J>cxolni] ߽uRmFR{D?ῒp`]}I_&@U"#G?Ef8Dt@19Po>. wuA[|>N؝\??l3h8ެF Sϊң;I߻{zZݧwגٺd^%tQ5m$9M.6B ,щzΜ&q{l^_cܞnDUt^o%2eUoX~p_[.\LUj$?I~5$1#?2Y9OTDg<|Y-^C>%جy~1ěay,`|U/5?Acn I5,7_7NhEA x+YXR+Jދo`O,[5tC8fx{ >QW?c5K_PZW,cz|0忶9C ;_r1WĢ+c%d@O9pr; ;{sy#ەe0ahaLZ_ZQr9,H<шaHb.LO$ AM]#gmIo4د^/xbtm]Ij$~k{dQY s}Vn 2_JvyTd@FdߛY@@K`/ =ǞSNu|k42-D,Ҟ8 )Rr݉[jn[sfx݄( %V焷Z} i[ϖo|Gj ADZDpaFT|a y|SoZ Ua8сGU=k@GEݘ鸞KSŜ/+e,<^ vl3?(BaWءQƿb[URZ>KOxk6}LdQQ{iJ&?و*+64>׮m-uAsn3ͫGܶeRj+^ Ow|O-Ϲ:UiTF9Wr%:)UW VR뎇{ϝэ9)+ڣ;IY]o߉\NrRyw/7@D*>$*[u[ ئN;}/, Nl%Ѵ`+ezVOA4|}psYnj7y*{+J_z$w3oۉ[X@z]Z6M F1ǺN;w+/y=}ټlf]:D?ZɭL/Wr~ʏK]ߊ%ȃR6ybi{"T H̊q`뿞L;I2뿐UvGl{v K,JP {y;<k}d-'B6{:cc-?)ŏLX2f/.aO+&Be/ ugO)ETM\lM_PA A<"(U@Uhg'lׂ?*I?X+:{$~ <',qJ <,:K҈H[H#/NX1CA˦Ɲۄ#ϼ5*uʳ5^I `/W3ӽIkQWzz֩R+2[iŊvKzvoD-s%P> /1}<\Mʚ~A+o "ּy13Glf9.S䖣?=y. <Їx"IA^c8GS<sV1 /w_б lZ&ߠfFa2-dZf?xlpP9xqvyy3Иx|<Ф8?q[{C3ъ~$ѭkeEfEz{wo^FcQL[>a»ӂu/Ex/d|u[sn4p|dWtZksbA}  zvqkອTl|CeՇLZj]ZZGBziY>l?~"˽'-aه~qZpHZ7Vm1Ɔ ⽊C/ܯVxXO5g'+#NK4-6V 561F+A}XT@w݌$^u lh| "ďXnu/ /q"Oϲ% {Nʰ4Kqi|@H`҅%Loo1r5G TAϢxA Rwba csaV-zn@C.3;}/j'BKcP:$>)R 0 }۴CňVLb&"-T >O'bL%&iD2ƛIc 8׆#M{4^x<:|^ G?B46S6?.rSuP1;=e(ɁqfXvV\Y6 c'U5uΦmq?WFKʀ1翵dSUWsr._|ѱhLPvr9}Ykݠw|*P ^^~jw14Ý؂"S ژ1Hbr@U4EW_.>vyLa-UT =4?r 4/+>hZ> 3`*IoǾ_+c*__dۿ. 1ˀq?_ EyLebR bA`o1@vp0R ZT/.1`YT/ 01@Ÿ+'1`Ky0_1 0_1$ȶ1wQ`b_) /6`;W+_|[ E*DȶgQ`z/g:R oݟ_ /EȶQ`z/g:J0^3@޺/LoLgb_)7Gŀo{<;쿞za ׿Vrkˀ\2`siu=}_SJq8OWߎwl*@-l]l"ֺDGs1mҹ'_vٮB-NyX:9@M ;osMyf28ن',2.㴇v.V̺4YTQZi9Ec҄^2gç63΃KWdٓ Ѐ&`^1*:MP[ 㰟xnc`^v! IFCl&bɨZwNG!U܇+4u\xż1.XH?s %ed/$RDZyuMp0%Hਲ?үDBh,80?&#PWA} zɯO74>V<@2xX cFPMyg{>q^JF0頄 ~*/ G)ZsB#shitt4lϒ0}Iٓc4- A4a i y6Gl` q4tdYu^!}N[I8~ `} \`Ck[Őjը2 1jO~ TaYŌV(P*E^Քj3>ĬiSWj)Td//PS4.2UX5$g(KdzSj/fEUg68$е|8]dؓ,x$ծW 0 ӻ7_5m+k:y&Bm_Ljԣi K-a\i JDeGڋhώsm3˪$=mw@Q6;8+}YSu0Oj_WUqk)0Wl6lF6Kv^}Ը,10eO}߾D/|i/x&SE¼iio[zYdoAC ć):͎]~n]/ejbBv.U}533C}U%* 0UJ?_>LUR`|7ˀqyZo4VE Ȟ5%f~=֙_+4Ж,vL<Ag3I?r-Jqȡ:3slW06.kKòYyyoI_wk,n82/E1]͚?U; mxfOt$K[(-쑮`Wdh FԖIKmc3|~{[w`6. zG ݿZ^Ug?>U| _D*se+@? 5lpN=g{c^2>::{R'O@@>LVoxl;ӧ10&IV_nǴ7M="dBuhk[9+gU]-}my7%mE#o8=o̴zH v7.Ҿ_ T=rm݋q$v졖G'͜= Gh>t+}0uFc4bw)0:{-|?9xuv0n7`thӞa_Q1)/!]cH1?2KI]8,=w8?L.T͆V*F,m,'vGۻ%aR/Oj۽_oId uYUK<)?5RFS}i:1>COϦXm01݁| X4-Iu! 33Ǜ`•eUN ;z͉"c5ɵqMf2hIsJ3/fgMV!,)/K P4X趒H O3iE%}V_C_C;"H5.*/PCIiwWJ5hd"]o'Ymv 3$zM#U,(*Z(- KʗJ$ 1FbZ&$&[!>^VZ 9mQqHZjȠ*>ZPڮᝳGr|xl(k3zS|{ EX 1k'\q-(lT5V?36MopJ}Ek`b{rT,8ajĸq9&;{ِC,}A3Ъ mQ33Y&ĺ3aYjY{pʩUCRϴSuwˊ`zu{FKM=GVJkjU*CÆCG@;glтl8ݦHZ< Qn:jl;QֲHJp\,r)A3T*ԍ .'5`g2t9U#9UZ \Pw 4F# C(3Z?MExBN@<[0.oh^^5CɣTqTaa/(4y ? bZHGy`Eh@\ݡR 2H9"G:;cTxH[Rńd(iO'H5ԣh$mIϯx#|| K>^(5f1ngkutGS(D'?=pbfMEK >: Geϝ: hFrBX"1ƅizz|r^?:q?: xDvA4ٶ~WF]-CޔNEak'1l .vQ҈Z&b8[g"Fsꂅ6#GZrlf""DV&jȇ2򸚉2D ))ėpkTe-*GXl/hԺAϻ\GDW5bͯX_ĆK0P*v!<=<$%S7ã*溗]xlk u kQE Q,ðk:5]k00mDCD=ezNq(x=9b5BFe\ -CFI{ۯ_ެ 6ĎG;mGP.ԫ휼?ٔ$Rÿ?9gcZB;\L@&*UnMLo6630Tk^ԟ~h 6_[|4o.PwA~;4?JV@T#:mNgxI]KgS#l_5'}5PXg<-MX3EW3=lx5.M]l Br-GRնwLEBF@%o[W*gq888iއuҸ0O0}e*||pARpN굀d~-\SJȠb<mY+~ /~4ć$[^7qzk>tOM(HbIg3AI,+l`0 R)U+ŋ/(si8iQdw{`Rm.ɐ~}H:;ݤE{5I>5B@tS=9w@WHPA:zIz}ԵMEa!ðǓ0;wԠv熑{9jUW#̡]XEu:U` 5[M{ZEOz bLS9ޑx^F ZK `ҏ$8ZC|b3^!?uF}S@T9Y Ӝhv$U$#:E95rud|EHrʄ*i,$ ղ!nl6"'q&v`,5<~_9kˎRI/N6 |OW И"7jim1=l['0 >¨" "<'Hi٤$;18z^Jńى=ܖBJ3IP_۵v*'zSޒg/aF (z|wD qlBVh7 ;?{.Rɒ hJ7?qF$.f?[>HjM}x PYЙ _:=Kq@V#` `CA_l~X` R -CbvD bHm@6;l^b&'+6;1|rHhSЩP}@}dk'ـQD,Y+Ap4 |RB*ME1xFo M~N뭸ijj֐uc><:aJm5[.C2Ʒf,.ˆD|M*Hҝ̻5$HEc Dp4&-XbVLb vP7]LvŲKi]FD/ i֛p4t&6p5/` z+(H`̪9!D O@&3P fKZu 5/:IYX(2zdiZ3׮2m&>%#V}XZ%Bhɞw VQ^&]p\H!bA"eVwm+GQ4+2Um)@ j"ޝbBCհTr&29W<#a *0܋Q%+L)GV 3Ρ:7cRq!1% n ?҂ij2G,D9X P$J|B$9%LBh ܦ- M|#6 2G`ݡ;bIH,50 Kaх3DsLNYR >odC&҅bw]lPP?ޜ&b9!p%S*27 fdJFLt~*wwl.afQjhT;LUHqPDMbX>AS\Fjͦ'\O_89e _gQKәHd,Df)$ʭg ȱG vs.7 k6Rcfܦ  ː5䭠"_nMZS)Z1>n UBR$IS%v&L_Q9+)gI5E%dJmJZIlʅ:El}IVw~퐓GoO[cخ3%iLBotϨtTOA8Jjle?̼F1ʘ/"1T$jf4{ph{.nf vnrZ ^+{zzv3a&'b!*WdI)I777,^:褠m]20> HP=FB_BzDoVUΥ=G2 +>왠ρ커}2rG~pf7#<3qXyr{1_9/ÔK4*'g/54Jl8C쇗kcfaI0m+ {/2 'Ѩxe_QrZOJb}X֏s) \xa Ү$m3Q;1fVrqʽcQ>g IRc R%Bľ悪Bz>YSbQ>Peğh Mw>a%-TJTBiXůM C b6)'~)J)H0M'>!?KܡJME7O \-VڥȶRa'kYN #Q]I)-UQlݢyO|+5ӡߴ$$cvbfBYk7TԨ鴦ɀ oTe+g%TI#]ȗ4F\Jiڴ6l<ӌtXbw;'Dt}f>SL3>+]@G;̉&VK48!9K &' !<ǹ!_|g6ڍjZe)aj{6ţq3vxtc-×L&xA3 h&͂5!h-Z !Lmo^\!/64P6>dnhf͍xfY VKQ87&HBDmB9T#i8H;ZL\.ns2-ƼVȝߵy/9\c0܌ٟѥcG {4 C7ԭܮA0Q!cnìΓ$_s[a)~!S{sX &nԃ^_~_rxvvtz-^XcxF T-} pV^3ϵ H+32sfCui-wVT+ospVfy+oܖs'fbwj%*OY8fW\k?rP]|>]|kvP+4L $[Hm\+si=["J),s W3ym݈+ )~?>!f0-sv ?:"#W9MZ>T_(Co m@'- *0п@U Tީ#“35j$ YGqZ_:u =J@kg]֝R`\ xrơl;.qPR\5&oOq`cҋ!EAoe  D_Fww50@ `P'ZDNZR@ZjA괚XrV(]'{lhj,tm DS+s,C8ь.7s.Z!K.][Z,qd4Y YᲑOQX|:OOf g-AOJV˜4fS ˜(vavǐ/;CqeZ4Ӣx[m V"X9?Ք?V_ps) FUQPE<ErX_VQ\i |,U#|-^S, ;KuYb]]&k嵅 G7x |ͩ_S_aN9/;ߐPj{Cr6輇ʆEEfeƪD8+6V% lTX(BQ`c(tI #kba N+-d':%0v+_ڎ}?ӵLu0q\ tVýGCW xAPā&&OI7Z׭MMHmϬ%u#>NI ?*?%ZrPrkS:Bo}-9%翽o_G(5-49 ςazQkiZR6e\ӓTIՑT= QZ"7Zu}fjwMjLQ}RߐK6ɉ;t^oEq?ֽpZz (0tOwszS,5 Vv0&HJOGotC%_G?P-ސG@|ٿ# b"O'5?ىF|NCSMKcsYPz`<{F`_w?y)κmMG8#d!= 9ѯGgohj*׋* Lƒ.Q?;Z]'`r۫B ,dB>U 1TP}u3ql{NO12I^"/bϟ V+{MTֵNܬg|Ab4)金8 >.#/Uݲ >u@H  !ʀ;^=3 7~>DI׿w*>%Xl@=>9;>;EkUҝ\"tdHM< 5[HE;/aJ`;%m{Qms}&"'g?J)nN3B-ǥ/Av,<- bM@h ,F>`OCe7rzJpǼϠMA.3ndx}:e-7ViCWM JfR.Jآ cm j 0﻽4t9-;= F'g"2’2ݜ")RDcI8$&$Ѕ>l `;*d8] 1z GY,I%.+QA<}{.4Rg=3\̉Gڠ VHua$0w4  @\)T#6Ȩ$3b>:9Xƒhc?h720y~ a- (rhޣ{h-׍0J{n uc0 \7 -K%aؑfQG$a=h*Ȓ4L3$Aƌ"2/I{2KR2ludIZ߃%>md̂ҟ a?ϝB#}ER¡tGmF}ϟj8& LAHr8ə'.zޜ`ndԷ'^ZhZFWkz5q'Sw6ilXW͒74m$ii]8R!`[\/@787j+@SE(~7p+\OEy3?  @K~a6_>* TT:_+8ՁRႬXc=d4\DN>YrdzmBR!Oyd(̻o )%LyeK|=R7VK{.˽^xK{-ۛtܹ!|Qը.zK$]>l^ }? Qlލ⋏8PXM-|BA#ߔY(-Ƽ-=h#Ґ/ȗ__:$pgAB]:PVǂ0N{GR3qV5k`)q4{H밭_B`sYF[k /$Ⱦ:Oh:TQ ^#Hɖ+lD*h/44 㡂z} I&ЧX{{=Lv h2 1U[W0&Ta/̌#kS(2y bM\gi6%_KS/G[wS[醡[BP  2S~[A; H[/Mcr1O3r?@IJ?߶o['YVV f7G1GO;_j``Y*wUY*:PNRLR HW,9Yl=X`UV0A\ '0cw|)ɚBC2)t+`mn#H7ԾGJ!J|*];(-OӲ?CoJ0sq @4-eښjښaZUJ=q!-4XiңQj٩ _m՞2w6kc?eژu ]K(:[?2јX4uHU{992 ﴕ&f2,J)ic>ϾezB_ǐ'oㅍ|2Qf>G5Q|T;FQlb#ɰP7's7L]S8)8nCצC2|PՖA% t_?)?i%Ϳk՜j՜a\eQa REDԒգ=e+'k 7_c֩F4[z#H <_*RZ@K}4__Ku%)Y~i-+ӛR[KOϚzg8? r@p;'n9O\^m4Ym ~YH@s$s׉zD}Ym  ݔ?www<=#D-ȶ/N1/.ǣ!xBOa<+{ s8vN&X 4_g-AK͏$NwQWP!Ci"P3ߔ'H/KO|t8M%幋EX%Q]7m3-A%/I0%4,l3WFib5'h҂DZgܘqhHVRRZi rd7yBRL_ʏR~|cx.zU9o4ƒ^i2m̡-|w=a$ agW' U/`?V6V6Vpd+ +  +  +  p2`rйK!~:Q0 ry ~u1>qǝΫWfyPe;㓣 Ͻz!]Q9w1hNߡ`(>'&86j}h*;OT "F lCk#JP.Zu5LVrnL1Z7ş)"3I#D&p]%E`LTώt|r3ZfEUmoG_{ǭjwN *l ׇ@PTsv$j* t!Dd1c֓)YC`зS\g@% +\-}{ iOtTq@ FԥhA^FCtG Չ-η(eEA߿~j, CBL<= Xq0 7&ϟɔdOf頢Z2ي|zY(M3Yԩ% RAؐ MyFiWV]aT,##`q!Q&FqѥPXf0-]L-L !pOꓑ} skC;w^hlٓ?{hd{=)6@ ݙR+e62Ի•&  ͣS*\3.ZUp?x?x>hd\\-̢S['zɴa*OJi8J0 Ct|ޘJ׍f>@ߧ8AF&B6mq|(j'BF/&!ZFSQvݡX ӗ< WP뽡k{Zxts?Y_C_S{xY[P'uR[4uQ}Z.r6 _.ZCR'G; _ќn#\x0\hҰԐG)S&7F8'.A{tٜem mohwNKu{llX,o5ZK1+д:7aXp=É@dʠOFjMN}$.G-Z UxLW=d:~@u 4]D=##]I pA- q:J^<3X K.Ɇv}a?$_4$?ѯGgohj*>E|AjW< +mQP < IQ~uikmH;pkW: @ɠT& ûI | 7'ڿ&}FFRVO 1ե҃e_e#U섆*d?^@d?jsuޑn|fHgYһW_eu|ƩqgK ?y~@q GϷMoonԮ(: Jӷ \%x//6t+ȅRs֙{-0I ?ϋ}vQ7}\<oIhWNO'L뗾t~UO Qj9_aV܉,:x$*V` F3 SpzN.|(* Ugx~ypؔv7] ?|֠ϕ͇Gr(aC)ː:ڙ ܞ8!{% dPu]d#]P24$J!*K|g[hPR|+6v"88X9RD<"#e&#Yy|dRu '{-/-?{*'#;G4 ɀEI G Be'nu Bd>ÁCl >L2<"_}+(YD3ddn vA2-N7e_i8^$׆X7WGzt+$;>bH|}N;uojި%CD?N-Dj~օ7{0/T@e ?Zv754NGK--I;!}sE6?E?89F4H`y%=>l-WN7̎fHoGNGL4ώN>Bo!vpal~X?vv?b|NCD$x,ZV㾥P> 9oz۔?,f!?H߉v @ pDo xzfx a q熢 {!r5E K4b3|]\vB_ tocMi-!q1/?JOcBʚ|FE#䧺F㞮7@R. 11ܿ]|YG[%{@R)Se ed?w-A%?CV 0&dgG ,+:;#cZKInw(Rlu_!YOg`'gS+ʚ]hĬ"TDEōTϙ^H4l))K; ]ͬS7ZB_Z't|}QSPp-> P &0D%i`T.)Ōt]LA?{O޶~,絝T4I>@D03ii9]Qfi{F,L5Qc^)C^X+^|G\k̔0nB+Gx\{sz_sFD Ýj .!;KSR¥"0FJ=I(v>CR9lɫƧ߫4.v4R^T-G?#}4\0nxRCw-yTs )GšfӌUAdH6AgXDZᎀI)|dCx<5ߗ{9.(d>T32o%+54IIWWߏI88QH~ _)&|E>L"TMLlB⚸[O+ƟWZ},@ +H0RV ~ Cܖb;] b!Ud"F!f!F=7g/&Cpg!CM=kE=mCIT ;\Y$ʡb@q &] VHC{TrT0z^?/Zoss9g!Udu, &3T)+-(Yr{sPy auNݡzSg_iQ7+ܻݶ\TDKxh^x`sم g ? Y٪ (@'KBLNHo97 B6/C|=4L-{:#pEn9U?CRj$<P>URAS v*/%cS,Y/g_6J^.2S[Tѳ@ZM zfv<ffN?T8cȡYZRcLG?#[Z(R)Me:4.*%7^ﳓV~zlt~rf:x՗jڽnG=kŕѫa/wkmswwV}mM^O Ӂa\:g^v+l)ѥS d$O\Xy۞T}ʩw{RSDݞT}Qos!NCx&y"֞pyDq9R'P61Y{t~vQ˺76tɚVW65`zyձJzq|zxVLtz-v1o|j~/kJ"4Hzn*b$#DYC S쎛YXu€j˃wlaM`p/{?x{9zїwc_oUqN6;z7֯_qNnjgo7m{rtݛݍzs:47 >4^8sGƎt}Yu輏 2:'PPX竳R]e ؈SlbŻ;@4U1 v~Qv%Γ s==9* vr%d.^w'ed؝yB#ye̔"(3 '3!VA&](ͩLe$Ȗӽto6e"!^7Fq6 >7ayRS.vP7l@^PQAc8 Ua 6PK3JC5`),͚]&Ox ˶hb%0v]v 8>b02 )AvT`ŃX8.dDץ ta&"(;5 3Zu2q^4rrbQc+Hȋ 0`UClYG,t m K)$s{S1%ڼ҂jV*'ܬknLת6Iq4T"e`ʁfYqe(p8hЋ1Me>`=/z^ɀ|0䫀6oS2?>xF {V&Gsf.(.sw5**KTںHVi29FhIw-˨/z$kzZol#׼wd1EjUḲiiߺ5o1g(cO[zq{!9 BWRB7!BW+B)B7/%ZɅP>MQ[e2s_pozre_)Wwxh+DOB,+(,n 73{ O#UD>\v5M͸15c@5@'?R"GF<ڟHÂ> h_0;(CNOJ9*O/xŷeDwV؉fctg]3Af6x40Xg}hDL(r, k3}߻}7v 똣wDhTOe=̂5 cX"FA;X+3:+) ,?-ZhmE01(|C%kr䴹3T gL\}y& TY6|{)%&qI`sp rGm\Lhº&E(&d~2apzVmݰpńـr'X98. ˓Kvhlb{ *#"mh `5+ꚮ,QY7@|>hB_e &?3j7k,*>ֽ,c׽˜VyCH9VJ^dM}/Ŝ? 'p5܂&w 85 ɭ+u8;p`x)]lAs20Kt)rZz\$% ImЦ{(SEVo@Qa(!ix!R P궀alw-)W='qn^nmOZ]qֈp-ǭm+0ot,UpbBжMqQKA\j77P̕'G a^|wfF6Pc)u%cɤ`gS{xRzAKY,jgdrNlH[͛6I+9)󊺊q$p3Z-s{l )C"(*(BSBiXan|2M3kDO f֝ʨ:4`p^FM$6Dfe]No$WNy/x C5?:xR!*FxֵIrh @ؾ»oE@(ajdx.&&.:aNmvzΜ d?@jldhqjO/ae!'{ւsbdaWx]/jk'jt߀8}5ùWdtj":^Q#V!"DRΤKI╤,Whɰe4le9~hIOlW4]*:tlTiDX*):DvR%N+(@%UZ JB+,.P2%L!=?1ߦ.qɞT7thv1fdD*g0>QK* 'BM6ϙ7n`!4 #cFYDU@j cxkυ7yqCӯ{obJm1EDUhbbA{'xa7=Q 4D n3D|W25u[%mܘ.s4:.ZXF5O{.=U*1z"ch22Iדf e"ky ¸FTMwFkPf OigdXA8I^=hl1U2j<Oaƶ?Kl:{N7> RAZ[?n7ć$de^*L6gwǃu,UPv:8,p)gdKF󝷦#p;q¯BX8mMu=I4uasSEOgǧ9;>@\HaxPCTYJ+%l2*|&y9?A5]~Hyr{w܍ F2֪B$Ws5紤Uqn1t-f(.;/<ꔍWIIC. få!OXYvR}JLUHd/XzK#8lZQ"-=5Sb4oCQ>e%| O&W̒%0X$1SkIe~`t: H vFrŻ&$,ֈYIͅz<(S':UyoϩzۂO/PQh ߁kGۦ}^1[,&x¡~YZaC?+|<} ǧkƭֆB NeBx^EՈ32ٍ+ʰ$7񎘁֊ I|XeSqh_T3sSxR//zﵱPM?`q8Wu@-ckVp=kt-ɐquoeW,!mvqD쌦s'vdX t=ڠ+S=]~ ёMֶ{ v*kp}h7Fc #7CCvdχj_ U^Cam[0?B4]< jݧ݆#c,4,(Lq|wtWjz^2.b `FZ_6^٪oU6jwnȖЋjC݈mmBOmSǥ*ӥVݭ*&Bڸeϱ8+U6%Ruu 6Η$ 2{`,G?6ް1Ɉ<3yo?{6jK ė061@B2;s&%rnɒ,۲1$:܏WuUuUuc"fU3{_G\$/h0Cr eSc-)cVO{?PTзK.%*UW!jSE@t#Mΰk'eIGe@]^$^RZB}&_ 埰J]{zIJ%n[3݋CְnӱlϯlӲsJG&.ˢfE '^:#+ȉU#CϘ&e㢜ѻ\\"u8^DM`ڲYnn%r.޴;AyucY ؿUᅿ\,fI,7,ߜ5ey{)SL[ޟ)ci"Qcgmr{O2P~R#t D;l50)~"2? je#ǰ{Jy""l' Y++6'Ho|2+Yelc!…+Ǣk2Ӳ&74N&@xF SȇaԝG> -CqdF-ʪ{7 5AXQ-ƞ_ h7u~S(4TP5\þ?-SfO5]󚯠]9H sax);[!JƙU?) ŦPUO5YnhdhIohLZI$Nmf3882rJeG`@^LrywK2eڦ,ϩ<'b `k־i3`M:?IW?vJGyit(j(`#=cA4AN߅vvr%sٜѰ^OeX O? idn;;_k:na \=hzch 6GWSuP݋=/Qudv #RL9X9|FAeaݛ3jQ0hg?3|𦨔UGI: 1 GIná* wd"?C))j8q}d[C=-}gjje/wuͨš7{OQ"s4W`LNi/&)>t$ >\ӸB6f>a1s\}99~¢8ihtz4.y""E'q|+i$ iyȄ[|'hrrwv6f1sySc,}MP=Ef=P|~$,7'tn ;݅ 3G>+kzT"u|8~Nnɝ P>Iԡ^ӵt+|ȴ2AϾM俞B:z/i96io OXk%7f$Ze%C(8/W7mtnitGM:bJ]1555/vrX$q+3L'ajq;fN]ڶ7]ȫBxT |*T1 %oc kxA\ܵJ@%ƟpJ1O(G6qسoHOjѷ/Y}DNs=ǎD/{I7]Q Hj9uzV~m4'Z^å!XZUj.aG ^QXpfX>йrY`ڂnP)Fun,eJb[WvN:eR]zqD| Xd@ĕW_w°]"dyDX=a 7߽kēy u(n؝+o3,FSO|ҽ5 `e`1­`hL~p =(][1Yo⨕‹7A/j7f@+4w<ߘ ;XXl;&0\]=JHtH =W]O_ o$jt:41I+J em_jE|{{跮wg>;9Ǒ~}w_~]<׻VVl6iWTDCWn #@Œw{a)i?~z*B __R9%(0h;kzy#ӡt(a %àސ!LIgŹPXQ¹O?^SӘ _mhiI*l5=047V Ùݜ@'?psbi͑%DձL+* @_5E Nc1Fo{g_QOaP09ۤ.Ȁpוb[+*fymH\] $ԡצ&V7*  nQ= p*f h+vcv%A8@OHT|QzyTOp]˂ߠw)]dثm_HAx[R᧧;2DyرnRJ89xyρtϊf O.90Ta¡p(o!1 8ʒəF)s=%j3!Ug1ߓhݽ+V3?peo>%.K%~eO)@VhXr%G!B?NV8[ǥ/>'VtR|ښg;+6-J^fc1OR%>0v^R8@gGV4X_CI>CAeij|F61C Nf9cOçYߗSS_Ն )-/~L ,҂ -߳a}@c9g-2`6敝 _Һ||?oܡ ׌xhYƵǔss%hꛔr-@&_+״j q_ޚ}FiDN12{ik뚰I>^Vх:nH)1FY(psB%5e na@)5c:u-22z6>`dRa,*e۰ vkע4B80v7e J|BlhJ:SxvVu=]]U],C*}ADQLy@|Ui!*Fȇe JV~[VK+fЂ(f˳˳ eDeSQրbu0&u2v,klM+o=w/:lrի7+ՃkiܿlSݫ+]{q~|pj٧_>jv,4㧯_wwlEitNw8% r\iD#f3UVԍ=e%aEF9Z$6WH(O&T=)"Sp f`uTUjZYz6QY)W^!^}NvYCe|WJ>(PgQAşEqzv&S,iSھμ~PtDf__U]y_޵_o>\]޼:v4ݍ۲yJ?_궏kmݱ/.~y4bK;8| ɯ*~ngs}Zcw $EK{+_uŸZOΟn6'G %4B̶,3^dp0_/ V.wqvI>c.pڣ):O))(s/cwpE`]W8-t]%N .Y:3>p,D([9URmѿNRTpf(XQ/;i]e!f94[3}TgxyP$Zdto@KC|ٰ. ۈeJ,MQlE g'3|Nދ9ƙb ӥ=);=)tA+эjq.Ȧ|0pfk[m|ly7wpwa.[XE`h}̐g7xy r[^ۻbHion ~"a6#zª6&ۢx|hwϞa?E6]&+~Ȟ首z?ۚRt>S:C[{VZeoV}ca18cB;>fe;?Xõkull0}w@yʴݼr2!B~%>T*|瘖xI@iSCl%۵&S 1ɋ!|bBG+;#:< ;<~ %oX5CR5qm+ 4pk7jH<`ѧl'~T"|p"1C1:WL{X-]4s|cO)桋.dTDn;omo| ?+b>bA8~(U`G޿=O )R>۰^dȠ۞ԯ$a|GDF\;GԦK/#+WrRJ%EXMaSWKe*_2 䛞ЯTI CbVs}(_N'Th5*_z?PN݋lAa<-h^GF {J#Opƻ2[WE0[͈2'>27+Ǘѿ&*{1%_6CB#~(D/# ewQB5+˕cuX^"T@hd.KFd.+oů,B7+Od.KFrKF;['R's R7/S!R'R'R'R'R'RB>?XϐIIIIIIMUI">mm#I~E0 G|H>/60i9 U>T"_ə70+z?3 g| z^LGf2oL0({zjun?/ ?B[A},G xrR|}2UЅmyHnxZ2w z>HSlz+3܍`ֽó70|I:4n$7|ha2OCzOEXxBi!͍/X_0{6'`a|¼ , 詽$9&+Ds]+kt,X^+EKXu*yEB!/sO?/-Ͱ:4ʱM Қ7a-eXW (o\D0'etA:+o*2 B`*ʏMpʄIip&Ey@^Q#31)}9U<&s2\q,&fB2ߣ6I&3߳m-ut )iT>6Ycq+)+z$~0Y7|Hr%B[ S"^G/tMbi΋<846l7[F gwKNqeT#7ȝXl <" &h,'jwdsk(wJ_?3 _07ߋ{ڶ!ila"2=^.K X>}~xƥחF`/Dh3>H*>[j\[-|^\yY.=# 9o,oBq6 0=%UL D4S@k?M L-d 8.WG# R9̈́:3rwsKj<[T -$\& {034LBF,-VB8*eh:Q8ωIOȆ`3;ɵMv؏2y4'-m-V? sпogd"e@f̌3L5 va(B}ՠohDFx\:xj9y5uhegBn&!UF$s.7R!Ǭçfm uAщf&r #c}-qAb7"Kn*DX#@X=Q`U/pjo, n3{K4Mx?RGMa3]mޯVqGBE""~@O]QX}d,ʥeQ聏HaW x [ V"5F"Y͋) &؁qOeڌM9bL"?0pW/rU$| q|E .Y{1 b)o&4Fe{N8 <3?1 _)zU,1`n?{ߞnW= `_M?? =? RKϐ3 Չa*uۇD4[a,},\^}Fqd[s_W!",ΒE,xd EބB:)d$$rD~)b#O  &@l͎GwĄkaTIY'82HI aYKYdu}TޅrpǷGǍ㓼n7@{@ w<EQ?ObǤY>0wWUXpG&aO3})'|ʉT*Se>to`g)ڄJco+MbXrսkWzhv@ӱg怯 YkSvaPk=Uc?UUA3 OhFf$)K?R#}(dDO#jƥ`,aO~7*vn:8$-@? /!k='IҿsGξ?w2wYj{rY7 d*"1gǨ(ZԚ뛛Du␲{󦑣_i'iֹߞu9_~^P~\ww:,+jw8>xyuV]\r\|;[uqp}Z xШ]츦UOleIsƟŸ4 S:A3 W);=3?r:8F=g>ܴȰJB*q4<0 z-SU_&a]|5: N’}B(dq07/=%|A YY߬ҝ$_XvضV䍜q_PQLa̞١Q)=~| N/sT|PI@9JL5"R76 yx|Ylv4`H5NπFC}Q틌UGhyRDUa0Q0TIа҈3)A&k-ãy9xjN~<|Ӈ) %eH3 :x$@1Gh 5Wi8 5T&YQLyhLL)*3g1_W*qߺ&_B0ㄲ^ݶm( sr:}?uq; s87޻,۱&Uo7_B+w 0FdyI)y=}#G9) L {LE{d_ '/: P6`T6JHFv;ߟk 2?0úxRxqx^T=Dm#fH;x C\ux ?/.?e&-fc4+ okVa &L)B]U*WK+fem$.-p'/4!FE4Ru]02s=4*̉8X,@!1|= mql}NF뜿 ~f,Mu46n 6,4|9KQR4|dJ@ sR);o^22;G\%Sxq)k5т(F5LlV}ekcpW3RMr9 ʥYF5M z.LdElEly r%~Y""t.vzv/d[*oeބO<ɇcAEcr_-.'Jl /[~節 s$"GCd%/va| ϰLnnBGrPMF1F\˲T**Oq֕[ ;ZkkA*/\EMԠlOĖr8W[R?@m.9st`ҡ~Dl$? F~[=4[ `b>vׂU1_)6mq%Vg u0 kctU@G^1B8 ҀV;Kæy;‹0 kAl]v0}[*2mZmGדC9fbS,MgqxiMu7u=SoH# Iv-Ʊ=7rq0 Ӱm20[% -V:GkM_Y6oMeCǀ;{{'g6q Ss\^yL[MS&r ld%6(?Hm.YGN5v;ː!D-m_1/V!~R }@bBMm2 DMl39sn3%NȆ% }T9eݶ%,47M jC)L] 9G bW~\CAZft9k: '|W. NM v ZvA:c1m_E67iirzY[&jU?c¦7Z:gTJ :ZhY,aQGtOZ@WO.hE[b2?C7'#fj1!~fwD{LrrLjYT* %#Ш6i[ɽɹy+ΈMrkFu .)y;u&,]j+7`]0ґ=u E%L^ܽܵt:4~_!{;7>jBxw0HOJgg= Q%L<]V5r.ftkN-ɵyOsǜ&31j*^h~ fׅYn&COɬXtM"S*Gq'o Å{;'+gpˉS&qݩ.b,z< p8x`A+?g&j)'Y~% Rqk Ee 73 نRq D64w֧|bBЀ!5BmPR kmT>!uj:FCȪva~#kqi\_ Dt$xHNڍv|ja\ZllzƧʼnK8uٺ Pl97ũ) U҆;2"ux^qTٞѼ(Ba + j{WB{3zAŔrR7w+bӗ3u³{gɃQܪt@d+ު3 86U4&q!o{-5JEzL7Pp=OSlױyB[`6N0^L)RC١sA[k 0[  PX `IoLY'h@Cs{V<7.f~Aml>=AffD)ஆ'|_W#+2,eh,aߴWgǥ:ɸXTވGoh-,ԨŃ23O""g4!pj0&IH" *[!l )X aOC]ge)UTܼ&]NʵO8}L;,qzh}Js찰Cez4B؎kwkLІ0Gdl%0`iŇHZivd۫ / Mkw` 8U~?xD"2H"6\m]W3ya}wto.dC q=d:$ɾҭnNoWia/xK >-~uP-~%Jg&u ^l7G{'o-PtR86il]V=1gɣ#I=aG`cF'"Ye)ݘô-*\_-|Bc1Q_b_Wq]G2Fay*Ȥ3cy]\1>Ӊ(l8au9[I+d(Nb3ecP\ߐMAo k hB _8WzzfWmM31e ?{ $"‡ ɵN(𼹅<׋EA`q& n2@yUL&8iNzbH +[ {},5'y$l\ .Dy *\2"tޏ܎# 칣.,p5Y$پg& Ø8c.gdufU*9QxDyLLJ_ K6qoMܜdscC7fsSQEq8Pg/(x!=z\|&yXR94$W 'Хז5TwՓpÆ?{ſaNC@1eX2_r1nooKlI8gI7f錔xH6*7o@zfSLavOg%p ~7 `ܽqR:*0(_]3`XW[?7ho;+ U@ |@4TikP))?!+̈́;ޏޅ*oݰn> ;KrA;rON?R ֮;pkzvyL\Y}xAȓ42{~zz|srW9>!ervwqi=޳>diiIA- i~U-!óߞEc3B.UMAƴ Ţ?^ F:0NI9?ISLfQ8S͡jhV : Ψ+FG2"v˝C/y1qM9 d8 . q\w?~zJ )乗Ƙ-3EAm$y9`Aih1d%)} U PD"Y#yR EN6Š/?] ]EДH&ƾ'罝eHW`ث6bH$wO]%,8'zqogRrmdVP,{DDk,$ze ȟ tN`[5F N zr nF:S3^e3HCdwiO,g"(% !8,/GW؊kOA2׸HOZj!@8'7%+yNDiHeS y%+Aݗ$C;s_PG6Wc@~-\'%cu.X2􇵹[7 *r:_LXA]{g͍=eWW3WEpש4/lvh㬢_w{'}s3Hueh{8S'1Vz:}8{^W;ә2\+?T{=u* R;jwN4,};'ySBv~,lLJi1j.ivuI& KwbԵSm򮯉HT/h"BGk|VZOm(6:ʉXzG{]Ti|UuKv>VuxwrOBݵ&Y;(Ӛyη LBH8-ʥRsX*CCL3Ȣ\:)R˗~e4q?1P8jNAݿ۶ N}${Tx\J}8|>htN~E< l5Q6Fr+W~qۧrK3jl^Ϯ\zVsRG=}9K_n_?mLoOK~Zv{.s?j ~b\T8wk,Gq~sRǴyQvFv RmT9wá<*Z4VkZ}4w^;}J>N?Jb͟MEB1^ ן; P</%٠faZOa3_2"W|9l]㿳Klf,ç88sQ: o8EMڣޠB*ʥi{ {wI  p 1?ۏS?4O?y+q?sq9 ;sQ寈UQw )?1^*W@ކYኸPN e݂Ȍ-(%L UubZ@ަ!deL 7xn[`tq=<@5zQ%$P-[kf3zJ.Ϛ{ڑ$|OI+ֆxjs`Z>k.7ԣs 厦XevE@''SI)EeG2VM\,CΆoxK"MvWBW ^S&l ebq3ٱrsC`ώn5튘Y4d^@B,I3ȃ?B>=COCx"re۾RLI:#NѠOG}gDYSR1uxxxx@o1 i4=fm8׸&=מ߱G=?S'a Dn pvv,;I :^7sA܃extto]r_{cXMӛ&F̉A"(qL&z+z"?_gWEqK 4|BБA|g۽}E54r?G #/hW[~R8=7 GzILn;Rp:j>2н#畃vR{ ヿ)5&E=vo2JRUvC%L]iZ ?=(Bq#1 <ݨ\S>=|nD]TZt!Ç[1hR{h涆a`Xg8`iI5`'1Q,1?F榡6eD$uS*j IB,’%:1Z7ǎ\?xtc y%]#3Zws8ʐ"eЕZ,kkR+&MzІh&46 mH'mPVH1"ɒ䘶-9-@P4dH`ǐ*† -R"иT' w+H{mnN0oOq"Qvޥ-c~Çw2ߣS6v`2n_3ޥ`lΪ[kmqиFprl>_eK~M7w`+{nMoz˜n;6W/,wqh^.}{gy0=77ܤC [6>,]#G뗼Ħ tMo[/6շ/FP>^S~]>}z}}V{1>'ޟOrzӵ?>]ܯ~2]>gǻِl}?&;‹u㘿>l>8]\_ta5=>5ѻ.Ӯkڎ3ǟ/=9|B*5a/~׹7{A{/5Ҫ>N]nxVN'ξlwӟ}[\Lo}ZMm'&/]ϟgZVo5 WŴ_qoF q_V3j3c-3[N-x_eZVo5 fXkN7~F.qo>˴wÉp?=<>^qu1\Lۃt0kyp\V2]WoX}17.b#g_zůظ{8~7kgK ..{wu .&|N_?rA>Gj-Yk+_w:2O/4^?,nEeoxX]b?t)OmnoN׹:ejO<}<>{:kx0v/8fZ>lOν[h7=a6v:yr6ӯן=_xA{[ul|/_olڸll;w~lw`o=>^hi볗[X?ַo~k_ڛ/ּ>~~;f~BY{$O__;[x-gK^Ν7ӝِẁlг6f # ʣ,048<@DHLƷO4i4hLF3fZii/zʹ4LK3-ʹ4LiW3j]ߓj]ʹv5ӮfL{iO3i=ʹ'ʹ4ӞfLi_3k}ʹ5ӾfL@3ht4Ӂ4Ӂf:LP3jCt5ӡf:ѩf:LGH3i#t4ӑf:LG>_b;>;>ؿLt(UK%jjbDZZyޮz+` XxK޲,hM Zx޶-p \xK޺څ.x ^x޾/ `xK0M bx:1 dx'KZ2 fx7z3 hxGK4M jxWwxWwxWwxWwxWwxWwxWwxWwxWwxWw,qla˜ t8ɰ%Ά-q:laKjjjjjjjjjjjjjL`")HD &R0L")HAE *RPT")HAE *RPT")HAE *RPT")HAE *RPT")HAE *RPT")HAE *RPT")HAE *RPT")HAE *RPT")HAE *RPT")HAE *RPT")HAE *RPT")HE .Rp\")HE .Rp\")HE .Rp\")HE .Rp\")HE .Rp\")HE .Rp\")HE .Rp\")HE .Rp\")HE .Rp\")HE .Rp\")HE .Rp\")HE .Rp\")HE .Rp\")HE .Rp\")HE .Rp\")HE .Rp\")HE .Rp\")HE .Rp\")HE .Rp\")HE .Rp)1)1)1)1)1)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)Q)q)q)q)q)q)q)q)q)q)q)q)q)q)q)q)q)q)q)q)q)q)q)q)q)q)q)q)q)q)q)q)q)q)q)q)q)q)q)q)q)q)q)q)q)q)q)q)q)q)q)q)q)q)q)q)q)q)q)q)q)q)q)q)q)q)q)q)q)q)q)q)q)q)q)q)q)q)qR&RDJH))e"L2R&RDJH))"TRR*RJEJH))"TRR*RJEJH))"TRR*RJEJH))"TRR*RJEJH))"TRR*RJEJH))"TRR*RJEJH))"TRR*RJEJH))"TRR*RJEJH))"TRR*RJEJH))"TRR*RJEJH))"TRR*RJEJH))"\rR.REJH))"\rR.REJH))"\rR.REJH))"\rR.REJH))"\rR.REJH))"\rR.REJH))"\rR.REJH))"\rR.REJH))"\rR.REJH))"\rR.REJH))"\rR.REJH))"\rR.REJH))"\rR.REJH))"\rR.REJH))"\rR.REJH))"\rR.REJH))"\7Ͼ}oo^͋W/^^;{SNx_~tqjy7ǣ/d鏚ds?of:o7=oZsv<}rv/G{M!kݦvfs|XodpNlQӎxփzdz8}4ez8}z޻[Ύ6?NoCt-57YǭU?5}L9dyWaok7>K|AR8irм?Ur06ka/GfkvolM6nMn>xg75hLF3f4ii5LK3-ʹ4LK3j]ʹv}Ov5ӮfLiW3i=ʹ4Ӟ4ӞfL{iO3k}ʹ5ӾfcfLi_3ht4Ӂf:L>L@3jCt5ӡf:LGP3i#t4ӑf:LGH31;>;>пc;2]T-ѪUK%jj /Wxޯ7,b /Yxk޳7-j] /[x޷…7.r /]xk޻7/z /_x޿70 /ax k"71] /cxB72 /ex+kb73 /gx;74 /ixKk75]-]-]-]-]-]-]-]-]-]-ղy%N-s&]\'Ö8%·-qB̻ZŻZŻZŻZŻZŻZŻZŻZŻZŻZŻZŻZŻZź&R0L`")HD &R0T")HAE *RPT")HAE *RPT")HAE *RPT")HAE *RPT")HAE *RPT")HAE *RPT")HAE *RPT")HAE *RPT")HAE *RPT")HAE *RPT")HAE *RPT")HE .Rp\")HE .Rp\")HE .Rp\")HE .Rp\")HE .Rp\")HE .Rp\")HE .Rp\")HE .Rp\")HE .Rp\")HE .Rp\")HE .Rp\")HE .Rp\")HE .Rp\")HE .Rp\")HE .Rp\?]}ᜆW18ՐF陋 vw =ȵY%WGsYcr,REʱH9)"Xcr,REʱH9)"Xcr,REʱH9)"Xcr,REʱH9)"Xcr,RB"%$RB"%$RB"%$RB"%$RB"%$R"%(R"%(R"%(R"%(R"%(R"%(R"%(R"%(R"%(R"%(R"%(R"%(R"%(R"%(R"%(R"%(R"%(R"%(R"%(R"%(R"%(R"%(R"%(R"%(R"%(R"%(R"%(R"%(R"%(R"%(R"%(R"%(R"%(R"%(R"%(R"%(R"%(R"%(R"%(R"%(R"%(R"%(R"%(R"%(R"%(R"%,R"%,R"%,R"%,R"%,R"%,R"%,R"%,R"%,R"%,R"%,R"%,R"%,R"%,R"%,R"%,R"%,R"%,R"%,R"%,R"%,R"%,R"%,R"%,R"%,R"%,R"%,R"%,R"%,R"%,R"%,R"%,R"%,R"%,R"%,R"%,R"%,R"%,R"%,R"%,R"%,R"%,R"%,R"%,R"%,R"%,R"%,R"%,R"%,R"%,R"%,R"%,R"%,R"%,R"%,R"%,R"%,R"%,R"%,R"%,R"%,R"%,R"%,R"%,R"%,R"%,R"%,R"%,R"%,R"%,R"%,R"%,R"%,R"%,R"%,R"%,R"%,R"%,RR"%%RR"%%RR"%%RR"%%RR"%%R"%)R"%)R"%)R"%)R"%)R"%)R"%)R"%)R"%)R"%)R"%)R"%)R"%)R"%)R"%)R"%)R"%)R"%)R"%)R"%)R"%)R"%)R"%)R"%)R"%)R"%)R"%)R"%)R"%)R"%)R"%)R"%)R"%)R"%)R"%)R"%)R"%)R"%)R"%)R"%)R"%)R"%)R"%)R"%)R"%)R"%-R"%-R"%-R"%-R"%-R"%-R"%-R"%-R"%-R"%-R"%-R"%-R"%-R"%-R"%-R"%-R"%-R"%-R"%-R"%-R"%-R"%-R"%-R"%-R"%-R"%-R"%-R"%-R"%-R"%-R"%-R"%-R"%-R"%-R"%-R"%-R"%-R"%-R"%-R"%-R"%-R"%-R"%-R"%-R"%-R"%-R"%-R"%-R"%-R"%-R"%-R"%-R"%-R"%-R"%-R"%-R"%-R"%-R"%-R"%-R"%-R"%-R"%-R"%-R"%-R"%-R"%-R"%-R"%-R"%-R"%-R"%-R"%-R"%-R"%-R"%-R"%-R"%-RJ"$RJ"$RJ"$RJ"$RJ"$R"(R"(R"(R"(R"(R"(R"(R"(R"(R"(R"(R"(R"(R"(R"(R"(R"(R"(R"(R"(R"(R"(R"(R"(R"(R"(R"(R"(R"(R"(R"(R"(R"(R"(R"(R"(R"(R"(R"(R"(R"(R"(R"(R"(R"(R",R",R",R",R",R",R",R",R",R",R",R",R",R",R",R",R",R",R",R",R",R",R",R",R",R",R",R",R",R",R",R",R",R",R",R",R",R",R",R",R",R",R",R",R",R",R",R",R",R",R",R",R",R",R",R",R",R",R",R",R",R",R",R",R",R",R",R",R",R",R",R",R",R",R",R",R",R",RZ"%RZ"%RZ"%RZ"%RZ"%R")R")R")R")R")R")R")R")R")R")R")R")R")R")R")R")R")R")R")R")R")R")R")R")R")R")R")R")R")R")R")R")R")R")R")R")R")R")R")R")R")R")R")R")R")R"-R"-R"-R"-R"-R"-R"-R"-R"-R"-R"-R"-R"-R"-R"-R"-R"-R"-R"-R"-R"-R"-R"-R"-R"-R"-R"-R"-R"-R"-R"-R"-R"-R"-R"-R"-R"-R"-R"-R"-R"-R"-R"-R"-R"-R"-R"-R"-R"-R"-R"-R"-R"-R"-R"-R"-R"-R"-R"-R"-R"-R"-R"-R"-R"-R"-R"-R"-R"-R"-R"-R"-R"-R"-R"-R"-R"-R"-RF"e$RF"e$RF"e$RF"e$RF"e$R"e(R"e(R"e(R"e(R"e(R"e(R"e(R"e(R"e(R"e(R"e(R"e(R"e(R"e(R"e(R"e(R"e(R"e(R"e(R"e(R"e(R"e(R"e(R"e(R"e(R"e(R"e(R"e(R"e(R"e(R"e(R"e(R"e(R"e(R"e(R"e(R"e(R"e(R"e(R"e(R"e(R"e(R"e(R"e(R"e(R"e,R"e,R"e,R"e,R"e,R"e,R"e,R"e,R"e,R"e,R"e,R"e,R"e,R"e,R"e,R"e,R"e,R"e,R"e,R"e,R"e,R"e,R"e,R"e,R"e,R"e,R"e,R"e,R"e,R"e,R"e,R"e,R"e,R"e,R"e,R"e,R"e,R"e,R"e,R"e,R"e,R"e,R"e,R"e,R"e,R"e,R"e,R"e,R"e,R"e,R"e,R"e,R"e,R"e,R"e,R"e,R"e,R"e,R"e,R"e,R"e,R"e,R"e,R"e,R"e,R"e,R"e,R"e,R"e,R"e,R"e,R"e,R"e,R"e,R"e,R"e,R"e,R"e,RV"e%RV"e%RV"e%RV"e%RV"e%R"e)R"e)R"e)R"e)R"e)R"e)R"e)R"e)R"e)R"e)R"e)R"e)R"e)R"e)R"e)R"e)R"e)R"e)R"e)R"e)R"e)R"e)R"e)R"e)R"e)R"e)R"e)R"e)R"e)R"e)R"e)R"e)R"e)R"e)R"e)R"e)R"e)R"e)R"e)R"e)R"e)R"e)R"e)R"e)R"e)R"e-R"e-R"e-R"e-R"e-R"e-R"e-R"e-R"e-R"e-R"e-R"e-R"e-R"e-R"e-R"e-R"e-R"e-R"e-R"e-R"e-R"e-R"e-R"e-R"e-R"e-R"e-R"e-R"e-R"e-R"e-R"e-R"e-R"e-R"e-R"e-R"e-R"e-R"e-R"e-R"e-R"e-R"e-R"e-R"e-R"e-R"e-R"e-R"e-R"e-R"e-R"e-R"e-R"e)o_>/ӗ~ك>oϏ>7G/?=/y}|߿~OWϾ{rmwOz_ՋS?c~\~_?D^A{p[~sįOr\^~'Ϯ{뭟oϞ?yntw}g{œw<_k\˛;ǛM^/\n"o~vk^|{}__]￙ˏFno?|엗{wutqy|ywGݹ ^/^?oN/^^ճo\='_~y{y珿g=>DϮzvѳCgճCg= gW=;߇U!OhzvI}]uzgWއU'!zvI}zAϮ:IѳNR+=$>DϮ:IѳNRCczvI}]uzgWއU'!zvI}jWϮ:INRC쪓=$>DϮ:IѳNRCNv usP1[ usP'1 uzsm;瓍dvw;ټNo7IacN|1`qR<NNǘy>Is09Icc`K'u}Nǘy>I"s0[;dc`w'c<ly99Z;M21|ϓd1`zR<nO™ǘy>I;ssz1`v}<Oǘy>IFs0?)ic`(1cɩ<%y9烍451|1`Ric+ Akc^9J`s:~PT61|1`<y'/w0'靼wz'라w1`<~Pǘy>Jss1`<~PJǘy>Js0AqcN0gH)r Eȁ9"R@H)rn3v0zV9ȁ9"Z@h-rEȁ9"Z@h-rEȁ9"Z@h-rEȁ9"Z@h-rEȁ9"Z@h-rEȁ9"Z@h-rEȁ9"Z@h-rEȁ9"Z@h-rEȁ9"Z@h-rEȁ9"Z@h-rEȁ9"Z@h-r<9P-<9Tm<Łȹ9Mg}G} o>w?>_ bo>g/^_^w/\~O>ջ/_~ŋOw/?|ۘ{˗_]ӷ\].%n_}į>˧\.K^.//߽~&o~>^߿z=o߼o~ŗϾ7^|Y&ظmȼ=G=^3n?r[4kk?8W?ymدs"/겞w?|~nOqz_^~o./~߼z7_/_|/_~/|'ɟOn_/I}|'?|u~//~y//ZǗ?oqB~C}TS={?_/yǗ/~W?{\凿ZO j@SR jPԀ-'JOKɄM鄜O Q)ӐsSi9 9!4䜆ӐsrN&z9Mis69MisrNSi9MݤrNSi9M9)4v9]isv$9rN.t9rN!t99_s:9Ss:N9Ss:BJs:.9Ks.9KsTsn9[sn9[s`ͯWeUz+^_W='[*=]`_u:Yl zs^Aﯠ7X;,- z˂fAﳠ7Z;-^ zۂnA﷠7\;.- zvAﻠ7^;/ z~A¢7`;0- z ކAà7b;1^ z3ގAǠ7d;2- zS+ޖAˠ7f;3 zs;ޞAϠ7h;4- zKަAӠ7j;5^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^;x!0=vja jjjjjjjjjjjjjjjjjjjjjjjjjjjP"J@(%RD H)P"J@H)R E H)"R@H)R E H)"R@H)R E H)"R@H)R E H)"R@H)R E H)"R@H)R E H)"R@H)R E H)"R@H)R E H)"R@H)R E H)"R@H)R E H)"R@H)R E H)"R@H-RE H)"Z@h-RE H)"Z@h-RE H)"Z@h-RE H)"Z@h-RE H)"Z@h-RE H)"Z@h-RE H)"Z@h-RE H)"Z@h-RE H)"Z@h-RE H)"Z@h-RE H)"Z@h-RE H)"Z@h-RE H)"Z@h-RE H)"Z@h-RE H)"Z@h-RE H)"Z@h-RE H)"Z@h-RE H)"Z@h-RE H)"Z@h-RE H)DJ(J)DJ(J)DJ(R)!EJHR)!EJHR)!EJHR)!EJHR)!EJHR)!EJHR)!EJHR)!EJHR)!EJHR)!EJHR)!EJHR)!EJHR)!EJHR)!EJHR)!EJHR)!EJHR)!EJHR)!EJHR)!EJHR)!EJHR)!EJHR)!EJHR)EJhZ)EJhZ)EJhZ)EJhZ)EJhZ)EJhZ)EJhZ)EJhZ)EJhZ)EJhZ)EJhZ)EJhZ)EJhZ)EJhZ)EJhZ)EJhZ)EJhZ)EJhZ)EJhZ)EJhZ)EJhZ)EJhZ)EJhZ)EJhZ)EJhZ)EJhZ)EJhZ)EJhZ)EJhZ)EJhZ)EJhZ)EJhZ)EJhZ)EJhZ)EJhZ)EJhZ)EJhZ)EJhZ)EJhZ)MDJS")ҔHiJ4%R)MDJ"IҤHiR4)R)M&EJ"IҤHiR4)R)M&EJ"IҤHiR4)R)M&EJ"IҤHiR4)R)M&EJ"IҤHiR4)R)M&EJ"IҤHiR4)R)M&EJ"IҤHiR4)R)M&EJ"IҤHiR4)R)M&EJ"IҤHiR4)R)M&EJ"IҤHiR4)R)M&EJ"IҤHiR4)R)M&EJ"IҴHiZ4-R)MEJ"iҴHiZ4-R)MEJ"iҴHiZ4-R)MEJ"iҴHiZ4-R)MEJ"iҴHiZ4-R)MEJ"iҴHiZ4-R)MEJ"iҴHiZ4-R)MEJ"iҴHiZ4-R)MEJ"iҴHiZ4-R)MEJ"iҴHiZ4-R)MEJ"iҴHiZ4-R)MEJ"iҴHiZ4-R)MEJ"iҴHiZ4-R)MEJ"iҴHiZ4-R)MEJ"iҴHiZ4-R)MEJ"iҴHiZ4-R)MEJ"iҴHiZ4-R)MEJ"iҴHiZ4-R)MEJ"iҴHiZ4-R)MEJ"iҴHiZ4-R)DJ*J)DJ*J)DJ*R))EJJR))EJJR))EJJR))EJJR))EJJR))EJJR))EJJR))EJJR))EJJR))EJJR))EJJR))EJJR))EJJR))EJJR))EJJR))EJJR))EJJR))EJJR))EJJR))EJJR))EJJR))EJJR)EJjZ)EJjZ)EJjZ)EJjZ)EJjZ)EJjZ)EJjZ)EJjZ)EJjZ)EJjZ)EJjZ)EJjZ)EJjZ)EJjZ)EJjZ)EJjZ)EJjZ)EJjZ)EJjZ)EJjZ)EJjZ)EJjZ)EJjZ)EJjZ)EJjZ)EJjZ)EJjZ)EJjZ)EJjZ)EJjZ)EJjZ)EJjZ)EJjZ)EJjZ)EJjZ)EJjZ)EJjZ)EJjZ)EJjZ)]DJW"+ҕHJt%R)]DJ"KҥHRt)R)].EJ"KҥHRt)R)].EJ"KҥHRt)R)].EJ"KҥHRt)R)].EJ"KҥHRt)R)].EJ"KҥHRt)R)].EJ"KҥHRt)R)].EJ"KҥHRt)R)].EJ"KҥHRt)R)].EJ"KҥHRt)R)].EJ"KҥHRt)R)].EJ"KҵHZt-R)]EJ"kҵHZt-R)]EJ"kҵHZt-R)]EJ"kҵHZt-R)]EJ"kҵHZt-R)]EJ"kҵHZt-R)]EJ"kҵHZt-R)]EJ"kҵHZt-R)]EJ"kҵHZt-R)]EJ"kҵHZt-R)]EJ"kҵHZt-R)]EJ"kҵHZt-R)]EJ"kҵHZt-R)]EJ"kҵHZt-R)]EJ"kҵHZt-R)]EJ"kҵHZt-R)]EJ"kҵHZt-R)]EJ"kҵHZt-R)]EJ"kҵHZt-R)]EJ"kҵHZt-R)CDP"e(2HJ %R)CDʐ"eH2HR )R)C!Eʐ"eH2HR )R)C!Eʐ"eH2HR )R)C!Eʐ"eH2HR )R)C!Eʐ"eH2HR )R)C!Eʐ"eH2HR )R)C!Eʐ"eH2HR )R)C!Eʐ"eH2HR )R)C!Eʐ"eH2HR )R)C!Eʐ"eH2HR )R)C!Eʐ"eH2HR )R)C!Eʐ"eH2HZ -R)CE"eh2HZ -R)CE"eh2HZ -R)CE"eh2HZ -R)CE"eh2HZ -R)CE"eh2HZ -R)CE"eh2HZ -R)CE"eh2HZ -R)CE"eh2HZ -R)CE"eh2HZ -R)CE"eh2HZ -R)CE"eh2HZ -R)CE"eh2HZ -R)CE"eh2HZ -R)CE"eh2HZ -R)CE"eh2HZ -R)CE"eh2HZ -R)CE"eh2HZ -R)CE"eh2HZ -R)CE"eh2HZ -R)SDT"e*2HJL%R)SDʔ"eJ2HRL)R)S)Eʔ"eJ2HRL)R)S)Eʔ"eJ2HRL)R)S)Eʔ"eJ2HRL)R)S)Eʔ"eJ2HRL)R)S)Eʔ"eJ2HRL)R)S)Eʔ"eJ2HRL)R)S)Eʔ"eJ2HRL)R)S)Eʔ"eJ2HRL)R)S)Eʔ"eJ2HRL)R)S)Eʔ"eJ2HRL)R)S)Eʔ"eJ2HZL-R)SE"ej2HZL-R)SE"ej2HZL-R)SE"ej2HZL-R)SE"ej2HZL-R)SE"ej2HZL-R)SE"ej2HZL-R)SE"ej2HZL-R)SE"ej2HZL-R)SE"ej2HZL-R)SE"ej2HZL-R)SE"ej2HZL-R)SE"ej2HZL-R)SE"ej2HZL-R)SE"ej2HZL-R)SE"ej2HZL-R)SE"ej2HZL-R)SE"ej2HZL-R)SE"ej2HZL-R)SE"ej2HZL-R)KDR"e)HYJ,%R)KDʒ"eIHYR,)R)K%Eʒ"eIHYR,)R)K%Eʒ"eIHYR,)R)K%Eʒ"eIHYR,)R)K%Eʒ"eIHYR,)R)K%Eʒ"eIHYR,)R)K%Eʒ"eIHYR,)R)K%Eʒ"eIHYR,)R)K%Eʒ"eIHYR,)R)K%Eʒ"eIHYR,)R)K%Eʒ"eIHYR,)R)K%Eʒ"eIHYZ,-R)KE"eiHYZ,-R)KE"eiHYZ,-R)KE"eiHYZ,-R)KE"eiHYZ,-R)KE"eiHYZ,-R)KE"eiHYZ,-R)KE"eiHYZ,-R)KE"eiHYZ,-R)KE"eiHYZ,-R)KE"eiHYZ,-R)KE"eiHYZ,-R)KE"eiHYZ,-R)KE"eiHYZ,-R)KE"eiHYZ,-R)KE"eiHYZ,-R)KE"eiHYZ,-R)KE"eiHYZ,-R)KE"eiHYZ,-R)KE"eiHYZ,-R)[DV"e+HJl%R)[Dʖ"eKHRl)R)[-Eʖ"eKHRl)R)[-Eʖ"eKHRl)R)[-Eʖ"eKHRl)R)[-Eʖ"eKHRl)R)[-Eʖ"eKHRl)R)[-Eʖ"eKHRl)R)[-Eʖ"eKHRl)R)[-Eʖ"eKHRl)R)[-Eʖ"eKHRl)R)[-Eʖ"eKHRl)R)[-Eʖ"eKHZl-R)[E"ekHZl-R)[E"ekHZl-R)[E"ekHZl-R)[E"ekHZl-R)[E"ekHZl-R)[E"ekHZl-R)[E"ekHZl-R)[E"ekHZl-R)[E"ekHZl-R)[E"ekHZl-R)[E"ekHZl-R)[E"ekHZl-R)[E"ekHZl-R)[E"ekHZl-R)[E"ekHZl-R)[E"ekHZl-R)[E"ekHZl-R)[E"ekHZl-R)[E"ekHZl-R)?__o6!K3v0zVճ}W|gV=;߇U!zvճ}]|gW=;߇U!zvճ'UϮzv9=>DϮzvѳCg=>qg=>DϮzv?CU!zvճ}]uzgWއU'!zvI}]uzr^гNRC쪓DϮ:IѳNRC쪓嘞]uzgWއU'!zvI}]uzrճNRo=$>DϮ:IѳNRC쪓vB>l(icB>l*ԉcBmdvs;ٺN6o'MRǘ<$y9m11|(1`6s<~NҘǘy>Iss>1`u<N*ǘy>I(s0JLsr*0@ jc`#(Mc<%y95jZs ~PǘA<r>`?(c<%y961|z zGkz'/ꝼwz'/%y971|1`Ry9d81|1`<~Pzǘ R@H)r Eȁ9"R@یLUD-rEȁ9"Z@h-rEȁ9"Z@h-rEȁ9"Z@h-rEȁ9"Z@h-rEȁ9"Z@h-rEȁ9"Z@h-rEȁ9"Z@h-rEȁ9"Z@h-rEȁ9"Z@h-rEȁ9"Z@h-rEȁ9"Z@n`;!O`c6>`K!O`c6>`[!O`q rp rp rp rp rp rp rcdv""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""' )rB"' )rB"' )rB=< -rB"' -rB"' -rB"' -rB"' -rB"' -rB"' -rB"' -rB"' -rB"' -rB"' -rB"' -rB"' -rB"' -rB"' -rB"' -rB"' -rB"' -rB"' -rB"' -rB"' -rB"' -rB89q r@āȉ"'DN89q r[m=91|">`vrZāȉ"'DN89q r@āȉ"'DN89q r@āȉ"'DN89q r@āȉ"'DN89q r@āȉ"'DN89q r@āȉ"'DN89q r@āȉ"'DN89q r@āȉ"'DN89q r@āȉ"'DN89q r@āȉ"'DN89q r@āȉ"'DN89q r@āȉ"'DN89q r@āȉ"'DN89q r@āȉ"'DN89q r@āȉ"'DN89q r@āȉ"'DN&EN"IӤiR4)r9M&EN"iӴȹ *Ǜ9MEN"iӴiZ4-r9MEN"iӴiZ4-r9MEN"iӴiZ4-r9MEN"iӴiZ4-r9MEN"iӴiZ4-r9MEN"iӴiZ4-r9MEN"iӴiZ4-r9MEN"iӴiZ4-r9MEN"iӴiZ4-r9MEN"iӴiZ4-r9MEN"iӴi"v rځi"v rځi"v rځi"v rځi"v rځȹk`E}<lȹ9}91|"> `sZNy>iDN;9@DN;9@DN;9@DN;9@DN;9@DN;9@DN;9@DN;9@DN;9@DN;9@DN;9@DN;9@DN;9@DN;9@DN;9@DN;9@DN;9@DN;9@DN;9@DN;9@DN;9@DN;9@DN;9@DN;9@DN;9@DN;9@DN;9@DN;9@DN;9)ENJR9)ENJR9)ENJZ9EmW4Z9ENjZ9ENjZ9ENjZ9ENjZ9ENjZ9ENjZ9ENjZ9ENjZ9ENjZ9ENjZ9ENjZ9ENjZ9ENjZ9ENjZ9ENjZ9ENjZ9ENjZ9ENjZ9ENjZ9ENjZ9ENjZ"'DN<9y r@"'DN<9y r@"'DN<9y r@"'DN<9Áy>iss09-rc`GEN <ȹ999烝91|"'DN<9y r@"'DN<9y r@"'DN<9y r@"'DN<9y r@"'DN<9y r@"'DN<9y r@"'DN<9y r@"'DN<9y r@"'DN<9y r@"'DN<9y r@"'DN<9y r@"'DN<9y r@"'DN<9y r@"'DN.EN"KӥRt)r9].EN"kӵZt-rnCgEN"kӵZt-r9]EN"kӵZt-r9]EN"kӵZt-r9]EN"kӵZt-r9]EN"kӵZt-r9]EN"kӵZt-r9]EN"kӵZt-r9]EN"kӵZt-r9]EN"kӵZt-r9]EN"kӵZt-r9]EN"kӵ"~ r"~ r"~ r"~ r"~ r"~ r"~ r"~ r"~ r"~ r"~ r"~ r"1<ȹ9-91|">f{]~'~O?g~ѻ>G߼›O_?~?:ًן߿}_}K}//?W^|/._>'O޽)nc|/_~uO~svA׻qkէuo^{i廗&?'z~z𧯟zꧯ~ۯ}͋_><{gW_O^|bsǿ9o_yGJkG|/oQ^ b7_w޻_\~_]ֳ[w?μ|~nOq{_^~o./~߼z7_/_|/_~/|'ɟOn_~^_r>G'Wo???}n?H?ѧs?퇟ѿ0?__^>q>ɿ8?T(ca cl3Ʀ1c1vc1v;ºqΝs;87݃s?87 p`8w0; sù͹͹ͪO666666sӹ;Lsӹn-b;؝;؝;؝;؝;8;8;8;8;8;8usssssssssspttrrrrrrrv\ֆ[[ZZZZ[u/^z4 wDx4)wLc:uRY X5k`:ub֙ CX6m`:ur X7o`:uCX8q`:ȁu(YX9s`:ЁuH֙CX:u`:؁uhX;w`:uCX}`uֹOX>auֹOX>auֹOX>auֹOX>auֹOX>BǺ񐎧t<9X>auֹOX>auֹOX>auֹOX>auֹOX>auֹOX>auֹOX>aqCd0D6 Cd0D6 CdpD6 GdpD6 GdpD6 GdpD6 GdpD6 GdpD6 GdpD6 GdpD6 GdpD6 GdpD6 GdpD6 GdpD6 GdpD6 GdpD6 GdpD6 GdpD6 GdpD6 GdpD6 GdpD6 GdpD6 GdpD6 GdpD6 GdpD6 KdٰD6, KdٰD6, KdٰD6, KdٰD6, KdٰD6, KdٰD6, KdٰD6, KdٰD6, KdٰD6, KdٰD6, KdٰD6, KdٰD6, KdٰD6, KdٰD6, KdٰD6, KdٰD6, KdٰD6, KdٰD6, KdٰD6, KdٰD6, KdٰD6, KdٰD6, KdٰD6, KdٰD6, KdٰD6, KdٰD6, KdٰD6, KdٰD6, KdٰD6, KdٰD6, KdٰD6, KdٰD6, KdٰD6, KdٰD6, KdٰD6, KdٰD6, KdٰD6, KdٰD6, KdٰD6,Cd!a0Dv"; Cd#pDv8";Gd#pDv8";Gd#pDv8";Gd#pDv8";Gd#pDv8";Gd#pDv8";Gd#pDv8";Gd#pDv8";Gd#pDv8";Gd#pDv8";Gd#pDv8";Gd#aDvX";,Kd%aDvX";,Kd%aDvX";,Kd%aDvX";,Kd%aDvX";,Kd%aDvX";,Kd%aDvX";,Kd%aDvX";,Kd%aDvX";,Kd%aDvX";,Kd%aDvX";,Kd%aDvX";,Kd%aDvX";,Kd%aDvX";,Kd%aDvX";,Kd%aDvX";,Kd%aDvX";,Kd%aDvX";,Kd%aDvX";,Kd%aDvX";, ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,NCd!i4Dv"; NCd#tDv:";NGd#tDv:";NGd#tDv:";NGd#tDv:";NGd#tDv:";NGd#tDv:";NGd#tDv:";NGd#tDv:";NGd#tDv:";NGd#tDv:";NGd#tDv:";NGd#iDvZ";-NKd%iDvZ";-NKd%iDvZ";-NKd%iDvZ";-NKd%iDvZ";-NKd%iDvZ";-NKd%iDvZ";-NKd%iDvZ";-NKd%iDvZ";-NKd%iDvZ";-NKd%iDvZ";-NKd%iDvZ";-NKd%iDvZ";-NKd%iDvZ";-NKd%iDvZ";-NKd%iDvZ";-NKd%iDvZ";-NKd%iDvZ";-NKd%iDvZ";-NKd%iDvZ";- ------------------------------------------------------------------------------------------------------------------------------------------------------------= = = = = = = = = = ===========================================================================================,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,=,= = = = = = = = = = ===========================================================================================-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, ------------------------------------------------------------------------------------------------------------------------------------------------------------}|>#?'|8lc8qm}~S[hCcxmEcxmGcxmIcxmKcx+W^h^h^h^h^hҺ*>ں*>ں*   =ֽ4^}u/W{iwmKտho kKտh^ݗֽ4^}u/W u/W{iwmKտh^G[x>]Zx}u/W{iwmKտh^Ggacw\`>{Gƫޡ:}{U<2s < 2 ?'{]΃UH]NU`q]ΆUxý9D1ܻ1ý9P1ܻac͗W9^1ܻޙCý9j1ܻɑý9v>;>rcwW$?{w;Dr cwWs$?{w;Jr$cwW$?q{w;Qr@cwWC%ǔ?{w;WrXcwW%GjpO/xgK. wp0xgK1ΖeUlɁ]ΖkUȕF]5Lmdr#;[rcwW%Ǟ?{w;[rcwW%G߇{gKA w0pzgKD w`pzgKG 7qWt8"H#t8"H#t8"vS[hCgKD:,KD:,KD:,KD:,KD:,KD:,KD:,KD:,KD:,KD:,KD:,KD:,KD:,KD:,KD:,KD:,KD:,KD:,KD:,KD:,KD:,KD;,p^5 W ýUpy>;4p^5'tx"H'tx">ܻQwdtx"H'tx"H'tx"H'tx"H'tx"H'tx"H'tx"H'tx"H'tx"H'tx"H'tx"H'tx"H'tx"H'tx"H'tx"H'tx"H'tx"H'tx"H'tx"H'tx"H'tx"H'tx"H'tx"H'tx"H'tx"H'tx"H'tx"H'tx"H'tx"H'tx"H'tx"H'tx"H'tx"H'tx"H'pDz8"=HG#DmucX"=,HK%aDzX"=,HK%aDzX"=,HK%aDzX"=,HK%aDzX"=,HK%aDzX"=,HK%aDzX"=,HK%aDzX"=,HK%aDzX"=,HK%aDzX"=,HK%aDzX"=,HK%aDzx"=<HO'Dzx"~cyw<2Oc <2Ọ ,ɞwW K߇{w;D}wWS!K'Dzx"=<HO'Dzx"=<HO'Dzx"=<HO'Dzx"=<HO'Dzx"=<HO'Dzx"=<HO'Dzx"=<HO'Dzx"=<HO'Dzx"=<HO'Dzx"=<HO'Dzx"=<HO'Dzx"=<HO'Dzx"=<HO'Dzx"=<HO'Dzx"=<HO'Dzx"9"9"9"9"9"9"9"9"9"9"Y"Y"6ںzY"Y"Y"Y"Y"Y"Y"Y"Y"Y"Y"Y"Y"Y"Y"Y"Y"Y"Y"Y"Y"Y"Y"Y"Y"Y"Y"Y"Y"Y"Y"Y"Y"Y"Y"Y"Y"Y"Y"Y"Y"Y"Y"Y"Y"Y"Y"Y"Y"Y"Y"Y"Y"Y"Y"Y"Y"Y"Y"Y"Y"Y"Y"Y"Y"Y"Y"Y"Y"Y"Y"Y"Y"Y"Y"Y"Y"Y"Y"Y"Y"Y"Y"Y"Y"Y"y"y"y"y"y"y"y"y"y"y"y"y"y"y"y"y"y"y"y"y"~U4],~UL],~nzw;D}wW!K߇{w; DzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDzDz:"=HOG#tDz:"=HOK%o,iDzZ"=-HOK%iDzZ"=-HOK%iDzZ"=-HOK%iDzZ"=-HOK%iDzZ"=-HOK%iDzZ"=-HOK%iDzZ"=-HOK%iDzZ"=-HOK%iDzZ"=-HOK%iDzZ"=-HOK%iDzZ"=-HOO'Dzz"==HOO'Dzz"==HOO'Dzz"==HOO'DԻ޹%ý Y">ܻ%lz'DH7ύY">ܻA%Dzz"==HOO'Dzz"==HOO'Dzz"==HOO'Dzz"==HOO'Dzz"==HOO'Dzz"==HOO'Dzz"==HOO'Dzz"==HOO'Dzz"==HOO'Dzz"==HOO'Dzz"==HOO'Dzz"==HOO'Dzz"==HOO'nnnnh6:nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnk]Ί,~U]N,~~zWq >~Ǟ;y{zcO} ={>ֹok`o{w} v1عk`g=d;x} v 1عǫGo9wxlէs׬<^>;wxucsר3sW<^>;wxUxw1عǫ`kucsנ<~1ع/Y>;w`kW+;xZc=W*;x:cs_| <~1ع/P>;w`8&ݠs_|{_|ɇ~ه;軿ѧ?|}A#ܟًן߿}_}KׯqǿzϿxqy?|Oq7w/K ݾލzէuo^{I\.//߽oKw˟gYß~ϿoۣS?_#G\1G?zϷ^۰__:{q/|:z_w^/߿^:'r_~wȫ_Ջ.~?s] i=r/ի^|so_=ۧ_~ۿ?˟xyW_~w߾~~y_?Oo_ū_n/}}//y-ԗ?_>o<|w/}믾x~UC~󗗯|W_}}.~|p?/ۿv_>_^n?y>|/nO~~ۧ}>G?_Ï>凷^yy{~}U>OoOgƏ/>/?~p_~pˏ?g~r{}>>F]~{Ƿ}r>_~v~}_~#_"/ߦߟ.oe?{>_~W|nW?~OnC?_OW?Y>1;wqo>M¯޿}ߠ[p[F˟|埼Χg>쳏g?_׷n}[տ-]/.ỸϿxWΟÿ o/?ݥ_ۏoݾߟ=>_pnSo^7yg'Iٳ/^|g0_ ņ?}'!|M}b?}//xŦbbb>? o[/^?lU.?5.w~O&}3N_/ߞui.{7.B3v^xoiᄎ]߼|~W^ﯿx /Od;?eWpo",F~޽w; p wg/0ПO޿wVg9\wfV_ٿj{VMW[7\VW^~SKws{m\>ܶg/.K|7oWR~K=WO'qs5_==;o>|_Oo۳7gg3~{c!z6ۿϟƛ~>ˏuƟ6߾ M'ȷe's{=]1Q>n,(*z-p2Qzqԫ^PDMQDM5AQDM5A ZMhkV&h5A &Ț k k &Ț k^&MX&5 FM0jQ`AM0jQ`&5 fM0kI?5 fMjU`&X5 AMj]`&5 vMkMčDtNR)]TKW+ӕJt,o#e䚤%PWԖ%0A LPge&8A NPwԞDeU(CA% jQPzT&ETBe jSPTFU*SAzTfU+[A jWP*Ա,fA= *ZPӂW>T.qA \PZanPnPnPnPnz7wz7wz7wz7x} ԷVרHU*/Sy Uݠ h\,ԻAԻAԻAԻAԻv,ԻAԻAԻAԻAԻy#Cʎ eG#CّY<|<ǫ|ʨF6Qzy@M5A^DM5AQDM5A&h5A ZMjV&Ț k j &Ț k zMk^7aMk^&5 FM0jA?5 FM0jY̚`&5 &(&5 VMjU`&X5 vMk]`&5 67Uҕ:JtVR-]TLWj+UӕU +;K[kzTjB] *KP[ԗ5&2AOjԛ5':A *OP{bT(EA5 QPR) )MAu SPTN*?SUPTn+]A WL^lPXPǂJԲ,hAM Z,^Pj[P݂TU.sA j]l^:bԻAԻAԻAԻAԻ^Rݠ ݠ ݠ )/PZR^"WLu*/Twz7wrPnPnPnPnPFڝPnPnPnPnPFYȢȢȢȢY<|<ǫ|ʨF6Qzy@M5A^DM5AQDM5A&h5A ZMjV&Ț k j &Ț k zMk^7aMk^&5 FM0jA?5 FM0jY̚`&5 &(&5 VMjU`&X5 vMk]`&5 67Uҕ:JtVR-]TLWj+UӕU +;K[kzTjB] *KP[ԗ5&2AOjԛ5':A *OP{bT(EA5 QPR) )MAu SPTN*?SUPTn+]A WL^lPXPǂJԲ,hAM Z,^Pj[P݂TU.sA j]l^:bԻAԻAԻAԻAԻ^Rݠ ݠ ݠ )/PZR^"WLu*/Twz7wrPnPnPnPnPFڝPnPnPnPnPFYZّ#keGʎY{V?(*z-p2Qzqԫ^PDMQDM5AQDM5A ZMhkV&h5A &Ț k k &Ț k^&MX&5 FM0jQ`AM0jQ`&5 fM0kI?5 fMjU`&X5 AMj]`&5 vMkMčDtNR)]TKW+ӕJt,o#e䚤%PWԖ%0A LPge&8A NPwԞDeU(CA% jQPzT&ETBe jSPTFU*SAzTfU+[A jWP*Ա,fA= *ZPӂW>T.qA \PZanPnPnPnPnz7wz7wz7wz7x} ԷVרHU*/Sy Uݠ޽w ~w=~O>}wO?zݧ=~GO}>=ӳ}z}wO?zݧ=~~ͣ}*~w=>=ӳ}~GOGO>}wO?zݧ}zݧ>=ӳ}zݧ=~GO}>}}xLYwz7wz7wz7wz7w#yNYwz7wz7wz7wz7wF,YvdYvdYvdYvdYvd~Q>U>ZtzeK^WG[+TkT^*N*nPn4^.Sݠ ݠ ݠ ݠ H^Sݠ ݠ ݠ ݠ 輑!(;QvdFّ#Y>^]EWF4Q/zuˣ^5j j & j &h5A MMjV&h5AYdMPdM5AYdMk^ k^&5 FM0jQ 9 FM0jQ̚`&5 fM0G&5 VMjU`&X56 VMk]`&5 vMIW*+ҕjJtbR3]z,\ܐ\ܑ\ܒ\ԓDpWSJPYT&1A L4~,T'9A NPyTH~,Ԡ u(DA- QPԤJYLAm SP ԨJu*T1PԬju+\A WPbbPł:T,gAE jZPbʇPۂԷ5.rA *]Pb2a ݠ ݠ ݠ ݠ 𢐲PnPnPnPOy Je*SyJԻA˔z7wz7wz7wz7wz7z7wz7wz7wz7wz7:o$~2ˎl,;YvdyFxWxkхQ/zmԋ^G j& j & j ZMjF_&h5A ZM5AY$}YdM5AY&5Aoš&5A FM0jQ`~jQ`&5 fM0kYLQ fM0kU`&X5 VM jU`&5 vMk]l*$n$+uҕJJtZR/]LW+ey) $7$W$w$$$$$(ՔT%/A jLPe:8( &7A jNPuT'( 5(BA *QPjԣ"5):?R*SPԧB5*RA *U ~~,ԫb5+ZA *WPԯؠ,T,eA5 YPтTX,Զ-pA \PJԺؼ u-Ĩwz7wz7wz#kOWX<=j|zzϧQ)=ӛG=<,Oeyzϧ7({>yDK|z<ӛG=,ע +?{>=OO5{>=S}O=<,Oeyzϧ7({>yDY#OoQ|Ã=[<{>u{>y]MY#OoQ|z<ӛG{zϧ7({>yDY*z-p{>=AMOOxP<{>GAY#OoQ|z<ӛG=<,Oeyzϧ?< =߹5{>=Q'=ӛGՔ=<,Oeyzϧ7({>yDK|z<ӛG=,ע +?{>=OO5{>=S}O=<,Oeyzϧ7({>yDY#OoQ|Ã=[<{>u{>y]MY#OoQ|z<ӛG{zϧ7({>yDY*z-p{>=AMOOxP<{>GAY#OoQ|z/O-Ȩw(,ԻAԻAԻAԻS^B,FE*RyT^RnPF2e ݠ ݠ ݠ ݠލ;e ݠ ݠ ݠ ݠލ#[eGʎl*;~Q>U>ZtzeK^WG[+TkT^*N*nPn4^.Sݠ ݠ ݠ ݠ H^Sݠ ݠ ݠ ݠ 輑!A>>ۨf}M%(K|P,AYe %(K,49QFYeiQFY$eIʒBY$eIʒ%)K,t)Ko[)K,t2(ˠ, 2(!2(ˠ,L2)ˤ,L2)h2)ˤ,,ʲ(ˢ,,ʲ(v,lʲ)˦,lʲ)˦,lmw庻r]xW+wޕKʩޮ`NV o[=VoU1w1o=3p*cp!\N2 e8W3 ngp=\W4QN- ipOw5m;76 .mpkkxk nop}\W81Z q*qp*w9msh\N:up[kG^ۨf}M%(K|P,AYe %(K,49QFYeiQFY$eIʒBY$eIʒ%)K,t)Ko[)K,t2(ˠ, 2(!2(ˠ,L2)ˤ,L2)h2)ˤ,,ʲ(ˢ,,ʲ(v,lʲ)˦,lʲ)˦,lmw庻r]xW+wޕKʩޮ`NV o[=VoU1w1o=3p*cp!\N2 e8W3 ngp=\W4QN- ipOw5m;76 .mpkkxk nop}\W81Z q*qp*Hz~?]Z֖ŎZG}Q_訯sԗ9׺'Qzqԫ^PDMQDM5AQDM5A ZMhkV&h5A &Ț k k &Ț k^&MX&5 FM0jQ`AM0jQ`&5 fM0kI?5 fMjU`&X5 AMj]`&5 vMkMčDtNR)]TKW+ӕJt,o#e䚤%PWԖ%0A LPge&8A NPwԞDeU(CA% jQPzT&ETBe jSPTFU*SAzTfU+[A jWP*Ա,fA= *ZPӂW>T.qA \PZanPnPnPnPnz7wz7wz7wz7x} ԷVרHU*/Sy Uݠ h\,ԻAԻAԻAԻAԻv,ԻAԻAԻAԻAԻy#Qvz_I=!ݑ??>>>>ӱ>ӡ>ӑ>Ӂ>q>a>Q>A>1>!>>>====ӱ=ӡ=ӑ=Ӂ=q=a=Q=A=1=!===<<<<ӱ<ӡ<ӑ<ӁT.qA \PZanPnPnPnPnz7wz7wz7wz7x} ԷVרHU*/Sy Uݠ h\,ԻAԻAԻAԻAԻv,ԻAԻAԻAԻAԻy#C,;,;,;,;,;|V?(*z-p2Qzqԫ^PDMQDM5AQDM5A ZMhkV&h5A &Ț k k &Ț k^&MX&5 FM0jQ`AM0jQ`&5 fM0kI?5 fMjU`&X5 AMj]`&5 vMkMčDtNR)]TKW+ӕJt,o#e䚤%PWԖ%0A LPge&8A NPwԞDeU(CA% jQPzT&ETBe jSPTFU*SAzTfU+[A jWP*Ա,fA= *ZPӂW>T.qA \PZanPnPnPnPnz7wz7wz7wz7x} ԷVרHU*/Sy Uݠ h\,ԻAԻAԻAԻAԻv,ԻAԻAԻAԻAԻy#C^vdzّ#eG֟3dz|ǻ^.\zik^ꨗG>jQ}5AQDM5AQDMjV4&h5A ZMj &Ț ;&Ț k &Ț&5A :}&5A zM0jQ`&sP`&5 fM0kY̚`ҏbM0kY`&X5 VMjEmP`&5 vMk]`S!q#Q%]TJWj+ҕzJtfR5])[HY !"#$%&'AE஦,ԕ%.A} *LPc*ԙhAY6A *NPsԝ'>,FYAA PPZT)I)PT>*QA TPb;e^+YA VPT~eu,dA- YPςԴe-oA j\P:Teh!FԻAԻAԻAԻAE!e ݠ ݠ ݠ ^*e5*/RyT^Bz7wz7/) nPnPnPnPn$) nPnPnPnPntHe(;QvdFّg,ע +^ڨG:Q5AA_{M5AQDM5AQ&h5A ZMjV k &H &Ț k &5A zMkN߄5A zMk^`&5 &5 fM0kY̚`&X̚`&X5 VMjU`Q&5 vMk]`&THHTIW+ҕZJt^R1]TMWV=R.HnHHH.InIIIPQ") u%,Am KP_ Ԙu&?qPMPoԜu'= -6w$R%$m=ҺFDJ2`w$E .k  )[1 * <*I d*@ *0@ *9w *P *ЫR0 +p@ 4+@ T+%# |+ +R1 c@ UxW]wUxW]wUaPxW]wUxW]w) B cTR2Ne *& *» *» j,» *» *fHTGVYezdUGVm9y]ץy]mavb7-vb7.vb7/vb%PvK@-Zj %H,Ab ~KX$ %H,Aj RKZ5 %H-Aj 2KYd C%%,Af 2K[ %qX %(,Aa KPX8-Aa KPZ%(-Ai J%,Ae *KPYTh$()bH)bh)b)b)KGP4$IGR$5 O D)JWR`K.S`L2Δ XM7SN;SOIي(TPDhTQH&M*X SM:T TQJ8U Uپ^U`VZnU`W^~XXcXVYgVZ)V[p(W\t֕a0b» *» * B *» *O*X2He0q*UxW]w5a xW]wUxW]wUxWS`wUxW]wUxW]w5cGǾFľI7}S76J0  D@"@(X, E`Q(X$`Ixp%K, X`I%eMK ,)XR`%K,X2d`%K,9XrC`%K,X `)RK,%XJ`)RK vK ,X*T`RK \GŴ]L]L4^Lt^LŤ L@ D8P1],h2> YhdNJYhe^$hHE5 ,B= ,BEKzZ(jZ(k% wRQBc -tPBk -PܒQn[o*\p)`TԸB M.TB m.ԹAF*]tӅRZ]uׅb] t bGtJ+ݮtJ+ݮtJҒnW]vەnW]v #mRvlvnvpJ+ݮI ݮtJ+ݮtJ+ݮi/!ݮtJ+ݮtJ+ݮY]2Tb{b{b{b{b{Fi}S7}SaDB@!p@$E?`Q(X, %K, X$`I%K ,)XR`I%K ,X2d`Xm%K ,9Xr`%9,9Xr`)RK,Oh`)RK ,%XJ`)i`RK ,X*T`u]L]L^LT^LŔ^LP $X8p@āB-cF*YdVjYeITTB9 ,ԳBA -TA;J*ZZiZjZy'-4PBg -PBo -yu[ho \hp…"HE =.B ].BKhхJ:](uՅZz](v٥ B vdH+ݮtJ+ݮtJ!-vەnW]vەn 0&Ukvmvo7ݮtRJ+ݮtJ+ݮtRJ+ݮtJ+ݮt%CGGGGGm7}S76J0  D@"@(X, E`Q(X$`Ixp%K, X`I%eMK ,)XR`%K,X2d`%K,9XrC`%K,X `)RK,%XJ`)RK vK ,X*T`RK \GŴ]L]L4^Lt^LŤ L@ D8P1],h2> YhdNJYhe^$hHE5 ,B= ,BEKzZ(jZ(k% wRQBc -tPBk -PܒQn[o*\p)`TԸB M.TB m.ԹAF*]tӅRZ]uׅb] t bGtJ+ݮtJ+ݮtJҒnW]vەnW]v #mRvlvnvpJ+ݮI ݮtJ+ݮtJ+ݮi/!ݮtJ+ݮtJ+ݮY]2T&Gib{&m7}S76J0  D@"@(X, E`Q(X$`Ixp%K, X`I%eMK ,)XR`%K,X2d`%K,9XrC`%K,X `)RK,%XJ`)RK vK ,X*T`RK \GŴ]L]L4^Lt^LŤ L@ D8P1],h2> YhdNJYhe^$hHE5 ,B= ,BEKzZ(jZ(k% wRQBc -tPBk -PܒQn[o*\p)`TԸB M.TB m.ԹAF*]tӅRZ]uׅb] t bGtJ+ݮtJ+ݮtJҒnW]vەnW]v #mRvlvnvpJ+ݮI ݮtJ+ݮtJ+ݮi/!ݮtJ+ݮtJ+ݮY]2T푦Gij{푦m7}S76J0  D@"@(X, E`Q(X$`Ixp%K, X`I%eMK ,)XR`%K,X2d`%K,9XrC`%K,X `)RK,%XJ`)RK vK ,X*T`RK \GŴ]L]L4^Lt^LŤ L@ D8P1],h2> YhdNJYhe^$hHE5 ,B= ,BEKzZ(jZ(k% wRQBc -tPBk -PܒQn[o*\p)`TԸB M.TB m.ԹAF*]tӅRZ]uׅb] t bGtJ+ݮtJ+ݮtJҒnW]vەnW]v #mRvlvnvpJ+ݮI ݮtJ+ݮtJ+ݮi/!ݮtJ+ݮtJ+ݮY]2TfGif{fm7}S76J0  D@"@(X, E`Q(X$`Ixp%K, X`I%eMK ,)XR`%K,X2d`%K,9XrC`%K,X `)RK,%XJ`)RK vK ,X*T`RK \GŴ]L]L4^Lt^LŤ L@ D8P1],h2> YhdNJYhe^$hHE5 ,B= ,BEKzZ(jZ(k% wRQBc {Ydzb&m.GfrmGfqmH'Nl؆97vb/@,Zoj %PK@-Z$ %H,Ab KX %HQ,Aj RKZ %,Af 2TBKYd %-An rK[%-An rKPX%(,AS%(-Ai JKPZ ,Ai *KPYT%,Ae *Fb8)bX)bx)b)bz ICRt$%IKR@t5XJ,RK0(SLIpxS N9S O=X`PBHT`QFT`Rؤ2TSOBUTSR;XUXfUV\vUW)l8V YexV ZiX`[nW`\rHW`]1C *» *» 0( » *»j1*TF S2PwUxW`wUxW]wUxW]w5exW]wUxW]wUxW3v$LCQh;mǠv?g >cCy1}!F11g 9cop3F1،f 5cg03F1Ȍ1f 1c_2F1e -cdWư2F11e )cDOp2F1d %c$G02F11d !c?1F1xc c7ư1F1h1c c/p1F1Xb c'01F1H1bs0G98̱a sd0G9(1a sDp0G9̱`s$00G91`s/G9˱_r/G}91_rėp/G{9˱^r9ӎ8눓8S88߈Ӎ8ۈ8׈S8ӈ8ψӌ8ˈ8LjS8È8Ӌ88S88ӊ88S88Ӊ88S88ӈ88S88Ӈ8{8wS8s8oӆ8k8gS8c8_Ӆ8[8WS8S8Oӄ8K8GS8C8?Ӄ8;87S#l6?l&?il?$C?C?$C>C>$C>C>$C>C>$C>C>$C>C>$C>C>$C>C>$C>C>$C~>Cv>$Cn>Cf>$C^>CV>$CN>CF>$C>>C6>$C.>C&>$C>C>$C>C>$C=C=$C=C=$C=C=$C=C=$C=C=$C=c=&c=c=&c=c=&c~=cv=&cn=cf=&c^=cV=&cN=cF=&c>=c6=&c.=c&=&c=c=&c=c=&c;fl.;fl;fC;C ;dC;C:dC:C:dC:C:dC:C:dC:C:dC:C:dC:C:dC:C:dC:Cz:dCr:Cj:dCb:CZ:dCR:CJ:dCB:C::dC2:C*:dC":C:dC:C :dC:C9dC9C9dC9C9dC9C9dC9C9dC9c9fc9c9fc9c9fc9cz9fcr9cj9fcb9cZ9fcR9cJ9fcB9c:9fc29c*9fc"9c9fc9c 9fc9c8fc8c8fc8c8fc8c8fc8c8fc8c8fc8c8fc8c8fc8cz8fcr8cj8fcb8cZ8fcR8cJ8fcB8c:8fc28c*8fc"8c8fc8c 8fc8c7fc7~c7f~c7}c7f}c7|c7f|c7{c7f{c7zc7fzc7yc7fyc7xc7fxc7wcz7fwcr7vcj7fvcb7ucZ7fucR7tcJ7ftcB7sl67rl&7qil7$qC7pC7$pC6oC6$oC6nC6$nC6mC6$mC6lC6$lC6kC6$kC6jC6$jC6iC6$iC6hC6$hC~6gCv6$gCn6fCf6$fC^6eCV6$eCN6dCF6$dC>6cC66$cC.6bC&6$bC6aC6$aC6`C6$`C5_C5$_C5^C5$^C5]C5$]C5\C5$\C5[C5$[C5Zc5&Zc5Yc5&Yc5Xc5&Xc~5Wcv5&Wcn5Vcf5&Vc^5UcV5&UcN5TcF5&Tc>5Sc65&Sc.5Rc&5&Rc5Qc5&Qc5Pc5&Pc4Oc4&Oc4Nc4&Nc4Mc4&Mc4Lc4&Lc4Kc4&Kc4Jc4&Jc4Ic4&Ic4Hc4&Hc~4Gcv4&Gcn4Fcf4&Fc^4EcV4&EcN4DcF4&Dc>4Cc64&Cc.4Bc&4&Bc4Ac4&Ac4@c4&@c3?c3&?c3>c3&>c3=c3&=c33f3l.3f2l3f1C30C 3d0C3/C2d/C2.C2d.C2-C2d-C2,C2d,C2+C2d+C2*C2d*C2)C2d)C2(C2d(C2'Cz2d'Cr2&Cj2d&Cb2%CZ2d%CR2$CJ2d$CB2#C:2d#C22"C*2d"C"2!C2d!C2 C 2d C2C1dC1C1dC1C1dC1C1dC1C1dC1c1fc1c1fc1c1fc1cz1fcr1cj1fcb1cZ1fcR1cJ1fcB1c:1fc21c*1fc"1c1fc1c 1fc1c0fc0c0fc0 c0f c0 c0f c° = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =r#M,7=-'7 4+-lnYn[n]n_,Xn %PK@-Z%H,Ao KX$ %H-Aj RKX %H-Af 2KYd %,Af rK[ 9K[䖠%(,Aa KPX%(,Aa JKPZ%(-A XT%,Ae *KPYT%pR )ŰR -R 10S 5`  "HJ&I(EjY l)Хa )P )@s )p@{ ))[1 * <*I d*@ *0@ *9w *P *ЫR0 +p@ 4+@ T+%# |+ +R1 c@ UxW]wUxW]wUaPxW]wUxW]w) B cTR2Ne *& *» *» j,» *» *fHGVYazdGVm9y]ץy]mavb7-vb7.vb7/vb%PvK@-Zj %H,Ab ~KX$ %H,Aj RKZ5 %H-Aj 2KYd C%%,Af 2K[ %qX %(,Aa KPX8-Aa KPZ%(-Ai J%,Ae *KPYTh$()bH)bh)b)b)KGP4$IGR$5 O D)JWR`K.S`L2Δ XM7SN;SOIي(TPDhTQH&M*X SM:T TQJ8U Uپ^U`VZnU`W^~XXcXVYgVZ)V[p(W\t֕a0b» *» * B *» *O*X2He0q*UxW]w5a xW]wUxW]wUxWS`wUxW]wUxW]w5cG⌥4=J#+M4=m¼.n [iq[y @-[j %PK@-Ab K`[$ %H,Ab RKZ %H-Aj RKYd *%,Af 2KY %-A %(,Aa KPXh KPX%(-Ai JKP%,Ae *KPYTD#AI1CJ1CK1CL1CM1X=!H:%IxR JQ,p@[ t)@c )p$l8m )u )}JV ,0@ $*@ D*0dlR l*Щ *PJ,@ *p@ * 6 + <+J,@ +0@ +T !wUxW]wUxW]wUUxW]wUxW]e|5PA*TS» * e *» *»2v » *» *;g,UGVYezdUm[Nn^ui^Wv[ذݲMݶ؍ݺ͋ݾXj %PK@-Zj KX$ %H,Ab KZ E %H-Aj RKZd %P -Af 2KY %-An r %-Aa KPXNEKPX%(-Ai JKPZ6%,Ae *KPYT% $ JRaZbaj,$ IEґ$-IM“Q`+RK/SL3%ahSM8SN<SRb`A 8T QExT RI%c T`SN>U`TRNHUr`WbUV[rUW_`(VXdhVYhVJF>`mV \q8W ]ub8 » *» * ,» *» *SA ƨ R2Le@UxW]M.UxW]wUxW]wՔ;X]wUxW]wUxW]ؑ8coľQ&oRMaߔM C!P, E`Q(X, , X$`I%K,)XR`IYS%K ,)X2d`%cK ,X2`%KXr`RK,X  |+ +R1 c@ UxW]wUxW]wUaPxW]wUxW]w) B cTR2Ne *& *» *» j,» *» *fHn)vQR;HjH!(FG18Q bdŰ(FE1(1Q bDp(FC1P b$0(FA11P b'F?1O }bİ'F=11O ybp'F;1؉N ub0'F91ȉ1N qb&F71M mbdİ&F511M ibDp&F31L eb$0&G191Lar%G/9xɱK]r%G-9h1KYrĒp%G+9XɱJUr0%G)9H1JNNN|NlN\NLN<N,NN NNNNNNNNN|NlN\NLN<N,NN NNAL#=2AL#=2AL#yxwtvduTtDs4r$qponmlkjihgtfdeTdDc4b$a`_^ALMLMLMLMLML۶ܼ.Ҽ춰aemu}b (~%PK@-Zj $  v%H,Ab KX$ %H-A` RKZ %,Af 2KZd %-An rK[8,An rK[%(,Aa %(-Ai JKPZ%l` JKPYT%,Ae *KPAH4I1J1K1L1%#X(H#)IZ'W d)@_ )0@gJ†,Цq )Py )Чl *p@ 4*@J&, |* *l *0@ *@J`,P ,+Ь L+P| t+@ +p@J0q1xW]wUxW]wUxWA!X]wUxW]wUƧ P,Q2Je8*»0\ » *» *)cw *» *»#qƒYbzd%GYҶua^ue -ݴmݸحݼK@-Zj %PK %H-Ab KX$ %H-Aj RKZ %,Af 2KY d %,An rK[ y` rK[%(,Aa KPT%(,Ai JKPZ%(aKPZT%,Ae *KPY BN!V^!f,BAҐT$IIҒ$<)(] R K-R L18S6`6S`N:S`O>%e+TPCXTQG"T26`L6TSPF(UTT%gxU VYjU W]zU `bHV`YfV`ZjdV[oW\sXW*a *» *»* *» *2>eD`a Q*TƩ T]wՄ2X]wUxW]wUxW]MUxW]wUxW]wՌ3R#KM,5=Ҷ-'7 4+-lnYn[n]n_,Xn %PK@-Z%H,Ao KX$ %H-Aj RKX %H-Af 2KYd %,Af rK[ 9K[䖠%(,Aa KPX%(,Aa JKPZ%(-A XT%,Ae *KPYT%pR )ŰR -R 10S 5`  "HJ&I(EjY l)Хa )P )@s )p@{ ))[1 * <*I d*@ *0@ *9w *P *ЫR0 +p@ 4+@ T+%# |+ +R1 c@ UxW]wUxW]wUaPxW]wUxW]w) B cTR2Ne *& *» *» j,» *» *fHdGYfzdeGm9y]ץy]mavb7-vb7.vb7/vb%PvK@-Zj %H,Ab ~KX$ %H,Aj RKZ5 %H-Aj 2KYd C%%,Af 2K[ %qX %(,Aa KPX8-Aa KPZ%(-Ai J%,Ae *KPYTh$()bH)bh)b)b)KGP4$IGR$5 O D)JWR`K.S`L2Δ XM7SN;SOIي(TPDhTQH&M*X SM:T TQJ8U Uپ^U`VZnU`W^~XXcXVYgVZ)V[p(W\t֕a0b» *» * B *» *O*X2He0q*UxW]w5a xW]wUxW]wUxWS`wUxW]wUxW]w5cG%7=r#M,7=m¼.n [iq[y @-[j %PK@-Ab K`[$ %H,Ab RKZ %H-Aj RKYd *%,Af 2KY %-A %(,Aa KPXh KPX%(-Ai JKP%,Ae *KPYTD#AI1CJ1CK1CL1CM1X=!H:%IxR JQ,p@[ t)@c )p$l8m )u )}JV ,0@ $*@ D*0dlR l*Щ *PJ,@ *p@ * 6 + <+J,@ +0@ +T !wUxW]wUxW]wUUxW]wUxW]e|5PA*TS» * e *» *»2v » *» *;g,GVYazdm[Nn^ui^Wv[ذݲMݶ؍ݺ͋ݾXj %PK@-Zj KX$ %H,Ab KZ E %H-Aj RKZd %P -Af 2KY %-An r %-Aa KPXNEKPX%(-Ai JKPZ6%,Ae *KPYT% $ JRaZbaj,$ IEґ$-IM“Q`+RK/SL3%ahSM8SN<SRb`A 8T QExT RI%c T`SN>U`TRNHUr`WbUV[rUW_`(VXdhVYhVJF>`mV \q8W ]ub8 » *» * ,» *» *SA ƨ R2Le@UxW]M.UxW]wUxW]wՔ;X]wUxW]wUxW]ؑ8c)M4=J#+Mlrr0K†nZn\n^%PK@-Zj %PKX$ %H,Ab KX )j%H-Aj RKZd %,AJh 2KYd %-An rK<%-An KPX%(p*Z%(-Ai JKPZ%(-Ae *KPYT%,A!HPR 'ŐR +R /S 3PS @` iH*$iIjR \)] |)e ) @o )0@w )@ *P ,*Ш L*T@ t*@ *p@} * * * @ $+@ D+0@R2 l+Э +P +0a]wUxW]wUxW]`wUxW]wUxW2@ "T0Fe(a*T» jp,» *» *𮦌*» *» jƎKezdUGVYezdUׅۖy]ו6l,vb-vb.vb/@,Zoj %PK@-Z$ %H,Ab KX %HQ,Aj RKZ %,Af 2TBKYd %-An rK[%-An rKPX%(,AS%(-Ai JKPZ ,Ai *KPYT%,Ae *Fb8)bX)bx)b)bz ICRt$%IKR@t5XJ,RK0(SLIpxS N9S O=X`PBHT`QFT`Rؤ2TSOBUTSR;XUXfUV\vUW)l8V YexV ZiX`[nW`\rHW`]1C *» *» 0( » *»j1*TF S2PwUxW`wUxW]wUxW]w5exW]wUxW]wUxW3v$XoԾIԾAi}S7}SaDB@!p@$E?`Q(X, %K, X$`I%K ,)XR`I%K ,X2d`Xm%K ,9Xr`%9,9Xr`)RK,Oh`)RK ,%XJ`)i`RK ,X*T`u]L]L^LT^LŔ^LP $X8p@āB-cF*YdVjYeITTB9 ,ԳBA -TA;J*ZZiZjZy'-4PBg -PBo -yu[ho \hp…"HE =.B ].BKhхJ:](uՅZz](v٥ B vdH+ݮtJ+ݮtJ!-vەnW]vەn 0&Ukvmvo7ݮtRJ+ݮtJ+ݮtRJ+ݮtJ+ݮt%C%G*G*G*G*G*m7}S76J0  D@"@(X, E`Q(X$`Ixp%K, X`I%eMK ,)XR`%K,X2d`%K,9XrC`%K,X `)RK,%XJ`)RK vK ,X*T`RK \GŴ]L]L4^Lt^LŤ L@ D8P1],h2> YhdNJYhe^$hHE5 ,B= ,BEKzZ(jZ(k% wRQBc -tPBk -PܒQn[o*\p)`TԸB M.TB m.ԹAF*]tӅRZ]uׅb] t bGtJ+ݮtJ+ݮtJҒnW]vەnW]v #mRvlvnvpJ+ݮI ݮtJ+ݮtJ+ݮi/!ݮtJ+ݮtJ+ݮY]2Tj{j{j{j{j{Fi}S7}SaDB@!p@$E?`Q(X, %K, X$`I%K ,)XR`I%K ,X2d`Xm%K ,9Xr`%9,9Xr`)RK,Oh`)RK ,%XJ`)i`RK ,X*T`u]L]L^LT^LŔ^LP $X8p@āB-cF*YdVjYeITTB9 ,ԳBA -TA;J*ZZiZjZy'-4PBg -PBo -yu[ho \hp…"HE =.B ].BKhхJ:](uՅZz](v٥ B vdH+ݮtJ+ݮtJ!-vەnW]vەn 0&Ukvmvo7ݮtRJ+ݮtJ+ݮtRJ+ݮtJ+ݮt%Cib{&GiFi}S7}SaDB@!p@$E?`Q(X, %K, X$`I%K ,)XR`I%K ,X2d`Xm%K ,9Xr`%9,9Xr`)RK,Oh`)RK ,%XJ`)i`RK ,X*T`u]L]L^LT^LŔ^LP $X8p@āB-cF*YdVjYeITTB9 ,ԳBA -TA;J*ZZiZjZy'-4PBg -PBo -yu[ho \hp…"HE =.B ].BKhхJ:](uՅZz](v٥ B vdH+ݮtJ+ݮtJ!-vەnW]vەn 0&Ukvmvo7ݮtRJ+ݮtJ+ݮtRJ+ݮtJ+ݮt%Cij{푦GiFi}S7}SaDB@!p@$E?`Q(X, %K, X$`I%K ,)XR`I%K ,X2d`Xm%K ,9Xr`%9,9Xr`)RK,Oh`)RK ,%XJ`)i`RK ,X*T`u]L]L^LT^LŔ^LP $X8p@āB-cF*YdVjYeITTB9 ,ԳBA -TA;J*ZZiZjZy'-4PBg -PBo -yu[ho \hp…"HE =.B ].BKhхJ:](uՅZz](v٥ B vdH+ݮtJ+ݮtJ!-vەnW]vەn 0&Ukvmvo7ݮtRJ+ݮtJ+ݮtRJ+ݮtJ+ݮt%Cif{fGiFi}S7}SaDB@!p@$E?`Q(X, %K, X$`I%K ,)XR`I%K ,X2d`Xm%K ,9Xr`%9,9Xr`)RK,Oh`)RK ,%XJ`)i`RK ,X*T`u]L]L^LT^LŔ^LP $X8p@āB-cF*YdVjYeITTB9 ,ԳBA -TA;J*ZZiZjZy'-4Pg=Rq浘j^'uj^gun^ui^ 6l,vb-vb.vb/@,Zoj %PK@-Z$ %H,Ab KX %HQ,Aj RKZ %,Af 2TBKYdg@n rK[ y` rK[%(,Aa KPT%(,Ai JKPZ%(aKPZ?Xe;p/7x1z3w6{G=?~{_^cqit/.1i;z'WϞ5~v~}h/iM=nk0Y{/l>s[{~OW{}:;~~G?#WNx}A58Һhp2u`"q3j/cWG/y;ve%q__wkCw vӬK? 'rhq7:긂qŚvau?]]=\l{z۸Lu˃[i甲`{k jB-5np[M[mfW4 uK?udWWݽ'kd[Ν;`֝WAN.vޡ;Zn;S'( r_u?ge}B4 :qo >wXOwL-`kgN$Phf s]k_ڳZMq.^7\7ۆon/K/ۣ7*Ak4*O>uɅ2ᜲ=łV,-ĂR,ɭƂV,ɭƂf,-Ƃ\ ~cA Go^]8ƽߏ4Gsg6mL"$i,W?n\5㛆OӸiW,7-7--ftz(r2J~wO]vǛ>4/6lO[Z[~ f=u׃hmgsHm7Z<+):vokɚƑ^are?Oj_< D_(fO_wwmhv} /܏ukIyPVosj0t'Q~tM? Ӻ8TUYOʝ*rgf9no"\ן8k3s%4Q@4Q2Q{m=ajGwنo][-?2zZw~õ??E FQ_wu/Ӣ/Z:Xkn?}DNk O}BmQoʼn :W?gӱ+;;a;v6^tj'{G&.UֵNi4s=/>((ul9 עju53^ ]4;8[!ѿOmE4:؋/hˎTM ?F'[0ڙLDF;W |w&t.r YSwWݾ?w8.p!Wor&sOO\I{鉾&"XS칃x̐շsI;ϐٟ&Ast|9t^K|'n}.}? )b8ٝ7V'_'u0ٗxZؖMΕn"Ե{wHox}x}bϒE0X`Ew9{-W"QC{Penq;nv&،N^Ow,6׏?Y3c%ekbo_U,Ih_3r׌} #wz$τ M8݌ͬ:ß;Y<ɼs9u^{{wuxL38:8ilte O3Jp'QmbY9X<۽5qeߕ,_mB&lBs00= HͤLϾ~_?{}嚟]O^hKtwq?Fz_a[:P oX9W\HK&C;v{c`p8xOQi{zz @oI3mg[Tי=1۾# tϦt3uwϲhEgWDqXKڧ_1߅w~ր_Y.^YϭWQu_is6vY }/;F{=W6o%;ﴀß#?FWt8Mt;W_w;_be^O=w_&JkMI+C]4z὞zɽz{=u{=;qI@w^3^\u?>?Mn) {Ó-{]}Iu{%K7_~wq?9tM6ف 8ϵZr˵;w|\MY`37$O#w~ϔSw׿_LϾn܎:N޸`ipK#`&D!rj` Խי[a݃ag4rQ O=3;G_:ht|?7>A[Z^&5\䰬gsM74N$H; OWw5˻[.O+? ĪM,+yǂςm&xHG= P'dS܍cש.ȼ}Pݟ9QNݽi+~51W?M8kZz/vxuk/~o~UWSEN[C\}Oqi%˕Myk3ӌ=rADѝ~_!IO7*&M[дY$+ۂ%Hx^#8{X#'!á뼿}Z>A]kdIG/f)BK0_;]5݊? !W C[탅o喚溡_͛hח=?O:냗%LV+I8SEns2l\\r40p*T_U܏bx \^{1綉l }'W&۸s_?\N+N7pGɟJI'y dzN_s^lP۸O^4J^ggN) lnHYab'vկ^~v]OuyꟉ:i7(M64Zol^Yj\ŵqU7jobɺ/l.n~<"_<"F~?8y?8<[RwJˋS?i}IGxRv-3 };-ykdY?sMdsdHo\FkM2&$FOÄ,6aBǝDI댢XtCC̒;C_ {7H!f(`fVФ W]#SjX_koJ7+%>W7g?WNz[''3'ڧa=[u[ݩ61rr/gif?)YheO`=DI;I'8wGtޟ}iײ_7]"92m̕ύ'qYҴMߴ?i6{ V?. 7w/ysjo,?>%iaUǝQw0FܻlLtHaTwozE/_]zүdyd~H~ XؚLHGL.pO60eԖ锘ɿ;_omjKY`-q^v﷞|Σn]v`vo>w%mge;-*,nx/a[ݰЦs& m:q'fC77Ǿs8W]x|Mw&p4+-{mMozǷ\s5…7~?)?fw%Kdo,4e4llW/&JŎ'_ŲOVbY?YsW,v9X97M|EȋpI3{%_s6cX@3Xr|(óK{óY/Mzoy LوB}áYڶ_ZkƳ)/NN&vmO>E%9k֜6ʼz/SӏLkY+[z+[} #Ow'#wLm7y<1WŠLqwBao50q L>4 Z8mM/o¿հ{n?W[;Ow6lVs}gsgjwB{l`ygt6NSwWiν{DIouzgEW< 7i߿>~ӫiulGQwZ_zYœI +TO5?Vsq&qOLskyx dɮ'"Yiչv\3j]kY\mor U_ms:ms_sGqG~cޕ6OL߷;sW`5U`ĬpwɏvYtgE)riU,]&o3t \W p[c c %c @~Z:VɌ^2.`.)qK.Q9-]-*Mӌ4#5 0{,z?ߌdiMrI?~?Ylpؓ tr;`0-mf%KoM7Y\7ybiȝޙ?]: CRegSjuGSO&,g%~>[״+Yfkfow\_d?W~ os_Ҍ5G8'%r?_0@÷6thhU,_3׌5_3w:uwrg@_v?lӤiW|qwvdΓ$^O7} o sU,Lr>y\fQys=wGvw84F]s}vӿoN|;۩AAhzF }BθsZݲp?迼C@YqU,󺽿6HMJ 7h4pIxrЍo ]@ Yoq2O[u?s/վ; ^:u{?[;?ݗ?gIQߝm/.-:?wvcOVhe^i7Qt]O~4? w\Y}2{gl۝ݮug|'z{}hڕpXyz_?}'JWv'_޴|_8_o_ܟ'γ?/>T~?՝OMp3ϳ-v{߿{xOv~oxՏգGz %.<˨~Zz?o7{,nLҦe㯫=YsW,~9X?jU,uz%W4afS-:2j[a[~f/gvuϫ6r9 h}8쮛2"WG~wmE_A'%@ߴGۙ%y_4og[TקSZv{c`p8xO4Ef;+aTϧIvE_Hw%U_YM+дE+ാw{ۻ{{Ͼn]|Vϋ藺ƭsV[w~õ??Ϩ۩qk۵V˟~"0_ ꛉ[֝ß菑Ժ3`뿚w'e~؝&gwsF읻~__EkwעPZw\濢M8RO2/;wr r];}0sd~p;' _}qegצu4?~֝<_uzx^Z#Foù?ienS&{r{WkE&vytTT鮛칻Fw5tB'oSgxїg/8.i_hO+ҫa8y_":;8+,ql.=4ogߝ{khe{}ϝ~{ҷ9EIݿl?ߌⵅwdɾٌ?s?hmTbggS ǃhݿouV _r6-U:M4Is0|,:_GH=B&oL^<=KJͭ7;$k6eWsrću,HVgzwu<'kr6^ouCk7pz Íxq3<]otxOw3xA桽A8tW MB-q/F;Ow=6^TYyntL,-$r mE.I=wfV4w|=h/KQoG_G>[f:sWs%}FTs];?ș̦ǏwU'\y*%3e]_y¬:V;jwOwZ{vzK{u},&jϷjm5ޥn~[klsni\uKXn7؟h۹`o;h|ec:>?.6CҍN9C5![ {?P@x{L=fsƻޯc..u.u4"q]DuΗ?W᫮:T杜Ҽ:1/3~oGu}QKxhvK"/:Wbqq2?~Pqr5G\Թwe\^yq tk+.a.*^~!g׷?|˚^IKqdW:Oz 7ۿy?દ SXvUk+we[Ď`q=:={ec:0רt"s7^3³ukSWo[>3~pqsťϤy!Y-8wJM뭄 rdի|ƴ]cLr/PޚWpdGiw$q3?νPs5x+Z99w_/u9v optyEow> |mɲWNoҢ\Yi25h M Xk՟N?e?GFsr۸e.5ͲϫX6{s[{+JS'J?nϮ|+J?zӟ{=yq}iO8Pd3+72: DۿGw(g߸/;thdj/cWG/؝x7Z~}|Nn0 ٟ_&[|sԧ)$.w #/ qZW'ߟ3/]q\i$4ܻ-/˴ݾ6h%oU,uAnp e?զmnp[l\/nuwoѸ;϶GAz0Oچ"ܝqiY}};[5Ν;Ẇn3 1Z͚$ٵe7^zYvY/>b?>z]EY?Зpk' |r e |r' |r' |r'WL}S-kvΏ=an]|;V_<_t`p>;_Fph+_>j3dZ?w^t_:iuۚHv~6_m6߿ɅK&ן,<7 N NU|ҼЭrn*]m5@\/mV4޿^Kz.ӛ.9۷e_^?_ҴMߴ7j˅\Y8M7iŲLߕ,fn?,Uϕ,M&CaE1,˶+]_{l?4*ehdioo?4*E?xs ?Kr=&jfW3uS]x) ?7Zl"T@_6iU,7z_^ˏu.յsrPz>߉^ dɰ㋪p'/]_=&%GII_lAou;q_E8]Wn3НY/ö_^kC87m/GĎz/?hXwuIDޭ'C-r>;+n75d,降}em?mdioKVik*7diOo%gCe'\YK-{yn+EoX[Kߎ_>K_zn6di?Sm7̟,KsK/? @W7W4or_1FSj.kLz.k4J_+&]g]ktYטt_뿫Y7ooiRW",kL_Y7ooi:?O4zvu[;ylOOWK#B¿֟::h4ܷ~ phL۬n{t?Rmǝah{m9_vNIʸwGOwAUy}o>8w蹓N=_P# ~Gqъ_qoBɱ 0gOxs9W~{GQw#6)|?~]>s?yŠ9h{j;Wh |N^ 6?h." 'I_Ѱ>.=p'B/4=;53F'=baZe+aDFuwKw78:vg)Oꓫ?h1yd{%3agWhsZÁ;383;tlsyw48uɡ5яhwվ.ҧv֨E_8=n6uinSw(\!Iݍ*6v>iruw좩Vnsz᧳պ(zٵOݧYg67?ܯ4U_o&pd+!,A*`4hu:_n=ÇD-- NJdu5k?F{/Q]Mtewx2űht"?뭺|vNw]oŎ}_齌>;!Q3I+명]9w^utc]Կ[0'!pkwk9;wjx&䳵ɓ?Ke賳2 w OF?SɱctY`wܑO%Kɇ<pɦ29.MGdco~A=t'=JӟU?hWp> ^zq dֶNLgkOm?cu/ÿw>['8qqVT$2nY;>%?vТ`⧅uZ9?ȳtz֘a4݇OiuxUF'a{zs }F1KQ_nywpbY'_ŲOWe㟽/_ŲbY'_Ų?v`X|_%?7țV,4+?W4"Pshi`/] $ڐxC(7ؔ nƃhU?N,vf\E;ݭg(}>b}mt蟸_AZd2÷KZ~zP^t֗9Oq׵ѯ?akI ~0RZ/{<@|{w7$ky_dVmk|=;_IЎ'Cvn~=onlFi~=>:x#׬jNDq;6btzXp寋Ow'ǓG *:dJZM6IpSZQ_9qaư7{.ӏNKgLu:d; I}h'MW\p/h0v]2}Ӛm9[:~Pr˕dw}{OǨ~ި;UvH/zJ ٗ}A΋C:vӲ,,x$_rֻWNIP%Jlz 8Y6)(ZC ȭ眻ZI5wH}h[pϻg6uݗ]%\CO"3# >h5,On68f%ǿqv>KJ;@ vno{woV;|JuW==[:w7pϾ}DZ t?nǭ?rN|GYkS5wu z ŝ8G.>:fl$\_~M&;?o?־Ѻ;,KDٷ2>>u:׽nM2%{ NzvH7^_xwl{k'!W`5L~fůE'}ytlR6||ݟo9GN 㮟~ҟ`_3?t7Wgoϯ4zm)f45nlgR}OK:7-~ o>8jSqgpZ;vgßl]Ogov}ukwg|AR<8埧ok';k`'~]?n4M|gzƮy?nzl4J4ʢ<*2ZĹ3)wxvN~ї%u/Neiۇzwѿ5! $s q|[~luN*Yy(:;î;Ҫ-oo/N)xm?O޹B?Qo=^ƛusʝ?Ok ݾ2&7>}lj;:v1ThR/wE^WIM9's)>#VMFY/Ěgmu\ǵy+;M\g\_.gtޞ9 {05wuTdc,"mY]F7=z蹽S -Jm~gx2;m-‚> YN hvkqU@K]7Ϟܿ(to;߿K 7Ka3 86lV~U\Gᯏ}Z,ֹ-vA+}AEzxK ,[n^^ k'O.jy#w,'kWw08<)hHp>c`aKyQ欶¨dxoi\胈6? tkׯBUMz5e_\<(luaQ=:;/ZVWx=9|WZ"S<}~T; <)`>MvJoOW\n .뚵dYszoE75AKtdNsf74FZǜvci?W5CkDž--՝KmjQlqqsKubJATg[]ђ yk_<9)t|oaefOMv?G{7D'2}ʶb7_17y֜~Ξ)"nΖ{"zGͻx"ڨ_7]fe|5|=3"/xՙ /o#쬉=nN);'>y;t?NCVOnBAsuv}R?Dos=<{y>=Oo.?Mõ[[GZw<՗b|廓_8MP>8ޏ^ Mp/G"o?^MnN$vp~ww]d|6?OY?xiͿIpOO{"̽l #s[&F1})x"OoUnUs!e)/8hKսi|Z`U[]z.B[\%ٌ McbUks7kOD%CU?1˓úNϓ>OSKU5w~U>!s$FM?^^9ŹP~EAm.?gE#?78o;[_ ;.)KUi.|wk-ųt G[Vo#Sp 3e[-6YG~>?vG3.ȁy_Ve6FxO xvw7g*&v{ZgSm7|K[Xe=Q[?s"^r#S\aWN*Mڷ W՜WP:|9jc:s&5TŽ~]zGj(vw1W+br3>hQFM-KKo2هzvܯ?^=.?tu&2\e/UeJZxs~SF?/?uOE{ L=}:|>.ѭ/FR^Vו2a-i~x:~d':~~^~m:PjmohCͼ /*>?i.7l~0\S^c,5+>{aθ{f>tsW;p*>DoZ*}5=e~x:ąm Q- {G ׫gCݼ"/.o^svj@Ԁsp~dE>[³v*ō|8WwNdsJ4}8ۭ3l"7"nkLhp>!b04Ax[qip*@|ʅȖ?ϓ?q/zE#?ABj9 lerK=;)(Hꇳphez!Or; M`НPNqsuyr׺mg;>WZ놈jdnƩ:fIVσrr^ro˯jΚV] rw%腟sP/fWMN0٣󭧏yЅb^VW~87nhѺcw&&7%ZIiޟ0O\}gEw=O/P|ty>}y\}:Ɵ{X_};X{>~U=Ͻ'~oo[ߦ;|g#Mȉ{7]vt^s='[.B|>>V'Ǯ&Ezx|]\}۵*~up䚾OGyyvUUךOf ړpp5ds|8dg/19{-4B*ή}KegY3}S.yLaI*x3]mIyZF96ӽkMCGk#Uw]?&rXUǏ}??8:7>T>qTUYrV?ESH;xWds֋;u뻰?~d7{mܭ׌~͚[?ڧW~~S뿢eEoglgTQ-zsG\7/\/{CW:ã3Bߛd^ &ܫI…:̤?K2N^|JtӮӍC$ûI MW.Q}8:k_Kaι;/$e_0)nunXn2)ն>ɣJFhV[ўwie5ƠOML:ѮY+wz;aNu4,i5oĭv_\'_Dm+ʕcbpDbMڱv{*e^M9zchQotWk:=5".ldяwk,ffw4H6ݳB{v xݗ3nY߂9Č7_qm?|]$'.^vr*~$y|;?loDWO[Of]oUR ;A&mϑ^~/?AkλjMW_YbbDluRNF+z4V#%n88<\:r {{Qeb_Y|j2d8'mxZͽ|asΙvSvm$݋>ѤDG~>2Fdz7dԍvǛ>OvVi>1k&N}׿ 'C%qqY tǹ.ᨋOnF 7̜.5tSދag}myudtN_dǝx㎷ |~Zºh?\sU6Dm.LwNƃM|v|e &5kLj+3Vw ?q+?I+w.~|6>E鮙;Pa [V{GnNƯuczd#Y8*t9FA1n~GYλ9f{_nO0$N[߻ǻ0jυ>F86q Xʻ8 cdin5uA>]s?ѿLo(dF_D}sꍞf7%_4nrmJ-93g g{Zv'QҌ"Lj">7N-Fai8C;di|l._zom*lsQqn4<ϯ#ɕU3ߘy=;(Ms zJҤ??|p*ɧ;O76~YtG>ksQW;ծ[vIpveaVnW~wXs+Ngu׏LO%:=1ӶM2&?ʏvNk}շ#Tzu[8 8AP3U&+6?]< _p*uS~۸l_9W/ܩ֩MRQt/<#T/>ƾ#ޮy^RDߟ=Kouʵ>V4s~v5M'̿:z3=T|~ݨ۩qG M\kS09:-<::uί?GfGw5?M/y ˛\=si&̶zg7ޙYnw&3;z. 4<3&rvjjvԶ>J$ren((}O$t?.PI6'M,c=S%((ʨ7_?$4,<"u0h 'n7Z<뫯-Ur޳b ^mjwŶt?'z8Mݔ炔ߧO ȵw O`"i7X_m OF{&?'9LJ?gGh}ZuO6Yp.~N BJL?:q 1Gu=7foOZY>όXe;p/7&7qhcr l_jqi<2E ufqŪE^(~KˉFPF-k/_^oN@ѣa?GG!鏻þsn]FK`8woG>Z ;=[2{߭vshoSmٽ[Ov~hV}Vsv܏Ynguۓ2.pt m8ݝMH}H\O8߈(7t/Y'8ۺ$] ?67B~{{O[~:<.I2yίLciɊ*{޹6 n[k\Y$n&L~- l\q.napbJWKۆFqo@InAH4LhbۤqoLZ-x88E\q;LmD~j 'u[ NXtxкkoؿ̒TϟV_K7&?ǽ_s3_w'?ͪOfNaIsܛnԾ;0gw܎&}S7yk5so]Bf>`0n?Uq!鬘a痮tgTyo"\|3Υ[^?gho2wx[ 7vtr8ϯs;nN ȳL ??EMRԧۻnosY*w۸"0+VܬbGϾ͞6m.^{=onlFi~=>:|sї ZkZ&WAM\?_m_,Tfo%K3׌5gゑ@|+ś‘PF8]DQh2*&'yպ૧sMݖ뜾|33deK,`:5?,~v^`mtuw(L"k~Zѝ;w|ݼsmuN?Z~`Yj:i殺 gE3ی6ER]bS˹   v9p(?F.gxwkR2?\I8zڻ!# [n94*oň-fΟnB&t~a!!0t. -KDM;exm\K|~4,MߴM?4gWg5mc uKצjߺ>>qt򏽓^qz|_}󟏋γG=;M/o{;Ig盝ߞp뛃QחyvEu߫~YX|kk/ Ir+'IJH34M=YϽ&_:m%qOo^qO/鸧︧>BO/N=_GYiuTvkY iuS3=E/r>Y+Ɲ^?4$O]S `}w9ANJ[s(u /rVw$9r^# Lγαla]m٧$G$D<#a&?`_:du+b.NqޔjF2 )/B^80x>Z@?OSWS`?l#cD!VIqtO3!s:M |vX_sB^~_N>ɷn䢘ߝt~)^_D8 |+*Xjk:' +63% !'uwBu@1񟄍Z._󜔧 LP'2q |A]1 ق-DGWIP $(.$(.IPIw< G-b`QuġGf m4=A\ 7iyhtSfd;exMsJʭeh/B -&|MHp–`&!%ҳb H|wMAe11zHUAV""O慘]9C8R>*Կ<r"ꓹ=d[>/Ő3Q+狍TC4,, :"7ba_^(i,E} 5b< qəΈ AZF65+[i.5<(PCg.gm,~ye0 NDuOܬeE?s'?X?M( VOExXKi;/iD$AO ? 78׺q h/Ct߅A: 0)k1,% ?X`E(/ r?O2N}fZ [ KI?#W/'Zfڨ5nm"/~$S\^r`6P2_n Ѱ9YO&& Y.D?{z?CT(!:n㹜gaWwnT{DO9S{M`?wO_KFQ+B?ݼVXg$~b_z %Ob)?GfBVĻ"v }iN$K ٰ63d?إPlf1LH_.YC*vb'|X'/\o^7`o*^fV[aF^:jf~F[x 6{R;Y(>ޔ}%4ǎ>:1ڶ^K7 `=d ;bFj dKQjd!r,}W Jw{.1>vKU#j3wwlꍔhz]}%?"̰ǟ:&fC[z~) 01ӳtdx#OhܜtYUfy a t"dK*\T!y-Ғ* 4J4ޡ<7!֪RN(4[JLZZ ɳE"i-pNoN^˫'+>\Ke)qiބdZ\"m6vZ!JzϏ O=._mkQXzM-? +uJOڹ|ݠpJ*cΓ%W.+W.b+QF@ +~B<_ I& q]j&By!H(C^{BfH"\zj,mLs@j 1w(m. xf+$YJL c5EgNDD63#6kxn^$Hkf.ȏW5,M*@<ΪV5scPrLBM?Bt_w_D >3d3FS{zV*O܉_g ft K+;Texxu5z ۴^w̩>:@YjJ1ȍ573*sHz[rm4=gwN}5[ XRlU EX>oQ,wr{VEOpoYx 's5P޳ _miq3;@}pIZ6M*rmw{ ʱ@v4~Jzs0- PՑ~F_VmDIT|sgYFrOCT?)8fRL2QFOH῔A| P,rj5w: ?Zt2owYs<>\s|])z|lؖ0Sb+|n}䥘P5sR@sA%4s>agͅ/+)Hq0qb XZfhC1ˈ<ҡʟM59T1 ucj1{a׭^Lw=^ ߧ=RL:˭cJ>ϋ"H?o ;D||rab>?JiNDz?Bn5iH`̿ Va@/4cWx?'2 Xz[!'kQNb9yWw/ bFe ]_׷Vńr P5:ڥI,[GK4GrA`nj[/m!y/@X eO5f"N֓-D Zx>BHYWѤc쓝!OOdc..IOAtjczs̚X yTټbXmnNօ+(]d4toi u$y1[g]SEr#oct8Z'ő>X53Iq0z +Ae%N^r8=DN*Me|)^w ׌7U٩W!0pk}Arh{B zr$:}HO!wC]PcuES1]iQg8vT&ܷtoѡ,Foo䡘QF?KJ^4hE&Cu9P%<(&㑧eq%ʈIT^V_*ȰlOLw&'[oA5+2Z]80 [i86@Vd N+aIɑ)+qĜWc5aгa3b}ߟ #4f >eF@4dXg3蝓}g^ѝ> 7@(+##6M`4 ]o2>^_Gq2 ̓Cl2YS7I Cƛv MmҭFizG}b 9R? tm(/z67n,~T< Cqke>n!=џfL^|\-ZHpe±( UOiv")z6gp7G_񡈂|gd+ g~{12z5)d[>BY|z4w~dd[`U:Wٗ/ZgW]\~<;*uٻđO9n:YTFpy C|; ង&sN:UUfn&΅h=%um,jݗ3׹ь_/zv_ӧn5%Q^htDmQ}(u:#ryz"\t7DJݝb9$O˫z+_HEJ]HMZx_EkuUIVZx͟В{dD)|=/AV3ZuTZB-DNOZ~o+1Z{}WSxt[(#jDw?jgoВtRj==QӫxJ=~O홺Nn'ut4Olk.vӕ[ի)>Zb)ev4=H%JK:liMwmbBb,Vrl]k lrs5)%{ٖЦW[Bl y%ЦW[Bn mz%-M%MBF^s?ʕy%[T{RC @q.a 6Q'sIa=)Rd2x/OSPCR.i&6s5 =|QC裇4A8)UZ=VDQ4"n?ȈcDf"2# Kh ӛ1bh< lFl6},p@⠤"Tb3tp 򡰈2 ߠ +Q=z ,D }ѰY}S"Vg%|e4̺FgIjLnܱ[5:xbt#4ʧu*FɅ`R] 뇆YrST$$9n)MmIb OR iR2$ <9>ͦϮY +C?bK90VlBc`N ~Bqk r= ?2HF?1|E; B^teWGC= |;J_'t vHC4zM8Aa'U~}p=$g '4H=DJ!hm2M=Tx*6ZZ@3 Ez}Lu>3>ׇ#{ z8I?^ _ ҝ`-W?ieZOq !|:ʩLblQ1nc,,zbU(- YMf DqYEP@ݳ(`J*-ޢySՊ yg-Cbc8O9lH/@6E,JV utV>s$Lo+&\/|$ugK&dxC#;;SwF?kMa )Ԃ04D 0Hd`l, }-*?7{Wdqj=̒h Q ﴼ[nfrCb5㲅 r9OrYA]NDAܣ r52A DN'HƏgpf.8uŝ1>Wu5Gg||icFE#DG; 3h_L$j;nԎ5{%tGX jRKj{#L_Xjh<:#$~8^(FDOhG$050#>Ᏸ?d!I}FAas70t`7ԏ]1=Ǟs[ķ"u+€SҜ|+Ĝ L MU8EƄ6Mm59En$.1dLݜ0^7}z FoBQ`kMm(1#d8eX%e9(_XTyi~1+9?ÏXEG, qN3&"Ca46e3K>@`ۈ܈GnaQ=0^r+uPW./gn\/gQ4g7aįT]n`;@RgQ6™foA=h C0x8a mhvP%j|b|[b ?iɽzpV`(!@Y>~/zGPTAF}m(E'*vN0:ǩ&mQq@ &~2ћax@X&fLF2cec054.2bH ~5ɏ_ܻv~&v3 U*Y-9%ޜcG-It/c/$/0¿3/+ G#u^4"s:PvRrrB@ƶ^~aц'4rMnpUa͏,t!1Ox4ƙ鏧bpA鿊/AOUU\??}Wޤ `q@C^6#dh }jK4$ 5 Whؚɥ!)?1^1} op08]Q{c홻3n} IRU;hWQZ hH>6k(!.Ah%эj3nMzG:ZSCb^h;Z]=5h4I RF0(ƦvӼ.QTO<*f®ڨ.Ut4|]VA?,Վ8=Oߧ9 md[QHk(j];D88 OӅ0NpQٯOkx+Ü+_8WT*X6Gc/èjq@1Ch&c` l{lMfaQ.1IM #,-\'q18qE))0IIB1B;_@^ eY]"ࣇ1>(Ș8RP#G، 7VԞ^MI EbKt2ۏ1 !gke=S3m>=u>0swm}Ľ'cB"5״y4CDêBu[6 |}"k;{F_ X֭}#$eVo}ܐ9s2}$Q[Un6k|LW]n34%Ng]\m#P2s`!Bjw.kj;{ꋁLm _4`Y/~ Ynk/DNTyW+F&7x}lGYedMUErIas2U"af-%l-nikc-ׂU;Ana7u_e--@tC^( !CJЯv;0GX,K$v]mm QMu '_66q(X;}]kEgڰ'$`lWdU^te*ڈvEKw%[ԋP?Ƚ&ڭ)6;<^/ sKܶvH 6Ⱦ e$X{_eE[z Ng |}ql;o,XVc20l1`s?CJIgI;LV6r_`~1ZrՉ }w` %Kv: $ v81{"0kv d^!ҽ$`R$O`pe}rsB8ɔT"ŅSϑN:]v{t6 gB ~]$"YA!p6(QHi1F6#'" oQ71{afO(Ӑ?mq_;.w$kg&C :_ EV&,C00H&) ~2/^ ]=&-siF'8°$aM³Cxz*=ӱ^SED?2('w8xP.8#3U"8jUw:oJ%ZAӱ x9n},-+rߞ ؙz+NБF9yd·6jgzF@;LNT'tH͙V: Xw3l6lv YvsyN=t&f/(6饂rU? kq#+{EkDhO #D#U@jk|2Gs? |#ODBO">*Dc!͜} ]Y= 2?䈼 w(vr ZezEy @Ce2'4(`oUmstp-]HݶigI{ V lDM5l+U9bVRp[~je K66t]XCz/cx|{$HQ%RDirΠO$vaKjʒ飫fQx\J(WF\&AT΃(Uge|*w^F|ARPe*W9-'RU&44h_frR1w~A<[Ji(U~}sB\hT(lʧ!Qs|KP*_dӹT~[ʦ+{\A?AP(],_/(2 m^*"ܭ*_+ǥ9n._,>_p6lyfp +bVJ)܉B$;Y- b ^:{(Uʕ}@ Q;!t~%S5[ S62DLH yB!{$pqpDxgڻ۶|?"ZH=Ml;vvMs\ZlSJRN|@|rh`7dg~DWGrqBY-rr+ k '$rPs`4](պ[tUni4ݠ$9FJϩwBZVfL U}iQnSa8~::g^2ywXfTTOT3ӭ=cR'<ߊD0JIal|O .~t4r>yZQBtLw՝=$Xߵ r6ĦqfU1d3@CH%SB~w Xaw =X \̬HCMOlrxbWU}o+H&ml]=Ƙcvݗ*Qg(F}Qg`ajZ>.Ϩ3 >cKz=Г=}K%::SWޠU~jMP:Pk}o89G"6Vrlh'yҫ:dOuF721am4"5͌\r-aS +-VӉU(9lfitRj4^ 0- 燃ryZ:NyRtsUتªB+KL0'4%%q;Jd#R28R8vpmuJ!@q\y!K͕L^1Q=m[/V2'#2W.Fѫ/iO*#ڌȟȟ6' Iq+HcU#׈w63Eh7XYiH XWMۥuR'S4ϡ[WD: xlQ/(~jM'SYZr{̱n/ouwz[E*ȟF8-d籈? 5LPW :'eU264_1N=!N^W֞yoHV_d ́́YMZZ]ZZZ9!O~ҸZ|BueZchiR"#૴?f ۣc, >gP]$I/&Kn?nM(h?DI3W3k;5h^Jg38ow$"I/&oKG<oi.$I/&NǴ8<"$U._ D?~KڔF#}>ʿeO92Z]I/_]l{$%ׅɫ/|`s_++I2/_u?7{\c<&(pl~Bt7 *6;1>n?y7׬dzr5I}pe]??(eo5I[[|/H_Q/_l_6W[\4YI/_l_=Oslo ]zyV}@˗˗M^}]M?P׵}}%t aM2svw"+JR0&:VTdF!϶kd\X>||=+e~Ol?)'i?o_E?Lq==(oKIAo9?_Btrxco7-n dcbNAj8wvS ꭿx31UJܡ'OGub΄~֛`бj&LS{BM AGggg͒7Έ#<; ]瑸c#qd8 :"?,27~0 ? ./ˈP% Z A+^ ݽEn=W^^a8go8}}YZ高E }bWj,|8$n~!i;bq~W/?}uxUn5|&4(H;Xtb-X}h S I’a BŵU%X VnV6,]:ثMYYE[ aNxf%;p@:Z~q&#S]um]Q[lj3]&a\zDpmTc3>Dy8"+X\ykPBnvSJ`+v=PT̓S) @ϗU$'h),CIE_3ޞEpr_6FPb0^PT\,U)f} Vq.Abًyŋ0W) 03_}˭)AYc v4͔8oyb:kDDzchZ-ٹ>98>}{n Q;t7MZYjgKM,7g(R;/߼q ^ܚzs IuHͧe7OC0霃O!X+P&w (hN)W{WyB4-)#yćZh(`% d Chir 7AĘ"E&48r륔-/̟y7>śdPV|nMms"tAzƀWdg +f,xdMN޽gf{úb+nBdd6aμEJI3w) ɒ-xGx 8Ww%tiy.GO~kskq] -k4n@X9}-Q@ IIiSOD-@r.F䃛_H= ӛ9y{(MBTSaD4cXIJ&KoCr;•^KCŧMi/l|`\SŎ\}"= f"Çs”a_"fr.,<9>TJ$4xJ۰ K]s---" e$UZ1⋍̅J6c@k#|]m!i^eA[sAӳ\4Yٽ}Km ,2V^jU6|֜`[<6̷pE68jX3&,4s ZΉSςI V8OmqSԠNT®a>_5@Mf@܏%arLEe~#1 `y ?FlL ܘ:7b#H_6" XRagI䝑jcM3ڵ2%uuf. ;~^蓈vX('@9ܢ)&}*mƁO^a6Uܩ!7v>VvAC1 ߵ!h^pI 0NVʲ31Y)]>i#Pb!jU6gX_R>4LRA+HːgyR&N>]A* ch\`QhݓfLYj.%v2J8lډ[1׮<)Mlʡvdfu5>Dʛ=u \<4{~Ticd~ũAG5E6J +K6~r=cY.vʖ)KK8ȕ(3_f$Gaƛu8ǭbiBa / m]B0!tM7Yjމ QZqib4%czjshFFop73bU-5מOrvt3sv))˱F5,cq2p-kFLt$9A}/;YDӓ؞0hxʞӜ]?vbέ},)譞R9(1$T-37cU~ ^f3H',ۻWVrϝ#|{QXy_a'-؆Jyw/yo8 go!xEA~3!~0* lXC Ap`2ڸZZX+",`H#= {fC]|gūߣ_oo "UR9ka,e =1Ϸ~Q#zf/AX, y:΃.z=j)@m`\aL]ō Ģbʶ0,2J[.kX(mD qz,%n+^Z8zEq'JRa/'1bE14e@1[=%m/DU|x{>{/Җ2,6 {{gSwMcʻƑ+~ <>InѼ)KݱƱ{3}IJHۚȒ[o:#$$ G+=tCYk~Y/ǡLe?*ցze-D} ? f]>r_jB#%?s{1#3:#f*Fmӓ7̽>=ygW͢XhW"찋0;`Ef77Խ-+G4> D,D<Ůyۛ?k$UԒ俐B?@;*W5entLɧ@DŽ.w4cy8z Q`>fۗޘAtQћ=xHҚIapDAKe?_74#GK:'?/Z/ fJ= `ng$|q洷+uCCɒսgPHd]IbWnjLA8څK d3F{4L [`$CΟ&&Q3*ɷ5.ib[HjcW*ha9d|o=|?kD&dl~z>ľD㠵ۮq{| coj/Dnr*¯S!f1gɡ)FI|aχ #MrQ. u4{3ք& +dÌ?5b7B {Kl h`2zyvmQ񯟥c'2܁pW!Df&Q/ReNHN >3 Heեץui+e\!VϧAUxx塙d:r2 W7zpZ> Ez+KͷHk@Xcw@Iˆ2lg2;//;9G!*m$CdKIPp?g ط&ۑ鷦'bI..kdBD.z8sf·G[Eլ@?TC7mՑe?f!_V( .s!ߍ'h?3OnE3l 8듃ɵB vXn#Bcs20#'oPd*58c>y>$|q-LC{@r-vv~e>zs*C)[QR1X߻m~&iNBrǾ BIS KbO2? \ZdBP ZRG{Qdk)_}嶂@z@XyT0%(u!*`_  Bs18wo:@L/ r5x-0D'\aZ8߲p+P%NaNKpQw1`&ƥJ&_x%87Dqzi1(e7TגV?o]~cl7VG7w]֒:ݟa/ Xfe>mëm~r?H+=Y]_L_G.7/t?|J}㽓}d 9"wTu[K2,_s>jWktTItidJ;\뚞1O-Ikoa "EM0m3 j;RXX{Ν FHY5(ҹĹ^T˛ͼykK 5.5Q;QJ9a"2>U#ן_T`c*5HVo}< b:w逆 Q0 98S@Z2U oIJ ZB _fJR&ўIi?;C[ LcAB.GS`d?"#鲏\ߎCKp@zkFUK~(M 4> k}M0ZGԘ?k]LA_ &%%a`03b0`r;WVHq4c1 , BBx J@QɻM_P["<@ʮP?Zb$?_ĴݿM{@ (}y( @C<o?4C?}|F?"v[yud.D./ &ōGG1A]B5hPxiRbW2DUk0R+ω cƮ=gΐᡥIq6jI_Wޝ׽+ů{z>i};UwuTޥ׽C[e^JUk G4w+8X zAiUMcP n鸤IH ztK6c L /ͧ ή@f8!z8^^ O={jP m*;qG7c ZX?bO6) H=,X* BU(t#.2_SޗP@Lχu1ג_+?s_&ce<5sfj%uL~#:eʎQRuX)0_K?\g05vA8ˣC,sI.7J1iwSd%:.=k:|o )iUV0;W:'&12%M{&jUKhKҺLrQiB%xHϓ$Gw#8oBo>‡ny4 #鎿'Mj>?4O?#Kf7hb]_,t8~8XS>͘*teSlua3Ju|FHb[gZgl x9) pU'LjU Tհ0-UK*濱 ZR1_% :R1THE_Zh4CՒʯ;bO=;fc-/~~止"*#oZ Y!HbG!C%*CrXZ>2ZwA @MǛ U12CP\ GG.FDh"Cߣe*[޾nS\^zG g~2veJK_rW&$#YO*I'$i$'SN>%9 ezuX*>h%h%i%hY%iY%h9%i9%hKjSN ZgJv 5MmӊښRLIմ,ב͏y6?<hz_(ءNZ(#h:.F.K/k ' @9gB?  jYzq@;&8O,65 􃭈|vyqdy.|L˨/#_B(F^ppm4q)8Z8hqjt8njlq-8TNwA8wPs'xȖ*O)x9`%yL:>=V`'hll<6ZVbFGqsJll籱-ظa%6qGqs3j 5w~ Fe)Mג?^@ Ȥjok;~߼54U?֒1п/@i_ֲ S@v5'uQ~7 ?lv:;|dGXVN{ 9 r x9>?=IG32#$*n0.)x6 Wsmbnr qu-X]NP5Z׮ե3o>a^۪vUmva#_5FP"pD~E6Un2|>i|1ZYSU"g11D9+|rE| 6E2FGd>> ‘+8Y լg5kyg5sP+/VZ1?4|φ.sqzm.Wro/c: ?;UZ:J@Y *#]oG9lpSoHũL`g:H⿨'/3P Kn!@V4q VnVܥ(Qc6F6(fX*l [aa+k7ʌ$1_b?Oy_7l#)-I_[@ wS͜TsTΠ?zeO6C f穻wmZ~Ux71R?-E,1 |d, ;ЈZGmu!xq$ P)8*?ki_" SKB IPmhᅩ)I!?yt#\:2\6ppϒ[O܎}Xȉ (\f)"QȤCe"2(p]L:V_S_&IKXd{&EK"J^m3VJi9 )$ږgڌm.fYMϲ҇eSвzRK#)=MUo(c[Y'GDQK.}+I}'o$ٕHMHV`[yGťadS;~ ?W>Gn rqQ#ߤ%}$e ud8 Lu' 'f{yyW>xnΑs3b~יUs ](}~?i\l9ҥΣڧK\\7:o{:gU7:|`>㥵ʁtsKBmEdSG>NLM gG9.8eSp{ 9*9.pπH)3UNћs~^yDK}u螘D]qV'eLgW9toq{ U{sN%6\ǾpgY=pMDv-L̵$Nz_'_UhVeWz ;NOUwW2^?z59!tzOx& |=>7D (Z f<9qIRL{ԯ4M^(]6N,ہ#o'v~_Ϙ(QIainW~0'x!ìp=&ogzX󳒏% V/Ao ?,ϟ;"?"AA]A<l!\[{? UΫ"VboVW26{26{ٽ&>0 MLTA"f=ٶ@" ~ +O>Zuhߒ\d(nAz[0<{_#jǽ%럿v{*牲g 찒2f7狪n /c ݋ducgC, ]UsY-ݿ ۑ2$vu{ }_:$h.~~vndo˽&Wa;YcPw'?)3Kij|xZcHfпu9|/4_IMПs;&]Ibk#ͬe¹Ang/~} {. ^B@^wôo;ܾ\yw6&6CzK󓔗'q E^90xZ 5Tv; z/+7g.agT,DKwS9z5k\y6\OQot -,) ΦD<_7Jn{ :QAɲ/Ľ¹I;83Uƈ§ReAnYk*'`l2i$aNyY6eO0+++\nߪ"ndDXPͿۓBOӒc-aІmWQ E}qӻ@}t~w?w#gzFcyN("~k4Kˍ(C@ r/Ų;p.-ڝ@{zEɻ(薴MGa-=$ n uX* IJ_!WB/H~ZBܦ?T" !3{7]ؠ^q$e?nR_LBo/俐(gܓUdGº^9DF0e7.9h!AAAOJX| *(( X?+BoB|/RžJgޟu1ݴePIEV"/OJ^.ժJoiɑ:C"yw?&Gr?"d!Ǹtt>22߭K{s~3P_=|&~ |-m^Q "?[) /,mUr9$%2pt/VWhtS?6V݈v҇~eѫA4ދXʝ[+ot]VnF~_EkeGl|iO* VJr[aJ{[F܃|>Mx1֑W&}A&='%JݖjrΎ^VުK<2-4;ㄽ)׵%r xЬr5_ }+eG2?[H, VoEHXSEީb!47֏Qי&CLqw]%zWY+Ge@/O?Yy~^6_+bQVG?^Aa`z0]o}#zH~|r4b3N\Nv':ۙU+g~E8Lg+EX`X``5|}4R ˡו{XKd^̛#S\S/ 31w_e_/8Ɂ1*g9FH3+@z}=a~']BO34J3_ıU?թɠ721lbbرaQ46mh|`ˍPD==<7FK3!h@ u|7k$ZkU&SQ4PgQ/EUǓ$W fnO3?LOiʇǟݔn&鵤@8]Ϊ}KIrp!eX1Gѿ_DbQedeOIbSH}^ʼn"k+5,c~w;q'n IJQ/L3{|.y̤F L="!J kø8I×C5n  ?7`t40Q;KJeT-FzVMcU,H&iF^_'gUt3ȕɆ55. l`^ޜ*J*iQ̰t,pff|eM- HU=DoCVŵ6Y~>#t}e(5X/'żoyl[PU)|\cxnYCfK俲_LWD'(v]_.˭EM=G%gBYcv?qV'[SrO}bOݎGTB{߮'?lOB {Vlc?f6z|qnn d`\j`lfk7$ *㲤5>me֒xK-%v/\c뷱_Lᏼ(B!a5t\@n V]̥pEa&>%2X_e~>P#o?s/k+Io/俐Os͡/D#ә᳄غKR_$/}$յ5RKg#oXA[)s+<;Fʂ*~ع |Wݑn1Knd|۹9ۛa |{oBwT/<#+.:: Kx֮绝@w*=Xox!p]9Qt2>i8cyʝݹ3t uwN"^'cqX^g֗*{yzs;+&ꍽԡ67fhdtZNqyw&:O{0H+חv)+b+ߡs^ k'X0/w;u4|pm7ΝMj!{NO'6iKpxaQfA*L}dxu̐QKQWp(RJD AfB(ER`X%0w`<#7 WV]O&P"E^f br0)+Ԍ{6gf8,X8,*o"xV|x@k`vg톃\ VhFq<$Cd P)D0=y A/j8Y` : w2rg,ߙdgй!o!C:X㥁(e5O/?W_PH@JI=(@DFl/"\ξ[Feح^qhH&CL6\ҮNLQ@,1bA#P_z |QH?K[ @)+Jλ!ߥIK|f E(+// B__0lE|^ z/)Ez^tYy/]Oz.=ڂkٸ?$yGj3fϸ#I^/{kdO w/7IrtPS *ML}Ov=4X=oE0wy9qfA}W9D|Azҥ+mZ_*n4*(AVvΐ|hw@n0I omTVI6 фKFj"<& [PGNe.:rӨjDI$]h]76n-ofe4F 5 T&}dt`G5]or?0#tTQ-\q=!un4޺v&'A% 7$b>mgF]*9:3˺m4OM>0 RnL2F,/E#itU$MĨ3^nHr*䤉wn&y8W= 9:0qVi3Y'uO=$'QTNY+Dk64TN:7NA(AfI  Cհ7z4ebՉm4~>0oUfPɬƚe.>ޒfovΌbh<_0h'@ԤfH=Za=䓡XXo]O͐J< ik3HT4OFĨv{Rր[PZ1pkhV mʭBPEuj8=~,]Se@ɦż'R4UH7\$0fliU eTɩ2u?#ڶa11ו:{ə:X!'3[1˷uč"QIbr̼oZJΚ0k`s FtBѵ 390!^{][4 SƘ6(1vddG%%< SXX0[E y 7KQ/Ac%bz" E?uABP  XB.Z%A؆ƎTRN ZIg8O{zO m:+;x2X:N ƹ*6Z@x>^@{MV4B DlX~HQc 0`#Xppmkm*V993W3"pD,JQAWU@6/q>Q&'_ H$5_fT\YPH +PaX!@Ҭ´:#Kijn";Ll -ZgF JQ3؅AēT+v5y@þ7Vz=Ѓa-V,+jI*v}@&/ecʼn"M0M*gFϝ|,o=X:? K=W䚬*Zz^0[~Ec S ˅ڏBE+QGHtKX!)sL/ɇd7'#6>+yBf5-#-txdMHTA_Mv jUpHbDrҽJ@(,2-Y `jǚU)ޮjS:n6v3Mz~r#V($°!uT5+ nYMF#1P]{WWCxBg *#\fBU씀aTQjti@_DWeT/fׁP>hDӨ*-rI*ZCii,VR7D-_L-qzMnг:Vįjډib6@B' w݌n@(Yw=qLgLujوjjWA:%QJ%jP-xg/m~l;pwp :nLJPs=kmN߀);5U@Gl1]+߮U"/FdhI^$_ !="y Dh8KA\3|Kpٹ|V:KZ`n͠23L}r/.16SALʌȩi@GV(HCFz5?!G^gK σkr곶9.qMn@'4<2cמB('n  ˠ`n]`hayMyenpsOMB~M$}1%yRa?>Y ѰHOj- "!'-X#Yfd$̆`t Rw]O4X"vmLqϹdTahx,UI) EڗŎp̈POTa:n찞;kTa)}tK:n6@yE0Tf5X QѪYm X]=i¸ɍ^SWIakq.M@Xc|K5:7q ,8?@6WњgTנg@[aeǛ&3f g$ЏQ]o@jLW@Q)U D#qb,B}eIkMP[ZFj%j6lLX#t!B6KM~f|)[e%>~t-]nKUX$kE/"^^1<;&@8 lQzMS 8Jyjj@z,Quֺۤ3ukڱF FpMa0V\7(ab2ʽNkZ &34T0w} |wҩ1*jGc -Th/l9A; =f:?9~ xp)3Nf@]pzu u]7ZB0~o8%^9(j1irU-ǰIw8ծN5Mf!gh.͙C#ua801u$L~\Cꢮ6JU[6j`&: 1jnY:1R>(;u8.A<:SAU6>ƪ2M*GtwjNU?M"O]H\T%IZ M+Oc1ɳ\z=FO0zMƉ ^UбYLIpE-ִZǶlԍf~c`eI4ҚGR@'>`t'5|>@=w w:cp3*<[)#CBNߝMˤVApmX /X;J|Pq$C. cb.]C_iGzbH>4;!7x;?ߐ,sUJ5*U]6)c UJ+L-Ve c^Due׃mj56Kz۵ \V[#ǿPcܩٺH@]?a "VڨR6:A_%IVl=e>A fF ,e;l {}Gbk7Uc>!iChb׸/ru18=@8%v4KڅEt^2?p&АK-T/[t(SnipHyJVyw^\\QuF|TRJY6x!kYI3X+ipb% ZePEuKJ&g0ybUwA$-"[Z.ϴxRKM)PiY ! s;PԠ>IJez]hr SM6_Ľ^/VOP&,6#ؤq+ A3]X˃rR"P@ 9[ѪU/M`r%BN#ʱUD@U1 W33jUt{c4>j%֩Ƈȶ2?U%bY qrNwC50ЏSh5n)'8wY*&)%'g%b:n(nq@rLtҡ6Xﲟ! C;145c#Jȸ'2*Qx ?UgZ.P ޛqx(~/O~iL(ZGG M "PMlAxU*u$WLɌ5x ưl ($4._@~%fғm>НJԫjP(P5T? !?L+Ĉ3aNuMiN !^%Ex:C^86Y*-#&CC6fx"!i]`kXNOB{9a 5*ņJ\~vS7qYyP9׫Q6kM?5¥x^]1-C7K JnuhrWE%[,"0jSµjuNxR,hVUS֔8Lg3i_A6M)#L[ 6"+uS84UBAu6j1ElDX21ѤG ilI8F2v33!1q ڵFs%:h)EX;C`,]۵ua$fКVjM5z-hW.L!x=/ۉ?$zoĴجTn ѬxhotGY}T59 tD@I\%zײ*tOTH[KZAa0 Yuq @JUH@U9ڶjo5ΰPҴ(/ ƹUUl8fe7'(@$ERHE 8#pvr^l)¸ ժ$` vLHCȻ&@ujnEF"^,@FHħoxW[9ebK6N޽md S"L<:=gA` %˻{v( xMj>dfoDd|Pl_*Ff5($x5MϘVP~[Ai ETy,yɿ!IbFK#G[-˽2XJ=y1 $޴QtOƆ1q:SUAoPƩE^$_~)#1(6,yn!5gt3'{E:]gpUG]g8WGP5McT$T@Nw6 { Okh10#`$0F,vMvŇE ҋ&$[ \̹Y5Z|,b''5as7.ɠ6M-D4LFeTE"b#H)<=Ps.qS5\^->\gZI:/\B40+BO77AAX四S TyˌgiDԚξ<>aR=W;s6g aɟOV^70BjW4zj A7! ;~q˧viFUuIƀB 4 wu%^*r<@ UKAE\ುٟ̒gj=K%ZHqE s/,p/a-P^N3sRy|K?Djp9itzf}š_`C~i*;&:'M"4O^}L~ã"]*U4@ ͬrl7/womW񗇯ӳ{xs6mMcb7|7&aB ї'gj{DaRq!=nvwK̠_^g3=z4 -I=1f*ۭ׮txv'B3cWKtR,Lg! _lE,hxP2%,D/>&>N1 d16U't>펚}=묊C%nͥ Xb X鄮+!.&ڢO3MPC}2Y쟖GyTt벎8|L0}yh~W3w^a{ڮwkb ̀5`{T*!YO(~:fBF I;{zv&&;p<0Rg!ť(Ӽνq5Syz<&`>,WAxet Vڮ@Ptx~pT_vl1ފ2V)^qg݄)(uhg@cvhzX;VŃbl@tb*]FT5LnmU Qi:>o63\%fvK|(\"a`pt_\MŸkU )U [,RtF^1=p4SA2Dws?O'lf ,\Os2 eQҤ]ll Rߟp +! Zbh-`.R4h,cQ6&Q:%d\ڔ(1*rޕiN@3^(~5Th~:rhQ>hHLUߚt=bޞ~t-'Π^Mq#,y0}h(Vt1,bEce5ϧi.2[ZLP&Y̢ |AբСR2 1 mPS$vi:R㧆绻V ߽>cUSKv/h1hiUПP1c2f2R\&wC`*~SǕ}tf(O(̩(8. "|2rrx]| w[u<=Ul"/q}Xs  u.2;OnSfLw4= ^}W4tL]!}]Î(d U+S0-rn-/ SDA@zv+i:Oܹ0f{PKKyr/7ǝbMlXi@>§>]|Z> x$KhEMzY,|+%CfKMOceSGh@vF6WK.$ڌ{8AY Y3*cZnZ-}{~n2P;֟weRTw_/:j_$&ԻOf hTzT)EG E T;(ټT)uؓ3aPd/O; 2W} ?JRh>8S;Po2EzrbLUWw,EVZq y}R/5ЬU"RXdE^*ViqL)iaX#ITzɷϿypm^&vN4jyrW8故\4}HUkJ. naeS F[w:+Y(=5۾h~'+i#xVK _-~T~h5NC2!^,S:&, ZyX聾 B~znv9|5 h%QgnZ!iվ~`mM;Jڻ٦{n68t~tv`V-M;ƭvFmyu\? ހcjbLp݀0J\}Pf7W32t;ރ8=GF}&hU^ __ >x߭&2^z-\J,_,R޳ =EX0MOf^ y[bšC7u ݦ8/k;y!~Upbf<~PX\EKf[) cSo߆O!!) 4- A(tdsy)]&(eʖu;Sӏ?V@S栂h&_h__Zվ ٘g%QԴ;k^SE:cPA>rCǰCx6h6n d6= m 7ҖsF %@6ϊ_7@Kk76 [BN[$l?ZsZC0A!NNdm e@kDe:|M7a%Qo2^łm,>\I^԰8g`(|n!M46D*nZ: ;zQ0ڂmoù6uɠG"ۤwPd+()qe6V)<.0DynUa/9LD;~oWӿ+QP,vUq}ch26ǍONu8.fAbNPnj>0olg)-ܜMRS<7ĝȝ*]KYAG7pO[mSϗ7+fMƨ㨳nkkzFdݴ@|KajAnH6J#_hM?;fbۤavŎ]'|.iBRk.-$ l-ap x;M|бa_ ÂoU*y}}Ɇmks#v;cM ĴJKoLGB7h7 Q J7Z>6T{Ua7U.\1t ol<0],v,#o!AbZ MɈ309u W..t&;(Q:S׆oY&-7ĕr|2п $V\VMRVmڷCS {+g67[w0Sm ١D.o #kb`"j@iIը_Ӄ> t$2< kPFe`zHhv·lIY{aTs(G1LxaJ2,((.8낾x'˩"c0.r z.-C`1y0D\%kx'R<KITA`A/ݕЫ `0<|2Mވ3&;n66 U4(K瘰`F;ar^WY(f[PB-ah#Ù+Ea:yX i[.4 K> {a8>F"`&=.qk=|9E&Bɛa!PhgP6`dکѿ ޱY7L3&rh7< Zaq&uiuvQ+0q:_G'{6AakU\GQ݆ ľj1rJleh[YC,.-t|PXx!:b"mhj 1EBbK%#8^aթ&s5˾*~uN^&oDB 1PLaQ?oz~Bb7T̩AQr+iv(xvŔ"AbMza}KKpOqeb8 } *L57asZ?1e6 = =tl$~}'>@񁯈׻6Zxu &(lBljQ$63rR :Q* q$Ք3|>L:Ǐbز&E_z=\V V@JcQ'L:4ɚm.E:2"] y"i؊Y3"R[1[ ;ByHQt^–TdGFH|1+$[B-a)ْL*9 JtZ Yp~9}\7þUnqJdMmNƼ*'c|&`o1Ne2orF)s$];&s`Rm.Y v "*i%22*!9AX"2[$#C,o%IfԴJ+g 7ˌ 6^,sipe%񍉈Πu^ZYL{[ і%,6ņcoE:,v6 eK0NeXhA ӫ.]rHdN{6Fk IeHP^0hŠL_S}&-itd!l[%ф$bCߕIş97i~!n0a{v)dִ(CVDeMg\Sˌ%MMcrYLz[B;)x,j#NrαPW,>FH)|If1Sȓ R5cc1: Z.!|;ᜡF^͐QD51Qyoxtiw"Y'3$F9dy#b:i@ϒ@;3Qh,8RHX(ȌlȜh U Ejj|@IgߨBƌO8"c?f2D"A -|B])94k)3υTQg\S&1Aː#LВcGij2LI_kh9s\YFC b*5J0r)I8鵢AJ$2(*%Rm)(q`_7MNUl\ϦNi砟ʉ!-SHiS/Ґ "旰MIsu["=4hܒCפ4žHzNBi*ԾȕkZ)7M^ UFqo ݺӸ.-E+Nͬ ܴӚB%h|O!A)J$m;`П%4|)adܴaQ#$bk e7E<7Jŕ)V[ N)tOCpD+̞5Aʳf6]Ϥ5rCD3;7%\,l $6Oh)6(4x bwEZ"tJc˧jn`%:6Y n LcFl+ѹ+K dC٪bBYs$Yy5M@p`$dˆi.JB20NtFl 6ܑdq5I>Xm͆k@Qct^Y L<ӽDDJl,1IžbЦ'I hU#5lP h/YO,fF)m ȣw5n մ!J 6H5((-i"נc65$jZ'/RY[w=i\ O VA}D TAc*|9)hda:T d!AmMY=֬½mr,Xrۧ{vNH-M; ZQiM_ j&5.tӯI;(n(c4 K#N7 _2znЩk+<úDP\+TۻzjoyY !QhҴ1F[m=v| 4>ws,V̈́AN37 -4>_f%WNxRf8&w¦gu3~Fw 嫣bWy,Q:(\\Q܋NM֣ ^Dʝ63>Da֣/dR5 Zp;6]@ϒhVk#o8ட&73̆,l11=fճ4rPhˆOi]ĕIfZr["/>b놔q<ݴ:2ׁ+ou`nq|I 4fT_֘1̱A8}zR,\ݢd0uo f rړav/ݢ/\u.]L&Z |ba6'u[ ͦqtG% ,bPBrJt@Ǜs_ڢڣͺX#ǚeߖ6'Zۄ(ZrcHBߗ>Sb0 $߻ly|YTgFTDJ/.Wi_Mw2˒=#2x[+t7Iq-IoFTCx3>$cH6=",ɹieF˽el \R')p*ٽ1 dnTk R",& vZxN6fFpB$%8 `B֏al78[QKJCjRSRX4QS<. SG|oPxͮhrT0 B,}#" ˭a7lz. |#<a&2b1l8ǖ~HbNiOTwEYr5!ƺfE}.vX9J؇ER0OY8߮0* ,ۨ½SǬfŠ="ѯ= "L]`vv{`Jڊp[G- n]! r#]r־׍=!AKHnpWڔgZށn~@;B_; LThqӎOt<ٛ"%Щh`6"u#D^q2F6Q)6Ezuv WWSP/'P$ayUUpG~Zw"2;(8")ňiP-0ba*8%d#nt~N' yᛴFU fuD5F+rDTwMTf.A}jSYᾐY|ۿצA^QO^Mw\wLY(>E<zb]%`J7QlPF; 3XL[dᷜb6~ DCBty[NTDQ3:b(,[9m vf R翅JyaU Vl{[<Նnג2ۿ[ "xVz <`ɝ |td{2`5bGBAqR ql\"tKv\CZp TCO䁓Kf7%žiYcJ־W 1*rFVr)OԢ h85D7tZOS۲ IGW1V_tV5VS{Ѥ^$BV:M,huVd]lKd31C>JĀs)rc tw,T"('0| E \G[Q!}iъXyyZ%n2-`x,sKMcTȜ6JVEP7$ꢎz\>ARq*AK:*)b2jcl˫Ň 4: 62ͩ*P?-WuKm烕8INeʚ>/.?* ̜NMxv.ser{[Ig ab%agVƷ'hcl8bjb+)Qm(UAT|s+0J6(a/O9?nv}@bunt wKWlnf7(PAO&?stAYވyr#}=:m@9 Ma>AԳcT9.^v"hV+>ޗsݛY\.'7M*;w_zDW K+] ,kQ9}dOQI)dKhQM%}wH%eNԚI 2-[;Np;+~J%;$# Cg8Dvg z}V3L{B(efH$`Pn\.[$|DhfKrbedJ) ~,ut_io ALW'#@r:ќp8S"J9Zh fNn)s;#1a] fp*EB?}19/a=Aò&y͏BØf/%٣Ÿ8iCyX`˞I<=+\Yܦvԫ k'if1 @F{fRgZb$l% am($[<m:d$賢߲H,2@ȷ. wyxrw8bBKLdSOlL"f+ ҆;AĶeZ5UvLtvEV,BpWĽ ľ.0,kg1&&Q2N(Zk< ˽YJ}<̒5@تJ.+d-$T?~jcV[ (z:wz>#oE@Ƭg@usf$"_GPMׅ#-x-/#i9(YBwv(X1Լ+m{gl gK 8pʽ= $XU/A/Ynܗ;Px-)MʂCEC7_)TZؐ}BJ._$%pbY^NgYTq1KX/bHC\^Ww}2W>&zu_Mn ׉HzT,]A A0"kc`b_MB7nz."3Xp1%.,H ae!-Q?Xκ@u"(. L;fVg]hBY[ %16H X\V! 0a=/垒 7ѩCzh /.bbvO * CkI7,URӈ<̖: NcSz#OLXaܣ~0 Pϩ)n#!ta. zp҅#P+-sS"'`Úag? <_3%YtcUĖ.)mzɐpےmԫ<d9oP"08ds+ImؙEij P ,|D&JAd =o9}f(Ll1m"O)LTE܆;wXXa@Z}CGB]?֟whAd%""(dw_/ÙF0X萨g:!F( AޟwqūnJV9`u3}]Ld=[W$Bs Ss'CB.q'f3$V(%n 팈lȨebN;ϧzkGet q/|O׊FdpױVL 'J%wiin#B% <)Q]|aE=-jlf^>o 6IL)J>J{[m*u}rB[^)*j?v&wPV +>1(f3 3I ϹL9i$ƽV^$U)owyK(q0Lu\6&3Ae`YxzBHBև)@Or|^6mrAWLdYo_g,!pt"c.fYdF\#v1!ҞkS (vH#ENOş&T.nwAy _a+9;|=w.{h4f~coѪ5{?Ԛ9nhQ_w7-~~O]G+ ~MrZ;?~xr߽|ݯS ,']% S-qn\ƕ[?#"ti^ݶvT{ݯr{nݯtkǧv(NW8i;S X{x~ 7uS }~[ᏼ۽pU$qU_-^^徶֖ \d˸XPKt^'xP1?֢~kc%F5>pa4)Ss-dHtV&DdolxՋl,skh_NZ|Owԋk$v`m-$7;DD}$] _4 "P7v1KpQ &W# Ҋa(}<aG0c8 M'h<0F2|ׁMך6ikyݚp}_^ju U1_\qkU[p>OOi8_ɰla/ n/O X7@cFf=/a)M$ޮ723'+XXӉ컚d81* # ̿W8w3 bFc4Љ[I 6,-m:F?QXT9ҹ#u`CN q3z_TW!NjLGtA~O)>/av' J z7a}:aQv%u :؅b+Cb.%@)1ZN1_)ՔTI˪UBq +txL,iH/nZqndwObtˣkwͦ@k+rآﮯh՘"A/2'-}pA#iĜc5k"&>U(,8Vsm}22I_Z9ݔ WP 7*lrV`'VLX3Æ~ޫD_%cWsI%WRFPmeUѴ./ʫK92K"Z?F i5Qiu.-PWW)fT,hߪYQ4cCU32*L{łI(%* TWXR45eګ,jvLF1B+K8Dv[7E02$+zKҁd/?Նej_ϻE&BT?6j/{{K}f}. ['_؟OenJݿ6'ʏ/j{Ɠ& :LEo*2a/N d0 p 6AKߔߩw6yŜd&VJTh:UYl ƙ]ꇲMÕYۍ`_8N/gᲘƣZ_kTVk` .I8u_;]؈^x}US3Ga:\՝be%8h)L&YoַK\ե$S7{=?hf.v|b@{nϯlaNE`,pj:!ШFY,mG!S->l+iBzH'D b ,ҷ cA+WhؑɄ @6|b|xzW6(x|">.|QCO~f[12Q>;nG}񉷇hi"#>n<۩e?l?@ .ɖ0Obvrs?QQ뭜M*ZBKϡIWP D ſ^4F.[Eɳ5TSs~8>,7V|SŐ8vA? } 2U쟖wEx)1 APvQIF@~;_9+]n4~3 fYV [z.HzaO:z("1τ> 1UR"@A2 ވQ@D\%ʌ}b>^IHZo"%LڏI;s+DHo,Yfì}9F¬LyKOODdrPہ DMM8o`CLj> ~0(xZ<>" -k|mQ֋.Q+!!1VP} i)fxnHGKǫ3\'""2rd2S pMzY?Y_x9̾&ٙUg0*8R:cM4G2!W7Ң2ԟq#X x339-2wx-ks  \]ν"<Ne6vJR}aY%N$5!|6)%6u @HPϠbaI0xWIh9&_UjUA^HsjKq)%ig}#*V]0^J`H*_`ߋ45 c!OÛ:8PuVp!)I*p$&n ByA/_-P*6եٞNHBs Bʠ*론m)@8Z]QץXfKr?nJXbaݺc-Gzf4*k>S(lo)%%_6͑RЋt 1׋& T{|DuM@ªp8\Yմb*68*rScRhv]Kcel)%"5E?cMʐhL{-<˒鑟r> jKnk+>1cܜ,kvʜ6̧(MR](/#'3WW*2r^F"^mVԡvGj*V'jtEyͺc =EsyIoZh0;.%GLv#`jN)jkIq1&^6W?^ :Ex^^}CTZq_қ$VDP]]>_SX-KRsWVXb*ޮŞ9 y3gm>;, vs.7m(yɂ<oS *ƏvmGÆg=[֣hvԷޯoz~ XEQ5~,7_OV;^uޭ? eviM 2㋻|RbEQT pV&*A[ rUǘչd]*bݚӕk3,SY \&Ԭ>?!JZt8VkxZךײ|^$fϩ/g(_pZ]# o75Lej4k/tz8 rGhy|ʰJ|> j&3C^sR/j}CGLnY~Əz|4>8p_qY{ ՗wCnpL-PIq(ME ' |'R~ηGmJ"39]*B QSXTy. Fө Lό;}aI+zk9K)B9ُۅ?q2Mk"?u빊s ?x矗͏}^~3jkie}GAz S?uɤĹJ ֳylj}mZLkLTߦMHܼ}cHAl<.&4 1d"@ݫ[B3W[:YIg˘*[!*aB'zT-csf}1}`(Q?ߝ/?MT:"jM8DaRսt*:};rjeɦUuvkQyhyKF!gi'bu4ҷFZyۢ :ʷ0gMϨ'~Fp%:.&Ow18ɼ8\Xr¶[N*U4 *쬲GZ<^i0Y0pL-[ ՘>*dE4*r,WX&5R^ QJr{5_#L։NjIewE}5&#ǘ]%LP"YYJHKH>1mNI ;Fc#ҘIl :|7W֧P.4c2 l|o L-QD4֞Kuh6*9Vx*(D`_0VrGa _,fK6sy(A0-V5 ٠*Zor3>OfzYQńޡP][J[5$wQͰwy!_ [R_W$/.~Y//4F)e*Zla Z.!Vz o4\k#Ul])1DVfi9b'h\`0vb MǪHŋy,Q?x:.k>4RqkDp?Pt00!:/O[̞>ס<--<;h1Rl|Cg׊{[.u Z hg25FȇQ9N!x-rzL]B|v ǫM3]&WьOFSc|Tuq㼏fdhkd-sa(Js 8jm&L$G 1~TnTʿ71jx" M85, Չf8w~P?\SFTߺ}W$| G@Ǚ5GBU 8hPx"ЀTBxsw>R_C%ׇ=?77jP}},{e":x_!h@4q&kjC&KGҥ".#j?=%)|7ă*j-\TsE½V㾊^@g],nZB4YLg3w:쉬1Е#HXk8oóOS&Izj7HlCi55`BR_qG=&9u4$fYM!p@ & (TYقdfu갹e-HhROUփOɊ%@Nǰ!*G14[-_,Vi|UG.1 gPJ$}\ہ} 4lhKdN NX߁buPՍ~XӀI}_2-X^D ,tiOgnD37*;ҚJ嬨Iˌ`#9˲ޢ|WAgmRF*W $͈?%M~JHw|pDu@}RP\-Ք95On.j[Pe[i z]Bf:*?o˧=|6rec Π?Irݾՙhf*9M 7&dǛ\bgSF$~k*oQ4>cDH0dPkGT }X`2pp$ ho0'|I}dg*Ey-P*yKE|RMg=پq3FATsJ5f_YU*n*kx<'M[:ŕ ;"_}>$P65vs/1F6&ٻr$fsG▢h6fE ]QGEw[ <%.lVwrOXjO\* S^;jC+v:&pɱNRȕ w K8Vi.ti>Gqy"o]LƦ#f4qeVd[JOUY}ҽ)*0,X~.Jmdk`bx)t `jq{h#թ/jH}kۋ$)pLwDQ䵊dC_8E>Dx -|EA ?2%z<(( Tϥ6jcqO!Elf?YH` UF{gF +JUs!Bp+pzxZ1r揼1N^n𙗏{748o9o:"I&}㻔TqC}R>6VvwrrDГ_o3O'簼,d \9nG}Ǒ\;_e}Y?.WUu\9UV 9JqGdt1EY1NqIZ•WZX%(T}.ԋLQ;^nNU_J=@(f,7rs1׮e{=CNdɠţ_h!Mi tvI {G]oaAӇ^N-7hW_o6(Gӄ!| \M뷊(a|D dZEd:Mޞv/ ttq01Cej| AL,~4!/S,hqrt.a29wfHi Jn@刲V ܏7s3/Ogwu)] .^̶PׁlE3:fCsmmq/gl$n<k7tcM1!ގ}90-c{ݫ3v_6y}EVDeE\a o/C҅ :n*ve_@w-I}?ׅ:| PLN -yq}ucȆdE%wf3~xpmew%f*\hPȼ '#;u;5Bue7 [ٿ :7*KdH5cǘ=[e2E5<z3  m Q}!Dy[Uh)|C,oTxӪm̆! Hlh>ϱzd# 3B:nsj ѢH9A-+%2D1Bqbay|=n"n v_OwE8Þm"u_ٛw- :}Mx H`C,Yf&)z/~ic/|]n1ߝBDU}^i gieЍIsN#:d)hwVd7a؛Fhuv'a<#+DМqɆ%qtqtdP;Qf3нKKW ->k.-*w~̵sQf}}N”{ 3f{$H 9mUT|Z$D`M2KʨLxRdv]7_'zʇGHr5+O+ % T⨗NOG )rKǓLx.)H$5&%L"Geĭ_c2 =䛞[DERΒ ph51Ieuѐ5.g OwU͉\ eIV$&7~2,R5zM4lm-*J@T_HՍSg axjȲj؉yZib?X`u~]߈}q&lW25 ?=\1<఻_~2ss~әQ@Jkp9^(CE&CIw< Y xn>5;Gty]}]-?,Ϻ >!{L}DS˽G.KCZS'R=(<ڇ(,j`* :1&4E삾BnNaV:+ǵr:pbVsY |LaF y67bPE0m5ʭ[џ'^qB6;eފq[/-=W gm]L(-=C[Pw`;j+߷w/#fno(YJSCK sonm;!ts/-g frʵGPitDt{|=T |lZ1&gz=MzM,9^N]+P` aA5aAhӹn"aW:Bj KEVvߚ.a J '!-j.>z:r R!mldą"` X:Nヲ6SB" i}W$ Eo#GG(YEL! DB:tWV#-MՐZ؛q̙PUi1,* Yr4U+`'7 Ò KAT(Lb2|-_5#ejxCw!O=LS[g!hEֲXF Kc-DC FO{U4>JX-2W \b*aQPM*:P Yn, ÄinmD| MSЎQڴW]EE3C("C* ɳ%`̣IҤ\`EjH#Dgv{ؾnUqTL\注<B-+ Ow#L_ %W)#ޅwQ9y`:7g}sRE2PIJ[e+_xDҡ{YVbUT#fK=Q5kmt5b:aA4)sٯ nr tPMOǙ8OG ӍHD[\m ''c[o.~E7{(&ũX ^-'IVEg !f]\\8gUee\h걵tq[[(4$^ ͳl nrA7>Pf`nCgmbW(3mQ)xBP&%|d(|-M1?m((;j j}#Kn}[cd`}\Ķz&HA `r0T&?qe\)ۣ۴|j@;^2MUKꊄZ =YKG$Wa ,l} *cϒ~d1DBH{8id4z`a3-ݕEw^\ JQ{EoGI_Y˘P2Ca[5ߴH(<7ץ2Z ænҹsg5-mEJD}[>kD"-tZͅ@@O4~yn^x iѾet଎Oh/X\=nL;?s~?J( JƁvٳ*Ơ?u9YԠ:2J?^,3V9uq;XJ43Eg9A&g;\ h-PQ,7fmQɆE' c#[jOD+ =G$P7֛-(L/&--]Dk`Aƥt/TeVԇFe{x"et6*%U @ /GeT4.G$?WȷriVdC;(F8,F#%*dI7:;bKl TR&T nSnT<$VLys߸obz]qWqVė۾bX*1ۏ70{ Or>'1o]&e`e4umgoeԶmO/<@qKf x\!7@IXӴ'Xӈ+ہ휹Pyy' 4ɉt mx)s1K&7QTpO^ӬUZsZJu :B- [aZdA.v@=kGWLbѫ6Z Anolrh80edNL]RģIHA m|ҡI r_\Z>BsdiQ28Y2n=-30 MV1fY4_޲ɍeYYJ9p&-Ю5z|^*BT&A Fieij|P7<Tq5=NZ*gPQRw^5fk3{uF3ş5 ^u)7{oڢ޹OSa6nW6]Ln:nOq#a D>̳1PR'//ͦxmDѥqo{LynJly٥TVoZ=_;[Mf?E&BALJg.wKdy r_NǸM2O/VP쐝ft`}OL#>y|%MZBciP+hGe)|9DxܽVI&nG#OZuޒ ,!0@wƩIi;(e[uܮZ f d&R/T>zqn}WE2{ڮv _mx\D0+u-)Zln$ʔENDtijDf+ߚS|dzbv+m6%ƒP ɿǼXڔoʥ[r}6Bc*ߎ,@!-/[,=M#>1G0%n+\\ `ax5d1,\̢I?ɐ.;;Tda!g8on[Dr8qYU%f,i-:\y$8-p[NQ?H N)jR>]2GXi.q =-_V˻~,to*t Ve#iAxJZxqJY;Gu({sU{0O'h0t1,S>zr[B)$+|QOA.O-@Z\>So9NgKgD=RI-?<+6CʫlM-<1>fsAᎬ&7YtܾW%9-C7E3zKv[ڄ'=ѭXNaZ|'l؊S M2>+9q甭Cj0-m*Wh@JUWBXjN5n{dM4`U%T9L UyD^x%׎X<#S ;mײk`YR*X¯s֙AOxӪTv6Ee2U &#a9';3?Zz(Rh, b'ֵA;}ѳ4M4*+%1 XDrz|\6<ږيe rHCWE)A+b݌y~1iz,햂21HG񥩶el=(z;O0PIA&DJ<0J ȴT(P>(Ne>cӗW&ciS|^ zts]!xCZ/]zׄJ ѭN/b5M1pOxzܸw/(⩸S)?]tծ~[6Nbn,没RQww_OJVk_NT$Y^q=-mM'J P: 0mS.Q+CbU*$/}n.I:$4=# Z ^\G>sN2{#g|(pJXk&oh7,;i:IU2Q.FyЧ'5}]*[+@UIJs8Y}, ;M:ٯؔ| n{H]-ՠWyi6Í.xI}RT;B ձ[@ 9<pw`utZnV: ˞,DH5T[1Dˎ9lbHBisMlJD6Q]^x^Zzw>un_@CVlH%B}>CՒIEwʼnR|GCT @)Vfvɞ²B4 LB*CXz:K aOA7gnEv W̢I26$]&VTS-JA:|ʨJ,J*3KԱ,+Ē}pU=vS$W*3o*8 KAiFEo٭dp[X\Q9!PIDcn)vgh5ˡאP*, (5} LE37*ԥLoʰ29FDMg mhLҁ*7aA=6D9D'KN,1-$ƑL/@ٿh ) M׹ĂsH̠ہz?@[ Qpn/l#tnRVg鰿.K㬈$D= tÛ\2G`L޼HQ v{or+.} wz}xQM|;ӒjyԤpLǚoE9[Fuίr>Nqћ@tr%%Go}BkRaqL5eyjAZeM:lF #IqFƳ;VUx5-S`Ydƞi%= _"ap!HWkt.2Я]?%l1cHm$ ͳ X"N\H-9%V~7}`)^vNM[=^n~XO;rÍiR셇eʋRȰxd$Wcr@oX[Se{ 9kfe!m:B5"SY< ,g;:NA^MmZ$fc<8bcky7,|#5lWD[mSq1]`u<2mԠM(F/:8P:GwZBGžAiGUY ^5hm{\6;yaLPz*o?J,^ͦW27E2$ _*tuAwEY]ؤsfP,4E`h|[[Tz`,3z`:sx\'sHw/=APꭚjR?edAW|.b)~R_( VqJ<S"8]w=˯`AbFdMəjis1J THf ?w}*7x}xxwz8(aɗwh^h°ۭ&nk05󻯵G0%O#זwϴ*f;Nw!Ro/lp:?O7kYzAd,NcE(Jh't! Yn%i٠6Opꤓh1H&CNN^"%%#x:E2 3|(TYju<@=(zlł~~۝Oxd"QN S jrtϛKpxl1B,FiFbL4p46'+ GD0F,›C`lJ .29'b'H霸@+Mx/bo|?\O5ҊzhagXǻݗZW jɟ__x8#L8hq~SZ?N{z{Pmj4)Pʇo!Ck  cȷu -hh^.j_OX?7]%=/{!n*|~ݏ40_boKu=#Z{=[?{x4-~bkG8~_}'/UgR]5|O/Q_75@Z!HO4ĀVûF][k?{ *]qty5?9iW1z(f)(B O{<$;Tt8la%uO?:MZ}Uswnn_2Y3]Vu͠<7b=ڏqb?*~c}n{_ œ֘J+nq"(oJvr&Z 7AV,51xdHW3AAOf}?[;;E| _Y0\o-%)H_Yo/%)D0u ?$-3);epޣ F|Fg韧gowZʱku R/ ?϶M~[<Ŷ@yD]R~u'`ɟΛ6TlQ h7 ;٢Y>FՒn:]ӔP&p"`#].L'Cr]].J6&ԼI0٥Y˥)47_sg{;9+B>d}i,M 7|7w jA^E)H;@W' BJ",Mc<4\)üVpMy߸(W7p_gK_`CP=fFc4.fp>܏}wv/mx!۰lU𗫫 j= R޺$QGsQ8]ԮI"7(hٗ_(ˬ ]+ð /i1mۭ-Vnr+[L*¾ \_`6)Dlivp? &2ee}6T{koUi9?j|XߋuÏfL2+4|Y&Śu]qlke/ o?~lXޙtxUPC}B983NNNA"xA 3`z~7Su^P|LѬ JdČա(nB 4@Z+ ֑ iCYeΚ>p &waZ2+੗:}I%`V}(bXD_Yȋ1Lcǧ`Fyx^:Wf߃&A5 Vl2qx˚M)}Fg'1p0yh`hqL1p8 %6&mn␕)>drJ5ZEf s%KH[ N.wGp%) ec]*MJ@'&7)F(Jia7$zn#VQe/gKXd2pAb*Un^CA;L3֖؂IvK)m rAWP J|DtL$l0+̊pH.HKe.yAGp;9hzYT>>x Eχ+0^fkuXy1<zƙ9>km7, ,K3st3dof4)ǚ͜h0"rg(pAksn|_+*n{"r7F:qm$@h}E'X:Lz,{mXi KadJcJdт! z7Uwe8` /tD'/kR)uQqVh4v6k5ޯ7sbcR?~ry,36|eMQ/Y 5p`8N|6} Mx^|I%5*pobofsD< !:% =lX`jO@:ش~m&Of+F0U'a<9i&UTY``>J_uď9%1YD.|a$H̍L,@C@kW\=:XkoCpb&FKOq9 UѠ *Y=dz"ZP+^k3D NP%3xHqyѵ8Emٯ\ cup ^[wN@J@Ey>~q S[o&&nxp&^D6qpF0yTE :A#{6 M5KE#1t20~K I&Rdlǎp*x"#lq ^Z+SuD1Xȭ5m[;0d-2*uvz[ [iO^#ʠkC3k y \7swVUZ??%ofS%0_otSr|iAI.;9)? f CE)al8/́rv ei$/bɣ$ȓ^*[I|gV8R *1-/4aԩBx"B>A]0N@K?WS'4{Qi*3 POgvH"7Cvs> Nؠt/J<9avBcә}(g d9&ZO?|ZFcY)CXCӲm LiS(߀Jq&J[ZЋTGE`dz qza>buᇏ/Ap2dتŽhɰ@1q3Ȓ5kL? sL䎅r狩g16 _C4dKx~nW_e c=rKyPFNc $N1%!GΏP̨EM6*4/׶s9ĘbevoNb͵1c2Y A_(g-d,kr#Ѣ<$(fXڟ́驋wV +;=gbk~aHվ8g|vԯ (UcJ{RhoO:0$\Q5XEl)XHeC*JV`Ef_*<4ȚKT$VH PĤ{XB6i2 +H =\B+KZ+"pTݯ7?=^̇ˇBSG՟<:^U>#e*FF+KuҦ[C*<DoR݌ŭ<ϤjZe-aPsړa5X$?Ίgˁ9A# f Ϋz"O0IWTToNHTZfRZZ+FO׋~4lBCmd|*Ռ(ћC&f"} 0,`tIl#Qe0b3(Ö-<ݵJ:llcz |Ngl>C1_nX=}-޾ ?aoy No!;8&L~;lc[Ch=P6ZQiU K):<6zSpJ!2?m)"řs]ZY@,Zq Vax'8o,Dn9R~0$.tB3ߢŧ?bWV6r%|Rs%AM$_.֐GuįT \{h' Ā}>OdO_160n*HIW7ޒRӃy~n4"~ N@ZF@S+:Ϙ+& MB: 9aj\Ŭq F]D1ZPLpg(nڪF-gp*E\ Um42Ώ F^QWx^Шjllx* XI6b dh_ ͉k$v1$r.T!!`Yda Ea*)(/3P :i&@ GG?4EO]\v] M7[aJʨd{PKj$"` rEx{ _ 'YYڥ\N&9AXʙ1U W$Z պ["/~󎕷%TKv]f!A:Jc)EwI\Y*2aQLy.B8m\y)B,k|*\o;>װ˧iKbΫsr12V=U֙81g+RXx4)r5wlUx?lŦ]dFb&Bȶ4$ A<7&7qx)9G&ɝa^β;8iOAӺ癉AG\_y@/3c05]`lɏ͙d /lM$_x6S?C1N0n/9E2fbحqạ̶9hM'rfgxWWOPk p|lkMB.G Ta 0z.-Ƌ@p@qZ|􁍃$^1ϩo80e230Wkў χ; iV"Itx9Z~xUV/|8Ђ`OXR]s:a((ɀf#@}E:Cq򿳵uOq¤]Pmfۥp \`e%2c7ۀvuVE7a^+mw0]wf~!ׯ]V6E6݀e} 0,=2S8)» c])4 5PMSoiiGY M,x S<) 3 5ibwƽ!* `q&P  ?|^̃Mb6]e2sB9vu <7J(E2:=%GGh\ HD=@ԠhpE*ύ¦8큭1lF2"_}[0t[Ѣl6lď(/0 o1Dv8s6Ce vOo6lݵ*eBx"SY5s(i>`yC `ӝ=HF5 x۫O[utzbZ5>JF ]lHuUxoVbgv0՗cM7GNJF #DEY _ࡷ@p9^/DH-k2Paື6a=`+ҭ*vBi{>̈́ /f)lW0_0.%6S*yd(0bҌϡh"OD+ ne5,M~^{Vk:*Aނ 8+--igv~7l)۬i+Vc5k># [P\fW‚OSXq~u4;Ba;%nph 7{5&%tg`f#\N3Ai9Fw{m"ڮ-#1u.tG޲sG0&qC9] R/x3#Sn"numtCOCwk~;do=srȎNٻ<:8<`RK64ם75'㳣Soޕv%uw@&uY'"(2 8k I $HUHB{U{'PHܙX?UZZɖN 3P +j.sxO B\Bs׹Jn M'9TOJ9:_;Qe b+$6 Gjp}*3ӷzs.6Uj\(z+U8WD֑ 5"6 r 6"JD%wV** VfnX/4PH)PaB0(;.>H|U5WAEy*E%^t{_'4 GetQAh7:CU9f3; 0)Z Wŧ$_BaRF3W xoI-R \L;-ڹe`{$ TvH=/fUUդXWj \P{տ {! C?w!V aou߶mB>#7c)·YD)GǑBq!{pagBí" :'g>E7%vN}U*nPف5N.ݠ5D"XKs}l5czt <p^?\!Kn + cQf<=UG^C4q MJcG3(̀GqYˠmX~(*P3xVrnB/iB?R,G\űca'?$C H' "B(y `i@G ߧ>zOOf7'ORjUoϞ) ^ql߆.wgb >NLb06(8^T`/Nr'؋E "{Qr9:NgrL g3$ R7h5r3h6ox=ޘoΣNc^尧 T: Kq:d(f'-_ ' _>O8O벽*lPI]5YwϑqԌiCӵ?2e\Ѥ_H{UC~i[\7ƬbXW#%uR-W65!J>,F.t-zL\ {U&(LPh޻摈[5#DbCZHA3t0LsPr-[uH`}>:w.=Yl:QA6 gj tVZӧ1vT_c a'IڒAZtù%x5훟-ۊAJ_#ZK[l-dz,&j˹tLX'ZKӡBz!?SzV`_-עd|{ŭkLU똄_X__!:k!%6 %IבW #VKɶh/-:F4&79ҭe,T+2l]!om9۸8*}&0׽,c87Ygnbs(~o4%/S!~lDX i'P+ӶH~O[PrlA^}VQeүr#w9[$_Aiek*ja/MwU0+$ dfi ell6.veXY:%6̪/Cor<fxq$8$8Ipw0ǀ}- |f''5I+Nz4eCtXB5Y/z&!p, $glvq>oI4/ QQԇEfYĚmu-^-& `*.4\LA< n@ .B)>8Sn~}`P>he5= IZ^q7`M=hƺ*)H2@בy9F ?,-*}e$1rA*(kjwIK Z0X܂IEEf}:h^ U!+?XR[\VX~)z1Nϔ(zN3ƫۇ=g6:}-O*V@s+?'C?9˷D6;C)0';Rg?n M=<?tCf}dyy+? Ds}Sd# C?''؊?-OIjOc\lm,֗Niol@׸|N}k[r|7޾6!S%c'B> ˧"_؊! c?Y&BUi Avt<4o;] 3`#BpX.^Q7od4Kn8o'xIl'[Ȟ$Bo$lbЯX6mYTm3(v.e\GmێB3 tDn$ 865}y·-)EPtԒ77RaN}vNA~ +r^_`A_>ZO&CűnI-V #{K1@סV?"&"!/Mc-B2Ib'B> ˿' '} c_Ȯ?V>"&4Y_sIrg;&]@,`$N ";N dhЃWF%ɨ'U5ebSG(ȄN%5kX7? ߭2G?aD IMhT76c iÑ[1{LL:݄`"{Qq8YD`/RN'؋E "{8 ^Ste9S04s)LG!F3Wnf-OTX';0EA rXq5j4& xo IQk%x2 ?2&%P5OOBMl9<̶C^܊i{-Ԏ4K$):.5e/;TPny@م|@m7+Q{ʷ'p]Jvg\v) }#m"1mh<"b*v!ѱΣ/WIBzi5 B[!ƒ\p?H[ BN-X_|uS  -F,n"fn6m@-E>T&#-=P!i!~bũN0LgR.];pYro먰ǾJH:z?D1& nRIk"Pژc[MB@܊I|/8xE (\B"$(*Ť/Ԋ7AWEPS?TﺽZk@:A,,Ab䝴9v.d6cDiĵG;YV&zؕ2ֵ|Q̤ٕvm9^3[MvוI>Yޥ<[JI  _Zq4[6ʖ~;ߓI#_IK=Y\޸lf\rH aX,RK0"ZhXC卶W*Ӹbt @S`}$sjonG]߯o[ck y|3Dzz-rxPU8݌ N:3ܾmJՓFuLMq+J}+tEL/ wVrWxjɓ?[15j z~ktDOR=zC O8}87l-;?ɳJ9y{v/_~p6KSIW/3LhW]ӹj3-VNgjiJ*3_Tf^)&Ķ֮ WvVdܖeޮ*wrݻ:WUd:t.gRT \#]88\N}{S{&ߧ\ ….tW}NÁ?vB>T:('Y^n^Ig洗 i$j(~0xw^)]8^ Ui7ָwRN/^~Fa`@k!^'UL ӽ3 cIn0Td۶z8:69)9^6'w2-W4y2;Ht0n9$k㧋ҽp4ˌ&-i(>ʷbθ/GSNe_9Q/<{Mg'36WT sNm4gΔ+?NZ^w>WeH)lJ[gOj-?oޜ#5bmc:7vg~bˊR!/ մ2]1gʛG?A7 67v!@!NwU:@6ۙXRݕʪ~OLX*g96u,ߖp= }h#ja_SkVohW-!is]ėnN|ϗAhR vQ+|*&Ne:N;Xwl<CJ0*z]GԕcDx_NȢܨkPڛF\fD. HXTɧ8gRLzݻ:)TJv+PQ'Vnn5aF+FGT68xJޔ[ף0^]SJ{$PfQ GǬ6(ܡ\+ˏ~+s*/y46T(t5].]'8hu&B2+lzo1#YҭRP-,RwPnFc~L5M> L)(OL6oB )^xb$b 5=5R;-ߒ|O (4;$iH|~1Xpj}{g25} B;Q0z-<۟6\AiW'z|x}=bYE1JJ%UTm CaPaNK$%ߴkͽ~"z-3ft7JQPy_EEINcWj6ɬJ>I~-3f: OpR$ﻍ)X[KE/O7ۧ|g!Y DŒOL^<&(Ev>Ttlpc~~H |,*QaX$+I>>RZLXGRm64CN>54ĝ(ʜ7ݮ(8o11BF]1Vaw&)=)FbhI#܍lplSԘDY(MIw: II͖%L?y D,˨]^)bUcB̶I y3~xŢZj*DS)"6uTB/[IA륲a6\]*|M>*(r| 9ỦD3-TQn}ZpkǕqsxK,=eYcb@no֊TմT3}xZq1Y#Gǻav#6')B 7IM>_c~ /WV\KExX&GotDiBEAkre0[EVJU_תu'[ >v"]\3z'^~(@~M F0݄FbSc~9IBEp@|&Ĺ5 bw So ~v;)_k+f8cWQY~?")qafyv3 BW8gľvG nx~{f0ry.pmʭn #bU\?`woEm,AXKW}_?lʥhX֌19E>n6˜;f?\< :????u2˕;`]::q+>lp/X=^h<|1t1[?$  sƒyԏG?+B#ZӯX8z:<RUڗ,JKE.Ɗ0~Z^_L/͟K_>Y+?=|MKó(:P.:'y6ķy #UZh\Ro+pӜaע#++>-YU`K4m49v_g;] p $0, @:81bsiLt.XoorCq v>=+uy,I&G#?1/P0ww[q2L+~꡾vs 4HOW?kws/їXjy AtK>g ^Z.r& o\!BԴQG#JjE>6'jPT>6m4V: ()uԩp,гDY 6zMRG@=YB \ZœZ jr]BR+/H`{w_NfW~'?:e`ɪb{qfxl϶!W/QA!YUTnHfeODDhtF HA) +"Jc4 (n6 Æn]:fʽjݱ"Ore1q~?H,|z;߭7Io&{ד>سWڗpj_ܩkl[i#Mbc4J؞J?o_}#$5|'6 Fm8ZiCjCM F(%v|EPT%_+У:~b'W=/]@  x4)yhU~&?oԩេ,j4[Y{s'EOߦtGOң̧ K|7SMCD@1 UKPxW:ޜWst3(sTܬސRnmD?+JolIyߟ\!M,˥sWZvԉxo? ,ԑ`H9V+Mg<Ñ:j mER`z< ]{aQk ?>kW}=Z[Fy^z` 63drϜugb h~gQYj9Lz}RـMs*7 vSvmPS=3ܰ0cf03ܞ hp~_ 7 {ǃ`WDXzf[_3M9j (ڼsm8B N:oFmިA~MqCJMPP`anRP-2tq MW]M+E^,f'-^aO/d97aŠOoX&'{LM9Opk<4>}٪po=MOox&9CXpޖ*8/=NoX y"M"j|9##kU#aZQy+k`09 K|70oeE':g|7Sy+V.}OqTї:Sn |ugSŚd?#,{z^z2}Hh`7! ( ׉::a?Q]N?Z丹lQ9h4p`rp'۷32=W;i}tL]鉺HwvgpV(Rm% 53^/kBɹ/<8 ػbl=t GZ,WlAɻ+V3<9eW 5:HZw|u!uHj@[dO_@@p2 *r *_}7W?& MsC*Cª̣5$`!} n??࿅=gΠl5==url؎*]!9`Q l5-GA p>w ion 9Xp:h 7_oaq/vО?)9c_, ooΔsAAXH>@!mh7-`-^h\$'I:c6']!7:q0-u 5z=݁4!U܁t!̪/7f(vJGFn[#"P:r7x:9aBN=??6g1_N Ks߆Opr?%߆A_8< ]!m/ EM$k6tt| r~w??6)Ӑs)7>7P>9jn?Xw)v<#05GcwfG.:5nԚ, G vT PN->=9ßf+ שƩ;'r?s?-\ 8 }F+ G ݓs? kNWWLWj;6Ɔ8>ӛUl=TH¨A%'M߽G$!! a6y?=r 3OGoH~K_I8 F/voxy#\~/$3gmSW`?n)1g? S<|7&&?RG Z:\~/_p8 ?(Iƺ~8 lt{ I118 0J&.Kb??ibῇkxbѸ(|_ql?oj@<|-ĚnvnTդ3:ܘAfO(!&@R 3ymP)7._̧~+)ȹ/#ԍ[ 4HH'C"[n|qY\ؠF؜En,^'bg)OM[Nf떛Xo1/1g? ![nnˏ+K98 _7pOas0/1g? SAI$lp. EH]SR\:!(XPS(wN);~'x˂npKf۾$in@WS _Sj0!f>sS뛚5 ;Uk7Η 8G8 wh': iGׇt~,P}4X4 Yg( \r콆w5Ç'"C뵹|i Fɳ)?.-/N_HX˃SV^3gO? 1? <2U54ueF,F -/m=n -n\c( l XV\`(.U(* lҸs`pٲmՌ E,SO(DOeH VK,w.*_y W3g? Q]Bew羰(>e@TF*~M5 ?) TU39!< ^e}^Ź_ #"Jh5U. >ڄR/ɁB pYkv,qS".m!?+ * 5H' ȷD|T SnC1ʪ[0m> QSNu'gju'V,tʭz{u dj\JG74y]m<贞[eSCF}%d 8:0ʄPd jC(s2'2""^&[%@<}ZzCYEe*P.kٶ#h+a=vy.nL9 {7mNMf~LC[cV5VEcbXNe+yZC 굙Ujn7ֻ݂hFlpͪj!] ֘vIfj Mӳ5O*64>svL)݂sH iu*ih Ez@ ozz]$ ̭lCͲȸOBZY@jBӄ<`$ݦh3IoN7!iG Et'qCG`hXʸxB%K69lZqcAch^έn̺RMZZ{͛di('i2=gSaE 87/j,/!˒|~ d|eqҵ$[ kj:c2t_6 URt04l> ڑy^=?rQV? US"u'I#W I{)b/D\tmh2 vzT.+w,K#ilKq*in|,!.lkΝF*o5lgfN,̙ c9d6v(C;p_4_H.+IlKqIcl4 g,@r( dB]L*F8[|7Wɶ28Pf%ot ?^RL3bەpLx͋mZoώw7ZvG#xf1U'[;p0(5>j_HY}Ckvz-D~[*vg" mArOQPλg_\38vdc|%ra\" _oV ("LuC+|ݸ=}|+2LBF_ qԏ6Ľ^G) 0mhj͆=/G]+O .@1 glDE؈s`|$GvQ~*#~sW(?`MEH 25ʶU6D0pC"΄ S+lV>0wNs={P=@PjyV;-Qj0z2n8TS/V N<'+(a<ˢtiqq[g'>y- =|`\e|m,{BnޜsA`C4C΄WUhAԡ<Ӣtyx;#2Hm[vɫArPƎҬ yt01\`Aua'nv|4w2%m?K?AR1DvGFrѿJ]d"|>W]ͳR燐ECN#<""VN-3E:'5!e8c/5c/AV– з'(`!_f ܼB;Z˩#\<Jd>#êMKD$2WzRZ&m{ha|1+ XJ?icdVYN[+}[-ynLG/DӳCNN !F_ȩ2"k2juThہO2-{󗿑4[GU nHP;qm焦+;|l7x ļjXtcbp`<&\)@g&EPTdxiGNaxKL Aތ Ff~pFfN6BaX*E *^ܪJ(>#9znhKpX6er'$7) Ofy=n/.#~g H!l@XЈ@dC'4(uɺӀm;{QuyYjxzϟwcVu;r \cr`Xe.[=W sI׋-ŧwc IqetɞYRklٍf ^i[i[$?acе6?irV@i *FdFh~Beiu?M'R~$Fb[^A/4Urc}awa\^ghnucjpQ~Ȣk۞h SU*6WS撻 .l4RY+c6[R$\%%/ǵ^a.R?ߡ\J^M >81Lc#*o!{=H=G&Wǿ-8O$."x?Ѧ,$1naT:D! 2or|; R?̞IwoN p}sE z7Zw|x-zΡ@oj;=1gk?{uR>jg/ou)ws7+Ot OINƛ5YPY~{8 xq:%~AvӋ/.~W4ٻnaCI SH ܼ{w}T۟0{?\~ ~;?_]H3~z0&ۧQ &rpZ?G^w$@N\%!XKPfomUM듩`o^>j̎+%p9`S OH;?GB&Ԫx{XQQ/p› SC{p\wxAsئ߅~_\ iroSʝǽ ! -'ǽ <Tu'9{$:CU8nIbU'Oi&wsRS 7Wg/;٢hzKF#s$G,,nVҍӽ{^VIC\SrD!̲''(47W.$s|qJ:."F⏊,3'搛=xv}[l=IÜpǝh]ٲ4ީ&:_ B܇I] 4Ti8ǓF/)?AN!0E@1^+Uz!%kq& )$AF^TU|LL"i,Bo)Jq|nsw3 fQ)xD)lEoyS[(`lXЖtp|Fܛ9#>kw)*GB`]U&nh/K>@G|sup x8r6)grBpŦC Ɇ|?{Oޞ/|Ӥ8qN/pƮMyxA±滿3{iuA55;;3;3;;Bcd#2M4"O'>#"0F+"'~j3-n))0Ohٔlq׃UAřԜ̆׶S;{A *69BUlV.lYGO>}k'( zKM:5$N6. bͰv<@DÂ0O,QÇ}"˗Sg5@sȜ2֗A)(ˏZ8-PL*+ +baw}Ԯ e|X^[MRO?]e@Q?"2K`0LRle2%E`J&`̼D鸊Hǘ-4(9劃be稁|]LvRFp~Z^LbV cƱ䋂Ze&jј.PE;gSCRj8n+jtB{Ļ7 )JqE}g-,Yb:~&,O8Nft0 GC4~| )CqUIuԒ=@PL<3Vt5%|KTYm*$?1#Y oP[ ײ]~B <>?FȚFR!>H+[;b($.%]D袶y"z8eW roǼ-!K_'sJL0FlE cf^SCבk$j@%-wmFi׍imu>0|a 6/AW74{W>F#fή$$ЮܤmG`PLCV\0Jp&*\ ɱUo c0WV-eEtZ&b"y̪POcs&9p I$(X%yEHm#=p?v7)Z,nXǜ7R+vݬeOg~ {fGqcvunv~^f^\IX| K<eԳT6@6.Cvj$`;|% -~Vx7^bѫwVҿ4~>JEZ"{ƫ=H=~b2IJ6O[3{0J…ӝm @߶ E#w@/8My9'U.sj78:lI3x5Z6`P15mcsP}k蔅 вDMf)ؠD:nF"7L.AP<9Z{uxzcwo4֫wm&tWE?#.h8 4 j*.(%\K Ru#džG9Av0:6L@JO>ǸnAе=tɀ9

,'%=bwj]^wձ3"*!Xbi4 D|f@wM'Al^KSJ۹pP@ۉ-4OH.DI>ދ߫]<rb$"xR٥@IrHzn[]yrr 9!E6Dpx@2<)K͗ (%M0 t$4ܱ22q+yr7ѐ-_9ڶ3N*8E`n : ^+PVk;hũq@!U?\Q|C;!@ݑjRF0@$ y#"F"RA2Xn uu6B z$@oN'! k!Bʺ,  ^\$ r`?~\k#k1Bq)ڶk# V2긃+T ZץKlFB28r H(A)pib0*JYH"Ņ!QDq1H\[J $؞tG1}ЅSv.RF _Sia0"TZ L0E©pHt M̜ӗ Sn}hT&TK2]EM>6ÁնJO:QxA6e*"7 Ug`EL3+]S`ރ@<6nc.Gm\uJTŘQGx^c=hrl|S#Rg QJI i4P$_\l]gb2)^+ŨU134)wyֵ3i?|G[Is3L];j<;O"k= Luη;6Fݨ 7L ut.*!!ˁS3Bتa>['{S%$!=$bփdÃ㺴3r쪰% EF=0_"_V-As^_KKTKhLd1d15t0 6.)4fdaO`ӵ 6&:M-LB-]_l$beܵdO:}j E%iIo:8h:64|~8* tiqS0Ѥu\VCnGQhe$JKa_7fw>$+,Ew]@kzOP. |Rte5!F< _mCw=Gb͓:RN h(*2'I)R45:3=_t\x1q)⥽wRԷF l Aq3Կn'v[GoV6/R6ͳ|wGXw$Zpu?鳎{(Ls:-V$AVFp=ďKILD BpYiFpY*79D޾ns-XD:%x36V1Rͬ'6sE]S5 (=ĕV׶~r "NswQkMW;w7N tޑ»4<9?  dJO\j1Dx'UG,yxsf?R Ofz*>l(@@j$)/<1rI8GSg&%D Qyz_4ޱ.'oީ=%m}342L "bPl>-${)%HĔ(0XAJuL5qg"&Pp%A8~`1eƍ,{qɠn.yL=E֞,هgRqfu2z3v sH=hN`H lţ mZW9N&򴗷,f\ʞrXl>+/ZP y($i0I'S~(A^ISF'SF(EQMSJ\*~}[$yBC=1odz ?p÷h󧟶.7پ٘3m0r&FYXeK<.rJXկob+WFkMj ^-DV Q_y!*t(o`$mG/,q7e#ڟ#o4#5$ )l!#g/q C^0G, ~Rnέ8ǏFvsaj@{OhGeuW|{K<)tX#)dEpa̲ٛHa#m+rEOd`5+L{ > -;H9/ڣ {-K2O΢%chKEAFչQeeTYU碕IL!e&]2ՁEv vnu`9h?Y6Dm E܈37 I3lC3IwfeHdQ.habAcO&pɄ' 'N{OBN'z'D|#]iQ==1ߦuG!#n1hg=כBw򰫑 yg>sIN  [$do ӻqs( dI/^[,Fj1ɚJ9x>'8S>ͩh(pf7鷧.g}8H5N0' j!GSa,gn_Ӊ21wAs, XRGi8ݠN{Q #H8/Bξ5_nMS9:>|WZHQé~eT $?4{fK:?HʄBWsqhW 8% 5aqX^gAh hNUvdr#'G^L}U'01B9*[|yQiBmЫWMlxBT `ƞl@:\aSC 6Qިֱ4{H34!gTNWM, 4P;>hRT *P6f& [Dэ guզV0r-`n{t_i{ag0WzS5q~}a?ہKn" OI1|kgkj !}f]"uY?ilzhl~:a#틢&_*u53rız6ZTW JHBӟyxV޹Fe?f{w[~C /x_'Nmk+Z;[Ow 2,JSwBKRO.hr1@m/& Q;c0G8>@ ֈyAo D2k'[-Νkqf㮮xmlTDCxWNE"#n{ dqMڈV6<~ZGu,WDYҮt& *xbƗX@S"OgG{GIIXҧ`b \17̓n9iJJJ_+3*$tI eܶ8 ȝPcS]|ThF6u[J0#(s,:b !v+v:Ϲ]x#dvf^ BX.M MlSQ*g"'tXLۦ7CZL=}2Z50!t,`.B#8;}eAt~E m@1匸4i)Rt,;; ax^m=LJBP? 'Ġ_O@  ӫPJ]21i  InCQ۬HzmhCZ.aƬĵe?߁F7csVR{[^D(K{ y=zk߽݂=%ޭ ~nKwb߽۔ݢwo Mf-S2ԍM-"o4b[3&ΤOȓ3,?Iy!hy_g;0Ae0~U~_߸.!w*t4bn~{ ?gg4Y~$B x( a@fyn xʳzm"N4:A+:0:ojg"2chDv}:m }Mxm˗4t~ZxGv[JW|5xD~~M $<#[g:T/ҷtjrND/^k%X/t[/Lg@J[Ƴ+"( XWyqV,{m~¥؞u\,OYPNi+Z)Bґ%Ied:ʚ5f6AwVa<%MRY}feuj ' FnFuH5.LiU{妌JvmʠW7ep qp@9 LK&%7h1;C% -r4i.Bʰ,=|=~0!;&xl0#Gco~=`'9*6.`tZ,/]h}bnQ036(Ƿ/Bbl [Wi }_^5o7CxqL{q0j*'~n-ꆌ>ۋmn]8<`޿KCt6V"m{[J!9*ܵՅSqf!85zN1 Ђ'7,j1* wLA2|GX"k(Bm#aukn@A|+JyE?D-$׬cgt,e<+o;h ]oTO boo&`4@ }ax/p )D1 bZ 9clg` 4Ȅh;g.{T&i =4K*,|zo,B0\8|`_̼-AaO>5ؗ.P<*Ia20-epo"p=IrήA :g㰇=^xdqν>~əhfh(\[JC/lU9FVh: }XXY+ ( i~&oDk:gu$_;Խ y,<3vp|@ߙaLÏˬ7_f?}O2v;g&aOnS2)*ޞ5@h=ݮ3P-hV+fO n``>A/VR8I՞ E<`_ʓM&̕) sa_'$xL@_=o<3ymCk\! /'z+.=W$xbC?̠(ߟ/>Gk`c{F PC`;Qćol o؁I܁AO١͌("ʁS-vn J[7mW,R,Lʟ}j52^(%t_$?h`㑜lx: z1W\%q%~B[ָv)&qa/dUgT&9~w@-"?;|% -_t:8{xoU~9ͷ_㯏Ggi>&Ⱦ?nQAO6d@[3{0J9K;҉mA9y1Y!ILi3?=W Ջg!gQn+니@,aY<Іܚeݒ%\d%IJMQ%YJMaEiJ=qQu rۋt_ wL)-TʪDY8@(Ǐ.@0Bd!.$%ۄVQm zrZކ)CY,9-;@BR )5t=b];Yr[c@uJR:k m_щ Y뽉mS|*'Dim56^D@$s>h:%I&ҲOFϓKtis;簼D7Cc2zfDŽX)V[ŗv3`mC9!B[TY5tdGO2o>H ^,jd(7^?Y0&-3e7.JM~&'' C(?컙1%NV8Q4S9 i;H yDNi ;2ܵutVu=XGae3F?9GvgUxQ&HȺŨ'!p=pv6a'{-BӢ8IG۵&z#p¾`cpc(L n44%xɌŔ1@y!.srև#qK9l<PqnJݵx{>UF!7Ɂ* +x@ݦME&O!;| _{/?aX 4Jk^d̏=3ėtD_ %qeOY ' qR\ OըW2j "WLZ uOGFfWH&U[n+,ծ4xHh@r/]& BC05=~ECQZŜ*78d"0VDZ$p^,u˳unh? ! '{m̾%IdkKB?+QIŊ+;>ۈJz"CӢ"RdQ- haH5=F -=t-’`$YDy ^OUq [ 6mlou{{a!_1erTWW!Jk%I$Mnzx\YՓ -WCr?wTC`Ndފ5FgluLڅ{, zbL"!WJJ IwCFaUֹ(E˔;9ʺ>=M_f&L sE~]:ѐ)r#[P:[+|t=XlW. ) 8yd{JԢEYf^ZR5КsN槡jJ X\K^Ojgnz jc*%7LQzzjfA,qTzRJ} o@Q)1,'ǝtǞ*$~(BL$9bT9R,UHrJZk`qڶ?+RL9sdI]Ge6̀.{'$u\F7BLMTT=`:Db*MK:O9Oa[gU7Bט&$R7ⵅpa -\v!"kOֽ*/!64ъ#oG$MQzcATػA԰yg9O4̕p-\K)vf^@`6h*ID aX_H~ųOlSi ~!iS'O*P&|(^~M[>T3C%5XKWƝ>4:nxc9Қ&r+[NeFq?AFM_!| *;Hݕ%b)>1GQ ]DAQk ;~r1 )tᓓݨʤ&7F9㢊6}3q3,'ܙ)>$>[p |9dj*=ƂY ԬǷR^¬z8SAٷxMvyR  RG=F}wøPgXoM˱<,`wXDzg!^+,.BWB_@{>rO"GBeqޮByF~=O }ƀ[1la쨧8!(z:D8+aĤKk<[!mπ7fxOD#4!C3O u, FWwJO4*v$w,+OS&pp{‹ohC|L~qDZ"lFt f aBXymB -D#spF;|@#l1I,1IMTFCB}=Prf\غ ?u%?71qaHœ}鈪q䙗ԐIyIMԻHRїPG<@iѫLkoɼsYߚ(@w-QvqtA;r=MQ*Rc t5YX0`,NA GBKV-@v&ؑYZԜF,JRƮDݢztDL(BJS pJ-uꈒ;gӌ-"EFK܎t"7 AdM; D +@⃵wO<GCV3aJCS0)D%U6[hM`Q? UoAsTi spBlq^2JOvXUQ=vHZh((piCވ55AZhs`Ѧq/-ٌG( 0q9[lwC 6c{AԹ4]e 6*„|eyE{O3۷o/_u#V޶I{`"{%wŒB3'+\L X qk~|("rWc:uTj~lz1}RPf[ p.!{}o{ Rm(R*Gm_E>??=v}~d ՙgni_MŚ/g@gq+%/XM8R.15@~zS$Gb1~skcTx`z}3cC4͹}!ϓŨ\)ƒn`ZG_|{HFC9riUY?ik54zsS ]3L:D^;W6a驚'uB~_jmv2tkE}NDuQ~+UB#%]hMZ2EX0uHM҇Z`M[K\8iZLlW5y^ZAIKRΌ9(!+ KY4A!].J}п5迸e<7Ҋ7[7Ђ/WܩU8hn@+ '  t$^Hm&*T@Aӝ'簉`j1d@nFƼd9,-9OVJ,$LGECQ[2ߝR5AC!]]DbZUJRT ˸z@znҊ!?o?y7$[uOPkQ`dMMf9m$n&Gm`NI/ai>dK.[zkrxoU~9m~>JCdSe7}Aq"?\^#-ҩptQL߶ <%ח4<ۨcF> ga7! >O#%&BY$BI7YnInS nI nSnQ;$oMDT) R?<ș)<5}0P9GL9q*3ٳj HX?qo&a #Jl 0ȟ 1KOD8L#{\Tަt_m4]OWScbpǰ̋`y$4[ob NA0枏= c}:<ss K^sd:=i.aS1=z$!]eX`47G?^vJ)N;f,1S3a˚ݞs?)HZvd].=έKO.h2JKxf:t3Uȡ%Yx /RD"WXz`45lX$̦#h:(dE>Wo:&j3tlZiZ_ۦO 6HJ)l_( i!4?)t)#λS]WGRxWHe90wx`$%`ҤM] KWqɜ2Vc 9@AhGPI7-yiv. 95F6Hx4%T E&:؈n ) :aIv$%aF"kOsKpNB}p<]5!78}NKM3x~E˳,fIzz-Nۃ'b}sQpism>]e( e\(&g Wё ;0#q'0dܙna Sbڶw&szX_:oƪ2%8QLDsaaߨ_THFjm9IwgvmIc޸w7vOׂ~{m FVkkm 3􂾲.A.,jbt {h;[{)Lf%g =AnӤ-BaZ!y-<`V+ /k Ԝ 4Yx dؖkGb^3.F_L5}#]ј^|9{ v S+F#w(|q ȂV}p6r,9崭f iLKvI`i*uRx;-ǂ@?O&u?|zh^/Jh6 RzȚNQOnѿ֊<uo2 FൔPb@[IK@{T%"I@7Q 7}Ϧr2,th b2qFh.@쀠ݱ\Pk;c;KvFqWĥ=2u\S_N+=^XQ?A ˊ\O9#,|'J濣g>K#{)G"3sKCkjw)Ϸ=~w̧o +_j OC/I ؝Y^#SMMƿ7Gm4D_]c?'{<4 +fv?ύwWhlj}5Qܸ;o8|wz:<<9WQټ5?MN&U}P^ifP?_M;œ{?zg+ zܵs?"^K>}.χi/^Go拁ٶݷIpUy}xok.ߝ^~4>7ޝ|wWYrI{Qؗ߃׿98swh[÷euSk,wnfU,f?8,_\NcŧG;eqcpb?ju1P@8u@{Cjl[a@?] ЯV |.B_-!{#)`ތ4}ѼM_s__Noϫ QMjoWg>BjyqNꆉ="3&7c6ES7C?<3Ϋ'A. hn_y+;&ZΚB֠4AV/z5x4Sü +^K\-Dbm8OZqGޒ :6՟6E|p5bQ(=FC'(P1qFPs.Rݯ7R)#]Xg 9@ur洫n%zL/#u=Gvc0 쩇MgNj S=`?xc yDwҏޒ{~(C1HU'@H 5a<`7 "[(坄˲λ}d+=۶y5ژ{k#*xxv['{9ȰK(15 ~)%s"(o}Ȕ6a{m(Ka `- |*匦 1:S0-"$ d-K`H׋ا0/C!et$M"׿k=ֽ 2}|Hs+ó {;kߛW 1_kX_h 0oxɰZߎ/6HD`$^% G[aJe1@В%NZm=MSmF#*O8^)ꖣ۩< Y7xx`iePLM0PwJ϶_A"A!J )ghʰBpW(΃^  N)ίfRR)0kU]f#&BǠ [1B).4<D% ˽_h=37%?s_ sy}2`9J60q{; N2v ɉP.jE?(k恆/m)X(OjghB$9xѶ҉X |VUg0vQ S vˉKNT| k=?>IcPCËSkπ=.>g?@e #oGB[]xRuH;5Ga8=PNWk2ŀd\HF$Ed\Hfn8A^`)?E^@cf sK.,Vc]'aPCt>5h%gxy]lo :@}RVB]zH^'C*63Uyvo!j³' )|@#_Py  UQ*@2XW8xH`_!\ ׁK!.ER\ h6hM14E@ShJ@3wk:}-EH_KkyT;u:^xyq]p4|l+3dy\P׮]]մd5Z=c{l3p=IRׯ u1Um"jf ?}= M'52dO\]&5/cNFyU"Ë(A72O_OZ&aI*g;LE"Ԯ7_}X~O]lgi5C0WDnJ Zy(\qK+1Ύp}M1^o6\axW;Wؾ b\a:z XCzH ZvTi+wث'̒{#3+boT?t#Y77*@Hl4s5v2_TN^л\{T׷)[2 0~2@)"dycje0ӎKI#U+n+?W8ע[CcsC!Ը-J1D6lzXI# QRoՀɜ4q #'2k,̒/$bd-(K^7Dx fBi?n]v{s1(5{S 8əiD.9uϳ/v(wD|jwNZ׿&OV" F{SCP ǑY׬rlf!W %`-FqXk)wZTȑ,ƚoZ5 3%(r+]|4,9fM锻VQ/8eyueMZdvFֺrJ%[/xk! :S Mf>S>B z?ÿo} Y B)ͷs9cFn[,WD-y;+:a)Rbm+߅J`mSvteP1 _hXhؔ =ob`ZcAt5KЀB!gyc)lR+OAw*1t-E_:/#_c.6jҿf`%U{0I ]ދ>iD%/ +rh-`m\t^uDAF@: cA|-*DwD,vj%jkqv^3m*lS3Ej6]$hwdj5̜! I$e R%"B6syC\TۥN4{]dhtr5`t!c\$z.W0s,.,7NmR*$zs=?"kE_&f<"|kQՍNU)RTs%c}uxl Qvrd\kN nTryPFI_o z\J7J[Wv]TkUCӪ h ^6Q7 V_)|F@m4JR9_0 ;Z*;BY+rR۩tMW %RfWmC\ݭ+e Z!Q/ru1(h#j,?_۩J:  8YQÀQ]Q0\)_ɡP"P1Q)/cnecw4xi3T7_ѿy@[-ҡ)k6ÿ tZN+s4Nki :A5儬6gڀk3G Vd E\,ͩ6W-kl4`jaZ] *^+* ڜZTiYT+;U}/4)kR[tT.ڜՂB¡Y*Wr9+jRkh%RjYKvA&LY- ڜ;b%&IUv Y.PX/5M+W|X>lq鵚aVshU]tgaV B`sy eyP@-| rqw)q| f:efm4aa*(4@lPʠVV7*5X.k\ u.$O\Eȕn OsP6y?:bO?Hʲ>xsѣ>?O=!ΐ2L:"q}'<}"0~$ÃSֲ;錯xME< b 'tUϗ1ni䊰u9D'K|Ns5BX_GS`H#@Ra8=:t W(r yj{[{DЈQS}0yA[׫u PkSS]{R36?8"C˥n/IA}q9t]WF iB;"Tk7˜2PE28M졏 A#qHAw9S{رCL3Tw锒=%%*1k-0N4iPCQkÕ'K D%9ΧIf)Ϩ@1|4dQ-жpS- @;!ZHAPȋEc@(!;KK& :"5a.B"89qooz0o8Wk8#"h%^|!u>)Pږ)#cƭcC"EXƆkp'M i5O< nM[3F&ƛ"*V"ݛ("wwtK|3-mQ-[:/Гt?N nF}4Zwlc TOT@kz"qrC*%VR OuwW4b2%B(v${onr;b+A꣊h`zb* 7A lИT"l.݈؂3ύ6eV$E(7r_CpVjDUj+5•*5fR3R3\ԜU04Ui.\i.\iΫ0[SqTĠKRkkk[= ]{1 ?5X\ƃ^.XPܰ) 0Kjtf0ԭp`JraM18P\C.ç7ǂԷr6eQުTR>H5g>W0 rP2#&m2hBdA?E=LKZ&ѬrP$z9(H@9_Wyf;7<Z>u][e<_ezί/՗R/\:д-''v?}_C۷f]e `z[!p[Xb^FsWM^|* @%5?i:E$k< \)#vh4B46%ۗ"/z+y+fNODUNJ=ro:r[S !^}їl[hCAyOceP?wq/ `EOt\"\]_7rx1z@^kal~@&د kńoj&+v>3t! MI93ZC%m0X& @8?axmQǕo+;KX$Ì|U =Ə_dޥj94 d|f䴌ef-'S) ^k*?uCp g/Y1V6]&-Z۠fk/+ãw˽燇uquFl+wA{i3 eQ6qS=cRz=w/#XItQylxɿ XbΓ%Qӻ\+ ś:-RZ5~3=3fhd$T@ohIi0p %=2#0e+?tl}n;PKψ#Q@>_{w9u[CS(e<1 Οdž AVxVxtD߄yY xY/6M8Or l":@P?1v!|Dqw^1FHxόB^X)n(*_ <:]`ǩbېwAN?-}Scw.7|L4B8 .C{5fUu ''=/G&[EWjcK(uqߢ6nέ~'dY ݥ2[0:`q FE2CO?zvN1qw; «e\_ߦ`>](d{edx"27a 1UN_n}b~Ș4Nju|aGbh vIYtT.S6r?|!F  2TPB$Qcѫ_d`yΐf,D-ya;G%ܕLp_\9fxzآ?;Xwd-m%ѤKID/&G hgزkf< .<}&c m=(?yf/NB-XXhh(M`E[oB2Y'- `sZ9?Ж8 aO ]X*A;+{?Wz!sUD^)޼5;ϒNKmK=^SSG2rU.Q} $1<ýSX8)1HtdٸjA VהLIE'I%)Uڷa 7]P)A0.!mGL2 g3DUD \n`a>E83Ske6ٞZP8P|\4˺Dg>93fd3p˧?D͕f;N 03 Rp@ 3]z3"-_Wʗd}tIT_|G衶ig?Kbq띈y|Qgpwo^T#k=m218 5mķ+=I\oj+dVw3Z6f׾؜&:(OѼ4\pD_uF:<g!,^~sԸCO v)Bd83qԈr,Wzyޭd'1tqwrTiV_T֫;qPyG EGrو DkVY~9C;(a@E$6HN+/=hnLMȭ+Bj*{v}c+0mf uƫ[ٺW_B;I@E71Xvc9ߗOC.`q0z]LN4-p7^]Uւ]I\FGBRQ" ޔYG4Lb_C70_;w /~M.Muyz0xGd䤩W>V?O7Kzv}7(<S:>ofP;ݩluMeUYn;رѻ\M? ˗;+_V:睱|s4.^qtލN F7Oj_?N_}nDw vo/4˰; ep۠1$+NodSm?*{oəvx͇`\ӗ/ATKGog;i5=WR?^?;G|7~=4w^^?/ ÏvM6-s;}6^_]_m4v܋΅[֛?^L?8{i}wewM.Y}<ڻ}vy<#(Nyik7/N?}YEq-xݮoXǝo+UH;yk^kFϟ~1߽|B?@D@HJeeQۃۃd;E3wԪuIj^vlz*Kxɤzl/FKVvq^hůaEf[@]yWg]=NfQIߙ ]J-N'{W;?ye4Vk0323h~wVjx5&e_'?U׮2Wjb.oJmzћ[R"LZ]3_+_@ywǗWt9t zwR[\fN&K{nluG ;Dj)i*/ n^wrXnғڙ]L7Z֟VYp:b\8)$nvAק|F?Q%{XdG-7ot쓑7ڵbTl}844A6OuA>SsoG9*TԅNu/:F/_̓vA&hWh G_C#n \,R>Ijֆ]uGbk8TrJ^i3ݔkUjmӛ|Zk&y;HvaX$gzI\L@ᖯnݼ{z7ILCpmXWq,^6*'Co\ΝhTqv _oh[={bK^x6MN[+Z+uN_۽Bٙ9#8Jty]r9oYe'_V6<3 >O/+ pvԹXf@:_V*C?5?VnuLEtz[Z\O/lwA{^:gR1[q3Xqin}Te51?T+e}9'GقyK3Qjk>2tVɈdŨpgjKM2(U8[kC4_o}Vٹq5yCo5Q]?M/'RgG{d4Jh7w)]u?oG=SWu(6^T6sOkK6JJX:& .+ n}b1ޫV̧w(={B1޵Ņ*]|z"1ޱF̧WJT&5> Υ0L4^&9W+^߾asm`8ʗ_= euƳgV׭1D}P 7g'E)~ߦ\Zp':3xrED|Uث]j=6}u"D޷;vUmX/$>+^kBz V[UamE~p*Q>$N4㶭G| =<|D>vEKN?Ql 89ę϶M79-Rt i.VT/{ \"U}wm1UP3ř*C ǿndz}K/|1S?q{ ۙ(=Psls(M`A, p,u>BaǏSۧ}cZ}|$>nf n)bEکe4M0oɆ5-12 aw| fقyhQ]ۉCwq\*r+ l6aSU$_=TijS:Ͷp O.ã T-Q-*oTEmmN˯?mxp` 25<.з4WA  UScC+蛩)MAG5u=4~.Bt NmxubT;}|,UX .t4]y3\&h/mr !~ݧ Yԋ5Pma+N}E6q񰽫vxQYxMwѡ>PYq*Q%3? `N?vm3 -HK-O |o߀Ƈ drm( %X<>n kOp!]%:߅ճܴIWV~⎫.-n?r+Va^\2p- 1>PGH`2l!BF}4{IuUc6W?6Si`nU/#+U-+{p*Kl$qn#dǚsŰݫz*;sb1]KMqwUG]]Oj9(/1XuTPQ0 Nd "i\K IrF'h)Q:A>%TM(u8aԒCA,4&(OUݫT?kdb87=NoFc!p#?ϰ2D_NJaQ,uԹ4ٰ&T~F[~,<0 =LgAVw noGb Uh)9\SҹQ8л~Y]'#5q@Ÿ | Wp s~b8EyWN c8%?N>Sw8 g@qp8 8YyeBsEl޸SO{'?L:Wrޡ 7lMz2*3mqG΀"y ˠA~Ѹx7roc8 Ў[L!\)ÁanbI &uʔb8sQ ="4&}覭 ƨ[.\`xT?HVsN]ac"5h7U/&q,*,]Z9URaB("G%D|!$j q~t I400LLJ$eyR[ 3GS-N" <*< pV !@oS"k" = \  x0!,$! |/筨@͵TP]: yMwF;w._SԜ=wx4QtV[!s>ltbUTcI &w 1'"RP. sM+v!K; jiB4ӕOdr(XuɕJ?l LXҙHb-}+D}R* "& *S}7Ѭה#<`zc],r.0ú V9S!\ά$KohCQ2ИڱA Li($khr؜ ѰZ!HC `0qLdF@C7cenh%Ƨ1Ct2 0d Y_gC2H0]qSHca 7[Qcn?m!!Tt# 2*HA=>\Z"$ݠ_("8Vg'z0PlEYq립bYM0>oL5l)~ .pKqKOͬd/B{aդcrqtG,hT '1ԧ)FHM pRkETbഃO)!pkX[ ԎƯK[X0ǒ${?Ήk'1q4l uyu&+luU{L6pKo⪺Lcg$W8^Koa߂eβjkwNTu^f'vbg͵v{5I4qBfq< ]k+ru><_(h=7x)w`ɎE~I8ݯAw-`%nj\1 N(ÿқrgcR }D<2EmʏL0ynŜ|w @"2YS俊ݠk2~S" s?YwËDDӽ~9#)݌gTM-mai);^=j r<,F:NF#.}Kz +"0P5ŏ(E>.wDBuʋCcX3yD܄(.a&?m)g,@Pfݼa%aHN7!::*Jl>-ڲkJ B*ȳ$q?Yh&%CS9C5,tI]ήNk4T Uh爀3Hwp1$JqFC$h[Y(wLisǎw͵s}j%LI6H(rx_p;>b#ha8iomV H&L E\|g3e>gGI ke|bdsיqȁ#.Gyþ6fk}Ǚ@͌,7g%MR&u )c+:_U-hCO)@⾠Àʣ#[hu}>Na\n49;{jǹ / 7-H0,ƻ!@(h B,OnAfiŧNK5 y&@"*#" ,[]ULВ cIp:!J^ + G9I p^#xN>eKtZu^fY3s\& 'o頊ؿ 2q%\._e rI'|Φ^}=#kFN STzrڀPH#"9]w5,VP L7 &8apAjotŇK3:$jٌ}Q?cMD\Щ"d0E$b&ĺlt ߈ o,YhA/ ;i\TMnʤFnl&6`.ǹ#iWu~>9ǒ7+b[_6¥j<}15D HWd˳W>eϽԻFvp#=d tCW6}[ > ]}Ú:.Wܞ:n9w])>~G[HP TQy.9 PEPF։ޘv_%\VJ  [*t #`7~ [KH'R$U𳋊s|Ct;7  8R){OtrfouTߚQ% xv 7D{%Y YFY5D\(xr,DӇʒ㎦Mw m MNЙCʲ?D  nPuj'dG,xX ѠBj oǺ{"gPȌ&H\p_?NX#b_=|ޡNÓ5n%FNr.dHqgUR=MeQp8߻j8yC?ߌ]̜~;!.pXq\x!n-PJzRNˉ͝rg/$y*j2Je\Պ8ਆ??#l9"z\I_NcƞyҰǤK5&NcXUpɍZ)CuS.JrB֩4DYIs޲r5kN|{ll0Dt~UDpH:dxS5L5'U͝ls"ؾug~1׳Ȟ<- {km3C w>Avvh:we0\pX!u3,Y6R҉WXp#??UE*zyLi^8Lf܎-l@"Uwu(t`'&겜U_\Ywv3fI~DM茂9iE5cQfz5xd2]\>]{o.BeȾYXaIҋϺUO6<`j:/qKvEN!d>䱹AeB#(f4 $'1:K8{#N(!UM缉Y1zr OJSPZ/ȃJ.{6^ST%5ej,K4-rQ6{L|4,#H*Һ"+voIڧiMAMࠅDҘ$*FFхmo)!n{TզQuc1U;5)Ɛ "7Q5k~!< %W뚖Ht}\#P8a aB Do9Oq (X+?/~sbW}67. K?/u'5ҧO-h4;]"^l<*)Ȇ:e~k,/tOmبRq { -̈́>(Jd'N5E{RehHz/SSĒ6-ŻNiF5HԜ|' =HQ$UjYYJA_pg )m>Fd[׃zjp^9;+ ŊsҤ k5^KNUK{ld5Wj)xC^:G?㹭ӨTRQT*V*G3ؑ^-Bl9bTG?tH_r[ltNF>|61_`X y> R:A1݉g'D'z"G]4v!.TęQW ]:^f Kwuۮ`&x qH88HWJi*a8<%l.9$(΢Qg#gImE'joF JYsPI3uRSrD|,;'kͮ`_D?)d(ԐBi@%@ 2ݝm%9V"9ϙVT.AE"/yC ju&Ou؞>H2x/lM|PY.$0w-4B"0|F:r:]xb?t>n`:W#YsROz] O@IA AQu̽΁_"eK | 1>f2ʸ|M>s3)A*iOƿ N:W"W7*Ϛ;2"¨_`y!X$ G`}%`\²ek|Pq'SXu~Y_N:2svޓq O)8eoz_QrIo ع p|Ȣ3RSA ǘIT/vC{&5e P1O}/M5icC`?A=VEN7uH)@]bI̐GpLG6 L02}q.(5D1X8CrMn A/LjP|^y[20jqF&TFZlkTQæIje(FJyT۱"lJ J"{%GIeDivBf7XᚿZhA'eWgBFo @}Z &B1BD 'W5&ZI{d}#Y)㓓Lk&!V 29nS,l9N8I`i4/9S]°1{miMuH>@*4uTٳDN˂/b3v1.@E;v5P$1  j^F9%Azk}WiAfd82i'qx6}6ݔǙV5gNS$ihqێJapkl&-Zf7_^*ˑzղ\ڶ]6cx؋pa+Qa({.e^e[Xۄ eU Dֹ_E x8f!,dm`NfXĻ )lmntwVdl>_ݕ5nN9h8ޱItOu[Cy,?8"F@xݳPLYε׀pX(B-eH-QP?h$0(Ybo#Z obZG++DY?# U!y: fܲ@rh0o' f4A|rŠJ.,ڷ,w~Iɵ9i ij̯5 iύ?FfR&s&l)miV Ĭ+ޛ|uw%ޭ]de!3WOެDExI B;b5]oP6_j7̈́`g" ˋN^Qwdqho O/xގ{.y؟GJf]yxhUBwr6V X\O~kXHiT0!k8zc 5;aŝwPb{CЀ ˛`}?n;D%;qqi2 nyl fs'')nt0, ZHYN2QhD3CL[˰MצəoWOu1RÚ]WJ6glH@Eg O@]s}Tɚ <&2[l91̪-T<֕;Me>% 5bZfPƳj\P)J~X^ @8̋ `ޣX=(0=@d427y7:-̗֗8Qb lʕNnq=}Kَpw]-/PPoJA:wdvG2-0LN O=Ej.Y3G DqbG\p1Tb  dL `2$fCG̢ZR̫#v4b]}*VG21p^_:,jPTU“E'uMf ~:i9"ApI@d[H=ӓ(F @G[a1.W*%l/!94flM$D}:JNn$I92(B7ňg;nwk)|='B&RӨSDeesJ΋d;|z9ZQc: Ҁ+oVP"?ss%Ɲ:U-X|oɒg@,G}}(n:=qkU \zkK)6i={UpQM?ƳOQ4 juBQĊp5o^!vV<yg0mkMmc[Ǐej#~m9.ƶhlxL 3ID9I^RjWŋDy rڙuVqI5Z#(pܿRx1g7)sZ=$\4°,3 :N:i0Cwx6w-yD##Rͮ|Zx56 E[,T{U׋ՋV)QEbi*4 &ƀX% f,W V@bVu[klBN)EPR-|#= li& A<C@~tDC;SV%bqa SPC` YHPC11H4ߩaaQ =5q b:P_AQvuR׼rh9 a og%{D/M|<Ԥv}n gܝS7R~ACTR!,AŬjCA Z] Yo3h 3{bu)뾒$ӂ/C| O&rZ˚a`~-vRanEy@0f<ȋMV!8'CD'}e)$GZjP=oKIm7˷ uFwx_toKe/y5R/~(  ( x1LFfD,[7_WS-g7#܂jJ.$m}݂&BE^ D꽫kŶO)՜;؞1}ǸܹGqmos;鑍2v@~g&f mvō$C+x/) HԌ(0UY n0AD3$dF헠h1w {!cTk%y:J 3Yyr斞?|{ ZOؤT zz7_)lv&{Z'l *=a&S5(6 Cݬ\LXГ<&Y&& Wle_Vʊ*qY5LlR)$P2T3M+ዃD&7T*#xb&]ه?>>F)YԧWCA-DfDEd[Ѥ CWx=U DKtM2h+-0͑(]fUG@5ܢ+Ú{^q9VBbҤ?':ֶ3&fS]Z 2IEaNsD|e宨W1+А bX{Wuq8ܟ?yϓ}g6?=:ki}~Ny,/Oc)Ĕ,(6ݛu3hhw{RBUlM:n-2Ej?&A m}7p~&$hҩBLeLIqžEب߇kXW7)@e ;Uk73\35Q!F9ŚiѴ R ZF^*<ɟ֚on6FŖ7^jv*jVnw͝oGgK$5:"t:U$؋Dף{xՃM6̣K#p^."CmC4Aȳɲtu]p=+"U`mܒZȲlմ$´QL,%I5nYjR,ϦyI:"{!M9DNITUQ̣ Sќe _W"׸tI93h>9C"rbV0;HqsvrE~oY-a6e#C$My|H8aMOr7,"Zrce0v=4@y|QtƠqύ)DA,vZ|z<|( -!< GY’ .PWs2Ѥ.-sh"v][=mIv5{mx]Bқx0`O"g;><V|#ChFx^.]F₞bc6 C[QƒTND-hh'ME ; G^iBD9趪lEPZZ3e)Ri`\Q}(l/*'KerˆTy ~m!DoXtI:}31PQDJLNCjwAh .=Z~ "5|A8‚"͛  eV;L O~;VW@WS@Hcݎ2?.rr$ׯ>/ߋfWRd'/ lom]Ysf_b_fL$0(֧JDǓVCo49%+^Th&n=cxLf2֢+)la8l Y 5wURɀ&6J @32hD<Әnh+\⌥FHBTZjSbQHQjNdQ\N`cZ!|&5⯤#GF6]]«3X]< Z"e4ꜜ̙w2:'&v1dKӁ1dz<ݚ IZ||tQ.{Q~z!<}-]y#JO_<BszOHb5VsQ$Vc1S Z]uh[EkY;FSw͋, mO["2$^(+\nq&Uw-E[Y ! \^(騘F]lf(Yɰ, -(ËyK\6sB1lU_+ԩ'& LAyB䤐zAOOyoBL&uc>@H.|sn(=Kv!66Mɺq #bׂJ&L{PD~2-sI))G54"*ʜI)Y.,$\Th6Zά 0~*2i X3GXx5fR L]l?C%QΡUPV,Bӌ}c6ƙwu մ:UomQS_lN83<MPe1Rfp)z^& W.pu!MJy1L26"E|F.@/DDqeBzYd 4!ڜy,75XE lP0{JWQoO༸ ݬLd>>%0 mq6K*>!t×eoƵY7!,hjz[Jt1Ģ6ߖ&7L>/3yCک0)wh<߫S9z9dw>hr Y1'kFDܕHZf״\L͔ϱD$V-%i{0D/P1kEӕ lP_ad4G8hT%G W1L ZI[!+Aǐ ur)nj$ɍV4+PM8Ta9%?}@BoKG~T2kj:Fpd8>a%0/Im-Nzoxk#ҷ({܊ZCAKQr^T=F-j=>Z,s =n6DsKG1/1+{|HJݖ׍uwXwmc}nDh!Ahz GVlm0l9-eD4}} n-UC$v*k*lH}mj r_49m; J͹IOum-{{MSlu uzoHɥd\hd͢0l/A6ӛQJA;WݷR`Y.tdg02_Vd0hM4,2-a3z q_^2R.DH7\LrNϧߣKwʸ |Gm2)g@h0R5(o(VHw<^(?=mٷ`!pT7[gI(_9d.f|I^DcXTMd)CE92aj2KB><%9>Є+wT 0#52*nc-!õ$6N|2VqF5 9Wak}'*IE0旗CY{1gQ\,pj? ,J"ݓ{ "eWY k^Y#NA*_GoUn^Kꌭy<WΣh>T:95G.|e/b+:oX^.`93oNs >P}1(Xokb`*?BLpF#C~[T3 B&,YokM5,Y3or$`?V Y,v fQ2hnxa2-9u^‰jbd\ +" & " dfapFE%Yج;^F,^'qƓWÑLJpݝ:Xro>?:~] AUj޽8gs:1ZPX/uA(Q*xs=)?a"o 2r  lJ416wNNׄuXBr+?O)e\%wyeaV:a8_F8wxNYR .ȳ/ۇ{njT ֖MHb{fIp li➱Tl+F+af5J}Z `JQvB4шh48[ V$P~VcwlGwE>V0qZRM1ڮ#8 9U@.NE9gTs.h*.(Ԕ흼~ VBJna1\?.d89ѝnq͑O@VǛ CrCZ7yc(>6Q/ߒؽ[gzl%_u`5֩\=Q;?;i-/g{H:>߱]c<?~GkjO/VwiKò`T O}L}_)5ݸ<>O m!tlu o]е qղ|H2:Ù%FQ8At23t˦ ^IqL- t&,Y+'PXQdXd"dcPqZcG|E?wۗ쭎٬M JY5J$!i#8k;CQZ+GQK7&qI9X'.u1ǬQBFɌR(pPrdPLϫٔ,c֚V \t^ÐOw #c Nf"KPs&#HIna(i{lN@v "_$8X"ycEL -'zuo3Uwv㹜_uDBk4"\ *$ (姞U3ܚY;ǡKjpgT'0)LMvG~RdNL3,*;XHh7Xy[4G9><8:Pl,Ji|),?=8^[xOɟ>{}Owp?=ڑ'%aßx_/E&h}GOi,skL7Mhom/[OO{˵&/~y::ՙy~Eqi DwᓎHE><,Kwr?=y}?<8_ dߣ_,;RA;k,wsAAqj8cgMt+V9`9w]xp'yÃY~p:r݀҅ u[&p#DƢ"R) u}3jGfb!wsXBJ " "8}5k f󫢅OEPPUKBKarx2E%3K9Mrwo?NHHju=Tp+X0E}f~o2moXHZSFtqIŦ,x +vfrD-"BICGP[T= l *$]%9|Avfx `(+.:E&QFdU]kRD,X-tI&_T /|+aQ 1SiY1ƈ/hxͳbGH|g.#U 9٠cFwl#:zKh!z'w7tsU Ň5NC\xE2tRmVj:-kl:UEhr:Hj\`HB+H ZJRq .J6BgX9?cʦ G[+UcaYDI )hP7ƎѝS^hZÊ(V&>ao PN`$k.Ȥ[`u8FdH}Eڄ ɩPg4,٫ F9$^ͅBC!J}a,*^;NMƅOS~5oEloBO.t9N~WQZj$5bJ?RIV\Ք!E#cE{Vc%vAC)c(ȋb Aw4:..?y'ג$`iIܜ-P9 xW}HzfIDGR=KY5 JNj=:79jlm GDS8SK$]>('45~hT\rJkw,]{ f弄 Tw9ε1"R LGEHE (&dȈظ~ɴ=x`06r^ W #2-7$A`NOʥۇ3AdHtş]H"&FŤX/,Aoqr"")=M,T7JR8,qrkK K#Ѯ$Lݝ૮O2%e[Bo!k-,*},O[6̝3 b[0,q(t\ΝL}0Ε\PPgPy|M4"S_P#]8vS@13,^ua"ꪙt4Si"flvѵ(]{ab|Ԭ+Q*^>w7AݠbI>iZƣCo_*,a\ ҽiEˤ,^N-LXlfAIh6e2 m.7ƪ{@T7)9WiXL6&R-iC7sB5X>5 &##dLgSZs|tDDنՠ7pWi , DlO_ۅpZ^\C'}*Zk\q)À#)ވL Tؚ2CavLxH$Җ'T-W,\F(9q ܼ\ e!r̟hvD+RIwa6O$:aDWsHiA8:#>Oâ ^W%"iy"g#JgM<7K x(AqK7>-#D$ː47 a5M@ɝ`d7 K@W!A;t6cWj~+'uUdl[v,ΖBc 3D:BNy6aU*ݕ:?ٲy>6-Umu^w~I,cC.5y`|wʢW  4}fjU7z&U1>! C6lƘGX)fRY5 OKLn`q BAlo )i+0OGYo!d9$[Z\ 6#5.bdі;b^#gU]u|Eº5S6@pdS=kvK8VoﴧKoYLZC#7?Rv2R_!F,NPTi`.B,N AK[%5&t)>]'?䉁oU. 3~ #[e.EA1}"\-Kg[A-_ow7aɀШU0THf 2 DԎiu$5Ҋ|ȣvc*%ΝKq^12Yԉ/8#1h3 J,tC]V5:OU 0 AaSZ/N,.nO2&AhgܔŴ!`Lsn*p|~`<6:FNh S ?RATgi@WU~ j{i &ӴTp N#|鿯?a# _:x{pN.{$V~1|KIß;n1Fr &d# ^7*2#`3IJڼo$:z0]RlBȥAeqJq q :qJfX۹Hm'c%j:Sbl7Ё NdW#TAAĐA!QV N[]M6?ˑF ^[9>:=hßLsäß$TЮ"Oh,|E_ ,pHjN>l勽'O6 `=CI)CO`>yC31O!r,q7wb|@ZLJ\o` W Q[Qg@,# 8LQ fcS@ߓ5+𫸴3tRYLco2~[kLp ng=fH>_Xk@<$Jc9T(( qZX'h䞏_{n'42Bb%/ <# X6|:f/~>Q^\6vHyL*=*Jj_HTd$~C2)g!mV\FYcn:// T>{i@^My BoXaQ-b(4OwXǸ#_2_~XWA_J u0(xŽ*J%%-Peb߽ UKdm x7w8sIvm'ͮڨ]QxqN`3~2ghɰ$l!oE8䴗#HXe`\&x;w4LǠWB^T"Fji];E$:qy=@#L>Ҙy:5H;4uTĽU># c-j'`]@"x),yKos5'ۿRiv-9ײ(D(G%&YSU 4Ծq?N8c^-ão LUլgm.Bs$`j -P5:tl)_{aQۨؒ; I Aܦ"M)( i\1cGC~fEɬ46$2$(iڈ(qhjQ|ΠcAxxm%9A5rQQV[]${r%Xd.NWn}GL(ZU bp N _L8hUgiN I)l,CW,'UVYY´=/W凓k*C>#¬ӳ45>T(x]r,ojRXXj[WcM#Q2ˆ T@TPJC YT, 1R(jYG-o[(H͔2,\Z \֦aMƁ"'h˴~T-_LݚSUEdQNV$*hEvtJ2bgH: PIyDh'Qpڳ5mU݃G ̸YLQUF$TX IhO3 d)@:|~CatW Ly LO/ Iq\Do5q #C\1Y, jECmc оbtN&.(sr]f ͋][Ydz@A3̥7>N@jD!A6b>Τ2CQ`eAtΠkY~_F,UF4k#>b>BY(G)FDGy1ɷsP"BdQix#2dT1 kTlmHz(&.I$I$Ts*RFXi VquUg3X 3e "Yq W Pi: 'ܵɸе@|wU2lBEx$i<1h65+NUaM{,UCZ[₫ MT 2fX㥹*|i&e7@kQAw2dmƍ-1?G'nb4n#Y)gߖ@޺ ӔHܗgnظh<~._e? -:)صJJx=Cպ $zu ٪DPp7,'ST[y&ϑ ߹[{։W^k['༆DcwK~7YrAe\#yv% h$ЭB2 V >vw,A5g& j0h)Cp[qb<-9ջEg`vM*e+Bic0Lzw,듏&_#y|Ҡ+jb~?04&9m<mr)e4qe7V}] R_;©AF)# xِ r3pL[+2V>2MX K@V˛7 +T>!Bv >QOG"4^c! q|,(LUı`V(((Z4:nr g-AA5e 3/%U&hϡ2\2CY; 1잉(Guc6aϷ_ VwHG=ywF>r*J̸h/aeJYzѐe 9p'_ο /CfW+ ɲxͩLS~͛3֑$ Ksh3@fCꮮ7QF/]RD &5H׌K^M]@`Q@](JLo0pCLNcK:yNoMWHExa|4IXV j;ZFW֎ X6!;9=4а„J)0x>ր_ѳ /]ea:^1F=ސW(P>^NN~z_ώ{vħa  ɿץ5cY&P5wokբD’UZYVZZZx5jWg% D%`k;b2/BZEJijahOQgIaH_l]0&Zq11X 1ҔR$P вL$@H=}oSq&?wd|du(uUa1 8}>H?.ͨd 'h~JzC jwh&)Hkىod &;6Mbo,'҆xliCB0_N?W:Y9] {ChԤ ;#͏ZB 1'HR}dŨL55M]KYdoA֡2bKhbT?Ŧw-JӲzuA*3[g[ɳO 讠ڡ:&p M ҪOfbBDSy[z)E~2G::.?1IzQֹ2CIU%NU˘A q4&=-M\9XpC<˵u˓]!>ٕsr^,v-ă04Ħ|+}eԔ:P]4;I {V,}ɨֲh1Sqr 8zERǾ$-+LKK4yt{(Cy ۮbɋA`eeg !Z edu9$[zxXm W:`x'3-h!2x!GCkR4@ٔK&r1dI(genv4>X++l j4:*Ґ$^v/szxE[gb _[5o~kIhnb2D}IGyMX/H ZaA# qNM/K9w# sxJ 6*̫s?!Do/s<15"*+C"kKA''f7Ԅ덼kp,.tJ!HWJHF/\4rG"M'a+[=$tZ&Yizޢ'*̹ P2 HL0*,)m@0̩N/;ԗ3ϥ* ECь%8ƇkChNЄџ]G%L=QF TjMW_ٽ5J_„ӈ$3߹NhB3sW Z=Ֆ#{-TÑoLi:EyJ@2/NN'7e'N9}_tW铯JwN|3s=Y9-:W8U=wtfi /Le<,X0);+IKh}ssWcmd[1 )ޞ}07(=tj6ˆ%Dl>}6^4|B e#'tKv\q$0W7qMM*ՄR p,qZ4?z9i|,h;ǃD(qd4wzڑFS4V=~(|͋˃tGh4ܐ=>tӓXs -ǏmO->K!Q8*'~nImtOlȦSɾӾuՍYFΚitxѠ |\9I|:c=̓+ iړE6ڇ\pXPK);Ag^%~QOv߲aln0j<"RM]6|d% 5B9H8Án WCD|t6mYϧ;7u?An*+4'-%lZ-˂k۲Ӌ}!M(먏o~|u?Uj'VuU7@t DFg%a~kYw${>Ďӯ> ]s +R Uۼq%0<&tSI-f;2`rg %ե]iO7]]Qկc E-"ɓTxy׵uO촾f{auu:%}SyQ (J<(^fgFпml}[oJq{]=Hh3j2fo!sm2S{8gʹNʻib~'r #G'~ӣ|?~.Ϙ$ MqD6!\%]{[N)Psx$2.o検 dJmq`h7Dje";,߼3'跑,`.Xu])=?(w8!ytܦbaQhㄊͲ p MjA?*ƗݢK R ۓaħq5`ӿ8aIP:P9="?vݩGY=wM 0QSRڢ҆<v[T- Ck[_+I@2"ٸlg(@OjӘIJe/^\]$du{丽GCċِj  x`&:^Jcv-mi#s—@S1DQNFwzrQNxx[k~ױUOpU6)?rx40绝|<\c>[4g$4+MC$zXbJ \?Qp4TiXY X6ocsyGԳ~E;sMR `Y"qGǃoGc y~GȢS.J$e<Ɗ`(ϟ?*{c3 E@Qicߗ+&j?J7*VNZ; r#l0a7ye㛶/oi'F} /{ݑOfS.C|sƣOw:F;lH\f#]>Jd˳W SDU,\FKej=#8Ra6tPH0ūw?!볬l?>n9Xֳof[tſo}}ǻ;-㝭Ǜ6v#?HJ{1H}ЁmTى@@C6bOYݝn9<<}KLJ=w|qJPV;O_tVjE~KWb\BkӬRWV\\WKDEJ,cxr @+{h{cSr@ln>}$j83E7KeD[z;領KYtBJI$ ~d0 )2~0 ,a*b&ɕ3++4|JFF PK7尸\R#б7<tyӢ+vpF앞nC6IǢ Gg'o䣢 vPl(v9Wcʃ>ngQ[Yll͎"(vxtnOv9ZZR硟MK]\Kp&'ۡVG v @mQ`g}P)X~VҎ[?|ACvܾl/AN骂Y34]GToh6Odf¶,Cz Qm>JqĶl͎sFV޽98C~v!' ";絛),T9m>IqMlg4mߝ}n;[r 81V7\$2R[n?{Rme&綴i.}?-kǝ}K$J=^(8N-@ ExiŽQKm˵-M٢ܜT!-m=I&?+'|r@[Ovh%4"DL>׏X0##vhT{_Y@*__-nutEF`FR h\xA;;I4hѳ;4k?wv G2]>2UBwpB l? U'`?7?s9 wʯ$?1RG@#F>glё֥X.zk1?LNyb?ZkLt&f~1S/=Ԏ}dL5=?iiZkLlg>iveYb+/'/' y"f 5V9I-"o@*(!t'I4?Q:ZAdp`I%N}a/BOBìV|hn4N.瞊 $MߢpqaX6Ak:TNcY}~Ӊ.NeT‹ LUJ78VAA"d8̑Uq$)V'^:_ѭw^&߶Xie.fB>KO~?33~*%g}Om(֣a?2kk GأH/h_\h~w|G眓f6~W}}xI 8w-/37xǠ=ş}fz@|^wUkv5mjKSs@6& TW@$}+G)p72%kO`lTK+`$^f#xM砸vϰt&.gX!In Z'IDV  Bs &M 𵔚F&Y<^Yq fɌKHD.Xw41=MBlk$qB"E+K|\3AU h#Kfxz^ͦ9k$ȵL$v.W\yӹT hpyﲓh%_Z^GQ'>T7\ f[#4xdJȴC)vpr[%*NBU/8",3*Hs %DВjqUoo+~Ka?K_ !بE2$lAZ;XY4o6`|+d٫R8/P'#$ Qu' wkp:PW8їXAf&0kZOxL_V/6ʹ֖IìØ%JW;G `Zx@Ul].K%xQE:*6˖Oq55B"hDIu7{KYZC3J v[)>E<9@wbG`u29o.cIkKez8n6q:crΏ6⺪c&r7^ qU]RWNIQĎ['&Y R#X =yw+[I r0U\0<GQ\.Ď6]'vڏOR(_< ]_dX(ZחLziokp!NZ_ ?I`^J>}:_?&Ɉ])d4^Đn(/|NcvYM|u+8F,2 9FbF-"*NfLwR4g1DJ=TXwILE:縿"WzTp+0uIs#P_YُWnArј3?g; Rckd0eq!>`Ay)߉CWBPqL cnNɐLylRH²r8+o,xt+ّnܡާ`~nxerT/gWLҭvHFnhçp ZVNtbdspn={}w=ӓQ &|/eats" d\ܲdHV!uMg\@re%'ybv_?Y}m LEj߳bt 񣚒4&(w(d5GN呾>_eڅCV+drd(O0'xLƍEԟ6|;I4N4O'R6mm'm=vv?X)*BX%uc\8㼢۞LݐI)m{#}E |֑6>,GQX|A3&уq}|G )]Tj.zS߹ZF K$ո.Q[fEsC0AEN ę`pܴ9:2 bEe# Ad>[؋, d / /Sbv0N}RzDx^w3xURvzx1ܭZe!cd12 ҷa͡7 R* E9]S@ BipNYq\@$$\8=D(?v5ɟ]AMkkΟ6 Ք3 Qn0Ű^$ K%6oomك:!Y츟,4M UrVzdyBDfgWȵ *F*usD{88A!rot~dx;y&^c߻N~N9gbTS |Sq`9/8tpRRԑ 4 07Cﶙ[IE+} E\|g3e>gGI ke|bd:a"90}d`(o7u-Xڻ8qec,$ԲIٻ.2e tEBE^`1t5cHxPytb nz"eZH?[;;g^Gqn>p :[`XwC @ "%QvsAY܂+-.OG-kLjׅDTFRE@SX8<_%~UK0'tBp nVsj`?DN1n%6sRI/[r; ⽮7+k ߝ21-M8yLquf*dJ\Zun'和O"M&>!|{F#)֌x2bO@BX0 )xD$!rw6TeỘiF=Y=Y'Y.0][mTmci`@zD-/:9P,{ :UCu]܄X7WsscɲG =iءDN#B/x)Fnl&6`.ǹ#iWu~>9ǒ7%e#\jH/-+~}ԫ{w/\,Gz0w;"w+Ol!jW`DaMyB]QnON;~-DY*(<g(ZY~1 !K4yyD5U*.:GyTݗ6D.Ov3e1cuC l͡s+ !%mZb(  _ 2$t^U\ʒ5Z8W^q$- hQߑK$bB*b^H1"[V!D)T$/QYv@BL^BvPy1)&)DBHf38͈Oqr,,5~Ca# $u(ېC r:"dwKx{$(~d@Du<;YmL2k[so|o-\+;bOƕ2H$P1 7).?8'=A^OWs| 0# 0*{D'ǎk&['[Oi^Q.݀graVw4m2<%/WhsThjw p׎U ʤ`V!:Vpƀ<\p?])|j'dG,xX ѠBj oǺ{"gPȌ&H\p_?NX#b_=|ޡNÓ5n%FNr.dHqgUR=MeQp8߻j8yC?ߌ]̜~;!.pXq\x!n-PJzRNˉ͝rg/$y*j2Je\Պ8ਆ??#l9"z\I_NcƞyҰǤK5&NcXUpɍZ)CuS.JrB֩4DYIs޲r5kN|{ll0Dt~UDpH:dxS5L5'U͝ls"ؾug~1׳Ȟ<- {km3C w>Avvh:we0\pX!u3,Y6R҉WXp#??UE*zyLi^8Lf܎-l@"Uwu(t`'&겜U_\Ywv3fI~DM茂9iE5cQfzu)>@${骵*{vr5/(CԘ̢ H^$}֭z:Sy;]:T(tx '//&0 *{ϴ4E4 W(4$9<(hY-]qG j:M̊{ĕKxW}8|xATu4tHb,) ܤUcYmِ˿e=` @RY]{K>Mkl j'/- '|$P7l6v.l{KqSC 6s:߁>oLt5L%v] QImW.E.Z״Djr^ kzf؇$}C%u~s`ofFX9x񳝃8ꃰ]vl_I}y;ɐ>}R~o`E)؁bAP৔MaF6Թx/Xߵt`}| hsFה -dh myl&AfP"?ypY]."u/cm4DcGBDC$h)urN3:qF;Io^gA*bg&VR s>kHeNiK5Y7r&[ߺS;jot[Y /V&M^߯Z"p^d ˨*TKϿ.À*u9mF ϤϨeʦRBV9H=לyDƎLje"'?'?:vCbs0r6೉N? N<ˀ> :I/{ekb̒<8w!cn)I" @.1vƘ5%kZSq`ӡTBCTV~C_xʿ^Jo?e ~g|pu)[⧔-g`X1QE3n:I)RI{2Lpɾ1LTy֔ݑTfq$@MFˣ &!e-C$RH$.Z\Q4 a$kp2 n=4$Nak͍VwB'ke) uousFa_oNώM2_}{Zwgaͯ1ƋeofͲtFj/Cl*TF$Y,D{2h}8ZY$ R_=42C8E5A;Y0a5 ڌ5p,]Wra־de NJI e~5еWL{(|n1 57J4s4xdKlsNӵR f]䫻k,n %+CQNzzxf \L(U{M)U5ީg4zD fUOo&{f>cQ_^|pS%CS}Xl$<|zsvsc}<(U22sFz;ceC.:/X5\ʘJL0b{7tȉaVhQ-Iwܡ%m*/,x^^V2Fr7-PJ)U&"^a^|FHXEE"/y fFIϻQiaDQʭa X'ܐUXu_usA[ .v<Ƞ䰇8hy"'zW"ҹT  78(laZtZHx v- T wҝ1=!;傋a-0l5װL!W6'eO!Y6?pl[nOhk=o=~,Wۤm˱p0Ecc]8$IB$IR(^%SPg${N]Ao?˸QMQ?'ᲥAu(6g_/\i.ppU=p,HπAj]6suƶwh1#mveoӚsܬd.bϦS^/^4L-.KS.71*I6c(Zb;xXcrjM-LjqD\PE`L 4Y yˤ#"ډ֟*m[t{NrS'VȢ-D:ڈDNM-#% nhA,䰤K#ԁ cK=@˱h@_ sd;(LO<܋-$R|h&m-~pCwL8@Ęz@p)g-?:  = Yf *feTm ^ZbdͨLPzAh #=oL^$|qS8}j7q7oNNZ SGkqk:]s+rׄ6A^l"ru\9A`]%?>/N =Ry[rLj޸Y5[}[Z-4})SĬ*|+EA\^pP4$FfP|8ǣόa2 0k$bٺj9pTSr!i4/*R &R]],}EL9;=k{$LHlt氕*;<30l{n,n $iJm$5X}IA*4f\xE:u'``p ""!!3hu@[+$\+QjdƜIʓAdC*r %K5Zxߗ pܙ 4 7zI|L8:5ŐMy4u n'XIJMQ5Hx@GqwbDHkF0?1\(ŸMpjxs3DK⮋%f= n<%Ի|1LV[mҬ˯1#bn* @1kUvYNHrJ1jNF \fj!$30HKQ輂Brc-yHh]L'CcmLRYKA#6X5GdRƯgjf'ZQ.~͈faPw8v,,TU"_&N2]aͧbMV/ 7Qd)/SHA C.e29k#3;X ʠCq<s]]^)uԙpW(X&-t<\:OIwݚB̬xTؓC{}Y?vO H BXff.O!m, Dzpz{ypJ$U}J- o紈m3ȺQ`FE:cĚ<4!wapEuaP 0yB)FiWzDf f21ͪ51,g+JUVi9N7L1΢>ڨ"h|0 2#j ("ۊ&M,Wh'¿E`=T^hZE[oI-=mt'a.hdF,7:85L~]ք˱&9ѱ113jUHr. sC&Ӽw..(wEYdVT߻o uw nyϓ?xNaYOKwut3d}Y{JuL&dqFTtDlACߓbxbo)U54vk.*S1 jh )4!ANeJ-eeH,$=Lݴv/2Fe(>\XĂDIgoZ([qZ1HA 1*4(LE_R(w†7RioN|s1(Խ_VS vWӼ:wg--loK>:[%ө$^$s͵haEXYDWw)lJensH BMMc_1eD|kCԭDe$Y :0e xfi-aMqRb|6xM )9m0!rJ%bU"\$(KbuNA#qAeõ[;/}jq }. |"m#fC(kz;a[G- )(0: 6nL%e?bT烴DmHm 1VQp=*Lp2Ӕ&uiwnG3z:'qhCH-g>VϨn WOSPDhv{%怹3|׈>G,! B[uO6pIO6aOHܲ~}D0ܥrPF&jAs@;'@?h,J(5ܑ8N"! oDU}f=,*|Ԛ)CM2pHC㒌W Eas~Q9__/K[64U̓5N$l &zâK雉y"*~P&.fju V?H< *GSp{m` :o?f !-hlg\.Ffm۱DdUv!vP#~y OO^\056ה";yYxL`eKkb4[qGŎ132+gП,. At4>EV"z8,z,,XڤF3AvYӔTd2EX]&Na acڠn- N0!!WjTǤ=ʜ)@x ⁜ltcDF;4fHO-7C(rދ/q,LkAW.}=}{E"#͈ |쪨ME8`܂>/X "}عX6↘}0Pܸk^dah{zP!BLeT]$4v3("ȼk/Ze*BIGt-$4zb7k~(nGJ0MfOhI D^LC_*^没SreEHZN=1h` 2vz%' `{b2Ѩ< ȌBbusCY. iL֍c8tW4)fZܣ$&Li9KgMI1>4iVQ,EMJraA%᪏BrfUЇ S>}Hki8«1gd+|*rpʹ`f )0΄;S|۸_8=hbs™i@$mW-+ᖢ5cK3f(tɇ i/hP&̋a8)ʗ4rz$>'#(Z kd%[='w 1cY/J`‡AۏT"žb͈"x{]|T?fe\'-G)4IMlC$YP1p ,{XE7ȺyMm՜ dGTR!4a2 )| fN=_'qOC.^ߕ\Ϝk^ϑ$̼@`TȊIe?I^4^&ܴg=G2"e\PD o||$=$jy(Iˆ&z"aO]+ZhgbD/ & o܀9A4-9ڌajP\Jz )d/] :\$3KqS DT#InY"oq<S)rx[:4ϰ9$_S1_/#,q7;+9XgH҆&nhu<5~{'̗][F߿h_Vr ~_bCq7j9 UIr~fy=no,KaWuc} ["?xA_ErVﶄnǺkӭ5u#o8-F  F\Hm=xƷQn eAΞ*@MLE+0@ tK]B |uC5QA5,#k+<Fp3)}K,r+Ք+G -H`lZP+Idk1` o) \ԕ[0OPP=TxtodZ"9wU^@U`CkSOДَfiYP poMznk kJv6`;USCJ.ǖ$F%kg{A ތVzع辕 >=M7pxu$(>Q7" _Alꯦ`i 3hhWu!Besr-, x>] S;lII/8Bc%8AyCbFSGFl˾ %Ռi8CL*@!p1kM'Z"o&&Ka&"',2,7̑ sPQ^1/ȡ&E] jApD|쎮Q1u{m 5'q0qRĸCWڈ3*iͩ8? [;QQL*13E8b8PY`QX[(Kj`X\Yv T>z;?tFF0R\UglYl$p}F2ɩ>p+sYg_ysv٨ysSXQ)@Bx[۶SYVWdt6BۢI 5aa}z[kaɚu-~%7# e̚ 44,Gd_0At[` oɁ NT#jȘM_Y0!f9M]0'ӕ0 p0**ɊPf 2Bfq:4dR;ԉb#M |LqlR3TLʼnQ}Š@-;wzvp&[q&J)# ,9춿+ z7Sݯvʒ\p@}>sVۥVЮlB3KLgKg6b[12\#0ӬQRP* JзAFDTْX@$"X68c;C-ɴ֒jvIЀ' ^Rv1p.9栚s1GeTpEl \BRt"q!So^wh| 8wL@ HҬɃC|(:SԻg+dDWNZgĿ/I?my>F¦Ie(D?Xh;ZS{*|oͷ߿N[kǦRx2dj9 j{6EnnQТD~i: "GlG3KeWtuQkO%;?ԗ,ʩ4I bx^7B"I$d,#RS o#e.Ra6 ,+(s1޴,Ñ~$j@*R<>Ɍv;7 Xe،X(Pf6uRY Om_澢gLznZ8@vSlRګ3/ߝsK߾(>Sgz_+ݾdoufmR5PȪQ"! IL@EYۙ\]9Z1H:q!9f0Mf2@#bz^ͦdִ|k7lPKp2Y͜39uF2uHw 3ENcp0nk//Ts ] "Kn?]iXd=Ǔ"d8œܑFCVR(vWRAw7?pkZYrb™42Wwשa|41POgb/!^a7|-zMeJ/Zb]jHUmTEtK`r9!jnϒOU ICM_7@n`t![vFUŲG.B;y122*eHy-Rdv g9&P`w7Yr&uMDo3]RL5 jL ) 4[߹kLY`K#G3 I =ŵ9S-}>(zb5S&0 ?5䜓o GI|*˝tU'UE^eZL[ >c4k] ^sy&TAj a˥A+mlwI#\r],5'JSS:ΩcJ~NFYXT!HDم -?t9]P〻?n-֩w(҈KS @ tD*1g1>o]׽?-y?-i~RV8&dّ A_cS}\|kz~XF2;<8o^G3]S.9Moۊ0X&2Ji; $0P>2 Ie$ÚUji9k^'U0_-tx.p%OZZ3퐃ē)-Yi"3K\ap"DBRK7] x[q*,j3{hk[ǧGҚ*5K2$,-6uWd 0kX3$jN8"8=Uhd[W!Խ l$(ɩ 3KCYq )2BW5R&"Z"gjD H52Rx[ `L̘JKΊ14F|9EkU;BK>ktjk.7d{щ[B;{_J(,>q(jW9ހh9_c+ x<өd/5樗-FFRZ4CZ\!hEWRMpQ:pFV6G9S+ˬ whjj_ɶ*Hx<+rʰ/l[KW3:N~U, O>`;9w3XYKgljL᨜!^eZub2&} ='$uiP}Ƨ8jl+qUc:ߖ_r,e-uA3N,Dm3? 8z0M @vg j^06^6.JR?㢼Z+p~%ƺ6 5.d " v)*h[7D oQp>K2;4xNu\Eo$d\G{9ښXttŴ "J| XHA=oG=ȸ1v\$ߟBdVD2! {Kps$YsD&)6Z&Dr+&HNE:`axp6_^eg5* %oWl. P cQ|hqhF0.~RǧĘJY~.b{fzrq#q_?W3o$9EF?PHJ@*檦 )(ߋj>#( ݵ TOpSGE^l5X *ѹptE`ϗdxw<80$KH_WoĻ8{D3@M"?T?^BXtϺ@d\PR?^Ѹ)Qck<$%ETb\"RG-Eٝ@x?QĦ @˸5ʕ4V\#D߸cxN,5C~/Yp``:*B*E1 NEFƥ% Ḓ"C(B.@11*&-== 1g x IycCjFm#˙HGnjeQ:`[7XtYv=$`_u5x5~R).) ~YCl8`YTcyݲ1}dYUXFߚeI \3r AR0{>BQefŒ.6Fv8\ "&23iղvT!7%|NU/6Z݈ˆxEt, b͌c$4h<ی(ҋ8(!YS wSm"p]Jl=VNd)9~`gUI ̵8@|# R<],`g~(1Ƞ%#)21U <_D+)ApVRd|ik-w U5^A)KӸ4BY.9:oǹVG#ˣu% xX,1#tV wsֵvY6EtB59"X :3goNnP#KS0B|A=w}K}y\ a|ۃ?uO>?s#򳍑;x?4_Ht$9u6zS7'IL`QIIRElx$уbB.%P*S;l P|Mc0PЉ{U2SΕEl;+Vәc;̸/Tp" "B \htjηYY4lW"v(AmueBu&=0%)vxDca׸L+/44QZ!-Y*"F49=Qa/ZX꠵l^ %H@˴N$* $rBZ96CT:BPsbYũ@fJ0ÝL.__ť͎&Rf{qZd+Np;y5SD qӎ@8Pnhfa\*! m6?XQ S1 v1ܴԞrOX^̱%P<"9HOV&J#9 C#JM'xx=Zbǵ!W+ΡbDHEl48j:A@CԨ%|uv;+yQDz1M/$1{.8)vW@`J]TQQjWB" QO?s56`HY>m&6Js#yyY(< oKhkd4jxj]oGyz="0ҸVhA\vTqV*/io*EUZ&;oc>ljKkl;>WovFWێMwÞ!9$@K%&a !|#7,]!4_AB(5ɸ?fz896RK+*i-"щxI%ap!'A +/"Ua{NlQ;bcMOaCXz`#P9Jwh̹%E1 F9"`-1ɚR\%-HU )t#jy~8|m`ef8k t#PkhYCeM!" FŖIh~x\HJh) 6hrNAIt]HZ܌;+5+7?/Nf=\a$, %/8FHF,GcF WۏrG_ fv |0Pn/I 3E"YmܓC/j&pqr=RfBrRh$[нvfA:8 Op\HM@e`:e>vx]}(?d^3T fG—eySRܺkBɍFl:8*φPRBbQ$DaGT:hycB9GlZG9rH1"'Eh8rM,ޟs"K IX3bknC"C4vH|$Y&N"SyJ5ZJgUuˮz<)R)Yx,o0eʀL)634Xxd*BO0(I5^=\jMx*%D8WSBɥL,aW>] oR"FׄX~j=x4SՋ;(і 0 10o0$X$\~bloy +)Ueɧ{Cg`#oc`jpC93Yƒ መѸJ w5(P"10FvT@u@߅F$QKl! aasI6D;vL|Wr&kkKyH||b^E=*ax_`H8]p {X2FJi`r%L"VZPeh'd(Q\)~xO"1F"mZ3)]1uq {ԣ\GurBFބ+Fv3$3Z^Y$K*߉rE]IQUM-w*\vC P32^Q$dr]ĵZ ⭑'DX*>rʦ^QD":Nbd]t")ZdF4 8<,wy4,Mk 6eN*EܖvX#G|P[ iܿJ TMҕb(]2eg Z tu9 ^UfoxgXHLpDH[1y0TkAO) u/,ćx7M Z N j6J\ˆ$%ȇcbZQi*hXڵ]Ĝh帑dX 9:$3NWz:=wTķ aX8؏KgAa"RUEAfFZ)pKXǵe=So1 e/@G)ɟ2_Fk}YjQ_gaLD9Z d {jC?@ͻ3oUPBd5D{ +SRC,Go Ʉ{8Yp}O2CZg d8 O mœnNeӷo%YXCPR7zVwu2z $Rx0!Gf\%lBQbzTN#<b Vv_sҴ~u`mCZz`^ _E*TT:Hޑ!ºYa]7C\WRBU!8Mʩ|(9|ɍPM)-X½c=&|:m[gaEYaB* ㋏ԥO2 0ҍF`PKJ6Rv?uWDz 5ĠA&TjD\LYBEMx ?*.W RՏ4m4B1Bwzvpӓzvc#p'> L`H.͢4Y{[E%:(TʲԒBūQ:/)O */[3yxAҊ/.VR}NoUC{:K Cb{5mRtY$(e$E GG3:+49#k%4vDbQF2Aw9oF%lHV?A'S LPC3IFZN|#'0@߱yhw~c=1ו6TcL$2Mʿt wOB7G դ&M Yh~LZe>9^F:Z]k$+F%gPi]"{  [B!,6EmQГ RYڏ=3J}g@w_1chZVDx5x ϓDB@N(zC!?8*v)LJ$Ћέ Oz*q]V Ц0n9lCy^KnWdEb? ^e7CyߣJZRYNǿ] 9ή  Ŝkb˴ Mo!!6#]+Ӥeᅺ"NR8<3bhKF͵}8@Q[_{,:%iQץXa^:_̣ܳDSvK^ ",/;cTR<.#`!Ó5:lLNȼ"}q3\ڄ$EsB& :M-9fQ?߈B_7]Rk]^WG\&lF%uwDEnb@ЊQk٥u07~sgJ)SyqprpwpnOMwNN|U8t̞a\40PoFn׹=#̤c6OMx}=e*aʀyOyH9^H_G뛛:ok#܊lPMI4t䧄Ai};T9F/)$bYh(9]j &9徺q'nnVW&*$LcyӚh+Igc!@[a'?&Bn&ӎ$7ܠ5-ݐFᓴo^^͐;:FŚ[hI}nj<~l}Fo)q_ !V`v|%eòZJ :C-|:' csCquTjJ#.9H—yEtt[467"[q,\Pm}> 潹 tUY9.o!-aҸm\,\ܖu^m kBYG}V?ʭڼa,' F7"=+i [κ#$v7~Y|0SG\m+Q (1ѦJom96)a;Sh.q.J{J"~5l`n_N(jAOdg+{bM74{ /I3ϋb@1OTyE2; 7mcCz};UܳAeFQ6{ Mmӭ9SuRލ'N'Im0&" *arJiē'!tyC7'<?N8%gWTjC }i$R+ya9Dd #dtM}AŽʼn Q~Sm6G@'Tlm؄chⱍ^W|g^}9pE)!9RW Wf77L?,^ V؞c'>} K ')hN?ʂk*26h3* Рj]BD^J^^9PL /9e;SEJ~R[$%,~Go !#(#͝?%^̆T+@Ns67dVk!nnKcG!Mޟrq t2ӓHtt\5ͯJw~Iã1?i"9<#ߥY=m]5"WR5TJrN|nv3?,ykRuH:s?> =?|7=V;BrQ'/{x7V4Cy4U PMg/珢_Nk%d$\q6iUQfhQ7Ϸvna>|p͋7/ߴ}?|{H>i<.O74}׍Px|ޠ0uy3E'|ӹl4B`C2pQ|'^ߟ"b:7Z:-KVq)F ㎆B)^ !\ =_e}(`siIwͰ}3.6}lll>z?[7>[;l<|ol>wϜ@Pj}cSM>nOh{kw񓽧ۏ7_lo?ʶ767w7{GO7m?ybю}c;=h֋/u>|;ӟo=m{zӭ{wo8^={b;;elm?:}ybgoG/o?~{~ݭ'lx9ݝl{Ow>|GO6 K]`}w67_g|,SoY[sƣA {j2\\5|ulqӧfbvK~L׽I/Tb~eRt.3ĈϽ&ںOoJPV.J1Q9c H!OM)ΝG- lJɌU샢t?^,HyuvgA?ߜN+yhs/w?<{NvW~~vt F^ċT8~r_DQ/gG]X;?姯АuAĽ^{rGs{hjk={/i)=98}F{}|1ZОn`O;'47]g'=Nw{{'S5p6]3G(; R=8q qsm+>Іe._᷹p·|No进Ʒ[[:-?uYQF(ߡeHbu$#t|{E-tҔ>{.~Nzu1FW\3, Gyۜ,ä|s>1ލeI17wʡuy q{66ϪQ"&z~oï]Kt?dig/n*b<,/7W?/~?tAc>,n(X ;Hv"aڞך!{=ۆNHT"JB:M1Z7#7s?<~#yLtM龣hDAߞeo{ry4^.U{!ofp}5$y;9蚚 '۹\_@Y])]?EmP/kk 'o? z+ݕ5oLO=NܭbJ5B3ܯ.\/ߤ-oViPHvezml  lC/>=#M_f >@LՖߍ6 4|uIHy9/ 'g\q-dzg(/(J/3퓘gA;7IY5M[('֞RF9: ߀ϥz$~+W[8o8:S+_/t, g DK>&=qoH{{eCCt`[Gnm$Щd{ p=;wmQghq+=<=7;aǝsaA9ZEJCKRL.ê߈ePpďega%+_1xv?C~ $ƚ@\v'^֧c@* %#@^^p؁[Wwgl,0$Sn"kn!,t@t'M{2M-{5 N0_Xm#zj#'鶃a1;;`B A8a%$kxwO3#X` |{=}2X'7l;F04$ӡ:Wa Iь3v(#=[#<l<=ڵa:mZm6N;&qڇ0gѴ0ia0.q*xO82w!.'4f-&Lj: X; &(1ԇ |=8yP#[u!M`&|p1Jc:: }d"Nq܌t#7DMR1a_Q>>pڲN=(Au:fr @:&^5;f.{ k!?U[g={$,эĹsR/DwR,䀜>+V+.oӾo"E7!.нӓw $v3|uT !tS}i0u?R]"[ %Kxn&m,B1>r}^z,euC1BFssF2.:pG6O9 Qwp r7du#3Յ[A[d СGPP  3Ĭ]bߟ꤬IX$vP#6Є $&ŵ[2($ G%w)Lu5QA~[܁% rl%wp J MBCTC7 OxA K|2n0v1W6zX!#c]}# ?jwlap11.Dc}KPGX0E 5d ƝoO3@5c]UUI@E'h_P1jnM&i֬Ւ%If ΃e2!#BR)c.9Bfm?c[ >G8E>U9^]EP5/`U6f#䱿Cca:؋CäQ O>{`"s ϱ6Grp@r @W͵Qb5ɜ5Qw-l˻ly;B8mH9|> ϸ`W\,my6?;L;ͮ sg765- x'f曤 &{τEe^OKHJ<³!B5""4Kd;%$J vԉORisoHvc3qj毂5Y[ ȸ@"1+یĴwIWE#A NF 0rSg8xyYB Hs;C A`wO >b=T J2/L^j^蓼G|Jx(?# Gg ܕ*WMq3' KiJ-<3̬Z1U Rc.d;mkZ;e.ۓU5F֙Z!Quۊƃp>6]>W.F1>3lO&-],ÞJh&/dӳLg"Lf8KpzYre.$[eUL+!%%&*X JHJa!QSIkA 2j:ɥ kÌuv1@Ze3LO*0ukNw#YQCۀQ:3Iecyk%9Nccv烞mj4\W9~Y̲(/H†^4=SI /!wĊm/fzaD+zba"fSAYסhhϮ6sy mZRPz9Zl_*Ӽ8QKny+!vQ'קbZirCKpU4]9؀M4Co+ԋ׷$oȩk}[Q=W3J1h4|b)V@:YJO ?ucrcQ4ErV#yLҖڮ/ItL)1|& JQuUyTrip3V5YU~&4-fAme0l'5z~!7%:VF|(R*j⛭)U xq2mJI%Q=Miq*3B06iFgUK3 VRf|>,}9u&X#_p}Z/Z-}ќϻ|y!lCj-5=n5IlEd߆w;c9̗M&jP[MGHҹ.0`H-~r1)\yjehmvrl zl_ :(hYx~Cg\ioVZX%[:?X$io %ܱ\pZ+bb7kqwrP6*mIldݠE: FQbWizR},ծW&ՁNɳ^)-=^o~B e%]˦ZP>̷kzE3%NJBXS&YTo"in[5aɯ=uýbijyL5j餗cd-y17:7ͧ#E$9"3XD=T|gK876Uwۖim0DL?N ڔNۛX9.)ӑnbٴ4xe.t6|M/C4eohܵy{7KyV;o q'v޾i۷Jy9;o2ef}!a'xI?sgPBt'0rl?ZuЇ9IFۃqo_O9/C|Yhdqm>ehcVo,a X 5M,ޠkk`kUU!`7 )yϽֿX,{,^On1b|;,Mu s9 OPu1 3 rc_֐x}FY?"-c&`9</~Z3Pvq}A>K}Ŋٝ wm,~< xS ?뿃,}s?LR`}hixJsZ\R)VA{T]ҳg[ŝ~zc\r݇{KG-=+΄G,χΆi:5GZr-iZR\*l9=>V_ )A>LAfű  =y^#,ljTZ?K;* V/w3G3K}K\B5ֵ`5P!&/|!t)qA+!e:Z K@E)kb|<`GnϾG\Z=kk~{,u擛H |*͏IxWYQob:_\26dΚ$Z[ V,=+_z=o’-i];E/Z;_qkg-3y*5 @{Ifǟ8d4jϷtQ2'8FlRȀD NDm3DC}E޽r+>yfUeThWO+^d5O~A>_(mu+ڳOn(̗\|4bgQk D;sDǐ m xR`a{<ؗUnGx?p{vDczq-WI?lI"ߝ#%{}> %a ' }-"H |x|yFOX?'$*/߻_K$Y[a>߬]w$Z] dhV[_L/K/d?-$@*"?/y3):)}yPz?+x뿴3WYlf/yL&ؒ8 e,}]ƛYNG;n̷m$]t[\_x[_Z?gӵ>BOu@hNw򿸻Y'_ YY}O3_t(R|oJ(׋$\J|'Z?I Z? ?:gy]qm?g-ڟ^|{MxWIwНZ? u߃|DmşZ{ZwZ?I Vu߇IdyYXvV=+1Z2ߊ/ Ӧ?Uof b9D(g@Y$~? :a>?|_%o{坵 $^v0ikk+?kd|+~>>0kϻ]^+R)ٯFɉT!p[g{gƂ|ώ-,)XX{3Td6`dOYF;:a^vA)ԚG\:ԄgqkbkP j.D`SFMdR78̐kclڋn5+Φo j\sˮ&tg=gMYX/>;u6:{+_Ƕ5a`YtlʚϕF՚Q[;L 3r~Y1sZ5YAFU6ϵԨ4Y v.Nk]_?agYyU;~hIu^m6 0AΪo-|CpGVyuZe'5/Gi:ۨv.3(sT?oV@)v\9o*fk-I~NMe TZ (6P l`w+#tcihը`ΫOkGUUTUo@˦gF/[XN yDA?-hH8daLA! zLTڦeY,mAqM;GV8fio9vzɿL@)rW0gmN &<>ߡ£?ZfKu7n©PzR;#9 i,6^V^E/HRG'yA*_cw{c FvAeI:ZOTx ӢeV~/9-unq ߦmkN5G| X +>'/TӸ<%K0 vS[i~\> ^\6j'ⷣ#.{RNDx㪳M 2}1ˮ;;Wlavm销6F$R FObV\U +?=gI=wB`iM0XE ^LX+A>)i![JV*muZ!\=L7pݐsV>pPY,Yq`Ai[SΨ;l#nCjg#om P{4ŵ]a!Ul MEYhSH刎yL[M1HP$b^yvV G` ΁tEtK{ zSwb[S; MYqP{g4|:e<~g LF{ Oӏy骃@.G:匦Tj`wW=WMԘ w|)E}{[?lx!֟9~V>,C2#ѦzxH|(TQ7Dԭ|+3icV%i{`t<|5 ThP^Eڡ g k,C]N-[VD|1a ŔA^#O j_S?}[=!k }מ{Ľ*4.5.4;A/+gY嗟(5wTQzU( e!(lN& js1]v:>Gu1u0i@>sU"iYτ̓J픣1ٔj,l"+w2r[mD<[6E {>~TLng>}=8݄5uSmиR ,RgU?nbQsi+ az¾TySǮJ 6۝M&08qdO>K|5%/^B}v~~}zYDOԛ(jI](t(zRFD,h)r` s|\#Bj9J0<)ܮ GObq`O+i޽XRIyI崉ڜ&ы6r[+V,Xenja:.؀lh>hoL?s,X1z8 v KOKYKӊaЇ*b82UU5)J^<{ EL84c`,\c =FP֗QCtj8Z˪ )np fn:MrTIrHiI4>eOrQ@~j<^|=Ky{L Bn~d9}4WOxOyݴv7-|e[rMpӭpZ)3ҿNWS v^pծIOnY$:} 5й<:w"ѹ:3}|'(f4p05%ǿ&wuEu.%pqKRd,P-DMŶ}d It9qPL'3G;ŹWB(Z葿W bTEX6CO|XϮ;[;ᮏιa\l@_O@&4#_.n}7zǒRQj7VX+_Zu-K.Xy9a/# !{g::yuyrZ=Owv5l=-o/EosBqڱO1wTyQ:Bs&_ڪX[KZBFUl] iRKlM9; &T L@JArT4m̘m[2jyοm8bq,YIF{5˽% ^z7O.XR܏Q.MdaW)  \Iޘ\pP|u{ o}TiϻF?t#EE?\0_gy.(xp+< B8/.8u9S'$! (8F&S+u#9otnNH)Ebؕa}xD#w':DpdLx n->|0`#n0<ۋCBz)rȰ)h7ɾ3M$q$xL <&׾N@ʂ&u= 7۵Z A#A0x{[WkFXm-L+pl~PZ>_+6;n yZ`r`f!^38Ӽ_RBu1XN=@+㎂ư`y׍:>znOާBJ'bA1ix) ؿ oߙޥXZYV,}MA  j )n_:YdUü=VQ[qUq_n_W>-efaϼX*X2ϵO `9etza#i`Ni7Gy ]YH?t:NktpATq{>TA=5\/*şyk+: ]\\IM͆X}}olq_u#_:=d݋0(@U W=m.%iR|Q9wʸB/-k L_l_=Z.(G>}; ZMpwc7‚,3TŦjAy:A!^F8 BvBB@YԶ}`y\"qH"|g|I ,2$ 뇎(,Jq j nomh3rϣhh3'&#G̳=u -dwKaTR7y&?ժ]zS0SpPBY67EeWK5,P?a`Xdp,(k!vdD;"aGjxeYWfA&`di"B ;_:X_/_L.[11Ódj6`fBZfxaX]xyqdd1wC9tX6o0ºÝ6z'ZUMxce6%z_dyӭ4]f,_qo2:ě9S]X jB2'H4"K> :t$H(tnhiRJV>(e?$Bx`UNKpS 0 xdtMQZ:$kMy$6:BCB;Br3h!1d~E#+yL*}1+‹yTYW9D y jzE/͋"Y cQqƤ#€K\P^*Fh!.ՌŒLqe3 MZZUh{Vui~%u:uẎp]G#\u:ucLu7p\4J/:uܱ^/U8Vy2_ǸC+a糇ig*Mų&cY]\_u@:u5-D>|>edOŝMԎuҍ2&Qב2|PP$a8?Iy+Mx2]S]uL1r-$sԘ8taq=0aEFO4A EWw6`E kvWs3$)2Aky9/ Jyӗ+\$5Y$vlei5ŗ3fV*Z>XX~i/utЛG~t 48> 2֓kтӢfT-kxIi._R+&ܷY w|0v4kI֘CNAG˂G _HĔ55Q+ _~!-˜xCC(]x`#ӅȆydn{_8;j2ݠHWuow7Ws*7^|)A};aX^<=ddFOfQ  wy$#y7^$I9^oG-Bҝj~5U9?`L۲1d?K^\Yf!W#޿|Q1I %xtwpM)!x1p!϶&k(v>4*`-t|^r$ҵS;(5wXTr  oi'RyRpNsUHMi/pVu2VYg8f߄~Wq=d\ \ͫN?\:@ ]#aל uGC!nr4 xlynMT]@9=1= v',|[^t!wB5y Qh"(; R ~!*^GVeYivADSxTP=nAZɭm.{Y9hn̢R.^4E?" /Ņ]>KKSlͥekG &yE) {+CLLBĐ"B jQ'y$#PD]!CnWhz(q*ϳ9C0- 5׆F.e߽H麳AP"r' O <3SDѹ#0A)@2 UU^p=^$/ϸD$ rgensynsT\2c̜p,jp[hz"wRRPH4C;S4"VZ*cXLn`ѶLy-u۞kW;1 >Pߟ󞏅{voi]OY(FCXmxBy ЃB#ϝL0/̀ɥO.ȕmAjBoӝ`VOo,rt b)E.$%xJu!ϗ__Z8Bל)M|S5^_c}JCo^?mՏev+~;:ON+G/ TF@B;xY >e]7ˤ\mX=Sp.؋#Nl]`ҟ3O~mJNP.l>I{逌`L X+R1ͽ@>ii [.V jxA$չ % |•B& Ψ;l#C37:(h(χ0p6u᧸FWcx< ??Q>?.+o֢'}͎T~~̱%Yx: iu=1jk{h+{G~}oG/N+-/cm~RϞƾ,45p,,`IJoy=}HVz !Hsq!;#*͟;֪6hsJ(6۰ڪ 5gNڻ<>ow=? ?P$J_Mm*,+O"AC!/HYwJs FUnG6/Bu]>~^pB"kz):TG;p]#C.[rd%Ax JڳamMs(N}>9s؏ѓ>/p&;?<+ɰ9 59O\ӄ ׃Т0(Ol;+ װ75+w`1N8%@6|o- z#ԧ FsƝ  쐾,xyοmgDgw6a4FRQr,@W6$`vP'CT׷F&Z@)KsM+cU{t`2X5&a'QSE/2RvK3B:xhEMzP *otzyGku2h[#!=jO{O=R&Q<XTr\_>Λkz@; d3U5X8sY9&1xcL~BЗbH rN0DES9X HI`O m&a`_`ķ_F{kW?dn sUmwg'vwggΪ:0F>gAV`wKkC|m /ѿϖ *n?eP uɟ5d-Ry;["A]m OV6j>Ii$῏'0OaA"ۿAMEݮ,UL"gsm\v8 B0 &Q !T 3F_xC0e>*JSRGHDND  (\Ԙ`Pzzq7#=M7Aq?O a" |LQg;v7St8ЊORw% ;j"8//PPQvZeDƱ`2?ˈ8mD @"ޭ'ak|,e>'h֑+FI4Dit@`**b0yrXxDePAN-W*.kGg0+=ˆh)cWCG5F(ɯ@ #m栈?mk(2) kܡ*tFq'PEwiCZ;o6i26׍'HxU-T> kXW y`jsg `8VƢݐ_*X;\V$0& VVf"Y BJFmBJ.Dp hچPJetO˙l., ur=:}v_{K5ۻ> {Bx=67A@/|bld->5YF|tg=L T2,7T > lv};G٘.wv.ߊZ=|({pǤ>ssM RȐm۞=`O6Loy&tIº |y~< כ؞G] {.{Ex2ǀ ή5r'㛳ѻcn5cT 3$xvwb~β_P!Xd$u@ȵMD *jj4t>7V!+!:ڂ H&BA[ ~ތ];?= sQ~{{D~wH|\R.,&Lla(]h4v똿aⅆs9aT`adHe3E(#7@KvaF_vNԨquY} #*Lƞݷ`yiOϢhg-y =|ާe* _)Hݘ-YtA{L7b#I9LyӜAP=#c /B>fՆ2Gj7 #A<څMl׶q+1`GyQ8fDl"7TS͐||Mt\)-a<{7VVȂvWW䗼e*ӵ$SV,)9+g|> JzH4&bK 5`҃BV$=`@Y-+@27Oi9ӥHTj4Φ9+pyMґIZDS!,hgvc֎bdO,GԒP/it ,v\ Q2M\`+2IlB4 ,&&X/AL8!cJj3'O6XB~XC@ ;0̩־8`ʧhƒ΄=Z]dk ID~X EKc@K7-]m%NzE0}w`ĭWly_Id`İ=?qz)'mTin`A N_`R4~+sPD+:Vl7x渥xů7LwJv{:h }\PKX=ߝ^[.>'oq{cC1?[LJLJLJ9+HVP. b "hy9c !r^1>^`7oz:£@8%c^ԋQb%%6+{s*(nV+ <@gbqnuq߼=6輚4R~SclЙcKk},M"qE?>#/KW$ a^xi=<:JwR>x!kYyc#; a| ~\D M!de8~q)q[omq=x'tP B0 vu[PK>`` h/8~c#` "Oo0eS(ZSgajk`v%Fv*z W9:(:99F;B@7/vjD%m4Ou,65ZO򜆱Ga;]Ǫ Б9` 4kl}ZfZUR [Gv*UV@ݙ ~(4:FWpuKv* (`|:us}*(..88+Ip-\9j /:v?;g6Ay P-~UVŚ))0 R]~m;!PFܘ@x̕ t.!2I~1(h AiXL Y! 7'gyЧCHMt|lVz5.m(rsoi'ba _3DF̎Ad ARF DT˶ޣ:) {DmRrP.1:ntYVrgVfjVj@?9Ih#y!&F3F#y8g^khƱ5ۊ,?CV$ XCA>UnoCdݷu>QE~γs4$^0Jo(>5x')lFCgy71vMfzaJ޾0+ 榐M;ғi4/s"I:uy~٬g"3tcCor/#tMn#sD ĄVdZnseL1œy;g lJ;Y)x˅I?* hy~,)PO}?:a1:|(9xsz@,NB~ Otq?[@0cZ ZAF(ٍ"Og;rJsZU#fx|:n`n7^ ­k)Qz⎰&jDԠ+,E,r;g)|,ZJ:_D \&kWᏐeVC:Bөz63&@–# ո,pcIydX[EMr^1rf62b$uy3Ud o7Dg63ƵA!' H'VoNMH\hs)%u AywO`Ur&qp(2yR+)ZF\bQ3GLU ;^(iܙ}K"k䎺Qf`Њ|u30 YlZy]9I*QG c`#kbuB2?BLFWT߇#Q ] _r& BG/ oxf(47E$>$ 4ژ{PGP`bNnD Kj$"Ib1MD&Df䱱j[k"x~=KLaQXc)`J6pZݬsDpFr'/gہT aK̤?24b٨.n 0|D09|On!#F\>VRkưfq yz R̭כ WQIUBwV]>! ťCV3o͚Е8 dػx[3ѺJPˉW_"}&/ c|Eg;Pr3lkj"L*)Ql/r5rcPjD3iP|BF4ckO<b1{FP!%p.>8όfZ-/-Y%b=Zq0J֕0͕KRz\`r̈́;kߠ + h:RP)% ҊqscWXo^!Qq?W6SrcCV9iΫ-xKia9X8bFG=&a*1]nqբ Jqk ep5~34{n I2^ȥX owy!^sJU=lԢJ F[ʃw.@tѣZP,dnMh?Cq#8]:x C FIr>lǫP=(P/!.,1Ŗ}="9}cNu,΁ #Jd8MTNU>d1/oM&o(^7b+89. |!7w۔1&9KLhVw24u{d;x%ȥ?B2m'd&t;$!5ط nt~ t>0Pi?h3L^Rv݈gq@\ny.xq;Tm85 5u#Wේ .20I y\bIiR}wrʱ:{6dcZ0oU|U MJ|8k) E_)ok"<Ƀ A^``izs8F+(MٳnfP2S=oi*J#(/;*[N,7?E;*~9! &LJ.`B0P q{3^AfMPiو!Q>A _oZlwggkC2Ao3&\G }:=KqsxwDk 2 RiK,EASVa G@r)>G`DDVi}VVr3 ׀ mWBVMۀZu8~C<:Ӓ3 y.ܭܒMKUSl<{nD~f,]1x~ I*O}$. vUm[M9Y"&0#b_ 4`ʍg2hy@L/q[%R$ X'` I=s0vD87qz6>.9]!">YO8Sm~/ibv 0Ô3"Ow ۣbLw'M=vXwq@qRXrhl$&VƮ+d a !lhPg~dǍKgD-tV7 M_Eԋ<8dx6fJژ/Kۻۻ[] |;Fr(` F*UilEj"UAR@x2pg]!R@x+"ڹRVG͛q,Ofx^;dSu/1>xX[sMs4~ëZg%0q? |w hPsӧ&λo(K|U b5mw77!>\~{Q7`#z FX WR7/ SX%p5[-556x[: "#߸//w#| qwy)n8_ɾ@Sb:={Z uq{XQ~Iws$wѭM9i.6wry0GgЊfysx<$y*Jc$`,ޢuG{Gd, ^-a謁) 4/_6  Ɉ3eӮ@\\O`nI/}ո1:]ѽ>v!ū%W9(Fň|Bs'F2Dgh6#>~z)pR~]:A$>lD,tg `SܸƝ1dUmSbg~j}> $ʸ-hTHt5Hw4\_{$-%!G$W  *2H&&wSIs{v sV9zqv#'!ΒAbJ=j6vK.#FV(֠:Rϝu)wJ֜BFwc}KW\KN 8G -PDD]p)Մx< Cb@f="HI{? GX> 6B`8 g4M &{w}kg)R V~(Vꆧ1<{zXk7wm2DŽ.,t *Ň+4D=-7E_;nu0fr(C83}ANN2],og`)_s>#3RO 0ci@ᏛQ:l|ET"&A^_/U~Qٲ4 2fVLK:0DUTZh@S<Њka0@9l]6Tq;[[;%#lI<%2ŏGMDe*-zI3DѬJhdQ"Aԙ^>Iٲtj|e΢#8ԯ3liNPH0pr6ҨXQZT~ck10zMQұk :(- I66o^yPr^Ap[TtڒosK 7W }9&NgZ$b~AqB~1.@-(Mԯ%j.IoCE\\JHn=dX]"U'JZ>L\]$}AvB/bW g[8N9)]2on^UG͇]a#S,ǽ!Ip̃laVwV?gze lAo 3h ~0#F^`@CYxg t w" {;@4q/+`X`\ˆ L+%';QòasGE陶u4'Ql$i&{i%AL #.E̫Ktv#6!үs-.c2;G1Bw1ܕ.-C0X<;20rT,af~Сo,??nbxE P×jZbV> J{`v{::::P1OOWʛmz {kaIg>LEyGTV/Aߢ͹l+O5 _4 X0׻%6lM` ` u` (ir@wQސ$~t[>\x`,طI &W’κ.o43IY&ҸrFڟp`Bcggk[7z '}Ɍm3j&#bC՞7jI6v7"gDφ^`Rdbw%:jRxaHs3e%?4=UцHLSwGujf@ņ_7[ 63aWt4HGo4"u#cR (סVqHw!"_@fw(Ƹ Kuuooooo+kXImn}BoFpw?zy$at@|=rwdc' 9 1azguIqB% .FK[2Ç.,H )M PhnQCCo/u-?4ԸġyQJRi~EaKw;E6{QB75=>^g{"- +!zzؿJuo@]GC#ɰv7(傂a0':(9&tor#$ bY_OD]~>ˋ;- -%aRкڨzpĉ"mr7W1Kc\}Zڃb3@D3e2/l"$yY܅)s0i׭w$_ML:2-owo(]e&aG;@&[=ς xrmN.Mkc~OSZz4{ʬJfU."F'yJOVd?OVdAޥ|s*qJٔx2f+ol?:l }bN|W'c-ݵOO>[kk-`_ &-TE /s5`Twgev~D?cx<*Ok&B#b{mwfpZ?m_Rg;[vFgEgػt?ojb{%u^?(ūڍv('L"oYj&^{b`qV?HFU%>0-ilrztL`5VQ;odK@$J ߶jqW91pY z\CX{ :|i |Ow㌶ʛkX%vJ[{wK 񟿸?< 7RYο}o?{vt'.`05㲋OG;=:{ߌ/+=kuYЫ3<邬coy6-!@lq?+[kJVie?=hGyXcTjG'S:;JwnMܹx Zm~7meTDSJYj^%o>BEw_FZ +Ac}F8.@2蒿3QkKٱVRЂ9c%y'U]wqA~#8N*&3.ԍƔ֓)ڐilndXodxĒ;}WXh_r-[.0h޽3FylA?G]| 56Vĕ29GAhW<:twM턱̣,H.cJ_Uɑ>u:kb邯3a^<x<r-kre Hpwjntv5r'v/ilAa&m܁{͟_f6vUW00^]ѶjO٫&|ͮo@>;6X 87ʅ= 2h 60݂ߎ\kź@ٜ3?f LRE+m@&m͞+ ſ<*v. $5Vzc>< n>ޣ?nU.6PM׫#D{cxc>XcY̻0F5J3ǟ:]YvWμY_O|L5HȃĪ@mK7^- 6Ý fqrK"JHNѽF/PizUdm避TImTIz&]Y/qg)Wr|U>),ƪېˠ@\XʽGE7yy'+rsk/*:3iYיގOěD^j@TCBah^ Ud0QbUB0x us[1`k_nph'l2M~9.^y6 2yy>yzkր"fqT=,c,Xb*7G^v2~~ >wF$]zKwa{ 1tyg8~KWρcʕg?PCN> 71.(;AN>ggwc]?Wö`j7~j^TvZ})3aF7qXCWӧOƋc gK`1o{!IeǷxx%B$s{ %` lC` k4]9BS 4]}{rU ?ai֏GZ)(7^8<<==H&~f vogIjΏg8Ux(zQ4bAY] ͓cw&"'O3:o 6GjwN1@[)enT*r5p rU]J9g;6!>`D@#6Zm恁NT2_7nƶlwqW: h<R:d+ =>˂pd6<ϕ_/N imoEFy>&@t-.DyV^7s4G>RƳ"hy(tEB5E)ҤȲN+ǣjܤEL0RR#ቔ#OHgpBmn"C:6sRr?#UJTH!QJan*[,oz4߱3tp]M^ (< Q""MR<& zwڈWoWk3"CkG9눙}=ޓt¦jS">h#:_:jpRoE :z9׹` ,40meh( *l*&W DJ2PUՃC5THO8\xqZ?I@?28 ~?~_}60{~f:LM8h]ntob/f{={L;`T=#2b)chFm/ oz)H Gkĵn dj*T{ ;ĸYKL-iFtzٸbڽ3#2S~v`=`ﰈbW/I [( KhQ.5]_]V tWLxB5[>Ѹo ;5/j0*rw삊+y.w1Ju]'3r^3Oo8Cq777 yǜ)uSS֣X\ C.Gz /-+L /+]j`,[ O+uڇKcHwǗxy٨g ܑ}7tGagp;|<=K넂dt3&6@`~FAҎH_e ,]z#CE PֻCo!Kd 1 W?deS Ry4k)Uבh£#K-Q9)׾o|na`y󿑏J怓ues(/4[cm$K!> }_ Z?]/{/rQR彃rVZ7xv p uW:)i#N'.>bZ|{ۏ8W4e)T`Nw{q1? Dt6y"KYk{Qb)g}1yy\빶j8vφ??~J%Z{Ox3ZA ݝ ÊRO]4WV}RmU)k߯TW~+Ծ_A4GJ"اAq{  )k7b֔KeE?LOL_)xƠ8݄ǂX⧣fԖ, 7j>IgjWOjO}Z? e!zA8}jق2G8LRAoN7/_Utc-|{Rz0]:%Kl`|n6Xʅn: 3AGaߨ~:;z= aV Jz2b5b's&jH!Yh~zyUmޯ?(aMxp¿/7ch!P5s=0XYFLR,]:yn t{Fm}J˔Fs`# $U^qc]FXv,Pкs2t4>۳AY %-xqz`X zؖ88ǓyXözY pA#&H6#X?QK]JCw̞v~,76(fMpvvm}ٕ=[7Ƅ,ZځQsO'r9RGUp1\i0_Fgwqw8: Mn٨  Dk7)BD⡥41DDV(ր=Ndy%Zqu~e#97Ma9o k锨F`˟DFlqYvM/~Oc8X|X;^|Pr6m'nm>cRX)tt\ OQ=\-sY Yv`a gC{jm;w$= tZNR% , pbSc0!ŃxÂ>HZFF#!~ pL0lDzN.IZSTD&hV@h9,par”;BLS/C 1A@xwGF1rWEA$,)q0 Hf]>cDVcr9l:Έn(lMCw!'iuS!Lk"k@Fl$ȇE BQ?P{f9$' ިA5Q+׸:; 7UihMރ 4%h28HP(kɖx=p~S}JV.` "p" `[Hg΂svd`9nez7'DAꎷAzۘgv˻RO dU6&9>ۘZv 7鍍:)d _ځllm]Z*>}:Nw}P9zP~m=}2{Pxl&q"qIY"at0mnu'_; S8#o_o6X.h`<#Eve2x*Փ/7נJlTd ɧ()]a+S'{[ '1f;a\PʩK.Z }/݀8 zw _?ٓ ہN=¦- )ufJY%:W8*95?U0gDe4SadF1Mѭ`7n&\uǯ00ZmԷϴqnTނ_y~5Go* 'v\mQ]7ꧧh* FvtpP;CqV{~w&XU6lJi?tۃ~ȱ6 ?SQꃪs^(,<Zt'%T<OeWP0@U6ѧ٫*w ۢllAXNߚJDO`D q'W Am_(Q55owFdpɪšmp=ԐԴ.h9O—ԱˏR?fM464`=,9w{C3vKNf9!YfeDӦrv), jba'O'@ȭ(MG !>tOL~J<]hw'NM,_م=59Ete%lM%F$CsUr8+QɿHO;x9))hD8ˠQE(&ϝӷJ00go3qN}MNIQmC⊯̰{{%<Ҧ@Pd`X8;l~M,9X6oyOCPv49-+H{)Rǂ]'Uwmk**ѧ_8=cʛ"ODOvwZL*RPZ9Zo3! (v?(u[A+nnZ к}M;~  Ɍp B񛶼NjfR)nkKYu힋ۭNd7 h,^)TWݑz){v1Jpmݲ>Y' WGHtjK=ws( MI@', \$N> I!@AnBomxi"/F#&o͌<[@/q1 )STLe0<%to{ǥm(~8i?8H֫KX͙n.`ZCSQP[`gmDWwJ5SJ%LW?գWp+@(.d?:m⣜BbqW v|]0]ѝ1mƒ:۴>hP킥pmvvu67?to;wowv77 ,8B k:>w3J""ʁdMM+ 6JōҎ(+ 46# W1rtQ&Vz!@ \c`w>$Qhwi\pƱW;7U <@>#:ӷqIo⎩a)Gm|i&"TFy cgdPc?AWE}Q r!>P嚽*l)u|%j^2oL&V'v VVfqs6R?d6v1TWyF)OEG U+@n'zL{e#Img*Xlc;멬HHshN&E[ܗ۹%j~6 ` C=ةtTsr0"c6{6~] Ą}s0 +uJ A2;@7+Y;ƲHdU&yЯ1ݨm K;d{l8YU H)HH5g62F%ْ؍ rxmL$Z~V$lys#}X&"[αXgϛg_0QhNO+K)VQ9PQ9%I=\:M'o,\dQ@F*t9#@Z|t@4!4cS_/z!2aF_<ü̩;󼗴#r{o,t|!֨pA[ves6*ϸn<7yjZ<2ï iOk4FP>3GD^UjF:(v Wʈݜ *"s; "u2qX3JŃ-D3?aO1y\|Uxt7`$jFkAnC<1~ VcYH8 13H*0([}dK/wtqY;n_#HaQ+`z(!E2#' ɏ zD~4g@M t ݳ=qMhIwk~dC y{-Lo|?t>vAߛ08>}Ζ皇@^G~vqUk+K_a&ynV.,N} ?΅!yA|=nлeXOK{bml> 3v"1)uo W%;dM 7[;̔("Vj?/բnjx }0P.ir4qyH&ޕ5pq^^& ư4n;/zhZ?P0=2x<[1sc̟9 xD8A7NHEjTL!Swbe "Ğnj盒@,iJɑ=iۻڤSy&(\m4ڠ-mٝ|>ٍr 3+=?4ToOQy[oM7~;(>'?KO~kZ=&olÑ!Tcn2R]PH>V'tiOj&E&g|kx?`&_ͻ^Ac |)>;. ,,пhH$ׂ2!02}ici HXpx\yz;N3J@:xh ‹ƛL'Ӣ|tHnb {,$1sbaP8XkˋIK6[c{ߓ(o؋_vB;$slb&K6vpfNL֩vl>Bll>ق@[йB̈́sw`)/!"{ߝ|x Űv _3&z`]؛ oi7Zb7o%TzAUV,Je]OJY*nQR' ;:>>V٪4Z)a+)b֌ tړ!OBzƺSm"1S>\* ,#d>+y= H!ȁX p jx2 `fQ /`Pɦ7nRiҨ5 "3q'2@S]ba(Z]0ڕP&1`סsc>Й~"0%{3 ԉp'uLJkpG^˜b<x~FC=kf/a݁΄roy,6jeqha2,ӿ.GKcr.܉8F-3naR"&4{°4F~~jyZ™Yx*.G'(% 3G-7I 9j?oT$;ёʼ~HPNw6}jgv)+SvA4g* u1(#C'0(&3,#PzDOw)+rS;o{wgգ7ZJnx)u1L{Om68b)OKg/FDuO=n 5 uWuO`QÓZcOxyJО[QQKG c#Z|2}CN\mZ.-VB甛]^HW@JE~OFQG'vU64h籎*k Gxv XKN\DR{TI?5`׵$Лk;syB[L!|1ݑ>|ަ3G\K+64TDӍ&&UKxgDI:T.lΞaijXS3oݲ9'n'x!£4Fd`bB$ yqZi3e٠a`T|V@RUuHǽRQNA8)Xg)Q8;z$N4a071n'Μy$P Lϯ@< ygED#u5܍lUJ+PɭC)W$7r g#Ѣ{B.5B&yQ7[%.b~NC"` ML g\PXUm!\kVyOПj+%zǿj䜧fV9~ p5.+}4kGo4VuUFRx]+U1دL0mݾZXȹDr|Rg=/*:Nv9]1;! <6ca uz'IqdiFj"_P0G =yi6b |]Ȋׁz>QPUB[(ȬNH/ }^{KqeOQ6vO{f~΁,+R$E9NS䖍w\0!9;зb"dmmc>A`V7wGib̔!R1`rk/U$Oij2ܸzy`Ib9#L ۜ$n Jy,,`uqs䂍qouLcO!j}/_}v+f9W"3|xb] -x,;yyugMrß94a#Y'$hDZJFXYF\ !C$[묩MfLhiY+'+Xٍ(oƭ<#(ԥ˃ g7O]i6 Fmyz-  dztRR8،L;v8 3<)£g*t W:ւh⧝Rq<D<u@㴘p4y|sYm4a2VsWn1#'l9 ^"yP㒁|u1q_jS KТqo #`#O.S52E3Z~A_mEz^Ad4J0r '>;TC,R;[9"#l@<`Op =3e0w_r u5_O9FLE=W5I,Guf}ޣlfkA0|ewxHtIlDB|8~5Y<ּgZF8Ik?Z Lֹc\ؔ6Nfq̓i@}٧kݗO?`E4†`!=cv6Ǯ^>(Xi(U+$[Lh\@sY3FX1zU"Pz,2q>$!jwaV2ʇ&ZT3wNN.4Č+ph"ၒ ^,%w/c88 q0ܸXa&Gp1:?#YwOv9"rV bxat^)^9%{lyݚWUQ@w3\r:eIS(kY;Pɿ "'Kt#=A03S'C'.jYTi%"ĵśj: {ҝ~!@9\d=>ݯ\7bRz[m%_6؏TX=W|Pe7..|"9 p}2g1MKM+ᨹQEbʻ t%Th+ڐ41@%24qh.Ju.OԚKy ^ Ÿών(o V0O Eɗvb`yL5?E'<(j`#b]`Ķq'#4?FMHv[E[>$֎%R'V֤Tھp{'ފVkO}"*Ⱦf5KxXQ僙{R1^F;6H%^Bfjf$;,!VgnDhȱ.Y#13|y=-7y"[z E*[vY@8VQuÍB={V=P9ÖuϰiZ: )3$=BU~I?)<(0ER`iStv|S)?mήskxS*X{]Eu?+j8ѭF,irͣW(h_RGJ|"Wqεfިf%s^GDaJ9  &#BoBفaͰ ~mv ;Ogn |?Ƥ P&o1*.!+FzƈTDwRtx{~Q7X{׉;4X^zOb)0{# (!jCMN-^4FWc)~ 1Ja,fvk?by9×3U}P[vYؖ /ہ_:~$__!p(x&mޟn K B/Fe]J!XêȱUpKؔ#)#ZG*2p+p&s18O6PE^/HeiШKPc5P,(opģ=]GvZ+z\m R$:)]^LhDctJ*`!PIPZ}BlF}EdL1iX*:Vz aC'cvHEkv)X FY=XX*eQ(,JEQ(,JEQ.^xoZ%!܏诌"1aCD:P;"yG5 -%Uhx$ݟc4[Vէ8YzCBWHTHǤR0PW^c ƙ쩜 x#y9H>,2`{Yl4`HުxIqoc#\"-[Q˹ '"HNeď1 Bˎ[1`1Bč!i^Q ez m:v}>EEYE'(y\tgFBeTIv^k+(~j3e 'eJesE%e(|X||*˲-w\(^( M\=u`Pу:N89z337G&r@olf._ˋq >,s * #r%j ]~a$oǔ'AYڕFYuFWmGaU"d:ԍ3hnmX~_uQV၇<ēXt,*d0OȵYѥ"mURjGo?{To_Ώ6nYOB@S=fb= ȾÁ(|`pXҗ&#yBݲ#ӝ)d)`ǜ1a䶤~*pDIMd[Vz@dދjɗ[eyil2`P<_-}ܬӠ|.f/逫^9VlJGW'%?C4jpSff)9o)ߏ>2whtbvq*8EOMrQYPJv|' oz$«?x}A"IwBhċ/?@{61\,=<'%$S'(/U= '9H\_\xadМ׶Orу9Eg] 8h 8Kpr7pJѰ9'' B3xjq0: 6m!'H/D\ZWsý4Ћor;&6 9(t4פ%㡙AGFA2+i[_#m"GF PfY1$i9בY~Å32sDo1MS~V/MO/먩jTwPX'4x2?۠z8`76N@SltfIvAǶ"QpBPlb13Sї1&k0.0QG9>&/_n'Ӈ(é$*Rdn>lvEDsHwAŏ›0uӒ%{dϛ̘F 9l0wrLn]% n??骾VɗF-8S9 k=-ު6Wq\^etӅ`>(eTDaxQ 5en1fD ri rU֮fN$|VD\[W@lX*sqk"9&\70|B1t3n|$l.%(ڡ&5Cf65 ]F*~t"BT/ē)c^+HHC7b6tujN$MI+7:o,O^LiJh>T6Ehg>NXӁo1o+ԧ0R\N1XN@D7evHyo?m!jh"z*|]QoI- >.&ڥʛOJ5KbnJG+c*x<ުNO-ݝf92#nqj߾:_bv=@1Jh&7ǽ7[8QT9qP2-"2á%y'nQH~H3NWJ;$\\+,FҬK|Y9|+x#ƣ{C,7ʶׯ/$ߤoE{b§vprR>ߑdp07+t+z'RAe='$;ЁqeCl9@(Ǒ3Fxo¹D~Eyی/%S1"fJ [>t/q@짪"r9k7(TYWayԹX4+ШJ/9|) l !B<ϞL} Ncz4trQha ,ZnuD I{7kK(BIxQb*1~9*}]\^ Um i%goؠpS29\h*Ʌá.Ia#*^&<).b˻2~*#Dzj0V97ʿG=0gܠ{N-ڡoܓZsg¼p@ P@ZCUв XFRZ>g:wG3>X_yURz֤Oյ ҅$aw]e7+& 4ƙvA}̋r\jqjŽ06* jC&%Ѵi^CR>5!bܘ%#s-uv5ZZط ieƟKp(@`[ьtY?DN쿢iH.)OM=}ggUͩ81CiH]q"3ÄȬ8V# zMڞ")'1bP!ZFvf}ql.Уd#-!{{O` 0Bv5B!i J@3hzl:/rD:pqkq }Ik.M5hb̛KmsNxԠA9pRDOU 9ɮʠ3-Հ xNLD8G챣&@mkVyϫ Y"+ɗ`.C|Ps -}fœwN+S;r"WgAQB!&^:)/jlzRr1)#e {4,Q+*wl,q.V'X`$taJP#u۷]vv9k/~e:$0Tb==if9Z{dhozZ:۞iƧ|ÒE3+Aqm((@ѡlgˁF NE+PczGaҕZR<|'b* [҄/R ͷʥ"\qu/\`̈́云\D}QaR>$cV\\5IFF4, 2sHN'PbPJd_9{[MuP`dz2n}My`i\5˿ZYz;%u~ⴴO 6ݩkᅲǼf;_"@ ޡTA2#M:8b?/r槥6'~th`CUL&DL/2ԌBW(iLT rѤkTQ#Jik2` 4Gi|UGIsoLmI/93C x><b֭EK}ٓ 6d\DJ^]7Ŋ [hll&NaMoZHt7: )lJx5){.ˮGTM4A -A$y5tu-C`b@qrQsxA,̰.b^LßȤ}ggSal,&ѻ%)<>$u]Cq#^+(xcr;ʍPk2F"Ouc-0:N8lS\:BY[\\7pAu[`P0$U>H,BW!OMm䁉;g/s{[N^&doTEVBՙmE  /@11W lcՕG8@dioᳫZڄVdl*7V)eV&~NrϗOm9] W< hs1+uք9&6'1b/)h'w.3Ej˟#C,-2ǦFJ4Րr n=U]SAB:܊6/ X%.A[eSwhR^a;?~+!$hc,f* Jγh }B-VHuxXSq Xxbe̼@*̛(r|tiLRL7L=C">%{k7nȑ(ӉK}q|q"B]KDq:bY(+SH68ͥe˅ZiX-SFɩ|F5wPwAS|!2$ x7XI'"nبo"+|h49N{v_^6L߰+}$uDU; R;YdO?ZGi('%$oC# : ;\5wLL ,k){7peN0Zc|IGjtEy(IȏUq#™0@ޢ] z3ka7袮ɬY6QfxSFvNkZp.F\I)'"?漓; NAIУt|V?y2خRaYv%mNl{fxw0**4%.I*Qd1N&\H[cEme}.NQq ,E*UzE5cp^l6W\q?#YήoQAixed;\ 2*mE=2~ݕl7o)~ϡ2q I W,ש1 u^u]!&cK/kΒŜH+Q/o*)"1-o%1El {,|.js u4}ROƼxd\칶Y3J[=ѳK8.s=֕{?U<\XRrLPͽ.K|"zHkp# ʈKCҗ5pb &cKH.ϓ+/&i4K1p"^0,s\9e7R2ӧ>MN jIp [xʋ(F-–l>0 ap"C̪םYO0Kuگ5#?2k4}5x^Vp_BQ0?tҨx` ;."{`QNs2r4^$ZA+ެ_bȿY+s1i6.nx019~GeU[8?P&Fَ9:V0wŠSrX8J!5-B8-m%u73L;#Om.O\Ԗg ,bVJo>aTqAEs#·Oc01GsaI~(K[σzrnx2D|ы6׫W(BעϹ"cKJ Ҹ3G _ 4\> 4|P~|]? (僎Gho$g!_xFK^\s^8_5fmE̯_e;=l؄ͮvrP̟=~x*Y@}@]z2c/y|LXY~opwǐ Gʝb}޲PtM86%_ ÜWna a 9Nڎ>Xݶv/>*T2<)RpɛP&j0{OG}&׶Z:99Y+`ܳ*PG!@ ?""eIȩuJrf~ j6 Ú v<ꞠsU0Z!+,<mN[ &4Ml"HKQJ%p̙ПAtMp"bgcc&ã{+ϛ 'CjV &.64K_q&~KO7nnG>f`P⟂?_o"),{-$ˢ:Icԝ$75 ?)~XV^00H: ;@x177dȆ3M8/q8:VƝP. CELs&GM!mlUGI 'kQe =SOq qg =M(c):hy4ԬpтKǏ?dao`{Ɓ~=8!* Y?^uzȮg~1tSr{>Fg} B^/3̟,f2Hӓ[eŘi^ Po1F%&<jd5jXI9SkȚVƮ)QUTcӢ:kFDLyBet R? plDeQ˨;EZ/ ㆧ<2~7<탿Fb dJ-S PRmT_1Sؗ:$mlDƍAj BG9۰@r<|&Njw&͹Rsd䲄,pO껿׏^;K5dO o/Yy#&IqrysS.z1SCĤ#Xwlc|KL;w%җ#Hh1kZ`E\i!$B' eO'X3/a9ÉOsqzbu+4mJp8U\#]OzEX prkJ*T;|1q@GnG+3?YAKS-G»`o^/blNmbqz =pcp$O%bH-зBL73W~!l(d+Tq'VG qH-dio;)aƢ0zGTZیHA0^|ÙGQcLube7&F 'jh|9S$D;rۉB||d\-D&erDQD8 э&`E]~JH}l'dzHw$ ݈zk}9iX๝%YL!! D.}Nd:3IBBhL%.՛bdn8WFZLXQ Jo3 S:S(b>]̩VC-fp$C>Bbg2*΀hF*%RW;rQ\h,8vtqʟTᒌ1+Ӊ7s?*ӺUɛ./¿Ou"wO Sˏ I:e7ڰ./AL(]Dp ou 4[bL.ƔVT*—OO5;(ʿc0( O̯4S_L ("?҈b.Oe::鹜]ZqWt^lP񐬄0:1 \غ؇S1,׌#P>4oMuQ48RW8C&ޮ";]R% PՑr!!Ss!|j\J<} RtQS~JqQO B^S[ɔ#,XsT#[}" ##Ig7O_􎔿kx.zkuIq$~'sބ=ĘEzq|UEJ@+s?c*xhtYQ?l?Y|?5;Ȗ]'ʽ 4? q~z~z@svBCG})jⱓ-g;Rm0D5I$ŋJ9ȝcCfBJ|㐌5 y$IꚢO 'o&S _ۈڤR| QP7:Jkp `*Ьrnoʺ>xVV~aWV|.K1MZ0pPR K~VJz%Z(  }aT5tƀf|#P>u6Luip%D8+o*wvi=;&`y_Ouƾ/q3KQhJ&v^)KNxwh9-N繵r?\AD/0Ger$Նk4z}bq,Ny+RU%zpMRITU1]z* d|[.}p%WP87)w\ IQ3),vLѦMzii v6A!3d7UW  : 3o² g/nuXQƸpqKV3}'TlnrCBŘڲS1aTBS$>dݝ'@LFCz}V(1[v^ )媧UTv+DkH|0d]N?Y@śAyufKק8SN~~ ܲXs.DqJ|teuVu$L4>W9kނaց{ ҅;xgNnxw{wq{ڡݓG]Q$q<%VH, -N?GK4{h׌e;~u&\͂-DO~^pKLQ2[όy&cf&>k޳V"Q\L([" *}PJhZmkmjW)B/vaWFN7}lz1 CجCc̹3:^Pc2A2]OW|wYd`Bi!MT8[}'ڲ@A2u0|;0͟T5_`AqIހkPԗy{Eq@rxm3xpCp$̼RTurC5,Øm5Dw^&p>%3#"dj JJ4LbdN(^d%/wP%ԏۇyY"SsN%0ΕE/U4l`ԂZA@-z SH̪?=u\Qh=Ny7qf꒘h2D}ɬ&Sbxe6qv,ۃńf5q0I7g2O< X%W=h%)6JۈRsLC1Ɓ.(B7Hyh [;QiynJmķjHBHQKaCpa}-XqbTXjQ[ݱ 9t&]mmm&N%vX2f&ӑ/Z˫VCmȩR@;HE?\ijͨ8F#sVMnkUPhj$nD3bh,y2 yC=YJ+vƎ)½̅ ZzW ௜G}Œ*/TzJ'^rvtǛd+4|sE*ℐL̤jFc&\/:vlt^|&T!y؅g_|wKV>~+S-u cf,ɏz LqNJ)Lo(ßND_!B@$KgX|G7&WIрjQBtOjդMf>/ҽ zo<|t{&/3ï_=ou XK~x=v|O㒰 ^5z ؋߆ݠRc8 =T"IHBCY"J1YpCn2C23ZdXBTvDzl,}Ӹ9 *-1d WRdرɮ[ kVk-R%0A0g,fVZ' ̨šf{@3iw}|&DF7l@V&̚Ҟ`Ze/UJ80k_qu?w҄m+/$Q8-d jed U56Asa-2mA|%Gr}µ:&'\´e;jM:E[%ʘ<r60yɌhCH1KCMDoXUOD7yypZ紋f+l79U뀬a};';(eeY 1|5o5< 3!&V'ͅis\Uݺ@gLs ww[rT9ԙȡl䩜yhseKwm SEk`~>ܽr0{6y.qe98-}*rZj]E&v2UadʿUWqD\-eN}{~Fc: Aٰڀ{.]iB+ºvMWw[WgeaC:;QuE>8^T%"aVlq^yg}-֙n\ M0r5̏EhAi[-)a2cJH#@ ՜-dϐ2T_r^ˉ@QC0fd7??ѠChrpګ&fRV"ٴ,假9%!ۉi>,= 睃f*Z}Z&RKӰ9"tJ"v YmYEsJMR`0|bD)E--Zʃ3ǍW J+JnӨlɮ\F~7 att1S{AVZe;pR{hҪ :CSJrȤmdNڜ_h@ (Ic,:7s"̺t./tOsEoa'PpSB'IІ8?\B3t!*Nj7!f$r XW0 ծ+_B[[J؃ajmPd &QNoܪD0)^1qT1a'/gSeTwt^FSnʪ 42RaX7XVj*Vrya)1F6ݢ+::Xտ!Tyt O8ב )8F6r`Y`Q#"t-JR^Vnm.<[Д[Nc6 4W g$o[,?gu[/p}gfW]I-Wo^/ř|dk $5 E0q]pPno6t{oyvl"1CÈ҈;o-, bJe1~& x0'h1ٮ+>5Pj;&Q^dGT})*}8"yİzYZ ;\#]FU* 0 ]fh JQ+Du8%='v6$V}$*iq H|A|'FHg#A4FW0Sޓ#$ɋSrby7G/,=1VwtH SYF:p쎂Ec480y64c(2:㧉~'#J#IJ$,2K6G% ˻1z*_~MmJL\*\F^X&F{˶EBl[Ӱ3 &dKW1Ƥ,X&6Uk%ȫao.n<UbPtI,UL 'tO1nhSSWg/e.nIoʜbhEpL^J >R]+R.Ή% :Z3 [eKulwfURXRtag΂('2/ *nQQU'z~^GD`&?c0 WUc11#b9+99+}DJ te;vg;Ʒ<63!,o$^_18'"1Q5;%?SHjpNlq4ϯNJMJ2X5}7*L!u^$Btǘ~ r"E]%%pwh6i*9,u/eQ*H3Q\9N>*'3#\KMAQژFAbeRHm}H+qHUuOf ~_E'uuzi3uz9l=ZGGiA<}׏v;iuEcT9Nr879p*㣢;v"v(ISeBRFPR.,R~@SEP Ha#"[]t,e PEZ{kRzzpjs.<"\rƐ˅^4, )-GZIQ$D|WIBzQ_UlL6}W\u{;[L0z@~^૫R!qr ͒'!VaPoV4O+%&>Z3VW~fįr)5L#gAGX\)~jǘ5chՏ[٨vɝߚ̀g eY-L5󞰷|$aFHscHsN5,Ht=[8r2E9e _x ̢t,1k?U-m3cf !93Ȕ4z,u9ȹV_ˊdY;N1 ;-Sz )אmgH]OJTxԸΰD TRllYEU.fO38zd̐.DHt)y,N0Œ3$SE/ 0Y[ 72o䈟Ibi[yrXaY;2Gxl~U,9#% 3]4!y6D vUi+S'^pXJi߲t 3rE XPpο4(a>J#NJvtyə9)P9|{v_]Eʞ1U<>j ]dK4QTc'5iUyc][| D8GwJKH+CJp7='uc#Z}X?IWx'a2ȝ*Z 98#P F&ٙG7V/i5C,VXZe%˥rفIti K-:I3`h}B&ìg\mMV|I1}ĖGp)x 6rE &Yӽwvw6M׍+{{=}.f~pq7z( uӯwqͿ-ޭj}o'rI<%-WLJݚ vNR%ݰ?8O 2{+eaG+apexNڭ6-z6Kh x\,դ$7 UFG777;؝dv1LeH,bݝwؙh9~I:$6FAXAC6O1O86 tJΒDCԳ( d1D[rE+l\'C1G}u 쁋θ#[9{T/oo'B2HMN'@[B9zrށQ? ֔VJL. f:hZQat>֊`V5 6&q|x hޏBe7=NIE)bbPkL6pq4q[I82?mq|dⰥ5=taj+3b3boQ2K^k,)+Śl[;osBIAtAf$bSp8Y7dtq nԘɖA5Ч' gr4L œ ]([kw=A҄,ȩf8 Z]`^;}il5k43wT?SB,Q?}M4>4]O{fFE-xv N۽uA^3Kmk~4;՟[4Vf Äρa;gn3=5ZzـGu S͗^=cGiai۝n ?;n򬧯at`,tϚ-, w^F0nΡ!|  k ,<-lϺV ^ۍ.mv^%(cFW0yEl2U|~Ђt_pkaBS ^5™ W0=) @Y{N/[/MƑ^M^ بӿw~_anooP8q#\ Ws;ʏKan#\^Rk^r;ͦqC"px"5tye_̧p;m%/Z|Z WtKG dcy7M6?/ɍbX& b}+đgGv~}}.\]!{K(tmP>mϼÐ{v=rGfs-V~ڃuK $wT>ߝ,P~OJhOsJֳȜy_+ͫrXy{mqmҮ3__҃:l҇K ^6syiFQKyܗ-?8>9in~)N.#m:b%nnK Ts`./KVɄJEF w%O3(G5{8%ԡqn ג?0qHsX2ߗu4˗,8(u:w]A"͇X (L`ҾH- cGݶNvþ2.&26ShXøN=3;*}Sᾛ>;uCgQ0M}Ӣږ48 FΪܳ-|\R\8۞9Zy8 i"5%6ucyߦ | & 4Y4!FhiEĽQap>)V(`kNfT#As >gE2/2m皙q;1=h&{g[t9XkY扲3]FBy6Ώ=}v:5"mI/fʛ} ޵+v9D>3U ]\mm5p7JiXbQbےukTI#8KI]5;p:49+D5۳06 TOqEѰ fbZ5OI7!Qw @;%)d j>r;t~v;5|D:1SʁGRwN'{A2 %0~4S67ž{zq^z}$t$E|v 5?ЋYfUh-({}` ~R _[IH [;Qe{y|s4P7;'5nQR3k07J_ N'@䋄UB5f:ySml}-xVU˺Wq4Κ]E!fv1Y^D%;:{w0 ӒBT&Ƿ*eLV̠0 TL^ -(|'KVU(/SMMG;;YO'&#"CC?XDqQZ> yi?US+m6S8!lR8ۧ u/^_bz}%KחX/^_bz !/PϜ{93t2]4-V,]e?o7}1֤k*r𑨧 vLJJ{-⸈{o_r_߄?>헿=}S!akw=\Ll ޢfzgOj񝷅P-$iEP6rWv3:Ŀ<1.xy'5>2P| OU8,ۧ=XƋ=2Ws=rUzeJ<=\yx |Wfq>+Yx0Yくs/q xy-;rZwtFe|/c?Wm^J7 |x+Bȃ2XLXij,XԁʺO^[:1YEс*|\9_~wǂe/k|X?sJ<VxdV|c =}<]_{{װ{<#.^&qwsz|]ع^u^_\k1wYZ/WG:s{Bo=ׯOm2\^ud<8lX489wQl~Pl9!'NW'Qq}?k&;9aBsσxYҘ<+ ZSB;c9LҠս^)y:|G<%_Oo4$zb Lȉ[i$'aT6%xp>!v]QwedYCoP KuXp_ѡ=jMV̦n+ wT4|w$NtÿzFF-\!:v'u|.^z4E2T?MuO{`hMD,YLɛ׍Ogsis>=#1mha6&F(R0(ILAùpɒTLMZffE5eo]@jEt,;AoLgʷ*s0PZ}Wb,PX/:K05f, 4p3'O5U5F0n>@dTJ?|4ZnMy=5[% @  Y<Ձ# |xLw VbF)Hs.K-9^΂fK#6c dŸ-e>#絚[5̿!V~%\axbtʰN PCExmI|'uFi2I$V,<1\*d6k@V.X6+ 'EogՉ<:̻jNd11|hdX% Ud#2;Z# <S*~GYL1V3j8˳r%[zN]@}L6Q-n K͜ }{y+ 4e3@S*+,qdGpp!yvZ-[/3PrKd~zH.pؖY-]B)8Uԡ_;X-جiEW e(\)%+趏Qqޗ;фD%[[9fVs6fT<GZ^5=:J8v{N)bui7bR:zc(JkK)_W2"vfUËh .X1NQQ+S-x(vdž3 w* fU餇?`|8^y` ֯~U>9\{?N㸝Þbw2 V:U ܬ7 \hwN7qa͸ڨt Hkʤ >YE:cra>SJH7_`o\ _@W#W!o#,V4_E-+ "=)vp6;ɳ)wl98%4Ef7yepoTĽ,Y!ypW0qa&Qr|&&2UpLMC@k\lK^UǂyO|BTqms{}V>҂\>ę_M+P!H6C<8!f9j)rUvʂtX/Q„CMCpۆXD x1LrDP =E6Jxx-&?~8ˁuuk?FN68Dm } e g(짰Y3 Ku^5LA .)6ʣ1X6&q3ϻ?FyW=#x./wwQIξVE&ifHfFѐ5@d1. ƴ$0P! h(EaܴhΰxHp_`q8- >!k/9S$m|[a)\)45NhƷlqHY; /LWqvF:Zvk[G6luM5V s?܎#Cgs~>0Mu\9*8 Fq`T {4<c'_ D{Li~)xW==p)=apgL۟w^y!Pޔe uzlŹwZnf *ǐr+lҌ:v1mr$2d%Z" bR$0SjS vNdL!T2c3!ބ9OZẌ.a5t5MǫU٬1@sJVDhG'eR%OuKݧ_OM?U̬es+=硸O WX<.:uprݽ wcFs[d}C|鸂RG_cgFoc`sO 22ݟ'}2?Me.+U56ԒB+CuO/&&(UF@8R΋n$r𣣱]gޚae3]yy"]s s ʂ<|- v"3p(j }O62uG# y -K0yP{ W$t dMQh^x!pY h+Y1d˜$ۊ @޾c8g_67߇O'MQ_: ϺM|gJؾ|]~5X|č|/aWC]Q|g{?,+q>JS=ǸB3p##GxyK>y\yXSfu8h C^-Ŧa?ay4$iQJ׍X Ÿb7m!toR,JyJE 'tqyb vޚ'[tɰXf_C+Fn)cщ`i9@Gm8֯) fo'M$a4WGσiA{R.Eh,KNY.#Gn;:Y?Rc N̗RjYǾ|0'ޘ8{aG z~uB2;3F.*!Xc$2%^]g#= ^{K'C~eـ#0~h4 `3įC ǛP= 1z'a<H g `vE0̒bUջP7@WŬS"}oE#*/?M s(, /XKDXWO{%MЪ ^n.^+a="_og$iۿٛE ]<"(Ci=i_p9<YXocy[#G˫'Mw5jg%Pn|285.5dHوD8{&lK7>0*Yop?$fE0ǁWk(٥kJ#JfUHj މvVsZ ExHV 8gh>{?*^rk5-kjI*9#l"WMLCs'8 Kb4zYSy)`1Y4SKADߚ\  ҏ8-;G ɒB τfzt xE_ĵ3yZi-hv%3=r" Q\~m& jk3>N,, BќP9B$rO0.>蟺mE*9 ůOeʑ.z='` B pnL\I^ĶENM5 ?F&pZWnhChg#O<obL P~8('Vrc¡`?YDwZ]Vx0/kcP:͝|fv[@"[$B4[*1iSDUQ_NįUT=I2q?Чn<^|Ŀ* qؔZ-xY u4ՙsPtE4kYGZt5AVQp,IYx,T YNW-?*pG==rwMل-bAQ)q0oN<,O@>ne$1/P y lsr4q yq\R'WU Zox(\/7>g.5J_t?$>^ψW 9xܬc1<֝?8{'zj=漱1ފxհ|O><ŰE΋,&Ig,x\?N¡W(L ka~cz7ӓ"T=CFe" T|! Jgk6rI(}-N=Qcr0O9wF8U%!h|tR"*##ׇ]4jCH§,@c, rCֽ}q cf`9RfҪp)g"uhK/Pr3Zf/pK \ ټP0 DzOK\<T=Ia4d- 3T"h^W\=>chJٌZŨVEHXS e' 5A +4 V(MžD0׀.Ur$YF2_\} ן{#z$e?(e(@ew73` E2.=rEHɀr}x=݃߯U{V{}DeYj :9t'0- JڬpzQ S~ǔZr;"o 5"Y‰z&B 4[HJBFbVYBİn X3礌!Tܢ7=2uLҪh>kOp#e,R^pITc͝./@w.D"]0uC{SoBxVn\*,z >t6VƅOfOP.Ӭ8$dY0Kr+-ͫ\[Lԕ+"yD3nwWxFqIӷvǷר~2LH_?/7wS*OȪZXYPZ/»k-bUOk>' .A[^'E3]#ѐ=Q}9,}Qmoi`Vx1Lգ1a8fETnZkysJVB;z:~Qj{ci|E& 6DžXyO̮ž$+C5tWєM*S1ҹ`r|V $oʟT$ԨIm3%* 5XէqItwϛ"JScğ J,nYVo0A!v#=ʼn6;2IfIPlVMUm~JC5'HpoјMN$A>e [O,P4+1'?,Hۿݵr,br6\s}]8?o6v\O8Mvga))>B瘠X+֏KKZKCm0c'3R[a֍m!]emFI?"wT"֡3ISٵ| W+JVyVPax 6ͲC&ǭ^4hۧ^:O zF-v k*SL1EWE]AI̤$B l W =պy7=&+e O&"t=o ?3cl ^*(V8}֭W_r”h{u,<miL9YR-7hqTRZR"ǔ4  $g茭6N^ uW4ljE=|- qeʤz˛:l/LU.X~*\N|>Lyh.tw#/1 kSp7WR`q%1=Gm--+ ̞Jun4Q~oKN |W:wwfi4O[:~ خ{ڻ\͵_>Boz\z\傉OU(s@& sx̧;!f' |[ɵf;ȑ,Fr#ȩr; Ci4ٮ58T5H(1fl_4bVմJ/7ٴ^-P{Իlo9S›bv՞Tr9'h ֪it c}}]Mg8OQp"e+N_u ^N"7^wCYJN>rO ^m~:6Y룴^!gE7؋`xH$z:姓2*5-V`G^|sN~ȓ֋OoTԵt YH7leT+g [葓ʓ*=W$:ƥ>>\a[(䎿k@ p!FcbQ0xL mlKprF%-.oM-Hx+B<5ԣç6 #+q{  *Ci,m??^[Um|Zپ ((xx0LH/(xp.55ܕy$Old;ÁW|Q0WR]`W R jWƄLVP> S"F@y>bMbVs;oqJ@2 P2򧝷0/]DA'۳Ff(;Mft(:%o!r~IJ 0V] ;PzWQ D0o i+pȊbb*oɥ!E[z WS,t 4 HPdiXhUaJ@hp&DbNTt6muB.Qxl[1?'e"ST)MYRZ',?fr|>p/ǸLTY&f(&C"vxvb ǔp"),J ;"̀n&?"7KmJi䒻5ÞZ_ 4"UX%CUv/_xiU6IDP֪ajòt_hӝFU*h1Fi@~$oO]$ROdK4TE1/^>%\a4ݿKb(4p:oU tRudQEЎ%z!3m6KJK(: U%((RZ]ctR-ar'|@QLe% w'ӄ+׫ErZwpz5N[SOd6xh(;$M߮oGj/H|>a >0ceZ#Q51W_t ߪJL4yMOa6;pieeWTk*cʿz;\ȕe$r.RB+V8TA5`j͔&l%#: )Yٟ7yd?cV'Nq iߓgHjuL?ޒF?%'gȦa]T3NŪp\Y RIU*f 3KejFIj^qO:b/>Xm ΣU@8o4K*?AbOh 1~Y2FhTpYvEfXd1ee%̙܆J! ?d)$kRH,oBR×b{# sVvͬLT/~Zq7Ip@@z"oMO|J$DNBktEχNۏ^G(b9RL*Gfa)R4qࡦֈD{M1KW*.rˀ |NO㛿? V/f|vZV!f:)Q?cicI憯m378RJFHKQz|Y)|qszx UCUCU8oMN/XEZ+VZmlR?tغJ}WwgP/ֿ: ݇ W{"rw_>ҟ@ɺ{!{j5KW :Tes=_ę i8v>Gkq_J!`v}gv%Rj+UX.gu 7utd/HB'H- 3-nOxF g487<м%]I-g|5AA}82JrSD7R]hZ7'HrCahN#FpO*7r`wвU6k2 gC(n{^`YKL@Wu8S|x,.dX*e E!&e fc7j+ :yȫ:>!jeܞ.gw]5Wn40FA>1Y%MYe O{Dz<,\VeՒ mתY[y51 X7ks7>ـlwTxm>ŸoSΑ̢t1҅' *x{'v@|fSInFҥ KXspH8&g\gfym].hs;"UnY:d/oo[J4u\s 7Nj4he-UI@Ŗ+Y^qdky*J⦫!Rhti|m:9Ow:W_tly *$x~ɘK7,`=Kl*m9(řt2pX5Lf{ OB0|zᄇ̻ݞuB~_}ugʿzvvؿXw7xQ]bYPӉ3cQonex;HL|$aǹi)֖Di*<2yHr7pͿ_ZA Cb[6e\.V0~  S%ra6]\qE\}@($-fE7>>ө8 w}g;_v<b} G:YCxc\Ni)Qƻxk禗"\0f+M {Vˏs7>]w!>,sDB\ +cV̧^!\2T9 Y~1{I]Qjjuگs^(H*Sa{ӎ{hq41w]P{ ejmғV;)L6Cyo[ w2i)5 i,K6g0TN-4nڀ0št(P`#@h{uWa@*vBxUbkPCSmJF>]Ҏ䁷^zgō%ޝ:G32~ L3Jj?̲FGn5c!8S+gDF:ț\ꏑrMy٬!2yqF\!4!RoUkx6Hu#[UwwEwˁߔez;Hrs{2Fn9BIk(fOɲtIwDb&YkF"|U8]s,􃠍R+?`d1Q<(dX`59GF$e$Y\t?\@N&|-aYcŚ JQx*}QHV+Ka1P83t9JnUMQu!>"G : @vz-hGg@s/^ ~qg>V|xfNDfW |q;@GԀ| oR3z&7|kd Hg UK\Z.* sg˱\T`3S)-ǔ@&u쿫Ē(YaVj}^`w QhI-w;Kё}BF'plah|yf&Ř`{ {🹻З J)b.&~Qy<p+%QhU'#;1P*zMǖƘ?X9,E_nY<,u!uaܔ᭩9R ~ K.%pU Zf@GO`"C"Ii=7B iWKwҠ@=!D.&dND+y(ɛh,7|a-7+cWGT0E($5/` ??v)V5hwEiP@'p`զ}~(c4M`]h|'=u aI]'mIJY 0R(zlDuaL@i#RRi(˘,N4f@6#2| }\;q dFׂ|4az1ޑޫB:>7F"A6O_N܁ٗ X3"w[MPZO-dOVR B7|h7{z}~}[u1)٭ٮ4[e|Ο7DE`[,qwi,Wg|f fA.T4B(\kR}{"n"ѵT$w^&b J:$s ʉT"5'11qC"E4b!(Oqp{ B`nq7QVyN_WK..HBWip|̷ǭl,Cۀ&W?!RFpM2 ]E_\DQɏB&Q4d#zdžL,aR0݈z"3f2{EZ=*H0Vu"D>@I(c:/QyiJ`*Jia[c"?NUBWQ|8Z#Uū{J =6;8'ȃC u~vD{)=b_~Ff@io>wVRd;Dq1kp0 }V8A n,Wp6s~lEHu<ؑV)W.܌GGoԍ3Ƴd9܍&t`ol-n ζO-02u㱠*bR^.Hq_#471Qj"KC&rnk9&.~J@,YuU:헭"\5G2!$=^ OO;ʾ qjXL/ݗYi% ѣg xTc"fym>b"ڢ ,W JժVh1Mz]uXRWX3@+Zd7Y)c>\E;$H,9v)${QpܴT̪|Y<ω+ <_`d P#<%8PQ@>񩥀\ T&GEsDrxg.K ?wGDkZZJآ1 ۜn"R- >wuDq/07PW*t$@w'sr |_pyɐه 'mTi9~ <۸p|.>Y/%8(ݑkT\mxČ,[-hإD{:ÈI퇘eEs,xRJ!w޲b,Z"y;NhQ6X0_I#@sR.NDK*X#,QSnUCV H*\Q'wݯ87^;`0>A>F|/yw><"+tkxv)bVxrIJ/Q s6FzF nWO\(}5OihR*H3x_kЩۘ~i:1 %zf6ڱ` EBrg2/A#ҫA3ć2^G<@K9?Mx6_=f5Hk}.d>d)3ջs o u!f۲1sfq9K' 4\DɆB>`rHWU 9,׆F^G[Sh_k;ڰv2S~z(F"X̸SM7aO12Wzdg}{A=t7Z{I'챫o2e}AăY]5AvEЦF?j,}f׺d=ޕ քTE,.șj0^n}9!w- Y:gDXG=I/Io@Gnnnv;QHj4$)Wg)03{m|4F,)c9 QD#k )HF`ePC݆# tJQ8D 䚌Fc,f~'/plNFHIb Ԫ(w ANR8u4Y!HC kB9zV7K$+6_X.ɧq_GVr`Z oN_Ԃg ['4k8'&@՟[4Vf ÄϏs6S=':蠃x 4hm >v>(U«2{5 x`k|x,To  *Zb ׋-h1LV濍é%+F84vzES9jb r,IsL61gSȆ6?d_0NvF?f~g@g?ަ!/J$IKc~z=C?f_.&O L/4,WID~e3O]hP5Z]`'=p$,hhGDqPj8bPJG˅t'M8/zJĎBowwv 8z+8 'p+8H<*F 9D! F0QP; _y|-8.GnMG gQ*jfpWd1%Fpx!$yraQT~BW{K^U {@֫dIV=q;_)32<_}+l=G#y;A]JH6LxAiSxTi vI4k1 ކ8YZh3t4Β1E"RWнeZqֶIm#ᄿa:kOӳ)P4|W {W3jh>?y=,?Nhnbؒ?/ؘzMW'Z *h:}AV/LB(1<Fw'c¿ÓαP I~eAiQ Yyz~j֬5EncA2f0"5֜_Csx¥gBT(PQT^[@k$VrQZN8%rdSwoYj)=7b$?(CpLf $U>H-q, ibn?^`TsJmٔN더uYrx>n2~".{hvjJ`f5xyCU)Dcf k,!bҘy̰_XѵUW g#-.a t뿮ًg27X $/+O;5/_w*qN,rohL; 9ӿ-%'Gg :2gXYlb1/\+^w/2ՄR.X@p(vO$͎AW4UID ɡx,F<9F%iR~U HrdSRsY-jae奱"mL:o[-=+yk=!N"<%;ΩNBG`F`18}$.%lgꡠV4BZ a% uP>žx;o+-@OZſtB{D ZAI}CVeߠTCbOIPGB@ĐRg웦6Be%%- l7`r&cã&ʕ貗 GkwUy2!5 = 'MVwabKC8d8zRUu YN)# ȳ**^^І&Wppi4X9: )\_I51oD,fPczy .C}*:WJ#YHg rj$eHBBYSrqXkgd8 WT;NJԹ%Gz.Ŧdأ@a!ё`μfj,Kn>dy!X!ș)cP8 &0&kjkذb =qhY6bsyD\+E{IHe,7YyY)ʶ4?:T>Y՗!+X'ÿg+Zd1fv\Lief @w_i&b2UQPSn-%^l:ôaJvl=yWrW :JJZv Y -zSDe-'%~x԰` p8 ~$bV#ˣN47 r١DeU+i#ɲL)jh'/< 7|<_`8KL|#V` y)Q4ݯwЭhgW6NH-!sV`ziF*%:}ަ]!q=}, bc6$#Bb]gz&4S투Bۚ;Dv*gT̰ǗGƼewA VN(/]CqխA,Ue*obځ]x=+B7S)=tMNI6̸9Gǀ092:;ee5;-FsdVZHT!XPfFQ,˽-VcAsڦW$Sڬ$gF]'ųs'j+ԻEl~ :٣ 9|S@Ei sj«+=Z:>W+R~x39 D fAE}L_@J4Ho֟1zG%&һ#-r=^]ek/+V<.gy R}E&+QR(RR߳! QͯU:~.&/[t/eۂt֊ ^UQ3ZW31kv/8.Lnu gP_lzxv:硚O,'#׏Qz]^Uf+aX!P lć@,]؎[KFP\}&9W΁`ddIA*iU$yk !AJ5ٿ Ҁr`# ̫(H1Hqw$8neXؕ0⟸$a+'HDː`/.bm,BSZm'эAUJ$\W7fP_EMp} -{_ܹgRۅoZ ߙQ1݉RRLlŴ8Ϟ,/g/q»Qubъ5dyC܄]9{!'sʜg%ޏahFο-1",[j+1 eTεT ȨܜRB\=ow~XFjP)_^O5O S*O g-i,ܸ"uYf| k} ߉mbJoD >QYjڻƈ6(;+0hlP+==j ]TG-,Lh[Ѿ0|a ‚5J6[@C>cYRbz*=ފQۚ$wU@JQLW! ҤZӺȌGB0ڎ ( C?YVrڊ ૢR!gEDs ~w4 x(LAcL1Uj 0Pn2sLbX*0dd!G2 5D'JrdƌIm/JuLKA%C$k*3( RXU_X <Ĕ)C{-?l`l'VΜ~$pdDnDjPUYqR1naBIi {UI*V~`&v>5&j&rF;W;$G!iX:mBQ%wmٜK7:7?<$uߺyJ0Qڸ)pQf3JgR]f3WXGQlN0t8uٵN,Qp9:h);xZQǡم/2~K$.ڜ(:ǚ5 {g*ԮQVВB5BYàQ'"UJ %杨8$Utc蜐(K և ">ou]G,& deb藳7m>Ph+f*'ԷH0hL $ KQT`CV̀_ҏĩ"?SM+Neç?M9\ZvWdn\_dHv=S`?/v1p+)/%87\XG|eu-bކ#Xjvu³7ώ~ '2gwLX)Jز_rj[lCҋJ5i{uB '?m2F5DiR'ź?WAW <C`,W{JCwT[׋~Z%~:yZ"$qdFV&o43?ݳHR՗49=-vʟ~JA3IU#N)yd#O-P^OI1's-(FeudJ^oҨLlW5<6>Fhw WyrbK+' sLl)60zf/ϙ 0'WLw4I>nmbAH&)Kl#r݇(TcJ#tlЯ]Q[QcÇa29?$ZG/g_.b"٘<]_%yu)GTCu_k*$k2 e*4%&p\T e Fҧ t(;\I\m{8?\*e#Gȼg]]KBb$+ XX|PR篲咥4\M˩mt>j;:l!ߝD)m2IbL(qަ+aʀ̇uh"?'q:xxpŜ ;+T`9sE ,;oA'+@7֓IIIsc$:pFGf %w<6VB@d`Zo#S)S+K $=(fN>%J̨#]X#УtV?yrXm_f6;d;6|EGlR>TZ|O@BP)%N`? Cޜ\H[ZaHe,#NQqBZ EԜrMy5c^l6PC ׷Xlp'D;AVhg6*]`9]I}y^W?99^5ia#*yF˕Dj%WGrh4ɋfj*"@;!'NZJSfqSii,UQ7l$vD+=bۖ@r5Pꤰy}^W>* OWrլizcY̴ȳ{,#+/%Iҡ5`)%4a0I&ۦ "Sɹ!K)=o\Rl -ZFMn"-`uc`,57IRjce7rr '2HKV.J5 ]d5AV\Zs:$BĿ MpuKo> œuD=QK E-A=F9ۧA2, (}kb{Xеh|:d,t(s7sjW`,]xtEMq{p.EΓew~ 㔽(ERYu}K.a_(z_ J *krxZR[Q'(/0gGwLDfn3#]GQ8u?F*`sr b=HY(IMI4k>o$4%;Lb>]Sbe/cDsч a,}M.Ù55K<Vpoy5`1C_jWT􍺟OY(G6ha}.kMt,y5HRkH^k":U$Xd0<1V;yfI!3$ qPH<<}Lssz qF?ӌU[ŏ .! 1w A($ǃN"2<2R׃;V@$^B>R/xû+/΄_7 ÷L6T;% 4K0/1a~2vՊQ+s{dꜾТ]VL/-#RU6Y%A)omU" ̾cl~[C|>u5C,+: }Yn:s φ\͂O$-/N=i\BfOTm8:IyT4wJ7Gg#)o(t󛝠 \~tA: y"d19nQ,C1*I8Dr,׫䐚(E(DME:g"b1?ه=IUBu hey' tG'ͶNj j˔(H3KhC2᪑Qf`RQb%ʵ{qS:egg]xo>4P5^{JQsٞ,dh.]ȯX( W~\!dZwт̣5TGH3؜oR&SԯMt8R/hWEh}4:#K6oodz;CZ~tI<%m:֚ v[f:#<* vDr`yshk=%HT,bx2/r~L +pZLr0gpe}^5%M<*|ѣN2zT  Z.Aη;;nf1U2`er0B; 2?CD'63)9K آ j\,*1Mf@ fLG{n*@lMXi,s56@sM`(5P`OFc2rq1`EYaJ ^"B B9aLQ?dx*54;]0K40fZxr"JoN_Ԃg=̰NZ=hkp&'Zǭkyw 3azpVZ;|wf{jIZ/{T?>ͣz}`N7xքEן7y0xZ_>Xq5[u,s6WN!`nCC4'׊ & *Xy lϺV ^ۍ.mv^%(_Aޫ`a"`N{ JگZ:@ȷOiv50{Lxس¼ԞyzįmU;.6j09VйFKAHnKxx$ǰA^ݫY8\k0hwd!^xg\Wk^|͇bQv8dŌ yʃEh&n=WV6JBU sh4 m/eI8m_~rnoGb%E$rŦG1?4;6||F_fiXJ ΡZyl#9QeݎpQmjJ*aNG3`7=LN6qͳ!? vχ?(ʫ `5b!k%:h0,+!&JM3 ӹD:Av-s 0<,ֽG.CP1L&o«0U.QM꛸UnwF[,`Ԍ*) -;Ė>-+„-MnՎ [#7w+ %2|UaVww_vobB !??G:_\^zC{TTƩ 2ukk}G0\=bk5PZj=PAx NF`#dDEd)N`2Ɔ;eX3삯 BD:'Ty@=緈+-_&gAŋe:HJ^}Lέ/xnTjʱ\U^B 'P !oUU餇?ޒ'YR jq~Jpߺ M7+zՄ2rf#ǟSup@3$`D"dP1]:JȢg(: cϋvJT?,0U,^0EN=O)a%$^Cj$ڛ1=J+w `\U,-l&OO*63[>n#u'y6evZǪbS oup& ՙς=]Wb%p&bϺwNV<DAhXNͶHjx/9|=>p|A;>ׇ3(&tҵ@?Sdc8H:y{BUVWtZZY2{m W~tRX\LU<ݿsu&l8, X 4-Ib 3R8Fy#+ާ$O +VJvǃ'+dzJaf>ڹuE;<,'i˽hc}ЈlSo;I.͍/ŔŔCUB2k-21.HCI_+6آ޴M~R~SSl'yPp'w2<2+03ï\wX-Z /-TKr;1"sP Âu| 묳*3M!+G2C4&)?76a$X  Y2%GݚUlӢ"^JaZǁTQv"h8ܝҚ+|WڟNn ݣ b"쟂%dwy- FrKu~8t~uXY e6Kz+aUK#ui^rW-Ød:ٙgNla N&7|5#Hn@ĤM@̊}E* _|IMU|*+"*@*p2PtR9g- un Ŀ* mUl]< ,V2|a${]x*x+&]խ)' #;-rAduv"=*?l zIȥm{j_\Iǹ#_tA~),vZiz.3**KCOTXc5F; x2-he%9gml*q랹cV=J?y!VCT~%ŭT+~4k0XJ\8-F+'x3Ƈz*b-moBzE|8 (9#K-<_ " &C pԜ`&ZetGwIݟe6K(v~鼗o`)?^{> 7i! pG%UIXyuAc,zeWd@#hAQRefaRa (49$#3+zϮ*` Jkv"몞(O&TfNp ã#4C+^ ؒDFB+go;d"L\-!}%Utj%r1[O8 5^Fh\}GԚ:)*ʪPh(U!Q g)'ê?*%@M ^^R( EU|5 T]"#qV(/~d0$4-5x01Se!-eXyu8!h${)KGDc hX6pPn1bI0@ͤU S3K[*[? Qߚ?;&%0@by?ǤXW\=>chJٌZNPKzxR؉"VBez\&ۄV bX4a>KGy= -Bd%[qm䠜镡K[I"jp75-CLn'M8!qT2vy`",!Ve>}Ӫa%t{4N{hOtfmV8\nxۤ;B|޲zޚDd,Dvj"ÃЯZ DqtI+}eE V2"t{ qPsR([10;;лnsg͓>> nesQR[^sVx*_w޹RbA3*-N7+1RgFUO7To.9'#$NgUVfä8]]fkwRO-Veޒؔ/潲;H-nԧ\[Lԕ+"89|'|xi05gth`4Lꟾ;.XFgkzi"yymZ~EV }\բƺ*n~]Ch|ZC?9~Ж9gv ՗ٷF3$‹qGcz5=b+(zNy=O 41TUyOΟ}ɟ% buRAn 11c`(bVJ?g4 U K{7'vMŊ/CEͅEqQ^Z!8Aŋ0d%Xg(Fy 8s΀H%/iw!B|5 qtV\BHzK4E4G};[&E4V1RrCruI=YEm21TC AUHuT5 jnfhTAp59MkS[`("V!ƽ"1ek_"ZDkBɺL}/f<"'ì7j#a/Z#S!t=D]U(J="{jCp1M2?&`eȟCN %C?hE"%(̕?iJ4C:%i\ݣm7}p?'(gŘhg2 `r 8fG&ViY{[ EmjcSj21n<=>a>Rx+6wm9&RIբfcR:Kig7bMFCvKwWSY~zbylfMY "—܏Qb* + E<ײᛌN&ۥ|*ӂ3ʁ 8?J`yz7}51Z͂(Y]+]B֫2b[ &]7LS%{#YCJП+@R'&/Y.I o+ވ?? Ζ|[|i{MuyXٶalnd>#r7\LջQ]!nk:c4MՊG4bt%M+ 1f7n< }̏߫q\Dڭ~!P9`5- /DD~EhAUBKT!*2aκSo;&+e MƼ ]gCmQb8KE ǵϓu@/9ZaJFtVHh -В ?{KJXW]zAҳ F <-ڰsqO:_KCzl2j+S ҨThŶ'&eMLVcϟ[ =,ོG6w?!jŝ|(=\F^b|?%\3y~m J@8N2Q+i^L`|dVzbӅDi-;M3O]4ii~KN=?n<.`y+ks7~\w =s=.q~r Թ||zŜ89QΦ& sx̧T)Q8IU8ȌܲL5A<Ů`Q46TW1oWVU-3+T;bь1kLmGIFK$`FNk/1jZllZYV[^6?JƷX?ҍ){aBסih_IQ!wy ׆-H}}]Mg8O.uW ]FJ'/к Z`IVO,%ZGJQP9m秅ٲ6?SenwwXTXk9-`{ DOv=1AEp0dl0go!D7<{2T(-ߨk t,-`3<('W +}Tbߒbu'Uz:I4 5tܑK7}|Ɂ̬3K .hl_Q|5 X5T 1WIu yE2z4xԆAbd%n#]pA}(퐥rǫyO\ o怞E cQ)|csp|5f2 Vbg8PJ/ u[X  AX'7ޫFqUjlLd`1%bg%/{}7YQOmdE ((s@8R˟väjȷ֤`7#b`Av3S߱&+v4ےKc/Xu1,BiuF^E3)+L@/ J>*xG:{Kkff XIMk !V&<,ΣRl>pȊbb*oɥ!E[z WS,t 4 HPdiLǟIu <1ngB$f1T:: qЊ J&1"L L qS5|pcSr]G4LhZ~e*Oep Ӭ7<#Q^̣w8QQYVopR ~n# 9gwfEJ$N[&32 M۪\(`fl o|Ο3D=`źKd-|f].lJRH@b_]#[/qɪ\%4;Aʽ*/áҕ(lA4餒@%#v׋xI|U2Vv_#+BT+Z%Y!?36eu8)kJ^$omZխQmOq2>\E;$ǥYs"5ҹwxT<** *Dv<ω+ <_`d O#<%8Pɤ6$NJ*o3D쭪s [$^1WoL,s3zPEzj>րU#3'%(E 4_B5[ GO'Y9/ᡫ}`IѼ; 5@x<;rl|i//NjtT>8M$5520|;UF.usߚghB4eb$N/*O<@l{|xiph<l&Ad?_}f.`iP>H$oYC7ߓ-T堃(r8vazIYb~OU`ãv:O6 adOy{;6Mxg m{=}\ `?~[[ >Ⱥ{0/@4D?*u1.zq_V>M.7WHYHa"S9?~Ks En4Xs& MG@Bzq%p7quTne&!Iحrb_`GAmPd] O\#0 `s+(%PX$ A(VA"E̢,JaX7f4CS*h^g"@eU$l$b61950, *`>c}EMnDdqgK yx um`ϼA?M[[(>DuQA_sJfFj-G1w;F`̠D!BG)iBQ:(B1\s~;Dv*M"6B! uT aDHq({P\.pRXwKӪ@N < 8[ĄqX' L!cIiIWFЋe[b-  ;ln#5b8,kyo II,zp銭­QrIsC{L/+}{Gg5. zF/*38"G'3(ۖ T&E[:@qjYMKu6̧UܘKS$zjĞЉ֤LUkC *XɓvDySy5gcϢ\~ DDdWh,# hu?B%kcؤ>d݆ 6+t_ݠ7 v vGLIK_}kj_B1 ]4(W_e>$}HRt;K{-Ιa3\0 Ytjs霞69o*ookUl*B:sLkłkƗ$zϠ-L9itQ̎HP`-B DN$ц-F$q$EKjN -U.SkXֈ :F?a7>?߫VMJϤ4fJ`gGx&YQUoz'N7s5ӼmjIl64.Ak_oZ$.Y5z5ƳF?Wrc!/|]J+aIAF!i);cPm >+PjƦN>u+wV+lD2e3{X50V̀NCgw6-F3DXӅOlCn2LFӹCVfsMJh2BMѬ >Yb)Hh-߿C/#C/[80)ڣ 4 ~":eMu*[r8fXf:2Y>ֵDm ]Ȯ߇jI'Dv^dO/^d" ^|Q-0^f!)~B/878υ!:@f++(?*i|2`!b+K'hH$ m_Ćk" %D0Kۉ&UᲖJLҴ!Dy-Wġ/D!i#7< r>x#8~1K؄ء#]a=-Z8FdH yJb[ Rd N"\n?s^ D,NNB9%Ax='efҚ/z1P0ɆQ) 9EP4cBl1$hz:zJ2R+z&(%U6Ld^UWNT1Mm(e(PЇF9QU:,iP[`+mIxYD'T͘*<-T+i\Tfa=>cf)tJ,3:ootjIDq*Te_4SYtg׆kwDm&_!:4%ȀHe4иnRͨqg9*anN`}(“^eQ}KUrUw/}O(gnՆx67ۯvHkWI-d0wFqI }ls7f: !攑hZ"\i[UORh΋[Yfq>`Td9luV$Sxۙa0Ij?a طܱpzU~"d|M^#nC3Hݷ Mk +V5!4E(OV_:+>7 o)R >im @|EI*0Tx>H ۜHJ{)ot$语aQӣ6VӮoyyeU|,%,WK 6銿IYZX >Cm4s$ljr,.Xe _:!tU&bSKV,Ucv|&=I nhtS1ɽ$}<C/`*dAzÊc 2o!Z0g\QhE1~a]1JAle? D6$c %3sG/S<ĤAU/:u7rҐbN!M3-Q]YP,"V%rUS}Vnڔgj&a K֮ exU1aԒ8 SP9(垷D"Kv2-?HcR+Vɱ'Q8Jgl oD+58u =jW'6 ' D{@"8PȜXLhޢY" |rH-MQCa8gF"mY(BeEF?Q,X+Y0E0YiW*H靽R? (2 ʼ',8NuY ltst!I\C,jzm7^|*)Od~W9qD4V D9R􇓛hjçW eo,鲋Fyx85O%?@4zgWfDa3NИ&u(Yޔ:`/8A g”j=IA/#s+'V:D8.1zyƓ|zW8|]|>bPV{I`,"2r4̈,{=|gȲ P0,}m}=Ė6el;]q8dۚ_2m[[xxK!Eȋt'|,ߒ%/Idٹ#T}|/{:o{Ǥ;E`1MF  `P=PyՔ ETZ@Al/ P$BL/ޥOAL}!=4_Q0Xǖ$bA9/ǯbɳ;^^(xN\)2P-0I]=PH$K̵T7 n^/3\bvEܡ*z:WA_j k#Y2\r76zۚp .ujTv&-l&0OU Nl.$zMŬeK0!M.IMA$v06ckr Dg#"w:ٓJ&b皯x8W>EŊ7s9'Ps B덡 2l_$!*`F/r(($ l6Idy8 Ghc!gf{ i0r1uؿW0!J7Ǩs2 (<$|L&=%.XAWH-#!~4-ȦN%x§ 0JUUHg$lE VDJTY(&?xyhA)9ZsD7d$jit Gq?_(JJDQ@ҍbcJ陚0S<#O nTW'm 9H9[9I挒dV+A&[5`/^c3Af`ΐ9#C2Z 2OϏ )r|/۰?=rfYO܍!P

wF7υ#92%GX]I<,Q7XAZ 7eу)."פ֏GH$30H#ˉRH򁟊B[}l9di1fX4sI7A0QrɢT|t";.Qio-Z{˽pBq>lvt/BBYd9OES۸&N75|!d;Kw%d;SD8? EO?)I=W!6r,E5!.5.($ý7Q/j{?u. eϺ>xafU$ JEIJxVMxԖb#`? Q Y§<&Ya(]a(IsPv~ m!Px{`_CSOm'-Q'"@K|"ۆ_8O~jFN/$9Yݒk8,|EY-Ip?]>$HL+C.ݢetEqswrtn]5_7=TA#ޖrt;ˀQ/”,H΋pdZĿ2&{q\~M o&I?DN^{0 1#+@|t^y)gz̕^yBd%_رBɜ?|Y0!ũ4ܝ-v$ wE Yw0:H2d'Q."O8cp'`s~.J |oj#",ȟ{3poXZg}|Ծ O_9hnvZhy"O6**-GdesSzz;nwA.vv}p :\DX~)|tAPez+cQĤ+W"@>zY~5u.aִ{ AP*rcٕzybă, aI9}vVf{bzDlz腙a*b%hUyƹ*9js煕NŀO nku_ȭ"[R]r~cAe=tZ>1 }΋OKv<8q&g05 %H_Jd?=buʮDܯ5>FU >H(S1qQpCjn0&V_ n:vtj}ޣN>3\4ʽp `,Iul/k T5Ut4U*C߀J@bȤߤ3SuET p}^-A2kvWr=EurgY)MBE*<w#rIg*50rܸIZ8 AVrp{Phو(O(99Q&̀<s#4 Ex/n$դ SL%[?Fy(qċYA- ~n5uz:K4Uo\vsh1y9< #F Bt)F9NP&suzDJ5os9$J}KVbVcrC[T=3s)=.E7,8%9pVZȓ/$Z%`s.(r2c.Qc܏۩7$4*;,ۦ.I +b6]XBhZdd;JqEvr5T _C~Eu:pMeI+.U} 'םSRuXVFF5UeSI|"k?qBsqFΜ\X9$gѰZ,DR9톯F|[PS=SFo^,LJvA^GB[B>T-%pgaX)P|^#cUjѩ5 \axsd*8!O8:O'C+@OY$d)8Le8M@nDQ))JYGY>M.Lgf.Wmr`0`B⸏fcYH?" _t1Ĕ%2x4x$|6LyzOq2;)FƄy}Oq2& (6akm A`~ ܹ-royͧ{4NlY]e)#eQzf=^]h BwHa[aKlOxʶ݇! (n(a-2d&)v`. #S@Lؗhudp]D@ AH1F-~q`چfP և* L.VkIGJ'XMa:-~ VC|D2ya6rNeaS|"^F$6(MKJPLXPg95_*^P;Q< ף &cDczY&]iO5Et>!5S1V8# #S0GCgk>JYlgx"QtΉNڲ1 <^їN@P:ͰWI\#*< 7ԱN!II%qJ`gbO^.w~OVt;kwe:9~)vL~mkO%)Muw1 M9H/<`/p͆4[ v7|ud9'Ft$:cV.!]n Gۦ|Tdw ePq&Dw$43,o zgZT8; J8dZ|ِܔOxųl7)N<>H%T'8Q|a\ۆJTk֫(ŒW>%Hy9JQCnF}UT6HL:f:mv zVFbhMSm*piz76`[[s_w5m4QMې)9NE UX_)yuj|^YR]HFDWt*-s _Ow3h4g$M- cFHr0" W(Я>Mvƻղe@π}4Ev2FP̣ [%`rqhN2A ;k:tӾuD?FQŪ+d z*(HCVG/׭+|`39Tø/;c`ãC`N[~A+zqԦoZ̓L|PqB?P-kn)pk珯# :~{ٿhio[0 =n@nv1ֆq;&N`epA#j9jCݷҦ58vpD}B7-NRBV }cg;I?ߕsZoVߢ :gpwՃ~ 3+Rl3 `@f Fq' f gIoyw0h0fx!ğ6_Lk(#ˣZH1m`/!OYӌIQgW+=+563~J[@<+RWkPu'dL7"o{~Ƙm|p>}U/< w}IIj}qcՃFl}dc;>D"Oc1af[%jvpJ버ߚ`|l~_0 BZZ' >Z[k 'c4 NeY@4j*zj,m֟J ]{k߼7y/Wt݆1^\_.̋+;݊ ~:C37.~Ǔ,*P2 ~$hhwm{6g Baw&~MӾZsdx\,XB>u"( gI7[;Ќ"Yi۵(tCÜ/އEI>j# W(VkK?F[#nmD4G_]Qh@Jp {$3`. ? GdW`GFWc *e=RCVp?nT<W6\i{j^}zڕA>L&RVhaiy ͷWعrۋ*C 4!/>o{]en]>a:/i |7!`ЋN"{}Ҋ5ZUd^U_KrO, tk6ʗ4̆]jn1ѱo_7jw#ڀ~|&3h{^:d >mG6t[ߚ~X3y~ipƺ.IzſՊ콂WM,/nC~-݅ZߒJ5?|{+?ԕe<:𷢊\QU}iDrǜx`aT S 0Ƶsda`CٺO-tM.h*zE+7~G\~*^9m4LOh[P:zdLYB(x#Ysj+Z"=.j]lȼ2G*ۄ:1V M.ٵ<܄æfR{|;Տh R D[s5#pj></͗\)śVqN )Zoq\?GR%[xEdX:_h |+&kT/>桌0_S{,0U[Rou)ސuSIX׽*0MS(~hLV)~(6ہoL7Ǧq[Sm,jK֛ ]SqHU9'}{яD.<f.Z0v El6voWTM4 9@/6r,wl<̆pF }5DZΟ51] =vX? ?aY U8uXkЕQ:z{,.k+%lG=iXtTυofmfEPFY0}АӃt .dik'?? QnJ-%+C\h7!**)CT&LFE/ׄj`+[ UB OY=nuD E>F_{ @pw+;7~/uCo?bQYO)x a*iɯRJueD?0=ݾ"QamA-#k;qb@9AČrR%cUAB;׻G>"6OS4 {T4Ri/a. [::&+9Eڋ]Μ4unIkkoJPlm%ǝ8ҕi @W!EAQH{E|@</rzw+`+2ra=z gS|{,`ʡuX悗@ept9|At u!/[1BG _Z_ѣ[Cpl׷6_?˿/_}R?/;E!8HLXWX'xaO@^%p6P@ K 6֤I.( &^^H:a1&pNfCwɰ*%f+#Nx 8ҬSժ~y|ĭC@ZjB>2m;&L5)T70:'VxSu#6՚?-;N)Fǯ̏p},ӧz"X3ӨijEK.jQ!E EFݭ[դ:! M!%7VIx{{xdoTmz=g}0!=` 1'Tz?}j~!pgb͞{q/~Oza٧hF\}qC*ѮĎ i&4"ʉVK,Տ!%SJO(Z֦5l,P"1oD`Dng #F*!RǻDɭbw~>h½(_2M/;Ѵ``# jw>ȋ5˱)(L?3_tBwVfBa gZ-׹ܷ(wϔ^bh3k6`]\R1WA[-I+eb RĴoLpacčkb V۷舑DG }<kxܤ-l,؇O›ގ<*?4o \bkt"]N8gG=➌WbòݥɆ4>Q,ymǮE^K#~}^soUkو)8E U;E MNn3b09$𗆳 -,WLhfr+ G*(VH 蒳QjEpΏ|wCB#`7PY@ﳸ'.x 3Q(A˿ 2*S凌PaM27nDag31v|qrUl6Y? 0 BJk5>a]ChL ^hWٓ'ѯۯ+ʲZI9nA܏z)/]ZiDBPrn2YZ؟K?P!4fѤ =6Xva *ѶVմ[ ugZ<햣$ћ.s2 as q}p.&;WYXL'#Iiq Zlj^k~Bz-F9íG<6>½hncWXb$׭NS%XO( BFӿT<5`<dR,*dHhFNX5vop?rBt I?Ԅ84N[*%ϼZU?y=Hf]:y:c\LhAih ZFjY@ҟj|*a !?$slƿk0C{}i`SWTM*߭"T-sw4Ǔ4P[Dr!ܣ^v|frT nȈQn[c=fYasOU*b>hq!nB7b'!5cADn&"+q-T,2-~_9QLs* D<ĺtsn]G. A\z9Ƀ :TDΒF&6Dl8gkR;>c^ɃZvΩH -g|z:v "v!i GR|=[ޱc᪈1Fq[ť8ل_tjdH2^;enXbr}6L0Pst3W |;YȋGcK|6(.~Ԟ8PFgeިww< H?9?M;$޽EGParaD/lT :3=2*+.9 Q+5ne^v ϑ'1[1_Hރv|ޑue@$N.x5|9`%' grכAua'XMܼR] d'hck-T,f5?fH֩F=ψD7z. lL=VI+_⋨ cY=#+gD袎VX3Cxcj  'ē_on}>sfDڄ9B?ф;tx޴v?i" 3NzrXN:]% \ѻ7_?aW)(.ڝx6Ir:.U'V`TT6Ta`ۤXgPⶕ 0C7}P͇mTRMN4gp8V]Qe'PH9{w4\ĖtBu+dh"'t%VB ߦK4, T!ۏ@5ZyƂjȲa4&w U`"WFRg1SXFvN2^bDDڴBB9#B`|'(ԩUG* mvɓX!4\G!" ĥ8щ7BbnZ0TuX^uI+ (;[uDUzDWVŽ+- K19uX uX(dC&z"H0)ݶmi.HZ&oOCL ^tD5=jVCͱL&sTl-&T#yH;*ZqB99biAئk E/?z, [}mvCgnP6N|Ӷբ{xLNmҼ%ĤN^pe~>s19ل[+sjfm -_kQ6+dnv,lz.>իMhN4z gvm_DӿpךKCN]~RUhB)ie+q6.rC?Y#|4gSe8}1 #mk T(_4@{h?ِRW9 >L綧j5A/?Æg%F|QW:joVwԫ>5p9pDIO|((v0[$d@6oU±@1Ƚ!F{%_EfŒqr@/䥟CPrEr'p4 $SB &>ȾmC7b!ګ52s5*f>!_4b #% R < hp󼋚 qgK0݈1iǓQ7ɐ{`k Tsoo5)`F+)bǤef.H=1*ĆC(^W->v_9p-X>C]DVfhwo17.sr[8,1xWM "龣Kl )2{& zXx8l> &5nlnN.Ps׬ NX*'Nmureo0ol>&;to>zQ(*G/C]uՠeBI0[H[~gFl͒biC4 S\1c}m>ڶe\Q\ޣ_ s ) /l:* OhEo_9)!c:[F ªGEh2dsl~F-J˥UK%JeRٲ3&RqӨeQ dQ"RLe'QCr >MQL)sR _# 0 OY%;A0ֹ9,c]+#J}] bB4iKIGz|vH`1wNo{xG'Pir*+0jJ%(^z`R6Gš.ef6|R4/rTk$+wi쵵qf0?lI1 )7l%uaI5uUVZe)eW?Z{mp9=%0`KgwtuK+^Ȃ:TAχM磮ʐwe޴A:nT/򥗏7Ò?@j$s/lY֖>5v kn3N"&M&Y%U{[L-Z'%!v}Ilӳꪼ_?>6r%0vzeClNx2%`6TaT{~$&3dt˾]b (<=ϔ`nT6T@Ψv|yN'>C>|AQڑ64@/6ٙ! ]f+w9QLEr!A<|[g5GOMX%%/3ڟ@-&nE5&E,'(i,r j^ 5c+ 5Q0^) yRd 4Oj霁 \6nfڍ(s]rq#qP>FŢkעix'gq?KTUP"؃MF) 7 cdhE g 7D ̆S@a5,!}i`WOc={ J D%SrfSTǢt·1x$?P,{*^%?Үrܒ> nDtx~8iMD 樀  P2fS CgYq5/^dL^W K)Xp*g<[ݳ t/Kpm@Ҩ)-ѭ֥o{vYi'n }HZ6۱'մ๩.CMbʡS:.e;-]Wa*llVؤ SSuې41C*AmZ87 3+ێMǨؐpeΜ6|Ze 6%8KֺcE; :W,A_Q4L03*&Qxjk5|x0l%R!)xʝ_WZ[vI3d继4^|?x}xǝ?_' \DI6t2MAȅsMdz$qtNU/gd7CVx΢ h e8 5jHID 2,/!6!PX&pOS 8"tgk)0=~xxIy;2q>$(2~;n W?S{2Dw?PL3&8'mz`qz#PӫM H arX5vd$T%zShzKe<=z`ٌ VQ@:dV% bvp?V& tJJ:8k;&#=M wSc]ﺀUE&a?}/߇۬^Kx0)in 43ށ=Q v '{wX#b] K\S|MґOnPo1j{DF0~ՠ{;q|SLIeQ5lWus1Wx(Y@0Kt~4VgyI>Pstˡ+w~& 7~:ǰ%e[8g 9jU:M&10idt-4(i,cFHB6Sg#9L 6RX`8ShDDkc'}O='$,:, G!S(1j~ uKh,sM\slx)  *,==23zOrrpJL51{lSfbFBmEQ"qޚԘ`0(j4`g}PD^'3]7xyJZ8VC)oC, ; ~>NQNZnsL'u[Tn[X<1sG? pƶ½D3YE_\-0TEUG#S+caeͽ߾Į?WdO^̋H~iXcZ-,:`!>@H [A޶PoAe<D|&Yd`-ALY$uiR^*vf7B54 R0z_{O2z#CΎ]},!u!rhͳUzEL{.ȝц?#=iZSNszXG>?ro4u5i:s=Ԋy#ZĝV{)]:Q^O,@,Cû$품FNEXǸ0xApw+̭mz6`~DC}|x{{WRdZǍz s3E6% }Qx̦('[uE ӡXlfh-H^4x<#\>UDKqPfK&Ęj^yW& iAm%X mSQ|m)='qof ,~`)I a'@K@кo-x)k,It̀"[=TT5}>’8*Z^f-|MpxU1 elv^3 djl0]jy{ 2"B(^d0"m]7ܒսF ▧m&)$74Y4pɨAoCHaKfF+6+E3u~y-:ϳ:Vф'iM zzR8b#̘!; 2.lm:Bn~2 zNaqP3;]0jWjjEr:N;UR#[d9'[3>?|yJ[;ϒ ۟Q߶1㧙:7髹iOYv!u7;oa6!G &L28ӧ~%> (4IhZP|D8 ףNmU)ַDEYa+ z|Hiq ㋜O^B5:i%J$G}R5!,iIWx } CmGRĩ-}m%|k~$q^Hl¿f(ꖥ30EMEwZO,ulK#X>H^CG1^=qW8`#"- 20E||a/'nc`O h7jX4Lqi倕Ts^OCz\l_QN ׾|W߽1׷"#oom>fck};ZX_ _oc0 [3/O⏯&4>~C}X_lF؊!Pl 2J;LS|)véu}o^7ۇv_%ܙΔ e;jW XKϮȐhLp6T f(K>l%:*:G@)a4}ޓrW/ 8ϴ+93pܱ*Q S#WEGM^@SJGs ~!sXv(B)|Of ;2ՇɹdI/KnW=(g4e7rW/[bRL tj% jLb< 8OYՇlLVPpv^$WE@̆)F,/ꩠ4w D6M =a};|o=Y|q4=}ZUٰ~7't0|Ia 1˛7+4#k/O^^voDn;u->unot4v E}io:[=9Y ^CI"&}[s-yߣo6Eyr|׳:w.ˆ 07 |_Lw/~(7wKT!9v_~c;t>%+Os1e2O^{&|1Bnu'wq,C:;IkP1S>lb^ ,p89VNc^S,ѯ<đpm}F lcίֈl.jafhyڍ\= Ђ]Go̓E6ed׷I"oA;η`/MXOEEǟn9l+ R wW`&~-UB2U N)OQAldja#<͘5]b$ta޽[%מً_ڟ||RbE2ԍ >-n[/#+[ Hr?zi{%\l_262h!@Q4T_˦|MQ u=tSu>(ڰ3z".9ϿrAK4Fɇ+O!ڡx44#3.)AbB2:wNmK]gƌ`bpݐ ʗw1q_*˿xt1-e>בt<NAFBrѴc=J4Se #S]QzMD?:z";/cfy3S0~o EʡW18/VvΪQ&?&]34>$$-yF1LMkN_}⠵pSy9y{RgLH{ qtnWrɧ aN|P]%W;aA EhT)fltӳ4Q/p0^"Üa]|hˈڴ1+hiMhy1[vڑ o Wlƭq[ [=dA=Ŏr?$il)Syīܥ%pWaeC˞5SR1/F\ rQ^ުSMLA~%;JtfܒI7я)'ptKvO"6w_rv,Tn'ƺ~QU-N9D1n֦U%WRu7B; 暴n) v{pʓ2X,z?(w4"a!@<6S<cz'hގkp )*&d./ٷ#b.Mv_Q霩crlAvJdi⹎WT2?v1בFf|y{۰ؖLew0}p/z;ė@;nUvWۘߍ%=oDeV`3y6oTJHSE+w<$za} =<8&EXM':vpfa[s{50Y2ܺN1oR\6ͪ1̝SU'db gO 5En5wG*rl"aL!RԜrO\/H}4!ߪw7TE]Y*\%Q"}Q '˺'<(+)gN&jÀUj!xcn 5;}P[kAM[.XF_#Zdnnէ5Ӳ"\eRV.-eb˛u!(%ñqdqKˎlf}s%> )}g3Glr}.*^Uy=x^Ïe\ m s1A3hx6Epl_6ΔnMބ_Y,֢y_>o t0'}~D{WMV_-|O=sY )z/;Yg26Q𡴻5/mN1_ %QAmn*3o Ef5*uq/Sx"zBT}%)n2-?Wg 1Wz Q,Fn grvmMр~zz|ui6(hc:-Xy_"uw;V<5˹%К}R$ J^/gCIMPRBJ^3%o*(^MsS:rAoFzn&Jb*_=,]2Kzw}EO!6SwO~j G=qvbٹ-td4VcD˷ߪ9_[NG)8u@SBoz({,Q-:V4A2RFJ]LjĊ INhB(XݚG?q;xwZxAğQJX]a]*|&p1 3`?s{W^Yvρl//V %v[Y5;Is@F7<pI>4N>LPטd} W$CʶāmiΐiRm+u"Nٖ̑¿;,Q%#dqmj>yWPRt@̍KnғO&# I@xYYv*L-vwŅ&x<5Wh:-)G| plp\w*, Rm;XzL 2ãؔF]MFS/$w(0ЌKG.,$$d֋G "v$wx Phӥv$0'pԿFCO61xMJCiTᑌr]i?[ !.vw @"{+p(f$4' zԽ葎Fʪ󸟍@0NzٸGѭ$9 z?NXT8ծ0F4 %QV>kOG;n&D4yBíئ+tN0UKetL"$$Ho|ƛI2{0c1xr0UV?l\F6wQ w"NOAVӐ4F5:7*̐ee4~$ã鄎) 澴;سZ㓏Fb2X.ۑevP4Z5koE\zqv_ސ3ѳgVT{cRmXUz2Q|k zDSgf+ߠG@9NTrbJ^ZZy:=Msm NU Ogo෣̈́RX Z(=0Z0I9Y;<]3,7MVab8Zp<] Uf=oi,!3³%;B >hRM9b"|p@^6d4ޭ{nCe| I|߂߁iYy6IC #1Di(~eGt|p9B8ՋՒxcQjPJ>.B~7h\pf0F>K.G6*rAGYLh1uƕó]lx{MBFp9-|o[o6IW:kP9J,8P=>(G UV;t:‰=0Gֈ#5$BYi%n`nP5E'h;JW8- :́EI5&M$SVf:uʻ $.}l7ckMOeô!=[L]>sx"r4MCk/nf#zވ3UZgpx dw IqgE_Clm/^ܞ_X^)fIm5 bN/Qi *gTF7;EFt43+ wl!-1-12Cٌ~2E%f.q>o4m) )($ @cGÄ@ m Z E?i"F(2 hrh6)XSw ʋ30x4/$]+^?qmœ/Bz.ɕ+Wl-i:ڂӉ;NjA𚗠GlEySU" ckH|)J7~m ׇ%"ı*)'UZ_btߏߥc['M6A#BfdrVX r/ڲ泽 \rZRQsX[7otZc6Y+Iqm^ +Bd WkIQ]"B͘^&Z2dSg r~raeYG"2k;h>W5'8!펯j{8o Ц;O=h:!r(<\X -ۄK"|$"؊R-}Tt_i^wDhTI<ő ޤ$C_l> M.ŀ\V겢XUEHsƃ=Z M9ډҤObir5bI(#@"% EWRtsTBBs,ue$9!"M P4%JenF 5+5חǗXXa~Ez*@9H'Ϳ7]b!6ͥNW?f+9ÜƯ|/IDOc>O7z`:`5|Wk3htON CCjrp;[#=bpMѠ5i[E᤯kt|zLMSa),"'j(ϟgk漪f^?=S'_ hX ? 6i=v>|̓9y~6Sg\~2N*Sr+XihpSJp碪Ϗ茵ۊݯ̷#iW"9  _ F!#;<! Ah..+(t^%xʒ!\*8{2.\ZVSNF\{&ydNv mqcB!ö |nbu S QVNGiEsٱc6sa_p|Ծg~KIz =1CGteO+uXlK -^2Wϫuq{& ;EYV9La܍0Sn3\Ny\RK)+$C= fjl* ӃEw0b:IR#Ug4Nfۃ.p专M3ꎒ,"I2D\-ea*t̹90x5U\Ud0ScC4tB\jSǩ-ji1 dWuVEгWIsMT$ƥ`k7#ΙUz(_u9Bא]ܵ7? ёܬMqZ-3қ +;ehMշ#& ͨصG˹(4I6BQy7;}+'cdbV4 ڻ2e 1 f~ՠ04ut@]81y7_N1ٰN5=~ WfSlJ!t)ndXwFBt(OOG*p#|YO\C3ahf843VППJx^JBg~NJʅ:=GC rE8)Wۄ`d(eh=f8جn$E0z#$n-b vHDS(],^k1FqM #S 6 8IMO5!?p c;e'\ \r p,וf$9\lZ65>_maMYI5KRY+zC~}?ޒ—zht:DC) 5ސW=QpuvSA; f2ٲtÝrV06&_㷇bޖANZbk+0Йrs}z|Q9/kTBS$uI-f#5/~P|?u[yvJKF'X*lXj0- ͷq;3;p?zeӼroU693w; oǑKPi2#WOr}i_Z46fC {]ƨX,+k08VBgG=c8W#Q _/\Ǔ{tn4,jţx/|hwZa +ƥ6H[;jU`hx:#)|6J7:|ŊhBȒ"= [EO#5EO,0\6NiSr4/B9.}s\D.sLsK\Ս2Rr)Kr#e4;z"̒MFs),pH'r_+H媾 EbY(ũ ouD6ZTR||Td DGA p ?S5W=Tr9mȟWSgEWV{x쁯ra!E@+|+5(M)|LYLw;LݩÁD%*Un*M2t(Du3P6WL)42}:Пʔ8kiA2G7C hu`&D .g!M|ά/7pVv3d%H]l?./6]3Yƅ4Aiw ]jߥLr4yG՚)G~> :Ԋd`"&eTϮ|}|݁R|g4;r=3S޹>S墯ޒn-~Ds;ة""r24yv!d_Qp垲/:oKK!Kܨz{qiZѪ(\>^*x;˸21cgq?dW9!Q\V_7}!vR^MtClN7Fova۝n1uuuuӘːwīt5< u\YլMl %-.J@s!KΪ683&fNh2;iI^ ,YV9q 5rz72~k]el~%˗/P<擺3.5pJi]ʧhn,_'pO=ܮy:ϓP@Ypʚi@N"|lw^lv.K6fw;1kIݴ\|\F.N5@~l)h@WdEv;%\dZ?)~1&O;<88F田h!AP'?1~Nwy֨GX !uUE>x^泄xzcyX@r^nn|&Y(w:ӕ6:ë%tJ&I7I#$9Z^Kpˮ݋h8e*w*AbڳX^2>lzS [V"lىMOkP2#L$;u7qv~I/%KQ:kkiLq˫ʵ@dhGid 8?l-ӋjD+ rh?\%A->[pbU" ]0vA}xW~ 0jڲӈprʕ׵J^ZSi@rsbŌj@^ D|Շ׹D_WS69Νf昐fND#1`Jp0fĘ{[P_WM0Ş4Qx ʄh)L>B_Buw)9:k*RK$4'O= x<⃍ޜQPN4jD]C3' H񅧮'˓+a! PM r+"FΙjX -),ٖqy12Rۆw 1**Ow[*~8yj[BT;=Vo:up6hScܚEL?ԃ^;3%Au̥K7N{WBc16w88.wx,JǮK|{jJr0BlL_rrs$"+ = HzPfšeuK ޹*M L&~Q>**,@<@T1k!QhwXuh3>7~ߴsbdk*կ ҈2, %&4 .'ԃJ终h`zoބߔ,DVT!+Ax~RҒsT$ҧL%>t\޵S􏐨aiZ 2 B3.;" q6n0>2&>V ;+hacO#jFwKMF}GSED%+tr^{BV]*Ӏ3! y'\!*,WbVU.WԛdPmBYi NJ?qKNYXݫ ֠[:*%qidS_bԞ8KR;\[֛5&;=d&NEq4'Zf rNFۺ%[& h,2pgE4<YczygWU & @KYFvQۇ?'ZO%8dprޚjh -z+cf 1r:gB\Q#X*T Ǟc$*ֹKCbŹWfOqe@s_o*M&g;.3γ6ؒ1Pxۂ"V ыY#%..FA CaUT{z/s%u + AX4ӟ*{3e(q+W[/983NivڏM($]ʴSKqs] &Si"06KYW:MFcd$meNso-@mQdZ=g{ 7.- 0mk{ e@P[A JAK*2=ϫT[,G~\HH&&-hPXh)e>)5uD_e+v#M:̓iw٤K [6ό!m䌝4gȀ9Rq߱`*;dyrv&2l%G߷Tʖ~e[}a3عpiya']yyQ(>ގ?,G ҕ3?΅Q!M|aws(xiNK)p϶:8.+v^7 ΁d Z$Zvm6 B)5~gYvs̕DiIU 8[dצc!NCĉ3Z.SJbİ7[OޞCB^@b؈'>ECk)y ||7ojZdՈl{2]^y&g.ܴ`>ⵗV1԰,v^mpIePpQ+,T>"¥?oPp@Ƕ66Çw~MAbjuIڙP,9 k9pM[z-P/br\ MUEI*9OK-AQY.B%g+ {Z8ZL(_yYQQ+VwFN_ 3Cyų'pt9F 4R|!rדt!GܕA:=񾏆Hfo)- .\@ƤX`Wz:GYO[]{rM{'ӥSiO7m#>kEn Pi< }-Z/֪v=)JZm{DaT8߿::@9|Ԝ>9\G#"w]Ϣ5цV{ݒtcp9/,Kۖ\Xx/1flLq#|_e.ۘ{}y4M=9ImD=V Wx?`JrL4s/f{G-}ٷz8俯Yٺ$ ou'8RPɵSbk\st43}6=X5{ kؿCG<=z||jAP5jݘGo:$aZoG\dGA@*rA|V!519QpZnk6v>YMֳj3ui#A^se7aSQh;9tJ0;f lbȉy R&H`agi9k GN5 Pl23 ׁ y  UCQ} :g%+)BC2R=~ay~< YKV2kuThLqܚe{fKeRjitg]j`K!dAճ.["jg-LЦ?rܗS9wr*4?^v- R ,D*W_#PdHKѼztV_}^ gqhı|$Y2MS%\SO9GQYj9o` Ua%qEU: ɐn}{%RҠb Nڵn}1L&)˅.xwilwyaW|+?v)E7**]̚i)?{ɿ: 8y  kEVDsTWLkse쭞,UTЎz7.˽ Qdm> J2z4;@*!O-i$WuNt-$q s 5T*16B5 OM[|x F:"&C'{|mI-:z)SYܻa91ef? ,OOOE~S}:qu-aղ0({ Nf@.D.N%( ]Ĵ->鲌 f%wr>/@`WD#L]0hPǐcpƣ,K@eC Ij\Ku\ Nݥ16% p 64oLz*/p tW*yu0[…")g',t_^}i1Bwtf#Qz  WD 7eUDz &e*Ma Ir3Kej# @ȑ#lQ\s(HgB;t|uTi恀s{v V]>nZeG7 A.p%^[+wcPO0GU :3U:Tx~#[ѹ;.(E>22+;gʁMq7CVUka&?-+<'I; 5K,##=ʞ׷fe9IS+v/tnV?{n rŔ9i,a݃?lIxk,$OVu-ٗj.2STY4 d]L vJsd %Opѕ)W*Ss xtw6ef vJ-K,˱ c!88Gϰ%r&r޹ލjeW⼃s;8SV^"RI/ @ޯ²j~X(;#m!&n=)P Om~b\V.GU;%q){&wt3I{Uuo_^uC\פ],(!}sPuy3˦W#cM~{P¹.k'SdQʊRt4fl2A|SgLDzfY*ftM b,+P]= ϻ4%!&V@}s y}&\O/> SI1,F'*khVW#;iy= PNjTU'Z:7{ Ikg6 4_J `Y'tyS("p-7"HvrJ>L3ЇfaӒAG{oZjKjN4"øǜ<i־LD$\[[f\ |[ml|h7[#_-_o{SeYI9-f=?E ڟIz~1jhs}}kms}c31U6Mf4 \ zozYh2:^bLӍ|Li= ܍@F ~@`4X6Thra4yt2{l8jDP<췎;bދ:G'td:=;55Ĕ*ныu 7a|`3vatxf":~EV -~ߴvѐ~ءT[) d t1D9p􋇕{P嬙ȿW7VzcT^;@KQ͓sf6?fû$IP#~@LGTᏝܦ?K(e,,N * 9_ml1RL0: B}^w; jYS-O&꾾lc. mz00zfnj௵g ~>V--56PVZ{%wgN}0:OsU.Q$UtdOR&LJ|BcDF*L @X)b.R 6B!F&n$@P/;.fr(`AH8Ň&O)O3՞)ک|ˤ:*t%WcdS~9 tho)ր Hy{̴:7 ˟‰)Ԡ2$H*j4߽"uï6qZL wW-+}v_I/]]и˷9 WPEcb\]Hc>VlSH?zXR)pNidxp*b,.VheryVJB={`"ƛneEOhn5x4+'е1iڝcDTSI$ h%q܄n=e٬;)JS˟h(@>e|dtxjpg$sPL9X{ FlsœaMvbDSV#BA#zɔ#_Ξhv4%J1\wqf3iKAaFiw6d컨>p`w=|iɩ'5~y aQzj!c%x+=k֦AL^ 6 z*If+bDSj R%|ceIm(PŞ2&]RF;RK,,C; _趡[S$$?- f*@^q!1c&M~jthl2 1Em$`KfRKplNEW^>Z""*By"6$^@>d G"׫-g#0H/Ko7?6;[v,]@VꇹX}3TcW U[{/rVo!n wGydО -:\K]tz-*RiyUA6>wj^]oV~`i[hzߝFͅӭ.ժWc2^Om5fZyqI3>>O?]υEM;8VJ#7L>Zdx$xqnҌ?Uufu^$z5.d2DLx.itd-K1l ϋʁh2|Cƹ'ȞY@){hq8@N6?rאEJAfs_ɱ%d!JSĵys ?lon;f"Z1}gYglU@q9}J[(o+o Zph OzbKvIeKRxɥு#2ߓavFEʞvi_M4c<.YgN0nZ(~[-4^JT13ȳ*#TGtz1LWfe] f4ɒ,pYuOthct+fް'p8 4CىjP9.IH+tKt뾤Fo+.R=0鳘?4@_e^~Zb޽KntX Rt;\]&8uMdl+ pX_CavcFv&daSY>=Րm$dW'E_U+=KX^/zoZ{4KM)ã:V6(͹jԉamRn&@Avh+~# 2fgV2Nǩ ӫ&^}Wq&̯{D/ᥠCD1!'W@[j{}/jiggn*Ay 0<ݜćN{,`GH;ůn 좗cXDC,~킊(3WIf҂78Se#o+;Ixmn}KI9EK0,D$_1KG- Hʾ/}}t`M 2Qv@d=?ƈblqi Z}Lߦslv=HPT+;gZq|tCS=K?:szMxrq?qIJ9 s.bKAcsz$x6SI!uf_7T;@]Dv(n[t>N!]6o;O.p*ȥ Ѝ o 1\F?bD XP0 Z/bKB¹sGBP`S=^!lG>H0Ёj"Ьt1ϰҸg' )Gp暼1TS 4sB'-=eK4d+83A Q^Jt!V/rrͻj~ GGӽ1aOUjZV8fKhh"*Iv8sV xX^yi+B0-m#6o>pmfU;lO$Ƌ]f%~/ahu5Z ,y"Sro`;б<У⴬,(#qL=,CL;) 2O+ DiM`rJꤕRG*$"Қ+A!A)9rYeR@S>rxQ|`e<E\ O%;t$c=O-Q9tKEOt* E!̆Iayt[u`B=½6Y ^fPb[LLT/9j/2+_Uȭ1"\ŝFymWMWI]yi&ph}8|)|e>s_dIBInHDՎ(ʠh drxn5\g|F dn9'2tt* Kx`8 gU] @n1šS7МjΕ`}M3b+ݨmQ0T(Sv},blsQ1}ejdy[V;V2 8w4@HV yie^h2-$?:pЦ+F"uD~ 0Csey-c>RLd,LH2hQƳy!${WN)h(:MSt){ *cz^9 LW: aWařNKPgS@ t)R{PJlz6d%=⤏< )!M/EdvR>b礙Q)?S gh eR[AEd ,wIMQ=ؙv oxGwjڵFtVOOqd҃)+PD003{tO>왳KqVW;c Sw_wINxü(xZfoڣpu^˜6ՙ^?ŧiB#\&ukA+fs,A:$&56Yl{sZvygd~E?EU7U:z\N.呻&񨲪گu L钃40G8q,$AtriǰުU1(Pol volYNCp\[eLC3v:L `i8xdzS oЀ Ze/D8m88YB('fb=mJF;@@jV[&<-cݪ|!E -jw:Ɓ6Cgg#t6,G."D( 9XzfEq \?0F P솱DhEn. ퟡ݃M22 z_I"ܸ y!7M|[7rf}=h#sl:sd,8&D H)#TqGY ~\I nHgicbm*c"tB|1wgt ܁@%&h5KiІvreYB=Ԃ\e+c_L'YtCtt}q{o 𺷘R"џ椕%F`UngQoP)ESN+=eYyA:Q5)[g,*,3%]wAKï[vWWm7s( C)Z?2kfw1 ] 0UNW¹"}rlIE}Djs.,%B~Eqe2 >Dl"*~n }{KFL$鑱hb 0>WTQD8TFJpCHy@`u*eq|IQ3WYf (L%:_7HzwɃRBH HUYpmyea6$#R=(LDU7dnM^m nm)E$lAmD-4*(lUl*T)&Wh bϝ9=|;ъΠfbݢJN~|4BX]cG *5WO(_bk :6VYYK@ bylGo3 o+D+Vid:[Yn5!.=TKK+9fUdR,}kљ+_#'J&?;K?>_·u=_5tRM8di )ɍ$'C@!Mi'Dۢ"͸ᡟ>RGPǒ \O1DPF4P c}N^]kEҟA;P"*C]WT-{1l`O!LxݚqU-"뜨pdk@ r VF7kx;#NXUs{67l.OjH)QknY*uMJdR֡ؤ3#lG\ '#NCWq47 LJՎ|, kӤ>n)HDeaOɵVrk|1Q߯꾭|8w(勩w%R. |!᫭ZՐnj%OY"XBjN~=*@pA Dbv9!oU,cvezyu/fO:F$vsIyRVjC5G9u+]Gt %x,L_(S:4Gݖb%0ib@խ=,cq%,oP>ma I);L7,% 6XD@i͍aѶ] Ωm xItgaS{ErQ?w3_R3dĊԾ$ Y fYXHpjg-1 7p?YQ1lP}_prszew.nJҢ2s eɚK"&_EǾ߈D8֖! I.u P 3oЧ'ha498^f|`7e/0S|s-PX>/6`@jG:U,|I6 T6u;PoTO:ߡIt%h>}(zAmN mS迴Ou  6\]vX֒WN‰zG\UqaUTp~}s7bWO-֋ǭ'M0rp6\u6*ܕŚX׬'#\OB[nWғ5gTpFE!E HTDːM'y7܌0< M,$Zg}|'$ ͹'WsPD爆ir*FG[LqMʠzN۬7^0jQP\Bse%_̣^"WEL Jl#,{nE"`y)*+6 _f1;)5'GsƉ?ݮRPG?R}I]HEYFByBJ9=H0 3ahdUI30,6{vnąS Hh\T׋Lt4l,먭*$!aFz鰟q4z)?vܸ\Pĉ v :NXW7<Ƿek;Q!Tê_P:.J;q] 0uB1Z[tJPpǩ1qx^K{o"6H!T֙.$M8=~!kwZdWMA=_6bF$D}mlwrU`kWe Fzq|ywOE-`121s-C iؓN~h}}=[<?lgH;J2T*κx6e: -p&6.+zkV_FsqcۯT#͎e0l9~p@5[0֯#$,hHc HҩS(@m4-09ϐS2YPNtu?Xqbf,sE'm@tjA0K4/s6mVO|N3@ KяNٙm*6.zp[XkJk)v-ڬŋ)eĔί;V?[ѧ`MɦV6WDLj\ϖy5]sZ v,1'6?"߫7wֈBQNH:Ф(/TgUm[z+K"Ϯ<"Y4Xd;Ú'|sd6!K~RYWBv(P^儁=9B܊҂ƽel#q TYk',.PQCi9m%š_a2.S#LXpΦCĞTfVSb =Hl{Ak9$NM 0/dEBa> „t8k"< 440t,vL//,-Ӂ. ka%$׍  ѻcx Ks D8n-$aK-#\.}C!r۱匇#t2L*C{ژjdX87Ӄ&&w[Cd5cu3GJtDlX\/4~ }ꝵga)09lP"u\%&êwSrMﴗf"j[ k4_rH &N͋t.b\$P^ê;,/Y`E63Y~PuMa7I=h⾨Pn_ ^(rϢSͺ*r(D!q66Te":c6Ce:DG1SJDN"tz{GuZ>.DT |E; 22('Gi" 'DpGó|FƁZ_>oaB-OGo@Vu͊;RUC΄ 5=w8%Ӣ?КW t1< bw! X i+9fX?7c@ͺh.f!1ΨN +.X"ҫ{)&RfWM@HV4P&96Au@VU-~m(n6}TYӚCKH9W@P=f2{ 9^2 );|HMǼ*UO]8:6#ÕyimZ(#2\*nb46hPN,{Eò}B볭}ąPhuUr,0'G~lvo[N #(t,Xʪ 6eU&%D8LSBL(Zi]/t ;]d^%4j)& :v 1vSA*ԾF mp8Vk tEs1 ⊎._. 2r(TYe$NDFWv"]%H*0JHc\<\v_ 8&Tdt:T[@ۚ/?ۂP  ý2-z9!8Y*h5`F |!;oIbLR2|uvrq< RVWO~ b=Q u <"mRkMFfn7 J>&`jy+Αk 5R *C̼by#ȽNJ9XO5ϮOz@zVv=G)%Y'uI"B=p>9*_7ߐ^#ې~a$/΂l$*c5P|3*.VZ2cp! rzAs0Nd9]'EdhrxRϙkܕ g7bUѻx4_g ylKb1">ES[8k>,ɡcmMso\ZІC٘dy%{)(>!C{'ҍl?`C/IM <[[CSe:4J]pVe"[OG8/;ɐ1@R v.={z*򮪙ٔڹ!^s`}ڹ?BCǼ/N8~u)83hzB-^/ g.6x8pn4]j5wYyйhJXIqTDuև⨬@g:6gS8rs>a?R~ %՝f BS vFCRlRm<7C{^Pi3?$B TXQr.Q)^'n@ 0X7=ӋU 9nXYXnki%AϻOCXUWQsWyEĂ5a{Nٗd|ow؇ -9\۵!~mۻ]'¦vrOznb4'Z]}xT6E@]12e8>h#g#{*ÑcxO6`d!˝H7YJ;%AŰ啃ڨ??Arsf_BH0ZbH,;ՒYIX*ڮ{p0ے` &׃J{pR@67}QK$QN0NJ/5XQxg{HJ]"A*JY=#GDU-DR MchL)zF.PƝWo;x~CEN//!"]s#Vt&b,N1X j4~3P6.Y[^im vpt PMpf>1s嗩\ݕΨ27%iنo+& 5p \r.''t .\|W[nkxmz̪݁nT˷bp~;x! 6'\Ÿؗ9Aw"F XttxEYV9WRnumߘ?L⻣XKtUw8l`Եl B993;a0d,{f ѷ'I;{x\g;'  Vt=(-0R C:qL2Ԯ*t1VA`mMf1Dkj{/c@]˾ dX*%)[\a2 zFϟKeV3d@~-idJD{h́z ѿˬ9q3TuU~^T*82RY<`FMZ7h:K wҮs*7D_N^=$2&rfUPAgO ڤg5M~?SNسXa*l_bM9ʎ*]77Z1UOuM\p;`ݪ01#םD pPU7DnE HN uf-24##V "+UWw4?}fgLw%cdŌd& r5hŁ ŧU%;ڝe(UAU%Q[$ocXH.#O]ԫtv=ܼQw_kw|- JxR>8Yּi(,E!{&Ȳuް9⦊å[LO)A6]p")' PAլڍ KG̓! Ũߗ]T<$e<=RiTj o.#hBeFpL\\6S (LCodz'9 `Fhgc:_bj+Y1iVR/|sOE9\A˞s s>_)ƹץRj[5$c 7,ʇZ(oyV k-#NtR4_0p4==LN*)5ӫtJ6>yh4c-{;;іxx8Ti̪E +opLQ;z?D~~ ]nӻg?w[QKPKK!- U£tJF}~ń\lpn[B$TP=B;kFy4P*aOmn*O;䦘̹>FjS;CIڝg7&# +>a-S@ڛ$}dկ߅aG'@ Ms@Om,5ӡKestФ|U٘s/CERMVw4K5AD6} mgn1yn>qN݉\9D:9\mfb:LCEj+¨F0+9cB T<jG\RJ#{H5 vtjZd "4ltӳp/~rFv5=B#&h Zt8>`ëR4uHQ?}ڳPK0 Rjٙahah|S5J3Y:\p -y׌~aB~ Hhʭu$ +b .GFy-9atdžӟ78ߣ1>eNoqWHwB5Zyv d"[A.m!:m:#KnuvN%PSWcJѳcFH@b uCi6tN#[WmF_q <˞#P:ֺUE'}uWUWZjtd٩ބ8<9/g$aB,$ۏ?ɠhu;0"nhxpZl ,Fۇ+ܦ%Lԕlx7ES$09 15OO+Gs.i;֎^\ V޷B,iV'\HSkJ0a.[o\?KZ ­xkejfvN&VUpy &N_kťٸJ>N&曒8ȕۊ#'#zC8' ⏄r.PsCII3sjz ^ɅW;IIrB.:E9*!QάHC;%sѩ 5zv&%*ylSi#\;L uf԰+Ylj(@a7fVqfabRR+1!Og[:>:%,X y!_ |` f}Ŷ68϶) R*GeM6Txwc(=2KE/7ԃȣÄ(t?rkieQ`:ĉo1w:+\tM"fxTc 9nзʯ0:ĐV8$Bfpqf F31EuO9螾0 6¹yOMsYǀ?&v/T /i<ϺqMĚ*N&JI*5W^6$.]OR(E\n ^}0.t̔!l0`bN;RTqoKo\X9¥p4+ݧ/2s$ O452"D]vQu64*|%2Rt s˩`%De;{wq?|m7`瘂Ff!Xbmzyfi?O?Nl1 e#Y@cP,yVUJ]!w^:Fbj,lVmR7Z"w ۨAx{ ,R3Q/bYpvK0>T {iC%֛=Hs̼`>O 8EՓvL/s(L`oSd٫;c튲aBÃ6(U$71ps'rʼO 4zXZy֡Ԫ{? vY-EjNPɁrky֩:I1eSQʢ߼!Ѥۄu?ѸBiTxé*35AM0E{M?ZJT3m*u4ŶPlRe'*:B?>ĺr|FDT dQux36,E/Bh%9)+n׺9qpLp5^߽{1\]'U2T R;; H8uUP #PQeHzG*l?2o^.[jEHhWBoP9xgtqvA_q82"^LLM=_J%){t]攃L9 i,IVfs DiO0Nf&3$H+^վ )Z}55pJb8d#o]b3M':B(t2>H: |N&ǔ9Ip8Yueiy]IE]Rўb4艹g^UywV-xOR=Z͊Vm;s Ne3X s}Hu nB/*/Fa$е`_J%~r*&^vء+~Uo>N@*2R:vMԆǔm{[Q: _c=9'hsZOI˨Aێȧlld|pY儳"KWw>ZoϹ";[|$%[ւ(YkïTg F19P%q+sI~Јk"_t s P-{T7|t OZI`zoJ}{HslfX/tOC~1 6 B]F.{XfOzz5ze ^.~*rL]-.ws@vwsGCZh(8#l9Thc3M= BЕ~I@fXU@R6hc8&"(5 }1fd|ܝHJ3BlT>Q]pkca٠Lf7<1MFgp4'zIFbD]\;,9P=-˲tN1QTC$*cSPTJwW\!8$ HNޖ GBQP[/렄ߞ2fXE N8VO *}\L^K&Vx~SV=UwE,ȴW#>g! ʷ@@ -H ?l] ˥K7OnbĊiRAQcӏpJOw<6pXD>{$N[<7CCw 2ZH(ŒCrGXN0 \b ]8m1S MuL? O1B OG葀y+0)ܚeW\6֪w[Lb~pjkKeF#oChTj>%ڂ1>GђWssk{;J!Bl[QFe {*fBsQ/BsS:txyB\dN7zy Oe-Rwa?Mڣ‚bɥT6ju >M"O~%4uvX)[[C5K>(*u_:Ycc)<V*N|k*ؾu7!$9ݵUe_ʐ<f.҇|4̃A\<0{/i,.ъBb4Ct 4(:p (%i(~P[e"bǫ aGFzZ" qaDp'@$ݘCI]Dzkba$%BvN!k3s&5fvǡ$|ak`gmꨕI=725TD bHuM*- @~ !+ױ-/m};F!zUa *`UQ6cnŞ(Ab1=7@Rc)j/w͍kZ=\w;zcRRzqoKLt@6Hx`*HP2j( gEF,x;/os9@ <v l^ץeml1KgG`4Q2AXlul"q_ـ` 'eb<0GOtw Ii6*ؽ8!  ڙ{ҼW\jFc:@9^/9@d|2(D5s&@-A䖙4Dd9Xc0É7K|Ml%eD>訌 4L;p"z3M'r( h%a5Zf jw;ǯ6_lmIsP~1IM!N ÔqC2Z^b_퓹iBY‹ҢŵՖ`x/P= ?|Q[S5hf5|x=<˕@,'T?4 'D/Hz5bvQqtjeNӾX'?#ҿdgW }r=:yrgUT[18\29wDrc ;BLX'ࡽ&|e9Mo_R V Yߐ>bU.ٰ!z _E~k]f}#n-0L_HJd%^A)T=豖D<锭AZ MXuk=MP@fp:o1Zd3wt 8oq*#*RH40Ćq=Ȑ#h<eݫ8U8p:J0Ly{}2v>QX0JfGy^KaK|gog*ᲟtH"[j vMwX2qUwBhceLdܦz}fC=ޖ{xyzP[S.3* G(%e|!uJEVfZd\{7$R'%tn)~tl~4Šy6tWAY94p`a18X ?>]d/9[t*7 lsZZR%mwIA'I=K.拎ᡏ:{G=YaK2Mq#|yp؉&9$euZG4g:Wv̀8C'dM FN1$}Bu>,?;)Csl ]FZu8B{|h&eblg] u b˷̬qQ15dܵ}0Mu~gwTG)d'͘\| bʷ]SC#zoRZ5)2l~_5B!DN"'><{d8d)'yT$&˙6`7MO= ՝"hv'NFl*Azbg۬:F8je+sWškνu<׋mzM&cX{/Z#bOm.FWOu_R]j}xeXǨ= dOD梯W= P*`3ߛz^b&Z,QD6UCƷse#gG[COda.|21<0W}X5DMyo9V^(o^336ѡxhpPr*R? >tD9DՋߊT @CEX\t? ‚WŸT H8F[aaҤq ٢豫y5J>Jnƹߴ|w榮BoUC$Z!ː٠!*\z$iXiJV0@84Wx\n2<ȯڲ; %*ף]హ[#9]W˞l`?!P8 YP%PƽVVV[NNuwN}I}]*Hb)kXA;y†+cӳe*lI[tDjdPY7eIcBo"E[,mcg}=N@k?Zʇ譚;8;.8lu. xLE_N9r1 >1۞Y](t6qyBG"/G/lX,6%35ji7C9>6y,?gsp.;OǜTwאcUq俻L1vg#˜p*;ߤw:0XJ[O_f0B pkw0]-%-p !#3I+A{&8Ɏ&N sw+v/EEqo qg΅ow0a(hgw/$gB9q]o^S"C 6c!yݜ-( ; du6IM8}B=ڬ ^0%J/!$QFFzq%Ij!<85 ;s P,rِŅ@S{Tڿ[QCQu_ؙi|K& ptHIÆ,s+8i!MdvqKSݕcOuL6c$1g%bI=eO<;GD # h$p6PS89]ZѤS8͝s &|8CHI56DK Oz<.ҟWIu3+og0,yYhd M1N%Hnzb:JPܕp>ݨ}gӞ{j4pXn\.0|)" $\*De f(\ (j0sh:9Cszu1_r ij(5FGrΕA.=S I #-%{ʠΏл~qt"-8K}u 0@{1"~Vh'*;/ MxVV&*t'LE(vd%~aS D/yb/-6PKB[Ib? `'.Ȕa@a WP!b1Ļ ׁSz/m6jQقw^6ow.Um MopgTlg 5gYɲ-t\aa1:;|!& @<r``];r8mrMXPTupQQ7o0Øc]ۆ*xz=BLWS 髈%ysQ>Q)}<>nŻ%!ŀ Ij\q1 ȼZ;d)7?a<Ǯt heUޜ܎|L"b!-K2#lKN2t?Q9dl?y$3 iB#|3޽Y|!-5k9>ʋNrh9 bKTL 2*Lb^ѧg \ -N Sid6G'# ]BtzÒ)!zce٧:6yvI ,> `T +mμU=kܴhiZ{j`K|v'}̨ µ2DHP, m˪ӆBatVUy/wiȷ/SPI̫%qm=ܦs+"(w8+,+EobLdn֚ƲMCac YroFٯduOQWXLNIV夠bu}?/spq 0dR3CH#CR#H4,KƷ ݻu{<Om &"uܹ]{MfgG%Qs{htFnjVmxÿXk90@~A瘈Zd5$&Bst)S؁*n %$ELJW6W{kwsxd`g_Pȋi&]"ы<Y-\ĉ6xMPۖРOAIBIgvYaz $Hq$!_Ň{J-UA7lWMGH^^{?n2~ U{ Jk9ahKd^uls@?h j~O7ETbiB#o=@lE$H\CtE["l ro,.-%f 7a]o3 d{;[6;67noLpDju~Rj?w?qIRnϾQ ._Q o})i%qU+zA/ﭯMyF;ӛ v {>\N/PD9~*Ğk4ڙWWK&qYrnFc:ʂ˕,cCd=]SVr3:eP3f}͏l)f3mnI1EIrNJn~UqŎpGG<29}.ـ(-Us\SOl4r+6BsI5,O`GUxRȟ/yѴ{uW]Rj.1Y<t#m:=ej^X)|Lx!m]:8gr4=_z+P݃YG0xSiB9&x9`'8dsbPo{L!$V+_z9$HDk*tQ6XT4mtGA|x٧vL:xN/OZ*Dq#o>n8֎t}YGI8X"qQl4L#\6sJ[pehMDJPղXUKAj=GgXp{#Fyf 3S;;y|Ds_r7[ ? Bc@5Aב>K n> p #q &ujAa>rڤ| sl-(c f R61U5%ac)Q,ꓗ a_ <l M HsQ6- S)9?tQ7xH WH}B+dTh&Դ.s)qt8Pġž@KHǡf 5W7jڊ\F'0?7zp)/r{e^BI}ઠ>xXҋzSppB4a5 ,wzPTͣat5,dJÌϯR"xUl <ͿD-?\Eա%wB@>4!OSJB?l'\ #⛻0$`5?G\[i^VH7͒Ҍ "+:Rp|m#\` <؃S=NZC]STW;{>Mgo+QB.G<wTsɲIP+C! JNׇF O+N"1j3Q-quQՃf=UXɾ,Y!",V`0\7hCަJX.U@ džlɷTo?}mt\|#:<>fik_ik+b!<@i'LvLUoduMgl\rSF_~v~=?w{R*~}BWpqs&Bpwݠ_&ybv2/3x7KC8>VPj grG WXȹYjiN.aE*[z2Wy RQ$El#Cu:=˯ q9YS5>4D}HZ.Bzh R@' C[nRQU~&^TMŦDz>;yu&S)h3|MC")y Ҙf2B#\UNS'05 I0h^ <3μN Ug5IU=?0sũ\ k|~tGli cӜ@S>F{UG;R?Zn)I8Vћ, V\)>%]L|t:f˔zm_47Xw;EH7"w_%_{fDY U/(- sJD} U$*f)sԑ;چ"U ənnHF";@8m@ E$$ZЇlqM֥6Xp5GOjϰxb8@VY+ SD3PnLR-ۮ)nWf(>< m^H9]2Ql/f0,L_n%;R8oK|kupk/ 913+)& |W"y&$#{sU17K`=ژx6uʶEWETJq>s_WMʃ47[f=RzIOGkr=JP6Y 0@PQ&6N2VE#E;(_-v&ФZ4CCχ{5 UΕWC9$H voO/ "(.+2,+}SI_̺熆? oAU9"vN!Z>"|5]3/ T01Kjaim CE-W#ONsoNXF앞e I|A`EfTX'MR=Ou6=i{=E]KN 6pZB-ό=tO '=4Ȅ̙C:}AfӦt5\kI r8 +G2{X^ Kag!IL1YUffG͵buKU'l1*oa9˃[W%s;r:b+h^ sZ M"i0ߟBEB#kdrpwO*m_xQmmU4I;cTY+kT{)b@OδX2U>L,2dd_m+)|o̼<85[s0ZTvFkkoK x@0.q#oLnA3PF+`3j٠A1h"j6b$bVs v,(Cŝs'4FEс8ەA><^@c Y)npta{;irQm =4qclj7%sƳ{O1/:p U{aI|pOޙ(Mی0o ċ)1A0*aײy^Kqc6}Lf{b]RSUT(ɭ[HęmIbB(TV6%WM8鍰#,˙x[biixk|vVC!(ah@)=3"4ّ5>bpetIR!z\DJ%xm%%~񮉰Tti+[%y`Rq\Bp5qs,n{#ym^hNCnl\O&)搨H]s#:_yGo@Y7q7w Gi<ݫ$SݹEγ7/V[Cq =D  5(w萕V׳޷%9g>!fc C~/qdϊ 4D1Pִ h?,d`?4" g|6iI!.\KbOvZ"_OStf$ " ؝63 ߈b0? u= U~A,f#w0*o.!}!<]o7T'EhPvHa5)(WgI; a8rE:4<-D?]|\UTL d& q--twh]|g_.jEM:6_Ӳ/lf^B֨4"nAP^$58֮]neݳ)E_t9w<>Bv/H)3!نSEFG=rpGpMkXX^lOҋqOA%p\rL(6Qڦ˛?tʧ#q;]9!ȴ#H e\]!*BQxoubmrpF9D~>͚I vaQRȻ=/hY-+{n&\ 8g,D`\뚠YU*Ñՙ3T *̢`]?aSZ( ~5nM), ;EoŸއ$d{ `qkft+s(&T"^2,UR8p.MՉ`زdhݥriqKeêڔ]e"FpI,QD.$֑hUj%K$l4rwh$'F8,&R#SȗΉ\=5(s&Fgf,,,4fK11PGzd>*ң}<]W"e^Nx!?[2rZV\Hb2@07Vz6#k%bI91 &+((Ěu>wkH>bTR0VQz"hyI2PڦKE ׀ca7f-mSO+wq[Z_jsIg0>5z`;9ԽI*IYMjd'#sT8n%;gvYM mb-j+Cbue `.!KeT;5[/Snv(6TZwX-d Ǡgxqexs}kK's:|ԑDuvL|/_Tabd[!@p8Mif7=. Τ=%P KŲݑd y7DlOG9@f8(v E9`)؀U9A(6g6k4"!c7e:"`sNn:ϑg{$I8sՇӫWtd!^yNK^"!qRRJQ)%&: ΐs]y O 2e'vL^gL8;Go2T{3t%=Ntbv|*O!B8(HDk<8)LVi[̡<' S;ĵ ѡJsY򨱍 bbZKXKICn 5lsm >٥>R#Z@q[#%\]ͯa"? _Y JQqR$߿ ߎWpҕs}՝Q?N98w*.T?ةpJϾV$CM: GfHD,ð{c C6!Jt57*%Mvo[@;XGe/ŗkz"c<Kz07\ˋLEνG?=ɩ#Jڀmc]a]u.5Ydt>v5\n(5]n- ˛hUÐ{sA,0Fӣx]pݨtI8c/j:,/Mvw/e;'6[bTC{WwB.kGs8LϺ ~Y4,@9xv*xp @bs {YA˦{y!2`$͍tox mܜa0H"PU*6^ ّt;*Q$ō+-O,՘ՙtFnNGhFI;65T-قlwn.!qQtK:A:A?M$?*nxk$x!=vѼU)&.>9Mp"Kck-EmSAz\B.HZLU{Qf[z.T;ʸ l-k&FcTcMO$p 7-tĥ00 =FWZ6smw emc 5Lf0gТZ;/fM_/sH۶lF[_pntA2m=$;G`]#B*|K̯ Jc_ o^Dk}K=Ū1n LL5C^yRL%xL(?]I'Ŀ0L譲#x{/#oOVIEe{v&9I㓝&$5`hx\çfM+q<.hNVM&cCJc]2cI¬m];@ſ7wZ2_ĤJs:W4)ah at޲D !s) ! [!Vc>ȕV6]u)w\u*`RX KZ5Z1L5&'Uv,FDZΘhzz֘p',NfL4-.b5U6vҲuq3V3\@f $t Pt ҺA-p@9L!фwf2{NR.'G LV"V)5C9XP̸|ۯ(A9C [ &2RQ|9C-kD* RHQhQ %lLl.ciQtSJ܍&C+|:"w!y% khzr s۔$/ R4в#dWW\d\K&jכPۣDQ1С\+CͭNs'ܙ U;鶒h0MH~5*`j!:r-O"1˹F n&D*t (\9??`\ rgkEӨ5#JT?}r:9JD\3: GMps:)\;S.Oq>tFƻSjG8a0r׸A#쭂o>%VfX_ J|,]ڕm3HZrGgș 7A %,6%J{&W%Ev0k8oBEEKK$&91|䙽J%c(3_e @.guO6أS+d/ Q;T#oH jpXC b\rG) Td, |w׵pφ%ڞ_mod'i'qYbXmz|.Omr<ȧiSF#$KK[R|b2FLe[[ifŅh_0af rI_JmF+Ts$~O8?H |hS9]tG:~ p6 \Gvն# a:~h!_5ܰL=2t>]f*#8 '𛶍ӦCG0#;37Ѿ'bMεsW|fJZ@⌋xd[}vHFlD_o ³=,`U9I$\ɾL([⫲Ǒ޻[-hI1X^`9 =Jѡ嗖%_sd[:8bPPK~ew]^'5K )ʗ"l@'AIfB uDŖjEPZe@͒qRy N K[nwr uP\Hю*=OnUW0 &+RR ʱZ+R_6C&P[*MeUysQc~ jCKY|k M;hi>;.Q$*F;:Q oCu+pB;?w^*IPrH8F)ޏ6ǃ1It_"ȀB<:2fwW?^Z][㯾{rϖ6&׬ ֡!fA|p8ӵ{frS?@I3TEAG#EVgw0&w1`.tbΝSpaR#GD>u0kAW,dQ>Ip;]kY1@;^dVάxK`:K-'G\Cg@c ͮ MbR]fqUwtPV$Z$yxO)d~qB!,swKre:|c2ic[ʁ;cٻL-0)|@,Zef7a|7("35n/4 /}Av sUi^ S;47[ -!0ܢmU%x7om[r.+mK6[2bVh|Q!Ŗ)X#r@6> ׻^h 6X㸋k?ZAƭIh%!.!'sN42~f7_e0=.Fhu[D5%A%&Zmk" Rg˨s׏nzsFh/VrAsnlPv`V=YdZ9_ 'ʦ+F%07z {4+BIKd;jNJ}v ߬6${)ˠqO vK¼y• ˑ\C.l.A9A6N5N^&{ =}m x*qb+'{6'08 ^ c0ZRŸ-=Ϻfz )wk>2NloL%Ρa7 CY!{8AaFWL#/.xnDG8 p1XƓm><&5㬌S]pޅ3$ FIl)W94b17K ց#Ƿ*x^!liwZh Gy{sgKɻNP𻣙5lNHdm~()Mg+xhOVY;t =Wa6=z0ER1D`$ m RQp*CEw,k'b63'KTK}4<͑ˇ֝iS9+ϣ}c8ohi㓀8pzA%w"+8!i?DCEtl|R|~`v?RQ>p#J0z D!d.̾ˍ(9:O5ܿ&gw(= 7 Vp9I}I1)p҉,UoRy]LJ`PhSalj1q:ۆ+c6̧W[iY-`V@  7Qj^@w]!hgY9( R>7a*58vP=| qW1O¤qv6vǃQv|^;lndKre=5G=95j.ibA4\a;ˀZ]L;q*IJOIQǰ;EȾ1CQr:sH~kܝ𾊂h4(pıAXnHIm?rƈIx99T}EwTrm֌.)Q"T2DT: ># ѹbDZӋKa{]XNuK 36lgc/r,[]3dd>MոDT)OoL36«|Vل( G [irӗ̛۩;_ݿ\r_$ Y%E#;ha!04/e8 R QAFcw9ԉ)0 Y ̀|xf8r;3!GjZ:u nVQq]Э rc46al+8:ֶd$p8@Nh%)OK9Vek`!u 9?vEqUfPH(exK!.Lg?풚׺$\ھd.L\'ޗ ^$n~gbx6;Z) vmN"P̜22Qxۣ ž3הU{jÊzi_+|֡MP @*ݳ ,SFt';i ZLe)xTޝ"J#w1q`Ta~1A R xՠJybzRhyFH} #Q( ix/ןLi:âҩ~HSfkٓ [3oH't@<{/w wQdOKzy]lYGy<y IV4^V,0.[FJ̳ml-}Q9uyk36NܩVK2J@鐎{ 5bXZdBk^l`&YX9K8ԭ2x ԭ9߁=DiyrW};t,Fv/J_^S[=R7 Ϩ%+K]s!]KpONP6\_½[< `|a9:^ץi내5 Q\Y1=G'"oQ #\ ͚!%CC@vlQa> <|7 ]lN;X ɫ {G;[~)S=0n>_RS?tg=`wUY"/ PQN˝= ~ҟZ[쿗<{r5w*=wˆ$LCJB?ChshY%1\ϋUBC _[pXpo䆋 OHsRjh77iRTpw=m0VUY۠.l9r㞲6@Z=܋azED$* ϊL!9caN] <JUΨ #NYAw+[n]kZVViXmȂ}>=֨:T:_]ț6M B1,IL # zwTo' i9X15Sw *ѭ}sfs2Xv86wG(gkD%?#Ƽ0, S!HOId^\6JLDPR]އDae1|r?7`K1;%%?e`\| Nr&x6R'ϭ|㶒mP b<.gP !.L GI]i;3bɨvssZXZH{] Ű5T̼[x裈JJ ͬw2tOF005)P_=u"UcYchDki%&y%)Jl)[UTݬ5$SBC&RФ $^ѷR9`@'3۞ي=p&Vfts'rc⬈{_2,o qh(!B =Fa{z~E|Xb҇lu=d Pɴ>1 I a5Q``2[ {„e7S$E@Jka W =iwbzV!A-ʀssv~AtT@#J.ōk\9a٘+vXA*rUgBX]'Z6[J 2N t$UTE'2[ X5clF%"%pMujV|EXӊWtuPG:.UE: $ 1"F7[ bȩ^+'x A^8CF'qwKnsЩ"iƘڎz=ϟ҂8TgNSޑp` q[ͧ$Ih_ỳ})IC.y)H,8+6L!ng V؋ LG{JɢނtU6udG,s|wr.H>=Fiq[/6M`ʜΦqJv2?5^uz͌=a{g, uŬL6>lبrY2Oҹ"R4RWO.śM뿓Kjz7%;N}퇆J?5[f5jjkZ-Ռҙay#~L^ \܊ ]R@_e)4<JO2.+a9j}\5'o6I_=)^n~a}fBf+G jvu:Ѝ";/pC IpÀcʤͰY+A\04Rn@Ā,bcQllU=e3)xqt49frv\s|)c! 4F,6Ѽ_#UCY1+vd뗖TX ްo\ BJP+UhVoFG{e5F?$ҍ6d)\.dwbW*^z>19pQ^ !zxT/&`¼Ԑ - @|yc Q^j V 8|ItVspQ+le_.Z0P''tl}H[HE0 ("o7C6e`2auvn!9p5.fsK3eMx}Z: I|!]zs Q ?xl3`^ zi•" !""DBOlt7'Du쾘- ZR=&UuМ UB _bFg;$]()w?AaeT[ާR;pw3J7ycB c, iJe6h/xzDʉ=6k}☔'kN3t~8FitB;+t\,c !_JC3:3|`(EgHW /1BjE2#(גPww[^[B[^ w}E _Bi~IF9K? ,4#_:zcsٛ;wcwb;d-Qq!ȃQ q%|2: e20vowo="p59CB MxH٥a=n-X^w_USI+z랗E11h *V.?psDM?&JѴ,.g,x?DDauMWE)6_JUZh3F?&MP Zg\FE P{@fOo/?i<wcÕ<0סR꾁eY$m0kd8JflfC^Ba~6FSmBGt(0:$-',p?% 9r)9}t:zƚra'5qJ-w5橯ڲB e<쮡Ho:,x!`bpX!g] -QeR-?v/Wtb`Qyl$o#)Nѐv|q/>.Y98ZqjofZE,&_~P4QJԸZq'kLKWGlբ~u>} ?{5+$tڙFbGjRTdd(rô271>uy[.k&a[[!^M f xzsxjl<˱d-<- ؓO2@@0N~RCIS"F'uVE&Mt=1XC6I,lU0a޴40wjOw޹'8aURfxSr-?[޶=Će_S?읠WJ ϼR lIߒ|*؜2_az61tIXTr>Y <P_wF.bf|,AɉuFSʦKL3#'~ 8|ݒNҶ Zu7A@˷]#U4ݢ9ۖgT3Xɫ*o;ѐxjUFMމl 馈6qg:HUśKbWxߩ(ZD7&hx'c͍U4@ݱFYv #ƣCXR&T5RO?8+ D`tA1rZ/!تZƠŚ(~[GrTlrc۵1氍ɻ'=˳3Q|~瞠No_p*#WJdž *xP 2zWwL!B;$?ș@?P},q؞\ i)Yv I¢hra yY|hXhَ|V+6#׻Nug/Qr+cSTEisgOFp6hs]~129A|5H_mE禾 uF0U OФ!|ST.{]6F2)u㛕G7`pDF8[.PUZrRM~>j3ǟoa-H& Z/Wv3HC U 2*?$iǻre/cC>k'ʁe5j4#LN6-aǾGtII .dا0Ժjtf1akty".zWXűr‘v PN6jR~CIUd;v6)Hk8:9dH@?!B-P"BXBCT8z֙>LCw('z2ym2kWz\%;jv:]G<ioz0[ ee_"]"WSʻimE[VY}Hzӧ/u*1rYeڪT$HQ;nwXA*0z(GlfGѹt\yqy1ZU=bcVޟʟk C]+Hh)D"ԉ.&3]s(a،um[DɉA4\p`*($,Qj,K0{Q&*5=Sa ]r띧h %H"|HdKű&С2,9ي\cS jbEp=&:l0PȲ/5F:JE%h̽$ 2F"'$/ ʡՌ}\ɐf\2z}$6ʹ6~I4]q,ŲlTr}u+XCT8'0:…S`IgHP*(>-$<=F]m(%?3H*oeͪ9V!Td">Uɠ(6SYC uBtIξVS][{G~NԝL9U<3ٲVٳ>.hʟJjs&8%Rɒt(;' N=TGq`{VjJSEYX]eS"s/SZ^%rfH1iGXJJp'N5aj<'fou\|FwnqDfCnB.ٸx:.x| 4TÑŰIΙ1ӷ-9±I03rnL֒s6IP't4<;lLw) j.1nv p) LTmu >'!DzTy˕qAAɷQzJV\dDŽl+lsDsd>&A┃Ā28A.y2Fmm)ɀc Ϟ AvW.GU-vhDHEfc.Qiŗ(yLht cE PeR7Na(o38IHAѦiE 2YRͿX;{bs'[xV6}3nZ̓/- h?uG3_\)CU)$4>[gUZ7;>~9>V-wٴلއ#_y/M7Ah4UNj;r\QK["b'۞VVԕvCOډl4A4QC)e*˔ rm _z  9t:k>ǟu.5K68Yʫ1;JO_|in3s ?X2NcT۵23;bI1t@iiißސjD,Q\ l(*v^Ϧ6> <)hr+ ]SEe;\Tp-S5$~T76pk|f߰ P/dŁ;4SY=mMq 6/៍ŨO Y%D:8Aju.?XT RSt6$}Gs :WI.PFf8S]2<נ2.%`<"us,(`V\T<`؄!IVHhbK!γgbC {3DYsش_ݴjep:#PV8 bQ "Zlqi[&]#b_w/6qJ5bAg:r]5[>|#YLDs.&nUE®YBMNxL!.f0i`HTMb?_s>13tmhRG&k1z%fbq{ZH!8`Q9DjQhb[|&pc&Bcš>8'Us ɵ=1U;m\?7@H2L!+smFKa-]g\ZwR7. qEWxi{Ŝkzy3 x஡}FY~1f */F8KFhph4($*X$9ߑ#ZWL#wS,}"LLqo߮iٽ43Ԍ8N:duyLqBdvvDQhH4Yty3M0Z}Ψt;?s(H*IL;D [H*69?DXWZvni|O=0k@.Lrl_tmd0В2D$Uf61m0WvqAALmؤtU7K.1?e B@j.WG|S̮uEN%caޝh4 J@='Mn#b~ PA-ovK67x9 W*`ûy FWՋҏgDhJ{g~C4Ž_~YUxn;.?24klh~lgn@DI{UuĒ $ҳg㛏,NO'э4;E!*xUliÍA ON27DG,=ᆵU;o T9`Co ZؑGq}UQ tKa]p}"Lݼd럝x}uf_}h {~6O   4\]yu}m'^"hFFb['5vo($,CZejƝE9~!fsB RE=z $LQV6V6X%˞ ˆ7!=4]bhDE+Gj%M;b{.uY3 YύQl>{$&<vH]WʉfV4Eh~u˫!Kz`95ɻ͉+Zsx*,89 ֣BrSL2)[H+t iʂ}NA} +̈~T]ZyC,D^J7wsZ0"V7I?Qg: ;b6ߔ7/Q]4zNy\D*3×hҺ7rByHe4]|V)ё6)W O~yp +ѩdLJ)O=ٸh%T[gw-SIg#CZ4y2kTnF;#ԏAybQu;+_WQ['><\WG(TM-ƛS9Xy'Zr nJ6]}EWnt;^  f!)E >qq>Xw ږv/!-x} V)x*P Z__&d[s2}wqn:2U|)7(R 6H)PZTS4(=MD<h*7&FQ3yPP5.bKrgςC?,JV7'7t~4gt; wi}x;޼[%֦wbn{߬|rl} WNo>߯?W7ѣW}pq+[T7Z3oY{ZLfn5/V+[_]}؆}սյ,BxP>?0ulgx-/j7_QVQFg+H~Y1=|r/ v0,ja|V? ֔Z!~Ƴ d@1 ,$E>O>d瓮W u{dK'w9tj4 pwnj<λBѸpÊflgKR ,jmgwsa{G;쇝0Avvo4Avl;^ϳW泝ݝ`8=3̳ā̜uݝgSvex嶙Ag #4;4ڌceۛ6_64f` s6&6`3=l=hY6a{;/:{[Gs}!|n`4uhP;ny9@ x~q7}+~_O^\goCå Osx?M^sxn(;fX1em/$& =!4sG`4<_j[s_@|=7%pWȋ8>^5lss= Puho4w3G'poaρ$k7c’xñE9Z0߸w̑%H\B ȋѸ&ivĜ˟^Ez0]/oh4y ?? hTC à6e5t} ͏T 9wADGJpMRhAZHFcH&hmϚ`u_'é d4`OQ'*fq>n}w)4QP<7v5=-F2ZEǭ27!YD98JJABş˯ ? u~?yˇyދ<$;X] H(Wv7=S#gF5zفf<=:ya?=}s0)*)F98?8P38#Mp<8!}z_t 9?p^O!G $?1٥?`2vgFRMCOo64:W* d⅃ʂag֜b± Bgy`l7mP(-92 c`)xE{U能{| 4,Ow2'Zzr@7#M\`xH]+۲C._Q7A=qp.;{Aɤ#~z@NUX#A6wR ]C,s pfS3Iy#Gh h_(#?ׂ11\(`PQD<9dVeGtHqj:6ԛ[|B$ɠ{bmr[߽|ua&D]0!Q0N ,bB@p)+A4lMbfilp+F S02{k=G5@Qbr A+t%x#L6Ha,dMGAG>z>?g,_+ 4tz1 "?/x:?Ps|VIC%y_;l˯ HߓAh_ b?;4, T$b/(`D8tD(R/bx4,b-Lt_1a݇>D {uteZ;94AGdBC s}=P2Li󱥬 VN+z di/*$Yl'.ѮP5>D](1ToVԐs;<X r}7ZP+ڒ7V6'QЍ].?*}ҟ^vq8?9z)9h5=rG|g [Zj{X_&dQ"9<|"Eki?M˔lDw\7jW`k @Ͻ<{9HOgq7Ee|4e2,R^fJD2/D y~ê#K SUOW"&IʶS^r^3b%T3! I?\Z+lnrk^AEˇ^ˇQKQbPCѕ{/ RKDeǀ]O6Pxx`;.,ѹ~&$;k~LSV}l]+I~ZBk8-v)eyPCkU IxaO&ȉ~7p4H丛c\.?1dbhKX`x}1[jgڟ8na- 5-cb_Ũh6Yiۂ[zC/ݬ~]mRXƎh0҉[  tOi$oNװpn!瘭iE7N˺,S#z_y. Aa񏟳l#m{ \־~WiwHncM^hZxd#(AC_7Wg'1Oy>GWx%QD#g@|7+_|mzeǫ.ŠO X9U~e|9lo Fnx3?<&m&KvT$ !!@6lQF,D}˛A4eK+UrD=?)2HV[CJ#b+T1wEe4J|6]j!Z+,t`>eڏis>x{.o69eR؈ǘ):Х[\=z_'XyA~<.Ìnkbq;ky P v<7=Y5p:nOd0 ݨF{`͋hDRY[H΄9& )o|Ir?yImIE7Vwݕ  q; \'j\*=/:zMiA՟:f~+LZ df(CJމ$Sx 5kJ%Ԉ/9rxk>Dyd[𓫐aD0(n7QD7jX6Ezq3-[` T @h|+@:nkR>e]C5*/OtמLGm*fNOvԱ.OбT8RYkO~! ,`/r/-ewW*l,DݫUfSP xّ\Dkn^ٿ-y'ŸHINeNx~6^[ũ&'ӥdRC tf4/ںꉾ،R\0,×ۢ Un>'yQ}΢azjNr2ōhwP g1O)ROk (ÚlyPrg:$C1jnCՐQQ68 jp"Cěq[l ԯ@u@%a!KPIjK];2*9 ޲ď;>i)*^sU{{tog[*`B¢ϓE\&Z)wpjH3` \oBPwI{לa`̭ۗq W†*49KOJgmK;V,qTx)倖3jcDV!ܖȘk|-4,T_ȗl>K dNUK;\ M Lƫc~ |iى>O2^# B[ѿG:B>@ Ǒ S#qinWy;,h߷𴓓x\Hth cnWrϑ~iZ:dXw!rQocڑa uߜT¹9>!Av..\|*xʵo]|~`U%ꦊtpm];qÁE-YqM+Uu'>&6"AvQȱn$%ӑ S=\A *. N@%]%T6ΏV!FU@jǮml͠l0]U.}6$'#RyI _~'Q~/2N^W< Ni)1֫B}!ᤐHF [ f_NROQwKJ0„$H&J߉JW]烑0q^fYC~ 3)NGٹؤ3<AʔblVrʥl lD?e#0Mo3廣[ eo ^{ݺOmO9Dcl}nEYBIRda[p itA`J, Y[;V%^A.jNZq'{?q"N>X$>PԨ>is\ݮׯF"ή_*L|G__~//kke΢l3gĜ-72#8xbnTv+,K*e˼iY?JY&UU+X^w'$lgIHfL8:v^K^7$0_w P _*FtXPAn>bB6,Raw(gg { _\g(= y+!@^t.{7\J8=lz-X fOFL@GC<*~,?xYdb̛;pg}/@E1pa4]`x;E#4a6P)/nFp44[2ID G\5ڍΞq n3Õ_Mi柋f'ܚ-KmZ [.du\&WN!ϙqr3G &6[2(ٷBʗ~~ e_`0/op-DO`KBto w h[6r4]MZ q?cB4 4{<=avn![}L\@3 KG9Zw=nᗩMP_WP3ڪ OmW!8`R]c_X0YGfAUd8L)\$U؎GRcom?p$1j0O@~KC;;K伖v4~V&t$ݭ,@&QQ>fpʾ> Z.\Ub%P<0_zc!NV)kz^,<>̟l..*x}g|P@1 Cv0nQL/&a^o-_Z5ɩfz&Y>U_C \me377R N$fXlh c#&xiЭA  8[G?HkK"'>5FU?NvbzEՄFUe@6z-Q@T`IJT3EA@Ґs3sJ`,]4w̿/G<J-|YH {EΆux$2ȶhONFi\YD>oЬ,Ppy *@<e1/2>~T9-8xDMc_k?8#?¤gez J AxZn w`v!a0jkv(][-ZX8.ZR>r&t/_}"Q> ]P%.UdWl䝉kĶ/;QSH͞᏾ ۴qm[/oC#IpA~mDbPn1ר5cGT(^ GX ]u!iOpiVît jO 6'IcP c *Iq?:B'J[>#ĸH`76 VޒGߊМ u1Y Wx9KE(%ojpgAKN$ pr@)x# .@wuRD>v"UO ODW9m>OupZ'rIf=$CzK@I-oYí댸ejzR/5z;K&ĶY3*Fdb$} u9?\`>ڭceb)W P hz+rg"wM-  bE@/لtYu aCC۾rKL+VDI;(ljDZFȌ HdI2a(%Lik}KY,Xf]kUnxyc7|URK)\|Y bW$vY#^y`[ExK7pX}z.fR]iW+6 rχ03#sp >Z0 BȘ&3$Dq3_b1v,aͪ8iXGMDJhղ~r+NFTZ_~3:C)Q.mRaw QkOGl_=,]I ƸoPa.V=~쓖eDS<;~Ƴ!C?(/ysDe:t$R?N>d#auʦ#t"򍃫ZK" B^x`^B6=#1K2xJx!aE?`~^1`ZKl;{qvJ"{x/?#޹nj k_~ڗ@_LDާU(|2*3pfo5$YfMSóljgdvEoENר:gO?뭟Ly_۬=nh4S\$fڗ Vu>(4M6ϿM)$]6%[V;[G/)F+2x!4T?t|lp j3j'\#lN\TK ~Vװ5Z.SO Xn]0Mc>fK+_7Т;Bfʬ+T@vK/oAb10o^k1$Mble-╜݊y}$Jm@~ca/w-< ~~VO*ܨF?*:9{J¾D5ZivC Unf9;~O)_24X&K(ßC}.~QN["ol<5\ ;VS'm%N;j"L4 @bQ.'`KPD,&ǜC[ T0*D̖1s>3q6oU_mAx0HT'{25*"y.LCBRFsQfD"9BG =9M0N ~xK(zw=yBXsYSӑ9xY6E}cU]K`d/:"x`:55KխrgPi@A˛'lT@W@vK${WPĉׯvi~!% M|#g~{'͝D KiqX ~;?ꃰ&44xK)miw?MB.RM$ԣF A?;ra[ "mn8bN=a+dvT3T2d9݆ԌR%e0$Ri{\&NӮ.1DJ 6K Gol EN1@a.)+ohz Cϰ avRZ^4&X<,*! [!tI 롤Z|CI֛Z2$)O$ҩ9JId,:6r^VQPO`6X& ,U=a: VXwʺxϳD^C>%w 7FG˓s>%' S bfhi +OLN__V4 h2 &:|ߑgtߑ㶜J}D@їn邬0he70/9&!P|N kJNM^ҺUӏ{^!JzkOard6PISpІd?008Nv3GTϦfUb ,]HxsJnCFx_) ?;#s5Q(7NdRByסIiͦU˩ElS۹uP\[-2izcŒDkrJtc{ v%)쿵!6 7D dCnlDf')t՟,!M&=@٠k ]+ke X41J0$*d>yag7V+Tma*T!W=l'f+YqC;ۋ9֭ $+cj%"UrW~okA v^ꎶ0>ǃiΥM\J|Ѫm'9.`C`LMLJDV1|3}Ta% NMRfcE>.D%3572S\5/Bg$bd&L++Q!Dztc=ݷTvJa +G %֧e\ cbJkC">tWT R BAEEl1 ^_ qϏ! Mm%vH_WW}8] ܇+JXTx'H ? H(riN-ޛU0)DNYu'OónX]<+~ąJ+bB:Bo67Np7 45kL~;tĒ۽ :JPiZG})7z\U{8cJCȣIwX @@°+U.n8 (Q^[O]b)kPIs} |9*FpSss U7`Oeq[ܨ5,2̎NMY+,TVNM DW8Nza&fXX95"h=~.>:4(uuVNGR~t?sff}nVggChPkQ& 6N:˳p9mm jBVVWֿ{LJ;ޒF&9K 쿕Xe{FJvʛCp1aPp&:Łʔ8aolɧB+Y;U?NG*]]yAVY/]yUg*kv96C@Qfp*`J}S) 9G扞Ƞ ¨ga<ĢPNWD~1-V'J>PL{>2UE޷a`v: Nl 0'W_9~4{997)!IJ.C o.'0m\DnKGMYl޳m3hnHyP^m-[QL$ s)e [º td[$iSc13gRlњ~=]0A^>^7 mim Ҳh7ſ<fpamYz to?0 A׿fv%]M7]ܡb="ʊ(ea㭧Ve.s<6|kaw.c\7W#nvn:G368+:XUx_)0jbV܋`XJw(zFf02dd>?+chxJQˍPN(0*ϩ!۾-z ҡ7?:9M3W>{(@=nŇ9z-@D4bo?y}y]97.4xhZ ,΂_y*hr6M4JoE<GݷNăƶ1e(3*(GmC=$^!1u.6d|SNzΰiC7@Elch2K!qT3| qk݊"GR3d#=҄tvb:=ISwrCxq`y??%7ģhH`bqi9r@CurVA>p/#8n#~aI~SM ZA9]k>[eBWlcPhf][Ԋa⒝xb $Rf Lt/ί&w<5m017˙riͶCFEUg(ǧ4 8%;ޛ~k#\Lڜ7C|^#Np`^/EOb,vxLrs"ssR"(]j)0x. ɸ[T@ka4$LHHȵoˠaga0?6HKu\I W$9Nx𳣵 Ё^X I3jBR{z!{ qȪ?igwܻӂE:r%sl;$PF ذ^immÑ!; :F)WB$OrztMI6]6+1j}K`YفjWVݛawv⣩PO࠵,ow񰵐x0UuLo!˜o=zt|KszxՀVIˣttΏ 5|htW;{;޼˪ u191vӡE-hw!+o>0Ƕ͟uw#|n?}{ߺ t yBJA*RHۂL;a8n`|w˃'=,4[FDt[6IU"8./?l,R %gϜedw)K&tt}/^wr~;wٶV%c̼Q{JVr),| s^[6^(?=A/d*VaHJa\*m\]J Yj֊ CಲY7*ޥDP5?#os6?Ftp5Pʄ}B-f B"!׏`Nǧ Pۊz1+kOw41k Q8+>o\5]wD,L>1;]BblF~:Bb#@@ `p? :GLbLSle>lj&eߞK}} ǾY2[xۍ<``k\pY>Y\DT * OD E%h lWG`fF.M\ބ7Vg\ (-n| <'I˷hd ,/webg!4Z~Ϭ?7_ǠG-~v#_q<~:@- :K(;t:Cw_@x d[q,+R* cr/=5?}"J ۝ EkE)rP _ eYz 5&_PL|i'J~tAb|@z[MFlaDԔ}8%!C%xI*Ȣ{J-XkXRn4q0u@`Yj2zn-\ve_GΪCJ Z:f䄵6\!Ql#A?*llGf.6[vӹMOZ~S :!_y@"fPAJ}+Ęx0e(6GnK.#DOJ<⛒PQ)~2$ZrMw,J-ww stNPw~8Un2ŮF79e S*f12tm܇bW &tÈ*bxx &'S -d)C,لOx;Ӊ{YROpm[ı5ڸ YǷO3bw һ8Ș[s#U`G9,vch`T+{"1ϲULnbu2)݁כ[͏.܏T&PQv?ۢFeiHLQ+m(3dCӴ^ψ9h$6]VD@`[w/qB=(AT"}sas_ߞ>&0FZ+j..?aqknƞ t䪺;&?b ]p7WJdAV |3]FJ~ELIp(}P?#ё/ˊ\7="l6JŠBQH^m;NͣN%4Agמzuw0 J&й7ε9%F)Gz@pK:(kd <͝Qx3׋} 9)UGk`ӒkyjIDnvspeMcÃnG!& Z习Бx̭Ny] VC+ބbTאvmVnw|=( nC)jǣΏGٗ#xiï~ï̍ed{Sk%.ҡpJp$slf2BO'vE-YUO$(,ʾL8cdsmv= ,iԄ>jJ;+2L1]]:\j^xy f6B;,ع4 N Kz'O[NŎ - ٷTj1xj-2YGǭ7ZL b޷<,x=㵛Evxj4$"/d1&yBd!ﭖsn]PRr"~/E}- &Gz,_f`zF#0SSý{?e01/.>BT~<v:F^‘lxB7xCOڔ7{o;˄:< jw.ׄ^Ɍ'Ϣ7'pnrU]BYY[=#oygKuՎ.?u HMLd+ OAZS5 gwb P' [~4gEWK$uk'g0*yw/;&HTLkD D?^#OxXIIPwd(SU/!^i\mq9 ]],t16ӗs[^YK7<]T(.ސ֒&3Yڰna^I2O5*+ >Y)0:̜f "I>L{Ҙ/hUL' QS>1OFJ,xDc\9XC\%1T8Cl zX4q rUg:GB[%! BgZ1Z-d\;$^;"174})Wµ1:2# qEZk-!U&XذѽEޥrާؚ08u\7ͤs:N7~Bn'[ybvA1n"+Zos(?Kߨ+ɴ+KJ:7hlDol6aa6^cfu(yoOA O*,n榁zՅP+D\8~cʝtZ)? ?`87zw_ؓ> yR,๢mΥۆ3Sd4s  8Mz_ 8ݿh r3Mep &9 +J֌l/xDT^*WM/bR R  !}7b4Ȇ#M-33M7ּ2FoCݲ+!fww_17a`lЭI"EwSpwk?CWXP5‚AԞU~~GGFW&y YkqC?BUJ_w{=TH:cɇ{nxcfGۀ/"y*3"Jo! NOm~l^@Pʑ% *0S6=D|RuVdT` dA8mV%ݍi1:Ojs'ϷQtv!u(;XqQg9i3YkTʐZ]+ƃCsZƨ} ^P(Mr+NO镚?u:K%:(%+Ջ)K|,wBm0~QrC#S zvI.Vdf79:}A}yӋ rB FWTOݼ 4s/!YN Vl8}*eo&vz-> ݬ[dJ?k78aƮto:?l%7Nvw4+ fM7jRȎ?y$ Qq`^ W^Nfy^;eH]*҆x`.f'Itz3bԂ52̯>t}~'7qs\F..ճ,"7 /AG"?1Th:jb׍Mt%e`})hpH&-_~U uEmt7ؠS7s% ۘ~B꠵43?ŵX5wpz$jl GT;C!L[( Tt1:ny9_f3T3]A~/L!r'M|tt*)4s5Ù* E BSY&fI\e L0D5]5"&*ȡkbVq }'ωw~LOT=9>5I-R̛*% -!TVsw(49K{v\JCЌh.G08V.0^a.7J0i~9VF6VYTC|^jjP9/JN*X[dDKS{ >¾+;L,'L#WVi2 b)"[/sp cz.xײ:]bnsU :=pkHf_Q  ulˆ af9xgw!<\rcFǂ#ftlg IL[:[ e;٣s$Uaal-{kl"Bl=u*8D&ĞH;a)vM[pJ{_~u6\+콶g6t.p?'86wv`ਫ}C9T^^k'v 3ECk3X70܂+!j] `Ҡ|ui,Qza8gE3FM ;We.󀳶"_g i[1 frYR#>L&[47,-'3lR% nEtX- v#ý.͙3s?w:P8Ҙ3׎LUt·t8FyWS/N^ swH||Ռ/S 4P[{w}ʃ}Eo ~cuuÇG:^]]{xlmG돾Z{8[]{գJ|3*bV3tMȩ| j/V+[_]}to}um=v=PLKh9,m^dK0/*[opkz cn3O.zMGt r럙}sh{@" ?Xd<*rhPM/I~!;tͼzl<#'w9tj4:SX5|w+;ì;@~^^vG?lt ^Ζ6lsormgwsa{G;쇝u^llgGfL3tok 3`ys|s }sg٨lo?|;_@fN:N|םݶAg #4"1f0-?xytov`Vuff` s~I!zM׎LxCkݣM^΋VF3}i̓C#`4uhP;ny90xiƆ.>WJ-:_١A)o/Jdp`ޮ lx<6`{<v^"uP\uZD&?*Iq688ީAsp`:;gM8]>i%eh؇Q=;[3ddW݂kx=DJH\A-9l:'.{evM35(; U3_5Grz>gꡑj \Dٴ?+Mq~??E8{rlzꝤ,xg͍Q,yv+#)ń:+TrϩKH..|/9KxbIتli?N\ubkF#ﭣ]/$ mb*U/gygZo(xJݐ1zdI ٛ! d-)@3]F-ͻ0$?;NA>>YG8MgX?aIsKUS) ?6\sU:nݝ[ C9XL#F`U@nykq^~'?IiC]Nʃ OzpbX򝸔%€ P7xD,jUMc<~t/aFS6=\}م/;-!S{# c$nK:*!;0>|o@# Ocqv'7Ra˰IkaYIWIUA ]%`am%&F=B:z܎>Z ᇸ P]w0B|AVWDU?_ʚ4ڜ^ˇ*ie;4JA&y Q0•.h7/38X[5| j2pܯ7h^A]8PQ/8E8͋Rw HNMDp;t*XhɇFP|41i/sJM>p61peؿ$5oMs!u~Zi6o+{2HFxGuXūv:(Dճ׎[S;@L 7o @-#fe,oMڣZYYA1wA1?8]ۙi&>fwW> ͣ΋A l KWov;džSPydgo^,Zέ#f2/}dOe?ϦGrFW 0J]-t͗ "X_aa+O'e! %pB>F/BV{ڣtP[I8di'_>7!<˲Y*Y2 _XUPe%h21-K {u  &Op<7:9r4?'8;ENBX֩fS}oNO!ד{=EMjA2r})ܻOԣR'`hzA%AcO$sJEAr;"౰?xK1z2Mu4Ꮹ>ZoKnI+I=qȥe)m,.IJ4}&QEg nkt ns'Y.dw EDw]]`Phz/T*N-*VCA4/*t:BZ`T"s`2v]/?Y7X6sԡyUdspJfJh6TFy43xqi"~Jn3%u1'ɳI)$`0~-V&Cj;$!kJr6W:nwg N/_R˵S;/iCLTQ Nlwd: G%/)Q/ 7b]<=/Ϥ<|۵EFB/oL-·MO7}_m~SpCLk|qK)a%5ZB  ޸)ԌHk{db63mTMMZjr7ڌj*BDF,ɂ#bPҩj ,mnb:Qrzȯ36hYRIR$/ݢEjuummR%{߹N;C,O4iA:< a1T,9>ng0!)/Ps/`CiZU>H$if}ZO"o?>/K%];$( BIO%L(>.VVN8;?nEeTN$D!Þc"ZS;+$>%/OJ XQsvvL7'2'W8*.|\+IAB7S 1basxtS\W{K3I<aC ?P+\NwE#ϯzx?'oV2%7J$i6w}clv¦ݴ3]M sDT:`f2OeυYA!(x߀osj`Q]<OA!H11+g"a^a.*pɼ>cT<}=@ J4cV {pc1T#aBWAX([NWCZ{?náF7l`o:,=IF?x4XBc׺-q裶@By [Fffl*2T L{Y >6n:~v*e5k-]9fNYNpt3̰ğ NJ+5ȋ1 ͰvZ/É,ҪSԤjGks4B!P^aw`;3_izCj6-;{/vt)7fg4iMO959V 1ܝl9DY-R $ cfdiH } n&俬EƝ3[TJlAeBP V'ZNq2L*cXBF8A{?qșʑ$w6<3}p2~Rs3&&[@b rjk!8mV%i1F8MvTreĄe@Ҭ{緾>Vb% ̵wugWeGT5Css6l^BhEϫJJ*+!d` -n@QHCʜ,A{dbL6ږTh6HaYЪhؤ: @vF:(V@"C<@kUqN`HuA59ѧҽ# n _xb6}*N̦%S;r9Aea¢BΑ 3zǒeZ* b6À\w/L(8T b?@35~4RlawNK)hkUP7t ?өwmk mϞfo ne1҇3"\ch! 9w|zC`-pؤA `3.߈&lL6|VIGz#iM!ZPrTh)/Gl8ǃ,M2ش+ yl>uׁd&i}D&56>QAv.QJxutc(đbv2tO7( De_}.|P#P i_%DŽpne_rCnκ<}yea>+asiws5WSH)d~-zҀۻgow#h., |Ww]LH]uz."?5rw6"WE_LC7E6wM\l)[ mnܦ[SG-&-_ҽFY)mPxovxH(z?{Ƒ% W2%G`Ny06O0A8N6jԀ!jɘx=vu̘ uԩSu2#hw (riBVz\FoFq#~Džl?9M<}0Oq]h F” M;%E,y@DW*^QylPO `dPM!>K9|=@~4x`]Ӎna+司\|vX\c鳴G]!,~/Cnzu'-ǖW!&|*|G\?nT!^X#TgMaBɕVe)PĤ HڊD\J^2kӖ5-eliZ>e+"nyUl=KYy b񧋣kgW72-Eɧ(Үdz##[=cjF125 LՋpx^HIm:}u%kc8SCfںq)n(7͐dxH:Q @`8P, w\`:5s4>i┹`>:c&AlO+ycscرOzw@i#nv kBǒgW ~ _>/hˡ3OXOP&kpjKݑMd+sVN n.͖Fq2 s70@eH1Oh_Uw| @KZ S4dWq|.]Ii(f+uL^ 'HI9MQ}ِC9>8{YoBԺ<C1UcQȈ\'IV'oT= PrH/ a$'W Kkz -$y`kO']OK=;wUG`2;``>hv%gNBU%0ڎ\OvGLlhkz+Dg}sE3A[տ:ǣ9{,e}8_Mnb>w!m2ݢO^6Ls[+nx=\ŵ}/8G4͸6#ä=f4fqxP? qp9t숪IoO#&Ddd4EX y⁍c4uf9K5A:ni94 ljvwь]75 i km,Wg+k~sLRmbN z@A^2aNBP-C,ZuO&bV(ʏegN}5AӾ众L,}ƦuN ! 2fΛ0 6o:" dzQ?!$b.\@ ƞ7($rӺo\E~%[@0H惛3[MMTH~F3dE61}!-:6ݐtJ!tT)>yTxRi>)]`_{]$-BD(ؘ q_X`T aՍ%B0`n~2ȧ\*+NćkFm{Bli[awPfIboOԒ%?o+L랶]呟Yb0# _$sb`eD%fZj&gxPwTn'"=C)+&W1Ksw~юٖ┙XU)7bPvDAW7[N.1y%cGljeTtN:n^$XdsQ)\xI-azP?F'xFRnC砀>& .VOWywmռQ]gomL.2~>##忝4?>%VhO#d4u'@rF Jk|qA12Hl#c_Olw\H|d :,!?}ph -*6%4vo$Z=ʖhѸq;all0>=青h(lܗKb,6b^a6  #q:BX>[xD>D3N#Wj<6Lx59 A*:(がhd'Bğ|1@{H=G>ʓ3&n5v̽kR'r= I~F'MW%iܻ' ]eQ~}<13N[a<$YV䋄Ln DzC9B1T4k3u8dn4d1fR;embL&[KȘW~4f9).;Dnq3iv+hK{L*ns8}Ɏx=4 ~o@wGj~Eծ:C-\ić#?2,OvWAӇM&O(EV?%c)z"-R PL:zVW6kR6M8Ѓ%nȈ j'pW>oR=%A}ȽJTVLH"&L)tqRk[$"z2\)JL2;Ql6yr `'C.i:5m q%'ym1ৌ Bmϓ*/J)9?s~3&gYœ&Lb"Y! &yF U:߀BPyr*^vԔSy+ǥǿ)ܖ͓aZX[/ljAqt*S4>IƄsSzÜ-oi)~ZP[{*}c¤ĜdʢݹGMS7̿>u]bl!|IG^dC-: A>cӧɨwv$(߀bZYX]Y،ߪ>@ p.t֣OOdN+Yq2oROLw$Gs2/j֟m?cQ>=>9^+pP%\_~)Y CrGU$g}pk4G.4-jݔu^L\!?EVQxhF^WMFjM֚cT*H9n 5+ ~u~"RDzY ֹG D:q ?Rޢ4{qU26 b_7DLkz, ]6'z /&Z"3Pt0s(hʗ$yPifw]Q轄6Ffā#ݭ7 1Cጼ_:O`C`Iܔa &ˆOZ \dhJQ11g<[ԙ1"Ӱގ-(~B*G"'k _dh*-=OZ%m0%q#,&`΍xIE@|O-F.eD:D{&:,ٿf"?|^~黥}頵Ծ>7}AW;M`cuZ^Y|j63Iǭ %E?P=OF GݳTz o{0X5p )\ l/ h̊t||IzM)T6IJu 6tO/PwyE Hb ' M8<8r@6ZZ0NM Gwb:[j9"ЎWֈ,H 5IgwώlՁ]Uۭ徭|_Pƪ] G{zw՟oCh;xNsw8|^֏v^{{?csﳽ{JwUj`LOjo~]=;<  m5li@((sxځbjws_߼>nBoG0c×a#|j`THpf6|y`ACp|xe_7NMm5! ԹQ;- ֏Ȅ*:Mo{p+%Z{VVViO݇WÕ/C7C&ѷvoI#\:|2HK|E̾yaKڗ cxN"+FbY_1GjuFЃM`̃5~\*x(tH<)F5dhS;*P\=y8u . J斀PٴxNqDD;h5Z>F}.rL!eqXN3();.E7'2I ei3:FsR%[ WWFDe=ln4OЙBUz]őu5lu&jMJ݈&k:C><Pw Y GB 7V )2ұ >y $ n-=>^|}XҨ])M][wC< `$z~Kf}ױV{͹I@mWSyWd|(k5[S d$ŕ&fls EҼC<åXSh@双@|N4Z:e [xQM4Q mXZ qmo~K~r6XjX6Y\ $u&ܑеd ):ܾ2Q : ӆ]j}w[&面lb$K΀dY4+ZuSKҪۥwKUΒ$o!q_7VoRL[~Pm7VIVS㫤u_ݰ⋤{ف9qMjn'C|֟ϿLxçsvQl~d{ aAˢV{=#Kj~X5PyR$%^Kj^\NƓVϾȋQ2쵮BNW5yN./Pؐfg͓R 8.2@tߔ(u d{f[%x):9HFco/vZ^ywNGI: 1FRq}%z-"aYE2JGDX6ռYP>i?> L$\AHy`ۆ~h`:ƒ;@`8sAmK`\+E &rT?kc}e9~r+v.z2& l2C~1R-5B SڃQ3U"" Z%u7Wb5xw>W~JcqCru62W\,M,aVgInu Ťhao;P^jNwMf̈́9Y&"Oia }0BQ 6N*I5џ#.'mnʩsz4{}պb&Vp›* ĽC:d#Ji 5akK? `x,?r+xuu4촗.Kir{/@h#⢶ZMj2 \9R=ŏfΪ͖Ue 5w-Ha" /okv7dHhףG4`d.h?J E$ȍp[5tB&K!ո^-E̖$}G.R04B)!%kA\ TgdHЌۭP;&ku/aXVc>T;v CupDZsx 5&MIjaOkF4֖2jg`5-ZR&2Id߁w!Fs9z`I{iG0i#a@ļVa-gbv_|űzq[?jCL\,64ed`?,]8A*~–KrϙVy W j ݥ'OSs}Jm̾f-$I"USf}sM2:B;(~8;~}\Ww я{;VPs. [k`~|I9&N >v1 :<E`R\5PTs<䋆3Y>b.#ou&rl#\3jjqυ OyB|R.&^~7hYz1|!\O1|'78\w N'pnpG-_.٦\2.'ށ&w[3+в3WrVaks\gv*sV&ǕVaC7>2g>g?"gfUpViW*O?5֫:.ce- CpMFڂ|~mhrYNE'I24~SA= `?N7yGQE/y}x\f$tDJ[NҾ& \"șL;#Ț:-"/w$ p>#\P~ %P ౠ[Q ~̃јVbBPY:R/\Z0 75ޤ}ܥygEvN5lqL%9OF(D T\7/F'<('fQ t's~VkR^i^}-攀cj-P (tJlpnp=9sz}_?x~u:3eXXZ,D`!]H_=TvMzj9oՠ=NMdӉJoٶܟ^;= %һq($}4nB##Fǝ냽1vMɃW5S9 YXR~ZvQSL3@ɗ2TزTbDHp V~}|YNdLgp<\;np!.yP5XmHMR@?!GhS?BWCi{y*|}sܥH2J]Z%Շmcӫa?d iueZ~i'˝$8Nl?7B;&5 =8pc  &c{\Wܗ@A3[mm]vxO(X!D+{txRzF#3Etychw4 N6Nd< DP0 0\j71DL-1O%Z3lN#E{9%YsI" BҐX pnSlc1LJm&7_c%WCΡ{ZegѴg^_LRj݅\`0?p4ЮHN f^gq0bs]vOWK՞ܞ1\ ] g`C@ti,ΰyr=N_~SWw{;^ W7^%^F:EH_qΫHo(iptNצ; `r ՏJ[.!iD_e##ȕ  w14¶Ј@C#2l}A#6UoɵLZ=|)nt"Yv餇YPLO6~cҞIá2yc` a23ø7YjBؾ6]c%9)VYH+IOu)}Fhhcy|C:I<{o 744 IWw2,LcӪz_{qsۆA~XٺJf0, TiȔ{X)]2ELM5EE4ӄQ6IMW#6 3R2^ &nt]j {dBQH06C>:߯chOљE0n`:;Hy#znd,1(펒M&v]4,sI=V׷ <$ӓ &tS-sgy+϶_9Wy9MsaB|kFM2t$3Ĝ< c͉ck3kف0S-y>j+y%??*{)-aky`ym0bN577P}2~Ԕ$ - P$*C dݤٞxcd{)CyoC}]㍰h !^i(kv<ֻV4~~w_گ׽X l+"}މ C3y"dQM!netd Ѕ罶9JOMV fp;$\C)U@cD[´5rn1zzY(nP˔CT+ٻw"޺ܤ ;3V;q{ SOu9UD!WL-G]\2|o(|*`>P*FMȐJyP#ҏD/Lݿ+*)6,h@H$lP*UфugnY+$}JC΀SᐽrxДΑ93>9xn4WOhbd9azBYv%ÊʻL9&~80>BY`Y|\z鸵]G\КZA𴚋VsEޘ,cU qlJxW3%k#R—۸2ჱ{K, rfo.#ޕ X3wɨ{z͚d%ڔBVT!eIKT t h^8xdC+t7#&pDXaΔI/}%^w(<;Mdhe5Bbet-RVt $9`0A /fhfv~;Bd@xdмɜ;wL,1[Ԥ{x%`[ թ٨;&bI.[)x OBwDSX`֍OI1`7o+c[l"g}L?vIُzYQ\=IKԴz^oԲ^ֻų6;lEH^Q_jŅoHsV76{Q ܂@љr uui3}OSg͆W8=Wer#N<{rmlQhzyw;dVh]L/فf ˸M׵];niz;u[~Lyw o- F&',{J5bDaZ1)Hr;CA/9'Ѯ9̱u qUe؂XjFUSN~*fwtʁ n:i //"i0zGxP2,W6`-xêi W˱+7\BӅoEL&Y"auKiʊ~ -h[:mfځBn_VWooYe%j9e&֟X*3>{e^ FЬSK.$W#gѷ~**"ES "FQ(r/VD?XƋ:!|' pg ^pIVBL~L/!ƈr#"7Sc'#)̓/r4HPJȍ+]/e(cs7q0*\d*a+MXM!= ´ȍۼ7\\97J:{m./KuQhn'iB@c\ThqVw`'3CrP!3%ePkQI8"Ɨd JV~QX;ɁY,.yo̴zé>ؙ?=Nv>܏S^ң'hgؕtet1#4)"f dnYiy{;t쮬phni7O]IDCzMs-Acӑp8@9@%wZH4+[Ob N&qDkG',n'bB8&x~`әכwf~aK)} ӧ4;" "GP0P?mյ./cA*N)FʦTtsmuޣY_ӡy׵2%7af;v',{[Y5{^yg_!ѕϕ^U |t/ܭD7b(+'dk4/ҬngA?:L2Q|DX%d_lG>*>="CKhZ KJ%6r{  sǁ]=jb6s'QL:Z i˙Y iu2pFo[oLE6v ;ӡi1F--|GrL;Vft˛UacE' >i#{GdA`.'HHޏGuuZ :'[&dT9cD\jw˳&G[`jbІУUQ Z?>tКqg6b,LrɂٱL״؝WXlן ϭNR\!1*nrϵ,ʺaL#5>`"Ru01q"[9 mkX"%[/8e—8C_]3j6MlN*jV^R.r)_ H`NuU+)u=-Y EH Mؙ5Μʯ!B,t]kעպqqZT}*-p#;drFŀ7k8R|R.VH)6W:J)AO2 KlqkWL)MÚr}?K6}Xـ(1+O "KFGɾh'줄6-wwn>}Yh+8F3 ^tdnX1;7}Ơ0S 1šL&o ||6d[YH%yL c!ԛ1QhšFP^$oH&ey ym@>P#AhwbL,htHxjdg1skG=m^6Il2R`NضhVαEb%Hv^\EFO9#{wqހ;2Je잊Y$IЃsѨ7R6"q g""IZ>N1 jnBoG0c×aQn6 ۨA: `im v= LJGPuCFuRCj9swZ>%T ^nCX[1#o{J;N[W6d^ߤWSذ_OF?5GHhrP@"/LKd .#h/Ex-Jz&Yi*-B{ќwF v1c3z`#KLGwh#A?zv!p1w6OwJ׃ZxMH`կuwZS[GK%-6,kACo.Š:%bs˽t/ZkFT){Wލb7س4cTA!(9wD%/!ihp bMHȁyػ©-CF`gqN5I@Zo;0*;X_WnNbc7H4Φ=[)itkP[~^Idr!t!<d^y-vH>xu  ]#v].Npɵo8^Ԯ_qrk;gU{|W䬘TוjʭkZ%~mk =[`Ч/U)}٨R)iy>DZ fdWWvwvwoToo$oB(uȢ[bz^Swz}vS/^%˺V)'InQxZUbiݲIlaգTCq&Y-_ul+Ujpn)6/Ŀ헵rJl8oNf>XߋeF}#čv%͔}bھ/7l׮_ql 6|.,;ۑLxQun_?CGxO8栰gZo-Kc y넿t)=7u:#H1j>G쐩cMb85MlO4rH pz6,YZ/w!c] L aQ QHo q /jcL8'z[;fpEzKJ 6~֋Ʉ|zw ps-("Ԛ_%VXYcPn/gdA!D6iA*y7:M| =K$rQp1= wϼS#?<+][d/b-q-X ]n  %Vt >؂^<ĬG=99,,W4&.IݒZ.mzrlr?.9Gn_{kg7z)&x12\6)r`۞1:=+uv% gɭL %t%\訷:ut%V@nDpVCce4O5^гZ s)dB-ťv.y]&xcnp^ gҟ\`rSh%y'Y>.].d7 A [lѵ Nvӥm@Bl@2)4_#|1,y){y+%Cxvdi8q8}eB欋3 v P/߈N*J$AENf[px Cv0WAG1G>aEFwtKKVI{[oX"Ϲ"6pS!~s#f:i PW DkL7\\}@e> @yAp嫽}[a?w.gCB'wΈͯ/,6e5Q Lż {}+`r/k%=?װ?fl48Ԣ\tQ8nD(3< Cx4pX%HU +A8)L](v+6t)ʍZ&@CLLzͰ$1!rǤwgRiB+=.&$5iE$3 E Rv Q GWjqovJ5TPEAFjtŽFq$_ ls|5AJѭ*[WpW8cnAen-#'k}3搘CY1*ЕaJ'GrI.SZ?_l/gk~Y^^u۽~:ϫNMR;jA-)??l3e)SWVu-ϰVc9u1g`$gilȻm-$t1o~e_;8[fcoV6zVMvjQWm&5:ƚ5WڏXSX 6L.% tJ͓1ǭy.j)0#xF.cҜQ)Cө9ZRmyJn $-8I9vHdLlQY98Jv/UWأ[TEo=w5jbnKRDxN"8ܮ4Ч- g*.઻-E/Z\8MX0~PY8bߣݠ `vN3>i8ljS(6ģ9wa*jޜ=4$ۚ\dn #8h1$;wИ=o8 ]s J,Wxbp_A5[ IՇG?.NEA;\ ݬr;;;p/B2F C5↫l*[<' =VO{{]TAt:uf)['=?ׂ'Ui; lu%k `;Jie|L̄/_ϘQ_^1/ҧ #;_hVC&2hu)oDO˕)WSB^TFde׿vq,"rp5I&.s,­&4Qnq|tetΰGxWom3;Dh#wDInNUpJ=sf@Dxyw_bӰ>D@TDM9PZuТF=2ť2t+ZHY.ŝ!1kiؓ%Xmc}jG5!UvOTiE:@gYSqn5ZiUsJgYC(eg/)`M['7A~Jf; ~ GA{~}Wuo|)fowgh;UiF?6) c){*:?s(>hJqgsl|fS2x#{\b 9.#c6 ?!gn/, )+c%?}:~FGN/OcNBUhL|k9$+Iӊ 42%byi2dr&~]}jsiB<'Pu5|Չ[7蟡?(PyH8 y\gK#\-G&iO+0#jZ7Yr,nmJ,c?<JlEW㽗΋:z1%OFI y.X6.- \J7 (K" [_V6~#`.#xN^DOAkAᵢ«Aբ+AᕢAe/(_ nE7  WnZhEk,YkPP4X`nE{]$'螇;z<%}UMbA,S ZTH ,[촂+\ϫեeou3cc g?fbO,}`g>t՜4grNIs82\%ؘ#DǘcJfN@O:V]t ܅Ch[TiBN ;fA;Wh [aK/d1[㤏vWP_S&vمw8-gPSI69) N~I-cREu)Gڱpů)PCW<;{>c ebWXBaf1uk<|;?`:&Y\.)nxSƙ|_~n'܂n%Ȕka_|xӱibM~%f_%fС# HȡcxA۾f?wsp] *}8@00/c˜.i%dlV"$AZ]ʏa%Q?a3v$pi'9%1§bzN 5'}zabdJ0H4gهR Tx7 ڽwIOggcqM---Ĉ - oJkXSPN['Akw=b%?|}\\qQy}ŹHn6651ϛWh|U h;A*Tˇysiο^X+ғM~JYqa0l9GU+[ӰyNbe`d4Oz" {~dd\}G!\M'&=]Zp92QE=&R-(^8o%Pl^N.7qj⊾H6;,^*S a럶Z}tzMϵ"Հlշ_֬1ŕ[\Ypq Qc?hiKԻB&̀+ãh1&} _,oR oi+ZSF*r{U?ÄNt0POAۂvpC d9MAxگh*(hV΀줾`f0ʗ i2@{2#@1L1DB25qC))X "4_+cSѽL0U dzG@7|f%:̐a $06EҢbpކ4,7fQ7{_ ؕfmҌsW*f`ZSdplo4AVWcU@)#R0NvApR$,8nP9(y0<|lb[ΡE? T,<@SDXvDNU^]_aaBq-\zU1iq[kOK`a~mXL:.߾VfBMmV9 T6nM!"NCYL73t22'tNO\ xz i:&]4Oy=ʞ7#oڞm2mEAFV$ʺ48(\r3R\AQ"|`Ts9DEM 5q㘊y Sc?"-ߞ\ۯ՚JS2rZ35THe4?(9v=K'LsNܐK:t|*in Ԕ:Ҧq2+\#XS)ia):sJmO [ ;1zn)ĥ~ Yjy7;aK?~΋+wjo7z(54"jJÅe42sA[ņ1CB8)Ul4!Ru9D=,q?}zo N2;)}6aBܴmUv /_(e5J9^3%E򳁕\^q޵=`IwlSINX 3x-!gYRVK2řYܧmQNti&d;u#64? pN)֐$;,L 3 J1Ab;{g`V}TӢѱ՝{Q)!S-f 5e!7Uz3X@y68;?|EE~R=zX} 6s~< CL6E(EuFXOVoǰMIu: )j5x_ˤ: | jD=b9$"?-SIriIP!QQ ߍ:bƷyH]ͼd «LFNR̊HYՁT*_+fhʄHۺZ{r)ٓO(e|vZ# SՍMi&Q7[u3KNv?9e駟CGBC.nl綳I`p\\1y$O+@{r:!'-^j./nlP[W T]vqt۠2õج#Jl-ޜRTOpzO`RxM{{l[f8gNCߪL $ߨ}TSEs6AYUI uy@`l8M=d.ribb{ŷ;E% БT0zeS69UwC30 |)?CQg."~/_&rWx~4mdg* "$;p-c=-wjܴ s⥴tKq k}yܳh8v9|\ A\tj6{fs9/^ܸdZ "FSd ֬L6) a:CH0ښl=Ұkg`K(w[#!3(;؇ED| &;a3Hzk/dGe=>oO6A 3e^r"Բ (]f^٦ţDyARN[:LTS+ݪMn"Ȱ nZQPJ ı6`p{RF(Cu>쪌yD7Dp y'<9E,[k=P'Y&.f-l94 _"C[cleO1|h$70c槿1egSw3.z=*֖,϶*KXbar6~`V$it5K5O.bfji5Z. dirȟC{KdG`[Sw)>>':oGYvIgsݎkv\;WI =adʻL7eiٻ,b>rDu6_vk[;N[oIn3ph,b5WN, aS8)XP E m Z%ݻ1@2FVW~ʋ!?hL.33ebssj7~S)oB:!?D4\ 0"R=!w&isg>m4АX 5!$he߻F*ݲk~2j0ߦ%t0ʤa)ER&je#^ )$<3&>JT@2Jz7+PY3SDezvS?-k_?O/>(ߕ~g_MKwm/o_^l~W6?7f \Ei:*Gl{#q ueCbѠƝ.c׭H9ݒ' \~MҫLHbT%z.bt5+A5cQ k^UﲄZ, fL-Y2Z9 &ݾaةyIڧ*U><$DS.84C58yQ!L<*I-V1~5]!(7-GyvH$Э{'[cK*b(>1qC74qukȰk]ZqTQfF#~}P Hq}~[0lOzzO(Έi;ޯa^᜽x "Ӽ7bNӮw`B** dQߠm8I?БMt~XS7-k6Q4pUg䙊kS/޼.MЃfMQ 00?z-|ac۴lK|[vI:CDTn~ct,gsI[ކ,~~l6qζ{MUJ{*Dg6W|!K<*;H,5 S] AUk6u<ЄY4׭(B!C,7׋"8dfF\)ˆXFGPR". +OOeÀ"wkh) ܲh{p˞!IK,S襢CC R_|}c'%vmҿJ1hX.$N^ 9#\r5AeȠ %smz]q^\ifSP!'3eaȦ7D}Hx6JeHI{y (;(ow~"I9Џ,ȟf"= >@ , Q*O A'Y7E,OK}4J10[>y֗lr?^&goff9E. ?˗/^|h,T).; ?M Iz&oZ>.<&Idƥ@Tl' P $քvS鶆몪FsR4W'+ډu|Hj,5&ΊsZTTmbuSrsեM} /)2$ǶM@˪˥eHYsmzdb)}| 8Ru”8s8Nhi[8ꖗ:0㨔]U,B~hZqFBP™puD}?ESu9!9+bJul֡B-CYiV ہ#||m3 >``4`&6atd˒"_ÏRJu:Jx˗J 2&7B,to;,fQP,z"ϾSgm^u"C姉\32DXo=9_/VmDplBZ >IgUQ#UZt4\[bU $ >3>Az`oV X[t s NbQ7ӡU-x5VC߹D{]EP#KFTú XbNXl0(hۣ׈H6f D֪js\ SQ<Wjd@@9ڢGYTT/""Լ(8Z\W{j+]pt릳x@z`gU2c!\_ wuSC:w\#hu_:~ӄ’t' uWU*sJ(N491+]@~Bp B6ãKTYWpuǘg1Mۭ)l ɵ.jfq򾝰σV~eM oU7+b[;[MK7@WDAr,Z;w'np~WNjP$vpJ ~yOǰV±EOEZ/lӰ`Um[xkÍ5{75VWY 0t%[ihړ%j&J`J- 8 5ؑpJ;R('~'OQda1T;HU1 Bu7]PmnZ*U f+o~#yœ&|\\"}5u=Ju|Eq@}"׀Sgwk.;DqX([׍e0}y\rG+mD'ؓ;NAٮ(UloHY@8*_ah0\ViI11獕H=hVogDh1/ܒо/&m  d4p%>\ל]`XIps~bEr++k/)xm?E7 ӕ`61üa%HF?b=PNId_!B7eCEy l!yoH?4٧if%;~'3 xxv=sV=|~qPʦ#׏CZ-!LqGR13++;RR櫣g(@^n?Q‰|#P5)(uD'Fś@D?|}\~xs6z%^ޯ7z8fxx*u!} t )a@%F>'J{&8x8e}DTn&ՍV Zd^j|Kdrf!~JH)OE;x1Qy_1w(F̜G)3ֿY~uwIt]<6_$*M<14 Znp{abL.&qތ}naǞ_!yeP xC2VSX\[K244nMs@u*)6eD։㬣xJ0ru%n,Ah_e@  +p!k)bqʊs6Jx \d:M@#.HdmH==x馀v ŊܡfV";t+=0gX9tH6QL_e|uEKA9Lmw !\^2;L৳ܭ7Wf5J`|y6Ė+YMŽq$]Z}4б9bi2z1M{4eg tFy@W_V B$r9a4{/w7TE 1嬺4&ẍ́FPO7+yM ]G5.*Β.tf:;(&Fswyq_?x~7w?k]2jtad*8h0p&uI$lvp\ 3hXbq;h_oבc Lڪefi3g`2E:PhA ssNqEz:/U U>"Vm0EP؎vTeн~>s':Ps(]ݫ+On&`[e)X4Ye2qqG'j=E$;~r4rDs >sC/2OgN3CGtG(iZG P -=GGdR+(|"@Y`>'p FKߛ'N1׍.oOWْ<x,>Ǎ/w48~YNi e7`TlY,_ڋp(2Aӛp8o<ƸR AhǪnǖD|/*;Jǖ)mnmFqvi"(M쬰_?y?;^N!qȚ-GHb@PJT1DK}4m-X3`v .!6 e\ݰ\T\)04ݹ`d-7\tg64M `DnFmuF-h@PBaUC'bl5j]1Jw+΅G Q1Qe Jfm)r:&ijd1>8T ` lI&U!Cwb (8O]h$-@i)a[VO&,r7l|>w D[SPb8䳑!gwVʡy$kDZ3BC!ټo̒Y!OOoy_ɸ;2Ebtxb aY8X+f(`YsxB_ڮi+Dnc!)Q>e|hP.26ú]d \*Ā 89-Xq? `VH*V[ |iΚDzQ&omx{(i~sA_4sd ,7@HRqH  {ne8Xe"NЄ85Q 7}Ez1{%>̊}!0ގhEv , '˞|)d5s8LuG@=Ӕ`(p_3_oÜo{:'twNcKTEz0cΥ. r(#,l] .]P+zl::=A++{:=;[1AꌮY NtK?l-kމBΈ)|F6; =!DbpJhLI5njƊn@(—J/ᢝ`dshYJ& (B^ݵrGcftGwm\Y<ܡ#!`T^f܈w%v>TEM^LE4RFSpnridH?<_M]k.`n!!Iqn6e[V7֭eĦF1gëul7&>38Мbq~po7=; d=zNޓ#b_&afPH BJ\fw̕ RÇi2z~msHPF1\R&E`e-f-[}*,r*SH.G^%#HryQOԛnqd nl/ڣoG抧&e d =166E)C wbXa?8ͲNS aQyZ;(P(W>r ḭ>V7!l3o. :_Egi6ku6=Pjz0ȣ eYtg#N(MP=XF=Ү]8򗇻u͓X.f5wpxnSwǪ-f_W;DsCz@a2vTE =E& 9͝q=bl&NH ˋ'qēD^m뤤ڒ%b:!dnl Pόg'ryo$nﺏ*BYⶾ pKL@[DmR ĻN[x;5Ξp:ᒰoj'Ņ*>uLmݷlfrɨ~:lus>O n%{M䚪wQP cI)Iw2oWZlWQ.LGXNQ|xC|1;]4=7[ bZ'f(sG^֛)=ˁ(ֶ"8K?5^Ь90a`wvƶSd/t1DTlR*5uw56&zpy6zv.gw1 Bl`TyB%q7o+'[К6Ӓt:1y,om{M7QV0Wӫ>! ukn΁|-.]jZ/YZ~~ւ7IY?|TkbX-›Hѱ,=f^+YϓN _R"cohG B(VMᤜ^r@^D\)יyZs1rS~(ćl . UhN3 pj)t>gFA={WQ}0oҁ^c5?J%kX֔3F׀{q΁ay#>6>Vw1sQ?~h=?>97R!xU3v5-[a sXcUy!h.9Bk;E1͚KEHG#%,Ct^RV*x_DZ#NYhܟQ2 2!. LZ/K}kc"FtZ9t\ DÛ X%.LG"HRָA3f ~hYɤ{qm!n&1nZYc1 S!#y7U? fB帶\myQVc<4v4.)ﯮ\a.>Ch. \uu藦T[\LtNMa )qX9A2n* o_n:)7[8U-| egv^)/zSYGG8rE$MbiI?ʴqzHn&~/}[/*ѯ*QeVu`,oōnǀ7{=ܾ D ʧ@B! y'[/+ѳ#5xɑQp:gTٍQ4iqȌfrd=ro9L M Pt71$nB t ]7n&4[qt+׹|=6ΚCly҅g|7'Me[|㟜IxO݁Z UņV 2 )0CyB3}(i ^r#CkrbY  `hC㗇GXnA}^ 44q ʆrD= 9FX>/l(eT#-ߜ\2ڳlf?G% Wsm:C$h;|"z^N?ڭtL#ܷYwgh vhiƹZshd5r`T^ָ'Nm O2z+"n.рţ{?:D~1,?wv9o@&(xd-A |FFk'5+U3rBh& k0V4Q*.Rٍ (mΌ.G}]ScFUly(˿V 6.w{q3WQiaPb3=~YȻ\".GIf1$5G0Oz8+ZQc%hA%Ɏ :iq8Hd'_Ik\(tPPbB!_$/rНY,Lpx&nyocsEҪIZ\.i5LIiJc:h9O5!«2Ue < Wet'Dqu[ tEa:5\zĮ{,j}U\`s9af鍯JJDWsH 'hZ+[s](zfy1U jPsow8L[7*m_.qn@omez%(\ִb|~ i32 c$Bg"(a^?dVQ`1F 2/9O&Jia^5 9r5t3=fEXB|w/ժ`N\چȣ4M۝Ph+V~]| p!g<]o34Z{</0;m+v ;1>׉J(3cLTUSզ "* %ذHra²:+dl] G'޵%2UFלKjHx8v@Oћ3R<'{2>G 0jS\MJ2$ 幅?]W/"6irV$SM$3!y/in.L$VPۉy#8 \ fY{\r}Rf󯱞~h9.i~ mwpW?02f}FsT5-gpb-zߟ仅m!KV%_nSSnm&a~;]^&eJQ*ϱ(JX-G V$lTCńD}G&k[NnտSP(b򒔿pʵ!='~0)vO|jTr:ۏǗsK-uOӤԾ>7}AluZYy`e}yS-l,oZ1LqkCIw;=-xsQ_)ҝ8T3^YV:U:#5ށw0w'pKdi `Ke7Mr><@^>Ν.Ʉ!0^?_SdpW# /P-u$'lԂ1bB]tl]2Op$Q Mկn1`Mrg7Gu{ja.Ri ̫}ŏἪ7ԛQѮ:>6!ݽTq=hizY?y_ac@cxA zvx5~VW=O q [;/ )ۀ8y}8ގ8gG/5 W񞅵l0F G8mX[,6|y`ACp|xe_7NMm5! 0Lp僁[B-ކp߿nHbZYz@Ík5hUG?b8pO SnGZH:d梾ӄۙJr#+_l5+SQ?Wh x:8RD#iOF8dpM`tr)$@ K`wHA`:)+R̜ŘTYN \L Ibqe6\9 MGŹ{29-!䃚Ї[1 Z51I#iA B0[ lW46+I8<6O@ DU_ L&V,(?LD2$9> hn4I ' s 痭eg)BLXB+EY)Dٶ66Y轢 JlkceuJ[P"Җы"8&8y CįY;yR*m :9rrNQp;nLcһ%KFdPfj: wkWoМO5QB 2*t;>w2:DvIt"K¡1,wHqSW\TfzrUoRaK2 C@g-Føhl*58 șͧvQSXa\ף%oiɳ+^SWÄ{ᚲ,FB/eVWd?k_?'G?A++=쵢ʑPxsGG%+\y_H񀿶Vq}l/T?>B@D)AN@imxYPk/ux,܄&]"U]PR4RRE\a* kIFqa1.([e}UxOw1~@m66EG .,Ex+0P|kZ*nopz {-RkjAM z;2J(ksP͚ڨrǘ'm{`go?m>;Ua|\5yւE|`]- `jR> 0%0 u=?׏@Dn e}mi좜Puǩ\@ &=Pë.TlC(4Bk. <.z^#g唅v2K++\˴x/Xx!s_y{&[!/U~e9x:ˎZ^ v#V+d L94c,W T z3$hk-vѴ%@%g 66-T} 66,/gZ :K9e +/Xy%JK`K,)K@v| Ք%3/T*^3^g|g .<ڊǤ9n+~t0 {H[Cy EF%YXc69RuRH "櫣gzQV&&JPLgƭV-;[ "ջOW-8{q<MhFx FܼB|=)hU|Ry~fNGҡWeFm(]7 ^WLɅGIdF8᭙Z?K6~"S }_s`dFeE놊q5)XQ.KYCӇ5Xl*j&NLBK7XOãէQߩ/w_I`T]%7]U&>Tߤ NIL.X?g&惿QGWȁ: y2s r!6&:eI7M-.uxOƒMLOZ1$LI:nPfћÝ*w9 utIL+JC3PֻD$I_1;V׊HI2\]:d0Hʸ+Q =ad:gEͬ MVTAZvgƶJ'a/LVO1Jp%Q 4 :5ު(ωO0jܰkP+EBY JRjpʻlYJࡆc窝5jB!T0:`4HH UgvUw|XI{LF$ z&YE=5'7gBK[*׶sl2e+Moo݁pԝSX?bh Q@nA'IiIhF꣯(qOݪ'jeY,(]Ix8M0Q1P4%dL\'(-҄eC7 R 5ǚa;iv G+o04tIdf`WB>)5[x}{\xoL7U)Oe]f!$zS9R1 Kgnt\+>u5]ZWYpyz M͂aTEw876հ (Oq@5+YuiIso6]GT3JOԱ4⥳7>9E"|,-mbQ6ćBؼ5}'w s}#v:R3q/0]zx3-g)QV>Q;uIJ̌rS>d76gTnl~ɢTq 3Yh3Nw3MVWBkcKԉ:oL75FPvrR?}߬Ȅ  T gU0A떏12N1qk;?9yQzX- 0|nHz:4ҍ]iT*x[ sq(ZS]-%.\\,8χ7O:?SF}c &#'"Tg~3+[V2FoGlXFw?7H37 lޚtmr >oc-+򠽳`OY֢h;)YKxhoRY:u ʻGjsXXi *aWF3]SMdt3>o<;t. ,' ڠMFID`dO"QrgΜZ*&;e7锄2.Jrh84,{xϮ?V (lYz.ӈDG~2KPUv("Bl2_Q8 ӇAxDs,s#BIH-u\6`ҷ M'ēϠ/0:c@b([^S o_鳰=0'vtA 4 pX# ^|94YIH̴\vvR'lYeU 0gn>לh,gmkV v~~==;4%89!<{mk]U>'u3uyKzV$Y_JhY.~_|F.ܿ"}=mPmdW !c2[ƒ=B;Zer^XVIN7 )fJ/KVb/AH[y,}$敞=[BF ɇ}vSLa |Kiwt`lts2yd Du$JUH M@uX$i:}1߸_`{9=0=ќP9sYydغHnزֶSd>@ 2 KM=ۯ{a%?wQ8D@ x- =g淌EIj\Lҧ[zJpj inO+C8Jfw,Xq pG+]X~^?|UbqSNlg{5 ewfo\#ޭG[W{G]ΰZ+VQ'%<%}ftxw-hpE4;pqҧH(Ѥ Fᔌ3pP lOzj J op 2E [eH}|T1KxrBБ˙!ۀo갿vÛWGLJƦv Re^Ք6zvqE憏ygD4rz~\z'\ۑ84 ;Àבw#| "GyNSɌ+}*atKxvBroY^\.+b9Q2^3kNŧ` ;m^ Όԣ| ʚ0q lD`Kc3%t0]\r:u ^C SBhVX5,!1`K[/{[31M~=tB'gˋ?I&b? "=?1O61WHئW>MO"nz'P7-rkye$Q|r{O炷L\`m^<|d 1]\li/ӂ[k~:ƕUKub+uBޝ i(Ww?q^TDqb ->WyDhxupN cZ"_X% TC%1;-Q[K,D>WB{sQ妍,ԼuD'u{ =.~ +WbK-?W@e0#5{;5Zf5 aɴ-E("zpJR(q=&s\ű.Op:k&+ds0:/?j./Q5-յLQIYgJ>0>HS T T&Eh{~0 *7(>|#9D.y:%s׻,¦ݎ/N{AM%gHɹEi%ڨan)QMٖHB>Zv%dT(Y53:ak>r֔~nE`&@PֿԶP<T"ŀ &QZ~@akGB|qiGtOcb8CEk`r2 Zo2o < Y3)0w`ˠ>Ĉa N|bힿ\NudmyֵoWߪ5/V7W_{qg{eӡ/%HԲwnuKlWգygGj{U<QK7dF'sΙm W1xg䭔]Z&}J|p7̮ 2kR֜}/Sp[Qi$y.@d R# `[]Ġ㌜9 Êb'hH0(sZ2E?0t-B r(Hk@/# l0|? 2yVj-uE@'9+2g$h0ꏹp_EV0rƺI4,#mi},̬d'd=/!)i/IQFw㻔6]OCZy(nnO"̍WfKޞH`m9ԉMY1ITɿ#n} SxDװD  2AH zcɮ xQ!e:"ViHМbwW(xү1eU+Uu_}+R 2an.|kOT@7V\֞^"-v Lm75謅n,MW*\G~JqQ7,QUx$«),Hd"er gGщ jѸfV{q"2Cմ<)-`7'[d'UњLj0;1D3#i-^zDvR4q{M:5#߲^|2EVm ɩm]2JRV ?B^WqEjJo#" rse͝*g`lk댧 *tR*ar' *XlX{ a\Xb~Ý×ںT&=>1}b+\UW9r&IΚZ;r3MRl+qa' sj5t[g>?bW {J -CM6,e{JQr4ZW(uI5#)FJjMs6|U#(Z9f扢k2.__Zd[ْLoD 4'qFˍa 8\EskI&BZxPHtOUR ̧z3Sf(_Oc\mOݢmU?΢LA[ZVh3zY݁ FA9LXa$QPoNZ :{M63ͭT±u38*"M3U.8~r`СK 8}ch6 Koe˄4u)ȱ4K꒫Bxk_A.e30-D=|6T ǞЬQKQSrd$ ̎s;.(¤G aӂOn@m !~EKRJ .\bROBq:e/$j^[wb~mM?8" aU\d'I6e߽\~U7 QT ŤUJ%)lBd*lz3S\0ungQ4ܴe0=-XaV*qWǃKUJՅG3}5kFԫnYdn'Ӌcrs9t hɯܬYr˚mss_GQ]K™԰O3eT- 1_~RYϗ2f\gON5p,YʬgZϘg,a8I' >@э{;QK)i;VԭN[0MJUsҔٗH4l:Y\N3= OL" J:y|4-i4NxԨ{3 T HZk ˄XPZ@fbhQEEy"joE 87_ɔ0WAxuxШ*K;jll5%3E@<VQTWË%]\)$Atp'4n پWT[EgQiʽP(Ϥ͎f,;>cشBfݞ#Hj?R7솚?ІZ9aog<"tM(k0E4V-`rsɀUĤa"u ?B%)$NSB`>`:`ƹģ c3M06`fe6* @Oȇ]C3rk UTS?i+ OOѥ$Aʫ֨t WdJL`tX}3+R=P3(Jo(WP)ǡ(4stevyY-:Yi:'ug#_fÐA 'ݟqŏDȚo8NrIX:#'h9nX̐tĘe.- Å`?#߫Dc2w2.-M.g%e] zeBiE$iTȬ8X+-9 Vr}̌KTä%Z`.Q;;Ga-x(9lfMCw8nH'Ks YSv ,ӝLzk>:}m y؜H)( [Ǵe5[i0"gګ~1]d_8ɠ`|&RҠXsŪg,(Fx64.eË|w7h| L$Rl]6M Z6Vm,@5H 9B -5ş>^nw+K)YKa/L@W+N(@?8W R#$\gH&QE qT =Y7Q?`P`1Gn/.Z-lޯ 9F8#C#y'>Ԏx YܙȶSz oY`-O`@ љ==i UO1kC6h!L] 9sSVvYӪ Iz$Dr{$e#,.c3MG&'yOsHiA)Ak;2L,5jݳ'C&E3+NYḱim[1|77҅sL]-Ղz  SٔC+Be7PI|[EߊGY1lPE* ^pFUݫ ^pfMFwC(%\Nb$֘Z0{1w:j^6&m@n~1-JLmhY{3rƢD5[?7ia׶,IPy3,`n:a ЁHd$╖/QG#;iB[߻V-138r&.1٘9P1r2 7WinW ȯ.=K U )0_+Ru$Lq+ 齯 NF-9ZmzJd\Ґ6>sYڐϾ1 t6a;Z] u@sur88Ĕ˯i^>4G 7deEC8TI grYvUwf] g qсLӻ#I9>ߊXcՍ9=heSiǸSAӟ~\M`ryd7pIU NQepM;6InxwvYglWSA ӥvsnTϓHSuo(: C3\ "xGFtCba]l qC$tWBҼ 7NlYw\?R-|- ^Y"mx4,R?'V`ū F-QѝN` pKSdr{u>!~ xV2vΝpevfv3͔jiEi//37 N݆_2ׂOnΛ!1,/4sL~/pm2?,\U"/?(T>4]YYClL/~[RB惍@Ey~俋-VQػEE,"%,AkYyerYZ"-Ibp{*-denƑiYmei7p MH,P'?ͼ[Z1PoPZ3d1"К B> H ; C>3uHVH\Q,'ka> uLEx9Z+1XF5ɮi;\YWwlvX[2=s|: 0`(vKNm$}I%c̀iw%Nm-x~D0%-e~BMRE)R>&<,9eaNo FK* b13hdA#G+ 6~tt0 cEkZ-wVk᯿߭,UU=]-luLY/^9[~FBp/jOcWgpէDhaRoIpJ&֕jo0ŻD␈쑼C-Xv#໹e6WYy(mMJHKր( NSL-^z}a"9 z9ܛE7֡XtH' Z8ɑ"(3ۻ GZPznǺw<'&w9>|u W˹m>U*hJZxVJTUxD`_) l3T8ގo٦t5%5ވS8rKTDAh{}%і'K6ąu;!MWjN#`8M6 fWQ h} "W0-.O 5a({v,7%_N9]ڼg0QعcҗF4[Le2)wfW$?~(މX=<2*-m78{W g9Ϧ3]rЙ8%}Vxouz w&en lE!Qt|uwpXtAKKKzaw\qL8MxQ4jN(` k{F&kCq+ T@ cXjugubP!5^G L*OUvŎ[(ysds.}+Iё eԳ[,K[7 \L[4>)2m18uz6CML'&EYC\ϑA-wmuصȍ @hgؤ3\]O1:k5I8Y/ (fM'`DtB"Ko6^*-Q D|˨m a!brm-WrD5Ha`T=z}pyQnމj7J 3)NFN}~޹mľD_wOz^lXo4燍cVtfL|bm=^S g%ʯ/ Xe>YL(BӛP"Zrvs`a"4ZhH\ 'p%nj W Ҩ/(.v'i> N?[^l|RfSvkVO)H>a`)L\5 |xܯEFξ0C'-ćlo) TCdErMv#p`dq3cM#(Zpq[P /M֟VXQ y,oR+]>?7sЮIp˽xOiZa0y9Bٟ+{V?y?jD*WaHJ<rkZXԙ~bOɂRl5[U}NWP\)TfÝEq u YjFb 6Tc j5nN!u5sW,4CCVh', Q̫~Wy{p-B DXM9 S CG[uL o/eo(4%GB$kNR(?̃U#HHO13'HD,( }@`jM4AF!Uq4W'Z^z9R1_<0}9]\5fM"0 b΋aZXw>fȘ[Ӊ (<햳|nC l[)f[#t HLt}.&ɓ!IY*[ORq.1G.d:):g| lI 3\6!"h&p^7hjRtf^[E^Wk_Q?3Tq=Q+kH&^D|δH-ʹ܈gCp%8 ;N.% T=q7vZAg)Ԃcq, "(Ct`r+֊dJG q4vȡxЛ):6zh֣RHmԐ`}b3RB':u(RiSHZc>s؜Շ9~>? N}Qv:18]/UaaȻPCJ u:]Lg ?M_n?5 N6D[K1,+Z4Ьn.Ȑhe2 <U/MD<f:c2$Ep%0Fӷ!ۇ$7c턖k1ОyJhƞxcd0n<+ZӀ~,sEIV ans⟞#sQPYL1x(#Zfv<}KH8 5g@Z=8T? ,8s^ mor/%YK犵Uvi-(UQ.ٕXw̻2N)UW~p#x; %2<ᄚg<$R"JbBޡ`Q'9ףQD:lNIyHtRPDL:(/ݐ3|Q/p3H%װ|@0-M2ULhɑtb.QtgpPD:&v{ڝKq 8csB{e>M?> [UxWXU)F; /WYL~ZߊH&/{}s|E 4pV&%@z`; Wt@ǒqZ[rL6LTMI_@׺^f{]n"a/ G]fxJl?^ezlE\ɳA-vtUNc|uy( ~GI|Z 0 Ut{9;7Zm*.fp@y" ii\Wpoz{fe ,\Hx!H q~Ō+mٳW D֦!h.^=eAu02Tu#vd|CnB>mz{S/IfԄ@y' ̗A;~:N e{6T(r$ul2@yaiIa){CIu%\~R@~r] oXl(AýSJ߈,g/C@JtpPH>u=;IGE8%]eoL,p9$v ߟ&^59-F9bv\>z )Dq΅7‘4?eֳ̜Wwʹ3ʢc$YqmVWTF;Ky0_Ͱ?h"Z%O'|a]>ѼR N7ҽ 吗>9䱳(M/?6Xt?IrQ[4L)tU/% +s}b\1d ]V$ -!lG%} p;ѓ,Z` U9FB:"(HnUqDtQ딪8P&+`y_c7=Wpჽd(hOKo6\f:|ABpr:\+EyD?{=f[аPX&\`xAW^:0~sҷ"0CXLT|2BLNaV6Hזfu7bs >>Q*̒A 8C rdn9%Y{E*-792bjz娽ݰhQza h=Bz1aD.=N?̐Q+QךX4g/z[جx4%D{iFh" 8o}ốx h'$: CЮ1hK/BL_R;s:YbL.B^Ӱ56G$C*b*@r.7>vn9~nH`>W(Xx/溟gr.->~Pj%CwwwF/VHBԵ d#Hd>W4\LF0E㜨U@Y &DNz}))3jQYq{S,ny[C[V:ͽ3Dцh*6MlXs^_Qb]rfeZ 03hhh::<|ss,}W<#ho*ب7+9:xu6.eH>ʕ/e;:[Hxrzj4gqsyF>B+5IfɄH1L"m~J()kU3Io su- b*>ua4^qlپTaw'|l@&w F;:~ GQqWV#ٳ/he&aKǴ6"|{t,&3D}z [:%4j h%a+wW5u(g!Aמ4h #^g%%%.zܲ,'À z޿w7qd  HD-16K.'ՖF֨%gڗU]2V׮];pv8\*t*f\ai ް'w;{['oz{[;{/g-]¶~w܇{/#oT$7v;TeׅK[@& IH@qȲXfP^ /bH<&3H@r>e|-&H-1]lx| }DW.*7{p=,qgI9SX4AJE[ thhSh :3U$oR1;Xjm"J-ox%d{[SEy5vU{H \*cd~om.)ͺtJt"6|f;dkR{Ɯc\M8%5^E/Z8J'{z޳d>ջ+=aڦnB& X. &B4WU);øCd2t4P3 ҌV= (vHWT8Bo ֟=dDSเraq\K5kHWQ[dǷ\tIgrn7߀ G/+ h$7W/Gr۪-Fbzdk*m~㡑F(㬭)߂8Y"1 6y qk4 @({2A/K_XA; by_Ո(F9d%+,!c=Y.벯ڛi2֠Էks4d%IVcɫc%%܇}v .YJGARZڸ/8FtuW5,`jmLhw>ŨHMZQ+󬾠iN]IٿqC /@c#%ÃC 3bFvLhb!DV8N ;F8ܟf Q2[9ڄ!d!]t@m o)׿^Z8eeO%}23B-wmףOENT()Jzıb}մɵb2sc MZ6,1BZ;nEQ"mIVyhgg2;`Nѝ3" $&x)Gl\m7JF%9hSf4ӆځd#fu)Kځ2M&Y|6c']!UF|7^0ҁ;v>y\(80sjHk&IYGrSC`tziVI6  ]uZW;upF/ o.+_]${[9H!Fd'b njXB g3#M;=Aࢯc4%PWᑶ wᥭ;wq% ɳ\ej=S\6 k5\wƵjQ^3ma/h#MnX(1Ez-1 l~If kXRd?eEOl߮0r_ 9PDZﰠq8lCiD疒H.g4P x:eஸsаۘ]N/K' 'Suc߃˔Juk 5ٳ \m G)7fYF)=-a2B1L a ,KIM>zꁺdZa ] mHQ {`&-KϟO|- -2 4(w<rb3!$q C5{ujTBj}tT 'X3aXPwو{`wMNcY(W3kNC&caH>+V?"w ,,GvCjű4p ިo|[\E.Ѐ_=B,_!@U}g@8 '_x/'ki?]I%++bm⚮bSdVo@@xa32 5t=Nu\/hG#3V d u˾S wIBrFUfS#Rpf*)"pjRSi!` ͮ*rNwo EpԩBܓ  #̲4>Qv3,&4EYs햖ްT E˻;vwdVns1o'<ѽ ̠JX*Gd1>U*E~R5JYJaJG` >EYIHGigel_忆 4aU락VLjxQr SSJG0s_!2DT#*^ US.QSegԒ%Cbʜ3m80l~ Gra(;[J/Dc2K~ ӡHcPpI *ߖ.;;[: Dq 1,8| ̸hT}(đ;CIM,p^)|1Mk$YXHJz i!G]LȉxmEP?hڎH71'A8se7xcIKA}ж+@YhoA/kąVI i5ȮQYZ'Q}b]{„~$4D:&d/y7< 2k%2(5Fjէ\&7KF~+$:/ # v,qP8]u#`M]o՟}> ( z&h Mn/ 7uxvęc=pK\Xbf,*3锭BJu23FI`JbDt/4L\YE 0Ƀ! u]qٙNxج?!+6x2 M@m rD;'ˀ(5uѥpڭ0Q0"7 5T#:vxÈF4!bG_=y:vګes26K~otT.LSm-QL|$ 65_s؅|(vy|SIWzFv^N_u2*cIegg yY!"W# t 0ihԹEv8Nn;*@YQ!#&H?jm3LWD$uIt+k4IɠF'n2*hZU >[7U^UQ*{yJHtQ_mH̯Y`Qk/zS ?%r'*+Tqm,hf8uLd-q-XM 2Vfn)"8RL*R&\,υ7ICy;N!A! !Z.MDL٥a%D6rKD3[kP۶b,=BlZF(Cԗj ]!SCg˜+ ƅ\ܞvӡ$xy˄G˘0,@ zNi ~tElģf!z[rˉz"LJG{&cMY߰dNےGO;\Mܘ9Eo#zk89sG˕Rgk<󚤏,{X@Q-|fE6taq0!TРo9HVI-*nǘi/DWi@hgQ9T)\ B|wÉ'B7Btg?PD(mef1i \<6ުjG{vQWNUMvGSb҇oNu\dUe7SDShe~ -h\ē}x\ѹ}az +,kd"bN7FsKJ9_db w%6lի` R*=L@1t]J4= &=VW:B5ݲ;X^ +8ܡY titflxf,GbMdv gݐ7R k [uŹ[t[Wk+^,Ie[?h^[\ 6 ]6|}!~L6 R=fC!2o#A2o%w[Qx(e#z_c)2%Xhh>]R&<""*)EFd.y18Ыl~BY3 0Eܛui>򩁦 #G n'!KBYUU0V5kOg_B F$l>&aEPxM8DAD-\(_%\`]~=Ԣ=6>,#s"8^747df>;?9 =bڿAo` r(~Uh?x1r0P]WaڈjA@4rE`oDpk2gO~$OxĂ1^ ~:^ Sޱ3@/,~3l>qWKS^a\38DrNЙg,ܣSzձP^"ߘs_Rgiv9Z2FYV3Wе꿘)Sh^թbON4\+֣=gu4#=%He $k %st(~'UfqQ?Ƃ .H 1<TGˮ %DY/-.XfuL\=VUI] FVEer>Hqj$; $ʒIL &B2nWQep_U|GߝIX5 tC8*zqL;h* _:ls90Z "){՘.IlI/@\n]^z©{Dd{6,u ݣ}J@7ۿ&5 ɧFwoŎNnrZ< l4 ?''@Љl?*1<])[hMG۔F8JA\bTh''|#J9(8S|4͇F tfNo[K#Y砃Γ~7|9sdWjT+*Uۜ G Х^tu DE;/XX䗃F\3 6c|\QF[O; 2Q l,:u?>*L΋ \Njh&֓Ϧ +f4St[nW8;w%"Y+Ñ%>^Qʴe^noXA~-ۙmn ,)x(cL$o6Kq[St ߮M<P[Bt#\%9"딧z,`GHvXJ2:!p8*"l.\W@ӅL'L -go?h)dZ낔%$e#&.& ^ 8kfTob_6^ Np>3 n *m:Řԉk5}$)L`X,/-Mlj=Ӆ,ܭ۲?S;~#doω̗f[@-vYwН3J 鿱cu =&ƹ , (( X7$gSt%G` \ k(DtvQ8:USc 1RޒkpKFcqV׎Sݝ h;Q,d YJo:Xa<9Yz9.`}]`}`w-ƖMcm@PC{|nK¯pB\8Jџ+i #wat)d[e`72]"OYS&S.ǼVYS4;FI0fGJby)UKH#T?FԔ"0u3e ('q d 蠆f>ؒ#Aq 'ph X6y%*ȝ61ytt\#1l&֣j0DqY L#;Pʍ8E際57jnLܘ!Isc6&gf#f`jR9%s9ӌ1~j L5&_$BHhN0!%L|4G9w4 GӌB*B)mjl&|W4'IY$đ#ک1rw]LV!杼3m"f(*SR=c8*r1g t T%f<J# >eXd@VtO G0ԟ}(j" M4 'B }A=}$FzIo2MfneW%nB VVZL 䥾˙< D.3%b^7ZRj7ߦ[䊙5 rtx<: pyH kocXԩS04CnLըSަ>TKDk+QEu'&Xh}A bVі&Õ.Yi!NӤ1*k :ukf C_O";G? " 4My ͷ!W2kLyY)"$?'y7~p^͢yy\}1&x[^P4R1WhU5-Ad/۲IUj¿s 72:|"`?{2P?ͯa7{[-̊}eN#k.CZz@m=B"/Z.ˬ4SԧA":-PWx7D tfo ^*:|taazQ0)隽&5f"Sw)F a9?x$,D$Xso!eexhj0h6XIDp۳۽7jho)Rԋ> 4Ej*AN8 a׎J߼4 5 .1ͱ;|ŷwi d[0|>Uz-XTp<fU -Kfs 钃SD5 n@][T[l/ʬH-)G@!]{.taxх"zVߓp8_u(/Ҧd6&u:&pމǑ,C .B-J G,QPUG~y 7|? YUz w WGLM7뚄TojD !t-q'ՂFD4Aq/)DOX*E\j)<泐ɶ*mD̋N-|,s VGLMҥ-<'/8C1(nĥ#R["¨fOy԰˙hY7˵JYLd4)gnT 3tڽ)a~fm;BkĔٮ-]kX|4 Ei6<]ʐRPD17y=b2L2N{ 8bXOQӰpa| 4W\/C 8^X0M(kG`0be/bnt>-(-ˀ;U:zW$7{o_*Uz7%y_5YJ{Ff+lЈI1dgIT(xrbd+҉YAH^8h >GwHvУz;27pl:!*9Fq!q(n"0 8w [ OinʐlݘȵnI \gU&Ud}W-&hؿn}Dp!M9RiW{g߃ር{a&MApskPHLb_,U,ۑB[ JCH ?Fb%!⟱^h'3Rњ)ihK7K4fИGg hbR_.S{ -i,nE~l"/0 ̾ˮg(CVhe^1+ RvSiEgVC6:6;Z(4VD[]F2eKs|&nFWĬk O^r%>aMuNkv"ϓ#nOFHD@Px%{s(7n`G`<}^񱎍 tLH 95nF&?:[$JVt8,c1ƆԟjL]^i6j Hʦ +k:HD%:f\4_g|_C,E\T:i&^nM|blD4b{mӤk "\^ X!yZ~]| ⵶4׸ Z,yviv_bFY+jƲ5KZc!zd4 :Őf<2ʘݒhzYI@rpyX'M+lG8,^gAX|ؤIʔG::[Ď[-.5*dX\ B  ݋L&*#R#JTNh##[l*G_[wc AȦ&LHRЛwP|AoՂmvHB3@@s ׂLk&?=) o{idJ79xh !hS&)'qG픽Xd Y)q[b&Wxn +@%#XqRq C7 `~yQt#`D4VǣRcC|POdQ3 UQ~Ztsx9r7O#5ܸ?"i!T 1_`) ?}Q6W܆\y|儫 yJt7Az?{_.q,_/-$w{힄D" =AZkGjwi06v!<̞!MN'[d_3y:A݇?uN<*,U/=AF5WG(L̾Ȭ׏w/7(,n"rJ>ԫ5g}?Tws՛~7£Q(:l~SjѦ1#庘bs Բ?I-Xөcd}|.Y@Aᵦj a |`؄M Fh8}Io"*a>1sh C\CpbQĀh"ԖBܷ5< {>kd8&N)"AR244vh$Tth0P1ddOG+ tDq9Ī?:IX\tܤT>t Ч ̨m04Y TdcGLFY=:M.(XkPN!_.jQXU[_$/")h<^ Doq|j0qr&]d;N$"BJڟD6p2~O mc`CCnZ6swk7Ћ=xfuE_~SK;KJvMcaj}Xlے ?W{WdXrRߩFߢsk.m_ιdM`v)đ}vSEqx$D#c>R XB${thkǽ.+LYyLZKb R^K1 ,(n1v9.!%AU&׌઄eU4,.w0K0bxK,Usj"(oH{rY.OT K*MUdNɄXhl7ϋ:i_XDӗĚxxeEd"Y{cfr|0du(ԍ²#4-f FvDOFi8C֞|1x*'WTO9nh1LU`>҉%9LMxxԩL ̾eCl4 D@ aأx%wE6Pƫ"dXNC(J4=/'_`b]fz m\vnQ]Űh\b'4v@+*“=j&({b %\OƫN=__'dged)l8PP;&+rc7T+법lv><m&^ ?'BhxMǃ (vCr)ttvWRn%YqzO-v`2h{_RT3qp ?C;^ l1i4%G?vz'om%+Ct $[äUw;L~9zV彗݃h_mVyfwG5/N^6_w;;G?w{hwX%Z+lH^n(jmtwխhͣFGD;TjGK/aT[?J}ہ~`54c>"P[-aGU%=wG;{PZ{tЅA^mbPUw+O=>:{sAئjfGº;TP2^~x?ĠekO)yٓ?Mf~׽ |%JOH%=TЅE=SLl{H#U~w绝#5u 厪ra =*v|#x?OfWwWx/'v+{^.\7/\ݖgsaemZ-EZu6}xx"9{0LнyOI >L|n,-: GvIi7=z? _F~g,Q֟,)-~]j.?hOYTi`~1)˧PIz;=^F%u ~B5&_^ :%[ P~;#S=gV j=6*Vwz?zAgiBM~S,8Mtϯ1L| Cdn8Q,\?` 58zg!TҢY Z6F{jRV/zGA}MC~8dZ+mw=]P(/ndQ6խk`0pLKCA'vqN2tuQ<PD]o3 H4g ,]~ݘp5z?)訷u;8?hlNN: /Rͬ9`s/.aYxsiqq~Ѧ'~jPlxwݺb?6L8-Z) b*_4lf\i[6^@}IV/5[lz; բ1ح5{Rvb8Z]b`|\k~Ÿ0I4{dS, L^fx2p$Hj@! Dƺ4#4l$>Kkx.*c?!g+ $1N#KgGʇGlLB>wӑbKओA]J)1:P 78G3$2xgo3D1i?B|#M! #FRb_T6HP6 ̥&j7'3*qld BA"X%}BHܽV4`Ԅ_nb5U} ~xU@t| 5Vp9y6*SϦ!HaQ\Ep6 EO_2cQ}P0Ǣ_@q :O9uѼxG&#ĩ$U/='ΆbO&-zX'&8=Ws.dl;'JK ⪛x-ib7#s is]  {.a=}ZmO3-a{;b`-1EtJȈ7Ί U^uVԗ iBVdH;hˈj[%c*hMžHj0EhSoex pd}8ݖQػKE%RI YߠW#4BWtN-pb%JC$1=P!;/Jc]"_[n %-\&L=`J ]9-IF`V9/}ir/k.U9Z`>4 "kud/Y;JcG^>!$ꟳb7qM>4f/j3 u0MpU/˴<.1B!H3w:a*uJl,J{bT+PuGUY+񲪺=:$a𮓘DA.A)!r'&mq'Cr,6@ ecqbs1+j,cVqbF̺AOPH곳wCLpq 55I"˰pV,'$\4ͥ&@@h *eY灚u['LGʩ|gOFu`L\4}擖YoWa i8`dL[ٿPdtԡ]+ x#!WAx4g}}再L)WZ}s4!+_7 Ғo<X 0jX/)N83&啗]5}iׯ&i.QNm 6ʋNk-c}͒Wc'mNWdYbLq4n,'X^G yCO/^|͸y /nX ۸x,/T~!W[Ĥu00e>9p t}ِ5c*uË18 dVHa-1$.0΀\-ezz0 2mm6Ze-9x5Ύ .y"vtϮ=.0$(0496KL WO*S.4O,$Qi-o3uFh֞ ![u,[7\ \kbX"3Qf ٧i.NI+l,B#]|>H3! \l+SN|JV3 }`m#*xtoTL,-lH>#]Kt+L~ հr={^}ܤ#$X("HTf 0HeItmc\b[Nl8n9ؽ^\G,Ay0DkP.fr@ݣW eSh{xoˈ_ȏlls'*cWEvBײu4?8hRrE;1qGw 6NˮWYͽ2Pf1\ 7u-' Si}58BhTOmp\mr NK=2>%ːDX6OpAf1Ⱥ Xp9 htl/z qzqF)< <=qw! l<+E[NjYH O?]ABM&6 `B:Jk7,K۔x<m~sse tiW q쮶 {|c bg9r(*Yk֝;yp"~."8lVA(N]&M*\DieveG")٣4)Dv$߶jZ&~䂧[L2%CKdzw,];m`ct*a "KwVH\DJz] &wѭkeI'dEbI;I1L` SYVtalxM]3f5E)LVOR͇=p4Pa||oS g^!WB%.KCzhUWd"|LiYџJaoz0Sɜ'XbQ>|ND+%T1E\9k<apm ]s@y{ ]}.S HE*<[ǁo  .-@h=~v$&%|aǃM4lAaA7 uwHd4~>0r#SW> 1f `2LefgTK8h[I)4|yMŭ#(D=F*V, 1]5:Hohx_pwDH4 W*BVD:H_LH{H>RZw;ڰDwvvZ/,6JXQr^HN#o(!$5(T&޳Eɥqv8KL_6X+"pw^t7^N\T3qqz%,sh胁M:("(^6j:TY[BҤ[8DrPŰԼ^LFǪ<aG:% O<^[M3熱ZAdUcdZۧ)(drBt[{MϧD6d488Ǎl?#fN@fA1LrzigCfG}?rUve`A(<e:N.!y߀*_+o[#ǽ櫞bx[K|7~̿ma5v!@x tY4P[NٷBst4 [^(g5__K7\Z/^* !)` IgklPĦ팣S-27oas5tԎz^^N3I=ͨ [}&q]L#j]7Q~DCYqY8VLzOQ@ ,PO tHɠ:xhJA!(rEpႀuoAN9eiޥe̙k$܀# Ղڃ)@ Uٴ@t zۨ4왣0@sXi.۵nIP^ЀeSY@ʐLĊ0omB4}'=p+}+JC|)rLŋۙ +Zj?W=p3}L l:w 6pt-k=ޢ,5g2اy\. h~k[BN-K)gM2OO/Ouy(;\jc)4j2[&7m` <#ӽkFYXu?_|\U'#/?bvT˓I6&inG>w)ːLcMIc1F>F_[#DRE\/f!Q;(2OtϓpCbp>y>rʔZLxFZ&5) Ai<+2w[D ?l+/!Bs?0²}ri67n NjT)}\Bz?9iMP̦IzquPVGəMvfipW%zk^Z;R=iD!w28B[ZEjh͊N|P |CӓqWR i %^eX’:cx93o9% B|fH TLxً k/?Tj=yF?mWZco6Ecn\e &j>)%G84S &lQ@nR{A-7f#u ^,b#=V7qնPD8 V(LiDQ(OCv/f,K*=/Ul^ݨ w[(&<\PE]vm.HS;fA1'FZ= Č@dmQH:2=y!lM#+ u`%ᷣ[`^yЁ(䥄08LMI([F]J1j ;NnvSgpf{|Sw]fw?eVVR^E5f:XbذuKNRrp: '.ׁ<>acXp3uW6:H6Q c^(O90XHCSU੸LaQH9±!9097 F搖i: k+9?~Tqm7MKVi ݠg k()TD/A C\KwST Bnkg/ W&}hdU1[d  7=mr8>a/]ɨ=7fiH5 硵} T!/PVVY(cM9ê"X†܀h\ǏNŔ$}2ce"HhW.>zg21%_u/E#9r{ʢKn٬8<$/./Hg:7Šk7Î2-Vj,6?p %S$Qu9O͙rTbŶv߼+62{s^E$ LYA OJ B0m;v%k+8 {0^>S!-Zo'|&؂uH)1?J:-3£f)"y e/<[ TWQnh\cq奈 ^vRSvrζ؞9#|ji2j[h˻F@TpU]1u|05j9;^j&r?E8]9g: &aO3<'7ٽFS'H< ,A \&k;H3PDt^ԹMj:e$zg]'*84˓?=uCxpՑWuYeߨTU7IS(B^ <Cf,9:`bJ9JpN =:'zCSx:S8=Yi}yra$ǗtP:<WN|衃+h83xhe꾪3zT" b/\[j `K2*\5#:龍j;Q6d٘ɔ0{ckptTXJw;YYv ;ЌMG#0s9lNknQm<|Mq|x^4jm~=jW$QS|^AKAIB&n@Es]1k-(uIM# @l{ B0}ϘuԶӎ0π\sw|kLWrŠ;xx5?~X[[) _?}?zJ1D(#?Yw_O`ߟڿ>z<}$_=y諯ןɣJno?_џ@~kCl'֞\&AmljUUmbpUZ{tЅA^*hoXh@=>:{sAئjfGºmleE#HǤ=hշ/KEJD)a(a SVi ?{0 6p椙di'Uux%~YL(J:ͧ~omyW[QMx HB[ j<Olな|?:n?4C*NnJuQ ϵLxj·Zzhnxq _ut<$ojEp'\TBs,Ϩ%LSUlv'GmAFjP_Uflx  ZB6_3=<:9~r_L]2@uW;ol!hݝ}*R=yxL§i])Uwi4j %qTnI EI=JT狺!:0_PW~]s7& }mq:1S_ (T83"&(O%" , ?4ؿ7g%*? sLuugɈj,/9XGU_ҒyRda:'`"/pư(K0x WM}(( ,Z]z\4mftf <$I߻ԚZ=$#u$ф"70MU sׄ ly)`zz)q(h-W_<C|h!L@0Vhi(] +> |ִ H 6/43E,`[F\V4 #uWx HM~ͧթd[`xt^ AtFQ Gۭ'd-:O0ժ|Ll##q'y$2(Tr誹+|/4'^~di`/aʔi:+يr>B5+//C'#KF6\XCr,J%yVDCؑZ"& b8M /. iږ :BAR+8 U' 0@c /4՚HDTsB(3c&{ J:PAfVw)hX xz+Sŧ@U4kZvA@nU!G?j֥>o@A3#y1s7NUmb#pn\'P@R3rI` $*Ptp:r4R濂ze)D#81 88Ǟ)\^3r %C*`pBE,&asZ·~naN\|ctnlo갌x?ZBSZE5J,kZ$8( ;pqv:2J1t(sT *k̴+hE3.gXգ*#g4\m& &zREh*E{E^~20ZMА,@ *O% 7" &t%V`8]Wˇ?_x)?D1*p#4hP) c$`h-kX1eyrbK԰҃H =1:!luY%3,.2uߊ8 |f9N| Lp`E=B Dyʡki5 PiDOYIp־9l@CK&l0ѶM/raq+3V=w/[fSc3bIVWcǜ5+؀y*vn<~s=깫Iy"ߠ!p >[) 'dMlL.˦tc jך} #kw1/vQu\{z@s% HxC6 Ҽr V|N, ipB-WUB$XNnz0&z0T9#!.r'|1W( 1d̞ݘ ؊I%o{-!,`l\c`dzgB`gWlI&|3XZ(EUG˖퓮: 1"AE6""Qsf#Ր\>޷@ >j6 8=փuӦW` %'ޓd#M#l Y"ᖪ`0L-?-^tuhp`'F~TUyvBKu"4{$drB~[鸟yԋ݆q+Fօ+iB;$o~O|1B,_B!NAFsF{أ@ IV\xi w; *U-S6F[-S Lwp[[;;ٖ&:%ZnNEz̙}K7W+m/ld11,H%=wT-;rE5vHOൠ =y{%+|@Bs䙠 7+_aH2@ǢmfkV^]wkd")6"Ӿ¾^&'6\Kd wt1z %b]qNq:)q0.&|xIt9]ӟfskK4>q)2w2"?95R #q5bN@'nE4Hۙ)# ]$AxA,Q>vƕJA1`4-ǒ?^5F46֔wՖ| 8 bɬR53q`"(d$CڪBG h[߉zCN$5Ȭi^T8]J0difMTw ѰEm]RQh&ǡWVǢ(#EiSL]͎G?(.ӈ'G \vR)F*B\w)8mEtGz̰InWhf0AbmH,ė[g= {Kѱ-B0/3ʱw ؃t>{Okrt mV{Nx@0/3Tlq8t9/ Z[۲4M~RsBj1uZ(9U߈[8>v}h(Wm</KtErҥ@-ׄܪՅ&#-6#^FqTCд)l(]{.,=fZt/j^Ѩt bhJiVYpq!$at=G5I *t(D5U&}<%u鍵_@{"fX/m(1s&a{.- "e   <_C|}1_+䠩#ܻ H9h6Z)&m"*z=|ZRtQQJv mb\FQ\{-' sy_? ]{Dk돿^d}}Wk+Y1D̨?Y5EhO5phmɃGk돒d a$ M\[p~q5i(4.?IXͮRm3lz1,ȡ$dHy1)V* RM|:9'⿠[?ހ:9W;rRљj ק%~}3%u2ĎWLÃ$WN5fwo=)9agtJۂ Rvw^&D?w^AK݃h_moĊ;E+ngwgM9&co?AK6]/~ſsra7vzGL*w˱jGK/aT[?J b`?1 (Z65ÎSKzP7 UG]^fZSu*{|u:I`?>MºUPهU4;_17 ՘ƁpUY僎o ?[iʯls1{8/ ;z7ֽI_{W^TFVr|uG4߶}l_g׵+W8n:wMsQl~0"~y] j6Dt W  2@#}*z@nMSVlгӉ|gzw~U]@|Oo\E0 As{D(ȧڽwGD]/{TQ1ȅ޷JɷIKn?ӏYbCI:ŗԖg찷z^KSYNlk9u0{?m&X6}gnfu~ߨ*Wrb::WZ:Ef _ΠUnOѲA&bU ?I}(*NMDa#;/ bL(N4|U~z gֿzIreK鴷u uy+STಅFQϓF.#RΞ)]oYRsmYOIB V$wI-W4T_m:{.dW#u2PL"Eq/~C uWz~ȱd0g我mQ?BD iZ\f](2ʡBd/~뱁Z>~F!MmQ<3]'YH͵zG?*jT wY{EfRQ.̏&R7b΀C8o:35KaMh%ި8{n|_*:tFbx0 ۪Ea%o4VhKKp,LXn.Tr}^$l/a?|\PPzձXV׆CZYD%YIL?'+@!E5_sV%~ ʉ3,z|i@J6nLb冰x?QKO^~Bkv|PC_~ bT@hd?>x^bg[ZkE /<s]X=h{ 1?ˡv}lj4OP+413Y9986LWߕ@qGOn"SW,YҖϖ}TO_K Y:<~D+Oߛ4UC5Ѭ$ 0=fޤԂ%P``̉b~VNdWiL!Olh~lC s8{_zÂlP.[6@b7l gFixO 0&0fxc06_']i9!,9JE ˖BC>/SJJ|mZH7)9 qPԖ34rTk\rv .Q:GR~ =$KQ=ʯB~ċ$<`"@~6ÈN;oM"YJc[/Ӱjc2aJwdcP ? ԙƲ _iƆ.qzME\{X *K@Ir${ ~#vVɰAG rLvW aHkZ bi"`iB M}8b6گ`w( C30MmG-c E5M9@o CctQm\181DKp E6:c(ʇ@{- 6l_z,,b($+V&S 3ЎahR,P6vvFm]dJBK pX1?~IiTM|xAJ&t<_('x1IjIB:MĊELԝrhT\a!j,Gp\ȦsvUm++!N%z1e&o+ZEmʣ5g("T4[T3dzH}bGc礭Twm\ B;v&7l &]_,4CNlGC;8iCtC3˜ږqq}a} =Ì,t=poBb.z4xb#G8R]6FH`>-u1կ a1X$wݴc3?66UOiIs~9k89] :>=|u|&V CXJaź#Vmh->}uiT+8MEaJ4b#Ph`s_ݐGPQUY^l'kryfe][:T' ׎e>g5mVuh X*#G;'(oCuuܶH3GZA{QVN\QҪ>!.KX4[P_N,0(;4H**|uJHÝ- X_nH$k< jRMxK]e<-' ԕDm2-KE> gGy, Kہ ANT*(zɊ4(#OE2Jwnib1?Le{(XGhJ?kߦzŬb~Ja.)^M~i! .Wte~+uSǠ|JT8O-*EmM2 qKX0-OO0%Q]g܈Qߖ^(%-'(xӴ$~@ҡ`Wh$t~&@(zbʀ> @͋ 7IU Ht~ fi\c+3'ϓB]&-ۧj Z#FiR s~zYa NP#{E08J!.6 l롃p@8~¾y D[ apO=٪ӵYx^ĚŹzjk`ҐΪHǤg*&-+EvN5GBξ 4^a^Z'LE6pԌTJq J>qW#M) HP0QJK\n* $S]`ɨ^Y@À.qAx{Eg1Ybiv Q~m5iKt4W_ZP8vZ(n-^.0Yp޳ӽU|K8U̠8wlJ A>]S|>kfp]e\\>HӘVΞ솉iJS-82$qin( m&$e!3HWq9L8VmEC=D6MQ@&`Lm tx9`:2 ꐨ c\Jc\3w:Δ|{Gzm|w @' BB Ƞ\dKcA Zw:zu&nFBu %7 B$d|(vI'띩p׵O޼NGQ7RGP&8a(8$dPr?oN Uv̛|YP&G0Ysxvp>FV|n(IPRT,@"y Ⱥci6kap g+xW 3x͎fUxE 4@ I_k Z1O`D<6T(<j޷E9P#!T1A6*Jؤo9ti5WO_j F-oS7}cjyuJrh˸琒e_xa?. r(tF)d\ (N_}A`/Mڋimi Q |S;Raȼ<-MVd %!%I0ғL%}ʀp`>_;\g2jNw-ˈN  ̦"M -ûzN+ms&]RDVay4A0~HV$ht ڤ+׾$j' ˓q$}qvLUlNI{&d{2V}esv>IXO/~3gE^vuD{;{/;Tr%z2Lfg|r>MjYT$_&_lIGvn bzط7)mhcM\~[Y62+ 6S Y "~/ 2y1Th 5qey8fǖ́߸mQkPr!$ .3ԃE;|$/uh sscFt˒0;["a{m%NIŕ9&[3̰ԟL`^[wF3`0TE(e׈NCsVΖH{3DK}!sd; dIk 0Ju}ȊMc1Ĵ)BMG;E99!F" .!V NJs⟘` zvu 0Vl;ar oM oBmtQt?%}&j&xȁ2Z 7EuG]ikhƏ|, SƖ٥ҭoHPvbe}N"c#9Њi|Mn;BxwmW3`dS `5%ubBq,VHH))_Ԕta4[:aEpP;r<(#U(9C.;$r.vߙݟ^mx ^ ('G_r JE.ﭻ{e+M qFrZA/"Bx/&B^?qtכzMqkc/ L5y9D. A@I& %Q`t':e_\hȎ9ca$X6Do0+4Z1f $TiӪllƜH(91QKYJgBcNJPpQ"A-TkzDF(p)Ѕ*u0P6~oˡ.eX`ib3HMw(a鬄PAD ˄էQ0CrO };vmݖ{Ʈ ~;¯~ Z{slw ИdJ$ k3Z͈p#> Na 4n!KYazmIWd_SDj +Sl~o[[2f]& ^Sȳ 2-p91݇W}TЊ>,ZU#P-Y~2 :meD zixTd콚$epI27^:v6VU-* Ӏ&tz툧P.{(\]rxbT; %B~GĊmBaߥX~n?gpFqA9%qJ8g4jRT$ËI>U{aCiċڹi~HHrݥЬ,nH CI&CŤ2 $`@PЈ3+z|/9%zӏ<_|%:E6Tw sy~ڨ%'emm6-@@8tp%rzd>4I}2>'yx&'jQ`7MO{n1')Sp/[tb\Uף'rLFgmliK 8MB1lw`rDtΗF hX%w,qSَ|7$ DkyHa ^,yAԼG뤟OpF$89$*!z L w~IJ́tc2:^ K0pT2fxHL?! Tj{i瘢teH1LMdѾzmmXq'rӿ P8%x J˔n-\eRYsd93@w  w;t"]n*Z2Tbz~]/n$!(Jѝ]"D6pQ1(ZUV yO_6PaK_~ gwB'-x < cVT\0&YmMe/Ol `>2vk 4sq^_VS:B3)P(WZJðxK76Xղe> RC8 BUGX5*|ZiX}cƿxG[FcL|iTVeނ vrB>ff2OYxtL* O n Y U<v{\bc-–l,ɹ\};΄G1B*7ayߡEܨcYp815_M7U#Z@Z5Զ5G)em7#wG'u\Y jr-'Tz2hަ8*"?C vl4i6/Pf9n|l}[a."fTqh5^=9یW #Y6NHrh+4L`h$Am:dc ^^1s$;;0}(9 MЫgÈ0 MS利ãCfz?mNzI'9SRh,,XL6UnM!&ABu`En0ɵƷY\NAST^Q?f9e/!k*Ȃk=OhfQ*Hj! ^rQ);z #$AP@!҇bLjtB`*KV9huP]dN;{@K>|B7A-g:&3/kv(  \TV+De-JqMp4 &C!!>$4%W%֧r Py"6&<ȕ3_) ?es =pP%H,{74f4ONA6塤4fir+DE3Z`L{ -N 2E+Άc_ǵdm Q9TRQC8+]B |\"(.?9r !}2ѶW&&D,Ti=|7f:tƣMt=M%*S}cMEmlC;8yL+ A׳(mzבUԾ!HPS.lc:*EjԺYp#,mDGPrHOL9܂ɌԙLKf 8tW#ӔFAϢ"u 78QWiy1Tтu3\Tqd=Qb]5RL+CnZ]K}\R:qsPQ@n Sf.w ! hxV1Lv"Cĩԑqätl#N9A-埃\,}%~\7S~'gM0p k\h1iW+0eF2 :N}p&isp8OTpb4JrbM庎hHg+U{ f1Q sZd @3k?NXϜ4= ~fcgvX7s--yT?eR :!N8d. {kRœi)dptߝw?Դ.')S/|oK4nq{ݭlK,8^0 6j .~Ӣ-6.Zwv6[umr0]C zǒ:!>=qOq[Aa=;EsEvəЍZ*[l:v6{ )ԇ7]M%M#(1 k\\0/~ˍU?\7Hi8R$ RYE4,ۖ܍ E=RA- WC EUdqșÛXOզm.a^A!x 㮩Ԥ%k9|j'.2LhoeM?20UVE.aj?ZB^_SWP Pƣpu5F@PYmI3i]/85'2%Pߒ騇Y<~5lJ4P7N̏;3뙁gf(]"ym!W,Y tH+@1>_ Ujb=6Uz)m#PGy gkSB0ys"Ew>x@mVO3EA9_eU]s>p:v(n1a(O]ZR5bad~܃ ;)'"$mw}<藸iHMO˜"W8WBosKԭ|Y) Jf-BYb~#LGl!@a$} ̚R ; n#HMkn>y^&.陿n[ǒ{|YJu!h^/G+m߱>E1? >BJH[%vhڌUJc *p]uH\R 0?se 3oс-قe%/FAO#)Z >Q5&!O#4aq?o41Qt cj/:4 ?؊Ucݝ=# ^9{Ğ=&wǡ6HBiEOɽ/{ӚtP$.}v՟Pۥ+d34vgCL&<6uר~?q5cR_oAO׬[܆hr[FX=i G<N|w b0|4 ]#-w44 TBlhy?d!¢хB (bzysR? -IAU?c`3[(\ꟾZK.wYrnޘZjumU;ܭmjF7L[%Vnf_i?v|:M$+=z3.~ޔ;c1*I8f]dsDE~yb?2g"WO tٸ%El_NsIc՟[ :y{ IesL0l-?_VxHIWRtm=J9q叧Lk>PߥYg_D?4!0c؄RvBvh>I^AKhѯVc% )H.啧l=v<k*m"MQ:k(UGw}RD-/eK-98BŔ A# fls ;34eÝvՕ"j}]b NQs^F?Aqv ($Z#F8N%6H`7?O.ûӰ*M 2hX"F-rKHl;; ?CDXj&w%^*G/rhzo45JwF%5BKqA0S&7b׿>.&)jm4el rQ NPTМN9u~~t:1z"4D[o66«ďLt7l8-f-Y8qgJ5FWgݔ`.>6Tp H/ߗ_nP3 /Sr /QF:.ӠOz\-ZG$as^<-9XJ<] B/ߣz&v -O"I5L*nư ,|/نu0T"ܷ_H9^Ev%VAF5="a$óN{qvX|`FR٭Qw_h~fTjHuՉ’0q/=Xp ʈn( Wk!ve(—hh.45&0ʀIF&O;z `18bmn",bSUJ#w C C/JI+9= hۅq,aoP~IY0Xr5L w 1A:)D>j,?gBwr^}x?x.w1@ƿG [a[¿h\P~U5dVsg̷ϋAWo1s@S"m!fY#a-%b^N۟ЈYVfeHmlTx2:bR,;2kjԬEb[Jd)ۦguiԍW+.,O#Iڽ?D E#2׬:΢Y{ͪEZ1~ZCv:!v!tE1jU1#8UY-szmWcƥkrscTor-'hR<\ bI9RܫjQAoֺs"[Klb*A6^`50νʱFiP/s-j*^Tk)khf>3"N+jp7B8dt6X%^ooډ3G0bmY6U%Tp#p?r_ | 9W`2JrtZ<G P&4@l ҶI $$ohpyC}G_$ NAz{C̓^ao7GG+mֆiS%۽f+a{18g}_֏vVE>^ղA#_nśxo*^f@!ʔ7UN=U]A 䡕@NJ 7Ү]4U(lG tQ6J%/אL1vuz+&e}~.qrX_(N9)r)mö ut;v4LR`Ʈ4+j}h*_Hյ[`-&bҊw5%Do 22fĒ:x4mWMr7WwZ;xÖʋAg9"$YUK搀䣻}W>u% rHd9Kik`h-MS(ûPĦ^̥r5 8{oh{xoˡhh\;czF=B*k&6TcwN#%w|m j"}pw ᕹM|^Hg/77 \8o'ooS3iS7!PTя|e|M .҅^v-´,ұvc.ݫP5ASr@%cQ N]Ybe^`6aF\yMXy%@0)njѻ'|{ a#oGHW'Gpäc5~q93qy6cH썋dIv#\lh6rlkjs%XOjzHf9ANջz5~'_f0"ʒy1KymJ d<ח"#PMBj:QQ>]' 2 W~;ӧm/=9-Z)j7wx/AW@hԓvad)(|֫]IS hh|.U=~elȂ-%!ד (84OwZ7B̶b~N[x Iy$IEVNX0A.jllfg{!v?+:Dyno[/I>->؅nd~? 3l|bo!|X1@<jA;G/Y ف`b@Cc>:P_/v,83lC'k 8v(b6'x4 Sfj?3ERo~张KPDu0+Ĥ%J^@?wbS & a^џaVsӴVxAkd',2;E w~:܅YXEcrcQϚwW;$:L&G{*xOy;7k5ӭw/[BGb3ȭuۂvQoc;VFMp Kw*!30n4I{X&;g.npt S(}~5wN'LFA}f1ai/mD [ ߓS w"]xrܮ;]3@5ױ)b0 ; }>ƣ5-ƭ:CċF;o{VBDԈ֍-'nP;G>h-~0רA+|Zr'ں]yҝm,!^fcd$${R$/0ƪooAL 鄔- MѠ`\c᫖Vr] CVh>Y:9K)nQʂ J%eQCG`*u #7}ID"lnk)z}xs!4w70T(3$*`M۝-dSSM(K͜VxY2z9!ꟊDiӥ?ѥOh.m~5E£NBJ5^p^+g}n֞k ,oehғ!P~ϡi[UL;rs+HݡPJ(Ŵnsd1T R˯'Qٍ&4DI:ͧ,!*j3HwBYea6mV$t&EWhΨHG|!d>-7UZh^|1ڽnb\4c/f̈AfTOk`UeH|kVu7<"n0>")[F_y\lZ$OFcIJ'n csiЋ]&Ilɦɒ|xG^kdrgsӖh X'Q> ZK`1 !HIHjnҔ|2" w|B ZDYZ؄_β  JDMTMVM ȴ=^+wM0sjlO1<5.NdkN} 'ijiZ. MFˎ]R13ݝ̄(3jnh:g07EY>Umջui[LU ;Es]NṙvS vB({Ҩ f'1 q6HFNEMsese |:i$WCZ0Df 8 R׎op}SC&H%UB*+[RuAPJ=T͐^#OnWs˺JbE>ΫF/C3#i+V#27#<|z}myt.]uumM[l"8f_`yl|RP\Lj7[M=Cm;ME'G8 sd GY\64d8LĄd<`Mɯal'`,\gRm, Ov=Qt.-\su9db9yx/g//-Qοx^+zdiV7ǟm5J#9)qre^3gWt1PTPe[kL< ]kTH75~ÕQ6N̆g.ߵE-o@{<J=eij#2搅YK][Jg>|Fkb@~L&}r~Uo5Ma-xRlo~Ȏ cjP0"^ox[f "!;m3ql4 nA.! h;g Q%||4 (E^@K,nMgZ`:bsgbs5iv} xc}@\W"C4qmH> $q؀.d2'S728qsz ̝ %ԋ6n:;0!7<%n)gAl6Nh<f#'B,LyKpM< ߬bysG4jMty걓/|{p}=|%RkO1׀BNmJ<#NzWRȖM'B_ƜMVuP:x>,+d jxk]p_P (GH4b8qw_-)p5HJҐnB# Q%ͩHDB52@(gҋ U'{n=dz?Èuf 6#{{r z[Q$vP3cugI#ȿ8M8@15$d "Z3O?% O͞>NSD |&*p0XYaD*FefXTVnORc"#^] BWOPQ{n!K%#1Vt~ ɇ\r1k7@!7{w7aayTZp2 5X%4n w5IJ$m3`u:S׶[&5<9=A]2| .Azx2108?zmLhvcz:% eG ”< |j@ppd9c>JHB!VdLQc8QZm \iH!!Zͪ)Zt@RL.ܑZDD4XLacx\׽̫TMq cc[ڷ#V\5}+9Rl6 0=Xx@C0a(y˱4nRy*RM/ӑ_{ Xvh{ ]{&AweĚ(&+KLJ|IsTpWD =⋢hJG < YQGB?֥nM P6ؠR@~85b eFOQG d@ABK"G<I \P[dcPerg@\$&7U2rWs+w]1EQpy7Ob,R"E{lB;A}5aه!_E|si]r+ dS ߲卶“./JO{5l052jr ϪVsp1'+ɢ9vZ.2E:%֤FwCˡ$cX:ϳD?C  Ȩ'yPw{ysz.sp MV{36Fk>Onq~:%ttq;uSE bMFi?SXL]HVk)"!6q0,ޭRθ#_#Dޖ+SW7 0O-;<9JB5( {@LߓBߚj% .Y9ސ~_뒪iXH2|6}l@$Igm s/_̓ucdvEI3Mxqb˭B[ sm 79w @ ( 1]۵+%vW!̳.)yg>tz~ TlȄQk'1GVݹaAZi@X5kо B jkǹۤ#)*갌hX8Ecmkax`=GY]kESZn86Եד)[TiKԹhG=Vj7h"R NO'DfcoU~.oJd5aAyDnqwz8hIͫ#Ȍ䍵|m,PXXcx`QyΜ!oCкȷ$=n+ +63l 1j撼0T31 fϓ)Q;F#TՂnqmhj䤓/:+f׎0 /+qڎdqQ&еH^qr{EY#hrLW`>riTܴ;#~4)V]acUkdg lq)Ȭ:% bK0M%3>?"rPx:V~l};<:% y_O=ɃWt4_?ZaW(V5џ7_3& ?C&b? g"fmp&?m/o{ [=a L5tں *f )j2f %+ґTLTR %>sUEPBɢFC~xe/ɷy~ saWdpX?53y'J} h:B*iqb0zkfnM9`FoITqQG dQHÔMs&AqRNe_BiRV0k 6BT-t\)29/ 'De 3k5ݷN^/6qʸ`5JEqǼ9i,̫eQTk {}i,/t/,b_' T7+5 DHM)me腽Rdaʰ9SȘ8R<)fm\_:S}[}QޔiImֶYeF7W9fuQM=!򀘋. mT\{nT;&rl뺣DFG JCóMP/G懢 w a`x[WֱFM9Y3C#rqm3WeMŕqc?$7djb[E-u#qB0@z~V(*1Yh2Cb GNL$nii|j1ǣj),5j(C]E6+x ܃v qH`zL@Iע&Ƃ.ʛ/ʰ@3 ȡp4)ױh& ^"cO|gLݟsΞjQ7-$T 0':~LL}W@ pQDN[gU;Jg2+0 :ΝB5\C 1K-JŒQZ@YF:䪛)fN9tP8 ju"˸pV@4Fk!c.8$:g>/ 3 9CeMD00]F~C'E6)%"Cx!ufyjoq#t\b|>SD^8b5I|a[O]˹qup9Lo"2~9!h23<6LXd >p;*ا^eK up/Qն! 1\ޡ1&j =){Vu(pJ%1#D;3napA}a*DQXr}[i1q5l@卮JK5ܺKTHhn 0 G#9$&cF"Vx|Kf_&azn#Cp"lH//zm~{wpDq!-(Nz`#X2 5WFl SE! ( ҕ֦|қҭn*tc+njY*0#M48 Jڗ;/Zool9]CC2& r {1Lv&LQgLs^90C;u }?S"YCT k0ђSz#``maﮱTzvA0}ck!q3&n%/l3lq>j E+]0&9Ga GA>v  QmC)yfÎ!~-=ZVZVVx+j3D+x71E[wv>8-cԥ8Ʊlu f#;_G<-Ӗv+: fs+ -5X}r.- 8 z ):kle>F#4R]Ŭ _\?=뎃Ybm3q+$kL/;5Cجp^ޟ9[V{)M!k|i@'\k^wfH塄!Dž~-F[ Z*-TDgKѵu[ղDG\’Hp}he%,9;hj#܏w FJ m$Xᘦ:bb??쪣r%)Z,aFאY2b|H>WPZBBlZ3b}Ќ.wMeyMތ2ŧrQ+.Y/{AQ:]˥߭ک.0n8™ ut1γc롆m ̈́#P]w[tP:w&[7\j wT@?67H/srghdrA,OLʆ{ס?*}\6KC4jym%Q&G(FXidَ8/t;ޗҭ^ bq8F V6~ SZ>t4 !"'. QxS]jd"KRIᴶ\*_Ӛ! Z( C]y U˒%̵YS4f|W+Tn$]&I{oYU6O-tjzg[$ &%UK#) ]laM8D k3>D|:9ȉ%O ,sgc`Ê`,Z U^aY)=uòv?Ece-GCrTb)nj%5\T)Z &,!˶XhԢ4 P:`^o hk7 3&92ԩvub!E, $e .Ї-.RO/p'+YNpgT'X+OVSg͏}.~G]s/EWtC>l)=9lX+1ᥤbRYTCIggp<Jabd)` ^f#Fݑ}rPD[X 4L _mtm3)ĔSvM9;@{Lpvg{{cR<+W8 2\=VZ%g6?/O&nm5ni<8yG듫t:q:m֫vg0kR@o~/{WG0Z<'6r0%?s,V#5б֨%crgvUWŽڵۍ~gEc\8MG$ODej%PB6mbn3J>O ƒ/0{N"ЃP~= @j-WnX_=i@&O/ g Ɇ$wLHL*sglb'*>vĺܜ@ꚷ#5%8y0К!u'}8װ휿GF/miWc@!0(֬ڙZ61lԣ ~]vJ$"."̦ V3a/ Œ0vgy>*8PDT`vc-,sYsP Iy(pH y!=FK{dxB^H\ x^؏aA<)pm]^cXtpIN)T/U1[1 kgHMH75L/3iT>1u:_{gPgb-BdDa-[6jH9-I8#SM¨WO^EZW&U33gT A@UY[J1RA>BZc*mEcqS!_rT-FҊc qf3QgNi4v14SK~, b/֔HXpF"2r:H2",M@1 o:sN%>I6GK($FMuhzȈ=3䭫@@zB bC@`u0$L2u}>@XrC/B%t25K%;2VZt jwŖ=(jz_By KqL [,#$(Ofr↬O$ 2͉b*qP򯁻($iG7 fz!԰nԞ<#U ]re ޲)&C|%4f[|\FP 43o9 dE!jެiŀii$Գjl⎗6a*@$"%s dXq6rEvW2 kA挦}> 9oj}bM:qDNоo$P<| u; y^dխAhBĻ"\o$9!lN6dž^2lCepf(%45{(\D^xx|0;MįJ-!^QGc-)O M0`Qw"޼܀3\Ui:Nr2txVN"$c 9+GQ_/{mRy/qS1f?&tpM$|%w"'-1),8`Ds˵sias(Fd"tӽ\04idUɔY^ >hNfAߔoL 3RLT.Ҍ52-Z?߿_6q곓 =n(m-Esk sƔ' %$d|]ozq%BBT>g*j{}% u7W>%;kR3'0FeΓFʂ :j.- Lv2E +ۜq Aw3]E?PZ$bD7,2 s c<$p&A8#c| f1]Sk/X 1:jH^0 Q$~)כٰta(&#DPU"DTS-p$]a2Cmׯ"[y wbQh'-WP(PܚPvHr͗)Ϫ^ss\WM-Xr(RmU#sdUQQ.ށGȊyos?$9#>_+^spx}UGMgAVvb@у"Y‡h J˖ͳS[)^nClV׸%ϳQ6A10}G) [mhڷ,fCa9De$ /FNgވRԣD qMK~@q{'i ixZ;0\1a{t4ܢ<֘b=yZ B< 9)ciVKM-" 7Ptaս@-*IE4E^M%n'(G z CKFEUtV|:mmᎎ [D3f9%7;I>e`4eRKN:omԉ4e-yWo<c®[8/;lmbhO~6-\l#f-}cF(MԖMy\d̳ɧqm=b?2R|I~ҡ(݃Ӈ$v~eYk _"3~8 #9q٫-^nъ;yYΎXi Kh0~d9a6O/WH`Y͡(cJY__Vmqp4z~VN'MG=E%"ȸ߹jFĞ ;Os G]&Q*} }po}0mDwj wj*Aۓ8z]9XĬJߎ.Ë' Z+hX_ laElAhl, R*$Fئ+/7?N|C>+٣(o^?{9Pѽ!+B48p3uHUٵƭZӠW\@@& ҙIuy5Z)WDe0 `G"C |!S#b"شA<]|h@NV_FĜ t.$aZ&0r̹L*>F@l xuX(=onXTyOƓ':;цaNZT@ZH Yb>#v2z}:I{;@Ϟ ӑ=fXQLE <eP I͹O1 % ņ{{IWr0潮_"&EY&)7Tcz@&l^+1!LygGo"C6Ku'!l A$=F{p&/h$S"W,dIˡ#*kl|i ИXL36 &VvCM̛Tn _, A!`Z#l]D^vJ~e`f;mc_!P]3trq$hqV&LqW8OFj-).U.%5|Q6F2f?[sܦͦcɎ >%y;O/+[@ϩ:јUwW*ce wرǫA.kt.;٬g-̂fmm]V> S]6c0 Z^EZj] ","^౛εG2߰hbbfg -KIń}(R}l\ ]33QXwUx*ptlt:x}ɳ [$wXno<2C 9ᒸ!Y2!cyQp.(Q c}Ů0@y|Q5Ki(`{#MA`(;.fe]ֶze$B@ jj{ |縉]/CViA[rǀgjR.-\U? %P]_X)PeЗ4w/Q"Q)FqۢĘɜi"W/齜K;rXQÖvI _XK톄ԟK aU;cCj16i>o<r{xa 2(V$K|55VÈA+O"I;!YեD\d:$QjKX;Q1ap PRfWe4掫HнS[TJ8IG-H#zp\3=XJ}{[+ ;802:(KBq#]Mgí|pZQ~Ovc1Y^ƙ><.5Wm5KW_GՑAnmb7wHF۸ K,1&5DӔRB*] wabձJp껤G^.0j^!n K_bOnCk nϒ*=P[Q[2zz q2vhΒæIگw_~ŵ&N( >\\IͶr;g%$ a !H=gZ2a.Q̀ Ϫ2L | Y9E2 r``0eH)1⇑rZKuh6JM[F)e /te+yݢe4\11bfmR*5buYqUxU׭"ԻEAg"Qe\0j$83w"Pؓ9'17Ehì.n{Am\::UӑWj"wTtE6."ɽN(Z{;O;?S$"JɓD]'ǤOdKhl< p' ˾(+Cy68wĨH94Rg"< gzMť#V34BK(Zzܘcc1:)wGz%%b 4<&)Kdv= j,+D<K+\}fpПu TsC<.<>a6i קQue.v2"&u* k A"lRiwedmonA"Z/L[$=:#}b{5K vW/VySqţYS.bgB}g䛋]n^kP7_ L+Z,̲n)>kLHpTye]< ohj=tʯ]ʵ.\k^"k}(Ec])FY+T m%-*-ȧ[ru,=sw.OU7HmvHa ^0 ]GvajTBXHd{dp~:{-Ϟ Ө$Ken4E# ڥ1yc0i .ϲ V/jjpٿ\4۫AgU _xI3+KvG-]+Ip䫶O!S(s<'KqYfؙ !XLސ^Aޱ 襁?@QLr;iՁ5n\L'tv84Q@UOod xRU\_Vrᖶ߼~3af8פ*[L^/46$7e.؇ <1OOgvoE F@,N&)b۳|k8;4'IG&*v'sF';DVv}h48rҳ,-gRD/C[RW4.~y*dvKmW2@3}/A.*^E`i.i1?퇯9qx&8/h#&]< Q8׊&5Gm{+%"/oNJa|㩗ZˣEW`}5KNfW57 >I|xaQ?#ipgOA:iu_:i!uGyd*3 %B\>2r;("صXE[5=NvWa>EU3*MJ哭QB-Nm9z>5e*vF<#r>Wa3Qx_#PH?\kwuy┞b<jx.Imy ضD0l;L,dn[ŤoBԯr*$I K#'Zd<h7!d -wo ݊}ZnUXQWp1/?2c35HH~LDGsi[u0H#_du2"e LW8GHUsgñ~b os? UPnw{wpO5fx˄I6 EAUyzKvy23Q6:)!1CyF,UHȗ{._kj#j'@/aei1SOI x:Dc_kF9pG=gD.LM$4ͺOza%h> xG34!:VUY ሓ8pWÏ`-p $Ӱ7JҤ z Ҷk¢fھϊi/WfQ@4*-%4be\5ׁUvh{}uBlb\KuK/{TbUW]RƖG}7! FVW_.ZQqҌm ;q C}Na-Js@8ğ(Dr^BJKSZ/_CV,Km>nP- #ۯ%elB^}n-)3:n GUw h.F+_I R' /lc$@zz Đ+NL`I8L!GL+x'@"`nj]3 r2n)>@霤L`>D[ EvYKV dvpP:-y(ғ bmC`nTOA~~H7H0n#zgf#Ӊ uHө)#q/@ \K ~ \+p͊G>-ύb >Is\`ZܨɤRp/YM8}PQH58UzhZf, V1(+a\*!=Hrd#Bizc/QzdMh4ebOzJ%:pZgr^`obg@XFϗbo D/@% ɛ" ' Qt7U=Ç֩%fGY\\VF7ĈJn)( c^M4Tjr[{zR#; %$4 0K( J1s+Xhbў7ͽW 9Qd`;MZ6 2LG~/-4#fHnkc4z/͗d;*#GD$戫G`]żT\ ?QeAz*RjIߨ 1I34ͫT 7+ T:zV5QWbn͋5_8x൸`׸[|_] te_/g+4t0 :"_ځyPv{_C-y;|a =XR1DcPcuz,F;:wU+W4N-fe_k@NZ|[LPZS^HԌt s!qv>W:Gʳ:mVT}] cu|_x[^+ mzK[yكOXh6?[Qj$ `S<-ڍ%=( 4pM6ڈؔ෌ m|ϰ7k~iB4l^:yd,͐xO,8 pAJ&C4]'*M?J6iY4`;\,H;j$mZTW!W](>#Y17&}8$j& AZg'&I:d^K &P]"QH2pM#7;Biuf:,\#] ~&+&Mbe65$Iٔ&Y#K r4YDZӑjje"s pdB!__>75`֡5U opB#>œX<6]H/θWХrZ7.jR?#C6[ QgrՂ@3./9jJ?P?M2d@gy3IOEğ㌮_޻#ylKK/wvW B) }I~zx",?O( 9ˎ tji'4X$p0Ә8$.Q@C1;`>=畵, "2aUIwkͿ4 :Nn_+W?49޺J%()@ŵlkc (/nz\P$4QTB,s"ٹ۽U='VM׍w@#2naGIXautMXUۤ egO|~݋Vh<ʬk`*E 5J`ljǖ/R TϚ|&b6eBB>9ݨN4T$ {sNpU&vR`[9ji}K{PXpIo>0^zd25cNq 2CcgՇuW#8CkcG&,;7m0Y9'R=|*iᲵ'm曫}|K3ˬ uY,)ْw6ȃW0pǦbJFޚ2Rk*GSm8t{IUNYJ]UE8LgoF :Za-"50.s;ư8\JEG%T845f􂔪DIYJ$!M\֡ϖ:VfN$+3;0FHɥMG=}_g݃oq?M‬oO{VHύ̡Gט sRGT"%G1*Э[cE*QisZޫ@kD$iJ_&+n객Fmc-./[M?(d&=34$=Eㄩn>8nXų 3$RiɲAR=`OjAVL g3C@ |H5i*Op)yEb} wHt(L2^}D7M~vnV(mJ{OG=:&4IܸkID0ۛ[=H*lm;-8=4-bI>񕧥CT|ƹS|)ߟ_m5k*:ֈX/ eXyKaoFe t\ۿKS$Kj.6+{zoh mi܆pۓ %ѭ)7MgSi(IG"d .VgyPsOHb c#$ޠh0¤V>C03Nب٧u,g/q)Ί;vU⭩E"pqփ{1Q!>+7@(4եy}/v+4GY4".̤!L z81vF"~) sU!~ֲy},vgkn?_jG\F^&dnf7&]ZTX) V|R*|X g@75@bG=`^uUbGRSjAV>f}fȑ̿c}/1[J?x P-;!3 W@Ŭ\y3BbQDI`j"mGC|  s$B2Pqj*bR0۰Hs.u4Vht@9,כH_.waY62`HѕJp*DPXUz($oD SSB5'HBbvv䛍h/.#*d;Ή# UCL _Zuhbl 09>B-6 eG}lQk6^%E!9dziPYe6md~{>D+0T9oӻE9]";8ow)`ٰD1'8s0W,՚Bjʧ,LfJިsw~{V,P$RxǬAP_=V#/sֈyY:|dM뺝n*G>Ǜy5gwIH~E|HyT[s"ݦ7$HW3#htߣ}-v 3IY kcsJ&6ѭKJA b2%/lEm|7c[k[ 00"wT#8E݋WiC11kzƒO* _ٌ3QfaoA69,⼣ D)"\|j=-Foqr71xX@kclܓSLTGkq_ݨDnfcO|N!p҉ r376s-24 _(Lr<)1P& QPy`*#C +䲂_<>r96fL+򔭌CUa/')ZIo8f4PQ $)|LT{Yl(WY Sy93w %IژM=o6La1Y\Y$Vq4+tdb UZ@sNn#":86dΧ 1zN?YQ*Qѹ]͸7 Ֆ# }S7KZKR#W֘=В򵹆s)hRzK X `Cl 4#Ig.Eq3t+WZFL܊O34e'a3&\ l6yDO&6$z2#z_IQ oָ,؈!lRvQl(wh?Wpȉ>Ch7 zP][z=53g@xrwvF(oj,\a_91:<~GnLr[~nrpU?f_{*KletW\m\] 968 l,|nu:[ /f }]++ٖhLDRrV 8J`eʚ:LRF(倴4dj#+/Rax [ #u*=w sTC=:A0-]vc: ;0ʰ%s/S ;*kܲ9ҫ27H0Ȣ&G@22X1 TTX a q4ɶd%T5Q80 qI"ez0:k@D,:{Rޥhřg=JDoɨYڇY^${3b#A:[rLWpg1\ d,GDA3t_S-ƉGy"Fn&#Ǭ%ړ › 6tR:c(hń٥aC;ό h',;I$# -YNd*U1^:~8N흭:fͰVp``w/ Noo82D _p,$Nz KJQؽ|5GPh ppD7S\ʊ0I©=O/6,UdM|z!qaf~l]DJ\ |^V_ R O9q1\ uұQE*I&8ȃ1su`K.fHL_2=d,9˴6Xȵ  1kJ%H f_:Ty{m'w֬IVÁ2Y8LIxxfEf@Yҁ,l\&<#u#ۄ%2⯷=h h8i oϦq@K&=q;\ybY՞EiS+:la"O(<.c%Q?|d4(чv7dx[TEF℄cscdq|i&‚[$@'!0V#Zxm"a2+qٺ8HzlCy(UMF2]d,gAkQ0G zb'M^~[T)#v=$%Չ+E~:Yb͐Q71 hBDI rPv[ݬ\=ιKr-p/JF(IԕBxz8;/-+>n8Sh5hV#=$o٘Ø$z+' 6QSD82nZs$vD6}> U4% 񃩛d6 #p+‰eB YKi  9˨K6X}lt֒ScZ;|½\v4g52q0X' #2e vyPGh4OrqrbB&F]> V#Y{Eo72g {8 0A.6QXZ|GlxCA|.EզPiiDW1凂|ؾnm}yF1TKERnCz-7&Jip-6Ns%jM$ }HlP)`+?w/L=(?w7Ӛ퐯n;L`?"ІHyeG5DQλgVN$BTsNr +>cXqb^C x})E b$~ E!(`jA-:Ũ ^vQO*ަ6H~OmƃByJ}YgsN.>"NoF26dҼyI@U|$S-2>6s: `*ɻ XpoRj0D:jENT2*BNA?UrZeؐsI8i 'ުM9U EEBΓ`g C_uxdO!9]}zgRj`ܠVJ*/GXë8@ =LOs|z>Hթ\lq$#UIN(toiH 7,6%[[MX}}({OXΓq&@{sќ cEmnMu _FELZ7{a9q_bGz3p/,HΧHuјn{HK~ʑ,N8iX(=|be7FB!Us$1+Gb֠;gaP=[wV0=E1RN`-q42v2?(0p1dnL#BA?/15pyǝ'(܌J J}tKKc7 O;bߝukmfmo]р9]$ wCħzY՛U|Sۇ{t-=iAS嫥+|-m"+2Ǔ ql)zDA>HiGو je.ir3 y?uUH鸞^ԑ'KǛ2E?q7ѳ[;R+qTbVW&R /UjBGtgc14Qsl:#UtϦ?ᡶɦqow|0. wuW@lh mzz׆M%%:[os alq9qV4>}Y'GG;![^ufHkG:¼^5sW,:MݡuQ jI҉{d`{ Iϻ ^[+$Z-?_>!Yx՛CŅtvIV%Scn+r(9ˆ 5\1 7oySIX3MmElypu7yXO}o@!8,m}k*O*z$|eOL@ 9Oj!.Zmx|* M1w+$b5Ĕk8m{!ro1KFc{,f5Cɧ=j؋د/JNx[=[rSIaa#jPt)\ j={ƂnTYLXkyZ0rMD=( |tRZ>dk&TߨMBhvlPHj% j4 | d*kxv,$ON;O ̳!>7BbQ`ZvooATC 4*(lVw2 PcOL+ܴG{w{~4gHoYHWVd(]^REqKxqbQ;>Ll~4$EA X̵DIK磢/Ǒ] yU7ciƆϛ:s> UBb$Axn|HlTN0L dBF@"^[0*:Տvn4w*q ?۳Z0A7f[MEZPJL}-Hxiӹ ?{Qs$~B^-px)b"dş#t#a;EVVjpS[y 6#? 10Gfpzu+n{uPnSCHD(l Dn);R[+s;t}u:jWxN='@ zTΝC(VG| *pY5$s3` ߑ'}#*Z)C b-4]\vsJ`#`-GEGy i#h{-,~u^#ؘ7*IVrNijN05֒:)DJq?/u5sȬ^\5O8N'rR$1Դv wfKHE0{ɿǶʌfB_Cώ7kU;9ϧg3P&JahKviъfI8=&y!iG_͵ZbKYǏ\7Ff+^;[nοMpBD%̭]X!\W[IDۖM<0^L5NvLrw(g) Ica4,5vtM6 *1䄌'ʕ}?5X~pt7줛2'YmwA/^J& a5UQ4@fS_{.;qY'39^YnJ ,%Xh!DQYB v``FM3>[>cLQpM_|޴7/}# d6B~rwl /6zyZ`x9Fw Per;-@|͌I\sRUG pלP\16{frk]LWB8M3m@ 3l= 6d!PDϥ\bSxM?#`jK1^Vm3 VGS:LG '|<-p/K1У y0r/ҫ௬XGH@d_J DnLVbi^N׸/mKݍO:1f.voZ|u鈯rlZ: -_w-1ђ 5I_pƉסߐQGקYø@y>y3qWŻW. b _'#/;H/=}aUI_yL '2#P<=:V雸6yԺ GyiVf}V&S3Z(AcUl$+̺^6#=rv5 `eJoLlh>?Wʊ]}*=KqƳֿA9_gc'7 NJ2_hp/ό>bJk▢H"(llX06&e)0سWp~'>[G"VG[?-,IUE&picX9ltH=lxثRGJ=[b^rI%lDA MUi Ҳwj.fñ?t6 aAa !2}%x4O? V'Vrp?z!LU[`M;9UqMiTNSpi?E&*{7[92ռn[sms)wty w>":g1>L\bFe޷y}Z:FP.GSĝ'nK,}qd[?T8?1'%*Bȟ ΦWWsUN<2}gCbSP"rֵp\[SC|e?%w&#?Pq/t:pRc oN #ׇ۹ŋ=E[R:Z G@ Gvս{\G Uj8oocD u)nߪik1 RKVnem{R|f {lSt o,Bj/+[}pl`Ef~|*An"HEH^^)PdlCDԆD|RMC?5鬍QnЭIK 0iiQf /C_?ӪԧN&ƟMЙNܢo^?{օvj=UtϦ`⢈C:fO 7p\,}ni5}0=jӣ+ѵS?;In,W0W//߮!i\Z}Ȏ w%dExH0-i3$7q~`TIJ^)׀:ӯ%tqrvzKLl0{<(xV#)Y J !qFCs.'E>/nL4SDlqX֡ !t3}qaI]p %e"0A>s<҉Of _#Nj$M`vٻM(0<>K}p^(7;03NܔsDbCL>4цfH ELa%:f99Q&<۟ewe s>":my9|㥜B\}Eu 8L VmB WU\jG$!JA+KZwʨ#TiVP ^׌`wC!dl@`T.ǂu*N`9 i((PU  \m`ymUyFkE~{5j>)>)J~nY T}2}2h_yzQ[QH;‘6QIas|<=mUtjg2Y?_ZjPQncxV^m-.T.u]M-f#:%~Tr\69USv*ՈxWeYS}b#,XXWRI-p_ 3`k$مO 'xNpmK)8B- ρOAC)cqd>0_qB?b%xN.)[覗[eO/ҩ.(Q/0YnhXw}{66_JjICB~Rp`*hw 8EiBgXeP~KYoŹ! JD!ugc!G9+ȇd g8cŀP|4bf˺EOuЀڪq>A]9ŢXxv{xԐv e>;߭6d,YZN*Ӳ{Z/o^{xQZ(KrN^v+{BHkvX3h(+gFK=Z_Fw"̧A}^x;~Fjx`?(NJֆG^κ,MIՎMr J`φ B/*8ߩ_!_)Wa0І&H9HU:& PIo΁Gb. 8|͑'SgE2b21?,\bZcPx1ܿ%r8+3rzeB@D(P@_PH-ݳmp{_^R2:ͭ,R)0`*"\ucr5$E(0ń#yukwbQe%*m 6Ӎ1)oX&E]ᑛ ί$8"dXpX1~K\ɰp> t/^ tÂ"//Rl<'CV%Ŋ J5zpN3TQT3EH$ Q,Y1͗[5ss5[5NTu8gf]LUl5U{X9+91D`Ż~qR`\NX{q΃]b$!PUa /}TXn\E.}TIU\`q$Lkƞ x2(֬jJ=fN"GiGqa/dPdı,Al&(|.b,'VifbWFUn_Ցр;Ut2CcgHc|4. TX![BkE0[$ԑ9M(v10ySٚiFxFHME^u bl gra m}t^\VduG]2 5 \bVI֛~moËcRY׋>!O|{j_Le7 j=5.gUMȞW3)? yϬYD;j~Kd\8ߵףs%!TTČ=8`h:GܬlJ]\еefnM+CiikHu[R8uչ%|y(\u\9v'eYrro[JaVbAE>u]"UtJs kf?7(DZS%5zd%QG|8l'܌9ď+E<48LѲ?"% H9 (4kיih]⃱VP\@ٌx}wk6X [kBB>M )lyb"ίl}6G&~eYӟfJ*U9 *+yӦt!7JSitljP}*i<5Le2P4.WLfScNI&.T֍gtvßy4Lop<ȦYp=㠺gÀ S`YsiV$7UT;\*]s{{)3¥ .3`AQJ?[{haDVaD#%kL P9&4~ͫFVҳPƅ=Cmz 1qX c(1JvC*~ a|+#1M E`;/bu^IEM(aEim)eQ,&AKhr;PNx>s/(C'u.,w<jU;v PlāVq4?۲ѧpR|^,FNh̤`?n郙Dzv&l47Am:rrnVφB92aK^>lie:{}kSņTA!w7xr&ٯ\$Wٸ_@R1u"hؖB0|?#pcV\zGgɰ]aeR8]䯄>=z WCƧ wPC+3!Mzv`6p(RDg.a4~&Ũ( Q; ,QVA,*$9x̄9$|zAMIG9¾Ǯ{o_ugY͢wĊy1" P]#{*OoM3UxT $gLnph&x(Q\m3%*0ɓkmq"N8e. QJn=s9XKh)΂XWN}R|k{Nu"ԌQc}jU3:mL;[^~-D+~bxILNwݿl.Sxww[/WymPV{7m4ws;[fAJ߼~<8 q6'B{'8,-h$/HꟄiW0%(:q.Ǣ$ͪIٰ_WM2{tV2-&hGX5%;0cMsUb$/Cl ~O} 50DC$. QG5ab׼|kC޹l=;O+[ńi7/X3nZx1[9T\@mإSkI[a6~[썋E2$\;X,h$y8:4|bCiA^ o? ǧ*-BFV*a*Ki%•/p⚸note/||'LV~!4D*64>FaC5⫭} P8wpyrcȲUfWTs<. M,N )9tdtzkkc|Vg/ٹ|~O ؤlSK[2@MgncJMޣx[+*MrS_nOa,c>wE1TH*lbqІEݯ+9ueàn*ٖ;y|;E#w@FA( fsxck{o!߱)C$${ףGzZ7a,HT4litmBGQyl@S#Բ:e2L!Z^oD*3"UI~::8tLΡ Q Ia+tX1Ώy``bv|Ӣ~{ٳgr 󓓒 V*`!i+ߢx^#=G" Ă 2 fuH<8>g#BGዼ,tMk\S]yˋS/G+qZ/N q~>YĕtZJ9eC?wis|=n&ޝu]X޻vpz dYG2'tϟ͒;g_t<hkyL k٤w-8Xn>Jjx < `BCƋhkM0C5xJ7uE(`WbH [FP ׫j᳽׻T :!HYJ_׾*MϣB?,< W *).IQgĘz.ZK^_rV*ƴ|7wchԌW.݁:oYxVՆ3[S8OҲ Ca:1/䉲jHÊHw b-Dk@lJa]J,ҵ]`w(M<3lVHV7A.2/Lǩ6M_٢7]H[?>ۧyVr^F8o2r41 _:ۆ~!TBo9 <|l&,-n忩gӥLLcΥ"5|M ܚ8l*gJ?= wBDOٴӣ-$"+}J##~l%A7 >)A[n(~ YQM}uS#o":JI6:أWlL]U=[n}E`ãWi-~Oئ_-3bu}&a9m:|6"ٻAJ`*MtToSr2}H5FVM[?i ^R=\Juw i<-we)H(-H*g#{ stnmoi,M]J N~qY]&֌3P4Y dzSqƐpwF%ϓ[V:X&L%¸cw\*ޘ1z@ҏA`2+)5 ޤ }-ӜFbe8{e U-Jf~vw󰚱G d?,S7lFC;M.fg92"+s Q*)'wCڝ(l6r׸Nv{866lJp-T!M^w4^rE jX%wN8ۃb3-I"h" 4K{ATE_dr (*aOkÄ [)mzߎV5eS06`دoFoH^<:_b|>[8/c,βR3*BkCoryO4b&yftq > lģ/k$^y/r&Unxx Z%޽y}zq0?sM|ҷ ~5į}GYG8a:Vơ/R4)𵙖Iy6sND ד2C RLlC4,Y%i֩nuF D! +8ZR;rtt35b_ጞ|0gQKuvU411n=Sg6tݪnw%QaF1ٺ AHR^ݍ}G1+$u f'/Ө>wwvEN~=/b"xeI -Ĩ1.fUC&O*Sz䎴^XN'.i,T~FV|dEtng/TbPqoTx a _^Kب{?ef (> O08tlϋDX+}b}vV6- 'jOsv5, i5w1x7]s( հW[6wAɥa݁ Y_tcnD,VжFo0pk 4f̙.!ߡ8hw=˫:rG~To+mn],`BYB'ĺY'6ߩE,#e^iд3Rр3#X`W\O"b@E-XSO/rLަu]H0(1?#9e:DtdReE4S*´UC%'JHqxa, 6 StBF^$ֻ$j%$?_xQj5IšXo [<NxU&a6ˏ{[#fOQmXvv2B6HVП+-# wI~0+5=ubt+4޲a:9ȋ7K('O0-MaEYO\@].igI߸O zuX;(mױ HpXFl)fS5p k Ig9 f4߼Ccr@ Ŀ{Bf^_Ʒ^`l,r`&vRsxEȤChDrzjV@dh" SMogO?YFaͨzM6M>WʊU2[V&22!G def,`y o>U5ZiN{5$Zs ,J^uEOoQкL~8v;+$rІ\$ kW=+ǖ6sSl}dl< [4>g#Z1WNN-Ss|8굔r?+inInl?ЁѰW[ X윜/?xd_f]>eX !ԺƓm^J(oMV!k|]}S!XY TU"et :ƛ 6C:_Jufrv,VO#b5մ”]m{nJ)JA#kBz/:Pi.M@mNmg$39Kl8BV\DCS=Q!WFYb$Ε-B:жJG9fXsY++UX:v?)T}%2,rIBe Sj(,;(F8⏵DVmbyШ/;u.&ҹ:bcpW9s~8+2 C8<M>9&,qhkd9~c' &u,0#z>ɝ'D vZ[c[5db%:M8uXә _hyri1N3୺=PJ|EG 5~mדWYOY6}FcLlD67ȐuN?o(>(lPKS6*B`yUqKv4ؽc,0Q“ZI2m|x\L,`& n7eȟT~DRT9aNѰ~q./O_O:Vڈ( evf 1Pfl?g=>0q;6L!$eVt|FRvE; u$)LCVf01*:CYƒTnŦ2MoHUvUbݗ|srG7쉑G&|DŽ$=ǽjb &h^R݃C%D6H|?2jW9aqbo,oE+-Xn чG( ;3jWȓ৥ZXTΪ>-SL#U*L㇭}cV(cY6ͷĿ5*szufEc& l$y lc%czv{;{{Q kJPw:FVAIS7gdH~o^?{VIv浂HTny_%ᩡoeB:nDcD T"qmT>\ݕb_&2V?>L|c- gcVdzf&Ây}D̈˛b4M65vO29|'t':vF8Ȭ2pPeq֛ڃ!>3+ @'ppL$u tĆ"zHFHQT;\ˇjqG͆G6;g Ss)Tܻ!Hf_\fGgvi3ÑrF,Y׿OTXozUL@,xGM&~d牫1 >9X=-y3lZK_AO2}RO3vb%g*Ú9̈1@̾h?{q!{S}LX$?̫ɓvev6>V*:5alFD`}|)|8 (-vsH7N[g$SB.yb÷бa{Op(ñɹr8l^1ҋ5wFsSm<[ÐiUMM;xr:7vcO都5H˾z[@y-Tb1(9\ ̰ c~B5YH+H4_ay(CIv>p-{m!nFH:;&[ȴN `9#?`;O~ E1Ok`&m}Givva8oR(97 =%cô$\W [r/kEUÍʼm!v4M~RWDe9{ Baؙ:*Q:ecLTE++I8/0!QrH^j)4?;|NKe e&K =K2@fKoæ $/u xBEIm2lh\Fh96_ckȓh VK웁qIie?!oiN\FЅmpI!ʽ8B[i{e j A g[c b&Ls~!N)l> M6Xm.6;kߍv'Q)ǂɄ8DzPrq3 }ԩ-CPJhz ̲bө u !d_t 6̂%ZdZPdXLlX&@ D%p,*rI u\*Wkdi6E 3:Q G{!@ DJ-|uwǕRy4ڈZӖD5Yɮ&U>$T)jp6qb;i(_3SѴ©g>4PhQN;y mB &ڴV㭠TyLSbc+iiAߦh G2Q$6ҡAzFo8T/rj Uobk& Ĉj4QdGT_/Z&0c8уL Ord6O Ը5:籋+]. x-0{1;=Oc`aҐjDTR32@~D(GnKZ߁ 2-8F0QqRξM#⯰/ѬK:a`!}0 " :Z1ָ2ƈɸw(=8}Z(4q(7]Z2HNkv6 nwl9]T@ ʥga3eA#m,:]dS/t'#|Sr"Uv #i38<8ԠW2e7 !adcXCs IuX{_.td𒕑.L\)TWh޳mWarX!;]6Cz?ϽMοFF.PbyFd–GFA$ВD\tZQzO)<Fzq?MpETXGRjr$s攛Q6%iNW ɓ׻ݭyaBƓYލsx[ٽX:—'s\s>hJsEZ!'bgtp }hZ0 a;+^]u>7JuvY2U_?~ rn>ݔ9ڽt`9,v]Q)er5;R8xzA@Ukk_d7rE7!WVo7WHAAmm vswA5l{w܉=ZOL^R=unIsa:|p#b$ٌ}۽G!l5\ H܈^_O}1+OM WYRu5̟j:V?|Fb?Ҟ(P#g!Vzs*0=& TߒNh) /V\RvĵH8OX)=t&j܌!%(P˵%ob2RL6DD1JʈWF#0LS0F 9+YB%=}ӫEi_if^5A E(FP0Ig4TzZæ*]|8Hk޵֙&G[7o&>45=ؒ}n鷢Yd2iF[^)Z:X{qeUn1-@fbػH?)VK)Jgbl|M<@Pʩt%=5ύhbHFt9gD \侂j?8ϠnNR5tc(t"{gI|JE{"#`1 :݉ i`6r]ddzSZ ^YK*Uz.~FY9Z#Mo ~,hl{{Ʉ*"8H]hz*=PA5{^/QevnRc 7NQ=MCM&5P+*EF:N-ՐhKMs3nYvӲfE o#'w螯u*%ޯʝ!f!<3%d}`zbr1*֫DAb7KS0~ӋӃPzŸl;sD8G!+:hO@H]^8'fAn>tM[#d_yQG{ܨ/,؉ǻnwq6:i|m?]njmMB][sҥVaC_ 'ذOmHN[A=i{jP|EqRiBjD9y4 ?41?f2{9䫞ǨXM$'5s2<.+qqw?rN ZʤSg4ƀyTjW! kLEiʗaT*p5o'U%;Ewi1C+3>Cy?TרZ;]U<5vlV~l' uP-60ЕxNa/kf0b ʽ~壿[<FjenC>Bs?R~!8cjFt`/qښscyqIKfE] y/.$M`R={|#B}}jU]K5tݏ8LǓm:͐mBp!{¦0WnO[u= {c6^ڇP:|sA"oc/)QqGZ:kpdhT;h6$$?k (SVkb4)3lO5ܢ@ЗB]>oMvoJ6&_s~goT_z3gpxAA;$S`OVnJc{o(S1lԑ]}DziY}dz8[bt^f3aVn8);<m>ɛqrc&$~IQ 0ƷFf2[tPG<-*Gp( hPGDf1EiXu:?0B9;KMb;2&qtYìB-%-eSwH SJ;,ڧgDiUҞVjR)*`ڠ>CX,I f=_8܇çcs,W:nX"uuBà#Ҍ:w)%ˌݽׇbKoThrXT#La $q >59떯fx*€>oq{' =hkRlwޫvȱqرb`6覎嗙L)!ɸŷnh9*FL,(.[(HVm8%f8 tA؈XPCG,)їBcNPtv\Oq/K{ x,g fQ6-zyE;7p+/W z:`el$7C  \w1УQZV 7` {*=(Ӟ,x5*&= :TR7 if<Ѕya݃ӄF1YJNVyLI`6xX@ %^\W !ZbUb#o*kDEZ$>A+ qpK9 ?LD&@ Bڄ?qbBs(coT GC'fT[RtrKdEݺ|>؊>}*58Vx]oh{HrVӵ/#I=L93=xXǽpgy9-@ڡ" N&Z%r2`ybx%|7HnlGdG󨩚4kiaU13y@RLB4NIHu`NjPJq`䘍tz$/6?9\>;~ӽVo36NjO',R '4}Tf)#n?CS>kA0W*M&HAU^Mjl-PMBLoTԵL :Q] S^Pߏ *uS6 `u)5ՌjHx3C>}#c(֊#ƤxG0ʖg(<3\#7lz+]TDᓅ߅e8: @E7Gc%<s0y#XZR첎Lq>&Gvn 3o~j6YJd2$6KY \2CNJ\(P9AAtIL#҃@ 7=l sv4۽_Zx$f/鄛4i]S>* M|p^8Pbf'DN,6ht?C#831dX![5c4oO:t96؜*U6KQi‘") Ɋa0&2{[U&/{Z#6Ǟ-\1A?#zFO:|\#^/7s%j,d1@v(,'FPqJ~RH6ġB333'& 4L0$oz A&.ts^ eg0?at"m(3/_óo6t# B@Ang`xZ&7'_fdKzEۅ~D^ 1 K7:T+tV9qr"nKNϞuMӥvV] ~8'jT @23 eLΫ>>B:%pѕs=g%L\b)Gj ȗ p;_CV {onXV*c/"BkH@]C(wN!/D SBe;yrd nZ,ǍQˆw"E "dt239C 0eU':zU+˭Ce_ƍWqN7LXK{/9o.?hC9`bثo0/̬jI9!bNj 0l:<.CR0c$q@ZE ubfSHBӺy^"H&/!uhXT#*uTS3' n㎊iV}bX@`&~7?Lr[xw߅un߽{}Eї{/z{{_{5fIR6NNZl_ <&O;Ƀ{XhLoX x%4d訷 ]D;O<'s4w<9ա=}YYI A (tԿ 8I~<I=Ƴ \*QB1[GEI!/I =גx-Ld߳k¸=qnx|DhgY`[]ɫw^Iv'?/v^$[/^$P}kp{s-}AБt;ϩ!BށU{ϒϭov^D`g;]xh7Kwwo#77/ɳ}hSrt(f~z=ʏ*== @d{s6?v`FۇU~q{w@s~[(O64Hq[O0Nb.m>}} m֒w!vG}B7]NtT&>[GFbqZݽ}ݸ(q_F?'|̀ϞBx2~9ex6A/a7>ҏk:PH'+c>рhLD֭n"R Ź57(N:]FGE3|PX]4b/3)ҁ#٤]Kbmir/6K M2QAp˨A ;M=x?<]b_{?n%:>q۴FF&6]3]v|t6-$}HqƼykdhڍ48HĎM{Fϳ@0wDqJ{%q9UuK P{%dN= wm <]2);.K/'r- ^Tφ MZGbgZ l8o[66q6e[I"ŀDV59ymT45lnvl?5Пgn/}#{bl)Sv2 Q>\od a6$12aq He@uիe>dJ+b761Ť ;펽]M06Ĺ_m#?r鷱K?ljMZѩzev;[? Ef nA̭ce;멩走-XT_-~Pp{^:̝Iaܰ#|j_uzk8 HzuPY<_S3Z^ԇڬ3H*1-X uAE|2)~L|`c"'\Hry鋭#0#Eœ]^vJ6 &kOM? [f;2U3fK6([6AmlU,K %y4QOg? iy3XvwP,<$(?brSU|t<v.\D)yEh-)lPNOkN,ܑp&W:&O&#h~vD|+rMMםP:=7[Cx=kλ85_:dgbK!ꇮ2Lޫk} pm RDגgY>+~V~"qM_'+W>:]LsUt@M`iF2?PךɥyD!]:cdu2EBYK{/jlK]%jά̟?جJK^QozIҼN/{ dyWeBᠿeByM$aj#7ޮiU!f3C6O/tɈIRGx~]w)̒N'.乾-:=?Ě^dQfSh_҇nxv:LpbL 3[K%Gz&s[oPj$zl8owviYgn[-I@NNGv-yd0~m';KVmMx?`Ap{YY&T 8K/_plX{Oz"גg$L`ɣ{9L;/X|ߒ&$Lpk<`{h%Clǧ&mgdzӿ,x XHƙs%&MFa)p"ݗ[uTW& ^Bqq9wX?FzK$uzOŌ|1"vIfdK6䜈,Ž% Zf|ˇIwp<6N{c|%U41Ί'9_37~6#[IV>.h9uSlW|\0˔\",'+)q;g~6Ðܳz#lW.YY_JO_zgﲿ,<}<0gI_DSο2u|TLrKUflzO׻A0cXz4ܧ̚'8S9/3pk{H0ރ.{@r?|B2FmދzS` m'w{ڞw+]'Co{ӷlq_5ŗ_#]"ANqrw{O8Ro>|!k_bg;#U 3LO~. qQ TT+ϲ+MMϥ㞩O5{8qI⢍ ʻ_m<#U7%wt*@knt_t1y.?w3պ }(sq]xo;$=G# FpUq`!qGH3<&>?dZbc4(pgt"B|I[\”jŒ}uHz>)fd堘Mzq,y:(\Ǜ޻w&p4͢?ƿnSշ<{x}ptٺx&UYڇ9̝Leys<nY?[YxfY~y&&uq>ڜSg200YNj|s1{V$5H~(&oq*ؤVV Oblw_t!aoW[Oɳ?R=4+MG5Jh~_߿}"|PvyGO}?1ϗ_|㿖:; veI'fYv-)?3r #*(˺njxߨrgmzb n2ZZҰ5JM);9 9<<>}|/(C =>ݓ Eonn*Tɰ2P1yL6hz̬t;:@#:կ%G7TF[&fu*^y@h]?U@}Mwc\mt8C(?)\9H`ևw߿{wC;O}|O.NH^,W{J^vU2̘2W'풆S<[?A!T^vt2gt_tA5ܝ$sNHFyg_o/4{qt:G|>PƳ"u>N$9PӉt"@k9O_tvH)((:ռ, N?̃> CԪmc¿,%YFDV tXtjqJޣ{y lh8:Hpay GS4#Ur:ZIot-B~l"/_P<1i>h|D5TtDAppŊi~t hI1*H=VTon4S:}vb\av.$Vb\idjugQ{߅]~Y9-Kd7ޛM󉮆jR O$sqe܁_"%<|Nk6DZ~q>xG1DZ2~t=zG]M,f":a 3(֊k{kpWvLI*1;ݻ׭^igh{+m݃9}u [$ݱFǝÃUq1ņTrVC:AIkc,Tu"BEHy;]_mG$ =P1yi+KrO,E@q4NAH͒ `3[2 ƥO#':ܘE7d"_}_/)>'gO|v5= Nv_͟Fe>_}n80 Rߺ~V@/ׇVRNeovkWiYfEǷff坡sÍz4Zj ~FlRzY_xzO? Jx7y-'f# S. aL6Kj  ] lޯJ19^WK*9@KReٴ lJ`l勀bLs`Vlp!)^Le>*l`>sNUa69utEƺп%>.SNH-~#iiFy]鵒eXp*㏴ߟ䣓bGke*tf(;9Xm9+<^[W2NFf؇ާʽrzI׿TtJCU@ .Oa{=c~ ~Vsu_^"8 g9镱M#64VA=83^+ ޝLL1y+f3ǞߠH'oMA`G/Ri4(+uۨ@O Qîs6Bm)M@R.&-?@ޔ7~ .p X5HOkǖU'Ւբ Yk) t<*؎Y@t?9-P2=- Kmtus~^՟ѧ|l$:th`H96^0%}ȨXW41)r4x.萰"*j|@r<ɖXm\aQUybrNujC_-Q qB~z/$6A)E/Wl"~VT JnYߔxeҏɟ9%ʢ] e"{~x: 55T+яSã!A~L}XR|7)"E"+̚`/@S5(7 -}9劃mM hۼu+OɉX6R[>X]Y7+A q:)`(_\f~8)<,<)BH@H !lP2/TA&DDʙӸGK#~h5_a@:bpWRm]fcRmeu_,Ҹ@)kr?cmZ  ?!l`c62N E f =+Ԉ PQ9 P_?yd ir)F! -Öa i_Ks `P! 3<Ւf'YZ]3Eg%4O} Q-_< qY f~Y9;VV;$-|pT>DY! }(ig>z(z̀{,1޾Z՚PS ~GVaW)]DٕՂw( #RTtۀBMQ+1NςB2p0}ǒe#pwʑhAw+Bfޭ$ > >04>pՕ3+=J] T ؒ&'K~9& tT .t"^[U(},NgWb ҈LMdȍTДO2r#(b+~R FٹC ] Vÿ/0+ E^gއͻ+y+BV. kUX4" lgUkQF \.i{m:LH!LA1[x-H7t x/[[a_^~,@ՏzP,Wbت.V7 ZW PVh03_H:? Y )Eޥ87tZU~WT0C0 5yt!M ^"<N^<UU"Ll^Rsˏi?/WRZY1%diXNn?*B>HUG1oSUH_ Sj˲F/lᗩfNtLl`"MF?0>4ĿMA(#$}g8> NI>=\WACZ8V>ye1" e87[J1xEM#LdPL~ri$!:Tʋcu9 ٴR][6+ 4֑:KnfQͲqPF9Δ~&;;Z/GVټNk(lh&SKR3iω- K[8 cYԊ"\b 62wN`GY~SO`\ 䶈>>zzp$jשkj+:mR v7L;K4q/RDY GDYj- 2 ?]ߔLzU.ip5cJ4 #epBxRLJ=.5$Xhp9"e%_R΀gbk1͖;Uˠ+[$\'*Tk"bX)u=EH,+Ổb_Z ,,?QH,yz , k}4Y,bI)J>~.kc͈;HT9C? DɧO)zE\#5_ԁ2Ew'VrUDiQqu\ $}A׈s2@}S_x>ZMqQd+B4ɚrT\~ߕ+ oe*gC;r=[ 7Ε;z/({Z]~Х+DV>y1[[hZ F~)j5L.XQ5緿 `n(xUKxEr:6>r H+ՂQ· jpCX?ӳTwn2Vf3 @i'831t--1Uw`ˠB!)B!]_TRT$ճQMi6f$)+K%4ۥ旒]<@S,a*k7ԍm<-ݒ27Hknn Be%٘b*$T!NT! :UHSd?Um}c%W"8 SܖG3%dۚʔ$4%iĐ m?c@ \%cu,\(U,]Ӿ/D[M4{F*=ے;ۨ,iN5у1dle8]ܿVnrZweГOI?rA4-]5K;weK=etLedQgpj +$,(hߏi߉Oź!dV~)nP+x=G~N/qD;adg}]!Rб!ђԥ(or*fW+G^խXMQUI1y#E*_lhuLQM{,Jrd 'Rֲ\RnRAO09L,[R0SdžI? ۴63Mwf,3MwL=4X۾k3]~"(+ӐzW SS+MwcyQM~noH).ws(f uџNwN߁x' ;PO_z|([ *I zӻ1(hrלO `rUQ] ؾpןwn~'XNIw#vx:Ϛc2 gx Ĺlr.A" ?L;f%;ޫA.5fծFy1S?3p;w Nvͽs'Sw̮l]1ջ{;fFgE;;&{F;R ;fG;k:x7sxshr׼NYw<]]]3δ}=={hmoWdOmdmplxl-[؎G!ڹ][{V54NԎӮgQ˴kf5/M5s3i=-*]{:;8;fF{7{ݣWyd {`SvUyOv>H 䭽Y/Nyf${<{G%{Oh ƞPh/ȌԱ#cft;UeR/ڰ7]{ ?DcSkx7iJ9Y+p :ɖ,,sШ%Y*W,ef8o?$_{.!&MBV|8?#: pУ:](ʹ"[FüVfXv'IbŜ3lUod U2U@9|nG8r6p1=e1yĝCYzAit/AgHJq;zNtsPguk^.8#3+:wL7$*o[@G\\eHN1;>Cs!dH_3l<s!'^ڡ3錡8[:c/W":=A_3q]\]31tS)΀p)Z4p=rS;[*n@/:Ñ XqBtA!~Еꪾ@ Gn}kkj:Ga݇bC0+%n.S Krm6}Ng.Piܿ\А38q b9rrnuܢ\pQ-;9g  Mpvʮb`3;M dkEV,`}_/)t$9߻z?vPhy3폕'D`@l"[ WܱҸVOM_ rt{:/b_~}n'oe)6ZQRiiD7R:"+/_5昨fBMvqnP6MIPYf.4'38tb u;$fs!] Tb:a{X Xt.%aQVuf~nWfrLTY[Ɋܚ *-` Ss'ZD[a!b Q~jꖞfIw#.1-.a\VBujk"-0,- mhMǺVXrhIw(kFK:Y-ڤ׉uhֆ0Vs,e h}nIg)93@[ƙ!T}.TqGg{pew;}a3ȸ#l3ث?֢~S EcHt@؆"QD&#Zng򯗊Ivz5J9diѮ"3aK&J=Maii{VTI Lΰ x0!r<Djt̒Wǘb"@]ntBs޵'#TotĪY 8SYsRsc\ɍڳ^Bci0^XPqaPO ןGk5kMN!;Ý&'ǝ3G 3m1:ZG3&~3 3 3yל*4 BEqus]0A)lQ: ɅZ Ù: vɽֱcǚn!;Ǒu:bk7vDQ1eEC]Ku 5~0 {7ŅZOÙZ_=uw!.4 KM|WhM[nO\:jk*D0`x0K&yDxTꢘFr.:0Ǒ$Qڜx/Ntiv_aj7oUW$9/2dO1K^H $ ՋG…=J`d!$Uq+O @$ '&Ev0%APcosO:.lL02TcAQ 6U$=e_BMz6g$ގjmjuVSz/1ѫۇAGxsiJoHެljmHŐA.+qz>.K 6xx_1օ,3q=Ŧ|,i,XCQFr(bKn*8݇6!`1egg^{j|fu;~.XhL؅?=lL ]F6*NO_|yUCuؿ  )7 !*EX R@4 ʿ?30DuBs0}L";e o0 XI Lp(I! )_BZә8$0SfE)F" PSQ`Op{)*j*锡E0R4,#)kTk>'Yؠ)Td3E~_PJMSO)Y,7dDz,fsY|U@҈e+MQ@O,U*&S,Aըed T@JW+c hT&YN! 8l6:UUjBsj+UV# I607`qfHa`k%bAz2QK|Bj oehV ynd؀V[MHh2,& 厚0f@`OgaC;~-RQ4|/@{‚.ԯ(fVPI+t!D}Gy T :$nݹ;`yQV/CtoC2"mKHd>X4rzڒ ="tw2]v20%_RBߋ2~0P42_`q`<X\ s4ce8 aGJ/#N}BiP݊ruѠqH4?coOVɊhJt`ّDSgߔ6AD- $@H}?qCA d.@2 y2Ӣ$ [BДF$T N`$j2C:"Y$g?h3" ب|yG } %V=k+UN`lPHbo{0A :A7ZcU2]d@WvägPXvY))MpukLNEpJjS 9s<ה;CD!sHIXX u>ܷFJՌ @AT͸UQ= Ka%K )Β\ `1toL@S HNZA]|qEnz@ۭtBPDp 0T90a+&QDay" _U2 X`3}IwMfH"d$@} ?ѣw wȮ:u^ 3a1Ut,+Hְݰ'yP[Xİ]WWqq>a8/ 0&ICv H^ rPhUau6c<-q4'9]P4W Md(&c 6SD>hן"cTPأ [K_VV隹T"gFu @E`&0"t!~0ֹS@!t>&M6րH(KL| ZLL4$Ff 2pK!ӂ:)|[2MȠL4C9Cu7O6?BlҀ$u7iYf zɤI7_]'3ߞMJ.1̛Y&9 p)џqH!j!MP@}wPu:?pe)dL){4gFW۠^o(EpJ`VDagkuY[ҤaҎj^A/CO^%:7͌0vZ?[-e7dw*3,OбI<͡B XqjHչE>kV&Yutݔ8M{OlJTj9.CNU! \Ƈ[Ƭt88krgjȱNNl/Nz6ẐbcD2нaMݡgo]u :^-u"Wm.,,R&3@q)OQNC*HTG*m r q˩:򓕪d]N.rƦ3P˯*N ]F4!QPZ'W2ԒѢZ]J\ͻLblұ+ >OӍrǚ@$2988]- feHn6Tؒ.1"Ks6Z&LQ7\9V@`wXr,84%@gm;7TBxRɱ<&0]5r!@}puouE}) ~/K!RW`ij*nQ0l¥X6ȗ+{~'#@*noaTwn5ಙ 'n._6V-zg֗ ar`| M:J@OܖTD4ud"K>gc갗ّ6%vP)ipNqqԞiОS՛rJKE\QwxXKhh+sڜ^/Z5R$fkJ)`jի_ e-!U=cQ49V D ;`3fiz7G@ǘ@sχ*6] \ 0eׇe H"r w=޺d˂yO؂DU[5!ܓŃ(+Ue/WWϊ{uN?AkVhbk'o3t]Sԃv싆 l=0@C XƜj3`/jgĉkuNBvLSQyeI[ k Ƶp̪rjI4(̯J4m@[(b'>LDWNy 2((BlG_yֳj }_76Q5:(EXvvo|(P3MjJ\N-T-O猺q C[ ;%NRSdq+o!oz59:|ұY\W jhhWZ/ԭYM n`{Q55u]$kn(xjiޮQ] -("ƱZNϯ cgENf;Em{[3LE-wrNY IsfPmW~ Ũ(`B(Pj7H:L>34lA"05+ŽJh{̌y4EXqlt=w2I3,Sh"*`]HfBrP$fs-VM (|>?{i5l2YRuz@}`kzhzp%򎅍D|en,Y&Ћ(D8t*t\V-07c sb" a}tz L9iFF~5{ 'Ћ$ _jX Pbʊۅ~#t }7f*)/qP͝EC/ƴ!Vu~ǯOiy&:.dqWF#FQZ-lwcX@hvZԓGS*9šJ$--[N4dY2q O]umF K"w^p Wm[K!k{ŠM`BTYmnt)%]#] 7[Wf*v!@l'=țzd0ٱX?qc<!hs>g :Å2%kqiٜAmRCͳu(ΔLWi`8ӱ]mLS\$kc8!w B>_X(h~;|/[uo#I(E%j2"zcQvN"'^`+dK@֯dԪg ;X׼ou3SkgaS2*P6UQmD(x8J8Ҕ J4q0R5: U1ʰecCQi194ϕ-xKGp/5MM(ez+ &M;Cw*n(. Z.DGrG ]hOqi #u#޷Q6MC 0*(m$|1Ȓcؗf=,/sK5`o 3,'A@~#yg^YӤ0>$ @"dA&iH]z t$qr" i°3P ZIZxMq$PQ&D G섢FF7Yw0q>$~Z֏1T0Z uZ RVdz3廽Ԕ IMTʁ~E/х  "S€:%~f8%)J3*@6oZ=C`6QBADԯQ5 J%̝Qd n<_ Щ\{ Ž֯Mv m@Ods-.Tai~e0%\Yi>0Oc+ţG]?RpCV!0?4*}1""ʞ1a)~:H 0/uͭ{#Ԅ틀Z³KƗޠCu(AnG!JQfkga uSi)nҭz@4$@)@C/*+s4/H`$!"_%\ 3UwT^ A/ޔ2Q:49fAyEagSZӡ2[J!8݈8] -UeS~`;_U^smv?,3>-ގN^;k ?/PI PDFP dMPs8z2Mސn=F1^E?7P=0t';xv bEK`e˱Xz YK]|lbMb#ﰁhA##XcE^2@ߧ|~,_2~5Sl_<5~C5@$귳Zv´iC2I)hxQ )B3Rm֒uTW:K]Մr!%i;`KRT̳_ 873Zh`t&+V@j ;%]yam{3m48?Tno}Ȉe{wdkno }8J;f |~NRϾ#T{ÙΫ{Q8W7iCZ[M|j$݃:$uB~7Z)0@d=mBt~϶vVb@0d0r4$cgJp $ FJ'RH/j-W3YМSkՋNsd.e/+Й{q; /sdV_)CO:)~j9鯖A[Fzqڭa`YWJA_Ic υxDOcido08 AF)qg+} Ba/zzs>iSnz!Z֕0 S: U9xpR)0]~X9'8Krl,hif1  sxk_$_\~WX>;g,ɪ ΐJ5b2R; x&Rs hWīT4&Tsovn ,A7/d8JuAQ*XjȠ2bphU}xl.SS!qMBo~4w9> 6=d; 1Kfǰ=}iLB*[YslI??E;Fzy}s["4a662Sr̛V޹oPgߞxx8*F6[!ؠ`g ݵ!kSB7« jOѶ &Ql&_ْq4#3@ ߳uǠ]ᶕey;V#+3?E)]<8+F A- a0 ss˚dWvM֖i}aMs=2:V!6PYџj}F{a3F,6izI} n{V"OУ-z<X鑏+&>ahE7փAֿk˩#J٣ ".$/9jGFLb2N+qPJ=38I aBB(Q0YaOLH7xG~aง}a2E%]  o0翌a@ 3y:ä g3놃w1t{GH>+ZuFV@kqy¸LsawS6-tӻcWB!3>'Ͽv!ѹN[})qP-wxo\W 4Pѿ{ŝzoK889BV%,W `[dBԿL:2QתgbUx-nOS$'ٲu @Q8&_@A2 ovadǟyijPt/8Ə7Q,Älcfl)0Ohl28^6 ٿp߹ hm/9)* <*Py,avi7:CCSD4#HBwL ˙1KtGmXYuѩ7DNA59؉Q N\.eRW  Pnj|[7 ~ΘcU`7Mx5fWm7KC*&(Jz~u;Czmh)1`I`fx%ی &#@fqa7"bzVLCnf1 ~oA.ZGMcDl1;12FzUn_qr68q)aKp7)lr).#F@1z PFʐKОCA4=hqRuП'26< a>LƒXx(Z=`?L$at_XIfxhf@4~]-'${qMㄠ3lPL3 nѫ1^e9 G#O">s:9wPКw{6&vy.|ԥ.kϽhz2yx׉Ozޟudg|״37̣7+>ڊ@XG7BaĹ}y=z4yˢ?k.G}+ܯh]9 a{0 {Ǣhk{M)zחµb(pRt6f&57/\/2 }ܶgG{GYxrdYgZ.xFs #:PZ%rRddd kMnu+>bh|Z ϠǮmp0(&"4/ cvYuCObʈo*NH+p섵 8KP%3p= L>cĥ:=}+-޸*$tOQ;g|ַ?fO[  S>? KSp?<ݞX3=R!*B%drhVb3 '8uP,FS_U~KL%=lSw.{R'K\;|,jS,۳Ps\"l0EaR7))qg`a&L 'gʽo0JJAU(wBSLϦ? 1S` i?C8Ks؎$11zn͗ó8v 1-Ac%U!&fRыBPe{Sb5_F-4cD3HZ;²P\nLEb#Xx_SyJdz *n&b7}l^p=Sy "KC{N_>T= R#O^aUFT9ܒgId^R|C2Vi%J=6և,$ߘՕTg~$^g[ܘ tK7_x@~g2ܩ5YO>`uâ-'&/rzJR9Sbv*yTIZ,=s4R|i6C=򡕠qa,a{_%i!奇7>h< =s ϖp7ɢy//]3םf45{VkNѺ N\?R/+Kt힞L+,qȴطNz^>U_Kkf͇{|)_ קX}ԋaf5JTNhjNm1T͌D&HbK_Ri<ٚgEv\gI}?Åzً<90Kb q)HLSGyPF^3AXqY`hЎ.\32^9)-/jraM=W\MgE|ܙU4_Hc|z'96boAx'q2i?~ٛ\b})HTdr$>>)0dKS!H8÷Qr(݉Pd1ƌ$Y\(=QI5/ur&4bo?m_v!5m6t>9-mǿnN3>`sMC9ˏG(8xfyR}F2!0p 3@4~϶`o3cS>p7 O?QS4c@?K% pP]A??J JQd2dD$ 3\ح^7(v k6 Sr?}aG0g|~dfo8f7?tӶߡ?[a?0O_4>[0Y)\KL&2 )VBѿ*N-ѿ ojBߤ\}yV+`K\ד0 kpb\' vF#V\#zdV6l6S>Ӝ Q.6Y5&c>X+(S?=7x?]O[~H|3{ad8OĀ C!JWH/'V*&43X1t|>YtF" V[{Ke>|eOϯӽZKtkcaVj\-*O|+Rzgh{Y|NY?ޒq_VT3NއW\O>Kn1j"} `+ԕҠAܠtѣ_07//!=MA?$vtj6Ug?v?ߧ|~R X7#ky֑[! hߟ]?~ >{{~wZr'2-?r?]ӣ{47|z;8 Zc-.a8vj8zؼC.9CN|jL 32y!]@~At }ssvt;Kd_͉oc(XS>wT2S`:,PHk$ A~WbG<0m6$6V[g@7MuNyRwN{]9.+թ(U2䧀VD],MP qkX7ytQدp@r'`0b3T-!D<B[ / tq TjP|^~Sy<x8C$YZ~@11?B\4zr& ȳF:䟳qJ|g|86U̗ru:ߪP?Cn=gT6S/EC(/kjJҀjԤ1 SvQ'b+ehڔ>Ta.%,S2Q.|:X/kk=j$*Jo+uT(z)ڏ? #.(G8n5e-1yK|InRo<1E8?K?/"ƳxB <[TMZ|hEѷL#lP%}nZ?B*$E+(_ x, }bN8Ǹ2ϫk(oB*I$q Z7_+'?}:|KIx 0ޘ%o=-Ykjq>̴N/%_W4"?\{sbCQY-Ok㏓:I0󧦣V2:0Ctv—E9M7SC:KZf̚%32ciU,3^~{ť;a01Nb GcLiWkl5;S>/>ӀԽ*悃x~x M|YeR:c>4'Fxbtݠ>q c'c8ȵX?X^ٴ#!&( Eȷ")?ޛ2cz0ŮR(}oZDd(Q~0(c̺Xt*j17(Y`ZrfVFsА'u rJH|YkT'-'5:눞χT50t{w cɏen9|5«"Y=RTeHʾPr$.xGzp8vl8ۯq "iv!b$srQq8f? -y_ry/Nvx =u_{`2l$j<2j{QVFo34$riSxR9f܌^Șlux}8K2Y>xS ?*JΎ@6fTB僐ҳp,y!׌_J/ZO&s[{O#ҍt3ݿ~,YQ'8,qylG|FNtt'ˠq0`2۩BmPƍS'_^_MEr* zLDx32-2TmtBS˟q1 KE`_EdX|Z}cu><0fLꯃxɆl6/NߢzʹR1]c_|u{^[l7at j}r|)+ᛯ=b蘭|FVt;J(…Q/(/ѩesMK/ϕV^)G?;q)L+s7IAZ_8}Wy |i2xыޠz'BU#L靫O"5_sAǘЛ&,]Jrhyi)"j[ImVRqU~Sxǘד?2w*79fF.Z\ 1|~+FN2Ęϓkf)QZ1cN5y_YXT/N;ӊL¢fwa|J?{dT.^,:ⲓJT<"_$V-^zU{}iV0]O"/Zǖ:~ voHx\'~(I__$_!ɤc{ 6zNƳ91>N˸rt%KTt?/?9YV}Ra4l{+$߹Xp6`C$r}T-Nb0ǕGvc"F<>Hh^Rϰ J )RHh=W'}iՙ?95 VYELD _?"-*fx<* :VKcs'qwY4.kM@?<> W4~Hۭ7ާN<` %7 I'/+f04c1[:"041VaiG_A6>ߊ1+>M_}4.<r97qP)B{4ql!;/\;H[.{B+0GZGItH6Z^>%?*C13k2}xaLG"z#`o 3n=UX0I(1eK>@^b=|=sQ=xh1Z&q/v*)P5s$w^?zS:q_tl)}Vo4'.|N&LzC˦RpnR 1Tv|-5SrfTuel]BQ ^MO)w)#+G & .@U6 &aɵi>3tb!WjxZ!DT/R2)fVbTKW8˒E^Ҿ lsԓ7B_grXBz:,aTRJL2,6 KJSu#eQN5 KAܚSZYw3j"ȍ&IS>SZ/R_N9T%s"Z}~DrT7*ɗ-G;h,rmT-- t&㛊tIN:޿XZ׊fSf"ךSjomDNs5Z渄i9a(CRTv9n֢5:Ś~jC-ز`Uk$7[)1KRsemd\r0@ ,qT%;UFj ~b:6jX6Lc xq6$odeCc˗Įyx(L h 0RdzDT&jY19:S\ƓBLzCvG 9q_nv1t\ qɬ&R9FA([;֗q]grd9t)j(eVߠn%^26 xViGFĔbMflz8`VE`8Yd<ʼ@k2l$XI4ųT4|*\W &Wk"QjtH&KNc;}Wh<ڴTD~m6Qij9gX+R*(lXn(2w,I77Dq:\Jw4՗nVei7{-r,r7@%DPc~WO5#r/pBҿZp>n- ٱÁCkts뙾hKTYhjx5]Ff~Y~DȔ^9 _{&滌!9c:1%B1Vd٩Z,add5fKf5 *d#%BSy,ڀEJ(D , $rA EuwnKt8SZ[ yZ6=5gWEwVϥ|l[Y˩2ZBQ/ePŬFb'@h'YkKq5qӶNYkBj%H\rEUVmJTg($_Kt0(J oT \H%"CVM  3-UӒ{a99ӽBfXFuRV%R.[v]r-;+rZލִi:#~q(G|t:f ۳Y6)9%^eLX&9Bf7%BK> HK>_s:PFM4`xW f:P)J PC-Z+w22ڋ``X')mX#>gQLlj^ x74C;緘581F'Vz)Yc+g^vU>ƶB_Ϊ=sߜvI%TLL[m~lbÏJ J})-w&q'$ݬ2<`LM:zXG;Ke~_7;jEr*;jCݘ'ɫׅ-khF8@3]!r\|dk2R!YV<[|ȕE4'lL$WM,Eq]DsXQo`IިhNq̴3-omjU)cjm/,.6kCSMj,Ć\ڰ(7rv^tOd.5YJ͡RjR):x%'$?uE0GRN,E $)a<\ӒčUWedk:K:;FِDV u*Xơ:o7*,vDKG:XVۭQ:Uun)(@ mRz>,sDӭm)* u}u4|FxзU'?Iɷ;O6zOo5L}50u:Ο`:{Uȧ3P&rQ1X*J= rv~(%=)wt(9=)R߿I}Cjb%]qc)'oX1a 俬"12wuHQofwG_ fsmmb 3I} 5Te~}_J0u&nxp1B.N|~M; ω:>s L2;eマ߬B&w:;cBe*<_BqsF쪬_"MҐ?njF~ 7N'Y9 nV| e ޞI@6cx: bѣk쿱X7`y7*RGecg@PY!}G$c"xԳX Yp4T(7F) Z*L;Ówo)4gOFLQ/ 0p(;ˀg0{+jfޙ67y D0xvpST30 &q+ Dk0gߏ>pEdbG1up j?ۍ识CE_ܷ6S$8 d}0=,M0@ƞyz<_L +в XC@G+|U5zmlFsFEJ?#>#qW }`[ }É-l pn_l|LSGOÓMxhQ)|;#`o$5@ۨ{ݘ+s@7{}dSD '[[iGAW O|6{zl;Fr=6&rpRGQȼ[z䀐 1QlƭsD9gt,g.dXEBE!jD,~g Mߑ?\Q9?NL`h#yVGx" (l+]E6 0$x='ub|}8~teG[ہ0lby70Vȿ7;Τii!GA^vn|Fl[]`guI|<8w) ϊXķ2acn TsJPA)rJœTG6d]_ rFݯ"OrgMQ0Deo %M; o>H#{cWwdUoٗL1dŸmc+,ڋsE [Cڗ (OQbç ~VpX 2@ g?W>}{0$@S8?9KrTh( dqRȷNbwґIiZa 3n?s˾88X WءvѰ6Yؙ~_d9ȡnrPulf+aǸ /JN] 9haI+`2-72d*|L;"^ d8gh+}ps1Bcl(ȄM퀉hͲB :؃]?!l{;)1KniHu8DszRHw:PSZ (+B b} ڑtC:#{0d~~EU=/)Țp7Um1[ϑO۰Ocǯ!Y_Ǧ>b\,nR_,T2],,%9 G 48}Bt837\)p7_,0`u㋕X8)6Br%\zpb6 6A8/n2%Y9@.ک~Rى}LG %3'"xzNܠpN:_GzdCܡd+u~N'rwG&Y7INt gvhD~ aHSYyYX^g6;PH0wjϩxڱsk˻σm}UߣnBwuJ3MȁN**8w W!T(ΎjMGD|ל}<ɹ_}3kMƜ WRި\!vMW;8]ԏ>#Ĺ5 /C9mjnPDO.F@)a)HjW1dK'/a@|fNr4-"Zӑ4S .&NXL |`.V[>Vnl&3y }>8+Go]O|uaQxKwG0r4 4@f*_? e"Cth AF`27epnĽɻ#S_o_9vߏmu:w`q{PW-B': Dq=_ {əzw6':{T9 ؼN7;(fܟ`'d1Ǐ?x$7tG_ԵD( scBxQ ¿Q(R (30(&f}mw\9sǮ7 z5GѰGl;g{-vD\IMN^ oPxFhZɆZ̤L9rEu_P)y*bɰZ\r2VNpI# r~+1DŽBQ+.{p}=~AR.YoJ n6l\GhkC3 F௰D/&1!8E~Etm ig6u\<}5z%SWB_/^xcvbY`0C.=T^4t\#SMm<9WهvWOXWC."\R{04%6wX#VW=^)Iw'zhdAa8(P<Rz r= zmӄ ہ0ሊqV_ Ox^r[=G_ Kɷk<|[]G c]{?yG8/#Y};'^Z' [޼`uWZL,>AK&>Cx%,!P/X o"?]8T2¢ZM}][17_&;/lB# I73}Y`kcy0``5vWژwn6\0=Bs|ILaRf>3/_9 ?~A߽B,d6H!$L`+&>F?S"VvB 5;ڃUb8 }%˜Src4/ hIz7z9DiG6LN߷̤w \(HfqEz;q#(| א,6,8q߸t4XFZ[ӻA&¾E*lY> T>DYP8?lΆ9ľxl]U o|rxp-wh/H pCre=F26რOEn-9@cLDo[.Tչ]$܎ ~ 5V>,6_ȇ_>|&P컮ժ/X#p {$ܛ9|q@cws+n#NB7F`sE:\-0(F\♸~bSvQKKjVUIpf ƟC6WY OR?(<3Pz=zd3bv^纉 noAU߽ѳq>׵7x | í7ELF tvvVnk" {x> }AߠSџ q8z O:ԙ20s ;{\ L>zy ېBrkH,7#b+BLPjUVN{Ǚ*Jd-%JݞDop-QyFߥ<%6É޳By"SZzj=l/Ȧ+c+辰~;`.t \D6b{+HoyO&z&1{GO~bü7͡?̿9 !(vjwV)fޟu ݾ-oz-KaҊbd|P~|Ф#wQ_kp=? ;b~_.GŸk0v9I#8n'6+ >~A>WSq{s^yfUe+6'W'DY\9U47W@ )BJhTk&8ɎWWuf"UbY8hX(`EoCJ^_uUQ805ˢ5EFNY¹e@5:,϶1e%˷&awe2'qx*σ}0ˉ(.+sB``۟&i6ZDiORq8jK|JAA݋ŻM[\F9әv(^4f-RaArhõ/ԇdf1ك0!ErVTa5 056ʱ6aU2W"WxkO4.kL׿,x*iYqiËp\A\S<7rKR"IAY!+⣤anR> rܳjA1e kESfM/|J$t/ =q1{pgr6.0槧 EnbZV>Jx*z(8!Ž7Ӻ~ [.LI{c7:'Ǜ:wuKM c/U#4wsB(#'p2_PC4q QgNƇƒ-d6=nwXﭸxqSj8a];x`]'!9ǭu!ndwOTedR`t:'O<~xs:Z]J؆=W $:$> M|@W TgLHwzOK,!Ây7pކ:[m"Aj^ >8sh#if$m/x/X0j_:wxx)~m_coWsNrǽXP圫CojĐ>zq(eSuqN}阎Խ{l0'9j[0gFMQ#+H]d_l߄FIz#GzNb*ݳ-`;_>ۃ]ŷ-2A+Nc6.bT" )Vb>=q82嫅jTw.L& `D|kH}Ƿ(r <;|8;Hm=L2ZK\S UUI[5z^^>UXVZ ÄXxvKoD*p7xW_Eb>'C,7Z(Gkr y M'FKUh.)X&+,,pLcڎeDO%n u܅벙;72k2%TdaKJX>+2Svlֹi}_&syô5hcA -`?mNg<n4U(@6)'9DɮGC)f,΢5Qƨ6`5՚"T#R 1TƑ}<8;/fI1V2m[yp8B555*\N;^9CE9YgD-F[;@O V{j=d6vӡln-bƭn0 :J1}ͶR{'U1as*HNõIV TG6pӁ5{,1Gó)o%\^/{L#%=zWh/We<%:OrT 6)-DÑr1o>.|8/Fi{ZizVY_&#n^PPZ@Gͼ˲}`Ul0e}1J_ YWwe%Z(QʮX}WUs\B԰]t5KM` .ԊotD|/}${g~T^˟ Xɍ1{'h/GpCS7 :YOhLk{3׼ o8/ ܇[g9W0 M >̇wV4%6JBva&UmrL+6o<.lCWrڛl9\k[ikgj_s~5ߚ2PGA[Qiƚ,B$l|s 5Nl0>^ןcqRHK`y_K;~ݾR!W* cwZY\<Ҕ4ԩ|aYokT^2Mm_Ump3)Z)ϲ-wa1;s!+4ezXJD%8 ĪIKrAEtZ^ڠ"[yDBD8N;soA䠥lUƽ*ZQ"UQ Ye `6(=@?Uux&E/9%tj 9WU8"y5"^Q&>a>b;,P>c\5+]c\ՙaU:wato9pyO  ->ob0f۝̽GN=3Y%+"\N}(++f#+n%c o0P觟! xߞ@B3 }ThCsЌ^@'cwF80OIT8e75|e<Zq 7ĊWLt=2O$Q@*>ӵPa \-gRQz¥̝ZO<ǖJ,~ -'ZRZ0Vp 7uɮk+ [L-$Z´N q'GB;bRlcQ-`1sb׍*Hr}sW 9) E@xP!Y fs΅C0[30Շ,|&XĉWT-#鑵wBv#ٓUmJuٝQ}nܑ 옳Cn&#IH)E "HbqE1R<rqhJ5#w|{O6\Ǜs?LXlͭͭ/Y,],3J1 du$n"+[mond>vl(6<k.OW/Xn) p<:$y[Jz_+zh3Ғ8g{o9')ߎu~4- +sbP6,7">Z |fmkk.0^jq!b@ p ^5(0fnZ ISEE,C玖 3NgQ]u}T 5ď.OXݗTJuRjb|R&THq>)5sg[$9}$UE/1ore<]"|@M)z. {iAodgoAvf`jV`_1'BR.7VM^/,>A oؑ'^]h,3*_k}Mc / _/{\\*OXFׄ - ߹ V$UfZ@6Ա!2CnhCr'كab/Lf,&|;`Z%/g'i|2N=#w66WWIX^I/LݛIqqM`J2:j:efʡyXayhԒq}TJ\(/ !5aQ .$qekȕi7VNr,%8!nnu%=6pIpL6/ȮC࿻6ט7}TߌO`䨧Kć"A~~ 1 O ·dt=OG|qe:5_SkY4rivQ|JHc_Ishp̈́Çxpjtsnl/" 7[D[.^>x>eǽElGɦz'YFz1NqrX?E9Ds5sHb'I^_mu dk:g:Gzڭ2:_"kc[ =}A΢r T?J;͹{3D`ӿ䖇WͼP4˧OTZ ̀.j(p1 i*FIaW==horT n'@~3|k}Upp>@g2"5eOֱ%5gF̃cB潻P\vťLh9G2* w.Z{0p%G᧵58D.jʂ;wIac,=Q\ϲBYl'e-N=4I92x|6"9rb4LuC¤}7# @x'1.F8d7Ʒṗ!P9'vqh/z3<2`ӕKGA*W/eM?p2H(Ɗ;8 Gss Z}km<5|՘73d+;=,h/V\r1Pqhwsk)O&goo ۭ_,Pí;5n\O)~=$DڍHD? Y. wKx-d/'1x"t84‡l\:f8>6 7ܢxO}zk"ˠ.ĝqK]~&"gi)`]4 &d^SJ&"&(_D5d7`^gP <L/1`QGG|:.c9$ gsIZ“ZBC3ɛdHH^[U`ְ?TrFNitk3C[,[ȂtrWms%URkmŝ!%*l~VNT\jƨv(28mlޜ*+D Y\8&=ES2E4KԃebՈhn̘&0–Ibp^J s5$~;ULQbʒ>sk|hNf?!jVt,REQk7DOɒ&nl0+r~&hȷcw8l/s3w2b&)l-3݃|Q̅u6dn- ߑ[^%W2S]1䴌67ߣ?z=}ʲ) } hE<"bhL{A IȪPFdxKD[)޼Vh"39バ_i%hmw @֣BœxUhRn>XXqC_HIr}S.9tYUӚ6"Bε #񵎮̗/T'D!H@wȦȟH 5 `_4HmɃ L>*3}3 {im4ɝ+|eyY8ժE;vc{hofNRxDPw6UeR y9^`)ֲSOһ=D3:QL,7H,_1-gt-u8 []∩fIL3cȽ 7R ԚuPo:2M4\.mE?}( >hcZlc0M Β  T&Mxe`߁VN'|2 zmHdMSG  1C"'lż/ZY(-h{mxJ 6%plS%aJo/ΤN2,n,c,hjoHR>S瓤5YH~2KĹ;ܮ*3PI S3}a{hYKkJ]* I,g O (Z}?_v~/~&f&00R]J_9HR'Yp{2MN Q;;l):Pِ.u5x_ ǝje<]jo1 7"9Ew >gE:@Hrmz3a*PRob%g'6 -F2xEzy;+nƦfg']ck)tyz{*GW N{St倇swlcÕn +^o7*6mq}THbq1KCUX<˺컺_c.Aҹ58ĵͧ@tRRVi%rNֳd2+R/sG c}P!K1s2?**LXnu(P`)r4P9Þs2'Շ=s^]hϲ. ?Dөs$qy' g3U {F*!v^bOߤƧ6yX_XJ8bqoxN~vq dkZN!}:`֪v#4<qRIaR5RwOEV\K'Ce~z,QP@3ހ[* r~jLڑC&_3Yjȩ-ꒃML63%93Sx>7/2Z,{%AԸFPiĵ|uOo7`yvSj_[AD xL6tH|ȡ?ZB/%9>hdg)6"+lFSDf9DNZNy?B Ąn2m7D˯Ng{ &#w ;c;| jA(mAE/`0>[Hש5'(e*p4hH)cyV2v߳RXiҋWo~{ג\i:T5ء87Ph5.h]eKo׎= {n%[Jkmz30P|HWpGKF#XSR6+AIp,PrK5d۬G_rǨYQd/ׇ>mߌ=ɀj[<;^;  2¼ټ @&TDUr |r nB'`2-h '_['oZ?eܽ"wzw6$ B@F?&=s@Lt}8e(蟿+%^T7EE߄ZFë~Dxzx~~/?5x_t BhIk&ZHC_Gc vN>{\ܶn6N¡mȕ>)a)nSCCzzLBk8fž?xqҒBw7]y*^z 4G蓖i.Ȃ bnTnӦ61-5lknsUB*SȧJaAfn*eZiDS}?qR]C+Nw @ߡCLjݣ #=7X -ܢMV8-F♆ 3.C>zyL zfMVaw8LdPkL`LAdo爬dH8r~d2Jura}:Dm_܈K E(S9@'s@ @#r"Uv}䇔ez*W4~ dG 8ANVCO'مZ|%찒QQpH)+2]&)Y%)5ud@>a| Srv.f^F暪<$n"$a s>&"zI[$QF䕇4 dǖI4?$%DR^G$s(ov9'R*xM!$*:TBeZ6Ukm;B  U`$ʷL H~Ezt! NgXlӵ5o)2j;AZ;x9J'yb6,!bpCB.z/Ovl?*?ldžƔ# :9xs?Yt4G[ j}(qtg9~ zVqo!~ڡЌ@o?fK~9)='J ݏ{Zsݏ. QJǻٔmE^)>Jn{xhuz>z^AHktEA_/P{y0@}c ^\NEy@yeR:O}_/snPO48`Za"h`ϓN֨wԷ3) Џ;qxBv-b&p|}?oj |ϲ ۯ?ubghe O:{DG ̑'ozoxN^Wdƨ%פ\t@^㿮v! @ By=T6H>;wM!ˬ}:.cbeЎ9y-3iضԮ#-,@v` \,}pSBaVa/%5494T7G!%\8< o8SQ$P1< ?:|ϸ3F\s*;wi:q YmU$}&1iok,ͳ7_ zKSOzq˿7xlFn.L%xzEEݬo/x ylN&[HPe5XUbl{XEՇWfz: j'+L_Y4J4AcՃ9v+C%,;aCo]h=bh:2~3[kٮB|CTNfqmNQfXc0aQMnϛt󖻉r 7#ʠ# ~e:҇* E%Dnżj#wow$V? Yen<8=/a)RCwY`*= ]"nKV ̤{@ŗT3X'yL  ,{ `/b)Mrmad lV^0GW}D nhn]TKsŲTlU jՂWg:@9a:R'D]? bH!)4[)eRȪ>7 Y5ڜY^bVbA|4MzێV& V6?2M<3'l_b>ܾga:kRkO1?6AW|"w+rPǏ)8Zk4E$}1Ӧ糢p`HX)LD2=ˉIK,?=pB?w'2R?Z"%M"XHCB8_BHixhAHtAF;B:貢=>{g뀢u@*E4H q%u@:hPv,&D`u0ѯ+h:H3AhuDFi84E|P Ն'BiءBʜ7rU"↦ÆJдL4*Wwɀ/iu,v79Xִ|дHiBjㄦaBӹEա?G}ؾ':zo̓;-+w'WZEVm|ntP mmbx搴 M!~Q݁6~ 2piz /Y4~["/y5Ղā[9`E$4Eq )(75G NU":``8h1Nx99v'1s> p}0}:++j[j+Y6BPbee-jǨ}j}8\aTYWYCAJk#YIFn)-හ׌\VR~8f+G&R[[ohזE6:VL JBTI= ;kXRP[ЗԼ*Ych^%TV9YՈ]Q 7[zE)cr~> XKXElgXSUFo.ՙ%!1Ƅ ڮ4|Tw*vh1;ѽ{&ji׍zEmvM|UҟrQ *rwaFf1 rMk;(Im"/g$h LUO! QgH.cT_kOY([l4:F9? =遂wa_4ԣx'VKM?`[_"D|Xz'_ Fg<.rq۶d5%\Q ~)֍˃_ސvxJA?|`b>0ZZmr<0$>l2bn s7e0ֵ j0X@tA ma>yJo9r1Lr#N厳h d7q넰􆙮R/|rUN!s,!9Rlς0 >oI$>œS<~]'0S䂺"^l%L8^ |6>+]HTY$uϥ6UsуO@r@ޜ"lr&\o"51Td.]O.oo /mV}'Z_w7_R[/?IwQewC^>K5NM<;ܙ9KWӳcSOD-o, nwP?j[[[RўZk.mqqɌ)DV[QՎx3o Q7nv3ozVϿ-恇ey0fܤ"|{1P|5x:6539FO.5P sGP wzϚ=ք­pi.< mdܯWGͨoTXk.RLteQx~r:'4Kۃ"谭:ˀpHEFiXNF0^f[ZC^ 8[7Ŷ`+2AD9%8Jd1F=.4q8%L oW}-%Hx,mm+;\5( ⚟{Cϖ1%>b$@cT} hN+"_MY?}& $I񙈟fjDJs:ٚzY糋uΏ~o _s,4W $ʢQiT^e}s9ͿSUf ';"Qq|ã>M?N}\@`bHM^ad'sXJ뛣V;]-17K8{4.D+7YҰJͅ`xlQvv}lWhN;#JN'=&MG:.5VjjMOQ2N/lb( ;)Gl>B$$0 xUA$լ!5Ny0(W#0㮹3q`!"2])Bq.3od-8:Ur9D 5K;A͊EWh b_e61üiWtqiiJ #@\' ~+^f'9A鴔BA~Np HO3T8KL6"=p}i]@@p8LMN7QJ2l.K^N0t.HR_giJ*:7?EP%&Dr9}&J uk 'p #*wXyIzqA8W yO$5{K8SC+sϱLЊ#)`Q[[Zj {pV^G76!ܘuvdW(,f곙ɬY F:F5$+KjP\3 `14Э(&҆Bˬ4E̯BJjLff4&4Xr4*јYh;7i1)d{> }kwp~c7T}A6(M S%)}`MzjSވkkA R vj02dMCn~D=U2OgOr}Nd䞝H5q=Z]-\D(cm_BתnT][+HnKӾ?+V. Υ*746˄O3qPh "oWs5-1n3]q!'If9}!*pLʏ_ 蓊_¬fr_@"v1|KaJ.L!fS4ak-(7Z.0|pٯ'kĩ!N'j:Gdѷէ('' .E 2q';6?Z{.WSз[[6|A!n7vl#GFMv]̱$pӋhMPDvH85>+ !HPX ? o!+ŋ%U*PuLnzeoKK  {'CnAum]r۽g8tyEQvw6ގcLb>&ώ'3̽__mR1>Hh3Fcr 7'-% ؕj M/Uk{-Li0iGXx<4jUlj_Zia.m3FsMXW-LoiC3zG[[Zz|V(o~)ռ6k^f Y?92/dkJ%siw1u t7yt6.h==}Fti4b\ʹq1iG󭧳WF*G(nY ѹlng+>? M*!|)euHF!о25S)P_P ƴ_ $i:ԿȰH^hlkaغpAmQ‚EQ'YIYUL3I3\RJc8_5an baem2.X՝]w([#;Y.O&UN`Z99B<`Lة#QxTY}bXL<.*8PXhxAOV8FF\e[? ɿN{2𦞬$pIJgE‡lo3 V`@#`X̷&Ayw\(d ۡ4ϵդ1?Yrԧƺ&%[q!~<- җ<=%XZoՒ|A4xH`.%2QdB[tT!"_<*z>ؿ \F)f(ϊ~:{Dr3\p1ي1yפ\tDE^ND1eb6Rэn+;+:l pOs# tLL1=C-ke_u :;? gr+E[UӟE9NwA7;{P0ct@Bq 8g]8YʸM6eaRz%pɻh7 ְ”o=*oTՏl{tDZukX#R2"AXޫo߽>yc Yr| g9 SI2^DlsA7+zlN#`ɂ IY[Y-2a8=ef9,:>e5F6jl{XEՇDw]NPK..A0m1xWEؐ堿9T‚)v>t\ ؅6cH*vzOV;V?Dxbr=N2  <.=GK905NJ^ ̎ksrmx^BϚ|d"Ą,\ibtL*髂 q;$y|O̩ϟ{0$/}yao-:n- T&sGY.\%x|h"Ђp87BY Yn0gjTiE\Z&{{C'y{hC]어܋tS=<Eu7P1JS˴ d9%oU?|Wx^]ޯr&ױ OةxŒ(t$Q˄s;#KCs{o'J,S5knj%13Se?NXS?kGX~?ONy)qi@xT=~(O!ZAdtGd<{bwLΗ{5Br7O0{B?fnfp{lukK=k]oM/CFh=kT%冷>7a@×CM3Ҡ }dS^]Z B2M֢h6$P @ZxWz6jbb1F0/NXaZ ? cU"JRBNsB\EN+6,{Tlٹy9y57\07iՍ# W*\y62\~GS"2BQ4OuHqUbm ^9X1G\2@rY1=ڊ T.5Xnꖃ-,/^\9̭!Q|yp>@:@0xn44ǸΏ[.jW_h/'[nU pkn>j7 ;8Jz ; rJ @{Y؈tsI\ό݆qΛR@ ,+7&2rY9h|Ի1x|y# XN.bsyy.O ioo,9o%;Y vw7 jG ]}%k9́]]^ ,W8 O nHazH( ևY!Sʽ+zz0"|!Q05{pwUVw\?r:T+tHN@x-Qq]0hs|w3H?EMh4>O $yB" Fz1Sxf*-1S0s-ӖLR8(y 'ɃH+рT&+3H|7 !Bqid_#_<%Lڭ0NלvrzU!>69JfP2sX}>_31zB|$cK9e$x^!"owon~"xz.TCbJY E)!ǼؤRBW| XL/ .!( 3@^> @/7ħz=s%vk_D1zn wo0eIIv{pa!R0xH LAFB$ؤױI⊶G[ǣwY44zMφO|q9yʅ#llr= ?~k7Cj>~7F7H;ʖ\2H۠.^R46}S( /m[ Wf 4M.P+H@ }@ՁG[FB̩)AM jJlJ`SHhd 6%xpZz;kg㳅Bř a%%( =# .G2*"D+QE]fQyvBtW-c u-zcxw)ylR|rˉl/ R|ih~\ c^$v9ɶG]?֖>\w/;p~( Jƕ"/nj6j=c`xDq UyI]zâ& |׼nol(>7t))RZ,'erWwוk*7btoRԌCKrP*}վ]L̞]L~TF.^zKxVw.ee|T{V{GGo>{QGW;>fݛR2ݬQvw=YV+?2.3mW2Mqlg-ϧf](Ír@7\v̽I'=A5*:5Ȧ dͅ}2xyk;#ZA btI]| 3CJj'ݲ):2$E$Nw-'UP(([/PRRnA}H*RS)/4"L(Q~ E8id]FyΨ͹f1{<͙!Q/FtqB?rȞfG7kOxB?UU{~=?}oL/#o$."xNk+5oQ?@y2Z^\@yIBMM.pLjtLXIc"R^70zCu nW U_.3Ƭ^xмUp?պ=@5'[sy6S^ʓ+]rJDw4Nss`[;N}< O럏^G#y]IGp5GW0"å*xQJl\i\q\Wv@ơdN~ ؛*}36JplN$3ԩt(vK|BvLj>%>:ɸc dN6B|ξӦ=m6"՝ ZLHh|X>?1yOJ,SZXSv'ҢxFꆸ˄~H7.?<~{ZɲFw'ZcPz %eʟ{Pf4,m:U65k0 ~MLb۰q{Ao)myiJ)kb Gytft EcB 9dD\Ek'&2(c;gկN< @iJ ?D͛'Fg<>r[]b4ϵRZ_/\/hE>;T7 ~L`aS)8ZD@c0EK3<ຐo-h z5wAS<B f}?VVP WPX4H ^ KC-&]}^Cqmv`y?dE9R4%]*31tBX+FBq!"?<讞ю$ çL/['S兰 ՚##XJ(sO4\O915- LϝC1C lyb.~k;ː'y=dzqt 竉0q r`bi@57_y dJ}<%=ꐅA`,y%yKX_+ 7/Oޯ }]0 Pn`Jx锇DZDr25n?!* 6x,< O< mj I]2,͆6T@ [ًRSu@d@B[U]1yݭxjgKrOT`ݚ 絹eN/f}>E'O/mYZS?k_?Rg'΅[;N+Yod??>G shOis41O>Wwߗi9Oa;w4]]9~Ο쩮[Kr4MQ=--f5C= M)"^Nq$G'mCyCس"bD?Ms4×z,Q%Οh<L!| <ȴJOX TbЦaB2V›yT}E, _Z|Vi:ӟ5J|}nZmOekYCY2uJPwrt6:4`_ID?QËK"0<"5yXxWpzA9#'ܽ&ώ?P߉Dr@ݔ7!8<|^!USѻִ|_]>6 ] -B OF6ڈZÍ!st؂ 7hAWў%;L$H˃H&ޤVr3(j7_!7]]><mq5ΣQeyi/tt9A h G].u=}#@Sл^BOp9[HŠ~i*u4ow]}/2`ko\E8j\0V"RO|19E9< o`Nc #-'Q, ikNOQ3IU@7Q'IGKqD*ŀ׋qsS(ܭ8Y00Pq&>Ͷe<5|Ԙ%?y9ԗB@.W&рì 5}=]po5þ]O.'S/So5_SD |:?wZB_4dHNσ dM'Gpߐy/F `%A_Q5l.73+gJNJ #E_,b ]ߓ,>ߘ,{kYΩ^%;ڬU4%gkʑ(Gm cr\ncrɑnk\4<GEp=pvcT ٌ.@^--WV8r]Bh7nݛץ5:؊ֻivA).!4@)RqkڵgO?g6VV ?T=D!W''ns H6on2ڭ/mb58aᖗ`| ֣W~i[o^ z#|3/Ϣn?!o$ >ZN ڱ-R+h%$ )'$PW>^k]7;,j73Iyo8~"RZ8=SF܂Hmfi,XD`awLE-+%FJgS-ȭz ")5cIFqDN浺wLw#~HpE\q*iB&n-^Pi@d޼y/PݍɱIݳ@z_dH$rzҪm5zZQ(^QR?j ; p zQJrxRdi<%RTcs&I&|.<|\vމXJ-Dӥ@Ze˾>u{Ko1tߐi2[MsHcu%M N, )]dr?!3NIîDJ8֔. e{{Ǔhy|t6^.d !q z"ǯPNO(~sq}pp݌-v/mDSBG"# dtilZ vkശ~ol: kQ; 2 };fU%0l'%1RҒD-gb߂Vz$ Yu KtHSSbGZ>@ $D%lonQwX OwmМ "EydSqFNlk:cAtq \nmם2t? #K Ir@ʎ#V`!*9/Vg&п負HISA>!%p5EvWjAw "sACP8FqeBteOyaM%/ln! y HGP0LD0vLy4Tղ$zaDs7l 's)ߩЋHe8m(ݣ!1}$~Vh-U vݏS[G:@9K=VɪqJGpURȪT*9^m4}M))!+ꢌ4lX-tCɊ}J%!`k%ZtN rLbT+ڤaAyb -aR.D˳IT(fL,\}nʔ$ 5TIv]Ri%ă7_yw9uV#ڪbTIZx6N_Mz-HeVxY0;;Ϻcb4ƑhJKV}PS1"zq=B<nRokn$)YC:2D8Krx&ecp,fN9bLI>*B(X*MWM+s0koEK65Q#e)/"^5e_4ջ%luKne X +$+hᙵ 7αZfӭdԖ?m0ee?I^n3ϓEviEie ljŋU΅6k48 RK^ESQ9Ju+@BqP5?6xf[G\;NDG8i [%ӏ!P7o` 88%]%i J'C$$(򊐩~G ǵ—hʰ_^8f5Њ?A!a'>Ui:9y6M2z^FqGNuÄSWP4%4$d7r8͜"i*:0Ht5_J(%c{ޓ@LegG8|MWs AK)^%hέRYN 6y݂qy>Qޮ'7M{V9'9?;G?,P|4"8v'M?@_}BEL6W%U#hn@7`"!= / $Wv};|[{We!йF ,fiERj[je׶˱46줫04"گ)gVdfyͻ4Qƫa/o g~/&h_ u[ 2 aMj(bYŲ3bX x6yHg7q|m3,7{%hQsuAW(^%*3ϡA|^kVbPDeaL*eJKCaw5CL H{ͅ22A,[ .Z6PE0Wcua-"sTnz˝4mq# Xn @^Nl<>G߳ڍ0^ EHw٣Gq7jvvNkTf]x2`k" B5FFB3| EU{ǣrwVfdAZs%ŴIDy;Q}o̟?O )odY&dmmĭlfD1袢۝<iR&ގ~Wz3Ҩ?qp?zsOlD d/ ˣ٣ӋOa&T;Q@{UzVeR+çmKC%@tخLu_e795OOd\U~1U!I񺤗]sG;8qY=VҶ#yh6aIh偢i8t! tw06Kmٯ jB+>ܵWk,月x$Rӎqb" 3p4!=p1+'4חŇoŵ[Lh9䄖^qyb<* EwqWda2 cm5k2L_KXXV"Ŵ@KqMf4 N 3hLrTVNw| >~ O>[[l/S/LD `Rע@- |o(z'GWO`{mjz2$iWH⻅/* '|7ZF@DnV=Ҋ}na'KGuc]!rsf`Bic=v9o (e. L)3e6M+ʇqrG1V? 'o㵖vs"`$d L r Hd+EUZEtʖ q-3a)4cP*Gd1Y+}"w2n1b%_,^QUޯm[0W:oem+Q9Դb45m!ElPNM+WFMC٢LO+_n6XQ5aMVoq{uJ*HU?2n|H_imxB;;Vє0||z̔-S ^Xg/yfdJOt0n׳\[[/ө2`OXxRw*PFH)ͮ?6in->>"e ;" k Q0ҴRZY~ХZbJC%=~_.{c)h#.:Cgka߻0t1#]qS eZt W636rENlVaq53 dP3?_ Uta F΄9.o]suϋ<qСDSѿ#:l6Xe;EIdC* =۾-^^)uPܲz1LnBs?5c2k]"?,'%'>-d_GqXo n/|Xj肞\?̎;E?;m][Բ@- ,K`V,(ӹIȥ^Ll"*CvDUyGdn9"F4IXɐє}La!z3YthF.M <础(1>>@Mt` [qlcN:JLW֭8bSTD{=XO˸)߹h ޡ\v!i=Rc3d`Z) Ά4y5W/W.ӊvz`i"|H?M|(U,+ :͎siGJaJQvQƭ1Z5 mQD})}K. VbFQ{=^@SC|~À&KQL?6<ǩ(}&69k""6D %!|9*$!pQj F ؉a*|ʤ HHQt9  0ol2+TvU,/'[M75Ÿ)ov [rsv.gCԿh!zL+M-)yuYDn&iDݩ˚YFA$J#'uTY %LQeKF-|W|DUC.DD0F!p0H3lmJDG=&]EQ])>uI\6ɵ/OJ}6R!tz t4 bo*rR@I˓/ `ds, #w1T%;bti :q-\lI?gK}"K#"nɿzRUC:= XXW qJ&i/?kuxB [[O\j_[1 ?NyiIh  jY(D2aGTqZGw2|gr==͇vSR? k}٫C=9ӤWGE4yxٕ tIZkaX> reVLηeZ˼nɓ+9`yZݎө忥`UP0_6߽qS i zš;Ӻ⩤O_y p~-[._}_|O&X` =W*Y΢is!B^D%4Je2.T-JkaO>M["?t[zGO8#Ⱦ;.";Xs\O>=zGUϦ>.Wi>..,Rĭ`JOF/6-67; j=cS?S8~r?,<|k~{iźRm~Oz}QlU |8Cu^m#܀*͐J%"9nrb5(3 x\?]xyWִt|[/]ÁJ Rxy;jVؖLЁU]}[?n@_QŢȢh"~I RMat;Ywl_$t޽ݻ $-=le)sFO(S_xlMy=jt7i~>|ѾZ k] n@0 &rs"~Ǭ(k kĶF  }RVhuԵ̶^l.wEXMH;s!4IHGc<$Na.V%5 1bm^9Hj}W'eo0:B!,lwHNV7l$)es@A^])nPOz}rNVYhϒvP\Ko]h?ެxjWKQ@_ښ aA{,C- BC*iU _#丵5+I'nMݻyJv7  B@'(U-3ɛgpAADGBfd#}$Q`5^20DC$m:# NL906@YO,x}X%5FgsIx:^]tj+m ֺJOZ]ٌ#DO.*VB( [K, m`HVjM;eE`s7<O o\D*(4!+\S.Q=DU$tjtuyBz;f4 Өy}v~oOa&5**p *7f@Yt@D]qC슈?HzdYbI.kk+d52G{Dg6.}5L$lB7[T^L0Ϫ:v|4G/M6;r.ذq }jN`EjG:O2>[ۉwonŏwWϔ FMӅ.K˭w P za4O0R NejJ j~mE7B1t؏.z1Vɚ! *six8QO8Mf0.f XϤ]EL5;Ɨ f Ph˧"9;[!i#(وvLV{fzt?gMdK! o.]ݞvIc [zDʫx-&?KXYӳIzhD'ΆsntxW{qn1^<ؗH.54}V? PjYeȗ&.`m)BMiDv0<%-RDyDYAҜ}j6XhYEVSV*풦H%́x*k\^Ng`[_lgǙNCd=r݉:.u($8ªe2bL)jmw{hsg޴/J 93IKeMkzډw1*$5{ d1|6ams>^+Kп ׻ma+/}eZ檵\޷<~c{3[^0@;"Q@Ek'2=J~<)'rHO0Sʭj=2 Ch2Xck%mANPr,C\rލbQR,oĆJ]){K˹}hc M3bɐ8-i v`MĬ{q bF^)oႽP.o^)ঽ.qrf״LZnX' :ɷG`㸵[]e<ˎ^ @] SJlF cᣋ+j,RxҌ CH{e)|T.|Ȭ!aCVm{smg-cYAMcޱcԲ44ɋhdh&L({60HN~JJĭ8HX& HGgxuC-)VBztibdbD+ /LeBqܳ3[/.-ˎZ\D.'x&W9h5j@+1LrAl-bdg0ChάD}ex֟bsA"vte1%vI 'A5ߚQBY+%1O(!D -$J>s DwrA :²aéCIgy8R$LGg"4Ġl|:wjJ_^ JV!efv^]3u)=W0Hy|57yI3rB@87Eq#@B[yL3/Zh.a>=Vdon;[H{#BotMDG7q&3gt?ܑ*nt~*x 4k2:K1KL.#,h.PR^ThR_b!> A-_,h;s@⿴u<5;Y`I_ x 4":.qghߥRw]].w@ lfQ``/]u:Kl1X[xP2090LSH$s,+L_TFNa { 3X̏dHvu[Ǩc8FţH'u :Qm^èaT0*(?/~Qы؅7P"^t D.nܢ#-0nX=.kaq3psEce*c9L`H2YsXqm=?ٴZ2m~eؤm?RM1E/ÿd{|?o.2 Yff'Wj R@\KI^_=Kk{[.7OY0M/j6_1 ë7f^Ց]F3 ,w E]h`$jF`<',ʌR+rSX\1U*Ţ4RBO/0amV \!BwE)-w)H _Xʄoko ˝ijOW (+kW &y*Ky3vil qnt'DnJdztw{AΦ= K/.d,ȩXryi[Mi]~$@c/p %sxQ>'C3"`*3Q*:kPR*)H ~ij2-b+^zo%SAFR_rLLTcSl_/osZ{S-[ᏌHoޤLJaU-۬J/o[4 +ڶbfV~[g 5^nQΪF9VJ)tOq/ĪMKU2`r2T!Qe&Km6_>3.lgrvX l98m&֯3=,u\j `4m7r-mіcmh+,R5124YOۜB*93Xlyd7,3gC1 B laEhEeJRQYYfk cD(4x!KB|I2v֛DQoՠ0"WZJuV"l YepyMx]+E96=~a>3p{zmni,Rsbl=i.<ֽ!\n,H8yeYDX2<ܭCa^hn,k+cY!r h֎CL6^pjypN~0^Ph J6jPQ"0"NW0qF/lL=Bhe"{T`8(#_!R񞜾[BziN ̮L^Ztb@5梙NdȷY aߘuFC4r".édLAUs}v~U*)]/2#lkTxljJoДm_&%ST. MU+^+Vse)@]׷fyךަk4ۧA,(/T!US 0  pGPDCEMw|lR-b,"p 4U[#{yˁ>,V}8N{2L@I!Nt%BVddgaZrֽCp`O=cNAL=yGՐHQSf뢢pLC})]UzAS-@0F S:H%@>|P>_ P{[&7,ʜ,=l_P'($ue!EȁunKj%P)x-Y!LVŇDO<(G;nRgcnO쩕=߯g'<7"9E`P[/pO40Z:ɀPލ ~'>$<@r?o;omujgyoA-|8oN[;N[wqAOYԟfdvAhur=l=4?J&?e~2==1.> _s* Hw HQlKw.cA4WY!Ƒ% ]J,fmrɆyP(~Nc:OMU(Ak xxTuBI-TcOہH6D1 j&c ]moXsk9:[_z&6;^H rUV"zNUR-3A?)ADr:ͭqDNq%0DWIC'ONF#BL61ˀ*mQfۣJ%$ldT|Slո{r11<ZNx<(>6Tk4pd"2"?~FZ DP߁ҥv)P]r Zw^"-jEz#KGKc_:C֛;YQrZwhǜSn]5M΋ׯy-o V#ZtPN+v]XrN1$xNKnxT'ߊـVIZ1Aܷb|`1#!}ȦF#RieC $ݘ"{xx1I^ 2PO}ң!\C\$K2)R dӛJhͪ1S]Ĝ RQ YQkqJ)X$>'F|@xxq[)^ GfHx7h`0xoM{t G$x$fK-#'.|JK7: iܭ2=Z%nd0K2- :;IX=iXإvEJ vRG3L+ʵ"y9Oؐn |w?OV嗐-F2MJ P̽>]$鲒%sa=aN-fYd'/=Ţå*GFݷA<O/=+{ՋiI^coB7w(eS UEVns@!=k e^iv>y9BN;V(;j#@, ;<s) Id̼@L,V*fv414Ίe5Ļ:~̼.f.0ꮱlJ~,? vfr9M?eOOE< ~ok]؎itvqK";]j 뾏s+ |ya1#7&э\g`^Y 5<swMws+27/jYg[7Z /_鷻-K]6+ .û)S,!dlp AUާ[`8_އ09Ubvk7;BߨrK^\=H={Mz(7MŹn_zȒ&H@Q( *4W%M&,' ܵCo߱]JKxk/Bo[-woY:x<7ѩRԓU꧝}Ev:e?8%i.ŽU2%3]YnϵPrp{J.ܕU1u}TSjx w8W TKC8b{we|QJP#'ۻ.-ۻl^gיּKr/9}o8=UzwKRr..NkO<'7;Z;8; Ehqj?dWU-@K~1Dy緝4t.f7qksO'ۛ:ommu5_ƓnC)q S؉8 Eng *>g7._~5qvL{A0Q2>{(܈]HAR^bDjh'*va3|P3RbY] ȸhWPVL ]sKK[Pi#5c3ZhRFgR\{z.G ;KMca3+{\W˥j}*7N-ZM?E*ϥ9|6$g]SD寗7M҅ 2z19TFQvԀ@Ekr5U"xt4,Lr` 1{nPlt|lJ]Aa vxȕ;y3+[V.n6E0h/M!wΥ38iA2zZ%5ݾQsJmE0e>$oKBSQy:ˆվA;l>/CUc(u a:}޺2*QJr4 ޠF_kpB?{%~Y}^]EԚed x ;xq e:D"ޓ8{KZo8MzQGlƀ?qe?;['*QA 7;shILHXAa;hbq7x\lP%6o\˛t2Jޯ oPƛ_8mv SsVP~)v5ۨ6Su/9P_z%ZVJU3?"=*(3ZYKeBV7ܶ3[=S5 WBj\=g*gHwA6hl8Cu0Ko u*kv1 Ri ]9\b O`ޜjt7{!TiQL/KWHͫQ{{c۬,/C}W}lQt[[s邅8^آmm3u:zZk`IO.ǭNjnuj'ZZ R3\f;Nwo9yjm3TajDT!‡2C2Vᚷ^XYqɷΌ_ VGclV qIWI* ap2wÈ RuyYZ}1Ugݭ ˶Tj7kUػ` d_3U*Aɝg*`{ 7r*mϢ5i~"TYcL UVΰ'ts)y 0YWv'qn[k]kgBtWN M bw.[Z p%GHsf.Vvz\]} 1yEqxnRp0/z 7eȁSQ^-%H~oѺRZTzK!O )h3'JeS35ݐovmv;2Z[755Z_ArKAqK`2$\h𣟦FyשpK7xqQ5>9߭vlfZsh~k.^sosv,̟5u6w0{xu -HKL,@~Jǽ͇HV5r>;nY\2:^'¥⩥+%I.+GEF]Rl7) UPsQ7GՋ޶?j=Fbl\W|lRx+fU;z1]Ӌ7;ty \ Q--KvkŰkO4z0!~F]R4Fw:8.v9޽|%mCD;b^_m[GC'd67Ns0dL앉i 3cp5y+Cϯ8ShN"Oq ʛɔ-H.ꄼC?HIg+wyn`Uq.t@%#r !hBbnpS1t) 3A`j5%.'A'xIztBlztO8t(-l JD .йzg?G B>ވ:N LO-$ljwx՛^:KٞW` 91Am=ğNS{:BQ6؀*jWl`~WsFb)1s[՜+AֵO,mc'}Ζ/ȏQ#?(0a0̹q<Q P۩69$3 $*"Ej4N/6PA]<<2;BڌNՈРOz DOÔ*SK >GtpN~4fv܍c+[Oo+]ۂԲ)Kitښ[,(I @-#O w+)}2D7GdBaPaUflGRt܇/yG9a5d<]d%][5G U-V"۱"T hǎ,CRsn~WGW'k/ZWϨ\EafWSXn:'`y;#0G+UWEZopPO(-0[%ſm.}BAȎٻ@(Vglzg0,?G?uw`s{0Ř,$kcfN&g&; LSmD-ȋjcݏzrY'-?~llG.$b&GBa8W|ʗ?Gn3 Ѐ@a[r o^HX]huq$ g97;<_^8~ 7^kk7*'ӤZc_@94foD1cY%VխUL%4$ g9sM-[hejb\QI]g\^b29"@}xMK!5԰> `CTƌ1tV9ʘ~jnKs3R;\?݀ vR`;f*f:kZX,7tFc5U99(fQ^󬎸C0f`RRy}׳d Q,)CO]f $ҽdyFHdT|Uio&}fY¬|i29Rp U3ŲYn\יӯDyypH9|=}B5  T9Rd$U- ueKFBM݂)\ܬE!esJ"khfWik38S%Hcl>j ,dMcY o`2Zg)T'OL hռrY~4j\ whK5lmZ~!鋰CGHj5] P&DʠOgjnW@eomKyO_mh8ȋ7،t`aN snj5X y Q>ej5bKABC OvvtUpUp W !:w^߭;Ynp7_Ɠ1{&ȑ!ګ)w:G_H7K!Bv#ZcUг+JRY*E+IrI#MEȿs'I׷{' f6tsd{B#®{Dܹ?y|zw_S8;̦NwmVw1'p_< /~ꋟGy~xt 7 !'0H^] 9!j6ᮅ_OgpwcM,OO (jtJ=; $ z3FRXgdG$C _J(LN})U}|Bt0>K`?ȑt<㻨Kd1X^3Fh^9%P6 gWh[(mAJZxֆ6ݟx-Oqwmō=^/{`v_}ImڅBFlhk~=׀q!i㰴vP6 JN˿Uеgv7}j_cڢ =3JF ؠcBOǍm4Cه/>vSb]xBLhx^LqMw}H`O^HʪY#吽|ݢ#y1sмiG?z $@]~%w/Y#9TάgI] Jÿ?g6w}~d 3T=DuYS"pƒdm\]{Mz7"yg|e@e}eqʤݛWsc$ &_Md9R$dJNt2DwBXcoFߤ7MGο]$#|(`\ YS"D$ "/wW##qpN%MɐpD&̋dKGFDIY˃7!3Yvt\& GH [cFOag3E"tj2MøR vpl`pߟd_g? I[yZt&%/9<8J&J,Ato0z/"( ,}qC7$ӱ}P!n^)ŀ5%(AFh*壕D%MF礇*As"\lC('I |K}5 ہ?9DЖt1+YLǚ$5KTKoa 9G`H I2% q g'Dvwy^*.&\)sɁ g@Vტy8LSeE@Rzҋd# -^Ro4NdCǏBFnCTF+P[1Q;'.BP xSNF@ U}`P-]ma9S$Ė8qvoku!+18i8uA2ott~)tk92 2Q"dG eJŸ(g`i$b7WIf-mv%DI|ذ0ڎ 5pBXbo0$3c(kH:u[ ѿJF$zD>w4&5j h#(g8 cK kyfiE"><9@W&Jg⯐oX ^d.8#d8$*lSAd4Oi!g}>&fU+G=(؎V9@gJ4g <\] [KwaI&Zc=d{+0s7uWʸXTOL%@heN TZ[a?g5%#1# .FN˼BWKD "WzJw4Μ (E欴{6}L3>jU9GDL[fuK gQ+Cw_-:LjcTc2v'pEe7:E!Cbb+ DSvb}nd`nNC+Tds2lwޙyiu+@5*܌x6>Y,b_BGUn>(T&Cx3Afe+zü#1lVJeEC%b:sJ>ƛd*r=QKn[\`^ڍ^F(pN$E[#(ᡅAxF/LBқss?29sB :&k'L;bp8)cRg8A]13ܻp  VGWчIExb,h:i:8~$ť;:pf`\ԋ>r Dx.h/XbV{aX@|ncvGچdRLX:( +G[2.\#R`R;lj2Ѽ!rP.}S^nSM{v\3sl^,(wH=}sS!A$Άw^Rx/#, „Ki9؀O)"%!$Un:<;X'=pqbAJ;'SmP l{!x"?>a$ԯ_jy4KG 3a'tWD|]c6Ǻ*g<~V5pq!y˞> F]Jrݻ ɼ6qZՈ!sU=ԄaPkd2IYZ|W\>.a ՛QB) DB0S'aA -ӄ)W#_ϣ .kw_^hC0kG弨0g\U>O+'f`<wAcJaYgVx*֎a7q"K38򞿡J~'ukXk>{4 wzfU]=bR*`Z, Ų9ٛAD$',YTP2K?ɠZgvŦփ]`L*ot5N'Wa/ȕ7㫙㴖 Hgt>}ܷ'&g0mye`Zd] 0kKz YE6 et8ޯ\kOB %._EJpZr rܜh$o߼;{ܡ\{fdWB TtP5\9 B*A4ܰ`2ä/iTVUB%O Fwj]9^REda ;WRzEBEFiOK{)vԏV /mխ GcS(nkVZxzHŒ5I`('V ӄ-WB2UF2dPrxZpbъ7e7b2Q}0C%/+~(p]gd}ÇM;L%‚l†`a5;DHWvBZ]HREvƷ`a:V, X9+ [XV=[8#G\[[ZU[%.O&6c.V˿(Zy)|G8-`FTL~i>l>\l'dxGtܗ쒕 oP ZA>`qҧ51X :dI)ȧMZb]kE+!@Ž1֪ytbȼ {z }Gj~ꝀQWABiH%Up{_~ j=N Q%DwIRQ+ -C?|<{㠇İIw$8gc4FT:ĩx^mWn3lq]-,7;dLۆp:iO$ LT~*=?LO=L#E6{7Ցw?wE2IzB?ljI÷d9~;k1Ů : \[mEr`iw5uw8S4ORP=Zt = zCN3-a> űc6bFJgLvޏ0#}U6&⬅eB=ǖ d(t<5sJ=<}S`F)7D"]4D3`2D18)CBk D~ȱ.G9&իI&y\3;40%W4>E=6_¹i0E޹Ohwt%ky 7c'^8t"aP`FL\#h1LW1kKvҠ#s Ϛϟ憒]C d0÷.!K$M>ކ, Jvຎ=1ͣ3mc|KVrKjy00U>WV$ozijc|ʳBe3^{[|v|ľߎV}TaA#$l iA1/zջ . JDpZNn.Mclv )7Rv"@W#QI ~r\BIzb|_pԸ{MEhӦm=]ks 2SU kfuLp7#e ȑpuU}Ro-Cu~}xumhu<7gKS8U1Ŧ)ΑOvχ`咫{YuMU'eS0 It$Y|œN5pR2Sm.6dTrR\, Z[Njل!LU 3j`Ԇs0GN쒐܇*ypJ&4K E-VwMſ:n' !ͺ/N; θ\K\dz1Շhށn1Z ?0ِ)`pAfNUEv`1<97799c "пvXVp@pVBD,d`zMO{S0egKr,Akh)4qѣ*\}&Rk%PrDB{8#;:ɻf)R?qb?Vgq+e?VX%Bc' +~2V"?wn7M?(ǿs'I׷{' f6ts&%/($$DEz[Ν?# {xq~?~!)q0J!/ݹÿzeC<$#ߞ+TIHr A_և/QN?}ypxD%"_H^ hAyT>9/ͶnO>?O~<"]4}+sQ4%cѦjYu @qҌ+`D2 q 0d N-bsӖ`=LS\ P-^&dXky=:ϦUoFFc+ l{s|obaZf7ћ7Kleyկh9^ufrR@YY#6ѻzQ ۻG޽y-e׀w{z zQB"竅EbvVZ|`x9ʟVו-Zf>?fG{˽m0o^g7Mk?x`?c63Tq8"r PW-`y(f.Zޮ#ؔ_w a^yfw<.TowMSv<>7|-<'(o;y^ax޳¼ k&km-z=_l^=~j$K|039Wra]F$AF=Ei! S`ObGOV& gSᙞLvWz;yeFY2JH-;@g""(=-biA?[:-{5$;[yE}(~R W}w@_Va+C]C`G}сS#&ӍsA#rAƇbjY*Ph(!C)DOGW8029T9dB&;2ctp/ f>Jܣ(cV? |:(Lހc]̺K̍;bx}0Pa[F0'pąv5@4 Y?&ؓpK&dFdz3ɠvqipwpJ/FD|Z:#O븨Չ.(A~翔=Dk[ ;J1,][0V1贿A@gq+]f?ho܌j0ߣDf1#얀цbuO"J+ $QrO`!8#0Հ*iYl`>J/@%aRgfV8r2aT+y+0#%"joF(}8f8&4pᢽPNpp5 ZOV,TXD!U~21> m&a0rwimOc(׏3.$iB =9eRcj\FhլO֌O> `y$c9iQtOK_Y3t2fH#b9nJ*p‰A:]=-ZL89VfPi2n٘H7u6dychTp)h`Iecezt#? `~V焴 k8wʨ'*٤1^S"Sqem\Ə4 | NI.cA%٪m[#m0dUV@@`(qEfȃ@pc5t3rhKe/od1\S$Dj# KÒYW .QI"I|9-`t\)'* v@s 1!WMpH OB/q@]:tsϓjf{ٹqEotG,HQv bụI1 vӂځ˟r$N"8T1 N)r;GE5?+u ɟK(%7b:EK7X5zLHUo4#4vQC3N0H9\Ra_%] S(@VC&p87npH%ɊdF߅QZ F;=eU="5Cp2dh1`q {fJmԾ<\EHiV4'*5j7!;ȱK4R^U諽)|~tc /PH6e&y )@ddByWݏNz$ -#\DPqFF;bAEnHUc{oU'TTa/p d|q r8 ?AbV\l- 2厁N rh NidvOaUOʒ7zĩݍ3+<(fQzM ⢂'MrY_iOq Y9>6\Lԅ(vqeLO/`BzB#U7Wי1#\];d5;PbqюGIЦڢb6M1%_z3$MEHؚU NU@ 0Jk#vU nhCmdSjRt"fA8&º(7:b Wdh[Nbߡ}ڠ]]j.$Z:-FX\bb%J_)i@XJK{Cb<'l.3sBwgDz_22D_,BAƘ"Tgh =,4*^%##$tSPpt/Qt,ZHD 0nDž~yNCOz_:^zs~)~ gXY\~(0Y-0kޱ-1X{<,.؉gx>>jbJ|̕0J&,gM+H4!iN>ɯF~ooQwY\,-KBs=K O9J[@ E,*wQ<[L_( sv4sp*Zm/7zwHq%\wZ `g\SAu=ٛ]_O0yPyL3Z*nCMʈj+HMWHrp$'y}n ퟠy֐doQq?2P{d(IS^1aÏ\SX΀N:ADԠmIF@wY0B8. !{yxtnq-D#E1U'ΘQz^`F?RZ9ΖRP)E>(Q)p~6Eauy=1GR/" =)B)~yy` ]$ ::{ y~ ˥3,`>oRqF+k|WDȴNSNOWEi M,a֧FM 򎆃l-;̪PrπȕF7J* 'PK*6>pPf4" 7әΡ |h(89"ں&C5bPGӈIOPbaRêb!2TtYPEGcj (Cq 1r 1[AQ5m䀻 ?I'gn7FOb7B46Fƙ\9sq\Xjk+[ LKQ\ ,U 3v5n>Yd5'NGV6@sF=J;^ҁ!sf}eS " GH})ruIp P:ul2MG RHCLtJaʊ90w1JA4y==TM< S̈P_ 41ipm:ND@2)8Q\Nf1qOْeFcט#.'K|E*b]]\=K#ͳ SY+j U^g'tnFM]T k^YƛQt .+2_Bꖀ.&TR)L7>UNDƷ{yiGeΤLpx8**g=ZT47 'DŇНlE ꘘ}RAM yPBNwH)6 Rv6SMIݾ3hǪ^$S\c [(sLJ _Lm ԈQ?v/KVp3,켗ٵ-ٚ|vb׽Aݹz,\Zm#yz:{# 8@o ;E7ne|pj&;H'lDK-Q`2잁\BNdtu4 @ǃ DeCݖ:>B3@?!3֗H@߃e-B󮈌cOR2&pgsE]+ ɼ|y&JFtLNwXeNZ߀vi":Fovi&zo4w(gD4j̱=.X]2^ o0+-6S7i?xJvL6]1᤼535&j4.zdDwm.  ?b(5}مGq9MF&>JDh$[Ǵ(S`ڂDlՇx֘pֵ}uX #3{7?l^bG? ;ȯ."b{4[~u/f23s⷏p`T[nG#n{xV|EŻ@CO}t[CRt>,+撌t7h)=ʭнs~yspA8^tXG׆JVAvSfCV|kˊVl?L$%6:F &%9y )ψ2-9=thcu>1#3i BnagN6E_S:%JH% Z'kT=Vu(7@\A#ע{6rWH?x\Nˉ+%dƁIȰjwkɇ䘟-1 G^񚳐hT6.ZDfL ah#LiP]tpSJ1Mw$6z ^C(6L4 3wл9a(Ȯ¦/wtR㇓q1(\q}1@ͰHΧ))`F41 3s גg殹ͤg-X{([J㱄dnyﭡGN|\ fVhJP{DT6tK'ծ=X&!2_(Y.Ye)fCZ5TQIp>>V, \%v/YL]F> p4Un75r\ܣbP_:BIFxMkbN̥X27,Z Nϱ'Ef罧Hо/A㆝~qVo9q]PғL'$?J5tO`njY#/)(^c,ꔢ!lČlű̙uǏU98@Lc>ho!w7^z5D!y8Q8ueJfnXH=S:ׯX$]v=igE<@ @Cك?[NC gA]*+ł`NM tc؈bMl 0bt?_<瓍k?>Okn{|o[j~y[4d3kKR ЏWD stiY.Уed_`”;&;{٧j@8!yQ~_6;bmZDU >JTX w LW';E})F3tHUON27eaެЀ!<=\=;N>rg投 ۵6zC.D "7O \b jw nP8 uf1g6J -f%IQ5e5)N 3vͼ,&I2 pm]*;x=K氿'a9IFkDY$/0I&%UN4 Wf ɳB|c K9a4a%2o9"b 30I(XI>C|Ȱ"(W¤{(쎎Ht5+%j&%&p?yPk`H\&9LG;K!`8Zs_<ϗVi cġ#:q1䍸Jz{$|03%\XP+!ؒwөs^|*F6̢z$~a?LK[2E?xl)`,žgʙ<@DA&/хUA12GANb\f9_DŽޘ&u5z!hLiLmA'go;1}S5BK5:Xkjlnooo}[Uօ; wΏoz  rt?ň:hs.YfĬ@T-GҞ&l><'"E@`k)v#43cU3{ׂNxKGNq|A,-'ovXv g0JVs訃k*)`|GW͂ F|}ܤ a:UXMhrau^K3Yų%ۋd:~s#]:%AIG|]E9$o|YME֕ozP6y ޚV 5D @B'd@s2yzǛlm};(3 ̾ cqRQu*@>$Sk/-KXe>ȳRn3GGGQ_^}`ڱAQBjkA!L^ >tlJRS.E^u]zmo[ovרdںCx`Q œY3eTԗw :/7n/"bg@t;z{gK $ꝅ Uh`>^䛃{mH>bUf|2=d c05dHs4.b2Fdd^A0 aГQY g7g^cRKz7>ƇL{^5opCqHّy}\+xO}fj}mx=yvs23v|'~~^kk-~ Gԏx "H"c-"-vkF?*H3[P'.Ce.q! ,,w*J%׉ l|wO:u!R/9)@̡c8wq3Tw*(IOe"EֶF_S6,*>_lIOW:CSb`Whj*"b F fRi9@7c0I)mZ=m͒2sDfni;>]s0Ѫ[  'BzSVLɉ঍kbÂ`dcnxpbvK^#6h?xpf5 "A#̀tVFg{IWv d,>a^1XOqQcc.?9cj:JI=T)4D+cǦtt'2ԻhEŃ@Ra8AM7f TͺmW&&J#䡠*E<Nt쬆E)z>| LL(qG~!t&%h jvb/Z x22 BZu %8f?fȗ" pS.L>%ۃjB9+m*Lz)ԭ)lr,teRuI1e4G?= 7T޲gRŴX+>hC2f6%_IVDb]pJn; 5}(̝|۠ |3m-q"f+Qy$1AQG.{c׭%ų!@1.-;YP;2b-Z 2͸)jX[k;hrE(5ڀH˼ 4 r!!$K kB\-&[P鐾Z?ROH#}3eO ȳ̂x;ƜJ.xs=$xnܥgbl?N*s YPN<t"32MӪ[ҩH" <{R$\YQPf}EVOXsvozKMKkoG_9Xy1r~O Л뛈ײ2M ,Rvs*xα3VxěLv~J"~n[};8q`Iih:8ۘbFr0o0є23-w!GufI3I+ߠv*X*E&@C6~G3d#1{ 9znAJVķ0>$dxVF0e-q}p)2l:!<SX"'5蒹&J+ɳӤ1s+oԳ7 e؊!cdA؈bd.5dPIcU?;Kq0cELEH"q65N%w0:},> l%̂ïҞ\Y!Xٔ6`ZV.Qua?TɏHoMZ_kh)<tCQ_$:9SCI t.y5Nq_1Z0dl;3'i6.&]Ӄ̑Yi%6 W9K7U?٨m|w1 Q{П{П'ϗ 1' ={E'Ͽ\LNI(9#I7!DCd$lWٓcۀ M(DՄ,'] xieI?#/,'I˵v{WwFm}m_-muT#AUNc^),ɯf׌qoe^W>/{c_'I7~D4YU aQK~iO\l6~ v/|[s4eT-ՎJ^ah WR^O/0IJJ鰍^|4؋I>,1욍# 嗣 ϗVfs(W[嗝OVOUhՄGqz61eɜWЂbՄWQ=I$Zj 2t:u TDMT'j>뎺%ÜAGGssɗ:&،ÑZ'E{r`7N F@v?6$W%`|qi#Vތ#cʭׯE_4`yʼn07.XaCfca&"fƔBd5 H2Oga9:yݳty0;^y}!|v,FDmN D4I UP٦jtl5fJGwrT4w*~GtyEJ5LVucC̀Np|a:^B uii|8y<.´wAA~:*[Y*x._X*[ B jk l7zs3pq6 ΓKIȳLJBe"uR5g3Y%-J3UmA0 y7Ys?z,u7;1|hXSc'i&mŀ\iɛp. /n=Jwϭ2} _9㼑lOra^x"!u 4KCl76J(Eڪ =`.iG)Π9#"Mp#5 ̟xń%8Y(}bfr1FЊyLy'+c-3Ϟ>?v??2}ѳ5S`]ŷMgR {vIg G>yt5me0ؙ>|8v^)#c֥0*⮄ϔ1Q<˄cw{Gq &͖F6 kj2;@ۨ5ɕ׽!9u*5*}ՅOQ5ΧGyWFUtU mDyCF: FFgD؀ AjďF,O.E wl:9H㩭FI [+=nHW@@$D (@p/ @i:f.!~ AꚒjhK<;\d 򀏐} !ב|RKB\spLpΓrp\$^"!4]*_m-C-@rT쮊-, 4ppmAʨ]~ vBn &.7L hH :ԢU~> t] YiQWFT}l()3 B-ۀ`X1PqSOo m-?i$xAp [)(j1'ݩM s!c~p_^,K@0pq'YboUtic}#+yaW t:e ʹ@ zqYٹAU2;cЬwت'ݦ Bp<u{*^t Op"E-2!xaВ rm*t Lx>W|1:GV:_l^\^NP(x/4HƝy}[;;aIF0O2o E76Gaŕmį=k{nAoE6Ǖ0ZB,nR'?T4Ӱ_ޮ?L?Cwd7O3l6{_m/7=zNJocqai/L-'NK #v|N? V`;\NU'wqiĪoӯ +\!6G͊yR>S ;K+lyy|+n5yGa[CB :w&}. P'^=+pf=Tw/MW)r;K'd@~Gw>K$GI:I/&u/]t+@*P\;7t 'bw%cҍ9mħq:`FOM-/;?l|wkO{Ks˄'|qAE.(u՞iʱK @_8;8v{S!wH,FF7Z6գ 5.4fLyS i~ 7="UcyLi5 ϥ^t:5%nq4h=@1ֵ y{HL!R&u-`Q]Q#arRykfJ(҂UmKpd,`Bs,Hzu526kd:N4?,wyy6x?|Cؚ;qwFhs *.ϒ(Y/z׳ߧiw/ p0@x //mYý 'oޥ 5S[CzE+' \ك͡)wZu  bJ{uKZ->'/idʧuZ~R v sւ!/_1T7D8J7Ч.e)HCvQH)pK,irW}]d !U*uA ~h|'SUN(|Y;Wjq5XLbtV 4Qg+QJv)A 윢͢k.lD NSp=/'*jfp6|e_%k3^DdJtՠʼn>?L?GO͉7} DvMmk$="HArS۵l2Y5`ļn렷yY%^LyI1S Z6nSb'<9ۚ3oMDY!ݲ#]Ⱥ澋kq{\αpTN.n[^+ϑOo$qaXr@uۆ9PVyЌwRz&28Ms9^7W٘R-ӭO<8%mUu L>8qs: BA^xaÎ)"RZG$;GgG9(gj󗗖5T:P:QBLaYd&:7/.(Ec0܋1x2s = F}SFcl4Vzi iqeZ*ka 7Nj$w@" -37XmOI6&Di-Iv>1W4,S2j  e6glL&Uu}۬_[*Mti/tHd-ϠaS鉦(o#x+:&ɜvH4XHgEy5rZFi1[o,CFSz H}Gt i9M/P |0E0;:XAGgtmZp?:t~A}u8 {>̇"VSw Љк([?D}PY}alV,\MF~5Oc90JشZ/ʲ,*j@ ʲg4Ѧwm|fca#x$\{й{1KG=&Ȝ;$^v஌+|GgüEs\GݎL%dE2UiYC yJ]-']_ۿ a5e_Lj 5NK̒=f הK&\׫% /'JB -٪أsO$E9[3㢠@d۟4>9eH .FkZdp+oͻݙ?Ag #Ec27 ZV5W vד"a}2L\dw5oo/O9I|VƖ\L%?~N<< 蚭z>%O1B 0_woዻtoĶl9OLjJ 7 .&$rR[v64&BD'!-4ZhMNB+I>A+~gMnl0]CSfwc^(Dy$[Z4T|;I`5pkQj0ͬ43dlF]uȭ$g=vM%JqsồO[iLYRߙ4Ry#΍ [p *Dǒ,Wl~ k6t°rme*d}o^A: zJ#N?a=|vr7$fEW\ژK$6tc栮ªBi {@aɒ3-3a63-!ob}Z-vI 綠F+1ĝdݜZ Dג]Uaі+ޞ_|b=~]ve].qEYhDkjt&zmj,Yjh ]S0uyO7U&Tl})0Bݖu[F0;M0\7ꍡ1M*M{BbAbuuajTB\~46gXF}>86-r0Io<=qA}@D&XҌ,Tu{3~M U=U)-藊w^9sM'? Udl!kOV|ގՒ42)x[s[~1>1mvyjД얳Թ5h!Zg3tn:;@XU=r zHc~F]έYa'AXuy,s lQO&PIqM/-RjURCa`s s-o?&G;_+&V85cJG }DaӡLUXԑ9a{0Mg ]BTu_<vĬc]׍K7neL5O(spҦYPosC+:i9FBgj$R#uTiHD ?Fk$SQS@T\:s-wf4kGO[)*h!\ӒN@ / EU%ͺE(0dKT`TG{߿1ڋ&'y*lΧNi-y+"k䫪#3!'YGӸÍ]͖+΢0蚿ЍFԾmsU=;ER.dTvm:ګ@7Cw߲ sH600g+L$ﱵQ,Cn^hdٓC/uTp [ŽLPEmtIpPOYql:q9;8wy&uiL6iI#\$ G֚ח*(}W <fcvz(饨du%ztBlp{IY/iPfwߋ8kQD?\gpB֚b:6Dg&]|?#|7dE6d̐~a(d~K4Pi߬r+m֟B1eVDJfFuNTna cMKK+m )@C88Õ II`;>@k=J~1R![ 5{羟!o4e'im8%Yfw}? 8<:zUxx@{J)X7veq#-g*v 5dfb$c#Fg/[!չ% HkRJ.Ŗ}6:rӳDeOtK49ৈL֕UU* :aT_{sP׻ꮋVa։报67ӽĹUn48۰ ٟFFu@]v 6N 4uWܲTڵ.\||'2ͼO6-BYYG4xP =<9gBЃ2_@dYEg^# $FP|NQʃdәl>d-@ЇY%JqWslD&xµbDܴϛzNy.5<#"9Œ_{Y&'ms=õmaUbfK?b^GHtUtkˍ8Zz Z)l4HO:/"oz^@s(\K8^#gV/&C4'.1Du:M[tyU8([@Z$6q6[x} VQZ*B`MJk+if&Nbu buId !0.z1{*71H.A\}qq'Q-6s kܲ5andͮ>ޮWأF ]bd_޼SnשF57̰Owo}cjg}6n|+{+i_VyxpӤpritn/޸jR a͉;FF2lj ¿l>SXYpr՗Y8 GBVhb?pEq޶D~hմl9B;^Iu O~2 ˌU2%)ft8IM/̒O%;1B=ka$ڤxU)`cOZt$~hGbfW-%ެ65Fz·S!/DtPye/z&` 3h0Q[a#5<=/gd;=hbTyVC?:Y1^EkoMoφ@t2*4M50ɻ2j1{%P2>_mGjR#GWV+M[5^j+ZSfB3 §Wm!jUi/ŝ3u|__Qz꟱_oak5y:Ep3q' d|sL{ !e('oLGݙ=N-Ie͋cswV|~"vk2dG9X`˭a\4oGXu6|"OgQY5S|ofM, x<Q3~:(Iy+^|| @G?"^xZ+9H9[;ElobBbtBei7@;H _ G-Iֳb| 1#ć:aāD4@/6;WAاQpƗOy ҁkӎQ+*4NGtNXl֬f__/zwu'm齒HL%^WWľ>:Ͻl {Z|4o_Yێ\~ih׽CJuJi!v4/p]'` 4'/iebfF$Nv t{{xZ/Q;I[;Pky!th[_Wzo#,l4l[$t.LyO];ZaWL!#"H|4ggyvO&<ӆDZ O3)Eҡcc]|oU,i@B~r ec;Qwٜ)y!klg~'Y~ftJ`.oa q s*&E$|7^4*LDC~{{~=>zvonL+Ct$*QaUzQoŐƚhkWdz B͑AzyM6 R$Q\[>t.{ԖE:eIEzPG92a;|=GulL'YWY4 zlW)Bf1Gs\Tm5r YE=\L(bSOBK!YUl cF8/B)/MFHߡI3|~eeA~+BbaYJ~а3fּ+zp.sEv̌ ٪JcA']tevI^"ScؚcS8ׂ)4Cds~+'ӓ9t#~wdx\6#S7윣}x*i T8Y98::2/)p~ݱ/Ƈs4GVDVX%MӮ@NwZw2`co\m04[fbn^:h8S]Fc\am60+~oEYX:"|y)*,9A]%uښ`~Ir$!ȶ" qrE*;~l0]56"ʭ~Jkx&䴅/q^D2ŝ Uy)ؿhv:c ~GV7͠!7/ CRO5z J oΒ->1bb: ɥ! |/s _yۑ%m~_p wz^m4\7kY 8Bl{1ߴȮBU̒ WPig'ǧg,Nfb+X%uGeBgtmՠv%ük];nUtaO0[O&>"U_tJ{Q=G3*zUiS^փ.IPzTy@$o<07uC%mw8j Yi3>.t ATBH!hRrk t9(ի -Pǧ})Rȃb /ALl!0bT'τޓ{#+^LD?vvaӃ]kD19FFw )?̆Ҿ0{u{@"# (^ԨhY]&qkL^`'?BMN_dW= Ꭰ`iih;fNR  ط45"cMn̡wAy}&&kƅ}IŽ % oL[A F84iED_97LN@v g S 9DaP2*}Qp$R3qПӦ$6K6'ZJpԦՈ>ÊLu""L+\v}3V So EP6i#l~~Ii-ˁPhl͙XcI'y÷ Ě5q/0'^˩/1cON|.+?yi&4~jszp@6QD$yeJuYLf)넵Zl2UC^l7$ʑ4O)%*csy!@Ѻ;m,pV$s䯈ovok...&HgL/PRAҜt ;Yku1tyIAsuBY3dk#C$fsvh< H-DAR`ra#?4\-08m]6GaP؝ {o ɱM,*bayŹLehJAQwP,+$ !+,X2ap1 , `Rҵ9Fq7Nwq#]PϟG=|Mw"ytft@3\-ן)kBx7#D8p%<6]hyIYK-q* b0J 1U3". W8UWk.s)1t77v(|!OٸpQ{/A[TWecE^ k wcd3]vuCNW}WyU HHASVD @RȆLsN9q25;7 ~s#iCɥJpE5N#11!9Hy&8~ַ!y5ws4j7ӪWaJsԢ#dٟԉzyF}<:_$/y+ `A0ˆ ;ˉ#>l<EFOwͦOJ`_Hu?] y[P9·9{3&dLSq@hA&z'l5UVS f3 NWIw n3'9mtBr=jycهiYb }3usO!),Y &NgC8%Q 2|WNFGի|Z)<:Pa9~ᇃo+"2P#}>l4(88zxzU:\nuo1׮0K[x/fZfy3#'7!5'N|Ҹpiפx7߬§uwN׺5w/ۻ Lpf_f KxGHAS8 W޿~7>sn#p8dU7eB2v㿔vfͿL~Q开4H?wsy,nV갪~`B[~uU_sor+j{jV IN&tȱk5޳(NՍu#*{P`lx 0e{my\b1;,go1֧~*>kqv3W?gu,r/)+| ZۆkWԔP8Y6qzv\ c }ĉr.[';4!dqG#^p5Ef 8[͘~$a>sfl|ZW}? #"E3EgDȨI%^3NSRAڒf63H&R 47XFɄ.h֕/Ǡz0}/V*QC>pr-,-56B)jY\uu~u.+^ܣ}eVkdj(_!3gle%> fdjLWIUe /)%_e͈&^\k/:T؇%m4s4Z/ a5)F6/q|&m ?mU$hb3T֑"V'|SRq5vӋq1,%߈TYp*Բq'hw%3I6?ZDDK_ 0D=Ý` z1W0a2Qf}-~GkRw쟄\NC !IG$U rEIhT)*Lز>+PŸ_aNH|lQ7(YKpDhr Vkg,PHwaL=dɜ˘5V⃠.tARvae;ba% ;HU_HK[iFNl槜C WYL~g@(+h1>2B I@wLyָPTM㦇 5z^2A&Ȕ NVX3Trϋ/ ]\$s^+k‡axZbEdOg!2N5 _) !1/#w7xzD=  b[S.qV:|@>D[7m\ ןjKBKš/ Az%Y:JCu*+X`0$:f~ʍXgS͝ov{{{G==<5#Iܜ.jl3Y "08t< PII*k2l!waQNӏG5L,0G9yBNjCK@E[3GQ*5cf"c&G.MRN5w *ݏhާT<6Xmq[v>]ۧ-F+n6ƗФ&SVDKTWCrkav88"G].Xp(.-3 .=&3Q9#Zt+7{hRiAzEBW@dH6`Qt|Z*Q`+8 2 GHOb!l#;m%7NA^狓NUܔmw0OR_?ǣ3R*Gy[rIh1ס)or|Λ!Q8D̖)"1 oL4qOb"_=x-_"8i1|ʙ(; 흃dPv3A9~E[& l3Zc?iS ;oil07O$"GJ_>]wX.$vWx(P,a E6 bo&RgQ]kVL/:I"v*'c[+@G}^LKY0F${SZ5lxzn#7eDDcxqoo{{YhE Asb8Ƀ/~A~lGwX[[{I?{JmgO?Y{m=y$kq?SsfMWJm?Y{Lb'ӭbt=/&rFl9<4d)9FX>\5/O&Kf-.[Y/ʺJq6;s(}@ؓ*S8VE |JDR $}d=Gڪ!YF8cq|~WIzR[^37je/|K^Phҡa;YڰRJV#1oM;Xzktkytov`FuvuRg66QL3Szo'Jl{wwmu)P&;#4Omfz(杖tļ%RxiF`,@?W'7b{=/$Tl7swi:~g"Y@s 5_17Ӣ?5?#ֿ%TUN8ҀaD3,O)T"O=[QYG.llfS wP,4A.0' Npęq@ZsŢl" JA:bSp!*' \+XK (qLpUȫo Ө'e68KJ~oΕgЗDovFȫ+=Q/.bSռ t^~,Zv Cr;-ԣZ6wZ`@oX̲wmUjj#M*>qq>¦ ;y?$tgӁ27Ԣz>[\F$Ea!|LE(٬ީ`EА m\Bc~q&e,0WD?JL\ClI[6 Y~ɿZBr#FcvWaӟDs{b> bR,//͎l0]4B٢xvvr4{C#* &s֟pTmeRRHTu{32DL9N!g_X\]%7d]+SNOK_+X!Y99߬-P%Ө=K~Rr-7/gW?3?&Ix{3cǡO?>Ͻǽǽ/!?_t>->qwׄ 5(e'JrAp<̗_1w|4G=/}"t>7DdvZ?us5.9O ko|Sӕֺ rJDaH:}cpm7W&jX'rpRe\anuWl$hKN$nVԬKkfśf&٫:/1$`vmp| B@MmSX 2O/0%z@ Mq r J))<ꏝ ŅeP] t4`<),(]7(O7BLSفKili Dl" TJW5X\O&[x!s`֥Q A5{ 5rygՂIF~ d?减4䌠@ykoaŶ >) TY# O&L_ҭkp WCv`31Gh dLzR`>% %@X0"] xCӗ̵y/YgQY nI4l!3+o]5;:^-w'^/JGNH#9W"4`ަ k(͛a|LC@?&${y!T5z5fǜp||œnl)`ZːȚ!&jyF!0wa&Mt9OFc@T;dBж٣|RQPDtT%*[pb]!9iQWиfglJ>d哖0ӏHV˛꘰q"4D6g (.(AVkJ`pJ;iBF$Vϰra l!&NNu"MZjӣ5 B"f 0&I,SYJՉy$H9**Ɓlx#!laNAd+x#/s1r@"߭-4ijÆxe[( #$TakH2yZ3Ֆe<$J̟ }j`H_#⚷*l|BNJ ڹ4r9nbͬKxSWFDuSn}z. knNhD454(5oFQ^|'UupfppM"xsypeRʷ_\PzO\VYفdjYhOXvKC vՕQ9ʐ)f\y0a0>{t8`ωt'U V2Ǯ8z%fYcG t eEY#]G:| OO ]i(*3n`+dKe>0W7d2`~FʈAq^&W%*rn 20&C !bK E0e]xr:rDYDi18]y@TjO;bd2?S=N' /G(ٿ*lK$ecAt>I"j+T) FD2IF"%H$ǣq*AGU@ וdҠϳOF*>C )A296V=hw2Neʛ2 //2 q 07sw%A&xTQ$ Qʅ.\sNpϽZ:>4;rfroV{''w*@F#.WX }JV̰0y-R;OYxDLd1=rړH4ϒv=LSZ!ż0OIʒEAP戢.b*%%Ȕ7WF$bڑE pYxhepsV\3kإ݈2Ef D0IUXǢ%)% ̦::~_[:,`;|)K:+_RCd% @$вf[ [ { WJRL ud\: Ŀf?3j>$A2Enˬ ֨Zw.s7tEE8L@6,P]en]Kg懤QIH9 czC]C}k$l* =ZX"hIsbv/^\[x"ԈpG.T񛃝6 *tXݯ&\x |i596߉T>b'̹VyݓUYaU7j {0h"Յ>4 Tx-$4FLȹ 2CG9Ɉ\*`I⬈lDoo\P _r 2PAGE3/Aa_\&HMcڰryHטyY!{?p;M3b$\Z3>gAE0n<3зyttmͅ eu\ɍfOZJ&}抮U:7J[ş)mn?ZiOkm[Z\hG:i|%ʯ8!{̿u7R5$jR!/ xMpMjoEx P NYw&49φo#X ls0Ո. }zsC0"zB40|YcT$@ n_+A .E閊cbʾN@jŶ\7-l|[öd`dU#DfљD w[8ԝ(ȧZΥEϱ+zi[, P'xS2+Z+g+ 6w. ,Ìw)S-f.S.6#@3QCn6W?Aa8Q/$D 1>|0eV㨦 Jn9es5O|H3<ߘHz#?ˊfo=™jhJpfO䮉"*p<bb 3L |[k2 .[ pqA;-l-06(R%/3&r15:eFĺ3G e8$JXtH 3 )ے}p'-ISD# AF}R9Ð> r.]EP^x!S,\A-{rn_&z:7$j?PZ*٫-~W}L,+tͮ 56)*s] %_]=Vw$+P V YZeAJ^GeCy=u@B J0V)t(¤l֡ ;XOJ1ZR_\>/3P5k {{ID\_cԥɟ={ n1?kNx?%k_<_{eԐb[ћ2ft?skJMN][\֚synڶ̝ӳ_G"V|@7XtSdfRtͿ쭁PVfp"]|ŀ΄$n!ɸ׉ ի赗 Vk;'KdJd~hqD,%v_xH?#MO! 0 "<=xޔvUJ}҇Œ{E7dKswM dp7&m8*r^K&NcE=} _+%3=(fRB&ɦJgԲ)͡3ܴ&jspw{ 3x,u*}ŏ 镏|S=3CX?鑧ۈv.LPIgbZP3xf7ua:qt|Uulaf=ƒ+W>&4Éqxtc yz*,U]Dtt-jW-wi)rKwĠo (.y~j3WL?KWlg\fs<\29|L~xbd*d2|A|W>f`tNE:4.*&^ jݨ58ɬFclb"2!E~MP`,UrE^X4^i-׎kQTG.ȟcҢV'J2MmFaٗY:,ƍ).^f:$" SgSЪ4=C%ER ;?C j X,rxRc*em9j%Z=Jdji%PNbn Od "S[nR"D3+8Ί !af,gpW VV: [m/&AיTȽRB:QtyS ?SCv/u ap:fS..'RA>CKjIwi8~+הXDN%r~jRAҕ7VUbA*QI6Y>}3;tN6ZNKs_Ll ,CXt..bmz^8#ԏoY{{{`g!TY`[ 2e1kX2FwBKÇֿҮ"תgcT,éXyCѢHrb}#bvc۔|!#He&ZM/Бӛ#[{5 1o>f88q3|Y ;#oϫ>i6@p|whC݇Q6CC*$`/~p` 2}8d{|Ajl X7G;[Yо[*Dpv Jαq]C$sCq KPňtQFX޾)wOWC%/ $aJ ǰӾ+AqNJ_&/~u~OpOUb+ݿ!kHu"ݿwOoKsM <=5(6Ucǰy>h ۼ[l5P!l*~drA7#XvW"6r;|>Ϯ*O#_%;H^5PB đw1mWM F64V6WÖv#_Z!'dy L$0żNshNNMΊK0Iq!&Z6v7^=$İJqNڈ";\yoCp[,lqfڥTZ4Ih RLW{qfI/~^4.PIG[\A^5K~ӡ%O#W0,5:]Ii]v^pS?j+t<]xD*=LZFҾ7؅@ԧF>X1%9ԹOEovCUwl_oz7Z!t,0,Q\:CgC%Uka6T0S։8xvx@Cv[}.:;vo= vqu.gccpն= D+ՊQ16N&ĕ́;c~A%CO8HײAY_bf(-P[ eer;.̘.7qn6Z WR p//;|<RF ܻa~ Jsx{b)'Ɣ(4e&߫?Y8nsW&BDoeCR,~rif&~3󟰫"O7a~c;c̛bxOp2TM_?ُ qVPlPf$zCg@:tgŎ ^m to.B2׽S6Tg($dNwYN/lyB$XפpzDJ&+ K[]FFu֩bO~jX6D/ήjiz\2 ~Қ?K'ev: JJͽr"CGu/;]j^;/4S%dgfl`p5gE U>JJB%Q F /[ϟ9 &dsѹ gԓERHꬄO>DgaN^m5ġM 3T!NZH݅/$,ڶZt s_.BbPeEaw'U4u*5K;\&I2Ee& ͠V '6а DAyWE}YJYG:tI28(itБbYdl1:ՃiΝ:&Cl)[v{m-P+KCKM[-~%zL~SSXV7PsOO(:zxt֪͜ɵq ;9k %yw\u.FKFcav'e tѺµ}m/ <}>L§O?CtMfL{G `8891n3F'Ejp#*-lH*TkMUc9@,zSnF#喔+1SbJSYMGؚ,$7v O'~mG͝+r,Oߌ"BKOj1iJ FL U}7WbIJ+bBj9#/)#^CّOIhh+ /HĂ/Ė81kx;diYI63mTt_HʸYL XUq: ^DR6kt9Q-NH+ʕ`=ͦ|{[)\#|gDb;/Om/mR,{j{jyj83[ymUÊVI^vWt}15%_=L`YhV.přD%8Ά/d&"c1 ~]~X2AU$C>5l*|~THs%y`ȬnpUhÛ)bKx+- v J͢#qu&KQOz-aVb>|0:2ԸĆsЯs|SZS?̻/m@.^t:=V>B|6¿E$ɵOYl g(6r@J۹f6:IÐ7DvUmhnUZ>qMmyhˌeaуlj0{:<$Dk78kdn)n>( 3aEuAVV與UpqWIZʊVY3 gp# +Kv*{:0otͫ zE+)StArBh򉼊uaO+2xXlJjfnVrED8 G]]7M!SyWsiw'Cļ_ĊDꞙ9^R_W:\q8,98NO~ʼnkOD?}fQY7FdϞb{ߧik5/aig}LNI(y;|䙟Akyܼt䆞:}"fJxowfib3b?Zs4j͉ҁ+)m;ńqc!)l9_t!A'#qft\&W8啘H )yI -)tu)R֕ȆZ" (_'F-yʲ3/0ĭ1VQ50:{>[ɬϰ:_e挤.h7?L:R )rk.d^Y. =XM>_M>[MoP_x?Pl&W䨉>xTW#0zoЍRIXvy {ޗ^kx>iHt=q:zfeeSQ K?ń*f8}fdr05 |琶Y #{^r4{D4e͎9kou5~Z;W[LUs/e$ GЉXSi'NSyCgXIEfFV;+"a7&pƒrҥIWF.Q.]!nd5{eʖm Rܘ;ɟQaO+b#} ]@'GijU'xXf NfbGFGfө;7 DM%0wCn7ٳë\} J=o?lkZPZd Y[#9rq_s͋} [>I"(_nŷT{]_߼5lz:**%D$|;wu& }Ca_G AJ;åOF.^p6Fmq'<㣃=A> )7a;k'Ȼo;TU6Ma?J@e9y9'cBML`CEgR*v+,B?.3Q9QͧcWC8Hka&t#D ]=5 X*_CRiģJcS5GG}6 ow>Sfw4~tjyvI~;q}oI}ZơV:D٩:p8NР(|ZN1C+&%D@66OkθwٵEi80bx_z~< 6DHwcs dd1HmhizdmIj>Np&PC}[mboW/VKi۩!|DO=U9=6c/wẃoߧcdBֺ*&هI j[_ѡ@}A#)وLWdFf=JͫuxƿUtr"u] :ZVdb<؟e zAFZIV į%i^\+,2Z4G:;"`,oɕI{ըJ ;;q )lWޙ7$USV %8#hYJf{|{_=o$S3X}+!ωW0QϰhO_TK;G |FN]izԳoc;#iO]x>;<\僾 C/sV)2)1]V>/2~E j薲Aeq6ˆg%P8\%]7CT帚L2Hx!\<-rfm`PenQmU@p4l=5bb TZUjŨ DTG&w\bZ~~߾7K 99 @=Ԓ.sw+Y6wOkpb{3"$1%1Oj w%n0)?F.nMv@OcAi8>O۱N]`2c@/V`^Ĵ)ƊǺ<6 i<9&zstȈ]boWX^@n y0ɛsl@8 B,jln j\1S:]hy}p|89]K|\T$D0Ifn_3OʘJڗ<= ! ! }CjXc#D$7~$S k;2nSfoO.T3ٿ4rc 1n$zdT2 *mwێᓀF`lt^sP[EWvi TA6!lva78>Ycqj쮲iYȚ_UT whdPpƄvraachJ86#pa ,w])P&v9 |.?;#m 7|׎BXZxgQr#'ۊ+,XY,"(=B eXA)avsV2E R>KY+i46vdu׶g]ȖÝX T|w]ˢeܹ%d%PW>ƨ %>9nԬ]4w^xA*9`f$s:YN`'/F4e]21&~mVyqo]وܘѮ*e4j6$ ! H=E)J͟X?6m ^4KxkwPl3fPg54Bi|{6X-&ii ƙOx @޷]^{yO?LBۺz}xEx 'Ͽ\=~x+ܠm3'GfqדƷO%K ?PQY**];#@nq}T|ߒmP̷y5P)tذoKغ(] ;ۨZU٦yP\ .m=m%+FgK!@y6$VJeQL)bYޚZqCaKMˎs`T_\y뤴 s_v?8Cx\olA>˽w/ũlЂ@}Ab__Zĸˊ Ǐ8oEJ#4^pr[w(fn\#<+MvЅ/:5[2T$qI,)$UjаW&7t?8WU4ti-SZ0Ľ(S[ú2c(Fz2γ3"2t2CWohw;Vzcl#$kM5zcվ}oG5hrVDZoZj:c|gM3;jmy}uc:f6^61æʟ7T۟ շv{$%|xuoT=B冺Q ֿfzLMi% tY7F>mt5J@/Ēo( ecf_rwh6=Q2"M_G574dzxypXL%W?>Vv#m%#ԡQ`QJzyx;Qb"7^K(5gz?Fi8ҏ_R_(!<6k#v5TґQ*~ͬ5}%#AȈkm,(-:QJi?易`l\qkg^s}j{L<^@_`w=~%/bv~m$s|]׳P] /M;3h]Ba .r@Z;;+3x'!(I6^ZA$07mabǜo##q b\ l' \kk{pm1:QQz:q9xٺUzuZ3rXdgѲ'2?ܯ/M)㠺&a5|tNyGu81k+mNBm#4RHcbs9g N\7O@kl\B`#rpq"]G ?fh@46 >OQ)%QzK(M>" ]kў'u$+OEk}yz/UBoʩ/SBd'U)_|\>؆jZk\ƆSTX4/^ n@_E vHr41GF롄 pۛޮ1¡ :RߤwM漏U7'L)M&=i '܀^K{cWJmuXJ,9ijMҌEp%xդ t.-⵴0unc+ٝgx (L$6JvZ:fdM[4 {~':mxDŽ0W.X9"ST 7χD|%n?tIlg^2y 3Q |Pp;;,@S[ٞN׫~f/y\~'OӠ^ssXH'bæ|˵6hnva+!|zM?nSH#;jDc=tH}"٩à 9¼\^TSW'6Lm.C7EMoKݣj75h%]J]=}Zo|恎{MdGnZ6gy6ؖN;oD6Kq 5e/Ɣ:níD#B/$6CכjXvLIٰg8fG t?(6㒎iF/ W;[y0=z0!A%jm%|;mj7|Rg0PՅ_RX<>OV ^BmVBV|S/|ے,$G|I8XO-y]ihTd ppQ,`;=23gF) ^^lF`^z}Y2novv:Jf5iIs5!Ic,Zwp21LLYel/"Kj){/1)| }g)  #Gr f6ҼeN8#). G!76h?Q\8EJXsekN}T0#M SbdxYĚd9YZ2BҒ%ڇW-n+4Q~q [874qIl%aL[T,L2,br4T3 ҽZ بߋ| 9t}R >*,esF%)GL1=yݏYv_'\j4>IWfS b茸M= ǒٶ 6xkN#>$Cy_u|׌WuWHk-cW`UQQQzZ"ؓ<7jW'xcD0>-xS"v&BȼR،S?k'aF=u_z2)`|6H-Tx-ǒΒljnYy8YK3{YǬxHpX$I,t@k]Дq BnK"kZ[s!ऍ dلꄅEDaUA HRK̉xX9MF٠U$|BD<qe&rD@GxBik=#_9U8R_1`/H36lnTL50'WWٰ//"_3Rc*6k6+fMhO~8ɕSjj\{M5I9?càjm`gP5Bvm-PzB¹]~OYsKJvk9C87Ed!AM^CKF"d!"R^֣Gh%98 EUUi3Hɔ8]G٢UMu.Y5Y$^osVk]Wq#p;P l"e<`'F8clM1_[U\0硬mUmL_SQإu9ƭR)@~ ,}$=}\"/jEiE*'tD4[A`MإlBʋ_\t.d*č̐df} eCȐq4<5`:dfnS$7OhjBݨZytJ\P],j%u5<hVZMDNROL^8"Y³.N]M;i:7%ռN5;H2 -#yeD&diY{: B FXe@3Red$ɼW;=6)eg'sZ{@gtmFa&iDL13q"qTp%*SJw(pw4%3u*Ys$db(nU zb}mExx.jϢ, 6}g9quP5!B]=D@_p9+vb95A*CfГ-dx]T*/` !9%.Ǥ?,̋c4tqf_73]vVڻ|cVe'ir}seb oHGג/n|xSDݿW<}[y.->h2*WxYN:67#Ԥ0?Nľl|WkK\(umMeWr{?3߾miok>6BByfVדUŇ_R|?n iͯ b:f @~b'}NO9@=/#>PiX7 i>CQs"]IJD{[>ea 6|lEd9Sl YTJ.l槆y^8Ѝ4$',s Hu29x (}AQK36K@:jRNL*9J#l\P݋C]╲kI{AijfmxW(PJ+P)] 2<6WsU1v:e6Oyuhtb7IvJrMSg:|7,s]{ ͖0#qMcǏO$fS =Lx/U&16ƂL4Y{ƓY܊ 7+$HRIl5TPPvI{cLgff' 9cErWi);E'"l`YFy>*U31Klq12|il}ou`c0M aokWdțAq*{#\ȟZ~^2;D`3cťa-(`).}vV-}נu:ώjH-sLJ'B# -c4gmw5ED$ ]M;I dru1vLǢt/ocp܏<oGmN2qJ?]z7p5l}9~3 a NCcuW9ʸv^bw4xs<8Ii>0Ұ?iggGf= Fg)GnlTL-Wfi{ظc\'& IzO[^@~5C0F 'e16SKɪ5~xCM!?L'R<_9J,hJ-c3$d=`ԉt c3Q1싡nnōt+R4*@:V7 n95T<;sS3Oq-qd%nÉBU:Uwl0l=C~ZC]-A`Hs*:Ƭ\Q /kUG3D78Q Ht`15B[Aan<#Xw;K6#6U+y\GeW,hgpd_!x,:@Z5u6L5:ì\ Fin CN_aNhϫ4s1ʁ,S.[9t×`vQLü;)|7mBu%h2B몃lk kKǃ:kuXbql3lO6hϪ??-?wt?w\]>`G0g}@ t~E,gy64*F=zڇ-:8i"\Q4Ǜo1SJo5e=Puv4?oO6侹)tEzT:5SMvmhioLYZ8%qCyذ hvW$jH?t@6m6މ)ވHF ?XCڏ' om)yrFM=FbS(t`C7GV c8(;Ѕ!B<76.yRB&@0lj/{=4^i|-Du^zi.>;h>K#\N/Z/'w5je㎭S+kqJ w 䤡3[Rt'/+;o31㽑gXOcEE~0?akR6$/`e@ytަg"< ڰ׿sDn',kÜŋzb&6ou:fb%t6ַ33l04E7UMǚn1*=v=cez[[Γ s"}XKxvhe$Nmxx:۝7xY[U~i|34C}Sfa {i0I]̵ܨbҥa>AG"M#'h M57QﰳTo??|ye?//!d Y($a%-<={bP>ˏ/\{,!:E+gfl8q>2R&=)LvUO ΃.C5b,̔Sk@p-sTq^ᚇz!\GjT:ڭͣ?{Տ+[rc%|zzZ0jm ik`Hv쉻X0-+e}Yw~zRW㝽ȷͪevME9|C3Z|;&am|Lo#(e0H69xȌj@6/͝h°.cD^6\AKكGqş=VhP-0lxdHכTGH_˛SoȤaKͭoj#iWG]۷R#BRj^\ɑSѼbh^ '5WrjUܪy R vZeLZy ևѼLo_i^nXDj[yT-޼ևh^WjśZUKtǫkʜRHkmk2#HgAXOu}EO x)j"-xV% :68>!F% 0uKR#C 2eO~'7jI/hc{Փhu_򕉲0<ϥ"hfwU@3?Ϟ>=]|_w|{L ?'[m߾}S[1? ͆2;ƶ!*ԏIB.Nf22C{&ۏ8|E œ3 [#\a *b!w~A.310/;k&ӿj$8=2dN}p7K#"fe AMsPfr@$F0rb7KE{J%3Q9\Q grW8-`-<0fo>zo)^t"Dh*oRBaS~_їe~^yx?8>b~{j/'}\5:p0}@V28|рr_V\Pt,a~t+ 4pp`Me@8M˭)ujT@.(N]zQ ^pzDž@` "A=<LᛷG0[xoʖt9~d\`)\QRI_5kI\b*rO(0F) nA mъ~7Dx?3L^I\6X'zC7c%{}ŵY|_'i*W{S3/2Ʋ B_EnM̸Coa>7f>{)~>k]|?ͮqTh:> ೏>zc?>xlB9>oݛMWdR]9-,G~q ۶yMosa F)Qп'ǜ|tL?FL'ŘTfS?b(~w P0y#m\;i]$; ոLK(~j`M>8ak:ʨ"_{#'{ IJ9:R&C*=5 =א;J5b20%-K@7r*'e8SOc/g;~ZpIPߌop6'"n'݅eN~߾4_8x;4tM@z#_utMoww9n;;y;<2?B 2,tp*YI;{Gב7?L}-y>ফs 3?݄wƌϟ?}6wso}vsa=JBܦz:;!J/'Dq9]RWԡ$O/9}8 x+љ?:M(|l-IZIཚ㣴d&0\k`$N3*)yW!eS{yz^{O:QrF?hsHg<>v5lBvQ ssסZCF}?Wm}M0\|GEv.1E$peE,sr2z\SP+}?yGDzJH–|E0$}7Z .eJ$I: _낼A'󖯾Z5|x=)X!b85GO@yM$Aj^&8N19fiidW0NR<^(J7ٿ˔)0*]>]!?"$J+( T|N H=Jddke`(]~o[oZ̓f`{:jTU\^vazbܶLsLH2GA\S}qӫ 9ҽ]-uLpSTo}qك|Ѓ43MͿRVEO ,.%A`PdoP87pzybL=+I|zG(n)2a$!ξ^8h67puSCd7[F9[tÄb{\@>D=VUuvh*M2ʍYlg@gu:ؠ~&r3s$M_ %?l36E3}枉nNB#+*odd7r[>y69sgnm]k;cq_# 0݈5~?QC0Vo9K'2քo2;Mؙc;`:sM-y3LfOf/3|#TNt6mw|gމnMxlo>0YMOU`e ?;xx<)f{Ǝvhf1KwE(ˤkϧe>BKnCVtWV#@P\/,9'Hޜ7;nMjO sϒZG$pZtz- 5:R-3L rPc=6_juȧDU)Hd1bKNDIb *i-ϳ!|T2vLr0r^*JG&Ӭ]-Es8^\C P\00-9R/lUlXse8@>r$E1PL 0O0ZC)Ϧծ'eî:vAislVA]صwӜHG簟%Kl2:%IXG2E/ w=dZ=㻶;c1,/HQ{G+' y5R1?}Wzyy49Qjs KX~/#Gb;lf$\"f`Ǿ,gkO>O 0W_4yJ8/(m'Gx-GE,'Ah72ݠ}Ch0I="/|T_,3H0ة<.H `SC'zxaߓ}"y^ 00OB9~qf;G^PL0Wx\ =T!lX@bBYpa zc4$֬4`? 顲bu H8vChK|>UQHNphKcgW>O$R=OʪʸZ꠷#"K s$|d~|MÌ Hvqդ' ID%FSL~[  gj?gZ-/9gavΣFa 'lipO9èx47oi%mAXu׶t+lWY=!:O;F]`NP:zv,@I U3cOvJx#iUyr rg!ql"%& c6 .06 R$s1M oq\"a$gatt$eGVu`T9j9FA< {@If4F!m)PX}!!Ø5C}Z6d12l֞pBtm)eo7U[{k}VxBdW)}8bYH ʛX”qbn$?T{*}) 2 dw "^^=Hq>o)=}ԉdI$N麚,E/dӏ˚wΖ[/SE*zlq;%~נ[ N!e6V—xNmD zň0_ւ@<ߒ^3+H}sʵuS{G5i`ѐf|>s"w|(<% f,gЩ-N3F5]27?J?Lه"U PŜO(Ij!FfB&vk )6#+3jɢ.#{p;dQO;_7!JK;tJ/މv-璿0vk*fwN6{ʼn 5/$fЫl3]T4)X{#\f޻ r)eCP% ^cɁ\&9Wj21L)2G-ZG$Sp҅ea%2VD+0?-ʤ9Ie\";&r^4oo#*\QC,pjnB\kBM)|H0$Iq*N!$^Z,/bx(ɮ)$*c.Kn&U^oB(h-0S=;͸Pl)ϻCaf\5rKe0+$ZI:f`lȆ@B~ ^aUk]#H6$01VQ1@FD[$r#|?A~a9$%B`әI<6^_`xFU;ne6QИx킛f Z5إU(+>0"dr a]wKt9B>)9U*ijX9$*C+ޙ_:򡯢+ªi@&v!V?TJ^Bhߊ+q\􏾏 5k >YvpWsaP?${ qP?YC|ȧ61@DHǕFh%GljUM.yD9or 9lngs-2m.sN-e6?\fk[]O4k{nRՠkGhcoh2/w3k;CG໼f7;YOzmARtp^c4g%p[6ܤv y@D.u_wW濯Սݝ|٫Ɪ?:~FE#&6;<80*+' ɮV&<'`PC&(w%a5Gu:z_ ]5T?o?0Ng#^`{{lv:%4=Yѽ9XbX;Yo)i -%q}Ep؀T+ykoYO{{G`>di{M[i/z\̶>."nu)Ĉ4Zܰ99u XZցkz K/>1s֯|hX8;2kv۽:k m*lse8=Sbbv10.0}^|iTԡc=&R>F5'RH1TƦ^zp$ۑ-u虑u:!o٘n&`W8ͳ[_}J JHIa*,ˈ*BA&x#bLω9Dz^"p3Vˮjz1BîMܶP҆t2qJ J^gVDUhօ^7L@ͦm"3?nIb~DX ?d~bjN~aswwW;GҴaEYt++r-w,LwXs.O-]7dL1BTԇ辝wiɿ(}ʏ_Ԋ\O56V/\乵+ּ_>`5Yb7iArG\ũzE |Z\ZޚqF.= !`d%H'14ɗFd$(ޙX`r::>6 W''c5EWbGKAs7jkx}c#/G9;g/g^(nZ<:|x!p^]+}3*Ĉg% ~1нFiE5Ru`h)d2˒kŬj+%ڷ5l;Ċp])P$.# -]ťy ˉ-(˅0fOIK"#uX4?KK9DO}( ֦B#B׌/Ba@8,?M ^[]Lٶ ,f]@%.ABRR k2fedr5 ,b(I>}S $b 09o/Ub͏  L:hmnl2M;Q@aչW*FFLy`͜1QmD8W.& ^C=/ ԲrJy7Y> 4PѿØb[iDgNw5Ou@i'ݠ]I&e+(ɏ3R= '8qX ìP=AP@S7_<R+s_ȥ `Lhs/}1taO:yrB?/^,L>BOr b z Y&#Ҁ~\wL(Vl: !vhayPU8: }յ%qHtf{MT  y9LdW;KwB0Vo@4ѹuh5M8 Sd2ݐc qX!cRgDž02Sa!V8gNKls{T|rOs,"TyNǝf wv{3 AYZW>Nص'1Cv4u5J1fjËf|:eN1'8ĝܬ*JM[jUpJ)pw@bKUM%_5 ă.%BWt]'5-C9/tj»z66I/2C\d7 o:eTK\h2gV#Ai!2a fRa^yE2If^t{?eu#U +9+jgS "(sUBx횡݄?eQy/V.ܲzIIm83olrj:{=%lyD]lTc[/r˲&Fcl\= RJ4XEp" WYw ͇D;%PM]#2Lau#ة*kod 5&=N% Zp̾ SIQ$eJuf5liFŬUve9@ŕ:3ñ`dz.('&:"jH J1jUJE#By:̮JDJ( &&L7A(.}<q3,g]rζYU#. 9#S6`x!ݏ(5ٙagE*$yH'faBcXL/N.\h):Q:Qf[@1 t?N[Ǎ" FnO .rD iJ)T;ߋ3GoADw܉nlqa?`n -fd/$ѥMㅲ6)'ה2?o *t0bSd#){;gboADt^OlAX)otigj#7ؤ R 6"H٥ bcjf<| C߅}0>pIc Yo*!ycìi>I>& ܱ*Fv1YRn6Ī흑ch?UQrtA-, 9ݤfya"9wh>%t2cٸQEzh j۴ls1|:Y4[[:5,] Oo[QV$Ó @'~ "CI׮AW5>Ak;ntWjEv}z(̒0"e*"9Gt}:.Zu?o Uo5W-b hJ-77RF:(b<.sa\/-unn 9Mzsg5rXbbBPwDRU {8-~k~ /o[9KpmwZ Od?ıX٩養[\ctWlP5DM4 dioΪ)(XWo;j~R )q:k1L$ӂ w">V'Dm[#PH[ ɺ"A\IQV.[;HnQ#`k+kZbұWܾf]D.#Qrs@jQ'FB3\ršRP IϡD,oA/VYEOްtb/fogc|^FKyQNRN7iOVz{_#DC4bP)2[JT"Å5!}JZEJy͎#tHs9Z(GE+@gFǩS"8fA8U˛X/ !^^^:u+DCHr۝5 |-פȪAGl̛VF[ P!joMA0r]%"Fwַj g^APS1@$7h8yFtC(M8 zD`;9ߩRCjClgmYޯ%q9b!l_Ϧ muU/?/O8XvaYR)'1?̡vGŭēb<&jD&YFkq-G!/N<0⣺4-3vcؿVIS_z;O8{bL |9ħF #G\2cN&DIߚs:i,{'ΐ(Z_zԔrn|<sud-EvFmT7'^,<8D(=, zv~mcG|~̄CZ{hoKCR3WD2$e%7bnZN:з*E@X!ly$Vy`ɍ3ۧv uZ?}h Zǭ1DT`SV6Цt9/F+e' hc47.d*6Q#N$".w=qmYE] 0j iV("l}MMQ O$B=ޝBd1|v-(V&T.J1 {dtn&(w*{#NݣmP-Ch(0{g(Lz[-i5kxx6eug][DB<|zb{m0ezG !}fXi2g@6-IpoX9Ⱥx2ڱ][ȨװbEO/6Wn֢l`fᧈlgT+7)M{<'S4Kɥ(ʇvj)hRM#wf'P(N"#I*:7yp\.Aj-@]ON+_gԒI#Ǯc龜A+T(߈`%g*:P{ 5G: )!cV4*RRl< םJH'!lu%! vJX~x6zrI|VwR}c;;;!ߘ޳`w݃gg W|¿U(6W?GG_/ˏYy<7Kْ0<4)f)^Nrl> h˗/}d]!I6ͨ=!ZLcIn94)pe&xjR -.`=lQ1M8#rpF id$VKx|&PO ׆F}z5G![<6q}; La|uqهߏfuL1sl1y{M[=ֻf8tMh49:9;nwQoV=li?9m: tAO 迧`LoZIRCAvve4@nj*'qn?~zg'^;igh#T6 o@nAޝߵ:v ۃg}vE_bhKmB3N4Np僁[BVMߚ6VqA!8j=zŷn;OwW/_./A0 58t4儣 ѲBYҜΐ2tQAqF|Oj'堭#痭.@N9HC &S64EV)Øy |W8ŷA4zL !9O:`-}, L:\D*+V(4I4c)0Ą!;Lg|?]j|{ ؎Z +(m*0Dγ#}#qzSԻG)B~͠N"LզlJ٣o>sbbHdF6Lk@;'TGU!oi>]z1w0#䐠TᙏQnrW bK C32J$dTW䀫zXg0`x:eVXP"48 Vxnz >eh+fs#*2' E<*e`[B9i"pl%B9q'WP/]c%oÍd*cra<1bsGێWo쥒0t~&cyNlԘpDkSs#n@\$uB1aZ1s!B85rp =}I2Efcm?9&L5EwlL ?PoLcB>wCLl&e`nw T)}nsT$DZ1ƹ 7AÈY.#J4yKE */khm=/,+T́ !sЍìĘV\ dUL.?D#LY ̩`OvP6cjX<8ͻy.D)&k`'>/M*l`vFfu0Ԃ6Qt/QmሌL4Dz4P֑q+ZHvao6KXV H՗`9\0Tu7še :ۓ 5#3sJ%>3hY$ Q<*(3 xS}!|Y9KI5UESc9a[Q'|JaYHDM'9WBzMI%uK%|YQ;00()-CK3[[`UЯc QBeƘv;kFt]hs͂f05(\ $*"S.hQW]*|2эj1*k.ԮVC1Rv`YqO EA>ˌt]\BpN0*gC~,;ʴ5N>h ?@qҮ`da RFtDob,+ d6ߐN,Sj ~xua=5g%F`Se g*A4 Y0y ;*n7Y-a][@)1tDS9)q [~j ġ︹Tm{::!$$[y.ägh6S "#߶yA췎Ċ ov놭ګgiW>>u0pS*vSڙX,eԳB930!,1ZVкTT09m '^ R9]pXs /؋~%WyZni6-Zbb#A&OǃZ9XY4*_e&)q3\ǺvPp6Գ( w7Fw"[ }a,/ R3Sbd%9q66طveWж]m_*&?e0Ձ}lvb6#L'$zU2M\ Y~,*MdL/XIՂ{#>yNM = Ht^# r5wIV|B!5|n."C7lbL&_P81@$(nPb,W,9vN-KYcqıH1:wbbcM檨r ']RPTv:ByC ,*D{'$NyPuY`o1)/Yo} A Y7B%LG&[vi:/Y禪uCU\Vy$uq|fÏ*ͯKҟZmfTWE9rO&"!{-@?gTCkX$+Kjk#laMtu|ma`̩}Oo}kݷ;5wFJ(:]y_>Bk)FP6nV983u$`yi՗*曡`@ O' ]tLV B.#b)t֪6FDt91ر;u>Z ?_l?j'6ƥ4=T=!6LEC56(D?>.)68zZf{2(,CPNVTyxVVe"rv/R *Laѕm~ .{CN%AL[)"6w`Y YAUm$S:w ̬̐B '5Tm1{rDJ4[uLn{@r&Ьk|*0\p*]'QZYB|Z)^ҭ}JAHlx:g>|-lM] }"LؾsC8"[~jUka,@50ci)C&k<L%T_]Nqp})wxHЩR w:ueԎ}3ѳ2w[ %j̄-HO,qnpH"OnKHT])ǦBbRx~};|X]!ߖ+vlET,*~T5‚(9%d(h(du&V\3~ڍt~e#IHA@` Ф V avVGPHo je;X&'N+.I'8gla%=:DGs p>CH|XN{{6cu.2$qe Y JiQa>4~sI٠ gY% b"ST$٫`$4U̸EYB'QTO3g(jV-$WU;tPlGf<*IJKB,Ǭ@sr9"%LbO{a4LʚD{s7) ^; *7H'5[$HCb Ʌы#ډ&ZqG^Ƴ;ql8%m9ѩ92p5)㤂liHNOiҭ7Z<:"hnkKNX0Q~ZPs9GZI$ p$6}sP߈gTcx͟L¿~||:qӣA{s߼iG-yii,(z+_GUV3]wϚ$%ےI~s{mw'2F=eZ 4wQtLÚ%ˠH`K۪Y!NGIVUvW>)=%lˊoٸ)$ĵN2o׉edC3ı4oOq8cJZ!s%DFtv0DE_r_0z0nj`Qظq|"7=sux`Eq纱xzigm{Ըz+YZv+頏؝6~;{z{"nU M|W[*`_g|x^q$;WʁhY'Jy ̅Ha; 5Fc}\iVuZS: ӏO0ڐA_0bBXj"5#TEc=5nAy5P^P`NZ#[gRM$Q5Oqr(r )%.W1G"' LEyh4gÆmX~-0ax/K_0Fڏ 8m{L}xIn.W)Z\I{]i "H%@v* >b)4$J/ "9NX-%Uӓ#?>HjFp ){$uDՇEsFYľ-"WExx,n:`~'^l=XZ,\ 0BcW6F#nɾ׷n&E,WlE`[-E뛭Eܑ7L頒ف_Ec I_WCԹYon?T]Q[[jzEiH=x[Nmʢ4)$IK$ ! TQn#]3Xzei>+UX Fg 4ΦݹUhG`Qh;L@DX1Ew 5{V$>$3@ABJw:j"<o?E6f=x)kji}2 &ɥNlM3+#Qb9[$!C˵bT :#Xp[T0Ž :YL)A/ZYq򥒲Id "$>nvN_1Xb!))<=Y9ↄeT> w BiIi0VPy(DRDpu6f*:$eKc %K,!Lss?@|j,KS~8:,Fʭ =V^t12 G{%;gfnsL6ij)##F0aQju'$#ֈb#VWذ(ޏpucw<* G E_beƣFmx/Aa0O3Դ!be)i_?j\& (D!v>”!ooCI[f6Y%$ XW}H7w\ *iđ:HS ;Ji8*]dR!q|,)*fƤdUR{duX$Hxjjnuu 0>|EbžoUI\xSQt?C) y'{(ZS4 iLsԂ1wL3TGͣp&< v9ОY4--kƉ<&ou lEѝ  Aן~)_yrA)(x׳E2F2Ëx"5m(1áu9,I7rkD[N? .}=y!]O'ri6i/7PTsx,\G)G@lJi) 3,H͌16(by4hDv1\ B*6Xl˪dĚ5zP:&L0"UNH/,p |4L;vF.U"g@מɓRT32e-wIcc4}af%V3Wu f%;mVM&u[2uDyՅ`pL0Ju`#uU#NP]-:3E E11ǀ)u~:6K>i3@ڰ$;=<@#uDɸQbnXUY ?.g Z!zvU~)ԃ%d30|vL-&=dNDŽA4ʻiuK°QyM7`= /$W,Ȼzkm?D!Uc0_;l-kUY`6hj,/OP7؛ Ɯ FdaET 8G3p# w@xB69KM=9ԛQ='gs2p&b`GRf 4iYbzGr4k `(WZwTւnH7G$1E8m"9V^$5'']1`"50vO=! )Z]guqh(r$žA`Qz+w蒍Y>.*:D(O,K2g.(SdŧBʽ{Ŷv~w>y>=bž'2\.SJ> MȻD%;[X3g#r5X917t-b/JF*&?[3Ҩ-FJ@kSZnˋ,8;p@rY+i8D)`dfcvc9eM^SľW8yLJlQkyY>,]?w->% ?}3YIqHs8B?zE4.gݧ=d0+4+'= 1bF0i| w^#HIh]y@ieK7duFpg-?ז_AylJk /%3 n9P>4{Sg<2-[>Z2cDGz~ w=@4ɻ`&3|\jafB.<?!'*4WzFյk`s5UWsqMp +e#ZtV8?58z޿zWtp({nBt_!E f|4D#%=safaeq}y7x?REvc{k'E$1WfT[| CG= =LfФLfv@YF «@*L0̞Anx`y]3Z|F?`UGˡ10H`FMX"OG#g`iIb DS˱3Γ"n޹<\S+eTK|Hihן#ʙLz eqϸ㳂(_s)|e܉(kFL yl\m@+||6G*\Xh MJ ?DrSQ$7dJJ=QuK`{F؁a 2h puԺkjrd|̰YΊU`M:YeP[HK-o'ZeTu0#&:oIq'j$Be%3M-b-"SRjEl˨LOQ B<DqBPI"{[RNi>p7a1]&QVe.{w[w%Z~ *nyNäZʰD\e onT0+NrJ,8y1:0mVAj 9Ө6`*eBg%Ha)2RmJO5F ½*ZGDB:OOQgWh fĴak|ovƆC-o'%`t4S(X[Yr `1!ep N+aA0K dHEL؞ m%R|.>ټ 2OԳ0JZ$ %+?9S~/;{ϟ??|O;Y~?~y0 //p;<Kr/G|h :j:N~"3]2/~gYS 0{ֹ5 t/BY`Q[һ5\ &!kP{D{9$HwX:9e<U&t;n??,۲$S眵r#3%cĸjpӛ h ~\?DxG7+*~s u\jz{) '!Z蛮:F9s#(I_} *O0&ߠGwOnQZEmY,tIhyF^ƂI/lҧ, t7X׭˂b`yKB^m)E( *;qIU~8v*盫bAf2烁)c*e)dԀp%&ba+&-0;]gɭfl>r?|Co_ޕ']`2J!Owv~,Uѭ@Pd5PF{˥f} lelop_e[j2&N´PBI\`Ji%D9oިG?o5*}(ڂVIOj7b5ay:_ՀBW0\Ad yfj5 kX“sx JzcX;(.1*Ҧj< }ׅk|!oB\h8D3A(j+;^^ާņe<2^ʡR#FiY]rc. S i}Z ? K=c 6^Y ȕB>ñ.Gsx]=%3CQQ\iCQ,K0p~a.|8 ~v~񳆞fǼ lz׬P 0wDbT i,aC'-B9-i)Ӗ%x{g9"VsjZL-RKO3hg~/HzdpgY\\#fv va =DS+|q Zy"Jnණ W*5yƔzQeIκևUGRAST^H77XT \K\14䬹ݤ@ϫ{Zͭ3<49Is Os %#qM&-z9 -3h`.4ri=ip &)R9U%D $ ,z(TYX*Rrk6xe[0,LW5ť*^CWCbtp]-qpaF娫_J](_MJG]B`ᾫ{Wy?:M:7ʩu kNz>j<&?( {%57咋{|N#ӳN'qa 7H/@G.3Atfm#d$RfO, T?(C|{H7볻ET P? e@緶$9xbT ʷ:8IlKZ$X- rk❟\5 hyRm2Vy7!9g|Jx^ |ήO g˪3>3}y$W1>稪S0װ}q[Z]rܡTE "bώ-LtXQ,H,:/5gy>Cbu$x@p`eA!Zĺm?FPnCx,3)\B RC8c (4QN . гDL同U9y8ļ*H'oZƘ"n.*^EY THq?sjʈu4gd9;E{|rO]aϧ^-.O%,og2=8>0RU@ϟӝ qv_}I1ޛA'EPem&z)0<VaN]9aփ-ac v5OQhl I?dp8;\~P|Vj~L筴[S'-OWRCЄ]Xtp=԰$ۣYg-=}O{>-UK%Ƹ^;^pt~^`Xj) YY-|eoEv-om8"эDM`so 2$tʸ'Bu! 0΋hb?8#E[''*cɩ2 g%D,bBsӃi`\m8cfQPFx٭5'dR @rs/'4&k8Z sH* ub;,U~ވf).(d($'4x3hH_0M'iB՚QRj5po+_,+goj^5\yI4<%vx\^+;I ) SíS8Sw aDUm0)ĨmDhERiPY"I{f$w">g\6 !㮢f.aDFP De#hW=`T罌<96h0l(^餅1@8M"_p΅wW񈓓m k 弞E(==EX11QTAP)(̄mO; B"}hZD/sT`FxME3rdG4GfXP= 4Ή`3XGAGN Ds3!rV qS$PUZoF[6L&RzՐ=:Gw \}jf)koo{jD}^{fjjp5_A +&qeNBݽQ-Kx I`38THmͨ^7Wr^ٸ@ 6=bV 8g.*LG @rq@|c8$Gŧ+ Uې)J_8*Xu͢ǹ]q`rpW ˅#rLX.Ri$F <%(4dt3'PsVuPFp`! XRf'!4;" R)>hA(y= 1-= ]"Yfz%mxGr$?^h >dVւp/ͶH ߠh8KV`MA^嘝]DM]~Ԯ@jj,QfCaa5wf黈x)79ا{VY fJ$=hml.*RTN'wLBSK"gރC$ELP m<3<~eA4$!f9L ۏ'OY4a1^ĪkqY;CT176PM1CQHTӼ*"0՜FU+C_Sc=a[e%)7E:R6vn;mOZ!+ k8VL1$s##%VKHT,..&wװ\$WGWEƄgjzgvQQE9+>0,ólN 'hNbdk}M_ta0Ex} u='v(8"fQs %DD͒r#2 띆_Hr4Yj@Q/uJǪ^=Yd!3ߎ$k::f19FKQ$t:,P-ʞ2H5$5vt%\D$75 gte$)\ Y(0rgH)vxX/N m†24I A¯82/(y '6)O"˜H׳-6Y#oఢrj蕥[)6(X(n`O^.$͖8SLt9YX4?a&Ø!} ,`آB(<ܑ>A('^׭H &0%Ɍ\M- uKR: exlQ7nE ~qf.Ugu)\=e3FD^p_m.# .6T|/0 %=LV ͹dAзaʫ `W`G*.ҲlpaQ$ w=g*NFaWԱzɎ:o`#c ȩq#2L"\1?2+OK|de2m*:t^Xx];Wf~XAJ,!BJҦ&x֐{7Ze)UM,7J6$Dׄt &k5QչN߱%ѥ,Y0O,uJIrV߮3f`h(R0Cqj tas.3ab6C#Φ;|A1ͪSѠ["4[ّ"Qņ;Ip QBԷ^ސ9RYs`1 /pRuI=MII3IsN:[Q眶>҅^bxv#banD.$ a >_|["`T.r`xK!-6djLi8UP2ӹ֪zsG"MWS lS^i3|yH9#kJ䌃cp]L4_K?^(Fq٭ [V!lb\dx6mo&7ElN R\?fY-ݤ$Ȧ`=Rb5]0HS֨X=t8mߦzEsT A -VV7ͤEFWYCS:34]ԜܝR~W=)п"ܤ7glLۭS#}NT{;hE":9V9"iTD3s5< 1^lm 긖WJT(2O~ZtɅt8Ɖ3tkECAt{<KwB\LȎ%o;;\w%Zb0FJ`"ޔ󚈠%[H8'KNPvtH:kՙڙMQI%41b寋vF$+?b;@%^{oUxF |vO\pB;ɂ9wW;\(_B4/eђQhP3eS= P/Ka5-bR=&({qpVUAR7+=y~O[*~"gAɮ% 1.hY)̤T/}DЕ)Unj$Pz>{o-+mt5,x\aU5*xQ'EpVgk*DH–[B-iNKqcd%SyΙ>++; ݍ["Eb[y=:9͞cNj~zݗ4<+4˲ݍxVnGI4\1`& H2!yeR֢ yrGrܓg|6S(l6Ž1vOw7jT#ExJѸ k#8f+TphCnj5$ %XXǮ4͓P0 44("sNi[xrIcKOJ][ouve!i@4@nmxjZ9ϕU&^B rƧYl9&NjWII0ۏBK+07/4˔E&ȴM o  U(A"}l`ffkQQ)@}[ߘh0@$aCVvP/%G59gfjܲxl(P#MDѡ%MZk(9HaϘnDx4QvxPD`f;ÂB΂f6wWNt'ʒ3VnQ7,복8zaV$c1P[$v!~x3;f3*t> ->JLK8X4 ÛQYAQ5e`,u3TgkOn ˲CiL0Tf6 r~g)WhkY)!RE\j?]Y RiN6_qf7o {T\+j+m82CV~7^wS+ ۔z[_Jk~DV}ֵ0U;^1lmAd[r[_d?3woŤ͎,F44v!8 127#d$:.CΐLMt9_nwI Xz8:݉0bNЅdTr?(28$ҿaEkkwG ɿSwŶ]gѭmP:y_ v+/QXx͐0>׿bEps7\`^;W}N-֞LUOn)Euf煢G.GjYHSL tzjəu{UN90P,_^9VfG|mB(7+Шc,t[9@ e6ONoeߌyF^B/Iח}Ə 4]&.^`ϗ0qmˁ{X\!>L" ?,PQ5Hv T}5[|u"aRqy*IF1?S QdF0Yez*V"B(Xx gDSs+#1K|F>O=fS,oFI]Z͹FznRxN`sglZVWz&ZYcBk;#P}#(_hّg]hݩi[13{o?ͦ?Oe"+Ŏh{?{-oK7fƱ{|M/4~+NbsRf6s \|¿]\/ u'$nRq? VT~@/ ƵmP:fys|::oxǢYO'>[}γ>vHw7~=vw>=y>?`~XYb&J V}x\$5ۍnm{;;O Hاm)z\i^Gm[}%k+ؘf>4)IF }c4}MkOQ_}R$?3|cHRFw7*.KRJ^:pL`KC=YCzZfFE_V쵂v?}:5QPp 4ۧyr@^3h{;5{ mBCq*O?y;z?o'Ϥ}~߶V:AJO ޴vI+xAQyҀZG@nłik?o]꟝ po{Slۧ1n0 ` pMhv4;5qֻVc`.Ut{P/uAcݳ6Х6NE@-jG>66VqA]o^B?]Y/|w{2./A<@ћ G{7!"? v)yxc<:-R-H?t.?~o? LI>Pߴ2M';8G\obI_lo% |W%X4s:kR(@hdYVޫkcukVI܎k=؁mVTZДT6,- /"m%VK{O02\F ke0LlݚjCׁнˆba|ڽ,rqqumzIS-TRL/w wO?~_m3xmo׽Kc~ 'fhm >!ȑyr,Û2_X-_*|ڿw| =S%lݽJ/)A uJgui2Zמ 휛J#l9 =5'qG7>o=y#aU{l [!8ppm/$ޏD)YtD!d 20Res4k2% AA0d Xi@8U15za䡪!P22-@BP8AmSG]Ǧ.[u$ݵRIJ`®͉͡% % a KL3YQ,:5!1{}%Ɠd)"+(3K>jp^thkO[Ԯm)oDyJ˟Jɏ0Ήa2xRdPz Kns8JmPXkk;Qo6jM5YTXL#3Ā_u^ϰ(Q;zȣhH摾rpxH V[N@rN7!̜BpG"CxPde;ӝvCE FT Ʃ 6x95hddE{78anOѥ5(/[C [rDp4M>StED 4E7r$oED2rqQ("nPFMU_k*!ACzA$.y&tz:s@e]Mw%vE [B( 6Vk 0 L,:(,bn\@f%&O[^-,cnhZ.zCm1a>F5+azusW?0dm}Rr$%C :LL%R% qsH끆rܕkd]x*|VCy? __dZ{yz oN Z(ΊN =MgMV- X/tl2 PL3(ȓ|a2r6l"S*_C;c QTijOuXh24W!tG"am锈% 2,TPɟjZNV(cO9<׵ Bn1;-"T$;|d[L_oxv=6?|6ӯȑ?ڒMZl'Y_13~!Ю C%N_CL(?04)fOM fOtݞiOE|j;_vvvvk5:r!Smz[ߓ^NX&|Y.'ۓ滾E]m%bYrk#\1b9&LwjIV\fxhgpqVHxV#'gHGɔ3w8ϒ4#VLGǔDuЏ%dc8'aVW&㣫x}|TX9~=lR:+pʅWx==muV{{g5?9jcS=*/Xo7+kmO|yYُjpSyYW)Fә gzR2W2QV/Is(Y\0in2$4%AUX9;IZq$lg:>&ݓZJ02 *j2B"sk {kd GҘZKd@XbZ4Dc e(#tρH/v%$GnEu, `69hOQNs/kLŚ̫qU64*"ףa%Ze_*+q#SUKPDɬڋɉkfau(4* }]K&tG['2l^ flKm&ůe(3#V $~-ӁVA1o>jKmllgpQH䰩5)@2'/ӜShNqY(QA]TbMśyu22,2S `;,5r%&>C$>HfV6xѾ 4¬9\:8>uV˶mެ`4),uUcP"WU!` thҵ'1 ҁjӡ̑rG]NJX\[} 6,3&27=+t{7Qa7 o:E9dAEqX $³-x u0aOARk6T.4I,Uoc& eOQ6k4VAMRbp?(_ӪjRFצhW6O1{p1L(|h*Z@L8#X">aR=v٠o΀Ru4{^88F,j+,[r{pTH-Hqp%5KH`޽J#hOEaoNaez%~vk6`R2,˥ܞlƭ(ؽS/6exXGX( <%=E|˗ sfrflC  Hbx#WKLp Kr#K=㧟~ {0Rc6Cm ts >%OR 0GBLIYz۰6\&¦nY.47"A$ ޺{S7tlU8q(IUX=MrFk(n ٩H:V ff9V4"Jr(MnnQ$( Iu%װO156%WbG"6D.NP p;V }l]Չ+ HXE5Ysrho8$304AǺ ԌJ'mշz̰FΚL\6.kZ% qOp"wjrwMm_ȱkOSw3ھn }K.TUqr؀ )W]Uz]nzd󈣳dЫ6rDL&6#Z B:t>d5Ts7r FrgmAL 50uv9"p+K*1ي)kf`&oLKT)>`kM9 Aޝnw o l0[a ݪD_(&LL9x0_So 3+ qepz.JvcQ8h#@[/ .RUI>?JӪ8ZQgY"u:e8m1šAn6P+5fi)O04Lb2OeC+L66;#LAp%Qy9XVLn-'5\ny|J}46n_=k1q(rэ_ a6[q! iK&dA6N_b;u-+>MD8- e?@ }:r! Jc`M57dlxϖR*{9n&皴s k_?<Փ"TDzѿ);,U8cWvMco墹rz4I &%9̘% D+Qaض޸-[_I Z2U.V>$qdέ :f0.,/bcmay&`4ywt;*Ze3 y%WS\–JVbl5h֬&&PΔ-Cy _T6̕_X-+C3xGgivwG7/# L*a^ulZ33Hm lB!Bz/$V"@TvdzVcu;'?^HOqNwpˎKcf3BĺG! R]sٳ])q}5KQIőErv`hTviw&(Oz8 2R4Wn/OGp1"ZF^x/\U'"oxjSR<8aJdGYŢ(e`ux``M;q", 5Mm] d'VRQcfkkЦvnnn RcJLX(bH=5r.WN:{dmQqM'ryX| 341+5E[FnkqS~a[VX^)-L}C'W F,:(N1}*!r9;Ҫxy]nm׋\Jlkְ߽Xe?4  dlExE 2ۈCbpd#2,.+ hj)u#BbŦyE8٫bh'80dxL\nQxxvxvgt9Q&(8M;~e[(3]:XX|=~2'9;^|s>g.uހM[N^\ 6E{oB v^a xwϬ5YCɏɣY^3| i sQRQ.U!T2w# v1 d-l7T.I?cV"c)\GP"30x9^B|a%EbǀA e8Z'# 2{(*# PLDѡw52{Y4i67NQ3rꈶ7XeV_Dr@s fӆ%AtdFΏyݭKYt=d4Ln~^ojVr/! "TDüDiy5c No{Ȍ?~_ܗ c FX(LCz_!#cznK.vtQXZV[T||*P[ϚXZvSї9 A/o L{H69уqQ}WWLopK+ΏI=N:sd?/dykH6lJ*H1&GU~TR}?_ou9u%pt=K]iO!zVk6mH OpOloTnĿ$Z'֬yqeƟI)# A8# EaĽkX$ϒ{Oj$ f]E$(a뵁a2 p12ڬV,75Cɒ5ZH;^7%gE ed<2P%)$5\%,ƑYTv5 6I }g`OK{6eD{49yr;r3ۏ7N(2 ڠ '161`ɨX=%2H0 CQp@vkME2E3\@=ԐlB%Aw]y\9u8,=:}Du߰Z% Uz) _hcbn3PD(!<vǣ@k=bGyp?U9=|{aw)"ߐN"$kvL![z!%U9 >L; e08i:t%4+LU@ (lQ̽'q %?fT$0~;Ք4~:Xh+kj6s62oW5r$Lc}?yd]?dy.}~],WX{Rv,g[^apz&aR LxСVأCs%ɐ9 Hkxd#vHbJs@yά$g)9c'Q 626_DvTM'`HPD0K;Xbal^sXTbQ_۠m9Um- N}"F۵r+mIX8Ȉ~>ySe?D: ab_^R[/хmY:^tcTEnvrY⚓} r/x Re䮦]SXlny)zU1ڠtFnR!V4"P+|l9+mnG=H('Gk*WC4ѸAGEe{C;D(/k݁J3'@h40%!փsbfVRN*kom|Ix8s6;ְȅܙ寵l\ݸ47:R"C%:LJ% Yy9x ul Q"0F_zJ>ÑL8a+)yT@Ѽ)AE("C$1}6$!( L$~S )S9s3[á93LAqȩyGXr.EEf jʮԔS N'VW~ٜn[7&-w߱q|%Ɨ&Cv -k>nNa%γikb*=Uȓ. a0\]9gJjfdbJt:03΀T~\U5-5'Ao us+?<ȟD~xb1JtV1ɱH(چIgOk7N8'~En-fJ5W+D$c唡VNjtyэN|GHϡyWFVTM8g-ɱ@Q-Cظ`Cnq\F Ní%]0V|[>t`ec2).WͤI!aaāJ;51p m \B*lZ * qs1cɶk"0bJtf!6)"ƒA{#’>Y^ʱGN#$@5S  Y&SY[``TLas-JM::aؓIZǾEMnŮW8(ZP.u$m?8S^:nK 7pb@$H 'Z§r!U²!%۰:7![&CF.G@/&cvQzOU:͈IE0'v>)Gy\j=ҢuE?5Xb>4ȎP8*8V_*m}YWnuN9mտV8q.p..%#؏Ě1́LfAyrP\9eV8T̥hS %9_BrҫS/0\,d ޘ_[x6֫L-#>3>7:I|:>OK }[|$$7Mxn[v7VqCʺ;wmMucN#neɿz;駥nF(5jy#"),XYD/hB98ɿbS2Z(&t(sJ{(Yėv, NSj:3Ym&og&TwH NF S#r1F30TM6ү#8so3nߊ:3et ̑@\\o xU 5|~^yd\C u%QSW+f)f gH6ʫ<\v7a_(? Mpɵ WhJnlDBk '7wz]ߧn06tK˝K=E]QSjt%@lrM~!.O*+ϲM)?>/)l,APw U"dn,ETD@f&LE⓫9g1[U'M&{> 0*?.^ ;>sϚb4-m ;;{zUO{ Pp>^I@~umӞZ9GJWFhY06: &2Ah.uwZ.8GG miէ뤠|lg4*8o.X\߯*oWHedZIx??>&qAu~oUʿʿ揞$n]AnH#&EcEF(oc`57I{x\=+܋D(blFbg^ ՈV-#`,JxAglq#33nJUP)mŚipck-z/Ĕ*˯ޭЁp\tm12mwF]22&k˶s/4>lҪ3,4ELt8Z6/MG?- WKn8~ɟ10Cȃnl $Y `ԝ0V̞│z &"[†zLn B/ )r}СE m[?bx"aT&I |GEʝj@oe,b8H.=Y_Q\@ķWwOV CsVvu &9瘞!u2<`%S@Ĉ HpďT)QZLNӇ1ғ{\a6"iaP蚒4=YDyw-"Ug tOavA۩u.kJ<`r!q.Pm3#6d &'8tW.N,dBə_HAP8]/^%\2q3H.9+]U0ygwJ~}I\ [P-Avi[=s ;*%%휿Ԙ7]/y 2ta_?'jŪo"?~\&0J;^K*I:c9 :ѻusRx'NTJb㯀>kȋ+(XxYdiUQJ̳ч$z=++vL3Ƃ8?Ꞟv;%e.BP*? .ɶUXmϚ'W^.y7R,uS Η,*wsDNICj'Ux ?J맿]A35Y0?l /6Z:%!M̚2$8Gb>u$r)O}nW@ ,0ApvA:dVlBh ~*~릜X6 :cȬ l1~+B&gNf4ӏl\I@I/>ґl|@k\Fx%) ቄ寛.F(ǘ<.|(v(:b #9SJ(v}ԫ(@ՎyꈣgIf '> lM* ycrߪ,^*(iU`DVZ)J: Kxp4NDQdo?EX 2 d苕b8|&SFsMeĩ.P[I30mX G]!ï3H>ҹ&RAFA0 1xI(X& 7St<& !}GMrC(>P'׀EˈMrʄecl<9r;LW #Ud%5MR9T|| ;78X@#?LEg~}5bT]vgc!~m^ y7wnO޻#[h^tFP+r"XEVmՏÀuCƚJb0 fU3:ԁY-feT-zp>[yN4*9.O"%f<$6Y2L&8Ɠ_;vjc2M/W<޽p`~X:«Ζjp#Xp߂)z7t-mekHrRbn_ax@gAş| @Iuf爍~gl^(17sN/*%Re&W^B*ܤ}m ދ`_a,GֆS3y!t.:{VMT\Dp^oEY;Қn ~PVㄎ%T8`;^9ݱ8o*oӥ<#an8NIdsIN^ pw8h"a)+ ?wi?3鷏bGx8p0Hm$P,=x^y Y;P}|0Hs(º`lNST5鄪$}"bOYƕR[ywPЫ=y.4]iojk4G ~ S/ilxϰIA~,q"^COi8l`>yAijpsKe}NgҸ& &JU=qtE᯺,qnro?g8JٍV[UMUK3ISeWj.D!DCIJ2Pz|[R1a%R:YL8Z6_XXmݝܺn4Oؕo"SǙCSHbywYMK-sE`4|P|L@H7̳q|\.}@Qp r/R갷AG? Lۈ4wNxƽ`2>]Xf%{Zw#*.vP^wI58Cӄ72zEE_+;L#%UKgtY41ARlPH0se48I ÈQ~3%En Y1v/Dg Kz~}NΆ^(kSb7)LoLhhOދ0XBX\|A3[kbIϠ1EǬb Y=+ chWG 2"&æT{%}]yx[Kb Z)ӷwhWv^3KV1̗ P:7Yh ^52)fFH 舳S:Rf7z9S:/  g(-M,urIAQAۜ%t@,(o)fɐB8ך{yi3os#./I,s~X<,qpW{fi4xGd1GdC^MfӨۃMbump6%+Itm&/C]jZlhPL ZeQ~Qo[Y+!róUh3ZܩLlEb/9fQiȌ*a8g62TJXoq`.Y,jèؔXv#{Ҵy:U^ ŭy `;B*dx!8+ZƺtR:.zˬ.nˈؼ~3LZB(I9hLc"MҊGlp )aRʣxs: 2_c}բb4OMm$E[lnxѓҙMgŃY%KX$ (5Wvb5Hu Rh;*D"z{8I.Y-(O&Nyy,IU}׵,U Bi_Gc&dr:U&,dDŽO^qk:΃eǧ.idqJk< !`;$mKfN!D El¡Z xX[aI 59XPr2Ѝubc%b"βd#Bl Sڙ2׬>yK-Q`&zm^Q^o}4򬲑EN^lĺ1q+@Qj//)?!&U x|*U= L9D}=*<&⑃'bM1gܐu.=f`؈sq`6G PL<[,)q:`e#ȋ3Z=/F"c& jMuA)E3*1>]4GaĂM9 7խv풠)17abCY<[QUKKv`r# Worhy"BcnSxlڪK078R'h%l?Qg!a )$bD'MքiY+og^>R)H f.}sSժv1~R,3\qaƩg>6RՈ`VlqrBllT&B9lI|ѻ}GxȃO|bցk ~˪tfD|\+ֺT,W!_uZ[ GB!В@Yj~4d㉙Gwv]DotgfxzjT MĻ")O-+gƳ= /oБcK՛Y& Ijc&+1I7p@nNXwx@r<:.'~A`Ïj[^ TW%i]_>p`cStޣ#wVc9yv;&,+H+FUY[?Kxw ZU !&V)`pR^aG@E᪵+f}y"tZ?v{w튽W6K+@Q tV5bv笂ur "AeP@7 k{lPQw&`*u?]àNu +?{~3:ʏ`V#|iqiW~CWq2*=ФJ+g=?WuW ՠ}ZŃro#4˫䬳^Q͓w&/RO+)hvIR^s~tޝWY%bp)*C)N}֡+>nyVtAVc|FNI F!ʪSy9oUЋruܪXeIH}=W ⸂N(!}r E3zS<ή^9=oȍ/ rRɭ(`nI{Q@ S"x췎xT8F൏*x&F_^xoZ+Xݝ"r D%SӟVoݝvhW NdcܯS]T*"Hqk*xݝh`H~\ )΋rhSrV*9$XY]$F%;[ t`kWi<hUhՓK):$_4Ld=[&%94D }|M+ t«^7 VY'%O(U^-"e袪YΟKWYU㴢OP4)\h̳ރ ;އ{6wŶ([:FomDk ;Lv۴xvp]i-6r3n: Z_J |V|V$I6K޳ރϷT<??NW3Zϟ<{2u H/c.O\Hz̅ sR ^TtY|= aY7x0 Hc 8v$ ++@xE mT~0 cc6FZK=ʮmc% {Vp&'o[U|ɪ;;8x?wo1x{O䵎]'u~(笪xI<T(2Td V)G~(GH_χhq?Df)iQM#jGGNOdtf:z'?4Yw NepPD9b$,&KeM<- 9.is\믂+tRz 1U^&(?Fv!9}f$&/jhF =nfKhfęQeTװ./.ka]p M$er uZ.8= 6g#<Vʫv_|Jg ]%A>_s΢,+WkǓ ۢ%jWH';?lI<f(#HV!2D/34sJ ytE(5:#sX'PVujR|{|!(d(JUVWY6> >qs-T6*/! D|7/9wml8)D\bf :ȁbqrZPdj C]ѧtZ{`sd9xu}|9 F|14; 6j)b-#ge"jso7E}񥛵u6_rH2?tl=tS#c+nn, r꿼D06A̫5)eeRTtT9bʶF' Z0{}wY(vQB֛w\pWz^t-+!ؿ@,m)Y?ܴXwzSrVslqWQI@ou$6'/ޕh}?:U 4)ma0 Q4H[߆p5Es5W4UlΕ0% 1"aY#{6=*1Qx13 [aq.I7rM uA?ZM> ,p B ]Co)xxx-t/|Kh ?)Em3NEEv)V&U8AU#Ͻ8)p9z=:&,hckOb܌k#2'3aۊlq<7#@#&F+:5IÍe\|^s z. 4tKq>piV=Ĭ8kqL1h5"$oFC*i y䵰5C|Z:Fg4ffɕ. !/%.̃\ |[xf_l%'[["zW ^zZ?m'<,±9ݲM8loz34LY@qƘ A~=j5 "'|~^tw"aYdZ~K?%,Nt-ԱsAe<28Ev& N4H*Neռiq.3S=:*B`U|n||KCٻcTM+`3dtQvw`S|QS<qcx-D ,UŤ/5JR`B@pfMy=?@{n-2 r vq7rM;K3]NOQP̱[)eZH^b|(5Mer3&g7Ts}+i^rJnQ8̄)+lX4T̈́JM?d+Ma(ɭ C-53ǔbv;ftOi/BǟP 5H(!H ;CYuy @FRүu^˄QN /pi,z2@$S4t$;[gI0B=7Eãɣ4hQ3c=A)&P`l6WK2 #J"cJg*pUYևdbu2X" ->G>+)wc!>ŧaTw Pc`orczr+1jWUܧgj~h[:_jg̴c4^3uG`%? SPhfeO9n7ؿhmuΤWu"D]Y8s@'f9۱wbnl˱Kj7SYN{n߶,l o@3J(r0i>dIBgqVWeywnq9l㳵2Y=t*}V\,,xAx_U][Ee 0/K3k:EWzǐg s PYA|VYG./=xk5ͷ-S_?;0^y4HuE-Ҙo+x,_ Y$O˔ lS (OYFJRS'/<瞉it4(ͰnfS'FwfSE~KIyS6dT $ ۿaNwLT͗ Cr@vb(Au:uN&<= Rb64'+q%+7 0Fg3`EaJqpftV:שRg 155~%u[l!q  {> SOŔW/TJ3#Aq:)U'J&ƙ5 ,J.ؘl2[,6l Ϣa#fS߬6bK` Ҭ 8l΂tI5LvٌjDyrxm ,! Yq$MEĶ|Ξvj<i˞8~)'Tbue i#ʹD^Z#Df`sI<kкB2Iq'af}UcQL[$YI&L8qxt) NE"䎒l=޻aW.SoQ3S8cdS->j.py'.HpSe@hy L37b񢌗^$S\h¸hd_Lshih,Oldʯ8Uzl ŸT_#GV!bp8{@ÇgUOO rVn$qiw4s.dך''N-fH'Sq{SBzO89XrUu-V)2pGqv ̝6_Vx8F9$sK<3|t ܟQly p9Ka #JDHJ=%e6K^Mlp7ÞMʐw,5F=%]NRl m=䊓f>lmeVf56JdQڐ2mM\C Zy'9K3,PAliZ=y ť1١s+Di8]ansF̖3TzC]*ߖT߬Ꙑ`^T-Qhœ>pRz\7P!ғ;B ^:Cم$ɵPU%BZM޺ )6Mvy)""0GPѹfN78# ߌFg< "s}Yޯꥧѹ';+e0"~cR9&V7>pRr2^^Zxuv8a[l5M Tn f0&"'Ha(][PW7]2:lF\Lotvh:]@ ۰mjfW+5\۫ېe!ݯ ~ܐ_G[s|znz,MU0| 6$Lz`m!΅R3d$CI0HX@9006KU6PkЯ6Ljy;kyǶ*KN|'r!xeMD)-sMf5;=xƷ]XJ۷Y^ArT6>Q2y\vhG+&EU,KFYČ# @U!蘕%l˯Geu{@~\f 8z=K`O.y1hjc?s+G P+E`ٕ s_DH&hSO&yՄ$KoΏB4.-r 86)N,!'@ bJChw1֛eTV-pV{[d rhkQˮOu͈gL[V[TygڦK8vk~Xđ_ajZ0hf:#-7mGeCs.* Sf?:_GOlc%KhX"֨O0dDnÓd,RtkG@G}5@Dv'+c"N=`Ƭ@ĖX۶@,KYUGFmHp?J|awJ`fsCboUXKF8|FCktM= +-diL5]aEW:]q*=̿"10^hL!s&0jРR]D9'4~!X4cG2`7ciT!4F0 8>C]5vB%$T* \jnnG \?LӘm=㔼ou#iRXCuȔEYoDhLX=< 3 'b [i8~`I(2:9Y$ GTMx9 J1ZC2Un1>M([ K_CTCӤX v$>GBDJ #Qݛ a!'U XtI,o~SXvsr >E^MU"gA/e#J(jb6."AZX9\/gqӳ#q\,yovR,/2L3 m&ڤ jti22]+\8T)[8,PB Fz^,/p3PVB'9_ jdjBbKكISTుh,*r'"Cږ]kʡ dWI<h諾B]g7L 40JC=o_{'TZ`q$X>i3G~YXJIrJqL)H#~ô! lJcԡp & !K>;NүbتšjRlBg#䯜kO-|!V!.fn7BM}:fQ2y,j/E/6x|&Q'odW&==o'Pl( ʢІ)BU]UϬTVr$ݔUB!} 冁P uVbzwZvKi wnJϳ0*hI(2WY]gxX]8Haqx AdkoR\ɮ{wiuŝhSU_O6s.8/-Ar8ocGQ~>" }!7TߑI3\ϟ<{xva҃n^_Q)K0\ 5RzՈƉoׯ" @4Ur&԰_D/Y'sY!|! e `t%bD6?>]Pm -2bmqS#JHO۷))鳹0{iO?x><[[>f5 'V|eo~g Da&!,8@ !.0(CTYe 4S9fř,rNIo6l'T |@&eM8-ŵze$ ٕxZ:  gI{j9uȬ# O:g%~F(Q3;iS[zh6~ :7s*P7#B W"e%%&(VWd/$Q%pvgܔ޹kEuu\[VemdkVU vI|ݽ')d_,$-^z= UA,Ou]M?UAAC^˭Trc ʯ UZthg0QPsݫT4x>b"VcpZ\ 2 /*YY׿^}[kR N ?.G?{R\k`#KBMQQ?4Rl})XF,^#={|Sg`.w*#Bv>r< n|kf矢klZrw ϲa6kloNQȱbjJ눳HdM$aH O99JtMfTሕ z>r#m0eD#0^4%i #Y,!-&-&U(hI2f q*! ;aTL\*Op_髴1ZJfVωqʴ&F [F@۝'v><zoݝC G{oÏGN5Gc×Ȁ*q%i:8 ST i>Yl(+K۳,9b 6^lVQ3 L a%R z}!+HF4bh6LzW# - M$iƇ8 vQ/GÌ^=}UHfMcmǻo&@Z,bS*n|dIA&0+|v?4i##"@nDkJ\xM+dxoޥM .m&RpNT`/a92E'i?wbۡJr#LyYyBxfɂD4l  $.#Frd o}o5o;ߒe|@PsB_qxnOOv4ՙ8 @!O58FV sU̦_:fүˠYUcӬJ9bk[U?\>+һW>{=x[|_ރÝÝ|=r&yrns]Z`EpH}J 1"~r~9L̦ݹ,-۪[%rdUV);ϠnI ㍚[U[/)4"I J`xqOaIU[,ijx|;pl.x+řGR&mђ SpaDX4udf:j_B'AD !!M~y(v.C<fHc4b]h9i91rCPpon3C6t2z='[|so%tТ/G1&6y#Uƪa`sDo!P#} y ƇQE\ NdQ2.0JrFvj幐^RY"9pA *'16h&HM:MN;l`͍ !r d1ښA, [RKKyt-.4LĮa4%) ^+gomwms3& ~|y UsMqҟ'g ?oy:9`jY$*H},PfD;y#sތ׾5B9fj5o ͚֌:JP qvp 1PK+2?,HBvp+lN4Uk/l΂pvn]ɮD$Ů*0[HdMY s5: CEC`{ky򄴀'ӸNM cTb`čQtDWoK:ChE_&bۉ+8їp65B6jñn)xӱˇ*SX}=k\/sl#cHa',Oq|tƹgƻXܫ\uI ˹K8- 5Ԥ CL|A N4bԜDO͛zr] JWCf(;GwZs^V5stńGѽL8N>Ws%J49ϩ^ZA|+W#)|<3D,3 rn,[9Fr@?xnY{_@]d4XP dݱZXt?P~n\Rz_= TFV(e΢;bT ax*\qگ@"8Ase=\Bpγ}xY0$C5&V(L=2+}XX/Zf Ռc*e%0b26TMT_azu|yk1yJ _ l8_9ݝݼR}4i?Q=,Z<$yE!Z?3FK] gnTbk 9Jfu= 0W!S-YFM)f*YH^[b'AI`A ;p>Yo&x!Jb5!`84a(8Ύ5fj5qG~w Y݀f KsT  :7LXWs4 /Y(5>޽cS=?-,#;?P4KfOݎ$^.eS T܊M*(\?zM۶s՞C2o֠vK.b?ʜyxd>*nAlApw/wpY"Eu]R˿1$(`8.PDi30BiA w-ɲ+p*#3G̤Pž\yhR5bE4 BɐڇS~:=y'%$>28 K0%ia Nj(|8Yӈv@VcYB<&*P'j*BHై[\)Iil´d?1Ë!-elA9 ) i1c8̚Mq3OQ4}τ1 ;1N6MZN գMם'pYiϘ`=R I'qMġ^GݙR> Ji΁HrNS05OѴ%+7Ŋ#>gBu+ Q6.c+eu%i2>W?2@Z_ȣiJzQvr*r *j(ԿrUN!J#>ߟړf/aO&- >;xr!\F0 8ش] Dwt@6} -7y+lV\)N$$ҏ 0ʙlf!br$0eG{*qNJI^{MFue^N71- ջc0 &~͕ff>Zcjux xCT~]QtW]eA#D^.,<1Ur:'IM\.«ẑ,w~y@欻,{ T2g_4-B0{ 5׍Pu׻}YWP}y_8${AW&),~ф} rdx酏yU.(ϱbJcNݐr.S=aF $\썗. BMj(p)UPK.c5b<ޕ UZR.}F xLTcK~".wֺ c{~-Uߧ+w?+<gwշwL~8A"ğ/TJNyFy@??݇i*0!EĮStv:¡v1ifuZǵ\>P]mur2Rv-T8t:i ZƆmf_ ?_^o88<pg<a4cZ?e2;‹®hJqx,6e/v:>0]\\*JqdoWW7;A%ǬN'C|ˤu[yCrXmC6f0ry p=q$ g0WS퐫C`b3崛EZӝOX)c>`'6幅`tPت@nN-c2 i )xd1 rd4փRj-7KL<+(Fl6T&9G^gݿ8Wq?t H܍m ;/¹P WVH\,'jH$Ls-cչŔ9Bpq]~ GoJb XASI<(JM`4%">#),= ]AlBH]p7!wYs2EBm诳ZB$/JX;U,;T,=H\C<_yst؅0lBOG5JT4 * A΀0A[5Z3y^"[ngi m^aЕ] )Q#MA;ڿ7^!w6肼:Im%cLk;#7^n =Sq] %CVZXLKTȥ0; t*_yAYR(ѕTzj mLJE{sMg+&НU5腩bMjlw={Ka,$Zh=c؊:x cYINpyҸtmG[T']IHLq57_nSg|^|I>%w6s ɂc3xck}!enނ#eTxP<-#IJ,i*G]Le7KDk'E"> o3)|Jf1aʁ3a]z,"œ8ӕۘ%pG9UcP,_' JWH1A&2q`E7 C% Q]+mRuu>׷쒢BaW{$~'0%qQr@ހ CL[>W@dVIJS=Bi) }}H0i: sh bFP&LvI5霗lNCO|CLte*6`dհ{3xxr^x[=TNnܩe |ɑ'M:! Bl-:V.}t,E ĴCzGt aHtX5-5MkYTtҐ} wI\X}0Pw̐/83dk qoK+ RؤkQ % ލ*x7UK+pTQ|hI i1#ʦa}5smueI|>ڃǃW{@ЏiXYx,>sڃ}hj}:)l Q}=Ld Z~cδ,#*ァ..AoL/=hq*Wk6FIloѪsiuFe6 V cՇ]]ͮm4%鲪of]P߶zן֍KxVUoյmUUkcdҟI \+Z_Yq=xeR? NN:\1Ca!u&6Pg|t -âX Uŕ&Tto /sM!@MF' ¢'A։|d94X8B7xv'óp#sTŸX#uGkRk4Pȸ{lsI?'mJ2 vʐO kF^S)jrj,oe5<^Mq .FIW7|?B^ +4EU%I:|GpZDt.4vE;&%^j u`~I BnkVĂ\碪wqqD7Qr_ƭ^2Q /˼{wQ %Y}*)9FES}[pסUJ3%U1|5~4fJc4fNJKr(S>=@и)Gdvgim)\HFYi1:͂AĂ-SᵡaTT6fzXYMirH.o2{%_bC$fa. 9ɋlS\sI؝W'44tğcB}.6ߤ nPq<Y/vu7VjbЩJ&o^p)p&?mCcor4~΄W7"*G7r K-`\ MLhn[o!#QҸBFXy]8u'YivƓP`9{qcFwf dȩ>eemco+qZ6%A+cq,)v~zƠ(4muxL|%odJ$nW++o\;\SkT-0\0TJcO7c!I gF ğTJϐCTS@J,UGEJmj1R6~`84$Vb~{X^ X>w;'mIn^* T:j݃ݿw(o ZahJyIeI*cr@˟_=TZ2ǝmUӃޔ*/[)Ӑ[KB\"ҀrBK.,( 1ر._\`FIFgjЊm=X4&JJ̧EHh O >P[y;&Nse<2j6wFiJ+Myt^8p^fkX4֠oօ_ v[I#߱7͛A m㼄c裥bNLN|# nU~#Y1*"|bc)HqHH'w W=wp/:}ԡM΂iiHsjjZ]vi!ק+6fku|>^F_F_?ku'y/|Ff37wO q/gҳϚo]G A:(5,mqf@d0*7#Ou:7SNJ):>oj{!1N_F\ˑ /w x*3T 0IYsz~1|6a(2mtv0PeZ5ES$X}_5ǩ(X!Ĭ}h>kqx2eb:=*o (m9p# )78+`?S-F/>ň^ñS'p6j?<,|OSS<?NdN7/3t,xΉOI"^6 (&*Ij: gŠCi4aTP4NFc |!) p/ʍ2qzh kN%1UƍSTց"K:@4tAym})+TTUYAP18)u[tb— _,/0_t+Tt,󏒒='K$Fy{O-iqBI(,uXDpYe!% YLPݧ3 JƺkA+^IIψҊ~=:W/)S|^PuFw˟5fͭAj*5TU8W TԱ]V>N77TY^ʙEpU4 {SW5J,T3z{ *){eaoUY|2ɾ+HUj\~FvaQ14sex( |\^#1\ǙE~ѭP1(kjtngE Ld,䯊f_%eU. {*E|AbSYX&gaHwky\g7dh!ʖ=*K4 C W8YVviL7Q4cȆT9^UC/aZ~V *=J>*`@*je ,5hW|4՘U@3xˬJ겆55dpe:.J;^7fȰEBpN͒ г@WʧDslϲp8sLXbeAYE'%^JIR%Ōœ.mA2]hzauпGᵂK7\V,lLRr*Z,PN?ס',%.?Qy%Iqd7QS+#H%CwZ8eS+*%P5iX /T*2G* 'vfl]A&/#bbUge@%wCa)J+<+!bM6d^8slZw3bX/B8@#t}.6dou"qzH>  Uq9e$S8[ ~WCRxi69ȆR&M ռߏ`΢ƪy;DXKGɨ##Sx7i) s/q/M e` rs#3&8֊[ݫ>;A<QiM8;y*ZT K= Sf&H^dROI;v t-x\K$V𒰢|.5)8*]Aip, ;Fca: , ,0)XS.) 8019Z3PU l^u .XX},RmN*yrAA3MЛڱ~~R 3ɂIY$YyrZ-YN @^۸-ೠnlrӢ|]ޢ,HeTnu*JwX]]'wd/^_%X񽄓#[69<̓ qw**Mb1R W Z('i9:r /6@uP.[3ddIo`Bi#+ԩjKD]A%!^Ō2LDJȁwMUt1 o2$ 4dBHHFN 'F*9ɗO8CMNa4A'Kv"7aަ}ا |jeTZ1-ڜBKKwe.Gxӡ |JQǜ*L'J/bm,+o~gJOGNCe@z6*(_FwDÍ=etj<|ddo\իbA̖nu܆\/V<*l. (=)Ntّea?/my^6K9O8т*f_VӬz]ް*#ӯݓ7C4[x0SRj *-jbs;{{hڶsPҢ"ګvx%{:xs\9Eiݮ9 _ǘBݖ{Jl] 'VPKX5Љu'=T5cJB%ZW!~M6_}q:+X[7OTA߰(XVq2c{?ӏ*e_KFZdj?m]|@?V7n<|Oǝ[N d.o /iu| j\oiLsi%a ׶Eצi䩨*W%&.u<%uG=<"/ӡ7DBdT\IG %fzCXU\FBJ4Fh9<%:VJ eVK 21[+) e{!~9ԽVup:Sn1bb,Zo|RA/Y*=`VO#_Z0I񈢄 }I 0 ƕ1/I 짥3)zUKw@pK8t8DX re0dLIdbS*减fՃ+/Px#ϼK? Yz) TԒlҳ6'٥Jy&۶)D@'~1a{?շe/;/6S 6¿ bJjϩmG-qHҕlF["$Qzi`N{),(thnhJs.ȳ74vvc 20QK;I40 oZHЭS"yDa'RKxN'CB)_yI0:yz@?1,1XlĈ4*CcTĸt8E8*KDp+}FYmj7SLƼE٠ټ]#w>:Ke}R1NXp/aͺLEvřBC*(dpO򩦅iRrdFr Ag}G_ij7}3ŮhQZ z繘T^4 S wX/e>4r.Bp_RO?[ȚkkO+?p_}X']O=wCx$G xwO'ÝSBI!娦a4YFg5<۷G(%ǟ6c>u?zx%y}ea*;G~~`  kΏyC>zt;>E4sIx;_1(YrތJk;6kɨh10S4a38.rQaj+a4/QmúK \I|>N~&)]P)RQ-o&/TKne+¥%;s]L:pzN,X&zh0PԠr@X\ ۉ܈0|k I2JKR?PB/a;b~TO-K35-LNDTEx(S1A9!$-9^)% "/&m M$*id$(WH/_. -` z 3.A72&,Y`/FFwe<+31 P:|ﵧ++.0}68Q Guz1OJ_{/_O(ɓw@~#N0P+":zj*__2p}UQc` .ߋ~yKьѩ7$B S΂Q$oy>'ݒ.BX0)mEiwMlbii ( %~ZsX(ʔ&.{ڼ-eekJ, <~"YoaH~h' tBnn,d͍^l,U: nNy^QgAoq4k 5cb6HN xIŁ.O,#YU31~ Kp]eBP>: A:e:p2'26 ! K^׶ 8| %16ZT:3KD4cM)\iJ5b|BZB%HI.!#Xb.,<_(Neh|LҊy Q}a|b]/0MEq+qя+R;{/Rke]jg§4D$~AђӺlT+b@ Ɉs?ɀ{3(Hh5QKEwd0i!Nhr|DYY6#d|٬3DSZغ*'vpB)s_}F# +b. HjU;X)=fɯ9< K0a8VwzY"L<~6_oGݑPjACD+A]'!Kdiwc'Amy<(ڧ(`A+3t@yJ<@sF>j.tjyil (2"a1]i0V⺤_{m-7`c?9w?tyFyP% 8\ͱ=И>!Ik<%c"VD΢wd: '1 7t!` J (Ijb=( zm(G~qj{ Dc~ (v5TLU=w|򤂼}y:-oYXɤ>c?+FĴS}PSC!F19! \g׬;MԀw.n_B-,񶡑(%]DhhO*n=]!˔ӉX&>>Y!LяQj'2?@ E)`qfYJϥ7op,{x{yHZX7jKA>l ڼ0fbmthY\&Jå!"wf" ("UEJOBiuǓr| TqV3dicˍJdq(d)%'4}ɑ_>9wܢjhSWѦ:vOU69f4PIIz#ˌ1H`Z&$>w8 z9Ep9)FJHSLᗑۻdӍc@C*;̀QTf*oKp"VȫWr(ޖPAD)*/B-'9@esyH`F"WF|V{*B;@_/1"y&cipDnN+z)p^ewnowXUʈmJG#cߥԸy,45DC^%1%r!j\rʖ @PdN:}U.%CD@t`D'b':b5_ uĢA:>vN<*_ kriuI,NjYH&A81D_ƒz4GxE )q k} ¬>PN^1$yYeH-̹,=0gA4dRAal>*h 'n"9yv%|S>NWfKGmm>X??Jf-XɌdar~[g5Qiҋl˓ w5Osi! C%#V>3Ynhb?Ȝۡt $>YiwY'7S吰`=8=HsÒjd c괔feg\)|Ϊvk GoajjctF'2 Jz\my7PWy M-]hH7fT7*wIj:3u65EB@VI4"TK@uQt7[ʴ vK,s[CϖIlqYؒҪlIbc;JB[<<{"']GєJCʭcY7R )84ĭ~]WPV˯1ژy=C\Üãrÿ*Dԟw e&Kq8Ӧi&Pr̉1Iͫ6u8wA%MYt%iMgf<@;NcN[qr`˄0%IUF4dEUT+ؙM_9Il ogK2"9@[sd_,YL٤He+7ốOVnx9k9UNȰ-rz4݊ۡ5Ih0xZJO 7ۺCO0LD2:αӢ8 [@KVZEŴjϞ* }Q>O|SS#pR<u*r:ЧKuI2idVVS nR'*dóŅop.nTԠ JJ:d2qi( Ƈ'E9K 37kW_qSrX?F#R#^%01;Lia{9\fۼ@-{aKB{{2 9:568(}]b sK^)`CZ$j-VwK,7u|;W:OF(|G, {!K몖"L.>cT F^9v64ɛkVy_{P6LMy7jݒN8-w0.fC_TwϫUI{<-8-;ک9%?w*dqBeԒ阩%76նdfQmp'(M|-wW6phP탌|: 'ޑ Y#5КBX ,8# 3i"F(k/WFٷ͊nk̑ML˺Mȼj6~]K(ф-5XU [)Ibl>C¯#qY43C뷔ipIEGz+|cĈSV*{)('r&VMJ!Z5!IPV2faA@NO!=w(Lq?#@Z؇0 $`lHRMr]:?xPjxb2E iΓ}yc{|A;gH^Hi̻Gi?m0b )xM*2mZ^*xL%(vrhD}p]OʸE(Aܻ,~FLj{Rw@NO{3 ;DcIח cB';1=ԎK~D3WT5wW krGE7AD^0fjH!Yތ92p0Y*(DxI(g ܩ)Z0`iH,Q=VW̮]cn[:Q< APh/L7%%lȩ¬!IٵơVD?&ð,6Zuglɽ|ȻkКߛ+O?7o<-^\!g.-!y)__DX3x0:T>UPQuX`S ) ;ДZßE=,ٞz9L*k`i<)( M^byg+$ 9 Vqy!ެ*4S_ٶ݃Rӡ{X(BB").`rG7N*ɯ@*n\ؙ>Ѡ<X [ϺX %8ɿc0cAXtC^UaԴGmV&~C){0mB%C1 [h;o3Ӛs&g{*bqH0\΅koV"k\}8F* :2Ibh2Rs|H%&tF=t)1WydjshwAN@,?*r~۠>"{SCMzAnڥrYӨ`[Sun*($c0 `- (' ibRZ;tfQQzN~xRt欷5?-(n%|ǎt.4}u2Pa0<s[t\9Edm7Ƃ?#>A{2z'is م#{^}@KEioO  g-g_ g=e]F~ ã?Pp@?wԬH^cV)(k dֹ##yݱtdkx AƓ%*hPvIFgkXO`ܯ'=}MU?:2O:aogpơ]5Px;258$c2@HV閺 |trp0bqn4{d[|CS-n!W6.V]7ȕu%XC;*ةMtvY9KۿHmŠZw{N(KхtqơUm.ZFo SZwΙ~7F+$83Sa -It^tV8-ڟ0|{HC%ߪ.|.'N=ciT.Y6W鍤<#,8Hcd'@2Bxg.qL5bu%M"D}a0Su; 6w8dbZ+^.LQ SDEJ WKzEP`;_hIprwue񢜀e˭fE,1/E[x,y/ ?aboT< Etɠe*]:jncPQ$!i*鹽B)|eDMNE$xhp2t9})1O\fyGJ`R-.YNa`-z𛉛0By++=v09KՋ-9D0DOaJK4vuCŶ;:!w\αTD ÷x! ,sN߾991581ӔaH})DSePH`8J] ix&BI)&XjEVZ7Hlh3b~C`v*L{xj c{I3n-3Y-[2tw_Ze8*sJQeK(< PdST2yrac"yL?(E ;{M4YBM:N׻g9/O;؀g%rga\RHLI )r[og戞?>ѻW ԠVr3u@䌙v=27-:[jIgJh&MxW^ܠ*"OUF&<F|Ԅ9Ps`&1gGuK'Dꄢ$L茎wRD̯/ e\$bys2t.M-Z]̱D͓wG@#ttZm13xBEc6/HrGqpS``*k(ȈTVzBmnm㚍Ġ=K8^vRRw`,O9iIQUmVZaT,Jv3eOtW\.:n ٛ*tA'#Z23GeIByN Ⱦ/^3lqw^?>K%ʭE]?NZ ɴr] WZ*z&ͺ W_D΀Y5K\Z/u+``!A[h2ݙulW 8%,yRii D, =GpÁ P> T_2 @ٍJ ~2HT^KJ(=T'БMxg~̱OcL:0)'wUT[IGaarCt`H˽k 'm:Gm7P*yuFa'L˻vroSnMgaVzn@|㉑(fS|$LY7 nɠf^NsVx(# bs V:UŖdy" .w.CS&afB#JQ*@"39O4QɈn~܍/nl>j0wMp-sQKF8IXgd(-FxH։̈́p.C 4ΆlQJ\.G*hWu2Z@KMe:Vre>_"_V{,k={_( C8vFt_HF22x^?v/>0Itw-z^|̷SۺJ *AZ__T)jݩj#w|\b^P|仜vkطGp 4IVFr aoF&q^2hS"}~l~<2hdKE4BGd7=;Uf#:?ÓDdVۓ& $1.gݑ6i00zE7H7=e=ŽZ=<*Vm9*$n'sqv\ 2jmNcJMčێFudἾq؛OAbq>ID=t٠JUݘ K^qsaY6 ^W7J>Wg 1nƮ3*⽈ԕ(ӗ*Mix:gv#u +;_ojW')M"kB&' ޙJ򟆒Ҏy;:pҥ<-f@;MAsެfXv& }y+y Dk]Ob4|8S IQ5sqkԆo,}ʈן6C%j=|t1KĭRD y̝zi$_C/Af:!?d!d9-KvāɶFq#unN685萓"8,I>2ϩtJ BiBXr*ʴ7@jCN 9 k P46NVh4^!*`ouWC+SG Gk `7='3:Cx*#7u0DNd$eJ.X|1Ei0AuK_7sQ.OnyCryJV2o pE%I PP qc԰:Wa- PxQ/ʘ*+͐DC 1.UB]o0:bpB+̺1߃,C463A$:I}s5;bl)ʌezb0#ճm2|?%V܏1Ȓ io A rsVzV`v4Q+XB0-/}VeGI \UtV2JfSր;3 _|h1vn# ;Tw\rrIݒ_9IR'kqr'O";kR+ۥom ^x_h|̕) X;9)yaZ*FMYhzTW5&pT%* laY. ysb.(R^.Zƫ?ťJXipyj^6ͺ\|I_9?d ĩU2'>A೯s.8/"L(Bﵿ&?uFUʘ>ߠŢy =KINCYŻxhe mcWyCt_p/'ƽAw ?/>m'dew,?,O2W%7$Sƛ:8EPDR]_X΢Wuti#@SP v8Q=ٟՔ\,'lV2M:kejոE6}V.8%Vԃa*K`P~%\? d,9Z'ϳl4@W=AI@)6UaPJvR)3eC+oJnh F?d8(V/RßX*f2zfpeƼ] ًzB9v`xCYBEC:!]R-A  $m̉ P&r2 8K=GF'LO8);N;{{݃a܇)Z~-;NDz3,gKO֗2"248e]ޥ͍ l>+k'?YX+ktdg]Iߪ;?xcɇ%dt2 пц(E&BOvaw+ɰRXh¢l.zxA7"⎉aäYG,tv6!,*bX;&56a{xq7Hs82 *z'`ThWkFFGq}Gt^s܁]E9>a';];{ۈ=`guW(~sxOjxOLd?|E_9ux{b`ݗ' R(D~OO/:`AG<:?A {=`BGpo{;w^a;'#hF}{py|.m`m@tۂ@1vx=?:v`UpРU89:oNKwݣ'`EAG-jn6VqAQ}u .'+˫Ɠ'";Kދ~\oep9~sx<gWеyl\| /.c<ޥ\/:`:yoKQRm۞^hynx)C`Kyp<1WWk*1.)ݶ~T+OdIr++(Ӕvaovqc|s4ϜƯ23Dz\q&4/qHv#cH갩;&%(v 㺑#9e>@rp1_ƕ}\>O^, 4IoзH'J+;)h:ڜ9Z]єȿQfC#uc pS8͍d}gj_vup&nB(`)W4WU2tk%sw}J/b(OWB)GZ9u\2 t$ЂGF"$ްy-!K`Q w-)sXxעsL՗IPJZ}nə}4N#1y@oIC "gx 9L9)ts}J.AgǜR͵5kum7\nzq"6< ȮO!`cyhs4oK`Fy-Xz[B* \XP 靬6D>s?l9Ec[Y[Y667<>sqbsK1=#\<[Wڏ`nVګ-~?n+ٖxV9C|ra1yVǻ$lw_mTǏr|*w?j4fͿQ껺|ήYp!j2os_O0[ (>C/R|1 iY8=HR|aM}Te ]49FA=u9݃vTcfDOzQ yWG]gٯŸ_d陁Md '\7PFC0JK6 8yԤ4bAvZ, c6huN՞B]%K7Rc$S>=c/X/3*t]J}5*5U`() k[Exz||tL!HDC[@l8/þL盦Fb^=s_)Οh",ϼ?5) 2R= x !0L0+Y 1Rh?Os@SOj)\0+g}7NVZFV8ZVB:48aH|;NQwDfլE'QyM.אeCe❩d >telJ!_Cr., rn0т= L+b+FI!ho2,DL}lեTa"EE[ $1뚊MtLI0 ew3ŬS (^i| >킌\*-k 7}=XѢFmm[z"4,*1èIם풽>#0qK`w'"G,-띟n+`N13Z`S֋!hc &ة(_ M}whn_1 l ;* /YFKu4ƺuGb6ςHʕӦhi֭ҙ>:-%ijbSW,85gc-UI*8D*/+ _QSԐ[+ +xꉔP-Ɔ\סsϔşvYpLgj_7lkD5B?RaY= `K|n}912E}2WJ\dB;{VZ;8aUʰks&dnm%DNMbQD d78>2C~ BjjId^e#J?>B[.M-HC[F f*)b2 ;:.$RlՕE%(Qod֐\h (k A9xd@$f۲,)ͭu>ZʖSK'r.@qG ~O{<) ցebeQBQ^ Ӟ \!6*v/[P被H)+Xze5$`y?^z`+d%㷇'a~ Ix=Ja@6qᓩ|(>\h ]f1&>*X "&皖Ih 2=*Wr3Op,2,.Q~*YE'J] . سAe8 »~URj>أ酞,*toE5uo`_BxXwI.h(.k-ù[Xz )K4,jssRlW`I5 1706ʆjA6E%V2XNfJ:%`ZBu;/z~(l!X#P"Uta* S/+qXxejl_<}eU|}>9H gArݦ8͖Ĩg?_g2P1R̴{X[:IX ҤpGhiF#>P/Q[Gk;w߇}o-I3X,Lό? ς>Htj&3UWqqkc驘יZJNtæA1H_ da"=|25Fa_7r$ !C/\_bObnJ޴Zˤ߃ _{hDp9Zчi 17 _!}}I2΃a4> 2=A>kc`2-N\\c ϡRn1+k qf245rĞO⧮p룐-t+(.4~X:R:xӖA#*qK&gGѼaL^H${O3 v#*~ȥj/SLժz@a&ޚ-BNTJJuqT4v6/ +UshI&Fs333kĖꙊUEMOHIU e &dgMEiy7Z@ [Mc ĥ~m~^]__M['FyK(_ty!D,+HA[nECM\m"J 34``i_m~\Eވ)&eiwlзƄ3XmEiDpzvl*L޶ғ6?!;aSv$߁w&&UG[ tƪ@gyҗ:HF4>doC)LHFV9x˰fk*ʗ遵6bK4oB 6uF^6~meKÌ17p|{kZ`i62˙I[zi/(Z` s^omdaRS'F"ЏoFFř F[CӦ:]Lٰ{'Sy0g?rv=5;Є%s ΁ 8/%M`kO#l-BQ?Iia0 N9{U v6ێq$]muTyi:StF}(Q')eep8n ]oY/IkvM/?Uz< }໣G1#N !˜8g ӄ*MbfJݲS7J_I~Q,ۢp{8۱rghے4 ɫ_՛i(궎d_JM%V,Z'\ϰȹ{u:9|hFD-(0띟`ӏ_ej`{(ahyKZ#s !n nv^5"L5UӛLkX4E:c Mb}ֿ%p.㻮a'.-a6NzVGhWrl#2W+-x}DNY#(=O#αXS:%PО\ 4}HbT$2](F-Y]hbtL&i rQqo_vY}f; A>ʉ(AAm)ףlg0 __ryDIQ6*Yyi&dR \Vt7gE/z87Fh Lϝkl Θl(9DeOFݡ:|̈2 et>Ή%AD"E[i߲KX.Aj38.z{Y+u|QYΠșFsVVcI ¯t~5U2zV48ק 5ͲHPYrtmdt܎P|Aچ`o2 E"+R X(x)Ϣ:veu 8ԅo D0:`rhֳԭgɲx^xj@+c<URךN&bs.G&[JaK>: cB9 KKq0WŇ%u&so T @8Єoy\L=̗A V+x&(FT$-swKM]zbǻuYK8<*ǝv۶?P_ K_6Gn]@S"[s~DpKq?{xv> ,PhcY*V)_6‘&PiK*GuܕIm7_m<" ID| KaqWD)0JjL ZJ6HT=`N]}0 1 3?5#ွW䚹X[%OcȕU3cdU!YT_ ~kd/|& xeseoɘ~H+8+c}`/@+OF՜mq1佦La3U 0ZBDuu'1-f&yjv/<{_[)4llk)1\7 и5gjJ\74<*Mx6ɈQ2z7E٤׶gq(a-c-JMFA l Fr'o\9aR;Kz'+H}\:'i#K-d״~T4Mݫ(d!͆e >2VV C7:E|%u}k/T6 w WXUx_cWRWcaKGGatX$=LtrLb-K gԤ3jxdFtיF| u} =L\@0Q U w(}2G՜{eVK+\ܭܭmk:s&KQIhQs}fqQCp3uԤ"y!;uA;R8s>;ݓva`=[3N޾G'~ǝ=u:vNͺ j:%y=h=ҹ)p T, ]."dzrQ!@W+aʤFW-x awFA\H'2}/F7ϫK)@R5XQ T{Z6,B/\U-Aie#>,-skC՝ʅ|I @,ۏBQpRŚxTmo[<-on 2? ީ46jkd2X}Y[A&-WP"`*0S7d?o sÞpcCv~5bY_x֗UT] C٠mFLދ,ahʃh:\1ԔLILY,<=D<=âpԮ&aePEhͰY8z=$HQ="TD^7qY˶uz++2|_?ad(14*_L'OeEUE 6GX% &ߥ>KPJnŒt=qH;C` s*dA>I,RܖG FWyV@u^mUL#\E Ro>Z;ߍ!%A![.dR0y{;PX<~UaQT .U݆4^ = lCHY IdHR0b" KrDbI'"(iqCB&a"Tds$5kNME^#J㰐Ui św޳gM)6S&-m; Rsd)'! -Rn 0~XfIקA,Nt~MUC2](( N Dzhf? )`1 Joa=ŌVfح.\WrxVtaN&U*^VEYA_sqn^Kq<5FtMɽN &VŖXLҪrO8v I3Kh8h@/2:i1fےcg %P,4 !#J;t(*$+e_~[pPu9"ӎ%h*Yl>POm7]S!}]Džfr|MP%19/B 㙻A/C9 ٷp]Ȕ7>^yMY#=k0P"Z~zDFN 2tjmrqd2d JXkU2λ^z!@ܯWЏ7Tu?ۘ"PDE,QЏo}ԝB|n磄P |#ͣ9$6Jڬ@Op}F(d CD)\V0+. E>x^2h*ŕ ~vXzq) gà%dUW# 8^u,900{V攴kL=(OZ++}aK(Ax?sS,ќұiz!h),tr!/~BaƑ&&U#Sqɋ4]* t&Y89NWTJòVuΧ0?:PQR<˖ |@˗HH(R2īI|ՌѢB \Շ._jx|l\]wQaܨ\5E퐥TQ,Ks9MJoS_- P̠/J*iV7Q(0LN8FEq)+hE^!rp>0"v$ITGF.bI$wp*稴o[NI{ G8]$[y8t@L8 za1PSô/f j.ËLWj -K*6Y|-yNoS<^]7z#cKA´(955~p3,zI.Dz()L‚WtXf/Z9_2;Ys9r0-(v0 '@PxdЈQ i-4Z< Hل۞aIa]hDUz*yLJ #7/LOqm  ֮]K|v殸-x#t5`B>8K9XRfЏfs7&FP4œx}jऻj 97&R{pE*U'UZHXLPڀZDg9UD-Ah8.1Nhm Meuzo0TS&5< TrBLJ3Ǵ2SǛӴ09TPIYVInR㟩JIT ;]TgԢIfhƜ #k̏#*N~/iş >qiUz +nȕM6Q;>}q;{3G}iͭR&t=J3.l[ =ҪB)1_d2jo.(Q ݡJR*gbsa!po11%>,I<ޅ$P%4IDx?]wDq hعqS&%T=&2d@sqGlGhJ *=\ Vxnے)ߴ3nҥBkݣ3.`F$Kr;oB[_6VmR src] jczT *kڊȃya5ŒS.㾐VQ(QM\[AdU⩛AklR0ʂH Ӟ曱gL*&zay)u)dm z1U7pUܭT! x3݌HYLd> ˤO5%)* 0Y. mJDW!~*ސ샛:)jceWllWY* ]f3-^ OW Yp쫳E>L4nx Pz+ q_ т^tqwΪ˽yxRrߊUX@~Y!"*=Y_c M}2H1=G(HI#P7MMZ}pf0?} S1nts[*~VvRvbLuC+daZ#KM3N«0 A{'fuy͢%#|b1<)LZ22|do_Q$%ΣU<ԎHzҶ䊻0NO >JmQ!c7bU.4{*9{\!b˂_ZXڦZ&T!TUx;Xb]5BV+CL[Zre}!lK{qJm,OIqfgyH9:%`lMho)sM־)V>|&sLiREgl3#x9x-T6P –g % !E1EeN[ 2io:cLf``sY2'/0N(3@N)4g`l[8Qt@+`Rp׾iˤٹޤZ`N!7a4[`T)2Zj6ӄ5V18[~bNRAⲢ wu0,FM=\V/hHCS]}+۱̟lo{.ɱj9UUیWkk%Y  U恢>2E! GrZ.Gyx3BCGAqRE΃24!F-cǂ ]`F}phtRh۲s9Y8Sեؑ77><䔋Nϗ FXq5`+dS@ՠ^7) (MP<}.6]HNNn%ws x7Zy xITU"57e454%qjb|V9B$P]&̝m]/l^2K>FR Jg(1Foi WJ'QcǴ(,7OPi<i#hLdY|OM"O$NM!YEEcp,q{)%Y>gV, whS^* oC0І SW6ȶa:ɒ_^P(+XR =:;E.2# KΥ1e`[tf.rГ@X6TKg/ykӚ4.|/^~]o Ƈ T!U⌬Bm԰t`TBR)ʒJ(tWyOŹy9̽bߚF퉬eeeE7^e4ܨ0\gO YwɴLy=]DǖIfo>Z֦`w6"R#f%C: 9().麗mRb?˹kprKGŨ(fZ[u'r{@[ku&wpb=U:HwrKeU`&qY yfa~1ZJ> ք?S^U_I PiS.&5sS;'[R[K/csз?MD[\Ae7-֭ D`#^'hJW)xX˯lZc6 Vd!L6Ȳs-a-i "Aœ2|#90.PՒ! S ZJL'j` \V~K9(f_زOQhQׯV|u <:⇝i 'ӽ-ӠU7:^/9CқViŏ;;{kI+j+C`K_SeBK' 0Ua.0cR%" 7lcm&2h؝v*NΒۥ PwKd<[鮒 E4իx!}e%%޳I4Ȣ . .DZ3o8u>%+n½/&ˇ4?$x{G^נ̿.ob^qj1N0vNˍ;W#D.\98G#oroQ7,vޘ"ĕ^?<,Y׫C(S -~B|B5OSYWh&^EUR1o$W%J_}rZ0╏f6 7 zfVU<6-c-VNrϨx^\RDy[敨3ÕPf7ֿVj :Q=^t{RLa@\3Y'ߺq,_)JfݚC4ɧMse\ [ή5%rV~R !2ʺ߹hᄧ'((g(lp.!g)\(Zӝvфr\[ߎhNQzky\5dqUܻT4f{M9-A;C^7B|ٕƣ`_ V.ŜR/JwJ Uj*vv]䮀ТWy^MS蜦3= CF/e2`5G:F;,yՉ B#ɞhU/;!ew%Pg:hdĢV &np.7&`#+hE˳XXK_՝'W`-[Mbbuۼlۆx~QfV4{g>E4SOB0OpJܗ>SĚIMC3M Ay!i˖1'SҋEu!TT.a SnY'/wϵK~~ti}y-z<)&ݹ͍ l>+k>kknl'++Gj?4 Е@<|ddt3..3(VV6ZcLto S8&CXqoI,4aU4V ̚ &9Ϯta਌2o1ԆsIJ~#2_~ʳI2JE@"5G RcL2qRw Hsv#.O>"sgUzzL}Tdd^F!pWO:_=zyqxs|^gO4w)v=`guWw)]O89==x*~s-G/s}rLԡ8<:'=>舃j,o:;-692?Bi8PLy]tcU kwpԥ>E hv[P(='GX=9Nv^v= 'GPmWi.{Lsaw>%RS&UyGsˏ-r֕X]Z[ŵLomWV:7,yٯ|CBL[MT?若sܟPH\< 8>c^3ga$OG&H#@c6=<7dgd!L|1~nJS3F+W*$y)6N$e-(TR Ziu$#2e:8fAN2^ZJkao zR ĿԑISfz (NLv3B=)ʔ;KQ[^RCgp}B "a ޥ^d4Al͙ zҁAy1煨X[ ˃W-prHʭ}. A Ax[GcyU軕y#%Ou3F?~aEBo[/ꈥi I&AE!TzV)/T+4aIY~E}_EYU%+6GKl=٤lm{9u6}ڤN27'?01PK^~όw*+mе=U Y0 .SZS[G*%5i/qx'w&^Y/x_B z63kݗ/ט' Qrh"W ~ilC(1#*E ]=6JVYHPz9pSuq攝ܜn77~ 6fC_9R,MW'T-Sxqߗ?7Wگxu.DRG+ןsm|>/{B>ksuoW~׍p#^>ϫ>(@w|פ ZA˫k+o}ukcE on.XUX /q: ò,yȾǵsL?;%WO-@jqH:_>xwƊh{k;V=@_$Ѷ5-[.`j3~<9MH[oY2gj``}'_a܇;=%AR2U _IO鯿^ B߶hUl6j'yeuAOb``jy) ehgY-|I\p9\Z\A/8l`էS˒ Qv_O?$S|*u݃X#+OO$A'I~F{*%gyzus*` nȤ25Sm21M9=퇽<.{/w싽{=BpX;ٳxTw޿>L-q懣=1]¸ώE\cE8H>c'!.xXgf0~ 5;3, i[M, NwNNvv\NQ'A)eM?B#qx 5'clj\-3_3F}:~yMb;Ҁ^$*|_ð.+;i0|;gOU0wjFCq?)>xz9Yq?mIܣEsГ<}x_3OGwjmc#od|>8X nD7D'#QD]d[‚Tdф'o;T]7\%W! D>n%. yHDtOc>MG4D2 n.=4ʎz(~'l+WVWְWUϡ\8D>{ K@!+b?@pX̡' R@{- :N,T[p8ē$?V +AB{ \9$6ݠG1 t>bQ29 t0}%8~i:Pp0p4f;4ԓ֛g%)oL,`>+AQ[d~^DZn7b ǻ4޽pNuq B^+ͦvߠI}yo}r|qC_ bkU{gix=t(pG@E&hEc4H#QU$%̫bϪ;Uٟ)>)/~l]H, f˯ObObhM,i5^Wؕ^U_vL?,Ja _ہ=ɖNp^[z҃TR4b&% r,)6\]u}4xuo$XVYyz===eFGcqs7{ݓS|xΩR B R15P(0C h& #_[!ԫzBMW7V微 ]_{~pffG-ly xj7zя7R:J]?oU0Rp$| &?Sko$h@lлzkQکDlVm^2fe[e ).Ie 6y> h'so^caZ-ߺW.֪wʵRۍ{ٲru >W[wwI7ǞYe:}:٬N6+f}By?꟡V`Ԅ/]b.H|;؞eq7;܃> 2'|ޫ81l'hvɸJ&w=9xF۽v?<o'6&/G> 2 Avv/-*}d'j*/VoS{WV=F}%cub9ھ,_x0 N%[bv8rAiÙ{SUK{p k ϶t":fIeSffU C-152}_ߩՕ|*?&w( TM/eѱtN:l!)ݭx~\[fk: ?,&?|c܇(tYI >8ܩjdmLy]wzP7]6gk#G֜0 KJNI䜗|VuKӒʖX1]ϸ$tgG7QW٨qK?QlO=}s= WrPq"+j@RHWEF3p8Jp0,.ȼb³֞c3;9V_ 6{(S/-+'8TE0٢o.Ēo*?,Q SRWE)[]kNR`5R6] sn#ZxŔT-)w5jDT+#i>=ZS%aL)9ʡɃzt q1_؃odK=t<}haiibd[&VX~$?d%߻+ K0׹tbzd#5G?-߄iP5^6IEwj)]UO`+Z,\1&o6'q2hRo4[V߮ NYkv o X~дVڈne11_t=$UX1h)V׿ZdƩOz[nBm+>mo?|qδHʮQ>eOo`\[ZZVjMDpJ2v8ޥ☏phe>%LH@gXMնjԦӫcP D黿ǍͥognDʛ@nBySaB@%xy>2/ g~>eH3~0HM M'F8}>?[)A*v/npju^vkjY?_.|'??#X}i! C$nӤ2ۜLY *Y׻J2=XeYXY2[z16ǻKJƴsu!קTο.my/sߧ|~/J9F/>GvO*}~_*}~(}^#A,>8x}7Ûhy<1Yб\ @s̉9ss߱Ȅzwb $w{SW?"Z}Svo?|8?pl6gӝ~x.~)H'tU;Kæs*4H";YFx[/Nv_輂;ݹ9(a0vg ?N3$cR_ !‹m[A6ӛ8 z83O`$|0Q0;cXƩ%" }ezsǯ0g<@.WR< < 3#t?Gvbӗ;o;LO~̀i ] ?y-q 2Fbj#yh22ٖɣs's * ` L!9vk?rV7OHA |[J.$apu) nUKp$u;݂PɆn/*".JI>_.]&i+)b!J; M[tC_CEoz$,1LӢO+̏5r^8 E$*H'=̪}>n<4@5sB9 æ)1;7` /&&# Xac Pl!]\<F0EPiƀ GCCLG o.Gc,ЃPfFp¨S8~dICiFq s܈ n8q9ߡ̞qRwMxR}Ljb"+R $OT BJK-a[b? )J^zxxt^˝?w߾A]`\m)f/zBh`Ɉ;O/X˃B-`'COy{{O^I.x$wA咒LL۸L`q%901H@PQFU0R X LX$>V@k*2ʜ k\wv:tG4ӹS6`3kn2dc_,t,/0<|gw{.::~Q)9UUi%A~ȇmOįp2 ,GET_|U'B?ÿ 5m+'<>h4{NhF;;| ۩Zc^j=e}E`}ˏ$ߟ>8=zO:kOOv{N=LJk:-id) xl%Whߛо_ }@>%vny?^=_\y8}ү9 a @~vtO[wO]6s@x b+?{u<dvl Nv2DxX}6ɓCOfmTN5X]^k[k+"n dBvy:t 81`Xga?;0t4.A0A 7p<ܲx&#IP ^9=E= &h9 l1RaJIޠ{->z|l-&>~%6$ k<+lj 9 ;[݇%XQɁ1 菓bqQ -8eɘFv<'OU܃@N!,rOk%ivrefFIYI`%7ɏ?u?R}/iCvIpiq(L`_i| AVhߌP䝠R i"L _\#QtIc"xԯV/bJIlEvlGWV6 gJ0vav&9 4xÐRcD|%KY i$d=8AZ+@Vf=ip` ㋐ ʍߜl ":8.p@p0gj᠙~"H?&NWYm%#(_Bbmu1OY?_Mblkeekmh՞>akW$ "%`SK` Nmyx[k["d#TFQG121x|+:W#~ʿ=L?b:9UOu ܿ{S=WlhrS :g˰^5Y9ⓛ~1L&On)6s wf)CWW=.?|.T5lNQ8;ߣ"\c<s$5!h.HǟAfeB9H~N8 Kz/+$ھM1u )|!gOnǹʓS|r󏊊{ocvɓk5TF$x!'=(@ڞ֟o:K߃GG)q9Mg 鯮H1S۳@xr4Z%!m%^ң'~qs,X\[!7/l|}}t/O݃X)ꛛ:cisui RNLѲٕŒ}Oˢ՜ n@ =l#8-3E, _`-1OjEiˋ yӚcA0m}rډΥ\F-|Ш>__۞PkUVM 4eݔ4ҼW`lΏ#wŷl?}[t_{}u}̀>H/,I4^?3 n_"Bv.&&G42,=͆]YFCb0f 7RZ6 .?5J8=o kCڊ)T*mp3]`J*Z8eAB+r!!)ob8Ͻ XA1݇/m'AAg-;{AIA}t?[#7vDX0[Q'͵OyoVI ܘZ $SB#m$ FGЕ\GX @} ~z\ L(ˆ `-{;i4װ R_-rWaiNzv5z `k? /Xջ-me0%7} orߤ_W|*>}5¿$/?&|%cNOe7,zسmވ>go|^]y)+jgXW61EE ?W%)4/vN:?;bHٯ0@91NQ" `7cxݑ\3 T4`u$Uҽ NŸIozoiT'*Cn淫+]')0V2 c~^"+Ǣ_ R,fY(^AQ=[߲|وVW%qYq<~Ľ7skD3"JSERBKPm1GP jV 1B}z#YOfĊϽ bˈo,,=E z{^&_K!&{aQ|\pfQo3ĿK➄^8t#BЯ9ZeZBK TSXJH'#z'C`! z&t_4b\ps#h- Z?§anI'$).%PۚL@ W$8^f GiFc+@"i ois6XnXl k~ްWTaM5p9])oq~7`Cpڇ/a*V!Q6 u.1%UI -e)fݨ=<~(RXj)TPdٕqJZ? |o`t< MjΣw_XR6= drqI3XxI85 >VЭP'z 2 @[섢Je{k\rG7 U%m>XY<|?PCZ6Hq5 3Fk}*^n^}%ǽƐcnC UP״]R =\Bn:-gxHg8J7bMeU^{YЭ+= ǰd.mGvUbQj kaK] VG0˴T_egW%p,*+3unIG)c~X M[ZR5R @,}#FrKi20Ek-V~{Z}jtOnł`2&K"tv,٭Ba6P7(է1 Q$YEUD&E>e_^=~0Jtl0v `^JdEf7^imڤ T l/%sd94:$s.=3*% _e5@E;yHlIKp -Sc_> =ߴ͏Jo}֮62l-ĸ%r-߱rܜs{5_71 qE܍x6& v_>hQw0Wqø8o EchZ+X xr9&PHyTd2k`ݪW_X+A"кƭYCHA)H) L!B 8LJc]0_0ClX"ea_UQ]BkՖ 3y"Qoeˍ_53˰V$>*gևh*K2^%,͡jTNĶ?ŘfNJf<⬝$-p%W3? Va݂?pUwuM@_kTdO޿qCRF4?J;,MPX_{\gɠ-1XX_]  8ƿ0h/8БCY:Ypн`e/ZœKz6z-p KFW|/kÓa A\2 ǼU,k ly@rsFaKǝi|IpZlD{7KwLDpklWRZQ8Qa|\t1k:KTg[# u{nJYmu +7"廵g^+^]yss+?>Ǔ߇4iǤFó׃5~؟K>4 aGu77S|uQ_e{'r u%x;ȾDʏe.dA %NS``L쾟)uKv $빾aZ_}tmum[{{.'ΣmYM9̆ﳅ_ $k ɥ[c&k͋VeWnӊ+"ka'3/$BבAYAUѿj?~ut;=ʹ(mhviyf}bQmgޏ4_5zN{$ܷ1W҆lJ30 x'Vdc0h^<挵h7Lǹwvv1/oq9lD:aByj+-nekhžh'nX(q 4I4j#+0.B'cT,=[ qqx zr>S  S~gKk-|p̮xNRigf-lcsmt\V23X2Y"s){Gs  P擅%$iL-2'=<@Ov.A&ʨQr!<  %n_~@/ ?_9FmBy730r r4UC1Mʻ&e#dLJW;*t"HhKl4 s#!ᴜcF$`<\~ql?^pObs\iP`hBt(ΑC-ղZ9*4gH,!.}h N{ ^MH1 QP`]/۽8UpLq9agW(l[(. #Nkׄ{C,t˼D;PNijE7/w?f9D>Ȏs2z\@ZyP# a hͽR bb*+s5],9݃V0f]^R`4SQ#RG|Cx\hؑ&_ց{(ݫ,1V%#^例g*Xo#-7EoI/P]&;w-I?8CUn&Xo"MN)P/ns!MCp>Tp&`iz>A#aJqѠlBNźsPcXEd8{ؐ 3A ;+l ~7ܙE=BCGW~U! r45O-Dm#{6me &&$Zm&j8dV 8Lv I9Z3D{ų' f}W1+xp>8Jd~"Ky>PƵh]Tظ`ֽLi0iM8- "8"(Q$%Q$JwGFրx5U'bĢZwlRJ g99P cە/Q*_`*£W_j#k?ekv Ln/3 og+n_n'*QWG ®?o򷵵Ѥg_O\,Tx@ *zk{{kzS|UYI Ϙٖz"[ PkB0jաRAwJfN_ܯJ_v¿hT[X2d00ٖRu0Wc?X?O8u* Qr!RAH&@bbdt:%F 4D;:f2Fp­R ԁ|+p)FQV v9DKZ 35j!\kxH1o.D¨JOqKJ GTkˁX~0< h:A 'z?egFS-?;2Í( S73M@r`^7"b؎`HpB`ǡ"@7:x[W, jgrs1k"]41k 'b|Xrt/F.e)נ=`vd(iģ,|QJ";=՜j* ȳF +KJjԢZjeGAFw"5L;d_^<q !FeNALQꡑk_ĂHͅH\c*G.[ bSj9yCu8DYI}53ZUo+6Y#xu($?c]Z&$0/QÚ)!n)QZN|ՙ>&^T ѽA"oӴ6Sf^ Fm_՛6 7wVGnJ@!g}egZ9Yw jZt-a]ߊJ"7LH%@%Ez*GZ`{Ml3"/t7^AvaH+T3IqHeQPmЅtѥHiV)-AMEASynijL(a.FԈBESR ht9pˈPB8rg2A`>ߋ=ܪ"x|%8#t_x<,0?n8κnkeݦZj[.pmc,lx?$?m?m|}joggge~i7^#E֑#ݣgBf7QH*Aļ%1>A 0Zz65)EtɊ3#(F i=Dۮ Lɯb6|u@= f|@X#zԝWFpOsάB"p -$s-N)A~ޯ"I0$B4' WPP"u=oOơ\KeS$l AllC5ϱ0MeYhY v0K(W,#t6c*΂G QKF4ZOx|>wT'"y3x; .cNmR@ 8YM=0Gܤb156QLQ{In)O1m8d-L&H,e4#6LJR%2g`/F u}S'n庡1x3"l{0ъ/dIh:&&(4Oݽ5ZIoSxjU')L0k)EnWw SU&dPcs3".0 ' |#f- Ѐ$HG*O\\u|`WdI MaiCy$vL`53i;-P=jk>ė[l AP:* ٩Ar%Sʦ+*7QfI4 26{vv@ X%K+ Rܠƣx:I2C*8.P@\xޱOBӱ7ɊTƤW׺B2 C#(l wT]RʗX#=4 W0b'}5T r po#ʩD0"Et|l?Tƶщ"\EYE{: "mswy!jW^WS# Ӳ6dcfře<]MLfeZc՜=&ᳳD且I`i˿ S МBk*k&g SHDej,ismڮSL#&IAMV o<ЃLU 8od;"}7n 2AGj$Ÿ^mJ3l~Yg1׫ 'xtL Z|J,RXSue-, V0'?fiȇ0IwY:TIWADV[ΟMh#e p,tr_mTnRJ4cJtz% ~];y"a]Sf "c?u{Ir ՝yZȧ䀤|¡*N>@xsg`38$T`~cuš.oM#$z K2\YL.` ʸ9ҋ/P_Y1n z76=ƄEac$Z*T]11UigSb=ل[K*A&[.> (=A~`X30:Jr#eHllD>-Iw/w]$BtY9!PD`C*XhPR1 5}ru= 0Gr)-W*A“Ŭ"seh ͔*C( 6$#%pWRuOLY֩%?!i!%KJjLؕ+"KQk&McU%a1<}]"\܄siFmΓ-]FZ?n!Ь]sGaUՊI4EV(`a+6'fH=9'ž:cؖs58@4uָ U=Jo#CaĜ> bCRvƮ )CcR72^t#R!cӖ~w}0~pa#NK}5tN8iE_55UCpjւc#%^ ӡ B˩QڭU+x]R[RHR[\eEυ=ITrq0q#?wCbiޔQ缝fz?y)]SUpjn>!4;\h{?it[]6ʯx9kf3}'Qm:JI"Y=]DK"dqX  S<š31%~c36IbnlkKm5jl>Jxxyh{XVM*cdR0O7;퇃gzO9Kl>zh~&Ƣ% ]AFU1-Փԫe8'DF ?l"+ #<- Kh02I R]N%x^(&LץN0AYT5xku+J2\[y R/dWv81@H*GӞ'qK8W~fP)HXdImSђH\jFU˭cS5疞C|^Gs"\8:1]I^.( ⳿QpsY2AKd6&+N R (/Ӝ8u&!@{-ULp1cq,Æ\4>_{H776p y)l_pu[ wțJvڇVX ujAZ{{w{\VIgi:-G7G+Y'1`+WۨGS'EJ󪁝ؤfչ8( ZS}]m5LqAi8ťD&"Tw$RΔʶOE 5r遚=_볯hiϧ)/ٺY?Gy?rpsHXT"`C'^~Ifh QXbݧ y߽U,K_8I޿$xz`4jg$~_\{jh˱} ajv&(oDh -@9b-f%OcLdF]#I8* ҪvlD$Vx,Y!(vQR.NZ O 9#S?l<.~Jef{&a'S kF'1dSf$ sCOqʁ^&_pjp"YjOyiJv)_I0>RZcY赕-]l4ԌU3yP˂XoZ2*3Cc_uJ>qYX,17D/2ѸRp\7ٓQ'-f'kAoɢûx>xQ^2.pwat-=w~3(8aښ#{Xa䇑˜tY3o*Z B!hpq)B~tk_1l4;V&,)wa7sUW,j́9oͫl0mr8lc`pPwB,]~vxLe1\̦Mm;P Ñ6P3#G4ľ IF+LcaʍK8 12mb?eaO(ȗ ң\ tr7@y5Ms(4#6Dw&LY?ᝉ*ǨG-bKu]Az46.̨(i Û2MB݁~X=g>M}ub2O8qMɥvSBJ79nΔJV&?@כwU[ey`|S.+f@?Ql$)S95?[wW?lum_n2dIjf ѧUT9UOA)=}&B=xsgDH`\$|qEC493P|"? Z6)tlѓg+i~뼄 'be3^ia7}^&sK ,`0M1 "/D'=z'+XFd iiJ Rk.2ZPbƭz&Kn>p0+sAu9~`RJXk'pA T|"vmRm`IS4Ԫal-}oA;YA)}mKOߜf#H`7B7؈h 4 BVsoEr J9FexKʭ (*vDwV턒=튇sϑb"Fs ߉}Eai .}w@iЕwXԽr]7QQųʣPGoOB ΁ɖ ɩ zhaDw tGI# ש(txhL[O$dyM%%mPN-6M+ 4IY3F'WWe8Pv %WѥWЕanr d]p1oPWDxw5yW)@|Y,Mw[(R]mP+(wZ\gѓ|ϐ!Hl˼ //Ԧb=XA@]" »!XSa֟Σh/RxghsØʧASz2Miq=f~oγ1r 9٪FK+}}2cf6I$J/e˻]3)nΊGADf seFS_ޥ!(OZ^0 U NKތ^|9+աДZ\%Bv?IEbq濯FBp%TFINpyQll#>}>9|XX%~Ǩ%$ 9shЪ?Oh՟$n.Phӟ1N1;BSH3T_L[C~[$&*Lu s+~jvsqC uC}>,|P-9lsHSHWt*ך\z~"n0I])l`2X:G4EK,EG"ҡ~S?+~.=ct90?Si@}~{稝>y{'M[XY~> ~Wwpws|NӲ?yjFﳂe[f w~([0?vG'G\R+K{noqik}sSGrZмCzir/,Q?&ܓw0tbYr^+ZܫAG/dUYsR )~Iݼ}[+=#lWP5ي{9~kY"<2+W/1NW?h%KeY̵'Uەsw]ڥwOGtiK܉J8vI UIVdVxl%-c({x]*9IjNEЖQpHiDjyɲ/cP=X eQ?,thq7Kg=x4|O[C~v$U t$<)y~o)bVM@bdP& )絛5g ~:%H=biA?,Z>vsƇcsc:51u9|SƟ7oyS&0M,4I,i #>L\R1M oql'NsHo)[BU_|:>V,~uNoPsux)u]U\gRjH*L|eg) ~ǂ[;o翠6MD]#}RqKd-6/~z@l}v>x2D`u5]O_ F=:+I^Jԡ^h6\agjfa!اmii4QP65.U'Uxd$)L $03o` TR^ ;K@C̼gX8r*,?<|gc}k[s_?7%llnvvoMκCG;7vscKvKpC~ܒ0T]~o?{3?߀6ojj6vozG[?wd-Z -b2 2ܑ|@R #vic})*Ȃ{>V Y7?<C$™ynk~w@7JQ8x'ofhϺm= 7WPKK5LauoEoAhb^W(u;gd1=6<|y ddq &OE&PqEwz'L|:{;#_\Y_2'HcVzG6؁Pڔk }sos`!/jk.Ѣ ، FŚ,33S*ӏ6"?~Y?Y[oaR #-%߶+"?5ʖ>COފ0T_lEWGAO}]\d>*@jH)%G1 bVZܻwϲ0ap }zJƲTIGN3<({qfM[ dnhv^B9։@, M{2UxQG$4vLQ8|49Ǘ_z.3 >X˒h"ёޤ"?˞`cS%;3>ixV N?j\o&%)uuZϑ̌ XIdGÁk90N&d~Ylǫ`&vR9c+ ^vi;]Ǒ-L*c̗6o7>A;O7SR^pESWtD7uYA>qHA0tZqw lrCwϐƢ?ƓHkڿMk0xX8LGHS[1@#D?\S Uu߻C;@paEW 5MÀ 1Ϙ)NaEC%!+Ucc +z>^&0.0&zEkm"<Ô@4@ivӜ؋Y3KO0m$hh @ j(gF(ZXL0m !, ӤQJg2Y0;L\ƟӠG@A@ Ľ~|19貦h1&9L*b+P: t@RÆ%! Uq8ӀD=E}^O"mM}*(0h~ dqF+ 76( Ѳr6=g[}&ta^W ' >dBsb,|sq4?VK{Tl'QPz^Zy!/H"] h5 NG jX@IfPK ikal|[SC?SHKd"#dHZk|@bbfdx",Pdso8KĻ7xcUB)w9H%{u` PAgX@wJBB0DQݠ ޓ[<55 p"Vq/xԤAl[hq A*G>3PJܠ̒hp q"(_HkBeS  ]h{Oɢ곪YBFs{Z4;Pxɳ)h0\!gJ-OF{Aw |jVhH#p0/KX`vk)@DJO~,\"%'j,\b5v%.ҶaNZ0=zVkG\]ž&jen_{WR!Z$wtMDa0K!h (M`a֐;$U!͑R#ǥ1OTCLY~,$팜.E0n59*~܈,Z`,Ԡ[C7[k9 ," !> ,9@*\kww;}q2޷NY R% Ґ{>u$K%2-4) .-oFc,m[d8HH[L"}D4I4F_DI%BhVVxOjzY=ۥ5KWa22L[b=~+F|:f N%E^Nj0!g̮!`VX|bRby4`$ 'X>㺄BLeeQk32gFSk{_(6C (׵!B1Q4j$1$uM63f24W7A8MPD°+FenmCnHbri43-;lj5`.Ac{BcáZA*#]HuVĝ^13{ -7PoR/"]H{Œ ogb5Sh),0Gmi0 H nhP@9)'z & wYfV~qzq1LA$O볖E , ( ٜ9nQjYx>ThPFNeNDF8Y470wv C8fL:GAF?~?/:0svEC;:?:iXы}~q<>n}ЀŞ5`Α3Gaxk_e1Lv {_h]Zyw&ie,ۀ76YiN۸WWG0zLϟ£]yO;] ?!a}AN'oAOmphkޢ h zY/QaGuЌ7!xϼ'їC@g^.:&(+Oӻ@YY??ɗk=yˋ'ܒ7ꓱf˯Syx=z}K"z,-4˖KW/U썋Ugj.\_2%&Aq RÒo^֗>qZ:Ayk~BZZG5K<Z tcs܂1ol~P9DP_\܄x "#7 &ܵ'$GnTMd2p96[!Jq@lף@|$t@j!Hbă h_Ǡ'/fh@14Bkw+BZ:":QD0͏`แB?r )|,}e%k2tN4Lt$@c1VG@(SMLY#t>Q^X OpcXLX)p0U2'Z;}u}˸GʅKv!LOLۢUȿEU}~B Ӫ&W'g, UG6c9W0Ps gyՎ24O7zC?$LK!aWQk}NM 0zc?zC6Tk`dt}=u {%oAd3׻>F6-da#VA7hY˅;A| }gaZ>6Ԗn&gcv)<0pw0iΆr25*Rb. GahJFiyZ-wZbA9hAn` #a:6#f^V "NwD0 oYpn5 03 diB{LYs g| 7!2>!^${ڏޮal 2BVi%rI }dϏh2-f~2T $5׳OhNSgqM%lOyNV޷oD&DupI#;'f9aE,Mnq|t:wfk;^w =*4ʒUlltfI70h_?u41Dh",Bip7T\2̢Nh-c鱨;HS& `5`Iヂ1RDLgE$USmdYA 4I64+Sg 21nM.T8ө23ƕn&7/N;//_ww,YK]G~E~0ŎaܫjVHR*s)JN±pWJ ] a[ar?`k NO_w4 PvW;`8Xn8?ȱ@ hgX1Jj=8eugotW6a-%@oZDbJU[/Y"@OS+iHU"T^[J#1yP蒐Q*c O\2>@!K '¢(fȠ Ũ"<*dr8(j!zi[?"Ǟ.Ҩ@ ?moɯz1W"k+/)Ɗ,QJIR4&!T{^> 7nr.YUB|VR¯:~W8|_e~tJ[6.>npMm9߻q? Ml㓋睃=tBѮ9d#.|9UC$ KP]6#2%F?FQ )!r9>YIqҢGO cJyĄ.s`&1( wOSK@}}|zVurtY f1 ag51 QZ]5d muϱ)GY[W8mq;E8aa~9v?ܬGs7(nώdc{D G1[O1HԄ"ӋDx咑+Xk)~J$!Lfς?KJH `JyE_(.V+B`:D81ݓN>m(K [Pi_zq筄kkkCX[[aQo )m)R-6P|rPejUZIQ)CR+2lQ\1\28 p0%@Ew1WTr_iOS簸t6)*!l6-B jjqKЪL-#*3-@9--2VEF$Z\(IQO(d)gbIx V"苰d%$k(ڝtHK7PnRA G %f~e8duE;ch3siU:ܟgeLd@*"[vod3|g:Ρ::y$g?1y] ݧA}]2EeJ 0Y_j '/TH/:y{:SA_:@|RN;++8u|r9Ӌ"%N뒜)g| k97M-/ij6! FzHx=wɆ nlNOU"ZA-CR+O ^^ CBq#@LS"]_CgG z$AO5cxhhKD@+,cV)j<*9 J^V՗dU LvpkqeL3^4APeh4P&f"6p bawb]˯"'DD֌A~/No{T,O&bjt 2́Y՞u. (9Beϔyv-,TYU:8?˰$`ogK>.\ [^ˈmy/nl+#$8KQZgʶZBJ/*'­l/$>C5ÓTGo{U}0$=>MC饾"b:]eA>Tw6S,Ā26Vڦ f$e^L&&MYm0_xeDI_x/0CLE_`DwQw. ГZ;PĒ+`?h uWȧ1*㼣p0@!5"Ci{iY}5&~Z]"?|vzX_iT9k%,dEGgAXLh=ǻ *^jm<=fTPhE,^/6QMjUrұ-Ը֖ݽ伛h!<3L]RZfF IYĮrɄ%\j)aeI<6$K({"vxKX#ˎRk͎ifS9I7bg'4y ٌmWap6(ȁ+ա2&>SP=)LQH)%+1XOU^ea.VcN1Bmv9H;nH+0 v/O;G{LJ'7LBÄ?GXB0!ĺ|! _N"'l*A!ɳQ> QIK\S{e*̡5)h8,;GgG@4ty݁m:YPb Tp%ԢܨEm?Rv5h9 q7\emw/G2sns]WT>&Q ˍ8Op%T`Y!-El@^EYbYE Dsi n4:K40GN"ЗKk#p.'QFy_y 㰞0=;tMH7rKqsssP*>.OHua0eexT)?zM,th%'?-"L*9e]nxk]*.pi O4"ëEK.pS]*wsi g0դ9hf69<Q0 8Iz59YiˌZk_4>>AuS+kbvd$N6u@Lq][67;ed2=zu`VlO++%j R _DZ#QMKsTEٵHcG'3sN#/?'A{V9Fa+UR+Gǫ}ube,`I=+^Z8 6.9xq귬7\v]VV6o{'oud:[?GsǪlRֈD y?af$NQl~'N!B۾R\a`j4"M8M,G8WӖX4,aL[Š(d@r$*qEaHLG35y~ƲP?b7a8wҟwNqzR'YR+@ b}Iͯz\ «p0#`0R)?5T5!$W]X[* Edg jf^`~2 4-;=kT%[o.KY-岄kҲdgY2(qyRkMTpclTT]+0%nJ;=C5ʤ|ϣ OPNKfYC\׫1K6?}:/)CFRl Z@[qHG [P"K'|ތNYǒ7V>UѾhqJ fRF!^C8ıN{L{̠;gzp /L)َ@DDLYLVG11>PN؅fNZO/9GV vDwZF1pcY#YQ#r%ˣE ʐD#N\$jL; $ן{IAǜ { Bhf;h_wFXBwM5soI=րk0)/\R2ڇWWE]zY+̉U8sq2D܊5.8+J"9`{ګ8BfJjO i[bqsY-ee?='@]7`+ɦ}L\3>y%_PWW5Gsr@dqY7{ّ!LHvDſS[&֠u1눍V&Ǟtbʎ0T{36'@e$U[mp>o:?}>^oaLd J^rK)Rtq_@YN"N\e̺XuvA=>D6? +ےO0$ ƥ]`a 5*.&]PHQE;k0 tMhꪘ-#xSŜB]J6<\*VNǺDc4Ϛi NҍX+a(cP .ڋOC9@ot  OjeqpG 3-IMJ/R~Z:Z<̰5L-nnad_~rV6PǪpul5MB)̈́i4(οJqg/UQMahET5@ix} j&X{[[Q# 6p(ʛ‚z@'Z,aIcL}@Kn-\؂˞>dˉVuR%N^_u0sC=hI€}0#زiΦ*v lG )%# ^FIKVnr52Gl5|)}9N@GۏdzI$=;;gy+*B/KGύVks_Zقh;qcRT-wj"6Jjօ7 YϖE TӠr5eE0Ϋ 㝹 ++(jJ笮 ȁLL>Z?a:bk }Maq*KUELb6Bt"C@f-a_d_vQ3#sQWɞ B&4O QB_8#sx!go*.$Wu4M.fjaf ,p)ぶX͖o|/S7_BZT[N 8=S#O={{}_j*IuScLGQfd`6lW/R̨Fi7K()KaTTn]ƵK<); 4xa#(9]ZZ.79aLڼ&) *msjc`왠Hejr)&M䌱#ʈdeX^TmPLIb{}Q8b!r2p t'ESl䍩TBt#pV4Yص)FWUw]b-P_^8lԲo V"W$n0$nSjȤi*=l=)rMsi \NaݽO^f|itu(#j?sqw(5UviTf-̬ 8x!AXK|i݊dMR]mɆ* EJYAXqs^C^)^rË݋Iޤo];oJGuX͚du 'lAϊ۵ sxI[z % *Mץoj_P.%6=v9cpq/S?0~$Op' q0ƷqY0v:) ARPsNB:2z;W0M^\L}Q@V}aixC}WNɱZ/tgcC9ς>Sb]֊r)1eYڌ°(x:7KRpA{g10T -Y=^^SoYzu#&ca萧gwRj3%lLJ'Tm&(W˶ulH:6Yp1=p+ڒ=QTM}ሔ<ugY6ʓ62ѳ's[VL}BҎŃ؅A(Ǟ voАr%cQ$*ȟ)ץUrnyNou`]J ({v|n`Uj$JXSBW`J<|.ESogbKajTS-^ {O3i[Lhy pѽLEQ0p"ţ-΂K1El^i4O?0rB15S`F,/F('EƉswA@q,"-^Rclа،66BbM˭^#d%|6& !f%PƅZ:j,b;@CVʹ0J*!%^~ Jx6hZ${S]R>={dlZp Yr/[LB@=Т#9 n [p܆ OC%wۓlnm?`AqqVO#$X<[FD3!v@B miL=Dyl>]vop ,La }-,9#m# ~C\wAp$Y2B=gs-P|4i0TX eH%)wf:22?:T,qlwloSJq!6Ϝ:mb}d p}&S1r-Q.43{9iodr);6 H ( @cX@ZS*mhݽdFY4 K(D{{ %,[49?#L(YLUL]@1+eKĮ iK+p hn!0V(gU4IL·EmPNX`6d"5*s{wg%ޛ Xm| _.tl+ X/e/ȀIplPρry?zX4-}Gt"9Y}D=urvEedwJC0FoƊd:bN49K N~{2}iIدn tnn\oP"'r 6s .SdQQba麊1v󱝵AZ!cT^A#BUI.񢖢~_DiBZAj$ΔAguo@qۧ6@?GJ^E $zjy Ԓ[lkXR!D{IP~.+O=kL+kw/ԧ\~tbT¸X8T/4Db/צ W/`Bn,[Mu&Y2gP2eq(S4&B(NK,uufvU8b;.3RΦӲg8}Q^匴49tlHY괅K'_!&><~ɽ`'ApS 5_~_,DW劘1r]HRyfJKU[e}f?S$$MKر%@zF ($HQQ_П\_?KR/TJ{08@ŖX0i/O}ߜ`"O+-bcv&t*us$6 SR^{d`[GU@d}ɹ$5 rk"UU%s-jJY~:0;"Kn{L~<((Ly5#.=hјҋ1 9EyD B9vhEٜiv!q2 ^f!G^}X,Ԟ׊VD+vvGl$ưSed׉ZB -TUr#iOLBFnr jF"RI:s3zyIzeSsE ^Cn4luB:-FzL[TþYsDbN6-5tC8,l[2˨Tcяv++A,f<:>sp[; Sv_[4cL.E\Ehv6(Ek6Sىw&JXEV 44zxo MV9BV[MbUvS.[_Xf>7c-_ 4 uY,1j FSJ ɽ"a U ۖSj8#=* Ü+sji` 2UyꖶS.N ̄E%jCx%%8 C9\:HВ˞@p+V ~3 łO<2HoRc됮Uzl3rGtTyjus+GL4Y!u1ڿA>e'$! J^MʻPuH:#E{1+'l>WW5Dx>\h# (;K8p5-ӆfr7$s/zi *;6Fie9 k:U'di#dJ917 %tG3 *r5E{Av<*cWhO("E!ڴJ'p1f '+g#VfWnq쪷qT{wU,@PڵC`vVic.lA$DS:[{"ucK$F@G> O^5c7GaD9̢S3%5ᤴA\)hIT{HU$TO?&O H> 4|}OU_wO*P 9A CjJqd:TUQBGW~XLw ۽F>uz".lߪ lJbv\rd5 YH RC@Xh+2칱ۏ>K['fs<-ᰖo83 kTg>p?n 1Lj̔das)a+}q I^Q^OO8}^Xtt.i'xջY`?bz3sph߄|Mn 4%nLzhSQ"$b[H,ŒP{3_u%mXɋ`b$R)OEh#nJPI~r z=:PNAPp>OCe樽5h[y[ d+:(cDԚwkFW򂁝@H+j6J8~W ldjEP ѵ6>mRZ%:;۰ 9d:C371) 7W!+(= ̭&jC€M&eWDuC5u^rڇT)Izў8_F ڮLi{>?rmVXpka^~15GY~3nf#yCy=$rQ.UQQ*ž? r6qHBd .[_ %j8 sSJlu.ڧ~BDeErMBԄ׾0st͘y-71r:0'8ؐsr 홤`9$'|N-LxJO;+p.D]^ l9˚ax{ߡAgkgkx`c{yxw?31y?p8{ދ|7E׵/LoMVvWM8g vVT'&X Vn}9AIjenPˀ01o70oGٞ%S,.DG bh9m UjDJswjoUvjW)&(VqJ}{ '^띜.]3k:;] qjs:>ΎaHnjIFq:'zw ltbsvb#$ߣ}M^{2x/O፷^d>h H~w0 <0|}=NaO]@`/Owi}}ƗdnprOô _t^a: ^=ώOڧʛ9>?iHhD:[DS]s-d _vWƕڦ~m㑷x-/ۿz_r),-Yk D;lNRHA\{RxOhLWb2Fs_i Fm]_ \ )f˩~JFBu{I 9KLjzB" Eԣݧ\B~F,/zNʥ5!о D!$~*{4 5j!"V^HmMW|>ӿ5?HM>#vُw?c0G`)pQ>:Wl6jx?X̑Dw3uVCQB70X#N={Ox"<{eGޗpcRh*MK wcQ , | מ5?sͱo<*?Yoĥ0DolDճ.wkN9wrA! ga7>yԲCf5٣$>cNPAut=u"s0eA@n?eA&}G%anݏ2`g{#omogmkTSOTn䁵͵M8ۏw#;_,kk<: ^/ Ete}BFɿ1nz;jjΚZ1ԧXZ/OCEؠ`). TcQHy2쫔FZijKj zTd5OJAXRcU0m8P2;ɿ$"bQ¼!]WU(܂8K"}]-.TVOLuK8\?ww@c΀\CkEo %7]l.@a^(" +:Kt:ZNDe~)O:MlD$Xi2%([%>H~/ߩ5 #AX.e_]R@7zQV]tǐ ixrV~Xd͹zENPO&5<\up q,(R2匸a ~AdQ IP'RQ`mKᜉvwU W ~8PЊ8 o*A 5 ŸOͭT1 R_wA8.FUB[,[rwZT1$:}#<zh\݊Zn[Dl6_<^_5Gl0B pqx*|^G9*BrrTs2!xGHt>\Xm1T_u}M,d-ӜJjh)$'ݐ)cw|i~,^2rxDyӠ/Pz.ܩU_"c)I3&dM+J\:)\'þH@M΀B_04|e.CD&+D3M3 dґJ=Fa@J#P4`^g)ҟ0HҙAt( 2zп2OT6#8vS|@:kyW";`Xx׉M! d^pc AY Ubu (F`TfhOnOQu( /,ԣ jt7XPx,^! r* Ŵf.(EܼJ! T?Pt;Ș1P!p d%mABrjэRU KDgx]*ł("̋ZOQ8OYd}KAz 1mIB_-L qH%5@s; is  f:>Bzt'PX p}=, @EÄQ)RŨSi.\[ 3dbz߆ʧ$> dH/A!ijzQ!BHkdAKi}*xCm*v|0fٽo}OO@|0ϙQu_P*JzVEpqz~ %xwN]ةZ4kLs$S. {yRlXmн_)LDI2 ~?K&^3/q<;՗ȯ~cp谫PlCEa?9'Wڧ^k71~oo~wޞ{xήWovۋ/[nm%`LVd &p5@5|[i AvOӿ!9{M~:닇OV\ؼ[JquPk%aZ[>ǷwƷX}Jnk> h-k?t<t,{0"$8U&AB˓PXz$D㱎x\}7|?a?X|x<Kk 5r+]Xz~E;(!sW!ȟ9<sQN5͍uB;ZfR`Vbv|tM*c_]鑻ʗVM/=?T54@?>YfKR2fln>qH)*WxTuYd &CV9hȃ둣9Z2],?sFC3~CmJ 'e6(; y5G@gx48dBT&E;ɕdtГp]\B\~CUyJmmSIVWX[ٺrF/x&%`O2*C脓W_Si;`,at 8/9l_7t sE6s#T DT [t}Ņ;1bv\O+ٗ\)",[ k8?U<'a=e8]M'|5P{2m)o8+Yz.CmӺ2tLw=O0+P-XR!J`1͖ ٥7juaǁ?fT1,;Є™ȯN}/% =sڏk8 \Quv$Y j5]POӸ@ZikAwED_18F>>=5BFj`FY$[pq6n`Eq2<B t!˻Y|2ɗaИRK /uSu \%B#eҍB9<$~Z/H+5R:_nRl+LU#G*X4BE%a)Qr ! ss]b2&B > ?$ &ohV6(p3G@Dr*7NA+>wp`Ԙ@S(\KM3zcf4qaʹi_|ܠkS+E@p[$5ě;jqP%9mGK*ܾU {c=UMw_@G<&8W%S:F0xyD2:7th \Npe9@]^m(1,zX|߯*$zU\QG`Bs#Roc ?R]&Lw-T^Rh߾H,>g,ULO[OjLN2$i#e޷ Qm+9+Ou´Q1Cf/q id@Dť/jپp&-#\s$=)_i$7VPH 孻',,4i6HxOvtϨ5Jw_v-WdfRJ* Ş8,;7! UFǯ[Q^ NHwH fQ3U١+{AXW)o+b\8K9X- cwTC8VxMm A #o+C9Lg)" cF#*}r,QM(lHZ 9rMkѣ5d!߶w&P* +ZSڗHKY<0'`J@:rȘ -c݇P^]g*BfT}E&+ДX;;4uo^9)vehbBʦ~JN앷܏hR}1*e8*Αݔyw^Zޕ3!_0 "bu3^"K!Q"z2Ћ "3 s4H SE, lT:V)bH+㖌rѳ)t6|:fЏhW h6Gƛ܋6c2յFV5a)LU!I4 'sE#=(4F' m_W*b.F }^% U% n}o6ņ(6*FEιOl-sĔaíA^U"w+$QZRd۠yxUUg(xms^uΤ ^lr>t.s319ù₧AnKT1)3* =x>-Bw9I8K܈LorV֙Y=lT-Ԕy*xlS &2;gTZ?XY枊c js:-dZKq3].kH"tnԻeY*r nn [!ӫeZ*uD58 .6@ހ/-ωaʖ,Wtܣ^>CҶM r4+BDvAщHi6>Zz9ԺbRURgxc\SRf"5rbIT}ܘ(vuY:qH@+¿8<Jhˆr3cTC\׻I퇜mdNҫ3b3K>>fT3ZX cĕ(xw8kiqZՅņZn;]haQH!pk<ɀ5TLf(O&(M؎gTcsO!]&-z4T)BGe|@jzg+/#=>ѥg:oR@"qz٘iN_$(PePtfgkV/@J%R$jTqBMհ׬t=Ǔ؝ʜVWk?%phLxG.]8W\=ZSVRڲJ᫠[nlF"Wn l%rKCd/lc\Zq }1xbܨkcfSb*9N6݊GZ{ĎGNTIpɐ&2E7#!=ĪcJ!>ip.V7< 5gT6q6Bk-3@0KW8qGٽ5OrC@7$&g8-g`~\^ -aKV7R` Vopknp/ cΐw(d@Il]ERr,z)Эt(j#}goDw*Hš3bKç9Ef dg \""J{3vV]n(4楕!Mz~):=]ki^^ӑ4.c'FW F%Z"%prPRkfV~a)0FWȉuzBUDMPBv-%,X7FL(۴gu]2!Y_MtP33UGWqEn]ߥ !g;X5&!0wLrϥJi8( #y%8e+ҽ1 [tsխ?%">Xx  LOk垪zWjk%9՝DQ|)A6 sfT'/ɌjإҠvm v~8PeҊU8\ºJ7 WDU0 zvw@Èު "Of1rL'"&ڙNlU2ipNun#nM- *sPQG9 Y@x,;Y+U9h;fe'D%q)=h|PƮ].V7ߎf$1[%#eþRUY 83-LB+-( [Z芹JI"4#aQ%Vd->&ZU {qLGB1L y7|1n7u.=ݒBQW,9%1oJ3 &`B̎y[8 dTd*RFuNp.`t7e`D\@јnnu{`ht]e0/D|Zp7Kf< 2HCP|)D%!v2\ԢpJX!f!"ÑhbQ!g9% r;?u u6^%+*7rXj| S31Pr-*('Aq xڷE&)la(5s=<1q`"~($!iJnE4T tdX (OQE`[8 O6df(kjÂ$mh.M,ՏdITOPqvz$i/l۸Iur_"ܪq PIڶ)<sjuqM$ȅk՛hiMMOLKF%:fՉՙ7˻(#T`gev;GC6`b  :X{9Z.qCJ"D=D=›&+CX3 2z2A>i,6'aj&h3(YܐSLAwlN{;H8ՒY|T:*i0X r/njMKw;S]h__1:P6xIr&G}L+AȄ{9tE 4eUIkaƭod<# gug\"۵,&c|,đ]1Z- R uf'ŶX+ף?hK!i8Vm*VHPQbHtn()M_%birML GMo@np6ӂbwĈT ?ўּX19ۊFO[UT~Jm>q+\U؄mHY5񑖟LZ<-IM -Hs0u]DC Q o[p"]RqE2Z='OjGqFmЉ`Pebe#zo/Vn5L ʺ=+J7jU`Y&+T0|>/x"bu듅 m99*\c+|^qbaOJ>ilQ .Hh "޻Rp# Qpe6/&}揹A J G};C)jTݒ=__"Hm)ד%F;ㄉԐT^USC rMjMؿ,DS[q9y(Ny%^voEeUvFh-Ʃ+$`IR 7o[Cʿ+vo3Mi6%j/ UMFxBM(i (1뭝e)l*GzHf6Ҏixe=̩ʲl񋱟|ٷ2AoioO?;wrS骷O*z ^ p\__)K 5~ςzAk=wBzﵜ;]%|U`3F(3;`I4xJN%Ljc֑gF6*=x.&qf;({0s&9f)`NjR ##c #!ULֵp[3xnCGyeXKU$avU,yF %\g<QYSl%,&*TUs{3p!Drio\s'EMU UX!wc6,/M9._9-mQCE>r©SWɺ Hvߔ:^R\o|Ւ7 .qؑuJjʮE폹 TB`U)4\NBzGpBhpgY2sa\ֈ t~BZb-_BL/M/O2li CS]a='+k8\FMw7UGs_g#}~~1..4]`0täK Go掤d5m̉x$ea!ØWR8AnC53x9[ TT -Xzad9-ab*`9.2A,fuGF\V1 'dd/G2 F8tŭVv^R6 ouL~r rfeM\@r UZ ' $=Z@KJG;]IMpx!N!@CENCL!c{ۅO8#W=?APiv4(vQ @=gD²o Pi=b*OH"[ZtsRdW r<2YRm`@\*R-I7+^ -lIu;*Ul)~\VQ%O#eIд \U#׃4?Z0a:-E9a+״VUD@LUcbP3/ K8m%_ODq"I.U'N* _n(XͯVUD$)Q4/.!UY7Dwbyۂ7xwz}]pyb.e8n-e#ti=c^Ǧƾ]y~yyZt$IO'C^6<*$#7u*F)u.[\_<Hx io]u͓)IX}>ڲ.ED}S8/y`¢CO #6l 9|~^sO#, r\Zr+(¹U%;&%-;Me9uu뵊V@|IU9Q3Gz';`(,H8T\cvwz^i\-@VĐJ@Ɗ!?Kuu,Z\Ӂz>.D3 RQZa\62QHۖs=T"F.VǖTdZ%L~FKg [e~ P&UdA .v}112@į0בQ$:d|&ٿ>$cȩmYst+ڝodI0R[h R.x)q\m2$BMP9|OGAr[M t rh)@?Xj`շO#SKKMspngH@2ջb /1zfG["'ŭVT<"P\9QM^<ۨPGΤV2ήn0Jf}܃[rW)HiLõXqϳCy0t/"j Af9şOӠ!.Yǥ5,䍿FmLsE[eqWbvQq 4T tq2eիX8J?S/O870( K@h9g՘5ؑԺqi8WTIL6[WnHT̓|Snc# q'UۍB"*Mg `eˀZ^ciUElm֩ɨWKU_gJ8%?2w:*MdAA+Uu>/jK% 9\_z,}X",HK8|+EWzi`XpFQ$gUwur'aª@*Xè? dt^-Nh:T9NzvxXh@ai1v, Qc^i:Q4S,JT^'%kK5Tɒ=Kz[9A׉Y"s댚G|YOIj RkؘT(v6'#'Q'h4; r+Eܳ0VJ4 `hM|SRUP u;8PCl/|5u=ގVU8!Ջ;lJ r ξی8 ɂ/PbZo#EyE /E4//SVS2 @$HC9N!WExS֏vgC0+}eX6i-9A4K,S\l-qu&ղ>΢ $P(&߬3^~VɨPe.g2O48*t,Q]"a7+OljNhEl> p'~] `6%,|59 $|2 *CG?D.NK(v{\ TpC֎e5BL:nł#>ء~A:Ybus [PʤB(8:m]F~6ө "ґF+YUe[n2_[^q9- ;0iIwAaoPKUJ]ւ>I(icge+Ӌ6Ү>A %7*G9*VQ&U,9 |Xľ< BT+PUi!z0Mq0/_4F(ǹʲY 2jEkwe#.ozEղUAřRR4{/!brA$NPV:ʫU[z^傱Ȣ9܅Ĵ3Nn|!{!0huM7.^24>":_>A2&㪎B"?\KU>. I1!HUV@fCi8eMG> ^ g)%`R9˴ a̟peL"j!kNsJ-i`zRuQ+D.)k.fi6";~Ic:hyMc( bC=,[~ -:ݮ9%x]vށ#0QT [ݨY)JU97rN娏gOLG.Cjqč0]nlST!U%J 4ث,&f<"J@m{0Mb9nKWeuA4Ldn?T=]&p]~ g_0]g܀F m%Ifb8R=gΩU ƕVʑG:IK#| *w6†}+(o lpS [O_EtuèP}&ɌsHil@Fߜ v)m~JCEyX%4h(U @7c0@ӗÏNd$0E*U5Bʧq$JZ+ȁڌC-`RM?ՅtX,h͹CveAlT+UDAin k(3SH73/RUr'ޯl o[xՀZGj!kW^P{/>TTaԶ p.V*nPJ-[Z*65LMIՄci B%2*`7Kib%w|[Fpb䓅V>iƱI]n05eĢZhݻ~6O?U4ZIϚ=k\3_[,a7V Jmn[}drz;8 pp[r` Uy}CWK9,GROj{Qo t+l#4|e4w-b rDX` YnoHI%trqU޿*  LtշPW51P.2`*5n,Hﲲnآ%OGj•%2Bb`ԏ vd/}Z4V8R/A>QU]O\P@ifW|;ɇxߍ1 Ӟ-:-K,ss7 3[q X9o@N)r+qevѣU+sqIz.EH`ڨmz ۢV#S c`8^v/(]].&:ucA2,n[ZkXʧקaPu d5'a["nf(pͪj ,vag+&JCVU(cnFbˉpAn&1i`FZ2BȻUҙy-I#.EYWs?f]C&5eL,~>Yp麌;$_ @@TQؕ2m]îc)V2,&Ԍk>3[: Pv,WUF ӟM[{wQb)HE6HzA4[ ReDzL{F)lWݮ!t28gjeP{di=kXJtd6F:zÅfcܑF^%H Y*V)kݰz=0Nn/͗7eJDNSWW7II) j˖&>U3+XӃ wy~C09*.$ f@TBcw#!dV4\LFb:L\<)\$[Tk{1!YHM,Jg\e\/[:™|r&qN9,Nnchm˄]k"5ݠu̢1)cA:%ȀsG=L໵:aPoj8@AR,`Ա(fΤi# ѕXVb"'i5VS- l{9z9AB 3quk(A|3CLQ)[Lm>T}tcvT++*mp4Pyo(l^)JH.'4xtj{CO8vu)>ȹ( fcE^=s2˕`rMe:2/1lUry; ]㒩 a0=+ߑC8l.Qf`:%_%;߸aQU+gXG\י/+XwujU(1tpv^+? % ⹆9QGEˤ,uzGvZe")Й(E+i SmiT=2M1>'ԎHe q&({'ypmţ5]g >0W=nZ@V/EB(C.p3-1M ̓r n=h`"*0I DBpɀ&MAj0U YV)0!A!^ r`ڵ(6!;-YR]~1_ MCѤ/Ǫ,#9ikD`VJ]zQh^LU"q0oyt8M  /.7*L^#u{l(ZQdg<&L: =w j@LEgS"!X{`5&U'Em2ɥ) zל'Hh(ؒV]mJGg < ;r 4eB`#+H H0+cB֘AY$4 nRVRp&JJуJkDžō,eF)4e`@V&1K W^(a(;9m-!To UWn. * Z 0 u+'Eñe$aD6q[ф9(K$5T)ǜqX㡍eWfYx#^$7 Tw1CZ5IQon/AH=1>̍F!겂NH98,-S>xʢ0_%qҘ-NP>uHzłVKaԍcj6!dn>>22Lx *7"z%Izƨʀ#Zc,0D+U9um !ُfw!3Du9Ց y9 qZ: |i8_VCD(}I.KPwa\R[؄\A$.hI4 Ui':;їRy 7¢MDnXމ$faY@ m`&n⨰x~_`V,yȨ6G A+4^ɵ+bU]%\(ܡ{j R*ӶwskA2){)ÆipGX gyb:6BaRUOTiy6 cBAJR8*܇6yh含rx'WcGpJs9cq αQa@Se7 BЇeT\DzKb.nΝvU7b#4yݺ$8mXq%]e P'O"씖iz ˝Ȣ(G0l3S)uYU[1Za6xpEt▚wjf{O.Ȕa_"N* + L߿1BF wEϴ ;TVݪrMI1'R˭{*V Hg9/帣*/ƐrH˦7;6zTzNUT4 '܉MRwRq)7P=ykt+l'l!-$N4Yᭇ:a|:1 aj:\ lQmp \pF깈p0+28g (3qUBqIɰWHtl8$Z7i8ro[Q'&. 2H8i%$`\һ~QsqKpMIw$o}(H'b{YzV0{%Y^|t#Nz.mgqʹˇj_i Ԋd6*z6QWY/M7hE: ޤ1Z7MlA٧[C| hSTQ)zUXGU ”d c(\͇Mطqp# Vׇfu{s3(Pbi'( 1956bP ' M %Z!ٛ=Gp3AT1ɹGupf5#q̳1tR+ ՑXgzzE䥢$|} "Xv.Hde Fյ1.ccs+K( 74u9I?^?Wt5xϯ?{y~: tws=*aag.pHY4D tH2CJ)OoO PaЦbI"PW\?Mg<~Qn>q~ø@CJXʼnUlj!oʎHf0wmyX>eBQB!4LN2]%;CTQ4TVIӻ 9X f\y ~^pKHAfC!! 5k(5T5yQ&Ӳ D ;kztr)G/"B鱪 08u@ oHG{$T+I gr<@(MJ0uA-"0kJ'z. %3K霶q#q`*sδG!\^5]`JP鵝 ʙ۸iclm-CO^!2$%da*aƛTBrXm&XrsqutT'/"R0S h*`SbeaM U:)r)/(zNȧz]s)L1᥮6d]Pir#h1|Wa2YUL[asf%,JWK.supmy/f{.* 6Dמrm6WrV"Qf_K KOSA5(LIt!|lDXtr6cQi( \!{0S!WPJ pXrP[ /k=w/czLJT p܄(-PjU(.ua$N%JT$SmO'4u~e., cSoEثV}3#Ӳ$ffTCJ`rɮ`0uhxáo30/xyHT}BϲL ΥDuǸ5ADx=<7%M<4hHy]E{e:B}aUVH&rYaz0Uvygw: $KBbs`#%/>~a:whU^/GU 43k Q}\db?Wjfkr~`z,r4uG \7򀈿SqU\ȱY1 z W#ux @(qGZ+hxG%bj쑇dNJ[519.z/>4_1,W0 As,^:@gǁ VtE5}+L]Y2U6A-!_qIfge]3fabrKkB5!WO`y(RYM~v YjQ}A;ƸwF+g\E׊]'4z<j QC0㾖"cՐ#j1ѹ<6 ul;{>bMp @)*-$R=(bGj3}z`JF\!iI4]]kP#(x 碧*'ax1iXP6 ..4b^UUY7͝hkTn`?s8xE,mwh;86O)sн F]@)& n*ozܥrDo`j$ Cfp-a)]tU=&Xʹ&݉|MճtD 7tN_\m5pTIՈSl&-?Ze*ņu*O\]7\$G^*fU c4{ajV:䆴rͷ׷톾Nvk*ԔJ)̓\IHEy0ԱEO hG"SqȂi*jWKzGVӐ\,#Z@IKDTxS~-|`y-_2Qt@JNl*M FRb Li3J@vX,@պgY1T#FOZ M [i䚃:yiC6[7a'H,S9WG1Zᐊu€;aaiN/£҂Lpl:27 R$[~6x+pr"Y!'J <=EQ7T&tk*!5sԊKtyJYq'TXDM-n]ORbLvr2W׍ ;ې=.yN٧P$9rۥe 9qfEHt.::U$[!6f\U  \ӕ HdiT掀kWCLy̌ET4wf:];WW(K͟QchHϸhޕlGS'+ c1亦wc Ld|XEyꊰt^>Q1eJ..vu{.\L,Нs7UXN%n Vip}72(CU%Ҡ3-23}i"25$TEqSTn,a=w9EiJ]3W %Jyl#Dgn1˅ιYsU˄t.qo9y `1iv txL3՚FJ=ǴIڹ)|ۼ޶kJ"!(G]Y4bKN&Џ yhwHPsdpp}RΝb2P, s%w2+G#DTHJ< Sk]<\s fY`j/6 C>w&,*Id( &`&Y)S[]E  *|'SSUhЉX-.R H{%~X}};"TU*B(ß-S 2>V PV~ժbi8|TN쾇/?L9͊~]1ɈhcyD\(T/$TԺX%7k[P*@ZRڌ+ 2[i؂oҁEՑX2۽$Z,W־bwɐ}r;!ʍ7.UkL 'p _05uf5'@c'n[%-Rw)}MZo%rnz;-ɛÍhw׻? ֓};{كtV|{]wV|szw͛΃]ln~=h`oɏw`4^{|<<onP{ ?o{g'W7~ջqc{Ń_;nx7j>xr Z/{};] ۛ٣Goޟ=ݼ-уߞM{;nѿ~6K 6v뻧/aglc-<,kR]uwrqvzzoN7{}&x/ηɛdGrW?_0~͏g|]_zty`o=?^؊^~?޽8>|6}jxڋ`sU;)o ܾ~݃{7[[^dsED/z;Mp|ݞN7ow"<y3izxyބA?aW^8Z4ٽӯoB3ꜟ\M ߾9}U=_n·` 8>nQ{K+Tz2U -lNi;=il48nDk鋓ozK?7ǃ#fcwߵ>:\vѫtu滃ooqt.o\c|]G ?ٸ?|W[~{ܹ$폃㷇ty5>vF?~{]>x>}Go_~^ a27^ҧѣd3&v]ڼlN::?xYDΣ~?~:=}6:1H\zӫf۫(ξ9[Dmvt=ztw^ ;Þ0,SVAتмDfT*IA8gc UE'@xO$zSHs+- AV嶶=9#eſ1u:V6MzKvRk5\AK:;<-)[[f`Tmu.,@TP ^)Pgo2jC:/ȏdLVZ[>z|k@3~x}Kߑ7PVnlk&iC' ͛ vL(@}JK m=34Ͷv[K]}P'GJ逺8Aptr7%+,hqQ|g10ݎW6 ʳ\aX&eMTi|q餻)yΥcKIj#k5vBnc# J LŇO!O}ۜqİ?xAng# ]/ћykmSNIQ$wj?·aoPX{,4 S%Q=:o.C+R(7L(c* y:T1$};Ξ rwUUVa atnfofA7+a?3nW#9FcW$UmM[;" AVMGFԲ6d)9dfR?qoU'G54U\b$ #8|#5öp@~W8/pF?c3tWL[,K2"S"y Ε62ϵwNJ,Ҏ^5YdmOv7O:؇j>÷qk\ =}'i%J XMBm4qUlkd qata/S$&VD??ۺ1ݭ-k7 veTq/[e: Όګ6Z bcE|% xĨqJ8 M@d pXneW-4b'ъ ~tu, `F M0X\LP-+2ƣK-l|w>P{v`e҈ѹ@(X7C+X T&8t7G|ckyo!K}-EkN Wɇy9" +dވ/N g==TsX'AOm-)+4Dd`,Xv8<ʊj9-/EN .0VR*@DY^՛aYcpBP:C}[#tFzx4Q;tP5G}OQ4?jNe~Ab-Bwmu2&]$KtHG8"y'cK@}DJrGb;mM[eсS\Q58@}fX!~&_Z ƜwEQû?E@9R\A1_}i=*o:Vw8I4ZAw"vmkT,I_bе FU2VTm;Wcc: ?SS?ӛ+G l|>_Cu:/烧9Rz:0=t8FO/\ 5jהiM"/I2egˋ]Ir}_6uFu*HЃ$ o΀jp]7YtQ ]I_b:V nf+T<L Yv2Y b53ض]Ssl'qxH:?*i!`/[)%<_Ue~RBsuGc.Jqvfh@F$HT)T;] ꤪ4c#_%%GMvYhtb]lA!.8͗7^406מ۫'ܫ&=Щd#Aهcc,mpd? QMJ+SZ4e P8i]$oƋrF][\1,{Xnԁ T jp42E\i[Ꝕ(J`foFb+q%0|]EQ~q9DG+$x:͠  iL ]]B'-l30#0Bp4&"4_b6n<0ÕٻRGfeɞ e42C|4#*7(VD xQa}(Dڴﴒ!˱{ut\m__&oaҹzkk5@{cl,<dGpp(KYB\E(NrYpo*V6VFv {UJe]`ļ %?o]}ZLQҷgz c΍kZB UP b !F[Hu]5i\]W/IYp;BS`Bɏs[wO]t֑r-)jAC{ǏmVw{V5FߣUDM$;R8H".+( qcc(Xe?qUA6n NJH<ţDP$tUEP'@9'S^+)XGu| }`v4(KmV\Xdq+]J|Un/}э*9+RZ!adt , ]Rw7GϞ|wLɥ襁XK>'M1j2/ѱl4Ll^gI>a#(GY]{Ue_ O3f-^]?ȸm;&eO>wf G% [amvq>8 t4P]l`9[>fELjL-dqπg)jqB1,^$ޗ/,nthtJa1`1uKg'4EمB I6%1;q()w\,}GK`?][/u =DΔs I@3^~xsLu5۟&ń1CѵV a^bJU#s!cx#(8R d (AX~2]etD rhV {VQI KN1 m~fpQWzJ椾 k7s)T "] h_Ap?N *_%cΞ^h=S}q!"ѣ'=zw{?TlS.S8RnjQ? U!|̺[`TgEyxM5zonVsWC {g@D8\FfVjHVgVVؓ/*~0;#~/kv$ ͧzWu:Y4 XYke2Q\;]  4L T`u1|:gJ)3)Vo ŮW>Ů?F L w[p-?GuqCgt\%qO&GY- wQkI [_@}ǓG`0B<x4rFa쎢mnax7K~DJfD_ >gI)+l+HA$˟ hc#LI(5H&H2e-tqi 4kcܨ5-HKz | ݒFy)08*=jlDvAPuIjjyBN7W_g^)8/7U=%[A$()ϷȃIU_.<v᎛]cz+b2JlpGxnx7@Jr]O!ԽUg=D7_zA*g '$KbR%FYNG)bQsJnqu03Eux5k4XFf96Z{ Ԕ GF?L.⫴ fab0|j +10SQN<>)ؚH8yħR3ou䦆úah<:-xã&ϘU6XBEMEŔv$_X2Đ65 :<JIC#h`C=/rFN42{ߢH `,tEҧJ?nwB'E]$^~pRg$v`z5 E_R(hQf ;An&Mjf t]BǗ' 8" et6B끀.Yv2|enӢ_;}W_ɟiNvt|K}W#yWF\ܸ}1)NJ&"tN1½юDRowՓ5T0wiK 1VB&q&.b"lGZS5V>FV-8Jz.12[`$V[oG|0gX'lժ * brhHd~4J9?ZpuxVbwZwôLx !'"}. b?цoNMY6!$Q[0۬8Om aq{ԏA B]j8#,!a.#,pjC;'Q6A)֚8ܐ Pir%餘p0l.k-9";I9h2߭ jk&5W5Ige=6zu76)?H&_3?SAsdǧzM"6cӁlv틼H33ݏ[`lF ncM .|g/3<=q%?xeXpb׶0g?Z$Hwڭƈ\<7 З4Tr&5T14|7OH08u'䜶Ft@ᦐ6^ *~uO6 ‚/2n27xD{eW]}e8䙔@3?#5W}N`f/jz_kĉ|u2Oj $j(} 0*!UC>!pӏ'KEӗXkqsk Bk7l0zTq<ዿ!Wي>zފ{ Bpغ]$R%bF c9BI0ZPfrx_ `?_9RtC(斿 #ήCN2~r?2%%j,܁,`}ޮ!ͿUШJ U_d_r"C%C)=.ĶL/y]ч/yK Q2֗[ 0)Q3;Tϣc,^E?Vz،Xgk1)!-qiݒ-G!݁(Li`Oy4ZF.6FtSaBY{{wjNމ֋g('H/j]^­9Optz}XZlI.*W vc` wrÎ@%aܹ`"ن"h:ަоDG$t m0`oM8_cv xAd^Ե_P؝ZN+rӋH^&Q׹2o(MCn|#a= H/툁DF;cD8dX: hC0j' ^Gm|D#AY4WRlV[Lә"9D:V'nV h[~I cՊ)}(+ $'}ɍ`J1pJ.0y L5G(&.S&`J+fjzNKcq*`r4DpG[m4fwhS}+;P@*,A5k:#PHGFy2" &$T] .T /9=w ?nfl߄'׌+m#W)RܮxzVa<4x-zRbߌ>u=`b<2$gx9ݫi+.6 G={| W)vj+DD[V"άo?.iU+NoW QQ;C,ᠩ2V ~iOp?D! !pʙ,ЖB,&^3I3;-<ڳT]itV{rzeR+b4;~T84G̸!Z>xx# se6KmU(!P 񤤟e6>wE;RpnY g,5Ur 2H]%\zQl4vf{Mq<0z"ܤ}5$ >*T1>+=[Z L$KmhqWbY](yQ=Qx.aLiֿNV]0o/H:@x{m3 m 3I#V䳨krB %3!M#UVf1 e^"gr}©WXXY/42ZjM6}tEDR1hmI14:5@%[~A>{Bj҇ў10j|q8h|hc7|2B[1.FeZM7 ٍ85qxu哌ՍEyvv UZ+qT]HxR64GךS5ϩ`1Jɴi[&.t9&#Q;C5Xhj+eO  P8XIy?J(euzP덖">ءjpL6kn.ͯj7"eRgE +[HrJR~Gx,@[r@le#kA-ӚTQ'B{!0*f#ΦI}I!Leb2aAZ\& :v7r̹=4C;!ӰiN 6l@*OgZy:VܿH(gkXc-#Nd m.A aZ1xOA[ǺnӍLu M<Ϛ  IѶ n͸{ + x;zXPF7JdZTj[{oX)XW'e[޷BEf+ }?agR`׏Uo. o GMC5ҏ(8έ]A}[/y#~HZuؖ:؎VͰXtz~~ ~­4n9}_U{,r>ب[7khV5mVR-Oeĝ INI]u1E,[db׳yAeIC-Q\)7o0/ԋZWe;`*D!CnL|-%W%YR% +|tX+J48GXTuUbT)U(9n. Ҟ8ţ3ƎȲIZs8pO#]g8 )C1[D8"P]QcØA=:e\+vltH9@W:eTX N;zoJQ+r^HO b 'е YbFv[rK]\ƛ6 znpiV?eyn>5 \a1GGNo rgل4I׊4ouD 42FJlT4%f ŗa:AK:gq\r@Ӛ"-i=k:Ze{"#.;B(:Ę5@߶E; 89*Sav sHϓI@YUnWiQJ:Sg6O3iR7~WDVeةv=SȱP)4;Mbd2 &iE1~$`׎ 9^26U;u Ք!$׮i%ݴjbOm\vI+%¡#y/,fIRpse9j^PLC"GJgf߄CԈ6]?#KƵf.f=r\MB(o C .al?2q5+ E/P0eiorC"OAѡtRMj}H&O9]#i-p:P=CTh72@߄9,>p^BHIQr8/B>1FZǶs8$/O^E1Q*t'[mO: d׶u=f?uO=xTv_ DWF{sz){zXZ8♚UtQR Pz@=SdjTly7KDg_95gImFH@:U6ZUХ&ݫ;WxTB o_g-ҷ;`[2iu$5jH*3-LX" \\")o.*W-*|.O;i w``]eʦ7+ʠ ZNʭ<ifք |K;f#)TKG`k0 bv==c^WK{{8lj?n*N#]П{Y9Nh&d\@G&5N~ )X?gIȞqaH.?(A5ְIrF,Dx6Is"E5%Q'u`Drܦ_)f7fnc Ec[=fT&BڤCthGкOb'1kCY( vǂ:6LKVCɛI\&%1Pu߆m#cQB&CbJTn!#߮E]B=ksaV=G4*mrddFVXtST]e.RObK(:wH Gfu q4C €_,/̨qT{:Xֲat}c!֒[$003,䞆}̝K{b43!'#4cL)ypBizxJ$=9E>2 {&?tqd/Ԥ I5]Rȿ#cөxUF$S4&EG:7z[H|iGk C#%L Ä^+ޞ`*'^JzKSD`4"36EZIaE;ui!iM2E=~~x0x0yDsp\v7`J/9IPR ٫EOpŊot"^ ,1~bEr`)0qkvas|"&!FH0!D& "݄Ԉ:`{Vb% (|y?"&@AB74@H"`6%6NGbH~HbRDZboo ,t)Vq4/ LA,%᩸kRQ |C]᯷ +C)H$^+ f&X*op(y#=6^fIYKc2O*4< Jk{T4 &ieu,2q/ɻ5@`_bIUd ֗[n.Tds=Q6*J8y 6+K%Y#Tl|B`ɞLJ_to+jBi~vp- Q{% O(~+zW4 }wz/p ԅ]VaY F#܇5֪Z}cȹSKHҭ!˵2 wPP)[pY[ eGOffStE4Mm81lHPFkhYr^uQ!j湍\z1|h- T bêHF/i+PiW?Rdoy`R~vźlk 1I6$Zt MB8.ܘ[XbT:$=qEeBx8}n#hw: !"]F$e$ji\)=FҠ֤SNA ut ӝрuo1C{ 21&}5"({A()~zmv_]!!pIU"]" 4J0c(I<q֏NބX,܈VO>p( H]e5@W'<<XZF'oc]MZ@?!~"!o?}?lQ_SX;*>T|G$N9x\<.uv]`C}*h~:5-L;%ܜ5pǹ^]p'bQ1_K83gO$u/xЏMʵ*L+'j ֽ0 jSv'׎6o 16^wIj!N{G~JaV6_X ڵWؒɐobPMaw/׺Cn(XҸ(YMIo-fmH K (}< rڔlQY{݄>ɌÛ#]eilm6c]@:(4xO?|L) [BB\9ZӍ$bqPX .vS7E9ꭶ_`jMEd A  LrY~|?2CIʤ8Ie !D=]@0PMINXcF,{Ak%5k#*,QЯn!A Tg%F6Ϋ`No7#853Y]c)-nW<2433m rjF]7kJ+P]wv@mwNo`PF 2 ~}:UjC` *ұ`R/Utlz#ddžZ:M]Kszw| g,mGe-`K5*XnE!|bxF;YinlC 9/v`<}x,oV: nņׯ҇Fq')QhPfRqzRy__,4ьEms<`' ]vs~_֐MT:.!Oд]sA,<5} Ĉ@5J/ßr<,7?;` ޱh`ֵힼESL`ӽ }Xx%{7w{̄6oĂzpTjwD,ʷ9$LX;SHLHȘ0/li ٛ]9=Ȓ)a`+B*6hPban2ִUQ&Y ѷ \#о}lyS3*P W1 VN1դjR9g<$Po[% Q{Pס'fS޵X: L'1L;Og࣮-e!gLPC5)/l1^X' #uZӊymhg]ÄxDX<a plXԜc 7l5/ ҂c`0L3b!$))-X%ۂiǠ"Q#74ʮ{c5 ڹWqDŮH#Qʦd&/렚EP'YK_+]xi˥G4 ؔju!y]b;w?219ж.Lc|&LKaE@V`Ab909R6gAN K))$C)d ٝNTq6ze-luJ;H~sv@_"+ĻX3XpGuZ,E)YU; FbX\/~pQ2c>ٺ{^3)̿^PuBV K36r-bu>jfK`g Wb;2 K >pli217BP,8}S.I_c^&&iD@L`]1(C5kE|1))D;)B 74E N^>؊6.7`s}y|6: e|;t$2\wߤHӾF>t;5_:Rs Q1#*&V|e1IC wV,_xwQ3ұ}qѹC{1m:}S[? ^pA/ÕBCpga9z50޸n:M Cؿcg+ XG͚*B,ĺQ`/{@Ys?ѥf`6B8*ysx6+(lriq:mL SKŎ",0:wqu%y/O})^N>:,2Sv+{/$:fދ~Ԁ}k[[Hlg#Nhqo',%xn3[Z-1o-:uԼ4̗wh0D'<W'g9ǝTI\*&-@_jmKfB?s6m+A!<8lxć4Pt *F^ƣLNxe4hcbUAp3"O܊U˧R鹸0#b3mgN{n,rK[qO4mKjd#݁ LM:: fR)iJ*"\Lp_JBh>zvϽV,&:B߸g^>tˑx(;RX#9w&2r"G7ĎAE8D3gŝ(r>2uYX  6?F}Ac90a6>PfT!wL`e&{IWHp7!0T)$ wW&K#&hvߗF1ֲUQ'PMl<-U놋&U4Ut>/'㵍1zhyBۈݙxUhp .3< bn-Sf#/{ uOcue+Jݍn\q)$Jv-v[`dދRܱ@k_& ݎ#d*ѕW6׮g+GgP aR7bWUW)HH"Qf` KliC*gMSlNu.s?ZWߒF)EQ[#Qt~N#uN1SN򸯺6/Rf +oW s>x8x>GP'W(Alz}0 d214urnt@BLwCauWxMUs;\LW[i$SZH<ˋvm Ħ|S驂~@jR?b7njT_a)7ЧbJ-r9,~vF$L)%Kz`s?E%ZXb^c2ƭ;Uٸ/`PZ%A4)g2Y oϷXrr*(y,4QTs 1w}y&3,'ý}ۿ}wJ/TbzVSq;O?M>F0޺OjRӾ!q{Fkk׼qηZ_tNĈ3nY1ug%w?=u,cqCz4Z~b׶.](Wx|AbP-v2!j|V4ϑ0-uWmyt)HanjQCPqk N:Xh.ݠɷ]v="ROm{(?>cl\y^7/)i\Oj8i6ƒvc u8DZJw ~\ /;:tBqg yV隔;9gɉpѝtn;ֆ]}o-?1rcjUὩnI+ׅBB:r6S@ozүy}Tir׆ˋ"4́YQ> >%_>n_l[WSk[|FF#mRX:{<9V=Ɵjd?B̦|gfU}߻hͻtޟ;ِ폹^$`+?a}II˻} t @3g&vyaht`ڔWXB;mw qX K}/ۍvzա];!s{dzZPUE;7xIWhL@~뭑YgE@]H5>PW ?X5 կ P@dgP`M__N0օlQLTE):o>V0"+Umsorp6O pNU{PWX`{{Cce[ߐre=LzSb7:6c] un:=jSYheY%uHcZQGaRZכНsDmMU֋5b+ߕ0Y >/ƫ(wwGo4p˭Gum@ջ[bQ W}L[|q υf[o:LJnS(uKqJSt,lBX +ި_!7J}kX!7$<ܟBo:n}A#bxP˾Tu\ia̓Gn'ﯞg~{UNz=p6nS|e=XDP?l7 ;Ϋ!!Up(Kuͨ:֘Tczx$VL  䩾_v1$,wA)2\2=L&ϵ֮ cװtխp䖧6m0j7z+=@~;B$$^mc62r2vL\c:SluVe+tE#N9ĦsSdmyפ#0& qs2WݒDljvZ"w!@ 7)fik+>%up[F%+.W2PW⪪/ʹU琫_ 0__FMP^c}(n:,Lu VDC2}w"5d2BT|g0ά $1@R"E~E9^_!/%Jd&]X:G&dluS @뭇d{d4̊%^b%ҺҸ}Bhuž hĩcGQ$H4Taٕ))ңEdcuTczU] 9ϸ: *V /  ,Å,bct⿔ #tc3“kaQǰ+Os7N)XF0QE1yQJQ g``6HY)Pchhg@h'E0g ۃHVH-GY"x C(?&Vj=x`QH_BQciX  T5u'$"`lGde0)l?TGd>1]Xn?HTNCEl G0 č"^,:7!db9p <᥷y8ן.WE&Rpk'CUuhyR^X +TІ7<.i]ÂO8'<|f'BB6HX2\yq.R.=WH%F:LK6yw(et5~,/^A̾01p8_O:yy5avdi0 0WDXXU_ ,s{t-25  lý9;Gng/o2DP؟L&ZAO!%t8MB?(!SnC'Fa/ {'Y.1.UZD"eVX1sO;>wJ7 (OQ#=mAZt۝O=f7c(;zگy=$ =кC#"et _ᱏ΍ٳ:E6Sq6{Aͬ-C}͇J L/\pHM1)ytX= h۾شJV^ r Un<]t*HLGjꞚuZxǣBIzmq̔` ?x9EFXicuݎ.  L_`T'(I9ܳ"O0z`׭PQN"Y1^6)o͖N=2R2 -`c7RO6E2HO wV"*#jkTP` ۇ=r ^46{AYJtigi;RM@)A.*v+i`q"jV?{{AcCvLQG mEMT`|T`z-r,"Xk9kNjL#B8a1@ՓjđCו@c\Km&v Z!/5*O1hJ~h7JQm] l^U-:Ǥ*ݳGVUfnl4n/OA\Aj:ՓwE h-sY RMlRdhM0?c@ A ^!+8WJ}k֥STptdzKgF3"_$~>#I-Rs7;%7hsY砰.%Kf8yV_2Xb m!$󤇗Z`@`:31r91BzFTa=5>x0H SKU[}3Y{]7މxAu?N1EI5)Ժ2Y5R2(V"EŲY)K()~Sz͕yL[|ȏC[p8WC*T1界%0aҋpqeŏ$II~$N0θblygн4zި1˗wi586UkҐLSiZvBrOh9-f/o>a^VZt|Nҳh6j$2pMSGmf(Zﺜh\@ENz^`76,Z|#t9BfYϿJMP܂bU=!J-pOi=hn@ Z7dώHQ/+jc'v<2;"XrӿY:XrW4F1B;Qj)8f[AV裎̈V;l1B`f=L3WN(+Λ2~ӨTg Xyq-1ܦZpHv-҈PYJQ@bhڽ9]$~>YrJݧ;Jp;6 =h I2./&﯁}_"ŽF "$廛W7οX6oBl')Y9qRtыO(E5T-tiɩxk₢ M2&J% 懏Ižj4GWe}: V6Bd ~Y5֦TWTchGy]\#N0Tvd:^2ޟtj~D;  3[`_܂)Xz;=9"or^q,E?sL= -F_;=hg#u#D3.Y\^hz)ER Pc2"B *oNs57>T=N^- dqr x@uJo~u'#uy!YC)xԯ.'MK|yzP{:~9Jn/m{AMϯ|O>ksH]W (Wo?j7DAV~b-hp)u s 6#kcCY1*4% +^Kb h8jGk~$tci<;:Ia^#aG"tWueB5<6 tɰ2imiwșbSH|Q>Ҷz49=VV|5Rz !e;& ؤ/b*}$,sMH[jqvX>LAk}`4dR;0 9u%q h51hw uxiq0 (I;wcQ:A2:V7`mCbx@[FZ_oIm鏯@ޮY%WIƱ"p*q[*4VSzQA|L>)c(ûWSpѝ¨ux F92s\I[E}G #<ҷ~㓷֛Ī͢oz- $GbEy*k1<}b#>3g1X$U'dgyJR"Ƅ/ @iK3،wǑ+a<׾ŤCa'sXHǭʒr(T\%1l5Î}ʍ3X:Hǃ$t??@RSWh?frBw (P;$OQ?ޚju9~٣Qj\!Db7 ҒcnjIK@D~8QsV/BRzDY8N`"RNLqED}W7̖vFAZ g :x :~`WbTqBVى?Jtzzm-~矶vDEtoq7Ed A'[GVv+wTϣN\E 56{yr,п 0â)$/+Mٽ"a׼30NVꄂ,KxM[foY+Bno6vR)v16tn)?y+o*XjS|ʉb5t38d`d +k%yY2%.2.$MhъatOu0D0}ʮW;z*xە!x(d :|꛺ _"FyVV!,NAD$¶svݲC{6Otn?D.h#&ḳ  Κ]c֪z5#Hm~m+N0S[POMc$9n,[h7 ر(q0'Sc%ˢ,ի. td'ٍzĕT¹u5. ATFWyrG޽/:5'AF|1'u=^__j6(].vٕ"S|pO.qnu+I!]:aJgF5C,͘PZQ-("P8C)^t F"18m [7c.lߝ~~dQES_4R:u6 &;{;0&'ە /+ʼnzhZ\ xOF8 RDäO 96H2.ҙYgC*m.6#"pwuY,dΗ\HrҤ{I'FC ^$5 K$"'ju@ 2W1ǎNSGIbD^1/0U3&t~̙ CB׬ y4 TOS+ aWQD@8h`&RR1jf~rNsQQbA/zAÃ7=qhÛѓK_z="" dp1~ .%Ac$ghRʹ=ҝaB0$I1*mի֓쒯9_ʍ6nkw4ƛD47)M7n$ݲlV^nN2̺F+G U%.pjvDC@XJ ]wYV?&ͽU/[2>S1،x%#ƹ ZJh%~-e5 f8{dh,*ZBuS:'V=\3-JZ\zڵȿ((CLgF$*OI)Y< #/k$ ʄk yz5i;j. fYªJƒ@7#L!(|#Br\]i&DsjJ:'q>&?b{iYε Dn!6|qOE R4 wn/l_Fēc"{8> چ@T%¿?#hph"f!H_$ ѶMC6WL;’CSoJC6UT|_6%)UhFi eQ9?>= <~~?@הШpܓG߼yJ8 X̑ԙtŷ1>jg['@{.*h۬ v_j,`ٍC i@ 5oDRz$z'#b9eϓk*szT{\!)5ՁYs 2Jc//F=kw>mao>FTixA;Bk^K/ E4{TfObP f4Ea쬵dUjiqxIL!6K"kbfa~B= +W=ؕ`ɬI}4C\bdԗe 7t;N3AyߌxH!=<%n1'HK\Eq cX'A\J7DmaEf; sxQ]틳}]|<hpsJU8يoS;A)V%yu aʍ{{J8ϾhwF.ᝅr* `h  p29[2V]&ŎA)$vB:Q{^"[`@J,|1mJ.!6n.z,HBdVf1U'AfxGΪ3x׊ia֭i2wHDc3{=!`]ɗx Թ-:0uL}6I*`,:>"#Ȫd,Ќ_Jzam= 詪^dzGMNd z@w[>v.*UV^B}>[y`]9~xۡ#KOuvw93-ByXS3vfDDýTp?/ܚ?Y5qxuvG˽x%p_ _5O]ƚ%orqK$/%m5OtŮcٴkj]B#ALOhpm w3/~awQ%7RT3ah ͌ *t A%bɛY[-š^Z+3 tYc  u a+vpK-bHV$ XAOѪXVCZE )5G.Cj'8\-ҌRF䉠`Sρ!U򀅯e9thy h3@'MT_: .qVֶrx@](l).)?fѩE8D-HGt||XUݗjkSu6ٗ`@ikG``o4}J|x-oKƕxn %6pmX?#"yx_"rH9 q0t;D.8FÂօcWi1r[&j1A u6(IuɈtxXsE}#`}$1lB(\5Ɵxyl13;NBKRo`餈cM%.`&$%Te+/P}!m*a!HOm9 1}&@Ҫz.0ե36bQM!F  U&sjE . u-Jx7Sxe~WXo:*tJ&-S0hao1z{|YQ( .X㒐Bj!@v&%_'qP׾ѯ~Uěɥ0 Gceҝr%en  )Z3W-޹ p; 1gqQYQfy(c1MLAw9*,9pE:V_XSRd@Lpuh\2s ;".hwFeK "HE,0[Rحf=#{u]FkR?h-:5Pۍl|h0{@k7R#? ,=im2 CbZF -}u-s9B4j9J[ *6vЁEº )WXVЩ޶A_0C`/ 9 ?l/v7ZXm dȉ Z+YBke難-:Cu9S}AU RBr q>.DpܤG28Fe:kx, 65ߣ_sޮ?*qկf#Io9/ۘ ֧Lv-=ЭpAd UOI1`r<4mCVkXGPurPE>E~~{Z͚Aqmq5ޞbw:ޟ ىDzmޞ[EuY)<,}J % -آ́}ܘ>,}pQ.=:]gW<$? *"d,j;Z[-?o*{a. xVtu Ӽ"a1 2[+%jm4.yǺ6" B]q}JX+e\2%f5"h)%RCq2hHfRUezip0l(UZA"vY X,L]h:╂m> M%AA oB~!E$TzQ5p/]]Ic%HېYaL@oP_u!8odPHB'y3us9 i\cu[v 凉n+MLo TS FKU?ۖT U w'E1ᆢ/.@ۜ۷twU{^6n8iˉKt1Jߢ8SI]t"匹8D wZ'i=Yu[F4ϡ40E'E}dh#MiY 0>p o aDQ`6d<ɬ.@xɦem-as*vkAJC.{H޴PrCqc<ؽiP@tQ"o,_xp'}{o{ts0r[qj.)4dàr:z"hZ{oFGiZU/vU8$ CI3tG[P,܁v +9ʌ%\T *z{&T!-R$y9Oh3|ea =j*f.҅72Y]t$#L%y ء R,Yd0IYRՃ?pbt嗢00XpS\f&wQ1/N1M "cWKj},a"֕"\Zcu~1`pP_ڷt-mqrj_$٬<5ɏ+sJw+چM){Z&"+" :HXr;Ԩ/O4-=mqR>uB ޠ`K[S~%[bЬt'' "A߾z*9E{qLXw5ѦJH\'u\ϱ,@xcb T\RK:،U+cDa#&春uo[w>&'Hgn(:VR}, Pʤ!tιt(Y@;%)v+v/VqsF/>IFylN@7U δdˋC*pMVqliZXTj[(jI!Asx@<6[s$wyfidt?7 d.9눎֑-XSPڄ |!. /7)e}@FDsUGL0A$I %5b!ւ##"*쯭XBR Bkf(r8^!q#UDa8Xʽj6h>Art]0RPKuIy׍SNx4$J8 i] [{*֝Q {KB>:S aK8^6rܶ$#InEDljŨ/:g+kV="H&|İI0zWh<#5L g, ;"d:+ʸLN=ރ,KԱ@#\u vU&aUy":X%oĞBy mN`fؒ⪺BJMG9!l;qN"mp%.e/V/UE[=b"e[w?sѲlֵ<*2(zB::Uc5^1zm w? w*V\'@?>pJc^!E%AAKJ//Qm` a:Pf1į#ko('ѯ.B"H F9Đ . c@[g^Co?g??~J=^ޟ~Ў`KC'D8;foy#:*#(ePb(ÞzapZO7 gz28y{%>gC,{.A屏-]b Zht8ꊳTEX:#a$-L-.9>x%څ0~k&`[o= 094Bt1+~fDOCr1)cAq}uʫ/pazVNwn %8(e=*9&F'X%߯I ݯb`=- A5 % -:=QZ5K7 qФUEc:( o_6ؓ5z8qsuIH]/Jdg}5#tk/˛,ObVX(*: H] S'juL NEU_,6W(%ք,Nu E(~ џyAL@ C,ԍz7ng9kZoW_Ek>)!Br( ѱ)_l:*ߐA1py!_ 8J V:MwA@_E+kY*+QW0\Z@x[fI %! y)$ʠJ ߦXMy8Hm\}䏮KIr;A4RKSN4ݨNYdjVrGu2lŪص=.~E}P;XT9g{n3+.G#nl(*SۈE,@[5phjp%z2ZY5v2L,>xc:,V!=T>#DTJsu d#{ ,ʅwx v:H3ИJP00ȡ5XbbTqw*7;ճ=mbSa5 :*.Me"vN&6'ᐡ%ثG|RVv?psxojG,-s34c 8iOGm&vT6Y$K݊G9F 3%ԩIusZPyg¿ꙕdXIwC#tˇ)P(Z)|Wpڌtn"n¯Rﭯ^?d 6l-B-I2_C “)z0'ЩȨVYǂR J s74'\ )m1QiFU :Kh>s^|bMF`[b=0Oǻv&NvprY܂v+LoJ7k=KO:ܖzE|].(vvco7~'%Ѽ\!j VdAYM"Z|H&܋s1/?v|8U+KHa7ou-$eKc{hSyM[A6g7ms )uRF޳xqP ۦ^b麗ԟX_QXlU$xOeЖ~P -LF<ۓ Ǚe 2@co&ӷ۶ebG&|pPI9BWK iL/8҇'V!1IVa!Ό)4 ; *Ӥ!rq\=v,p*od%xJg,^- m|lv0Eq0elvMҁG/_2rQ !ʘƨ.]V+v[<ȳvBA rBUb .}xkHq5Xm{رW=M.W\&ؒ^Pk`5)H ,X+'tcflE'3@ k!h5gtQi)Χ:L8ܴR_;x|}M[fTh'4#u&G\#¹̘uk]cv?Ty>e)=7a$>h=SbɇsC)!1Ǐڮh$+:jMKem#ZM%ŪQ'-Kw T렿4*.Z ؍ S딎8yagL̏BXM{\r qv,&ۘ[.tD8ydv2I* LfB딺)\q!St}B޸Y&%K˝*zp<+HiVmT{^a*K]1jsn%@73j$J3\2RSು}z1.Wʁ7"&4Ov|=c1bzdU[>:n[Amך9W%]ˎ4F,bG.fq<_决'[ozo HuZ[uE (T1hpiG?=3ӰyhNQ0c H_85#"b*(Wx,= Kp#FlS("@ G/lk16'd}e B~9PB'Ypm̥PLs4',K ryOq 9,q6Q$UZ9'oN2*zbMsoji?8s{VHWpP)GTqlTUK[ xӘ㤊"&0uB,C%Up9YTtF֠#_=M4_#?W6iu TeL"+|uoΐqFӒ+`l]k!8w1]4sx峦9O(@em"~`}C!< Lqm9TL0,A|bO Odz P<4ӋE F<~ 0I/>},S