From 9c801f9ab6d51e9fd0ebc3bccf6b3c1210a4879d Mon Sep 17 00:00:00 2001 From: Thomas Date: Thu, 24 Mar 2022 22:46:43 +0100 Subject: [PATCH 01/35] inc size of name, max length names crash on addrecent due to buffer overflow --- src/structs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/structs.h b/src/structs.h index 4954a1b..08e47db 100644 --- a/src/structs.h +++ b/src/structs.h @@ -1276,7 +1276,7 @@ struct happyhour { struct recent_player { int vnum; /* The ID number for this instance */ - char name[MAX_NAME_LENGTH]; /* The char name of the player */ + char name[MAX_NAME_LENGTH+1];/* The char name of the player */ bool new_player; /* Is this a new player? */ bool copyover_player; /* Is this a player that was on during the last copyover? */ time_t time; /* login time */ From 2d8c05b4ed3415dc677c09ec695a8d1b00625894 Mon Sep 17 00:00:00 2001 From: Mackerel Date: Sat, 3 Sep 2022 00:11:03 -0400 Subject: [PATCH 02/35] use strncat(sizeof(...) - strlen(...) - 1) --- src/dg_olc.c | 2 +- src/genzon.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dg_olc.c b/src/dg_olc.c index ac28e01..1a4affa 100644 --- a/src/dg_olc.c +++ b/src/dg_olc.c @@ -1148,7 +1148,7 @@ int format_script(struct descriptor_data *d) *line = '\0'; for (nlen = 0, i = 0;i Date: Sun, 23 Oct 2022 14:57:14 -0500 Subject: [PATCH 03/35] Update handler.c Fixes the display order of objects in obj_to_room(). Objects are now displayed in the order they are placed/dropped. This prevents fountains, boards, etcetera from "moving" around the room. --- src/handler.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/src/handler.c b/src/handler.c index 61bca67..d6660f4 100644 --- a/src/handler.c +++ b/src/handler.c @@ -671,17 +671,25 @@ struct char_data *get_char_num(mob_rnum nr) /* put an object in a room */ void obj_to_room(struct obj_data *object, room_rnum room) { - if (!object || room == NOWHERE || room > top_of_world) + if (!object || room == NOWHERE || room > top_of_world){ log("SYSERR: Illegal value(s) passed to obj_to_room. (Room #%d/%d, obj %p)", room, top_of_world, (void *)object); - else { - object->next_content = world[room].contents; - world[room].contents = object; - IN_ROOM(object) = room; - object->carried_by = NULL; - if (ROOM_FLAGGED(room, ROOM_HOUSE)) - SET_BIT_AR(ROOM_FLAGS(room), ROOM_HOUSE_CRASH); } + else { + if (world[room].contents == NULL){ // if list is empty + world[room].contents = object; // add object to list + } + else { + struct obj_data *i = world[room].contents; // define a temporary pointer + while (i->next_content != NULL) i = i->next_content; // find the first without a next_content + i->next_content = object; // add object at the end + } + object->next_content = NULL; // mostly for sanity. should do nothing. + IN_ROOM(object) = room + object->carried_by = NULL; + if (ROOM_FLAGGED(room, ROOM_HOUSE)) + SET_BIT_AR(ROOM_FLAGS(room), ROOM_HOUSE_CRASH); + } } /* Take an object from a room */ From 7039f9c402b8fad3ba37184b992853cb1ec74b0f Mon Sep 17 00:00:00 2001 From: tjr1974 <116045172+tjr1974@users.noreply.github.com> Date: Sun, 23 Oct 2022 15:12:57 -0500 Subject: [PATCH 04/35] Update act.informative.c Fixes unguarded else clauses due to inconsistent use of {} in look_at_room(). --- src/act.informative.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/act.informative.c b/src/act.informative.c index e1187ef..443aff6 100644 --- a/src/act.informative.c +++ b/src/act.informative.c @@ -492,7 +492,8 @@ void look_at_room(struct char_data *ch, int ignore_brief) if (IS_DARK(IN_ROOM(ch)) && !CAN_SEE_IN_DARK(ch)) { send_to_char(ch, "It is pitch black...\r\n"); return; - } else if (AFF_FLAGGED(ch, AFF_BLIND) && GET_LEVEL(ch) < LVL_IMMORT) { + } + else if (AFF_FLAGGED(ch, AFF_BLIND) && GET_LEVEL(ch) < LVL_IMMORT) { send_to_char(ch, "You see nothing but infinite darkness...\r\n"); return; } @@ -511,17 +512,19 @@ void look_at_room(struct char_data *ch, int ignore_brief) send_to_char(ch, "]"); } } - else + else { send_to_char(ch, "%s", world[IN_ROOM(ch)].name); - send_to_char(ch, "%s\r\n", CCNRM(ch, C_NRM)); + } + send_to_char(ch, "%s\r\n", CCCYN(ch, C_NRM)); if ((!IS_NPC(ch) && !PRF_FLAGGED(ch, PRF_BRIEF)) || ignore_brief || ROOM_FLAGGED(IN_ROOM(ch), ROOM_DEATH)) { if(!IS_NPC(ch) && PRF_FLAGGED(ch, PRF_AUTOMAP) && can_see_map(ch)) str_and_map(world[target_room].description, ch, target_room); - else + } + else { send_to_char(ch, "%s", world[IN_ROOM(ch)].description); - } + } /* autoexits */ if (!IS_NPC(ch) && PRF_FLAGGED(ch, PRF_AUTOEXIT)) From 97bd28ffd37e1562485bf8d0bfcb0caaf03212de Mon Sep 17 00:00:00 2001 From: tjr1974 <116045172+tjr1974@users.noreply.github.com> Date: Sun, 23 Oct 2022 15:29:43 -0500 Subject: [PATCH 05/35] Update act.informative.c Fixes unguarded blocks of code in ACMD(do_exits) that could cause the server to report scripted trigger events (mob movements, exit links to rooms being reassigned, and doors being opened or closed) as script errors. Particularly, if this code is copy and pasted into the do_auto_exits(). --- src/act.informative.c | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/src/act.informative.c b/src/act.informative.c index 443aff6..22a8636 100644 --- a/src/act.informative.c +++ b/src/act.informative.c @@ -443,39 +443,44 @@ ACMD(do_exits) { int door, len = 0; - if (AFF_FLAGGED(ch, AFF_BLIND) && GET_LEVEL(ch) < LVL_IMMORT) { + if (AFF_FLAGGED(ch, AFF_BLIND) && GET_LEVEL(ch) < LVL_IMMORT) + { send_to_char(ch, "You can't see a damned thing, you're blind!\r\n"); return; } - + send_to_char(ch, "Obvious exits:\r\n"); - for (door = 0; door < DIR_COUNT; door++) { + for (door = 0; door < DIR_COUNT; door++) + { if (!EXIT(ch, door) || EXIT(ch, door)->to_room == NOWHERE) continue; if (EXIT_FLAGGED(EXIT(ch, door), EX_CLOSED) && !CONFIG_DISP_CLOSED_DOORS) continue; if (EXIT_FLAGGED(EXIT(ch, door), EX_HIDDEN) && !PRF_FLAGGED(ch, PRF_HOLYLIGHT)) - continue; + continue; len++; if (!IS_NPC(ch) && PRF_FLAGGED(ch, PRF_SHOWVNUMS) && !EXIT_FLAGGED(EXIT(ch, door), EX_CLOSED)) - send_to_char(ch, "%-5s - [%5d]%s %s\r\n", dirs[door], GET_ROOM_VNUM(EXIT(ch, door)->to_room), - EXIT_FLAGGED(EXIT(ch, door), EX_HIDDEN) ? " [HIDDEN]" : "", world[EXIT(ch, door)->to_room].name); + { + send_to_char(ch, "%-5s -[%5d]%s %s\r\n", dirs[door], GET_ROOM_VNUM(EXIT(ch, door)->to_room), + EXIT_FLAGGED(EXIT(ch, door), EX_HIDDEN) ? "[HIDDEN]" : "", world[EXIT(ch, door)->to_room].name); + } else if (CONFIG_DISP_CLOSED_DOORS && EXIT_FLAGGED(EXIT(ch, door), EX_CLOSED)) { /* But we tell them the door is closed */ send_to_char(ch, "%-5s - The %s is closed%s\r\n", dirs[door], - (EXIT(ch, door)->keyword)? fname(EXIT(ch, door)->keyword) : "opening", - EXIT_FLAGGED(EXIT(ch, door), EX_HIDDEN) ? " and hidden." : "."); - } + (EXIT(ch, door)->keyword) ? fname(EXIT(ch, door)->keyword) : "opening", + EXIT_FLAGGED(EXIT(ch, door), EX_HIDDEN) ? " and hidden." : "."); + } else + { send_to_char(ch, "%-5s - %s\r\n", dirs[door], IS_DARK(EXIT(ch, door)->to_room) && - !CAN_SEE_IN_DARK(ch) ? "Too dark to tell." : world[EXIT(ch, door)->to_room].name); + !CAN_SEE_IN_DARK(ch) ? "Too dark to tell." : world[EXIT(ch, door)->to_room].name); + } + if (!len) + send_to_char(ch, " None.\r\n"); } - - if (!len) - send_to_char(ch, " None.\r\n"); } void look_at_room(struct char_data *ch, int ignore_brief) From 59398b2fdca8be5ac65cf7f7043056c9cf95e6bc Mon Sep 17 00:00:00 2001 From: tjr1974 <116045172+tjr1974@users.noreply.github.com> Date: Mon, 24 Oct 2022 16:07:49 -0500 Subject: [PATCH 06/35] Update handler.c Fixes indentations in obj_to_room() --- src/handler.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/handler.c b/src/handler.c index d6660f4..72eaf9a 100644 --- a/src/handler.c +++ b/src/handler.c @@ -675,21 +675,21 @@ void obj_to_room(struct obj_data *object, room_rnum room) log("SYSERR: Illegal value(s) passed to obj_to_room. (Room #%d/%d, obj %p)", room, top_of_world, (void *)object); } - else { - if (world[room].contents == NULL){ // if list is empty - world[room].contents = object; // add object to list + else { + if (world[room].contents == NULL){ // if list is empty + world[room].contents = object; // add object to list } - else { - struct obj_data *i = world[room].contents; // define a temporary pointer - while (i->next_content != NULL) i = i->next_content; // find the first without a next_content - i->next_content = object; // add object at the end - } - object->next_content = NULL; // mostly for sanity. should do nothing. - IN_ROOM(object) = room - object->carried_by = NULL; - if (ROOM_FLAGGED(room, ROOM_HOUSE)) - SET_BIT_AR(ROOM_FLAGS(room), ROOM_HOUSE_CRASH); - } + else { + struct obj_data *i = world[room].contents; // define a temporary pointer + while (i->next_content != NULL) i = i->next_content; // find the first without a next_content + i->next_content = object; // add object at the end + } + object->next_content = NULL; // mostly for sanity. should do nothing. + IN_ROOM(object) = room + object->carried_by = NULL; + if (ROOM_FLAGGED(room, ROOM_HOUSE)) + SET_BIT_AR(ROOM_FLAGS(room), ROOM_HOUSE_CRASH); + } } /* Take an object from a room */ From 041765438a6052726ce1018468e396aa0d526fda Mon Sep 17 00:00:00 2001 From: tjr1974 <116045172+tjr1974@users.noreply.github.com> Date: Mon, 24 Oct 2022 16:38:11 -0500 Subject: [PATCH 07/35] Update act.informative.c Used code formatter to correct indentations and align all {} in the look_at_room() Checked for unmactched braces and found none. My code editor shows all {} are matched. --- src/act.informative.c | 43 ++++++++++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/src/act.informative.c b/src/act.informative.c index 22a8636..48516ac 100644 --- a/src/act.informative.c +++ b/src/act.informative.c @@ -485,7 +485,7 @@ ACMD(do_exits) void look_at_room(struct char_data *ch, int ignore_brief) { - trig_data *t; + trig_data * t; struct room_data *rm = &world[IN_ROOM(ch)]; room_vnum target_room; @@ -494,48 +494,57 @@ void look_at_room(struct char_data *ch, int ignore_brief) if (!ch->desc) return; - if (IS_DARK(IN_ROOM(ch)) && !CAN_SEE_IN_DARK(ch)) { + if (IS_DARK(IN_ROOM(ch)) && !CAN_SEE_IN_DARK(ch)) + { send_to_char(ch, "It is pitch black...\r\n"); return; - } - else if (AFF_FLAGGED(ch, AFF_BLIND) && GET_LEVEL(ch) < LVL_IMMORT) { + } + else if (AFF_FLAGGED(ch, AFF_BLIND) && GET_LEVEL(ch) < LVL_IMMORT) + { send_to_char(ch, "You see nothing but infinite darkness...\r\n"); return; } + send_to_char(ch, "%s", CCCYN(ch, C_NRM)); - if (!IS_NPC(ch) && PRF_FLAGGED(ch, PRF_SHOWVNUMS)) { + if (!IS_NPC(ch) && PRF_FLAGGED(ch, PRF_SHOWVNUMS)) + { char buf[MAX_STRING_LENGTH]; sprintbitarray(ROOM_FLAGS(IN_ROOM(ch)), room_bits, RF_ARRAY_MAX, buf); send_to_char(ch, "[%5d] ", GET_ROOM_VNUM(IN_ROOM(ch))); - send_to_char(ch, "%s [ %s] [ %s ]", world[IN_ROOM(ch)].name, buf, sector_types[world[IN_ROOM(ch)].sector_type]); + send_to_char(ch, "%s[ %s][ %s ]", world[IN_ROOM(ch)].name, buf, sector_types[world[IN_ROOM(ch)].sector_type]); - if (SCRIPT(rm)) { + if (SCRIPT(rm)) + { send_to_char(ch, "[T"); for (t = TRIGGERS(SCRIPT(rm)); t; t = t->next) send_to_char(ch, " %d", GET_TRIG_VNUM(t)); send_to_char(ch, "]"); } } - else { + else + { send_to_char(ch, "%s", world[IN_ROOM(ch)].name); } + send_to_char(ch, "%s\r\n", CCCYN(ch, C_NRM)); if ((!IS_NPC(ch) && !PRF_FLAGGED(ch, PRF_BRIEF)) || ignore_brief || - ROOM_FLAGGED(IN_ROOM(ch), ROOM_DEATH)) { - if(!IS_NPC(ch) && PRF_FLAGGED(ch, PRF_AUTOMAP) && can_see_map(ch)) - str_and_map(world[target_room].description, ch, target_room); - } - else { - send_to_char(ch, "%s", world[IN_ROOM(ch)].description); - } + ROOM_FLAGGED(IN_ROOM(ch), ROOM_DEATH)) + { + if (!IS_NPC(ch) && PRF_FLAGGED(ch, PRF_AUTOMAP) && can_see_map(ch)) + str_and_map(world[target_room].description, ch, target_room); + } + else + { + send_to_char(ch, "%s", world[IN_ROOM(ch)].description); + } - /* autoexits */ + /*autoexits */ if (!IS_NPC(ch) && PRF_FLAGGED(ch, PRF_AUTOEXIT)) do_auto_exits(ch); - /* now list characters & objects */ + /*now list characters &objects */ list_obj_to_char(world[IN_ROOM(ch)].contents, ch, SHOW_OBJ_LONG, FALSE); list_char_to_char(world[IN_ROOM(ch)].people, ch); } From 34aca229df79dc14c73e811ae7fc169b0f466c26 Mon Sep 17 00:00:00 2001 From: tjr1974 <116045172+tjr1974@users.noreply.github.com> Date: Mon, 24 Oct 2022 17:07:54 -0500 Subject: [PATCH 08/35] Update act.informative.c Used code formatter to correct indentations and align all {} in lACMD(do_exits) Checked for unmactched braces and found none. My code editor shows all {} are matched. --- src/act.informative.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/act.informative.c b/src/act.informative.c index 48516ac..6964a20 100644 --- a/src/act.informative.c +++ b/src/act.informative.c @@ -448,7 +448,7 @@ ACMD(do_exits) send_to_char(ch, "You can't see a damned thing, you're blind!\r\n"); return; } - + send_to_char(ch, "Obvious exits:\r\n"); for (door = 0; door < DIR_COUNT; door++) @@ -467,8 +467,9 @@ ACMD(do_exits) send_to_char(ch, "%-5s -[%5d]%s %s\r\n", dirs[door], GET_ROOM_VNUM(EXIT(ch, door)->to_room), EXIT_FLAGGED(EXIT(ch, door), EX_HIDDEN) ? "[HIDDEN]" : "", world[EXIT(ch, door)->to_room].name); } - else if (CONFIG_DISP_CLOSED_DOORS && EXIT_FLAGGED(EXIT(ch, door), EX_CLOSED)) { - /* But we tell them the door is closed */ + else if (CONFIG_DISP_CLOSED_DOORS && EXIT_FLAGGED(EXIT(ch, door), EX_CLOSED)) + { + /*But we tell them the door is closed */ send_to_char(ch, "%-5s - The %s is closed%s\r\n", dirs[door], (EXIT(ch, door)->keyword) ? fname(EXIT(ch, door)->keyword) : "opening", EXIT_FLAGGED(EXIT(ch, door), EX_HIDDEN) ? " and hidden." : "."); @@ -478,9 +479,9 @@ ACMD(do_exits) send_to_char(ch, "%-5s - %s\r\n", dirs[door], IS_DARK(EXIT(ch, door)->to_room) && !CAN_SEE_IN_DARK(ch) ? "Too dark to tell." : world[EXIT(ch, door)->to_room].name); } - if (!len) - send_to_char(ch, " None.\r\n"); } + if (!len) + send_to_char(ch, " None.\r\n"); } void look_at_room(struct char_data *ch, int ignore_brief) From 15074b1d93b0babb6c1fea2e378be2befbe07264 Mon Sep 17 00:00:00 2001 From: Thomas Arp <357770+welcor@users.noreply.github.com> Date: Wed, 2 Nov 2022 22:31:56 +0100 Subject: [PATCH 09/35] Added check for NOTHING key in has_key() --- src/act.movement.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/act.movement.c b/src/act.movement.c index ffef0d8..a1ba0de 100644 --- a/src/act.movement.c +++ b/src/act.movement.c @@ -461,6 +461,9 @@ int has_key(struct char_data *ch, obj_vnum key) { struct obj_data *o; + if (key == NOTHING) + return (0); + for (o = ch->carrying; o; o = o->next_content) if (GET_OBJ_VNUM(o) == key) return (1); From 0ee3aac10d92c69a8ff77568e38c0f613a3a2fdf Mon Sep 17 00:00:00 2001 From: Joseph Date: Fri, 4 Nov 2022 21:02:35 -0300 Subject: [PATCH 10/35] Replaced missing semi-colon. -No Compile --- src/handler.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/handler.c b/src/handler.c index 72eaf9a..87269bb 100644 --- a/src/handler.c +++ b/src/handler.c @@ -685,7 +685,7 @@ void obj_to_room(struct obj_data *object, room_rnum room) i->next_content = object; // add object at the end } object->next_content = NULL; // mostly for sanity. should do nothing. - IN_ROOM(object) = room + IN_ROOM(object) = room; object->carried_by = NULL; if (ROOM_FLAGGED(room, ROOM_HOUSE)) SET_BIT_AR(ROOM_FLAGS(room), ROOM_HOUSE_CRASH); From c9ebc7174c64d2f5c3282799000d1b37df96c1b5 Mon Sep 17 00:00:00 2001 From: Thomas Arp <357770+welcor@users.noreply.github.com> Date: Sun, 6 Nov 2022 23:41:31 +0100 Subject: [PATCH 11/35] Create build.yml (#117) Support for building pull requests with github actions --- .github/workflows/build.yml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 .github/workflows/build.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..717fe7a --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,19 @@ +name: C/C++ CI + +on: + push: + branches: [ "master" ] + pull_request: + branches: [ "master" ] + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + - name: configure + run: ./configure + - name: build + run: cd src && touch .accepted && make From e9c9808a2425f739d187f0d8c75e61592843bf45 Mon Sep 17 00:00:00 2001 From: tjr1974 <116045172+tjr1974@users.noreply.github.com> Date: Wed, 16 Nov 2022 16:08:33 -0600 Subject: [PATCH 12/35] Update act.informative.c (#119) Fixed formatting for readability. Indentations should be correct. Tested on fresh install. It does compile. Room descriptions display properly. --- src/act.informative.c | 59 ++++++++++++++++++------------------------- 1 file changed, 25 insertions(+), 34 deletions(-) diff --git a/src/act.informative.c b/src/act.informative.c index 6964a20..e5db496 100644 --- a/src/act.informative.c +++ b/src/act.informative.c @@ -495,59 +495,50 @@ void look_at_room(struct char_data *ch, int ignore_brief) if (!ch->desc) return; - if (IS_DARK(IN_ROOM(ch)) && !CAN_SEE_IN_DARK(ch)) - { + if (IS_DARK(IN_ROOM(ch)) && !CAN_SEE_IN_DARK(ch)){ send_to_char(ch, "It is pitch black...\r\n"); return; } - else if (AFF_FLAGGED(ch, AFF_BLIND) && GET_LEVEL(ch) < LVL_IMMORT) - { + else if (AFF_FLAGGED(ch, AFF_BLIND) && GET_LEVEL(ch) < LVL_IMMORT) { send_to_char(ch, "You see nothing but infinite darkness...\r\n"); return; } - send_to_char(ch, "%s", CCCYN(ch, C_NRM)); - if (!IS_NPC(ch) && PRF_FLAGGED(ch, PRF_SHOWVNUMS)) - { + send_to_char(ch, "%s", CCYEL(ch, C_NRM)); + if (!IS_NPC(ch) && PRF_FLAGGED(ch, PRF_SHOWVNUMS)) { char buf[MAX_STRING_LENGTH]; sprintbitarray(ROOM_FLAGS(IN_ROOM(ch)), room_bits, RF_ARRAY_MAX, buf); send_to_char(ch, "[%5d] ", GET_ROOM_VNUM(IN_ROOM(ch))); send_to_char(ch, "%s[ %s][ %s ]", world[IN_ROOM(ch)].name, buf, sector_types[world[IN_ROOM(ch)].sector_type]); - if (SCRIPT(rm)) - { + if (SCRIPT(rm)) { send_to_char(ch, "[T"); for (t = TRIGGERS(SCRIPT(rm)); t; t = t->next) send_to_char(ch, " %d", GET_TRIG_VNUM(t)); send_to_char(ch, "]"); } } - else - { + else { send_to_char(ch, "%s", world[IN_ROOM(ch)].name); - } + send_to_char(ch, "%s\r\n", CCNRM(ch, C_NRM)); - send_to_char(ch, "%s\r\n", CCCYN(ch, C_NRM)); + if ((!IS_NPC(ch) && !PRF_FLAGGED(ch, PRF_BRIEF)) || ignore_brief || + ROOM_FLAGGED(IN_ROOM(ch), ROOM_DEATH)) { + if (!IS_NPC(ch) && PRF_FLAGGED(ch, PRF_AUTOMAP) && can_see_map(ch)) + str_and_map(world[target_room].description, ch, target_room); + } - if ((!IS_NPC(ch) && !PRF_FLAGGED(ch, PRF_BRIEF)) || ignore_brief || - ROOM_FLAGGED(IN_ROOM(ch), ROOM_DEATH)) - { - if (!IS_NPC(ch) && PRF_FLAGGED(ch, PRF_AUTOMAP) && can_see_map(ch)) - str_and_map(world[target_room].description, ch, target_room); - } - else - { - send_to_char(ch, "%s", world[IN_ROOM(ch)].description); - } + send_to_char(ch, "%s", world[IN_ROOM(ch)].description); - /*autoexits */ - if (!IS_NPC(ch) && PRF_FLAGGED(ch, PRF_AUTOEXIT)) - do_auto_exits(ch); + /*autoexits */ + if (!IS_NPC(ch) && PRF_FLAGGED(ch, PRF_AUTOEXIT)) + do_auto_exits(ch); - /*now list characters &objects */ - list_obj_to_char(world[IN_ROOM(ch)].contents, ch, SHOW_OBJ_LONG, FALSE); - list_char_to_char(world[IN_ROOM(ch)].people, ch); + /*now list characters &objects */ + list_obj_to_char(world[IN_ROOM(ch)].contents, ch, SHOW_OBJ_LONG, FALSE); + list_char_to_char(world[IN_ROOM(ch)].people, ch); + } } static void look_in_direction(struct char_data *ch, int dir) @@ -1069,7 +1060,7 @@ int search_help(const char *argument, int level) mid++; if (strn_cmp(argument, help_table[mid].keywords, minlen) || level < help_table[mid].min_level) break; - + return (mid); } else if (chk > 0) @@ -1296,7 +1287,7 @@ ACMD(do_who) GET_LEVEL(tch), CLASS_ABBR(tch), GET_NAME(tch), (*GET_TITLE(tch) ? " " : ""), GET_TITLE(tch), CCNRM(ch, C_SPR)); - + if (GET_INVIS_LEV(tch)) send_to_char(ch, " (i%d)", GET_INVIS_LEV(tch)); else if (AFF_FLAGGED(tch, AFF_INVISIBLE)) @@ -2130,7 +2121,7 @@ ACMD(do_toggle) for (i=0; *arg2 && *(sector_types[i]) != '\n'; i++) if (is_abbrev(arg2, sector_types[i])) break; - if (*(sector_types[i]) == '\n') + if (*(sector_types[i]) == '\n') i=0; GET_BUILDWALK_SECTOR(ch) = i; send_to_char(ch, "Default sector type is %s\r\n", sector_types[i]); @@ -2383,9 +2374,9 @@ ACMD(do_whois) { CREATE(victim, struct char_data, 1); clear_char(victim); - + new_mobile_data(victim); - + CREATE(victim->player_specials, struct player_special_data, 1); if (load_char(buf, victim) > -1) From 7f495670f2fa84d94e927936c0d84f6c57905406 Mon Sep 17 00:00:00 2001 From: Thomas Arp <357770+welcor@users.noreply.github.com> Date: Wed, 16 Nov 2022 23:08:51 +0100 Subject: [PATCH 13/35] Bugfix: the "rest" is added but was never subtracted. (#120) --- src/act.other.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/act.other.c b/src/act.other.c index d5bb798..37cc284 100644 --- a/src/act.other.c +++ b/src/act.other.c @@ -546,7 +546,6 @@ ACMD(do_split) if (rest) { send_to_char(ch, "%d coin%s %s not splitable, so you keep the money.\r\n", rest, (rest == 1) ? "" : "s", (rest == 1) ? "was" : "were"); - increase_gold(ch, rest); } } else { send_to_char(ch, "How many coins do you wish to split with your group?\r\n"); From 79e2f9189496e5ed2ca827ca7e8d263ae706fd32 Mon Sep 17 00:00:00 2001 From: Steaphan Greene Date: Mon, 5 Dec 2022 03:53:37 -0800 Subject: [PATCH 14/35] Fix (remove) rogue non-ascii character from socials.new. (#123) This character isn't ascii, nor even utf8. It doesn't serve any real textual purpose either, so, just delete it. --- lib/misc/socials.new | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/misc/socials.new b/lib/misc/socials.new index ae027f6..c993418 100644 --- a/lib/misc/socials.new +++ b/lib/misc/socials.new @@ -6109,7 +6109,7 @@ $n looks around for a victim to strangle. You throw yourself against $N's throat, trying to squeeze the life out. $n throws $mself after $N's throat. $n throws $mself after your throat, you try to defend yourself. -AARGH! They must have left... #&%Ł@! +AARGH! They must have left... #&%@! You put your hands around your throat and stop breathing. $n tries to strangle $mself, making a very strange noise and getting blue in the face. You strangle $M $t. From 213e52d25589eadb927fc347d088b7c241beeebc Mon Sep 17 00:00:00 2001 From: Rumble Date: Mon, 2 Jan 2023 14:23:51 +0000 Subject: [PATCH 15/35] Updated for 2023 release --- doc/releases.txt | 1 + lib/misc/socials.new | 2 +- lib/text/greetings | 2 +- lib/text/help/help.hlp | 5 +- lib/world/wld/302.wld | 152 ++++++++++++++++++++--------------------- lib/world/zon/302.zon | 4 +- lib/world/zon/4.zon | 4 +- lib/world/zon/6.zon | 2 +- src/constants.c | 2 +- 9 files changed, 88 insertions(+), 86 deletions(-) diff --git a/doc/releases.txt b/doc/releases.txt index 7c7e027..3ef6c0d 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 2023 release: January, 2023 Version 2021 release: March, 2021 Version 2020 release: January, 2020 Version 2019 release: January, 2019 diff --git a/lib/misc/socials.new b/lib/misc/socials.new index c993418..d05ae0e 100644 --- a/lib/misc/socials.new +++ b/lib/misc/socials.new @@ -6109,7 +6109,7 @@ $n looks around for a victim to strangle. You throw yourself against $N's throat, trying to squeeze the life out. $n throws $mself after $N's throat. $n throws $mself after your throat, you try to defend yourself. -AARGH! They must have left... #&%@! +AARGH! They must have left... You put your hands around your throat and stop breathing. $n tries to strangle $mself, making a very strange noise and getting blue in the face. You strangle $M $t. diff --git a/lib/text/greetings b/lib/text/greetings index fd5a2d2..5bdc12a 100644 --- a/lib/text/greetings +++ b/lib/text/greetings @@ -1,5 +1,5 @@ T B A M U D - 2 0 2 1 + 2 0 2 3 Based on CircleMUD by Jeremy Elson and DikuMUD by Hans-Henrik Staerfeldt, Katja Nyboe, Tom Madsen, Michael Seifert, and Sebastian Hammer diff --git a/lib/text/help/help.hlp b/lib/text/help/help.hlp index ea6c6a1..d7b2eae 100644 --- a/lib/text/help/help.hlp +++ b/lib/text/help/help.hlp @@ -3312,7 +3312,7 @@ the earthquake spell. See also: WATERWALK, EARTHQUAKE #0 -FOLLOWERS +FOLLOWERS UNFOLLOW Usage: follow @@ -3350,7 +3350,7 @@ The 3rd number is liquid type from the following: value 1: Initial drink units. Must be 1 or greater. value 2: see below value 3: 0 for not poisoned. Otherwise, the number of hours until the poison - burns off? + burns off. value 2: The type of liquid in the drink-container, one of: @@ -9879,6 +9879,7 @@ tbalim test 61165 return toggle nohassle on +To list empty zones "show zone none" To setup test with zone 348 return saveall diff --git a/lib/world/wld/302.wld b/lib/world/wld/302.wld index a1841a4..28cc82b 100644 --- a/lib/world/wld/302.wld +++ b/lib/world/wld/302.wld @@ -1,6 +1,6 @@ #30200 -The Top Of The Greasepole~ - You've made it to the top! All you have to do now is get down... +The Top of the Greasepole~ +You've made it to the top! All you have to do now is get down. ~ 302 4 0 0 0 5 D5 @@ -9,6 +9,11 @@ It's a long slide down. ~ 0 -1 30192 E +pole greasepole~ + The pole still looks pretty bad, but it doesn't look quite as bad as before. + +~ +E info credits~ See zone description room for Campus. Zone 302 is linked to the following zones: @@ -48,11 +53,6 @@ Links: 64e to catacombs (Mobs Stay_Zone flags have all been disabled to allow free access between 301, 302 and 303. Please ensure that any entrances into the area are flagged nomob to keep them in. - Parna for TBAMud.) -~ -E -pole greasepole~ - The pole still looks pretty bad, but it doesn't look quite as bad as before. - ~ S #30201 @@ -71,13 +71,13 @@ D2 ~ 0 -1 30142 E -mail~ - Why are you trying to look at the mail, it's private! -~ -E hooks hook key keys~ Unfortunately you don't see any keys hanging off of any of the hooks. ~ +E +mail~ + Why are you trying to look at the mail, it's private! +~ S #30202 Main Office~ @@ -92,9 +92,10 @@ This way leads back to the reception desk. door~ 1 30103 30201 E -chair~ - The chair is not unusual in any way whatsoever. The chair is in excellent -condition. +filing cabinet files~ + Looking through the files you see that Wally World was originally slated to +have at least eleven levels but the designers got sick and tired of it and gave +up after just a few levels. ~ E desk~ @@ -102,10 +103,9 @@ desk~ excellent condition. ~ E -filing cabinet files~ - Looking through the files you see that Wally World was originally slated to -have at least eleven levels but the designers got sick and tired of it and gave -up after just a few levels. +chair~ + The chair is not unusual in any way whatsoever. The chair is in excellent +condition. ~ S #30203 @@ -230,14 +230,14 @@ You can't tell where this leads. door~ 1 -1 30210 E -door~ - The door on the west has the number 206 and the door on the east, 205. -~ -E floor carpet~ This is a nice, groovy, red patterned carpet which extends all the way down the hall. ~ +E +door~ + The door on the west has the number 206 and the door on the east, 205. +~ S #30209 Private Room 205~ @@ -300,15 +300,15 @@ You can't tell where this leads. door~ 1 -1 30213 E -door~ - The door on the west has the number 204 and the door on the east, 203 while -the door to the north has the number 201. -~ -E floor carpet~ This is a nice, groovy, red patterned carpet which extends all the way down the hall. ~ +E +door~ + The door on the west has the number 204 and the door on the east, 203 while +the door to the north has the number 201. +~ S #30212 Private Room 203~ @@ -388,14 +388,14 @@ You can't tell where this leads. door~ 1 -1 30217 E -door~ - The door on the west has the number 208 and the door on the east, 207. -~ -E floor carpet~ This is a nice, groovy, red patterned carpet which extends all the way down the hall. ~ +E +door~ + The door on the west has the number 208 and the door on the east, 207. +~ S #30216 Private Room 207~ @@ -458,15 +458,15 @@ You can't tell where this leads. door~ 1 -1 30220 E -door~ - The door on the west has the number 210 and the door on the east, 209 and the -door to the south has the number 202. -~ -E floor carpet~ This is a nice, groovy, red patterned carpet which extends all the way down the hall. ~ +E +door~ + The door on the west has the number 210 and the door on the east, 209 and the +door to the south has the number 202. +~ S #30219 Private Room 209~ @@ -654,14 +654,14 @@ The trapdoor leads up... beyond that, you aren't sure where it goes. trapdoor door~ 1 -1 30233 E +trapdoor~ + The trapdoor is neatly fastened with a small hook. +~ +E desk chair plush~ The desk and chairs are neatly arranged as if in preparation for an upcoming meeting or something of the sort. ~ -E -trapdoor~ - The trapdoor is neatly fastened with a small hook. -~ S #30229 Hallway~ @@ -770,13 +770,13 @@ A chute leads down from this room. ~ 0 -1 30235 E -chute~ - The chute is rather smooth and looks to be a fun ride. -~ -E grate~ Beyond the grate you can see the attic. ~ +E +chute~ + The chute is rather smooth and looks to be a fun ride. +~ S #30235 The Chute~ @@ -871,13 +871,13 @@ An exit from this hellhole. ~ 0 -1 30240 E -mess~ - Need you ask? -~ -E hell hole hellhole~ Never seen one before? ~ +E +mess~ + Need you ask? +~ S #30240 The Ghetto~ @@ -897,13 +897,13 @@ A run-down house lies to the west. ~ 0 -1 30239 E -house run-down~ - It's in bad shape. -~ -E overturned police policemobile mobile~ It is blocking the road quite nicely. Maybe it is meant to impede passage. ~ +E +house run-down~ + It's in bad shape. +~ S #30241 The Ghetto Intersection~ @@ -1344,16 +1344,16 @@ The auditorium is to the north. ~ 0 -1 30259 E -drab brown curtains curtain~ - They are just your average, everyday, drab brown curtains. +sturdy wooden plank planks~ + They are sturdy. They are wooden. They are planks. ~ E cords cord pulley pulleys~ Hey! It can make you look like you are flying! ~ E -sturdy wooden plank planks~ - They are sturdy. They are wooden. They are planks. +drab brown curtains curtain~ + They are just your average, everyday, drab brown curtains. ~ S #30262 @@ -1403,13 +1403,13 @@ It's the same stairwell. ~ 0 -1 30257 E -cobweb cobwebs web webs~ - Don't disturb them now! -~ -E huge stone door~ The huge stone door looks very inviting. ~ +E +cobweb cobwebs web webs~ + Don't disturb them now! +~ S #30265 The Grant Hall Clock~ @@ -1785,10 +1785,6 @@ It is too dark to tell. ~ 0 -1 30276 E -door~ - This door is covered with all types of non-magical sigils. -~ -E sigils~ The sigils seem to form some strange shapes: SSSSS @@ -1805,6 +1801,10 @@ sigils~ SSSSS I wonder what it could be? ~ +E +door~ + This door is covered with all types of non-magical sigils. +~ S #30281 A Classroom~ @@ -1851,13 +1851,13 @@ You are repulsed by this exit since the exit to the east is well lit. ~ 0 -1 30274 E -light~ - It's nice, warm, and inviting. -~ -E dark~ Are you mad? ~ +E +light~ + It's nice, warm, and inviting. +~ S #30283 The Exit~ @@ -1875,13 +1875,13 @@ Back into darkness, I don't think so! ~ 0 -1 30282 E -light~ - It's nice, warm, and inviting. -~ -E dark~ Are you mad? ~ +E +light~ + It's nice, warm, and inviting. +~ S #30284 Mob Chute A~ @@ -1916,10 +1916,6 @@ This is just an exit. ~ 0 -1 30106 E -door~ - This door is covered with all types of non-magical sigils. -~ -E sigils~ The sigils seem to form some strange shapes: MMM MMM OOO OOO !! @@ -1929,6 +1925,10 @@ sigils~ MM M MM OO OO OO OO MM MM OOO OOO !! ~ +E +door~ + This door is covered with all types of non-magical sigils. +~ S #30285 Mob Chute B~ diff --git a/lib/world/zon/302.zon b/lib/world/zon/302.zon index cd8ff3b..bdbb0d6 100644 --- a/lib/world/zon/302.zon +++ b/lib/world/zon/302.zon @@ -2,6 +2,8 @@ Matrix of C.A.W.~ Campus II~ 30200 30299 30 2 +R 0 30200 30112 -1 (a tam) +O 1 30112 99 30200 (a tam) M 0 30105 4 30284 (Security) E 1 30115 99 16 (a flashlight) M 0 30105 4 30284 (Security) @@ -32,8 +34,6 @@ M 0 30132 1 30284 (Chris) M 0 30137 1 30284 (Alex) M 0 30138 1 30284 (Steve) M 0 30145 10 30284 (a copy of Golden World) -R 0 30200 30112 -1 (a tam) -O 1 30112 99 30200 (a tam) M 0 30139 1 30245 (Bob the storekeeper) G 1 30136 99 -1 (a pale apple) G 1 30140 99 -1 (a can of PopCoke) diff --git a/lib/world/zon/4.zon b/lib/world/zon/4.zon index b3e1c35..ffa11d7 100644 --- a/lib/world/zon/4.zon +++ b/lib/world/zon/4.zon @@ -1,6 +1,6 @@ #4 -Unknown~ -Jade Forest~ +trunks shaoden~ +Rename~ 400 499 30 2 d 0 0 0 10 25 M 0 481 1 481 (Zachary) G 1 403 99 -1 (rawhide whip) diff --git a/lib/world/zon/6.zon b/lib/world/zon/6.zon index 9db35c2..2993a50 100644 --- a/lib/world/zon/6.zon +++ b/lib/world/zon/6.zon @@ -1,5 +1,5 @@ #6 -Unknown~ +q~ Sea of Souls~ 600 699 30 2 d 0 0 0 10 25 M 0 600 1 600 (a snail) diff --git a/src/constants.c b/src/constants.c index 50e50f9..c18f11f 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 2021"; +cpp_extern const char *tbamud_version = "tbaMUD 2023"; /* strings corresponding to ordinals/bitvectors in structs.h */ /* (Note: strings for class definitions in class.c instead of here) */ From 498b6525460180f47d72dbfbade61fa1650d6f19 Mon Sep 17 00:00:00 2001 From: Serge Date: Sat, 7 Jan 2023 16:43:06 +0200 Subject: [PATCH 16/35] fixed small bug in toggle showvnum (#125) Thanks, @prool --- src/act.informative.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/act.informative.c b/src/act.informative.c index e5db496..79705f3 100644 --- a/src/act.informative.c +++ b/src/act.informative.c @@ -519,7 +519,7 @@ void look_at_room(struct char_data *ch, int ignore_brief) send_to_char(ch, "]"); } } - else { + else send_to_char(ch, "%s", world[IN_ROOM(ch)].name); send_to_char(ch, "%s\r\n", CCNRM(ch, C_NRM)); @@ -538,7 +538,6 @@ void look_at_room(struct char_data *ch, int ignore_brief) /*now list characters &objects */ list_obj_to_char(world[IN_ROOM(ch)].contents, ch, SHOW_OBJ_LONG, FALSE); list_char_to_char(world[IN_ROOM(ch)].people, ch); - } } static void look_in_direction(struct char_data *ch, int dir) From b2d38522e01203d61a12546a806457c022aa6d0d Mon Sep 17 00:00:00 2001 From: Roman Shapiro Date: Sun, 19 Nov 2023 10:04:39 +0700 Subject: [PATCH 17/35] Added new easy way of building TbaMUD in the Visual Studio through the CMake (#127) * Added new experimental MSVC build way through CMake * Small build/README.md fix --- .gitignore | 3 +++ build/README.md | 15 +++++++++++++++ build/create_solution.bat | 1 + src/CMakeLists.txt | 26 ++++++++++++++++++++++++++ src/protocol.c | 5 +++++ 5 files changed, 50 insertions(+) create mode 100644 build/README.md create mode 100644 build/create_solution.bat create mode 100644 src/CMakeLists.txt diff --git a/.gitignore b/.gitignore index 35c0bed..e8e8f46 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,6 @@ src/util/Makefile src/.accepted src/depend src/util/depend +build/* +!build/create_solution.bat +!build/README.md \ No newline at end of file diff --git a/build/README.md b/build/README.md new file mode 100644 index 0000000..bd84d9a --- /dev/null +++ b/build/README.md @@ -0,0 +1,15 @@ +### 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. + +4. Compile and run. \ No newline at end of file diff --git a/build/create_solution.bat b/build/create_solution.bat new file mode 100644 index 0000000..ab60043 --- /dev/null +++ b/build/create_solution.bat @@ -0,0 +1 @@ +cmake -B . -S ..\src -G "Visual Studio 17 2022" \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..51832b4 --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,26 @@ +cmake_minimum_required(VERSION 3.27) + +# Set the project name +project(circle) + +# Global definitions +if(MSVC) + # using Visual Studio C++ + add_definitions(-D_CRT_SECURE_NO_WARNINGS -D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE) +endif() + +# circle itself +file(GLOB CIRCLE_SOURCES + "*.h" + "*.c" +) + +add_executable(circle ${CIRCLE_SOURCES}) + +if(MSVC) + target_link_libraries(circle wsock32.lib) + + set_target_properties(circle PROPERTIES + VS_DEBUGGER_WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/.." + ) +endif() \ No newline at end of file diff --git a/src/protocol.c b/src/protocol.c index e2beac3..587e6ac 100644 --- a/src/protocol.c +++ b/src/protocol.c @@ -13,6 +13,11 @@ #include #include "protocol.h" +#ifdef _MSC_VER +#include "telnet.h" +#define alloca _alloca +#endif + /****************************************************************************** The following section is for Diku/Merc derivatives. Replace as needed. ******************************************************************************/ From 5da67ddc6a402861d8431471c7a1488646efff4d Mon Sep 17 00:00:00 2001 From: Nick Schmoyer Date: Sat, 2 Mar 2024 16:11:28 -0600 Subject: [PATCH 18/35] Add missing lookup for flags in read_ibt (#128) --- src/ibt.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/ibt.c b/src/ibt.c index 3ead2c1..1586b54 100755 --- a/src/ibt.c +++ b/src/ibt.c @@ -177,6 +177,13 @@ static IBT_DATA *read_ibt( char *filename, FILE *fp ) } break; + case 'F': + if (!str_cmp(word, "Flags")) { + fMatch = TRUE; + fread_flags(fp, ibtData->flags, 4); + } + break; + case 'I': TXT_KEY("IdNum", id_num, fread_line(fp)); break; From cde4b84be16b4f81daa7af777a954a9025183b8d Mon Sep 17 00:00:00 2001 From: Thomas Arp <357770+welcor@users.noreply.github.com> Date: Sat, 8 Jun 2024 12:12:54 +0200 Subject: [PATCH 19/35] Update FAQ.txt (#130) Added info about generated maps for the areas on tbaMUD --- doc/FAQ.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/FAQ.txt b/doc/FAQ.txt index ac1321d..3b28a08 100644 --- a/doc/FAQ.txt +++ b/doc/FAQ.txt @@ -257,6 +257,9 @@ http://tbamud.com All donated areas have been added to the latest version of tbaMUD. If you wish to donate some of your own work stop by the Builder Academy. +https://github.com/rds1983 has generated maps of all the existing areas, +and they can be found here: https://mudmapbuilder.github.io/ + 2.3. I have questions about tbaMUD. Where should I go? Stop by The Builder Academy at tbamud.com 9091 or the website at: From ac711ffff8b768e102bf4cb015457cdb47f2706f Mon Sep 17 00:00:00 2001 From: Dan Danese Date: Tue, 18 Jun 2024 14:56:13 -0400 Subject: [PATCH 20/35] Update wld2html.c (#131) Triggers on elements of the room break this utility. Added code to toss them since we don't need them. Can add handling that pulls the trigger info later if desired, but too time consuming to index them before building the room for this simple tool. --- src/util/wld2html.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/util/wld2html.c b/src/util/wld2html.c index 9afc9c8..ac3c111 100755 --- a/src/util/wld2html.c +++ b/src/util/wld2html.c @@ -257,6 +257,9 @@ void discrete_load(FILE * fl) fprintf(stderr, "Format error after room #%d\n", nr); exit(1); } + if (*line == 'T') //Toss triggers. THey currently break this util. + return; + if (*line == '$') return; From 317286d051d667918aede914b2834d5d222ba494 Mon Sep 17 00:00:00 2001 From: Thomas Arp <357770+welcor@users.noreply.github.com> Date: Thu, 20 Jun 2024 19:31:20 +0200 Subject: [PATCH 21/35] Ignore project files on commit, and fix the automap bug showing two (#133) descriptions --- .gitignore | 73 +++++++++- src/act.informative.c | 329 +++++++++++++++++++++--------------------- 2 files changed, 238 insertions(+), 164 deletions(-) diff --git a/.gitignore b/.gitignore index e8e8f46..29a5738 100644 --- a/.gitignore +++ b/.gitignore @@ -12,4 +12,75 @@ src/depend src/util/depend build/* !build/create_solution.bat -!build/README.md \ No newline at end of file +!build/README.md + +# Do not commit files from players +lib/plrfiles/A-E/* +lib/plrfiles/F-J/* +lib/plrfiles/K-O/* +lib/plrfiles/P-T/* +lib/plrfiles/U-Z/* +lib/plrfiles/ZZZ/* +lib/plrfiles/index + +# but do commit the placeholders +!lib/plrfiles/A-E/00 +!lib/plrfiles/F-J/00 +!lib/plrfiles/K-O/00 +!lib/plrfiles/P-T/00 +!lib/plrfiles/U-Z/00 +!lib/plrfiles/ZZZ/00 + +# or vars +lib/plrvars/A-E/* +lib/plrvars/F-J/* +lib/plrvars/K-O/* +lib/plrvars/P-T/* +lib/plrvars/U-Z/* +lib/plrvars/ZZZ/* +lib/plrvars/index + +# except the placeholders +!lib/plrvars/A-E/00 +!lib/plrvars/F-J/00 +!lib/plrvars/K-O/00 +!lib/plrvars/P-T/00 +!lib/plrvars/U-Z/00 +!lib/plrvars/ZZZ/00 + +# or objects +lib/plrobjs/A-E/* +lib/plrobjs/F-J/* +lib/plrobjs/K-O/* +lib/plrobjs/P-T/* +lib/plrobjs/U-Z/* +lib/plrobjs/ZZZ/* +lib/plrobjs/index + +# except the placeholders +!lib/plrobjs/A-E/00 +!lib/plrobjs/F-J/00 +!lib/plrobjs/K-O/00 +!lib/plrobjs/P-T/00 +!lib/plrobjs/U-Z/00 +!lib/plrobjs/ZZZ/00 + +# also not autogenerated config file +/lib/etc/config +# or the list of last logins +/lib/etc/last +# or mail +lib/etc/plrmail + +# test object files, etc +src/test/depend +src/test/*.o +src/test/testfile + + +# ide etc. +.vscode +.project +.settings + +.cproject \ No newline at end of file diff --git a/src/act.informative.c b/src/act.informative.c index 79705f3..5298e1c 100644 --- a/src/act.informative.c +++ b/src/act.informative.c @@ -51,7 +51,7 @@ 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); /* Subcommands */ -/* For show_obj_to_char 'mode'. /-- arbitrary */ +/* For show_obj_to_char 'mode'. /-- arbitrary */ #define SHOW_OBJ_LONG 0 #define SHOW_OBJ_SHORT 1 #define SHOW_OBJ_ACTION 2 @@ -125,7 +125,7 @@ static void show_obj_to_char(struct obj_data *obj, struct char_data *ch, int mod snprintf(notebuf, sizeof(notebuf), "There is something written on it:\r\n\r\n%s", obj->action_description); page_string(ch->desc, notebuf, TRUE); } else - send_to_char(ch, "It's blank.\r\n"); + send_to_char(ch, "It's blank.\r\n"); return; case ITEM_DRINKCON: @@ -225,14 +225,14 @@ static void diag_char_to_char(struct char_data *i, struct char_data *ch) byte percent; const char *text; } diagnosis[] = { - { 100, "is in excellent condition." }, - { 90, "has a few scratches." }, - { 75, "has some small wounds and bruises." }, - { 50, "has quite a few wounds." }, - { 30, "has some big nasty wounds and scratches." }, - { 15, "looks pretty hurt." }, - { 0, "is in awful condition." }, - { -1, "is bleeding awfully from big wounds." }, + { 100, "is in excellent condition." }, + { 90, "has a few scratches." }, + { 75, "has some small wounds and bruises." }, + { 50, "has quite a few wounds." }, + { 30, "has some big nasty wounds and scratches." }, + { 15, "looks pretty hurt." }, + { 0, "is in awful condition." }, + { -1, "is bleeding awfully from big wounds." }, }; int percent, ar_index; const char *pers = PERS(i, ch); @@ -240,7 +240,7 @@ static void diag_char_to_char(struct char_data *i, struct char_data *ch) if (GET_MAX_HIT(i) > 0) percent = (100 * GET_HIT(i)) / GET_MAX_HIT(i); else - percent = -1; /* How could MAX_HIT be < 1?? */ + percent = -1; /* How could MAX_HIT be < 1?? */ for (ar_index = 0; diagnosis[ar_index].percent >= 0; ar_index++) if (percent >= diagnosis[ar_index].percent) @@ -269,12 +269,12 @@ static void look_at_char(struct char_data *i, struct char_data *ch) found = TRUE; if (found) { - send_to_char(ch, "\r\n"); /* act() does capitalization. */ + send_to_char(ch, "\r\n"); /* act() does capitalization. */ act("$n is using:", FALSE, i, 0, ch, TO_VICT); for (j = 0; j < NUM_WEARS; j++) if (GET_EQ(i, j) && CAN_SEE_OBJ(ch, GET_EQ(i, j))) { - send_to_char(ch, "%s", wear_where[j]); - show_obj_to_char(GET_EQ(i, j), ch, SHOW_OBJ_SHORT); + send_to_char(ch, "%s", wear_where[j]); + show_obj_to_char(GET_EQ(i, j), ch, SHOW_OBJ_SHORT); } } if (ch != i && (IS_THIEF(ch) || GET_LEVEL(ch) >= LVL_IMMORT)) { @@ -300,7 +300,7 @@ static void list_one_char(struct char_data *i, struct char_data *ch) if (!IS_NPC(ch) && PRF_FLAGGED(ch, PRF_SHOWVNUMS)) { if (IS_NPC(i)) - send_to_char(ch, "[%d] ", GET_MOB_VNUM(i)); + send_to_char(ch, "[%d] ", GET_MOB_VNUM(i)); if (SCRIPT(i) && TRIGGERS(SCRIPT(i))) { if (!TRIGGERS(SCRIPT(i))->next) send_to_char(ch, "[T%d] ", GET_TRIG_VNUM(TRIGGERS(SCRIPT(i)))); @@ -312,12 +312,12 @@ static void list_one_char(struct char_data *i, struct char_data *ch) if (GROUP(i)) { if (GROUP(i) == GROUP(ch)) send_to_char(ch, "(%s%s%s) ", CBGRN(ch, C_NRM), - GROUP_LEADER(GROUP(i)) == i ? "leader" : "group", - CCNRM(ch, C_NRM)); + GROUP_LEADER(GROUP(i)) == i ? "leader" : "group", + CCNRM(ch, C_NRM)); else send_to_char(ch, "(%s%s%s) ", CBRED(ch, C_NRM), - GROUP_LEADER(GROUP(i)) == i ? "leader" : "group", - CCNRM(ch, C_NRM)); + GROUP_LEADER(GROUP(i)) == i ? "leader" : "group", + CCNRM(ch, C_NRM)); } if (IS_NPC(i) && i->player.long_descr && GET_POS(i) == GET_DEFAULT_POS(i)) { @@ -326,9 +326,9 @@ static void list_one_char(struct char_data *i, struct char_data *ch) if (AFF_FLAGGED(ch, AFF_DETECT_ALIGN)) { if (IS_EVIL(i)) - send_to_char(ch, "(Red Aura) "); + send_to_char(ch, "(Red Aura) "); else if (IS_GOOD(i)) - send_to_char(ch, "(Blue Aura) "); + send_to_char(ch, "(Blue Aura) "); } send_to_char(ch, "%s", i->player.long_descr); @@ -361,24 +361,24 @@ static void list_one_char(struct char_data *i, struct char_data *ch) if (GET_POS(i) != POS_FIGHTING) { if (!SITTING(i)) send_to_char(ch, "%s", positions[(int) GET_POS(i)]); - else { - furniture = SITTING(i); - send_to_char(ch, " is %s upon %s.", (GET_POS(i) == POS_SLEEPING ? + else { + furniture = SITTING(i); + send_to_char(ch, " is %s upon %s.", (GET_POS(i) == POS_SLEEPING ? "sleeping" : (GET_POS(i) == POS_RESTING ? "resting" : "sitting")), OBJS(furniture, ch)); - } + } } else { if (FIGHTING(i)) { send_to_char(ch, " is here, fighting "); if (FIGHTING(i) == ch) - send_to_char(ch, "YOU!"); + send_to_char(ch, "YOU!"); else { - if (IN_ROOM(i) == IN_ROOM(FIGHTING(i))) - send_to_char(ch, "%s!", PERS(FIGHTING(i), ch)); - else - send_to_char(ch, "someone who has already left!"); + if (IN_ROOM(i) == IN_ROOM(FIGHTING(i))) + send_to_char(ch, "%s!", PERS(FIGHTING(i), ch)); + else + send_to_char(ch, "someone who has already left!"); } - } else /* NIL fighting pointer */ + } else /* NIL fighting pointer */ send_to_char(ch, " is here struggling with thin air."); } @@ -402,13 +402,13 @@ static void list_char_to_char(struct char_data *list, struct char_data *ch) if (ch != i) { /* hide npcs whose description starts with a '.' from non-holylighted people - Idea from Elaseth of TBA */ if (!IS_NPC(ch) && !PRF_FLAGGED(ch, PRF_HOLYLIGHT) && - IS_NPC(i) && i->player.long_descr && *i->player.long_descr == '.') + IS_NPC(i) && i->player.long_descr && *i->player.long_descr == '.') continue; send_to_char(ch, "%s", CCYEL(ch, C_NRM)); if (CAN_SEE(ch, i)) list_one_char(i, ch); else if (IS_DARK(IN_ROOM(ch)) && !CAN_SEE_IN_DARK(ch) && - AFF_FLAGGED(i, AFF_INFRAVISION)) + AFF_FLAGGED(i, AFF_INFRAVISION)) send_to_char(ch, "You see a pair of glowing red eyes looking your way.\r\n"); send_to_char(ch, "%s", CCNRM(ch, C_NRM)); } @@ -425,12 +425,12 @@ static void do_auto_exits(struct char_data *ch) continue; if (EXIT_FLAGGED(EXIT(ch, door), EX_CLOSED) && !CONFIG_DISP_CLOSED_DOORS) continue; - if (EXIT_FLAGGED(EXIT(ch, door), EX_HIDDEN) && !PRF_FLAGGED(ch, PRF_HOLYLIGHT)) - continue; + if (EXIT_FLAGGED(EXIT(ch, door), EX_HIDDEN) && !PRF_FLAGGED(ch, PRF_HOLYLIGHT)) + continue; if (EXIT_FLAGGED(EXIT(ch, door), EX_CLOSED)) - send_to_char(ch, "%s(%s)%s ", EXIT_FLAGGED(EXIT(ch, door), EX_HIDDEN) ? CCWHT(ch, C_NRM) : CCRED(ch, C_NRM), autoexits[door], CCCYN(ch, C_NRM)); - else if (EXIT_FLAGGED(EXIT(ch, door), EX_HIDDEN)) - send_to_char(ch, "%s%s%s ", CCWHT(ch, C_NRM), autoexits[door], CCCYN(ch, C_NRM)); + send_to_char(ch, "%s(%s)%s ", EXIT_FLAGGED(EXIT(ch, door), EX_HIDDEN) ? CCWHT(ch, C_NRM) : CCRED(ch, C_NRM), autoexits[door], CCCYN(ch, C_NRM)); + else if (EXIT_FLAGGED(EXIT(ch, door), EX_HIDDEN)) + send_to_char(ch, "%s%s%s ", CCWHT(ch, C_NRM), autoexits[door], CCCYN(ch, C_NRM)); else send_to_char(ch, "\t(%s\t) ", autoexits[door]); slen++; @@ -521,23 +521,25 @@ void look_at_room(struct char_data *ch, int ignore_brief) } else send_to_char(ch, "%s", world[IN_ROOM(ch)].name); - send_to_char(ch, "%s\r\n", CCNRM(ch, C_NRM)); - if ((!IS_NPC(ch) && !PRF_FLAGGED(ch, PRF_BRIEF)) || ignore_brief || - ROOM_FLAGGED(IN_ROOM(ch), ROOM_DEATH)) { - if (!IS_NPC(ch) && PRF_FLAGGED(ch, PRF_AUTOMAP) && can_see_map(ch)) - str_and_map(world[target_room].description, ch, target_room); - } + send_to_char(ch, "%s\r\n", CCNRM(ch, C_NRM)); - send_to_char(ch, "%s", world[IN_ROOM(ch)].description); + if ((!IS_NPC(ch) && !PRF_FLAGGED(ch, PRF_BRIEF)) || ignore_brief || + ROOM_FLAGGED(IN_ROOM(ch), ROOM_DEATH)) { + if (!IS_NPC(ch) && PRF_FLAGGED(ch, PRF_AUTOMAP) && can_see_map(ch)) + str_and_map(world[target_room].description, ch, target_room); + else + send_to_char(ch, "%s", world[IN_ROOM(ch)].description); + } - /*autoexits */ - if (!IS_NPC(ch) && PRF_FLAGGED(ch, PRF_AUTOEXIT)) - do_auto_exits(ch); - /*now list characters &objects */ - list_obj_to_char(world[IN_ROOM(ch)].contents, ch, SHOW_OBJ_LONG, FALSE); - list_char_to_char(world[IN_ROOM(ch)].people, ch); + /*autoexits */ + if (!IS_NPC(ch) && PRF_FLAGGED(ch, PRF_AUTOEXIT)) + do_auto_exits(ch); + + /*now list characters &objects */ + list_obj_to_char(world[IN_ROOM(ch)].contents, ch, SHOW_OBJ_LONG, FALSE); + list_char_to_char(world[IN_ROOM(ch)].people, ch); } static void look_in_direction(struct char_data *ch, int dir) @@ -565,35 +567,35 @@ static void look_in_obj(struct char_data *ch, char *arg) if (!*arg) send_to_char(ch, "Look in what?\r\n"); else if (!(bits = generic_find(arg, FIND_OBJ_INV | FIND_OBJ_ROOM | - FIND_OBJ_EQUIP, ch, &dummy, &obj))) { + FIND_OBJ_EQUIP, ch, &dummy, &obj))) { send_to_char(ch, "There doesn't seem to be %s %s here.\r\n", AN(arg), arg); } else if ((GET_OBJ_TYPE(obj) != ITEM_DRINKCON) && - (GET_OBJ_TYPE(obj) != ITEM_FOUNTAIN) && - (GET_OBJ_TYPE(obj) != ITEM_CONTAINER)) + (GET_OBJ_TYPE(obj) != ITEM_FOUNTAIN) && + (GET_OBJ_TYPE(obj) != ITEM_CONTAINER)) send_to_char(ch, "There's nothing inside that!\r\n"); else { if (GET_OBJ_TYPE(obj) == ITEM_CONTAINER) { if (OBJVAL_FLAGGED(obj, CONT_CLOSED) && (GET_LEVEL(ch) < LVL_IMMORT || !PRF_FLAGGED(ch, PRF_NOHASSLE))) - send_to_char(ch, "It is closed.\r\n"); + send_to_char(ch, "It is closed.\r\n"); else { - send_to_char(ch, "%s", fname(obj->name)); - switch (bits) { - case FIND_OBJ_INV: - send_to_char(ch, " (carried): \r\n"); - break; - case FIND_OBJ_ROOM: - send_to_char(ch, " (here): \r\n"); - break; - case FIND_OBJ_EQUIP: - send_to_char(ch, " (used): \r\n"); - break; - } + send_to_char(ch, "%s", fname(obj->name)); + switch (bits) { + case FIND_OBJ_INV: + send_to_char(ch, " (carried): \r\n"); + break; + case FIND_OBJ_ROOM: + send_to_char(ch, " (here): \r\n"); + break; + case FIND_OBJ_EQUIP: + send_to_char(ch, " (used): \r\n"); + break; + } - list_obj_to_char(obj->contains, ch, SHOW_OBJ_SHORT, TRUE); + list_obj_to_char(obj->contains, ch, SHOW_OBJ_SHORT, TRUE); } - } else { /* item must be a fountain or drink container */ + } else { /* item must be a fountain or drink container */ if ((GET_OBJ_VAL(obj, 1) == 0) && (GET_OBJ_VAL(obj, 0) != -1)) - send_to_char(ch, "It is empty.\r\n"); + send_to_char(ch, "It is empty.\r\n"); else { if (GET_OBJ_VAL(obj, 0) < 0) { @@ -601,14 +603,15 @@ static void look_in_obj(struct char_data *ch, char *arg) sprinttype(GET_OBJ_VAL(obj, 2), color_liquid, buf2, sizeof(buf2)); send_to_char(ch, "It's full of a %s liquid.\r\n", buf2); } - else if (GET_OBJ_VAL(obj,1)>GET_OBJ_VAL(obj,0)) + else if (GET_OBJ_VAL(obj,1)>GET_OBJ_VAL(obj,0)) send_to_char(ch, "Its contents seem somewhat murky.\r\n"); /* BUG */ - else { + else + { char buf2[MAX_STRING_LENGTH]; - amt = (GET_OBJ_VAL(obj, 1) * 3) / GET_OBJ_VAL(obj, 0); - sprinttype(GET_OBJ_VAL(obj, 2), color_liquid, buf2, sizeof(buf2)); - send_to_char(ch, "It's %sfull of a %s liquid.\r\n", fullness[amt], buf2); - } + amt = (GET_OBJ_VAL(obj, 1) * 3) / GET_OBJ_VAL(obj, 0); + sprinttype(GET_OBJ_VAL(obj, 2), color_liquid, buf2, sizeof(buf2)); + send_to_char(ch, "It's %sfull of a %s liquid.\r\n", fullness[amt], buf2); + } } } } @@ -645,14 +648,14 @@ static void look_at_target(struct char_data *ch, char *arg) } bits = generic_find(arg, FIND_OBJ_INV | FIND_OBJ_ROOM | FIND_OBJ_EQUIP | - FIND_CHAR_ROOM, ch, &found_char, &found_obj); + FIND_CHAR_ROOM, ch, &found_char, &found_obj); /* Is the target a character? */ if (found_char != NULL) { look_at_char(found_char, ch); if (ch != found_char) { if (CAN_SEE(found_char, ch)) - act("$n looks at you.", TRUE, ch, 0, found_char, TO_VICT); + act("$n looks at you.", TRUE, ch, 0, found_char, TO_VICT); act("$n looks at $N.", TRUE, ch, 0, found_char, TO_NOTVICT); } return; @@ -674,16 +677,16 @@ static void look_at_target(struct char_data *ch, char *arg) for (j = 0; j < NUM_WEARS && !found; j++) if (GET_EQ(ch, j) && CAN_SEE_OBJ(ch, GET_EQ(ch, j))) if ((desc = find_exdesc(arg, GET_EQ(ch, j)->ex_description)) != NULL && ++i == fnum) { - send_to_char(ch, "%s", desc); - found = TRUE; + send_to_char(ch, "%s", desc); + found = TRUE; } /* Does the argument match an extra desc in the char's inventory? */ for (obj = ch->carrying; obj && !found; obj = obj->next_content) { if (CAN_SEE_OBJ(ch, obj)) if ((desc = find_exdesc(arg, obj->ex_description)) != NULL && ++i == fnum) { - send_to_char(ch, "%s", desc); - found = TRUE; + send_to_char(ch, "%s", desc); + found = TRUE; } } @@ -691,8 +694,8 @@ static void look_at_target(struct char_data *ch, char *arg) for (obj = world[IN_ROOM(ch)].contents; obj && !found; obj = obj->next_content) if (CAN_SEE_OBJ(ch, obj)) if ((desc = find_exdesc(arg, obj->ex_description)) != NULL && ++i == fnum) { - send_to_char(ch, "%s", desc); - found = TRUE; + send_to_char(ch, "%s", desc); + found = TRUE; } /* If an object was found back in generic_find */ @@ -722,7 +725,7 @@ ACMD(do_look) send_to_char(ch, "You can't see a damned thing, you're blind!\r\n"); else if (IS_DARK(IN_ROOM(ch)) && !CAN_SEE_IN_DARK(ch)) { send_to_char(ch, "It is pitch black...\r\n"); - list_char_to_char(world[IN_ROOM(ch)].people, ch); /* glowing red eyes */ + list_char_to_char(world[IN_ROOM(ch)].people, ch); /* glowing red eyes */ } else { char arg[MAX_INPUT_LENGTH], arg2[MAX_INPUT_LENGTH]; @@ -730,12 +733,12 @@ ACMD(do_look) if (subcmd == SCMD_READ) { if (!*arg) - send_to_char(ch, "Read what?\r\n"); + send_to_char(ch, "Read what?\r\n"); else - look_at_target(ch, strcpy(tempsave, arg)); + look_at_target(ch, strcpy(tempsave, arg)); return; } - if (!*arg) /* "look" alone, without an argument at all */ + if (!*arg) /* "look" alone, without an argument at all */ look_at_room(ch, 1); else if (is_abbrev(arg, "in")) look_in_obj(ch, arg2); @@ -775,15 +778,15 @@ ACMD(do_examine) } /* look_at_target() eats the number. */ - look_at_target(ch, strcpy(tempsave, arg)); /* strcpy: OK */ + look_at_target(ch, strcpy(tempsave, arg)); /* strcpy: OK */ generic_find(arg, FIND_OBJ_INV | FIND_OBJ_ROOM | FIND_CHAR_ROOM | - FIND_OBJ_EQUIP, ch, &tmp_char, &tmp_object); + FIND_OBJ_EQUIP, ch, &tmp_char, &tmp_object); if (tmp_object) { if ((GET_OBJ_TYPE(tmp_object) == ITEM_DRINKCON) || - (GET_OBJ_TYPE(tmp_object) == ITEM_FOUNTAIN) || - (GET_OBJ_TYPE(tmp_object) == ITEM_CONTAINER)) { + (GET_OBJ_TYPE(tmp_object) == ITEM_FOUNTAIN) || + (GET_OBJ_TYPE(tmp_object) == ITEM_CONTAINER)) { send_to_char(ch, "When you look inside, you see:\r\n"); look_in_obj(ch, arg); } @@ -815,18 +818,18 @@ ACMD(do_score) send_to_char(ch, "\r\n"); send_to_char(ch, "You have %d(%d) hit, %d(%d) mana and %d(%d) movement points.\r\n", - GET_HIT(ch), GET_MAX_HIT(ch), GET_MANA(ch), GET_MAX_MANA(ch), - GET_MOVE(ch), GET_MAX_MOVE(ch)); + GET_HIT(ch), GET_MAX_HIT(ch), GET_MANA(ch), GET_MAX_MANA(ch), + GET_MOVE(ch), GET_MAX_MOVE(ch)); send_to_char(ch, "Your armor class is %d/10, and your alignment is %d.\r\n", - compute_armor_class(ch), GET_ALIGNMENT(ch)); + compute_armor_class(ch), GET_ALIGNMENT(ch)); send_to_char(ch, "You have %d exp, %d gold coins, and %d questpoints.\r\n", - GET_EXP(ch), GET_GOLD(ch), GET_QUESTPOINTS(ch)); + GET_EXP(ch), GET_GOLD(ch), GET_QUESTPOINTS(ch)); if (GET_LEVEL(ch) < LVL_IMMORT) send_to_char(ch, "You need %d exp to reach your next level.\r\n", - level_exp(GET_CLASS(ch), GET_LEVEL(ch) + 1) - GET_EXP(ch)); + level_exp(GET_CLASS(ch), GET_LEVEL(ch) + 1) - GET_EXP(ch)); send_to_char(ch, "You have earned %d quest points.\r\n", GET_QUESTPOINTS(ch)); send_to_char(ch, "You have completed %d quest%s, ", @@ -845,13 +848,13 @@ ACMD(do_score) } playing_time = *real_time_passed((time(0) - ch->player.time.logon) + - ch->player.time.played, 0); + ch->player.time.played, 0); send_to_char(ch, "You have been playing for %d day%s and %d hour%s.\r\n", playing_time.day, playing_time.day == 1 ? "" : "s", playing_time.hours, playing_time.hours == 1 ? "" : "s"); send_to_char(ch, "This ranks you as %s %s (level %d).\r\n", - GET_NAME(ch), GET_TITLE(ch), GET_LEVEL(ch)); + GET_NAME(ch), GET_TITLE(ch), GET_LEVEL(ch)); switch (GET_POS(ch)) { case POS_DEAD: @@ -982,8 +985,8 @@ ACMD(do_time) weekday = ((35 * time_info.month) + day) % 7; send_to_char(ch, "It is %d o'clock %s, on %s.\r\n", - (time_info.hours % 12 == 0) ? 12 : (time_info.hours % 12), - time_info.hours >= 12 ? "pm" : "am", weekdays[weekday]); + (time_info.hours % 12 == 0) ? 12 : (time_info.hours % 12), + time_info.hours >= 12 ? "pm" : "am", weekdays[weekday]); /* Peter Ajamian supplied the following as a fix for a bug introduced in the * ordinal display that caused 11, 12, and 13 to be incorrectly displayed as @@ -1005,7 +1008,7 @@ ACMD(do_time) } } send_to_char(ch, "The %d%s Day of the %s, Year %d.\r\n", - day, suf, month_name[time_info.month], time_info.year); + day, suf, month_name[time_info.month], time_info.year); } ACMD(do_weather) @@ -1020,8 +1023,8 @@ ACMD(do_weather) if (OUTSIDE(ch)) { send_to_char(ch, "The sky is %s and %s.\r\n", sky_look[weather_info.sky], - weather_info.change >= 0 ? "you feel a warm wind from south" : - "your foot tells you bad weather is due"); + weather_info.change >= 0 ? "you feel a warm wind from south" : + "your foot tells you bad weather is due"); if (GET_LEVEL(ch) >= LVL_GOD) send_to_char(ch, "Pressure: %d (change: %d), Sky: %d (%s)\r\n", weather_info.pressure, @@ -1379,7 +1382,7 @@ ACMD(do_users) host_search[0] = name_search[0] = '\0'; - strcpy(buf, argument); /* strcpy: OK (sizeof: argument == buf) */ + strcpy(buf, argument); /* strcpy: OK (sizeof: argument == buf) */ while (*buf) { char buf1[MAX_INPUT_LENGTH]; @@ -1389,49 +1392,49 @@ ACMD(do_users) switch (mode) { case 'o': case 'k': - outlaws = 1; - playing = 1; - strcpy(buf, buf1); /* strcpy: OK (sizeof: buf1 == buf) */ - break; + outlaws = 1; + playing = 1; + strcpy(buf, buf1); /* strcpy: OK (sizeof: buf1 == buf) */ + break; case 'p': - playing = 1; - strcpy(buf, buf1); /* strcpy: OK (sizeof: buf1 == buf) */ - break; + playing = 1; + strcpy(buf, buf1); /* strcpy: OK (sizeof: buf1 == buf) */ + break; case 'd': - deadweight = 1; - strcpy(buf, buf1); /* strcpy: OK (sizeof: buf1 == buf) */ - break; + deadweight = 1; + strcpy(buf, buf1); /* strcpy: OK (sizeof: buf1 == buf) */ + break; case 'l': - playing = 1; - half_chop(buf1, arg, buf); - sscanf(arg, "%d-%d", &low, &high); - break; + playing = 1; + half_chop(buf1, arg, buf); + sscanf(arg, "%d-%d", &low, &high); + break; case 'n': - playing = 1; - half_chop(buf1, name_search, buf); - break; + playing = 1; + half_chop(buf1, name_search, buf); + break; case 'h': - playing = 1; - half_chop(buf1, host_search, buf); - break; + playing = 1; + half_chop(buf1, host_search, buf); + break; case 'c': - playing = 1; - half_chop(buf1, arg, buf); - showclass = find_class_bitvector(arg); - break; + playing = 1; + half_chop(buf1, arg, buf); + showclass = find_class_bitvector(arg); + break; default: - send_to_char(ch, "%s", USERS_FORMAT); - return; - } /* end of switch */ + send_to_char(ch, "%s", USERS_FORMAT); + return; + } /* end of switch */ - } else { /* endif */ + } else { /* endif */ send_to_char(ch, "%s", USERS_FORMAT); return; } - } /* end while (parser) */ + } /* end while (parser) */ send_to_char(ch, - "Num Class Name State Idl Login\t* Site\r\n" - "--- ------- ------------ -------------- ----- -------- ------------------------\r\n"); + "Num Class Name State Idl Login\t* Site\r\n" + "--- ------- ------------ -------------- ----- -------- ------------------------\r\n"); one_argument(argument, arg); @@ -1453,7 +1456,7 @@ ACMD(do_users) if (!CAN_SEE(ch, tch) || GET_LEVEL(tch) < low || GET_LEVEL(tch) > high) continue; if (outlaws && !PLR_FLAGGED(tch, PLR_KILLER) && - !PLR_FLAGGED(tch, PLR_THIEF)) + !PLR_FLAGGED(tch, PLR_THIEF)) continue; if (showclass && !(showclass & (1 << GET_CLASS(tch)))) continue; @@ -1461,11 +1464,11 @@ ACMD(do_users) continue; if (d->original) - sprintf(classname, "[%2d %s]", GET_LEVEL(d->original), - CLASS_ABBR(d->original)); + sprintf(classname, "[%2d %s]", GET_LEVEL(d->original), + CLASS_ABBR(d->original)); else - sprintf(classname, "[%2d %s]", GET_LEVEL(d->character), - CLASS_ABBR(d->character)); + sprintf(classname, "[%2d %s]", GET_LEVEL(d->character), + CLASS_ABBR(d->character)); } else strcpy(classname, " - "); @@ -1478,15 +1481,15 @@ ACMD(do_users) if (d->character && STATE(d) == CON_PLAYING) sprintf(idletime, "%5d", d->character->char_specials.timer * - SECS_PER_MUD_HOUR / SECS_PER_REAL_MIN); + SECS_PER_MUD_HOUR / SECS_PER_REAL_MIN); else strcpy(idletime, " "); sprintf(line, "%3d %-7s %-12s %-14s %-3s %-8s ", d->desc_num, classname, - d->original && d->original->player.name ? d->original->player.name : - d->character && d->character->player.name ? d->character->player.name : - "UNDEFINED", - state, idletime, timestr); + d->original && d->original->player.name ? d->original->player.name : + d->character && d->character->player.name ? d->character->player.name : + "UNDEFINED", + state, idletime, timestr); if (*d->host) sprintf(line + strlen(line), "[%s]\r\n", d->host); @@ -1576,23 +1579,23 @@ static void perform_mortal_where(struct char_data *ch, char *arg) send_to_char(ch, "Players in %s\tn.\r\n--------------------\r\n", zone_table[j].name); for (d = descriptor_list; d; d = d->next) { if (STATE(d) != CON_PLAYING || d->character == ch) - continue; + continue; if ((i = (d->original ? d->original : d->character)) == NULL) - continue; + continue; if (IN_ROOM(i) == NOWHERE || !CAN_SEE(ch, i)) - continue; + continue; if (world[IN_ROOM(ch)].zone != world[IN_ROOM(i)].zone) - continue; + continue; send_to_char(ch, "%-20s%s - %s%s\r\n", GET_NAME(i), QNRM, world[IN_ROOM(i)].name, QNRM); } - } else { /* print only FIRST char, not all. */ + } else { /* print only FIRST char, not all. */ for (i = character_list; i; i = i->next) { if (IN_ROOM(i) == NOWHERE || i == ch) - continue; + continue; if (!CAN_SEE(ch, i) || world[IN_ROOM(i)].zone != world[IN_ROOM(ch)].zone) - continue; + continue; if (!isname(arg, i->player.name)) - continue; + continue; send_to_char(ch, "%-25s%s - %s%s\r\n", GET_NAME(i), QNRM, world[IN_ROOM(i)].name, QNRM); return; } @@ -1601,7 +1604,7 @@ 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) + int recur) { if (num > 0) send_to_char(ch, "O%3d. %-25s%s - ", num, obj->short_description, QNRM); @@ -1666,7 +1669,7 @@ static void perform_immort_where(struct char_data *ch, char *arg) else send_to_char(ch, "[TRIGS] "); } - send_to_char(ch, "%s\r\n", QNRM); + send_to_char(ch, "%s\r\n", QNRM); } for (num = 0, k = object_list; k; k = k->next) if (CAN_SEE_OBJ(ch, k) && isname(arg, k->name)) { @@ -1735,7 +1738,7 @@ ACMD(do_levels) for (i = min_lev; i < max_lev; i++) { nlen = snprintf(buf + len, sizeof(buf) - len, "[%2d] %8d-%-8d : ", (int)i, - level_exp(GET_CLASS(ch), i), level_exp(GET_CLASS(ch), i + 1) - 1); + level_exp(GET_CLASS(ch), i), level_exp(GET_CLASS(ch), i + 1) - 1); if (len + nlen >= sizeof(buf)) break; len += nlen; @@ -1759,7 +1762,7 @@ ACMD(do_levels) if (len < sizeof(buf) && max_lev == LVL_IMMORT) snprintf(buf + len, sizeof(buf) - len, "[%2d] %8d : Immortality\r\n", - LVL_IMMORT, level_exp(GET_CLASS(ch), LVL_IMMORT)); + LVL_IMMORT, level_exp(GET_CLASS(ch), LVL_IMMORT)); page_string(ch->desc, buf, TRUE); } @@ -1949,14 +1952,14 @@ ACMD(do_toggle) else sprintf(buf2, "%-3.3d", GET_WIMP_LEV(ch)); /* sprintf: OK */ - if (GET_LEVEL(ch) == LVL_IMPL) { + if (GET_LEVEL(ch) == LVL_IMPL) { send_to_char(ch, " SlowNameserver: %-3s " - " " - " Trackthru Doors: %-3s\r\n", + " " + " Trackthru Doors: %-3s\r\n", - ONOFF(CONFIG_NS_IS_SLOW), - ONOFF(CONFIG_TRACK_T_DOORS)); + ONOFF(CONFIG_NS_IS_SLOW), + ONOFF(CONFIG_TRACK_T_DOORS)); } if (GET_LEVEL(ch) >= LVL_IMMORT) { From 762cb77c60cbe7c9ade0fe7e0ad3c2bcaea96907 Mon Sep 17 00:00:00 2001 From: Dan Danese Date: Thu, 20 Jun 2024 13:56:51 -0400 Subject: [PATCH 22/35] Fix a bug with the prior commit for handling triggers. It should have (#132) continued the loop, not returned since it isn't likely to be the end of the wld file. Added the ability to specify multiple files on the command line. This will load all files passed before processing into html files. This is to fix the 'missing exits' from the output html files. The prior version only worked on a single zone or wld file and generated incomplete output. The record count was moved global to enable proper tracking of the entire world. The index_boot function was modified to scan the files first, get a record count, then start over and load the room records. example usage: wld2html *.wld This command will generate the entire world as one html file per room. Fixed room number roll over. The original was using a short int which is a 16bit int and rolls at 32k. Fixed an issue where the html files would get negative names due to integer rollover. It had something to do with sprintf an int using %d, but only if you passed that to fopen. Casting the int (room number) to a long before using sprintf with %ld fixed the issue. Added the missing four directions from the dir_names array and defines. Co-authored-by: Dan Danese --- src/util/wld2html.c | 149 +++++++++++++++++++++++--------------------- 1 file changed, 77 insertions(+), 72 deletions(-) diff --git a/src/util/wld2html.c b/src/util/wld2html.c index ac3c111..410d0bc 100755 --- a/src/util/wld2html.c +++ b/src/util/wld2html.c @@ -12,7 +12,6 @@ #include "conf.h" #include "sysdep.h" - #define NOWHERE -1 /* nil reference for room-database */ /* The cardinal directions: used as index to room_data.dir_option[] */ @@ -22,14 +21,17 @@ #define WEST 3 #define UP 4 #define DOWN 5 +#define NORTHWEST 6 +#define NORTHEAST 7 +#define SOUTHEAST 8 +#define SOUTHWEST 9 -#define NUM_OF_DIRS 6 +#define NUM_OF_DIRS 10 #define CREATE(result, type, number) do {\ if (!((result) = (type *) calloc ((number), sizeof(type))))\ { perror("malloc failure"); abort(); } } while(0) - /* Exit info: used in room_data.dir_option.exit_info */ #define EX_ISDOOR (1 << 0) /* Exit is a door */ #define EX_CLOSED (1 << 1) /* The door is closed */ @@ -45,7 +47,7 @@ typedef unsigned short int ush_int; typedef char bool; typedef char byte; -typedef sh_int room_num; +typedef int room_num; typedef sh_int obj_num; @@ -133,13 +135,14 @@ struct room_data { struct room_data *world = NULL; /* array of rooms */ int top_of_world = 0; /* ref to top element of world */ +int rec_count = 0; /* local functions */ char *fread_string(FILE * fl, char *error); void setup_dir(FILE * fl, int room, int dir); -void index_boot(char *name); +void index_boot(int cnt, char **name); void discrete_load(FILE * fl); void parse_room(FILE * fl, int virtual_nr); void parse_mobile(FILE * mob_f, int nr); @@ -150,7 +153,7 @@ void write_output(void); char *dir_names[] = -{"North", "East", "South", "West", "Up", "Down"}; +{"North", "East", "South", "West", "Up", "Down","North West","North East","South East","South West"}; /************************************************************************* @@ -160,14 +163,12 @@ char *dir_names[] = /* body of the booting system */ int main(int argc, char **argv) { - if (argc != 2) { - fprintf(stderr, "Usage: %s \n", argv[0]); + if (argc < 2) { + fprintf(stderr, "Usage: %s \n", argv[0]); exit(1); } - index_boot(argv[1]); - log("Renumbering rooms."); - renum_world(); + index_boot(argc,argv); log("Writing output."); write_output(); @@ -176,6 +177,21 @@ int main(int argc, char **argv) return (0); } +/* Since the world is loaded into memory by index + * and not room number, we need to search through + * all rooms and return the correct one. This is + * used to generate door information (ie: the name) + */ +struct room_data* findRoom(int nr) +{ + int i; + + for (i=0;ito_room != NOWHERE) { - found = 1; - fprintf(fl, " %s to %s

\n", - world[world[i].dir_option[door]->to_room].number, - dir_names[door], - world[world[i].dir_option[door]->to_room].name); + world[i].dir_option[door]->to_room != NOWHERE) { + found = 1; + //this call gets a pointer to the room referenced by the to_room for the door. + //This fixes a lot of issues introduced with the whole 'renumbering rooms' call + //and the binary search that didn't work well. + struct room_data* to_room = findRoom(world[i].dir_option[door]->to_room); + fprintf(fl, " %s to %s

\n", + to_room->number, + dir_names[door], + to_room->name); } if (!found) fprintf(fl, "None!"); fclose(fl); } -} +} /* function to count how many hash-mark delimited records exist in a file */ int count_hash_records(FILE * fl) @@ -231,19 +262,35 @@ int count_hash_records(FILE * fl) -void index_boot(char *name) +void index_boot(int cnt, char **names) { FILE *db_file; - int rec_count = 0; - if (!(db_file = fopen(name, "r"))) { - perror("error opening world file"); - exit(1); + //throw first entry away as that is the executable. + for (int i=1;ito_room != NOWHERE) - world[room].dir_option[door]->to_room = - real_room(world[room].dir_option[door]->to_room, - world[room].number); -} - - - /************************************************************************* * procedures for resetting, both play-time and boot-time * *********************************************************************** */ @@ -467,32 +498,6 @@ char *fread_string(FILE * fl, char *error) -/* returns the real number of the room with given virtual number */ -int real_room(int virtual, int reference) -{ - int bot, top, mid; - - bot = 0; - top = top_of_world; - - /* perform binary search on world-table */ - for (;;) { - mid = (bot + top) / 2; - - if ((world + mid)->number == virtual) - return (mid); - if (bot >= top) { - fprintf(stderr, "Room %d does not exist in database (referenced in room %d)\n", virtual, reference); - return (-1); - } - if ((world + mid)->number > virtual) - top = mid - 1; - else - bot = mid + 1; - } -} - - /* get_line reads the next non-blank line off of the input stream. * The newline character is removed from the input. Lines which begin * with '*' are considered to be comments. 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 23/35] 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 24/35] 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 25/35] 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 26/35] 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 27/35] 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 28/35] 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 29/35] 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 30/35] 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 31/35] 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 32/35] 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 33/35] 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 34/35] 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 35/35] 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” or“a”, depending on the first character of obj’s 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 you’re %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 (don’t -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 you’re 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 player’s 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, "Don’t 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: - Don’t 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: - Don’t 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: - Don’t 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: - Don’t you just love color, color, COLOR! (no color, as you’d 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 don’t 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 don’t 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 can’t 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 player’s 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.0’s 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 “I’m 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 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. +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 don’t 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 people’s 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 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, ...)”). +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 can’t interpret it, and they can’t 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. -It’s 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 won’t +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 tbaMUD’s 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 tbaMUD’s 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 can’t 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 tbaMUD’s +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 you’re 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, -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’ +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 don’t 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 don’t 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, you’ll 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 don’t 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 aren’t 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 character’s 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 -administrator’s 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 game’s Wizlist. - should be set to your game’s 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.