From c838a513ddbf7f94835877e9858f84f8f3ce0030 Mon Sep 17 00:00:00 2001 From: Thomas Arp <357770+welcor@users.noreply.github.com> Date: Mon, 16 Sep 2024 22:25:29 +0200 Subject: [PATCH 01/19] Added loop counter per while instead of global. fixes #135 (#136) --- src/dg_scripts.c | 8 ++++---- src/dg_scripts.h | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/dg_scripts.c b/src/dg_scripts.c index 978cf6d..88a4b6d 100644 --- a/src/dg_scripts.c +++ b/src/dg_scripts.c @@ -2486,7 +2486,6 @@ int script_driver(void *go_adress, trig_data *trig, int type, int mode) char cmd[MAX_INPUT_LENGTH], *p; struct script_data *sc = 0; struct cmdlist_element *temp; - unsigned long loops = 0; void *go = NULL; void obj_command_interpreter(obj_data *obj, char *argument); @@ -2578,8 +2577,8 @@ int script_driver(void *go_adress, trig_data *trig, int type, int mode) if (process_if(p + 6, go, sc, trig, type)) { temp->original = cl; } else { + cl->loops = 0; cl = temp; - loops = 0; } } else if (!strn_cmp("switch ", p, 7)) { cl = find_case(trig, cl, go, sc, type, p + 7); @@ -2599,9 +2598,10 @@ int script_driver(void *go_adress, trig_data *trig, int type, int mode) if (cl->original && process_if(orig_cmd + 6, go, sc, trig, type)) { cl = cl->original; - loops++; + cl->loops++; GET_TRIG_LOOPS(trig)++; - if (loops == 30) { + if (cl->loops == 30) { + cl->loops = 0; process_wait(go, trig, type, "wait 1", cl); depth--; return ret_val; diff --git a/src/dg_scripts.h b/src/dg_scripts.h index e860f02..34434b1 100644 --- a/src/dg_scripts.h +++ b/src/dg_scripts.h @@ -135,6 +135,7 @@ struct cmdlist_element { char *cmd; /* one line of a trigger */ struct cmdlist_element *original; struct cmdlist_element *next; + int loops; /* for counting number of runs in a while loop */ }; struct trig_var_data { From 7036a15782f22f2eb2fb12e7b0379ca7d533fa48 Mon Sep 17 00:00:00 2001 From: Victor Augusto Borges Dias de Almeida Date: Sun, 22 Sep 2024 06:15:28 -0300 Subject: [PATCH 02/19] Changes to make the code compile normally on macOS. (#137) Changes in configure to set crypt lib dynamically depending on the OS --- .gitignore | 11 +- configure | 71 +++++---- src/Makefile.in | 4 +- src/Makefile.macOS | 56 +++++++ src/conf.h.macOS | 367 +++++++++++++++++++++++++++++++++++++++++++++ src/sysdep.h | 29 +++- 6 files changed, 500 insertions(+), 38 deletions(-) create mode 100644 src/Makefile.macOS create mode 100644 src/conf.h.macOS diff --git a/.gitignore b/.gitignore index 29a5738..e671ea7 100644 --- a/.gitignore +++ b/.gitignore @@ -83,4 +83,13 @@ src/test/testfile .project .settings -.cproject \ No newline at end of file +.cproject + +# macOS generated files +.DS_Store +.DS_Store? +._* +.Spotlight-V100 +.Trashes +ehthumbs.db +Thumbs.db diff --git a/configure b/configure index 73db816..1aa45bf 100755 --- a/configure +++ b/configure @@ -1227,18 +1227,28 @@ if eval "test \"`echo '$ac_cv_func_'crypt`\" = yes"; then cat >> confdefs.h <<\EOF #define CIRCLE_CRYPT 1 EOF + CRYPTLIB="-lcrypt" + echo "CRYPTLIB set to: $CRYPTLIB" 1>&6 else echo "$ac_t""no" 1>&6 -echo $ac_n "checking for crypt in -lcrypt""... $ac_c" 1>&6 -echo "configure:1235: checking for crypt in -lcrypt" >&5 -ac_lib_var=`echo crypt'_'crypt | sed 'y%./+-%__p_%'` -if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - ac_save_LIBS="$LIBS" -LIBS="-lcrypt $LIBS" -cat > conftest.$ac_ext <&6 + echo "configure:1235: checking for crypt in -lcrypt" >&5 + + OS_NAME=$(uname) + if [ "$OS_NAME" = "Darwin" ]; then + # macOS: No need for -lcrypt + CRYPTLIB="" + echo "CRYPTLIB not needed on macOS" 1>&6 + else + # Other systems (Linux): Use -lcrypt + ac_lib_var=`echo crypt'_'crypt | sed 'y%./+-%__p_%'` + if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 + else + ac_save_LIBS="$LIBS" + LIBS="-lcrypt $LIBS" + cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then - rm -rf conftest* - eval "ac_cv_lib_$ac_lib_var=yes" -else - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -rf conftest* - eval "ac_cv_lib_$ac_lib_var=no" -fi -rm -f conftest* -LIBS="$ac_save_LIBS" - -fi -if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then - echo "$ac_t""yes" 1>&6 - cat >> confdefs.h <<\EOF + if { (eval echo configure:1254: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" + else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" + fi + rm -f conftest* + LIBS="$ac_save_LIBS" + fi + if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + cat >> confdefs.h <<\EOF #define CIRCLE_CRYPT 1 EOF - CRYPTLIB="-lcrypt" -else - echo "$ac_t""no" 1>&6 -fi - - + CRYPTLIB="-lcrypt" + echo "CRYPTLIB set to: $CRYPTLIB on Linux" 1>&6 + else + echo "$ac_t""no" 1>&6 + fi + fi fi diff --git a/src/Makefile.in b/src/Makefile.in index 5308258..1436143 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -20,8 +20,8 @@ CFLAGS = @CFLAGS@ $(MYFLAGS) $(PROFILE) LIBS = @LIBS@ @CRYPTLIB@ @NETLIB@ -SRCFILES := act.comm.c act.informative.c act.item.c act.movement.c act.offensive.c act.other.c act.social.c act.wizard.c aedit.c asciimap.c ban.c boards.c bsd-snprintf.c castle.c cedit.c class.c comm.c config.c constants.c db.c dg_comm.c dg_db_scripts.c dg_event.c dg_handler.c dg_misc.c dg_mobcmd.c dg_objcmd.c dg_olc.c dg_scripts.c dg_triggers.c dg_variables.c dg_wldcmd.c fight.c genmob.c genobj.c genolc.c genqst.c genshp.c genwld.c genzon.c graph.c handler.c hedit.c house.c ibt.c improved-edit.c interpreter.c limits.c lists.c magic.c mail.c medit.c mobact.c modify.c msgedit.c mud_event.c oasis.c oasis_copy.c oasis_delete.c oasis_list.c objsave.c oedit.c players.c prefedit.c protocol.c qedit.c quest.c random.c redit.c sedit.c shop.c spec_assign.c spec_procs.c spell_parser.c spells.c tedit.c utils.c weather.c zedit.c zmalloc.c -OBJFILES := act.comm.o act.informative.o act.item.o act.movement.o act.offensive.o act.other.o act.social.o act.wizard.o aedit.o asciimap.o ban.o boards.o bsd-snprintf.o castle.o cedit.o class.o comm.o config.o constants.o db.o dg_comm.o dg_db_scripts.o dg_event.o dg_handler.o dg_misc.o dg_mobcmd.o dg_objcmd.o dg_olc.o dg_scripts.o dg_triggers.o dg_variables.o dg_wldcmd.o fight.o genmob.o genobj.o genolc.o genqst.o genshp.o genwld.o genzon.o graph.o handler.o hedit.o house.o ibt.o improved-edit.o interpreter.o limits.o lists.o magic.o mail.o medit.o mobact.o modify.o msgedit.o mud_event.o oasis.o oasis_copy.o oasis_delete.o oasis_list.o objsave.o oedit.o players.o prefedit.o protocol.o qedit.o quest.o random.o redit.o sedit.o shop.o spec_assign.o spec_procs.o spell_parser.o spells.o tedit.o utils.o weather.o zedit.o zmalloc.o +SRCFILES := $(shell ls *.c | sort) +OBJFILES := $(patsubst %.c,%.o,$(SRCFILES)) default: all diff --git a/src/Makefile.macOS b/src/Makefile.macOS new file mode 100644 index 0000000..40d6640 --- /dev/null +++ b/src/Makefile.macOS @@ -0,0 +1,56 @@ +# tbaMUD Makefile.in - Makefile template used by 'configure' +# Clean-up provided by seqwith. + +# C compiler to use +CC = gcc + +# Any special flags you want to pass to the compiler +MYFLAGS = -Wall -Wno-char-subscripts -Wno-invalid-source-encoding -DMEMORY_DEBUG + +#flags for profiling (see hacker.doc for more information) +PROFILE = + +############################################################################## +# Do Not Modify Anything Below This Line (unless you know what you're doing) # +############################################################################## + +BINDIR = ../bin + +CFLAGS = -g -O0 $(MYFLAGS) $(PROFILE) + +LIBS = + +SRCFILES := $(shell ls *.c | sort) +OBJFILES := $(patsubst %.c,%.o,$(SRCFILES)) + +default: all + +all: .accepted + $(MAKE) $(BINDIR)/circle + $(MAKE) utils + +.accepted: + @./licheck less + +utils: .accepted + (cd util; $(MAKE) all) + +circle: + $(MAKE) $(BINDIR)/circle + +$(BINDIR)/circle : $(OBJFILES) + $(CC) -o $(BINDIR)/circle $(PROFILE) $(OBJFILES) $(LIBS) + +$%.o: %.c + $(CC) $< $(CFLAGS) -c -o $@ + +clean: + rm -f *.o depend + +# Dependencies for the object files (automagically generated with +# gcc -MM) + +depend: + $(CC) -MM *.c > depend + +-include depend diff --git a/src/conf.h.macOS b/src/conf.h.macOS new file mode 100644 index 0000000..21a9cda --- /dev/null +++ b/src/conf.h.macOS @@ -0,0 +1,367 @@ +#ifndef _CONF_H_ +#define _CONF_H_ + +/* Define to empty if the keyword does not work. */ +/* #undef const */ + +/* Define if you don't have vprintf but do have _doprnt. */ +/* #undef HAVE_DOPRNT */ + +/* Define if you have that is POSIX.1 compatible. */ +#define HAVE_SYS_WAIT_H 1 + +/* Define if you have the vprintf function. */ +#define HAVE_VPRINTF 1 + +/* Define to `int' if doesn't define. */ +/* #undef pid_t */ + +/* Define as the return type of signal handlers (int or void). */ +#define RETSIGTYPE void + +/* Define to `unsigned' if doesn't define. */ +/* #undef size_t */ + +/* Define if you have the ANSI C header files. */ +/* #undef STDC_HEADERS */ + +/* Define if you can safely include both and . */ +#define TIME_WITH_SYS_TIME 1 + +/* Define if we're compiling CircleMUD under any type of UNIX system. */ +#define CIRCLE_UNIX 1 + +/* Machine-specific dependencies for running on modern macOS systems 10.13+ (High Sierra) + * Updated by Victor Augusto Borges Dias de Almeida (aka Stoneheart), 26 June 2024. + * + * Tested on: + * - macOS 10.13: High Sierra - September 25, 2017 (Latest: 10.13.6) + * - macOS 10.14: Mojave - September 24, 2018 (Latest: 10.14.6) + * - macOS 10.15: Catalina - October 7, 2019 (Latest: 10.15.7) + * - macOS 11: Big Sur - November 12, 2020 (Latest: 11.7.10) + * - macOS 12: Monterey - October 25, 2021 (Latest: 12.7) + * - macOS 13: Ventura - November 7, 2022 (Latest: 13.7) + * - macOS 14: Sonoma - November 7, 2023 (Latest: 14.3) + * + * This file works on Apple Silicon Chips (M1, M2, M3) without futher configurations. */ +#if defined(__APPLE__) && defined(__MACH__) +#define CIRCLE_MAC_OS 1 +#endif + +/* Define if the system is capable of using crypt() to encrypt. */ +#define CIRCLE_CRYPT 1 + +/* Define if we don't have proper support for the system's crypt(). */ +/* #undef HAVE_UNSAFE_CRYPT */ + +/* Define is the system has struct in_addr. */ +#define HAVE_STRUCT_IN_ADDR 1 + +/* Define to `int' if doesn't define. */ +/* #undef socklen_t */ + +/* Define to `int' if doesn't define. */ +/* #undef ssize_t */ + +/* Define if you have the gettimeofday function. */ +#define HAVE_GETTIMEOFDAY 1 + +/* Define if you have the inet_addr function. */ +#define HAVE_INET_ADDR 1 + +/* Define if you have the inet_aton function. */ +#define HAVE_INET_ATON 1 + +/* Define if you have the select function. */ +#define HAVE_SELECT 1 + +/* Define if you have the snprintf function. */ +#define HAVE_SNPRINTF 1 + +/* Define if you have the strcasecmp function. */ +#define HAVE_STRCASECMP 1 + +/* Define if you have the strdup function. */ +#define HAVE_STRDUP 1 + +/* Define if you have the strerror function. */ +#define HAVE_STRERROR 1 + +/* Define if you have the stricmp function. */ +/* #undef HAVE_STRICMP */ + +/* Define if you have the strlcpy function. */ +#ifndef CIRCLE_MAC_OS +#define HAVE_STRLCPY 1 +#else +#define HAVE_STRLCPY 0 +#endif + +/* Define if you have the strncasecmp function. */ +#define HAVE_STRNCASECMP 1 + +/* Define if you have the strnicmp function. */ +/* #undef HAVE_STRNICMP */ + +/* Define if you have the strstr function. */ +#define HAVE_STRSTR 1 + +/* Define if you have the vsnprintf function. */ +#define HAVE_VSNPRINTF 1 + +/* Define if you have the header file. */ +#define HAVE_ARPA_INET_H 1 + +/* Define if you have the header file. */ +#define HAVE_ARPA_TELNET_H 1 + +/* Define if you have the header file. */ +#define HAVE_ASSERT_H 1 + +/* Define if you have the header file. */ +/* #undef HAVE_CRYPT_H */ +#ifdef CIRCLE_MAC_OS +#define HAVE_CRYPT_H 1 +#endif + +/* Define if you have the header file. */ +#define HAVE_ERRNO_H 1 + +/* Define if you have the header file. */ +#define HAVE_FCNTL_H 1 + +/* Define if you have the header file. */ +#define HAVE_LIMITS_H 1 + +/* Define if you have the header file. */ +/* #undef HAVE_MCHECK_H */ +#ifdef CIRCLE_MAC_OS +#define HAVE_MCHECK_H 1 +#endif + +/* Define if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define if you have the header file. */ +/* #undef HAVE_NET_ERRNO_H */ + +/* Define if you have the header file. */ +#define HAVE_NETDB_H 1 + +/* Define if you have the header file. */ +#define HAVE_NETINET_IN_H 1 + +/* Define if you have the header file. */ +#define HAVE_SIGNAL_H 1 + +/* Define if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_FCNTL_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_RESOURCE_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_SELECT_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_SOCKET_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_TIME_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_UIO_H 1 + +/* Define if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Define if you have the malloc library (-lmalloc). */ +/* #undef HAVE_LIBMALLOC */ + +/* Check for a prototype to accept. */ +/* #undef NEED_ACCEPT_PROTO */ + +#ifndef CIRCLE_MAC_OS +/* Check for a prototype to atoi. */ +#define NEED_ATOI_PROTO +/* Check for a prototype to atol. */ +#define NEED_ATOL_PROTO +#endif + +/* Check for a prototype to bind. */ +/* #undef NEED_BIND_PROTO */ + +/* Check for a prototype to bzero. */ +/* #undef NEED_BZERO_PROTO */ + +/* Check for a prototype to chdir. */ +/* #undef NEED_CHDIR_PROTO */ + +/* Check for a prototype to close. */ +/* #undef NEED_CLOSE_PROTO */ + +/* Check for a prototype to crypt. */ +/* #undef NEED_CRYPT_PROTO */ + +/* Check for a prototype to fclose. */ +/* #undef NEED_FCLOSE_PROTO */ + +/* Check for a prototype to fcntl. */ +/* #undef NEED_FCNTL_PROTO */ + +/* Check for a prototype to fflush. */ +/* #undef NEED_FFLUSH_PROTO */ + +/* Check for a prototype to fprintf. */ +/* #undef NEED_FPRINTF_PROTO */ + +/* Check for a prototype to fputc. */ +/* #undef NEED_FPUTC_PROTO */ + +/* Check for a prototype to fputs. */ +/* #undef NEED_FPUTS_PROTO */ + +/* Check for a prototype to fread. */ +/* #undef NEED_FREAD_PROTO */ + +/* Check for a prototype to fscanf. */ +/* #undef NEED_FSCANF_PROTO */ + +/* Check for a prototype to fseek. */ +/* #undef NEED_FSEEK_PROTO */ + +/* Check for a prototype to fwrite. */ +/* #undef NEED_FWRITE_PROTO */ + +/* Check for a prototype to getpeername. */ +/* #undef NEED_GETPEERNAME_PROTO */ + +/* Check for a prototype to getpid. */ +/* #undef NEED_GETPID_PROTO */ + +/* Check for a prototype to getrlimit. */ +/* #undef NEED_GETRLIMIT_PROTO */ + +/* Check for a prototype to getsockname. */ +/* #undef NEED_GETSOCKNAME_PROTO */ + +/* Check for a prototype to gettimeofday. */ +/* #undef NEED_GETTIMEOFDAY_PROTO */ + +/* Check for a prototype to htonl. */ +/* #undef NEED_HTONL_PROTO */ + +/* Check for a prototype to htons. */ +/* #undef NEED_HTONS_PROTO */ + +/* Check for a prototype to inet_addr. */ +/* #undef NEED_INET_ADDR_PROTO */ + +/* Check for a prototype to inet_aton. */ +/* #undef NEED_INET_ATON_PROTO */ + +/* Check for a prototype to inet_ntoa. */ +/* #undef NEED_INET_NTOA_PROTO */ + +/* Check for a prototype to listen. */ +/* #undef NEED_LISTEN_PROTO */ + +/* Check for a prototype to ntohl. */ +/* #undef NEED_NTOHL_PROTO */ + +/* Check for a prototype to perror. */ +/* #undef NEED_PERROR_PROTO */ + +/* Check for a prototype to printf. */ +/* #undef NEED_PRINTF_PROTO */ + +/* Check for a prototype to qsort. */ +#ifndef CIRCLE_MAC_OS +#define NEED_QSORT_PROTO +#endif + +/* Check for a prototype to read. */ +/* #undef NEED_READ_PROTO */ + +/* Check for a prototype to remove. */ +/* #undef NEED_REMOVE_PROTO */ + +/* Check for a prototype to rewind. */ +/* #undef NEED_REWIND_PROTO */ + +/* Check for a prototype to select. */ +/* #undef NEED_SELECT_PROTO */ + +/* Check for a prototype to setitimer. */ +/* #undef NEED_SETITIMER_PROTO */ + +/* Check for a prototype to setrlimit. */ +/* #undef NEED_SETRLIMIT_PROTO */ + +/* Check for a prototype to setsockopt. */ +/* #undef NEED_SETSOCKOPT_PROTO */ + +/* Check for a prototype to snprintf. */ +/* #undef NEED_SNPRINTF_PROTO */ + +/* Check for a prototype to socket. */ +/* #undef NEED_SOCKET_PROTO */ + +/* Check for a prototype to sprintf. */ +/* #undef NEED_SPRINTF_PROTO */ + +/* Check for a prototype to sscanf. */ +/* #undef NEED_SSCANF_PROTO */ + +/* Check for a prototype to strcasecmp. */ +/* #undef NEED_STRCASECMP_PROTO */ + +/* Check for a prototype to strdup. */ +/* #undef NEED_STRDUP_PROTO */ + +/* Check for a prototype to strerror. */ +/* #undef NEED_STRERROR_PROTO */ + +/* Check for a prototype to stricmp. */ +#define NEED_STRICMP_PROTO + +/* Check for a prototype to strlcpy. */ +/* #undef NEED_STRLCPY_PROTO */ + +/* Check for a prototype to strncasecmp. */ +/* #undef NEED_STRNCASECMP_PROTO */ + +/* Check for a prototype to strnicmp. */ +#define NEED_STRNICMP_PROTO + +/* Check for a prototype to system. */ +#ifndef CIRCLE_MAC_OS +#define NEED_SYSTEM_PROTO +#endif + +/* Check for a prototype to time. */ +/* #undef NEED_TIME_PROTO */ + +/* Check for a prototype to unlink. */ +/* #undef NEED_UNLINK_PROTO */ + +/* Check for a prototype to vsnprintf. */ +/* #undef NEED_VSNPRINTF_PROTO */ + +/* Check for a prototype to write. */ +/* #undef NEED_WRITE_PROTO */ + + +#endif /* _CONF_H_ */ diff --git a/src/sysdep.h b/src/sysdep.h index b7e5542..27b45db 100644 --- a/src/sysdep.h +++ b/src/sysdep.h @@ -63,6 +63,24 @@ /* Do not change anything below this line. */ +#if defined(__APPLE__) && defined(__MACH__) +/* Machine-specific dependencies for running on modern macOS systems 10.13+ (High Sierra) +* Updated by Victor Augusto Borges Dias de Almeida (aka Stoneheart), 26 June 2024. +* +* Tested on: +* - macOS 10.13: High Sierra (Lobo) - September 25, 2017 (Latest: 10.13.6) +* - macOS 10.14: Mojave (Liberty) - September 24, 2018 (Latest: 10.14.6) +* - macOS 10.15: Catalina (Jazz) - October 7, 2019 (Latest: 10.15.7) +* - macOS 11: Big Sur (GoldenGate) - November 12, 2020 (Latest: 11.7.10) +* - macOS 12: Monterey (Star) - October 25, 2021 (Latest: 12.7) +* - macOS 13: Ventura (Rome) - November 7, 2022 (Latest: 13.7) +* - macOS 14: Sonoma (Sunburst) - November 7, 2023 (Latest: 14.3) +* +* This file works on Apple Silicon Chips (M1, M2, M3) without futher configurations. +*/ +#define CIRCLE_MAC_OS 1 +#endif + /* Set up various machine-specific things based on the values determined from * configure and conf.h. */ @@ -78,7 +96,7 @@ #include #endif -#if (defined (STDC_HEADERS) || defined (__GNU_LIBRARY__)) +#if (defined (STDC_HEADERS) || defined (__GNU_LIBRARY__) || defined(CIRCLE_MAC_OS)) #include #else /* No standard headers. */ @@ -88,9 +106,8 @@ #endif extern char *malloc(), *calloc(), *realloc(); -extern void free (); - -extern void abort (), exit (); +extern void free(); +extern void abort(), exit(); #endif /* Standard headers. */ @@ -150,9 +167,11 @@ extern void abort (), exit (); #include #endif +#ifndef CIRCLE_MAC_OS #ifdef HAVE_CRYPT_H #include #endif +#endif #ifdef TIME_WITH_SYS_TIME # include @@ -434,9 +453,11 @@ struct in_addr { char *strerror(int errnum); #endif +#ifndef CIRCLE_MAC_OS #ifdef NEED_STRLCPY_PROTO size_t strlcpy(char *dest, const char *src, size_t copylen); #endif +#endif #ifdef NEED_SYSTEM_PROTO int system(const char *string); From 88b3027ec662d24f609c50ccd561e7816f24c65e Mon Sep 17 00:00:00 2001 From: Thomas Arp <357770+welcor@users.noreply.github.com> Date: Sat, 28 Sep 2024 20:29:11 +0200 Subject: [PATCH 03/19] Bugfix/135 while freezes the mud (#138) * Added loop counter per while instead of global. fixes #135 * Revert "Added loop counter per while instead of global. fixes #135" This reverts commit 59cf6a1fb217e1fad9e1886eaf4ead076058e347. * Remove extraneous reset of loop var. Fixes #135 Thanks to bylins for the fix - https://github.com/bylins From d3227f130000a8d0f31951c050c45198095d3f55 Mon Sep 17 00:00:00 2001 From: Thomas Arp <357770+welcor@users.noreply.github.com> Date: Mon, 30 Dec 2024 12:30:29 +0100 Subject: [PATCH 04/19] Fix bug in process_output (#140) Based on error report from JTP in the tbamud forums. If an attacker was able to start a session and then break the connection, the process_output function would fail. This would trigger two calls to close_socket on the same descriptor. This in turn results in a double free on the character struct. https://www.tbamud.com/kunena/4-development/5617-another-core-dump-not-long-after-the-one-earlier Thanks to JTP for the bug report. --- src/comm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/comm.c b/src/comm.c index 0c1ec9e..12323d2 100644 --- a/src/comm.c +++ b/src/comm.c @@ -1596,7 +1596,7 @@ static int process_output(struct descriptor_data *t) result = write_to_descriptor(t->descriptor, osb); if (result < 0) { /* Oops, fatal error. Bye! */ - close_socket(t); +// close_socket(t); // close_socket is called after return of negative result return (-1); } else if (result == 0) /* Socket buffer full. Try later. */ return (0); From 1ccb6adaeec7284f0da219cfe9c603c841a1389c Mon Sep 17 00:00:00 2001 From: haloway13 Date: Wed, 1 Jan 2025 03:05:54 -0700 Subject: [PATCH 05/19] Update dg_olc.c (#143) Better auto-formatting of dg_scripts. Thanks to haloway13 for the patch. --- src/dg_olc.c | 77 +++++++++++++++++++++++++++++++--------------------- 1 file changed, 46 insertions(+), 31 deletions(-) diff --git a/src/dg_olc.c b/src/dg_olc.c index 1a4affa..2bf8aae 100644 --- a/src/dg_olc.c +++ b/src/dg_olc.c @@ -1091,70 +1091,85 @@ int format_script(struct descriptor_data *d) char nsc[MAX_CMD_LENGTH], *t, line[READ_SIZE]; char *sc; size_t len = 0, nlen = 0, llen = 0; - int indent = 0, indent_next = FALSE, found_case = FALSE, i, line_num = 0, ret; + int indent = 0, indent_next = FALSE, line_num = 0, ret, i; // Declare i here + int block_stack[READ_SIZE]; // Stack to track block types + int stack_top = -1; // Initialize stack as empty + int switch_indent[READ_SIZE]; // Array to track switch indent levels + int switch_top = -1; // Index for switch_indent array + int case_indent = 0; // Track indent for case blocks + int in_switch = 0; // Flag to indicate if we're inside a switch block if (!d->str || !*d->str) return FALSE; - sc = strdup(*d->str); /* we work on a copy, because of strtok() */ + sc = strdup(*d->str); // Work on a copy t = strtok(sc, "\n\r"); *nsc = '\0'; while (t) { line_num++; skip_spaces(&t); - if (!strn_cmp(t, "if ", 3) || - !strn_cmp(t, "switch ", 7)) { + + if (!strn_cmp(t, "switch ", 7)) { indent_next = TRUE; - } else if (!strn_cmp(t, "while ", 6)) { - found_case = TRUE; /* so you can 'break' a loop without complains */ + stack_top++; + block_stack[stack_top] = 's'; // 's' for switch + switch_top++; + switch_indent[switch_top] = indent; // Save current indent level for switch + in_switch++; // We're entering a switch block + } else if (!strn_cmp(t, "case", 4) || !strn_cmp(t, "default", 7)) { + if (in_switch > 0) { // If we're inside a switch + indent = switch_indent[switch_top] + 1; // Indent cases one level under switch + indent_next = TRUE; // Indent the next line after case + case_indent = indent; // Save indent for case block + } + } else if (!strn_cmp(t, "if ", 3) || !strn_cmp(t, "while ", 6)) { indent_next = TRUE; - } else if (!strn_cmp(t, "end", 3) || - !strn_cmp(t, "done", 4)) { - if (!indent) { + stack_top++; + block_stack[stack_top] = 'l'; // 'l' for loop or conditional + } else if (!strn_cmp(t, "end", 3) || !strn_cmp(t, "done", 4)) { + if (stack_top < 0) { write_to_output(d, "Unmatched 'end' or 'done' (line %d)!\r\n", line_num); free(sc); return FALSE; } - indent--; - indent_next = FALSE; + if (block_stack[stack_top] == 's') { + indent = switch_indent[switch_top]; // Reset to the exact indent level where switch was declared + switch_top--; // Decrease switch stack if ending a switch + case_indent = 0; // Reset case indent since we're leaving the switch + in_switch--; // We're leaving a switch block + } else { + indent--; // For other blocks like while + } + stack_top--; + indent_next = FALSE; // Reset for next line } else if (!strn_cmp(t, "else", 4)) { - if (!indent) { + if (stack_top < 0 || block_stack[stack_top] != 'l') { write_to_output(d, "Unmatched 'else' (line %d)!\r\n", line_num); free(sc); return FALSE; } - indent--; + indent--; // Reduce indent for else, then increment for next statement indent_next = TRUE; - } else if (!strn_cmp(t, "case", 4) || - !strn_cmp(t, "default", 7)) { - if (!indent) { - write_to_output(d, "Case/default outside switch (line %d)!\r\n", line_num); - free(sc); - return FALSE; - } - if (!found_case) /* so we don't indent multiple case statements without a break */ - indent_next = TRUE; - found_case = TRUE; } else if (!strn_cmp(t, "break", 5)) { - if (!found_case || !indent ) { - write_to_output(d, "Break not in case (line %d)!\r\n", line_num); + if (stack_top < 0 || (block_stack[stack_top] != 's' && block_stack[stack_top] != 'l')) { + write_to_output(d, "Break not in case or loop (line %d)!\r\n", line_num); free(sc); return FALSE; } - found_case = FALSE; - indent--; + indent = case_indent + 1; // Indent break one level deeper than case + indent_next = FALSE; // Ensure no automatic increase for next line after break } *line = '\0'; - for (nlen = 0, i = 0;i d->max_str - 1 ) { + if (ret < 0 || llen + nlen + len > d->max_str - 1) { write_to_output(d, "String too long, formatting aborted\r\n"); free(sc); return FALSE; @@ -1169,8 +1184,8 @@ int format_script(struct descriptor_data *d) t = strtok(NULL, "\n\r"); } - if (indent) - write_to_output(d, "Unmatched if, while or switch ignored.\r\n"); + if (stack_top >= 0) + write_to_output(d, "Unmatched block statements ignored.\r\n"); free(*d->str); *d->str = strdup(nsc); From 69888a5d89b893455295300d22006393d66ff474 Mon Sep 17 00:00:00 2001 From: Thomas Arp <357770+welcor@users.noreply.github.com> Date: Wed, 8 Jan 2025 22:57:39 +0100 Subject: [PATCH 06/19] Update aedit.c (#145) fixes #144 Thanks to @gbstott for the bug report --- src/aedit.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/aedit.c b/src/aedit.c index 5310c22..e8035da 100644 --- a/src/aedit.c +++ b/src/aedit.c @@ -557,7 +557,7 @@ void aedit_parse(struct descriptor_data * d, char *arg) { } if (OLC_ACTION(d)->command) free(OLC_ACTION(d)->command); - OLC_ACTION(d)->command = strdup(arg); + OLC_ACTION(d)->command = strdup(arg); break; @@ -566,10 +566,10 @@ void aedit_parse(struct descriptor_data * d, char *arg) { aedit_disp_menu(d); return; } - if (OLC_ACTION(d)->sort_as) { + if (OLC_ACTION(d)->sort_as) free(OLC_ACTION(d)->sort_as); - OLC_ACTION(d)->sort_as = strdup(arg); - } + OLC_ACTION(d)->sort_as = strdup(arg); + break; case AEDIT_MIN_CHAR_POS: From 5024dd8e66d05b49356f08a048850468e8bf823a Mon Sep 17 00:00:00 2001 From: Rumble Date: Thu, 9 Jan 2025 23:57:59 +0000 Subject: [PATCH 07/19] Updated for 2025 release --- doc/releases.txt | 1 + lib/text/greetings | 2 +- src/constants.c | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/doc/releases.txt b/doc/releases.txt index 3ef6c0d..a6f0756 100755 --- a/doc/releases.txt +++ b/doc/releases.txt @@ -10,6 +10,7 @@ to rec.games.mud.diku which originally announced CircleMUD as a publicly available MUD source code. tbaMUD Release history: +Version 2025 release: January, 2025 Version 2023 release: January, 2023 Version 2021 release: March, 2021 Version 2020 release: January, 2020 diff --git a/lib/text/greetings b/lib/text/greetings index 5bdc12a..5792e0d 100644 --- a/lib/text/greetings +++ b/lib/text/greetings @@ -1,5 +1,5 @@ T B A M U D - 2 0 2 3 + 2 0 2 5 Based on CircleMUD by Jeremy Elson and DikuMUD by Hans-Henrik Staerfeldt, Katja Nyboe, Tom Madsen, Michael Seifert, and Sebastian Hammer diff --git a/src/constants.c b/src/constants.c index c18f11f..cc6b190 100644 --- a/src/constants.c +++ b/src/constants.c @@ -24,7 +24,7 @@ * @todo cpp_extern isn't needed here (or anywhere) as the extern reserved word * works correctly with C compilers (at least in my Experience) * Jeremy Osborne 1/28/2008 */ -cpp_extern const char *tbamud_version = "tbaMUD 2023"; +cpp_extern const char *tbamud_version = "tbaMUD 2025"; /* strings corresponding to ordinals/bitvectors in structs.h */ /* (Note: strings for class definitions in class.c instead of here) */ From be8de64cf86754da86e61f40d491adac08b180c0 Mon Sep 17 00:00:00 2001 From: Thomas Arp <357770+welcor@users.noreply.github.com> Date: Wed, 19 Feb 2025 21:18:39 +0100 Subject: [PATCH 08/19] fix buffer overrun act.informative.c (#146) Ref https://www.tbamud.com/kunena/4-development/5636-bug-in-do-toggle-in-act-informative-c#10540 Thanks to Ironfist for the fix --- src/act.informative.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/act.informative.c b/src/act.informative.c index 5298e1c..a44ba72 100644 --- a/src/act.informative.c +++ b/src/act.informative.c @@ -1950,7 +1950,8 @@ ACMD(do_toggle) if (!GET_WIMP_LEV(ch)) strcpy(buf2, "OFF"); /* strcpy: OK */ else - sprintf(buf2, "%-3.3d", GET_WIMP_LEV(ch)); /* sprintf: OK */ + snprintf(buf2, sizeof(buf2), "%-3.3d", GET_WIMP_LEV(ch)); /* thanks to Ironfist for the fix for the buffer overrun here */ + if (GET_LEVEL(ch) == LVL_IMPL) { send_to_char(ch, From 392f3d90b8098a2967b7b931e3c397308973beee Mon Sep 17 00:00:00 2001 From: Rumble Date: Wed, 16 Apr 2025 12:24:37 -0700 Subject: [PATCH 09/19] Staying ahead of the power curve --- power_curve.ipynb | 81 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 power_curve.ipynb diff --git a/power_curve.ipynb b/power_curve.ipynb new file mode 100644 index 0000000..3ec0726 --- /dev/null +++ b/power_curve.ipynb @@ -0,0 +1,81 @@ +{ + "nbformat": 4, + "nbformat_minor": 0, + "metadata": { + "colab": { + "provenance": [], + "authorship_tag": "ABX9TyOj1yqYrLX9mLbUuHL9DP3T", + "include_colab_link": true + }, + "kernelspec": { + "name": "python3", + "display_name": "Python 3" + }, + "language_info": { + "name": "python" + } + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "view-in-github", + "colab_type": "text" + }, + "source": [ + "\"Open" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 569 + }, + "id": "X9G-1-Tm9yk1", + "outputId": "31c04ccd-06e7-4319-aa70-2141971ea984" + }, + "outputs": [ + { + "output_type": "display_data", + "data": { + "text/plain": [ + "
" + ], + "image/png": "iVBORw0KGgoAAAANSUhEUgAAArsAAAIoCAYAAABpkSNvAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjAsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvlHJYcgAAAAlwSFlzAAAPYQAAD2EBqD+naQAA+SFJREFUeJzs3Xdc1PUfB/DX9wbj2HsoAuJWHGkquXfqr9xZ7pGamZY7906zMk0t904zR5Zmipp77y2JIoiAKFP2je/vj4tTAhSOgzvg9Xw8eMh9x937Phzyvs+9v++PIIqiCCIiIiKiEkhi7ACIiIiIiAoLk10iIiIiKrGY7BIRERFRicVkl4iIiIhKLCa7RERERFRiMdklIiIiohKLyS4RERERlVhMdomIiIioxGKyS0REREQlFpNdIiIyGceOHYMgCJg5c6axQymQAQMGQBAEPHr0yNihvNGGDRsgCAI2bNhg7FCICgWTXaIS4NGjRxAEIcuXmZkZvLy80KtXL9y4ccPYIRapJ0+eYNKkSXjrrbdgb28PMzMzeHh4oGPHjtiwYQMyMjKMHWKRO336NHr06IEyZcrAzMwMDg4OqFKlCnr16oWNGzdmOZbJT+42bdqk+x27ePGiscMhojyQGTsAIjIcPz8/9OnTBwCQlJSEc+fOYdu2bdi9ezeOHDmCRo0aGTnCwrdt2zYMHjwYqampqFu3Lvr06QM7OztERUXh77//xsCBA7F582YcOXLE2KEWmQ0bNmDQoEGQyWTo0KEDKlasCEEQEBQUhP379+PEiRPo37+/scMEANSvXx93796Fs7OzsUPJ0dq1ayEIAkRRxLp16/D2228bOyQiegMmu0QlSIUKFbJ9/Dt16lTMmzcPU6ZMwbFjx4wSV1E5cOAA+vTpA3t7e/z+++9o06ZNlv2iKGLPnj1Ys2aNkSIseikpKRg1ahRsbGxw5swZVK9ePct+pVJpUq8LhUKBKlWqGDuMHN2/fx8nTpzA+++/j3v37mHbtm1YtGgRLC0tjR0aEb0GyxiISriRI0cCQJaPXFUqFRYtWoRatWrB0tISdnZ2aNGiBfbu3Zvl3OvXr0MQBHz22WdZtu/ZsweCIMDc3BwpKSlZ9vn4+MDX1zdbHL///jtatWoFBwcHWFhYoEaNGvj222+hVquzHPfqR+h79+5Fo0aNYGNjAx8fn9c+T7VajREjRkCj0eDXX3/NlugCgCAI6NKlC3bv3q3bNnPmTAiCkGPCl9PH+ZklIwMGDMDdu3fRpUsXODk5QRAE3LlzBzY2NvDz88s1zpo1a8LS0hKJiYm6bZmzhI0aNYKtrS0UCgXq1auHdevWvfY558WtW7fw4sULtGjRIluiCwByuTzLWA0YMAADBw4EAAwcODBLaUymy5cv47PPPkONGjVgZ2cHS0tL+Pv7Y8GCBVAqlbrjNBoNvL294eTkhPT09Bzja9q0KWQyGcLDwwHkXrPr4+MDHx8fJCUl4fPPP4enpyfMzc1Rs2ZN7Ny5M8f7fvToEXr27AlHR0dYW1ujWbNmOHHixGt/5q+T+fPo168f+vbti4SEhFwfO5Moivjhhx9QpUoVmJubw9vbG7NmzYJGo8nx+Lz+niQkJODrr79Gs2bN4OnpCTMzM3h6eqJfv3548OBBjvcdGxuLTz75BG5ublAoFHj77bfx22+/5WsMiIojJrtEpURmsiKKIrp3746xY8ciLS0NI0aMQK9evXD9+nW8//77+P7773Xn1KxZE05OTjh69GiW+8q8nZGRgdOnT+u2h4SEIDQ0FC1atMhy/KRJk9C5c2cEBQWha9eu+PTTT2FpaYnx48fjww8/zDHeHTt2oGvXrnB1dcWnn36K9u3bv/b5HT16FA8fPsQ777yDVq1avfZYc3Pz1+7Pi+DgYDRs2BDPnj3DgAED0L9/f9jb26Nbt254+PAhzpw5k+2c69ev4+bNm+jUqRNsbW0BaH8evXv3xuDBg/Hs2TP06tULH3/8MZKTkzF48GCMGzcu2/38N/l8HScnJwDAw4cPsyVMOencuTM6deoEAOjUqRNmzJih+8q0evVq/Pbbb/D398ewYcMwePBgiKKISZMmZfl5SiQSfPzxx4iNjcWuXbuyPVZQUBBOnjyJd999F2XLln1jbEqlEm3btkVgYCC6deuGPn364MGDB/jggw8QGBiY5dgnT57gnXfewa+//ooGDRpg1KhRcHZ2Rps2bXD+/Pk3PtZ/qdVqbNy4EQ4ODvjf//6Hvn37QhAErF279rXnjR8/HnPmzEFAQAA++eQTANo3WNOmTct2bH5+T+7evYvp06fD0tISXbp0wRdffIF69eph69atqF+/PkJDQ7Mcn5KSgubNm2PlypXw8/PD559/jsqVK6Nnz55vTNiJij2RiIq9kJAQEYDYrl27bPumT58uAhBbtGghiqIobty4UQQgNmvWTExPT9cdFxoaKjo7O4symUx88OCBbnvXrl1FAGJUVJRum7+/v9ikSRPRzMxMnDRpkm772rVrRQDipk2bdNsCAwN1sSUlJem2azQa8ZNPPhEBiDt37tRtX79+vQhAlEgk4qFDh/I8BjNnzhQBiFOnTs3zOaIoijNmzBABiEePHs22LzOW9evX67ZljjUAcfr06dnOOXz4sAhAHD58eLZ9Y8eOFQGI+/bt021btWqVCEAcOHCgmJGRoduenp4uvvfeeyIA8dKlS1nuJ/Px80Kj0Yh169YVAYiNGzcWV69eLd68eVNUqVS5npPT835VaGhotvM1Go04aNAgEYB46tQp3fYnT56IMplMbN68ebb7GTdunAhA3LNnj27b0aNHRQDijBkzshzr7e0tAhA7deqU5XWbOd7/fe336dNHBCDOmzcvy/bM12huP/Pc/PHHHyIAcdiwYbptTZs2FQVBEO/fv5/t+P79+4sARF9fXzEiIkK3/dmzZ6K9vb1oY2OT5Xnk9/ckPj5ejImJyfa4f//9tyiRSMSPP/44y/bM1/mQIUOybD9w4IBuPHL7eRMVd0x2iUqAzATMz89PnDFjhjhjxgxx3LhxYpMmTUQAooWFhXjmzBlRFEWxZcuWIgDx/Pnz2e5n3rx5IgBx9uzZum1Lly4VAYjbtm0TRVH7x1oQBHH+/Pli06ZNxQYNGuiOzUwwwsLCdNvef/99EYAYGhqa7fHi4+NFQRDEbt266bZlJlpdunTJ1xhkJgQrVqzI13n6Jrvu7u5ZkpVMarVaLFOmjOjk5JQleVWr1aKHh4fo4uIiKpVK3faaNWuKVlZWYkpKSrb7unHjhghAHDt2bJbtd+/eFe/evZvn5xgSEiI2atRIl9QAEBUKhdiqVStx/fr12RLXNyW7ubl8+bIIQJw5c2aW7V26dMmWFGZkZIiurq6ih4dHlvF4U7L78OHDbI/r7e0tOjo66m6npaWJ5ubmoqurq5iWlpblWI1GI1auXDnfyW6nTp1EAOLp06d129asWSMCyPKGL1Nmsrtu3bpc9924cUO3Lb+/J6/j7+8v+vj4ZNnm6+srmpmZiZGRkdmOb9WqFZNdKtF4gRpRCfLgwQPMmjULgLYW083NDb169cKXX34Jf39/AMDVq1ehUChQv379bOdnlh9cu3Yt27ajR4/iww8/xLFjxyCKIlq2bIm0tDTMmzcPL168gI2NDY4ePQo/Pz94eXnpzj937hysrKxyrT+1tLTEvXv3sm3PKT5TUqtWLZiZmWXbLpFI0Lt3byxcuBD79+/XlQQcOXIEkZGRGDlyJGQy7X+9KSkpuHnzJjw9PfH1119nu6/M+tf/jk9+L+Dy8fHBqVOncO3aNRw+fBiXLl3C6dOnceTIERw5cgSbNm3CX3/9lefyjoyMDCxbtgy//PIL7t27h6SkJIiiqNsfERGR5fhhw4bht99+w5o1a7BgwQIAwB9//IHo6GhMnjxZNx5vYm9vn2M9eNmyZXH27Fnd7aCgIKSnp6NevXrZnpMgCHjnnXcQFBSUp8cEgKioKPz555+oUKEC3nnnHd32Hj16YOTIkdi4cSPmzJkDqVSa7dy6devmGC8AxMfH67bp83ty7NgxLF68GOfPn8fz58+hUql0+159bSYmJiIkJATVqlWDu7t7tvtu0qRJqepOQqUPk12iEqRdu3Y4cODAa49JTEzMkoy+ysPDQ3dMpurVq8PV1VVXp3v06FHY2tqibt26SE1NxaxZs3Dy5ElUrFgRT548wccff5zlPmNjY6FSqXRJeE6Sk5OzbXNzc3vt8/ivzD/iT548ydd5+npdfH379sXChQuxZcsWXbK7efNm3b5McXFxEEURT548yff46KN27dqoXbu27vaxY8fQp08fHD16FD/++CNGjx6dp/vp3r079u7di0qVKqFnz55wdXWFXC5HfHw8lixZku1itLZt28LX1xcbN27E3LlzIZPJsGbNGgiCgMGDB+c5fjs7uxy3y2SyLBd8Zb5+XV1dczw+v6+tjRs3QqVSZfnZAYCtrS06deqEX375BQcOHEDHjh2znZtZm/3feAFkqaHO7+/Jjh070LNnT1hbW6Ndu3bw8fGBQqHQXVD5as2uoceDqLhhsktUytja2iI6OjrHfVFRUbpjXtW8eXP8+uuvePLkCY4dO4amTZtCKpWiYcOGsLS0xNGjR3VJ5n8vTrO1tYUgCHj+/Hm+4szrBViZMnsIHzlyBLNnz87zeRKJ9jrdV2fFMiUkJOgVX40aNVC7dm3s27cPCQkJkMvl+O2331C5cuUsfVkzx7lu3bq4dOlSnmM2lObNm2POnDkYNGgQ/v777zwluxcvXsTevXvRrl07/Pnnn1lmM8+dO4clS5ZkO0cQBAwdOhSTJk3C3r17Ua9ePQQGBqJVq1YoX768QZ8T8HJcc3udP336NF/3lznb+t8L9V61du3aHJPdvMrv78nMmTNhYWGBy5cvo2LFiln2/fLLL9nuGzDceBAVN+zGQFTK1KlTBykpKbhw4UK2fZmtmF6d/QNeJrDbtm3DnTt30LJlSwDargbvvPMO/v77b93Mb/PmzbOc26BBA8TExOD+/fuGfSL/0aJFC5QvXx5nzpzJ1j3iv16deXRwcACQ84zw1atX9Y6nb9++SEtLw86dO/Hbb78hKSlJt+BHJhsbG1StWhV3797N8pF2UbK2ts62LTOBzal7Q2Zbq44dO2b72P7kyZO5Ps7AgQMhl8uxZs0arFu3DhqNBkOGDClI6LmqXLkyzM3Ncfny5WyzzKIoZil5eJOTJ0/in3/+gZ+fHwYPHpzjl4uLC/bt25drMpkX+f09efDgAapWrZot0Y2MjMTDhw+zbLO1tYWvry+Cg4N1b2j/+xyJSjImu0SlTOZKWZMmTcrSE/Xx48dYtGgRZDIZevfuneWczGR34cKFAKBLdjP3Xbt2DYGBgahUqRI8PT2znDtq1CgAwKBBgxATE5MtnqioKNy9e7fAz0sqlWL58uWQSCT44IMP8Pfff+d43N69e9G9e3fd7cyZ1k2bNmX5KPzs2bP4+eef9Y6nV69ekEql2Lx5MzZv3gxBELIlu4B2fFJSUjBkyJAcyxVCQkLw6NGjLNvu3buXY51zTkJCQrBs2TK8ePEi276UlBTdTGzjxo112x0dHQFoXxP/5e3tDQA4depUlu23b9/G/Pnzc43Dzc0NnTt3xoEDB/DTTz/B2dkZnTt3ztNzyC9zc3N0794dT58+xeLFi7Ps27RpU57HDoCutdiUKVOwZs2aHL8+/vhjKJVKbNq0Se+Y8/t74u3tjeDg4CyzsmlpaRg+fHiW3+tMffv2RUZGBqZPn55le2BgIOt1qeQz7vVxRGQIr2s99l8ajUZ3ZXmVKlXEcePGicOHDxcdHR1FAOJ3332X43keHh4iANHJyUnUaDS67adPn9Zd4f9qW6ZXTZs2TQQg2tvbix9++KE4ceJE8eOPPxabN28uSqVScf78+bpj9e0EkOnnn38WLS0tRQBivXr1xJEjR4qTJ08WBw8eLPr5+YkAxNatW2c5J7NTQf369cVx48aJPXr0EM3MzMQuXbrk2o2hf//+b4ylXbt2oiAIolQqFZs0aZLjMRqNRnd1voeHh9i3b19x4sSJ4oABA8SGDRuKgiDoOmFkyhzvvLh69aquI0fr1q3FL774Qpw0aZLYr18/0cnJSQQg1q1bV0xOTtadExMTI1paWop2dnbiqFGjxDlz5ohz5swRRVEUVSqVWL9+fRGA2KRJE3H8+PFiz549RUtLS7F79+6vHZsjR47oYv9vh4lMr+vG4O3tneM5zZo1yzYeYWFhopubmwhAbN++vTh58mSxW7duorm5ufjuu++KAMTjx4+/duwSEhJEhUIhWllZiS9evMj1uKCgIN3vU6bMn2lISEi243PrAJKf35PMLikeHh7iyJEjxeHDh4sVKlQQ/fz8xFq1amUbj6SkJLFGjRoiAPGdd94Rv/zyS7F3796iXC4XO3bsyG4MVKIx2SUqAfKT7IqiKCqVSvHbb78V/f39RXNzc9HGxkZs1qyZ+Pvvv+d6Tq9evUQA2dofZWRkiNbW1lnak+Xk0KFD4nvvvSe6uLiIcrlcdHd3FwMCAsQ5c+ZkaVVW0GRXFEUxPDxcnDhxolinTh3R1tZWlMlkopubm/juu++K69evz9ISTBRF8fnz52K/fv1ER0dH0dLSUmzYsKF48ODB17Yey0uyu2XLFl1yt3Llytceu337drF169aig4ODKJfLxTJlyojNmzcXv/vuO/HZs2dZjs1PspuWlibu2rVLHDp0qFirVi3R2dlZlEqlooODg9i4cWNx0aJFYmpqarbz/vzzT/Htt9/WvXF49fGio6PFQYMGiZ6enqKFhYXo7+8vLl++XHz48OFrx0aj0YjlypUTAeTaOs1Qya4oiuLDhw/FHj16iHZ2dqJCoRCbNGkiHj9+XPzss89EAOLVq1dzvL9MK1euzPPPOvMNU2ZrMn2SXVHM+++JRqMRV6xYIVavXl20sLAQ3d3dxcGDB4vR0dG5jkdMTIw4dOhQ0cXFRbSwsBDr1q0r7t692yC/c0SmTBDFV/rFEBERFZLIyEiUK1cOAQEBOHHihNHiaNy4Mc6ePYuEhIQca5aJqGRhzS4RERWJxYsXQ6VSYfjw4UXyeJGRkdm2bdmyBadPn0br1q2Z6BKVEpzZJSKiQpOQkICffvoJoaGhWLNmDSpVqoQbN27kuACDoTk5OaFOnTqoVq0apFIprl27hmPHjsHGxganT5/WLbRCRCUbk10iIio0jx49gq+vLywsLNCwYUOsWLEClStXLpLHnjJlCvbu3YuwsDAkJyfDxcUFLVq0wLRp0/K9Ch0RFV9MdomIiIioxGLNLhERERGVWEx2iYiIiKjEkhk7AFOk0WgQEREBGxsbCIJg7HCIiIiI6D9EUcSLFy/g6ekJiST3+VsmuzmIiIiAl5eXscMgIiIiojd4/PgxypYtm+t+Jrs5sLGxAaAdPFtb28J/wJQU4PRpwMwMMDfP16lKjQaBcXFo6+AA+Wve1VB2HDv9FGTclBoVVoXuxsPkcHRoNBBW1g6FFKXp0ag1iLsdB4fqDpBI+XrLK46b/jh2+uG46SctIw3J95LRpEUT2CqKIHcCkJiYCC8vL13elhsmuznILF2wtbUtmmRXJgOsrAAbG8DCIl+nKjUaKNLTYevkxIQtnzh2+inIuCWrUjH5/FoAQE+bz+Bg71QYIZokjVqDdEU6nByc+Ac0Hzhu+uPY6Yfjpp+U9BSIClGbOxVRspvpTSWn/CkSERERUYnFZJeIiIiISiwmu0RERERUYjHZJSIiIqISi8kuEREREZVYTHaJiIiIqMRi6zEiKjLmEjl2+c/Frdh7kEvMjB0OERGVAkx2iajIyCQyvOvcEIoMETKJ1NjhEBFRKcAyBiIiIiIqsZjsElGRUWpU2Bx5EIcSrkClURk7HCIiKgVYxkBERSZDo8Qn974BALTXDDJyNEREVBpwZpeIiIiISiwmu0RERERUYjHZJSIiIqISi8kuEREREZVYTHaJiIiIqMRismtkERHA7/uk+Puao7FDISIiIipx2HrMyI4cAfr1M0frOuXRskmQscMhKlTmEjk2V5+Gu3H/cLlgIiIqEkx2jaxMGe2/T55bGDcQoiIgk8jQ1bUZTqjMuFwwEREVCZMqY5g5cyYEQcjyVaVKFd3+tLQ0jBgxAk5OTrC2tka3bt3w9OnTLPcRFhaGjh07QqFQwNXVFePHj4dKZborNXl6av99EmNu3ECIiIiISiCTSnYBoHr16oiMjNR9nTp1Srdv9OjR2Lt3L3bs2IHjx48jIiICXbt21e1Xq9Xo2LEjMjIycObMGWzcuBEbNmzA9OnTjfFU8iRzZjcxRY6kFJP7cRAZlEqjwu7o4zj54hZUGrWxwyEiolLA5MoYZDIZ3N3ds21PSEjA2rVrsXXrVrRs2RIAsH79elStWhXnzp1Dw4YNERgYiDt37uDw4cNwc3ND7dq1MWfOHEycOBEzZ86EmZnp1Qja2AA2NiJevBAQ8dwMlXidGpVg6Rol+t6eAwBooelj5GiIiKg0MLlk9/79+/D09ISFhQUCAgIwf/58lCtXDpcvX4ZSqUTr1q11x1apUgXlypXD2bNn0bBhQ5w9exb+/v5wc3PTHdOuXTsMHz4ct2/fRp06dXJ8zPT0dKSnp+tuJyYmAgCUSiWUSmUhPdOXPD0kCHohRWi0HL4V0t98wiuUGk2WfynvOHb6Kci4vXqORi1Coy49Y5/5XEvTczYEjpv+OHb64bjpR1SLAACVSlUkuROAPD+OSSW7DRo0wIYNG1C5cmVERkZi1qxZaNKkCW7duoWoqCiYmZnB3t4+yzlubm6IiooCAERFRWVJdDP3Z+7Lzfz58zFr1qxs2wMDA6FQKAr4rN7MzPwdAC7Y/0iJFJ8Ive7j0GueH70ex04/+oxbmjpN933c/RSkSvV7vRdnUdf5etMHx01/HDv9cNz0c/LoySJ7rJSUlDwdZ1LJbvv27XXf16xZEw0aNIC3tzd+/fVXWFpaFtrjTpo0CWPGjNHdTkxMhJeXF9q2bQtbW9tCe9xMO34RcfMm4JLqiA6e+XsnqdRocCgqCm3c3SGXsOY3Pzh2+inIuCWrUoGb2u8dKirgYJ+9ZKmk0qg1iLoeBfda7pBI+XrLK46b/jh2+uG46Sc1PRVxt+PQpEUT2FjaFMljZn4S/yYmlez+l729PSpVqoTg4GC0adMGGRkZiI+PzzK7+/TpU12Nr7u7Oy5cuJDlPjK7NeRUB5zJ3Nwc5ubZuyHI5XLI5XIDPJPX8yqjnYZ/GmOud9Ill0iYsOmJY6cffcbt1eMlUqFU/iGRSCWl8nkXFMdNfxw7/XDc8keQCgC0114VRe4EIM+PY9I/xaSkJDx48AAeHh6oW7cu5HI5jhw5otsfFBSEsLAwBAQEAAACAgJw8+ZNREdH6445dOgQbG1tUa1atSKPP688PbR1Lk+em94FdERERETFmUnN7I4bNw7vvfcevL29ERERgRkzZkAqleKjjz6CnZ0dBg8ejDFjxsDR0RG2trYYOXIkAgIC0LBhQwBA27ZtUa1aNfTt2xcLFy5EVFQUpk6dihEjRuQ4c2sqynj+m+w+Y7JLREREZEgmleyGh4fjo48+QkxMDFxcXNC4cWOcO3cOLi4uAIDvv/8eEokE3bp1Q3p6Otq1a4cff/xRd75UKsW+ffswfPhwBAQEwMrKCv3798fs2bON9ZTyJDPZjeDMLpVwZhI5VlQZj3/igyGXFM3HXEREVLqZVLL7yy+/vHa/hYUFli9fjuXLl+d6jLe3N/bv32/o0ArVq8muRgOwfJRKKrlEhr4e7XBCtIVMYlL//RARUQnFtMoEuLmKEAQRKrUEz+KYABAREREZCpNdEyCXA2722sUknjzjR7tUcqk0Khx4fg4XkoK4XDARERUJJrsmooyzNtmN4EVqVIKla5TodnMqZjzZAqUmw9jhEBFRKcBk10R4Ov47sxvNmV0iIiIiQ2GyayLKOGmXUWUZAxEREZHhMNk1EWWc/012o1nGQERERGQoTHZNRBmnf2t2n3Nml4iIiMhQmOyaCE8n1uwSERERGRqTXRPxsmaXZQxEREREhsIVDExEZrIbmyBDWroAC3PRyBERGZ6ZRI5FFUciOCGEywUTEVGR4MyuibC3VsHCTNtkP4IdGaiEkktkGFa2E95zaMDlgomIqEgw2TURggCUcdE22WcpAxEREZFhMNk1IbpklxepUQmlFtU4EXcNN1JCoOZywUREVAT4OaIJKeOsTXZZxkAlVZo6A+2vjQMAHNJ0gZWR4yEiopKPM7smxNOZZQxEREREhsRk14SwjIGIiIjIsJjsmpAyzv8uLMEyBiIiIiKDYLJrQjx1NbssYyAiIiIyBCa7JuRl6zE5RK4pQURERFRgTHZNSObMbnqGBLEJUiNHQ0RERFT8sfWYCTE3E+Fsr8TzeDkinsvhZM8+pFSyyCUyzPUbgpDEMMgE/vdDRESFjzO7JsbTRQkAeBLNul0qecwkcowu1xPdHRtDLuWFmEREVPiY7JqYMrpkl4kAERERUUEx2TUxZVy5sASVXGpRjcuJ9xCUGs7lgomIqEiwaM7EZJYxcMlgKonS1BloevkzAMChBv/jcsFERFToOLNrYnRlDEx2iYiIiAqMya6J0ZUx8AI1IiIiogJjsmtiMmd2I55zZpeIiIiooJjsmpjMmt3oWBmUKiMHQ0RERFTMMdk1Mc72KshlGoiigEjO7hIREREVCJNdEyORcGEJIiIiIkNh6zET5OmiRGikOduPUYkjl8gw2acvQl+Ec7lgIiIqEvxrY4LYfoxKKjOJHFN8++NExFkuF0xEREWCZQwmiO3HiIiIiAyDya4J4swulVQaUYM7yY8Qmv4UGlFj7HCIiKgUYBmDCeKSwVRSparT8faFjwEAh95uB4WR4yEiopKPM7smqIwLyxiIiIiIDIHJrgkq4/qyjEEUjRwMERERUTHGZNcEZZYxJKdK8SKZPyIiIiIifTGTMkFWlhrYWWvXCn7yjKUMRERERPpismuidKUM0bxIjYiIiEhfTHZNFNuPERERERUcW4+ZqMyFJR5HsYyBSg65RIbPvXogPCmCywUTEVGR4F8bE+XjoU12Q5nsUgliJpHjqwrDuFwwEREVGZYxmCgfz3QAQGikuZEjISIiIiq+mOyaKG937czuo0jO7FLJoRE1CE2NwlNlHJcLJiKiIsEyBhPl4/lvGUOkGTQaQMK3JVQCpKrTUe1cHwDAobotuFwwEREVOqZQJqqsawakUhEZSgmiYljbSERERKQPJrsmSibTJryAdnaXiIiIiPKPya4J8/63I8OjCCa7RERERPpgsmvCMtuPPWJHBiIiIiK9MNk1YZntxzizS0RERKQfJrsmjAtLEBERERUMW4+ZsJc1uyxjoJJBJkgxtMz7iEiOglSQGjscIiIqBZjsmjAfj39XUYsygygCgmDkgIgKyFxqhu8rjcKJiLMwk/ITCyIiKnwsYzBhZd2UkEhEpKVL8DSG70uIiIiI8stkk90FCxZAEAR88cUXum3NmzeHIAhZvj755JMs54WFhaFjx45QKBRwdXXF+PHjoVKpijh6wzCTiyjjogTAul0qGURRxLOMeMSrkiGKorHDISKiUsAkpwsvXryIlStXombNmtn2DRkyBLNnz9bdViheLjiqVqvRsWNHuLu748yZM4iMjES/fv0gl8vx1VdfFUnshubtkY7HT83wKMIcDWqkGDscogJJUafB53R3AMChtxrB0sjxEBFRyWdyM7tJSUno3bs3Vq9eDQcHh2z7FQoF3N3ddV+2tra6fYGBgbhz5w62bNmC2rVro3379pgzZw6WL1+OjIyMonwaBuPDhSWIiIjIxIU9tMT+/T7QaIwdSXYmN7M7YsQIdOzYEa1bt8bcuXOz7f/555+xZcsWuLu747333sO0adN0s7tnz56Fv78/3NzcdMe3a9cOw4cPx+3bt1GnTp0cHzM9PR3p6em624mJiQAApVIJpVJpyKeXM5UKEEVAo8F/XyVe/16k9jDCDMocXkGZ23LaR6/HsdNPQcbt1XM0ahEadekZ+8znWpqesyFw3PTHsdMPxy3/RBH4dkpFXDtvDzPzVCz6rghyJyDPOZpJJbu//PILrly5gosXL+a4v1evXvD29oanpydu3LiBiRMnIigoCLt37wYAREVFZUl0AehuR0VF5fq48+fPx6xZs7JtDwwMzFImUehiY7NtSrSUAfDEpUci9kdE5Hrqodc8P3o9jp1+9Bm3NHWa7vu4+ylIleb+mi6poq7z9aYPjpv+OHb64bjl3ZEj5bSJrpkK/jVOYf/+oim7TEnJ2+OYTLL7+PFjfP755zh06BAsLCxyPGbo0KG67/39/eHh4YFWrVrhwYMH8PPz0/uxJ02ahDFjxuhuJyYmwsvLC23bts1SJlFoUlOB06cBa2vgP8/dvKoCywGkxNmig6dntlOVGg0ORUWhjbs75BKTq0oxaRw7/RRk3JJVqcBN7fcOFRVwsHcvhAhNk0atQdT1KLjXcodEytdbXnHc9Mex0w/HLX/iYmTYuNkfAPDRR0Ho/mFd2FjaFMljZ34S/yYmk+xevnwZ0dHReOutt3Tb1Go1Tpw4gWXLliE9PR1SadYm9A0aNAAABAcHw8/PD+7u7rhw4UKWY54+fQoAcHfP/Y+qubk5zM2zL9wgl8shl8v1fk55plRqm+hKJNqvV1Qo8283hghzyARJrr125RIJEzY9cez0o8+4vXq8RCqUyj8kEqmkVD7vguK46Y9jpx+OW94snlMOifEyVKyWhPfffwCZzKtocicgz49jMj/FVq1a4ebNm7h27Zruq169eujduzeuXbuWLdEFgGvXrgEAPDw8AAABAQG4efMmoqOjdcccOnQItra2qFatWpE8D0PzcsuAIIhITZfgWZzJvDchIiKiUu7cCRv8tdsJEomIcfPuQyo1zZaSJpM92djYoEaNGlm2WVlZwcnJCTVq1MCDBw+wdetWdOjQAU5OTrhx4wZGjx6Npk2b6lqUtW3bFtWqVUPfvn2xcOFCREVFYerUqRgxYkSOM7fFgbmZCE8XJZ5EmyE00gyujsWzZzARoF0uuLd7WzxNecblgomIirG0VAHzv/QGAHwwMBpVayUh9oaRg8qFyczsvomZmRkOHz6Mtm3bokqVKhg7diy6deuGvXv36o6RSqXYt28fpFIpAgIC0KdPH/Tr1y9LX97iyNv93/ZjkWw/RsWbudQMq6pOwFiPrlwumIioGFuz2ANPQs3h5pGB4RNM+2Jjk5nZzcmxY8d033t5eeH48eNvPMfb2xv79+8vxKiKno9nOs7csMajiOI5O01EREQlR/BdC2xeob0Wavy8MFhZa5CS/oaTjCjfyW5KSgoOHTqE06dP486dO3j+/DkEQYCzszOqVq2KRo0aoXXr1rCysiqMeEsl3cISnNmlYk4URSSrU5GmyYA1lwsmIip2NBpg3gRvqFUCWnSIQ/N2CcYO6Y3ynOzevHkT3333HXbv3o2kpCRYWlrCy8sLDg4OEEUR//zzD44cOYJvv/0WVlZW6NatG8aOHQt/f//CjL9U8PHUJruhTHapmEtRp8H1xHsAgEO193K5YCKiYmbnJhfcvGINK2s1xs9+bOxw8iRPyW7Pnj2xa9cu1KtXDzNnzkSbNm1QrVq1bB0S1Go17ty5g8DAQOzcuRN16tRBjx49sG3btkIJvrTw/ncVNZYxEBERkbE8jZBj+fwyAIARk57A1aNoVkorqDwluxKJBJcuXULt2rVfe5xUKoW/vz/8/f0xduxYXLt2DV9//bUh4izVXi1jEEXk2muXiIiIqDCIIvD1lHJITpKiZt0kdO/3zNgh5Vmekl19Z2Zr167NWV0DKPdvN4bkVCliEqRwtlcbOSIiIiIqTY78aY8TgfaQyTWY8k3of9fAMmnFKNTSy8JchIdzZt0uSxmIiIio6CTGS/HNtHIAgAEjouBXOc3IEeWPXsnutWvXss3YHjx4EE2bNkWDBg2wZMkSgwRHL3lnljJE8CI1IiIiKjpLvyqDmGg5vP3SMHBklLHDyTe9kt0JEyZg+/btutshISHo0qULQkJCAABjxozBqlWrDBMhAWD7MSIiIip6l89a47efXQAAU78JhblF8WsbqVeye/36dTRu3Fh3e9OmTZBKpbh69SrOnz+P7t27Y8WKFQYLkrQLSwDsyEDFm1SQoItLUzS2rg4JlwsmIjJp6WkC5k3QLgncpfcz1GmQZOSI9KNXspuQkAAnJyfd7f3796NNmzZwdnYGALRp0wbBwcGGiZAAvFwymL12qTizkJpjS43pmFLmQ5hzuWAiIpO27gcPhD20gLNbBkZNeWLscPSmV7Lr4eGBu3fvAgAiIyNx+fJltG3bVrc/KSkJkuJ0mV4xkLmwBMsYiIiIqLAF37XAxh/dAADj5zyGjV3x7QSV7+WCAaBTp05YunQp0tLScP78eZibm6NLly66/devX0f58uUNFiS9UsYQac5eu0RERFRo1GpgzngfqJQSNH83Di07xBs7pALRK9mdO3cunj17hs2bN8Pe3h4bNmyAm5s2+09MTMTOnTsxYsQIgwZa2mWWMbxIliIuUQrHYvwOi0qvZFUqrI+2BgAcqrkXFrA3bkBERJTN9nWuuH3VClY2akyc97jYT7DplexaW1vj559/znVfeHg4rKysChQYZWVpIcLVUYnoWDlCI83gaJdq7JCIiIiohHkSZoYfv/YEAHw+NRwu7sVjSeDX0auwdtCgQTh//nzOdyiRICgoCEOHDi1QYJTdy/Zj7MhAREREhiWKwFcTvZGWKsVbAS/QuddzY4dkEHoluxs2bMCDBw9y3R8SEoKNGzfqHRTl7GX7MV6kRkRERIb15w5HnD9hC3MLDaYuLF5LAr9OoTyNiIgIWFpaFsZdl2pcWIKIiIgKQ8wzGRbN8gIADBkTgXLl040ckeHkuWb3999/x++//667vWrVKhw+fDjbcfHx8Th8+DDefvttw0RIOplLBoeyjIGIiIgM6NtpXkiMl6FS9RT0GfrU2OEYVJ6T3Tt37mDHjh0AAEEQcP78eVy+fDnLMYIgwMrKCk2bNsWiRYsMGynBxyOz/RhndomIiMgwjgfa4dBeR0ilIqZ/9wgyubEjMqw8J7uTJk3CpEmTAGgvQlu7di169epVaIFRdrqFJVizS8WUVJCgnWN9xKbHc7lgIiITkJQowYJJ5QAAvYc9RRX/ktftSa/WYxqNxtBxUB5kljEkJMkQ/0IKexv22qXixUJqjt21vsKJiLNcLpiIyAQsmVsWz6LM4OWThqFjIowdTqEoIdfZlQ5Wlhq4Omr73T0IZ90uERER6e/iKRv89rMLAGDad6GwsBSNHFHhyFOyK5FIIJPJkJGRobstlUpf+yWT6TVpTG9Q0Utbt3s/jMkuERER6Sc1RYK5E7wBAN37ReOthklGjqjw5CkjnT59OgRB0CWwmbep6FUsl4bT161x/zGTXSp+klWpcD3+P6hFNfbV3M3lgomIjOSnhZ54EmoON88MfDb5ibHDKVR5SnZnzpz52ttUdF7O7FoYORIi/aRo0owdAhFRqXbzshW2rXEFAEz+OhTWNiX7WizW7BYzFctpEwXO7BIREVF+ZaQLmDPOG6IooEO3GDRqmWjskAqd3oW1arUaBw8exMOHDxEXFwdRzFrULAgCpk2bVuAAKatK5bQzu/9wZpeIiIjyad0P7nj4jyUcnZUYM/OxscMpEnolu5cuXUK3bt0QHh6eLcnNxGS3cFT4t4whNkGG2AQpbEr4Rw9ERERkGPfvWGL9Mg8AwIR5YbB3LB0tTPUqY/j000+RmpqKPXv2IDY2FhqNJtuXWl06BrCoWVlq4Omi7YrBUgYiIiLKC5USmDXGG2qVgBbt49CqY7yxQyoyeiW7N27cwMSJE/Hee+/B3t7ewCHRm+hKGUJZykBERERvtnmFO+7dtIKtvQoTvwpDaWqqpVeyW7Zs2VzLF6jw8SI1Kq4kgoAm9jXhb+kDCa+PJSIqEg//scCqRdryhbGzHsPZVWXkiIqWXn9tJk6ciNWrVyMxseRfwWeK2H6MiitLqQUO1FmEheUGw1zGN2tERIVNrQZmj/GGMkOCxq3i0aFbrLFDKnJ6XaD24sULWFtbo0KFCvjwww/h5eUFqVSa5RhBEDB69GiDBElZcWaXiIiI8mLbalfcumoNKxs1Ji0oXeULmfRKdseNG6f7ftmyZTkew2S38LzafozVJEVo717gu++AY8fyfs7MmcCLF9rzitrQoUDlysDYsUX/2K+qVw/49lugeXPjxkFEVMqEPjDHT9+UAQCMnvEYbp5KI0dkHHoluyEhIYaOg/KhfJl0CIKIF8lSRMfq3SqZ/iWdNQtISsqekF66BHzyCXD0KGBjA7RpAzRqVPgB6ZNUFxPJqlT4nOqGDI0Su2puhwXs4f3FTDjv2AcAEGVSqOztkFq1AmI7t0PMB+8BEtb2EhHll0YDzBnnjfQ0CRo0TUSnD2OMHZLR6JUpeXt7GzoOygcLcxHl3DMQGmmO4McWgKuxIyolLCy0X1Qgz5UJ2bYltHgHjxZNh6DWQPY8FnZHz8Br+ndw+PMIgtcvAmS5/FelVAFyvuEjIvqvX9e74NoFGyis1Jj6TWipLF/IxCmTYiqzlIEXqRWhvXuzfxS/Zo12xrdpU2DOHGDpUqBXr+znbt4MtGsHtGoFfP01oMrHlbArV2rv888/gffeA5o1AyZNApKTXx6TmgpMnw40aaJ9nC1bst9PvXrZZ4ubN9c+r0xPnwKTJwMtWwKNGwN9+wK3br3cf+wYZH374n89ekDWuTOwalXW5xIWBgwZArzzDtCjB3DuXJ6eomgmh8rVGUoPV6T6V0HUqEF4sO472P19Bk6/7tMdV7dMPThv3Am/AaNRu0JjePywFlCr4T12Nmo0fB91/BqhepOucF2zLesDqFTwmvYNalVtjlrVW6HMvB/g8/kM+A0ycokHEVEhCA81w7L52vKFUVPC4VE2w8gRGZdeUyK+vr4Q3vAWQRAEPHjwQK+g6M0qlkvDofO2uP/YAq71jB1NKfXXX8D69cDEiUCtWkBgoDbJLFMm63GXLgHOztqk9fFjbaJaqRLQpUveHys8XJuofv+9tgb4yy+BDRuAESO0+5csAa5c0ZY/ODoCy5cDQUHamt28SknR1vm6ugKLFgFOTsC9e9rPwgDg6lVgxgyox47FUU9PtFAqIZs/X7tv6FDtcePHa8/bsCHn0pB8eNH4baRUqwSHv/5GTK/Ouu2ei1bhyeTP8HjWWIgyGaARkeHhhocrF0DlYAfrSzdQbsI8KF2dEfd+GwCA+/KNcNx9AKGLZiC1oi/c1myD/cFjePEOf3mIqGTRaIDZY32QlipF3YAX6Nr3ubFDMjq9kt1mzZplS3bVajVCQ0Nx+vRp1KhRA3Xq1DFIgJSzzPZjwY/NUQRVpCXfqVPaWdFXad6wFPP27cD772u/AO2M5rlz2lnWV9naAhMmAFIp4OOjnTG9cCF/ya5Go73YzcpKe7tDB+DiRe33KSnA779rZ5br19dumzlTe0x+HDgAxMcDmzYBdnbabV5eL/evXg0MGADxf/9DSkQERE9PbU3zDz9ok90LF4BHj4BlywAXF+05I0YAo0blL45XpFXwhuXd4CzbYju3Q0zP97Nsixw37OX+cmVgdfkGHPYe0iW7rut/RdTIAYhv3wIAEDZvAmz/Pq13XEREpmrHRhdcOWsDS4Ua0757xMseoGeyu2HDhlz3Xb9+He3atUPv3r31jYnyILP9WDDLGAyjbl3tjOurbt0Cpk3L/ZzQUKB796zbqlfXzuS+qnx5baKbydkZCM6awL2Rp+fLRDfzPuLitN+HhwNKJVCjxsv9dnZAfmvr//lHOxOcmejmtP/6dcjWrUNHUYRUELRJeHo6kJYGhIQA7u4vE10AqFkzfzH8lwj8t9AspVa1bIe5bPgVTr/8AbMnUZCkpUNQKpFavRIAQJKYBPmzGCTXrv7yBKkUKTWrQnjTGxoiomIk/JEZls7Tfro4csoTlPUu3eULmQx+ZUetWrUwbNgwTJw4EZcvXzb03dO/Mmt2gx+bv3ECkvLA0jLrLCagrV81hP9eXJWZJBb1fQgCsvWqe7Xe1vwNfZtTU4GhQ6Fq3hzHo6PRzNUV8swpAzOz/MWSRxbBIUj38syyTa2wzHLb4feDKDtnCcKnfYGkev7QWFnB7adNsLp6u1BiIiIyRRoNMHvcy/KF7v2eGTskk1Eok9tubm64c+dOYdw1/cvHMx1SqYjUdCliYzm7axTe3sB/X+fGeN2XLatNhl+9kCwxUXux2KscHIDnr9RuhYVpZ2QzVayorfNNyN4tAYB21jc0FPDyQrKHh/bNQeaXRAL4+gJRUVkf4+bNLHchEQS8ZVMJFS3KvHG5YJtTF6G4G4z4ji1fe5z1xetIqlsTzwb0QGqNKkj39YJ56BPdfo2tNZQuTlBce+Vno1ZDcfPea++XiKg4YflC7gw+sxsTE4O1a9eibNmyhr5reoVcBvh6piP4sQUiI62BAn5aTHro2ROYOxeoVk37cX1gIHD/fvYL1AqbQgF06qS9SM3OTpvU/vhj9v609eoBv/4K+PtrpwCWLs06Y9yuHbBuHTBunLbW1tlZm/y6uGif35AhwBdfQOLmBht/f235QnAw8OAB8Omn2nphb29gxgzg88+13SJ+/DFLCJZSC5ys9yNORJzNslywkKGELPp5ltZj7ss2IL51E8R07/jap5/mWw5OO/+E7bGzSPfyhNOu/bC6fhvpXi9/DtEDP4DHsvVI9y2LND8fuK7fDllCIsTS3IuHiEoMli+8nl7JbsuWOc+0xMfH4969e8jIyMDmzZsLFBi9WaVy2mQ3IsIKQOlcFcWo2rcHnjwBFi8GMjKA1q21rcFuG+Hj888/116oNnq0tra3d29tN4RXjR4NzJqlTVpdXLQrq929+3K/XK7t4vD999r7U6u19cYTJmj3BwQAixdDWL0aTTduhFQu115w17mzdr9EAnzzjfZCuf79AQ8PbXeGkSPfGL7d0TOoVedd7aISdrZIrVYRj+eMQ0yP/71xUYnnfbpCcSsIvsMnAYKA2E7tEN2/B+z+PqM7JmpEf8ifxcD38xkQpVI8790FCc0CACmnPoioeGP5wpsJopj/BWebN2+erRuDIAhwcHCAn58fBg0ahCpVqhgsyKKWmJgIOzs7JCQkwNbWtvAfMCUFOHFCu0pXPhYt+OK7sliyzQ2dOgVjx5S4l/WTlCdKjQb7IyLQwdPTcGP36afa1ltz5hjm/kxQQcctJTkeJyLOwuatAFhY2xs+wLzQaFC9WXfEvdcGEROGF81DqjWIuBIBz7c8IWGSnWccN/1x7PRT3MZt+3oXfDO1HCwVamw7fMdos7op6SmIvRGLFm1awFZRBLkT8p6v6TWze6wELmNaHGW2H4uMtAIQZ9xgSqO0NGDnTu2Mp1QKHDyobb+1fLmxIzNZKeo0VD3bG2mqdGytuQVFVW1uFh4J2+Pn8KLhWxAylHBdvx1mjyMQ2+XdIoqAiMjwHoeYs3whD7jOZjGW2X4sIsLayJGUYmfOaBeWSE/X1qsuXAg0aGDsqEyWKIoIS9N2uRCR7w+V9H9cQYDTr3tRds5iQARSK/vh/i8/Iq2ib5HFQERkSGo1MGuMN9JSpaj3TiLLF16DyW4xltl+LCpKAbUakJv+py0li4VFtguwyDQpy7gj6Pd1xg6DiMhgflnrimsXbKCwUmP6olB2X3gNDk0x5uWWATO5BiqVFGFRhdPnlIiIiEzLo2Bz/Pi1tnzhi+nh8PRi+cLrMNktxqRSoHzZzMUl2Gu3QOLjgTZtgIiI/J03c6a2q4Ghj82PlSuBtm21rcWKup5+716gefOssfTq9fL20qXa0g4iIjIIlQqY+YUP0tMkaNgsAV16P3/zSaUcyxiKuYpeabgXYvlvspv0xuMpF+vWAc2aaZflBbRJ7/vvv9xvawtUqAAMHw7UqfNy+7hx2VclK0ohIcDq1cC332qXC87tatSjR4GNG7XHi6J2Wd8GDV4m3ytXAsePA1u3Gja+vn21PYB79dIufkFERAWyZaUbbl21hpWNGlO/Cf3viuqUA71mdjMyOF1uKjIvUrsfxpldvaWlAb//rk3K/uvHH4EDB4BVq7SLLHzxBRAT83K/tbW2ZZyxhIdr/23WTBtfTsv2XrgATJoEtGypTXg3b9a2SHt1qeDCYm8PNGwI7NpV+I9FRFTCBd+zwMpvtZMy42Y9hnsZ9tjPC72SXXd3dwwdOhQnT540dDyUTxW8MssYzN9wJOVGOH1amyT6+2ffaWenTSIrVAAGDdKuCvbqsrz/LU04fFi7slqjRkCrVtqkMjU15we+fVu7EMWGDbkHFxwMfPLJy/ubN0/blxnQzsaOHq39/u23tWUMOTl5EqhVC+jXT7sIhLe3tvRg4kTt/r17tbPD//yjvY969bTbAGDLFu3zadwY6NgRWLDg5ePnVZMm2tXloO3HXVXhjXJmLhDA6QgiorxSKbXlC8oMCZq0jsf/Poh580kEQM8yhu7du2PXrl1Yu3YtvLy80KdPH/Tu3RtVq1Y1dHz0BhW8tDO7rNnVn3DtGvCm125aGvDnn9rv5fKcj3n+HJgyBRg1CmjRQpsUXr2ac5nDxYva1cVGjQK6ds35/lJTgc8+0ybhGzcCcXHa5YkXLtQm2X37assuZs3Szj7nxskJePhQmzhXqJB9f5s22iV/z5x52V3C+t92dhKJNk5PT+1qcQsWQLJ0qfax86pGDeDpUyAiAgpPT1xqsBYnIs7CQsbXLBFRXq1f5oF7N61ga6/ClIUsX8gPvWZ2V61ahaioKOzcuRP16tXDd999hxo1aqBevXpYsmQJnj59aug4KReZZQwhEeZQFsGn0iWREBmpnb3NyaBB2pnJJk20H/9XrQrUr5/zsc+faxsftmypTQ4rVAB69AAUiqzHHT2qnQ2ePDn3RBfQJrAZGcDs2dr7evttbeK5f7+2lEKheFlC4eyc+3Po2ROoVg348EPtcsaTJmnLNjLLkSwsAEtLQCZ7eT+ZK/n16qWd6fX01D7+8OGQHD6ce8w5yYwrMjJ/5xEREQDg3k1LrFnsAQCYMDcMzm78g58fendjkMvl6NKlC3bu3ImnT59i1apVsLOzw9ixY+Hl5YUOHTpg69atSM3tI9w3WLBgAQRBwBdffKHblpaWhhEjRsDJyQnW1tbo1q1btsQ6LCwMHTt2hEKhgKurK8aPHw9VUdQmGomnixLm5iqo1QJCnrCUQS/p6YB5LmM3fz7w88/a2VQvL2DGDG1SmJOKFbWJ8IcfaksEfvsNSEzMesytW8CXX2oT2LZtXx9XSIj2Pi0tX26rXVu7EHpoaJ6fHiwtgSVLgD17gMGDtUny4sVA//7aGevXOX9ee1Fe+/ZA06bAjBkQEhIgTU/P++NnJs5veiwiIsomPU3A9M99oVYJaNUxDu06c8XU/DJI6zFbW1sMHjwYX3/9Nbp06QKVSoUDBw6gT58+cHd3x/jx45GcnJzn+7t48SJWrlyJmjVrZtk+evRo7N27Fzt27MDx48cRERGBrq/MjKnVanTs2BEZGRk4c+YMNm7ciA0bNmD69OmGeJomSRAADw/t2N5n3a5+7O2zJ6WZ3NyAcuW0ZQkjRmhnVnO7QFMq1S4VvGQJUL48sH070K2b9uP/TGXLamtmf/+9aC4Qe1XZskDnzsC0adpa3IcPdbW0OYqI0NYEV6igTfY3bwYmTAAACMp8XBSRkKD918EBKeo01Ds/GMNCfkCaiskvEdGbrPjWEw+DLOHorMSX88NYvqCHAie7ISEhmDt3LqpWrYoGDRrg+PHj+Oyzz3DhwgVcu3YNffv2xQ8//IB+/frl6f6SkpLQu3dvrF69Gg4ODrrtCQkJWLt2LRYtWoSWLVuibt26WL9+Pc6cOYNz584BAAIDA3Hnzh1s2bIFtWvXRvv27TFnzhwsX768RHeQ8PTUthxjRwb9iJUra2dR36RVK21Cu2NH7scIgnb2ddgw7YywXK4tW8hkbw+sWKHtovDll69PeH19gfv3s17gdu2ato7W2/vN8b6Op6d2xjXzvuVybQnGq+7e1c4ijx6trRv29gae6bEc5YMH2tnw8uUhiiLupoQiLONZkS4XTERUHF27YIUtK9wAAFO+CYWDU8n9pLow6XWBWkxMDLZv344tW7bg/PnzMDMzw//+9z8sXLgQ7du3h+yVj3mXLVsGLy8vzJ49O0/3PWLECHTs2BGtW7fG3LlzddsvX74MpVKJ1q1b67ZVqVIF5cqVw9mzZ9GwYUOcPXsW/v7+cHNz0x3Trl07DB8+HLdv30adV/ujviI9PR3pr3wsm/jvLJ9SqYQyPzNY+lKptBcxaTTar3xQajS6md17oeZQ5vP80ixzrDLq14fF8uVQxce/7FOr0UAOQJn5c/mX5IMPIFmzBqouXQALC0hFERBFqDUaCLduQbh4EWKDBhAdHSHcugVpXBzUPj4QNZqXx9rbA8uXQ/bppxAnT4Z67tycSyPatYNs5UqIM2ZAPWQIhLg4SL/5BmL79lA7OAAaDQSNBrJXnktOJKtWAWlpEBs1gujuDiQlQbp9OwSVCqr69bX34+4OaUQEVPfuAa6u2lKHMmUgV6mg/uUXaJo0gXD9OqS7d+t6KCg1GgiiCCkA1b+PLxFFSERRdxsAJFeuQKhdG2ozMyhVLxN3jVqERl16Xq+Zz7U0PWdD4Ljpj2OnH1MZt5RkCWZ87gNRFPC/Hs/QpFUcNOo3n2csolo7gaFSqYomdwLy/Dh6JbseHh5QqVQICAjAjz/+iJ49e8Le3j7X46tXrw5XV9c33u8vv/yCK1eu4OLFi9n2RUVFwczMLNvjuLm5ISoqSnfMq4lu5v7MfbmZP38+Zs2alW17YGAgFP+9uKgwxcbqdZqnp7a36rlgYH9+VwAjBFpbo2n58gjdtQuh7doBACyfPkVbAKeio5GY2ZkAgLRuXbT98UfcX7MGwV27ok5KCuRpabgQEQHr5GTUOHcO9lu3QpaSglQXFzwcMAAhPj5ARESWYwHAfPp0NJ46FQnjx+PSmDHaWeP/sJk6Ff5r18Kxf3+ozc0R3rAhbvXpA/W/9+EeG4sGeP3P3dnbG77798P+wAGYx8dDaW2N2PLl8c+MGYiVy4GICEiqVkXd2rXhPGwYzJKTcWXkSDxu1QrlBw1CxfXrIVu2DDHVqyP8o49Qd8kSAMChqCh4xcXBX6PRPX7lFy/goVTi2CvxtPzrLwR9+CGeREQgTf2ydCHufgpSpaXv9Rp1Pff/iyh3HDf9cez0Y+xxW7GiJp6EWcDFJQUfdb6AiCvFY1b35NGia0ubksdWmIIo5n/5p5kzZ6Jv377w8/PLd2C5efz4MerVq4dDhw7panWbN2+O2rVrY/Hixdi6dSsGDhyYZQYWAOrXr48WLVrg66+/xtChQxEaGoqDBw/q9qekpMDKygr79+9H+/btc3zsnGZ2vby88Pz5c9jmtiKVIaWmAqdPa9s9WeSvFEGp0WDpsXR8+WVTlHXNwMN91wspyJJHqdHgUFQU2ri7w+zMGUiXLoVq2zZtmQDl6tVxk79hrIQzZyBdsgSqn38GZDIkq1LhENgMAHCw6x9wsHcvipBNgkatQdT1KLjXcodEytdYXnHc9Mex048pjNu5E7YY1acyAGD5tnt4u9ELo8SRH6npqYi7HYcmLZrAxrJoFltKTEyEs7MzEhISXpuv5XtmNyUlBTdu3MC5c+cMmuxevnwZ0dHReOutt3Tb1Go1Tpw4gWXLluHgwYPIyMhAfHx8ltndp0+fwt1d+wfT3d0dFy5cyHK/md0aMo/Jibm5OcxzuBpfLpdDnltPVUNSKrW1nhKJXolW2bLaX4LwaDOkpMhgZ82PrPJDLpFA1rQpEB4O+fPn2qV06Y3kEskbk12kpQEzZkD+78purx4vkQql8g+wRCoplc+7oDhu+uPY6cdY45YYL8Xccb4AgJ6DotGgaTIM1E+gUAlSbZGbTCYrmtwJyPPj5Hv0FAoFDh8+nOep47xq1aoVbt68iWvXrum+6tWrh969e+u+l8vlOHLkiO6coKAghIWFISAgAAAQEBCAmzdvIjo6WnfMoUOHYGtri2rVqhk0XlNiba2Cp4v2Arw7Dy3fcDTlqlcvJrqG1rq1dlEJIiLKk4VTvRAdZYZyvmkYOTnc2OGUCHrV7DZu3Bhnz57FkCFDDBaIjY0Navznj6KVlRWcnJx02wcPHowxY8bA0dERtra2GDlyJAICAtCwYUMAQNu2bVGtWjX07dsXCxcuRFRUFKZOnYoRI0bkOHNbklQvn4qIZ2a49cASATXz3uaNqCgJgoByFm5IU6VzuWAiov849IcDDvzmBKlUxOwfQmBhya41hqDXvPiyZctw8uRJTJ06FeHhRfeu4/vvv8f//vc/dOvWDU2bNoW7uzt2796t2y+VSrFv3z5IpVIEBASgT58+6NevX547QRRn1cprr3K//ZDtx8h0KaQWuBvwMzb6jeVywUREr3gWJcf8SeUAAANHRqLGW4b9BL0002tmt1atWlCpVJg/fz7mz58PmUyWbeZUEAQkZDaT19OxY8ey3LawsMDy5cuxfPnyXM/x9vbG/v37C/S4xZEu2X3AMgYiIqLiRBSB2WO9kRgvQ9Wayfj4Cy6vbkh6JbvdunWDwCU8TEp1P87sEhERFUe7Njnj7DE7mFtoMPuHR5AVzfVdpYZeye6GDRsMHAYVVFVfbbIb+dwMsQlSONqZcOdpKrVS1WloculTvFAmY0XNt8C3ZkRU2oU9NMfiOWUBAJ9NegLfilxK3dBMv5cF5YmNlQbl3LW9gm+zIwOZKI0o4sqLf3A/7Qk0YIs8IirdVCpg+igfpKVKUb9xInoOin7zSZRves3sZgoPD8fVq1eRkJAATQ7Llfbr168gd0/5VMMvDWFR5rj9wAJN6iQZOxwiIiJ6jQ3L3HHrqjWsbVWYvugR1zQqJHolu2lpaejfvz927doFjUYDQRCQuRDbq7W8THaLVvXyqdh/2g63eJEaERGRSbtzXYHV33sCACbMfQz3MkojR1Ry6fUeYvLkydi9ezfmzZuHY8eOQRRFbNy4EYGBgWjfvj1q1aqF69e5bG1Re3mRGpNdIiIiU5WWKmDaSF+oVQJa/y8W7bvGGjukEk2vZHfnzp0YOHAgJk6ciOrVqwMAypQpg9atW2Pfvn2wt7d/bXswKhw1/LRF7ezIQEREZLqWzC2L0AcWcHHPwKQFYWCDq8KlV7IbHR2N+vXrAwAsLbWziMnJL1ft6tatW5bFHqhoVPVNhSCIeBYnR3RsgcqxiYiIqBCc/tsWOza4AgBmfP8Idg7snlTY9Ep23dzcEBMTAwBQKBRwcHBAUFCQbn9iYiLS0tg6o6gpLET4emYA4OwumS5nuR1spQpjh0FEVOTiY6WYPdYHAPDh4Kdo2PSFcQMqJfSa/mvQoAFOnTqFiRMnAgDee+89fPPNN/Dw8IBGo8H333+Phg0bGjRQypsafql4+MQctx9YokU9dmQg02Ils0Ro4104EXEWljLWlhNR6SGKwLwJ3oiJlqN8pVR8NumJsUMqNfSa2R01ahTKly+P9HRtX9c5c+bA3t4effv2Rf/+/WFnZ4cffvjBoIFS3mRepMaODERERKZj769OOPqXA2RyDWYvDYGFpWjskEoNvWZ2GzdujMaNG+tue3l54e7du7h58yakUimqVKkCmYw1o8ZQvTwvUiMiIjIl4aFm+HaaFwDgk3ERqFIj1cgRlS75ntlNSUlB165d8fPPP2e9I4kEtWrVQo0aNZjoGlH18i/bj4l800gmJlWdhnevjsGEsLVIV6UbOxwiokKnXSXNFynJUtRp8AJ9hz81dkilTr6TXYVCgcOHDyMlJaUw4qECquKTBolERFyiDJHP5cYOhygLjSjiZPwN3Ex9xOWCiahUWL/UAzcuWcPKRo1ZSx5BKjV2RKWPXjW7jRs3xtmzZw0dCxmAhbmICmW1M2a3H7CUgYiIyFhuXrbCmu89AABffhUGT68MI0dUOumV7C5btgwnT57E1KlTER4ebuiYqIC4khoREZFxJSdJMHWkL9RqAe92ieEqaUakV7Jbq1YthIeHY/78+fD29oa5uTlsbW2zfNnZ2Rk6VsqjGrpklzO7RERExvDtdC88CTWHe5l0TJz32NjhlGp6XUnWrVs3CFzbzmRldmRg+zEiIqKid3ivPfZud4ZEImLO0kewseMqacakV7K7YcMGA4dBhpTZkeHOvx0Z+L6EiIioaDyNkOOrL70BAP1HRKFOAy7wZGx6lTHMnj0bt27dynX/7du3MXv2bL2DooKp5J0OmVREYrIU4U/ZkYFMi0JiAXOBr0siKnk0GmDG5z5IjJehWq1kDBsbYeyQCHomuzNnzsSNGzdy3X/r1i3MmjVL76CoYMzkIip5s5SBTI+VzBLPmu3DnkrTuVwwEZU4m1e44dIZW1hYqjFnaQhkfF9vEvRKdt8kNjYWZmZmhXHXlEevLi5BREREhevOdQV+/LoMAGDc7Mfw9uPCOaYizzW7J06cwLFjx3S3d+/ejeDg4GzHxcfHY/v27fD39zdIgKSfGn5p2HGYHRmIiIgKW0qyBFNH+EKtEtCyQxw6fRRj7JDoFXlOdo8ePaorTRAEAbt378bu3btzPLZatWpYunSpYSIkvWTO7LKMgUxJmjodXa9PRmx6PBbUqgu+FSOikuDb6V4IC7GAm0cGpiwM5YXhJibPye6ECRPw2WefQRRFuLq6YsWKFejWrVuWYwRBgEKhgIUF/4QZW+bCEnceWkCjASSFUrBClD9qUYODsRcAABqRrXiIqPg79IcD/vjFGYIgYvbSENg58P82U5PnZNfS0hKWltpZwpCQELi4uEChUBRaYFQwFcqmw0yuQUqaFKGRZvAtwyUKiYiIDCnqiRzzJpYDAAwcGYW6AWwzZor0mu/z9vZmomviZDKgig87MhARERUGtRqYNtIXSYky1KiThKFj2GbMVOVpZtfX1xcSiQT37t2DXC6Hr6/vG1dQEwQBDx48MEiQpJ/q5dNw474Ctx5Y4r2mCcYOh4iIqMRYv9QdV8/bQGGlxtxlbDNmyvKU7DZr1gyCIEDyb+Fn5m0ybTUrpmDbQUdc/4czu0RERIZy/aIVVi/yBABM/CoMZX1YKmjK8pTs/nd5YC4XXDy8VSUFAHAliCUnREREhvAiQYqpn/lCrRbwbpcYdOgWa+yQ6A14jX4JVqeytiPD/TALJCbxR01ERFQQogjMm1AOkeHmKOOdji/nh7HNWDGQ524M/5Weno7Vq1dj//79ePToEQDAx8cHHTp0wMcff8z2YybAxUEFL7cMPH5qhmv/KND0LV4lSsZlJbNEcovDOBFxlssFE1Gx8/s2Jxze5wipTMS85Q9hbaMxdkiUB3pN94WHh6N27doYNWoUrl+/DhcXF7i4uOD69esYNWoUateujfDwcEPHSnrQlTLcYykDERGRvh7+Y4FvpmnbjI348glq1EkxckSUV3oluyNGjEBoaCh+/fVXPHnyBMePH8fx48fx5MkTbN++HWFhYRgxYoShYyU9MNklIiIqmPQ0AZM/9UV6mgQNmiaiz7Cnxg6J8kGvMoYjR45g9OjR6N69e7Z9PXr0wJUrV7hcsIlgskumJE2djj63ZuNZagxmcblgIiomlswti+C7Cjg6KzFrSQhXJS1m9Ep2bWxs4Orqmut+d3d32NjY6B0UGU5msnv3kQVS0gQoLEQjR0SlmVrU4LdnJwBwuWAiKh6OB9rh1/XanGfm4kdwdlUZOSLKL73emwwcOBAbNmxASkr2epWkpCSsX78egwcPLnBwVHAezkq4OSmh0Qi4GcwLgoiIiPIq6okcs0f7AAD6DIvCOy0SjRsQ6SVPM7u7d+/OcrtOnTr4888/UaVKFfTv3x8VKlQAANy/fx+bNm2Co6MjatasafhoKd8EAXircgr+OmOHK/cUaFCDBfVERERvolIBU0aUR0K8DNVqJWPEl1wOuLjKU7LbvXt3CIIAUcz+Efi8efOybQsPD8dHH32EDz74oOARUoG9VeVlsktERERvtvr7Mrh+0RpW1mp89eNDyM1YBlhc5SnZPXr0aGHHQYWIF6kRERHl3fXrztiwzAMAMGVhKJcDLubylOw2a9ZM971SqcTdu3fh6OiIsmXLFlpgZDiZye7NYEtkKAWYyfnulIiIKCcxz2RYvNgfoiigS+9naNspztghUQHl+wI1iUSCunXrZqvjJdPl7ZEBB1sVlCoJbj9gsyciIqKcaDTAzNHlERdngfKVUjB21mNjh0QGkO9kVyqVwtvbG+np6YURDxUCQWApA5kGhdQC0U334reK02Ah5RsvIjItm35yw/kTdjAzU2He8gewsOQnoSWBXq3HRo4ciVWrViE2NtbQ8VAhqVP532Q3iMkuGY8gCLCSWsJCYgZBEIwdDhGRzo1LVvjp6zIAgCFDbsKvcpqRIyJD0WtRCbVaDXNzc/j5+aF79+7w8fGBpWXWHq6CIGD06NEGCZIK7q3KnNklIiLKSUKcFJM/9YVaLaDt+zFo3ToMgKexwyID0SvZHTdunO77tWvX5ngMk13TklnGcP0fBVQqQKbXT56oYNLVGRh6dyGepjzDZDWXCyYi4xNFYOZoH0Q9MYeXTxq+nP8IifeNHRUZkl4pT0hIiKHjoEJWsVw6rBVqJKVIERRqgep+/HiGip5KVOPnqEAAwEQuF0xEJuDnVa44ecgecjMN5q98CGsbDbhOWsmiV7Lr7e1t6DiokEkkQO1KKTh1zQZX7imY7BIRUal364oCS7/StlEdO/MxqtRIhYbvw0scvS5Qo+KJHRmIiIi0EuOlmDS8PNQqAa3/F4tu/Z4bOyQqJHpXbt64cQNLly7FlStXkJCQAI1Gk2W/IAh48OBBgQMkw9Elu+zIQEREpZgoArPG+CAy3BxlfdIw9ZtQsEFMyaXXzO6xY8dQv3597Nu3D56ennj48CHKly8PT09PhIaGwtraGk2bNjV0rFRAmcnutSAF/vPehIiIqNTYtsYVxw9q63QXrHgIa1v+USzJ9Ep2p0+fjvLlyyMoKAjr168HAEyePBmnTp3CmTNnEB4ejg8++MCggVLBVfVJg4W5BonJUjx8Ym7scIiIiIrcrSsK/DBP20939IxwVPFPNXJEVNj0SnavXLmCwYMHw9bWFlKpFIC29y4ANGjQAMOGDcO0adMMFyUZhEwG1Kyg/aVm3S4REZU2CXFSfPlJeaiUErTqGIce/Z8ZOyQqAnoluzKZDDY2NgAAe3t7yOVyREdH6/aXL18ed+7cMUyEZFC8SI2MSSG1wKNGO7HN70suF0xERUqjAWZ+8bKf7rRvH7FOt5TQK9mtUKEC7t/XdlwWBAFVqlTBb7/9ptv/559/wt3d3TARkkEx2SVjEgQBLmb2sJdZcblgIipSm1e44eRhe5iZa7BgJet0SxO9kt0OHTpg27ZtUKlUAIAxY8Zg9+7dqFixIipWrIg//vgDw4YNM2igZBivJruiaORgiIiIisDV89b4cYG2Tnf8nMeoXIN1uqWJXsnutGnTcP36dV29bv/+/bFp0ybUqFEDtWrVwrp16zBx4sR83+9PP/2EmjVrwtbWFra2tggICMBff/2l29+8eXMIgpDl65NPPslyH2FhYejYsSMUCgVcXV0xfvx4XVJOQA2/VMikImISZAiLMjN2OFTKpKszMPqfH7D86V5kqDOMHQ4RlQKxz2WY/Kkv1GoB7bvGoHMv9tMtbfTqsyuXy+Hk5JRlW58+fdCnT58CBVO2bFksWLAAFStWhCiK2LhxIzp16oSrV6+ievXqAIAhQ4Zg9uzZunMUipcfx6vVanTs2BHu7u44c+YMIiMj0a9fP8jlcnz11VcFiq2kMDcT4V8hFVeDFLhwWwFvDyYcVHRUohqrnvwBAPicywUTUSFTq4Gpn/niWZQZfCumYtKCMNbplkImtYLae++9hw4dOqBixYqoVKkS5s2bB2tra5w7d053jEKhgLu7u+7L1tZWty8wMBB37tzBli1bULt2bbRv3x5z5szB8uXLkZHBpC5TQM0kAMDZG9ZGjoSIiKjwrF3igQsnbWFhqcbXqx5CYcU63dIoTzO77dq1w5QpU/K9UMTRo0exYMECHDx4MN+BqdVq7NixA8nJyQgICNBt//nnn7Flyxa4u7vjvffew7Rp03Szu2fPnoW/vz/c3NyyxD58+HDcvn0bderUyfGx0tPTkZ6errudmJgIAFAqlVAqlfmOPd9UKu1yLhoN8rvag/Lf45X5OO/tGknADlecuWGVr/NKGn3Gjgo2bq+eo1GL0KhLz9hnPtfS9JwNgeOmv9I+dudO2GL1Ig8AwMR5ofDxS4EmDx8olfZx05eo1l4IpFKpiiZ3AvL8OHlKdv38/NCmTRuUL18ePXv2RKtWrVCnTh1YW2edGXzx4gUuX76Mw4cPY8eOHQgNDcXgwYPzFfjNmzcREBCAtLQ0WFtb47fffkO1atUAAL169YK3tzc8PT1x48YNTJw4EUFBQdi9ezcAICoqKkuiC0B3OyoqKtfHnD9/PmbNmpVte2BgYJYyiUIXG6v3qYde8/z+K801HkB5XL5nid9DoyCXl+5f6PyMHb2kz7ilqdN038fdT0GqNMKQIRULUdf5etMHx01/pXHsnj2zwJQxNSGKAtq0eYQ65W8i4kr+7qM0jpshnDx6ssgeKyUlJU/HCaKYt2vyQ0JCsGTJEmzduhUxMTEQBAGOjo5wcHCAKIqIi4tDXFwcRFGEo6Mjevfujc8//xy+vr75CjwjIwNhYWFISEjAzp07sWbNGhw/flyX8L7q77//RqtWrRAcHAw/Pz8MHToUoaGhWWaSU1JSYGVlhf3796N9+/Y5PmZOM7teXl54/vx5ljKJQpOaCpw+DVhbAxb56z2q1GhwKCoKbdzdIZfkrSpFFIGy79bGszg5Tqy5g4Y1k/WJutjTZ+yoYOOWrEqFQ2AzAMDBrn/Awb70tCjUqDWIuh4F91rukEj5essrjpv+SuvYKTMEDOtRBbeuWqNKjWSs3n0X5hZ5bz9UWsetoFLTUxF3Ow5NWjSBjaVNkTxmYmIinJ2dkZCQ8Np8Lc8XqPn6+mLx4sX49ttvcfLkSZw9exb37t1DTEwMAMDJyQlVqlRBQEAAGjduDLlcrlfgZmZmqFChAgCgbt26uHjxIpYsWYKVK1dmO7ZBgwYAoEt23d3dceHChSzHPH36FABe2/fX3Nwc5ubZl8+Vy+V6P498USoBQQAkEu2XHuQSSb4SjwD/ZPxxwh4Xb9mgSe3S3YIlv2NHWvqM26vHS6RCqfxDIpFKSuXzLiiOm/5K29j98JUXbl21ho2dCl+vfghLKwFA/q9KK23jVlCCVDvGMpmsaHInIM+Pk+9uDDKZDC1atECLFi3yHZQ+NBpNllnXV127dg0A4OGhrckJCAjAvHnzEB0dDVdXVwDAoUOHYGtrm+PMcGkWUDMJf5ywx5kb1hiD6DefQEREZOICf3fA9nXav/+zlzxCmXK8OJ30bD1WWCZNmoT27dujXLlyePHiBbZu3Ypjx47h4MGDePDgAbZu3YoOHTrAyckJN27cwOjRo9G0aVPUrFkTANC2bVtUq1YNffv2xcKFCxEVFYWpU6dixIgROc7clmbv/Fu6cPamFUQRbMVCRcJSao47DbfgQvQVmEv5O0lEhvMo2Bxzx3sDAAZ+FokmbRKMHBGZCpNKdqOjo9GvXz9ERkbCzs4ONWvWxMGDB9GmTRs8fvwYhw8fxuLFi5GcnAwvLy9069YNU6dO1Z0vlUqxb98+DB8+HAEBAbCyskL//v2z9OUlrXrVkiGTioh4ZobHT+Uo5140V05S6SYRJPC2dEeo3AESgR8PEpFhpCRLMGGIH1KSpaj3TiKGjS99F79S7kwq2V27dm2u+7y8vHD8+PE33oe3tzf2799vyLBKJIWFiFqVUnD5rhXO3rBGOfc4Y4dERESUb6IIzJvgjYf/WMLZLQPzfgyBzKSyGzI2Tq2UYgH+L0sZiIpChkaJycErsSb6AJRqfppARAW3fZ0LDu5xhFQmYsGKh3ByURk7JDIxTHZLMa6kRkVNqVFhyeMd2BV3GiqRf5CIqGCuXbTC97O9AABfTAtH7fqls5UmvR6T3VIsc2b3apAlUtN4hRoRERUfz6Nl+HJYeahVAtp2isWHg9lZiHKWp6qWsLAwve68XLlyep1HRcPHMwNuTko8jZHj8j0FGtfmO2IiIjJ9KiUweXh5PH9qhvKVUjH1m1B2FaJc5SnZ9fHxgaDHq0itzsMi1GQ0ggAE+CdhzzEHnL1hzWSXiIiKhaVflcWVczawslZj4eoHUFiV7mXv6fXylOyuW7cuS7Kr0WiwZMkShIaGonfv3qhcuTIA4N69e9i6dSt8fHwwatSowomYDOqdmsnaZJcXqRERUTFw6A8H/LzKDQAwc/Ej+FTIeeEpokx5SnYHDBiQ5fa8efOQlpaG4OBgODk5Zdk3c+ZMNG7cGFFRUQYLkgrPqxepcXEJIiIyZQ//scDssdqFI/p9GoUW7eONGxAVC3pdoLZixQoMHTo0W6ILAC4uLhgyZAh++umnAgdHha9ulRTIpCKiYuQIjTQzdjhEREQ5SkqUYNwgP6SmaBeO+HTiE2OHRMWEXsluTEwMUlJSct2fkpKCmJgYvYOiomNpIaJOZe3P8uwNljJQ4bKUmuNi/TVY4fMZlwsmojzTaIBpo3wRFmIBN88MzF/BhSMo7/RKdhs2bIjFixfj8uXL2fZdunQJS5YsQYMGDQocHBUNXSnDTfbbpcIlESSoZuUDb3M3LhdMRHm2bok7Th6yh5m5Bt+seQAHJ/bpprzT633RsmXL0Lx5c9SvXx8NGzZExYoVAQD379/HuXPn4OjoiKVLlxo0UCo8Af7J+OEX4AxndomIyMScOmKLld95AgC+nB+GarVy/2SZKCd6Ta1Uq1YNN2/exKhRoxATE4Pt27dj+/btiImJweeff46bN2+ievXqho6VCklATW3Lsev/KJDCxSWoEGVolJgXshFbnv/N5YKJ6I0eh5hj6me+EEUB3ftF4/2eLJGk/NO74sXNzQ3ff/89vv/+e0PGQ0ZQzj0Dni4ZiHhmhkt3rND0rSRjh0QllFKjwlePNgMABohjjBwNEZmy1BQJxn3sh6REGWrWTcLYWeHGDomKqQIXzUVGRuL69etITuaCBMWVdnEJ7c+PF6kREZGxiSIwe6w3HtyzhJOrEl+vegi5mWjssKiY0jvZ/f3331GlShWULVsWb731Fs6fPw8AeP78OerUqYM9e/YYKkYqArxIjYiITMWmn9xw6A9HSGUivl75AC7uLHsi/emV7O7duxddu3aFs7MzZsyYAVF8+W7L2dkZZcqUwfr16w0WJBW+zJndMzesIPLNMxERGcnZY7ZYPr8MAGD87DDUrs9Pjqlg9Ep2Z8+ejaZNm+LUqVMYMWJEtv0BAQG4evVqgYOjolO3agoszTV4FifHnYcWxg6HiIhKocch5pj8qS80GgGdez1Dt37PjR0SlQB6Jbu3bt3CBx98kOt+Nzc3REdH6x0UFT1zMxGNamlLGY5esjFyNEREVNqkJEswdrAfXiTI4P9WEibMfcwl7Mkg9Ep2FQrFay9Ie/jwYY5LCZNpa1HvBQAmu0REVLREEZjxhQ8eBlnC2S0DC1c/hJk5a+rIMPRKdlu0aIGNGzdCpcq+gklUVBRWr16Ntm3bFjg4KlqZye6xKzbQaIwcDJVIFlIznKi7DIvLDYOZxMzY4RCRiVj3gzuO7neATK7BwlUPeUEaGZReye7cuXMRHh6Ot99+GytXroQgCDh48CCmTp0Kf39/iKKIGTNmGDpWKmT1qiXDylKN2AQZbgZbGjscKoGkghR1baugsmVZSCVSY4dDRCbg1GFbrPjm3xXSvgpDzXq8II0MS69kt0qVKjh9+jScnJwwbdo0iKKIb775Bl999RX8/f1x8uRJ+Pj4GDhUKmxyGdCkDut2iYioaITct8CUEeUhigK69X2Gzr24QhoZXr5XUFMqlbh79y4cHR1x+PBhxMXFITg4GBqNBuXLl4eLi0thxElFpEXdFzhwxg5HL9ngi168yJAMK0OjxPdh2xGSGIY+6npg3w+i0isxXooxA/yQnCRFnQYvMG72Y2OHRCVUvmd2JRIJ6tati927dwMAHBwc8Pbbb6NBgwZMdEuAzLrd41esoVYbORgqcZQaFaY+WI21zw5CJWav+Sei0kGlAiZ/6ovHjyzgXiadK6RRocp3siuVSuHt7Y309PTCiIeMrE7lFNhaqZGQJMO1fxTGDoeIiEqgpfPK4txxO1hYqvHdugdwdOabXyo8etXsjhw5EqtWrUJsbKyh4yEjk8mApm+xBRkRERWOfTsc8fMqNwDAzO8foXKNVCNHRCVdvmt2AUCtVsPc3Bx+fn7o3r07fHx8YGmZ9ep9QRAwevRogwRJRatF3RfYd9IeRy/ZYFzfp8YOh4iISohbVxT4aqI3AODjLyLQ+r144wZEpYJeye64ceN0369duzbHY5jsFl+Zdbsnr1lDpdLO9hIRERVEdKQc4z72Q0a6BM3fjcPQsZHGDolKCb3SmJCQEEPHQSakVqVUONiqEJcow+V7CjSokWLskIiIqBhLSxUwbrAfnj81Q/nKqZi15BEkehVSEuWfXsmut7e3oeMgEyKRAM3eeoE9xxxw9JINk10iItKbKAKzxvjgznUr2DmosGh9MKysuUwnFR2+r6IctazHi9TI8CykZvir9rf42msQlwsmKiXWLnbHoT8cIZWJWLj6Acp6Zxg7JCpl8jSz6+vrC4lEgnv37kEul8PX1xeCILz2HEEQ8ODBA4MESUUvs2731DVrZCgFmMnZ/5AKTipI0dShNpCayuWCiUqBI3/aY8W3ZQBolwKuG5Bk5IioNMpTstusWTMIggDJvwU2mbep5KrulwYXByWexclx8bYCjWpzrXIiIsq7e7csMeNzHwDAR4Ofokvv58YNiEqtPCW7GzZseO1tKnkEAWhe9wV2HHbE0Us2THbJIJQaFVaG/47ghBB8oHnb2OEQUSF5Hi3D2IEVkJYqRcNmCfh8erixQ6JSjDW7lKvMUoajl1m3S4aRoVFizP2l+DF6H5QapbHDIaJCkJ4mYPxgPzyNMEO58mmY/1MIW1iSUen18jtx4kSejmvatKk+d08mIjPZPXPDGukZAsy5bjkREb2GKAKzx/rg5hVr2Nip8P2GYNjYqY0dFpVyeiW7zZs3z1PNrlrNF3hxVtk7He5OSkTFyHHuphWa1eWFBURElLu1i91xcI+288LXKx/C2y/d2CER6ZfsHj16NNs2tVqNR48eYdWqVdBoNFiwYEGBgyPjEgTt7O62g9q6XSa7RESUm8DfHbJ0Xqjf5IWRIyLS0ivZbdasWa77BgwYgCZNmuDYsWNo2bKl3oGRaWj1diK2HXTEwXO2mDmMSzsSEVF2t64oMGuMDwCg91B2XiDTYvAL1CQSCT788EOsWbPG0HdNRvDuO4kAgPO3rPA8nn1RiYgoq6gncowdVAHpaRI0aR2PUVPZeYFMS6F0Y4iNjUV8fHxh3DUVsTKuStSqlAJRFBB4ztbY4RARkQlJTpJgdP8KiHkmR4WqKZi7PARSzouQidGrjCEsLCzH7fHx8Thx4gS++eYbNGnSpECBkelo/04Crv+jwP7Tduj1bpyxw6FizFwixy7/ubgVew9yLhdMVKyp1cDUEb64f1cBJxclvt/wAFbWGmOHRZSNXsmuj49Prt0YRFFEw4YNsXLlygIFRqajQ6NELNjggYNnbaFWg+/aSW8yiQzvOjeEIkOEjMsFExVr388qi5OH7WFuocF364LhUTbD2CER5UivZHfdunXZkl1BEODg4AA/Pz9Uq1bNIMGRaQjwT4KdtQrP4+W4dFeBBjVSjB0SEREZ0S/rXPDLWjcAwKwlIajxFv8ukOnSK9kdMGCAgcMgUyaTAW0bJmLHYUfsP23HZJf0ptSosDnyIP5JCMb7XC6YqFg6ddgWi2Z4AQA+mxSO1v+LN25ARG/A5YIpT9r/25Xhr9N2Ro6EirMMjRKf3PsGi6J+43LBRMVQ0C1LTBpeHhqNgE4fPUf/EU+NHRLRG+k1s6tP/1xBEHDkyBF9Ho5MwLvvJAAALt6xQnSsDK6OKiNHRERERSk6Uo7R/SsgNUWK+o0TMWl+KPKwmCqR0emV7Go0GoSHh+Phw4ews7ND+fLlAQAhISGIj4+Hn58fypYtm+UcURQLHi0ZjYezCnUqp+BqkAIHz9qib8dYY4dERERFJCVZgtEDKiA6ygy+FVPx9aqHkMmNHRVR3uiV7M6dOxfvv/8+Vq9ejf79+0Mm096NSqXC+vXrMXHiRGzYsAGNGjUyaLBkXB0aJeBqkLYFGZNdIqLSQaUCJn1SHkG3FHBwUmLxpmDY2KmNHRZRnulVsztu3DgMHDgQgwcP1iW6ACCTyTBkyBAMHDgQY8aMMViQZBra/1vKcPCcLVSsYiAiKvFEEfhmajmc/tsO5hYaLFr/AGXKscUYFS96Jbs3btzQlS7kxNfXFzdv3tQ7KDJNDWokw8FWhbhEGS7ctjJ2OEREVMg2/eSGXZtdIAgi5i4LgX/dZGOHRJRveiW7np6e2L59O1Q5TO+pVCps374dnp6eBQ6OTItMBrRtoO3KsJ9dGYiISrTA3x2wdJ72+pvRM8LRon28cQMi0pNeye6ECRNw6tQpNGzYEGvWrMGxY8dw7NgxrF69Gg0aNMCZM2cwfvx4Q8dKJqBDI20pA5Nd0oe5RI7N1adhsmdPLhdMZMKuXbDCjC98AAAfDn6KXkOijRsQUQHodYHa0KFDIZVKMWXKFAwdOlS3mpooinBxccGKFSswZMgQgwZKpqFdgHZm92qQApHPZfBwZvEu5Z1MIkNX12Y4oTLjcsFEJupRsDnGDqwAZYYEzd+Nw+gZ4cYOiahA9Ep2AWDw4MHo378/Ll68iLCwMACAt7c36tWrl+WiNSpZ3JxUqFctGZfuWOHAGTsMfD/G2CEREZGBxDyT4fN+FZEQL0P1OsmYuywEUr4vpWKuQFmpTCZDQEAAAgICDBUPFQMdGiXg0h0r/HXGlsku5YtKo8Lu6OO4++IftNXUN3Y4RPSKlGQJRvevgCeh5ihTLh2L1gfDwpI98qn403u54MTERCxYsADt2rVDnTp1cOHCBQBAbGwsFi1ahODg4Hzf508//YSaNWvC1tYWtra2CAgIwF9//aXbn5aWhhEjRsDJyQnW1tbo1q0bnj7NulRhWFgYOnbsCIVCAVdXV4wfPz7HC+lIf5lLBwees4WSQ0v5kK5Rou/tOfgqYjuUGrYvIjIVmb1071y3gp2DCj9suQ8nF/4HTyWDXslueHg46tSpg+nTpyM8PBw3btxAUlISAMDR0RErV67E0qVL832/ZcuWxYIFC3D58mVcunQJLVu2RKdOnXD79m0AwOjRo7F3717s2LEDx48fR0REBLp27ao7X61Wo2PHjsjIyMCZM2ewceNGbNiwAdOnT9fnaVIu3q6WDCc7FRKSZDhz3drY4RARUQGIIjD/S29dL93vNwTD2y/d2GERGYxeye748ePx4sULXLt2DcePH8+2FHDnzp1x+PDhfN/ve++9hw4dOqBixYqoVKkS5s2bB2tra5w7dw4JCQlYu3YtFi1ahJYtW6Ju3bpYv349zpw5g3PnzgEAAgMDcefOHWzZsgW1a9dG+/btMWfOHCxfvhwZGZxFMhSp9GVXht+O2Rs3GCIiKpDV33vg923OkEhEzPvxIWrWYy9dKln0qtkNDAzE6NGjUa1aNcTEZK/ZLF++PB4/flygwNRqNXbs2IHk5GQEBATg8uXLUCqVaN26te6YKlWqoFy5cjh79iwaNmyIs2fPwt/fH25ubrpj2rVrh+HDh+P27duoU6dOjo+Vnp6O9PSX72ITE7Uf0yuVSiiVygI9jzxRqbRvrTUa7Vc+KP89XpnP8wqqU4tYbN7vhN1/22PhF2H4tyFHsWKssSvuCjJur56jUYvQqEvP2Gc+19L0nA2B46a/vIzdH9udseo7bV/8cXNC0bR1HDSlfCVgvub0I6q1E58qlapocicgz4+jV7KbmpoKFxeXXPe/ePFCn7sFANy8eRMBAQFIS0uDtbU1fvvtN1SrVg3Xrl2DmZkZ7O3tsxzv5uaGqKgoAEBUVFSWRDdzf+a+3MyfPx+zZs3Ktj0wMBAKhULv55JvsbF6n3roNc+vMKjLRcHCwhePn5pjyfEUVKoUX6SPb0hFPXYlhT7jlqZO030fdz8FqdIIQ4ZULERd5+tNHxw3/eU2dpcvu+Kred4AgG7d/sE71e8i4kpRRmba+JrTz8mjJ4vssVJSUvJ0nF7JbrVq1XDixAkMGzYsx/179uzJdRb1TSpXroxr164hISEBO3fuRP/+/XH8+HG97iuvJk2ahDFjxuhuJyYmwsvLC23btoWtrW2hPjYAIDUVOH0asLYGLCzydapSo8GhqCi0cXeHXKL39YZ62dE4ETsPO+LpzUr4onnx68NozLErzgoybsmqVODflcQdKirgYO9eCBGaJo1ag6jrUXCv5Q6JlK+3vOK46e91Y3frqhW++bYyNBoJOnR7jgmLEiAIXPkU4GtOX6npqYi7HYcmLZrAxtKmSB4z85P4N9Er2f3iiy/Qv39/1KxZEz169AAAaDQaBAcHY9asWTh79ix27dqlz13DzMwMFSpUAADUrVsXFy9exJIlS9CzZ09kZGQgPj4+y+zu06dP4e6u/YPp7u6u6wrx6v7MfbkxNzeHubl5tu1yuRxyuVyv55EvSiUgCIBEov3Sg1wiKfKErUereOw87Ig9Rx3wzaiIYlnKABhn7EoCfcbt1eMlUqFU/iGRSCWl8nkXFMdNf/8du0fB5hg9oBLSUqVo2CwB074Ng1TGsf0vvubyR5BqkwCZTFY0uROQ58fR66fYp08fzJ49G1OnTkWlSpUAAO+++y4qV66MX375BV999RU6d+6sz11no9FokJ6ejrp160Iul+PIkSO6fUFBQQgLC9P1+Q0ICMDNmzcRHf1yWcNDhw7B1tYW1apVM0g89FKHRgmwMNfgQbgFbty3NHY4VAyYSeRYUWU8xrh3gVxSNP8ZEtFLz6LkGNm7IhLiZKhWKxkLVz+E3Iy9dKlk03tRiSlTpqBv377YtWsXgoODodFo4Ofnh65du6J8+fJ63eekSZPQvn17lCtXDi9evMDWrVtx7NgxHDx4EHZ2dhg8eDDGjBkDR0dH2NraYuTIkQgICEDDhg0BAG3btkW1atXQt29fLFy4EFFRUZg6dSpGjBiR48wtFYy1QoN2DRPx+3F77PrbHrUqpRo7JDJxcokMfT3a4YRoC5mEKy0SFaWkRAlG9amAyHBzePmkYfGmYCiseBEWlXwF+mtTrlw5jB49Otv2uLg4LF26NN/9baOjo9GvXz9ERkbCzs4ONWvWxMGDB9GmTRsAwPfffw+JRIJu3bohPT0d7dq1w48//qg7XyqVYt++fRg+fDgCAgJgZWWF/v37Y/bs2QV5mvQa3VrG4ffj9tj9twNmfxJp7HCIiCgH6WkCxgyqgPt3FXByUWLp1vtwdOaiEVQ65DvZFUUR0dHRsLe3zzZbGh4ejkWLFmHNmjVITk7Od7K7du3a1+63sLDA8uXLsXz58lyP8fb2xv79+/P1uKS/95omQC7T4PZDSwQ9MkdlHzYip9ypNCoceH4Ot5KC0IzLBRMVCbUamDbSF1fO2sDKWo0lW+6jrDd7z1PpkeeaXVEUMW3aNDg4OMDT0xNWVlbo1KkTYmNjkZKSgi+++AIVK1bEkiVL0KxZMxw9erQw4yYTYW+jRqv62lZzu/52MHI0ZOrSNUp0uzkVM55s4XLBREVAFIFvpnnj7/0OkJtp8O3aB6hSgyVnVLrkeWb3hx9+wLx58+Dt7Y22bdsiJCQEe/fuxeDBg/Hs2TOcP38effr0wYQJE1C1atXCjJlMTLeWcThwxg67/rbH5EHsS0hEZCq2bauC3b+6QhBEzF7yCG831r8PPlFxledkd926dahfvz6OHz+uK1+YMGECvv32W5QtWxZXrlyBv79/oQVKpqtTswQM+0rElXtWCHliBt8ynLEjIjK27etc8euv2kUjJs4LQ5v344wcEZFx5LmM4f79++jVq1eWOt2PP/4YgLYzAxPd0svFQYVmb2lnC3YftTduMEREhL92O+K7mdpEd9jYcHTv/9zIEREZT56T3bS0NDg7O2fZ5uTkBADw8/MzbFRU7HRrGQ+AdbtERMZ2+m9bzBztAwDo2PEhBo1ipxwq3fK1qISQyxJZUqnUIMFQ8dW5eTwA4OwNazyJ5mIBRETGcP2iFSYM8YNaJaBd5xgMHnyz2K5uSWQo+Wo99uWXX2L+/Pm622q1GoC2nMHKyirLsYIg4Pr16wYIkYqDMq5KBNRMwtkb1thzzB4jPnhm7JCIiEqV+3csMXpABaSnSfBOiwRM/zYEz24ZOyoi48tzstu0adMcZ3ZdXV0NGhAVX91axuHsDWvs+pvJLuXMTCLHooojEZwQwuWCiQzocYg5PutVEYnxMtSsm4SvV3EZYKJMeU52jx07VohhUEnQrWU8xi32wvErNoh8LoMHV+eh/5BLZBhWthNOSM5yuWAiA3kaIcenH1ZEzDM5KlZNweJNwbBUaKBRGzsyItOQr5pdotfx8czAOzWToNEI2HrA0djhEBGVeHExMoz4qCIiw83h5ZOGZdvuw9aeWS7Rq5jskkH17RADANi838nIkZApUotqnIi7hhspIVBz2omoQJJeSDCqTwU8CraEm0cGftx+H04u/ESN6L+Y7JJBfdAmDmZyDa7/o8DNYAtjh0MmJk2dgfbXxmHi43XI4HLBRHpLSxUwZkAF3L1hBQcnJZb/8g88yvJ3iignTHbJoBzt1OjYOAEAsPlPzu4SERmaMkPAxKF+uHLOBlY2aizdeh8+FdKNHRaRyWKySwbXt0MsAODnA45Q85NqIiKDUamAKSN8cfpvO5hbaLBk031UqZFq7LCITFq+k9309HT88ccfuHHjRmHEQyVAh0YJcLBVIeKZGY5esjF2OEREJYJGA8we44O/9ztAbqbBd+uCUbt+srHDIjJ5+U52zczM0KNHD5w5c6Yw4qESwNxMRM82cQB4oRoRkSGIIvD15HLYv8sJUqmI+SseomGzF8YOi6hYyHeyKwgCKlasiOfPnxdGPFRC9Ouo7cqw6297JKeyWoaISF+iCCyZUwa7NrtAEETMXhqC5u0SjB0WUbGhVxYyefJkLFu2DEFBQYaOh0qIhv7JqOCVhuRUKfYcszd2OERExdaqRR7YstIdADD121C06xRn5IiIihe9ljA6d+4cnJycUKNGDTRv3hw+Pj6wtLTMcowgCFiyZIlBgqTiRxCAPu1jMXOVJzb96Yje7WONHRKZALlEhrl+QxCSGAaZwBXUiN5k449uWL3IEwAwbk4YOn0YY+SIiIofvf7aLFu2TPf9kSNHcjyGyS716RCDmas8cfiCLZcPJgCAmUSO0eV64kTEWcilcmOHQ2TStq52xdJ5ZQEAI758gg8HPTNyRETFk15lDBqN5o1favacKvX8ynL5YCIifezY4IJFM70AAEPGRGDgyCgjR0RUfPHKISpUXD6YXqUW1biceA9BqeFcLpgoF3u2OuHrKeUAAAM+i8TQMZFGjoioeCtQsnvu3DnMnz8fo0ePxv379wEAKSkpuHLlCpKSkgwSIBVvXD6YXpWmzkDTy5/hi7CVXC6YKAf7djhi3gRvAECvIU8x4ssICIKRgyIq5vRKdjMyMtC1a1c0atQIU6ZMwQ8//IDHjx9r71AiQdu2bVmvSwCyLh+8icsHExHl6uDvDpg9xgeiKKDHgGiMnhHORJfIAPRKdqdNm4Z9+/bhp59+QlBQEERR1O2zsLBAjx498PvvvxssSCre+v/bc3fjPiekZ/B/biKi/zq81x7TR/pCoxHQudczjJ/zmIkukYHolexu27YNw4cPx9ChQ+HomP3Co6pVq+Lhw4cFDo5Kho6NE1DGNQPP4uT47ai9scMhIjIpR/60x5QR5aFWC/hfj+eY/HUYJLyihshg9Pp1io6Ohr+/f677pVIpUlJS9A6KShaZDBjSWbvi3opdLkaOhojIdPy93x6TP9Umuh26xWDad6FMdIkMTK9fKS8vL9y7dy/X/adPn0aFChX0DopKno87P4dUKuL4FRvcecgL1YiIjv5lj0nDy0OtEtC+awxmfP8IUqmxoyIqefRKdnv16oWVK1fi7Nmzum3Cv8VFq1evxq+//op+/foZJkIqEcq4KvFek3gAwMrdzsYNhojIyI4dtMOXn2gT3Xe7xGDmYia6RIVFrxXUpkyZgnPnzqFp06aoWrUqBEHA6NGjERsbi/DwcHTo0AGjR482dKxUzH3S7Tn2HHPAxn1OmP/ZEygsxDefRCWKXCLDZJ++CH0RzuWCqdQ6HmiHL4dpE912nWOZ6BIVMr1mds3MzHDgwAGsX78e5cuXR5UqVZCeno6aNWtiw4YN2Lt3L6T8zaX/aNMgEeXLpCMhSYZfDnJFtdLITCLHFN/+6OPckssFU6l07IAdJg4tD5VSgradYjFrSQhkfN9HVKj0/hUTBAF9+vRBnz59DBkPlWASCTCs6zNMXFoWK3a5YFCnGGOHRERUZI78+e/FaCoBbd6PxewfmOgSFQW9ZnZXrlyJu3fvGjoWKgUGvh8DuUyDi3escPmuwtjhUBHTiBrcSX6E0PSn0IgaY4dDVGQO/eGAya9cjDZnKRNdoqKiV7I7fPhw1KhRAy4uLujSpQsWLVqEixcvQqPhHy96PRcHFbq3igfAC9VKo1R1Ot6+8DE+ebQM6ep0Y4dDVCQO7HHA1M98oVYL6NhdezEaE12ioqNXshsVFYXt27ejd+/eCAsLw4QJE9CwYUPY29ujbdu2mDNnDo4dO2bgUKmkGN79GQDg578ckZDEhpJEVHLt3+WI6SO1ie57PZ9j+iJejEZU1PR6b+nq6oru3buje/fuAIAXL17gzJkzOHnyJHbu3ImZM2dCEASoVCqDBkslQ+PaSahWPhV3Hlpiy34njPjgmbFDIiIyuL3bnTB7rDdEUbsEMFdGIzKOAv/aPXjwALt27cKvv/6K7du3459//oFCoUDLli0NER+VQIIAfNJVm+Cu2OUCkR3IiKiE2bnRGbPG+EAUBXTtw0SXyJj0+tVbtmwZevbsCU9PT1SsWBHjxo1DTEwMhg8fjvPnzyM+Ph6BgYGGjpVKkL4dY6GwUOPWA0ucumZt7HCIiAzm51WuWDDZGwDw4eCnmLSAiS6RMelVxjBq1ChIpVJ069YN48ePR926dQ0dF5Vw9jZq9Ho3Fmv2uOD7ra5oUifJ2CERERXYuh/c8ePXZQAA/UdE4bNJT/DvAqNEZCR6vdccMWIEatSogZ07d6JRo0Zo3LgxJk2ahP379yMhIcHQMVIJNaZ3NABgzzF7/BNqbuRoiIj0J4rATws9dYnusHERTHSJTIReye7SpUtx9epVxMbGYvfu3WjatClOnTqFrl27wsnJCbVr18bIkSMNHSuVMFV90/C/JvEQRQGLfnYzdjhUBOQSGT736oFuDo24XDCVGKIILJlTBmuXeAAARk4Jx5DRkUx0iUxEgaqIbG1t0aFDB3z11VfYtGkTfvjhB1SsWBE3btzAjz/+aKgYqQQb1+cpAGDjn06IjmXyU9KZSeT4qsIwfOz6LpcLphJBrQbmf1kOW1a6AwDGzw1D/0+fGjkqInqV3tnFnTt3cPLkSZw4cQInT57EkydPAACenp748MMP0aRJE4MFSSVX07eS8Ha1ZFy8Y4XlO1wwa1iksUMiIsoTlRKYOdoHB35zgiCImLIwFJ17cRl0IlOjV7Lr7OyMuLg4iKKIKlWqoH379mjcuDGaNGkCHx8fA4dIJZkgAOP6PkXPSeWx/FdXTOwfBYUFe5GVVBpRg9DUKDxVxsGKywVTMZaeJmDS8PI4EWgPqUzEnB9C0LZTnLHDIqIc6JXs9u/fH02aNEHjxo3h7MwlX6lguraIg2+ZdIQ8MceGvc74tAcXmSipUtXpqHauDwDgUN0WUBg5HiJ9pCRLMG6QHy6csoW5hQZfr3yAxq0TjR0WEeVCr5rd7777Dp07d2aiSwYhkwFjemlr3Bb97Aq12sgBERHlIjFeis8+qogLp2yhsFJjyeb7THSJTFyBrgg6fvw4/vzzT4SGhgIAvL290bFjRzRr1swgwVHpMfD9GMxY5YkH4RbYc8we3VrFGzskIqIsnkfLMKp3RfxzRwFbexV+2HIfNeqkGDssInoDvZLdjIwMfPTRR9izZw9EUYS9vT0AID4+Ht999x26dOmCbdu2QS7n1daUN1aWGnza/RnmrvXAN5vd0LVlPNv2EJHJCA81w2e9KiL8kQWcXJRYvu0fVKiaZuywiCgP9CpjmDVrFn777TeMHTsWkZGRiI2NRWxsLKKiojBu3Djs3r0bs2fPNnSsVMJ99kE0zM00OH/LGqevWxk7HCIiAEDwXQsM7lwF4Y8sUKZcOtbuucdEl6gY0SvZ3bp1K/r374+FCxfCze3lYgCurq74+uuv0a9fP2zevNlgQVLp4OakQr+O2rY93252N3I0RETA9YtWGNKtMmKi5ahQNQVr99xDWZ8MY4dFRPmgV7IbGRmJBg0a5Lq/QYMGiIqK0jsoKr3G9NZeqPb7cXvcDLYwcjREVJqdOmKLTz+shBcJMtR6Owmrdv4DZzeVscMionzSK9ktW7Ysjh07luv+48ePo2zZsvrGRKVYFZ90dG+l7VU5a5WnkaMhQ5MJUgwt8z7+Z18fUkFq7HCIcvXXbkeMHVQB6WkSNGqZgOXb/oGtPVvFEBVHeiW7/fv3x6+//opPPvkEQUFBUKvV0Gg0CAoKwvDhw7Fjxw4MGDDAwKFSaTFjSAQEQcSuvx1wLcjS2OGQAZlLzfB9pVEY4fYezKRmxg6HKEdbVrhi2khfqFUC2neNwXfrgmFhycVuiIorvboxTJ48GQ8ePMCqVauwevVqSCTanFmj0UAURfTv3x+TJ082aKBUetSokIaebeLwS6AjZq7yxJ7vHhg7JCIqBTQaYMmcsvh5lfZalI8+forRM8Ih0WtaiIhMhV7JrlQqxYYNGzBmzBj8+eefCAsLA6Dts9uhQwfUrFnToEFS6TNjaAR+PeyA34/b4/JdBepWZS/LkkAURTzLiEe8KhnWImfKyHQoMwTMGuONA785AQA+nxaOPsOesgUiUQmQr/eraWlp2L59OxYsWIA1a9bAxcUFkyZNwk8//YSffvoJX375ZYES3fnz5+Ptt9+GjY0NXF1d0blzZwQFBWU5pnnz5hAEIcvXJ598kuWYsLAwdOzYEQqFAq6urhg/fjxUKl5UUJxU8UlHr3axAIAZKz2MHA0ZSoo6DT6nu+OjBwuQpmbrJjINyUkSfNG/Ag785gSpTMTsH0LQ9xMmukQlRZ5ndqOjo/HOO+8gJCQE4r8zMgqFAnv27EHr1q0NEszx48cxYsQIvP3221CpVJg8eTLatm2LO3fuwMrqZd/VIUOGZOnjq1AodN+r1Wp07NgR7u7uOHPmDCIjI9GvXz/I5XJ89dVXBomTisb0IZHYFuiIP0/Z4/wtBRrU4OwuERnW82gZRvevgLs3rGCpUGPh6ocIaM7lf4lKkjzP7M6ZMwePHj3C6NGjsW/fPixevBiWlpYYNmyYwYI5cOAABgwYgOrVq6NWrVrYsGEDwsLCcPny5SzHKRQKuLu7675sbW11+wIDA3Hnzh1s2bIFtWvXRvv27TFnzhwsX74cGRnsjVicVCyXjr4dtH13Z6xkZwYiMqxHweYY9H4V3L1hBQcnJVbu/IeJLlEJlOeZ3cDAQPTr1w/ffvutbpubmxt69eqFoKAgVK5c2eDBJSQkAAAcHR2zbP/555+xZcsWuLu747333sO0adN0s7tnz56Fv79/lsUu2rVrh+HDh+P27duoU6dOtsdJT09Henq67nZiovY/O6VSCaVSafDnlY1KBYii9uoIjSZfpyr/PV6Zz/OKiy8HRWDzficcPGuH41cVeKdWksHuu6SPXWEpyLi9eo5GLUKjLj1jn/lcS9NzNoTCGrer560x/uOKSEyQwcsnDYs3/QMvn3RoSlB3Mb7m9MNx04+o1n7qr1KpiiZ3AvL8OHlOdsPCwjBx4sQs2xo3bgxRFPH06VODJ7sajQZffPEFGjVqhBo1aui29+rVC97e3vD09MSNGzcwceJEBAUFYffu3QCAqKioLIkuAN3t3Ba6mD9/PmbNmpVte2BgYJYSiUIXG6v3qYdK6iIeAtCypS0OHfLBqKXOmD37H4M/RIkdu0Kmz7i9Wqcbdz8FqdIIQ4ZULERd5+tNH4Yct1OnPLF4cSWoVFJUrhyLyZPPQxqbgQj9/ws2aXzN6Yfjpp+TR08W2WOlpOStvDHPyW56ejosLLKuaJV5uzAu/hoxYgRu3bqFU6dOZdk+dOhQ3ff+/v7w8PBAq1at8P/27jssiuMN4Pj37oCj9y5FREWxl6jYNWo0lthLTGyJ3dijsZfYjcYSW4pdYzSxRGNssfdeYkFRxIKAIh0Oruzvj/t55gIiEATE+TzPPXq7s7vvDnt3783Nzty9exd/f/8cHWvMmDEMHz7c8Dw+Ph5vb2+aNGli1EXijUlJgRMnwNoazLM3a5hap2N/RASN3d0xLaTj4wQOjKPMIR1Xr7pgE1GSOpVzp3X3Xai7N+G/1FuSJgWu6f/vUMISB/t3Z1ponVZHxJUI3Cu4I1eI6y2rcrPeJAk2fO/Oom+8AajfNIapC0Mxt3DOjVALHHHN5Yyot5xJSU0h5noMdRrUwcbCJk+O+eKX+NfJ1tBj9+/f5+LFi4bnL7oZ3LlzB3t7+3TlK1eunJ3dGwwaNIhdu3Zx9OjR187E9mLa4pCQEPz9/XF3d+fs2bNGZSIj9VPQurtn/MGqVCpRKpXplpuammJqapqTU8getRpkMpDLyemAjqZyeaFN2Ep4afjso2iW/+bCxGXeHPsxOFfvki7Mdfcm5aTe/llerpC9kx8kcoX8nTzv/+q/1ptWC/Mme7N5lSsAnT/Tj6GrUEAO51d6a4hrLmdEvWWPTKH/YDYxMcmb3AmyfJxsJbsTJkxgwoQJ6ZYPGDDA6LkkSchkMrTa7HV+kiSJL774gm3btnH48GH8/Pxeu83ly5cB8PDQD08VFBTE9OnTiYqKwtVV/6a2f/9+bG1tCQwMzFY8QsExrtcT1uxy4sQVa377y572jWLzOyQhB0xkCrq6NyEy+amYLljIM0mJcsYN8OP4X/bIZBJDJz6ia5+o/A5LEIQ8kuVkd9WqVW8yDkDfdWHjxo3s2LEDGxsbQx9bOzs7LCwsuHv3Lhs3buTDDz/EycmJq1evMmzYMOrWrWsY37dJkyYEBgby6aefMmfOHCIiIhg/fjwDBw7MsPVWeDt4uan5slsEU3/wZNRiL1rUicNcKSYleNsoFWZ8X3oUR8NPiemChTwRGW7KsO7FuX3DEqW5jqmLQnm/eWx+hyUIQh7KcrLbvXv3NxkHAMuWLQP0E0f806pVq+jRowdmZmYcOHCABQsWkJSUhLe3N+3atWP8+PGGsgqFgl27dtG/f3+CgoKwsrKie/fuRuPyCm+nUd0i+XG7M6GPlSz+xZUvu0Xmd0iCIBRgN69aMqyHP88izXByUTNvVQhlK4nxugXhXZOj6YLfFOk104d6e3tz5MiR1+7H19eX3bt351ZYQgFhZaFjxsDH9Jjsx7SfPOjeIhpXRzEz3ttEkiSStCmodGliumDhjTq8147xA/1QpSgoFpDCwrUheHiJsdYF4V1UoJJdQXidTz98zqJNrly8ZcWkFZ4sG/Mgv0MSsiFZq8L1aEsA9lfciUU+xyMUPvoRF1xZ+LUXkiSjRr04Zi2/h7VtARwzVQLe5Li+Wv3NQmj+fywha0S95YhMK8PExIS01DRU8tyZDt7U1BSF4r/f3yGSXeGtIpfDt8MfUa9PAN9vc2ZghyjKFs+dF5UgCG83dZqMmWN8+H2Tfiixtp88ZdT0B5gUxE86LchiZciRI8vN4WX+QZIk3N3dUSQq3tgxCiNRbzljJVlh4W5BZHgkT+VPc22/9vb2uLu7/6e/RUF8CxCETNWtnEjbBjFsPeTAiAVe7FkckqtDkQmC8PaJiTZhVO9iXDpjg1yuH3Ghy+dRBfO9QQISwUJpgaub6xtNqDQqDSbm4qM+u0S9ZZ+EhFalxcrKKldaYyVJIjk5mago/cgpL0bdygnxlxTeSnOGPGLXcTv2nbbjzxO2fFhbzGcvCO+qkFvmDO9RnPCHSqxstMxYeo9aDQvwe4IOFBoFjq6OmFtkbyKh7JLr5Jia582Yp4WJqLfs00k6tDot5ubmuZLsAlhY6Du7vRhONqf7FaMlC28lf680BnfWf9sbscALtbhPTRDeSccP2NKrVSnCHyop4pvK6p23CnaiC/qWXVnWB8QXhHeZpaUlAGq1Osf7EMmu8NYa1ysCZ3s1t+5bsGSza36HIwhCHpIkWLPUjWE9ipOcpKBKUAJrdt3Er8Tb0YdfRkHsXyEIBU9udPMRya7w1rK30TKtfzgAE5Z78jBCtJIIwrtAlSJj/CA/Fk/Xj7jQputTvtt4B3vHNzm0gSAIbyuR7Apvtd5tnlGzfCKJyQoGzfFBDN1asClkctq41KW2dRnkYrpgIQeePDLjs9al2LvdEYWJxOjpDxg7+wGmZuLFLxR8R48cxVppTWxsbK7ve/3a9RRxLZLr+y0MRLIrvNXkcvh+XBimJjp+P2rPtkP2+R2SkAlzhZL1ZScyrkhnlGK6YCGbLpyy5tNmpQj+2xIHJzVLN92mQ4+nBXPEhUKo7+d9sVZaY620xsHagfKlyzNz+kw0moJ908SLBPPFw7eIL21bteXvv//O81hqBNXgbthd7Ozs8vzY7zKR7ApvvTL+Kkb9f+rgQXO8iUsUl7UgFCaSBL+udWFA55LEPjcloGwy6/68SZWgxPwO7Z3TuElj7obd5cr1K3wx9AtmfD2DBfMX5HdYAKSlZT5D3qVrl7gbdpcdu3aQmppK+9btX7tNbjMzM8PN3e2V/VC1Wi06XQGcAOUtJ7ICoVAY/9kTSvioePLMjLFLxM84glBYqFQyFi2qxJzxRdFqZDT56Dk/bb+Fe5Gc35kt5JxSqcTN3Q0fXx969+1Ng4YN2L1rNwAxMTH07tUbLzcvXOxdaNOyDSF3QgD9mKm+RXzZtnWbYV9B7wXh7+tveH7yxEkcbRxJTk4GIDY2loH9BuJbxBcPZw8+/OBDrl29Zig//evpBL0XxOqVqylTsgxOtk6Zxu7i6oKbuxsVK1Vk4BcDefTwEbeDbxsdv3HDxjjbOVOmTBlGDhtJUlKSYX1UVBQd2nTQry9Zhl9+/oXAkoEsWbQEgLD7YVgrrbl65aphm9jYWKyV1hw9chRI343hRdeDP3b+QZUKVXC0ceThg4ekpqYydvRYSviVwNXBlfq16xv28cL6tespVbwULvYudO7QmefRz1/z13t3iWRXKBTMlRLL/z918LJfXTh11SqfIxIykqRJwepQI5oFTyBFk5Lf4QgFXPhDM3q3Lc2hQz7I5RJfjHvE9CWhmFsUrv65kgRJSfnz+K/3OVhYWBhaR/t93o+LFy7yy2+/cPDoQSRJot1H7VCr1chkMmrVrsWxI8cAfWIcfCsYVYqK4FvBABw/dpwqVasYhpr6tMunPI16yrbft3Hs1DEqVqxI86bNef78ZVJ37+49dmzbwcbNGzl17lSWYo6Li+PXLb8CL4d/u3f3Hm1atqF169acPn+alStXcurkKUYMHWHYrt/n/Xj06BG79+1m/ab1/LDiB55G/feZwpKTk/l23rcsWb6Ec5fO4eLqwoihIzh75iyr163m9PnTtGnbxujLw7mz5xjQdwB9+/Xl5NmT1K1Xlzmz5vznWAorMamEUGg0fC+BHi2fsXqnM32m+3Jxww1MxRUuCG+l00dsGDegGHGxJtjapjJjeSg16iW9fsO3UHIyuDnmzxf0yOdJWOXg0JIkcfjgYQ7sP0C/Af0IuRPCH7v+4MDhA9QIqgHAT2t+opR/KXb+vpO27dpSp24dVv64EoATx05QoWIF3NzcOHb0GAGlAjh25Bi16tQC9K2sF85fIPRRKEqlEoAZs2ew6/ddbN+6nV6f9wL0XRe+X/k9Li4ur405oFgAgKG1tnmL5gSU0i+bN3ceHTt3ZODggQD4FvFl7vy5NG3UlAWLF/DwwUP27d3HkRNHqFK1CgBLli+hSoUq2a+8f1Gr1Xy76FvKlS8HwMMHD1m3Zh23Qm7h4amfNWzI8CHs37ef9WvXM/nrySz9bimNmzRm2MhhAJQoWYIzp89wYN+B/xxPYSRSAaFQ+WbII3Yds+PvuxZ8s86dMT0j8jskQRCyQaeDVYvdWT7XE0mSEVghkWGDTlKhtgPix8j89+fuP3FzdEOtVqPT6ejYuSNjJ4zl8MHDmJiY8F619wxlnZycKFGyhKHltk7dOowaMYqnT59y/Nhx6tStY0h2u/fszpnTZxg2Qp+8Xbt6jcTERHw8fIyOn5KSQui9UMNzHx+fLCW6APsO7sPCwoJzZ8/xzexvWPjdQsO6a1ev8fe1v9m8abNhmSRJ6HQ67ofeJ+ROCCYmJlSqXMmwPqBUAPb29lmvvFcwMzOjbLmyhufX/76OVqulYtmKRuVSU1NxdHIEIPhWMC0/amm0vlr1aiLZfQWR7AqFipO9lvnDHtFtkh9Tf/Sgdf1YSvu9HYPMC8K7Lj5WweRhRTm6zx6ANl2fMnxSGNE3UgCHfI3tTbK01LewvgnqZDWmlq8eg/z/PQayrG69uixYvAAzMzM8PD0wMcl6GlGmbBkcHB04fuw4x48dZ9KUSbi5uzF/3nwunL+AWq2melB1QN/66u7hzp/7/ky3Hzv7lyMZWFpl/QR8i/pib29PyYCSPI16SrdPurHvr30AJCYm0uvzXvQf2B8AjUqDibn+3Lx9vA3dBzIjl+u/jEn/6BuSlVm/LCwsjG5YS0xKRKFQcOzUsXTT41pbW792f0J6ItkVCp1PPnzOhj2O7D1lxycTinJqVTBmpoWrj58gFDY3r1ryVd9iPH6gxNRMx+jpD2j9cTQ6beF/7cpk5KgrQVaoZWCazYQ2M1ZWVvgX90+3PKBUABqNhnNnzxm6MURHR3Pn9h1KlS4F6GfCqlmrJn/s/IObN24SVCsIS0tL0lLTWPnjSipXqYzV/yuiYsWKREZEYmJigm9R39w7gf/r078P8+bO4/cdv9Pqo1ZUrFSRWzdvGc7t318SSgaURKPRcOniJUM3htvBt43Gy3V2cQYg4kkEFSpWAODalZc31GVVhQoV0Gq1PH36lFq1a2VYJqBUAOfPnjdadu7suWwf610hfhMSCh2ZDFZODMPRTsPFW1ZM/t4jv0MSBOEV9MOKOdProwAeP1BSxCeVlTuCaf1xdH6HJmRD8RLFadGyBYP6D+LkiZNcu3qNz3t8jqenJy1atjCUq1O3Dlt+2UL5CuWxtrZGLpdTq3Ytfvn5F2rXqW0o1+D9BlSrUY3OHTrz1/6/CLsfxulTp5k8cTIXL1z8z/FaWlrSo1cPpk+djiRJDB85nDOnzzB8yHCuXrnK3bt32fX7LoYPGQ7ok93GTRozeOBgzp09x6WLlxjYfyAWFhaGfVpYWFCtejXmfTOPWzdvcezoMaZOnprt2EqULEGnLp3o06sPO7bv4H7ofc6fO883c75hz+49APQf2J/9+/azcP5CQu6EsHzpctGFIRMi2RUKJU8XNSvGhAEwa7U7xy6Jn34EoaBJTpIz4YuizBrjizpNTt0msaz78yalyyfnd2hCDiz7YRmVKleiQ5sONKzbEEmS+G3Hb4YRD0Cf7Gq1WurUrZPpMplMxtYdW6lVuxb9+vSjYtmK9Pi0Bw8fPMTV1TVX4u3bvy/Bt4LZ+ttWypYry54Dewi5E0KThk2oV68e06ZOM9wgBrD8h+V4eHjQtFFTPu70Mb0+64WLq3F/4aUrlqLVaKkTVIfRI0czcfLEHMW2/IfldPmkC2NHjaVSuUp07tCZC+cv4OXjBej753637DuWLllK0HtBHDxwkFFfjcp5ZRRyMkkSE6z+W3x8PHZ2dsTFxWFra/vmD5icDEePgo0NmJtna1O1Tsfu8HA+9PTEVC6+u/xbzym+rN7pjK9HKld+voGd9cvBukXd5cx/qTeVNpXWZ4bxPDWWWc0XYGeXOx9abwOdVkf4xXA8K3siV4jr7W6wOV/1LUboHQsUComBYx7zab/IdLOhFcp604BJvAnePt4ozZVv9FCv67MrZCyr9RZYMpCBgwYaRnF4l+kkHdoULTY2Nun6Gv8XKpWK0NBQ/Pz8MP9XjpTVfK2QvHMIQsYWjniIX5FUwp4oGTzX5/UbCG+UuULJ1gozmOr1qZgu+B0lSbB9oxPdPixN6B0LnN3SWL7lNt36p090BUEQcoNIdoVCzdZax7opocjlEmv/cGLLAfv8DkkQ3lmJCXLGDfRj2pdFSVXJqVEvjg17b1Kpupj2VxCEN0eMxiAUerUqJjGmRwTTV3rQd4YvNcsnUcRVTDUqCHnp5lVLxvT349F9cxQKif6jH9OtfySiB5HwNrtx+0Z+hyBkgXibEd4Jk/qEUzUwiZh4Ez6dWBSNJr8jejclaVJwOdKC1reniumC3xGSBD//6ErPVgE8um+Oe5FUftgaTI+BItEVBCFviLca4Z1gagLrp4ZiZaHl0HlbJiz3zO+Q3lnJOhWpkmhZfxdEPzVhSLfizJvkjUYtp0GzGDbuu0n5qoVz2l9BEAomkewK74yAoqn8NOHFcGQebD9kn78BCUIhdvwvW7o0CuTkQTuU5jpGTX/AnB/uYWuvze/QBEF4x4hkV3indGoSw7CPIwH4bGoxHj9+Q9MWCcI7SpUiY+4Eb4Z2K8HzZ6YUL53M2t036djjqRhtQRCEfCGSXeGdM3vwI+pUSiAhScGsWdVITBYvA0HIDSE3zeneojS/rNSPn9zl80jW7LqFf4AqnyMTBOFdJj7lhXeOqQlsnnkPD+c0Hj60pe/0ooipVQQh57RaWLvMjU8/LM3dWxY4uahZtP4OI6Y8QmkuXlyCIOQvkewK7yR3Zw0/z7yLQqFjy34nFv787szkJQi56VGYGX3bl2TRNC/UaXLqNI7l5wM3qNkgPr9DE/JZ08ZNGTUi61PYht0Pw1ppzdUrV99gVEJuWL92PUVci+R3GFkmkl3hnVWzQiI9e/4NwMiFXhy5YJ3PERV+cpmMOvblKWdRFLl4+3mrvZgJ7ePGgVw+a4OllZYJ8+4zf9VdHJ3F2H6FUd/P+2KttGbwwMHp1g0bPAxrpTV9P+9rWLbxl41MmDwhy/v38vbibthdAssE5kq8ecFaaW14eLp40qh+Iw4fOpzfYb3Wi7+ltdIaB2sHypcuz8zpM9FkcVzOdh3acenvS9k6Zv369Rk6dGgOov3vxKeN8E5r3jyUzh9Eo9XKaPOlP7fuv9l56t91Fgpz9lSazxyfz1CaiLp+Wz2LMmF4D3+mfVmU5CQFlaon8POBG3zUOVrchFbIeXl78duW30hJeTlOtkqlYssvW/D28TYq6+joiI2NTZb3rVAocHN3w8Tk7ZrvavkPy7kbdpf9h/fj5OREhzYdCL0Xmt9hAZCWlvbKdY2bNOZu2F2uXL/CF0O/YMbXM1gwf0GW9mthYYGr69vzi6hIdoV3mkwGK8aFUqNcIjHxJjQbXILI6LfrjVYQ8ookwe7fHOnYoAzHDthjaqZjyIRHLN9ymyI+r/5QFbImKS3plQ+VRpXlsinqlCyVzYmKFStSxKsIv2//3bDs9+2/4+XtRYUKFYzK/rsbQ2DJQObOnkv/Pv1xd3KnVPFSrPxxpWH9v7sxHD1yFGulNQf2HaBmtZo42znz4QcfEhUVxb49+6hcvjIezh707NaT5ORko+MsWbTEKJag94KY/vV0w3NrpTU//fAT7Vu3x8XehcrlK3Pm9BnuhtylaeOmFClShPfrvc+9u/deWyd2dna4ubtRpkwZFixeQEpKCgf/OgjAsaPHqFerHo42jvj7+jNx3ERD6+mff/xJEdciaLX64fiuXrmKtdKaieMmGvY9sN9APuvxmeH5yRMnadywMc52zgT4BzBy2EiSkl7+LQNLBjJrxix69+qNh7MHXwz44pVxK5VK3Nzd8PH1oXff3jRo2IDdu3YDEBMTQ+9evfFy88LF3oU2LdsQcifEsO2/uzFM/3o6tarVYtOmTfj7+2NnZ0fnzp1JSEgAoEePHhw5coSFCxcik8mQyWTcv3//tXWbW0SyK7zzLMwlfp9/F38vFffDlbQYVpykFPHSEIR/ehphyvCe/kwc7Ed8rAmlyiWxbvdNPu0XiUKR39EVDm7z3F756Lq1q1FZv0V+ryzbZnMbo7KBSwMzLJdT3bp3Y92adYbna1ev5dNun2Zp28ULFlOpciVOnDlB7769GfrFUG4H3850mxnTZjBvwTz+OvIXjx8+plvXbixZvIRVa1fx6/Zf+evAXyxfujzb5zF75my6fNKFk2dPUjKgJL269WLwwMGM/HIkBw8eRJIkRgwdka19mluYA/oW1fDH4bT7qB2Vq1Tm1LlTLFi0gDWr1zB75mwAatauSUJCAlcuXwH0ibGTsxPHjh4z7O/40ePUqVsHgHt379GmZRtat27N6fOnWbN+DadOnkoX46JvF1GuXDlOnDnB6DGjsxy7hYWFoSW43+f9uHjhIr/89gsHj+rrot1H7VCrXz0hUOi9UHbv3s2OHTvYtWsXR44cYdasWQAsXLiQoKAgevfuzZMnT3jy5Ane3t6v3FduE5/oggC4OGj4c1EITnYazt+wostYP7Ri7Ptcl6RJwfd4OzqFzBTTBb8lJAl2bXGkY8NAju23x8RUR/9Rj1m98xbFS+f+kGLPkp8xYPcAaq+qTf019QGIUccwaM8go2VVf6jK4fuHs7TPFRdW8PFvH+d6rO+CuNQ4gqODjZZ1+rgTp06e4kHYAx6EPeD0qdN0+rhTlvbXpGkT+vTrg39xf4aPHI6TsxNHjxzNdJsJkycQVDOIChUr0K1nN44fPc6CxQuoULECtWrXonWb1hw9nPk+MvJJt09o174dJUqWYPjI4YSFhdGpSycaNWlEQEAA/Qf1N0o8Xyc5OZmpk6aiUCioU7cO36/4niJeRZi/cD4BpQJo+VFLxk0Yx+IFi9HpdNjZ2VG+QnmOHdEf49jRYwwaPIgrl6+QmJhI+ONw7t69S+06tQGYN3ceHTt3ZODggRQvUZwaQTWYO38uG9dvRKV6+VqsW78ug4cNpph/MYr5F3tt3JIkceivQxzYf4B69esRcieEP3b9wZLlS6hVuxblypfjpzU/ER4ezs7fd75yPzqdjiVLllC2bFnq1KnDp59+yl9//QXoW7/NzMywtLTE3d0dd3d3FHn4LVn8XisI/1fCJ5Xf54fQsH9Jdh6zZ8g33iwe9VD0Qcxlz9Rx+R2CkEURj02ZNcaH43/ZA1C6fBKTvr1P8VI5S3InH57Mrju70i0P8gpicbPFAGy8tpFnyc/Y2HYj1mb6m0Z/f/o7z9KMl+3pugdbpW2Wjvtp+U/pVCZryVhW7by9k3mn5nG4++HXllVpVKy5soa9IXt5kviEALsAFgctxk3nhpKXfdcjR0S+ch8KuXFiEDr41X1C5TLjdqwbA268NkaAkOchOFo44mjhaFhma2aLtYPxzbsuLi580OwD1q9bjyRJfNDsA5ydnbN0jLJlyxr+L5PJcHNz4+nTp5lvU+7lNq6urlhaWuJXzO/lMjdXLpy/kKXjZ7ZfgDJlyxgtU6lUxMfHY2v76mutZ7eeKBQKUlJScHZxZumKpZQtV5bpX0+neo3qyP7xIRJUM4jExEQeP3qMt483tevU5tjRYwweNpiTJ04y5espbP11K6dOnCImJgYPTw+KlygOwLWr1/j72t9s3rTZsD9JktDpdNwPvU+p0qUAqFylcpbO/8/df+Lm6IZarUan09Gxc0fGThjL4YOHMTEx4b1q7xnKOjk5UaJkCYJvBb9yfz6+PkZ9tD08PIiKispSLG+aSHYF4R9qVkhiw9ehdPiqGEu2uOJXJJURnxSMF6sg5BWtFn5d68KSmUVITlJgaqaj74hwPukXyX+9d6imV00m1ptotMxMYWb4/6OER5R2Lo2PnQ8AOq2OiNQISrmUMiwDcLbMWnIFYGlqiaWp5X8LPIfStGkM2D2AyMRIhlYfSlnXsiQkJ4AGHsc/xtfMFwsTCwCszLI+o2NWy0qShKWppVHClR0ymQyFLH0LXLfu3Qw/n89fOD/L+zM1NU23f51Ol+VtZDLZa/chl8mR/jV4ekY/v5uaGO83o2MBr41v1txZNGjYAFs7W1xcXDIt+2916tZh3Zp1XLt6DVNTUwJKBVCnbh2OHT1GTEyMoVUXIDExkV6f96L/wP7p9vPPmwOtLLN2bdStV5cFixdgZmaGh6fHf74xMCd/27wikl1B+Jd278fyzZBHjFjgzcgF3jjaaunZKjq/wxKEPHE32JxpI325dlHfmle+SiLjvwmjWMnc6bJgqjB9ZaLa8ueWPEl8AsAfd/6gRYkWXHhyQb8sDnaH7KZFiRZMrj+Zqj9U5ZvG31C/aH0AIhMjWXh2IacfnSZNm4afvR+ja42mrGtZVlxYwZH7R9jYbqPhWNtvbWf9tfWEJ4TjYe1B57Kd6RDYAYDwhHBabWrFnEZz+OX6L/wd9Tc+dj6MqT2G8m7lOR9+nilHpgD67hQAvSv3pm+VvvzbxmsbuRZ5jQ1tN1DSqSQAHhYeKOIUyBVyniQ8oZhDMcNxdZIOcxNznqc8R0LCVmmLu7U7Ml4mq9Ep0cSkxKDRaTBTmOFs6Wxo5U5WJxMWF4a3rTdPk5+SqknF28wbM7kZEUkRqDQqdJIOM4UZrlauWJnqE6OwuDDUOjWRSZFEJulbmEs7lyYuNY6IxAgCnAIMx49RxeD3nh/JqcnIZDLeq/eyBRDg5rObeFh7kKpJJSYlhrsxd3G1yrs7951dnImIiDA8j4+PJ+x+2Bs7npubG/7F/dMtDygVwI5tO5AkyZA4nzp5ChsbG4p46W/uetFv97tF3xkS2zp16zD/m/nExsTyxdCXN5hVrFSRWzdvZXisnLCysnpl3BqNhnNnz1EjqAYA0dHR3Ll9x9B6nBNmZmaGm/Hymkh2BSEDw7pG8TDSjAU/u/HZ176Ymkh88uHz/A5LEN6YtFQZKxe5s3qJOxq1HCtrLYPGPKZdt6fI8+jujrWt1zLp8CSszKwYETQCcxNzUtNSGbNrDI7OjoysORJzE/N02yWrk+mzqw+uVq7MbzIfJwsnbj27hU7KuFXpz5A/WX5hOaNqjiLAKYDg6GCmH5uOhYkFLUq2MJRben4pQ6sPxdvWm6XnlzLu4Di2ddpGBbcKjAgawfLzy/mt428Ar2w53nt3L9WLVDckui/IZDLsze2JSo1CpVEZzitJnYRMJsPX3he1Vk14QjgmchNcLPUths+SnxGXGoeHtQdmCjOSNcmGMv+MISopCjcrN0gDc4U5ap0aazNrXK1ckSEjLjWOh3EP8Xf0x1RuipetF6Exodib22Nvbv/Kv5FapyYyMRI3GzfOXT5HUloSkcmRmJsa/12eJT/DRG6Crbkt1qbWhCeEQx5Nplevfj3Wr1tPs+bNsLO3Y9qUaXnaP/SFPn37sHTxUkYMHUHf/n25c/sO07+ezqAhg5D//0Xl4OBA2XJl+eXnX5i3YB4AterUolvXbqjVaqOW3eEjh9OgTgOGDxlOj149sLS05NbNWxz862C2Wtdfp3iJ4rRo2YJB/QexaMkibGxsmDhuIp6enrRo2eL1O3iFokWLcubMGe7fv4+1tTWOjo6GenjTRLIrCBmQyWD+8Eeo0uQs/82F7pOLYmYq0bFxTH6HJgi57uwxG2aP8yHsrj5hqdM4lq9mPMDN89V3XufU8QfHqbOqjtGynhV70qtSLxwsHDBVmKJUKA2tv5YKS0xkJkbL/m1PyB5iVbGsbb0WO3M7ALztXn2n94oLKxhafSgN/RoCUMS2CPdi7rH15lajZPeTcp9Q20efbPSt0peOv3bkUfwjitoXxdrMGplM9truFA/iHlDVs2qG60zl+p9907RphmRXhgxPa09kMhlKhRIXKxeikqJwsXRBQuJZyjN87V52fbBT2JGsTiZGFWOU7LpYuWBlZoVao0YhV6CQK4y+KLhYupCQmkBiWiIO5g6GrgpymRwT+atTA7VWjZ25HQ7mDmAOzjjzOP4x0SnGv37ZmdvpjytT4GLlwnPVc3TkzU/aI0aN4P79+3Ro0wFbO1smTJrwRlt2X8WziCe/7fiN8WPGE/ReEA6ODnTv0T3dCAm169Tm6pWrhlEXHB0dKVW6FFFRUZQMePklqWy5suw5sIcpE6fQpGETJEnCr5gf7Tq0y/XYl/2wjFEjRtGhTQfS0tKoVbsWv+34LV1XhewYOXIk3bt3JzAwkJSUFEJDQylatGjuBZ0JkewKwivIZLBk9APUGhk/7XDm4/F+mJpItGkQm9+hCUKueBZlwrdTvNm7XX9DkpOLmi+/fsD7LWLf2I2ZVTyrMKbWGKNlWb3R7FVuR98mwCnAkOhmJkWdwqP4R3x99GumH3s57qpW0hpufnuhhFMJw/9fJLXPU55T1L5otuL7d//RzChNlEb9ay1MLNBJOtQ6NTpJhyRJPIh7kG7//27xfpEMv6CTdDxNfkpiWiIancawTK3N+heaFT+u4Hb07XSt2BamFjxPec6mXzcB+m4MSoWSPfv3GMrIZXLO/H0GO6Xx3+jUuVOG//sW9SUxNdHwvG69ukbPQT+CwifdPjFaNm7COMZNGGd4bmtry5r1a4zKdP3UeOi2f+/338d+1fH/7XXr69Stw5ETRzItM2feHObMm2O07J/18k9Vqlbh992/Z7gO4MbtrN2MuOLHFZmud3Bw4IeVP7xy/b//DuMmjGPM+DFoU152Uxg6dKjRjGklS5bk1KmMz+tNE8muIGRCLofvx4Wh1shY+4cTncb48duce7SsK0YUyAm5TEZlm5IkqJPEdMH56MUNaEtnFyEpQYFMJtG++1MGjArHxu7N9qmzMLHItNU1J7IzG1+yWj/5wPi64ynrUtZo3b9HMfhnC+eLPrOv6hrxKj52PoTGZjxyglqnTzT/eYNeZl4c29vWO13r679vQPv3uUQmRZKUloSbtRtmCjNkyHgc/xjpDfUtyOkNcYLwJohPG0F4DbkcVk68T5cPnqPWyGk/uhh/nvhvLVHvKguFOceqLmWRbz8xXXA++fuiJd2bl2LueB+SEhQEVkhizR+3GD394RtPdN+UEo4lCI4OJk71+i+hTpZOuFi68Dj+Md523kaPIrZFXrv9C6Zy0ywlvk38m3D28VluRxtPnCBJErGqWJQKpVGrbKom1aglOEWTglwmx1Su794hQ4Zap8ZMYWb0eNEl4lVS1CnYm9tjY2aDUqHERG5Cms541rusJKhmCjPDF4Z/7lu8noWCTCS7gpAFCgWsnRJKu4YxpKnlfDTCn837HfI7LEHIsmdRJkwZ5kuPlqW5dc0Ka1sNX80IY9XOWwRWSH79DnKJWqvmWfIzo0esKvY/7fMD/w9wsnRi5P6RXI64zKP4R/wV+hdXI69mWL5vlb6suryKTX9vIiw2jJDnIfwe/Dvrr67P8jE9bDxIVidz9vFZYlWx6abzfeHjsh9TxrUMw/YO48C9A0QkRnDn+R1iVbGotWo8bDyMyktIhCeGk6pNJTEtkWfJz/T9Y9G31jpZOhGZGElcahxqrRqVRsXzlOfEpWae6JspzEhIS0ClUaHSqHic8DhdGVO5KUnqJDQ6DVop4y8+TpZOxKniiFHFkKZN43nKc+LT4nGycMpKtQlCvhDdGAQhi0xM4OcZ9+g63o8tBxzpPNaPZ7EmDOiQ+YDogpCf1GkyNq105cdvPUhK1N+E1KLDM74Y9xgnF02ex3Py0UmabmhqtMzXztcwqkFOmCpMWdJsCd+e+ZYhe4aglbQUsy/GqFqjMizfulRrzE3MWXt1LQvPLMTC1ILiDsXpUrZLlo9Zwa0C7Uq3Y8xfY4hLjXvl0GNKEyXLmy9n5aWVLDm3hCeJTyhlV4rFQYspYlskXd9aK1MrzBRmhMWGGYYec7F6OXari6ULCpmCZ8nPUGvVyGVyzE3MX3ujnJu1G+EJ4dyPvY+J3AQnS6d0LdMuVi48SXhCyPMQJCRKO5dOtx8bMxvcrN2ITo4mUheJqcIUTxvPfBvHWBCyQiZlp+f8OyI+Ph47Ozvi4uIynTUl1yQnw9GjYGMD5umH1cmMWqdjd3g4H3p6YppX4wMVEjmtO60WvpjrzbJf9eNGTuodzqQ+T96Zmdb+yzWXrFVR+lA7VJpUNrZZj729+xuKsuDRaXWEXwzHs7InckXevFZPHrLlm4nePLinf18JrJjEqK8fULZy3rXk/lf5UW9vnAZM4k3w9vFGaf7y5/8X4+x62Xrl2qHUyWpMLXN+B/27StRb9ukkHdoULTY2Nrk61JtKpSI0NBQ/Pz/M/5UjZTVfEy27gpBNCgUsGf0QN0cNk7/3ZMoPnkTFmLD4y4fkw1CObxVJknig0g9Y/6ZujBEg5JY5i6Z5cfKQ/s53R2c1g8Y+pkWH6DwbM1cQBKGgEMmuIOSATAaT+jzBxUHDoDn6Vt5nsSasm3ofpZlI4oT88SzKhBXfeLLjZ2d0Ohkmpjo69XxK72HhWNsWjGk7BUEQ8ppIdgXhPxjQ4SnO9ho+mVCULQccCX9qxm9z7uLmlPd9IYV3lypFxvoVbqxd6k5ykv7nhYYfxvDF2Md4+6Xmc3RCVnnaeOZ3CIJQKIlkVxD+o46NY3Cy09BuVDFOXLGmarfSbJt7l6qBb0+/SOHtpFHD77848+O3HkRF6MdqLVspkaGTHlHxvaR8jk4QBKFgEL23BCEXvF8tgbNrbhHgq+JRpBl1egew4U/H/A5LKKR0Oti3w4GODcowY7QvURFmeHilMn3pPVbtDBaJ7tsqLU1/w3JePdLSXh9TPggsGciSRUtydZ99P+9L5/adMy3TtHFTRo3IeASP7Dh08BCVy1dGq83euNVh98OwVlpz9UrGQ+ZlZP3a9RRxzfr40AXJjRs38PLyIinpzb9fiZZdQcglJX1TObPmJl3H+/HHcXs+meDH5dsWzBr0WNy4JuQKSdKPsLB0dhGC/9YP9eTgpOazIU9o+8kzzJQFv794rCqWDls6sKb1GvGz/T+lpSE/dx4Sc/eDX5GqQa5M/1H/LPkZZnYOWNduCGZZm8Gt7+d92bBug+G5o6MjlatUZtrMaZQtVzaTLd+8VT+tYsWyFYTeC8XExATfor60bd+WkaNGAvopefNq8KkJYycwesxow4gE69euZ/TI0TyOSj+2sbXSmp83/0zLj1ri5e3F3bC7ODm/2TGLw+6HUSagzMsYrK3x8vaiTt06DPxiIMVLFH+jx38hMDCQGjVqMH/+fCZMmPBGjyWSXUHIRXbWOnbMu8vE5Z7MWOXBN+vcuXrHgvVf38fFQfTjlclklLb0JUmTbJh+VXg9SYJzx234fr4Hl8/aAGBlreXTfhF06R2FlfXbc/PZyksrqedbz5DohieE02pTqwzLrmq1ijLOZTJcV1BNPjyZXXd2Afrpht2t3Wleojk9K/ZMN8WvEY1Gn+iamYEya8lnlphqwDz9ce1MIDL6MZbqNORZTHYBGjdpzPIflgMQGRnJ1ElTad+mPbdCbuVayNm1dvVaRo8czdz5c6ldpzapaan8fe1vbly/YShjZ2eXJ7GcPHGS0HuhfNTmo2xvq1AocHN3ewNRZWznnzsJDAwkOTmZ639fZ+mSpQS9F8TmrZtp0LBBhtukpaVhlo3r5XV69uxJ7969GTNmDCYmby4lFd0YBCGXKRQwfWA4m2fdxdJcy77TdpTvHMj+0zb5HVq+s1SYc776T6zwG2w0RaqQMUmCs8ds6N22JAM6l+TyWRvMlDq69olkx6lrfD4s4q1KdFUaFTuCd/BRQPpEYOmHS9nTdY/Ro7RL+kkN3gY1vWqyp+setnXcxiflPuH7C9+z7uq6rG2sNNOPt/6GHpK5EszNMbWwxkShID41PlvnplQqcXN3w83djfIVyjP8y+E8eviIp09fTq4zYewEKpapiIu9C2UDyjJ18lTUarXRfnbv2k3dmnVxsnXCx9OHzh1e3cVg9crVFHEtwqGDhzJcv3vXbtq2b0v3nt3xL+5PYGAgHTt1ZPLUyYYy/+7GkJSURO9evXFzdMPf159F3y5Kt9/U1FTGjh5LCb8SuDq4Ur92fY4eOZpp/fy6+VcavN8g3XiwWZFRN4Y/dv5BhcAKONk60axJMzas24C10prY2FijbQ/sO0Dl8pVxc3SjdYvWRDyJeO3xnJyccHN3w6+YHy1atWDXn7uoWq0qA/sNNHTBmP71dILeC2L1ytWUKVkGJ1t9q/P+vftp3KAxRVyL4OPhQ/vW7bl3957R/k+ePEnFihUxNzenatWqbN++HZlMxuXLlw1lGjduzPPnzzly5Ei26ys7RLIrCG9Ih0axnFoVTGCxFCKiTWkyqCQjFxQhNU20aAqZe9GS26edcZLbqVcU20/8zbBJj7B3zF5/wILg+IPjmCnMKOdWLt06O3M7nC2djR4mchMkSWJiyES+2PuF4WfoOFUcH278kOXnlxu2Pxp2lG7bulFzZU3eX/s+I/eNNKxL06ax4PQCmm1oRu1Vtem+vTvnw88b1j9JeMKwvcNosKYBtVfVpuOWjhx/cByA+NR4xh8cT6N1jai1shZtfmnD78G/Z3qepgpTnC2d8bDxoH1ge6oVqcbRsKOG/S06s4iIxAhCY0N5GPeQNO3LvrMP4h6QmPayK8Pj+Mc8iHtgeK7SqLgfe99QFzpJx7PkZ4TFhXE/LowniU9I1b4cgSNWHcej+MckpCbwMO4h92PvG9ZZmlgQr8pesvtPiYmJbNq4CX9/f5ycXv70bm1jzfIfl3P+8nnmzJvD6pWr+W7hd4b1e3bvoUvHLjRp2oQTZ07wx54/qPpe1QyP8e033zJx/ER2/LHjla2Nrm6unD1zlgdhDzJcn5FxX43j+LHjbPp1Ezv+2MGxo8e4cumKUZkRQ0dw9sxZVq9bzenzp2nTtg1tWrYh5E7IK/d78sRJKlepnOU4MnM/9D6fdPmEFq1acOrcKXp93ospk6akK5ecnMzCbxfy46of2fvXXh4+fMjYr8Zm+3hyuZwBAwfwIOwBly5eMiy/d/ceO7btYOPmjZw6dwqApOQkBg0ZxNGTR9m1ZxdyuZyunbqi0+m/fMfHx9OyZUvKlSvHxYsX+frrrxk9enS6Y5qZmVGxYkWOHTuW7XizQ3RjEIQ3qHyJFM6tvcnIBV4s+9WVeevdOXjOlo3T71GqqBgSSjCm08GxA3asXuzOtYvWAJgpdbTp+ozuAyJw9VC/Zg8F2+WIyxlOQZsZmUzGEJ8hDAsZxqbrm+hStgszj8/ExdKFzyt/DuiT6C/3f0mvSr2YUn8Kap2aEw9PGPYx58Qc7sXeY0bDGbhYuXDo/iEG7xnMpnab8LHzYfaJ2ah1an5o+QPmJuaExoQapr9ddn4Z92LvsajpIuzN7XkY/5BUTfZeu0oTJXGpcQBMPjIZbZoWh5IOeNp4EquJ5WH8Q4op9bMJmpuYo9KosDazQitpUevUIJOh1qoxVZii0qgwU5gh+/+UjVFJUSCT4W7tjhw58WnxRCRG4GXrhUKm7zOqkTQkqZNxtXY16j5kpjAjRatCQspyt6I/d/+Jm6P+p/akpCTcPdz5dduvyP8xW8noMS+TGt+ivgy5PYRft/zKsJHDAJg7ey7tO7Zn/MTxhnLlyqf/AjRh7AR+3vgzew7sITAw8JUxjR0/lo87fUxgyUBKlChBtRrVaNK0CW3atjGK64XExETWrl7Lj6t/NCTQK35aQUCxAEOZhw8fsm7NOm6F3MLD0wOAIcOHsH/fftavXc/krydnGMvDBw/x8PBItzwuLs5Qb1m18seVlChZgumzpgNQMqAkN67fYO6suUbl1Go1C79bSDH/YgD07d+XWTNmZetYL5QMKAlAWFiY4QtIWloa36/8HheXl9NWt27T2mi7pd8vpWiRoty6dYvq1auzceNGZDIZP/zwA+bm5gQGBvL48WN69+6d7pienp6EhYXlKN6sEsmuILxhluYSS796SNOgeHpNLcqlYEsqdw1k/rCH9Gn77J2a0SpZq6Lqmc9I0iSzsnwlREcGPY0a9u5wZM1Sd+4FWwD6JLf1x8/oMfDtT3JfeJL4BGdL5wzX9drRC7nM+MVwrKe+tcfJzImvan3FlKNTiE6O5sTDE2xou8HQB3blpZU08W9C3yp9DduWdNJ/aEckRrDz9k52ddmFi5X+w/rT8p9y6uEpdt7eycD3BhKRFEHDog0p7qi/Meef0/VGJEYQ4BRAoIs+2crOTXWSJHE2/CynH52mU5lOPIh7wNGwo6xvuR6lQolSoaSIZRHuRN8hITUBe/SJcYJGBWBIbBVyBSmaFEOya2FqYViv0qbia+djSFadLJxIUaeQnJaMjdLmRSC4WDqjkBvfKat/LqHRaTCVZ21q3Lr16rJg8QIAYmNj+WHFD7Rp1YYjx4/g4+sDwK9bfmX5kuXcu3ePpMQkNBoNNrYvu3FdvXKVHr16ZHqcRQsXkZyUzNGTR/Er5pdpWXcPdw4ePcj169c5cewEZ06foe9nfVmzcg3bd21Pl/CG3gslLS2N9957z7DM0dGREiVLGJ7fuHEDrVZLxbIVjbZNTU3F0enVI+2kpKQYTQH9go2NDcdPH0+3vEKZCq/c1+3bt6lStYrRsqpV07eAW1paGhJd0NfH06in6cplxYtfDF58mQLw8fExSnQBQu6EMG3qNM6fPU90dLShRffRo0dUr16d4OBgypcvb9Sdo1q1ahke08LCguTkNztUZ4FKdmfOnMnWrVu5desWFhYW1KxZk9mzZxMQ8PLblkqlYsSIEWzatInU1FQ++OADli5dipvby29MDx48oH///hw6dAhra2u6d+/OzJkz32jnZ0F4nVb14ri66QbdJxXlwFlb+s/yZeNeR1aMfUBpP1V+h5cnJEniZrL+G7yYLhhSkuX8/osTG1a4Ef5Q/wFpZaOlQ/counwehZNL4bqpMVWTitIqfSIAMPP9mfjZvzqpaeTXiCMPjrD6ymq+qvUVPnY+hnXB0cG0LtU6w+1CnoeglbS03dzWaHmaNg07c/1NS53LdGbm8Zmcfnya6kWq07BoQ0o46ROf9oHtGbV/FMHPgqnuVZ36RetTwe3VCQroW5rrrKqDRqdBJ+loWrwpfSr34Wz4WRQyBSUcS0CivqxCpkBpokSt0X+hsTCx4Lk6Gq1Oi0qjwtzEHIVcgUqjwkZpg0qrMsSdpk1DknSExRn/fC9JOn2L8P+ZyE3SJbqAIUHWSVnv921lZYV/cX/D84qVKuLp4smqlauYNGUSZ06f4bPunzFu4jgaNW6Era0tv275lcULFhu2sbCweO1xataqyd4/97L1t62M+HJElmIrU6YMZcqUoU+/PnzW+zOaNGzCsaPHqFe/XpbP74WkpCQUCgXHTh0zjKrwgrW19Su3c3J2IjYmNt1yuVxuVG+5ydTU+IuKDFmOR54IDg4GoGjRooZlllaW6cp1aNsBHx8fFi9bjIeHBzpJR7VK1dL1zc6K58+f4+//ZurmhQKV/R05coSBAwfy3nvvodFoGDt2LE2aNOHGjRtYWVkBMGzYMP744w+2bNmCnZ0dgwYNom3btpw4of/JSqvV0rx5c9zd3Tl58iRPnjyhW7dumJqaMmPGjPw8PUHA00XN3u/usPgXV8Yt9eTYJRsqdCnNVz0iGNszAvO3YOgo4b+LeGzK5tWubNvgTEKc/m3Y0VlNl8+j6NA9qtBO7Wtvbv/KG6LcrN3wtvN+5bYqjYqbz26ikCl4GP/QaF1mNzsmq5NRyBSsa7PO8LP+Cy9aSFuXak0Nrxocf3CcM4/PsOryKoZWH0rnsp2p5V2LXV12ceLhCc48PsOAPwbQIbADQ2sMfeUxq3hWYUytMYa+u5mOwvAvZgoz5Bo5KRoVKo0KB3MHFHIFcao4UrVpIIFSof/CoENCIVPgYZ3+Z3Pj1syMuyjo0F9n2Ynv32QyGXK5HFWK/gv7mVNn8PHxYdRXL8erffjA+O9VplwZDh86zKfdP33lfqtWrUrf/n1p07INJgoThgwfkq24SpUuBUByUvoWQ79ifpiamnLu3Dm8ffTXXExMDCF3QqhdpzYA5cuXR6vV8vTpU2rVrpXl41aoUIFbN3NnZIqSJUuyd89eo2UXLlzIlX1nRKfTsWzJMooWLUqFiq/+QhcdHc2d23f4btl3hro5eeKkUZmAgADWr19PamoqSqX+ej137lyG+/v7779p3759Lp1FxgpUsrtnzx6j56tXr8bV1ZULFy5Qt25d4uLi+Omnn9i4cSMNGzYEYNWqVZQuXZrTp09To0YN9u3bx40bNzhw4ABubm5UrFjR0DF68uTJuTpkhiDkhFwOQ7pE0aZBDANn+7DrmD1f/+jJL/scWT42jAZVE/M7ROENuX3bnqUri/HXH45otfoExLuoii69o2jV6RnmFoX7y06AcwB/3vkzR9suOLsAuUzOwqYLGbJnCLW9a/NeEf3P0MUdi3Mu/BytAtIPYRbgFIBW0hKTEkMlj0qv3L+7tTvtA9vTPrA93539ju3B2+lcVn/3voOFAy1KtqBFyRZUdK/IojOLMk12LUwsMkzc/ez90Epa7jy/Q1kz/bi0WklLqiYVU8X/WztT07DQyFAlxKBRJ2Fu4oBcJoFKRaLmKUqdhDxVf0ObUqNDl5KMzDQ1g4RVC6iRqVKRSalg9q9fj1LTSNOoMZGZpPsSkJnU1FQiIyIBfYK4YtkKEhMTada8GQD+xf15+PAhWzZvoUqVKuz5cw87d+w02seYcWNo0bQFfsX8aN+hPRqthn179jF85HCjcjWCavDbjt9o26otJiYmDBw8MMOYhgwagoenB/Xq16NIkSJEREQwZ+YcnF2cqVYj/U/n1tbWdOvRjfFjxuPo6IiLqwtTJ041+oJQvHhxOnXpRJ9efZgxZwYVKlTg2bNnHD50mLJly9L0w6YZxvJ+4/fZuH5jluszM70+78XihYuZMHYC3Xp04+rVq4Zxjv/ZzSCnoqOjiYyIJDk5mRvXb7DkuyVcOHeBX7f/mq41+58cHBxwdHJk1U+rcHd35+HDh0waP8mozMcff8y4cePo06cPX331FQ8ePOCbb75JF/v9+/d5/PgxjRo1+s/nk5kClez+W1ycvkO/o6O+f8yFCxdQq9VGlVKqVCl8fHw4deoUNWrU4NSpU5QrV86oW8MHH3xA//79uX79OpUqpX+zS01NJTX15Q0H8fH6lge1Wp2jJvls02j0t1/rdPpHNqj/X16dze2E/K87D9dUfvvmDlsPOjB8ng+3H5jTsF8AnZpE8/WARxT1LJizG/2XevvnNjqthE5b+K9blUrGgZ2O/LbOleuXX/78WSUoni6fRVK7Uayh37bu7RtgIVuqe1Tnu7PfEZsci63SFsBwDcQkxxBlFmVU3sbMBlOZKefjzrMzbCc/tfiJUs6l+LTcp0w6MomNrTdiq7Tl84qfM3DPQIpYF6FxscZodVpOPDpB9/Ld8bbxpql/UyYensjQakMp6VSSWFUs58LPUdyxOLW9azP/9HyCvILwsfMhITWB8+HnKWpXFJ1Wx4qLKyjlVIpiDsVI06ZxLOyYYV1GJElCkjK+tr2svajrU5dl55cxv9p8UrWpRMZHYqowxcbSAaytIDEJizQNsapYzBVK5Ap9y6SlSkuKJgobM1te9IGwkMBCpeVZSij25vaYyE3RSlpS1ClYmllgJjNDnpyIQkoFWfov0SnmCiwssjck4v59+/H31f/kbGNjQ8mAkqz7eR1169UFoHnL5gwaPIgRQ0eQlprGB80+YPSY0cyY9vKX1br16rLu53XMnjGb+XPnY2Nr88rW05q1avLr9l9p91E75Ao5/Qf2T1emwfsNWLd6HT9+/yPPo5/j5OxEterV2LVnl9EoEf80fdZ0kpKS6Ni2I9Y21gweMpi4eH3O8aILwLLvlzFn1hzGjhpLeHg4Ts5OvFftvVcmugCdunRiwtgJ3A6+bbjZK6eK+hVl/c/rGTt6LEu/W0q1GtX4cvSXDP1iqKG19L9o2awloO/z6+3jTd16dVm8ZPFru1vI5XLWrFvDyOEjqVa5GiVKlmDu/Lk0a6z/wiMhYW1tzY4dOxg4cCAVK1akXLlyjB8/nk8++QQzMzNDH9+NGzfSuHFjvL29Dcv+TafTIUkSarU6XRKe1RxNJuXVlCLZpNPpaNWqFbGxsRw/ru/UvXHjRnr27GmUmIK+03ODBg2YPXs2ffr0ISwsjL17Xzb9JycnY2Vlxe7du2nWrFm6Y02ePJkpU9IP57Fx40YsLdP3VRGE3JaUZMK6dYHs3VsUSZJhYqKlefNQ2re/jY1N4bg5CUClVdH5mr61bFO5TZgrCu8tauHhVuzZU5RDh3xISND/omRioqNOnUe0bHmXYsVyPuTT2+zL21/SyLERHzh/AEBkaiR9b/bNsOwI3xGUtynPkFtDaOHSgvZu+p86NZKG0bdH465058uiXwJwKvYUmyM381D1EEu5JYHWgXzl95Wh/JaILRyKOcRz9XNsFDYEWAXQ2b0zRS2K8v2j77kYf5FodTSWCksq2VSiV5Fe2JrYsjliM0djjhKVFoVSrqS0VWk+K/IZbsqM76xfGLaQJG0SY4tlPPRToiaRHc938FnZz3Au4oyFmQXOZs6Yyc300/dqNKRqU3mc9hg7hR1OZvpkLU4dR7QmGg8zDywUL/u86iQdz9XPSdImoUWHAjkWcgscTB0wlZvyPE2/ztvCuKVZJ+kIUz/Gw8a3UL8O88OECRNISEhgwYIFub7vb775hlWrVnH9+vVc3/ebtnnzZgYNGkRYWBgWFhakpaVRpUoVfvjhB2rUqPHK7dLS0nj48CERERFoNMb3MSQnJ/Pxxx8TFxeHra3tK/dRYJPd/v378+eff3L8+HG8vPR3xr6pZDejll1vb2+ePXuWaeXlmpQUOHECrK31A39ng1qnY39EBI3d3TF9l27rzwUFse4uBVsyZpEXB8/pb0BxsNXwVc9wBnSIQmlWMF6q/6XekjQpOOzT3yyyt+3vONi7v4kQ802qSsbRfQ7s2OTM2eMvZ2zy8Erlo85R1Ch7nVL1HJArCsb1lh+OPzzO4nOL+bnNz+lGX8iITqsj4koE7hXcC0+9acA00RQfX58M79zPLZIkoUnRYGJhku5n75iUGBLSEoxu9BP0Mqu3rHgxSsWIL0dkOPRZdny//HuqVK2Co6Mjp0+dZuSwkfTp34dJUya9fuM8ptPp0Kq0WNtYI5fJWbt2LcWKFaNIkSJcuXKFwYMHU69ePdat00+wEhISwl9//UXfvhl/2X1BpVJx//59vL29003WER8fj7Oz82uT3QLZjWHQoEHs2rWLo0ePGhJdAHd3d9LS0oiNjcXe3t6wPDIyEnd3d0OZs2fPGu0vMjLSsC4jSqUyw58ETE1N093l+Eao9eMoIpeT03GoTOXyApOwvW0KUt1VK63iwNIQ9p6yZdSiIlwLsWT0Qh+Wbnbjq+4R9GgZXWBuYstJvZkpFPiYu6HSpKJQyAtF8iJJcPOqJTt/cWLPdkfDDWcymUSthnG07/aUoAbxyNARfjEVeSE575yqW7QujxIe8Uz1DHfrrH/ZKVT1JuVOn8vXeXGMjI4l+//YvEJ6mdVbVtjb2/Pl6C9zJZa7IXeZM2sOMc9j8Pb25ouhXzBy1MjXb5gfZC/+0d+0GBUVxeTJk4mIiMDDw4MOHTowffp0wxeAkiVLUrLk67t6yOVyZDJZhjlZVnO0ApXsSpLEF198wbZt2zh8+DB+fsbD0FSpUgVTU1P++usv2rVrB+iHyXjw4AFBQUEABAUFMX36dKKionB1dQVg//792NraZjootSAUFDIZNK0ZT+Pq8az9w4kJyz0Je6Kk/yxfpvzgybCPI+nX7im2b9E0sS9YKsy5GbSBo+Gn3vrpgiPDTdn3uyO7tjhx99bLn5XdPNNo0SGaj7o8w9P7Zb/rwt4fNzs+LvdxfofwzrM3t8/vEIQsmP3NbGZ/Mzu/w8iRUaNGMWrUqNcXzAMFKtkdOHAgGzduZMeOHdjY2BARoZ/b2c7ODgsLC+zs7Pjss88YPnw4jo6O2Nra8sUXXxAUFGTo79GkSRMCAwP59NNPmTNnDhEREYwfP56BAwfmSoduQcgrCgX0bBVNpybP+XG7M9+sc+dhpBmjF3sxc7U7Azs8ZUiXKFwcCtdYrAVZTLQJf+2yZ9/vjlw6Y40k6ZsylOY6GjSLoUXHaN6rlUAmNzILgiAIeaxAJbvLli0DoH79+kbLV61aRY8ePQD49ttvkcvltGvXzmhSiRcUCgW7du2if//+BAUFYWVlRffu3Zk6dWpenYYg5CpLc4nBnZ/Sv/1TNu5xZNZqd27dt2D6Sg/mrnOj/fsx9G37jDqVEsmDX0bfOTHRJhzdb8eBnQ6cPWZrGDIMoFL1BJq2eU6TVjHY2ImmW0EQhIKoQCW7WblXztzcnCVLlrBkyZJXlvH19WX37t25GZog5DtTE+je4jmffvicHUfsmbXanbPXrdi4x4mNe5wo7ZdCnzbP6NY8GscCmnilaFXUOT+ABHUSy8tXLrDTBT+6b8bhvfYc2WvPlXPW6HQvE9zACkk0afWcRi1jcC9SeEbKEARBKKwKVLIrCMLryeXQpkEsbRrEcuGmJSu2OrNxjyM3Qy0YNt+br74rQqu6sXRsFMOHteOwNC8YN7QB6CSJiwm39f+n4PQ5TkuVceWcNaeO2HLioJ1RH1yA0uWTqPdBLE1axeBTLPUVexEEQRAKIpHsCsJbrErpZL4f94Bvhjxi4x5HVmx14fJtS7YccGTLAUcszbW0rBNHx8YxNKsZh0UBSnzzkyRB2F0lp4/YcuqwHRdOWaNKednRVmEiUaVGAvWaxlKvSaxowRUEQXiLiWRXEAoBW2sd/do/o2+7Z1y8Zcnm/Q5sPuDA/XAlv+x35Jf9jlhZaGlQNYEm1eNpUiOekr6p70wfX60W7ty04PIZay6etuHyWWuePzMessbJVU1QvThq1IunZoN4bO0LZlcQQRAEIXtEsisIhYhMpm/trVI6mVlfPOb8DUs2H3Bg834HHkQo2XXMnl3H7AHwcU+lSY14GlZNoEa5JIp6phWK5FeSIOqJKTevWnLjihU3rlhy7aI1SQnGQySYKXVUfC+RGvXjCaoXT/HSKYXi/IW3V5o2DY0ud0dXUavVmKozHovURG6CmcIsV4939MhRPmzyIY8iHxmNh58X1q9dz+iRo3kc9fg/7Wf619P5ccWPPH36lJ83/0zLj1rmUoRCfhHJriAUUjIZvFcmmffKJDNn8GMuB1uw77Qt+87YcvyyNQ8ilPy43YUft7sA4OqoplqZJKqXSaJ62SQqlEzBxUFToBNAVYqM+yHm3LttQehtc+7ctODmVSuin6b/cLey1lLhvUQqVU+kUo0EAssnY1ZAJugQhDRtGufDz5OUlpSr+9WkajBRZvxRb2VmRVXPqtlOeM+cPkPjBo1p3KQxv+34LTfCLDBu3bzFzGkzWb9+PUF1grB3sE9XJux+GGUCyhieOzo6UrFSRb6e8TUVKlbIw2hz5m7IXebOnsvBvw7y7OkzPDw8eK/6ewweOpjKVSrnd3hvhEh2BeEdIJNBpVIpVCqVwugekSSlyDl2yZq9p2w5fsWay8GWRD03NWr5BXC001C6qIpSRVWU9kshwDcVD1cV8VpTJI83H7ckQexzE8IfmvHkkRlPHikJf2hG+AMl90PMCX9oZhjr9p8UCgn/gBRKV0imdPkkylZKonjpFEzEO55QQGl0GpLSkjBTmOVqa6tGp8HELP2Fn6ZNIyktCY1Ok+3jrV29ln4D+rF29VqehD/BwzMP3gzySOi9UAA+/PBDzKwyr5edf+4kMDCQx48f8+XwL2nTqg0Xr17M8xbtjKjV6gxnF7t44SItmrYgsEwgi75bRMmAkiQmJrJr5y7GjB7D3gN7c3Q8rVaLRMFtPBBv/YLwDrKy0NG0ZjxNa8YDoEqVcSnYkjN/W3H2uhVnr1ty77GS53EmnLhizYkr1v/aQ1n6KHV4Oqsp4pqGu5MaO2sttlY6bK20hofSTEIul5D/fzbsVMywwQGNTssfv3mgkFxRpchRpchJTpQT89yEmGhTYqJNiI02Iea5Ceq0zKeIdXBS41dSRbESKRQLUFG6XDIlApMxtyi4b7yC8CpmCrNcnV1QY6LB5BXf8tK0aRkuz0xiYiK/bfmNoyePEhkZyfp16zOcGvfSxUtMHDeRWzdvUb5CeZZ9v4ySAS+nht31+y5mTp/JrZu38PDw4ONPP2bUV6MMsS5esJh1a9dxP/Q+Do4ONPuwGdNmTsPa+uV70fq165k2dRrRz6J5v/H71KxZ87Xx//3334waMYqzp89iaWlJq9atmDV3FtbW1kz/ejozp80E9K21AImpia/cl5OTE27ubri5uzF91nQa1W/E+bPnadSkEdu3bWfalGncu3sPdw93+vXvx+BhgwFYvnQ5P/3wE+cunQNg546ddOnYhQWLF/B5n88BaNG0Be9Vf49JUyZlqb6sldZ8u+hb9u/dz+FDhxkyfAjjJowzileSJPp+3hf/4v7sO7jPMG0vQPkK5RkwaACQcVeUq1euUrNaTa4HX8e3qK+hy8j3P33PxPETCbkTwvyF8xk1YhSPHz/GycnJsO8hQ4Zw7do1Dh48CMDx48cZM2YM58+fx9nZmTZt2jBz5kysrKxe+/fLKZHsCoKAuVIiqHwSQeVf/oSarJJxO8ycW/fNuXlf/29wmDmPo0x5FmuKKlXOvcdK7j3O7syEzwFYkMXSMpmEs5saD680PL1T8fBKw8MrDV9/FcVKqnBwEjPICUJe2frrVkoGlKRkQEk6d+nM6JGjGTlqJLJ/9XeaOmkqM2bPwNnFmSGDhjCg7wAOHD4AwInjJ+jzWR/mzp9LzVo1Cb0XyhcDvgBg7PixAMjlcubOn0vRokUJDQ1l2OBhjB8zngWLFwBw7uw5BvQdwJSvp9CiVQv279vPjK9nZBp7UlISrVu0plr1ahw5eYSnUU8Z1G8QI4aOYMWPKxgybAi+vr70692PW7duYWqRcV/njFhY6IcrTEtL49LFS3T7uBtjJ4ylXft2nDl9hmGDh+Ho5Mgn3T6hdt3afDn8S54+fYqLiwvHjx3HydmJY0eP8Xmfz1Gr1Zw9c5YRX47Icn0BzJg2g6nTpjL7m9kZfsG5euUqN2/cZOXalUaJ7gvZbZFOTk7m23nfsmT5EhwdHfEo4sH0qdPZunUrvXv3BvQtvr/88gvTp08H4O7duzRt2pRp06axcuVKnj59yqBBgxg0aBCrVq3K1vGzQyS7giBkyNJcomJAChUDUoyWq3U6tt+PoIKpD1HRSh5HmRH53ISEJAXxhoecuEQFaWo5Ogl0OtDpZEiARq0lRXqOlasNljYKzC10mFvosLTSYu+gwcFZg4PTi4caR2eN6FsrCAXE2tVr6dSlEwCNP2hMvz79OHb0GHXr1TUqN3HKROrUrQPAiJEjaNe6HSqVCnNzc2ZOm8nwL4fT9dOuAPgV82PC5AmMHzvekLwNHDzQsC/for5MnDKRIYOGGJLdpd8tpXGTxgwbOQyAEiVLcOb0GQ7sO/DK2Ddv2kyqKpUfVv6gb0UsA/MWzKND2w5MnT4VNzc37OzsAHBzc8PUMmvJbmxsLLNm6FuHq7xXhTGjxlC/QX2+GvuVIbZbN2+xYP4CPun2CWXKlMHB0YHjx47Tpm0bjh09xuChg1n6nX422PPnzqNWq6keVB0gS/UF0LFTRz7t/ukr4wwJCQEgICAgS+f1Omq1mm8XfUu58uUA0Ek62rZty88//2xIdv/66y9iY2Np166d/lxmzqRr164MHTpUXzclSrBo0SLq1avHsmXLMDd/M1MNiWRXEIRsMzPT4eeZRklvDZC9G2qSk2I5Gn4Km8pBmFvbv5H4BEHIfbeDb3P+3Hk2bt4IgImJCe3at2Pt6rXpkt2y5coa/u/u4Q7A06inePt4c+3aNU6fOs3cWXMNZbRaLSqViuTkZCwtLTn01yG+mfMNt2/fJiE+AY1GY7Q++FZwulESqlWvlmmyG3wrmLLlyxr9XF6jZg10Oh13bt/Bzc0tW/Xxfr33kcvlJCUl4efnx5r1a3BzcyP4VjDNWzY3KlsjqAZLFi9Bq9WiUCioVbsWx44co0HDBty6eYvefXuzYN4Cgm8Fc/zYcapUrYKlpSVAluoLeO3NZVmZpTY7zMzMjP7OAB06dKBx48aEh4fj6enJhg0baN68uaHV+MqVK1y9epUNGzYYxaXT6QgNDaV06dK5GuMLItkVBCHPpGhVNL00nNjUeBYU4OmCBUFIb+3qtWg0GkoULWFYJkkSSqWSeQvmGVpFAaObo150cdDp9LMmJiUmMW7COFq1bpXuGObm5oTdD6N9m/Z83udzJk2dhIODA6dOnmJA3wGkpaUZkrv8tmb9GkqVLoWjk2O2uwDUqVuHVT+t4uTxk1SoWAFbW1t9Anz0GMePHqd2ndqGsq+rrxdeVy8lSuj/bsHBwZmOGvGii8M/k2O1Ov3EOhYWFum6r1SuXBl/f382bdpE//792bZtG6tXrzasT0xMpG/fvgwePDjd/nx8fDKN/78Qya4gCHlGJ0kci72q/38Bmi5YEITMaTQaNm7YyMzZM2nYuKHRui7tu7Dlly2Gm6tep2Klity5cwf/4v4Zrr906RI6nY6Zc2YaEq+tv201KhNQKoDzZ88bLTt39lymxw0oFcCGdRtISkoytO6ePnkauVxOiZIlMt02I17eXhTzL5bhcU6fPG207PSp0xQvURyFQj/ed526dRg9cjTbtm4zdPeoU7cOhw4e4vSp0wwe+jIZfF19ZVX5CuUpVboUixcspn2H9un67cbGxmJvb4+zszMAERERODg4APr+vlnVpUsXNmzYgJeXF3K5nObNX7ZyV65cmRs3blC8ePH/dC7ZlfltzoIgCIIg5Jk0bRoqjeqNP7I7EsOff/xJbEws3Xp2o0yZMkaPj9p8xNrVa7O8r6/GfsXG9RuZMW0GN27c4NbNW2zZvIUpk6YA4O/vj1qtZtmSZYTeC+XnDT/z0w8/Ge2j/8D+7N+3n4XzFxJyJ4TlS5dn2oUBoFOXTijNlfT5rA/Xr1/nyOEjjBw2ki5du2S7C0NmBg8dzOFDh5k1YxZ3bt9hw7oNrFimvwHuhbLlyuLg4MDmTZtfJrv16rDr912kpqZSo2YNQ9nX1VdWyWQylv+wnJA7ITRp2IS9f+4l9F4of1/7mzmz5tCpvb4vtn9xf7y8vZjx9QxC7oSwZ/ceFi1YlOXjfPzxx1y8eJHp06fTvn17lMqXNzGPHj2akydPMmjQIC5fvsydO3fYsWMHgwYNyta5ZJdIdgVBEAQhn5nITbAysyJNm0ZiWmLuPdQZL0/TpmFlZoWJPGs/8K5dvZYGDRsYdVV44aM2H3HxwkX+vvZ3lvbVqEkjft32KwcPHKRezXo0rNuQJYuWGH7GLle+HLPmzOLbed9SrXI1fvn5F6Z8bZzYVateje+WfcfSJUsJei+IgwcOMuqrUZke19LSku27thMTE0O9mvX4tMun1GtQj3kL5mUp7qyqWKkiazeu5dfNv1KtcjWmTZ3G+Inj+aTbJ4YyMpmMmrVqIpPJCKoVBOgTYFtbWypXqWzUr/h19ZUdVd+rytGTRynmX4xBAwZRpUIVOrbryM0bN5nzzRxA3wVl1dpV3A6+TY2qNZg/bz4Tp0zM8jGKFy9OtWrVuHr1Kl27djVaV758eY4cOcLt27epU6cOlSpVYuLEiXh6emb7XLJDJuV2j+VCID4+Hjs7O+Li4rC1tX3zB0xOhqNHwcYGsnknolqnY3d4OB96emKawVAiwquJusuZ/1JvSZoUrPfoWzH2d9iJg33hGYz+dXRaHeEXw/Gs7IlcIa63rCqU9aYBk3gTvH28UZq/bPV6I9MFJ6tfOarAm5guuLDIrN6EjOkkHdoULTY2NobuGrlBpVIRGhqKn59futEaspqviT67giAIglAA5PbsaQBq04xn0hKEd0kh+ZosCIIgCIIgCOmJll1BEPKUpdwcraTN7zAEQRCEd4RIdgVByDNWJhY8rbeLo+GnsDCxyO9wBEEQhHeA6MYgCIIgCHlMQtwbLghZkRvjKIhkVxAEQRDykgyQMp6VShAEY8nJyQD/6UZL0Y1BEIQ8o9Km0vbKWJ6nxjKrQhUxXbDwbpKD1kTL8+jnmJiYpJtyNTdp0jTo5GK2wuwS9ZZ9EhLaNC0qlSpXhh6TJInk5GSioqKwt7f/T/sUya4gCHlGK+nY+/wsADpxk5rwrpIB1pASm8LDBw/fWLIrSfrkQ2GmeKMJdWEj6i1ndJIOXZoOc3PzdFMR/xf29va4u7v/p32IZFcQBEEQ8poCJEcJrfbNfenTaXVE3YjCNdC18EzIkQdEveVMSloKcQ/iqF6zOtYW1rmyT1NT01xpJRbJriAIgiDkBxlv9lNYBhqNRn+M3JvQqvAT9ZYjklZCo9FgpjRLN9NZfhNfWQRBEARBEIRCSyS7giAIgiAIQqElkl1BEARBEASh0BJ9djPwYgDj+Pj4vDlgcjIkJYFaDUpltjZV63QkJycTHx2NaS7e/fguEHWXM/+l3pK0KaDS/z8mLg6dZPYGIiyYdFp9vUXHRIubXrJB1FvOibrLGVFvOaNKU+k/G+LjQZM3x3yRp71u4gmZlBtTUxQyjx49wtvbO7/DEARBEARBEF7j4cOHeHl5vXK9SHYzoNPpCA8Px8bGpsCPsRcfH4+3tzcPHz7E1tY2v8N5q4i6yxlRbzkj6i1nRL3lnKi7nBH1ljP5UW+SJJGQkICnp2emY/uKbgwZkMvlmX5DKIhsbW3FizKHRN3ljKi3nBH1ljOi3nJO1F3OiHrLmbyuNzs7u9eWEZ1RBEEQBEEQhEJLJLuCIAiCIAhCoSWS3becUqlk0qRJKLM5ioMg6i6nRL3ljKi3nBH1lnOi7nJG1FvOFOR6EzeoCYIgCIIgCIWWaNkVBEEQBEEQCi2R7AqCIAiCIAiFlkh2BUEQBEEQhEJLJLuCIAiCIAhCoSWS3bfEzJkzee+997CxscHV1ZXWrVsTHBxsVKZ+/frIZDKjR79+/fIp4oJh8uTJ6eqkVKlShvUqlYqBAwfi5OSEtbU17dq1IzIyMh8jLhiKFi2art5kMhkDBw4ExLX2T0ePHqVly5Z4enoik8nYvn270XpJkpg4cSIeHh5YWFjQqFEj7ty5Y1Tm+fPndO3aFVtbW+zt7fnss89ITEzMw7PIe5nVm1qtZvTo0ZQrVw4rKys8PT3p1q0b4eHhRvvI6DqdNWtWHp9J3nrd9dajR490ddK0aVOjMuJ6S19vGb3fyWQy5s6dayjzLl5vWck9svI5+uDBA5o3b46lpSWurq58+eWXaDSaPDsPkey+JY4cOcLAgQM5ffo0+/fvR61W06RJE5KSkozK9e7dmydPnhgec+bMyaeIC44yZcoY1cnx48cN64YNG8bOnTvZsmULR44cITw8nLZt2+ZjtAXDuXPnjOps//79AHTo0MFQRlxreklJSVSoUIElS5ZkuH7OnDksWrSI5cuXc+bMGaysrPjggw9QqVSGMl27duX69evs37+fXbt2cfToUfr06ZNXp5AvMqu35ORkLl68yIQJE7h48SJbt24lODiYVq1apSs7depUo+vwiy++yIvw883rrjeApk2bGtXJzz//bLReXG/p/bO+njx5wsqVK5HJZLRr186o3Lt2vWUl93jd56hWq6V58+akpaVx8uRJ1qxZw+rVq5k4cWLenYgkvJWioqIkQDpy5IhhWb169aQhQ4bkX1AF0KRJk6QKFSpkuC42NlYyNTWVtmzZYlh28+ZNCZBOnTqVRxG+HYYMGSL5+/tLOp1OkiRxrb0KIG3bts3wXKfTSe7u7tLcuXMNy2JjYyWlUin9/PPPkiRJ0o0bNyRAOnfunKHMn3/+KclkMunx48d5Fnt++ne9ZeTs2bMSIIWFhRmW+fr6St9+++2bDa4Ay6jeunfvLn300Uev3EZcb1m73j766COpYcOGRsve9etNktLnHln5HN29e7ckl8uliIgIQ5lly5ZJtra2Umpqap7ELVp231JxcXEAODo6Gi3fsGEDzs7OlC1bljFjxpCcnJwf4RUod+7cwdPTk2LFitG1a1cePHgAwIULF1Cr1TRq1MhQtlSpUvj4+HDq1Kn8CrfASUtLY/369fTq1QuZTGZYLq611wsNDSUiIsLoGrOzs6N69eqGa+zUqVPY29tTtWpVQ5lGjRohl8s5c+ZMnsdcUMXFxSGTybC3tzdaPmvWLJycnKhUqRJz587N059GC6rDhw/j6upKQEAA/fv3Jzo62rBOXG+vFxkZyR9//MFnn32Wbt27fr39O/fIyufoqVOnKFeuHG5uboYyH3zwAfHx8Vy/fj1P4jbJk6MIuUqn0zF06FBq1apF2bJlDcs//vhjfH198fT05OrVq4wePZrg4GC2bt2aj9Hmr+rVq7N69WoCAgJ48uQJU6ZMoU6dOvz9999ERERgZmaW7sPTzc2NiIiI/Am4ANq+fTuxsbH06NHDsExca1nz4jr655v8i+cv1kVERODq6mq03sTEBEdHR3Ed/p9KpWL06NF06dIFW1tbw/LBgwdTuXJlHB0dOXnyJGPGjOHJkyfMnz8/H6PNX02bNqVt27b4+flx9+5dxo4dS7NmzTh16hQKhUJcb1mwZs0abGxs0nVpe9evt4xyj6x8jkZERGT4HvhiXV4Qye5baODAgfz9999GfU8Boz5X5cqVw8PDg/fff5+7d+/i7++f12EWCM2aNTP8v3z58lSvXh1fX182b96MhYVFPkb29vjpp59o1qwZnp6ehmXiWhPyilqtpmPHjkiSxLJly4zWDR8+3PD/8uXLY2ZmRt++fZk5c2aBnLI0L3Tu3Nnw/3LlylG+fHn8/f05fPgw77//fj5G9vZYuXIlXbt2xdzc3Gj5u369vSr3eBuIbgxvmUGDBrFr1y4OHTqEl5dXpmWrV68OQEhISF6E9lawt7enZMmShISE4O7uTlpaGrGxsUZlIiMjcXd3z58AC5iwsDAOHDjA559/nmk5ca1l7MV19O87k/95jbm7uxMVFWW0XqPR8Pz583f+OnyR6IaFhbF//36jVt2MVK9eHY1Gw/379/MmwLdAsWLFcHZ2Nrw2xfWWuWPHjhEcHPza9zx4t663V+UeWfkcdXd3z/A98MW6vCCS3beEJEkMGjSIbdu2cfDgQfz8/F67zeXLlwHw8PB4w9G9PRITE7l79y4eHh5UqVIFU1NT/vrrL8P64OBgHjx4QFBQUD5GWXCsWrUKV1dXmjdvnmk5ca1lzM/PD3d3d6NrLD4+njNnzhiusaCgIGJjY7lw4YKhzMGDB9HpdIYvEe+iF4nunTt3OHDgAE5OTq/d5vLly8jl8nQ/07/LHj16RHR0tOG1Ka63zP30009UqVKFChUqvLbsu3C9vS73yMrnaFBQENeuXTP6kvXiy2tgYGCenYjwFujfv79kZ2cnHT58WHry5InhkZycLEmSJIWEhEhTp06Vzp8/L4WGhko7duyQihUrJtWtWzefI89fI0aMkA4fPiyFhoZKJ06ckBo1aiQ5OztLUVFRkiRJUr9+/SQfHx/p4MGD0vnz56WgoCApKCgon6MuGLRareTj4yONHj3aaLm41owlJCRIly5dki5duiQB0vz586VLly4ZRg2YNWuWZG9vL+3YsUO6evWq9NFHH0l+fn5SSkqKYR9NmzaVKlWqJJ05c0Y6fvy4VKJECalLly75dUp5IrN6S0tLk1q1aiV5eXlJly9fNnrPe3H39smTJ6Vvv/1Wunz5snT37l1p/fr1kouLi9StW7d8PrM3K7N6S0hIkEaOHCmdOnVKCg0NlQ4cOCBVrlxZKlGihKRSqQz7ENdb+tepJElSXFycZGlpKS1btizd9u/q9fa63EOSXv85qtFopLJly0pNmjSRLl++LO3Zs0dycXGRxowZk2fnIZLdtwSQ4WPVqlWSJEnSgwcPpLp160qOjo6SUqmUihcvLn355ZdSXFxc/gaezzp16iR5eHhIZmZmUpEiRaROnTpJISEhhvUpKSnSgAEDJAcHB8nS0lJq06aN9OTJk3yMuODYu3evBEjBwcFGy8W1ZuzQoUMZvja7d+8uSZJ++LEJEyZIbm5uklKplN5///10dRodHS116dJFsra2lmxtbaWePXtKCQkJ+XA2eSezegsNDX3le96hQ4ckSZKkCxcuSNWrV5fs7Owkc3NzqXTp0tKMGTOMkrrCKLN6S05Olpo0aSK5uLhIpqamkq+vr9S7d2+jIZ8kSVxvGb1OJUmSVqxYIVlYWEixsbHptn9Xr7fX5R6SlLXP0fv370vNmjWTLCwsJGdnZ2nEiBGSWq3Os/OQ/f9kBEEQBEEQBKHQEX12BUEQBEEQhEJLJLuCIAiCIAhCoSWSXUEQBEEQBKHQEsmuIAiCIAiCUGiJZFcQBEEQBEEotESyKwiCIAiCIBRaItkVBEEQBEEQCi2R7AqCIAiCIAiFlkh2BUEQ/k8mkzF58uT8DuONKlq0KD169MhS2YcPH2Jubs6JEycMy+rXr0/ZsmXfUHRvRnR0NFZWVuzevTu/QxEEIR+IZFcQhHfC0qVLkclkVK9ePb9DeWtMnTqV6tWrU6tWrfwOhRs3bjB58mTu37+f7W2dnJz4/PPPmTBhQu4HJghCgSeSXUEQ3gkbNmygaNGinD17lpCQkAzLpKSkMH78+DyOrGB6+vQpa9asoV+/fvkdCqBPdqdMmZKjZBegX79+XLx4kYMHD+ZuYIIgFHgi2RUEodALDQ3l5MmTzJ8/HxcXFzZs2JBhOXNzc0xMTDLdV1JS0psIscBZv349JiYmtGzZMr9DyRWlS5embNmyrF69Or9DEQQhj4lkVxCEQm/Dhg04ODjQvHlz2rdv/8pk9999didPnoxMJuPGjRt8/PHHODg4ULt2bQAiIiLo2bMnXl5eKJVKPDw8+Oijj4xaHosWLUqLFi3Yt28fFStWxNzcnMDAQLZu3Zru2LGxsQwdOhRvb2+USiXFixdn9uzZ6HQ6o3I6nY4FCxZQpkwZzM3NcXNzo2/fvsTExBiVkySJadOm4eXlhaWlJQ0aNOD69etZrrPt27dTvXp1rK2tX1t23759WFpa0qVLFzQaDaCvy0GDBrF9+3bKli2LUqmkTJky7NmzJ932ly5dolmzZtja2mJtbc3777/P6dOnDetXr15Nhw4dAGjQoAEymQyZTMbhw4cBOH/+PB988AHOzs5YWFjg5+dHr1690h2ncePG7Ny5E0mSslwPgiC8/USyKwhCobdhwwbatm2LmZkZXbp04c6dO5w7dy7L23fo0IHk5GRmzJhB7969AWjXrh3btm2jZ8+eLF26lMGDB5OQkMCDBw+Mtr1z5w6dOnWiWbNmzJw5ExMTEzp06MD+/fsNZZKTk6lXrx7r16+nW7duLFq0iFq1ajFmzBiGDx9utL++ffvy5ZdfUqtWLRYuXEjPnj3ZsGEDH3zwAWq12lBu4sSJTJgwgQoVKjB37lyKFStGkyZNstQyrVarOXfuHJUrV35t2V27dtGqVSs6dOhgaA1+4fjx4wwYMIDOnTszZ84cVCoV7dq1Izo62lDm+vXr1KlThytXrjBq1CgmTJhAaGgo9evX58yZMwDUrVuXwYMHAzB27FjWrVvHunXrKF26NFFRUTRp0oT79+/z1VdfsXjxYrp27WqULL9QpUoVYmNjs5X0C4JQCEiCIAiF2Pnz5yVA2r9/vyRJkqTT6SQvLy9pyJAh6coC0qRJkwzPJ02aJAFSly5djMrFxMRIgDR37txMj+3r6ysB0m+//WZYFhcXJ3l4eEiVKlUyLPv6668lKysr6fbt20bbf/XVV5JCoZAePHggSZIkHTt2TAKkDRs2GJXbs2eP0fKoqCjJzMxMat68uaTT6Qzlxo4dKwFS9+7dM407JCREAqTFixenW1evXj2pTJkykiRJ0m+//SaZmppKvXv3lrRarVE5QDIzM5NCQkIMy65cuZJuv61bt5bMzMyku3fvGpaFh4dLNjY2Ut26dQ3LtmzZIgHSoUOHjI6zbds2CZDOnTuX6TlJkiSdPHlSAqRffvnltWUFQSg8RMuuIAiF2oYNG3Bzc6NBgwaA/uf1Tp06sWnTJrRabZb28e+btCwsLDAzM+Pw4cPpug/8m6enJ23atDE8t7W1pVu3bly6dImIiAgAtmzZQp06dXBwcODZs2eGR6NGjdBqtRw9etRQzs7OjsaNGxuVq1KlCtbW1hw6dAiAAwcOkJaWxhdffIFMJjMce+jQoVk63xctrw4ODq8s8/PPP9OpUyf69u3LihUrkMvTf5w0atQIf39/w/Py5ctja2vLvXv3ANBqtezbt4/WrVtTrFgxQzkPDw8+/vhjjh8/Tnx8fKax2tvbA/oW5n+2bGfkxfk8e/Ys03KCIBQuItkVBKHQ0mq1bNq0iQYNGhAaGkpISAghISFUr16dyMhI/vrrryztx8/Pz+i5Uqlk9uzZ/Pnnn7i5uVG3bl3mzJljSF7/qXjx4kYJJ0DJkiUBDP1779y5w549e3BxcTF6NGrUCICoqChDubi4OFxdXdOVTUxMNJQLCwsDoESJEkbHdXFxyTSB/TfpFX1bQ0ND+eSTT2jXrh2LFy9Od34v+Pj4pFvm4OBg+ILw9OlTkpOTCQgISFeudOnS6HQ6Hj58mGmM9erVo127dkyZMgVnZ2c++ugjVq1aRWpq6ivP51XxCoJQOGV+27EgCMJb7ODBgzx58oRNmzaxadOmdOs3bNhAkyZNXrsfCwuLdMuGDh1Ky5Yt2b59O3v37mXChAnMnDmTgwcPUqlSpWzFqdPpaNy4MaNGjcpw/YvkWKfT4erq+sob7FxcXLJ13FdxcnICeGWrtYeHBx4eHuzevZvz589TtWrVDMspFIoMl78qic4JmUzGr7/+yunTp9m5cyd79+6lV69ezJs3j9OnTxvdYPfifJydnXPt+IIgFHwi2RUEodDasGEDrq6uLFmyJN26rVu3sm3bNpYvX55hMpsV/v7+jBgxghEjRnDnzh0qVqzIvHnzWL9+vaFMSEgIkiQZtSbevn0b0I/W8GI/iYmJhpbczI534MABatWqlWnMvr6+gL4l+J/dA54+ffrabhegb5G1sLAgNDQ0w/Xm5ubs2rWLhg0b0rRpU44cOUKZMmVeu99/c3FxwdLSkuDg4HTrbt26hVwux9vbG3h9a2yNGjWoUaMG06dPZ+PGjXTt2pVNmzbx+eefG8q8OJ/SpUtnO1ZBEN5eohuDIAiFUkpKClu3bqVFixa0b98+3WPQoEEkJCTw+++/Z3vfycnJqFQqo2X+/v7Y2Nik+/k8PDycbdu2GZ7Hx8ezdu1aKlasiLu7OwAdO3bk1KlT7N27N92xYmNjDcN5dezYEa1Wy9dff52unEajITY2FtD3lTU1NWXx4sVGragLFizI0vmZmppStWpVzp8//8oydnZ27N27F1dXVxo3bszdu3eztO9/UigUNGnShB07dhgN2RYZGcnGjRupXbs2tra2AFhZWQEYzvGFmJiYdC3FFStWBEj3t7hw4QJ2dnY5SswFQXh7iZZdQRAKpd9//52EhARatWqV4foaNWoYJpjo1KlTtvZ9+/Zt3n//fTp27EhgYCAmJiZs27aNyMhIOnfubFS2ZMmSfPbZZ5w7dw43NzdWrlxJZGQkq1atMpT58ssv+f3332nRogU9evSgSpUqJCUlce3aNX799Vfu37+Ps7Mz9erVo2/fvsycOZPLly/TpEkTTE1NuXPnDlu2bGHhwoW0b98eFxcXRo4cycyZM2nRogUffvghly5d4s8//8zyT/gfffQR48aNIz4+3pBw/puzszP79++ndu3aNGrUiOPHj1OkSJFs1eW0adMM+xgwYAAmJiasWLGC1NRU5syZYyhXsWJFFAoFs2fPJi4uDqVSScOGDdm4cSNLly6lTZs2+Pv7k5CQwA8//ICtrS0ffvih0bH2799Py5YtRZ9dQXjX5OdQEIIgCG9Ky5YtJXNzcykpKemVZXr06CGZmppKz549kyTp1UOPPX361Gi7Z8+eSQMHDpRKlSolWVlZSXZ2dlL16tWlzZs3G5Xz9fWVmjdvLu3du1cqX768pFQqpVKlSklbtmxJF0tCQoI0ZswYqXjx4pKZmZnk7Ows1axZU/rmm2+ktLQ0o7Lff/+9VKVKFcnCwkKysbGRypUrJ40aNUoKDw83lNFqtdKUKVMkDw8PycLCQqpfv770999/S76+vq8dekySJCkyMlIyMTGR1q1bZ7T8n0OPvRASEiJ5eHhIpUuXNtQVIA0cODDdfjM6/sWLF6UPPvhAsra2liwtLaUGDRpIJ0+eTLftDz/8IBUrVkxSKBSGYcguXrwodenSRfLx8ZGUSqXk6uoqtWjRQjp//rzRtjdv3pQA6cCBA689d0EQCheZJImpZARBEN6EokWLUrZsWXbt2pXfoeTIZ599xu3btzl27Fh+h/KfDR06lKNHj3LhwgXRsisI7xjRZ1cQBEHI0KRJkzh37hwnTpzI71D+k+joaH788UemTZsmEl1BeAeJPruCIAhChnx8fNLdiPc2cnJyIjExMb/DEAQhn4iWXUEQBEEQBKHQEn12BUEQBEEQhEJLtOwKgiAIgiAIhZZIdgVBEARBEIRCSyS7giAIgiAIQqElkl1BEARBEASh0BLJriAIgiAIglBoiWRXEARBEARBKLREsisIgiAIgiAUWiLZFQRBEARBEAqt/wHbwwFo2bT7MQAAAABJRU5ErkJggg==\n" + }, + "metadata": {} + } + ], + "source": [ + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "\n", + "# Simulated power curve data\n", + "airspeed = np.linspace(20, 200, 100) # Airspeed in knots\n", + "power_required = 10000 / airspeed + 0.01 * airspeed**2 # Simplified model: induced + parasitic drag\n", + "\n", + "# Create the plot\n", + "plt.figure(figsize=(8, 6))\n", + "plt.plot(airspeed, power_required, label=\"Power Required\", color=\"blue\")\n", + "plt.axvline(x=80, color=\"green\", linestyle=\"--\", label=\"Minimum Power Point\")\n", + "plt.axvspan(20, 80, alpha=0.2, color=\"red\", label=\"Back Side (High Drag)\")\n", + "plt.axvspan(80, 200, alpha=0.2, color=\"green\", label=\"Ahead of Power Curve\")\n", + "\n", + "# Annotations\n", + "plt.text(50, 400, \"High Induced Drag\\n(Risk of Stall)\", fontsize=10, color=\"red\")\n", + "plt.text(120, 200, \"Efficient Operation\\n(Excess Power)\", fontsize=10, color=\"green\")\n", + "\n", + "# Plot settings\n", + "plt.title(\"Power Curve: Staying Ahead\", fontsize=14)\n", + "plt.xlabel(\"Airspeed (knots)\", fontsize=12)\n", + "plt.ylabel(\"Power Required (arbitrary units)\", fontsize=12)\n", + "plt.grid(True)\n", + "plt.legend()\n", + "plt.show()" + ] + } + ] +} \ No newline at end of file From b471ff195e12c81a53e022350be841978070ef48 Mon Sep 17 00:00:00 2001 From: Thomas Arp <357770+welcor@users.noreply.github.com> Date: Tue, 6 May 2025 23:15:06 +0200 Subject: [PATCH 10/19] avoid freeing obj_proto[].name. (#149) fixes #148 --- src/act.item.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/act.item.c b/src/act.item.c index 793226a..3a34604 100644 --- a/src/act.item.c +++ b/src/act.item.c @@ -785,6 +785,9 @@ void name_from_drinkcon(struct obj_data *obj) if (!obj || (GET_OBJ_TYPE(obj) != ITEM_DRINKCON && GET_OBJ_TYPE(obj) != ITEM_FOUNTAIN)) return; + if (obj->name == obj_proto[GET_OBJ_RNUM(obj)].name) + obj->name = strdup(obj_proto[GET_OBJ_RNUM(obj)].name); + liqname = drinknames[GET_OBJ_VAL(obj, 2)]; remove_from_string(obj->name, liqname); From a4af23538f42dc5180e234d7c561decf5ce3510a Mon Sep 17 00:00:00 2001 From: Marthammor Date: Sat, 28 Jun 2025 17:58:14 -0400 Subject: [PATCH 11/19] Add MTTS support (#150) MTTS support - thanks to marthammer for the patch --- src/protocol.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/protocol.c b/src/protocol.c index 587e6ac..78c8600 100644 --- a/src/protocol.c +++ b/src/protocol.c @@ -1768,7 +1768,26 @@ static void PerformSubnegotiation( descriptor_t *apDescriptor, char aCmd, char * Write(apDescriptor, RequestTTYPE); } - if ( PrefixString("Mudlet", pClientName) ) + if ( PrefixString("MTTS ", pClientName) ) + { + pProtocol->pVariables[eMSDP_CLIENT_VERSION]->ValueInt = atoi(pClientName+5); + + if (pProtocol->pVariables[eMSDP_CLIENT_VERSION]->ValueInt & 1) + { + pProtocol->pVariables[eMSDP_ANSI_COLORS]->ValueInt = 1; + } + if (pProtocol->pVariables[eMSDP_CLIENT_VERSION]->ValueInt & 4) + { + pProtocol->pVariables[eMSDP_UTF_8]->ValueInt = 1; + } + if (pProtocol->pVariables[eMSDP_CLIENT_VERSION]->ValueInt & 8) + { + pProtocol->pVariables[eMSDP_XTERM_256_COLORS]->ValueInt = 1; + pProtocol->b256Support = eYES; + } + + } + else if ( PrefixString("Mudlet", pClientName) ) { /* Mudlet beta 15 and later supports 256 colours, but we can't * identify it from the mud - everything prior to 1.1 claims From 558e71eed8f2d6622d1ab04388b5f82f22edfa21 Mon Sep 17 00:00:00 2001 From: Thomas Arp <357770+welcor@users.noreply.github.com> Date: Wed, 2 Jul 2025 21:25:34 +0200 Subject: [PATCH 12/19] ignore .idea from clion IDE --- .gitignore | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index e671ea7..e3e03a9 100644 --- a/.gitignore +++ b/.gitignore @@ -71,6 +71,8 @@ lib/plrobjs/index /lib/etc/last # or mail lib/etc/plrmail +#or time +lib/etc/time # test object files, etc src/test/depend @@ -82,7 +84,7 @@ src/test/testfile .vscode .project .settings - +.idea .cproject # macOS generated files From ba7dc7bf6f2bb6a7d9c1bee7b16179ad2231fec1 Mon Sep 17 00:00:00 2001 From: Thomas Arp <357770+welcor@users.noreply.github.com> Date: Wed, 2 Jul 2025 21:26:19 +0200 Subject: [PATCH 13/19] convert docs files to utf-8 --- doc/README | 2 +- doc/act.txt | 30 ++++++++--------- doc/color.txt | 48 +++++++++++++-------------- doc/debugging.txt | 84 +++++++++++++++++++++++------------------------ doc/files.txt | 36 ++++++++++---------- doc/porting.txt | 46 +++++++++++++------------- doc/releases.txt | 2 +- doc/socials.txt | 6 ++-- doc/utils.txt | 8 ++--- 9 files changed, 131 insertions(+), 131 deletions(-) diff --git a/doc/README b/doc/README index d9a9f15..50ffb3f 100644 --- a/doc/README +++ b/doc/README @@ -1,7 +1,7 @@ Updated: Apr 2007 tbaMUD README ------------- -All requests for help or bugs should be reported to: builderacademy.net 9091. +All requests for help or bugs should be reported to: tbamud.com 9091. Information about CircleMUD can be found at the CircleMUD Home Page and FTP: http://www.circlemud.org diff --git a/doc/act.txt b/doc/act.txt index 3bc99fa..991d8c4 100644 --- a/doc/act.txt +++ b/doc/act.txt @@ -24,7 +24,7 @@ Contents 1.1 Overview The act() function is used to process and send strings of text to characters in a room. It can be used to send the same basic string to a number of -characters filling in certain segments designated by control characters +characters filling in certain segments – designated by control characters – in different ways, dependant on what each character can see and who each character is. Once the text string passed to the function has been parsed, it is capitalized and a newline is added to its tail. @@ -38,17 +38,17 @@ struct obj_data *obj, const void *vict_obj, int type) These pieces are used as follows: str: This is the basic string, a null terminated character array, including -control characters (see section 1.4 on Control Characters), to be sent to +control characters (see section 1.4 on ‘Control Characters’), to be sent to characters designated by the targets. hide_invisible: A TRUE or FALSE value indicating whether or not to hide the -entire output from any characters that cannot see the performing character. +entire output from any characters that cannot see the “performing character”. -ch: The performing character. This is the character that the output string +ch: The “performing character”. This is the character that the output string is associated with. The character is used to determine the room for the output of the action in question. -obj: An object (an actual item obj_data) used in the course of the action. +obj: An object (an actual item – obj_data) used in the course of the action. vict_obj: This can be either a character involved in the action, another object, or even a predefined string of text. @@ -73,7 +73,7 @@ The next parameter vict_objcan be a number of things ranging from a game object null terminated character array (char *). Do note, however, that obj and vict_obj are both ignored if there is no control -character reference (see section 1.4 Control Characters) to them and the type +character reference (see section 1.4 ‘Control Characters’) to them and the type is set to TO_ROOM or TO_CHAR. In these cases, NULL should be supplied as the input to the function. @@ -96,7 +96,7 @@ TO_CHAR: Finally, this option sends the output to the ch. TO_SLEEP: This is a special option that must be combined with one of the above options. It tells act() that the output is to be sent even to characters that -are sleeping. It is combined with a bitwise or. i.e. TO_VICT | TO_SLEEP. +are sleeping. It is combined with a bitwise ‘or’. i.e. TO_VICT | TO_SLEEP. When the string has been parsed, it is capitalized and a newline is added. @@ -105,20 +105,20 @@ In a manner similar to the printf() family of functions, act() uses control characters. However, instead of using the % symbol, act() uses the $ character to indicate control characters. -$n Write name, short description, or someone, for ch, depending on whether +$n Write name, short description, or “someone”, for ch, depending on whether ch is a PC, a NPC, or an invisible PC/NPC. $N Like $n, except insert the text for vict_obj.* -$m him, her, or it, depending on the gender of ch. +$m “him,” “her,” or “it,” depending on the gender of ch. $M Like $m, for vict_obj.* -$s his, her,or it, depending on the gender of ch. +$s “his,” “her,”or “it,” depending on the gender of ch. $S Like $s, for vict_obj.* -$e he, she, it, depending on the gender of ch. +$e “he,” “she,” “it,” depending on the gender of ch. $E Like $e, for vict_obj.* -$o Name or something for obj, depending on visibility. +$o Name or “something” for obj, depending on visibility. $O Like $o, for vict_obj.* -$p Short description or something for obj. +$p Short description or “something” for obj. $P Like $p for vict_obj.* -$a an ora, depending on the first character of objs name. +$a “an” or“a”, depending on the first character of obj’s name. $A Like $a, for vict_obj.* $T Prints the string pointed to by vict_obj.* $F Processes the string pointed to by vict_obj with the fname() function prior @@ -129,7 +129,7 @@ no action is taken. $U Processes the buffer and uppercases the first letter of the following word (the word immediately after to the control code). If there is no following word, no action is taken. -$$ Print the character $. +$$ Print the character ‘$’. NOTE*: vict_obj must be a pointer of type struct char_data *. diff --git a/doc/color.txt b/doc/color.txt index 377cb85..226231a 100644 --- a/doc/color.txt +++ b/doc/color.txt @@ -9,8 +9,8 @@ to players in color in the tbaMUD game engine. Its intended audience is for Coders of tbaMUD. tbaMUD allows you to create colorful messages by using ANSI control sequences. -Each player may select what level of color he/she desires from the four -levels off, brief, normal, and complete. Each player can select his/her +Each player may select what “level” of color he/she desires from the four +levels “off,” “brief,” “normal,” and “complete.” Each player can select his/her color level by using the TOGGLE COLOR command from within the MUD; you as the programmer must decide which messages will be colored for each of the color levels. @@ -21,17 +21,17 @@ All files in which you wish to use color must have the line: This should be put in after all other includes in the beginning of the file. -There are 8 colors available normal, red, green, yellow, blue, magenta, +There are 8 colors available – “normal,” red, green, yellow, blue, magenta, cyan and white. They are accessible by sending control sequences as part of another string, for example: -sprintf(buf, "If youre %shappy%s and you know it clap " +sprintf(buf, "If you’re %shappy%s and you know it clap " "%d of your hands.\n\r", x, y, num_of_hands); send_to_char(ch, buf); -In this example, x and y are the on and off sequences for the color you -want. There are 2 main series of color macros available for you to use (dont -actually use x and y, of course!): the K series and the CC series. The CC +In this example, x and y are the “on” and “off” sequences for the color you +want. There are 2 main series of color macros available for you to use (don’t +actually use “x” and “y,” of course!): the K series and the CC series. The CC (Conditional Color) series is recommended for most general use. The name of the actual sequence starts with the name of its series, plus a @@ -51,21 +51,21 @@ CCBLU() (arguments defined below). The K series requires no arguments, and is simply a macro to the ANSI color code. Therefore, if you use a K-series color code, the color will ALWAYS be -sent, even if the person youre sending it to has color off. This can very bad. +sent, even if the person you’re sending it to has color off. This can very bad. Some people who do not have ANSI-compatible terminals will see garbage characters instead of colors. If the terminal correctly ignores ANSI color codes, then nothing will show up on their screen at all. The K series is mainly -used to print colors to a string if the players color level will later be +used to print colors to a string if the player’s color level will later be tested manually (for an example, see do_gen_com in act.comm.c). The recommended series is the CC series (i.e. CCNRM(), CCRED(), etc.) The CC -series macros require two arguments a pointer to the character to whom the +series macros require two arguments – a pointer to the character to whom the string is being sent, and the minimum color level the player must be set to in order to see the color. Color sent as 'brief' (formerly known as sparse it was changed for consistency with the syslog command) (C_SPR) will be seen by people -with color set to sparse, normal, or complete; color sent as normal (C_NRM) +with color set to sparse, normal, or complete; color sent as ‘normal’ (C_NRM) will be seen only by people with color set to normal or complete; color sent as -complete (C_CMP) will be seen only by people with color set to complete. +‘complete’ (C_CMP) will be seen only by people with color set to complete. To illustrate the above, an example is in order: @@ -76,29 +76,29 @@ ACMD(do_showcolor) { char buf[300]; -sprintf(buf, "Dont you just love %scolor%s, %scolor%s, " "%sCOLOR%s!\n\r", +sprintf(buf, "Don’t you just love %scolor%s, %scolor%s, " "%sCOLOR%s!\n\r", CCBLU(ch, C_CMP), CCNRM(ch, C_CMP), CCYEL(ch, C_NRM), CCNRM(ch, C_NRM), CCRED(ch, C_SPR), CCNRM(ch, C_SPR)); send_to_char(ch, buf); } What does this do? For people with color set to Complete, it prints: - Dont you just love color, color, COLOR! (blue) (yellow) (red) + Don’t you just love color, color, COLOR! (blue) (yellow) (red) People who have color set to Normal will see: - Dont you just love color, color, COLOR! (yellow) (red) + Don’t you just love color, color, COLOR! (yellow) (red) People who have color set to Sparse will see: - Dont you just love color, color, COLOR! (red) + Don’t you just love color, color, COLOR! (red) People who have color set to Off will see: - Dont you just love color, color, COLOR! (no color, as youd expect) + Don’t you just love color, color, COLOR! (no color, as you’d expect) There are several common pitfalls with using the CC series of color macros: Do not confuse CCNRM with C_NRM. CCNRM() is a macro to turn the color back to -normal; C_NRMis a color level of normal. Always make sure that every pair of -on and off codes are at the same color level. For example: +normal; C_NRMis a color level of “normal.” Always make sure that every pair of +“on” and “off” codes are at the same color level. For example: WRONG: sprintf(buf, "%sCOLOR%s\n\r", CCBLU(ch, C_NRM), CCNRM(ch, C_CMP)); @@ -110,14 +110,14 @@ WRONG: sprintf(buf, "%sCOLOR%s\n\r", CCBLU(ch, C_CMP), CCNRM(ch, C_NRM)); The above statement is also wrong, although not as bad. In this case, someone with color set to Normal will (correctly) not get the CCBLU code, but will then -unnecessarily get the CCNRM code. Never send a color code if you dont have to. +unnecessarily get the CCNRM code. Never send a color code if you don’t have to. The codes are several bytes long, and cause a noticeable pause at 2400 baud. -This should go without saying, but dont ever send color at the C_OFF level. +This should go without saying, but don’t ever send color at the C_OFF level. Special precautions must be taken when sending a colored string to a large -group of people. You cant use the color level of ch (the person sending the -string) each person receiving the string must get a string appropriately +group of people. You can’t use the color level of “ch” (the person sending the +string) – each person receiving the string must get a string appropriately colored for his/her level. In such cases, it is usually best to set up two -strings (one colored and one not), and test each players color level +strings (one colored and one not), and test each player’s color level individually (see do_gen_comin act.comm.c for an example). diff --git a/doc/debugging.txt b/doc/debugging.txt index 37a444a..c4ca478 100644 --- a/doc/debugging.txt +++ b/doc/debugging.txt @@ -4,14 +4,14 @@ Builder Academy at telnet://tbamud.com:9091 or email rumble@tbamud.com -- Rumble The Art of Debugging Originally by Michael Chastain and Sammy -The following documentation is excerpted from Merc 2.0s hacker.txt file. It +The following documentation is excerpted from Merc 2.0’s hacker.txt file. It was written by Furey of MERC Industries and is included here with his permission. We have packaged it with tbaMUD (changed in a couple of places, such as specific filenames) because it offers good advice and insight into the art and science of software engineering. More information about tbaMUD, can be found at the tbaMUD home page http://tbamud.com. -1 Im running a Mud so I can learn C programming! +1 “I’m running a Mud so I can learn C programming!” Yeah, right. The purpose of this document is to record some of our knowledge, experience and philosophy. No matter what your level, we hope that this @@ -31,11 +31,11 @@ Play with it some more. Read documentation again. Get the idea? -The idea is that your mind can accept only so much new data in a single -session. Playing with something doesnt introduce very much new data, but it -does transform data in your head from the new category to the familiar -category. Reading documentation doesnt make anything familiar, but it -refills your new hopper. +The idea is that your mind can accept only so much “new data” in a single +session. Playing with something doesn’t introduce very much new data, but it +does transform data in your head from the “new” category to the “familiar” +category. Reading documentation doesn’t make anything “familiar,” but it +refills your “new” hopper. Most people, if they even read documentation in the first place, never return to it. They come to a certain minimum level of proficiency and then never @@ -47,17 +47,17 @@ through the two-step learning cycle many times to master it. man gives you online manual pages. -grep stands for global regular expression print; searches for strings in text +grep stands for “global regular expression print;” searches for strings in text files. vi, emacs, jove use whatever editor floats your boat, but learn the hell out of it; you should know every command in your editor. -ctags mags tags for your editor which allows you to go to functions by name +ctags mags “tags” for your editor which allows you to go to functions by name in any source file. >, >>, <, | input and output redirection at the command line; get someone to -show you, or dig it out of man csh +show you, or dig it out of “man csh” These are the basic day-in day-out development tools. Developing without knowing how to use all of these well is like driving a car without knowing @@ -70,21 +70,21 @@ the hypothesis, run the program and provide it experimental input, observe its behavior, and confirm or refute the hypothesis. A good hypothesis is one which makes surprising predictions which then come -true; predictions that other hypotheses dont make. +true; predictions that other hypotheses don’t make. The first step in debugging is not to write bugs in the first place. This sounds obvious, but sadly, is all too often ignored. If you build a program, and you get any errors or any warnings, you should fix them before continuing. C was designed so that many buggy ways of writing code -are legal, but will draw warnings from a suitably smart compiler (such as gcc +are legal, but will draw warnings from a suitably smart compiler (such as “gcc” with the -Wall flag enabled). It takes only minutes to check your warnings and to fix the code that generates them, but it takes hours to find bugs otherwise. -Desk checking (proof reading) is almost a lost art these days. Too bad. You +“Desk checking” (proof reading) is almost a lost art these days. Too bad. You should desk check your code before even compiling it, and desk-check it again periodically to keep it fresh in mind and find new errors. If you have someone -in your group whose only job it is to desk-check other peoples code, that +in your group whose only job it is to desk-check other people’s code, that person will find and fix more bugs than everyone else combined. One can desk-check several hundred lines of code per hour. A top-flight @@ -95,20 +95,20 @@ fixing technique. Compare that to all the hours you spend screwing around with broken programs trying to find one bug at a time. The next technique beyond desk-checking is the time-honored technique of -inserting print statements into the code, and then watching the logged +inserting “print” statements into the code, and then watching the logged values. Within tbaMUD code, you can call printf(), fprintf(), or log()to dump interesting values at interesting times. Where and when to dump these values is an art, which you will learn only with practice. -If you dont already know how to redirect output in your operating system, now -is the time to learn. On Unix, type the command man csh, and read the part -about the > operator. You should also learn the difference between standard -output (for example, output from printf) and standard error (for example, -output from fprintf(stderr, ...)). +If you don’t already know how to redirect output in your operating system, now +is the time to learn. On Unix, type the command “man csh”, and read the part +about the “>” operator. You should also learn the difference between “standard +output” (for example, output from “printf”) and “standard error” (for example, +output from “fprintf(stderr, ...)”). Ultimately, you cannot fix a program unless you understand how it is operating in the first place. Powerful debugging tools will help you collect data, but -they cant interpret it, and they cant fix the underlying problems. Only you +they can’t interpret it, and they can’t fix the underlying problems. Only you can do that. When you find a bug... your first impulse will be to change the code, kill the @@ -117,9 +117,9 @@ observe is often just the symptom of a deeper bug. You should keep pursuing the bug, all the way down. You should grok the bug and cherish it in fullness before causing its discorporation. -Also, when finding a bug, ask yourself two questions: What design and -programming habits led to the introduction of the bug in the first place? And: -What habits would systematically prevent the introduction of bugs like this? +Also, when finding a bug, ask yourself two questions: “What design and +programming habits led to the introduction of the bug in the first place?” And: +“What habits would systematically prevent the introduction of bugs like this?” 5 Debugging: Tools @@ -127,20 +127,20 @@ When a Unix process accesses an invalid memory location, or (more rarely) executes an illegal instruction, or (even more rarely) something else goes wrong, the Unix operating system takes control. The process is incapable of further execution and must be killed. Before killing the process, however, the -operating system does something for you: it opens a file named core and +operating system does something for you: it opens a file named “core” and writes the entire data space of the process into it. -Thus, dumping core is not a cause of problems, or even an effect of problems. -Its something the operating system does to help you find fatal problems which +Thus, “dumping core” is not a cause of problems, or even an effect of problems. +It’s something the operating system does to help you find fatal problems which have rendered your process unable to continue. -One reads a core file with a debugger. The two most popular debuggers on Unix +One reads a “core” file with a debugger. The two most popular debuggers on Unix are adb and gdb, although occasionally one finds dbx. Typically one starts a -debugger like this: gdb bin/circle or gdb bin/circle lib/core. +debugger like this: “gdb bin/circle” or “gdb bin/circle lib/core”. The first thing, and often the only thing, you need to do inside the debugger -is take a stack trace. In adb, the command for this is $c. In gdb, the -command is backtrace. In dbx, the command is where. The stack trace will +is take a stack trace. In adb, the command for this is “$c”. In gdb, the +command is “backtrace”. In dbx, the command is “where”. The stack trace will tell you what function your program was in when it crashed, and what functions were calling it. The debugger will also list the arguments to these functions. Interpreting these arguments, and using more advanced debugger features, @@ -343,12 +343,12 @@ new tools. 7 Profiling -Another useful technique is profiling, to find out where your program is +Another useful technique is “profiling,” to find out where your program is spending most of its time. This can help you to make a program more efficient. Here is how to profile a program: -1. Remove all the .o files and the circle executable: +1. Remove all the .o files and the “circle” executable: make clean 2. Edit your Makefile, and change the PROFILE=line: @@ -359,25 +359,25 @@ make 4. Run circle as usual. Shutdown the game with the shutdown command when you have run long enough to get a good profiling base under normal usage -conditions. If you crash the game, or kill the process externally, you wont +conditions. If you crash the game, or kill the process externally, you won’t get profiling information. 5. Run the profcommand: prof bin/circle > prof.out -6. Read prof.out. Run man prof to understand the format of the output. For -advanced profiling, you can use PROFILE = -pg in step 2, and use the gprof -command in step 5. The gprof form of profiling gives you a report which lists +6. Read prof.out. Run “man prof” to understand the format of the output. For +advanced profiling, you can use “PROFILE = -pg” in step 2, and use the “gprof” +command in step 5. The “gprof” form of profiling gives you a report which lists exactly how many times any function calls any other function. This information is valuable for debugging as well as performance analysis. -Availability of prof and gprof varies from system to system. Almost every -Unix system has prof. Only some systems have gprof. +Availability of “prof” and “gprof” varies from system to system. Almost every +Unix system has “prof”. Only some systems have “gprof”. 7 Books for Serious Programmers Out of all the thousands of books out there, three stand out: -Kernighan and Plaugher, The Elements of Programming Style -Kernighan and Ritchie, The C Programming Language -Brooks, The Mythical Man Month +Kernighan and Plaugher, “The Elements of Programming Style” +Kernighan and Ritchie, “The C Programming Language” +Brooks, “The Mythical Man Month” diff --git a/doc/files.txt b/doc/files.txt index 5b4b2f2..a300f7f 100644 --- a/doc/files.txt +++ b/doc/files.txt @@ -3,7 +3,7 @@ Builder Academy at telnet://tbamud.com:9091 or email rumble@tbamud.com -- Rumble tbaMUD File Manifest -The main tbaMUD/ directory has the following subdirectories and files: +The main ‘tbaMUD/’ directory has the following subdirectories and files: autorun - Shell script to run the MUD (./autorun &). FAQ - Frequently Aske Questions with answers. @@ -16,7 +16,7 @@ lib/ - MUD data. log/ - System logs. src/ - Source code. -The bin/directory contains only binaries: circle (the main MUD) and its +The bin/directory contains only binaries: ‘circle’ (the main MUD) and its utilities, which are described in utils.txt. The doc/ directory has its own README file, describing the contents of each @@ -51,12 +51,12 @@ time - Where the MUD time is saved. The lib/misc/ directory contains the following files: -bugs - Bugs reported by players with the bug command. -ideas - Ideas from players from idea command. +bugs - Bugs reported by players with the ’bug’ command. +ideas - Ideas from players from ’idea’ command. messages - Spell and skill damage messages. socials - Text file with text of the socials. socials.new - New format of socials you can edit via AEDIT. -typos - Typos reported by players with the typo command. +typos - Typos reported by players with the ’typo’ command. xnames - Text file of invalid names. The lib/plrobjs/ contains the following files and directories: @@ -80,18 +80,18 @@ zzz/ The lib/text/ directory contains the following files: background - Background story (for option 3 from main menu). -credits - Text for credits command. +credits - Text for ’credits’ command. greetings - Greeting message. -handbook - Text for Immortal Handbook (handbook command). -immlist - Text for immlist command. +handbook - Text for Immortal Handbook (’handbook’ command). +immlist - Text for ’immlist’ command. imotd - Immortal MOTD --seen by immortals on login. -info - Text for info command. +info - Text for ’info’ command. motd - MOTD --seen by mortals on login. -news - Text for news command. -policies - Text for policy command. -wizlist - Text for wizlist command. -/help/screen - Text for help command as a mortal with no arguments. -/help/iscreen - Text for help command an an immortal with no arguments. +news - Text for ’news’ command. +policies - Text for ’policy’ command. +wizlist - Text for ’wizlist’ command. +/help/screen - Text for ’help’ command as a mortal with no arguments. +/help/iscreen - Text for ’help’ command an an immortal with no arguments. The lib/world/directory contains the following subdirectories: @@ -103,8 +103,8 @@ wld - Contains *.wld files (world files) zon - Contains *.zon files (zone files) Each of the 6 subdirectories in the lib/world/ directory also contains two -additional files one called index, which specifies which files in that -directory should be loaded when the MUD boots, and index.mini, which +additional files – one called ‘index’, which specifies which files in that +directory should be loaded when the MUD boots, and ‘index.mini’, which specifies which files should be loaded if the MUD is booted with the -m (mini-mud) option. @@ -128,6 +128,6 @@ trigger - Trigedit log messages. usage - Mud system usage (player load & memory usage info). The src/ directory contains all of the C and header files for the MUD, along -with a Makefile. The src/util/ directory contains source for tbaMUDs utility +with a Makefile. The src/util/ directory contains source for tbaMUD’s utility programs. See admin.txt for more information on how to compile the MUD. See -utils.txt for more information on how to use tbaMUDs utilities. +utils.txt for more information on how to use tbaMUD’s utilities. diff --git a/doc/porting.txt b/doc/porting.txt index 9ec3885..97c7824 100644 --- a/doc/porting.txt +++ b/doc/porting.txt @@ -9,16 +9,16 @@ every platform that exists. This document is for experienced programmers trying to make tbaMUD work on their platform. tbaMUD should work on most UNIX platforms without any modifications; simply run -the configure script and it should automatically detect what type of system +the “configure” script and it should automatically detect what type of system you have and anything that may be strange about it. These findings are all stored in a header file called conf.h which is created in the src directory from a template called conf.h.in. A Makefile is also created from the template Makefile.in. -Non-UNIX platforms are a problem. Some cant run tbaMUD at all. However, any +Non-UNIX platforms are a problem. Some can’t run tbaMUD at all. However, any multitasking OS that has an ANSI C compiler, and supports non-blocking I/O and socket-based TCP/IP networking, should theoretically be able to run tbaMUD; for -example, OS/2, AmigaOS, Mac OS (Classic versions; Mac OS X supports tbaMUDs +example, OS/2, AmigaOS, Mac OS (Classic versions; Mac OS X supports tbaMUD’s configure script from the command line), and all versions of Windows. The port can be very easy or very difficult, depending mainly on whether or nor @@ -26,7 +26,7 @@ your OS supports the Berkeley socket API. The general steps for porting tbaMUD to a non-UNIX platform are listed below. A number of tips for porting can be found after the porting steps. Note that we -have already ported tba to Windows, so if youre confused as to how to perform +have already ported tba to Windows, so if you’re confused as to how to perform some of these steps, you can look at what we have done as an example (see the files README.CYGWIN). @@ -36,11 +36,11 @@ trying to port the code. Porting the Code -Step 1. Create a conf.h file for your system. Copy the template conf.h.in -to conf.h, and then define or undefine each item as directed by the comments +Step 1. Create a “conf.h” file for your system. Copy the template “conf.h.in” +to “conf.h”, and then define or undefine each item as directed by the comments and based on the characteristics of your system. To write the conf.h file, -youll need to know which header files are included with your system, the -return type of signals, whether or not your compiler supports the const +you’ll need to know which header files are included with your system, the +return type of signals, whether or not your compiler supports the ‘const’ keyword, and whether or not you have various functions such as crypt()and random(). Also, you can ignore the HAVE_LIBxxx and HAVE_xxx_PROTO constants at the end of conf.h.in; they are not used in the code (they are part of UNIX @@ -58,12 +58,12 @@ be in the source file comm.c. Step 4. Test your changes! Make sure that multiple people can log in simultaneously and that they can all type commands at the same time. No player -should ever have a frozen screen just because another is waiting at a prompt. +should ever have a “frozen” screen just because another is waiting at a prompt. Leave the MUD up for at least 24 hours, preferably with people playing it, to make sure that your changes are stable. Make sure that automatic events such as zone resets, point regeneration, and corpse decomposition are being timed correctly (a tick should be about 75 seconds). Try resetting all the zones -repeatedly by typing zr * many times. Play the MUD and make sure that the +repeatedly by typing “zr *” many times. Play the MUD and make sure that the basic commands (killing mobs as a mortal, casting spells, etc.) work correctly. Step 5. If you are satisfied that your changes work correctly, you are @@ -71,20 +71,20 @@ encouraged to submit them to be included as part of the tbaMUD distribution so that future releases of tbaMUD will support your platform. This prevents you from re-porting the code every time a new version is released and allows other people who use your platform to enjoy tbaMUD as well. To submit your changes -you must make a patch file using the GNU diff program. diff will create a -patch file which can be later used with the patch utility to incorporate +you must make a patch file using the GNU ‘diff’ program. diff will create a +patch file which can be later used with the ‘patch’ utility to incorporate your changes into the stock tbaMUD distribution. For example, if you have a -copy of tbaMUD in the stock-tba directory, and your changes are in my-tba, +copy of tbaMUD in the “stock-tba” directory, and your changes are in “my-tba”, you can create a patch file like this: diff -u --new-file --recursive stock-tba/src my-tba/src > patch -This will create a file called patch with your patches. You should then try -to use the patch program (the inverse of diff) on a copy of tbaMUD to make +This will create a file called ‘patch’ with your patches. You should then try +to use the ‘patch’ program (the inverse of ‘diff’) on a copy of tbaMUD to make sure that tbaMUD is correctly changed to incorporate your patches. This step is -very important: if you dont create these patches correctly, your work will be +very important: if you don’t create these patches correctly, your work will be useless because no one will be able to figure out what you did! Make sure to -read the documentation to diff and patch if you dont understand how to use +read the documentation to ‘diff’ and ‘patch’ if you don’t understand how to use them. If your patches work, CELEBRATE!! Step 6. Write a README file for your operating system that describes everything @@ -107,7 +107,7 @@ Each system to which tba is already ported has a CIRCLE_xx constant associated with it: CIRCLE_UNIX for plain vanilla UNIX tbaMUD, CIRCLE_WINDOWS for MS Windows, CIRCLE_OS2 for IBM OS/2, and CIRCLE_AMIGA for the Amiga. You must use a similar constant for your system. At the top of your conf.h, make sure to -comment out #define CIRCLE_UNIX and add #define CIRCLE_YOUR_SYSTEM. +comment out “#define CIRCLE_UNIX” and add “#define CIRCLE_YOUR_SYSTEM”. 3.2 ANSI C and GCC As long as your system has an ANSI C compiler, all of the code (except for @@ -122,22 +122,22 @@ you use gcc. Make absolutely sure to use non-blocking I/O; i.e. make sure to enable the option so that the read() system call will immediately return with an error if there is no data available. If you do not use non-blocking I/O, read() will -block, meaning it will wait infinitely for one particular player to type +“block,” meaning it will wait infinitely for one particular player to type something even if other players are trying to enter commands. If your system does not implement non-blocking I/O correctly, try using the POSIX_NONBLOCK_BROKEN constant in sysdep.h. 3.4 Timing tbaMUD needs a fairly precise (on the order of 5 or 10 ms) timer in order to -correctly schedule events such as zone resets, point regeneration (ticks), +correctly schedule events such as zone resets, point regeneration (“ticks”), corpse decomposition, and other automatic tasks. If your system supports the select() system call with sufficient precision, the default timing code should -work correctly. If not, youll have to find out which system calls your system +work correctly. If not, you’ll have to find out which system calls your system supports for determining how much time has passed and replace the select() timing method. 3.5 Signals and Signal Handlers -A note about signals: Most systems dont support the concept of signals in the +A note about signals: Most systems don’t support the concept of signals in the same way that UNIX does. Since signals are not a critical part of how tbaMUD works anyway (they are only used for updating the wizlist and some other trivial things), all signal handling is turned off by default when compiling @@ -147,7 +147,7 @@ conf.h file and all signal code will be ignored automatically. 4 Final Note IMPORTANT: Remember to keep any changes you make surrounded by #ifdef -statements (i.e. #ifdef CIRCLE_WINDOWS ... #endif). If you make absolutely +statements (i.e. “#ifdef CIRCLE_WINDOWS ... #endif”). If you make absolutely sure to mark all of your changes with #ifdef statements, then your patches (once you get them to work) will be suitable for incorporation into the tbaMUD distribution, meaning that tbaMUD will officially support your platform. diff --git a/doc/releases.txt b/doc/releases.txt index a6f0756..37e2df5 100755 --- a/doc/releases.txt +++ b/doc/releases.txt @@ -143,7 +143,7 @@ communication channels totally ignores all commands from that player until they are thawed. --Even handier DELETE flag allows you to delete players on the fly. --"set" command (mentioned above) allows you to freeze/unfreeze/ -delete/siteok/un-siteok players --even if they arent logged in! +delete/siteok/un-siteok players --even if they aren’t logged in! --Bad password attempts are written to the system log and saved; if someone tries to hack your account, you see "4 LOGIN FAILURES SINCE LAST SUCCESSFUL LOGIN" next time you log on. diff --git a/doc/socials.txt b/doc/socials.txt index ad4a780..0d72a5e 100644 --- a/doc/socials.txt +++ b/doc/socials.txt @@ -110,12 +110,12 @@ is being specified. The command sort name is the shortest part of the command a player must type for it to match. The hide-flag can be either 0 or 1; if 1, the social is hidden from OTHERS if they cannot see the character performing the social. The action is not hidden from the VICTIM, even if s/he cannot see the -character performing the social, although in such cases the characters name -will, of course, be replaced with someone. The min positions should be set to +character performing the social, although in such cases the character’s name +will, of course, be replaced with “someone”. The min positions should be set to dictate the minimum position a player must be in to target the victim and perform the social. Min level allows you to further customize who can use what socials.Where it makes sense to do so, text fields may be left empty. If -editing manually you should by put a # in the first column on the line. Aedit +editing manually you should by put a ‘#’ in the first column on the line. Aedit does this automatically. Examples: diff --git a/doc/utils.txt b/doc/utils.txt index 79c8bfc..bc3915d 100644 --- a/doc/utils.txt +++ b/doc/utils.txt @@ -34,7 +34,7 @@ older CircleMUD data files to the versions used in CircleMUD v3, while others are used to convert currently existing files into different formats. Overall, these utilities have been created in an attempt to make the tbaMUD -administrators life a bit easier, and to give the administrator some ideas of +administrator’s life a bit easier, and to give the administrator some ideas of further and more grandiose utilities to create. Some are no longer applicable but are retained as examples. @@ -61,7 +61,7 @@ the second, and so forth. The split utility is designed to split large world files into smaller, zone sized files that are easier to manage and maintain. The utility reads its input from the standard input and writes the output to files with names specified -within the larger world file. This is done by inserting =filename into the +within the larger world file. This is done by inserting ‘=filename’ into the world file at the appropriate points, where filename is the name of the file for the following section. @@ -141,8 +141,8 @@ The command line syntax for autowiz is as follows: autowiz [pid to signal] where is equal to whatever LVL_GOD is set to in your tbaMUD server, - is the filename for the file containing the games Wizlist. - should be set to your games LVL_IMMORT, while + is the filename for the file containing the game’s Wizlist. + should be set to your game’s LVL_IMMORT, while is the name of the Immlist file. This utility must be recompiled if you make any changes to the player file structure. From 89eb009c4f2d35ecef0ecdfd4479b056dff2f0c7 Mon Sep 17 00:00:00 2001 From: Thomas Arp <357770+welcor@users.noreply.github.com> Date: Wed, 2 Jul 2025 22:18:40 +0200 Subject: [PATCH 14/19] Remove webster lookup since it no longer works (#99) * removed useless util/webster.c and fixed a couple of potential buffer overruns in the util functions * removed stray utf-8 error chars. I guess someone has used an editor with fancy 's * removed last webster integrations --- lib/text/help/help.hlp | 96 +++++++++------------- src/act.comm.c | 34 +------- src/comm.c | 70 ++--------------- src/comm.h | 3 - src/util/Makefile.in | 7 +- src/util/autowiz.c | 2 +- src/util/shopconv.c | 16 ++-- src/util/webster.c | 175 ----------------------------------------- 8 files changed, 55 insertions(+), 348 deletions(-) delete mode 100755 src/util/webster.c diff --git a/lib/text/help/help.hlp b/lib/text/help/help.hlp index d7b2eae..5ecfd23 100644 --- a/lib/text/help/help.hlp +++ b/lib/text/help/help.hlp @@ -865,7 +865,7 @@ AUTOQUESTS QUESTS QUESTMASTERS QUEST-MOBS QUESTMOBS An autoquest is a quest that can be automatically started and completed without the intervention of an immortal. Simply visit a questmaster and join -an available quest, and get rewarded on its completion. Keep an eye out for +an available quest, and get rewarded on it's completion. Keep an eye out for autoquests scattered throughout the World. See Also: QUEST-FLAG, QUESTPOINTS @@ -1584,7 +1584,6 @@ qedit (quest editor) questpoints buildwalk dig -tell m-w (an in game dictionary lookup) gemote history file @@ -2444,25 +2443,6 @@ Example: > diagnose doctor See also: CONSIDER, HIT, KILL -#0 -DICTIONARY DICTIONARIES THESAURUS M-W.COM DEFINITION MERRIAM-WEBSTER M-W-DEFINITION WEBSTER MW TELL-M-W BREATHER SPELLING WORDS - -Usage: tell m-w - - We have a direct link to Merriam Webster. To use the dictionary just -tell m-w - ->tell m-w breather -You get this feedback from Merriam-Webster: -That means: -1 : one that breathes -2 : a break in activity for rest or relief -3 : a small vent in an otherwise airtight enclosure - -A few obscure definitions are not available through m-w since they are in the -unabridged version that requires membership. They also offer a thesaurus at: -@Chttp://m-w.com/@n - #31 DIG UNDIG RDIG RELINK RLINKS @@ -3173,7 +3153,7 @@ game. Invest in a thesaurus. Makes a world of difference, and if that doesn't help, just make up your own words for things you create (just be sure to describe them very well. Use @Chttp://m-w.com/@n for an online thesaurus -and dictionary. You can @Rtell m-w @n to lookup a definition. +and dictionary. 4. Where can I learn Trigedit? Here! Welcor is now the developer of trigedit. We have extensive help files, @@ -3564,8 +3544,8 @@ GRAMMAR GRAMMER TIPS words can be particularly tricky and elude electronic spell checkers. A good dictionary, however, will help you spell archaic words. Whenever I am building I use our Merriam Webster dictionary link on TBA to check any tough words for -proper spelling. Test it out @RTELL M-W DEFINITION@n. We hope to add a thesaurus -soon! Goto @Chttp://m-w.com/@n until then. +proper spelling. We hope to add a thesaurus soon! Goto @Chttp://m-w.com/@n +until then. I have found that a good principle to make is to avoid the use of all contractions. For example, if you mean to say "it is", do not use "it's", spell it out. This will help differentiate between "its" (which means 'belonging to @@ -7192,7 +7172,7 @@ prefer to add the quest in the zone where quest completion takes place. Quests use vnums in exactly the same way as mobiles, object and rooms. Each zone will normally have 100 vnums available (#00 to #99, where # is the zone number). Usually, when creating the first quest in a zone, #00 is used, -then #01, etc +then #01, etc. When you qedit to create a new quest (or edit an existing one), you will see the menu in @RHELP QEDIT-MENU@n @@ -7203,12 +7183,12 @@ QEDIT-ACCEPT This is the text that is sent to the player when they start the quest. It should describe in detail exactly what is required to complete the quest. The -text is simply output on the players screen, so be creative here. An example +text is simply output on the player's screen, so be creative here. An example of an accept message text could be something like: The questmaster rummages in a large pile of papers. -The questmaster says Ah, here it is -The questmaster says Bob, the local butcher has offered this quest +The questmaster says "Ah, here it is" +The questmaster says "Bob, the local butcher has offered this quest" The questmaster shows you a hastily scrawled note, that reads: I am willing to offer any plucky adventurer 10 quest points if they bring me a @@ -7218,7 +7198,7 @@ order to fill. I need these within 24 hours Thanks, Bob the Butcher, Midgaard The questmaster sighs. -The questmaster says A tricky quest, but itll cost you 5qp to back out now +The questmaster says "A tricky quest, but it'll cost you 5qp to back out now" #31 QEDIT-COMPLETED QEDIT-ABANDONED @@ -7232,7 +7212,7 @@ all timed quests. QEDIT-COMPLETION Just like the accept message, this is simply text that is output on the -players screen when they successfully complete the quest. Prizes (quest +player's screen when they successfully complete the quest. Prizes (quest points, gold coins, experience points or an object) are automatically announced after this text is shown, so this text does not need to have that information in it. @@ -7258,7 +7238,7 @@ Quest flags: @cNOBITS@n Enter quest flags, 0 to quit : Currently, only one flag is available, the REPEATABLE flag. When you have -finished turning this on or off, select 0 (zero) to return to the main menu. +finished turning this on or off, select "0" (zero) to return to the main menu. #31 QEDIT-LEVELS @@ -7312,12 +7292,12 @@ QEDIT-NEXT This is the quest vnum of next quest in a chain. When a player completes the current quest, the next quest will automatically be joined. This allows -for long quests with a number of steps. +for long quests with a number of "steps". #31 QEDIT-PREREQUISITE This is the object vnum for a prerequisite object. The prerequisite object -should be in the players inventory in order for them to be able to join the +should be in the player's inventory in order for them to be able to join the quest. It is not taken from the player when the quest starts. #31 QEDIT-PREVIOUS @@ -7328,15 +7308,15 @@ completed by the player in order to join this quest. QEDIT-QUANTITY This is the number of times the player needs to repeat the quest. For -example, it could be the number of items the player needs to find in a object -quest of the number of mobs the player should kill in a kill mob quest. This -should be used with caution, however. In an object quest picking up the same +example, it could be the number of items the player needs to find in a "object" +quest of the number of mobs the player should kill in a "kill mob" quest. This +should be used with caution, however. In an object quest picking up the same object 20 times will also complete the quest. #31 QEDIT-QUIT QEDIT-MESSAGE The quit message is sent to the player when they type quest leave. Players -can lose quest points for abandoning a quest (see Abandoned on the next +can lose quest points for abandoning a quest (see "Abandoned" on the next page), so if they lose quest points, this text really should inform them of that. #31 @@ -7365,14 +7345,14 @@ Room, Clear Room - Room VNUM #31 QEDIT-TIME - This is the number of ticks or game hours that the player has to complete + This is the number of 'ticks' or game hours that the player has to complete the quest. If this is set, then the builder should really try to do the quest -themselves, and time how long it takes (typing time before and after the -attempt), and then giving at least one extra tick for players to complete it. +themselves, and time how long it takes (typing 'time' before and after the +attempt), and then giving at least one extra 'tick' for players to complete it. #31 QEDIT-TYPE - There are a few different quest types. When you select option 7 from the + There are a few different quest types. When you select option '7' from the main menu, you will be shown a list to choose from: 0) Object - Player needs to find a particular object. @@ -7447,7 +7427,7 @@ Usage: quest [list | join <#> | progress | leave | history] quest - Show usage information for the quest command. quest list - Used at the questmaster to see which quests are available. -quest join # - Used to the questmaster to join the quest listed as number nn on quest list. +quest join # - Used to the questmaster to join the quest listed as number 'nn' on quest list. quest progress - Shows the player which quest they are doing, and their quest progress. quest leave - Allows the player to abandon the current quest, taking the quest point penalty. quest history - Shows all previously completed non-repeatable quests. @@ -9352,7 +9332,7 @@ and simply bearing artistic merit. Second, by ensuring that they are absolutely necessary to achieve the goals of the game! If your game is made for experience and equipment gathering, and failure to read descriptions directly impedes this goal, then players will learn to read everything. If your game is made for -exploring or role-play, most of your players probably already read them - +exploring or role-play, most of your players probably already read them - because knowing their environment is a basic requirement of play. In any case, builders exist to ensure that the goals of play are supported by game descriptions. @@ -9364,7 +9344,7 @@ meaning behind descriptions, areas to find, special items, unique nooks and crannies to spend time socializing, and hints that point to these things elsewhere outside of your own zone is an excellent idea. In fact, if you don't wish to be building descriptions no one will read, you should employ -special secrets - most especially on games where knowing one's environment +special secrets - most especially on games where knowing one's environment does deeply affect a character's development. No matter what kind of zone you are building, keep it interesting throughout! @@ -9387,7 +9367,7 @@ road. shouldn't be the sole builder of your zone. Instead, seek the assistance of someone who adds creative merit to your descriptions. You can do practically everything from plot to secrets to minutiae, even write the zone in full and - just ask someone you know who writes well to 'say it better' and rewrite + just ask someone you know who writes well to 'say it better' and rewrite what you intended to have there all along. Novels have editors, and so should any zone. @@ -9659,19 +9639,19 @@ have a point and here it is: *drum roll please* Building is hard work! It is a form of expression and creativity. What kind of areas you build generally reflects on what kind of person you are. You do not have to be a good speller but you do need a good dictionary/thesaurus. -@RHELP M-W@n. Sometimes building can seem like a thankless job and sometimes -building can be a reward in itself. Building a few areas, even a few good -ones, does not make you an Immortal or an Imp. It takes more than building to -be one of those and it entails even more work. Respect others and they will -respect you. The more detailed an area the better it is. Always choose Quality -over Quantity. Put some pride in your areas, develop a style of your own. Try -new things keep it interesting, if you become bored with building an area take -a break and play a mortal or do something else, don't take advantage of builder -privileges. Treat others as you wish to be treated. One more warning I would -give to builders before they take things personally or get insulted. Everyone -has their own ideas on how to run a MUD, what it comes down to is whoever owns -the MUD makes the final decision, so it does not matter how good you think your -idea is, it may never be used if the owner does not like it. Plain and simple. +Sometimes building can seem like a thankless job and sometimes building can be +a reward in itself. Building a few areas, even a few good ones, does not make +you an Immortal or an Imp. It takes more than building to be one of those and +it entails even more work. Respect others and they will respect you. The more +detailed an area the better it is. Always choose Quality over Quantity. Put +some pride in your areas, develop a style of your own. Try new things keep it +interesting, if you become bored with building an area take a break and play a +mortal or do something else, don't take advantage of builder privileges. +Treat others as you wish to be treated. One more warning I would give to +builders before they take things personally or get insulted. Everyone has their +own ideas on how to run a MUD, what it comes down to is whoever owns the MUD +makes the final decision, so it does not matter how good you think your idea +is, it may never be used if the owner does not like it. Plain and simple. You see this on every MUD. So please keep the ideas coming, but do not try to force them onto anyone. Be constructive, not critical about peoples ideas. Everyone is allowed their opinions. diff --git a/src/act.comm.c b/src/act.comm.c index 84e0449..637b9df 100644 --- a/src/act.comm.c +++ b/src/act.comm.c @@ -150,39 +150,7 @@ ACMD(do_tell) if (!*buf || !*buf2) send_to_char(ch, "Who do you wish to tell what??\r\n"); - else if (!strcmp(buf, "m-w")) { -#ifdef CIRCLE_WINDOWS - /* getpid() is not portable */ - send_to_char(ch, "Sorry, that is not available in the windows port.\r\n"); -#else /* all other configurations */ - char word[MAX_INPUT_LENGTH], *p, *q; - - if (last_webster_teller != -1L) { - if (GET_IDNUM(ch) == last_webster_teller) { - send_to_char(ch, "You are still waiting for a response.\r\n"); - return; - } else { - send_to_char(ch, "Hold on, m-w is busy. Try again in a couple of seconds.\r\n"); - return; - } - } - - /* Only a-z and +/- allowed. */ - for (p = buf2, q = word; *p ; p++) - if ((LOWER(*p) <= 'z' && LOWER(*p) >= 'a') || (*p == '+') || (*p == '-')) - *q++ = *p; - - *q = '\0'; - - if (!*word) { - send_to_char(ch, "Sorry, only letters and +/- are allowed characters.\r\n"); - return; - } - snprintf(buf, sizeof(buf), "../bin/webster %s %d &", word, (int) getpid()); - last_webster_teller = GET_IDNUM(ch); - send_to_char(ch, "You look up '%s' in Merriam-Webster.\r\n", word); -#endif /* platform specific part */ - } else if (GET_LEVEL(ch) < LVL_IMMORT && !(vict = get_player_vis(ch, buf, NULL, FIND_CHAR_WORLD))) + else if (GET_LEVEL(ch) < LVL_IMMORT && !(vict = get_player_vis(ch, buf, NULL, FIND_CHAR_WORLD))) send_to_char(ch, "%s", CONFIG_NOPERSON); else if (GET_LEVEL(ch) >= LVL_IMMORT && !(vict = get_char_vis(ch, buf, NULL, FIND_CHAR_WORLD))) send_to_char(ch, "%s", CONFIG_NOPERSON); diff --git a/src/comm.c b/src/comm.c index 12323d2..ed7d609 100644 --- a/src/comm.c +++ b/src/comm.c @@ -104,8 +104,7 @@ unsigned long pulse = 0; /* number of pulses since game start */ ush_int port; socket_t mother_desc; int next_tick = SECS_PER_MUD_HOUR; /* Tick countdown */ -/* used with do_tell and handle_webster_file utility */ -long last_webster_teller = -1L; + /* static local global variable declarations (current file scope only) */ static struct txt_block *bufpool = 0; /* pool of large output buffers */ @@ -113,14 +112,11 @@ static int max_players = 0; /* max descriptors available */ static int tics_passed = 0; /* for extern checkpointing */ static struct timeval null_time; /* zero-valued time structure */ static byte reread_wizlist; /* signal: SIGUSR1 */ -/* normally signal SIGUSR2, currently orphaned in favor of Webster dictionary - * lookup -static byte emergency_unban; -*/ +static byte emergency_unban; /* signal: SIGUSR2 */ + static int dg_act_check; /* toggle for act_trigger */ static bool fCopyOver; /* Are we booting in copyover mode? */ static char *last_act_message = NULL; -static byte webster_file_ready = FALSE;/* signal: SIGUSR2 */ /* static local function prototypes (current file scope only) */ static RETSIGTYPE reread_wizlists(int sig); @@ -160,9 +156,6 @@ static int open_logfile(const char *filename, FILE *stderr_fp); #if defined(POSIX) static sigfunc *my_signal(int signo, sigfunc *func); #endif -/* Webster Dictionary Lookup functions */ -static RETSIGTYPE websterlink(int sig); -static void handle_webster_file(void); static void msdp_update(void); /* KaVir plugin*/ @@ -958,7 +951,7 @@ void game_loop(socket_t local_mother_desc) mudlog(CMP, LVL_IMMORT, TRUE, "Signal received - rereading wizlists."); reboot_wizlists(); } -/* Orphaned right now as signal trapping is used for Webster lookup + if (emergency_unban) { emergency_unban = FALSE; mudlog(BRF, LVL_IMMORT, TRUE, "Received SIGUSR2 - completely unrestricting game (emergent)"); @@ -966,11 +959,7 @@ void game_loop(socket_t local_mother_desc) circle_restrict = 0; num_invalid = 0; } -*/ - if (webster_file_ready) { - webster_file_ready = FALSE; - handle_webster_file(); - } + #ifdef CIRCLE_UNIX /* Update tics_passed for deadlock protection (UNIX only) */ @@ -2232,18 +2221,10 @@ static RETSIGTYPE reread_wizlists(int sig) reread_wizlist = TRUE; } -/* Orphaned right now in place of Webster ... static RETSIGTYPE unrestrict_game(int sig) { emergency_unban = TRUE; } -*/ - -static RETSIGTYPE websterlink(int sig) -{ - webster_file_ready = TRUE; -} - #ifdef CIRCLE_UNIX @@ -2318,7 +2299,7 @@ static void signal_setup(void) /* user signal 2: unrestrict game. Used for emergencies if you lock * yourself out of the MUD somehow. */ - my_signal(SIGUSR2, websterlink); + my_signal(SIGUSR2, unrestrict_game); /* set up the deadlock-protection so that the MUD aborts itself if it gets * caught in an infinite loop for more than 3 minutes. */ @@ -2780,45 +2761,6 @@ static void circle_sleep(struct timeval *timeout) #endif /* CIRCLE_WINDOWS */ -static void handle_webster_file(void) { - FILE *fl; - struct char_data *ch = find_char(last_webster_teller); - char retval[MAX_STRING_LENGTH], line[READ_SIZE]; - size_t len = 0, nlen = 0; - - last_webster_teller = -1L; - - if (!ch) /* they quit ? */ - return; - - fl = fopen("websterinfo", "r"); - if (!fl) { - send_to_char(ch, "It seems the dictionary is offline..\r\n"); - return; - } - - unlink("websterinfo"); - - get_line(fl, line); - while (!feof(fl)) { - nlen = snprintf(retval + len, sizeof(retval) - len, "%s\r\n", line); - if (len + nlen >= sizeof(retval)) - break; - len += nlen; - get_line(fl, line); - } - - if (len >= sizeof(retval)) { - const char *overflow = "\r\n**OVERFLOW**\r\n"; - strcpy(retval + sizeof(retval) - strlen(overflow) - 1, overflow); /* strcpy: OK */ - } - fclose(fl); - - send_to_char(ch, "You get this feedback from Merriam-Webster:\r\n"); - page_string(ch->desc, retval, 1); -} - - /* KaVir's plugin*/ static void msdp_update( void ) { diff --git a/src/comm.h b/src/comm.h index 9837c86..d723998 100644 --- a/src/comm.h +++ b/src/comm.h @@ -60,9 +60,6 @@ void game_loop(socket_t mother_desc); void heartbeat(int heart_pulse); void copyover_recover(void); -/** webster dictionary lookup */ -extern long last_webster_teller; - extern struct descriptor_data *descriptor_list; extern int buf_largecount; extern int buf_overflows; diff --git a/src/util/Makefile.in b/src/util/Makefile.in index e96c361..7c5b5af 100644 --- a/src/util/Makefile.in +++ b/src/util/Makefile.in @@ -23,7 +23,7 @@ CFLAGS = @CFLAGS@ $(MYFLAGS) $(PROFILE) -I$(INCDIR) default: all -all: $(BINDIR)/asciipasswd $(BINDIR)/autowiz $(BINDIR)/plrtoascii $(BINDIR)/rebuildIndex $(BINDIR)/rebuildMailIndex $(BINDIR)/shopconv $(BINDIR)/sign $(BINDIR)/split $(BINDIR)/wld2html $(BINDIR)/webster +all: $(BINDIR)/asciipasswd $(BINDIR)/autowiz $(BINDIR)/plrtoascii $(BINDIR)/rebuildIndex $(BINDIR)/rebuildMailIndex $(BINDIR)/shopconv $(BINDIR)/sign $(BINDIR)/split $(BINDIR)/wld2html asciipasswd: $(BINDIR)/asciipasswd @@ -43,8 +43,6 @@ split: $(BINDIR)/split wld2html: $(BINDIR)/wld2html -webster: $(BINDIR)/webster - $(BINDIR)/asciipasswd: asciipasswd.c $(CC) $(CFLAGS) -o $(BINDIR)/asciipasswd asciipasswd.c @CRYPTLIB@ @@ -72,9 +70,6 @@ $(BINDIR)/split: split.c $(BINDIR)/wld2html: wld2html.c $(CC) $(CFLAGS) -o $(BINDIR)/wld2html wld2html.c -$(BINDIR)/webster: webster.c - $(CC) $(CFLAGS) -o $(BINDIR)/webster webster.c - # Dependencies for the object files (automagically generated with # gcc -MM) diff --git a/src/util/autowiz.c b/src/util/autowiz.c index f5f0209..a711834 100755 --- a/src/util/autowiz.c +++ b/src/util/autowiz.c @@ -85,7 +85,7 @@ void read_file(void) while (get_line(fl, line)) if (*line != '~') recs++; - rewind(fl); + rewind(fl); for (i = 0; i < recs; i++) { get_line(fl, line); diff --git a/src/util/shopconv.c b/src/util/shopconv.c index 6f71c6b..3bdc567 100755 --- a/src/util/shopconv.c +++ b/src/util/shopconv.c @@ -155,7 +155,7 @@ static int boot_the_shops_conv(FILE * shop_f, FILE * newshop_f, char *filename) int main(int argc, char *argv[]) { FILE *sfp, *nsfp; - char fn[256], part[256]; + char fn[120], part[256]; int result, index, i; if (argc < 2) { @@ -173,20 +173,20 @@ int main(int argc, char *argv[]) perror(fn); } else { if ((nsfp = fopen(fn, "w")) == NULL) { - printf("Error writing to %s.\n", fn); - continue; + printf("Error writing to %s.\n", fn); + continue; } printf("%s:\n", fn); result = boot_the_shops_conv(sfp, nsfp, fn); fclose(nsfp); fclose(sfp); if (result) { - sprintf(part, "mv %s.tmp %s", fn, fn); - i = system(part); + sprintf(part, "mv %s.tmp %s", fn, fn); + i = system(part); } else { - sprintf(part, "mv %s.tmp %s.bak", fn, fn); - i = system(part); - printf("Done!\n"); + sprintf(part, "mv %s.tmp %s.bak", fn, fn); + i = system(part); + printf("Done!\n"); } } } diff --git a/src/util/webster.c b/src/util/webster.c deleted file mode 100755 index b234452..0000000 --- a/src/util/webster.c +++ /dev/null @@ -1,175 +0,0 @@ -/* ************************************************************************ -* File: webster.c Part of tbaMUD * -* Usage: Use an online dictionary via tell m-w . * -* * -* Based on the Circle 3.0 syntax checker and wld2html programs. * -************************************************************************ */ - -#define log(msg) fprintf(stderr, "%s\n", msg) - -#include "conf.h" -#include "sysdep.h" - - -#define MEM_USE 10000 -char buf[MEM_USE]; - -int get_line(FILE * fl, char *buf); -void skip_spaces(char **string); -void parse_webster_html(char *arg); -int main(int argc, char **argv) -{ - int pid = 0; - if (argc != 3) { - return 0; /* no word/pid given */ - } - pid = atoi(argv[2]); - - snprintf(buf, sizeof(buf), - "lynx -accept_all_cookies -source http://www.thefreedictionary.com/%s" - " >webster.html", argv[1]); - system(buf); - - parse_webster_html(argv[1]); - - if (pid) - kill(pid, SIGUSR2); - - return (0); -} - -void parse_webster_html(char *arg) { - FILE *infile, *outfile; - char scanbuf[MEM_USE], outline[MEM_USE], *p, *q; - - outfile = fopen("websterinfo", "w"); - if (!outfile) - exit(1); - - infile = fopen("webster.html", "r"); - if (!infile) { - fprintf(outfile, "A bug has occured in webster. (no webster.html) Please notify Welcor."); - fclose(outfile); - return; - } - - unlink("webster.html"); /* We can still read */ - - for ( ; get_line(infile, buf)!=0; ) { - - if (strncmp(buf, "", 40) != 0) - continue; // read until we hit the line with results in it. - - p = buf+40; - - if (strncmp(p, "
", 4) == 0) - { - fprintf(outfile, "That word could not be found.\n"); - goto end; - } - else if (strncmp(p, "
"); // chop the line at the end of tags:
word becomes ""); // skip the rest of this tag. - - fprintf(outfile, "Info on: %s\n\n", arg); - - while (1) - { - q = outline; - - while (*p != '<') - { - assert(p < scanbuf+sizeof(scanbuf)); - *q++ = *p++; - } - if (!strncmp(p, " tag or a
or
tag, ignore it. - - *q++='\0'; - fprintf(outfile, "%s", outline); - - if (!strncmp(p, ""); - } - } - else if (strncmp(p, "
", 5) == 0) // not found, but suggestions are ample: - { - strncpy(scanbuf, p, sizeof(scanbuf)); // strtok on a copy. - - p = strtok(scanbuf, ">"); // chop the line at the end of tags:
word becomes "
" "" "word" - p = strtok(NULL, ">"); // skip the rest of this tag. - - while (1) - { - q = outline; - - while (*p != '<') - *q++ = *p++; - - if (!strncmp(p, " tag, ignore it. - - *q++='\0'; - fprintf(outfile, "%s", outline); - - if (!strncmp(p, ""); - } - } - else - { - // weird.. one of the above should be correct. - fprintf(outfile, "It would appear that the free online dictionary has changed their format.\n" - "Sorry, but you might need a webrowser instead.\n\n" - "See http://www.thefreedictionary.com/%s", arg); - goto end; - } - } - -end: - fclose(infile); - - fprintf(outfile, "~"); - fclose(outfile); -} - -/* get_line reads the next non-blank line off of the input stream. - * The newline character is removed from the input. - */ -int get_line(FILE * fl, char *buf) -{ - char temp[MEM_USE]; - - do { - fgets(temp, MEM_USE, fl); - if (*temp) - temp[strlen(temp) - 1] = '\0'; - } while (!feof(fl) && !*temp); - - if (feof(fl)) - return (0); - else { - strcpy(buf, temp); - return (1); - } -} - -/* - * Function to skip over the leading spaces of a string. - */ -void skip_spaces(char **string) -{ - for (; **string && isspace(**string); (*string)++); -} From f1794521cf967b41e6bc3796fe0e2173ab7fa6c1 Mon Sep 17 00:00:00 2001 From: Thomas Arp <357770+welcor@users.noreply.github.com> Date: Wed, 2 Jul 2025 22:21:14 +0200 Subject: [PATCH 15/19] Feature/issue 141 immort where (#142) * perform_immort_where and print_object_location rewritten to handle paging. Fixes #141 * A little more info in immort where now we have more space for output. Fixes #141 * Added PRF_VERBOSE for toggling long output in where command. Fixes #141 * Also toggle headers in `where x` depending on verbose-pref. Fixes #141 --- src/act.informative.c | 137 ++++++++++++++++++++++++++++++++---------- src/prefedit.c | 30 +++++++-- src/structs.h | 5 +- 3 files changed, 134 insertions(+), 38 deletions(-) diff --git a/src/act.informative.c b/src/act.informative.c index a44ba72..3715691 100644 --- a/src/act.informative.c +++ b/src/act.informative.c @@ -46,10 +46,10 @@ static void list_obj_to_char(struct obj_data *list, struct char_data *ch, int mo static void show_obj_to_char(struct obj_data *obj, struct char_data *ch, int mode); static void show_obj_modifiers(struct obj_data *obj, struct char_data *ch); /* do_where utility functions */ -static void perform_immort_where(struct char_data *ch, char *arg); +static void perform_immort_where(char_data *ch, const char *arg); static void perform_mortal_where(struct char_data *ch, char *arg); -static void print_object_location(int num, struct obj_data *obj, struct char_data *ch, int recur); - +static size_t print_object_location(int num, const obj_data *obj, const char_data *ch, + char *buf, size_t len, size_t buf_size, int recur); /* Subcommands */ /* For show_obj_to_char 'mode'. /-- arbitrary */ #define SHOW_OBJ_LONG 0 @@ -1603,41 +1603,71 @@ static void perform_mortal_where(struct char_data *ch, char *arg) } } -static void print_object_location(int num, struct obj_data *obj, struct char_data *ch, - int recur) +static size_t print_object_location(const int num, const obj_data *obj, const char_data *ch, // NOLINT(*-no-recursion) + char *buf, size_t len, const size_t buf_size, const int recur) { + size_t nlen = 0; + if (num > 0) - send_to_char(ch, "O%3d. %-25s%s - ", num, obj->short_description, QNRM); + nlen = snprintf(buf + len, buf_size - len, "O%4d. %-25s%s - ", num, obj->short_description, QNRM); else - send_to_char(ch, "%33s", " - "); + nlen = snprintf(buf + len, buf_size - len, "%37s", " - "); + + len += nlen; + nlen = 0; + if (len > buf_size) + return len; // let the caller know we overflowed if (SCRIPT(obj)) { if (!TRIGGERS(SCRIPT(obj))->next) - send_to_char(ch, "[T%d] ", GET_TRIG_VNUM(TRIGGERS(SCRIPT(obj)))); + nlen = snprintf(buf + len, buf_size - len, "[T%d] ", GET_TRIG_VNUM(TRIGGERS(SCRIPT(obj)))); else - send_to_char(ch, "[TRIGS] "); + nlen = snprintf(buf + len, buf_size - len, "[TRIGS] "); } + len += nlen; + if (len > buf_size) + return len; // let the caller know we overflowed + if (IN_ROOM(obj) != NOWHERE) - send_to_char(ch, "[%5d] %s%s\r\n", GET_ROOM_VNUM(IN_ROOM(obj)), world[IN_ROOM(obj)].name, QNRM); - else if (obj->carried_by) - send_to_char(ch, "carried by %s%s\r\n", PERS(obj->carried_by, ch), QNRM); - else if (obj->worn_by) - send_to_char(ch, "worn by %s%s\r\n", PERS(obj->worn_by, ch), QNRM); - else if (obj->in_obj) { - send_to_char(ch, "inside %s%s%s\r\n", obj->in_obj->short_description, QNRM, (recur ? ", which is" : " ")); - if (recur) - print_object_location(0, obj->in_obj, ch, recur); + nlen = snprintf(buf + len, buf_size - len, "[%5d] %s%s\r\n", GET_ROOM_VNUM(IN_ROOM(obj)), world[IN_ROOM(obj)].name, QNRM); + else if (obj->carried_by) { + if (PRF_FLAGGED(ch, PRF_SHOWVNUMS)) + nlen = snprintf(buf + len, buf_size - len, "carried by [%5d] %s%s\r\n", GET_MOB_VNUM(obj->carried_by), PERS(obj->carried_by, ch), QNRM); + else + nlen = snprintf(buf + len, buf_size - len, "carried by %s%s\r\n", PERS(obj->carried_by, ch), QNRM); + if (PRF_FLAGGED(ch, PRF_VERBOSE) && IN_ROOM(obj->carried_by) != NOWHERE && len + nlen < buf_size) + nlen += snprintf(buf + len + nlen, buf_size - len - nlen, "%37sin [%5d] %s%s\r\n", " - ", GET_ROOM_VNUM(IN_ROOM(obj->carried_by)), world[IN_ROOM(obj->carried_by)].name, QNRM); + } else if (obj->worn_by) { + if (PRF_FLAGGED(ch, PRF_SHOWVNUMS)) + nlen = snprintf(buf + len, buf_size - len, "worn by [%5d] %s%s\r\n", GET_MOB_VNUM(obj->worn_by), PERS(obj->worn_by, ch), QNRM); + else + nlen = snprintf(buf + len, buf_size - len, "worn by %s%s\r\n", PERS(obj->worn_by, ch), QNRM); + if (PRF_FLAGGED(ch, PRF_VERBOSE) && IN_ROOM(obj->worn_by) != NOWHERE && len + nlen < buf_size) + nlen += snprintf(buf + len + nlen, buf_size - len - nlen, "%37sin [%5d] %s%s\r\n", " - ", GET_ROOM_VNUM(IN_ROOM(obj->worn_by)), world[IN_ROOM(obj->worn_by)].name, QNRM); + } else if (obj->in_obj) { + nlen = snprintf(buf + len, buf_size - len, "inside %s%s%s\r\n", obj->in_obj->short_description, QNRM, (recur ? ", which is" : " ")); + if (recur && nlen + len < buf_size) { + len += nlen; + nlen = 0; + len = print_object_location(0, obj->in_obj, ch, buf, len, buf_size, recur); + } } else - send_to_char(ch, "in an unknown location\r\n"); + nlen = snprintf(buf + len, buf_size - len, "in an unknown location\r\n"); + len += nlen; + return len; } -static void perform_immort_where(struct char_data *ch, char *arg) +static void perform_immort_where(char_data *ch, const char *arg) { - struct char_data *i; - struct obj_data *k; + char_data *i; + obj_data *k; struct descriptor_data *d; - int num = 0, found = 0; + int num = 0, found = FALSE; // "num" here needs to match the lookup in do_stat, so "stat 4.sword" finds the right one + const char *error_message = "\r\n***OVERFLOW***\r\n"; + char buf[MAX_STRING_LENGTH]; + size_t len = 0, nlen = 0; + const size_t buf_size = sizeof(buf) - strlen(error_message) - 1; if (!*arg) { send_to_char(ch, "Players Room Location Zone\r\n"); @@ -1658,26 +1688,64 @@ static void perform_immort_where(struct char_data *ch, char *arg) } } } else { + if (PRF_FLAGGED(ch, PRF_VERBOSE)) + len = snprintf(buf, buf_size, " ### Mob name - Room # Room name\r\n"); + for (i = character_list; i; i = i->next) if (CAN_SEE(ch, i) && IN_ROOM(i) != NOWHERE && isname(arg, i->player.name)) { found = 1; - send_to_char(ch, "M%3d. %-25s%s - [%5d] %-25s%s", ++num, GET_NAME(i), QNRM, + nlen = snprintf(buf + len, buf_size - len, "M%4d. %-25s%s - [%5d] %-25s%s", ++num, GET_NAME(i), QNRM, GET_ROOM_VNUM(IN_ROOM(i)), world[IN_ROOM(i)].name, QNRM); + if (len + nlen >= buf_size) { + len += snprintf(buf + len, buf_size - len, "%s", error_message); + break; + } + len += nlen; if (SCRIPT(i) && TRIGGERS(SCRIPT(i))) { if (!TRIGGERS(SCRIPT(i))->next) - send_to_char(ch, "[T%d] ", GET_TRIG_VNUM(TRIGGERS(SCRIPT(i)))); + nlen = snprintf(buf + len, buf_size - len, "[T%d]", GET_TRIG_VNUM(TRIGGERS(SCRIPT(i)))); else - send_to_char(ch, "[TRIGS] "); + nlen = snprintf(buf + len, buf_size - len, "[TRIGS]"); + + if (len + nlen >= buf_size) { + snprintf(buf + len, buf_size - len, "%s", error_message); + break; + } + len += nlen; } - send_to_char(ch, "%s\r\n", QNRM); + nlen = snprintf(buf + len, buf_size - len, "%s\r\n", QNRM); + if (len + nlen >= buf_size) { + snprintf(buf + len, buf_size - len, "%s", error_message); + break; + } + len += nlen; } - for (num = 0, k = object_list; k; k = k->next) - if (CAN_SEE_OBJ(ch, k) && isname(arg, k->name)) { - found = 1; - print_object_location(++num, k, ch, TRUE); + + if (PRF_FLAGGED(ch, PRF_VERBOSE) && len < buf_size) { + nlen = snprintf(buf + len, buf_size - len, " ### Object name Location\r\n"); + if (len + nlen >= buf_size) { + snprintf(buf + len, buf_size - len, "%s", error_message); } + len += nlen; + } + + if (len < buf_size) { + for (k = object_list; k; k = k->next) { + if (CAN_SEE_OBJ(ch, k) && isname(arg, k->name)) { + found = 1; + len = print_object_location(++num, k, ch, buf, len, buf_size, TRUE); + if (len >= buf_size) { + snprintf(buf + buf_size, sizeof(buf) - buf_size, "%s", error_message); + break; + } + } + } + } + if (!found) send_to_char(ch, "Couldn't find any such thing.\r\n"); + else + page_string(ch->desc, buf, TRUE); } } @@ -1937,6 +2005,9 @@ ACMD(do_toggle) {"pagelength", 0, 0, "\n", "\n"}, {"screenwidth", 0, 0, "\n", "\n"}, {"color", 0, 0, "\n", "\n"}, + {"verbose", PRF_VERBOSE, LVL_IMMORT, + "You will no longer see verbose output in listings.\n", + "You will now see verbose listings.\n"}, {"\n", 0, -1, "\n", "\n"} /* must be last */ }; @@ -1971,7 +2042,8 @@ ACMD(do_toggle) " NoHassle: %-3s " " Holylight: %-3s " " ShowVnums: %-3s\r\n" - " Syslog: %-3s%s ", + " Syslog: %-3s " + " Verbose: %-3s%s ", ONOFF(PRF_FLAGGED(ch, PRF_BUILDWALK)), ONOFF(PRF_FLAGGED(ch, PRF_NOWIZ)), @@ -1980,6 +2052,7 @@ ACMD(do_toggle) ONOFF(PRF_FLAGGED(ch, PRF_HOLYLIGHT)), ONOFF(PRF_FLAGGED(ch, PRF_SHOWVNUMS)), types[(PRF_FLAGGED(ch, PRF_LOG1) ? 1 : 0) + (PRF_FLAGGED(ch, PRF_LOG2) ? 2 : 0)], + ONOFF(PRF_FLAGGED(ch, PRF_VERBOSE)), GET_LEVEL(ch) == LVL_IMPL ? "" : "\r\n"); } if (GET_LEVEL(ch) >= LVL_IMPL) { diff --git a/src/prefedit.c b/src/prefedit.c index 35356fb..5fbf95b 100755 --- a/src/prefedit.c +++ b/src/prefedit.c @@ -146,7 +146,8 @@ static void prefedit_disp_main_menu(struct descriptor_data *d) "%sImmortal Preferences\r\n" "%s1%s) Syslog Level %s[%s%8s%s] %s4%s) ClsOLC %s[%s%3s%s]\r\n" "%s2%s) Show Flags %s[%s%3s%s] %s5%s) No WizNet %s[%s%3s%s]\r\n" - "%s3%s) No Hassle %s[%s%3s%s] %s6%s) Holylight %s[%s%3s%s]\r\n", + "%s3%s) No Hassle %s[%s%3s%s] %s6%s) Holylight %s[%s%3s%s]\r\n" + "%s7%s) Verbose %s[%s%3s%s] ", CBWHT(d->character, C_NRM), /* Line 1 - syslog and clsolc */ CBYEL(d->character, C_NRM), CCNRM(d->character, C_NRM), CCCYN(d->character, C_NRM), CCYEL(d->character, C_NRM), @@ -159,12 +160,17 @@ static void prefedit_disp_main_menu(struct descriptor_data *d) /* Line 3 - nohassle and holylight */ CBYEL(d->character, C_NRM), CCNRM(d->character, C_NRM), CCCYN(d->character, C_NRM), CCYEL(d->character, C_NRM), ONOFF(PREFEDIT_FLAGGED(PRF_NOHASSLE)), CCCYN(d->character, C_NRM), CBYEL(d->character, C_NRM), CCNRM(d->character, C_NRM), - CCCYN(d->character, C_NRM), CCYEL(d->character, C_NRM), ONOFF(PREFEDIT_FLAGGED(PRF_HOLYLIGHT)), CCCYN(d->character, C_NRM) + CCCYN(d->character, C_NRM), CCYEL(d->character, C_NRM), ONOFF(PREFEDIT_FLAGGED(PRF_HOLYLIGHT)), CCCYN(d->character, C_NRM), +/* Line 4 - Verbose */ + CBYEL(d->character, C_NRM), CCNRM(d->character, C_NRM), CCCYN(d->character, C_NRM), CCYEL(d->character, C_NRM), + ONOFF(PREFEDIT_FLAGGED(PRF_VERBOSE)), CCCYN(d->character, C_NRM) ); if (GET_LEVEL(PREFEDIT_GET_CHAR) == LVL_IMPL) - send_to_char(d->character, "%s7%s) Zone Resets %s[%s%3s%s]\r\n", + send_to_char(d->character, "%s8%s) Zone Resets %s[%s%3s%s]\r\n", CBYEL(d->character, C_NRM), CCNRM(d->character, C_NRM), CCCYN(d->character, C_NRM), CCYEL(d->character, C_NRM), ONOFF(PREFEDIT_FLAGGED(PRF_ZONERESETS)), CCCYN(d->character, C_NRM)); + else + send_to_char(d->character, "\r\n"); } /* Finishing Off */ @@ -505,7 +511,19 @@ void prefedit_parse(struct descriptor_data * d, char *arg) } break; - case '7': + case '7': + if (GET_LEVEL(PREFEDIT_GET_CHAR) < LVL_IMMORT) + { + send_to_char(d->character, "%sInvalid choice!%s\r\n", CBRED(d->character, C_NRM), CCNRM(d->character, C_NRM)); + prefedit_disp_main_menu(d); + } + else + { + TOGGLE_BIT_AR(PREFEDIT_GET_FLAGS, PRF_VERBOSE); + } + break; + + case '8': if (GET_LEVEL(PREFEDIT_GET_CHAR) < LVL_IMPL) { send_to_char(d->character, "%sInvalid choice!%s\r\n", CBRED(d->character, C_NRM), CCNRM(d->character, C_NRM)); @@ -901,6 +919,10 @@ void prefedit_Restore_Defaults(struct descriptor_data *d) if (PREFEDIT_FLAGGED(PRF_AUTODOOR)) SET_BIT_AR(PREFEDIT_GET_FLAGS, PRF_AUTODOOR); + /* PRF_VERBOSE - On */ + if (PREFEDIT_FLAGGED(PRF_VERBOSE)) + SET_BIT_AR(PREFEDIT_GET_FLAGS, PRF_VERBOSE); + /* Other (non-toggle) options */ PREFEDIT_GET_WIMP_LEV = 0; /* Wimpy off by default */ PREFEDIT_GET_PAGELENGTH = 22; /* Default telnet screen is 22 lines */ diff --git a/src/structs.h b/src/structs.h index 08e47db..8dd7089 100644 --- a/src/structs.h +++ b/src/structs.h @@ -262,9 +262,10 @@ #define PRF_AUTOMAP 31 /**< Show map at the side of room descs */ #define PRF_AUTOKEY 32 /**< Automatically unlock locked doors when opening */ #define PRF_AUTODOOR 33 /**< Use the next available door */ -#define PRF_ZONERESETS 34 +#define PRF_ZONERESETS 34 /**< Show when zones reset */ +#define PRF_VERBOSE 35 /**< Listings like where are more verbose */ /** Total number of available PRF flags */ -#define NUM_PRF_FLAGS 35 +#define NUM_PRF_FLAGS 36 /* Affect bits: used in char_data.char_specials.saved.affected_by */ /* WARNING: In the world files, NEVER set the bits marked "R" ("Reserved") */ From bdaca46e794404d3fd1227f9bc5a85405b119276 Mon Sep 17 00:00:00 2001 From: Thomas Arp <357770+welcor@users.noreply.github.com> Date: Wed, 2 Jul 2025 22:22:17 +0200 Subject: [PATCH 16/19] Added a new trigger type for mobs, called "Damage", that triggers every (#151) time the mob is harmed, through any means. Valid return values: -1: prevents damage from occurring. Will also prevent a fight from starting. 0: forces a miss. >0 : the damage the mob will endure. Available variables: %actor%: the one doing the damage %victim%: typically the same as %self% - the one being attacked %damage%: the damage inflicted. Always a non-negative number. %attacktype%: The attack type. Will be UNDEFINED when hitting with a weapon. --- src/constants.c | 1 + src/dg_olc.h | 2 +- src/dg_scripts.h | 2 ++ src/dg_triggers.c | 27 +++++++++++++++++++++++++++ src/fight.c | 5 +++++ 5 files changed, 36 insertions(+), 1 deletion(-) diff --git a/src/constants.c b/src/constants.c index cc6b190..79299dc 100644 --- a/src/constants.c +++ b/src/constants.c @@ -877,6 +877,7 @@ const char *trig_types[] = { "Door", "UNUSED", "Time", + "Damage", "\n" }; diff --git a/src/dg_olc.h b/src/dg_olc.h index 82098c5..ecb4e81 100644 --- a/src/dg_olc.h +++ b/src/dg_olc.h @@ -16,7 +16,7 @@ #include "dg_scripts.h" -#define NUM_TRIG_TYPE_FLAGS 20 +#define NUM_TRIG_TYPE_FLAGS 21 /* Submodes of TRIGEDIT connectedness. */ #define TRIGEDIT_MAIN_MENU 0 diff --git a/src/dg_scripts.h b/src/dg_scripts.h index 34434b1..7021957 100644 --- a/src/dg_scripts.h +++ b/src/dg_scripts.h @@ -71,6 +71,7 @@ #define MTRIG_DOOR (1 << 17) /* door manipulated in room */ #define MTRIG_TIME (1 << 19) /* trigger based on game hour */ +#define MTRIG_DAMAGE (1 << 20) /* trigger whenever mob is damaged */ /* obj trigger types */ #define OTRIG_GLOBAL (1 << 0) /* unused */ @@ -264,6 +265,7 @@ void time_wtrigger(room_data *room); int login_wtrigger(struct room_data *room, char_data *actor); +int damage_mtrigger(char_data *ch, char_data *victim, int dam, int attacktype); /* function prototypes from dg_scripts.c */ ACMD(do_attach) ; ACMD(do_detach); diff --git a/src/dg_triggers.c b/src/dg_triggers.c index 5a54d17..7cea1ad 100644 --- a/src/dg_triggers.c +++ b/src/dg_triggers.c @@ -554,6 +554,33 @@ int cast_mtrigger(char_data *actor, char_data *ch, int spellnum) return 1; } +int damage_mtrigger(char_data *actor, char_data *victim, int dam, int attacktype) +{ + trig_data *t; + char buf[MAX_INPUT_LENGTH]; + + if (victim == NULL) + return dam; + + if (!SCRIPT_CHECK(victim, MTRIG_DAMAGE) || AFF_FLAGGED(victim, AFF_CHARM)) + return dam; + + for (t = TRIGGERS(SCRIPT(victim)); t; t = t->next) { + if (TRIGGER_CHECK(t, MTRIG_DAMAGE) && + (rand_number(1, 100) <= GET_TRIG_NARG(t))) { + ADD_UID_VAR(buf, t, char_script_id(actor), "actor", 0); + ADD_UID_VAR(buf, t, char_script_id(victim), "victim", 0); + sprintf(buf, "%d", dam); + add_var(&GET_TRIG_VARS(t), "damage", buf, 0); + add_var(&GET_TRIG_VARS(t), "attacktype", skill_name(attacktype), 0); + return script_driver(&victim, t, MOB_TRIGGER, TRIG_NEW); + } + } + + return dam; +} + + int leave_mtrigger(char_data *actor, int dir) { trig_data *t; diff --git a/src/fight.c b/src/fight.c index e4b74b5..e823eb9 100644 --- a/src/fight.c +++ b/src/fight.c @@ -620,6 +620,11 @@ int damage(struct char_data *ch, struct char_data *victim, int dam, int attackty if (!IS_NPC(victim) && ((GET_LEVEL(victim) >= LVL_IMMORT) && PRF_FLAGGED(victim, PRF_NOHASSLE))) dam = 0; + dam = damage_mtrigger(ch, victim, dam, attacktype); + if (dam == -1) { + return (0); + } + if (victim != ch) { /* Start the attacker fighting the victim */ if (GET_POS(ch) > POS_STUNNED && (FIGHTING(ch) == NULL)) From b9d84fc325bc1a5fa456e1ac1c76e18eb423e1c3 Mon Sep 17 00:00:00 2001 From: Thomas Arp <357770+welcor@users.noreply.github.com> Date: Wed, 2 Jul 2025 22:22:36 +0200 Subject: [PATCH 17/19] Make sure %target% also works in act triggers and code cleanup (#152) * Make sure %target% works in act triggers * code cleanup. Remove inline block, make variable names more understandable. Ref https://www.tbamud.com/forum/4-development/4525-confused-over-piece-of-code-in-parse-room From 3e0c1ccc186bfd59c8c8f05bbca595c4b15f9bd7 Mon Sep 17 00:00:00 2001 From: Thomas Arp <357770+welcor@users.noreply.github.com> Date: Wed, 2 Jul 2025 22:23:10 +0200 Subject: [PATCH 18/19] Support cmake (#153) * First cmake list file, simple docs. TODO: utils folder. * Support for building utils * All fields except HAVE_DOPRNT in place * Now builds and runs :) --- .gitignore | 2 - CMakeLists.txt | 396 +++++++++++++++++++++++++ build/create_solution.bat | 1 - doc/README.CMAKE.md | 93 ++++++ build/README.md => doc/README.MSVC2022 | 34 ++- src/conf.h.cmake.in | 337 +++++++++++++++++++++ src/util/CMakeLists.txt | 46 +++ 7 files changed, 892 insertions(+), 17 deletions(-) create mode 100644 CMakeLists.txt delete mode 100644 build/create_solution.bat create mode 100644 doc/README.CMAKE.md rename build/README.md => doc/README.MSVC2022 (60%) create mode 100644 src/conf.h.cmake.in create mode 100644 src/util/CMakeLists.txt diff --git a/.gitignore b/.gitignore index e3e03a9..4611369 100644 --- a/.gitignore +++ b/.gitignore @@ -11,8 +11,6 @@ src/.accepted src/depend src/util/depend build/* -!build/create_solution.bat -!build/README.md # Do not commit files from players lib/plrfiles/A-E/* diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..9fa9a76 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,396 @@ +cmake_minimum_required(VERSION 3.12) +project(TbaMUD C) + +set(CMAKE_C_STANDARD 99) + +# Include checker modules +include(CheckFunctionExists) +include(CheckIncludeFile) +include(CheckTypeSize) +include(CheckStructHasMember) +include(CheckSymbolExists) +include(CheckCSourceCompiles) + +# Output paths +set(BIN_OUTPUT_DIR ${CMAKE_SOURCE_DIR}/bin) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${BIN_OUTPUT_DIR}) + +# Include source and build paths +include_directories(src ${CMAKE_BINARY_DIR}) + +# ========== Compiler flags ========== +if (CMAKE_COMPILER_IS_GNUCC) + include(CheckCCompilerFlag) + + check_c_compiler_flag(-Wall SUPPORTS_WALL) + check_c_compiler_flag(-Wno-char-subscripts SUPPORTS_WNO_CHAR_SUBSCRIPTS) + + if (SUPPORTS_WALL) + set(MYFLAGS "-Wall") + if (SUPPORTS_WNO_CHAR_SUBSCRIPTS) + set(MYFLAGS "${MYFLAGS} -Wno-char-subscripts") + endif() + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${MYFLAGS}") + endif() +endif() + +# ========== Header checks ========== +check_include_file("fcntl.h" HAVE_FCNTL_H) +check_include_file("errno.h" HAVE_ERRNO_H) +check_include_file("string.h" HAVE_STRING_H) +check_include_file("strings.h" HAVE_STRINGS_H) +check_include_file("limits.h" HAVE_LIMITS_H) +check_include_file("sys/select.h" HAVE_SYS_SELECT_H) +check_include_file("sys/wait.h" HAVE_SYS_WAIT_H) +check_include_file("sys/types.h" HAVE_SYS_TYPES_H) +check_include_file("unistd.h" HAVE_UNISTD_H) +check_include_file("memory.h" HAVE_MEMORY_H) +check_include_file("assert.h" HAVE_ASSERT_H) +check_include_file("arpa/telnet.h" HAVE_ARPA_TELNET_H) +check_include_file("arpa/inet.h" HAVE_ARPA_INET_H) +check_include_file("sys/stat.h" HAVE_SYS_STAT_H) +check_include_file("sys/socket.h" HAVE_SYS_SOCKET_H) +check_include_file("sys/resource.h" HAVE_SYS_RESOURCE_H) +check_include_file("netinet/in.h" HAVE_NETINET_IN_H) +check_include_file("netdb.h" HAVE_NETDB_H) +check_include_file("signal.h" HAVE_SIGNAL_H) +check_include_file("sys/uio.h" HAVE_SYS_UIO_H) +check_include_file("mcheck.h" HAVE_MCHECK_H) +check_include_file("stdlib.h" HAVE_STDLIB_H) +check_include_file("stdarg.h" HAVE_STDARG_H) +check_include_file("float.h" HAVE_FLOAT_H) + +if (HAVE_STDLIB_H AND HAVE_STDARG_H AND HAVE_STRING_H AND HAVE_FLOAT_H) + set(STDC_HEADERS 1) +endif() + +# macros +macro(check_run_return_value CODE EXPECTED_RESULT VAR_NAME) + set(_file "${CMAKE_BINARY_DIR}/check_run_${VAR_NAME}.c") + file(WRITE "${_file}" "${CODE}") + try_run(_run_result _compile_result + ${CMAKE_BINARY_DIR} ${_file} + ) + if (_compile_result EQUAL 0 AND _run_result EQUAL ${EXPECTED_RESULT}) + set(${VAR_NAME} TRUE) + else() + set(${VAR_NAME} FALSE) + endif() +endmacro() + +# ========== Function checks ========== +foreach(FUNC gettimeofday select snprintf strcasecmp strdup strerror + stricmp strlcpy strncasecmp strnicmp strstr vsnprintf vprintf + inet_addr inet_aton) + string(TOUPPER "${FUNC}" _upper_name) + check_function_exists(${FUNC} HAVE_${_upper_name}) +endforeach() + +if (NOT HAVE_VPRINTF) + check_function_exists(_doprnt HAVE_DOPRNT) +endif() + + +# ========== Type checks ========== +check_type_size("pid_t" HAVE_PID_T) +check_type_size("size_t" HAVE_SIZE_T) +check_type_size("ssize_t" HAVE_SSIZE_T) +set(CMAKE_EXTRA_INCLUDE_FILES "sys/socket.h") +check_type_size("socklen_t" HAVE_SOCKLEN_T) +unset(CMAKE_EXTRA_INCLUDE_FILES) + + +if (NOT HAVE_PID_T) + set(pid_t int) +endif() + +if (NOT HAVE_SIZE_T) + set(size_t "unsigned") +endif() + +if (NOT HAVE_SSIZE_T) + set(ssize_t int) +endif() + +if (NOT HAVE_SOCKLEN_T) + set(socklen_t int) +endif() + +# ========== const ========== +check_c_source_compiles(" +int main() { + +/* Ultrix mips cc rejects this. */ +typedef int charset[2]; const charset x; +/* SunOS 4.1.1 cc rejects this. */ +char const *const *ccp; +char **p; +/* NEC SVR4.0.2 mips cc rejects this. */ +struct point {int x, y;}; +static struct point const zero = {0,0}; +/* AIX XL C 1.02.0.0 rejects this. + It does not let you subtract one const X* pointer from another in an arm + of an if-expression whose if-part is not a constant expression */ +const char *g = \"string\"; +ccp = &g + (g ? g-g : 0); +/* HPUX 7.0 cc rejects these. */ +++ccp; +p = (char**) ccp; +ccp = (char const *const *) p; +{ /* SCO 3.2v4 cc rejects this. */ + char *t; + char const *s = 0 ? (char *) 0 : (char const *) 0; + + *t++ = 0; +} +{ /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */ + int x[] = {25, 17}; + const int *foo = &x[0]; + ++foo; +} +{ /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */ + typedef const int *iptr; + iptr p = 0; + ++p; +} +{ /* AIX XL C 1.02.0.0 rejects this saying + \"k.c\", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */ + struct s { int j; const int *ap[3]; }; + struct s *b; b->j = 5; +} +{ /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ + const int foo = 10; +} + +; return 0; } +" HAVE_CONST) + +if (HAVE_CONST) + set(CONST_KEYWORD const) +else() + set(CONST_KEYWORD "") +endif() + +# ========== Struct checks ========== +if (HAVE_NETINET_IN_H) + check_struct_has_member("struct in_addr" s_addr netinet/in.h HAVE_STRUCT_IN_ADDR) +endif() + +# ========== crypt()/libcrypt ========== + +find_library(CRYPT_LIBRARY crypt) +if (CRYPT_LIBRARY) + message(STATUS "Found libcrypt: ${CRYPT_LIBRARY}") + list(APPEND EXTRA_LIBS ${CRYPT_LIBRARY}) + set(_saved_lib_list ${CMAKE_REQUIRED_LIBRARIES}) + set(CMAKE_REQUIRED_LIBRARIES ${CRYPT_LIBRARY}) + check_include_file("crypt.h" HAVE_CRYPT_H) + check_function_exists(crypt CIRCLE_CRYPT) + + check_run_return_value(" +#include +#include +${HAVE_CRYPT_H} ? \"#include \" : \"\" + +int main(void) +{ + char pwd[11], pwd2[11]; + + strncpy(pwd, (char *)crypt(\"FooBar\", \"BazQux\"), 10); + pwd[10] = '\\\\0'; + strncpy(pwd2, (char *)crypt(\"xyzzy\", \"BazQux\"), 10); + pwd2[10] = '\\\\0'; + if (strcmp(pwd, pwd2) == 0) + exit(0); + exit(1); +} + " 0 HAVE_UNSAFE_CRYPT) + + set(CMAKE_REQUIRED_LIBRARIES ${_saved_lib_list}) +endif() + + +# ========== network libs ========== +check_function_exists(gethostbyaddr HAVE_GETHOSTBYADDR) +if (NOT HAVE_GETHOSTBYADDR) + message(STATUS "gethostbyaddr() not available, trying nsllib") + find_library(NSL_LIBRARY nsl) + if (NSL_LIBRARY) + message(STATUS "...nsllib found.") + list(APPEND EXTRA_LIBS ${NSL_LIBRARY}) + endif() +endif() + +check_function_exists(socket HAVE_SOCKET) +if (NOT HAVE_SOCKET) + message(STATUS "socket() not available, trying socketlib") + find_library(SOCKET_LIBRARY socket) + if (SOCKET_LIBRARY) + message(STATUS "...socketlib found") + list(APPEND EXTRA_LIBS ${SOCKET_LIBRARY}) + endif() +endif() + +# ========== time.h needs special treatment ========== +check_include_file("sys/time.h" HAVE_SYS_TIME_H) +check_include_file("sys/time.h" HAVE_TIME_H) + +if (HAVE_SYS_TIME_H AND HAVE_TIME_H) + check_c_source_compiles(" +#include +#include +#include +int main() { +struct tm *tp; +; return 0; } + " TIME_WITH_SYS_TIME) +endif() + +# ========== Determine return value of signal() ========== +check_c_source_compiles(" + #include + int handler(int sig) { return 0; } + int main() { + signal(SIGINT, handler); + return 1; + } +" SIGNAL_RETURNS_INT FAIL_REGEX ".*incompatible pointer type.*") + +check_c_source_compiles(" + #include + void handler(int sig) { } + int main() { + signal(SIGINT, handler); + return 1; + } +" SIGNAL_RETURNS_VOID FAIL_REGEX ".*incompatible pointer type.*") + +if (SIGNAL_RETURNS_INT) + message(STATUS "signal() returns int.") + set(RETSIGTYPE int) +elseif (SIGNAL_RETURNS_VOID) + message(STATUS "signal() returns void.") + set(RETSIGTYPE void) +else() + message(FATAL_ERROR "Could not determine return value from signal handler.") +endif() + +# ========== Define general UNIX-system ========== +if (UNIX) + set(CIRCLE_UNIX 1) +endif() + +set(PROTO_FUNCTIONS + accept + bind + gettimeofday + atoi + atol + bzero + chdir + close + fclose + fcntl + fflush + fprintf + fputc + fread + fscanf + fseek + fwrite + getpeername + getpid + getrlimit + getsockname + htonl + htons + inet_addr + inet_aton + inet_ntoa + listen + ntohl + perror + printf + qsort + read + remove + rewind + select + setitimer + setrlimit + setsockopt + snprintf + sprintf + sscanf + strcasecmp + strdup + strerror + stricmp + strlcpy + strncasecmp + strnicmp + system + time + unlink + vsnprintf + write + socket +) + +configure_file( + ${CMAKE_SOURCE_DIR}/src/conf.h.cmake.in + ${CMAKE_BINARY_DIR}/tmp_conf.h +) + +macro(check_function_prototype FUNCTION) + set(_code " +#define NO_LIBRARY_PROTOTYPES +#define __COMM_C__ +#define __ACT_OTHER_C__ +#include \"${CMAKE_BINARY_DIR}/tmp_conf.h\" +#include \"${CMAKE_SOURCE_DIR}/src/sysdep.h\" +#ifdef ${FUNCTION} + error - already defined! +#endif +void ${FUNCTION}(int a, char b, int c, char d, int e, char f, int g, char h); + +int main() { + +; return 0; } + ") + string(TOUPPER "${FUNCTION}" _upper_name) + check_c_source_compiles("${_code}" NEED_${_upper_name}_PROTO FAIL_REGEX ".*incompatible pointer type.*") + if (NEED_${_upper_name}_PROTO) + message(STATUS "${FUNCTION}() has no prototype, NEED_${_upper_name}_PROTO set!") + else() + message(STATUS "${FUNCTION}() has a prototype, not setting NEED_${_upper_name}_PROTO") + endif() +endmacro() + + +foreach (FUNC ${PROTO_FUNCTIONS}) + check_function_prototype(${FUNC}) +endforeach() + + +# ========== Generate conf.h ========== +configure_file( + ${CMAKE_SOURCE_DIR}/src/conf.h.cmake.in + ${CMAKE_BINARY_DIR}/conf.h +) + + + +# ========== Source-filer ========== +file(GLOB SRC_FILES src/*.c) + +# ========== Bygg kjørbar ========== +add_executable(circle ${SRC_FILES}) +target_link_libraries(circle ${EXTRA_LIBS}) + +add_subdirectory(src/util) + +if (MEMORY_DEBUG) + message(STATUS "MEMORY_DEBUG is activated, setting up zmalloc") + target_compile_definitions(circle PRIVATE MEMORY_DEBUG) +endif() diff --git a/build/create_solution.bat b/build/create_solution.bat deleted file mode 100644 index ab60043..0000000 --- a/build/create_solution.bat +++ /dev/null @@ -1 +0,0 @@ -cmake -B . -S ..\src -G "Visual Studio 17 2022" \ No newline at end of file diff --git a/doc/README.CMAKE.md b/doc/README.CMAKE.md new file mode 100644 index 0000000..0408e2a --- /dev/null +++ b/doc/README.CMAKE.md @@ -0,0 +1,93 @@ +Updated 2025-04 + +## Building TbaMUD with the cmake tool + +# Building with CMake + +This document describes how to configure, build and install tbamud +from source code using the CMake build tool. To build with CMake, you of +course first have to install CMake. The minimum required version of CMake is +specified in the file `CMakeLists.txt` found in the top of the tbamud source +tree. Once the correct version of CMake is installed you can follow the +instructions below for the platform you are building on. + +CMake builds can be configured either from the command line, or from one of +CMake's GUIs. + +NOTE: The current CMakeLists.txt only supports linux. + +# Configuring + +A CMake configuration of tbamud is similar to the autotools build of curl. +It consists of the following steps after you have unpacked the source. + +We recommend building with CMake on Windows. + +## Using `cmake` + +You can configure for in source tree builds or for a build tree +that is apart from the source tree. + +- Build in a separate directory (parallel to the source tree in this + example). The build directory is created for you. This is recommended over + building in the source tree to separate source and build artifacts. + +```shell +$ cmake -B build -S . +``` + +- Build in the source tree. Not recommended. + +```shell +$ cmake -B . +``` + +The examples below will assume you have created a build folder. + +The above commands will generate the build files. If you need to regenerate +the files, you can delete the cmake cache file, and rerun the above command: + +```shell +$ rm build/CMakeCache.txt +``` + +Once the build files are generated, the build is run with cmake + +```shell +$ cmake --build build +``` + +This will generate the object files in a subdirectory under the specified +build folder and link the executable. The resulting binaries will be in the +bin/ folder. + +### Utilities + +It is possible to build only single tools, none or all of them, +by specifying the target in the build command: + +```shell +# only build the mud +$ cmake --build build --target circle + +# only build tools +$ cmake --build build --target utils + +# only build one tool +$ cmake --build build --target wld2html +``` + +### Debugging memory + +In case you want to run the mud with memory debugging turned on, you +can set the MEMORY_DEBUG flag during configuration by specifying the +flag: + +```shell +$ cmake -B build -S . -DMEMORY_DEBUG:int=1 +$ cmake --build build +``` + +When the mud is shut down, the zmalloc code will identify any leaks in your code. +Note that memory debugging may consume quite a lot of memory and take some time +to be handled on shutdown. \ No newline at end of file diff --git a/build/README.md b/doc/README.MSVC2022 similarity index 60% rename from build/README.md rename to doc/README.MSVC2022 index bd84d9a..7cca485 100644 --- a/build/README.md +++ b/doc/README.MSVC2022 @@ -1,15 +1,21 @@ -### Overview -This guide describes how to build TbaMUD in the Visual Studio through the new experimental CMake environment. - -### Prerequisites -* [Visual Studio 2022+](https://visualstudio.microsoft.com/ru/vs/) -* [CMake 3.27+](https://cmake.org/) - -### Build Steps -1. Goto the folder `src` and copy `conf.h.win` to `conf.h`. - -2. Goto the folder `build` and execute `create_solution.bat`. - -3. Open `build/circle.sln` in Visual Studio. - +Updated: Apr 2025 + Compiling CircleMUD under Microsoft Windows XP + using Microsoft Visual C++ 2022 (8.0) + +### Overview +This guide describes how to build TbaMUD in the Visual Studio through the new experimental CMake environment. + +### Prerequisites +* [Visual Studio 2022+](https://visualstudio.microsoft.com/ru/vs/) +* [CMake 3.27+](https://cmake.org/) + +### Build Steps +1. Goto the folder `src` and copy `conf.h.win` to `conf.h`. + +2. Run this command in the root folder: + + cmake -B build -S . -G "Visual Studio 17 2022" + +3. Open `build/circle.sln` in Visual Studio. + 4. Compile and run. \ No newline at end of file diff --git a/src/conf.h.cmake.in b/src/conf.h.cmake.in new file mode 100644 index 0000000..541d14c --- /dev/null +++ b/src/conf.h.cmake.in @@ -0,0 +1,337 @@ +/* src/conf.h.cmake.in. Used as basis for conf.h when building with cmake */ + +#ifndef _CONF_H_ +#define _CONF_H_ + +/* Define to empty if the keyword does not work. */ +#define const @CONST_KEYWORD@ + +/* Define if you don't have vprintf but do have _doprnt. */ +#cmakedefine HAVE_DOPRNT + +/* Define if you have that is POSIX.1 compatible. */ +#cmakedefine HAVE_SYS_WAIT_H + +/* Define if you have the vprintf function. */ +#cmakedefine HAVE_VPRINTF + +/* Define to `int' if doesn't define. */ +#cmakedefine pid_t @pid_t@ + +/* Define as the return type of signal handlers (int or void). */ +#define RETSIGTYPE @RETSIGTYPE@ + +/* Define to `unsigned' if doesn't define. */ +#cmakedefine size_t @size_t@ + +/* Define if you have the ANSI C header files. */ +#cmakedefine STDC_HEADERS + +/* Define if you can safely include both and . */ +#cmakedefine TIME_WITH_SYS_TIME + +/* Define if we're compiling CircleMUD under any type of UNIX system. */ +#cmakedefine CIRCLE_UNIX + +/* Define if the system is capable of using crypt() to encrypt. */ +#cmakedefine CIRCLE_CRYPT + +/* Define if we don't have proper support for the system's crypt(). */ +#cmakedefine HAVE_UNSAFE_CRYPT + +/* Define is the system has struct in_addr. */ +#cmakedefine HAVE_STRUCT_IN_ADDR + +/* Define to `int' if doesn't define. */ +#cmakedefine socklen_t @socklen_t@ + +/* Define to `int' if doesn't define. */ +#cmakedefine ssize_t @ssize_t@ + +/* Define if you have the gettimeofday function. */ +#cmakedefine HAVE_GETTIMEOFDAY + +/* Define if you have the inet_addr function. */ +#cmakedefine HAVE_INET_ADDR + +/* Define if you have the inet_aton function. */ +#cmakedefine HAVE_INET_ATON + +/* Define if you have the select function. */ +#cmakedefine HAVE_SELECT + +/* Define if you have the snprintf function. */ +#cmakedefine HAVE_SNPRINTF + +/* Define if you have the strcasecmp function. */ +#cmakedefine HAVE_STRCASECMP + +/* Define if you have the strdup function. */ +#cmakedefine HAVE_STRDUP + +/* Define if you have the strerror function. */ +#cmakedefine HAVE_STRERROR + +/* Define if you have the stricmp function. */ +#cmakedefine HAVE_STRICMP + +/* Define if you have the strlcpy function. */ +#cmakedefine HAVE_STRLCPY + +/* Define if you have the strncasecmp function. */ +#cmakedefine HAVE_STRNCASECMP + +/* Define if you have the strnicmp function. */ +#cmakedefine HAVE_STRNICMP + +/* Define if you have the strstr function. */ +#cmakedefine HAVE_STRSTR + +/* Define if you have the vsnprintf function. */ +#cmakedefine HAVE_VSNPRINTF + +/* Define if you have the header file. */ +#cmakedefine HAVE_ARPA_INET_H + +/* Define if you have the header file. */ +#cmakedefine HAVE_ARPA_TELNET_H + +/* Define if you have the header file. */ +#cmakedefine HAVE_ASSERT_H + +/* Define if you have the header file. */ +#cmakedefine HAVE_CRYPT_H + +/* Define if you have the header file. */ +#cmakedefine HAVE_ERRNO_H + +/* Define if you have the header file. */ +#cmakedefine HAVE_FCNTL_H + +/* Define if you have the header file. */ +#cmakedefine HAVE_LIMITS_H + +/* Define if you have the header file. */ +#cmakedefine HAVE_MCHECK_H + +/* Define if you have the header file. */ +#cmakedefine HAVE_MEMORY_H + +/* Define if you have the header file. */ +#cmakedefine HAVE_NET_ERRNO_H + +/* Define if you have the header file. */ +#cmakedefine HAVE_NETDB_H + +/* Define if you have the header file. */ +#cmakedefine HAVE_NETINET_IN_H + +/* Define if you have the header file. */ +#cmakedefine HAVE_SIGNAL_H + +/* Define if you have the header file. */ +#cmakedefine HAVE_STRING_H + +/* Define if you have the header file. */ +#cmakedefine HAVE_STRINGS_H + +/* Define if you have the header file. */ +#cmakedefine HAVE_SYS_FCNTL_H + +/* Define if you have the header file. */ +#cmakedefine HAVE_SYS_RESOURCE_H + +/* Define if you have the header file. */ +#cmakedefine HAVE_SYS_SELECT_H + +/* Define if you have the header file. */ +#cmakedefine HAVE_SYS_SOCKET_H + +/* Define if you have the header file. */ +#cmakedefine HAVE_SYS_STAT_H + +/* Define if you have the header file. */ +#cmakedefine HAVE_SYS_TIME_H + +/* Define if you have the header file. */ +#cmakedefine HAVE_SYS_TYPES_H + +/* Define if you have the header file. */ +#cmakedefine HAVE_SYS_UIO_H + +/* Define if you have the header file. */ +#cmakedefine HAVE_UNISTD_H + +/* Define if you have the malloc library (-lmalloc). */ +#cmakedefine HAVE_LIBMALLOC + +/* Check for a prototype to accept. */ +#cmakedefine NEED_ACCEPT_PROTO + +/* Check for a prototype to atoi. */ +#cmakedefine NEED_ATOI_PROTO + +/* Check for a prototype to atol. */ +#cmakedefine NEED_ATOL_PROTO + +/* Check for a prototype to bind. */ +#cmakedefine NEED_BIND_PROTO + +/* Check for a prototype to bzero. */ +#cmakedefine NEED_BZERO_PROTO + +/* Check for a prototype to chdir. */ +#cmakedefine NEED_CHDIR_PROTO + +/* Check for a prototype to close. */ +#cmakedefine NEED_CLOSE_PROTO + +/* Check for a prototype to crypt. */ +#cmakedefine NEED_CRYPT_PROTO + +/* Check for a prototype to fclose. */ +#cmakedefine NEED_FCLOSE_PROTO + +/* Check for a prototype to fcntl. */ +#cmakedefine NEED_FCNTL_PROTO + +/* Check for a prototype to fflush. */ +#cmakedefine NEED_FFLUSH_PROTO + +/* Check for a prototype to fprintf. */ +#cmakedefine NEED_FPRINTF_PROTO + +/* Check for a prototype to fputc. */ +#cmakedefine NEED_FPUTC_PROTO + +/* Check for a prototype to fputs. */ +#cmakedefine NEED_FPUTS_PROTO + +/* Check for a prototype to fread. */ +#cmakedefine NEED_FREAD_PROTO + +/* Check for a prototype to fscanf. */ +#cmakedefine NEED_FSCANF_PROTO + +/* Check for a prototype to fseek. */ +#cmakedefine NEED_FSEEK_PROTO + +/* Check for a prototype to fwrite. */ +#cmakedefine NEED_FWRITE_PROTO + +/* Check for a prototype to getpeername. */ +#cmakedefine NEED_GETPEERNAME_PROTO + +/* Check for a prototype to getpid. */ +#cmakedefine NEED_GETPID_PROTO + +/* Check for a prototype to getrlimit. */ +#cmakedefine NEED_GETRLIMIT_PROTO + +/* Check for a prototype to getsockname. */ +#cmakedefine NEED_GETSOCKNAME_PROTO + +/* Check for a prototype to gettimeofday. */ +#cmakedefine NEED_GETTIMEOFDAY_PROTO + +/* Check for a prototype to htonl. */ +#cmakedefine NEED_HTONL_PROTO + +/* Check for a prototype to htons. */ +#cmakedefine NEED_HTONS_PROTO + +/* Check for a prototype to inet_addr. */ +#cmakedefine NEED_INET_ADDR_PROTO + +/* Check for a prototype to inet_aton. */ +#cmakedefine NEED_INET_ATON_PROTO + +/* Check for a prototype to inet_ntoa. */ +#cmakedefine NEED_INET_NTOA_PROTO + +/* Check for a prototype to listen. */ +#cmakedefine NEED_LISTEN_PROTO + +/* Check for a prototype to ntohl. */ +#cmakedefine NEED_NTOHL_PROTO + +/* Check for a prototype to perror. */ +#cmakedefine NEED_PERROR_PROTO + +/* Check for a prototype to printf. */ +#cmakedefine NEED_PRINTF_PROTO + +/* Check for a prototype to qsort. */ +#cmakedefine NEED_QSORT_PROTO + +/* Check for a prototype to read. */ +#cmakedefine NEED_READ_PROTO + +/* Check for a prototype to remove. */ +#cmakedefine NEED_REMOVE_PROTO + +/* Check for a prototype to rewind. */ +#cmakedefine NEED_REWIND_PROTO + +/* Check for a prototype to select. */ +#cmakedefine NEED_SELECT_PROTO + +/* Check for a prototype to setitimer. */ +#cmakedefine NEED_SETITIMER_PROTO + +/* Check for a prototype to setrlimit. */ +#cmakedefine NEED_SETRLIMIT_PROTO + +/* Check for a prototype to setsockopt. */ +#cmakedefine NEED_SETSOCKOPT_PROTO + +/* Check for a prototype to snprintf. */ +#cmakedefine NEED_SNPRINTF_PROTO + +/* Check for a prototype to socket. */ +#cmakedefine NEED_SOCKET_PROTO + +/* Check for a prototype to sprintf. */ +#cmakedefine NEED_SPRINTF_PROTO + +/* Check for a prototype to sscanf. */ +#cmakedefine NEED_SSCANF_PROTO + +/* Check for a prototype to strcasecmp. */ +#cmakedefine NEED_STRCASECMP_PROTO + +/* Check for a prototype to strdup. */ +#cmakedefine NEED_STRDUP_PROTO + +/* Check for a prototype to strerror. */ +#cmakedefine NEED_STRERROR_PROTO + +/* Check for a prototype to stricmp. */ +#cmakedefine NEED_STRICMP_PROTO + +/* Check for a prototype to strlcpy. */ +#cmakedefine NEED_STRLCPY_PROTO + +/* Check for a prototype to strncasecmp. */ +#cmakedefine NEED_STRNCASECMP_PROTO + +/* Check for a prototype to strnicmp. */ +#cmakedefine NEED_STRNICMP_PROTO + +/* Check for a prototype to system. */ +#cmakedefine NEED_SYSTEM_PROTO + +/* Check for a prototype to time. */ +#cmakedefine NEED_TIME_PROTO + +/* Check for a prototype to unlink. */ +#cmakedefine NEED_UNLINK_PROTO + +/* Check for a prototype to vsnprintf. */ +#cmakedefine NEED_VSNPRINTF_PROTO + +/* Check for a prototype to write. */ +#cmakedefine NEED_WRITE_PROTO + + +#endif /* _CONF_H_ */ diff --git a/src/util/CMakeLists.txt b/src/util/CMakeLists.txt new file mode 100644 index 0000000..5e6fe78 --- /dev/null +++ b/src/util/CMakeLists.txt @@ -0,0 +1,46 @@ + +set(TOOLS + asciipasswd + autowiz + plrtoascii + rebuildIndex + rebuildMailIndex + shopconv + sign + split + wld2html + webster +) + +# common includes and flags +include_directories(${CMAKE_SOURCE_DIR}/src) +add_definitions(-DCIRCLE_UTIL) + +find_library(CRYPT_LIBRARY crypt) +find_library(NETLIB_LIBRARY nsl socket) # for sign.c, hvis nødvendig + +foreach(tool ${TOOLS}) + if(${tool} STREQUAL "rebuildIndex") + add_executable(rebuildIndex rebuildAsciiIndex.c) + else() + add_executable(${tool} ${tool}.c) + endif() + + # Set output location + set_target_properties(${tool} PROPERTIES + RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/bin + ) + + # Link to libcrypt for asciipasswd + if(${tool} STREQUAL "asciipasswd" AND CRYPT_LIBRARY) + target_link_libraries(${tool} ${CRYPT_LIBRARY}) + endif() + + # Link to netlib for sign + if(${tool} STREQUAL "sign" AND NETLIB_LIBRARY) + target_link_libraries(${tool} ${NETLIB_LIBRARY}) + endif() +endforeach() + +add_custom_target(utils DEPENDS ${TOOLS}) + From f6339b495e544ecea48e3563ea2ab5997b98d813 Mon Sep 17 00:00:00 2001 From: Thomas Arp <357770+welcor@users.noreply.github.com> Date: Wed, 2 Jul 2025 22:34:57 +0200 Subject: [PATCH 19/19] Feature/clang tidy (#154) * First cmake list file, simple docs. TODO: utils folder. * Support for building utils * All fields except HAVE_DOPRNT in place * Now builds and runs :) * Added support for clang-tidy, if available. --- .clang-tidy | 8 ++++++++ CMakeLists.txt | 11 +++++++++++ 2 files changed, 19 insertions(+) create mode 100644 .clang-tidy diff --git a/.clang-tidy b/.clang-tidy new file mode 100644 index 0000000..1bae24a --- /dev/null +++ b/.clang-tidy @@ -0,0 +1,8 @@ +Checks: > + -*, + clang-analyzer-*, + bugprone-*, + performance-*, + portability-* +#WarningsAsErrors: '*' +HeaderFilterRegex: 'src/.*' \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 9fa9a76..78cd2af 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,6 +34,17 @@ if (CMAKE_COMPILER_IS_GNUCC) endif() endif() +# clang-tidy if available +find_program(CLANG_TIDY_EXE NAMES clang-tidy) + +if(CLANG_TIDY_EXE AND STATIC_ANALYSIS) + message(STATUS "clang-tidy enabled: ${CLANG_TIDY_EXE}") + set(CMAKE_C_CLANG_TIDY "${CLANG_TIDY_EXE}") + set(CMAKE_EXPORT_COMPILE_COMMANDS ON) +else() + message(WARNING "clang-tidy not found. Static analysis disabled.") +endif() + # ========== Header checks ========== check_include_file("fcntl.h" HAVE_FCNTL_H) check_include_file("errno.h" HAVE_ERRNO_H)